Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(69)

Side by Side Diff: pkg/compiler/lib/src/ssa/interceptor_simplifier.dart

Issue 2619813005: Use entities in various ssa helpers. (Closed)
Patch Set: Fix. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/backend_api.dart' show BackendClasses; 5 import '../common/backend_api.dart' show BackendClasses;
6 import '../compiler.dart' show Compiler; 6 import '../compiler.dart' show Compiler;
7 import '../constants/constant_system.dart'; 7 import '../constants/constant_system.dart';
8 import '../constants/values.dart'; 8 import '../constants/values.dart';
9 import '../elements/elements.dart'; 9 import '../elements/entities.dart';
10 import '../js_backend/backend.dart'; 10 import '../js_backend/backend.dart';
11 import '../types/types.dart'; 11 import '../types/types.dart';
12 import '../universe/selector.dart' show Selector; 12 import '../universe/selector.dart' show Selector;
13 import '../world.dart' show ClosedWorld; 13 import '../world.dart' show ClosedWorld;
14 import 'nodes.dart'; 14 import 'nodes.dart';
15 import 'optimize.dart'; 15 import 'optimize.dart';
16 16
17 /** 17 /**
18 * This phase simplifies interceptors in multiple ways: 18 * This phase simplifies interceptors in multiple ways:
19 * 19 *
(...skipping 12 matching lines...) Expand all
32 * 32 *
33 * 5) Some HIs operations on an interceptor are replaced with a HIs version that 33 * 5) Some HIs operations on an interceptor are replaced with a HIs version that
34 * uses 'instanceof' rather than testing a type flag. 34 * uses 'instanceof' rather than testing a type flag.
35 * 35 *
36 */ 36 */
37 class SsaSimplifyInterceptors extends HBaseVisitor 37 class SsaSimplifyInterceptors extends HBaseVisitor
38 implements OptimizationPhase { 38 implements OptimizationPhase {
39 final String name = "SsaSimplifyInterceptors"; 39 final String name = "SsaSimplifyInterceptors";
40 final ClosedWorld closedWorld; 40 final ClosedWorld closedWorld;
41 final Compiler compiler; 41 final Compiler compiler;
42 final Element element; 42 final ClassEntity enclosingClass;
43 HGraph graph; 43 HGraph graph;
44 44
45 SsaSimplifyInterceptors(this.compiler, this.closedWorld, this.element); 45 SsaSimplifyInterceptors(this.compiler, this.closedWorld, this.enclosingClass);
46 46
47 JavaScriptBackend get backend => compiler.backend; 47 JavaScriptBackend get backend => compiler.backend;
48 48
49 BackendClasses get backendClasses => closedWorld.backendClasses; 49 BackendClasses get backendClasses => closedWorld.backendClasses;
50 50
51 ConstantSystem get constantSystem => closedWorld.constantSystem; 51 ConstantSystem get constantSystem => closedWorld.constantSystem;
52 52
53 void visitGraph(HGraph graph) { 53 void visitGraph(HGraph graph) {
54 this.graph = graph; 54 this.graph = graph;
55 visitDominatorTree(graph); 55 visitDominatorTree(graph);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 88
89 HInstruction constant = tryComputeConstantInterceptor( 89 HInstruction constant = tryComputeConstantInterceptor(
90 invoke.inputs[1], interceptor.interceptedClasses); 90 invoke.inputs[1], interceptor.interceptedClasses);
91 if (constant != null) { 91 if (constant != null) {
92 invoke.changeUse(interceptor, constant); 92 invoke.changeUse(interceptor, constant);
93 } 93 }
94 return false; 94 return false;
95 } 95 }
96 96
97 bool canUseSelfForInterceptor( 97 bool canUseSelfForInterceptor(
98 HInstruction receiver, Set<ClassElement> interceptedClasses) { 98 HInstruction receiver, Set<ClassEntity> interceptedClasses) {
99 if (receiver.canBePrimitive(closedWorld)) { 99 if (receiver.canBePrimitive(closedWorld)) {
100 // Primitives always need interceptors. 100 // Primitives always need interceptors.
101 return false; 101 return false;
102 } 102 }
103 if (receiver.canBeNull() && 103 if (receiver.canBeNull() &&
104 interceptedClasses.contains(backendClasses.nullImplementation)) { 104 interceptedClasses.contains(backendClasses.nullImplementation)) {
105 // Need the JSNull interceptor. 105 // Need the JSNull interceptor.
106 return false; 106 return false;
107 } 107 }
108 108
109 // All intercepted classes extend `Interceptor`, so if the receiver can't be 109 // All intercepted classes extend `Interceptor`, so if the receiver can't be
110 // a class extending `Interceptor` then it can be called directly. 110 // a class extending `Interceptor` then it can be called directly.
111 return new TypeMask.nonNullSubclass( 111 return new TypeMask.nonNullSubclass(
112 backend.helpers.jsInterceptorClass, closedWorld) 112 backend.helpers.jsInterceptorClass, closedWorld)
113 .isDisjoint(receiver.instructionType, closedWorld); 113 .isDisjoint(receiver.instructionType, closedWorld);
114 } 114 }
115 115
116 HInstruction tryComputeConstantInterceptor( 116 HInstruction tryComputeConstantInterceptor(
117 HInstruction input, Set<ClassElement> interceptedClasses) { 117 HInstruction input, Set<ClassEntity> interceptedClasses) {
118 if (input == graph.explicitReceiverParameter) { 118 if (input == graph.explicitReceiverParameter) {
119 // If `explicitReceiverParameter` is set it means the current method is an 119 // If `explicitReceiverParameter` is set it means the current method is an
120 // interceptor method, and `this` is the interceptor. The caller just did 120 // interceptor method, and `this` is the interceptor. The caller just did
121 // `getInterceptor(foo).currentMethod(foo)` to enter the current method. 121 // `getInterceptor(foo).currentMethod(foo)` to enter the current method.
122 return graph.thisInstruction; 122 return graph.thisInstruction;
123 } 123 }
124 124
125 ClassElement constantInterceptor = tryComputeConstantInterceptorFromType( 125 ClassEntity constantInterceptor = tryComputeConstantInterceptorFromType(
126 input.instructionType, interceptedClasses); 126 input.instructionType, interceptedClasses);
127 127
128 if (constantInterceptor == null) return null; 128 if (constantInterceptor == null) return null;
129 129
130 // If we just happen to be in an instance method of the constant 130 // If we just happen to be in an instance method of the constant
131 // interceptor, `this` is a shorter alias. 131 // interceptor, `this` is a shorter alias.
132 if (constantInterceptor == element.enclosingClass && 132 if (constantInterceptor == enclosingClass &&
133 graph.thisInstruction != null) { 133 graph.thisInstruction != null) {
134 return graph.thisInstruction; 134 return graph.thisInstruction;
135 } 135 }
136 136
137 ConstantValue constant = new InterceptorConstantValue(constantInterceptor); 137 ConstantValue constant = new InterceptorConstantValue(constantInterceptor);
138 return graph.addConstant(constant, closedWorld); 138 return graph.addConstant(constant, closedWorld);
139 } 139 }
140 140
141 ClassElement tryComputeConstantInterceptorFromType( 141 ClassEntity tryComputeConstantInterceptorFromType(
142 TypeMask type, Set<ClassElement> interceptedClasses) { 142 TypeMask type, Set<ClassEntity> interceptedClasses) {
143 if (type.isNullable) { 143 if (type.isNullable) {
144 if (type.isNull) { 144 if (type.isNull) {
145 return backendClasses.nullImplementation; 145 return backendClasses.nullImplementation;
146 } 146 }
147 } else if (type.containsOnlyInt(closedWorld)) { 147 } else if (type.containsOnlyInt(closedWorld)) {
148 return backendClasses.intImplementation; 148 return backendClasses.intImplementation;
149 } else if (type.containsOnlyDouble(closedWorld)) { 149 } else if (type.containsOnlyDouble(closedWorld)) {
150 return backendClasses.doubleImplementation; 150 return backendClasses.doubleImplementation;
151 } else if (type.containsOnlyBool(closedWorld)) { 151 } else if (type.containsOnlyBool(closedWorld)) {
152 return backendClasses.boolImplementation; 152 return backendClasses.boolImplementation;
(...skipping 13 matching lines...) Expand all
166 // is constrained to a leaf native class, we can use the class's 166 // is constrained to a leaf native class, we can use the class's
167 // interceptor directly. 167 // interceptor directly.
168 168
169 // TODO(sra): Key DOM classes like Node, Element and Event are not leaf 169 // 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 170 // 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 171 // 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 172 // 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 173 // for a subclass or call methods defined on a subclass. Provided the
174 // code is completely insensitive to the specific instance subclasses, we 174 // code is completely insensitive to the specific instance subclasses, we
175 // can use the non-leaf class directly. 175 // can use the non-leaf class directly.
176 ClassElement element = type.singleClass(closedWorld); 176 ClassEntity element = type.singleClass(closedWorld);
177 if (element != null && backendClasses.isNativeClass(element)) { 177 if (element != null && backendClasses.isNativeClass(element)) {
178 return element; 178 return element;
179 } 179 }
180 } 180 }
181 181
182 return null; 182 return null;
183 } 183 }
184 184
185 HInstruction findDominator(Iterable<HInstruction> instructions) { 185 HInstruction findDominator(Iterable<HInstruction> instructions) {
186 HInstruction result; 186 HInstruction result;
(...skipping 22 matching lines...) Expand all
209 // (a) => a.length + a.hashCode 209 // (a) => a.length + a.hashCode
210 // 210 //
211 // Currently we use the most general interceptor since all intercepted types 211 // Currently we use the most general interceptor since all intercepted types
212 // implement `hashCode`. But in this example, `a.hashCode` is only reached 212 // implement `hashCode`. But in this example, `a.hashCode` is only reached
213 // if `a.length` succeeds, which is indicated by the hashCode receiver being 213 // if `a.length` succeeds, which is indicated by the hashCode receiver being
214 // a HTypeKnown instruction. 214 // a HTypeKnown instruction.
215 215
216 int useCount(HInstruction user, HInstruction used) => 216 int useCount(HInstruction user, HInstruction used) =>
217 user.inputs.where((input) => input == used).length; 217 user.inputs.where((input) => input == used).length;
218 218
219 Set<ClassElement> interceptedClasses; 219 Set<ClassEntity> interceptedClasses;
220 HInstruction dominator = findDominator(node.usedBy); 220 HInstruction dominator = findDominator(node.usedBy);
221 // If there is a call that dominates all other uses, we can use just the 221 // If there is a call that dominates all other uses, we can use just the
222 // selector of that instruction. 222 // selector of that instruction.
223 if (dominator is HInvokeDynamic && 223 if (dominator is HInvokeDynamic &&
224 dominator.isCallOnInterceptor(closedWorld) && 224 dominator.isCallOnInterceptor(closedWorld) &&
225 node == dominator.receiver && 225 node == dominator.receiver &&
226 useCount(dominator, node) == 1) { 226 useCount(dominator, node) == 1) {
227 interceptedClasses = 227 interceptedClasses =
228 backend.getInterceptedClassesOn(dominator.selector.name); 228 backend.getInterceptedClassesOn(dominator.selector.name);
229 229
230 // If we found that we need number, we must still go through all 230 // If we found that we need number, we must still go through all
231 // uses to check if they require int, or double. 231 // uses to check if they require int, or double.
232 if (interceptedClasses.contains(backendClasses.numImplementation) && 232 if (interceptedClasses.contains(backendClasses.numImplementation) &&
233 !(interceptedClasses.contains(backendClasses.doubleImplementation) || 233 !(interceptedClasses.contains(backendClasses.doubleImplementation) ||
234 interceptedClasses.contains(backendClasses.intImplementation))) { 234 interceptedClasses.contains(backendClasses.intImplementation))) {
235 Set<ClassElement> required; 235 Set<ClassEntity> required;
236 for (HInstruction user in node.usedBy) { 236 for (HInstruction user in node.usedBy) {
237 if (user is! HInvoke) continue; 237 if (user is! HInvoke) continue;
238 Set<ClassElement> intercepted = 238 Set<ClassEntity> intercepted =
239 backend.getInterceptedClassesOn(user.selector.name); 239 backend.getInterceptedClassesOn(user.selector.name);
240 if (intercepted.contains(backendClasses.intImplementation)) { 240 if (intercepted.contains(backendClasses.intImplementation)) {
241 required ??= new Set<ClassElement>(); 241 // TODO(johnniwinther): Use type argument when all uses of intercept ed
Siggi Cherem (dart-lang) 2017/01/11 23:58:51 nit: 80 col here and below
Johnni Winther 2017/01/12 12:01:48 Done.
242 // classes expect entities instead of elements.
243 required ??= new Set/*<ClassEntity>*/();
242 required.add(backendClasses.intImplementation); 244 required.add(backendClasses.intImplementation);
243 } 245 }
244 if (intercepted.contains(backendClasses.doubleImplementation)) { 246 if (intercepted.contains(backendClasses.doubleImplementation)) {
245 required ??= new Set<ClassElement>(); 247 // TODO(johnniwinther): Use type argument when all uses of intercept ed
248 // classes expect entities instead of elements.
249 required ??= new Set/*<ClassEntity>*/();
246 required.add(backendClasses.doubleImplementation); 250 required.add(backendClasses.doubleImplementation);
247 } 251 }
248 } 252 }
249 // Don't modify the result of [backend.getInterceptedClassesOn]. 253 // Don't modify the result of [backend.getInterceptedClassesOn].
250 if (required != null) { 254 if (required != null) {
251 interceptedClasses = interceptedClasses.union(required); 255 interceptedClasses = interceptedClasses.union(required);
252 } 256 }
253 } 257 }
254 } else { 258 } else {
255 interceptedClasses = new Set<ClassElement>(); 259 // TODO(johnniwinther): Use type argument when all uses of intercepted
260 // classes expect entities instead of elements.
261 interceptedClasses = new Set/*<ClassEntity>*/();
256 for (HInstruction user in node.usedBy) { 262 for (HInstruction user in node.usedBy) {
257 if (user is HInvokeDynamic && 263 if (user is HInvokeDynamic &&
258 user.isCallOnInterceptor(closedWorld) && 264 user.isCallOnInterceptor(closedWorld) &&
259 node == user.receiver && 265 node == user.receiver &&
260 useCount(user, node) == 1) { 266 useCount(user, node) == 1) {
261 interceptedClasses 267 interceptedClasses
262 .addAll(backend.getInterceptedClassesOn(user.selector.name)); 268 .addAll(backend.getInterceptedClassesOn(user.selector.name));
263 } else if (user is HInvokeSuper && 269 } else if (user is HInvokeSuper &&
264 user.isCallOnInterceptor(closedWorld) && 270 user.isCallOnInterceptor(closedWorld) &&
265 node == user.receiver && 271 node == user.receiver &&
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 // `null` but not any other JavaScript falsy value, `null` values cause 313 // `null` but not any other JavaScript falsy value, `null` values cause
308 // `NoSuchMethodError`s, and if the receiver was not null we would have a 314 // `NoSuchMethodError`s, and if the receiver was not null we would have a
309 // constant interceptor `C`. Then we can use `(receiver && C)` for the 315 // constant interceptor `C`. Then we can use `(receiver && C)` for the
310 // interceptor. 316 // interceptor.
311 if (receiver.canBeNull()) { 317 if (receiver.canBeNull()) {
312 if (!interceptedClasses.contains(backendClasses.nullImplementation)) { 318 if (!interceptedClasses.contains(backendClasses.nullImplementation)) {
313 // Can use `(receiver && C)` only if receiver is either null or truthy. 319 // Can use `(receiver && C)` only if receiver is either null or truthy.
314 if (!(receiver.canBePrimitiveNumber(closedWorld) || 320 if (!(receiver.canBePrimitiveNumber(closedWorld) ||
315 receiver.canBePrimitiveBoolean(closedWorld) || 321 receiver.canBePrimitiveBoolean(closedWorld) ||
316 receiver.canBePrimitiveString(closedWorld))) { 322 receiver.canBePrimitiveString(closedWorld))) {
317 ClassElement interceptorClass = tryComputeConstantInterceptorFromType( 323 ClassEntity interceptorClass = tryComputeConstantInterceptorFromType(
318 receiver.instructionType.nonNullable(), interceptedClasses); 324 receiver.instructionType.nonNullable(), interceptedClasses);
319 if (interceptorClass != null) { 325 if (interceptorClass != null) {
320 HInstruction constantInstruction = graph.addConstant( 326 HInstruction constantInstruction = graph.addConstant(
321 new InterceptorConstantValue(interceptorClass), closedWorld); 327 new InterceptorConstantValue(interceptorClass), closedWorld);
322 node.conditionalConstantInterceptor = constantInstruction; 328 node.conditionalConstantInterceptor = constantInstruction;
323 constantInstruction.usedBy.add(node); 329 constantInstruction.usedBy.add(node);
324 return false; 330 return false;
325 } 331 }
326 } 332 }
327 } 333 }
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 instruction = new HInvokeDynamicMethod( 423 instruction = new HInvokeDynamicMethod(
418 selector, mask, inputs, node.instructionType, true); 424 selector, mask, inputs, node.instructionType, true);
419 } 425 }
420 426
421 HBasicBlock block = node.block; 427 HBasicBlock block = node.block;
422 block.addAfter(node, instruction); 428 block.addAfter(node, instruction);
423 block.rewrite(node, instruction); 429 block.rewrite(node, instruction);
424 return true; 430 return true;
425 } 431 }
426 } 432 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698