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

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

Issue 2569733002: Even less reliance on Compiler.closedWorld (Closed)
Patch Set: Updated cf. comments. Created 4 years 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/codegen.dart' show CodegenWorkItem; 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/elements.dart';
10 import '../js_backend/backend_helpers.dart' show BackendHelpers; 10 import '../js_backend/backend.dart';
11 import '../js_backend/js_backend.dart';
12 import '../types/types.dart'; 11 import '../types/types.dart';
13 import '../universe/selector.dart' show Selector; 12 import '../universe/selector.dart' show Selector;
14 import '../world.dart' show ClosedWorld; 13 import '../world.dart' show ClosedWorld;
15 import 'nodes.dart'; 14 import 'nodes.dart';
16 import 'optimize.dart'; 15 import 'optimize.dart';
17 16
18 /** 17 /**
19 * This phase simplifies interceptors in multiple ways: 18 * This phase simplifies interceptors in multiple ways:
20 * 19 *
21 * 1) If the interceptor is for an object whose type is known, it 20 * 1) If the interceptor is for an object whose type is known, it
(...skipping 18 matching lines...) Expand all
40 final String name = "SsaSimplifyInterceptors"; 39 final String name = "SsaSimplifyInterceptors";
41 final ConstantSystem constantSystem; 40 final ConstantSystem constantSystem;
42 final Compiler compiler; 41 final Compiler compiler;
43 final Element element; 42 final Element element;
44 HGraph graph; 43 HGraph graph;
45 44
46 SsaSimplifyInterceptors(this.compiler, this.constantSystem, this.element); 45 SsaSimplifyInterceptors(this.compiler, this.constantSystem, this.element);
47 46
48 JavaScriptBackend get backend => compiler.backend; 47 JavaScriptBackend get backend => compiler.backend;
49 48
50 BackendHelpers get helpers => backend.helpers; 49 ClosedWorld get closedWorld => compiler.closedWorld;
51 50
52 ClosedWorld get closedWorld => compiler.closedWorld; 51 BackendClasses get backendClasses => closedWorld.backendClasses;
53 52
54 void visitGraph(HGraph graph) { 53 void visitGraph(HGraph graph) {
55 this.graph = graph; 54 this.graph = graph;
56 visitDominatorTree(graph); 55 visitDominatorTree(graph);
57 } 56 }
58 57
59 void visitBasicBlock(HBasicBlock node) { 58 void visitBasicBlock(HBasicBlock node) {
60 currentBlock = node; 59 currentBlock = node;
61 60
62 HInstruction instruction = node.first; 61 HInstruction instruction = node.first;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 return false; 94 return false;
96 } 95 }
97 96
98 bool canUseSelfForInterceptor( 97 bool canUseSelfForInterceptor(
99 HInstruction receiver, Set<ClassElement> interceptedClasses) { 98 HInstruction receiver, Set<ClassElement> interceptedClasses) {
100 if (receiver.canBePrimitive(closedWorld)) { 99 if (receiver.canBePrimitive(closedWorld)) {
101 // Primitives always need interceptors. 100 // Primitives always need interceptors.
102 return false; 101 return false;
103 } 102 }
104 if (receiver.canBeNull() && 103 if (receiver.canBeNull() &&
105 interceptedClasses.contains(helpers.jsNullClass)) { 104 interceptedClasses.contains(backendClasses.nullImplementation)) {
106 // Need the JSNull interceptor. 105 // Need the JSNull interceptor.
107 return false; 106 return false;
108 } 107 }
109 108
110 // 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
111 // a class extending `Interceptor` then it can be called directly. 110 // a class extending `Interceptor` then it can be called directly.
112 return new TypeMask.nonNullSubclass(helpers.jsInterceptorClass, closedWorld) 111 return new TypeMask.nonNullSubclass(
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<ClassElement> 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;
(...skipping 13 matching lines...) Expand all
136 136
137 ConstantValue constant = 137 ConstantValue constant =
138 new InterceptorConstantValue(constantInterceptor.thisType); 138 new InterceptorConstantValue(constantInterceptor.thisType);
139 return graph.addConstant(constant, compiler); 139 return graph.addConstant(constant, compiler);
140 } 140 }
141 141
142 ClassElement tryComputeConstantInterceptorFromType( 142 ClassElement tryComputeConstantInterceptorFromType(
143 TypeMask type, Set<ClassElement> interceptedClasses) { 143 TypeMask type, Set<ClassElement> interceptedClasses) {
144 if (type.isNullable) { 144 if (type.isNullable) {
145 if (type.isNull) { 145 if (type.isNull) {
146 return helpers.jsNullClass; 146 return backendClasses.nullImplementation;
147 } 147 }
148 } else if (type.containsOnlyInt(closedWorld)) { 148 } else if (type.containsOnlyInt(closedWorld)) {
149 return helpers.jsIntClass; 149 return backendClasses.intImplementation;
150 } else if (type.containsOnlyDouble(closedWorld)) { 150 } else if (type.containsOnlyDouble(closedWorld)) {
151 return helpers.jsDoubleClass; 151 return backendClasses.doubleImplementation;
152 } else if (type.containsOnlyBool(closedWorld)) { 152 } else if (type.containsOnlyBool(closedWorld)) {
153 return helpers.jsBoolClass; 153 return backendClasses.boolImplementation;
154 } else if (type.containsOnlyString(closedWorld)) { 154 } else if (type.containsOnlyString(closedWorld)) {
155 return helpers.jsStringClass; 155 return backendClasses.stringImplementation;
156 } else if (type.satisfies(helpers.jsArrayClass, closedWorld)) { 156 } else if (type.satisfies(backendClasses.listImplementation, closedWorld)) {
157 return helpers.jsArrayClass; 157 return backendClasses.listImplementation;
158 } else if (type.containsOnlyNum(closedWorld) && 158 } else if (type.containsOnlyNum(closedWorld) &&
159 !interceptedClasses.contains(helpers.jsIntClass) && 159 !interceptedClasses.contains(backendClasses.intImplementation) &&
160 !interceptedClasses.contains(helpers.jsDoubleClass)) { 160 !interceptedClasses.contains(backendClasses.doubleImplementation)) {
161 // If the method being intercepted is not defined in [int] or [double] we 161 // If the method being intercepted is not defined in [int] or [double] we
162 // can safely use the number interceptor. This is because none of the 162 // can safely use the number interceptor. This is because none of the
163 // [int] or [double] methods are called from a method defined on [num]. 163 // [int] or [double] methods are called from a method defined on [num].
164 return helpers.jsNumberClass; 164 return backendClasses.numImplementation;
165 } else { 165 } else {
166 // Try to find constant interceptor for a native class. If the receiver 166 // Try to find constant interceptor for a native class. If the receiver
167 // is constrained to a leaf native class, we can use the class's 167 // is constrained to a leaf native class, we can use the class's
168 // interceptor directly. 168 // interceptor directly.
169 169
170 // TODO(sra): Key DOM classes like Node, Element and Event are not leaf 170 // TODO(sra): Key DOM classes like Node, Element and Event are not leaf
171 // classes. When the receiver type is not a leaf class, we might still be 171 // classes. When the receiver type is not a leaf class, we might still be
172 // able to use the receiver class as a constant interceptor. It is 172 // able to use the receiver class as a constant interceptor. It is
173 // usually the case that methods defined on a non-leaf class don't test 173 // usually the case that methods defined on a non-leaf class don't test
174 // for a subclass or call methods defined on a subclass. Provided the 174 // for a subclass or call methods defined on a subclass. Provided the
175 // code is completely insensitive to the specific instance subclasses, we 175 // code is completely insensitive to the specific instance subclasses, we
176 // can use the non-leaf class directly. 176 // can use the non-leaf class directly.
177 ClassElement element = type.singleClass(closedWorld); 177 ClassElement element = type.singleClass(closedWorld);
178 if (element != null && backend.isNative(element)) { 178 if (element != null && backendClasses.isNative(element)) {
179 return element; 179 return element;
180 } 180 }
181 } 181 }
182 182
183 return null; 183 return null;
184 } 184 }
185 185
186 HInstruction findDominator(Iterable<HInstruction> instructions) { 186 HInstruction findDominator(Iterable<HInstruction> instructions) {
187 HInstruction result; 187 HInstruction result;
188 L1: 188 L1:
(...skipping 26 matching lines...) Expand all
215 // a HTypeKnown instruction. 215 // a HTypeKnown instruction.
216 216
217 int useCount(HInstruction user, HInstruction used) => 217 int useCount(HInstruction user, HInstruction used) =>
218 user.inputs.where((input) => input == used).length; 218 user.inputs.where((input) => input == used).length;
219 219
220 Set<ClassElement> interceptedClasses; 220 Set<ClassElement> interceptedClasses;
221 HInstruction dominator = findDominator(node.usedBy); 221 HInstruction dominator = findDominator(node.usedBy);
222 // If there is a call that dominates all other uses, we can use just the 222 // If there is a call that dominates all other uses, we can use just the
223 // selector of that instruction. 223 // selector of that instruction.
224 if (dominator is HInvokeDynamic && 224 if (dominator is HInvokeDynamic &&
225 dominator.isCallOnInterceptor(compiler) && 225 dominator.isCallOnInterceptor(closedWorld) &&
226 node == dominator.receiver && 226 node == dominator.receiver &&
227 useCount(dominator, node) == 1) { 227 useCount(dominator, node) == 1) {
228 interceptedClasses = 228 interceptedClasses =
229 backend.getInterceptedClassesOn(dominator.selector.name); 229 backend.getInterceptedClassesOn(dominator.selector.name);
230 230
231 // If we found that we need number, we must still go through all 231 // If we found that we need number, we must still go through all
232 // uses to check if they require int, or double. 232 // uses to check if they require int, or double.
233 if (interceptedClasses.contains(helpers.jsNumberClass) && 233 if (interceptedClasses.contains(backendClasses.numImplementation) &&
234 !(interceptedClasses.contains(helpers.jsDoubleClass) || 234 !(interceptedClasses.contains(backendClasses.doubleImplementation) ||
235 interceptedClasses.contains(helpers.jsIntClass))) { 235 interceptedClasses.contains(backendClasses.intImplementation))) {
236 Set<ClassElement> required; 236 Set<ClassElement> required;
237 for (HInstruction user in node.usedBy) { 237 for (HInstruction user in node.usedBy) {
238 if (user is! HInvoke) continue; 238 if (user is! HInvoke) continue;
239 Set<ClassElement> intercepted = 239 Set<ClassElement> intercepted =
240 backend.getInterceptedClassesOn(user.selector.name); 240 backend.getInterceptedClassesOn(user.selector.name);
241 if (intercepted.contains(helpers.jsIntClass)) { 241 if (intercepted.contains(backendClasses.intImplementation)) {
242 required ??= new Set<ClassElement>(); 242 required ??= new Set<ClassElement>();
243 required.add(helpers.jsIntClass); 243 required.add(backendClasses.intImplementation);
244 } 244 }
245 if (intercepted.contains(helpers.jsDoubleClass)) { 245 if (intercepted.contains(backendClasses.doubleImplementation)) {
246 required ??= new Set<ClassElement>(); 246 required ??= new Set<ClassElement>();
247 required.add(helpers.jsDoubleClass); 247 required.add(backendClasses.doubleImplementation);
248 } 248 }
249 } 249 }
250 // Don't modify the result of [backend.getInterceptedClassesOn]. 250 // Don't modify the result of [backend.getInterceptedClassesOn].
251 if (required != null) { 251 if (required != null) {
252 interceptedClasses = interceptedClasses.union(required); 252 interceptedClasses = interceptedClasses.union(required);
253 } 253 }
254 } 254 }
255 } else { 255 } else {
256 interceptedClasses = new Set<ClassElement>(); 256 interceptedClasses = new Set<ClassElement>();
257 for (HInstruction user in node.usedBy) { 257 for (HInstruction user in node.usedBy) {
258 if (user is HInvokeDynamic && 258 if (user is HInvokeDynamic &&
259 user.isCallOnInterceptor(compiler) && 259 user.isCallOnInterceptor(closedWorld) &&
260 node == user.receiver && 260 node == user.receiver &&
261 useCount(user, node) == 1) { 261 useCount(user, node) == 1) {
262 interceptedClasses 262 interceptedClasses
263 .addAll(backend.getInterceptedClassesOn(user.selector.name)); 263 .addAll(backend.getInterceptedClassesOn(user.selector.name));
264 } else if (user is HInvokeSuper && 264 } else if (user is HInvokeSuper &&
265 user.isCallOnInterceptor(compiler) && 265 user.isCallOnInterceptor(closedWorld) &&
266 node == user.receiver && 266 node == user.receiver &&
267 useCount(user, node) == 1) { 267 useCount(user, node) == 1) {
268 interceptedClasses 268 interceptedClasses
269 .addAll(backend.getInterceptedClassesOn(user.selector.name)); 269 .addAll(backend.getInterceptedClassesOn(user.selector.name));
270 } else { 270 } else {
271 // Use a most general interceptor for other instructions, example, 271 // Use a most general interceptor for other instructions, example,
272 // is-checks and escaping interceptors. 272 // is-checks and escaping interceptors.
273 interceptedClasses.addAll(backend.interceptedClasses); 273 interceptedClasses.addAll(backend.interceptedClasses);
274 break; 274 break;
275 } 275 }
(...skipping 27 matching lines...) Expand all
303 // If it is a conditional constant interceptor and was not strengthened to a 303 // If it is a conditional constant interceptor and was not strengthened to a
304 // constant interceptor then there is nothing more we can do. 304 // constant interceptor then there is nothing more we can do.
305 if (node.isConditionalConstantInterceptor) return false; 305 if (node.isConditionalConstantInterceptor) return false;
306 306
307 // Do we have an 'almost constant' interceptor? The receiver could be 307 // Do we have an 'almost constant' interceptor? The receiver could be
308 // `null` but not any other JavaScript falsy value, `null` values cause 308 // `null` but not any other JavaScript falsy value, `null` values cause
309 // `NoSuchMethodError`s, and if the receiver was not null we would have a 309 // `NoSuchMethodError`s, and if the receiver was not null we would have a
310 // constant interceptor `C`. Then we can use `(receiver && C)` for the 310 // constant interceptor `C`. Then we can use `(receiver && C)` for the
311 // interceptor. 311 // interceptor.
312 if (receiver.canBeNull()) { 312 if (receiver.canBeNull()) {
313 if (!interceptedClasses.contains(helpers.jsNullClass)) { 313 if (!interceptedClasses.contains(backendClasses.nullImplementation)) {
314 // Can use `(receiver && C)` only if receiver is either null or truthy. 314 // Can use `(receiver && C)` only if receiver is either null or truthy.
315 if (!(receiver.canBePrimitiveNumber(closedWorld) || 315 if (!(receiver.canBePrimitiveNumber(closedWorld) ||
316 receiver.canBePrimitiveBoolean(closedWorld) || 316 receiver.canBePrimitiveBoolean(closedWorld) ||
317 receiver.canBePrimitiveString(closedWorld))) { 317 receiver.canBePrimitiveString(closedWorld))) {
318 ClassElement interceptorClass = tryComputeConstantInterceptorFromType( 318 ClassElement interceptorClass = tryComputeConstantInterceptorFromType(
319 receiver.instructionType.nonNullable(), interceptedClasses); 319 receiver.instructionType.nonNullable(), interceptedClasses);
320 if (interceptorClass != null) { 320 if (interceptorClass != null) {
321 HInstruction constantInstruction = graph.addConstant( 321 HInstruction constantInstruction = graph.addConstant(
322 new InterceptorConstantValue(interceptorClass.thisType), 322 new InterceptorConstantValue(interceptorClass.thisType),
323 compiler); 323 compiler);
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
419 instruction = new HInvokeDynamicMethod( 419 instruction = new HInvokeDynamicMethod(
420 selector, mask, inputs, node.instructionType, true); 420 selector, mask, inputs, node.instructionType, true);
421 } 421 }
422 422
423 HBasicBlock block = node.block; 423 HBasicBlock block = node.block;
424 block.addAfter(node, instruction); 424 block.addAfter(node, instruction);
425 block.rewrite(node, instruction); 425 block.rewrite(node, instruction);
426 return true; 426 return true;
427 } 427 }
428 } 428 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/ssa/graph_builder.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