/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "cds/archiveUtils.hpp"
#include "cds/classListWriter.hpp"
#include "cds/heapShared.hpp"
#include "cds/metaspaceShared.hpp"
#include "classfile/classFileParser.hpp"
#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "classfile/verifier.hpp"
#include "classfile/vmClasses.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/codeCache.hpp"
#include "code/dependencyContext.hpp"
#include "compiler/compilationPolicy.hpp"
#include "compiler/compileBroker.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
#include "interpreter/oopMapCache.hpp"
#include "interpreter/rewriter.hpp"
#include "jvm.h"
#include "jvmtifiles/jvmti.h"
#include "logging/log.hpp"
#include "logging/logMessage.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/iterator.inline.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceClosure.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/fieldStreams.inline.hpp"
#include "oops/constantPool.hpp"
#include "oops/instanceClassLoaderKlass.hpp"
#include "oops/instanceKlass.inline.hpp"
#include "oops/instanceMirrorKlass.hpp"
#include "oops/instanceOop.hpp"
#include "oops/instanceStackChunkKlass.hpp"
#include "oops/klass.inline.hpp"
#include "oops/method.hpp"
#include "oops/oop.inline.hpp"
#include "oops/recordComponent.hpp"
#include "oops/symbol.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/jvmtiRedefineClasses.hpp"
#include "prims/jvmtiThreadState.hpp"
#include "prims/methodComparator.hpp"
#include "runtime/arguments.hpp"
#include "runtime/atomic.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/javaThread.inline.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/orderAccess.hpp"
#include "runtime/reflectionUtils.hpp"
#include "runtime/threads.hpp"
#include "services/classLoadingService.hpp"
#include "services/finalizerService.hpp"
#include "services/threadService.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/events.hpp"
#include "utilities/macros.hpp"
#include "utilities/stringUtils.hpp"
#include "utilities/pair.hpp"
#ifdef COMPILER1
#include "c1/c1_Compiler.hpp"
#endif
#if INCLUDE_JFR
#include "jfr/jfrEvents.hpp"
#endif
#ifdef DTRACE_ENABLED
#define HOTSPOT_CLASS_INITIALIZATION_required HOTSPOT_CLASS_INITIALIZATION_REQUIRED
#define HOTSPOT_CLASS_INITIALIZATION_recursive HOTSPOT_CLASS_INITIALIZATION_RECURSIVE
#define HOTSPOT_CLASS_INITIALIZATION_concurrent HOTSPOT_CLASS_INITIALIZATION_CONCURRENT
#define HOTSPOT_CLASS_INITIALIZATION_erroneous HOTSPOT_CLASS_INITIALIZATION_ERRONEOUS
#define HOTSPOT_CLASS_INITIALIZATION_super__failed HOTSPOT_CLASS_INITIALIZATION_SUPER_FAILED
#define HOTSPOT_CLASS_INITIALIZATION_clinit HOTSPOT_CLASS_INITIALIZATION_CLINIT
#define HOTSPOT_CLASS_INITIALIZATION_error HOTSPOT_CLASS_INITIALIZATION_ERROR
#define HOTSPOT_CLASS_INITIALIZATION_end HOTSPOT_CLASS_INITIALIZATION_END
#define DTRACE_CLASSINIT_PROBE(type, thread_type) \
{ \
char* data = NULL; \
int len = 0; \
Symbol* clss_name = name(); \
if (clss_name != NULL) { \
data = (char*)clss_name->bytes(); \
len = clss_name->utf8_length(); \
} \
HOTSPOT_CLASS_INITIALIZATION_##type( \
data, len, (void*)class_loader(), thread_type); \
}
#define DTRACE_CLASSINIT_PROBE_WAIT(type, thread_type, wait) \
{ \
char* data = NULL; \
int len = 0; \
Symbol* clss_name = name(); \
if (clss_name != NULL) { \
data = (char*)clss_name->bytes(); \
len = clss_name->utf8_length(); \
} \
HOTSPOT_CLASS_INITIALIZATION_##type( \
data, len, (void*)class_loader(), thread_type, wait); \
}
#else // ndef DTRACE_ENABLED
#define DTRACE_CLASSINIT_PROBE(type, thread_type)
#define DTRACE_CLASSINIT_PROBE_WAIT(type, thread_type, wait)
#endif // ndef DTRACE_ENABLED
bool InstanceKlass::_finalization_enabled = true;
static inline bool is_class_loader(const Symbol* class_name,
const ClassFileParser& parser) {
assert(class_name != NULL, "invariant");
if (class_name == vmSymbols::java_lang_ClassLoader()) {
return true;
}
if (vmClasses::ClassLoader_klass_loaded()) {
const Klass* const super_klass = parser.super_klass();
if (super_klass != NULL) {
if (super_klass->is_subtype_of(vmClasses::ClassLoader_klass())) {
return true;
}
}
}
return false;
}
static inline bool is_stack_chunk_class(const Symbol* class_name,
const ClassLoaderData* loader_data) {
return (class_name == vmSymbols::jdk_internal_vm_StackChunk() &&
loader_data->is_the_null_class_loader_data());
}
// private: called to verify that k is a static member of this nest.
// We know that k is an instance class in the same package and hence the
// same classloader.
bool InstanceKlass::has_nest_member(JavaThread* current, InstanceKlass* k) const {
assert(!is_hidden(), "unexpected hidden class");
if (_nest_members == NULL || _nest_members == Universe::the_empty_short_array()) {
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(current);
log_trace(class, nestmates)("Checked nest membership of %s in non-nest-host class %s",
k->external_name(), this->external_name());
}
return false;
}
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(current);
log_trace(class, nestmates)("Checking nest membership of %s in %s",
k->external_name(), this->external_name());
}
// Check for the named class in _nest_members.
// We don't resolve, or load, any classes.
for (int i = 0; i < _nest_members->length(); i++) {
int cp_index = _nest_members->at(i);
Symbol* name = _constants->klass_name_at(cp_index);
if (name == k->name()) {
log_trace(class, nestmates)("- named class found at nest_members[%d] => cp[%d]", i, cp_index);
return true;
}
}
log_trace(class, nestmates)("- class is NOT a nest member!");
return false;
}
// Called to verify that k is a permitted subclass of this class
bool InstanceKlass::has_as_permitted_subclass(const InstanceKlass* k) const {
Thread* current = Thread::current();
assert(k != NULL, "sanity check");
assert(_permitted_subclasses != NULL && _permitted_subclasses != Universe::the_empty_short_array(),
"unexpected empty _permitted_subclasses array");
if (log_is_enabled(Trace, class, sealed)) {
ResourceMark rm(current);
log_trace(class, sealed)("Checking for permitted subclass of %s in %s",
k->external_name(), this->external_name());
}
// Check that the class and its super are in the same module.
if (k->module() != this->module()) {
ResourceMark rm(current);
log_trace(class, sealed)("Check failed for same module of permitted subclass %s and sealed class %s",
k->external_name(), this->external_name());
return false;
}
if (!k->is_public() && !is_same_class_package(k)) {
ResourceMark rm(current);
log_trace(class, sealed)("Check failed, subclass %s not public and not in the same package as sealed class %s",
k->external_name(), this->external_name());
return false;
}
for (int i = 0; i < _permitted_subclasses->length(); i++) {
int cp_index = _permitted_subclasses->at(i);
Symbol* name = _constants->klass_name_at(cp_index);
if (name == k->name()) {
log_trace(class, sealed)("- Found it at permitted_subclasses[%d] => cp[%d]", i, cp_index);
return true;
}
}
log_trace(class, sealed)("- class is NOT a permitted subclass!");
return false;
}
// Return nest-host class, resolving, validating and saving it if needed.
// In cases where this is called from a thread that cannot do classloading
// (such as a native JIT thread) then we simply return NULL, which in turn
// causes the access check to return false. Such code will retry the access
// from a more suitable environment later. Otherwise the _nest_host is always
// set once this method returns.
// Any errors from nest-host resolution must be preserved so they can be queried
// from higher-level access checking code, and reported as part of access checking
// exceptions.
// VirtualMachineErrors are propagated with a NULL return.
// Under any conditions where the _nest_host can be set to non-NULL the resulting
// value of it and, if applicable, the nest host resolution/validation error,
// are idempotent.
InstanceKlass* InstanceKlass::nest_host(TRAPS) {
InstanceKlass* nest_host_k = _nest_host;
if (nest_host_k != NULL) {
return nest_host_k;
}
ResourceMark rm(THREAD);
// need to resolve and save our nest-host class.
if (_nest_host_index != 0) { // we have a real nest_host
// Before trying to resolve check if we're in a suitable context
bool can_resolve = THREAD->can_call_java();
if (!can_resolve && !_constants->tag_at(_nest_host_index).is_klass()) {
log_trace(class, nestmates)("Rejected resolution of nest-host of %s in unsuitable thread",
this->external_name());
return NULL; // sentinel to say "try again from a different context"
}
log_trace(class, nestmates)("Resolving nest-host of %s using cp entry for %s",
this->external_name(),
_constants->klass_name_at(_nest_host_index)->as_C_string());
Klass* k = _constants->klass_at(_nest_host_index, THREAD);
if (HAS_PENDING_EXCEPTION) {
if (PENDING_EXCEPTION->is_a(vmClasses::VirtualMachineError_klass())) {
return NULL; // propagate VMEs
}
stringStream ss;
char* target_host_class = _constants->klass_name_at(_nest_host_index)->as_C_string();
ss.print("Nest host resolution of %s with host %s failed: ",
this->external_name(), target_host_class);
java_lang_Throwable::print(PENDING_EXCEPTION, &ss);
const char* msg = ss.as_string(true /* on C-heap */);
constantPoolHandle cph(THREAD, constants());
SystemDictionary::add_nest_host_error(cph, _nest_host_index, msg);
CLEAR_PENDING_EXCEPTION;
log_trace(class, nestmates)("%s", msg);
} else {
// A valid nest-host is an instance class in the current package that lists this
// class as a nest member. If any of these conditions are not met the class is
// its own nest-host.
const char* error = NULL;
// JVMS 5.4.4 indicates package check comes first
if (is_same_class_package(k)) {
// Now check actual membership. We can't be a member if our "host" is
// not an instance class.
if (k->is_instance_klass()) {
nest_host_k = InstanceKlass::cast(k);
bool is_member = nest_host_k->has_nest_member(THREAD, this);
if (is_member) {
_nest_host = nest_host_k; // save resolved nest-host value
log_trace(class, nestmates)("Resolved nest-host of %s to %s",
this->external_name(), k->external_name());
return nest_host_k;
} else {
error = "current type is not listed as a nest member";
}
} else {
error = "host is not an instance class";
}
} else {
error = "types are in different packages";
}
// something went wrong, so record what and log it
{
stringStream ss;
ss.print("Type %s (loader: %s) is not a nest member of type %s (loader: %s): %s",
this->external_name(),
this->class_loader_data()->loader_name_and_id(),
k->external_name(),
k->class_loader_data()->loader_name_and_id(),
error);
const char* msg = ss.as_string(true /* on C-heap */);
constantPoolHandle cph(THREAD, constants());
SystemDictionary::add_nest_host_error(cph, _nest_host_index, msg);
log_trace(class, nestmates)("%s", msg);
}
}
} else {
log_trace(class, nestmates)("Type %s is not part of a nest: setting nest-host to self",
this->external_name());
}
// Either not in an explicit nest, or else an error occurred, so
// the nest-host is set to `this`. Any thread that sees this assignment
// will also see any setting of nest_host_error(), if applicable.
return (_nest_host = this);
}
// Dynamic nest member support: set this class's nest host to the given class.
// This occurs as part of the class definition, as soon as the instanceKlass
// has been created and doesn't require further resolution. The code:
// lookup().defineHiddenClass(bytes_for_X, NESTMATE);
// results in:
// class_of_X.set_nest_host(lookup().lookupClass().getNestHost())
// If it has an explicit _nest_host_index or _nest_members, these will be ignored.
// We also know the "host" is a valid nest-host in the same package so we can
// assert some of those facts.
void InstanceKlass::set_nest_host(InstanceKlass* host) {
assert(is_hidden(), "must be a hidden class");
assert(host != NULL, "NULL nest host specified");
assert(_nest_host == NULL, "current class has resolved nest-host");
assert(nest_host_error() == NULL, "unexpected nest host resolution error exists: %s",
nest_host_error());
assert((host->_nest_host == NULL && host->_nest_host_index == 0) ||
(host->_nest_host == host), "proposed host is not a valid nest-host");
// Can't assert this as package is not set yet:
// assert(is_same_class_package(host), "proposed host is in wrong package");
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm;
const char* msg = "";
// a hidden class does not expect a statically defined nest-host
if (_nest_host_index > 0) {
msg = "(the NestHost attribute in the current class is ignored)";
} else if (_nest_members != NULL && _nest_members != Universe::the_empty_short_array()) {
msg = "(the NestMembers attribute in the current class is ignored)";
}
log_trace(class, nestmates)("Injected type %s into the nest of %s %s",
this->external_name(),
host->external_name(),
msg);
}
// set dynamic nest host
_nest_host = host;
// Record dependency to keep nest host from being unloaded before this class.
ClassLoaderData* this_key = class_loader_data();
assert(this_key != NULL, "sanity");
this_key->record_dependency(host);
}
// check if 'this' and k are nestmates (same nest_host), or k is our nest_host,
// or we are k's nest_host - all of which is covered by comparing the two
// resolved_nest_hosts.
// Any exceptions (i.e. VMEs) are propagated.
bool InstanceKlass::has_nestmate_access_to(InstanceKlass* k, TRAPS) {
assert(this != k, "this should be handled by higher-level code");
// Per JVMS 5.4.4 we first resolve and validate the current class, then
// the target class k.
InstanceKlass* cur_host = nest_host(CHECK_false);
if (cur_host == NULL) {
return false;
}
Klass* k_nest_host = k->nest_host(CHECK_false);
if (k_nest_host == NULL) {
return false;
}
bool access = (cur_host == k_nest_host);
ResourceMark rm(THREAD);
log_trace(class, nestmates)("Class %s does %shave nestmate access to %s",
this->external_name(),
access ? "" : "NOT ",
k->external_name());
return access;
}
const char* InstanceKlass::nest_host_error() {
if (_nest_host_index == 0) {
return NULL;
} else {
constantPoolHandle cph(Thread::current(), constants());
return SystemDictionary::find_nest_host_error(cph, (int)_nest_host_index);
}
}
InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& parser, TRAPS) {
const int size = InstanceKlass::size(parser.vtable_size(),
parser.itable_size(),
nonstatic_oop_map_size(parser.total_oop_map_count()),
parser.is_interface());
const Symbol* const class_name = parser.class_name();
assert(class_name != NULL, "invariant");
ClassLoaderData* loader_data = parser.loader_data();
assert(loader_data != NULL, "invariant");
InstanceKlass* ik;
// Allocation
if (parser.is_instance_ref_klass()) {
// java.lang.ref.Reference
ik = new (loader_data, size, THREAD) InstanceRefKlass(parser);
} else if (class_name == vmSymbols::java_lang_Class()) {
// mirror - java.lang.Class
ik = new (loader_data, size, THREAD) InstanceMirrorKlass(parser);
} else if (is_stack_chunk_class(class_name, loader_data)) {
// stack chunk
ik = new (loader_data, size, THREAD) InstanceStackChunkKlass(parser);
} else if (is_class_loader(class_name, parser)) {
// class loader - java.lang.ClassLoader
ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass(parser);
} else {
// normal
ik = new (loader_data, size, THREAD) InstanceKlass(parser);
}
// Check for pending exception before adding to the loader data and incrementing
// class count. Can get OOM here.
if (HAS_PENDING_EXCEPTION) {
return NULL;
}
return ik;
}
// copy method ordering from resource area to Metaspace
void InstanceKlass::copy_method_ordering(const intArray* m, TRAPS) {
if (m != NULL) {
// allocate a new array and copy contents (memcpy?)
_method_ordering = MetadataFactory::new_array<int>(class_loader_data(), m->length(), CHECK);
for (int i = 0; i < m->length(); i++) {
_method_ordering->at_put(i, m->at(i));
}
} else {
_method_ordering = Universe::the_empty_int_array();
}
}
// create a new array of vtable_indices for default methods
Array<int>* InstanceKlass::create_new_default_vtable_indices(int len, TRAPS) {
Array<int>* vtable_indices = MetadataFactory::new_array<int>(class_loader_data(), len, CHECK_NULL);
assert(default_vtable_indices() == NULL, "only create once");
set_default_vtable_indices(vtable_indices);
return vtable_indices;
}
static Monitor* create_init_monitor(const char* name) {
return new Monitor(Mutex::safepoint, name);
}
InstanceKlass::InstanceKlass(const ClassFileParser& parser, KlassKind kind, ReferenceType reference_type) :
Klass(kind),
_nest_members(NULL),
_nest_host(NULL),
_permitted_subclasses(NULL),
_record_components(NULL),
_static_field_size(parser.static_field_size()),
_nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
_itable_len(parser.itable_size()),
_nest_host_index(0),
_init_state(allocated),
_reference_type(reference_type),
_init_monitor(create_init_monitor("InstanceKlassInitMonitor_lock")),
_init_thread(NULL)
{
set_vtable_length(parser.vtable_size());
set_access_flags(parser.access_flags());
if (parser.is_hidden()) set_is_hidden();
set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
false));
assert(NULL == _methods, "underlying memory not zeroed?");
assert(is_instance_klass(), "is layout incorrect?");
assert(size_helper() == parser.layout_size(), "incorrect size_helper?");
}
void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data,
Array<Method*>* methods) {
if (methods != NULL && methods != Universe::the_empty_method_array() &&
!methods->is_shared()) {
for (int i = 0; i < methods->length(); i++) {
Method* method = methods->at(i);
if (method == NULL) continue; // maybe null if error processing
// Only want to delete methods that are not executing for RedefineClasses.
// The previous version will point to them so they're not totally dangling
assert (!method->on_stack(), "shouldn't be called with methods on stack");
MetadataFactory::free_metadata(loader_data, method);
}
MetadataFactory::free_array<Method*>(loader_data, methods);
}
}
void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data,
const Klass* super_klass,
Array<InstanceKlass*>* local_interfaces,
Array<InstanceKlass*>* transitive_interfaces) {
// Only deallocate transitive interfaces if not empty, same as super class
// or same as local interfaces. See code in parseClassFile.
Array<InstanceKlass*>* ti = transitive_interfaces;
if (ti != Universe::the_empty_instance_klass_array() && ti != local_interfaces) {
// check that the interfaces don't come from super class
Array<InstanceKlass*>* sti = (super_klass == NULL) ? NULL :
InstanceKlass::cast(super_klass)->transitive_interfaces();
if (ti != sti && ti != NULL && !ti->is_shared()) {
MetadataFactory::free_array<InstanceKlass*>(loader_data, ti);
}
}
// local interfaces can be empty
if (local_interfaces != Universe::the_empty_instance_klass_array() &&
local_interfaces != NULL && !local_interfaces->is_shared()) {
MetadataFactory::free_array<InstanceKlass*>(loader_data, local_interfaces);
}
}
void InstanceKlass::deallocate_record_components(ClassLoaderData* loader_data,
Array<RecordComponent*>* record_components) {
if (record_components != NULL && !record_components->is_shared()) {
for (int i = 0; i < record_components->length(); i++) {
RecordComponent* record_component = record_components->at(i);
MetadataFactory::free_metadata(loader_data, record_component);
}
MetadataFactory::free_array<RecordComponent*>(loader_data, record_components);
}
}
// This function deallocates the metadata and C heap pointers that the
// InstanceKlass points to.
void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
// Orphan the mirror first, CMS thinks it's still live.
if (java_mirror() != NULL) {
java_lang_Class::set_klass(java_mirror(), NULL);
}
// Also remove mirror from handles
loader_data->remove_handle(_java_mirror);
// Need to take this class off the class loader data list.
loader_data->remove_class(this);
// The array_klass for this class is created later, after error handling.
// For class redefinition, we keep the original class so this scratch class
// doesn't have an array class. Either way, assert that there is nothing
// to deallocate.
assert(array_klasses() == NULL, "array classes shouldn't be created for this class yet");
// Release C heap allocated data that this points to, which includes
// reference counting symbol names.
// Can't release the constant pool or MethodData C heap data here because the constant
// pool can be deallocated separately from the InstanceKlass for default methods and
// redefine classes. MethodData can also be released separately.
release_C_heap_structures(/* release_sub_metadata */ false);
deallocate_methods(loader_data, methods());
set_methods(NULL);
deallocate_record_components(loader_data, record_components());
set_record_components(NULL);
if (method_ordering() != NULL &&
method_ordering() != Universe::the_empty_int_array() &&
!method_ordering()->is_shared()) {
MetadataFactory::free_array<int>(loader_data, method_ordering());
}
set_method_ordering(NULL);
// default methods can be empty
if (default_methods() != NULL &&
default_methods() != Universe::the_empty_method_array() &&
!default_methods()->is_shared()) {
MetadataFactory::free_array<Method*>(loader_data, default_methods());
}
// Do NOT deallocate the default methods, they are owned by superinterfaces.
set_default_methods(NULL);
// default methods vtable indices can be empty
if (default_vtable_indices() != NULL &&
!default_vtable_indices()->is_shared()) {
MetadataFactory::free_array<int>(loader_data, default_vtable_indices());
}
set_default_vtable_indices(NULL);
// This array is in Klass, but remove it with the InstanceKlass since
// this place would be the only caller and it can share memory with transitive
// interfaces.
if (secondary_supers() != NULL &&
secondary_supers() != Universe::the_empty_klass_array() &&
// see comments in compute_secondary_supers about the following cast
(address)(secondary_supers()) != (address)(transitive_interfaces()) &&
!secondary_supers()->is_shared()) {
MetadataFactory::free_array<Klass*>(loader_data, secondary_supers());
}
set_secondary_supers(NULL);
deallocate_interfaces(loader_data, super(), local_interfaces(), transitive_interfaces());
set_transitive_interfaces(NULL);
set_local_interfaces(NULL);
if (fields() != NULL && !fields()->is_shared()) {
MetadataFactory::free_array<jushort>(loader_data, fields());
}
set_fields(NULL, 0);
// If a method from a redefined class is using this constant pool, don't
// delete it, yet. The new class's previous version will point to this.
if (constants() != NULL) {
assert (!constants()->on_stack(), "shouldn't be called if anything is onstack");
if (!constants()->is_shared()) {
MetadataFactory::free_metadata(loader_data, constants());
}
// Delete any cached resolution errors for the constant pool
SystemDictionary::delete_resolution_error(constants());
set_constants(NULL);
}
if (inner_classes() != NULL &&
inner_classes() != Universe::the_empty_short_array() &&
!inner_classes()->is_shared()) {
MetadataFactory::free_array<jushort>(loader_data, inner_classes());
}
set_inner_classes(NULL);
if (nest_members() != NULL &&
nest_members() != Universe::the_empty_short_array() &&
!nest_members()->is_shared()) {
MetadataFactory::free_array<jushort>(loader_data, nest_members());
}
set_nest_members(NULL);
if (permitted_subclasses() != NULL &&
permitted_subclasses() != Universe::the_empty_short_array() &&
!permitted_subclasses()->is_shared()) {
MetadataFactory::free_array<jushort>(loader_data, permitted_subclasses());
}
set_permitted_subclasses(NULL);
// We should deallocate the Annotations instance if it's not in shared spaces.
if (annotations() != NULL && !annotations()->is_shared()) {
MetadataFactory::free_metadata(loader_data, annotations());
}
set_annotations(NULL);
SystemDictionaryShared::handle_class_unloading(this);
}
bool InstanceKlass::is_record() const {
return _record_components != NULL &&
is_final() &&
java_super() == vmClasses::Record_klass();
}
bool InstanceKlass::is_sealed() const {
return _permitted_subclasses != NULL &&
_permitted_subclasses != Universe::the_empty_short_array();
}
bool InstanceKlass::should_be_initialized() const {
return !is_initialized();
}
klassItable InstanceKlass::itable() const {
return klassItable(const_cast<InstanceKlass*>(this));
}
// JVMTI spec thinks there are signers and protection domain in the
// instanceKlass. These accessors pretend these fields are there.
// The hprof specification also thinks these fields are in InstanceKlass.
oop InstanceKlass::protection_domain() const {
// return the protection_domain from the mirror
return java_lang_Class::protection_domain(java_mirror());
}
objArrayOop InstanceKlass::signers() const {
// return the signers from the mirror
return java_lang_Class::signers(java_mirror());
}
// See "The Virtual Machine Specification" section 2.16.5 for a detailed explanation of the class initialization
// process. The step comments refers to the procedure described in that section.
// Note: implementation moved to static method to expose the this pointer.
void InstanceKlass::initialize(TRAPS) {
if (this->should_be_initialized()) {
initialize_impl(CHECK);
// Note: at this point the class may be initialized
// OR it may be in the state of being initialized
// in case of recursive initialization!
} else {
assert(is_initialized(), "sanity check");
}
}
bool InstanceKlass::verify_code(TRAPS) {
// 1) Verify the bytecodes
return Verifier::verify(this, should_verify_class(), THREAD);
}
void InstanceKlass::link_class(TRAPS) {
assert(is_loaded(), "must be loaded");
if (!is_linked()) {
link_class_impl(CHECK);
}
}
void InstanceKlass::check_link_state_and_wait(JavaThread* current) {
MonitorLocker ml(current, _init_monitor);
// Another thread is linking this class, wait.
while (is_being_linked() && !is_init_thread(current)) {
ml.wait();
}
// This thread is recursively linking this class, continue
if (is_being_linked() && is_init_thread(current)) {
return;
}
// If this class wasn't linked already, set state to being_linked
if (!is_linked()) {
set_init_state(being_linked);
set_init_thread(current);
}
}
// Called to verify that a class can link during initialization, without
// throwing a VerifyError.
bool InstanceKlass::link_class_or_fail(TRAPS) {
assert(is_loaded(), "must be loaded");
if (!is_linked()) {
link_class_impl(CHECK_false);
}
return is_linked();
}
bool InstanceKlass::link_class_impl(TRAPS) {
if (DumpSharedSpaces && SystemDictionaryShared::has_class_failed_verification(this)) {
// This is for CDS dumping phase only -- we use the in_error_state to indicate that
// the class has failed verification. Throwing the NoClassDefFoundError here is just
// a convenient way to stop repeat attempts to verify the same (bad) class.
//
// Note that the NoClassDefFoundError is not part of the JLS, and should not be thrown
// if we are executing Java code. This is not a problem for CDS dumping phase since
// it doesn't execute any Java code.
ResourceMark rm(THREAD);
Exceptions::fthrow(THREAD_AND_LOCATION,
vmSymbols::java_lang_NoClassDefFoundError(),
"Class %s, or one of its supertypes, failed class initialization",
external_name());
return false;
}
// return if already verified
if (is_linked()) {
return true;
}
// Timing
// timer handles recursion
JavaThread* jt = THREAD;
// link super class before linking this class
Klass* super_klass = super();
if (super_klass != NULL) {
if (super_klass->is_interface()) { // check if super class is an interface
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IncompatibleClassChangeError(),
"class %s has interface %s as super class",
external_name(),
super_klass->external_name()
);
return false;
}
InstanceKlass* ik_super = InstanceKlass::cast(super_klass);
ik_super->link_class_impl(CHECK_false);
}
// link all interfaces implemented by this class before linking this class
Array<InstanceKlass*>* interfaces = local_interfaces();
int num_interfaces = interfaces->length();
for (int index = 0; index < num_interfaces; index++) {
InstanceKlass* interk = interfaces->at(index);
interk->link_class_impl(CHECK_false);
}
// in case the class is linked in the process of linking its superclasses
if (is_linked()) {
return true;
}
// trace only the link time for this klass that includes
// the verification time
PerfClassTraceTime vmtimer(ClassLoader::perf_class_link_time(),
ClassLoader::perf_class_link_selftime(),
ClassLoader::perf_classes_linked(),
jt->get_thread_stat()->perf_recursion_counts_addr(),
jt->get_thread_stat()->perf_timers_addr(),
PerfClassTraceTime::CLASS_LINK);
// verification & rewriting
{
LockLinkState init_lock(this, jt);
// rewritten will have been set if loader constraint error found
// on an earlier link attempt
// don't verify or rewrite if already rewritten
//
if (!is_linked()) {
if (!is_rewritten()) {
if (is_shared()) {
assert(!verified_at_dump_time(), "must be");
}
{
bool verify_ok = verify_code(THREAD);
if (!verify_ok) {
return false;
}
}
// Just in case a side-effect of verify linked this class already
// (which can sometimes happen since the verifier loads classes
// using custom class loaders, which are free to initialize things)
if (is_linked()) {
return true;
}
// also sets rewritten
rewrite_class(CHECK_false);
} else if (is_shared()) {
SystemDictionaryShared::check_verification_constraints(this, CHECK_false);
}
// relocate jsrs and link methods after they are all rewritten
link_methods(CHECK_false);
// Initialize the vtable and interface table after
// methods have been rewritten since rewrite may
// fabricate new Method*s.
// also does loader constraint checking
//
// initialize_vtable and initialize_itable need to be rerun
// for a shared class if
// 1) the class is loaded by custom class loader or
// 2) the class is loaded by built-in class loader but failed to add archived loader constraints or
// 3) the class was not verified during dump time
bool need_init_table = true;
if (is_shared() && verified_at_dump_time() &&
SystemDictionaryShared::check_linking_constraints(THREAD, this)) {
need_init_table = false;
}
if (need_init_table) {
vtable().initialize_vtable_and_check_constraints(CHECK_false);
itable().initialize_itable_and_check_constraints(CHECK_false);
}
#ifdef ASSERT
vtable().verify(tty, true);
// In case itable verification is ever added.
// itable().verify(tty, true);
#endif
set_initialization_state_and_notify(linked, THREAD);
if (JvmtiExport::should_post_class_prepare()) {
JvmtiExport::post_class_prepare(THREAD, this);
}
}
}
return true;
}
// Rewrite the byte codes of all of the methods of a class.
// The rewriter must be called exactly once. Rewriting must happen after
// verification but before the first method of the class is executed.
void InstanceKlass::rewrite_class(TRAPS) {
assert(is_loaded(), "must be loaded");
if (is_rewritten()) {
assert(is_shared(), "rewriting an unshared class?");
return;
}
Rewriter::rewrite(this, CHECK);
set_rewritten();
}
// Now relocate and link method entry points after class is rewritten.
// This is outside is_rewritten flag. In case of an exception, it can be
// executed more than once.
void InstanceKlass::link_methods(TRAPS) {
int len = methods()->length();
for (int i = len-1; i >= 0; i--) {
methodHandle m(THREAD, methods()->at(i));
// Set up method entry points for compiler and interpreter .
m->link_method(m, CHECK);
}
}
// Eagerly initialize superinterfaces that declare default methods (concrete instance: any access)
void InstanceKlass::initialize_super_interfaces(TRAPS) {
assert (has_nonstatic_concrete_methods(), "caller should have checked this");
for (int i = 0; i < local_interfaces()->length(); ++i) {
InstanceKlass* ik = local_interfaces()->at(i);
// Initialization is depth first search ie. we start with top of the inheritance tree
// has_nonstatic_concrete_methods drives searching superinterfaces since it
// means has_nonstatic_concrete_methods in its superinterface hierarchy
if (ik->has_nonstatic_concrete_methods()) {
ik->initialize_super_interfaces(CHECK);
}
// Only initialize() interfaces that "declare" concrete methods.
if (ik->should_be_initialized() && ik->declares_nonstatic_concrete_methods()) {
ik->initialize(CHECK);
}
}
}
ResourceHashtable<const InstanceKlass*, OopHandle, 107, AnyObj::C_HEAP, mtClass>
_initialization_error_table;
void InstanceKlass::add_initialization_error(JavaThread* current, Handle exception) {
// Create the same exception with a message indicating the thread name,
// and the StackTraceElements.
// If the initialization error is OOM, this might not work, but if GC kicks in
// this would be still be helpful.
JavaThread* THREAD = current;
Handle cause = java_lang_Throwable::get_cause_with_stack_trace(exception, THREAD);
if (HAS_PENDING_EXCEPTION || cause.is_null()) {
CLEAR_PENDING_EXCEPTION;
return;
}
MutexLocker ml(THREAD, ClassInitError_lock);
OopHandle elem = OopHandle(Universe::vm_global(), cause());
bool created = false;
_initialization_error_table.put_if_absent(this, elem, &created);
assert(created, "Initialization is single threaded");
ResourceMark rm(THREAD);
log_trace(class, init)("Initialization error added for class %s", external_name());
}
oop InstanceKlass::get_initialization_error(JavaThread* current) {
MutexLocker ml(current, ClassInitError_lock);
OopHandle* h = _initialization_error_table.get(this);
return (h != nullptr) ? h->resolve() : nullptr;
}
// Need to remove entries for unloaded classes.
void InstanceKlass::clean_initialization_error_table() {
struct InitErrorTableCleaner {
bool do_entry(const InstanceKlass* ik, OopHandle h) {
if (!ik->is_loader_alive()) {
h.release(Universe::vm_global());
return true;
} else {
return false;
}
}
};
assert_locked_or_safepoint(ClassInitError_lock);
InitErrorTableCleaner cleaner;
_initialization_error_table.unlink(&cleaner);
}
void InstanceKlass::initialize_impl(TRAPS) {
HandleMark hm(THREAD);
// Make sure klass is linked (verified) before initialization
// A class could already be verified, since it has been reflected upon.
link_class(CHECK);
DTRACE_CLASSINIT_PROBE(required, -1);
bool wait = false;
bool throw_error = false;
JavaThread* jt = THREAD;
// refer to the JVM book page 47 for description of steps
// Step 1
{
MonitorLocker ml(THREAD, _init_monitor);
// Step 2
while (is_being_initialized() && !is_init_thread(jt)) {
wait = true;
jt->set_class_to_be_initialized(this);
ml.wait();
jt->set_class_to_be_initialized(NULL);
}
// Step 3
if (is_being_initialized() && is_init_thread(jt)) {
DTRACE_CLASSINIT_PROBE_WAIT(recursive, -1, wait);
return;
}
// Step 4
if (is_initialized()) {
DTRACE_CLASSINIT_PROBE_WAIT(concurrent, -1, wait);
return;
}
// Step 5
if (is_in_error_state()) {
throw_error = true;
} else {
// Step 6
set_init_state(being_initialized);
set_init_thread(jt);
}
}
// Throw error outside lock
if (throw_error) {
DTRACE_CLASSINIT_PROBE_WAIT(erroneous, -1, wait);
ResourceMark rm(THREAD);
Handle cause(THREAD, get_initialization_error(THREAD));
stringStream ss;
ss.print("Could not initialize class %s", external_name());
if (cause.is_null()) {
THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), ss.as_string());
} else {
THROW_MSG_CAUSE(vmSymbols::java_lang_NoClassDefFoundError(),
ss.as_string(), cause);
}
}
// Step 7
// Next, if C is a class rather than an interface, initialize it's super class and super
// interfaces.
if (!is_interface()) {
Klass* super_klass = super();
if (super_klass != NULL && super_klass->should_be_initialized()) {
super_klass->initialize(THREAD);
}
// If C implements any interface that declares a non-static, concrete method,
// the initialization of C triggers initialization of its super interfaces.
// Only need to recurse if has_nonstatic_concrete_methods which includes declaring and
// having a superinterface that declares, non-static, concrete methods
if (!HAS_PENDING_EXCEPTION && has_nonstatic_concrete_methods()) {
initialize_super_interfaces(THREAD);
}
// If any exceptions, complete abruptly, throwing the same exception as above.
if (HAS_PENDING_EXCEPTION) {
Handle e(THREAD, PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;
{
EXCEPTION_MARK;
add_initialization_error(THREAD, e);
// Locks object, set state, and notify all waiting threads
set_initialization_state_and_notify(initialization_error, THREAD);
CLEAR_PENDING_EXCEPTION;
}
DTRACE_CLASSINIT_PROBE_WAIT(super__failed, -1, wait);
THROW_OOP(e());
}
}
// Step 8
{
DTRACE_CLASSINIT_PROBE_WAIT(clinit, -1, wait);
if (class_initializer() != NULL) {
// Timer includes any side effects of class initialization (resolution,
// etc), but not recursive entry into call_class_initializer().
PerfClassTraceTime timer(ClassLoader::perf_class_init_time(),
ClassLoader::perf_class_init_selftime(),
ClassLoader::perf_classes_inited(),
jt->get_thread_stat()->perf_recursion_counts_addr(),
jt->get_thread_stat()->perf_timers_addr(),
PerfClassTraceTime::CLASS_CLINIT);
call_class_initializer(THREAD);
} else {
// The elapsed time is so small it's not worth counting.
if (UsePerfData) {
ClassLoader::perf_classes_inited()->inc();
}
call_class_initializer(THREAD);
}
}
// Step 9
if (!HAS_PENDING_EXCEPTION) {
set_initialization_state_and_notify(fully_initialized, THREAD);
debug_only(vtable().verify(tty, true);)
}
else {
// Step 10 and 11
Handle e(THREAD, PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;
// JVMTI has already reported the pending exception
// JVMTI internal flag reset is needed in order to report ExceptionInInitializerError
JvmtiExport::clear_detected_exception(jt);
{
EXCEPTION_MARK;
add_initialization_error(THREAD, e);
set_initialization_state_and_notify(initialization_error, THREAD);
CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, class initialization error is thrown below
// JVMTI has already reported the pending exception
// JVMTI internal flag reset is needed in order to report ExceptionInInitializerError
JvmtiExport::clear_detected_exception(jt);
}
DTRACE_CLASSINIT_PROBE_WAIT(error, -1, wait);
if (e->is_a(vmClasses::Error_klass())) {
THROW_OOP(e());
} else {
JavaCallArguments args(e);
THROW_ARG(vmSymbols::java_lang_ExceptionInInitializerError(),
vmSymbols::throwable_void_signature(),
&args);
}
}
DTRACE_CLASSINIT_PROBE_WAIT(end, -1, wait);
}
void InstanceKlass::set_initialization_state_and_notify(ClassState state, JavaThread* current) {
MonitorLocker ml(current, _init_monitor);
// Now flush all code that assume the class is not linked.
// Set state under the Compile_lock also.
if (state == linked && UseVtableBasedCHA && Universe::is_fully_initialized()) {
MutexLocker ml(current, Compile_lock);
set_init_thread(NULL); // reset _init_thread before changing _init_state
set_init_state(state);
CodeCache::flush_dependents_on(this);
} else {
set_init_thread(NULL); // reset _init_thread before changing _init_state
set_init_state(state);
}
ml.notify_all();
}
InstanceKlass* InstanceKlass::implementor() const {
InstanceKlass* volatile* ik = adr_implementor();
if (ik == NULL) {
return NULL;
} else {
// This load races with inserts, and therefore needs acquire.
InstanceKlass* ikls = Atomic::load_acquire(ik);
if (ikls != NULL && !ikls->is_loader_alive()) {
return NULL; // don't return unloaded class
} else {
return ikls;
}
}
}
void InstanceKlass::set_implementor(InstanceKlass* ik) {
assert_locked_or_safepoint(Compile_lock);
assert(is_interface(), "not interface");
InstanceKlass* volatile* addr = adr_implementor();
assert(addr != NULL, "null addr");
if (addr != NULL) {
Atomic::release_store(addr, ik);
}
}
int InstanceKlass::nof_implementors() const {
InstanceKlass* ik = implementor();
if (ik == NULL) {
return 0;
} else if (ik != this) {
return 1;
} else {
return 2;
}
}
// The embedded _implementor field can only record one implementor.
// When there are more than one implementors, the _implementor field
// is set to the interface Klass* itself. Following are the possible
// values for the _implementor field:
// NULL - no implementor
// implementor Klass* - one implementor
// self - more than one implementor
//
// The _implementor field only exists for interfaces.
void InstanceKlass::add_implementor(InstanceKlass* ik) {
if (Universe::is_fully_initialized()) {
assert_lock_strong(Compile_lock);
}
assert(is_interface(), "not interface");
// Filter out my subinterfaces.
// (Note: Interfaces are never on the subklass list.)
if (ik->is_interface()) return;
// Filter out subclasses whose supers already implement me.
// (Note: CHA must walk subclasses of direct implementors
// in order to locate indirect implementors.)
InstanceKlass* super_ik = ik->java_super();
if (super_ik != NULL && super_ik->implements_interface(this))
// We only need to check one immediate superclass, since the
// implements_interface query looks at transitive_interfaces.
// Any supers of the super have the same (or fewer) transitive_interfaces.
return;
InstanceKlass* iklass = implementor();
if (iklass == NULL) {
set_implementor(ik);
} else if (iklass != this && iklass != ik) {
// There is already an implementor. Use itself as an indicator of
// more than one implementors.
set_implementor(this);
}
// The implementor also implements the transitive_interfaces
for (int index = 0; index < local_interfaces()->length(); index++) {
local_interfaces()->at(index)->add_implementor(ik);
}
}
void InstanceKlass::init_implementor() {
if (is_interface()) {
set_implementor(NULL);
}
}
void InstanceKlass::process_interfaces() {
// link this class into the implementors list of every interface it implements
for (int i = local_interfaces()->length() - 1; i >= 0; i--) {
assert(local_interfaces()->at(i)->is_klass(), "must be a klass");
InstanceKlass* interf = local_interfaces()->at(i);
assert(interf->is_interface(), "expected interface");
interf->add_implementor(this);
}
}
bool InstanceKlass::can_be_primary_super_slow() const {
if (is_interface())
return false;
else
return Klass::can_be_primary_super_slow();
}
GrowableArray<Klass*>* InstanceKlass::compute_secondary_supers(int num_extra_slots,
Array<InstanceKlass*>* transitive_interfaces) {
// The secondaries are the implemented interfaces.
Array<InstanceKlass*>* interfaces = transitive_interfaces;
int num_secondaries = num_extra_slots + interfaces->length();
if (num_secondaries == 0) {
// Must share this for correct bootstrapping!
set_secondary_supers(Universe::the_empty_klass_array());
return NULL;
} else if (num_extra_slots == 0) {
// The secondary super list is exactly the same as the transitive interfaces, so
// let's use it instead of making a copy.
// Redefine classes has to be careful not to delete this!
// We need the cast because Array<Klass*> is NOT a supertype of Array<InstanceKlass*>,
// (but it's safe to do here because we won't write into _secondary_supers from this point on).
set_secondary_supers((Array<Klass*>*)(address)interfaces);
return NULL;
} else {
// Copy transitive interfaces to a temporary growable array to be constructed
// into the secondary super list with extra slots.
GrowableArray<Klass*>* secondaries = new GrowableArray<Klass*>(interfaces->length());
for (int i = 0; i < interfaces->length(); i++) {
secondaries->push(interfaces->at(i));
}
return secondaries;
}
}
bool InstanceKlass::implements_interface(Klass* k) const {
if (this == k) return true;
assert(k->is_interface(), "should be an interface class");
for (int i = 0; i < transitive_interfaces()->length(); i++) {
if (transitive_interfaces()->at(i) == k) {
return true;
}
}
return false;
}
bool InstanceKlass::is_same_or_direct_interface(Klass *k) const {
// Verify direct super interface
if (this == k) return true;
assert(k->is_interface(), "should be an interface class");
for (int i = 0; i < local_interfaces()->length(); i++) {
if (local_interfaces()->at(i) == k) {
return true;
}
}
return false;
}
objArrayOop InstanceKlass::allocate_objArray(int n, int length, TRAPS) {
check_array_allocation_length(length, arrayOopDesc::max_array_length(T_OBJECT), CHECK_NULL);
size_t size = objArrayOopDesc::object_size(length);
Klass* ak = array_klass(n, CHECK_NULL);
objArrayOop o = (objArrayOop)Universe::heap()->array_allocate(ak, size, length,
/* do_zero */ true, CHECK_NULL);
return o;
}
instanceOop InstanceKlass::register_finalizer(instanceOop i, TRAPS) {
if (TraceFinalizerRegistration) {
tty->print("Registered ");
i->print_value_on(tty);
tty->print_cr(" (" PTR_FORMAT ") as finalizable", p2i(i));
}
instanceHandle h_i(THREAD, i);
// Pass the handle as argument, JavaCalls::call expects oop as jobjects
JavaValue result(T_VOID);
JavaCallArguments args(h_i);
methodHandle mh(THREAD, Universe::finalizer_register_method());
JavaCalls::call(&result, mh, &args, CHECK_NULL);
MANAGEMENT_ONLY(FinalizerService::on_register(h_i(), THREAD);)
return h_i();
}
instanceOop InstanceKlass::allocate_instance(TRAPS) {
bool has_finalizer_flag = has_finalizer(); // Query before possible GC
size_t size = size_helper(); // Query before forming handle.
instanceOop i;
i = (instanceOop)Universe::heap()->obj_allocate(this, size, CHECK_NULL);
if (has_finalizer_flag && !RegisterFinalizersAtInit) {
i = register_finalizer(i, CHECK_NULL);
}
return i;
}
instanceHandle InstanceKlass::allocate_instance_handle(TRAPS) {
return instanceHandle(THREAD, allocate_instance(THREAD));
}
void InstanceKlass::check_valid_for_instantiation(bool throwError, TRAPS) {
if (is_interface() || is_abstract()) {
ResourceMark rm(THREAD);
THROW_MSG(throwError ? vmSymbols::java_lang_InstantiationError()
: vmSymbols::java_lang_InstantiationException(), external_name());
}
if (this == vmClasses::Class_klass()) {
ResourceMark rm(THREAD);
THROW_MSG(throwError ? vmSymbols::java_lang_IllegalAccessError()
: vmSymbols::java_lang_IllegalAccessException(), external_name());
}
}
Klass* InstanceKlass::array_klass(int n, TRAPS) {
// Need load-acquire for lock-free read
if (array_klasses_acquire() == NULL) {
ResourceMark rm(THREAD);
JavaThread *jt = THREAD;
{
// Atomic creation of array_klasses
MutexLocker ma(THREAD, MultiArray_lock);
// Check if update has already taken place
if (array_klasses() == NULL) {
ObjArrayKlass* k = ObjArrayKlass::allocate_objArray_klass(class_loader_data(), 1, this, CHECK_NULL);
// use 'release' to pair with lock-free load
release_set_array_klasses(k);
}
}
}
// array_klasses() will always be set at this point
ObjArrayKlass* oak = array_klasses();
return oak->array_klass(n, THREAD);
}
Klass* InstanceKlass::array_klass_or_null(int n) {
// Need load-acquire for lock-free read
ObjArrayKlass* oak = array_klasses_acquire();
if (oak == NULL) {
return NULL;
} else {
return oak->array_klass_or_null(n);
}
}
Klass* InstanceKlass::array_klass(TRAPS) {
return array_klass(1, THREAD);
}
Klass* InstanceKlass::array_klass_or_null() {
return array_klass_or_null(1);
}
static int call_class_initializer_counter = 0; // for debugging
Method* InstanceKlass::class_initializer() const {
Method* clinit = find_method(
vmSymbols::class_initializer_name(), vmSymbols::void_method_signature());
if (clinit != NULL && clinit->has_valid_initializer_flags()) {
return clinit;
}
return NULL;
}
void InstanceKlass::call_class_initializer(TRAPS) {
if (ReplayCompiles &&
(ReplaySuppressInitializers == 1 ||
(ReplaySuppressInitializers >= 2 && class_loader() != NULL))) {
// Hide the existence of the initializer for the purpose of replaying the compile
return;
}
#if INCLUDE_CDS
// This is needed to ensure the consistency of the archived heap objects.
if (has_archived_enum_objs()) {
assert(is_shared(), "must be");
bool initialized = HeapShared::initialize_enum_klass(this, CHECK);
if (initialized) {
return;
}
}
#endif
methodHandle h_method(THREAD, class_initializer());
assert(!is_initialized(), "we cannot initialize twice");
LogTarget(Info, class, init) lt;
if (lt.is_enabled()) {
ResourceMark rm(THREAD);
LogStream ls(lt);
ls.print("%d Initializing ", call_class_initializer_counter++);
name()->print_value_on(&ls);
ls.print_cr("%s (" PTR_FORMAT ")", h_method() == NULL ? "(no method)" : "", p2i(this));
}
if (h_method() != NULL) {
JavaCallArguments args; // No arguments
JavaValue result(T_VOID);
JavaCalls::call(&result, h_method, &args, CHECK); // Static call (no args)
}
}
void InstanceKlass::mask_for(const methodHandle& method, int bci,
InterpreterOopMap* entry_for) {
// Lazily create the _oop_map_cache at first request
// Lock-free access requires load_acquire.
OopMapCache* oop_map_cache = Atomic::load_acquire(&_oop_map_cache);
if (oop_map_cache == NULL) {
MutexLocker x(OopMapCacheAlloc_lock);
// Check if _oop_map_cache was allocated while we were waiting for this lock
if ((oop_map_cache = _oop_map_cache) == NULL) {
oop_map_cache = new OopMapCache();
// Ensure _oop_map_cache is stable, since it is examined without a lock
Atomic::release_store(&_oop_map_cache, oop_map_cache);
}
}
// _oop_map_cache is constant after init; lookup below does its own locking.
oop_map_cache->lookup(method, bci, entry_for);
}
bool InstanceKlass::contains_field_offset(int offset) {
fieldDescriptor fd;
return find_field_from_offset(offset, false, &fd);
}
bool InstanceKlass::find_local_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const {
for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
Symbol* f_name = fs.name();
Symbol* f_sig = fs.signature();
if (f_name == name && f_sig == sig) {
fd->reinitialize(const_cast<InstanceKlass*>(this), fs.index());
return true;
}
}
return false;
}
Klass* InstanceKlass::find_interface_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const {
const int n = local_interfaces()->length();
for (int i = 0; i < n; i++) {
Klass* intf1 = local_interfaces()->at(i);
assert(intf1->is_interface(), "just checking type");
// search for field in current interface
if (InstanceKlass::cast(intf1)->find_local_field(name, sig, fd)) {
assert(fd->is_static(), "interface field must be static");
return intf1;
}
// search for field in direct superinterfaces
Klass* intf2 = InstanceKlass::cast(intf1)->find_interface_field(name, sig, fd);
if (intf2 != NULL) return intf2;
}
// otherwise field lookup fails
return NULL;
}
Klass* InstanceKlass::find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const {
// search order according to newest JVM spec (5.4.3.2, p.167).
// 1) search for field in current klass
if (find_local_field(name, sig, fd)) {
return const_cast<InstanceKlass*>(this);
}
// 2) search for field recursively in direct superinterfaces
{ Klass* intf = find_interface_field(name, sig, fd);
if (intf != NULL) return intf;
}
// 3) apply field lookup recursively if superclass exists
{ Klass* supr = super();
if (supr != NULL) return InstanceKlass::cast(supr)->find_field(name, sig, fd);
}
// 4) otherwise field lookup fails
return NULL;
}
Klass* InstanceKlass::find_field(Symbol* name, Symbol* sig, bool is_static, fieldDescriptor* fd) const {
// search order according to newest JVM spec (5.4.3.2, p.167).
// 1) search for field in current klass
if (find_local_field(name, sig, fd)) {
if (fd->is_static() == is_static) return const_cast<InstanceKlass*>(this);
}
// 2) search for field recursively in direct superinterfaces
if (is_static) {
Klass* intf = find_interface_field(name, sig, fd);
if (intf != NULL) return intf;
}
// 3) apply field lookup recursively if superclass exists
{ Klass* supr = super();
if (supr != NULL) return InstanceKlass::cast(supr)->find_field(name, sig, is_static, fd);
}
// 4) otherwise field lookup fails
return NULL;
}
bool InstanceKlass::find_local_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const {
for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
if (fs.offset() == offset) {
fd->reinitialize(const_cast<InstanceKlass*>(this), fs.index());
if (fd->is_static() == is_static) return true;
}
}
return false;
}
bool InstanceKlass::find_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const {
Klass* klass = const_cast<InstanceKlass*>(this);
while (klass != NULL) {
if (InstanceKlass::cast(klass)->find_local_field_from_offset(offset, is_static, fd)) {
return true;
}
klass = klass->super();
}
return false;
}
void InstanceKlass::methods_do(void f(Method* method)) {
// Methods aren't stable until they are loaded. This can be read outside
// a lock through the ClassLoaderData for profiling
// Redefined scratch classes are on the list and need to be cleaned
if (!is_loaded() && !is_scratch_class()) {
return;
}
int len = methods()->length();
for (int index = 0; index < len; index++) {
Method* m = methods()->at(index);
assert(m->is_method(), "must be method");
f(m);
}
}
void InstanceKlass::do_local_static_fields(FieldClosure* cl) {
for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
if (fs.access_flags().is_static()) {
fieldDescriptor& fd = fs.field_descriptor();
cl->do_field(&fd);
}
}
}
void InstanceKlass::do_local_static_fields(void f(fieldDescriptor*, Handle, TRAPS), Handle mirror, TRAPS) {
for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
if (fs.access_flags().is_static()) {
fieldDescriptor& fd = fs.field_descriptor();
f(&fd, mirror, CHECK);
}
}
}
void InstanceKlass::do_nonstatic_fields(FieldClosure* cl) {
InstanceKlass* super = superklass();
if (super != NULL) {
super->do_nonstatic_fields(cl);
}
fieldDescriptor fd;
int length = java_fields_count();
for (int i = 0; i < length; i += 1) {
fd.reinitialize(this, i);
if (!fd.is_static()) {
cl->do_field(&fd);
}
}
}
// first in Pair is offset, second is index.
static int compare_fields_by_offset(Pair<int,int>* a, Pair<int,int>* b) {
return a->first - b->first;
}
void InstanceKlass::print_nonstatic_fields(FieldClosure* cl) {
InstanceKlass* super = superklass();
if (super != NULL) {
super->print_nonstatic_fields(cl);
}
ResourceMark rm;
fieldDescriptor fd;
// In DebugInfo nonstatic fields are sorted by offset.
GrowableArray<Pair<int,int> > fields_sorted;
int i = 0;
for (AllFieldStream fs(this); !fs.done(); fs.next()) {
if (!fs.access_flags().is_static()) {
fd = fs.field_descriptor();
Pair<int,int> f(fs.offset(), fs.index());
fields_sorted.push(f);
i++;
}
}
if (i > 0) {
int length = i;
assert(length == fields_sorted.length(), "duh");
// _sort_Fn is defined in growableArray.hpp.
fields_sorted.sort(compare_fields_by_offset);
for (int i = 0; i < length; i++) {
fd.reinitialize(this, fields_sorted.at(i).second);
assert(!fd.is_static() && fd.offset() == fields_sorted.at(i).first, "only nonstatic fields");
cl->do_field(&fd);
}
}
}
#ifdef ASSERT
static int linear_search(const Array<Method*>* methods,
const Symbol* name,
const Symbol* signature) {
const int len = methods->length();
for (int index = 0; index < len; index++) {
const Method* const m = methods->at(index);
assert(m->is_method(), "must be method");
if (m->signature() == signature && m->name() == name) {
return index;
}
}
return -1;
}
#endif
bool InstanceKlass::_disable_method_binary_search = false;
NOINLINE int linear_search(const Array<Method*>* methods, const Symbol* name) {
int len = methods->length();
int l = 0;
int h = len - 1;
while (l <= h) {
Method* m = methods->at(l);
if (m->name() == name) {
return l;
}
l++;
}
return -1;
}
inline int InstanceKlass::quick_search(const Array<Method*>* methods, const Symbol* name) {
if (_disable_method_binary_search) {
assert(DynamicDumpSharedSpaces, "must be");
// At the final stage of dynamic dumping, the methods array may not be sorted
// by ascending addresses of their names, so we can't use binary search anymore.
// However, methods with the same name are still laid out consecutively inside the
// methods array, so let's look for the first one that matches.
return linear_search(methods, name);
}
int len = methods->length();
int l = 0;
int h = len - 1;
// methods are sorted by ascending addresses of their names, so do binary search
while (l <= h) {
int mid = (l + h) >> 1;
Method* m = methods->at(mid);
assert(m->is_method(), "must be method");
int res = m->name()->fast_compare(name);
if (res == 0) {
return mid;
} else if (res < 0) {
l = mid + 1;
} else {
h = mid - 1;
}
}
return -1;
}
// find_method looks up the name/signature in the local methods array
Method* InstanceKlass::find_method(const Symbol* name,
const Symbol* signature) const {
return find_method_impl(name, signature,
OverpassLookupMode::find,
StaticLookupMode::find,
PrivateLookupMode::find);
}
Method* InstanceKlass::find_method_impl(const Symbol* name,
const Symbol* signature,
OverpassLookupMode overpass_mode,
StaticLookupMode static_mode,
PrivateLookupMode private_mode) const {
return InstanceKlass::find_method_impl(methods(),
name,
signature,
overpass_mode,
static_mode,
private_mode);
}
// find_instance_method looks up the name/signature in the local methods array
// and skips over static methods
--> --------------------
--> maximum size reached
--> --------------------
¤ Dauer der Verarbeitung: 0.75 Sekunden
(vorverarbeitet)
¤
|
Haftungshinweis
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.
|