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: lib/compiler/implementation/ssa/bailout.dart

Issue 10807069: Split TypeGuard and BailoutTarget. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebase. Created 8 years, 5 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 | lib/compiler/implementation/ssa/codegen.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 class BailoutInfo { 5 class BailoutInfo {
6 int instructionId; 6 int instructionId;
7 int bailoutId; 7 int bailoutId;
8 BailoutInfo(this.instructionId, this.bailoutId); 8 BailoutInfo(this.instructionId, this.bailoutId);
9 } 9 }
10 10
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
145 if (isNested(userLoopHeader, currentLoopHeader)) return true; 145 if (isNested(userLoopHeader, currentLoopHeader)) return true;
146 } 146 }
147 147
148 // To speed up computations on values loaded from arrays, we 148 // To speed up computations on values loaded from arrays, we
149 // insert type guards for builtin array indexing operations in 149 // insert type guards for builtin array indexing operations in
150 // nested loops. Since this can blow up code size quite 150 // nested loops. Since this can blow up code size quite
151 // significantly, we only do it if type guards have already been 151 // significantly, we only do it if type guards have already been
152 // inserted for this method. The code size price for an additional 152 // inserted for this method. The code size price for an additional
153 // type guard is much smaller than the first one that causes the 153 // type guard is much smaller than the first one that causes the
154 // generation of a bailout method. 154 // generation of a bailout method.
155 if (instruction is HIndex && instruction.builtin && hasTypeGuards) { 155 if (instruction is HIndex &&
156 (instruction as HIndex).builtin &&
157 hasTypeGuards) {
156 HBasicBlock loopHeader = instruction.block.enclosingLoopHeader; 158 HBasicBlock loopHeader = instruction.block.enclosingLoopHeader;
157 if (loopHeader != null && loopHeader.parentLoopHeader != null) { 159 if (loopHeader != null && loopHeader.parentLoopHeader != null) {
158 return true; 160 return true;
159 } 161 }
160 } 162 }
161 163
162 // Insert type guards if the method is likely to be called in a 164 // Insert type guards if the method is likely to be called in a
163 // loop. 165 // loop.
164 return calledInLoop; 166 return calledInLoop;
165 } 167 }
(...skipping 16 matching lines...) Expand all
182 // If the types agree we don't need to check. 184 // If the types agree we don't need to check.
183 if (speculativeType == computedType) return false; 185 if (speculativeType == computedType) return false;
184 // If a bailout check is more expensive than doing the actual operation 186 // If a bailout check is more expensive than doing the actual operation
185 // don't do it either. 187 // don't do it either.
186 return typeGuardWouldBeValuable(instruction, speculativeType); 188 return typeGuardWouldBeValuable(instruction, speculativeType);
187 } 189 }
188 190
189 void visitInstruction(HInstruction instruction) { 191 void visitInstruction(HInstruction instruction) {
190 HType speculativeType = instruction.propagatedType; 192 HType speculativeType = instruction.propagatedType;
191 if (shouldInsertTypeGuard(instruction)) { 193 if (shouldInsertTypeGuard(instruction)) {
192 List<HInstruction> inputs = <HInstruction>[instruction];
193 HInstruction insertionPoint; 194 HInstruction insertionPoint;
194 if (instruction is HPhi) { 195 if (instruction is HPhi) {
195 insertionPoint = instruction.block.first; 196 insertionPoint = instruction.block.first;
196 } else if (instruction is HParameterValue) { 197 } else if (instruction is HParameterValue) {
197 // We insert the type guard at the end of the entry block 198 // We insert the type guard at the end of the entry block
198 // because if a parameter is live, it must be kept in the live 199 // because if a parameter is live, it must be kept in the live
199 // environment. Not doing so would mean we could visit a 200 // environment. Not doing so would mean we could visit a
200 // parameter and remove it from the environment before 201 // parameter and remove it from the environment before
201 // visiting a type guard. 202 // visiting a type guard.
202 insertionPoint = instruction.block.last; 203 insertionPoint = instruction.block.last;
203 } else { 204 } else {
204 insertionPoint = instruction.next; 205 insertionPoint = instruction.next;
205 } 206 }
206 // If the previous instruction is also a type guard, then both 207 // If the previous instruction is also a type guard, then both
207 // guards have the same environment, and can therefore share the 208 // guards have the same environment, and can therefore share the
208 // same state id. 209 // same state id.
210 HBailoutTarget target;
209 int state; 211 int state;
210 if (insertionPoint.previous is HTypeGuard) { 212 if (insertionPoint.previous is HTypeGuard) {
211 HTypeGuard other = insertionPoint.previous; 213 HTypeGuard other = insertionPoint.previous;
212 state = other.state; 214 target = other.bailoutTarget;
213 } else { 215 } else {
214 state = stateId++; 216 state = stateId++;
217 target = new HBailoutTarget(state);
218 insertionPoint.block.addBefore(insertionPoint, target);
215 } 219 }
216 HTypeGuard guard = new HTypeGuard(speculativeType, state, inputs); 220 HTypeGuard guard = new HTypeGuard(speculativeType, instruction, target);
217 guard.propagatedType = speculativeType; 221 guard.propagatedType = speculativeType;
218 work.guards.add(guard); 222 work.guards.add(guard);
219 instruction.block.rewrite(instruction, guard); 223 instruction.block.rewrite(instruction, guard);
220 insertionPoint.block.addBefore(insertionPoint, guard); 224 insertionPoint.block.addBefore(insertionPoint, guard);
221 } 225 }
222 } 226 }
223 } 227 }
224 228
225 /** 229 /**
226 * Computes the environment for each SSA instruction: visits the graph 230 * Computes the environment for each SSA instruction: visits the graph
227 * in post-dominator order. Removes an instruction from the environment 231 * in post-dominator order. Removes an instruction from the environment
228 * and adds its inputs to the environment at the instruction's 232 * and adds its inputs to the environment at the instruction's
229 * definition. 233 * definition.
230 * 234 *
231 * At the end of the computation, insert type guards in the graph. 235 * At the end of the computation, insert type guards in the graph.
232 */ 236 */
233 class SsaEnvironmentBuilder extends HBaseVisitor implements OptimizationPhase { 237 class SsaEnvironmentBuilder extends HBaseVisitor implements OptimizationPhase {
234 final Compiler compiler; 238 final Compiler compiler;
235 final String name = 'SsaEnvironmentBuilder'; 239 final String name = 'SsaEnvironmentBuilder';
236 240
237 final Map<HInstruction, Environment> capturedEnvironments; 241 final Map<HBailoutTarget, Environment> capturedEnvironments;
238 final Map<HBasicBlock, Environment> liveInstructions; 242 final Map<HBasicBlock, Environment> liveInstructions;
239 Environment environment; 243 Environment environment;
240 244
241 SsaEnvironmentBuilder(Compiler this.compiler) 245 SsaEnvironmentBuilder(Compiler this.compiler)
242 : capturedEnvironments = new Map<HInstruction, Environment>(), 246 : capturedEnvironments = new Map<HBailoutTarget, Environment>(),
243 liveInstructions = new Map<HBasicBlock, Environment>(); 247 liveInstructions = new Map<HBasicBlock, Environment>();
244 248
245 249
246 void visitGraph(HGraph graph) { 250 void visitGraph(HGraph graph) {
247 visitPostDominatorTree(graph); 251 visitPostDominatorTree(graph);
248 if (!liveInstructions[graph.entry].isEmpty()) { 252 if (!liveInstructions[graph.entry].isEmpty()) {
249 compiler.internalError('Bailout environment computation', 253 compiler.internalError('Bailout environment computation',
250 node: compiler.currentElement.parseNode(compiler)); 254 node: compiler.currentElement.parseNode(compiler));
251 } 255 }
252 updateLoopMarkers(); 256 updateLoopMarkers();
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 // If the block is a loop header, we can remove the loop marker, 320 // If the block is a loop header, we can remove the loop marker,
317 // because it will just recompute the loop phis. 321 // because it will just recompute the loop phis.
318 if (block.isLoopHeader()) { 322 if (block.isLoopHeader()) {
319 environment.removeLoopMarker(block); 323 environment.removeLoopMarker(block);
320 } 324 }
321 325
322 // Finally save the liveInstructions of that block. 326 // Finally save the liveInstructions of that block.
323 liveInstructions[block] = environment; 327 liveInstructions[block] = environment;
324 } 328 }
325 329
326 void visitTypeGuard(HTypeGuard guard) { 330 void visitBailoutTarget(HBailoutTarget target) {
327 visitInstruction(guard); 331 visitInstruction(target);
328 capturedEnvironments[guard] = new Environment.from(environment); 332 capturedEnvironments[target] = new Environment.from(environment);
329 } 333 }
330 334
331 void visitInstruction(HInstruction instruction) { 335 void visitInstruction(HInstruction instruction) {
332 environment.remove(instruction); 336 environment.remove(instruction);
333 for (int i = 0, len = instruction.inputs.length; i < len; i++) { 337 for (int i = 0, len = instruction.inputs.length; i < len; i++) {
334 environment.add(instruction.inputs[i]); 338 environment.add(instruction.inputs[i]);
335 } 339 }
336 } 340 }
337 341
342 /**
343 * Stores all live variables in the bailout target and the guards.
344 */
338 void insertCapturedEnvironments() { 345 void insertCapturedEnvironments() {
339 Map<int, HTypeGuard> seenGuardStates = new Map<int, HTypeGuard>(); 346 capturedEnvironments.forEach((HBailoutTarget target, Environment env) {
340 capturedEnvironments.forEach((HTypeGuard guard, Environment env) { 347 assert(target.inputs.length == 0);
341 storeInGuard(guard, env.lives, seenGuardStates); 348 target.inputs.addAll(env.lives);
349 // TODO(floitsch): we should add the bailout-target's input variables
350 // as input to the guards only in the optimized version. The
351 // non-optimized version does not use the bailout guards and it is
352 // unnecessary to keep the variables alive until the check.
353 for (HTypeGuard guard in target.usedBy) {
354 // A type-guard initially only has two inputs: the guarded instruction
355 // and the bailout-target. Only after adding the environment is it
356 // allowed to have more inputs.
357 assert(guard.inputs.length == 2);
358 guard.inputs.addAll(env.lives);
359 }
360 for (HInstruction live in env.lives) {
361 live.usedBy.add(target);
362 live.usedBy.addAll(target.usedBy);
363 }
342 }); 364 });
343 } 365 }
344
345 /**
346 * Stores all live variables in the guard.
347 */
348 void storeInGuard(HTypeGuard guard,
349 Set<HInstruction> lives,
350 Map<int, HTypeGuard> seenGuardStates) {
351 HInstruction guarded = guard.guarded;
352 List<HInstruction> inputs = guard.inputs;
353 assert(inputs.length == 1);
354 inputs.clear();
355 HTypeGuard other = seenGuardStates[guard.state];
356 if (other !== null) {
357 // The guards are sharing the same state. Also share the same
358 // environment, in the same order.
359 inputs.addAll(other.inputs);
360 assert(inputs.length == lives.length);
361 } else {
362 seenGuardStates[guard.state] = guard;
363 inputs.addAll(lives);
364 }
365
366 for (int i = 0; i < inputs.length; i++) {
367 HInstruction input = inputs[i];
368 if (input == guarded) {
369 guard.checkedInputIndex = i;
370 // No need to update [input.usedBy], the guard is already
371 // there.
372 } else {
373 input.usedBy.add(guard);
374 }
375 }
376 }
377 } 366 }
378 367
379 /** 368 /**
380 * Propagates bailout information to blocks that need it. This visitor 369 * Propagates bailout information to blocks that need it. This visitor
381 * is run before codegen, to know which blocks have to deal with 370 * is run before codegen, to know which blocks have to deal with
382 * bailouts. 371 * bailouts.
383 */ 372 */
384 class SsaBailoutPropagator extends HBaseVisitor { 373 class SsaBailoutPropagator extends HBaseVisitor {
385 final Compiler compiler; 374 final Compiler compiler;
386 final List<HBasicBlock> blocks; 375 final List<HBasicBlock> blocks;
387 final List<HLabeledBlockInformation> labeledBlockInformations; 376 final List<HLabeledBlockInformation> labeledBlockInformations;
388 final Set<HInstruction> generateAtUseSite; 377 final Set<HInstruction> generateAtUseSite;
389 SubGraph subGraph; 378 SubGraph subGraph;
390 int maxBailoutParameters = 0; 379 int maxBailoutParameters = 0;
391 380
392 /** 381 /**
393 * If set to true, the graph has either multiple bailouts in 382 * If set to true, the graph has either multiple bailouts in
394 * different places, or a bailout inside an if or a loop. For such a 383 * different places, or a bailout inside an if or a loop. For such a
395 * graph, the code generator will emit a generic switch. 384 * graph, the code generator will emit a generic switch.
396 */ 385 */
397 bool hasComplexTypeGuards = false; 386 bool hasComplexBailoutTargets = false;
398 387
399 /** 388 /**
400 * The first type guard in the graph. 389 * The first type guard in the graph.
401 */ 390 */
402 HTypeGuard firstTypeGuard; 391 HBailoutTarget firstBailoutTarget;
403 392
404 /** 393 /**
405 * If set, it is the first block in the graph where we generate 394 * If set, it is the first block in the graph where we generate
406 * code. Blocks before this one are dead code in the bailout 395 * code. Blocks before this one are dead code in the bailout
407 * version. 396 * version.
408 */ 397 */
409 398
410 SsaBailoutPropagator(this.compiler, this.generateAtUseSite) 399 SsaBailoutPropagator(this.compiler, this.generateAtUseSite)
411 : blocks = <HBasicBlock>[], 400 : blocks = <HBasicBlock>[],
412 labeledBlockInformations = <HLabeledBlockInformation>[]; 401 labeledBlockInformations = <HLabeledBlockInformation>[];
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
515 504
516 visitBasicBlock(branchBlock.successors[1]); 505 visitBasicBlock(branchBlock.successors[1]);
517 // With labeled breaks we can have more dominated blocks. 506 // With labeled breaks we can have more dominated blocks.
518 if (dominated.length >= 3) { 507 if (dominated.length >= 3) {
519 for (int i = 2; i < dominated.length; i++) { 508 for (int i = 2; i < dominated.length; i++) {
520 visitBasicBlock(dominated[i]); 509 visitBasicBlock(dominated[i]);
521 } 510 }
522 } 511 }
523 } 512 }
524 513
525 visitTypeGuard(HTypeGuard guard) { 514 visitBailoutTarget(HBailoutTarget target) {
526 int inputLength = guard.inputs.length; 515 int inputLength = target.inputs.length;
527 if (inputLength > maxBailoutParameters) { 516 if (inputLength > maxBailoutParameters) {
528 maxBailoutParameters = inputLength; 517 maxBailoutParameters = inputLength;
529 } 518 }
530 if (blocks.isEmpty()) { 519 if (blocks.isEmpty()) {
531 if (firstTypeGuard === null || firstTypeGuard.state === guard.state) { 520 if (firstBailoutTarget === null) {
532 firstTypeGuard = guard; 521 firstBailoutTarget = target;
533 } else { 522 } else {
534 hasComplexTypeGuards = true; 523 hasComplexBailoutTargets = true;
535 } 524 }
536 } else { 525 } else {
537 hasComplexTypeGuards = true; 526 hasComplexBailoutTargets = true;
538 blocks.forEach((HBasicBlock block) { 527 blocks.forEach((HBasicBlock block) {
539 block.guards.add(guard); 528 block.bailoutTargets.add(target);
540 }); 529 });
541 } 530 }
542 } 531 }
543 } 532 }
OLDNEW
« no previous file with comments | « no previous file | lib/compiler/implementation/ssa/codegen.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698