/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.baseline;
/**
* Structure to describe the basic blocks of the byte code Used in calculating
* stack map and local variable map for the garbage collector.
*/
final class VM_BasicBlock {
// NOTE: Block number 1 is the epilog block, the only block
// that exits from the method. Blocks that end in a return will
// have the exit block as their only successor.
// NOTE: Block number 0 is NOT used;
// ------------------- Static Class Fields -----------------
public static final int NOTBLOCK = 0;
public static final int EXITBLOCK = 1;
public static final int STARTPREDSIZE = 4;
public static final int STARTBBNUMBER = 2;
static final byte JSRENTRY = 1;
static final byte JSREXIT = 2;
static final byte METHODENTRY = 4;
static final byte TRYSTART = 8;
static final byte TRYBLOCK = 16;
static final byte INJSR = 32;
static final byte TRYHANDLERSTART = 64;
// --------------------- Instance Fields ---------------------
/** ID number (index into block array) */
private final int blockNumber;
/** starting byte in byte code array */
private int start;
/** ending byte in byte code array */
private int end;
/** number of preceding basic blocks */
private int predcount = 0;
// First 2 are listed individually.
private short pred1;
private short pred2;
/** list of rest preceding basic blocks */
private short[] restPredecessors;
// may be bigger then predcount;
/** additional state info for jsr handling, and other flags */
private byte state = 0;
// --------------- Constructor --------------------------------
/** This should be called only from the factory. */
VM_BasicBlock(int startval, int bn) {
blockNumber = bn;
start = startval;
}
/**
* This should be used when building the EXIT block EXIT is likely to have
* several predecessors.
*/
VM_BasicBlock(int startval, int endval, int blockNumber) {
start = startval;
end = endval;
this.blockNumber = blockNumber;
restPredecessors = new short[STARTPREDSIZE];
}
// ------------------ Static Methods -------------------------
/** transfer predecessor blocks from one block to another */
public static void transferPredecessors(VM_BasicBlock fromBB,
VM_BasicBlock toBB) {
toBB.predcount = fromBB.predcount;
toBB.pred1 = fromBB.pred1;
toBB.pred2 = fromBB.pred2;
toBB.restPredecessors = fromBB.restPredecessors;
fromBB.predcount = 0;
fromBB.restPredecessors = null;
}
// -------------------------- Instance Methods ----------------
void setStart(int startval) {
start = startval;
}
void setEnd(int endval) {
end = endval;
}
void setState(byte stateval) {
state |= stateval;
}
public int getStart() {
return start;
}
public int getEnd() {
return end;
}
public int getBlockNumber() {
return blockNumber;
}
public byte getState() {
return state;
}
public boolean isJSRExit() {
return ((state & JSREXIT) == JSREXIT);
}
public boolean isJSREntry() {
return ((state & JSRENTRY) == JSRENTRY);
}
public boolean isInJSR() {
return ((state & INJSR) == INJSR);
}
public boolean isMethodEntry() {
return ((state & METHODENTRY) == METHODENTRY);
}
public boolean isTryStart() {
return ((state & TRYSTART) == TRYSTART);
}
public boolean isTryBlock() {
return ((state & TRYBLOCK) == TRYBLOCK);
}
public boolean isTryHandlerStart() {
return ((state & TRYHANDLERSTART) == TRYHANDLERSTART);
}
public void addPredecessor(VM_BasicBlock predbb) {
predcount++;
if (predcount == 1) {
pred1 = (short) predbb.getBlockNumber();
} else if (predcount == 2) {
pred2 = (short) predbb.getBlockNumber();
} else if (restPredecessors == null) {
restPredecessors = new short[STARTPREDSIZE];
restPredecessors[predcount - 3] = (short) predbb.getBlockNumber();
} else {
if (restPredecessors.length <= predcount - 3) {
short[] newpreds = new short[predcount << 1];
int restLength = restPredecessors.length;
for (int i = 0; i < restLength; i++) {
newpreds[i] = restPredecessors[i];
}
restPredecessors = newpreds;
newpreds = null;
}
restPredecessors[predcount - 3] = (short) predbb.getBlockNumber();
// -3 to get it zero-based
}
}
/**
* This method first checks if a block is already on the predecessor list.
* Used with try blocks being added to their catch block as predecessors.
*/
public void addUniquePredecessor(VM_BasicBlock predbb) {
boolean dupFound = false, checkMade = false;
short predbbNum = (short) predbb.getBlockNumber();
if (predcount >= 1) {
if (pred1 == predbbNum) {
return;
}
if (predcount > 1) {
if (pred2 == predbbNum) {
return;
}
if (predcount > 2) {
if (restPredecessors.length <= predcount - 2) {
short[] newpreds = new short[predcount << 1];
int restLength = restPredecessors.length;
for (int i = 0; i < restLength; i++) {
if (restPredecessors[i] == predbbNum) {
dupFound = true; // finish up the copy anyway.
}
newpreds[i] = restPredecessors[i];
}
restPredecessors = newpreds;
newpreds = null;
if (dupFound)
return;
checkMade = true;
}
if (!checkMade) {
for (int i = 0; i < predcount - 2; i++) {
if (restPredecessors[i] == predbbNum) {
return;
}
}
}
predcount++;
restPredecessors[predcount - 3] = predbbNum;
} else { // predcount must be 2
restPredecessors = new short[STARTPREDSIZE];
predcount++;
restPredecessors[predcount - 3] = predbbNum;
}
} else {
// predcount must be 1
predcount++;
pred2 = predbbNum;
}
} else { // predcount must be 0
predcount++;
pred1 = predbbNum;
}
}
public int[] getPredecessors() {
int[] preds;
preds = new int[predcount];
if (predcount >= 1) {
preds[0] = pred1;
}
if (predcount > 1) {
preds[1] = pred2;
}
for (int i = 0; i < predcount - 2; i++) {
preds[i + 2] = restPredecessors[i];
}
return preds;
}
}