| 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 '../compile_time_constants.dart' show BackendConstantEnvironment; | 7 import '../compile_time_constants.dart' show BackendConstantEnvironment; |
| 8 import '../constants/constant_system.dart'; | 8 import '../constants/constant_system.dart'; |
| 9 import '../constants/expressions.dart'; | 9 import '../constants/expressions.dart'; |
| 10 import '../constants/values.dart' show ConstantValue, PrimitiveConstantValue; | 10 import '../constants/values.dart' show ConstantValue, PrimitiveConstantValue; |
| (...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 415 // `List` instead of `Link`. | 415 // `List` instead of `Link`. |
| 416 SubbuildFunction subbuildSequence(/*Iterable<N>*/ nodes) { | 416 SubbuildFunction subbuildSequence(/*Iterable<N>*/ nodes) { |
| 417 return (IrBuilder builder) { | 417 return (IrBuilder builder) { |
| 418 return withBuilder(builder, () => builder.buildSequence(nodes, build)); | 418 return withBuilder(builder, () => builder.buildSequence(nodes, build)); |
| 419 }; | 419 }; |
| 420 } | 420 } |
| 421 } | 421 } |
| 422 | 422 |
| 423 /// Shared state between delimited IrBuilders within the same function. | 423 /// Shared state between delimited IrBuilders within the same function. |
| 424 class IrBuilderSharedState { | 424 class IrBuilderSharedState { |
| 425 final GlobalProgramInformation program; |
| 426 |
| 425 final BackendConstantEnvironment constants; | 427 final BackendConstantEnvironment constants; |
| 426 | 428 |
| 427 ConstantSystem get constantSystem => constants.constantSystem; | 429 ConstantSystem get constantSystem => constants.constantSystem; |
| 428 | 430 |
| 429 /// A stack of collectors for breaks. | 431 /// A stack of collectors for breaks. |
| 430 List<JumpCollector> breakCollectors = <JumpCollector>[]; | 432 List<JumpCollector> breakCollectors = <JumpCollector>[]; |
| 431 | 433 |
| 432 /// A stack of collectors for continues. | 434 /// A stack of collectors for continues. |
| 433 List<JumpCollector> continueCollectors = <JumpCollector>[]; | 435 List<JumpCollector> continueCollectors = <JumpCollector>[]; |
| 434 | 436 |
| 435 final ExecutableElement currentElement; | 437 final ExecutableElement currentElement; |
| 436 | 438 |
| 437 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); | 439 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); |
| 438 | 440 |
| 439 /// The target of a return from the function. | 441 /// The target of a return from the function. |
| 440 /// | 442 /// |
| 441 /// A null value indicates that the target is the function's return | 443 /// A null value indicates that the target is the function's return |
| 442 /// continuation. Otherwise, when inside the try block of try/finally | 444 /// continuation. Otherwise, when inside the try block of try/finally |
| 443 /// a return is intercepted to give a place to generate the finally code. | 445 /// a return is intercepted to give a place to generate the finally code. |
| 444 JumpCollector returnCollector = null; | 446 JumpCollector returnCollector = null; |
| 445 | 447 |
| 446 ir.Parameter _thisParameter; | 448 /// Parameter holding the internal value of 'this' passed to the function. |
| 447 ir.Parameter enclosingMethodThisParameter; | 449 /// |
| 450 /// For nested functions, this is *not* captured receiver, but the function |
| 451 /// object itself. |
| 452 ir.Parameter thisParameter; |
| 453 |
| 454 /// If non-null, this refers to the receiver (`this`) in the enclosing method. |
| 455 ir.Primitive enclosingThis; |
| 448 | 456 |
| 449 final List<ir.Parameter> functionParameters = <ir.Parameter>[]; | 457 final List<ir.Parameter> functionParameters = <ir.Parameter>[]; |
| 450 | 458 |
| 451 IrBuilderSharedState(this.constants, this.currentElement); | 459 /// Maps boxed locals to their location. These locals are not part of |
| 460 /// the environment. |
| 461 final Map<Local, ClosureLocation> boxedVariables = {}; |
| 452 | 462 |
| 453 ir.Parameter get thisParameter => _thisParameter; | 463 IrBuilderSharedState(this.program, this.constants, this.currentElement); |
| 454 void set thisParameter(ir.Parameter value) { | |
| 455 assert(_thisParameter == null); | |
| 456 _thisParameter = value; | |
| 457 } | |
| 458 } | 464 } |
| 459 | 465 |
| 460 class ThisParameterLocal implements Local { | 466 class ThisParameterLocal implements Local { |
| 461 final ExecutableElement executableContext; | 467 final ExecutableElement executableContext; |
| 462 ThisParameterLocal(this.executableContext); | 468 ThisParameterLocal(this.executableContext); |
| 463 String get name => 'this'; | 469 String get name => 'this'; |
| 464 toString() => 'ThisParameterLocal($executableContext)'; | 470 toString() => 'ThisParameterLocal($executableContext)'; |
| 465 } | 471 } |
| 466 | 472 |
| 467 /// A factory for building the cps IR. | 473 /// The IR builder maintains an environment and an IR fragment. |
| 468 /// | 474 /// |
| 469 /// [DartIrBuilder] and [JsIrBuilder] implement nested functions and captured | 475 /// The IR fragment is an expression with a hole in it. The hole represents |
| 470 /// variables in different ways. | 476 /// the focus where new expressions can be added. The fragment is implemented |
| 471 abstract class IrBuilder { | 477 /// by [_root] which is the root of the expression and [_current] which is the |
| 472 IrBuilder _makeInstance(); | 478 /// expression that immediately contains the hole. Not all expressions have a |
| 473 | 479 /// hole (e.g., invocations, which always occur in tail position, do not have a |
| 474 void declareLocalVariable(LocalVariableElement element, | 480 /// hole). Expressions with a hole have a plug method. |
| 475 {ir.Primitive initialValue}); | 481 /// |
| 476 | 482 /// The environment maintains the reaching definition of each local variable, |
| 477 /// Called when entering a nested function with free variables. | 483 /// including some synthetic locals such as [TypeVariableLocal]. |
| 478 /// | 484 /// |
| 479 /// The free variables must subsequently be accessible using [buildLocalGet] | 485 /// Internally, IR builders also maintains a [JumpCollector] stack and tracks |
| 480 /// and [buildLocalSet]. | 486 /// which variables are currently boxed or held in a mutable local variable. |
| 481 void _enterClosureEnvironment(ClosureEnvironment env); | 487 class IrBuilder { |
| 482 | |
| 483 /// Called when entering a function body or loop body. | |
| 484 /// | |
| 485 /// This is not called for for-loops, which instead use the methods | |
| 486 /// [_enterForLoopInitializer], [_enterForLoopBody], and [_enterForLoopUpdate] | |
| 487 /// due to their special scoping rules. | |
| 488 /// | |
| 489 /// The boxed variables declared in this scope must subsequently be available | |
| 490 /// using [buildLocalGet], [buildLocalSet], etc. | |
| 491 void _enterScope(ClosureScope scope); | |
| 492 | |
| 493 /// Called before building the initializer of a for-loop. | |
| 494 /// | |
| 495 /// The loop variables will subsequently be declared using | |
| 496 /// [declareLocalVariable]. | |
| 497 void _enterForLoopInitializer(ClosureScope scope, | |
| 498 List<LocalElement> loopVariables); | |
| 499 | |
| 500 /// Called before building the body of a for-loop. | |
| 501 void _enterForLoopBody(ClosureScope scope, | |
| 502 List<LocalElement> loopVariables); | |
| 503 | |
| 504 /// Called before building the update of a for-loop. | |
| 505 void _enterForLoopUpdate(ClosureScope scope, | |
| 506 List<LocalElement> loopVariables); | |
| 507 | |
| 508 /// Add the given function parameter to the IR, and bind it in the environment | |
| 509 /// or put it in its box, if necessary. | |
| 510 void _createFunctionParameter(Local parameterElement); | |
| 511 void _createThisParameter(); | |
| 512 | |
| 513 /// Reifies the value of [variable] on the current receiver object. | |
| 514 ir.Primitive buildReifyTypeVariable(TypeVariableType variable); | |
| 515 | |
| 516 /// Creates an access to the receiver from the current (or enclosing) method. | |
| 517 /// | |
| 518 /// If inside a closure class, [buildThis] will redirect access through | |
| 519 /// closure fields in order to access the receiver from the enclosing method. | |
| 520 ir.Primitive buildThis(); | |
| 521 | |
| 522 /// Creates a type test or type cast of [value] against [type]. | |
| 523 ir.Primitive buildTypeOperator(ir.Primitive value, | |
| 524 DartType type, | |
| 525 {bool isTypeTest}); | |
| 526 | |
| 527 // TODO(johnniwinther): Make these field final and remove the default values | |
| 528 // when [IrBuilder] is a property of [IrBuilderVisitor] instead of a mixin. | |
| 529 | |
| 530 final List<ir.Parameter> _parameters = <ir.Parameter>[]; | 488 final List<ir.Parameter> _parameters = <ir.Parameter>[]; |
| 531 | 489 |
| 532 IrBuilderSharedState state; | 490 final IrBuilderSharedState state; |
| 533 | 491 |
| 534 /// A map from variable indexes to their values. | 492 /// A map from variable indexes to their values. |
| 535 /// | 493 /// |
| 536 /// [BoxLocal]s map to their box. [LocalElement]s that are boxed are not | 494 /// [BoxLocal]s map to their box. [LocalElement]s that are boxed are not |
| 537 /// in the map; look up their [BoxLocal] instead. | 495 /// in the map; look up their [BoxLocal] instead. |
| 538 Environment environment; | 496 Environment environment; |
| 539 | 497 |
| 540 /// A map from mutable local variables to their [ir.MutableVariable]s. | 498 /// A map from mutable local variables to their [ir.MutableVariable]s. |
| 541 /// | 499 /// |
| 542 /// Mutable variables are treated as boxed. Writes to them are observable | 500 /// Mutable variables are treated as boxed. Writes to them are observable |
| 543 /// side effects. | 501 /// side effects. |
| 544 Map<Local, ir.MutableVariable> mutableVariables; | 502 Map<Local, ir.MutableVariable> mutableVariables; |
| 545 | 503 |
| 504 ir.Expression _root = null; |
| 505 ir.Expression _current = null; |
| 506 |
| 507 GlobalProgramInformation get program => state.program; |
| 508 |
| 509 IrBuilder(GlobalProgramInformation program, |
| 510 BackendConstantEnvironment constants, |
| 511 ExecutableElement currentElement) |
| 512 : state = new IrBuilderSharedState(program, constants, currentElement), |
| 513 environment = new Environment.empty(), |
| 514 mutableVariables = <Local, ir.MutableVariable>{}; |
| 515 |
| 516 IrBuilder._internal(this.state, this.environment, this.mutableVariables); |
| 517 |
| 518 /// Construct a delimited visitor for visiting a subtree. |
| 519 /// |
| 520 /// Build a subterm that is not (yet) connected to the CPS term. The |
| 521 /// delimited visitor has its own has its own context for building an IR |
| 522 /// expression, so the built expression is not plugged into the parent's |
| 523 /// context. It has its own compile-time environment mapping local |
| 524 /// variables to their values. If an optional environment argument is |
| 525 /// supplied, it is used as the builder's initial environment. Otherwise |
| 526 /// the environment is initially a copy of the parent builder's environment. |
| 527 IrBuilder makeDelimitedBuilder([Environment env = null]) { |
| 528 return new IrBuilder._internal( |
| 529 state, |
| 530 env != null ? env : new Environment.from(environment), |
| 531 mutableVariables); |
| 532 } |
| 533 |
| 546 /// True if [local] should currently be accessed from a [ir.MutableVariable]. | 534 /// True if [local] should currently be accessed from a [ir.MutableVariable]. |
| 547 bool isInMutableVariable(Local local) { | 535 bool isInMutableVariable(Local local) { |
| 548 return mutableVariables.containsKey(local); | 536 return mutableVariables.containsKey(local); |
| 549 } | 537 } |
| 550 | 538 |
| 551 /// Creates a [ir.MutableVariable] for the given local. | 539 /// Creates a [ir.MutableVariable] for the given local. |
| 552 void makeMutableVariable(Local local) { | 540 void makeMutableVariable(Local local) { |
| 553 mutableVariables[local] = new ir.MutableVariable(local); | 541 mutableVariables[local] = new ir.MutableVariable(local); |
| 554 } | 542 } |
| 555 | 543 |
| 556 /// Remove an [ir.MutableVariable] for a local. | 544 /// Remove an [ir.MutableVariable] for a local. |
| 557 /// | 545 /// |
| 558 /// Subsequent access to the local will be direct rather than through the | 546 /// Subsequent access to the local will be direct rather than through the |
| 559 /// mutable variable. | 547 /// mutable variable. |
| 560 void removeMutableVariable(Local local) { | 548 void removeMutableVariable(Local local) { |
| 561 mutableVariables.remove(local); | 549 mutableVariables.remove(local); |
| 562 } | 550 } |
| 563 | 551 |
| 564 /// Gets the [MutableVariable] containing the value of [local]. | 552 /// Gets the [MutableVariable] containing the value of [local]. |
| 565 ir.MutableVariable getMutableVariable(Local local) { | 553 ir.MutableVariable getMutableVariable(Local local) { |
| 566 return mutableVariables[local]; | 554 return mutableVariables[local]; |
| 567 } | 555 } |
| 568 | 556 |
| 569 // The IR builder maintains a context, which is an expression with a hole in | |
| 570 // it. The hole represents the focus where new expressions can be added. | |
| 571 // The context is implemented by 'root' which is the root of the expression | |
| 572 // and 'current' which is the expression that immediately contains the hole. | |
| 573 // Not all expressions have a hole (e.g., invocations, which always occur in | |
| 574 // tail position, do not have a hole). Expressions with a hole have a plug | |
| 575 // method. | |
| 576 // | |
| 577 // Conceptually, visiting a statement takes a context as input and returns | |
| 578 // either a new context or else an expression without a hole if all | |
| 579 // control-flow paths through the statement have exited. An expression | |
| 580 // without a hole is represented by a (root, current) pair where root is the | |
| 581 // expression and current is null. | |
| 582 // | |
| 583 // Conceptually again, visiting an expression takes a context as input and | |
| 584 // returns either a pair of a new context and a definition denoting | |
| 585 // the expression's value, or else an expression without a hole if all | |
| 586 // control-flow paths through the expression have exited. | |
| 587 // | |
| 588 // We do not pass contexts as arguments or return them. Rather we use the | |
| 589 // current context (root, current) as the visitor state and mutate current. | |
| 590 // Visiting a statement returns null; visiting an expression returns the | |
| 591 // primitive denoting its value. | |
| 592 | |
| 593 ir.Expression _root = null; | |
| 594 ir.Expression _current = null; | |
| 595 | |
| 596 /// Initialize a new top-level IR builder. | |
| 597 void _init(BackendConstantEnvironment constants, | |
| 598 ExecutableElement currentElement) { | |
| 599 state = new IrBuilderSharedState(constants, currentElement); | |
| 600 environment = new Environment.empty(); | |
| 601 mutableVariables = <Local, ir.MutableVariable>{}; | |
| 602 } | |
| 603 | |
| 604 /// Construct a delimited visitor for visiting a subtree. | |
| 605 /// | |
| 606 /// Build a subterm that is not (yet) connected to the CPS term. The | |
| 607 /// delimited visitor has its own has its own context for building an IR | |
| 608 /// expression, so the built expression is not plugged into the parent's | |
| 609 /// context. It has its own compile-time environment mapping local | |
| 610 /// variables to their values. If an optional environment argument is | |
| 611 /// supplied, it is used as the builder's initial environment. Otherwise | |
| 612 /// the environment is initially a copy of the parent builder's environment. | |
| 613 IrBuilder makeDelimitedBuilder([Environment env = null]) { | |
| 614 return _makeInstance() | |
| 615 ..state = state | |
| 616 ..environment = env != null ? env : new Environment.from(environment) | |
| 617 ..mutableVariables = mutableVariables; | |
| 618 } | |
| 619 | |
| 620 bool get isOpen => _root == null || _current != null; | 557 bool get isOpen => _root == null || _current != null; |
| 621 | 558 |
| 622 List<ir.Primitive> buildFunctionHeader(Iterable<Local> parameters, | 559 List<ir.Primitive> buildFunctionHeader(Iterable<Local> parameters, |
| 623 {ClosureScope closureScope, | 560 {ClosureScope closureScope, |
| 624 ClosureEnvironment env}) { | 561 ClosureEnvironment env}) { |
| 625 _createThisParameter(); | 562 _createThisParameter(); |
| 626 _enterClosureEnvironment(env); | 563 _enterClosureEnvironment(env); |
| 627 _enterScope(closureScope); | 564 _enterScope(closureScope); |
| 628 parameters.forEach(_createFunctionParameter); | 565 parameters.forEach(_createFunctionParameter); |
| 629 return _parameters; | 566 return _parameters; |
| 630 } | 567 } |
| 631 | 568 |
| 632 /// Creates a parameter for [local] and adds it to the current environment. | 569 /// Creates a parameter for [local] and adds it to the current environment. |
| 633 ir.Parameter createLocalParameter(Local local) { | 570 ir.Parameter _createLocalParameter(Local local) { |
| 634 ir.Parameter parameter = new ir.Parameter(local); | 571 ir.Parameter parameter = new ir.Parameter(local); |
| 635 _parameters.add(parameter); | 572 _parameters.add(parameter); |
| 636 environment.extend(local, parameter); | 573 environment.extend(local, parameter); |
| 637 return parameter; | 574 return parameter; |
| 638 } | 575 } |
| 639 | 576 |
| 640 /// Plug an expression into the 'hole' in the context being accumulated. The | 577 /// Plug an expression into the 'hole' in the context being accumulated. The |
| 641 /// empty context (just a hole) is represented by root (and current) being | 578 /// empty context (just a hole) is represented by root (and current) being |
| 642 /// null. Since the hole in the current context is filled by this function, | 579 /// null. Since the hole in the current context is filled by this function, |
| 643 /// the new hole must be in the newly added expression---which becomes the | 580 /// the new hole must be in the newly added expression---which becomes the |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 851 CallStructure callStructure, | 788 CallStructure callStructure, |
| 852 List<ir.Primitive> arguments) { | 789 List<ir.Primitive> arguments) { |
| 853 // TODO(johnniwinther): This shouldn't be necessary. | 790 // TODO(johnniwinther): This shouldn't be necessary. |
| 854 SelectorKind kind = Elements.isOperatorName(method.name) | 791 SelectorKind kind = Elements.isOperatorName(method.name) |
| 855 ? SelectorKind.OPERATOR : SelectorKind.CALL; | 792 ? SelectorKind.OPERATOR : SelectorKind.CALL; |
| 856 Selector selector = | 793 Selector selector = |
| 857 new Selector(kind, method.memberName, callStructure); | 794 new Selector(kind, method.memberName, callStructure); |
| 858 return _buildInvokeSuper(method, selector, arguments); | 795 return _buildInvokeSuper(method, selector, arguments); |
| 859 } | 796 } |
| 860 | 797 |
| 861 /// Create a read access of the [field] on the super class. | |
| 862 ir.Primitive buildSuperFieldGet(FieldElement field) { | |
| 863 // TODO(johnniwinther): This should have its own ir node. | |
| 864 return _buildInvokeSuper( | |
| 865 field, | |
| 866 new Selector.getter(field.name, field.library), | |
| 867 const <ir.Primitive>[]); | |
| 868 } | |
| 869 | |
| 870 /// Create a read access of the [method] on the super class, i.e. a | 798 /// Create a read access of the [method] on the super class, i.e. a |
| 871 /// closurization of [method]. | 799 /// closurization of [method]. |
| 872 ir.Primitive buildSuperMethodGet(MethodElement method) { | 800 ir.Primitive buildSuperMethodGet(MethodElement method) { |
| 873 // TODO(johnniwinther): This should have its own ir node. | 801 // TODO(johnniwinther): This should have its own ir node. |
| 874 return _buildInvokeSuper( | 802 return _buildInvokeSuper( |
| 875 method, | 803 method, |
| 876 new Selector.getter(method.name, method.library), | 804 new Selector.getter(method.name, method.library), |
| 877 const <ir.Primitive>[]); | 805 const <ir.Primitive>[]); |
| 878 } | 806 } |
| 879 | 807 |
| 880 /// Create a getter invocation of the [getter] on the super class. | 808 /// Create a getter invocation of the [getter] on the super class. |
| 881 ir.Primitive buildSuperGetterGet(MethodElement getter) { | 809 ir.Primitive buildSuperGetterGet(MethodElement getter) { |
| 882 // TODO(johnniwinther): This should have its own ir node. | 810 // TODO(johnniwinther): This should have its own ir node. |
| 883 return _buildInvokeSuper( | 811 return _buildInvokeSuper( |
| 884 getter, | 812 getter, |
| 885 new Selector.getter(getter.name, getter.library), | 813 new Selector.getter(getter.name, getter.library), |
| 886 const <ir.Primitive>[]); | 814 const <ir.Primitive>[]); |
| 887 } | 815 } |
| 888 | 816 |
| 889 /// Create a write access to the [field] on the super class of with [value]. | |
| 890 ir.Primitive buildSuperFieldSet(Element field, ir.Primitive value) { | |
| 891 // TODO(johnniwinther): This should have its own ir node. | |
| 892 _buildInvokeSuper( | |
| 893 field, | |
| 894 new Selector.setter(field.name, field.library), | |
| 895 <ir.Primitive>[value]); | |
| 896 return value; | |
| 897 } | |
| 898 | |
| 899 /// Create an setter invocation of the [setter] on the super class with | 817 /// Create an setter invocation of the [setter] on the super class with |
| 900 /// [value]. | 818 /// [value]. |
| 901 ir.Primitive buildSuperSetterSet(MethodElement setter, | 819 ir.Primitive buildSuperSetterSet(MethodElement setter, |
| 902 ir.Primitive value) { | 820 ir.Primitive value) { |
| 903 // TODO(johnniwinther): This should have its own ir node. | 821 // TODO(johnniwinther): This should have its own ir node. |
| 904 _buildInvokeSuper( | 822 _buildInvokeSuper( |
| 905 setter, | 823 setter, |
| 906 new Selector.setter(setter.name, setter.library), | 824 new Selector.setter(setter.name, setter.library), |
| 907 <ir.Primitive>[value]); | 825 <ir.Primitive>[value]); |
| 908 return value; | 826 return value; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 928 | 846 |
| 929 /// Create a dynamic invocation on [receiver] where the method name and | 847 /// Create a dynamic invocation on [receiver] where the method name and |
| 930 /// argument structure are defined by [selector] and the argument values are | 848 /// argument structure are defined by [selector] and the argument values are |
| 931 /// defined by [arguments]. | 849 /// defined by [arguments]. |
| 932 ir.Primitive buildDynamicInvocation(ir.Primitive receiver, | 850 ir.Primitive buildDynamicInvocation(ir.Primitive receiver, |
| 933 Selector selector, | 851 Selector selector, |
| 934 List<ir.Primitive> arguments) { | 852 List<ir.Primitive> arguments) { |
| 935 return _buildInvokeDynamic(receiver, selector, arguments); | 853 return _buildInvokeDynamic(receiver, selector, arguments); |
| 936 } | 854 } |
| 937 | 855 |
| 938 /// Create an if-null expression. This is equivalent to a conditional | |
| 939 /// expression whose result is either [value] if [value] is not null, or | |
| 940 /// `right` if [value] is null. Only when [value] is null, [buildRight] is | |
| 941 /// evaluated to produce the `right` value. | |
| 942 ir.Primitive buildIfNull(ir.Primitive value, | |
| 943 ir.Primitive buildRight(IrBuilder builder)); | |
| 944 | |
| 945 /// Create a conditional send. This is equivalent to a conditional expression | |
| 946 /// that checks if [receiver] is null, if so, it returns null, otherwise it | |
| 947 /// evaluates the [buildSend] expression. | |
| 948 ir.Primitive buildIfNotNullSend(ir.Primitive receiver, | |
| 949 ir.Primitive buildSend(IrBuilder builder)); | |
| 950 | |
| 951 /// Create a dynamic getter invocation on [receiver] where the getter name is | 856 /// Create a dynamic getter invocation on [receiver] where the getter name is |
| 952 /// defined by [selector]. | 857 /// defined by [selector]. |
| 953 ir.Primitive buildDynamicGet(ir.Primitive receiver, Selector selector) { | 858 ir.Primitive buildDynamicGet(ir.Primitive receiver, Selector selector) { |
| 954 assert(selector.isGetter); | 859 assert(selector.isGetter); |
| 955 return _buildInvokeDynamic(receiver, selector, const <ir.Primitive>[]); | 860 return _buildInvokeDynamic(receiver, selector, const <ir.Primitive>[]); |
| 956 } | 861 } |
| 957 | 862 |
| 958 /// Create a dynamic setter invocation on [receiver] where the setter name and | 863 /// Create a dynamic setter invocation on [receiver] where the setter name and |
| 959 /// argument are defined by [selector] and [value], respectively. | 864 /// argument are defined by [selector] and [value], respectively. |
| 960 ir.Primitive buildDynamicSet(ir.Primitive receiver, | 865 ir.Primitive buildDynamicSet(ir.Primitive receiver, |
| 961 Selector selector, | 866 Selector selector, |
| 962 ir.Primitive value) { | 867 ir.Primitive value) { |
| 963 assert(selector.isSetter); | 868 assert(selector.isSetter); |
| 964 _buildInvokeDynamic(receiver, selector, <ir.Primitive>[value]); | 869 _buildInvokeDynamic(receiver, selector, <ir.Primitive>[value]); |
| 965 return value; | 870 return value; |
| 966 } | 871 } |
| 967 | 872 |
| 968 /// Create a dynamic index set invocation on [receiver] with the provided | 873 /// Create a dynamic index set invocation on [receiver] with the provided |
| 969 /// [index] and [value]. | 874 /// [index] and [value]. |
| 970 ir.Primitive buildDynamicIndexSet(ir.Primitive receiver, | 875 ir.Primitive buildDynamicIndexSet(ir.Primitive receiver, |
| 971 ir.Primitive index, | 876 ir.Primitive index, |
| 972 ir.Primitive value) { | 877 ir.Primitive value) { |
| 973 _buildInvokeDynamic( | 878 _buildInvokeDynamic( |
| 974 receiver, new Selector.indexSet(), <ir.Primitive>[index, value]); | 879 receiver, new Selector.indexSet(), <ir.Primitive>[index, value]); |
| 975 return value; | 880 return value; |
| 976 } | 881 } |
| 977 | 882 |
| 978 ir.Primitive _buildLocalGet(LocalElement element); | |
| 979 | |
| 980 /// Create a read access of the [local] variable or parameter. | 883 /// Create a read access of the [local] variable or parameter. |
| 981 ir.Primitive buildLocalVariableGet(LocalElement local) { | 884 ir.Primitive buildLocalVariableGet(LocalElement local) { |
| 982 // TODO(johnniwinther): Separate function access from variable access. | 885 // TODO(johnniwinther): Separate function access from variable access. |
| 983 return _buildLocalGet(local); | 886 return _buildLocalGet(local); |
| 984 } | 887 } |
| 985 | 888 |
| 986 /// Create a read access of the local [function], i.e. closurization of | 889 /// Create a read access of the local [function], i.e. closurization of |
| 987 /// [function]. | 890 /// [function]. |
| 988 ir.Primitive buildLocalFunctionGet(LocalFunctionElement function) { | 891 ir.Primitive buildLocalFunctionGet(LocalFunctionElement function) { |
| 989 // TODO(johnniwinther): Separate function access from variable access. | 892 // TODO(johnniwinther): Separate function access from variable access. |
| 990 return _buildLocalGet(function); | 893 return _buildLocalGet(function); |
| 991 } | 894 } |
| 992 | 895 |
| 993 /// Create a write access to the [local] variable or parameter with the | |
| 994 /// provided [value]. | |
| 995 ir.Primitive buildLocalVariableSet(LocalElement local, ir.Primitive value); | |
| 996 | |
| 997 /// Create an invocation of the the [local] variable or parameter where | 896 /// Create an invocation of the the [local] variable or parameter where |
| 998 /// argument structure is defined by [callStructure] and the argument values | 897 /// argument structure is defined by [callStructure] and the argument values |
| 999 /// are defined by [arguments]. | 898 /// are defined by [arguments]. |
| 1000 ir.Primitive buildLocalVariableInvocation(LocalVariableElement local, | 899 ir.Primitive buildLocalVariableInvocation(LocalVariableElement local, |
| 1001 CallStructure callStructure, | 900 CallStructure callStructure, |
| 1002 List<ir.Primitive> arguments) { | 901 List<ir.Primitive> arguments) { |
| 1003 return buildCallInvocation( | 902 return buildCallInvocation( |
| 1004 buildLocalVariableGet(local), callStructure, arguments); | 903 buildLocalVariableGet(local), callStructure, arguments); |
| 1005 } | 904 } |
| 1006 | 905 |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1081 /// [selector] and the argument values are defined by [arguments]. | 980 /// [selector] and the argument values are defined by [arguments]. |
| 1082 // TODO(johnniwinther): Make this more fine-grained. | 981 // TODO(johnniwinther): Make this more fine-grained. |
| 1083 ir.Primitive buildErroneousInvocation( | 982 ir.Primitive buildErroneousInvocation( |
| 1084 Element element, | 983 Element element, |
| 1085 Selector selector, | 984 Selector selector, |
| 1086 List<ir.Primitive> arguments) { | 985 List<ir.Primitive> arguments) { |
| 1087 // TODO(johnniwinther): This should have its own ir node. | 986 // TODO(johnniwinther): This should have its own ir node. |
| 1088 return _buildInvokeStatic(element, selector, arguments, null); | 987 return _buildInvokeStatic(element, selector, arguments, null); |
| 1089 } | 988 } |
| 1090 | 989 |
| 1091 /// Create a constructor invocation of [element] on [type] where the | |
| 1092 /// constructor name and argument structure are defined by [callStructure] and | |
| 1093 /// the argument values are defined by [arguments]. | |
| 1094 ir.Primitive buildConstructorInvocation(FunctionElement element, | |
| 1095 CallStructure callStructure, | |
| 1096 DartType type, | |
| 1097 List<ir.Primitive> arguments); | |
| 1098 | |
| 1099 ir.Primitive buildStringify(ir.Primitive argument); | |
| 1100 | |
| 1101 /// Concatenate string values. | 990 /// Concatenate string values. |
| 1102 /// | 991 /// |
| 1103 /// The arguments must be strings; usually a call to [buildStringify] is | 992 /// The arguments must be strings; usually a call to [buildStringify] is |
| 1104 /// needed to ensure the proper conversion takes places. | 993 /// needed to ensure the proper conversion takes places. |
| 1105 ir.Primitive buildStringConcatenation(List<ir.Primitive> arguments) { | 994 ir.Primitive buildStringConcatenation(List<ir.Primitive> arguments) { |
| 1106 assert(isOpen); | 995 assert(isOpen); |
| 1107 return addPrimitive(new ir.ApplyBuiltinOperator( | 996 return addPrimitive(new ir.ApplyBuiltinOperator( |
| 1108 ir.BuiltinOperator.StringConcatenate, | 997 ir.BuiltinOperator.StringConcatenate, |
| 1109 arguments)); | 998 arguments)); |
| 1110 } | 999 } |
| (...skipping 1111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2222 leftTrueContinuation, | 2111 leftTrueContinuation, |
| 2223 leftFalseContinuation)))); | 2112 leftFalseContinuation)))); |
| 2224 environment = join.environment; | 2113 environment = join.environment; |
| 2225 return environment.discard(1); | 2114 return environment.discard(1); |
| 2226 } | 2115 } |
| 2227 | 2116 |
| 2228 ir.Primitive buildIdentical(ir.Primitive x, ir.Primitive y) { | 2117 ir.Primitive buildIdentical(ir.Primitive x, ir.Primitive y) { |
| 2229 return addPrimitive(new ir.ApplyBuiltinOperator( | 2118 return addPrimitive(new ir.ApplyBuiltinOperator( |
| 2230 ir.BuiltinOperator.Identical, <ir.Primitive>[x, y])); | 2119 ir.BuiltinOperator.Identical, <ir.Primitive>[x, y])); |
| 2231 } | 2120 } |
| 2232 } | |
| 2233 | 2121 |
| 2234 /// State shared between JsIrBuilders within the same function. | 2122 /// Called when entering a nested function with free variables. |
| 2235 /// | 2123 /// |
| 2236 /// Note that this is not shared between builders of nested functions. | 2124 /// The free variables must subsequently be accessible using [buildLocalGet] |
| 2237 class JsIrBuilderSharedState { | 2125 /// and [buildLocalSet]. |
| 2238 /// Maps boxed locals to their location. These locals are not part of | |
| 2239 /// the environment. | |
| 2240 final Map<Local, ClosureLocation> boxedVariables = {}; | |
| 2241 | |
| 2242 /// If non-null, this refers to the receiver (`this`) in the enclosing method. | |
| 2243 ir.Primitive receiver; | |
| 2244 | |
| 2245 /// `true` when we are currently building expressions inside the initializer | |
| 2246 /// list of a constructor. | |
| 2247 bool inInitializers = false; | |
| 2248 } | |
| 2249 | |
| 2250 /// JS-specific subclass of [IrBuilder]. | |
| 2251 /// | |
| 2252 /// Inner functions are represented by a [ClosureClassElement], and captured | |
| 2253 /// variables are boxed as necessary using [CreateBox], [GetField], [SetField]. | |
| 2254 class JsIrBuilder extends IrBuilder { | |
| 2255 final JsIrBuilderSharedState jsState; | |
| 2256 final GlobalProgramInformation program; | |
| 2257 | |
| 2258 IrBuilder _makeInstance() => new JsIrBuilder._blank(program, jsState); | |
| 2259 JsIrBuilder._blank(this.program, this.jsState); | |
| 2260 | |
| 2261 JsIrBuilder(this.program, BackendConstantEnvironment constants, | |
| 2262 ExecutableElement currentElement) | |
| 2263 : jsState = new JsIrBuilderSharedState() { | |
| 2264 _init(constants, currentElement); | |
| 2265 } | |
| 2266 | |
| 2267 void enterInitializers() { | |
| 2268 assert(jsState.inInitializers == false); | |
| 2269 jsState.inInitializers = true; | |
| 2270 } | |
| 2271 | |
| 2272 void leaveInitializers() { | |
| 2273 assert(jsState.inInitializers == true); | |
| 2274 jsState.inInitializers = false; | |
| 2275 } | |
| 2276 | |
| 2277 void _enterClosureEnvironment(ClosureEnvironment env) { | 2126 void _enterClosureEnvironment(ClosureEnvironment env) { |
| 2278 if (env == null) return; | 2127 if (env == null) return; |
| 2279 | 2128 |
| 2280 // Obtain a reference to the function object (this). | 2129 // Obtain a reference to the function object (this). |
| 2281 ir.Parameter thisPrim = state.thisParameter; | 2130 ir.Parameter thisPrim = state.thisParameter; |
| 2282 | 2131 |
| 2283 // Obtain access to the free variables. | 2132 // Obtain access to the free variables. |
| 2284 env.freeVariables.forEach((Local local, ClosureLocation location) { | 2133 env.freeVariables.forEach((Local local, ClosureLocation location) { |
| 2285 if (location.isBox) { | 2134 if (location.isBox) { |
| 2286 // Boxed variables are loaded from their box on-demand. | 2135 // Boxed variables are loaded from their box on-demand. |
| 2287 jsState.boxedVariables[local] = location; | 2136 state.boxedVariables[local] = location; |
| 2288 } else { | 2137 } else { |
| 2289 // Unboxed variables are loaded from the function object immediately. | 2138 // Unboxed variables are loaded from the function object immediately. |
| 2290 // This includes BoxLocals which are themselves unboxed variables. | 2139 // This includes BoxLocals which are themselves unboxed variables. |
| 2291 environment.extend(local, | 2140 environment.extend(local, |
| 2292 addPrimitive(new ir.GetField(thisPrim, location.field))); | 2141 addPrimitive(new ir.GetField(thisPrim, location.field))); |
| 2293 } | 2142 } |
| 2294 }); | 2143 }); |
| 2295 | 2144 |
| 2296 // If the function captures a reference to the receiver from the | 2145 // If the function captures a reference to the receiver from the |
| 2297 // enclosing method, remember which primitive refers to the receiver object. | 2146 // enclosing method, remember which primitive refers to the receiver object. |
| 2298 if (env.thisLocal != null && env.freeVariables.containsKey(env.thisLocal)) { | 2147 if (env.thisLocal != null && env.freeVariables.containsKey(env.thisLocal)) { |
| 2299 jsState.receiver = environment.lookup(env.thisLocal); | 2148 state.enclosingThis = environment.lookup(env.thisLocal); |
| 2300 } | 2149 } |
| 2301 | 2150 |
| 2302 // If the function has a self-reference, use the value of `this`. | 2151 // If the function has a self-reference, use the value of `this`. |
| 2303 if (env.selfReference != null) { | 2152 if (env.selfReference != null) { |
| 2304 environment.extend(env.selfReference, thisPrim); | 2153 environment.extend(env.selfReference, thisPrim); |
| 2305 } | 2154 } |
| 2306 } | 2155 } |
| 2307 | 2156 |
| 2308 /// Creates a box for [scope.box] and binds the captured variables to | 2157 /// Creates a box for [scope.box] and binds the captured variables to |
| 2309 /// that box. | 2158 /// that box. |
| 2310 /// | 2159 /// |
| 2311 /// The captured variables can subsequently be manipulated with | 2160 /// The captured variables can subsequently be manipulated with |
| 2312 /// [declareLocalVariable], [buildLocalGet], and [buildLocalSet]. | 2161 /// [declareLocalVariable], [buildLocalGet], and [buildLocalSet]. |
| 2313 void enterScope(ClosureScope scope) => _enterScope(scope); | 2162 void enterScope(ClosureScope scope) => _enterScope(scope); |
| 2314 | 2163 |
| 2164 /// Called when entering a function body or loop body. |
| 2165 /// |
| 2166 /// This is not called for for-loops, which instead use the methods |
| 2167 /// [_enterForLoopInitializer], [_enterForLoopBody], and [_enterForLoopUpdate] |
| 2168 /// due to their special scoping rules. |
| 2169 /// |
| 2170 /// The boxed variables declared in this scope must subsequently be available |
| 2171 /// using [buildLocalGet], [buildLocalSet], etc. |
| 2315 void _enterScope(ClosureScope scope) { | 2172 void _enterScope(ClosureScope scope) { |
| 2316 if (scope == null) return; | 2173 if (scope == null) return; |
| 2317 ir.CreateBox boxPrim = addPrimitive(new ir.CreateBox()); | 2174 ir.CreateBox boxPrim = addPrimitive(new ir.CreateBox()); |
| 2318 environment.extend(scope.box, boxPrim); | 2175 environment.extend(scope.box, boxPrim); |
| 2319 boxPrim.useElementAsHint(scope.box); | 2176 boxPrim.useElementAsHint(scope.box); |
| 2320 scope.capturedVariables.forEach((Local local, ClosureLocation location) { | 2177 scope.capturedVariables.forEach((Local local, ClosureLocation location) { |
| 2321 assert(!jsState.boxedVariables.containsKey(local)); | 2178 assert(!state.boxedVariables.containsKey(local)); |
| 2322 if (location.isBox) { | 2179 if (location.isBox) { |
| 2323 jsState.boxedVariables[local] = location; | 2180 state.boxedVariables[local] = location; |
| 2324 } | 2181 } |
| 2325 }); | 2182 }); |
| 2326 } | 2183 } |
| 2327 | 2184 |
| 2185 /// Add the given function parameter to the IR, and bind it in the environment |
| 2186 /// or put it in its box, if necessary. |
| 2328 void _createFunctionParameter(Local parameterElement) { | 2187 void _createFunctionParameter(Local parameterElement) { |
| 2329 ir.Parameter parameter = new ir.Parameter(parameterElement); | 2188 ir.Parameter parameter = new ir.Parameter(parameterElement); |
| 2330 _parameters.add(parameter); | 2189 _parameters.add(parameter); |
| 2331 state.functionParameters.add(parameter); | 2190 state.functionParameters.add(parameter); |
| 2332 ClosureLocation location = jsState.boxedVariables[parameterElement]; | 2191 ClosureLocation location = state.boxedVariables[parameterElement]; |
| 2333 if (location != null) { | 2192 if (location != null) { |
| 2334 add(new ir.SetField(environment.lookup(location.box), | 2193 add(new ir.SetField(environment.lookup(location.box), |
| 2335 location.field, | 2194 location.field, |
| 2336 parameter)); | 2195 parameter)); |
| 2337 } else { | 2196 } else { |
| 2338 environment.extend(parameterElement, parameter); | 2197 environment.extend(parameterElement, parameter); |
| 2339 } | 2198 } |
| 2340 } | 2199 } |
| 2341 | 2200 |
| 2342 void _createThisParameter() { | 2201 void _createThisParameter() { |
| 2202 assert(state.thisParameter == null); |
| 2343 if (Elements.isStaticOrTopLevel(state.currentElement)) return; | 2203 if (Elements.isStaticOrTopLevel(state.currentElement)) return; |
| 2344 if (state.currentElement.isLocal) return; | 2204 if (state.currentElement.isLocal) return; |
| 2345 state.thisParameter = | 2205 state.thisParameter = |
| 2346 new ir.Parameter(new ThisParameterLocal(state.currentElement)); | 2206 new ir.Parameter(new ThisParameterLocal(state.currentElement)); |
| 2347 } | 2207 } |
| 2348 | 2208 |
| 2349 void declareLocalVariable(LocalElement variableElement, | 2209 void declareLocalVariable(LocalElement variableElement, |
| 2350 {ir.Primitive initialValue}) { | 2210 {ir.Primitive initialValue}) { |
| 2351 assert(isOpen); | 2211 assert(isOpen); |
| 2352 if (initialValue == null) { | 2212 if (initialValue == null) { |
| 2353 initialValue = buildNullConstant(); | 2213 initialValue = buildNullConstant(); |
| 2354 } | 2214 } |
| 2355 ClosureLocation location = jsState.boxedVariables[variableElement]; | 2215 ClosureLocation location = state.boxedVariables[variableElement]; |
| 2356 if (location != null) { | 2216 if (location != null) { |
| 2357 add(new ir.SetField(environment.lookup(location.box), | 2217 add(new ir.SetField(environment.lookup(location.box), |
| 2358 location.field, | 2218 location.field, |
| 2359 initialValue)); | 2219 initialValue)); |
| 2360 } else if (isInMutableVariable(variableElement)) { | 2220 } else if (isInMutableVariable(variableElement)) { |
| 2361 add(new ir.LetMutable(getMutableVariable(variableElement), | 2221 add(new ir.LetMutable(getMutableVariable(variableElement), |
| 2362 initialValue)); | 2222 initialValue)); |
| 2363 } else { | 2223 } else { |
| 2364 initialValue.useElementAsHint(variableElement); | 2224 initialValue.useElementAsHint(variableElement); |
| 2365 environment.extend(variableElement, initialValue); | 2225 environment.extend(variableElement, initialValue); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2381 ir.Primitive value = field.local is ThisLocal | 2241 ir.Primitive value = field.local is ThisLocal |
| 2382 ? buildThis() | 2242 ? buildThis() |
| 2383 : environment.lookup(field.local); | 2243 : environment.lookup(field.local); |
| 2384 arguments.add(value); | 2244 arguments.add(value); |
| 2385 } | 2245 } |
| 2386 return addPrimitive( | 2246 return addPrimitive( |
| 2387 new ir.CreateInstance(classElement, arguments, const <ir.Primitive>[])); | 2247 new ir.CreateInstance(classElement, arguments, const <ir.Primitive>[])); |
| 2388 } | 2248 } |
| 2389 | 2249 |
| 2390 /// Create a read access of [local] variable or parameter. | 2250 /// Create a read access of [local] variable or parameter. |
| 2391 @override | |
| 2392 ir.Primitive _buildLocalGet(LocalElement local) { | 2251 ir.Primitive _buildLocalGet(LocalElement local) { |
| 2393 assert(isOpen); | 2252 assert(isOpen); |
| 2394 ClosureLocation location = jsState.boxedVariables[local]; | 2253 ClosureLocation location = state.boxedVariables[local]; |
| 2395 if (location != null) { | 2254 if (location != null) { |
| 2396 ir.Primitive result = new ir.GetField(environment.lookup(location.box), | 2255 ir.Primitive result = new ir.GetField(environment.lookup(location.box), |
| 2397 location.field); | 2256 location.field); |
| 2398 result.useElementAsHint(local); | 2257 result.useElementAsHint(local); |
| 2399 return addPrimitive(result); | 2258 return addPrimitive(result); |
| 2400 } else if (isInMutableVariable(local)) { | 2259 } else if (isInMutableVariable(local)) { |
| 2401 return addPrimitive(new ir.GetMutableVariable(getMutableVariable(local))); | 2260 return addPrimitive(new ir.GetMutableVariable(getMutableVariable(local))); |
| 2402 } else { | 2261 } else { |
| 2403 return environment.lookup(local); | 2262 return environment.lookup(local); |
| 2404 } | 2263 } |
| 2405 } | 2264 } |
| 2406 | 2265 |
| 2407 /// Create a write access to [local] variable or parameter with the provided | 2266 /// Create a write access to [local] variable or parameter with the provided |
| 2408 /// [value]. | 2267 /// [value]. |
| 2409 @override | |
| 2410 ir.Primitive buildLocalVariableSet(LocalElement local, ir.Primitive value) { | 2268 ir.Primitive buildLocalVariableSet(LocalElement local, ir.Primitive value) { |
| 2411 assert(isOpen); | 2269 assert(isOpen); |
| 2412 ClosureLocation location = jsState.boxedVariables[local]; | 2270 ClosureLocation location = state.boxedVariables[local]; |
| 2413 if (location != null) { | 2271 if (location != null) { |
| 2414 add(new ir.SetField(environment.lookup(location.box), | 2272 add(new ir.SetField(environment.lookup(location.box), |
| 2415 location.field, | 2273 location.field, |
| 2416 value)); | 2274 value)); |
| 2417 } else if (isInMutableVariable(local)) { | 2275 } else if (isInMutableVariable(local)) { |
| 2418 add(new ir.SetMutableVariable(getMutableVariable(local), value)); | 2276 add(new ir.SetMutableVariable(getMutableVariable(local), value)); |
| 2419 } else { | 2277 } else { |
| 2420 value.useElementAsHint(local); | 2278 value.useElementAsHint(local); |
| 2421 environment.update(local, value); | 2279 environment.update(local, value); |
| 2422 } | 2280 } |
| 2423 return value; | 2281 return value; |
| 2424 } | 2282 } |
| 2425 | 2283 |
| 2284 /// Called before building the initializer of a for-loop. |
| 2285 /// |
| 2286 /// The loop variables will subsequently be declared using |
| 2287 /// [declareLocalVariable]. |
| 2426 void _enterForLoopInitializer(ClosureScope scope, | 2288 void _enterForLoopInitializer(ClosureScope scope, |
| 2427 List<LocalElement> loopVariables) { | 2289 List<LocalElement> loopVariables) { |
| 2428 if (scope == null) return; | 2290 if (scope == null) return; |
| 2429 // If there are no boxed loop variables, don't create the box here, let | 2291 // If there are no boxed loop variables, don't create the box here, let |
| 2430 // it be created inside the body instead. | 2292 // it be created inside the body instead. |
| 2431 if (scope.boxedLoopVariables.isEmpty) return; | 2293 if (scope.boxedLoopVariables.isEmpty) return; |
| 2432 _enterScope(scope); | 2294 _enterScope(scope); |
| 2433 } | 2295 } |
| 2434 | 2296 |
| 2297 /// Called before building the body of a for-loop. |
| 2435 void _enterForLoopBody(ClosureScope scope, | 2298 void _enterForLoopBody(ClosureScope scope, |
| 2436 List<LocalElement> loopVariables) { | 2299 List<LocalElement> loopVariables) { |
| 2437 if (scope == null) return; | 2300 if (scope == null) return; |
| 2438 // If there are boxed loop variables, the box has already been created | 2301 // If there are boxed loop variables, the box has already been created |
| 2439 // at the initializer. | 2302 // at the initializer. |
| 2440 if (!scope.boxedLoopVariables.isEmpty) return; | 2303 if (!scope.boxedLoopVariables.isEmpty) return; |
| 2441 _enterScope(scope); | 2304 _enterScope(scope); |
| 2442 } | 2305 } |
| 2443 | 2306 |
| 2307 /// Called before building the update of a for-loop. |
| 2444 void _enterForLoopUpdate(ClosureScope scope, | 2308 void _enterForLoopUpdate(ClosureScope scope, |
| 2445 List<LocalElement> loopVariables) { | 2309 List<LocalElement> loopVariables) { |
| 2446 if (scope == null) return; | 2310 if (scope == null) return; |
| 2447 // If there are no boxed loop variables, then the box is created inside the | 2311 // If there are no boxed loop variables, then the box is created inside the |
| 2448 // body, so there is no need to explicitly renew it. | 2312 // body, so there is no need to explicitly renew it. |
| 2449 if (scope.boxedLoopVariables.isEmpty) return; | 2313 if (scope.boxedLoopVariables.isEmpty) return; |
| 2450 ir.Primitive box = environment.lookup(scope.box); | 2314 ir.Primitive box = environment.lookup(scope.box); |
| 2451 ir.Primitive newBox = addPrimitive(new ir.CreateBox()); | 2315 ir.Primitive newBox = addPrimitive(new ir.CreateBox()); |
| 2452 newBox.useElementAsHint(scope.box); | 2316 newBox.useElementAsHint(scope.box); |
| 2453 for (VariableElement loopVar in scope.boxedLoopVariables) { | 2317 for (VariableElement loopVar in scope.boxedLoopVariables) { |
| 2454 ClosureLocation location = scope.capturedVariables[loopVar]; | 2318 ClosureLocation location = scope.capturedVariables[loopVar]; |
| 2455 ir.Primitive value = addPrimitive(new ir.GetField(box, location.field)); | 2319 ir.Primitive value = addPrimitive(new ir.GetField(box, location.field)); |
| 2456 add(new ir.SetField(newBox, location.field, value)); | 2320 add(new ir.SetField(newBox, location.field, value)); |
| 2457 } | 2321 } |
| 2458 environment.update(scope.box, newBox); | 2322 environment.update(scope.box, newBox); |
| 2459 } | 2323 } |
| 2460 | 2324 |
| 2325 /// Creates an access to the receiver from the current (or enclosing) method. |
| 2326 /// |
| 2327 /// If inside a closure class, [buildThis] will redirect access through |
| 2328 /// closure fields in order to access the receiver from the enclosing method. |
| 2461 ir.Primitive buildThis() { | 2329 ir.Primitive buildThis() { |
| 2462 if (jsState.receiver != null) return jsState.receiver; | 2330 if (state.enclosingThis != null) return state.enclosingThis; |
| 2463 assert(state.thisParameter != null); | 2331 assert(state.thisParameter != null); |
| 2464 return state.thisParameter; | 2332 return state.thisParameter; |
| 2465 } | 2333 } |
| 2466 | 2334 |
| 2467 @override | |
| 2468 ir.Primitive buildSuperFieldGet(FieldElement target) { | 2335 ir.Primitive buildSuperFieldGet(FieldElement target) { |
| 2469 return addPrimitive(new ir.GetField(buildThis(), target)); | 2336 return addPrimitive(new ir.GetField(buildThis(), target)); |
| 2470 } | 2337 } |
| 2471 | 2338 |
| 2472 @override | |
| 2473 ir.Primitive buildSuperFieldSet(FieldElement target, ir.Primitive value) { | 2339 ir.Primitive buildSuperFieldSet(FieldElement target, ir.Primitive value) { |
| 2474 add(new ir.SetField(buildThis(), target, value)); | 2340 add(new ir.SetField(buildThis(), target, value)); |
| 2475 return value; | 2341 return value; |
| 2476 } | 2342 } |
| 2477 | 2343 |
| 2478 ir.Primitive buildInvokeDirectly(FunctionElement target, | 2344 ir.Primitive buildInvokeDirectly(FunctionElement target, |
| 2479 ir.Primitive receiver, | 2345 ir.Primitive receiver, |
| 2480 List<ir.Primitive> arguments) { | 2346 List<ir.Primitive> arguments) { |
| 2481 assert(isOpen); | 2347 assert(isOpen); |
| 2482 Selector selector = | 2348 Selector selector = |
| 2483 new Selector.call(target.name, target.library, arguments.length); | 2349 new Selector.call(target.name, target.library, arguments.length); |
| 2484 return _continueWithExpression( | 2350 return _continueWithExpression( |
| 2485 (k) => new ir.InvokeMethodDirectly( | 2351 (k) => new ir.InvokeMethodDirectly( |
| 2486 receiver, target, selector, arguments, k)); | 2352 receiver, target, selector, arguments, k)); |
| 2487 } | 2353 } |
| 2488 | 2354 |
| 2489 /// Loads parameters to a constructor body into the environment. | 2355 /// Loads parameters to a constructor body into the environment. |
| 2490 /// | 2356 /// |
| 2491 /// The header for a constructor body differs from other functions in that | 2357 /// The header for a constructor body differs from other functions in that |
| 2492 /// some parameters are already boxed, and the box is passed as an argument | 2358 /// some parameters are already boxed, and the box is passed as an argument |
| 2493 /// instead of being created in the header. | 2359 /// instead of being created in the header. |
| 2494 void buildConstructorBodyHeader(Iterable<Local> parameters, | 2360 void buildConstructorBodyHeader(Iterable<Local> parameters, |
| 2495 ClosureScope closureScope) { | 2361 ClosureScope closureScope) { |
| 2496 _createThisParameter(); | 2362 _createThisParameter(); |
| 2497 for (Local param in parameters) { | 2363 for (Local param in parameters) { |
| 2498 ir.Parameter parameter = createLocalParameter(param); | 2364 ir.Parameter parameter = _createLocalParameter(param); |
| 2499 state.functionParameters.add(parameter); | 2365 state.functionParameters.add(parameter); |
| 2500 } | 2366 } |
| 2501 if (closureScope != null) { | 2367 if (closureScope != null) { |
| 2502 jsState.boxedVariables.addAll(closureScope.capturedVariables); | 2368 state.boxedVariables.addAll(closureScope.capturedVariables); |
| 2503 } | 2369 } |
| 2504 } | 2370 } |
| 2505 | 2371 |
| 2506 @override | 2372 /// Create a constructor invocation of [element] on [type] where the |
| 2373 /// constructor name and argument structure are defined by [callStructure] and |
| 2374 /// the argument values are defined by [arguments]. |
| 2507 ir.Primitive buildConstructorInvocation(ConstructorElement element, | 2375 ir.Primitive buildConstructorInvocation(ConstructorElement element, |
| 2508 CallStructure callStructure, | 2376 CallStructure callStructure, |
| 2509 DartType type, | 2377 DartType type, |
| 2510 List<ir.Primitive> arguments) { | 2378 List<ir.Primitive> arguments) { |
| 2511 assert(isOpen); | 2379 assert(isOpen); |
| 2512 Selector selector = | 2380 Selector selector = |
| 2513 new Selector(SelectorKind.CALL, element.memberName, callStructure); | 2381 new Selector(SelectorKind.CALL, element.memberName, callStructure); |
| 2514 ClassElement cls = element.enclosingClass; | 2382 ClassElement cls = element.enclosingClass; |
| 2515 if (program.requiresRuntimeTypesFor(cls)) { | 2383 if (program.requiresRuntimeTypesFor(cls)) { |
| 2516 InterfaceType interface = type; | 2384 InterfaceType interface = type; |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2569 } | 2437 } |
| 2570 | 2438 |
| 2571 /// Make the given type variable accessible through the local environment | 2439 /// Make the given type variable accessible through the local environment |
| 2572 /// with the value of [binding]. | 2440 /// with the value of [binding]. |
| 2573 void declareTypeVariable(TypeVariableType variable, DartType binding) { | 2441 void declareTypeVariable(TypeVariableType variable, DartType binding) { |
| 2574 environment.extend( | 2442 environment.extend( |
| 2575 new TypeVariableLocal(variable, state.currentElement), | 2443 new TypeVariableLocal(variable, state.currentElement), |
| 2576 buildTypeExpression(binding)); | 2444 buildTypeExpression(binding)); |
| 2577 } | 2445 } |
| 2578 | 2446 |
| 2579 @override | 2447 /// Reifies the value of [variable] on the current receiver object. |
| 2580 ir.Primitive buildReifyTypeVariable(TypeVariableType variable) { | 2448 ir.Primitive buildReifyTypeVariable(TypeVariableType variable) { |
| 2581 ir.Primitive typeArgument = buildTypeVariableAccess(variable); | 2449 ir.Primitive typeArgument = buildTypeVariableAccess(variable); |
| 2582 return addPrimitive(new ir.ReifyRuntimeType(typeArgument)); | 2450 return addPrimitive(new ir.ReifyRuntimeType(typeArgument)); |
| 2583 } | 2451 } |
| 2584 | 2452 |
| 2585 ir.Primitive buildInvocationMirror(Selector selector, | 2453 ir.Primitive buildInvocationMirror(Selector selector, |
| 2586 List<ir.Primitive> arguments) { | 2454 List<ir.Primitive> arguments) { |
| 2587 return addPrimitive(new ir.CreateInvocationMirror(selector, arguments)); | 2455 return addPrimitive(new ir.CreateInvocationMirror(selector, arguments)); |
| 2588 } | 2456 } |
| 2589 | 2457 |
| 2590 ir.Primitive buildForeignCode(js.Template codeTemplate, | 2458 ir.Primitive buildForeignCode(js.Template codeTemplate, |
| 2591 List<ir.Primitive> arguments, | 2459 List<ir.Primitive> arguments, |
| 2592 NativeBehavior behavior, | 2460 NativeBehavior behavior, |
| 2593 {Element dependency}) { | 2461 {Element dependency}) { |
| 2594 types.TypeMask type = program.getTypeMaskForForeign(behavior); | 2462 types.TypeMask type = program.getTypeMaskForForeign(behavior); |
| 2595 if (codeTemplate.isExpression) { | 2463 if (codeTemplate.isExpression) { |
| 2596 return _continueWithExpression((k) => new ir.ForeignCode( | 2464 return _continueWithExpression((k) => new ir.ForeignCode( |
| 2597 codeTemplate, | 2465 codeTemplate, |
| 2598 type, | 2466 type, |
| 2599 arguments, | 2467 arguments, |
| 2600 behavior, | 2468 behavior, |
| 2601 continuation: k, | 2469 continuation: k, |
| 2602 dependency: dependency)); | 2470 dependency: dependency)); |
| 2603 } else { | 2471 } else { |
| 2604 assert(isOpen); | 2472 assert(isOpen); |
| 2605 add(new ir.ForeignCode(codeTemplate, type, arguments, behavior, | 2473 add(new ir.ForeignCode(codeTemplate, type, arguments, behavior, |
| 2606 dependency: dependency)); | 2474 dependency: dependency)); |
| 2607 _current = null; | 2475 _current = null; |
| 2476 return null; |
| 2608 } | 2477 } |
| 2609 } | 2478 } |
| 2610 | 2479 |
| 2611 @override | 2480 /// Creates a type test or type cast of [value] against [type]. |
| 2612 ir.Primitive buildTypeOperator(ir.Primitive value, | 2481 ir.Primitive buildTypeOperator(ir.Primitive value, |
| 2613 DartType type, | 2482 DartType type, |
| 2614 {bool isTypeTest}) { | 2483 {bool isTypeTest}) { |
| 2615 assert(isOpen); | 2484 assert(isOpen); |
| 2616 assert(isTypeTest != null); | 2485 assert(isTypeTest != null); |
| 2617 | 2486 |
| 2618 type = program.unaliasType(type); | 2487 type = program.unaliasType(type); |
| 2619 | 2488 |
| 2620 if (type.isMalformed) { | 2489 if (type.isMalformed) { |
| 2621 FunctionElement helper = program.throwTypeErrorHelper; | 2490 FunctionElement helper = program.throwTypeErrorHelper; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 2649 // `x is Null` is true if and only if x is null. | 2518 // `x is Null` is true if and only if x is null. |
| 2650 return _buildCheckNull(value); | 2519 return _buildCheckNull(value); |
| 2651 } | 2520 } |
| 2652 return addPrimitive(new ir.TypeTest(value, type, typeArguments)); | 2521 return addPrimitive(new ir.TypeTest(value, type, typeArguments)); |
| 2653 } else { | 2522 } else { |
| 2654 return _continueWithExpression( | 2523 return _continueWithExpression( |
| 2655 (k) => new ir.TypeCast(value, type, typeArguments, k)); | 2524 (k) => new ir.TypeCast(value, type, typeArguments, k)); |
| 2656 } | 2525 } |
| 2657 } | 2526 } |
| 2658 | 2527 |
| 2659 @override | 2528 /// Create an if-null expression. This is equivalent to a conditional |
| 2529 /// expression whose result is either [value] if [value] is not null, or |
| 2530 /// `right` if [value] is null. Only when [value] is null, [buildRight] is |
| 2531 /// evaluated to produce the `right` value. |
| 2660 ir.Primitive buildIfNull(ir.Primitive value, | 2532 ir.Primitive buildIfNull(ir.Primitive value, |
| 2661 ir.Primitive buildRight(IrBuilder builder)) { | 2533 ir.Primitive buildRight(IrBuilder builder)) { |
| 2662 ir.Primitive condition = _buildCheckNull(value); | 2534 ir.Primitive condition = _buildCheckNull(value); |
| 2663 return buildConditional(condition, buildRight, (_) => value); | 2535 return buildConditional(condition, buildRight, (_) => value); |
| 2664 } | 2536 } |
| 2665 | 2537 |
| 2666 @override | 2538 /// Create a conditional send. This is equivalent to a conditional expression |
| 2539 /// that checks if [receiver] is null, if so, it returns null, otherwise it |
| 2540 /// evaluates the [buildSend] expression. |
| 2667 ir.Primitive buildIfNotNullSend(ir.Primitive receiver, | 2541 ir.Primitive buildIfNotNullSend(ir.Primitive receiver, |
| 2668 ir.Primitive buildSend(IrBuilder builder)) { | 2542 ir.Primitive buildSend(IrBuilder builder)) { |
| 2669 ir.Primitive condition = _buildCheckNull(receiver); | 2543 ir.Primitive condition = _buildCheckNull(receiver); |
| 2670 return buildConditional(condition, (_) => receiver, buildSend); | 2544 return buildConditional(condition, (_) => receiver, buildSend); |
| 2671 } | 2545 } |
| 2672 | 2546 |
| 2673 /// Creates a type test checking whether [value] is null. | 2547 /// Creates a type test checking whether [value] is null. |
| 2674 ir.Primitive _buildCheckNull(ir.Primitive value) { | 2548 ir.Primitive _buildCheckNull(ir.Primitive value) { |
| 2675 assert(isOpen); | 2549 assert(isOpen); |
| 2676 return buildIdentical(value, buildNullConstant()); | 2550 return buildIdentical(value, buildNullConstant()); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2757 } | 2631 } |
| 2758 | 2632 |
| 2759 class SwitchCaseInfo { | 2633 class SwitchCaseInfo { |
| 2760 final List<ir.Primitive> constants = <ir.Primitive>[]; | 2634 final List<ir.Primitive> constants = <ir.Primitive>[]; |
| 2761 final SubbuildFunction buildBody; | 2635 final SubbuildFunction buildBody; |
| 2762 | 2636 |
| 2763 SwitchCaseInfo(this.buildBody); | 2637 SwitchCaseInfo(this.buildBody); |
| 2764 | 2638 |
| 2765 void addConstant(ir.Primitive constant) => constants.add(constant); | 2639 void addConstant(ir.Primitive constant) => constants.add(constant); |
| 2766 } | 2640 } |
| OLD | NEW |