mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
258 lines
12 KiB
C++
258 lines
12 KiB
C++
/*
|
|
* Copyright (c) 1998, 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_CPCACHE_HPP
|
|
#define SHARE_OOPS_CPCACHE_HPP
|
|
|
|
#include "interpreter/bytecodes.hpp"
|
|
#include "memory/allocation.hpp"
|
|
#include "oops/array.hpp"
|
|
#include "oops/oopHandle.hpp"
|
|
#include "runtime/handles.hpp"
|
|
#include "utilities/align.hpp"
|
|
#include "utilities/constantTag.hpp"
|
|
#include "utilities/growableArray.hpp"
|
|
|
|
// The ConstantPoolCache is not a cache! It is the resolution table that the
|
|
// interpreter uses to avoid going into the runtime and a way to access resolved
|
|
// values.
|
|
|
|
class CallInfo;
|
|
class ResolvedFieldEntry;
|
|
class ResolvedIndyEntry;
|
|
class ResolvedMethodEntry;
|
|
|
|
// A constant pool cache is a runtime data structure set aside to a constant pool. The cache
|
|
// holds runtime information for all field access and invoke bytecodes. The cache
|
|
// is created and initialized before a class is actively used (i.e., initialized), the indivi-
|
|
// dual cache entries are filled at resolution (i.e., "link") time (see also: rewriter.*).
|
|
|
|
class ConstantPoolCache: public MetaspaceObj {
|
|
friend class VMStructs;
|
|
friend class MetadataFactory;
|
|
private:
|
|
// If you add a new field that points to any metaspace object, you
|
|
// must add this field to ConstantPoolCache::metaspace_pointers_do().
|
|
|
|
// The narrowOop pointer to the archived resolved_references. Set at CDS dump
|
|
// time when caching java heap object is supported.
|
|
CDS_JAVA_HEAP_ONLY(int _archived_references_index;) // Gap on LP64
|
|
|
|
ConstantPool* _constant_pool; // the corresponding constant pool
|
|
|
|
// The following fields need to be modified at runtime, so they cannot be
|
|
// stored in the ConstantPool, which is read-only.
|
|
// Array of resolved objects from the constant pool and map from resolved
|
|
// object index to original constant pool index
|
|
OopHandle _resolved_references;
|
|
Array<u2>* _reference_map;
|
|
|
|
// RedefineClasses support
|
|
uint64_t _gc_epoch;
|
|
|
|
Array<ResolvedIndyEntry>* _resolved_indy_entries;
|
|
Array<ResolvedFieldEntry>* _resolved_field_entries;
|
|
Array<ResolvedMethodEntry>* _resolved_method_entries;
|
|
|
|
// Sizing
|
|
DEBUG_ONLY(friend class ClassVerifier;)
|
|
|
|
public:
|
|
// specific but defiinitions for ldc
|
|
enum {
|
|
// high order bits are the TosState corresponding to field type or method return type
|
|
tos_state_bits = 4,
|
|
tos_state_mask = right_n_bits(tos_state_bits),
|
|
tos_state_shift = BitsPerInt - tos_state_bits, // see verify_tos_state_shift below
|
|
// low order bits give field index (for FieldInfo) or method parameter size:
|
|
field_index_bits = 16,
|
|
field_index_mask = right_n_bits(field_index_bits),
|
|
};
|
|
|
|
// Constructor
|
|
ConstantPoolCache(const intStack& invokedynamic_references_map,
|
|
Array<ResolvedIndyEntry>* indy_info,
|
|
Array<ResolvedFieldEntry>* field_entries,
|
|
Array<ResolvedMethodEntry>* mehtod_entries);
|
|
|
|
// Initialization
|
|
void initialize(const intArray& invokedynamic_references_map);
|
|
public:
|
|
static ConstantPoolCache* allocate(ClassLoaderData* loader_data,
|
|
const intStack& invokedynamic_references_map,
|
|
const GrowableArray<ResolvedIndyEntry> indy_entries,
|
|
const GrowableArray<ResolvedFieldEntry> field_entries,
|
|
const GrowableArray<ResolvedMethodEntry> method_entries,
|
|
TRAPS);
|
|
|
|
void metaspace_pointers_do(MetaspaceClosure* it);
|
|
MetaspaceObj::Type type() const { return ConstantPoolCacheType; }
|
|
|
|
oop archived_references() NOT_CDS_JAVA_HEAP_RETURN_(nullptr);
|
|
void clear_archived_references() NOT_CDS_JAVA_HEAP_RETURN;
|
|
CDS_JAVA_HEAP_ONLY(int archived_references_index() { return _archived_references_index; })
|
|
|
|
inline objArrayOop resolved_references();
|
|
void set_resolved_references(OopHandle s) { _resolved_references = s; }
|
|
Array<u2>* reference_map() const { return _reference_map; }
|
|
void set_reference_map(Array<u2>* o) { _reference_map = o; }
|
|
|
|
private:
|
|
void set_direct_or_vtable_call(
|
|
Bytecodes::Code invoke_code, // the bytecode used for invoking the method
|
|
int method_index, // Index into the resolved method entry array
|
|
const methodHandle& method, // the method/prototype if any (null, otherwise)
|
|
int vtable_index, // the vtable index if any, else negative
|
|
bool sender_is_interface
|
|
);
|
|
|
|
public:
|
|
void set_direct_call( // sets entry to exact concrete method entry
|
|
Bytecodes::Code invoke_code, // the bytecode used for invoking the method
|
|
int method_index, // Index into the resolved method entry array
|
|
const methodHandle& method, // the method to call
|
|
bool sender_is_interface
|
|
);
|
|
|
|
void set_vtable_call( // sets entry to vtable index
|
|
Bytecodes::Code invoke_code, // the bytecode used for invoking the method
|
|
int method_index, // Index into the resolved method entry array
|
|
const methodHandle& method, // resolved method which declares the vtable index
|
|
int vtable_index // the vtable index
|
|
);
|
|
|
|
void set_itable_call(
|
|
Bytecodes::Code invoke_code, // the bytecode used; must be invokeinterface
|
|
int method_index, // Index into the resolved method entry array
|
|
Klass* referenced_klass, // the referenced klass in the InterfaceMethodref
|
|
const methodHandle& method, // the resolved interface method
|
|
int itable_index // index into itable for the method
|
|
);
|
|
|
|
// The "appendix" is an optional call-site-specific parameter which is
|
|
// pushed by the JVM at the end of the argument list. This argument may
|
|
// be a MethodType for the MH.invokes and a CallSite for an invokedynamic
|
|
// instruction. However, its exact type and use depends on the Java upcall,
|
|
// which simply returns a compiled LambdaForm along with any reference
|
|
// that LambdaForm needs to complete the call. If the upcall returns a
|
|
// null appendix, the argument is not passed at all.
|
|
//
|
|
// The appendix is *not* represented in the signature of the symbolic
|
|
// reference for the call site, but (if present) it *is* represented in
|
|
// the Method* bound to the site. This means that static and dynamic
|
|
// resolution logic needs to make slightly different assessments about the
|
|
// number and types of arguments.
|
|
ResolvedMethodEntry* set_method_handle(
|
|
int method_index,
|
|
const CallInfo &call_info // Call link information
|
|
);
|
|
|
|
Method* method_if_resolved(int method_index) const;
|
|
|
|
Array<ResolvedFieldEntry>* resolved_field_entries() { return _resolved_field_entries; }
|
|
inline ResolvedFieldEntry* resolved_field_entry_at(int field_index) const;
|
|
inline int resolved_field_entries_length() const;
|
|
void print_resolved_field_entries(outputStream* st) const;
|
|
|
|
Array<ResolvedIndyEntry>* resolved_indy_entries() { return _resolved_indy_entries; }
|
|
inline ResolvedIndyEntry* resolved_indy_entry_at(int index) const;
|
|
inline int resolved_indy_entries_length() const;
|
|
void print_resolved_indy_entries(outputStream* st) const;
|
|
|
|
Array<ResolvedMethodEntry>* resolved_method_entries() { return _resolved_method_entries; }
|
|
inline ResolvedMethodEntry* resolved_method_entry_at(int method_index) const;
|
|
inline int resolved_method_entries_length() const;
|
|
void print_resolved_method_entries(outputStream* st) const;
|
|
|
|
// Assembly code support
|
|
static ByteSize resolved_references_offset() { return byte_offset_of(ConstantPoolCache, _resolved_references); }
|
|
static ByteSize invokedynamic_entries_offset() { return byte_offset_of(ConstantPoolCache, _resolved_indy_entries); }
|
|
static ByteSize field_entries_offset() { return byte_offset_of(ConstantPoolCache, _resolved_field_entries); }
|
|
static ByteSize method_entries_offset() { return byte_offset_of(ConstantPoolCache, _resolved_method_entries); }
|
|
|
|
#if INCLUDE_CDS
|
|
void remove_unshareable_info();
|
|
#endif
|
|
|
|
public:
|
|
static int size() { return align_metadata_size(sizeof(ConstantPoolCache) / wordSize); }
|
|
|
|
private:
|
|
// Helpers
|
|
ConstantPool** constant_pool_addr() { return &_constant_pool; }
|
|
|
|
public:
|
|
// Accessors
|
|
void set_constant_pool(ConstantPool* pool) { _constant_pool = pool; }
|
|
ConstantPool* constant_pool() const { return _constant_pool; }
|
|
|
|
// Code generation
|
|
static ByteSize base_offset() { return in_ByteSize(sizeof(ConstantPoolCache)); }
|
|
|
|
#if INCLUDE_JVMTI
|
|
// RedefineClasses() API support:
|
|
// If any entry of this ConstantPoolCache points to any of
|
|
// old_methods, replace it with the corresponding new_method.
|
|
// trace_name_printed is set to true if the current call has
|
|
// printed the klass name so that other routines in the adjust_*
|
|
// group don't print the klass name.
|
|
void adjust_method_entries(bool* trace_name_printed);
|
|
bool check_no_old_or_obsolete_entries();
|
|
void dump_cache();
|
|
#endif // INCLUDE_JVMTI
|
|
|
|
#if INCLUDE_CDS
|
|
void remove_resolved_field_entries_if_non_deterministic();
|
|
void remove_resolved_indy_entries_if_non_deterministic();
|
|
void remove_resolved_method_entries_if_non_deterministic();
|
|
bool can_archive_resolved_method(ConstantPool* src_cp, ResolvedMethodEntry* method_entry);
|
|
#endif
|
|
|
|
// RedefineClasses support
|
|
DEBUG_ONLY(bool on_stack() { return false; })
|
|
void deallocate_contents(ClassLoaderData* data);
|
|
void record_gc_epoch();
|
|
uint64_t gc_epoch() { return _gc_epoch; }
|
|
|
|
// Return TRUE if resolution failed and this thread got to record the failure
|
|
// status. Return FALSE if another thread succeeded or failed in resolving
|
|
// the method and recorded the success or failure before this thread had a
|
|
// chance to record its failure.
|
|
bool save_and_throw_indy_exc(const constantPoolHandle& cpool, int cpool_index, int index, constantTag tag, TRAPS);
|
|
oop set_dynamic_call(const CallInfo &call_info, int index);
|
|
oop appendix_if_resolved(int method_index) const;
|
|
oop appendix_if_resolved(ResolvedMethodEntry* method_entry) const;
|
|
|
|
// Printing
|
|
void print_on(outputStream* st) const;
|
|
void print_value_on(outputStream* st) const;
|
|
|
|
const char* internal_name() const { return "{constant pool cache}"; }
|
|
|
|
// Verify
|
|
void verify_on(outputStream* st);
|
|
};
|
|
|
|
#endif // SHARE_OOPS_CPCACHE_HPP
|