Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(178)

Unified Diff: lib/compiler/implementation/js_backend/emitter.dart

Issue 10855174: Lazy implementation of final variables. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Remove lazy bailout initializers. Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 552f5792b805b645855ec8e8679e41053f074629..dc1361a58bc28950dac297fc976b62e8d7dc36f3 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 = "!";
@@ -251,9 +254,41 @@ function(collectedClasses) {
}""";
}
+ String get lazyInitializerFunction() {
+ String isolate = namer.CURRENT_ISOLATE;
+ String cyclicThrow = namer.isolateAccess(compiler.cyclicThrowHelper);
+ return """
+function(prototype, staticName, fieldName, getterName, lazyValue) {
+ var sentinel_undefined = {};
kasperl 2012/09/05 08:25:24 Are you deliberately using a non-JS naming convent
floitsch 2012/09/05 09:31:07 Don't know why. Changed to JS convention. done.
+ var sentinel_in_progress = {};
+ prototype[fieldName] = sentinel_undefined;
+ var getter = new Function("{ return $isolate." + fieldName + ";}");
+ prototype[getterName] = function() {
+ var result = $isolate[fieldName];
+ try {
+ if (result === sentinel_undefined) {
+ $isolate[fieldName] = sentinel_in_progress;
+ try {
+ result = $isolate[fieldName] = lazyValue();
+ } catch (e) {
+ if ($isolate[fieldName] === sentinel_in_progress) {
+ $isolate[fieldName] = null;
+ }
+ throw e;
+ }
+ } else if(result === sentinel_in_progress) {
kasperl 2012/09/05 08:25:24 Add space between if and (.
floitsch 2012/09/05 09:31:07 Done.
+ $cyclicThrow(staticName);
+ }
+ 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");
@@ -261,6 +296,12 @@ function(collectedClasses) {
}
}
+ void addLazyInitializerFunctionIfNecessary(CodeBuffer buffer) {
+ if (needsLazyInitializer) {
+ buffer.add("$lazyInitializerName = $lazyInitializerFunction;\n");
+ }
+ }
+
void emitFinishIsolateConstructor(CodeBuffer buffer) {
String name = finishIsolateConstructorName;
String value = finishIsolateConstructorFunction;
@@ -388,18 +429,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.isFinalOrConst())
&& 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);
@@ -410,10 +451,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;
@@ -427,7 +468,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);
}
@@ -685,16 +726,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);
}
});
}
@@ -826,7 +874,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);
@@ -867,6 +915,35 @@ $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) {
+ assert(compiler.codegenWorld.generatedBailoutCode[element] === null);
+ 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(element.name.slowToString());
+ 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");
+ }
+ }
+ }
+
void emitCompileTimeConstants(CodeBuffer buffer) {
ConstantHandler handler = compiler.constantHandler;
List<Constant> constants = handler.getConstantsForEmission();
@@ -899,12 +976,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);
}
@@ -1154,6 +1231,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
@@ -1174,6 +1252,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();

Powered by Google App Engine
This is Rietveld 408576698