Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of dart2js.ir_builder; | 5 part of dart2js.ir_builder; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * This task iterates through all resolved elements and builds [ir.Node]s. The | 8 * This task iterates through all resolved elements and builds [ir.Node]s. The |
| 9 * nodes are stored in the [nodes] map and accessible through [hasIr] and | 9 * nodes are stored in the [nodes] map and accessible through [hasIr] and |
| 10 * [getIr]. | 10 * [getIr]. |
| 11 * | 11 * |
| 12 * The functionality of the IrNodes is added gradually, therefore elements might | 12 * The functionality of the IrNodes is added gradually, therefore elements might |
| 13 * have an IR or not, depending on the language features that are used. For | 13 * have an IR or not, depending on the language features that are used. For |
| 14 * elements that do have an IR, the tree [ast.Node]s and the [Token]s are not | 14 * elements that do have an IR, the tree [ast.Node]s and the [Token]s are not |
| 15 * used in the rest of the compilation. This is ensured by setting the element's | 15 * used in the rest of the compilation. This is ensured by setting the element's |
| 16 * cached tree to `null` and also breaking the token stream to crash future | 16 * cached tree to `null` and also breaking the token stream to crash future |
| 17 * attempts to parse. | 17 * attempts to parse. |
| 18 * | 18 * |
| 19 * The type inferrer works on either IR nodes or tree nodes. The IR nodes are | 19 * The type inferrer works on either IR nodes or tree nodes. The IR nodes are |
| 20 * then translated into the SSA form for optimizations and code generation. | 20 * then translated into the SSA form for optimizations and code generation. |
| 21 * Long-term, once the IR supports the full language, the backend can be | 21 * Long-term, once the IR supports the full language, the backend can be |
| 22 * re-implemented to work directly on the IR. | 22 * re-implemented to work directly on the IR. |
| 23 */ | 23 */ |
| 24 class IrBuilderTask extends CompilerTask { | 24 class IrBuilderTask extends CompilerTask { |
| 25 final Map<Element, ir.FunctionDefinition> nodes = | 25 final Map<Element, ir.ExecutableDefinition> nodes = |
| 26 <Element, ir.FunctionDefinition>{}; | 26 <Element, ir.ExecutableDefinition>{}; |
| 27 | 27 |
| 28 IrBuilderTask(Compiler compiler) : super(compiler); | 28 IrBuilderTask(Compiler compiler) : super(compiler); |
| 29 | 29 |
| 30 String get name => 'IR builder'; | 30 String get name => 'IR builder'; |
| 31 | 31 |
| 32 bool hasIr(Element element) => nodes.containsKey(element.implementation); | 32 bool hasIr(Element element) => nodes.containsKey(element.implementation); |
| 33 | 33 |
| 34 ir.FunctionDefinition getIr(Element element) => nodes[element.implementation]; | 34 ir.ExecutableDefinition getIr(ExecutableElement element) { |
| 35 return nodes[element.implementation]; | |
| 36 } | |
| 35 | 37 |
| 36 ir.FunctionDefinition buildNode(AstElement element) { | 38 ir.ExecutableDefinition buildNode(AstElement element) { |
| 37 if (!canBuild(element)) return null; | 39 if (!canBuild(element)) return null; |
| 38 TreeElements elementsMapping = element.resolvedAst.elements; | 40 TreeElements elementsMapping = element.resolvedAst.elements; |
| 39 element = element.implementation; | 41 element = element.implementation; |
| 40 return compiler.withCurrentElement(element, () { | 42 return compiler.withCurrentElement(element, () { |
| 41 SourceFile sourceFile = elementSourceFile(element); | 43 SourceFile sourceFile = elementSourceFile(element); |
| 42 IrBuilderVisitor builder = | 44 IrBuilderVisitor builder = |
| 43 new IrBuilderVisitor(elementsMapping, compiler, sourceFile); | 45 new IrBuilderVisitor(elementsMapping, compiler, sourceFile); |
| 44 return builder.buildFunction(element); | 46 return builder.buildExecutable(element); |
| 45 }); | 47 }); |
| 46 } | 48 } |
| 47 | 49 |
| 48 void buildNodes() { | 50 void buildNodes() { |
| 49 measure(() { | 51 measure(() { |
| 50 Set<Element> resolved = compiler.enqueuer.resolution.resolvedElements; | 52 Set<Element> resolved = compiler.enqueuer.resolution.resolvedElements; |
| 51 resolved.forEach((AstElement element) { | 53 resolved.forEach((AstElement element) { |
| 52 ir.FunctionDefinition functionDefinition = buildNode(element); | 54 ir.ExecutableDefinition definition = buildNode(element); |
| 53 if (functionDefinition != null) { | 55 if (definition != null) { |
| 54 nodes[element] = functionDefinition; | 56 nodes[element] = definition; |
| 55 } | 57 } |
| 56 }); | 58 }); |
| 57 }); | 59 }); |
| 58 } | 60 } |
| 59 | 61 |
| 62 bool canBuild(Element element) { | |
| 63 if (element is TypedefElement) return false; | |
| 64 if (element is FunctionElement) { | |
| 65 // TODO(sigurdm): Support native functions for dart2js. | |
| 66 assert(invariant(element, !element.isNative)); | |
| 60 | 67 |
| 61 bool canBuild(Element element) { | 68 // TODO(kmillikin,sigurdm): Support constructors. |
| 62 FunctionElement function = element.asFunctionElement(); | 69 if (element is ConstructorElement) return false; |
| 63 // TODO(kmillikin,sigurdm): support lazy field initializers. | |
| 64 if (function == null) return false; | |
| 65 | 70 |
| 66 if (!compiler.backend.shouldOutput(function)) return false; | 71 } else if (element is! FieldElement) { |
| 67 | 72 compiler.internalError(element, "Unexpected elementtype $element"); |
| 68 assert(invariant(element, !function.isNative)); | 73 } |
| 69 | 74 return compiler.backend.shouldOutput(element); |
| 70 // TODO(kmillikin,sigurdm): Support constructors. | |
| 71 if (function is ConstructorElement) return false; | |
| 72 | |
| 73 return true; | |
| 74 } | 75 } |
| 75 | 76 |
| 76 bool get inCheckedMode { | 77 bool get inCheckedMode { |
| 77 bool result = false; | 78 bool result = false; |
| 78 assert((result = true)); | 79 assert((result = true)); |
| 79 return result; | 80 return result; |
| 80 } | 81 } |
| 81 | 82 |
| 82 SourceFile elementSourceFile(Element element) { | 83 SourceFile elementSourceFile(Element element) { |
| 83 if (element is FunctionElement) { | 84 if (element is FunctionElement) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 122 // assigned in the delimited subexpression to their reaching definition --- | 123 // assigned in the delimited subexpression to their reaching definition --- |
| 123 // that is, the definition in effect at the hole in 'current'. These are | 124 // that is, the definition in effect at the hole in 'current'. These are |
| 124 // used to determine if a join-point continuation needs to be passed | 125 // used to determine if a join-point continuation needs to be passed |
| 125 // arguments, and what the arguments are. | 126 // arguments, and what the arguments are. |
| 126 | 127 |
| 127 /// Construct a top-level visitor. | 128 /// Construct a top-level visitor. |
| 128 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile) | 129 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile) |
| 129 : super(elements); | 130 : super(elements); |
| 130 | 131 |
| 131 /** | 132 /** |
| 132 * Builds the [ir.FunctionDefinition] for a function element. In case the | 133 * Builds the [ir.ExecutableDefinition] for an executable element. In case the |
| 133 * function uses features that cannot be expressed in the IR, this function | 134 * function uses features that cannot be expressed in the IR, this element |
| 134 * returns `null`. | 135 * returns `null`. |
| 135 */ | 136 */ |
| 136 ir.FunctionDefinition buildFunction(FunctionElement functionElement) { | 137 ir.ExecutableDefinition buildExecutable(ExecutableElement element) { |
| 137 return nullIfGiveup(() => buildFunctionInternal(functionElement)); | 138 return nullIfGiveup(() { |
| 139 if (element is FieldElement) { | |
| 140 return buildField(element); | |
| 141 } else if (element is FunctionElement) { | |
| 142 return buildFunction(element); | |
| 143 } else { | |
| 144 compiler.internalError(element, "Unexpected element type $element"); | |
| 145 } | |
| 146 }); | |
| 138 } | 147 } |
| 139 | 148 |
| 140 ir.FunctionDefinition buildFunctionInternal(FunctionElement element) { | 149 ir.FieldDefinition buildField(FieldElement element) { |
| 150 assert(invariant(element, element.isImplementation)); | |
| 151 ast.VariableDefinitions definitions = element.node; | |
| 152 ast.Node fieldDefinition = | |
| 153 definitions.definitions.nodes.first; | |
|
Kevin Millikin (Google)
2014/11/26 13:31:29
Indent.
sigurdm
2014/11/26 14:38:43
Done.
| |
| 154 if (definitions.modifiers.isConst) { | |
| 155 // TODO(sigurdm): Just return const value. | |
| 156 } | |
| 157 assert(fieldDefinition != null); | |
| 158 assert(elements[fieldDefinition] != null); | |
| 159 if (fieldDefinition is! ast.SendSet) return null; | |
|
Kevin Millikin (Google)
2014/11/26 13:31:29
Is this the case that there is no initializer? It
sigurdm
2014/11/26 14:38:43
Done.
| |
| 160 DetectClosureVariables closureLocals = | |
| 161 new DetectClosureVariables(elements); | |
|
Kevin Millikin (Google)
2014/11/26 13:31:29
Indent.
sigurdm
2014/11/26 14:38:43
Done.
| |
| 162 closureLocals.visit(fieldDefinition); | |
| 163 | |
| 164 IrBuilder builder = new IrBuilder(compiler.backend.constantSystem, | |
| 165 element, | |
| 166 closureLocals.usedFromClosure); | |
| 167 return withBuilder( | |
| 168 builder, () { | |
|
Kevin Millikin (Google)
2014/11/26 13:31:29
This needs a 4-space indent. I prefer
return wit
sigurdm
2014/11/26 14:38:43
Done.
| |
| 169 ast.SendSet sendSet = fieldDefinition; | |
| 170 ir.Primitive result = visit(sendSet.arguments.first); | |
| 171 builder.buildReturn(result); | |
| 172 return builder.makeFieldDefinition(); | |
| 173 }); | |
| 174 } | |
| 175 | |
| 176 ir.FunctionDefinition buildFunction(FunctionElement element) { | |
| 141 assert(invariant(element, element.isImplementation)); | 177 assert(invariant(element, element.isImplementation)); |
| 142 ast.FunctionExpression function = element.node; | 178 ast.FunctionExpression function = element.node; |
| 143 assert(function != null); | 179 assert(function != null); |
| 144 assert(elements[function] != null); | 180 assert(elements[function] != null); |
| 145 | 181 |
| 146 DetectClosureVariables closureLocals = new DetectClosureVariables(elements); | 182 DetectClosureVariables closureLocals = new DetectClosureVariables(elements); |
| 147 closureLocals.visit(function); | 183 closureLocals.visit(function); |
| 148 | 184 |
| 149 return withBuilder( | 185 return withBuilder( |
| 150 new IrBuilder(compiler.backend.constantSystem, | 186 new IrBuilder(compiler.backend.constantSystem, |
| 151 element, closureLocals.usedFromClosure), | 187 element, closureLocals.usedFromClosure), |
| 152 () { | 188 () { |
| 153 FunctionSignature signature = element.functionSignature; | 189 FunctionSignature signature = element.functionSignature; |
| 154 signature.orderedForEachParameter((ParameterElement parameterElement) { | 190 signature.orderedForEachParameter((ParameterElement parameterElement) { |
| 155 irBuilder.createParameter(parameterElement); | 191 irBuilder.createParameter(parameterElement); |
| 156 }); | 192 }); |
| 157 | 193 |
| 158 List<ConstantExpression> defaults = new List<ConstantExpression>(); | 194 List<ConstantExpression> defaults = new List<ConstantExpression>(); |
| 159 signature.orderedOptionalParameters.forEach((ParameterElement element) { | 195 signature.orderedOptionalParameters.forEach((ParameterElement element) { |
| 160 defaults.add(getConstantForVariable(element)); | 196 defaults.add(getConstantForVariable(element)); |
| 161 }); | 197 }); |
| 162 | 198 |
| 163 visit(function.body); | 199 visit(function.body); |
| 164 return irBuilder.buildFunctionDefinition(element, defaults); | 200 return irBuilder.buildFunctionDefinition(defaults); |
| 165 }); | 201 }); |
| 166 } | 202 } |
| 167 | 203 |
| 168 ir.Primitive visit(ast.Node node) => node.accept(this); | 204 ir.Primitive visit(ast.Node node) => node.accept(this); |
| 169 | 205 |
| 170 // ==== Statements ==== | 206 // ==== Statements ==== |
| 171 visitBlock(ast.Block node) { | 207 visitBlock(ast.Block node) { |
| 172 irBuilder.buildBlock(node.statements.nodes, build); | 208 irBuilder.buildBlock(node.statements.nodes, build); |
| 173 } | 209 } |
| 174 | 210 |
| (...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 799 | 835 |
| 800 ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) { | 836 ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) { |
| 801 assert(irBuilder.isOpen); | 837 assert(irBuilder.isOpen); |
| 802 if (constant == null) { | 838 if (constant == null) { |
| 803 constant = getConstantForNode(node); | 839 constant = getConstantForNode(node); |
| 804 } | 840 } |
| 805 return irBuilder.buildConstantLiteral(constant); | 841 return irBuilder.buildConstantLiteral(constant); |
| 806 } | 842 } |
| 807 | 843 |
| 808 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) { | 844 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) { |
| 809 return buildFunctionInternal(elements[node]); | 845 return buildFunction(elements[node]); |
| 810 } | 846 } |
| 811 | 847 |
| 812 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { | 848 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { |
| 813 return irBuilder.buildFunctionExpression(makeSubFunction(node)); | 849 return irBuilder.buildFunctionExpression(makeSubFunction(node)); |
| 814 } | 850 } |
| 815 | 851 |
| 816 visitFunctionDeclaration(ast.FunctionDeclaration node) { | 852 visitFunctionDeclaration(ast.FunctionDeclaration node) { |
| 817 LocalFunctionElement element = elements[node.function]; | 853 LocalFunctionElement element = elements[node.function]; |
| 818 ir.FunctionDefinition inner = makeSubFunction(node.function); | 854 ir.FunctionDefinition inner = makeSubFunction(node.function); |
| 819 irBuilder.declareLocalFunction(element, inner); | 855 irBuilder.declareLocalFunction(element, inner); |
| 820 } | 856 } |
| 821 | 857 |
| 822 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; | 858 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; |
| 823 | 859 |
| 824 dynamic giveup(ast.Node node, [String reason]) { | 860 dynamic giveup(ast.Node node, [String reason]) { |
| 825 throw ABORT_IRNODE_BUILDER; | 861 throw ABORT_IRNODE_BUILDER; |
| 826 } | 862 } |
| 827 | 863 |
| 828 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) { | 864 ir.ExecutableDefinition nullIfGiveup(ir.ExecutableDefinition action()) { |
| 829 try { | 865 try { |
| 830 return action(); | 866 return action(); |
| 831 } catch(e, tr) { | 867 } catch(e, tr) { |
| 832 if (e == ABORT_IRNODE_BUILDER) { | 868 if (e == ABORT_IRNODE_BUILDER) { |
| 833 return null; | 869 return null; |
| 834 } | 870 } |
| 835 rethrow; | 871 rethrow; |
| 836 } | 872 } |
| 837 } | 873 } |
| 838 | 874 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 875 node.visitChildren(this); | 911 node.visitChildren(this); |
| 876 } | 912 } |
| 877 | 913 |
| 878 visitFunctionExpression(ast.FunctionExpression node) { | 914 visitFunctionExpression(ast.FunctionExpression node) { |
| 879 FunctionElement oldFunction = currentFunction; | 915 FunctionElement oldFunction = currentFunction; |
| 880 currentFunction = elements[node]; | 916 currentFunction = elements[node]; |
| 881 visit(node.body); | 917 visit(node.body); |
| 882 currentFunction = oldFunction; | 918 currentFunction = oldFunction; |
| 883 } | 919 } |
| 884 } | 920 } |
| OLD | NEW |