hotspot/src/share/vm/oops/cpCacheOop.hpp
changeset 13391 30245956af37
parent 10008 d84de97ad847
--- a/hotspot/src/share/vm/oops/cpCacheOop.hpp	Mon Jul 23 13:04:59 2012 -0700
+++ b/hotspot/src/share/vm/oops/cpCacheOop.hpp	Tue Jul 24 10:51:00 2012 -0700
@@ -38,13 +38,14 @@
 // bit number |31                0|
 // bit length |-8--|-8--|---16----|
 // --------------------------------
-// _indices   [ b2 | b1 |  index  ]
-// _f1        [  entry specific   ]
-// _f2        [  entry specific   ]
-// _flags     [t|f|vf|v|m|h|unused|field_index] (for field entries)
-// bit length |4|1|1 |1|1|0|---7--|----16-----]
-// _flags     [t|f|vf|v|m|h|unused|eidx|psze] (for method entries)
-// bit length |4|1|1 |1|1|1|---7--|-8--|-8--]
+// _indices   [ b2 | b1 |  index  ]  index = constant_pool_index (!= 0, normal entries only)
+// _indices   [  index  |  00000  ]  index = main_entry_index (secondary entries only)
+// _f1        [  entry specific   ]  method, klass, or oop (MethodType or CallSite)
+// _f2        [  entry specific   ]  vtable index or vfinal method
+// _flags     [tos|0|00|00|00|f|v|f2|unused|field_index] (for field entries)
+// bit length [ 4 |1|1 |1 | 1|1|1| 1|---5--|----16-----]
+// _flags     [tos|M|vf|fv|ea|f|0|f2|unused|00000|psize] (for method entries)
+// bit length [ 4 |1|1 |1 | 1|1|1| 1|---5--|--8--|--8--]
 
 // --------------------------------
 //
@@ -52,24 +53,23 @@
 // index  = original constant pool index
 // b1     = bytecode 1
 // b2     = bytecode 2
-// psze   = parameters size (method entries only)
-// eidx   = interpreter entry index (method entries only)
+// psize  = parameters size (method entries only)
 // field_index = index into field information in holder instanceKlass
 //          The index max is 0xffff (max number of fields in constant pool)
 //          and is multiplied by (instanceKlass::next_offset) when accessing.
 // t      = TosState (see below)
 // f      = field is marked final (see below)
-// vf     = virtual, final (method entries only : is_vfinal())
+// f2     = virtual but final (method entries only: is_vfinal())
 // v      = field is volatile (see below)
 // m      = invokeinterface used for method in class Object (see below)
 // h      = RedefineClasses/Hotswap bit (see below)
 //
 // The flags after TosState have the following interpretation:
-// bit 27: f flag  true if field is marked final
-// bit 26: vf flag true if virtual final method
-// bit 25: v flag true if field is volatile (only for fields)
-// bit 24: m flag true if invokeinterface used for method in class Object
-// bit 23: 0 for fields, 1 for methods
+// bit 27: 0 for fields, 1 for methods
+// f  flag true if field is marked final
+// v  flag true if field is volatile (only for fields)
+// f2 flag true if f2 contains an oop (e.g., virtual final method)
+// fv flag true if invokeinterface used for method in class Object
 //
 // The flags 31, 30, 29, 28 together build a 4 bit number 0 to 8 with the
 // following mapping to the TosState states:
@@ -86,25 +86,26 @@
 //
 // Entry specific: field entries:
 // _indices = get (b1 section) and put (b2 section) bytecodes, original constant pool index
-// _f1      = field holder
-// _f2      = field offset in words
-// _flags   = field type information, original field index in field holder
+// _f1      = field holder (as a java.lang.Class, not a klassOop)
+// _f2      = field offset in bytes
+// _flags   = field type information, original FieldInfo index in field holder
 //            (field_index section)
 //
 // Entry specific: method entries:
 // _indices = invoke code for f1 (b1 section), invoke code for f2 (b2 section),
 //            original constant pool index
