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, |