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

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: include feedback, don't build ir for intercepted methods 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;
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 [Element.irNode]
18 * and [Element.hasIrNode].
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 void buildNodes() {
40 // TODO(lry): support checked-mode checks.
41 if (compiler.enableTypeAssertions) return;
42
43 Map<Element, TreeElements> resolved =
44 compiler.enqueuer.resolution.resolvedElements;
45 resolved.forEach((Element element, TreeElements elementsMapping) {
46 if (canBuild(element)) {
47 element = element.implementation;
48
49 SourceFile sourceFile = elementSourceFile(element);
50 IrNodeBuilderVisitor visitor =
51 new IrNodeBuilderVisitor(elementsMapping, compiler, sourceFile);
52 IrNode irNode;
53 ElementKind kind = element.kind;
54 if (kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
55 // TODO(lry): build ir for constructors.
56 } else if (kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY ||
57 kind == ElementKind.FUNCTION ||
58 kind == ElementKind.GETTER ||
59 kind == ElementKind.SETTER) {
60 irNode = visitor.buildMethod(element);
61 } else if (kind == ElementKind.FIELD) {
62 // TODO(lry): build ir for lazy initializers of static fields.
63 } else {
64 compiler.internalErrorOnElement(element,
65 'unexpected element kind $kind');
66 }
67
68 if (irNode != null) {
69 nodes[element] = irNode;
70 unlinkTreeAndToken(element);
71 }
72 }
73 });
74 }
75
76 bool canBuild(Element element) {
77 FunctionElement function = element.asFunctionElement();
78 if (function == null) return false;
79
80 // TODO(lry): support functions with parameters.
81 FunctionSignature signature = function.computeSignature(compiler);
82 if (signature.parameterCount > 0) return false;
83
84 if (compiler.backend is JavaScriptBackend) {
85 JavaScriptBackend backend = compiler.backend;
86 if (backend.isInterceptedMethod(element)) return false;
karlklose 2013/11/22 08:01:06 Consider storing compiler.backend in a field. (of
lukas 2013/11/22 11:51:34 Cleaned up as discussed offline. For now we abort
87 }
88
89 return true;
90 }
91
92 void unlinkTreeAndToken(element) {
93 // TODO(lry): Make the dart backend generate code from IR nodes.
94 if (compiler.backend is JavaScriptBackend) {
95 element.beginToken.next = null;
96 element.cachedNode = null;
97 }
98 }
99
100 SourceFile elementSourceFile(Element element) {
101 if (element is FunctionElement) {
102 FunctionElement functionElement = element;
103 if (functionElement.patch != null) element = functionElement.patch;
104 }
105 return element.getCompilationUnit().script.file;
106 }
107 }
108
109 /**
110 * A tree visitor that builds [IrNodes]. The visit methods add statements using
111 * to the [builder] and return the last added statement for trees that represent
112 * an expression.
113 */
114 class IrNodeBuilderVisitor extends ResolvedVisitor<IrNode> {
115 final SourceFile sourceFile;
116
117 IrNodeBuilderVisitor(
118 TreeElements elements,
119 Compiler compiler,
120 this.sourceFile)
121 : super(elements, compiler);
122
123 IrBuilder builder;
124
125 /**
126 * Builds the [IrFunction] for a function element. In case the function
127 * uses features that cannot be expressed in the IR, this function returns
128 * [:null:].
129 */
130 IrFunction buildMethod(FunctionElement functionElement) {
131 return nullIfGiveup(() => buildMethodInternal(functionElement));
132 }
133
134 IrFunction buildMethodInternal(FunctionElement functionElement) {
135 assert(invariant(functionElement, functionElement.isImplementation));
136 FunctionExpression function = functionElement.parseNode(compiler);
137 assert(function != null);
138 assert(!function.modifiers.isExternal());
139 assert(elements[function] != null);
140
141 int endPosition = function.getEndToken().charOffset;
142 int namePosition = elements[function].position().charOffset;
143 IrFunction result = new IrFunction(
144 nodePosition(function), endPosition, namePosition, <IrNode>[]);
145 builder = new IrBuilder(this);
146 builder.enterBlock();
147 if (function.hasBody()) {
148 function.body.accept(this);
149 ensureReturn(function);
150 result.statements
151 ..addAll(builder.constants.values)
152 ..addAll(builder.statements);
153 }
154 builder.exitBlock();
155 return result;
156 }
157
158 ConstantSystem get constantSystem => compiler.backend.constantSystem;
159
160 /* int | PositionWithIdentifierName */ nodePosition(Node node) {
161 Token token = node.getBeginToken();
162 if (token.isIdentifier()) {
163 return new PositionWithIdentifierName(token.charOffset, token.value);
164 } else {
165 return token.charOffset;
166 }
167 }
168
169 /**
170 * Add an explicit [:return null:] for functions that don't have a return
171 * statement on each branch. This includes functions with an empty body,
172 * such as [:foo(){ }:].
173 */
174 void ensureReturn(FunctionExpression node) {
175 if (builder.returnOnAllBranches) return;
176 IrConstant nullValue =
177 builder.addConstant(constantSystem.createNull(), node);
178 builder.addStatement(new IrReturn(nodePosition(node), nullValue));
179 }
180
181 IrNode visitBlock(Block node) {
182 for (Node n in node.statements.nodes) {
183 n.accept(this);
184 }
185 }
186
187 IrNode visitReturn(Return node) {
188 IrNode value;
189 if (node.expression == null) {
190 if (node.beginToken.value == 'native') return giveup();
191 value = builder.addConstant(constantSystem.createNull(), node);
192 } else {
193 value = node.expression.accept(this);
194 }
195 builder.branchReturns();
196 return builder.addStatement(new IrReturn(nodePosition(node), value));
197 }
198
199 IrConstant visitLiteralBool(LiteralBool node) =>
200 builder.addConstant(constantSystem.createBool(node.value), node);
201
202 IrConstant visitLiteralDouble(LiteralDouble node) =>
203 builder.addConstant(constantSystem.createDouble(node.value), node);
204
205 IrConstant visitLiteralInt(LiteralInt node) =>
206 builder.addConstant(constantSystem.createInt(node.value), node);
207
208 IrConstant visitLiteralString(LiteralString node) =>
209 builder.addConstant(
210 constantSystem.createString(node.dartString, node), node);
211
212 IrConstant visitLiteralNull(LiteralNull node) =>
213 builder.addConstant(constantSystem.createNull(), node);
214
215 // TODO(lry): other literals.
216 // IrNode visitLiteralList(LiteralList node) => visitExpression(node);
217 // IrNode visitLiteralMap(LiteralMap node) => visitExpression(node);
218 // IrNode visitLiteralMapEntry(LiteralMapEntry node) => visitNode(node);
219 // IrNode visitLiteralSymbol(LiteralSymbol node) => visitExpression(node);
220
221 IrNode visitAssert(Send node) {
222 return giveup();
223 }
224
225 IrNode visitClosureSend(Send node) {
226 return giveup();
227 }
228
229 IrNode visitDynamicSend(Send node) {
230 return giveup();
231 }
232
233 IrNode visitGetterSend(Send node) {
234 return giveup();
235 }
236
237 IrNode visitOperatorSend(Send node) {
238 return giveup();
239 }
240
241 IrNode visitStaticSend(Send node) {
242 return giveup();
243 }
244
245 IrNode visitSuperSend(Send node) {
246 return giveup();
247 }
248
249 IrNode visitTypeReferenceSend(Send node) {
250 return giveup();
251 }
252
253 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted";
254
255 IrNode giveup() => throw ABORT_IRNODE_BUILDER;
256
257 IrNode nullIfGiveup(IrNode action()) {
258 try {
259 return action();
260 } catch(e) {
261 if (e == ABORT_IRNODE_BUILDER) return null;
262 rethrow;
263 }
264 }
265
266 void internalError(String reason, {Node node}) {
267 giveup();
268 }
269 }
270
271 class IrBuilder {
272 final IrNodeBuilderVisitor visitor;
273 IrBuilder(this.visitor);
274
275 // Statements lists for nested blocks.
276 List<List<IrNode>> statementsList = <List<IrNode>>[];
277 List<IrNode> get statements => statementsList.last;
278
279 // TODO(lry): Need to fix this once we actually have branching. Probably
280 // this will be handled by the LocalsHandler, not here.
281 List<bool> returnOnAllBranchesList = <bool>[];
282 bool get returnOnAllBranches => returnOnAllBranchesList.last;
283 void branchReturns() {
284 returnOnAllBranchesList[returnOnAllBranchesList.length - 1] = true;
285 }
286
287 Map<Constant, IrConstant> constants = <Constant, IrConstant>{};
288
289 IrConstant addConstant(Constant value, Node node) {
290 return constants.putIfAbsent(
291 value, () => new IrConstant(visitor.nodePosition(node), value));
292 }
293
294 IrNode addStatement(IrNode statement) {
295 statements.add(statement);
296 return statement;
297 }
298
299 void enterBlock() {
300 statementsList.add(<IrNode>[]);
301 returnOnAllBranchesList.add(false);
302 }
303
304 void exitBlock() {
305 statementsList.removeLast();
306 returnOnAllBranchesList.removeLast();
307 }
308 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698