| Index: pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
|
| diff --git a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
|
| index d7e1578c9962a0ecc46ba159681e45a0fd10f593..79dbcf607969116f933e64700799161b5a6b3a8a 100644
|
| --- a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
|
| +++ b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
|
| @@ -112,3 +112,101 @@ class ClassStubGenerator {
|
| return generatedStubs;
|
| }
|
| }
|
| +
|
| +/// Creates two JavaScript functions: `tearOffGetter` and `tearOff`.
|
| +///
|
| +/// `tearOffGetter` is internal and only used by `tearOff`.
|
| +///
|
| +/// `tearOff` takes the following arguments:
|
| +/// * `funcs`: a list of functions. These are the functions representing the
|
| +/// member that is torn off. There can be more than one, since a member
|
| +/// can have several stubs.
|
| +/// Each function must have the `$callName` property set.
|
| +/// * `reflectionInfo`: contains reflective information, and the function
|
| +/// type. TODO(floitsch): point to where this is specified.
|
| +/// * `isStatic`.
|
| +/// * `name`.
|
| +/// * `isIntercepted.
|
| +List<jsAst.Statement> buildTearOffCode(JavaScriptBackend backend) {
|
| + Namer namer = backend.namer;
|
| + Compiler compiler = backend.compiler;
|
| +
|
| + Element closureFromTearOff = backend.findHelper('closureFromTearOff');
|
| + String tearOffAccessText;
|
| + jsAst.Expression tearOffAccessExpression;
|
| + String tearOffGlobalObjectName;
|
| + String tearOffGlobalObject;
|
| + if (closureFromTearOff != null) {
|
| + // We need both the AST that references [closureFromTearOff] and a string
|
| + // for the NoCsp version that constructs a function.
|
| + tearOffAccessExpression =
|
| + backend.emitter.staticFunctionAccess(closureFromTearOff);
|
| + tearOffAccessText =
|
| + jsAst.prettyPrint(tearOffAccessExpression, compiler).getText();
|
| + tearOffGlobalObjectName = tearOffGlobalObject =
|
| + namer.globalObjectFor(closureFromTearOff);
|
| + } else {
|
| + // Default values for mocked-up test libraries.
|
| + tearOffAccessText =
|
| + r'''function() { throw 'Helper \'closureFromTearOff\' missing.' }''';
|
| + tearOffAccessExpression = js(tearOffAccessText);
|
| + tearOffGlobalObjectName = 'MissingHelperFunction';
|
| + tearOffGlobalObject = '($tearOffAccessText())';
|
| + }
|
| +
|
| + jsAst.Statement tearOffGetter;
|
| + if (!compiler.useContentSecurityPolicy) {
|
| + // This template is uncached because it is constructed from code fragments
|
| + // that can change from compilation to compilation. Some of these could be
|
| + // avoided, except for the string literals that contain the compiled access
|
| + // path to 'closureFromTearOff'.
|
| + tearOffGetter = js.uncachedStatementTemplate('''
|
| + function tearOffGetter(funcs, reflectionInfo, name, isIntercepted) {
|
| + return isIntercepted
|
| + ? new Function("funcs", "reflectionInfo", "name",
|
| + "$tearOffGlobalObjectName", "c",
|
| + "return function tearOff_" + name + (functionCounter++)+ "(x) {" +
|
| + "if (c === null) c = $tearOffAccessText(" +
|
| + "this, funcs, reflectionInfo, false, [x], name);" +
|
| + "return new c(this, funcs[0], x, name);" +
|
| + "}")(funcs, reflectionInfo, name, $tearOffGlobalObject, null)
|
| + : new Function("funcs", "reflectionInfo", "name",
|
| + "$tearOffGlobalObjectName", "c",
|
| + "return function tearOff_" + name + (functionCounter++)+ "() {" +
|
| + "if (c === null) c = $tearOffAccessText(" +
|
| + "this, funcs, reflectionInfo, false, [], name);" +
|
| + "return new c(this, funcs[0], null, name);" +
|
| + "}")(funcs, reflectionInfo, name, $tearOffGlobalObject, null);
|
| + }''').instantiate([]);
|
| + } else {
|
| + tearOffGetter = js.statement('''
|
| + function tearOffGetter(funcs, reflectionInfo, name, isIntercepted) {
|
| + var cache = null;
|
| + return isIntercepted
|
| + ? function(x) {
|
| + if (cache === null) cache = #(
|
| + this, funcs, reflectionInfo, false, [x], name);
|
| + return new cache(this, funcs[0], x, name);
|
| + }
|
| + : function() {
|
| + if (cache === null) cache = #(
|
| + this, funcs, reflectionInfo, false, [], name);
|
| + return new cache(this, funcs[0], null, name);
|
| + };
|
| + }''', [tearOffAccessExpression, tearOffAccessExpression]);
|
| + }
|
| +
|
| + jsAst.Statement tearOff = js.statement('''
|
| + function tearOff(funcs, reflectionInfo, isStatic, name, isIntercepted) {
|
| + var cache;
|
| + return isStatic
|
| + ? function() {
|
| + if (cache === void 0) cache = #tearOff(
|
| + this, funcs, reflectionInfo, true, [], name).prototype;
|
| + return cache;
|
| + }
|
| + : tearOffGetter(funcs, reflectionInfo, name, isIntercepted);
|
| + }''', {'tearOff': tearOffAccessExpression});
|
| +
|
| + return <jsAst.Statement>[tearOffGetter, tearOff];
|
| +}
|
|
|