📄 code.java
字号:
public void put4(int pc, int od) {
put1(pc, od >> 24);
put1(pc + 1, od >> 16);
put1(pc + 2, od >> 8);
put1(pc + 3, od);
}
/**
* Return code byte at position pc as an unsigned int.
*/
public int get1(int pc) {
return code[pc] & 255;
}
/**
* Return two code bytes at position pc as an unsigned int.
*/
public int get2(int pc) {
return (get1(pc)<< 8) | get1(pc + 1);
}
/**
* Return four code bytes at position pc as an int.
*/
public int get4(int pc) {
return (get1(pc)<< 24) | (get1(pc + 1)<< 16) | (get1(pc + 2)<< 8) |
(get1(pc + 3));
}
/**
* Is code generation currently enabled?
*/
public boolean isAlive() {
return alive || pendingJumps != null;
}
/**
* Switch code generation on/off.
*/
public void markDead() {
alive = false;
}
/**
* Declare an entry point; return current code pointer
*/
public int entryPoint() {
alive = true;
return curPc();
}
/**
* Declare an entry point with initial stack size;
* return current code pointer
*/
public int entryPoint(int size) {
alive = true;
stacksize = size;
if (stacksize > max_stack)
max_stack = stacksize;
return curPc();
}
/**
* A chain represents a list of unresolved jumps. Jump locations
* are sorted in decreasing order.
*/
public static class Chain {
/**
* The position of the jump instruction.
*/
public final int pc;
/**
* The stacksize after the jump instruction.
* Invariant: all elements of a chain list have the same stacksize.
*/
public final int stacksize;
/**
* The next jump in the list.
*/
public final Chain next;
/**
* The set of variables alive at the jump.
*/
public final Bits defined;
/**
* Construct a chain from its jump position, stacksize, previous
* chain, and set of defined variables.
*/
public Chain(int pc, int stacksize, Chain next, Bits defined) {
super();
this.pc = pc;
this.stacksize = stacksize;
this.next = next;
this.defined = defined;
}
}
/**
* Negate a branch opcode.
*/
public static int negate(int opcode) {
if (opcode == if_acmp_null)
return if_acmp_nonnull;
else if (opcode == if_acmp_nonnull)
return if_acmp_null;
else return ((opcode + 1) ^ 1)
- 1;
}
/**
* Emit a jump instruction.
* Return code pointer of instruction to be patched.
*/
public int emitJump(int opcode) {
if (fatcode) {
if (opcode == goto_ || opcode == jsr) {
emitop4(opcode + goto_w - goto_, 0);
} else {
emitop2(negate(opcode), 8);
emitop4(goto_w, 0);
}
return cp - 5;
} else {
emitop2(opcode, 0);
return cp - 3;
}
}
/**
* Emit a branch with given opcode; return its chain.
* branch differs from jump in that jsr is treated as no-op.
*/
public Chain branch(int opcode) {
Chain result = null;
if (opcode == goto_) {
result = pendingJumps;
pendingJumps = null;
}
if (opcode != dontgoto && isAlive()) {
result = new Chain(emitJump(opcode), stacksize, result,
varDebugInfo ? defined.dup() : null);
fixedPc = fatcode;
if (opcode == goto_)
alive = false;
}
return result;
}
/**
* Resolve chain l to point to given target.
*/
public void resolve(Chain chain, int target) {
Bits newDefined = defined;
for (; chain != null; chain = chain.next) {
assert target > chain.pc || stacksize == 0;
if (target >= cp) {
target = cp;
} else if (get1(target) == goto_) {
if (fatcode)
target = target + get4(target + 1);
else
target = target + get2(target + 1);
}
if (get1(chain.pc) == goto_ && chain.pc + 3 == target &&
target == cp && !fixedPc) {
cp = cp - 3;
target = target - 3;
} else {
if (fatcode)
put4(chain.pc + 1, target - chain.pc);
else if (target - chain.pc < Short.MIN_VALUE ||
target - chain.pc > Short.MAX_VALUE)
fatcode = true;
else
put2(chain.pc + 1, target - chain.pc);
assert ! alive || chain.stacksize == stacksize;
}
fixedPc = true;
if (cp == target) {
if (alive) {
assert stacksize == chain.stacksize;
if (varDebugInfo)
newDefined = chain.defined.andSet(defined);
} else {
stacksize = chain.stacksize;
if (varDebugInfo)
newDefined = chain.defined;
alive = true;
}
}
}
setDefined(newDefined);
}
/**
* Set the current variable defined state.
*/
public void setDefined(Bits newDefined) {
if (alive && varDebugInfo && newDefined != defined) {
Bits diff = defined.dup().xorSet(newDefined);
for (int adr = diff.nextBit(0); adr >= 0; adr = diff.nextBit(adr + 1)) {
if (adr >= nextreg)
defined.excl(adr);
else if (defined.isMember(adr))
setUndefined(adr);
else
setDefined(adr);
}
}
}
/**
* Resolve chain l to point to current code pointer.
*/
public void resolve(Chain chain) {
pendingJumps = mergeChains(chain, pendingJumps);
}
/**
* Resolve any pending jumps.
*/
public void resolvePending() {
Chain x = pendingJumps;
pendingJumps = null;
resolve(x, cp);
}
/**
* Merge the jumps in of two chains into one.
*/
public static Chain mergeChains(Chain chain1, Chain chain2) {
if (chain2 == null)
return chain1;
if (chain1 == null)
return chain2;
if (chain1.pc < chain2.pc)
return new Chain(chain2.pc, chain2.stacksize,
mergeChains(chain1, chain2.next), chain2.defined);
return new Chain(chain1.pc, chain1.stacksize,
mergeChains(chain1.next, chain2), chain1.defined);
}
/**
* Add a catch clause to code.
*/
public void addCatch(char startPc, char endPc, char handlerPc, char catchType) {
catchInfo.append(new char[]{startPc, endPc, handlerPc, catchType});
}
/**
* Add a line number entry.
*/
public void addLineNumber(char startPc, char lineNumber) {
if (lineDebugInfo) {
if (lineInfo.nonEmpty() && ((char[]) lineInfo.head)[0] == startPc)
lineInfo = lineInfo.tail;
if (lineInfo.isEmpty() || ((char[]) lineInfo.head)[1] != lineNumber)
lineInfo = lineInfo.prepend(new char[]{startPc, lineNumber});
}
}
/**
* Mark beginning of statement.
*/
public void statBegin(int pos) {
if (pos != Position.NOPOS) {
pendingStatPos = pos;
}
}
/**
* Force stat begin eagerly
*/
public void markStatBegin() {
int line = Position.line(pendingStatPos);
pendingStatPos = Position.NOPOS;
if (alive && lineDebugInfo) {
char cp1 = (char) cp;
char line1 = (char) line;
if (cp1 == cp && line1 == line)
addLineNumber(cp1, line1);
}
}
/**
* A live range of a local variable.
*/
static class LocalVar {
final VarSymbol var;
final char reg;
char start_pc = Character.MAX_VALUE;
char length = Character.MAX_VALUE;
LocalVar(VarSymbol v) {
super();
this.var = v;
this.reg = (char) v.adr;
}
public LocalVar dup() {
return new LocalVar(var);
}
}
{
}
/**
* Local variables, indexed by register.
*/
LocalVar[] lvar;
public Bits defined;
/**
* Add a new local variable.
*/
private void addLocalVar(VarSymbol v) {
int adr = v.adr;
if (adr >= lvar.length) {
int newlength = lvar.length * 2;
if (newlength <= adr)
newlength = adr + 10;
LocalVar[] new_lvar = new LocalVar[newlength];
System.arraycopy(lvar, 0, new_lvar, 0, lvar.length);
lvar = new_lvar;
}
assert lvar[adr] == null;
lvar[adr] = new LocalVar(v);
defined.excl(adr);
}
/**
* Mark a register as being defined.
*/
public void setDefined(int adr) {
if (!varDebugInfo)
return;
defined.incl(adr);
if (cp < Character.MAX_VALUE && adr < lvar.length) {
LocalVar v = lvar[adr];
if (v != null && v.start_pc == Character.MAX_VALUE)
v.start_pc = (char) cp;
}
}
/**
* Mark a register as being undefined.
*/
public void setUndefined(int adr) {
defined.excl(adr);
if (adr < lvar.length && lvar[adr] != null &&
lvar[adr].start_pc != Character.MAX_VALUE) {
LocalVar v = lvar[adr];
char length = (char)(curPc() - v.start_pc);
if (length < Character.MAX_VALUE) {
lvar[adr] = v.dup();
v.length = length;
putVar(v);
} else {
v.start_pc = Character.MAX_VALUE;
}
}
}
/**
* End the scope of a variable.
*/
private void endScope(int adr) {
defined.excl(adr);
if (adr < lvar.length && lvar[adr] != null) {
LocalVar v = lvar[adr];
lvar[adr] = null;
if (v.start_pc != Character.MAX_VALUE) {
char length = (char)(curPc() - v.start_pc);
if (length < Character.MAX_VALUE) {
v.length = length;
putVar(v);
}
}
}
}
/**
* Put a live variable range into the buffer to be output to the
* class file.
*/
void putVar(LocalVar var) {
if (varBuffer == null)
varBuffer = new LocalVar[20];
if (varBufferSize >= varBuffer.length) {
LocalVar[] newVarBuffer = new LocalVar[varBufferSize * 2];
System.arraycopy(varBuffer, 0, newVarBuffer, 0, varBuffer.length);
varBuffer = newVarBuffer;
}
varBuffer[varBufferSize++] = var;
}
/**
* Previously live local variables, to be put into the variable table.
*/
LocalVar[] varBuffer;
int varBufferSize;
/**
* Create a new local variable address and return it.
*/
public int newLocal(int typecode) {
int reg = nextreg;
int w = width(typecode);
nextreg = reg + w;
if (nextreg > max_locals)
max_locals = nextreg;
return reg;
}
public int newLocal(Type type) {
return newLocal(typecode(type));
}
public int newLocal(VarSymbol v) {
int reg = v.adr = newLocal(v.erasure());
if (varDebugInfo)
addLocalVar(v);
return reg;
}
/**
* Start a set of fresh registers.
*/
public void newRegSegment() {
nextreg = max_locals;
}
/**
* End scopes of all variables with registers >= first.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -