| 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/values.dart' show ConstantValue, PrimitiveConstantValue; | 9 import '../constants/values.dart' show ConstantValue, PrimitiveConstantValue; |
| 10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 for (Iterable<LocalVariableElement> boxedOnEntry in _boxedTryVariables) { | 186 for (Iterable<LocalVariableElement> boxedOnEntry in _boxedTryVariables) { |
| 187 for (LocalVariableElement variable in boxedOnEntry) { | 187 for (LocalVariableElement variable in boxedOnEntry) { |
| 188 assert(builder.isInMutableVariable(variable)); | 188 assert(builder.isInMutableVariable(variable)); |
| 189 ir.Primitive value = builder.buildLocalVariableGet(variable); | 189 ir.Primitive value = builder.buildLocalVariableGet(variable); |
| 190 builder.environment.update(variable, value); | 190 builder.environment.update(variable, value); |
| 191 } | 191 } |
| 192 } | 192 } |
| 193 } | 193 } |
| 194 | 194 |
| 195 /// True if a jump inserted now will escape from a try block. | 195 /// True if a jump inserted now will escape from a try block. |
| 196 /// | 196 /// |
| 197 /// Concretely, this is true when [enterTry] has been called without | 197 /// Concretely, this is true when [enterTry] has been called without |
| 198 /// its corresponding [leaveTry] call. | 198 /// its corresponding [leaveTry] call. |
| 199 bool get isEscapingTry => _boxedTryVariables.isNotEmpty; | 199 bool get isEscapingTry => _boxedTryVariables.isNotEmpty; |
| 200 } | 200 } |
| 201 | 201 |
| 202 /// A class to collect 'forward' jumps. | 202 /// A class to collect 'forward' jumps. |
| 203 /// | 203 /// |
| 204 /// A forward jump to a continuation in the sense of the CPS translation is | 204 /// A forward jump to a continuation in the sense of the CPS translation is |
| 205 /// a jump where the jump is emitted before any code in the body of the | 205 /// a jump where the jump is emitted before any code in the body of the |
| 206 /// continuation is translated. They have the property that continuation | 206 /// continuation is translated. They have the property that continuation |
| (...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 630 assert(isOpen); | 630 assert(isOpen); |
| 631 return _continueWithExpression( | 631 return _continueWithExpression( |
| 632 (k) => new ir.InvokeMethodDirectly( | 632 (k) => new ir.InvokeMethodDirectly( |
| 633 buildThis(), target, selector, arguments, k, sourceInformation)); | 633 buildThis(), target, selector, arguments, k, sourceInformation)); |
| 634 } | 634 } |
| 635 | 635 |
| 636 ir.Primitive _buildInvokeDynamic(ir.Primitive receiver, | 636 ir.Primitive _buildInvokeDynamic(ir.Primitive receiver, |
| 637 Selector selector, | 637 Selector selector, |
| 638 TypeMask mask, | 638 TypeMask mask, |
| 639 List<ir.Primitive> arguments, | 639 List<ir.Primitive> arguments, |
| 640 {SourceInformation sourceInformation}) { | 640 SourceInformation sourceInformation) { |
| 641 assert(isOpen); | 641 assert(isOpen); |
| 642 return _continueWithExpression( | 642 return _continueWithExpression( |
| 643 (k) => new ir.InvokeMethod(receiver, selector, mask, arguments, k, | 643 (k) => new ir.InvokeMethod(receiver, selector, mask, arguments, k, |
| 644 sourceInformation)); | 644 sourceInformation)); |
| 645 } | 645 } |
| 646 | 646 |
| 647 ir.Primitive _buildInvokeCall(ir.Primitive target, | 647 ir.Primitive _buildInvokeCall(ir.Primitive target, |
| 648 CallStructure callStructure, | 648 CallStructure callStructure, |
| 649 TypeMask mask, | 649 TypeMask mask, |
| 650 List<ir.Definition> arguments, | 650 List<ir.Definition> arguments, |
| 651 {SourceInformation sourceInformation}) { | 651 {SourceInformation sourceInformation}) { |
| 652 Selector selector = callStructure.callSelector; | 652 Selector selector = callStructure.callSelector; |
| 653 return _buildInvokeDynamic(target, selector, mask, arguments, | 653 return _buildInvokeDynamic( |
| 654 sourceInformation: sourceInformation); | 654 target, selector, mask, arguments, sourceInformation); |
| 655 } | 655 } |
| 656 | 656 |
| 657 | 657 |
| 658 /// Create a [ir.Constant] from [value] and add it to the CPS term. | 658 /// Create a [ir.Constant] from [value] and add it to the CPS term. |
| 659 ir.Constant buildConstant(ConstantValue value, | 659 ir.Constant buildConstant(ConstantValue value, |
| 660 {SourceInformation sourceInformation}) { | 660 {SourceInformation sourceInformation}) { |
| 661 assert(isOpen); | 661 assert(isOpen); |
| 662 return addPrimitive( | 662 return addPrimitive( |
| 663 new ir.Constant(value, sourceInformation: sourceInformation)); | 663 new ir.Constant(value, sourceInformation: sourceInformation)); |
| 664 } | 664 } |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 869 | 869 |
| 870 /// Create a dynamic invocation on [receiver] where the method name and | 870 /// Create a dynamic invocation on [receiver] where the method name and |
| 871 /// argument structure are defined by [selector] and the argument values are | 871 /// argument structure are defined by [selector] and the argument values are |
| 872 /// defined by [arguments]. | 872 /// defined by [arguments]. |
| 873 ir.Primitive buildDynamicInvocation(ir.Primitive receiver, | 873 ir.Primitive buildDynamicInvocation(ir.Primitive receiver, |
| 874 Selector selector, | 874 Selector selector, |
| 875 TypeMask mask, | 875 TypeMask mask, |
| 876 List<ir.Primitive> arguments, | 876 List<ir.Primitive> arguments, |
| 877 {SourceInformation sourceInformation}) { | 877 {SourceInformation sourceInformation}) { |
| 878 return _buildInvokeDynamic( | 878 return _buildInvokeDynamic( |
| 879 receiver, selector, mask, arguments, | 879 receiver, selector, mask, arguments, sourceInformation); |
| 880 sourceInformation: sourceInformation); | |
| 881 } | 880 } |
| 882 | 881 |
| 883 /// Create a dynamic getter invocation on [receiver] where the getter name is | 882 /// Create a dynamic getter invocation on [receiver] where the getter name is |
| 884 /// defined by [selector]. | 883 /// defined by [selector]. |
| 885 ir.Primitive buildDynamicGet(ir.Primitive receiver, | 884 ir.Primitive buildDynamicGet(ir.Primitive receiver, |
| 886 Selector selector, | 885 Selector selector, |
| 887 TypeMask mask) { | 886 TypeMask mask, |
| 887 SourceInformation sourceInformation) { |
| 888 assert(selector.isGetter); | 888 assert(selector.isGetter); |
| 889 FieldElement field = program.locateSingleField(selector, mask); | 889 FieldElement field = program.locateSingleField(selector, mask); |
| 890 if (field != null) { | 890 if (field != null) { |
| 891 // If the world says this resolves to a unique field, then it MUST be | 891 // If the world says this resolves to a unique field, then it MUST be |
| 892 // treated as a field access, since the getter might not be emitted. | 892 // treated as a field access, since the getter might not be emitted. |
| 893 return buildFieldGet(receiver, field); | 893 return buildFieldGet(receiver, field); |
| 894 } else { | 894 } else { |
| 895 return _buildInvokeDynamic( | 895 return _buildInvokeDynamic( |
| 896 receiver, selector, mask, const <ir.Primitive>[]); | 896 receiver, selector, mask, const <ir.Primitive>[], sourceInformation); |
| 897 } | 897 } |
| 898 } | 898 } |
| 899 | 899 |
| 900 /// Create a dynamic setter invocation on [receiver] where the setter name and | 900 /// Create a dynamic setter invocation on [receiver] where the setter name and |
| 901 /// argument are defined by [selector] and [value], respectively. | 901 /// argument are defined by [selector] and [value], respectively. |
| 902 ir.Primitive buildDynamicSet(ir.Primitive receiver, | 902 ir.Primitive buildDynamicSet(ir.Primitive receiver, |
| 903 Selector selector, | 903 Selector selector, |
| 904 TypeMask mask, | 904 TypeMask mask, |
| 905 ir.Primitive value) { | 905 ir.Primitive value, |
| 906 {SourceInformation sourceInformation}) { |
| 906 assert(selector.isSetter); | 907 assert(selector.isSetter); |
| 907 FieldElement field = program.locateSingleField(selector, mask); | 908 FieldElement field = program.locateSingleField(selector, mask); |
| 908 if (field != null) { | 909 if (field != null) { |
| 909 // If the world says this resolves to a unique field, then it MUST be | 910 // If the world says this resolves to a unique field, then it MUST be |
| 910 // treated as a field access, since the setter might not be emitted. | 911 // treated as a field access, since the setter might not be emitted. |
| 911 buildFieldSet(receiver, field, value); | 912 buildFieldSet(receiver, field, value); |
| 912 } else { | 913 } else { |
| 913 _buildInvokeDynamic(receiver, selector, mask, <ir.Primitive>[value]); | 914 _buildInvokeDynamic(receiver, selector, mask, <ir.Primitive>[value], |
| 915 sourceInformation); |
| 914 } | 916 } |
| 915 return value; | 917 return value; |
| 916 } | 918 } |
| 917 | 919 |
| 918 /// Create a dynamic index set invocation on [receiver] with the provided | 920 /// Create a dynamic index set invocation on [receiver] with the provided |
| 919 /// [index] and [value]. | 921 /// [index] and [value]. |
| 920 ir.Primitive buildDynamicIndexSet(ir.Primitive receiver, | 922 ir.Primitive buildDynamicIndexSet(ir.Primitive receiver, |
| 921 TypeMask mask, | 923 TypeMask mask, |
| 922 ir.Primitive index, | 924 ir.Primitive index, |
| 923 ir.Primitive value) { | 925 ir.Primitive value, |
| 926 {SourceInformation sourceInformation}) { |
| 924 _buildInvokeDynamic( | 927 _buildInvokeDynamic( |
| 925 receiver, new Selector.indexSet(), mask, <ir.Primitive>[index, value]); | 928 receiver, new Selector.indexSet(), mask, <ir.Primitive>[index, value], |
| 929 sourceInformation); |
| 926 return value; | 930 return value; |
| 927 } | 931 } |
| 928 | 932 |
| 929 /// Create a read access of the [local] variable or parameter. | 933 /// Create a read access of the [local] variable or parameter. |
| 930 ir.Primitive buildLocalVariableGet(LocalElement local) { | 934 ir.Primitive buildLocalVariableGet(LocalElement local) { |
| 931 // TODO(johnniwinther): Separate function access from variable access. | 935 // TODO(johnniwinther): Separate function access from variable access. |
| 932 return _buildLocalGet(local); | 936 return _buildLocalGet(local); |
| 933 } | 937 } |
| 934 | 938 |
| 935 /// Create a read access of the local [function], i.e. closurization of | 939 /// Create a read access of the local [function], i.e. closurization of |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1035 Selector selector, | 1039 Selector selector, |
| 1036 List<ir.Primitive> arguments) { | 1040 List<ir.Primitive> arguments) { |
| 1037 // TODO(johnniwinther): This should have its own ir node. | 1041 // TODO(johnniwinther): This should have its own ir node. |
| 1038 return _buildInvokeStatic(element, selector, arguments, null); | 1042 return _buildInvokeStatic(element, selector, arguments, null); |
| 1039 } | 1043 } |
| 1040 | 1044 |
| 1041 /// Concatenate string values. | 1045 /// Concatenate string values. |
| 1042 /// | 1046 /// |
| 1043 /// The arguments must be strings; usually a call to [buildStringify] is | 1047 /// The arguments must be strings; usually a call to [buildStringify] is |
| 1044 /// needed to ensure the proper conversion takes places. | 1048 /// needed to ensure the proper conversion takes places. |
| 1045 ir.Primitive buildStringConcatenation(List<ir.Primitive> arguments) { | 1049 ir.Primitive buildStringConcatenation(List<ir.Primitive> arguments, |
| 1050 {SourceInformation sourceInformation}) { |
| 1046 assert(isOpen); | 1051 assert(isOpen); |
| 1047 return addPrimitive(new ir.ApplyBuiltinOperator( | 1052 return addPrimitive(new ir.ApplyBuiltinOperator( |
| 1048 ir.BuiltinOperator.StringConcatenate, | 1053 ir.BuiltinOperator.StringConcatenate, |
| 1049 arguments)); | 1054 arguments, |
| 1055 sourceInformation)); |
| 1050 } | 1056 } |
| 1051 | 1057 |
| 1052 /// Create an invocation of the `call` method of [functionExpression], where | 1058 /// Create an invocation of the `call` method of [functionExpression], where |
| 1053 /// the structure of arguments are given by [callStructure]. | 1059 /// the structure of arguments are given by [callStructure]. |
| 1054 // TODO(johnniwinther): This should take a [TypeMask]. | 1060 // TODO(johnniwinther): This should take a [TypeMask]. |
| 1055 ir.Primitive buildCallInvocation( | 1061 ir.Primitive buildCallInvocation( |
| 1056 ir.Primitive functionExpression, | 1062 ir.Primitive functionExpression, |
| 1057 CallStructure callStructure, | 1063 CallStructure callStructure, |
| 1058 List<ir.Definition> arguments, | 1064 List<ir.Definition> arguments, |
| 1059 {SourceInformation sourceInformation}) { | 1065 {SourceInformation sourceInformation}) { |
| (...skipping 1147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2207 | 2213 |
| 2208 add(new ir.LetCont(join.continuation, | 2214 add(new ir.LetCont(join.continuation, |
| 2209 new ir.LetCont.two(leftTrueContinuation, leftFalseContinuation, | 2215 new ir.LetCont.two(leftTrueContinuation, leftFalseContinuation, |
| 2210 new ir.Branch(new ir.IsTrue(leftValue), | 2216 new ir.Branch(new ir.IsTrue(leftValue), |
| 2211 leftTrueContinuation, | 2217 leftTrueContinuation, |
| 2212 leftFalseContinuation)))); | 2218 leftFalseContinuation)))); |
| 2213 environment = join.environment; | 2219 environment = join.environment; |
| 2214 return environment.discard(1); | 2220 return environment.discard(1); |
| 2215 } | 2221 } |
| 2216 | 2222 |
| 2217 ir.Primitive buildIdentical(ir.Primitive x, ir.Primitive y) { | 2223 ir.Primitive buildIdentical(ir.Primitive x, ir.Primitive y, |
| 2224 {SourceInformation sourceInformation}) { |
| 2218 return addPrimitive(new ir.ApplyBuiltinOperator( | 2225 return addPrimitive(new ir.ApplyBuiltinOperator( |
| 2219 ir.BuiltinOperator.Identical, <ir.Primitive>[x, y])); | 2226 ir.BuiltinOperator.Identical, <ir.Primitive>[x, y], |
| 2227 sourceInformation)); |
| 2220 } | 2228 } |
| 2221 | 2229 |
| 2222 /// Called when entering a nested function with free variables. | 2230 /// Called when entering a nested function with free variables. |
| 2223 /// | 2231 /// |
| 2224 /// The free variables must subsequently be accessible using [buildLocalGet] | 2232 /// The free variables must subsequently be accessible using [buildLocalGet] |
| 2225 /// and [buildLocalSet]. | 2233 /// and [buildLocalSet]. |
| 2226 void _enterClosureEnvironment(ClosureEnvironment env) { | 2234 void _enterClosureEnvironment(ClosureEnvironment env) { |
| 2227 if (env == null) return; | 2235 if (env == null) return; |
| 2228 | 2236 |
| 2229 // Obtain a reference to the function object (this). | 2237 // Obtain a reference to the function object (this). |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2432 ir.Primitive buildThis() { | 2440 ir.Primitive buildThis() { |
| 2433 if (state.enclosingThis != null) return state.enclosingThis; | 2441 if (state.enclosingThis != null) return state.enclosingThis; |
| 2434 assert(state.thisParameter != null); | 2442 assert(state.thisParameter != null); |
| 2435 return state.thisParameter; | 2443 return state.thisParameter; |
| 2436 } | 2444 } |
| 2437 | 2445 |
| 2438 ir.Primitive buildFieldGet(ir.Primitive receiver, FieldElement target) { | 2446 ir.Primitive buildFieldGet(ir.Primitive receiver, FieldElement target) { |
| 2439 return addPrimitive(new ir.GetField(receiver, target)); | 2447 return addPrimitive(new ir.GetField(receiver, target)); |
| 2440 } | 2448 } |
| 2441 | 2449 |
| 2442 void buildFieldSet(ir.Primitive receiver, | 2450 void buildFieldSet(ir.Primitive receiver, |
| 2443 FieldElement target, | 2451 FieldElement target, |
| 2444 ir.Primitive value) { | 2452 ir.Primitive value) { |
| 2445 add(new ir.SetField(receiver, target, value)); | 2453 add(new ir.SetField(receiver, target, value)); |
| 2446 } | 2454 } |
| 2447 | 2455 |
| 2448 ir.Primitive buildSuperFieldGet(FieldElement target) { | 2456 ir.Primitive buildSuperFieldGet(FieldElement target) { |
| 2449 return addPrimitive(new ir.GetField(buildThis(), target)); | 2457 return addPrimitive(new ir.GetField(buildThis(), target)); |
| 2450 } | 2458 } |
| 2451 | 2459 |
| 2452 ir.Primitive buildSuperFieldSet(FieldElement target, ir.Primitive value) { | 2460 ir.Primitive buildSuperFieldSet(FieldElement target, ir.Primitive value) { |
| 2453 add(new ir.SetField(buildThis(), target, value)); | 2461 add(new ir.SetField(buildThis(), target, value)); |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2648 return _continueWithExpression( | 2656 return _continueWithExpression( |
| 2649 (k) => new ir.TypeCast(value, type, typeArguments, k)); | 2657 (k) => new ir.TypeCast(value, type, typeArguments, k)); |
| 2650 } | 2658 } |
| 2651 } | 2659 } |
| 2652 | 2660 |
| 2653 /// Create an if-null expression. This is equivalent to a conditional | 2661 /// Create an if-null expression. This is equivalent to a conditional |
| 2654 /// expression whose result is either [value] if [value] is not null, or | 2662 /// expression whose result is either [value] if [value] is not null, or |
| 2655 /// `right` if [value] is null. Only when [value] is null, [buildRight] is | 2663 /// `right` if [value] is null. Only when [value] is null, [buildRight] is |
| 2656 /// evaluated to produce the `right` value. | 2664 /// evaluated to produce the `right` value. |
| 2657 ir.Primitive buildIfNull(ir.Primitive value, | 2665 ir.Primitive buildIfNull(ir.Primitive value, |
| 2658 ir.Primitive buildRight(IrBuilder builder)) { | 2666 ir.Primitive buildRight(IrBuilder builder), |
| 2659 ir.Primitive condition = _buildCheckNull(value); | 2667 {SourceInformation sourceInformation}) { |
| 2668 ir.Primitive condition = |
| 2669 _buildCheckNull(value, sourceInformation: sourceInformation); |
| 2660 return buildConditional(condition, buildRight, (_) => value); | 2670 return buildConditional(condition, buildRight, (_) => value); |
| 2661 } | 2671 } |
| 2662 | 2672 |
| 2663 /// Create a conditional send. This is equivalent to a conditional expression | 2673 /// Create a conditional send. This is equivalent to a conditional expression |
| 2664 /// that checks if [receiver] is null, if so, it returns null, otherwise it | 2674 /// that checks if [receiver] is null, if so, it returns null, otherwise it |
| 2665 /// evaluates the [buildSend] expression. | 2675 /// evaluates the [buildSend] expression. |
| 2666 ir.Primitive buildIfNotNullSend(ir.Primitive receiver, | 2676 ir.Primitive buildIfNotNullSend(ir.Primitive receiver, |
| 2667 ir.Primitive buildSend(IrBuilder builder)) { | 2677 ir.Primitive buildSend(IrBuilder builder), |
| 2668 ir.Primitive condition = _buildCheckNull(receiver); | 2678 {SourceInformation sourceInformation}) { |
| 2679 ir.Primitive condition = |
| 2680 _buildCheckNull(receiver, sourceInformation: sourceInformation); |
| 2669 return buildConditional(condition, (_) => receiver, buildSend); | 2681 return buildConditional(condition, (_) => receiver, buildSend); |
| 2670 } | 2682 } |
| 2671 | 2683 |
| 2672 /// Creates a type test checking whether [value] is null. | 2684 /// Creates a type test checking whether [value] is null. |
| 2673 ir.Primitive _buildCheckNull(ir.Primitive value) { | 2685 ir.Primitive _buildCheckNull(ir.Primitive value, |
| 2686 {SourceInformation sourceInformation}) { |
| 2674 assert(isOpen); | 2687 assert(isOpen); |
| 2675 return buildIdentical(value, buildNullConstant()); | 2688 return buildIdentical(value, buildNullConstant(), |
| 2689 sourceInformation: sourceInformation); |
| 2676 } | 2690 } |
| 2677 | 2691 |
| 2678 /// Convert the given value to a string. | 2692 /// Convert the given value to a string. |
| 2679 ir.Primitive buildStringify(ir.Primitive value) { | 2693 ir.Primitive buildStringify(ir.Primitive value) { |
| 2680 return buildStaticFunctionInvocation( | 2694 return buildStaticFunctionInvocation( |
| 2681 program.stringifyFunction, | 2695 program.stringifyFunction, |
| 2682 new CallStructure.unnamed(1), | 2696 new CallStructure.unnamed(1), |
| 2683 <ir.Primitive>[value]); | 2697 <ir.Primitive>[value]); |
| 2684 } | 2698 } |
| 2685 } | 2699 } |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2756 } | 2770 } |
| 2757 | 2771 |
| 2758 class SwitchCaseInfo { | 2772 class SwitchCaseInfo { |
| 2759 final List<ir.Primitive> constants = <ir.Primitive>[]; | 2773 final List<ir.Primitive> constants = <ir.Primitive>[]; |
| 2760 final SubbuildFunction buildBody; | 2774 final SubbuildFunction buildBody; |
| 2761 | 2775 |
| 2762 SwitchCaseInfo(this.buildBody); | 2776 SwitchCaseInfo(this.buildBody); |
| 2763 | 2777 |
| 2764 void addConstant(ir.Primitive constant) => constants.add(constant); | 2778 void addConstant(ir.Primitive constant) => constants.add(constant); |
| 2765 } | 2779 } |
| OLD | NEW |