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