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 part of ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 class SsaCodeGeneratorTask extends CompilerTask { | 7 class SsaCodeGeneratorTask extends CompilerTask { |
| 8 | 8 |
| 9 final JavaScriptBackend backend; | 9 final JavaScriptBackend backend; |
| 10 | 10 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 47 if (work.element.isField()) { | 47 if (work.element.isField()) { |
| 48 return generateLazyInitializer(work, graph); | 48 return generateLazyInitializer(work, graph); |
| 49 } else { | 49 } else { |
| 50 return generateMethod(work, graph); | 50 return generateMethod(work, graph); |
| 51 } | 51 } |
| 52 } | 52 } |
| 53 | 53 |
| 54 CodeBuffer generateLazyInitializer(work, graph) { | 54 CodeBuffer generateLazyInitializer(work, graph) { |
| 55 return measure(() { | 55 return measure(() { |
| 56 compiler.tracer.traceGraph("codegen", graph); | 56 compiler.tracer.traceGraph("codegen", graph); |
| 57 List<js.Parameter> parameters = <js.Parameter>[]; | 57 SsaOptimizedCodeGenerator codegen = |
| 58 SsaOptimizedCodeGenerator codegen = new SsaOptimizedCodeGenerator( | 58 new SsaOptimizedCodeGenerator(backend, work); |
| 59 backend, work, parameters, new Map<Element, String>()); | |
| 60 codegen.visitGraph(graph); | 59 codegen.visitGraph(graph); |
| 61 js.Block body = codegen.body; | 60 js.Block body = codegen.body; |
| 62 js.Fun fun = new js.Fun(parameters, body); | 61 js.Fun fun = new js.Fun(codegen.parameters, body); |
| 63 return prettyPrint(fun); | 62 return prettyPrint(fun); |
| 64 }); | 63 }); |
| 65 } | 64 } |
| 66 | 65 |
| 67 CodeBuffer generateMethod(WorkItem work, HGraph graph) { | 66 CodeBuffer generateMethod(WorkItem work, HGraph graph) { |
| 68 return measure(() { | 67 return measure(() { |
| 69 JavaScriptItemCompilationContext context = work.compilationContext; | 68 JavaScriptItemCompilationContext context = work.compilationContext; |
| 70 HTypeMap types = context.types; | 69 HTypeMap types = context.types; |
| 71 graph.exit.predecessors.forEach((block) { | 70 graph.exit.predecessors.forEach((block) { |
| 72 assert(block.last is HGoto || block.last is HReturn); | 71 assert(block.last is HGoto || block.last is HReturn); |
| 73 if (block.last is HReturn) { | 72 if (block.last is HReturn) { |
| 74 backend.registerReturnType(work.element, types[block.last.inputs[0]]); | 73 backend.registerReturnType(work.element, types[block.last.inputs[0]]); |
| 75 } else { | 74 } else { |
| 76 backend.registerReturnType(work.element, HType.NULL); | 75 backend.registerReturnType(work.element, HType.NULL); |
| 77 } | 76 } |
| 78 }); | 77 }); |
| 79 compiler.tracer.traceGraph("codegen", graph); | 78 compiler.tracer.traceGraph("codegen", graph); |
| 80 Map<Element, String> parameterNames = getParameterNames(work); | 79 SsaOptimizedCodeGenerator codegen = |
| 81 // Use [work.element] to ensure that the parameter element come from | 80 new SsaOptimizedCodeGenerator(backend, work); |
| 82 // the declaration. | |
| 83 FunctionElement function = work.element; | |
| 84 function.computeSignature(compiler).forEachParameter((element) { | |
| 85 compiler.enqueuer.codegen.addToWorkList(element, work.resolutionTree); | |
| 86 }); | |
| 87 List<js.Parameter> parameters = <js.Parameter>[]; | |
| 88 parameterNames.forEach((element, name) { | |
| 89 parameters.add(new js.Parameter(name)); | |
| 90 }); | |
| 91 addBackendParameters(work.element, parameters, parameterNames); | |
| 92 String parametersString = Strings.join(parameterNames.values, ", "); | |
| 93 SsaOptimizedCodeGenerator codegen = new SsaOptimizedCodeGenerator( | |
| 94 backend, work, parameters, parameterNames); | |
| 95 codegen.visitGraph(graph); | 81 codegen.visitGraph(graph); |
| 96 | 82 |
| 97 FunctionElement element = work.element; | 83 FunctionElement element = work.element; |
| 98 js.Block body; | 84 js.Block body; |
| 99 ClassElement enclosingClass = element.getEnclosingClass(); | 85 ClassElement enclosingClass = element.getEnclosingClass(); |
| 100 bool allowVariableMinification; | 86 bool allowVariableMinification; |
| 101 if (element.isInstanceMember() | 87 if (element.isInstanceMember() |
| 102 && enclosingClass.isNative() | 88 && enclosingClass.isNative() |
| 103 && native.isOverriddenMethod( | 89 && native.isOverriddenMethod( |
| 104 element, enclosingClass, nativeEmitter)) { | 90 element, enclosingClass, nativeEmitter)) { |
| 105 // Record that this method is overridden. In case of optional | 91 // Record that this method is overridden. In case of optional |
| 106 // arguments, the emitter will generate stubs to handle them, | 92 // arguments, the emitter will generate stubs to handle them, |
| 107 // and needs to know if the method is overridden. | 93 // and needs to know if the method is overridden. |
| 108 nativeEmitter.overriddenMethods.add(element); | 94 nativeEmitter.overriddenMethods.add(element); |
| 109 StringBuffer buffer = new StringBuffer(); | 95 StringBuffer buffer = new StringBuffer(); |
| 110 String codeString = prettyPrint(codegen.body).toString(); | 96 String codeString = prettyPrint(codegen.body).toString(); |
| 97 String parametersString = Strings.join(codegen.parameterNames.values, ", "); | |
|
floitsch
2012/11/07 14:44:37
80chars.
ngeoffray
2012/11/07 14:47:48
Done.
| |
| 111 native.generateMethodWithPrototypeCheckForElement( | 98 native.generateMethodWithPrototypeCheckForElement( |
| 112 compiler, buffer, element, codeString, parametersString); | 99 compiler, buffer, element, codeString, parametersString); |
| 113 js.Node nativeCode = new js.LiteralStatement(buffer.toString()); | 100 js.Node nativeCode = new js.LiteralStatement(buffer.toString()); |
| 114 body = new js.Block(<js.Statement>[nativeCode]); | 101 body = new js.Block(<js.Statement>[nativeCode]); |
| 115 allowVariableMinification = false; | 102 allowVariableMinification = false; |
| 116 } else { | 103 } else { |
| 117 body = codegen.body; | 104 body = codegen.body; |
| 118 allowVariableMinification = !codegen.visitedForeignCode; | 105 allowVariableMinification = !codegen.visitedForeignCode; |
| 119 } | 106 } |
| 120 js.Fun fun = buildJavaScriptFunction(element, parameters, body); | 107 js.Fun fun = buildJavaScriptFunction(element, codegen.parameters, body); |
| 121 return prettyPrint(fun, | 108 return prettyPrint(fun, |
| 122 allowVariableMinification: allowVariableMinification); | 109 allowVariableMinification: allowVariableMinification); |
| 123 }); | 110 }); |
| 124 } | 111 } |
| 125 | 112 |
| 126 void addBackendParameter(Element element, | |
| 127 List<js.Parameter> parameters, | |
| 128 Map<Element, String> parameterNames) { | |
| 129 String name = element.name.slowToString(); | |
| 130 String prefix = ''; | |
| 131 // Avoid collisions with real parameters of the method. | |
| 132 do { | |
| 133 name = JsNames.getValid('$prefix$name'); | |
| 134 prefix = '\$$prefix'; | |
| 135 } while (parameterNames.containsValue(name)); | |
| 136 parameterNames[element] = name; | |
| 137 parameters.add(new js.Parameter(name)); | |
| 138 } | |
| 139 | |
| 140 void addBackendParameters(Element element, | |
| 141 List<js.Parameter> parameters, | |
| 142 Map<Element, String> parameterNames) { | |
| 143 // TODO(ngeoffray): We should infer this information from the | |
| 144 // graph, instead of recomputing what the builder did. | |
| 145 if (element.isConstructor()) { | |
| 146 // Put the type parameters. | |
| 147 ClassElement cls = element.enclosingElement; | |
| 148 if (!compiler.world.needsRti(cls)) return; | |
| 149 cls.typeVariables.forEach((TypeVariableType typeVariable) { | |
| 150 addBackendParameter(typeVariable.element, parameters, parameterNames); | |
| 151 }); | |
| 152 } else if (element.isGenerativeConstructorBody()) { | |
| 153 // Put the parameter checks parameters. | |
| 154 Node node = element.implementation.parseNode(compiler); | |
| 155 ClosureClassMap closureData = | |
| 156 compiler.closureToClassMapper.getMappingForNestedFunction(node); | |
| 157 FunctionElement functionElement = element; | |
| 158 FunctionSignature params = functionElement.computeSignature(compiler); | |
| 159 TreeElements elements = | |
| 160 compiler.enqueuer.resolution.getCachedElements(element); | |
| 161 params.orderedForEachParameter((Element element) { | |
| 162 if (elements.isParameterChecked(element)) { | |
| 163 Element checkResultElement = | |
| 164 closureData.parametersWithSentinel[element]; | |
| 165 addBackendParameter(checkResultElement, parameters, parameterNames); | |
| 166 } | |
| 167 }); | |
| 168 // Put the box parameter. | |
| 169 ClosureScope scopeData = closureData.capturingScopes[node]; | |
| 170 if (scopeData != null) { | |
| 171 addBackendParameter(scopeData.boxElement, parameters, parameterNames); | |
| 172 } | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 CodeBuffer generateBailoutMethod(WorkItem work, HGraph graph) { | 113 CodeBuffer generateBailoutMethod(WorkItem work, HGraph graph) { |
| 177 return measure(() { | 114 return measure(() { |
| 178 compiler.tracer.traceGraph("codegen-bailout", graph); | 115 compiler.tracer.traceGraph("codegen-bailout", graph); |
| 179 | 116 |
| 180 Map<Element, String> parameterNames = getParameterNames(work); | 117 SsaUnoptimizedCodeGenerator codegen = |
| 181 List<js.Parameter> parameters = <js.Parameter>[]; | 118 new SsaUnoptimizedCodeGenerator(backend, work); |
| 182 parameterNames.forEach((element, name) { | |
| 183 parameters.add(new js.Parameter(name)); | |
| 184 }); | |
| 185 addBackendParameters(work.element, parameters, parameterNames); | |
| 186 | |
| 187 SsaUnoptimizedCodeGenerator codegen = new SsaUnoptimizedCodeGenerator( | |
| 188 backend, work, parameters, parameterNames); | |
| 189 codegen.visitGraph(graph); | 119 codegen.visitGraph(graph); |
| 190 | 120 |
| 191 js.Block body = new js.Block(<js.Statement>[]); | 121 js.Block body = new js.Block(<js.Statement>[]); |
| 192 if (codegen.setup != null) body.statements.add(codegen.setup); | 122 if (codegen.setup != null) body.statements.add(codegen.setup); |
| 193 body.statements.add(codegen.body); | 123 body.statements.add(codegen.body); |
| 194 js.Fun fun = | 124 js.Fun fun = |
| 195 buildJavaScriptFunction(work.element, codegen.newParameters, body); | 125 buildJavaScriptFunction(work.element, codegen.newParameters, body); |
| 196 return prettyPrint(fun); | 126 return prettyPrint(fun); |
| 197 }); | 127 }); |
| 198 } | 128 } |
| 199 | |
| 200 Map<Element, String> getParameterNames(WorkItem work) { | |
| 201 // Make sure the map preserves insertion order, so that fetching | |
| 202 // the values will keep the order of parameters. | |
| 203 Map<Element, String> parameterNames = new LinkedHashMap<Element, String>(); | |
| 204 FunctionElement function = work.element.implementation; | |
| 205 | |
| 206 // The dom/html libraries have inline JS code that reference | |
| 207 // parameter names directly. Long-term such code will be rejected. | |
| 208 // Now, just don't mangle the parameter name. | |
| 209 FunctionSignature signature = function.computeSignature(compiler); | |
| 210 signature.orderedForEachParameter((Element element) { | |
| 211 parameterNames[element] = function.isNative() | |
| 212 ? element.name.slowToString() | |
| 213 : JsNames.getValid('${element.name.slowToString()}'); | |
| 214 }); | |
| 215 return parameterNames; | |
| 216 } | |
| 217 } | 129 } |
| 218 | 130 |
| 219 // Stop-gap until the core classes have such a class. | 131 // Stop-gap until the core classes have such a class. |
| 220 class OrderedSet<T> { | 132 class OrderedSet<T> { |
| 221 final LinkedHashMap<T, bool> map = new LinkedHashMap<T, bool>(); | 133 final LinkedHashMap<T, bool> map = new LinkedHashMap<T, bool>(); |
| 222 | 134 |
| 223 void add(T x) { | 135 void add(T x) { |
| 224 if (!map.containsKey(x)) { | 136 if (!map.containsKey(x)) { |
| 225 map[x] = true; | 137 map[x] = true; |
| 226 } | 138 } |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 268 | 180 |
| 269 final JavaScriptBackend backend; | 181 final JavaScriptBackend backend; |
| 270 final WorkItem work; | 182 final WorkItem work; |
| 271 final HTypeMap types; | 183 final HTypeMap types; |
| 272 | 184 |
| 273 final Set<HInstruction> generateAtUseSite; | 185 final Set<HInstruction> generateAtUseSite; |
| 274 final Set<HInstruction> controlFlowOperators; | 186 final Set<HInstruction> controlFlowOperators; |
| 275 final Map<Element, ElementAction> breakAction; | 187 final Map<Element, ElementAction> breakAction; |
| 276 final Map<Element, ElementAction> continueAction; | 188 final Map<Element, ElementAction> continueAction; |
| 277 final Map<Element, String> parameterNames; | 189 final Map<Element, String> parameterNames; |
| 190 final List<js.Parameter> parameters; | |
| 278 | 191 |
| 279 js.Block currentContainer; | 192 js.Block currentContainer; |
| 280 js.Block get body => currentContainer; | 193 js.Block get body => currentContainer; |
| 281 List<js.Expression> expressionStack; | 194 List<js.Expression> expressionStack; |
| 282 List<js.Block> oldContainerStack; | 195 List<js.Block> oldContainerStack; |
| 283 | 196 |
| 284 /** | 197 /** |
| 285 * Contains the names of the instructions, as well as the parallel | 198 * Contains the names of the instructions, as well as the parallel |
| 286 * copies to perform on block transitioning. | 199 * copies to perform on block transitioning. |
| 287 */ | 200 */ |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 307 HGraph currentGraph; | 220 HGraph currentGraph; |
| 308 HBasicBlock currentBlock; | 221 HBasicBlock currentBlock; |
| 309 | 222 |
| 310 // Records a block-information that is being handled specially. | 223 // Records a block-information that is being handled specially. |
| 311 // Used to break bad recursion. | 224 // Used to break bad recursion. |
| 312 HBlockInformation currentBlockInformation; | 225 HBlockInformation currentBlockInformation; |
| 313 // The subgraph is used to delimit traversal for some constructions, e.g., | 226 // The subgraph is used to delimit traversal for some constructions, e.g., |
| 314 // if branches. | 227 // if branches. |
| 315 SubGraph subGraph; | 228 SubGraph subGraph; |
| 316 | 229 |
| 317 SsaCodeGenerator(this.backend, | 230 SsaCodeGenerator(this.backend, WorkItem work) |
| 318 WorkItem work, | |
| 319 this.parameterNames) | |
| 320 : this.work = work, | 231 : this.work = work, |
| 321 this.types = | 232 this.types = |
| 322 (work.compilationContext as JavaScriptItemCompilationContext).types, | 233 (work.compilationContext as JavaScriptItemCompilationContext).types, |
| 234 parameterNames = new LinkedHashMap<Element, String>(), | |
| 323 declaredLocals = new Set<String>(), | 235 declaredLocals = new Set<String>(), |
| 324 collectedVariableDeclarations = new OrderedSet<String>(), | 236 collectedVariableDeclarations = new OrderedSet<String>(), |
| 325 currentContainer = new js.Block.empty(), | 237 currentContainer = new js.Block.empty(), |
| 238 parameters = <js.Parameter>[], | |
| 326 expressionStack = <js.Expression>[], | 239 expressionStack = <js.Expression>[], |
| 327 oldContainerStack = <js.Block>[], | 240 oldContainerStack = <js.Block>[], |
| 328 generateAtUseSite = new Set<HInstruction>(), | 241 generateAtUseSite = new Set<HInstruction>(), |
| 329 controlFlowOperators = new Set<HInstruction>(), | 242 controlFlowOperators = new Set<HInstruction>(), |
| 330 breakAction = new Map<Element, ElementAction>(), | 243 breakAction = new Map<Element, ElementAction>(), |
| 331 continueAction = new Map<Element, ElementAction>(); | 244 continueAction = new Map<Element, ElementAction>(); |
| 332 | 245 |
| 333 LibraryElement get currentLibrary => work.element.getLibrary(); | 246 LibraryElement get currentLibrary => work.element.getLibrary(); |
| 334 Compiler get compiler => backend.compiler; | 247 Compiler get compiler => backend.compiler; |
| 335 NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter; | 248 NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter; |
| (...skipping 2282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2618 } | 2531 } |
| 2619 String helperName = backend.namer.isolateAccess(helperElement); | 2532 String helperName = backend.namer.isolateAccess(helperElement); |
| 2620 push(new js.Call(new js.VariableUse(helperName), arguments)); | 2533 push(new js.Call(new js.VariableUse(helperName), arguments)); |
| 2621 } else { | 2534 } else { |
| 2622 use(node.checkedInput); | 2535 use(node.checkedInput); |
| 2623 } | 2536 } |
| 2624 } | 2537 } |
| 2625 } | 2538 } |
| 2626 | 2539 |
| 2627 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { | 2540 class SsaOptimizedCodeGenerator extends SsaCodeGenerator { |
| 2628 SsaOptimizedCodeGenerator(backend, work, parameters, parameterNames) | 2541 SsaOptimizedCodeGenerator(backend, work) : super(backend, work); |
| 2629 : super(backend, work, parameterNames) { | 2542 |
| 2543 int maxBailoutParameters; | |
| 2544 | |
| 2545 HBasicBlock beginGraph(HGraph graph) { | |
| 2630 // Declare the parameter names only for the optimized version. The | 2546 // Declare the parameter names only for the optimized version. The |
| 2631 // unoptimized version has different parameters. | 2547 // unoptimized version has different parameters. |
| 2632 parameterNames.forEach((Element element, String name) { | 2548 parameterNames.forEach((Element element, String name) { |
| 2549 parameters.add(new js.Parameter(name)); | |
| 2633 declaredLocals.add(name); | 2550 declaredLocals.add(name); |
| 2634 }); | 2551 }); |
| 2552 return graph.entry; | |
| 2635 } | 2553 } |
| 2636 | 2554 |
| 2637 int maxBailoutParameters; | |
| 2638 | |
| 2639 HBasicBlock beginGraph(HGraph graph) => graph.entry; | |
| 2640 void endGraph(HGraph graph) {} | 2555 void endGraph(HGraph graph) {} |
| 2641 | 2556 |
| 2642 js.Statement bailout(HTypeGuard guard, String reason) { | 2557 js.Statement bailout(HTypeGuard guard, String reason) { |
| 2643 if (maxBailoutParameters == null) { | 2558 if (maxBailoutParameters == null) { |
| 2644 maxBailoutParameters = 0; | 2559 maxBailoutParameters = 0; |
| 2645 work.guards.forEach((HTypeGuard workGuard) { | 2560 work.guards.forEach((HTypeGuard workGuard) { |
| 2646 HBailoutTarget target = workGuard.bailoutTarget; | 2561 HBailoutTarget target = workGuard.bailoutTarget; |
| 2647 int inputLength = target.inputs.length; | 2562 int inputLength = target.inputs.length; |
| 2648 if (inputLength > maxBailoutParameters) { | 2563 if (inputLength > maxBailoutParameters) { |
| 2649 maxBailoutParameters = inputLength; | 2564 maxBailoutParameters = inputLength; |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2815 /** | 2730 /** |
| 2816 * Keeps track if a bailout switch already used its [:default::] clause. New | 2731 * Keeps track if a bailout switch already used its [:default::] clause. New |
| 2817 * bailout-switches just push [:false:] on the stack and replace it when | 2732 * bailout-switches just push [:false:] on the stack and replace it when |
| 2818 * they used the [:default::] clause. | 2733 * they used the [:default::] clause. |
| 2819 */ | 2734 */ |
| 2820 final List<bool> defaultClauseUsedInBailoutStack; | 2735 final List<bool> defaultClauseUsedInBailoutStack; |
| 2821 | 2736 |
| 2822 SsaBailoutPropagator propagator; | 2737 SsaBailoutPropagator propagator; |
| 2823 HInstruction savedFirstInstruction; | 2738 HInstruction savedFirstInstruction; |
| 2824 | 2739 |
| 2825 SsaUnoptimizedCodeGenerator(backend, work, parameters, parameterNames) | 2740 SsaUnoptimizedCodeGenerator(backend, work) |
| 2826 : super(backend, work, parameterNames), | 2741 : super(backend, work), |
| 2827 oldBailoutSwitches = <js.Switch>[], | 2742 oldBailoutSwitches = <js.Switch>[], |
| 2828 newParameters = <js.Parameter>[], | 2743 newParameters = <js.Parameter>[], |
| 2829 labels = <String>[], | 2744 labels = <String>[], |
| 2830 defaultClauseUsedInBailoutStack = <bool>[]; | 2745 defaultClauseUsedInBailoutStack = <bool>[]; |
| 2831 | 2746 |
| 2832 String pushLabel() { | 2747 String pushLabel() { |
| 2833 String label = 'L${labelId++}'; | 2748 String label = 'L${labelId++}'; |
| 2834 labels.addLast(label); | 2749 labels.addLast(label); |
| 2835 return label; | 2750 return label; |
| 2836 } | 2751 } |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3144 if (leftType.canBeNull() && rightType.canBeNull()) { | 3059 if (leftType.canBeNull() && rightType.canBeNull()) { |
| 3145 if (left.isConstantNull() || right.isConstantNull() || | 3060 if (left.isConstantNull() || right.isConstantNull() || |
| 3146 (leftType.isPrimitive() && leftType == rightType)) { | 3061 (leftType.isPrimitive() && leftType == rightType)) { |
| 3147 return '=='; | 3062 return '=='; |
| 3148 } | 3063 } |
| 3149 return null; | 3064 return null; |
| 3150 } else { | 3065 } else { |
| 3151 return '==='; | 3066 return '==='; |
| 3152 } | 3067 } |
| 3153 } | 3068 } |
| OLD | NEW |