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

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

Issue 1058433003: "Redo "Avoid getInterceptor calls in cases were the interceptor would be constant if it were not `n… (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 8 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 | Annotate | Revision Log
« no previous file with comments | « pkg/compiler/lib/src/ssa/codegen.dart ('k') | pkg/compiler/lib/src/ssa/nodes.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 HInstruction tryComputeConstantInterceptor( 103 HInstruction tryComputeConstantInterceptor(
104 HInstruction input, 104 HInstruction input,
105 Set<ClassElement> interceptedClasses) { 105 Set<ClassElement> interceptedClasses) {
106 if (input == graph.explicitReceiverParameter) { 106 if (input == graph.explicitReceiverParameter) {
107 // If `explicitReceiverParameter` is set it means the current method is an 107 // If `explicitReceiverParameter` is set it means the current method is an
108 // interceptor method, and `this` is the interceptor. The caller just did 108 // interceptor method, and `this` is the interceptor. The caller just did
109 // `getInterceptor(foo).currentMethod(foo)` to enter the current method. 109 // `getInterceptor(foo).currentMethod(foo)` to enter the current method.
110 return graph.thisInstruction; 110 return graph.thisInstruction;
111 } 111 }
112 112
113 ClassElement constantInterceptor; 113 ClassElement constantInterceptor = tryComputeConstantInterceptorFromType(
114 input.instructionType, interceptedClasses);
115
116 if (constantInterceptor == null) return null;
117
118 // If we just happen to be in an instance method of the constant
119 // interceptor, `this` is a shorter alias.
120 if (constantInterceptor == work.element.enclosingClass &&
121 graph.thisInstruction != null) {
122 return graph.thisInstruction;
123 }
124
125 ConstantValue constant =
126 new InterceptorConstantValue(constantInterceptor.thisType);
127 return graph.addConstant(constant, compiler);
128 }
129
130 ClassElement tryComputeConstantInterceptorFromType(
131 TypeMask type,
132 Set<ClassElement> interceptedClasses) {
133
114 ClassWorld classWorld = compiler.world; 134 ClassWorld classWorld = compiler.world;
115 JavaScriptBackend backend = compiler.backend; 135 JavaScriptBackend backend = compiler.backend;
116 if (input.canBeNull()) { 136 if (type.isNullable) {
117 if (input.isNull()) { 137 if (type.isEmpty) {
118 constantInterceptor = backend.jsNullClass; 138 return backend.jsNullClass;
119 } 139 }
120 } else if (input.isInteger(compiler)) { 140 } else if (type.containsOnlyInt(classWorld)) {
121 constantInterceptor = backend.jsIntClass; 141 return backend.jsIntClass;
122 } else if (input.isDouble(compiler)) { 142 } else if (type.containsOnlyDouble(classWorld)) {
123 constantInterceptor = backend.jsDoubleClass; 143 return backend.jsDoubleClass;
124 } else if (input.isBoolean(compiler)) { 144 } else if (type.containsOnlyBool(classWorld)) {
125 constantInterceptor = backend.jsBoolClass; 145 return backend.jsBoolClass;
126 } else if (input.isString(compiler)) { 146 } else if (type.containsOnlyString(classWorld)) {
127 constantInterceptor = backend.jsStringClass; 147 return backend.jsStringClass;
128 } else if (input.isArray(compiler)) { 148 } else if (type.satisfies(backend.jsArrayClass, classWorld)) {
129 constantInterceptor = backend.jsArrayClass; 149 return backend.jsArrayClass;
130 } else if (input.isNumber(compiler) && 150 } else if (type.containsOnlyNum(classWorld) &&
131 !interceptedClasses.contains(backend.jsIntClass) && 151 !interceptedClasses.contains(backend.jsIntClass) &&
132 !interceptedClasses.contains(backend.jsDoubleClass)) { 152 !interceptedClasses.contains(backend.jsDoubleClass)) {
133 // If the method being intercepted is not defined in [int] or [double] we 153 // If the method being intercepted is not defined in [int] or [double] we
134 // can safely use the number interceptor. This is because none of the 154 // can safely use the number interceptor. This is because none of the
135 // [int] or [double] methods are called from a method defined on [num]. 155 // [int] or [double] methods are called from a method defined on [num].
136 constantInterceptor = backend.jsNumberClass; 156 return backend.jsNumberClass;
137 } else { 157 } else {
138 // Try to find constant interceptor for a native class. If the receiver 158 // Try to find constant interceptor for a native class. If the receiver
139 // is constrained to a leaf native class, we can use the class's 159 // is constrained to a leaf native class, we can use the class's
140 // interceptor directly. 160 // interceptor directly.
141 161
142 // TODO(sra): Key DOM classes like Node, Element and Event are not leaf 162 // TODO(sra): Key DOM classes like Node, Element and Event are not leaf
143 // classes. When the receiver type is not a leaf class, we might still be 163 // classes. When the receiver type is not a leaf class, we might still be
144 // able to use the receiver class as a constant interceptor. It is 164 // able to use the receiver class as a constant interceptor. It is
145 // usually the case that methods defined on a non-leaf class don't test 165 // usually the case that methods defined on a non-leaf class don't test
146 // for a subclass or call methods defined on a subclass. Provided the 166 // for a subclass or call methods defined on a subclass. Provided the
147 // code is completely insensitive to the specific instance subclasses, we 167 // code is completely insensitive to the specific instance subclasses, we
148 // can use the non-leaf class directly. 168 // can use the non-leaf class directly.
149 ClassElement element = input.instructionType.singleClass(classWorld); 169 ClassElement element = type.singleClass(classWorld);
150 if (element != null && element.isNative) { 170 if (element != null && element.isNative) {
151 constantInterceptor = element; 171 return element;
152 } 172 }
153 } 173 }
154 174
155 if (constantInterceptor == null) return null; 175 return null;
156
157 // If we just happen to be in an instance method of the constant
158 // interceptor, `this` is a shorter alias.
159 if (constantInterceptor == work.element.enclosingClass &&
160 graph.thisInstruction != null) {
161 return graph.thisInstruction;
162 }
163
164 ConstantValue constant =
165 new InterceptorConstantValue(constantInterceptor.thisType);
166 return graph.addConstant(constant, compiler);
167 } 176 }
168 177
169 HInstruction findDominator(Iterable<HInstruction> instructions) { 178 HInstruction findDominator(Iterable<HInstruction> instructions) {
170 HInstruction result; 179 HInstruction result;
171 L1: for (HInstruction candidate in instructions) { 180 L1: for (HInstruction candidate in instructions) {
172 for (HInstruction current in instructions) { 181 for (HInstruction current in instructions) {
173 if (current != candidate && !candidate.dominates(current)) continue L1; 182 if (current != candidate && !candidate.dominates(current)) continue L1;
174 } 183 }
175 result = candidate; 184 result = candidate;
176 break; 185 break;
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 } 278 }
270 279
271 // Try computing a constant interceptor. 280 // Try computing a constant interceptor.
272 HInstruction constantInterceptor = 281 HInstruction constantInterceptor =
273 tryComputeConstantInterceptor(receiver, interceptedClasses); 282 tryComputeConstantInterceptor(receiver, interceptedClasses);
274 if (constantInterceptor != null) { 283 if (constantInterceptor != null) {
275 node.block.rewrite(node, constantInterceptor); 284 node.block.rewrite(node, constantInterceptor);
276 return false; 285 return false;
277 } 286 }
278 287
288 // Do we have an 'almost constant' interceptor? The receiver could be
289 // `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 // constant interceptor `C`. Then we can use `(receiver && C)` for the
292 // interceptor.
293 if (receiver.canBeNull() && !node.isConditionalConstantInterceptor) {
294 if (!interceptedClasses.contains(backend.jsNullClass)) {
295 // Can use `(receiver && C)` only if receiver is either null or truthy.
296 if (!(receiver.canBePrimitiveNumber(compiler) ||
297 receiver.canBePrimitiveBoolean(compiler) ||
298 receiver.canBePrimitiveString(compiler))) {
299 ClassElement interceptorClass = tryComputeConstantInterceptorFromType(
300 receiver.instructionType.nonNullable(), interceptedClasses);
301 if (interceptorClass != null) {
302 HInstruction constantInstruction =
303 graph.addConstant(
304 new InterceptorConstantValue(interceptorClass.thisType),
305 compiler);
306 node.conditionalConstantInterceptor = constantInstruction;
307 constantInstruction.usedBy.add(node);
308 return false;
309 }
310 }
311 }
312 }
313
279 // Try creating a one-shot interceptor or optimized is-check 314 // Try creating a one-shot interceptor or optimized is-check
280 if (compiler.hasIncrementalSupport) return false; 315 if (compiler.hasIncrementalSupport) return false;
281 if (node.usedBy.length != 1) return false; 316 if (node.usedBy.length != 1) return false;
282 HInstruction user = node.usedBy.single; 317 HInstruction user = node.usedBy.single;
283 318
284 // If the interceptor [node] was loop hoisted, we keep the interceptor. 319 // If the interceptor [node] was loop hoisted, we keep the interceptor.
285 if (!user.hasSameLoopHeaderAs(node)) return false; 320 if (!user.hasSameLoopHeaderAs(node)) return false;
286 321
287 bool replaceUserWith(HInstruction replacement) { 322 bool replaceUserWith(HInstruction replacement) {
288 HBasicBlock block = user.block; 323 HBasicBlock block = user.block;
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 instruction = new HInvokeDynamicMethod( 399 instruction = new HInvokeDynamicMethod(
365 selector, inputs, node.instructionType, true); 400 selector, inputs, node.instructionType, true);
366 } 401 }
367 402
368 HBasicBlock block = node.block; 403 HBasicBlock block = node.block;
369 block.addAfter(node, instruction); 404 block.addAfter(node, instruction);
370 block.rewrite(node, instruction); 405 block.rewrite(node, instruction);
371 return true; 406 return true;
372 } 407 }
373 } 408 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/ssa/codegen.dart ('k') | pkg/compiler/lib/src/ssa/nodes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698