-// _f1      = method for all but virtual calls, unused by virtual calls
-//            (note: for interface calls, which are essentially virtual,
-//             contains klassOop for the corresponding interface.
-//            for invokedynamic, f1 contains the CallSite object for the invocation
-// _f2      = method/vtable index for virtual calls only, unused by all other
-//            calls.  The vf flag indicates this is a method pointer not an
-//            index.
-// _flags   = field type info (f section),
-//            virtual final entry (vf),
-//            interpreter entry index (eidx section),
-//            parameter size (psze section)
+// _f1      = methodOop for non-virtual calls, unused by virtual calls.
+//            for interface calls, which are essentially virtual but need a klass,
+//            contains klassOop for the corresponding interface.
+//            for invokedynamic, f1 contains a site-specific CallSite object (as an appendix)
+//            for invokehandle, f1 contains a site-specific MethodType object (as an appendix)
+//            (upcoming metadata changes will move the appendix to a separate array)
+// _f2      = vtable/itable index (or final methodOop) for virtual calls only,
+//            unused by non-virtual.  The is_vfinal flag indicates this is a
+//            method pointer for a final method, not an index.
+// _flags   = method type info (t section),
+//            virtual final bit (vfinal),
+//            parameter size (psize section)
 //
 // Note: invokevirtual & invokespecial bytecodes can share the same constant
 //       pool entry and thus the same constant pool cache entry. All invoke
@@ -138,30 +139,61 @@
     assert(existing_f1 == NULL || existing_f1 == f1, "illegal field change");
     oop_store(&_f1, f1);
   }
-  void set_f1_if_null_atomic(oop f1);
-  void set_f2(intx f2)                           { assert(_f2 == 0    || _f2 == f2, "illegal field change"); _f2 = f2; }
-  int as_flags(TosState state, bool is_final, bool is_vfinal, bool is_volatile,
-               bool is_method_interface, bool is_method);
+  void release_set_f1(oop f1);
+  void set_f2(intx f2)                           { assert(_f2 == 0 || _f2 == f2,            "illegal field change"); _f2 = f2; }
+  void set_f2_as_vfinal_method(methodOop f2)     { assert(_f2 == 0 || _f2 == (intptr_t) f2, "illegal field change"); assert(is_vfinal(), "flags must be set"); _f2 = (intptr_t) f2; }
+  int make_flags(TosState state, int option_bits, int field_index_or_method_params);
   void set_flags(intx flags)                     { _flags = flags; }
+  bool init_flags_atomic(intx flags);
+  void set_field_flags(TosState field_type, int option_bits, int field_index) {
+    assert((field_index & field_index_mask) == field_index, "field_index in range");
+    set_flags(make_flags(field_type, option_bits | (1 << is_field_entry_shift), field_index));
+  }
+  void set_method_flags(TosState return_type, int option_bits, int method_params) {
+    assert((method_params & parameter_size_mask) == method_params, "method_params in range");
+    set_flags(make_flags(return_type, option_bits, method_params));
+  }
+  bool init_method_flags_atomic(TosState return_type, int option_bits, int method_params) {
+    assert((method_params & parameter_size_mask) == method_params, "method_params in range");
+    return init_flags_atomic(make_flags(return_type, option_bits, method_params));
+  }
 
  public:
