/* * 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. *
*/
// 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());
} returnfalse;
}
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); returntrue;
}
}
log_trace(class, nestmates)("- class is NOT a nest member!"); returnfalse;
}
// 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()); returnfalse;
}
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()); returnfalse;
}
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); returntrue;
}
}
log_trace(class, sealed)("- class is NOT a permitted subclass!"); returnfalse;
}
// 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); constchar* 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. constchar* 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); constchar* 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; constchar* 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)";
} elseif (_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.
// Allocation if (parser.is_instance_ref_klass()) { // java.lang.ref.Reference
ik = new (loader_data, size, THREAD) InstanceRefKlass(parser);
} elseif (class_name == vmSymbols::java_lang_Class()) { // mirror - java.lang.Class
ik = new (loader_data, size, THREAD) InstanceMirrorKlass(parser);
} elseif (is_stack_chunk_class(class_name, loader_data)) { // stack chunk
ik = new (loader_data, size, THREAD) InstanceStackChunkKlass(parser);
} elseif (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;
}
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);
// 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);
// 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());
// 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);
// 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");
}
}
// 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()); returnfalse;
} // return if already verified if (is_linked()) { returntrue;
}
// 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()
); returnfalse;
}
// 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()) { returntrue;
}
// 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);
// 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) { returnfalse;
}
}
// 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()) { returntrue;
}
// 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);
}
}
} returntrue;
}
// 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);
}
}
}
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());
}
// 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);
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);
}
// 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);
int InstanceKlass::nof_implementors() const {
InstanceKlass* ik = implementor(); if (ik == NULL) { return 0;
} elseif (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);
} elseif (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);
}
}
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;
} elseif (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) returntrue;
assert(k->is_interface(), "should be an interface class"); for (int i = 0; i < transitive_interfaces()->length(); i++) { if (transitive_interfaces()->at(i) == k) { returntrue;
}
} returnfalse;
}
bool InstanceKlass::is_same_or_direct_interface(Klass *k) const { // Verify direct super interface if (this == k) returntrue;
assert(k->is_interface(), "should be an interface class"); for (int i = 0; i < local_interfaces()->length(); i++) { if (local_interfaces()->at(i) == k) { returntrue;
}
} returnfalse;
}
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;
}
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);
}
}
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
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);
}
Klass* InstanceKlass::find_interface_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const { constint 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)) { returnconst_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) returnconst_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_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)) { returntrue;
}
klass = klass->super();
} returnfalse;
}
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);
}
}
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;
}
inlineint 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;
} elseif (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);
}
// find_instance_method looks up the name/signature in the local methods array // and skips over static methods
--> --------------------
--> maximum size reached
--> --------------------
¤ 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.0.34Bemerkung:
(vorverarbeitet)
¤
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.