| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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.cps_ir.optimize_interceptors; | 5 library dart2js.cps_ir.optimize_interceptors; |
| 6 | 6 |
| 7 import 'optimizers.dart'; | 7 import 'optimizers.dart'; |
| 8 import 'cps_ir_nodes.dart'; | 8 import 'cps_ir_nodes.dart'; |
| 9 import 'loop_hierarchy.dart'; | 9 import 'loop_hierarchy.dart'; |
| 10 import 'cps_fragment.dart'; | 10 import 'cps_fragment.dart'; |
| 11 import '../constants/values.dart'; | 11 import '../constants/values.dart'; |
| 12 import '../elements/elements.dart'; | 12 import '../elements/elements.dart'; |
| 13 import '../js_backend/backend_helpers.dart' show BackendHelpers; | 13 import '../js_backend/backend_helpers.dart' show BackendHelpers; |
| 14 import '../js_backend/js_backend.dart' show JavaScriptBackend; | 14 import '../js_backend/js_backend.dart' show JavaScriptBackend; |
| 15 import '../types/types.dart' show TypeMask; | 15 import '../types/types.dart' show TypeMask; |
| 16 import '../io/source_information.dart' show SourceInformation; | 16 import '../io/source_information.dart' show SourceInformation; |
| 17 import '../universe/selector.dart'; |
| 17 | 18 |
| 18 /// Replaces `getInterceptor` calls with interceptor constants when possible, | 19 /// Replaces `getInterceptor` calls with interceptor constants when possible, |
| 19 /// or with "almost constant" expressions like "x && CONST" when the input | 20 /// or with "almost constant" expressions like "x && CONST" when the input |
| 20 /// is either null or has a known interceptor. | 21 /// is either null or has a known interceptor. |
| 21 // | 22 // |
| 22 // TODO(asgerf): Compute intercepted classes in this pass. | 23 // TODO(asgerf): Compute intercepted classes in this pass. |
| 23 class OptimizeInterceptors extends TrampolineRecursiveVisitor implements Pass { | 24 class OptimizeInterceptors extends TrampolineRecursiveVisitor implements Pass { |
| 24 String get passName => 'Optimize interceptors'; | 25 String get passName => 'Optimize interceptors'; |
| 25 | 26 |
| 26 JavaScriptBackend backend; | 27 JavaScriptBackend backend; |
| 27 LoopHierarchy loopHierarchy; | 28 LoopHierarchy loopHierarchy; |
| 28 Continuation currentLoopHeader; | 29 Continuation currentLoopHeader; |
| 29 | 30 |
| 30 OptimizeInterceptors(this.backend); | 31 OptimizeInterceptors(this.backend); |
| 31 | 32 |
| 32 BackendHelpers get helpers => backend.helpers; | 33 BackendHelpers get helpers => backend.helpers; |
| 33 | 34 |
| 35 Map<Interceptor, Continuation> loopHeaderFor = <Interceptor, Continuation>{}; |
| 36 |
| 34 void rewrite(FunctionDefinition node) { | 37 void rewrite(FunctionDefinition node) { |
| 35 // TODO(asgerf): Computing the LoopHierarchy here may be overkill when all | 38 // TODO(asgerf): Computing the LoopHierarchy here may be overkill when all |
| 36 // we want is to hoist constants out of loops. | 39 // we want is to hoist constants out of loops. |
| 37 loopHierarchy = new LoopHierarchy(node); | 40 loopHierarchy = new LoopHierarchy(node); |
| 38 visit(node.body); | 41 visit(node.body); |
| 39 new ShareConstants().visit(node); | 42 new ShareConstants().visit(node); |
| 40 } | 43 } |
| 41 | 44 |
| 42 @override | 45 @override |
| 43 Expression traverseContinuation(Continuation cont) { | 46 Expression traverseContinuation(Continuation cont) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 Continuation loop = getCurrentOuterLoop(); | 97 Continuation loop = getCurrentOuterLoop(); |
| 95 if (loop != null) { | 98 if (loop != null) { |
| 96 LetCont loopBinding = loop.parent; | 99 LetCont loopBinding = loop.parent; |
| 97 letPrim.insertAbove(loopBinding); | 100 letPrim.insertAbove(loopBinding); |
| 98 } else { | 101 } else { |
| 99 letPrim.insertAbove(useSite); | 102 letPrim.insertAbove(useSite); |
| 100 } | 103 } |
| 101 return prim; | 104 return prim; |
| 102 } | 105 } |
| 103 | 106 |
| 104 void constifyInterceptor(Interceptor interceptor) { | 107 bool constifyInterceptor(Interceptor interceptor) { |
| 105 LetPrim let = interceptor.parent; | 108 LetPrim let = interceptor.parent; |
| 106 InterceptorConstantValue constant = getInterceptorConstant(interceptor); | 109 InterceptorConstantValue constant = getInterceptorConstant(interceptor); |
| 107 | 110 |
| 108 if (constant == null) return; | 111 if (constant == null) return false; |
| 109 | 112 |
| 110 if (interceptor.isAlwaysIntercepted) { | 113 if (interceptor.isAlwaysIntercepted) { |
| 111 Primitive constantPrim = makeConstantFor(constant, | 114 Primitive constantPrim = makeConstantFor(constant, |
| 112 useSite: let, | 115 useSite: let, |
| 113 type: interceptor.type, | 116 type: interceptor.type, |
| 114 sourceInformation: interceptor.sourceInformation); | 117 sourceInformation: interceptor.sourceInformation); |
| 115 constantPrim.useElementAsHint(interceptor.hint); | 118 constantPrim.useElementAsHint(interceptor.hint); |
| 116 interceptor..replaceUsesWith(constantPrim)..destroy(); | 119 interceptor..replaceUsesWith(constantPrim)..destroy(); |
| 117 let.remove(); | 120 let.remove(); |
| 118 } else if (interceptor.isAlwaysNullOrIntercepted) { | 121 } else if (interceptor.isAlwaysNullOrIntercepted) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 134 BuiltinOperator.LooseEq, | 137 BuiltinOperator.LooseEq, |
| 135 [input, cps.makeNull()]); | 138 [input, cps.makeNull()]); |
| 136 cps.ifTruthy(condition).invokeContinuation(cont, [input]); | 139 cps.ifTruthy(condition).invokeContinuation(cont, [input]); |
| 137 } | 140 } |
| 138 cps.invokeContinuation(cont, [constantPrim]); | 141 cps.invokeContinuation(cont, [constantPrim]); |
| 139 cps.context = cont; | 142 cps.context = cont; |
| 140 cps.insertAbove(let); | 143 cps.insertAbove(let); |
| 141 interceptor..replaceUsesWith(param)..destroy(); | 144 interceptor..replaceUsesWith(param)..destroy(); |
| 142 let.remove(); | 145 let.remove(); |
| 143 } | 146 } |
| 147 return true; |
| 144 } | 148 } |
| 145 | 149 |
| 146 @override | 150 @override |
| 147 Expression traverseLetPrim(LetPrim node) { | 151 Expression traverseLetPrim(LetPrim node) { |
| 148 Expression next = node.body; | 152 Expression next = node.body; |
| 149 if (node.primitive is Interceptor) { | 153 visit(node.primitive); |
| 150 constifyInterceptor(node.primitive); | 154 return next; |
| 155 } |
| 156 |
| 157 @override |
| 158 void visitInterceptor(Interceptor node) { |
| 159 if (constifyInterceptor(node)) return; |
| 160 if (node.hasExactlyOneUse) { |
| 161 // Set the loop header on single-use interceptors so [visitInvokeMethod] |
| 162 // can determine if it should become a one-shot interceptor. |
| 163 loopHeaderFor[node] = currentLoopHeader; |
| 151 } | 164 } |
| 152 return next; | 165 } |
| 166 |
| 167 @override |
| 168 void visitInvokeMethod(InvokeMethod node) { |
| 169 if (node.callingConvention != CallingConvention.Intercepted) return; |
| 170 Primitive interceptor = node.receiver.definition; |
| 171 if (interceptor is! Interceptor || |
| 172 interceptor.hasMultipleUses || |
| 173 loopHeaderFor[interceptor] != currentLoopHeader) { |
| 174 return; |
| 175 } |
| 176 // TODO(asgerf): Consider heuristics for when to use one-shot interceptors. |
| 177 // E.g. using only one-shot interceptors with a fast path. |
| 178 node.callingConvention = CallingConvention.OneShotIntercepted; |
| 179 node..receiver.unlink()..receiver = node.arguments.removeAt(0); |
| 180 } |
| 181 |
| 182 @override |
| 183 void visitTypeTestViaFlag(TypeTestViaFlag node) { |
| 184 Primitive interceptor = node.interceptor.definition; |
| 185 if (interceptor is! Interceptor || |
| 186 interceptor.hasMultipleUses || |
| 187 loopHeaderFor[interceptor] != currentLoopHeader || |
| 188 !backend.mayGenerateInstanceofCheck(node.dartType)) { |
| 189 return; |
| 190 } |
| 191 Interceptor inter = interceptor; |
| 192 Primitive value = inter.input.definition; |
| 193 node.replaceWith(new TypeTest(value, node.dartType, [])..type = node.type); |
| 153 } | 194 } |
| 154 } | 195 } |
| 155 | 196 |
| 156 /// Shares interceptor constants when one is in scope of another. | 197 /// Shares interceptor constants when one is in scope of another. |
| 157 /// | 198 /// |
| 158 /// Interceptor optimization runs after GVN, hence this clean-up step is needed. | 199 /// Interceptor optimization runs after GVN, hence this clean-up step is needed. |
| 159 /// | 200 /// |
| 160 /// TODO(asgerf): Handle in separate constant optimization pass? With some other | 201 /// TODO(asgerf): Handle in separate constant optimization pass? With some other |
| 161 /// constant-related optimizations, like cloning small constants at use-site. | 202 /// constant-related optimizations, like cloning small constants at use-site. |
| 162 class ShareConstants extends TrampolineRecursiveVisitor { | 203 class ShareConstants extends TrampolineRecursiveVisitor { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 179 sharedConstantFor.remove(prim.value); | 220 sharedConstantFor.remove(prim.value); |
| 180 }); | 221 }); |
| 181 } | 222 } |
| 182 return next; | 223 return next; |
| 183 } | 224 } |
| 184 | 225 |
| 185 bool shouldShareConstant(Constant constant) { | 226 bool shouldShareConstant(Constant constant) { |
| 186 return constant.value.isInterceptor; | 227 return constant.value.isInterceptor; |
| 187 } | 228 } |
| 188 } | 229 } |
| OLD | NEW |