Chromium Code Reviews| Index: sdk/lib/_internal/compiler/implementation/js_emitter/old_emitter/emitter.dart |
| diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/old_emitter/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/old_emitter/emitter.dart |
| index f98d119d6afbb52b10dcee896982cf99fbad8a7a..a7a84e1258bb10874e0d0b02872c5ef60f1e6ea0 100644 |
| --- a/sdk/lib/_internal/compiler/implementation/js_emitter/old_emitter/emitter.dart |
| +++ b/sdk/lib/_internal/compiler/implementation/js_emitter/old_emitter/emitter.dart |
| @@ -83,22 +83,17 @@ class OldEmitter implements Emitter { |
| Map<OutputUnit, List<jsAst.Expression>> _cspPrecompiledConstructorNames = |
| new Map<OutputUnit, List<jsAst.Expression>>(); |
| - // True if Isolate.makeConstantList is needed. |
| - bool hasMakeConstantList = false; |
| - |
| /** |
| * Accumulate properties for classes and libraries, describing their |
| * static/top-level members. |
| * Later, these members are emitted when the class or library is emitted. |
| * |
| - * For supporting deferred loading we keep one list per output unit. |
| - * |
| - * See [getElementDecriptor]. |
| + * See [getElementDescriptor]. |
| */ |
| // TODO(ahe): Generate statics with their class, and store only libraries in |
| // this map. |
| - final Map<Element, Map<OutputUnit, ClassBuilder>> elementDescriptors |
| - = new Map<Element, Map<OutputUnit, ClassBuilder>>(); |
| + final Map<Element, ClassBuilder> elementDescriptors = |
| + new Map<Element, ClassBuilder>(); |
| final bool generateSourceMap; |
| @@ -581,7 +576,7 @@ class OldEmitter implements Emitter { |
| // isolateProperties themselves. |
| return js(''' |
| function (oldIsolate) { |
| - var isolateProperties = oldIsolate.#; |
| + var isolateProperties = oldIsolate.#; // isolatePropertiesName |
| function Isolate() { |
| var hasOwnProperty = Object.prototype.hasOwnProperty; |
| for (var staticName in isolateProperties) |
| @@ -613,16 +608,17 @@ class OldEmitter implements Emitter { |
| } |
| Isolate.prototype = oldIsolate.prototype; |
| Isolate.prototype.constructor = Isolate; |
| - Isolate.# = isolateProperties; |
| - if (#) |
| - Isolate.# = oldIsolate.#; |
| - if (#) |
| - Isolate.# = oldIsolate.#; |
| + Isolate.# = isolateProperties; // isolatePropertiesName |
|
Johnni Winther
2014/10/16 08:04:50
Maybe we should change [js] to take a map of argum
floitsch
2014/10/16 11:53:36
Thought the same thing.
I might look into this lat
|
| + if (#) // needsDefineClass. |
| + Isolate.# = oldIsolate.#; // finishClassesProperty * 2 |
| + if (#) // outputContainsConstantList |
| + Isolate.# = oldIsolate.#; // makeConstListProperty * 2 |
| return Isolate; |
| }''', |
| [namer.isolatePropertiesName, namer.isolatePropertiesName, |
| needsDefineClass, finishClassesProperty, finishClassesProperty, |
| - hasMakeConstantList, makeConstListProperty, makeConstListProperty ]); |
| + task.outputContainsConstantList, |
| + makeConstListProperty, makeConstListProperty ]); |
| } |
| jsAst.Fun get lazyInitializerFunction { |
| @@ -877,14 +873,8 @@ class OldEmitter implements Emitter { |
| } |
| } |
| - void emitStaticFunctions() { |
| - bool isStaticFunction(Element element) => |
| - !element.isInstanceMember && !element.isField; |
| - |
| - Iterable<Element> elements = |
| - backend.generatedCode.keys.where(isStaticFunction); |
| - |
| - for (Element element in Elements.sortedByPosition(elements)) { |
| + void emitStaticFunctions(List<Element> staticFunctions) { |
| + for (Element element in staticFunctions) { |
| ClassBuilder builder = new ClassBuilder(element, namer); |
| containerBuilder.addMember(element, builder); |
| getElementDescriptor(element).properties.addAll(builder.properties); |
| @@ -997,7 +987,6 @@ class OldEmitter implements Emitter { |
| cachedEmittedConstants.add(constant); |
| } |
| String name = namer.constantName(constant); |
| - if (constant.isList) emitMakeConstantListIfNotEmitted(buffer); |
| jsAst.Expression init = js('#.# = #', |
| [namer.globalObjectForConstant(constant), name, |
| constantInitializerExpression(constant)]); |
| @@ -1010,9 +999,7 @@ class OldEmitter implements Emitter { |
| } |
| } |
| - void emitMakeConstantListIfNotEmitted(CodeBuffer buffer) { |
| - if (hasMakeConstantList) return; |
| - hasMakeConstantList = true; |
| + void emitMakeConstantList(CodeBuffer buffer) { |
| buffer.write( |
| jsAst.prettyPrint( |
| js.statement(r'''#.# = function(list) { |
| @@ -1220,9 +1207,7 @@ class OldEmitter implements Emitter { |
| mainBuffer.add(N); |
| } |
| - void writeLibraryDescriptors( |
| - LibraryElement library, |
| - Map<OutputUnit, CodeBuffer> libraryDescriptorBuffers) { |
| + void writeLibraryDescriptors(CodeBuffer buffer, LibraryElement library) { |
| var uri = ""; |
| if (!compiler.enableMinification || backend.mustRetainUris) { |
| uri = library.canonicalUri; |
| @@ -1230,42 +1215,42 @@ class OldEmitter implements Emitter { |
| uri = relativize(compiler.outputUri, library.canonicalUri, false); |
| } |
| } |
| - Map<OutputUnit, ClassBuilder> descriptors = elementDescriptors[library]; |
| + ClassBuilder descriptor = elementDescriptors[library]; |
| + if (descriptor == null) { |
| + // Nothing of the library was emitted. |
| + // TODO(floitsch): this should not happen. We currently have an example |
| + // with language/prefix6_negative_test.dart where we have an instance |
| + // method without its corresponding class. |
| + return; |
| + } |
| + |
| String libraryName = |
| (!compiler.enableMinification || backend.mustRetainLibraryNames) ? |
| library.getLibraryName() : |
| ""; |
| - for (OutputUnit outputUnit in compiler.deferredLoadTask.allOutputUnits) { |
| - if (!descriptors.containsKey(outputUnit)) continue; |
| - |
| - ClassBuilder descriptor = descriptors[outputUnit]; |
| - |
| - jsAst.Fun metadata = metadataEmitter.buildMetadataFunction(library); |
| - |
| - jsAst.ObjectInitializer initializers = descriptor.toObjectInitializer(); |
| - |
| - CodeBuffer libraryDescriptorBuffer = |
| - libraryDescriptorBuffers.putIfAbsent(outputUnit, |
| - () => new CodeBuffer()); |
| - |
| - compiler.dumpInfoTask.registerElementAst(library, metadata); |
| - compiler.dumpInfoTask.registerElementAst(library, initializers); |
| - libraryDescriptorBuffer |
| - ..write('["$libraryName",$_') |
| - ..write('"${uri}",$_') |
| - ..write(metadata == null ? "" : jsAst.prettyPrint(metadata, |
| - compiler, |
| - monitor: compiler.dumpInfoTask)) |
| - ..write(',$_') |
| - ..write(namer.globalObjectFor(library)) |
| - ..write(',$_') |
| - ..write(jsAst.prettyPrint(initializers, |
| - compiler, |
| - monitor: compiler.dumpInfoTask)) |
| - ..write(library == compiler.mainApp ? ',${n}1' : "") |
| - ..write('],$n'); |
| - } |
| + jsAst.Fun metadata = metadataEmitter.buildMetadataFunction(library); |
| + |
| + jsAst.ObjectInitializer initializers = descriptor.toObjectInitializer(); |
| + |
| + CodeBuffer libraryDescriptorBuffer = buffer; |
|
Johnni Winther
2014/10/16 08:04:50
Remove and use [buffer] below.
floitsch
2014/10/16 11:53:36
Was to make diff easier. Wasn't really worth it...
|
| + |
| + compiler.dumpInfoTask.registerElementAst(library, metadata); |
| + compiler.dumpInfoTask.registerElementAst(library, initializers); |
| + libraryDescriptorBuffer |
| + ..write('["$libraryName",$_') |
| + ..write('"${uri}",$_') |
| + ..write(metadata == null ? "" : jsAst.prettyPrint(metadata, |
| + compiler, |
| + monitor: compiler.dumpInfoTask)) |
| + ..write(',$_') |
| + ..write(namer.globalObjectFor(library)) |
| + ..write(',$_') |
| + ..write(jsAst.prettyPrint(initializers, |
| + compiler, |
| + monitor: compiler.dumpInfoTask)) |
| + ..write(library == compiler.mainApp ? ',${n}1' : "") |
| + ..write('],$n'); |
| } |
| void emitPrecompiledConstructor(OutputUnit outputUnit, |
| @@ -1309,13 +1294,122 @@ class OldEmitter implements Emitter { |
| } |
| } |
| - void emitProgram(Program program) { |
| - bool isProgramSplit = compiler.deferredLoadTask.isProgramSplit; |
| - // Maps each output unit to a codebuffers with the library descriptors of |
| - // the output unit emitted to it. |
| - Map<OutputUnit, CodeBuffer> libraryDescriptorBuffers = |
| - new Map<OutputUnit, CodeBuffer>(); |
| + void emitLibraries(Iterable<LibraryElement> libraries) { |
| + if (libraries.isEmpty) return; |
| + |
| + // TODO(karlklose): document what kinds of fields this loop adds to the |
| + // library class builder. |
| + for (LibraryElement element in libraries) { |
| + LibraryElement library = element; |
| + ClassBuilder builder = new ClassBuilder(library, namer); |
| + if (classEmitter.emitFields( |
| + library, builder, null, emitStatics: true)) { |
| + jsAst.ObjectInitializer initializer = |
| + builder.toObjectInitializer(); |
|
Johnni Winther
2014/10/16 08:04:50
Indent by 4.
floitsch
2014/10/16 11:53:36
All the statements here actually fit on one line.
|
| + compiler.dumpInfoTask.registerElementAst(builder.element, |
| + initializer); |
| + getElementDescriptor(library) |
| + .properties.addAll(initializer.properties); |
| + } |
| + } |
| + } |
| + |
| + void emitTypedefs() { |
| + OutputUnit mainOutputUnit = compiler.deferredLoadTask.mainOutputUnit; |
| + |
| + // Emit all required typedef declarations into the main output unit. |
| + // TODO(karlklose): unify required classes and typedefs to declarations |
| + // and have builders for each kind. |
| + for (TypedefElement typedef in typedefsNeededForReflection) { |
| + OutputUnit mainUnit = compiler.deferredLoadTask.mainOutputUnit; |
| + LibraryElement library = typedef.library; |
| + // TODO(karlklose): add a TypedefBuilder and move this code there. |
| + DartType type = typedef.alias; |
| + int typeIndex = metadataEmitter.reifyType(type); |
| + String typeReference = |
| + encoding.encodeTypedefFieldDescriptor(typeIndex); |
| + jsAst.Property descriptor = new jsAst.Property( |
| + js.string(namer.classDescriptorProperty), |
| + js.string(typeReference)); |
| + jsAst.Node declaration = new jsAst.ObjectInitializer([descriptor]); |
| + String mangledName = namer.getNameX(typedef); |
| + String reflectionName = getReflectionName(typedef, mangledName); |
| + getElementDescriptor(library) |
| + ..addProperty(mangledName, declaration) |
| + ..addProperty("+$reflectionName", js.string('')); |
| + // Also emit a trivial constructor for CSP mode. |
| + String constructorName = mangledName; |
| + jsAst.Expression constructorAst = js('function() {}'); |
| + emitPrecompiledConstructor(mainOutputUnit, |
| + constructorName, |
| + constructorAst); |
| + } |
| + } |
| + |
| + void emitMangledNames() { |
| + if (!mangledFieldNames.isEmpty) { |
| + var keys = mangledFieldNames.keys.toList(); |
| + keys.sort(); |
| + var properties = []; |
| + for (String key in keys) { |
| + var value = js.string('${mangledFieldNames[key]}'); |
| + properties.add(new jsAst.Property(js.string(key), value)); |
| + } |
| + |
| + jsAst.Expression mangledNamesAccess = |
| + generateEmbeddedGlobalAccess(embeddedNames.MANGLED_NAMES); |
| + var map = new jsAst.ObjectInitializer(properties); |
| + mainBuffer.write( |
| + jsAst.prettyPrint( |
| + js.statement('# = #', [mangledNamesAccess, map]), |
| + compiler, |
| + monitor: compiler.dumpInfoTask)); |
| + if (compiler.enableMinification) { |
| + mainBuffer.write(';'); |
| + } |
| + } |
| + if (!mangledGlobalFieldNames.isEmpty) { |
| + var keys = mangledGlobalFieldNames.keys.toList(); |
| + keys.sort(); |
| + var properties = []; |
| + for (String key in keys) { |
| + var value = js.string('${mangledGlobalFieldNames[key]}'); |
| + properties.add(new jsAst.Property(js.string(key), value)); |
| + } |
| + jsAst.Expression mangledGlobalNamesAccess = |
| + generateEmbeddedGlobalAccess(embeddedNames.MANGLED_GLOBAL_NAMES); |
| + var map = new jsAst.ObjectInitializer(properties); |
| + mainBuffer.write( |
| + jsAst.prettyPrint( |
| + js.statement('# = #', [mangledGlobalNamesAccess, map]), |
| + compiler, |
| + monitor: compiler.dumpInfoTask)); |
| + if (compiler.enableMinification) { |
| + mainBuffer.write(';'); |
| + } |
| + } |
| + } |
| + |
| + void checkEverythingEmitted(Iterable<Element> elements) { |
| + List<Element> pendingStatics; |
| + if (!compiler.hasIncrementalSupport) { |
| + pendingStatics = |
| + Elements.sortedByPosition(elements.where((e) => !e.isLibrary)); |
| + pendingStatics.forEach((element) => |
| + compiler.reportInfo( |
| + element, MessageKind.GENERIC, {'text': 'Pending statics.'})); |
| + } |
| + |
| + if (pendingStatics != null && !pendingStatics.isEmpty) { |
| + compiler.internalError(pendingStatics.first, |
| + 'Pending statics (see above).'); |
| + } |
| + } |
| + |
| + void emitMainOutputUnit(Map<OutputUnit, String> deferredLoadHashes, |
| + CodeBuffer nativeBuffer) { |
| + bool isProgramSplit = compiler.deferredLoadTask.isProgramSplit; |
| OutputUnit mainOutputUnit = compiler.deferredLoadTask.mainOutputUnit; |
| mainBuffer.add(buildGeneratedBy()); |
| @@ -1370,169 +1464,51 @@ class OldEmitter implements Emitter { |
| '${globalsHolder}.$initName$_=${_}$initName$N'); |
| } |
| mainBuffer.add('init()$N$n'); |
| - // Shorten the code by using [namer.currentIsolate] as temporary. |
| - isolateProperties = namer.currentIsolate; |
| - mainBuffer.add( |
| - '$isolateProperties$_=$_$isolatePropertiesName$N'); |
| + mainBuffer.add('$isolateProperties$_=$_$isolatePropertiesName$N'); |
| - emitStaticFunctions(); |
| + emitStaticFunctions(task.outputStaticLists[mainOutputUnit]); |
| // Only output the classesCollector if we actually have any classes. |
| if (!(nativeClasses.isEmpty && |
| compiler.codegenWorld.staticFunctionsNeedingGetter.isEmpty && |
| - outputClassLists.values.every((classList) => classList.isEmpty) && |
| - typedefsNeededForReflection.isEmpty)) { |
| + outputClassLists.values.every((classList) => classList.isEmpty) && |
| + typedefsNeededForReflection.isEmpty)) { |
| // Shorten the code by using "$$" as temporary. |
| classesCollector = r"$$"; |
| mainBuffer.add('var $classesCollector$_=${_}Object.create(null)$N$n'); |
| } |
| - // Emit native classes on [nativeBuffer]. |
| - final CodeBuffer nativeBuffer = new CodeBuffer(); |
| if (!nativeClasses.isEmpty) { |
| - addComment('Native classes', nativeBuffer); |
| addComment('Native classes', mainBuffer); |
| - nativeEmitter.generateNativeClasses(nativeClasses, mainBuffer, |
| - additionalProperties); |
| } |
| - for (List<ClassElement> outputClassList in outputClassLists.values) { |
| - for (ClassElement element in outputClassList) { |
| + List<ClassElement> classes = task.outputClassLists[mainOutputUnit]; |
| + if (classes != null) { |
| + for (ClassElement element in classes) { |
| generateClass(element, getElementDescriptor(element)); |
| } |
| } |
| - nativeEmitter.finishGenerateNativeClasses(); |
| - nativeEmitter.assembleCode(nativeBuffer); |
| - |
| - |
| - // After this assignment we will produce invalid JavaScript code if we use |
| - // the classesCollector variable. |
| - classesCollector = 'classesCollector should not be used from now on'; |
| - |
| - // TODO(sigurdm): Need to check this for each outputUnit. |
| - if (!elementDescriptors.isEmpty) { |
| - var oldClassesCollector = classesCollector; |
| - classesCollector = r"$$"; |
| - if (compiler.enableMinification) { |
| - mainBuffer.write(';'); |
| - } |
| - |
| - // TODO(karlklose): document what kinds of fields this loop adds to the |
| - // library class builder. |
| - for (Element element in elementDescriptors.keys) { |
| - // TODO(ahe): Should iterate over all libraries. Otherwise, we will |
| - // not see libraries that only have fields. |
| - if (element.isLibrary) { |
| - LibraryElement library = element; |
| - ClassBuilder builder = new ClassBuilder(library, namer); |
| - if (classEmitter.emitFields( |
| - library, builder, null, emitStatics: true)) { |
| - jsAst.ObjectInitializer initializer = |
| - builder.toObjectInitializer(); |
| - compiler.dumpInfoTask.registerElementAst(builder.element, |
| - initializer); |
| - getElementDescriptor(library) |
| - .properties.addAll(initializer.properties); |
| - } |
| - } |
| - } |
| - |
| - // Emit all required typedef declarations into the main output unit. |
| - // TODO(karlklose): unify required classes and typedefs to declarations |
| - // and have builders for each kind. |
| - for (TypedefElement typedef in typedefsNeededForReflection) { |
| - OutputUnit mainUnit = compiler.deferredLoadTask.mainOutputUnit; |
| - LibraryElement library = typedef.library; |
| - // TODO(karlklose): add a TypedefBuilder and move this code there. |
| - DartType type = typedef.alias; |
| - int typeIndex = metadataEmitter.reifyType(type); |
| - String typeReference = |
| - encoding.encodeTypedefFieldDescriptor(typeIndex); |
| - jsAst.Property descriptor = new jsAst.Property( |
| - js.string(namer.classDescriptorProperty), |
| - js.string(typeReference)); |
| - jsAst.Node declaration = new jsAst.ObjectInitializer([descriptor]); |
| - String mangledName = namer.getNameX(typedef); |
| - String reflectionName = getReflectionName(typedef, mangledName); |
| - getElementDescriptor(library) |
| - ..addProperty(mangledName, declaration) |
| - ..addProperty("+$reflectionName", js.string('')); |
| - // Also emit a trivial constructor for CSP mode. |
| - String constructorName = mangledName; |
| - jsAst.Expression constructorAst = js('function() {}'); |
| - emitPrecompiledConstructor(mainOutputUnit, |
| - constructorName, |
| - constructorAst); |
| - } |
| - |
| - if (!mangledFieldNames.isEmpty) { |
| - var keys = mangledFieldNames.keys.toList(); |
| - keys.sort(); |
| - var properties = []; |
| - for (String key in keys) { |
| - var value = js.string('${mangledFieldNames[key]}'); |
| - properties.add(new jsAst.Property(js.string(key), value)); |
| - } |
| - |
| - jsAst.Expression mangledNamesAccess = |
| - generateEmbeddedGlobalAccess(embeddedNames.MANGLED_NAMES); |
| - var map = new jsAst.ObjectInitializer(properties); |
| - mainBuffer.write( |
| - jsAst.prettyPrint( |
| - js.statement('# = #', [mangledNamesAccess, map]), |
| - compiler, |
| - monitor: compiler.dumpInfoTask)); |
| - if (compiler.enableMinification) { |
| - mainBuffer.write(';'); |
| - } |
| - } |
| - if (!mangledGlobalFieldNames.isEmpty) { |
| - var keys = mangledGlobalFieldNames.keys.toList(); |
| - keys.sort(); |
| - var properties = []; |
| - for (String key in keys) { |
| - var value = js.string('${mangledGlobalFieldNames[key]}'); |
| - properties.add(new jsAst.Property(js.string(key), value)); |
| - } |
| - jsAst.Expression mangledGlobalNamesAccess = |
| - generateEmbeddedGlobalAccess(embeddedNames.MANGLED_GLOBAL_NAMES); |
| - var map = new jsAst.ObjectInitializer(properties); |
| - mainBuffer.write( |
| - jsAst.prettyPrint( |
| - js.statement('# = #', [mangledGlobalNamesAccess, map]), |
| - compiler, |
| - monitor: compiler.dumpInfoTask)); |
| - if (compiler.enableMinification) { |
| - mainBuffer.write(';'); |
| - } |
| - } |
| + if (compiler.enableMinification) { |
| + mainBuffer.write(';'); |
| + } |
| - List<Element> sortedElements = |
| - Elements.sortedByPosition(elementDescriptors.keys); |
| + if (elementDescriptors.isNotEmpty) { |
| + Iterable<LibraryElement> libraries = |
| + task.outputLibraryLists[mainOutputUnit]; |
| + if (libraries == null) libraries = []; |
| + emitLibraries(libraries); |
| + emitTypedefs(); |
| + emitMangledNames(); |
| - Iterable<Element> pendingStatics; |
| - if (!compiler.hasIncrementalSupport) { |
| - pendingStatics = sortedElements.where((element) { |
| - return !element.isLibrary && |
| - elementDescriptors[element].values.any((descriptor) => |
| - descriptor != null); |
| - }); |
| + checkEverythingEmitted(elementDescriptors.keys); |
| - pendingStatics.forEach((element) => |
| - compiler.reportInfo( |
| - element, MessageKind.GENERIC, {'text': 'Pending statics.'})); |
| + CodeBuffer libraryBuffer = new CodeBuffer(); |
| + for (LibraryElement library in Elements.sortedByPosition(libraries)) { |
| + writeLibraryDescriptors(libraryBuffer, library); |
| + elementDescriptors.remove(library); |
| } |
| - for (LibraryElement library in sortedElements.where((element) => |
| - element.isLibrary)) { |
| - writeLibraryDescriptors(library, libraryDescriptorBuffers); |
| - elementDescriptors[library] = const {}; |
| - } |
| - if (pendingStatics != null && !pendingStatics.isEmpty) { |
| - compiler.internalError(pendingStatics.first, |
| - 'Pending statics (see above).'); |
| - } |
| mainBuffer |
| ..write('(') |
| ..write( |
| @@ -1541,30 +1517,27 @@ class OldEmitter implements Emitter { |
| compiler)) |
| ..write(')') |
| ..write('([$n') |
| - ..add(libraryDescriptorBuffers[mainOutputUnit]) |
| + ..add(libraryBuffer) |
| ..write('])$N'); |
| emitFinishClassesInvocationIfNecessary(mainBuffer); |
| - classesCollector = oldClassesCollector; |
| } |
| + |
| typeTestEmitter.emitRuntimeTypeSupport(mainBuffer, mainOutputUnit); |
| interceptorEmitter.emitGetInterceptorMethods(mainBuffer); |
| interceptorEmitter.emitOneShotInterceptors(mainBuffer); |
| + |
| + if (task.outputContainsConstantList) { |
| + emitMakeConstantList(mainBuffer); |
| + } |
| + |
| // 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(mainBuffer, mainOutputUnit); |
| - if (isProgramSplit) { |
| - /// Map from OutputUnit to a hash of its content. The hash uniquely |
| - /// identifies the code of the output-unit. It does not include |
| - /// boilerplate JS code, like the sourcemap directives or the hash |
| - /// itself. |
| - Map<OutputUnit, String> deferredLoadHashes = |
| - emitDeferredCode(libraryDescriptorBuffers); |
| - emitDeferredBoilerPlate(mainBuffer, deferredLoadHashes); |
| - } |
| + emitDeferredBoilerPlate(mainBuffer, deferredLoadHashes); |
| // Static field initializations require the classes and compile-time |
| // constants to be set up. |
| @@ -1573,6 +1546,7 @@ class OldEmitter implements Emitter { |
| interceptorEmitter.emitMapTypeToInterceptor(mainBuffer); |
| emitLazilyInitializedStaticFields(mainBuffer); |
| + mainBuffer.writeln(); |
| mainBuffer.add(nativeBuffer); |
| metadataEmitter.emitMetadata(mainBuffer); |
| @@ -1686,6 +1660,83 @@ class OldEmitter implements Emitter { |
| ..add(cspBuffer.getText()) |
| ..close(); |
| } |
| + } |
| + |
| + /// Returns a map from OutputUnit to a hash of its content. The hash uniquely |
| + /// identifies the code of the output-unit. It does not include |
| + /// boilerplate JS code, like the sourcemap directives or the hash |
| + /// itself. |
| + Map<OutputUnit, String> emitDeferredOutputUnits() { |
| + if (!compiler.deferredLoadTask.isProgramSplit) return const {}; |
| + |
| + Map<OutputUnit, CodeBuffer> outputBuffers = |
| + new Map<OutputUnit, CodeBuffer>(); |
| + |
| + for (OutputUnit outputUnit in compiler.deferredLoadTask.allOutputUnits) { |
| + if (outputUnit == compiler.deferredLoadTask.mainOutputUnit) continue; |
| + |
| + List<Element> functions = task.outputStaticLists[outputUnit]; |
| + if (functions != null) { |
| + emitStaticFunctions(functions); |
| + } |
| + |
| + List<ClassElement> classes = task.outputClassLists[outputUnit]; |
| + if (classes != null) { |
| + for (ClassElement element in classes) { |
| + generateClass(element, getElementDescriptor(element)); |
| + } |
| + } |
| + |
| + if (elementDescriptors.isNotEmpty) { |
| + Iterable<LibraryElement> libraries = |
| + task.outputLibraryLists[outputUnit]; |
| + if (libraries == null) libraries = []; |
| + emitLibraries(libraries); |
| + |
| + CodeBuffer buffer = new CodeBuffer(); |
| + outputBuffers[outputUnit] = buffer; |
| + for (LibraryElement library in Elements.sortedByPosition(libraries)) { |
| + writeLibraryDescriptors(buffer, library); |
| + elementDescriptors.remove(library); |
| + } |
| + } |
| + } |
| + |
| + return emitDeferredCode(outputBuffers); |
| + } |
| + |
| + CodeBuffer buildNativesBuffer() { |
| + // Emit native classes on [nativeBuffer]. |
| + final CodeBuffer nativeBuffer = new CodeBuffer(); |
| + |
| + if (nativeClasses.isEmpty) return nativeBuffer; |
| + |
| + |
| + addComment('Native classes', nativeBuffer); |
| + |
| + nativeEmitter.generateNativeClasses(nativeClasses, mainBuffer, |
| + additionalProperties); |
| + |
| + nativeEmitter.finishGenerateNativeClasses(); |
| + nativeEmitter.assembleCode(nativeBuffer); |
| + |
| + return nativeBuffer; |
| + } |
| + |
| + void emitProgram(Program program) { |
| + // Shorten the code by using [namer.currentIsolate] as temporary. |
| + isolateProperties = namer.currentIsolate; |
| + |
| + classesCollector = r"$$"; |
| + |
| + // 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 |
| + // boilerplate JS code, like the sourcemap directives or the hash |
| + // itself. |
| + Map<OutputUnit, String> deferredLoadHashes = emitDeferredOutputUnits(); |
| + CodeBuffer nativeBuffer = buildNativesBuffer(); |
| + emitMainOutputUnit(deferredLoadHashes, nativeBuffer); |
| if (backend.requiresPreamble && |
| !backend.htmlLibraryIsLoaded) { |
| @@ -1704,15 +1755,6 @@ class OldEmitter implements Emitter { |
| return ''; |
| } |
| - ClassBuilder getElementDescriptorForOutputUnit(Element element, |
| - OutputUnit outputUnit) { |
| - Map<OutputUnit, ClassBuilder> descriptors = |
| - elementDescriptors.putIfAbsent( |
| - element, () => new Map<OutputUnit, ClassBuilder>()); |
| - return descriptors.putIfAbsent(outputUnit, |
| - () => new ClassBuilder(element, namer)); |
| - } |
| - |
| ClassBuilder getElementDescriptor(Element element) { |
| Element owner = element.library; |
| if (!element.isLibrary && !element.isTopLevel && !element.isNative) { |
| @@ -1729,8 +1771,9 @@ class OldEmitter implements Emitter { |
| if (owner == null) { |
| compiler.internalError(element, 'Owner is null.'); |
| } |
| - return getElementDescriptorForOutputUnit(owner, |
| - compiler.deferredLoadTask.outputUnitForElement(element)); |
| + return elementDescriptors.putIfAbsent( |
| + owner, |
| + () => new ClassBuilder(owner, namer)); |
| } |
| /// Emits support-code for deferred loading into [buffer]. |
| @@ -1802,20 +1845,17 @@ class OldEmitter implements Emitter { |
| /// Returns a mapping from outputUnit to a hash of the corresponding hunk that |
| /// can be used for calling the initializer. |
| Map<OutputUnit, String> emitDeferredCode( |
| - Map<OutputUnit, CodeBuffer> libraryDescriptorBuffers) { |
| + Map<OutputUnit, CodeBuffer> deferredBuffers) { |
| Map<OutputUnit, String> hunkHashes = new Map<OutputUnit, String>(); |
| for (OutputUnit outputUnit in compiler.deferredLoadTask.allOutputUnits) { |
| if (outputUnit == compiler.deferredLoadTask.mainOutputUnit) continue; |
| - CodeBuffer libraryDescriptorBuffer = libraryDescriptorBuffers[outputUnit]; |
| + CodeBuffer libraryDescriptorBuffer = deferredBuffers[outputUnit]; |
| CodeBuffer outputBuffer = new CodeBuffer(); |
| - var oldClassesCollector = classesCollector; |
| - classesCollector = r"$$"; |
| - |
| outputBuffer..write(buildGeneratedBy()) |
| ..write('${deferredInitializers}.current$_=$_' |
| 'function$_(${globalsHolder}) {$N'); |
| @@ -1855,8 +1895,6 @@ class OldEmitter implements Emitter { |
| } |
| - classesCollector = oldClassesCollector; |
| - |
| // 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 |