| Index: pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
|
| diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
|
| index b429495122bb9b9332d8a176daa666445ecd3cbb..7f5bc4a0d6e014f6f34a9f94ab6d13ef9749ca8e 100644
|
| --- a/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
|
| +++ b/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
|
| @@ -74,9 +74,8 @@ class OldEmitter implements Emitter {
|
| * precompiled function.
|
| *
|
| * To save space, dart2js normally generates constructors and accessors
|
| - * dynamically. This doesn't work in CSP mode, and may impact startup time
|
| - * negatively. So dart2js will emit these functions to a separate file that
|
| - * can be optionally included to support CSP mode or for faster startup.
|
| + * dynamically. This doesn't work in CSP mode, so dart2js emits them directly
|
| + * when in CSP mode.
|
| */
|
| Map<OutputUnit, List<jsAst.Node>> _cspPrecompiledFunctions =
|
| new Map<OutputUnit, List<jsAst.Node>>();
|
| @@ -166,6 +165,11 @@ class OldEmitter implements Emitter {
|
| String get makeConstListProperty
|
| => namer.getMappedInstanceName('makeConstantList');
|
|
|
| + /// The name of the property that contains all field names.
|
| + ///
|
| + /// This property is added to constructors when isolate support is enabled.
|
| + static const String FIELD_NAMES_PROPERTY_NAME = r"$__fields__";
|
| +
|
| /// For deferred loading we communicate the initializers via this global var.
|
| final String deferredInitializers = r"$dart_deferred_initializers";
|
|
|
| @@ -182,7 +186,7 @@ class OldEmitter implements Emitter {
|
| }
|
|
|
| jsAst.Expression isolateLazyInitializerAccess(Element element) {
|
| - return jsAst.js('#.#', [namer.globalObjectFor(element),
|
| + return jsAst.js('#.#', [namer.globalObjectFor(element),
|
| namer.getLazyInitializerName(element)]);
|
| }
|
|
|
| @@ -190,7 +194,7 @@ class OldEmitter implements Emitter {
|
| return jsAst.js('#.#()',
|
| [namer.globalObjectFor(element), namer.getStaticClosureName(element)]);
|
| }
|
| -
|
| +
|
| jsAst.PropertyAccess globalPropertyAccess(Element element) {
|
| String name = namer.getNameX(element);
|
| jsAst.PropertyAccess pa = new jsAst.PropertyAccess.field(
|
| @@ -198,19 +202,19 @@ class OldEmitter implements Emitter {
|
| name);
|
| return pa;
|
| }
|
| -
|
| +
|
| jsAst.PropertyAccess staticFieldAccess(Element element) {
|
| return globalPropertyAccess(element);
|
| }
|
| -
|
| +
|
| jsAst.PropertyAccess staticFunctionAccess(Element element) {
|
| return globalPropertyAccess(element);
|
| }
|
| -
|
| +
|
| jsAst.PropertyAccess classAccess(Element element) {
|
| return globalPropertyAccess(element);
|
| }
|
| -
|
| +
|
| jsAst.PropertyAccess typedefAccess(Element element) {
|
| return globalPropertyAccess(element);
|
| }
|
| @@ -288,7 +292,7 @@ class OldEmitter implements Emitter {
|
| }''');
|
| }
|
|
|
| - List get defineClassFunction {
|
| + List<jsAst.Node> get defineClassFunction {
|
| // First the class name, then the field names in an array and the members
|
| // (inside an Object literal).
|
| // The caller can also pass in the constructor as a function if needed.
|
| @@ -303,45 +307,99 @@ class OldEmitter implements Emitter {
|
| // },
|
| // });
|
|
|
| - var defineClass = js('''function(name, fields) {
|
| - var accessors = [];
|
| -
|
| - var str = "function " + name + "(";
|
| - var body = "";
|
| + bool hasIsolateSupport = compiler.hasIsolateSupport;
|
| + String fieldNamesProperty = FIELD_NAMES_PROPERTY_NAME;
|
|
|
| - for (var i = 0; i < fields.length; i++) {
|
| - if(i != 0) str += ", ";
|
| -
|
| - var field = generateAccessor(fields[i], accessors, name);
|
| - var parameter = "parameter_" + field;
|
| - str += parameter;
|
| - body += ("this." + field + " = " + parameter + ";\\n");
|
| - }
|
| - str += ") {\\n" + body + "}\\n";
|
| - str += name + ".builtin\$cls=\\"" + name + "\\";\\n";
|
| - str += "\$desc=\$collectedClasses." + name + ";\\n";
|
| - str += "if(\$desc instanceof Array) \$desc = \$desc[1];\\n";
|
| - str += name + ".prototype = \$desc;\\n";
|
| - if (typeof defineClass.name != "string") {
|
| - str += name + ".name=\\"" + name + "\\";\\n";
|
| - }
|
| - str += accessors.join("");
|
| + jsAst.Expression defineClass = js('''
|
| + function(name, fields) {
|
| + var accessors = [];
|
| +
|
| + var str = "function " + name + "(";
|
| + var body = "";
|
| + if (#hasIsolateSupport) { var fieldNames = ""; }
|
| +
|
| + for (var i = 0; i < fields.length; i++) {
|
| + if(i != 0) str += ", ";
|
| +
|
| + var field = generateAccessor(fields[i], accessors, name);
|
| + if (#hasIsolateSupport) { fieldNames += "'" + field + "',"; }
|
| + var parameter = "parameter_" + field;
|
| + str += parameter;
|
| + body += ("this." + field + " = " + parameter + ";\\n");
|
| + }
|
| + str += ") {\\n" + body + "}\\n";
|
| + str += name + ".builtin\$cls=\\"" + name + "\\";\\n";
|
| + str += "\$desc=\$collectedClasses." + name + ";\\n";
|
| + str += "if(\$desc instanceof Array) \$desc = \$desc[1];\\n";
|
| + str += name + ".prototype = \$desc;\\n";
|
| + if (typeof defineClass.name != "string") {
|
| + str += name + ".name=\\"" + name + "\\";\\n";
|
| + }
|
| + if (#hasIsolateSupport) {
|
| + str += name + ".$fieldNamesProperty=[" + fieldNames + "];\\n";
|
| + }
|
| + str += accessors.join("");
|
| +
|
| + return str;
|
| + }''', { 'hasIsolateSupport': hasIsolateSupport });
|
|
|
| - return str;
|
| - }''');
|
| // Declare a function called "generateAccessor". This is used in
|
| // defineClassFunction (it's a local declaration in init()).
|
| - List<jsAst.Node> saveDefineClass = [];
|
| - if (compiler.hasIncrementalSupport) {
|
| - saveDefineClass.add(
|
| - js(r'self.$dart_unsafe_eval.defineClass = defineClass'));
|
| - }
|
| - return [
|
| + List result = <jsAst.Node>[
|
| generateAccessorFunction,
|
| js('$generateAccessorHolder = generateAccessor'),
|
| new jsAst.FunctionDeclaration(
|
| - new jsAst.VariableDeclaration('defineClass'), defineClass) ]
|
| - ..addAll(saveDefineClass);
|
| + new jsAst.VariableDeclaration('defineClass'), defineClass) ];
|
| +
|
| + if (compiler.hasIncrementalSupport) {
|
| + result.add(
|
| + js(r'self.$dart_unsafe_eval.defineClass = defineClass'));
|
| + }
|
| +
|
| + if (hasIsolateSupport) {
|
| + jsAst.Expression classIdExtractorAccess =
|
| + generateEmbeddedGlobalAccess(embeddedNames.CLASS_ID_EXTRACTOR);
|
| + var classIdExtractorAssignment =
|
| + js('# = function(o) { return o.constructor.name; }',
|
| + classIdExtractorAccess);
|
| +
|
| + jsAst.Expression classFieldsExtractorAccess =
|
| + generateEmbeddedGlobalAccess(embeddedNames.CLASS_FIELDS_EXTRACTOR);
|
| + var classFieldsExtractorAssignment = js('''
|
| + # = function(o) {
|
| + var fieldNames = o.constructor.$fieldNamesProperty;
|
| + if (!fieldNames) return []; // TODO(floitsch): do something else here.
|
| + var result = [];
|
| + result.length = fieldNames.length;
|
| + for (var i = 0; i < fieldNames.length; i++) {
|
| + result[i] = o[fieldNames[i]];
|
| + }
|
| + return result;
|
| + }''', classFieldsExtractorAccess);
|
| +
|
| + jsAst.Expression instanceFromClassIdAccess =
|
| + generateEmbeddedGlobalAccess(embeddedNames.INSTANCE_FROM_CLASS_ID);
|
| + jsAst.Expression allClassesAccess =
|
| + generateEmbeddedGlobalAccess(embeddedNames.ALL_CLASSES);
|
| + var instanceFromClassIdAssignment =
|
| + js('# = function(name) { return new #[name](); }',
|
| + [instanceFromClassIdAccess, allClassesAccess]);
|
| +
|
| + jsAst.Expression initializeEmptyInstanceAccess =
|
| + generateEmbeddedGlobalAccess(embeddedNames.INITIALIZE_EMPTY_INSTANCE);
|
| + var initializeEmptyInstanceAssignment = js('''
|
| + # = function(name, o, fields) {
|
| + #[name].apply(o, fields);
|
| + return o;
|
| + }''', [ initializeEmptyInstanceAccess, allClassesAccess ]);
|
| +
|
| + result.addAll([classIdExtractorAssignment,
|
| + classFieldsExtractorAssignment,
|
| + instanceFromClassIdAssignment,
|
| + initializeEmptyInstanceAssignment]);
|
| + }
|
| +
|
| + return result;
|
| }
|
|
|
| /** Needs defineClass to be defined. */
|
| @@ -1310,25 +1368,34 @@ class OldEmitter implements Emitter {
|
|
|
| void emitPrecompiledConstructor(OutputUnit outputUnit,
|
| String constructorName,
|
| - jsAst.Expression constructorAst) {
|
| + jsAst.Expression constructorAst,
|
| + List<String> fields) {
|
| cspPrecompiledFunctionFor(outputUnit).add(
|
| new jsAst.FunctionDeclaration(
|
| new jsAst.VariableDeclaration(constructorName), constructorAst));
|
| - cspPrecompiledFunctionFor(outputUnit).add(
|
| - js.statement(r'''{
|
| - #.builtin$cls = #;
|
| - if (!"name" in #)
|
| - #.name = #;
|
| - $desc=$collectedClasses.#;
|
| +
|
| + String fieldNamesProperty = FIELD_NAMES_PROPERTY_NAME;
|
| + bool hasIsolateSupport = compiler.hasIsolateSupport;
|
| + jsAst.Node fieldNamesArray =
|
| + hasIsolateSupport ? js.stringArray(fields) : new jsAst.LiteralNull();
|
| +
|
| + cspPrecompiledFunctionFor(outputUnit).add(js.statement(r'''
|
| + {
|
| + #constructorName.builtin$cls = #constructorNameString;
|
| + if (!"name" in #constructorName)
|
| + #constructorName.name = #constructorNameString;
|
| + $desc = $collectedClasses.#constructorName;
|
| if ($desc instanceof Array) $desc = $desc[1];
|
| - #.prototype = $desc;
|
| + #constructorName.prototype = $desc;
|
| + ''' /* next string is not a raw string */ '''
|
| + if (#hasIsolateSupport) {
|
| + #constructorName.$fieldNamesProperty = #fieldNamesArray;
|
| + }
|
| }''',
|
| - [ constructorName, js.string(constructorName),
|
| - constructorName,
|
| - constructorName, js.string(constructorName),
|
| - constructorName,
|
| - constructorName
|
| - ]));
|
| + {"constructorName": constructorName,
|
| + "constructorNameString": js.string(constructorName),
|
| + "hasIsolateSupport": hasIsolateSupport,
|
| + "fieldNamesArray": fieldNamesArray}));
|
|
|
| cspPrecompiledConstructorNamesFor(outputUnit).add(js('#', constructorName));
|
| }
|
| @@ -1391,9 +1458,11 @@ class OldEmitter implements Emitter {
|
| // Also emit a trivial constructor for CSP mode.
|
| String constructorName = mangledName;
|
| jsAst.Expression constructorAst = js('function() {}');
|
| + List<String> fieldNames = [];
|
| emitPrecompiledConstructor(mainOutputUnit,
|
| constructorName,
|
| - constructorAst);
|
| + constructorAst,
|
| + fieldNames);
|
| }
|
| }
|
|
|
|
|