| OLD | NEW |
| 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 tree_ir_builder; | 5 library tree_ir_builder; |
| 6 | 6 |
| 7 import '../common.dart'; | 7 import '../common.dart'; |
| 8 import '../constants/values.dart'; | 8 import '../constants/values.dart'; |
| 9 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; | 9 import '../cps_ir/cps_ir_nodes.dart' as cps_ir; |
| 10 import '../elements/elements.dart'; | 10 import '../elements/elements.dart'; |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 if (thisParameter != null && reference.definition == thisParameter) { | 110 if (thisParameter != null && reference.definition == thisParameter) { |
| 111 return new This(); | 111 return new This(); |
| 112 } | 112 } |
| 113 return new VariableUse(getVariable(reference.definition)); | 113 return new VariableUse(getVariable(reference.definition)); |
| 114 } | 114 } |
| 115 | 115 |
| 116 Label getLabel(cps_ir.Continuation cont) { | 116 Label getLabel(cps_ir.Continuation cont) { |
| 117 return labels.putIfAbsent(cont, () => new Label()); | 117 return labels.putIfAbsent(cont, () => new Label()); |
| 118 } | 118 } |
| 119 | 119 |
| 120 Variable addFunctionParameter(cps_ir.Definition variable) { | 120 Variable addFunctionParameter(cps_ir.Parameter parameter) { |
| 121 if (variable is cps_ir.Parameter) { | 121 return getVariable(parameter); |
| 122 return getVariable(variable); | |
| 123 } else { | |
| 124 return addMutableVariable(variable as cps_ir.MutableVariable) | |
| 125 ..isCaptured = true; | |
| 126 } | |
| 127 } | 122 } |
| 128 | 123 |
| 129 FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) { | 124 FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) { |
| 130 currentElement = node.element; | 125 currentElement = node.element; |
| 131 if (parent != null) { | 126 if (parent != null) { |
| 132 // Local function's 'this' refers to enclosing method's 'this' | 127 // Local function's 'this' refers to enclosing method's 'this' |
| 133 thisParameter = parent.thisParameter; | 128 thisParameter = parent.thisParameter; |
| 134 } else { | 129 } else { |
| 135 thisParameter = node.thisParameter; | 130 thisParameter = node.thisParameter; |
| 136 } | 131 } |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 Statement result = node.accept(this); // Translate the tail expression. | 261 Statement result = node.accept(this); // Translate the tail expression. |
| 267 for (NodeCallback fun in stack.reversed) { | 262 for (NodeCallback fun in stack.reversed) { |
| 268 result = fun(result); | 263 result = fun(result); |
| 269 } | 264 } |
| 270 return result; | 265 return result; |
| 271 } | 266 } |
| 272 | 267 |
| 273 /// Translates a CPS primitive to a tree expression. | 268 /// Translates a CPS primitive to a tree expression. |
| 274 /// | 269 /// |
| 275 /// This simply calls the visit method for the primitive. | 270 /// This simply calls the visit method for the primitive. |
| 276 Expression translatePrimitive(cps_ir.Primitive prim) { | 271 translatePrimitive(cps_ir.Primitive prim) { |
| 277 return prim.accept(this); | 272 return prim.accept(this); |
| 278 } | 273 } |
| 279 | 274 |
| 280 /************************ INTERIOR EXPRESSIONS ************************/ | 275 /************************ INTERIOR EXPRESSIONS ************************/ |
| 281 // | 276 // |
| 282 // Visit methods for interior expressions must return a function: | 277 // Visit methods for interior expressions must return a function: |
| 283 // | 278 // |
| 284 // (Statement next) => <result statement> | 279 // (Statement next) => <result statement> |
| 285 // | 280 // |
| 286 | 281 |
| 287 NodeCallback visitLetPrim(cps_ir.LetPrim node) => (Statement next) { | 282 NodeCallback visitLetPrim(cps_ir.LetPrim node) { |
| 288 Variable variable = getVariable(node.primitive); | 283 Variable variable = getVariable(node.primitive); |
| 289 Expression value = translatePrimitive(node.primitive); | 284 var value = translatePrimitive(node.primitive); |
| 290 if (node.primitive.hasAtLeastOneUse) { | 285 if (value is Expression) { |
| 291 return Assign.makeStatement(variable, value, next); | 286 if (node.primitive.hasAtLeastOneUse) { |
| 287 return (Statement next) => Assign.makeStatement(variable, value, next); |
| 288 } else { |
| 289 return (Statement next) => new ExpressionStatement(value, next); |
| 290 } |
| 292 } else { | 291 } else { |
| 293 return new ExpressionStatement(value, next); | 292 assert(value is NodeCallback); |
| 293 return value; |
| 294 } | 294 } |
| 295 }; | 295 } |
| 296 | 296 |
| 297 // Continuations are bound at the same level, but they have to be | 297 // Continuations are bound at the same level, but they have to be |
| 298 // translated as if nested. This is because the body can invoke any | 298 // translated as if nested. This is because the body can invoke any |
| 299 // of them from anywhere, so it must be nested inside all of them. | 299 // of them from anywhere, so it must be nested inside all of them. |
| 300 // | 300 // |
| 301 // The continuation bodies are not always translated directly here because | 301 // The continuation bodies are not always translated directly here because |
| 302 // they may have been already translated: | 302 // they may have been already translated: |
| 303 // * For singly-used continuations, the continuation's body is | 303 // * For singly-used continuations, the continuation's body is |
| 304 // translated at the site of the continuation invocation. | 304 // translated at the site of the continuation invocation. |
| 305 // * For recursive continuations, there is a single non-recursive | 305 // * For recursive continuations, there is a single non-recursive |
| (...skipping 25 matching lines...) Expand all Loading... |
| 331 Statement catchBody = translateExpression(node.handler.body); | 331 Statement catchBody = translateExpression(node.handler.body); |
| 332 return new Try(next, catchParameters, catchBody); | 332 return new Try(next, catchParameters, catchBody); |
| 333 }; | 333 }; |
| 334 | 334 |
| 335 NodeCallback visitLetMutable(cps_ir.LetMutable node) { | 335 NodeCallback visitLetMutable(cps_ir.LetMutable node) { |
| 336 Variable variable = addMutableVariable(node.variable); | 336 Variable variable = addMutableVariable(node.variable); |
| 337 Expression value = getVariableUse(node.value); | 337 Expression value = getVariableUse(node.value); |
| 338 return (Statement next) => Assign.makeStatement(variable, value, next); | 338 return (Statement next) => Assign.makeStatement(variable, value, next); |
| 339 } | 339 } |
| 340 | 340 |
| 341 | |
| 342 /************************ CALL EXPRESSIONS ************************/ | |
| 343 // | |
| 344 // Visit methods for call expressions must return a function: | |
| 345 // | |
| 346 // (Statement next) => <result statement> | |
| 347 // | |
| 348 // The result statement must include an assignment to the continuation | |
| 349 // parameter, if the parameter is used. | |
| 350 // | |
| 351 | |
| 352 NodeCallback makeCallExpression(cps_ir.CallExpression call, | |
| 353 Expression expression) { | |
| 354 return (Statement next) { | |
| 355 cps_ir.Parameter result = call.continuation.definition.parameters.single; | |
| 356 if (result.hasAtLeastOneUse) { | |
| 357 return Assign.makeStatement(getVariable(result), expression, next); | |
| 358 } else { | |
| 359 return new ExpressionStatement(expression, next); | |
| 360 } | |
| 361 }; | |
| 362 } | |
| 363 | |
| 364 NodeCallback visitInvokeStatic(cps_ir.InvokeStatic node) { | |
| 365 List<Expression> arguments = translateArguments(node.arguments); | |
| 366 Expression invoke = new InvokeStatic(node.target, node.selector, arguments, | |
| 367 node.sourceInformation); | |
| 368 return makeCallExpression(node, invoke); | |
| 369 } | |
| 370 | |
| 371 NodeCallback visitInvokeMethod(cps_ir.InvokeMethod node) { | |
| 372 InvokeMethod invoke = new InvokeMethod( | |
| 373 getVariableUse(node.receiver), | |
| 374 node.selector, | |
| 375 node.mask, | |
| 376 translateArguments(node.arguments), | |
| 377 node.sourceInformation); | |
| 378 invoke.receiverIsNotNull = node.receiverIsNotNull; | |
| 379 return makeCallExpression(node, invoke); | |
| 380 } | |
| 381 | |
| 382 NodeCallback visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) { | |
| 383 Expression receiver = getVariableUse(node.receiver); | |
| 384 List<Expression> arguments = translateArguments(node.arguments); | |
| 385 Expression invoke = new InvokeMethodDirectly(receiver, node.target, | |
| 386 node.selector, arguments, node.sourceInformation); | |
| 387 return makeCallExpression(node, invoke); | |
| 388 } | |
| 389 | |
| 390 NodeCallback visitTypeCast(cps_ir.TypeCast node) { | |
| 391 Expression value = getVariableUse(node.value); | |
| 392 List<Expression> typeArgs = translateArguments(node.typeArguments); | |
| 393 Expression expression = | |
| 394 new TypeOperator(value, node.dartType, typeArgs, isTypeTest: false); | |
| 395 return makeCallExpression(node, expression); | |
| 396 } | |
| 397 | |
| 398 NodeCallback visitInvokeConstructor(cps_ir.InvokeConstructor node) { | |
| 399 List<Expression> arguments = translateArguments(node.arguments); | |
| 400 Expression invoke = new InvokeConstructor( | |
| 401 node.dartType, | |
| 402 node.target, | |
| 403 node.selector, | |
| 404 arguments, | |
| 405 node.sourceInformation); | |
| 406 return makeCallExpression(node, invoke); | |
| 407 } | |
| 408 | |
| 409 NodeCallback visitForeignCode(cps_ir.ForeignCode node) { | |
| 410 List<Expression> arguments = | |
| 411 node.arguments.map(getVariableUse).toList(growable: false); | |
| 412 if (HasCapturedArguments.check(node.codeTemplate.ast)) { | |
| 413 for (Expression arg in arguments) { | |
| 414 if (arg is VariableUse) { | |
| 415 arg.variable.isCaptured = true; | |
| 416 } else { | |
| 417 // TODO(asgerf): Avoid capture of 'this'. | |
| 418 } | |
| 419 } | |
| 420 } | |
| 421 if (node.codeTemplate.isExpression) { | |
| 422 Expression foreignCode = new ForeignExpression( | |
| 423 node.codeTemplate, | |
| 424 node.type, | |
| 425 arguments, | |
| 426 node.nativeBehavior, | |
| 427 node.dependency); | |
| 428 return makeCallExpression(node, foreignCode); | |
| 429 } else { | |
| 430 return (Statement next) { | |
| 431 assert(next is Unreachable); // We are not using the `next` statement. | |
| 432 return new ForeignStatement( | |
| 433 node.codeTemplate, | |
| 434 node.type, | |
| 435 arguments, | |
| 436 node.nativeBehavior, | |
| 437 node.dependency); | |
| 438 }; | |
| 439 } | |
| 440 } | |
| 441 | |
| 442 NodeCallback visitGetLazyStatic(cps_ir.GetLazyStatic node) { | |
| 443 // In the tree IR, GetStatic handles lazy fields because we do not need | |
| 444 // as fine-grained control over side effects. | |
| 445 GetStatic value = new GetStatic(node.element, node.sourceInformation); | |
| 446 return makeCallExpression(node, value); | |
| 447 } | |
| 448 | |
| 449 @override | |
| 450 NodeCallback visitYield(cps_ir.Yield node) { | |
| 451 return (Statement next) { | |
| 452 return new Yield(getVariableUse(node.input), node.hasStar, next); | |
| 453 }; | |
| 454 } | |
| 455 | |
| 456 @override | |
| 457 NodeCallback visitAwait(cps_ir.Await node) { | |
| 458 Expression value = new Await(getVariableUse(node.input)); | |
| 459 return makeCallExpression(node, value); | |
| 460 } | |
| 461 | |
| 462 | |
| 463 /************************** TAIL EXPRESSIONS **************************/ | 341 /************************** TAIL EXPRESSIONS **************************/ |
| 464 // | 342 // |
| 465 // Visit methods for tail expressions must return a statement directly | 343 // Visit methods for tail expressions must return a statement directly |
| 466 // (not a function like interior and call expressions). | 344 // (not a function like interior and call expressions). |
| 467 | 345 |
| 468 Statement visitThrow(cps_ir.Throw node) { | 346 Statement visitThrow(cps_ir.Throw node) { |
| 469 Expression value = getVariableUse(node.value); | 347 Expression value = getVariableUse(node.value); |
| 470 return new Throw(value); | 348 return new Throw(value); |
| 471 } | 349 } |
| 472 | 350 |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 691 return new GetIndex(getVariableUse(node.object), | 569 return new GetIndex(getVariableUse(node.object), |
| 692 getVariableUse(node.index)); | 570 getVariableUse(node.index)); |
| 693 } | 571 } |
| 694 | 572 |
| 695 Expression visitSetIndex(cps_ir.SetIndex node) { | 573 Expression visitSetIndex(cps_ir.SetIndex node) { |
| 696 return new SetIndex(getVariableUse(node.object), | 574 return new SetIndex(getVariableUse(node.object), |
| 697 getVariableUse(node.index), | 575 getVariableUse(node.index), |
| 698 getVariableUse(node.value)); | 576 getVariableUse(node.value)); |
| 699 } | 577 } |
| 700 | 578 |
| 579 Expression visitInvokeStatic(cps_ir.InvokeStatic node) { |
| 580 List<Expression> arguments = translateArguments(node.arguments); |
| 581 return new InvokeStatic(node.target, node.selector, arguments, |
| 582 node.sourceInformation); |
| 583 } |
| 584 |
| 585 Expression visitInvokeMethod(cps_ir.InvokeMethod node) { |
| 586 InvokeMethod invoke = new InvokeMethod( |
| 587 getVariableUse(node.receiver), |
| 588 node.selector, |
| 589 node.mask, |
| 590 translateArguments(node.arguments), |
| 591 node.sourceInformation); |
| 592 invoke.receiverIsNotNull = node.receiverIsNotNull; |
| 593 return invoke; |
| 594 } |
| 595 |
| 596 Expression visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) { |
| 597 Expression receiver = getVariableUse(node.receiver); |
| 598 List<Expression> arguments = translateArguments(node.arguments); |
| 599 return new InvokeMethodDirectly(receiver, node.target, |
| 600 node.selector, arguments, node.sourceInformation); |
| 601 } |
| 602 |
| 603 Expression visitTypeCast(cps_ir.TypeCast node) { |
| 604 Expression value = getVariableUse(node.value); |
| 605 List<Expression> typeArgs = translateArguments(node.typeArguments); |
| 606 return new TypeOperator(value, node.dartType, typeArgs, isTypeTest: false); |
| 607 } |
| 608 |
| 609 Expression visitInvokeConstructor(cps_ir.InvokeConstructor node) { |
| 610 List<Expression> arguments = translateArguments(node.arguments); |
| 611 return new InvokeConstructor( |
| 612 node.dartType, |
| 613 node.target, |
| 614 node.selector, |
| 615 arguments, |
| 616 node.sourceInformation); |
| 617 } |
| 618 |
| 619 visitForeignCode(cps_ir.ForeignCode node) { |
| 620 List<Expression> arguments = |
| 621 node.arguments.map(getVariableUse).toList(growable: false); |
| 622 if (HasCapturedArguments.check(node.codeTemplate.ast)) { |
| 623 for (Expression arg in arguments) { |
| 624 if (arg is VariableUse) { |
| 625 arg.variable.isCaptured = true; |
| 626 } else { |
| 627 // TODO(asgerf): Avoid capture of 'this'. |
| 628 } |
| 629 } |
| 630 } |
| 631 if (node.codeTemplate.isExpression) { |
| 632 return new ForeignExpression( |
| 633 node.codeTemplate, |
| 634 node.type, |
| 635 arguments, |
| 636 node.nativeBehavior, |
| 637 node.dependency); |
| 638 } else { |
| 639 return (Statement next) { |
| 640 assert(next is Unreachable); // We are not using the `next` statement. |
| 641 return new ForeignStatement( |
| 642 node.codeTemplate, |
| 643 node.type, |
| 644 arguments, |
| 645 node.nativeBehavior, |
| 646 node.dependency); |
| 647 }; |
| 648 } |
| 649 } |
| 650 |
| 651 Expression visitGetLazyStatic(cps_ir.GetLazyStatic node) { |
| 652 // In the tree IR, GetStatic handles lazy fields because we do not need |
| 653 // as fine-grained control over side effects. |
| 654 return new GetStatic(node.element, node.sourceInformation); |
| 655 } |
| 656 |
| 657 @override |
| 658 NodeCallback visitYield(cps_ir.Yield node) { |
| 659 return (Statement next) { |
| 660 return new Yield(getVariableUse(node.input), node.hasStar, next); |
| 661 }; |
| 662 } |
| 663 |
| 664 @override |
| 665 Expression visitAwait(cps_ir.Await node) { |
| 666 return new Await(getVariableUse(node.input)); |
| 667 } |
| 668 |
| 701 @override | 669 @override |
| 702 Expression visitRefinement(cps_ir.Refinement node) { | 670 Expression visitRefinement(cps_ir.Refinement node) { |
| 703 throw 'Unexpected Refinement node in tree builder'; | 671 throw 'Unexpected Refinement node in tree builder'; |
| 704 } | 672 } |
| 705 | 673 |
| 706 /********** UNUSED VISIT METHODS *************/ | 674 /********** UNUSED VISIT METHODS *************/ |
| 707 | 675 |
| 708 unexpectedNode(cps_ir.Node node) { | 676 unexpectedNode(cps_ir.Node node) { |
| 709 internalError(CURRENT_ELEMENT_SPANNABLE, 'Unexpected IR node: $node'); | 677 internalError(CURRENT_ELEMENT_SPANNABLE, 'Unexpected IR node: $node'); |
| 710 } | 678 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 734 --enclosingFunctions; | 702 --enclosingFunctions; |
| 735 } | 703 } |
| 736 | 704 |
| 737 @override | 705 @override |
| 738 visitInterpolatedNode(js.InterpolatedNode node) { | 706 visitInterpolatedNode(js.InterpolatedNode node) { |
| 739 if (enclosingFunctions > 0) { | 707 if (enclosingFunctions > 0) { |
| 740 found = true; | 708 found = true; |
| 741 } | 709 } |
| 742 } | 710 } |
| 743 } | 711 } |
| OLD | NEW |