1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 package org.apache.bcel.generic; 19 20 import java.io.DataOutputStream; 21 import java.io.IOException; 22 23 import org.apache.bcel.Const; 24 import org.apache.bcel.util.ByteSequence; 25 26 /** 27 * Abstract super class for instructions dealing with local variables. 28 * 29 * @version $Id$ 30 */ 31 public abstract class LocalVariableInstruction extends Instruction implements TypedInstruction, 32 IndexedInstruction { 33 34 /** 35 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 36 */ 37 @Deprecated 38 protected int n = -1; // index of referenced variable 39 40 private short c_tag = -1; // compact version, such as ILOAD_0 41 private short canon_tag = -1; // canonical tag such as ILOAD 42 43 wide()44 private boolean wide() { 45 return n > Const.MAX_BYTE; 46 } 47 48 49 /** 50 * Empty constructor needed for Instruction.readInstruction. 51 * Not to be used otherwise. 52 * tag and length are defined in readInstruction and initFromFile, respectively. 53 */ LocalVariableInstruction(final short canon_tag, final short c_tag)54 LocalVariableInstruction(final short canon_tag, final short c_tag) { 55 super(); 56 this.canon_tag = canon_tag; 57 this.c_tag = c_tag; 58 } 59 60 61 /** 62 * Empty constructor needed for Instruction.readInstruction. 63 * Also used by IINC()! 64 */ LocalVariableInstruction()65 LocalVariableInstruction() { 66 } 67 68 69 /** 70 * @param opcode Instruction opcode 71 * @param c_tag Instruction number for compact version, ALOAD_0, e.g. 72 * @param n local variable index (unsigned short) 73 */ LocalVariableInstruction(final short opcode, final short c_tag, final int n)74 protected LocalVariableInstruction(final short opcode, final short c_tag, final int n) { 75 super(opcode, (short) 2); 76 this.c_tag = c_tag; 77 canon_tag = opcode; 78 setIndex(n); 79 } 80 81 82 /** 83 * Dump instruction as byte code to stream out. 84 * @param out Output stream 85 */ 86 @Override dump( final DataOutputStream out )87 public void dump( final DataOutputStream out ) throws IOException { 88 if (wide()) { 89 out.writeByte(Const.WIDE); 90 } 91 out.writeByte(super.getOpcode()); 92 if (super.getLength() > 1) { // Otherwise ILOAD_n, instruction, e.g. 93 if (wide()) { 94 out.writeShort(n); 95 } else { 96 out.writeByte(n); 97 } 98 } 99 } 100 101 102 /** 103 * Long output format: 104 * 105 * <name of opcode> "["<opcode number>"]" 106 * "("<length of instruction>")" "<"< local variable index>">" 107 * 108 * @param verbose long/short format switch 109 * @return mnemonic for instruction 110 */ 111 @Override toString( final boolean verbose )112 public String toString( final boolean verbose ) { 113 final short _opcode = super.getOpcode(); 114 if (((_opcode >= Const.ILOAD_0) && (_opcode <= Const.ALOAD_3)) 115 || ((_opcode >= Const.ISTORE_0) && (_opcode <= Const.ASTORE_3))) { 116 return super.toString(verbose); 117 } 118 return super.toString(verbose) + " " + n; 119 } 120 121 122 /** 123 * Read needed data (e.g. index) from file. 124 * <pre> 125 * (ILOAD <= tag <= ALOAD_3) || (ISTORE <= tag <= ASTORE_3) 126 * </pre> 127 */ 128 @Override initFromFile( final ByteSequence bytes, final boolean wide )129 protected void initFromFile( final ByteSequence bytes, final boolean wide ) throws IOException { 130 if (wide) { 131 n = bytes.readUnsignedShort(); 132 super.setLength(4); 133 } else { 134 final short _opcode = super.getOpcode(); 135 if (((_opcode >= Const.ILOAD) && (_opcode <= Const.ALOAD)) 136 || ((_opcode >= Const.ISTORE) && (_opcode <= Const.ASTORE))) { 137 n = bytes.readUnsignedByte(); 138 super.setLength(2); 139 } else if (_opcode <= Const.ALOAD_3) { // compact load instruction such as ILOAD_2 140 n = (_opcode - Const.ILOAD_0) % 4; 141 super.setLength(1); 142 } else { // Assert ISTORE_0 <= tag <= ASTORE_3 143 n = (_opcode - Const.ISTORE_0) % 4; 144 super.setLength(1); 145 } 146 } 147 } 148 149 150 /** 151 * @return local variable index (n) referred by this instruction. 152 */ 153 @Override getIndex()154 public final int getIndex() { 155 return n; 156 } 157 158 159 /** 160 * Set the local variable index. 161 * also updates opcode and length 162 * TODO Why? 163 * @see #setIndexOnly(int) 164 */ 165 @Override setIndex( final int n )166 public void setIndex( final int n ) { // TODO could be package-protected? 167 if ((n < 0) || (n > Const.MAX_SHORT)) { 168 throw new ClassGenException("Illegal value: " + n); 169 } 170 this.n = n; 171 // Cannot be < 0 as this is checked above 172 if (n <= 3) { // Use more compact instruction xLOAD_n 173 super.setOpcode((short) (c_tag + n)); 174 super.setLength(1); 175 } else { 176 super.setOpcode(canon_tag); 177 if (wide()) { 178 super.setLength(4); 179 } else { 180 super.setLength(2); 181 } 182 } 183 } 184 185 186 /** @return canonical tag for instruction, e.g., ALOAD for ALOAD_0 187 */ getCanonicalTag()188 public short getCanonicalTag() { 189 return canon_tag; 190 } 191 192 193 /** 194 * Returns the type associated with the instruction - 195 * in case of ALOAD or ASTORE Type.OBJECT is returned. 196 * This is just a bit incorrect, because ALOAD and ASTORE 197 * may work on every ReferenceType (including Type.NULL) and 198 * ASTORE may even work on a ReturnaddressType . 199 * @return type associated with the instruction 200 */ 201 @Override getType( final ConstantPoolGen cp )202 public Type getType( final ConstantPoolGen cp ) { 203 switch (canon_tag) { 204 case Const.ILOAD: 205 case Const.ISTORE: 206 return Type.INT; 207 case Const.LLOAD: 208 case Const.LSTORE: 209 return Type.LONG; 210 case Const.DLOAD: 211 case Const.DSTORE: 212 return Type.DOUBLE; 213 case Const.FLOAD: 214 case Const.FSTORE: 215 return Type.FLOAT; 216 case Const.ALOAD: 217 case Const.ASTORE: 218 return Type.OBJECT; 219 default: 220 throw new ClassGenException("Oops: unknown case in switch" + canon_tag); 221 } 222 } 223 224 /** 225 * Sets the index of the referenced variable (n) only 226 * @since 6.0 227 * @see #setIndex(int) 228 */ setIndexOnly(final int n)229 final void setIndexOnly(final int n) { 230 this.n = n; 231 } 232 } 233