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

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: about to land 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
« no previous file with comments | « pkg/compiler/lib/src/serialization/modelz.dart ('k') | pkg/compiler/lib/src/types/types.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 e24af1149cbc83888b475d375c66d39cc9cffed0..bb00a2640caf363cc5a45d4592002585afbc3269 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -1339,6 +1339,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;
@@ -1369,6 +1374,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
@@ -1547,6 +1554,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;
+
HInstruction handleConstantForOptionalParameter(Element parameter) {
ConstantValue constantValue =
backend.constants.getConstantValueForVariable(parameter);
@@ -1634,10 +1648,19 @@ class SsaBuilder extends ast.Visitor
graph.calledInLoop = compiler.world.isCalledInLoop(functionElement);
ast.FunctionExpression function = functionElement.node;
assert(function != null);
- assert(invariant(functionElement, !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();
+ }
+ assert(invariant(functionElement, !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.
@@ -1842,6 +1865,7 @@ class SsaBuilder extends ast.Visitor
*/
void visitInlinedFunction(FunctionElement function) {
potentiallyCheckInlinedParameterTypes(function);
+
if (function.isGenerativeConstructor) {
buildFactory(function);
} else {
@@ -2145,7 +2169,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
@@ -3956,7 +3981,9 @@ class SsaBuilder extends ast.Visitor
arguments,
element,
compileArgument,
- handleConstantForOptionalParameter);
+ element.isJsInterop ?
+ handleConstantForOptionalParameterJsInterop :
+ handleConstantForOptionalParameter);
}
void addGenericSendArgumentsToList(Link<ast.Node> link, List<HInstruction> list) {
@@ -5101,7 +5128,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));
}
@@ -5818,6 +5846,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) {
+ reporter.reportErrorMessage(
+ parameter, MessageKind.GENERIC,
+ {'text': 'All arguments to external constructors of 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,
@@ -5836,16 +5954,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 {
« no previous file with comments | « pkg/compiler/lib/src/serialization/modelz.dart ('k') | pkg/compiler/lib/src/types/types.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698