/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.classloader; import org.jikesrvm.VM; import org.jikesrvm.SizeConstants; import org.jikesrvm.runtime.Statics; import org.vmmagic.pragma.Inline; import org.vmmagic.unboxed.Offset; /** * Provides minimal abstraction layer to a stream of bytecodes * from the code attribute of a method. */ public class BytecodeStream implements BytecodeConstants, ClassLoaderConstants, SizeConstants { private final NormalMethod method; private final int bcLength; private final byte[] bcodes; private int bcIndex; private int opcode; private boolean wide; /** * @param m the method containing the bytecodes * @param bc the array of bytecodes */ public BytecodeStream(NormalMethod m, byte[] bc) { method = m; bcodes = bc; bcLength = bc.length; bcIndex = 0; } /** * Returns the method that this bytecode stream is from * @return method */ public final NormalMethod getMethod() { return method; } /** * Returns the declaring class that this bytecode stream is from * @return method */ public final RVMClass getDeclaringClass() { return method.getDeclaringClass(); } /** * Returns the length of the bytecode stream * Returns 0 if the method doesn't have any bytecodes * (i.e. is abstract or native) * @return bytecode stream length */ public final int length() { return bcLength; } /** * Returns the current bytecode index * @return the current bytecode index */ public final int index() { return bcIndex; } /** * Resets the stream to the beginning * @see #reset(int) */ public final void reset() { reset(0); } /** * Resets the stream to a given position * Use with caution * @param index the position to reset the stream to * @see #reset() */ public final void reset(int index) { bcIndex = index; } /** * Does the stream have more bytecodes in it? * @return whether there are more bytecodes */ public final boolean hasMoreBytecodes() { return bcIndex < bcLength; } /** * Returns the opcode of the next instruction in the sequence * without advancing to it * @return the opcode of the next instruction * @see #nextInstruction() */ public final int peekNextOpcode() { if (VM.VerifyAssertions) VM._assert(bcIndex < bcLength); return getUnsignedByte(bcIndex); } /** * Sets up the next instruction in the sequence * @return the opcode of the next instruction * @see #peekNextOpcode() */ public final int nextInstruction() { if (VM.VerifyAssertions) VM._assert(bcIndex < bcLength); opcode = readUnsignedByte(); wide = (opcode == JBC_wide); return opcode; } /** * Returns the opcode of the current instruction in the sequence * Note: if skipInstruction has been called, but nextInstruction has not, * this method will return the opcode of the skipped instruction! * @return the opcode of the current instruction * @see #nextInstruction() * @see #isWide() */ public final int getOpcode() { return opcode; } /** * Are we currently processing a wide instruction? * @return true if current instruction is wide * @see #nextInstruction() * @see #getOpcode() */ public final boolean isWide() { return wide; } /** * Skips the current instruction * @see #skipInstruction(int,boolean) */ public final void skipInstruction() { if (VM.VerifyAssertions) VM._assert(bcIndex <= bcLength); int len = JBC_length[opcode] - 1; if (wide) len += len; if (len >= 0) { bcIndex += len; } else { skipSpecialInstruction(opcode); } } /** * Skips the current instruction (without using the opcode field) * A slightly optimized version of skipInstruction() * @param opcode current opcode * @param wide whether current instruction follows wide * @see #skipInstruction() */ public final void skipInstruction(int opcode, boolean wide) { if (VM.VerifyAssertions) VM._assert(bcIndex < bcLength); int len = JBC_length[opcode] - 1; if (wide) len += len; if (len >= 0) { bcIndex += len; } else { skipSpecialInstruction(opcode); } } /** * Returns a signed byte value * Used for bipush * @return signed byte value */ public final int getByteValue() { if (VM.VerifyAssertions) VM._assert(opcode == JBC_bipush); return readSignedByte(); } /** * Returns a signed short value * Used for sipush * @return signed short value */ public final int getShortValue() { if (VM.VerifyAssertions) VM._assert(opcode == JBC_sipush); return readSignedShort(); } /** * Returns the number of the local (as an unsigned byte) * Used for iload, lload, fload, dload, aload, * istore, lstore, fstore, dstore, astore, * iinc, ret * @return local number * @see #getWideLocalNumber() */ public final int getLocalNumber() { if (VM.VerifyAssertions) { VM._assert((opcode >= JBC_iload && opcode <= JBC_aload) || (opcode >= JBC_istore && opcode <= JBC_astore) || opcode == JBC_iinc || opcode == JBC_ret); } return readUnsignedByte(); } /** * Returns the wide number of the local (as an unsigned short) * Used for iload, lload, fload, dload, aload, * istore, lstore, fstore, dstore, astore, * iinc prefixed by wide * @return wide local number * @see #getLocalNumber() */ public final int getWideLocalNumber() { if (VM.VerifyAssertions) { VM._assert(wide && ((opcode >= JBC_iload && opcode <= JBC_aload) || (opcode >= JBC_istore && opcode <= JBC_astore) || opcode == JBC_iinc)); } return readUnsignedShort(); } /** * Returns an increment value (as a signed byte) * Used for iinc * @return increment * @see #getWideIncrement() */ public final int getIncrement() { if (VM.VerifyAssertions) VM._assert(opcode == JBC_iinc); return readSignedByte(); } /** * Returns an increment value (as a signed short) * Used for iinc prefixed by wide * @return wide increment * @see #getIncrement() */ public final int getWideIncrement() { if (VM.VerifyAssertions) VM._assert(wide && opcode == JBC_iinc); return readSignedShort(); } /** * Returns the offset of the branch (as a signed short) * Used for if<cond>, ificmp<cond>, ifacmp<cond>, goto, jsr * @return branch offset * @see #getWideBranchOffset() */ public final int getBranchOffset() { if (VM.VerifyAssertions) { VM._assert((opcode >= JBC_ifeq && opcode <= JBC_ifle) || (opcode >= JBC_if_icmpeq && opcode <= JBC_if_icmple) || opcode == JBC_if_acmpeq || opcode == JBC_if_acmpne || opcode == JBC_ifnull || opcode == JBC_ifnonnull || opcode == JBC_goto || opcode == JBC_jsr); } return readSignedShort(); } /** * Returns the wide offset of the branch (as a signed int) * Used for goto_w, jsr_w * @return wide branch offset * @see #getBranchOffset() */ public final int getWideBranchOffset() { if (VM.VerifyAssertions) { VM._assert(opcode == JBC_goto_w || opcode == JBC_jsr_w); } return readSignedInt(); } /** * Skips the padding of a switch instruction * Used for tableswitch, lookupswitch */ public final void alignSwitch() { if (VM.VerifyAssertions) { VM._assert(opcode == JBC_tableswitch || opcode == JBC_lookupswitch); } int align = bcIndex & 3; if (align != 0) bcIndex += 4 - align; // eat padding } /** * Returns the default offset of the switch (as a signed int) * Used for tableswitch, lookupswitch * @return default switch offset */ public final int getDefaultSwitchOffset() { if (VM.VerifyAssertions) { VM._assert(opcode == JBC_tableswitch || opcode == JBC_lookupswitch); } return readSignedInt(); } /** * Returns the lowest value of the tableswitch (as a signed int) * Used for tableswitch * @return lowest switch value * @see #getHighSwitchValue() */ public final int getLowSwitchValue() { if (VM.VerifyAssertions) VM._assert(opcode == JBC_tableswitch); return readSignedInt(); } /** * Returns the highest value of the tableswitch (as a signed int) * Used for tableswitch * @return highest switch value * @see #getLowSwitchValue() */ public final int getHighSwitchValue() { if (VM.VerifyAssertions) VM._assert(opcode == JBC_tableswitch); return readSignedInt(); } /** * Skips the offsets of a tableswitch instruction * Used for tableswitch * @param num the number of offsets to skip * @see #getTableSwitchOffset(int) */ public final void skipTableSwitchOffsets(int num) { if (VM.VerifyAssertions) VM._assert(opcode == JBC_tableswitch); bcIndex += (num << LOG_BYTES_IN_INT); } /** * Returns the numbered offset of the tableswitch (as a signed int) * Used for tableswitch * The "cursor" has to be positioned at the start of the offset table * NOTE: Will NOT advance cursor * @param num the number of the offset to retrieve * @return switch offset */ public final int getTableSwitchOffset(int num) { if (VM.VerifyAssertions) VM._assert(opcode == JBC_tableswitch); return getSignedInt(bcIndex + (num << LOG_BYTES_IN_INT)); } /** * Returns the offset for a given value of the tableswitch (as a signed int) * or 0 if the value is out of range. * Used for tableswitch * The "cursor" has to be positioned at the start of the offset table * NOTE: Will NOT advance cursor * @param value the value to retrieve offset for * @param low the lowest value of the tableswitch * @param high the highest value of the tableswitch * @return switch offset */ public final int computeTableSwitchOffset(int value, int low, int high) { if (VM.VerifyAssertions) VM._assert(opcode == JBC_tableswitch); if (value < low || value > high) return 0; return getSignedInt(bcIndex + ((value - low) << LOG_BYTES_IN_INT)); } /** * Returns the number of match-offset pairs in the lookupswitch * (as a signed int) * Used for lookupswitch * @return number of switch pairs */ public final int getSwitchLength() { if (VM.VerifyAssertions) VM._assert(opcode == JBC_lookupswitch); return readSignedInt(); } /** * Skips the match-offset pairs of a lookupswitch instruction * Used for lookupswitch * @param num the number of match-offset pairs to skip * @see #getLookupSwitchValue(int) * @see #getLookupSwitchOffset(int) */ public final void skipLookupSwitchPairs(int num) { if (VM.VerifyAssertions) VM._assert(opcode == JBC_lookupswitch); bcIndex += (num << (LOG_BYTES_IN_INT + 1)); } /** * Returns the numbered offset of the lookupswitch (as a signed int) * Used for lookupswitch * The "cursor" has to be positioned at the start of the pair table * NOTE: Will NOT advance cursor * @param num the number of the offset to retrieve * @return switch offset * @see #getLookupSwitchValue(int) */ public final int getLookupSwitchOffset(int num) { if (VM.VerifyAssertions) VM._assert(opcode == JBC_lookupswitch); return getSignedInt(bcIndex + (num << (LOG_BYTES_IN_INT + 1)) + BYTES_IN_INT); } /** * Returns the numbered value of the lookupswitch (as a signed int) * Used for lookupswitch * The "cursor" has to be positioned at the start of the pair table * NOTE: Will NOT advance cursor * @param num the number of the value to retrieve * @return switch value * @see #getLookupSwitchOffset(int) */ public final int getLookupSwitchValue(int num) { if (VM.VerifyAssertions) VM._assert(opcode == JBC_lookupswitch); return getSignedInt(bcIndex + (num << (LOG_BYTES_IN_INT + 1))); } /** * Returns the offset for a given value of the lookupswitch * (as a signed int) or 0 if the value is not in the table. * Used for lookupswitch * The "cursor" has to be positioned at the start of the offset table * NOTE: Will NOT advance cursor * WARNING: Uses LINEAR search. Whoever has time on their hands can * re-implement this as a binary search. * @param value the value to retrieve offset for * @param num the number of match-offset pairs in the lookupswitch * @return switch offset */ public final int computeLookupSwitchOffset(int value, int num) { if (VM.VerifyAssertions) VM._assert(opcode == JBC_lookupswitch); for (int i = 0; i < num; i++) { if (getSignedInt(bcIndex + (i << (LOG_BYTES_IN_INT + 1))) == value) { return getSignedInt(bcIndex + (i << (LOG_BYTES_IN_INT + 1)) + BYTES_IN_INT); } } return 0; } /** * Returns a reference to a field * Used for getstatic, putstatic, getfield, putfield * @return field reference */ public final FieldReference getFieldReference() { if (VM.VerifyAssertions) { VM._assert(opcode == JBC_getstatic || opcode == JBC_putstatic || opcode == JBC_getfield || opcode == JBC_putfield); } return getDeclaringClass().getFieldRef(readUnsignedShort()); } /** * Returns a reference to a field, for use prior to the class being loaded. * Used for getstatic, putstatic, getfield, putfield * @return field reference */ public final FieldReference getFieldReference(int[] constantPool) { if (VM.VerifyAssertions) { VM._assert(opcode == JBC_getstatic || opcode == JBC_putstatic || opcode == JBC_getfield || opcode == JBC_putfield); } return ClassFileReader.getFieldRef(constantPool, readUnsignedShort()); } /** * Returns a reference to a field * Used for invokevirtual, invokespecial, invokestatic, invokeinterface * @return method reference */ public final MethodReference getMethodReference() { if (VM.VerifyAssertions) { VM._assert(opcode == JBC_invokevirtual || opcode == JBC_invokespecial || opcode == JBC_invokestatic || opcode == JBC_invokeinterface); } return getDeclaringClass().getMethodRef(readUnsignedShort()); } /** * Returns a reference to a field, for use prior to the class being loaded * Used for invokevirtual, invokespecial, invokestatic, invokeinterface * @return method reference */ public final MethodReference getMethodReference(int[] constantPool) { if (VM.VerifyAssertions) { VM._assert(opcode == JBC_invokevirtual || opcode == JBC_invokespecial || opcode == JBC_invokestatic || opcode == JBC_invokeinterface); } return ClassFileReader.getMethodRef(constantPool, readUnsignedShort()); } /** * Skips the extra stuff after an invokeinterface instruction * Used for invokeinterface */ public final void alignInvokeInterface() { if (VM.VerifyAssertions) VM._assert(opcode == JBC_invokeinterface); bcIndex += 2; // eat superfluous stuff } /** * Returns the type reference (as a RVMType) * Used for new, anewarray, checkcast, instanceof, multianewarray * @return type reference */ public final TypeReference getTypeReference() { if (VM.VerifyAssertions) { VM._assert(opcode == JBC_new || opcode == JBC_anewarray || opcode == JBC_checkcast || opcode == JBC_instanceof || opcode == JBC_multianewarray); } int index = readUnsignedShort(); return getDeclaringClass().getTypeRef(index); } /** * Returns the element type (primitive) of the array (as an unsigned byte) * Used for newarray * @return array element type * @see #getPrimitiveArrayType() * @see #getPrimitiveArrayType(int) */ public final int getArrayElementType() { if (VM.VerifyAssertions) VM._assert(opcode == JBC_newarray); return readUnsignedByte(); } /** * Returns the type of the array of given primitive type (as a RVMType) * Used for newarray * @param etype element type * @return array type * @see #getArrayElementType() * @see #getPrimitiveArrayType() */ public final RVMArray getPrimitiveArrayType(int etype) { if (VM.VerifyAssertions) VM._assert(opcode == JBC_newarray); return RVMArray.getPrimitiveArrayType(etype); } /** * Returns the type of the primitive array (as a RVMType) * Used for newarray * @return array type * @see #getArrayElementType() * @see #getPrimitiveArrayType(int) */ public final RVMType getPrimitiveArrayType() { if (VM.VerifyAssertions) VM._assert(opcode == JBC_newarray); int etype = readUnsignedByte(); return RVMArray.getPrimitiveArrayType(etype); } /** * Returns the type of the array of given object type (as a RVMType) * Used for anewarray * @param klass element type * @return array type * @see #getTypeReference() * @see #getObjectArrayType() */ public final RVMType getObjectArrayType(RVMType klass) { if (VM.VerifyAssertions) VM._assert(opcode == JBC_anewarray); return klass.getArrayTypeForElementType(); } /** * Returns the type of the object array (as a RVMType) * Used for anewarray * @return array type * @see #getObjectArrayType(RVMType) */ public final TypeReference getObjectArrayType() { if (VM.VerifyAssertions) VM._assert(opcode == JBC_anewarray); TypeReference klass = getTypeReference(); return klass.getArrayTypeForElementType(); } /** * Returns the dimension of the array (as an unsigned byte) * Used for multianewarray * @return array dimension */ public final int getArrayDimension() { if (VM.VerifyAssertions) VM._assert(opcode == JBC_multianewarray); return readUnsignedByte(); } /** * Returns the opcode of the wide instruction * Used for wide * Can be one of iload, lload, fload, dload, aload, * istore, lstore, fstore, dstore, astore, iinc * @return the opcode of the wide instruction */ public final int getWideOpcode() { if (VM.VerifyAssertions) VM._assert(wide && opcode == JBC_wide); opcode = readUnsignedByte(); if (VM.VerifyAssertions) { VM._assert((opcode >= JBC_iload && opcode <= JBC_aload) || (opcode >= JBC_istore && opcode <= JBC_astore) || opcode == JBC_iinc); } return opcode; } /** * Returns the constant pool index of a constant (as an unsigned byte) * Used for ldc * @return constant index * @see #getWideConstantIndex() * @see #getConstantType(int) * @see #getIntConstant(int) * @see #getLongConstant(int) * @see #getFloatConstant(int) * @see #getDoubleConstant(int) * @see #getStringConstant(int) */ public final int getConstantIndex() { if (VM.VerifyAssertions) VM._assert(opcode == JBC_ldc); return readUnsignedByte(); } /** * Returns the wide constant pool index of a constant (as an unsigned short) * Used for ldc_w, ldc2_w * @return wide constant index * @see #getConstantIndex() * @see #getConstantType(int) * @see #getIntConstant(int) * @see #getLongConstant(int) * @see #getFloatConstant(int) * @see #getDoubleConstant(int) * @see #getStringConstant(int) */ public final int getWideConstantIndex() { if (VM.VerifyAssertions) { VM._assert(opcode == JBC_ldc_w || opcode == JBC_ldc2_w); } return readUnsignedShort(); } /** * Returns the type of a constant at a given constant pool index (as a byte) * Used for ldc, ldc_w, ldc2_w * @return constant type * @see #getConstantIndex() * @see #getWideConstantIndex() * @see #getIntConstant(int) * @see #getLongConstant(int) * @see #getFloatConstant(int) * @see #getDoubleConstant(int) * @see #getStringConstant(int) */ public final byte getConstantType(int index) { if (VM.VerifyAssertions) { VM._assert(opcode == JBC_ldc || opcode == JBC_ldc_w || opcode == JBC_ldc2_w); } byte desc = getDeclaringClass().getLiteralDescription(index); return desc; } /** * Returns the constant at a given constant pool index (as an int) * Used for ldc, ldc_w * @return int constant * @see #getConstantIndex() * @see #getWideConstantIndex() * @see #getConstantType(int) * @see #getLongConstant(int) * @see #getFloatConstant(int) * @see #getDoubleConstant(int) * @see #getStringConstant(int) */ public final int getIntConstant(int index) { if (VM.VerifyAssertions) { VM._assert((opcode == JBC_ldc || opcode == JBC_ldc_w) && getDeclaringClass().getLiteralDescription(index) == CP_INT); } Offset offset = getDeclaringClass().getLiteralOffset(index); int val = Statics.getSlotContentsAsInt(offset); return val; } /** * Returns the constant at a given constant pool index (as a long) * Used for ldc2_w * @return long constant * @see #getConstantIndex() * @see #getWideConstantIndex() * @see #getConstantType(int) * @see #getIntConstant(int) * @see #getFloatConstant(int) * @see #getDoubleConstant(int) * @see #getStringConstant(int) */ public final long getLongConstant(int index) { if (VM.VerifyAssertions) { VM._assert(opcode == JBC_ldc2_w && getDeclaringClass().getLiteralDescription(index) == CP_LONG); } Offset offset = getDeclaringClass().getLiteralOffset(index); long val = Statics.getSlotContentsAsLong(offset); return val; } /** * Returns the constant at a given constant pool index (as a float) * Used for ldc, ldc_w * @return float constant * @see #getConstantIndex() * @see #getWideConstantIndex() * @see #getConstantType(int) * @see #getIntConstant(int) * @see #getLongConstant(int) * @see #getDoubleConstant(int) * @see #getStringConstant(int) */ public final float getFloatConstant(int index) { if (VM.VerifyAssertions) { VM._assert((opcode == JBC_ldc || opcode == JBC_ldc_w) && getDeclaringClass().getLiteralDescription(index) == CP_FLOAT); } Offset offset = getDeclaringClass().getLiteralOffset(index); int val_raw = Statics.getSlotContentsAsInt(offset); float val = Float.intBitsToFloat(val_raw); return val; } /** * Returns the constant at a given constant pool index (as a double) * Used for ldc2_w * @return double constant * @see #getConstantIndex() * @see #getWideConstantIndex() * @see #getConstantType(int) * @see #getIntConstant(int) * @see #getLongConstant(int) * @see #getFloatConstant(int) * @see #getStringConstant(int) */ public final double getDoubleConstant(int index) { if (VM.VerifyAssertions) { VM._assert(opcode == JBC_ldc2_w && getDeclaringClass().getLiteralDescription(index) == CP_DOUBLE); } Offset offset = getDeclaringClass().getLiteralOffset(index); long val_raw = Statics.getSlotContentsAsLong(offset); double val = Double.longBitsToDouble(val_raw); return val; } /** * Returns the constant at a given constant pool index (as a String) * Used for ldc, ldc_w * @return String constant * @see #getConstantIndex() * @see #getWideConstantIndex() * @see #getConstantType(int) * @see #getIntConstant(int) * @see #getLongConstant(int) * @see #getFloatConstant(int) * @see #getDoubleConstant(int) */ public final String getStringConstant(int index) { if (VM.VerifyAssertions) { VM._assert((opcode == JBC_ldc || opcode == JBC_ldc_w) && getDeclaringClass().getLiteralDescription(index) == CP_STRING); } Offset offset = getDeclaringClass().getLiteralOffset(index); String val = (String) Statics.getSlotContentsAsObject(offset); return val; } //// HELPER FUNCTIONS // Skip a tableswitch or a lookupswitch instruction private void skipSpecialInstruction(int opcode) { switch (opcode) { case JBC_tableswitch: { alignSwitch(); getDefaultSwitchOffset(); int l = getLowSwitchValue(); int h = getHighSwitchValue(); skipTableSwitchOffsets(h - l + 1); // jump offsets } break; case JBC_lookupswitch: { alignSwitch(); getDefaultSwitchOffset(); int n = getSwitchLength(); skipLookupSwitchPairs(n); // match-offset pairs } break; case JBC_wide: { int oc = getWideOpcode(); int len = JBC_length[oc] - 1; bcIndex += len + len; } break; default: if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); } } public final int nextPseudoInstruction() { if (VM.VerifyAssertions) VM._assert(opcode == JBC_impdep1); return readUnsignedByte(); } public final int readIntConst() { if (VM.VerifyAssertions) VM._assert(opcode == JBC_impdep1); return readSignedInt(); } public final long readLongConst() { if (VM.VerifyAssertions) VM._assert(opcode == JBC_impdep1); return readLong(); } @Inline private long readLong() { if (VM.VerifyAssertions) VM._assert(bcIndex <= bcLength); int msb = bcodes[bcIndex++] << (3 * BITS_IN_BYTE); msb |= (bcodes[bcIndex++] & 0xFF) << (2 * BITS_IN_BYTE); msb |= (bcodes[bcIndex++] & 0xFF) << BITS_IN_BYTE; msb |= (bcodes[bcIndex++] & 0xFF); int lsb = bcodes[bcIndex++] << (3 * BITS_IN_BYTE); lsb |= (bcodes[bcIndex++] & 0xFF) << (2 * BITS_IN_BYTE); lsb |= (bcodes[bcIndex++] & 0xFF) << BITS_IN_BYTE; lsb |= (bcodes[bcIndex++] & 0xFF); return (((long)msb) << 32) | (lsb & 0xFFFFFFFFL); } //// READ BYTECODES @Inline private byte readSignedByte() { if (VM.VerifyAssertions) VM._assert(bcIndex <= bcLength); return bcodes[bcIndex++]; } @Inline private int readUnsignedByte() { if (VM.VerifyAssertions) VM._assert(bcIndex <= bcLength); return bcodes[bcIndex++] & 0xFF; } @Inline private int getUnsignedByte(int index) { if (VM.VerifyAssertions) VM._assert(index <= bcLength); return bcodes[index] & 0xFF; } @Inline private int readSignedShort() { if (VM.VerifyAssertions) VM._assert(bcIndex <= bcLength); int i = bcodes[bcIndex++] << BITS_IN_BYTE; i |= (bcodes[bcIndex++] & 0xFF); return i; } @Inline private int readUnsignedShort() { if (VM.VerifyAssertions) VM._assert(bcIndex <= bcLength); int i = (bcodes[bcIndex++] & 0xFF) << BITS_IN_BYTE; i |= (bcodes[bcIndex++] & 0xFF); return i; } @Inline private int readSignedInt() { if (VM.VerifyAssertions) VM._assert(bcIndex <= bcLength); int i = bcodes[bcIndex++] << (3 * BITS_IN_BYTE); i |= (bcodes[bcIndex++] & 0xFF) << (2 * BITS_IN_BYTE); i |= (bcodes[bcIndex++] & 0xFF) << BITS_IN_BYTE; i |= (bcodes[bcIndex++] & 0xFF); return i; } @Inline private int getSignedInt(int index) { if (VM.VerifyAssertions) VM._assert(index <= bcLength); int i = bcodes[index++] << (3 * BITS_IN_BYTE); i |= (bcodes[index++] & 0xFF) << (2 * BITS_IN_BYTE); i |= (bcodes[index++] & 0xFF) << BITS_IN_BYTE; i |= (bcodes[index] & 0xFF); return i; } }