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

Unified Diff: pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart

Issue 1185633003: cps-ir: Support foreign code. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Update test expectations. Created 5 years, 6 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/cps_ir/cps_ir_builder.dart ('k') | pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
index 3bfeed456686a7f73bb206602e37e4d153e6f6f2..88373676a4111b53ab6a16f33315c9ffc173020b 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
@@ -20,6 +20,17 @@ import '../tree/tree.dart' as ast;
import '../universe/universe.dart' show SelectorKind, CallStructure;
import 'cps_ir_nodes.dart' as ir;
import 'cps_ir_builder.dart';
+import '../native/native.dart' show NativeBehavior;
+
+// TODO(karlklose): remove.
+import '../js/js.dart' as js show js, Template, Expression;
+import '../ssa/ssa.dart' show TypeMaskFactory;
+import '../types/types.dart' show TypeMask;
+import '../util/util.dart';
+
+import 'package:_internal/compiler/js_lib/shared/embedded_names.dart'
+ show JsBuiltin, JsGetName;
+import '../constants/values.dart';
typedef void IrBuilderCallback(Element element, ir.FunctionDefinition irNode);
@@ -997,15 +1008,7 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive>
MethodElement function,
ast.NodeList arguments,
CallStructure callStructure,
- _) {
- // TODO(karlklose): support foreign functions.
- if (compiler.backend.isForeign(function)) {
- return giveup(node, 'handleStaticFunctionInvoke: foreign: $function');
- }
- return irBuilder.buildStaticFunctionInvocation(function, callStructure,
- translateStaticArguments(arguments, function, callStructure),
- sourceInformation: sourceInformationBuilder.buildCall(node));
- }
+ _);
@override
ir.Primitive handleStaticFunctionIncompatibleInvoke(
@@ -1864,7 +1867,7 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive>
}
}
- void internalError(ast.Node node, String message) {
+ internalError(ast.Node node, String message) {
giveup(node, message);
}
@@ -2059,6 +2062,10 @@ class GlobalProgramInformation {
ClassElement get nullClass => _compiler.nullClass;
DartType unaliasType(DartType type) => type.unalias(_compiler);
+
+ TypeMask getTypeMaskForForeign(NativeBehavior behavior) {
+ return TypeMaskFactory.fromNativeBehavior(behavior, _compiler);
+ }
}
/// IR builder specific to the JavaScript backend, coupled to the [JsIrBuilder].
@@ -2810,6 +2817,232 @@ class JsIrBuilderVisitor extends IrBuilderVisitor {
return irBuilder.buildStaticFieldGet(field, src);
}
}
+
+ /// Build code to handle foreign code, that is, native JavaScript code, or
+ /// builtin values and operations of the backend.
+ ir.Primitive handleForeignCode(ast.Send node,
+ MethodElement function,
+ ast.NodeList argumentList,
+ CallStructure callStructure) {
+
+ void validateArgumentCount({int minimum, int exactly}) {
+ assert((minimum == null) != (exactly == null));
+ int count = 0;
+ int maximum;
+ if (exactly != null) {
+ minimum = exactly;
+ maximum = exactly;
+ }
+ for (ast.Node argument in argumentList) {
+ count++;
+ if (maximum != null && count > maximum) {
+ internalError(argument, 'Additional argument.');
+ }
+ }
+ if (count < minimum) {
+ internalError(node, 'Expected at least $minimum arguments.');
+ }
+ }
+
+ /// Call a helper method from the isolate library. The isolate library uses
+ /// its own isolate structure, that encapsulates dart2js's isolate.
+ ir.Primitive buildIsolateHelperInvocation(String helperName,
+ CallStructure callStructure) {
+ Element element = backend.isolateHelperLibrary.find(helperName);
+ if (element == null) {
+ compiler.internalError(node,
+ 'Isolate library and compiler mismatch.');
+ }
+ List<ir.Primitive> arguments = translateStaticArguments(argumentList,
+ element, CallStructure.TWO_ARGS);
+ return irBuilder.buildStaticFunctionInvocation(element,
+ CallStructure.TWO_ARGS, arguments,
+ sourceInformation: sourceInformationBuilder.buildCall(node));
+ }
+
+ /// Lookup the value of the enum described by [node].
+ getEnumValue(ast.Node node, EnumClassElement enumClass, List values) {
+ Element element = elements[node];
+ if (element is! FieldElement || element.enclosingClass != enumClass) {
+ internalError(node, 'expected a JsBuiltin enum value');
+ }
+
+ int index = enumClass.enumValues.indexOf(element);
+ return values[index];
+ }
+
+ /// Returns the String the node evaluates to, or throws an error if the
+ /// result is not a string constant.
+ String expectStringConstant(ast.Node node) {
+ ir.Primitive nameValue = visit(node);
+ if (nameValue is ir.Constant && nameValue.value.isString) {
+ StringConstantValue constantValue = nameValue.value;
+ return constantValue.primitiveValue.slowToString();
+ } else {
+ return internalError(node, 'expected a literal string');
+ }
+ }
+
+ Link<ast.Node> argumentNodes = argumentList.nodes;
+ NativeBehavior behavior =
+ compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node);
+ switch (function.name) {
+ case 'JS':
+ validateArgumentCount(minimum: 2);
+ // The first two arguments are the type and the foreign code template,
+ // which already have been analyzed by the resolver and can be retrieved
+ // using [NativeBehavior]. We can ignore these arguments in the backend.
+ List<ir.Primitive> arguments =
+ argumentNodes.skip(2).mapToList(visit, growable: false);
+ return irBuilder.buildForeignCode(behavior.codeTemplate, arguments,
+ behavior);
+
+ case 'DART_CLOSURE_TO_JS':
+ // TODO(ahe): This should probably take care to wrap the closure in
+ // another closure that saves the current isolate.
+ case 'RAW_DART_FUNCTION_REF':
+ validateArgumentCount(exactly: 1);
+
+ ast.Node argument = node.arguments.single;
+ FunctionElement closure = elements[argument].implementation;
+ if (!Elements.isStaticOrTopLevelFunction(closure)) {
+ internalError(argument,
+ 'only static or toplevel function supported');
+ }
+ if (closure.functionSignature.hasOptionalParameters) {
+ internalError(argument,
+ 'closures with optional parameters not supported');
+ }
+ return irBuilder.buildForeignCode(
+ js.js.expressionTemplateYielding(
+ backend.emitter.staticFunctionAccess(function)),
+ <ir.Primitive>[],
+ NativeBehavior.PURE,
+ dependency: closure);
+
+ case 'JS_BUILTIN':
+ // The first argument is a description of the type and effect of the
+ // builtin, which has already been analyzed in the frontend. The second
+ // argument must be a [JsBuiltin] value. All other arguments are
+ // values used by the JavaScript template that is associated with the
+ // builtin.
+ validateArgumentCount(minimum: 2);
+
+ ast.Node builtin = argumentNodes.tail.head;
+ JsBuiltin value = getEnumValue(argumentNodes.tail.head,
+ backend.jsBuiltinEnum, JsBuiltin.values);
+ js.Template template = backend.emitter.builtinTemplateFor(value);
+ List<ir.Primitive> arguments =
+ argumentNodes.skip(2).mapToList(visit, growable: false);
+ return irBuilder.buildForeignCode(template, arguments, behavior);
+
+ case 'JS_EMBEDDED_GLOBAL':
+ validateArgumentCount(exactly: 2);
+
+ String name = expectStringConstant(argumentNodes.tail.head);
+ js.Expression access =
+ backend.emitter.generateEmbeddedGlobalAccess(name);
+ js.Template template = js.js.expressionTemplateYielding(access);
+ return irBuilder.buildForeignCode(template, <ir.Primitive>[], behavior);
+
+ case 'JS_INTERCEPTOR_CONSTANT':
+ validateArgumentCount(exactly: 1);
+
+ ast.Node argument = argumentNodes.head;
+ ir.Primitive argumentValue = visit(argument);
+ if (argumentValue is ir.Constant && argumentValue.value.isType) {
+ TypeConstantValue constant = argumentValue.value;
+ ConstantValue interceptorValue =
+ new InterceptorConstantValue(constant.representedType);
+ return irBuilder.buildConstant(argumentValue.expression,
+ interceptorValue);
+ } else {
+ internalError(argument, 'expected Type as argument');
+ }
+ break;
+
+ case 'JS_EFFECT':
+ return irBuilder.buildNullConstant();
+
+ case 'JS_GET_NAME':
+ validateArgumentCount(exactly: 1);
+
+ ast.Node argument = argumentNodes.head;
+ JsGetName id = getEnumValue(argument, backend.jsGetNameEnum,
+ JsGetName.values);
+ String name = backend.namer.getNameForJsGetName(argument, id);
+ return irBuilder.buildStringConstant(name);
+
+ case 'JS_GET_FLAG':
+ validateArgumentCount(exactly: 1);
+
+ String name = expectStringConstant(argumentNodes.first);
+ bool value = false;
+ switch (name) {
+ case 'MUST_RETAIN_METADATA':
+ value = backend.mustRetainMetadata;
+ break;
+ case 'USE_CONTENT_SECURITY_POLICY':
+ value = compiler.useContentSecurityPolicy;
+ break;
+ default:
+ internalError(node, 'Unknown internal flag "$name".');
+ }
+ return irBuilder.buildBooleanConstant(value);
+
+ case 'JS_STRING_CONCAT':
+ validateArgumentCount(exactly: 2);
+ List<ir.Primitive> arguments = argumentNodes.mapToList(visit);
+ return irBuilder.buildStringConcatenation(arguments);
+
+ case 'JS_CURRENT_ISOLATE_CONTEXT':
+ validateArgumentCount(exactly: 0);
+
+ if (!compiler.hasIsolateSupport) {
+ // If the isolate library is not used, we just generate code
+ // to fetch the current isolate.
+ String name = backend.namer.currentIsolate;
+ return irBuilder.buildForeignCode(js.js.parseForeignJS(name),
+ const <ir.Primitive>[], NativeBehavior.PURE);
+ } else {
+ return buildIsolateHelperInvocation('_currentIsolate',
+ CallStructure.NO_ARGS);
+ }
+ break;
+
+ case 'JS_CALL_IN_ISOLATE':
+ validateArgumentCount(exactly: 2);
+
+ if (!compiler.hasIsolateSupport) {
+ ir.Primitive closure = visit(argumentNodes.tail.head);
+ return irBuilder.buildCallInvocation(closure, CallStructure.NO_ARGS,
+ const <ir.Primitive>[]);
+ } else {
+ return buildIsolateHelperInvocation('_callInIsolate',
+ CallStructure.TWO_ARGS);
+ }
+ break;
+
+ default:
+ giveup(node, 'unplemented native construct: ${function.name}');
+ break;
+ }
+ }
+
+ @override
+ ir.Primitive handleStaticFunctionInvoke(ast.Send node,
+ MethodElement function,
+ ast.NodeList argumentList,
+ CallStructure callStructure,
+ _) {
+ if (compiler.backend.isForeign(function)) {
+ return handleForeignCode(node, function, argumentList, callStructure);
+ } else {
+ return irBuilder.buildStaticFunctionInvocation(function, callStructure,
+ translateStaticArguments(argumentList, function, callStructure),
+ sourceInformation: sourceInformationBuilder.buildCall(node));
+ }
+ }
}
/// Perform simple post-processing on the initial CPS-translated root term.
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart ('k') | pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698