Chromium Code Reviews| 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..5065c3d5a131517b5f60822221cc3b64be729c95 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,33 @@ 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) { |
| + print('generating output for typedef $typedef'); |
|
Johnni Winther
2014/08/04 13:49:52
Remove debug code.
|
| + 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 +1775,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 |