You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pc...@apache.org on 2006/06/28 21:46:19 UTC
svn commit: r417860 [5/12] - in /incubator/openjpa/trunk: ./ openjpa-lib/
openjpa-lib/main/ openjpa-lib/src/ openjpa-lib/src/main/
openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/
openjpa-lib/src/test/ openjpa-lib/src/test/java/ openjpa-lib/src/t...
Added: incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/Code.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/Code.java?rev=417860&view=auto
==============================================================================
--- incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/Code.java (added)
+++ incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/Code.java Wed Jun 28 12:46:13 2006
@@ -0,0 +1,2847 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package serp.bytecode;
+
+import serp.bytecode.lowlevel.*;
+
+import serp.bytecode.visitor.*;
+
+import java.io.*;
+
+import java.util.*;
+
+
+/**
+ * <p>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.</p>
+ *
+ * <p>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.</p>
+ *
+ * <p>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 <code>aload</code>
+ * opcode, but later change the type to load to <code>int</code> and the
+ * opcode will automatically morph to the <code>iload</code> opcode.</p>
+ *
+ * @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();
+
+ 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 <code>search</code> and <code>replace</code>
+ * 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 <code>nop</code> 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
+ * <code>lconst0</code>.
+ */
+ public ConstantInstruction constant() {
+ return (ConstantInstruction) addInstruction(new ConstantInstruction(
+ this));
+ }
+
+ /**
+ * Load a local variable onto the stack. This instruction will result
+ * in a <code>nop</code> 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 <code>nop</code> 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 <code>nop</code> 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 <code>nop</code> 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 <code>nop</code> 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 <code>nop</code> 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 <code>nop</code> 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 <code>nop</code> 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 result in a <code>nop</code> 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 <code>nop</code> 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 <code>nop</code> 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 <code>nop</code> until its local index is
+ * set.
+ */
+ public StoreInstruction astore() {
+ return (StoreInstruction) addInstruction(new StoreInstruction(this).setType(
+ Object.class));
+ }
+
+ /**
+ * Add the <code>ret</code> opcode, used in implementing
+ * <code>finally</code> clauses.
+ */
+ public RetInstruction ret() {
+ return (RetInstruction) addInstruction(Constants.RET);
+ }
+
+ /**
+ * Add the <code>iinc</code> opcode.
+ */
+ public IIncInstruction iinc() {
+ return (IIncInstruction) addInstruction(Constants.IINC);
+ }
+
+ /**
+ * Add the <code>wide</code> opcode.
+ */
+ public WideInstruction wide() {
+ return (WideInstruction) addInstruction(Constants.WIDE);
+ }
+
+ /**
+ * Load an array value onto the stack. This instruction will result
+ * in a <code>nop</code> until its type is set.
+ */
+ public ArrayLoadInstruction xaload() {
+ return (ArrayLoadInstruction) addInstruction(new ArrayLoadInstruction(
+ this));
+ }
+
+ /**
+ * Load an int array value onto the stack; the <code>iaload</code>
+ * opcode.
+ */
+ public ArrayLoadInstruction iaload() {
+ return (ArrayLoadInstruction) addInstruction(Constants.IALOAD);
+ }
+
+ /**
+ * Load a long array value onto the stack; the <code>laload</code>
+ * opcode.
+ */
+ public ArrayLoadInstruction laload() {
+ return (ArrayLoadInstruction) addInstruction(Constants.LALOAD);
+ }
+
+ /**
+ * Load a float array value onto the stack; the <code>faload</code>
+ * opcode.
+ */
+ public ArrayLoadInstruction faload() {
+ return (ArrayLoadInstruction) addInstruction(Constants.FALOAD);
+ }
+
+ /**
+ * Load a double array value onto the stack; the <code>daload</code>
+ * opcode.
+ */
+ public ArrayLoadInstruction daload() {
+ return (ArrayLoadInstruction) addInstruction(Constants.DALOAD);
+ }
+
+ /**
+ * Load an object array value onto the stack; the <code>aaload</code>
+ * opcode.
+ */
+ public ArrayLoadInstruction aaload() {
+ return (ArrayLoadInstruction) addInstruction(Constants.AALOAD);
+ }
+
+ /**
+ * Load a byte array value onto the stack; the <code>baload</code>
+ * opcode.
+ */
+ public ArrayLoadInstruction baload() {
+ return (ArrayLoadInstruction) addInstruction(Constants.BALOAD);
+ }
+
+ /**
+ * Load a char array value onto the stack; the <code>caload</code>
+ * opcode.
+ */
+ public ArrayLoadInstruction caload() {
+ return (ArrayLoadInstruction) addInstruction(Constants.CALOAD);
+ }
+
+ /**
+ * Load a short array value onto the stack; the <code>saload</code>
+ * opcode.
+ */
+ public ArrayLoadInstruction saload() {
+ return (ArrayLoadInstruction) addInstruction(Constants.SALOAD);
+ }
+
+ /**
+ * Store a value from the stack into an array. This instruction
+ * will result in a <code>nop</code> 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
+ * <code>iastore</code> opcode.
+ */
+ public ArrayStoreInstruction iastore() {
+ return (ArrayStoreInstruction) addInstruction(Constants.IASTORE);
+ }
+
+ /**
+ * Store a long value from the stack into an array; the
+ * <code>lastore</code> opcode.
+ */
+ public ArrayStoreInstruction lastore() {
+ return (ArrayStoreInstruction) addInstruction(Constants.LASTORE);
+ }
+
+ /**
+ * Store a float value from the stack into an array; the
+ * <code>fastore</code> opcode.
+ */
+ public ArrayStoreInstruction fastore() {
+ return (ArrayStoreInstruction) addInstruction(Constants.FASTORE);
+ }
+
+ /**
+ * Store a double value from the stack into an array; the
+ * <code>dastore</code> opcode.
+ */
+ public ArrayStoreInstruction dastore() {
+ return (ArrayStoreInstruction) addInstruction(Constants.DASTORE);
+ }
+
+ /**
+ * Store an object value from the stack into an array; the
+ * <code>aastore</code> opcode.
+ */
+ public ArrayStoreInstruction aastore() {
+ return (ArrayStoreInstruction) addInstruction(Constants.AASTORE);
+ }
+
+ /**
+ * Store a byte value from the stack into an array; the
+ * <code>bastore</code> opcode.
+ */
+ public ArrayStoreInstruction bastore() {
+ return (ArrayStoreInstruction) addInstruction(Constants.BASTORE);
+ }
+
+ /**
+ * Store a char value from the stack into an array; the
+ * <code>castore</code> opcode.
+ */
+ public ArrayStoreInstruction castore() {
+ return (ArrayStoreInstruction) addInstruction(Constants.CASTORE);
+ }
+
+ /**
+ * Store a short value from the stack into an array; the
+ * <code>sastore</code> opcode.
+ */
+ public ArrayStoreInstruction sastore() {
+ return (ArrayStoreInstruction) addInstruction(Constants.SASTORE);
+ }
+
+ /**
+ * The <code>pop</code> opcode.
+ */
+ public StackInstruction pop() {
+ return (StackInstruction) addInstruction(Constants.POP);
+ }
+
+ /**
+ * The <code>pop2</code> opcode.
+ */
+ public StackInstruction pop2() {
+ return (StackInstruction) addInstruction(Constants.POP2);
+ }
+
+ /**
+ * The <code>dup</code> opcode.
+ */
+ public StackInstruction dup() {
+ return (StackInstruction) addInstruction(Constants.DUP);
+ }
+
+ /**
+ * The <code>dupx1</code> opcode.
+ */
+ public StackInstruction dupx1() {
+ return (StackInstruction) addInstruction(Constants.DUPX1);
+ }
+
+ /**
+ * The <code>dupx2</code> opcode.
+ */
+ public StackInstruction dupx2() {
+ return (StackInstruction) addInstruction(Constants.DUPX2);
+ }
+
+ /**
+ * The <code>dup2</code> opcode.
+ */
+ public StackInstruction dup2() {
+ return (StackInstruction) addInstruction(Constants.DUP2);
+ }
+
+ /**
+ * The <code>dup2x1</code> opcode.
+ */
+ public StackInstruction dup2x1() {
+ return (StackInstruction) addInstruction(Constants.DUP2X1);
+ }
+
+ /**
+ * The <code>dup2x2</code> opcode.
+ */
+ public StackInstruction dup2x2() {
+ return (StackInstruction) addInstruction(Constants.DUP2X2);
+ }
+
+ /**
+ * The <code>swap</code> opcode.
+ */
+ public StackInstruction swap() {
+ return (StackInstruction) addInstruction(Constants.SWAP);
+ }
+
+ /**
+ * Perform some math operation on the stack items. This instruction will
+ * result in a <code>nop</code> 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 <code>nop</code> 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 <code>iadd</code> opcode.
+ */
+ public MathInstruction iadd() {
+ return (MathInstruction) addInstruction(Constants.IADD);
+ }
+
+ /**
+ * Add the top two stack long values; the <code>ladd</code> opcode.
+ */
+ public MathInstruction ladd() {
+ return (MathInstruction) addInstruction(Constants.LADD);
+ }
+
+ /**
+ * Add the top two stack float values; the <code>fadd</code> opcode.
+ */
+ public MathInstruction fadd() {
+ return (MathInstruction) addInstruction(Constants.FADD);
+ }
+
+ /**
+ * Add the top two stack double values; the <code>dadd</code> opcode.
+ */
+ public MathInstruction dadd() {
+ return (MathInstruction) addInstruction(Constants.DADD);
+ }
+
+ /**
+ * Subtract the top two stack values. This instruction will result in
+ * a <code>nop</code> 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 <code>isub</code> opcode.
+ */
+ public MathInstruction isub() {
+ return (MathInstruction) addInstruction(Constants.ISUB);
+ }
+
+ /**
+ * Subtract the top two stack long values; the <code>lsub</code> opcode.
+ */
+ public MathInstruction lsub() {
+ return (MathInstruction) addInstruction(Constants.LSUB);
+ }
+
+ /**
+ * Subtract the top two stack float values; the <code>fsub</code> opcode.
+ */
+ public MathInstruction fsub() {
+ return (MathInstruction) addInstruction(Constants.FSUB);
+ }
+
+ /**
+ * Subtract the top two stack double values; the <code>dsub</code> opcode.
+ */
+ public MathInstruction dsub() {
+ return (MathInstruction) addInstruction(Constants.DSUB);
+ }
+
+ /**
+ * Multiply the top two stack values. This instruction will result in
+ * a <code>nop</code> 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 <code>imul</code> opcode.
+ */
+ public MathInstruction imul() {
+ return (MathInstruction) addInstruction(Constants.IMUL);
+ }
+
+ /**
+ * Multiply the top two stack long values; the <code>lmul</code> opcode.
+ */
+ public MathInstruction lmul() {
+ return (MathInstruction) addInstruction(Constants.LMUL);
+ }
+
+ /**
+ * Multiply the top two stack float values; the <code>fmul</code> opcode.
+ */
+ public MathInstruction fmul() {
+ return (MathInstruction) addInstruction(Constants.FMUL);
+ }
+
+ /**
+ * Multiply the top two stack double values; the <code>dmul</code> opcode.
+ */
+ public MathInstruction dmul() {
+ return (MathInstruction) addInstruction(Constants.DMUL);
+ }
+
+ /**
+ * Divide the top two stack values. This instruction will result in
+ * a <code>nop</code> 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 <code>idiv</code> opcode.
+ */
+ public MathInstruction idiv() {
+ return (MathInstruction) addInstruction(Constants.IDIV);
+ }
+
+ /**
+ * Divide the top two stack long values; the <code>ldiv</code> opcode.
+ */
+ public MathInstruction ldiv() {
+ return (MathInstruction) addInstruction(Constants.LDIV);
+ }
+
+ /**
+ * Divide the top two stack float values; the <code>fdiv</code> opcode.
+ */
+ public MathInstruction fdiv() {
+ return (MathInstruction) addInstruction(Constants.FDIV);
+ }
+
+ /**
+ * Divide the top two stack double values; the <code>ddiv</code> opcode.
+ */
+ public MathInstruction ddiv() {
+ return (MathInstruction) addInstruction(Constants.DDIV);
+ }
+
+ /**
+ * Take the remainder of the top two stack values. This instruction will
+ * result in a <code>nop</code> 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
+ * <code>irem</code> opcode.
+ */
+ public MathInstruction irem() {
+ return (MathInstruction) addInstruction(Constants.IREM);
+ }
+
+ /**
+ * Take the remainder of the top two long stack values; the
+ * <code>lrem</code> opcode.
+ */
+ public MathInstruction lrem() {
+ return (MathInstruction) addInstruction(Constants.LREM);
+ }
+
+ /**
+ * Take the remainder of the top two float stack values; the
+ * <code>frem</code> opcode.
+ */
+ public MathInstruction frem() {
+ return (MathInstruction) addInstruction(Constants.FREM);
+ }
+
+ /**
+ * Take the remainder of the top two double stack values; the
+ * <code>drem</code> opcode.
+ */
+ public MathInstruction drem() {
+ return (MathInstruction) addInstruction(Constants.DREM);
+ }
+
+ /**
+ * Negate the top stack value. This instruction will result in a
+ * <code>nop</code> until its type is set.
+ */
+ public MathInstruction xneg() {
+ MathInstruction mi = math();
+
+ return mi.setOperation(Constants.MATH_NEG);
+ }
+
+ /**
+ * Negate the top stack int value; the <code>ineg</code> opcode.
+ */
+ public MathInstruction ineg() {
+ return (MathInstruction) addInstruction(Constants.INEG);
+ }
+
+ /**
+ * Negate the top stack long value; the <code>lneg</code> opcode.
+ */
+ public MathInstruction lneg() {
+ return (MathInstruction) addInstruction(Constants.LNEG);
+ }
+
+ /**
+ * Negate the top stack float value; the <code>fneg</code> opcode.
+ */
+ public MathInstruction fneg() {
+ return (MathInstruction) addInstruction(Constants.FNEG);
+ }
+
+ /**
+ * Negate the top stack double value; the <code>dneg</code> opcode.
+ */
+ public MathInstruction dneg() {
+ return (MathInstruction) addInstruction(Constants.DNEG);
+ }
+
+ /**
+ * Shift the top stack values. This instruction will result in a
+ * <code>nop</code> until its type is set.
+ */
+ public MathInstruction xshl() {
+ MathInstruction mi = math();
+
+ return mi.setOperation(Constants.MATH_SHL);
+ }
+
+ /**
+ * Shift the top stack int values; the <code>ishl</code> opcode.
+ */
+ public MathInstruction ishl() {
+ return (MathInstruction) addInstruction(Constants.ISHL);
+ }
+
+ /**
+ * Shift the top stack long values; the <code>lshl</code> opcode.
+ */
+ public MathInstruction lshl() {
+ return (MathInstruction) addInstruction(Constants.LSHL);
+ }
+
+ /**
+ * Shift the top stack values. This instruction will result in a
+ * <code>nop</code> until its type is set.
+ */
+ public MathInstruction xshr() {
+ MathInstruction mi = math();
+
+ return mi.setOperation(Constants.MATH_SHR);
+ }
+
+ /**
+ * Shift the top stack int values; the <code>ishr</code> opcode.
+ */
+ public MathInstruction ishr() {
+ return (MathInstruction) addInstruction(Constants.ISHR);
+ }
+
+ /**
+ * Shift the top stack long values; the <code>lshr</code> opcode.
+ */
+ public MathInstruction lshr() {
+ return (MathInstruction) addInstruction(Constants.LSHR);
+ }
+
+ /**
+ * Shift the top stack values. This instruction will result in a
+ * <code>nop</code> until its type is set.
+ */
+ public MathInstruction xushr() {
+ MathInstruction mi = math();
+
+ return mi.setOperation(Constants.MATH_USHR);
+ }
+
+ /**
+ * Shift the top stack int values; the <code>iushr</code> opcode.
+ */
+ public MathInstruction iushr() {
+ return (MathInstruction) addInstruction(Constants.IUSHR);
+ }
+
+ /**
+ * Shift the top stack long values; the <code>lushr</code> opcode.
+ */
+ public MathInstruction lushr() {
+ return (MathInstruction) addInstruction(Constants.LUSHR);
+ }
+
+ /**
+ * Take the mathematical and of the top two stack values. This instruction
+ * results in a <code>nop</code> 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
+ * <code>iand</code> opcode.
+ */
+ public MathInstruction iand() {
+ return (MathInstruction) addInstruction(Constants.IAND);
+ }
+
+ /**
+ * Take the mathematical and of the top two stack long values; the
+ * <code>land</code> opcode.
+ */
+ public MathInstruction land() {
+ return (MathInstruction) addInstruction(Constants.LAND);
+ }
+
+ /**
+ * Take the mathematical or of the top two stack values. This instruction
+ * results in a <code>nop</code> 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
+ * <code>ior</code> opcode.
+ */
+ public MathInstruction ior() {
+ return (MathInstruction) addInstruction(Constants.IOR);
+ }
+
+ /**
+ * Take the mathematical or of the top two stack long values; the
+ * <code>lor</code> opcode.
+ */
+ public MathInstruction lor() {
+ return (MathInstruction) addInstruction(Constants.LOR);
+ }
+
+ /**
+ * Take the mathematical xor of the top two stack values. This instruction
+ * results in a <code>nop</code> 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
+ * <code>ixor</code> opcode.
+ */
+ public MathInstruction ixor() {
+ return (MathInstruction) addInstruction(Constants.IXOR);
+ }
+
+ /**
+ * Take the mathematical xor of the top two stack long values; the
+ * <code>lxor</code> opcode.
+ */
+ public MathInstruction lxor() {
+ return (MathInstruction) addInstruction(Constants.LXOR);
+ }
+
+ /**
+ * Convert the top stack value to another type. This instruction
+ * will result in a <code>nop</code> 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
+ * <code>nop</code> until its type is set.
+ */
+ public CmpInstruction xcmp() {
+ return (CmpInstruction) addInstruction(new CmpInstruction(this));
+ }
+
+ /**
+ * Compare the top two stack values; the <code>lcmp</code> opcode.
+ */
+ public CmpInstruction lcmp() {
+ return (CmpInstruction) addInstruction(Constants.LCMP);
+ }
+
+ /**
+ * Compare the top two stack values; the <code>fcmpl</code> opcode.
+ */
+ public CmpInstruction fcmpl() {
+ return (CmpInstruction) addInstruction(Constants.FCMPL);
+ }
+
+ /**
+ * Compare the top two stack values; the <code>fcmpg</code> opcode.
+ */
+ public CmpInstruction fcmpg() {
+ return (CmpInstruction) addInstruction(Constants.FCMPG);
+ }
+
+ /**
+ * Compare the top two stack values; the <code>dcmpl</code> opcode.
+ */
+ public CmpInstruction dcmpl() {
+ return (CmpInstruction) addInstruction(Constants.DCMPL);
+ }
+
+ /**
+ * Compare the top two stack values; the <code>dcmpg</code> opcode.
+ */
+ public CmpInstruction dcmpg() {
+ return (CmpInstruction) addInstruction(Constants.DCMPG);
+ }
+
+ /**
+ * The <code>ifeq</code> opcode.
+ */
+ public IfInstruction ifeq() {
+ return (IfInstruction) addInstruction(Constants.IFEQ);
+ }
+
+ /**
+ * The <code>ifne</code> opcode.
+ */
+ public IfInstruction ifne() {
+ return (IfInstruction) addInstruction(Constants.IFNE);
+ }
+
+ /**
+ * The <code>iflt</code> opcode.
+ */
+ public IfInstruction iflt() {
+ return (IfInstruction) addInstruction(Constants.IFLT);
+ }
+
+ /**
+ * The <code>ifge</code> opcode.
+ */
+ public IfInstruction ifge() {
+ return (IfInstruction) addInstruction(Constants.IFGE);
+ }
+
+ /**
+ * The <code>ifgt</code> opcode.
+ */
+ public IfInstruction ifgt() {
+ return (IfInstruction) addInstruction(Constants.IFGT);
+ }
+
+ /**
+ * The <code>ifle</code> opcode.
+ */
+ public IfInstruction ifle() {
+ return (IfInstruction) addInstruction(Constants.IFLE);
+ }
+
+ /**
+ * The <code>ificmpeq</code> opcode.
+ */
+ public IfInstruction ificmpeq() {
+ return (IfInstruction) addInstruction(Constants.IFICMPEQ);
+ }
+
+ /**
+ * The <code>ificmpne</code> opcode.
+ */
+ public IfInstruction ificmpne() {
+ return (IfInstruction) addInstruction(Constants.IFICMPNE);
+ }
+
+ /**
+ * The <code>ificmplt</code> opcode.
+ */
+ public IfInstruction ificmplt() {
+ return (IfInstruction) addInstruction(Constants.IFICMPLT);
+ }
+
+ /**
+ * The <code>ificmpge</code> opcode.
+ */
+ public IfInstruction ificmpge() {
+ return (IfInstruction) addInstruction(Constants.IFICMPGE);
+ }
+
+ /**
+ * The <code>ificmpgt</code> opcode.
+ */
+ public IfInstruction ificmpgt() {
+ return (IfInstruction) addInstruction(Constants.IFICMPGT);
+ }
+
+ /**
+ * The <code>ificmple</code> opcode.
+ */
+ public IfInstruction ificmple() {
+ return (IfInstruction) addInstruction(Constants.IFICMPLE);
+ }
+
+ /**
+ * The <code>ifacmpeq</code> opcode.
+ */
+ public IfInstruction ifacmpeq() {
+ return (IfInstruction) addInstruction(Constants.IFACMPEQ);
+ }
+
+ /**
+ * The <code>ifacmpne</code> opcode.
+ */
+ public IfInstruction ifacmpne() {
+ return (IfInstruction) addInstruction(Constants.IFACMPNE);
+ }
+
+ /**
+ * The <code>ifnull</code> opcode.
+ */
+ public IfInstruction ifnull() {
+ return (IfInstruction) addInstruction(Constants.IFNULL);
+ }
+
+ /**
+ * The <code>ifnonnull</code> opcode.
+ */
+ public IfInstruction ifnonnull() {
+ return (IfInstruction) addInstruction(Constants.IFNONNULL);
+ }
+
+ /**
+ * The <code>go2</code> opcode.
+ */
+ public JumpInstruction go2() {
+ return (JumpInstruction) addInstruction(Constants.GOTO);
+ }
+
+ /**
+ * The <code>jsr</code> opcode used in implementing <code>finally</code>
+ * clauses.
+ */
+ public JumpInstruction jsr() {
+ return (JumpInstruction) addInstruction(Constants.JSR);
+ }
+
+ /**
+ * The <code>tableswitch</code> opcode.
+ */
+ public TableSwitchInstruction tableswitch() {
+ return (TableSwitchInstruction) addInstruction(Constants.TABLESWITCH);
+ }
+
+ /**
+ * The <code>lookupswitch</code> opcode.
+ */
+ public LookupSwitchInstruction lookupswitch() {
+ return (LookupSwitchInstruction) addInstruction(Constants.LOOKUPSWITCH);
+ }
+
+ /**
+ * Return from a method. This method will result in a
+ * <code>nop</code> until its type is set.
+ */
+ public ReturnInstruction xreturn() {
+ return (ReturnInstruction) addInstruction(new ReturnInstruction(this));
+ }
+
+ /**
+ * Return void from a method; the <code>return</code> opcode.
+ */
+ public ReturnInstruction vreturn() {
+ return (ReturnInstruction) addInstruction(Constants.RETURN);
+ }
+
+ /**
+ * Return an int from a method; the <code>ireturn</code> opcode.
+ */
+ public ReturnInstruction ireturn() {
+ return (ReturnInstruction) addInstruction(Constants.IRETURN);
+ }
+
+ /**
+ * Return a long from a method; the <code>lreturn</code> opcode.
+ */
+ public ReturnInstruction lreturn() {
+ return (ReturnInstruction) addInstruction(Constants.LRETURN);
+ }
+
+ /**
+ * Return a float from a method; the <code>freturn</code> opcode.
+ */
+ public ReturnInstruction freturn() {
+ return (ReturnInstruction) addInstruction(Constants.FRETURN);
+ }
+
+ /**
+ * Return a double from a method; the <code>dreturn</code> opcode.
+ */
+ public ReturnInstruction dreturn() {
+ return (ReturnInstruction) addInstruction(Constants.DRETURN);
+ }
+
+ /**
+ * Return an object from a method; the <code>areturn</code> opcode.
+ */
+ public ReturnInstruction areturn() {
+ return (ReturnInstruction) addInstruction(Constants.ARETURN);
+ }
+
+ /**
+ * Load the value from a field onto the stack; the <code>getfield</code>
+ * opcode.
+ */
+ public GetFieldInstruction getfield() {
+ return (GetFieldInstruction) addInstruction(Constants.GETFIELD);
+ }
+
+ /**
+ * Load the value from a static field onto the stack; the
+ * <code>getstatic</code> opcode.
+ */
+ public GetFieldInstruction getstatic() {
+ return (GetFieldInstruction) addInstruction(Constants.GETSTATIC);
+ }
+
+ /**
+ * Place the value of a field onto the stack; the <code>putfield</code>
+ * opcode.
+ */
+ public PutFieldInstruction putfield() {
+ return (PutFieldInstruction) addInstruction(Constants.PUTFIELD);
+ }
+
+ /**
+ * Place the value of a static field onto the stack; the
+ * <code>putstatic</code> opcode.
+ */
+ public PutFieldInstruction putstatic() {
+ return (PutFieldInstruction) addInstruction(Constants.PUTSTATIC);
+ }
+
+ /**
+ * Invoke a virtual method; the <code>invokevirtual</code> opcode.
+ */
+ public MethodInstruction invokevirtual() {
+ return (MethodInstruction) addInstruction(Constants.INVOKEVIRTUAL);
+ }
+
+ /**
+ * Invoke a method non-virtually, as for constructors and superclass
+ * methods; the <code>invokespecial</code> opcode.
+ */
+ public MethodInstruction invokespecial() {
+ return (MethodInstruction) addInstruction(Constants.INVOKESPECIAL);
+ }
+
+ /**
+ * Invoke a method on an interface; the <code>invokeinterface</code>
+ * opcode.
+ */
+ public MethodInstruction invokeinterface() {
+ return (MethodInstruction) addInstruction(Constants.INVOKEINTERFACE);
+ }
+
+ /**
+ * Invoke a static method; the <code>invokestatic</code> opcode.
+ */
+ public MethodInstruction invokestatic() {
+ return (MethodInstruction) addInstruction(Constants.INVOKESTATIC);
+ }
+
+ /**
+ * Create a new instance of an object; the <code>new</code> opcode.
+ */
+ public ClassInstruction anew() {
+ return (ClassInstruction) addInstruction(Constants.NEW);
+ }
+
+ /**
+ * Create a new instance of an object array; the <code>anew</code> opcode.
+ */
+ public ClassInstruction anewarray() {
+ return (ClassInstruction) addInstruction(Constants.ANEWARRAY);
+ }
+
+ /**
+ * Cast an object on the stack to another type; the <code>checkcast</code>
+ * opcode.
+ */
+ public ClassInstruction checkcast() {
+ return (ClassInstruction) addInstruction(Constants.CHECKCAST);
+ }
+
+ /**
+ * Test if a stack object is an instance of a class; the
+ * <code>instanceof</code> opcode.
+ */
+ public ClassInstruction isinstance() {
+ return (ClassInstruction) addInstruction(Constants.INSTANCEOF);
+ }
+
+ /**
+ * Create a new multidimensional array; the <code>multianewarray</code>
+ * opcode.
+ */
+ public MultiANewArrayInstruction multianewarray() {
+ return (MultiANewArrayInstruction) addInstruction(Constants.MULTIANEWARRAY);
+ }
+
+ /**
+ * Create a new array of a primitive type; the <code>newarray</code>
+ * opcode.
+ */
+ public NewArrayInstruction newarray() {
+ return (NewArrayInstruction) addInstruction(Constants.NEWARRAY);
+ }
+
+ /**
+ * Get the length of an array on the stack; the <code>arraylength</code>
+ * opcode.
+ */
+ public Instruction arraylength() {
+ return addInstruction(Constants.ARRAYLENGTH);
+ }
+
+ /**
+ * Throw an exception; the <code>athrow</code> opcode.
+ */
+ public Instruction athrow() {
+ return addInstruction(Constants.ATHROW);
+ }
+
+ /**
+ * The <code>monitorenter</code> opcode.
+ */
+ public MonitorEnterInstruction monitorenter() {
+ return (MonitorEnterInstruction) addInstruction(Constants.MONITORENTER);
+ }
+
+ /**
+ * The <code>monitorexit</code> 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
+ try {
+ length += toByteArray().length;
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe.toString());
+ }
+
+ // 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 <code>add</code> 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 <code>add</code> 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 <code>add</code> 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;
+ 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 = addInstruction(origIns.getOpcode());
+
+ 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;
+ beforeFirst();
+
+ Instruction ins;
+
+ for (int byteIndex = 0; byteIndex < len;) {
+ ins = addInstruction(in.readUnsignedByte());
+ ins.read(in);
+ byteIndex += ins.getLength();
+ }
+
+ updateInstructionPointers();
+ beforeFirst();
+ }
+
+ /**
+ * 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) {
+ 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");
+ }
+
+ /**
+ * 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();
+ }
+
+ throw new IllegalArgumentException(String.valueOf(byteIndex));
+ }
+
+ /**
+ * 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 JumpInstruction(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:
+ 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) {
+ 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;
+ }
+
+ 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;
+ }
+
+ 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);
+ }
+ }
+ }
+}
Propchange: incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/Code.java
------------------------------------------------------------------------------
svn:executable = *
Added: incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/CodeEntry.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/CodeEntry.java?rev=417860&view=auto
==============================================================================
--- incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/CodeEntry.java (added)
+++ incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/CodeEntry.java Wed Jun 28 12:46:13 2006
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package serp.bytecode;
+
+
+/**
+ * <p>An entry in a code block.</p>
+ *
+ * @author Abe White
+ */
+class CodeEntry {
+ CodeEntry next = null;
+ CodeEntry prev = null;
+}
Propchange: incubator/openjpa/trunk/serp/src/main/java/serp/bytecode/CodeEntry.java
------------------------------------------------------------------------------
svn:executable = *