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