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

Unified 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 side-by-side diff with in-line comments
Download patch
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 40ed4ccd2ffd8b9e48af788ef03b2e50e4984a38..193d63b6597cc4b0fd5f0faa4190388b4b0a46af 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -1301,6 +1301,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;
@@ -1331,6 +1336,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
@@ -1510,6 +1517,13 @@ class SsaBuilder extends ast.Visitor
});
}
+ /**
+ * Return null so it is simple to remove the optional parameters completely
+ * from interop methods to match JavaScript semantics for ommitted arguments.
+ */
+ HInstruction handleConstantForOptionalParameterJsInterop(Element parameter) =>
+ null;
Siggi Cherem (dart-lang) 2015/10/06 22:38:02 do we need `null`, or the null-constant object? (g
Jacob 2015/10/13 01:19:24 this is intentional and not something I'm particul
+
HInstruction handleConstantForOptionalParameter(Element parameter) {
ConstantValue constantValue =
backend.constants.getConstantValueForVariable(parameter);
@@ -1604,10 +1618,21 @@ 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)));
+ var value = pop();
+ closeAndGotoExit(new HReturn(value,
+ sourceInformationBuilder.buildReturn(functionElement.node)));
+ return closeFunction();
+ } else if (function.modifiers.isExternal) {
+ compiler.reportErrorMessage(
+ function, MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
Siggi Cherem (dart-lang) 2015/10/06 22:38:02 it would be nice to produce these errors elsewhere
Jacob 2015/10/13 01:19:24 added TODO
+ }
+
// 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.
@@ -1812,6 +1837,7 @@ class SsaBuilder extends ast.Visitor
*/
void visitInlinedFunction(FunctionElement function) {
potentiallyCheckInlinedParameterTypes(function);
+
if (function.isGenerativeConstructor) {
buildFactory(function);
} else {
@@ -2115,7 +2141,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
@@ -3925,7 +3952,10 @@ class SsaBuilder extends ast.Visitor
arguments,
element,
compileArgument,
- handleConstantForOptionalParameter);
+ element.isJsInterop ?
+ handleConstantForOptionalParameterJsInterop :
+ handleConstantForOptionalParameter
+ );
Siggi Cherem (dart-lang) 2015/10/06 22:38:02 style nit: move this back to the line above? even
Jacob 2015/10/13 01:19:24 Done.
}
void addGenericSendArgumentsToList(Link<ast.Node> link, List<HInstruction> list) {
@@ -5072,7 +5102,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));
}
@@ -5788,6 +5819,96 @@ class SsaBuilder extends ast.Visitor
}
}
+ HForeignCode invokeJsInteropFunction(Element element,
+ List<HInstruction> arguments,
+ SourceInformation sourceInformation) {
+ assert(element.isJsInterop);
+ nativeEmitter.nativeMethods.add(element);
+ String templateString;
+
+ if (element.isFactoryConstructor) {
+ // Treat factory constructors as syntactic sugar for creating object
+ // literals.
+ ConstructorElement constructor = element;
+ FunctionSignature params = constructor.functionSignature;
+ 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.reportErrorMessage(
+ parameter, MessageKind.GENERIC,
+ {'text': 'Error: all arguments to external constructors of'
Siggi Cherem (dart-lang) 2015/10/06 22:38:02 nit: add trailing spaces here and below (to avoid
Jacob 2015/10/13 01:19:24 Done.
+ 'JavaScript interop classes must be named as these'
+ 'constructors are syntactic sugar for object literals'});
+ }
+ HInstruction 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(
+ "${backend.namer.fixedBackendPath(element)}."
+ "${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 = <HInstruction>[target]..addAll(arguments);
+
+ js.Template codeTemplate;
+ if (element.isGetter) {
+ codeTemplate = js.js.parseForeignJS("#");
+ } else if (element.isSetter) {
+ codeTemplate = js.js.parseForeignJS("# = #");
+ } else {
+ var argsStub = <String>[];
+ 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.jsJavaScriptObjectClass.thisType)
+ ..typesInstantiated.add(
+ backend.jsJavaScriptObjectClass.thisType)
+ ..sideEffects.setAllSideEffects();
+ return new HForeignCode(
+ codeTemplate,
+ backend.dynamicType, inputs,
+ nativeBehavior: nativeBehavior)
+ ..sourceInformation = sourceInformation;
+ }
+
void pushInvokeStatic(ast.Node location,
Element element,
List<HInstruction> arguments,
@@ -5806,16 +5927,22 @@ 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 {

Powered by Google App Engine
This is Rietveld 408576698