From bfb812a8ff8bca70aed7695c73f019ae66ac6f33 Mon Sep 17 00:00:00 2001 From: Frederic Parain Date: Fri, 17 Mar 2023 20:18:36 +0000 Subject: [PATCH] 8292818: replace 96-bit representation for field metadata with variable-sized streams Co-authored-by: John R Rose Co-authored-by: Chris Plummer Reviewed-by: dholmes, coleenp, cjplummer, dnsimon --- src/hotspot/share/ci/ciField.cpp | 2 +- src/hotspot/share/ci/ciFlags.hpp | 13 +- .../share/classfile/classFileParser.cpp | 141 +++---- .../share/classfile/classFileParser.hpp | 5 +- .../share/classfile/fieldLayoutBuilder.cpp | 49 +-- .../share/classfile/fieldLayoutBuilder.hpp | 12 +- src/hotspot/share/classfile/javaClasses.cpp | 28 +- .../share/interpreter/interpreterRuntime.cpp | 4 +- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 29 +- src/hotspot/share/jvmci/jvmciEnv.cpp | 27 ++ src/hotspot/share/jvmci/jvmciEnv.hpp | 1 + src/hotspot/share/jvmci/jvmciJavaClasses.hpp | 10 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 16 +- src/hotspot/share/jvmci/vmSymbols_jvmci.hpp | 3 +- src/hotspot/share/oops/array.hpp | 3 +- src/hotspot/share/oops/fieldInfo.cpp | 143 +++++++ src/hotspot/share/oops/fieldInfo.hpp | 349 ++++++++++++------ src/hotspot/share/oops/fieldInfo.inline.hpp | 182 +++++++++ src/hotspot/share/oops/fieldStreams.hpp | 144 +++----- .../share/oops/fieldStreams.inline.hpp | 32 +- src/hotspot/share/oops/instanceKlass.cpp | 26 +- src/hotspot/share/oops/instanceKlass.hpp | 45 +-- .../share/oops/instanceKlass.inline.hpp | 10 + .../prims/jvmtiClassFileReconstituter.cpp | 1 + .../share/prims/jvmtiRedefineClasses.cpp | 36 +- src/hotspot/share/runtime/deoptimization.cpp | 2 +- src/hotspot/share/runtime/fieldDescriptor.cpp | 37 +- src/hotspot/share/runtime/fieldDescriptor.hpp | 37 +- .../share/runtime/fieldDescriptor.inline.hpp | 36 +- src/hotspot/share/runtime/reflectionUtils.cpp | 2 + src/hotspot/share/runtime/reflectionUtils.hpp | 4 +- src/hotspot/share/runtime/vmStructs.cpp | 38 +- src/hotspot/share/utilities/accessFlags.hpp | 71 +--- src/hotspot/share/utilities/unsigned5.hpp | 4 +- .../sun/jvm/hotspot/oops/AccessFlags.java | 7 +- .../classes/sun/jvm/hotspot/oops/Field.java | 100 ++++- .../sun/jvm/hotspot/oops/InstanceKlass.java | 175 +++++---- .../jvm/hotspot/runtime/ClassConstants.java | 13 +- .../jvm/hotspot/tools/ClassLoaderStats.java | 4 +- .../jvm/hotspot/tools/jcore/ClassWriter.java | 8 +- .../ui/classbrowser/HTMLGenerator.java | 32 +- .../jvm/hotspot/utilities/GenericArray.java | 6 +- .../jdk/vm/ci/hotspot/CompilerToVM.java | 15 +- .../vm/ci/hotspot/HotSpotConstantPool.java | 7 +- .../hotspot/HotSpotResolvedJavaFieldImpl.java | 30 +- .../HotSpotResolvedObjectTypeImpl.java | 134 +++---- .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 17 +- .../jdk/vm/ci/meta/ResolvedJavaField.java | 2 +- .../hotspot/gtest/oops/test_instanceKlass.cpp | 6 +- .../HotSpotResolvedJavaFieldHelper.java | 4 +- .../compilerToVM/ResolveFieldInPoolTest.java | 4 +- .../test/HotSpotResolvedJavaFieldTest.java | 46 +-- .../test/TestHotSpotResolvedJavaField.java | 6 +- .../runtime/test/TestResolvedJavaField.java | 2 +- 54 files changed, 1302 insertions(+), 858 deletions(-) create mode 100644 src/hotspot/share/oops/fieldInfo.cpp create mode 100644 src/hotspot/share/oops/fieldInfo.inline.hpp diff --git a/src/hotspot/share/ci/ciField.cpp b/src/hotspot/share/ci/ciField.cpp index 62468f53bab..cd48bbbd6b2 100644 --- a/src/hotspot/share/ci/ciField.cpp +++ b/src/hotspot/share/ci/ciField.cpp @@ -255,7 +255,7 @@ static bool trust_final_non_static_fields(ciInstanceKlass* holder) { void ciField::initialize_from(fieldDescriptor* fd) { // Get the flags, offset, and canonical holder of the field. - _flags = ciFlags(fd->access_flags()); + _flags = ciFlags(fd->access_flags(), fd->field_flags().is_stable(), fd->field_status().is_initialized_final_update()); _offset = fd->offset(); Klass* field_holder = fd->field_holder(); assert(field_holder != nullptr, "null field_holder"); diff --git a/src/hotspot/share/ci/ciFlags.hpp b/src/hotspot/share/ci/ciFlags.hpp index 991cb1db0f0..dd1df622487 100644 --- a/src/hotspot/share/ci/ciFlags.hpp +++ b/src/hotspot/share/ci/ciFlags.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. 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 @@ -40,9 +40,12 @@ private: friend class ciMethod; jint _flags; + bool _stable; + bool _intialized_final_update; - ciFlags() { _flags = 0; } - ciFlags(AccessFlags flags) { _flags = flags.as_int(); } + ciFlags() :_flags(0), _stable(false), _intialized_final_update(false) { } + ciFlags(AccessFlags flags, bool is_stable = false, bool is_initialized_final_update = false) : + _flags(flags.as_int()), _stable(is_stable), _intialized_final_update(is_initialized_final_update) { } public: // Java access flags @@ -58,12 +61,12 @@ public: bool is_native () const { return (_flags & JVM_ACC_NATIVE ) != 0; } bool is_interface () const { return (_flags & JVM_ACC_INTERFACE ) != 0; } bool is_abstract () const { return (_flags & JVM_ACC_ABSTRACT ) != 0; } - bool is_stable () const { return (_flags & JVM_ACC_FIELD_STABLE ) != 0; } + bool is_stable () const { return _stable; } // In case the current object represents a field, return true if // the field is modified outside of instance initializer methods // (or class/initializer methods if the field is static) and false // otherwise. - bool has_initialized_final_update() const { return (_flags & JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE) != 0; }; + bool has_initialized_final_update() const { return _intialized_final_update; }; // Conversion jint as_int() { return _flags; } diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index f2ff82c4949..890df676736 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -48,6 +48,7 @@ #include "memory/universe.hpp" #include "oops/annotations.hpp" #include "oops/constantPool.inline.hpp" +#include "oops/fieldInfo.hpp" #include "oops/fieldStreams.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/instanceMirrorKlass.hpp" @@ -1471,7 +1472,6 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, assert(cp != nullptr, "invariant"); assert(java_fields_count_ptr != nullptr, "invariant"); - assert(nullptr == _fields, "invariant"); assert(nullptr == _fields_annotations, "invariant"); assert(nullptr == _fields_type_annotations, "invariant"); @@ -1484,34 +1484,11 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, &num_injected); const 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* const fa = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, - u2, - total_fields * (FieldInfo::field_slots + 1)); + // Allocate a temporary resource array to collect field data. + // After parsing all fields, data are stored in a UNSIGNED5 compressed stream. + _temp_field_info = new GrowableArray(total_fields); - // The generic signature slots start after all other fields' data. - int generic_signature_slot = total_fields * FieldInfo::field_slots; - int num_generic_signature = 0; + ResourceMark rm(THREAD); for (int n = 0; n < length; n++) { // access_flags, name_index, descriptor_index, attributes_count cfs->guarantee_more(8, CHECK); @@ -1520,6 +1497,7 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, const jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_FIELD_MODIFIERS; verify_legal_field_modifiers(flags, is_interface, CHECK); access_flags.set_flags(flags); + FieldInfo::FieldFlags fieldFlags(0); const u2 name_index = cfs->get_u2_fast(); check_property(valid_symbol_at(name_index), @@ -1578,31 +1556,27 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, 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 ++; + fieldFlags.update_generic(true); } } - FieldInfo* const field = FieldInfo::from_field_array(fa, n); - field->initialize(access_flags.as_short(), - name_index, - signature_index, - constantvalue_index); const BasicType type = cp->basic_type_for_signature_at(signature_index); // Update FieldAllocationCount for this kind of field fac->update(is_static, type); - // After field is initialized with type, we can augment it with aux info - if (parsed_annotations.has_any_annotations()) { - parsed_annotations.apply_to(field); - if (field->is_contended()) { - _has_contended_fields = true; - } + FieldInfo fi(access_flags, name_index, signature_index, constantvalue_index, fieldFlags); + fi.set_index(n); + if (fieldFlags.is_generic()) { + fi.set_generic_signature_index(generic_signature_index); } + parsed_annotations.apply_to(&fi); + if (fi.field_flags().is_contended()) { + _has_contended_fields = true; + } + _temp_field_info->append(fi); } + assert(_temp_field_info->length() == length, "Must be"); int index = length; if (num_injected != 0) { @@ -1613,7 +1587,7 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, const Symbol* const signature = injected[n].signature(); bool duplicate = false; for (int i = 0; i < length; i++) { - const FieldInfo* const f = FieldInfo::from_field_array(fa, i); + const FieldInfo* const f = _temp_field_info->adr_at(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 @@ -1628,41 +1602,21 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, } // Injected field - FieldInfo* const field = FieldInfo::from_field_array(fa, index); - field->initialize((u2)JVM_ACC_FIELD_INTERNAL, - (u2)(injected[n].name_index), - (u2)(injected[n].signature_index), - 0); - - const BasicType type = Signature::basic_type(injected[n].signature()); + FieldInfo::FieldFlags fflags(0); + fflags.update_injected(true); + AccessFlags aflags; + FieldInfo fi(aflags, (u2)(injected[n].name_index), (u2)(injected[n].signature_index), 0, fflags); + fi.set_index(index); + _temp_field_info->append(fi); // Update FieldAllocationCount for this kind of field + const BasicType type = Signature::basic_type(injected[n].signature()); fac->update(false, type); index++; } } - assert(nullptr == _fields, "invariant"); - - _fields = - MetadataFactory::new_array(_loader_data, - index * FieldInfo::field_slots + num_generic_signature, - CHECK); - // Sometimes injected fields already exist in the Java source so - // the fields array could be too long. In that case the - // fields array is trimmed. Also unused slots that were reserved - // for generic signature indexes are discarded. - { - int i = 0; - for (; i < index * FieldInfo::field_slots; i++) { - _fields->at_put(i, fa[i]); - } - for (int j = total_fields * FieldInfo::field_slots; - j < generic_signature_slot; j++) { - _fields->at_put(i++, fa[j]); - } - assert(_fields->length() == i, ""); - } + assert(_temp_field_info->length() == index, "Must be"); if (_need_verify && length > 1) { // Check duplicated fields @@ -1675,9 +1629,9 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, const Symbol* sig = nullptr; { debug_only(NoSafepointVerifier nsv;) - for (AllFieldStream fs(_fields, cp); !fs.done(); fs.next()) { - name = fs.name(); - sig = fs.signature(); + for (int i = 0; i < _temp_field_info->length(); i++) { + name = _temp_field_info->adr_at(i)->name(_cp); + sig = _temp_field_info->adr_at(i)->signature(_cp); // If no duplicates, add name/signature in hashtable names_and_sigs. if (!put_after_lookup(name, sig, names_and_sigs)) { dup = true; @@ -2055,9 +2009,10 @@ AnnotationCollector::annotation_index(const ClassLoaderData* loader_data, void ClassFileParser::FieldAnnotationCollector::apply_to(FieldInfo* f) { if (is_contended()) + // Setting the contended group also sets the contended bit in field flags f->set_contended_group(contended_group()); if (is_stable()) - f->set_stable(true); + (f->field_flags_addr())->update_stable(true); } ClassFileParser::FieldAnnotationCollector::~FieldAnnotationCollector() { @@ -3969,7 +3924,8 @@ void ClassFileParser::apply_parsed_class_metadata( _cp->set_pool_holder(this_klass); this_klass->set_constants(_cp); - this_klass->set_fields(_fields, java_fields_count); + this_klass->set_fieldinfo_stream(_fieldinfo_stream); + this_klass->set_fields_status(_fields_status); this_klass->set_methods(_methods); this_klass->set_inner_classes(_inner_classes); this_klass->set_nest_members(_nest_members); @@ -5316,7 +5272,8 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, // note that is not safe to use the fields in the parser from this point on assert(nullptr == _cp, "invariant"); - assert(nullptr == _fields, "invariant"); + assert(nullptr == _fieldinfo_stream, "invariant"); + assert(nullptr == _fields_status, "invariant"); assert(nullptr == _methods, "invariant"); assert(nullptr == _inner_classes, "invariant"); assert(nullptr == _nest_members, "invariant"); @@ -5548,7 +5505,8 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream, _orig_cp_size(0), _super_klass(), _cp(nullptr), - _fields(nullptr), + _fieldinfo_stream(nullptr), + _fields_status(nullptr), _methods(nullptr), _inner_classes(nullptr), _nest_members(nullptr), @@ -5567,6 +5525,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream, _parsed_annotations(nullptr), _fac(nullptr), _field_info(nullptr), + _temp_field_info(nullptr), _method_ordering(nullptr), _all_mirandas(nullptr), _vtable_size(0), @@ -5638,7 +5597,8 @@ void ClassFileParser::clear_class_metadata() { // metadata created before the instance klass is created. Must be // deallocated if classfile parsing returns an error. _cp = nullptr; - _fields = nullptr; + _fieldinfo_stream = nullptr; + _fields_status = nullptr; _methods = nullptr; _inner_classes = nullptr; _nest_members = nullptr; @@ -5656,8 +5616,13 @@ ClassFileParser::~ClassFileParser() { if (_cp != nullptr) { MetadataFactory::free_metadata(_loader_data, _cp); } - if (_fields != nullptr) { - MetadataFactory::free_array(_loader_data, _fields); + + if (_fieldinfo_stream != nullptr) { + MetadataFactory::free_array(_loader_data, _fieldinfo_stream); + } + + if (_fields_status != nullptr) { + MetadataFactory::free_array(_loader_data, _fields_status); } if (_methods != nullptr) { @@ -5894,7 +5859,7 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream, &_java_fields_count, CHECK); - assert(_fields != nullptr, "invariant"); + assert(_temp_field_info != nullptr, "invariant"); // Methods parse_methods(stream, @@ -6050,9 +6015,17 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st assert(_parsed_annotations != nullptr, "invariant"); _field_info = new FieldLayoutInfo(); - FieldLayoutBuilder lb(class_name(), super_klass(), _cp, _fields, + FieldLayoutBuilder lb(class_name(), super_klass(), _cp, /*_fields*/ _temp_field_info, _parsed_annotations->is_contended(), _field_info); lb.build_layout(); + + int injected_fields_count = _temp_field_info->length() - _java_fields_count; + _fieldinfo_stream = + FieldInfoStream::create_FieldInfoStream(_temp_field_info, _java_fields_count, + injected_fields_count, loader_data(), CHECK); + _fields_status = + MetadataFactory::new_array(_loader_data, _temp_field_info->length(), + FieldStatus(0), CHECK); } void ClassFileParser::set_klass(InstanceKlass* klass) { diff --git a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp index 9c9a388f3e8..d57d7fed7d7 100644 --- a/src/hotspot/share/classfile/classFileParser.hpp +++ b/src/hotspot/share/classfile/classFileParser.hpp @@ -28,6 +28,7 @@ #include "memory/referenceType.hpp" #include "oops/annotations.hpp" #include "oops/constantPool.hpp" +#include "oops/fieldInfo.hpp" #include "oops/instanceKlass.hpp" #include "oops/typeArrayOop.hpp" #include "utilities/accessFlags.hpp" @@ -121,7 +122,8 @@ class ClassFileParser { // in which case these pointers have been set to null. const InstanceKlass* _super_klass; ConstantPool* _cp; - Array* _fields; + Array* _fieldinfo_stream; + Array* _fields_status; Array* _methods; Array* _inner_classes; Array* _nest_members; @@ -141,6 +143,7 @@ class ClassFileParser { ClassAnnotationCollector* _parsed_annotations; FieldAllocationCount* _fac; FieldLayoutInfo* _field_info; + GrowableArray* _temp_field_info; const intArray* _method_ordering; GrowableArray* _all_mirandas; diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp index f89eb625642..c77016d74aa 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp @@ -80,18 +80,18 @@ FieldGroup::FieldGroup(int contended_group) : _contended_group(contended_group), // -1 means no contended group, 0 means default contended group _oop_count(0) {} -void FieldGroup::add_primitive_field(AllFieldStream fs, BasicType type) { +void FieldGroup::add_primitive_field(int idx, BasicType type) { int size = type2aelembytes(type); - LayoutRawBlock* block = new LayoutRawBlock(fs.index(), LayoutRawBlock::REGULAR, size, size /* alignment == size for primitive types */, false); + LayoutRawBlock* block = new LayoutRawBlock(idx, LayoutRawBlock::REGULAR, size, size /* alignment == size for primitive types */, false); if (_primitive_fields == nullptr) { _primitive_fields = new GrowableArray(INITIAL_LIST_SIZE); } _primitive_fields->append(block); } -void FieldGroup::add_oop_field(AllFieldStream fs) { +void FieldGroup::add_oop_field(int idx) { int size = type2aelembytes(T_OBJECT); - LayoutRawBlock* block = new LayoutRawBlock(fs.index(), LayoutRawBlock::REGULAR, size, size /* alignment == size for oops */, true); + LayoutRawBlock* block = new LayoutRawBlock(idx, LayoutRawBlock::REGULAR, size, size /* alignment == size for oops */, true); if (_oop_fields == nullptr) { _oop_fields = new GrowableArray(INITIAL_LIST_SIZE); } @@ -105,8 +105,8 @@ void FieldGroup::sort_by_size() { } } -FieldLayout::FieldLayout(Array* fields, ConstantPool* cp) : - _fields(fields), +FieldLayout::FieldLayout(GrowableArray* field_info, ConstantPool* cp) : + _field_info(field_info), _cp(cp), _blocks(nullptr), _start(_blocks), @@ -231,7 +231,7 @@ void FieldLayout::add_field_at_offset(LayoutRawBlock* block, int offset, LayoutR if (slot->size() == 0) { remove(slot); } - FieldInfo::from_field_array(_fields, block->field_index())->set_offset(block->offset()); + _field_info->adr_at(block->field_index())->set_offset(block->offset()); return; } slot = slot->next_block(); @@ -290,7 +290,7 @@ LayoutRawBlock* FieldLayout::insert_field_block(LayoutRawBlock* slot, LayoutRawB if (slot->size() == 0) { remove(slot); } - FieldInfo::from_field_array(_fields, block->field_index())->set_offset(block->offset()); + _field_info->adr_at(block->field_index())->set_offset(block->offset()); return block; } @@ -298,7 +298,7 @@ bool FieldLayout::reconstruct_layout(const InstanceKlass* ik) { bool has_instance_fields = false; GrowableArray* all_fields = new GrowableArray(32); while (ik != nullptr) { - for (AllFieldStream fs(ik->fields(), ik->constants()); !fs.done(); fs.next()) { + for (AllFieldStream fs(ik->fieldinfo_stream(), ik->constants()); !fs.done(); fs.next()) { BasicType type = Signature::basic_type(fs.signature()); // distinction between static and non-static fields is missing if (fs.access_flags().is_static()) continue; @@ -430,7 +430,7 @@ void FieldLayout::print(outputStream* output, bool is_static, const InstanceKlas while(b != _last) { switch(b->kind()) { case LayoutRawBlock::REGULAR: { - FieldInfo* fi = FieldInfo::from_field_array(_fields, b->field_index()); + FieldInfo* fi = _field_info->adr_at(b->field_index()); output->print_cr(" @%d \"%s\" %s %d/%d %s", b->offset(), fi->name(_cp)->as_C_string(), @@ -441,7 +441,7 @@ void FieldLayout::print(outputStream* output, bool is_static, const InstanceKlas break; } case LayoutRawBlock::FLATTENED: { - FieldInfo* fi = FieldInfo::from_field_array(_fields, b->field_index()); + FieldInfo* fi = _field_info->adr_at(b->field_index()); output->print_cr(" @%d \"%s\" %s %d/%d %s", b->offset(), fi->name(_cp)->as_C_string(), @@ -464,7 +464,7 @@ void FieldLayout::print(outputStream* output, bool is_static, const InstanceKlas bool found = false; const InstanceKlass* ik = super; while (!found && ik != nullptr) { - for (AllFieldStream fs(ik->fields(), ik->constants()); !fs.done(); fs.next()) { + for (AllFieldStream fs(ik->fieldinfo_stream(), ik->constants()); !fs.done(); fs.next()) { if (fs.offset() == b->offset()) { output->print_cr(" @%d \"%s\" %s %d/%d %s", b->offset(), @@ -499,11 +499,11 @@ void FieldLayout::print(outputStream* output, bool is_static, const InstanceKlas } FieldLayoutBuilder::FieldLayoutBuilder(const Symbol* classname, const InstanceKlass* super_klass, ConstantPool* constant_pool, - Array* fields, bool is_contended, FieldLayoutInfo* info) : + GrowableArray* field_info, bool is_contended, FieldLayoutInfo* info) : _classname(classname), _super_klass(super_klass), _constant_pool(constant_pool), - _fields(fields), + _field_info(field_info), _info(info), _root_group(nullptr), _contended_groups(GrowableArray(8)), @@ -529,13 +529,13 @@ FieldGroup* FieldLayoutBuilder::get_or_create_contended_group(int g) { } void FieldLayoutBuilder::prologue() { - _layout = new FieldLayout(_fields, _constant_pool); + _layout = new FieldLayout(_field_info, _constant_pool); const InstanceKlass* super_klass = _super_klass; _layout->initialize_instance_layout(super_klass); if (super_klass != nullptr) { _has_nonstatic_fields = super_klass->has_nonstatic_fields(); } - _static_layout = new FieldLayout(_fields, _constant_pool); + _static_layout = new FieldLayout(_field_info, _constant_pool); _static_layout->initialize_static_layout(); _static_fields = new FieldGroup(); _root_group = new FieldGroup(); @@ -547,14 +547,17 @@ void FieldLayoutBuilder::prologue() { // (support of the @Contended annotation) // - @Contended annotation is ignored for static fields void FieldLayoutBuilder::regular_field_sorting() { - for (AllFieldStream fs(_fields, _constant_pool); !fs.done(); fs.next()) { + int idx = 0; + for (GrowableArrayIterator it = _field_info->begin(); it != _field_info->end(); ++it, ++idx) { + FieldInfo ctrl = _field_info->at(0); FieldGroup* group = nullptr; - if (fs.access_flags().is_static()) { + FieldInfo fieldinfo = *it; + if (fieldinfo.access_flags().is_static()) { group = _static_fields; } else { _has_nonstatic_fields = true; - if (fs.is_contended()) { - int g = fs.contended_group(); + if (fieldinfo.field_flags().is_contended()) { + int g = fieldinfo.contended_group(); if (g == 0) { group = new FieldGroup(true); _contended_groups.append(group); @@ -566,7 +569,7 @@ void FieldLayoutBuilder::regular_field_sorting() { } } assert(group != nullptr, "invariant"); - BasicType type = Signature::basic_type(fs.signature()); + BasicType type = Signature::basic_type(fieldinfo.signature(_constant_pool)); switch(type) { case T_BYTE: case T_CHAR: @@ -576,12 +579,12 @@ void FieldLayoutBuilder::regular_field_sorting() { case T_LONG: case T_SHORT: case T_BOOLEAN: - group->add_primitive_field(fs, type); + group->add_primitive_field(idx, type); break; case T_OBJECT: case T_ARRAY: if (group != _static_fields) _nonstatic_oopmap_count++; - group->add_oop_field(fs); + group->add_oop_field(idx); break; default: fatal("Something wrong?"); diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.hpp b/src/hotspot/share/classfile/fieldLayoutBuilder.hpp index 63a9337f674..cda64788acf 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.hpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.hpp @@ -141,8 +141,8 @@ class FieldGroup : public ResourceObj { int contended_group() const { return _contended_group; } int oop_count() const { return _oop_count; } - void add_primitive_field(AllFieldStream fs, BasicType type); - void add_oop_field(AllFieldStream fs); + void add_primitive_field(int idx, BasicType type); + void add_oop_field(int idx); void sort_by_size(); }; @@ -164,14 +164,14 @@ class FieldGroup : public ResourceObj { // class FieldLayout : public ResourceObj { private: - Array* _fields; + GrowableArray* _field_info; ConstantPool* _cp; LayoutRawBlock* _blocks; // the layout being computed LayoutRawBlock* _start; // points to the first block where a field can be inserted LayoutRawBlock* _last; // points to the last block of the layout (big empty block) public: - FieldLayout(Array* fields, ConstantPool* cp); + FieldLayout(GrowableArray* field_info, ConstantPool* cp); void initialize_static_layout(); void initialize_instance_layout(const InstanceKlass* ik); @@ -230,7 +230,7 @@ class FieldLayoutBuilder : public ResourceObj { const Symbol* _classname; const InstanceKlass* _super_klass; ConstantPool* _constant_pool; - Array* _fields; + GrowableArray* _field_info; FieldLayoutInfo* _info; FieldGroup* _root_group; GrowableArray _contended_groups; @@ -244,7 +244,7 @@ class FieldLayoutBuilder : public ResourceObj { public: FieldLayoutBuilder(const Symbol* classname, const InstanceKlass* super_klass, ConstantPool* constant_pool, - Array* fields, bool is_contended, FieldLayoutInfo* info); + GrowableArray* field_info, bool is_contended, FieldLayoutInfo* info); int get_alignment() { assert(_alignment != -1, "Uninitialized"); diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index c2b83aaeb02..98c75cfba39 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -50,6 +50,7 @@ #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" +#include "oops/fieldInfo.hpp" #include "oops/fieldStreams.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/instanceMirrorKlass.hpp" @@ -861,12 +862,29 @@ void java_lang_Class::fixup_mirror(Klass* k, TRAPS) { // During bootstrap, java.lang.Class wasn't loaded so static field // offsets were computed without the size added it. Go back and // update all the static field offsets to included the size. - for (JavaFieldStream fs(InstanceKlass::cast(k)); !fs.done(); fs.next()) { - if (fs.access_flags().is_static()) { - int real_offset = fs.offset() + InstanceMirrorKlass::offset_of_static_fields(); - fs.set_offset(real_offset); + + // Unfortunately, the FieldInfo stream is encoded with UNSIGNED5 which doesn't allow + // content updates. So the FieldInfo stream has to be decompressed into a temporary array, + // static fields offsets are updated in this array before reencoding everything into + // a new UNSIGNED5 stream, and substitute it to the old FieldInfo stream. + + int java_fields; + int injected_fields; + InstanceKlass* ik = InstanceKlass::cast(k); + GrowableArray* fields = + FieldInfoStream::create_FieldInfoArray(ik->fieldinfo_stream(), + &java_fields, &injected_fields); + for (int i = 0; i < fields->length(); i++) { + FieldInfo* fi = fields->adr_at(i); + if (fi->access_flags().is_static()) { + fi->set_offset(fi->offset() + InstanceMirrorKlass::offset_of_static_fields()); } } + Array* old_stream = ik->fieldinfo_stream(); + assert(fields->length() == (java_fields + injected_fields), "Must be"); + Array* new_fis = FieldInfoStream::create_FieldInfoStream(fields, java_fields, injected_fields, k->class_loader_data(), CHECK); + ik->set_fieldinfo_stream(new_fis); + MetadataFactory::free_array(k->class_loader_data(), old_stream); } } @@ -5345,7 +5363,7 @@ void JavaClasses::check_offsets() { int InjectedField::compute_offset() { InstanceKlass* ik = InstanceKlass::cast(klass()); for (AllFieldStream fs(ik); !fs.done(); fs.next()) { - if (!may_be_java && !fs.access_flags().is_internal()) { + if (!may_be_java && !fs.field_flags().is_injected()) { // Only look at injected fields continue; } diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index af1d016f44b..b1dd60a6ae8 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -1155,7 +1155,7 @@ JRT_ENTRY(void, InterpreterRuntime::post_field_access(JavaThread* current, oopDe InstanceKlass* ik = InstanceKlass::cast(cp_entry->f1_as_klass()); int index = cp_entry->field_index(); - if ((ik->field_access_flags(index) & JVM_ACC_FIELD_ACCESS_WATCHED) == 0) return; + if (!ik->field_status(index).is_access_watched()) return; bool is_static = (obj == nullptr); HandleMark hm(current); @@ -1180,7 +1180,7 @@ JRT_ENTRY(void, InterpreterRuntime::post_field_modification(JavaThread* current, InstanceKlass* ik = InstanceKlass::cast(k); int index = cp_entry->field_index(); // bail out if field modifications are not watched - if ((ik->field_access_flags(index) & JVM_ACC_FIELD_MODIFICATION_WATCHED) == 0) return; + if (!ik->field_status(index).is_modification_watched()) return; char sig_type = '\0'; diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 2e9e4d1047e..784f8fb2991 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -810,12 +810,13 @@ C2V_VMENTRY_NULL(jobject, resolveFieldInPool, (JNIEnv* env, jobject, ARGUMENT_PA LinkInfo link_info(cp, index, mh, CHECK_NULL); LinkResolver::resolve_field(fd, link_info, Bytecodes::java_code(code), false, CHECK_NULL); JVMCIPrimitiveArray info = JVMCIENV->wrap(info_handle); - if (info.is_null() || JVMCIENV->get_length(info) != 3) { - JVMCI_ERROR_NULL("info must not be null and have a length of 3"); + if (info.is_null() || JVMCIENV->get_length(info) != 4) { + JVMCI_ERROR_NULL("info must not be null and have a length of 4"); } JVMCIENV->put_int_at(info, 0, fd.access_flags().as_int()); JVMCIENV->put_int_at(info, 1, fd.offset()); JVMCIENV->put_int_at(info, 2, fd.index()); + JVMCIENV->put_int_at(info, 3, fd.field_flags().as_uint()); JVMCIKlassHandle handle(THREAD, fd.field_holder()); JVMCIObject field_holder = JVMCIENV->get_jvmci_type(handle, JVMCI_CHECK_NULL); return JVMCIENV->get_jobject(field_holder); @@ -1963,6 +1964,25 @@ C2V_VMENTRY_NULL(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, ARGUME return JVMCIENV->get_jobjectArray(methods); C2V_END +C2V_VMENTRY_NULL(jobjectArray, getDeclaredFieldsInfo, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) + Klass* klass = UNPACK_PAIR(Klass, klass); + if (klass == nullptr) { + JVMCI_THROW_0(NullPointerException); + } + if (!klass->is_instance_klass()) { + JVMCI_THROW_MSG_NULL(IllegalArgumentException, "not an InstanceKlass"); + } + InstanceKlass* iklass = InstanceKlass::cast(klass); + int java_fields, injected_fields; + GrowableArray* fields = FieldInfoStream::create_FieldInfoArray(iklass->fieldinfo_stream(), &java_fields, &injected_fields); + JVMCIObjectArray array = JVMCIENV->new_FieldInfo_array(fields->length(), JVMCIENV); + for (int i = 0; i < fields->length(); i++) { + JVMCIObject field_info = JVMCIENV->new_FieldInfo(fields->adr_at(i), JVMCI_CHECK_NULL); + JVMCIENV->put_object_at(array, i, field_info); + } + return array.as_jobject(); +C2V_END + static jobject read_field_value(Handle obj, long displacement, jchar type_char, bool is_static, Thread* THREAD, JVMCIEnv* JVMCIENV) { BasicType basic_type = JVMCIENV->typeCharToBasicType(type_char, JVMCI_CHECK_NULL); @@ -2649,8 +2669,7 @@ C2V_VMENTRY_NULL(jobject, asReflectionField, (JNIEnv* env, jobject, ARGUMENT_PAI err_msg("Expected non-primitive type, got %s", klass->external_name())); } InstanceKlass* iklass = InstanceKlass::cast(klass); - Array* fields = iklass->fields(); - if (index < 0 ||index > fields->length()) { + if (index < 0 || index > iklass->total_fields_count()) { JVMCI_THROW_MSG_NULL(IllegalArgumentException, err_msg("Field index %d out of bounds for %s", index, klass->external_name())); } @@ -2814,6 +2833,7 @@ C2V_VMENTRY_0(jlong, getThreadLocalLong, (JNIEnv* env, jobject, jint id)) #define JAVACONSTANT "Ljdk/vm/ci/meta/JavaConstant;" #define INSPECTED_FRAME_VISITOR "Ljdk/vm/ci/code/stack/InspectedFrameVisitor;" #define RESOLVED_METHOD "Ljdk/vm/ci/meta/ResolvedJavaMethod;" +#define FIELDINFO "Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl$FieldInfo;" #define HS_RESOLVED_TYPE "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaType;" #define HS_INSTALLED_CODE "Ljdk/vm/ci/hotspot/HotSpotInstalledCode;" #define HS_NMETHOD "Ljdk/vm/ci/hotspot/HotSpotNmethod;" @@ -2912,6 +2932,7 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "boxPrimitive", CC "(" OBJECT ")" OBJECTCONSTANT, FN_PTR(boxPrimitive)}, {CC "getDeclaredConstructors", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredConstructors)}, {CC "getDeclaredMethods", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredMethods)}, + {CC "getDeclaredFieldsInfo", CC "(" HS_KLASS2 ")[" FIELDINFO, FN_PTR(getDeclaredFieldsInfo)}, {CC "readStaticFieldValue", CC "(" HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readStaticFieldValue)}, {CC "readFieldValue", CC "(" OBJECTCONSTANT HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readFieldValue)}, {CC "isInstance", CC "(" HS_KLASS2 OBJECTCONSTANT ")Z", FN_PTR(isInstance)}, diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index ff7587b8321..2aa10f5098a 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -1420,6 +1420,33 @@ JVMCIObject JVMCIEnv::new_JVMCIError(JVMCI_TRAPS) { } } +JVMCIObject JVMCIEnv::new_FieldInfo(FieldInfo* fieldinfo, JVMCI_TRAPS) { + JavaThread* THREAD = JavaThread::current(); // For exception macros. + if (is_hotspot()) { + HotSpotJVMCI::FieldInfo::klass()->initialize(CHECK_(JVMCIObject())); + oop obj = HotSpotJVMCI::FieldInfo::klass()->allocate_instance(CHECK_(JVMCIObject())); + Handle obj_h(THREAD, obj); + HotSpotJVMCI::FieldInfo::set_nameIndex(JVMCIENV, obj_h(), (jint)fieldinfo->name_index()); + HotSpotJVMCI::FieldInfo::set_signatureIndex(JVMCIENV, obj_h(), (jint)fieldinfo->signature_index()); + HotSpotJVMCI::FieldInfo::set_offset(JVMCIENV, obj_h(), (jint)fieldinfo->offset()); + HotSpotJVMCI::FieldInfo::set_classfileFlags(JVMCIENV, obj_h(), (jint)fieldinfo->access_flags().as_int()); + HotSpotJVMCI::FieldInfo::set_internalFlags(JVMCIENV, obj_h(), (jint)fieldinfo->field_flags().as_uint()); + HotSpotJVMCI::FieldInfo::set_initializerIndex(JVMCIENV, obj_h(), (jint)fieldinfo->initializer_index()); + return wrap(obj_h()); + } else { + JNIAccessMark jni(this, THREAD); + jobject result = jni()->NewObject(JNIJVMCI::FieldInfo::clazz(), + JNIJVMCI::FieldInfo::constructor(), + (jint)fieldinfo->name_index(), + (jint)fieldinfo->signature_index(), + (jint)fieldinfo->offset(), + (jint)fieldinfo->access_flags().as_int(), + (jint)fieldinfo->field_flags().as_uint(), + (jint)fieldinfo->initializer_index()); + + return wrap(result); + } +} JVMCIObject JVMCIEnv::get_object_constant(oop objOop, bool compressed, bool dont_register) { JavaThread* THREAD = JavaThread::current(); // For exception macros. diff --git a/src/hotspot/share/jvmci/jvmciEnv.hpp b/src/hotspot/share/jvmci/jvmciEnv.hpp index b1bc439c2ba..2fb141525ce 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.hpp +++ b/src/hotspot/share/jvmci/jvmciEnv.hpp @@ -403,6 +403,7 @@ public: JVMCIObject new_VMIntrinsicMethod(JVMCIObject declaringClass, JVMCIObject name, JVMCIObject descriptor, int id, JVMCI_TRAPS); JVMCIObject new_HotSpotStackFrameReference(JVMCI_TRAPS); JVMCIObject new_JVMCIError(JVMCI_TRAPS); + JVMCIObject new_FieldInfo(FieldInfo* fieldinfo, JVMCI_TRAPS); // Makes a handle to a HotSpot heap object. These handles are // individually reclaimed by JVMCIRuntime::destroy_oop_handle and diff --git a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp index 2bbd7da9df8..a2660e316ba 100644 --- a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp +++ b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp @@ -74,7 +74,15 @@ object_field(HotSpotResolvedJavaFieldImpl, type, "Ljdk/vm/ci/meta/JavaType;") \ object_field(HotSpotResolvedJavaFieldImpl, holder, "Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl;") \ int_field(HotSpotResolvedJavaFieldImpl, offset) \ - int_field(HotSpotResolvedJavaFieldImpl, modifiers) \ + end_class \ + start_class(FieldInfo, jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl_FieldInfo) \ + int_field(FieldInfo, nameIndex) \ + int_field(FieldInfo, signatureIndex) \ + int_field(FieldInfo, offset) \ + int_field(FieldInfo, classfileFlags) \ + int_field(FieldInfo, internalFlags) \ + int_field(FieldInfo, initializerIndex) \ + jvmci_constructor(FieldInfo, "(IIIIII)V") \ end_class \ start_class(HotSpotResolvedJavaMethodImpl, jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl) \ long_field(HotSpotResolvedJavaMethodImpl, methodHandle) \ diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 753bcd9fa9f..15276d44d65 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -156,7 +156,7 @@ nonstatic_field(ExceptionTableElement, handler_pc, u2) \ nonstatic_field(ExceptionTableElement, catch_type_index, u2) \ \ - nonstatic_field(InstanceKlass, _fields, Array*) \ + nonstatic_field(InstanceKlass, _fieldinfo_stream, Array*) \ nonstatic_field(InstanceKlass, _constants, ConstantPool*) \ volatile_nonstatic_field(InstanceKlass, _init_state, InstanceKlass::ClassState) \ volatile_nonstatic_field(InstanceKlass, _init_thread, JavaThread*) \ @@ -403,7 +403,6 @@ #define VM_INT_CONSTANTS(declare_constant, declare_constant_with_value, declare_preprocessor_constant) \ declare_preprocessor_constant("ASSERT", DEBUG_ONLY(1) NOT_DEBUG(0)) \ - declare_preprocessor_constant("FIELDINFO_TAG_SIZE", FIELDINFO_TAG_SIZE) \ \ declare_constant(CompLevel_none) \ declare_constant(CompLevel_simple) \ @@ -421,17 +420,15 @@ declare_constant(JVM_ACC_HAS_FINALIZER) \ declare_constant(JVM_ACC_IS_CLONEABLE_FAST) \ declare_constant(JVM_ACC_IS_HIDDEN_CLASS) \ - declare_constant(JVM_ACC_FIELD_INTERNAL) \ - declare_constant(JVM_ACC_FIELD_STABLE) \ - declare_constant(JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE) \ declare_constant(JVM_ACC_IS_VALUE_BASED_CLASS) \ + declare_constant(FieldInfo::FieldFlags::_ff_injected) \ + declare_constant(FieldInfo::FieldFlags::_ff_stable) \ declare_preprocessor_constant("JVM_ACC_VARARGS", JVM_ACC_VARARGS) \ declare_preprocessor_constant("JVM_ACC_BRIDGE", JVM_ACC_BRIDGE) \ declare_preprocessor_constant("JVM_ACC_ANNOTATION", JVM_ACC_ANNOTATION) \ declare_preprocessor_constant("JVM_ACC_ENUM", JVM_ACC_ENUM) \ declare_preprocessor_constant("JVM_ACC_SYNTHETIC", JVM_ACC_SYNTHETIC) \ declare_preprocessor_constant("JVM_ACC_INTERFACE", JVM_ACC_INTERFACE) \ - declare_preprocessor_constant("JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE", JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE) \ \ declare_constant(JVM_CONSTANT_Utf8) \ declare_constant(JVM_CONSTANT_Unicode) \ @@ -645,13 +642,6 @@ declare_constant(Deoptimization::Reason_TRAP_HISTORY_LENGTH) \ declare_constant(Deoptimization::_support_large_access_byte_array_virtualization) \ \ - declare_constant(FieldInfo::access_flags_offset) \ - declare_constant(FieldInfo::name_index_offset) \ - declare_constant(FieldInfo::signature_index_offset) \ - declare_constant(FieldInfo::initval_index_offset) \ - declare_constant(FieldInfo::low_packed_offset) \ - declare_constant(FieldInfo::high_packed_offset) \ - declare_constant(FieldInfo::field_slots) \ \ declare_constant(InstanceKlass::linked) \ declare_constant(InstanceKlass::being_initialized) \ diff --git a/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp b/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp index 6624936d4d8..792db5f18e1 100644 --- a/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp +++ b/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, Oracle and/or its affiliates. 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 @@ -38,6 +38,7 @@ template(jdk_vm_ci_hotspot_HotSpotNmethod, "jdk/vm/ci/hotspot/HotSpotNmethod") \ template(jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl, "jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl") \ template(jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl, "jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl") \ + template(jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl_FieldInfo, "jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl$FieldInfo") \ template(jdk_vm_ci_hotspot_HotSpotResolvedPrimitiveType, "jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType") \ template(jdk_vm_ci_hotspot_HotSpotResolvedJavaFieldImpl, "jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl") \ template(jdk_vm_ci_hotspot_HotSpotCompressedNullConstant, "jdk/vm/ci/hotspot/HotSpotCompressedNullConstant") \ diff --git a/src/hotspot/share/oops/array.hpp b/src/hotspot/share/oops/array.hpp index 68c97e78b58..25dd8cd6beb 100644 --- a/src/hotspot/share/oops/array.hpp +++ b/src/hotspot/share/oops/array.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, Oracle and/or its affiliates. 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 @@ -41,6 +41,7 @@ class Array: public MetaspaceObj { friend class JVMCIVMStructs; friend class MethodHandleCompiler; // special case friend class WhiteBox; + friend class FieldInfoStream; protected: int _length; // the number of array elements T _data[1]; // the array memory diff --git a/src/hotspot/share/oops/fieldInfo.cpp b/src/hotspot/share/oops/fieldInfo.cpp new file mode 100644 index 00000000000..9e7e3260df0 --- /dev/null +++ b/src/hotspot/share/oops/fieldInfo.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "oops/fieldInfo.inline.hpp" +#include "runtime/atomic.hpp" + +void FieldInfo::print(outputStream* os, ConstantPool* cp) { + os->print_cr("index=%d name_index=%d name=%s signature_index=%d signature=%s offset=%d " + "AccessFlags=%d FieldFlags=%d " + "initval_index=%d gen_signature_index=%d, gen_signature=%s contended_group=%d", + index(), + name_index(), name(cp)->as_utf8(), + signature_index(), signature(cp)->as_utf8(), + offset(), + access_flags().as_int(), + field_flags().as_uint(), + initializer_index(), + generic_signature_index(), + _field_flags.is_injected() ? lookup_symbol(generic_signature_index())->as_utf8() : cp->symbol_at(generic_signature_index())->as_utf8(), + contended_group()); +} + +void FieldInfo::print_from_growable_array(outputStream* os, GrowableArray* array, ConstantPool* cp) { + for (int i = 0; i < array->length(); i++) { + array->adr_at(i)->print(os, cp); + } +} + +Array* FieldInfoStream::create_FieldInfoStream(GrowableArray* fields, int java_fields, int injected_fields, + ClassLoaderData* loader_data, TRAPS) { + // The stream format described in fieldInfo.hpp is: + // FieldInfoStream := j=num_java_fields k=num_injected_fields Field[j+k] End + // Field := name sig offset access flags Optionals(flags) + // Optionals(i) := initval?[i&is_init] // ConstantValue attr + // gsig?[i&is_generic] // signature attr + // group?[i&is_contended] // Contended anno (group) + // End = 0 + + using StreamSizer = UNSIGNED5::Sizer<>; + using StreamFieldSizer = Mapper; + StreamSizer s; + StreamFieldSizer sizer(&s); + + sizer.consumer()->accept_uint(java_fields); + sizer.consumer()->accept_uint(injected_fields); + for (int i = 0; i < fields->length(); i++) { + FieldInfo* fi = fields->adr_at(i); + sizer.map_field_info(*fi); + } + int storage_size = sizer.consumer()->position() + 1; + Array* const fis = MetadataFactory::new_array(loader_data, storage_size, CHECK_NULL); + + using StreamWriter = UNSIGNED5::Writer*, int, ArrayHelper*, int>>; + using StreamFieldWriter = Mapper; + StreamWriter w(fis); + StreamFieldWriter writer(&w); + + writer.consumer()->accept_uint(java_fields); + writer.consumer()->accept_uint(injected_fields); + for (int i = 0; i < fields->length(); i++) { + FieldInfo* fi = fields->adr_at(i); + writer.map_field_info(*fi); + } + +#ifdef ASSERT + FieldInfoReader r(fis); + u2 jfc = r.next_uint(); + assert(jfc == java_fields, "Must be"); + int ifc = r.next_uint(); + assert(ifc == injected_fields, "Must be"); + for (int i = 0; i < jfc + ifc; i++) { + FieldInfo fi; + r.read_field_info(fi); + FieldInfo* fi_ref = fields->adr_at(i); + assert(fi_ref->name_index() == fi.name_index(), "Must be"); + assert(fi_ref->signature_index() == fi.signature_index(), "Must be"); + assert(fi_ref->offset() == fi.offset(), "Must be"); + assert(fi_ref->access_flags().as_int() == fi.access_flags().as_int(), "Must be"); + assert(fi_ref->field_flags().as_uint() == fi.field_flags().as_uint(), " Must be"); + if(fi_ref->field_flags().is_initialized()) { + assert(fi_ref->initializer_index() == fi.initializer_index(), "Must be"); + } + if (fi_ref->field_flags().is_generic()) { + assert(fi_ref->generic_signature_index() == fi.generic_signature_index(), "Must be"); + } + if (fi_ref->field_flags().is_contended()) { + assert(fi_ref->contended_group() == fi.contended_group(), "Must be"); + } + } +#endif // ASSERT + + return fis; +} + +GrowableArray* FieldInfoStream::create_FieldInfoArray(const Array* fis, int* java_fields_count, int* injected_fields_count) { + int length = FieldInfoStream::num_total_fields(fis); + GrowableArray* array = new GrowableArray(length); + FieldInfoReader r(fis); + *java_fields_count = r.next_uint(); + *injected_fields_count = r.next_uint(); + while (r.has_next()) { + FieldInfo fi; + r.read_field_info(fi); + array->append(fi); + } + assert(array->length() == length, "Must be"); + assert(array->length() == *java_fields_count + *injected_fields_count, "Must be"); + return array; +} + +void FieldInfoStream::print_from_fieldinfo_stream(Array* fis, outputStream* os, ConstantPool* cp) { + int length = FieldInfoStream::num_total_fields(fis); + FieldInfoReader r(fis); + int java_field_count = r.next_uint(); + int injected_fields_count = r.next_uint(); + while (r.has_next()) { + FieldInfo fi; + r.read_field_info(fi); + fi.print(os, cp); + } +} diff --git a/src/hotspot/share/oops/fieldInfo.hpp b/src/hotspot/share/oops/fieldInfo.hpp index bee2e21213c..d2fd79332a9 100644 --- a/src/hotspot/share/oops/fieldInfo.hpp +++ b/src/hotspot/share/oops/fieldInfo.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, Oracle and/or its affiliates. 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 @@ -25,11 +25,27 @@ #ifndef SHARE_OOPS_FIELDINFO_HPP #define SHARE_OOPS_FIELDINFO_HPP -#include "oops/constantPool.hpp" -#include "oops/symbol.hpp" +#include "memory/allocation.hpp" #include "oops/typeArrayOop.hpp" +#include "utilities/unsigned5.hpp" #include "utilities/vmEnums.hpp" +static constexpr u4 flag_mask(int pos) { + return (u4)1 << pos; +} + + +// Helper class for access to the underlying Array used to +// store the compressed stream of FieldInfo +template +struct ArrayHelper { + uint8_t operator()(ARR a, OFF i) const { return a->at(i); }; + void operator()(ARR a, OFF i, uint8_t b) const { a->at_put(i,b); }; + // So, an expression ArrayWriterHelper() acts like these lambdas: + // auto get = [&](ARR a, OFF i){ return a[i]; }; + // auto set = [&](ARR a, OFF i, uint8_t x){ a[i] = x; }; +}; + // This class represents the field information contained in the fields // array of an InstanceKlass. Currently it's laid on top an array of // Java shorts but in the future it could simply be used as a real @@ -40,135 +56,260 @@ class FieldInfo { friend class fieldDescriptor; friend class JavaFieldStream; friend class ClassFileParser; + friend class FieldInfoStream; + friend class FieldStreamBase; + friend class FieldInfoReader; + friend class VMStructs; public: - // fields - // Field info extracted from the class file and stored - // as an array of 6 shorts. -#define FIELDINFO_TAG_SIZE 2 -#define FIELDINFO_TAG_OFFSET 1 << 0 -#define FIELDINFO_TAG_CONTENDED 1 << 1 + class FieldFlags { + friend class VMStructs; + friend class JVMCIVMStructs; - // Packed field has the tag, and can be either of: - // hi bits <--------------------------- lo bits - // |---------high---------|---------low---------| - // ..........................................CO - // ..........................................00 - non-contended field - // [--contention_group--]....................10 - contended field with contention group - // [------------------offset----------------]01 - real field offset + // The ordering of this enum is totally internal. More frequent + // flags should come earlier than less frequent ones, because + // earlier ones compress better. + enum FieldFlagBitPosition { + _ff_initialized, // has ConstantValue initializer attribute + _ff_injected, // internal field injected by the JVM + _ff_generic, // has a generic signature + _ff_stable, // trust as stable b/c declared as @Stable + _ff_contended, // is contended, may have contention-group + }; - // Bit O indicates if the packed field contains an offset (O=1) or not (O=0) - // Bit C indicates if the field is contended (C=1) or not (C=0) - // (if it is contended, the high packed field contains the contention group) + // Some but not all of the flag bits signal the presence of an + // additional 32-bit item in the field record. + static const u4 _optional_item_bit_mask = + flag_mask((int)_ff_initialized) | + flag_mask((int)_ff_generic) | + flag_mask((int)_ff_contended); - enum FieldOffset { - access_flags_offset = 0, - name_index_offset = 1, - signature_index_offset = 2, - initval_index_offset = 3, - low_packed_offset = 4, - high_packed_offset = 5, - field_slots = 6 + // boilerplate: + u4 _flags; + + bool test_flag(FieldFlagBitPosition pos) const { + return (_flags & flag_mask(pos)) != 0; + } + void update_flag(FieldFlagBitPosition pos, bool z) { + if (z) _flags |= flag_mask(pos); + else _flags &= ~flag_mask(pos); + } + + public: + FieldFlags(u4 flags) { + _flags = flags; + } + u4 as_uint() const { return _flags; } + bool has_any_optionals() const { + return (_flags & _optional_item_bit_mask) != 0; + } + + bool is_initialized() const { return test_flag(_ff_initialized); } + bool is_injected() const { return test_flag(_ff_injected); } + bool is_generic() const { return test_flag(_ff_generic); } + bool is_stable() const { return test_flag(_ff_stable); } + bool is_contended() const { return test_flag(_ff_contended); } + + void update_initialized(bool z) { update_flag(_ff_initialized, z); } + void update_injected(bool z) { update_flag(_ff_injected, z); } + void update_generic(bool z) { update_flag(_ff_generic, z); } + void update_stable(bool z) { update_flag(_ff_stable, z); } + void update_contended(bool z) { update_flag(_ff_contended, z); } }; private: - u2 _shorts[field_slots]; - - 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; } - - 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]; } + // The following items are the unpacked bitwise information content + // of a field record. Per-field metadata extracted from the class + // file are stored logically as a group of these items. The + // classfile parser produces these records in a temporary array, and + // then compresses them into a FieldInfoStream. + // + u4 _index; // which field it is + u2 _name_index; // index in CP of name + u2 _signature_index; // index in CP of descriptor + u4 _offset; // offset in object layout + AccessFlags _access_flags; // access flags (JVM spec) + FieldFlags _field_flags; // VM defined flags (not JVM spec) + u2 _initializer_index; // index from ConstantValue attr (or 0) + u2 _generic_signature_index; // index from GenericSignature attr (or 0) + u2 _contention_group; // index from @Contended group item (or 0) public: - static FieldInfo* from_field_array(Array* fields, int index) { - return ((FieldInfo*)fields->adr_at(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) { - _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[low_packed_offset] = 0; - _shorts[high_packed_offset] = 0; - } + FieldInfo() : _name_index(0), + _signature_index(0), + _offset(0), + _access_flags(AccessFlags(0)), + _field_flags(FieldFlags(0)), + _initializer_index(0), + _generic_signature_index(0), + _contention_group(0) { } - u2 access_flags() const { return _shorts[access_flags_offset]; } - u4 offset() const { - assert((_shorts[low_packed_offset] & FIELDINFO_TAG_OFFSET) != 0, "Offset must have been set"); - return build_int_from_shorts(_shorts[low_packed_offset], _shorts[high_packed_offset]) >> FIELDINFO_TAG_SIZE; - } + FieldInfo(AccessFlags access_flags, u2 name_index, u2 signature_index, u2 initval_index, FieldInfo::FieldFlags fflags) : + _name_index(name_index), + _signature_index(signature_index), + _offset(0), + _access_flags(access_flags), + _field_flags(fflags), + _initializer_index(initval_index), + _generic_signature_index(0), + _contention_group(0) { + if (initval_index != 0) { + _field_flags.update_initialized(true); + } + } + + u4 index() const { return _index; } + void set_index(u4 index) { _index = index; } + u2 name_index() const { return _name_index; } + void set_name_index(u2 index) { _name_index = index; } + u2 signature_index() const { return _signature_index; } + void set_signature_index(u2 index) { _signature_index = index; } + u4 offset() const { return _offset; } + void set_offset(u4 offset) { _offset = offset; } + AccessFlags access_flags() const { return _access_flags; } + FieldFlags field_flags() const { return _field_flags; } + FieldFlags* field_flags_addr() { return &_field_flags; } + u2 initializer_index() const { return _initializer_index; } + void set_initializer_index(u2 index) { _initializer_index = index; } + u2 generic_signature_index() const { return _generic_signature_index; } + void set_generic_signature_index(u2 index) { _generic_signature_index = index; } + u2 contention_group() const { return _contention_group; } bool is_contended() const { - return (_shorts[low_packed_offset] & FIELDINFO_TAG_CONTENDED) != 0; + return _field_flags.is_contended(); } u2 contended_group() const { - assert((_shorts[low_packed_offset] & FIELDINFO_TAG_OFFSET) == 0, "Offset must not have been set"); - assert((_shorts[low_packed_offset] & FIELDINFO_TAG_CONTENDED) != 0, "Field must be contended"); - return _shorts[high_packed_offset]; - } + assert(is_contended(), ""); + return _contention_group; + } + + void set_contended_group(u2 group) { + _field_flags.update_contended(true); + _contention_group = group; + } bool is_offset_set() const { - return (_shorts[low_packed_offset] & FIELDINFO_TAG_OFFSET)!= 0; + return _offset != 0; } - Symbol* name(ConstantPool* cp) const { - int index = name_index(); - if (is_internal()) { - return lookup_symbol(index); - } - return cp->symbol_at(index); - } + inline Symbol* name(ConstantPool* cp) const; - Symbol* signature(ConstantPool* cp) const { - int index = signature_index(); - if (is_internal()) { - return lookup_symbol(index); - } - return cp->symbol_at(index); - } + inline Symbol* signature(ConstantPool* cp) const; - void set_access_flags(u2 val) { _shorts[access_flags_offset] = val; } - void set_offset(u4 val) { - val = val << FIELDINFO_TAG_SIZE; // make room for tag - _shorts[low_packed_offset] = extract_low_short_from_int(val) | FIELDINFO_TAG_OFFSET; - _shorts[high_packed_offset] = extract_high_short_from_int(val); - } + inline Symbol* lookup_symbol(int symbol_index) const; - void set_contended_group(u2 val) { - assert((_shorts[low_packed_offset] & FIELDINFO_TAG_OFFSET) == 0, "Offset must not have been set"); - assert((_shorts[low_packed_offset] & FIELDINFO_TAG_CONTENDED) == 0, "Overwriting contended group"); - _shorts[low_packed_offset] |= FIELDINFO_TAG_CONTENDED; - _shorts[high_packed_offset] = val; - } + void print(outputStream* os, ConstantPool* cp); + void static print_from_growable_array(outputStream* os, GrowableArray* array, ConstantPool* cp); +}; - bool is_internal() const { - return (access_flags() & JVM_ACC_FIELD_INTERNAL) != 0; - } +class FieldInfoStream; - bool is_stable() const { - return (access_flags() & JVM_ACC_FIELD_STABLE) != 0; - } - void set_stable(bool z) { - if (z) _shorts[access_flags_offset] |= JVM_ACC_FIELD_STABLE; - else _shorts[access_flags_offset] &= ~JVM_ACC_FIELD_STABLE; - } +// Gadget for sizing and/or writing a stream of field records. +template +class Mapper { + CON* _consumer; // can be UNSIGNED5::Writer or UNSIGNED5::Sizer + int _next_index; +public: + Mapper(CON* consumer) : _consumer(consumer) { _next_index = 0; } + int next_index() const { return _next_index; } + void set_next_index(int next_index) { _next_index = next_index; } + CON* consumer() const { return _consumer; } + void map_field_info(const FieldInfo& fi); +}; - Symbol* lookup_symbol(int symbol_index) const { - assert(is_internal(), "only internal fields"); - return Symbol::vm_symbol_at(static_cast(symbol_index)); - } + +// Gadget for decoding and reading the stream of field records. +class FieldInfoReader { + friend class FieldInfoStream; + friend class ClassFileParser; + friend class FieldStreamBase; + friend class FieldInfo; + + UNSIGNED5::Reader _r; + int _next_index; + + public: + FieldInfoReader(const Array* fi); + + private: + uint32_t next_uint() { return _r.next_uint(); } + void skip(int n) { int s = _r.try_skip(n); assert(s == n,""); } + +public: + int has_next() { return _r.has_next(); } + int position() { return _r.position(); } + int next_index() { return _next_index; } + void read_field_info(FieldInfo& fi); + // skip a whole field record, both required and optional bits + FieldInfoReader& skip_field_info(); + + // Skip to the nth field. If the reader is freshly initialized to + // the zero index, this will call skip_field_info() n times. + FieldInfoReader& skip_to_field_info(int n); + + // for random access, if you know where to go up front: + FieldInfoReader& set_position_and_next_index(int position, int next_index); +}; + +// The format of the stream, after decompression, is a series of +// integers organized like this: +// +// FieldInfoStream := j=num_java_fields k=num_injected_fields Field[j+k] End +// Field := name sig offset access flags Optionals(flags) +// Optionals(i) := initval?[i&is_init] // ConstantValue attr +// gsig?[i&is_generic] // signature attr +// group?[i&is_contended] // Contended anno (group) +// End = 0 +// +class FieldInfoStream : AllStatic { + friend class fieldDescriptor; + friend class JavaFieldStream; + friend class FieldStreamBase; + friend class ClassFileParser; + + public: + static int num_java_fields(const Array* fis); + static int num_injected_java_fields(const Array* fis); + static int num_total_fields(const Array* fis); + + static Array* create_FieldInfoStream(GrowableArray* fields, int java_fields, int injected_fields, + ClassLoaderData* loader_data, TRAPS); + static GrowableArray* create_FieldInfoArray(const Array* fis, int* java_fields_count, int* injected_fields_count); + static void print_from_fieldinfo_stream(Array* fis, outputStream* os, ConstantPool* cp); +}; + +class FieldStatus { + enum FieldStatusBitPosition { + _fs_access_watched, // field access is watched by JVMTI + _fs_modification_watched, // field modification is watched by JVMTI + _initialized_final_update // (static) final field updated outside (class) initializer + }; + + // boilerplate: + u1 _flags; + static constexpr u1 flag_mask(FieldStatusBitPosition pos) { return (u1)1 << (int)pos; } + bool test_flag(FieldStatusBitPosition pos) { return (_flags & flag_mask(pos)) != 0; } + // this performs an atomic update on a live status byte! + void update_flag(FieldStatusBitPosition pos, bool z); + // out-of-line functions do a CAS-loop + static void atomic_set_bits(u1& flags, u1 mask); + static void atomic_clear_bits(u1& flags, u1 mask); + + public: + FieldStatus() { _flags = 0; } + FieldStatus(u1 flags) { _flags = flags; } + u1 as_uint() { return _flags; } + + bool is_access_watched() { return test_flag(_fs_access_watched); } + bool is_modification_watched() { return test_flag(_fs_modification_watched); } + bool is_initialized_final_update() { return test_flag(_initialized_final_update); } + + void update_access_watched(bool z); + void update_modification_watched(bool z); + void update_initialized_final_update(bool z); }; #endif // SHARE_OOPS_FIELDINFO_HPP diff --git a/src/hotspot/share/oops/fieldInfo.inline.hpp b/src/hotspot/share/oops/fieldInfo.inline.hpp new file mode 100644 index 00000000000..3df343dc1fe --- /dev/null +++ b/src/hotspot/share/oops/fieldInfo.inline.hpp @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_OOPS_FIELDINFO_INLINE_HPP +#define SHARE_OOPS_FIELDINFO_INLINE_HPP + +#include "oops/fieldInfo.hpp" + +#include "memory/metadataFactory.hpp" +#include "oops/constantPool.hpp" +#include "oops/symbol.hpp" + +inline Symbol* FieldInfo::name(ConstantPool* cp) const { + int index = _name_index; + if (_field_flags.is_injected()) { + return lookup_symbol(index); + } + return cp->symbol_at(index); +} + +inline Symbol* FieldInfo::signature(ConstantPool* cp) const { + int index = _signature_index; + if (_field_flags.is_injected()) { + return lookup_symbol(index); + } + return cp->symbol_at(index); +} + +inline Symbol* FieldInfo::lookup_symbol(int symbol_index) const { + assert(_field_flags.is_injected(), "only injected fields"); + return Symbol::vm_symbol_at(static_cast(symbol_index)); +} + +inline int FieldInfoStream::num_injected_java_fields(const Array* fis) { + FieldInfoReader fir(fis); + fir.skip(1); + return fir.next_uint(); +} + +inline int FieldInfoStream::num_total_fields(const Array* fis) { + FieldInfoReader fir(fis); + return fir.next_uint() + fir.next_uint(); +} + +inline int FieldInfoStream::num_java_fields(const Array* fis) { return FieldInfoReader(fis).next_uint(); } + +template +inline void Mapper::map_field_info(const FieldInfo& fi) { + _next_index++; // pre-increment + _consumer->accept_uint(fi.name_index()); + _consumer->accept_uint(fi.signature_index()); + _consumer->accept_uint(fi.offset()); + _consumer->accept_uint(fi.access_flags().as_int()); + _consumer->accept_uint(fi.field_flags().as_uint()); + if(fi.field_flags().has_any_optionals()) { + if (fi.field_flags().is_initialized()) { + _consumer->accept_uint(fi.initializer_index()); + } + if (fi.field_flags().is_generic()) { + _consumer->accept_uint(fi.generic_signature_index()); + } + if (fi.field_flags().is_contended()) { + _consumer->accept_uint(fi.contention_group()); + } + } else { + assert(fi.initializer_index() == 0, ""); + assert(fi.generic_signature_index() == 0, ""); + assert(fi.contention_group() == 0, ""); + } +} + + +inline FieldInfoReader::FieldInfoReader(const Array* fi) + : _r(fi->data(), 0), + _next_index(0) { } + +inline void FieldInfoReader::read_field_info(FieldInfo& fi) { + fi._index = _next_index++; + fi._name_index = next_uint(); + fi._signature_index = next_uint(); + fi._offset = next_uint(); + fi._access_flags = AccessFlags(next_uint()); + fi._field_flags = FieldInfo::FieldFlags(next_uint()); + if (fi._field_flags.is_initialized()) { + fi._initializer_index = next_uint(); + } else { + fi._initializer_index = 0; + } + if (fi._field_flags.is_generic()) { + fi._generic_signature_index = next_uint(); + } else { + fi._generic_signature_index = 0; + } + if (fi._field_flags.is_contended()) { + fi._contention_group = next_uint(); + } else { + fi._contention_group = 0; + } +} + +inline FieldInfoReader& FieldInfoReader::skip_field_info() { + _next_index++; + const int name_sig_af_off = 4; // four items + skip(name_sig_af_off); + FieldInfo::FieldFlags ff(next_uint()); + if (ff.has_any_optionals()) { + const int init_gen_cont = (ff.is_initialized() + + ff.is_generic() + + ff.is_contended()); + skip(init_gen_cont); // up to three items + } + return *this; +} + +// Skip to the nth field. If the reader is freshly initialized to +// the zero index, this will call skip_field_info() n times. +inline FieldInfoReader& FieldInfoReader::skip_to_field_info(int n) { + assert(n >= _next_index, "already past that index"); + const int count = n - _next_index; + for (int i = 0; i < count; i++) skip_field_info(); + assert(_next_index == n, ""); + return *this; +} + +// for random access, if you know where to go up front: +inline FieldInfoReader& FieldInfoReader::set_position_and_next_index(int position, int next_index) { + _r.set_position(position); + _next_index = next_index; + return *this; +} + +inline void FieldStatus::atomic_set_bits(u1& flags, u1 mask) { + // Atomically update the flags with the bits given + u1 old_flags, new_flags, witness; + do { + old_flags = flags; + new_flags = old_flags | mask; + witness = Atomic::cmpxchg(&flags, old_flags, new_flags); + } while (witness != old_flags); +} + +inline void FieldStatus::atomic_clear_bits(u1& flags, u1 mask) { + // Atomically update the flags with the bits given + u1 old_flags, new_flags, witness; + do { + old_flags = flags; + new_flags = old_flags & ~mask; + witness = Atomic::cmpxchg(&flags, old_flags, new_flags); + } while (witness != old_flags); +} + +inline void FieldStatus::update_flag(FieldStatusBitPosition pos, bool z) { + if (z) atomic_set_bits(_flags, flag_mask(pos)); + else atomic_clear_bits(_flags, flag_mask(pos)); +} + +inline void FieldStatus::update_access_watched(bool z) { update_flag(_fs_access_watched, z); } +inline void FieldStatus::update_modification_watched(bool z) { update_flag(_fs_modification_watched, z); } +inline void FieldStatus::update_initialized_final_update(bool z) { update_flag(_initialized_final_update, z); } + +#endif // SHARE_OOPS_FIELDINFO_INLINE_HPP diff --git a/src/hotspot/share/oops/fieldStreams.hpp b/src/hotspot/share/oops/fieldStreams.hpp index c075e11fab6..31f3fa6ca40 100644 --- a/src/hotspot/share/oops/fieldStreams.hpp +++ b/src/hotspot/share/oops/fieldStreams.hpp @@ -39,48 +39,33 @@ // cases. class FieldStreamBase : public StackObj { protected: - Array* _fields; + const Array* _fieldinfo_stream; + FieldInfoReader _reader; constantPoolHandle _constants; int _index; int _limit; - int _generic_signature_slot; + + FieldInfo _fi_buf; fieldDescriptor _fd_buf; - FieldInfo* field() const { return FieldInfo::from_field_array(_fields, _index); } - - int init_generic_signature_start_slot() { - int length = _fields->length(); - int num_fields = _index; - 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; + FieldInfo const * field() const { + assert(!done(), "no more fields"); + return &_fi_buf; } - inline FieldStreamBase(Array* fields, ConstantPool* constants, int start, int limit); + inline FieldStreamBase(const Array* fieldinfo_stream, ConstantPool* constants, int start, int limit); - inline FieldStreamBase(Array* fields, ConstantPool* constants); + inline FieldStreamBase(Array* fieldinfo_stream, ConstantPool* constants); + + private: + void initialize() { + int java_fields_count = _reader.next_uint(); + int injected_fields_count = _reader.next_uint(); + assert( _limit <= java_fields_count + injected_fields_count, "Safety check"); + if (_limit != 0) { + _reader.read_field_info(_fi_buf); + } + } public: inline FieldStreamBase(InstanceKlass* klass); @@ -89,27 +74,19 @@ class FieldStreamBase : public StackObj { InstanceKlass* field_holder() const { return _constants->pool_holder(); } void next() { - if (access_flags().field_has_generic_signature()) { - _generic_signature_slot ++; - assert(_generic_signature_slot <= _fields->length(), ""); - } _index += 1; + if (done()) return; + _reader.read_field_info(_fi_buf); } bool done() const { return _index >= _limit; } // Accessors for current field AccessFlags access_flags() const { - AccessFlags flags; - flags.set_flags(field()->access_flags()); - return flags; + return field()->access_flags(); } - void set_access_flags(u2 flags) const { - field()->set_access_flags(flags); - } - - void set_access_flags(AccessFlags flags) const { - set_access_flags(flags.as_short()); + FieldInfo::FieldFlags field_flags() const { + return field()->field_flags(); } Symbol* name() const { @@ -121,10 +98,8 @@ class FieldStreamBase : public StackObj { } Symbol* generic_signature() const { - if (access_flags().field_has_generic_signature()) { - assert(_generic_signature_slot < _fields->length(), "out of bounds"); - int index = _fields->at(_generic_signature_slot); - return _constants->symbol_at(index); + if (field()->field_flags().is_generic()) { + return _constants->symbol_at(field()->generic_signature_index()); } else { return nullptr; } @@ -134,14 +109,6 @@ class FieldStreamBase : public StackObj { return field()->offset(); } - void set_offset(int offset) { - field()->set_offset(offset); - } - - bool is_offset_set() const { - return field()->is_offset_set(); - } - bool is_contended() const { return field()->is_contended(); } @@ -150,6 +117,16 @@ class FieldStreamBase : public StackObj { return field()->contended_group(); } + // Convenient methods + + FieldInfo to_FieldInfo() { + return _fi_buf; + } + + int num_total_fields() const { + return FieldInfoStream::num_total_fields(_fieldinfo_stream); + } + // bridge to a heavier API: fieldDescriptor& field_descriptor() const { fieldDescriptor& field = const_cast(_fd_buf); @@ -161,47 +138,30 @@ class FieldStreamBase : public StackObj { // Iterate over only the internal fields class JavaFieldStream : public FieldStreamBase { public: - JavaFieldStream(const InstanceKlass* k): FieldStreamBase(k->fields(), k->constants(), 0, k->java_fields_count()) {} + JavaFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants(), 0, k->java_fields_count()) {} int name_index() const { - assert(!field()->is_internal(), "regular only"); + assert(!field()->field_flags().is_injected(), "regular only"); return field()->name_index(); } - void set_name_index(int index) { - assert(!field()->is_internal(), "regular only"); - field()->set_name_index(index); - } + int signature_index() const { - assert(!field()->is_internal(), "regular only"); + assert(!field()->field_flags().is_injected(), "regular only"); return field()->signature_index(); + return -1; } - void set_signature_index(int index) { - assert(!field()->is_internal(), "regular only"); - field()->set_signature_index(index); - } + int generic_signature_index() const { - assert(!field()->is_internal(), "regular only"); - if (access_flags().field_has_generic_signature()) { - assert(_generic_signature_slot < _fields->length(), "out of bounds"); - return _fields->at(_generic_signature_slot); - } else { - return 0; - } - } - void set_generic_signature_index(int index) { - assert(!field()->is_internal(), "regular only"); - if (access_flags().field_has_generic_signature()) { - assert(_generic_signature_slot < _fields->length(), "out of bounds"); - _fields->at_put(_generic_signature_slot, index); + assert(!field()->field_flags().is_injected(), "regular only"); + if (field()->field_flags().is_generic()) { + return field()->generic_signature_index(); } + return 0; } + int initval_index() const { - assert(!field()->is_internal(), "regular only"); - return field()->initval_index(); - } - void set_initval_index(int index) { - assert(!field()->is_internal(), "regular only"); - return field()->set_initval_index(index); + assert(!field()->field_flags().is_injected(), "regular only"); + return field()->initializer_index(); } }; @@ -209,14 +169,14 @@ class JavaFieldStream : public FieldStreamBase { // Iterate over only the internal fields class InternalFieldStream : public FieldStreamBase { public: - InternalFieldStream(InstanceKlass* k): FieldStreamBase(k->fields(), k->constants(), k->java_fields_count(), 0) {} + InternalFieldStream(InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants(), k->java_fields_count(), 0) {} }; class AllFieldStream : public FieldStreamBase { public: - AllFieldStream(Array* fields, ConstantPool* constants): FieldStreamBase(fields, constants) {} - AllFieldStream(InstanceKlass* k): FieldStreamBase(k->fields(), k->constants()) {} + AllFieldStream(Array* fieldinfo, ConstantPool* constants): FieldStreamBase(fieldinfo, constants) {} + AllFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants()) {} }; #endif // SHARE_OOPS_FIELDSTREAMS_HPP diff --git a/src/hotspot/share/oops/fieldStreams.inline.hpp b/src/hotspot/share/oops/fieldStreams.inline.hpp index e71f66c4835..776bcd1671c 100644 --- a/src/hotspot/share/oops/fieldStreams.inline.hpp +++ b/src/hotspot/share/oops/fieldStreams.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. 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 @@ -27,29 +27,39 @@ #include "oops/fieldStreams.hpp" +#include "oops/fieldInfo.hpp" #include "runtime/javaThread.hpp" -FieldStreamBase::FieldStreamBase(Array* fields, ConstantPool* constants, int start, int limit) : _fields(fields), +FieldStreamBase::FieldStreamBase(const Array* fieldinfo_stream, ConstantPool* constants, int start, int limit) : + _fieldinfo_stream(fieldinfo_stream), + _reader(FieldInfoReader(_fieldinfo_stream)), _constants(constantPoolHandle(Thread::current(), constants)), _index(start) { _index = start; - int num_fields = init_generic_signature_start_slot(); if (limit < start) { - _limit = num_fields; + _limit = FieldInfoStream::num_total_fields(_fieldinfo_stream); } else { _limit = limit; } + initialize(); } -FieldStreamBase::FieldStreamBase(Array* fields, ConstantPool* constants) : _fields(fields), - _constants(constantPoolHandle(Thread::current(), constants)), _index(0) { - _limit = init_generic_signature_start_slot(); +FieldStreamBase::FieldStreamBase(Array* fieldinfo_stream, ConstantPool* constants) : + _fieldinfo_stream(fieldinfo_stream), + _reader(FieldInfoReader(_fieldinfo_stream)), + _constants(constantPoolHandle(Thread::current(), constants)), + _index(0), + _limit(FieldInfoStream::num_total_fields(_fieldinfo_stream)) { + initialize(); } -FieldStreamBase::FieldStreamBase(InstanceKlass* klass) : _fields(klass->fields()), - _constants(constantPoolHandle(Thread::current(), klass->constants())), _index(0), - _limit(klass->java_fields_count()) { - init_generic_signature_start_slot(); +FieldStreamBase::FieldStreamBase(InstanceKlass* klass) : + _fieldinfo_stream(klass->fieldinfo_stream()), + _reader(FieldInfoReader(_fieldinfo_stream)), + _constants(constantPoolHandle(Thread::current(), klass->constants())), + _index(0), + _limit(FieldInfoStream::num_total_fields(_fieldinfo_stream)) { assert(klass == field_holder(), ""); + initialize(); } #endif // SHARE_OOPS_FIELDSTREAMS_INLINE_HPP diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 62ae6ffc16a..cea1b2487d9 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -647,10 +647,15 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { set_transitive_interfaces(nullptr); set_local_interfaces(nullptr); - if (fields() != nullptr && !fields()->is_shared()) { - MetadataFactory::free_array(loader_data, fields()); + if (fieldinfo_stream() != nullptr && !fieldinfo_stream()->is_shared()) { + MetadataFactory::free_array(loader_data, fieldinfo_stream()); } - set_fields(nullptr, 0); + set_fieldinfo_stream(nullptr); + + if (fields_status() != nullptr && !fields_status()->is_shared()) { + MetadataFactory::free_array(loader_data, fields_status()); + } + set_fields_status(nullptr); // If a method from a redefined class is using this constant pool, don't // delete it, yet. The new class's previous version will point to this. @@ -1533,6 +1538,16 @@ bool InstanceKlass::contains_field_offset(int offset) { return find_field_from_offset(offset, false, &fd); } +FieldInfo InstanceKlass::field(int index) const { + for (AllFieldStream fs(this); !fs.done(); fs.next()) { + if (fs.index() == index) { + return fs.to_FieldInfo(); + } + } + fatal("Field not found"); + return FieldInfo(); +} + bool InstanceKlass::find_local_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const { for (JavaFieldStream fs(this); !fs.done(); fs.next()) { Symbol* f_name = fs.name(); @@ -2449,8 +2464,9 @@ void InstanceKlass::metaspace_pointers_do(MetaspaceClosure* it) { it->push(&_default_vtable_indices); } - // _fields might be written into by Rewriter::scan_method() -> fd.set_has_initialized_final_update() - it->push(&_fields, MetaspaceClosure::_writable); + it->push(&_fieldinfo_stream); + // _fields_status might be written into by Rewriter::scan_method() -> fd.set_has_initialized_final_update() + it->push(&_fields_status, MetaspaceClosure::_writable); if (itable_length() > 0) { itableOffsetEntry* ioe = (itableOffsetEntry*)start_of_itable(); diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index db61e378921..5fdc77bc8cb 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -28,6 +28,7 @@ #include "memory/referenceType.hpp" #include "oops/annotations.hpp" #include "oops/constMethod.hpp" +#include "oops/constantPool.hpp" #include "oops/fieldInfo.hpp" #include "oops/instanceKlassFlags.hpp" #include "oops/instanceOop.hpp" @@ -219,7 +220,6 @@ class InstanceKlass: public Klass { u2 _nest_host_index; u2 _this_class_index; // constant pool entry u2 _static_oop_field_count; // number of static oop fields in this klass - u2 _java_fields_count; // The number of declared Java fields volatile u2 _idnum_allocated_count; // JNI/JVMTI: increments with the addition of methods, old ids don't change @@ -272,20 +272,9 @@ class InstanceKlass: public Klass { // offset matches _default_methods offset Array* _default_vtable_indices; - // 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] - // ... - Array* _fields; + // Fields information is stored in an UNSIGNED5 encoded stream (see fieldInfo.hpp) + Array* _fieldinfo_stream; + Array* _fields_status; // embedded Java vtable follows here // embedded Java itables follows here @@ -394,23 +383,25 @@ class InstanceKlass: public Klass { private: friend class fieldDescriptor; - FieldInfo* field(int index) const { return FieldInfo::from_field_array(_fields, index); } + FieldInfo field(int index) const; public: - int field_offset (int index) const { return field(index)->offset(); } - int field_access_flags(int index) const { return field(index)->access_flags(); } - Symbol* field_name (int index) const { return field(index)->name(constants()); } - Symbol* field_signature (int index) const { return field(index)->signature(constants()); } + int field_offset (int index) const { return field(index).offset(); } + int field_access_flags(int index) const { return field(index).access_flags().as_int(); } + FieldInfo::FieldFlags field_flags(int index) const { return field(index).field_flags(); } + FieldStatus field_status(int index) const { return fields_status()->at(index); } + inline Symbol* field_name (int index) const; + inline Symbol* field_signature (int index) const; // Number of Java declared fields - int java_fields_count() const { return (int)_java_fields_count; } + int java_fields_count() const; + int total_fields_count() const; - Array* fields() const { return _fields; } - void set_fields(Array* f, u2 java_fields_count) { - guarantee(_fields == nullptr || f == nullptr, "Just checking"); - _fields = f; - _java_fields_count = java_fields_count; - } + Array* fieldinfo_stream() const { return _fieldinfo_stream; } + void set_fieldinfo_stream(Array* fis) { _fieldinfo_stream = fis; } + + Array* fields_status() const {return _fields_status; } + void set_fields_status(Array* array) { _fields_status = array; } // inner classes Array* inner_classes() const { return _inner_classes; } diff --git a/src/hotspot/share/oops/instanceKlass.inline.hpp b/src/hotspot/share/oops/instanceKlass.inline.hpp index e03d1329422..327c74891a5 100644 --- a/src/hotspot/share/oops/instanceKlass.inline.hpp +++ b/src/hotspot/share/oops/instanceKlass.inline.hpp @@ -27,7 +27,11 @@ #include "oops/instanceKlass.hpp" +#include "classfile/javaClasses.hpp" +#include "classfile/vmSymbols.hpp" #include "memory/memRegion.hpp" +#include "memory/resourceArea.hpp" +#include "oops/fieldInfo.inline.hpp" #include "oops/klass.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" @@ -41,6 +45,12 @@ inline int InstanceKlass::itable_offset_in_words() const { return start_of_itabl inline oop InstanceKlass::static_field_base_raw() { return java_mirror(); } +inline Symbol* InstanceKlass::field_name(int index) const { return field(index).name(constants()); } +inline Symbol* InstanceKlass::field_signature(int index) const { return field(index).signature(constants()); } + +inline int InstanceKlass::java_fields_count() const { return FieldInfoStream::num_java_fields(fieldinfo_stream()); } +inline int InstanceKlass::total_fields_count() const { return FieldInfoStream::num_total_fields(fieldinfo_stream()); } + inline OopMapBlock* InstanceKlass::start_of_nonstatic_oop_maps() const { return (OopMapBlock*)(start_of_itable() + itable_length()); } diff --git a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp index 3fbb6e3b2b1..b7e4ff0c057 100644 --- a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp +++ b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp @@ -27,6 +27,7 @@ #include "interpreter/bytecodeStream.hpp" #include "memory/universe.hpp" #include "oops/fieldStreams.inline.hpp" +#include "oops/instanceKlass.inline.hpp" #include "oops/recordComponent.hpp" #include "prims/jvmtiClassFileReconstituter.hpp" #include "runtime/handles.inline.hpp" diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index 38190c42124..b081950e526 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -3547,32 +3547,48 @@ void VM_RedefineClasses::set_new_constant_pool( int i; // for portability // update each field in klass to use new constant pool indices as needed - for (JavaFieldStream fs(scratch_class); !fs.done(); fs.next()) { - jshort cur_index = fs.name_index(); + int java_fields; + int injected_fields; + bool update_required = false; + GrowableArray* fields = FieldInfoStream::create_FieldInfoArray(scratch_class->fieldinfo_stream(), &java_fields, &injected_fields); + for (int i = 0; i < java_fields; i++) { + FieldInfo* fi = fields->adr_at(i); + jshort cur_index = fi->name_index(); jshort new_index = find_new_index(cur_index); if (new_index != 0) { log_trace(redefine, class, constantpool)("field-name_index change: %d to %d", cur_index, new_index); - fs.set_name_index(new_index); + fi->set_name_index(new_index); + update_required = true; } - cur_index = fs.signature_index(); + cur_index = fi->signature_index(); new_index = find_new_index(cur_index); if (new_index != 0) { log_trace(redefine, class, constantpool)("field-signature_index change: %d to %d", cur_index, new_index); - fs.set_signature_index(new_index); + fi->set_signature_index(new_index); + update_required = true; } - cur_index = fs.initval_index(); + cur_index = fi->initializer_index(); new_index = find_new_index(cur_index); if (new_index != 0) { log_trace(redefine, class, constantpool)("field-initval_index change: %d to %d", cur_index, new_index); - fs.set_initval_index(new_index); + fi->set_initializer_index(new_index); + update_required = true; } - cur_index = fs.generic_signature_index(); + cur_index = fi->generic_signature_index(); new_index = find_new_index(cur_index); if (new_index != 0) { log_trace(redefine, class, constantpool)("field-generic_signature change: %d to %d", cur_index, new_index); - fs.set_generic_signature_index(new_index); + fi->set_generic_signature_index(new_index); + update_required = true; } - } // end for each field + } + if (update_required) { + Array* old_stream = scratch_class->fieldinfo_stream(); + assert(fields->length() == (java_fields + injected_fields), "Must be"); + Array* new_fis = FieldInfoStream::create_FieldInfoStream(fields, java_fields, injected_fields, scratch_class->class_loader_data(), CHECK); + scratch_class->set_fieldinfo_stream(new_fis); + MetadataFactory::free_array(scratch_class->class_loader_data(), old_stream); + } // Update constant pool indices in the inner classes info to use // new constant indices as needed. The inner classes info is a diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 8348556f795..4d5bf7b423e 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1437,7 +1437,7 @@ static int reassign_fields_by_klass(InstanceKlass* klass, frame* fr, RegisterMap InstanceKlass* ik = klass; while (ik != nullptr) { for (AllFieldStream fs(ik); !fs.done(); fs.next()) { - if (!fs.access_flags().is_static() && (!skip_internal || !fs.access_flags().is_internal())) { + if (!fs.access_flags().is_static() && (!skip_internal || !fs.field_flags().is_injected())) { ReassignedField field; field._offset = fs.offset(); field._type = Signature::basic_type(fs.signature()); diff --git a/src/hotspot/share/runtime/fieldDescriptor.cpp b/src/hotspot/share/runtime/fieldDescriptor.cpp index d5efb6ea358..c2e063e8759 100644 --- a/src/hotspot/share/runtime/fieldDescriptor.cpp +++ b/src/hotspot/share/runtime/fieldDescriptor.cpp @@ -39,18 +39,7 @@ Symbol* fieldDescriptor::generic_signature() const { if (!has_generic_signature()) { return nullptr; } - - int idx = 0; - InstanceKlass* ik = 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 vmSymbols::void_signature(); // return a default value (for code analyzers) + return _cp->symbol_at(_fieldinfo.generic_signature_index()); } bool fieldDescriptor::is_trusted_final() const { @@ -106,30 +95,14 @@ void fieldDescriptor::reinitialize(InstanceKlass* ik, int index) { // but that's ok because of constant pool merging. assert(field_holder() == ik || ik->is_scratch_class(), "must be already initialized to this class"); } - FieldInfo* f = ik->field(index); - _access_flags = accessFlags_from(f->access_flags()); - guarantee(f->name_index() != 0 && f->signature_index() != 0, "bad constant pool index for fieldDescriptor"); - _index = index; - verify(); + _fieldinfo= ik->field(index); + assert((int)_fieldinfo.index() == index, "just checking"); + guarantee(_fieldinfo.name_index() != 0 && _fieldinfo.signature_index() != 0, "bad constant pool index for fieldDescriptor"); } -#ifndef PRODUCT - -void fieldDescriptor::verify() const { - if (_cp.is_null()) { - assert(_index == badInt, "constructor must be called"); // see constructor - } else { - assert(_index >= 0, "good index"); - assert(access_flags().is_internal() || - _index < field_holder()->java_fields_count(), "oob"); - } -} - -#endif /* PRODUCT */ - void fieldDescriptor::print_on(outputStream* st) const { access_flags().print_on(st); - if (access_flags().is_internal()) st->print("internal "); + if (field_flags().is_injected()) st->print("injected "); name()->print_value_on(st); st->print(" "); signature()->print_value_on(st); diff --git a/src/hotspot/share/runtime/fieldDescriptor.hpp b/src/hotspot/share/runtime/fieldDescriptor.hpp index 6bdbec2dd3e..1f7fdbe390a 100644 --- a/src/hotspot/share/runtime/fieldDescriptor.hpp +++ b/src/hotspot/share/runtime/fieldDescriptor.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. 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 @@ -38,33 +38,29 @@ class fieldDescriptor { private: - AccessFlags _access_flags; - int _index; // the field index + FieldInfo _fieldinfo; constantPoolHandle _cp; - // update the access_flags for the field in the klass - inline void update_klass_field_access_flag(); - - inline FieldInfo* field() const; + inline FieldInfo field() const { return _fieldinfo; }; public: - fieldDescriptor() { - DEBUG_ONLY(_index = badInt); - } + fieldDescriptor() {} fieldDescriptor(InstanceKlass* ik, int index) { - DEBUG_ONLY(_index = badInt); reinitialize(ik, index); } inline Symbol* name() const; inline Symbol* signature() const; - inline InstanceKlass* field_holder() const; + inline InstanceKlass* field_holder() const {return _cp->pool_holder(); }; inline ConstantPool* constants() const; - AccessFlags access_flags() const { return _access_flags; } + AccessFlags access_flags() const { return _fieldinfo.access_flags(); } + FieldInfo::FieldFlags field_flags() const { return _fieldinfo.field_flags(); } + FieldStatus field_status() const { return field_holder()->fields_status()->at(_fieldinfo.index()); } + oop loader() const; // Offset (in bytes) of field from start of instanceOop / Klass* inline int offset() const; Symbol* generic_signature() const; - int index() const { return _index; } + int index() const { return _fieldinfo.index(); } AnnotationArray* annotations() const; AnnotationArray* type_annotations() const; @@ -87,15 +83,17 @@ class fieldDescriptor { bool is_static() const { return access_flags().is_static(); } bool is_final() const { return access_flags().is_final(); } - bool is_stable() const { return access_flags().is_stable(); } + bool is_stable() const { return field_flags().is_stable(); } + bool is_volatile() const { return access_flags().is_volatile(); } + bool is_transient() const { return access_flags().is_transient(); } bool is_synthetic() const { return access_flags().is_synthetic(); } - bool is_field_access_watched() const { return access_flags().is_field_access_watched(); } + bool is_field_access_watched() const { return field_status().is_access_watched(); } bool is_field_modification_watched() const - { return access_flags().is_field_modification_watched(); } - bool has_initialized_final_update() const { return access_flags().has_field_initialized_final_update(); } - bool has_generic_signature() const { return access_flags().field_has_generic_signature(); } + { return field_status().is_modification_watched(); } + bool has_initialized_final_update() const { return field_status().is_initialized_final_update(); } + bool has_generic_signature() const { return field_flags().is_generic(); } bool is_trusted_final() const; @@ -110,7 +108,6 @@ class fieldDescriptor { void print() const; void print_on(outputStream* st) const; void print_on_for(outputStream* st, oop obj); - void verify() const PRODUCT_RETURN; }; #endif // SHARE_RUNTIME_FIELDDESCRIPTOR_HPP diff --git a/src/hotspot/share/runtime/fieldDescriptor.inline.hpp b/src/hotspot/share/runtime/fieldDescriptor.inline.hpp index de3ad851f3c..6d6290f0fa1 100644 --- a/src/hotspot/share/runtime/fieldDescriptor.inline.hpp +++ b/src/hotspot/share/runtime/fieldDescriptor.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023, Oracle and/or its affiliates. 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 @@ -27,6 +27,7 @@ #include "runtime/fieldDescriptor.hpp" +#include "oops/fieldInfo.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/signature.hpp" @@ -34,48 +35,31 @@ // must be put in this file, as they require runtime/handles.inline.hpp. inline Symbol* fieldDescriptor::name() const { - return field()->name(_cp()); + return field().name(_cp()); } inline Symbol* fieldDescriptor::signature() const { - return field()->signature(_cp()); -} - -inline InstanceKlass* fieldDescriptor::field_holder() const { - return _cp->pool_holder(); + return field().signature(_cp()); } inline ConstantPool* fieldDescriptor::constants() const { return _cp(); } -inline FieldInfo* fieldDescriptor::field() const { - InstanceKlass* ik = field_holder(); - return ik->field(_index); -} - -inline int fieldDescriptor::offset() const { return field()->offset(); } -inline bool fieldDescriptor::has_initial_value() const { return field()->initval_index() != 0; } -inline int fieldDescriptor::initial_value_index() const { return field()->initval_index(); } - -inline void fieldDescriptor::update_klass_field_access_flag() { - InstanceKlass* ik = field_holder(); - ik->field(index())->set_access_flags(_access_flags.as_short()); -} +inline int fieldDescriptor::offset() const { return field().offset(); } +inline bool fieldDescriptor::has_initial_value() const { return field().field_flags().is_initialized(); } +inline int fieldDescriptor::initial_value_index() const { return field().initializer_index(); } inline void fieldDescriptor::set_is_field_access_watched(const bool value) { - _access_flags.set_is_field_access_watched(value); - update_klass_field_access_flag(); + field_holder()->fields_status()->adr_at(index())->update_access_watched(value); } inline void fieldDescriptor::set_is_field_modification_watched(const bool value) { - _access_flags.set_is_field_modification_watched(value); - update_klass_field_access_flag(); + field_holder()->fields_status()->adr_at(index())->update_modification_watched(value); } inline void fieldDescriptor::set_has_initialized_final_update(const bool value) { - _access_flags.set_has_field_initialized_final_update(value); - update_klass_field_access_flag(); + field_holder()->fields_status()->adr_at(index())->update_initialized_final_update(value); } inline BasicType fieldDescriptor::field_type() const { diff --git a/src/hotspot/share/runtime/reflectionUtils.cpp b/src/hotspot/share/runtime/reflectionUtils.cpp index 16b3ca77315..ae33c1ba77a 100644 --- a/src/hotspot/share/runtime/reflectionUtils.cpp +++ b/src/hotspot/share/runtime/reflectionUtils.cpp @@ -26,6 +26,7 @@ #include "classfile/javaClasses.hpp" #include "classfile/vmClasses.hpp" #include "memory/universe.hpp" +#include "oops/instanceKlass.inline.hpp" #include "runtime/reflectionUtils.hpp" KlassStream::KlassStream(InstanceKlass* klass, bool local_only, @@ -68,6 +69,7 @@ bool KlassStream::eos() { return eos(); } +int FieldStream::length() { return _klass->java_fields_count(); } GrowableArray *FilteredFieldsMap::_filtered_fields = new (mtServiceability) GrowableArray(3, mtServiceability); diff --git a/src/hotspot/share/runtime/reflectionUtils.hpp b/src/hotspot/share/runtime/reflectionUtils.hpp index c534e361ddf..04ff68c4271 100644 --- a/src/hotspot/share/runtime/reflectionUtils.hpp +++ b/src/hotspot/share/runtime/reflectionUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. 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 @@ -120,7 +120,7 @@ class MethodStream : public KlassStream { class FieldStream : public KlassStream { private: - int length() { return _klass->java_fields_count(); } + int length(); fieldDescriptor _fd_buf; diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 96623646ac9..28928a2120f 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -66,6 +66,7 @@ #include "oops/constMethod.hpp" #include "oops/constantPool.hpp" #include "oops/cpCache.hpp" +#include "oops/fieldInfo.hpp" #include "oops/instanceClassLoaderKlass.hpp" #include "oops/instanceKlass.hpp" #include "oops/instanceMirrorKlass.hpp" @@ -225,8 +226,7 @@ nonstatic_field(InstanceKlass, _default_methods, Array*) \ nonstatic_field(InstanceKlass, _local_interfaces, Array*) \ nonstatic_field(InstanceKlass, _transitive_interfaces, Array*) \ - nonstatic_field(InstanceKlass, _fields, Array*) \ - nonstatic_field(InstanceKlass, _java_fields_count, u2) \ + nonstatic_field(InstanceKlass, _fieldinfo_stream, Array*) \ nonstatic_field(InstanceKlass, _constants, ConstantPool*) \ nonstatic_field(InstanceKlass, _source_debug_extension, const char*) \ nonstatic_field(InstanceKlass, _inner_classes, Array*) \ @@ -2092,11 +2092,6 @@ declare_constant(JVM_ACC_HAS_FINALIZER) \ declare_constant(JVM_ACC_IS_CLONEABLE_FAST) \ declare_constant(JVM_ACC_HAS_LOCAL_VARIABLE_TABLE) \ - declare_constant(JVM_ACC_FIELD_ACCESS_WATCHED) \ - declare_constant(JVM_ACC_FIELD_MODIFICATION_WATCHED) \ - declare_constant(JVM_ACC_FIELD_INTERNAL) \ - declare_constant(JVM_ACC_FIELD_STABLE) \ - declare_constant(JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE) \ \ declare_constant(JVM_CONSTANT_Utf8) \ declare_constant(JVM_CONSTANT_Unicode) \ @@ -2228,24 +2223,6 @@ /*************************************/ \ \ \ - /*************************************/ \ - /* FieldInfo FieldOffset enum */ \ - /*************************************/ \ - \ - declare_constant(FieldInfo::access_flags_offset) \ - declare_constant(FieldInfo::name_index_offset) \ - declare_constant(FieldInfo::signature_index_offset) \ - declare_constant(FieldInfo::initval_index_offset) \ - declare_constant(FieldInfo::low_packed_offset) \ - declare_constant(FieldInfo::high_packed_offset) \ - declare_constant(FieldInfo::field_slots) \ - \ - /*************************************/ \ - /* FieldInfo tag constants */ \ - /*************************************/ \ - \ - declare_preprocessor_constant("FIELDINFO_TAG_SIZE", FIELDINFO_TAG_SIZE) \ - declare_preprocessor_constant("FIELDINFO_TAG_OFFSET", FIELDINFO_TAG_OFFSET) \ \ /************************************************/ \ /* InstanceKlass InnerClassAttributeOffset enum */ \ @@ -2315,6 +2292,17 @@ declare_constant(JavaThreadStatus::BLOCKED_ON_MONITOR_ENTER) \ declare_constant(JavaThreadStatus::TERMINATED) \ \ + \ + /******************************/ \ + /* FieldFlags enum */ \ + /******************************/ \ + \ + declare_constant(FieldInfo::FieldFlags::_ff_initialized) \ + declare_constant(FieldInfo::FieldFlags::_ff_injected) \ + declare_constant(FieldInfo::FieldFlags::_ff_generic) \ + declare_constant(FieldInfo::FieldFlags::_ff_stable) \ + declare_constant(FieldInfo::FieldFlags::_ff_contended) \ + \ /******************************/ \ /* Debug info */ \ /******************************/ \ diff --git a/src/hotspot/share/utilities/accessFlags.hpp b/src/hotspot/share/utilities/accessFlags.hpp index b7814b0d96c..901be7964e4 100644 --- a/src/hotspot/share/utilities/accessFlags.hpp +++ b/src/hotspot/share/utilities/accessFlags.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. 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 @@ -74,30 +74,6 @@ enum { // Method* flags JVM_ACC_HAS_LOCAL_VARIABLE_TABLE= 0x00400000, - - // field flags - // Note: these flags must be defined in the low order 16 bits because - // InstanceKlass only stores a ushort worth of information from the - // AccessFlags value. - // These bits must not conflict with any other field-related access flags - // (e.g., ACC_ENUM). - // Note that the class-related ACC_ANNOTATION bit conflicts with these flags. - 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_STABLE = 0x00000020, // @Stable field, same as JVM_ACC_SYNCHRONIZED and JVM_ACC_SUPER - JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE = 0x00000100, // (static) final field updated outside (class) initializer, same as JVM_ACC_NATIVE - 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_STABLE | - 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 - }; @@ -166,25 +142,15 @@ class AccessFlags { bool has_resolved_methods() const { return (_flags & JVM_ACC_HAS_RESOLVED_METHODS) != 0; } void set_has_resolved_methods() { atomic_set_bits(JVM_ACC_HAS_RESOLVED_METHODS); } - // field flags - bool is_field_access_watched() const { return (_flags & JVM_ACC_FIELD_ACCESS_WATCHED) != 0; } - bool is_field_modification_watched() const - { return (_flags & JVM_ACC_FIELD_MODIFICATION_WATCHED) != 0; } - bool has_field_initialized_final_update() const - { return (_flags & JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE) != 0; } bool on_stack() const { return (_flags & JVM_ACC_ON_STACK) != 0; } - bool is_internal() const { return (_flags & JVM_ACC_FIELD_INTERNAL) != 0; } - bool is_stable() const { return (_flags & JVM_ACC_FIELD_STABLE) != 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); } // Initialization void set_field_flags(jint flags) { - assert((flags & JVM_ACC_FIELD_FLAGS) == flags, "only recognized flags"); - _flags = (flags & JVM_ACC_FIELD_FLAGS); + assert((flags & JVM_RECOGNIZED_FIELD_MODIFIERS) == flags, "only recognized flags"); + _flags = (flags & JVM_RECOGNIZED_FIELD_MODIFIERS); } void set_flags(jint flags) { _flags = (flags & JVM_ACC_WRITTEN_FLAGS); } @@ -235,37 +201,6 @@ class AccessFlags { void set_is_value_based_class() { atomic_set_bits(JVM_ACC_IS_VALUE_BASED_CLASS); } public: - // field flags - void set_is_field_access_watched(const bool value) - { - if (value) { - atomic_set_bits(JVM_ACC_FIELD_ACCESS_WATCHED); - } else { - atomic_clear_bits(JVM_ACC_FIELD_ACCESS_WATCHED); - } - } - void set_is_field_modification_watched(const bool value) - { - if (value) { - atomic_set_bits(JVM_ACC_FIELD_MODIFICATION_WATCHED); - } else { - atomic_clear_bits(JVM_ACC_FIELD_MODIFICATION_WATCHED); - } - } - - void set_has_field_initialized_final_update(const bool value) { - if (value) { - atomic_set_bits(JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE); - } else { - atomic_clear_bits(JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE); - } - } - - void set_field_has_generic_signature() - { - atomic_set_bits(JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE); - } - void set_on_stack(const bool value) { if (value) { diff --git a/src/hotspot/share/utilities/unsigned5.hpp b/src/hotspot/share/utilities/unsigned5.hpp index 59803bc4437..01b55ed8ade 100644 --- a/src/hotspot/share/utilities/unsigned5.hpp +++ b/src/hotspot/share/utilities/unsigned5.hpp @@ -258,8 +258,8 @@ class UNSIGNED5 : AllStatic { // MyReader r(array); while (r.has_next()) print(r.next_uint()); template> class Reader { - const ARR _array; - const OFF _limit; + ARR _array; + OFF _limit; OFF _position; int next_length() { return UNSIGNED5::check_length(_array, _position, _limit, GET()); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/AccessFlags.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/AccessFlags.java index 3116c8537f5..917515c2a0d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/AccessFlags.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/AccessFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, Oracle and/or its affiliates. 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 @@ -78,11 +78,6 @@ public class AccessFlags implements /* imports */ ClassConstants { // Klass* and Method* flags public boolean hasLocalVariableTable() { return (flags & JVM_ACC_HAS_LOCAL_VARIABLE_TABLE ) != 0; } - // 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 if (isPublic ()) tty.print("public " ); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java index be41165b61a..ebf571c7b0f 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, Oracle and/or its affiliates. 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 @@ -26,6 +26,7 @@ package sun.jvm.hotspot.oops; import java.io.*; +import sun.jvm.hotspot.code.CompressedReadStream; import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.utilities.*; @@ -40,23 +41,85 @@ public class Field { /** Constructor for fields that are named in an InstanceKlass's fields array (i.e., named, non-VM fields) */ - Field(InstanceKlass holder, int fieldIndex) { + private Field(InstanceKlass holder, int fieldIndex, FieldInfoValues values) { this.holder = holder; this.fieldIndex = fieldIndex; + this.values = values; + offset = values.offset; - offset = holder.getFieldOffset(fieldIndex); - genericSignature = holder.getFieldGenericSignature(fieldIndex); - - name = holder.getFieldName(fieldIndex); + name = holder.getSymbolFromIndex(values.nameIndex, isInjected()); + signature = holder.getSymbolFromIndex(values.signatureIndex, isInjected()); id = new NamedFieldIdentifier(name.asString()); - - signature = holder.getFieldSignature(fieldIndex); fieldType = new FieldType(signature); + accessFlags = new AccessFlags(values.accessFlags); - short access = holder.getFieldAccessFlags(fieldIndex); - accessFlags = new AccessFlags(access); + if (isGeneric()) { + genericSignature = holder.getSymbolFromIndex(values.genericSignatureIndex, isInjected()); + } } + /** Constructor for cloning an existing Field object */ + Field(InstanceKlass holder, int fieldIndex) { + this(holder, fieldIndex, holder.getField(fieldIndex).values); + } + + + static class FieldInfoValues { + int nameIndex; + int signatureIndex; + int offset; + int accessFlags; + int fieldFlags; + int initialValueIndex; + int genericSignatureIndex; + int contendedGroup; + } + + // The format of the stream, after decompression, is a series of + // integers organized like this: + // + // FieldInfoStream := j=num_java_fields k=num_injected_fields Field[j+k] End + // Field := name sig offset access flags Optionals(flags) + // Optionals(i) := initval?[i&is_init] // ConstantValue attr + // gsig?[i&is_generic] // signature attr + // group?[i&is_contended] // Contended anno (group) + // End = 0 + // + + static FieldInfoValues readFieldInfoValues(CompressedReadStream crs) { + FieldInfoValues fieldInfoValues = new FieldInfoValues(); + fieldInfoValues.nameIndex = crs.readInt(); // read name_index + fieldInfoValues.signatureIndex = crs.readInt(); // read signature index + fieldInfoValues.offset = crs.readInt(); // read offset + fieldInfoValues.accessFlags = crs.readInt(); // read access flags + fieldInfoValues.fieldFlags = crs.readInt(); // read field flags + // Optional reads: + if (fieldIsInitialized(fieldInfoValues.fieldFlags)) { + fieldInfoValues.initialValueIndex = crs.readInt(); // read initial value index + } + if (fieldIsGeneric(fieldInfoValues.fieldFlags)) { + fieldInfoValues.genericSignatureIndex = crs.readInt(); // read generic signature index + } + if (fieldIsContended(fieldInfoValues.fieldFlags)) { + fieldInfoValues.contendedGroup = crs.readInt(); // read contended group + } + return fieldInfoValues; + } + + public static Field[] getFields(InstanceKlass kls) { + CompressedReadStream crs = new CompressedReadStream(kls.getFieldInfoStream().getDataStart()); + int numJavaFields = crs.readInt(); // read num_java_fields + int numInjectedFields = crs.readInt(); // read num_injected_fields; + int numFields = numJavaFields + numInjectedFields; + Field[] fields = new Field[numFields]; + for (int i = 0; i < numFields; i++) { + FieldInfoValues values = readFieldInfoValues(crs); + fields[i] = new Field(kls, i, values); + } + return fields; + } + + FieldInfoValues values; private Symbol name; private long offset; private FieldIdentifier id; @@ -76,6 +139,7 @@ public class Field { public FieldIdentifier getID() { return id; } public Symbol getName() { return name; } + public int getNameIndex() { return values.nameIndex; } /** Indicates whether this is a VM field */ public boolean isVMField() { return isVMField; } @@ -111,9 +175,12 @@ public class Field { /** (Named, non-VM fields only) Returns the signature of this field. */ public Symbol getSignature() { return signature; } + public int getSignatureIndex() { return values.signatureIndex; } public Symbol getGenericSignature() { return genericSignature; } + public int getGenericSignatureIndex() { return values.genericSignatureIndex; } public boolean hasInitialValue() { return holder.getFieldInitialValueIndex(fieldIndex) != 0; } + public int getInitialValueIndex() { return values.initialValueIndex; } // // Following accessors are for named, non-VM fields only @@ -131,6 +198,19 @@ public class Field { public boolean isSynthetic() { return accessFlags.isSynthetic(); } public boolean isEnumConstant() { return accessFlags.isEnum(); } + private static boolean fieldIsInitialized(int flags) { return ((flags >> InstanceKlass.FIELD_FLAG_IS_INITIALIZED) & 1 ) != 0; } + private static boolean fieldIsInjected(int flags) { return ((flags >> InstanceKlass.FIELD_FLAG_IS_INJECTED ) & 1 ) != 0; } + private static boolean fieldIsGeneric(int flags) { return ((flags >> InstanceKlass.FIELD_FLAG_IS_GENERIC ) & 1 ) != 0; } + private static boolean fieldIsStable(int flags) { return ((flags >> InstanceKlass.FIELD_FLAG_IS_STABLE ) & 1 ) != 0; } + private static boolean fieldIsContended(int flags) { return ((flags >> InstanceKlass.FIELD_FLAG_IS_CONTENDED ) & 1 ) != 0; } + + + public boolean isInitialized() { return fieldIsInitialized(values.fieldFlags); } + public boolean isInjected() { return fieldIsInjected(values.fieldFlags); } + public boolean isGeneric() { return fieldIsGeneric(values.fieldFlags); } + public boolean isStable() { return fieldIsStable(values.fieldFlags); } + public boolean isContended() { return fieldIsContended(values.fieldFlags); } + public boolean equals(Object obj) { if (obj == null) { return false; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java index 4944c85aa2c..2648ebfc36e 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, Oracle and/or its affiliates. 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 @@ -27,6 +27,7 @@ package sun.jvm.hotspot.oops; import java.io.*; import java.util.*; import sun.jvm.hotspot.classfile.ClassLoaderData; +import sun.jvm.hotspot.code.CompressedReadStream; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.memory.*; import sun.jvm.hotspot.runtime.*; @@ -46,16 +47,12 @@ public class InstanceKlass extends Klass { }); } - // field offset constants - private static int ACCESS_FLAGS_OFFSET; - private static int NAME_INDEX_OFFSET; - private static int SIGNATURE_INDEX_OFFSET; - private static int INITVAL_INDEX_OFFSET; - private static int LOW_OFFSET; - private static int HIGH_OFFSET; - private static int FIELD_SLOTS; - private static short FIELDINFO_TAG_SIZE; - private static short FIELDINFO_TAG_OFFSET; + // internal field flags constants + static int FIELD_FLAG_IS_INITIALIZED; + static int FIELD_FLAG_IS_INJECTED; + static int FIELD_FLAG_IS_GENERIC; + static int FIELD_FLAG_IS_STABLE; + static int FIELD_FLAG_IS_CONTENDED; // ClassState constants private static int CLASS_STATE_ALLOCATED; @@ -75,8 +72,7 @@ public class InstanceKlass extends Klass { methodOrdering = type.getAddressField("_method_ordering"); localInterfaces = type.getAddressField("_local_interfaces"); transitiveInterfaces = type.getAddressField("_transitive_interfaces"); - fields = type.getAddressField("_fields"); - javaFieldsCount = new CIntField(type.getCIntegerField("_java_fields_count"), 0); + fieldinfoStream = type.getAddressField("_fieldinfo_stream"); constants = new MetadataField(type.getAddressField("_constants"), 0); sourceDebugExtension = type.getAddressField("_source_debug_extension"); innerClasses = type.getAddressField("_inner_classes"); @@ -92,16 +88,13 @@ public class InstanceKlass extends Klass { } headerSize = type.getSize(); - // read field offset constants - ACCESS_FLAGS_OFFSET = db.lookupIntConstant("FieldInfo::access_flags_offset").intValue(); - NAME_INDEX_OFFSET = db.lookupIntConstant("FieldInfo::name_index_offset").intValue(); - SIGNATURE_INDEX_OFFSET = db.lookupIntConstant("FieldInfo::signature_index_offset").intValue(); - INITVAL_INDEX_OFFSET = db.lookupIntConstant("FieldInfo::initval_index_offset").intValue(); - LOW_OFFSET = db.lookupIntConstant("FieldInfo::low_packed_offset").intValue(); - HIGH_OFFSET = db.lookupIntConstant("FieldInfo::high_packed_offset").intValue(); - FIELD_SLOTS = db.lookupIntConstant("FieldInfo::field_slots").intValue(); - FIELDINFO_TAG_SIZE = db.lookupIntConstant("FIELDINFO_TAG_SIZE").shortValue(); - FIELDINFO_TAG_OFFSET = db.lookupIntConstant("FIELDINFO_TAG_OFFSET").shortValue(); + // read internal field flags constants + FIELD_FLAG_IS_INITIALIZED = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_initialized"); + FIELD_FLAG_IS_INJECTED = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_injected"); + FIELD_FLAG_IS_GENERIC = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_generic"); + FIELD_FLAG_IS_STABLE = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_stable"); + FIELD_FLAG_IS_CONTENDED = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_contended"); + // read ClassState constants CLASS_STATE_ALLOCATED = db.lookupIntConstant("InstanceKlass::allocated").intValue(); @@ -111,6 +104,8 @@ public class InstanceKlass extends Klass { CLASS_STATE_BEING_INITIALIZED = db.lookupIntConstant("InstanceKlass::being_initialized").intValue(); CLASS_STATE_FULLY_INITIALIZED = db.lookupIntConstant("InstanceKlass::fully_initialized").intValue(); CLASS_STATE_INITIALIZATION_ERROR = db.lookupIntConstant("InstanceKlass::initialization_error").intValue(); + // We need a new fieldsCache each time we attach. + fieldsCache = new WeakHashMap(); } public InstanceKlass(Address addr) { @@ -142,8 +137,7 @@ public class InstanceKlass extends Klass { private static AddressField methodOrdering; private static AddressField localInterfaces; private static AddressField transitiveInterfaces; - private static AddressField fields; - private static CIntField javaFieldsCount; + private static AddressField fieldinfoStream; private static MetadataField constants; private static AddressField sourceDebugExtension; private static AddressField innerClasses; @@ -264,81 +258,71 @@ public class InstanceKlass extends Klass { public static long getHeaderSize() { return headerSize; } - public short getFieldAccessFlags(int index) { - return getFields().at(index * FIELD_SLOTS + ACCESS_FLAGS_OFFSET); + // Each InstanceKlass mirror instance will cache the Field[] array after it is decoded, + // but since there can be multiple InstanceKlass mirror instances per hotspot InstanceKlass, + // we also have a global cache that uses the Address of the hotspot InstanceKlass as the key. + private Field[] fields; + private static Map fieldsCache; + + Field getField(int index) { + synchronized (this) { + fields = fieldsCache.get(this.getAddress()); + if (fields == null) { + fields = Field.getFields(this); + fieldsCache.put(this.getAddress(), fields); + } else { + } + } + return fields[index]; } - public short getFieldNameIndex(int index) { + public short getFieldAccessFlags(int index) { + return (short)getField(index).getAccessFlags(); + } + + public int getFieldNameIndex(int index) { if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;"); - return getFields().at(index * FIELD_SLOTS + NAME_INDEX_OFFSET); + return getField(index).getNameIndex(); } public Symbol getFieldName(int index) { - int nameIndex = getFields().at(index * FIELD_SLOTS + NAME_INDEX_OFFSET); - if (index < getJavaFieldsCount()) { - return getConstants().getSymbolAt(nameIndex); + // Cannot use getFieldNameIndex() because this method is also used for injected fields + return getField(index).getName(); + } + + public Symbol getSymbolFromIndex(int cpIndex, boolean injected) { + if (injected) { + return vmSymbols.symbolAt(cpIndex); } else { - return vmSymbols.symbolAt(nameIndex); + return getConstants().getSymbolAt(cpIndex); } } - public short getFieldSignatureIndex(int index) { + public int getFieldSignatureIndex(int index) { if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;"); - return getFields().at(index * FIELD_SLOTS + SIGNATURE_INDEX_OFFSET); + return getField(index).getGenericSignatureIndex(); } public Symbol getFieldSignature(int index) { - int signatureIndex = getFields().at(index * FIELD_SLOTS + SIGNATURE_INDEX_OFFSET); - if (index < getJavaFieldsCount()) { - return getConstants().getSymbolAt(signatureIndex); - } else { - return vmSymbols.symbolAt(signatureIndex); - } + // Cannot use getFieldSignatureIndex() because this method is also use for injected fields + return getField(index).getSignature(); } - public short getFieldGenericSignatureIndex(int index) { - // int len = getFields().length(); - 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().at(generic_signature_slot); - } else { - return 0; - } - } else { - if (access.fieldHasGenericSignature()) { - generic_signature_slot ++; - } - } - } - return 0; + public int getFieldGenericSignatureIndex(int index) { + return getField(index).getGenericSignatureIndex(); } public Symbol getFieldGenericSignature(int index) { - short genericSignatureIndex = getFieldGenericSignatureIndex(index); - if (genericSignatureIndex != 0) { - return getConstants().getSymbolAt(genericSignatureIndex); - } - return null; + return getField(index).getGenericSignature(); } - public short getFieldInitialValueIndex(int index) { + public int getFieldInitialValueIndex(int index) { if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;"); - return getFields().at(index * FIELD_SLOTS + INITVAL_INDEX_OFFSET); + return getField(index).getInitialValueIndex(); } public int getFieldOffset(int index) { - U2Array fields = getFields(); - short lo = fields.at(index * FIELD_SLOTS + LOW_OFFSET); - short hi = fields.at(index * FIELD_SLOTS + HIGH_OFFSET); - if ((lo & FIELDINFO_TAG_OFFSET) == FIELDINFO_TAG_OFFSET) { - return VM.getVM().buildIntFromShorts(lo, hi) >> FIELDINFO_TAG_SIZE; - } - throw new RuntimeException("should not reach here"); + return (int)getField(index).getOffset(); } // Accessors for declared fields @@ -358,21 +342,31 @@ public class InstanceKlass extends Klass { } } - public KlassArray getLocalInterfaces() { return new KlassArray(localInterfaces.getValue(getAddress())); } - public KlassArray getTransitiveInterfaces() { return new KlassArray(transitiveInterfaces.getValue(getAddress())); } - public int getJavaFieldsCount() { return (int) javaFieldsCount.getValue(this); } - public int getAllFieldsCount() { - int len = getFields().length(); - int allFieldsCount = 0; - for (; allFieldsCount*FIELD_SLOTS < len; allFieldsCount++) { - short flags = getFieldAccessFlags(allFieldsCount); - AccessFlags access = new AccessFlags(flags); - if (access.fieldHasGenericSignature()) { - len --; - } + private int javaFieldsCount = -1; + private int allFieldsCount = -1; + + private void initFieldCounts() { + CompressedReadStream crs = new CompressedReadStream(getFieldInfoStream().getDataStart()); + javaFieldsCount = crs.readInt(); // read num_java_fields + allFieldsCount = javaFieldsCount + crs.readInt(); // read num_injected_fields; + } + + public int getJavaFieldsCount() { + if (javaFieldsCount == -1) { + initFieldCounts(); + } + return javaFieldsCount; + } + + public int getAllFieldsCount() { + if (allFieldsCount == -1) { + initFieldCounts(); } return allFieldsCount; } + + public KlassArray getLocalInterfaces() { return new KlassArray(localInterfaces.getValue(getAddress())); } + public KlassArray getTransitiveInterfaces() { return new KlassArray(transitiveInterfaces.getValue(getAddress())); } public ConstantPool getConstants() { return (ConstantPool) constants.getValue(this); } public Symbol getSourceFileName() { return getConstants().getSourceFileName(); } public String getSourceDebugExtension(){ return CStringUtilities.getString(sourceDebugExtension.getValue(getAddress())); } @@ -622,7 +616,6 @@ public class InstanceKlass extends Klass { } public Field[] getStaticFields() { - U2Array fields = getFields(); int length = getJavaFieldsCount(); ArrayList result = new ArrayList<>(); for (int index = 0; index < length; index++) { @@ -860,9 +853,9 @@ public class InstanceKlass extends Klass { return VMObjectFactory.newObject(IntArray.class, addr); } - public U2Array getFields() { - Address addr = getAddress().getAddressAt(fields.getOffset()); - return VMObjectFactory.newObject(U2Array.class, addr); + public U1Array getFieldInfoStream() { + Address addr = getAddress().getAddressAt(fieldinfoStream.getOffset()); + return VMObjectFactory.newObject(U1Array.class, addr); } public U2Array getInnerClasses() { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java index f3224be7f78..8492e222403 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2023, Oracle and/or its affiliates. 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 @@ -137,17 +137,6 @@ public interface ClassConstants // Method* flags public static final long JVM_ACC_HAS_LOCAL_VARIABLE_TABLE = 0x00200000; - // field flags - // Note: these flags must be defined in the low order 16 bits because - // InstanceKlass only stores a ushort worth of information from the - // AccessFlags value. - // field access is watched by JVMTI - 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; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java index 9488dfeba33..b7c470e3477 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. 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 @@ -271,7 +271,7 @@ public class ClassLoaderStats extends Tool { size += arraySize(k.getInnerClasses()); // Fields - size += arraySize(k.getFields()); + size += arraySize(k.getFieldInfoStream()); // Methods MethodArray methods = k.getMethods(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java index 622d9a02c5d..382eae2e8cb 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java @@ -377,10 +377,10 @@ public class ClassWriter implements /* imports */ ClassConstants short accessFlags = klass.getFieldAccessFlags(index); dos.writeShort(accessFlags & (short) JVM_RECOGNIZED_FIELD_MODIFIERS); - short nameIndex = klass.getFieldNameIndex(index); + int nameIndex = klass.getFieldNameIndex(index); dos.writeShort(nameIndex); - short signatureIndex = klass.getFieldSignatureIndex(index); + int signatureIndex = klass.getFieldSignatureIndex(index); dos.writeShort(signatureIndex); if (DEBUG) debugMessage("\tfield name = " + nameIndex + ", signature = " + signatureIndex); @@ -389,11 +389,11 @@ public class ClassWriter implements /* imports */ ClassConstants if (hasSyn) fieldAttributeCount++; - short initvalIndex = klass.getFieldInitialValueIndex(index); + int initvalIndex = klass.getFieldInitialValueIndex(index); if (initvalIndex != 0) fieldAttributeCount++; - short genSigIndex = klass.getFieldGenericSignatureIndex(index); + int genSigIndex = klass.getFieldGenericSignatureIndex(index); if (genSigIndex != 0) fieldAttributeCount++; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java index f0e93c76025..004ba28bf31 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2023, Oracle and/or its affiliates. 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 @@ -1120,18 +1120,14 @@ public class HTMLGenerator implements /* imports */ ClassConstants { buf.append(" " + kls.getName().asString() + "={"); int flen = ov.fieldsSize(); - U2Array klfields = kls.getFields(); - int klen = klfields.length(); + sun.jvm.hotspot.oops.Field[] fields = sun.jvm.hotspot.oops.Field.getFields(kls); int findex = 0; - for (int index = 0; index < klen; index++) { - int accsFlags = kls.getFieldAccessFlags(index); - Symbol f_name = kls.getFieldName(index); - AccessFlags access = new AccessFlags(accsFlags); - if (!access.isStatic()) { - ScopeValue svf = ov.getFieldAt(findex++); - String fstr = scopeValueAsString(sd, svf); - buf.append(" [" + f_name.asString() + " :"+ index + "]=(#" + fstr + ")"); - } + for (int index = 0; index < fields.length; index++) { + if (!fields[index].getAccessFlagsObj().isStatic()) { + ScopeValue svf = ov.getFieldAt(findex++); + String fstr = scopeValueAsString(sd, svf); + buf.append(" [" + fields[index].getName().asString() + " :"+ index + "]=(#" + fstr + ")"); + } } buf.append(" }"); } else { @@ -1680,15 +1676,15 @@ public class HTMLGenerator implements /* imports */ ClassConstants { protected String genHTMLListForFields(InstanceKlass klass) { Formatter buf = new Formatter(genHTML); - U2Array fields = klass.getFields(); - int numFields = klass.getAllFieldsCount(); + sun.jvm.hotspot.oops.Field[] fields = sun.jvm.hotspot.oops.Field.getFields(klass); + int numFields = fields.length; if (numFields != 0) { buf.h3("Fields"); buf.beginList(); for (int f = 0; f < numFields; f++) { - sun.jvm.hotspot.oops.Field field = klass.getFieldByIndex(f); - String f_name = ((NamedFieldIdentifier)field.getID()).getName(); - Symbol f_sig = field.getSignature(); + sun.jvm.hotspot.oops.Field field = fields[f]; + String f_name = field.getName().asString(); + Symbol f_sig = field.getSignature(); Symbol f_genSig = field.getGenericSignature(); AccessFlags acc = field.getAccessFlagsObj(); @@ -1702,7 +1698,7 @@ public class HTMLGenerator implements /* imports */ ClassConstants { buf.append(f_name); buf.append(';'); // is it generic? - if (f_genSig != null) { + if (field.isGeneric()) { buf.append(" [signature "); buf.append(escapeHTMLSpecialChars(f_genSig.asString())); buf.append("] "); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/GenericArray.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/GenericArray.java index 4b7f81ba778..3fb6b26a88d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/GenericArray.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/GenericArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, Oracle and/or its affiliates. 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 @@ -74,6 +74,10 @@ public abstract class GenericArray extends VMObject { return length(); } + public Address getDataStart() { + return getAddress().addOffsetTo(dataFieldOffset); + } + /** * Gets the element at the given index. */ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index 5194149f104..b4866e2fa43 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, Oracle and/or its affiliates. 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 @@ -463,9 +463,10 @@ final class CompilerToVM { * {@code info} are: * *
-     *     [ flags,  // fieldDescriptor::access_flags()
-     *       offset, // fieldDescriptor::offset()
-     *       index   // fieldDescriptor::index()
+     *     [ aflags,  // fieldDescriptor::access_flags()
+     *       offset,  // fieldDescriptor::offset()
+     *       index,   // fieldDescriptor::index()
+     *       fflags   // fieldDescriptor::field_flags()
      *     ]
      * 
* @@ -1043,6 +1044,12 @@ final class CompilerToVM { native ResolvedJavaMethod[] getDeclaredMethods(HotSpotResolvedObjectTypeImpl klass, long klassPointer); + HotSpotResolvedObjectTypeImpl.FieldInfo[] getDeclaredFieldsInfo(HotSpotResolvedObjectTypeImpl klass) { + return getDeclaredFieldsInfo(klass, klass.getKlassPointer()); + } + + native HotSpotResolvedObjectTypeImpl.FieldInfo[] getDeclaredFieldsInfo(HotSpotResolvedObjectTypeImpl klass, long klassPointer); + /** * Reads the current value of a static field of {@code declaringKlass}. Extra sanity checking is * performed on the offset and kind of the read being performed. diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java index 3578cd01da8..fd158d0cc21 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, Oracle and/or its affiliates. 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 @@ -808,7 +808,7 @@ public final class HotSpotConstantPool implements ConstantPool, MetaspaceHandleO JavaType fieldHolder = lookupType(holderIndex, opcode); if (fieldHolder instanceof HotSpotResolvedObjectTypeImpl) { - int[] info = new int[3]; + int[] info = new int[4]; HotSpotResolvedObjectTypeImpl resolvedHolder; try { resolvedHolder = compilerToVM().resolveFieldInPool(this, index, (HotSpotResolvedJavaMethodImpl) method, (byte) opcode, info); @@ -822,7 +822,8 @@ public final class HotSpotConstantPool implements ConstantPool, MetaspaceHandleO final int flags = info[0]; final int offset = info[1]; final int fieldIndex = info[2]; - HotSpotResolvedJavaField result = resolvedHolder.createField(type, offset, flags, fieldIndex); + final int fieldFlags = info[3]; + HotSpotResolvedJavaField result = resolvedHolder.createField(type, offset, flags, fieldFlags, fieldIndex); return result; } else { return new UnresolvedJavaField(fieldHolder, lookupUtf8(getNameRefIndexAt(nameAndTypeIndex)), type); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index 792d412e776..1103f592b26 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, Oracle and/or its affiliates. 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 @@ -56,16 +56,22 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { private final int index; /** - * This value contains all flags as stored in the VM including internal ones. + * This value contains all flags from the class file */ - private final int modifiers; + private final int classfileFlags; - HotSpotResolvedJavaFieldImpl(HotSpotResolvedObjectTypeImpl holder, JavaType type, int offset, int modifiers, int index) { + /** + * This value contains VM internal flags + */ + private final int internalFlags; + + HotSpotResolvedJavaFieldImpl(HotSpotResolvedObjectTypeImpl holder, JavaType type, int offset, int classfileFlags, int internalFlags, int index) { this.holder = holder; this.type = type; - this.index = index; this.offset = offset; - this.modifiers = modifiers; + this.classfileFlags = classfileFlags; + this.internalFlags = internalFlags; + this.index = index; } @Override @@ -91,12 +97,12 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { @Override public int getModifiers() { - return modifiers & HotSpotModifiers.jvmFieldModifiers(); + return classfileFlags & HotSpotModifiers.jvmFieldModifiers(); } @Override public boolean isInternal() { - return (modifiers & config().jvmAccFieldInternal) != 0; + return (internalFlags & (1 << config().jvmFieldFlagInternalShift)) != 0; } /** @@ -121,7 +127,7 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { @Override public String getName() { - return holder.createFieldInfo(index).getName(); + return holder.getFieldInfo(index).getName(holder); } @Override @@ -165,7 +171,7 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { @Override public boolean isSynthetic() { - return (config().jvmAccSynthetic & modifiers) != 0; + return (config().jvmAccSynthetic & classfileFlags) != 0; } /** @@ -175,7 +181,7 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { */ @Override public boolean isStable() { - return (config().jvmAccFieldStable & modifiers) != 0; + return (1 << (config().jvmFieldFlagStableShift ) & internalFlags) != 0; } private boolean hasAnnotations() { @@ -219,6 +225,6 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField { @Override public JavaConstant getConstantValue() { - return holder.createFieldInfo(index).getConstantValue(); + return holder.getFieldInfo(index).getConstantValue(holder); } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 6473c2d68b3..11d08eb1c2b 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, Oracle and/or its affiliates. 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 @@ -84,6 +84,11 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem */ private HotSpotResolvedJavaType componentType; + /** + * Lazily initialized cache for FieldInfo. + */ + private FieldInfo[] fieldInfo; + /** * Managed exclusively by {@link HotSpotJDKReflection#getField}. */ @@ -576,8 +581,8 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem return result; } - HotSpotResolvedJavaField createField(JavaType type, int offset, int rawFlags, int index) { - return new HotSpotResolvedJavaFieldImpl(this, type, offset, rawFlags, index); + HotSpotResolvedJavaField createField(JavaType type, int offset, int classfileFlags, int internalFlags, int index) { + return new HotSpotResolvedJavaFieldImpl(this, type, offset, classfileFlags, internalFlags, index); } @Override @@ -623,8 +628,15 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem return null; } - FieldInfo createFieldInfo(int index) { - return new FieldInfo(index); + private FieldInfo[] getFieldInfo() { + if (fieldInfo == null) { + fieldInfo = runtime().compilerToVm.getDeclaredFieldsInfo(this); + } + return fieldInfo; + } + + FieldInfo getFieldInfo(int index) { + return getFieldInfo()[index]; } public void ensureInitialized() { @@ -657,75 +669,74 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem * This class represents the field information for one field contained in the fields array of an * {@code InstanceKlass}. The implementation is similar to the native {@code FieldInfo} class. */ - class FieldInfo { - /** - * Native pointer into the array of Java shorts. - */ - private final long metaspaceData; + static class FieldInfo { + + private final int nameIndex; + private final int signatureIndex; + private final int offset; + private final int classfileFlags; + private final int internalFlags; + private final int initializerIndex; /** - * Creates a field info for the field in the fields array at index {@code index}. + * Creates a field info with the provided indices. * - * @param index index to the fields array + * @param nameIndex index of field's name in the constant pool + * @param signatureIndex index of field's signature in the constant pool + * @param offset field's offset + * @param classfileFlags field's access flags (from the class file) + * @param internalFlags field's internal flags (from the VM) + * @param initializerIndex field's initial value index in the constant pool */ - FieldInfo(int index) { - HotSpotVMConfig config = config(); - // Get Klass::_fields - final long metaspaceFields = UNSAFE.getAddress(getKlassPointer() + config.instanceKlassFieldsOffset); - assert config.fieldInfoFieldSlots == 6 : "revisit the field parsing code"; - int offset = config.fieldInfoFieldSlots * Short.BYTES * index; - metaspaceData = metaspaceFields + config.arrayU2DataOffset + offset; + FieldInfo(int nameIndex, int signatureIndex, int offset, int classfileFlags, int internalFlags, int initializerIndex) { + this.nameIndex = nameIndex; + this.signatureIndex = signatureIndex; + this.offset = offset; + this.classfileFlags = classfileFlags; + this.internalFlags = internalFlags; + this.initializerIndex = initializerIndex; } - private int getAccessFlags() { - return readFieldSlot(config().fieldInfoAccessFlagsOffset); + private int getClassfileFlags() { + return classfileFlags; + } + + private int getInternalFlags() { + return internalFlags; } private int getNameIndex() { - return readFieldSlot(config().fieldInfoNameIndexOffset); + return nameIndex; } private int getSignatureIndex() { - return readFieldSlot(config().fieldInfoSignatureIndexOffset); + return signatureIndex; } private int getConstantValueIndex() { - return readFieldSlot(config().fieldInfoConstantValueIndexOffset); + return initializerIndex; } public int getOffset() { - HotSpotVMConfig config = config(); - final int lowPacked = readFieldSlot(config.fieldInfoLowPackedOffset); - final int highPacked = readFieldSlot(config.fieldInfoHighPackedOffset); - final int offset = ((highPacked << Short.SIZE) | lowPacked) >> config.fieldInfoTagSize; return offset; } - /** - * Helper method to read an entry (slot) from the field array. Currently field info is laid - * on top an array of Java shorts. - */ - private int readFieldSlot(int index) { - int offset = Short.BYTES * index; - return UNSAFE.getChar(metaspaceData + offset); - } - /** * Returns the name of this field as a {@link String}. If the field is an internal field the * name index is pointing into the vmSymbols table. + * @param klass field's holder class */ - public String getName() { - final int nameIndex = getNameIndex(); - return isInternal() ? config().symbolAt(nameIndex) : getConstantPool().lookupUtf8(nameIndex); + public String getName(HotSpotResolvedObjectTypeImpl klass) { + return isInternal() ? config().symbolAt(nameIndex) : klass.getConstantPool().lookupUtf8(nameIndex); } /** * Returns the signature of this field as {@link String}. If the field is an internal field * the signature index is pointing into the vmSymbols table. + * @param klass field's holder class */ - public String getSignature() { - final int signatureIndex = getSignatureIndex(); - return isInternal() ? config().symbolAt(signatureIndex) : getConstantPool().lookupUtf8(signatureIndex); + public String getSignature(HotSpotResolvedObjectTypeImpl klass) { + return isInternal() ? config().symbolAt(signatureIndex) : klass.getConstantPool().lookupUtf8(signatureIndex); } /** @@ -733,29 +744,24 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem * * @return {@code null} if this field has no {@code ConstantValue} attribute */ - public JavaConstant getConstantValue() { - int cvIndex = getConstantValueIndex(); - if (cvIndex == 0) { + public JavaConstant getConstantValue(HotSpotResolvedObjectTypeImpl klass) { + if (initializerIndex == 0) { return null; } - return constantPool.getStaticFieldConstantValue(cvIndex); + return klass.constantPool.getStaticFieldConstantValue(initializerIndex); } - public JavaType getType() { - String signature = getSignature(); - return runtime().lookupType(signature, HotSpotResolvedObjectTypeImpl.this, false); + public JavaType getType(HotSpotResolvedObjectTypeImpl klass) { + String signature = getSignature(klass); + return runtime().lookupType(signature, klass, false); } private boolean isInternal() { - return (getAccessFlags() & config().jvmAccFieldInternal) != 0; + return (getInternalFlags() & (1 << config().jvmFieldFlagInternalShift)) != 0; } public boolean isStatic() { - return Modifier.isStatic(getAccessFlags()); - } - - public boolean hasGenericSignature() { - return (getAccessFlags() & config().jvmAccFieldHasGenericSignature) != 0; + return Modifier.isStatic(getClassfileFlags()); } } @@ -820,17 +826,11 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem */ private HotSpotResolvedJavaField[] getFields(boolean retrieveStaticFields, HotSpotResolvedJavaField[] prepend) { HotSpotVMConfig config = config(); - final long metaspaceFields = UNSAFE.getAddress(getKlassPointer() + config.instanceKlassFieldsOffset); - int metaspaceFieldsLength = UNSAFE.getInt(metaspaceFields + config.arrayU1LengthOffset); int resultCount = 0; int index = 0; - for (int i = 0; i < metaspaceFieldsLength; i += config.fieldInfoFieldSlots, index++) { - FieldInfo field = new FieldInfo(index); - if (field.hasGenericSignature()) { - metaspaceFieldsLength--; - } - if (field.isStatic() == retrieveStaticFields) { + for (index = 0; index < getFieldInfo().length; index++) { + if (getFieldInfo(index).isStatic() == retrieveStaticFields) { resultCount++; } } @@ -851,11 +851,11 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem // but the array of fields to be returned must be sorted by increasing offset // This code populates the array, then applies the sorting function int resultIndex = prependLength; - for (int i = 0; i < index; ++i) { - FieldInfo field = new FieldInfo(i); + for (int i = 0; i < getFieldInfo().length; ++i) { + FieldInfo field = getFieldInfo(i); if (field.isStatic() == retrieveStaticFields) { int offset = field.getOffset(); - HotSpotResolvedJavaField resolvedJavaField = createField(field.getType(), offset, field.getAccessFlags(), i); + HotSpotResolvedJavaField resolvedJavaField = createField(field.getType(this), offset, field.getClassfileFlags(), field.getInternalFlags(), i); result[resultIndex++] = resolvedJavaField; } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 6f729c3c242..223b210c555 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -99,7 +99,7 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { final int instanceKlassInitStateOffset = getFieldOffset("InstanceKlass::_init_state", Integer.class, "InstanceKlass::ClassState"); final int instanceKlassConstantsOffset = getFieldOffset("InstanceKlass::_constants", Integer.class, "ConstantPool*"); - final int instanceKlassFieldsOffset = getFieldOffset("InstanceKlass::_fields", Integer.class, "Array*"); + final int instanceKlassFieldInfoStreamOffset = getFieldOffset("InstanceKlass::_fieldinfo_stream", Integer.class, "Array*"); final int instanceKlassAnnotationsOffset = getFieldOffset("InstanceKlass::_annotations", Integer.class, "Annotations*"); final int instanceKlassMiscFlagsOffset = getFieldOffset("InstanceKlass::_misc_flags._flags", Integer.class, "u2"); final int klassVtableStartOffset = getFieldValue("CompilerToVM::Data::Klass_vtable_start_offset", Integer.class, "int"); @@ -116,20 +116,9 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { final int arrayU1DataOffset = getFieldOffset("Array::_data", Integer.class); final int arrayU2DataOffset = getFieldOffset("Array::_data", Integer.class); - final int fieldInfoAccessFlagsOffset = getConstant("FieldInfo::access_flags_offset", Integer.class); - final int fieldInfoNameIndexOffset = getConstant("FieldInfo::name_index_offset", Integer.class); - final int fieldInfoSignatureIndexOffset = getConstant("FieldInfo::signature_index_offset", Integer.class); - final int fieldInfoConstantValueIndexOffset = getConstant("FieldInfo::initval_index_offset", Integer.class); - final int fieldInfoLowPackedOffset = getConstant("FieldInfo::low_packed_offset", Integer.class); - final int fieldInfoHighPackedOffset = getConstant("FieldInfo::high_packed_offset", Integer.class); - final int fieldInfoFieldSlots = getConstant("FieldInfo::field_slots", Integer.class); - - final int fieldInfoTagSize = getConstant("FIELDINFO_TAG_SIZE", Integer.class); - final int jvmAccHasFinalizer = getConstant("JVM_ACC_HAS_FINALIZER", Integer.class); - final int jvmAccFieldInternal = getConstant("JVM_ACC_FIELD_INTERNAL", Integer.class); - final int jvmAccFieldStable = getConstant("JVM_ACC_FIELD_STABLE", Integer.class); - final int jvmAccFieldHasGenericSignature = getConstant("JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE", Integer.class); + final int jvmFieldFlagInternalShift = getConstant("FieldInfo::FieldFlags::_ff_injected", Integer.class); + final int jvmFieldFlagStableShift = getConstant("FieldInfo::FieldFlags::_ff_stable", Integer.class); final int jvmAccIsCloneableFast = getConstant("JVM_ACC_IS_CLONEABLE_FAST", Integer.class); // These modifiers are not public in Modifier so we get them via vmStructs. diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java index 2d8e253e2ed..a6b5b7fb2d0 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2023, Oracle and/or its affiliates. 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 diff --git a/test/hotspot/gtest/oops/test_instanceKlass.cpp b/test/hotspot/gtest/oops/test_instanceKlass.cpp index 9a9aea76103..dd7982e88aa 100644 --- a/test/hotspot/gtest/oops/test_instanceKlass.cpp +++ b/test/hotspot/gtest/oops/test_instanceKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. 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 @@ -51,12 +51,12 @@ TEST_VM(InstanceKlass, class_loader_printer) { stringStream st; loader->print_on(&st); // See if injected loader_data field is printed in string - ASSERT_TRUE(strstr(st.as_string(), "internal 'loader_data'") != NULL) << "Must contain internal fields"; + ASSERT_TRUE(strstr(st.as_string(), "injected 'loader_data'") != NULL) << "Must contain injected fields"; st.reset(); // See if mirror injected fields are printed. oop mirror = vmClasses::ClassLoader_klass()->java_mirror(); mirror->print_on(&st); - ASSERT_TRUE(strstr(st.as_string(), "internal 'protection_domain'") != NULL) << "Must contain internal fields"; + ASSERT_TRUE(strstr(st.as_string(), "injected 'protection_domain'") != NULL) << "Must contain injected fields"; // We should test other printing functions too. #ifndef PRODUCT st.reset(); diff --git a/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldHelper.java b/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldHelper.java index b9be6ab68c8..d83d6e972bd 100644 --- a/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldHelper.java +++ b/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldHelper.java @@ -27,8 +27,8 @@ import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaField; public class HotSpotResolvedJavaFieldHelper { - public static ResolvedJavaField createField(HotSpotResolvedObjectTypeImpl holder, JavaType type, int offset, int modifiers, int index) { - return new HotSpotResolvedJavaFieldImpl(holder, type, offset, modifiers, index); + public static ResolvedJavaField createField(HotSpotResolvedObjectTypeImpl holder, JavaType type, int offset, int modifiers, int internalModifiers, int index) { + return new HotSpotResolvedJavaFieldImpl(holder, type, offset, modifiers, internalModifiers, index); } public static int getIndex(ResolvedJavaField field) { diff --git a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java index a5bcfdc71f7..cfec9c1d184 100644 --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. 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 @@ -104,7 +104,7 @@ public class ResolveFieldInPoolTest { cached = "cached "; } for (int j = 0; j < entry.opcodes.length; j++) { - int[] info = new int[3]; + int[] info = new int[4]; HotSpotResolvedObjectType fieldToVerify = CompilerToVMHelper.resolveFieldInPool(constantPoolCTVM, index, diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/HotSpotResolvedJavaFieldTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/HotSpotResolvedJavaFieldTest.java index c85241decfc..e4de1dd0bee 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/HotSpotResolvedJavaFieldTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/HotSpotResolvedJavaFieldTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. 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 @@ -22,14 +22,6 @@ */ package jdk.vm.ci.hotspot.test; -import static java.lang.reflect.Modifier.FINAL; -import static java.lang.reflect.Modifier.PRIVATE; -import static java.lang.reflect.Modifier.PROTECTED; -import static java.lang.reflect.Modifier.PUBLIC; -import static java.lang.reflect.Modifier.STATIC; -import static java.lang.reflect.Modifier.TRANSIENT; -import static java.lang.reflect.Modifier.VOLATILE; - import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -38,8 +30,8 @@ import org.junit.Assert; import org.junit.Test; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotModifiers; import jdk.vm.ci.hotspot.HotSpotResolvedJavaField; -import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaField; @@ -63,35 +55,28 @@ public class HotSpotResolvedJavaFieldTest { private static final Method createFieldMethod; private static final Field indexField; + private static final Field internalFlagsField; static { Method m = null; - Field f = null; + Field f1 = null; + Field f2 = null; try { Class typeImpl = Class.forName("jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl"); - m = typeImpl.getDeclaredMethod("createField", JavaType.class, int.class, int.class, int.class); + m = typeImpl.getDeclaredMethod("createField", JavaType.class, int.class, int.class, int.class, int.class); m.setAccessible(true); Class fieldImpl = Class.forName("jdk.vm.ci.hotspot.HotSpotResolvedJavaFieldImpl"); - f = fieldImpl.getDeclaredField("index"); - f.setAccessible(true); + f1 = fieldImpl.getDeclaredField("index"); + f1.setAccessible(true); + f2 = fieldImpl.getDeclaredField("internalFlags"); + f2.setAccessible(true); } catch (Exception e) { throw new AssertionError(e); } createFieldMethod = m; - indexField = f; - } - - /** - * Same as {@code HotSpotModifiers.jvmFieldModifiers()} but works when using a JVMCI version - * prior to the introduction of that method. - */ - private int jvmFieldModifiers() { - HotSpotJVMCIRuntime runtime = runtime(); - HotSpotVMConfigAccess access = new HotSpotVMConfigAccess(runtime.getConfigStore()); - int accEnum = access.getConstant("JVM_ACC_ENUM", Integer.class, 0x4000); - int accSynthetic = access.getConstant("JVM_ACC_SYNTHETIC", Integer.class, 0x1000); - return PUBLIC | PRIVATE | PROTECTED | STATIC | FINAL | VOLATILE | TRANSIENT | accEnum | accSynthetic; + indexField = f1; + internalFlagsField = f2; } HotSpotJVMCIRuntime runtime() { @@ -113,14 +98,14 @@ public class HotSpotResolvedJavaFieldTest { ResolvedJavaType type = getMetaAccess().lookupJavaType(c); for (ResolvedJavaField field : type.getInstanceFields(false)) { if (field.isInternal()) { - Assert.assertEquals(0, ~jvmFieldModifiers() & field.getModifiers()); + Assert.assertEquals(0, ~HotSpotModifiers.jvmFieldModifiers() & field.getModifiers()); } } } } /** - * Tests that {@code HotSpotResolvedObjectTypeImpl#createField(String, JavaType, long, int)} + * Tests that {@code HotSpotResolvedObjectTypeImpl#createField(String, JavaType, int, int)} * always returns an {@linkplain ResolvedJavaField#equals(Object) equivalent} object for an * internal field. * @@ -136,7 +121,8 @@ public class HotSpotResolvedJavaFieldTest { if (field.isInternal()) { HotSpotResolvedJavaField expected = (HotSpotResolvedJavaField) field; int index = indexField.getInt(expected); - ResolvedJavaField actual = (ResolvedJavaField) createFieldMethod.invoke(type, expected.getType(), expected.getOffset(), expected.getModifiers(), index); + int internalFlags = internalFlagsField.getInt(expected); + ResolvedJavaField actual = (ResolvedJavaField) createFieldMethod.invoke(type, expected.getType(), expected.getOffset(), expected.getModifiers(), internalFlags, index); Assert.assertEquals(expected, actual); } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestHotSpotResolvedJavaField.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestHotSpotResolvedJavaField.java index 2acb62dad67..489f9dcf97d 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestHotSpotResolvedJavaField.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestHotSpotResolvedJavaField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. 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 @@ -48,7 +48,7 @@ public class TestHotSpotResolvedJavaField { int max = Character.MAX_VALUE; int[] valid = {0, 1, max - 1, max}; for (int index : valid) { - ResolvedJavaField field = HotSpotResolvedJavaFieldHelper.createField(null, null, 0, 0, index); + ResolvedJavaField field = HotSpotResolvedJavaFieldHelper.createField(null, null, 0, 0, 0, index); Assert.assertEquals(HotSpotResolvedJavaFieldHelper.getIndex(field), index); } } @@ -59,7 +59,7 @@ public class TestHotSpotResolvedJavaField { int max = Integer.MAX_VALUE; int[] valid = {min, min + 1, -2, 0, 1, max - 1, max}; for (int offset : valid) { - ResolvedJavaField field = HotSpotResolvedJavaFieldHelper.createField(null, null, offset, 0, 0); + ResolvedJavaField field = HotSpotResolvedJavaFieldHelper.createField(null, null, offset, 0, 0, 0); Assert.assertEquals(field.getOffset(), offset); } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java index 252c55b954d..a159dc64cc6 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, Oracle and/or its affiliates. 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