Chromium Code Reviews| Index: dart/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
| diff --git a/dart/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/dart/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
| index 183ecd797abd35a0e407c2604d358a9b4f7dd72d..829d6b8d19b153715c3ddef8671064b35fdcff11 100644 |
| --- a/dart/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
| +++ b/dart/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
| @@ -137,6 +137,14 @@ class CodeEmitterTask extends CompilerTask { |
| Set<FunctionType> checkedNonGenericFunctionTypes = |
| new Set<FunctionType>(); |
| + /** |
| + * For classes and libraries, record code for static/top-level members. |
| + * Later, this code is emitted when the class or library is emitted. |
|
ngeoffray
2013/07/17 07:35:57
Would there be a way to just produce them when we
ahe
2013/07/17 07:55:27
Yes. I hope to clean this up.
However, there are,
ngeoffray
2013/07/17 08:08:42
I agree it's not trivial.
|
| + * See [bufferForElement]. |
| + */ |
| + final Map<Element, List<CodeBuffer>> elementBuffers = |
| + new Map<Element, List<CodeBuffer>>(); |
| + |
| void registerDynamicFunctionTypeCheck(FunctionType functionType) { |
| ClassElement classElement = Types.getClassContext(functionType); |
| if (classElement != null) { |
| @@ -1784,6 +1792,25 @@ class CodeEmitterTask extends CompilerTask { |
| } |
| emitIsTests(classElement, builder); |
| + List<CodeBuffer> classBuffers = elementBuffers[classElement]; |
| + CodeBuffer statics = new CodeBuffer(); |
| + bool hasStatics = false; |
| + if (classBuffers != null) { |
| + statics.write('{$n'); |
| + elementBuffers.remove(classElement); |
| + for (CodeBuffer classBuffer in classBuffers) { |
| + // TODO(ahe): What about deferred? |
| + if (classBuffer != null) { |
| + hasStatics = true; |
| + statics.addBuffer(classBuffer); |
| + } |
| + } |
| + statics.write('}$n'); |
| + } |
| + if (hasStatics) { |
| + builder.addProperty('static', new jsAst.Blob(statics)); |
| + } |
| + |
| // TODO(ahe): This method (generateClass) should return a jsAst.Expression. |
| if (!buffer.isEmpty) { |
| buffer.write(',$n$n'); |
| @@ -3389,6 +3416,8 @@ if (typeof document !== "undefined" && document.readyState !== "complete") { |
| mainBuffer.add( |
| '$isolateProperties$_=$_$isolatePropertiesName$N'); |
| + emitStaticFunctions(mainBuffer); |
| + |
| if (!regularClasses.isEmpty || |
| !deferredClasses.isEmpty || |
| !nativeClasses.isEmpty || |
| @@ -3443,9 +3472,7 @@ if (typeof document !== "undefined" && document.readyState !== "complete") { |
| // the classesCollector variable. |
| classesCollector = 'classesCollector should not be used from now on'; |
| - emitStaticFunctions(mainBuffer); |
| - |
| - if (!libraryBuffers.isEmpty) { |
| + if (!elementBuffers.isEmpty) { |
| var oldClassesCollector = classesCollector; |
| classesCollector = r"$$"; |
| if (compiler.enableMinification) { |
| @@ -3471,9 +3498,22 @@ if (typeof document !== "undefined" && document.readyState !== "complete") { |
| ..write(getReflectionDataParser()) |
| ..write('([$n'); |
| - var sortedLibraries = Elements.sortedByPosition(libraryBuffers.keys); |
| - for (LibraryElement library in sortedLibraries) { |
| - List<CodeBuffer> buffers = libraryBuffers[library]; |
| + var sortedElements = Elements.sortedByPosition(elementBuffers.keys); |
|
karlklose
2013/07/17 08:01:40
Type this variable (and also b in l. 3505)?
ahe
2013/07/17 08:31:24
Done.
|
| + bool hasPendingStatics = false; |
| + for (Element element in sortedElements) { |
| + if (!element.isLibrary()) { |
| + for (var b in elementBuffers[element]) { |
|
ngeoffray
2013/07/17 07:35:57
Add a TODO to remove this once you implement it fo
ahe
2013/07/17 07:55:27
I'm not sure this code would go away. Consider it
ngeoffray
2013/07/17 08:08:42
OK. So after reading the code again, I realize I m
ahe
2013/07/17 08:31:24
If feel that would be easier to accomplish once I
|
| + if (b != null) { |
| + hasPendingStatics = true; |
| + compiler.reportInfo( |
| + element, MessageKind.GENERIC, {'text': 'Pending statics.'}); |
| + print(b.getText()); |
| + } |
| + } |
| + continue; |
| + } |
| + LibraryElement library = element; |
| + List<CodeBuffer> buffers = elementBuffers[library]; |
| var buffer = buffers[0]; |
| var uri = library.canonicalUri; |
| if (uri.scheme == 'file' && compiler.sourceMapUri != null) { |
| @@ -3505,7 +3545,10 @@ if (typeof document !== "undefined" && document.readyState !== "complete") { |
| ..addBuffer(buffer) |
| ..write('}],$n'); |
| } |
| - libraryBuffers[library] = const []; |
| + elementBuffers[library] = const []; |
| + } |
| + if (hasPendingStatics) { |
| + compiler.internalError('Pending statics (see above).'); |
|
ngeoffray
2013/07/17 07:35:57
Is that an internal error, or a not yet implemente
ahe
2013/07/17 07:55:27
It is an internal error.
If a static is "pending"
|
| } |
| mainBuffer.write('])$N'); |
| @@ -3555,13 +3598,24 @@ if (typeof document !== "undefined" && document.readyState !== "complete") { |
| return compiler.assembledCode; |
| } |
| - final Map<LibraryElement, List<CodeBuffer>> libraryBuffers = |
| - new Map<LibraryElement, List<CodeBuffer>>(); |
| - |
| CodeBuffer bufferForElement(Element element, CodeBuffer eagerBuffer) { |
| - LibraryElement library = element.getLibrary(); |
| - List<CodeBuffer> buffers = libraryBuffers.putIfAbsent( |
| - library, () => <CodeBuffer>[null, null]); |
| + Element owner = element.getLibrary(); |
| + if (!element.isTopLevel() && !element.isNative()) { |
| + // For static (not top level) elements, record their code in a buffer |
| + // specific to the class. For now, not supported for native classes and |
| + // native elements. |
| + ClassElement cls = |
| + element.getEnclosingClassOrCompilationUnit().declaration; |
| + if (compiler.codegenWorld.instantiatedClasses.contains(cls) |
| + && !cls.isNative()) { |
| + owner = cls; |
| + } |
| + } |
| + if (owner == null) { |
|
ngeoffray
2013/07/17 07:35:57
This looks too defensive.
ahe
2013/07/17 07:55:27
At first sight, yes. But notice that if we don't c
|
| + throw 'Bad owner of $element'; |
|
karlklose
2013/07/17 08:01:40
Could you call internalError instead?
ahe
2013/07/17 08:31:24
Done.
|
| + } |
| + List<CodeBuffer> buffers = elementBuffers.putIfAbsent( |
| + owner, () => <CodeBuffer>[null, null]); |
| bool deferred = isDeferred(element); |
| int index = deferred ? 1 : 0; |
| CodeBuffer buffer = buffers[index]; |
| @@ -3682,11 +3736,13 @@ if (typeof document !== "undefined" && document.readyState !== "complete") { |
| // TODO(ahe): This code should be integrated in finishClasses. |
| String getReflectionDataParser() { |
| + String metadataField = '"${namer.metadataField}"'; |
| return ''' |
| (function (reflectionData) { |
| if (!init.libraries) init.libraries = []; |
| if (!init.mangledNames) init.mangledNames = {}; |
| if (!init.mangledGlobalNames) init.mangledGlobalNames = {}; |
| + if (!init.statics) init.statics = {}; |
| init.getterPrefix = "${namer.getterPrefix}"; |
| init.setterPrefix = "${namer.setterPrefix}"; |
| var libraries = init.libraries; |
| @@ -3702,39 +3758,43 @@ if (typeof document !== "undefined" && document.readyState !== "complete") { |
| var descriptor = data[3]; |
| var classes = []; |
| var functions = []; |
| - for (var property in descriptor) { |
| - if (!hasOwnProperty.call(descriptor, property)) continue; |
| - var element = descriptor[property]; |
| - var firstChar = property.substring(0, 1); |
| - var previousProperty; |
| - if (firstChar == "+") { |
| - mangledGlobalNames[previousProperty] = property.substring(1); |
| - } else if (firstChar == "@") { |
| - property = property.substring(1); |
| - ${namer.CURRENT_ISOLATE}[property]["${namer.metadataField}"] = element; |
| - } else if (typeof element === "function") { |
| - ${namer.CURRENT_ISOLATE}[previousProperty = property] = element; |
| - functions.push(property); |
| - } else { |
| - previousProperty = property; |
| - var newDesc = {}; |
| - var previousProp; |
| - for (var prop in element) { |
| - if (!hasOwnProperty.call(element, prop)) continue; |
| - firstChar = prop.substring(0, 1); |
| - if (firstChar == "+") { |
| - mangledNames[previousProp] = prop.substring(1); |
| - } else if (firstChar == "@" && prop != "@") { |
| - newDesc[prop.substring(1)]["${namer.metadataField}"] =''' |
| -'''element[prop]; |
| - } else { |
| - newDesc[previousProp = prop] = element[prop]; |
| + function processStatics(descriptor) { |
| + for (var property in descriptor) { |
| + if (!hasOwnProperty.call(descriptor, property)) continue; |
| + var element = descriptor[property]; |
| + var firstChar = property.substring(0, 1); |
| + var previousProperty; |
| + if (firstChar === "+") { |
| + mangledGlobalNames[previousProperty] = property.substring(1); |
| + } else if (firstChar === "@") { |
| + property = property.substring(1); |
| + ${namer.CURRENT_ISOLATE}[property][$metadataField] = element; |
| + } else if (typeof element === "function") { |
| + ${namer.CURRENT_ISOLATE}[previousProperty = property] = element; |
| + functions.push(property); |
| + } else { |
| + previousProperty = property; |
| + var newDesc = {}; |
| + var previousProp; |
| + for (var prop in element) { |
| + if (!hasOwnProperty.call(element, prop)) continue; |
| + firstChar = prop.substring(0, 1); |
| + if (prop === "static") { |
| + processStatics(init.statics[property] = element[prop]); |
| + } else if (firstChar === "+") { |
| + mangledNames[previousProp] = prop.substring(1); |
| + } else if (firstChar === "@" && prop !== "@") { |
| + newDesc[prop.substring(1)][$metadataField] = element[prop]; |
| + } else { |
| + newDesc[previousProp = prop] = element[prop]; |
| + } |
| } |
| + $classesCollector[property] = newDesc; |
| + classes.push(property); |
| } |
| - $classesCollector[property] = newDesc; |
| - classes.push(property); |
| } |
| } |
| + processStatics(descriptor); |
| libraries.push([name, uri, classes, functions, metadata]); |
| } |
| })'''; |