src/share/classes/jdk/internal/org/objectweb/asm/tree/analysis/Frame.java

Print this page




  56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  57  * THE POSSIBILITY OF SUCH DAMAGE.
  58  */
  59 package jdk.internal.org.objectweb.asm.tree.analysis;
  60 
  61 import java.util.ArrayList;
  62 import java.util.List;
  63 
  64 import jdk.internal.org.objectweb.asm.Opcodes;
  65 import jdk.internal.org.objectweb.asm.Type;
  66 import jdk.internal.org.objectweb.asm.tree.AbstractInsnNode;
  67 import jdk.internal.org.objectweb.asm.tree.IincInsnNode;
  68 import jdk.internal.org.objectweb.asm.tree.InvokeDynamicInsnNode;
  69 import jdk.internal.org.objectweb.asm.tree.MethodInsnNode;
  70 import jdk.internal.org.objectweb.asm.tree.MultiANewArrayInsnNode;
  71 import jdk.internal.org.objectweb.asm.tree.VarInsnNode;
  72 
  73 /**
  74  * A symbolic execution stack frame. A stack frame contains a set of local
  75  * variable slots, and an operand stack. Warning: long and double values are
  76  * represented by <i>two</i> slots in local variables, and by <i>one</i> slot
  77  * in the operand stack.
  78  *
  79  * @param <V> type of the Value used for the analysis.

  80  *
  81  * @author Eric Bruneton
  82  */
  83 public class Frame<V extends Value> {
  84 
  85     /**
  86      * The expected return type of the analyzed method, or <tt>null</tt> if the
  87      * method returns void.
  88      */
  89     private V returnValue;
  90 
  91     /**
  92      * The local variables and operand stack of this frame.
  93      */
  94     private V[] values;
  95 
  96     /**
  97      * The number of local variables of this frame.
  98      */
  99     private int locals;
 100 
 101     /**
 102      * The number of elements in the operand stack.
 103      */
 104     private int top;
 105 
 106     /**
 107      * Constructs a new frame with the given size.
 108      *
 109      * @param nLocals the maximum number of local variables of the frame.
 110      * @param nStack the maximum stack size of the frame.


 111      */
 112     public Frame(final int nLocals, final int nStack) {
 113         this.values = (V[]) new Value[nLocals + nStack];
 114         this.locals = nLocals;
 115     }
 116 
 117     /**
 118      * Constructs a new frame that is identical to the given frame.
 119      *
 120      * @param src a frame.

 121      */
 122     public Frame(final Frame<? extends V> src) {
 123         this(src.locals, src.values.length - src.locals);
 124         init(src);
 125     }
 126 
 127     /**
 128      * Copies the state of the given frame into this frame.
 129      *
 130      * @param src a frame.

 131      * @return this frame.
 132      */
 133     public Frame<V> init(final Frame<? extends V> src) {
 134         returnValue = src.returnValue;
 135         System.arraycopy(src.values, 0, values, 0, values.length);
 136         top = src.top;
 137         return this;
 138     }
 139 
 140     /**
 141      * Sets the expected return type of the analyzed method.
 142      *
 143      * @param v the expected return type of the analyzed method, or

 144      *        <tt>null</tt> if the method returns void.
 145      */
 146     public void setReturn(final V v) {
 147         returnValue = v;
 148     }
 149 
 150     /**
 151      * Returns the maximum number of local variables of this frame.
 152      *
 153      * @return the maximum number of local variables of this frame.
 154      */
 155     public int getLocals() {
 156         return locals;
 157     }
 158 
 159     /**
 160      * Returns the value of the given local variable.
 161      *
 162      * @param i a local variable index.

 163      * @return the value of the given local variable.
 164      * @throws IndexOutOfBoundsException if the variable does not exist.

 165      */
 166     public V getLocal(final int i) throws IndexOutOfBoundsException {
 167         if (i >= locals) {
 168             throw new IndexOutOfBoundsException("Trying to access an inexistant local variable");

 169         }
 170         return values[i];
 171     }
 172 
 173     /**
 174      * Sets the value of the given local variable.
 175      *
 176      * @param i a local variable index.
 177      * @param value the new value of this local variable.
 178      * @throws IndexOutOfBoundsException if the variable does not exist.



 179      */
 180     public void setLocal(final int i, final V value)
 181             throws IndexOutOfBoundsException
 182     {
 183         if (i >= locals) {
 184             throw new IndexOutOfBoundsException("Trying to access an inexistant local variable "+i);

 185         }
 186         values[i] = value;
 187     }
 188 
 189     /**
 190      * Returns the number of values in the operand stack of this frame. Long and
 191      * double values are treated as single values.
 192      *
 193      * @return the number of values in the operand stack of this frame.
 194      */
 195     public int getStackSize() {
 196         return top;
 197     }
 198 
 199     /**
 200      * Returns the value of the given operand stack slot.
 201      *
 202      * @param i the index of an operand stack slot.

 203      * @return the value of the given operand stack slot.
 204      * @throws IndexOutOfBoundsException if the operand stack slot does not
 205      *         exist.
 206      */
 207     public V getStack(final int i) throws IndexOutOfBoundsException {
 208         return values[i + locals];
 209     }
 210 
 211     /**
 212      * Clears the operand stack of this frame.
 213      */
 214     public void clearStack() {
 215         top = 0;
 216     }
 217 
 218     /**
 219      * Pops a value from the operand stack of this frame.
 220      *
 221      * @return the value that has been popped from the stack.
 222      * @throws IndexOutOfBoundsException if the operand stack is empty.

 223      */
 224     public V pop() throws IndexOutOfBoundsException {
 225         if (top == 0) {
 226             throw new IndexOutOfBoundsException("Cannot pop operand off an empty stack.");

 227         }
 228         return values[--top + locals];
 229     }
 230 
 231     /**
 232      * Pushes a value into the operand stack of this frame.
 233      *
 234      * @param value the value that must be pushed into the stack.
 235      * @throws IndexOutOfBoundsException if the operand stack is full.


 236      */
 237     public void push(final V value) throws IndexOutOfBoundsException {
 238         if (top + locals >= values.length) {
 239             throw new IndexOutOfBoundsException("Insufficient maximum stack size.");

 240         }
 241         values[top++ + locals] = value;
 242     }
 243 
 244     public void execute(
 245         final AbstractInsnNode insn,
 246         final Interpreter<V> interpreter) throws AnalyzerException
 247     {
 248         V value1, value2, value3, value4;
 249         List<V> values;
 250         int var;
 251 
 252         switch (insn.getOpcode()) {
 253             case Opcodes.NOP:
 254                 break;
 255             case Opcodes.ACONST_NULL:
 256             case Opcodes.ICONST_M1:
 257             case Opcodes.ICONST_0:
 258             case Opcodes.ICONST_1:
 259             case Opcodes.ICONST_2:
 260             case Opcodes.ICONST_3:
 261             case Opcodes.ICONST_4:
 262             case Opcodes.ICONST_5:
 263             case Opcodes.LCONST_0:
 264             case Opcodes.LCONST_1:
 265             case Opcodes.FCONST_0:
 266             case Opcodes.FCONST_1:
 267             case Opcodes.FCONST_2:


 651             case Opcodes.CHECKCAST:
 652             case Opcodes.INSTANCEOF:
 653                 push(interpreter.unaryOperation(insn, pop()));
 654                 break;
 655             case Opcodes.MONITORENTER:
 656             case Opcodes.MONITOREXIT:
 657                 interpreter.unaryOperation(insn, pop());
 658                 break;
 659             case Opcodes.MULTIANEWARRAY:
 660                 values = new ArrayList<V>();
 661                 for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) {
 662                     values.add(0, pop());
 663                 }
 664                 push(interpreter.naryOperation(insn, values));
 665                 break;
 666             case Opcodes.IFNULL:
 667             case Opcodes.IFNONNULL:
 668                 interpreter.unaryOperation(insn, pop());
 669                 break;
 670             default:
 671                 throw new RuntimeException("Illegal opcode "+insn.getOpcode());
 672         }
 673     }
 674 
 675     /**
 676      * Merges this frame with the given frame.
 677      *
 678      * @param frame a frame.
 679      * @param interpreter the interpreter used to merge values.


 680      * @return <tt>true</tt> if this frame has been changed as a result of the
 681      *         merge operation, or <tt>false</tt> otherwise.
 682      * @throws AnalyzerException if the frames have incompatible sizes.

 683      */
 684     public boolean merge(final Frame<? extends V> frame, final Interpreter<V> interpreter)
 685             throws AnalyzerException
 686     {
 687         if (top != frame.top) {
 688             throw new AnalyzerException(null, "Incompatible stack heights");
 689         }
 690         boolean changes = false;
 691         for (int i = 0; i < locals + top; ++i) {
 692             V v = interpreter.merge(values[i], frame.values[i]);
 693             if (v != values[i]) {
 694                 values[i] = v;
 695                 changes |= true;
 696             }
 697         }
 698         return changes;
 699     }
 700 
 701     /**
 702      * Merges this frame with the given frame (case of a RET instruction).
 703      *
 704      * @param frame a frame
 705      * @param access the local variables that have been accessed by the
 706      *        subroutine to which the RET instruction corresponds.


 707      * @return <tt>true</tt> if this frame has been changed as a result of the
 708      *         merge operation, or <tt>false</tt> otherwise.
 709      */
 710     public boolean merge(final Frame<? extends V> frame, final boolean[] access) {
 711         boolean changes = false;
 712         for (int i = 0; i < locals; ++i) {
 713             if (!access[i] && !values[i].equals(frame.values[i])) {
 714                 values[i] = frame.values[i];
 715                 changes = true;
 716             }
 717         }
 718         return changes;
 719     }
 720 
 721     /**
 722      * Returns a string representation of this frame.
 723      *
 724      * @return a string representation of this frame.
 725      */
 726     @Override


  56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  57  * THE POSSIBILITY OF SUCH DAMAGE.
  58  */
  59 package jdk.internal.org.objectweb.asm.tree.analysis;
  60 
  61 import java.util.ArrayList;
  62 import java.util.List;
  63 
  64 import jdk.internal.org.objectweb.asm.Opcodes;
  65 import jdk.internal.org.objectweb.asm.Type;
  66 import jdk.internal.org.objectweb.asm.tree.AbstractInsnNode;
  67 import jdk.internal.org.objectweb.asm.tree.IincInsnNode;
  68 import jdk.internal.org.objectweb.asm.tree.InvokeDynamicInsnNode;
  69 import jdk.internal.org.objectweb.asm.tree.MethodInsnNode;
  70 import jdk.internal.org.objectweb.asm.tree.MultiANewArrayInsnNode;
  71 import jdk.internal.org.objectweb.asm.tree.VarInsnNode;
  72 
  73 /**
  74  * A symbolic execution stack frame. A stack frame contains a set of local
  75  * variable slots, and an operand stack. Warning: long and double values are
  76  * represented by <i>two</i> slots in local variables, and by <i>one</i> slot in
  77  * the operand stack.
  78  *
  79  * @param <V>
  80  *            type of the Value used for the analysis.
  81  *
  82  * @author Eric Bruneton
  83  */
  84 public class Frame<V extends Value> {
  85 
  86     /**
  87      * The expected return type of the analyzed method, or <tt>null</tt> if the
  88      * method returns void.
  89      */
  90     private V returnValue;
  91 
  92     /**
  93      * The local variables and operand stack of this frame.
  94      */
  95     private V[] values;
  96 
  97     /**
  98      * The number of local variables of this frame.
  99      */
 100     private int locals;
 101 
 102     /**
 103      * The number of elements in the operand stack.
 104      */
 105     private int top;
 106 
 107     /**
 108      * Constructs a new frame with the given size.
 109      *
 110      * @param nLocals
 111      *            the maximum number of local variables of the frame.
 112      * @param nStack
 113      *            the maximum stack size of the frame.
 114      */
 115     public Frame(final int nLocals, final int nStack) {
 116         this.values = (V[]) new Value[nLocals + nStack];
 117         this.locals = nLocals;
 118     }
 119 
 120     /**
 121      * Constructs a new frame that is identical to the given frame.
 122      *
 123      * @param src
 124      *            a frame.
 125      */
 126     public Frame(final Frame<? extends V> src) {
 127         this(src.locals, src.values.length - src.locals);
 128         init(src);
 129     }
 130 
 131     /**
 132      * Copies the state of the given frame into this frame.
 133      *
 134      * @param src
 135      *            a frame.
 136      * @return this frame.
 137      */
 138     public Frame<V> init(final Frame<? extends V> src) {
 139         returnValue = src.returnValue;
 140         System.arraycopy(src.values, 0, values, 0, values.length);
 141         top = src.top;
 142         return this;
 143     }
 144 
 145     /**
 146      * Sets the expected return type of the analyzed method.
 147      *
 148      * @param v
 149      *            the expected return type of the analyzed method, or
 150      *            <tt>null</tt> if the method returns void.
 151      */
 152     public void setReturn(final V v) {
 153         returnValue = v;
 154     }
 155 
 156     /**
 157      * Returns the maximum number of local variables of this frame.
 158      *
 159      * @return the maximum number of local variables of this frame.
 160      */
 161     public int getLocals() {
 162         return locals;
 163     }
 164 
 165     /**
 166      * Returns the value of the given local variable.
 167      *
 168      * @param i
 169      *            a local variable index.
 170      * @return the value of the given local variable.
 171      * @throws IndexOutOfBoundsException
 172      *             if the variable does not exist.
 173      */
 174     public V getLocal(final int i) throws IndexOutOfBoundsException {
 175         if (i >= locals) {
 176             throw new IndexOutOfBoundsException(
 177                     "Trying to access an inexistant local variable");
 178         }
 179         return values[i];
 180     }
 181 
 182     /**
 183      * Sets the value of the given local variable.
 184      *
 185      * @param i
 186      *            a local variable index.
 187      * @param value
 188      *            the new value of this local variable.
 189      * @throws IndexOutOfBoundsException
 190      *             if the variable does not exist.
 191      */
 192     public void setLocal(final int i, final V value)
 193             throws IndexOutOfBoundsException {

 194         if (i >= locals) {
 195             throw new IndexOutOfBoundsException(
 196                     "Trying to access an inexistant local variable " + i);
 197         }
 198         values[i] = value;
 199     }
 200 
 201     /**
 202      * Returns the number of values in the operand stack of this frame. Long and
 203      * double values are treated as single values.
 204      *
 205      * @return the number of values in the operand stack of this frame.
 206      */
 207     public int getStackSize() {
 208         return top;
 209     }
 210 
 211     /**
 212      * Returns the value of the given operand stack slot.
 213      *
 214      * @param i
 215      *            the index of an operand stack slot.
 216      * @return the value of the given operand stack slot.
 217      * @throws IndexOutOfBoundsException
 218      *             if the operand stack slot does not exist.
 219      */
 220     public V getStack(final int i) throws IndexOutOfBoundsException {
 221         return values[i + locals];
 222     }
 223 
 224     /**
 225      * Clears the operand stack of this frame.
 226      */
 227     public void clearStack() {
 228         top = 0;
 229     }
 230 
 231     /**
 232      * Pops a value from the operand stack of this frame.
 233      *
 234      * @return the value that has been popped from the stack.
 235      * @throws IndexOutOfBoundsException
 236      *             if the operand stack is empty.
 237      */
 238     public V pop() throws IndexOutOfBoundsException {
 239         if (top == 0) {
 240             throw new IndexOutOfBoundsException(
 241                     "Cannot pop operand off an empty stack.");
 242         }
 243         return values[--top + locals];
 244     }
 245 
 246     /**
 247      * Pushes a value into the operand stack of this frame.
 248      *
 249      * @param value
 250      *            the value that must be pushed into the stack.
 251      * @throws IndexOutOfBoundsException
 252      *             if the operand stack is full.
 253      */
 254     public void push(final V value) throws IndexOutOfBoundsException {
 255         if (top + locals >= values.length) {
 256             throw new IndexOutOfBoundsException(
 257                     "Insufficient maximum stack size.");
 258         }
 259         values[top++ + locals] = value;
 260     }
 261 
 262     public void execute(final AbstractInsnNode insn,
 263             final Interpreter<V> interpreter) throws AnalyzerException {


 264         V value1, value2, value3, value4;
 265         List<V> values;
 266         int var;
 267 
 268         switch (insn.getOpcode()) {
 269         case Opcodes.NOP:
 270             break;
 271         case Opcodes.ACONST_NULL:
 272         case Opcodes.ICONST_M1:
 273         case Opcodes.ICONST_0:
 274         case Opcodes.ICONST_1:
 275         case Opcodes.ICONST_2:
 276         case Opcodes.ICONST_3:
 277         case Opcodes.ICONST_4:
 278         case Opcodes.ICONST_5:
 279         case Opcodes.LCONST_0:
 280         case Opcodes.LCONST_1:
 281         case Opcodes.FCONST_0:
 282         case Opcodes.FCONST_1:
 283         case Opcodes.FCONST_2:


 667         case Opcodes.CHECKCAST:
 668         case Opcodes.INSTANCEOF:
 669             push(interpreter.unaryOperation(insn, pop()));
 670             break;
 671         case Opcodes.MONITORENTER:
 672         case Opcodes.MONITOREXIT:
 673             interpreter.unaryOperation(insn, pop());
 674             break;
 675         case Opcodes.MULTIANEWARRAY:
 676             values = new ArrayList<V>();
 677             for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) {
 678                 values.add(0, pop());
 679             }
 680             push(interpreter.naryOperation(insn, values));
 681             break;
 682         case Opcodes.IFNULL:
 683         case Opcodes.IFNONNULL:
 684             interpreter.unaryOperation(insn, pop());
 685             break;
 686         default:
 687             throw new RuntimeException("Illegal opcode " + insn.getOpcode());
 688         }
 689     }
 690 
 691     /**
 692      * Merges this frame with the given frame.
 693      *
 694      * @param frame
 695      *            a frame.
 696      * @param interpreter
 697      *            the interpreter used to merge values.
 698      * @return <tt>true</tt> if this frame has been changed as a result of the
 699      *         merge operation, or <tt>false</tt> otherwise.
 700      * @throws AnalyzerException
 701      *             if the frames have incompatible sizes.
 702      */
 703     public boolean merge(final Frame<? extends V> frame,
 704             final Interpreter<V> interpreter) throws AnalyzerException {

 705         if (top != frame.top) {
 706             throw new AnalyzerException(null, "Incompatible stack heights");
 707         }
 708         boolean changes = false;
 709         for (int i = 0; i < locals + top; ++i) {
 710             V v = interpreter.merge(values[i], frame.values[i]);
 711             if (!v.equals(values[i])) {
 712                 values[i] = v;
 713                 changes = true;
 714             }
 715         }
 716         return changes;
 717     }
 718 
 719     /**
 720      * Merges this frame with the given frame (case of a RET instruction).
 721      *
 722      * @param frame
 723      *            a frame
 724      * @param access
 725      *            the local variables that have been accessed by the subroutine
 726      *            to which the RET instruction corresponds.
 727      * @return <tt>true</tt> if this frame has been changed as a result of the
 728      *         merge operation, or <tt>false</tt> otherwise.
 729      */
 730     public boolean merge(final Frame<? extends V> frame, final boolean[] access) {
 731         boolean changes = false;
 732         for (int i = 0; i < locals; ++i) {
 733             if (!access[i] && !values[i].equals(frame.values[i])) {
 734                 values[i] = frame.values[i];
 735                 changes = true;
 736             }
 737         }
 738         return changes;
 739     }
 740 
 741     /**
 742      * Returns a string representation of this frame.
 743      *
 744      * @return a string representation of this frame.
 745      */
 746     @Override