src/cpu/x86/vm/nativeInst_x86.hpp

Wed, 21 May 2008 10:45:07 -0700

author
kvn
date
Wed, 21 May 2008 10:45:07 -0700
changeset 598
885ed790ecf0
parent 551
018d5b58dd4f
child 631
d1605aabd0a1
permissions
-rw-r--r--

6695810: null oop passed to encode_heap_oop_not_null
Summary: fix several problems in C2 related to Escape Analysis and Compressed Oops.
Reviewed-by: never, jrose

     1 /*
     2  * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    20  * CA 95054 USA or visit www.sun.com if you need additional information or
    21  * have any questions.
    22  *
    23  */
    25 // We have interfaces for the following instructions:
    26 // - NativeInstruction
    27 // - - NativeCall
    28 // - - NativeMovConstReg
    29 // - - NativeMovConstRegPatching
    30 // - - NativeMovRegMem
    31 // - - NativeMovRegMemPatching
    32 // - - NativeJump
    33 // - - NativeIllegalOpCode
    34 // - - NativeGeneralJump
    35 // - - NativeReturn
    36 // - - NativeReturnX (return with argument)
    37 // - - NativePushConst
    38 // - - NativeTstRegMem
    40 // The base class for different kinds of native instruction abstractions.
    41 // Provides the primitive operations to manipulate code relative to this.
    43 class NativeInstruction VALUE_OBJ_CLASS_SPEC {
    44   friend class Relocation;
    46  public:
    47   enum Intel_specific_constants {
    48     nop_instruction_code        = 0x90,
    49     nop_instruction_size        =    1
    50   };
    52   bool is_nop()                        { return ubyte_at(0) == nop_instruction_code; }
    53   bool is_dtrace_trap();
    54   inline bool is_call();
    55   inline bool is_illegal();
    56   inline bool is_return();
    57   inline bool is_jump();
    58   inline bool is_cond_jump();
    59   inline bool is_safepoint_poll();
    60   inline bool is_mov_literal64();
    62  protected:
    63   address addr_at(int offset) const    { return address(this) + offset; }
    65   s_char sbyte_at(int offset) const    { return *(s_char*) addr_at(offset); }
    66   u_char ubyte_at(int offset) const    { return *(u_char*) addr_at(offset); }
    68   jint int_at(int offset) const         { return *(jint*) addr_at(offset); }
    70   intptr_t ptr_at(int offset) const    { return *(intptr_t*) addr_at(offset); }
    72   oop  oop_at (int offset) const       { return *(oop*) addr_at(offset); }
    75   void set_char_at(int offset, char c)        { *addr_at(offset) = (u_char)c; wrote(offset); }
    76   void set_int_at(int offset, jint  i)        { *(jint*)addr_at(offset) = i;  wrote(offset); }
    77   void set_ptr_at (int offset, intptr_t  ptr) { *(intptr_t*) addr_at(offset) = ptr;  wrote(offset); }
    78   void set_oop_at (int offset, oop  o)        { *(oop*) addr_at(offset) = o;  wrote(offset); }
    80   // This doesn't really do anything on Intel, but it is the place where
    81   // cache invalidation belongs, generically:
    82   void wrote(int offset);
    84  public:
    86   // unit test stuff
    87   static void test() {}                 // override for testing
    89   inline friend NativeInstruction* nativeInstruction_at(address address);
    90 };
    92 inline NativeInstruction* nativeInstruction_at(address address) {
    93   NativeInstruction* inst = (NativeInstruction*)address;
    94 #ifdef ASSERT
    95   //inst->verify();
    96 #endif
    97   return inst;
    98 }
   100 inline NativeCall* nativeCall_at(address address);
   101 // The NativeCall is an abstraction for accessing/manipulating native call imm32/rel32off
   102 // instructions (used to manipulate inline caches, primitive & dll calls, etc.).
   104 class NativeCall: public NativeInstruction {
   105  public:
   106   enum Intel_specific_constants {
   107     instruction_code            = 0xE8,
   108     instruction_size            =    5,
   109     instruction_offset          =    0,
   110     displacement_offset         =    1,
   111     return_address_offset       =    5
   112   };
   114   enum { cache_line_size = BytesPerWord };  // conservative estimate!
   116   address instruction_address() const       { return addr_at(instruction_offset); }
   117   address next_instruction_address() const  { return addr_at(return_address_offset); }
   118   int   displacement() const                { return (jint) int_at(displacement_offset); }
   119   address displacement_address() const      { return addr_at(displacement_offset); }
   120   address return_address() const            { return addr_at(return_address_offset); }
   121   address destination() const;
   122   void  set_destination(address dest)       {
   123 #ifdef AMD64
   124     assert((labs((intptr_t) dest - (intptr_t) return_address())  &
   125             0xFFFFFFFF00000000) == 0,
   126            "must be 32bit offset");
   127 #endif // AMD64
   128     set_int_at(displacement_offset, dest - return_address());
   129   }
   130   void  set_destination_mt_safe(address dest);
   132   void  verify_alignment() { assert((intptr_t)addr_at(displacement_offset) % BytesPerInt == 0, "must be aligned"); }
   133   void  verify();
   134   void  print();
   136   // Creation
   137   inline friend NativeCall* nativeCall_at(address address);
   138   inline friend NativeCall* nativeCall_before(address return_address);
   140   static bool is_call_at(address instr) {
   141     return ((*instr) & 0xFF) == NativeCall::instruction_code;
   142   }
   144   static bool is_call_before(address return_address) {
   145     return is_call_at(return_address - NativeCall::return_address_offset);
   146   }
   148   static bool is_call_to(address instr, address target) {
   149     return nativeInstruction_at(instr)->is_call() &&
   150       nativeCall_at(instr)->destination() == target;
   151   }
   153   // MT-safe patching of a call instruction.
   154   static void insert(address code_pos, address entry);
   156   static void replace_mt_safe(address instr_addr, address code_buffer);
   157 };
   159 inline NativeCall* nativeCall_at(address address) {
   160   NativeCall* call = (NativeCall*)(address - NativeCall::instruction_offset);
   161 #ifdef ASSERT
   162   call->verify();
   163 #endif
   164   return call;
   165 }
   167 inline NativeCall* nativeCall_before(address return_address) {
   168   NativeCall* call = (NativeCall*)(return_address - NativeCall::return_address_offset);
   169 #ifdef ASSERT
   170   call->verify();
   171 #endif
   172   return call;
   173 }
   175 // An interface for accessing/manipulating native mov reg, imm32 instructions.
   176 // (used to manipulate inlined 32bit data dll calls, etc.)
   177 class NativeMovConstReg: public NativeInstruction {
   178 #ifdef AMD64
   179   static const bool has_rex = true;
   180   static const int rex_size = 1;
   181 #else
   182   static const bool has_rex = false;
   183   static const int rex_size = 0;
   184 #endif // AMD64
   185  public:
   186   enum Intel_specific_constants {
   187     instruction_code            = 0xB8,
   188     instruction_size            =    1 + rex_size + wordSize,
   189     instruction_offset          =    0,
   190     data_offset                 =    1 + rex_size,
   191     next_instruction_offset     =    instruction_size,
   192     register_mask               = 0x07
   193   };
   195   address instruction_address() const       { return addr_at(instruction_offset); }
   196   address next_instruction_address() const  { return addr_at(next_instruction_offset); }
   197   intptr_t data() const                     { return ptr_at(data_offset); }
   198   void  set_data(intptr_t x)                { set_ptr_at(data_offset, x); }
   200   void  verify();
   201   void  print();
   203   // unit test stuff
   204   static void test() {}
   206   // Creation
   207   inline friend NativeMovConstReg* nativeMovConstReg_at(address address);
   208   inline friend NativeMovConstReg* nativeMovConstReg_before(address address);
   209 };
   211 inline NativeMovConstReg* nativeMovConstReg_at(address address) {
   212   NativeMovConstReg* test = (NativeMovConstReg*)(address - NativeMovConstReg::instruction_offset);
   213 #ifdef ASSERT
   214   test->verify();
   215 #endif
   216   return test;
   217 }
   219 inline NativeMovConstReg* nativeMovConstReg_before(address address) {
   220   NativeMovConstReg* test = (NativeMovConstReg*)(address - NativeMovConstReg::instruction_size - NativeMovConstReg::instruction_offset);
   221 #ifdef ASSERT
   222   test->verify();
   223 #endif
   224   return test;
   225 }
   227 class NativeMovConstRegPatching: public NativeMovConstReg {
   228  private:
   229     friend NativeMovConstRegPatching* nativeMovConstRegPatching_at(address address) {
   230     NativeMovConstRegPatching* test = (NativeMovConstRegPatching*)(address - instruction_offset);
   231     #ifdef ASSERT
   232       test->verify();
   233     #endif
   234     return test;
   235   }
   236 };
   238 #ifndef AMD64
   240 // An interface for accessing/manipulating native moves of the form:
   241 //      mov[b/w/l] [reg + offset], reg   (instruction_code_reg2mem)
   242 //      mov[b/w/l] reg, [reg+offset]     (instruction_code_mem2reg
   243 //      mov[s/z]x[w/b] [reg + offset], reg
   244 //      fld_s  [reg+offset]
   245 //      fld_d  [reg+offset]
   246 //      fstp_s [reg + offset]
   247 //      fstp_d [reg + offset]
   248 //
   249 // Warning: These routines must be able to handle any instruction sequences
   250 // that are generated as a result of the load/store byte,word,long
   251 // macros.  For example: The load_unsigned_byte instruction generates
   252 // an xor reg,reg inst prior to generating the movb instruction.  This
   253 // class must skip the xor instruction.
   255 class NativeMovRegMem: public NativeInstruction {
   256  public:
   257   enum Intel_specific_constants {
   258     instruction_code_xor                = 0x33,
   259     instruction_extended_prefix         = 0x0F,
   260     instruction_code_mem2reg_movzxb     = 0xB6,
   261     instruction_code_mem2reg_movsxb     = 0xBE,
   262     instruction_code_mem2reg_movzxw     = 0xB7,
   263     instruction_code_mem2reg_movsxw     = 0xBF,
   264     instruction_operandsize_prefix      = 0x66,
   265     instruction_code_reg2meml           = 0x89,
   266     instruction_code_mem2regl           = 0x8b,
   267     instruction_code_reg2memb           = 0x88,
   268     instruction_code_mem2regb           = 0x8a,
   269     instruction_code_float_s            = 0xd9,
   270     instruction_code_float_d            = 0xdd,
   271     instruction_code_long_volatile      = 0xdf,
   272     instruction_code_xmm_ss_prefix      = 0xf3,
   273     instruction_code_xmm_sd_prefix      = 0xf2,
   274     instruction_code_xmm_code           = 0x0f,
   275     instruction_code_xmm_load           = 0x10,
   276     instruction_code_xmm_store          = 0x11,
   277     instruction_code_xmm_lpd            = 0x12,
   279     instruction_size                    = 4,
   280     instruction_offset                  = 0,
   281     data_offset                         = 2,
   282     next_instruction_offset             = 4
   283   };
   285   address instruction_address() const {
   286     if (*addr_at(instruction_offset)   == instruction_operandsize_prefix &&
   287         *addr_at(instruction_offset+1) != instruction_code_xmm_code) {
   288       return addr_at(instruction_offset+1); // Not SSE instructions
   289     }
   290     else if (*addr_at(instruction_offset) == instruction_extended_prefix) {
   291       return addr_at(instruction_offset+1);
   292     }
   293     else if (*addr_at(instruction_offset) == instruction_code_xor) {
   294       return addr_at(instruction_offset+2);
   295     }
   296     else return addr_at(instruction_offset);
   297   }
   299   address next_instruction_address() const {
   300     switch (*addr_at(instruction_offset)) {
   301     case instruction_operandsize_prefix:
   302       if (*addr_at(instruction_offset+1) == instruction_code_xmm_code)
   303         return instruction_address() + instruction_size; // SSE instructions
   304     case instruction_extended_prefix:
   305       return instruction_address() + instruction_size + 1;
   306     case instruction_code_reg2meml:
   307     case instruction_code_mem2regl:
   308     case instruction_code_reg2memb:
   309     case instruction_code_mem2regb:
   310     case instruction_code_xor:
   311       return instruction_address() + instruction_size + 2;
   312     default:
   313       return instruction_address() + instruction_size;
   314     }
   315   }
   316   int   offset() const{
   317     if (*addr_at(instruction_offset)   == instruction_operandsize_prefix &&
   318         *addr_at(instruction_offset+1) != instruction_code_xmm_code) {
   319       return int_at(data_offset+1); // Not SSE instructions
   320     }
   321     else if (*addr_at(instruction_offset) == instruction_extended_prefix) {
   322       return int_at(data_offset+1);
   323     }
   324     else if (*addr_at(instruction_offset) == instruction_code_xor ||
   325              *addr_at(instruction_offset) == instruction_code_xmm_ss_prefix ||
   326              *addr_at(instruction_offset) == instruction_code_xmm_sd_prefix ||
   327              *addr_at(instruction_offset) == instruction_operandsize_prefix) {
   328       return int_at(data_offset+2);
   329     }
   330     else return int_at(data_offset);
   331   }
   333   void  set_offset(int x) {
   334     if (*addr_at(instruction_offset)   == instruction_operandsize_prefix &&
   335         *addr_at(instruction_offset+1) != instruction_code_xmm_code) {
   336       set_int_at(data_offset+1, x); // Not SSE instructions
   337     }
   338     else if (*addr_at(instruction_offset) == instruction_extended_prefix) {
   339       set_int_at(data_offset+1, x);
   340     }
   341     else if (*addr_at(instruction_offset) == instruction_code_xor ||
   342              *addr_at(instruction_offset) == instruction_code_xmm_ss_prefix ||
   343              *addr_at(instruction_offset) == instruction_code_xmm_sd_prefix ||
   344              *addr_at(instruction_offset) == instruction_operandsize_prefix) {
   345       set_int_at(data_offset+2, x);
   346     }
   347     else set_int_at(data_offset, x);
   348   }
   350   void  add_offset_in_bytes(int add_offset)     { set_offset ( ( offset() + add_offset ) ); }
   351   void  copy_instruction_to(address new_instruction_address);
   353   void verify();
   354   void print ();
   356   // unit test stuff
   357   static void test() {}
   359  private:
   360   inline friend NativeMovRegMem* nativeMovRegMem_at (address address);
   361 };
   363 inline NativeMovRegMem* nativeMovRegMem_at (address address) {
   364   NativeMovRegMem* test = (NativeMovRegMem*)(address - NativeMovRegMem::instruction_offset);
   365 #ifdef ASSERT
   366   test->verify();
   367 #endif
   368   return test;
   369 }
   371 class NativeMovRegMemPatching: public NativeMovRegMem {
   372  private:
   373   friend NativeMovRegMemPatching* nativeMovRegMemPatching_at (address address) {
   374     NativeMovRegMemPatching* test = (NativeMovRegMemPatching*)(address - instruction_offset);
   375     #ifdef ASSERT
   376       test->verify();
   377     #endif
   378     return test;
   379   }
   380 };
   384 // An interface for accessing/manipulating native leal instruction of form:
   385 //        leal reg, [reg + offset]
   387 class NativeLoadAddress: public NativeMovRegMem {
   388  public:
   389   enum Intel_specific_constants {
   390     instruction_code            = 0x8D
   391   };
   393   void verify();
   394   void print ();
   396   // unit test stuff
   397   static void test() {}
   399  private:
   400   friend NativeLoadAddress* nativeLoadAddress_at (address address) {
   401     NativeLoadAddress* test = (NativeLoadAddress*)(address - instruction_offset);
   402     #ifdef ASSERT
   403       test->verify();
   404     #endif
   405     return test;
   406   }
   407 };
   409 #endif // AMD64
   411 // jump rel32off
   413 class NativeJump: public NativeInstruction {
   414  public:
   415   enum Intel_specific_constants {
   416     instruction_code            = 0xe9,
   417     instruction_size            =    5,
   418     instruction_offset          =    0,
   419     data_offset                 =    1,
   420     next_instruction_offset     =    5
   421   };
   423   address instruction_address() const       { return addr_at(instruction_offset); }
   424   address next_instruction_address() const  { return addr_at(next_instruction_offset); }
   425   address jump_destination() const          {
   426      address dest = (int_at(data_offset)+next_instruction_address());
   427 #ifdef AMD64 // What is this about?
   428      // return -1 if jump to self
   429     dest = (dest == (address) this) ? (address) -1 : dest;
   430 #endif // AMD64
   431     return dest;
   432   }
   434   void  set_jump_destination(address dest)  {
   435     intptr_t val = dest - next_instruction_address();
   436 #ifdef AMD64
   437     if (dest == (address) -1) { // can't encode jump to -1
   438       val = -5; // jump to self
   439     } else {
   440       assert((labs(val)  & 0xFFFFFFFF00000000) == 0,
   441              "must be 32bit offset");
   442     }
   443 #endif // AMD64
   444     set_int_at(data_offset, (jint)val);
   445   }
   447   // Creation
   448   inline friend NativeJump* nativeJump_at(address address);
   450   void verify();
   452   // Unit testing stuff
   453   static void test() {}
   455   // Insertion of native jump instruction
   456   static void insert(address code_pos, address entry);
   457   // MT-safe insertion of native jump at verified method entry
   458   static void check_verified_entry_alignment(address entry, address verified_entry);
   459   static void patch_verified_entry(address entry, address verified_entry, address dest);
   460 };
   462 inline NativeJump* nativeJump_at(address address) {
   463   NativeJump* jump = (NativeJump*)(address - NativeJump::instruction_offset);
   464 #ifdef ASSERT
   465   jump->verify();
   466 #endif
   467   return jump;
   468 }
   470 // Handles all kinds of jump on Intel. Long/far, conditional/unconditional
   471 class NativeGeneralJump: public NativeInstruction {
   472  public:
   473   enum Intel_specific_constants {
   474     // Constants does not apply, since the lengths and offsets depends on the actual jump
   475     // used
   476     // Instruction codes:
   477     //   Unconditional jumps: 0xE9    (rel32off), 0xEB (rel8off)
   478     //   Conditional jumps:   0x0F8x  (rel32off), 0x7x (rel8off)
   479     unconditional_long_jump  = 0xe9,
   480     unconditional_short_jump = 0xeb,
   481     instruction_size = 5
   482   };
   484   address instruction_address() const       { return addr_at(0); }
   485   address jump_destination()    const;
   487   // Creation
   488   inline friend NativeGeneralJump* nativeGeneralJump_at(address address);
   490   // Insertion of native general jump instruction
   491   static void insert_unconditional(address code_pos, address entry);
   492   static void replace_mt_safe(address instr_addr, address code_buffer);
   494   void verify();
   495 };
   497 inline NativeGeneralJump* nativeGeneralJump_at(address address) {
   498   NativeGeneralJump* jump = (NativeGeneralJump*)(address);
   499   debug_only(jump->verify();)
   500   return jump;
   501 }
   503 class NativePopReg : public NativeInstruction {
   504  public:
   505   enum Intel_specific_constants {
   506     instruction_code            = 0x58,
   507     instruction_size            =    1,
   508     instruction_offset          =    0,
   509     data_offset                 =    1,
   510     next_instruction_offset     =    1
   511   };
   513   // Insert a pop instruction
   514   static void insert(address code_pos, Register reg);
   515 };
   518 class NativeIllegalInstruction: public NativeInstruction {
   519  public:
   520   enum Intel_specific_constants {
   521     instruction_code            = 0x0B0F,    // Real byte order is: 0x0F, 0x0B
   522     instruction_size            =    2,
   523     instruction_offset          =    0,
   524     next_instruction_offset     =    2
   525   };
   527   // Insert illegal opcode as specific address
   528   static void insert(address code_pos);
   529 };
   531 // return instruction that does not pop values of the stack
   532 class NativeReturn: public NativeInstruction {
   533  public:
   534   enum Intel_specific_constants {
   535     instruction_code            = 0xC3,
   536     instruction_size            =    1,
   537     instruction_offset          =    0,
   538     next_instruction_offset     =    1
   539   };
   540 };
   542 // return instruction that does pop values of the stack
   543 class NativeReturnX: public NativeInstruction {
   544  public:
   545   enum Intel_specific_constants {
   546     instruction_code            = 0xC2,
   547     instruction_size            =    2,
   548     instruction_offset          =    0,
   549     next_instruction_offset     =    2
   550   };
   551 };
   553 // Simple test vs memory
   554 class NativeTstRegMem: public NativeInstruction {
   555  public:
   556   enum Intel_specific_constants {
   557     instruction_code_memXregl   = 0x85
   558   };
   559 };
   561 inline bool NativeInstruction::is_illegal()      { return (short)int_at(0) == (short)NativeIllegalInstruction::instruction_code; }
   562 inline bool NativeInstruction::is_call()         { return ubyte_at(0) == NativeCall::instruction_code; }
   563 inline bool NativeInstruction::is_return()       { return ubyte_at(0) == NativeReturn::instruction_code ||
   564                                                           ubyte_at(0) == NativeReturnX::instruction_code; }
   565 inline bool NativeInstruction::is_jump()         { return ubyte_at(0) == NativeJump::instruction_code ||
   566                                                           ubyte_at(0) == 0xEB; /* short jump */ }
   567 inline bool NativeInstruction::is_cond_jump()    { return (int_at(0) & 0xF0FF) == 0x800F /* long jump */ ||
   568                                                           (ubyte_at(0) & 0xF0) == 0x70;  /* short jump */ }
   569 inline bool NativeInstruction::is_safepoint_poll() {
   570 #ifdef AMD64
   571   return ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl &&
   572          ubyte_at(1) == 0x05 && // 00 rax 101
   573          ((intptr_t) addr_at(6)) + int_at(2) == (intptr_t) os::get_polling_page();
   574 #else
   575   return ( ubyte_at(0) == NativeMovRegMem::instruction_code_mem2regl ||
   576            ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl ) &&
   577            (ubyte_at(1)&0xC7) == 0x05 && /* Mod R/M == disp32 */
   578            (os::is_poll_address((address)int_at(2)));
   579 #endif // AMD64
   580 }
   582 inline bool NativeInstruction::is_mov_literal64() {
   583 #ifdef AMD64
   584   return ((ubyte_at(0) == Assembler::REX_W || ubyte_at(0) == Assembler::REX_WB) &&
   585           (ubyte_at(1) & (0xff ^ NativeMovConstReg::register_mask)) == 0xB8);
   586 #else
   587   return false;
   588 #endif // AMD64
   589 }

mercurial