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

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

Powered by Google App Engine
This is Rietveld 408576698