Mercurial > hg > graal-jvmci-8
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 } |