/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* 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/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt.bc2ir;
import org.jikesrvm.compilers.opt.inlining.InlineSequence;
import org.jikesrvm.compilers.opt.ir.BasicBlock;
import org.jikesrvm.compilers.opt.ir.ControlFlowGraph;
import org.jikesrvm.compilers.opt.ir.operand.Operand;
/**
* This class is used as a 'wrapper' to a basic block to hold
* information that is necessary only for IR generation.
*/
class BasicBlockLE {
// Used by BBSet to maintain red/black tree of BBLE's during generation
BasicBlockLE parent, left, right;
/** Start bytecode of this BBLE */
final int low;
/** Current end bytecode of this BBLE */
int high;
/** Maximum possible bytecode of this BBLE (wrt exception ranges) */
int max;
/** Basic block that this BBLE refers to. */
BasicBlock block;
/** State of the stack at the start of this basic block. */
OperandStack stackState;
/** State of the local variables at the start of this basic block. */
Operand[] localState;
/**
* The desired fallthrough (next in code order) BBLE (may be {@code null}).
* NOTE: we may not always end up actually falling through
* (see BBSet.finalPass).
*/
BasicBlockLE fallThrough;
/**
* The exception handler BBLE's for this block ({@code null} if none)
*/
HandlerBlockLE[] handlers;
/**
* Encoding of random boolean state
*/
private byte flags;
private static final byte STACK_KNOWN = 0x01;
private static final byte LOCAL_KNOWN = 0x02;
private static final byte SELF_REGEN = 0x04;
private static final byte GENERATED = 0x08;
private static final byte COLOR = 0x10; //(Red = 0, Black = 1)
private static final byte IN_CODE_ORDER = 0x20;
final void setStackKnown() {
flags |= STACK_KNOWN;
}
final void clearStackKnown() {
flags &= ~STACK_KNOWN;
}
final boolean isStackKnown() {
return (flags & STACK_KNOWN) != 0;
}
final void setLocalKnown() {
flags |= LOCAL_KNOWN;
}
final void clearLocalKnown() {
flags &= ~LOCAL_KNOWN;
}
final boolean isLocalKnown() {
return (flags & LOCAL_KNOWN) != 0;
}
final void setSelfRegen() {
flags |= SELF_REGEN;
}
final void clearSelfRegen() {
flags &= ~SELF_REGEN;
}
final boolean isSelfRegen() {
return (flags & SELF_REGEN) != 0;
}
final void setGenerated() {
flags |= GENERATED;
}
final void clearGenerated() {
flags &= ~GENERATED;
}
final boolean isGenerated() {
return (flags & GENERATED) != 0;
}
final void setBlack() {
flags |= COLOR;
}
final boolean isBlack() {
return (flags & COLOR) != 0;
}
final void setRed() {
flags &= ~COLOR;
}
final boolean isRed() {
return (flags & COLOR) == 0;
}
final void setInCodeOrder() {
flags |= IN_CODE_ORDER;
}
final void clearInCodeOrder() {
flags &= ~IN_CODE_ORDER;
}
final boolean isInCodeOrder() {
return (flags & IN_CODE_ORDER) != 0;
}
final boolean isReadyToGenerate() {
// (isStackKnown() && isLocalKnown && !isGenerated)
byte READY_MASK = STACK_KNOWN | LOCAL_KNOWN | GENERATED;
byte READY_VAL = STACK_KNOWN | LOCAL_KNOWN;
return (flags & READY_MASK) == READY_VAL;
}
/**
* Save a shallow copy of the given local variable state into this.
* @param _localState local variable state to save
*/
final void copyIntoLocalState(Operand[] _localState) {
localState = new Operand[_localState.length];
System.arraycopy(_localState, 0, localState, 0, _localState.length);
setLocalKnown();
}
/**
* @return a shallow copy of the local state
*/
final Operand[] copyLocalState() {
Operand[] ls = new Operand[localState.length];
System.arraycopy(localState, 0, ls, 0, localState.length);
return ls;
}
/**
* Adds an exception handler BBLE to the handlers array.
* <p>
* NOTE: this isn't incredibly efficient, but empirically the expected
* number of handlers per basic block is 0, with an observed
* maximum across 10,000+ methods of 3.
* Until this changes, we just don't care.
*
* @param handler the handler block to add
*/
final void addHandler(HandlerBlockLE handler) {
if (handlers == null) {
handlers = new HandlerBlockLE[1];
handlers[0] = handler;
} else {
for (HandlerBlockLE handler1 : handlers) {
if (handler1 == handler) {
return; //already there (was in emap more than once)
}
}
int n = handlers.length;
HandlerBlockLE[] tmp = new HandlerBlockLE[n + 1];
for (int i = 0; i < n; i++) {
tmp[i] = handlers[i];
}
tmp[n] = handler;
handlers = tmp;
}
}
/**
* Create a new BBLE (and basic block) for the specified bytecode index.
*
* @param loc bytecode index
* @param position the inline sequence
* @param cfg ControlFlowGraph into which the block
* will eventually be inserted
*/
BasicBlockLE(int loc, InlineSequence position, ControlFlowGraph cfg) {
block = new BasicBlock(loc, position, cfg);
low = loc;
high = loc;
}
// Only for use by subclasses to avoid above constructor.
protected BasicBlockLE(int loc) {
low = loc;
}
/**
* Returns a string representation of this BBLE.
*/
@Override
public String toString() {
if (isGenerated()) {
return "(" + low + "," + high + "," + max + ")";
}
if (isReadyToGenerate()) {
return "{" + low + "," + max + "}";
}
return "[" + low + "," + max + "]";
}
/**
* @return a string representation of state that determines if the BBLE
* is ready to be generated
*/
public String genState() {
return "(sk=" + isStackKnown() + ", lk=" + isLocalKnown() + ", gen=" + isGenerated() + ")";
}
}