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 */ 030public abstract class LocalVariableInstruction extends Instruction implements TypedInstruction, 031 IndexedInstruction { 032 033 /** 034 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 035 */ 036 @Deprecated 037 protected int n = -1; // index of referenced variable 038 039 private short c_tag = -1; // compact version, such as ILOAD_0 040 private short canon_tag = -1; // canonical tag such as ILOAD 041 042 043 private boolean wide() { 044 return n > Const.MAX_BYTE; 045 } 046 047 048 /** 049 * Empty constructor needed for Instruction.readInstruction. 050 * Not to be used otherwise. 051 * tag and length are defined in readInstruction and initFromFile, respectively. 052 */ 053 LocalVariableInstruction(final short canon_tag, final short c_tag) { 054 super(); 055 this.canon_tag = canon_tag; 056 this.c_tag = c_tag; 057 } 058 059 060 /** 061 * Empty constructor needed for Instruction.readInstruction. 062 * Also used by IINC()! 063 */ 064 LocalVariableInstruction() { 065 } 066 067 068 /** 069 * @param opcode Instruction opcode 070 * @param c_tag Instruction number for compact version, ALOAD_0, e.g. 071 * @param n local variable index (unsigned short) 072 */ 073 protected LocalVariableInstruction(final short opcode, final short c_tag, final int n) { 074 super(opcode, (short) 2); 075 this.c_tag = c_tag; 076 canon_tag = opcode; 077 setIndex(n); 078 } 079 080 081 /** 082 * Dump instruction as byte code to stream out. 083 * @param out Output stream 084 */ 085 @Override 086 public void dump( final DataOutputStream out ) throws IOException { 087 if (wide()) { 088 out.writeByte(Const.WIDE); 089 } 090 out.writeByte(super.getOpcode()); 091 if (super.getLength() > 1) { // Otherwise ILOAD_n, instruction, e.g. 092 if (wide()) { 093 out.writeShort(n); 094 } else { 095 out.writeByte(n); 096 } 097 } 098 } 099 100 101 /** 102 * Long output format: 103 * 104 * <name of opcode> "["<opcode number>"]" 105 * "("<length of instruction>")" "<"< local variable index>">" 106 * 107 * @param verbose long/short format switch 108 * @return mnemonic for instruction 109 */ 110 @Override 111 public String toString( final boolean verbose ) { 112 final short _opcode = super.getOpcode(); 113 if (((_opcode >= Const.ILOAD_0) && (_opcode <= Const.ALOAD_3)) 114 || ((_opcode >= Const.ISTORE_0) && (_opcode <= Const.ASTORE_3))) { 115 return super.toString(verbose); 116 } 117 return super.toString(verbose) + " " + n; 118 } 119 120 121 /** 122 * Read needed data (e.g. index) from file. 123 * <pre> 124 * (ILOAD <= tag <= ALOAD_3) || (ISTORE <= tag <= ASTORE_3) 125 * </pre> 126 */ 127 @Override 128 protected void initFromFile( final ByteSequence bytes, final boolean wide ) throws IOException { 129 if (wide) { 130 n = bytes.readUnsignedShort(); 131 super.setLength(4); 132 } else { 133 final short _opcode = super.getOpcode(); 134 if (((_opcode >= Const.ILOAD) && (_opcode <= Const.ALOAD)) 135 || ((_opcode >= Const.ISTORE) && (_opcode <= Const.ASTORE))) { 136 n = bytes.readUnsignedByte(); 137 super.setLength(2); 138 } else if (_opcode <= Const.ALOAD_3) { // compact load instruction such as ILOAD_2 139 n = (_opcode - Const.ILOAD_0) % 4; 140 super.setLength(1); 141 } else { // Assert ISTORE_0 <= tag <= ASTORE_3 142 n = (_opcode - Const.ISTORE_0) % 4; 143 super.setLength(1); 144 } 145 } 146 } 147 148 149 /** 150 * @return local variable index (n) referred by this instruction. 151 */ 152 @Override 153 public final int getIndex() { 154 return n; 155 } 156 157 158 /** 159 * Set the local variable index. 160 * also updates opcode and length 161 * TODO Why? 162 * @see #setIndexOnly(int) 163 */ 164 @Override 165 public void setIndex( final int n ) { // TODO could be package-protected? 166 if ((n < 0) || (n > Const.MAX_SHORT)) { 167 throw new ClassGenException("Illegal value: " + n); 168 } 169 this.n = n; 170 // Cannot be < 0 as this is checked above 171 if (n <= 3) { // Use more compact instruction xLOAD_n 172 super.setOpcode((short) (c_tag + n)); 173 super.setLength(1); 174 } else { 175 super.setOpcode(canon_tag); 176 if (wide()) { 177 super.setLength(4); 178 } else { 179 super.setLength(2); 180 } 181 } 182 } 183 184 185 /** @return canonical tag for instruction, e.g., ALOAD for ALOAD_0 186 */ 187 public short getCanonicalTag() { 188 return canon_tag; 189 } 190 191 192 /** 193 * Returns the type associated with the instruction - 194 * in case of ALOAD or ASTORE Type.OBJECT is returned. 195 * This is just a bit incorrect, because ALOAD and ASTORE 196 * may work on every ReferenceType (including Type.NULL) and 197 * ASTORE may even work on a ReturnaddressType . 198 * @return type associated with the instruction 199 */ 200 @Override 201 public Type getType( final ConstantPoolGen cp ) { 202 switch (canon_tag) { 203 case Const.ILOAD: 204 case Const.ISTORE: 205 return Type.INT; 206 case Const.LLOAD: 207 case Const.LSTORE: 208 return Type.LONG; 209 case Const.DLOAD: 210 case Const.DSTORE: 211 return Type.DOUBLE; 212 case Const.FLOAD: 213 case Const.FSTORE: 214 return Type.FLOAT; 215 case Const.ALOAD: 216 case Const.ASTORE: 217 return Type.OBJECT; 218 default: 219 throw new ClassGenException("Oops: unknown case in switch" + canon_tag); 220 } 221 } 222 223 /** 224 * Sets the index of the referenced variable (n) only 225 * @since 6.0 226 * @see #setIndex(int) 227 */ 228 final void setIndexOnly(final int n) { 229 this.n = n; 230 } 231}