/* * Copyright (c) 2003, 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. *
*/
constint _placeholder_table_size = 503; // Does this really have to be prime?
ResourceHashtable<PlaceholderKey, PlaceholderEntry, _placeholder_table_size, AnyObj::C_HEAP, mtClass,
PlaceholderKey::hash, PlaceholderKey::equals> _placeholders;
// SeenThread objects represent list of threads that are // currently performing a load action on a class. // For class circularity, set before loading a superclass. // For bootclasssearchpath, set before calling load_instance_class. // Defining must be single threaded on a class/classloader basis // For DEFINE_CLASS, the head of the queue owns the // define token and the rest of the threads wait to return the // result the first thread gets. class SeenThread: public CHeapObj<mtInternal> { private:
JavaThread* _thread;
SeenThread* _stnext;
SeenThread* _stprev; public:
SeenThread(JavaThread* thread) {
_thread = thread;
_stnext = NULL;
_stprev = NULL;
}
JavaThread* thread() const { return _thread;} void set_thread(JavaThread* thread) { _thread = thread; }
// Doubly-linked list of Threads per action for class/classloader pair // Class circularity support: links in thread before loading superclass // bootstrap loader support: links in a thread before load_instance_class // definers: use as queue of define requestors, including owner of // define token. Appends for debugging of requestor order void PlaceholderEntry::add_seen_thread(JavaThread* thread, PlaceholderTable::classloadAction action) {
assert_lock_strong(SystemDictionary_lock);
SeenThread* threadEntry = new SeenThread(thread);
SeenThread* seen = actionToQueue(action);
assert(action != PlaceholderTable::LOAD_INSTANCE || !EnableWaitForParallelLoad || seen == NULL, "Only one LOAD_INSTANCE allowed at a time");
if (seen == NULL) {
set_threadQ(threadEntry, action); return;
}
SeenThread* next; while ((next = seen->next()) != NULL) {
seen = next;
}
seen->set_next(threadEntry);
threadEntry->set_prev(seen); return;
}
bool PlaceholderEntry::check_seen_thread(JavaThread* thread, PlaceholderTable::classloadAction action) {
assert_lock_strong(SystemDictionary_lock);
SeenThread* threadQ = actionToQueue(action);
SeenThread* seen = threadQ; while (seen) { if (thread == seen->thread()) { returntrue;
}
seen = seen->next();
} returnfalse;
}
// returns true if seenthreadQ is now empty // Note, caller must ensure probe still exists while holding // SystemDictionary_lock // ignores if cleanup has already been done // if found, deletes SeenThread bool PlaceholderEntry::remove_seen_thread(JavaThread* thread, PlaceholderTable::classloadAction action) {
assert_lock_strong(SystemDictionary_lock);
SeenThread* threadQ = actionToQueue(action);
SeenThread* seen = threadQ;
SeenThread* prev = NULL; while (seen) { if (thread == seen->thread()) { if (prev) {
prev->set_next(seen->next());
} else {
set_threadQ(seen->next(), action);
} if (seen->next()) {
seen->next()->set_prev(prev);
} delete seen; break;
}
prev = seen;
seen = seen->next();
} return (actionToQueue(action) == NULL);
}
// Placeholder methods
// Placeholder objects represent classes currently being loaded. // All threads examining the placeholder table must hold the // SystemDictionary_lock, so we don't need special precautions // on store ordering here.
PlaceholderEntry* add_entry(Symbol* class_name, ClassLoaderData* loader_data,
Symbol* supername){
assert_locked_or_safepoint(SystemDictionary_lock);
assert(class_name != NULL, "adding NULL obj");
// find_and_add returns probe pointer - old or new // If no entry exists, add a placeholder entry // If entry exists, reuse entry // For both, push SeenThread for classloadAction // If LOAD_SUPER, this is used for circularity detection for instanceklass loading.
PlaceholderEntry* PlaceholderTable::find_and_add(Symbol* name,
ClassLoaderData* loader_data,
classloadAction action,
Symbol* supername,
JavaThread* thread) {
assert(action != LOAD_SUPER || supername != NULL, "must have a super class name");
PlaceholderEntry* probe = get_entry(name, loader_data); if (probe == NULL) { // Nothing found, add place holder
probe = add_entry(name, loader_data, supername);
} else { if (action == LOAD_SUPER) {
probe->set_supername(supername);
}
}
probe->add_seen_thread(thread, action);
log(name, probe, "find_and_add", action); return probe;
}
// placeholder is used to track class loading internal states // placeholder existence now for loading superclass/superinterface // superthreadQ tracks class circularity, while loading superclass/superinterface // loadInstanceThreadQ tracks load_instance_class calls // definer() tracks the single thread that owns define token // defineThreadQ tracks waiters on defining thread's results // 1st claimant creates placeholder // find_and_add adds SeenThread entry for appropriate queue // All claimants remove SeenThread after completing action // On removal: if definer and all queues empty, remove entry // Note: you can be in both placeholders and systemDictionary // Therefore - must always check SD first // Ignores the case where entry is not found void PlaceholderTable::find_and_remove(Symbol* name, ClassLoaderData* loader_data,
classloadAction action,
JavaThread* thread) {
assert_locked_or_safepoint(SystemDictionary_lock);
PlaceholderEntry* probe = get_entry(name, loader_data); if (probe != NULL) {
log(name, probe, "find_and_remove", action);
probe->remove_seen_thread(thread, action); // If no other threads using this entry, and this thread is not using this entry for other states if ((probe->superThreadQ() == NULL) && (probe->loadInstanceThreadQ() == NULL)
&& (probe->defineThreadQ() == NULL) && (probe->definer() == NULL)) {
probe->clear_supername();
remove_entry(name, loader_data);
}
}
}
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.