/** * VerifyFrame are part of StackMap/StackMapFrame attributes * @author $Author: Daniel Reynaud $ * @author $Author: Iouri Kharon $ * @version $Revision: 1.1 $ */ package jas; import java.io.*; import java.util.Vector; import java.util.Enumeration; public class VerifyFrame { private static final int SAME_FRAME_S0_min = 0; private static final int SAME_FRAME_S0_max = 63; private static final int SAME_FRAME_S1_min = 64; // + vi private static final int SAME_FRAME_S1_max = 127; private static final int SAME_FRAME_S1 = 247; // + off, vi private static final int CHOP_FRAME_S0_min = 248; // + off // private static final int CHOP_FRAME_S0_max = 250; private static final int SAME_FRAME_S0 = 251; // +off // private static final int APPEND_FRAME_S0_min = 252; // +off, vi[n] private static final int APPEND_FRAME_S0_max = 254; private static final int FULL_FRAME = 255; private Vector stack, locals; private int offset; private Label off_label; private boolean offset_defined; public VerifyFrame(Vector InitialFrame) { stack = new Vector(); locals = InitialFrame; if(locals == null) locals = new Vector(); offset_defined = false; } private void defineOffset() throws jasError { if(offset_defined) throw new jasError("offset already defined"); offset_defined = true; } public void setOffset(int offset) throws jasError { defineOffset(); this.offset = offset; } public void setOffset(Label label) throws jasError { defineOffset(); off_label = label; } public void addStackItem(String item, String val) throws jasError { stack.add(new VerificationTypeInfo(item, val)); } public void addLocalsItem(String item, String val) throws jasError { locals.add(new VerificationTypeInfo(item, val)); } public boolean haveOffset() { return offset_defined; } // make copy of locals frame (with type-independed counter) public Vector getFrame(int count) throws jasError { if(count > locals.size()) throw new jasError("Counter exceed range", true); Vector result = new Vector(locals); if(count != 0) // else -- full copy result.setSize(count); return result; } public int getOffset(CodeAttr ce) throws jasError { if(off_label != null) { offset = ce.getPc(off_label); off_label = null; // for speed in next's request } return offset; } void resolve(ClassEnv e) { Enumeration en = stack.elements(); while(en.hasMoreElements()) ((VerificationTypeInfo)en.nextElement()).resolve(e); en = locals.elements(); while(en.hasMoreElements()) ((VerificationTypeInfo)en.nextElement()).resolve(e); } void write(ClassEnv e, CodeAttr ce, DataOutputStream out, VerifyFrame prev) throws IOException, jasError { int off = getOffset(ce); int stack_size = stack.size(); int locals_size = locals.size(); if(prev != this) { // JDK >= 6 if(prev != null) { // not first element int prev_off = prev.getOffset(ce); if(prev_off >= off) throw new jasError("Write unsorted StackMapFrame"); off -= prev_off + 1; } if(stack_size <= 1) { // else can't compact boolean can_compact = true; int prev_size = 0; if(prev == null) { // first record if(stack_size == 0) { if(locals_size > (APPEND_FRAME_S0_max - SAME_FRAME_S0)) can_compact = false; } else if(locals_size != 0) can_compact = false; } else { // not first record int cmpcn = locals_size; prev_size = prev.locals.size(); int delta = locals_size - prev_size; if(stack_size == 0) { if(delta >= 0) { if(delta > (APPEND_FRAME_S0_max - SAME_FRAME_S0)) can_compact = false; cmpcn -= delta; } else if(delta < (CHOP_FRAME_S0_min - SAME_FRAME_S0)) can_compact = false; } else if(delta != 0) can_compact = false; if(can_compact) while(--cmpcn >= 0) if(!((VerificationTypeInfo) locals.elementAt(cmpcn)).isEqual(e, ce, ((VerificationTypeInfo) prev.locals.elementAt(cmpcn)))) { can_compact = false; break; } } if(can_compact) { if(stack_size != 0) { // only if SAME_FRAME_S1... if(off <= (SAME_FRAME_S1_max - SAME_FRAME_S1_min)) out.writeByte((byte)(off + SAME_FRAME_S1_min)); else { out.writeByte((byte)SAME_FRAME_S1); out.writeShort((short)off); } ((VerificationTypeInfo)stack.elementAt(0)).write(e, ce, out); return; } // stack is empty int wrdt = locals_size - prev_size; if( wrdt == 0 && off <= (SAME_FRAME_S0_max - SAME_FRAME_S0_min)) { out.writeByte((byte)(off + SAME_FRAME_S0_min)); return; } out.writeByte((byte)(SAME_FRAME_S0 + wrdt)); out.writeShort((short)off); while(--wrdt >= 0) ((VerificationTypeInfo) locals.elementAt(prev_size++)).write(e, ce, out); return; } } // can't compact -- write full frame out.writeByte((byte)FULL_FRAME); } // end of StackMapFrame(JDK>=1.6) mode out.writeShort((short)off); out.writeShort((short)locals_size); // number_of_locals // System.out.println("number of local items "+locals_size); Enumeration en = locals.elements(); while(--locals_size >= 0) ((VerificationTypeInfo)en.nextElement()).write(e, ce, out); out.writeShort((short)stack_size); // number_of_stack_items // System.out.println("number of stack items "+stack_size); en = stack.elements(); while(--stack_size >= 0) ((VerificationTypeInfo)en.nextElement()).write(e, ce, out); } }