7168280: Eliminate the generic signature index slot from field array for field without generic signature.
authorjiangli
Mon, 21 May 2012 14:10:35 -0400
changeset 12772 d317e5e08194
parent 12724 1e3d7ca55ffc
child 12773 55938361f8fa
7168280: Eliminate the generic signature index slot from field array for field without generic signature. Summary: Only allocate the generic signature index slot in the field array for field with generic signature attribute. Reviewed-by: coleenp, dlong
hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/AccessFlags.java
hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java
hotspot/src/share/vm/classfile/classFileParser.cpp
hotspot/src/share/vm/classfile/systemDictionary.cpp
hotspot/src/share/vm/oops/fieldInfo.hpp
hotspot/src/share/vm/oops/fieldStreams.hpp
hotspot/src/share/vm/oops/instanceKlass.hpp
hotspot/src/share/vm/runtime/fieldDescriptor.cpp
hotspot/src/share/vm/runtime/fieldDescriptor.hpp
hotspot/src/share/vm/runtime/vmStructs.cpp
hotspot/src/share/vm/utilities/accessFlags.hpp
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/AccessFlags.java	Fri May 18 14:57:28 2012 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/AccessFlags.java	Mon May 21 14:10:35 2012 -0400
@@ -81,6 +81,7 @@
   // field flags
   public boolean fieldAccessWatched () { return (flags & JVM_ACC_FIELD_ACCESS_WATCHED) != 0; }
   public boolean fieldModificationWatched() { return (flags & JVM_ACC_FIELD_MODIFICATION_WATCHED) != 0; }
