/** * CodeAttr's are used as a bag to hold lists of instructions * until it is time to put them into a Class. * @see ClassEnv#addMethod * @author $Author: jonmeyerny $ * @version $Revision: 1.1 $ */ package jas; import java.io.*; import java.util.*; public class CodeAttr { static final CP attr = new AsciiCP("Code"); short stack_size, num_locals; int code_size; Vector insns; Hashtable insn_pc; Catchtable ctb; LineTableAttr ltab; LocalVarTableAttr lvar; LocalVarTypeTableAttr lvtyp; StackMap stackmap; Vector generic; /** * Create a new bag. Add instructions with the addInsn() method, * set the catch table with the setCatchTable() method. * @see Insn * @see Catchtable * @see ClassEnv#addMethod */ public CodeAttr() { this.stack_size = 1; this.num_locals = 1; this.ctb = null; this.insns = new Vector(); generic = new Vector(); } /** * Set the catchtable for this code */ public void setCatchtable(Catchtable ctb) { this.ctb = ctb; } /** * Set the line number table for this method */ public void setLineTable(LineTableAttr ltab) { this.ltab = ltab; } /** * Set the local variable information for this method */ public void setLocalVarTable(LocalVarTableAttr lvar) { this.lvar = lvar; } /** * Set the local variable type information for this method */ public void setLocalVarTypeTable(LocalVarTypeTableAttr lvtyp) { this.lvtyp = lvtyp; } /** * Set the StackMap attribute for this method */ public void setStackMap(StackMap s) { stackmap = s; } /** * Add a generic attribute to the method. A generic attribute * contains a stream of uninterpreted bytes which is ignored by * the VM (as long as its name doesn't conflict with other names * for attributes that are understood by the VM) */ public void addGenericAttr(GenericAttr g) { generic.addElement(g); } /** * Append a new Insn to this code. Insn's are sequentially * stored, in the order in which this method is called. You * can't reorder code fragments after you've added it here. */ public void addInsn(Insn insn) { insns.addElement(insn); } public void setStackSize(short stack_size) { this.stack_size = stack_size; } public void setVarSize(short num_vars) { num_locals = num_vars; } void resolve(ClassEnv e) { // propagate this resolution to // the insns and catch table, so // that any CP's referenced by them // also get added. e.addCPItem(attr); for (Enumeration en = insns.elements(); en.hasMoreElements();) { Insn i = (Insn)(en.nextElement()); i.resolve(e); } if (ctb != null) ctb.resolve(e); if (ltab != null) ltab.resolve(e); if (lvar != null) lvar.resolve(e); if (lvtyp != null) lvtyp.resolve(e); if (stackmap != null) stackmap.resolve(e); for (Enumeration gen = generic.elements(); gen.hasMoreElements();) { GenericAttr gattr = (GenericAttr)gen.nextElement(); gattr.resolve(e); } } int getPc(Insn i) throws jasError { if (insn_pc == null) throw new jasError("Internal error, insn_pc has not been initialized"); Integer tmp; if (i instanceof Label) { tmp = (Integer)(insn_pc.get(((Label)i).id)); } else { tmp = (Integer)(insn_pc.get(i)); } if (tmp == null) throw new jasError(i + " has not been added to the code"); return tmp.intValue(); } void write(ClassEnv e, DataOutputStream out) throws IOException, jasError { // First, resolve all labels and // compute total size int code_size = 0; insn_pc = new Hashtable(); for (Enumeration en = insns.elements(); en.hasMoreElements();) { Insn now = (Insn)(en.nextElement()); if (now instanceof Label) { insn_pc.put(((Label)now).id, new Integer(code_size)); } else { insn_pc.put(now, new Integer(code_size)); } code_size += now.size(e, this); } int total_size = code_size; if (ctb != null) total_size += ctb.size(); if (ltab != null) total_size += ltab.size(); if (lvar != null) total_size += lvar.size(); if (lvtyp != null) total_size += lvtyp.size(); if (stackmap != null) total_size += stackmap.size(e, this); for (Enumeration gen = generic.elements(); gen.hasMoreElements();) { GenericAttr gattr = (GenericAttr)(gen.nextElement()); total_size += gattr.size(); } // extra headers total_size += 12; out.writeShort(e.getCPIndex(attr)); out.writeInt(total_size); out.writeShort(stack_size); out.writeShort(num_locals); out.writeInt(code_size); for (Enumeration en = insns.elements(); en.hasMoreElements();) { Insn now = (Insn)(en.nextElement()); now.write(e, this, out); } if (ctb != null) { ctb.write(e, this, out); } else { out.writeShort(0); } short extra = 0; if (ltab != null) extra++; if (lvar != null) extra++; if (lvtyp != null) extra++; if (stackmap != null) extra++; extra += generic.size(); out.writeShort(extra); if (ltab != null) { ltab.write(e, this, out); } if (lvar != null) { lvar.write(e, this, out); } if (lvtyp != null) { lvtyp.write(e, this, out); } if (stackmap != null) { stackmap.write(e, this, out); } for (Enumeration gen = generic.elements(); gen.hasMoreElements();) { GenericAttr gattr = (GenericAttr)gen.nextElement(); gattr.write(e, out); } } public String toString() { return ("<#code-attr>"); } }