duke@1: /* xdono@117: * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@1: * duke@1: * This code is free software; you can redistribute it and/or modify it duke@1: * under the terms of the GNU General Public License version 2 only, as duke@1: * published by the Free Software Foundation. Sun designates this duke@1: * particular file as subject to the "Classpath" exception as provided duke@1: * by Sun in the LICENSE file that accompanied this code. duke@1: * duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@1: * version 2 for more details (a copy is included in the LICENSE file that duke@1: * accompanied this code). duke@1: * duke@1: * You should have received a copy of the GNU General Public License version duke@1: * 2 along with this work; if not, write to the Free Software Foundation, duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@1: * duke@1: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@1: * CA 95054 USA or visit www.sun.com if you need additional information or duke@1: * have any questions. duke@1: */ duke@1: duke@1: package com.sun.tools.javac.jvm; duke@1: duke@1: import com.sun.tools.javac.code.*; duke@1: import com.sun.tools.javac.code.Symbol.*; duke@1: import com.sun.tools.javac.util.*; duke@1: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; duke@1: duke@1: import static com.sun.tools.javac.code.TypeTags.*; duke@1: import static com.sun.tools.javac.jvm.ByteCodes.*; duke@1: import static com.sun.tools.javac.jvm.UninitializedType.*; duke@1: import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame; duke@1: duke@1: /** An internal structure that corresponds to the code attribute of duke@1: * methods in a classfile. The class also provides some utility operations to duke@1: * generate bytecode instructions. duke@1: * duke@1: *

This is NOT part of any API supported by Sun Microsystems. If duke@1: * you write code that depends on this, you do so at your own risk. duke@1: * This code and its internal interfaces are subject to change or duke@1: * deletion without notice. duke@1: */ duke@1: public class Code { duke@1: duke@1: public final boolean debugCode; duke@1: public final boolean needStackMap; duke@1: duke@1: public enum StackMapFormat { duke@1: NONE, duke@1: CLDC { jjg@113: Name getAttributeName(Names names) { duke@1: return names.StackMap; duke@1: } duke@1: }, duke@1: JSR202 { jjg@113: Name getAttributeName(Names names) { duke@1: return names.StackMapTable; duke@1: } duke@1: }; jjg@113: Name getAttributeName(Names names) { duke@1: return names.empty; duke@1: } duke@1: } duke@1: duke@1: final Types types; duke@1: final Symtab syms; duke@1: duke@1: /*---------- classfile fields: --------------- */ duke@1: duke@1: /** The maximum stack size. duke@1: */ duke@1: public int max_stack = 0; duke@1: duke@1: /** The maximum number of local variable slots. duke@1: */ duke@1: public int max_locals = 0; duke@1: duke@1: /** The code buffer. duke@1: */ duke@1: public byte[] code = new byte[64]; duke@1: duke@1: /** the current code pointer. duke@1: */ duke@1: public int cp = 0; duke@1: duke@1: /** Check the code against VM spec limits; if duke@1: * problems report them and return true. duke@1: */ duke@1: public boolean checkLimits(DiagnosticPosition pos, Log log) { duke@1: if (cp > ClassFile.MAX_CODE) { duke@1: log.error(pos, "limit.code"); duke@1: return true; duke@1: } duke@1: if (max_locals > ClassFile.MAX_LOCALS) { duke@1: log.error(pos, "limit.locals"); duke@1: return true; duke@1: } duke@1: if (max_stack > ClassFile.MAX_STACK) { duke@1: log.error(pos, "limit.stack"); duke@1: return true; duke@1: } duke@1: return false; duke@1: } duke@1: duke@1: /** A buffer for expression catch data. Each enter is a vector duke@1: * of four unsigned shorts. duke@1: */ duke@1: ListBuffer catchInfo = new ListBuffer(); duke@1: duke@1: /** A buffer for line number information. Each entry is a vector duke@1: * of two unsigned shorts. duke@1: */ duke@1: List lineInfo = List.nil(); // handled in stack fashion duke@1: duke@1: /** The CharacterRangeTable duke@1: */ duke@1: public CRTable crt; duke@1: duke@1: /*---------- internal fields: --------------- */ duke@1: duke@1: /** Are we generating code with jumps >= 32K? duke@1: */ duke@1: public boolean fatcode; duke@1: duke@1: /** Code generation enabled? duke@1: */ duke@1: private boolean alive = true; duke@1: duke@1: /** The current machine state (registers and stack). duke@1: */ duke@1: State state; duke@1: duke@1: /** Is it forbidden to compactify code, because something is duke@1: * pointing to current location? duke@1: */ duke@1: private boolean fixedPc = false; duke@1: duke@1: /** The next available register. duke@1: */ duke@1: public int nextreg = 0; duke@1: duke@1: /** A chain for jumps to be resolved before the next opcode is emitted. duke@1: * We do this lazily to avoid jumps to jumps. duke@1: */ duke@1: Chain pendingJumps = null; duke@1: duke@1: /** The position of the currently statement, if we are at the duke@1: * start of this statement, NOPOS otherwise. duke@1: * We need this to emit line numbers lazily, which we need to do duke@1: * because of jump-to-jump optimization. duke@1: */ duke@1: int pendingStatPos = Position.NOPOS; duke@1: duke@1: /** Set true when a stackMap is needed at the current PC. */ duke@1: boolean pendingStackMap = false; duke@1: duke@1: /** The stack map format to be generated. */ duke@1: StackMapFormat stackMap; duke@1: duke@1: /** Switch: emit variable debug info. duke@1: */ duke@1: boolean varDebugInfo; duke@1: duke@1: /** Switch: emit line number info. duke@1: */ duke@1: boolean lineDebugInfo; duke@1: duke@1: /** Emit line number info if map supplied duke@1: */ duke@1: Position.LineMap lineMap; duke@1: duke@1: /** The constant pool of the current class. duke@1: */ duke@1: final Pool pool; duke@1: duke@1: final MethodSymbol meth; duke@1: duke@1: /** Construct a code object, given the settings of the fatcode, duke@1: * debugging info switches and the CharacterRangeTable. duke@1: */ duke@1: public Code(MethodSymbol meth, duke@1: boolean fatcode, duke@1: Position.LineMap lineMap, duke@1: boolean varDebugInfo, duke@1: StackMapFormat stackMap, duke@1: boolean debugCode, duke@1: CRTable crt, duke@1: Symtab syms, duke@1: Types types, duke@1: Pool pool) { duke@1: this.meth = meth; duke@1: this.fatcode = fatcode; duke@1: this.lineMap = lineMap; duke@1: this.lineDebugInfo = lineMap != null; duke@1: this.varDebugInfo = varDebugInfo; duke@1: this.crt = crt; duke@1: this.syms = syms; duke@1: this.types = types; duke@1: this.debugCode = debugCode; duke@1: this.stackMap = stackMap; duke@1: switch (stackMap) { duke@1: case CLDC: duke@1: case JSR202: duke@1: this.needStackMap = true; duke@1: break; duke@1: default: duke@1: this.needStackMap = false; duke@1: } duke@1: state = new State(); duke@1: lvar = new LocalVar[20]; duke@1: this.pool = pool; duke@1: } duke@1: duke@1: duke@1: /* ************************************************************************** duke@1: * Typecodes & related stuff duke@1: ****************************************************************************/ duke@1: duke@1: /** Given a type, return its type code (used implicitly in the duke@1: * JVM architecture). duke@1: */ duke@1: public static int typecode(Type type) { duke@1: switch (type.tag) { duke@1: case BYTE: return BYTEcode; duke@1: case SHORT: return SHORTcode; duke@1: case CHAR: return CHARcode; duke@1: case INT: return INTcode; duke@1: case LONG: return LONGcode; duke@1: case FLOAT: return FLOATcode; duke@1: case DOUBLE: return DOUBLEcode; duke@1: case BOOLEAN: return BYTEcode; duke@1: case VOID: return VOIDcode; duke@1: case CLASS: duke@1: case ARRAY: duke@1: case METHOD: duke@1: case BOT: duke@1: case TYPEVAR: duke@1: case UNINITIALIZED_THIS: duke@1: case UNINITIALIZED_OBJECT: duke@1: return OBJECTcode; duke@1: default: throw new AssertionError("typecode " + type.tag); duke@1: } duke@1: } duke@1: duke@1: /** Collapse type code for subtypes of int to INTcode. duke@1: */ duke@1: public static int truncate(int tc) { duke@1: switch (tc) { duke@1: case BYTEcode: case SHORTcode: case CHARcode: return INTcode; duke@1: default: return tc; duke@1: } duke@1: } duke@1: duke@1: /** The width in bytes of objects of the type. duke@1: */ duke@1: public static int width(int typecode) { duke@1: switch (typecode) { duke@1: case LONGcode: case DOUBLEcode: return 2; duke@1: case VOIDcode: return 0; duke@1: default: return 1; duke@1: } duke@1: } duke@1: duke@1: public static int width(Type type) { duke@1: return type == null ? 1 : width(typecode(type)); duke@1: } duke@1: duke@1: /** The total width taken up by a vector of objects. duke@1: */ duke@1: public static int width(List types) { duke@1: int w = 0; duke@1: for (List l = types; l.nonEmpty(); l = l.tail) duke@1: w = w + width(l.head); duke@1: return w; duke@1: } duke@1: duke@1: /** Given a type, return its code for allocating arrays of that type. duke@1: */ duke@1: public static int arraycode(Type type) { duke@1: switch (type.tag) { duke@1: case BYTE: return 8; duke@1: case BOOLEAN: return 4; duke@1: case SHORT: return 9; duke@1: case CHAR: return 5; duke@1: case INT: return 10; duke@1: case LONG: return 11; duke@1: case FLOAT: return 6; duke@1: case DOUBLE: return 7; duke@1: case CLASS: return 0; duke@1: case ARRAY: return 1; duke@1: default: throw new AssertionError("arraycode " + type); duke@1: } duke@1: } duke@1: duke@1: duke@1: /* ************************************************************************** duke@1: * Emit code duke@1: ****************************************************************************/ duke@1: duke@1: /** The current output code pointer. duke@1: */ duke@1: public int curPc() { duke@1: if (pendingJumps != null) resolvePending(); duke@1: if (pendingStatPos != Position.NOPOS) markStatBegin(); duke@1: fixedPc = true; duke@1: return cp; duke@1: } duke@1: duke@1: /** Emit a byte of code. duke@1: */ duke@1: private void emit1(int od) { duke@1: if (!alive) return; duke@1: if (cp == code.length) { duke@1: byte[] newcode = new byte[cp * 2]; duke@1: System.arraycopy(code, 0, newcode, 0, cp); duke@1: code = newcode; duke@1: } duke@1: code[cp++] = (byte)od; duke@1: } duke@1: duke@1: /** Emit two bytes of code. duke@1: */ duke@1: private void emit2(int od) { duke@1: if (!alive) return; duke@1: if (cp + 2 > code.length) { duke@1: emit1(od >> 8); duke@1: emit1(od); duke@1: } else { duke@1: code[cp++] = (byte)(od >> 8); duke@1: code[cp++] = (byte)od; duke@1: } duke@1: } duke@1: duke@1: /** Emit four bytes of code. duke@1: */ duke@1: public void emit4(int od) { duke@1: if (!alive) return; duke@1: if (cp + 4 > code.length) { duke@1: emit1(od >> 24); duke@1: emit1(od >> 16); duke@1: emit1(od >> 8); duke@1: emit1(od); duke@1: } else { duke@1: code[cp++] = (byte)(od >> 24); duke@1: code[cp++] = (byte)(od >> 16); duke@1: code[cp++] = (byte)(od >> 8); duke@1: code[cp++] = (byte)od; duke@1: } duke@1: } duke@1: duke@1: /** Emit an opcode. duke@1: */ duke@1: private void emitop(int op) { duke@1: if (pendingJumps != null) resolvePending(); duke@1: if (alive) { duke@1: if (pendingStatPos != Position.NOPOS) duke@1: markStatBegin(); duke@1: if (pendingStackMap) { duke@1: pendingStackMap = false; duke@1: emitStackMap(); duke@1: } duke@1: if (debugCode) duke@1: System.err.println("emit@" + cp + " stack=" + duke@1: state.stacksize + ": " + duke@1: mnem(op)); duke@1: emit1(op); duke@1: } duke@1: } duke@1: duke@1: void postop() { duke@1: assert alive || state.stacksize == 0; duke@1: } duke@1: duke@1: /** Emit a multinewarray instruction. duke@1: */ duke@1: public void emitMultianewarray(int ndims, int type, Type arrayType) { duke@1: emitop(multianewarray); duke@1: if (!alive) return; duke@1: emit2(type); duke@1: emit1(ndims); duke@1: state.pop(ndims); duke@1: state.push(arrayType); duke@1: } duke@1: duke@1: /** Emit newarray. duke@1: */ duke@1: public void emitNewarray(int elemcode, Type arrayType) { duke@1: emitop(newarray); duke@1: if (!alive) return; duke@1: emit1(elemcode); duke@1: state.pop(1); // count duke@1: state.push(arrayType); duke@1: } duke@1: duke@1: /** Emit anewarray. duke@1: */ duke@1: public void emitAnewarray(int od, Type arrayType) { duke@1: emitop(anewarray); duke@1: if (!alive) return; duke@1: emit2(od); duke@1: state.pop(1); duke@1: state.push(arrayType); duke@1: } duke@1: duke@1: /** Emit an invokeinterface instruction. duke@1: */ duke@1: public void emitInvokeinterface(int meth, Type mtype) { duke@1: int argsize = width(mtype.getParameterTypes()); duke@1: emitop(invokeinterface); duke@1: if (!alive) return; duke@1: emit2(meth); duke@1: emit1(argsize + 1); duke@1: emit1(0); duke@1: state.pop(argsize + 1); duke@1: state.push(mtype.getReturnType()); duke@1: } duke@1: duke@1: /** Emit an invokespecial instruction. duke@1: */ duke@1: public void emitInvokespecial(int meth, Type mtype) { duke@1: int argsize = width(mtype.getParameterTypes()); duke@1: emitop(invokespecial); duke@1: if (!alive) return; duke@1: emit2(meth); duke@1: Symbol sym = (Symbol)pool.pool[meth]; duke@1: state.pop(argsize); duke@1: if (sym.isConstructor()) duke@1: state.markInitialized((UninitializedType)state.peek()); duke@1: state.pop(1); duke@1: state.push(mtype.getReturnType()); duke@1: } duke@1: duke@1: /** Emit an invokestatic instruction. duke@1: */ duke@1: public void emitInvokestatic(int meth, Type mtype) { duke@1: int argsize = width(mtype.getParameterTypes()); duke@1: emitop(invokestatic); duke@1: if (!alive) return; duke@1: emit2(meth); duke@1: state.pop(argsize); duke@1: state.push(mtype.getReturnType()); duke@1: } duke@1: duke@1: /** Emit an invokevirtual instruction. duke@1: */ duke@1: public void emitInvokevirtual(int meth, Type mtype) { duke@1: int argsize = width(mtype.getParameterTypes()); duke@1: emitop(invokevirtual); duke@1: if (!alive) return; duke@1: emit2(meth); duke@1: state.pop(argsize + 1); duke@1: state.push(mtype.getReturnType()); duke@1: } duke@1: jrose@267: /** Emit an invokedynamic instruction. jrose@267: */ jrose@267: public void emitInvokedynamic(int desc, Type mtype) { jrose@267: // N.B. this format is under consideration by the JSR 292 EG jrose@267: int argsize = width(mtype.getParameterTypes()); jrose@267: emitop(invokedynamic); jrose@267: if (!alive) return; jrose@267: emit2(desc); jrose@267: emit2(0); jrose@267: state.pop(argsize); jrose@267: state.push(mtype.getReturnType()); jrose@267: } jrose@267: duke@1: /** Emit an opcode with no operand field. duke@1: */ duke@1: public void emitop0(int op) { duke@1: emitop(op); duke@1: if (!alive) return; duke@1: switch (op) { duke@1: case aaload: { duke@1: state.pop(1);// index duke@1: Type a = state.stack[state.stacksize-1]; duke@1: state.pop(1); duke@1: state.push(types.erasure(types.elemtype(a))); } duke@1: break; duke@1: case goto_: duke@1: markDead(); duke@1: break; duke@1: case nop: duke@1: case ineg: duke@1: case lneg: duke@1: case fneg: duke@1: case dneg: duke@1: break; duke@1: case aconst_null: duke@1: state.push(syms.botType); duke@1: break; duke@1: case iconst_m1: duke@1: case iconst_0: duke@1: case iconst_1: duke@1: case iconst_2: duke@1: case iconst_3: duke@1: case iconst_4: duke@1: case iconst_5: duke@1: case iload_0: duke@1: case iload_1: duke@1: case iload_2: duke@1: case iload_3: duke@1: state.push(syms.intType); duke@1: break; duke@1: case lconst_0: duke@1: case lconst_1: duke@1: case lload_0: duke@1: case lload_1: duke@1: case lload_2: duke@1: case lload_3: duke@1: state.push(syms.longType); duke@1: break; duke@1: case fconst_0: duke@1: case fconst_1: duke@1: case fconst_2: duke@1: case fload_0: duke@1: case fload_1: duke@1: case fload_2: duke@1: case fload_3: duke@1: state.push(syms.floatType); duke@1: break; duke@1: case dconst_0: duke@1: case dconst_1: duke@1: case dload_0: duke@1: case dload_1: duke@1: case dload_2: duke@1: case dload_3: duke@1: state.push(syms.doubleType); duke@1: break; duke@1: case aload_0: duke@1: state.push(lvar[0].sym.type); duke@1: break; duke@1: case aload_1: duke@1: state.push(lvar[1].sym.type); duke@1: break; duke@1: case aload_2: duke@1: state.push(lvar[2].sym.type); duke@1: break; duke@1: case aload_3: duke@1: state.push(lvar[3].sym.type); duke@1: break; duke@1: case iaload: duke@1: case baload: duke@1: case caload: duke@1: case saload: duke@1: state.pop(2); duke@1: state.push(syms.intType); duke@1: break; duke@1: case laload: duke@1: state.pop(2); duke@1: state.push(syms.longType); duke@1: break; duke@1: case faload: duke@1: state.pop(2); duke@1: state.push(syms.floatType); duke@1: break; duke@1: case daload: duke@1: state.pop(2); duke@1: state.push(syms.doubleType); duke@1: break; duke@1: case istore_0: duke@1: case istore_1: duke@1: case istore_2: duke@1: case istore_3: duke@1: case fstore_0: duke@1: case fstore_1: duke@1: case fstore_2: duke@1: case fstore_3: duke@1: case astore_0: duke@1: case astore_1: duke@1: case astore_2: duke@1: case astore_3: duke@1: case pop: duke@1: case lshr: duke@1: case lshl: duke@1: case lushr: duke@1: state.pop(1); duke@1: break; duke@1: case areturn: duke@1: case ireturn: duke@1: case freturn: duke@1: assert state.nlocks == 0; duke@1: state.pop(1); duke@1: markDead(); duke@1: break; duke@1: case athrow: duke@1: state.pop(1); duke@1: markDead(); duke@1: break; duke@1: case lstore_0: duke@1: case lstore_1: duke@1: case lstore_2: duke@1: case lstore_3: duke@1: case dstore_0: duke@1: case dstore_1: duke@1: case dstore_2: duke@1: case dstore_3: duke@1: case pop2: duke@1: state.pop(2); duke@1: break; duke@1: case lreturn: duke@1: case dreturn: duke@1: assert state.nlocks == 0; duke@1: state.pop(2); duke@1: markDead(); duke@1: break; duke@1: case dup: duke@1: state.push(state.stack[state.stacksize-1]); duke@1: break; duke@1: case return_: duke@1: assert state.nlocks == 0; duke@1: markDead(); duke@1: break; duke@1: case arraylength: duke@1: state.pop(1); duke@1: state.push(syms.intType); duke@1: break; duke@1: case isub: duke@1: case iadd: duke@1: case imul: duke@1: case idiv: duke@1: case imod: duke@1: case ishl: duke@1: case ishr: duke@1: case iushr: duke@1: case iand: duke@1: case ior: duke@1: case ixor: duke@1: state.pop(1); duke@1: // state.pop(1); duke@1: // state.push(syms.intType); duke@1: break; duke@1: case aastore: duke@1: state.pop(3); duke@1: break; duke@1: case land: duke@1: case lor: duke@1: case lxor: duke@1: case lmod: duke@1: case ldiv: duke@1: case lmul: duke@1: case lsub: duke@1: case ladd: duke@1: state.pop(2); duke@1: break; duke@1: case lcmp: duke@1: state.pop(4); duke@1: state.push(syms.intType); duke@1: break; duke@1: case l2i: duke@1: state.pop(2); duke@1: state.push(syms.intType); duke@1: break; duke@1: case i2l: duke@1: state.pop(1); duke@1: state.push(syms.longType); duke@1: break; duke@1: case i2f: duke@1: state.pop(1); duke@1: state.push(syms.floatType); duke@1: break; duke@1: case i2d: duke@1: state.pop(1); duke@1: state.push(syms.doubleType); duke@1: break; duke@1: case l2f: duke@1: state.pop(2); duke@1: state.push(syms.floatType); duke@1: break; duke@1: case l2d: duke@1: state.pop(2); duke@1: state.push(syms.doubleType); duke@1: break; duke@1: case f2i: duke@1: state.pop(1); duke@1: state.push(syms.intType); duke@1: break; duke@1: case f2l: duke@1: state.pop(1); duke@1: state.push(syms.longType); duke@1: break; duke@1: case f2d: duke@1: state.pop(1); duke@1: state.push(syms.doubleType); duke@1: break; duke@1: case d2i: duke@1: state.pop(2); duke@1: state.push(syms.intType); duke@1: break; duke@1: case d2l: duke@1: state.pop(2); duke@1: state.push(syms.longType); duke@1: break; duke@1: case d2f: duke@1: state.pop(2); duke@1: state.push(syms.floatType); duke@1: break; duke@1: case tableswitch: duke@1: case lookupswitch: duke@1: state.pop(1); duke@1: // the caller is responsible for patching up the state duke@1: break; duke@1: case dup_x1: { duke@1: Type val1 = state.pop1(); duke@1: Type val2 = state.pop1(); duke@1: state.push(val1); duke@1: state.push(val2); duke@1: state.push(val1); duke@1: break; duke@1: } duke@1: case bastore: duke@1: state.pop(3); duke@1: break; duke@1: case int2byte: duke@1: case int2char: duke@1: case int2short: duke@1: break; duke@1: case fmul: duke@1: case fadd: duke@1: case fsub: duke@1: case fdiv: duke@1: case fmod: duke@1: state.pop(1); duke@1: break; duke@1: case castore: duke@1: case iastore: duke@1: case fastore: duke@1: case sastore: duke@1: state.pop(3); duke@1: break; duke@1: case lastore: duke@1: case dastore: duke@1: state.pop(4); duke@1: break; duke@1: case dup2: duke@1: if (state.stack[state.stacksize-1] != null) { duke@1: Type value1 = state.pop1(); duke@1: Type value2 = state.pop1(); duke@1: state.push(value2); duke@1: state.push(value1); duke@1: state.push(value2); duke@1: state.push(value1); duke@1: } else { duke@1: Type value = state.pop2(); duke@1: state.push(value); duke@1: state.push(value); duke@1: } duke@1: break; duke@1: case dup2_x1: duke@1: if (state.stack[state.stacksize-1] != null) { duke@1: Type value1 = state.pop1(); duke@1: Type value2 = state.pop1(); duke@1: Type value3 = state.pop1(); duke@1: state.push(value2); duke@1: state.push(value1); duke@1: state.push(value3); duke@1: state.push(value2); duke@1: state.push(value1); duke@1: } else { duke@1: Type value1 = state.pop2(); duke@1: Type value2 = state.pop1(); duke@1: state.push(value1); duke@1: state.push(value2); duke@1: state.push(value1); duke@1: } duke@1: break; duke@1: case dup2_x2: duke@1: if (state.stack[state.stacksize-1] != null) { duke@1: Type value1 = state.pop1(); duke@1: Type value2 = state.pop1(); duke@1: if (state.stack[state.stacksize-1] != null) { duke@1: // form 1 duke@1: Type value3 = state.pop1(); duke@1: Type value4 = state.pop1(); duke@1: state.push(value2); duke@1: state.push(value1); duke@1: state.push(value4); duke@1: state.push(value3); duke@1: state.push(value2); duke@1: state.push(value1); duke@1: } else { duke@1: // form 3 duke@1: Type value3 = state.pop2(); duke@1: state.push(value2); duke@1: state.push(value1); duke@1: state.push(value3); duke@1: state.push(value2); duke@1: state.push(value1); duke@1: } duke@1: } else { duke@1: Type value1 = state.pop2(); duke@1: if (state.stack[state.stacksize-1] != null) { duke@1: // form 2 duke@1: Type value2 = state.pop1(); duke@1: Type value3 = state.pop1(); duke@1: state.push(value1); duke@1: state.push(value3); duke@1: state.push(value2); duke@1: state.push(value1); duke@1: } else { duke@1: // form 4 duke@1: Type value2 = state.pop2(); duke@1: state.push(value1); duke@1: state.push(value2); duke@1: state.push(value1); duke@1: } duke@1: } duke@1: break; duke@1: case dup_x2: { duke@1: Type value1 = state.pop1(); duke@1: if (state.stack[state.stacksize-1] != null) { duke@1: // form 1 duke@1: Type value2 = state.pop1(); duke@1: Type value3 = state.pop1(); duke@1: state.push(value1); duke@1: state.push(value3); duke@1: state.push(value2); duke@1: state.push(value1); duke@1: } else { duke@1: // form 2 duke@1: Type value2 = state.pop2(); duke@1: state.push(value1); duke@1: state.push(value2); duke@1: state.push(value1); duke@1: } duke@1: } duke@1: break; duke@1: case fcmpl: duke@1: case fcmpg: duke@1: state.pop(2); duke@1: state.push(syms.intType); duke@1: break; duke@1: case dcmpl: duke@1: case dcmpg: duke@1: state.pop(4); duke@1: state.push(syms.intType); duke@1: break; duke@1: case swap: { duke@1: Type value1 = state.pop1(); duke@1: Type value2 = state.pop1(); duke@1: state.push(value1); duke@1: state.push(value2); duke@1: break; duke@1: } duke@1: case dadd: duke@1: case dsub: duke@1: case dmul: duke@1: case ddiv: duke@1: case dmod: duke@1: state.pop(2); duke@1: break; duke@1: case ret: duke@1: markDead(); duke@1: break; duke@1: case wide: duke@1: // must be handled by the caller. duke@1: return; duke@1: case monitorenter: duke@1: case monitorexit: duke@1: state.pop(1); duke@1: break; duke@1: duke@1: default: duke@1: throw new AssertionError(mnem(op)); duke@1: } duke@1: postop(); duke@1: } duke@1: duke@1: /** Emit an opcode with a one-byte operand field. duke@1: */ duke@1: public void emitop1(int op, int od) { duke@1: emitop(op); duke@1: if (!alive) return; duke@1: emit1(od); duke@1: switch (op) { duke@1: case bipush: duke@1: state.push(syms.intType); duke@1: break; duke@1: case ldc1: duke@1: state.push(typeForPool(pool.pool[od])); duke@1: break; duke@1: default: duke@1: throw new AssertionError(mnem(op)); duke@1: } duke@1: postop(); duke@1: } duke@1: duke@1: /** The type of a constant pool entry. */ duke@1: private Type typeForPool(Object o) { duke@1: if (o instanceof Integer) return syms.intType; duke@1: if (o instanceof Float) return syms.floatType; duke@1: if (o instanceof String) return syms.stringType; duke@1: if (o instanceof Long) return syms.longType; duke@1: if (o instanceof Double) return syms.doubleType; duke@1: if (o instanceof ClassSymbol) return syms.classType; duke@1: if (o instanceof Type.ArrayType) return syms.classType; duke@1: throw new AssertionError(o); duke@1: } duke@1: duke@1: /** Emit an opcode with a one-byte operand field; duke@1: * widen if field does not fit in a byte. duke@1: */ duke@1: public void emitop1w(int op, int od) { duke@1: if (od > 0xFF) { duke@1: emitop(wide); duke@1: emitop(op); duke@1: emit2(od); duke@1: } else { duke@1: emitop(op); duke@1: emit1(od); duke@1: } duke@1: if (!alive) return; duke@1: switch (op) { duke@1: case iload: duke@1: state.push(syms.intType); duke@1: break; duke@1: case lload: duke@1: state.push(syms.longType); duke@1: break; duke@1: case fload: duke@1: state.push(syms.floatType); duke@1: break; duke@1: case dload: duke@1: state.push(syms.doubleType); duke@1: break; duke@1: case aload: duke@1: state.push(lvar[od].sym.type); duke@1: break; duke@1: case lstore: duke@1: case dstore: duke@1: state.pop(2); duke@1: break; duke@1: case istore: duke@1: case fstore: duke@1: case astore: duke@1: state.pop(1); duke@1: break; duke@1: case ret: duke@1: markDead(); duke@1: break; duke@1: default: duke@1: throw new AssertionError(mnem(op)); duke@1: } duke@1: postop(); duke@1: } duke@1: duke@1: /** Emit an opcode with two one-byte operand fields; duke@1: * widen if either field does not fit in a byte. duke@1: */ duke@1: public void emitop1w(int op, int od1, int od2) { duke@1: if (od1 > 0xFF || od2 < -128 || od2 > 127) { duke@1: emitop(wide); duke@1: emitop(op); duke@1: emit2(od1); duke@1: emit2(od2); duke@1: } else { duke@1: emitop(op); duke@1: emit1(od1); duke@1: emit1(od2); duke@1: } duke@1: if (!alive) return; duke@1: switch (op) { duke@1: case iinc: duke@1: break; duke@1: default: duke@1: throw new AssertionError(mnem(op)); duke@1: } duke@1: } duke@1: duke@1: /** Emit an opcode with a two-byte operand field. duke@1: */ duke@1: public void emitop2(int op, int od) { duke@1: emitop(op); duke@1: if (!alive) return; duke@1: emit2(od); duke@1: switch (op) { duke@1: case getstatic: duke@1: state.push(((Symbol)(pool.pool[od])).erasure(types)); duke@1: break; duke@1: case putstatic: duke@1: state.pop(((Symbol)(pool.pool[od])).erasure(types)); duke@1: break; duke@1: case new_: duke@1: state.push(uninitializedObject(((Symbol)(pool.pool[od])).erasure(types), cp-3)); duke@1: break; duke@1: case sipush: duke@1: state.push(syms.intType); duke@1: break; duke@1: case if_acmp_null: duke@1: case if_acmp_nonnull: duke@1: case ifeq: duke@1: case ifne: duke@1: case iflt: duke@1: case ifge: duke@1: case ifgt: duke@1: case ifle: duke@1: state.pop(1); duke@1: break; duke@1: case if_icmpeq: duke@1: case if_icmpne: duke@1: case if_icmplt: duke@1: case if_icmpge: duke@1: case if_icmpgt: duke@1: case if_icmple: duke@1: case if_acmpeq: duke@1: case if_acmpne: duke@1: state.pop(2); duke@1: break; duke@1: case goto_: duke@1: markDead(); duke@1: break; duke@1: case putfield: duke@1: state.pop(((Symbol)(pool.pool[od])).erasure(types)); duke@1: state.pop(1); // object ref duke@1: break; duke@1: case getfield: duke@1: state.pop(1); // object ref duke@1: state.push(((Symbol)(pool.pool[od])).erasure(types)); duke@1: break; duke@1: case checkcast: { duke@1: state.pop(1); // object ref duke@1: Object o = pool.pool[od]; duke@1: Type t = (o instanceof Symbol) duke@1: ? ((Symbol)o).erasure(types) duke@1: : types.erasure(((Type)o)); duke@1: state.push(t); duke@1: break; } duke@1: case ldc2w: duke@1: state.push(typeForPool(pool.pool[od])); duke@1: break; duke@1: case instanceof_: duke@1: state.pop(1); duke@1: state.push(syms.intType); duke@1: break; duke@1: case ldc2: duke@1: state.push(typeForPool(pool.pool[od])); duke@1: break; duke@1: case jsr: duke@1: break; duke@1: default: duke@1: throw new AssertionError(mnem(op)); duke@1: } duke@1: // postop(); duke@1: } duke@1: duke@1: /** Emit an opcode with a four-byte operand field. duke@1: */ duke@1: public void emitop4(int op, int od) { duke@1: emitop(op); duke@1: if (!alive) return; duke@1: emit4(od); duke@1: switch (op) { duke@1: case goto_w: duke@1: markDead(); duke@1: break; duke@1: case jsr_w: duke@1: break; duke@1: default: duke@1: throw new AssertionError(mnem(op)); duke@1: } duke@1: // postop(); duke@1: } duke@1: duke@1: /** Align code pointer to next `incr' boundary. duke@1: */ duke@1: public void align(int incr) { duke@1: if (alive) duke@1: while (cp % incr != 0) emitop0(nop); duke@1: } duke@1: duke@1: /** Place a byte into code at address pc. Pre: pc + 1 <= cp. duke@1: */ duke@1: private void put1(int pc, int op) { duke@1: code[pc] = (byte)op; duke@1: } duke@1: duke@1: /** Place two bytes into code at address pc. Pre: pc + 2 <= cp. duke@1: */ duke@1: private void put2(int pc, int od) { duke@1: // pre: pc + 2 <= cp duke@1: put1(pc, od >> 8); duke@1: put1(pc+1, od); duke@1: } duke@1: duke@1: /** Place four bytes into code at address pc. Pre: pc + 4 <= cp. duke@1: */ duke@1: public void put4(int pc, int od) { duke@1: // pre: pc + 4 <= cp duke@1: put1(pc , od >> 24); duke@1: put1(pc+1, od >> 16); duke@1: put1(pc+2, od >> 8); duke@1: put1(pc+3, od); duke@1: } duke@1: duke@1: /** Return code byte at position pc as an unsigned int. duke@1: */ duke@1: private int get1(int pc) { duke@1: return code[pc] & 0xFF; duke@1: } duke@1: duke@1: /** Return two code bytes at position pc as an unsigned int. duke@1: */ duke@1: private int get2(int pc) { duke@1: return (get1(pc) << 8) | get1(pc+1); duke@1: } duke@1: duke@1: /** Return four code bytes at position pc as an int. duke@1: */ duke@1: public int get4(int pc) { duke@1: // pre: pc + 4 <= cp duke@1: return duke@1: (get1(pc) << 24) | duke@1: (get1(pc+1) << 16) | duke@1: (get1(pc+2) << 8) | duke@1: (get1(pc+3)); duke@1: } duke@1: duke@1: /** Is code generation currently enabled? duke@1: */ duke@1: public boolean isAlive() { duke@1: return alive || pendingJumps != null; duke@1: } duke@1: duke@1: /** Switch code generation on/off. duke@1: */ duke@1: public void markDead() { duke@1: alive = false; duke@1: } duke@1: duke@1: /** Declare an entry point; return current code pointer duke@1: */ duke@1: public int entryPoint() { duke@1: int pc = curPc(); duke@1: alive = true; duke@1: pendingStackMap = needStackMap; duke@1: return pc; duke@1: } duke@1: duke@1: /** Declare an entry point with initial state; duke@1: * return current code pointer duke@1: */ duke@1: public int entryPoint(State state) { duke@1: int pc = curPc(); duke@1: alive = true; duke@1: this.state = state.dup(); duke@1: assert state.stacksize <= max_stack; duke@1: if (debugCode) System.err.println("entry point " + state); duke@1: pendingStackMap = needStackMap; duke@1: return pc; duke@1: } duke@1: duke@1: /** Declare an entry point with initial state plus a pushed value; duke@1: * return current code pointer duke@1: */ duke@1: public int entryPoint(State state, Type pushed) { duke@1: int pc = curPc(); duke@1: alive = true; duke@1: this.state = state.dup(); duke@1: assert state.stacksize <= max_stack; duke@1: this.state.push(pushed); duke@1: if (debugCode) System.err.println("entry point " + state); duke@1: pendingStackMap = needStackMap; duke@1: return pc; duke@1: } duke@1: duke@1: duke@1: /************************************************************************** duke@1: * Stack map generation duke@1: *************************************************************************/ duke@1: duke@1: /** An entry in the stack map. */ duke@1: static class StackMapFrame { duke@1: int pc; duke@1: Type[] locals; duke@1: Type[] stack; duke@1: } duke@1: duke@1: /** A buffer of cldc stack map entries. */ duke@1: StackMapFrame[] stackMapBuffer = null; duke@1: duke@1: /** A buffer of compressed StackMapTable entries. */ duke@1: StackMapTableFrame[] stackMapTableBuffer = null; duke@1: int stackMapBufferSize = 0; duke@1: duke@1: /** The last PC at which we generated a stack map. */ duke@1: int lastStackMapPC = -1; duke@1: duke@1: /** The last stack map frame in StackMapTable. */ duke@1: StackMapFrame lastFrame = null; duke@1: duke@1: /** The stack map frame before the last one. */ duke@1: StackMapFrame frameBeforeLast = null; duke@1: duke@1: /** Emit a stack map entry. */ duke@1: public void emitStackMap() { duke@1: int pc = curPc(); duke@1: if (!needStackMap) return; duke@1: duke@1: duke@1: duke@1: switch (stackMap) { duke@1: case CLDC: duke@1: emitCLDCStackMap(pc, getLocalsSize()); duke@1: break; duke@1: case JSR202: duke@1: emitStackMapFrame(pc, getLocalsSize()); duke@1: break; duke@1: default: duke@1: throw new AssertionError("Should have chosen a stackmap format"); duke@1: } duke@1: // DEBUG code follows duke@1: if (debugCode) state.dump(pc); duke@1: } duke@1: duke@1: private int getLocalsSize() { duke@1: int nextLocal = 0; duke@1: for (int i=max_locals-1; i>=0; i--) { duke@1: if (state.defined.isMember(i) && lvar[i] != null) { duke@1: nextLocal = i + width(lvar[i].sym.erasure(types)); duke@1: break; duke@1: } duke@1: } duke@1: return nextLocal; duke@1: } duke@1: duke@1: /** Emit a CLDC stack map frame. */ duke@1: void emitCLDCStackMap(int pc, int localsSize) { duke@1: if (lastStackMapPC == pc) { duke@1: // drop existing stackmap at this offset duke@1: stackMapBuffer[--stackMapBufferSize] = null; duke@1: } duke@1: lastStackMapPC = pc; duke@1: duke@1: if (stackMapBuffer == null) { duke@1: stackMapBuffer = new StackMapFrame[20]; duke@1: } else if (stackMapBuffer.length == stackMapBufferSize) { duke@1: StackMapFrame[] newStackMapBuffer = duke@1: new StackMapFrame[stackMapBufferSize << 1]; duke@1: System.arraycopy(stackMapBuffer, 0, newStackMapBuffer, duke@1: 0, stackMapBufferSize); duke@1: stackMapBuffer = newStackMapBuffer; duke@1: } duke@1: StackMapFrame frame = duke@1: stackMapBuffer[stackMapBufferSize++] = new StackMapFrame(); duke@1: frame.pc = pc; duke@1: duke@1: frame.locals = new Type[localsSize]; duke@1: for (int i=0; i 1) i++; duke@1: } duke@1: } duke@1: frame.locals = new Type[localCount]; duke@1: for (int i=0, j=0; i 1) i++; duke@1: } duke@1: duke@1: int stackCount = 0; duke@1: for (int i=0; i arg_types = ((MethodType)meth.externalType(types)).argtypes; duke@1: int len = arg_types.length(); duke@1: int count = 0; duke@1: if (!meth.isStatic()) { duke@1: Type thisType = meth.owner.type; duke@1: frame.locals = new Type[len+1]; duke@1: if (meth.isConstructor() && thisType != syms.objectType) { duke@1: frame.locals[count++] = UninitializedType.uninitializedThis(thisType); duke@1: } else { duke@1: frame.locals[count++] = types.erasure(thisType); duke@1: } duke@1: } else { duke@1: frame.locals = new Type[len]; duke@1: } duke@1: for (Type arg_type : arg_types) { duke@1: frame.locals[count++] = types.erasure(arg_type); duke@1: } duke@1: frame.pc = -1; duke@1: frame.stack = null; duke@1: return frame; duke@1: } duke@1: duke@1: duke@1: /************************************************************************** duke@1: * Operations having to do with jumps duke@1: *************************************************************************/ duke@1: duke@1: /** A chain represents a list of unresolved jumps. Jump locations duke@1: * are sorted in decreasing order. duke@1: */ duke@1: public static class Chain { duke@1: duke@1: /** The position of the jump instruction. duke@1: */ duke@1: public final int pc; duke@1: duke@1: /** The machine state after the jump instruction. duke@1: * Invariant: all elements of a chain list have the same stacksize duke@1: * and compatible stack and register contents. duke@1: */ duke@1: Code.State state; duke@1: duke@1: /** The next jump in the list. duke@1: */ duke@1: public final Chain next; duke@1: duke@1: /** Construct a chain from its jump position, stacksize, previous duke@1: * chain, and machine state. duke@1: */ duke@1: public Chain(int pc, Chain next, Code.State state) { duke@1: this.pc = pc; duke@1: this.next = next; duke@1: this.state = state; duke@1: } duke@1: } duke@1: duke@1: /** Negate a branch opcode. duke@1: */ duke@1: public static int negate(int opcode) { duke@1: if (opcode == if_acmp_null) return if_acmp_nonnull; duke@1: else if (opcode == if_acmp_nonnull) return if_acmp_null; duke@1: else return ((opcode + 1) ^ 1) - 1; duke@1: } duke@1: duke@1: /** Emit a jump instruction. duke@1: * Return code pointer of instruction to be patched. duke@1: */ duke@1: public int emitJump(int opcode) { duke@1: if (fatcode) { duke@1: if (opcode == goto_ || opcode == jsr) { duke@1: emitop4(opcode + goto_w - goto_, 0); duke@1: } else { duke@1: emitop2(negate(opcode), 8); duke@1: emitop4(goto_w, 0); duke@1: alive = true; duke@1: pendingStackMap = needStackMap; duke@1: } duke@1: return cp - 5; duke@1: } else { duke@1: emitop2(opcode, 0); duke@1: return cp - 3; duke@1: } duke@1: } duke@1: duke@1: /** Emit a branch with given opcode; return its chain. duke@1: * branch differs from jump in that jsr is treated as no-op. duke@1: */ duke@1: public Chain branch(int opcode) { duke@1: Chain result = null; duke@1: if (opcode == goto_) { duke@1: result = pendingJumps; duke@1: pendingJumps = null; duke@1: } duke@1: if (opcode != dontgoto && isAlive()) { duke@1: result = new Chain(emitJump(opcode), duke@1: result, duke@1: state.dup()); duke@1: fixedPc = fatcode; duke@1: if (opcode == goto_) alive = false; duke@1: } duke@1: return result; duke@1: } duke@1: duke@1: /** Resolve chain to point to given target. duke@1: */ duke@1: public void resolve(Chain chain, int target) { duke@1: boolean changed = false; duke@1: State newState = state; duke@1: for (; chain != null; chain = chain.next) { duke@1: assert state != chain.state; duke@1: assert target > chain.pc || state.stacksize == 0; duke@1: if (target >= cp) { duke@1: target = cp; duke@1: } else if (get1(target) == goto_) { duke@1: if (fatcode) target = target + get4(target + 1); duke@1: else target = target + get2(target + 1); duke@1: } duke@1: if (get1(chain.pc) == goto_ && duke@1: chain.pc + 3 == target && target == cp && !fixedPc) { duke@1: // If goto the next instruction, the jump is not needed: duke@1: // compact the code. duke@1: cp = cp - 3; duke@1: target = target - 3; duke@1: if (chain.next == null) { duke@1: // This is the only jump to the target. Exit the loop duke@1: // without setting new state. The code is reachable duke@1: // from the instruction before goto_. duke@1: alive = true; duke@1: break; duke@1: } duke@1: } else { duke@1: if (fatcode) duke@1: put4(chain.pc + 1, target - chain.pc); duke@1: else if (target - chain.pc < Short.MIN_VALUE || duke@1: target - chain.pc > Short.MAX_VALUE) duke@1: fatcode = true; duke@1: else duke@1: put2(chain.pc + 1, target - chain.pc); duke@1: assert !alive || duke@1: chain.state.stacksize == newState.stacksize && duke@1: chain.state.nlocks == newState.nlocks; duke@1: } duke@1: fixedPc = true; duke@1: if (cp == target) { duke@1: changed = true; duke@1: if (debugCode) duke@1: System.err.println("resolving chain state=" + chain.state); duke@1: if (alive) { duke@1: newState = chain.state.join(newState); duke@1: } else { duke@1: newState = chain.state; duke@1: alive = true; duke@1: } duke@1: } duke@1: } duke@1: assert !changed || state != newState; duke@1: if (state != newState) { duke@1: setDefined(newState.defined); duke@1: state = newState; duke@1: pendingStackMap = needStackMap; duke@1: } duke@1: } duke@1: duke@1: /** Resolve chain to point to current code pointer. duke@1: */ duke@1: public void resolve(Chain chain) { duke@1: assert duke@1: !alive || duke@1: chain==null || duke@1: state.stacksize == chain.state.stacksize && duke@1: state.nlocks == chain.state.nlocks; duke@1: pendingJumps = mergeChains(chain, pendingJumps); duke@1: } duke@1: duke@1: /** Resolve any pending jumps. duke@1: */ duke@1: public void resolvePending() { duke@1: Chain x = pendingJumps; duke@1: pendingJumps = null; duke@1: resolve(x, cp); duke@1: } duke@1: duke@1: /** Merge the jumps in of two chains into one. duke@1: */ duke@1: public static Chain mergeChains(Chain chain1, Chain chain2) { duke@1: // recursive merge sort duke@1: if (chain2 == null) return chain1; duke@1: if (chain1 == null) return chain2; duke@1: assert duke@1: chain1.state.stacksize == chain2.state.stacksize && duke@1: chain1.state.nlocks == chain2.state.nlocks; duke@1: if (chain1.pc < chain2.pc) duke@1: return new Chain( duke@1: chain2.pc, duke@1: mergeChains(chain1, chain2.next), duke@1: chain2.state); duke@1: return new Chain( duke@1: chain1.pc, duke@1: mergeChains(chain1.next, chain2), duke@1: chain1.state); duke@1: } duke@1: duke@1: duke@1: /* ************************************************************************** duke@1: * Catch clauses duke@1: ****************************************************************************/ duke@1: duke@1: /** Add a catch clause to code. duke@1: */ duke@1: public void addCatch( duke@1: char startPc, char endPc, char handlerPc, char catchType) { duke@1: catchInfo.append(new char[]{startPc, endPc, handlerPc, catchType}); duke@1: } duke@1: duke@1: duke@1: /* ************************************************************************** duke@1: * Line numbers duke@1: ****************************************************************************/ duke@1: duke@1: /** Add a line number entry. duke@1: */ duke@1: public void addLineNumber(char startPc, char lineNumber) { duke@1: if (lineDebugInfo) { duke@1: if (lineInfo.nonEmpty() && lineInfo.head[0] == startPc) duke@1: lineInfo = lineInfo.tail; duke@1: if (lineInfo.isEmpty() || lineInfo.head[1] != lineNumber) duke@1: lineInfo = lineInfo.prepend(new char[]{startPc, lineNumber}); duke@1: } duke@1: } duke@1: duke@1: /** Mark beginning of statement. duke@1: */ duke@1: public void statBegin(int pos) { duke@1: if (pos != Position.NOPOS) { duke@1: pendingStatPos = pos; duke@1: } duke@1: } duke@1: duke@1: /** Force stat begin eagerly duke@1: */ duke@1: public void markStatBegin() { duke@1: if (alive && lineDebugInfo) { duke@1: int line = lineMap.getLineNumber(pendingStatPos); duke@1: char cp1 = (char)cp; duke@1: char line1 = (char)line; duke@1: if (cp1 == cp && line1 == line) duke@1: addLineNumber(cp1, line1); duke@1: } duke@1: pendingStatPos = Position.NOPOS; duke@1: } duke@1: duke@1: duke@1: /* ************************************************************************** duke@1: * Simulated VM machine state duke@1: ****************************************************************************/ duke@1: duke@1: class State implements Cloneable { duke@1: /** The set of registers containing values. */ duke@1: Bits defined; duke@1: duke@1: /** The (types of the) contents of the machine stack. */ duke@1: Type[] stack; duke@1: duke@1: /** The first stack position currently unused. */ duke@1: int stacksize; duke@1: duke@1: /** The numbers of registers containing locked monitors. */ duke@1: int[] locks; duke@1: int nlocks; duke@1: duke@1: State() { duke@1: defined = new Bits(); duke@1: stack = new Type[16]; duke@1: } duke@1: duke@1: State dup() { duke@1: try { duke@1: State state = (State)super.clone(); duke@1: state.defined = defined.dup(); duke@1: state.stack = stack.clone(); duke@1: if (locks != null) state.locks = locks.clone(); duke@1: if (debugCode) { duke@1: System.err.println("duping state " + this); duke@1: dump(); duke@1: } duke@1: return state; duke@1: } catch (CloneNotSupportedException ex) { duke@1: throw new AssertionError(ex); duke@1: } duke@1: } duke@1: duke@1: void lock(int register) { duke@1: if (locks == null) { duke@1: locks = new int[20]; duke@1: } else if (locks.length == nlocks) { duke@1: int[] newLocks = new int[locks.length << 1]; duke@1: System.arraycopy(locks, 0, newLocks, 0, locks.length); duke@1: locks = newLocks; duke@1: } duke@1: locks[nlocks] = register; duke@1: nlocks++; duke@1: } duke@1: duke@1: void unlock(int register) { duke@1: nlocks--; duke@1: assert locks[nlocks] == register; duke@1: locks[nlocks] = -1; duke@1: } duke@1: duke@1: void push(Type t) { duke@1: if (debugCode) System.err.println(" pushing " + t); duke@1: switch (t.tag) { duke@1: case TypeTags.VOID: duke@1: return; duke@1: case TypeTags.BYTE: duke@1: case TypeTags.CHAR: duke@1: case TypeTags.SHORT: duke@1: case TypeTags.BOOLEAN: duke@1: t = syms.intType; duke@1: break; duke@1: default: duke@1: break; duke@1: } duke@1: if (stacksize+2 >= stack.length) { duke@1: Type[] newstack = new Type[2*stack.length]; duke@1: System.arraycopy(stack, 0, newstack, 0, stack.length); duke@1: stack = newstack; duke@1: } duke@1: stack[stacksize++] = t; duke@1: switch (width(t)) { duke@1: case 1: duke@1: break; duke@1: case 2: duke@1: stack[stacksize++] = null; duke@1: break; duke@1: default: duke@1: throw new AssertionError(t); duke@1: } duke@1: if (stacksize > max_stack) duke@1: max_stack = stacksize; duke@1: } duke@1: duke@1: Type pop1() { duke@1: if (debugCode) System.err.println(" popping " + 1); duke@1: stacksize--; duke@1: Type result = stack[stacksize]; duke@1: stack[stacksize] = null; duke@1: assert result != null && width(result) == 1; duke@1: return result; duke@1: } duke@1: duke@1: Type peek() { duke@1: return stack[stacksize-1]; duke@1: } duke@1: duke@1: Type pop2() { duke@1: if (debugCode) System.err.println(" popping " + 2); duke@1: stacksize -= 2; duke@1: Type result = stack[stacksize]; duke@1: stack[stacksize] = null; duke@1: assert stack[stacksize+1] == null; duke@1: assert result != null && width(result) == 2; duke@1: return result; duke@1: } duke@1: duke@1: void pop(int n) { duke@1: if (debugCode) System.err.println(" popping " + n); duke@1: while (n > 0) { duke@1: stack[--stacksize] = null; duke@1: n--; duke@1: } duke@1: } duke@1: duke@1: void pop(Type t) { duke@1: pop(width(t)); duke@1: } duke@1: duke@1: /** Force the top of the stack to be treated as this supertype duke@1: * of its current type. */ duke@1: void forceStackTop(Type t) { duke@1: if (!alive) return; duke@1: switch (t.tag) { duke@1: case CLASS: duke@1: case ARRAY: duke@1: int width = width(t); duke@1: Type old = stack[stacksize-width]; duke@1: assert types.isSubtype(types.erasure(old), duke@1: types.erasure(t)); duke@1: stack[stacksize-width] = t; duke@1: break; duke@1: default: duke@1: } duke@1: } duke@1: duke@1: void markInitialized(UninitializedType old) { duke@1: Type newtype = old.initializedType(); duke@1: for (int i=0; i=0; i--) { duke@1: if (defined.isMember(i)) { duke@1: lastLocal = i; duke@1: break; duke@1: } duke@1: } duke@1: if (lastLocal >= 0) duke@1: System.err.println(" locals:"); duke@1: for (int i=0; i<=lastLocal; i++) { duke@1: System.err.print(" " + i + ": "); duke@1: if (defined.isMember(i)) { duke@1: LocalVar var = lvar[i]; duke@1: if (var == null) { duke@1: System.err.println("(none)"); duke@1: } else if (var.sym == null) duke@1: System.err.println("UNKNOWN!"); duke@1: else duke@1: System.err.println("" + var.sym + " of type " + duke@1: var.sym.erasure(types)); duke@1: } else { duke@1: System.err.println("undefined"); duke@1: } duke@1: } duke@1: if (nlocks != 0) { duke@1: System.err.print(" locks:"); duke@1: for (int i=0; i