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

Unified Diff: pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart

Issue 1140703006: dart2js: Construct the entire output as a single AST before printing. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Comments Created 5 years, 7 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
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 dd2c214d749f956ddbcd98accd490c3fe046f230..ee4093faebe03662530a2b89050ecadce6ea3a56 100644
--- a/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
@@ -16,7 +16,7 @@ class OldEmitter implements Emitter {
// TODO(johnniwinther): Wrap these fields in a caching strategy.
final Set<ConstantValue> cachedEmittedConstants;
- final CodeBuffer cachedEmittedConstantsBuffer = new CodeBuffer();
+ final List<jsAst.Statement> cachedEmittedConstantsAst = <jsAst.Statement>[];
final Map<Element, ClassBuilder> cachedClassBuilders;
final Set<Element> cachedElements;
@@ -37,9 +37,6 @@ class OldEmitter implements Emitter {
// The full code that is written to each hunk part-file.
Map<OutputUnit, CodeOutput> outputBuffers = new Map<OutputUnit, CodeOutput>();
- /** Shorter access to [isolatePropertiesName]. Both here in the code, as
- well as in the generated code. */
- String isolateProperties;
String classesCollector;
Set<ClassElement> get neededClasses => task.neededClasses;
Map<OutputUnit, List<ClassElement>> get outputClassLists
@@ -123,10 +120,6 @@ class OldEmitter implements Emitter {
_cspPrecompiledConstructorNames.clear();
}
- void addComment(String comment, CodeOutput output) {
- output.addBuffer(jsAst.prettyPrint(js.comment(comment), compiler));
- }
-
@override
bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) {
if (constant.isFunction) return true; // Already emitted.
@@ -202,7 +195,7 @@ class OldEmitter implements Emitter {
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";
+ final String deferredInitializers = r"$dart_deferred_initializers$";
/// Contains the global state that is needed to initialize and load a
/// deferred library.
@@ -343,11 +336,6 @@ class OldEmitter implements Emitter {
return interceptorEmitter.generateInterceptedNamesSet();
}
- void emitFinishIsolateConstructorInvocation(CodeOutput output) {
- String isolate = namer.isolateName;
- output.add("$isolate = $finishIsolateConstructorName($isolate)$N");
- }
-
/// In minified mode we want to keep the name for the most common core types.
bool _isNativeTypeNeedingReflectionName(Element element) {
if (!element.isClass) return false;
@@ -471,21 +459,25 @@ class OldEmitter implements Emitter {
jsAst.Statement buildCspPrecompiledFunctionFor(
OutputUnit outputUnit) {
- // TODO(ahe): Compute a hash code.
- // TODO(sigurdm): Avoid this precompiled function. Generated
- // constructor-functions and getter/setter functions can be stored in the
- // library-description table. Setting properties on these can be moved to
- // finishClasses.
- return js.statement('''
- # = function (\$collectedClasses) {
- var \$desc;
- #;
- return #;
- };''',
- [generateEmbeddedGlobalAccess(embeddedNames.PRECOMPILED),
- cspPrecompiledFunctionFor(outputUnit),
- new jsAst.ArrayInitializer(
- cspPrecompiledConstructorNamesFor(outputUnit))]);
+ if (compiler.useContentSecurityPolicy) {
+ // TODO(ahe): Compute a hash code.
+ // TODO(sigurdm): Avoid this precompiled function. Generated
+ // constructor-functions and getter/setter functions can be stored in the
+ // library-description table. Setting properties on these can be moved to
+ // finishClasses.
+ return js.statement('''
+ # = function (\$collectedClasses) {
+ var \$desc;
+ #;
+ return #;
+ };''',
+ [generateEmbeddedGlobalAccess(embeddedNames.PRECOMPILED),
+ cspPrecompiledFunctionFor(outputUnit),
+ new jsAst.ArrayInitializer(
+ cspPrecompiledConstructorNamesFor(outputUnit))]);
+ } else {
+ return js.comment("Constructors are generated at runtime.");
+ }
}
void assembleClass(Class cls, ClassBuilder enclosingBuilder,
@@ -526,19 +518,18 @@ class OldEmitter implements Emitter {
}
}
- void emitStaticNonFinalFieldInitializations(CodeOutput output,
- OutputUnit outputUnit) {
- void emitInitialization(Element element, jsAst.Expression initialValue) {
- jsAst.Expression init =
- js('$isolateProperties.# = #',
- [namer.globalPropertyName(element), initialValue]);
- output.addBuffer(jsAst.prettyPrint(init, compiler,
- monitor: compiler.dumpInfoTask));
- output.add('$N');
+ jsAst.Statement buildStaticNonFinalFieldInitializations(
+ OutputUnit outputUnit) {
+ jsAst.Statement buildInitialization(Element element,
+ jsAst.Expression initialValue) {
+ // Note: `namer.currentIsolate` refers to the isolate properties here.
+ return js.statement('${namer.currentIsolate}.# = #',
+ [namer.globalPropertyName(element), initialValue]);
}
bool inMainUnit = (outputUnit == compiler.deferredLoadTask.mainOutputUnit);
JavaScriptConstantCompiler handler = backend.constants;
+ List<jsAst.Statement> parts = <jsAst.Statement>[];
Iterable<Element> fields = task.outputStaticNonFinalFieldLists[outputUnit];
// If the outputUnit does not contain any static non-final fields, then
@@ -547,7 +538,7 @@ class OldEmitter implements Emitter {
for (Element element in fields) {
compiler.withCurrentElement(element, () {
ConstantValue constant = handler.getInitialValueFor(element).value;
- emitInitialization(element, constantReference(constant));
+ parts.add(buildInitialization(element, constantReference(constant)));
});
}
}
@@ -560,21 +551,23 @@ class OldEmitter implements Emitter {
if (fieldsOutputUnit == outputUnit) return; // Skip the main unit.
for (Element element in fields) {
compiler.withCurrentElement(element, () {
- emitInitialization(element, jsAst.number(0));
+ parts.add(buildInitialization(element, jsAst.number(0)));
});
}
});
}
+
+ return new jsAst.Block(parts);
}
- void emitLazilyInitializedStaticFields(CodeOutput output) {
+ jsAst.Statement buildLazilyInitializedStaticFields() {
JavaScriptConstantCompiler handler = backend.constants;
List<VariableElement> lazyFields =
handler.getLazilyInitializedFieldsForEmission();
- if (!lazyFields.isEmpty) {
+ if (lazyFields.isNotEmpty) {
needsLazyInitializer = true;
List<jsAst.Expression> laziesInfo = buildLaziesInfo(lazyFields);
- jsAst.Statement code = js.statement('''
+ return js.statement('''
(function(lazies) {
if (#notInMinifiedMode) {
var descriptorLength = 4;
@@ -604,10 +597,8 @@ class OldEmitter implements Emitter {
''', {'notInMinifiedMode': !compiler.enableMinification,
'laziesInfo': new jsAst.ArrayInitializer(laziesInfo),
'lazy': js(lazyInitializerName)});
-
- output.addBuffer(
- jsAst.prettyPrint(code, compiler, monitor: compiler.dumpInfoTask));
- output.add("$N");
+ } else {
+ return js.comment("No lazy statics.");
}
}
@@ -673,7 +664,8 @@ class OldEmitter implements Emitter {
}
}
- void emitMetadata(Program program, CodeOutput output, OutputUnit outputUnit) {
+ jsAst.Statement buildMetadata(Program program, OutputUnit outputUnit) {
+ List<jsAst.Statement> parts = <jsAst.Statement>[];
jsAst.Expression constructList(List<jsAst.Expression> list) {
return new jsAst.ArrayInitializer(list == null ? [] : list);
@@ -687,34 +679,24 @@ class OldEmitter implements Emitter {
jsAst.Expression typesAccess =
generateEmbeddedGlobalAccess(embeddedNames.TYPES);
- output.addBuffer(
- jsAst.prettyPrint(new jsAst.Block([
- js.statement('# = #;', [metadataAccess,
- constructList(program.metadata)]),
- js.statement('# = #;', [typesAccess, constructList(types)])]),
- compiler, monitor: compiler.dumpInfoTask));
- output.add(n);
+ parts..add(js.statement('# = #;', [metadataAccess,
+ constructList(program.metadata)]))
+ ..add(js.statement('# = #;', [typesAccess, constructList(types)]));
} else if (types != null) {
- output.addBuffer(
- jsAst.prettyPrint(
- js.statement('var ${namer.deferredTypesName} = #;',
- constructList(types)),
- compiler, monitor: compiler.dumpInfoTask));
- if (compiler.enableMinification) {
- output.add('\n');
- }
+ parts.add(js.statement('var ${namer.deferredTypesName} = #;',
+ constructList(types)));
}
+ return new jsAst.Block(parts);
}
- void emitCompileTimeConstants(CodeOutput output,
- List<Constant> constants,
- {bool isMainFragment}) {
+ jsAst.Statement buildCompileTimeConstants(List<Constant> constants,
+ {bool isMainFragment}) {
assert(isMainFragment != null);
- if (constants.isEmpty) return;
- CodeOutput constantOutput = output;
+ if (constants.isEmpty) return js.comment("No constants in program.");
+ List<jsAst.Statement> parts = <jsAst.Statement>[];
if (compiler.hasIncrementalSupport && isMainFragment) {
- constantOutput = cachedEmittedConstantsBuffer;
+ parts = cachedEmittedConstantsAst;
}
for (Constant constant in constants) {
ConstantValue constantValue = constant.value;
@@ -722,21 +704,17 @@ class OldEmitter implements Emitter {
if (cachedEmittedConstants.contains(constantValue)) continue;
cachedEmittedConstants.add(constantValue);
}
- jsAst.Expression init = buildConstantInitializer(constantValue);
- constantOutput.addBuffer(
- jsAst.prettyPrint(init, compiler, monitor: compiler.dumpInfoTask));
- constantOutput.add('$N');
- }
- if (compiler.hasIncrementalSupport && isMainFragment) {
- output.addBuffer(constantOutput);
+ parts.add(buildConstantInitializer(constantValue));
}
+
+ return new jsAst.Block(parts);
}
- jsAst.Expression buildConstantInitializer(ConstantValue constant) {
+ jsAst.Statement buildConstantInitializer(ConstantValue constant) {
String name = namer.constantName(constant);
- return js('#.# = #',
- [namer.globalObjectForConstant(constant), name,
- constantInitializerExpression(constant)]);
+ return js.statement('#.# = #',
+ [namer.globalObjectForConstant(constant), name,
+ constantInitializerExpression(constant)]);
}
jsAst.Template get makeConstantListTemplate {
@@ -745,59 +723,53 @@ class OldEmitter implements Emitter {
'${namer.isolateName}.$makeConstListProperty(#)');
}
- void emitMakeConstantList(CodeOutput output) {
- output.addBuffer(
- jsAst.prettyPrint(
- // Functions are stored in the hidden class and not as properties in
- // the object. We never actually look at the value, but only want
- // to know if the property exists.
- js.statement(r'''#.# = function(list) {
- list.immutable$list = Array;
- list.fixed$length = Array;
- return list;
- }''',
- [namer.isolateName, makeConstListProperty]),
- compiler, monitor: compiler.dumpInfoTask));
- output.add(N);
- }
-
- void emitFunctionThatReturnsNull(CodeOutput output) {
- output.addBuffer(
- jsAst.prettyPrint(
- js.statement('#.# = function() {}',
- [backend.namer.currentIsolate,
- backend.rti.getFunctionThatReturnsNullName]),
- compiler, monitor: compiler.dumpInfoTask));
- output.add(N);
+ jsAst.Statement buildMakeConstantList() {
+ if (task.outputContainsConstantList) {
+ return js.statement(r'''
+ // Functions are stored in the hidden class and not as properties in
+ // the object. We never actually look at the value, but only want
+ // to know if the property exists.
+ #.# = function (list) {
+ list.immutable$list = Array;
+ list.fixed$length = Array;
+ return list;
+ }''',
+ [namer.isolateName, makeConstListProperty]);
+ } else {
+ return js.comment("Output contains no constant list.");
+ }
+ }
+
+ jsAst.Statement buildFunctionThatReturnsNull() {
+ return js.statement('# = function() {}',
+ [backend.rti.getFunctionThatReturnsNullName]);
}
jsAst.Expression generateFunctionThatReturnsNull() {
- return js("#.#", [backend.namer.currentIsolate,
- backend.rti.getFunctionThatReturnsNullName]);
+ return js("#", [backend.rti.getFunctionThatReturnsNullName]);
}
- emitMain(CodeOutput output, jsAst.Statement invokeMain) {
- if (compiler.isMockCompilation) return;
+ buildMain(jsAst.Statement invokeMain) {
+ if (compiler.isMockCompilation) return js.comment("Mock compilation");
+
+ List<jsAst.Statement> parts = <jsAst.Statement>[];
if (NativeGenerator.needsIsolateAffinityTagInitialization(backend)) {
- jsAst.Statement nativeBoilerPlate =
+ parts.add(
NativeGenerator.generateIsolateAffinityTagInitialization(
backend,
generateEmbeddedGlobalAccess,
- js("convertToFastObject", []));
- output.addBuffer(jsAst.prettyPrint(
- nativeBoilerPlate, compiler, monitor: compiler.dumpInfoTask));
+ js("convertToFastObject", [])));
}
- output.add(';');
- addComment('BEGIN invoke [main].', output);
- output.addBuffer(jsAst.prettyPrint(invokeMain,
- compiler, monitor: compiler.dumpInfoTask));
- output.add(N);
- addComment('END invoke [main].', output);
+ parts..add(js.comment('BEGIN invoke [main].'))
+ ..add(invokeMain)
+ ..add(js.comment('END invoke [main].'));
+
+ return new jsAst.Block(parts);
}
- void emitInitFunction(CodeOutput output) {
+ jsAst.Statement buildInitFunction() {
jsAst.Expression allClassesAccess =
generateEmbeddedGlobalAccess(embeddedNames.ALL_CLASSES);
jsAst.Expression getTypeFromNameAccess =
@@ -813,9 +785,9 @@ class OldEmitter implements Emitter {
jsAst.Expression laziesAccess =
generateEmbeddedGlobalAccess(embeddedNames.LAZIES);
- jsAst.FunctionDeclaration decl = js.statement('''
+ return js.statement('''
function init() {
- $isolateProperties = Object.create(null);
+ $isolatePropertiesName = Object.create(null);
#allClasses = Object.create(null);
#getTypeFromName = function(name) {return #allClasses[name];};
#interceptorsByTag = Object.create(null);
@@ -834,7 +806,7 @@ class OldEmitter implements Emitter {
// 'prototype' will be undefined except if we are doing an update
// during incremental compilation. In this case we put the lazy
// field directly on the isolate instead of the isolateProperties.
- prototype = prototype || $isolateProperties;
+ prototype = prototype || $isolatePropertiesName;
var sentinelUndefined = {};
var sentinelInProgress = {};
prototype[fieldName] = sentinelUndefined;
@@ -933,15 +905,9 @@ class OldEmitter implements Emitter {
'makeConstListProperty': makeConstListProperty,
'hasIncrementalSupport': compiler.hasIncrementalSupport,
'lazyInitializerProperty': lazyInitializerProperty,});
-
- output.addBuffer(
- jsAst.prettyPrint(decl, compiler, monitor: compiler.dumpInfoTask));
- if (compiler.enableMinification) {
- output.add('\n');
- }
}
- void emitConvertToFastObjectFunction(CodeOutput output) {
+ jsAst.Statement buildConvertToFastObjectFunction() {
List<jsAst.Statement> debugCode = <jsAst.Statement>[];
if (DEBUG_FAST_OBJECTS) {
debugCode.add(js.statement(r'''
@@ -957,7 +923,7 @@ class OldEmitter implements Emitter {
}'''));
}
- jsAst.Statement convertToFastObject = js.statement(r'''
+ return js.statement(r'''
function convertToFastObject(properties) {
// Create an instance that uses 'properties' as prototype. This should
// make 'properties' a fast object.
@@ -967,13 +933,10 @@ class OldEmitter implements Emitter {
#;
return properties;
}''', [debugCode]);
-
- output.addBuffer(jsAst.prettyPrint(convertToFastObject, compiler));
- output.add(N);
}
- void emitConvertToSlowObjectFunction(CodeOutput output) {
- jsAst.Statement convertToSlowObject = js.statement(r'''
+ jsAst.Statement buildConvertToSlowObjectFunction() {
+ return js.statement(r'''
function convertToSlowObject(properties) {
// Add and remove a property to make the object transition into hashmap
// mode.
@@ -981,12 +944,9 @@ class OldEmitter implements Emitter {
delete properties.__MAGIC_SLOW_PROPERTY;
return properties;
}''');
-
- output.addBuffer(jsAst.prettyPrint(convertToSlowObject, compiler));
- output.add(N);
}
- void emitSupportsDirectProtoAccess(CodeOutput output) {
+ jsAst.Statement buildSupportsDirectProtoAccess() {
jsAst.Statement supportsDirectProtoAccess;
if (compiler.hasIncrementalSupport) {
@@ -1005,8 +965,7 @@ class OldEmitter implements Emitter {
''');
}
- output.addBuffer(jsAst.prettyPrint(supportsDirectProtoAccess, compiler));
- output.add(N);
+ return supportsDirectProtoAccess;
}
jsAst.Expression generateLibraryDescriptor(LibraryElement library,
@@ -1046,7 +1005,7 @@ class OldEmitter implements Emitter {
parts..add(js.string(libraryName))
..add(js.string(uri.toString()))
..add(metadata == null ? new jsAst.ArrayHole() : metadata)
- ..add(js.name(namer.globalObjectFor(library)))
+ ..add(js('#', namer.globalObjectFor(library)))
..add(initializer);
if (library == compiler.mainApp) {
parts.add(js.number(1));
@@ -1132,7 +1091,95 @@ class OldEmitter implements Emitter {
}
}
- void emitMangledNames(CodeOutput output) {
+ jsAst.Statement buildGlobalObjectSetup(bool isProgramSplit) {
+ List<jsAst.Statement> parts = <jsAst.Statement>[];
+
+ parts.add(js.comment("""
+ // The global objects start as so-called "slow objects". For V8, this
+ // means that it won't try to make map transitions as we add properties
+ // to these objects. Later on, we attempt to turn these objects into
+ // fast objects by calling "convertToFastObject" (see
+ // [emitConvertToFastObjectFunction]).
+ """));
+
+ for (String globalObject in Namer.reservedGlobalObjectNames) {
+ if (isProgramSplit) {
+ String template =
+ "var #globalObject = #globalsHolder.#globalObject = map();";
+ parts.add(js.statement(template, {"globalObject": globalObject,
+ "globalsHolder": globalsHolder}));
+ } else {
+ parts.add(js.statement("var #globalObject = map();",
+ {"globalObject": globalObject}));
+ }
+
+ }
+
+ return new jsAst.Block(parts);
+ }
+
+ jsAst.Statement buildConvertGlobalObjectToFastObjects() {
+ List<jsAst.Statement> parts = <jsAst.Statement>[];
+
+ for (String globalObject in Namer.reservedGlobalObjectNames) {
+ parts.add(js.statement(
+ '#globalObject = convertToFastObject(#globalObject);',
+ {"globalObject": globalObject}));
+ }
+
+ return new jsAst.Block(parts);
+ }
+
+ jsAst.Statement buildDebugFastObjectCode() {
+ List<jsAst.Statement> parts = <jsAst.Statement>[];
+
+ if (DEBUG_FAST_OBJECTS) {
+ parts.add(js.statement(r'''
+ // The following only works on V8 when run with option
+ // "--allow-natives-syntax". We use'new Function' because the
+ // miniparser does not understand V8 native syntax.
+ if (typeof print === "function") {
+ var HasFastProperties =
+ new Function("a", "return %HasFastProperties(a)");
+ print("Size of global helper object: "
+ + String(Object.getOwnPropertyNames(H).length)
+ + ", fast properties " + HasFastProperties(H));
+ print("Size of global platform object: "
+ + String(Object.getOwnPropertyNames(P).length)
+ + ", fast properties " + HasFastProperties(P));
+ print("Size of global dart:html object: "
+ + String(Object.getOwnPropertyNames(W).length)
+ + ", fast properties " + HasFastProperties(W));
+ print("Size of isolate properties object: "
+ + String(Object.getOwnPropertyNames($).length)
+ + ", fast properties " + HasFastProperties($));
+ print("Size of constant object: "
+ + String(Object.getOwnPropertyNames(C).length)
+ + ", fast properties " + HasFastProperties(C));
+ var names = Object.getOwnPropertyNames($);
+ for (var i = 0; i < names.length; i++) {
+ print("$." + names[i]);
+ }
+ }
+ '''));
+
+ for (String object in Namer.userGlobalObjects) {
+ parts.add(js.statement('''
+ if (typeof print === "function") {
+ print("Size of " + #objectString + ": "
+ + String(Object.getOwnPropertyNames(#object).length)
+ + ", fast properties " + HasFastProperties(#object));
+ }
+ ''', {"object": object, "objectString": js.string(object)}));
+ }
+ }
+
+ return new jsAst.Block(parts);
+ }
+
+ jsAst.Statement buildMangledNames() {
+ List<jsAst.Statement> parts = <jsAst.Statement>[];
+
if (!mangledFieldNames.isEmpty) {
var keys = mangledFieldNames.keys.toList();
keys.sort();
@@ -1145,15 +1192,9 @@ class OldEmitter implements Emitter {
jsAst.Expression mangledNamesAccess =
generateEmbeddedGlobalAccess(embeddedNames.MANGLED_NAMES);
var map = new jsAst.ObjectInitializer(properties);
- output.addBuffer(
- jsAst.prettyPrint(
- js.statement('# = #', [mangledNamesAccess, map]),
- compiler,
- monitor: compiler.dumpInfoTask));
- if (compiler.enableMinification) {
- output.add(';');
- }
+ parts.add(js.statement('# = #', [mangledNamesAccess, map]));
}
+
if (!mangledGlobalFieldNames.isEmpty) {
var keys = mangledGlobalFieldNames.keys.toList();
keys.sort();
@@ -1165,15 +1206,10 @@ class OldEmitter implements Emitter {
jsAst.Expression mangledGlobalNamesAccess =
generateEmbeddedGlobalAccess(embeddedNames.MANGLED_GLOBAL_NAMES);
var map = new jsAst.ObjectInitializer(properties);
- output.addBuffer(
- jsAst.prettyPrint(
- js.statement('# = #', [mangledGlobalNamesAccess, map]),
- compiler,
- monitor: compiler.dumpInfoTask));
- if (compiler.enableMinification) {
- output.add(';');
- }
+ parts.add(js.statement('# = #', [mangledGlobalNamesAccess, map]));
}
+
+ return new jsAst.Block(parts);
}
void checkEverythingEmitted(Iterable<Element> elements) {
@@ -1235,96 +1271,31 @@ class OldEmitter implements Emitter {
bool isProgramSplit = program.isSplit;
- mainOutput.add(buildGeneratedBy());
- addComment(HOOKS_API_USAGE, mainOutput);
+ List<jsAst.Statement> statements = <jsAst.Statement>[];
+
+ statements..add(buildGeneratedBy())
+ ..add(js.comment(HOOKS_API_USAGE));
if (isProgramSplit) {
/// For deferred loading we communicate the initializers via this global
/// variable. The deferred hunks will add their initialization to this.
/// The semicolon is important in minified mode, without it the
/// following parenthesis looks like a call to the object literal.
- mainOutput.add(
- 'self.${deferredInitializers} = self.${deferredInitializers} || '
- 'Object.create(null);$n');
+ statements.add(
+ js.statement('self.#deferredInitializers = '
+ 'self.#deferredInitializers || Object.create(null);',
+ {'deferredInitializers': deferredInitializers}));
}
- // Using a named function here produces easier to read stack traces in
- // Chrome/V8.
- mainOutput.add('(function(${namer.currentIsolate})$_{\n');
- emitSupportsDirectProtoAccess(mainOutput);
- if (compiler.hasIncrementalSupport) {
- mainOutput.addBuffer(jsAst.prettyPrint(js.statement(
- """
-{
- #helper = #helper || Object.create(null);
- #helper.patch = function(a) { eval(a)};
- #helper.schemaChange = #schemaChange;
- #helper.addMethod = #addMethod;
- #helper.extractStubs = function(array, name, isStatic, originalDescriptor) {
- var descriptor = Object.create(null);
- this.addStubs(descriptor, array, name, isStatic, []);
- return descriptor;
- };
-}""",
- { 'helper': js('this.#', [namer.incrementalHelperName]),
- 'schemaChange': buildSchemaChangeFunction(),
- 'addMethod': buildIncrementalAddMethod() }), compiler));
- }
- if (isProgramSplit) {
- /// We collect all the global state, so it can be passed to the
- /// initializer of deferred files.
- mainOutput.add('var ${globalsHolder}$_=${_}Object.create(null)$N');
- }
-
- jsAst.Statement mapFunction = js.statement('''
-// [map] returns an object that V8 shouldn't try to optimize with a hidden
-// class. This prevents a potential performance problem where V8 tries to build
-// a hidden class for an object used as a hashMap.
-// It requires fewer characters to declare a variable as a parameter than
-// with `var`.
- function map(x) {
- x = Object.create(null);
- x.x = 0;
- delete x.x;
- return x;
- }
-''');
- mainOutput.addBuffer(jsAst.prettyPrint(mapFunction, compiler));
- for (String globalObject in Namer.reservedGlobalObjectNames) {
- // The global objects start as so-called "slow objects". For V8, this
- // means that it won't try to make map transitions as we add properties
- // to these objects. Later on, we attempt to turn these objects into
- // fast objects by calling "convertToFastObject" (see
- // [emitConvertToFastObjectFunction]).
- mainOutput.add('var ${globalObject}$_=${_}');
- if(isProgramSplit) {
- mainOutput.add('${globalsHolder}.$globalObject$_=${_}');
- }
- mainOutput.add('map()$N');
- }
-
- mainOutput.add('function ${namer.isolateName}()$_{}\n');
- if (isProgramSplit) {
- mainOutput.add(
- '${globalsHolder}.${namer.isolateName}$_=$_${namer.isolateName}$N'
- '${globalsHolder}.$initName$_=${_}$initName$N'
- '${globalsHolder}.$setupProgramName$_=$_'
- '$setupProgramName$N');
- }
- mainOutput.add('init()$N$n');
- mainOutput.add('$isolateProperties$_=$_$isolatePropertiesName$N');
+ // Collect the AST for the decriptors
+ Map<Element, ClassBuilder> descriptors = elementDescriptors[mainFragment];
+ if (descriptors == null) descriptors = const {};
- emitFunctionThatReturnsNull(mainOutput);
+ checkEverythingEmitted(descriptors.keys);
Iterable<LibraryElement> libraries =
task.outputLibraryLists[mainOutputUnit];
if (libraries == null) libraries = [];
- emitMangledNames(mainOutput);
-
- Map<Element, ClassBuilder> descriptors = elementDescriptors[mainFragment];
- if (descriptors == null) descriptors = const {};
-
- checkEverythingEmitted(descriptors.keys);
List<jsAst.Expression> parts = <jsAst.Expression>[];
for (LibraryElement library in Elements.sortedByPosition(libraries)) {
@@ -1334,8 +1305,8 @@ class OldEmitter implements Emitter {
if (descriptors.isNotEmpty) {
List<Element> remainingLibraries = descriptors.keys
- .where((Element e) => e is LibraryElement)
- .toList();
+ .where((Element e) => e is LibraryElement)
+ .toList();
// The remaining descriptors are only accessible through reflection.
// The program builder does not collect libraries that only
@@ -1350,127 +1321,166 @@ class OldEmitter implements Emitter {
}
jsAst.ArrayInitializer descriptorsAst = new jsAst.ArrayInitializer(parts);
- bool needsNativeSupport = program.needsNativeSupport;
- mainOutput.addBuffer(
- jsAst.prettyPrint(
- buildSetupProgram(program, compiler, backend, namer, this),
- compiler));
-
- // The argument to reflectionDataParser is assigned to a temporary 'dart'
- // so that 'dart.' will appear as the prefix to dart methods in stack
- // traces and profile entries.
- mainOutput..add('var dart =')
- ..addBuffer(jsAst.prettyPrint(descriptorsAst, compiler,
- monitor: compiler.dumpInfoTask))
- ..add('$N');
- if (compiler.useContentSecurityPolicy) {
- jsAst.Statement precompiledFunctionAst =
- buildCspPrecompiledFunctionFor(mainOutputUnit);
- mainOutput.addBuffer(
- jsAst.prettyPrint(
- precompiledFunctionAst,
- compiler,
- monitor: compiler.dumpInfoTask,
- allowVariableMinification: false));
- mainOutput.add(N);
- }
-
- mainOutput.add('$setupProgramName(dart, 0)$N');
-
- interceptorEmitter.emitGetInterceptorMethods(mainOutput);
- interceptorEmitter.emitOneShotInterceptors(mainOutput);
-
- if (task.outputContainsConstantList) {
- emitMakeConstantList(mainOutput);
- }
-
- // Constants in checked mode call into RTI code to set type information
- // which may need getInterceptor (and one-shot interceptor) methods, so
- // we have to make sure that [emitGetInterceptorMethods] and
- // [emitOneShotInterceptors] have been called.
- emitCompileTimeConstants(
- mainOutput, mainFragment.constants, isMainFragment: true);
+ // Using a named function here produces easier to read stack traces in
+ // Chrome/V8.
+ statements.add(js.statement("""
+ (function() {
+ // No renaming in the top-level function to save the locals for the
+ // nested context where they will be used more. We have to put the
+ // comment into a hole as the parser strips out comments right away.
+ #disableVariableRenaming;
+ #supportsDirectProtoAccess;
- emitDeferredBoilerPlate(mainOutput, deferredLoadHashes);
+ if (#hasIncrementalSupport) {
+ #helper = #helper || Object.create(null);
+ #helper.patch = function(a) { eval(a)};
+ #helper.schemaChange = #schemaChange;
+ #helper.addMethod = #addMethod;
+ #helper.extractStubs =
+ function(array, name, isStatic, originalDescriptor) {
+ var descriptor = Object.create(null);
+ this.addStubs(descriptor, array, name, isStatic, []);
+ return descriptor;
+ };
+ }
+
+ if (#isProgramSplit) {
+ /// We collect all the global state, so it can be passed to the
+ /// initializer of deferred files.
+ var #globalsHolder = Object.create(null)
+ }
+
+ // [map] returns an object that V8 shouldn't try to optimize with a
+ // hidden class. This prevents a potential performance problem where V8
+ // tries to build a hidden class for an object used as a hashMap.
+ // It requires fewer characters to declare a variable as a parameter than
+ // with `var`.
+ function map(x) {
+ x = Object.create(null);
+ x.x = 0;
+ delete x.x;
+ return x;
+ }
+
+ #globalObjectSetup;
+
+ function #isolateName() {}
+
+ if (#isProgramSplit) {
+ #globalsHolder.#isolateName = #isolateName;
+ #globalsHolder.#initName = #initName;
+ #globalsHolder.#setupProgramName = #setupProgramName;
+ }
+
+ init();
+
+ #mangledNames;
+
+ #setupProgram;
+
+ #functionThatReturnsNull;
+
+ // The argument to reflectionDataParser is assigned to a temporary 'dart'
+ // so that 'dart.' will appear as the prefix to dart methods in stack
+ // traces and profile entries.
+ var dart = #descriptors;
+
+ #setupProgramName(dart, 0);
+
+ #cspPrecompiledFunctions;
+
+ #getInterceptorMethods;
+ #oneShotInterceptors;
+
+ #makeConstantList;
+
+ // We abuse the short name used for the isolate here to store
+ // the isolate properties. This is safe as long as the real isolate
+ // object does not exist yet.
+ var ${namer.currentIsolate} = #isolatePropertiesName;
+
+ // Constants in checked mode call into RTI code to set type information
+ // which may need getInterceptor (and one-shot interceptor) methods, so
+ // we have to make sure that [emitGetInterceptorMethods] and
+ // [emitOneShotInterceptors] have been called.
+ #compileTimeConstants;
+
+ // Static field initializations require the classes and compile-time
+ // constants to be set up.
+ #staticNonFinalInitializers;
+
+ ${namer.currentIsolate} = null;
+
+ #deferredBoilerPlate;
+
+ #typeToInterceptorMap;
+
+ #lazyStaticFields;
+
+ #isolateName = $finishIsolateConstructorName(#isolateName);
+
+ ${namer.currentIsolate} = new #isolateName();
+
+ #metadata;
+
+ #convertToFastObject;
+ #convertToSlowObject;
+
+ #convertGlobalObjectsToFastObjects;
+ #debugFastObjects;
+
+ #init;
+
+ #main;
+ })();
+ """, {
+ "disableVariableRenaming": js.comment("/* ::norenaming:: */"),
+ "hasIncrementalSupport": compiler.hasIncrementalSupport,
+ "helper": js('this.#', [namer.incrementalHelperName]),
+ "schemaChange": buildSchemaChangeFunction(),
+ "addMethod": buildIncrementalAddMethod(),
+ "isProgramSplit": isProgramSplit,
+ "supportsDirectProtoAccess": buildSupportsDirectProtoAccess(),
+ "globalsHolder": globalsHolder,
+ "globalObjectSetup": buildGlobalObjectSetup(isProgramSplit),
+ "isolateName": namer.isolateName,
+ "isolatePropertiesName": js(isolatePropertiesName),
+ "initName": initName,
+ "functionThatReturnsNull": buildFunctionThatReturnsNull(),
+ "mangledNames": buildMangledNames(),
+ "setupProgram": buildSetupProgram(program, compiler, backend, namer, this),
+ "setupProgramName": setupProgramName,
+ "descriptors": descriptorsAst,
+ "cspPrecompiledFunctions": buildCspPrecompiledFunctionFor(mainOutputUnit),
+ "getInterceptorMethods": interceptorEmitter.buildGetInterceptorMethods(),
+ "oneShotInterceptors": interceptorEmitter.buildOneShotInterceptors(),
+ "makeConstantList": buildMakeConstantList(),
+ "compileTimeConstants": buildCompileTimeConstants(mainFragment.constants,
+ isMainFragment: true),
+ "deferredBoilerPlate": buildDeferredBoilerPlate(deferredLoadHashes),
+ "staticNonFinalInitializers": buildStaticNonFinalFieldInitializations(
+ mainOutputUnit),
+ "typeToInterceptorMap":
+ interceptorEmitter.buildTypeToInterceptorMap(program),
+ "lazyStaticFields": buildLazilyInitializedStaticFields(),
+ "metadata": buildMetadata(program, mainOutputUnit),
+ "convertToFastObject": buildConvertToFastObjectFunction(),
+ "convertToSlowObject": buildConvertToSlowObjectFunction(),
+ "convertGlobalObjectsToFastObjects":
+ buildConvertGlobalObjectToFastObjects(),
+ "debugFastObjects": buildDebugFastObjectCode(),
+ "init": buildInitFunction(),
+ "main": buildMain(mainFragment.invokeMain)
+ }));
+
+ mainOutput.addBuffer(jsAst.prettyPrint(new jsAst.Program(statements),
+ compiler,
+ monitor: compiler.dumpInfoTask));
if (compiler.deferredMapUri != null) {
outputDeferredMap();
}
- // Static field initializations require the classes and compile-time
- // constants to be set up.
- emitStaticNonFinalFieldInitializations(mainOutput, mainOutputUnit);
- interceptorEmitter.emitTypeToInterceptorMap(program, mainOutput);
- if (compiler.enableMinification) {
- mainOutput.add(';');
- }
- emitLazilyInitializedStaticFields(mainOutput);
-
- mainOutput.add('\n');
-
- emitMetadata(program, mainOutput, mainOutputUnit);
-
- isolateProperties = isolatePropertiesName;
- // The following code should not use the short-hand for the
- // initialStatics.
- mainOutput.add('${namer.currentIsolate}$_=${_}null$N');
-
- emitFinishIsolateConstructorInvocation(mainOutput);
- mainOutput.add(
- '${namer.currentIsolate}$_=${_}new ${namer.isolateName}()$N');
-
- emitConvertToFastObjectFunction(mainOutput);
- emitConvertToSlowObjectFunction(mainOutput);
-
- for (String globalObject in Namer.reservedGlobalObjectNames) {
- mainOutput.add('$globalObject = convertToFastObject($globalObject)$N');
- }
- if (DEBUG_FAST_OBJECTS) {
- mainOutput.add(r'''
- // The following only works on V8 when run with option
- // "--allow-natives-syntax". We use'new Function' because the
- // miniparser does not understand V8 native syntax.
- if (typeof print === "function") {
- var HasFastProperties =
- new Function("a", "return %HasFastProperties(a)");
- print("Size of global helper object: "
- + String(Object.getOwnPropertyNames(H).length)
- + ", fast properties " + HasFastProperties(H));
- print("Size of global platform object: "
- + String(Object.getOwnPropertyNames(P).length)
- + ", fast properties " + HasFastProperties(P));
- print("Size of global dart:html object: "
- + String(Object.getOwnPropertyNames(W).length)
- + ", fast properties " + HasFastProperties(W));
- print("Size of isolate properties object: "
- + String(Object.getOwnPropertyNames($).length)
- + ", fast properties " + HasFastProperties($));
- print("Size of constant object: "
- + String(Object.getOwnPropertyNames(C).length)
- + ", fast properties " + HasFastProperties(C));
- var names = Object.getOwnPropertyNames($);
- for (var i = 0; i < names.length; i++) {
- print("$." + names[i]);
- }
- }
-''');
- for (String object in Namer.userGlobalObjects) {
- mainOutput.add('''
- if (typeof print === "function") {
- print("Size of $object: "
- + String(Object.getOwnPropertyNames($object).length)
- + ", fast properties " + HasFastProperties($object));
-}
-''');
- }
- }
-
- emitInitFunction(mainOutput);
- emitMain(mainOutput, mainFragment.invokeMain);
-
- mainOutput.add('})()\n');
-
-
if (generateSourceMap) {
mainOutput.add(
generateSourceMapTag(compiler.sourceMapUri, compiler.outputUri));
@@ -1487,6 +1497,7 @@ class OldEmitter implements Emitter {
/// Used by incremental compilation to patch up the prototype of
/// [oldConstructor] for use as prototype of [newConstructor].
jsAst.Fun buildSchemaChangeFunction() {
+ if (!compiler.hasIncrementalSupport) return null;
return js('''
function(newConstructor, oldConstructor, superclass) {
// Invariant: newConstructor.prototype has no interesting properties besides
@@ -1519,6 +1530,7 @@ function(newConstructor, oldConstructor, superclass) {
/// top-level). [globalFunctionsAccess] is a reference to
/// [embeddedNames.GLOBAL_FUNCTIONS].
jsAst.Fun buildIncrementalAddMethod() {
+ if (!compiler.hasIncrementalSupport) return null;
return js(r"""
function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) {
var arrayOrFunction = originalDescriptor[name];
@@ -1639,9 +1651,6 @@ function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) {
assembleProgram(program);
- // Shorten the code by using [namer.currentIsolate] as temporary.
- isolateProperties = namer.currentIsolate;
-
// Emit deferred units first, so we have their hashes.
// Map from OutputUnit to a hash of its content. The hash uniquely
// identifies the code of the output-unit. It does not include
@@ -1694,9 +1703,11 @@ function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) {
}
/// Emits support-code for deferred loading into [output].
- void emitDeferredBoilerPlate(CodeOutput output,
- Map<OutputUnit, String> deferredLoadHashes) {
- jsAst.Statement functions = js.statement('''
+ jsAst.Statement buildDeferredBoilerPlate(
+ Map<OutputUnit, String> deferredLoadHashes) {
+ List<jsAst.Statement> parts = <jsAst.Statement>[];
+
+ parts.add(js.statement('''
{
// Function for checking if a hunk is loaded given its hash.
#isHunkLoaded = function(hunkHash) {
@@ -1721,9 +1732,8 @@ function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) {
"initializeLoadedHunk": generateEmbeddedGlobalAccess(
embeddedNames.INITIALIZE_LOADED_HUNK),
"deferredInitialized": generateEmbeddedGlobalAccess(
- embeddedNames.DEFERRED_INITIALIZED)});
- output.addBuffer(jsAst.prettyPrint(functions,
- compiler, monitor: compiler.dumpInfoTask));
+ embeddedNames.DEFERRED_INITIALIZED)}));
+
// Write a javascript mapping from Deferred import load ids (derrived
// from the import prefix.) to a list of lists of uris of hunks to load,
// and a corresponding mapping to a list of hashes used by
@@ -1757,15 +1767,14 @@ function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) {
new jsAst.ObjectInitializer(properties, isOneLiner: true);
jsAst.Node globalName = generateEmbeddedGlobalAccess(name);
- output.addBuffer(jsAst.prettyPrint(
- js("# = #", [globalName, initializer]),
- compiler, monitor: compiler.dumpInfoTask));
- output.add('$N');
+ parts.add(js.statement("# = #", [globalName, initializer]));
}
emitMapping(embeddedNames.DEFERRED_LIBRARY_URIS, deferredLibraryUris);
emitMapping(embeddedNames.DEFERRED_LIBRARY_HASHES,
deferredLibraryHashes);
+
+ return new jsAst.Block(parts);
}
/// Emits code for all output units except the main.
@@ -1800,84 +1809,72 @@ function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) {
outputBuffers[outputUnit] = output;
- output
- ..add(buildGeneratedBy())
- ..add('${deferredInitializers}.current$_=$_'
- 'function$_(${globalsHolder}) {$N');
+ List<jsAst.Statement> body = <jsAst.Statement>[];
+
+ // No renaming in the top-level function to save the locals for the
+ // nested context where they will be used more.
+ body.add(js.comment("/* ::norenaming:: "));
+
for (String globalObject in Namer.reservedGlobalObjectNames) {
- output
- .add('var $globalObject$_=$_'
- '${globalsHolder}.$globalObject$N');
+ body.add(js.statement('var #object = ${globalsHolder}.#object;',
+ {'object': globalObject}));
}
- output
- ..add('var init$_=$_${globalsHolder}.init$N')
- ..add('var $setupProgramName$_=$_'
- '$globalsHolder.$setupProgramName$N')
- ..add('var ${namer.isolateName}$_=$_'
- '${globalsHolder}.${namer.isolateName}$N');
+ body..add(js.statement('var init = ${globalsHolder}.init;'))
+ ..add(js.statement('var $setupProgramName = '
+ '$globalsHolder.$setupProgramName;'))
+ ..add(js.statement('var ${namer.isolateName} = '
+ '${globalsHolder}.${namer.isolateName};'));
String typesAccess =
generateEmbeddedGlobalAccessString(embeddedNames.TYPES);
if (libraryDescriptor != null) {
- // TODO(ahe): This defines a lot of properties on the
- // Isolate.prototype object. We know this will turn it into a
- // slow object in V8, so instead we should do something similar
- // to Isolate.$finishIsolateConstructor.
- output
- ..add('var ${namer.currentIsolate}$_=$_$isolatePropertiesName$N')
- // The argument to reflectionDataParser is assigned to a temporary
- // 'dart' so that 'dart.' will appear as the prefix to dart methods
- // in stack traces and profile entries.
- ..add('var dart = $n ')
- ..addBuffer(jsAst.prettyPrint(libraryDescriptor, compiler,
- monitor: compiler.dumpInfoTask))
- ..add('$N');
+ // The argument to reflectionDataParser is assigned to a temporary
+ // 'dart' so that 'dart.' will appear as the prefix to dart methods
+ // in stack traces and profile entries.
+ body.add(js.statement('var dart = #', libraryDescriptor));
if (compiler.useContentSecurityPolicy) {
- jsAst.Statement precompiledFunctionAst =
- buildCspPrecompiledFunctionFor(outputUnit);
-
- output.addBuffer(
- jsAst.prettyPrint(
- precompiledFunctionAst, compiler,
- monitor: compiler.dumpInfoTask,
- allowVariableMinification: false));
- output.add(N);
+ body.add(buildCspPrecompiledFunctionFor(outputUnit));
}
- output.add('$setupProgramName(dart, ${typesAccess}.length)$N');
+ body.add(
+ js.statement('$setupProgramName(dart, ${typesAccess}.length);'));
}
if (task.metadataCollector.types[outputUnit] != null) {
- emitMetadata(program, output, outputUnit);
- output.add('${typesAccess}.'
- 'push.apply(${typesAccess},$_${namer.deferredTypesName})$N');
+ body..add(buildMetadata(program, outputUnit))
+ ..add(js.statement('${typesAccess}.push.apply(${typesAccess}, '
+ '${namer.deferredTypesName});'));
}
// Set the currentIsolate variable to the current isolate (which is
// provided as second argument).
- // We need to do this, because we use the same variable for setting up
- // the isolate-properties and for storing the current isolate. During
- // the setup (the code above this lines) we must set the variable to
- // the isolate-properties.
- // After we have done the setup it must point to the current Isolate.
- // Otherwise all methods/functions accessing isolate variables will
- // access the wrong object.
- output.add("${namer.currentIsolate}$_=${_}arguments[1]$N");
-
- emitCompileTimeConstants(
- output, fragment.constants, isMainFragment: false);
- emitStaticNonFinalFieldInitializations(output, outputUnit);
-
- output.add('}$N');
+ body.add(js.statement("${namer.currentIsolate} = arguments[1];"));
+
+ body.add(buildCompileTimeConstants(fragment.constants,
+ isMainFragment: false));
+ body.add(buildStaticNonFinalFieldInitializations(outputUnit));
+
+ List<jsAst.Statement> statements = <jsAst.Statement>[];
+
+ statements..add(buildGeneratedBy())
+ ..add(js.statement('${deferredInitializers}.current = '
+ """function (${globalsHolder}) {
+ #
+ }
+ """, [body]));
+
+ output.addBuffer(jsAst.prettyPrint(new jsAst.Program(statements),
+ compiler,
+ monitor: compiler.dumpInfoTask));
+
// Make a unique hash of the code (before the sourcemaps are added)
// This will be used to retrieve the initializing function from the global
// variable.
String hash = hasher.getHash();
- output.add('${deferredInitializers}["$hash"]$_=$_'
+ output.add('$N${deferredInitializers}["$hash"]$_=$_'
'${deferredInitializers}.current$N');
if (generateSourceMap) {
-
Uri mapUri, partUri;
Uri sourceMapUri = compiler.sourceMapUri;
Uri outputUri = compiler.outputUri;
@@ -1911,10 +1908,12 @@ function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) {
return hunkHashes;
}
- String buildGeneratedBy() {
- var suffix = '';
+ jsAst.Comment buildGeneratedBy() {
+ String suffix = '';
if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}';
- return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n';
+ String msg = '// Generated by dart2js, the Dart to JavaScript '
+ 'compiler$suffix.';
+ return new jsAst.Comment(msg);
}
void outputSourceMap(CodeOutput output,

Powered by Google App Engine
This is Rietveld 408576698