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

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: type inference and inlining for new ir nodes 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 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 Map<Element, TreeElements> resolved =
24 compiler.enqueuer.resolution.resolvedElements;
25 resolved.forEach((Element element, TreeElements elementsMapping) {
26 element = element.implementation;
27
28 SourceFile sourceFile = elementSourceFile(element);
29 IrNodeBuilderVisitor visitor =
30 new IrNodeBuilderVisitor(elementsMapping, compiler, sourceFile);
31 IrNode irNode;
32 ElementKind kind = element.kind;
33 if (kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
34 // TODO(lry): build ir for constructors.
35 } else if (kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY ||
36 kind == ElementKind.FUNCTION ||
37 kind == ElementKind.GETTER ||
38 kind == ElementKind.SETTER) {
39 irNode = visitor.buildMethod(element);
40 } else if (kind == ElementKind.FIELD) {
41 // TODO(lry): build ir for lazy initializers of static fields.
42 } else {
43 compiler.internalErrorOnElement(element,
44 'unexpected element kind $kind');
45 }
46
47 if (irNode != null) {
48 nodes[element] = irNode;
49 unlinkTreeAndToken(element);
50 }
51 });
52 }
53
54 void unlinkTreeAndToken(Element element) {
ngeoffray 2013/11/20 14:55:27 I'd just untype element to avoid the 'as dynamic'.
lukas 2013/11/21 12:20:21 Done.
55 if (compiler.backend is JavaScriptBackend) {
56 (element as dynamic).beginToken.next = null;
57 (element as dynamic).cachedNode = null;
58 }
59 }
60
61 SourceFile elementSourceFile(Element element) {
62 if (element is FunctionElement) {
63 FunctionElement functionElement = element;
64 if (functionElement.patch != null) element = functionElement.patch;
65 }
66 return element.getCompilationUnit().script.file;
67 }
68 }
69
70
71 class IrNodeBuilderVisitor extends ResolvedVisitor<IrNode> {
72 SourceFile sourceFile;
73
74 Context context;
75
76 IrNodeBuilderVisitor(TreeElements elements, Compiler compiler,
77 this.sourceFile) : super(elements, compiler) {
ngeoffray 2013/11/20 14:55:27 Nit: One argument per line, and super on a new lin
lukas 2013/11/21 12:20:21 Done.
78 context = new Context(this);
79 }
80
81 IrNode buildMethod(FunctionElement functionElement) {
82 assert(invariant(functionElement, functionElement.isImplementation));
83 FunctionExpression function = functionElement.parseNode(compiler);
84 assert(function != null);
85 assert(!function.modifiers.isExternal());
86 assert(elements[function] != null);
87 return buildNode(function);
88 }
89
90 IrNode buildNode(Node node) {
91 try {
92 return node.accept(this);
93 } catch(e) {
94 if (e == ABORT_IRNODE_BUILDER) return null;
95 rethrow;
96 }
97 }
98
99 ConstantSystem get constantSystem => compiler.backend.constantSystem;
100
101 /* int | PositionWithIdentifierName */ nodePosition(Node node) {
102 Token token = node.getBeginToken();
103 if (token.isIdentifier()) {
104 return new PositionWithIdentifierName(token.charOffset, token.value);
105 } else {
106 return token.charOffset;
107 }
108 }
109
110 IrNode visitFunctionExpression(FunctionExpression node) {
111 int endPosition = node.getEndToken().charOffset;
112 int namePosition = elements[node].position().charOffset;
113 IrFunction result = new IrFunction(
114 nodePosition(node), endPosition, namePosition, <IrNode>[]);
115 context.openFunction(result);
116 if (node.hasBody()) {
117 node.body.accept(this);
118 ensureReturn(node);
119 result.statements..addAll(context.constants)..addAll(context.statements);
120 }
121 context.closeFunction();
122 if (!context.isTopLevel()) {
123 context.enterStatement(result);
124 }
125 return result;
126 }
127
128 void ensureReturn(FunctionExpression node) {
129 if (!context.returnOnAllBranches) {
130 IrConstant nullValue =
131 context.enterConstant(constantSystem.createNull(), node);
132 context.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 = context.enterConstant(constantSystem.createNull(), node);
147 } else {
148 value = node.expression.accept(this);
149 }
150 context.branchReturns();
151 return context.enterStatement(
152 new IrReturn(nodePosition(node), value));
153 }
154
155 IrConstant visitLiteralBool(LiteralBool node) =>
156 context.enterConstant(constantSystem.createBool(node.value), node);
157
158 IrConstant visitLiteralDouble(LiteralDouble node) =>
159 context.enterConstant(constantSystem.createDouble(node.value), node);
160
161 IrConstant visitLiteralInt(LiteralInt node) =>
162 context.enterConstant(constantSystem.createInt(node.value), node);
163
164 IrConstant visitLiteralString(LiteralString node) =>
165 context.enterConstant(
166 constantSystem.createString(node.dartString, node), node);
167
168 IrConstant visitLiteralNull(LiteralNull node) =>
169 context.enterConstant(constantSystem.createNull(), node);
170
171 // IrNode visitLiteralList(LiteralList node) => visitExpression(node);
172 // IrNode visitLiteralMap(LiteralMap node) => visitExpression(node);
173 // IrNode visitLiteralMapEntry(LiteralMapEntry node) => visitNode(node);
174 // IrNode visitLiteralSymbol(LiteralSymbol node) => visitExpression(node);
175
176
177 IrNode visitAssert(Send node) {
178 return giveup();
179 }
180
181 IrNode visitClosureSend(Send node) {
182 return giveup();
183 }
184
185 IrNode visitDynamicSend(Send node) {
186 return giveup();
187 }
188
189 IrNode visitGetterSend(Send node) {
190 return giveup();
191 }
192
193 IrNode visitOperatorSend(Send node) {
194 return giveup();
195 }
196
197 IrNode visitStaticSend(Send node) {
198 return giveup();
199 }
200
201 IrNode visitSuperSend(Send node) {
202 return giveup();
203 }
204
205 IrNode visitTypeReferenceSend(Send node) {
206 return giveup();
207 }
208
209 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted";
210
211 IrNode giveup() => throw ABORT_IRNODE_BUILDER;
212
213 void internalError(String reason, {Node node}) {
214 giveup();
215 }
216 }
217
218 class Context {
219 IrNodeBuilderVisitor visitor;
220 Context(this.visitor);
221
222 List<IrFunction> currentFunctionList = <IrFunction>[];
223 IrFunction get currentFunction => currentFunctionList.last;
ngeoffray 2013/11/20 14:55:27 Actually, we will probably not inline at this leve
lukas 2013/11/21 12:20:21 Maybe we want to keep nested functions as such in
224
225 // TODO(lry): Need to fix this once we actually have branching. The things we
226 // currently achieve with the Conctext class might overlap with LocalHandlers.
ngeoffray 2013/11/20 14:55:27 Conctext -> Context
lukas 2013/11/21 12:20:21 Done.
227 List<bool> returnOnAllBranchesList = <bool>[];
228 bool get returnOnAllBranches => returnOnAllBranchesList.last;
229 void branchReturns() {
230 returnOnAllBranchesList[returnOnAllBranchesList.length - 1] = true;
231 }
232
233 List<List<IrNode>> statementsList = <List<IrNode>>[];
234 List<IrNode> get statements => statementsList.last;
235
236 List<List<IrConstant>> constantsList = <List<IrConstant>>[];
237 List<IrConstant> get constants => constantsList.last;
238
239 IrConstant enterConstant(Constant value, Node node) {
ngeoffray 2013/11/20 14:55:27 Why not a Map of Constant -> IrConstant? Like we h
lukas 2013/11/21 12:20:21 Done.
240 return constants.firstWhere((c) => c.value == value, orElse: () {
241 IrConstant c = new IrConstant(visitor.nodePosition(node), value);
242 constants.add(c);
243 return c;
244 });
245 }
246
247 IrNode enterStatement(IrNode statement) {
248 statements.add(statement);
249 return statement;
250 }
251
252 void openFunction(IrFunction function) {
253 currentFunctionList.add(function);
254 statementsList.add(<IrNode>[]);
255 returnOnAllBranchesList.add(false);
256 constantsList.add(<IrConstant>[]);
257 }
258
259 void closeFunction() {
260 currentFunctionList.removeLast();
261 statementsList.removeLast();
262 returnOnAllBranchesList.removeLast();
263 constantsList.removeLast();
264 }
265
266 void openContinuation() {
ngeoffray 2013/11/20 14:55:27 Unused.
lukas 2013/11/21 12:20:21 Done.
267 statementsList.add(<IrNode>[]);
268 }
269
270 void closeContinuation() {
ngeoffray 2013/11/20 14:55:27 Unused.
lukas 2013/11/21 12:20:21 Done.
271 statementsList.removeLast();
272 }
273
274 isTopLevel() => currentFunctionList.isEmpty;
275 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698