001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.bcel.generic; 020 021import java.io.DataOutputStream; 022import java.io.IOException; 023 024import org.apache.bcel.Const; 025import org.apache.bcel.util.ByteSequence; 026 027/** 028 * Abstract super class for instructions dealing with local variables. 029 */ 030public abstract class LocalVariableInstruction extends Instruction implements TypedInstruction, IndexedInstruction { 031 032 /** 033 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 034 */ 035 @Deprecated 036 protected int n = -1; // index of referenced variable 037 038 private short cTag = -1; // compact version, such as ILOAD_0 039 private short canonTag = -1; // canonical tag such as ILOAD 040 041 /** 042 * Empty constructor needed for Instruction.readInstruction. Also used by IINC()! 043 */ 044 LocalVariableInstruction() { 045 } 046 047 /** 048 * Empty constructor needed for Instruction.readInstruction. Not to be used otherwise. tag and length are defined in 049 * readInstruction and initFromFile, respectively. 050 */ 051 LocalVariableInstruction(final short canonTag, final short cTag) { 052 this.canonTag = canonTag; 053 this.cTag = cTag; 054 } 055 056 /** 057 * Constructs a LocalVariableInstruction. 058 * 059 * @param opcode Instruction opcode. 060 * @param cTag Instruction number for compact version, ALOAD_0, for example. 061 * @param n local variable index (unsigned short). 062 */ 063 protected LocalVariableInstruction(final short opcode, final short cTag, final int n) { 064 super(opcode, (short) 2); 065 this.cTag = cTag; 066 canonTag = opcode; 067 setIndex(n); 068 } 069 070 /** 071 * Dumps instruction as byte code to stream out. 072 * 073 * @param out Output stream. 074 */ 075 @Override 076 public void dump(final DataOutputStream out) throws IOException { 077 if (wide()) { 078 out.writeByte(Const.WIDE); 079 } 080 out.writeByte(super.getOpcode()); 081 if (super.getLength() > 1) { // Otherwise ILOAD_n, instruction, for example. 082 if (wide()) { 083 out.writeShort(n); 084 } else { 085 out.writeByte(n); 086 } 087 } 088 } 089 090 /** 091 * Gets the canonical tag for instruction, for example, ALOAD for ALOAD_0. 092 * 093 * @return canonical tag for instruction, for example, ALOAD for ALOAD_0. 094 */ 095 public short getCanonicalTag() { 096 return canonTag; 097 } 098 099 /** 100 * @return local variable index (n) referred by this instruction. 101 */ 102 @Override 103 public final int getIndex() { 104 return n; 105 } 106 107 /** 108 * Returns the type associated with the instruction - in case of ALOAD or ASTORE Type.OBJECT is returned. This is just a 109 * bit incorrect, because ALOAD and ASTORE may work on every ReferenceType (including Type.NULL) and ASTORE may even 110 * work on a ReturnaddressType. 111 * 112 * @return type associated with the instruction. 113 */ 114 @Override 115 public Type getType(final ConstantPoolGen cp) { 116 switch (canonTag) { 117 case Const.ILOAD: 118 case Const.ISTORE: 119 return Type.INT; 120 case Const.LLOAD: 121 case Const.LSTORE: 122 return Type.LONG; 123 case Const.DLOAD: 124 case Const.DSTORE: 125 return Type.DOUBLE; 126 case Const.FLOAD: 127 case Const.FSTORE: 128 return Type.FLOAT; 129 case Const.ALOAD: 130 case Const.ASTORE: 131 return Type.OBJECT; 132 default: 133 throw new ClassGenException("Unknown case in switch" + canonTag); 134 } 135 } 136 137 /** 138 * Reads needed data (for example index) from file. 139 * 140 * <pre> 141 * (ILOAD <= tag <= ALOAD_3) || (ISTORE <= tag <= ASTORE_3) 142 * </pre> 143 */ 144 @Override 145 protected void initFromFile(final ByteSequence bytes, final boolean wide) throws IOException { 146 if (wide) { 147 n = bytes.readUnsignedShort(); 148 super.setLength(4); 149 } else { 150 final short opcode = super.getOpcode(); 151 if (opcode >= Const.ILOAD && opcode <= Const.ALOAD || opcode >= Const.ISTORE && opcode <= Const.ASTORE) { 152 n = bytes.readUnsignedByte(); 153 super.setLength(2); 154 } else { 155 if (opcode <= Const.ALOAD_3) { // compact load instruction such as ILOAD_2 156 n = (opcode - Const.ILOAD_0) % 4; 157 } else { // Assert ISTORE_0 <= tag <= ASTORE_3 158 n = (opcode - Const.ISTORE_0) % 4; 159 } 160 super.setLength(1); 161 } 162 } 163 } 164 165 /** 166 * Sets the local variable index. also updates opcode and length TODO Why? 167 * 168 * @see #setIndexOnly(int) 169 */ 170 @Override 171 public void setIndex(final int n) { // TODO could be package-protected? 172 if (n < 0 || n > Const.MAX_SHORT) { 173 throw new ClassGenException("Illegal value: " + n); 174 } 175 this.n = n; 176 // Cannot be < 0 as this is checked above 177 if (n <= 3) { // Use more compact instruction xLOAD_n 178 super.setOpcode((short) (cTag + n)); 179 super.setLength(1); 180 } else { 181 super.setOpcode(canonTag); 182 if (wide()) { 183 super.setLength(4); 184 } else { 185 super.setLength(2); 186 } 187 } 188 } 189 190 /** 191 * Sets the index of the referenced variable (n) only 192 * 193 * @since 6.0 194 * @see #setIndex(int) 195 */ 196 final void setIndexOnly(final int n) { 197 this.n = n; 198 } 199 200 /** 201 * Long output format: 202 * 203 * <name of opcode> "["<opcode number>"]" "("<length of instruction>")" "<"< local variable 204 * index>">" 205 * 206 * @param verbose long/short format switch. 207 * @return mnemonic for instruction. 208 */ 209 @Override 210 public String toString(final boolean verbose) { 211 final short opcode = super.getOpcode(); 212 if (opcode >= Const.ILOAD_0 && opcode <= Const.ALOAD_3 || opcode >= Const.ISTORE_0 && opcode <= Const.ASTORE_3) { 213 return super.toString(verbose); 214 } 215 return super.toString(verbose) + " " + n; 216 } 217 218 private boolean wide() { 219 return n > Const.MAX_BYTE; 220 } 221}