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

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
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/implementation/ssa/builder.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) 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 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 && typeGuardWouldBeValuable(user, speculativeType)) { 184 && typeGuardWouldBeValuable(user, speculativeType)) {
184 return true; 185 return true;
185 } 186 }
186 } 187 }
187 188
188 // Insert type guards if the method is likely to be called in a 189 // Insert type guards if the method is likely to be called in a
189 // loop. 190 // loop.
190 return calledInLoop; 191 return calledInLoop;
191 } 192 }
192 193
194 // Returns whether an invocation of [selector] on [receiver] will throw a
195 // [ArgumentError] if the argument is not of the right type.
196 bool willThrowArgumentError(Selector selector, HInstruction receiver) {
197 if (receiver != null && (receiver.isInteger() || receiver.isString())) {
198 return selector.isOperator() && selector.name != const SourceString('==');
199 }
200 return false;
201 }
202
203 // Returns whether an invocation of [selector] will throw a
204 // [NoSuchMethodError] if the receiver is not of the type
205 // [speculativeType].
206 bool willThrowNoSuchMethodErrorIfNot(Selector selector,
207 HType speculativeType) {
208 return compiler.world.hasSingleMatch(selector)
209 // In some cases, we want the receiver to be an integer,
210 // but that does not mean we will get a NoSuchMethodError
211 // if it's not: the receiver could be a double.
212 && !speculativeType.isInteger()
213 // We speculate on the [operator==] instruction, but we know it
214 // will never throw a [NoSuchMethodError].
215 && selector.name != const SourceString('==');
216 }
217
193 bool shouldInsertTypeGuard(HInstruction instruction, HType speculativeType) { 218 bool shouldInsertTypeGuard(HInstruction instruction, HType speculativeType) {
194 if (!speculativeType.isUseful()) return false; 219 if (!speculativeType.isUseful()) return false;
195 // If the types agree we don't need to check. 220 // If the types agree we don't need to check.
196 if (speculativeType == instruction.instructionType) return false; 221 if (speculativeType == instruction.instructionType) return false;
197 // If a bailout check is more expensive than doing the actual operation 222 // If a bailout check is more expensive than doing the actual operation
198 // don't do it either. 223 // don't do it either.
199 return typeGuardWouldBeValuable(instruction, speculativeType); 224 return typeGuardWouldBeValuable(instruction, speculativeType);
200 } 225 }
201 226
227 HInstruction computeFirstDominatingUserWithSelector(
228 HInstruction instruction) {
229 // TODO(ngeoffray): We currently only look at the instruction's
230 // block, so that we know it will be executed. We should lift this
231 // limitation.
232
233 // (meaning it will be a call), we can put a type check instead
kasperl 2013/04/23 09:01:43 This comment seems a little incomplete.
ngeoffray 2013/04/23 11:00:56 Wrong copy/paste. Removed the line.
234 // For a parameter, we look at the first block that contains
235 // user instructions.
236 HBasicBlock userMustBeInBlock = instruction is HParameterValue
237 ? instruction.block.successors[0]
238 : instruction.block;
239
240 HInstruction firstUser;
241 for (HInstruction user in instruction.usedBy) {
242 if (user.block == userMustBeInBlock && user.selector != null) {
243 if (firstUser == null || user.dominates(firstUser)) {
244 firstUser = user;
245 }
246 }
247 }
248 return firstUser;
249 }
250
251 /**
252 * Tries to insert a type conversion instruction for [instruction]
253 * instead of a type guard if we know an user will throw. Returns
254 * whether it succeeded at adding a type conversion instruction.
255 */
256 bool tryTypeConversion(HInstruction instruction, HType speculativeType) {
257 HInstruction firstUser =
258 computeFirstDominatingUserWithSelector(instruction);
259 if (firstUser == null) return false;
260
261 // If we have found a user with a selector, we find out if it
262 // will throw [NoSuchMethodError] or [ArgumentError].
263 Selector selector = firstUser.selector;
264 Selector receiverSelectorOnThrow = null;
265 HInstruction receiver = firstUser.getDartReceiver(compiler);
266 bool willThrow = false;
267 if (receiver == instruction) {
268 if (willThrowNoSuchMethodErrorIfNot(selector, speculativeType)) {
269 receiverSelectorOnThrow = selector;
270 willThrow = true;
271 }
272 } else if (willThrowArgumentError(selector, receiver)) {
273 willThrow = true;
274 }
275
276 if (!willThrow) return false;
277
278 HTypeConversion check = new HTypeConversion(
279 null,
280 receiverSelectorOnThrow == null
281 ? HTypeConversion.ARGUMENT_TYPE_CHECK
282 : HTypeConversion.RECEIVER_TYPE_CHECK,
283 speculativeType,
284 instruction,
285 receiverSelectorOnThrow);
286 hasInsertedChecks = true;
287 firstUser.block.addBefore(firstUser, check);
288 instruction.replaceAllUsersDominatedBy(firstUser, check);
289 return true;
290 }
291
202 bool updateType(HInstruction instruction) { 292 bool updateType(HInstruction instruction) {
203 bool hasChanged = super.updateType(instruction); 293 bool hasChanged = super.updateType(instruction);
204 HType speculativeType = savedTypes[instruction]; 294 HType speculativeType = savedTypes[instruction];
205 if (speculativeType == null) return hasChanged; 295 if (speculativeType == null) return hasChanged;
206 296
207 if (shouldInsertTypeGuard(instruction, speculativeType)) { 297 if (shouldInsertTypeGuard(instruction, speculativeType)
298 && !tryTypeConversion(instruction, speculativeType)) {
208 HInstruction insertionPoint; 299 HInstruction insertionPoint;
209 if (instruction is HPhi) { 300 if (instruction is HPhi) {
210 insertionPoint = instruction.block.first; 301 insertionPoint = instruction.block.first;
211 } else if (instruction is HParameterValue) { 302 } else if (instruction is HParameterValue) {
212 // We insert the type guard at the end of the entry block 303 // 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 304 // because if a parameter is live, it must be kept in the live
214 // environment. Not doing so would mean we could visit a 305 // environment. Not doing so would mean we could visit a
215 // parameter and remove it from the environment before 306 // parameter and remove it from the environment before
216 // visiting a type guard. 307 // visiting a type guard.
217 insertionPoint = instruction.block.last; 308 insertionPoint = instruction.block.last;
218 } else { 309 } else {
219 insertionPoint = instruction.next; 310 insertionPoint = instruction.next;
220 } 311 }
221 // If the previous instruction is also a type guard, then both 312 // If the previous instruction is also a type guard, then both
222 // guards have the same environment, and can therefore share the 313 // guards have the same environment, and can therefore share the
223 // same state id. 314 // same state id.
224 HBailoutTarget target; 315 HBailoutTarget target;
225 int state; 316 int state;
226 if (insertionPoint.previous is HTypeGuard) { 317 if (insertionPoint.previous is HTypeGuard) {
227 HTypeGuard other = insertionPoint.previous; 318 HTypeGuard other = insertionPoint.previous;
228 target = other.bailoutTarget; 319 target = other.bailoutTarget;
229 } else { 320 } else {
230 state = stateId++; 321 state = stateId++;
231 target = new HBailoutTarget(state); 322 target = new HBailoutTarget(state);
232 insertionPoint.block.addBefore(insertionPoint, target); 323 insertionPoint.block.addBefore(insertionPoint, target);
233 } 324 }
234 HTypeGuard guard = new HTypeGuard(speculativeType, instruction, target); 325 HTypeGuard check = new HTypeGuard(speculativeType, instruction, target);
kasperl 2013/04/23 09:01:43 Undo this change?
ngeoffray 2013/04/23 11:00:56 Done.
235 work.guards.add(guard); 326 work.guards.add(check);
236 // By setting the type of the guard to the speculated type, we 327 // By setting the type of the guard to the speculated type, we
237 // help the analysis find valuable type guards. This however 328 // help the analysis find valuable type guards. This however
238 // requires to run a non-speculative type propagation again 329 // requires to run a non-speculative type propagation again
239 // after this analysis. 330 // after this analysis.
240 guard.instructionType = speculativeType; 331 check.instructionType = speculativeType;
241 instruction.block.rewrite(instruction, guard); 332 instruction.block.rewrite(instruction, check);
242 insertionPoint.block.addBefore(insertionPoint, guard); 333 insertionPoint.block.addBefore(insertionPoint, check);
243 } 334 }
244 return hasChanged; 335 return hasChanged;
245 } 336 }
246 } 337 }
247 338
248 /** 339 /**
249 * Computes the environment for each SSA instruction: visits the graph 340 * Computes the environment for each SSA instruction: visits the graph
250 * in post-dominator order. Removes an instruction from the environment 341 * in post-dominator order. Removes an instruction from the environment
251 * and adds its inputs to the environment at the instruction's 342 * and adds its inputs to the environment at the instruction's
252 * definition. 343 * definition.
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 hasComplexBailoutTargets = true; 711 hasComplexBailoutTargets = true;
621 } 712 }
622 } else { 713 } else {
623 hasComplexBailoutTargets = true; 714 hasComplexBailoutTargets = true;
624 blocks.forEach((HBasicBlock block) { 715 blocks.forEach((HBasicBlock block) {
625 block.bailoutTargets.add(target); 716 block.bailoutTargets.add(target);
626 }); 717 });
627 } 718 }
628 } 719 }
629 } 720 }
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/implementation/ssa/builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698