8367656: Refactor Constantpool's operand array into two

Reviewed-by: coleenp, sspitsyn, dholmes
This commit is contained in:
Johan Sjölen 2025-11-25 13:43:25 +00:00
parent c00d29afa9
commit d94c52ccf2
12 changed files with 610 additions and 456 deletions

View File

@ -449,7 +449,7 @@ bool AOTConstantPoolResolver::check_lambda_metafactory_signature(ConstantPool* c
}
bool AOTConstantPoolResolver::check_lambda_metafactory_methodtype_arg(ConstantPool* cp, int bsms_attribute_index, int arg_i) {
int mt_index = cp->bsm_attribute_entry(bsms_attribute_index)->argument_index(arg_i);
int mt_index = cp->bsm_attribute_entry(bsms_attribute_index)->argument(arg_i);
if (!cp->tag_at(mt_index).is_method_type()) {
// malformed class?
return false;
@ -465,7 +465,7 @@ bool AOTConstantPoolResolver::check_lambda_metafactory_methodtype_arg(ConstantPo
}
bool AOTConstantPoolResolver::check_lambda_metafactory_methodhandle_arg(ConstantPool* cp, int bsms_attribute_index, int arg_i) {
int mh_index = cp->bsm_attribute_entry(bsms_attribute_index)->argument_index(arg_i);
int mh_index = cp->bsm_attribute_entry(bsms_attribute_index)->argument(arg_i);
if (!cp->tag_at(mh_index).is_method_handle()) {
// malformed class?
return false;

View File

@ -47,6 +47,7 @@
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/annotations.hpp"
#include "oops/bsmAttribute.inline.hpp"
#include "oops/constantPool.inline.hpp"
#include "oops/fieldInfo.hpp"
#include "oops/fieldStreams.inline.hpp"
@ -3298,8 +3299,9 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil
TRAPS) {
assert(cfs != nullptr, "invariant");
assert(cp != nullptr, "invariant");
const int cp_size = cp->length();
const u1* const current_start = cfs->current();
const u1* const current_before_parsing = cfs->current();
guarantee_property(attribute_byte_length >= sizeof(u2),
"Invalid BootstrapMethods attribute length %u in class file %s",
@ -3308,57 +3310,40 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil
cfs->guarantee_more(attribute_byte_length, CHECK);
const int attribute_array_length = cfs->get_u2_fast();
const int num_bootstrap_methods = cfs->get_u2_fast();
guarantee_property(_max_bootstrap_specifier_index < attribute_array_length,
guarantee_property(_max_bootstrap_specifier_index < num_bootstrap_methods,
"Short length on BootstrapMethods in class file %s",
CHECK);
const u4 bootstrap_methods_u2_len = (attribute_byte_length - sizeof(u2)) / sizeof(u2);
// The attribute contains a counted array of counted tuples of shorts,
// represending bootstrap specifiers:
// length*{bootstrap_method_index, argument_count*{argument_index}}
const unsigned int operand_count = (attribute_byte_length - (unsigned)sizeof(u2)) / (unsigned)sizeof(u2);
// operand_count = number of shorts in attr, except for leading length
// The attribute is copied into a short[] array.
// The array begins with a series of short[2] pairs, one for each tuple.
const int index_size = (attribute_array_length * 2);
Array<u2>* const operands =
MetadataFactory::new_array<u2>(_loader_data, index_size + operand_count, CHECK);
// Eagerly assign operands so they will be deallocated with the constant
// Eagerly assign the arrays so that they will be deallocated with the constant
// pool if there is an error.
cp->set_operands(operands);
BSMAttributeEntries::InsertionIterator iter =
cp->bsm_entries().start_extension(num_bootstrap_methods,
bootstrap_methods_u2_len,
_loader_data,
CHECK);
int operand_fill_index = index_size;
const int cp_size = cp->length();
for (int n = 0; n < attribute_array_length; n++) {
// Store a 32-bit offset into the header of the operand array.
ConstantPool::operand_offset_at_put(operands, n, operand_fill_index);
// Read a bootstrap specifier.
for (int i = 0; i < num_bootstrap_methods; i++) {
cfs->guarantee_more(sizeof(u2) * 2, CHECK); // bsm, argc
const u2 bootstrap_method_index = cfs->get_u2_fast();
const u2 argument_count = cfs->get_u2_fast();
u2 bootstrap_method_ref = cfs->get_u2_fast();
u2 num_bootstrap_arguments = cfs->get_u2_fast();
guarantee_property(
valid_cp_range(bootstrap_method_index, cp_size) &&
cp->tag_at(bootstrap_method_index).is_method_handle(),
"bootstrap_method_index %u has bad constant type in class file %s",
bootstrap_method_index,
CHECK);
valid_cp_range(bootstrap_method_ref, cp_size) &&
cp->tag_at(bootstrap_method_ref).is_method_handle(),
"bootstrap_method_index %u has bad constant type in class file %s",
bootstrap_method_ref,
CHECK);
cfs->guarantee_more(sizeof(u2) * num_bootstrap_arguments, CHECK); // argv[argc]
guarantee_property((operand_fill_index + 1 + argument_count) < operands->length(),
"Invalid BootstrapMethods num_bootstrap_methods or num_bootstrap_arguments value in class file %s",
CHECK);
BSMAttributeEntry* entry = iter.reserve_new_entry(bootstrap_method_ref, num_bootstrap_arguments);
guarantee_property(entry != nullptr,
"Invalid BootstrapMethods num_bootstrap_methods."
" The total amount of space reserved for the BootstrapMethod attribute was not sufficient", CHECK);
operands->at_put(operand_fill_index++, bootstrap_method_index);
operands->at_put(operand_fill_index++, argument_count);
cfs->guarantee_more(sizeof(u2) * argument_count, CHECK); // argv[argc]
for (int j = 0; j < argument_count; j++) {
for (int argi = 0; argi < num_bootstrap_arguments; argi++) {
const u2 argument_index = cfs->get_u2_fast();
guarantee_property(
valid_cp_range(argument_index, cp_size) &&
@ -3366,10 +3351,11 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil
"argument_index %u has bad constant type in class file %s",
argument_index,
CHECK);
operands->at_put(operand_fill_index++, argument_index);
entry->set_argument(argi, argument_index);
}
}
guarantee_property(current_start + attribute_byte_length == cfs->current(),
cp->bsm_entries().end_extension(iter, _loader_data, CHECK);
guarantee_property(current_before_parsing + attribute_byte_length == cfs->current(),
"Bad length on BootstrapMethods in class file %s",
CHECK);
}

View File

@ -0,0 +1,170 @@
/*
* Copyright (c) 1997, 2025, 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_BSMATTRIBUTE_HPP
#define SHARE_OOPS_BSMATTRIBUTE_HPP
#include "oops/array.hpp"
#include "utilities/checkedCast.hpp"
#include "utilities/globalDefinitions.hpp"
class ClassLoaderData;
class BSMAttributeEntry {
friend class ConstantPool;
friend class BSMAttributeEntries;
u2 _bootstrap_method_index;
u2 _argument_count;
// The argument indexes are stored right after the object, in a contiguous array.
// [ bsmi_0 argc_0 arg_00 arg_01 ... arg_0N bsmi_1 argc_1 arg_10 ... arg_1N ... ]
// So in order to find the argument array, jump over ourselves.
const u2* argument_indexes() const {
return reinterpret_cast<const u2*>(this + 1);
}
u2* argument_indexes() {
return reinterpret_cast<u2*>(this + 1);
}
// These are overlays on top of the BSMAttributeEntries data array, do not construct.
BSMAttributeEntry() = delete;
NONCOPYABLE(BSMAttributeEntry);
void copy_args_into(BSMAttributeEntry* entry) const;
public:
// Offsets for SA
enum {
_bsmi_offset = 0,
_argc_offset = 1,
_argv_offset = 2
};
int bootstrap_method_index() const {
return _bootstrap_method_index;
}
int argument_count() const {
return _argument_count;
}
int argument(int n) const {
assert(checked_cast<u2>(n) < _argument_count, "oob");
return argument_indexes()[n];
}
void set_argument(int index, u2 value) {
assert(index >= 0 && index < argument_count(), "invariant");
argument_indexes()[index] = value;
}
// How many u2s are required to store a BSM entry with argc arguments?
static int u2s_required (u2 argc) {
return 1 /* index */ + 1 /* argc */ + argc /* argv */;
}
};
// The BSMAttributeEntries stores the state of the BootstrapMethods attribute.
class BSMAttributeEntries {
friend class VMStructs;
friend class JVMCIVMStructs;
public:
class InsertionIterator {
friend BSMAttributeEntries;
BSMAttributeEntries* _insert_into;
// Current unused offset into BSMAEs offset array.
int _cur_offset;
// Current unused offset into BSMAEs bsm-data array.
int _cur_array;
public:
InsertionIterator() : _insert_into(nullptr), _cur_offset(-1), _cur_array(-1) {}
InsertionIterator(BSMAttributeEntries* insert_into, int cur_offset, int cur_array)
: _insert_into(insert_into),
_cur_offset(cur_offset),
_cur_array(cur_array) {}
InsertionIterator(const InsertionIterator&) = default;
InsertionIterator& operator=(const InsertionIterator&) = default;
int current_offset() const { return _cur_offset; }
// Add a new BSMAE, reserving the necessary memory for filling the argument vector.
// Returns null if there isn't enough space.
inline BSMAttributeEntry* reserve_new_entry(u2 bsmi, u2 argc);
};
private:
// Each bootstrap method has a variable-sized array associated with it.
// We want constant-time lookup of the Nth BSM. Therefore, we use an offset table,
// such that the Nth BSM is located at _bootstrap_methods[_offsets[N]].
Array<u4>* _offsets;
Array<u2>* _bootstrap_methods;
// Copy the first num_entries into iter.
void copy_into(InsertionIterator& iter, int num_entries) const;
public:
BSMAttributeEntries() : _offsets(nullptr), _bootstrap_methods(nullptr) {}
BSMAttributeEntries(Array<u4>* offsets, Array<u2>* bootstrap_methods)
: _offsets(offsets),
_bootstrap_methods(bootstrap_methods) {}
bool is_empty() const {
return _offsets == nullptr && _bootstrap_methods == nullptr;
}
Array<u4>*& offsets() { return _offsets; }
const Array<u4>* const& offsets() const { return _offsets; }
Array<u2>*& bootstrap_methods() { return _bootstrap_methods; }
const Array<u2>* const& bootstrap_methods() const { return _bootstrap_methods; }
BSMAttributeEntry* entry(int bsms_attribute_index) {
return reinterpret_cast<BSMAttributeEntry*>(_bootstrap_methods->adr_at(_offsets->at(bsms_attribute_index)));
}
const BSMAttributeEntry* entry(int bsms_attribute_index) const {
return reinterpret_cast<BSMAttributeEntry*>(_bootstrap_methods->adr_at(_offsets->at(bsms_attribute_index)));
}
int number_of_entries() const {
return _offsets == nullptr ? 0 : _offsets->length();
}
// The number of U2s the BSM data consists of.
int array_length() const {
return _bootstrap_methods == nullptr ? 0 : _bootstrap_methods->length();
}
void deallocate_contents(ClassLoaderData* loader_data);
// Extend to have the space for both this BSMAEntries and other's.
// Does not copy in the other's BSMAEntrys, that must be done via the InsertionIterator.
// This starts an insertion iterator. Any call to start_extension must have a matching end_extension call.
InsertionIterator start_extension(const BSMAttributeEntries& other, ClassLoaderData* loader_data, TRAPS);
// Extend the BSMAEntries with an additional number_of_entries with a total data_size.
InsertionIterator start_extension(int number_of_entries, int data_size, ClassLoaderData* loader_data, TRAPS);
// Reallocates the underlying memory to fit the limits of the InsertionIterator precisely.
// This ends an insertion iteration. The memory is truncated to fit exactly the data used.
void end_extension(InsertionIterator& iter, ClassLoaderData* loader_data, TRAPS);
// Append all of the BSMAEs in other into this.
void append(const BSMAttributeEntries& other, ClassLoaderData* loader_data, TRAPS);
};
#endif // SHARE_OOPS_BSMATTRIBUTE_HPP

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2018, 2025, 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_BSMATTRIBUTE_INLINE_HPP
#define SHARE_OOPS_BSMATTRIBUTE_INLINE_HPP
#include "oops/bsmAttribute.hpp"
inline BSMAttributeEntry* BSMAttributeEntries::InsertionIterator::reserve_new_entry(u2 bsmi, u2 argc) {
assert(_insert_into->offsets() != nullptr, "must");
assert(_insert_into->bootstrap_methods() != nullptr, "must");
if (_cur_offset + 1 > _insert_into->offsets()->length() ||
_cur_array + BSMAttributeEntry::u2s_required(argc) > _insert_into->bootstrap_methods()->length()) {
return nullptr;
}
_insert_into->offsets()->at_put(_cur_offset, _cur_array);
BSMAttributeEntry* e = _insert_into->entry(_cur_offset);
e->_bootstrap_method_index = bsmi;
e->_argument_count = argc;
_cur_array += 1 + 1 + argc;
_cur_offset += 1;
return e;
}
inline void BSMAttributeEntry::copy_args_into(BSMAttributeEntry* entry) const {
assert(entry->argument_count() == this->argument_count(), "must be same");
for (int i = 0; i < argument_count(); i++) {
entry->set_argument(i, this->argument(i));
}
}
#endif // SHARE_OOPS_BSMATTRIBUTE_INLINE_HPP

View File

@ -131,8 +131,7 @@ void ConstantPool::deallocate_contents(ClassLoaderData* loader_data) {
MetadataFactory::free_array<Klass*>(loader_data, resolved_klasses());
set_resolved_klasses(nullptr);
MetadataFactory::free_array<jushort>(loader_data, operands());
set_operands(nullptr);
bsm_entries().deallocate_contents(loader_data);
release_C_heap_structures();
@ -152,7 +151,8 @@ void ConstantPool::metaspace_pointers_do(MetaspaceClosure* it) {
it->push(&_tags, MetaspaceClosure::_writable);
it->push(&_cache);
it->push(&_pool_holder);
it->push(&_operands);
it->push(&bsm_entries().offsets());
it->push(&bsm_entries().bootstrap_methods());
it->push(&_resolved_klasses, MetaspaceClosure::_writable);
for (int i = 0; i < length(); i++) {
@ -761,7 +761,7 @@ Method* ConstantPool::method_at_if_loaded(const constantPoolHandle& cpool,
if (cpool->cache() == nullptr) return nullptr; // nothing to load yet
if (!(which >= 0 && which < cpool->resolved_method_entries_length())) {
// FIXME: should be an assert
log_debug(class, resolve)("bad operand %d in:", which); cpool->print();
log_debug(class, resolve)("bad BSM %d in:", which); cpool->print();
return nullptr;
}
return cpool->cache()->method_if_resolved(which);
@ -1562,8 +1562,8 @@ bool ConstantPool::compare_entry_to(int index1, const constantPoolHandle& cp2,
int i1 = bootstrap_methods_attribute_index(index1);
int i2 = cp2->bootstrap_methods_attribute_index(index2);
bool match_entry = compare_entry_to(k1, cp2, k2);
bool match_operand = compare_operand_to(i1, cp2, i2);
return (match_entry && match_operand);
bool match_bsm = compare_bootstrap_entry_to(i1, cp2, i2);
return (match_entry && match_bsm);
} break;
case JVM_CONSTANT_InvokeDynamic:
@ -1573,8 +1573,8 @@ bool ConstantPool::compare_entry_to(int index1, const constantPoolHandle& cp2,
int i1 = bootstrap_methods_attribute_index(index1);
int i2 = cp2->bootstrap_methods_attribute_index(index2);
bool match_entry = compare_entry_to(k1, cp2, k2);
bool match_operand = compare_operand_to(i1, cp2, i2);
return (match_entry && match_operand);
bool match_bsm = compare_bootstrap_entry_to(i1, cp2, i2);
return (match_entry && match_bsm);
} break;
case JVM_CONSTANT_String:
@ -1608,140 +1608,29 @@ bool ConstantPool::compare_entry_to(int index1, const constantPoolHandle& cp2,
return false;
} // end compare_entry_to()
// Resize the operands array with delta_len and delta_size.
// Extend the BSMAttributeEntries with the length and size of the ext_cp BSMAttributeEntries.
// Used in RedefineClasses for CP merge.
void ConstantPool::resize_operands(int delta_len, int delta_size, TRAPS) {
int old_len = operand_array_length(operands());
int new_len = old_len + delta_len;
int min_len = (delta_len > 0) ? old_len : new_len;
int old_size = operands()->length();
int new_size = old_size + delta_size;
int min_size = (delta_size > 0) ? old_size : new_size;
ClassLoaderData* loader_data = pool_holder()->class_loader_data();
Array<u2>* new_ops = MetadataFactory::new_array<u2>(loader_data, new_size, CHECK);
// Set index in the resized array for existing elements only
for (int idx = 0; idx < min_len; idx++) {
int offset = operand_offset_at(idx); // offset in original array
operand_offset_at_put(new_ops, idx, offset + 2*delta_len); // offset in resized array
}
// Copy the bootstrap specifiers only
Copy::conjoint_memory_atomic(operands()->adr_at(2*old_len),
new_ops->adr_at(2*new_len),
(min_size - 2*min_len) * sizeof(u2));
// Explicitly deallocate old operands array.
// Note, it is not needed for 7u backport.
if ( operands() != nullptr) { // the safety check
MetadataFactory::free_array<u2>(loader_data, operands());
}
set_operands(new_ops);
} // end resize_operands()
BSMAttributeEntries::InsertionIterator
ConstantPool::start_extension(const constantPoolHandle& ext_cp, TRAPS) {
BSMAttributeEntries::InsertionIterator iter =
bsm_entries().start_extension(ext_cp->bsm_entries(), pool_holder()->class_loader_data(),
CHECK_(BSMAttributeEntries::InsertionIterator()));
return iter;
}
// Extend the operands array with the length and size of the ext_cp operands.
// Used in RedefineClasses for CP merge.
void ConstantPool::extend_operands(const constantPoolHandle& ext_cp, TRAPS) {
int delta_len = operand_array_length(ext_cp->operands());
if (delta_len == 0) {
return; // nothing to do
}
int delta_size = ext_cp->operands()->length();
assert(delta_len > 0 && delta_size > 0, "extended operands array must be bigger");
if (operand_array_length(operands()) == 0) {
ClassLoaderData* loader_data = pool_holder()->class_loader_data();
Array<u2>* new_ops = MetadataFactory::new_array<u2>(loader_data, delta_size, CHECK);
// The first element index defines the offset of second part
operand_offset_at_put(new_ops, 0, 2*delta_len); // offset in new array
set_operands(new_ops);
} else {
resize_operands(delta_len, delta_size, CHECK);
}
} // end extend_operands()
void ConstantPool::end_extension(BSMAttributeEntries::InsertionIterator iter, TRAPS) {
bsm_entries().end_extension(iter, pool_holder()->class_loader_data(), THREAD);
}
// Shrink the operands array to a smaller array with new_len length.
// Used in RedefineClasses for CP merge.
void ConstantPool::shrink_operands(int new_len, TRAPS) {
int old_len = operand_array_length(operands());
if (new_len == old_len) {
return; // nothing to do
}
assert(new_len < old_len, "shrunken operands array must be smaller");
int free_base = operand_next_offset_at(new_len - 1);
int delta_len = new_len - old_len;
int delta_size = 2*delta_len + free_base - operands()->length();
resize_operands(delta_len, delta_size, CHECK);
} // end shrink_operands()
void ConstantPool::copy_operands(const constantPoolHandle& from_cp,
const constantPoolHandle& to_cp,
TRAPS) {
int from_oplen = operand_array_length(from_cp->operands());
int old_oplen = operand_array_length(to_cp->operands());
if (from_oplen != 0) {
ClassLoaderData* loader_data = to_cp->pool_holder()->class_loader_data();
// append my operands to the target's operands array
if (old_oplen == 0) {
// Can't just reuse from_cp's operand list because of deallocation issues
int len = from_cp->operands()->length();
Array<u2>* new_ops = MetadataFactory::new_array<u2>(loader_data, len, CHECK);
Copy::conjoint_memory_atomic(
from_cp->operands()->adr_at(0), new_ops->adr_at(0), len * sizeof(u2));
to_cp->set_operands(new_ops);
} else {
int old_len = to_cp->operands()->length();
int from_len = from_cp->operands()->length();
int old_off = old_oplen * sizeof(u2);
int from_off = from_oplen * sizeof(u2);
// Use the metaspace for the destination constant pool
Array<u2>* new_operands = MetadataFactory::new_array<u2>(loader_data, old_len + from_len, CHECK);
int fillp = 0, len = 0;
// first part of dest
Copy::conjoint_memory_atomic(to_cp->operands()->adr_at(0),
new_operands->adr_at(fillp),
(len = old_off) * sizeof(u2));
fillp += len;
// first part of src
Copy::conjoint_memory_atomic(from_cp->operands()->adr_at(0),
new_operands->adr_at(fillp),
(len = from_off) * sizeof(u2));
fillp += len;
// second part of dest
Copy::conjoint_memory_atomic(to_cp->operands()->adr_at(old_off),
new_operands->adr_at(fillp),
(len = old_len - old_off) * sizeof(u2));
fillp += len;
// second part of src
Copy::conjoint_memory_atomic(from_cp->operands()->adr_at(from_off),
new_operands->adr_at(fillp),
(len = from_len - from_off) * sizeof(u2));
fillp += len;
assert(fillp == new_operands->length(), "");
// Adjust indexes in the first part of the copied operands array.
for (int j = 0; j < from_oplen; j++) {
int offset = operand_offset_at(new_operands, old_oplen + j);
assert(offset == operand_offset_at(from_cp->operands(), j), "correct copy");
offset += old_len; // every new tuple is preceded by old_len extra u2's
operand_offset_at_put(new_operands, old_oplen + j, offset);
}
// replace target operands array with combined array
to_cp->set_operands(new_operands);
}
}
} // end copy_operands()
void ConstantPool::copy_bsm_entries(const constantPoolHandle& from_cp,
const constantPoolHandle& to_cp,
TRAPS) {
to_cp->bsm_entries().append(from_cp->bsm_entries(),
to_cp->pool_holder()->class_loader_data(),
THREAD);
}
// Copy this constant pool's entries at start_i to end_i (inclusive)
@ -1771,7 +1660,7 @@ void ConstantPool::copy_cp_to_impl(const constantPoolHandle& from_cp, int start_
break;
}
}
copy_operands(from_cp, to_cp, CHECK);
copy_bsm_entries(from_cp, to_cp, THREAD);
} // end copy_cp_to_impl()
@ -1895,7 +1784,7 @@ void ConstantPool::copy_entry_to(const constantPoolHandle& from_cp, int from_i,
{
int k1 = from_cp->bootstrap_methods_attribute_index(from_i);
int k2 = from_cp->bootstrap_name_and_type_ref_index_at(from_i);
k1 += operand_array_length(to_cp->operands()); // to_cp might already have operands
k1 += to_cp->bsm_entries().array_length(); // to_cp might already have a BSM attribute
to_cp->dynamic_constant_at_put(to_i, k1, k2);
} break;
@ -1903,7 +1792,7 @@ void ConstantPool::copy_entry_to(const constantPoolHandle& from_cp, int from_i,
{
int k1 = from_cp->bootstrap_methods_attribute_index(from_i);
int k2 = from_cp->bootstrap_name_and_type_ref_index_at(from_i);
k1 += operand_array_length(to_cp->operands()); // to_cp might already have operands
k1 += to_cp->bsm_entries().array_length(); // to_cp might already have a BSM attribute
to_cp->invoke_dynamic_at_put(to_i, k1, k2);
} break;
@ -1939,9 +1828,9 @@ int ConstantPool::find_matching_entry(int pattern_i,
// Compare this constant pool's bootstrap specifier at idx1 to the constant pool
// cp2's bootstrap specifier at idx2.
bool ConstantPool::compare_operand_to(int idx1, const constantPoolHandle& cp2, int idx2) {
BSMAttributeEntry* e1 = bsm_attribute_entry(idx1);
BSMAttributeEntry* e2 = cp2->bsm_attribute_entry(idx2);
bool ConstantPool::compare_bootstrap_entry_to(int idx1, const constantPoolHandle& cp2, int idx2) {
const BSMAttributeEntry* const e1 = bsm_attribute_entry(idx1);
const BSMAttributeEntry* const e2 = cp2->bsm_attribute_entry(idx2);
int k1 = e1->bootstrap_method_index();
int k2 = e2->bootstrap_method_index();
bool match = compare_entry_to(k1, cp2, k2);
@ -1949,34 +1838,37 @@ bool ConstantPool::compare_operand_to(int idx1, const constantPoolHandle& cp2, i
if (!match) {
return false;
}
int argc = e1->argument_count();
if (argc == e2->argument_count()) {
for (int j = 0; j < argc; j++) {
k1 = e1->argument_index(j);
k2 = e2->argument_index(j);
match = compare_entry_to(k1, cp2, k2);
if (!match) {
return false;
}
}
return true; // got through loop; all elements equal
const int argc = e1->argument_count();
if (argc != e2->argument_count()) {
return false;
}
return false;
} // end compare_operand_to()
for (int j = 0; j < argc; j++) {
k1 = e1->argument(j);
k2 = e2->argument(j);
match = compare_entry_to(k1, cp2, k2);
if (!match) {
return false;
}
}
return true; // got through loop; all elements equal
} // end compare_bootstrap_entry_to()
// Search constant pool search_cp for a bootstrap specifier that matches
// this constant pool's bootstrap specifier data at pattern_i index.
// Return the index of a matching bootstrap attribute record or (-1) if there is no match.
int ConstantPool::find_matching_operand(int pattern_i,
const constantPoolHandle& search_cp, int search_len) {
for (int i = 0; i < search_len; i++) {
bool found = compare_operand_to(pattern_i, search_cp, i);
int ConstantPool::find_matching_bsm_entry(int pattern_i,
const constantPoolHandle& search_cp, int offset_limit) {
for (int i = 0; i < offset_limit; i++) {
bool found = compare_bootstrap_entry_to(pattern_i, search_cp, i);
if (found) {
return i;
}
}
return -1; // bootstrap specifier data not found; return unused index (-1)
} // end find_matching_operand()
} // end find_matching_bsm_entry()
#ifndef PRODUCT
@ -2411,7 +2303,7 @@ void ConstantPool::print_value_on(outputStream* st) const {
assert(is_constantPool(), "must be constantPool");
st->print("constant pool [%d]", length());
if (has_preresolution()) st->print("/preresolution");
if (operands() != nullptr) st->print("/operands[%d]", operands()->length());
if (!bsm_entries().is_empty()) st->print("/BSMs[%d]", bsm_entries().bootstrap_methods()->length());
print_address_on(st);
if (pool_holder() != nullptr) {
st->print(" for ");
@ -2446,3 +2338,87 @@ void ConstantPool::verify_on(outputStream* st) {
guarantee(pool_holder()->is_klass(), "should be klass");
}
}
void BSMAttributeEntries::deallocate_contents(ClassLoaderData* loader_data) {
MetadataFactory::free_array<u4>(loader_data, this->_offsets);
MetadataFactory::free_array<u2>(loader_data, this->_bootstrap_methods);
this->_offsets = nullptr;
this->_bootstrap_methods = nullptr;
}
void BSMAttributeEntries::copy_into(InsertionIterator& iter, int num_entries) const {
assert(num_entries + iter._cur_offset <= iter._insert_into->_offsets->length(), "must");
for (int i = 0; i < num_entries; i++) {
const BSMAttributeEntry* e = entry(i);
BSMAttributeEntry* e_new = iter.reserve_new_entry(e->bootstrap_method_index(), e->argument_count());
assert(e_new != nullptr, "must be");
e->copy_args_into(e_new);
}
}
BSMAttributeEntries::InsertionIterator
BSMAttributeEntries::start_extension(const BSMAttributeEntries& other, ClassLoaderData* loader_data, TRAPS) {
InsertionIterator iter = start_extension(other.number_of_entries(), other.array_length(),
loader_data, CHECK_(BSMAttributeEntries::InsertionIterator()));
return iter;
}
BSMAttributeEntries::InsertionIterator
BSMAttributeEntries::start_extension(int number_of_entries, int array_length,
ClassLoaderData* loader_data, TRAPS) {
InsertionIterator extension_iterator(this, this->number_of_entries(), this->array_length());
int new_number_of_entries = this->number_of_entries() + number_of_entries;
int new_array_length = this->array_length() + array_length;
int invalid_index = new_array_length;
Array<u4>* new_offsets =
MetadataFactory::new_array<u4>(loader_data, new_number_of_entries, invalid_index, CHECK_(InsertionIterator()));
Array<u2>* new_array = MetadataFactory::new_array<u2>(loader_data, new_array_length, CHECK_(InsertionIterator()));
{ // Copy over all the old BSMAEntry's and their respective offsets
BSMAttributeEntries carrier(new_offsets, new_array);
InsertionIterator copy_iter(&carrier, 0, 0);
copy_into(copy_iter, this->number_of_entries());
}
// Replace content
deallocate_contents(loader_data);
_offsets = new_offsets;
_bootstrap_methods = new_array;
return extension_iterator;
}
void BSMAttributeEntries::append(const BSMAttributeEntries& other, ClassLoaderData* loader_data, TRAPS) {
if (other.number_of_entries() == 0) {
return; // Done!
}
InsertionIterator iter = start_extension(other, loader_data, CHECK);
other.copy_into(iter, other.number_of_entries());
end_extension(iter, loader_data, THREAD);
}
void BSMAttributeEntries::end_extension(InsertionIterator& iter, ClassLoaderData* loader_data, TRAPS) {
assert(iter._insert_into == this, "must be");
assert(iter._cur_offset <= this->_offsets->length(), "must be");
assert(iter._cur_array <= this->_bootstrap_methods->length(), "must be");
// Did we fill up all of the available space? If so, do nothing.
if (iter._cur_offset == this->_offsets->length() &&
iter._cur_array == this->_bootstrap_methods->length()) {
return;
}
// We used less, truncate by allocating new arrays
Array<u4>* new_offsets =
MetadataFactory::new_array<u4>(loader_data, iter._cur_offset, 0, CHECK);
Array<u2>* new_array =
MetadataFactory::new_array<u2>(loader_data, iter._cur_array, CHECK);
{ // Copy over the constructed BSMAEntry's
BSMAttributeEntries carrier(new_offsets, new_array);
InsertionIterator copy_iter(&carrier, 0, 0);
copy_into(copy_iter, iter._cur_offset);
}
deallocate_contents(loader_data);
_offsets = new_offsets;
_bootstrap_methods = new_array;
}

View File

@ -27,6 +27,7 @@
#include "memory/allocation.hpp"
#include "oops/arrayOop.hpp"
#include "oops/bsmAttribute.inline.hpp"
#include "oops/cpCache.hpp"
#include "oops/objArrayOop.hpp"
#include "oops/oopHandle.hpp"
@ -77,43 +78,6 @@ public:
}
};
class BSMAttributeEntry {
friend class ConstantPool;
u2 _bootstrap_method_index;
u2 _argument_count;
// The argument indexes are stored right after the object, in a contiguous array.
// [ bsmi_0 argc_0 arg_00 arg_01 ... arg_0N bsmi_1 argc_1 arg_10 ... arg_1N ... ]
// So in order to find the argument array, jump over ourselves.
const u2* argument_indexes() const {
return reinterpret_cast<const u2*>(this + 1);
}
u2* argument_indexes() {
return reinterpret_cast<u2*>(this + 1);
}
// These are overlays on top of the operands array. Do not construct.
BSMAttributeEntry() = delete;
public:
// Offsets for SA
enum {
_bsmi_offset = 0,
_argc_offset = 1,
_argv_offset = 2
};
int bootstrap_method_index() const {
return _bootstrap_method_index;
}
int argument_count() const {
return _argument_count;
}
int argument_index(int n) const {
assert(checked_cast<u2>(n) < _argument_count, "oob");
return argument_indexes()[n];
}
};
class ConstantPool : public Metadata {
friend class VMStructs;
friend class JVMCIVMStructs;
@ -126,7 +90,8 @@ class ConstantPool : public Metadata {
Array<u1>* _tags; // the tag array describing the constant pool's contents
ConstantPoolCache* _cache; // the cache holding interpreter runtime information
InstanceKlass* _pool_holder; // the corresponding class
Array<u2>* _operands; // for variable-sized (InvokeDynamic) nodes, usually empty
BSMAttributeEntries _bsm_entries;
// Consider using an array of compressed klass pointers to
// save space on 64-bit platforms.
@ -167,8 +132,6 @@ class ConstantPool : public Metadata {
u1* tag_addr_at(int cp_index) const { return tags()->adr_at(cp_index); }
void set_operands(Array<u2>* operands) { _operands = operands; }
u2 flags() const { return _flags; }
void set_flags(u2 f) { _flags = f; }
@ -208,7 +171,13 @@ class ConstantPool : public Metadata {
virtual bool is_constantPool() const { return true; }
Array<u1>* tags() const { return _tags; }
Array<u2>* operands() const { return _operands; }
BSMAttributeEntries& bsm_entries() {
return _bsm_entries;
}
const BSMAttributeEntries& bsm_entries() const {
return _bsm_entries;
}
bool has_preresolution() const { return (_flags & _has_preresolution) != 0; }
void set_has_preresolution() {
@ -556,76 +525,21 @@ class ConstantPool : public Metadata {
assert(tag_at(cp_index).has_bootstrap(), "Corrupted constant pool");
return extract_low_short_from_int(*int_at_addr(cp_index));
}
// The first part of the operands array consists of an index into the second part.
// Extract a 32-bit index value from the first part.
static int operand_offset_at(Array<u2>* operands, int bsms_attribute_index) {
int n = (bsms_attribute_index * 2);
assert(n >= 0 && n+2 <= operands->length(), "oob");
// The first 32-bit index points to the beginning of the second part
// of the operands array. Make sure this index is in the first part.
DEBUG_ONLY(int second_part = build_int_from_shorts(operands->at(0),
operands->at(1)));
assert(second_part == 0 || n+2 <= second_part, "oob (2)");
int offset = build_int_from_shorts(operands->at(n+0),
operands->at(n+1));
// The offset itself must point into the second part of the array.
assert(offset == 0 || (offset >= second_part && offset <= operands->length()), "oob (3)");
return offset;
}
static void operand_offset_at_put(Array<u2>* operands, int bsms_attribute_index, int offset) {
int n = bsms_attribute_index * 2;
assert(n >= 0 && n+2 <= operands->length(), "oob");
operands->at_put(n+0, extract_low_short_from_int(offset));
operands->at_put(n+1, extract_high_short_from_int(offset));
}
static int operand_array_length(Array<u2>* operands) {
if (operands == nullptr || operands->length() == 0) return 0;
int second_part = operand_offset_at(operands, 0);
return (second_part / 2);
}
#ifdef ASSERT
// operand tuples fit together exactly, end to end
static int operand_limit_at(Array<u2>* operands, int bsms_attribute_index) {
int nextidx = bsms_attribute_index + 1;
if (nextidx == operand_array_length(operands))
return operands->length();
else
return operand_offset_at(operands, nextidx);
}
#endif //ASSERT
// These functions are used in RedefineClasses for CP merge
int operand_offset_at(int bsms_attribute_index) {
assert(0 <= bsms_attribute_index &&
bsms_attribute_index < operand_array_length(operands()),
"Corrupted CP operands");
return operand_offset_at(operands(), bsms_attribute_index);
}
BSMAttributeEntry* bsm_attribute_entry(int bsms_attribute_index) {
int offset = operand_offset_at(bsms_attribute_index);
return reinterpret_cast<BSMAttributeEntry*>(operands()->adr_at(offset));
return _bsm_entries.entry(bsms_attribute_index);
}
int operand_next_offset_at(int bsms_attribute_index) {
BSMAttributeEntry* bsme = bsm_attribute_entry(bsms_attribute_index);
u2* argv_start = bsme->argument_indexes();
int offset = argv_start - operands()->data();
return offset + bsme->argument_count();
}
// Compare a bootstrap specifier data in the operands arrays
bool compare_operand_to(int bsms_attribute_index1, const constantPoolHandle& cp2,
int bsms_attribute_index2);
// Find a bootstrap specifier data in the operands array
int find_matching_operand(int bsms_attribute_index, const constantPoolHandle& search_cp,
int operands_cur_len);
// Resize the operands array with delta_len and delta_size
void resize_operands(int delta_len, int delta_size, TRAPS);
// Extend the operands array with the length and size of the ext_cp operands
void extend_operands(const constantPoolHandle& ext_cp, TRAPS);
// Shrink the operands array to a smaller array with new_len length
void shrink_operands(int new_len, TRAPS);
bool compare_bootstrap_entry_to(int bsms_attribute_index1, const constantPoolHandle& cp2,
int bsms_attribute_index2);
// Find a BSM entry in search_cp that matches the BSM at bsm_attribute_index.
// Return -1 if not found.
int find_matching_bsm_entry(int bsms_attribute_index, const constantPoolHandle& search_cp,
int offset_limit);
// Extend the BSM attribute storage to fit both the current data and the BSM data in ext_cp.
// Use the returned InsertionIterator to fill out the newly allocated space.
BSMAttributeEntries::InsertionIterator start_extension(const constantPoolHandle& ext_cp, TRAPS);
void end_extension(BSMAttributeEntries::InsertionIterator iter, TRAPS);
u2 bootstrap_method_ref_index_at(int cp_index) {
assert(tag_at(cp_index).has_bootstrap(), "Corrupted constant pool");
@ -641,7 +555,7 @@ class ConstantPool : public Metadata {
int bsmai = bootstrap_methods_attribute_index(cp_index);
BSMAttributeEntry* bsme = bsm_attribute_entry(bsmai);
assert((uint)j < (uint)bsme->argument_count(), "oob");
return bsm_attribute_entry(bsmai)->argument_index(j);
return bsm_attribute_entry(bsmai)->argument(j);
}
// The following methods (name/signature/klass_ref_at, klass_ref_at_noresolve,
@ -848,7 +762,7 @@ private:
}
static void copy_cp_to_impl(const constantPoolHandle& from_cp, int start_cpi, int end_cpi, const constantPoolHandle& to_cp, int to_cpi, TRAPS);
static void copy_entry_to(const constantPoolHandle& from_cp, int from_cpi, const constantPoolHandle& to_cp, int to_cpi);
static void copy_operands(const constantPoolHandle& from_cp, const constantPoolHandle& to_cp, TRAPS);
static void copy_bsm_entries(const constantPoolHandle& from_cp, const constantPoolHandle& to_cp, TRAPS);
int find_matching_entry(int pattern_i, const constantPoolHandle& search_cp);
int version() const { return _saved._version; }
void set_version(int version) { _saved._version = version; }

View File

@ -25,6 +25,7 @@
#include "classfile/symbolTable.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "memory/universe.hpp"
#include "oops/bsmAttribute.inline.hpp"
#include "oops/constantPool.inline.hpp"
#include "oops/fieldStreams.inline.hpp"
#include "oops/instanceKlass.inline.hpp"
@ -389,20 +390,13 @@ void JvmtiClassFileReconstituter::write_annotations_attribute(const char* attr_n
// } bootstrap_methods[num_bootstrap_methods];
// }
void JvmtiClassFileReconstituter::write_bootstrapmethod_attribute() {
Array<u2>* operands = cpool()->operands();
write_attribute_name_index("BootstrapMethods");
int num_bootstrap_methods = ConstantPool::operand_array_length(operands);
// calculate length of attribute
u4 length = sizeof(u2); // num_bootstrap_methods
for (int n = 0; n < num_bootstrap_methods; n++) {
u2 num_bootstrap_arguments = cpool()->bsm_attribute_entry(n)->argument_count();
length += sizeof(u2); // bootstrap_method_ref
length += sizeof(u2); // num_bootstrap_arguments
length += (u4)sizeof(u2) * num_bootstrap_arguments; // bootstrap_arguments[num_bootstrap_arguments]
}
u4 length = sizeof(u2) + // Size of num_bootstrap_methods
// The rest of the data for the attribute is exactly the u2s in the data array.
sizeof(u2) * cpool()->bsm_entries().array_length();
write_u4(length);
int num_bootstrap_methods = cpool()->bsm_entries().number_of_entries();
// write attribute
write_u2(checked_cast<u2>(num_bootstrap_methods));
for (int n = 0; n < num_bootstrap_methods; n++) {
@ -411,7 +405,7 @@ void JvmtiClassFileReconstituter::write_bootstrapmethod_attribute() {
write_u2(bsme->bootstrap_method_index());
write_u2(num_bootstrap_arguments);
for (int arg = 0; arg < num_bootstrap_arguments; arg++) {
u2 bootstrap_argument = bsme->argument_index(arg);
u2 bootstrap_argument = bsme->argument(arg);
write_u2(bootstrap_argument);
}
}
@ -798,7 +792,7 @@ void JvmtiClassFileReconstituter::write_class_attributes() {
if (type_anno != nullptr) {
++attr_count; // has RuntimeVisibleTypeAnnotations attribute
}
if (cpool()->operands() != nullptr) {
if (!cpool()->bsm_entries().is_empty()) {
++attr_count;
}
if (ik()->nest_host_index() != 0) {
@ -843,7 +837,7 @@ void JvmtiClassFileReconstituter::write_class_attributes() {
if (ik()->record_components() != nullptr) {
write_record_attribute();
}
if (cpool()->operands() != nullptr) {
if (!cpool()->bsm_entries().is_empty()) {
write_bootstrapmethod_attribute();
}
if (inner_classes_length > 0) {

View File

@ -45,7 +45,8 @@
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/annotations.hpp"
#include "oops/constantPool.hpp"
#include "oops/bsmAttribute.inline.hpp"
#include "oops/constantPool.inline.hpp"
#include "oops/fieldStreams.inline.hpp"
#include "oops/klass.inline.hpp"
#include "oops/klassVtable.hpp"
@ -573,9 +574,9 @@ void VM_RedefineClasses::append_entry(const constantPoolHandle& scratch_cp,
case JVM_CONSTANT_Dynamic: // fall through
case JVM_CONSTANT_InvokeDynamic:
{
// Index of the bootstrap specifier in the operands array
// Index of the bootstrap specifier in the BSM array
int old_bs_i = scratch_cp->bootstrap_methods_attribute_index(scratch_i);
int new_bs_i = find_or_append_operand(scratch_cp, old_bs_i, merge_cp_p,
int new_bs_i = find_or_append_bsm_entry(scratch_cp, old_bs_i, merge_cp_p,
merge_cp_length_p);
// The bootstrap method NameAndType_info index
int old_ref_i = scratch_cp->bootstrap_name_and_type_ref_index_at(scratch_i);
@ -591,10 +592,11 @@ void VM_RedefineClasses::append_entry(const constantPoolHandle& scratch_cp,
("Dynamic entry@%d name_and_type_index change: %d to %d", *merge_cp_length_p, old_ref_i, new_ref_i);
}
if (scratch_cp->tag_at(scratch_i).is_dynamic_constant())
if (scratch_cp->tag_at(scratch_i).is_dynamic_constant()) {
(*merge_cp_p)->dynamic_constant_at_put(*merge_cp_length_p, new_bs_i, new_ref_i);
else
} else {
(*merge_cp_p)->invoke_dynamic_at_put(*merge_cp_length_p, new_bs_i, new_ref_i);
}
if (scratch_i != *merge_cp_length_p) {
// The new entry in *merge_cp_p is at a different index than
// the new entry in scratch_cp so we need to map the index values.
@ -660,10 +662,10 @@ u2 VM_RedefineClasses::find_or_append_indirect_entry(const constantPoolHandle& s
} // end find_or_append_indirect_entry()
// Append a bootstrap specifier into the merge_cp operands that is semantically equal
// to the scratch_cp operands bootstrap specifier passed by the old_bs_i index.
// Append a bootstrap specifier into the merge_cp BSM entries that is semantically equal
// to the scratch_cp BSM entries' bootstrap specifier passed by the old_bs_i index.
// Recursively append new merge_cp entries referenced by the new bootstrap specifier.
void VM_RedefineClasses::append_operand(const constantPoolHandle& scratch_cp, const int old_bs_i,
int VM_RedefineClasses::append_bsm_entry(const constantPoolHandle& scratch_cp, const int old_bs_i,
constantPoolHandle *merge_cp_p, int *merge_cp_length_p) {
BSMAttributeEntry* old_bsme = scratch_cp->bsm_attribute_entry(old_bs_i);
@ -672,90 +674,82 @@ void VM_RedefineClasses::append_operand(const constantPoolHandle& scratch_cp, co
merge_cp_length_p);
if (new_ref_i != old_ref_i) {
log_trace(redefine, class, constantpool)
("operands entry@%d bootstrap method ref_index change: %d to %d", _operands_cur_length, old_ref_i, new_ref_i);
("BSM attribute entry@%d bootstrap method ref_index change: %d to %d", _bsmae_iter.current_offset() - 1, old_ref_i, new_ref_i);
}
Array<u2>* merge_ops = (*merge_cp_p)->operands();
int new_bs_i = _operands_cur_length;
// We have _operands_cur_length == 0 when the merge_cp operands is empty yet.
// However, the operand_offset_at(0) was set in the extend_operands() call.
int new_base = (new_bs_i == 0) ? (*merge_cp_p)->operand_offset_at(0)
: (*merge_cp_p)->operand_next_offset_at(new_bs_i - 1);
u2 argc = old_bsme->argument_count();
ConstantPool::operand_offset_at_put(merge_ops, _operands_cur_length, new_base);
merge_ops->at_put(new_base++, new_ref_i);
merge_ops->at_put(new_base++, argc);
for (int i = 0; i < argc; i++) {
u2 old_arg_ref_i = old_bsme->argument_index(i);
const int new_bs_i = _bsmae_iter.current_offset();
BSMAttributeEntry* new_bsme =
_bsmae_iter.reserve_new_entry(new_ref_i, old_bsme->argument_count());
assert(new_bsme != nullptr, "must be");
for (int i = 0; i < new_bsme->argument_count(); i++) {
u2 old_arg_ref_i = old_bsme->argument(i);
u2 new_arg_ref_i = find_or_append_indirect_entry(scratch_cp, old_arg_ref_i, merge_cp_p,
merge_cp_length_p);
merge_ops->at_put(new_base++, new_arg_ref_i);
new_bsme->set_argument(i, new_arg_ref_i);
if (new_arg_ref_i != old_arg_ref_i) {
log_trace(redefine, class, constantpool)
("operands entry@%d bootstrap method argument ref_index change: %d to %d",
_operands_cur_length, old_arg_ref_i, new_arg_ref_i);
("BSM attribute entry@%d bootstrap method argument ref_index change: %d to %d",
_bsmae_iter.current_offset() - 1, old_arg_ref_i, new_arg_ref_i);
}
}
if (old_bs_i != _operands_cur_length) {
// The bootstrap specifier in *merge_cp_p is at a different index than
// that in scratch_cp so we need to map the index values.
map_operand_index(old_bs_i, new_bs_i);
}
_operands_cur_length++;
} // end append_operand()
// This is only for the logging
map_bsm_index(old_bs_i, new_bs_i);
return new_bs_i;
} // end append_bsm_entry()
int VM_RedefineClasses::find_or_append_operand(const constantPoolHandle& scratch_cp,
int VM_RedefineClasses::find_or_append_bsm_entry(const constantPoolHandle& scratch_cp,
int old_bs_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p) {
const int max_offset_in_merge = _bsmae_iter.current_offset();
int new_bs_i = old_bs_i; // bootstrap specifier index
bool match = (old_bs_i < _operands_cur_length) &&
scratch_cp->compare_operand_to(old_bs_i, *merge_cp_p, old_bs_i);
// Has the old_bs_i index been used already? Check if it's the same so we know
// whether or not a remapping is required.
bool match = (old_bs_i < max_offset_in_merge) &&
scratch_cp->compare_bootstrap_entry_to(old_bs_i, *merge_cp_p, old_bs_i);
if (!match) {
// forward reference in *merge_cp_p or not a direct match
int found_i = scratch_cp->find_matching_operand(old_bs_i, *merge_cp_p,
_operands_cur_length);
int found_i = scratch_cp->find_matching_bsm_entry(old_bs_i, *merge_cp_p,
max_offset_in_merge);
if (found_i != -1) {
guarantee(found_i != old_bs_i, "compare_operand_to() and find_matching_operand() disagree");
// found a matching operand somewhere else in *merge_cp_p so just need a mapping
guarantee(found_i != old_bs_i, "compare_bootstrap_entry_to() and find_matching_bsm_entry() disagree");
// found a matching BSM entry somewhere else in *merge_cp_p so just need a mapping
new_bs_i = found_i;
map_operand_index(old_bs_i, found_i);
map_bsm_index(old_bs_i, found_i);
} else {
// no match found so we have to append this bootstrap specifier to *merge_cp_p
append_operand(scratch_cp, old_bs_i, merge_cp_p, merge_cp_length_p);
new_bs_i = _operands_cur_length - 1;
new_bs_i = append_bsm_entry(scratch_cp, old_bs_i, merge_cp_p, merge_cp_length_p);
}
}
return new_bs_i;
} // end find_or_append_operand()
} // end find_or_append_bsm_entry()
void VM_RedefineClasses::finalize_operands_merge(const constantPoolHandle& merge_cp, TRAPS) {
if (merge_cp->operands() == nullptr) {
void VM_RedefineClasses::finalize_bsm_entries_merge(const constantPoolHandle& merge_cp, TRAPS) {
if (merge_cp->bsm_entries().number_of_entries() == 0) {
return;
}
// Shrink the merge_cp operands
merge_cp->shrink_operands(_operands_cur_length, CHECK);
// Finished extending the BSMAEs
merge_cp->end_extension(_bsmae_iter, CHECK);
if (log_is_enabled(Trace, redefine, class, constantpool)) {
// don't want to loop unless we are tracing
int count = 0;
for (int i = 1; i < _operands_index_map_p->length(); i++) {
int value = _operands_index_map_p->at(i);
for (int i = 1; i < _bsm_index_map_p->length(); i++) {
int value = _bsm_index_map_p->at(i);
if (value != -1) {
log_trace(redefine, class, constantpool)("operands_index_map[%d]: old=%d new=%d", count, i, value);
log_trace(redefine, class, constantpool)("bsm_index_map[%d]: old=%d new=%d", count, i, value);
count++;
}
}
}
// Clean-up
_operands_index_map_p = nullptr;
_operands_cur_length = 0;
_operands_index_map_count = 0;
} // end finalize_operands_merge()
_bsm_index_map_p = nullptr;
_bsm_index_map_count = 0;
_bsmae_iter = BSMAttributeEntries::InsertionIterator();
} // end finalize_bsmentries_merge()
// Symbol* comparator for qsort
// The caller must have an active ResourceMark.
@ -1272,26 +1266,26 @@ u2 VM_RedefineClasses::find_new_index(int old_index) {
// Find new bootstrap specifier index value for old bootstrap specifier index
// value by searching the index map. Returns unused index (-1) if there is
// no mapped value for the old bootstrap specifier index.
int VM_RedefineClasses::find_new_operand_index(int old_index) {
if (_operands_index_map_count == 0) {
int VM_RedefineClasses::find_new_bsm_index(int old_index) {
if (_bsm_index_map_count == 0) {
// map is empty so nothing can be found
return -1;
}
if (old_index == -1 || old_index >= _operands_index_map_p->length()) {
if (old_index == -1 || old_index >= _bsm_index_map_p->length()) {
// The old_index is out of range so it is not mapped.
// This should not happen in regular constant pool merging use.
return -1;
}
int value = _operands_index_map_p->at(old_index);
int value = _bsm_index_map_p->at(old_index);
if (value == -1) {
// the old_index is not mapped
return -1;
}
return value;
} // end find_new_operand_index()
} // end find_new_bsm_index()
// The bug 6214132 caused the verification to fail.
@ -1560,22 +1554,15 @@ void VM_RedefineClasses::map_index(const constantPoolHandle& scratch_cp,
// Map old_index to new_index as needed.
void VM_RedefineClasses::map_operand_index(int old_index, int new_index) {
if (find_new_operand_index(old_index) != -1) {
// old_index is already mapped
return;
}
void VM_RedefineClasses::map_bsm_index(int old_index, int new_index) {
if (old_index == new_index) {
// no mapping is needed
return;
}
_operands_index_map_p->at_put(old_index, new_index);
_operands_index_map_count++;
_bsm_index_map_p->at_put(old_index, new_index);
_bsm_index_map_count++;
log_trace(redefine, class, constantpool)("mapped bootstrap specifier at index %d to %d", old_index, new_index);
} // end map_index()
} // end map_bsm_index()
// Merge old_cp and scratch_cp and return the results of the merge via
@ -1639,8 +1626,8 @@ bool VM_RedefineClasses::merge_constant_pools(const constantPoolHandle& old_cp,
}
} // end for each old_cp entry
ConstantPool::copy_operands(old_cp, merge_cp_p, CHECK_false);
merge_cp_p->extend_operands(scratch_cp, CHECK_false);
ConstantPool::copy_bsm_entries(old_cp, merge_cp_p, CHECK_false);
_bsmae_iter = merge_cp_p->start_extension(scratch_cp, CHECK_false);
// We don't need to sanity check that *merge_cp_length_p is within
// *merge_cp_p bounds since we have the minimum on-entry check above.
@ -1737,7 +1724,7 @@ bool VM_RedefineClasses::merge_constant_pools(const constantPoolHandle& old_cp,
("after pass 1b: merge_cp_len=%d, scratch_i=%d, index_map_len=%d",
merge_cp_length_p, scratch_i, _index_map_count);
}
finalize_operands_merge(merge_cp_p, CHECK_false);
finalize_bsm_entries_merge(merge_cp_p, CHECK_false);
return true;
} // end merge_constant_pools()
@ -1807,12 +1794,11 @@ jvmtiError VM_RedefineClasses::merge_cp_and_rewrite(
_index_map_count = 0;
_index_map_p = new intArray(scratch_cp->length(), scratch_cp->length(), -1);
_operands_cur_length = ConstantPool::operand_array_length(old_cp->operands());
_operands_index_map_count = 0;
int operands_index_map_len = ConstantPool::operand_array_length(scratch_cp->operands());
_operands_index_map_p = new intArray(operands_index_map_len, operands_index_map_len, -1);
_bsm_index_map_count = 0;
int bsm_data_len = scratch_cp->bsm_entries().array_length();
_bsm_index_map_p = new intArray(bsm_data_len, bsm_data_len, -1);
// reference to the cp holder is needed for copy_operands()
// reference to the cp holder is needed for reallocating the BSM attribute
merge_cp->set_pool_holder(scratch_class);
bool result = merge_constant_pools(old_cp, scratch_cp, merge_cp,
merge_cp_length, THREAD);
@ -3500,7 +3486,7 @@ void VM_RedefineClasses::set_new_constant_pool(
smaller_cp->set_version(version);
// attach klass to new constant pool
// reference to the cp holder is needed for copy_operands()
// reference to the cp holder is needed for reallocating the BSM attribute
smaller_cp->set_pool_holder(scratch_class);
smaller_cp->copy_fields(scratch_cp());

View File

@ -363,11 +363,16 @@ class VM_RedefineClasses: public VM_Operation {
int _index_map_count;
intArray * _index_map_p;
// _operands_index_map_count is just an optimization for knowing if
// _operands_index_map_p contains any entries.
int _operands_cur_length;
int _operands_index_map_count;
intArray * _operands_index_map_p;
// _bsm_index_map_count is just an optimization for knowing if
// _bsm_index_map_p contains any entries.
int _bsm_index_map_count;
intArray * _bsm_index_map_p;
// After merge_constant_pools "Pass 0", the BSMAttribute entries of merge_cp_p will have been expanded to fit
// scratch_cp's BSMAttribute entries as well.
// However, the newly acquired space will not have been filled in yet.
// To append to this new space, the iterator is used.
BSMAttributeEntries::InsertionIterator _bsmae_iter;
// ptr to _class_count scratch_classes
InstanceKlass** _scratch_classes;
@ -429,17 +434,18 @@ class VM_RedefineClasses: public VM_Operation {
// Support for constant pool merging (these routines are in alpha order):
void append_entry(const constantPoolHandle& scratch_cp, int scratch_i,
constantPoolHandle *merge_cp_p, int *merge_cp_length_p);
void append_operand(const constantPoolHandle& scratch_cp, int scratch_bootstrap_spec_index,
// Returns the index of the appended BSM
int append_bsm_entry(const constantPoolHandle& scratch_cp, int scratch_bootstrap_spec_index,
constantPoolHandle *merge_cp_p, int *merge_cp_length_p);
void finalize_operands_merge(const constantPoolHandle& merge_cp, TRAPS);
void finalize_bsm_entries_merge(const constantPoolHandle& merge_cp, TRAPS);
u2 find_or_append_indirect_entry(const constantPoolHandle& scratch_cp, int scratch_i,
constantPoolHandle *merge_cp_p, int *merge_cp_length_p);
int find_or_append_operand(const constantPoolHandle& scratch_cp, int scratch_bootstrap_spec_index,
int find_or_append_bsm_entry(const constantPoolHandle& scratch_cp, int scratch_bootstrap_spec_index,
constantPoolHandle *merge_cp_p, int *merge_cp_length_p);
u2 find_new_index(int old_index);
int find_new_operand_index(int old_bootstrap_spec_index);
int find_new_bsm_index(int old_bootstrap_spec_index);
void map_index(const constantPoolHandle& scratch_cp, int old_index, int new_index);
void map_operand_index(int old_bootstrap_spec_index, int new_bootstrap_spec_index);
void map_bsm_index(int old_bootstrap_spec_index, int new_bootstrap_spec_index);
bool merge_constant_pools(const constantPoolHandle& old_cp,
const constantPoolHandle& scratch_cp, constantPoolHandle& merge_cp_p,
int& merge_cp_length_p, TRAPS);

View File

@ -54,6 +54,7 @@
#include "oops/array.hpp"
#include "oops/arrayKlass.hpp"
#include "oops/arrayOop.hpp"
#include "oops/bsmAttribute.hpp"
#include "oops/constantPool.hpp"
#include "oops/constMethod.hpp"
#include "oops/cpCache.hpp"
@ -166,10 +167,12 @@
nonstatic_field(ArrayKlass, _dimension, int) \
volatile_nonstatic_field(ArrayKlass, _higher_dimension, ObjArrayKlass*) \
volatile_nonstatic_field(ArrayKlass, _lower_dimension, ArrayKlass*) \
nonstatic_field(BSMAttributeEntries, _offsets, Array<u4>*) \
nonstatic_field(BSMAttributeEntries, _bootstrap_methods, Array<u2>*) \
nonstatic_field(ConstantPool, _bsm_entries, BSMAttributeEntries) \
nonstatic_field(ConstantPool, _tags, Array<u1>*) \
nonstatic_field(ConstantPool, _cache, ConstantPoolCache*) \
nonstatic_field(ConstantPool, _pool_holder, InstanceKlass*) \
nonstatic_field(ConstantPool, _operands, Array<u2>*) \
nonstatic_field(ConstantPool, _resolved_klasses, Array<Klass*>*) \
nonstatic_field(ConstantPool, _length, int) \
nonstatic_field(ConstantPool, _minor_version, u2) \
@ -733,6 +736,7 @@
unchecked_nonstatic_field(Array<int>, _data, sizeof(int)) \
unchecked_nonstatic_field(Array<u1>, _data, sizeof(u1)) \
unchecked_nonstatic_field(Array<u2>, _data, sizeof(u2)) \
unchecked_nonstatic_field(Array<u4>, _data, sizeof(u4)) \
unchecked_nonstatic_field(Array<Method*>, _data, sizeof(Method*)) \
unchecked_nonstatic_field(Array<Klass*>, _data, sizeof(Klass*)) \
unchecked_nonstatic_field(Array<ResolvedFieldEntry>, _data, sizeof(ResolvedFieldEntry)) \
@ -964,6 +968,7 @@
declare_toplevel_type(volatile Metadata*) \
\
declare_toplevel_type(DataLayout) \
declare_toplevel_type(BSMAttributeEntries) \
\
/********/ \
/* Oops */ \

View File

@ -88,8 +88,11 @@ public class ConstantPool extends Metadata implements ClassConstants {
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
Type type = db.lookupType("ConstantPool");
tags = type.getAddressField("_tags");
operands = type.getAddressField("_operands");
cache = type.getAddressField("_cache");
bsm_entries = type.getField("_bsm_entries").getOffset();
Type bsmae_type = db.lookupType("BSMAttributeEntries");
bsm_entries_offsets = bsmae_type.getAddressField("_offsets");
bsm_entries_bootstrap_methods = bsmae_type.getAddressField("_bootstrap_methods");
poolHolder = new MetadataField(type.getAddressField("_pool_holder"), 0);
length = new CIntField(type.getCIntegerField("_length"), 0);
resolved_klasses = type.getAddressField("_resolved_klasses");
@ -112,9 +115,11 @@ public class ConstantPool extends Metadata implements ClassConstants {
public boolean isConstantPool() { return true; }
private static AddressField tags;
private static AddressField operands;
private static AddressField cache;
private static AddressField resolved_klasses;
private static long bsm_entries; // Offset in the constantpool where the Bsm_Entries are found
private static AddressField bsm_entries_offsets;
private static AddressField bsm_entries_bootstrap_methods;
private static MetadataField poolHolder;
private static CIntField length; // number of elements in oop
private static CIntField majorVersion;
@ -130,10 +135,6 @@ public class ConstantPool extends Metadata implements ClassConstants {
private static int INDY_ARGV_OFFSET;
public U1Array getTags() { return new U1Array(tags.getValue(getAddress())); }
public U2Array getOperands() {
Address addr = operands.getValue(getAddress());
return VMObjectFactory.newObject(U2Array.class, addr);
}
public ConstantPoolCache getCache() {
Address addr = cache.getValue(getAddress());
return VMObjectFactory.newObject(ConstantPoolCache.class, addr);
@ -435,26 +436,23 @@ public class ConstantPool extends Metadata implements ClassConstants {
return res;
}
private U4Array getOffsets() {
Address a = getAddress().addOffsetTo(bsm_entries);
if (a == null) return null;
a = bsm_entries_offsets.getValue(a);
return VMObjectFactory.newObject(U4Array.class, a);
}
private U2Array getBootstrapMethods() {
Address a = getAddress().addOffsetTo(bsm_entries);
if (a == null) return null;
return VMObjectFactory.newObject(U2Array.class, bsm_entries_bootstrap_methods.getValue(a));
}
public int getBootstrapMethodsCount() {
U2Array operands = getOperands();
U4Array offsets = getOffsets();
int count = 0;
if (operands != null) {
// Operands array consists of two parts. First part is an array of 32-bit values which denote
// index of the bootstrap method data in the operands array. Note that elements of operands array are of type short.
// So each element of first part occupies two slots in the array.
// Second part is the bootstrap methods data.
// This layout allows us to get BSM count by getting the index of first BSM and dividing it by 2.
//
// The example below shows layout of operands array with 3 bootstrap methods.
// First part has 3 32-bit values indicating the index of the respective bootstrap methods in
// the operands array.
// The first BSM is at index 6. So the count in this case is 6/2=3.
//
// <-----first part----><-------second part------->
// index: 0 2 4 6 i2 i3
// operands: | 6 | i2 | i3 | bsm1 | bsm2 | bsm3 |
//
count = getOperandOffsetAt(operands, 0) / 2;
if (offsets != null) {
count = offsets.length();
}
if (DEBUG) {
System.err.println("ConstantPool.getBootstrapMethodsCount: count = " + count);
@ -463,12 +461,12 @@ public class ConstantPool extends Metadata implements ClassConstants {
}
public int getBootstrapMethodArgsCount(int bsmIndex) {
U2Array operands = getOperands();
U4Array offs = getOffsets();
U2Array bsms = getBootstrapMethods();
if (Assert.ASSERTS_ENABLED) {
Assert.that(operands != null, "Operands is not present");
Assert.that(offs != null && bsms != null, "BSM attribute is not present");
}
int bsmOffset = getOperandOffsetAt(operands, bsmIndex);
int argc = operands.at(bsmOffset + INDY_ARGC_OFFSET);
int argc = bsms.at(offs.at(bsmIndex) + INDY_ARGC_OFFSET);
if (DEBUG) {
System.err.println("ConstantPool.getBootstrapMethodArgsCount: bsm index = " + bsmIndex + ", args count = " + argc);
}
@ -476,15 +474,16 @@ public class ConstantPool extends Metadata implements ClassConstants {
}
public short[] getBootstrapMethodAt(int bsmIndex) {
U2Array operands = getOperands();
if (operands == null) return null; // safety first
int basePos = getOperandOffsetAt(operands, bsmIndex);
U4Array offs = getOffsets();
U2Array bsms = getBootstrapMethods();
if (offs == null || bsms == null) return null; // safety first
int basePos = offs.at(bsmIndex);
int argv = basePos + INDY_ARGV_OFFSET;
int argc = operands.at(basePos + INDY_ARGC_OFFSET);
int argc = getBootstrapMethodArgsCount(bsmIndex);
int endPos = argv + argc;
short[] values = new short[endPos - basePos];
for (int j = 0; j < values.length; j++) {
values[j] = operands.at(basePos+j);
values[j] = bsms.at(basePos+j);
}
return values;
}
@ -773,8 +772,7 @@ public class ConstantPool extends Metadata implements ClassConstants {
// Return the offset of the requested Bootstrap Method in the operands array
private int getOperandOffsetAt(U2Array operands, int bsmIndex) {
return VM.getVM().buildIntFromShorts(operands.at(bsmIndex * 2),
operands.at(bsmIndex * 2 + 1));
return 0;
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2025, 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.
*
*/
package sun.jvm.hotspot.utilities;
import sun.jvm.hotspot.debugger.Address;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.types.Type;
import sun.jvm.hotspot.types.TypeDataBase;
import sun.jvm.hotspot.types.WrongTypeException;
import sun.jvm.hotspot.utilities.Observable;
import sun.jvm.hotspot.utilities.Observer;
public class U4Array extends GenericArray {
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
initialize(VM.getVM().getTypeDataBase());
}
});
}
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
elemType = db.lookupType("u4");
Type type = db.lookupType("Array<u4>");
dataFieldOffset = type.getAddressField("_data").getOffset();
}
private static long dataFieldOffset;
protected static Type elemType;
public U4Array(Address addr) {
super(addr, dataFieldOffset);
}
public int at(int i) {
return (int)getIntegerAt(i);
}
public Type getElemType() {
return elemType;
}
}