📄 code.java
字号:
/** Return two code bytes at position pc as an unsigned int. */ private 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) { // pre: pc + 4 <= cp 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() { int pc = curPc(); alive = true; pendingStackMap = needStackMap; return pc; } /** Declare an entry point with initial state; * return current code pointer */ public int entryPoint(State state) { int pc = curPc(); alive = true; this.state = state.dup(); assert state.stacksize <= max_stack; if (debugCode) System.err.println("entry point " + state); pendingStackMap = needStackMap; return pc; } /** Declare an entry point with initial state plus a pushed value; * return current code pointer */ public int entryPoint(State state, Type pushed) { int pc = curPc(); alive = true; this.state = state.dup(); assert state.stacksize <= max_stack; this.state.push(pushed); if (debugCode) System.err.println("entry point " + state); pendingStackMap = needStackMap; return pc; }/************************************************************************** * Stack map generation *************************************************************************/ /** An entry in the stack map. */ static class StackMapFrame { int pc; Type[] locals; Type[] stack; } /** A buffer of cldc stack map entries. */ StackMapFrame[] stackMapBuffer = null; /** A buffer of compressed StackMapTable entries. */ StackMapTableFrame[] stackMapTableBuffer = null; int stackMapBufferSize = 0; /** The last PC at which we generated a stack map. */ int lastStackMapPC = -1; /** The last stack map frame in StackMapTable. */ StackMapFrame lastFrame = null; /** The stack map frame before the last one. */ StackMapFrame frameBeforeLast = null; /** Emit a stack map entry. */ public void emitStackMap() { int pc = curPc(); if (!needStackMap) return; switch (stackMap) { case CLDC: emitCLDCStackMap(pc, getLocalsSize()); break; case JSR202: emitStackMapFrame(pc, getLocalsSize()); break; default: throw new AssertionError("Should have chosen a stackmap format"); } // DEBUG code follows if (debugCode) state.dump(pc); } private int getLocalsSize() { int nextLocal = 0; for (int i=max_locals-1; i>=0; i--) { if (state.defined.isMember(i) && lvar[i] != null) { nextLocal = i + width(lvar[i].sym.erasure(types)); break; } } return nextLocal; } /** Emit a CLDC stack map frame. */ void emitCLDCStackMap(int pc, int localsSize) { if (lastStackMapPC == pc) { // drop existing stackmap at this offset stackMapBuffer[--stackMapBufferSize] = null; } lastStackMapPC = pc; if (stackMapBuffer == null) { stackMapBuffer = new StackMapFrame[20]; } else if (stackMapBuffer.length == stackMapBufferSize) { StackMapFrame[] newStackMapBuffer = new StackMapFrame[stackMapBufferSize << 1]; System.arraycopy(stackMapBuffer, 0, newStackMapBuffer, 0, stackMapBufferSize); stackMapBuffer = newStackMapBuffer; } StackMapFrame frame = stackMapBuffer[stackMapBufferSize++] = new StackMapFrame(); frame.pc = pc; frame.locals = new Type[localsSize]; for (int i=0; i<localsSize; i++) { if (state.defined.isMember(i) && lvar[i] != null) { Type vtype = lvar[i].sym.type; if (!(vtype instanceof UninitializedType)) vtype = types.erasure(vtype); frame.locals[i] = vtype; } } frame.stack = new Type[state.stacksize]; for (int i=0; i<state.stacksize; i++) frame.stack[i] = state.stack[i]; } void emitStackMapFrame(int pc, int localsSize) { if (lastFrame == null) { // first frame lastFrame = getInitialFrame(); } else if (lastFrame.pc == pc) { // drop existing stackmap at this offset stackMapTableBuffer[--stackMapBufferSize] = null; lastFrame = frameBeforeLast; frameBeforeLast = null; } StackMapFrame frame = new StackMapFrame(); frame.pc = pc; int localCount = 0; Type[] locals = new Type[localsSize]; for (int i=0; i<localsSize; i++, localCount++) { if (state.defined.isMember(i) && lvar[i] != null) { Type vtype = lvar[i].sym.type; if (!(vtype instanceof UninitializedType)) vtype = types.erasure(vtype); locals[i] = vtype; if (width(vtype) > 1) i++; } } frame.locals = new Type[localCount]; for (int i=0, j=0; i<localsSize; i++, j++) { assert(j < localCount); frame.locals[j] = locals[i]; if (width(locals[i]) > 1) i++; } int stackCount = 0; for (int i=0; i<state.stacksize; i++) { if (state.stack[i] != null) { stackCount++; } } frame.stack = new Type[stackCount]; stackCount = 0; for (int i=0; i<state.stacksize; i++) { if (state.stack[i] != null) { frame.stack[stackCount++] = state.stack[i]; } } if (stackMapTableBuffer == null) { stackMapTableBuffer = new StackMapTableFrame[20]; } else if (stackMapTableBuffer.length == stackMapBufferSize) { StackMapTableFrame[] newStackMapTableBuffer = new StackMapTableFrame[stackMapBufferSize << 1]; System.arraycopy(stackMapTableBuffer, 0, newStackMapTableBuffer, 0, stackMapBufferSize); stackMapTableBuffer = newStackMapTableBuffer; } stackMapTableBuffer[stackMapBufferSize++] = StackMapTableFrame.getInstance(frame, lastFrame.pc, lastFrame.locals, types); frameBeforeLast = lastFrame; lastFrame = frame; } StackMapFrame getInitialFrame() { StackMapFrame frame = new StackMapFrame(); List<Type> arg_types = ((MethodType)meth.externalType(types)).argtypes; int len = arg_types.length(); int count = 0; if (!meth.isStatic()) { Type thisType = meth.owner.type; frame.locals = new Type[len+1]; if (meth.isConstructor() && thisType != syms.objectType) { frame.locals[count++] = UninitializedType.uninitializedThis(thisType); } else { frame.locals[count++] = types.erasure(thisType); } } else { frame.locals = new Type[len]; } for (Type arg_type : arg_types) { frame.locals[count++] = types.erasure(arg_type); } frame.pc = -1; frame.stack = null; return frame; } /************************************************************************** * Operations having to do with jumps *************************************************************************/ /** 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 machine state after the jump instruction. * Invariant: all elements of a chain list have the same stacksize * and compatible stack and register contents. */ Code.State state; /** The next jump in the list. */ public final Chain next; /** Construct a chain from its jump position, stacksize, previous * chain, and machine state. */ public Chain(int pc, Chain next, Code.State state) { this.pc = pc; this.next = next; this.state = state; } } /** 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); alive = true; pendingStackMap = needStackMap; } 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), result, state.dup()); fixedPc = fatcode; if (opcode == goto_) alive = false; } return result; } /** Resolve chain to point to given target. */ public void resolve(Chain chain, int target) { boolean changed = false; State newState = state; for (; chain != null; chain = chain.next) { assert state != chain.state; assert target > chain.pc || state.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) { // If goto the next instruction, the jump is not needed: // compact the code. cp = cp - 3; target = target - 3; if (chain.next == null) { // This is the only jump to the target. Exit the loop // without setting new state. The code is reachable // from the instruction before goto_. alive = true; break; } } 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.state.stacksize == newState.stacksize && chain.state.nlocks == newState.nlocks; } fixedPc = true; if (cp == target) { changed = true; if (debugCode) System.err.println("resolving chain state=" + chain.state); if (alive) { newState = chain.state.join(newState); } else { newState = chain.state; alive = true; } } } assert !changed || state != newState; if (state != newState) { setDefined(newState.defined); state = newState; pendingStackMap = needStackMap; } } /** Resolve chain to point to current code pointer. */ public void resolve(Chain chain) { assert !alive || chain==null || state.stacksize == chain.state.stacksize && state.nlocks == chain.state.nlocks; 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) { // recursive merge sort if (chain2 == null) return chain1; if (chain1 == null) return chain2; assert chain1.state.stacksize == chain2.state.stacksize && chain1.state.nlocks == chain2.state.nlocks; if (chain1.pc < chain2.pc) return new Chain( chain2.pc, mergeChains(chain1, chain2.next), chain2.state); return new Chain( chain1.pc, mergeChains(chain1.next, chain2), chain1.state); }/* ************************************************************************** * Catch clauses ****************************************************************************/ /** 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}); }/* ************************************************************************** * Line numbers ****************************************************************************/ /** Add a line number entry. */ public void addLineNumber(char startPc, char lineNumber) { if (lineDebugInfo) { if (lineInfo.nonEmpty() && lineInfo.head[0] == startPc) lineInfo = lineInfo.tail; if (lineInfo.isEmpty() || 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() { if (alive && lineDebugInfo) { int line = lineMap.getLineNumber(pendingStatPos); char cp1 = (char)cp; char line1 = (char)line; if (cp1 == cp && line1 == line) addLineNumber(cp1, line1); } pendingStatPos = Position.NOPOS; }/* ************************************************************************** * Simulated VM machine state ****************************************************************************/ class State implements Cloneable { /** The set of registers containing values. */ Bits defined; /** The (types of the) contents of the machine stack. */ Type[] stack; /** The first stack position currently unused. */ int stacksize; /** The numbers of registers containing locked monitors. */ int[] locks; int nlocks; State() { defined = new Bits(); stack = new Type[16]; } State dup() { try { State state = (State)super.clone(); state.defined = defined.dup(); state.stack = stack.clone(); if (locks != null) state.locks = locks.clone(); if (debugCode) { System.err.println("duping state " + this); dump(); } return state; } catch (CloneNotSupportedException ex) { throw new AssertionError(ex); } } void lock(int register) { if (locks == null) { locks = new int[20]; } else if (locks.length == nlocks) { int[] newLocks = new int[locks.length << 1]; System.arraycopy(locks, 0, newLocks, 0, locks.length); locks = newLocks; } locks[nlocks] = register; nlocks++; } void unlock(int register) { nlocks--; assert locks[nlocks] == register; locks[nlocks] = -1; } void push(Type t) { if (debugCode) System.err.println(" pushing " + t); switch (t.tag) { case TypeTags.VOID: return; case TypeTags.BYTE: case TypeTags.CHAR: case TypeTags.SHORT: case TypeTags.BOOLEAN: t = syms.intType; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -