| 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 |