+  public boolean fieldHasGenericSignature() { return (flags & JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE)!= 0; }
 
   public void printOn(PrintStream tty) {
     // prints only .class flags and not the hotspot internal flags
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java	Fri May 18 14:57:28 2012 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java	Mon May 21 14:10:35 2012 -0400
@@ -50,7 +50,6 @@
   private static int INITVAL_INDEX_OFFSET;
   private static int LOW_OFFSET;
   private static int HIGH_OFFSET;
-  private static int GENERIC_SIGNATURE_INDEX_OFFSET;
   private static int FIELD_SLOTS;
 
   // ClassState constants
@@ -99,7 +98,6 @@
     INITVAL_INDEX_OFFSET           = db.lookupIntConstant("FieldInfo::initval_index_offset").intValue();
     LOW_OFFSET                     = db.lookupIntConstant("FieldInfo::low_offset").intValue();
     HIGH_OFFSET                    = db.lookupIntConstant("FieldInfo::high_offset").intValue();
-    GENERIC_SIGNATURE_INDEX_OFFSET = db.lookupIntConstant("FieldInfo::generic_signature_offset").intValue();
     FIELD_SLOTS                    = db.lookupIntConstant("FieldInfo::field_slots").intValue();
     // read ClassState constants
     CLASS_STATE_UNPARSABLE_BY_GC = db.lookupIntConstant("instanceKlass::unparsable_by_gc").intValue();
@@ -279,7 +277,25 @@
   }
 
   public short getFieldGenericSignatureIndex(int index) {
-    return getFields().getShortAt(index * FIELD_SLOTS + GENERIC_SIGNATURE_INDEX_OFFSET);
+    int len = (int)getFields().getLength();
+    int allFieldsCount = getAllFieldsCount();
+    int generic_signature_slot = allFieldsCount * FIELD_SLOTS;
+    for (int i = 0; i < allFieldsCount; i++) {
+      short flags = getFieldAccessFlags(i);
+      AccessFlags access = new AccessFlags(flags);
+      if (i == index) {
+        if (access.fieldHasGenericSignature()) {
+          return getFields().getShortAt(generic_signature_slot);
+        } else {
+          return 0;
+        }
+      } else {
+        if (access.fieldHasGenericSignature()) {
+          generic_signature_slot ++;
+        }
+      }
+    }
+    return 0;
   }
 
   public Symbol getFieldGenericSignature(int index) {
@@ -309,7 +325,18 @@
   public ObjArray  getTransitiveInterfaces() { return (ObjArray)     transitiveInterfaces.getValue(this); }
   public TypeArray getFields()              { return (TypeArray)    fields.getValue(this); }
   public int       getJavaFieldsCount()     { return                (int) javaFieldsCount.getValue(this); }
-  public int       getAllFieldsCount()      { return                (int)getFields().getLength() / FIELD_SLOTS; }
+  public int       getAllFieldsCount()      {
+    int len = (int)getFields().getLength();
+    int allFieldsCount = 0;
+    for (; allFieldsCount*FIELD_SLOTS < len; allFieldsCount++) {
+      short flags = getFieldAccessFlags(allFieldsCount);
+      AccessFlags access = new AccessFlags(flags);
+      if (access.fieldHasGenericSignature()) {
+        len --;
+      }
+    }
+    return allFieldsCount;
+  }
   public ConstantPool getConstants()        { return (ConstantPool) constants.getValue(this); }
   public Oop       getClassLoader()         { return                classLoader.getValue(this); }
   public Oop       getProtectionDomain()    { return                protectionDomain.getValue(this); }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java	Fri May 18 14:57:28 2012 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java	Mon May 21 14:10:35 2012 -0400
@@ -153,6 +153,8 @@
     public static final long JVM_ACC_FIELD_ACCESS_WATCHED         = 0x00002000;
     // field modification is watched by JVMTI
     public static final long JVM_ACC_FIELD_MODIFICATION_WATCHED   = 0x00008000;
+    // field has generic signature
+    public static final long JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE  = 0x00000800;
 
     // flags accepted by set_field_flags
     public static final long JVM_ACC_FIELD_FLAGS = 0x00008000 | JVM_ACC_WRITTEN_FLAGS;
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp	Fri May 18 14:57:28 2012 -0700
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp	Mon May 21 14:10:35 2012 -0400
@@ -1082,12 +1082,36 @@
 
   int num_injected = 0;
   InjectedField* injected = JavaClasses::get_injected(class_name, &num_injected);
-
-  // Tuples of shorts [access, name index, sig index, initial value index, byte offset, generic signature index]
-  typeArrayOop new_fields = oopFactory::new_permanent_shortArray((length + num_injected) * FieldInfo::field_slots, CHECK_(nullHandle));
-  typeArrayHandle fields(THREAD, new_fields);
+  int total_fields = length + num_injected;
+
+  // The field array starts with tuples of shorts
+  // [access, name index, sig index, initial value index, byte offset].
+  // A generic signature slot only exists for field with generic
+  // signature attribute. And the access flag is set with
+  // JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE for that field. The generic
+  // signature slots are at the end of the field array and after all
+  // other fields data.
+  //
+  //   f1: [access, name index, sig index, initial value index, low_offset, high_offset]
+  //   f2: [access, name index, sig index, initial value index, low_offset, high_offset]
+  //       ...
+  //   fn: [access, name index, sig index, initial value index, low_offset, high_offset]
+  //       [generic signature index]
+  //       [generic signature index]
+  //       ...
+  //
+  // Allocate a temporary resource array for field data. For each field,
+  // a slot is reserved in the temporary array for the generic signature
+  // index. After parsing all fields, the data are copied to a permanent
+  // array and any unused slots will be discarded.
+  ResourceMark rm(THREAD);
+  u2* fa = NEW_RESOURCE_ARRAY_IN_THREAD(
+             THREAD, u2, total_fields * (FieldInfo::field_slots + 1));
 
   typeArrayHandle field_annotations;
+  // The generic signature slots start after all other fields' data.
+  int generic_signature_slot = total_fields * FieldInfo::field_slots;
+  int num_generic_signature = 0;
   for (int n = 0; n < length; n++) {
     cfs->guarantee_more(8, CHECK_(nullHandle));  // access_flags, name_index, descriptor_index, attributes_count
 
@@ -1135,14 +1159,19 @@
       if (is_synthetic) {
         access_flags.set_is_synthetic();
       }
+      if (generic_signature_index != 0) {
+        access_flags.set_field_has_generic_signature();
+        fa[generic_signature_slot] = generic_signature_index;
+        generic_signature_slot ++;
+        num_generic_signature ++;
+      }
     }
 
-    FieldInfo* field = FieldInfo::from_field_array(fields(), n);
+    FieldInfo* field = FieldInfo::from_field_array(fa, n);
     field->initialize(access_flags.as_short(),
                       name_index,
                       signature_index,
                       constantvalue_index,
-                      generic_signature_index,
                       0);
 
     BasicType type = cp->basic_type_for_signature_at(signature_index);
@@ -1155,8 +1184,8 @@
     field->set_offset(atype);
   }
 
