001/*** 002 * ASM: a very small and fast Java bytecode manipulation framework 003 * Copyright (c) 2000-2011 INRIA, France Telecom 004 * All rights reserved. 005 * 006 * Redistribution and use in source and binary forms, with or without 007 * modification, are permitted provided that the following conditions 008 * are met: 009 * 1. Redistributions of source code must retain the above copyright 010 * notice, this list of conditions and the following disclaimer. 011 * 2. Redistributions in binary form must reproduce the above copyright 012 * notice, this list of conditions and the following disclaimer in the 013 * documentation and/or other materials provided with the distribution. 014 * 3. Neither the name of the copyright holders nor the names of its 015 * contributors may be used to endorse or promote products derived from 016 * this software without specific prior written permission. 017 * 018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 028 * THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package io.ebean.enhance.asm.tree; 031 032import io.ebean.enhance.asm.MethodVisitor; 033import io.ebean.enhance.asm.Opcodes; 034 035import java.util.ArrayList; 036import java.util.Arrays; 037import java.util.List; 038import java.util.Map; 039 040/** 041 * A node that represents a stack map frame. These nodes are pseudo instruction 042 * nodes in order to be inserted in an instruction list. In fact these nodes 043 * must(*) be inserted <i>just before</i> any instruction node <b>i</b> that 044 * follows an unconditionnal branch instruction such as GOTO or THROW, that is 045 * the target of a jump instruction, or that starts an exception handler block. 046 * The stack map frame types must describe the values of the local variables and 047 * of the operand stack elements <i>just before</i> <b>i</b> is executed. <br> 048 * <br> 049 * (*) this is mandatory only for classes whose version is greater than or equal 050 * to {@link Opcodes#V1_6 V1_6}. 051 * 052 * @author Eric Bruneton 053 */ 054public class FrameNode extends AbstractInsnNode { 055 056 /** 057 * The type of this frame. Must be {@link Opcodes#F_NEW} for expanded 058 * frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, 059 * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or 060 * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames. 061 */ 062 public int type; 063 064 /** 065 * The types of the local variables of this stack map frame. Elements of 066 * this list can be Integer, String or LabelNode objects (for primitive, 067 * reference and uninitialized types respectively - see 068 * {@link MethodVisitor}). 069 */ 070 public List<Object> local; 071 072 /** 073 * The types of the operand stack elements of this stack map frame. Elements 074 * of this list can be Integer, String or LabelNode objects (for primitive, 075 * reference and uninitialized types respectively - see 076 * {@link MethodVisitor}). 077 */ 078 public List<Object> stack; 079 080 private FrameNode() { 081 super(-1); 082 } 083 084 /** 085 * Constructs a new {@link FrameNode}. 086 * 087 * @param type 088 * the type of this frame. Must be {@link Opcodes#F_NEW} for 089 * expanded frames, or {@link Opcodes#F_FULL}, 090 * {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, 091 * {@link Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, 092 * {@link Opcodes#F_SAME1} for compressed frames. 093 * @param nLocal 094 * number of local variables of this stack map frame. 095 * @param local 096 * the types of the local variables of this stack map frame. 097 * Elements of this list can be Integer, String or LabelNode 098 * objects (for primitive, reference and uninitialized types 099 * respectively - see {@link MethodVisitor}). 100 * @param nStack 101 * number of operand stack elements of this stack map frame. 102 * @param stack 103 * the types of the operand stack elements of this stack map 104 * frame. Elements of this list can be Integer, String or 105 * LabelNode objects (for primitive, reference and uninitialized 106 * types respectively - see {@link MethodVisitor}). 107 */ 108 public FrameNode(final int type, final int nLocal, final Object[] local, 109 final int nStack, final Object[] stack) { 110 super(-1); 111 this.type = type; 112 switch (type) { 113 case Opcodes.F_NEW: 114 case Opcodes.F_FULL: 115 this.local = asList(nLocal, local); 116 this.stack = asList(nStack, stack); 117 break; 118 case Opcodes.F_APPEND: 119 this.local = asList(nLocal, local); 120 break; 121 case Opcodes.F_CHOP: 122 this.local = Arrays.asList(new Object[nLocal]); 123 break; 124 case Opcodes.F_SAME: 125 break; 126 case Opcodes.F_SAME1: 127 this.stack = asList(1, stack); 128 break; 129 } 130 } 131 132 @Override 133 public int getType() { 134 return FRAME; 135 } 136 137 /** 138 * Makes the given visitor visit this stack map frame. 139 * 140 * @param mv 141 * a method visitor. 142 */ 143 @Override 144 public void accept(final MethodVisitor mv) { 145 switch (type) { 146 case Opcodes.F_NEW: 147 case Opcodes.F_FULL: 148 mv.visitFrame(type, local.size(), asArray(local), stack.size(), 149 asArray(stack)); 150 break; 151 case Opcodes.F_APPEND: 152 mv.visitFrame(type, local.size(), asArray(local), 0, null); 153 break; 154 case Opcodes.F_CHOP: 155 mv.visitFrame(type, local.size(), null, 0, null); 156 break; 157 case Opcodes.F_SAME: 158 mv.visitFrame(type, 0, null, 0, null); 159 break; 160 case Opcodes.F_SAME1: 161 mv.visitFrame(type, 0, null, 1, asArray(stack)); 162 break; 163 } 164 } 165 166 @Override 167 public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) { 168 FrameNode clone = new FrameNode(); 169 clone.type = type; 170 if (local != null) { 171 clone.local = new ArrayList<Object>(); 172 for (int i = 0; i < local.size(); ++i) { 173 Object l = local.get(i); 174 if (l instanceof LabelNode) { 175 l = labels.get(l); 176 } 177 clone.local.add(l); 178 } 179 } 180 if (stack != null) { 181 clone.stack = new ArrayList<Object>(); 182 for (int i = 0; i < stack.size(); ++i) { 183 Object s = stack.get(i); 184 if (s instanceof LabelNode) { 185 s = labels.get(s); 186 } 187 clone.stack.add(s); 188 } 189 } 190 return clone; 191 } 192 193 // ------------------------------------------------------------------------ 194 195 private static List<Object> asList(final int n, final Object[] o) { 196 return Arrays.asList(o).subList(0, n); 197 } 198 199 private static Object[] asArray(final List<Object> l) { 200 Object[] objs = new Object[l.size()]; 201 for (int i = 0; i < objs.length; ++i) { 202 Object o = l.get(i); 203 if (o instanceof LabelNode) { 204 o = ((LabelNode) o).getLabel(); 205 } 206 objs[i] = o; 207 } 208 return objs; 209 } 210}