Chromium Code Reviews| Index: lib/compiler/implementation/emitter.dart |
| diff --git a/lib/compiler/implementation/emitter.dart b/lib/compiler/implementation/emitter.dart |
| index e14c8efe9aa794ab37668f1d89e615077ade5ce7..199d3b4b3331f90125c0e0964f5116ae9982fd14 100644 |
| --- a/lib/compiler/implementation/emitter.dart |
| +++ b/lib/compiler/implementation/emitter.dart |
| @@ -28,7 +28,9 @@ class CodeEmitterTask extends CompilerTask { |
| final NativeEmitter nativeEmitter; |
| StringBuffer boundClosureBuffer; |
| StringBuffer mainBuffer; |
| - String isolatePrototype; |
| + /** Shorter access to [initialStaticValuesName]. Both here in the code, as |
| + well as in the generated code. */ |
| + String initialStatics; |
|
kasperl
2012/05/03 12:30:18
isolateProperties?
floitsch
2012/05/03 14:24:01
Done.
|
| CodeEmitterTask(Compiler compiler) |
| : namer = compiler.namer, |
| @@ -41,8 +43,13 @@ class CodeEmitterTask extends CompilerTask { |
| String get defineClassName() => '${namer.ISOLATE}.\$defineClass'; |
|
kasperl
2012/05/03 12:30:18
I think I'd prefer to break before => in this enti
floitsch
2012/05/03 14:24:01
Done.
|
| String get finishClassesName() => '${namer.ISOLATE}.\$finishClasses'; |
| + String get finishIsolateConstructorName() |
| + => '${namer.ISOLATE}.\$finishIsolateConstructor'; |
| + String get pendingClassesName() => '${namer.ISOLATE}.\$pendingClasses'; |
| + String get initialStaticValuesName() |
| + => '${namer.ISOLATE}.${namer.INITIAL_STATICS}'; |
| - String buildDefineClassFunction(String isolate) { |
| + String get defineClassFunction() { |
|
kasperl
2012/05/03 12:30:18
It feels a bit weird to me that these are getters.
floitsch
2012/05/03 14:24:01
If they weren't going through other getters (which
|
| // Example: |
| // defineClass("A", "B", |
| // function(x) { /* The JavaScript constructor. */ |
| @@ -57,15 +64,15 @@ class CodeEmitterTask extends CompilerTask { |
| // }); |
| return """ |
| function(cls, superclass, constructor, prototype) { |
| - $isolate.prototype[cls] = constructor; |
| + $initialStaticValuesName[cls] = constructor; |
| constructor.prototype = prototype; |
| if (superclass !== "") { |
| - $isolate.pendingClasses[cls] = superclass; |
| + $pendingClassesName[cls] = superclass; |
| } |
| }"""; |
| } |
| - String buildFinishClassesFunction(String isolate) { |
| + String get finishClassesFunction() { |
| // 'defineClass' does not require the classes to be constructed in order. |
| // Classes are initially just stored in the 'pendingClasses' field. |
| // 'finishClasses' takes all pending classes and sets up the prototype. |
| @@ -80,10 +87,10 @@ function(cls, superclass, constructor, prototype) { |
| // object and copy over the members. |
| return ''' |
| function() { |
| - var pendingClasses = $isolate.pendingClasses; |
| + var pendingClasses = $pendingClassesName; |
| '''/* FinishClasses can be called multiple times. This means that we need to |
| clear the pendingClasses property. */''' |
| - $isolate.pendingClasses = {}; |
| + $pendingClassesName = {}; |
| var finishedClasses = {}; |
| function finishClass(cls) { |
| if (finishedClasses[cls]) return; |
| @@ -92,8 +99,8 @@ function() { |
| '''/* The superclass is only false (empty string) for Dart's Object class. */''' |
| if (!superclass) return; |
| finishClass(superclass); |
| - var constructor = $isolate.prototype[cls]; |
| - var superConstructor = $isolate.prototype[superclass]; |
| + var constructor = $initialStaticValuesName[cls]; |
| + var superConstructor = $initialStaticValuesName[superclass]; |
| var prototype = constructor.prototype; |
| if (prototype.__proto__) { |
| '''/* On Firefox and Webkit browsers we can manipulate the __proto__ |
| @@ -120,16 +127,46 @@ function() { |
| } |
| } |
| for (var cls in pendingClasses) finishClass(cls); |
| -}; |
| -'''; |
| +}'''; |
| + } |
| + |
| + String get finishIsolateConstructorFunction() { |
| + return """function(oldIsolate) { |
| + var initialStatics = oldIsolate.${namer.INITIAL_STATICS}; |
| + var isolatePrototype = oldIsolate.prototype; |
| + var str = "{\\n"; |
| +"""/* We fetch the initial static values from the same location as before. */""" |
|
kasperl
2012/05/03 12:30:18
Somehow this "embedded comment" make it harder to
floitsch
2012/05/03 14:24:01
Done.
|
| + str += "var initialStatics = ${namer.ISOLATE}.${namer.INITIAL_STATICS};\\n"; |
| + for (var staticName in initialStatics) { |
| + if (Object.prototype.hasOwnProperty.call(initialStatics, staticName)) { |
| + str += "this." + staticName + "= initialStatics." + staticName + ";\\n"; |
| + } |
| + } |
| + str += "}\\n"; |
| + var newIsolate = new Function(str); |
| + newIsolate.prototype = isolatePrototype; |
| + isolatePrototype.constructor = newIsolate; |
| + newIsolate.${namer.INITIAL_STATICS} = initialStatics; |
| + return newIsolate; |
| +}"""; |
| } |
| void addDefineClassAndFinishClassFunctionsIfNecessary(StringBuffer buffer) { |
| String isolate = namer.ISOLATE; |
| - buffer.add("$defineClassName = ${buildDefineClassFunction(isolate)};\n"); |
| - buffer.add("$isolate.pendingClasses = {};\n"); |
| - buffer.add("$finishClassesName = ${buildFinishClassesFunction(isolate)};"); |
| - buffer.add("\n"); |
| + buffer.add("$defineClassName = $defineClassFunction;\n"); |
| + buffer.add("$pendingClassesName = {};\n"); |
| + buffer.add("$finishClassesName = $finishClassesFunction;\n"); |
| + } |
| + |
| + void emitFinishIsolateConstructor(StringBuffer buffer) { |
| + String name = finishIsolateConstructorName; |
| + String value = finishIsolateConstructorFunction; |
| + buffer.add("$name = $value;\n"); |
| + } |
| + |
| + void emitFinishIsolateConstructorInvocation(StringBuffer buffer) { |
| + String isolate = namer.ISOLATE; |
| + buffer.add("$isolate = $finishIsolateConstructorName($isolate);\n"); |
| } |
| void addParameterStub(FunctionElement member, |
| @@ -443,10 +480,8 @@ function() { |
| String functionNamer(Element element)) { |
| generatedCode.forEach((Element element, String codeBlock) { |
| if (!element.isInstanceMember()) { |
| - buffer.add(isolatePrototype); |
| - buffer.add('.${functionNamer(element)} = '); |
| - buffer.add(codeBlock); |
| - buffer.add(';\n\n'); |
| + String functionName = functionNamer(element); |
| + buffer.add('$initialStatics.$functionName = $codeBlock;\n\n'); |
| } |
| }); |
| } |
| @@ -475,12 +510,10 @@ function() { |
| String invocationName = |
| namer.instanceMethodName(element.getLibrary(), callElement.name, |
| parameterCount); |
| - buffer.add(isolatePrototype); |
| - buffer.add(".$staticName.$invocationName = "); |
| - buffer.add(isolatePrototype); |
| - buffer.add(".$staticName;\n"); |
| + String fieldAccess = '$initialStatics.$staticName'; |
| + buffer.add("$fieldAccess.$invocationName = $fieldAccess;\n"); |
| addParameterStubs(callElement, (String name, String value) { |
| - buffer.add('$isolatePrototype.$staticName.$name = $value;\n'); |
| + buffer.add('$fieldAccess.$name = $value;\n'); |
| }); |
| } |
| } |
| @@ -586,18 +619,11 @@ function() { |
| } |
| void emitStaticNonFinalFieldInitializations(StringBuffer buffer) { |
| - // Adds initializations inside the Isolate constructor. |
| - // Example: |
| - // function Isolate() { |
| - // this.staticNonFinal = Isolate.prototype.someVal; |
| - // ... |
| - // } |
| ConstantHandler handler = compiler.constantHandler; |
| List<VariableElement> staticNonFinalFields = |
| handler.getStaticNonFinalFieldsForEmission(); |
| - if (!staticNonFinalFields.isEmpty()) buffer.add('\n'); |
| for (Element element in staticNonFinalFields) { |
| - buffer.add(' this.${namer.getName(element)} = '); |
| + buffer.add('$initialStatics.${namer.getName(element)} = '); |
| compiler.withCurrentElement(element, () { |
| handler.writeJsCodeForVariable(buffer, element); |
| }); |
| @@ -619,14 +645,14 @@ function() { |
| addedMakeConstantList = true; |
| emitMakeConstantList(buffer); |
| } |
| - buffer.add('$isolatePrototype.$name = '); |
| + buffer.add('$initialStatics.$name = '); |
| handler.writeJsCode(buffer, constant); |
| buffer.add(';\n'); |
| } |
| } |
| void emitMakeConstantList(StringBuffer buffer) { |
| - buffer.add(isolatePrototype); |
| + buffer.add(namer.ISOLATE); |
| buffer.add(@'''.makeConstantList = function(list) { |
| list.immutable$list = true; |
| list.fixed$length = true; |
| @@ -808,13 +834,11 @@ if (typeof window != 'undefined' && typeof document != 'undefined' && |
| String assembleProgram() { |
| measure(() { |
| - mainBuffer.add('function ${namer.ISOLATE}() {'); |
| - emitStaticNonFinalFieldInitializations(mainBuffer); |
| - mainBuffer.add('}\n'); |
| + mainBuffer.add('function ${namer.ISOLATE}() {}\n'); |
| mainBuffer.add('init();\n\n'); |
| // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary. |
| - isolatePrototype = namer.CURRENT_ISOLATE; |
| - mainBuffer.add('var $isolatePrototype = ${namer.ISOLATE}.prototype;\n'); |
| + initialStatics = namer.CURRENT_ISOLATE; |
| + mainBuffer.add('var $initialStatics = $initialStaticValuesName;\n'); |
| emitClasses(mainBuffer); |
| mainBuffer.add(boundClosureBuffer); |
| // Clear the buffer, so that we can reuse it for the native classes. |
| @@ -824,18 +848,28 @@ if (typeof window != 'undefined' && typeof document != 'undefined' && |
| // We need to finish the classes before we construct compile time |
| // constants. |
| emitFinishClassesInvocationIfNecessary(mainBuffer); |
| + // Static field initializations require the classes to be set up. |
| + emitStaticNonFinalFieldInitializations(mainBuffer); |
| emitCompileTimeConstants(mainBuffer); |
| - isolatePrototype = '${namer.ISOLATE}.prototype;\n'; |
| - mainBuffer.add( |
| - 'var ${namer.CURRENT_ISOLATE} = new ${namer.ISOLATE}();\n'); |
| + initialStatics = initialStaticValuesName; |
| + // The following code should not use the short-hand for the |
| + // initialStatics. |
| + mainBuffer.add('var ${namer.CURRENT_ISOLATE} = null;\n'); |
| nativeEmitter.emitDynamicDispatchMetadata(); |
| nativeEmitter.assembleCode(mainBuffer); |
| mainBuffer.add(boundClosureBuffer); |
| emitFinishClassesInvocationIfNecessary(mainBuffer); |
| + |
| + emitFinishIsolateConstructorInvocation(mainBuffer); |
| + mainBuffer.add( |
| + 'var ${namer.CURRENT_ISOLATE} = new ${namer.ISOLATE}();\n'); |
| + |
| emitMain(mainBuffer); |
| mainBuffer.add('function init() {\n'); |
| + mainBuffer.add(' $initialStatics = {};\n'); |
| addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); |
| + emitFinishIsolateConstructor(mainBuffer); |
| mainBuffer.add('}\n'); |
| compiler.assembledCode = mainBuffer.toString(); |
| }); |