| Index: sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
|
| index b1dbdc374d49a83732eab23b100552a4eb277118..41b74735eeacf7362c9511096c590b4d34d35930 100644
|
| --- a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
|
| +++ b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
|
| @@ -55,6 +55,8 @@ class CodeEmitterTask extends CompilerTask {
|
| // TODO(ngeoffray): remove this field.
|
| Set<ClassElement> instantiatedClasses;
|
|
|
| + List<TypedefElement> typedefsNeededForReflection;
|
| +
|
| JavaScriptBackend get backend => compiler.backend;
|
| TypeVariableHandler get typeVariableHandler => backend.typeVariableHandler;
|
|
|
| @@ -63,9 +65,12 @@ class CodeEmitterTask extends CompilerTask {
|
| String get n => compiler.enableMinification ? "" : "\n";
|
| String get N => compiler.enableMinification ? "\n" : ";\n";
|
|
|
| + CodeBuffer getBuffer(OutputUnit outputUnit) {
|
| + return outputBuffers.putIfAbsent(outputUnit, () => new CodeBuffer());
|
| + }
|
| +
|
| CodeBuffer get mainBuffer {
|
| - return outputBuffers.putIfAbsent(compiler.deferredLoadTask.mainOutputUnit,
|
| - () => new CodeBuffer());
|
| + return getBuffer(compiler.deferredLoadTask.mainOutputUnit);
|
| }
|
|
|
| /**
|
| @@ -752,6 +757,8 @@ class CodeEmitterTask extends CompilerTask {
|
| ClassElement cls = element;
|
| if (cls.isUnnamedMixinApplication) return null;
|
| return cls.name;
|
| + } else if (element.isTypedef) {
|
| + return element.name;
|
| }
|
| throw compiler.internalError(element,
|
| 'Do not know how to reflect on this $element.');
|
| @@ -861,7 +868,7 @@ class CodeEmitterTask extends CompilerTask {
|
| for (Element element in Elements.sortedByPosition(elements)) {
|
| ClassBuilder builder = new ClassBuilder(element, namer);
|
| containerBuilder.addMember(element, builder);
|
| - getElementDecriptor(element).properties.addAll(builder.properties);
|
| + getElementDescriptor(element).properties.addAll(builder.properties);
|
| }
|
| }
|
|
|
| @@ -1149,10 +1156,15 @@ class CodeEmitterTask extends CompilerTask {
|
| }
|
| }
|
|
|
| - /**
|
| - * Compute all the classes that must be emitted.
|
| - */
|
| - void computeNeededClasses() {
|
| + /// Compute all the classes and typedefs that must be emitted.
|
| + void computeNeededDeclarations() {
|
| + // Compute needed typedefs.
|
| + typedefsNeededForReflection = Elements.sortedByPosition(
|
| + compiler.world.allTypedefs
|
| + .where(backend.isAccessibleByReflection)
|
| + .toList());
|
| +
|
| + // Compute needed classes.
|
| instantiatedClasses =
|
| compiler.codegenWorld.instantiatedClasses.where(computeClassFilter())
|
| .toSet();
|
| @@ -1311,26 +1323,21 @@ class CodeEmitterTask extends CompilerTask {
|
| uri = relativize(compiler.outputUri, library.canonicalUri, false);
|
| }
|
| }
|
| + Map<OutputUnit, ClassBuilder> descriptors = elementDescriptors[library];
|
| String libraryName =
|
| (!compiler.enableMinification || backend.mustRetainLibraryNames) ?
|
| library.getLibraryName() :
|
| "";
|
| - Map<OutputUnit, ClassBuilder> descriptors =
|
| - elementDescriptors[library];
|
|
|
| for (OutputUnit outputUnit in compiler.deferredLoadTask.allOutputUnits) {
|
| - ClassBuilder descriptor =
|
| - descriptors.putIfAbsent(outputUnit,
|
| - () => new ClassBuilder(library, namer));
|
| - if (descriptor.properties.isEmpty) continue;
|
| - bool isDeferred =
|
| - outputUnit != compiler.deferredLoadTask.mainOutputUnit;
|
| + if (!descriptors.containsKey(outputUnit)) continue;
|
| +
|
| + ClassBuilder descriptor = descriptors[outputUnit];
|
| jsAst.Fun metadata = metadataEmitter.buildMetadataFunction(library);
|
|
|
| - jsAst.ObjectInitializer initializers =
|
| - descriptor.toObjectInitializer();
|
| - CodeBuffer outputBuffer =
|
| - outputBuffers.putIfAbsent(outputUnit, () => new CodeBuffer());
|
| + jsAst.ObjectInitializer initializers = descriptor.toObjectInitializer();
|
| + CodeBuffer outputBuffer = getBuffer(outputUnit);
|
| +
|
| int sizeBefore = outputBuffer.length;
|
| compiler.dumpInfoTask.registerElementAst(library, metadata);
|
| compiler.dumpInfoTask.registerElementAst(library, initializers);
|
| @@ -1352,6 +1359,30 @@ class CodeEmitterTask extends CompilerTask {
|
| }
|
| }
|
|
|
| + void emitPrecompiledConstructor(String constructorName,
|
| + jsAst.Expression constructorAst) {
|
| + precompiledFunction.add(
|
| + new jsAst.FunctionDeclaration(
|
| + new jsAst.VariableDeclaration(constructorName), constructorAst));
|
| + precompiledFunction.add(
|
| + js.statement(r'''{
|
| + #.builtin$cls = #;
|
| + if (!"name" in #)
|
| + #.name = #;
|
| + $desc=$collectedClasses.#;
|
| + if ($desc instanceof Array) $desc = $desc[1];
|
| + #.prototype = $desc;
|
| + }''',
|
| + [ constructorName, js.string(constructorName),
|
| + constructorName,
|
| + constructorName, js.string(constructorName),
|
| + constructorName,
|
| + constructorName
|
| + ]));
|
| +
|
| + precompiledConstructorNames.add(js('#', constructorName));
|
| + }
|
| +
|
| String assembleProgram() {
|
| measure(() {
|
| invalidateCaches();
|
| @@ -1360,7 +1391,7 @@ class CodeEmitterTask extends CompilerTask {
|
| // 'is$' method.
|
| typeTestEmitter.computeRequiredTypeChecks();
|
|
|
| - computeNeededClasses();
|
| + computeNeededDeclarations();
|
|
|
| mainBuffer.add(buildGeneratedBy());
|
| addComment(HOOKS_API_USAGE, mainBuffer);
|
| @@ -1395,7 +1426,8 @@ class CodeEmitterTask extends CompilerTask {
|
| // Only output the classesCollector if we actually have any classes.
|
| if (!(nativeClasses.isEmpty &&
|
| compiler.codegenWorld.staticFunctionsNeedingGetter.isEmpty &&
|
| - outputClassLists.values.every((classList) => classList.isEmpty))) {
|
| + outputClassLists.values.every((classList) => classList.isEmpty) &&
|
| + typedefsNeededForReflection.isEmpty)) {
|
| // Shorten the code by using "$$" as temporary.
|
| classesCollector = r"$$";
|
| mainBuffer.add('var $classesCollector$_=$_{}$N$n');
|
| @@ -1419,7 +1451,7 @@ class CodeEmitterTask extends CompilerTask {
|
| // Might create methodClosures.
|
| for (List<ClassElement> outputClassList in outputClassLists.values) {
|
| for (ClassElement element in outputClassList) {
|
| - generateClass(element, getElementDecriptor(element));
|
| + generateClass(element, getElementDescriptor(element));
|
| }
|
| }
|
|
|
| @@ -1439,6 +1471,8 @@ class CodeEmitterTask extends CompilerTask {
|
| 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.
|
| @@ -1458,6 +1492,32 @@ class CodeEmitterTask extends CompilerTask {
|
| }
|
| }
|
|
|
| + // 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);
|
| + getElementDescriptorForOutputUnit(library, mainUnit)
|
| + ..addProperty(mangledName, declaration)
|
| + ..addProperty("+$reflectionName", js.string(''));
|
| + // Also emit a trivial constructor for CSP mode.
|
| + String constructorName = mangledName;
|
| + jsAst.Expression constructorAst = js('function() {}');
|
| + emitPrecompiledConstructor(constructorName, constructorAst);
|
| + }
|
| +
|
| if (!mangledFieldNames.isEmpty) {
|
| var keys = mangledFieldNames.keys.toList();
|
| keys.sort();
|
| @@ -1714,7 +1774,7 @@ class CodeEmitterTask extends CompilerTask {
|
| () => new ClassBuilder(element, namer));
|
| }
|
|
|
| - ClassBuilder getElementDecriptor(Element element) {
|
| + ClassBuilder getElementDescriptor(Element element) {
|
| Element owner = element.library;
|
| if (!element.isTopLevel && !element.isNative) {
|
| // For static (not top level) elements, record their code in a buffer
|
|
|