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

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

Issue 85813002: Revert "Revert "Build new IR for functions returning a constant."" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: feedback by kasper 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 dart2js.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 [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 ||
83 compiler.backend is !JavaScriptBackend ||
84 compiler.enableConcreteTypeInference) {
85 return false;
86 }
87 return true;
88 }
89
90 bool canBuild(Element element) {
91 // TODO(lry): support lazy initializers.
92 FunctionElement function = element.asFunctionElement();
93 if (function == null) return false;
94
95 // TODO(lry): support functions with parameters.
96 FunctionSignature signature = function.computeSignature(compiler);
97 if (signature.parameterCount > 0) return false;
98
99 // TODO(lry): support intercepted methods. Then the dependency on
100 // JavaScriptBackend will go away.
101 JavaScriptBackend backend = compiler.backend;
102 if (backend.isInterceptedMethod(element)) return false;
103
104 // TODO(lry): support native functions (also in [visitReturn]).
105 if (function.isNative()) return false;
106
107 return true;
108 }
109
110 void unlinkTreeAndToken(element) {
111 element.beginToken.next = null;
112 element.cachedNode = null;
113 }
114
115 SourceFile elementSourceFile(Element element) {
116 if (element is FunctionElement) {
117 FunctionElement functionElement = element;
118 if (functionElement.patch != null) element = functionElement.patch;
119 }
120 return element.getCompilationUnit().script.file;
121 }
122 }
123
124 /**
125 * A tree visitor that builds [IrNodes]. The visit methods add statements using
126 * to the [builder] and return the last added statement for trees that represent
127 * an expression.
128 */
129 class IrNodeBuilderVisitor extends ResolvedVisitor<IrNode> {
130 final SourceFile sourceFile;
131
132 IrNodeBuilderVisitor(
133 TreeElements elements,
134 Compiler compiler,
135 this.sourceFile)
136 : super(elements, compiler);
137
138 IrBuilder builder;
139
140 /**
141 * Builds the [IrFunction] for a function element. In case the function
142 * uses features that cannot be expressed in the IR, this function returns
143 * [:null:].
144 */
145 IrFunction buildMethod(FunctionElement functionElement) {
146 return nullIfGiveup(() => buildMethodInternal(functionElement));
147 }
148
149 IrFunction buildMethodInternal(FunctionElement functionElement) {
150 assert(invariant(functionElement, functionElement.isImplementation));
151 FunctionExpression function = functionElement.parseNode(compiler);
152 assert(function != null);
153 assert(!function.modifiers.isExternal());
154 assert(elements[function] != null);
155
156 int endPosition = function.getEndToken().charOffset;
157 int namePosition = elements[function].position().charOffset;
158 IrFunction result = new IrFunction(
159 nodePosition(function), endPosition, namePosition, <IrNode>[]);
160 builder = new IrBuilder(this);
161 builder.enterBlock();
162 if (function.hasBody()) {
163 function.body.accept(this);
164 ensureReturn(function);
165 result.statements
166 ..addAll(builder.constants.values)
167 ..addAll(builder.block.statements);
168 }
169 builder.exitBlock();
170 return result;
171 }
172
173 ConstantSystem get constantSystem => compiler.backend.constantSystem;
174
175 /* int | PositionWithIdentifierName */ nodePosition(Node node) {
176 Token token = node.getBeginToken();
177 if (token.isIdentifier()) {
178 return new PositionWithIdentifierName(token.charOffset, token.value);
179 } else {
180 return token.charOffset;
181 }
182 }
183
184 bool get blockReturns => builder.block.hasReturn;
185
186 /**
187 * Add an explicit [:return null:] for functions that don't have a return
188 * statement on each branch. This includes functions with an empty body,
189 * such as [:foo(){ }:].
190 */
191 void ensureReturn(FunctionExpression node) {
192 if (blockReturns) return;
193 IrConstant nullValue =
194 builder.addConstant(constantSystem.createNull(), node);
195 builder.addStatement(new IrReturn(nodePosition(node), nullValue));
196 }
197
198 IrNode visitBlock(Block node) {
199 for (Node n in node.statements.nodes) {
200 n.accept(this);
201 if (blockReturns) return null;
202 }
203 }
204
205 IrNode visitReturn(Return node) {
206 assert(!blockReturns);
207 IrNode value;
208 // TODO(lry): support native returns.
209 if (node.beginToken.value == 'native') return giveup();
210 if (node.expression == null) {
211 value = builder.addConstant(constantSystem.createNull(), node);
212 } else {
213 value = node.expression.accept(this);
214 }
215 builder.addStatement(new IrReturn(nodePosition(node), value));
216 builder.block.hasReturn = true;
217 }
218
219 IrConstant visitLiteralBool(LiteralBool node) {
220 return builder.addConstant(constantSystem.createBool(node.value), node);
221 }
222
223 IrConstant visitLiteralDouble(LiteralDouble node) {
224 return builder.addConstant(constantSystem.createDouble(node.value), node);
225 }
226
227 IrConstant visitLiteralInt(LiteralInt node) {
228 return builder.addConstant(constantSystem.createInt(node.value), node);
229 }
230
231 IrConstant visitLiteralString(LiteralString node) {
232 Constant value = constantSystem.createString(node.dartString, node);
233 return builder.addConstant(value, node);
234 }
235
236 IrConstant visitLiteralNull(LiteralNull node) {
237 return builder.addConstant(constantSystem.createNull(), node);
238 }
239
240 // TODO(lry): other literals.
241 // IrNode visitLiteralList(LiteralList node) => visitExpression(node);
242 // IrNode visitLiteralMap(LiteralMap node) => visitExpression(node);
243 // IrNode visitLiteralMapEntry(LiteralMapEntry node) => visitNode(node);
244 // IrNode visitLiteralSymbol(LiteralSymbol node) => visitExpression(node);
245
246 IrNode visitAssert(Send node) {
247 return giveup();
248 }
249
250 IrNode visitClosureSend(Send node) {
251 return giveup();
252 }
253
254 IrNode visitDynamicSend(Send node) {
255 return giveup();
256 }
257
258 IrNode visitGetterSend(Send node) {
259 return giveup();
260 }
261
262 IrNode visitOperatorSend(Send node) {
263 return giveup();
264 }
265
266 IrNode visitStaticSend(Send node) {
267 return giveup();
268 }
269
270 IrNode visitSuperSend(Send node) {
271 return giveup();
272 }
273
274 IrNode visitTypeReferenceSend(Send node) {
275 return giveup();
276 }
277
278 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted";
279
280 IrNode giveup() => throw ABORT_IRNODE_BUILDER;
281
282 IrNode nullIfGiveup(IrNode action()) {
283 try {
284 return action();
285 } catch(e) {
286 if (e == ABORT_IRNODE_BUILDER) return null;
287 rethrow;
288 }
289 }
290
291 void internalError(String reason, {Node node}) {
292 giveup();
293 }
294 }
295
296 class IrBuilder {
297 final IrNodeBuilderVisitor visitor;
298 IrBuilder(this.visitor);
299
300 List<BlockBuilder> blockBuilders = <BlockBuilder>[];
301
302 BlockBuilder get block => blockBuilders.last;
303
304 Map<Constant, IrConstant> constants = <Constant, IrConstant>{};
305
306 IrConstant addConstant(Constant value, Node node) {
307 return constants.putIfAbsent(
308 value, () => new IrConstant(visitor.nodePosition(node), value));
309 }
310
311 IrNode addStatement(IrNode statement) {
312 block.statements.add(statement);
313 return statement;
314 }
315
316 void enterBlock() {
317 blockBuilders.add(new BlockBuilder());
318 }
319
320 void exitBlock() {
321 blockBuilders.removeLast();
322 }
323 }
324
325 class BlockBuilder {
326 List<IrNode> statements = <IrNode>[];
327 bool hasReturn = false;
328 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698