001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 * 017 */ 018package org.apache.bcel.generic; 019 020import java.io.DataOutputStream; 021import java.io.IOException; 022 023import org.apache.bcel.Const; 024import org.apache.bcel.util.ByteSequence; 025 026/** 027 * Abstract super class for instructions dealing with local variables. 028 * 029 * @version $Id: LocalVariableInstruction.java 1812166 2017-10-13 23:48:11Z ggregory $ 030 */ 031public abstract class LocalVariableInstruction extends Instruction implements TypedInstruction, 032 IndexedInstruction { 033 034 /** 035 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 036 */ 037 @Deprecated 038 protected int n = -1; // index of referenced variable 039 040 private short c_tag = -1; // compact version, such as ILOAD_0 041 private short canon_tag = -1; // canonical tag such as ILOAD 042 043 044 private boolean wide() { 045 return n > Const.MAX_BYTE; 046 } 047 048 049 /** 050 * Empty constructor needed for Instruction.readInstruction. 051 * Not to be used otherwise. 052 * tag and length are defined in readInstruction and initFromFile, respectively. 053 */ 054 LocalVariableInstruction(final short canon_tag, final short c_tag) { 055 super(); 056 this.canon_tag = canon_tag; 057 this.c_tag = c_tag; 058 } 059 060 061 /** 062 * Empty constructor needed for Instruction.readInstruction. 063 * Also used by IINC()! 064 */ 065 LocalVariableInstruction() { 066 } 067 068 069 /** 070 * @param opcode Instruction opcode 071 * @param c_tag Instruction number for compact version, ALOAD_0, e.g. 072 * @param n local variable index (unsigned short) 073 */ 074 protected LocalVariableInstruction(final short opcode, final short c_tag, final int n) { 075 super(opcode, (short) 2); 076 this.c_tag = c_tag; 077 canon_tag = opcode; 078 setIndex(n); 079 } 080 081 082 /** 083 * Dump instruction as byte code to stream out. 084 * @param out Output stream 085 */ 086 @Override 087 public void dump( final DataOutputStream out ) throws IOException { 088 if (wide()) { 089 out.writeByte(Const.WIDE); 090 } 091 out.writeByte(super.getOpcode()); 092 if (super.getLength() > 1) { // Otherwise ILOAD_n, instruction, e.g. 093 if (wide()) { 094 out.writeShort(n); 095 } else { 096 out.writeByte(n); 097 } 098 } 099 } 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 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 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 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 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 */ 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 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 */ 229 final void setIndexOnly(final int n) { 230 this.n = n; 231 } 232}