OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 import '../compiler.dart' show Compiler; | 5 import '../compiler.dart' show Compiler; |
6 import '../constants/values.dart'; | 6 import '../constants/values.dart'; |
7 import '../elements/elements.dart'; | 7 import '../elements/elements.dart'; |
8 import '../js_backend/js_backend.dart'; | 8 import '../js_backend/js_backend.dart'; |
9 import '../types/types.dart'; | 9 import '../types/types.dart'; |
10 import '../universe/selector.dart' show Selector; | 10 import '../universe/selector.dart' show Selector; |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 (left.isPrimitive(compiler) && leftType == rightType)) { | 89 (left.isPrimitive(compiler) && leftType == rightType)) { |
90 return '=='; | 90 return '=='; |
91 } | 91 } |
92 return null; | 92 return null; |
93 } | 93 } |
94 return '==='; | 94 return '==='; |
95 } | 95 } |
96 | 96 |
97 HInstruction visitInvokeDynamic(HInvokeDynamic node) { | 97 HInstruction visitInvokeDynamic(HInvokeDynamic node) { |
98 if (node.isInterceptedCall) { | 98 if (node.isInterceptedCall) { |
99 // Calls of the form | 99 tryReplaceInterceptorWithDummy(node, node.selector, node.mask); |
100 // | |
101 // a.foo$1(a, x) | |
102 // | |
103 // where the interceptor calling convention is used come from recognizing | |
104 // that 'a' is a 'self-interceptor'. If the selector matches only methods | |
105 // that ignore the explicit receiver parameter, replace occurences of the | |
106 // receiver argument with a dummy receiver '0': | |
107 // | |
108 // a.foo$1(a, x) ---> a.foo$1(0, x) | |
109 // | |
110 // This often reduces the number of references to 'a' to one, allowing 'a' | |
111 // to be generated at use to avoid a temporary, e.g. | |
112 // | |
113 // t1 = b.get$thing(); | |
114 // t1.foo$1(t1, x) | |
115 // ---> | |
116 // b.get$thing().foo$1(0, x) | |
117 // | |
118 Selector selector = node.selector; | |
119 TypeMask mask = node.mask; | |
120 if (backend.isInterceptedSelector(selector) && | |
121 !backend.isInterceptedMixinSelector(selector, mask)) { | |
122 HInstruction interceptor = node.inputs[0]; | |
123 HInstruction receiverArgument = node.inputs[1]; | |
124 | |
125 if (interceptor.nonCheck() == receiverArgument.nonCheck()) { | |
126 // TODO(15933): Make automatically generated property extraction | |
127 // closures work with the dummy receiver optimization. | |
128 if (!selector.isGetter) { | |
129 ConstantValue constant = new SyntheticConstantValue( | |
130 SyntheticConstantKind.DUMMY_INTERCEPTOR, | |
131 receiverArgument.instructionType); | |
132 HConstant dummy = graph.addConstant(constant, compiler); | |
133 receiverArgument.usedBy.remove(node); | |
134 node.inputs[1] = dummy; | |
135 dummy.usedBy.add(node); | |
136 } | |
137 } | |
138 } | |
139 } | 100 } |
140 | |
141 return node; | 101 return node; |
142 } | 102 } |
143 | 103 |
| 104 HInstruction visitInvokeSuper(HInvokeSuper node) { |
| 105 if (node.isInterceptedCall) { |
| 106 TypeMask mask = node.getDartReceiver(compiler).instructionType; |
| 107 tryReplaceInterceptorWithDummy(node, node.selector, mask); |
| 108 } |
| 109 return node; |
| 110 } |
| 111 |
| 112 void tryReplaceInterceptorWithDummy( |
| 113 HInvoke node, Selector selector, TypeMask mask) { |
| 114 // Calls of the form |
| 115 // |
| 116 // a.foo$1(a, x) |
| 117 // |
| 118 // where the interceptor calling convention is used come from recognizing |
| 119 // that 'a' is a 'self-interceptor'. If the selector matches only methods |
| 120 // that ignore the explicit receiver parameter, replace occurences of the |
| 121 // receiver argument with a dummy receiver '0': |
| 122 // |
| 123 // a.foo$1(a, x) ---> a.foo$1(0, x) |
| 124 // |
| 125 // This often reduces the number of references to 'a' to one, allowing 'a' |
| 126 // to be generated at use to avoid a temporary, e.g. |
| 127 // |
| 128 // t1 = b.get$thing(); |
| 129 // t1.foo$1(t1, x) |
| 130 // ---> |
| 131 // b.get$thing().foo$1(0, x) |
| 132 // |
| 133 |
| 134 // TODO(15933): Make automatically generated property extraction closures |
| 135 // work with the dummy receiver optimization. |
| 136 if (selector.isGetter) return; |
| 137 |
| 138 // This assignment of inputs is uniform for HInvokeDynamic and HInvokeSuper. |
| 139 HInstruction interceptor = node.inputs[0]; |
| 140 HInstruction receiverArgument = node.inputs[1]; |
| 141 |
| 142 if (interceptor.nonCheck() == receiverArgument.nonCheck()) { |
| 143 if (backend.isInterceptedSelector(selector) && |
| 144 !backend.isInterceptedMixinSelector(selector, mask)) { |
| 145 ConstantValue constant = new SyntheticConstantValue( |
| 146 SyntheticConstantKind.DUMMY_INTERCEPTOR, |
| 147 receiverArgument.instructionType); |
| 148 HConstant dummy = graph.addConstant(constant, compiler); |
| 149 receiverArgument.usedBy.remove(node); |
| 150 node.inputs[1] = dummy; |
| 151 dummy.usedBy.add(node); |
| 152 } |
| 153 } |
| 154 } |
| 155 |
144 HInstruction visitFieldSet(HFieldSet setter) { | 156 HInstruction visitFieldSet(HFieldSet setter) { |
145 // Pattern match | 157 // Pattern match |
146 // t1 = x.f; t2 = t1 + 1; x.f = t2; use(t2) --> ++x.f | 158 // t1 = x.f; t2 = t1 + 1; x.f = t2; use(t2) --> ++x.f |
147 // t1 = x.f; t2 = t1 op y; x.f = t2; use(t2) --> x.f op= y | 159 // t1 = x.f; t2 = t1 op y; x.f = t2; use(t2) --> x.f op= y |
148 // t1 = x.f; t2 = t1 + 1; x.f = t2; use(t1) --> x.f++ | 160 // t1 = x.f; t2 = t1 + 1; x.f = t2; use(t1) --> x.f++ |
149 HBasicBlock block = setter.block; | 161 HBasicBlock block = setter.block; |
150 HInstruction op = setter.value; | 162 HInstruction op = setter.value; |
151 HInstruction receiver = setter.receiver; | 163 HInstruction receiver = setter.receiver; |
152 | 164 |
153 bool isMatchingRead(HInstruction candidate) { | 165 bool isMatchingRead(HInstruction candidate) { |
(...skipping 622 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
776 } | 788 } |
777 | 789 |
778 // If [thenInput] is defined in the first predecessor, then it is only used | 790 // If [thenInput] is defined in the first predecessor, then it is only used |
779 // by [phi] and can be generated at use site. | 791 // by [phi] and can be generated at use site. |
780 if (identical(thenInput.block, end.predecessors[0])) { | 792 if (identical(thenInput.block, end.predecessors[0])) { |
781 assert(thenInput.usedBy.length == 1); | 793 assert(thenInput.usedBy.length == 1); |
782 markAsGenerateAtUseSite(thenInput); | 794 markAsGenerateAtUseSite(thenInput); |
783 } | 795 } |
784 } | 796 } |
785 } | 797 } |
OLD | NEW |