Chromium Code Reviews| Index: pkg/compiler/lib/src/ssa/builder.dart |
| diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart |
| index f9d87f94304cfb42add3c17338ba54c19881a5c1..76625f1c8fa53cbbb8e99d862bc72971d41273f7 100644 |
| --- a/pkg/compiler/lib/src/ssa/builder.dart |
| +++ b/pkg/compiler/lib/src/ssa/builder.dart |
| @@ -1297,6 +1297,11 @@ class SsaBuilder extends ast.Visitor |
| // enqueued. |
| backend.registerStaticUse(element, compiler.enqueuer.codegen); |
| + if (element.isJsInterop && !element.isFactoryConstructor) { |
| + // We only inline factory JavaScript interop constructors. |
| + return false; |
| + } |
| + |
| // Ensure that [element] is an implementation element. |
| element = element.implementation; |
| @@ -1327,6 +1332,8 @@ class SsaBuilder extends ast.Visitor |
| } |
| } |
| + if (element.isJsInterop) return false; |
| + |
| // Don't inline operator== methods if the parameter can be null. |
| if (element.name == '==') { |
| if (element.enclosingClass != compiler.objectClass |
| @@ -1502,6 +1509,13 @@ class SsaBuilder extends ast.Visitor |
| }); |
| } |
| + /** |
| + * Return null so it is simple to remove the optional parameters completely |
| + * interop methods to match JavaScript semantics for ommitted arguments. |
|
Siggi Cherem (dart-lang)
2015/09/18 20:34:10
completely interop => completely from interop?
Jacob
2015/10/01 00:47:33
Done.
|
| + */ |
| + HInstruction handleConstantForOptionalParameterJsInterop(Element parameter) => |
| + null; |
| + |
| HInstruction handleConstantForOptionalParameter(Element parameter) { |
| ConstantValue constantValue = |
| backend.constants.getConstantValueForVariable(parameter); |
| @@ -1596,10 +1610,19 @@ class SsaBuilder extends ast.Visitor |
| graph.calledInLoop = compiler.world.isCalledInLoop(functionElement); |
| ast.FunctionExpression function = functionElement.node; |
| assert(function != null); |
| - assert(!function.modifiers.isExternal); |
| assert(elements.getFunctionDefinition(function) != null); |
| openFunction(functionElement, function); |
| String name = functionElement.name; |
| + if (functionElement.isJsInterop) { |
| + push(invokeJsInteropFunction(functionElement, parameters.values.toList(), sourceInformationBuilder.buildGeneric(function))); |
|
Siggi Cherem (dart-lang)
2015/09/18 20:34:10
long lines (here and below)
Jacob
2015/10/01 00:47:33
Done.
|
| + var value = pop(); |
| + closeAndGotoExit(new HReturn(value, |
| + sourceInformationBuilder.buildReturn(functionElement.node))); |
|
Siggi Cherem (dart-lang)
2015/09/18 20:34:10
indent
Jacob
2015/10/01 00:47:33
Done.
|
| + return closeFunction(); |
| + } else { |
| + assert(!function.modifiers.isExternal); |
| + } |
| + |
| // If [functionElement] is `operator==` we explicitely add a null check at |
| // the beginning of the method. This is to avoid having call sites do the |
| // null check. |
| @@ -1781,6 +1804,7 @@ class SsaBuilder extends ast.Visitor |
| */ |
| void visitInlinedFunction(FunctionElement function) { |
| potentiallyCheckInlinedParameterTypes(function); |
| + |
| if (function.isGenerativeConstructor) { |
| buildFactory(function); |
| } else { |
| @@ -2084,7 +2108,8 @@ class SsaBuilder extends ast.Visitor |
| ClassElement classElement = |
| functionElement.enclosingClass.implementation; |
| bool isNativeUpgradeFactory = |
| - Elements.isNativeOrExtendsNative(classElement); |
| + Elements.isNativeOrExtendsNative(classElement) |
| + && !classElement.isJsInterop; |
| ast.FunctionExpression function = functionElement.node; |
| // Note that constructors (like any other static function) do not need |
| // to deal with optional arguments. It is the callers job to provide all |
| @@ -3863,7 +3888,10 @@ class SsaBuilder extends ast.Visitor |
| arguments, |
| element, |
| compileArgument, |
| - handleConstantForOptionalParameter); |
| + element.isJsInterop ? |
| + handleConstantForOptionalParameterJsInterop : |
| + handleConstantForOptionalParameter |
| + ); |
| } |
| void addGenericSendArgumentsToList(Link<ast.Node> link, List<HInstruction> list) { |
| @@ -4998,7 +5026,8 @@ class SsaBuilder extends ast.Visitor |
| var inputs = <HInstruction>[]; |
| if (constructor.isGenerativeConstructor && |
| - Elements.isNativeOrExtendsNative(constructor.enclosingClass)) { |
| + Elements.isNativeOrExtendsNative(constructor.enclosingClass) && |
| + !constructor.isJsInterop) { |
| // Native class generative constructors take a pre-constructed object. |
| inputs.add(graph.addConstantNull(compiler)); |
| } |
| @@ -5726,6 +5755,96 @@ class SsaBuilder extends ast.Visitor |
| } |
| } |
| + HForeignCode invokeJsInteropFunction(Element element, |
| + List<HInstruction> arguments, |
| + SourceInformation sourceInformation) { |
| + assert(element.isJsInterop); |
| + nativeEmitter.nativeMethods.add(element); |
| + var templateString; |
|
sra1
2015/10/01 17:34:30
The rest of this file uses local types.
We have fo
Jacob
2015/10/02 20:08:15
Done. Tried to match the general style of builder.
|
| + |
| + if (element.isFactoryConstructor) { |
| + // Treat factory constructors as syntactic sugar for creating object |
| + // literals. |
| + var templateParts = []; |
| + var parameterValues = []; |
| + |
| + FunctionSignature params = (element as ConstructorElement).functionSignature; |
|
sra1
2015/10/01 17:34:30
The dart2js way is to use a local declaration:
C
Jacob
2015/10/02 20:08:15
Done.
|
| + int i = 0; |
| + int positions = 0; |
| + var filteredArguments = <HInstruction>[]; |
| + var parameterNameMap = new Map<String, js.Expression>(); |
| + params.orderedForEachParameter((ParameterElement parameter) { |
| + // TODO(jacobr): throw if parameter names do not match names of property |
| + // names in the class. |
| + assert (parameter.isNamed); |
| + if (!parameter.isNamed) { |
| + compiler.reportError( |
| + parameter, MessageKind.GENERIC, |
| + {'text': 'Error: all arguments to external constructors of' |
| + 'JavaScript interop classes must be named as these' |
| + 'constructors are syntactic sugar for object literals'}); |
| + } |
| + var argument = arguments[i]; |
| + if (argument != null) { |
| + filteredArguments.add(argument); |
| + parameterNameMap[parameter.name] = |
| + new js.InterpolatedExpression(positions++); |
| + } |
| + i++; |
| + }); |
| + var codeTemplate = new js.Template(null, |
| + js.objectLiteral(parameterNameMap)); |
| + |
| + var nativeBehavior = new native.NativeBehavior() |
| + ..codeTemplate = codeTemplate; |
| + return new HForeignCode( |
| + codeTemplate, |
| + backend.dynamicType, filteredArguments, |
| + nativeBehavior: nativeBehavior) |
| + ..sourceInformation = sourceInformation; |
| + } |
| + var target = new HForeignCode(js.js.parseForeignJS( |
| + element.isInstanceMember ? |
| + "this.${element.fixedBackendName}" : element.fixedBackendName), |
| + backend.dynamicType, |
| + <HInstruction>[]); |
| + add(target); |
| + // Strip off trailing arguments that were not specified. |
| + // we could assert that the trailing arguments are all null. |
| + // TODO(jacobr): rewrite named arguments to an object literal matching |
| + // the factory constructor case. |
| + arguments = arguments.where((arg) => arg != null).toList(); |
| + var inputs = [target]..addAll(arguments); |
| + |
| + var codeTemplate; |
| + if (element.isGetter) { |
| + codeTemplate = js.js.parseForeignJS("#"); |
| + } else if (element.isSetter) { |
| + codeTemplate = js.js.parseForeignJS("# = #"); |
| + } else { |
| + var argsStub = []; |
| + for (int i = 0; i < arguments.length; i++) { |
| + argsStub.add('#'); |
| + } |
| + if (element.isConstructor) { |
| + codeTemplate = js.js.parseForeignJS("new #(${argsStub.join(",")})"); |
| + } else { |
| + codeTemplate = js.js.parseForeignJS("#(${argsStub.join(",")})"); |
| + } |
| + } |
| + |
| + var nativeBehavior = new native.NativeBehavior() |
| + ..codeTemplate = codeTemplate |
| + ..typesReturned.add(backend.jsPlainJavaScriptObjectClass.computeType(compiler)) |
| + ..typesInstantiated.add(backend.jsPlainJavaScriptObjectClass.computeType(compiler)) |
| + ..sideEffects.setAllSideEffects(); |
| + return new HForeignCode( |
| + codeTemplate, |
| + backend.dynamicType, inputs, |
| + nativeBehavior: nativeBehavior) |
| + ..sourceInformation = sourceInformation; |
| + } |
| + |
| void pushInvokeStatic(ast.Node location, |
| Element element, |
| List<HInstruction> arguments, |
| @@ -5744,16 +5863,21 @@ class SsaBuilder extends ast.Visitor |
| } |
| bool targetCanThrow = !compiler.world.getCannotThrow(element); |
| // TODO(5346): Try to avoid the need for calling [declaration] before |
| - // creating an [HInvokeStatic]. |
| - HInvokeStatic instruction = new HInvokeStatic( |
| - element.declaration, arguments, typeMask, |
| - targetCanThrow: targetCanThrow) |
| - ..sourceInformation = sourceInformation; |
| - if (!currentInlinedInstantiations.isEmpty) { |
| - instruction.instantiatedTypes = new List<DartType>.from( |
| - currentInlinedInstantiations); |
| + var instruction; |
| + if (element.isJsInterop) { |
| + instruction = invokeJsInteropFunction(element, arguments, sourceInformation); |
| + } else { |
| + // creating an [HInvokeStatic]. |
| + instruction = new HInvokeStatic( |
| + element.declaration, arguments, typeMask, |
| + targetCanThrow: targetCanThrow) |
| + ..sourceInformation = sourceInformation; |
| + if (!currentInlinedInstantiations.isEmpty) { |
| + instruction.instantiatedTypes = new List<DartType>.from( |
| + currentInlinedInstantiations); |
| + } |
| + instruction.sideEffects = compiler.world.getSideEffectsOfElement(element); |
| } |
| - instruction.sideEffects = compiler.world.getSideEffectsOfElement(element); |
| if (location == null) { |
| push(instruction); |
| } else { |