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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/ssa/bailout.dart

Issue 14404004: Throw NoSuchMethod or ArgumentError instead of generating a bailout, when we know the next instruct… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 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
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 class BailoutInfo { 7 class BailoutInfo {
8 int instructionId; 8 int instructionId;
9 int bailoutId; 9 int bailoutId;
10 BailoutInfo(this.instructionId, this.bailoutId); 10 BailoutInfo(this.instructionId, this.bailoutId);
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 * Visits the graph in dominator order and inserts TypeGuards in places where 60 * Visits the graph in dominator order and inserts TypeGuards in places where
61 * we consider the guard to be of value. This phase also does type 61 * we consider the guard to be of value. This phase also does type
62 * propagation to help find valuable type guards. 62 * propagation to help find valuable type guards.
63 */ 63 */
64 class SsaTypeGuardInserter extends SsaNonSpeculativeTypePropagator 64 class SsaTypeGuardInserter extends SsaNonSpeculativeTypePropagator
65 implements OptimizationPhase { 65 implements OptimizationPhase {
66 final String name = 'SsaTypeGuardInserter'; 66 final String name = 'SsaTypeGuardInserter';
67 final CodegenWorkItem work; 67 final CodegenWorkItem work;
68 bool calledInLoop = false; 68 bool calledInLoop = false;
69 bool isRecursiveMethod = false; 69 bool isRecursiveMethod = false;
70 bool hasInsertedChecks = false;
70 int stateId = 1; 71 int stateId = 1;
71 Map<HInstruction, HType> savedTypes = new Map<HInstruction, HType>(); 72 Map<HInstruction, HType> savedTypes = new Map<HInstruction, HType>();
72 73
73 SsaTypeGuardInserter(compiler, this.work) : super(compiler); 74 SsaTypeGuardInserter(compiler, this.work) : super(compiler);
74 75
75 void visitGraph(HGraph graph) { 76 void visitGraph(HGraph graph) {
76 // Run the speculative type propagator. This does in-place 77 // Run the speculative type propagator. This does in-place
77 // update of the type of the instructions, and saves the 78 // update of the type of the instructions, and saves the
78 // previous types in the [savedTypes] map. 79 // previous types in the [savedTypes] map.
79 SsaTypePropagator propagator = 80 SsaTypePropagator propagator =
(...skipping 26 matching lines...) Expand all
106 } 107 }
107 108
108 // Primitive types that are not null are valuable. These include 109 // Primitive types that are not null are valuable. These include
109 // indexable arrays. 110 // indexable arrays.
110 bool typeValuable(HType type) { 111 bool typeValuable(HType type) {
111 return type.isPrimitive() && !type.isNull(); 112 return type.isPrimitive() && !type.isNull();
112 } 113 }
113 114
114 bool get hasTypeGuards => work.guards.length != 0; 115 bool get hasTypeGuards => work.guards.length != 0;
115 116
117 bool isUsedWithIncompatibleSelector(HInstruction instruction,
118 HType speculativeType) {
119 for (HInstruction user in instruction.usedBy) {
120 if (user is HCheck
121 && isUsedWithIncompatibleSelector(user, speculativeType)) {
122 return true;
123 } else if (user.selector != null
124 && user.getDartReceiver(compiler) == instruction
125 && !speculativeType.computeMask(compiler).willHit(
126 user.selector, compiler)) {
127 print('$speculativeType and ${user.selector} disagree');
128 return true;
129 }
130 }
131 return false;
132 }
133
116 bool typeGuardWouldBeValuable(HInstruction instruction, 134 bool typeGuardWouldBeValuable(HInstruction instruction,
117 HType speculativeType) { 135 HType speculativeType) {
118 // If the type itself is not valuable, do not generate a guard for it. 136 // If the type itself is not valuable, do not generate a guard for it.
119 if (!typeValuable(speculativeType)) return false; 137 if (!typeValuable(speculativeType)) return false;
120 138
121 // Do not insert a type guard if the instruction has a type 139 // Do not insert a type guard if the instruction has a type
122 // annotation that disagrees with the speculated type. 140 // annotation that disagrees with the speculated type.
123 Element source = instruction.sourceElement; 141 Element source = instruction.sourceElement;
124 if (source != null) { 142 if (source != null) {
125 DartType sourceType = source.computeType(compiler); 143 DartType sourceType = source.computeType(compiler);
126 if (!sourceType.isMalformed && !sourceType.isDynamic && 144 if (!sourceType.isMalformed && !sourceType.isDynamic &&
127 sourceType.kind == TypeKind.INTERFACE) { 145 sourceType.kind == TypeKind.INTERFACE) {
128 TypeMask sourceMask = new TypeMask.subtype(sourceType); 146 TypeMask sourceMask = new TypeMask.subtype(sourceType);
129 TypeMask speculatedMask = speculativeType.computeMask(compiler); 147 TypeMask speculatedMask = speculativeType.computeMask(compiler);
130 if (sourceMask.intersection(speculatedMask, compiler).isEmpty) { 148 if (sourceMask.intersection(speculatedMask, compiler).isEmpty) {
131 return false; 149 return false;
132 } 150 }
133 } 151 }
134 } 152 }
135 153
154 // Do not insert a type guard if one of the calls on it will hit
155 // [NoSuchMethodError].
156 if (isUsedWithIncompatibleSelector(instruction, speculativeType)) {
157 return false;
158 }
159
136 // Insert type guards for recursive methods. 160 // Insert type guards for recursive methods.
137 if (isRecursiveMethod) return true; 161 if (isRecursiveMethod) return true;
138 162
139 // Insert type guards if there are uses in loops. 163 // Insert type guards if there are uses in loops.
140 bool isNested(HBasicBlock inner, HBasicBlock outer) { 164 bool isNested(HBasicBlock inner, HBasicBlock outer) {
141 if (identical(inner, outer)) return false; 165 if (identical(inner, outer)) return false;
142 if (outer == null) return true; 166 if (outer == null) return true;
143 while (inner != null) { 167 while (inner != null) {
144 if (identical(inner, outer)) return true; 168 if (identical(inner, outer)) return true;
145 inner = inner.parentLoopHeader; 169 inner = inner.parentLoopHeader;
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 && typeGuardWouldBeValuable(user, speculativeType)) { 207 && typeGuardWouldBeValuable(user, speculativeType)) {
184 return true; 208 return true;
185 } 209 }
186 } 210 }
187 211
188 // Insert type guards if the method is likely to be called in a 212 // Insert type guards if the method is likely to be called in a
189 // loop. 213 // loop.
190 return calledInLoop; 214 return calledInLoop;
191 } 215 }
192 216
217 // Returns whether an invocation of [selector] on [receiver] will throw a
218 // [ArgumentError] if the argument is not of the right type.
219 bool willThrowArgumentError(Selector selector, HInstruction receiver) {
220 if (receiver != null && (receiver.isInteger() || receiver.isString())) {
221 return selector.isOperator() && selector.name != const SourceString('==');
222 }
223 return false;
224 }
225
226 // Returns whether an invocation of [selector] will throw a
227 // [NoSuchMethodError] if the receiver is not of the type
228 // [speculativeType].
229 bool willThrowNoSuchMethodErrorIfNot(Selector selector,
230 HType speculativeType) {
231 return compiler.world.hasSingleMatch(selector)
232 // In some cases, we want the receiver to be an integer,
233 // but that does not mean we will get a NoSuchMethodError
234 // if it's not: the receiver could be a double.
235 && !speculativeType.isInteger()
236 // We speculate on the [operator==] instruction, but we know it
237 // will never throw a [NoSuchMethodError].
238 && selector.name != const SourceString('==');
239 }
240
193 bool shouldInsertTypeGuard(HInstruction instruction, HType speculativeType) { 241 bool shouldInsertTypeGuard(HInstruction instruction, HType speculativeType) {
194 if (!speculativeType.isUseful()) return false; 242 if (!speculativeType.isUseful()) return false;
195 // If the types agree we don't need to check. 243 // If the types agree we don't need to check.
196 if (speculativeType == instruction.instructionType) return false; 244 if (speculativeType == instruction.instructionType) return false;
197 // If a bailout check is more expensive than doing the actual operation 245 // If a bailout check is more expensive than doing the actual operation
198 // don't do it either. 246 // don't do it either.
199 return typeGuardWouldBeValuable(instruction, speculativeType); 247 return typeGuardWouldBeValuable(instruction, speculativeType);
200 } 248 }
201 249
250 HInstruction computeFirstDominatingUserWithSelector(
251 HInstruction instruction) {
252 // TODO(ngeoffray): We currently only look at the instruction's
253 // block, so that we know it will be executed. We should lift this
254 // limitation.
255
256 // For a parameter, we look at the first block that contains
257 // user instructions.
258 HBasicBlock userMustBeInBlock = instruction is HParameterValue
259 ? instruction.block.successors[0]
260 : instruction.block;
261
262 HInstruction firstUser;
263 for (HInstruction user in instruction.usedBy) {
264 if (user.block == userMustBeInBlock && user.selector != null) {
265 if (firstUser == null || user.dominates(firstUser)) {
266 firstUser = user;
267 }
268 }
269 }
270 return firstUser;
271 }
272
273 /**
274 * Tries to insert a type conversion instruction for [instruction]
275 * instead of a type guard if we know an user will throw. Returns
276 * whether it succeeded at adding a type conversion instruction.
277 */
278 bool tryTypeConversion(HInstruction instruction, HType speculativeType) {
279 HInstruction firstUser =
280 computeFirstDominatingUserWithSelector(instruction);
281 if (firstUser == null) return false;
282
283 // If we have found a user with a selector, we find out if it
284 // will throw [NoSuchMethodError] or [ArgumentError].
285 Selector selector = firstUser.selector;
286 Selector receiverSelectorOnThrow = null;
287 HInstruction receiver = firstUser.getDartReceiver(compiler);
288 bool willThrow = false;
289 if (receiver == instruction) {
290 if (willThrowNoSuchMethodErrorIfNot(selector, speculativeType)) {
291 receiverSelectorOnThrow = selector;
292 willThrow = true;
293 }
294 } else if (willThrowArgumentError(selector, receiver)) {
295 willThrow = true;
296 }
297
298 if (!willThrow) return false;
299
300 HTypeConversion check = new HTypeConversion(
301 null,
302 receiverSelectorOnThrow == null
303 ? HTypeConversion.ARGUMENT_TYPE_CHECK
304 : HTypeConversion.RECEIVER_TYPE_CHECK,
305 speculativeType,
306 instruction,
307 receiverSelectorOnThrow);
308 hasInsertedChecks = true;
309 firstUser.block.addBefore(firstUser, check);
310 instruction.replaceAllUsersDominatedBy(firstUser, check);
311 return true;
312 }
313
202 bool updateType(HInstruction instruction) { 314 bool updateType(HInstruction instruction) {
203 bool hasChanged = super.updateType(instruction); 315 bool hasChanged = super.updateType(instruction);
204 HType speculativeType = savedTypes[instruction]; 316 HType speculativeType = savedTypes[instruction];
205 if (speculativeType == null) return hasChanged; 317 if (speculativeType == null) return hasChanged;
206 318
207 if (shouldInsertTypeGuard(instruction, speculativeType)) { 319 if (shouldInsertTypeGuard(instruction, speculativeType)
320 && !tryTypeConversion(instruction, speculativeType)) {
208 HInstruction insertionPoint; 321 HInstruction insertionPoint;
209 if (instruction is HPhi) { 322 if (instruction is HPhi) {
210 insertionPoint = instruction.block.first; 323 insertionPoint = instruction.block.first;
211 } else if (instruction is HParameterValue) { 324 } else if (instruction is HParameterValue) {
212 // We insert the type guard at the end of the entry block 325 // We insert the type guard at the end of the entry block
213 // because if a parameter is live, it must be kept in the live 326 // because if a parameter is live, it must be kept in the live
214 // environment. Not doing so would mean we could visit a 327 // environment. Not doing so would mean we could visit a
215 // parameter and remove it from the environment before 328 // parameter and remove it from the environment before
216 // visiting a type guard. 329 // visiting a type guard.
217 insertionPoint = instruction.block.last; 330 insertionPoint = instruction.block.last;
(...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 hasComplexBailoutTargets = true; 733 hasComplexBailoutTargets = true;
621 } 734 }
622 } else { 735 } else {
623 hasComplexBailoutTargets = true; 736 hasComplexBailoutTargets = true;
624 blocks.forEach((HBasicBlock block) { 737 blocks.forEach((HBasicBlock block) {
625 block.bailoutTargets.add(target); 738 block.bailoutTargets.add(target);
626 }); 739 });
627 } 740 }
628 } 741 }
629 } 742 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698