Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1781)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart

Issue 57873002: Build new IR for functions returning a constant (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: yet another rebase Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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.
4
5 library ir_builder;
kasperl 2013/11/25 11:32:54 dart2js.ir_builder?
lukas 2013/11/25 14:50:52 Done.
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 /**
16 * This task iterates through all resolved elements and builds [IrNode]s. The
17 * nodes are stored in the [nodes] map and accessible through [hasIr] and
18 * [getIr].
19 *
20 * The functionality of the IrNodes is added gradually, therefore elements might
21 * have an IR or not, depending on the language features that are used. For
22 * elements that do have an IR, the tree [Node]s and the [Token]s are not used
23 * in the rest of the compilation. This is ensured by setting the element's
24 * cached tree to [:null:] and also breaking the token stream to crash future
25 * attempts to parse.
26 *
27 * The type inferrer works on either IR nodes or tree nodes. The IR nodes are
28 * then translated into the SSA form for optimizations and code generation.
29 * Long-term, once the IR supports the full language, the backend can be
30 * re-implemented to work directly on the IR.
31 */
32 class IrBuilderTask extends CompilerTask {
33 final Map<Element, IrNode> nodes = new Map<Element, IrNode>();
34
35 IrBuilderTask(Compiler compiler) : super(compiler);
36
37 String get name => 'IR builder';
38
39 bool hasIr(Element element) => nodes.containsKey(element.implementation);
40
41 IrNode getIr(Element element) => nodes[element.implementation];
42
43 void buildNodes() {
44 if (!irEnabled()) return;
45 measure(() {
46 Map<Element, TreeElements> resolved =
47 compiler.enqueuer.resolution.resolvedElements;
48 resolved.forEach((Element element, TreeElements elementsMapping) {
49 if (canBuild(element)) {
50 element = element.implementation;
51
52 SourceFile sourceFile = elementSourceFile(element);
53 IrNodeBuilderVisitor visitor =
54 new IrNodeBuilderVisitor(elementsMapping, compiler, sourceFile);
55 IrNode irNode;
56 ElementKind kind = element.kind;
57 if (kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
58 // TODO(lry): build ir for constructors.
59 } else if (kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY ||
60 kind == ElementKind.FUNCTION ||
61 kind == ElementKind.GETTER ||
62 kind == ElementKind.SETTER) {
63 irNode = visitor.buildMethod(element);
64 } else if (kind == ElementKind.FIELD) {
65 // TODO(lry): build ir for lazy initializers of static fields.
66 } else {
67 compiler.internalErrorOnElement(element,
68 'unexpected element kind $kind');
69 }
70
71 if (irNode != null) {
72 nodes[element] = irNode;
73 unlinkTreeAndToken(element);
74 }
75 }
76 });
77 });
78 }
79
80 bool irEnabled() {
81 // TODO(lry): support checked-mode checks.
82 if (compiler.enableTypeAssertions) return false;
83 if (compiler.backend is !JavaScriptBackend) return false;
84 return true;
85 }
86
87 bool canBuild(Element element) {
88 // TODO(lry): support lazy initializers.
89 FunctionElement function = element.asFunctionElement();
90 if (function == null) return false;
91
92 // TODO(lry): support functions with parameters.
93 FunctionSignature signature = function.computeSignature(compiler);
94 if (signature.parameterCount > 0) return false;
95
96 // TODO(lry): support intercepted methods. Then the dependency on
97 // JavaScriptBackend will go away.
98 JavaScriptBackend backend = compiler.backend;
99 if (backend.isInterceptedMethod(element)) return false;
100
101 return true;
102 }
103
104 void unlinkTreeAndToken(element) {
105 element.beginToken.next = null;
106 element.cachedNode = null;
107 }
108
109 SourceFile elementSourceFile(Element element) {
110 if (element is FunctionElement) {
111 FunctionElement functionElement = element;
112 if (functionElement.patch != null) element = functionElement.patch;
113 }
114 return element.getCompilationUnit().script.file;
115 }
116 }
117
118 /**
119 * A tree visitor that builds [IrNodes]. The visit methods add statements using
120 * to the [builder] and return the last added statement for trees that represent
121 * an expression.
122 */
123 class IrNodeBuilderVisitor extends ResolvedVisitor<IrNode> {
124 final SourceFile sourceFile;
125
126 IrNodeBuilderVisitor(
127 TreeElements elements,
128 Compiler compiler,
129 this.sourceFile)
130 : super(elements, compiler);
131
132 IrBuilder builder;
133
134 /**
135 * Builds the [IrFunction] for a function element. In case the function
136 * uses features that cannot be expressed in the IR, this function returns
137 * [:null:].
138 */
139 IrFunction buildMethod(FunctionElement functionElement) {
140 return nullIfGiveup(() => buildMethodInternal(functionElement));
141 }
142
143 IrFunction buildMethodInternal(FunctionElement functionElement) {
144 assert(invariant(functionElement, functionElement.isImplementation));
145 FunctionExpression function = functionElement.parseNode(compiler);
146 assert(function != null);
147 assert(!function.modifiers.isExternal());
148 assert(elements[function] != null);
149
150 int endPosition = function.getEndToken().charOffset;
151 int namePosition = elements[function].position().charOffset;
152 IrFunction result = new IrFunction(
153 nodePosition(function), endPosition, namePosition, <IrNode>[]);
154 builder = new IrBuilder(this);
155 builder.enterBlock();
156 if (function.hasBody()) {
157 function.body.accept(this);
158 ensureReturn(function);
159 result.statements
160 ..addAll(builder.constants.values)
161 ..addAll(builder.statements);
162 }
163 builder.exitBlock();
164 return result;
165 }
166
167 ConstantSystem get constantSystem => compiler.backend.constantSystem;
168
169 /* int | PositionWithIdentifierName */ nodePosition(Node node) {
170 Token token = node.getBeginToken();
171 if (token.isIdentifier()) {
172 return new PositionWithIdentifierName(token.charOffset, token.value);
173 } else {
174 return token.charOffset;
175 }
176 }
177
178 /**
179 * Add an explicit [:return null:] for functions that don't have a return
180 * statement on each branch. This includes functions with an empty body,
181 * such as [:foo(){ }:].
182 */
183 void ensureReturn(FunctionExpression node) {
184 if (builder.returnOnAllBranches) return;
185 IrConstant nullValue =
186 builder.addConstant(constantSystem.createNull(), node);
187 builder.addStatement(new IrReturn(nodePosition(node), nullValue));
188 }
189
190 IrNode visitBlock(Block node) {
191 for (Node n in node.statements.nodes) {
192 n.accept(this);
193 }
194 }
195
196 IrNode visitReturn(Return node) {
197 IrNode value;
198 if (node.expression == null) {
199 if (node.beginToken.value == 'native') return giveup();
200 value = builder.addConstant(constantSystem.createNull(), node);
201 } else {
202 value = node.expression.accept(this);
203 }
204 builder.branchReturns();
205 return builder.addStatement(new IrReturn(nodePosition(node), value));
206 }
207
208 IrConstant visitLiteralBool(LiteralBool node) =>
209 builder.addConstant(constantSystem.createBool(node.value), node);
210
211 IrConstant visitLiteralDouble(LiteralDouble node) =>
212 builder.addConstant(constantSystem.createDouble(node.value), node);
213
214 IrConstant visitLiteralInt(LiteralInt node) =>
215 builder.addConstant(constantSystem.createInt(node.value), node);
216
217 IrConstant visitLiteralString(LiteralString node) =>
218 builder.addConstant(
219 constantSystem.createString(node.dartString, node), node);
220
221 IrConstant visitLiteralNull(LiteralNull node) =>
222 builder.addConstant(constantSystem.createNull(), node);
223
224 // TODO(lry): other literals.
225 // IrNode visitLiteralList(LiteralList node) => visitExpression(node);
226 // IrNode visitLiteralMap(LiteralMap node) => visitExpression(node);
227 // IrNode visitLiteralMapEntry(LiteralMapEntry node) => visitNode(node);
228 // IrNode visitLiteralSymbol(LiteralSymbol node) => visitExpression(node);
229
230 IrNode visitAssert(Send node) {
231 return giveup();
232 }
233
234 IrNode visitClosureSend(Send node) {
235 return giveup();
236 }
237
238 IrNode visitDynamicSend(Send node) {
239 return giveup();
240 }
241
242 IrNode visitGetterSend(Send node) {
243 return giveup();
244 }
245
246 IrNode visitOperatorSend(Send node) {
247 return giveup();
248 }
249
250 IrNode visitStaticSend(Send node) {
251 return giveup();
252 }
253
254 IrNode visitSuperSend(Send node) {
255 return giveup();
256 }
257
258 IrNode visitTypeReferenceSend(Send node) {
259 return giveup();
260 }
261
262 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted";
263
264 IrNode giveup() => throw ABORT_IRNODE_BUILDER;
265
266 IrNode nullIfGiveup(IrNode action()) {
267 try {
268 return action();
269 } catch(e) {
270 if (e == ABORT_IRNODE_BUILDER) return null;
271 rethrow;
272 }
273 }
274
275 void internalError(String reason, {Node node}) {
276 giveup();
277 }
278 }
279
280 class IrBuilder {
281 final IrNodeBuilderVisitor visitor;
282 IrBuilder(this.visitor);
283
284 // Statements lists for nested blocks.
285 List<List<IrNode>> statementsList = <List<IrNode>>[];
286 List<IrNode> get statements => statementsList.last;
287
288 // TODO(lry): Need to fix this once we actually have branching. Probably
289 // this will be handled by the LocalsHandler, not here.
290 List<bool> returnOnAllBranchesList = <bool>[];
291 bool get returnOnAllBranches => returnOnAllBranchesList.last;
292 void branchReturns() {
293 returnOnAllBranchesList[returnOnAllBranchesList.length - 1] = true;
294 }
295
296 Map<Constant, IrConstant> constants = <Constant, IrConstant>{};
297
298 IrConstant addConstant(Constant value, Node node) {
299 return constants.putIfAbsent(
300 value, () => new IrConstant(visitor.nodePosition(node), value));
301 }
302
303 IrNode addStatement(IrNode statement) {
304 statements.add(statement);
305 return statement;
306 }
307
308 void enterBlock() {
309 statementsList.add(<IrNode>[]);
310 returnOnAllBranchesList.add(false);
311 }
312
313 void exitBlock() {
314 statementsList.removeLast();
315 returnOnAllBranchesList.removeLast();
316 }
317 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698