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

Side by Side Diff: pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart

Issue 1201463003: dart2js cps: Merge JsIrBuilder and IrBuilder. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Rebase Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library dart2js.ir_builder; 5 library dart2js.ir_builder;
6 6
7 import '../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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698