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

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

Issue 1413213004: Move remaining helpers to BackendHelpers (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 5 years, 1 month 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 part of ssa; 5 part of ssa;
6 6
7 /** 7 /**
8 * This phase simplifies interceptors in multiple ways: 8 * This phase simplifies interceptors in multiple ways:
9 * 9 *
10 * 1) If the interceptor is for an object whose type is known, it 10 * 1) If the interceptor is for an object whose type is known, it
(...skipping 16 matching lines...) Expand all
27 class SsaSimplifyInterceptors extends HBaseVisitor 27 class SsaSimplifyInterceptors extends HBaseVisitor
28 implements OptimizationPhase { 28 implements OptimizationPhase {
29 final String name = "SsaSimplifyInterceptors"; 29 final String name = "SsaSimplifyInterceptors";
30 final ConstantSystem constantSystem; 30 final ConstantSystem constantSystem;
31 final Compiler compiler; 31 final Compiler compiler;
32 final CodegenWorkItem work; 32 final CodegenWorkItem work;
33 HGraph graph; 33 HGraph graph;
34 34
35 SsaSimplifyInterceptors(this.compiler, this.constantSystem, this.work); 35 SsaSimplifyInterceptors(this.compiler, this.constantSystem, this.work);
36 36
37 JavaScriptBackend get backend => compiler.backend;
38
39 BackendHelpers get helpers => backend.helpers;
40
41 ClassWorld get classWorld => compiler.world;
42
37 void visitGraph(HGraph graph) { 43 void visitGraph(HGraph graph) {
38 this.graph = graph; 44 this.graph = graph;
39 visitDominatorTree(graph); 45 visitDominatorTree(graph);
40 } 46 }
41 47
42 void visitBasicBlock(HBasicBlock node) { 48 void visitBasicBlock(HBasicBlock node) {
43 currentBlock = node; 49 currentBlock = node;
44 50
45 HInstruction instruction = node.first; 51 HInstruction instruction = node.first;
46 while (instruction != null) { 52 while (instruction != null) {
(...skipping 26 matching lines...) Expand all
73 HInstruction constant = tryComputeConstantInterceptor( 79 HInstruction constant = tryComputeConstantInterceptor(
74 invoke.inputs[1], interceptor.interceptedClasses); 80 invoke.inputs[1], interceptor.interceptedClasses);
75 if (constant != null) { 81 if (constant != null) {
76 invoke.changeUse(interceptor, constant); 82 invoke.changeUse(interceptor, constant);
77 } 83 }
78 return false; 84 return false;
79 } 85 }
80 86
81 bool canUseSelfForInterceptor(HInstruction receiver, 87 bool canUseSelfForInterceptor(HInstruction receiver,
82 Set<ClassElement> interceptedClasses) { 88 Set<ClassElement> interceptedClasses) {
83 JavaScriptBackend backend = compiler.backend;
84 ClassWorld classWorld = compiler.world;
85 89
86 if (receiver.canBePrimitive(compiler)) { 90 if (receiver.canBePrimitive(compiler)) {
87 // Primitives always need interceptors. 91 // Primitives always need interceptors.
88 return false; 92 return false;
89 } 93 }
90 if (receiver.canBeNull() && 94 if (receiver.canBeNull() &&
91 interceptedClasses.contains(backend.jsNullClass)) { 95 interceptedClasses.contains(helpers.jsNullClass)) {
92 // Need the JSNull interceptor. 96 // Need the JSNull interceptor.
93 return false; 97 return false;
94 } 98 }
95 99
96 // All intercepted classes extend `Interceptor`, so if the receiver can't be 100 // All intercepted classes extend `Interceptor`, so if the receiver can't be
97 // a class extending `Interceptor` then it can be called directly. 101 // a class extending `Interceptor` then it can be called directly.
98 return new TypeMask.nonNullSubclass(backend.jsInterceptorClass, classWorld) 102 return new TypeMask.nonNullSubclass(helpers.jsInterceptorClass, classWorld)
99 .intersection(receiver.instructionType, classWorld) 103 .intersection(receiver.instructionType, classWorld)
100 .isEmpty; 104 .isEmpty;
101 } 105 }
102 106
103 HInstruction tryComputeConstantInterceptor( 107 HInstruction tryComputeConstantInterceptor(
104 HInstruction input, 108 HInstruction input,
105 Set<ClassElement> interceptedClasses) { 109 Set<ClassElement> interceptedClasses) {
106 if (input == graph.explicitReceiverParameter) { 110 if (input == graph.explicitReceiverParameter) {
107 // If `explicitReceiverParameter` is set it means the current method is an 111 // If `explicitReceiverParameter` is set it means the current method is an
108 // interceptor method, and `this` is the interceptor. The caller just did 112 // interceptor method, and `this` is the interceptor. The caller just did
(...skipping 15 matching lines...) Expand all
124 128
125 ConstantValue constant = 129 ConstantValue constant =
126 new InterceptorConstantValue(constantInterceptor.thisType); 130 new InterceptorConstantValue(constantInterceptor.thisType);
127 return graph.addConstant(constant, compiler); 131 return graph.addConstant(constant, compiler);
128 } 132 }
129 133
130 ClassElement tryComputeConstantInterceptorFromType( 134 ClassElement tryComputeConstantInterceptorFromType(
131 TypeMask type, 135 TypeMask type,
132 Set<ClassElement> interceptedClasses) { 136 Set<ClassElement> interceptedClasses) {
133 137
134 ClassWorld classWorld = compiler.world;
135 JavaScriptBackend backend = compiler.backend;
136 if (type.isNullable) { 138 if (type.isNullable) {
137 if (type.isEmpty) { 139 if (type.isEmpty) {
138 return backend.jsNullClass; 140 return helpers.jsNullClass;
139 } 141 }
140 } else if (type.containsOnlyInt(classWorld)) { 142 } else if (type.containsOnlyInt(classWorld)) {
141 return backend.jsIntClass; 143 return helpers.jsIntClass;
142 } else if (type.containsOnlyDouble(classWorld)) { 144 } else if (type.containsOnlyDouble(classWorld)) {
143 return backend.jsDoubleClass; 145 return helpers.jsDoubleClass;
144 } else if (type.containsOnlyBool(classWorld)) { 146 } else if (type.containsOnlyBool(classWorld)) {
145 return backend.jsBoolClass; 147 return helpers.jsBoolClass;
146 } else if (type.containsOnlyString(classWorld)) { 148 } else if (type.containsOnlyString(classWorld)) {
147 return backend.jsStringClass; 149 return helpers.jsStringClass;
148 } else if (type.satisfies(backend.jsArrayClass, classWorld)) { 150 } else if (type.satisfies(helpers.jsArrayClass, classWorld)) {
149 return backend.jsArrayClass; 151 return helpers.jsArrayClass;
150 } else if (type.containsOnlyNum(classWorld) && 152 } else if (type.containsOnlyNum(classWorld) &&
151 !interceptedClasses.contains(backend.jsIntClass) && 153 !interceptedClasses.contains(helpers.jsIntClass) &&
152 !interceptedClasses.contains(backend.jsDoubleClass)) { 154 !interceptedClasses.contains(helpers.jsDoubleClass)) {
153 // If the method being intercepted is not defined in [int] or [double] we 155 // If the method being intercepted is not defined in [int] or [double] we
154 // can safely use the number interceptor. This is because none of the 156 // can safely use the number interceptor. This is because none of the
155 // [int] or [double] methods are called from a method defined on [num]. 157 // [int] or [double] methods are called from a method defined on [num].
156 return backend.jsNumberClass; 158 return helpers.jsNumberClass;
157 } else { 159 } else {
158 // Try to find constant interceptor for a native class. If the receiver 160 // Try to find constant interceptor for a native class. If the receiver
159 // is constrained to a leaf native class, we can use the class's 161 // is constrained to a leaf native class, we can use the class's
160 // interceptor directly. 162 // interceptor directly.
161 163
162 // TODO(sra): Key DOM classes like Node, Element and Event are not leaf 164 // TODO(sra): Key DOM classes like Node, Element and Event are not leaf
163 // classes. When the receiver type is not a leaf class, we might still be 165 // classes. When the receiver type is not a leaf class, we might still be
164 // able to use the receiver class as a constant interceptor. It is 166 // able to use the receiver class as a constant interceptor. It is
165 // usually the case that methods defined on a non-leaf class don't test 167 // usually the case that methods defined on a non-leaf class don't test
166 // for a subclass or call methods defined on a subclass. Provided the 168 // for a subclass or call methods defined on a subclass. Provided the
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 // 204 //
203 // Currently we use the most general interceptor since all intercepted types 205 // Currently we use the most general interceptor since all intercepted types
204 // implement `hashCode`. But in this example, `a.hashCode` is only reached 206 // implement `hashCode`. But in this example, `a.hashCode` is only reached
205 // if `a.length` succeeds, which is indicated by the hashCode receiver being 207 // if `a.length` succeeds, which is indicated by the hashCode receiver being
206 // a HTypeKnown instruction. 208 // a HTypeKnown instruction.
207 209
208 int useCount(HInstruction user, HInstruction used) => 210 int useCount(HInstruction user, HInstruction used) =>
209 user.inputs.where((input) => input == used).length; 211 user.inputs.where((input) => input == used).length;
210 212
211 Set<ClassElement> interceptedClasses; 213 Set<ClassElement> interceptedClasses;
212 JavaScriptBackend backend = compiler.backend;
213 HInstruction dominator = findDominator(node.usedBy); 214 HInstruction dominator = findDominator(node.usedBy);
214 // If there is a call that dominates all other uses, we can use just the 215 // If there is a call that dominates all other uses, we can use just the
215 // selector of that instruction. 216 // selector of that instruction.
216 if (dominator is HInvokeDynamic && 217 if (dominator is HInvokeDynamic &&
217 dominator.isCallOnInterceptor(compiler) && 218 dominator.isCallOnInterceptor(compiler) &&
218 node == dominator.receiver && 219 node == dominator.receiver &&
219 useCount(dominator, node) == 1) { 220 useCount(dominator, node) == 1) {
220 interceptedClasses = 221 interceptedClasses =
221 backend.getInterceptedClassesOn(dominator.selector.name); 222 backend.getInterceptedClassesOn(dominator.selector.name);
222 223
223 // If we found that we need number, we must still go through all 224 // If we found that we need number, we must still go through all
224 // uses to check if they require int, or double. 225 // uses to check if they require int, or double.
225 if (interceptedClasses.contains(backend.jsNumberClass) && 226 if (interceptedClasses.contains(helpers.jsNumberClass) &&
226 !(interceptedClasses.contains(backend.jsDoubleClass) || 227 !(interceptedClasses.contains(helpers.jsDoubleClass) ||
227 interceptedClasses.contains(backend.jsIntClass))) { 228 interceptedClasses.contains(helpers.jsIntClass))) {
228 for (HInstruction user in node.usedBy) { 229 for (HInstruction user in node.usedBy) {
229 if (user is! HInvoke) continue; 230 if (user is! HInvoke) continue;
230 Set<ClassElement> intercepted = 231 Set<ClassElement> intercepted =
231 backend.getInterceptedClassesOn(user.selector.name); 232 backend.getInterceptedClassesOn(user.selector.name);
232 if (intercepted.contains(backend.jsIntClass)) { 233 if (intercepted.contains(helpers.jsIntClass)) {
233 interceptedClasses.add(backend.jsIntClass); 234 interceptedClasses.add(helpers.jsIntClass);
234 } 235 }
235 if (intercepted.contains(backend.jsDoubleClass)) { 236 if (intercepted.contains(helpers.jsDoubleClass)) {
236 interceptedClasses.add(backend.jsDoubleClass); 237 interceptedClasses.add(helpers.jsDoubleClass);
237 } 238 }
238 } 239 }
239 } 240 }
240 } else { 241 } else {
241 interceptedClasses = new Set<ClassElement>(); 242 interceptedClasses = new Set<ClassElement>();
242 for (HInstruction user in node.usedBy) { 243 for (HInstruction user in node.usedBy) {
243 if (user is HInvokeDynamic && 244 if (user is HInvokeDynamic &&
244 user.isCallOnInterceptor(compiler) && 245 user.isCallOnInterceptor(compiler) &&
245 node == user.receiver && 246 node == user.receiver &&
246 useCount(user, node) == 1) { 247 useCount(user, node) == 1) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
284 node.block.rewrite(node, constantInterceptor); 285 node.block.rewrite(node, constantInterceptor);
285 return false; 286 return false;
286 } 287 }
287 288
288 // Do we have an 'almost constant' interceptor? The receiver could be 289 // Do we have an 'almost constant' interceptor? The receiver could be
289 // `null` but not any other JavaScript falsy value, `null` values cause 290 // `null` but not any other JavaScript falsy value, `null` values cause
290 // `NoSuchMethodError`s, and if the receiver was not null we would have a 291 // `NoSuchMethodError`s, and if the receiver was not null we would have a
291 // constant interceptor `C`. Then we can use `(receiver && C)` for the 292 // constant interceptor `C`. Then we can use `(receiver && C)` for the
292 // interceptor. 293 // interceptor.
293 if (receiver.canBeNull() && !node.isConditionalConstantInterceptor) { 294 if (receiver.canBeNull() && !node.isConditionalConstantInterceptor) {
294 if (!interceptedClasses.contains(backend.jsNullClass)) { 295 if (!interceptedClasses.contains(helpers.jsNullClass)) {
295 // Can use `(receiver && C)` only if receiver is either null or truthy. 296 // Can use `(receiver && C)` only if receiver is either null or truthy.
296 if (!(receiver.canBePrimitiveNumber(compiler) || 297 if (!(receiver.canBePrimitiveNumber(compiler) ||
297 receiver.canBePrimitiveBoolean(compiler) || 298 receiver.canBePrimitiveBoolean(compiler) ||
298 receiver.canBePrimitiveString(compiler))) { 299 receiver.canBePrimitiveString(compiler))) {
299 ClassElement interceptorClass = tryComputeConstantInterceptorFromType( 300 ClassElement interceptorClass = tryComputeConstantInterceptorFromType(
300 receiver.instructionType.nonNullable(), interceptedClasses); 301 receiver.instructionType.nonNullable(), interceptedClasses);
301 if (interceptorClass != null) { 302 if (interceptorClass != null) {
302 HInstruction constantInstruction = 303 HInstruction constantInstruction =
303 graph.addConstant( 304 graph.addConstant(
304 new InterceptorConstantValue(interceptorClass.thisType), 305 new InterceptorConstantValue(interceptorClass.thisType),
(...skipping 19 matching lines...) Expand all
324 block.addAfter(user, replacement); 325 block.addAfter(user, replacement);
325 block.rewrite(user, replacement); 326 block.rewrite(user, replacement);
326 block.remove(user); 327 block.remove(user);
327 return false; 328 return false;
328 } 329 }
329 330
330 if (user is HIs) { 331 if (user is HIs) {
331 // See if we can rewrite the is-check to use 'instanceof', i.e. rewrite 332 // See if we can rewrite the is-check to use 'instanceof', i.e. rewrite
332 // "getInterceptor(x).$isT" to "x instanceof T". 333 // "getInterceptor(x).$isT" to "x instanceof T".
333 if (node == user.interceptor) { 334 if (node == user.interceptor) {
334 JavaScriptBackend backend = compiler.backend;
335 if (backend.mayGenerateInstanceofCheck(user.typeExpression)) { 335 if (backend.mayGenerateInstanceofCheck(user.typeExpression)) {
336 HInstruction instanceofCheck = new HIs.instanceOf( 336 HInstruction instanceofCheck = new HIs.instanceOf(
337 user.typeExpression, user.expression, user.instructionType); 337 user.typeExpression, user.expression, user.instructionType);
338 instanceofCheck.sourceInformation = user.sourceInformation; 338 instanceofCheck.sourceInformation = user.sourceInformation;
339 instanceofCheck.sourceElement = user.sourceElement; 339 instanceofCheck.sourceElement = user.sourceElement;
340 return replaceUserWith(instanceofCheck); 340 return replaceUserWith(instanceofCheck);
341 } 341 }
342 } 342 }
343 } else if (user is HInvokeDynamic) { 343 } else if (user is HInvokeDynamic) {
344 if (node == user.inputs[0]) { 344 if (node == user.inputs[0]) {
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 instruction = new HInvokeDynamicMethod( 403 instruction = new HInvokeDynamicMethod(
404 selector, mask, inputs, node.instructionType, true); 404 selector, mask, inputs, node.instructionType, true);
405 } 405 }
406 406
407 HBasicBlock block = node.block; 407 HBasicBlock block = node.block;
408 block.addAfter(node, instruction); 408 block.addAfter(node, instruction);
409 block.rewrite(node, instruction); 409 block.rewrite(node, instruction);
410 return true; 410 return true;
411 } 411 }
412 } 412 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/ssa/codegen.dart ('k') | pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698