1 // ASM: a very small and fast Java bytecode manipulation framework 2 // Copyright (c) 2000-2011 INRIA, France Telecom 3 // All rights reserved. 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions 7 // are met: 8 // 1. Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // 2. Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // 3. Neither the name of the copyright holders nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 // THE POSSIBILITY OF SUCH DAMAGE. 28 package org.objectweb.asm.tree; 29 30 import java.util.ArrayList; 31 import java.util.List; 32 import java.util.Map; 33 import org.objectweb.asm.MethodVisitor; 34 import org.objectweb.asm.Opcodes; 35 36 /** 37 * A node that represents a stack map frame. These nodes are pseudo instruction nodes in order to be 38 * inserted in an instruction list. In fact these nodes must(*) be inserted <i>just before</i> any 39 * instruction node <b>i</b> that follows an unconditionnal branch instruction such as GOTO or 40 * THROW, that is the target of a jump instruction, or that starts an exception handler block. The 41 * stack map frame types must describe the values of the local variables and of the operand stack 42 * elements <i>just before</i> <b>i</b> is executed. <br> 43 * <br> 44 * (*) this is mandatory only for classes whose version is greater than or equal to {@link 45 * Opcodes#V1_6}. 46 * 47 * @author Eric Bruneton 48 */ 49 public class FrameNode extends AbstractInsnNode { 50 51 /** 52 * The type of this frame. Must be {@link Opcodes#F_NEW} for expanded frames, or {@link 53 * Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or 54 * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames. 55 */ 56 public int type; 57 58 /** 59 * The types of the local variables of this stack map frame. Elements of this list can be Integer, 60 * String or LabelNode objects (for primitive, reference and uninitialized types respectively - 61 * see {@link MethodVisitor}). 62 */ 63 public List<Object> local; 64 65 /** 66 * The types of the operand stack elements of this stack map frame. Elements of this list can be 67 * Integer, String or LabelNode objects (for primitive, reference and uninitialized types 68 * respectively - see {@link MethodVisitor}). 69 */ 70 public List<Object> stack; 71 FrameNode()72 private FrameNode() { 73 super(-1); 74 } 75 76 /** 77 * Constructs a new {@link FrameNode}. 78 * 79 * @param type the type of this frame. Must be {@link Opcodes#F_NEW} for expanded frames, or 80 * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link 81 * Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames. 82 * @param numLocal number of local variables of this stack map frame. Long and double values count 83 * for one variable. 84 * @param local the types of the local variables of this stack map frame. Elements of this list 85 * can be Integer, String or LabelNode objects (for primitive, reference and uninitialized 86 * types respectively - see {@link MethodVisitor}). Long and double values are represented by 87 * a single element. 88 * @param numStack number of operand stack elements of this stack map frame. Long and double 89 * values count for one stack element. 90 * @param stack the types of the operand stack elements of this stack map frame. Elements of this 91 * list can be Integer, String or LabelNode objects (for primitive, reference and 92 * uninitialized types respectively - see {@link MethodVisitor}). Long and double values are 93 * represented by a single element. 94 */ FrameNode( final int type, final int numLocal, final Object[] local, final int numStack, final Object[] stack)95 public FrameNode( 96 final int type, 97 final int numLocal, 98 final Object[] local, 99 final int numStack, 100 final Object[] stack) { 101 super(-1); 102 this.type = type; 103 switch (type) { 104 case Opcodes.F_NEW: 105 case Opcodes.F_FULL: 106 this.local = Util.asArrayList(numLocal, local); 107 this.stack = Util.asArrayList(numStack, stack); 108 break; 109 case Opcodes.F_APPEND: 110 this.local = Util.asArrayList(numLocal, local); 111 break; 112 case Opcodes.F_CHOP: 113 this.local = Util.asArrayList(numLocal); 114 break; 115 case Opcodes.F_SAME: 116 break; 117 case Opcodes.F_SAME1: 118 this.stack = Util.asArrayList(1, stack); 119 break; 120 default: 121 throw new IllegalArgumentException(); 122 } 123 } 124 125 @Override getType()126 public int getType() { 127 return FRAME; 128 } 129 130 @Override accept(final MethodVisitor methodVisitor)131 public void accept(final MethodVisitor methodVisitor) { 132 switch (type) { 133 case Opcodes.F_NEW: 134 case Opcodes.F_FULL: 135 methodVisitor.visitFrame(type, local.size(), asArray(local), stack.size(), asArray(stack)); 136 break; 137 case Opcodes.F_APPEND: 138 methodVisitor.visitFrame(type, local.size(), asArray(local), 0, null); 139 break; 140 case Opcodes.F_CHOP: 141 methodVisitor.visitFrame(type, local.size(), null, 0, null); 142 break; 143 case Opcodes.F_SAME: 144 methodVisitor.visitFrame(type, 0, null, 0, null); 145 break; 146 case Opcodes.F_SAME1: 147 methodVisitor.visitFrame(type, 0, null, 1, asArray(stack)); 148 break; 149 default: 150 throw new IllegalArgumentException(); 151 } 152 } 153 154 @Override clone(final Map<LabelNode, LabelNode> clonedLabels)155 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) { 156 FrameNode clone = new FrameNode(); 157 clone.type = type; 158 if (local != null) { 159 clone.local = new ArrayList<>(); 160 for (int i = 0, n = local.size(); i < n; ++i) { 161 Object localElement = local.get(i); 162 if (localElement instanceof LabelNode) { 163 localElement = clonedLabels.get(localElement); 164 } 165 clone.local.add(localElement); 166 } 167 } 168 if (stack != null) { 169 clone.stack = new ArrayList<>(); 170 for (int i = 0, n = stack.size(); i < n; ++i) { 171 Object stackElement = stack.get(i); 172 if (stackElement instanceof LabelNode) { 173 stackElement = clonedLabels.get(stackElement); 174 } 175 clone.stack.add(stackElement); 176 } 177 } 178 return clone; 179 } 180 asArray(final List<Object> list)181 private static Object[] asArray(final List<Object> list) { 182 Object[] array = new Object[list.size()]; 183 for (int i = 0, n = array.length; i < n; ++i) { 184 Object o = list.get(i); 185 if (o instanceof LabelNode) { 186 o = ((LabelNode) o).getLabel(); 187 } 188 array[i] = o; 189 } 190 return array; 191 } 192 } 193