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 /** | 7 /** |
8 * A special element for the extra parameter taken by intercepted | 8 * A special element for the extra parameter taken by intercepted |
9 * methods. We need to override [Element.computeType] because our | 9 * methods. We need to override [Element.computeType] because our |
10 * optimizers may look at its declared type. | 10 * optimizers may look at its declared type. |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 name = "${element.name.slowToString()}"; | 96 name = "${element.name.slowToString()}"; |
97 } | 97 } |
98 compiler.tracer.traceCompilation(name, work.compilationContext); | 98 compiler.tracer.traceCompilation(name, work.compilationContext); |
99 compiler.tracer.traceGraph('builder', graph); | 99 compiler.tracer.traceGraph('builder', graph); |
100 } | 100 } |
101 return graph; | 101 return graph; |
102 }); | 102 }); |
103 } | 103 } |
104 | 104 |
105 HGraph compileConstructor(SsaBuilder builder, CodegenWorkItem work) { | 105 HGraph compileConstructor(SsaBuilder builder, CodegenWorkItem work) { |
106 // The body of the constructor will be generated in a separate function. | 106 return builder.buildFactory(work.element); |
107 final ClassElement classElement = work.element.getEnclosingClass(); | |
108 return builder.buildFactory(classElement.implementation, | |
109 work.element.implementation); | |
110 } | 107 } |
111 } | 108 } |
112 | 109 |
113 | 110 |
114 /** | 111 /** |
115 * Keeps track of locals (including parameters and phis) when building. The | 112 * Keeps track of locals (including parameters and phis) when building. The |
116 * 'this' reference is treated as parameter and hence handled by this class, | 113 * 'this' reference is treated as parameter and hence handled by this class, |
117 * too. | 114 * too. |
118 */ | 115 */ |
119 class LocalsHandler { | 116 class LocalsHandler { |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 closureData.freeVariableMapping.forEach((Element from, Element to) { | 269 closureData.freeVariableMapping.forEach((Element from, Element to) { |
273 redirectElement(from, to); | 270 redirectElement(from, to); |
274 }); | 271 }); |
275 if (closureData.isClosure()) { | 272 if (closureData.isClosure()) { |
276 // Inside closure redirect references to itself to [:this:]. | 273 // Inside closure redirect references to itself to [:this:]. |
277 HThis thisInstruction = new HThis(closureData.thisElement, | 274 HThis thisInstruction = new HThis(closureData.thisElement, |
278 HType.NON_NULL); | 275 HType.NON_NULL); |
279 builder.graph.thisInstruction = thisInstruction; | 276 builder.graph.thisInstruction = thisInstruction; |
280 builder.graph.entry.addAtEntry(thisInstruction); | 277 builder.graph.entry.addAtEntry(thisInstruction); |
281 updateLocal(closureData.closureElement, thisInstruction); | 278 updateLocal(closureData.closureElement, thisInstruction); |
282 } else if (element.isInstanceMember() | 279 } else if (element.isInstanceMember()) { |
283 || element.isGenerativeConstructor()) { | |
284 // Once closures have been mapped to classes their instance members might | 280 // Once closures have been mapped to classes their instance members might |
285 // not have any thisElement if the closure was created inside a static | 281 // not have any thisElement if the closure was created inside a static |
286 // context. | 282 // context. |
287 HThis thisInstruction = new HThis( | 283 HThis thisInstruction = new HThis( |
288 closureData.thisElement, builder.getTypeOfThis()); | 284 closureData.thisElement, builder.getTypeOfThis()); |
289 builder.graph.thisInstruction = thisInstruction; | 285 builder.graph.thisInstruction = thisInstruction; |
290 builder.graph.entry.addAtEntry(thisInstruction); | 286 builder.graph.entry.addAtEntry(thisInstruction); |
291 directLocals[closureData.thisElement] = thisInstruction; | 287 directLocals[closureData.thisElement] = thisInstruction; |
292 } | 288 } |
293 | 289 |
(...skipping 816 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1110 classElement.origin.addBackendMember(bodyElement.origin); | 1106 classElement.origin.addBackendMember(bodyElement.origin); |
1111 } | 1107 } |
1112 compiler.enqueuer.codegen.addToWorkList(bodyElement.declaration, | 1108 compiler.enqueuer.codegen.addToWorkList(bodyElement.declaration, |
1113 treeElements); | 1109 treeElements); |
1114 } | 1110 } |
1115 assert(bodyElement.isGenerativeConstructorBody()); | 1111 assert(bodyElement.isGenerativeConstructorBody()); |
1116 return bodyElement; | 1112 return bodyElement; |
1117 } | 1113 } |
1118 | 1114 |
1119 HParameterValue addParameter(Element element) { | 1115 HParameterValue addParameter(Element element) { |
| 1116 assert(inliningStack.isEmpty); |
1120 HParameterValue result = new HParameterValue(element); | 1117 HParameterValue result = new HParameterValue(element); |
1121 if (lastAddedParameter == null) { | 1118 if (lastAddedParameter == null) { |
1122 graph.entry.addBefore(graph.entry.first, result); | 1119 graph.entry.addBefore(graph.entry.first, result); |
1123 } else { | 1120 } else { |
1124 graph.entry.addAfter(lastAddedParameter, result); | 1121 graph.entry.addAfter(lastAddedParameter, result); |
1125 } | 1122 } |
1126 lastAddedParameter = result; | 1123 lastAddedParameter = result; |
1127 return result; | 1124 return result; |
1128 } | 1125 } |
1129 | 1126 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1172 assert(succeeded); | 1169 assert(succeeded); |
1173 } else { | 1170 } else { |
1174 assert(providedArguments != null); | 1171 assert(providedArguments != null); |
1175 compiledArguments = providedArguments; | 1172 compiledArguments = providedArguments; |
1176 } | 1173 } |
1177 | 1174 |
1178 // Create the inlining state after evaluating the arguments, that | 1175 // Create the inlining state after evaluating the arguments, that |
1179 // may have an impact on the state of the current method. | 1176 // may have an impact on the state of the current method. |
1180 InliningState state = new InliningState( | 1177 InliningState state = new InliningState( |
1181 function, returnElement, returnType, elements, stack, localsHandler); | 1178 function, returnElement, returnType, elements, stack, localsHandler); |
1182 LocalsHandler newLocalsHandler = new LocalsHandler.from(localsHandler); | 1179 LocalsHandler newLocalsHandler = new LocalsHandler(this); |
1183 newLocalsHandler.closureData = | 1180 newLocalsHandler.closureData = |
1184 compiler.closureToClassMapper.computeClosureToClassMapping( | 1181 compiler.closureToClassMapper.computeClosureToClassMapping( |
1185 function, function.parseNode(compiler), elements); | 1182 function, function.parseNode(compiler), elements); |
1186 int argumentIndex = 0; | 1183 int argumentIndex = 0; |
1187 if (isInstanceMember) { | 1184 if (isInstanceMember) { |
1188 newLocalsHandler.updateLocal(newLocalsHandler.closureData.thisElement, | 1185 newLocalsHandler.updateLocal(newLocalsHandler.closureData.thisElement, |
1189 compiledArguments[argumentIndex++]); | 1186 compiledArguments[argumentIndex++]); |
1190 } | 1187 } |
1191 | 1188 |
1192 if (function.isConstructor()) { | 1189 if (function.isConstructor()) { |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1266 // Ensure that [element] is an implementation element. | 1263 // Ensure that [element] is an implementation element. |
1267 element = element.implementation; | 1264 element = element.implementation; |
1268 // TODO(floitsch): we should be able to inline inside lazy initializers. | 1265 // TODO(floitsch): we should be able to inline inside lazy initializers. |
1269 if (!currentElement.isFunction()) return false; | 1266 if (!currentElement.isFunction()) return false; |
1270 // TODO(floitsch): find a cleaner way to know if the element is a function | 1267 // TODO(floitsch): find a cleaner way to know if the element is a function |
1271 // containing nodes. | 1268 // containing nodes. |
1272 // [PartialFunctionElement]s are [FunctionElement]s that have [Node]s. | 1269 // [PartialFunctionElement]s are [FunctionElement]s that have [Node]s. |
1273 if (element is !PartialFunctionElement) return false; | 1270 if (element is !PartialFunctionElement) return false; |
1274 // TODO(ngeoffray): try to inline generative constructors. They | 1271 // TODO(ngeoffray): try to inline generative constructors. They |
1275 // don't have any body, which make it more difficult. | 1272 // don't have any body, which make it more difficult. |
1276 if (element.isGenerativeConstructor()) return false; | |
1277 if (inliningStack.length > MAX_INLINING_DEPTH) return false; | 1273 if (inliningStack.length > MAX_INLINING_DEPTH) return false; |
1278 // Don't inline recursive calls. We use the same elements for the inlined | 1274 // Don't inline recursive calls. We use the same elements for the inlined |
1279 // functions and would thus clobber our local variables. | 1275 // functions and would thus clobber our local variables. |
1280 // Use [:element.declaration:] since [work.element] is always a declaration. | 1276 // Use [:element.declaration:] since [work.element] is always a declaration. |
1281 if (currentElement == element.declaration) return false; | 1277 if (currentElement == element.declaration) return false; |
1282 for (int i = 0; i < inliningStack.length; i++) { | 1278 for (int i = 0; i < inliningStack.length; i++) { |
1283 if (inliningStack[i].function == element) return false; | 1279 if (inliningStack[i].function == element) return false; |
1284 } | 1280 } |
1285 | 1281 |
1286 PartialFunctionElement function = element; | 1282 PartialFunctionElement function = element; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1324 // inlining. We use [element] to get the same name in the NoSuchMethodError | 1320 // inlining. We use [element] to get the same name in the NoSuchMethodError |
1325 // message as if we had called it. | 1321 // message as if we had called it. |
1326 if (element.isInstanceMember() | 1322 if (element.isInstanceMember() |
1327 && (selector.mask == null || selector.mask.isNullable)) { | 1323 && (selector.mask == null || selector.mask.isNullable)) { |
1328 addWithPosition( | 1324 addWithPosition( |
1329 new HFieldGet(element, providedArguments[0]), currentNode); | 1325 new HFieldGet(element, providedArguments[0]), currentNode); |
1330 } | 1326 } |
1331 InliningState state = enterInlinedMethod( | 1327 InliningState state = enterInlinedMethod( |
1332 function, selector, argumentsNodes, providedArguments, currentNode); | 1328 function, selector, argumentsNodes, providedArguments, currentNode); |
1333 inlinedFrom(element, () { | 1329 inlinedFrom(element, () { |
1334 functionExpression.body.accept(this); | 1330 element.isGenerativeConstructor() |
| 1331 ? buildFactory(element) |
| 1332 : functionExpression.body.accept(this); |
1335 }); | 1333 }); |
1336 leaveInlinedMethod(state); | 1334 leaveInlinedMethod(state); |
1337 return true; | 1335 return true; |
1338 } | 1336 } |
1339 | 1337 |
1340 inlinedFrom(Element element, f()) { | 1338 inlinedFrom(Element element, f()) { |
1341 assert(element is FunctionElement || element is VariableElement); | 1339 assert(element is FunctionElement || element is VariableElement); |
1342 return compiler.withCurrentElement(element, () { | 1340 return compiler.withCurrentElement(element, () { |
1343 sourceElementStack.add(element); | 1341 sourceElementStack.add(element); |
1344 var result = f(); | 1342 var result = f(); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1430 if (constructor.isForwardingConstructor) { | 1428 if (constructor.isForwardingConstructor) { |
1431 constructor = constructor.targetConstructor; | 1429 constructor = constructor.targetConstructor; |
1432 } | 1430 } |
1433 elements = | 1431 elements = |
1434 compiler.enqueuer.resolution.getCachedElements(constructor); | 1432 compiler.enqueuer.resolution.getCachedElements(constructor); |
1435 ClosureClassMap oldClosureData = localsHandler.closureData; | 1433 ClosureClassMap oldClosureData = localsHandler.closureData; |
1436 Node node = constructor.parseNode(compiler); | 1434 Node node = constructor.parseNode(compiler); |
1437 ClosureClassMap newClosureData = | 1435 ClosureClassMap newClosureData = |
1438 compiler.closureToClassMapper.computeClosureToClassMapping( | 1436 compiler.closureToClassMapper.computeClosureToClassMapping( |
1439 constructor, node, elements); | 1437 constructor, node, elements); |
1440 // The [:this:] element now refers to the one in the new closure | |
1441 // data, that is the [:this:] of the super constructor. We | |
1442 // update the element to refer to the current [:this:]. | |
1443 localsHandler.updateLocal(newClosureData.thisElement, | |
1444 localsHandler.readThis()); | |
1445 localsHandler.closureData = newClosureData; | 1438 localsHandler.closureData = newClosureData; |
1446 | 1439 |
1447 params.orderedForEachParameter((Element parameterElement) { | 1440 params.orderedForEachParameter((Element parameterElement) { |
1448 if (elements.isParameterChecked(parameterElement)) { | 1441 if (elements.isParameterChecked(parameterElement)) { |
1449 addParameterCheckInstruction(parameterElement); | 1442 addParameterCheckInstruction(parameterElement); |
1450 } | 1443 } |
1451 }); | 1444 }); |
1452 localsHandler.enterScope(node, constructor); | 1445 localsHandler.enterScope(node, constructor); |
1453 buildInitializers(constructor, constructors, fieldValues); | 1446 buildInitializers(constructor, constructors, fieldValues); |
1454 localsHandler.closureData = oldClosureData; | 1447 localsHandler.closureData = oldClosureData; |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1570 | 1563 |
1571 | 1564 |
1572 /** | 1565 /** |
1573 * Build the factory function corresponding to the constructor | 1566 * Build the factory function corresponding to the constructor |
1574 * [functionElement]: | 1567 * [functionElement]: |
1575 * - Initialize fields with the values of the field initializers of the | 1568 * - Initialize fields with the values of the field initializers of the |
1576 * current constructor and super constructors or constructors redirected | 1569 * current constructor and super constructors or constructors redirected |
1577 * to, starting from the current constructor. | 1570 * to, starting from the current constructor. |
1578 * - Call the the constructor bodies, starting from the constructor(s) in the | 1571 * - Call the the constructor bodies, starting from the constructor(s) in the |
1579 * super class(es). | 1572 * super class(es). |
1580 * | |
1581 * Invariant: Both [classElement] and [functionElement] must be | |
1582 * implementation elements. | |
1583 */ | 1573 */ |
1584 HGraph buildFactory(ClassElement classElement, | 1574 HGraph buildFactory(FunctionElement functionElement) { |
1585 FunctionElement functionElement) { | 1575 functionElement = functionElement.implementation; |
1586 assert(invariant(classElement, classElement.isImplementation)); | 1576 ClassElement classElement = |
1587 assert(invariant(functionElement, functionElement.isImplementation)); | 1577 functionElement.getEnclosingClass().implementation; |
1588 FunctionExpression function = functionElement.parseNode(compiler); | 1578 FunctionExpression function = functionElement.parseNode(compiler); |
1589 // Note that constructors (like any other static function) do not need | 1579 // Note that constructors (like any other static function) do not need |
1590 // to deal with optional arguments. It is the callers job to provide all | 1580 // to deal with optional arguments. It is the callers job to provide all |
1591 // arguments as if they were positional. | 1581 // arguments as if they were positional. |
1592 | 1582 |
1593 // The initializer list could contain closures. | 1583 if (inliningStack.isEmpty) { |
1594 openFunction(functionElement, function); | 1584 // The initializer list could contain closures. |
| 1585 openFunction(functionElement, function); |
| 1586 } |
1595 | 1587 |
1596 Map<Element, HInstruction> fieldValues = new Map<Element, HInstruction>(); | 1588 Map<Element, HInstruction> fieldValues = new Map<Element, HInstruction>(); |
1597 | 1589 |
1598 // Compile the possible initialization code for local fields and | 1590 // Compile the possible initialization code for local fields and |
1599 // super fields. | 1591 // super fields. |
1600 buildFieldInitializers(classElement, fieldValues); | 1592 buildFieldInitializers(classElement, fieldValues); |
1601 | 1593 |
1602 // Compile field-parameters such as [:this.x:]. | 1594 // Compile field-parameters such as [:this.x:]. |
1603 FunctionSignature params = functionElement.computeSignature(compiler); | 1595 FunctionSignature params = functionElement.computeSignature(compiler); |
1604 params.orderedForEachParameter((Element element) { | 1596 params.orderedForEachParameter((Element element) { |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1692 ClosureScope scopeData = parameterClosureData.capturingScopes[node]; | 1684 ClosureScope scopeData = parameterClosureData.capturingScopes[node]; |
1693 if (scopeData != null) { | 1685 if (scopeData != null) { |
1694 bodyCallInputs.add(localsHandler.readLocal(scopeData.boxElement)); | 1686 bodyCallInputs.add(localsHandler.readLocal(scopeData.boxElement)); |
1695 } | 1687 } |
1696 | 1688 |
1697 HInvokeConstructorBody invoke = | 1689 HInvokeConstructorBody invoke = |
1698 new HInvokeConstructorBody(body, bodyCallInputs); | 1690 new HInvokeConstructorBody(body, bodyCallInputs); |
1699 invoke.sideEffects = compiler.world.getSideEffectsOfElement(constructor); | 1691 invoke.sideEffects = compiler.world.getSideEffectsOfElement(constructor); |
1700 add(invoke); | 1692 add(invoke); |
1701 } | 1693 } |
1702 closeAndGotoExit(new HReturn(newObject)); | 1694 if (inliningStack.isEmpty) { |
1703 return closeFunction(); | 1695 closeAndGotoExit(new HReturn(newObject)); |
| 1696 return closeFunction(); |
| 1697 } else { |
| 1698 localsHandler.updateLocal(returnElement, newObject); |
| 1699 return null; |
| 1700 } |
1704 } | 1701 } |
1705 | 1702 |
1706 void addParameterCheckInstruction(Element element) { | 1703 void addParameterCheckInstruction(Element element) { |
1707 HInstruction check; | 1704 HInstruction check; |
1708 Element checkResultElement = | 1705 Element checkResultElement = |
1709 localsHandler.closureData.parametersWithSentinel[element]; | 1706 localsHandler.closureData.parametersWithSentinel[element]; |
1710 if (currentElement.isGenerativeConstructorBody()) { | 1707 if (currentElement.isGenerativeConstructorBody()) { |
1711 // A generative constructor body receives extra parameters that | 1708 // A generative constructor body receives extra parameters that |
1712 // indicate if a parameter was passed to the factory. | 1709 // indicate if a parameter was passed to the factory. |
1713 check = addParameter(checkResultElement); | 1710 check = addParameter(checkResultElement); |
(...skipping 3337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5051 | 5048 |
5052 bool seenReturn = false; | 5049 bool seenReturn = false; |
5053 bool tooDifficult = false; | 5050 bool tooDifficult = false; |
5054 int nodeCount = 0; | 5051 int nodeCount = 0; |
5055 | 5052 |
5056 InlineWeeder(this.elements); | 5053 InlineWeeder(this.elements); |
5057 | 5054 |
5058 static bool canBeInlined(FunctionExpression functionExpression, | 5055 static bool canBeInlined(FunctionExpression functionExpression, |
5059 TreeElements elements) { | 5056 TreeElements elements) { |
5060 InlineWeeder weeder = new InlineWeeder(elements); | 5057 InlineWeeder weeder = new InlineWeeder(elements); |
| 5058 weeder.visit(functionExpression.initializers); |
5061 weeder.visit(functionExpression.body); | 5059 weeder.visit(functionExpression.body); |
5062 if (weeder.tooDifficult) return false; | 5060 if (weeder.tooDifficult) return false; |
5063 return true; | 5061 return true; |
5064 } | 5062 } |
5065 | 5063 |
5066 bool registerNode() { | 5064 bool registerNode() { |
5067 if (nodeCount++ > SsaBuilder.MAX_INLINING_NODES) { | 5065 if (nodeCount++ > SsaBuilder.MAX_INLINING_NODES) { |
5068 tooDifficult = true; | 5066 tooDifficult = true; |
5069 return false; | 5067 return false; |
5070 } else { | 5068 } else { |
5071 return true; | 5069 return true; |
5072 } | 5070 } |
5073 } | 5071 } |
5074 | 5072 |
5075 void visit(Node node) { | 5073 void visit(Node node) { |
5076 node.accept(this); | 5074 if (node != null) node.accept(this); |
5077 } | 5075 } |
5078 | 5076 |
5079 void visitNode(Node node) { | 5077 void visitNode(Node node) { |
5080 if (!registerNode()) return; | 5078 if (!registerNode()) return; |
5081 if (seenReturn) { | 5079 if (seenReturn) { |
5082 tooDifficult = true; | 5080 tooDifficult = true; |
5083 } else { | 5081 } else { |
5084 node.visitChildren(this); | 5082 node.visitChildren(this); |
5085 } | 5083 } |
5086 } | 5084 } |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5392 new HSubGraphBlockInformation(elseBranch.graph)); | 5390 new HSubGraphBlockInformation(elseBranch.graph)); |
5393 | 5391 |
5394 HBasicBlock conditionStartBlock = conditionBranch.block; | 5392 HBasicBlock conditionStartBlock = conditionBranch.block; |
5395 conditionStartBlock.setBlockFlow(info, joinBlock); | 5393 conditionStartBlock.setBlockFlow(info, joinBlock); |
5396 SubGraph conditionGraph = conditionBranch.graph; | 5394 SubGraph conditionGraph = conditionBranch.graph; |
5397 HIf branch = conditionGraph.end.last; | 5395 HIf branch = conditionGraph.end.last; |
5398 assert(branch is HIf); | 5396 assert(branch is HIf); |
5399 branch.blockInformation = conditionStartBlock.blockFlow; | 5397 branch.blockInformation = conditionStartBlock.blockFlow; |
5400 } | 5398 } |
5401 } | 5399 } |
OLD | NEW |