/** Generate code */ public void write(Environment env, DataOutputStream out, MemberDefinition field, ConstantPool tab) throws IOException { // listing(System.out); if ((field != null) && field.getArguments() != null) { int sum = 0; Vector v = field.getArguments(); for (Enumeration e = v.elements(); e.hasMoreElements(); ) { MemberDefinition f = ((MemberDefinition) e.nextElement()); sum += f.getType().stackSize(); } maxvar = sum; } // Make sure the stack balances. Also calculate maxvar and maxstack try { balance(first, 0); } catch (CompilerError e) { System.out.println("ERROR: " + e); listing(System.out); throw e; } // Assign PCs int pc = 0, nexceptions = 0; for (Instruction inst = first; inst != null; inst = inst.next) { inst.pc = pc; int sz = inst.size(tab); if (pc < 65536 && (pc + sz) >= 65536) { env.error(inst.where, "warn.method.too.long"); } pc += sz; if (inst.opc == opc_try) { nexceptions += ((TryData) inst.value).catches.size(); } } // Write header out.writeShort(maxdepth); out.writeShort(maxvar); out.writeInt(maxpc = pc); // Generate code for (Instruction inst = first.next; inst != null; inst = inst.next) { inst.write(out, tab); } // write exceptions out.writeShort(nexceptions); if (nexceptions > 0) { // listing(System.out); writeExceptions(env, out, tab, first, last); } }
/** 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; } } } }