Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(77)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/ssa/builder.dart

Issue 15739005: Inline generative constructor calls. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698