8292818: replace 96-bit representation for field metadata with variable-sized streams
Co-authored-by: John R Rose <jrose@openjdk.org> Co-authored-by: Chris Plummer <cjplummer@openjdk.org> Reviewed-by: dholmes, coleenp, cjplummer, dnsimon
This commit is contained in:
parent
932be3542d
commit
bfb812a8ff
@ -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");
|
||||
|
@ -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; }
|
||||
|
@ -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<FieldInfo>(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<u2>(_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<u2>(_loader_data, _fields);
|
||||
|
||||
if (_fieldinfo_stream != nullptr) {
|
||||
MetadataFactory::free_array<u1>(_loader_data, _fieldinfo_stream);
|
||||
}
|
||||
|
||||
if (_fields_status != nullptr) {
|
||||
MetadataFactory::free_array<FieldStatus>(_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<FieldStatus>(_loader_data, _temp_field_info->length(),
|
||||
FieldStatus(0), CHECK);
|
||||
}
|
||||
|
||||
void ClassFileParser::set_klass(InstanceKlass* klass) {
|
||||
|
@ -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<u2>* _fields;
|
||||
Array<u1>* _fieldinfo_stream;
|
||||
Array<FieldStatus>* _fields_status;
|
||||
Array<Method*>* _methods;
|
||||
Array<u2>* _inner_classes;
|
||||
Array<u2>* _nest_members;
|
||||
@ -141,6 +143,7 @@ class ClassFileParser {
|
||||
ClassAnnotationCollector* _parsed_annotations;
|
||||
FieldAllocationCount* _fac;
|
||||
FieldLayoutInfo* _field_info;
|
||||
GrowableArray<FieldInfo>* _temp_field_info;
|
||||
const intArray* _method_ordering;
|
||||
GrowableArray<Method*>* _all_mirandas;
|
||||
|
||||
|
@ -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<LayoutRawBlock*>(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<LayoutRawBlock*>(INITIAL_LIST_SIZE);
|
||||
}
|
||||
@ -105,8 +105,8 @@ void FieldGroup::sort_by_size() {
|
||||
}
|
||||
}
|
||||
|
||||
FieldLayout::FieldLayout(Array<u2>* fields, ConstantPool* cp) :
|
||||
_fields(fields),
|
||||
FieldLayout::FieldLayout(GrowableArray<FieldInfo>* 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<LayoutRawBlock*>* all_fields = new GrowableArray<LayoutRawBlock*>(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<u2>* fields, bool is_contended, FieldLayoutInfo* info) :
|
||||
GrowableArray<FieldInfo>* 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<FieldGroup*>(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<FieldInfo> 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?");
|
||||
|
@ -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<u2>* _fields;
|
||||
GrowableArray<FieldInfo>* _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<u2>* fields, ConstantPool* cp);
|
||||
FieldLayout(GrowableArray<FieldInfo>* 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<u2>* _fields;
|
||||
GrowableArray<FieldInfo>* _field_info;
|
||||
FieldLayoutInfo* _info;
|
||||
FieldGroup* _root_group;
|
||||
GrowableArray<FieldGroup*> _contended_groups;
|
||||
@ -244,7 +244,7 @@ class FieldLayoutBuilder : public ResourceObj {
|
||||
|
||||
public:
|
||||
FieldLayoutBuilder(const Symbol* classname, const InstanceKlass* super_klass, ConstantPool* constant_pool,
|
||||
Array<u2>* fields, bool is_contended, FieldLayoutInfo* info);
|
||||
GrowableArray<FieldInfo>* field_info, bool is_contended, FieldLayoutInfo* info);
|
||||
|
||||
int get_alignment() {
|
||||
assert(_alignment != -1, "Uninitialized");
|
||||
|
@ -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<FieldInfo>* 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<u1>* old_stream = ik->fieldinfo_stream();
|
||||
assert(fields->length() == (java_fields + injected_fields), "Must be");
|
||||
Array<u1>* new_fis = FieldInfoStream::create_FieldInfoStream(fields, java_fields, injected_fields, k->class_loader_data(), CHECK);
|
||||
ik->set_fieldinfo_stream(new_fis);
|
||||
MetadataFactory::free_array<u1>(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;
|
||||
}
|
||||
|
@ -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';
|
||||
|
||||
|
@ -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<FieldInfo>* 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<u2>* 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)},
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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) \
|
||||
|
@ -156,7 +156,7 @@
|
||||
nonstatic_field(ExceptionTableElement, handler_pc, u2) \
|
||||
nonstatic_field(ExceptionTableElement, catch_type_index, u2) \
|
||||
\
|
||||
nonstatic_field(InstanceKlass, _fields, Array<u2>*) \
|
||||
nonstatic_field(InstanceKlass, _fieldinfo_stream, Array<u1>*) \
|
||||
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) \
|
||||
|
@ -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") \
|
||||
|
@ -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
|
||||
|
143
src/hotspot/share/oops/fieldInfo.cpp
Normal file
143
src/hotspot/share/oops/fieldInfo.cpp
Normal file
@ -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<FieldInfo>* array, ConstantPool* cp) {
|
||||
for (int i = 0; i < array->length(); i++) {
|
||||
array->adr_at(i)->print(os, cp);
|
||||
}
|
||||
}
|
||||
|
||||
Array<u1>* FieldInfoStream::create_FieldInfoStream(GrowableArray<FieldInfo>* 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>;
|
||||
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<u1>* const fis = MetadataFactory::new_array<u1>(loader_data, storage_size, CHECK_NULL);
|
||||
|
||||
using StreamWriter = UNSIGNED5::Writer<Array<u1>*, int, ArrayHelper<Array<u1>*, int>>;
|
||||
using StreamFieldWriter = Mapper<StreamWriter>;
|
||||
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<FieldInfo>* FieldInfoStream::create_FieldInfoArray(const Array<u1>* fis, int* java_fields_count, int* injected_fields_count) {
|
||||
int length = FieldInfoStream::num_total_fields(fis);
|
||||
GrowableArray<FieldInfo>* array = new GrowableArray<FieldInfo>(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<u1>* 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);
|
||||
}
|
||||
}
|
@ -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<u1> used to
|
||||
// store the compressed stream of FieldInfo
|
||||
template<typename ARR, typename OFF>
|
||||
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<u2>* 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<FieldInfo>* 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<typename CON>
|
||||
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<vmSymbolID>(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<const u1*, int> _r;
|
||||
int _next_index;
|
||||
|
||||
public:
|
||||
FieldInfoReader(const Array<u1>* 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<u1>* fis);
|
||||
static int num_injected_java_fields(const Array<u1>* fis);
|
||||
static int num_total_fields(const Array<u1>* fis);
|
||||
|
||||
static Array<u1>* create_FieldInfoStream(GrowableArray<FieldInfo>* fields, int java_fields, int injected_fields,
|
||||
ClassLoaderData* loader_data, TRAPS);
|
||||
static GrowableArray<FieldInfo>* create_FieldInfoArray(const Array<u1>* fis, int* java_fields_count, int* injected_fields_count);
|
||||
static void print_from_fieldinfo_stream(Array<u1>* 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
|
||||
|
182
src/hotspot/share/oops/fieldInfo.inline.hpp
Normal file
182
src/hotspot/share/oops/fieldInfo.inline.hpp
Normal file
@ -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<vmSymbolID>(symbol_index));
|
||||
}
|
||||
|
||||
inline int FieldInfoStream::num_injected_java_fields(const Array<u1>* fis) {
|
||||
FieldInfoReader fir(fis);
|
||||
fir.skip(1);
|
||||
return fir.next_uint();
|
||||
}
|
||||
|
||||
inline int FieldInfoStream::num_total_fields(const Array<u1>* fis) {
|
||||
FieldInfoReader fir(fis);
|
||||
return fir.next_uint() + fir.next_uint();
|
||||
}
|
||||
|
||||
inline int FieldInfoStream::num_java_fields(const Array<u1>* fis) { return FieldInfoReader(fis).next_uint(); }
|
||||
|
||||
template<typename CON>
|
||||
inline void Mapper<CON>::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<u1>* 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
|
@ -39,48 +39,33 @@
|
||||
// cases.
|
||||
class FieldStreamBase : public StackObj {
|
||||
protected:
|
||||
Array<u2>* _fields;
|
||||
const Array<u1>* _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<u2>* fields, ConstantPool* constants, int start, int limit);
|
||||
inline FieldStreamBase(const Array<u1>* fieldinfo_stream, ConstantPool* constants, int start, int limit);
|
||||
|
||||
inline FieldStreamBase(Array<u2>* fields, ConstantPool* constants);
|
||||
inline FieldStreamBase(Array<u1>* 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<fieldDescriptor&>(_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<u2>* fields, ConstantPool* constants): FieldStreamBase(fields, constants) {}
|
||||
AllFieldStream(InstanceKlass* k): FieldStreamBase(k->fields(), k->constants()) {}
|
||||
AllFieldStream(Array<u1>* fieldinfo, ConstantPool* constants): FieldStreamBase(fieldinfo, constants) {}
|
||||
AllFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants()) {}
|
||||
};
|
||||
|
||||
#endif // SHARE_OOPS_FIELDSTREAMS_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<u2>* fields, ConstantPool* constants, int start, int limit) : _fields(fields),
|
||||
FieldStreamBase::FieldStreamBase(const Array<u1>* 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<u2>* fields, ConstantPool* constants) : _fields(fields),
|
||||
_constants(constantPoolHandle(Thread::current(), constants)), _index(0) {
|
||||
_limit = init_generic_signature_start_slot();
|
||||
FieldStreamBase::FieldStreamBase(Array<u1>* 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
|
||||
|
@ -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<jushort>(loader_data, fields());
|
||||
if (fieldinfo_stream() != nullptr && !fieldinfo_stream()->is_shared()) {
|
||||
MetadataFactory::free_array<u1>(loader_data, fieldinfo_stream());
|
||||
}
|
||||
set_fields(nullptr, 0);
|
||||
set_fieldinfo_stream(nullptr);
|
||||
|
||||
if (fields_status() != nullptr && !fields_status()->is_shared()) {
|
||||
MetadataFactory::free_array<FieldStatus>(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();
|
||||
|
@ -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<int>* _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<u2>* _fields;
|
||||
// Fields information is stored in an UNSIGNED5 encoded stream (see fieldInfo.hpp)
|
||||
Array<u1>* _fieldinfo_stream;
|
||||
Array<FieldStatus>* _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<u2>* fields() const { return _fields; }
|
||||
void set_fields(Array<u2>* f, u2 java_fields_count) {
|
||||
guarantee(_fields == nullptr || f == nullptr, "Just checking");
|
||||
_fields = f;
|
||||
_java_fields_count = java_fields_count;
|
||||
}
|
||||
Array<u1>* fieldinfo_stream() const { return _fieldinfo_stream; }
|
||||
void set_fieldinfo_stream(Array<u1>* fis) { _fieldinfo_stream = fis; }
|
||||
|
||||
Array<FieldStatus>* fields_status() const {return _fields_status; }
|
||||
void set_fields_status(Array<FieldStatus>* array) { _fields_status = array; }
|
||||
|
||||
// inner classes
|
||||
Array<u2>* inner_classes() const { return _inner_classes; }
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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<FieldInfo>* 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<u1>* old_stream = scratch_class->fieldinfo_stream();
|
||||
assert(fields->length() == (java_fields + injected_fields), "Must be");
|
||||
Array<u1>* 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<u1>(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
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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<FilteredField*> *FilteredFieldsMap::_filtered_fields =
|
||||
new (mtServiceability) GrowableArray<FilteredField*>(3, mtServiceability);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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<Method*>*) \
|
||||
nonstatic_field(InstanceKlass, _local_interfaces, Array<InstanceKlass*>*) \
|
||||
nonstatic_field(InstanceKlass, _transitive_interfaces, Array<InstanceKlass*>*) \
|
||||
nonstatic_field(InstanceKlass, _fields, Array<u2>*) \
|
||||
nonstatic_field(InstanceKlass, _java_fields_count, u2) \
|
||||
nonstatic_field(InstanceKlass, _fieldinfo_stream, Array<u1>*) \
|
||||
nonstatic_field(InstanceKlass, _constants, ConstantPool*) \
|
||||
nonstatic_field(InstanceKlass, _source_debug_extension, const char*) \
|
||||
nonstatic_field(InstanceKlass, _inner_classes, Array<jushort>*) \
|
||||
@ -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 */ \
|
||||
/******************************/ \
|
||||
|
@ -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) {
|
||||
|
@ -258,8 +258,8 @@ class UNSIGNED5 : AllStatic {
|
||||
// MyReader r(array); while (r.has_next()) print(r.next_uint());
|
||||
template<typename ARR, typename OFF, typename GET = ArrayGetSet<ARR,OFF>>
|
||||
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());
|
||||
|
@ -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 " );
|
||||
|
@ -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;
|
||||
|
@ -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<Address, Field[]>();
|
||||
}
|
||||
|
||||
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<Address, Field[]> 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<Field> 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() {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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++;
|
||||
|
||||
|
@ -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("] ");
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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:
|
||||
*
|
||||
* <pre>
|
||||
* [ flags, // fieldDescriptor::access_flags()
|
||||
* offset, // fieldDescriptor::offset()
|
||||
* index // fieldDescriptor::index()
|
||||
* [ aflags, // fieldDescriptor::access_flags()
|
||||
* offset, // fieldDescriptor::offset()
|
||||
* index, // fieldDescriptor::index()
|
||||
* fflags // fieldDescriptor::field_flags()
|
||||
* ]
|
||||
* </pre>
|
||||
*
|
||||
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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<u2>*");
|
||||
final int instanceKlassFieldInfoStreamOffset = getFieldOffset("InstanceKlass::_fieldinfo_stream", Integer.class, "Array<u1>*");
|
||||
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<u1>::_data", Integer.class);
|
||||
final int arrayU2DataOffset = getFieldOffset("Array<u2>::_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.
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user