mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-14 09:53:18 +00:00
8367656: Refactor Constantpool's operand array into two
Reviewed-by: coleenp, sspitsyn, dholmes
This commit is contained in:
parent
c00d29afa9
commit
d94c52ccf2
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
170
src/hotspot/share/oops/bsmAttribute.hpp
Normal file
170
src/hotspot/share/oops/bsmAttribute.hpp
Normal 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
|
||||
55
src/hotspot/share/oops/bsmAttribute.inline.hpp
Normal file
55
src/hotspot/share/oops/bsmAttribute.inline.hpp
Normal 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
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 */ \
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user