Chromium Code Reviews| Index: lib/compiler/implementation/js_backend/emitter.dart |
| diff --git a/lib/compiler/implementation/js_backend/emitter.dart b/lib/compiler/implementation/js_backend/emitter.dart |
| index aa64cd873ab237454ccc4a199d9bfa8f7380d103..5cdbe3188d1a44ee14f10a33dd3ec2c5cdafaab5 100644 |
| --- a/lib/compiler/implementation/js_backend/emitter.dart |
| +++ b/lib/compiler/implementation/js_backend/emitter.dart |
| @@ -24,6 +24,7 @@ class CodeEmitterTask extends CompilerTask { |
| bool needsInheritFunction = false; |
| bool needsDefineClass = false; |
| bool needsClosureClass = false; |
| + bool needsLazyInitializer = false; |
| final Namer namer; |
| NativeEmitter nativeEmitter; |
| CodeBuffer boundClosureBuffer; |
| @@ -62,6 +63,8 @@ class CodeEmitterTask extends CompilerTask { |
| => '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}'; |
| String get supportsProtoName() |
| => 'supportsProto'; |
| + String get lazyInitializerName() |
| + => '${namer.ISOLATE}.\$lazy'; |
| final String GETTER_SUFFIX = "?"; |
| final String SETTER_SUFFIX = "!"; |
| @@ -249,9 +252,36 @@ function(collectedClasses) { |
| }"""; |
| } |
| + String get lazyInitializerFunction() { |
| + String isolate = namer.CURRENT_ISOLATE; |
| + return """ |
| +function(prototype, fieldName, getterName, lazyValue) { |
| + var sentinel = {}; |
| + prototype[fieldName] = sentinel; |
| + var getter = new Function("{ return $isolate." + fieldName + ";}"); |
| + prototype[getterName] = function() { |
| + var result = $isolate[fieldName]; |
| + try { |
| + if (result === sentinel) { |
|
kasperl
2012/08/17 09:30:04
I guess this doesn't catch cyclic initialization.
floitsch
2012/09/04 17:32:21
Done.
|
| + try { |
| + result = $isolate[fieldName] = lazyValue(); |
| + } catch (e) { |
| + if ($isolate[fieldName] === sentinel) { |
| + $isolate[fieldName] = null; |
| + } |
| + throw e; |
| + } |
| + } |
| + return result; |
| + } finally { |
| + $isolate[getterName] = getter; |
| + } |
| + }; |
| +}"""; |
| + } |
| + |
| void addDefineClassAndFinishClassFunctionsIfNecessary(CodeBuffer buffer) { |
| if (needsDefineClass) { |
| - String isolate = namer.ISOLATE; |
| buffer.add("$defineClassName = $defineClassFunction;\n"); |
| buffer.add(protoSupportCheck); |
| buffer.add("$pendingClassesName = {};\n"); |
| @@ -259,6 +289,12 @@ function(collectedClasses) { |
| } |
| } |
| + void addLazyInitializerFunctionIfNecessary(CodeBuffer buffer) { |
| + if (needsLazyInitializer) { |
| + buffer.add("$lazyInitializerName = $lazyInitializerFunction;\n"); |
| + } |
| + } |
| + |
| void emitFinishIsolateConstructor(CodeBuffer buffer) { |
| String name = finishIsolateConstructorName; |
| String value = finishIsolateConstructorFunction; |
| @@ -386,18 +422,18 @@ function(collectedClasses) { |
| } |
| bool instanceFieldNeedsGetter(Element member) { |
| - assert(member.kind === ElementKind.FIELD); |
| + assert(member.isField()); |
| return compiler.codegenWorld.hasInvokedGetter(member, compiler); |
| } |
| bool instanceFieldNeedsSetter(Element member) { |
| - assert(member.kind === ElementKind.FIELD); |
| + assert(member.isField()); |
| return (member.modifiers === null || !member.modifiers.isFinal()) |
| && compiler.codegenWorld.hasInvokedSetter(member, compiler); |
| } |
| String compiledFieldName(Element member) { |
| - assert(member.kind === ElementKind.FIELD); |
| + assert(member.isField()); |
| return member.isNative() |
| ? member.name.slowToString() |
| : namer.getName(member); |
| @@ -408,10 +444,10 @@ function(collectedClasses) { |
| // TODO(floitsch): we don't need to deal with members of |
| // uninstantiated classes, that have been overwritten by subclasses. |
| - if (member.kind === ElementKind.FUNCTION |
| - || member.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY |
| - || member.kind === ElementKind.GETTER |
| - || member.kind === ElementKind.SETTER) { |
| + if (member.isFunction() |
| + || member.isGenerativeConstructorBody() |
| + || member.isGetter() |
| + || member.isSetter()) { |
| if (member.modifiers !== null && member.modifiers.isAbstract()) return; |
| CodeBuffer codeBuffer = compiler.codegenWorld.generatedCode[member]; |
| if (codeBuffer == null) return; |
| @@ -425,7 +461,7 @@ function(collectedClasses) { |
| if (!parameters.optionalParameters.isEmpty()) { |
| addParameterStubs(member, defineInstanceMember); |
| } |
| - } else if (member.kind !== ElementKind.FIELD) { |
| + } else if (!member.isField()) { |
| compiler.internalError('unexpected kind: "${member.kind}"', |
| element: member); |
| } |
| @@ -653,16 +689,23 @@ function(collectedClasses) { |
| } |
| } |
| + void emitStaticFunctionWithNamer(CodeBuffer buffer, |
| + Element element, |
| + CodeBuffer functionBuffer, |
| + String functionNamer(Element element)) { |
| + String functionName = functionNamer(element); |
| + buffer.add('$isolateProperties.$functionName = '); |
| + addMappings(functionBuffer, buffer.length); |
| + buffer.add(functionBuffer); |
| + buffer.add(';\n\n'); |
| + } |
| void emitStaticFunctionsWithNamer(CodeBuffer buffer, |
| Map<Element, CodeBuffer> generatedCode, |
| String functionNamer(Element element)) { |
| generatedCode.forEach((Element element, CodeBuffer functionBuffer) { |
| - if (!element.isInstanceMember()) { |
| - String functionName = functionNamer(element); |
| - buffer.add('$isolateProperties.$functionName = '); |
| - addMappings(functionBuffer, buffer.length); |
| - buffer.add(functionBuffer); |
| - buffer.add(';\n\n'); |
| + if (!element.isInstanceMember() && !element.isField()) { |
| + emitStaticFunctionWithNamer( |
| + buffer, element, functionBuffer,functionNamer); |
| } |
| }); |
| } |
| @@ -794,7 +837,7 @@ $classesCollector.$mangledName = {'': |
| Set<Selector> selectors, |
| DefineMemberFunction defineInstanceMember) { |
| String getter; |
| - if (member.kind == ElementKind.GETTER) { |
| + if (member.isGetter()) { |
| getter = "this.${namer.getterName(member.getLibrary(), member.name)}()"; |
| } else { |
| String name = namer.instanceFieldName(member.getLibrary(), member.name); |
| @@ -835,6 +878,40 @@ $classesCollector.$mangledName = {'': |
| } |
| } |
| + void emitLazilyInitializedStaticFields(CodeBuffer buffer) { |
| + ConstantHandler handler = compiler.constantHandler; |
| + List<VariableElement> lazyFields = |
| + handler.getLazilyInitializedFieldsForEmission(); |
| + if (!lazyFields.isEmpty()) { |
| + needsLazyInitializer = true; |
| + for (VariableElement element in lazyFields) { |
| + StringBuffer code = compiler.codegenWorld.generatedCode[element]; |
| + assert(code != null); |
| + // The code only computes the initial value. We build the lazy-check |
| + // here: |
| + // lazyInitializer(prototype, fieldName, getterName, initialValue); |
| + buffer.add("$lazyInitializerName("); |
| + buffer.add(isolateProperties); |
| + buffer.add(", '"); |
| + buffer.add(namer.getName(element)); |
| + buffer.add("', '"); |
| + buffer.add(namer.getLazyInitializerName(element)); |
| + buffer.add("', "); |
| + addMappings(code, buffer.length); |
| + buffer.add(code); |
| + buffer.add(");\n"); |
| + |
| + CodeBuffer bailoutCode = |
| + compiler.codegenWorld.generatedBailoutCode[element]; |
| + if (bailoutCode != null) { |
| + Function functionNamer = namer.getLazyInitializerBailoutName; |
| + emitStaticFunctionWithNamer( |
| + buffer, element, bailoutCode, functionNamer); |
| + } |
| + } |
| + } |
| + } |
| + |
| void emitCompileTimeConstants(CodeBuffer buffer) { |
| ConstantHandler handler = compiler.constantHandler; |
| List<Constant> constants = handler.getConstantsForEmission(); |
| @@ -867,12 +944,12 @@ $classesCollector.$mangledName = {'': |
| void emitExtraAccessors(Element member, |
| DefineMemberFunction defineInstanceMember) { |
| - if (member.kind == ElementKind.GETTER || member.kind == ElementKind.FIELD) { |
| + if (member.isGetter() || member.isField()) { |
| Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name]; |
| if (selectors !== null && !selectors.isEmpty()) { |
| emitCallStubForGetter(member, selectors, defineInstanceMember); |
| } |
| - } else if (member.kind == ElementKind.FUNCTION) { |
| + } else if (member.isFunction()) { |
| if (compiler.codegenWorld.hasInvokedGetter(member, compiler)) { |
| emitDynamicFunctionGetter(member, defineInstanceMember); |
| } |
| @@ -1130,6 +1207,7 @@ if (typeof document != 'undefined' && document.readyState != 'complete') { |
| // Static field initializations require the classes and compile-time |
| // constants to be set up. |
| emitStaticNonFinalFieldInitializations(mainBuffer); |
| + emitLazilyInitializedStaticFields(mainBuffer); |
| isolateProperties = isolatePropertiesName; |
| // The following code should not use the short-hand for the |
| @@ -1150,6 +1228,7 @@ if (typeof document != 'undefined' && document.readyState != 'complete') { |
| mainBuffer.add('function init() {\n'); |
| mainBuffer.add('$isolateProperties = {};\n'); |
| addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); |
| + addLazyInitializerFunctionIfNecessary(mainBuffer); |
| emitFinishIsolateConstructor(mainBuffer); |
| mainBuffer.add('}\n'); |
| compiler.assembledCode = mainBuffer.toString(); |