Chromium Code Reviews| Index: pkg/compiler/lib/src/ssa/interceptor_simplifier.dart |
| diff --git a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart |
| index d8213e2ca289cebe0d47db8d2d71574239ae4c80..57a75e4e36007fa3d1ed27668c46a4fb6204bc43 100644 |
| --- a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart |
| +++ b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart |
| @@ -110,30 +110,50 @@ class SsaSimplifyInterceptors extends HBaseVisitor |
| return graph.thisInstruction; |
| } |
| - ClassElement constantInterceptor; |
| + ClassElement constantInterceptor = tryComputeConstantInterceptorFromType( |
| + input.instructionType, interceptedClasses); |
| + |
| + if (constantInterceptor == null) return null; |
| + |
| + // If we just happen to be in an instance method of the constant |
| + // interceptor, `this` is a shorter alias. |
| + if (constantInterceptor == work.element.enclosingClass && |
| + graph.thisInstruction != null) { |
| + return graph.thisInstruction; |
| + } |
| + |
| + ConstantValue constant = |
| + new InterceptorConstantValue(constantInterceptor.thisType); |
| + return graph.addConstant(constant, compiler); |
| + } |
| + |
| + ClassElement tryComputeConstantInterceptorFromType( |
| + TypeMask type, |
| + Set<ClassElement> interceptedClasses) { |
| + |
| ClassWorld classWorld = compiler.world; |
| JavaScriptBackend backend = compiler.backend; |
| - if (input.canBeNull()) { |
| - if (input.isNull()) { |
| - constantInterceptor = backend.jsNullClass; |
| + if (type.isNullable) { |
| + if (type.isEmpty) { |
| + return backend.jsNullClass; |
| } |
| - } else if (input.isInteger(compiler)) { |
| - constantInterceptor = backend.jsIntClass; |
| - } else if (input.isDouble(compiler)) { |
| - constantInterceptor = backend.jsDoubleClass; |
| - } else if (input.isBoolean(compiler)) { |
| - constantInterceptor = backend.jsBoolClass; |
| - } else if (input.isString(compiler)) { |
| - constantInterceptor = backend.jsStringClass; |
| - } else if (input.isArray(compiler)) { |
| - constantInterceptor = backend.jsArrayClass; |
| - } else if (input.isNumber(compiler) && |
| + } else if (type.containsOnlyInt(classWorld)) { |
| + return backend.jsIntClass; |
| + } else if (type.containsOnlyDouble(classWorld)) { |
| + return backend.jsDoubleClass; |
| + } else if (type.containsOnlyBool(classWorld)) { |
| + return backend.jsBoolClass; |
| + } else if (type.containsOnlyString(classWorld)) { |
| + return backend.jsStringClass; |
| + } else if (type.satisfies(backend.jsArrayClass, classWorld)) { |
| + return backend.jsArrayClass; |
| + } else if (type.containsOnlyNum(classWorld) && |
| !interceptedClasses.contains(backend.jsIntClass) && |
| !interceptedClasses.contains(backend.jsDoubleClass)) { |
| // If the method being intercepted is not defined in [int] or [double] we |
| // can safely use the number interceptor. This is because none of the |
| // [int] or [double] methods are called from a method defined on [num]. |
| - constantInterceptor = backend.jsNumberClass; |
| + return backend.jsNumberClass; |
| } else { |
| // Try to find constant interceptor for a native class. If the receiver |
| // is constrained to a leaf native class, we can use the class's |
| @@ -146,24 +166,13 @@ class SsaSimplifyInterceptors extends HBaseVisitor |
| // for a subclass or call methods defined on a subclass. Provided the |
| // code is completely insensitive to the specific instance subclasses, we |
| // can use the non-leaf class directly. |
| - ClassElement element = input.instructionType.singleClass(classWorld); |
| + ClassElement element = type.singleClass(classWorld); |
| if (element != null && element.isNative) { |
| - constantInterceptor = element; |
| + return element; |
| } |
| } |
| - if (constantInterceptor == null) return null; |
| - |
| - // If we just happen to be in an instance method of the constant |
| - // interceptor, `this` is a shorter alias. |
| - if (constantInterceptor == work.element.enclosingClass && |
| - graph.thisInstruction != null) { |
| - return graph.thisInstruction; |
| - } |
| - |
| - ConstantValue constant = |
| - new InterceptorConstantValue(constantInterceptor.thisType); |
| - return graph.addConstant(constant, compiler); |
| + return null; |
| } |
| HInstruction findDominator(Iterable<HInstruction> instructions) { |
| @@ -276,6 +285,34 @@ class SsaSimplifyInterceptors extends HBaseVisitor |
| return false; |
| } |
| + // Do we have an 'almost constant' interceptor? The receiver could be |
| + // `null` but not any other JavaScript falsy value, `null` values cause |
| + // `NoSuchMethodError`s, and if the receiver was not null we would have a |
| + // constant interceptor `C`. Then we can use `(receiver && C)` for the |
| + // interceptor. |
| + if (receiver.canBeNull()) { |
| + if (!interceptedClasses.contains(backend.jsNullClass)) { |
| + if (!(receiver.canBePrimitiveNumber(compiler) || |
|
floitsch
2015/03/26 20:26:45
Why this `if`?
sra1
2015/04/01 23:06:59
Added comment. Only works for truthy values.
|
| + receiver.canBePrimitiveBoolean(compiler) || |
| + receiver.canBePrimitiveString(compiler))) { |
| + ClassElement interceptorClass = tryComputeConstantInterceptorFromType( |
| + receiver.instructionType.nonNullable(), interceptedClasses); |
| + if (interceptorClass != null) { |
| + if (node.inputs.length == 1) { |
| + ConstantValue constant = |
| + new InterceptorConstantValue(interceptorClass.thisType); |
| + HInstruction constantInstruction = |
| + graph.addConstant(constant, compiler); |
| + node.inputs.length = 2; |
| + node.inputs[1] = constantInstruction; |
| + constantInstruction.usedBy.add(node); |
| + return false; |
| + } |
| + } |
| + } |
| + } |
| + } |
| + |
| // Try creating a one-shot interceptor or optimized is-check |
| if (compiler.hasIncrementalSupport) return false; |
| if (node.usedBy.length != 1) return false; |