+  int index = length;
   if (num_injected != 0) {
-    int index = length;
     for (int n = 0; n < num_injected; n++) {
       // Check for duplicates
       if (injected[n].may_be_java) {
@@ -1164,7 +1193,7 @@
         Symbol* signature = injected[n].signature();
         bool duplicate = false;
         for (int i = 0; i < length; i++) {
-          FieldInfo* f = FieldInfo::from_field_array(fields(), i);
+          FieldInfo* f = FieldInfo::from_field_array(fa, i);
           if (name      == cp->symbol_at(f->name_index()) &&
               signature == cp->symbol_at(f->signature_index())) {
             // Symbol is desclared in Java so skip this one
@@ -1179,12 +1208,11 @@
       }
 
       // Injected field
-      FieldInfo* field = FieldInfo::from_field_array(fields(), index);
+      FieldInfo* field = FieldInfo::from_field_array(fa, index);
       field->initialize(JVM_ACC_FIELD_INTERNAL,
                         injected[n].name_index,
                         injected[n].signature_index,
                         0,
-                        0,
                         0);
 
       BasicType type = FieldType::basic_type(injected[n].signature());
@@ -1197,17 +1225,27 @@
       field->set_offset(atype);
       index++;
     }
-
-    if (index < length + num_injected) {
-      // sometimes injected fields already exist in the Java source so
-      // the fields array could be too long.  In that case trim the
-      // fields array.
-      new_fields = oopFactory::new_permanent_shortArray(index * FieldInfo::field_slots, CHECK_(nullHandle));
-      for (int i = 0; i < index * FieldInfo::field_slots; i++) {
-        new_fields->short_at_put(i, fields->short_at(i));
-      }
-      fields = new_fields;
+  }
+
+  // Now copy the fields' data from the temporary resource array.
+  // Sometimes injected fields already exist in the Java source so
+  // the fields array could be too long.  In that case the
+  // fields array is trimed. Also unused slots that were reserved
+  // for generic signature indexes are discarded.
+  typeArrayOop new_fields = oopFactory::new_permanent_shortArray(
+    index * FieldInfo::field_slots + num_generic_signature,
+    CHECK_(nullHandle));
+  typeArrayHandle fields(THREAD, new_fields);
+  {
+    int i = 0;
+    for (; i < index * FieldInfo::field_slots; i++) {
+      new_fields->short_at_put(i, fa[i]);
     }
+    for (int j = total_fields * FieldInfo::field_slots;
+         j < generic_signature_slot; j++) {
+      new_fields->short_at_put(i++, fa[j]);
+    }
+    assert(i == new_fields->length(), "");
   }
 
   if (_need_verify && length > 1) {
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp	Fri May 18 14:57:28 2012 -0700
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp	Mon May 21 14:10:35 2012 -0400
@@ -2763,7 +2763,7 @@
       class_size += ik->local_interfaces()->size();
       class_size += ik->transitive_interfaces()->size();
       // We do not have to count implementors, since we only store one!
-      class_size += ik->all_fields_count() * FieldInfo::field_slots;
+      class_size += ik->fields()->length();
     }
   }
 
--- a/hotspot/src/share/vm/oops/fieldInfo.hpp	Fri May 18 14:57:28 2012 -0700
+++ b/hotspot/src/share/vm/oops/fieldInfo.hpp	Mon May 21 14:10:35 2012 -0400
@@ -50,8 +50,7 @@
     initval_index_offset     = 3,
     low_offset               = 4,
     high_offset              = 5,
-    generic_signature_offset = 6,
-    field_slots              = 7
+    field_slots              = 6
   };
 
  private:
@@ -60,29 +59,28 @@
   void set_name_index(u2 val)                    { _shorts[name_index_offset] = val;         }
   void set_signature_index(u2 val)               { _shorts[signature_index_offset] = val;    }
   void set_initval_index(u2 val)                 { _shorts[initval_index_offset] = val;      }
-  void set_generic_signature_index(u2 val)       { _shorts[generic_signature_offset] = val;  }
 
   u2 name_index() const                          { return _shorts[name_index_offset];        }
   u2 signature_index() const                     { return _shorts[signature_index_offset];   }
   u2 initval_index() const                       { return _shorts[initval_index_offset];     }
-  u2 generic_signature_index() const             { return _shorts[generic_signature_offset]; }
 
  public:
   static FieldInfo* from_field_array(typeArrayOop fields, int index) {
     return ((FieldInfo*)fields->short_at_addr(index * field_slots));
   }
+  static FieldInfo* from_field_array(u2* fields, int index) {
+    return ((FieldInfo*)(fields + index * field_slots));
+  }
 
   void initialize(u2 access_flags,
                   u2 name_index,
                   u2 signature_index,
                   u2 initval_index,
-                  u2 generic_signature_index,
                   u4 offset) {
     _shorts[access_flags_offset] = access_flags;
     _shorts[name_index_offset] = name_index;
     _shorts[signature_index_offset] = signature_index;
     _shorts[initval_index_offset] = initval_index;
-    _shorts[generic_signature_offset] = generic_signature_index;
     set_offset(offset);
   }
 
@@ -105,14 +103,6 @@
     return cp->symbol_at(index);
   }
 
