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

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

Issue 231863007: Support local variables in dart2dart. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Incorporated review comments. Created 6 years, 7 months 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
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library dart2js.ir_builder; 5 library dart2js.ir_builder;
6 6
7 import 'ir_nodes.dart' as ir; 7 import 'ir_nodes.dart' as ir;
8 import '../elements/elements.dart'; 8 import '../elements/elements.dart';
9 import '../dart2jslib.dart'; 9 import '../dart2jslib.dart';
10 import '../dart_types.dart'; 10 import '../dart_types.dart';
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 } 143 }
144 return element.getCompilationUnit().script.file; 144 return element.getCompilationUnit().script.file;
145 } 145 }
146 } 146 }
147 147
148 /** 148 /**
149 * A tree visitor that builds [IrNodes]. The visit methods add statements using 149 * A tree visitor that builds [IrNodes]. The visit methods add statements using
150 * to the [builder] and return the last added statement for trees that represent 150 * to the [builder] and return the last added statement for trees that represent
151 * an expression. 151 * an expression.
152 */ 152 */
153 class IrBuilder extends ResolvedVisitor<ir.Definition> { 153 class IrBuilder extends ResolvedVisitor<ir.Primitive> {
154 final SourceFile sourceFile; 154 final SourceFile sourceFile;
155 ir.Continuation returnContinuation = null; 155 final ir.Continuation returnContinuation;
156 List<ir.Parameter> parameters = <ir.Parameter>[]; 156 final List<ir.Parameter> parameters;
157 157
158 // The IR builder maintains a context, which is an expression with a hole in 158 // The IR builder maintains a context, which is an expression with a hole in
159 // it. The hole represents the focus where new expressions can be added. 159 // it. The hole represents the focus where new expressions can be added.
160 // The context is implemented by 'root' which is the root of the expression 160 // The context is implemented by 'root' which is the root of the expression
161 // and 'current' which is the expression that immediately contains the hole. 161 // and 'current' which is the expression that immediately contains the hole.
162 // Not all expressions have a hole (e.g., invocations, which always occur in 162 // Not all expressions have a hole (e.g., invocations, which always occur in
163 // tail position, do not have a hole). Expressions with a hole have a plug 163 // tail position, do not have a hole). Expressions with a hole have a plug
164 // method. 164 // method.
165 // 165 //
166 // Conceptually, visiting a statement takes a context as input and returns 166 // Conceptually, visiting a statement takes a context as input and returns
167 // either a new context or else an expression without a hole if all 167 // either a new context or else an expression without a hole if all
168 // control-flow paths through the statement have exited. An expression 168 // control-flow paths through the statement have exited. An expression
169 // without a hole is represented by a (root, current) pair where root is the 169 // without a hole is represented by a (root, current) pair where root is the
170 // expression and current is null. 170 // expression and current is null.
171 // 171 //
172 // Conceptually again, visiting an expression takes a context as input and 172 // Conceptually again, visiting an expression takes a context as input and
173 // returns either a pair of a new context and a definition denoting 173 // returns either a pair of a new context and a definition denoting
174 // the expression's value, or else an expression without a hole if all 174 // the expression's value, or else an expression without a hole if all
175 // control-flow paths through the expression have exited. 175 // control-flow paths through the expression have exited.
176 // 176 //
177 // We do not pass and return contexts, rather we use the current context 177 // We do not pass contexts as arguments or return them. Rather we use the
178 // (root, current) as the visitor state and mutate current. Visiting a 178 // current context (root, current) as the visitor state and mutate current.
179 // statement returns null; visiting an expression optionally returns the 179 // Visiting a statement returns null; visiting an expression returns the
180 // definition denoting its value. 180 // primitive denoting its value.
181
181 ir.Expression root = null; 182 ir.Expression root = null;
182 ir.Expression current = null; 183 ir.Expression current = null;
183 184
184 Map<Element, int> variableIndex = <Element, int>{}; 185 // In SSA terms, join-point continuation parameters are the phis and the
185 List<ir.Definition> assignedVars = <ir.Definition>[]; 186 // continuation invocation arguments are the corresponding phi inputs. To
187 // support name introduction and renaming for source level variables, we use
188 // nested (delimited) visitors for constructing subparts of the IR that will
189 // need renaming. Each source variable is assigned an index.
190 //
191 // Each nested visitor maintains a list of free variable uses in the body.
192 // These are implemented as a list of parameters, each with their own use
193 // list of references. When the delimited subexpression is plugged into the
194 // surrounding context, the free occurrences can be captured or become free
195 // occurrences in the next outer delimited subexpression.
196 //
197 // Each nested visitor maintains a list that maps indexes of variables
198 // assigned in the delimited subexpression to their reaching definition ---
199 // that is, the definition in effect at the hole in 'current'. These are
200 // used to determine if a join-point continuation needs to be passed
201 // arguments, and what the arguments are.
202 final Map<Element, int> variableIndex;
203 final List<ir.Parameter> freeVars;
204 final List<ir.Primitive> assignedVars;
186 205
206 /// Construct a top-level visitor.
187 IrBuilder(TreeElements elements, Compiler compiler, this.sourceFile) 207 IrBuilder(TreeElements elements, Compiler compiler, this.sourceFile)
188 : super(elements, compiler); 208 : returnContinuation = new ir.Continuation.retrn(),
209 parameters = <ir.Parameter>[],
210 variableIndex = <Element, int>{},
211 freeVars = null,
212 assignedVars = <ir.Primitive>[],
213 super(elements, compiler);
214
215 /// Construct a delimited visitor.
216 IrBuilder.delimited(IrBuilder parent)
217 : sourceFile = parent.sourceFile,
218 returnContinuation = parent.returnContinuation,
219 parameters = parent.parameters,
220 variableIndex = parent.variableIndex,
221 freeVars = new List<ir.Parameter>.generate(
222 parent.assignedVars.length, (_) => new ir.Parameter(null),
223 growable: false),
224 assignedVars = new List<ir.Primitive>.generate(
225 parent.assignedVars.length, (_) => null),
226 super(parent.elements, parent.compiler);
189 227
190 /** 228 /**
191 * Builds the [ir.FunctionDefinition] for a function element. In case the 229 * Builds the [ir.FunctionDefinition] for a function element. In case the
192 * function uses features that cannot be expressed in the IR, this function 230 * function uses features that cannot be expressed in the IR, this function
193 * returns `null`. 231 * returns `null`.
194 */ 232 */
195 ir.FunctionDefinition buildFunction(FunctionElement functionElement) { 233 ir.FunctionDefinition buildFunction(FunctionElement functionElement) {
196 return nullIfGiveup(() => buildFunctionInternal(functionElement)); 234 return nullIfGiveup(() => buildFunctionInternal(functionElement));
197 } 235 }
198 236
199 ir.FunctionDefinition buildFunctionInternal(FunctionElement element) { 237 ir.FunctionDefinition buildFunctionInternal(FunctionElement element) {
200 assert(invariant(element, element.isImplementation)); 238 assert(invariant(element, element.isImplementation));
201 ast.FunctionExpression function = element.parseNode(compiler); 239 ast.FunctionExpression function = element.parseNode(compiler);
202 assert(function != null); 240 assert(function != null);
203 assert(!function.modifiers.isExternal()); 241 assert(!function.modifiers.isExternal());
204 assert(elements[function] != null); 242 assert(elements[function] != null);
205 243
206 returnContinuation = new ir.Continuation.retrn();
207 root = current = null; 244 root = current = null;
208 245
209 FunctionSignature signature = element.functionSignature; 246 FunctionSignature signature = element.functionSignature;
210 signature.orderedForEachParameter((parameterElement) { 247 signature.orderedForEachParameter((parameterElement) {
211 ir.Parameter parameter = new ir.Parameter(parameterElement); 248 ir.Parameter parameter = new ir.Parameter(parameterElement);
212 parameters.add(parameter); 249 parameters.add(parameter);
213 variableIndex[parameterElement] = assignedVars.length; 250 variableIndex[parameterElement] = assignedVars.length;
214 assignedVars.add(parameter); 251 assignedVars.add(parameter);
215 }); 252 });
216 253
217 visit(function.body); 254 visit(function.body);
218 ensureReturn(function); 255 ensureReturn(function);
219 return new ir.FunctionDefinition(returnContinuation, parameters, root); 256 return new ir.FunctionDefinition(returnContinuation, parameters, root);
220 } 257 }
221 258
222 ConstantSystem get constantSystem => compiler.backend.constantSystem; 259 ConstantSystem get constantSystem => compiler.backend.constantSystem;
223 260
224 bool get isOpen => root == null || current != null; 261 bool get isOpen => root == null || current != null;
225 262
226 // Plug an expression into the 'hole' in the context being accumulated. The 263 // Plug an expression into the 'hole' in the context being accumulated. The
227 // empty context (just a hole) is represented by root (and current) being 264 // empty context (just a hole) is represented by root (and current) being
228 // null. Since the hole in the current context is filled by this function, 265 // null. Since the hole in the current context is filled by this function,
229 // the new hole must be in the newly added expression---which becomes the 266 // the new hole must be in the newly added expression---which becomes the
230 // new value of current. 267 // new value of current.
231 void add(ir.Expression expr) { 268 void add(ir.Expression expr) {
269 assert(isOpen);
232 if (root == null) { 270 if (root == null) {
233 root = current = expr; 271 root = current = expr;
234 } else if (current != null) { 272 } else {
235 current = current.plug(expr); 273 current = current.plug(expr);
236 } 274 }
237 } 275 }
238 276
239 /** 277 /**
240 * Add an explicit `return null` for functions that don't have a return 278 * Add an explicit `return null` for functions that don't have a return
241 * statement on each branch. This includes functions with an empty body, 279 * statement on each branch. This includes functions with an empty body,
242 * such as `foo(){ }`. 280 * such as `foo(){ }`.
243 */ 281 */
244 void ensureReturn(ast.FunctionExpression node) { 282 void ensureReturn(ast.FunctionExpression node) {
245 if (!isOpen) return; 283 if (!isOpen) return;
246 ir.Constant constant = new ir.Constant(constantSystem.createNull()); 284 ir.Constant constant = new ir.Constant(constantSystem.createNull());
247 add(new ir.LetPrim(constant)); 285 add(new ir.LetPrim(constant));
248 add(new ir.InvokeContinuation(returnContinuation, constant)); 286 add(new ir.InvokeContinuation(returnContinuation, [constant]));
249 current = null; 287 current = null;
250 } 288 }
251 289
252 ir.Definition visit(ast.Node node) => node.accept(this); 290 ir.Primitive visit(ast.Node node) => node.accept(this);
253 291
254 // ==== Statements ==== 292 // ==== Statements ====
255 // Build(Block(stamements), C) = C' 293 // Build(Block(stamements), C) = C'
256 // where C' = statements.fold(Build, C) 294 // where C' = statements.fold(Build, C)
257 ir.Definition visitBlock(ast.Block node) { 295 ir.Primitive visitBlock(ast.Block node) {
258 assert(isOpen); 296 assert(isOpen);
259 for (ast.Node n in node.statements.nodes) { 297 for (ast.Node n in node.statements.nodes) {
260 visit(n); 298 visit(n);
261 if (!isOpen) return null; 299 if (!isOpen) return null;
262 } 300 }
263 return null; 301 return null;
264 } 302 }
265 303
266 // Build(EmptyStatement, C) = C 304 // Build(EmptyStatement, C) = C
267 ir.Definition visitEmptyStatement(ast.EmptyStatement node) { 305 ir.Primitive visitEmptyStatement(ast.EmptyStatement node) {
268 assert(isOpen); 306 assert(isOpen);
269 return null; 307 return null;
270 } 308 }
271 309
272 // Build(ExpressionStatement(e), C) = C' 310 // Build(ExpressionStatement(e), C) = C'
273 // where (C', _) = Build(e, C) 311 // where (C', _) = Build(e, C)
274 ir.Definition visitExpressionStatement(ast.ExpressionStatement node) { 312 ir.Primitive visitExpressionStatement(ast.ExpressionStatement node) {
275 assert(isOpen); 313 assert(isOpen);
276 visit(node.expression); 314 visit(node.expression);
277 return null; 315 return null;
278 } 316 }
279 317
280 ir.Definition visitIf(ast.If node) { 318 ir.Primitive visitIf(ast.If node) {
281 assert(isOpen); 319 assert(isOpen);
282 return giveup(); 320 ir.Primitive condition = visit(node.condition);
321
322 // The then and else parts are delimited.
323 IrBuilder thenBuilder = new IrBuilder.delimited(this);
324 thenBuilder.visit(node.thenPart);
325 IrBuilder elseBuilder = new IrBuilder.delimited(this);
326 if (node.hasElsePart) elseBuilder.visit(node.elsePart);
327
328 // The free variables in the then and else parts are uses of definitions
329 // from an outer builder. Capture them or propagate them outward. The
330 // assigned variables in the then and else parts are arguments to the join
331 // point continuation if any.
332
333 // FreeVars is initially the length of assignedVars of the parent, and it
334 // does not grow. AssignedVars can grow.
335 assert(assignedVars.length == thenBuilder.freeVars.length);
336 assert(assignedVars.length == elseBuilder.freeVars.length);
337 assert(assignedVars.length <= thenBuilder.assignedVars.length);
338 assert(assignedVars.length <= elseBuilder.assignedVars.length);
339 List<ir.Parameter> parameters = <ir.Parameter>[];
340 List<ir.Primitive> thenArguments = <ir.Primitive>[];
341 List<ir.Primitive> elseArguments = <ir.Primitive>[];
342 for (int i = 0; i < assignedVars.length; ++i) {
343 // These are the last assignments, if any, in the then and else
344 // continuations respectively (if they can reach the join point). If a
345 // variable is assigned in either branch reaching the join point, it has
346 // different values that must be passed as an argument to the join point
347 // continuation.
348 ir.Definition thenAssignment =
349 thenBuilder.isOpen ? thenBuilder.assignedVars[i] : null;
350 ir.Definition elseAssignment =
351 elseBuilder.isOpen ? elseBuilder.assignedVars[i] : null;
352 if (thenAssignment != null || elseAssignment != null) {
353 // In the case that not both then and else parts can reach the join
354 // point, there will still be a join-point continuation possibly with
355 // arguments passed to it. Such singly-used continuations should be
356 // eliminated by shrinking conversions (because they can arise
357 // otherwise as the result of optimization).
358 ir.Parameter parameter = new ir.Parameter(null);
359 parameters.add(parameter);
360 thenArguments.add(thenAssignment == null
361 ? thenBuilder.freeVars[i]
362 : thenAssignment);
363 elseArguments.add(elseAssignment == null
364 ? elseBuilder.freeVars[i]
365 : elseAssignment);
366 }
367 }
368
369 // Create a then and else continuations and a join continuation if
370 // necessary. Jump to the join continuation from the exits of the then
371 // and else continuations.
372 ir.Continuation joinContinuation;
373 ir.Continuation thenContinuation = new ir.Continuation([]);
374 ir.Continuation elseContinuation = new ir.Continuation([]);
375 if (thenBuilder.isOpen || elseBuilder.isOpen) {
376 joinContinuation = new ir.Continuation(parameters);
377 if (thenBuilder.isOpen) {
378 thenBuilder.add(
379 new ir.InvokeContinuation(joinContinuation, thenArguments));
380 }
381 if (elseBuilder.isOpen) {
382 elseBuilder.add(
383 new ir.InvokeContinuation(joinContinuation, elseArguments));
384 }
385 }
386 thenContinuation.body = thenBuilder.root;
387 elseContinuation.body = elseBuilder.root;
388
389 // Capture free occurrences in the then and else bodies. This is done
390 // after creating invocations of the join continuation so free join
391 // continuation arguments are properly captured.
392 //
393 // Also add join continuation parameters as assignments for the join body.
394 // This is done last because the assigned variables are updated in place.
395 int parameterIndex = 0;
396 for (int i = 0; i < assignedVars.length; ++i) {
397 // This is the definition that reaches the then and else continuations.
398 // All free uses in either continuation are uses of this definition.
399 ir.Definition reachingDefinition =
400 assignedVars[i] == null ? freeVars[i] : assignedVars[i];
401 reachingDefinition
402 ..substituteFor(thenBuilder.freeVars[i])
403 ..substituteFor(elseBuilder.freeVars[i]);
404
405 if ((thenBuilder.isOpen && thenBuilder.assignedVars[i] != null) ||
406 (elseBuilder.isOpen && elseBuilder.assignedVars[i] != null)) {
407 assignedVars[i] = parameters[parameterIndex++];
408 }
409 }
410
411 ir.Expression branch =
412 new ir.LetCont(thenContinuation,
413 new ir.LetCont(elseContinuation,
414 new ir.Branch(new ir.IsTrue(condition),
415 thenContinuation,
416 elseContinuation)));
417 if (joinContinuation == null) {
418 add(branch);
419 current = null;
420 } else {
421 add(new ir.LetCont(joinContinuation, branch));
422 }
423 return null;
283 } 424 }
284 425
285 ir.Definition visitVariableDefinitions(ast.VariableDefinitions node) { 426 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) {
286 assert(isOpen); 427 assert(isOpen);
287 for (ast.Node definition in node.definitions.nodes) { 428 for (ast.Node definition in node.definitions.nodes) {
288 Element element = elements[definition]; 429 Element element = elements[definition];
289 // Definitions are either SendSets if there is an initializer, or 430 // Definitions are either SendSets if there is an initializer, or
290 // Identifiers if there is no initializer. 431 // Identifiers if there is no initializer.
291 if (definition is ast.SendSet) { 432 if (definition is ast.SendSet) {
292 assert(!definition.arguments.isEmpty); 433 assert(!definition.arguments.isEmpty);
293 assert(definition.arguments.tail.isEmpty); 434 assert(definition.arguments.tail.isEmpty);
294 ir.Definition initialValue = visit(definition.arguments.head); 435 ir.Primitive initialValue = visit(definition.arguments.head);
295 // Do not continue adding instructions if the initializer throws.
296 if (!isOpen) return null;
297 variableIndex[element] = assignedVars.length; 436 variableIndex[element] = assignedVars.length;
298 assignedVars.add(initialValue); 437 assignedVars.add(initialValue);
299 } else { 438 } else {
300 assert(definition is ast.Identifier); 439 assert(definition is ast.Identifier);
301 // The initial value is null. 440 // The initial value is null.
302 // TODO(kmillikin): Consider pooling constants. 441 // TODO(kmillikin): Consider pooling constants.
303 ir.Constant constant = new ir.Constant(constantSystem.createNull()); 442 ir.Constant constant = new ir.Constant(constantSystem.createNull());
304 add(new ir.LetPrim(constant)); 443 add(new ir.LetPrim(constant));
305 variableIndex[element] = assignedVars.length; 444 variableIndex[element] = assignedVars.length;
306 assignedVars.add(constant); 445 assignedVars.add(constant);
307 } 446 }
308 } 447 }
309 return null; 448 return null;
310 } 449 }
311 450
312 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] 451 // Build(Return(e), C) = C'[InvokeContinuation(return, x)]
313 // where (C', x) = Build(e, C) 452 // where (C', x) = Build(e, C)
314 // 453 //
315 // Return without a subexpression is translated as if it were return null. 454 // Return without a subexpression is translated as if it were return null.
316 ir.Definition visitReturn(ast.Return node) { 455 ir.Primitive visitReturn(ast.Return node) {
317 assert(isOpen); 456 assert(isOpen);
318 // TODO(lry): support native returns. 457 // TODO(lry): support native returns.
319 if (node.beginToken.value == 'native') return giveup(); 458 if (node.beginToken.value == 'native') return giveup();
320 ir.Definition value; 459 ir.Primitive value;
321 if (node.expression == null) { 460 if (node.expression == null) {
322 value = new ir.Constant(constantSystem.createNull()); 461 value = new ir.Constant(constantSystem.createNull());
323 add(new ir.LetPrim(value)); 462 add(new ir.LetPrim(value));
324 } else { 463 } else {
325 value = visit(node.expression); 464 value = visit(node.expression);
326 if (!isOpen) return null;
327 } 465 }
328 add(new ir.InvokeContinuation(returnContinuation, value)); 466 add(new ir.InvokeContinuation(returnContinuation, [value]));
329 current = null; 467 current = null;
330 return null; 468 return null;
331 } 469 }
332 470
333 // ==== Expressions ==== 471 // ==== Expressions ====
334 // For all simple literals: 472 // For all simple literals:
335 // Build(Literal(c), C) = C[let val x = Constant(c) in [], x] 473 // Build(Literal(c), C) = C[let val x = Constant(c) in [], x]
336 ir.Definition visitLiteralBool(ast.LiteralBool node) { 474 ir.Primitive visitLiteralBool(ast.LiteralBool node) {
337 assert(isOpen); 475 assert(isOpen);
338 ir.Constant constant = 476 ir.Constant constant =
339 new ir.Constant(constantSystem.createBool(node.value)); 477 new ir.Constant(constantSystem.createBool(node.value));
340 add(new ir.LetPrim(constant)); 478 add(new ir.LetPrim(constant));
341 return constant; 479 return constant;
342 } 480 }
343 481
344 ir.Definition visitLiteralDouble(ast.LiteralDouble node) { 482 ir.Primitive visitLiteralDouble(ast.LiteralDouble node) {
345 assert(isOpen); 483 assert(isOpen);
346 ir.Constant constant = 484 ir.Constant constant =
347 new ir.Constant(constantSystem.createDouble(node.value)); 485 new ir.Constant(constantSystem.createDouble(node.value));
348 add(new ir.LetPrim(constant)); 486 add(new ir.LetPrim(constant));
349 return constant; 487 return constant;
350 } 488 }
351 489
352 ir.Definition visitLiteralInt(ast.LiteralInt node) { 490 ir.Primitive visitLiteralInt(ast.LiteralInt node) {
353 assert(isOpen); 491 assert(isOpen);
354 ir.Constant constant = 492 ir.Constant constant =
355 new ir.Constant(constantSystem.createInt(node.value)); 493 new ir.Constant(constantSystem.createInt(node.value));
356 add(new ir.LetPrim(constant)); 494 add(new ir.LetPrim(constant));
357 return constant; 495 return constant;
358 } 496 }
359 497
360 498
361 ir.Definition visitLiteralNull(ast.LiteralNull node) { 499 ir.Primitive visitLiteralNull(ast.LiteralNull node) {
362 assert(isOpen); 500 assert(isOpen);
363 ir.Constant constant = new ir.Constant(constantSystem.createNull()); 501 ir.Constant constant = new ir.Constant(constantSystem.createNull());
364 add(new ir.LetPrim(constant)); 502 add(new ir.LetPrim(constant));
365 return constant; 503 return constant;
366 } 504 }
367 505
368 // TODO(kmillikin): other literals. Strings require quoting and escaping 506 // TODO(kmillikin): other literals. Strings require quoting and escaping
369 // in the Dart backend. 507 // in the Dart backend.
370 // LiteralString 508 // LiteralString
371 // LiteralList 509 // LiteralList
372 // LiteralMap 510 // LiteralMap
373 // LiteralMapEntry 511 // LiteralMapEntry
374 // LiteralSymbol 512 // LiteralSymbol
375 513
376 ir.Definition visitParenthesizedExpression( 514 ir.Primitive visitParenthesizedExpression(
377 ast.ParenthesizedExpression node) { 515 ast.ParenthesizedExpression node) {
516 assert(isOpen);
378 return visit(node.expression); 517 return visit(node.expression);
379 } 518 }
380 519
381 // ==== Sends ==== 520 // ==== Sends ====
382 ir.Definition visitAssert(ast.Send node) { 521 ir.Primitive visitAssert(ast.Send node) {
522 assert(isOpen);
383 return giveup(); 523 return giveup();
384 } 524 }
385 525
386 ir.Definition visitClosureSend(ast.Send node) { 526 ir.Primitive visitClosureSend(ast.Send node) {
527 assert(isOpen);
387 return giveup(); 528 return giveup();
388 } 529 }
389 530
390 ir.Definition visitDynamicSend(ast.Send node) { 531 ir.Primitive visitDynamicSend(ast.Send node) {
532 assert(isOpen);
391 return giveup(); 533 return giveup();
392 } 534 }
393 535
394 ir.Definition visitGetterSend(ast.Send node) { 536 ir.Primitive visitGetterSend(ast.Send node) {
537 assert(isOpen);
395 Element element = elements[node]; 538 Element element = elements[node];
396 if (!Elements.isLocal(element)) return giveup(); 539 if (!Elements.isLocal(element)) return giveup();
397 return assignedVars[variableIndex[element]]; 540 int index = variableIndex[element];
541 ir.Primitive value = assignedVars[index];
542 return value == null ? freeVars[index] : value;
398 } 543 }
399 544
400 ir.Definition visitOperatorSend(ast.Send node) { 545 ir.Primitive visitOperatorSend(ast.Send node) {
546 assert(isOpen);
401 return giveup(); 547 return giveup();
402 } 548 }
403 549
404 // Build(StaticSend(f, arguments), C) = C[C'[InvokeStatic(f, xs)]] 550 // Build(StaticSend(f, arguments), C) = C[C'[InvokeStatic(f, xs)]]
405 // where (C', xs) = arguments.fold(Build, C) 551 // where (C', xs) = arguments.fold(Build, C)
406 ir.Definition visitStaticSend(ast.Send node) { 552 ir.Primitive visitStaticSend(ast.Send node) {
407 assert(isOpen); 553 assert(isOpen);
408 Element element = elements[node]; 554 Element element = elements[node];
409 // TODO(lry): support static fields. (separate IR instruction?) 555 // TODO(lry): support static fields. (separate IR instruction?)
410 if (element.isField() || element.isGetter()) return giveup(); 556 if (element.isField() || element.isGetter()) return giveup();
411 // TODO(kmillikin): support static setters. 557 // TODO(kmillikin): support static setters.
412 if (element.isSetter()) return giveup(); 558 if (element.isSetter()) return giveup();
413 // TODO(lry): support constructors / factory calls. 559 // TODO(lry): support constructors / factory calls.
414 if (element.isConstructor()) return giveup(); 560 if (element.isConstructor()) return giveup();
415 // TODO(lry): support foreign functions. 561 // TODO(lry): support foreign functions.
416 if (element.isForeign(compiler)) return giveup(); 562 if (element.isForeign(compiler)) return giveup();
417 // TODO(lry): for elements that could not be resolved emit code to throw a 563 // TODO(lry): for elements that could not be resolved emit code to throw a
418 // [NoSuchMethodError]. 564 // [NoSuchMethodError].
419 if (element.isErroneous()) return giveup(); 565 if (element.isErroneous()) return giveup();
420 // TODO(lry): generate IR for object identicality. 566 // TODO(lry): generate IR for object identicality.
421 if (element == compiler.identicalFunction) giveup(); 567 if (element == compiler.identicalFunction) giveup();
422 568
423 Selector selector = elements.getSelector(node); 569 Selector selector = elements.getSelector(node);
424 // TODO(lry): support named arguments 570 // TODO(lry): support named arguments
425 if (selector.namedArgumentCount != 0) return giveup(); 571 if (selector.namedArgumentCount != 0) return giveup();
426 572
427 // TODO(kmillikin): support a receiver: A.m(). 573 // TODO(kmillikin): support a receiver: A.m().
428 if (node.receiver != null) return giveup(); 574 if (node.receiver != null) return giveup();
429 575
430 List arguments = []; 576 List arguments = [];
431 // TODO(lry): support default arguments, need support for locals. 577 // TODO(lry): support default arguments, need support for locals.
432 bool succeeded = selector.addArgumentsToList( 578 bool succeeded = selector.addArgumentsToList(
433 node.arguments, arguments, element.implementation, 579 node.arguments, arguments, element.implementation, visit,
434 // Guard against visiting arguments after an argument expression throws. 580 (node) => giveup(), compiler);
435 (node) => isOpen ? visit(node) : null,
436 (node) => giveup(),
437 compiler);
438 if (!succeeded) { 581 if (!succeeded) {
439 // TODO(lry): generate code to throw a [WrongArgumentCountError]. 582 // TODO(lry): generate code to throw a [WrongArgumentCountError].
440 return giveup(); 583 return giveup();
441 } 584 }
442 if (!isOpen) return null;
443 ir.Parameter v = new ir.Parameter(null); 585 ir.Parameter v = new ir.Parameter(null);
444 ir.Continuation k = new ir.Continuation([v]); 586 ir.Continuation k = new ir.Continuation([v]);
445 ir.Expression invoke = 587 ir.Expression invoke =
446 new ir.InvokeStatic(element, selector, k, arguments); 588 new ir.InvokeStatic(element, selector, k, arguments);
447 add(new ir.LetCont(k, invoke)); 589 add(new ir.LetCont(k, invoke));
448 return v; 590 return v;
449 } 591 }
450 592
451 ir.Definition visitSuperSend(ast.Send node) { 593 ir.Primitive visitSuperSend(ast.Send node) {
594 assert(isOpen);
452 return giveup(); 595 return giveup();
453 } 596 }
454 597
455 ir.Definition visitTypeReferenceSend(ast.Send node) { 598 ir.Primitive visitTypeReferenceSend(ast.Send node) {
599 assert(isOpen);
456 return giveup(); 600 return giveup();
457 } 601 }
458 602
459 ir.Definition visitSendSet(ast.SendSet node) { 603 ir.Primitive visitSendSet(ast.SendSet node) {
604 assert(isOpen);
460 Element element = elements[node]; 605 Element element = elements[node];
461 if (!Elements.isLocal(element)) return giveup(); 606 if (!Elements.isLocal(element)) return giveup();
462 if (node.assignmentOperator.source != '=') return giveup(); 607 if (node.assignmentOperator.source != '=') return giveup();
463 // Exactly one argument expected for a simple assignment. 608 // Exactly one argument expected for a simple assignment.
464 assert(!node.arguments.isEmpty); 609 assert(!node.arguments.isEmpty);
465 assert(node.arguments.tail.isEmpty); 610 assert(node.arguments.tail.isEmpty);
466 ir.Definition result = visit(node.arguments.head); 611 ir.Primitive result = visit(node.arguments.head);
467 assignedVars[variableIndex[element]] = result; 612 assignedVars[variableIndex[element]] = result;
468 return result; 613 return result;
469 } 614 }
470 615
471 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; 616 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted";
472 617
473 ir.Definition giveup() => throw ABORT_IRNODE_BUILDER; 618 ir.Primitive giveup() => throw ABORT_IRNODE_BUILDER;
474 619
475 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) { 620 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) {
476 try { 621 try {
477 return action(); 622 return action();
478 } catch(e) { 623 } catch(e) {
479 if (e == ABORT_IRNODE_BUILDER) return null; 624 if (e == ABORT_IRNODE_BUILDER) return null;
480 rethrow; 625 rethrow;
481 } 626 }
482 } 627 }
483 628
484 void internalError(String reason, {ast.Node node}) { 629 void internalError(String reason, {ast.Node node}) {
485 giveup(); 630 giveup();
486 } 631 }
487 } 632 }
488 633
489 // Verify that types are ones that can be reconstructed by the type emitter. 634 // Verify that types are ones that can be reconstructed by the type emitter.
490 class SupportedTypeVerifier extends DartTypeVisitor<bool, Null> { 635 class SupportedTypeVerifier extends DartTypeVisitor<bool, Null> {
491 bool visit(DartType type, Null _) => type.accept(this, null); 636 bool visit(DartType type, Null _) => type.accept(this, null);
492 637
493 bool visitType(DartType type, Null _) => false; 638 bool visitType(DartType type, Null _) => false;
494 639
495 bool visitVoidType(VoidType type, Null _) => true; 640 bool visitVoidType(VoidType type, Null _) => true;
496 641
497 // Currently, InterfaceType and TypedefType are supported so long as they 642 // Currently, InterfaceType and TypedefType are supported so long as they
498 // do not have type parameters. They are subclasses of GenericType. 643 // do not have type parameters. They are subclasses of GenericType.
499 bool visitGenericType(GenericType type, Null _) => !type.isGeneric; 644 bool visitGenericType(GenericType type, Null _) => !type.isGeneric;
500 } 645 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698