Chromium Code Reviews| Index: lib/compiler/implementation/ssa/optimize.dart |
| diff --git a/lib/compiler/implementation/ssa/optimize.dart b/lib/compiler/implementation/ssa/optimize.dart |
| index 2b4831ad2a2097aa905c57f98ba09560826f80c2..fc21d22e062f59658e8e14925c75f7c30ed55a31 100644 |
| --- a/lib/compiler/implementation/ssa/optimize.dart |
| +++ b/lib/compiler/implementation/ssa/optimize.dart |
| @@ -17,26 +17,30 @@ class SsaOptimizerTask extends CompilerTask { |
| void runPhases(HGraph graph, List<OptimizationPhase> phases) { |
| for (OptimizationPhase phase in phases) { |
| - phase.visitGraph(graph); |
| - compiler.tracer.traceGraph(phase.name, graph); |
| + runPhase(graph, phase); |
| } |
| } |
| - void optimize(WorkItem work, HGraph graph) { |
| + void runPhase(HGraph graph, OptimizationPhase phase) { |
| + phase.visitGraph(graph); |
| + compiler.tracer.traceGraph(phase.name, graph); |
| + } |
| + |
| + void optimize(JavaScriptWorkItem work, HGraph graph) { |
| measure(() { |
| List<OptimizationPhase> phases = <OptimizationPhase>[ |
| // Run trivial constant folding first to optimize |
| // some patterns useful for type conversion. |
| new SsaConstantFolder(backend, work), |
| new SsaTypeConversionInserter(compiler), |
| - new SsaTypePropagator(compiler), |
| - new SsaCheckInserter(backend), |
| + new SsaTypePropagator(compiler, work), |
| + new SsaCheckInserter(backend, work), |
| new SsaConstantFolder(backend, work), |
| new SsaRedundantPhiEliminator(), |
| new SsaDeadPhiEliminator(), |
| - new SsaGlobalValueNumberer(compiler), |
| + new SsaGlobalValueNumberer(compiler, work), |
| new SsaCodeMotion(), |
| - new SsaDeadCodeEliminator(), |
| + new SsaDeadCodeEliminator(work), |
| new SsaRegisterRecompilationCandidates(backend, work)]; |
| runPhases(graph, phases); |
| }); |
| @@ -47,7 +51,7 @@ class SsaOptimizerTask extends CompilerTask { |
| // Run the phases that will generate type guards. |
| List<OptimizationPhase> phases = <OptimizationPhase>[ |
| new SsaRecompilationFieldTypePropagator(backend, work), |
| - new SsaSpeculativeTypePropagator(compiler), |
| + new SsaSpeculativeTypePropagator(compiler, work), |
| new SsaTypeGuardInserter(compiler, work), |
| new SsaEnvironmentBuilder(compiler), |
| // Change the propagated types back to what they were before we |
| @@ -56,11 +60,11 @@ class SsaOptimizerTask extends CompilerTask { |
| // Note that we do this even if there were no guards inserted. If a |
| // guard is not beneficial enough we don't emit one, but there might |
| // still be speculative types on the instructions. |
| - new SsaTypePropagator(compiler), |
| + new SsaTypePropagator(compiler, work), |
| // Then run the [SsaCheckInserter] because the type propagator also |
| // propagated types non-speculatively. For example, it might have |
| // propagated the type array for a call to the List constructor. |
| - new SsaCheckInserter(backend)]; |
| + new SsaCheckInserter(backend, work)]; |
| runPhases(graph, phases); |
| return !work.guards.isEmpty(); |
| }); |
| @@ -79,8 +83,8 @@ class SsaOptimizerTask extends CompilerTask { |
| // Also run the type propagator, to please the codegen in case |
| // no other optimization is run. |
| runPhases(graph, |
| - <OptimizationPhase>[new SsaCheckInserter(backend), |
| - new SsaTypePropagator(compiler)]); |
| + <OptimizationPhase>[new SsaCheckInserter(backend, work), |
| + new SsaTypePropagator(compiler, work)]); |
| }); |
| } |
| } |
| @@ -92,7 +96,7 @@ class SsaOptimizerTask extends CompilerTask { |
| class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| final String name = "SsaConstantFolder"; |
| final JavaScriptBackend backend; |
| - final WorkItem work; |
| + final JavaScriptWorkItem work; |
| HGraph graph; |
| Compiler get compiler() => backend.compiler; |
| @@ -104,6 +108,7 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| } |
| visitBasicBlock(HBasicBlock block) { |
| + HTypeMap types = work.types; |
| HInstruction instruction = block.first; |
| while (instruction !== null) { |
| HInstruction next = instruction.next; |
| @@ -120,8 +125,8 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| // If the replacement instruction does not know its type or |
| // source element yet, use the type and source element of the |
| // instruction. |
| - if (!replacement.propagatedType.isUseful()) { |
| - replacement.propagatedType = instruction.propagatedType; |
| + if (!types[replacement].isUseful()) { |
| + types[replacement] = types[instruction]; |
| } |
| if (replacement.sourceElement === null) { |
| replacement.sourceElement = instruction.sourceElement; |
| @@ -136,12 +141,13 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| } |
| HInstruction visitBoolify(HBoolify node) { |
| + HTypeMap types = work.types; |
| List<HInstruction> inputs = node.inputs; |
| assert(inputs.length == 1); |
| HInstruction input = inputs[0]; |
| - if (input.isBoolean()) return input; |
| + if (input.isBoolean(types)) return input; |
| // All values !== true are boolified to false. |
| - Type type = input.propagatedType.computeType(compiler); |
| + Type type = types[input].computeType(compiler); |
| if (type !== null && type.element !== compiler.boolClass) { |
| return graph.addConstantBool(false); |
| } |
| @@ -191,14 +197,16 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| } |
| } |
| - if (input.isString() |
| + HTypeMap types = work.types; |
| + |
| + if (input.isString(types) |
| && node.name == const SourceString('toString')) { |
| return node.inputs[1]; |
| } |
| - if (!input.canBePrimitive() && !node.getter && !node.setter) { |
| + if (!input.canBePrimitive(types) && !node.getter && !node.setter) { |
| bool transformToDynamicInvocation = true; |
| - if (input.canBeNull()) { |
| + if (input.canBeNull(types)) { |
| // Check if the method exists on Null. If yes we must not transform |
| // the static interceptor call to a dynamic invocation. |
| // TODO(floitsch): get a list of methods that exist on 'null' and only |
| @@ -214,7 +222,7 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| } |
| HInstruction visitInvokeDynamic(HInvokeDynamic node) { |
| - HType receiverType = node.receiver.propagatedType; |
| + HType receiverType = work.types[node.receiver]; |
| if (receiverType.isExact()) { |
| HBoundedType type = receiverType; |
| Element element = type.lookupMember(node.name); |
| @@ -236,7 +244,7 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| HInstruction fromInterceptorToDynamicInvocation( |
| HInvokeStatic node, SourceString methodName) { |
| - HBoundedType type = node.inputs[1].propagatedType; |
| + HBoundedType type = work.types[node.inputs[1]]; |
| HInvokeDynamicMethod result = new HInvokeDynamicMethod( |
| node.selector, |
| methodName, |
| @@ -288,7 +296,7 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| HInstruction visitIntegerCheck(HIntegerCheck node) { |
| HInstruction value = node.value; |
| - if (value.isInteger()) return value; |
| + if (value.isInteger(work.types)) return value; |
| if (value.isConstant()) { |
| assert((){ |
| HConstant constantInstruction = value; |
| @@ -301,7 +309,7 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| HInstruction visitIndex(HIndex node) { |
| - if (!node.receiver.canBePrimitive()) { |
| + if (!node.receiver.canBePrimitive(work.types)) { |
| SourceString methodName = Elements.constructOperatorName( |
| const SourceString('operator'), const SourceString('[]')); |
| return fromInterceptorToDynamicInvocation(node, methodName); |
| @@ -310,7 +318,7 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| } |
| HInstruction visitIndexAssign(HIndexAssign node) { |
| - if (!node.receiver.canBePrimitive()) { |
| + if (!node.receiver.canBePrimitive(work.types)) { |
| SourceString methodName = Elements.constructOperatorName( |
| const SourceString('operator'), const SourceString('[]=')); |
| return fromInterceptorToDynamicInvocation(node, methodName); |
| @@ -329,7 +337,7 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| if (folded !== null) return graph.addConstant(folded); |
| } |
| - if (!left.canBePrimitive() |
| + if (!left.canBePrimitive(work.types) |
| && node.operation.isUserDefinable() |
| // The equals operation is being optimized in visitEquals. |
| && node.operation !== const EqualsOperation()) { |
| @@ -368,7 +376,7 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| node.inputs[0] = boolifiedTarget; |
| boolifiedTarget.usedBy.add(node); |
| node.usesBoolifiedInterceptor = true; |
| - node.propagatedType = HType.BOOLEAN; |
| + work.types[node] = HType.BOOLEAN; |
| } |
| // This node stays the same, but the Boolify node will go away. |
| } |
| @@ -378,19 +386,20 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| } |
| HInstruction handleIdentityCheck(HInvokeBinary node) { |
| + HTypeMap types = work.types; |
| HInstruction left = node.left; |
| HInstruction right = node.right; |
| - HType leftType = left.propagatedType; |
| - HType rightType = right.propagatedType; |
| + HType leftType = types[left]; |
| + HType rightType = types[right]; |
| assert(!leftType.isConflicting() && !rightType.isConflicting()); |
| // We don't optimize on numbers to preserve the runtime semantics. |
| - if (!(left.isNumber() && right.isNumber()) && |
| + if (!(left.isNumber(types) && right.isNumber(types)) && |
| leftType.intersection(rightType).isConflicting()) { |
| return graph.addConstantBool(false); |
| } |
| - if (left.isConstantBoolean() && right.isBoolean()) { |
| + if (left.isConstantBoolean() && right.isBoolean(types)) { |
| HConstant constant = left; |
| if (constant.constant.isTrue()) { |
| return right; |
| @@ -399,7 +408,7 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| } |
| } |
| - if (right.isConstantBoolean() && left.isBoolean()) { |
| + if (right.isConstantBoolean() && left.isBoolean(types)) { |
| HConstant constant = right; |
| if (constant.constant.isTrue()) { |
| return left; |
| @@ -430,10 +439,11 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| } |
| HInstruction visitEquals(HEquals node) { |
| + HTypeMap types = work.types; |
| HInstruction left = node.left; |
| HInstruction right = node.right; |
| - if (node.builtin) { |
| + if (node.isBuiltin(types)) { |
| return foldBuiltinEqualsCheck(node); |
| } |
| @@ -441,8 +451,9 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| return super.visitEquals(node); |
| } |
| - if (left.propagatedType.isExact()) { |
| - HBoundedType type = left.propagatedType; |
| + HType leftType = types[left]; |
| + if (leftType.isExact()) { |
| + HBoundedType type = leftType; |
| Element element = type.lookupMember(Elements.OPERATOR_EQUALS); |
| if (element !== null) { |
| // If the left-hand side is guaranteed to be a non-primitive |
| @@ -459,7 +470,7 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| } |
| if (right.isConstantNull()) { |
| - if (left.propagatedType.isPrimitive()) { |
| + if (leftType.isPrimitive()) { |
| return graph.addConstantBool(false); |
| } |
| } |
| @@ -471,12 +482,13 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| } |
| HInstruction visitTypeGuard(HTypeGuard node) { |
| + HTypeMap types = work.types; |
| HInstruction value = node.guarded; |
| // If the intersection of the types is still the incoming type then |
| // the incoming type was a subtype of the guarded type, and no check |
| // is required. |
| - HType combinedType = value.propagatedType.intersection(node.guardedType); |
| - return (combinedType == value.propagatedType) ? value : node; |
| + HType combinedType = types[value].intersection(node.guardedType); |
| + return (combinedType == types[value]) ? value : node; |
| } |
| HInstruction visitIs(HIs node) { |
| @@ -486,7 +498,7 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| compiler.unimplemented("visitIs for type variables"); |
| } |
| - HType expressionType = node.expression.propagatedType; |
| + HType expressionType = work.types[node.expression]; |
| if (element === compiler.objectClass |
| || element === compiler.dynamicClass) { |
| return graph.addConstantBool(true); |
| @@ -548,21 +560,23 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| } |
| HInstruction visitTypeConversion(HTypeConversion node) { |
| + HTypeMap types = work.types; |
| HInstruction value = node.inputs[0]; |
| - Type type = node.propagatedType.computeType(compiler); |
| + Type type = types[node].computeType(compiler); |
| if (type.element === compiler.dynamicClass |
| || type.element === compiler.objectClass) { |
| return value; |
| } |
| - HType combinedType = value.propagatedType.intersection(node.propagatedType); |
| - return (combinedType == value.propagatedType) ? value : node; |
| + HType combinedType = types[value].intersection(types[node]); |
| + return (combinedType == types[value]) ? value : node; |
| } |
| HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { |
| HInstruction receiver = node.inputs[0]; |
| - if (!receiver.propagatedType.isUseful()) return node; |
| - if (receiver.propagatedType.canBeNull()) return node; |
| - Type type = receiver.propagatedType.computeType(compiler); |
| + HType receiverType = work.types[receiver]; |
| + if (!receiverType.isUseful()) return node; |
| + if (receiverType.canBeNull()) return node; |
| + Type type = receiverType.computeType(compiler); |
| if (type === null) return node; |
| Element field = compiler.world.locateSingleField(type, node.name); |
| if (field === null) return node; |
| @@ -597,9 +611,10 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
| HInstruction receiver = node.inputs[0]; |
| - if (!receiver.propagatedType.isUseful()) return node; |
| - if (receiver.propagatedType.canBeNull()) return node; |
| - Type type = receiver.propagatedType.computeType(compiler); |
| + HType receiverType = work.types[receiver]; |
| + if (!receiverType.isUseful()) return node; |
| + if (receiverType.canBeNull()) return node; |
| + Type type = receiverType.computeType(compiler); |
| if (type === null) return node; |
| Element field = compiler.world.locateSingleField(type, node.name); |
| if (field === null) return node; |
| @@ -621,10 +636,13 @@ class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase { |
| } |
| class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { |
| + final JavaScriptBackend backend; |
|
Lasse Reichstein Nielsen
2012/08/08 07:44:53
Used?
floitsch
2012/08/08 19:18:37
Done.
|
| + final JavaScriptWorkItem work; |
| final String name = "SsaCheckInserter"; |
| Element lengthInterceptor; |
| - SsaCheckInserter(JavaScriptBackend backend) { |
| + SsaCheckInserter(JavaScriptBackend backend, this.work) |
| + : this.backend = backend { |
| SourceString lengthString = const SourceString('length'); |
| lengthInterceptor = |
| backend.builder.interceptors.getStaticGetInterceptor(lengthString); |
| @@ -653,7 +671,7 @@ class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { |
| const SourceString("length"), |
| <HInstruction>[interceptor, receiver], |
| getter: true); |
| - length.propagatedType = HType.INTEGER; |
| + work.types[length] = HType.INTEGER; |
| node.block.addBefore(node, length); |
| HBoundsCheck check = new HBoundsCheck(index, length); |
| @@ -672,10 +690,11 @@ class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { |
| } |
| void visitIndex(HIndex node) { |
| - if (!node.receiver.isIndexablePrimitive()) return; |
| + HTypeMap types = work.types; |
| + if (!node.receiver.isIndexablePrimitive(types)) return; |
| HInstruction index = node.index; |
| if (index is HBoundsCheck) return; |
| - if (!node.index.isInteger()) { |
| + if (!node.index.isInteger(types)) { |
| index = insertIntegerCheck(node, index); |
| } |
| index = insertBoundsCheck(node, node.receiver, index); |
| @@ -683,10 +702,11 @@ class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { |
| } |
| void visitIndexAssign(HIndexAssign node) { |
| - if (!node.receiver.isMutableArray()) return; |
| + HTypeMap types = work.types; |
| + if (!node.receiver.isMutableArray(types)) return; |
| HInstruction index = node.index; |
| if (index is HBoundsCheck) return; |
| - if (!node.index.isInteger()) { |
| + if (!node.index.isInteger(types)) { |
| index = insertIntegerCheck(node, index); |
| } |
| index = insertBoundsCheck(node, node.receiver, index); |
| @@ -695,10 +715,14 @@ class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { |
| } |
| class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { |
| + final HTypeMap types; |
| final String name = "SsaDeadCodeEliminator"; |
| - static bool isDeadCode(HInstruction instruction) { |
| - return !instruction.hasSideEffects() |
| + SsaDeadCodeEliminator(JavaScriptWorkItem work) |
| + : types = work.types; |
| + |
| + bool isDeadCode(HInstruction instruction) { |
| + return !instruction.hasSideEffects(types) |
| && instruction.usedBy.isEmpty() |
| && instruction is !HCheck |
| && instruction is !HTypeGuard |
| @@ -825,12 +849,13 @@ class SsaRedundantPhiEliminator implements OptimizationPhase { |
| class SsaGlobalValueNumberer implements OptimizationPhase { |
| final String name = "SsaGlobalValueNumberer"; |
| final Compiler compiler; |
| + 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.
|
| final Set<int> visited; |
| List<int> blockChangesFlags; |
| List<int> loopChangesFlags; |
| - SsaGlobalValueNumberer(this.compiler) : visited = new Set<int>(); |
| + SsaGlobalValueNumberer(this.compiler, this.work) : visited = new Set<int>(); |
| void visitGraph(HGraph graph) { |
| computeChangesFlags(graph); |
| @@ -938,6 +963,8 @@ class SsaGlobalValueNumberer implements OptimizationPhase { |
| } |
| void computeChangesFlags(HGraph graph) { |
| + HTypeMap types = work.types; |
| + |
| // Create the changes flags lists. Make sure to initialize the |
| // loop changes flags list to zero so we can use bitwise or when |
| // propagating loop changes upwards. |
| @@ -956,7 +983,7 @@ class SsaGlobalValueNumberer implements OptimizationPhase { |
| int changesFlags = 0; |
| HInstruction instruction = block.first; |
| while (instruction !== null) { |
| - instruction.prepareGvn(); |
| + instruction.prepareGvn(types); |
| changesFlags |= instruction.getChangesFlags(); |
| instruction = instruction.next; |
| } |
| @@ -1163,7 +1190,7 @@ class SsaTypeConversionInserter extends HBaseVisitor |
| // field types. |
| class BaseRecompilationVisitor extends HBaseVisitor { |
| final JavaScriptBackend backend; |
| - final WorkItem work; |
| + final JavaScriptWorkItem work; |
|
Lasse Reichstein Nielsen
2012/08/08 07:44:53
Just needed for types?
floitsch
2012/08/08 19:18:37
Done.
|
| Compiler get compiler() => backend.compiler; |
| BaseRecompilationVisitor(this.backend, this.work); |
| @@ -1265,8 +1292,9 @@ class SsaRecompilationFieldTypePropagator |
| final String name = "SsaRecompilationFieldTypePropagator"; |
| HGraph graph; |
| - SsaRecompilationFieldTypePropagator( |
| - JavaScriptBackend backend, WorkItem work) : super(backend, work); |
| + SsaRecompilationFieldTypePropagator(JavaScriptBackend backend, |
| + JavaScriptWorkItem work) |
| + : super(backend, work); |
| void visitGraph(HGraph visitee) { |
| graph = visitee; |
| @@ -1287,8 +1315,7 @@ class SsaRecompilationFieldTypePropagator |
| field.guaranteedType = |
| type.union(backend.fieldSettersTypeSoFar(element)); |
| } else { |
| - field.propagatedType = |
| - type.union(backend.fieldSettersTypeSoFar(element)); |
| + work.types[field] = type.union(backend.fieldSettersTypeSoFar(element)); |
| } |
| } |
| } |
| @@ -1301,7 +1328,7 @@ class SsaRecompilationFieldTypePropagator |
| // type, but the fact that the class itself sticks to |
| // this type for the field is still a strong signal |
| // indicating the expected type of the field. |
| - field.propagatedType = type; |
| + work.types[field] = type; |
| } else { |
| // If there are no invoked setters we know the type of |
| // this field for sure. |