001/* 002 * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.bytecode; 024 025/** 026 * A utility class that makes iterating over bytecodes and reading operands simpler and less error 027 * prone. For example, it handles the {@link Bytecodes#WIDE} instruction and wide variants of 028 * instructions internally. 029 */ 030public final class BytecodeStream { 031 032 private final byte[] code; 033 private int opcode; 034 private int curBCI; 035 private int nextBCI; 036 037 /** 038 * Creates a new {@code BytecodeStream} for the specified bytecode. 039 * 040 * @param code the array of bytes that contains the bytecode 041 */ 042 public BytecodeStream(byte[] code) { 043 assert code != null; 044 this.code = code; 045 setBCI(0); 046 } 047 048 /** 049 * Advances to the next bytecode. 050 */ 051 public void next() { 052 setBCI(nextBCI); 053 } 054 055 /** 056 * Gets the next bytecode index (no side-effects). 057 * 058 * @return the next bytecode index 059 */ 060 public int nextBCI() { 061 return nextBCI; 062 } 063 064 /** 065 * Gets the current bytecode index. 066 * 067 * @return the current bytecode index 068 */ 069 public int currentBCI() { 070 return curBCI; 071 } 072 073 /** 074 * Gets the bytecode index of the end of the code. 075 * 076 * @return the index of the end of the code 077 */ 078 public int endBCI() { 079 return code.length; 080 } 081 082 /** 083 * Gets the current opcode. This method will never return the {@link Bytecodes#WIDE WIDE} 084 * opcode, but will instead return the opcode that is modified by the {@code WIDE} opcode. 085 * 086 * @return the current opcode; {@link Bytecodes#END} if at or beyond the end of the code 087 */ 088 public int currentBC() { 089 if (opcode == Bytecodes.WIDE) { 090 return Bytes.beU1(code, curBCI + 1); 091 } else { 092 return opcode; 093 } 094 } 095 096 /** 097 * Reads the index of a local variable for one of the load or store instructions. The WIDE 098 * modifier is handled internally. 099 * 100 * @return the index of the local variable 101 */ 102 public int readLocalIndex() { 103 // read local variable index for load/store 104 if (opcode == Bytecodes.WIDE) { 105 return Bytes.beU2(code, curBCI + 2); 106 } 107 return Bytes.beU1(code, curBCI + 1); 108 } 109 110 /** 111 * Read the delta for an {@link Bytecodes#IINC} bytecode. 112 * 113 * @return the delta for the {@code IINC} 114 */ 115 public int readIncrement() { 116 // read the delta for the iinc bytecode 117 if (opcode == Bytecodes.WIDE) { 118 return Bytes.beS2(code, curBCI + 4); 119 } 120 return Bytes.beS1(code, curBCI + 2); 121 } 122 123 /** 124 * Read the destination of a {@link Bytecodes#GOTO} or {@code IF} instructions. 125 * 126 * @return the destination bytecode index 127 */ 128 public int readBranchDest() { 129 // reads the destination for a branch bytecode 130 if (opcode == Bytecodes.GOTO_W || opcode == Bytecodes.JSR_W) { 131 return curBCI + Bytes.beS4(code, curBCI + 1); 132 } else { 133 return curBCI + Bytes.beS2(code, curBCI + 1); 134 } 135 } 136 137 /** 138 * Read a signed 4-byte integer from the bytecode stream at the specified bytecode index. 139 * 140 * @param bci the bytecode index 141 * @return the integer value 142 */ 143 public int readInt(int bci) { 144 // reads a 4-byte signed value 145 return Bytes.beS4(code, bci); 146 } 147 148 /** 149 * Reads an unsigned, 1-byte value from the bytecode stream at the specified bytecode index. 150 * 151 * @param bci the bytecode index 152 * @return the byte 153 */ 154 public int readUByte(int bci) { 155 return Bytes.beU1(code, bci); 156 } 157 158 /** 159 * Reads a constant pool index for the current instruction. 160 * 161 * @return the constant pool index 162 */ 163 public char readCPI() { 164 if (opcode == Bytecodes.LDC) { 165 return (char) Bytes.beU1(code, curBCI + 1); 166 } 167 return (char) Bytes.beU2(code, curBCI + 1); 168 } 169 170 /** 171 * Reads a constant pool index for an invokedynamic instruction. 172 * 173 * @return the constant pool index 174 */ 175 public int readCPI4() { 176 assert opcode == Bytecodes.INVOKEDYNAMIC; 177 return Bytes.beS4(code, curBCI + 1); 178 } 179 180 /** 181 * Reads a signed, 1-byte value for the current instruction (e.g. BIPUSH). 182 * 183 * @return the byte 184 */ 185 public byte readByte() { 186 return code[curBCI + 1]; 187 } 188 189 /** 190 * Reads a signed, 2-byte short for the current instruction (e.g. SIPUSH). 191 * 192 * @return the short value 193 */ 194 public short readShort() { 195 return (short) Bytes.beS2(code, curBCI + 1); 196 } 197 198 /** 199 * Sets the bytecode index to the specified value. If {@code bci} is beyond the end of the 200 * array, {@link #currentBC} will return {@link Bytecodes#END} and other methods may throw 201 * {@link ArrayIndexOutOfBoundsException}. 202 * 203 * @param bci the new bytecode index 204 */ 205 public void setBCI(int bci) { 206 curBCI = bci; 207 if (curBCI < code.length) { 208 opcode = Bytes.beU1(code, bci); 209 assert opcode < Bytecodes.BREAKPOINT : "illegal bytecode"; 210 nextBCI = bci + lengthOf(); 211 } else { 212 opcode = Bytecodes.END; 213 nextBCI = curBCI; 214 } 215 } 216 217 /** 218 * Gets the length of the current bytecode. 219 */ 220 private int lengthOf() { 221 int length = Bytecodes.lengthOf(opcode); 222 if (length == 0) { 223 switch (opcode) { 224 case Bytecodes.TABLESWITCH: { 225 return new BytecodeTableSwitch(this, curBCI).size(); 226 } 227 case Bytecodes.LOOKUPSWITCH: { 228 return new BytecodeLookupSwitch(this, curBCI).size(); 229 } 230 case Bytecodes.WIDE: { 231 int opc = Bytes.beU1(code, curBCI + 1); 232 if (opc == Bytecodes.RET) { 233 return 4; 234 } else if (opc == Bytecodes.IINC) { 235 return 6; 236 } else { 237 return 4; // a load or store bytecode 238 } 239 } 240 default: 241 throw new Error("unknown variable-length bytecode: " + opcode); 242 } 243 } 244 return length; 245 } 246}