| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * This phase simplifies interceptors in multiple ways: | 8 * This phase simplifies interceptors in multiple ways: |
| 9 * | 9 * |
| 10 * 1) If the interceptor is for an object whose type is known, it | 10 * 1) If the interceptor is for an object whose type is known, it |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 if (input == graph.explicitReceiverParameter) { | 84 if (input == graph.explicitReceiverParameter) { |
| 85 // If `explicitReceiverParameter` is set it means the current method is an | 85 // If `explicitReceiverParameter` is set it means the current method is an |
| 86 // interceptor method, and `this` is the interceptor. The caller just did | 86 // interceptor method, and `this` is the interceptor. The caller just did |
| 87 // `getInterceptor(foo).currentMethod(foo)` to enter the current method. | 87 // `getInterceptor(foo).currentMethod(foo)` to enter the current method. |
| 88 return graph.thisInstruction; | 88 return graph.thisInstruction; |
| 89 } | 89 } |
| 90 | 90 |
| 91 HType type = input.instructionType; | 91 HType type = input.instructionType; |
| 92 ClassElement constantInterceptor; | 92 ClassElement constantInterceptor; |
| 93 JavaScriptBackend backend = compiler.backend; | 93 JavaScriptBackend backend = compiler.backend; |
| 94 if (type.isInteger()) { | 94 if (type.canBeNull()) { |
| 95 if (type.isNull()) { |
| 96 constantInterceptor = backend.jsNullClass; |
| 97 } |
| 98 } else if (type.isInteger()) { |
| 95 constantInterceptor = backend.jsIntClass; | 99 constantInterceptor = backend.jsIntClass; |
| 96 } else if (type.isDouble()) { | 100 } else if (type.isDouble()) { |
| 97 constantInterceptor = backend.jsDoubleClass; | 101 constantInterceptor = backend.jsDoubleClass; |
| 98 } else if (type.isBoolean()) { | 102 } else if (type.isBoolean()) { |
| 99 constantInterceptor = backend.jsBoolClass; | 103 constantInterceptor = backend.jsBoolClass; |
| 100 } else if (type.isString()) { | 104 } else if (type.isString(compiler)) { |
| 101 constantInterceptor = backend.jsStringClass; | 105 constantInterceptor = backend.jsStringClass; |
| 102 } else if (type.isArray(compiler)) { | 106 } else if (type.isArray(compiler)) { |
| 103 constantInterceptor = backend.jsArrayClass; | 107 constantInterceptor = backend.jsArrayClass; |
| 104 } else if (type.isNull()) { | |
| 105 constantInterceptor = backend.jsNullClass; | |
| 106 } else if (type.isNumber() | 108 } else if (type.isNumber() |
| 107 && !interceptedClasses.contains(backend.jsIntClass) | 109 && !interceptedClasses.contains(backend.jsIntClass) |
| 108 && !interceptedClasses.contains(backend.jsDoubleClass)) { | 110 && !interceptedClasses.contains(backend.jsDoubleClass)) { |
| 109 // If the method being intercepted is not defined in [int] or [double] we | 111 // If the method being intercepted is not defined in [int] or [double] we |
| 110 // can safely use the number interceptor. This is because none of the | 112 // can safely use the number interceptor. This is because none of the |
| 111 // [int] or [double] methods are called from a method defined on [num]. | 113 // [int] or [double] methods are called from a method defined on [num]. |
| 112 constantInterceptor = backend.jsNumberClass; | 114 constantInterceptor = backend.jsNumberClass; |
| 113 } else { | 115 } else { |
| 114 // Try to find constant interceptor for a native class. If the receiver | 116 // Try to find constant interceptor for a native class. If the receiver |
| 115 // is constrained to a leaf native class, we can use the class's | 117 // is constrained to a leaf native class, we can use the class's |
| 116 // interceptor directly. | 118 // interceptor directly. |
| 117 | 119 |
| 118 // TODO(sra): Key DOM classes like Node, Element and Event are not leaf | 120 // TODO(sra): Key DOM classes like Node, Element and Event are not leaf |
| 119 // classes. When the receiver type is not a leaf class, we might still be | 121 // classes. When the receiver type is not a leaf class, we might still be |
| 120 // able to use the receiver class as a constant interceptor. It is | 122 // able to use the receiver class as a constant interceptor. It is |
| 121 // usually the case that methods defined on a non-leaf class don't test | 123 // usually the case that methods defined on a non-leaf class don't test |
| 122 // for a subclass or call methods defined on a subclass. Provided the | 124 // for a subclass or call methods defined on a subclass. Provided the |
| 123 // code is completely insensitive to the specific instance subclasses, we | 125 // code is completely insensitive to the specific instance subclasses, we |
| 124 // can use the non-leaf class directly. | 126 // can use the non-leaf class directly. |
| 125 | 127 ClassElement element = type.computeMask(compiler).singleClass(compiler); |
| 126 if (!type.canBeNull()) { | 128 if (element != null && element.isNative()) { |
| 127 ClassElement element = type.computeMask(compiler).singleClass(compiler); | 129 constantInterceptor = element; |
| 128 if (element != null && element.isNative()) { | |
| 129 constantInterceptor = element; | |
| 130 } | |
| 131 } | 130 } |
| 132 } | 131 } |
| 133 | 132 |
| 134 if (constantInterceptor == null) return null; | 133 if (constantInterceptor == null) return null; |
| 135 if (constantInterceptor == work.element.getEnclosingClass()) { | 134 if (constantInterceptor == work.element.getEnclosingClass()) { |
| 136 return graph.thisInstruction; | 135 return graph.thisInstruction; |
| 137 } | 136 } |
| 138 | 137 |
| 139 Constant constant = new InterceptorConstant( | 138 Constant constant = new InterceptorConstant( |
| 140 constantInterceptor.computeType(compiler)); | 139 constantInterceptor.computeType(compiler)); |
| 141 return graph.addConstant(constant); | 140 return graph.addConstant(constant, compiler); |
| 142 } | 141 } |
| 143 | 142 |
| 144 HInstruction findDominator(Iterable<HInstruction> instructions) { | 143 HInstruction findDominator(Iterable<HInstruction> instructions) { |
| 145 HInstruction result; | 144 HInstruction result; |
| 146 L1: for (HInstruction candidate in instructions) { | 145 L1: for (HInstruction candidate in instructions) { |
| 147 for (HInstruction current in instructions) { | 146 for (HInstruction current in instructions) { |
| 148 if (current != candidate && !candidate.dominates(current)) continue L1; | 147 if (current != candidate && !candidate.dominates(current)) continue L1; |
| 149 } | 148 } |
| 150 result = candidate; | 149 result = candidate; |
| 151 break; | 150 break; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 222 // Try creating a one-shot interceptor. | 221 // Try creating a one-shot interceptor. |
| 223 if (node.usedBy.length != 1) return false; | 222 if (node.usedBy.length != 1) return false; |
| 224 if (node.usedBy[0] is !HInvokeDynamic) return false; | 223 if (node.usedBy[0] is !HInvokeDynamic) return false; |
| 225 | 224 |
| 226 HInvokeDynamic user = node.usedBy[0]; | 225 HInvokeDynamic user = node.usedBy[0]; |
| 227 | 226 |
| 228 // If [node] was loop hoisted, we keep the interceptor. | 227 // If [node] was loop hoisted, we keep the interceptor. |
| 229 if (!user.hasSameLoopHeaderAs(node)) return false; | 228 if (!user.hasSameLoopHeaderAs(node)) return false; |
| 230 | 229 |
| 231 // Replace the user with a [HOneShotInterceptor]. | 230 // Replace the user with a [HOneShotInterceptor]. |
| 232 HConstant nullConstant = graph.addConstantNull(constantSystem); | 231 HConstant nullConstant = graph.addConstantNull(compiler); |
| 233 List<HInstruction> inputs = new List<HInstruction>.from(user.inputs); | 232 List<HInstruction> inputs = new List<HInstruction>.from(user.inputs); |
| 234 inputs[0] = nullConstant; | 233 inputs[0] = nullConstant; |
| 235 HOneShotInterceptor interceptor = new HOneShotInterceptor( | 234 HOneShotInterceptor interceptor = new HOneShotInterceptor( |
| 236 user.selector, inputs, node.interceptedClasses); | 235 user.selector, inputs, node.interceptedClasses); |
| 237 interceptor.sourcePosition = user.sourcePosition; | 236 interceptor.sourcePosition = user.sourcePosition; |
| 238 interceptor.sourceElement = user.sourceElement; | 237 interceptor.sourceElement = user.sourceElement; |
| 239 interceptor.instructionType = user.instructionType; | 238 interceptor.instructionType = user.instructionType; |
| 240 | 239 |
| 241 HBasicBlock block = user.block; | 240 HBasicBlock block = user.block; |
| 242 block.addAfter(user, interceptor); | 241 block.addAfter(user, interceptor); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 273 inputs[0] = constant; | 272 inputs[0] = constant; |
| 274 instruction = new HInvokeDynamicMethod(selector, inputs, true); | 273 instruction = new HInvokeDynamicMethod(selector, inputs, true); |
| 275 } | 274 } |
| 276 | 275 |
| 277 HBasicBlock block = node.block; | 276 HBasicBlock block = node.block; |
| 278 block.addAfter(node, instruction); | 277 block.addAfter(node, instruction); |
| 279 block.rewrite(node, instruction); | 278 block.rewrite(node, instruction); |
| 280 return true; | 279 return true; |
| 281 } | 280 } |
| 282 } | 281 } |
| OLD | NEW |