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); |
} |
} |