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

Side by Side Diff: pkg/compiler/lib/src/ssa/builder.dart

Issue 1318043005: Support user generated custom native JS classes. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: ptal Created 5 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
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 class SsaFunctionCompiler implements FunctionCompiler { 7 class SsaFunctionCompiler implements FunctionCompiler {
8 final SsaCodeGeneratorTask generator; 8 final SsaCodeGeneratorTask generator;
9 final SsaBuilderTask builder; 9 final SsaBuilderTask builder;
10 final SsaOptimizerTask optimizer; 10 final SsaOptimizerTask optimizer;
(...skipping 1283 matching lines...) Expand 10 before | Expand all | Expand 10 after
1294 Selector selector, 1294 Selector selector,
1295 TypeMask mask, 1295 TypeMask mask,
1296 List<HInstruction> providedArguments, 1296 List<HInstruction> providedArguments,
1297 ast.Node currentNode, 1297 ast.Node currentNode,
1298 {InterfaceType instanceType}) { 1298 {InterfaceType instanceType}) {
1299 // TODO(johnniwinther): Register this on the [registry]. Currently the 1299 // TODO(johnniwinther): Register this on the [registry]. Currently the
1300 // [CodegenRegistry] calls the enqueuer, but [element] should _not_ be 1300 // [CodegenRegistry] calls the enqueuer, but [element] should _not_ be
1301 // enqueued. 1301 // enqueued.
1302 backend.registerStaticUse(element, compiler.enqueuer.codegen); 1302 backend.registerStaticUse(element, compiler.enqueuer.codegen);
1303 1303
1304 if (element.isJsInterop && !element.isFactoryConstructor) {
1305 // We only inline factory JavaScript interop constructors.
1306 return false;
1307 }
1308
1304 // Ensure that [element] is an implementation element. 1309 // Ensure that [element] is an implementation element.
1305 element = element.implementation; 1310 element = element.implementation;
1306 1311
1307 if (compiler.elementHasCompileTimeError(element)) return false; 1312 if (compiler.elementHasCompileTimeError(element)) return false;
1308 1313
1309 FunctionElement function = element; 1314 FunctionElement function = element;
1310 bool insideLoop = loopNesting > 0 || graph.calledInLoop; 1315 bool insideLoop = loopNesting > 0 || graph.calledInLoop;
1311 1316
1312 // Bail out early if the inlining decision is in the cache and we can't 1317 // Bail out early if the inlining decision is in the cache and we can't
1313 // inline (no need to check the hard constraints). 1318 // inline (no need to check the hard constraints).
(...skipping 10 matching lines...) Expand all
1324 Elements.isStaticOrTopLevel(element) || 1329 Elements.isStaticOrTopLevel(element) ||
1325 element.isGenerativeConstructorBody, 1330 element.isGenerativeConstructorBody,
1326 message: "Missing selector for inlining of $element.")); 1331 message: "Missing selector for inlining of $element."));
1327 if (selector != null) { 1332 if (selector != null) {
1328 if (!selector.applies(function, compiler.world)) return false; 1333 if (!selector.applies(function, compiler.world)) return false;
1329 if (mask != null && !mask.canHit(function, selector, compiler.world)) { 1334 if (mask != null && !mask.canHit(function, selector, compiler.world)) {
1330 return false; 1335 return false;
1331 } 1336 }
1332 } 1337 }
1333 1338
1339 if (element.isJsInterop) return false;
1340
1334 // Don't inline operator== methods if the parameter can be null. 1341 // Don't inline operator== methods if the parameter can be null.
1335 if (element.name == '==') { 1342 if (element.name == '==') {
1336 if (element.enclosingClass != compiler.objectClass 1343 if (element.enclosingClass != compiler.objectClass
1337 && providedArguments[1].canBeNull()) { 1344 && providedArguments[1].canBeNull()) {
1338 return false; 1345 return false;
1339 } 1346 }
1340 } 1347 }
1341 1348
1342 // Generative constructors of native classes should not be called directly 1349 // Generative constructors of native classes should not be called directly
1343 // and have an extra argument that causes problems with inlining. 1350 // and have an extra argument that causes problems with inlining.
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
1503 sourceInformationBuilder = 1510 sourceInformationBuilder =
1504 sourceInformationBuilder.forContext(element.implementation); 1511 sourceInformationBuilder.forContext(element.implementation);
1505 sourceElementStack.add(element.declaration); 1512 sourceElementStack.add(element.declaration);
1506 var result = f(); 1513 var result = f();
1507 sourceInformationBuilder = oldSourceInformationBuilder; 1514 sourceInformationBuilder = oldSourceInformationBuilder;
1508 sourceElementStack.removeLast(); 1515 sourceElementStack.removeLast();
1509 return result; 1516 return result;
1510 }); 1517 });
1511 } 1518 }
1512 1519
1520 /**
1521 * Return null so it is simple to remove the optional parameters completely
1522 * from interop methods to match JavaScript semantics for ommitted arguments.
1523 */
1524 HInstruction handleConstantForOptionalParameterJsInterop(Element parameter) =>
1525 null;
1526
1513 HInstruction handleConstantForOptionalParameter(Element parameter) { 1527 HInstruction handleConstantForOptionalParameter(Element parameter) {
1514 ConstantValue constantValue = 1528 ConstantValue constantValue =
1515 backend.constants.getConstantValueForVariable(parameter); 1529 backend.constants.getConstantValueForVariable(parameter);
1516 assert(invariant(parameter, constantValue != null, 1530 assert(invariant(parameter, constantValue != null,
1517 message: 'No constant computed for $parameter')); 1531 message: 'No constant computed for $parameter'));
1518 return graph.addConstant(constantValue, compiler); 1532 return graph.addConstant(constantValue, compiler);
1519 } 1533 }
1520 1534
1521 Element get currentNonClosureClass { 1535 Element get currentNonClosureClass {
1522 ClassElement cls = sourceElement.enclosingClass; 1536 ClassElement cls = sourceElement.enclosingClass;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
1597 /** 1611 /**
1598 * Documentation wanted -- johnniwinther 1612 * Documentation wanted -- johnniwinther
1599 * 1613 *
1600 * Invariant: [functionElement] must be an implementation element. 1614 * Invariant: [functionElement] must be an implementation element.
1601 */ 1615 */
1602 HGraph buildMethod(FunctionElement functionElement) { 1616 HGraph buildMethod(FunctionElement functionElement) {
1603 assert(invariant(functionElement, functionElement.isImplementation)); 1617 assert(invariant(functionElement, functionElement.isImplementation));
1604 graph.calledInLoop = compiler.world.isCalledInLoop(functionElement); 1618 graph.calledInLoop = compiler.world.isCalledInLoop(functionElement);
1605 ast.FunctionExpression function = functionElement.node; 1619 ast.FunctionExpression function = functionElement.node;
1606 assert(function != null); 1620 assert(function != null);
1607 assert(!function.modifiers.isExternal);
1608 assert(elements.getFunctionDefinition(function) != null); 1621 assert(elements.getFunctionDefinition(function) != null);
1609 openFunction(functionElement, function); 1622 openFunction(functionElement, function);
1610 String name = functionElement.name; 1623 String name = functionElement.name;
1624 if (functionElement.isJsInterop) {
1625 push(invokeJsInteropFunction(functionElement, parameters.values.toList(),
1626 sourceInformationBuilder.buildGeneric(function)));
1627 var value = pop();
1628 closeAndGotoExit(new HReturn(value,
1629 sourceInformationBuilder.buildReturn(functionElement.node)));
1630 return closeFunction();
1631 }
1632
1611 // If [functionElement] is `operator==` we explicitely add a null check at 1633 // If [functionElement] is `operator==` we explicitely add a null check at
1612 // the beginning of the method. This is to avoid having call sites do the 1634 // the beginning of the method. This is to avoid having call sites do the
1613 // null check. 1635 // null check.
1614 if (name == '==') { 1636 if (name == '==') {
1615 if (!backend.operatorEqHandlesNullArgument(functionElement)) { 1637 if (!backend.operatorEqHandlesNullArgument(functionElement)) {
1616 handleIf( 1638 handleIf(
1617 function, 1639 function,
1618 visitCondition: () { 1640 visitCondition: () {
1619 HParameterValue parameter = parameters.values.first; 1641 HParameterValue parameter = parameters.values.first;
1620 push(new HIdentity( 1642 push(new HIdentity(
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
1805 returnType = state.oldReturnType; 1827 returnType = state.oldReturnType;
1806 assert(stack.isEmpty); 1828 assert(stack.isEmpty);
1807 stack = state.oldStack; 1829 stack = state.oldStack;
1808 } 1830 }
1809 1831
1810 /** 1832 /**
1811 * Run this builder on the body of the [function] to be inlined. 1833 * Run this builder on the body of the [function] to be inlined.
1812 */ 1834 */
1813 void visitInlinedFunction(FunctionElement function) { 1835 void visitInlinedFunction(FunctionElement function) {
1814 potentiallyCheckInlinedParameterTypes(function); 1836 potentiallyCheckInlinedParameterTypes(function);
1837
1815 if (function.isGenerativeConstructor) { 1838 if (function.isGenerativeConstructor) {
1816 buildFactory(function); 1839 buildFactory(function);
1817 } else { 1840 } else {
1818 ast.FunctionExpression functionNode = function.node; 1841 ast.FunctionExpression functionNode = function.node;
1819 functionNode.body.accept(this); 1842 functionNode.body.accept(this);
1820 } 1843 }
1821 } 1844 }
1822 1845
1823 1846
1824 addInlinedInstantiation(DartType type) { 1847 addInlinedInstantiation(DartType type) {
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after
2108 * current constructor and super constructors or constructors redirected 2131 * current constructor and super constructors or constructors redirected
2109 * to, starting from the current constructor. 2132 * to, starting from the current constructor.
2110 * - Call the constructor bodies, starting from the constructor(s) in the 2133 * - Call the constructor bodies, starting from the constructor(s) in the
2111 * super class(es). 2134 * super class(es).
2112 */ 2135 */
2113 HGraph buildFactory(ConstructorElement functionElement) { 2136 HGraph buildFactory(ConstructorElement functionElement) {
2114 functionElement = functionElement.implementation; 2137 functionElement = functionElement.implementation;
2115 ClassElement classElement = 2138 ClassElement classElement =
2116 functionElement.enclosingClass.implementation; 2139 functionElement.enclosingClass.implementation;
2117 bool isNativeUpgradeFactory = 2140 bool isNativeUpgradeFactory =
2118 Elements.isNativeOrExtendsNative(classElement); 2141 Elements.isNativeOrExtendsNative(classElement)
2142 && !classElement.isJsInterop;
2119 ast.FunctionExpression function = functionElement.node; 2143 ast.FunctionExpression function = functionElement.node;
2120 // Note that constructors (like any other static function) do not need 2144 // Note that constructors (like any other static function) do not need
2121 // to deal with optional arguments. It is the callers job to provide all 2145 // to deal with optional arguments. It is the callers job to provide all
2122 // arguments as if they were positional. 2146 // arguments as if they were positional.
2123 2147
2124 if (inliningStack.isEmpty) { 2148 if (inliningStack.isEmpty) {
2125 // The initializer list could contain closures. 2149 // The initializer list could contain closures.
2126 openFunction(functionElement, function); 2150 openFunction(functionElement, function);
2127 } 2151 }
2128 2152
(...skipping 1789 matching lines...) Expand 10 before | Expand all | Expand 10 after
3918 3942
3919 HInstruction compileArgument(ast.Node argument) { 3943 HInstruction compileArgument(ast.Node argument) {
3920 visit(argument); 3944 visit(argument);
3921 return pop(); 3945 return pop();
3922 } 3946 }
3923 3947
3924 return callStructure.makeArgumentsList( 3948 return callStructure.makeArgumentsList(
3925 arguments, 3949 arguments,
3926 element, 3950 element,
3927 compileArgument, 3951 compileArgument,
3928 handleConstantForOptionalParameter); 3952 element.isJsInterop ?
3953 handleConstantForOptionalParameterJsInterop :
3954 handleConstantForOptionalParameter);
3929 } 3955 }
3930 3956
3931 void addGenericSendArgumentsToList(Link<ast.Node> link, List<HInstruction> lis t) { 3957 void addGenericSendArgumentsToList(Link<ast.Node> link, List<HInstruction> lis t) {
3932 for (; !link.isEmpty; link = link.tail) { 3958 for (; !link.isEmpty; link = link.tail) {
3933 visit(link.head); 3959 visit(link.head);
3934 list.add(pop()); 3960 list.add(pop());
3935 } 3961 }
3936 } 3962 }
3937 3963
3938 /// Generate a dynamic method, getter or setter invocation. 3964 /// Generate a dynamic method, getter or setter invocation.
(...skipping 1126 matching lines...) Expand 10 before | Expand all | Expand 10 after
5065 5091
5066 if (compiler.elementHasCompileTimeError(constructor)) { 5092 if (compiler.elementHasCompileTimeError(constructor)) {
5067 // TODO(ahe): Do something like [generateWrongArgumentCountError]. 5093 // TODO(ahe): Do something like [generateWrongArgumentCountError].
5068 stack.add(graph.addConstantNull(compiler)); 5094 stack.add(graph.addConstantNull(compiler));
5069 return; 5095 return;
5070 } 5096 }
5071 if (checkTypeVariableBounds(node, type)) return; 5097 if (checkTypeVariableBounds(node, type)) return;
5072 5098
5073 var inputs = <HInstruction>[]; 5099 var inputs = <HInstruction>[];
5074 if (constructor.isGenerativeConstructor && 5100 if (constructor.isGenerativeConstructor &&
5075 Elements.isNativeOrExtendsNative(constructor.enclosingClass)) { 5101 Elements.isNativeOrExtendsNative(constructor.enclosingClass) &&
5102 !constructor.isJsInterop) {
5076 // Native class generative constructors take a pre-constructed object. 5103 // Native class generative constructors take a pre-constructed object.
5077 inputs.add(graph.addConstantNull(compiler)); 5104 inputs.add(graph.addConstantNull(compiler));
5078 } 5105 }
5079 // TODO(5347): Try to avoid the need for calling [implementation] before 5106 // TODO(5347): Try to avoid the need for calling [implementation] before
5080 // calling [makeStaticArgumentList]. 5107 // calling [makeStaticArgumentList].
5081 constructorImplementation = constructor.implementation; 5108 constructorImplementation = constructor.implementation;
5082 if (constructorImplementation.isErroneous || 5109 if (constructorImplementation.isErroneous ||
5083 !callStructure.signatureApplies( 5110 !callStructure.signatureApplies(
5084 constructorImplementation.functionSignature)) { 5111 constructorImplementation.functionSignature)) {
5085 generateWrongArgumentCountError(send, constructor, send.arguments); 5112 generateWrongArgumentCountError(send, constructor, send.arguments);
(...skipping 695 matching lines...) Expand 10 before | Expand all | Expand 10 after
5781 push( 5808 push(
5782 new HInvokeDynamicSetter(selector, mask, null, inputs, type) 5809 new HInvokeDynamicSetter(selector, mask, null, inputs, type)
5783 ..sourceInformation = sourceInformation); 5810 ..sourceInformation = sourceInformation);
5784 } else { 5811 } else {
5785 push( 5812 push(
5786 new HInvokeDynamicMethod(selector, mask, inputs, type, isIntercepted) 5813 new HInvokeDynamicMethod(selector, mask, inputs, type, isIntercepted)
5787 ..sourceInformation = sourceInformation); 5814 ..sourceInformation = sourceInformation);
5788 } 5815 }
5789 } 5816 }
5790 5817
5818 HForeignCode invokeJsInteropFunction(Element element,
5819 List<HInstruction> arguments,
5820 SourceInformation sourceInformation) {
5821 assert(element.isJsInterop);
5822 nativeEmitter.nativeMethods.add(element);
5823 String templateString;
5824
5825 if (element.isFactoryConstructor) {
5826 // Treat factory constructors as syntactic sugar for creating object
5827 // literals.
5828 ConstructorElement constructor = element;
5829 FunctionSignature params = constructor.functionSignature;
5830 int i = 0;
5831 int positions = 0;
5832 var filteredArguments = <HInstruction>[];
5833 var parameterNameMap = new Map<String, js.Expression>();
5834 params.orderedForEachParameter((ParameterElement parameter) {
5835 // TODO(jacobr): throw if parameter names do not match names of property
5836 // names in the class.
5837 assert (parameter.isNamed);
5838 if (!parameter.isNamed) {
5839 compiler.reportErrorMessage(
5840 parameter, MessageKind.GENERIC,
5841 {'text': 'All arguments to external constructors of JavaScript '
5842 'interop classes must be named as these constructors '
5843 'are syntactic sugar for object literals.'});
5844 }
5845 HInstruction argument = arguments[i];
5846 if (argument != null) {
5847 filteredArguments.add(argument);
5848 parameterNameMap[parameter.name] =
5849 new js.InterpolatedExpression(positions++);
5850 }
5851 i++;
5852 });
5853 var codeTemplate = new js.Template(null,
5854 js.objectLiteral(parameterNameMap));
5855
5856 var nativeBehavior = new native.NativeBehavior()
5857 ..codeTemplate = codeTemplate;
5858 return new HForeignCode(
5859 codeTemplate,
5860 backend.dynamicType, filteredArguments,
5861 nativeBehavior: nativeBehavior)
5862 ..sourceInformation = sourceInformation;
5863 }
5864 var target = new HForeignCode(js.js.parseForeignJS(
5865 "${backend.namer.fixedBackendPath(element)}."
5866 "${element.fixedBackendName}"),
5867 backend.dynamicType,
5868 <HInstruction>[]);
5869 add(target);
5870 // Strip off trailing arguments that were not specified.
5871 // we could assert that the trailing arguments are all null.
5872 // TODO(jacobr): rewrite named arguments to an object literal matching
5873 // the factory constructor case.
5874 arguments = arguments.where((arg) => arg != null).toList();
5875 var inputs = <HInstruction>[target]..addAll(arguments);
5876
5877 js.Template codeTemplate;
5878 if (element.isGetter) {
5879 codeTemplate = js.js.parseForeignJS("#");
5880 } else if (element.isSetter) {
5881 codeTemplate = js.js.parseForeignJS("# = #");
5882 } else {
5883 var argsStub = <String>[];
5884 for (int i = 0; i < arguments.length; i++) {
5885 argsStub.add('#');
5886 }
5887 if (element.isConstructor) {
5888 codeTemplate = js.js.parseForeignJS("new #(${argsStub.join(",")})");
5889 } else {
5890 codeTemplate = js.js.parseForeignJS("#(${argsStub.join(",")})");
5891 }
5892 }
5893
5894 var nativeBehavior = new native.NativeBehavior()
5895 ..codeTemplate = codeTemplate
5896 ..typesReturned.add(
5897 backend.jsJavaScriptObjectClass.thisType)
5898 ..typesInstantiated.add(
5899 backend.jsJavaScriptObjectClass.thisType)
5900 ..sideEffects.setAllSideEffects();
5901 return new HForeignCode(
5902 codeTemplate,
5903 backend.dynamicType, inputs,
5904 nativeBehavior: nativeBehavior)
5905 ..sourceInformation = sourceInformation;
5906 }
5907
5791 void pushInvokeStatic(ast.Node location, 5908 void pushInvokeStatic(ast.Node location,
5792 Element element, 5909 Element element,
5793 List<HInstruction> arguments, 5910 List<HInstruction> arguments,
5794 {TypeMask typeMask, 5911 {TypeMask typeMask,
5795 InterfaceType instanceType, 5912 InterfaceType instanceType,
5796 SourceInformation sourceInformation}) { 5913 SourceInformation sourceInformation}) {
5797 // TODO(johnniwinther): Use [sourceInformation] instead of [location]. 5914 // TODO(johnniwinther): Use [sourceInformation] instead of [location].
5798 if (tryInlineMethod(element, null, null, arguments, location, 5915 if (tryInlineMethod(element, null, null, arguments, location,
5799 instanceType: instanceType)) { 5916 instanceType: instanceType)) {
5800 return; 5917 return;
5801 } 5918 }
5802 5919
5803 if (typeMask == null) { 5920 if (typeMask == null) {
5804 typeMask = 5921 typeMask =
5805 TypeMaskFactory.inferredReturnTypeForElement(element, compiler); 5922 TypeMaskFactory.inferredReturnTypeForElement(element, compiler);
5806 } 5923 }
5807 bool targetCanThrow = !compiler.world.getCannotThrow(element); 5924 bool targetCanThrow = !compiler.world.getCannotThrow(element);
5808 // TODO(5346): Try to avoid the need for calling [declaration] before 5925 // TODO(5346): Try to avoid the need for calling [declaration] before
5809 // creating an [HInvokeStatic]. 5926 var instruction;
5810 HInvokeStatic instruction = new HInvokeStatic( 5927 if (element.isJsInterop) {
5811 element.declaration, arguments, typeMask, 5928 instruction = invokeJsInteropFunction(element, arguments,
5812 targetCanThrow: targetCanThrow) 5929 sourceInformation);
5813 ..sourceInformation = sourceInformation; 5930 } else {
5814 if (!currentInlinedInstantiations.isEmpty) { 5931 // creating an [HInvokeStatic].
5815 instruction.instantiatedTypes = new List<DartType>.from( 5932 instruction = new HInvokeStatic(
5816 currentInlinedInstantiations); 5933 element.declaration, arguments, typeMask,
5934 targetCanThrow: targetCanThrow)
5935 ..sourceInformation = sourceInformation;
5936 if (!currentInlinedInstantiations.isEmpty) {
5937 instruction.instantiatedTypes = new List<DartType>.from(
5938 currentInlinedInstantiations);
5939 }
5940 instruction.sideEffects = compiler.world.getSideEffectsOfElement(element);
5817 } 5941 }
5818 instruction.sideEffects = compiler.world.getSideEffectsOfElement(element);
5819 if (location == null) { 5942 if (location == null) {
5820 push(instruction); 5943 push(instruction);
5821 } else { 5944 } else {
5822 pushWithPosition(instruction, location); 5945 pushWithPosition(instruction, location);
5823 } 5946 }
5824 } 5947 }
5825 5948
5826 HInstruction buildInvokeSuper(Selector selector, 5949 HInstruction buildInvokeSuper(Selector selector,
5827 Element element, 5950 Element element,
5828 List<HInstruction> arguments, 5951 List<HInstruction> arguments,
(...skipping 3162 matching lines...) Expand 10 before | Expand all | Expand 10 after
8991 if (unaliased is TypedefType) throw 'unable to unalias $type'; 9114 if (unaliased is TypedefType) throw 'unable to unalias $type';
8992 unaliased.accept(this, builder); 9115 unaliased.accept(this, builder);
8993 } 9116 }
8994 9117
8995 void visitDynamicType(DynamicType type, SsaBuilder builder) { 9118 void visitDynamicType(DynamicType type, SsaBuilder builder) {
8996 JavaScriptBackend backend = builder.compiler.backend; 9119 JavaScriptBackend backend = builder.compiler.backend;
8997 ClassElement cls = backend.findHelper('DynamicRuntimeType'); 9120 ClassElement cls = backend.findHelper('DynamicRuntimeType');
8998 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); 9121 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld)));
8999 } 9122 }
9000 } 9123 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698