-  // specific bit values in flag field
-  // Note: the interpreter knows this layout!
-  enum FlagBitValues {
-    hotSwapBit    = 23,
-    methodInterface = 24,
-    volatileField = 25,
-    vfinalMethod  = 26,
-    finalField    = 27
+  // specific bit definitions for the flags field:
+  // (Note: the interpreter must use these definitions to access the CP cache.)
+  enum {
+    // high order bits are the TosState corresponding to field type or method return type
+    tos_state_bits             = 4,
+    tos_state_mask             = right_n_bits(tos_state_bits),
+    tos_state_shift            = BitsPerInt - tos_state_bits,  // see verify_tos_state_shift below
+    // misc. option bits; can be any bit position in [16..27]
+    is_vfinal_shift            = 21,
+    is_volatile_shift          = 22,
+    is_final_shift             = 23,
+    has_appendix_shift         = 24,
+    is_forced_virtual_shift    = 25,
+    is_field_entry_shift       = 26,
+    // low order bits give field index (for FieldInfo) or method parameter size:
+    field_index_bits           = 16,
+    field_index_mask           = right_n_bits(field_index_bits),
+    parameter_size_bits        = 8,  // subset of field_index_mask, range is 0..255
+    parameter_size_mask        = right_n_bits(parameter_size_bits),
+    option_bits_mask           = ~(((-1) << tos_state_shift) | (field_index_mask | parameter_size_mask))
   };
 
-  enum { field_index_mask = 0xFFFF };
+  // specific bit definitions for the indices field:
+  enum {
+    main_cp_index_bits         = 2*BitsPerByte,
+    main_cp_index_mask         = right_n_bits(main_cp_index_bits),
+    bytecode_1_shift           = main_cp_index_bits,
+    bytecode_1_mask            = right_n_bits(BitsPerByte), // == (u1)0xFF
+    bytecode_2_shift           = main_cp_index_bits + BitsPerByte,
+    bytecode_2_mask            = right_n_bits(BitsPerByte), // == (u1)0xFF
+    // the secondary cp index overlaps with bytecodes 1 and 2:
+    secondary_cp_index_shift   = bytecode_1_shift,
+    secondary_cp_index_bits    = BitsPerInt - main_cp_index_bits
+  };
 
-  // start of type bits in flags
-  // Note: the interpreter knows this layout!
-  enum FlagValues {
-    tosBits      = 28
-  };
 
   // Initialization
   void initialize_entry(int original_index);     // initialize primary entry
@@ -189,30 +221,40 @@
     int index                                    // Method index into interface
   );
 
+  void set_method_handle(
+    methodHandle method,                         // adapter for invokeExact, etc.
+    Handle appendix                              // stored in f1; could be a java.lang.invoke.MethodType
+  );
+
   void set_dynamic_call(
-    Handle call_site,                            // Resolved java.lang.invoke.CallSite (f1)
-    methodHandle signature_invoker               // determines signature information
+    methodHandle method,                         // adapter for this call site
+    Handle appendix                              // stored in f1; could be a java.lang.invoke.CallSite
   );
 
-  methodOop get_method_if_resolved(Bytecodes::Code invoke_code, constantPoolHandle cpool);
-
-  // For JVM_CONSTANT_InvokeDynamic cache entries:
-  void initialize_bootstrap_method_index_in_cache(int bsm_cache_index);
-  int  bootstrap_method_index_in_cache();
+  // Common code for invokedynamic and MH invocations.
 
-  void set_parameter_size(int value) {
-    assert(parameter_size() == 0 || parameter_size() == value,
-           "size must not change");
-    // Setting the parameter size by itself is only safe if the
-    // current value of _flags is 0, otherwise another thread may have
-    // updated it and we don't want to overwrite that value.  Don't
-    // bother trying to update it once it's nonzero but always make
-    // sure that the final parameter size agrees with what was passed.
-    if (_flags == 0) {
-      Atomic::cmpxchg_ptr((value & 0xFF), &_flags, 0);
-    }
-    guarantee(parameter_size() == value, "size must not change");
-  }
+  // The "appendix" is an optional call-site-specific parameter which is
+  // pushed by the JVM at the end of the argument list.  This argument may
+  // be a MethodType for the MH.invokes and a CallSite for an invokedynamic
+  // instruction.  However, its exact type and use depends on the Java upcall,
+  // which simply returns a compiled LambdaForm along with any reference
+  // that LambdaForm needs to complete the call.  If the upcall returns a
+  // null appendix, the argument is not passed at all.
+  //
+  // The appendix is *not* represented in the signature of the symbolic
+  // reference for the call site, but (if present) it *is* represented in
+  // the methodOop bound to the site.  This means that static and dynamic
+  // resolution logic needs to make slightly different assessments about the
+  // number and types of arguments.
+  void set_method_handle_common(
+    Bytecodes::Code invoke_code,                 // _invokehandle or _invokedynamic
+    methodHandle adapter,                        // invoker method (f2)
+    Handle appendix                              // appendix such as CallSite, MethodType, etc. (f1)
+  );
+
+  methodOop method_if_resolved(constantPoolHandle cpool);
+
+  void set_parameter_size(int value);
 
   // Which bytecode number (1 or 2) in the index field is valid for this bytecode?
   // Returns -1 if neither is valid.
