Path: blob/master/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Instruction.java
41161 views
/*1* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.tools.classfile;2627import java.util.Locale;2829/**30* See JVMS, chapter 6.31*32* <p><b>This is NOT part of any supported API.33* If you write code that depends on this, you do so at your own risk.34* This code and its internal interfaces are subject to change or35* deletion without notice.</b>36*37* @see Code_attribute#getInstructions38*/39public class Instruction {40/** The kind of an instruction, as determined by the position, size and41* types of its operands. */42public static enum Kind {43/** Opcode is not followed by any operands. */44NO_OPERANDS(1),45/** Opcode is followed by a byte indicating a type. */46ATYPE(2),47/** Opcode is followed by a 2-byte branch offset. */48BRANCH(3),49/** Opcode is followed by a 4-byte branch offset. */50BRANCH_W(5),51/** Opcode is followed by a signed byte value. */52BYTE(2),53/** Opcode is followed by a 1-byte index into the constant pool. */54CPREF(2),55/** Opcode is followed by a 2-byte index into the constant pool. */56CPREF_W(3),57/** Opcode is followed by a 2-byte index into the constant pool,58* an unsigned byte value. */59CPREF_W_UBYTE(4),60/** Opcode is followed by a 2-byte index into the constant pool.,61* an unsigned byte value, and a zero byte. */62CPREF_W_UBYTE_ZERO(5),63/** Opcode is followed by variable number of operands, depending64* on the instruction.*/65DYNAMIC(-1),66/** Opcode is followed by a 1-byte reference to a local variable. */67LOCAL(2),68/** Opcode is followed by a 1-byte reference to a local variable,69* and a signed byte value. */70LOCAL_BYTE(3),71/** Opcode is followed by a signed short value. */72SHORT(3),73/** Wide opcode is not followed by any operands. */74WIDE_NO_OPERANDS(2),75/** Wide opcode is followed by a 2-byte index into the local variables array. */76WIDE_LOCAL(4),77/** Wide opcode is followed by a 2-byte index into the constant pool. */78WIDE_CPREF_W(4),79/** Wide opcode is followed by a 2-byte index into the constant pool,80* and a signed short value. */81WIDE_CPREF_W_SHORT(6),82/** Wide opcode is followed by a 2-byte reference to a local variable,83* and a signed short value. */84WIDE_LOCAL_SHORT(6),85/** Opcode was not recognized. */86UNKNOWN(1);8788Kind(int length) {89this.length = length;90}9192/** The length, in bytes, of this kind of instruction, or -1 is the93* length depends on the specific instruction. */94public final int length;95}9697/** A utility visitor to help decode the operands of an instruction.98* @see Instruction#accept */99public interface KindVisitor<R,P> {100/** See {@link Kind#NO_OPERANDS}, {@link Kind#WIDE_NO_OPERANDS}. */101R visitNoOperands(Instruction instr, P p);102/** See {@link Kind#ATYPE}. */103R visitArrayType(Instruction instr, TypeKind kind, P p);104/** See {@link Kind#BRANCH}, {@link Kind#BRANCH_W}. */105R visitBranch(Instruction instr, int offset, P p);106/** See {@link Kind#CPREF}, {@link Kind#CPREF_W}, {@link Kind#WIDE_CPREF_W}. */107R visitConstantPoolRef(Instruction instr, int index, P p);108/** See {@link Kind#CPREF_W_UBYTE}, {@link Kind#CPREF_W_UBYTE_ZERO}, {@link Kind#WIDE_CPREF_W_SHORT}. */109R visitConstantPoolRefAndValue(Instruction instr, int index, int value, P p);110/** See {@link Kind#LOCAL}, {@link Kind#WIDE_LOCAL}. */111R visitLocal(Instruction instr, int index, P p);112/** See {@link Kind#LOCAL_BYTE}. */113R visitLocalAndValue(Instruction instr, int index, int value, P p);114/** See {@link Kind#DYNAMIC}. */115R visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, P p);116/** See {@link Kind#DYNAMIC}. */117R visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, P p);118/** See {@link Kind#BYTE}, {@link Kind#SHORT}. */119R visitValue(Instruction instr, int value, P p);120/** Instruction is unrecognized. */121R visitUnknown(Instruction instr, P p);122123}124125/** The kind of primitive array type to create.126* See JVMS chapter 6, newarray. */127public static enum TypeKind {128T_BOOLEAN(4, "boolean"),129T_CHAR(5, "char"),130T_FLOAT(6, "float"),131T_DOUBLE(7, "double"),132T_BYTE(8, "byte"),133T_SHORT(9, "short"),134T_INT (10, "int"),135T_LONG (11, "long");136TypeKind(int value, String name) {137this.value = value;138this.name = name;139}140141public static TypeKind get(int value) {142switch (value) {143case 4: return T_BOOLEAN;144case 5: return T_CHAR;145case 6: return T_FLOAT;146case 7: return T_DOUBLE;147case 8: return T_BYTE;148case 9: return T_SHORT;149case 10: return T_INT;150case 11: return T_LONG;151default: return null;152}153}154155public final int value;156public final String name;157}158159/** An instruction is defined by its position in a bytecode array. */160public Instruction(byte[] bytes, int pc) {161this.bytes = bytes;162this.pc = pc;163}164165/** Get the position of the instruction within the bytecode array. */166public int getPC() {167return pc;168}169170/** Get a byte value, relative to the start of this instruction. */171public int getByte(int offset) {172return bytes[pc + offset];173}174175/** Get an unsigned byte value, relative to the start of this instruction. */176public int getUnsignedByte(int offset) {177return getByte(offset) & 0xff;178}179180/** Get a 2-byte value, relative to the start of this instruction. */181public int getShort(int offset) {182return (getByte(offset) << 8) | getUnsignedByte(offset + 1);183}184185/** Get a unsigned 2-byte value, relative to the start of this instruction. */186public int getUnsignedShort(int offset) {187return getShort(offset) & 0xFFFF;188}189190/** Get a 4-byte value, relative to the start of this instruction. */191public int getInt(int offset) {192return (getShort(offset) << 16) | (getUnsignedShort(offset + 2));193}194195/** Get the Opcode for this instruction, or null if the instruction is196* unrecognized. */197public Opcode getOpcode() {198int b = getUnsignedByte(0);199switch (b) {200case Opcode.NONPRIV:201case Opcode.PRIV:202case Opcode.WIDE:203return Opcode.get(b, getUnsignedByte(1));204}205return Opcode.get(b);206}207208/** Get the mnemonic for this instruction, or a default string if the209* instruction is unrecognized. */210public String getMnemonic() {211Opcode opcode = getOpcode();212if (opcode == null)213return "bytecode " + getUnsignedByte(0);214else215return opcode.toString().toLowerCase(Locale.US);216}217218/** Get the length, in bytes, of this instruction, including the opcode219* and all its operands. */220public int length() {221Opcode opcode = getOpcode();222if (opcode == null)223return 1;224225switch (opcode) {226case TABLESWITCH: {227int pad = align(pc + 1) - pc;228int low = getInt(pad + 4);229int high = getInt(pad + 8);230return pad + 12 + 4 * (high - low + 1);231}232case LOOKUPSWITCH: {233int pad = align(pc + 1) - pc;234int npairs = getInt(pad + 4);235return pad + 8 + 8 * npairs;236237}238default:239return opcode.kind.length;240}241}242243/** Get the {@link Kind} of this instruction. */244public Kind getKind() {245Opcode opcode = getOpcode();246return (opcode != null ? opcode.kind : Kind.UNKNOWN);247}248249/** Invoke a method on the visitor according to the kind of this250* instruction, passing in the decoded operands for the instruction. */251public <R,P> R accept(KindVisitor<R,P> visitor, P p) {252switch (getKind()) {253case NO_OPERANDS:254return visitor.visitNoOperands(this, p);255256case ATYPE:257return visitor.visitArrayType(258this, TypeKind.get(getUnsignedByte(1)), p);259260case BRANCH:261return visitor.visitBranch(this, getShort(1), p);262263case BRANCH_W:264return visitor.visitBranch(this, getInt(1), p);265266case BYTE:267return visitor.visitValue(this, getByte(1), p);268269case CPREF:270return visitor.visitConstantPoolRef(this, getUnsignedByte(1), p);271272case CPREF_W:273return visitor.visitConstantPoolRef(this, getUnsignedShort(1), p);274275case CPREF_W_UBYTE:276case CPREF_W_UBYTE_ZERO:277return visitor.visitConstantPoolRefAndValue(278this, getUnsignedShort(1), getUnsignedByte(3), p);279280case DYNAMIC: {281switch (getOpcode()) {282case TABLESWITCH: {283int pad = align(pc + 1) - pc;284int default_ = getInt(pad);285int low = getInt(pad + 4);286int high = getInt(pad + 8);287if (low > high)288throw new IllegalStateException();289int[] values = new int[high - low + 1];290for (int i = 0; i < values.length; i++)291values[i] = getInt(pad + 12 + 4 * i);292return visitor.visitTableSwitch(293this, default_, low, high, values, p);294}295case LOOKUPSWITCH: {296int pad = align(pc + 1) - pc;297int default_ = getInt(pad);298int npairs = getInt(pad + 4);299if (npairs < 0)300throw new IllegalStateException();301int[] matches = new int[npairs];302int[] offsets = new int[npairs];303for (int i = 0; i < npairs; i++) {304matches[i] = getInt(pad + 8 + i * 8);305offsets[i] = getInt(pad + 12 + i * 8);306}307return visitor.visitLookupSwitch(308this, default_, npairs, matches, offsets, p);309}310default:311throw new IllegalStateException();312}313}314315case LOCAL:316return visitor.visitLocal(this, getUnsignedByte(1), p);317318case LOCAL_BYTE:319return visitor.visitLocalAndValue(320this, getUnsignedByte(1), getByte(2), p);321322case SHORT:323return visitor.visitValue(this, getShort(1), p);324325case WIDE_NO_OPERANDS:326return visitor.visitNoOperands(this, p);327328case WIDE_LOCAL:329return visitor.visitLocal(this, getUnsignedShort(2), p);330331case WIDE_CPREF_W:332return visitor.visitConstantPoolRef(this, getUnsignedShort(2), p);333334case WIDE_CPREF_W_SHORT:335return visitor.visitConstantPoolRefAndValue(336this, getUnsignedShort(2), getUnsignedByte(4), p);337338case WIDE_LOCAL_SHORT:339return visitor.visitLocalAndValue(340this, getUnsignedShort(2), getShort(4), p);341342case UNKNOWN:343return visitor.visitUnknown(this, p);344345default:346throw new IllegalStateException();347}348}349350private static int align(int n) {351return (n + 3) & ~3;352}353354private byte[] bytes;355private int pc;356}357358359