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