Chromium Code Reviews| Index: sdk/lib/_internal/compiler/implementation/compile_time_constants.dart |
| diff --git a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart |
| index 94523f092acdc2a38df11c8bef179891a973a8ec..3ee1cae15bde821f2aa9947e04c942a95cc04b11 100644 |
| --- a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart |
| +++ b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart |
| @@ -4,14 +4,92 @@ |
| part of dart2js; |
| +abstract class ConstantHandler { |
|
floitsch
2014/04/02 16:50:02
The name "ConstantHandler" is now used with three
Johnni Winther
2014/04/07 11:42:27
Done.
|
| + Constant getConstantForVariable(VariableElement element); |
| +} |
| + |
| +abstract class ConstantCompiler extends ConstantHandler { |
| + /** |
| + * Returns a compile-time constant, or reports an error if the element is not |
| + * a compile-time constant. |
| + */ |
| + Constant compileConstant(VariableElement element); |
| + |
| + Constant compileNode(Node node, TreeElements elements); |
|
karlklose
2014/04/02 13:04:44
Please ad comments to these methods, too. And perh
Johnni Winther
2014/04/07 11:42:27
Done.
|
| + |
| + Constant compileMetadata(MetadataAnnotation metadata, |
| + Node node, TreeElements elements); |
| +} |
| + |
| +abstract class BackendConstantHandler extends ConstantHandler { |
| + /** |
| + * Returns the a compile-time constant if the variable could be compiled |
| + * eagerly. Otherwise returns `null`. |
| + */ |
| + void compileVariable(VariableElement element); |
| + |
| + Constant getConstantForNode(Node node, TreeElements elements); |
| + |
| + Constant getConstantForMetadata(MetadataAnnotation metadata); |
| +} |
| + |
| +class DartConstantHandler extends CompilerTask |
| + implements ConstantCompiler, BackendConstantHandler { |
| + final DartConstantCompiler constantCompiler; |
| + |
| + DartConstantHandler(Compiler compiler) |
| + : this.constantCompiler = new DartConstantCompiler(compiler), |
| + super(compiler); |
| + |
| + String get name => 'ConstantHandler'; |
| + |
| + Constant getConstantForVariable(VariableElement element) { |
| + return constantCompiler.getConstantForVariable(element); |
| + } |
| + |
| + Constant getConstantForNode(Node node, TreeElements elements) { |
| + return constantCompiler.getConstantForNode(node, elements); |
| + } |
| + |
| + Constant getConstantForMetadata(MetadataAnnotation metadata) { |
| + return metadata.value; |
| + } |
| + |
| + Constant compileConstant(VariableElement element) { |
| + return measure(() { |
| + return constantCompiler.compileConstant(element); |
| + }); |
| + } |
| + |
| + Constant compileVariable(VariableElement element) { |
| + return measure(() { |
| + return constantCompiler.compileVariable(element); |
| + }); |
| + } |
| + |
| + Constant compileNode(Node node, TreeElements elements) { |
| + return measure(() { |
| + return constantCompiler.compileNodeWithDefinitions(node, elements); |
| + }); |
| + } |
| + |
| + Constant compileMetadata(MetadataAnnotation metadata, |
| + Node node, |
| + TreeElements elements) { |
| + return measure(() { |
| + return constantCompiler.compileMetadata(metadata, node, elements); |
| + }); |
| + } |
| +} |
| + |
| /** |
| - * The [ConstantHandler] keeps track of compile-time constants, |
| + * The [ConstantCompilerBase] is used to keeps track of compile-time constants, |
| * initializations of global and static fields, and default values of |
| * optional parameters. |
| */ |
| -class ConstantHandler extends CompilerTask { |
| +abstract class ConstantCompilerBase implements ConstantCompiler { |
| + final Compiler compiler; |
| final ConstantSystem constantSystem; |
| - final bool isMetadata; |
| /** |
| * Contains the initial value of fields. Must contain all static and global |
| @@ -20,66 +98,40 @@ class ConstantHandler extends CompilerTask { |
| * |
| * Invariant: The keys in this map are declarations. |
| */ |
| - final Map<VariableElement, Constant> initialVariableValues; |
| - |
| - /** Set of all registered compiled constants. */ |
| - final Set<Constant> compiledConstants; |
| + final Map<VariableElement, Constant> initialVariableValues = |
| + new Map<VariableElement, Constant>(); |
| /** 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, this.constantSystem, |
| - { bool this.isMetadata: false }) |
| - : initialVariableValues = new Map<VariableElement, dynamic>(), |
| - compiledConstants = new Set<Constant>(), |
| - pendingVariables = new Set<VariableElement>(), |
| - lazyStatics = new Set<VariableElement>(), |
| - super(compiler); |
| + final Set<VariableElement> pendingVariables = new Set<VariableElement>(); |
| - String get name => 'ConstantHandler'; |
| - |
| - void addCompileTimeConstantForEmission(Constant constant) { |
| - compiledConstants.add(constant); |
| - } |
| + ConstantCompilerBase(this.compiler, this.constantSystem); |
| Constant getConstantForVariable(VariableElement element) { |
| return initialVariableValues[element.declaration]; |
| } |
| - /** |
| - * 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.declaration)) { |
| - Constant result = initialVariableValues[element.declaration]; |
| - return result; |
| - } |
| - Element currentElement = element; |
| - if (element.isParameter() |
| - || element.isFieldParameter() |
| - || element.isVariable()) { |
| - currentElement = element.enclosingElement; |
| - } |
| - return compiler.withCurrentElement(currentElement, () { |
| - TreeElements definitions = |
| - compiler.analyzeElement(currentElement.declaration); |
| - Constant constant = compileVariableWithDefinitions( |
| - element, definitions, isConst: isConst); |
| - return constant; |
| - }); |
| + |
| + if (initialVariableValues.containsKey(element.declaration)) { |
| + Constant result = initialVariableValues[element.declaration]; |
| + return result; |
| + } |
| + Element currentElement = element; |
| + if (element.isParameter() || |
| + element.isFieldParameter() || |
| + element.isVariable()) { |
| + currentElement = element.enclosingElement; |
| + } |
| + return compiler.withCurrentElement(currentElement, () { |
| + TreeElements definitions = |
| + compiler.analyzeElement(currentElement.declaration); |
| + Constant constant = compileVariableWithDefinitions( |
| + element, definitions, isConst: isConst); |
| + return constant; |
| }); |
| } |
| @@ -92,149 +144,114 @@ class ConstantHandler extends CompilerTask { |
| Constant compileVariableWithDefinitions(VariableElement element, |
| TreeElements definitions, |
| {bool isConst: false}) { |
| - return measure(() { |
| - if (!isConst && lazyStatics.contains(element)) return null; |
| - |
| - Node node = element.parseNode(compiler); |
| - if (pendingVariables.contains(element)) { |
| - if (isConst) { |
| - compiler.reportFatalError( |
| - node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS); |
| - } else { |
| - lazyStatics.add(element); |
| - return null; |
| - } |
| + Node node = element.parseNode(compiler); |
| + if (pendingVariables.contains(element)) { |
| + if (isConst) { |
| + compiler.reportFatalError( |
| + node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS); |
| } |
| - pendingVariables.add(element); |
| + return null; |
| + } |
| + pendingVariables.add(element); |
| - Expression initializer = element.initializer; |
| - Constant value; |
| - if (initializer == null) { |
| - // No initial value. |
| - value = new NullConstant(); |
| - } else { |
| - value = compileNodeWithDefinitions( |
| - initializer, definitions, isConst: isConst); |
| - if (compiler.enableTypeAssertions && |
| - value != null && |
| - element.isField()) { |
| - DartType elementType = element.type; |
| - if (elementType.kind == TypeKind.MALFORMED_TYPE && !value.isNull) { |
| + Expression initializer = element.initializer; |
| + Constant value; |
| + if (initializer == null) { |
| + // No initial value. |
| + value = new NullConstant(); |
| + } else { |
| + value = compileNodeWithDefinitions( |
| + initializer, definitions, isConst: isConst); |
| + if (compiler.enableTypeAssertions && |
| + value != null && |
| + element.isField()) { |
| + DartType elementType = element.type; |
| + if (elementType.kind == TypeKind.MALFORMED_TYPE && !value.isNull) { |
| + if (isConst) { |
| + ErroneousElement element = elementType.element; |
| + compiler.reportFatalError( |
| + node, element.messageKind, element.messageArguments); |
| + } else { |
| + // We need to throw an exception at runtime. |
| + value = null; |
| + } |
| + } else { |
| + DartType constantType = value.computeType(compiler); |
| + if (!constantSystem.isSubtype(compiler, |
| + constantType, elementType)) { |
| if (isConst) { |
| - ErroneousElement element = elementType.element; |
| compiler.reportFatalError( |
| - node, element.messageKind, element.messageArguments); |
| + node, MessageKind.NOT_ASSIGNABLE, |
| + {'fromType': constantType, 'toType': elementType}); |
| } else { |
| - // We need to throw an exception at runtime. |
| + // If the field cannot be lazily initialized, we will throw |
| + // the exception at runtime. |
| value = null; |
| } |
| - } else { |
| - DartType constantType = value.computeType(compiler); |
| - if (!constantSystem.isSubtype(compiler, |
| - constantType, elementType)) { |
| - if (isConst) { |
| - compiler.reportFatalError( |
| - node, MessageKind.NOT_ASSIGNABLE, |
| - {'fromType': constantType, 'toType': elementType}); |
| - } else { |
| - // If the field cannot be lazily initialized, we will throw |
| - // the exception at runtime. |
| - value = null; |
| - } |
| - } |
| } |
| } |
| } |
| - if (value != null) { |
| - initialVariableValues[element.declaration] = value; |
| - } else { |
| - assert(!isConst); |
| - lazyStatics.add(element); |
| - } |
| - pendingVariables.remove(element); |
| - return value; |
| - }); |
| + } |
| + if (value != null) { |
| + initialVariableValues[element.declaration] = value; |
| + } else { |
| + assert(!isConst); |
| + } |
| + pendingVariables.remove(element); |
| + return value; |
| } |
| Constant compileNodeWithDefinitions(Node node, |
| TreeElements definitions, |
| - {bool isConst: false}) { |
| - return measure(() { |
| - assert(node != null); |
| - Constant constant = definitions.getConstant(node); |
| - if (constant != null) { |
| - return constant; |
| - } |
| - CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( |
| - this, definitions, compiler, isConst: isConst); |
| - constant = evaluator.evaluate(node); |
| - if (constant != null) { |
| - definitions.setConstant(node, constant); |
| - } |
| - return constant; |
| - }); |
| + {bool isConst: true}) { |
| + assert(node != null); |
| + CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( |
| + this, definitions, compiler, isConst: isConst); |
| + return evaluator.evaluate(node); |
| } |
| - /** |
| - * Returns an [Iterable] of static non final fields that need to be |
| - * initialized. The fields list must be evaluated in order since they might |
| - * depend on each other. |
| - */ |
| - Iterable<VariableElement> getStaticNonFinalFieldsForEmission() { |
| - return initialVariableValues.keys.where((element) { |
| - return element.kind == ElementKind.FIELD |
| - && !element.isInstanceMember() |
| - && !element.modifiers.isFinal() |
| - // The const fields are all either emitted elsewhere or inlined. |
| - && !element.modifiers.isConst(); |
| - }); |
| + Constant compileNode(Node node, TreeElements elements) { |
| + return compileNodeWithDefinitions(node, elements); |
| } |
| - List<VariableElement> getLazilyInitializedFieldsForEmission() { |
| - return new List<VariableElement>.from(lazyStatics); |
| + Constant compileMetadata(MetadataAnnotation metadata, |
| + Node node, |
| + TreeElements elements) { |
| + return compileNodeWithDefinitions(node, elements); |
| } |
| +} |
| - /** |
| - * Returns a list of constants topologically sorted so that dependencies |
| - * appear before the dependent constant. [preSortCompare] is a comparator |
| - * function that gives the constants a consistent order prior to the |
| - * topological sort which gives the constants an ordering that is less |
| - * sensitive to perturbations in the source code. |
| - */ |
| - List<Constant> getConstantsForEmission([preSortCompare]) { |
| - // We must emit dependencies before their uses. |
| - Set<Constant> seenConstants = new Set<Constant>(); |
| - List<Constant> result = new List<Constant>(); |
| - |
| - void addConstant(Constant constant) { |
| - if (!seenConstants.contains(constant)) { |
| - constant.getDependencies().forEach(addConstant); |
| - assert(!seenConstants.contains(constant)); |
| - result.add(constant); |
| - seenConstants.add(constant); |
| - } |
| - } |
| +class DartConstantCompiler extends ConstantCompilerBase { |
| + DartConstantCompiler(Compiler compiler) |
| + : super(compiler, const DartConstantSystem()); |
| - List<Constant> sorted = compiledConstants.toList(); |
| - if (preSortCompare != null) { |
| - sorted.sort(preSortCompare); |
| - } |
| - sorted.forEach(addConstant); |
| - return result; |
| + Constant getConstantForNode(Node node, TreeElements definitions) { |
| + return definitions.getConstant(node); |
| } |
| - Constant getInitialValueFor(VariableElement element) { |
| - Constant initialValue = initialVariableValues[element.declaration]; |
| - if (initialValue == null) { |
| - compiler.internalError(element, "No initial value for given element."); |
| + Constant getConstantForMetadata(MetadataAnnotation metadata) { |
| + return metadata.value; |
| + } |
| + |
| + Constant compileNodeWithDefinitions(Node node, |
| + TreeElements definitions, |
| + {bool isConst: true}) { |
| + Constant constant = definitions.getConstant(node); |
| + if (constant != null) { |
| + return constant; |
| + } |
| + constant = |
| + super.compileNodeWithDefinitions(node, definitions, isConst: isConst); |
| + if (constant != null) { |
| + definitions.setConstant(node, constant); |
| } |
| - return initialValue; |
| + return constant; |
| } |
| } |
| class CompileTimeConstantEvaluator extends Visitor { |
| bool isEvaluatingConstant; |
| - final ConstantHandler handler; |
| + final ConstantCompilerBase handler; |
| final TreeElements elements; |
| final Compiler compiler; |
| @@ -440,6 +457,14 @@ class CompileTimeConstantEvaluator extends Visitor { |
| return false; |
| } |
| + Constant visitIdentifier(Identifier node) { |
| + Element element = elements[node]; |
| + if (Elements.isClass(element) || Elements.isTypedef(element)) { |
| + return makeTypeConstant(element); |
| + } |
| + return signalNotCompileTimeConstant(node); |
| + } |
| + |
| // TODO(floitsch): provide better error-messages. |
| Constant visitSend(Send send) { |
| Element element = elements[send]; |
| @@ -477,11 +502,6 @@ class CompileTimeConstantEvaluator extends Visitor { |
| Constant right = evaluate(send.argumentsNode.nodes.tail.head); |
| Constant result = constantSystem.identity.fold(left, right); |
| if (result != null) return result; |
| - } else if (Elements.isClass(element) || Elements.isTypedef(element)) { |
| - // The node itself is not a constant but we register the selector (the |
| - // identifier that refers to the class/typedef) as a constant. |
| - Constant typeConstant = makeTypeConstant(element); |
| - elements.setConstant(send.selector, typeConstant); |
| } |
| return signalNotCompileTimeConstant(send); |
| } else if (send.isPrefix) { |
| @@ -810,7 +830,7 @@ class ConstructorEvaluator extends CompileTimeConstantEvaluator { |
| * Invariant: [constructor] must be an implementation element. |
| */ |
| ConstructorEvaluator(FunctionElement constructor, |
| - ConstantHandler handler, |
| + ConstantCompiler handler, |
| Compiler compiler) |
| : this.constructor = constructor, |
| this.definitions = new Map<Element, Constant>(), |
| @@ -843,6 +863,8 @@ class ConstructorEvaluator extends CompileTimeConstantEvaluator { |
| // TODO(ngeoffray): Handle type parameters. |
| if (elementType.element.isTypeVariable()) return; |
| if (!constantSystem.isSubtype(compiler, constantType, elementType)) { |
| + // TODO(johnniwinther): Provide better [node] values that point to the |
| + // origin of the constant and not (just) the assignment. |
| compiler.reportFatalError( |
| node, MessageKind.NOT_ASSIGNABLE, |
| {'fromType': elementType, 'toType': constantType}); |