Chromium Code Reviews| Index: pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart |
| diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart |
| index 77806c00c334282149e35f446964ba6b83a99a65..d1461fc838d07c113de8da951b130f782369820d 100644 |
| --- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart |
| +++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart |
| @@ -20,7 +20,7 @@ import 'cps_ir_builder_task.dart' show DartCapturedVariables, |
| GlobalProgramInformation; |
| import '../common.dart' as types show TypeMask; |
| -import '../js/js.dart' as js show Template; |
| +import '../js/js.dart' as js show Template, js, LiteralStatement; |
| import '../native/native.dart' show NativeBehavior; |
| /// A mapping from variable elements to their compile-time values. |
| @@ -2025,6 +2025,88 @@ class IrBuilder { |
| } |
| } |
| + /// Build a call to the closure conversion helper for the [Function] typed |
| + /// value in [value]. |
| + ir.Primitive _convertDartClosure(ir.Primitive value, FunctionType type) { |
| + ir.Constant arity = buildIntegerConstant(type.computeArity()); |
| + return buildStaticFunctionInvocation( |
| + program.closureConverter, |
| + CallStructure.TWO_ARGS, |
| + <ir.Primitive>[value, arity]); |
| + } |
| + |
| + final RegExp nativeRedirectionRegExp = |
| + new RegExp(r'^[a-zA-Z][a-zA-Z_$0-9]*$'); |
|
asgerf
2015/08/12 13:15:02
Make this static?
|
| + |
| + /// Generate the body for a native function. |
| + /// |
| + /// If [nativeBody] is non-null, generate a [ForeignCode] statement for the |
| + /// body defined in JavaScript. Otherwise, generate a call to the real |
| + /// target, which is given by the [FunctionElement]'s `fixedBackendName`. |
| + /// The target can be a function, getter, or setter. |
| + void buildNativeFunctionBody(ast.Node nativeBody, |
| + SourceInformation source) { |
| + FunctionElement function = state.currentElement; |
| + assert(function.isNative); |
| + String name = function.fixedBackendName; |
| + List<ir.Primitive> arguments = <ir.Primitive>[]; |
| + NativeBehavior behavior = new NativeBehavior(); |
| + behavior.sideEffects.setAllSideEffects(); |
| + |
| + if (nativeBody != null) { |
|
asgerf
2015/08/12 13:15:02
I think it would make more sense to have this spli
|
| + ast.LiteralString jsCode = nativeBody.asLiteralString(); |
| + String code = jsCode.dartString.slowToString(); |
| + assert(invariant(nativeBody, !nativeRedirectionRegExp.hasMatch(code), |
| + message: "Deprecated syntax, use @JSName('name') instead.")); |
| + assert(invariant(nativeBody, |
| + function.functionSignature.parameterCount == 0, |
| + message: 'native "..." syntax is restricted to ' |
| + 'functions with zero parameters.')); |
| + // Generate a [ForeignCode] statement from the given native code. |
| + buildForeignCode( |
| + js.js.statementTemplateYielding(new js.LiteralStatement(code)), |
| + <ir.Primitive>[], |
| + behavior); |
| + } else { |
| + program.addNativeMethod(function); |
| + // Construct the access of the target element. |
| + String code = function.isInstanceMember ? '#.$name' : name; |
| + if (function.isInstanceMember) { |
| + arguments.add(state.thisParameter); |
| + } |
| + // Collect all parameters of the function and templates for them to be |
| + // inserted into the JavaScript code. |
| + List<String> argumentTemplates = <String>[]; |
| + function.functionSignature.forEachParameter((ParameterElement parameter) { |
| + ir.Primitive input = environment.lookup(parameter); |
| + DartType type = program.unaliasType(parameter.type); |
| + if (type is FunctionType) { |
| + // The parameter type is a function type either directly or through |
| + // typedef(s). |
| + input = _convertDartClosure(input, type); |
| + } |
| + arguments.add(input); |
| + argumentTemplates.add('#'); |
| + }); |
| + // Construct the application of parameters for functions and setters. |
| + if (function.kind == ElementKind.FUNCTION) { |
| + code = "$code(${argumentTemplates.join(', ')})"; |
| + } else if (function.kind == ElementKind.SETTER) { |
| + code = "$code = ${argumentTemplates.single}"; |
| + } else { |
| + assert(argumentTemplates.isEmpty); |
| + assert(function.kind == ElementKind.GETTER); |
| + } |
| + // Generate the [ForeignCode] expression and a return statement to return |
| + // its value. |
| + ir.Primitive value = buildForeignCode( |
| + js.js.uncachedExpressionTemplate(code), |
| + arguments, |
| + behavior); |
| + buildReturn(value: value, sourceInformation: source); |
| + } |
| + } |
| + |
| /// Create a blocks of [statements] by applying [build] to all reachable |
| /// statements. The first statement is assumed to be reachable. |
| // TODO(johnniwinther): Type [statements] as `Iterable` when `NodeList` uses |
| @@ -2599,6 +2681,7 @@ class IrBuilder { |
| List<ir.Primitive> arguments, |
| NativeBehavior behavior, |
| {Element dependency}) { |
| + assert(behavior != null); |
| types.TypeMask type = program.getTypeMaskForForeign(behavior); |
| ir.Primitive result = _continueWithExpression((k) => new ir.ForeignCode( |
| codeTemplate, |
| @@ -2608,7 +2691,7 @@ class IrBuilder { |
| k, |
| dependency: dependency)); |
| if (!codeTemplate.isExpression) { |
| - // Close the term if this is a "throw" expression. |
| + // Close the term if this is a "throw" expression or native body. |
| add(new ir.Unreachable()); |
| _current = null; |
| } |