| 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 |