/** Write the exceptions table */ void writeExceptions( Environment env, DataOutputStream out, ConstantPool tab, Instruction first, Instruction last) throws IOException { for (Instruction inst = first; inst != last.next; inst = inst.next) { if (inst.opc == opc_try) { TryData td = (TryData) inst.value; writeExceptions(env, out, tab, inst.next, td.getEndLabel()); for (Enumeration e = td.catches.elements(); e.hasMoreElements(); ) { CatchData cd = (CatchData) e.nextElement(); // System.out.println("EXCEPTION: " + env.getSource() + ", pc=" + inst.pc + ", end=" + // td.getEndLabel().pc + ", hdl=" + cd.getLabel().pc + ", tp=" + cd.getType()); out.writeShort(inst.pc); out.writeShort(td.getEndLabel().pc); out.writeShort(cd.getLabel().pc); if (cd.getType() != null) { out.writeShort(tab.index(cd.getType())); } else { out.writeShort(0); } } inst = td.getEndLabel(); } } }
/** Optimize instructions and mark those that can be reached */ void optimize(Environment env, Label lbl) { lbl.pc = REACHED; for (Instruction inst = lbl.next; inst != null; inst = inst.next) { switch (inst.pc) { case NOTREACHED: inst.optimize(env); inst.pc = REACHED; break; case REACHED: return; case NEEDED: break; } switch (inst.opc) { case opc_label: case opc_dead: if (inst.pc == REACHED) { inst.pc = NOTREACHED; } break; case opc_ifeq: case opc_ifne: case opc_ifgt: case opc_ifge: case opc_iflt: case opc_ifle: case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpgt: case opc_if_icmpge: case opc_if_icmplt: case opc_if_icmple: case opc_if_acmpeq: case opc_if_acmpne: case opc_ifnull: case opc_ifnonnull: optimize(env, (Label) inst.value); break; case opc_goto: optimize(env, (Label) inst.value); return; case opc_jsr: optimize(env, (Label) inst.value); break; case opc_ret: case opc_return: case opc_ireturn: case opc_lreturn: case opc_freturn: case opc_dreturn: case opc_areturn: case opc_athrow: return; case opc_tableswitch: case opc_lookupswitch: { SwitchData sw = (SwitchData) inst.value; optimize(env, sw.defaultLabel); for (Enumeration e = sw.tab.elements(); e.hasMoreElements(); ) { optimize(env, (Label) e.nextElement()); } return; } case opc_try: { TryData td = (TryData) inst.value; td.getEndLabel().pc = NEEDED; for (Enumeration e = td.catches.elements(); e.hasMoreElements(); ) { CatchData cd = (CatchData) e.nextElement(); optimize(env, cd.getLabel()); } break; } } } }
/** * Figure out when registers contain a legal value. This is done using a simple data flow * algorithm. This information is later used to generate the local variable table. */ void flowFields(Environment env, Label lbl, MemberDefinition locals[]) { if (lbl.locals != null) { // Been here before. Erase any conflicts. MemberDefinition f[] = lbl.locals; for (int i = 0; i < maxvar; i++) { if (f[i] != locals[i]) { f[i] = null; } } return; } // Remember the set of active registers at this point lbl.locals = new MemberDefinition[maxvar]; System.arraycopy(locals, 0, lbl.locals, 0, maxvar); MemberDefinition newlocals[] = new MemberDefinition[maxvar]; System.arraycopy(locals, 0, newlocals, 0, maxvar); locals = newlocals; for (Instruction inst = lbl.next; inst != null; inst = inst.next) { switch (inst.opc) { case opc_istore: case opc_istore_0: case opc_istore_1: case opc_istore_2: case opc_istore_3: case opc_fstore: case opc_fstore_0: case opc_fstore_1: case opc_fstore_2: case opc_fstore_3: case opc_astore: case opc_astore_0: case opc_astore_1: case opc_astore_2: case opc_astore_3: case opc_lstore: case opc_lstore_0: case opc_lstore_1: case opc_lstore_2: case opc_lstore_3: case opc_dstore: case opc_dstore_0: case opc_dstore_1: case opc_dstore_2: case opc_dstore_3: if (inst.value instanceof LocalVariable) { LocalVariable v = (LocalVariable) inst.value; locals[v.slot] = v.field; } break; case opc_label: flowFields(env, (Label) inst, locals); return; case opc_ifeq: case opc_ifne: case opc_ifgt: case opc_ifge: case opc_iflt: case opc_ifle: case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpgt: case opc_if_icmpge: case opc_if_icmplt: case opc_if_icmple: case opc_if_acmpeq: case opc_if_acmpne: case opc_ifnull: case opc_ifnonnull: case opc_jsr: flowFields(env, (Label) inst.value, locals); break; case opc_goto: flowFields(env, (Label) inst.value, locals); return; case opc_return: case opc_ireturn: case opc_lreturn: case opc_freturn: case opc_dreturn: case opc_areturn: case opc_athrow: case opc_ret: return; case opc_tableswitch: case opc_lookupswitch: { SwitchData sw = (SwitchData) inst.value; flowFields(env, sw.defaultLabel, locals); for (Enumeration e = sw.tab.elements(); e.hasMoreElements(); ) { flowFields(env, (Label) e.nextElement(), locals); } return; } case opc_try: { Vector catches = ((TryData) inst.value).catches; for (Enumeration e = catches.elements(); e.hasMoreElements(); ) { CatchData cd = (CatchData) e.nextElement(); flowFields(env, cd.getLabel(), locals); } break; } } } }
/** Determine stack size, count local variables */ void balance(Label lbl, int depth) { for (Instruction inst = lbl; inst != null; inst = inst.next) { // Environment.debugOutput(inst.toString() + ": " + depth + " => " + // (depth + inst.balance())); depth += inst.balance(); if (depth < 0) { throw new CompilerError("stack under flow: " + inst.toString() + " = " + depth); } if (depth > maxdepth) { maxdepth = depth; } switch (inst.opc) { case opc_label: lbl = (Label) inst; if (inst.pc == REACHED) { if (lbl.depth != depth) { throw new CompilerError( "stack depth error " + depth + "/" + lbl.depth + ": " + inst.toString()); } return; } lbl.pc = REACHED; lbl.depth = depth; break; case opc_ifeq: case opc_ifne: case opc_ifgt: case opc_ifge: case opc_iflt: case opc_ifle: case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpgt: case opc_if_icmpge: case opc_if_icmplt: case opc_if_icmple: case opc_if_acmpeq: case opc_if_acmpne: case opc_ifnull: case opc_ifnonnull: balance((Label) inst.value, depth); break; case opc_goto: balance((Label) inst.value, depth); return; case opc_jsr: balance((Label) inst.value, depth + 1); break; case opc_ret: case opc_return: case opc_ireturn: case opc_lreturn: case opc_freturn: case opc_dreturn: case opc_areturn: case opc_athrow: return; case opc_iload: case opc_fload: case opc_aload: case opc_istore: case opc_fstore: case opc_astore: { int v = ((inst.value instanceof Number) ? ((Number) inst.value).intValue() : ((LocalVariable) inst.value).slot) + 1; if (v > maxvar) maxvar = v; break; } case opc_lload: case opc_dload: case opc_lstore: case opc_dstore: { int v = ((inst.value instanceof Number) ? ((Number) inst.value).intValue() : ((LocalVariable) inst.value).slot) + 2; if (v > maxvar) maxvar = v; break; } case opc_iinc: { int v = ((int[]) inst.value)[0] + 1; if (v > maxvar) maxvar = v + 1; break; } case opc_tableswitch: case opc_lookupswitch: { SwitchData sw = (SwitchData) inst.value; balance(sw.defaultLabel, depth); for (Enumeration e = sw.tab.elements(); e.hasMoreElements(); ) { balance((Label) e.nextElement(), depth); } return; } case opc_try: { TryData td = (TryData) inst.value; for (Enumeration e = td.catches.elements(); e.hasMoreElements(); ) { CatchData cd = (CatchData) e.nextElement(); balance(cd.getLabel(), depth + 1); } break; } } } }