123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086 |
- /*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later,
- * or the Apache License Version 2.0.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
- package javassist.bytecode;
-
- import java.io.ByteArrayOutputStream;
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.IOException;
- import java.io.PrintWriter;
- import java.util.Map;
-
- import javassist.CannotCompileException;
-
- /**
- * <code>stack_map</code> attribute.
- *
- * <p>This is an entry in the attributes table of a Code attribute.
- * It was introduced by J2SE 6 for the verification by
- * typechecking.
- *
- * @see StackMap
- * @since 3.4
- */
- public class StackMapTable extends AttributeInfo {
- /**
- * The name of this attribute <code>"StackMapTable"</code>.
- */
- public static final String tag = "StackMapTable";
-
- /**
- * Constructs a <code>stack_map</code> attribute.
- */
- StackMapTable(ConstPool cp, byte[] newInfo) {
- super(cp, tag, newInfo);
- }
-
- StackMapTable(ConstPool cp, int name_id, DataInputStream in)
- throws IOException
- {
- super(cp, name_id, in);
- }
-
- /**
- * Makes a copy.
- *
- * @exception RuntimeCopyException if a <code>BadBytecode</code>
- * exception is thrown while copying,
- * it is converted into
- * <code>RuntimeCopyException</code>.
- *
- */
- @Override
- public AttributeInfo copy(ConstPool newCp, Map<String,String> classnames)
- throws RuntimeCopyException
- {
- try {
- return new StackMapTable(newCp,
- new Copier(this.constPool, info, newCp, classnames).doit());
- }
- catch (BadBytecode e) {
- throw new RuntimeCopyException("bad bytecode. fatal?");
- }
- }
-
- /**
- * An exception that may be thrown by <code>copy()</code>
- * in <code>StackMapTable</code>.
- */
- public static class RuntimeCopyException extends RuntimeException {
- /** default serialVersionUID */
- private static final long serialVersionUID = 1L;
-
- /**
- * Constructs an exception.
- */
- public RuntimeCopyException(String s) {
- super(s);
- }
- }
-
- @Override
- void write(DataOutputStream out) throws IOException {
- super.write(out);
- }
-
- /**
- * <code>Top_variable_info.tag</code>.
- */
- public static final int TOP = 0;
-
- /**
- * <code>Integer_variable_info.tag</code>.
- */
- public static final int INTEGER = 1;
-
- /**
- * <code>Float_variable_info.tag</code>.
- */
- public static final int FLOAT = 2;
-
- /**
- * <code>Double_variable_info.tag</code>.
- */
- public static final int DOUBLE = 3;
-
- /**
- * <code>Long_variable_info.tag</code>.
- */
- public static final int LONG = 4;
-
- /**
- * <code>Null_variable_info.tag</code>.
- */
- public static final int NULL = 5;
-
- /**
- * <code>UninitializedThis_variable_info.tag</code>.
- */
- public static final int THIS = 6;
-
- /**
- * <code>Object_variable_info.tag</code>.
- */
- public static final int OBJECT = 7;
-
- /**
- * <code>Uninitialized_variable_info.tag</code>.
- */
- public static final int UNINIT = 8;
-
- /**
- * A code walker for a StackMapTable attribute.
- */
- public static class Walker {
- byte[] info;
- int numOfEntries;
-
- /**
- * Constructs a walker.
- *
- * @param smt the StackMapTable that this walker
- * walks around.
- */
- public Walker(StackMapTable smt) {
- this(smt.get());
- }
-
- /**
- * Constructs a walker.
- *
- * @param data the <code>info</code> field of the
- * <code>attribute_info</code> structure.
- * It can be obtained by <code>get()</code>
- * in the <code>AttributeInfo</code> class.
- */
- public Walker(byte[] data) {
- info = data;
- numOfEntries = ByteArray.readU16bit(data, 0);
- }
-
- /**
- * Returns the number of the entries.
- */
- public final int size() { return numOfEntries; }
-
- /**
- * Visits each entry of the stack map frames.
- */
- public void parse() throws BadBytecode {
- int n = numOfEntries;
- int pos = 2;
- for (int i = 0; i < n; i++)
- pos = stackMapFrames(pos, i);
- }
-
- /**
- * Invoked when the next entry of the stack map frames is visited.
- *
- * @param pos the position of the frame in the <code>info</code>
- * field of <code>attribute_info</code> structure.
- * @param nth the frame is the N-th
- * (0, 1st, 2nd, 3rd, 4th, ...) entry.
- * @return the position of the next frame.
- */
- int stackMapFrames(int pos, int nth) throws BadBytecode {
- int type = info[pos] & 0xff;
- if (type < 64) {
- sameFrame(pos, type);
- pos++;
- }
- else if (type < 128)
- pos = sameLocals(pos, type);
- else if (type < 247) {
- throw new BadBytecode(
- "bad frame_type " + type + " in StackMapTable (pos: "
- + pos + ", frame no.:" + nth + ")");
- }
- else if (type == 247) // SAME_LOCALS_1_STACK_ITEM_EXTENDED
- pos = sameLocals(pos, type);
- else if (type < 251) {
- int offset = ByteArray.readU16bit(info, pos + 1);
- chopFrame(pos, offset, 251 - type);
- pos += 3;
- }
- else if (type == 251) { // SAME_FRAME_EXTENDED
- int offset = ByteArray.readU16bit(info, pos + 1);
- sameFrame(pos, offset);
- pos += 3;
- }
- else if (type < 255)
- pos = appendFrame(pos, type);
- else // FULL_FRAME
- pos = fullFrame(pos);
-
- return pos;
- }
-
- /**
- * Invoked if the visited frame is a <code>same_frame</code> or
- * a <code>same_frame_extended</code>.
- *
- * @param pos the position of this frame in the <code>info</code>
- * field of <code>attribute_info</code> structure.
- * @param offsetDelta
- */
- public void sameFrame(int pos, int offsetDelta) throws BadBytecode {}
-
- private int sameLocals(int pos, int type) throws BadBytecode {
- int top = pos;
- int offset;
- if (type < 128)
- offset = type - 64;
- else { // type == 247
- offset = ByteArray.readU16bit(info, pos + 1);
- pos += 2;
- }
-
- int tag = info[pos + 1] & 0xff;
- int data = 0;
- if (tag == OBJECT || tag == UNINIT) {
- data = ByteArray.readU16bit(info, pos + 2);
- objectOrUninitialized(tag, data, pos + 2);
- pos += 2;
- }
-
- sameLocals(top, offset, tag, data);
- return pos + 2;
- }
-
- /**
- * Invoked if the visited frame is a <code>same_locals_1_stack_item_frame</code>
- * or a <code>same_locals_1_stack_item_frame_extended</code>.
- *
- * @param pos the position.
- * @param offsetDelta
- * @param stackTag <code>stack[0].tag</code>.
- * @param stackData <code>stack[0].cpool_index</code>
- * if the tag is <code>OBJECT</code>,
- * or <code>stack[0].offset</code>
- * if the tag is <code>UNINIT</code>.
- */
- public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData)
- throws BadBytecode {}
-
- /**
- * Invoked if the visited frame is a <code>chop_frame</code>.
- *
- * @param pos the position.
- * @param offsetDelta
- * @param k the <code>k</code> last locals are absent.
- */
- public void chopFrame(int pos, int offsetDelta, int k) throws BadBytecode {}
-
- private int appendFrame(int pos, int type) throws BadBytecode {
- int k = type - 251;
- int offset = ByteArray.readU16bit(info, pos + 1);
- int[] tags = new int[k];
- int[] data = new int[k];
- int p = pos + 3;
- for (int i = 0; i < k; i++) {
- int tag = info[p] & 0xff;
- tags[i] = tag;
- if (tag == OBJECT || tag == UNINIT) {
- data[i] = ByteArray.readU16bit(info, p + 1);
- objectOrUninitialized(tag, data[i], p + 1);
- p += 3;
- }
- else {
- data[i] = 0;
- p++;
- }
- }
-
- appendFrame(pos, offset, tags, data);
- return p;
- }
-
- /**
- * Invoked if the visited frame is a <code>append_frame</code>.
- *
- * @param pos the position.
- * @param offsetDelta
- * @param tags <code>locals[i].tag</code>.
- * @param data <code>locals[i].cpool_index</code>
- * or <code>locals[i].offset</code>.
- */
- public void appendFrame(int pos, int offsetDelta, int[] tags, int[] data)
- throws BadBytecode {}
-
- private int fullFrame(int pos) throws BadBytecode {
- int offset = ByteArray.readU16bit(info, pos + 1);
- int numOfLocals = ByteArray.readU16bit(info, pos + 3);
- int[] localsTags = new int[numOfLocals];
- int[] localsData = new int[numOfLocals];
- int p = verifyTypeInfo(pos + 5, numOfLocals, localsTags, localsData);
- int numOfItems = ByteArray.readU16bit(info, p);
- int[] itemsTags = new int[numOfItems];
- int[] itemsData = new int[numOfItems];
- p = verifyTypeInfo(p + 2, numOfItems, itemsTags, itemsData);
- fullFrame(pos, offset, localsTags, localsData, itemsTags, itemsData);
- return p;
- }
-
- /**
- * Invoked if the visited frame is <code>full_frame</code>.
- *
- * @param pos the position.
- * @param offsetDelta
- * @param localTags <code>locals[i].tag</code>
- * @param localData <code>locals[i].cpool_index</code>
- * or <code>locals[i].offset</code>
- * @param stackTags <code>stack[i].tag</code>
- * @param stackData <code>stack[i].cpool_index</code>
- * or <code>stack[i].offset</code>
- */
- public void fullFrame(int pos, int offsetDelta, int[] localTags,
- int[] localData, int[] stackTags, int[] stackData)
- throws BadBytecode {}
-
- private int verifyTypeInfo(int pos, int n, int[] tags, int[] data) {
- for (int i = 0; i < n; i++) {
- int tag = info[pos++] & 0xff;
- tags[i] = tag;
- if (tag == OBJECT || tag == UNINIT) {
- data[i] = ByteArray.readU16bit(info, pos);
- objectOrUninitialized(tag, data[i], pos);
- pos += 2;
- }
- }
-
- return pos;
- }
-
- /**
- * Invoked if <code>Object_variable_info</code>
- * or <code>Uninitialized_variable_info</code> is visited.
- *
- * @param tag <code>OBJECT</code> or <code>UNINIT</code>.
- * @param data the value of <code>cpool_index</code> or <code>offset</code>.
- * @param pos the position of <code>cpool_index</code> or <code>offset</code>.
- */
- public void objectOrUninitialized(int tag, int data, int pos) {}
- }
-
- static class SimpleCopy extends Walker {
- private Writer writer;
-
- public SimpleCopy(byte[] data) {
- super(data);
- writer = new Writer(data.length);
- }
-
- public byte[] doit() throws BadBytecode {
- parse();
- return writer.toByteArray();
- }
-
- @Override
- public void sameFrame(int pos, int offsetDelta) {
- writer.sameFrame(offsetDelta);
- }
-
- @Override
- public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData) {
- writer.sameLocals(offsetDelta, stackTag, copyData(stackTag, stackData));
- }
-
- @Override
- public void chopFrame(int pos, int offsetDelta, int k) {
- writer.chopFrame(offsetDelta, k);
- }
-
- @Override
- public void appendFrame(int pos, int offsetDelta, int[] tags, int[] data) {
- writer.appendFrame(offsetDelta, tags, copyData(tags, data));
- }
-
- @Override
- public void fullFrame(int pos, int offsetDelta, int[] localTags, int[] localData,
- int[] stackTags, int[] stackData) {
- writer.fullFrame(offsetDelta, localTags, copyData(localTags, localData),
- stackTags, copyData(stackTags, stackData));
- }
-
- protected int copyData(int tag, int data) {
- return data;
- }
-
- protected int[] copyData(int[] tags, int[] data) {
- return data;
- }
- }
-
- static class Copier extends SimpleCopy {
- private ConstPool srcPool, destPool;
- private Map<String,String> classnames;
-
- public Copier(ConstPool src, byte[] data, ConstPool dest, Map<String,String> names) {
- super(data);
- srcPool = src;
- destPool = dest;
- classnames = names;
- }
-
- @Override
- protected int copyData(int tag, int data) {
- if (tag == OBJECT)
- return srcPool.copy(data, destPool, classnames);
- return data;
- }
-
- @Override
- protected int[] copyData(int[] tags, int[] data) {
- int[] newData = new int[data.length];
- for (int i = 0; i < data.length; i++)
- if (tags[i] == OBJECT)
- newData[i] = srcPool.copy(data[i], destPool, classnames);
- else
- newData[i] = data[i];
-
- return newData;
- }
- }
-
- /**
- * Updates this stack map table when a new local variable is inserted
- * for a new parameter.
- *
- * @param index the index of the added local variable.
- * @param tag the type tag of that local variable.
- * @param classInfo the index of the <code>CONSTANT_Class_info</code> structure
- * in a constant pool table. This should be zero unless the tag
- * is <code>ITEM_Object</code>.
- *
- * @see javassist.CtBehavior#addParameter(javassist.CtClass)
- * @see #typeTagOf(char)
- * @see ConstPool
- */
- public void insertLocal(int index, int tag, int classInfo)
- throws BadBytecode
- {
- byte[] data = new InsertLocal(this.get(), index, tag, classInfo).doit();
- this.set(data);
- }
-
- /**
- * Returns the tag of the type specified by the
- * descriptor. This method returns <code>INTEGER</code>
- * unless the descriptor is either D (double), F (float),
- * J (long), L (class type), or [ (array).
- *
- * @param descriptor the type descriptor.
- * @see Descriptor
- */
- public static int typeTagOf(char descriptor) {
- switch (descriptor) {
- case 'D' :
- return DOUBLE;
- case 'F' :
- return FLOAT;
- case 'J' :
- return LONG;
- case 'L' :
- case '[' :
- return OBJECT;
- // case 'V' :
- default :
- return INTEGER;
- }
- }
-
- /* This implementation assumes that a local variable initially
- * holding a parameter value is never changed to be a different
- * type.
- *
- */
- static class InsertLocal extends SimpleCopy {
- private int varIndex;
- private int varTag, varData;
-
- public InsertLocal(byte[] data, int varIndex, int varTag, int varData) {
- super(data);
- this.varIndex = varIndex;
- this.varTag = varTag;
- this.varData = varData;
- }
-
- @Override
- public void fullFrame(int pos, int offsetDelta, int[] localTags, int[] localData,
- int[] stackTags, int[] stackData) {
- int len = localTags.length;
- if (len < varIndex) {
- super.fullFrame(pos, offsetDelta, localTags, localData, stackTags, stackData);
- return;
- }
-
- int typeSize = (varTag == LONG || varTag == DOUBLE) ? 2 : 1;
- int[] localTags2 = new int[len + typeSize];
- int[] localData2 = new int[len + typeSize];
- int index = varIndex;
- int j = 0;
- for (int i = 0; i < len; i++) {
- if (j == index)
- j += typeSize;
-
- localTags2[j] = localTags[i];
- localData2[j++] = localData[i];
- }
-
- localTags2[index] = varTag;
- localData2[index] = varData;
- if (typeSize > 1) {
- localTags2[index + 1] = TOP;
- localData2[index + 1] = 0;
- }
-
- super.fullFrame(pos, offsetDelta, localTags2, localData2, stackTags, stackData);
- }
- }
-
- /**
- * A writer of stack map tables.
- */
- public static class Writer {
- ByteArrayOutputStream output;
- int numOfEntries;
-
- /**
- * Constructs a writer.
- * @param size the initial buffer size.
- */
- public Writer(int size) {
- output = new ByteArrayOutputStream(size);
- numOfEntries = 0;
- output.write(0); // u2 number_of_entries
- output.write(0);
- }
-
- /**
- * Returns the stack map table written out.
- */
- public byte[] toByteArray() {
- byte[] b = output.toByteArray();
- ByteArray.write16bit(numOfEntries, b, 0);
- return b;
- }
-
- /**
- * Constructs and a return a stack map table containing
- * the written stack map entries.
- *
- * @param cp the constant pool used to write
- * the stack map entries.
- */
- public StackMapTable toStackMapTable(ConstPool cp) {
- return new StackMapTable(cp, toByteArray());
- }
-
- /**
- * Writes a <code>same_frame</code> or a <code>same_frame_extended</code>.
- */
- public void sameFrame(int offsetDelta) {
- numOfEntries++;
- if (offsetDelta < 64)
- output.write(offsetDelta);
- else {
- output.write(251); // SAME_FRAME_EXTENDED
- write16(offsetDelta);
- }
- }
-
- /**
- * Writes a <code>same_locals_1_stack_item</code>
- * or a <code>same_locals_1_stack_item_extended</code>.
- *
- * @param tag <code>stack[0].tag</code>.
- * @param data <code>stack[0].cpool_index</code>
- * if the tag is <code>OBJECT</code>,
- * or <code>stack[0].offset</code>
- * if the tag is <code>UNINIT</code>.
- * Otherwise, this parameter is not used.
- */
- public void sameLocals(int offsetDelta, int tag, int data) {
- numOfEntries++;
- if (offsetDelta < 64)
- output.write(offsetDelta + 64);
- else {
- output.write(247); // SAME_LOCALS_1_STACK_ITEM_EXTENDED
- write16(offsetDelta);
- }
-
- writeTypeInfo(tag, data);
- }
-
- /**
- * Writes a <code>chop_frame</code>.
- *
- * @param k the number of absent locals. 1, 2, or 3.
- */
- public void chopFrame(int offsetDelta, int k) {
- numOfEntries++;
- output.write(251 - k);
- write16(offsetDelta);
- }
-
- /**
- * Writes a <code>append_frame</code>. The number of the appended
- * locals is specified by the length of <code>tags</code>.
- *
- * @param tags <code>locals[].tag</code>.
- * The length of this array must be
- * either 1, 2, or 3.
- * @param data <code>locals[].cpool_index</code>
- * if the tag is <code>OBJECT</code>,
- * or <code>locals[].offset</code>
- * if the tag is <code>UNINIT</code>.
- * Otherwise, this parameter is not used.
- */
- public void appendFrame(int offsetDelta, int[] tags, int[] data) {
- numOfEntries++;
- int k = tags.length; // k is 1, 2, or 3
- output.write(k + 251);
- write16(offsetDelta);
- for (int i = 0; i < k; i++)
- writeTypeInfo(tags[i], data[i]);
- }
-
- /**
- * Writes a <code>full_frame</code>.
- * <code>number_of_locals</code> and <code>number_of_stack_items</code>
- * are specified by the the length of <code>localTags</code> and
- * <code>stackTags</code>.
- *
- * @param localTags <code>locals[].tag</code>.
- * @param localData <code>locals[].cpool_index</code>
- * if the tag is <code>OBJECT</code>,
- * or <code>locals[].offset</code>
- * if the tag is <code>UNINIT</code>.
- * Otherwise, this parameter is not used.
- * @param stackTags <code>stack[].tag</code>.
- * @param stackData <code>stack[].cpool_index</code>
- * if the tag is <code>OBJECT</code>,
- * or <code>stack[].offset</code>
- * if the tag is <code>UNINIT</code>.
- * Otherwise, this parameter is not used.
- */
- public void fullFrame(int offsetDelta, int[] localTags, int[] localData,
- int[] stackTags, int[] stackData) {
- numOfEntries++;
- output.write(255); // FULL_FRAME
- write16(offsetDelta);
- int n = localTags.length;
- write16(n);
- for (int i = 0; i < n; i++)
- writeTypeInfo(localTags[i], localData[i]);
-
- n = stackTags.length;
- write16(n);
- for (int i = 0; i < n; i++)
- writeTypeInfo(stackTags[i], stackData[i]);
- }
-
- private void writeTypeInfo(int tag, int data) {
- output.write(tag);
- if (tag == OBJECT || tag == UNINIT)
- write16(data);
- }
-
- private void write16(int value) {
- output.write((value >>> 8) & 0xff);
- output.write(value & 0xff);
- }
- }
-
- /**
- * Prints the stack table map.
- */
- public void println(PrintWriter w) {
- Printer.print(this, w);
- }
-
- /**
- * Prints the stack table map.
- *
- * @param ps a print stream such as <code>System.out</code>.
- */
- public void println(java.io.PrintStream ps) {
- Printer.print(this, new java.io.PrintWriter(ps, true));
- }
-
- static class Printer extends Walker {
- private PrintWriter writer;
- private int offset;
-
- /**
- * Prints the stack table map.
- */
- public static void print(StackMapTable smt, PrintWriter writer) {
- try {
- new Printer(smt.get(), writer).parse();
- }
- catch (BadBytecode e) {
- writer.println(e.getMessage());
- }
- }
-
- Printer(byte[] data, PrintWriter pw) {
- super(data);
- writer = pw;
- offset = -1;
- }
-
- @Override
- public void sameFrame(int pos, int offsetDelta) {
- offset += offsetDelta + 1;
- writer.println(offset + " same frame: " + offsetDelta);
- }
-
- @Override
- public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData) {
- offset += offsetDelta + 1;
- writer.println(offset + " same locals: " + offsetDelta);
- printTypeInfo(stackTag, stackData);
- }
-
- @Override
- public void chopFrame(int pos, int offsetDelta, int k) {
- offset += offsetDelta + 1;
- writer.println(offset + " chop frame: " + offsetDelta + ", " + k + " last locals");
- }
-
- @Override
- public void appendFrame(int pos, int offsetDelta, int[] tags, int[] data) {
- offset += offsetDelta + 1;
- writer.println(offset + " append frame: " + offsetDelta);
- for (int i = 0; i < tags.length; i++)
- printTypeInfo(tags[i], data[i]);
- }
-
- @Override
- public void fullFrame(int pos, int offsetDelta, int[] localTags, int[] localData,
- int[] stackTags, int[] stackData) {
- offset += offsetDelta + 1;
- writer.println(offset + " full frame: " + offsetDelta);
- writer.println("[locals]");
- for (int i = 0; i < localTags.length; i++)
- printTypeInfo(localTags[i], localData[i]);
-
- writer.println("[stack]");
- for (int i = 0; i < stackTags.length; i++)
- printTypeInfo(stackTags[i], stackData[i]);
- }
-
- private void printTypeInfo(int tag, int data) {
- String msg = null;
- switch (tag) {
- case TOP :
- msg = "top";
- break;
- case INTEGER :
- msg = "integer";
- break;
- case FLOAT :
- msg = "float";
- break;
- case DOUBLE :
- msg = "double";
- break;
- case LONG :
- msg = "long";
- break;
- case NULL :
- msg = "null";
- break;
- case THIS :
- msg = "this";
- break;
- case OBJECT :
- msg = "object (cpool_index " + data + ")";
- break;
- case UNINIT :
- msg = "uninitialized (offset " + data + ")";
- break;
- }
-
- writer.print(" ");
- writer.println(msg);
- }
- }
-
- void shiftPc(int where, int gapSize, boolean exclusive)
- throws BadBytecode
- {
- new OffsetShifter(this, where, gapSize).parse();
- new Shifter(this, where, gapSize, exclusive).doit();
- }
-
- static class OffsetShifter extends Walker {
- int where, gap;
-
- public OffsetShifter(StackMapTable smt, int where, int gap) {
- super(smt);
- this.where = where;
- this.gap = gap;
- }
-
- @Override
- public void objectOrUninitialized(int tag, int data, int pos) {
- if (tag == UNINIT)
- if (where <= data)
- ByteArray.write16bit(data + gap, info, pos);
- }
- }
-
- static class Shifter extends Walker {
- private StackMapTable stackMap;
- int where, gap;
- int position;
- byte[] updatedInfo;
- boolean exclusive;
-
- public Shifter(StackMapTable smt, int where, int gap, boolean exclusive) {
- super(smt);
- stackMap = smt;
- this.where = where;
- this.gap = gap;
- this.position = 0;
- this.updatedInfo = null;
- this.exclusive = exclusive;
- }
-
- public void doit() throws BadBytecode {
- parse();
- if (updatedInfo != null)
- stackMap.set(updatedInfo);
- }
-
- @Override
- public void sameFrame(int pos, int offsetDelta) {
- update(pos, offsetDelta, 0, 251);
- }
-
- @Override
- public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData) {
- update(pos, offsetDelta, 64, 247);
- }
-
- void update(int pos, int offsetDelta, int base, int entry) {
- int oldPos = position;
- position = oldPos + offsetDelta + (oldPos == 0 ? 0 : 1);
- boolean match;
- if (exclusive)
- // We optimize this expression by hand:
- // match = (oldPos == 0 && where == 0 && (0 < position || 0 == position))
- // || oldPos < where && where <= position;
- match = (oldPos == 0 && where == 0)
- || oldPos < where && where <= position;
- else
- match = oldPos <= where && where < position;
-
- if (match) {
- int current = info[pos] & 0xff;
- int newDelta = offsetDelta + gap;
- position += gap;
- if (newDelta < 64)
- info[pos] = (byte)(newDelta + base);
- else if (offsetDelta < 64 && current != entry) {
- byte[] newinfo = insertGap(info, pos, 2);
- newinfo[pos] = (byte)entry;
- ByteArray.write16bit(newDelta, newinfo, pos + 1);
- updatedInfo = newinfo;
- }
- else
- ByteArray.write16bit(newDelta, info, pos + 1);
- }
- }
-
- static byte[] insertGap(byte[] info, int where, int gap) {
- int len = info.length;
- byte[] newinfo = new byte[len + gap];
- for (int i = 0; i < len; i++)
- newinfo[i + (i < where ? 0 : gap)] = info[i];
-
- return newinfo;
- }
-
- @Override
- public void chopFrame(int pos, int offsetDelta, int k) {
- update(pos, offsetDelta);
- }
-
- @Override
- public void appendFrame(int pos, int offsetDelta, int[] tags, int[] data) {
- update(pos, offsetDelta);
- }
-
- @Override
- public void fullFrame(int pos, int offsetDelta, int[] localTags, int[] localData,
- int[] stackTags, int[] stackData) {
- update(pos, offsetDelta);
- }
-
- void update(int pos, int offsetDelta) {
- int oldPos = position;
- position = oldPos + offsetDelta + (oldPos == 0 ? 0 : 1);
- boolean match;
- if (exclusive)
- match = (oldPos == 0 && where == 0)
- || oldPos < where && where <= position;
- else
- match = oldPos <= where && where < position;
-
- if (match) {
- int newDelta = offsetDelta + gap;
- ByteArray.write16bit(newDelta, info, pos + 1);
- position += gap;
- }
- }
- }
-
- /**
- * @see CodeIterator.Switcher#adjustOffsets(int, int)
- */
- void shiftForSwitch(int where, int gapSize) throws BadBytecode {
- new SwitchShifter(this, where, gapSize).doit();
- }
-
- static class SwitchShifter extends Shifter {
- SwitchShifter(StackMapTable smt, int where, int gap) {
- super(smt, where, gap, false);
- }
-
- @Override
- void update(int pos, int offsetDelta, int base, int entry) {
- int oldPos = position;
- position = oldPos + offsetDelta + (oldPos == 0 ? 0 : 1);
- int newDelta = offsetDelta;
- if (where == position)
- newDelta = offsetDelta - gap;
- else if (where == oldPos)
- newDelta = offsetDelta + gap;
- else
- return;
-
- if (offsetDelta < 64)
- if (newDelta < 64)
- info[pos] = (byte)(newDelta + base);
- else {
- byte[] newinfo = insertGap(info, pos, 2);
- newinfo[pos] = (byte)entry;
- ByteArray.write16bit(newDelta, newinfo, pos + 1);
- updatedInfo = newinfo;
- }
- else
- if (newDelta < 64) {
- byte[] newinfo = deleteGap(info, pos, 2);
- newinfo[pos] = (byte)(newDelta + base);
- updatedInfo = newinfo;
- }
- else
- ByteArray.write16bit(newDelta, info, pos + 1);
- }
-
- static byte[] deleteGap(byte[] info, int where, int gap) {
- where += gap;
- int len = info.length;
- byte[] newinfo = new byte[len - gap];
- for (int i = 0; i < len; i++)
- newinfo[i - (i < where ? 0 : gap)] = info[i];
-
- return newinfo;
- }
-
- @Override
- void update(int pos, int offsetDelta) {
- int oldPos = position;
- position = oldPos + offsetDelta + (oldPos == 0 ? 0 : 1);
- int newDelta = offsetDelta;
- if (where == position)
- newDelta = offsetDelta - gap;
- else if (where == oldPos)
- newDelta = offsetDelta + gap;
- else
- return;
-
- ByteArray.write16bit(newDelta, info, pos + 1);
- }
- }
-
- /**
- * Undocumented method. Do not use; internal-use only.
- *
- * <p>This method is for javassist.convert.TransformNew.
- * It is called to update the stack map table when
- * the NEW opcode (and the following DUP) is removed.
- *
- * @param where the position of the removed NEW opcode.
- */
- public void removeNew(int where) throws CannotCompileException {
- try {
- byte[] data = new NewRemover(this.get(), where).doit();
- this.set(data);
- }
- catch (BadBytecode e) {
- throw new CannotCompileException("bad stack map table", e);
- }
- }
-
- static class NewRemover extends SimpleCopy {
- int posOfNew;
-
- public NewRemover(byte[] data, int pos) {
- super(data);
- posOfNew = pos;
- }
-
- @Override
- public void sameLocals(int pos, int offsetDelta, int stackTag, int stackData) {
- if (stackTag == UNINIT && stackData == posOfNew)
- super.sameFrame(pos, offsetDelta);
- else
- super.sameLocals(pos, offsetDelta, stackTag, stackData);
- }
-
- @Override
- public void fullFrame(int pos, int offsetDelta, int[] localTags, int[] localData,
- int[] stackTags, int[] stackData) {
- int n = stackTags.length - 1;
- for (int i = 0; i < n; i++)
- if (stackTags[i] == UNINIT && stackData[i] == posOfNew
- && stackTags[i + 1] == UNINIT && stackData[i + 1] == posOfNew) {
- n++;
- int[] stackTags2 = new int[n - 2];
- int[] stackData2 = new int[n - 2];
- int k = 0;
- for (int j = 0; j < n; j++)
- if (j == i)
- j++;
- else {
- stackTags2[k] = stackTags[j];
- stackData2[k++] = stackData[j];
- }
-
- stackTags = stackTags2;
- stackData = stackData2;
- break;
- }
-
- super.fullFrame(pos, offsetDelta, localTags, localData, stackTags, stackData);
- }
- }
- }
|