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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart

Issue 231863007: Support local variables in dart2dart. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 8 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) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 dart_tree; 5 library dart_tree;
6 6
7 import '../dart2jslib.dart' as dart2js; 7 import '../dart2jslib.dart' as dart2js;
8 import '../dart_types.dart'; 8 import '../dart_types.dart';
9 import '../util/util.dart'; 9 import '../util/util.dart';
10 import '../elements/elements.dart' 10 import '../elements/elements.dart'
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 // Uses of IR definitions are replaced with Tree variables. This is the 210 // Uses of IR definitions are replaced with Tree variables. This is the
211 // mapping from definitions to variables. 211 // mapping from definitions to variables.
212 final Map<ir.Definition, Variable> variables = {}; 212 final Map<ir.Definition, Variable> variables = {};
213 213
214 FunctionDefinition function; 214 FunctionDefinition function;
215 ir.Continuation returnContinuation; 215 ir.Continuation returnContinuation;
216 216
217 Builder(this.compiler); 217 Builder(this.compiler);
218 218
219 FunctionDefinition build(ir.FunctionDefinition node) { 219 FunctionDefinition build(ir.FunctionDefinition node) {
220 node.accept(this); 220 visit(node);
221 return function; 221 return function;
222 } 222 }
223 223
224 List<Expression> translateArguments(List<ir.Reference> args) { 224 List<Expression> translateArguments(List<ir.Reference> args) {
225 return new List.generate(args.length, 225 return new List.generate(args.length,
226 (int index) => variables[args[index].definition]); 226 (int index) => variables[args[index].definition]);
227 } 227 }
228 228
229 Expression visitFunctionDefinition(ir.FunctionDefinition node) { 229 Expression visitFunctionDefinition(ir.FunctionDefinition node) {
230 returnContinuation = node.returnContinuation; 230 returnContinuation = node.returnContinuation;
231 List<Variable> parameters = <Variable>[]; 231 List<Variable> parameters = <Variable>[];
232 for (ir.Parameter p in node.parameters) { 232 for (ir.Parameter p in node.parameters) {
233 Variable parameter = new Variable(p.element); 233 Variable parameter = new Variable(p.element);
234 parameters.add(parameter); 234 parameters.add(parameter);
235 variables[p] = parameter; 235 variables[p] = parameter;
236 } 236 }
237 function = new FunctionDefinition(parameters, node.body.accept(this)); 237 function = new FunctionDefinition(parameters, visit(node.body));
238 return null; 238 return null;
239 } 239 }
240 240
241 Expression visitLetPrim(ir.LetPrim node) { 241 Expression visitLetPrim(ir.LetPrim node) {
242 // LetPrim is translated to LetVal. 242 // LetPrim is translated to LetVal.
243 Expression definition = node.primitive.accept(this); 243 Expression definition = visit(node.primitive);
244 if (node.primitive.hasAtLeastOneUse) { 244 if (node.primitive.hasAtLeastOneUse) {
245 Variable variable = new Variable(null); 245 Variable variable = new Variable(null);
246 variables[node.primitive] = variable; 246 variables[node.primitive] = variable;
247 return new LetVal(node.primitive.hasExactlyOneUse, variable, 247 return new LetVal(node.primitive.hasExactlyOneUse, variable,
248 definition, node.body.accept(this)); 248 definition, visit(node.body));
249 } else if (node.primitive is ir.Constant) {
250 // TODO(kmillikin): Implement more systematic treatment of pure CPS
251 // values (e.g., as part of a shrinking reductions pass).
252 return visit(node.body);
249 } else { 253 } else {
250 return new Sequence([definition, node.body.accept(this)]); 254 return new Sequence([definition, visit(node.body)]);
251 } 255 }
252 } 256 }
253 257
254 Expression visitLetCont(ir.LetCont node) { 258 Expression visitLetCont(ir.LetCont node) {
255 // TODO(kmillikin): Allow continuations to have multiple uses. This could 259 // TODO(kmillikin): Allow continuations to have multiple uses. This could
256 // arise due to the representation of local control flow or due to 260 // arise due to the representation of local control flow or due to
257 // optimization. 261 // optimization.
258 assert(node.continuation.hasAtMostOneUse); 262 assert(node.continuation.hasAtMostOneUse);
259 return node.body.accept(this); 263 return visit(node.body);
260 } 264 }
261 265
262 Expression visitInvokeStatic(ir.InvokeStatic node) { 266 Expression visitInvokeStatic(ir.InvokeStatic node) {
263 // Calls are translated to direct style. 267 // Calls are translated to direct style.
264 List<Expression> arguments = translateArguments(node.arguments); 268 List<Expression> arguments = translateArguments(node.arguments);
265 Expression invoke = new InvokeStatic(node.target, arguments); 269 Expression invoke = new InvokeStatic(node.target, arguments);
266 ir.Continuation cont = node.continuation.definition; 270 ir.Continuation cont = node.continuation.definition;
267 if (cont == returnContinuation) { 271 if (cont == returnContinuation) {
268 return new Return(invoke); 272 return new Return(invoke);
269 } else { 273 } else {
270 assert(cont.hasExactlyOneUse); 274 assert(cont.hasExactlyOneUse);
271 if (cont.parameter.hasAtLeastOneUse) { 275 if (cont.parameter.hasAtLeastOneUse) {
272 Variable variable = new Variable(null); 276 Variable variable = new Variable(null);
273 variables[cont.parameter] = variable; 277 variables[cont.parameter] = variable;
274 return new LetVal(cont.parameter.hasExactlyOneUse, variable, 278 return new LetVal(cont.parameter.hasExactlyOneUse, variable,
275 invoke, cont.body.accept(this)); 279 invoke, visit(cont.body));
276 } else { 280 } else {
277 return new Sequence([invoke, cont.body.accept(this)]); 281 return new Sequence([invoke, visit(cont.body)]);
278 } 282 }
279 } 283 }
280 } 284 }
281 285
282 Expression visitInvokeContinuation(ir.InvokeContinuation node) { 286 Expression visitInvokeContinuation(ir.InvokeContinuation node) {
283 // TODO(kmillikin): Support non-return continuations. These could arise 287 // TODO(kmillikin): Support non-return continuations. These could arise
284 // due to local control flow or due to inlining or other optimization. 288 // due to local control flow or due to inlining or other optimization.
285 assert(node.continuation.definition == returnContinuation); 289 assert(node.continuation.definition == returnContinuation);
286 return new Return(variables[node.argument.definition]); 290 return new Return(variables[node.argument.definition]);
287 } 291 }
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
324 * See [visitVariable] for the implementation of the heuristic for propagating 328 * See [visitVariable] for the implementation of the heuristic for propagating
325 * a definition. 329 * a definition.
326 */ 330 */
327 class Unnamer extends Visitor<Expression> { 331 class Unnamer extends Visitor<Expression> {
328 // The binding environment. The rightmost element of the list is the nearest 332 // The binding environment. The rightmost element of the list is the nearest
329 // enclosing binding. 333 // enclosing binding.
330 List<LetVal> environment; 334 List<LetVal> environment;
331 335
332 void unname(FunctionDefinition definition) { 336 void unname(FunctionDefinition definition) {
333 environment = <LetVal>[]; 337 environment = <LetVal>[];
334 definition.body = definition.body.accept(this); 338 definition.body = visit(definition.body);
335 339
336 // TODO(kmillikin): Allow definitions that are not propagated. Here, 340 // TODO(kmillikin): Allow definitions that are not propagated. Here,
337 // this means rebuilding the binding with a recursively unnamed definition, 341 // this means rebuilding the binding with a recursively unnamed definition,
338 // or else introducing a variable definition and an assignment. 342 // or else introducing a variable definition and an assignment.
339 assert(environment.isEmpty); 343 assert(environment.isEmpty);
340 } 344 }
341 345
342 Expression visitVariable(Variable node) { 346 Expression visitVariable(Variable node) {
343 // Propagate a variable's definition to its use site if: 347 // Propagate a variable's definition to its use site if:
344 // 1. It has a single use, to avoid code growth and potential duplication 348 // 1. It has a single use, to avoid code growth and potential duplication
345 // of side effects, AND 349 // of side effects, AND
346 // 2a. It is pure (i.e., does not have side effects that prevent it from 350 // 2a. It is pure (i.e., does not have side effects that prevent it from
347 // being moved), OR 351 // being moved), OR
348 // 2b. There are only pure expressions between the definition and use. 352 // 2b. There are only pure expressions between the definition and use.
349 353
350 // TODO(kmillikin): It's not always beneficial to propagate pure 354 // TODO(kmillikin): It's not always beneficial to propagate pure
351 // definitions---it can prevent propagation of their inputs. Implement 355 // definitions---it can prevent propagation of their inputs. Implement
352 // a heuristic to avoid this. 356 // a heuristic to avoid this.
353 357
354 // TODO(kmillikin): Replace linear search with something faster in 358 // TODO(kmillikin): Replace linear search with something faster in
355 // practice. 359 // practice.
356 bool seenImpure = false; 360 bool seenImpure = false;
357 for (int i = environment.length - 1; i >= 0; --i) { 361 for (int i = environment.length - 1; i >= 0; --i) {
358 if (environment[i].variable == node) { 362 if (environment[i].variable == node) {
359 if ((!seenImpure || environment[i].definition.isPure) 363 if ((!seenImpure || environment[i].definition.isPure)
360 && environment[i].hasExactlyOneUse) { 364 && environment[i].hasExactlyOneUse) {
361 // Use the definition if it is pure or if it is the first impure 365 // Use the definition if it is pure or if it is the first impure
362 // definition (i.e., propagating past only pure expressions). 366 // definition (i.e., propagating past only pure expressions).
363 return environment.removeAt(i).definition.accept(this); 367 return visit(environment.removeAt(i).definition);
364 } 368 }
365 break; 369 break;
366 } else if (!environment[i].definition.isPure) { 370 } else if (!environment[i].definition.isPure) {
367 // Once the first impure definition is seen, impure definitions should 371 // Once the first impure definition is seen, impure definitions should
368 // no longer be propagated. Continue searching for a pure definition. 372 // no longer be propagated. Continue searching for a pure definition.
369 seenImpure = true; 373 seenImpure = true;
370 } 374 }
371 } 375 }
372 // If the definition could not be propagated, leave the variable use. 376 // If the definition could not be propagated, leave the variable use.
373 return node; 377 return node;
374 } 378 }
375 379
376 Expression visitSequence(Sequence node) { 380 Expression visitSequence(Sequence node) {
377 for (int i = 0; i < node.expressions.length; ++i) { 381 for (int i = 0; i < node.expressions.length; ++i) {
378 node.expressions[i] = node.expressions[i].accept(this); 382 node.expressions[i] = visit(node.expressions[i]);
379 } 383 }
380 return node; 384 return node;
381 } 385 }
382 386
383 Expression visitLetVal(LetVal node) { 387 Expression visitLetVal(LetVal node) {
384 environment.add(node); 388 environment.add(node);
385 Expression body = node.body.accept(this); 389 Expression body = visit(node.body);
386 390
387 if (!environment.isEmpty && environment.last == node) { 391 if (!environment.isEmpty && environment.last == node) {
388 // The definition could not be propagated. Residualize the let binding. 392 // The definition could not be propagated. Residualize the let binding.
389 node.body = body; 393 node.body = body;
390 environment.removeLast(); 394 environment.removeLast();
391 node.definition = node.definition.accept(this); 395 node.definition = visit(node.definition);
392 return node; 396 return node;
393 } 397 }
394 assert(!environment.contains(node)); 398 assert(!environment.contains(node));
395 return body; 399 return body;
396 } 400 }
397 401
398 Expression visitInvokeStatic(InvokeStatic node) { 402 Expression visitInvokeStatic(InvokeStatic node) {
399 // Process arguments right-to-left, the opposite of evaluation order. 403 // Process arguments right-to-left, the opposite of evaluation order.
400 for (int i = node.arguments.length - 1; i >= 0; --i) { 404 for (int i = node.arguments.length - 1; i >= 0; --i) {
401 node.arguments[i] = node.arguments[i].accept(this); 405 node.arguments[i] = visit(node.arguments[i]);
402 } 406 }
403 return node; 407 return node;
404 } 408 }
405 409
406 Expression visitReturn(Return node) { 410 Expression visitReturn(Return node) {
407 node.value = node.value.accept(this); 411 node.value = visit(node.value);
408 return node; 412 return node;
409 } 413 }
410 414
411 visitConstant(Constant node) { 415 visitConstant(Constant node) {
412 return node; 416 return node;
413 } 417 }
414 } 418 }
415 419
416 /** 420 /**
417 * [Emitter] translates Tree to a Dart AST. 421 * [Emitter] translates Tree to a Dart AST.
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
483 // Reset the variable index. This function is not reentrant. 487 // Reset the variable index. This function is not reentrant.
484 Variable.counter = 0; 488 Variable.counter = 0;
485 this.treeElements = treeElements; 489 this.treeElements = treeElements;
486 ast.Identifier name = makeIdentifier(element.name); 490 ast.Identifier name = makeIdentifier(element.name);
487 491
488 TypeEmitter typeEmitter = new TypeEmitter(); 492 TypeEmitter typeEmitter = new TypeEmitter();
489 FunctionSignature signature = element.functionSignature; 493 FunctionSignature signature = element.functionSignature;
490 ast.TypeAnnotation returnType; 494 ast.TypeAnnotation returnType;
491 if (!signature.type.returnType.isDynamic) { 495 if (!signature.type.returnType.isDynamic) {
492 returnType = 496 returnType =
493 signature.type.returnType.accept(typeEmitter, treeElements); 497 typeEmitter.visitType(signature.type.returnType, treeElements);
494 } 498 }
495 499
496 List<ast.VariableDefinitions> parameterList = <ast.VariableDefinitions>[]; 500 List<ast.VariableDefinitions> parameterList = <ast.VariableDefinitions>[];
497 for (Variable parameter in definition.parameters) { 501 for (Variable parameter in definition.parameters) {
498 ParameterElement element = parameter.element; 502 ParameterElement element = parameter.element;
499 parameter.assignIdentifier(); 503 parameter.assignIdentifier();
500 ast.TypeAnnotation type; 504 ast.TypeAnnotation type;
501 if (!element.type.isDynamic) { 505 if (!element.type.isDynamic) {
502 type = element.type.accept(typeEmitter, treeElements); 506 type = typeEmitter.visitType(element.type, treeElements);
503 } 507 }
504 parameterList.add(new ast.VariableDefinitions( 508 parameterList.add(new ast.VariableDefinitions(
505 type, 509 type,
506 ast.Modifiers.EMPTY, 510 ast.Modifiers.EMPTY,
507 new ast.NodeList.singleton(parameter.identifier))); 511 new ast.NodeList.singleton(parameter.identifier)));
508 } 512 }
509 ast.NodeList parameters = 513 ast.NodeList parameters =
510 new ast.NodeList(openParen, 514 new ast.NodeList(openParen,
511 new Link<ast.Node>.fromList(parameterList), 515 new Link<ast.Node>.fromList(parameterList),
512 closeParen, 516 closeParen,
513 ','); 517 ',');
514 518
515 ast.Node body = definition.body.accept(this); 519 ast.Node body = visit(definition.body);
516 520
517 if (!variables.isEmpty) { 521 if (!variables.isEmpty) {
518 // Introduce hoisted definitions for all variables. 522 // Introduce hoisted definitions for all variables.
519 ast.Identifier modifier = 523 ast.Identifier modifier =
520 new ast.Identifier(new KeywordToken(Keyword.keywords['var'], -1)); 524 new ast.Identifier(new KeywordToken(Keyword.keywords['var'], -1));
521 ast.VariableDefinitions definitions = new ast.VariableDefinitions( 525 ast.VariableDefinitions definitions = new ast.VariableDefinitions(
522 null, 526 null,
523 new ast.Modifiers(new ast.NodeList( 527 new ast.Modifiers(new ast.NodeList(
524 null, 528 null,
525 new Link<ast.Node>.fromList([modifier]), 529 new Link<ast.Node>.fromList([modifier]),
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
562 } 566 }
563 567
564 return new ast.FunctionExpression(name, parameters, body, returnType, 568 return new ast.FunctionExpression(name, parameters, body, returnType,
565 ast.Modifiers.EMPTY, null, null); 569 ast.Modifiers.EMPTY, null, null);
566 } 570 }
567 571
568 /** 572 /**
569 * Translate a list of arguments to an AST NodeList. 573 * Translate a list of arguments to an AST NodeList.
570 */ 574 */
571 ast.NodeList translateArguments(List<Expression> args) { 575 ast.NodeList translateArguments(List<Expression> args) {
572 List<ast.Expression> arguments = 576 List<ast.Expression> arguments = args.map(visit).toList(growable: false);
573 args.map((e) => e.accept(this)).toList(growable: false);
574 return makeArgumentList(arguments); 577 return makeArgumentList(arguments);
575 } 578 }
576 579
577 /** 580 /**
578 * Concatenate a pair of AST expressions or statements into a single Block 581 * Concatenate a pair of AST expressions or statements into a single Block
579 * statement. 582 * statement.
580 */ 583 */
581 ast.Node concatenate(ast.Node first, ast.Node second) { 584 ast.Node concatenate(ast.Node first, ast.Node second) {
582 // This is a convenient but very inefficient way to accumulate statements. 585 // This is a convenient but very inefficient way to accumulate statements.
583 // The Block and NodeList nodes are not mutable so we can't simply use a 586 // The Block and NodeList nodes are not mutable so we can't simply use a
(...skipping 24 matching lines...) Expand all
608 } 611 }
609 612
610 ast.Node visitVariable(Variable node) { 613 ast.Node visitVariable(Variable node) {
611 // The scope of variables is the body of their binding, so a name has 614 // The scope of variables is the body of their binding, so a name has
612 // already been generated when we visit a variable. 615 // already been generated when we visit a variable.
613 assert(node.identifier != null); 616 assert(node.identifier != null);
614 return new ast.Send(null, node.identifier); 617 return new ast.Send(null, node.identifier);
615 } 618 }
616 619
617 ast.Node visitSequence(Sequence node) { 620 ast.Node visitSequence(Sequence node) {
618 return node.expressions.map((e) => e.accept(this)).reduce(concatenate); 621 return node.expressions.map(visit).reduce(concatenate);
619 } 622 }
620 623
621 ast.Node visitLetVal(LetVal node) { 624 ast.Node visitLetVal(LetVal node) {
622 // Let bindings translate into assignments. 625 // Let bindings translate into assignments.
623 ast.Identifier identifier = node.variable.assignIdentifier(); 626 ast.Identifier identifier = node.variable.assignIdentifier();
624 variables.add(identifier); 627 variables.add(identifier);
625 628
626 ast.Expression expression = node.definition.accept(this); 629 ast.Expression expression = visit(node.definition);
627 ast.Expression assignment = makeAssignment(identifier, expression); 630 ast.Expression assignment = makeAssignment(identifier, expression);
628 631
629 ast.Node rest = node.body.accept(this); 632 ast.Node rest = visit(node.body);
630 return concatenate(assignment, rest); 633 return concatenate(assignment, rest);
631 } 634 }
632 635
633 ast.Node visitInvokeStatic(InvokeStatic node) { 636 ast.Node visitInvokeStatic(InvokeStatic node) {
634 ast.Identifier name = makeIdentifier(node.target.name); 637 ast.Identifier name = makeIdentifier(node.target.name);
635 ast.Send send = 638 ast.Send send =
636 new ast.Send(null, name, translateArguments(node.arguments)); 639 new ast.Send(null, name, translateArguments(node.arguments));
637 treeElements[send] = node.target; 640 treeElements[send] = node.target;
638 return send; 641 return send;
639 } 642 }
640 643
641 ast.Node visitReturn(Return node) { 644 ast.Node visitReturn(Return node) {
642 ast.Expression expression = node.value.accept(this); 645 ast.Expression expression = visit(node.value);
643 return new ast.Return( 646 return new ast.Return(
644 new KeywordToken(Keyword.keywords['return'], -1), 647 new KeywordToken(Keyword.keywords['return'], -1),
645 semicolon, 648 semicolon,
646 expression); 649 expression);
647 } 650 }
648 651
649 ast.Node visitConstant(Constant node) { 652 ast.Node visitConstant(Constant node) {
650 return node.value.accept(constantEmitter); 653 return node.value.accept(constantEmitter);
651 } 654 }
652 } 655 }
653 656
654 class TypeEmitter extends 657 class TypeEmitter extends
655 DartTypeVisitor<ast.TypeAnnotation, dart2js.TreeElementMapping> { 658 DartTypeVisitor<ast.TypeAnnotation, dart2js.TreeElementMapping> {
656 659
657 // Supported types are verified at IR construction time. The unimplemented 660 // Supported types are verified at IR construction time. The unimplemented
658 // emit methods should be unreachable. 661 // emit methods should be unreachable.
659 ast.TypeAnnotation unimplemented() => throw new UnimplementedError(); 662 ast.TypeAnnotation unimplemented() => throw new UnimplementedError();
660 663
661 ast.TypeAnnotation makeSimpleAnnotation( 664 ast.TypeAnnotation makeSimpleAnnotation(
662 DartType type, 665 DartType type,
663 dart2js.TreeElementMapping treeElements) { 666 dart2js.TreeElementMapping treeElements) {
664 ast.TypeAnnotation annotation = 667 ast.TypeAnnotation annotation =
665 new ast.TypeAnnotation(Emitter.makeIdentifier(type.toString()), null); 668 new ast.TypeAnnotation(Emitter.makeIdentifier(type.toString()), null);
666 treeElements.setType(annotation, type); 669 treeElements.setType(annotation, type);
667 return annotation; 670 return annotation;
668 } 671 }
669 672
670 ast.TypeAnnotation visitType(DartType type, 673 ast.TypeAnnotation visitType(DartType type,
671 dart2js.TreeElementMapping treeElements) { 674 dart2js.TreeElementMapping treeElements) {
672 return unimplemented(); 675 return type.accept(this, treeElements);
673 } 676 }
674 677
675 ast.TypeAnnotation visitVoidType(VoidType type, 678 ast.TypeAnnotation visitVoidType(VoidType type,
676 dart2js.TreeElementMapping treeElements) { 679 dart2js.TreeElementMapping treeElements) {
677 return makeSimpleAnnotation(type, treeElements); 680 return makeSimpleAnnotation(type, treeElements);
678 } 681 }
679 682
680 ast.TypeAnnotation visitInterfaceType( 683 ast.TypeAnnotation visitInterfaceType(
681 InterfaceType type, 684 InterfaceType type,
682 dart2js.TreeElementMapping treeElements) { 685 dart2js.TreeElementMapping treeElements) {
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
753 } 756 }
754 757
755 ast.Expression visitInterceptor(dart2js.InterceptorConstant constant) { 758 ast.Expression visitInterceptor(dart2js.InterceptorConstant constant) {
756 return unimplemented(); 759 return unimplemented();
757 } 760 }
758 761
759 ast.Expression visitDummy(dart2js.DummyConstant constant) { 762 ast.Expression visitDummy(dart2js.DummyConstant constant) {
760 return unimplemented(); 763 return unimplemented();
761 } 764 }
762 } 765 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698