| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 abstract class OptimizationPhase { | 7 abstract class OptimizationPhase { |
| 8 String get name; | 8 String get name; |
| 9 void visitGraph(HGraph graph); | 9 void visitGraph(HGraph graph); |
| 10 } | 10 } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 51 new SsaDeadPhiEliminator(), | 51 new SsaDeadPhiEliminator(), |
| 52 new SsaConstantFolder(constantSystem, backend, work, types), | 52 new SsaConstantFolder(constantSystem, backend, work, types), |
| 53 new SsaTypePropagator(compiler, types), | 53 new SsaTypePropagator(compiler, types), |
| 54 new SsaReceiverSpecialization(compiler), | 54 new SsaReceiverSpecialization(compiler), |
| 55 new SsaGlobalValueNumberer(compiler, types), | 55 new SsaGlobalValueNumberer(compiler, types), |
| 56 new SsaCodeMotion(), | 56 new SsaCodeMotion(), |
| 57 new SsaValueRangeAnalyzer(constantSystem, types, work), | 57 new SsaValueRangeAnalyzer(constantSystem, types, work), |
| 58 // Previous optimizations may have generated new | 58 // Previous optimizations may have generated new |
| 59 // opportunities for constant folding. | 59 // opportunities for constant folding. |
| 60 new SsaConstantFolder(constantSystem, backend, work, types), | 60 new SsaConstantFolder(constantSystem, backend, work, types), |
| 61 new SsaSimplifyInterceptors(constantSystem), | 61 new SsaSimplifyInterceptors(constantSystem, types), |
| 62 new SsaDeadCodeEliminator(types)]; | 62 new SsaDeadCodeEliminator(types)]; |
| 63 runPhases(graph, phases); | 63 runPhases(graph, phases); |
| 64 if (!speculative) { | 64 if (!speculative) { |
| 65 runPhase(graph, new SsaConstructionFieldTypes(backend, work, types)); | 65 runPhase(graph, new SsaConstructionFieldTypes(backend, work, types)); |
| 66 } | 66 } |
| 67 }); | 67 }); |
| 68 } | 68 } |
| 69 | 69 |
| 70 bool trySpeculativeOptimizations(CodegenWorkItem work, HGraph graph) { | 70 bool trySpeculativeOptimizations(CodegenWorkItem work, HGraph graph) { |
| 71 if (work.element.isField()) { | 71 if (work.element.isField()) { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 visitBasicBlock(HBasicBlock block) { | 143 visitBasicBlock(HBasicBlock block) { |
| 144 HInstruction instruction = block.first; | 144 HInstruction instruction = block.first; |
| 145 while (instruction != null) { | 145 while (instruction != null) { |
| 146 HInstruction next = instruction.next; | 146 HInstruction next = instruction.next; |
| 147 HInstruction replacement = instruction.accept(this); | 147 HInstruction replacement = instruction.accept(this); |
| 148 if (replacement != instruction) { | 148 if (replacement != instruction) { |
| 149 block.rewrite(instruction, replacement); | 149 block.rewrite(instruction, replacement); |
| 150 | 150 |
| 151 // If we can replace [instruction] with [replacement], then | 151 // If we can replace [instruction] with [replacement], then |
| 152 // [replacement]'s type can be narrowed. | 152 // [replacement]'s type can be narrowed. |
| 153 types[replacement] = | 153 types[replacement] = types[replacement].intersection( |
| 154 types[replacement].intersection(types[instruction], compiler); | 154 types[instruction], compiler); |
| 155 replacement.guaranteedType = replacement.guaranteedType.intersection( |
| 156 instruction.guaranteedType, compiler); |
| 155 | 157 |
| 156 // If the replacement instruction does not know its | 158 // If the replacement instruction does not know its |
| 157 // source element, use the source element of the | 159 // source element, use the source element of the |
| 158 // instruction. | 160 // instruction. |
| 159 if (replacement.sourceElement == null) { | 161 if (replacement.sourceElement == null) { |
| 160 replacement.sourceElement = instruction.sourceElement; | 162 replacement.sourceElement = instruction.sourceElement; |
| 161 } | 163 } |
| 162 if (replacement.sourcePosition == null) { | 164 if (replacement.sourcePosition == null) { |
| 163 replacement.sourcePosition = instruction.sourcePosition; | 165 replacement.sourcePosition = instruction.sourcePosition; |
| 164 } | 166 } |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 return result; | 253 return result; |
| 252 } else if (actualReceiver.isConstantMap()) { | 254 } else if (actualReceiver.isConstantMap()) { |
| 253 HConstant constantInput = actualReceiver; | 255 HConstant constantInput = actualReceiver; |
| 254 MapConstant constant = constantInput.constant; | 256 MapConstant constant = constantInput.constant; |
| 255 return graph.addConstantInt(constant.length, constantSystem); | 257 return graph.addConstantInt(constant.length, constantSystem); |
| 256 } | 258 } |
| 257 return node; | 259 return node; |
| 258 } | 260 } |
| 259 | 261 |
| 260 HInstruction handleInterceptorCall(HInvokeDynamic node) { | 262 HInstruction handleInterceptorCall(HInvokeDynamic node) { |
| 261 // We only optimize for intercepted method calls in this method. | |
| 262 Selector selector = node.selector; | |
| 263 | |
| 264 // Try constant folding the instruction. | 263 // Try constant folding the instruction. |
| 265 Operation operation = node.specializer.operation(constantSystem); | 264 Operation operation = node.specializer.operation(constantSystem); |
| 266 if (operation != null) { | 265 if (operation != null) { |
| 267 HInstruction instruction = node.inputs.length == 2 | 266 HInstruction instruction = node.inputs.length == 2 |
| 268 ? foldUnary(operation, node.inputs[1]) | 267 ? foldUnary(operation, node.inputs[1]) |
| 269 : foldBinary(operation, node.inputs[1], node.inputs[2]); | 268 : foldBinary(operation, node.inputs[1], node.inputs[2]); |
| 270 if (instruction != null) return instruction; | 269 if (instruction != null) return instruction; |
| 271 } | 270 } |
| 272 | 271 |
| 273 // Try converting the instruction to a builtin instruction. | 272 // Try converting the instruction to a builtin instruction. |
| 274 HInstruction instruction = | 273 HInstruction instruction = |
| 275 node.specializer.tryConvertToBuiltin(node, types); | 274 node.specializer.tryConvertToBuiltin(node, types); |
| 276 if (instruction != null) return instruction; | 275 if (instruction != null) return instruction; |
| 277 | 276 |
| 278 // Check if this call does not need to be intercepted. | 277 Selector selector = node.selector; |
| 279 HInstruction input = node.inputs[1]; | |
| 280 HType type = types[input]; | |
| 281 var interceptor = node.inputs[0]; | 278 var interceptor = node.inputs[0]; |
| 282 | 279 |
| 283 if (interceptor.isConstant() && selector.isCall()) { | 280 // If the intercepted call is through a constant interceptor, we |
| 281 // know which element to call. |
| 282 if (node is !HOneShotInterceptor |
| 283 && interceptor.isConstant() |
| 284 && selector.isCall()) { |
| 284 DartType type = types[interceptor].computeType(compiler); | 285 DartType type = types[interceptor].computeType(compiler); |
| 285 ClassElement cls = type.element; | 286 ClassElement cls = type.element; |
| 286 node.element = cls.lookupSelector(selector); | 287 node.element = cls.lookupSelector(selector); |
| 287 } | 288 } |
| 288 | 289 |
| 290 HInstruction input = node.inputs[1]; |
| 291 HType type = types[input]; |
| 292 // Check if this call does not need to be intercepted. |
| 289 if (interceptor is !HThis && !type.canBePrimitive()) { | 293 if (interceptor is !HThis && !type.canBePrimitive()) { |
| 290 // If the type can be null, and the intercepted method can be in | 294 // If the type can be null, and the intercepted method can be in |
| 291 // the object class, keep the interceptor. | 295 // the object class, keep the interceptor. |
| 292 if (type.canBeNull()) { | 296 if (type.canBeNull()) { |
| 293 Set<ClassElement> interceptedClasses; | 297 Set<ClassElement> interceptedClasses; |
| 294 if (interceptor is HInterceptor) { | 298 if (interceptor is HInterceptor) { |
| 295 interceptedClasses = interceptor.interceptedClasses; | 299 interceptedClasses = interceptor.interceptedClasses; |
| 296 } else if (node is HOneShotInterceptor) { | 300 } else if (node is HOneShotInterceptor) { |
| 297 var oneShotInterceptor = node; | 301 var oneShotInterceptor = node; |
| 298 interceptedClasses = oneShotInterceptor.interceptedClasses; | 302 interceptedClasses = oneShotInterceptor.interceptedClasses; |
| (...skipping 1196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1495 | 1499 |
| 1496 /** | 1500 /** |
| 1497 * This phase replaces all interceptors that are used only once with | 1501 * This phase replaces all interceptors that are used only once with |
| 1498 * one-shot interceptors. It saves code size and makes the receiver of | 1502 * one-shot interceptors. It saves code size and makes the receiver of |
| 1499 * an intercepted call a candidate for being generated at use site. | 1503 * an intercepted call a candidate for being generated at use site. |
| 1500 */ | 1504 */ |
| 1501 class SsaSimplifyInterceptors extends HBaseVisitor | 1505 class SsaSimplifyInterceptors extends HBaseVisitor |
| 1502 implements OptimizationPhase { | 1506 implements OptimizationPhase { |
| 1503 final String name = "SsaSimplifyInterceptors"; | 1507 final String name = "SsaSimplifyInterceptors"; |
| 1504 final ConstantSystem constantSystem; | 1508 final ConstantSystem constantSystem; |
| 1509 final HTypeMap types; |
| 1505 HGraph graph; | 1510 HGraph graph; |
| 1506 | 1511 |
| 1507 SsaSimplifyInterceptors(this.constantSystem); | 1512 SsaSimplifyInterceptors(this.constantSystem, this.types); |
| 1508 | 1513 |
| 1509 void visitGraph(HGraph graph) { | 1514 void visitGraph(HGraph graph) { |
| 1510 this.graph = graph; | 1515 this.graph = graph; |
| 1511 visitDominatorTree(graph); | 1516 visitDominatorTree(graph); |
| 1512 } | 1517 } |
| 1513 | 1518 |
| 1514 void visitInterceptor(HInterceptor node) { | 1519 void visitInterceptor(HInterceptor node) { |
| 1515 if (node.usedBy.length != 1) return; | 1520 if (node.usedBy.length != 1) return; |
| 1516 // [HBailoutTarget] instructions might have the interceptor as | 1521 // [HBailoutTarget] instructions might have the interceptor as |
| 1517 // input. In such situation we let the dead code analyzer find out | 1522 // input. In such situation we let the dead code analyzer find out |
| 1518 // the interceptor is not needed. | 1523 // the interceptor is not needed. |
| 1519 if (node.usedBy[0] is !HInvokeDynamic) return; | 1524 if (node.usedBy[0] is !HInvokeDynamic) return; |
| 1520 | 1525 |
| 1521 HInvokeDynamic user = node.usedBy[0]; | 1526 HInvokeDynamic user = node.usedBy[0]; |
| 1522 | 1527 |
| 1523 // If [node] was loop hoisted, we keep the interceptor. | 1528 // If [node] was loop hoisted, we keep the interceptor. |
| 1524 if (!user.hasSameLoopHeaderAs(node)) return; | 1529 if (!user.hasSameLoopHeaderAs(node)) return; |
| 1525 | 1530 |
| 1526 // Replace the user with a [HOneShotInterceptor]. | 1531 // Replace the user with a [HOneShotInterceptor]. |
| 1527 HConstant nullConstant = graph.addConstantNull(constantSystem); | 1532 HConstant nullConstant = graph.addConstantNull(constantSystem); |
| 1528 List<HInstruction> inputs = new List<HInstruction>.from(user.inputs); | 1533 List<HInstruction> inputs = new List<HInstruction>.from(user.inputs); |
| 1529 inputs[0] = nullConstant; | 1534 inputs[0] = nullConstant; |
| 1530 HOneShotInterceptor interceptor = new HOneShotInterceptor( | 1535 HOneShotInterceptor interceptor = new HOneShotInterceptor( |
| 1531 user.selector, inputs, node.interceptedClasses); | 1536 user.selector, inputs, node.interceptedClasses); |
| 1532 interceptor.sourcePosition = user.sourcePosition; | 1537 interceptor.sourcePosition = user.sourcePosition; |
| 1533 interceptor.sourceElement = user.sourceElement; | 1538 interceptor.sourceElement = user.sourceElement; |
| 1539 interceptor.guaranteedType = user.guaranteedType; |
| 1540 types[interceptor] = types[user]; |
| 1534 | 1541 |
| 1535 HBasicBlock block = user.block; | 1542 HBasicBlock block = user.block; |
| 1536 block.addAfter(user, interceptor); | 1543 block.addAfter(user, interceptor); |
| 1537 block.rewrite(user, interceptor); | 1544 block.rewrite(user, interceptor); |
| 1538 block.remove(user); | 1545 block.remove(user); |
| 1539 | 1546 |
| 1540 // The interceptor will be removed in the dead code elimination | 1547 // The interceptor will be removed in the dead code elimination |
| 1541 // phase. Note that removing it here would not work because of how | 1548 // phase. Note that removing it here would not work because of how |
| 1542 // the [visitBasicBlock] is implemented. | 1549 // the [visitBasicBlock] is implemented. |
| 1543 } | 1550 } |
| 1544 } | 1551 } |
| OLD | NEW |