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 |