All Downloads are FREE. Search and download functionalities are using the official Maven repository.

serp.bytecode.Code Maven / Gradle / Ivy

There is a newer version: 4.0.1
Show newest version
package serp.bytecode;

import java.io.*;
import java.util.*;

import serp.bytecode.lowlevel.*;
import serp.bytecode.visitor.*;

/**
 * Representation of a code block of a class.
 * The methods of this class mimic those of the same name in the
 * {@link java.util.ListIterator} class. Note that the size and index
 * information of the code block will change as opcodes are added.
 *
 * 

Code blocks are usually obtained from a {@link BCMethod}, but can also * be constructed via the default constructor. Blocks created this way can * be used to provide template instructions to the various search/replace * methods in this class.

* *

The code class contains methods named after most JVM instructions, each * of which adds the matching opcode to the code block at the * current iterator position. It also contains generic versions of various * JVM instructions whose opcodes are not set until their properties are set * with additional information. Almost all instruction types are able to * 'morph' their opcode on the fly as the arguments to the instruction change. * Thus the developer can initially call, for example, the aload * opcode, but later change the type to load to int and the * opcode will automatically morph to the iload opcode.

* * @author Abe White */ public class Code extends Attribute { private final CodeEntry _head; private final CodeEntry _tail; private CodeIterator _ci; private int _maxStack = 0; private int _maxLocals = 0; private int _size = 0; private Collection _handlers = new LinkedList(); private Collection _attrs = new LinkedList(); private boolean _byteIndexesValid; Code(int nameIndex, Attributes owner) { super(nameIndex, owner); _head = new CodeEntry(); _tail = new CodeEntry(); _head.next = _tail; _tail.prev = _head; _ci = new CodeIterator(_head, -1); } /** * The public constructor is for creating template code modules * that produce {@link Instruction}s used in matching through * the various search and replace methods. */ public Code() { this(0, new Project().loadClass("", null).declareMethod("", void.class, null)); } /** * The owning method. */ public BCMethod getMethod() { return (BCMethod) getOwner(); } Collection getAttributesHolder() { return _attrs; } //////////////////////////// // Stack, Locals operations //////////////////////////// /** * Return the maximum stack depth set for this code block. */ public int getMaxStack() { return _maxStack; } /** * Set the maximum stack depth for this code block. */ public void setMaxStack(int max) { _maxStack = max; } /** * Return the maximum number of local variables (including params) * set for this method. */ public int getMaxLocals() { return _maxLocals; } /** * Set the maximum number of local variables (including params) in * this method. */ public void setMaxLocals(int max) { _maxLocals = max; } /** * Return the local variable index for the paramIndex'th parameter to * the method. Local variable indexes differ from parameter indexes because: * a) non-static methods use the 0th local variable for the 'this' ptr, and * b) double and long values occupy two spots in the local variable array. * Returns -1 if the given index is not valid. */ public int getLocalsIndex(int paramIndex) { if (paramIndex < 0) return -1; int pos = 0; if (!getMethod().isStatic()) pos = 1; String[] params = getMethod().getParamNames(); for (int i = 0; i < paramIndex; i++, pos++) { if (i == params.length) return -1; if (params[i].equals(long.class.getName()) || params[i].equals(double.class.getName())) pos++; } return pos; } /** * Return the parameter index for the given local index, or -1 if * the given local does not reference a param. * * @see #getLocalsIndex */ public int getParamsIndex(int localIndex) { int pos = 0; if (!getMethod().isStatic()) pos = 1; String[] params = getMethod().getParamNames(); for (int i = 0; i < params.length; i++, pos++) { if (localIndex == pos) return i; if (params[i].equals(long.class.getName()) || params[i].equals(double.class.getName())) pos++; } return -1; } /** * Return the next available local variable index. */ public int getNextLocalsIndex() { calculateMaxLocals(); return getMaxLocals(); } /** * Calculate and set the number of locals needed based on * the instructions used and the parameters of the method this code * block is a part of. * * @see #setMaxLocals */ public void calculateMaxLocals() { // start off assuming the max number needed is the // number for all the params String[] params = getMethod().getParamNames(); int max = 0; if ((params.length == 0) && !getMethod().isStatic()) max = 1; else if (params.length > 0) { max = getLocalsIndex(params.length - 1) + 1; if (params[params.length - 1].equals(long.class.getName()) || params[params.length - 1].equals(double.class.getName())) max++; } // check to see if there are any store instructions that // try to reference beyond that point StoreInstruction store; int current; for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) { current = 0; if (entry instanceof StoreInstruction) { store = (StoreInstruction) entry; current = store.getLocal() + 1; if (store.getType().equals(long.class) || store.getType().equals(double.class)) current++; if (current > max) max = current; } } setMaxLocals(max); } /** * Calculate and set the maximum stack depth needed for * the instructions used. * * @see #setMaxStack */ public void calculateMaxStack() { int stack = 0; int max = 0; ExceptionHandler[] handlers = getExceptionHandlers(); Instruction ins; for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) { ins = (Instruction) entry; stack += ins.getStackChange(); // if this is the start of a try, the exception will be placed // on the stack for (int j = 0; j < handlers.length; j++) if (handlers[j].getTryStart() == ins) stack++; if (stack > max) max = stack; } setMaxStack(max); } /////////////////////////////// // ExceptionHandler operations /////////////////////////////// /** * Return the exception handlers active in this code block, or an * empty array if none. */ public ExceptionHandler[] getExceptionHandlers() { return (ExceptionHandler[]) _handlers.toArray (new ExceptionHandler[_handlers.size()]); } /** * Return the exception handler that catches the given exception type; * if multiple handlers catch the given type, which is returned is * undefined. */ public ExceptionHandler getExceptionHandler(String catchType) { catchType = getProject().getNameCache().getExternalForm(catchType, false); String type; ExceptionHandler[] handlers = getExceptionHandlers(); for (int i = 0; i < handlers.length; i++) { type = handlers[i].getCatchName(); if ((type == null && catchType == null) || (type != null && type.equals(catchType))) return handlers[i]; } return null; } /** * Return the exception handler that catches the given exception type; * if multiple handlers catch the given type, which is returned is * undefined. */ public ExceptionHandler getExceptionHandler(Class catchType) { if (catchType == null) return getExceptionHandler((String) null); return getExceptionHandler(catchType.getName()); } /** * Return the exception handler that catches the given exception type; * if multiple handlers catch the given type, which is returned is * undefined. */ public ExceptionHandler getExceptionHandler(BCClass catchType) { if (catchType == null) return getExceptionHandler((String) null); return getExceptionHandler(catchType.getName()); } /** * Return all exception handlers that catch the given exception type, * or an empty array if none. */ public ExceptionHandler[] getExceptionHandlers(String catchType) { catchType = getProject().getNameCache().getExternalForm(catchType, false); List matches = new LinkedList(); String type; ExceptionHandler[] handlers = getExceptionHandlers(); for (int i = 0; i < handlers.length; i++) { type = handlers[i].getCatchName(); if ((type == null && catchType == null) || (type != null && type.equals(catchType))) matches.add(handlers[i]); } return (ExceptionHandler[]) matches.toArray (new ExceptionHandler[matches.size()]); } /** * Return all exception handlers that catch the given exception type, * or an empty array if none. */ public ExceptionHandler[] getExceptionHandlers(Class catchType) { if (catchType == null) return getExceptionHandlers((String) null); return getExceptionHandlers(catchType.getName()); } /** * Return all exception handlers that catch the given exception type, * or an empty array if none. */ public ExceptionHandler[] getExceptionHandlers(BCClass catchType) { if (catchType == null) return getExceptionHandlers((String) null); return getExceptionHandlers(catchType.getName()); } /** * Set the exception handlers for this code block. This method is useful * for importing all handlers from another code block. Set to null or * empty array if none. */ public void setExceptionHandlers(ExceptionHandler[] handlers) { clearExceptionHandlers(); if (handlers != null) for (int i = 0; i < handlers.length; i++) addExceptionHandler(handlers[i]); } /** * Import the given exception handler from another code block. */ public ExceptionHandler addExceptionHandler(ExceptionHandler handler) { ExceptionHandler newHandler = addExceptionHandler(); newHandler.read(handler); return newHandler; } /** * Add an exception handler to this code block. */ public ExceptionHandler addExceptionHandler() { ExceptionHandler handler = new ExceptionHandler(this); _handlers.add(handler); return handler; } /** * Add an exception handler to this code block. * * @param tryStart the first instruction of the try {} block * @param tryEnd the last instruction of the try {} block * @param handlerStart the first instruction of the catch {} block * @param catchType the type of exception being caught */ public ExceptionHandler addExceptionHandler(Instruction tryStart, Instruction tryEnd, Instruction handlerStart, String catchType) { ExceptionHandler handler = addExceptionHandler(); handler.setTryStart(tryStart); handler.setTryEnd(tryEnd); handler.setHandlerStart(handlerStart); handler.setCatch(catchType); return handler; } /** * Add an exception handler to this code block. * * @param tryStart the first instruction of the try {} block * @param tryEnd the last instruction of the try {} block * @param handlerStart the first instruction of the catch {} block * @param catchType the type of exception being caught */ public ExceptionHandler addExceptionHandler(Instruction tryStart, Instruction tryEnd, Instruction handlerStart, Class catchType) { String catchName = null; if (catchType != null) catchName = catchType.getName(); return addExceptionHandler(tryStart, tryEnd, handlerStart, catchName); } /** * Add an exception handler to this code block. * * @param tryStart the first instruction of the try {} block * @param tryEnd the last instruction of the try {} block * @param handlerStart the first instruction of the catch {} block * @param catchType the type of exception being caught */ public ExceptionHandler addExceptionHandler(Instruction tryStart, Instruction tryEnd, Instruction handlerStart, BCClass catchType) { String catchName = null; if (catchType != null) catchName = catchType.getName(); return addExceptionHandler(tryStart, tryEnd, handlerStart, catchName); } /** * Clear all exception handlers. */ public void clearExceptionHandlers() { ExceptionHandler handler; for (Iterator itr = _handlers.iterator(); itr.hasNext();) { handler = (ExceptionHandler) itr.next(); itr.remove(); handler.invalidate(); } } /** * Remove the exception handler that catches the given type. */ public boolean removeExceptionHandler(String catchType) { return removeExceptionHandler(getExceptionHandler(catchType)); } /** * Remove the exception handler that catches the given type. * * @return true if the handler was removed, false otherwise */ public boolean removeExceptionHandler(Class catchType) { if (catchType == null) return removeExceptionHandler((String) null); return removeExceptionHandler(catchType.getName()); } /** * Remove the exception handler that catches the given type. * * @return true if the handler was removed, false otherwise */ public boolean removeExceptionHandler(BCClass catchType) { if (catchType == null) return removeExceptionHandler((String) null); return removeExceptionHandler(catchType.getName()); } /** * Remove an exception handler from this code block. The given handler * must belong to this code block. */ public boolean removeExceptionHandler(ExceptionHandler handler) { if ((handler == null) || !_handlers.remove(handler)) return false; handler.invalidate(); return true; } ///////////////////////// // Code block operations ///////////////////////// /** * Return the number of instructions in the method. */ public int size() { return _size; } /** * Reset the position of the instruction iterator to the first opcode. */ public void beforeFirst() { _ci = new CodeIterator(_head, -1); } /** * Set the position of the instruction iterator to after the last opcode. */ public void afterLast() { if (_size == 0) _ci = new CodeIterator(_head, -1); else _ci = new CodeIterator(_tail.prev, _size - 1); } /** * Position the iterator just before the given instruction. The * instruction must belong to this method. */ public void before(Instruction ins) { if (ins.getCode() != this) throw new IllegalArgumentException("ins.code != this"); _ci = new CodeIterator(ins.prev, CodeIterator.UNSET); } /** * Position the iterator just after the given instruction. The * instruction must belong to this method. */ public void after(Instruction ins) { before(ins); next(); } /** * Return true if a subsequent call to {@link #next} will return an * instruction. */ public boolean hasNext() { return _ci.hasNext(); } /** * Return true if a subsequent call to {@link #previous} will return an * instruction. */ public boolean hasPrevious() { return _ci.hasPrevious(); } /** * Return the next instruction. */ public Instruction next() { return (Instruction) _ci.next(); } /** * Return the index of the next instruction, or {@link #size} if at end. */ public int nextIndex() { return _ci.nextIndex(); } /** * Return the previous instruction. */ public Instruction previous() { return (Instruction) _ci.previous(); } /** * Return the index of the previous instruction, or -1 if at beginning. */ public int previousIndex() { return _ci.previousIndex(); } /** * Place the iterator before the given list index. */ public void before(int index) { if (index < 0 || index >= _size) throw new IndexOutOfBoundsException(String.valueOf(index)); CodeEntry entry = _head; for (int i = 0; i < index; entry = entry.next, i++); _ci = new CodeIterator(entry, index - 1); } /** * Place the iterator after the given list index. */ public void after(int index) { before(index); next(); } /** * Find the next instruction from the current iterator position that * matches the given one, according to the {@link Object#equals} methods of * the instruction types. This allows for matching based on template * instructions, as the equals methods of most instructions return * true if the information for the given instruction has not been filled * in. If a match is found, the iterator is placed after the matching * Instruction. If no match is found, moves the iterator to * {@link #afterLast}. * * @return true if match found */ public boolean searchForward(Instruction template) { if (template == null) return false; while (hasNext()) if (template.equalsInstruction(next())) return true; return false; } /** * Find the closest previous instruction from the current iterator * position that matches the given one, according to the * {@link Object#equals} methods of the instruction types. This allows * for matching based on template instructions, as the equals methods of * most instructions return true if the information for the given * instruction has not been filled in. If a match is found, the iterator * is placed before the matching Instruction. If no match is found, * moves the iterator to {@link #beforeFirst}. * * @return true if match found */ public boolean searchBackward(Instruction template) { if (template == null) return false; while (hasPrevious()) if (template.equalsInstruction(previous())) return true; return false; } /** * Adds a copy of the given instruction. * * @return the newly added instruction */ public Instruction add(Instruction ins) { Instruction newIns = createInstruction(ins.getOpcode()); newIns.read(ins); _ci.add(newIns); return newIns; } /** * Replaces the last iterated instruction with a copy of the given one. * This method will also make sure that all jump points * that referenced the old opcode are updated correctly. * * @return the newly added instruction * @see ListIterator#set */ public Instruction set(Instruction ins) { Instruction newIns = createInstruction(ins.getOpcode()); newIns.read(ins); _ci.set(newIns); return newIns; } /** * Replaces all the instructions in this code block that match the * given template with the given instruction. After this method, * the iterator will be {@link #afterLast}. * * @return the number of substitutions made */ public int replace(Instruction template, Instruction with) { beforeFirst(); int count; for (count = 0; searchForward(template); count++) set(with); return count; } /** * Equivalent to looping over each given template/replacement * pair and calling {@link #replace(Instruction,Instruction)} for each. */ public int replace(Instruction[] templates, Instruction[] with) { if (templates == null || with == null) return 0; int count = 0; for (int i = 0; i < templates.length; i++) { if (with == null) count += replace(templates[i], null); else count += replace(templates[i], with[i]); } return count; } /** * Remove the last iterated instruction. * * @see ListIterator#remove */ public void remove() { _ci.remove(); } ////////////////////////// // Instruction operations ////////////////////////// /** * Load a class constant onto the stack. * For primitive types, this translates into a * getstatic for the TYPE field of the primitive's wrapper type. * For non-primitives, things get much more complex. Suffice it to * say that the operation involves adding synthetic static fields * and even methods to the class. Note that this instruction requires * up to 3 stack positions to execute. */ public ClassConstantInstruction classconstant() { return new ClassConstantInstruction(getMethod().getDeclarer(), this, nop()); } /** * Add the nop opcode. */ public Instruction nop() { return addInstruction(Constants.NOP); } /** * Load some constant onto the stack. The {@link ConstantInstruction} * type takes any constant and correctly translates it into the proper * opcode, depending on the constant type and value. For example, * if the constant value is set to 0L, the opcode will be set to * lconst0. */ public ConstantInstruction constant() { return (ConstantInstruction) addInstruction(new ConstantInstruction (this)); } /** * Load a local variable onto the stack. This instruction will result * in a nop until its type and local index are set. */ public LoadInstruction xload() { return (LoadInstruction) addInstruction(new LoadInstruction(this)); } /** * Load an int local variable onto the stack. This instruction will * result in a nop until its local index is set. */ public LoadInstruction iload() { return (LoadInstruction) addInstruction(new LoadInstruction(this). setType(int.class)); } /** * Load a long local variable onto the stack. This instruction will * result in a nop until its local index is set. */ public LoadInstruction lload() { return (LoadInstruction) addInstruction(new LoadInstruction(this). setType(long.class)); } /** * Load a float local variable onto the stack. This instruction will * result in a nop until its local index is set. */ public LoadInstruction fload() { return (LoadInstruction) addInstruction(new LoadInstruction(this). setType(float.class)); } /** * Load a double local variable onto the stack. This instruction will * result in a nop until its local index is set. */ public LoadInstruction dload() { return (LoadInstruction) addInstruction(new LoadInstruction(this). setType(double.class)); } /** * Load an object local variable onto the stack. This instruction will * result in a nop until its local index is set. */ public LoadInstruction aload() { return (LoadInstruction) addInstruction(new LoadInstruction(this). setType(Object.class)); } /** * Store a value from the stack into a local variable. This instruction * will result in a nop until its type and local index are set. */ public StoreInstruction xstore() { return (StoreInstruction) addInstruction(new StoreInstruction(this)); } /** * Store an int value from the stack into a local variable. This * instruction will result in a nop until its local index is * set. */ public StoreInstruction istore() { return (StoreInstruction) addInstruction(new StoreInstruction(this). setType(int.class)); } /** * Store a long value from the stack into a local variable. This * instruction will resultin a nop until its local index is * set. */ public StoreInstruction lstore() { return (StoreInstruction) addInstruction(new StoreInstruction(this). setType(long.class)); } /** * Store a float value from the stack into a local variable. This * instruction will result in a nop until its local index is * set. */ public StoreInstruction fstore() { return (StoreInstruction) addInstruction(new StoreInstruction(this). setType(float.class)); } /** * Store a double value from the stack into a local variable. This * instruction will result in a nop until its local index is * set. */ public StoreInstruction dstore() { return (StoreInstruction) addInstruction(new StoreInstruction(this). setType(double.class)); } /** * Store an object value from the stack into a local variable. This * instruction will result in a nop until its local index is * set. */ public StoreInstruction astore() { return (StoreInstruction) addInstruction(new StoreInstruction(this). setType(Object.class)); } /** * Add the ret opcode, used in implementing * finally clauses. */ public RetInstruction ret() { return (RetInstruction) addInstruction(Constants.RET); } /** * Add the iinc opcode. */ public IIncInstruction iinc() { return (IIncInstruction) addInstruction(Constants.IINC); } /** * Add the wide opcode. */ public WideInstruction wide() { return (WideInstruction) addInstruction(Constants.WIDE); } /** * Load an array value onto the stack. This instruction will result * in a nop until its type is set. */ public ArrayLoadInstruction xaload() { return (ArrayLoadInstruction) addInstruction(new ArrayLoadInstruction( this)); } /** * Load an int array value onto the stack; the iaload opcode. */ public ArrayLoadInstruction iaload() { return (ArrayLoadInstruction) addInstruction(Constants.IALOAD); } /** * Load a long array value onto the stack; the laload opcode. */ public ArrayLoadInstruction laload() { return (ArrayLoadInstruction) addInstruction(Constants.LALOAD); } /** * Load a float array value onto the stack; the faload opcode. */ public ArrayLoadInstruction faload() { return (ArrayLoadInstruction) addInstruction(Constants.FALOAD); } /** * Load a double array value onto the stack; the daload opcode. */ public ArrayLoadInstruction daload() { return (ArrayLoadInstruction) addInstruction(Constants.DALOAD); } /** * Load an object array value onto the stack; the aaload * opcode. */ public ArrayLoadInstruction aaload() { return (ArrayLoadInstruction) addInstruction(Constants.AALOAD); } /** * Load a byte array value onto the stack; the baload opcode. */ public ArrayLoadInstruction baload() { return (ArrayLoadInstruction) addInstruction(Constants.BALOAD); } /** * Load a char array value onto the stack; the caload opcode. */ public ArrayLoadInstruction caload() { return (ArrayLoadInstruction) addInstruction(Constants.CALOAD); } /** * Load a short array value onto the stack; the saload opcode. */ public ArrayLoadInstruction saload() { return (ArrayLoadInstruction) addInstruction(Constants.SALOAD); } /** * Store a value from the stack into an array. This instruction * will result in a nop until its type is set. */ public ArrayStoreInstruction xastore() { return (ArrayStoreInstruction) addInstruction(new ArrayStoreInstruction( this)); } /** * Store an int value from the stack into an array; the * iastore opcode. */ public ArrayStoreInstruction iastore() { return (ArrayStoreInstruction) addInstruction(Constants.IASTORE); } /** * Store a long value from the stack into an array; the * lastore opcode. */ public ArrayStoreInstruction lastore() { return (ArrayStoreInstruction) addInstruction(Constants.LASTORE); } /** * Store a float value from the stack into an array; the * fastore opcode. */ public ArrayStoreInstruction fastore() { return (ArrayStoreInstruction) addInstruction(Constants.FASTORE); } /** * Store a double value from the stack into an array; the * dastore opcode. */ public ArrayStoreInstruction dastore() { return (ArrayStoreInstruction) addInstruction(Constants.DASTORE); } /** * Store an object value from the stack into an array; the * aastore opcode. */ public ArrayStoreInstruction aastore() { return (ArrayStoreInstruction) addInstruction(Constants.AASTORE); } /** * Store a byte value from the stack into an array; the * bastore opcode. */ public ArrayStoreInstruction bastore() { return (ArrayStoreInstruction) addInstruction(Constants.BASTORE); } /** * Store a char value from the stack into an array; the * castore opcode. */ public ArrayStoreInstruction castore() { return (ArrayStoreInstruction) addInstruction(Constants.CASTORE); } /** * Store a short value from the stack into an array; the * sastore opcode. */ public ArrayStoreInstruction sastore() { return (ArrayStoreInstruction) addInstruction(Constants.SASTORE); } /** * The pop opcode. */ public StackInstruction pop() { return (StackInstruction) addInstruction(Constants.POP); } /** * The pop2 opcode. */ public StackInstruction pop2() { return (StackInstruction) addInstruction(Constants.POP2); } /** * The dup opcode. */ public StackInstruction dup() { return (StackInstruction) addInstruction(Constants.DUP); } /** * The dupx1 opcode. */ public StackInstruction dupx1() { return (StackInstruction) addInstruction(Constants.DUPX1); } /** * The dupx2 opcode. */ public StackInstruction dupx2() { return (StackInstruction) addInstruction(Constants.DUPX2); } /** * The dup2 opcode. */ public StackInstruction dup2() { return (StackInstruction) addInstruction(Constants.DUP2); } /** * The dup2x1 opcode. */ public StackInstruction dup2x1() { return (StackInstruction) addInstruction(Constants.DUP2X1); } /** * The dup2x2 opcode. */ public StackInstruction dup2x2() { return (StackInstruction) addInstruction(Constants.DUP2X2); } /** * The swap opcode. */ public StackInstruction swap() { return (StackInstruction) addInstruction(Constants.SWAP); } /** * Perform some math operation on the stack items. This instruction will * result in a nop until its operation and type are set. */ public MathInstruction math() { return (MathInstruction) addInstruction(new MathInstruction(this)); } /** * Add the top two stack values. This instruction will result in * a nop until its type is set. */ public MathInstruction xadd() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_ADD); } /** * Add the top two stack int values; the iadd opcode. */ public MathInstruction iadd() { return (MathInstruction) addInstruction(Constants.IADD); } /** * Add the top two stack long values; the ladd opcode. */ public MathInstruction ladd() { return (MathInstruction) addInstruction(Constants.LADD); } /** * Add the top two stack float values; the fadd opcode. */ public MathInstruction fadd() { return (MathInstruction) addInstruction(Constants.FADD); } /** * Add the top two stack double values; the dadd opcode. */ public MathInstruction dadd() { return (MathInstruction) addInstruction(Constants.DADD); } /** * Subtract the top two stack values. This instruction will result in * a nop until its type is set. */ public MathInstruction xsub() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_SUB); } /** * Subtract the top two stack int values; the isub opcode. */ public MathInstruction isub() { return (MathInstruction) addInstruction(Constants.ISUB); } /** * Subtract the top two stack long values; the lsub opcode. */ public MathInstruction lsub() { return (MathInstruction) addInstruction(Constants.LSUB); } /** * Subtract the top two stack float values; the fsub opcode. */ public MathInstruction fsub() { return (MathInstruction) addInstruction(Constants.FSUB); } /** * Subtract the top two stack double values; the dsub opcode. */ public MathInstruction dsub() { return (MathInstruction) addInstruction(Constants.DSUB); } /** * Multiply the top two stack values. This instruction will result in * a nop until its type is set. */ public MathInstruction xmul() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_MUL); } /** * Multiply the top two stack int values; the imul opcode. */ public MathInstruction imul() { return (MathInstruction) addInstruction(Constants.IMUL); } /** * Multiply the top two stack long values; the lmul opcode. */ public MathInstruction lmul() { return (MathInstruction) addInstruction(Constants.LMUL); } /** * Multiply the top two stack float values; the fmul opcode. */ public MathInstruction fmul() { return (MathInstruction) addInstruction(Constants.FMUL); } /** * Multiply the top two stack double values; the dmul opcode. */ public MathInstruction dmul() { return (MathInstruction) addInstruction(Constants.DMUL); } /** * Divide the top two stack values. This instruction will result in * a nop until its type is set. */ public MathInstruction xdiv() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_DIV); } /** * Divide the top two stack int values; the idiv opcode. */ public MathInstruction idiv() { return (MathInstruction) addInstruction(Constants.IDIV); } /** * Divide the top two stack long values; the ldiv opcode. */ public MathInstruction ldiv() { return (MathInstruction) addInstruction(Constants.LDIV); } /** * Divide the top two stack float values; the fdiv opcode. */ public MathInstruction fdiv() { return (MathInstruction) addInstruction(Constants.FDIV); } /** * Divide the top two stack double values; the ddiv opcode. */ public MathInstruction ddiv() { return (MathInstruction) addInstruction(Constants.DDIV); } /** * Take the remainder of the top two stack values. This instruction will * result in a nop until its type is set. */ public MathInstruction xrem() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_REM); } /** * Take the remainder of the top two int stack values; the * irem opcode. */ public MathInstruction irem() { return (MathInstruction) addInstruction(Constants.IREM); } /** * Take the remainder of the top two long stack values; the * lrem opcode. */ public MathInstruction lrem() { return (MathInstruction) addInstruction(Constants.LREM); } /** * Take the remainder of the top two float stack values; the * frem opcode. */ public MathInstruction frem() { return (MathInstruction) addInstruction(Constants.FREM); } /** * Take the remainder of the top two double stack values; the * drem opcode. */ public MathInstruction drem() { return (MathInstruction) addInstruction(Constants.DREM); } /** * Negate the top stack value. This instruction will result in a * nop until its type is set. */ public MathInstruction xneg() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_NEG); } /** * Negate the top stack int value; the ineg opcode. */ public MathInstruction ineg() { return (MathInstruction) addInstruction(Constants.INEG); } /** * Negate the top stack long value; the lneg opcode. */ public MathInstruction lneg() { return (MathInstruction) addInstruction(Constants.LNEG); } /** * Negate the top stack float value; the fneg opcode. */ public MathInstruction fneg() { return (MathInstruction) addInstruction(Constants.FNEG); } /** * Negate the top stack double value; the dneg opcode. */ public MathInstruction dneg() { return (MathInstruction) addInstruction(Constants.DNEG); } /** * Shift the top stack values. This instruction will result in a * nop until its type is set. */ public MathInstruction xshl() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_SHL); } /** * Shift the top stack int values; the ishl opcode. */ public MathInstruction ishl() { return (MathInstruction) addInstruction(Constants.ISHL); } /** * Shift the top stack long values; the lshl opcode. */ public MathInstruction lshl() { return (MathInstruction) addInstruction(Constants.LSHL); } /** * Shift the top stack values. This instruction will result in a * nop until its type is set. */ public MathInstruction xshr() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_SHR); } /** * Shift the top stack int values; the ishr opcode. */ public MathInstruction ishr() { return (MathInstruction) addInstruction(Constants.ISHR); } /** * Shift the top stack long values; the lshr opcode. */ public MathInstruction lshr() { return (MathInstruction) addInstruction(Constants.LSHR); } /** * Shift the top stack values. This instruction will result in a * nop until its type is set. */ public MathInstruction xushr() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_USHR); } /** * Shift the top stack int values; the iushr opcode. */ public MathInstruction iushr() { return (MathInstruction) addInstruction(Constants.IUSHR); } /** * Shift the top stack long values; the lushr opcode. */ public MathInstruction lushr() { return (MathInstruction) addInstruction(Constants.LUSHR); } /** * Take the mathematical and of the top two stack values. This instruction * results in a nop until its type is set. */ public MathInstruction xand() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_AND); } /** * Take the mathematical and of the top two stack int values; the * iand opcode. */ public MathInstruction iand() { return (MathInstruction) addInstruction(Constants.IAND); } /** * Take the mathematical and of the top two stack long values; the * land opcode. */ public MathInstruction land() { return (MathInstruction) addInstruction(Constants.LAND); } /** * Take the mathematical or of the top two stack values. This instruction * results in a nop until its type is set. */ public MathInstruction xor() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_OR); } /** * Take the mathematical or of the top two stack int values; the * ior opcode. */ public MathInstruction ior() { return (MathInstruction) addInstruction(Constants.IOR); } /** * Take the mathematical or of the top two stack long values; the * lor opcode. */ public MathInstruction lor() { return (MathInstruction) addInstruction(Constants.LOR); } /** * Take the mathematical xor of the top two stack values. This instruction * results in a nop until its type is set. */ public MathInstruction xxor() { MathInstruction mi = math(); return mi.setOperation(Constants.MATH_XOR); } /** * Take the mathematical xor of the top two stack int values; the * ixor opcode. */ public MathInstruction ixor() { return (MathInstruction) addInstruction(Constants.IXOR); } /** * Take the mathematical xor of the top two stack long values; the * lxor opcode. */ public MathInstruction lxor() { return (MathInstruction) addInstruction(Constants.LXOR); } /** * Convert the top stack value to another type. This instruction * will result in a nop until the types to convert * between are set. */ public ConvertInstruction convert() { return (ConvertInstruction)addInstruction(new ConvertInstruction(this)); } /** * Compare the top two stack values. This instruction will result in a * nop until its type is set. */ public CmpInstruction xcmp() { return (CmpInstruction) addInstruction(new CmpInstruction(this)); } /** * Compare the top two stack values; the lcmp opcode. */ public CmpInstruction lcmp() { return (CmpInstruction) addInstruction(Constants.LCMP); } /** * Compare the top two stack values; the fcmpl opcode. */ public CmpInstruction fcmpl() { return (CmpInstruction) addInstruction(Constants.FCMPL); } /** * Compare the top two stack values; the fcmpg opcode. */ public CmpInstruction fcmpg() { return (CmpInstruction) addInstruction(Constants.FCMPG); } /** * Compare the top two stack values; the dcmpl opcode. */ public CmpInstruction dcmpl() { return (CmpInstruction) addInstruction(Constants.DCMPL); } /** * Compare the top two stack values; the dcmpg opcode. */ public CmpInstruction dcmpg() { return (CmpInstruction) addInstruction(Constants.DCMPG); } /** * The ifeq opcode. */ public IfInstruction ifeq() { return (IfInstruction) addInstruction(Constants.IFEQ); } /** * The ifne opcode. */ public IfInstruction ifne() { return (IfInstruction) addInstruction(Constants.IFNE); } /** * The iflt opcode. */ public IfInstruction iflt() { return (IfInstruction) addInstruction(Constants.IFLT); } /** * The ifge opcode. */ public IfInstruction ifge() { return (IfInstruction) addInstruction(Constants.IFGE); } /** * The ifgt opcode. */ public IfInstruction ifgt() { return (IfInstruction) addInstruction(Constants.IFGT); } /** * The ifle opcode. */ public IfInstruction ifle() { return (IfInstruction) addInstruction(Constants.IFLE); } /** * The ificmpeq opcode. */ public IfInstruction ificmpeq() { return (IfInstruction) addInstruction(Constants.IFICMPEQ); } /** * The ificmpne opcode. */ public IfInstruction ificmpne() { return (IfInstruction) addInstruction(Constants.IFICMPNE); } /** * The ificmplt opcode. */ public IfInstruction ificmplt() { return (IfInstruction) addInstruction(Constants.IFICMPLT); } /** * The ificmpge opcode. */ public IfInstruction ificmpge() { return (IfInstruction) addInstruction(Constants.IFICMPGE); } /** * The ificmpgt opcode. */ public IfInstruction ificmpgt() { return (IfInstruction) addInstruction(Constants.IFICMPGT); } /** * The ificmple opcode. */ public IfInstruction ificmple() { return (IfInstruction) addInstruction(Constants.IFICMPLE); } /** * The ifacmpeq opcode. */ public IfInstruction ifacmpeq() { return (IfInstruction) addInstruction(Constants.IFACMPEQ); } /** * The ifacmpne opcode. */ public IfInstruction ifacmpne() { return (IfInstruction) addInstruction(Constants.IFACMPNE); } /** * The ifnull opcode. */ public IfInstruction ifnull() { return (IfInstruction) addInstruction(Constants.IFNULL); } /** * The ifnonnull opcode. */ public IfInstruction ifnonnull() { return (IfInstruction) addInstruction(Constants.IFNONNULL); } /** * The go2 opcode. */ public JumpInstruction go2() { return (JumpInstruction) addInstruction(Constants.GOTO); } /** * The jsr opcode used in implementing finally * clauses. */ public JumpInstruction jsr() { return (JumpInstruction) addInstruction(Constants.JSR); } /** * The tableswitch opcode. */ public TableSwitchInstruction tableswitch() { return (TableSwitchInstruction) addInstruction(Constants.TABLESWITCH); } /** * The lookupswitch opcode. */ public LookupSwitchInstruction lookupswitch() { return (LookupSwitchInstruction) addInstruction(Constants.LOOKUPSWITCH); } /** * Return from a method. This method will result in a * nop until its type is set. */ public ReturnInstruction xreturn() { return (ReturnInstruction) addInstruction(new ReturnInstruction(this)); } /** * Return void from a method; the return opcode. */ public ReturnInstruction vreturn() { return (ReturnInstruction) addInstruction(Constants.RETURN); } /** * Return an int from a method; the ireturn opcode. */ public ReturnInstruction ireturn() { return (ReturnInstruction) addInstruction(Constants.IRETURN); } /** * Return a long from a method; the lreturn opcode. */ public ReturnInstruction lreturn() { return (ReturnInstruction) addInstruction(Constants.LRETURN); } /** * Return a float from a method; the freturn opcode. */ public ReturnInstruction freturn() { return (ReturnInstruction) addInstruction(Constants.FRETURN); } /** * Return a double from a method; the dreturn opcode. */ public ReturnInstruction dreturn() { return (ReturnInstruction) addInstruction(Constants.DRETURN); } /** * Return an object from a method; the areturn opcode. */ public ReturnInstruction areturn() { return (ReturnInstruction) addInstruction(Constants.ARETURN); } /** * Load the value from a field onto the stack; the getfield * opcode. */ public GetFieldInstruction getfield() { return (GetFieldInstruction) addInstruction(Constants.GETFIELD); } /** * Load the value from a static field onto the stack; the * getstatic opcode. */ public GetFieldInstruction getstatic() { return (GetFieldInstruction) addInstruction(Constants.GETSTATIC); } /** * Place the value of a field onto the stack; the putfield * opcode. */ public PutFieldInstruction putfield() { return (PutFieldInstruction) addInstruction(Constants.PUTFIELD); } /** * Place the value of a static field onto the stack; the * putstatic opcode. */ public PutFieldInstruction putstatic() { return (PutFieldInstruction) addInstruction(Constants.PUTSTATIC); } /** * Invoke a virtual method; the invokevirtual opcode. */ public MethodInstruction invokevirtual() { return (MethodInstruction) addInstruction(Constants.INVOKEVIRTUAL); } /** * Invoke a method non-virtually, as for constructors and superclass * methods; the invokespecial opcode. */ public MethodInstruction invokespecial() { return (MethodInstruction) addInstruction(Constants.INVOKESPECIAL); } /** * Invoke a method on an interface; the invokeinterface opcode. */ public MethodInstruction invokeinterface() { return (MethodInstruction) addInstruction(Constants.INVOKEINTERFACE); } /** * Invoke a static method; the invokestatic opcode. */ public MethodInstruction invokestatic() { return (MethodInstruction) addInstruction(Constants.INVOKESTATIC); } /** * Invoke a dynamic method; the invokedynamic opcode. */ public MethodInstruction invokedynamic() { return (MethodInstruction) addInstruction(Constants.INVOKEDYNAMIC); } /** * Create a new instance of an object; the new opcode. */ public ClassInstruction anew() { return (ClassInstruction) addInstruction(Constants.NEW); } /** * Create a new instance of an object array; the anew opcode. */ public ClassInstruction anewarray() { return (ClassInstruction) addInstruction(Constants.ANEWARRAY); } /** * Cast an object on the stack to another type; the checkcast * opcode. */ public ClassInstruction checkcast() { return (ClassInstruction) addInstruction(Constants.CHECKCAST); } /** * Test if a stack object is an instance of a class; the * instanceof opcode. */ public ClassInstruction isinstance() { return (ClassInstruction) addInstruction(Constants.INSTANCEOF); } /** * Create a new multidimensional array; the multianewarray * opcode. */ public MultiANewArrayInstruction multianewarray() { return (MultiANewArrayInstruction) addInstruction (Constants.MULTIANEWARRAY); } /** * Create a new array of a primitive type; the newarray opcode. */ public NewArrayInstruction newarray() { return (NewArrayInstruction) addInstruction(Constants.NEWARRAY); } /** * Get the length of an array on the stack; the arraylength * opcode. */ public Instruction arraylength() { return addInstruction(Constants.ARRAYLENGTH); } /** * Throw an exception; the athrow opcode. */ public Instruction athrow() { return addInstruction(Constants.ATHROW); } /** * The monitorenter opcode. */ public MonitorEnterInstruction monitorenter() { return (MonitorEnterInstruction) addInstruction(Constants.MONITORENTER); } /** * The monitorexit opcode. */ public MonitorExitInstruction monitorexit() { return (MonitorExitInstruction) addInstruction(Constants.MONITOREXIT); } ///////////////////////// // Wholisitic operations ///////////////////////// /** * Return all the Instructions of this method. */ public Instruction[] getInstructions() { Instruction[] arr = new Instruction[_size]; int i = 0; for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) arr[i++] = (Instruction) entry; return arr; } int getLength() { // covers maxStack, maxLocals, codeLength, exceptionTableLength, // attributeCount int length = 12; // add code Instruction last = getLastInstruction(); if (last != null) length += last.getByteIndex() + last.getLength(); // add exception reps; each is 8 bytes length += (8 * _handlers.size()); // add all attribute lengths Attribute[] attrs = getAttributes(); for (int i = 0; i < attrs.length; i++) length += (attrs[i].getLength() + 6); return length; } public void acceptVisit(BCVisitor visit) { visit.enterCode(this); Instruction ins; for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) { ins = (Instruction) entry; visit.enterInstruction(ins); ins.acceptVisit(visit); visit.exitInstruction(ins); } for (Iterator i = _handlers.iterator(); i.hasNext();) ((ExceptionHandler) i.next()).acceptVisit(visit); visitAttributes(visit); visit.exitCode(this); } ////////////////////////// // Convenience operations ////////////////////////// /** * Return line number information for the code. * Acts internally through the {@link Attributes} interface. * * @param add if true, a new line number table will be added * if not already present * @return the line number information, or null if none * and the add param is set to false */ public LineNumberTable getLineNumberTable(boolean add) { LineNumberTable attr = (LineNumberTable) getAttribute (Constants.ATTR_LINENUMBERS); if (!add || (attr != null)) return attr; return (LineNumberTable) addAttribute(Constants.ATTR_LINENUMBERS); } /** * Remove the line number table for the code. * Acts internally through the {@link Attributes} interface. * * @return true if there was a table to remove */ public boolean removeLineNumberTable() { return removeAttribute(Constants.ATTR_LINENUMBERS); } /** * Return local variable information for the code. * Acts internally through the {@link Attributes} interface. * * @param add if true, a new local variable table will be * added if not already present * @return the local variable information, or null if none * and the add param is set to false */ public LocalVariableTable getLocalVariableTable(boolean add) { LocalVariableTable attr = (LocalVariableTable) getAttribute (Constants.ATTR_LOCALS); if (!add || (attr != null)) return attr; return (LocalVariableTable) addAttribute(Constants.ATTR_LOCALS); } /** * Remove the local variable table for the code. * Acts internally through the {@link Attributes} interface. * * @return true if there was a table to remove */ public boolean removeLocalVariableTables() { return removeAttribute(Constants.ATTR_LOCALS); } /** * Return local variable generics information for the code. * Acts internally through the {@link Attributes} interface. * * @param add if true, a new local variable type table will be * added if not already present * @return the local variable type information, or null if none * and the add param is set to false */ public LocalVariableTypeTable getLocalVariableTypeTable(boolean add) { LocalVariableTypeTable attr = (LocalVariableTypeTable) getAttribute (Constants.ATTR_LOCAL_TYPES); if (!add || (attr != null)) return attr; return (LocalVariableTypeTable)addAttribute(Constants.ATTR_LOCAL_TYPES); } /** * Remove the local variable type table for the code. * Acts internally through the {@link Attributes} interface. * * @return true if there was a table to remove */ public boolean removeLocalVariableTypeTables() { return removeAttribute(Constants.ATTR_LOCAL_TYPES); } ////////////////// // I/O operations ////////////////// void read(Attribute attr) { Code orig = (Code) attr; _maxStack = orig.getMaxStack(); _maxLocals = orig.getMaxLocals(); // clear existing code _head.next = _tail; _tail.prev = _head; _size = 0; _byteIndexesValid = false; beforeFirst(); _handlers.clear(); // copy all instructions; don't set constant instruction values until // instruction ptrs have been updated in case the instruction width // changes because of differences in the constant pool (LDC vs LDCW) Instruction ins; Instruction origIns; for (CodeEntry entry = orig._head.next; entry != orig._tail; entry = entry.next) { origIns = (Instruction) entry; ins = createInstruction(origIns.getOpcode()); _ci.addInternal(ins); if (!(ins instanceof ConstantInstruction)) ins.read(origIns); } // copy exception handlers ExceptionHandler[] origHandlers = orig.getExceptionHandlers(); ExceptionHandler handler; for (int i = 0; i < origHandlers.length; i++) { handler = addExceptionHandler(); handler.read(origHandlers[i]); handler.updateTargets(); } // reset all opcode ptrs to the new copied opcodes updateInstructionPointers(); setAttributes(orig.getAttributes()); // setup local variable markers LocalVariableTable locals = getLocalVariableTable(false); if (locals != null) locals.updateTargets(); // setup local variable markers LocalVariableTypeTable localTypes = getLocalVariableTypeTable(false); if (localTypes != null) localTypes.updateTargets(); // setup line number markers LineNumberTable lines = getLineNumberTable(false); if (lines != null) lines.updateTargets(); // now copy constant instruction values CodeEntry copy = _head.next; for (CodeEntry entry = orig._head.next; entry != orig._tail; entry = entry.next, copy = copy.next) { if (entry instanceof ConstantInstruction) ((ConstantInstruction) copy).read((Instruction) entry); } beforeFirst(); } void read(DataInput in, int length) throws IOException { _maxStack = in.readUnsignedShort(); _maxLocals = in.readUnsignedShort(); readCode(in, in.readInt()); _handlers.clear(); int exceptionCount = in.readUnsignedShort(); ExceptionHandler excep; for (int i = 0; i < exceptionCount; i++) { excep = addExceptionHandler(); excep.read(in); excep.updateTargets(); } readAttributes(in); // setup local variable markers LocalVariableTable locals = getLocalVariableTable(false); if (locals != null) locals.updateTargets(); // setup local variable markers LocalVariableTypeTable localTypes = getLocalVariableTypeTable(false); if (localTypes != null) localTypes.updateTargets(); // setup line number markers LineNumberTable lines = getLineNumberTable(false); if (lines != null) lines.updateTargets(); } void write(DataOutput out, int length) throws IOException { out.writeShort(_maxStack); out.writeShort(_maxLocals); byte[] code = toByteArray(); out.writeInt(code.length); out.write(code); out.writeShort(_handlers.size()); for (Iterator itr = _handlers.iterator(); itr.hasNext();) ((ExceptionHandler) itr.next()).write(out); writeAttributes(out); } private void readCode(DataInput in, int len) throws IOException { _head.next = _tail; _tail.prev = _head; _size = 0; _byteIndexesValid = true; beforeFirst(); Instruction ins; for (int byteIndex = 0; byteIndex < len;) { ins = createInstruction(in.readUnsignedByte()); _ci.addInternal(ins); ins.byteIndex = byteIndex; ins.read(in); byteIndex += ins.getLength(); } updateInstructionPointers(); beforeFirst(); // sanity check if (!_byteIndexesValid) throw new IllegalStateException(); } /** * Ensures that all the opcode targets are set up correctly. */ private void updateInstructionPointers() { for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) if (entry instanceof InstructionPtr) ((InstructionPtr) entry).updateTargets(); } /** * Returns the byteIndex of the given instruction. */ int getByteIndex(Instruction ins) { if (_byteIndexesValid && ins.byteIndex != -1) return ins.byteIndex; int byteIndex = 0; for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) { if (entry == ins) return byteIndex; byteIndex += ((Instruction) entry).getLength(); } throw new IllegalArgumentException("ins.owner != this"); } /** * Invalidate all byteindexes when the code block changes. */ void invalidateByteIndexes() { _byteIndexesValid = false; } /** * Returns the instruction in this code block found at the given byte index. */ Instruction getInstruction(int byteIndex) { if (byteIndex < 0) return null; int curIndex = 0; for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) { if (byteIndex == curIndex) return (Instruction) entry; curIndex += ((Instruction) entry).getLength(); } // some instruction ptrs are actually to a "next" instruction, so // allow one past the end if (byteIndex == curIndex) return null; throw new IllegalArgumentException(String.valueOf(byteIndex)); } /** * Return the first instruction in this code block, or null if none. */ Instruction getFirstInstruction() { return (Instruction) _head.next; } /** * Return the last instruction in this code block, or null if none. */ Instruction getLastInstruction() { return (Instruction) _tail.prev; } /** * Returns the number of instructions that occur before 'ins' * in this code block that 'ins' is a part of. * * @throws IllegalArgumentException if this code block is not the owner * of ins */ private int indexOf(Instruction ins) { int i = 0; for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next, i++) if (entry == ins) return i; throw new IllegalArgumentException("ins.code != this"); } private void writeCode(DataOutput out) throws IOException { Instruction ins; for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) { ins = (Instruction) entry; out.writeByte(ins.getOpcode()); ins.write(out); } } private byte[] toByteArray() throws IOException { ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); DataOutputStream stream = new DataOutputStream(byteStream); try { writeCode(stream); return byteStream.toByteArray(); } finally { try { stream.close(); } catch (Exception e) {} } } private void fromByteArray(byte[] code) throws IOException { if (code == null) { _head.next = _tail; _tail.prev = _head; _size = 0; } else { DataInputStream stream = new DataInputStream (new ByteArrayInputStream(code)); try { readCode(stream, code.length); } finally { try { stream.close(); } catch (Exception e) {} } } } private Instruction addInstruction(Instruction ins) { _ci.add(ins); return ins; } private Instruction addInstruction(int opcode) { return addInstruction(createInstruction(opcode)); } /** * Creates an Instruction, with this code block as the owner. * Note that the Instruction is not added to this Code block. */ private Instruction createInstruction(int opcode) { switch (opcode) { case Constants.NOP: case Constants.ARRAYLENGTH: case Constants.ATHROW: return new Instruction(this, opcode); case Constants.ACONSTNULL: case Constants.ICONSTM1: case Constants.ICONST0: case Constants.ICONST1: case Constants.ICONST2: case Constants.ICONST3: case Constants.ICONST4: case Constants.ICONST5: case Constants.LCONST0: case Constants.LCONST1: case Constants.FCONST0: case Constants.FCONST1: case Constants.FCONST2: case Constants.DCONST0: case Constants.DCONST1: case Constants.BIPUSH: case Constants.SIPUSH: case Constants.LDC: case Constants.LDCW: case Constants.LDC2W: return new ConstantInstruction(this, opcode); case Constants.ILOAD: case Constants.LLOAD: case Constants.FLOAD: case Constants.DLOAD: case Constants.ALOAD: case Constants.ILOAD0: case Constants.ILOAD1: case Constants.ILOAD2: case Constants.ILOAD3: case Constants.LLOAD0: case Constants.LLOAD1: case Constants.LLOAD2: case Constants.LLOAD3: case Constants.FLOAD0: case Constants.FLOAD1: case Constants.FLOAD2: case Constants.FLOAD3: case Constants.DLOAD0: case Constants.DLOAD1: case Constants.DLOAD2: case Constants.DLOAD3: case Constants.ALOAD0: case Constants.ALOAD1: case Constants.ALOAD2: case Constants.ALOAD3: return new LoadInstruction(this, opcode); case Constants.IALOAD: case Constants.LALOAD: case Constants.FALOAD: case Constants.DALOAD: case Constants.AALOAD: case Constants.BALOAD: case Constants.CALOAD: case Constants.SALOAD: return new ArrayLoadInstruction(this, opcode); case Constants.ISTORE: case Constants.LSTORE: case Constants.FSTORE: case Constants.DSTORE: case Constants.ASTORE: case Constants.ISTORE0: case Constants.ISTORE1: case Constants.ISTORE2: case Constants.ISTORE3: case Constants.LSTORE0: case Constants.LSTORE1: case Constants.LSTORE2: case Constants.LSTORE3: case Constants.FSTORE0: case Constants.FSTORE1: case Constants.FSTORE2: case Constants.FSTORE3: case Constants.DSTORE0: case Constants.DSTORE1: case Constants.DSTORE2: case Constants.DSTORE3: case Constants.ASTORE0: case Constants.ASTORE1: case Constants.ASTORE2: case Constants.ASTORE3: return new StoreInstruction(this, opcode); case Constants.IASTORE: case Constants.LASTORE: case Constants.FASTORE: case Constants.DASTORE: case Constants.AASTORE: case Constants.BASTORE: case Constants.CASTORE: case Constants.SASTORE: return new ArrayStoreInstruction(this, opcode); case Constants.POP: case Constants.POP2: case Constants.DUP: case Constants.DUPX1: case Constants.DUPX2: case Constants.DUP2: case Constants.DUP2X1: case Constants.DUP2X2: case Constants.SWAP: return new StackInstruction(this, opcode); case Constants.IADD: case Constants.LADD: case Constants.FADD: case Constants.DADD: case Constants.ISUB: case Constants.LSUB: case Constants.FSUB: case Constants.DSUB: case Constants.IMUL: case Constants.LMUL: case Constants.FMUL: case Constants.DMUL: case Constants.IDIV: case Constants.LDIV: case Constants.FDIV: case Constants.DDIV: case Constants.IREM: case Constants.LREM: case Constants.FREM: case Constants.DREM: case Constants.INEG: case Constants.LNEG: case Constants.FNEG: case Constants.DNEG: case Constants.ISHL: case Constants.LSHL: case Constants.ISHR: case Constants.LSHR: case Constants.IUSHR: case Constants.LUSHR: case Constants.IAND: case Constants.LAND: case Constants.IOR: case Constants.LOR: case Constants.IXOR: case Constants.LXOR: return new MathInstruction(this, opcode); case Constants.IINC: return new IIncInstruction(this); case Constants.I2L: case Constants.I2F: case Constants.I2D: case Constants.L2I: case Constants.L2F: case Constants.L2D: case Constants.F2I: case Constants.F2L: case Constants.F2D: case Constants.D2I: case Constants.D2L: case Constants.D2F: case Constants.I2B: case Constants.I2C: case Constants.I2S: return new ConvertInstruction(this, opcode); case Constants.LCMP: case Constants.FCMPL: case Constants.FCMPG: case Constants.DCMPL: case Constants.DCMPG: return new CmpInstruction(this, opcode); case Constants.IFEQ: case Constants.IFNE: case Constants.IFLT: case Constants.IFGE: case Constants.IFGT: case Constants.IFLE: case Constants.IFICMPEQ: case Constants.IFICMPNE: case Constants.IFICMPLT: case Constants.IFICMPGE: case Constants.IFICMPGT: case Constants.IFICMPLE: case Constants.IFACMPEQ: case Constants.IFACMPNE: case Constants.IFNULL: case Constants.IFNONNULL: return new IfInstruction(this, opcode); case Constants.GOTO: case Constants.JSR: case Constants.GOTOW: case Constants.JSRW: return new GotoInstruction(this, opcode); case Constants.RET: return new RetInstruction(this); case Constants.TABLESWITCH: return new TableSwitchInstruction(this); case Constants.LOOKUPSWITCH: return new LookupSwitchInstruction(this); case Constants.IRETURN: case Constants.LRETURN: case Constants.FRETURN: case Constants.DRETURN: case Constants.ARETURN: case Constants.RETURN: return new ReturnInstruction(this, opcode); case Constants.GETSTATIC: case Constants.GETFIELD: return new GetFieldInstruction(this, opcode); case Constants.PUTSTATIC: case Constants.PUTFIELD: return new PutFieldInstruction(this, opcode); case Constants.INVOKEVIRTUAL: case Constants.INVOKESPECIAL: case Constants.INVOKESTATIC: case Constants.INVOKEINTERFACE: case Constants.INVOKEDYNAMIC: return new MethodInstruction(this, opcode); case Constants.NEW: case Constants.ANEWARRAY: case Constants.CHECKCAST: case Constants.INSTANCEOF: return new ClassInstruction(this, opcode); case Constants.NEWARRAY: return new NewArrayInstruction(this); case Constants.MONITORENTER: return new MonitorEnterInstruction(this); case Constants.MONITOREXIT: return new MonitorExitInstruction(this); case Constants.WIDE: return new WideInstruction(this); case Constants.MULTIANEWARRAY: return new MultiANewArrayInstruction(this); default: throw new IllegalArgumentException("Illegal opcode: " + opcode); } } /** * Returns another listIterator view of the Instructions in this * code block. Useful for performing read-only searches through * Instructions without effecting the pointer location of the main * code block. */ public ListIterator listIterator() { return new CodeIterator(_head, -1); } /** * Helper class to handle invalidation of instructions on removal * and notification of modification on addition. */ private class CodeIterator implements ListIterator { public static final int UNSET = -99; private CodeEntry _bn = null; // "before next" entry private Instruction _last = null; // last entry returned private int _index = UNSET; // index of _bn public CodeIterator(CodeEntry entry, int index) { _bn = entry; _index = index; } public boolean hasNext() { return _bn.next != _tail; } public boolean hasPrevious() { return _bn != _head; } public Object next() { if (!hasNext()) throw new NoSuchElementException(); _bn = _bn.next; _last = (Instruction) _bn; if (_index != UNSET) _index++; return _last; } public int nextIndex() { return initIndex() + 1; } public Object previous() { if (!hasPrevious()) throw new NoSuchElementException(); _last = (Instruction) _bn; _bn = _bn.prev; if (_index != UNSET) _index--; return _last; } public int previousIndex() { return initIndex(); } private int initIndex() { if (_index == UNSET) { if (_bn == _head) _index = -1; else _index = indexOf((Instruction) _bn); } return _index; } public void add(Object obj) { addInternal(obj); invalidateByteIndexes(); } private void addInternal(Object obj) { if (obj == null) throw new NullPointerException("obj = null"); Instruction ins = (Instruction) obj; if (_size == 0) { _head.next = ins; _tail.prev = ins; ins.prev = _head; ins.next = _tail; _index = 0; } else { CodeEntry next = _bn.next; _bn.next = ins; next.prev = ins; ins.prev = _bn; ins.next = next; if (_index != UNSET) _index++; } _bn = ins; _last = ins; _size++; } public void set(Object obj) { if (obj == null) throw new NullPointerException("obj = null"); if (_last == null) throw new IllegalStateException(); Instruction ins = (Instruction) obj; ins.prev = _last.prev; ins.next = _last.next; ins.prev.next = ins; ins.next.prev = ins; replaceTarget(_last, ins); _last.invalidate(); if (_bn == _last) _bn = ins; _last = ins; invalidateByteIndexes(); } public void remove() { if (_last == null) throw new IllegalStateException(); if (_bn == _last) _bn = _last.prev; _index--; _last.prev.next = _last.next; _last.next.prev = _last.prev; _size--; Instruction orig = _last; Instruction replace = null; if (orig.next != _tail) replace = (Instruction) orig.next; else replace = nop(); replaceTarget(orig, replace); orig.invalidate(); _last = null; invalidateByteIndexes(); } private void replaceTarget(Instruction orig, Instruction replace) { for (CodeEntry entry = _head.next; entry != _tail; entry = entry.next) { if (entry instanceof InstructionPtr) ((InstructionPtr) entry).replaceTarget(orig, replace); } // update the ExceptionHandler pointers ExceptionHandler[] handlers = getExceptionHandlers(); for (int i = 0; i < handlers.length; i++) handlers[i].replaceTarget(orig, replace); // update LineNumber pointers LineNumberTable lineNumbers = getLineNumberTable(false); if (lineNumbers != null) lineNumbers.replaceTarget(orig, replace); // update LocalVariable pointers LocalVariableTable variables = getLocalVariableTable(false); if (variables != null) variables.replaceTarget(orig, replace); // update LocalVariableType pointers LocalVariableTypeTable types = getLocalVariableTypeTable(false); if (types != null) types.replaceTarget(orig, replace); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy