| // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import '../compile_time_constants.dart'; |
| import '../compiler.dart' show Compiler; |
| import '../constants/constant_system.dart'; |
| import '../constants/expressions.dart'; |
| import '../constants/values.dart'; |
| import '../elements/elements.dart'; |
| import '../elements/entities.dart'; |
| import '../elements/visitor.dart' show BaseElementVisitor; |
| import '../resolution/tree_elements.dart' show TreeElements; |
| import '../tree/tree.dart'; |
| import 'constant_system_javascript.dart'; |
| |
| /// [ConstantCompilerTask] for compilation of constants for the JavaScript |
| /// backend. |
| /// |
| /// Since this task needs to distinguish between frontend and backend constants |
| /// the actual compilation of the constants is forwarded to a |
| /// [DartConstantCompiler] for the frontend interpretation of the constants and |
| /// to a [JavaScriptConstantCompiler] for the backend interpretation. |
| class JavaScriptConstantTask extends ConstantCompilerTask { |
| DartConstantCompiler dartConstantCompiler; |
| JavaScriptConstantCompiler jsConstantCompiler; |
| |
| JavaScriptConstantTask(Compiler compiler) |
| : this.dartConstantCompiler = new DartConstantCompiler(compiler), |
| this.jsConstantCompiler = new JavaScriptConstantCompiler(compiler), |
| super(compiler.measurer); |
| |
| String get name => 'ConstantHandler'; |
| |
| @override |
| ConstantSystem get constantSystem => dartConstantCompiler.constantSystem; |
| |
| @override |
| bool hasConstantValue(ConstantExpression expression) { |
| return dartConstantCompiler.hasConstantValue(expression); |
| } |
| |
| @override |
| ConstantValue getConstantValue(ConstantExpression expression) { |
| return dartConstantCompiler.getConstantValue(expression); |
| } |
| |
| @override |
| ConstantValue getConstantValueForVariable(VariableElement element) { |
| return dartConstantCompiler.getConstantValueForVariable(element); |
| } |
| |
| @override |
| ConstantExpression compileConstant(VariableElement element) { |
| return measure(() { |
| // TODO(het): Only report errors from one of the constant compilers |
| ConstantExpression result = dartConstantCompiler.compileConstant(element); |
| jsConstantCompiler.compileConstant(element); |
| return result; |
| }); |
| } |
| |
| @override |
| void evaluate(ConstantExpression constant) { |
| return measure(() { |
| dartConstantCompiler.evaluate(constant); |
| jsConstantCompiler.evaluate(constant); |
| }); |
| } |
| |
| @override |
| ConstantExpression compileVariable(VariableElement element) { |
| return measure(() { |
| return jsConstantCompiler.compileVariable(element); |
| }); |
| } |
| |
| ConstantExpression compileNode(Node node, TreeElements elements, |
| {bool enforceConst: true}) { |
| return measure(() { |
| ConstantExpression result = dartConstantCompiler |
| .compileNode(node, elements, enforceConst: enforceConst); |
| jsConstantCompiler.compileNode(node, elements, |
| enforceConst: enforceConst); |
| return result; |
| }); |
| } |
| |
| ConstantExpression compileMetadata( |
| MetadataAnnotation metadata, Node node, TreeElements elements) { |
| return measure(() { |
| ConstantExpression constant = |
| dartConstantCompiler.compileMetadata(metadata, node, elements); |
| jsConstantCompiler.compileMetadata(metadata, node, elements); |
| return constant; |
| }); |
| } |
| |
| // TODO(johnniwinther): Remove this when values are computed from the |
| // expressions. |
| @override |
| void copyConstantValues(covariant JavaScriptConstantTask task) { |
| jsConstantCompiler.constantValueMap |
| .addAll(task.jsConstantCompiler.constantValueMap); |
| dartConstantCompiler.constantValueMap |
| .addAll(task.dartConstantCompiler.constantValueMap); |
| } |
| } |
| |
| /** |
| * The [JavaScriptConstantCompiler] is used to keep track of compile-time |
| * constants, initializations of global and static fields, and default values of |
| * optional parameters for the JavaScript interpretation of constants. |
| */ |
| class JavaScriptConstantCompiler extends ConstantCompilerBase |
| implements BackendConstantEnvironment { |
| // TODO(johnniwinther): Move this to the backend constant handler. |
| /** Caches the statics where the initial value cannot be eagerly compiled. */ |
| final Set<FieldEntity> lazyStatics = new Set<FieldEntity>(); |
| |
| // Constants computed for constant expressions. |
| final Map<Node, ConstantExpression> nodeConstantMap = |
| new Map<Node, ConstantExpression>(); |
| |
| // Constants computed for metadata. |
| // TODO(johnniwinther): Remove this when no longer used by |
| // poi/forget_element_test. |
| final Map<MetadataAnnotation, ConstantExpression> metadataConstantMap = |
| new Map<MetadataAnnotation, ConstantExpression>(); |
| |
| JavaScriptConstantCompiler(Compiler compiler) |
| : super(compiler, JAVA_SCRIPT_CONSTANT_SYSTEM); |
| |
| ConstantExpression compileVariableWithDefinitions( |
| VariableElement element, TreeElements definitions, |
| {bool isConst: false, bool checkType: true}) { |
| if (!isConst && lazyStatics.contains(element)) { |
| return null; |
| } |
| ConstantExpression value = super.compileVariableWithDefinitions( |
| element, definitions, |
| isConst: isConst, checkType: checkType); |
| if (!isConst && value == null) { |
| FieldElement field = element; |
| registerLazyStatic(field); |
| } |
| return value; |
| } |
| |
| @override |
| void registerLazyStatic(FieldEntity element) { |
| lazyStatics.add(element); |
| } |
| |
| List<FieldEntity> getLazilyInitializedFieldsForEmission() { |
| return new List<FieldEntity>.from(lazyStatics); |
| } |
| |
| ConstantExpression compileNode(Node node, TreeElements elements, |
| {bool enforceConst: true}) { |
| return compileNodeWithDefinitions(node, elements, isConst: enforceConst); |
| } |
| |
| ConstantExpression compileNodeWithDefinitions( |
| Node node, TreeElements definitions, |
| {bool isConst: true}) { |
| ConstantExpression constant = nodeConstantMap[node]; |
| if (constant != null && getConstantValue(constant) != null) { |
| return constant; |
| } |
| constant = |
| super.compileNodeWithDefinitions(node, definitions, isConst: isConst); |
| if (constant != null) { |
| nodeConstantMap[node] = constant; |
| } |
| return constant; |
| } |
| |
| ConstantValue getConstantValueForNode(Node node, TreeElements definitions) { |
| return getConstantValue(getConstantForNode(node, definitions)); |
| } |
| |
| ConstantExpression getConstantForNode(Node node, TreeElements definitions) { |
| ConstantExpression constant = nodeConstantMap[node]; |
| if (constant != null) { |
| return constant; |
| } |
| return definitions.getConstant(node); |
| } |
| |
| ConstantValue getConstantValueForMetadata(MetadataAnnotation metadata) { |
| return getConstantValue(metadata.constant); |
| } |
| |
| @override |
| ConstantExpression compileMetadata( |
| MetadataAnnotation metadata, Node node, TreeElements elements) { |
| ConstantExpression constant = |
| super.compileMetadata(metadata, node, elements); |
| metadataConstantMap[metadata] = constant; |
| return constant; |
| } |
| } |
| |
| class ForgetConstantElementVisitor |
| extends BaseElementVisitor<dynamic, JavaScriptConstantCompiler> { |
| const ForgetConstantElementVisitor(); |
| |
| void visitElement(Element e, JavaScriptConstantCompiler constants) { |
| for (MetadataAnnotation data in e.implementation.metadata) { |
| constants.metadataConstantMap.remove(data); |
| if (data.hasNode) { |
| data.node.accept(new ForgetConstantNodeVisitor(constants)); |
| } |
| } |
| } |
| |
| void visitFunctionElement( |
| FunctionElement e, JavaScriptConstantCompiler constants) { |
| super.visitFunctionElement(e, constants); |
| if (e.hasFunctionSignature) { |
| e.functionSignature.forEachParameter((p) => visit(p, constants)); |
| } |
| } |
| } |
| |
| class ForgetConstantNodeVisitor extends Visitor { |
| final JavaScriptConstantCompiler constants; |
| |
| ForgetConstantNodeVisitor(this.constants); |
| |
| void visitNode(Node node) { |
| node.visitChildren(this); |
| constants.nodeConstantMap.remove(node); |
| } |
| } |