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 import '../common_elements.dart' show CommonElements; | 5 import '../common_elements.dart' show CommonElements; |
6 import '../common/backend_api.dart' show BackendClasses; | |
7 import '../constants/constant_system.dart'; | 6 import '../constants/constant_system.dart'; |
8 import '../constants/values.dart'; | 7 import '../constants/values.dart'; |
9 import '../elements/entities.dart'; | 8 import '../elements/entities.dart'; |
10 import '../js_backend/interceptor_data.dart'; | 9 import '../js_backend/interceptor_data.dart'; |
11 import '../types/types.dart'; | 10 import '../types/types.dart'; |
12 import '../universe/selector.dart' show Selector; | 11 import '../universe/selector.dart' show Selector; |
13 import '../world.dart' show ClosedWorld; | 12 import '../world.dart' show ClosedWorld; |
14 import 'nodes.dart'; | 13 import 'nodes.dart'; |
15 import 'optimize.dart'; | 14 import 'optimize.dart'; |
16 | 15 |
(...skipping 22 matching lines...) Expand all Loading... |
39 final String name = "SsaSimplifyInterceptors"; | 38 final String name = "SsaSimplifyInterceptors"; |
40 final ClosedWorld closedWorld; | 39 final ClosedWorld closedWorld; |
41 final InterceptorData interceptorData; | 40 final InterceptorData interceptorData; |
42 final CommonElements _commonElements; | 41 final CommonElements _commonElements; |
43 final ClassEntity enclosingClass; | 42 final ClassEntity enclosingClass; |
44 HGraph graph; | 43 HGraph graph; |
45 | 44 |
46 SsaSimplifyInterceptors(this.closedWorld, this._commonElements, | 45 SsaSimplifyInterceptors(this.closedWorld, this._commonElements, |
47 this.interceptorData, this.enclosingClass); | 46 this.interceptorData, this.enclosingClass); |
48 | 47 |
49 BackendClasses get backendClasses => closedWorld.backendClasses; | |
50 | |
51 ConstantSystem get constantSystem => closedWorld.constantSystem; | 48 ConstantSystem get constantSystem => closedWorld.constantSystem; |
52 | 49 |
53 void visitGraph(HGraph graph) { | 50 void visitGraph(HGraph graph) { |
54 this.graph = graph; | 51 this.graph = graph; |
55 visitDominatorTree(graph); | 52 visitDominatorTree(graph); |
56 } | 53 } |
57 | 54 |
58 void visitBasicBlock(HBasicBlock node) { | 55 void visitBasicBlock(HBasicBlock node) { |
59 currentBlock = node; | 56 currentBlock = node; |
60 | 57 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 return false; | 91 return false; |
95 } | 92 } |
96 | 93 |
97 bool canUseSelfForInterceptor( | 94 bool canUseSelfForInterceptor( |
98 HInstruction receiver, Set<ClassEntity> interceptedClasses) { | 95 HInstruction receiver, Set<ClassEntity> interceptedClasses) { |
99 if (receiver.canBePrimitive(closedWorld)) { | 96 if (receiver.canBePrimitive(closedWorld)) { |
100 // Primitives always need interceptors. | 97 // Primitives always need interceptors. |
101 return false; | 98 return false; |
102 } | 99 } |
103 if (receiver.canBeNull() && | 100 if (receiver.canBeNull() && |
104 interceptedClasses.contains(backendClasses.nullClass)) { | 101 interceptedClasses.contains(_commonElements.jsNullClass)) { |
105 // Need the JSNull interceptor. | 102 // Need the JSNull interceptor. |
106 return false; | 103 return false; |
107 } | 104 } |
108 | 105 |
109 // All intercepted classes extend `Interceptor`, so if the receiver can't be | 106 // All intercepted classes extend `Interceptor`, so if the receiver can't be |
110 // a class extending `Interceptor` then it can be called directly. | 107 // a class extending `Interceptor` then it can be called directly. |
111 return new TypeMask.nonNullSubclass( | 108 return new TypeMask.nonNullSubclass( |
112 _commonElements.jsInterceptorClass, closedWorld) | 109 _commonElements.jsInterceptorClass, closedWorld) |
113 .isDisjoint(receiver.instructionType, closedWorld); | 110 .isDisjoint(receiver.instructionType, closedWorld); |
114 } | 111 } |
(...skipping 20 matching lines...) Expand all Loading... |
135 } | 132 } |
136 | 133 |
137 ConstantValue constant = new InterceptorConstantValue(constantInterceptor); | 134 ConstantValue constant = new InterceptorConstantValue(constantInterceptor); |
138 return graph.addConstant(constant, closedWorld); | 135 return graph.addConstant(constant, closedWorld); |
139 } | 136 } |
140 | 137 |
141 ClassEntity tryComputeConstantInterceptorFromType( | 138 ClassEntity tryComputeConstantInterceptorFromType( |
142 TypeMask type, Set<ClassEntity> interceptedClasses) { | 139 TypeMask type, Set<ClassEntity> interceptedClasses) { |
143 if (type.isNullable) { | 140 if (type.isNullable) { |
144 if (type.isNull) { | 141 if (type.isNull) { |
145 return backendClasses.nullClass; | 142 return _commonElements.jsNullClass; |
146 } | 143 } |
147 } else if (type.containsOnlyInt(closedWorld)) { | 144 } else if (type.containsOnlyInt(closedWorld)) { |
148 return backendClasses.intClass; | 145 return _commonElements.jsIntClass; |
149 } else if (type.containsOnlyDouble(closedWorld)) { | 146 } else if (type.containsOnlyDouble(closedWorld)) { |
150 return backendClasses.doubleClass; | 147 return _commonElements.jsDoubleClass; |
151 } else if (type.containsOnlyBool(closedWorld)) { | 148 } else if (type.containsOnlyBool(closedWorld)) { |
152 return backendClasses.boolClass; | 149 return _commonElements.jsBoolClass; |
153 } else if (type.containsOnlyString(closedWorld)) { | 150 } else if (type.containsOnlyString(closedWorld)) { |
154 return backendClasses.stringClass; | 151 return _commonElements.jsStringClass; |
155 } else if (type.satisfies(backendClasses.listClass, closedWorld)) { | 152 } else if (type.satisfies(_commonElements.jsArrayClass, closedWorld)) { |
156 return backendClasses.listClass; | 153 return _commonElements.jsArrayClass; |
157 } else if (type.containsOnlyNum(closedWorld) && | 154 } else if (type.containsOnlyNum(closedWorld) && |
158 !interceptedClasses.contains(backendClasses.intClass) && | 155 !interceptedClasses.contains(_commonElements.jsIntClass) && |
159 !interceptedClasses.contains(backendClasses.doubleClass)) { | 156 !interceptedClasses.contains(_commonElements.jsDoubleClass)) { |
160 // If the method being intercepted is not defined in [int] or [double] we | 157 // If the method being intercepted is not defined in [int] or [double] we |
161 // can safely use the number interceptor. This is because none of the | 158 // can safely use the number interceptor. This is because none of the |
162 // [int] or [double] methods are called from a method defined on [num]. | 159 // [int] or [double] methods are called from a method defined on [num]. |
163 return backendClasses.numClass; | 160 return _commonElements.jsNumberClass; |
164 } else { | 161 } else { |
165 // Try to find constant interceptor for a native class. If the receiver | 162 // Try to find constant interceptor for a native class. If the receiver |
166 // is constrained to a leaf native class, we can use the class's | 163 // is constrained to a leaf native class, we can use the class's |
167 // interceptor directly. | 164 // interceptor directly. |
168 | 165 |
169 // TODO(sra): Key DOM classes like Node, Element and Event are not leaf | 166 // TODO(sra): Key DOM classes like Node, Element and Event are not leaf |
170 // classes. When the receiver type is not a leaf class, we might still be | 167 // classes. When the receiver type is not a leaf class, we might still be |
171 // able to use the receiver class as a constant interceptor. It is | 168 // able to use the receiver class as a constant interceptor. It is |
172 // usually the case that methods defined on a non-leaf class don't test | 169 // usually the case that methods defined on a non-leaf class don't test |
173 // for a subclass or call methods defined on a subclass. Provided the | 170 // for a subclass or call methods defined on a subclass. Provided the |
174 // code is completely insensitive to the specific instance subclasses, we | 171 // code is completely insensitive to the specific instance subclasses, we |
175 // can use the non-leaf class directly. | 172 // can use the non-leaf class directly. |
176 ClassEntity element = type.singleClass(closedWorld); | 173 ClassEntity element = type.singleClass(closedWorld); |
177 if (element != null && backendClasses.isNativeClass(element)) { | 174 if (element != null && closedWorld.nativeData.isNativeClass(element)) { |
178 return element; | 175 return element; |
179 } | 176 } |
180 } | 177 } |
181 | 178 |
182 return null; | 179 return null; |
183 } | 180 } |
184 | 181 |
185 HInstruction findDominator(Iterable<HInstruction> instructions) { | 182 HInstruction findDominator(Iterable<HInstruction> instructions) { |
186 HInstruction result; | 183 HInstruction result; |
187 L1: | 184 L1: |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 // selector of that instruction. | 219 // selector of that instruction. |
223 if (dominator is HInvokeDynamic && | 220 if (dominator is HInvokeDynamic && |
224 dominator.isCallOnInterceptor(closedWorld) && | 221 dominator.isCallOnInterceptor(closedWorld) && |
225 node == dominator.receiver && | 222 node == dominator.receiver && |
226 useCount(dominator, node) == 1) { | 223 useCount(dominator, node) == 1) { |
227 interceptedClasses = | 224 interceptedClasses = |
228 interceptorData.getInterceptedClassesOn(dominator.selector.name); | 225 interceptorData.getInterceptedClassesOn(dominator.selector.name); |
229 | 226 |
230 // If we found that we need number, we must still go through all | 227 // If we found that we need number, we must still go through all |
231 // uses to check if they require int, or double. | 228 // uses to check if they require int, or double. |
232 if (interceptedClasses.contains(backendClasses.numClass) && | 229 if (interceptedClasses.contains(_commonElements.jsNumberClass) && |
233 !(interceptedClasses.contains(backendClasses.doubleClass) || | 230 !(interceptedClasses.contains(_commonElements.jsDoubleClass) || |
234 interceptedClasses.contains(backendClasses.intClass))) { | 231 interceptedClasses.contains(_commonElements.jsIntClass))) { |
235 Set<ClassEntity> required; | 232 Set<ClassEntity> required; |
236 for (HInstruction user in node.usedBy) { | 233 for (HInstruction user in node.usedBy) { |
237 if (user is! HInvoke) continue; | 234 if (user is! HInvoke) continue; |
238 Set<ClassEntity> intercepted = | 235 Set<ClassEntity> intercepted = |
239 interceptorData.getInterceptedClassesOn(user.selector.name); | 236 interceptorData.getInterceptedClassesOn(user.selector.name); |
240 if (intercepted.contains(backendClasses.intClass)) { | 237 if (intercepted.contains(_commonElements.jsIntClass)) { |
241 // TODO(johnniwinther): Use type argument when all uses of | 238 // TODO(johnniwinther): Use type argument when all uses of |
242 // intercepted classes expect entities instead of elements. | 239 // intercepted classes expect entities instead of elements. |
243 required ??= new Set/*<ClassEntity>*/(); | 240 required ??= new Set/*<ClassEntity>*/(); |
244 required.add(backendClasses.intClass); | 241 required.add(_commonElements.jsIntClass); |
245 } | 242 } |
246 if (intercepted.contains(backendClasses.doubleClass)) { | 243 if (intercepted.contains(_commonElements.jsDoubleClass)) { |
247 // TODO(johnniwinther): Use type argument when all uses of | 244 // TODO(johnniwinther): Use type argument when all uses of |
248 // intercepted classes expect entities instead of elements. | 245 // intercepted classes expect entities instead of elements. |
249 required ??= new Set/*<ClassEntity>*/(); | 246 required ??= new Set/*<ClassEntity>*/(); |
250 required.add(backendClasses.doubleClass); | 247 required.add(_commonElements.jsDoubleClass); |
251 } | 248 } |
252 } | 249 } |
253 // Don't modify the result of [interceptorData.getInterceptedClassesOn]. | 250 // Don't modify the result of [interceptorData.getInterceptedClassesOn]. |
254 if (required != null) { | 251 if (required != null) { |
255 interceptedClasses = interceptedClasses.union(required); | 252 interceptedClasses = interceptedClasses.union(required); |
256 } | 253 } |
257 } | 254 } |
258 } else { | 255 } else { |
259 // TODO(johnniwinther): Use type argument when all uses of intercepted | 256 // TODO(johnniwinther): Use type argument when all uses of intercepted |
260 // classes expect entities instead of elements. | 257 // classes expect entities instead of elements. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
308 // If it is a conditional constant interceptor and was not strengthened to a | 305 // If it is a conditional constant interceptor and was not strengthened to a |
309 // constant interceptor then there is nothing more we can do. | 306 // constant interceptor then there is nothing more we can do. |
310 if (node.isConditionalConstantInterceptor) return false; | 307 if (node.isConditionalConstantInterceptor) return false; |
311 | 308 |
312 // Do we have an 'almost constant' interceptor? The receiver could be | 309 // Do we have an 'almost constant' interceptor? The receiver could be |
313 // `null` but not any other JavaScript falsy value, `null` values cause | 310 // `null` but not any other JavaScript falsy value, `null` values cause |
314 // `NoSuchMethodError`s, and if the receiver was not null we would have a | 311 // `NoSuchMethodError`s, and if the receiver was not null we would have a |
315 // constant interceptor `C`. Then we can use `(receiver && C)` for the | 312 // constant interceptor `C`. Then we can use `(receiver && C)` for the |
316 // interceptor. | 313 // interceptor. |
317 if (receiver.canBeNull()) { | 314 if (receiver.canBeNull()) { |
318 if (!interceptedClasses.contains(backendClasses.nullClass)) { | 315 if (!interceptedClasses.contains(_commonElements.jsNullClass)) { |
319 // Can use `(receiver && C)` only if receiver is either null or truthy. | 316 // Can use `(receiver && C)` only if receiver is either null or truthy. |
320 if (!(receiver.canBePrimitiveNumber(closedWorld) || | 317 if (!(receiver.canBePrimitiveNumber(closedWorld) || |
321 receiver.canBePrimitiveBoolean(closedWorld) || | 318 receiver.canBePrimitiveBoolean(closedWorld) || |
322 receiver.canBePrimitiveString(closedWorld))) { | 319 receiver.canBePrimitiveString(closedWorld))) { |
323 ClassEntity interceptorClass = tryComputeConstantInterceptorFromType( | 320 ClassEntity interceptorClass = tryComputeConstantInterceptorFromType( |
324 receiver.instructionType.nonNullable(), interceptedClasses); | 321 receiver.instructionType.nonNullable(), interceptedClasses); |
325 if (interceptorClass != null) { | 322 if (interceptorClass != null) { |
326 HInstruction constantInstruction = graph.addConstant( | 323 HInstruction constantInstruction = graph.addConstant( |
327 new InterceptorConstantValue(interceptorClass), closedWorld); | 324 new InterceptorConstantValue(interceptorClass), closedWorld); |
328 node.conditionalConstantInterceptor = constantInstruction; | 325 node.conditionalConstantInterceptor = constantInstruction; |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
422 instruction = new HInvokeDynamicMethod( | 419 instruction = new HInvokeDynamicMethod( |
423 selector, mask, inputs, node.instructionType, true); | 420 selector, mask, inputs, node.instructionType, true); |
424 } | 421 } |
425 | 422 |
426 HBasicBlock block = node.block; | 423 HBasicBlock block = node.block; |
427 block.addAfter(node, instruction); | 424 block.addAfter(node, instruction); |
428 block.rewrite(node, instruction); | 425 block.rewrite(node, instruction); |
429 return true; | 426 return true; |
430 } | 427 } |
431 } | 428 } |
OLD | NEW |