@@ -222,10 +264,11 @@
       case Bytecodes::_getfield        :    // fall through
       case Bytecodes::_invokespecial   :    // fall through
       case Bytecodes::_invokestatic    :    // fall through
-      case Bytecodes::_invokedynamic   :    // fall through
       case Bytecodes::_invokeinterface : return 1;
       case Bytecodes::_putstatic       :    // fall through
       case Bytecodes::_putfield        :    // fall through
+      case Bytecodes::_invokehandle    :    // fall through
+      case Bytecodes::_invokedynamic   :    // fall through
       case Bytecodes::_invokevirtual   : return 2;
       default                          : break;
     }
@@ -242,31 +285,43 @@
   }
 
   // Accessors
-  bool is_secondary_entry() const                { return (_indices & 0xFFFF) == 0; }
-  int constant_pool_index() const                { assert((_indices & 0xFFFF) != 0, "must be main entry");
-                                                   return (_indices & 0xFFFF); }
-  int main_entry_index() const                   { assert((_indices & 0xFFFF) == 0, "must be secondary entry");
-                                                   return ((uintx)_indices >> 16); }
-  Bytecodes::Code bytecode_1() const             { return Bytecodes::cast((_indices >> 16) & 0xFF); }
-  Bytecodes::Code bytecode_2() const             { return Bytecodes::cast((_indices >> 24) & 0xFF); }
-  volatile oop  f1() const                       { return _f1; }
-  bool is_f1_null() const                        { return (oop)_f1 == NULL; }  // classifies a CPC entry as unbound
-  intx f2() const                                { return _f2; }
-  int  field_index() const;
-  int  parameter_size() const                    { return _flags & 0xFF; }
-  bool is_vfinal() const                         { return ((_flags & (1 << vfinalMethod)) == (1 << vfinalMethod)); }
-  bool is_volatile() const                       { return ((_flags & (1 << volatileField)) == (1 << volatileField)); }
-  bool is_methodInterface() const                { return ((_flags & (1 << methodInterface)) == (1 << methodInterface)); }
-  bool is_byte() const                           { return (((uintx) _flags >> tosBits) == btos); }
-  bool is_char() const                           { return (((uintx) _flags >> tosBits) == ctos); }
-  bool is_short() const                          { return (((uintx) _flags >> tosBits) == stos); }
-  bool is_int() const                            { return (((uintx) _flags >> tosBits) == itos); }
-  bool is_long() const                           { return (((uintx) _flags >> tosBits) == ltos); }
-  bool is_float() const                          { return (((uintx) _flags >> tosBits) == ftos); }
-  bool is_double() const                         { return (((uintx) _flags >> tosBits) == dtos); }
-  bool is_object() const                         { return (((uintx) _flags >> tosBits) == atos); }
-  TosState flag_state() const                    { assert( ( (_flags >> tosBits) & 0x0F ) < number_of_states, "Invalid state in as_flags");
-                                                   return (TosState)((_flags >> tosBits) & 0x0F); }
+  bool is_secondary_entry() const                { return (_indices & main_cp_index_mask) == 0; }
+  int main_entry_index() const                   { assert(is_secondary_entry(), "must be secondary entry");
+                                                   return ((uintx)_indices >> secondary_cp_index_shift); }
+  int primary_entry_indices() const              { assert(!is_secondary_entry(), "must be main entry");
+                                                   return _indices; }
+  int constant_pool_index() const                { return (primary_entry_indices() & main_cp_index_mask); }
+  Bytecodes::Code bytecode_1() const             { return Bytecodes::cast((primary_entry_indices() >> bytecode_1_shift)
+                                                                          & bytecode_1_mask); }
+  Bytecodes::Code bytecode_2() const             { return Bytecodes::cast((primary_entry_indices() >> bytecode_2_shift)
+                                                                          & bytecode_2_mask); }
+  methodOop f1_as_method() const                 { oop f1 = _f1; assert(f1 == NULL || f1->is_method(), ""); return methodOop(f1); }
+  klassOop  f1_as_klass() const                  { oop f1 = _f1; assert(f1 == NULL || f1->is_klass(), ""); return klassOop(f1); }
+  oop       f1_as_klass_mirror() const           { oop f1 = f1_as_instance(); return f1; }  // i.e., return a java_mirror
+  oop       f1_as_instance() const               { oop f1 = _f1; assert(f1 == NULL || f1->is_instance() || f1->is_array(), ""); return f1; }
+  oop       f1_appendix() const                  { assert(has_appendix(), ""); return f1_as_instance(); }
+  bool      is_f1_null() const                   { oop f1 = _f1; return f1 == NULL; }  // classifies a CPC entry as unbound
+  int       f2_as_index() const                  { assert(!is_vfinal(), ""); return (int) _f2; }
+  methodOop f2_as_vfinal_method() const          { assert(is_vfinal(), ""); return methodOop(_f2); }
+  int  field_index() const                       { assert(is_field_entry(),  ""); return (_flags & field_index_mask); }
+  int  parameter_size() const                    { assert(is_method_entry(), ""); return (_flags & parameter_size_mask); }
+  bool is_volatile() const                       { return (_flags & (1 << is_volatile_shift))       != 0; }
+  bool is_final() const                          { return (_flags & (1 << is_final_shift))          != 0; }
+  bool has_appendix() const                      { return (_flags & (1 << has_appendix_shift))     != 0; }
+  bool is_forced_virtual() const                 { return (_flags & (1 << is_forced_virtual_shift)) != 0; }
+  bool is_vfinal() const                         { return (_flags & (1 << is_vfinal_shift))         != 0; }
+  bool is_method_entry() const                   { return (_flags & (1 << is_field_entry_shift))    == 0; }
+  bool is_field_entry() const                    { return (_flags & (1 << is_field_entry_shift))    != 0; }
+  bool is_byte() const                           { return flag_state() == btos; }
+  bool is_char() const                           { return flag_state() == ctos; }
+  bool is_short() const                          { return flag_state() == stos; }
+  bool is_int() const                            { return flag_state() == itos; }
+  bool is_long() const                           { return flag_state() == ltos; }
+  bool is_float() const                          { return flag_state() == ftos; }
+  bool is_double() const                         { return flag_state() == dtos; }
+  bool is_object() const                         { return flag_state() == atos; }
+  TosState flag_state() const                    { assert((uint)number_of_states <= (uint)tos_state_mask+1, "");
+                                                   return (TosState)((_flags >> tos_state_shift) & tos_state_mask); }
 
   // Code generation support
   static WordSize size()                         { return in_WordSize(sizeof(ConstantPoolCacheEntry) / HeapWordSize); }
@@ -299,15 +354,14 @@
   bool adjust_method_entry(methodOop old_method, methodOop new_method,
          bool * trace_name_printed);
   bool is_interesting_method_entry(klassOop k);
-  bool is_field_entry() const                    { return (_flags & (1 << hotSwapBit)) == 0; }
-  bool is_method_entry() const                   { return (_flags & (1 << hotSwapBit)) != 0; }
 
   // Debugging & Printing
   void print (outputStream* st, int index) const;
   void verify(outputStream* st) const;
 
-  static void verify_tosBits() {
-    assert(tosBits == 28, "interpreter now assumes tosBits is 28");
+  static void verify_tos_state_shift() {
+    // When shifting flags as a 32-bit int, make sure we don't need an extra mask for tos_state:
+    assert((((u4)-1 >> tos_state_shift) & ~tos_state_mask) == 0, "no need for tos_state mask");
   }
 };