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'; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 Continuation oldLoopHeader = currentLoopHeader; | 52 Continuation oldLoopHeader = currentLoopHeader; |
53 currentLoopHeader = loopHierarchy.getLoopHeader(cont); | 53 currentLoopHeader = loopHierarchy.getLoopHeader(cont); |
54 pushAction(() { | 54 pushAction(() { |
55 currentLoopHeader = oldLoopHeader; | 55 currentLoopHeader = oldLoopHeader; |
56 }); | 56 }); |
57 return cont.body; | 57 return cont.body; |
58 } | 58 } |
59 | 59 |
60 bool hasNoFalsyValues(ClassElement class_) { | 60 bool hasNoFalsyValues(ClassElement class_) { |
61 return class_ != helpers.jsInterceptorClass && | 61 return class_ != helpers.jsInterceptorClass && |
62 class_ != helpers.jsNullClass && | 62 class_ != helpers.jsNullClass && |
63 class_ != helpers.jsBoolClass && | 63 class_ != helpers.jsBoolClass && |
64 class_ != helpers.jsStringClass && | 64 class_ != helpers.jsStringClass && |
65 !class_.isSubclassOf(helpers.jsNumberClass); | 65 !class_.isSubclassOf(helpers.jsNumberClass); |
66 } | 66 } |
67 | 67 |
68 Continuation getCurrentOuterLoop({Continuation scope}) { | 68 Continuation getCurrentOuterLoop({Continuation scope}) { |
69 Continuation inner = null, outer = currentLoopHeader; | 69 Continuation inner = null, outer = currentLoopHeader; |
70 while (outer != scope) { | 70 while (outer != scope) { |
71 inner = outer; | 71 inner = outer; |
72 outer = loopHierarchy.getEnclosingLoop(outer); | 72 outer = loopHierarchy.getEnclosingLoop(outer); |
73 } | 73 } |
74 return inner; | 74 return inner; |
75 } | 75 } |
76 | 76 |
77 /// Binds the given constant in a primitive, in scope of the [useSite]. | 77 /// Binds the given constant in a primitive, in scope of the [useSite]. |
78 /// | 78 /// |
79 /// The constant will be hoisted out of loops, and shared with other requests | 79 /// The constant will be hoisted out of loops, and shared with other requests |
80 /// for the same constant as long as it is in scope. | 80 /// for the same constant as long as it is in scope. |
81 Primitive makeConstantFor(ConstantValue constant, | 81 Primitive makeConstantFor(ConstantValue constant, |
82 {Expression useSite, | 82 {Expression useSite, |
83 TypeMask type, | 83 TypeMask type, |
84 SourceInformation sourceInformation, | 84 SourceInformation sourceInformation, |
85 Entity hint}) { | 85 Entity hint}) { |
86 Constant prim = | 86 Constant prim = |
87 new Constant(constant, sourceInformation: sourceInformation); | 87 new Constant(constant, sourceInformation: sourceInformation); |
88 prim.hint = hint; | 88 prim.hint = hint; |
89 prim.type = type; | 89 prim.type = type; |
90 LetPrim letPrim = new LetPrim(prim); | 90 LetPrim letPrim = new LetPrim(prim); |
91 Continuation loop = getCurrentOuterLoop(); | 91 Continuation loop = getCurrentOuterLoop(); |
92 if (loop != null) { | 92 if (loop != null) { |
93 LetCont loopBinding = loop.parent; | 93 LetCont loopBinding = loop.parent; |
94 letPrim.insertAbove(loopBinding); | 94 letPrim.insertAbove(loopBinding); |
95 } else { | 95 } else { |
96 letPrim.insertAbove(useSite); | 96 letPrim.insertAbove(useSite); |
97 } | 97 } |
98 return prim; | 98 return prim; |
99 } | 99 } |
100 | 100 |
101 void computeInterceptedClasses(Interceptor interceptor) { | 101 void computeInterceptedClasses(Interceptor interceptor) { |
102 Set<ClassElement> intercepted = interceptor.interceptedClasses; | 102 Set<ClassElement> intercepted = interceptor.interceptedClasses; |
103 intercepted.clear(); | 103 intercepted.clear(); |
104 for (Reference ref = interceptor.firstRef; ref != null; ref = ref.next) { | 104 for (Reference ref = interceptor.firstRef; ref != null; ref = ref.next) { |
105 Node use = ref.parent; | 105 Node use = ref.parent; |
106 if (use is InvokeMethod) { | 106 if (use is InvokeMethod) { |
107 TypeMask type = use.receiver.type; | 107 TypeMask type = use.receiver.type; |
108 bool canOccurAsReceiver(ClassElement elem) { | 108 bool canOccurAsReceiver(ClassElement elem) { |
109 return classWorld.isInstantiated(elem) && | 109 return classWorld.isInstantiated(elem) && |
110 !typeSystem.areDisjoint(type, | 110 !typeSystem.areDisjoint( |
111 typeSystem.getInterceptorSubtypes(elem)); | 111 type, typeSystem.getInterceptorSubtypes(elem)); |
112 } | 112 } |
113 Iterable<ClassElement> classes = | 113 Iterable<ClassElement> classes = |
114 backend.getInterceptedClassesOn(use.selector.name); | 114 backend.getInterceptedClassesOn(use.selector.name); |
115 intercepted.addAll(classes.where(canOccurAsReceiver)); | 115 intercepted.addAll(classes.where(canOccurAsReceiver)); |
116 } else { | 116 } else { |
117 intercepted.clear(); | 117 intercepted.clear(); |
118 intercepted.add(backend.helpers.jsInterceptorClass); | 118 intercepted.add(backend.helpers.jsInterceptorClass); |
119 break; | 119 break; |
120 } | 120 } |
121 } | 121 } |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
203 | 203 |
204 if (classElement == null) return false; | 204 if (classElement == null) return false; |
205 ConstantValue constant = new InterceptorConstantValue(classElement.rawType); | 205 ConstantValue constant = new InterceptorConstantValue(classElement.rawType); |
206 | 206 |
207 if (!input.type.isNullable) { | 207 if (!input.type.isNullable) { |
208 Primitive constantPrim = makeConstantFor(constant, | 208 Primitive constantPrim = makeConstantFor(constant, |
209 useSite: let, | 209 useSite: let, |
210 type: interceptor.type, | 210 type: interceptor.type, |
211 sourceInformation: interceptor.sourceInformation); | 211 sourceInformation: interceptor.sourceInformation); |
212 constantPrim.useElementAsHint(interceptor.hint); | 212 constantPrim.useElementAsHint(interceptor.hint); |
213 interceptor..replaceUsesWith(constantPrim)..destroy(); | 213 interceptor |
| 214 ..replaceUsesWith(constantPrim) |
| 215 ..destroy(); |
214 let.remove(); | 216 let.remove(); |
215 } else { | 217 } else { |
216 Primitive constantPrim = makeConstantFor(constant, | 218 Primitive constantPrim = makeConstantFor(constant, |
217 useSite: let, | 219 useSite: let, |
218 type: interceptor.type.nonNullable(), | 220 type: interceptor.type.nonNullable(), |
219 sourceInformation: interceptor.sourceInformation); | 221 sourceInformation: interceptor.sourceInformation); |
220 CpsFragment cps = new CpsFragment(interceptor.sourceInformation); | 222 CpsFragment cps = new CpsFragment(interceptor.sourceInformation); |
221 Parameter param = new Parameter(interceptor.hint); | 223 Parameter param = new Parameter(interceptor.hint); |
222 param.type = interceptor.type; | 224 param.type = interceptor.type; |
223 Continuation cont = cps.letCont(<Parameter>[param]); | 225 Continuation cont = cps.letCont(<Parameter>[param]); |
224 if (hasNoFalsyValues(classElement)) { | 226 if (hasNoFalsyValues(classElement)) { |
225 // If null is the only falsy value, compile as "x && CONST". | 227 // If null is the only falsy value, compile as "x && CONST". |
226 cps.ifFalsy(input).invokeContinuation(cont, [input]); | 228 cps.ifFalsy(input).invokeContinuation(cont, [input]); |
227 } else { | 229 } else { |
228 // If there are other falsy values compile as "x == null ? x : CONST". | 230 // If there are other falsy values compile as "x == null ? x : CONST". |
229 Primitive condition = cps.applyBuiltin( | 231 Primitive condition = |
230 BuiltinOperator.LooseEq, | 232 cps.applyBuiltin(BuiltinOperator.LooseEq, [input, cps.makeNull()]); |
231 [input, cps.makeNull()]); | |
232 cps.ifTruthy(condition).invokeContinuation(cont, [input]); | 233 cps.ifTruthy(condition).invokeContinuation(cont, [input]); |
233 } | 234 } |
234 cps.invokeContinuation(cont, [constantPrim]); | 235 cps.invokeContinuation(cont, [constantPrim]); |
235 cps.context = cont; | 236 cps.context = cont; |
236 cps.insertAbove(let); | 237 cps.insertAbove(let); |
237 interceptor..replaceUsesWith(param)..destroy(); | 238 interceptor |
| 239 ..replaceUsesWith(param) |
| 240 ..destroy(); |
238 let.remove(); | 241 let.remove(); |
239 } | 242 } |
240 return true; | 243 return true; |
241 } | 244 } |
242 | 245 |
243 @override | 246 @override |
244 Expression traverseLetPrim(LetPrim node) { | 247 Expression traverseLetPrim(LetPrim node) { |
245 Expression next = node.body; | 248 Expression next = node.body; |
246 visit(node.primitive); | 249 visit(node.primitive); |
247 return next; | 250 return next; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
296 class ShareConstants extends TrampolineRecursiveVisitor { | 299 class ShareConstants extends TrampolineRecursiveVisitor { |
297 Map<ConstantValue, Constant> sharedConstantFor = <ConstantValue, Constant>{}; | 300 Map<ConstantValue, Constant> sharedConstantFor = <ConstantValue, Constant>{}; |
298 | 301 |
299 Expression traverseLetPrim(LetPrim node) { | 302 Expression traverseLetPrim(LetPrim node) { |
300 Expression next = node.body; | 303 Expression next = node.body; |
301 if (node.primitive is Constant && shouldShareConstant(node.primitive)) { | 304 if (node.primitive is Constant && shouldShareConstant(node.primitive)) { |
302 Constant prim = node.primitive; | 305 Constant prim = node.primitive; |
303 Constant existing = sharedConstantFor[prim.value]; | 306 Constant existing = sharedConstantFor[prim.value]; |
304 if (existing != null) { | 307 if (existing != null) { |
305 existing.useElementAsHint(prim.hint); | 308 existing.useElementAsHint(prim.hint); |
306 prim..replaceUsesWith(existing)..destroy(); | 309 prim |
| 310 ..replaceUsesWith(existing) |
| 311 ..destroy(); |
307 node.remove(); | 312 node.remove(); |
308 return next; | 313 return next; |
309 } | 314 } |
310 sharedConstantFor[prim.value] = prim; | 315 sharedConstantFor[prim.value] = prim; |
311 pushAction(() { | 316 pushAction(() { |
312 assert(sharedConstantFor[prim.value] == prim); | 317 assert(sharedConstantFor[prim.value] == prim); |
313 sharedConstantFor.remove(prim.value); | 318 sharedConstantFor.remove(prim.value); |
314 }); | 319 }); |
315 } | 320 } |
316 return next; | 321 return next; |
317 } | 322 } |
318 | 323 |
319 bool shouldShareConstant(Constant constant) { | 324 bool shouldShareConstant(Constant constant) { |
320 return constant.value.isInterceptor; | 325 return constant.value.isInterceptor; |
321 } | 326 } |
322 } | 327 } |
OLD | NEW |