-  Symbol* generic_signature(constantPoolHandle cp) const {
-    int index = generic_signature_index();
-    if (index == 0) {
-      return NULL;
-    }
-    return cp->symbol_at(index);
-  }
-
   void set_access_flags(u2 val)                  { _shorts[access_flags_offset] = val;             }
   void set_offset(u4 val)                        {
     _shorts[low_offset] = extract_low_short_from_int(val);
--- a/hotspot/src/share/vm/oops/fieldStreams.hpp	Fri May 18 14:57:28 2012 -0700
+++ b/hotspot/src/share/vm/oops/fieldStreams.hpp	Mon May 21 14:10:35 2012 -0400
@@ -42,21 +42,57 @@
   constantPoolHandle  _constants;
   int                 _index;
   int                 _limit;
+  int                 _generic_signature_slot;
 
   FieldInfo* field() const { return FieldInfo::from_field_array(_fields(), _index); }
 
+  int init_generic_signature_start_slot() {
+    int length = _fields->length();
+    int num_fields = 0;
+    int skipped_generic_signature_slots = 0;
+    FieldInfo* fi;
+    AccessFlags flags;
+    /* Scan from 0 to the current _index. Count the number of generic
+       signature slots for field[0] to field[_index - 1]. */
+    for (int i = 0; i < _index; i++) {
+      fi = FieldInfo::from_field_array(_fields(), i);
+      flags.set_flags(fi->access_flags());
+      if (flags.field_has_generic_signature()) {
+        length --;
+        skipped_generic_signature_slots ++;
+      }
+    }
+    /* Scan from the current _index. */
+    for (int i = _index; i*FieldInfo::field_slots < length; i++) {
+      fi = FieldInfo::from_field_array(_fields(), i);
+      flags.set_flags(fi->access_flags());
+      if (flags.field_has_generic_signature()) {
+        length --;
+      }
+      num_fields ++;
+    }
+    _generic_signature_slot = length + skipped_generic_signature_slots;
+    assert(_generic_signature_slot <= _fields->length(), "");
+    return num_fields;
+  }
+
   FieldStreamBase(typeArrayHandle fields, constantPoolHandle constants, int start, int limit) {
     _fields = fields;
     _constants = constants;
     _index = start;
-    _limit = limit;
+    int num_fields = init_generic_signature_start_slot();
+    if (limit < start) {
+      _limit = num_fields;
+    } else {
+      _limit = limit;
+    }
   }
 
   FieldStreamBase(typeArrayHandle fields, constantPoolHandle constants) {
     _fields = fields;
     _constants = constants;
     _index = 0;
-    _limit = fields->length() / FieldInfo::field_slots;
+    _limit = init_generic_signature_start_slot();
   }
 
  public:
@@ -65,18 +101,26 @@
     _constants = klass->constants();
     _index = 0;
     _limit = klass->java_fields_count();
+    init_generic_signature_start_slot();
   }
   FieldStreamBase(instanceKlassHandle klass) {
     _fields = klass->fields();
     _constants = klass->constants();
     _index = 0;
     _limit = klass->java_fields_count();
+    init_generic_signature_start_slot();
   }
 
   // accessors
   int index() const                 { return _index; }
 
