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 /// Returns a [ir.FieldDefinition] describing the initializer of [element]. |
| 150 /// Returns `null` if [element] has no initializer. |
| 151 ir.FieldDefinition buildField(FieldElement element) { |
| 152 assert(invariant(element, element.isImplementation)); |
| 153 ast.VariableDefinitions definitions = element.node; |
| 154 ast.Node fieldDefinition = |
| 155 definitions.definitions.nodes.first; |
| 156 if (definitions.modifiers.isConst) { |
| 157 // TODO(sigurdm): Just return const value. |
| 158 } |
| 159 assert(fieldDefinition != null); |
| 160 assert(elements[fieldDefinition] != null); |
| 161 // This means there is no initializer. |
| 162 // TODO(sigurdm): Avoid ever getting here. Abstract functions and fields |
| 163 // with no initializer should not have a representation in the IR. |
| 164 if (fieldDefinition is! ast.SendSet) return null; |
| 165 DetectClosureVariables closureLocals = |
| 166 new DetectClosureVariables(elements); |
| 167 closureLocals.visit(fieldDefinition); |
| 168 |
| 169 IrBuilder builder = new IrBuilder(compiler.backend.constantSystem, |
| 170 element, |
| 171 closureLocals.usedFromClosure); |
| 172 return withBuilder(builder, () { |
| 173 ast.SendSet sendSet = fieldDefinition; |
| 174 ir.Primitive result = visit(sendSet.arguments.first); |
| 175 builder.buildReturn(result); |
| 176 return builder.makeFieldDefinition(); |
| 177 }); |
| 178 } |
| 179 |
| 180 ir.FunctionDefinition buildFunction(FunctionElement element) { |
141 assert(invariant(element, element.isImplementation)); | 181 assert(invariant(element, element.isImplementation)); |
142 ast.FunctionExpression function = element.node; | 182 ast.FunctionExpression function = element.node; |
143 assert(function != null); | 183 assert(function != null); |
144 assert(elements[function] != null); | 184 assert(elements[function] != null); |
145 | 185 |
146 DetectClosureVariables closureLocals = new DetectClosureVariables(elements); | 186 DetectClosureVariables closureLocals = new DetectClosureVariables(elements); |
147 closureLocals.visit(function); | 187 closureLocals.visit(function); |
148 | 188 |
149 return withBuilder( | 189 return withBuilder( |
150 new IrBuilder(compiler.backend.constantSystem, | 190 new IrBuilder(compiler.backend.constantSystem, |
151 element, closureLocals.usedFromClosure), | 191 element, closureLocals.usedFromClosure), |
152 () { | 192 () { |
153 FunctionSignature signature = element.functionSignature; | 193 FunctionSignature signature = element.functionSignature; |
154 signature.orderedForEachParameter((ParameterElement parameterElement) { | 194 signature.orderedForEachParameter((ParameterElement parameterElement) { |
155 irBuilder.createParameter(parameterElement); | 195 irBuilder.createParameter(parameterElement); |
156 }); | 196 }); |
157 | 197 |
158 List<ConstantExpression> defaults = new List<ConstantExpression>(); | 198 List<ConstantExpression> defaults = new List<ConstantExpression>(); |
159 signature.orderedOptionalParameters.forEach((ParameterElement element) { | 199 signature.orderedOptionalParameters.forEach((ParameterElement element) { |
160 defaults.add(getConstantForVariable(element)); | 200 defaults.add(getConstantForVariable(element)); |
161 }); | 201 }); |
162 | 202 |
163 visit(function.body); | 203 visit(function.body); |
164 return irBuilder.buildFunctionDefinition(element, defaults); | 204 return irBuilder.buildFunctionDefinition(defaults); |
165 }); | 205 }); |
166 } | 206 } |
167 | 207 |
168 ir.Primitive visit(ast.Node node) => node.accept(this); | 208 ir.Primitive visit(ast.Node node) => node.accept(this); |
169 | 209 |
170 // ==== Statements ==== | 210 // ==== Statements ==== |
171 visitBlock(ast.Block node) { | 211 visitBlock(ast.Block node) { |
172 irBuilder.buildBlock(node.statements.nodes, build); | 212 irBuilder.buildBlock(node.statements.nodes, build); |
173 } | 213 } |
174 | 214 |
(...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
799 | 839 |
800 ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) { | 840 ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) { |
801 assert(irBuilder.isOpen); | 841 assert(irBuilder.isOpen); |
802 if (constant == null) { | 842 if (constant == null) { |
803 constant = getConstantForNode(node); | 843 constant = getConstantForNode(node); |
804 } | 844 } |
805 return irBuilder.buildConstantLiteral(constant); | 845 return irBuilder.buildConstantLiteral(constant); |
806 } | 846 } |
807 | 847 |
808 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) { | 848 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) { |
809 return buildFunctionInternal(elements[node]); | 849 return buildFunction(elements[node]); |
810 } | 850 } |
811 | 851 |
812 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { | 852 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { |
813 return irBuilder.buildFunctionExpression(makeSubFunction(node)); | 853 return irBuilder.buildFunctionExpression(makeSubFunction(node)); |
814 } | 854 } |
815 | 855 |
816 visitFunctionDeclaration(ast.FunctionDeclaration node) { | 856 visitFunctionDeclaration(ast.FunctionDeclaration node) { |
817 LocalFunctionElement element = elements[node.function]; | 857 LocalFunctionElement element = elements[node.function]; |
818 ir.FunctionDefinition inner = makeSubFunction(node.function); | 858 ir.FunctionDefinition inner = makeSubFunction(node.function); |
819 irBuilder.declareLocalFunction(element, inner); | 859 irBuilder.declareLocalFunction(element, inner); |
820 } | 860 } |
821 | 861 |
822 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; | 862 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; |
823 | 863 |
824 dynamic giveup(ast.Node node, [String reason]) { | 864 dynamic giveup(ast.Node node, [String reason]) { |
825 throw ABORT_IRNODE_BUILDER; | 865 throw ABORT_IRNODE_BUILDER; |
826 } | 866 } |
827 | 867 |
828 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) { | 868 ir.ExecutableDefinition nullIfGiveup(ir.ExecutableDefinition action()) { |
829 try { | 869 try { |
830 return action(); | 870 return action(); |
831 } catch(e, tr) { | 871 } catch(e, tr) { |
832 if (e == ABORT_IRNODE_BUILDER) { | 872 if (e == ABORT_IRNODE_BUILDER) { |
833 return null; | 873 return null; |
834 } | 874 } |
835 rethrow; | 875 rethrow; |
836 } | 876 } |
837 } | 877 } |
838 | 878 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
875 node.visitChildren(this); | 915 node.visitChildren(this); |
876 } | 916 } |
877 | 917 |
878 visitFunctionExpression(ast.FunctionExpression node) { | 918 visitFunctionExpression(ast.FunctionExpression node) { |
879 FunctionElement oldFunction = currentFunction; | 919 FunctionElement oldFunction = currentFunction; |
880 currentFunction = elements[node]; | 920 currentFunction = elements[node]; |
881 visit(node.body); | 921 visit(node.body); |
882 currentFunction = oldFunction; | 922 currentFunction = oldFunction; |
883 } | 923 } |
884 } | 924 } |
OLD | NEW |