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

Unified Diff: lib/compiler/implementation/compile_time_constants.dart

Issue 10855174: Lazy implementation of final variables. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: rebase wrt CL 10832351. Created 8 years, 4 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
« no previous file with comments | « no previous file | lib/compiler/implementation/compiler.dart » ('j') | lib/compiler/implementation/compiler.dart » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/compiler/implementation/compile_time_constants.dart
diff --git a/lib/compiler/implementation/compile_time_constants.dart b/lib/compiler/implementation/compile_time_constants.dart
index d70bd83f3b5126ab021a1ee99ea2982f923a6bde..a736d6d1645339f4e9b83b20f5b5d17e75ee2a78 100644
--- a/lib/compiler/implementation/compile_time_constants.dart
+++ b/lib/compiler/implementation/compile_time_constants.dart
@@ -477,24 +477,32 @@ class ConstructedConstant extends ObjectConstant {
/**
* The [ConstantHandler] keeps track of compile-time constants,
- * initializations of global and static fields, and default values of
+ * initializations of global and static const fields, and default values of
* optional parameters.
*/
class ConstantHandler extends CompilerTask {
- // Contains the initial value of fields. Must contain all static and global
- // initializations of used fields. May contain caches for instance fields.
+ /**
+ * Contains the initial value of fields. Must contain all static and global
+ * initializations of const fields. May contain eagerly compiled values for
+ * statics and instance fields.
+ */
final Map<VariableElement, Constant> initialVariableValues;
- // Map from compile-time constants to their JS name.
+ /** Map from compile-time constants to their JS name. */
final Map<Constant, String> compiledConstants;
- // The set of variable elements that are in the process of being computed.
+ /** The set of variable elements that are in the process of being computed. */
final Set<VariableElement> pendingVariables;
+ /** Caches the statics where the initial value cannot be eagerly compiled. */
+ final Set<VariableElement> lazyStatics;
+
+
ConstantHandler(Compiler compiler)
: initialVariableValues = new Map<VariableElement, Dynamic>(),
compiledConstants = new Map<Constant, String>(),
pendingVariables = new Set<VariableElement>(),
+ lazyStatics = new Set<VariableElement>(),
super(compiler);
String get name() => 'ConstantHandler';
@@ -505,44 +513,78 @@ class ConstantHandler extends CompilerTask {
/**
* Compiles the initial value of the given field and stores it in an internal
- * map.
+ * map. Returns the initial value (a constant) if it can be computed
+ * statically. Returns [:null:] if the variable must be initialized lazily.
*
* [WorkItem] must contain a [VariableElement] refering to a global or
* static field.
*/
- void compileWorkItem(WorkItem work) {
- measure(() {
+ Constant compileWorkItem(WorkItem work) {
+ return measure(() {
assert(work.element.kind == ElementKind.FIELD
|| work.element.kind == ElementKind.PARAMETER
|| work.element.kind == ElementKind.FIELD_PARAMETER);
VariableElement element = work.element;
+ Constant result;
kasperl 2012/08/17 09:30:04 Constant result = initial... ?
floitsch 2012/09/04 17:32:21 Done.
// Shortcut if it has already been compiled.
- if (initialVariableValues.containsKey(element)) return;
- compileVariableWithDefinitions(element, work.resolutionTree);
+ result = initialVariableValues[element];
+ if (result != null) return result;
+ if (lazyStatics.contains(element)) return null;
+ result = compileVariableWithDefinitions(element, work.resolutionTree);
assert(pendingVariables.isEmpty());
+ return result;
});
}
- Constant compileVariable(VariableElement element) {
+ /**
+ * Returns a compile-time constant, or reports an error if the element is not
+ * a compile-time constant.
+ */
+ Constant compileConstant(VariableElement element) {
+ return compileVariable(element, isConst: true);
+ }
+
+ /**
+ * Returns the a compile-time constant if the variable could be compiled
+ * eagerly. Otherwise returns `null`.
+ */
+ Constant compileVariable(VariableElement element, [bool isConst = false]) {
return measure(() {
if (initialVariableValues.containsKey(element)) {
Constant result = initialVariableValues[element];
return result;
}
TreeElements definitions = compiler.analyzeElement(element);
- Constant constant = compileVariableWithDefinitions(element, definitions);
+ Constant constant = compileVariableWithDefinitions(
+ element, definitions, isConst: isConst);
return constant;
});
}
+ /**
+ * Returns the a compile-time constant if the variable could be compiled
+ * eagerly. If the variable needs to be initialized lazily returns `null`.
+ * If the variable is `const` but cannot be compiled eagerly reports an
+ * error.
+ */
Constant compileVariableWithDefinitions(VariableElement element,
- TreeElements definitions) {
+ TreeElements definitions,
+ [bool isConst = false]) {
return measure(() {
+ // Initializers for fields, or parameters must be const.
+ isConst = isConst || !element.modifiers.isFinal();
+ if (!isConst && lazyStatics.contains(element)) return null;
+
Node node = element.parseNode(compiler);
if (pendingVariables.contains(element)) {
- MessageKind kind = MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS;
- compiler.reportError(node,
- new CompileTimeConstantError(kind, const []));
+ if (isConst) {
+ MessageKind kind = MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS;
+ compiler.reportError(node,
+ new CompileTimeConstantError(kind, const []));
+ } else {
+ lazyStatics.add(element);
+ return null;
+ }
}
pendingVariables.add(element);
@@ -553,19 +595,27 @@ class ConstantHandler extends CompilerTask {
value = new NullConstant();
} else {
Node right = assignment.arguments.head;
- value = compileNodeWithDefinitions(right, definitions);
+ value =
+ compileNodeWithDefinitions(right, definitions, isConst: isConst);
+ }
+ if (value != null) {
+ initialVariableValues[element] = value;
+ } else {
+ assert(!isConst);
+ lazyStatics.add(element);
}
- initialVariableValues[element] = value;
pendingVariables.remove(element);
return value;
});
}
- Constant compileNodeWithDefinitions(Node node, TreeElements definitions) {
+ Constant compileNodeWithDefinitions(Node node,
+ TreeElements definitions,
+ [bool isConst]) {
return measure(() {
assert(node !== null);
CompileTimeConstantEvaluator evaluator =
- new CompileTimeConstantEvaluator(definitions, compiler);
+ new CompileTimeConstantEvaluator(definitions, compiler, isConst);
return evaluator.evaluate(node);
});
}
@@ -610,6 +660,10 @@ class ConstantHandler extends CompilerTask {
});
}
+ List<VariableElement> getLazilyInitializedFieldsForEmission() {
+ return new List<VariableElement>.from(lazyStatics);
+ }
+
List<Constant> getConstantsForEmission() {
// We must emit dependencies before their uses.
Set<Constant> seenConstants = new Set<Constant>();
@@ -713,17 +767,29 @@ class ConstantHandler extends CompilerTask {
}
class CompileTimeConstantEvaluator extends AbstractVisitor {
+ bool isEvaluatingConstant;
final TreeElements elements;
final Compiler compiler;
- CompileTimeConstantEvaluator(this.elements, this.compiler);
+ CompileTimeConstantEvaluator(this.elements, this.compiler, [bool isConst])
+ : this.isEvaluatingConstant = isConst;
Constant evaluate(Node node) {
return node.accept(this);
}
- visitNode(Node node) {
- error(node);
+ Constant evaluateConstant(Node node) {
+ bool oldIsEvaluatingConstant = isEvaluatingConstant;
+ isEvaluatingConstant = true;
+ Constant result = node.accept(this);
+ isEvaluatingConstant = oldIsEvaluatingConstant;
+ assert(result != null);
+ return result;
+ }
+
+ Constant visitNode(Node node) {
+ signalNotACompileTimeConstant(node);
+ return null;
}
Constant visitLiteralBool(LiteralBool node) {
@@ -739,12 +805,15 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
}
Constant visitLiteralList(LiteralList node) {
- if (!node.isConst()) error(node);
+ if (!node.isConst()) {
+ signalNotACompileTimeConstant(node);
+ return null;
+ }
List<Constant> arguments = <Constant>[];
for (Link<Node> link = node.elements.nodes;
!link.isEmpty();
link = link.tail) {
- arguments.add(evaluate(link.head));
+ arguments.add(evaluateConstant(link.head));
}
// TODO(floitsch): get type from somewhere.
Type type = null;
@@ -754,21 +823,24 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
}
Constant visitLiteralMap(LiteralMap node) {
- if (!node.isConst()) error(node);
+ if (!node.isConst()) {
+ signalNotACompileTimeConstant(node);
+ error(node);
+ }
List<StringConstant> keys = <StringConstant>[];
Map<StringConstant, Constant> map = new Map<StringConstant, Constant>();
for (Link<Node> link = node.entries.nodes;
!link.isEmpty();
link = link.tail) {
LiteralMapEntry entry = link.head;
- Constant key = evaluate(entry.key);
+ Constant key = evaluateConstant(entry.key);
if (!key.isString() || entry.key.asStringNode() === null) {
MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL;
compiler.reportError(entry.key, new ResolutionError(kind, const []));
}
StringConstant keyConstant = key;
if (!map.containsKey(key)) keys.add(key);
- map[key] = evaluate(entry.value);
+ map[key] = evaluateConstant(entry.value);
}
List<Constant> values = <Constant>[];
Constant protoValue = null;
@@ -808,12 +880,14 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
Constant visitStringJuxtaposition(StringJuxtaposition node) {
StringConstant left = evaluate(node.first);
StringConstant right = evaluate(node.second);
+ if (left == null || right == null) return null;
return new StringConstant(new DartString.concat(left.value, right.value),
node);
}
Constant visitStringInterpolation(StringInterpolation node) {
StringConstant initialString = evaluate(node.string);
+ if (initialString == null) return null;
DartString accumulator = initialString.value;
for (StringInterpolationPart part in node.parts) {
Constant expression = evaluate(part.expression);
@@ -825,10 +899,12 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
PrimitiveConstant primitive = expression;
expressionString = primitive.value;
} else {
- error(part.expression);
+ signalNotACompileTimeConstant(part.expression);
+ return null;
}
accumulator = new DartString.concat(accumulator, expressionString);
StringConstant partString = evaluate(part.string);
+ if (partString == null) return null;
accumulator = new DartString.concat(accumulator, partString.value);
};
return new StringConstant(accumulator, node);
@@ -838,14 +914,22 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
Constant visitSend(Send send) {
Element element = elements[send];
if (Elements.isStaticOrTopLevelField(element)) {
- if (element.modifiers === null ||
- !element.modifiers.isFinal()) {
- error(send);
+ Constant result;
+ if (element.modifiers !== null) {
+ if (element.modifiers.isConst()) {
+ result = compiler.compileConstant(element);
+ } else if (element.modifiers.isFinal()) {
+ // TODO(4516): remove support for final compile-time constants: if
+ // isCompilingConstant is true don't compile the variable.
+ result = compiler.compileVariable(element);
+ }
}
- return compiler.compileVariable(element);
+ if (result == null) signalNotACompileTimeConstant(send);
+ return result;
} else if (send.isPrefix) {
assert(send.isOperator);
Constant receiverConstant = evaluate(send.receiver);
+ if (receiverConstant == null) return null;
Operator op = send.selector;
Constant folded;
switch (op.source.stringValue) {
@@ -862,12 +946,13 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
compiler.internalError("Unexpected operator.", node: op);
break;
}
- if (folded === null) error(send);
+ if (folded === null) signalNotACompileTimeConstant(send);
return folded;
} else if (send.isOperator && !send.isPostfix) {
assert(send.argumentCount() == 1);
Constant left = evaluate(send.receiver);
Constant right = evaluate(send.argumentsNode.nodes.head);
+ if (left == null || right == null) return null;
Operator op = send.selector.asOperator();
Constant folded = null;
switch (op.source.stringValue) {
@@ -954,14 +1039,16 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
}
break;
}
- if (folded === null) error(send);
+ if (folded === null) signalNotACompileTimeConstant(send);
return folded;
}
- return super.visitSend(send);
+ signalNotACompileTimeConstant(send);
+ return null;
}
- visitSendSet(SendSet node) {
- error(node);
+ Constant visitSendSet(SendSet node) {
+ signalNotACompileTimeConstant(node);
+ return null;
}
/** Returns the list of constants that are passed to the static function. */
@@ -970,8 +1057,8 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
FunctionElement target) {
List<Constant> compiledArguments = <Constant>[];
- Function compileArgument = evaluate;
- Function compileConstant = compiler.compileVariable;
+ Function compileArgument = evaluateConstant;
+ Function compileConstant = compiler.compileConstant;
bool succeeded = selector.addArgumentsToList(arguments,
compiledArguments,
target,
@@ -983,7 +1070,10 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
}
Constant visitNewExpression(NewExpression node) {
- if (!node.isConst()) error(node);
+ if (!node.isConst()) {
+ signalNotACompileTimeConstant(node);
+ return null;
+ }
Send send = node.send;
FunctionElement constructor = elements[send];
@@ -1020,11 +1110,20 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT;
compiler.reportError(node, new CompileTimeConstantError(kind, const []));
}
+
+ void signalNotACompileTimeConstant(Node node) {
kasperl 2012/08/17 09:30:04 I would remove the A.
floitsch 2012/09/04 17:32:21 Done.
+ if (isEvaluatingConstant) {
+ error(node);
+ }
+ // Else we don't need to do anything. The final handler is only
+ // optimistically trying to compile constants. So it is normal that we
+ // sometimes see non-compile time constants.
kasperl 2012/08/17 09:30:04 So in this case, you'll end up returning null anyw
floitsch 2012/09/04 17:32:21 Done.
+ }
}
class TryCompileTimeConstantEvaluator extends CompileTimeConstantEvaluator {
TryCompileTimeConstantEvaluator(TreeElements elements, Compiler compiler):
- super(elements, compiler);
+ super(elements, compiler, isConst: true);
error(Node node) {
// Just fail without reporting it anywhere.
@@ -1043,7 +1142,8 @@ class ConstructorEvaluator extends CompileTimeConstantEvaluator {
this.definitions = new Map<Element, Constant>(),
this.fieldValues = new Map<Element, Constant>(),
super(compiler.resolver.resolveMethodElement(constructor),
- compiler);
+ compiler,
+ isConst: true);
Constant visitSend(Send send) {
Element element = elements[send];
@@ -1169,7 +1269,7 @@ class ConstructorEvaluator extends CompileTimeConstantEvaluator {
Constant fieldValue = fieldValues[field];
if (fieldValue === null) {
// Use the default value.
- fieldValue = compiler.compileVariable(field);
+ fieldValue = compiler.compileConstant(field);
}
jsNewArguments.add(fieldValue);
});
« no previous file with comments | « no previous file | lib/compiler/implementation/compiler.dart » ('j') | lib/compiler/implementation/compiler.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698