| OLD | NEW |
| 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 '../constants/expressions.dart'; | 7 import '../constants/expressions.dart'; |
| 8 import '../constants/values.dart' show PrimitiveConstantValue; | 8 import '../constants/values.dart' show PrimitiveConstantValue; |
| 9 import '../dart_backend/dart_backend.dart' show DartBackend; | 9 import '../dart_backend/dart_backend.dart' show DartBackend; |
| 10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 // new value of current. | 336 // new value of current. |
| 337 void add(ir.Expression expr) { | 337 void add(ir.Expression expr) { |
| 338 assert(isOpen); | 338 assert(isOpen); |
| 339 if (_root == null) { | 339 if (_root == null) { |
| 340 _root = _current = expr; | 340 _root = _current = expr; |
| 341 } else { | 341 } else { |
| 342 _current = _current.plug(expr); | 342 _current = _current.plug(expr); |
| 343 } | 343 } |
| 344 } | 344 } |
| 345 | 345 |
| 346 ir.Primitive continueWithExpression(ir.Expression build(ir.Continuation k)) { | 346 ir.Primitive _continueWithExpression(ir.Expression build(ir.Continuation k)) { |
| 347 ir.Parameter v = new ir.Parameter(null); | 347 ir.Parameter v = new ir.Parameter(null); |
| 348 ir.Continuation k = new ir.Continuation([v]); | 348 ir.Continuation k = new ir.Continuation([v]); |
| 349 ir.Expression expression = build(k); | 349 ir.Expression expression = build(k); |
| 350 add(new ir.LetCont(k, expression)); | 350 add(new ir.LetCont(k, expression)); |
| 351 return v; | 351 return v; |
| 352 } | 352 } |
| 353 | 353 |
| 354 ir.Primitive _buildInvokeStatic(Element element, |
| 355 Selector selector, |
| 356 List<ir.Definition> arguments) { |
| 357 assert(isOpen); |
| 358 return _continueWithExpression( |
| 359 (k) => new ir.InvokeStatic(element, selector, k, arguments)); |
| 360 } |
| 361 |
| 362 ir.Primitive _buildInvokeSuper(Selector selector, |
| 363 List<ir.Definition> arguments) { |
| 364 assert(isOpen); |
| 365 return _continueWithExpression( |
| 366 (k) => new ir.InvokeSuperMethod(selector, k, arguments)); |
| 367 } |
| 368 |
| 369 ir.Primitive _buildInvokeDynamic(ir.Primitive receiver, |
| 370 Selector selector, |
| 371 List<ir.Definition> arguments) { |
| 372 assert(isOpen); |
| 373 return _continueWithExpression( |
| 374 (k) => new ir.InvokeMethod(receiver, selector, k, arguments)); |
| 375 } |
| 376 |
| 377 |
| 354 /// Create a constant literal from [constant]. | 378 /// Create a constant literal from [constant]. |
| 355 ir.Constant buildConstantLiteral(ConstantExpression constant) { | 379 ir.Constant buildConstantLiteral(ConstantExpression constant) { |
| 356 assert(isOpen); | 380 assert(isOpen); |
| 357 ir.Constant prim = new ir.Constant(constant); | 381 ir.Constant prim = new ir.Constant(constant); |
| 358 add(new ir.LetPrim(prim)); | 382 add(new ir.LetPrim(prim)); |
| 359 return prim; | 383 return prim; |
| 360 } | 384 } |
| 361 | 385 |
| 362 // Helper for building primitive literals. | 386 // Helper for building primitive literals. |
| 363 ir.Constant _buildPrimitiveConstant(PrimitiveConstantValue constant) { | 387 ir.Constant _buildPrimitiveConstant(PrimitiveConstantValue constant) { |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 463 new ir.LetCont(elseContinuation, | 487 new ir.LetCont(elseContinuation, |
| 464 new ir.Branch(new ir.IsTrue(condition), | 488 new ir.Branch(new ir.IsTrue(condition), |
| 465 thenContinuation, | 489 thenContinuation, |
| 466 elseContinuation))))); | 490 elseContinuation))))); |
| 467 return (thenValue == elseValue) | 491 return (thenValue == elseValue) |
| 468 ? thenValue | 492 ? thenValue |
| 469 : joinContinuation.parameters.last; | 493 : joinContinuation.parameters.last; |
| 470 | 494 |
| 471 } | 495 } |
| 472 | 496 |
| 473 /// Create a read access of [local]. | |
| 474 ir.Primitive buildLocalGet(LocalElement local) { | |
| 475 assert(isOpen); | |
| 476 if (isClosureVariable(local)) { | |
| 477 ir.Primitive result = new ir.GetClosureVariable(local); | |
| 478 add(new ir.LetPrim(result)); | |
| 479 return result; | |
| 480 } else { | |
| 481 return environment.lookup(local); | |
| 482 } | |
| 483 } | |
| 484 | |
| 485 /// Create a write access to [local]. | |
| 486 ir.Primitive buildLocalSet(LocalElement local, ir.Primitive valueToStore) { | |
| 487 assert(isOpen); | |
| 488 if (isClosureVariable(local)) { | |
| 489 add(new ir.SetClosureVariable(local, valueToStore)); | |
| 490 } else { | |
| 491 valueToStore.useElementAsHint(local); | |
| 492 environment.update(local, valueToStore); | |
| 493 } | |
| 494 return valueToStore; | |
| 495 } | |
| 496 | |
| 497 /// Create a get access of the static [element]. | |
| 498 ir.Primitive buildStaticGet(Element element, Selector selector) { | |
| 499 assert(isOpen); | |
| 500 assert(selector.isGetter); | |
| 501 return continueWithExpression( | |
| 502 (k) => new ir.InvokeStatic( | |
| 503 element, selector, k, const <ir.Definition>[])); | |
| 504 } | |
| 505 | |
| 506 /// Create a dynamic get access on [receiver] where the property is defined | |
| 507 /// by the getter [selector]. | |
| 508 ir.Primitive buildDynamicGet(ir.Primitive receiver, Selector selector) { | |
| 509 assert(isOpen); | |
| 510 assert(selector.isGetter); | |
| 511 return continueWithExpression( | |
| 512 (k) => new ir.InvokeMethod( | |
| 513 receiver, selector, k, const <ir.Definition>[])); | |
| 514 } | |
| 515 | |
| 516 /** | 497 /** |
| 517 * Add an explicit `return null` for functions that don't have a return | 498 * Add an explicit `return null` for functions that don't have a return |
| 518 * statement on each branch. This includes functions with an empty body, | 499 * statement on each branch. This includes functions with an empty body, |
| 519 * such as `foo(){ }`. | 500 * such as `foo(){ }`. |
| 520 */ | 501 */ |
| 521 void ensureReturn() { | 502 void _ensureReturn() { |
| 522 if (!isOpen) return; | 503 if (!isOpen) return; |
| 523 ir.Constant constant = buildNullLiteral(); | 504 ir.Constant constant = buildNullLiteral(); |
| 524 add(new ir.InvokeContinuation(state.returnContinuation, [constant])); | 505 add(new ir.InvokeContinuation(state.returnContinuation, [constant])); |
| 525 _current = null; | 506 _current = null; |
| 526 } | 507 } |
| 527 | 508 |
| 528 /// Create a [ir.FunctionDefinition] for [element] using [_root] as the body. | 509 /// Create a [ir.FunctionDefinition] for [element] using [_root] as the body. |
| 529 /// | 510 /// |
| 530 /// Parameters must be created before the construction of the body using | 511 /// Parameters must be created before the construction of the body using |
| 531 /// [createParameter]. | 512 /// [createParameter]. |
| 532 ir.FunctionDefinition buildFunctionDefinition( | 513 ir.FunctionDefinition buildFunctionDefinition( |
| 533 FunctionElement element, | 514 FunctionElement element, |
| 534 List<ConstantExpression> defaults) { | 515 List<ConstantExpression> defaults) { |
| 535 if (!element.isAbstract) { | 516 if (!element.isAbstract) { |
| 536 ensureReturn(); | 517 _ensureReturn(); |
| 537 return new ir.FunctionDefinition( | 518 return new ir.FunctionDefinition( |
| 538 element, state.returnContinuation, _parameters, _root, | 519 element, state.returnContinuation, _parameters, _root, |
| 539 state.localConstants, defaults); | 520 state.localConstants, defaults); |
| 540 } else { | 521 } else { |
| 541 assert(invariant(element, _root == null, | 522 assert(invariant(element, _root == null, |
| 542 message: "Non-empty body for abstract method $element: $_root")); | 523 message: "Non-empty body for abstract method $element: $_root")); |
| 543 assert(invariant(element, state.localConstants.isEmpty, | 524 assert(invariant(element, state.localConstants.isEmpty, |
| 544 message: "Local constants for abstract method $element: " | 525 message: "Local constants for abstract method $element: " |
| 545 "${state.localConstants}")); | 526 "${state.localConstants}")); |
| 546 return new ir.FunctionDefinition.abstract( | 527 return new ir.FunctionDefinition.abstract( |
| 547 element, _parameters, defaults); | 528 element, _parameters, defaults); |
| 548 } | 529 } |
| 549 } | 530 } |
| 550 | 531 |
| 551 | 532 |
| 552 /// Create a super invocation with method name and arguments structure defined | 533 /// Create a super invocation where the method name and the argument structure |
| 553 /// by [selector] and argument values defined by [arguments]. | 534 /// are defined by [selector] and the argument values are defined by |
| 535 /// [arguments]. |
| 554 ir.Primitive buildSuperInvocation(Selector selector, | 536 ir.Primitive buildSuperInvocation(Selector selector, |
| 555 List<ir.Definition> arguments) { | 537 List<ir.Definition> arguments) { |
| 556 assert(isOpen); | 538 return _buildInvokeSuper(selector, arguments); |
| 557 return continueWithExpression( | |
| 558 (k) => new ir.InvokeSuperMethod(selector, k, arguments)); | |
| 559 | |
| 560 } | 539 } |
| 561 | 540 |
| 562 /// Create a dynamic invocation on [receiver] with method name and argument | 541 /// Create a getter invocation on the super class where the getter name is |
| 563 /// structure defined by [selector] and argument values defined by | 542 /// defined by [selector]. |
| 564 /// [arguments]. | 543 ir.Primitive buildSuperGet(Selector selector) { |
| 544 assert(selector.isGetter); |
| 545 return _buildInvokeSuper(selector, const <ir.Definition>[]); |
| 546 } |
| 547 |
| 548 /// Create a setter invocation on the super class where the setter name and |
| 549 /// argument are defined by [selector] and [value], respectively. |
| 550 ir.Primitive buildSuperSet(Selector selector, ir.Primitive value) { |
| 551 assert(selector.isSetter); |
| 552 _buildInvokeSuper(selector, <ir.Definition>[value]); |
| 553 return value; |
| 554 } |
| 555 |
| 556 /// Create an index set invocation on the super class with the provided |
| 557 /// [index] and [value]. |
| 558 ir.Primitive buildSuperIndexSet(ir.Primitive index, |
| 559 ir.Primitive value) { |
| 560 _buildInvokeSuper(new Selector.indexSet(), <ir.Definition>[index, value]); |
| 561 return value; |
| 562 } |
| 563 |
| 564 /// Create a dynamic invocation on [receiver] where the method name and |
| 565 /// argument structure are defined by [selector] and the argument values are |
| 566 /// defined by [arguments]. |
| 565 ir.Primitive buildDynamicInvocation(ir.Definition receiver, | 567 ir.Primitive buildDynamicInvocation(ir.Definition receiver, |
| 566 Selector selector, | 568 Selector selector, |
| 567 List<ir.Definition> arguments) { | 569 List<ir.Definition> arguments) { |
| 568 assert(isOpen); | 570 return _buildInvokeDynamic(receiver, selector, arguments); |
| 569 return continueWithExpression( | |
| 570 (k) => new ir.InvokeMethod(receiver, selector, k, arguments)); | |
| 571 } | 571 } |
| 572 | 572 |
| 573 /// Create a static invocation of [element] with argument structure defined | 573 /// Create a dynamic getter invocation on [receiver] where the getter name is |
| 574 /// by [selector] and argument values defined by [arguments]. | 574 /// defined by [selector]. |
| 575 ir.Primitive buildDynamicGet(ir.Primitive receiver, Selector selector) { |
| 576 assert(selector.isGetter); |
| 577 return _buildInvokeDynamic(receiver, selector, const <ir.Definition>[]); |
| 578 } |
| 579 |
| 580 /// Create a dynamic setter invocation on [receiver] where the setter name and |
| 581 /// argument are defined by [selector] and [value], respectively. |
| 582 ir.Primitive buildDynamicSet(ir.Primitive receiver, |
| 583 Selector selector, |
| 584 ir.Primitive value) { |
| 585 assert(selector.isSetter); |
| 586 _buildInvokeDynamic(receiver, selector, <ir.Definition>[value]); |
| 587 return value; |
| 588 } |
| 589 |
| 590 /// Create a dynamic index set invocation on [receiver] with the provided |
| 591 /// [index] and [value]. |
| 592 ir.Primitive buildDynamicIndexSet(ir.Primitive receiver, |
| 593 ir.Primitive index, |
| 594 ir.Primitive value) { |
| 595 _buildInvokeDynamic( |
| 596 receiver, new Selector.indexSet(), <ir.Definition>[index, value]); |
| 597 return value; |
| 598 } |
| 599 |
| 600 /// Create a static invocation of [element] where argument structure is |
| 601 /// defined by [selector] and the argument values are defined by [arguments]. |
| 575 ir.Primitive buildStaticInvocation(Element element, | 602 ir.Primitive buildStaticInvocation(Element element, |
| 576 Selector selector, | 603 Selector selector, |
| 577 List<ir.Definition> arguments) { | 604 List<ir.Definition> arguments) { |
| 578 return continueWithExpression( | 605 return _buildInvokeStatic(element, selector, arguments); |
| 579 (k) => new ir.InvokeStatic(element, selector, k, arguments)); | |
| 580 } | 606 } |
| 581 | 607 |
| 582 /// Create a constructor invocation of [element] on [type] with argument | 608 /// Create a static getter invocation of [element] where the getter name is |
| 583 /// structure defined by [selector] and argument values defined by | 609 /// defined by [selector]. |
| 584 /// [arguments]. | 610 ir.Primitive buildStaticGet(Element element, Selector selector) { |
| 611 assert(selector.isGetter); |
| 612 return _buildInvokeStatic(element, selector, const <ir.Definition>[]); |
| 613 } |
| 614 |
| 615 /// Create a static setter invocation of [element] where the setter name and |
| 616 /// argument are defined by [selector] and [value], respectively. |
| 617 ir.Primitive buildStaticSet(Element element, |
| 618 Selector selector, |
| 619 ir.Primitive value) { |
| 620 assert(selector.isSetter); |
| 621 _buildInvokeStatic(element, selector, <ir.Definition>[value]); |
| 622 return value; |
| 623 } |
| 624 |
| 625 /// Create a constructor invocation of [element] on [type] where the |
| 626 /// constructor name and argument structure are defined by [selector] and the |
| 627 /// argument values are defined by [arguments]. |
| 585 ir.Primitive buildConstructorInvocation(FunctionElement element, | 628 ir.Primitive buildConstructorInvocation(FunctionElement element, |
| 586 Selector selector, | 629 Selector selector, |
| 587 DartType type, | 630 DartType type, |
| 588 List<ir.Definition> arguments) { | 631 List<ir.Definition> arguments) { |
| 589 assert(isOpen); | 632 assert(isOpen); |
| 590 return continueWithExpression( | 633 return _continueWithExpression( |
| 591 (k) => new ir.InvokeConstructor(type, element, selector, k, arguments)); | 634 (k) => new ir.InvokeConstructor(type, element, selector, k, arguments)); |
| 592 } | 635 } |
| 593 | 636 |
| 637 /// Create a string concatenation of the [arguments]. |
| 638 ir.Primitive buildStringConcatenation(List<ir.Definition> arguments) { |
| 639 assert(isOpen); |
| 640 return _continueWithExpression( |
| 641 (k) => new ir.ConcatenateStrings(k, arguments)); |
| 642 } |
| 643 |
| 644 /// Create a read access of [local]. |
| 645 ir.Primitive buildLocalGet(LocalElement local) { |
| 646 assert(isOpen); |
| 647 if (isClosureVariable(local)) { |
| 648 ir.Primitive result = new ir.GetClosureVariable(local); |
| 649 add(new ir.LetPrim(result)); |
| 650 return result; |
| 651 } else { |
| 652 return environment.lookup(local); |
| 653 } |
| 654 } |
| 655 |
| 656 /// Create a write access to [local] with the provided [value]. |
| 657 ir.Primitive buildLocalSet(LocalElement local, ir.Primitive value) { |
| 658 assert(isOpen); |
| 659 if (isClosureVariable(local)) { |
| 660 add(new ir.SetClosureVariable(local, value)); |
| 661 } else { |
| 662 value.useElementAsHint(local); |
| 663 environment.update(local, value); |
| 664 } |
| 665 return value; |
| 666 } |
| 667 |
| 594 /// Creates an if-then-else statement with the provided [condition] where the | 668 /// Creates an if-then-else statement with the provided [condition] where the |
| 595 /// then and else branches are created through the [buildThenPart] and | 669 /// then and else branches are created through the [buildThenPart] and |
| 596 /// [buildElsePart] functions, respectively. | 670 /// [buildElsePart] functions, respectively. |
| 597 /// | 671 /// |
| 598 /// An if-then statement is created if [buildElsePart] is a no-op. | 672 /// An if-then statement is created if [buildElsePart] is a no-op. |
| 599 // TODO(johnniwinther): Unify implementation with [buildConditional] and | 673 // TODO(johnniwinther): Unify implementation with [buildConditional] and |
| 600 // [_buildLogicalOperator]. | 674 // [_buildLogicalOperator]. |
| 601 void buildIf(ir.Primitive condition, | 675 void buildIf(ir.Primitive condition, |
| 602 void buildThenPart(IrBuilder builder), | 676 void buildThenPart(IrBuilder builder), |
| 603 void buildElsePart(IrBuilder builder)) { | 677 void buildElsePart(IrBuilder builder)) { |
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 987 | 1061 |
| 988 add(new ir.LetCont(joinContinuation, | 1062 add(new ir.LetCont(joinContinuation, |
| 989 new ir.LetCont(thenContinuation, | 1063 new ir.LetCont(thenContinuation, |
| 990 new ir.LetCont(elseContinuation, | 1064 new ir.LetCont(elseContinuation, |
| 991 new ir.Branch(new ir.IsTrue(condition), | 1065 new ir.Branch(new ir.IsTrue(condition), |
| 992 thenContinuation, | 1066 thenContinuation, |
| 993 elseContinuation))))); | 1067 elseContinuation))))); |
| 994 return resultParameter; | 1068 return resultParameter; |
| 995 } | 1069 } |
| 996 | 1070 |
| 1071 /// Creates a type test or type cast of [receiver] against [type]. |
| 1072 /// |
| 1073 /// Set [isTypeTest] to `true` to create a type test and furthermore set |
| 1074 /// [isNotCheck] to `true` to create a negated type test. |
| 1075 ir.Primitive buildTypeOperator(ir.Primitive receiver, |
| 1076 DartType type, |
| 1077 {bool isTypeTest: false, |
| 1078 bool isNotCheck: false}) { |
| 1079 assert(isOpen); |
| 1080 assert(isTypeTest != null); |
| 1081 assert(!isNotCheck || isTypeTest); |
| 1082 ir.Primitive check = _continueWithExpression( |
| 1083 (k) => new ir.TypeOperator(receiver, type, k, isTypeTest: isTypeTest)); |
| 1084 return isNotCheck ? buildNegation(check) : check; |
| 1085 |
| 1086 } |
| 1087 |
| 997 /// Create a lazy and/or expression. [leftValue] is the value of the left | 1088 /// Create a lazy and/or expression. [leftValue] is the value of the left |
| 998 /// operand and [buildRightValue] is called to process the value of the right | 1089 /// operand and [buildRightValue] is called to process the value of the right |
| 999 /// operand in the context of its own [IrBuilder]. | 1090 /// operand in the context of its own [IrBuilder]. |
| 1000 ir.Primitive buildLogicalOperator( | 1091 ir.Primitive buildLogicalOperator( |
| 1001 ir.Primitive leftValue, | 1092 ir.Primitive leftValue, |
| 1002 ir.Primitive buildRightValue(IrBuilder builder), | 1093 ir.Primitive buildRightValue(IrBuilder builder), |
| 1003 {bool isLazyOr: false}) { | 1094 {bool isLazyOr: false}) { |
| 1004 // e0 && e1 is translated as if e0 ? (e1 == true) : false. | 1095 // e0 && e1 is translated as if e0 ? (e1 == true) : false. |
| 1005 // e0 || e1 is translated as if e0 ? true : (e1 == true). | 1096 // e0 || e1 is translated as if e0 ? true : (e1 == true). |
| 1006 // The translation must convert both e0 and e1 to booleans and handle | 1097 // The translation must convert both e0 and e1 to booleans and handle |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1177 index = 0; | 1268 index = 0; |
| 1178 for (int i = 0; i < environment.length; ++i) { | 1269 for (int i = 0; i < environment.length; ++i) { |
| 1179 if (common[i] == null) { | 1270 if (common[i] == null) { |
| 1180 environment.index2value[i] = parameters[index++]; | 1271 environment.index2value[i] = parameters[index++]; |
| 1181 } | 1272 } |
| 1182 } | 1273 } |
| 1183 | 1274 |
| 1184 return join; | 1275 return join; |
| 1185 } | 1276 } |
| 1186 } | 1277 } |
| OLD | NEW |