Mercurial > hg > graal-jvmci-8
diff agent/src/share/classes/sun/jvm/hotspot/asm/x86/InstructionDecoder.java @ 0:a61af66fc99e jdk7-b24
Initial load
author | duke |
---|---|
date | Sat, 01 Dec 2007 00:00:00 +0000 |
parents | |
children | c18cbe5936b8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/asm/x86/InstructionDecoder.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,554 @@ +/* + * Copyright 2002-2003 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package sun.jvm.hotspot.asm.x86; + +import sun.jvm.hotspot.asm.*; + +// basic instruction decoder class +public class InstructionDecoder implements /* imports */ X86Opcodes , RTLDataTypes, RTLOperations { + + protected String name; + protected int addrMode1; + protected int operandType1; + protected int addrMode2; + protected int operandType2; + protected int addrMode3; + protected int operandType3; + + private int mod; + private int regOrOpcode; + private int rm; + protected int prefixes; + + protected int byteIndex; + protected int instrStartIndex; + + public InstructionDecoder(String name) { + this.name = name; + this.operandType1 = INVALID_OPERANDTYPE; + this.operandType2 = INVALID_OPERANDTYPE; + this.operandType3 = INVALID_OPERANDTYPE; + this.addrMode1 = INVALID_ADDRMODE; + this.addrMode2 = INVALID_ADDRMODE; + this.addrMode3 = INVALID_ADDRMODE; + } + public InstructionDecoder(String name, int addrMode1, int operandType1) { + this(name); + this.addrMode1 = addrMode1; + this.operandType1 = operandType1; + } + public InstructionDecoder(String name, int addrMode1, int operandType1, int addrMode2, int operandType2) { + this(name, addrMode1, operandType1); + this.addrMode2 = addrMode2; + this.operandType2 = operandType2; + } + public InstructionDecoder(String name, int addrMode1, int operandType1, int addrMode2, int operandType2, + int addrMode3, int operandType3) { + this(name, addrMode1, operandType1, addrMode2, operandType2); + this.addrMode3 = addrMode3; + this.operandType3 = operandType3; + } + // "operand1" + protected Operand getOperand1(byte[] bytesArray, boolean operandSize, boolean addrSize) { + if( (addrMode1 != INVALID_ADDRMODE) && (operandType1 != INVALID_OPERANDTYPE) ) + return getOperand(bytesArray, addrMode1, operandType1, operandSize, addrSize); + else + return null; + } + + // "operand2" + protected Operand getOperand2(byte[] bytesArray, boolean operandSize, boolean addrSize) { + if( (addrMode2 != INVALID_ADDRMODE) && (operandType2 != INVALID_OPERANDTYPE) ) + return getOperand(bytesArray, addrMode2, operandType2, operandSize, addrSize); + else + return null; + } + + // "operand3" + protected Operand getOperand3(byte[] bytesArray, boolean operandSize, boolean addrSize) { + if( (addrMode3 != INVALID_ADDRMODE) && (operandType3 != INVALID_OPERANDTYPE) ) + return getOperand(bytesArray, addrMode3, operandType3, operandSize, addrSize); + else + return null; + } + + static int readInt32(byte[] bytesArray, int index) { + int ret = 0; + ret = readByte(bytesArray, index); + ret |= readByte(bytesArray, index+1) << 8; + ret |= readByte(bytesArray, index+2) << 16; + ret |= readByte(bytesArray, index+3) << 24; + return ret; + } + static int readInt16(byte[] bytesArray, int index) { + int ret = 0; + ret = readByte(bytesArray, index); + ret |= readByte(bytesArray, index+1) << 8; + return ret; + } + static int readByte(byte[] bytesArray, int index) { + int ret = 0; + if (index < bytesArray.length) { + ret = (int)bytesArray[index]; + ret = ret & 0xff; + } + return ret; + } + private boolean isModRMPresent(int addrMode) { + if( (addrMode == ADDR_E) || (addrMode == ADDR_G) || (addrMode == ADDR_FPREG) || (addrMode == ADDR_Q) || (addrMode == ADDR_W) ) + return true; + else + return false; + } + public int getCurrentIndex() { + return byteIndex; + } + + public Instruction decode(byte[] bytesArray, int index, int instrStartIndex, int segmentOverride, int prefixes, X86InstructionFactory factory) { + this.byteIndex = index; + this.instrStartIndex = instrStartIndex; + this.prefixes = prefixes; + boolean operandSize; //operand-size prefix + boolean addrSize; //address-size prefix + if ( ( (prefixes & PREFIX_DATA) ^ segmentOverride ) == 1) + operandSize = true; + else + operandSize = false; + if ( ((prefixes & PREFIX_ADR) ^ segmentOverride) == 1) + addrSize = true; + else + addrSize = false; + this.name = getCorrectOpcodeName(name, prefixes, operandSize, addrSize); + + //Fetch the mod/reg/rm byte only if it is present. + if( isModRMPresent(addrMode1) || isModRMPresent(addrMode2) || isModRMPresent(addrMode3) ) { + + int ModRM = readByte(bytesArray, byteIndex); + byteIndex++; + mod = (ModRM >> 6) & 3; + regOrOpcode = (ModRM >> 3) & 7; + rm = ModRM & 7; + } + return decodeInstruction(bytesArray, operandSize, addrSize, factory); + } + + protected Instruction decodeInstruction(byte[] bytesArray, boolean operandSize, boolean addrSize, X86InstructionFactory factory) { + Operand op1 = getOperand1(bytesArray, operandSize, addrSize); + Operand op2 = getOperand2(bytesArray, operandSize, addrSize); + Operand op3 = getOperand3(bytesArray, operandSize, addrSize); + int size = byteIndex - instrStartIndex; + return factory.newGeneralInstruction(name, op1, op2, op3, size, prefixes); + } + + // capital letters in template are macros + private String getCorrectOpcodeName(String oldName, int prefixes, boolean operandSize, boolean addrSize) { + StringBuffer newName = new StringBuffer(oldName); + int index = 0; + for(index=0; index<oldName.length(); index++) { + switch (oldName.charAt(index)) { + case 'C': /* For jcxz/jecxz */ + if (addrSize) + newName.setCharAt(index, 'e'); + index++; + break; + case 'N': + if ((prefixes & PREFIX_FWAIT) == 0) + newName.setCharAt(index, 'n'); + index++; + break; + case 'S': + /* operand size flag */ + if (operandSize == true) + newName.setCharAt(index, 'l'); + else + newName.setCharAt(index, 'w'); + index++; + break; + default: + break; + } + } + return newName.toString(); + } + + //IA-32 Intel Architecture Software Developer's Manual Volume 2 + //Refer to Chapter 2 - Instruction Format + + //Get the Operand object from the address type and the operand type + private Operand getOperand(byte[] bytesArray, int addrMode, int operandType, boolean operandSize, boolean addrSize) { + Operand op = null; + switch(addrMode) { + case ADDR_E: + case ADDR_W: //SSE: ModR/M byte specifies either 128 bit XMM register or memory + case ADDR_Q: //SSE: ModR/M byte specifies either 128 bit MMX register or memory + X86SegmentRegister segReg = getSegmentRegisterFromPrefix(prefixes); + + if (mod == 3) { //Register operand, no SIB follows + if (addrMode == ADDR_E) { + switch (operandType) { + case b_mode: + op = X86Registers.getRegister8(rm); + break; + case w_mode: + op = X86Registers.getRegister16(rm); + break; + case v_mode: + if (operandSize == true) //Operand size prefix is present + op = X86Registers.getRegister32(rm); + else + op = X86Registers.getRegister16(rm); + break; + case p_mode: + X86Register reg; + if (operandSize == true) //Operand size prefix is present + reg = X86Registers.getRegister32(rm); + else + reg = X86Registers.getRegister16(rm); + + op = new X86RegisterIndirectAddress(segReg, reg, null, 0); + break; + default: + break; + } + } else if (addrMode == ADDR_W) { + op = X86XMMRegisters.getRegister(rm); + } else if (addrMode == ADDR_Q) { + op = X86MMXRegisters.getRegister(rm); + } + + } else { //mod != 3 + //SIB follows for (rm==4), SIB gives scale, index and base in this case + //disp32 is present for (mod==0 && rm==5) || (mod==2) + //disp8 is present for (mod==1) + //for (rm!=4) base is register at rm. + int scale = 0; + int index = 0; + int base = 0; + long disp = 0; + if(rm == 4) { + int sib = readByte(bytesArray, byteIndex); + byteIndex++; + scale = (sib >> 6) & 3; + index = (sib >> 3) & 7; + base = sib & 7; + } + + switch (mod) { + case 0: + switch(rm) { + case 4: + if(base == 5) { + disp = readInt32(bytesArray, byteIndex); + byteIndex += 4; + if (index != 4) { + op = new X86RegisterIndirectAddress(segReg, null, X86Registers.getRegister32(index), disp, scale); + } else { + op = new X86RegisterIndirectAddress(segReg, null, null, disp, scale); + } + } + else { + if (index != 4) { + op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), X86Registers.getRegister32(index), 0, scale); + } else { + op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), null, 0, scale); + } + } + break; + case 5: + disp = readInt32(bytesArray, byteIndex); + byteIndex += 4; + //Create an Address object only with displacement + op = new X86RegisterIndirectAddress(segReg, null, null, disp); + break; + default: + base = rm; + //Create an Address object only with base + op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), null, 0); + break; + } + break; + case 1: + disp = (byte)readByte(bytesArray, byteIndex); + byteIndex++; + if (rm !=4) { + base = rm; + //Address with base and disp only + op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), null, disp); + } else { + if (index != 4) { + op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), X86Registers.getRegister32(index), disp, scale); + } else { + op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), null, disp, scale); + } + } + break; + case 2: + disp = readInt32(bytesArray, byteIndex); + byteIndex += 4; + if (rm !=4) { + base = rm; + //Address with base and disp + op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), null, disp); + } else if (index != 4) { + op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), X86Registers.getRegister32(index), disp, scale); + } else { + op = new X86RegisterIndirectAddress(segReg, X86Registers.getRegister32(base), null, disp, scale); + } + break; + } + } + break; + + case ADDR_I: + switch (operandType) { + case b_mode: + op = new Immediate(new Integer(readByte(bytesArray, byteIndex))); + byteIndex++; + break; + case w_mode: + op = new Immediate(new Integer(readInt16(bytesArray, byteIndex))); + byteIndex += 2; + break; + case v_mode: + if (operandSize == true) { //Operand size prefix is present + op = new Immediate(new Integer(readInt32(bytesArray, byteIndex))); + byteIndex += 4; + } else { + op = new Immediate(new Integer(readInt16(bytesArray, byteIndex))); + byteIndex += 2; + } + break; + default: + break; + } + break; + case ADDR_REG: //registers + switch(operandType) { + case EAX: + case ECX: + case EDX: + case EBX: + case ESP: + case EBP: + case ESI: + case EDI: + if(operandSize == true) { + op = X86Registers.getRegister32(operandType - EAX); + } + else { + op = X86Registers.getRegister16(operandType - EAX); + } + break; + case AX: + case CX: + case DX: + case BX: + case SP: + case BP: + case SI: + case DI: + op = X86Registers.getRegister16(operandType - AX); + break; + case AL: + case CL: + case DL: + case BL: + case AH: + case CH: + case DH: + case BH: + op = X86Registers.getRegister8(operandType - AL); + break; + case ES: //ES, CS, SS, DS, FS, GS + case CS: + case SS: + case DS: + case FS: + case GS: + op = X86SegmentRegisters.getSegmentRegister(operandType - ES); + break; + } + break; + case ADDR_DIR: //segment and offset + long segment = 0; + long offset = 0; + switch (operandType) { + case p_mode: + if (addrSize == true) { + offset = readInt32(bytesArray, byteIndex); + byteIndex += 4; + segment = readInt16(bytesArray, byteIndex); + byteIndex += 2; + } else { + offset = readInt16(bytesArray, byteIndex); + byteIndex += 2; + segment = readInt16(bytesArray, byteIndex); + byteIndex += 2; + } + op = new X86DirectAddress(segment, offset); //with offset + break; + case v_mode: + if (addrSize == true) { + offset = readInt32(bytesArray, byteIndex); + byteIndex += 4; + } else { + offset = readInt16(bytesArray, byteIndex); + byteIndex += 2; + } + op = new X86DirectAddress(offset); //with offset + break; + default: + break; + } + break; + case ADDR_G: + switch (operandType) { + case b_mode: + op = X86Registers.getRegister8(regOrOpcode); + break; + case w_mode: + op = X86Registers.getRegister16(regOrOpcode); + break; + case d_mode: + op = X86Registers.getRegister32(regOrOpcode); + break; + case v_mode: + if (operandSize == true) + op = X86Registers.getRegister32(regOrOpcode); + else + op = X86Registers.getRegister16(regOrOpcode); + break; + default: + break; + } + break; + case ADDR_SEG: + op = X86SegmentRegisters.getSegmentRegister(regOrOpcode); + break; + case ADDR_OFF: + int off = 0; + if (addrSize == true) { + off = readInt32(bytesArray, byteIndex); + byteIndex += 4; + } + else { + off = readInt16(bytesArray, byteIndex); + byteIndex += 2; + } + op = new X86DirectAddress((long)off); + break; + case ADDR_J: + long disp = 0; + //The effective address is Instruction pointer + relative offset + switch(operandType) { + case b_mode: + disp = (byte)readByte(bytesArray, byteIndex); + byteIndex++; + break; + case v_mode: + if (operandSize == true) { + disp = readInt32(bytesArray, byteIndex); + byteIndex += 4; + } + else { + disp = readInt16(bytesArray, byteIndex); + byteIndex += 2; + } + //disp = disp + (byteIndex-instrStartIndex); + break; + } + op = new X86PCRelativeAddress(disp); + break; + case ADDR_ESDI: + op = new X86SegmentRegisterAddress(X86SegmentRegisters.ES, X86Registers.DI); + break; + case ADDR_DSSI: + op = new X86SegmentRegisterAddress(X86SegmentRegisters.DS, X86Registers.SI); + break; + case ADDR_R: + switch (operandType) { + case b_mode: + op = X86Registers.getRegister8(mod); + break; + case w_mode: + op = X86Registers.getRegister16(mod); + break; + case d_mode: + op = X86Registers.getRegister32(mod); + break; + case v_mode: + if (operandSize == true) + op = X86Registers.getRegister32(mod); + else + op = X86Registers.getRegister16(mod); + break; + default: + break; + } + break; + case ADDR_FPREG: + switch (operandType) { + case 0: + op = X86FloatRegisters.getRegister(0); + break; + case 1: + op = X86FloatRegisters.getRegister(rm); + break; + } + break; + + //SSE: reg field of ModR/M byte selects a 128-bit XMM register + case ADDR_V: + op = X86XMMRegisters.getRegister(regOrOpcode); + break; + + //SSE: reg field of ModR/M byte selects a 64-bit MMX register + case ADDR_P: + op = X86MMXRegisters.getRegister(regOrOpcode); + break; + } + return op; + } + + private X86SegmentRegister getSegmentRegisterFromPrefix(int prefixes) { + X86SegmentRegister segRegister = null; + + if ( (prefixes & PREFIX_CS) != 0) + segRegister = X86SegmentRegisters.CS; + if ( (prefixes & PREFIX_DS) != 0) + segRegister = X86SegmentRegisters.DS; + if ( (prefixes & PREFIX_ES) != 0) + segRegister = X86SegmentRegisters.ES; + if ( (prefixes & PREFIX_FS) != 0) + segRegister = X86SegmentRegisters.FS; + if ( (prefixes & PREFIX_SS) != 0) + segRegister = X86SegmentRegisters.SS; + if ( (prefixes & PREFIX_GS) != 0) + segRegister = X86SegmentRegisters.GS; + + return segRegister; + } + +}