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

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

Issue 25675002: Generative constructor factories for native objects (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 2 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
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 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 builder.graph.thisInstruction = thisInstruction; 268 builder.graph.thisInstruction = thisInstruction;
269 builder.graph.entry.addAtEntry(thisInstruction); 269 builder.graph.entry.addAtEntry(thisInstruction);
270 directLocals[closureData.thisElement] = thisInstruction; 270 directLocals[closureData.thisElement] = thisInstruction;
271 } 271 }
272 272
273 // If this method is an intercepted method, add the extra 273 // If this method is an intercepted method, add the extra
274 // parameter to it, that is the actual receiver for intercepted 274 // parameter to it, that is the actual receiver for intercepted
275 // classes, or the same as [:this:] for non-intercepted classes. 275 // classes, or the same as [:this:] for non-intercepted classes.
276 ClassElement cls = element.getEnclosingClass(); 276 ClassElement cls = element.getEnclosingClass();
277 JavaScriptBackend backend = compiler.backend; 277 JavaScriptBackend backend = compiler.backend;
278 bool isNativeUpgradeFactory = element.isGenerativeConstructor()
ngeoffray 2013/10/17 09:08:59 What is a native upgrade factory?
sra1 2013/10/18 04:09:32 Added comment
279 && Elements.isNativeOrExtendsNative(cls);
278 if (backend.isInterceptedMethod(element)) { 280 if (backend.isInterceptedMethod(element)) {
279 bool isInterceptorClass = backend.isInterceptorClass(cls.declaration); 281 bool isInterceptorClass = backend.isInterceptorClass(cls.declaration);
280 SourceString name = isInterceptorClass 282 SourceString name = isInterceptorClass
281 ? const SourceString('receiver') 283 ? const SourceString('receiver')
282 : const SourceString('_'); 284 : const SourceString('_');
283 Element parameter = new InterceptedElement( 285 Element parameter = new InterceptedElement(
284 cls.computeType(compiler), name, element); 286 cls.computeType(compiler), name, element);
285 HParameterValue value = new HParameterValue(parameter); 287 HParameterValue value = new HParameterValue(parameter);
286 builder.graph.explicitReceiverParameter = value; 288 builder.graph.explicitReceiverParameter = value;
287 builder.graph.entry.addAfter( 289 builder.graph.entry.addAfter(
288 directLocals[closureData.thisElement], value); 290 directLocals[closureData.thisElement], value);
289 if (isInterceptorClass) { 291 if (isInterceptorClass) {
290 // Only use the extra parameter in intercepted classes. 292 // Only use the extra parameter in intercepted classes.
291 directLocals[closureData.thisElement] = value; 293 directLocals[closureData.thisElement] = value;
292 } 294 }
293 value.instructionType = builder.getTypeOfThis(); 295 value.instructionType = builder.getTypeOfThis();
296 } else if (isNativeUpgradeFactory) {
297 bool isInterceptorClass = backend.isInterceptorClass(cls.declaration);
298 Element parameter = new InterceptedElement(
299 cls.computeType(compiler), const SourceString('receiver'), element);
300 HParameterValue value = new HParameterValue(parameter);
301 builder.graph.explicitReceiverParameter = value;
302 builder.graph.entry.addAtEntry(value);
303 value.instructionType = builder.getTypeOfThis();
ngeoffray 2013/10/17 09:08:59 This seems very similar to the code line 281 to 29
sra1 2013/10/18 04:09:32 In the fixed version there are more differences, e
294 } 304 }
295 } 305 }
296 306
297 bool hasValueForDirectLocal(Element element) { 307 bool hasValueForDirectLocal(Element element) {
298 assert(element != null); 308 assert(element != null);
299 assert(isAccessedDirectly(element)); 309 assert(isAccessedDirectly(element));
300 return directLocals[element] != null; 310 return directLocals[element] != null;
301 } 311 }
302 312
303 /** 313 /**
(...skipping 956 matching lines...) Expand 10 before | Expand all | Expand 10 after
1260 } 1270 }
1261 1271
1262 // Don't inline operator== methods if the parameter can be null. 1272 // Don't inline operator== methods if the parameter can be null.
1263 if (element.name == const SourceString('==')) { 1273 if (element.name == const SourceString('==')) {
1264 if (element.getEnclosingClass() != compiler.objectClass 1274 if (element.getEnclosingClass() != compiler.objectClass
1265 && providedArguments[1].canBeNull()) { 1275 && providedArguments[1].canBeNull()) {
1266 return false; 1276 return false;
1267 } 1277 }
1268 } 1278 }
1269 1279
1280 // Generative constructors of native classes should not be called directly
1281 // and have an extra argument that causes problems with inlining.
1282 if (element.isGenerativeConstructor()
1283 && Elements.isNativeOrExtendsNative(element.getEnclosingClass())) {
1284 return false;
1285 }
1286
1270 // A generative constructor body is not seen by global analysis, 1287 // A generative constructor body is not seen by global analysis,
1271 // so we should not query for its type. 1288 // so we should not query for its type.
1272 if (!element.isGenerativeConstructorBody()) { 1289 if (!element.isGenerativeConstructorBody()) {
1273 // Don't inline if the return type was inferred to be non-null empty. 1290 // Don't inline if the return type was inferred to be non-null empty.
1274 // This means that the function always throws an exception. 1291 // This means that the function always throws an exception.
1275 TypeMask returnType = 1292 TypeMask returnType =
1276 compiler.typesTask.getGuaranteedReturnTypeOfElement(element); 1293 compiler.typesTask.getGuaranteedReturnTypeOfElement(element);
1277 if (returnType != null 1294 if (returnType != null
1278 && returnType.isEmpty 1295 && returnType.isEmpty
1279 && !returnType.isNullable) { 1296 && !returnType.isNullable) {
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after
1579 */ 1596 */
1580 void buildFieldInitializers(ClassElement classElement, 1597 void buildFieldInitializers(ClassElement classElement,
1581 Map<Element, HInstruction> fieldValues) { 1598 Map<Element, HInstruction> fieldValues) {
1582 assert(invariant(classElement, classElement.isImplementation)); 1599 assert(invariant(classElement, classElement.isImplementation));
1583 classElement.forEachInstanceField( 1600 classElement.forEachInstanceField(
1584 (ClassElement enclosingClass, Element member) { 1601 (ClassElement enclosingClass, Element member) {
1585 compiler.withCurrentElement(member, () { 1602 compiler.withCurrentElement(member, () {
1586 TreeElements definitions = compiler.analyzeElement(member); 1603 TreeElements definitions = compiler.analyzeElement(member);
1587 Node node = member.parseNode(compiler); 1604 Node node = member.parseNode(compiler);
1588 SendSet assignment = node.asSendSet(); 1605 SendSet assignment = node.asSendSet();
1589 HInstruction value;
1590 if (assignment == null) { 1606 if (assignment == null) {
1591 value = graph.addConstantNull(compiler); 1607 // Unassigned fields of native classes are not initialized to
1608 // prevent overwriting pre-initialized native properties.
1609 if (!Elements.isNativeOrExtendsNative(classElement)) {
1610 HInstruction value = graph.addConstantNull(compiler);
ngeoffray 2013/10/17 09:08:59 Avoid the temporary?
sra1 2013/10/18 04:09:32 Done.
1611 fieldValues[member] = value;
1612 }
1592 } else { 1613 } else {
1593 Node right = assignment.arguments.head; 1614 Node right = assignment.arguments.head;
1594 TreeElements savedElements = elements; 1615 TreeElements savedElements = elements;
1595 elements = definitions; 1616 elements = definitions;
1596 // In case the field initializer uses closures, run the 1617 // In case the field initializer uses closures, run the
1597 // closure to class mapper. 1618 // closure to class mapper.
1598 compiler.closureToClassMapper.computeClosureToClassMapping( 1619 compiler.closureToClassMapper.computeClosureToClassMapping(
1599 member, node, elements); 1620 member, node, elements);
1600 inlinedFrom(member, () => right.accept(this)); 1621 inlinedFrom(member, () => right.accept(this));
1601 elements = savedElements; 1622 elements = savedElements;
1602 value = pop(); 1623 HInstruction value = pop();
1624 fieldValues[member] = value;
ngeoffray 2013/10/17 09:08:59 Avoid the temporary?
sra1 2013/10/18 04:09:32 Done.
1603 } 1625 }
1604 fieldValues[member] = value;
1605 }); 1626 });
1606 }); 1627 });
1607 } 1628 }
1608 1629
1609 /** 1630 /**
1610 * Build the factory function corresponding to the constructor 1631 * Build the factory function corresponding to the constructor
1611 * [functionElement]: 1632 * [functionElement]:
1612 * - Initialize fields with the values of the field initializers of the 1633 * - Initialize fields with the values of the field initializers of the
1613 * current constructor and super constructors or constructors redirected 1634 * current constructor and super constructors or constructors redirected
1614 * to, starting from the current constructor. 1635 * to, starting from the current constructor.
1615 * - Call the constructor bodies, starting from the constructor(s) in the 1636 * - Call the constructor bodies, starting from the constructor(s) in the
1616 * super class(es). 1637 * super class(es).
1617 */ 1638 */
1618 HGraph buildFactory(FunctionElement functionElement) { 1639 HGraph buildFactory(FunctionElement functionElement) {
1619 functionElement = functionElement.implementation; 1640 functionElement = functionElement.implementation;
1620 ClassElement classElement = 1641 ClassElement classElement =
1621 functionElement.getEnclosingClass().implementation; 1642 functionElement.getEnclosingClass().implementation;
1643 bool isNativeUpgradeFactory =
1644 Elements.isNativeOrExtendsNative(classElement);
1622 FunctionExpression function = functionElement.parseNode(compiler); 1645 FunctionExpression function = functionElement.parseNode(compiler);
1623 // Note that constructors (like any other static function) do not need 1646 // Note that constructors (like any other static function) do not need
1624 // to deal with optional arguments. It is the callers job to provide all 1647 // to deal with optional arguments. It is the callers job to provide all
1625 // arguments as if they were positional. 1648 // arguments as if they were positional.
1626 1649
1627 if (inliningStack.isEmpty) { 1650 if (inliningStack.isEmpty) {
1628 // The initializer list could contain closures. 1651 // The initializer list could contain closures.
1629 openFunction(functionElement, function); 1652 openFunction(functionElement, function);
1630 } 1653 }
1631 1654
(...skipping 15 matching lines...) Expand all
1647 } 1670 }
1648 }); 1671 });
1649 1672
1650 // Analyze the constructor and all referenced constructors and collect 1673 // Analyze the constructor and all referenced constructors and collect
1651 // initializers and constructor bodies. 1674 // initializers and constructor bodies.
1652 List<FunctionElement> constructors = <FunctionElement>[functionElement]; 1675 List<FunctionElement> constructors = <FunctionElement>[functionElement];
1653 buildInitializers(functionElement, constructors, fieldValues); 1676 buildInitializers(functionElement, constructors, fieldValues);
1654 1677
1655 // Call the JavaScript constructor with the fields as argument. 1678 // Call the JavaScript constructor with the fields as argument.
1656 List<HInstruction> constructorArguments = <HInstruction>[]; 1679 List<HInstruction> constructorArguments = <HInstruction>[];
1680 List<Element> fields = <Element>[];
1681
1657 classElement.forEachInstanceField( 1682 classElement.forEachInstanceField(
1658 (ClassElement enclosingClass, Element member) { 1683 (ClassElement enclosingClass, Element member) {
1659 constructorArguments.add(potentiallyCheckType( 1684 HInstruction value = fieldValues[member];
1660 fieldValues[member], member.computeType(compiler))); 1685 if (value == null) {
1686 // Uninitialized native fields are pre-initialized by the native
1687 // implementation.
1688 assert(isNativeUpgradeFactory);
1689 } else {
1690 fields.add(member);
1691 constructorArguments.add(
1692 potentiallyCheckType(value, member.computeType(compiler)));
1693 }
1661 }, 1694 },
1662 includeSuperAndInjectedMembers: true); 1695 includeSuperAndInjectedMembers: true);
1663 1696
1664 InterfaceType type = classElement.computeType(compiler); 1697 InterfaceType type = classElement.computeType(compiler);
1665 HType ssaType = new HType.nonNullExact(classElement, compiler); 1698 HType ssaType = new HType.nonNullExact(classElement, compiler);
1666 List<DartType> instantiatedTypes; 1699 List<DartType> instantiatedTypes;
1667 addInlinedInstantiation(type); 1700 addInlinedInstantiation(type);
1668 if (!currentInlinedInstantiations.isEmpty) { 1701 if (!currentInlinedInstantiations.isEmpty) {
1669 instantiatedTypes = new List<DartType>.from(currentInlinedInstantiations); 1702 instantiatedTypes = new List<DartType>.from(currentInlinedInstantiations);
1670 } 1703 }
1671 HForeignNew newObject = new HForeignNew(classElement, 1704
1672 ssaType, 1705 HInstruction newObject;
1673 constructorArguments, 1706 if (!isNativeUpgradeFactory) {
1674 instantiatedTypes); 1707 newObject = new HForeignNew(classElement,
1675 add(newObject); 1708 ssaType,
1709 constructorArguments,
1710 instantiatedTypes);
1711 add(newObject);
1712 } else {
1713 // Bulk assign to the initialized fields.
1714 newObject = graph.explicitReceiverParameter;
1715 // Null guard ensures an error if we are being called from an explicit
1716 // 'new' of the constructor instead of via an upgrade. It is optimized out
1717 // if there are field initializers.
1718 add(new HFieldGet(null, newObject, isAssignable: false));
1719 for (int i = 0; i < fields.length; i++) {
1720 add(new HFieldSet(fields[i], newObject, constructorArguments[i]));
1721 }
1722 }
1676 removeInlinedInstantiation(type); 1723 removeInlinedInstantiation(type);
1677 // Create the runtime type information, if needed. 1724 // Create the runtime type information, if needed.
1678 if (backend.classNeedsRti(classElement)) { 1725 if (backend.classNeedsRti(classElement)) {
1679 List<HInstruction> rtiInputs = <HInstruction>[]; 1726 List<HInstruction> rtiInputs = <HInstruction>[];
1680 classElement.typeVariables.forEach((TypeVariableType typeVariable) { 1727 classElement.typeVariables.forEach((TypeVariableType typeVariable) {
1681 rtiInputs.add(localsHandler.readLocal(typeVariable.element)); 1728 rtiInputs.add(localsHandler.readLocal(typeVariable.element));
1682 }); 1729 });
1683 callSetRuntimeTypeInfo(classElement, rtiInputs, newObject); 1730 callSetRuntimeTypeInfo(classElement, rtiInputs, newObject);
1684 } 1731 }
1685 1732
1686 // Generate calls to the constructor bodies. 1733 // Generate calls to the constructor bodies.
1734 HInstruction interceptor = null;
1687 for (int index = constructors.length - 1; index >= 0; index--) { 1735 for (int index = constructors.length - 1; index >= 0; index--) {
1688 FunctionElement constructor = constructors[index]; 1736 FunctionElement constructor = constructors[index];
1689 assert(invariant(functionElement, constructor.isImplementation)); 1737 assert(invariant(functionElement, constructor.isImplementation));
1690 ConstructorBodyElement body = getConstructorBody(constructor); 1738 ConstructorBodyElement body = getConstructorBody(constructor);
1691 if (body == null) continue; 1739 if (body == null) continue;
1740
1692 List bodyCallInputs = <HInstruction>[]; 1741 List bodyCallInputs = <HInstruction>[];
1742 if (isNativeUpgradeFactory) {
1743 if (interceptor == null) {
1744 Constant constant = new InterceptorConstant(
1745 classElement.computeType(compiler));
1746 interceptor = graph.addConstant(constant, compiler);
1747 }
1748 bodyCallInputs.add(interceptor);
1749 }
1693 bodyCallInputs.add(newObject); 1750 bodyCallInputs.add(newObject);
1694 TreeElements elements = 1751 TreeElements elements =
1695 compiler.enqueuer.resolution.getCachedElements(constructor); 1752 compiler.enqueuer.resolution.getCachedElements(constructor);
1696 Node node = constructor.parseNode(compiler); 1753 Node node = constructor.parseNode(compiler);
1697 ClosureClassMap parameterClosureData = 1754 ClosureClassMap parameterClosureData =
1698 compiler.closureToClassMapper.getMappingForNestedFunction(node); 1755 compiler.closureToClassMapper.getMappingForNestedFunction(node);
1699 1756
1700
1701 FunctionSignature functionSignature = body.computeSignature(compiler); 1757 FunctionSignature functionSignature = body.computeSignature(compiler);
1702 // Provide the parameters to the generative constructor body. 1758 // Provide the parameters to the generative constructor body.
1703 functionSignature.orderedForEachParameter((parameter) { 1759 functionSignature.orderedForEachParameter((parameter) {
1704 // If [parameter] is boxed, it will be a field in the box passed as the 1760 // If [parameter] is boxed, it will be a field in the box passed as the
1705 // last parameter. So no need to directly pass it. 1761 // last parameter. So no need to directly pass it.
1706 if (!localsHandler.isBoxed(parameter)) { 1762 if (!localsHandler.isBoxed(parameter)) {
1707 bodyCallInputs.add(localsHandler.readLocal(parameter)); 1763 bodyCallInputs.add(localsHandler.readLocal(parameter));
1708 } 1764 }
1709 }); 1765 });
1710 1766
1711 ClassElement currentClass = constructor.getEnclosingClass(); 1767 ClassElement currentClass = constructor.getEnclosingClass();
1712 if (backend.classNeedsRti(currentClass)) { 1768 if (backend.classNeedsRti(currentClass)) {
1713 // If [currentClass] needs RTI, we add the type variables as 1769 // If [currentClass] needs RTI, we add the type variables as
1714 // parameters of the generative constructor body. 1770 // parameters of the generative constructor body.
1715 currentClass.typeVariables.forEach((DartType argument) { 1771 currentClass.typeVariables.forEach((DartType argument) {
1716 bodyCallInputs.add(localsHandler.readLocal(argument.element)); 1772 bodyCallInputs.add(localsHandler.readLocal(argument.element));
1717 }); 1773 });
1718 } 1774 }
1719 1775
1720 // If there are locals that escape (ie mutated in closures), we 1776 // If there are locals that escape (ie mutated in closures), we
1721 // pass the box to the constructor. 1777 // pass the box to the constructor.
1722 ClosureScope scopeData = parameterClosureData.capturingScopes[node]; 1778 ClosureScope scopeData = parameterClosureData.capturingScopes[node];
1723 if (scopeData != null) { 1779 if (scopeData != null) {
1724 bodyCallInputs.add(localsHandler.readLocal(scopeData.boxElement)); 1780 bodyCallInputs.add(localsHandler.readLocal(scopeData.boxElement));
1725 } 1781 }
1726 1782
1727 if (tryInlineMethod(body, null, bodyCallInputs, function)) { 1783 if (!isNativeUpgradeFactory && // TODO(13836): Fix inlining.
1784 tryInlineMethod(body, null, bodyCallInputs, function)) {
1728 pop(); 1785 pop();
1729 } else { 1786 } else {
1730 HInvokeConstructorBody invoke = 1787 HInvokeConstructorBody invoke =
1731 new HInvokeConstructorBody(body.declaration, bodyCallInputs); 1788 new HInvokeConstructorBody(body.declaration, bodyCallInputs);
1732 invoke.sideEffects = 1789 invoke.sideEffects =
1733 compiler.world.getSideEffectsOfElement(constructor); 1790 compiler.world.getSideEffectsOfElement(constructor);
1734 add(invoke); 1791 add(invoke);
1735 } 1792 }
1736 } 1793 }
1737 if (inliningStack.isEmpty) { 1794 if (inliningStack.isEmpty) {
(...skipping 1820 matching lines...) Expand 10 before | Expand all | Expand 10 after
3558 } 3615 }
3559 3616
3560 bool isRedirected = functionElement.isRedirectingFactory; 3617 bool isRedirected = functionElement.isRedirectingFactory;
3561 InterfaceType type = elements.getType(node); 3618 InterfaceType type = elements.getType(node);
3562 DartType expectedType = type; 3619 DartType expectedType = type;
3563 if (isRedirected) { 3620 if (isRedirected) {
3564 type = functionElement.computeTargetType(compiler, type); 3621 type = functionElement.computeTargetType(compiler, type);
3565 } 3622 }
3566 3623
3567 var inputs = <HInstruction>[]; 3624 var inputs = <HInstruction>[];
3625 if (constructor.isGenerativeConstructor() &&
3626 Elements.isNativeOrExtendsNative(constructor.getEnclosingClass())) {
3627 // Native class generative constructors take a pre-constructed object.
3628 inputs.add(graph.addConstantNull(compiler));
3629 }
3568 // TODO(5347): Try to avoid the need for calling [implementation] before 3630 // TODO(5347): Try to avoid the need for calling [implementation] before
3569 // calling [addStaticSendArgumentsToList]. 3631 // calling [addStaticSendArgumentsToList].
3570 bool succeeded = addStaticSendArgumentsToList(selector, send.arguments, 3632 bool succeeded = addStaticSendArgumentsToList(selector, send.arguments,
3571 constructor.implementation, 3633 constructor.implementation,
3572 inputs); 3634 inputs);
3573 if (!succeeded) { 3635 if (!succeeded) {
3574 generateWrongArgumentCountError(send, constructor, send.arguments); 3636 generateWrongArgumentCountError(send, constructor, send.arguments);
3575 return; 3637 return;
3576 } 3638 }
3577 3639
(...skipping 1977 matching lines...) Expand 10 before | Expand all | Expand 10 after
5555 new HSubGraphBlockInformation(elseBranch.graph)); 5617 new HSubGraphBlockInformation(elseBranch.graph));
5556 5618
5557 HBasicBlock conditionStartBlock = conditionBranch.block; 5619 HBasicBlock conditionStartBlock = conditionBranch.block;
5558 conditionStartBlock.setBlockFlow(info, joinBlock); 5620 conditionStartBlock.setBlockFlow(info, joinBlock);
5559 SubGraph conditionGraph = conditionBranch.graph; 5621 SubGraph conditionGraph = conditionBranch.graph;
5560 HIf branch = conditionGraph.end.last; 5622 HIf branch = conditionGraph.end.last;
5561 assert(branch is HIf); 5623 assert(branch is HIf);
5562 branch.blockInformation = conditionStartBlock.blockFlow; 5624 branch.blockInformation = conditionStartBlock.blockFlow;
5563 } 5625 }
5564 } 5626 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698