comparison graal/GraalCompiler/src/com/sun/c1x/graph/BlockMap.java @ 2675:bcd20d26d52d

Refactoring of BlockMap so that it doesn't create BlockBegin objects, but maintains its own Block data structure
author Christian.Wimmer@Oracle.com
date Fri, 13 May 2011 13:59:32 -0700
parents ce054e34fbaf
children bcbda467e1ae
comparison
equal deleted inserted replaced
2672:35453d725a2a 2675:bcd20d26d52d
24 24
25 import static com.sun.cri.bytecode.Bytecodes.*; 25 import static com.sun.cri.bytecode.Bytecodes.*;
26 26
27 import java.util.*; 27 import java.util.*;
28 28
29 import com.oracle.graal.graph.*; 29 import com.sun.c1x.debug.*;
30 import com.sun.c1x.ir.*;
31 import com.sun.c1x.util.*;
32 import com.sun.cri.bytecode.*; 30 import com.sun.cri.bytecode.*;
33 import com.sun.cri.ci.*; 31 import com.sun.cri.ci.*;
34 import com.sun.cri.ri.*; 32 import com.sun.cri.ri.*;
35 33
36 /** 34 /**
112 * 110 *
113 * If the {@code computeStoresInLoops} argument to {@code build} is true, the {@code loopBlocks} list is processed to 111 * If the {@code computeStoresInLoops} argument to {@code build} is true, the {@code loopBlocks} list is processed to
114 * mark all local variables that are stored in the blocks in the list. 112 * mark all local variables that are stored in the blocks in the list.
115 */ 113 */
116 public final class BlockMap { 114 public final class BlockMap {
117 115 public class Block {
118 private static final BlockBegin[] NONE = {}; 116 public int startBci;
119 private static final List<BlockBegin> NONE_LIST = Collections.emptyList(); 117 public int endBci;
120 118 public boolean isExceptionEntry;
121 /** 119 public boolean isLoopHeader;
122 * The {@code ExceptionMap} class is used internally to track exception handlers 120
123 * while iterating over the bytecode and the control flow graph. Since methods with 121 private Block[] successors;
124 * exception handlers are much less frequent than those without, the common case 122 private boolean visited;
125 * does not need to construct an exception map. 123 private boolean active;
126 */ 124 private int loops;
127 private class ExceptionMap { 125 }
128 private final CiBitMap canTrap; 126
129 private final boolean isObjectInit; 127 private static final Block[] NO_SUCCESSORS = new Block[0];
130 private final RiExceptionHandler[] allHandlers; 128
131 private final ArrayMap<HashSet<BlockBegin>> handlerMap; 129 /**
132 130 * The blocks found in this method, in reverse postorder.
133 ExceptionMap(RiMethod method, byte[] code) { 131 */
134 canTrap = new CiBitMap(code.length); 132 public final List<Block> blocks;
135 isObjectInit = (method.isConstructor() && method.holder().superType() == null); 133
136 allHandlers = method.exceptionHandlers(); 134 /**
137 handlerMap = new ArrayMap<HashSet<BlockBegin>>(firstBlock, firstBlock + code.length / 5); 135 * A bit map covering the locals with a bit set for each local that might be stored to within a
138 } 136 * loop. If the bit is cleared, it is guaranteed that the local is never stored in a loop.
139 137 */
140 void setCanTrap(int bci) { 138 public final BitSet storesInLoops;
141 canTrap.set(bci); 139
142 } 140 private final RiMethod method;
143 141
144 void addHandlers(BlockBegin block, int bci) { 142 private Block[] blockMap;
145 if (canTrap.get(bci)) { 143
146 // XXX: replace with faster algorithm (sort exception handlers by start and end) 144 private BitSet canTrap;
147 for (RiExceptionHandler h : allHandlers) {
148 if (h.startBCI() <= bci && bci < h.endBCI()) {
149 addHandler(block, get(h.handlerBCI()));
150 if (h.isCatchAll()) {
151 break;
152 }
153 }
154 }
155 }
156 }
157
158 Collection<BlockBegin> getHandlers(BlockBegin block) {
159 // lookup handlers for the basic block
160 HashSet<BlockBegin> set = handlerMap.get(block.blockID);
161 return set == null ? NONE_LIST : set;
162 }
163
164 void setHandlerEntrypoints() {
165 // start basic blocks at all exception handler blocks and mark them as exception entries
166 for (RiExceptionHandler h : allHandlers) {
167 addEntrypoint(h.handlerBCI(), BlockBegin.BlockFlag.ExceptionEntry);
168 }
169 }
170
171 void addHandler(BlockBegin block, BlockBegin handler) {
172 // add a handler to a basic block, creating the set if necessary
173 HashSet<BlockBegin> set = handlerMap.get(block.blockID);
174 if (set == null) {
175 set = new HashSet<BlockBegin>();
176 handlerMap.put(block.blockID, set);
177 }
178 set.add(handler);
179 }
180 }
181
182 /** The bytecodes for the associated method. */
183 private final byte[] code;
184
185 /**
186 * Every {@link BlockBegin} node created by {@link BlockMap#build} has an entry in this
187 * array at the corresponding bytecode index. Length is same as {@link BlockMap#code}.
188 */
189 private final BlockBegin[] blockMap;
190
191 /**
192 * A bit map covering the locals with a bit set for each local that is
193 * stored to within a loop. This may be conservative depending on the value
194 * of the {@code computeStoresInLoops} parameters of {@link #build(boolean)}.
195 */
196 private final CiBitMap storesInLoops;
197
198 /**
199 * Every bytecode instruction that has zero, one or more successor nodes (e.g. {@link Bytecodes#GOTO} has one) has
200 * an entry in this array at the corresponding bytecode index. The value is another array of {@code BlockBegin} nodes,
201 * with length equal to the number of successors, whose entries are the {@code BlockBegin} nodes for the successor
202 * blocks. Length is same as {@link BlockMap#code}.
203 */
204 private BlockBegin[][] successorMap;
205
206 /** List of {@code BlockBegin} nodes that are inside loops. */
207 private ArrayList<BlockBegin> loopBlocks;
208 private ExceptionMap exceptionMap;
209
210 /**
211 * The first block number allocated for the blocks within this block map.
212 */
213 private final int firstBlock;
214
215 /**
216 * Used for initial block ID (count up) and post-order number (count down).
217 */
218 private int blockNum;
219
220 private final Graph graph;
221 145
222 /** 146 /**
223 * Creates a new BlockMap instance from bytecode of the given method . 147 * Creates a new BlockMap instance from bytecode of the given method .
224 * @param method the compiler interface method containing the code 148 * @param method the compiler interface method containing the code
225 * @param firstBlockNum the first block number to use when creating {@link BlockBegin} nodes 149 */
226 * @param graph 150 public BlockMap(RiMethod method) {
227 */ 151 this.method = method;
228 public BlockMap(RiMethod method, int firstBlockNum, Graph graph) { 152 this.blockMap = new Block[method.code().length];
229 this.graph = graph;
230 byte[] code = method.code();
231 this.code = code;
232 firstBlock = firstBlockNum;
233 blockNum = firstBlockNum;
234 blockMap = new BlockBegin[code.length];
235 successorMap = new BlockBegin[code.length][];
236 storesInLoops = new CiBitMap(method.maxLocals());
237 if (method.exceptionHandlers().length != 0) { 153 if (method.exceptionHandlers().length != 0) {
238 exceptionMap = new ExceptionMap(method, code); 154 this.canTrap = new BitSet(blockMap.length);
239 } 155 }
240 } 156 this.blocks = new ArrayList<Block>();
241 157 this.storesInLoops = new BitSet(method.maxLocals());
242 /**
243 * Add an entrypoint to this BlockMap. The resulting block will be marked
244 * with the specified block flags.
245 * @param bci the bytecode index of the start of the block
246 * @param entryFlag the entry flag to mark the block with
247 */
248 public void addEntrypoint(int bci, BlockBegin.BlockFlag entryFlag) {
249 make(bci).setBlockFlag(entryFlag);
250 }
251
252 /**
253 * Gets the block that begins at the specified bytecode index.
254 * @param bci the bytecode index of the start of the block
255 * @return the block starting at the specified index, if it exists; {@code null} otherwise
256 */
257 public BlockBegin get(int bci) {
258 if (bci < blockMap.length) {
259 return blockMap[bci];
260 }
261 return null;
262 }
263
264 private BlockBegin make(int bci) {
265 BlockBegin block = blockMap[bci];
266 if (block == null) {
267 block = new BlockBegin(bci, blockNum++, graph);
268 blockMap[bci] = block;
269 }
270 return block;
271 }
272
273 /**
274 * Gets a conservative approximation of the successors of a given block.
275 * @param block the block for which to get the successors
276 * @return an array of the successors of the specified block
277 */
278 public BlockBegin[] getSuccessors(BlockBegin block) {
279 BlockBegin[] succ = successorMap[block.bci()];
280 return succ == null ? NONE : succ;
281 }
282
283 /**
284 * Gets the exception handlers for a specified block. Note that this
285 * set of exception handlers takes into account whether the block contains
286 * bytecodes that can cause traps or not.
287 * @param block the block for which to get the exception handlers
288 * @return an array of the blocks which represent exception handlers; a zero-length
289 * array of blocks if there are no handlers that cover any potentially trapping
290 * instruction in the specified block
291 */
292 public Collection<BlockBegin> getHandlers(BlockBegin block) {
293 if (exceptionMap == null) {
294 return NONE_LIST;
295 }
296 return exceptionMap.getHandlers(block);
297 } 158 }
298 159
299 /** 160 /**
300 * Builds the block map and conservative CFG and numbers blocks. 161 * Builds the block map and conservative CFG and numbers blocks.
301 * @param computeStoresInLoops {@code true} if the block map builder should 162 */
302 * make a second pass over the bytecodes for blocks in loops 163 public void build() {
303 * @return {@code true} if the block map was built successfully; {@code false} otherwise 164 makeExceptionEntries();
304 */
305 public boolean build(boolean computeStoresInLoops) {
306 if (exceptionMap != null) {
307 exceptionMap.setHandlerEntrypoints();
308 }
309 iterateOverBytecodes(); 165 iterateOverBytecodes();
310 moveSuccessorLists(); 166 addExceptionEdges();
311 computeBlockNumbers(); 167 computeBlockOrder();
312 if (computeStoresInLoops) { 168
313 // process any blocks in loops to compute their stores 169 // Discard big arrays so that they can be GCed
314 // (requires another pass, but produces fewer phi's and ultimately better code) 170 blockMap = null;
315 processLoopBlocks(); 171 canTrap = null;
316 } else { 172 }
317 // be conservative and assume all locals are potentially stored in loops 173
318 // (does not require another pass, but produces more phi's and worse code) 174 private void makeExceptionEntries() {
319 storesInLoops.setAll(); 175 // start basic blocks at all exception handler blocks and mark them as exception entries
320 } 176 for (RiExceptionHandler h : method.exceptionHandlers()) {
321 return true; // XXX: what bailout conditions should the BlockMap check? 177 Block xhandler = makeBlock(h.handlerBCI());
322 } 178 xhandler.isExceptionEntry = true;
323 179 }
324 /** 180 }
325 * Cleans up any internal state not necessary after the initial pass. Note that 181
326 * this method discards the conservative CFG edges and only retains the block mapping 182 private void iterateOverBytecodes() {
327 * and stores in loops.
328 */
329 public void cleanup() {
330 // discard internal state no longer needed
331 successorMap = null;
332 loopBlocks = null;
333 exceptionMap = null;
334 }
335
336 /**
337 * Gets the number of blocks in this block map.
338 * @return the number of blocks
339 */
340 public int numberOfBlocks() {
341 return blockNum - firstBlock;
342 }
343
344 public int numberOfBytes() {
345 return code.length;
346 }
347
348 /**
349 * Gets the bitmap that indicates which local variables are assigned in loops.
350 * @return a bitmap which indicates the locals stored in loops
351 */
352 public CiBitMap getStoresInLoops() {
353 return storesInLoops;
354 }
355
356 void iterateOverBytecodes() {
357 // iterate over the bytecodes top to bottom. 183 // iterate over the bytecodes top to bottom.
358 // mark the entrypoints of basic blocks and build lists of successors for 184 // mark the entrypoints of basic blocks and build lists of successors for
359 // all bytecodes that end basic blocks (i.e. goto, ifs, switches, throw, jsr, returns, ret) 185 // all bytecodes that end basic blocks (i.e. goto, ifs, switches, throw, jsr, returns, ret)
186 byte[] code = method.code();
187 Block current = null;
360 int bci = 0; 188 int bci = 0;
361 ExceptionMap exceptionMap = this.exceptionMap;
362 byte[] code = this.code;
363 make(0);
364 while (bci < code.length) { 189 while (bci < code.length) {
190 if (current == null || blockMap[bci] != null) {
191 Block b = makeBlock(bci);
192 if (current != null) {
193 setSuccessors(current.endBci, b);
194 }
195 current = b;
196 }
197 blockMap[bci] = current;
198 current.endBci = bci;
199
365 int opcode = Bytes.beU1(code, bci); 200 int opcode = Bytes.beU1(code, bci);
366 switch (opcode) { 201 switch (opcode) {
367 case ATHROW:
368 if (exceptionMap != null) {
369 exceptionMap.setCanTrap(bci);
370 }
371 // fall through
372 case IRETURN: // fall through 202 case IRETURN: // fall through
373 case LRETURN: // fall through 203 case LRETURN: // fall through
374 case FRETURN: // fall through 204 case FRETURN: // fall through
375 case DRETURN: // fall through 205 case DRETURN: // fall through
376 case ARETURN: // fall through 206 case ARETURN: // fall through
377 case WRETURN: // fall through 207 case WRETURN: // fall through
378 case RETURN: 208 case RETURN: {
379 if (exceptionMap != null && exceptionMap.isObjectInit) { 209 current = null;
380 exceptionMap.setCanTrap(bci); 210
211 assert lengthOf(code, bci) == 1;
212 bci += 1;
213 break;
214 }
215
216 case ATHROW: {
217 current = null;
218 if (canTrap != null) {
219 canTrap.set(bci);
381 } 220 }
382 successorMap[bci] = NONE; // end of control flow 221
383 bci += 1; // these are all 1 byte opcodes 222 assert lengthOf(code, bci) == 1;
384 break; 223 bci += 1;
385 224 break;
386 case RET: 225 }
387 successorMap[bci] = NONE; // end of control flow
388 bci += 2; // ret is 2 bytes
389 break;
390 226
391 case IFEQ: // fall through 227 case IFEQ: // fall through
392 case IFNE: // fall through 228 case IFNE: // fall through
393 case IFLT: // fall through 229 case IFLT: // fall through
394 case IFGE: // fall through 230 case IFGE: // fall through
402 case IF_ICMPLE: // fall through 238 case IF_ICMPLE: // fall through
403 case IF_ACMPEQ: // fall through 239 case IF_ACMPEQ: // fall through
404 case IF_ACMPNE: // fall through 240 case IF_ACMPNE: // fall through
405 case IFNULL: // fall through 241 case IFNULL: // fall through
406 case IFNONNULL: { 242 case IFNONNULL: {
407 succ2(bci, bci + 3, bci + Bytes.beS2(code, bci + 1)); 243 current = null;
408 bci += 3; // these are all 3 byte opcodes 244 Block b1 = makeBlock(bci + 3);
245 Block b2 = makeBlock(bci + Bytes.beS2(code, bci + 1));
246 setSuccessors(bci, b1, b2);
247
248 assert lengthOf(code, bci) == 3;
249 bci += 3;
409 break; 250 break;
410 } 251 }
411 252
412 case GOTO: { 253 case GOTO: {
413 succ1(bci, bci + Bytes.beS2(code, bci + 1)); 254 current = null;
414 bci += 3; // goto is 3 bytes 255 Block b1 = makeBlock(bci + Bytes.beS2(code, bci + 1));
256 setSuccessors(bci, b1);
257
258 assert lengthOf(code, bci) == 3;
259 bci += 3;
415 break; 260 break;
416 } 261 }
417 262
418 case GOTO_W: { 263 case GOTO_W: {
419 succ1(bci, bci + Bytes.beS4(code, bci + 1)); 264 current = null;
420 bci += 5; // goto_w is 5 bytes 265 Block b1 = makeBlock(bci + Bytes.beS4(code, bci + 1));
266 setSuccessors(bci, b1);
267
268 assert lengthOf(code, bci) == 5;
269 bci += 5;
270 break;
271 }
272
273 case TABLESWITCH: {
274 BytecodeTableSwitch sw = new BytecodeTableSwitch(code, bci);
275 setSuccessors(bci, makeSwitchSuccessors(sw));
276 current = null;
277
278 assert lengthOf(code, bci) == sw.size();
279 bci += sw.size();
280 break;
281 }
282
283 case LOOKUPSWITCH: {
284 current = null;
285 BytecodeLookupSwitch sw = new BytecodeLookupSwitch(code, bci);
286 setSuccessors(bci, makeSwitchSuccessors(sw));
287
288 assert lengthOf(code, bci) == sw.size();
289 bci += sw.size();
421 break; 290 break;
422 } 291 }
423 292
424 case JSR: { 293 case JSR: {
425 int target = bci + Bytes.beS2(code, bci + 1); 294 throw new JSRNotSupportedBailout();
426 succ2(bci, bci + 3, target); // make JSR's a successor or not? 295 }
427 addEntrypoint(target, BlockBegin.BlockFlag.SubroutineEntry);
428 bci += 3; // jsr is 3 bytes
429 break;
430 }
431
432 case JSR_W: { 296 case JSR_W: {
433 int target = bci + Bytes.beS4(code, bci + 1); 297 throw new JSRNotSupportedBailout();
434 succ2(bci, bci + 5, target); 298 }
435 addEntrypoint(target, BlockBegin.BlockFlag.SubroutineEntry); 299 case RET: {
436 bci += 5; // jsr_w is 5 bytes 300 throw new JSRNotSupportedBailout();
437 break; 301 }
438 } 302
439
440 case TABLESWITCH: {
441 BytecodeSwitch sw = new BytecodeTableSwitch(code, bci);
442 makeSwitchSuccessors(bci, sw);
443 bci += sw.size();
444 break;
445 }
446
447 case LOOKUPSWITCH: {
448 BytecodeSwitch sw = new BytecodeLookupSwitch(code, bci);
449 makeSwitchSuccessors(bci, sw);
450 bci += sw.size();
451 break;
452 }
453 case WIDE: { 303 case WIDE: {
304 if (canTrap != null && ProfileInformationStub.trappedFrequently(method, bci)) {
305 canTrap.set(bci);
306 }
307
454 bci += lengthOf(code, bci); 308 bci += lengthOf(code, bci);
455 break; 309 break;
456 } 310 }
457 311
458 default: { 312 default: {
459 if (exceptionMap != null && canTrap(opcode)) { 313 if (canTrap != null && ProfileInformationStub.trappedFrequently(method, bci)) {
460 exceptionMap.setCanTrap(bci); 314 canTrap.set(bci);
461 } 315 }
462 bci += lengthOf(opcode); // all variable length instructions are handled above 316
463 } 317 assert lengthOf(code, bci) == lengthOf(opcode);
464 } 318 bci += lengthOf(opcode);
465 } 319 }
466 } 320 }
467 321 }
468 private void makeSwitchSuccessors(int bci, BytecodeSwitch tswitch) { 322 }
469 // make a list of all the successors of a switch 323
324 private Block makeBlock(int startBci) {
325 Block oldBlock = blockMap[startBci];
326 if (oldBlock == null) {
327 Block newBlock = new Block();
328 newBlock.startBci = startBci;
329 newBlock.successors = NO_SUCCESSORS;
330 blockMap[startBci] = newBlock;
331 return newBlock;
332
333 } else if (oldBlock.startBci != startBci) {
334 // Backward branch into the middle of an already processed block.
335 // Add the correct fall-through successor.
336 Block newBlock = new Block();
337 newBlock.startBci = startBci;
338 newBlock.endBci = oldBlock.endBci;
339 newBlock.successors = oldBlock.successors;
340
341 oldBlock.endBci = startBci - 1;
342 oldBlock.successors = new Block[] {newBlock };
343
344 for (int i = startBci; i <= newBlock.endBci; i++) {
345 blockMap[i] = newBlock;
346 }
347 return newBlock;
348
349 } else {
350 return oldBlock;
351 }
352 }
353
354 private Block[] makeSwitchSuccessors(BytecodeSwitch tswitch) {
470 int max = tswitch.numberOfCases(); 355 int max = tswitch.numberOfCases();
471 ArrayList<BlockBegin> list = new ArrayList<BlockBegin>(max + 1); 356 Block[] successors = new Block[max + 1];
472 for (int i = 0; i < max; i++) { 357 for (int i = 0; i < max; i++) {
473 list.add(make(tswitch.targetAt(i))); 358 successors[i] = makeBlock(tswitch.targetAt(i));
474 } 359 }
475 list.add(make(tswitch.defaultTarget())); 360 successors[max] = makeBlock(tswitch.defaultTarget());
476 successorMap[bci] = list.toArray(new BlockBegin[list.size()]); 361 return successors;
477 } 362 }
478 363
479 private void moveSuccessorLists() { 364 private void setSuccessors(int predBci, Block... successors) {
480 // move successor lists from the block-ending bytecodes that created them 365 for (Block sux : successors) {
481 // to the basic blocks which they end. 366 if (sux.isExceptionEntry) {
482 // also handle fall-through cases from backwards branches into the middle of a block 367 throw new CiBailout("Exception handler can be reached by both normal and exceptional control flow");
483 // add exception handlers to basic blocks 368 }
484 BlockBegin current = get(0); 369 }
485 ExceptionMap exceptionMap = this.exceptionMap; 370 Block predecessor = blockMap[predBci];
486 for (int bci = 0; bci < blockMap.length; bci++) { 371 assert predecessor.successors.length == 0;
487 BlockBegin next = blockMap[bci]; 372 predecessor.successors = successors;
488 if (next != null && next != current) { 373 }
489 if (current != null) { 374
490 // add fall through successor to current block 375 private void addExceptionEdges() {
491 successorMap[current.bci()] = new BlockBegin[] {next}; 376 if (canTrap == null) {
492 }
493 current = next;
494 }
495 if (exceptionMap != null) {
496 exceptionMap.addHandlers(current, bci);
497 }
498 BlockBegin[] succ = successorMap[bci];
499 if (succ != null && current != null) {
500 // move this successor list to current block
501 successorMap[bci] = null;
502 successorMap[current.bci()] = succ;
503 current = null;
504 }
505 }
506 assert current == null : "fell off end of code, should end with successor list";
507 }
508
509 private void computeBlockNumbers() {
510 // compute the block number for all blocks
511 int blockNum = this.blockNum;
512 int numBlocks = blockNum - firstBlock;
513 numberBlock(get(0), new CiBitMap(numBlocks), new CiBitMap(numBlocks));
514 this.blockNum = blockNum; // _blockNum is used to compute the number of blocks later
515 }
516
517 private boolean numberBlock(BlockBegin block, CiBitMap visited, CiBitMap active) {
518 // number a block with its reverse post-order traversal number
519 int blockIndex = block.blockID - firstBlock;
520
521 if (visited.get(blockIndex)) {
522 if (active.get(blockIndex)) {
523 // reached block via backward branch
524 block.setParserLoopHeader(true);
525 addLoopBlock(block);
526 return true;
527 }
528 // return whether the block is already a loop header
529 return block.isParserLoopHeader();
530 }
531
532 visited.set(blockIndex);
533 active.set(blockIndex);
534
535 boolean inLoop = false;
536 for (BlockBegin succ : getSuccessors(block)) {
537 // recursively process successors
538 inLoop |= numberBlock(succ, visited, active);
539 }
540 if (exceptionMap != null) {
541 for (BlockBegin succ : exceptionMap.getHandlers(block)) {
542 // process exception handler blocks
543 inLoop |= numberBlock(succ, visited, active);
544 }
545 }
546 // clear active bit after successors are processed
547 active.clear(blockIndex);
548 block.setDepthFirstNumber(blockNum--);
549 if (inLoop) {
550 addLoopBlock(block);
551 }
552
553 return inLoop;
554 }
555
556 private void addLoopBlock(BlockBegin block) {
557 if (loopBlocks == null) {
558 loopBlocks = new ArrayList<BlockBegin>();
559 }
560 loopBlocks.add(block);
561 }
562
563 private void processLoopBlocks() {
564 if (loopBlocks == null) {
565 return; 377 return;
566 } 378 }
567 for (BlockBegin block : loopBlocks) { 379
568 // process all the stores in this block 380 Block block = null;
569 int bci = block.bci(); 381 HashSet<Block> newSuccessorsOfBlock = new HashSet<Block>();
570 byte[] code = this.code; 382
571 while (true) { 383 for (int bci = canTrap.nextSetBit(0); bci >= 0; bci = canTrap.nextSetBit(bci + 1)) {
572 // iterate over the bytecodes in this block 384 Block newBlock = blockMap[bci];
573 int opcode = code[bci] & 0xff; 385 if (newBlock != block) {
574 if (opcode == WIDE) { 386 if (block != null) {
575 bci += processWideStore(code[bci + 1] & 0xff, code, bci); 387 block.successors = newSuccessorsOfBlock.toArray(new Block[newSuccessorsOfBlock.size()]);
576 } else if (isStore(opcode)) { 388 newSuccessorsOfBlock.clear();
577 bci += processStore(opcode, code, bci); 389 }
578 } else { 390 Collections.addAll(newSuccessorsOfBlock, newBlock.successors);
579 bci += lengthOf(code, bci); 391 }
580 } 392 block = newBlock;
581 if (bci >= code.length || blockMap[bci] != null) { 393
582 // stop when we reach the next block 394 for (RiExceptionHandler h : method.exceptionHandlers()) {
583 break; 395 if (h.startBCI() <= bci && bci < h.endBCI()) {
584 } 396 newSuccessorsOfBlock.add(blockMap[h.handlerBCI()]);
585 } 397 if (h.isCatchAll()) {
586 } 398 break;
587 } 399 }
588 400 }
589 private int processWideStore(int opcode, byte[] code, int bci) { 401 }
402 }
403 if (block != null) {
404 block.successors = newSuccessorsOfBlock.toArray(new Block[newSuccessorsOfBlock.size()]);
405 }
406 }
407
408 private void computeBlockOrder() {
409 int loop = computeBlockOrder(blockMap[0]);
410
411 if (loop != 0) {
412 // There is a path from a loop end to the method entry that does not pass the loop header.
413 // Therefore, the loop is non reducible (has more than one entry).
414 // We don't want to compile such methods because the IR only supports structured loops.
415 throw new CiBailout("Non-reducible loop");
416 }
417
418 // Convert postorder to the desired reverse postorder.
419 Collections.reverse(blocks);
420 }
421
422 /**
423 * The next available loop number.
424 */
425 private int nextLoop = 0;
426
427 /**
428 * Mark the block as a loop header, using the next available loop number.
429 * Also checks for corner cases that we don't want to compile.
430 */
431 private void makeLoopHeader(Block block) {
432 if (!block.isLoopHeader) {
433 block.isLoopHeader = true;
434
435 if (block.isExceptionEntry) {
436 // Loops that are implicitly formed by an exception handler lead to all sorts of corner cases.
437 // Don't compile such methods for now, until we see a concrete case that allows checking for correctness.
438 throw new CiBailout("Loop formed by an exception handler");
439 }
440 if (nextLoop >= Integer.SIZE) {
441 // This restriction can be removed by using a fall-back to a BitSet in case we have more than 32 loops
442 // Don't compile such methods for now, until we see a concrete case that allows checking for correctness.
443 throw new CiBailout("Too many loops in method");
444 }
445
446 assert block.loops == 0;
447 block.loops = 1 << nextLoop;
448 nextLoop++;
449 }
450 assert Integer.bitCount(block.loops) == 1;
451 }
452
453 /**
454 * Depth-first traversal of the control flow graph. The flag {@linkplain Block#visited} is used to
455 * visit every block only once. The flag {@linkplain Block#active} is used to detect cycles (backward
456 * edges).
457 */
458 private int computeBlockOrder(Block block) {
459 if (block.visited) {
460 if (block.active) {
461 // Reached block via backward branch.
462 makeLoopHeader(block);
463 }
464 // Return cached loop information for this block.
465 return block.loops;
466 }
467
468 block.visited = true;
469 block.active = true;
470
471 int loops = 0;
472 for (Block successor : block.successors) {
473 // Recursively process successors.
474 loops |= computeBlockOrder(successor);
475 }
476
477 if (loops != 0) {
478 processLoopBlock(block);
479 }
480 if (block.isLoopHeader) {
481 assert Integer.bitCount(block.loops) == 1;
482 loops &= ~block.loops;
483 }
484
485 block.loops = loops;
486 block.active = false;
487 blocks.add(block);
488
489 return loops;
490 }
491
492 private void processLoopBlock(Block block) {
493 // process all the stores in this block
494 byte[] code = method.code();
495 int bci = block.startBci;
496 while (bci <= block.endBci) {
497 int opcode = Bytes.beU1(code, bci);
498 if (isStore(opcode)) {
499 processStore(opcode, Bytes.beU1(code, bci + 1));
500
501 } else if (opcode == WIDE) {
502 opcode = Bytes.beU1(code, bci + 1);
503 if (isStore(opcode)) {
504 processStore(opcode, Bytes.beU2(code, bci + 2));
505 }
506 }
507 bci += lengthOf(code, bci);
508 }
509 }
510
511 private void processStore(int opcode, int local) {
590 switch (opcode) { 512 switch (opcode) {
591 case IINC: storeOne(Bytes.beU2(code, bci + 2)); return 6; 513 case IINC:
592 case ISTORE: storeOne(Bytes.beU2(code, bci + 2)); return 3; 514 case ISTORE:
593 case LSTORE: storeTwo(Bytes.beU2(code, bci + 2)); return 3; 515 case FSTORE:
594 case FSTORE: storeOne(Bytes.beU2(code, bci + 2)); return 3;
595 case DSTORE: storeTwo(Bytes.beU2(code, bci + 2)); return 3;
596 case ASTORE: storeOne(Bytes.beU2(code, bci + 2)); return 3;
597 }
598 return lengthOf(code, bci);
599 }
600
601 private int processStore(int opcode, byte[] code, int bci) {
602 switch (opcode) {
603 case IINC: storeOne(code[bci + 1] & 0xff); return 3;
604 case ISTORE: storeOne(code[bci + 1] & 0xff); return 2;
605 case LSTORE: storeTwo(code[bci + 1] & 0xff); return 2;
606 case FSTORE: storeOne(code[bci + 1] & 0xff); return 2;
607 case DSTORE: storeTwo(code[bci + 1] & 0xff); return 2;
608 case WSTORE: 516 case WSTORE:
609 case ASTORE: storeOne(code[bci + 1] & 0xff); return 2; 517 case ASTORE:
610 case ISTORE_0: // fall through 518 storesInLoops.set(local);
611 case ISTORE_1: // fall through 519 break;
612 case ISTORE_2: // fall through 520
613 case ISTORE_3: storeOne(opcode - ISTORE_0); return 1; 521 case LSTORE:
614 case LSTORE_0: // fall through 522 case DSTORE:
615 case LSTORE_1: // fall through 523 storesInLoops.set(local);
616 case LSTORE_2: // fall through 524 storesInLoops.set(local + 1);
617 case LSTORE_3: storeTwo(opcode - LSTORE_0); return 1; 525 break;
618 case FSTORE_0: // fall through 526
619 case FSTORE_1: // fall through 527 case ISTORE_0:
620 case FSTORE_2: // fall through 528 case FSTORE_0:
621 case FSTORE_3: storeOne(opcode - FSTORE_0); return 1; 529 case ASTORE_0:
622 case DSTORE_0: // fall through 530 case WSTORE_0:
623 case DSTORE_1: // fall through 531 storesInLoops.set(0);
624 case DSTORE_2: // fall through 532 break;
625 case DSTORE_3: storeTwo(opcode - DSTORE_0); return 1; 533 case ISTORE_1:
626 case ASTORE_0: // fall through 534 case FSTORE_1:
627 case ASTORE_1: // fall through 535 case ASTORE_1:
628 case ASTORE_2: // fall through 536 case WSTORE_1:
629 case ASTORE_3: storeOne(opcode - ASTORE_0); return 1; 537 storesInLoops.set(1);
630 case WSTORE_0: // fall through 538 break;
631 case WSTORE_1: // fall through 539 case ISTORE_2:
632 case WSTORE_2: // fall through 540 case FSTORE_2:
633 case WSTORE_3: storeOne(opcode - WSTORE_0); return 1; 541 case ASTORE_2:
634 } 542 case WSTORE_2:
635 throw Util.shouldNotReachHere(); 543 storesInLoops.set(2);
636 } 544 break;
637 545 case ISTORE_3:
638 private void storeOne(int local) { 546 case FSTORE_3:
639 storesInLoops.set(local); 547 case ASTORE_3:
640 } 548 case WSTORE_3:
641 549 storesInLoops.set(3);
642 private void storeTwo(int local) { 550 break;
643 storesInLoops.set(local); 551
644 storesInLoops.set(local + 1); 552 case LSTORE_0:
645 } 553 case DSTORE_0:
646 554 storesInLoops.set(0);
647 private void succ2(int bci, int s1, int s2) { 555 storesInLoops.set(1);
648 successorMap[bci] = new BlockBegin[] {make(s1), make(s2)}; 556 break;
649 } 557 case LSTORE_1:
650 558 case DSTORE_1:
651 private void succ1(int bci, int s1) { 559 storesInLoops.set(1);
652 successorMap[bci] = new BlockBegin[] {make(s1)}; 560 storesInLoops.set(2);
653 } 561 break;
654 562 case LSTORE_2:
655 private static StringBuilder append(StringBuilder sb, BlockBegin block) { 563 case DSTORE_2:
656 return sb.append('B').append(block.blockID).append('@').append(block.bci()); 564 storesInLoops.set(2);
657 } 565 storesInLoops.set(3);
658 566 break;
659 @Override 567 case LSTORE_3:
660 public String toString() { 568 case DSTORE_3:
661 StringBuilder sb = new StringBuilder(); 569 storesInLoops.set(3);
662 for (int bci = 0; bci < blockMap.length; ++bci) { 570 storesInLoops.set(4);
663 BlockBegin block = blockMap[bci]; 571 break;
664 if (block != null) { 572
665 append(sb, block); 573 default:
666 if (loopBlocks != null && loopBlocks.contains(block)) { 574 throw new InternalError("undefined store bytecode");
667 sb.append("{loop-header}"); 575 }
668 } 576 }
669 if (successorMap != null) { 577
670 BlockBegin[] succs = successorMap[bci]; 578
671 if (succs != null && succs.length > 0) { 579
672 sb.append(" ->"); 580 /**
673 for (BlockBegin succ : succs) { 581 * Print block information in the format required by {@linkplain CFGPrinter}. The method must
674 append(sb.append(' '), succ); 582 * be here because it accesses private state of a block.
675 } 583 */
676 } 584 public void printBlock(Block block, LogStream out) {
677 } 585 out.print("name \"B").print(block.startBci).println('"');
678 Collection<BlockBegin> handlers = getHandlers(block); 586 out.print("from_bci ").println(block.startBci);
679 if (!handlers.isEmpty()) { 587 out.print("to_bci ").println(block.endBci);
680 sb.append(" xhandlers{"); 588
681 for (BlockBegin h : handlers) { 589 out.println("predecessors ");
682 append(sb, h).append(' '); 590
683 } 591 out.print("successors ");
684 sb.append('}'); 592 for (Block succ : block.successors) {
685 } 593 if (!succ.isExceptionEntry) {
686 sb.append(String.format("%n")); 594 out.print("\"B").print(succ.startBci).print("\" ");
687 } 595 }
688 } 596 }
689 return sb.toString(); 597 out.println();
690 } 598
599 out.print("xhandlers");
600 for (Block succ : block.successors) {
601 if (succ.isExceptionEntry) {
602 out.print("\"B").print(succ.startBci).print("\" ");
603 }
604 }
605 out.println();
606
607 out.print("flags ");
608 if (block.isExceptionEntry) {
609 out.print("\"ex\" ");
610 }
611 if (block.isLoopHeader) {
612 out.print("\"plh\" ");
613 }
614 out.println();
615
616 out.print("loop_depth ").println(Integer.bitCount(block.loops));
617 }
618
619 //
620 // private static StringBuilder append(StringBuilder sb, BlockBegin block) {
621 // return sb.append('B').append(block.blockID).append('@').append(block.bci());
622 // }
623 //
624 // @Override
625 // public String toString() {
626 // StringBuilder sb = new StringBuilder();
627 // for (int bci = 0; bci < blockMap.length; ++bci) {
628 // BlockBegin block = blockMap[bci];
629 // if (block != null) {
630 // append(sb, block);
631 // if (loopBlocks != null && loopBlocks.contains(block)) {
632 // sb.append("{loop-header}");
633 // }
634 // if (successorMap != null) {
635 // BlockBegin[] succs = successorMap[bci];
636 // if (succs != null && succs.length > 0) {
637 // sb.append(" ->");
638 // for (BlockBegin succ : succs) {
639 // append(sb.append(' '), succ);
640 // }
641 // }
642 // }
643 // Collection<BlockBegin> handlers = getHandlers(block);
644 // if (!handlers.isEmpty()) {
645 // sb.append(" xhandlers{");
646 // for (BlockBegin h : handlers) {
647 // append(sb, h).append(' ');
648 // }
649 // sb.append('}');
650 // }
651 // sb.append(String.format("%n"));
652 // }
653 // }
654 // return sb.toString();
655 // }
691 } 656 }