OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
ngeoffray
2013/11/21 15:02:05
Please add high-level comments on classes in this
lukas
2013/11/21 17:14:27
Done.
| |
4 | |
5 library ir_builder; | |
6 | |
7 import 'ir_nodes.dart'; | |
8 import '../elements/elements.dart'; | |
9 import '../dart2jslib.dart'; | |
10 import '../source_file.dart'; | |
11 import '../tree/tree.dart'; | |
12 import '../scanner/scannerlib.dart' show Token; | |
13 import '../js_backend/js_backend.dart' show JavaScriptBackend; | |
14 | |
15 class IrBuilderTask extends CompilerTask { | |
16 final Map<Element, IrNode> nodes = new Map<Element, IrNode>(); | |
17 | |
18 IrBuilderTask(Compiler compiler) : super(compiler); | |
19 | |
20 String get name => 'IR builder'; | |
21 | |
22 void buildNodes() { | |
23 // TODO(lry): support checked-mode checks. | |
24 if (compiler.enableTypeAssertions) return; | |
25 | |
26 Map<Element, TreeElements> resolved = | |
27 compiler.enqueuer.resolution.resolvedElements; | |
28 resolved.forEach((Element element, TreeElements elementsMapping) { | |
29 element = element.implementation; | |
30 | |
31 SourceFile sourceFile = elementSourceFile(element); | |
32 IrNodeBuilderVisitor visitor = | |
33 new IrNodeBuilderVisitor(elementsMapping, compiler, sourceFile); | |
34 IrNode irNode; | |
35 ElementKind kind = element.kind; | |
36 if (kind == ElementKind.GENERATIVE_CONSTRUCTOR) { | |
37 // TODO(lry): build ir for constructors. | |
38 } else if (kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY || | |
39 kind == ElementKind.FUNCTION || | |
40 kind == ElementKind.GETTER || | |
41 kind == ElementKind.SETTER) { | |
42 irNode = visitor.buildMethod(element); | |
43 } else if (kind == ElementKind.FIELD) { | |
44 // TODO(lry): build ir for lazy initializers of static fields. | |
45 } else { | |
46 compiler.internalErrorOnElement(element, | |
47 'unexpected element kind $kind'); | |
48 } | |
49 | |
50 if (irNode != null) { | |
51 nodes[element] = irNode; | |
52 unlinkTreeAndToken(element); | |
53 } | |
54 }); | |
55 } | |
56 | |
57 void unlinkTreeAndToken(element) { | |
58 // TODO(lry): Make the dart backend generate code from IR nodes. | |
59 if (compiler.backend is JavaScriptBackend) { | |
60 element.beginToken.next = null; | |
61 element.cachedNode = null; | |
62 } | |
63 } | |
64 | |
65 SourceFile elementSourceFile(Element element) { | |
66 if (element is FunctionElement) { | |
67 FunctionElement functionElement = element; | |
68 if (functionElement.patch != null) element = functionElement.patch; | |
69 } | |
70 return element.getCompilationUnit().script.file; | |
71 } | |
72 } | |
73 | |
74 | |
75 class IrNodeBuilderVisitor extends ResolvedVisitor<IrNode> { | |
76 final SourceFile sourceFile; | |
77 | |
78 IrNodeBuilderVisitor( | |
79 TreeElements elements, | |
80 Compiler compiler, | |
81 this.sourceFile) | |
82 : super(elements, compiler); | |
83 | |
84 IrBuilder builder; | |
85 | |
86 IrNode buildMethod(FunctionElement functionElement) { | |
87 return nullIfGiveup(() => buildMethodInternal(functionElement)); | |
88 } | |
89 | |
90 IrNode buildMethodInternal(FunctionElement functionElement) { | |
91 assert(invariant(functionElement, functionElement.isImplementation)); | |
92 FunctionExpression function = functionElement.parseNode(compiler); | |
93 assert(function != null); | |
94 assert(!function.modifiers.isExternal()); | |
95 assert(elements[function] != null); | |
96 | |
97 int endPosition = function.getEndToken().charOffset; | |
98 int namePosition = elements[function].position().charOffset; | |
99 IrFunction result = new IrFunction( | |
100 nodePosition(function), endPosition, namePosition, <IrNode>[]); | |
101 builder = new IrBuilder(this); | |
102 builder.enterBlock(); | |
103 if (function.hasBody()) { | |
104 function.body.accept(this); | |
105 ensureReturn(function); | |
106 result.statements | |
107 ..addAll(builder.constants.values) | |
108 ..addAll(builder.statements); | |
109 } | |
110 builder.exitBlock(); | |
111 return result; | |
112 } | |
113 | |
114 IrNode buildNode(Node node) { | |
ngeoffray
2013/11/21 15:02:05
Unused.
lukas
2013/11/21 17:14:27
Done.
| |
115 } | |
116 | |
117 ConstantSystem get constantSystem => compiler.backend.constantSystem; | |
118 | |
119 /* int | PositionWithIdentifierName */ nodePosition(Node node) { | |
120 Token token = node.getBeginToken(); | |
121 if (token.isIdentifier()) { | |
122 return new PositionWithIdentifierName(token.charOffset, token.value); | |
123 } else { | |
124 return token.charOffset; | |
125 } | |
126 } | |
127 | |
128 void ensureReturn(FunctionExpression node) { | |
129 if (!builder.returnOnAllBranches) { | |
ngeoffray
2013/11/21 15:02:05
Nit: Reverse the condition and return to avoid ind
lukas
2013/11/21 17:14:27
Done.
| |
130 IrConstant nullValue = | |
131 builder.enterConstant(constantSystem.createNull(), node); | |
132 builder.enterStatement(new IrReturn(nodePosition(node), nullValue)); | |
133 } | |
134 } | |
135 | |
136 IrNode visitBlock(Block node) { | |
137 for (Node n in node.statements.nodes) { | |
138 n.accept(this); | |
139 } | |
140 } | |
141 | |
142 IrNode visitReturn(Return node) { | |
143 IrNode value; | |
144 if (node.expression == null) { | |
145 if (node.beginToken.value == 'native') return giveup(); | |
146 value = builder.enterConstant(constantSystem.createNull(), node); | |
147 } else { | |
148 value = node.expression.accept(this); | |
149 } | |
150 builder.branchReturns(); | |
151 return builder.enterStatement( | |
152 new IrReturn(nodePosition(node), value)); | |
153 } | |
154 | |
155 IrConstant visitLiteralBool(LiteralBool node) => | |
156 builder.enterConstant(constantSystem.createBool(node.value), node); | |
157 | |
158 IrConstant visitLiteralDouble(LiteralDouble node) => | |
159 builder.enterConstant(constantSystem.createDouble(node.value), node); | |
160 | |
161 IrConstant visitLiteralInt(LiteralInt node) => | |
162 builder.enterConstant(constantSystem.createInt(node.value), node); | |
163 | |
164 IrConstant visitLiteralString(LiteralString node) => | |
165 builder.enterConstant( | |
166 constantSystem.createString(node.dartString, node), node); | |
167 | |
168 IrConstant visitLiteralNull(LiteralNull node) => | |
169 builder.enterConstant(constantSystem.createNull(), node); | |
170 | |
171 // TODO(lry): other literals. | |
172 // IrNode visitLiteralList(LiteralList node) => visitExpression(node); | |
173 // IrNode visitLiteralMap(LiteralMap node) => visitExpression(node); | |
174 // IrNode visitLiteralMapEntry(LiteralMapEntry node) => visitNode(node); | |
175 // IrNode visitLiteralSymbol(LiteralSymbol node) => visitExpression(node); | |
176 | |
177 | |
178 IrNode visitAssert(Send node) { | |
179 return giveup(); | |
180 } | |
181 | |
182 IrNode visitClosureSend(Send node) { | |
183 return giveup(); | |
184 } | |
185 | |
186 IrNode visitDynamicSend(Send node) { | |
187 return giveup(); | |
188 } | |
189 | |
190 IrNode visitGetterSend(Send node) { | |
191 return giveup(); | |
192 } | |
193 | |
194 IrNode visitOperatorSend(Send node) { | |
195 return giveup(); | |
196 } | |
197 | |
198 IrNode visitStaticSend(Send node) { | |
199 return giveup(); | |
200 } | |
201 | |
202 IrNode visitSuperSend(Send node) { | |
203 return giveup(); | |
204 } | |
205 | |
206 IrNode visitTypeReferenceSend(Send node) { | |
207 return giveup(); | |
208 } | |
209 | |
210 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; | |
211 | |
212 IrNode giveup() => throw ABORT_IRNODE_BUILDER; | |
213 | |
214 IrNode nullIfGiveup(IrNode action()) { | |
215 try { | |
216 return action(); | |
217 } catch(e) { | |
218 if (e == ABORT_IRNODE_BUILDER) return null; | |
219 rethrow; | |
220 } | |
221 } | |
222 | |
223 void internalError(String reason, {Node node}) { | |
224 giveup(); | |
225 } | |
226 } | |
227 | |
228 class IrBuilder { | |
229 final IrNodeBuilderVisitor visitor; | |
230 IrBuilder(this.visitor); | |
231 | |
232 // Statements lists for nested blocks. | |
233 List<List<IrNode>> statementsList = <List<IrNode>>[]; | |
234 List<IrNode> get statements => statementsList.last; | |
235 | |
236 // TODO(lry): Need to fix this once we actually have branching. Probably | |
237 // this will be handled by the LocalsHandler, not here. | |
238 List<bool> returnOnAllBranchesList = <bool>[]; | |
239 bool get returnOnAllBranches => returnOnAllBranchesList.last; | |
240 void branchReturns() { | |
241 returnOnAllBranchesList[returnOnAllBranchesList.length - 1] = true; | |
242 } | |
243 | |
244 Map<Constant, IrConstant> constants = <Constant, IrConstant>{}; | |
245 | |
246 IrConstant enterConstant(Constant value, Node node) { | |
ngeoffray
2013/11/21 15:02:05
addConstant?
lukas
2013/11/21 17:14:27
Done.
| |
247 return constants.putIfAbsent( | |
248 value, () => new IrConstant(visitor.nodePosition(node), value)); | |
249 } | |
250 | |
251 IrNode enterStatement(IrNode statement) { | |
ngeoffray
2013/11/21 15:02:05
addStatement?
lukas
2013/11/21 17:14:27
Done.
| |
252 statements.add(statement); | |
253 return statement; | |
254 } | |
255 | |
256 void enterBlock() { | |
257 statementsList.add(<IrNode>[]); | |
258 returnOnAllBranchesList.add(false); | |
259 } | |
260 | |
261 void exitBlock() { | |
262 statementsList.removeLast(); | |
263 returnOnAllBranchesList.removeLast(); | |
264 } | |
265 } | |
OLD | NEW |