| 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 interface OptimizationPhase { | 5 interface OptimizationPhase { |
| 6 String get name(); | 6 String get name(); |
| 7 void visitGraph(HGraph graph); | 7 void visitGraph(HGraph graph); |
| 8 } | 8 } |
| 9 | 9 |
| 10 class SsaOptimizerTask extends CompilerTask { | 10 class SsaOptimizerTask extends CompilerTask { |
| 11 final JavaScriptBackend backend; | 11 final JavaScriptBackend backend; |
| 12 SsaOptimizerTask(JavaScriptBackend backend) | 12 SsaOptimizerTask(JavaScriptBackend backend) |
| 13 : this.backend = backend, | 13 : this.backend = backend, |
| 14 super(backend.compiler); | 14 super(backend.compiler); |
| 15 String get name() => 'SSA optimizer'; | 15 String get name() => 'SSA optimizer'; |
| 16 Compiler get compiler() => backend.compiler; | 16 Compiler get compiler() => backend.compiler; |
| 17 | 17 |
| 18 void runPhases(HGraph graph, List<OptimizationPhase> phases) { | 18 void runPhases(HGraph graph, List<OptimizationPhase> phases) { |
| 19 for (OptimizationPhase phase in phases) { | 19 for (OptimizationPhase phase in phases) { |
| 20 phase.visitGraph(graph); | 20 runPhase(graph, phase); |
| 21 compiler.tracer.traceGraph(phase.name, graph); | |
| 22 } | 21 } |
| 23 } | 22 } |
| 24 | 23 |
| 24 void runPhase(HGraph graph, OptimizationPhase phase) { |
| 25 phase.visitGraph(graph); |
| 26 compiler.tracer.traceGraph(phase.name, graph); |
| 27 } |
| 28 |
| 25 void optimize(WorkItem work, HGraph graph) { | 29 void optimize(WorkItem work, HGraph graph) { |
| 30 JavaScriptItemCompilationContext context = work.compilationContext; |
| 31 HTypeMap types = context.types; |
| 26 measure(() { | 32 measure(() { |
| 27 List<OptimizationPhase> phases = <OptimizationPhase>[ | 33 List<OptimizationPhase> phases = <OptimizationPhase>[ |
| 28 // Run trivial constant folding first to optimize | 34 // Run trivial constant folding first to optimize |
| 29 // some patterns useful for type conversion. | 35 // some patterns useful for type conversion. |
| 30 new SsaConstantFolder(backend, work), | 36 new SsaConstantFolder(backend, work, types), |
| 31 new SsaTypeConversionInserter(compiler), | 37 new SsaTypeConversionInserter(compiler), |
| 32 new SsaTypePropagator(compiler), | 38 new SsaTypePropagator(compiler, types), |
| 33 new SsaCheckInserter(backend), | 39 new SsaCheckInserter(backend, types), |
| 34 new SsaConstantFolder(backend, work), | 40 new SsaConstantFolder(backend, work, types), |
| 35 new SsaRedundantPhiEliminator(), | 41 new SsaRedundantPhiEliminator(), |
| 36 new SsaDeadPhiEliminator(), | 42 new SsaDeadPhiEliminator(), |
| 37 new SsaGlobalValueNumberer(compiler), | 43 new SsaGlobalValueNumberer(compiler, types), |
| 38 new SsaCodeMotion(), | 44 new SsaCodeMotion(), |
| 39 new SsaDeadCodeEliminator(), | 45 new SsaDeadCodeEliminator(types), |
| 40 new SsaRegisterRecompilationCandidates(backend, work)]; | 46 new SsaRegisterRecompilationCandidates(backend, work, types)]; |
| 41 runPhases(graph, phases); | 47 runPhases(graph, phases); |
| 42 }); | 48 }); |
| 43 } | 49 } |
| 44 | 50 |
| 45 bool trySpeculativeOptimizations(WorkItem work, HGraph graph) { | 51 bool trySpeculativeOptimizations(WorkItem work, HGraph graph) { |
| 52 JavaScriptItemCompilationContext context = work.compilationContext; |
| 53 HTypeMap types = context.types; |
| 46 return measure(() { | 54 return measure(() { |
| 47 // Run the phases that will generate type guards. | 55 // Run the phases that will generate type guards. |
| 48 List<OptimizationPhase> phases = <OptimizationPhase>[ | 56 List<OptimizationPhase> phases = <OptimizationPhase>[ |
| 49 new SsaRecompilationFieldTypePropagator(backend, work), | 57 new SsaRecompilationFieldTypePropagator(backend, work, types), |
| 50 new SsaSpeculativeTypePropagator(compiler), | 58 new SsaSpeculativeTypePropagator(compiler, types), |
| 51 new SsaTypeGuardInserter(compiler, work), | 59 new SsaTypeGuardInserter(compiler, work, types), |
| 52 new SsaEnvironmentBuilder(compiler), | 60 new SsaEnvironmentBuilder(compiler), |
| 53 // Change the propagated types back to what they were before we | 61 // Change the propagated types back to what they were before we |
| 54 // speculatively propagated, so that we can generate the bailout | 62 // speculatively propagated, so that we can generate the bailout |
| 55 // version. | 63 // version. |
| 56 // Note that we do this even if there were no guards inserted. If a | 64 // Note that we do this even if there were no guards inserted. If a |
| 57 // guard is not beneficial enough we don't emit one, but there might | 65 // guard is not beneficial enough we don't emit one, but there might |
| 58 // still be speculative types on the instructions. | 66 // still be speculative types on the instructions. |
| 59 new SsaTypePropagator(compiler), | 67 new SsaTypePropagator(compiler, types), |
| 60 // Then run the [SsaCheckInserter] because the type propagator also | 68 // Then run the [SsaCheckInserter] because the type propagator also |
| 61 // propagated types non-speculatively. For example, it might have | 69 // propagated types non-speculatively. For example, it might have |
| 62 // propagated the type array for a call to the List constructor. | 70 // propagated the type array for a call to the List constructor. |
| 63 new SsaCheckInserter(backend)]; | 71 new SsaCheckInserter(backend, types)]; |
| 64 runPhases(graph, phases); | 72 runPhases(graph, phases); |
| 65 return !work.guards.isEmpty(); | 73 return !work.guards.isEmpty(); |
| 66 }); | 74 }); |
| 67 } | 75 } |
| 68 | 76 |
| 69 void prepareForSpeculativeOptimizations(WorkItem work, HGraph graph) { | 77 void prepareForSpeculativeOptimizations(WorkItem work, HGraph graph) { |
| 78 JavaScriptItemCompilationContext context = work.compilationContext; |
| 79 HTypeMap types = context.types; |
| 70 measure(() { | 80 measure(() { |
| 71 // In order to generate correct code for the bailout version, we did not | 81 // In order to generate correct code for the bailout version, we did not |
| 72 // propagate types from the instruction to the type guard. We do it | 82 // propagate types from the instruction to the type guard. We do it |
| 73 // now to be able to optimize further. | 83 // now to be able to optimize further. |
| 74 work.guards.forEach((HTypeGuard guard) { guard.isEnabled = true; }); | 84 work.guards.forEach((HTypeGuard guard) { guard.isEnabled = true; }); |
| 75 // We also need to insert range and integer checks for the type | 85 // We also need to insert range and integer checks for the type |
| 76 // guards. Now that they claim to have a certain type, some | 86 // guards. Now that they claim to have a certain type, some |
| 77 // depending instructions might become builtin (like native array | 87 // depending instructions might become builtin (like native array |
| 78 // accesses) and need to be checked. | 88 // accesses) and need to be checked. |
| 79 // Also run the type propagator, to please the codegen in case | 89 // Also run the type propagator, to please the codegen in case |
| 80 // no other optimization is run. | 90 // no other optimization is run. |
| 81 runPhases(graph, | 91 runPhases(graph, |
| 82 <OptimizationPhase>[new SsaCheckInserter(backend), | 92 <OptimizationPhase>[new SsaCheckInserter(backend, types), |
| 83 new SsaTypePropagator(compiler)]); | 93 new SsaTypePropagator(compiler, types)]); |
| 84 }); | 94 }); |
| 85 } | 95 } |
| 86 } | 96 } |
| 87 | 97 |
| 88 /** | 98 /** |
| 89 * If both inputs to known operations are available execute the operation at | 99 * If both inputs to known operations are available execute the operation at |
| 90 * compile-time. | 100 * compile-time. |
| 91 */ | 101 */ |
| 92 class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { | 102 class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| 93 final String name = "SsaConstantFolder"; | 103 final String name = "SsaConstantFolder"; |
| 94 final JavaScriptBackend backend; | 104 final JavaScriptBackend backend; |
| 95 final WorkItem work; | 105 final WorkItem work; |
| 106 final HTypeMap types; |
| 96 HGraph graph; | 107 HGraph graph; |
| 97 Compiler get compiler() => backend.compiler; | 108 Compiler get compiler() => backend.compiler; |
| 98 | 109 |
| 99 SsaConstantFolder(this.backend, this.work); | 110 SsaConstantFolder(this.backend, this.work, this.types); |
| 100 | 111 |
| 101 void visitGraph(HGraph visitee) { | 112 void visitGraph(HGraph visitee) { |
| 102 graph = visitee; | 113 graph = visitee; |
| 103 visitDominatorTree(visitee); | 114 visitDominatorTree(visitee); |
| 104 } | 115 } |
| 105 | 116 |
| 106 visitBasicBlock(HBasicBlock block) { | 117 visitBasicBlock(HBasicBlock block) { |
| 107 HInstruction instruction = block.first; | 118 HInstruction instruction = block.first; |
| 108 while (instruction !== null) { | 119 while (instruction !== null) { |
| 109 HInstruction next = instruction.next; | 120 HInstruction next = instruction.next; |
| 110 HInstruction replacement = instruction.accept(this); | 121 HInstruction replacement = instruction.accept(this); |
| 111 if (replacement !== instruction) { | 122 if (replacement !== instruction) { |
| 112 if (!replacement.isInBasicBlock()) { | 123 if (!replacement.isInBasicBlock()) { |
| 113 // The constant folding can return an instruction that is already | 124 // The constant folding can return an instruction that is already |
| 114 // part of the graph (like an input), so we only add the replacement | 125 // part of the graph (like an input), so we only add the replacement |
| 115 // if necessary. | 126 // if necessary. |
| 116 block.addAfter(instruction, replacement); | 127 block.addAfter(instruction, replacement); |
| 117 } | 128 } |
| 118 block.rewrite(instruction, replacement); | 129 block.rewrite(instruction, replacement); |
| 119 block.remove(instruction); | 130 block.remove(instruction); |
| 120 // If the replacement instruction does not know its type or | 131 // If the replacement instruction does not know its type or |
| 121 // source element yet, use the type and source element of the | 132 // source element yet, use the type and source element of the |
| 122 // instruction. | 133 // instruction. |
| 123 if (!replacement.propagatedType.isUseful()) { | 134 if (!types[replacement].isUseful()) { |
| 124 replacement.propagatedType = instruction.propagatedType; | 135 types[replacement] = types[instruction]; |
| 125 } | 136 } |
| 126 if (replacement.sourceElement === null) { | 137 if (replacement.sourceElement === null) { |
| 127 replacement.sourceElement = instruction.sourceElement; | 138 replacement.sourceElement = instruction.sourceElement; |
| 128 } | 139 } |
| 129 } | 140 } |
| 130 instruction = next; | 141 instruction = next; |
| 131 } | 142 } |
| 132 } | 143 } |
| 133 | 144 |
| 134 HInstruction visitInstruction(HInstruction node) { | 145 HInstruction visitInstruction(HInstruction node) { |
| 135 return node; | 146 return node; |
| 136 } | 147 } |
| 137 | 148 |
| 138 HInstruction visitBoolify(HBoolify node) { | 149 HInstruction visitBoolify(HBoolify node) { |
| 139 List<HInstruction> inputs = node.inputs; | 150 List<HInstruction> inputs = node.inputs; |
| 140 assert(inputs.length == 1); | 151 assert(inputs.length == 1); |
| 141 HInstruction input = inputs[0]; | 152 HInstruction input = inputs[0]; |
| 142 if (input.isBoolean()) return input; | 153 if (input.isBoolean(types)) return input; |
| 143 // All values !== true are boolified to false. | 154 // All values !== true are boolified to false. |
| 144 Type type = input.propagatedType.computeType(compiler); | 155 Type type = types[input].computeType(compiler); |
| 145 if (type !== null && type.element !== compiler.boolClass) { | 156 if (type !== null && type.element !== compiler.boolClass) { |
| 146 return graph.addConstantBool(false); | 157 return graph.addConstantBool(false); |
| 147 } | 158 } |
| 148 return node; | 159 return node; |
| 149 } | 160 } |
| 150 | 161 |
| 151 HInstruction visitNot(HNot node) { | 162 HInstruction visitNot(HNot node) { |
| 152 List<HInstruction> inputs = node.inputs; | 163 List<HInstruction> inputs = node.inputs; |
| 153 assert(inputs.length == 1); | 164 assert(inputs.length == 1); |
| 154 HInstruction input = inputs[0]; | 165 HInstruction input = inputs[0]; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 184 HConstant constantInput = input; | 195 HConstant constantInput = input; |
| 185 ListConstant constant = constantInput.constant; | 196 ListConstant constant = constantInput.constant; |
| 186 return graph.addConstantInt(constant.length); | 197 return graph.addConstantInt(constant.length); |
| 187 } else if (input.isConstantMap()) { | 198 } else if (input.isConstantMap()) { |
| 188 HConstant constantInput = input; | 199 HConstant constantInput = input; |
| 189 MapConstant constant = constantInput.constant; | 200 MapConstant constant = constantInput.constant; |
| 190 return graph.addConstantInt(constant.length); | 201 return graph.addConstantInt(constant.length); |
| 191 } | 202 } |
| 192 } | 203 } |
| 193 | 204 |
| 194 if (input.isString() | 205 if (input.isString(types) |
| 195 && node.name == const SourceString('toString')) { | 206 && node.name == const SourceString('toString')) { |
| 196 return node.inputs[1]; | 207 return node.inputs[1]; |
| 197 } | 208 } |
| 198 | 209 |
| 199 if (!input.canBePrimitive() && !node.getter && !node.setter) { | 210 if (!input.canBePrimitive(types) && !node.getter && !node.setter) { |
| 200 bool transformToDynamicInvocation = true; | 211 bool transformToDynamicInvocation = true; |
| 201 if (input.canBeNull()) { | 212 if (input.canBeNull(types)) { |
| 202 // Check if the method exists on Null. If yes we must not transform | 213 // Check if the method exists on Null. If yes we must not transform |
| 203 // the static interceptor call to a dynamic invocation. | 214 // the static interceptor call to a dynamic invocation. |
| 204 // TODO(floitsch): get a list of methods that exist on 'null' and only | 215 // TODO(floitsch): get a list of methods that exist on 'null' and only |
| 205 // bail out on them. | 216 // bail out on them. |
| 206 transformToDynamicInvocation = false; | 217 transformToDynamicInvocation = false; |
| 207 } | 218 } |
| 208 if (transformToDynamicInvocation) { | 219 if (transformToDynamicInvocation) { |
| 209 return fromInterceptorToDynamicInvocation(node, node.selector); | 220 return fromInterceptorToDynamicInvocation(node, node.selector); |
| 210 } | 221 } |
| 211 } | 222 } |
| 212 | 223 |
| 213 return node; | 224 return node; |
| 214 } | 225 } |
| 215 | 226 |
| 216 HInstruction visitInvokeDynamic(HInvokeDynamic node) { | 227 HInstruction visitInvokeDynamic(HInvokeDynamic node) { |
| 217 HType receiverType = node.receiver.propagatedType; | 228 HType receiverType = types[node.receiver]; |
| 218 if (receiverType.isExact()) { | 229 if (receiverType.isExact()) { |
| 219 HBoundedType type = receiverType; | 230 HBoundedType type = receiverType; |
| 220 Element element = type.lookupMember(node.name); | 231 Element element = type.lookupMember(node.name); |
| 221 // TODO(ngeoffray): Also fold if it's a getter or variable. | 232 // TODO(ngeoffray): Also fold if it's a getter or variable. |
| 222 if (element != null && element.isFunction()) { | 233 if (element != null && element.isFunction()) { |
| 223 if (node.selector.applies(element, compiler)) { | 234 if (node.selector.applies(element, compiler)) { |
| 224 FunctionElement method = element; | 235 FunctionElement method = element; |
| 225 FunctionSignature parameters = method.computeSignature(compiler); | 236 FunctionSignature parameters = method.computeSignature(compiler); |
| 226 if (parameters.optionalParameterCount == 0) { | 237 if (parameters.optionalParameterCount == 0) { |
| 227 node.element = element; | 238 node.element = element; |
| 228 } | 239 } |
| 229 // TODO(ngeoffray): If the method has optional parameters, | 240 // TODO(ngeoffray): If the method has optional parameters, |
| 230 // we should pass the default values here. | 241 // we should pass the default values here. |
| 231 } | 242 } |
| 232 } | 243 } |
| 233 } | 244 } |
| 234 return node; | 245 return node; |
| 235 } | 246 } |
| 236 | 247 |
| 237 HInstruction fromInterceptorToDynamicInvocation(HInvokeStatic node, | 248 HInstruction fromInterceptorToDynamicInvocation(HInvokeStatic node, |
| 238 Selector selector) { | 249 Selector selector) { |
| 239 HBoundedType type = node.inputs[1].propagatedType; | 250 HBoundedType type = types[node.inputs[1]]; |
| 240 HInvokeDynamicMethod result = new HInvokeDynamicMethod( | 251 HInvokeDynamicMethod result = new HInvokeDynamicMethod( |
| 241 selector, | 252 selector, |
| 242 selector.name, | 253 selector.name, |
| 243 node.inputs.getRange(1, node.inputs.length - 1)); | 254 node.inputs.getRange(1, node.inputs.length - 1)); |
| 244 if (type.isExact()) { | 255 if (type.isExact()) { |
| 245 HBoundedType concrete = type; | 256 HBoundedType concrete = type; |
| 246 result.element = concrete.lookupMember(selector.name); | 257 result.element = concrete.lookupMember(selector.name); |
| 247 } | 258 } |
| 248 return result; | 259 return result; |
| 249 } | 260 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 281 } | 292 } |
| 282 return node; | 293 return node; |
| 283 } | 294 } |
| 284 node.staticChecks = HBoundsCheck.ALWAYS_ABOVE_ZERO; | 295 node.staticChecks = HBoundsCheck.ALWAYS_ABOVE_ZERO; |
| 285 } | 296 } |
| 286 return node; | 297 return node; |
| 287 } | 298 } |
| 288 | 299 |
| 289 HInstruction visitIntegerCheck(HIntegerCheck node) { | 300 HInstruction visitIntegerCheck(HIntegerCheck node) { |
| 290 HInstruction value = node.value; | 301 HInstruction value = node.value; |
| 291 if (value.isInteger()) return value; | 302 if (value.isInteger(types)) return value; |
| 292 if (value.isConstant()) { | 303 if (value.isConstant()) { |
| 293 assert((){ | 304 assert((){ |
| 294 HConstant constantInstruction = value; | 305 HConstant constantInstruction = value; |
| 295 return !constantInstruction.constant.isInt(); | 306 return !constantInstruction.constant.isInt(); |
| 296 }); | 307 }); |
| 297 node.alwaysFalse = true; | 308 node.alwaysFalse = true; |
| 298 } | 309 } |
| 299 return node; | 310 return node; |
| 300 } | 311 } |
| 301 | 312 |
| 302 | 313 |
| 303 HInstruction visitIndex(HIndex node) { | 314 HInstruction visitIndex(HIndex node) { |
| 304 if (!node.receiver.canBePrimitive()) { | 315 if (!node.receiver.canBePrimitive(types)) { |
| 305 Selector selector = new Selector.index(); | 316 Selector selector = new Selector.index(); |
| 306 return fromInterceptorToDynamicInvocation(node, selector); | 317 return fromInterceptorToDynamicInvocation(node, selector); |
| 307 } | 318 } |
| 308 return node; | 319 return node; |
| 309 } | 320 } |
| 310 | 321 |
| 311 HInstruction visitIndexAssign(HIndexAssign node) { | 322 HInstruction visitIndexAssign(HIndexAssign node) { |
| 312 if (!node.receiver.canBePrimitive()) { | 323 if (!node.receiver.canBePrimitive(types)) { |
| 313 Selector selector = new Selector.indexSet(); | 324 Selector selector = new Selector.indexSet(); |
| 314 return fromInterceptorToDynamicInvocation(node, selector); | 325 return fromInterceptorToDynamicInvocation(node, selector); |
| 315 } | 326 } |
| 316 return node; | 327 return node; |
| 317 } | 328 } |
| 318 | 329 |
| 319 HInstruction visitInvokeBinary(HInvokeBinary node) { | 330 HInstruction visitInvokeBinary(HInvokeBinary node) { |
| 320 HInstruction left = node.left; | 331 HInstruction left = node.left; |
| 321 HInstruction right = node.right; | 332 HInstruction right = node.right; |
| 322 if (left is HConstant && right is HConstant) { | 333 if (left is HConstant && right is HConstant) { |
| 323 BinaryOperation operation = node.operation; | 334 BinaryOperation operation = node.operation; |
| 324 HConstant op1 = left; | 335 HConstant op1 = left; |
| 325 HConstant op2 = right; | 336 HConstant op2 = right; |
| 326 Constant folded = operation.fold(op1.constant, op2.constant); | 337 Constant folded = operation.fold(op1.constant, op2.constant); |
| 327 if (folded !== null) return graph.addConstant(folded); | 338 if (folded !== null) return graph.addConstant(folded); |
| 328 } | 339 } |
| 329 | 340 |
| 330 if (!left.canBePrimitive() | 341 if (!left.canBePrimitive(types) |
| 331 && node.operation.isUserDefinable() | 342 && node.operation.isUserDefinable() |
| 332 // The equals operation is being optimized in visitEquals. | 343 // The equals operation is being optimized in visitEquals. |
| 333 && node.operation !== const EqualsOperation()) { | 344 && node.operation !== const EqualsOperation()) { |
| 334 Selector selector = new Selector.binaryOperator(node.operation.name); | 345 Selector selector = new Selector.binaryOperator(node.operation.name); |
| 335 return fromInterceptorToDynamicInvocation(node, selector); | 346 return fromInterceptorToDynamicInvocation(node, selector); |
| 336 } | 347 } |
| 337 return node; | 348 return node; |
| 338 } | 349 } |
| 339 | 350 |
| 340 bool allUsersAreBoolifies(HInstruction instruction) { | 351 bool allUsersAreBoolifies(HInstruction instruction) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 358 // instructions. If it is unused it will be treated as dead code and | 369 // instructions. If it is unused it will be treated as dead code and |
| 359 // discarded. | 370 // discarded. |
| 360 oldTarget.block.addAfter(oldTarget, boolifiedTarget); | 371 oldTarget.block.addAfter(oldTarget, boolifiedTarget); |
| 361 // Remove us as user from the [oldTarget]. | 372 // Remove us as user from the [oldTarget]. |
| 362 oldTarget.removeUser(node); | 373 oldTarget.removeUser(node); |
| 363 // Replace old target with boolified target. | 374 // Replace old target with boolified target. |
| 364 assert(node.target == node.inputs[0]); | 375 assert(node.target == node.inputs[0]); |
| 365 node.inputs[0] = boolifiedTarget; | 376 node.inputs[0] = boolifiedTarget; |
| 366 boolifiedTarget.usedBy.add(node); | 377 boolifiedTarget.usedBy.add(node); |
| 367 node.usesBoolifiedInterceptor = true; | 378 node.usesBoolifiedInterceptor = true; |
| 368 node.propagatedType = HType.BOOLEAN; | 379 types[node] = HType.BOOLEAN; |
| 369 } | 380 } |
| 370 // This node stays the same, but the Boolify node will go away. | 381 // This node stays the same, but the Boolify node will go away. |
| 371 } | 382 } |
| 372 // Note that we still have to call [super] to make sure that we end up | 383 // Note that we still have to call [super] to make sure that we end up |
| 373 // in the remaining optimizations. | 384 // in the remaining optimizations. |
| 374 return super.visitRelational(node); | 385 return super.visitRelational(node); |
| 375 } | 386 } |
| 376 | 387 |
| 377 HInstruction handleIdentityCheck(HInvokeBinary node) { | 388 HInstruction handleIdentityCheck(HInvokeBinary node) { |
| 378 HInstruction left = node.left; | 389 HInstruction left = node.left; |
| 379 HInstruction right = node.right; | 390 HInstruction right = node.right; |
| 380 HType leftType = left.propagatedType; | 391 HType leftType = types[left]; |
| 381 HType rightType = right.propagatedType; | 392 HType rightType = types[right]; |
| 382 assert(!leftType.isConflicting() && !rightType.isConflicting()); | 393 assert(!leftType.isConflicting() && !rightType.isConflicting()); |
| 383 | 394 |
| 384 // We don't optimize on numbers to preserve the runtime semantics. | 395 // We don't optimize on numbers to preserve the runtime semantics. |
| 385 if (!(left.isNumber() && right.isNumber()) && | 396 if (!(left.isNumber(types) && right.isNumber(types)) && |
| 386 leftType.intersection(rightType).isConflicting()) { | 397 leftType.intersection(rightType).isConflicting()) { |
| 387 return graph.addConstantBool(false); | 398 return graph.addConstantBool(false); |
| 388 } | 399 } |
| 389 | 400 |
| 390 if (left.isConstantBoolean() && right.isBoolean()) { | 401 if (left.isConstantBoolean() && right.isBoolean(types)) { |
| 391 HConstant constant = left; | 402 HConstant constant = left; |
| 392 if (constant.constant.isTrue()) { | 403 if (constant.constant.isTrue()) { |
| 393 return right; | 404 return right; |
| 394 } else { | 405 } else { |
| 395 return new HNot(right); | 406 return new HNot(right); |
| 396 } | 407 } |
| 397 } | 408 } |
| 398 | 409 |
| 399 if (right.isConstantBoolean() && left.isBoolean()) { | 410 if (right.isConstantBoolean() && left.isBoolean(types)) { |
| 400 HConstant constant = right; | 411 HConstant constant = right; |
| 401 if (constant.constant.isTrue()) { | 412 if (constant.constant.isTrue()) { |
| 402 return left; | 413 return left; |
| 403 } else { | 414 } else { |
| 404 return new HNot(left); | 415 return new HNot(left); |
| 405 } | 416 } |
| 406 } | 417 } |
| 407 | 418 |
| 408 return null; | 419 return null; |
| 409 } | 420 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 423 return new HIdentity(target, node.left, node.right); | 434 return new HIdentity(target, node.left, node.right); |
| 424 } else { | 435 } else { |
| 425 return newInstruction; | 436 return newInstruction; |
| 426 } | 437 } |
| 427 } | 438 } |
| 428 | 439 |
| 429 HInstruction visitEquals(HEquals node) { | 440 HInstruction visitEquals(HEquals node) { |
| 430 HInstruction left = node.left; | 441 HInstruction left = node.left; |
| 431 HInstruction right = node.right; | 442 HInstruction right = node.right; |
| 432 | 443 |
| 433 if (node.builtin) { | 444 if (node.isBuiltin(types)) { |
| 434 return foldBuiltinEqualsCheck(node); | 445 return foldBuiltinEqualsCheck(node); |
| 435 } | 446 } |
| 436 | 447 |
| 437 if (left.isConstant() && right.isConstant()) { | 448 if (left.isConstant() && right.isConstant()) { |
| 438 return super.visitEquals(node); | 449 return super.visitEquals(node); |
| 439 } | 450 } |
| 440 | 451 |
| 441 if (left.propagatedType.isExact()) { | 452 HType leftType = types[left]; |
| 442 HBoundedType type = left.propagatedType; | 453 if (leftType.isExact()) { |
| 454 HBoundedType type = leftType; |
| 443 Element element = type.lookupMember(Elements.OPERATOR_EQUALS); | 455 Element element = type.lookupMember(Elements.OPERATOR_EQUALS); |
| 444 if (element !== null) { | 456 if (element !== null) { |
| 445 // If the left-hand side is guaranteed to be a non-primitive | 457 // If the left-hand side is guaranteed to be a non-primitive |
| 446 // type and and it defines operator==, we emit a call to that | 458 // type and and it defines operator==, we emit a call to that |
| 447 // operator. | 459 // operator. |
| 448 return super.visitEquals(node); | 460 return super.visitEquals(node); |
| 449 } else if (right.isConstantNull()) { | 461 } else if (right.isConstantNull()) { |
| 450 return graph.addConstantBool(false); | 462 return graph.addConstantBool(false); |
| 451 } else { | 463 } else { |
| 452 // We can just emit an identity check because the type does | 464 // We can just emit an identity check because the type does |
| 453 // not implement operator=. | 465 // not implement operator=. |
| 454 return foldBuiltinEqualsCheck(node); | 466 return foldBuiltinEqualsCheck(node); |
| 455 } | 467 } |
| 456 } | 468 } |
| 457 | 469 |
| 458 if (right.isConstantNull()) { | 470 if (right.isConstantNull()) { |
| 459 if (left.propagatedType.isPrimitive()) { | 471 if (leftType.isPrimitive()) { |
| 460 return graph.addConstantBool(false); | 472 return graph.addConstantBool(false); |
| 461 } | 473 } |
| 462 } | 474 } |
| 463 | 475 |
| 464 // All other cases are dealt with by the [visitRelational] and | 476 // All other cases are dealt with by the [visitRelational] and |
| 465 // [visitInvokeBinary], which are visited by invoking the [super]'s | 477 // [visitInvokeBinary], which are visited by invoking the [super]'s |
| 466 // visit method. | 478 // visit method. |
| 467 return super.visitEquals(node); | 479 return super.visitEquals(node); |
| 468 } | 480 } |
| 469 | 481 |
| 470 HInstruction visitTypeGuard(HTypeGuard node) { | 482 HInstruction visitTypeGuard(HTypeGuard node) { |
| 471 HInstruction value = node.guarded; | 483 HInstruction value = node.guarded; |
| 472 // If the intersection of the types is still the incoming type then | 484 // If the intersection of the types is still the incoming type then |
| 473 // the incoming type was a subtype of the guarded type, and no check | 485 // the incoming type was a subtype of the guarded type, and no check |
| 474 // is required. | 486 // is required. |
| 475 HType combinedType = value.propagatedType.intersection(node.guardedType); | 487 HType combinedType = types[value].intersection(node.guardedType); |
| 476 return (combinedType == value.propagatedType) ? value : node; | 488 return (combinedType == types[value]) ? value : node; |
| 477 } | 489 } |
| 478 | 490 |
| 479 HInstruction visitIs(HIs node) { | 491 HInstruction visitIs(HIs node) { |
| 480 Type type = node.typeExpression; | 492 Type type = node.typeExpression; |
| 481 Element element = type.element; | 493 Element element = type.element; |
| 482 if (element.kind === ElementKind.TYPE_VARIABLE) { | 494 if (element.kind === ElementKind.TYPE_VARIABLE) { |
| 483 compiler.unimplemented("visitIs for type variables"); | 495 compiler.unimplemented("visitIs for type variables"); |
| 484 } | 496 } |
| 485 | 497 |
| 486 HType expressionType = node.expression.propagatedType; | 498 HType expressionType = types[node.expression]; |
| 487 if (element === compiler.objectClass | 499 if (element === compiler.objectClass |
| 488 || element === compiler.dynamicClass) { | 500 || element === compiler.dynamicClass) { |
| 489 return graph.addConstantBool(true); | 501 return graph.addConstantBool(true); |
| 490 } else if (expressionType.isInteger()) { | 502 } else if (expressionType.isInteger()) { |
| 491 if (element === compiler.intClass || element === compiler.numClass) { | 503 if (element === compiler.intClass || element === compiler.numClass) { |
| 492 return graph.addConstantBool(true); | 504 return graph.addConstantBool(true); |
| 493 } else if (element === compiler.doubleClass) { | 505 } else if (element === compiler.doubleClass) { |
| 494 // We let the JS semantics decide for that check. Currently | 506 // We let the JS semantics decide for that check. Currently |
| 495 // the code we emit will always return true. | 507 // the code we emit will always return true. |
| 496 return node; | 508 return node; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 539 } else if (expressionType.isExact()) { | 551 } else if (expressionType.isExact()) { |
| 540 return graph.addConstantBool(false); | 552 return graph.addConstantBool(false); |
| 541 } | 553 } |
| 542 } | 554 } |
| 543 } | 555 } |
| 544 return node; | 556 return node; |
| 545 } | 557 } |
| 546 | 558 |
| 547 HInstruction visitTypeConversion(HTypeConversion node) { | 559 HInstruction visitTypeConversion(HTypeConversion node) { |
| 548 HInstruction value = node.inputs[0]; | 560 HInstruction value = node.inputs[0]; |
| 549 Type type = node.propagatedType.computeType(compiler); | 561 Type type = types[node].computeType(compiler); |
| 550 if (type.element === compiler.dynamicClass | 562 if (type.element === compiler.dynamicClass |
| 551 || type.element === compiler.objectClass) { | 563 || type.element === compiler.objectClass) { |
| 552 return value; | 564 return value; |
| 553 } | 565 } |
| 554 HType combinedType = value.propagatedType.intersection(node.propagatedType); | 566 HType combinedType = types[value].intersection(types[node]); |
| 555 return (combinedType == value.propagatedType) ? value : node; | 567 return (combinedType == types[value]) ? value : node; |
| 556 } | 568 } |
| 557 | 569 |
| 558 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { | 570 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { |
| 559 HInstruction receiver = node.inputs[0]; | 571 HInstruction receiver = node.inputs[0]; |
| 560 if (!receiver.propagatedType.isUseful()) return node; | 572 HType receiverType = types[receiver]; |
| 561 if (receiver.propagatedType.canBeNull()) return node; | 573 if (!receiverType.isUseful()) return node; |
| 562 Type type = receiver.propagatedType.computeType(compiler); | 574 if (receiverType.canBeNull()) return node; |
| 575 Type type = receiverType.computeType(compiler); |
| 563 if (type === null) return node; | 576 if (type === null) return node; |
| 564 Element field = compiler.world.locateSingleField(type, node.name); | 577 Element field = compiler.world.locateSingleField(type, node.name); |
| 565 if (field === null) return node; | 578 if (field === null) return node; |
| 566 if (node.name.isPrivate() && | 579 if (node.name.isPrivate() && |
| 567 field.getLibrary() !== work.element.getLibrary()) { | 580 field.getLibrary() !== work.element.getLibrary()) { |
| 568 return node; | 581 return node; |
| 569 } | 582 } |
| 570 Modifiers modifiers = field.modifiers; | 583 Modifiers modifiers = field.modifiers; |
| 571 bool isFinalOrConst = false; | 584 bool isFinalOrConst = false; |
| 572 if (modifiers != null) { | 585 if (modifiers != null) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 592 isFinalOrConst = true; | 605 isFinalOrConst = true; |
| 593 break; | 606 break; |
| 594 } | 607 } |
| 595 } | 608 } |
| 596 return new HFieldGet.withElement( | 609 return new HFieldGet.withElement( |
| 597 field, node.inputs[0], isFinalOrConst: isFinalOrConst); | 610 field, node.inputs[0], isFinalOrConst: isFinalOrConst); |
| 598 } | 611 } |
| 599 | 612 |
| 600 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { | 613 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
| 601 HInstruction receiver = node.inputs[0]; | 614 HInstruction receiver = node.inputs[0]; |
| 602 if (!receiver.propagatedType.isUseful()) return node; | 615 HType receiverType = types[receiver]; |
| 603 if (receiver.propagatedType.canBeNull()) return node; | 616 if (!receiverType.isUseful()) return node; |
| 604 Type type = receiver.propagatedType.computeType(compiler); | 617 if (receiverType.canBeNull()) return node; |
| 618 Type type = receiverType.computeType(compiler); |
| 605 if (type === null) return node; | 619 if (type === null) return node; |
| 606 Element field = compiler.world.locateSingleField(type, node.name); | 620 Element field = compiler.world.locateSingleField(type, node.name); |
| 607 if (field === null) return node; | 621 if (field === null) return node; |
| 608 return new HFieldSet.withElement(field, node.inputs[0], node.inputs[1]); | 622 return new HFieldSet.withElement(field, node.inputs[0], node.inputs[1]); |
| 609 } | 623 } |
| 610 | 624 |
| 611 HInstruction visitStringConcat(HStringConcat node) { | 625 HInstruction visitStringConcat(HStringConcat node) { |
| 612 DartString folded = const LiteralDartString(""); | 626 DartString folded = const LiteralDartString(""); |
| 613 for (int i = 0; i < node.inputs.length; i++) { | 627 for (int i = 0; i < node.inputs.length; i++) { |
| 614 HInstruction part = node.inputs[i]; | 628 HInstruction part = node.inputs[i]; |
| 615 if (!part.isConstant()) return node; | 629 if (!part.isConstant()) return node; |
| 616 HConstant constant = part; | 630 HConstant constant = part; |
| 617 if (!constant.constant.isPrimitive()) return node; | 631 if (!constant.constant.isPrimitive()) return node; |
| 618 PrimitiveConstant primitive = constant.constant; | 632 PrimitiveConstant primitive = constant.constant; |
| 619 folded = new DartString.concat(folded, primitive.toDartString()); | 633 folded = new DartString.concat(folded, primitive.toDartString()); |
| 620 } | 634 } |
| 621 return graph.addConstantString(folded, node.node); | 635 return graph.addConstantString(folded, node.node); |
| 622 } | 636 } |
| 623 } | 637 } |
| 624 | 638 |
| 625 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { | 639 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { |
| 640 final HTypeMap types; |
| 626 final String name = "SsaCheckInserter"; | 641 final String name = "SsaCheckInserter"; |
| 627 Element lengthInterceptor; | 642 Element lengthInterceptor; |
| 628 | 643 |
| 629 SsaCheckInserter(JavaScriptBackend backend) { | 644 SsaCheckInserter(JavaScriptBackend backend, this.types) { |
| 630 SourceString lengthString = const SourceString('length'); | 645 SourceString lengthString = const SourceString('length'); |
| 631 lengthInterceptor = | 646 lengthInterceptor = |
| 632 backend.builder.interceptors.getStaticGetInterceptor(lengthString); | 647 backend.builder.interceptors.getStaticGetInterceptor(lengthString); |
| 633 } | 648 } |
| 634 | 649 |
| 635 void visitGraph(HGraph graph) { | 650 void visitGraph(HGraph graph) { |
| 636 visitDominatorTree(graph); | 651 visitDominatorTree(graph); |
| 637 } | 652 } |
| 638 | 653 |
| 639 void visitBasicBlock(HBasicBlock block) { | 654 void visitBasicBlock(HBasicBlock block) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 652 node.block.addBefore(node, interceptor); | 667 node.block.addBefore(node, interceptor); |
| 653 Selector selector = new Selector.call( | 668 Selector selector = new Selector.call( |
| 654 lengthInterceptor.name, | 669 lengthInterceptor.name, |
| 655 lengthInterceptor.getLibrary(), // TODO(kasperl): Wrong. | 670 lengthInterceptor.getLibrary(), // TODO(kasperl): Wrong. |
| 656 0); | 671 0); |
| 657 HInvokeInterceptor length = new HInvokeInterceptor( | 672 HInvokeInterceptor length = new HInvokeInterceptor( |
| 658 selector, | 673 selector, |
| 659 const SourceString("length"), | 674 const SourceString("length"), |
| 660 <HInstruction>[interceptor, receiver], | 675 <HInstruction>[interceptor, receiver], |
| 661 getter: true); | 676 getter: true); |
| 662 length.propagatedType = HType.INTEGER; | 677 types[length] = HType.INTEGER; |
| 663 node.block.addBefore(node, length); | 678 node.block.addBefore(node, length); |
| 664 | 679 |
| 665 HBoundsCheck check = new HBoundsCheck(index, length); | 680 HBoundsCheck check = new HBoundsCheck(index, length); |
| 666 node.block.addBefore(node, check); | 681 node.block.addBefore(node, check); |
| 667 return check; | 682 return check; |
| 668 } | 683 } |
| 669 | 684 |
| 670 HIntegerCheck insertIntegerCheck(HInstruction node, HInstruction value) { | 685 HIntegerCheck insertIntegerCheck(HInstruction node, HInstruction value) { |
| 671 HIntegerCheck check = new HIntegerCheck(value); | 686 HIntegerCheck check = new HIntegerCheck(value); |
| 672 node.block.addBefore(node, check); | 687 node.block.addBefore(node, check); |
| 673 Set<HInstruction> dominatedUsers = value.dominatedUsers(check); | 688 Set<HInstruction> dominatedUsers = value.dominatedUsers(check); |
| 674 for (HInstruction user in dominatedUsers) { | 689 for (HInstruction user in dominatedUsers) { |
| 675 user.changeUse(value, check); | 690 user.changeUse(value, check); |
| 676 } | 691 } |
| 677 return check; | 692 return check; |
| 678 } | 693 } |
| 679 | 694 |
| 680 void visitIndex(HIndex node) { | 695 void visitIndex(HIndex node) { |
| 681 if (!node.receiver.isIndexablePrimitive()) return; | 696 if (!node.receiver.isIndexablePrimitive(types)) return; |
| 682 HInstruction index = node.index; | 697 HInstruction index = node.index; |
| 683 if (index is HBoundsCheck) return; | 698 if (index is HBoundsCheck) return; |
| 684 if (!node.index.isInteger()) { | 699 if (!node.index.isInteger(types)) { |
| 685 index = insertIntegerCheck(node, index); | 700 index = insertIntegerCheck(node, index); |
| 686 } | 701 } |
| 687 index = insertBoundsCheck(node, node.receiver, index); | 702 index = insertBoundsCheck(node, node.receiver, index); |
| 688 node.changeUse(node.index, index); | 703 node.changeUse(node.index, index); |
| 689 } | 704 } |
| 690 | 705 |
| 691 void visitIndexAssign(HIndexAssign node) { | 706 void visitIndexAssign(HIndexAssign node) { |
| 692 if (!node.receiver.isMutableArray()) return; | 707 if (!node.receiver.isMutableArray(types)) return; |
| 693 HInstruction index = node.index; | 708 HInstruction index = node.index; |
| 694 if (index is HBoundsCheck) return; | 709 if (index is HBoundsCheck) return; |
| 695 if (!node.index.isInteger()) { | 710 if (!node.index.isInteger(types)) { |
| 696 index = insertIntegerCheck(node, index); | 711 index = insertIntegerCheck(node, index); |
| 697 } | 712 } |
| 698 index = insertBoundsCheck(node, node.receiver, index); | 713 index = insertBoundsCheck(node, node.receiver, index); |
| 699 node.changeUse(node.index, index); | 714 node.changeUse(node.index, index); |
| 700 } | 715 } |
| 701 } | 716 } |
| 702 | 717 |
| 703 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { | 718 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { |
| 719 final HTypeMap types; |
| 704 final String name = "SsaDeadCodeEliminator"; | 720 final String name = "SsaDeadCodeEliminator"; |
| 705 | 721 |
| 706 static bool isDeadCode(HInstruction instruction) { | 722 SsaDeadCodeEliminator(this.types); |
| 707 return !instruction.hasSideEffects() | 723 |
| 724 bool isDeadCode(HInstruction instruction) { |
| 725 return !instruction.hasSideEffects(types) |
| 708 && instruction.usedBy.isEmpty() | 726 && instruction.usedBy.isEmpty() |
| 709 && instruction is !HCheck | 727 && instruction is !HCheck |
| 710 && instruction is !HTypeGuard | 728 && instruction is !HTypeGuard |
| 711 && !instruction.isControlFlow(); | 729 && !instruction.isControlFlow(); |
| 712 } | 730 } |
| 713 | 731 |
| 714 void visitGraph(HGraph graph) { | 732 void visitGraph(HGraph graph) { |
| 715 visitPostDominatorTree(graph); | 733 visitPostDominatorTree(graph); |
| 716 } | 734 } |
| 717 | 735 |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 824 } | 842 } |
| 825 phi.block.rewrite(phi, candidate); | 843 phi.block.rewrite(phi, candidate); |
| 826 phi.block.removePhi(phi); | 844 phi.block.removePhi(phi); |
| 827 } | 845 } |
| 828 } | 846 } |
| 829 } | 847 } |
| 830 | 848 |
| 831 class SsaGlobalValueNumberer implements OptimizationPhase { | 849 class SsaGlobalValueNumberer implements OptimizationPhase { |
| 832 final String name = "SsaGlobalValueNumberer"; | 850 final String name = "SsaGlobalValueNumberer"; |
| 833 final Compiler compiler; | 851 final Compiler compiler; |
| 852 final HTypeMap types; |
| 834 final Set<int> visited; | 853 final Set<int> visited; |
| 835 | 854 |
| 836 List<int> blockChangesFlags; | 855 List<int> blockChangesFlags; |
| 837 List<int> loopChangesFlags; | 856 List<int> loopChangesFlags; |
| 838 | 857 |
| 839 SsaGlobalValueNumberer(this.compiler) : visited = new Set<int>(); | 858 SsaGlobalValueNumberer(this.compiler, this.types) : visited = new Set<int>(); |
| 840 | 859 |
| 841 void visitGraph(HGraph graph) { | 860 void visitGraph(HGraph graph) { |
| 842 computeChangesFlags(graph); | 861 computeChangesFlags(graph); |
| 843 moveLoopInvariantCode(graph); | 862 moveLoopInvariantCode(graph); |
| 844 visitBasicBlock(graph.entry, new ValueSet()); | 863 visitBasicBlock(graph.entry, new ValueSet()); |
| 845 } | 864 } |
| 846 | 865 |
| 847 void moveLoopInvariantCode(HGraph graph) { | 866 void moveLoopInvariantCode(HGraph graph) { |
| 848 for (int i = graph.blocks.length - 1; i >= 0; i--) { | 867 for (int i = graph.blocks.length - 1; i >= 0; i--) { |
| 849 HBasicBlock block = graph.blocks[i]; | 868 HBasicBlock block = graph.blocks[i]; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 955 // Run through all the basic blocks in the graph and fill in the | 974 // Run through all the basic blocks in the graph and fill in the |
| 956 // changes flags lists. | 975 // changes flags lists. |
| 957 for (int i = length - 1; i >= 0; i--) { | 976 for (int i = length - 1; i >= 0; i--) { |
| 958 final HBasicBlock block = graph.blocks[i]; | 977 final HBasicBlock block = graph.blocks[i]; |
| 959 final int id = block.id; | 978 final int id = block.id; |
| 960 | 979 |
| 961 // Compute block changes flags for the block. | 980 // Compute block changes flags for the block. |
| 962 int changesFlags = 0; | 981 int changesFlags = 0; |
| 963 HInstruction instruction = block.first; | 982 HInstruction instruction = block.first; |
| 964 while (instruction !== null) { | 983 while (instruction !== null) { |
| 965 instruction.prepareGvn(); | 984 instruction.prepareGvn(types); |
| 966 changesFlags |= instruction.getChangesFlags(); | 985 changesFlags |= instruction.getChangesFlags(); |
| 967 instruction = instruction.next; | 986 instruction = instruction.next; |
| 968 } | 987 } |
| 969 assert(blockChangesFlags[id] === null); | 988 assert(blockChangesFlags[id] === null); |
| 970 blockChangesFlags[id] = changesFlags; | 989 blockChangesFlags[id] = changesFlags; |
| 971 | 990 |
| 972 // Loop headers are part of their loop, so update the loop | 991 // Loop headers are part of their loop, so update the loop |
| 973 // changes flags accordingly. | 992 // changes flags accordingly. |
| 974 if (block.isLoopHeader()) { | 993 if (block.isLoopHeader()) { |
| 975 loopChangesFlags[id] |= changesFlags; | 994 loopChangesFlags[id] |= changesFlags; |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1163 } | 1182 } |
| 1164 } | 1183 } |
| 1165 } | 1184 } |
| 1166 | 1185 |
| 1167 | 1186 |
| 1168 // Base class for the handling of recompilation based on inferred | 1187 // Base class for the handling of recompilation based on inferred |
| 1169 // field types. | 1188 // field types. |
| 1170 class BaseRecompilationVisitor extends HBaseVisitor { | 1189 class BaseRecompilationVisitor extends HBaseVisitor { |
| 1171 final JavaScriptBackend backend; | 1190 final JavaScriptBackend backend; |
| 1172 final WorkItem work; | 1191 final WorkItem work; |
| 1192 final HTypeMap types; |
| 1173 Compiler get compiler() => backend.compiler; | 1193 Compiler get compiler() => backend.compiler; |
| 1174 | 1194 |
| 1175 BaseRecompilationVisitor(this.backend, this.work); | 1195 BaseRecompilationVisitor(this.backend, this.work, this.types); |
| 1176 | 1196 |
| 1177 abstract void handleFieldGet(HFieldGet node, HType type); | 1197 abstract void handleFieldGet(HFieldGet node, HType type); |
| 1178 abstract void handleFieldNumberOperation(HFieldGet field, HType type); | 1198 abstract void handleFieldNumberOperation(HFieldGet field, HType type); |
| 1179 | 1199 |
| 1180 // Checks if the binary invocation operates on a field and a | 1200 // Checks if the binary invocation operates on a field and a |
| 1181 // constant number. If it does [handleFieldNumberOperation] is | 1201 // constant number. If it does [handleFieldNumberOperation] is |
| 1182 // called with the field and the type inferred for the field so far. | 1202 // called with the field and the type inferred for the field so far. |
| 1183 void checkFieldNumberOperation(HInvokeBinary node) { | 1203 void checkFieldNumberOperation(HInvokeBinary node) { |
| 1184 // Determine if one of the operands is an HFieldGet. | 1204 // Determine if one of the operands is an HFieldGet. |
| 1185 HFieldGet field; | 1205 HFieldGet field; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1235 } | 1255 } |
| 1236 } | 1256 } |
| 1237 | 1257 |
| 1238 | 1258 |
| 1239 // Visitor that registers candidates for recompilation. | 1259 // Visitor that registers candidates for recompilation. |
| 1240 class SsaRegisterRecompilationCandidates | 1260 class SsaRegisterRecompilationCandidates |
| 1241 extends BaseRecompilationVisitor implements OptimizationPhase { | 1261 extends BaseRecompilationVisitor implements OptimizationPhase { |
| 1242 final String name = "SsaRegisterRecompileCandidates"; | 1262 final String name = "SsaRegisterRecompileCandidates"; |
| 1243 HGraph graph; | 1263 HGraph graph; |
| 1244 | 1264 |
| 1245 SsaRegisterRecompilationCandidates( | 1265 SsaRegisterRecompilationCandidates(JavaScriptBackend backend, |
| 1246 JavaScriptBackend backend, WorkItem work) : super(backend, work); | 1266 WorkItem work, |
| 1267 HTypeMap types) |
| 1268 : super(backend, work, types); |
| 1247 | 1269 |
| 1248 void visitGraph(HGraph visitee) { | 1270 void visitGraph(HGraph visitee) { |
| 1249 graph = visitee; | 1271 graph = visitee; |
| 1250 if (compiler.phase == Compiler.PHASE_COMPILING) { | 1272 if (compiler.phase == Compiler.PHASE_COMPILING) { |
| 1251 visitDominatorTree(visitee); | 1273 visitDominatorTree(visitee); |
| 1252 } | 1274 } |
| 1253 } | 1275 } |
| 1254 | 1276 |
| 1255 void handleFieldGet(HFieldGet node, HType type) { | 1277 void handleFieldGet(HFieldGet node, HType type) { |
| 1256 assert(compiler.phase == Compiler.PHASE_COMPILING); | 1278 assert(compiler.phase == Compiler.PHASE_COMPILING); |
| 1257 compiler.enqueuer.codegen.registerRecompilationCandidate( | 1279 compiler.enqueuer.codegen.registerRecompilationCandidate( |
| 1258 work.element); | 1280 work.element); |
| 1259 } | 1281 } |
| 1260 | 1282 |
| 1261 void handleFieldNumberOperation(HFieldGet node, HType type) { | 1283 void handleFieldNumberOperation(HFieldGet node, HType type) { |
| 1262 assert(compiler.phase == Compiler.PHASE_COMPILING); | 1284 assert(compiler.phase == Compiler.PHASE_COMPILING); |
| 1263 compiler.enqueuer.codegen.registerRecompilationCandidate( | 1285 compiler.enqueuer.codegen.registerRecompilationCandidate( |
| 1264 work.element); | 1286 work.element); |
| 1265 } | 1287 } |
| 1266 } | 1288 } |
| 1267 | 1289 |
| 1268 | 1290 |
| 1269 // Visitor that sets the known or suspected type of fields during | 1291 // Visitor that sets the known or suspected type of fields during |
| 1270 // recompilation. | 1292 // recompilation. |
| 1271 class SsaRecompilationFieldTypePropagator | 1293 class SsaRecompilationFieldTypePropagator |
| 1272 extends BaseRecompilationVisitor implements OptimizationPhase { | 1294 extends BaseRecompilationVisitor implements OptimizationPhase { |
| 1273 final String name = "SsaRecompilationFieldTypePropagator"; | 1295 final String name = "SsaRecompilationFieldTypePropagator"; |
| 1274 HGraph graph; | 1296 HGraph graph; |
| 1275 | 1297 |
| 1276 SsaRecompilationFieldTypePropagator( | 1298 SsaRecompilationFieldTypePropagator(JavaScriptBackend backend, |
| 1277 JavaScriptBackend backend, WorkItem work) : super(backend, work); | 1299 WorkItem work, |
| 1300 HTypeMap types) |
| 1301 : super(backend, work, types); |
| 1278 | 1302 |
| 1279 void visitGraph(HGraph visitee) { | 1303 void visitGraph(HGraph visitee) { |
| 1280 graph = visitee; | 1304 graph = visitee; |
| 1281 if (compiler.phase == Compiler.PHASE_RECOMPILING) { | 1305 if (compiler.phase == Compiler.PHASE_RECOMPILING) { |
| 1282 visitDominatorTree(visitee); | 1306 visitDominatorTree(visitee); |
| 1283 } | 1307 } |
| 1284 } | 1308 } |
| 1285 | 1309 |
| 1286 void handleFieldGet(HFieldGet field, HType type) { | 1310 void handleFieldGet(HFieldGet field, HType type) { |
| 1287 assert(compiler.phase == Compiler.PHASE_RECOMPILING); | 1311 assert(compiler.phase == Compiler.PHASE_RECOMPILING); |
| 1288 if (!type.isConflicting()) { | 1312 if (!type.isConflicting()) { |
| 1289 // If there are no invoked setters with this name, the union of | 1313 // If there are no invoked setters with this name, the union of |
| 1290 // the types of the initializers and the setters is guaranteed | 1314 // the types of the initializers and the setters is guaranteed |
| 1291 // otherwise it is only speculative. | 1315 // otherwise it is only speculative. |
| 1292 Element element = field.element; | 1316 Element element = field.element; |
| 1293 assert(!element.isGenerativeConstructorBody()); | 1317 assert(!element.isGenerativeConstructorBody()); |
| 1294 if (!compiler.codegenWorld.hasInvokedSetter(element, compiler)) { | 1318 if (!compiler.codegenWorld.hasInvokedSetter(element, compiler)) { |
| 1295 field.guaranteedType = | 1319 field.guaranteedType = |
| 1296 type.union(backend.fieldSettersTypeSoFar(element)); | 1320 type.union(backend.fieldSettersTypeSoFar(element)); |
| 1297 } else { | 1321 } else { |
| 1298 field.propagatedType = | 1322 types[field] = type.union(backend.fieldSettersTypeSoFar(element)); |
| 1299 type.union(backend.fieldSettersTypeSoFar(element)); | |
| 1300 } | 1323 } |
| 1301 } | 1324 } |
| 1302 } | 1325 } |
| 1303 | 1326 |
| 1304 void handleFieldNumberOperation(HFieldGet field, HType type) { | 1327 void handleFieldNumberOperation(HFieldGet field, HType type) { |
| 1305 assert(compiler.phase == Compiler.PHASE_RECOMPILING); | 1328 assert(compiler.phase == Compiler.PHASE_RECOMPILING); |
| 1306 if (compiler.codegenWorld.hasInvokedSetter(field.element, compiler)) { | 1329 if (compiler.codegenWorld.hasInvokedSetter(field.element, compiler)) { |
| 1307 // If there are invoked setters we don't know for sure | 1330 // If there are invoked setters we don't know for sure |
| 1308 // that the field will hold a value of the calculated | 1331 // that the field will hold a value of the calculated |
| 1309 // type, but the fact that the class itself sticks to | 1332 // type, but the fact that the class itself sticks to |
| 1310 // this type for the field is still a strong signal | 1333 // this type for the field is still a strong signal |
| 1311 // indicating the expected type of the field. | 1334 // indicating the expected type of the field. |
| 1312 field.propagatedType = type; | 1335 types[field] = type; |
| 1313 } else { | 1336 } else { |
| 1314 // If there are no invoked setters we know the type of | 1337 // If there are no invoked setters we know the type of |
| 1315 // this field for sure. | 1338 // this field for sure. |
| 1316 field.guaranteedType = type; | 1339 field.guaranteedType = type; |
| 1317 } | 1340 } |
| 1318 } | 1341 } |
| 1319 } | 1342 } |
| OLD | NEW |