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 |