comparison graal/GraalCompiler/src/com/sun/c1x/ir/BlockBegin.java @ 2509:16b9a8b5ad39

Renamings Runtime=>GraalRuntime and Compiler=>GraalCompiler
author Thomas Wuerthinger <thomas@wuerthinger.net>
date Wed, 27 Apr 2011 11:50:44 +0200
parents graal/Compiler/src/com/sun/c1x/ir/BlockBegin.java@9ec15d6914ca
children a384fac3fd34
comparison
equal deleted inserted replaced
2508:fea94949e0a2 2509:16b9a8b5ad39
1 /*
2 * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package com.sun.c1x.ir;
24
25 import java.util.*;
26
27 import com.sun.c1x.*;
28 import com.sun.c1x.asm.*;
29 import com.sun.c1x.debug.*;
30 import com.sun.c1x.lir.*;
31 import com.sun.c1x.util.*;
32 import com.sun.c1x.value.*;
33 import com.sun.cri.ci.*;
34
35 /**
36 * Denotes the beginning of a basic block, and holds information
37 * about the basic block, including the successor and
38 * predecessor blocks, exception handlers, liveness information, etc.
39 *
40 * @author Ben L. Titzer
41 */
42 public final class BlockBegin extends Instruction {
43 private static final List<BlockBegin> NO_HANDLERS = Collections.emptyList();
44
45 /**
46 * An enumeration of flags for block entries indicating various things.
47 */
48 public enum BlockFlag {
49 StandardEntry,
50 OsrEntry,
51 ExceptionEntry,
52 SubroutineEntry,
53 BackwardBranchTarget,
54 IsOnWorkList,
55 WasVisited,
56 DefaultExceptionHandler,
57 ParserLoopHeader,
58 CriticalEdgeSplit,
59 LinearScanLoopHeader,
60 LinearScanLoopEnd;
61
62 public final int mask = 1 << ordinal();
63 }
64
65 /**
66 * A unique id used in tracing.
67 */
68 public final int blockID;
69
70 /**
71 * Denotes the current set of {@link BlockBegin.BlockFlag} settings.
72 */
73 private int blockFlags;
74
75 /**
76 * The frame state before execution of the first instruction in this block.
77 */
78 private FrameState stateBefore;
79
80 /**
81 * A link to the last node in the block (which contains the successors).
82 */
83 private BlockEnd end;
84
85 /**
86 * The {@link BlockBegin} nodes for which this node is a successor.
87 */
88 private final List<BlockBegin> predecessors;
89
90 private int depthFirstNumber;
91 private int linearScanNumber;
92 private int loopDepth;
93 private int loopIndex;
94
95 private BlockBegin dominator;
96 private List<BlockBegin> exceptionHandlerBlocks;
97 private List<FrameState> exceptionHandlerStates;
98
99 // LIR block
100 public LIRBlock lirBlock;
101
102 /**
103 * Constructs a new BlockBegin at the specified bytecode index.
104 * @param bci the bytecode index of the start
105 * @param blockID the ID of the block
106 */
107 public BlockBegin(int bci, int blockID) {
108 super(CiKind.Illegal);
109 this.blockID = blockID;
110 depthFirstNumber = -1;
111 linearScanNumber = -1;
112 predecessors = new ArrayList<BlockBegin>(2);
113 loopIndex = -1;
114 setBCI(bci);
115 }
116
117 /**
118 * Gets the list of predecessors of this block.
119 * @return the predecessor list
120 */
121 public List<BlockBegin> predecessors() {
122 return predecessors;
123 }
124
125 /**
126 * Gets the dominator of this block.
127 * @return the dominator block
128 */
129 public BlockBegin dominator() {
130 return dominator;
131 }
132
133 /**
134 * Sets the dominator block for this block.
135 * @param dominator the dominator for this block
136 */
137 public void setDominator(BlockBegin dominator) {
138 this.dominator = dominator;
139 }
140
141 /**
142 * Gets the depth first traversal number of this block.
143 * @return the depth first number
144 */
145 public int depthFirstNumber() {
146 return depthFirstNumber;
147 }
148
149 /**
150 * Gets the linear scan number of this block.
151 * @return the linear scan number
152 */
153 public int linearScanNumber() {
154 return linearScanNumber;
155 }
156
157 /**
158 * Gets the loop depth of this block.
159 * @return the loop depth
160 */
161 public int loopDepth() {
162 return loopDepth;
163 }
164
165 /**
166 * Gets the loop index of this block.
167 * @return the loop index
168 */
169 public int loopIndex() {
170 return loopIndex;
171 }
172
173 /**
174 * Gets the block end associated with this basic block.
175 * @return the block end
176 */
177 public BlockEnd end() {
178 return end;
179 }
180
181 /**
182 * Gets the state at the start of this block.
183 * @return the state at the start of this block
184 */
185 @Override
186 public FrameState stateBefore() {
187 return stateBefore;
188 }
189
190 /**
191 * Sets the initial state for this block.
192 * @param stateBefore the state for this block
193 */
194 public void setStateBefore(FrameState stateBefore) {
195 assert this.stateBefore == null;
196 this.stateBefore = stateBefore;
197 }
198
199 /**
200 * Gets the exception handlers that cover one or more instructions of this basic block.
201 *
202 * @return the exception handlers
203 */
204 public List<BlockBegin> exceptionHandlerBlocks() {
205 return exceptionHandlerBlocks == null ? NO_HANDLERS : exceptionHandlerBlocks;
206 }
207
208 public List<FrameState> exceptionHandlerStates() {
209 return exceptionHandlerStates;
210 }
211
212 public void setDepthFirstNumber(int depthFirstNumber) {
213 assert depthFirstNumber >= 0;
214 this.depthFirstNumber = depthFirstNumber;
215 }
216
217 public void setLinearScanNumber(int linearScanNumber) {
218 this.linearScanNumber = linearScanNumber;
219 }
220
221 public void setLoopDepth(int loopDepth) {
222 this.loopDepth = loopDepth;
223 }
224
225 public void setLoopIndex(int loopIndex) {
226 this.loopIndex = loopIndex;
227 }
228
229 /**
230 * Set the block end for this block begin. This method will
231 * reset this block's successor list and rebuild it to be equivalent
232 * to the successor list of the specified block end.
233 * @param end the new block end for this block begin
234 */
235 public void setEnd(BlockEnd end) {
236 assert end != null;
237 BlockEnd old = this.end;
238 if (old != end) {
239 if (old != null) {
240 // disconnect this block from the old end
241 old.setBegin(null);
242 // disconnect this block from its current successors
243 for (BlockBegin s : old.successors()) {
244 s.predecessors().remove(this);
245 }
246 }
247 this.end = end;
248 end.setBegin(this);
249 for (BlockBegin s : end.successors()) {
250 s.addPredecessor(this);
251 }
252 }
253 }
254
255 /**
256 * Set a flag on this block.
257 * @param flag the flag to set
258 */
259 public void setBlockFlag(BlockFlag flag) {
260 blockFlags |= flag.mask;
261 }
262
263 /**
264 * Clear a flag on this block.
265 * @param flag the flag to clear
266 */
267 public void clearBlockFlag(BlockFlag flag) {
268 blockFlags &= ~flag.mask;
269 }
270
271 public void copyBlockFlag(BlockBegin other, BlockFlag flag) {
272 setBlockFlag(flag, other.checkBlockFlag(flag));
273 }
274
275 /**
276 * Check whether this block has the specified flag set.
277 * @param flag the flag to test
278 * @return {@code true} if this block has the flag
279 */
280 public boolean checkBlockFlag(BlockFlag flag) {
281 return (blockFlags & flag.mask) != 0;
282 }
283
284 /**
285 * Iterate over this block, its exception handlers, and its successors, in that order.
286 * @param closure the closure to apply to each block
287 */
288 public void iteratePreOrder(BlockClosure closure) {
289 // XXX: identity hash map might be too slow, consider a boolean array or a mark field
290 iterate(new IdentityHashMap<BlockBegin, BlockBegin>(), closure);
291 }
292
293 /**
294 * Iterate over all blocks transitively reachable from this block.
295 * @param closure the closure to apply to each block
296 * @param predecessors {@code true} if also to include this blocks predecessors
297 */
298 public void iterateAnyOrder(BlockClosure closure, boolean predecessors) {
299 IdentityHashMap<BlockBegin, BlockBegin> mark = new IdentityHashMap<BlockBegin, BlockBegin>();
300 LinkedList<BlockBegin> queue = new LinkedList<BlockBegin>();
301 queue.offer(this);
302 mark.put(this, this);
303 BlockBegin block;
304 while ((block = queue.poll()) != null) {
305 closure.apply(block);
306 queueBlocks(queue, block.exceptionHandlerBlocks(), mark);
307 queueBlocks(queue, block.end.successors(), mark);
308 queueBlocks(queue, predecessors ? block.predecessors : null, mark);
309 }
310 }
311
312 private void queueBlocks(LinkedList<BlockBegin> queue, List<BlockBegin> list, IdentityHashMap<BlockBegin, BlockBegin> mark) {
313 if (list != null) {
314 for (BlockBegin b : list) {
315 if (!mark.containsKey(b)) {
316 queue.offer(b);
317 mark.put(b, b);
318 }
319 }
320 }
321 }
322
323 private void iterate(IdentityHashMap<BlockBegin, BlockBegin> mark, BlockClosure closure) {
324 if (!mark.containsKey(this)) {
325 mark.put(this, this);
326 closure.apply(this);
327 BlockEnd e = end();
328 if (exceptionHandlerBlocks != null) {
329 iterateReverse(mark, closure, exceptionHandlerBlocks);
330 }
331 assert e != null : "block must have block end";
332 iterateReverse(mark, closure, e.successors());
333 }
334 }
335
336 private void iterateReverse(IdentityHashMap<BlockBegin, BlockBegin> mark, BlockClosure closure, List<BlockBegin> list) {
337 for (int i = list.size() - 1; i >= 0; i--) {
338 list.get(i).iterate(mark, closure);
339 }
340 }
341
342 /**
343 * Adds an exception handler that covers one or more instructions in this block.
344 *
345 * @param handler the entry block for the exception handler to add
346 */
347 public void addExceptionHandler(BlockBegin handler) {
348 assert handler != null && handler.checkBlockFlag(BlockBegin.BlockFlag.ExceptionEntry);
349 if (exceptionHandlerBlocks == null) {
350 exceptionHandlerBlocks = new ArrayList<BlockBegin>(3);
351 exceptionHandlerBlocks.add(handler);
352 } else if (!exceptionHandlerBlocks.contains(handler)) {
353 exceptionHandlerBlocks.add(handler);
354 }
355 }
356
357 /**
358 * Adds a frame state that merges into the exception handler whose entry is this block.
359 *
360 * @param state the frame state at an instruction that raises an exception that can be caught by the exception
361 * handler represented by this block
362 * @return the index of {@code state} in the list of frame states merging at this block (i.e. the frames states for
363 * all instruction throwing an exception caught by this exception handler)
364 */
365 public int addExceptionState(FrameState state) {
366 assert checkBlockFlag(BlockBegin.BlockFlag.ExceptionEntry);
367 if (exceptionHandlerStates == null) {
368 exceptionHandlerStates = new ArrayList<FrameState>(4);
369 }
370 exceptionHandlerStates.add(state);
371 return exceptionHandlerStates.size() - 1;
372 }
373
374 /**
375 * Add a predecessor to this block.
376 * @param pred the predecessor to add
377 */
378 public void addPredecessor(BlockBegin pred) {
379 predecessors.add(pred);
380 }
381
382 /**
383 * Removes all occurrences of the specified block from the predecessor list of this block.
384 * @param pred the predecessor to remove
385 */
386 public void removePredecessor(BlockBegin pred) {
387 while (predecessors.remove(pred)) {
388 // the block may appear multiple times in the list
389 // XXX: this is not very efficient, consider Util.removeAllFromList
390 }
391 }
392
393 @Override
394 public void accept(ValueVisitor v) {
395 v.visitBlockBegin(this);
396 }
397
398 public void mergeOrClone(FrameState newState) {
399 FrameState existingState = stateBefore;
400
401 if (existingState == null) {
402 // this is the first state for the block
403 if (wasVisited()) {
404 // this can happen for complex jsr/ret patterns; just bail out
405 throw new CiBailout("jsr/ret too complex");
406 }
407
408 // copy state because it is modified
409 newState = newState.copy();
410
411 if (C1XOptions.UseStackMapTableLiveness) {
412 // if a liveness map is available, use it to invalidate dead locals
413 CiBitMap[] livenessMap = newState.scope().method.livenessMap();
414 if (livenessMap != null && bci() >= 0) {
415 assert bci() < livenessMap.length;
416 CiBitMap liveness = livenessMap[bci()];
417 if (liveness != null) {
418 invalidateDeadLocals(newState, liveness);
419 }
420 }
421 }
422
423 // if the block is a loop header, insert all necessary phis
424 if (isParserLoopHeader()) {
425 insertLoopPhis(newState);
426 }
427
428 stateBefore = newState;
429 } else {
430 if (!C1XOptions.AssumeVerifiedBytecode && !existingState.isSameAcrossScopes(newState)) {
431 // stacks or locks do not match--bytecodes would not verify
432 throw new CiBailout("stack or locks do not match");
433 }
434
435 // while (existingState.scope() != newState.scope()) {
436 // // XXX: original code is not sure if this is necessary
437 // newState = newState.scope().callerState();
438 // assert newState != null : "could not match scopes";
439 // }
440 // above code replaced with assert for the moment
441 assert existingState.scope() == newState.scope();
442
443 assert existingState.localsSize() == newState.localsSize();
444 assert existingState.stackSize() == newState.stackSize();
445
446 if (wasVisited() && !isParserLoopHeader()) {
447 throw new CiBailout("jsr/ret too complicated");
448 }
449
450 existingState.merge(this, newState);
451 }
452 }
453
454 private void invalidateDeadLocals(FrameState newState, CiBitMap liveness) {
455 int max = newState.localsSize();
456 assert max <= liveness.size();
457 for (int i = 0; i < max; i++) {
458 Value x = newState.localAt(i);
459 if (x != null) {
460 if (!liveness.get(i)) {
461 // invalidate the local if it is not live
462 newState.invalidateLocal(i);
463 }
464 }
465 }
466 }
467
468 private void insertLoopPhis(FrameState newState) {
469 int stackSize = newState.stackSize();
470 for (int i = 0; i < stackSize; i++) {
471 // always insert phis for the stack
472 newState.setupPhiForStack(this, i);
473 }
474 int localsSize = newState.localsSize();
475 CiBitMap requiresPhi = newState.scope().getStoresInLoops();
476 for (int i = 0; i < localsSize; i++) {
477 Value x = newState.localAt(i);
478 if (x != null) {
479 if (requiresPhi != null) {
480 if (requiresPhi.get(i) || x.kind.isDoubleWord() && requiresPhi.get(i + 1)) {
481 // selectively do a phi
482 newState.setupPhiForLocal(this, i);
483 }
484 } else {
485 // always setup a phi
486 newState.setupPhiForLocal(this, i);
487 }
488 }
489 }
490 }
491
492 public boolean isStandardEntry() {
493 return checkBlockFlag(BlockFlag.StandardEntry);
494 }
495
496 public void setStandardEntry() {
497 setBlockFlag(BlockFlag.StandardEntry);
498 }
499
500 public boolean isOsrEntry() {
501 return checkBlockFlag(BlockFlag.OsrEntry);
502 }
503
504 public void setOsrEntry(boolean value) {
505 setBlockFlag(BlockFlag.OsrEntry, value);
506 }
507
508 public boolean isBackwardBranchTarget() {
509 return checkBlockFlag(BlockFlag.BackwardBranchTarget);
510 }
511
512 public void setBackwardBranchTarget(boolean value) {
513 setBlockFlag(BlockFlag.BackwardBranchTarget, value);
514 }
515
516 public boolean isCriticalEdgeSplit() {
517 return checkBlockFlag(BlockFlag.CriticalEdgeSplit);
518 }
519
520 public void setCriticalEdgeSplit(boolean value) {
521 setBlockFlag(BlockFlag.CriticalEdgeSplit, value);
522 }
523
524 public boolean isExceptionEntry() {
525 return checkBlockFlag(BlockFlag.ExceptionEntry);
526 }
527
528 public void setExceptionEntry() {
529 setBlockFlag(BlockFlag.ExceptionEntry);
530 }
531
532 public boolean isSubroutineEntry() {
533 return checkBlockFlag(BlockFlag.SubroutineEntry);
534 }
535
536 public void setSubroutineEntry() {
537 setBlockFlag(BlockFlag.SubroutineEntry);
538 }
539
540 public boolean isOnWorkList() {
541 return checkBlockFlag(BlockFlag.IsOnWorkList);
542 }
543
544 public void setOnWorkList(boolean value) {
545 setBlockFlag(BlockFlag.IsOnWorkList, value);
546 }
547
548 public boolean wasVisited() {
549 return checkBlockFlag(BlockFlag.WasVisited);
550 }
551
552 public void setWasVisited(boolean value) {
553 setBlockFlag(BlockFlag.WasVisited, value);
554 }
555
556 public boolean isParserLoopHeader() {
557 return checkBlockFlag(BlockFlag.ParserLoopHeader);
558 }
559
560 public void setParserLoopHeader(boolean value) {
561 setBlockFlag(BlockFlag.ParserLoopHeader, value);
562 }
563
564 public boolean isLinearScanLoopHeader() {
565 return checkBlockFlag(BlockFlag.LinearScanLoopHeader);
566 }
567
568 public void setLinearScanLoopHeader(boolean value) {
569 setBlockFlag(BlockFlag.LinearScanLoopHeader, value);
570 }
571
572 public boolean isLinearScanLoopEnd() {
573 return checkBlockFlag(BlockFlag.LinearScanLoopEnd);
574 }
575
576 public void setLinearScanLoopEnd(boolean value) {
577 setBlockFlag(BlockFlag.LinearScanLoopEnd, value);
578 }
579
580 private void setBlockFlag(BlockFlag flag, boolean value) {
581 if (value) {
582 setBlockFlag(flag);
583 } else {
584 clearBlockFlag(flag);
585 }
586 }
587
588 public void copyBlockFlags(BlockBegin other) {
589 copyBlockFlag(other, BlockBegin.BlockFlag.ParserLoopHeader);
590 copyBlockFlag(other, BlockBegin.BlockFlag.SubroutineEntry);
591 copyBlockFlag(other, BlockBegin.BlockFlag.ExceptionEntry);
592 copyBlockFlag(other, BlockBegin.BlockFlag.WasVisited);
593 }
594
595 @Override
596 public String toString() {
597 StringBuilder builder = new StringBuilder();
598 builder.append("block #");
599 builder.append(blockID);
600 builder.append(",");
601 builder.append(depthFirstNumber);
602 builder.append(" @ ");
603 builder.append(bci());
604 builder.append(" [");
605 boolean hasFlag = false;
606 for (BlockFlag f : BlockFlag.values()) {
607 if (checkBlockFlag(f)) {
608 if (hasFlag) {
609 builder.append(' ');
610 }
611 builder.append(f.name());
612 hasFlag = true;
613 }
614 }
615
616 builder.append("]");
617 if (end != null) {
618 builder.append(" -> ");
619 boolean hasSucc = false;
620 for (BlockBegin s : end.successors()) {
621 if (hasSucc) {
622 builder.append(", ");
623 }
624 builder.append("#");
625 builder.append(s.blockID);
626 hasSucc = true;
627 }
628 }
629 return builder.toString();
630 }
631
632 /**
633 * Get the number of successors.
634 * @return the number of successors
635 */
636 public int numberOfSux() {
637 return end.successors.size();
638 }
639
640 /**
641 * Get the successor at a certain position.
642 * @param i the position
643 * @return the successor
644 */
645 public BlockBegin suxAt(int i) {
646 return end.successors.get(i);
647 }
648
649 /**
650 * Get the number of predecessors.
651 * @return the number of predecessors
652 */
653 public int numberOfPreds() {
654 return predecessors.size();
655 }
656
657 /**
658 * @return the label associated with the block, used by the LIR
659 */
660 public Label label() {
661 return lirBlock().label;
662 }
663
664 public void setLir(LIRList lir) {
665 lirBlock().setLir(lir);
666 }
667
668 public LIRList lir() {
669 return lirBlock().lir();
670 }
671
672 public LIRBlock lirBlock() {
673 if (lirBlock == null) {
674 lirBlock = new LIRBlock();
675 }
676 return lirBlock;
677 }
678
679 public int exceptionHandlerPco() {
680 return lirBlock == null ? 0 : lirBlock.exceptionHandlerPCO;
681 }
682
683 public void setExceptionHandlerPco(int codeOffset) {
684 lirBlock().exceptionHandlerPCO = codeOffset;
685 }
686
687 public int numberOfExceptionHandlers() {
688 return exceptionHandlerBlocks == null ? 0 : exceptionHandlerBlocks.size();
689 }
690
691 public BlockBegin exceptionHandlerAt(int i) {
692 return exceptionHandlerBlocks.get(i);
693 }
694
695 public BlockBegin predAt(int j) {
696 return predecessors.get(j);
697 }
698
699 public int firstLirInstructionId() {
700 return lirBlock.firstLirInstructionID;
701 }
702
703 public void setFirstLirInstructionId(int firstLirInstructionId) {
704 lirBlock.firstLirInstructionID = firstLirInstructionId;
705 }
706
707 public int lastLirInstructionId() {
708 return lirBlock.lastLirInstructionID;
709 }
710
711 public void setLastLirInstructionId(int lastLirInstructionId) {
712 lirBlock.lastLirInstructionID = lastLirInstructionId;
713 }
714
715 public boolean isPredecessor(BlockBegin block) {
716 return this.predecessors.contains(block);
717 }
718
719 public void printWithoutPhis(LogStream out) {
720 // print block id
721 BlockEnd end = end();
722 out.print("B").print(blockID).print(" ");
723
724 // print flags
725 StringBuilder sb = new StringBuilder(8);
726 if (isStandardEntry()) {
727 sb.append('S');
728 }
729 if (isOsrEntry()) {
730 sb.append('O');
731 }
732 if (isExceptionEntry()) {
733 sb.append('E');
734 }
735 if (isSubroutineEntry()) {
736 sb.append('s');
737 }
738 if (isParserLoopHeader()) {
739 sb.append("LH");
740 }
741 if (isBackwardBranchTarget()) {
742 sb.append('b');
743 }
744 if (wasVisited()) {
745 sb.append('V');
746 }
747 if (sb.length() != 0) {
748 out.print('(').print(sb.toString()).print(')');
749 }
750
751 // print block bci range
752 out.print('[').print(bci()).print(", ").print(end == null ? -1 : end.bci()).print(']');
753
754 // print block successors
755 if (end != null && end.successors().size() > 0) {
756 out.print(" .");
757 for (BlockBegin successor : end.successors()) {
758 out.print(" B").print(successor.blockID);
759 }
760 }
761 // print exception handlers
762 if (!exceptionHandlers().isEmpty()) {
763 out.print(" (xhandlers");
764 for (BlockBegin handler : exceptionHandlerBlocks()) {
765 out.print(" B").print(handler.blockID);
766 }
767 out.print(')');
768 }
769
770 // print dominator block
771 if (dominator() != null) {
772 out.print(" dom B").print(dominator().blockID);
773 }
774
775 // print predecessors
776 if (!predecessors().isEmpty()) {
777 out.print(" pred:");
778 for (BlockBegin pred : predecessors()) {
779 out.print(" B").print(pred.blockID);
780 }
781 }
782 }
783
784 @Override
785 public void print(LogStream out) {
786
787 printWithoutPhis(out);
788
789 // print phi functions
790 boolean hasPhisInLocals = false;
791 boolean hasPhisOnStack = false;
792
793 if (end != null && end.stateAfter() != null) {
794 FrameState state = stateBefore();
795
796 int i = 0;
797 while (!hasPhisOnStack && i < state.stackSize()) {
798 Value value = state.stackAt(i);
799 hasPhisOnStack = isPhiAtBlock(value);
800 if (value != null && !value.isIllegal()) {
801 i += value.kind.sizeInSlots();
802 } else {
803 i++;
804 }
805 }
806
807 do {
808 for (i = 0; !hasPhisInLocals && i < state.localsSize();) {
809 Value value = state.localAt(i);
810 hasPhisInLocals = isPhiAtBlock(value);
811 // also ignore illegal HiWords
812 if (value != null && !value.isIllegal()) {
813 i += value.kind.sizeInSlots();
814 } else {
815 i++;
816 }
817 }
818 state = state.callerState();
819 } while (state != null);
820 }
821
822 // print values in locals
823 if (hasPhisInLocals) {
824 out.println();
825 out.println("Locals:");
826
827 FrameState state = stateBefore();
828 do {
829 int i = 0;
830 while (i < state.localsSize()) {
831 Value value = state.localAt(i);
832 if (value != null) {
833 out.println(stateString(i, value));
834 // also ignore illegal HiWords
835 i += value.isIllegal() ? 1 : value.kind.sizeInSlots();
836 } else {
837 i++;
838 }
839 }
840 out.println();
841 state = state.callerState();
842 } while (state != null);
843 }
844
845 // print values on stack
846 if (hasPhisOnStack) {
847 out.println();
848 out.println("Stack:");
849 int i = 0;
850 while (i < stateBefore().stackSize()) {
851 Value value = stateBefore().stackAt(i);
852 if (value != null) {
853 out.println(stateString(i, value));
854 i += value.kind.sizeInSlots();
855 } else {
856 i++;
857 }
858 }
859 }
860
861 }
862
863
864
865 /**
866 * Determines if a given instruction is a phi whose {@linkplain Phi#block() join block} is a given block.
867 *
868 * @param value the instruction to test
869 * @param block the block that may be the join block of {@code value} if {@code value} is a phi
870 * @return {@code true} if {@code value} is a phi and its join block is {@code block}
871 */
872 private boolean isPhiAtBlock(Value value) {
873 return value instanceof Phi && ((Phi) value).block() == this;
874 }
875
876
877 /**
878 * Formats a given instruction as a value in a {@linkplain FrameState frame state}. If the instruction is a phi defined at a given
879 * block, its {@linkplain Phi#inputCount() inputs} are appended to the returned string.
880 *
881 * @param index the index of the value in the frame state
882 * @param value the frame state value
883 * @param block if {@code value} is a phi, then its inputs are formatted if {@code block} is its
884 * {@linkplain Phi#block() join point}
885 * @return the instruction representation as a string
886 */
887 public String stateString(int index, Value value) {
888 StringBuilder sb = new StringBuilder(30);
889 sb.append(String.format("%2d %s", index, Util.valueString(value)));
890 if (value instanceof Phi) {
891 Phi phi = (Phi) value;
892 // print phi operands
893 if (phi.block() == this) {
894 sb.append(" [");
895 for (int j = 0; j < phi.inputCount(); j++) {
896 sb.append(' ');
897 Value operand = phi.inputAt(j);
898 if (operand != null) {
899 sb.append(Util.valueString(operand));
900 } else {
901 sb.append("NULL");
902 }
903 }
904 sb.append("] ");
905 }
906 }
907 if (value != null && value.hasSubst()) {
908 sb.append("alias ").append(Util.valueString(value.subst()));
909 }
910 return sb.toString();
911 }
912 }