-  void next() { _index += 1; }
+  void next() {
+    if (access_flags().field_has_generic_signature()) {
+      _generic_signature_slot ++;
+      assert(_generic_signature_slot <= _fields->length(), "");
+    }
+    _index += 1;
+  }
   bool done() const { return _index >= _limit; }
 
   // Accessors for current field
@@ -103,7 +147,13 @@
   }
 
   Symbol* generic_signature() const {
-    return field()->generic_signature(_constants);
+    if (access_flags().field_has_generic_signature()) {
+      assert(_generic_signature_slot < _fields->length(), "out of bounds");
+      int index = _fields->short_at(_generic_signature_slot);
+      return _constants->symbol_at(index);
+    } else {
+      return NULL;
+    }
   }
 
   int offset() const {
@@ -139,11 +189,19 @@
   }
   int generic_signature_index() const {
     assert(!field()->is_internal(), "regular only");
-    return field()->generic_signature_index();
+    if (access_flags().field_has_generic_signature()) {
+      assert(_generic_signature_slot < _fields->length(), "out of bounds");
+      return _fields->short_at(_generic_signature_slot);
+    } else {
+      return 0;
+    }
   }
   void set_generic_signature_index(int index) {
     assert(!field()->is_internal(), "regular only");
-    field()->set_generic_signature_index(index);
+    if (access_flags().field_has_generic_signature()) {
+      assert(_generic_signature_slot < _fields->length(), "out of bounds");
+      _fields->short_at_put(_generic_signature_slot, index);
+    }
   }
   int initval_index() const {
     assert(!field()->is_internal(), "regular only");
@@ -159,8 +217,8 @@
 // Iterate over only the internal fields
 class InternalFieldStream : public FieldStreamBase {
  public:
-  InternalFieldStream(instanceKlass* k):      FieldStreamBase(k->fields(), k->constants(), k->java_fields_count(), k->all_fields_count()) {}
-  InternalFieldStream(instanceKlassHandle k): FieldStreamBase(k->fields(), k->constants(), k->java_fields_count(), k->all_fields_count()) {}
+  InternalFieldStream(instanceKlass* k):      FieldStreamBase(k->fields(), k->constants(), k->java_fields_count(), 0) {}
+  InternalFieldStream(instanceKlassHandle k): FieldStreamBase(k->fields(), k->constants(), k->java_fields_count(), 0) {}
 };
 
 
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp	Fri May 18 14:57:28 2012 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp	Mon May 21 14:10:35 2012 -0400
@@ -168,8 +168,19 @@
   objArrayOop     _local_interfaces;
   // Interface (klassOops) this class implements transitively.
   objArrayOop     _transitive_interfaces;
-  // Instance and static variable information, 5-tuples of shorts [access, name
-  // index, sig index, initval index, offset].
+  // Instance and static variable information, starts with 6-tuples of shorts
+  // [access, name index, sig index, initval index, low_offset, high_offset]
+  // for all fields, followed by the generic signature data at the end of
+  // the array. Only fields with generic signature attributes have the generic
+  // signature data set in the array. The fields array looks like following:
+  //
+  // f1: [access, name index, sig index, initial value index, low_offset, high_offset]
+  // f2: [access, name index, sig index, initial value index, low_offset, high_offset]
+  //      ...
+  // fn: [access, name index, sig index, initial value index, low_offset, high_offset]
+  //     [generic signature index]
+  //     [generic signature index]
+  //     ...
   typeArrayOop    _fields;
   // Constant pool for this class.
   constantPoolOop _constants;
@@ -351,9 +362,6 @@
   // Number of Java declared fields
   int java_fields_count() const           { return (int)_java_fields_count; }
 
-  // Number of fields including any injected fields
-  int all_fields_count() const            { return _fields->length() / FieldInfo::field_slots; }
-
   typeArrayOop fields() const              { return _fields; }
 
   void set_fields(typeArrayOop f, u2 java_fields_count) {
--- a/hotspot/src/share/vm/runtime/fieldDescriptor.cpp	Fri May 18 14:57:28 2012 -0700
+++ b/hotspot/src/share/vm/runtime/fieldDescriptor.cpp	Mon May 21 14:10:35 2012 -0400
@@ -28,6 +28,7 @@
 #include "memory/resourceArea.hpp"
 #include "memory/universe.inline.hpp"
 #include "oops/instanceKlass.hpp"
+#include "oops/fieldStreams.hpp"
 #include "runtime/fieldDescriptor.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/signature.hpp"
@@ -37,6 +38,20 @@
   return instanceKlass::cast(_cp->pool_holder())->class_loader();
 }
 
+Symbol* fieldDescriptor::generic_signature() const {
+  int idx = 0;
+  instanceKlass* ik = instanceKlass::cast(field_holder());
+  for (AllFieldStream fs(ik); !fs.done(); fs.next()) {
+    if (idx == _index) {
+      return fs.generic_signature();
+    } else {
+      idx ++;
+    }
+  }
+  assert(false, "should never happen");
+  return NULL;
+}
+
 typeArrayOop fieldDescriptor::annotations() const {
   instanceKlass* ik = instanceKlass::cast(field_holder());
   objArrayOop md = ik->fields_annotations();
--- a/hotspot/src/share/vm/runtime/fieldDescriptor.hpp	Fri May 18 14:57:28 2012 -0700
+++ b/hotspot/src/share/vm/runtime/fieldDescriptor.hpp	Mon May 21 14:10:35 2012 -0400
@@ -67,7 +67,7 @@
   oop loader() const;
   // Offset (in words) of field from start of instanceOop / klassOop
   int offset() const                   { return field()->offset(); }
-  Symbol* generic_signature() const    { return field()->generic_signature(_cp); }
+  Symbol* generic_signature() const;
   int index() const                    { return _index; }
   typeArrayOop annotations() const;
 
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp	Fri May 18 14:57:28 2012 -0700
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp	Mon May 21 14:10:35 2012 -0400
@@ -2352,7 +2352,6 @@
   declare_constant(FieldInfo::initval_index_offset)                       \
   declare_constant(FieldInfo::low_offset)                                 \
   declare_constant(FieldInfo::high_offset)                                \
-  declare_constant(FieldInfo::generic_signature_offset)                   \
   declare_constant(FieldInfo::field_slots)                                \
                                                                           \
   /************************************************/                      \
--- a/hotspot/src/share/vm/utilities/accessFlags.hpp	Fri May 18 14:57:28 2012 -0700
+++ b/hotspot/src/share/vm/utilities/accessFlags.hpp	Mon May 21 14:10:35 2012 -0400
@@ -80,10 +80,12 @@
   JVM_ACC_FIELD_ACCESS_WATCHED       = 0x00002000,  // field access is watched by JVMTI
   JVM_ACC_FIELD_MODIFICATION_WATCHED = 0x00008000,  // field modification is watched by JVMTI
   JVM_ACC_FIELD_INTERNAL             = 0x00000400,  // internal field, same as JVM_ACC_ABSTRACT
+  JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE = 0x00000800, // field has generic signature
 
   JVM_ACC_FIELD_INTERNAL_FLAGS       = JVM_ACC_FIELD_ACCESS_WATCHED |
                                        JVM_ACC_FIELD_MODIFICATION_WATCHED |
-                                       JVM_ACC_FIELD_INTERNAL,
+                                       JVM_ACC_FIELD_INTERNAL |
+                                       JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE,
 
                                                     // flags accepted by set_field_flags()
   JVM_ACC_FIELD_FLAGS                = JVM_RECOGNIZED_FIELD_MODIFIERS | JVM_ACC_FIELD_INTERNAL_FLAGS
@@ -156,6 +158,8 @@
   bool is_field_modification_watched() const
                                         { return (_flags & JVM_ACC_FIELD_MODIFICATION_WATCHED) != 0; }
   bool is_internal() const              { return (_flags & JVM_ACC_FIELD_INTERNAL) != 0; }
+  bool field_has_generic_signature() const
+                                        { return (_flags & JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE) != 0; }
 
   // get .class file flags
   jint get_flags               () const { return (_flags & JVM_ACC_WRITTEN_FLAGS); }
@@ -225,6 +229,10 @@
                                            atomic_clear_bits(JVM_ACC_FIELD_MODIFICATION_WATCHED);
                                          }
                                        }
+  void set_field_has_generic_signature()
+                                       {
+                                         atomic_set_bits(JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE);
+                                       }
 
   // Conversion
   jshort as_short() const              { return (jshort)_flags; }