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;
+   }
+
+}