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 |