📄 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 + -