Index: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
index 58debdba0858b1686abc9702ca6cd7ce12610569..3a7f5ee8cb7db248b0ad276b40084d9335d64f3f 100644 |
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
@@ -48,6 +48,9 @@ class CodeEmitterTask extends CompilerTask { |
// TODO(ngeoffray): remove this field. |
Set<ClassElement> instantiatedClasses; |
+ List<js.Expression> libraryMirrorsParametersList; |
+ Map<String, int> libraryMirrorsIndices; |
+ |
String get _ => compiler.enableMinification ? "" : " "; |
String get n => compiler.enableMinification ? "" : "\n"; |
String get N => compiler.enableMinification ? "\n" : ";\n"; |
@@ -1030,6 +1033,16 @@ $lazyInitializerLogic |
}); |
} |
+ void emitClassLibraryGetter(ClassElement classElement, CodeBuffer buffer) { |
+ var name = classElement.getLibrary().getLibraryOrScriptName(); |
+ // Some builtin classes come from js_helper libraries, which are |
+ // not in libraryMirrorsIndices collection. At this point we |
+ // will ignore them. |
+ if (libraryMirrorsIndices.containsKey(name)) { |
+ buffer.add(",$n$_${_}builtin\$library:$_${libraryMirrorsIndices[name]}"); |
+ } |
+ } |
+ |
/** |
* Documentation wanted -- johnniwinther |
* |
@@ -1065,6 +1078,9 @@ $lazyInitializerLogic |
// syntax. |
emitClassGettersSetters(classElement, buffer, true); |
emitInstanceMembers(classElement, buffer, true); |
+ if (compiler.hasMirrorsSupport()) { |
+ emitClassLibraryGetter(classElement, buffer); |
+ } |
buffer.add('$n}$N$n'); |
} |
@@ -2107,9 +2123,194 @@ if (typeof document !== 'undefined' && document.readyState !== 'complete') { |
} |
} |
+ Collection<js.Expression> extract(listElements, filterToApply) { |
+ return new js.ArrayInitializer.from( |
+ listElements |
+ .filter(filterToApply) |
+ .map((member) => js.string(namer.getName(member)))); |
+ } |
+ |
+ Collection extractClasses(listElements) { |
+ var classDescriptions = []; |
+ var classes = listElements.filter((e) => Elements.isClass(e)); |
+ for (Element classElement in classes) { |
+ var classMembers = []; |
+ for (var classMember in classElement.localMembers) { |
+ var prefixType; |
+ var name; |
+ if (classMember.isGetter()) { |
+ prefixType = 'G'; |
+ name = qualifiedFunctionName(classMember); |
+ } else if (classMember.isSetter()) { |
+ prefixType = 'S'; |
+ name = qualifiedFunctionName(classMember); |
+ } else if (classMember.isField()) { |
+ prefixType = 'V'; |
+ name = qualifiedVariableName(classMember); |
+ } else if (classMember.isConstructor()) { |
+ prefixType = 'C'; |
+ name = namer.getName(classMember); |
+ } else if (classMember.isTypeVariable()) { |
+ prefixType = 'T'; |
+ name = namer.getName(classMember); |
+ } else if (classMember.isParameter()) { |
+ prefixType = 'A'; |
+ name = namer.getName(classMember); |
+ } else { |
+ prefixType = 'M'; |
+ name = qualifiedFunctionName(classMember); |
+ } |
+ var originalName = classMember.name.slowToString(); |
+ if (name != originalName) { |
+ name = "$name[$originalName]"; |
+ } |
+ classMembers.add(js.string("$prefixType:$name")); |
+ } |
+ classDescriptions.add( |
+ new js.ArrayInitializer.from( |
+ [js.string(namer.getName(classElement)), |
+ new js.ArrayInitializer.from(classMembers)])); |
+ } |
+ return new js.ArrayInitializer.from(classDescriptions); |
+ } |
+ |
+ String qualifiedFunctionName(Element functionElement) { |
+ String prefixType; |
+ if (functionElement.modifiers.isStatic()) { |
+ prefixType = 'S'; |
+ } else { |
+ prefixType = 'I'; |
+ } |
+ var typeName = ""; |
+ var libraryID = ""; |
+ assert(functionElement.type != null); |
+ DartType dt = functionElement.type; |
+ // Ignore types that weren't computed. |
+ if (dt != null) { |
+ if (dt.kind == TypeKind.FUNCTION) { |
+ typeName = dt.returnType.name.slowToString(); |
+ if (typeName == 'void' || typeName == 'dynamic') { |
+ libraryID = ""; |
+ } else { |
+ var library = dt.returnType.element.getLibrary(); |
+ var libraryName = library.getLibraryOrScriptName(); |
+ libraryID = libraryMirrorsIndices[libraryName]; |
+ } |
+ } |
+ } |
+ return "$prefixType:$libraryID:$typeName:${namer.getName(functionElement)}"; |
+ } |
+ |
+ Collection extractMethods(listElements, filterToApply) { |
+ var methodsDescription = |
+ listElements |
+ .filter(filterToApply) |
+ .map((e) => js.string(qualifiedFunctionName(e))); |
+ return new js.ArrayInitializer.from(methodsDescription); |
+ } |
+ |
+ String qualifiedVariableName(Element fieldElement) { |
+ String prefixType; |
+ if (fieldElement.modifiers.isStatic()) { |
+ prefixType = 'S'; |
+ } else { |
+ prefixType = 'I'; |
+ } |
+ // Use case to indicate whether field is final or not. |
+ // Is it too fancy? |
+ if (fieldElement.modifiers.isFinal()) { |
+ prefixType = prefixType.toLowerCase(); |
+ } |
+ var name = namer.getName(fieldElement); |
+ var originalName = fieldElement.name.slowToString(); |
+ if (name != originalName) { |
+ name = "$name[$originalName]"; |
+ } |
+ return "$prefixType:$name"; |
+ } |
+ |
+ Collection extractVariables(listElements) { |
+ var fieldsDescription = |
+ listElements |
+ .filter((e) => e.isField()) |
+ .map((e) => js.string(qualifiedVariableName(e))); |
+ return new js.ArrayInitializer.from(fieldsDescription); |
+ } |
+ |
+ Collection extractClosures(Collection<ClosureClassMap> listClosures) { |
+ var closuresDescriptions = |
+ listClosures.map( |
+ (map) => js.string( |
+ "${namer.getName(map.closureClassElement)}:" |
+ "${namer.getName(map.callElement)}:" |
+ "${map.callElement.functionSignature.requiredParameterCount}:" |
+ "${map.callElement.functionSignature.optionalParameterCount}:")); |
+ return new js.ArrayInitializer.from(closuresDescriptions); |
+ } |
+ |
+ void computeLibraryMirrors() { |
+ int index = 0; |
+ libraryMirrorsParametersList = new List<js.Expression>(); |
+ libraryMirrorsIndices = new Map<String, int>(); |
+ for (LibraryElement libraryElement in compiler.libraries.values) { |
+ // |
+ // [lib1, |
+ // [[class1, classConstructor, [member1,...]] |
+ // ...], |
+ // [function1...], |
+ // [getter1...] |
+ // [setter1...] |
+ // [variable1...] |
+ // [closure1...] |
+ // ]... |
+ // |
+ var elements = |
+ new List<Element>.from(libraryElement.localMembers); |
+ var libraryName = libraryElement.getLibraryOrScriptName(); |
+ libraryMirrorsParametersList.add( |
+ new js.ArrayInitializer.from( |
+ <js.Expression>[ |
+ js.string(libraryName), |
+ extractClasses(elements), |
+ extractMethods(elements, (e) => e.isFunction()), |
+ extractMethods(elements, (e) => e.isGetter()), |
+ extractMethods(elements, (e) => e.isSetter()), |
+ extractVariables(elements), |
+ extractClosures( |
+ new List<ClassElement>.from( |
+ compiler.closureToClassMapper |
+ .closureMappingCache.values |
+ .filter((map) => map.closureElement != null |
+ && map.closureElement.getLibrary() |
+ == libraryElement))) |
+ ])); |
+ libraryMirrorsIndices[libraryName] = index++; |
+ } |
+ } |
+ |
+ void emitMirrorsSupport(CodeBuffer buffer) { |
+ Element createMirrorSystem = |
+ compiler.mirrorsLibrary.find(Compiler.CREATE_MIRROR_SYSTEM); |
+ String isolateCreateMirrorSystem = |
+ namer.isolateAccess(createMirrorSystem); |
+ |
+ // createMirrorSystem([library1, library2, ...]) |
+ var createMirrorSystemCall = |
+ new js.ExpressionStatement( |
+ js.call( |
+ js.use(isolateCreateMirrorSystem), |
+ [new js.ArrayInitializer.from(libraryMirrorsParametersList)])); |
+ mainBuffer.add(js.prettyPrint(createMirrorSystemCall, compiler)); |
+ } |
+ |
String assembleProgram() { |
measure(() { |
computeNeededClasses(); |
+ if (compiler.hasMirrorsSupport()) { |
+ // Create library mirror structure up front so that we can refer to |
+ // library elements during class construction by array index. |
+ computeLibraryMirrors(); |
+ } |
mainBuffer.add(GENERATED_BY); |
if (!compiler.enableMinification) mainBuffer.add(HOOKS_API_USAGE); |
@@ -2139,6 +2340,10 @@ if (typeof document !== 'undefined' && document.readyState !== 'complete') { |
emitGetInterceptorMethods(mainBuffer); |
emitLazilyInitializedStaticFields(mainBuffer); |
+ if (compiler.hasMirrorsSupport()) { |
+ emitMirrorsSupport(mainBuffer); |
+ } |
+ |
isolateProperties = isolatePropertiesName; |
// The following code should not use the short-hand for the |
// initialStatics. |