Chromium Code Reviews| 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) { |
|
Lasse Reichstein Nielsen
2012/08/16 10:41:34
You know this work item is a JavaScriptWorkItem?
floitsch
2012/08/16 14:10:04
There is no JavaScriptWorkItem anymore.
| |
| 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.name); | 220 return fromInterceptorToDynamicInvocation(node, node.name); |
| 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( | 248 HInstruction fromInterceptorToDynamicInvocation( |
| 238 HInvokeStatic node, SourceString methodName) { | 249 HInvokeStatic node, SourceString methodName) { |
| 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 node.selector, | 252 node.selector, |
| 242 methodName, | 253 methodName, |
| 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(methodName); | 257 result.element = concrete.lookupMember(methodName); |
| 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 SourceString methodName = Elements.constructOperatorName( | 316 SourceString methodName = Elements.constructOperatorName( |
| 306 const SourceString('operator'), const SourceString('[]')); | 317 const SourceString('operator'), const SourceString('[]')); |
| 307 return fromInterceptorToDynamicInvocation(node, methodName); | 318 return fromInterceptorToDynamicInvocation(node, methodName); |
| 308 } | 319 } |
| 309 return node; | 320 return node; |
| 310 } | 321 } |
| 311 | 322 |
| 312 HInstruction visitIndexAssign(HIndexAssign node) { | 323 HInstruction visitIndexAssign(HIndexAssign node) { |
| 313 if (!node.receiver.canBePrimitive()) { | 324 if (!node.receiver.canBePrimitive(types)) { |
| 314 SourceString methodName = Elements.constructOperatorName( | 325 SourceString methodName = Elements.constructOperatorName( |
| 315 const SourceString('operator'), const SourceString('[]=')); | 326 const SourceString('operator'), const SourceString('[]=')); |
| 316 return fromInterceptorToDynamicInvocation(node, methodName); | 327 return fromInterceptorToDynamicInvocation(node, methodName); |
| 317 } | 328 } |
| 318 return node; | 329 return node; |
| 319 } | 330 } |
| 320 | 331 |
| 321 HInstruction visitInvokeBinary(HInvokeBinary node) { | 332 HInstruction visitInvokeBinary(HInvokeBinary node) { |
| 322 HInstruction left = node.left; | 333 HInstruction left = node.left; |
| 323 HInstruction right = node.right; | 334 HInstruction right = node.right; |
| 324 if (left is HConstant && right is HConstant) { | 335 if (left is HConstant && right is HConstant) { |
| 325 BinaryOperation operation = node.operation; | 336 BinaryOperation operation = node.operation; |
| 326 HConstant op1 = left; | 337 HConstant op1 = left; |
| 327 HConstant op2 = right; | 338 HConstant op2 = right; |
| 328 Constant folded = operation.fold(op1.constant, op2.constant); | 339 Constant folded = operation.fold(op1.constant, op2.constant); |
| 329 if (folded !== null) return graph.addConstant(folded); | 340 if (folded !== null) return graph.addConstant(folded); |
| 330 } | 341 } |
| 331 | 342 |
| 332 if (!left.canBePrimitive() | 343 if (!left.canBePrimitive(types) |
| 333 && node.operation.isUserDefinable() | 344 && node.operation.isUserDefinable() |
| 334 // The equals operation is being optimized in visitEquals. | 345 // The equals operation is being optimized in visitEquals. |
| 335 && node.operation !== const EqualsOperation()) { | 346 && node.operation !== const EqualsOperation()) { |
| 336 SourceString methodName = Elements.constructOperatorName( | 347 SourceString methodName = Elements.constructOperatorName( |
| 337 const SourceString('operator'), node.operation.name); | 348 const SourceString('operator'), node.operation.name); |
| 338 return fromInterceptorToDynamicInvocation(node, methodName); | 349 return fromInterceptorToDynamicInvocation(node, methodName); |
| 339 } | 350 } |
| 340 return node; | 351 return node; |
| 341 } | 352 } |
| 342 | 353 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 361 // instructions. If it is unused it will be treated as dead code and | 372 // instructions. If it is unused it will be treated as dead code and |
| 362 // discarded. | 373 // discarded. |
| 363 oldTarget.block.addAfter(oldTarget, boolifiedTarget); | 374 oldTarget.block.addAfter(oldTarget, boolifiedTarget); |
| 364 // Remove us as user from the [oldTarget]. | 375 // Remove us as user from the [oldTarget]. |
| 365 oldTarget.removeUser(node); | 376 oldTarget.removeUser(node); |
| 366 // Replace old target with boolified target. | 377 // Replace old target with boolified target. |
| 367 assert(node.target == node.inputs[0]); | 378 assert(node.target == node.inputs[0]); |
| 368 node.inputs[0] = boolifiedTarget; | 379 node.inputs[0] = boolifiedTarget; |
| 369 boolifiedTarget.usedBy.add(node); | 380 boolifiedTarget.usedBy.add(node); |
| 370 node.usesBoolifiedInterceptor = true; | 381 node.usesBoolifiedInterceptor = true; |
| 371 node.propagatedType = HType.BOOLEAN; | 382 types[node] = HType.BOOLEAN; |
| 372 } | 383 } |
| 373 // This node stays the same, but the Boolify node will go away. | 384 // This node stays the same, but the Boolify node will go away. |
| 374 } | 385 } |
| 375 // Note that we still have to call [super] to make sure that we end up | 386 // Note that we still have to call [super] to make sure that we end up |
| 376 // in the remaining optimizations. | 387 // in the remaining optimizations. |
| 377 return super.visitRelational(node); | 388 return super.visitRelational(node); |
| 378 } | 389 } |
| 379 | 390 |
| 380 HInstruction handleIdentityCheck(HInvokeBinary node) { | 391 HInstruction handleIdentityCheck(HInvokeBinary node) { |
| 381 HInstruction left = node.left; | 392 HInstruction left = node.left; |
| 382 HInstruction right = node.right; | 393 HInstruction right = node.right; |
| 383 HType leftType = left.propagatedType; | 394 HType leftType = types[left]; |
| 384 HType rightType = right.propagatedType; | 395 HType rightType = types[right]; |
| 385 assert(!leftType.isConflicting() && !rightType.isConflicting()); | 396 assert(!leftType.isConflicting() && !rightType.isConflicting()); |
| 386 | 397 |
| 387 // We don't optimize on numbers to preserve the runtime semantics. | 398 // We don't optimize on numbers to preserve the runtime semantics. |
| 388 if (!(left.isNumber() && right.isNumber()) && | 399 if (!(left.isNumber(types) && right.isNumber(types)) && |
| 389 leftType.intersection(rightType).isConflicting()) { | 400 leftType.intersection(rightType).isConflicting()) { |
| 390 return graph.addConstantBool(false); | 401 return graph.addConstantBool(false); |
| 391 } | 402 } |
| 392 | 403 |
| 393 if (left.isConstantBoolean() && right.isBoolean()) { | 404 if (left.isConstantBoolean() && right.isBoolean(types)) { |
| 394 HConstant constant = left; | 405 HConstant constant = left; |
| 395 if (constant.constant.isTrue()) { | 406 if (constant.constant.isTrue()) { |
| 396 return right; | 407 return right; |
| 397 } else { | 408 } else { |
| 398 return new HNot(right); | 409 return new HNot(right); |
| 399 } | 410 } |
| 400 } | 411 } |
| 401 | 412 |
| 402 if (right.isConstantBoolean() && left.isBoolean()) { | 413 if (right.isConstantBoolean() && left.isBoolean(types)) { |
| 403 HConstant constant = right; | 414 HConstant constant = right; |
| 404 if (constant.constant.isTrue()) { | 415 if (constant.constant.isTrue()) { |
| 405 return left; | 416 return left; |
| 406 } else { | 417 } else { |
| 407 return new HNot(left); | 418 return new HNot(left); |
| 408 } | 419 } |
| 409 } | 420 } |
| 410 | 421 |
| 411 return null; | 422 return null; |
| 412 } | 423 } |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 426 return new HIdentity(target, node.left, node.right); | 437 return new HIdentity(target, node.left, node.right); |
| 427 } else { | 438 } else { |
| 428 return newInstruction; | 439 return newInstruction; |
| 429 } | 440 } |
| 430 } | 441 } |
| 431 | 442 |
| 432 HInstruction visitEquals(HEquals node) { | 443 HInstruction visitEquals(HEquals node) { |
| 433 HInstruction left = node.left; | 444 HInstruction left = node.left; |
| 434 HInstruction right = node.right; | 445 HInstruction right = node.right; |
| 435 | 446 |
| 436 if (node.builtin) { | 447 if (node.isBuiltin(types)) { |
| 437 return foldBuiltinEqualsCheck(node); | 448 return foldBuiltinEqualsCheck(node); |
| 438 } | 449 } |
| 439 | 450 |
| 440 if (left.isConstant() && right.isConstant()) { | 451 if (left.isConstant() && right.isConstant()) { |
| 441 return super.visitEquals(node); | 452 return super.visitEquals(node); |
| 442 } | 453 } |
| 443 | 454 |
| 444 if (left.propagatedType.isExact()) { | 455 HType leftType = types[left]; |
| 445 HBoundedType type = left.propagatedType; | 456 if (leftType.isExact()) { |
| 457 HBoundedType type = leftType; | |
| 446 Element element = type.lookupMember(Elements.OPERATOR_EQUALS); | 458 Element element = type.lookupMember(Elements.OPERATOR_EQUALS); |
| 447 if (element !== null) { | 459 if (element !== null) { |
| 448 // If the left-hand side is guaranteed to be a non-primitive | 460 // If the left-hand side is guaranteed to be a non-primitive |
| 449 // type and and it defines operator==, we emit a call to that | 461 // type and and it defines operator==, we emit a call to that |
| 450 // operator. | 462 // operator. |
| 451 return super.visitEquals(node); | 463 return super.visitEquals(node); |
| 452 } else if (right.isConstantNull()) { | 464 } else if (right.isConstantNull()) { |
| 453 return graph.addConstantBool(false); | 465 return graph.addConstantBool(false); |
| 454 } else { | 466 } else { |
| 455 // We can just emit an identity check because the type does | 467 // We can just emit an identity check because the type does |
| 456 // not implement operator=. | 468 // not implement operator=. |
| 457 return foldBuiltinEqualsCheck(node); | 469 return foldBuiltinEqualsCheck(node); |
| 458 } | 470 } |
| 459 } | 471 } |
| 460 | 472 |
| 461 if (right.isConstantNull()) { | 473 if (right.isConstantNull()) { |
| 462 if (left.propagatedType.isPrimitive()) { | 474 if (leftType.isPrimitive()) { |
| 463 return graph.addConstantBool(false); | 475 return graph.addConstantBool(false); |
| 464 } | 476 } |
| 465 } | 477 } |
| 466 | 478 |
| 467 // All other cases are dealt with by the [visitRelational] and | 479 // All other cases are dealt with by the [visitRelational] and |
| 468 // [visitInvokeBinary], which are visited by invoking the [super]'s | 480 // [visitInvokeBinary], which are visited by invoking the [super]'s |
| 469 // visit method. | 481 // visit method. |
| 470 return super.visitEquals(node); | 482 return super.visitEquals(node); |
| 471 } | 483 } |
| 472 | 484 |
| 473 HInstruction visitTypeGuard(HTypeGuard node) { | 485 HInstruction visitTypeGuard(HTypeGuard node) { |
| 474 HInstruction value = node.guarded; | 486 HInstruction value = node.guarded; |
| 475 // If the intersection of the types is still the incoming type then | 487 // If the intersection of the types is still the incoming type then |
| 476 // the incoming type was a subtype of the guarded type, and no check | 488 // the incoming type was a subtype of the guarded type, and no check |
| 477 // is required. | 489 // is required. |
| 478 HType combinedType = value.propagatedType.intersection(node.guardedType); | 490 HType combinedType = types[value].intersection(node.guardedType); |
| 479 return (combinedType == value.propagatedType) ? value : node; | 491 return (combinedType == types[value]) ? value : node; |
| 480 } | 492 } |
| 481 | 493 |
| 482 HInstruction visitIs(HIs node) { | 494 HInstruction visitIs(HIs node) { |
| 483 Type type = node.typeExpression; | 495 Type type = node.typeExpression; |
| 484 Element element = type.element; | 496 Element element = type.element; |
| 485 if (element.kind === ElementKind.TYPE_VARIABLE) { | 497 if (element.kind === ElementKind.TYPE_VARIABLE) { |
| 486 compiler.unimplemented("visitIs for type variables"); | 498 compiler.unimplemented("visitIs for type variables"); |
| 487 } | 499 } |
| 488 | 500 |
| 489 HType expressionType = node.expression.propagatedType; | 501 HType expressionType = types[node.expression]; |
| 490 if (element === compiler.objectClass | 502 if (element === compiler.objectClass |
| 491 || element === compiler.dynamicClass) { | 503 || element === compiler.dynamicClass) { |
| 492 return graph.addConstantBool(true); | 504 return graph.addConstantBool(true); |
| 493 } else if (expressionType.isInteger()) { | 505 } else if (expressionType.isInteger()) { |
| 494 if (element === compiler.intClass || element === compiler.numClass) { | 506 if (element === compiler.intClass || element === compiler.numClass) { |
| 495 return graph.addConstantBool(true); | 507 return graph.addConstantBool(true); |
| 496 } else if (element === compiler.doubleClass) { | 508 } else if (element === compiler.doubleClass) { |
| 497 // We let the JS semantics decide for that check. Currently | 509 // We let the JS semantics decide for that check. Currently |
| 498 // the code we emit will always return true. | 510 // the code we emit will always return true. |
| 499 return node; | 511 return node; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 542 } else if (expressionType.isExact()) { | 554 } else if (expressionType.isExact()) { |
| 543 return graph.addConstantBool(false); | 555 return graph.addConstantBool(false); |
| 544 } | 556 } |
| 545 } | 557 } |
| 546 } | 558 } |
| 547 return node; | 559 return node; |
| 548 } | 560 } |
| 549 | 561 |
| 550 HInstruction visitTypeConversion(HTypeConversion node) { | 562 HInstruction visitTypeConversion(HTypeConversion node) { |
| 551 HInstruction value = node.inputs[0]; | 563 HInstruction value = node.inputs[0]; |
| 552 Type type = node.propagatedType.computeType(compiler); | 564 Type type = types[node].computeType(compiler); |
| 553 if (type.element === compiler.dynamicClass | 565 if (type.element === compiler.dynamicClass |
| 554 || type.element === compiler.objectClass) { | 566 || type.element === compiler.objectClass) { |
| 555 return value; | 567 return value; |
| 556 } | 568 } |
| 557 HType combinedType = value.propagatedType.intersection(node.propagatedType); | 569 HType combinedType = types[value].intersection(types[node]); |
| 558 return (combinedType == value.propagatedType) ? value : node; | 570 return (combinedType == types[value]) ? value : node; |
| 559 } | 571 } |
| 560 | 572 |
| 561 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { | 573 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { |
| 562 HInstruction receiver = node.inputs[0]; | 574 HInstruction receiver = node.inputs[0]; |
| 563 if (!receiver.propagatedType.isUseful()) return node; | 575 HType receiverType = types[receiver]; |
| 564 if (receiver.propagatedType.canBeNull()) return node; | 576 if (!receiverType.isUseful()) return node; |
| 565 Type type = receiver.propagatedType.computeType(compiler); | 577 if (receiverType.canBeNull()) return node; |
| 578 Type type = receiverType.computeType(compiler); | |
| 566 if (type === null) return node; | 579 if (type === null) return node; |
| 567 Element field = compiler.world.locateSingleField(type, node.name); | 580 Element field = compiler.world.locateSingleField(type, node.name); |
| 568 if (field === null) return node; | 581 if (field === null) return node; |
| 569 Modifiers modifiers = field.modifiers; | 582 Modifiers modifiers = field.modifiers; |
| 570 bool isFinalOrConst = false; | 583 bool isFinalOrConst = false; |
| 571 if (modifiers != null) { | 584 if (modifiers != null) { |
| 572 isFinalOrConst = modifiers.isFinal() || modifiers.isConst(); | 585 isFinalOrConst = modifiers.isFinal() || modifiers.isConst(); |
| 573 } | 586 } |
| 574 if (!compiler.resolverWorld.hasInvokedSetter(field, compiler)) { | 587 if (!compiler.resolverWorld.hasInvokedSetter(field, compiler)) { |
| 575 // If no setter is ever used for this field it is only initialized in the | 588 // If no setter is ever used for this field it is only initialized in the |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 591 isFinalOrConst = true; | 604 isFinalOrConst = true; |
| 592 break; | 605 break; |
| 593 } | 606 } |
| 594 } | 607 } |
| 595 return new HFieldGet.withElement( | 608 return new HFieldGet.withElement( |
| 596 field, node.inputs[0], isFinalOrConst: isFinalOrConst); | 609 field, node.inputs[0], isFinalOrConst: isFinalOrConst); |
| 597 } | 610 } |
| 598 | 611 |
| 599 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { | 612 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
| 600 HInstruction receiver = node.inputs[0]; | 613 HInstruction receiver = node.inputs[0]; |
| 601 if (!receiver.propagatedType.isUseful()) return node; | 614 HType receiverType = types[receiver]; |
| 602 if (receiver.propagatedType.canBeNull()) return node; | 615 if (!receiverType.isUseful()) return node; |
| 603 Type type = receiver.propagatedType.computeType(compiler); | 616 if (receiverType.canBeNull()) return node; |
| 617 Type type = receiverType.computeType(compiler); | |
| 604 if (type === null) return node; | 618 if (type === null) return node; |
| 605 Element field = compiler.world.locateSingleField(type, node.name); | 619 Element field = compiler.world.locateSingleField(type, node.name); |
| 606 if (field === null) return node; | 620 if (field === null) return node; |
| 607 return new HFieldSet.withElement(field, node.inputs[0], node.inputs[1]); | 621 return new HFieldSet.withElement(field, node.inputs[0], node.inputs[1]); |
| 608 } | 622 } |
| 609 | 623 |
| 610 HInstruction visitStringConcat(HStringConcat node) { | 624 HInstruction visitStringConcat(HStringConcat node) { |
| 611 DartString folded = const LiteralDartString(""); | 625 DartString folded = const LiteralDartString(""); |
| 612 for (int i = 0; i < node.inputs.length; i++) { | 626 for (int i = 0; i < node.inputs.length; i++) { |
| 613 HInstruction part = node.inputs[i]; | 627 HInstruction part = node.inputs[i]; |
| 614 if (!part.isConstant()) return node; | 628 if (!part.isConstant()) return node; |
| 615 HConstant constant = part; | 629 HConstant constant = part; |
| 616 if (!constant.constant.isPrimitive()) return node; | 630 if (!constant.constant.isPrimitive()) return node; |
| 617 PrimitiveConstant primitive = constant.constant; | 631 PrimitiveConstant primitive = constant.constant; |
| 618 folded = new DartString.concat(folded, primitive.toDartString()); | 632 folded = new DartString.concat(folded, primitive.toDartString()); |
| 619 } | 633 } |
| 620 return graph.addConstantString(folded, node.node); | 634 return graph.addConstantString(folded, node.node); |
| 621 } | 635 } |
| 622 } | 636 } |
| 623 | 637 |
| 624 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { | 638 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { |
| 639 final HTypeMap types; | |
| 625 final String name = "SsaCheckInserter"; | 640 final String name = "SsaCheckInserter"; |
| 626 Element lengthInterceptor; | 641 Element lengthInterceptor; |
| 627 | 642 |
| 628 SsaCheckInserter(JavaScriptBackend backend) { | 643 SsaCheckInserter(JavaScriptBackend backend, this.types) { |
| 629 SourceString lengthString = const SourceString('length'); | 644 SourceString lengthString = const SourceString('length'); |
| 630 lengthInterceptor = | 645 lengthInterceptor = |
| 631 backend.builder.interceptors.getStaticGetInterceptor(lengthString); | 646 backend.builder.interceptors.getStaticGetInterceptor(lengthString); |
| 632 } | 647 } |
| 633 | 648 |
| 634 void visitGraph(HGraph graph) { | 649 void visitGraph(HGraph graph) { |
| 635 visitDominatorTree(graph); | 650 visitDominatorTree(graph); |
| 636 } | 651 } |
| 637 | 652 |
| 638 void visitBasicBlock(HBasicBlock block) { | 653 void visitBasicBlock(HBasicBlock block) { |
| 639 HInstruction instruction = block.first; | 654 HInstruction instruction = block.first; |
| 640 while (instruction !== null) { | 655 while (instruction !== null) { |
| 641 HInstruction next = instruction.next; | 656 HInstruction next = instruction.next; |
| 642 instruction = instruction.accept(this); | 657 instruction = instruction.accept(this); |
| 643 instruction = next; | 658 instruction = next; |
| 644 } | 659 } |
| 645 } | 660 } |
| 646 | 661 |
| 647 HBoundsCheck insertBoundsCheck(HInstruction node, | 662 HBoundsCheck insertBoundsCheck(HInstruction node, |
| 648 HInstruction receiver, | 663 HInstruction receiver, |
| 649 HInstruction index) { | 664 HInstruction index) { |
| 650 HStatic interceptor = new HStatic(lengthInterceptor); | 665 HStatic interceptor = new HStatic(lengthInterceptor); |
| 651 node.block.addBefore(node, interceptor); | 666 node.block.addBefore(node, interceptor); |
| 652 HInvokeInterceptor length = new HInvokeInterceptor( | 667 HInvokeInterceptor length = new HInvokeInterceptor( |
| 653 Selector.INVOCATION_0, | 668 Selector.INVOCATION_0, |
| 654 const SourceString("length"), | 669 const SourceString("length"), |
| 655 <HInstruction>[interceptor, receiver], | 670 <HInstruction>[interceptor, receiver], |
| 656 getter: true); | 671 getter: true); |
| 657 length.propagatedType = HType.INTEGER; | 672 types[length] = HType.INTEGER; |
| 658 node.block.addBefore(node, length); | 673 node.block.addBefore(node, length); |
| 659 | 674 |
| 660 HBoundsCheck check = new HBoundsCheck(index, length); | 675 HBoundsCheck check = new HBoundsCheck(index, length); |
| 661 node.block.addBefore(node, check); | 676 node.block.addBefore(node, check); |
| 662 return check; | 677 return check; |
| 663 } | 678 } |
| 664 | 679 |
| 665 HIntegerCheck insertIntegerCheck(HInstruction node, HInstruction value) { | 680 HIntegerCheck insertIntegerCheck(HInstruction node, HInstruction value) { |
| 666 HIntegerCheck check = new HIntegerCheck(value); | 681 HIntegerCheck check = new HIntegerCheck(value); |
| 667 node.block.addBefore(node, check); | 682 node.block.addBefore(node, check); |
| 668 Set<HInstruction> dominatedUsers = value.dominatedUsers(check); | 683 Set<HInstruction> dominatedUsers = value.dominatedUsers(check); |
| 669 for (HInstruction user in dominatedUsers) { | 684 for (HInstruction user in dominatedUsers) { |
| 670 user.changeUse(value, check); | 685 user.changeUse(value, check); |
| 671 } | 686 } |
| 672 return check; | 687 return check; |
| 673 } | 688 } |
| 674 | 689 |
| 675 void visitIndex(HIndex node) { | 690 void visitIndex(HIndex node) { |
| 676 if (!node.receiver.isIndexablePrimitive()) return; | 691 if (!node.receiver.isIndexablePrimitive(types)) return; |
| 677 HInstruction index = node.index; | 692 HInstruction index = node.index; |
| 678 if (index is HBoundsCheck) return; | 693 if (index is HBoundsCheck) return; |
| 679 if (!node.index.isInteger()) { | 694 if (!node.index.isInteger(types)) { |
| 680 index = insertIntegerCheck(node, index); | 695 index = insertIntegerCheck(node, index); |
| 681 } | 696 } |
| 682 index = insertBoundsCheck(node, node.receiver, index); | 697 index = insertBoundsCheck(node, node.receiver, index); |
| 683 node.changeUse(node.index, index); | 698 node.changeUse(node.index, index); |
| 684 } | 699 } |
| 685 | 700 |
| 686 void visitIndexAssign(HIndexAssign node) { | 701 void visitIndexAssign(HIndexAssign node) { |
| 687 if (!node.receiver.isMutableArray()) return; | 702 if (!node.receiver.isMutableArray(types)) return; |
| 688 HInstruction index = node.index; | 703 HInstruction index = node.index; |
| 689 if (index is HBoundsCheck) return; | 704 if (index is HBoundsCheck) return; |
| 690 if (!node.index.isInteger()) { | 705 if (!node.index.isInteger(types)) { |
| 691 index = insertIntegerCheck(node, index); | 706 index = insertIntegerCheck(node, index); |
| 692 } | 707 } |
| 693 index = insertBoundsCheck(node, node.receiver, index); | 708 index = insertBoundsCheck(node, node.receiver, index); |
| 694 node.changeUse(node.index, index); | 709 node.changeUse(node.index, index); |
| 695 } | 710 } |
| 696 } | 711 } |
| 697 | 712 |
| 698 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { | 713 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { |
| 714 final HTypeMap types; | |
| 699 final String name = "SsaDeadCodeEliminator"; | 715 final String name = "SsaDeadCodeEliminator"; |
| 700 | 716 |
| 701 static bool isDeadCode(HInstruction instruction) { | 717 SsaDeadCodeEliminator(this.types); |
| 702 return !instruction.hasSideEffects() | 718 |
| 719 bool isDeadCode(HInstruction instruction) { | |
| 720 return !instruction.hasSideEffects(types) | |
| 703 && instruction.usedBy.isEmpty() | 721 && instruction.usedBy.isEmpty() |
| 704 && instruction is !HCheck | 722 && instruction is !HCheck |
| 705 && instruction is !HTypeGuard | 723 && instruction is !HTypeGuard |
| 706 && !instruction.isControlFlow(); | 724 && !instruction.isControlFlow(); |
| 707 } | 725 } |
| 708 | 726 |
| 709 void visitGraph(HGraph graph) { | 727 void visitGraph(HGraph graph) { |
| 710 visitPostDominatorTree(graph); | 728 visitPostDominatorTree(graph); |
| 711 } | 729 } |
| 712 | 730 |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 819 } | 837 } |
| 820 phi.block.rewrite(phi, candidate); | 838 phi.block.rewrite(phi, candidate); |
| 821 phi.block.removePhi(phi); | 839 phi.block.removePhi(phi); |
| 822 } | 840 } |
| 823 } | 841 } |
| 824 } | 842 } |
| 825 | 843 |
| 826 class SsaGlobalValueNumberer implements OptimizationPhase { | 844 class SsaGlobalValueNumberer implements OptimizationPhase { |
| 827 final String name = "SsaGlobalValueNumberer"; | 845 final String name = "SsaGlobalValueNumberer"; |
| 828 final Compiler compiler; | 846 final Compiler compiler; |
| 847 final HTypeMap types; | |
| 829 final Set<int> visited; | 848 final Set<int> visited; |
| 830 | 849 |
| 831 List<int> blockChangesFlags; | 850 List<int> blockChangesFlags; |
| 832 List<int> loopChangesFlags; | 851 List<int> loopChangesFlags; |
| 833 | 852 |
| 834 SsaGlobalValueNumberer(this.compiler) : visited = new Set<int>(); | 853 SsaGlobalValueNumberer(this.compiler, this.types) : visited = new Set<int>(); |
| 835 | 854 |
| 836 void visitGraph(HGraph graph) { | 855 void visitGraph(HGraph graph) { |
| 837 computeChangesFlags(graph); | 856 computeChangesFlags(graph); |
| 838 moveLoopInvariantCode(graph); | 857 moveLoopInvariantCode(graph); |
| 839 visitBasicBlock(graph.entry, new ValueSet()); | 858 visitBasicBlock(graph.entry, new ValueSet()); |
| 840 } | 859 } |
| 841 | 860 |
| 842 void moveLoopInvariantCode(HGraph graph) { | 861 void moveLoopInvariantCode(HGraph graph) { |
| 843 for (int i = graph.blocks.length - 1; i >= 0; i--) { | 862 for (int i = graph.blocks.length - 1; i >= 0; i--) { |
| 844 HBasicBlock block = graph.blocks[i]; | 863 HBasicBlock block = graph.blocks[i]; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 950 // Run through all the basic blocks in the graph and fill in the | 969 // Run through all the basic blocks in the graph and fill in the |
| 951 // changes flags lists. | 970 // changes flags lists. |
| 952 for (int i = length - 1; i >= 0; i--) { | 971 for (int i = length - 1; i >= 0; i--) { |
| 953 final HBasicBlock block = graph.blocks[i]; | 972 final HBasicBlock block = graph.blocks[i]; |
| 954 final int id = block.id; | 973 final int id = block.id; |
| 955 | 974 |
| 956 // Compute block changes flags for the block. | 975 // Compute block changes flags for the block. |
| 957 int changesFlags = 0; | 976 int changesFlags = 0; |
| 958 HInstruction instruction = block.first; | 977 HInstruction instruction = block.first; |
| 959 while (instruction !== null) { | 978 while (instruction !== null) { |
| 960 instruction.prepareGvn(); | 979 instruction.prepareGvn(types); |
| 961 changesFlags |= instruction.getChangesFlags(); | 980 changesFlags |= instruction.getChangesFlags(); |
| 962 instruction = instruction.next; | 981 instruction = instruction.next; |
| 963 } | 982 } |
| 964 assert(blockChangesFlags[id] === null); | 983 assert(blockChangesFlags[id] === null); |
| 965 blockChangesFlags[id] = changesFlags; | 984 blockChangesFlags[id] = changesFlags; |
| 966 | 985 |
| 967 // Loop headers are part of their loop, so update the loop | 986 // Loop headers are part of their loop, so update the loop |
| 968 // changes flags accordingly. | 987 // changes flags accordingly. |
| 969 if (block.isLoopHeader()) { | 988 if (block.isLoopHeader()) { |
| 970 loopChangesFlags[id] |= changesFlags; | 989 loopChangesFlags[id] |= changesFlags; |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1158 } | 1177 } |
| 1159 } | 1178 } |
| 1160 } | 1179 } |
| 1161 | 1180 |
| 1162 | 1181 |
| 1163 // Base class for the handling of recompilation based on inferred | 1182 // Base class for the handling of recompilation based on inferred |
| 1164 // field types. | 1183 // field types. |
| 1165 class BaseRecompilationVisitor extends HBaseVisitor { | 1184 class BaseRecompilationVisitor extends HBaseVisitor { |
| 1166 final JavaScriptBackend backend; | 1185 final JavaScriptBackend backend; |
| 1167 final WorkItem work; | 1186 final WorkItem work; |
| 1187 final HTypeMap types; | |
| 1168 Compiler get compiler() => backend.compiler; | 1188 Compiler get compiler() => backend.compiler; |
| 1169 | 1189 |
| 1170 BaseRecompilationVisitor(this.backend, this.work); | 1190 BaseRecompilationVisitor(this.backend, this.work, this.types); |
| 1171 | 1191 |
| 1172 abstract void handleFieldGet(HFieldGet node, HType type); | 1192 abstract void handleFieldGet(HFieldGet node, HType type); |
| 1173 abstract void handleFieldNumberOperation(HFieldGet field, HType type); | 1193 abstract void handleFieldNumberOperation(HFieldGet field, HType type); |
| 1174 | 1194 |
| 1175 // Checks if the binary invocation operates on a field and a | 1195 // Checks if the binary invocation operates on a field and a |
| 1176 // constant number. If it does [handleFieldNumberOperation] is | 1196 // constant number. If it does [handleFieldNumberOperation] is |
| 1177 // called with the field and the type inferred for the field so far. | 1197 // called with the field and the type inferred for the field so far. |
| 1178 void checkFieldNumberOperation(HInvokeBinary node) { | 1198 void checkFieldNumberOperation(HInvokeBinary node) { |
| 1179 // Determine if one of the operands is an HFieldGet. | 1199 // Determine if one of the operands is an HFieldGet. |
| 1180 HFieldGet field; | 1200 HFieldGet field; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1228 } | 1248 } |
| 1229 } | 1249 } |
| 1230 | 1250 |
| 1231 | 1251 |
| 1232 // Visitor that registers candidates for recompilation. | 1252 // Visitor that registers candidates for recompilation. |
| 1233 class SsaRegisterRecompilationCandidates | 1253 class SsaRegisterRecompilationCandidates |
| 1234 extends BaseRecompilationVisitor implements OptimizationPhase { | 1254 extends BaseRecompilationVisitor implements OptimizationPhase { |
| 1235 final String name = "SsaRegisterRecompileCandidates"; | 1255 final String name = "SsaRegisterRecompileCandidates"; |
| 1236 HGraph graph; | 1256 HGraph graph; |
| 1237 | 1257 |
| 1238 SsaRegisterRecompilationCandidates( | 1258 SsaRegisterRecompilationCandidates(JavaScriptBackend backend, |
| 1239 JavaScriptBackend backend, WorkItem work) : super(backend, work); | 1259 WorkItem work, |
| 1260 HTypeMap types) | |
| 1261 : super(backend, work, types); | |
| 1240 | 1262 |
| 1241 void visitGraph(HGraph visitee) { | 1263 void visitGraph(HGraph visitee) { |
| 1242 graph = visitee; | 1264 graph = visitee; |
| 1243 if (compiler.phase == Compiler.PHASE_COMPILING) { | 1265 if (compiler.phase == Compiler.PHASE_COMPILING) { |
| 1244 visitDominatorTree(visitee); | 1266 visitDominatorTree(visitee); |
| 1245 } | 1267 } |
| 1246 } | 1268 } |
| 1247 | 1269 |
| 1248 void handleFieldGet(HFieldGet node, HType type) { | 1270 void handleFieldGet(HFieldGet node, HType type) { |
| 1249 assert(compiler.phase == Compiler.PHASE_COMPILING); | 1271 assert(compiler.phase == Compiler.PHASE_COMPILING); |
| 1250 compiler.enqueuer.codegen.registerRecompilationCandidate( | 1272 compiler.enqueuer.codegen.registerRecompilationCandidate( |
| 1251 work.element); | 1273 work.element); |
| 1252 } | 1274 } |
| 1253 | 1275 |
| 1254 void handleFieldNumberOperation(HFieldGet node, HType type) { | 1276 void handleFieldNumberOperation(HFieldGet node, HType type) { |
| 1255 assert(compiler.phase == Compiler.PHASE_COMPILING); | 1277 assert(compiler.phase == Compiler.PHASE_COMPILING); |
| 1256 compiler.enqueuer.codegen.registerRecompilationCandidate( | 1278 compiler.enqueuer.codegen.registerRecompilationCandidate( |
| 1257 work.element); | 1279 work.element); |
| 1258 } | 1280 } |
| 1259 } | 1281 } |
| 1260 | 1282 |
| 1261 | 1283 |
| 1262 // Visitor that sets the known or suspected type of fields during | 1284 // Visitor that sets the known or suspected type of fields during |
| 1263 // recompilation. | 1285 // recompilation. |
| 1264 class SsaRecompilationFieldTypePropagator | 1286 class SsaRecompilationFieldTypePropagator |
| 1265 extends BaseRecompilationVisitor implements OptimizationPhase { | 1287 extends BaseRecompilationVisitor implements OptimizationPhase { |
| 1266 final String name = "SsaRecompilationFieldTypePropagator"; | 1288 final String name = "SsaRecompilationFieldTypePropagator"; |
| 1267 HGraph graph; | 1289 HGraph graph; |
| 1268 | 1290 |
| 1269 SsaRecompilationFieldTypePropagator( | 1291 SsaRecompilationFieldTypePropagator(JavaScriptBackend backend, |
| 1270 JavaScriptBackend backend, WorkItem work) : super(backend, work); | 1292 WorkItem work, |
| 1293 HTypeMap types) | |
| 1294 : super(backend, work, types); | |
| 1271 | 1295 |
| 1272 void visitGraph(HGraph visitee) { | 1296 void visitGraph(HGraph visitee) { |
| 1273 graph = visitee; | 1297 graph = visitee; |
| 1274 if (compiler.phase == Compiler.PHASE_RECOMPILING) { | 1298 if (compiler.phase == Compiler.PHASE_RECOMPILING) { |
| 1275 visitDominatorTree(visitee); | 1299 visitDominatorTree(visitee); |
| 1276 } | 1300 } |
| 1277 } | 1301 } |
| 1278 | 1302 |
| 1279 void handleFieldGet(HFieldGet field, HType type) { | 1303 void handleFieldGet(HFieldGet field, HType type) { |
| 1280 assert(compiler.phase == Compiler.PHASE_RECOMPILING); | 1304 assert(compiler.phase == Compiler.PHASE_RECOMPILING); |
| 1281 if (!type.isConflicting()) { | 1305 if (!type.isConflicting()) { |
| 1282 // If there are no invoked setters with this name, the union of | 1306 // If there are no invoked setters with this name, the union of |
| 1283 // the types of the initializers and the setters is guaranteed | 1307 // the types of the initializers and the setters is guaranteed |
| 1284 // otherwise it is only speculative. | 1308 // otherwise it is only speculative. |
| 1285 Element element = field.element; | 1309 Element element = field.element; |
| 1286 assert(!element.isGenerativeConstructorBody()); | 1310 assert(!element.isGenerativeConstructorBody()); |
| 1287 if (!compiler.codegenWorld.hasInvokedSetter(element, compiler)) { | 1311 if (!compiler.codegenWorld.hasInvokedSetter(element, compiler)) { |
| 1288 field.guaranteedType = | 1312 field.guaranteedType = |
| 1289 type.union(backend.fieldSettersTypeSoFar(element)); | 1313 type.union(backend.fieldSettersTypeSoFar(element)); |
| 1290 } else { | 1314 } else { |
| 1291 field.propagatedType = | 1315 types[field] = type.union(backend.fieldSettersTypeSoFar(element)); |
| 1292 type.union(backend.fieldSettersTypeSoFar(element)); | |
| 1293 } | 1316 } |
| 1294 } | 1317 } |
| 1295 } | 1318 } |
| 1296 | 1319 |
| 1297 void handleFieldNumberOperation(HFieldGet field, HType type) { | 1320 void handleFieldNumberOperation(HFieldGet field, HType type) { |
| 1298 assert(compiler.phase == Compiler.PHASE_RECOMPILING); | 1321 assert(compiler.phase == Compiler.PHASE_RECOMPILING); |
| 1299 if (compiler.codegenWorld.hasInvokedSetter(field.element, compiler)) { | 1322 if (compiler.codegenWorld.hasInvokedSetter(field.element, compiler)) { |
| 1300 // If there are invoked setters we don't know for sure | 1323 // If there are invoked setters we don't know for sure |
| 1301 // that the field will hold a value of the calculated | 1324 // that the field will hold a value of the calculated |
| 1302 // type, but the fact that the class itself sticks to | 1325 // type, but the fact that the class itself sticks to |
| 1303 // this type for the field is still a strong signal | 1326 // this type for the field is still a strong signal |
| 1304 // indicating the expected type of the field. | 1327 // indicating the expected type of the field. |
| 1305 field.propagatedType = type; | 1328 types[field] = type; |
| 1306 } else { | 1329 } else { |
| 1307 // If there are no invoked setters we know the type of | 1330 // If there are no invoked setters we know the type of |
| 1308 // this field for sure. | 1331 // this field for sure. |
| 1309 field.guaranteedType = type; | 1332 field.guaranteedType = type; |
| 1310 } | 1333 } |
| 1311 } | 1334 } |
| 1312 } | 1335 } |
| OLD | NEW |