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