Chromium Code Reviews| 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..1b96b8711b5e71bb11b2e25c96105cc0e1e59c13 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,17 @@ 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) { |
| + return js.statement('${namer.currentIsolate}.# = #', |
|
floitsch
2015/05/19 13:43:35
I don't like this.
It is true, that the isolatePro
herhut
2015/05/19 14:08:09
But I can no longer do the magic "from here on we
floitsch
2015/05/19 14:15:28
No it's not clear. This code says: "store the init
floitsch
2015/05/19 14:16:50
Also: it doesn't matter when things are instantiat
|
| + [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 +537,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 +550,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 +596,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 +663,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 +678,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 +703,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,30 +722,27 @@ 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.namer.currentIsolate, |
| + backend.rti.getFunctionThatReturnsNullName]); |
| } |
| jsAst.Expression generateFunctionThatReturnsNull() { |
| @@ -776,28 +750,27 @@ class OldEmitter implements Emitter { |
| 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 +786,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 +807,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 +906,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 +924,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 +934,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 +945,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 +966,7 @@ class OldEmitter implements Emitter { |
| '''); |
| } |
| - output.addBuffer(jsAst.prettyPrint(supportsDirectProtoAccess, compiler)); |
| - output.add(N); |
| + return supportsDirectProtoAccess; |
| } |
| jsAst.Expression generateLibraryDescriptor(LibraryElement library, |
| @@ -1046,7 +1006,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 +1092,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 +1193,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 +1207,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 +1272,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'); |
| - } |
| - |
| - // 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'); |
| + statements.add( |
| + js.statement('self.#deferredInitializers = ' |
| + 'self.#deferredInitializers || Object.create(null);', |
| + {'deferredInitializers': deferredInitializers})); |
| } |
| - 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 +1306,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 +1322,163 @@ 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(); |
| + |
| + var ${namer.currentIsolate} = #isolatePropertiesName; |
| + |
| + #functionThatReturnsNull; |
| + |
| + #mangledNames; |
| + |
| + #setupProgram; |
| + |
| + // 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; |
| + |
| + // 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; |
| + |
| + #deferredBoilerPlate; |
| + |
| + #typeToInterceptorMap; |
| + |
| + #lazyStaticFields; |
| + |
| + ${namer.currentIsolate} = null; |
| + |
| + #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 +1495,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 +1528,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 +1649,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 +1701,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 +1730,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 +1765,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,21 +1807,21 @@ 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) { |
| @@ -1822,34 +1829,24 @@ function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) { |
| // 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') |
| + body..add(js.statement('var ${namer.currentIsolate} = ' |
| + '$isolatePropertiesName;')) |
| // 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'); |
| + ..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 |
| @@ -1861,23 +1858,34 @@ function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) { |
| // 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"); |
| + 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>[]; |
| - emitCompileTimeConstants( |
| - output, fragment.constants, isMainFragment: false); |
| - emitStaticNonFinalFieldInitializations(output, outputUnit); |
| + statements..add(buildGeneratedBy()) |
| + ..add(js.statement('${deferredInitializers}.current = ' |
| + """function (${globalsHolder}) { |
| + # |
| + } |
| + """, [body])); |
| + |
| + output.addBuffer(jsAst.prettyPrint(new jsAst.Program(statements), |
| + compiler, |
| + monitor: compiler.dumpInfoTask)); |
| - output.add('}$N'); |
| // 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 +1919,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, |