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