/* * 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. *
*/
// Helpful routine for computing field offsets at run time rather than hardcoding them // Finds local fields only, including static fields. Static field offsets are from the // beginning of the mirror. void JavaClasses::compute_offset(int &dest_offset,
InstanceKlass* ik, Symbol* name_symbol, Symbol* signature_symbol, bool is_static) {
fieldDescriptor fd; if (ik == NULL) {
ResourceMark rm;
log_error(class)("Mismatch JDK version for field: %s type: %s", name_symbol->as_C_string(), signature_symbol->as_C_string());
vm_exit_during_initialization("Invalid layout of well-known class");
}
if (!ik->find_local_field(name_symbol, signature_symbol, &fd) || fd.is_static() != is_static) {
ResourceMark rm;
log_error(class)("Invalid layout of %s field: %s type: %s", ik->external_name(),
name_symbol->as_C_string(), signature_symbol->as_C_string()); #ifndef PRODUCT // Prints all fields and offsets
Log(class) lt;
LogStream ls(lt.error());
ik->print_on(&ls); #endif//PRODUCT
vm_exit_during_initialization("Invalid layout of well-known class: use -Xlog:class+load=info to see the origin of the problem class");
}
dest_offset = fd.offset();
}
// Overloading to pass name as a string. void JavaClasses::compute_offset(int& dest_offset, InstanceKlass* ik, constchar* name_string, Symbol* signature_symbol, bool is_static) {
TempNewSymbol name = SymbolTable::probe(name_string, (int)strlen(name_string)); if (name == NULL) {
ResourceMark rm;
log_error(class)("Name %s should be in the SymbolTable since its class is loaded", name_string);
vm_exit_during_initialization("Invalid layout of well-known class", ik->external_name());
}
compute_offset(dest_offset, ik, name, signature_symbol, is_static);
}
// java_lang_String
int java_lang_String::_value_offset; int java_lang_String::_hash_offset; int java_lang_String::_hashIsZero_offset; int java_lang_String::_coder_offset; int java_lang_String::_flags_offset;
bool java_lang_String::_initialized;
bool java_lang_String::test_and_set_flag(oop java_string, uint8_t flag_mask) {
uint8_t* addr = flags_addr(java_string);
uint8_t value = Atomic::load(addr); while ((value & flag_mask) == 0) {
uint8_t old_value = value;
value |= flag_mask;
value = Atomic::cmpxchg(addr, old_value, value); if (value == old_value) returnfalse; // Flag bit changed from 0 to 1.
} returntrue; // Flag bit is already 1.
}
Handle java_lang_String::basic_create(int length, bool is_latin1, TRAPS) {
assert(_initialized, "Must be initialized");
assert(CompactStrings || !is_latin1, "Must be UTF16 without CompactStrings");
// Create the String object first, so there's a chance that the String // and the char array it points to end up in the same cache line.
oop obj;
obj = vmClasses::String_klass()->allocate_instance(CHECK_NH);
// Create the char array. The String object must be handlized here // because GC can happen as a result of the allocation attempt.
Handle h_obj(THREAD, obj); int arr_length = is_latin1 ? length : length << 1; // 2 bytes per UTF16.
typeArrayOop buffer = oopFactory::new_byteArray(arr_length, CHECK_NH);;
// Point the String at the char array
obj = h_obj();
set_value(obj, buffer); // No need to zero the offset, allocation zero'ed the entire String object
set_coder(obj, is_latin1 ? CODER_LATIN1 : CODER_UTF16); return h_obj;
}
Handle java_lang_String::create_from_unicode(const jchar* unicode, int length, TRAPS) { bool is_latin1 = CompactStrings && UNICODE::is_latin1(unicode, length);
Handle h_obj = basic_create(length, is_latin1, CHECK_NH);
typeArrayOop buffer = value(h_obj());
assert(TypeArrayKlass::cast(buffer->klass())->element_type() == T_BYTE, "only byte[]"); if (is_latin1) { for (int index = 0; index < length; index++) {
buffer->byte_at_put(index, (jbyte)unicode[index]);
}
} else { for (int index = 0; index < length; index++) {
buffer->char_at_put(index, unicode[index]);
}
}
#ifdef ASSERT // This check is too strict when the input string is not a valid UTF8. // For example, it may be created with arbitrary content via jni_NewStringUTF. if (UTF8::is_legal_utf8((constunsignedchar*)utf8_str, (int)strlen(utf8_str), false)) {
ResourceMark rm; constchar* expected = utf8_str; char* actual = as_utf8_string(h_obj()); if (strcmp(expected, actual) != 0) {
fatal("String conversion failure: %s --> %s", expected, actual);
}
} #endif
// Converts a C string to a Java String based on current encoding
Handle java_lang_String::create_from_platform_dependent_str(constchar* str, TRAPS) {
assert(str != NULL, "bad arguments");
// Converts a Java String to a native C string that can be used for // native OS calls. char* java_lang_String::as_platform_dependent_str(Handle java_string, TRAPS) { typedefchar* (*to_platform_string_fn_t)(JNIEnv*, jstring, bool*); static to_platform_string_fn_t _to_platform_string_fn = NULL;
jchar* result = NEW_RESOURCE_ARRAY_RETURN_NULL(jchar, length); if (result != NULL) { if (!is_latin1) { for (int index = 0; index < length; index++) {
result[index] = value->char_at(index);
}
} else { for (int index = 0; index < length; index++) {
result[index] = ((jchar) value->byte_at(index)) & 0xff;
}
}
} return result;
}
inlineunsignedint java_lang_String::hash_code_impl(oop java_string, bool update) { // The hash and hashIsZero fields are subject to a benign data race, // making it crucial to ensure that any observable result of the // calculation in this method stays correct under any possible read of // these fields. Necessary restrictions to allow this to be correct // without explicit memory fences or similar concurrency primitives is // that we can ever only write to one of these two fields for a given // String instance, and that the computation is idempotent and derived // from immutable state
assert(_initialized && (_hash_offset > 0) && (_hashIsZero_offset > 0), "Must be initialized"); if (java_lang_String::hash_is_set(java_string)) { return java_string->int_field(_hash_offset);
}
typeArrayOop value = java_lang_String::value(java_string); int length = java_lang_String::length(java_string, value); bool is_latin1 = java_lang_String::is_latin1(java_string);
if (is_latin1 != is_latin2) { // Strings with different coders are never equal. returnfalse;
} return value_equals(value1, value2);
}
void java_lang_String::print(oop java_string, outputStream* st) {
assert(java_string->klass() == vmClasses::String_klass(), "must be java_string");
typeArrayOop value = java_lang_String::value_no_keepalive(java_string);
if (value == NULL) { // This can happen if, e.g., printing a String // object before its initializer has been called
st->print("NULL"); return;
}
int length = java_lang_String::length(java_string, value); bool is_latin1 = java_lang_String::is_latin1(java_string);
st->print("\""); for (int index = 0; index < length; index++) {
st->print("%c", (!is_latin1) ? value->char_at(index) :
((jchar) value->byte_at(index)) & 0xff );
}
st->print("\"");
}
// java_lang_Class
int java_lang_Class::_klass_offset; int java_lang_Class::_array_klass_offset; int java_lang_Class::_oop_size_offset; int java_lang_Class::_static_oop_field_count_offset; int java_lang_Class::_class_loader_offset; int java_lang_Class::_module_offset; int java_lang_Class::_protection_domain_offset; int java_lang_Class::_component_mirror_offset; int java_lang_Class::_signers_offset; int java_lang_Class::_name_offset; int java_lang_Class::_source_file_offset; int java_lang_Class::_classData_offset; int java_lang_Class::_classRedefinedCount_offset;
#ifdef ASSERT inlinestaticvoid assert_valid_static_string_field(fieldDescriptor* fd) {
assert(fd->has_initial_value(), "caller should have checked this");
assert(fd->field_type() == T_OBJECT, "caller should have checked this"); // Can't use vmSymbols::string_signature() as fd->signature() may have been relocated // during DumpSharedSpaces
assert(fd->signature()->equals("Ljava/lang/String;"), "just checking");
} #endif
#if INCLUDE_CDS_JAVA_HEAP staticvoid initialize_static_string_field_for_dump(fieldDescriptor* fd, Handle mirror) {
DEBUG_ONLY(assert_valid_static_string_field(fd);)
assert(DumpSharedSpaces, "must be");
assert(HeapShared::is_archived_object_during_dumptime(mirror()), "must be"); // Archive the String field and update the pointer.
oop s = mirror()->obj_field(fd->offset());
oop archived_s = StringTable::create_archived_string(s);
mirror()->obj_field_put(fd->offset(), archived_s);
} #endif
staticvoid initialize_static_primitive_field(fieldDescriptor* fd, Handle mirror) {
assert(fd->has_initial_value(), "caller should have checked this");
BasicType t = fd->field_type(); switch (t) { case T_BYTE:
mirror()->byte_field_put(fd->offset(), fd->int_initial_value()); break; case T_BOOLEAN:
mirror()->bool_field_put(fd->offset(), fd->int_initial_value()); break; case T_CHAR:
mirror()->char_field_put(fd->offset(), fd->int_initial_value()); break; case T_SHORT:
mirror()->short_field_put(fd->offset(), fd->int_initial_value()); break; case T_INT:
mirror()->int_field_put(fd->offset(), fd->int_initial_value()); break; case T_FLOAT:
mirror()->float_field_put(fd->offset(), fd->float_initial_value()); break; case T_DOUBLE:
mirror()->double_field_put(fd->offset(), fd->double_initial_value()); break; case T_LONG:
mirror()->long_field_put(fd->offset(), fd->long_initial_value()); break; default: // Illegal ConstantValue attribute in class file should have been // caught during classfile parsing.
ShouldNotReachHere();
}
}
void java_lang_Class::fixup_mirror(Klass* k, TRAPS) {
assert(InstanceMirrorKlass::offset_of_static_fields() != 0, "must have been computed already");
// If the offset was read from the shared archive, it was fixed up already if (!k->is_shared()) { if (k->is_instance_klass()) { // During bootstrap, java.lang.Class wasn't loaded so static field // offsets were computed without the size added it. Go back and // update all the static field offsets to included the size. for (JavaFieldStream fs(InstanceKlass::cast(k)); !fs.done(); fs.next()) { if (fs.access_flags().is_static()) { int real_offset = fs.offset() + InstanceMirrorKlass::offset_of_static_fields();
fs.set_offset(real_offset);
}
}
}
}
// Set classData
set_class_data(mirror(), classData());
}
// Set the java.lang.Module module field in the java_lang_Class mirror void java_lang_Class::set_mirror_module_field(JavaThread* current, Klass* k, Handle mirror, Handle module) { if (module.is_null()) { // During startup, the module may be NULL only if java.base has not been defined yet. // Put the class on the fixup_module_list to patch later when the java.lang.Module // for java.base is known. But note that since we captured the NULL module another // thread may have completed that initialization.
bool javabase_was_defined = false;
{
MutexLocker m1(current, Module_lock); // Keep list of classes needing java.base module fixup if (!ModuleEntryTable::javabase_defined()) {
assert(k->java_mirror() != NULL, "Class's mirror is null");
k->class_loader_data()->inc_keep_alive();
assert(fixup_module_field_list() != NULL, "fixup_module_field_list not initialized");
fixup_module_field_list()->push(k);
} else {
javabase_was_defined = true;
}
}
// If java.base was already defined then patch this particular class with java.base. if (javabase_was_defined) {
ModuleEntry *javabase_entry = ModuleEntryTable::javabase_moduleEntry();
assert(javabase_entry != NULL && javabase_entry->module() != NULL, "Setting class module field, " JAVA_BASE_NAME " should be defined");
Handle javabase_handle(current, javabase_entry->module());
set_module(mirror(), javabase_handle());
}
} else {
assert(Universe::is_module_initialized() ||
(ModuleEntryTable::javabase_defined() &&
(module() == ModuleEntryTable::javabase_moduleEntry()->module())), "Incorrect java.lang.Module specification while creating mirror");
set_module(mirror(), module());
}
}
// Statically allocate fixup lists because they always get created. void java_lang_Class::allocate_fixup_lists() {
GrowableArray<Klass*>* mirror_list = new (mtClass) GrowableArray<Klass*>(40, mtClass);
set_fixup_mirror_list(mirror_list);
GrowableArray<Klass*>* module_list = new (mtModule) GrowableArray<Klass*>(500, mtModule);
set_fixup_module_field_list(module_list);
}
// Use this moment of initialization to cache modifier_flags also, // to support Class.getModifiers(). Instance classes recalculate // the cached flags after the class file is parsed, but before the // class is put into the system dictionary. int computed_modifiers = k->compute_modifier_flags();
k->set_modifier_flags(computed_modifiers); // Class_klass has to be loaded because it is used to allocate // the mirror. if (vmClasses::Class_klass_loaded()) { // Allocate mirror (java.lang.Class instance)
oop mirror_oop = InstanceMirrorKlass::cast(vmClasses::Class_klass())->allocate_instance(k, CHECK);
Handle mirror(THREAD, mirror_oop);
Handle comp_mirror;
// Setup indirection from mirror->klass
set_klass(mirror(), k);
InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(mirror->klass());
assert(oop_size(mirror()) == mk->instance_size(k), "should have been set");
// It might also have a component mirror. This mirror must already exist. if (k->is_array_klass()) { if (k->is_typeArray_klass()) {
BasicType type = TypeArrayKlass::cast(k)->element_type();
comp_mirror = Handle(THREAD, Universe::java_mirror(type));
} else {
assert(k->is_objArray_klass(), "Must be");
Klass* element_klass = ObjArrayKlass::cast(k)->element_klass();
assert(element_klass != NULL, "Must have an element klass");
comp_mirror = Handle(THREAD, element_klass->java_mirror());
}
assert(comp_mirror() != NULL, "must have a mirror");
// Two-way link between the array klass and its component mirror: // (array_klass) k -> mirror -> component_mirror -> array_klass -> k
set_component_mirror(mirror(), comp_mirror()); // See below for ordering dependencies between field array_klass in component mirror // and java_mirror in this klass.
} else {
assert(k->is_instance_klass(), "Must be");
initialize_mirror_fields(k, mirror, protection_domain, classData, THREAD); if (HAS_PENDING_EXCEPTION) { // If any of the fields throws an exception like OOM remove the klass field // from the mirror so GC doesn't follow it after the klass has been deallocated. // This mirror looks like a primitive type, which logically it is because it // it represents no class.
set_klass(mirror(), NULL); return;
}
}
// set the classLoader field in the java_lang_Class instance
assert(class_loader() == k->class_loader(), "should be same");
set_class_loader(mirror(), class_loader());
// Setup indirection from klass->mirror // after any exceptions can happen during allocations.
k->set_java_mirror(mirror);
// Set the module field in the java_lang_Class instance. This must be done // after the mirror is set.
set_mirror_module_field(THREAD, k, mirror, module);
if (comp_mirror() != NULL) { // Set after k->java_mirror() is published, because compiled code running // concurrently doesn't expect a k to have a null java_mirror.
release_set_array_klass(comp_mirror(), k);
}
} else {
assert(fixup_mirror_list() != NULL, "fixup_mirror_list not initialized");
fixup_mirror_list()->push(k);
}
}
#if INCLUDE_CDS_JAVA_HEAP // Clears mirror fields. Static final fields with initial values are reloaded // from constant pool. The object identity hash is in the object header and is // not affected. class ResetMirrorField: public FieldClosure { private:
Handle _m;
void do_field(fieldDescriptor* fd) {
assert(DumpSharedSpaces, "dump time only");
assert(_m.not_null(), "Mirror cannot be NULL");
if (fd->is_static() && fd->has_initial_value()) {
initialize_static_field_for_dump(fd, _m); return;
}
BasicType ft = fd->field_type(); switch (ft) { case T_BYTE:
_m()->byte_field_put(fd->offset(), 0); break; case T_CHAR:
_m()->char_field_put(fd->offset(), 0); break; case T_DOUBLE:
_m()->double_field_put(fd->offset(), 0); break; case T_FLOAT:
_m()->float_field_put(fd->offset(), 0); break; case T_INT:
_m()->int_field_put(fd->offset(), 0); break; case T_LONG:
_m()->long_field_put(fd->offset(), 0); break; case T_SHORT:
_m()->short_field_put(fd->offset(), 0); break; case T_BOOLEAN:
_m()->bool_field_put(fd->offset(), false); break; case T_ARRAY: case T_OBJECT: { // It might be useful to cache the String field, but // for now just clear out any reference field
oop o = _m()->obj_field(fd->offset());
_m()->obj_field_put(fd->offset(), NULL); break;
} default:
ShouldNotReachHere(); break;
}
}
};
for (int t = T_BOOLEAN; t < T_VOID+1; t++) {
BasicType bt = (BasicType)t; if (!is_reference_type(bt)) {
oop m = Universe::java_mirror(bt);
assert(m != NULL, "sanity"); // Update the field at _array_klass_offset to point to the relocated array klass.
oop archived_m = HeapShared::archive_object(m);
assert(archived_m != NULL, "sanity");
// Clear the fields. Just to be safe
Klass *k = m->klass();
Handle archived_mirror_h(Thread::current(), archived_m);
ResetMirrorField reset(archived_mirror_h);
InstanceKlass::cast(k)->do_nonstatic_fields(&reset);
Universe::set_archived_basic_type_mirror_index(bt, HeapShared::append_root(archived_m));
}
}
} // // After the mirror object is successfully archived, the archived // klass is set with _has_archived_raw_mirror flag. // // The _has_archived_raw_mirror flag is cleared at runtime when the // archived mirror is restored. If archived java heap data cannot // be used at runtime, new mirror object is created for the shared // class. The _has_archived_raw_mirror is cleared also during the process.
oop java_lang_Class::archive_mirror(Klass* k) {
assert(HeapShared::can_write(), "must be");
// Mirror is already archived if (k->has_archived_mirror_index()) {
assert(k->archived_java_mirror() != NULL, "no archived mirror"); return k->archived_java_mirror();
}
// No mirror
oop mirror = k->java_mirror(); if (mirror == NULL) { return NULL;
}
if (k->is_instance_klass()) {
InstanceKlass *ik = InstanceKlass::cast(k);
assert(ik->signers() == NULL, "class with signer should have been excluded");
if (!(ik->is_shared_boot_class() || ik->is_shared_platform_class() ||
ik->is_shared_app_class())) { // Archiving mirror for classes from non-builtin loaders is not // supported. return NULL;
}
}
// Now start archiving the mirror object
oop archived_mirror = HeapShared::archive_object(mirror); if (archived_mirror == NULL) { return NULL;
}
// The process is based on create_mirror().
oop java_lang_Class::process_archived_mirror(Klass* k, oop mirror,
oop archived_mirror) { // Clear nonstatic fields in archived mirror. Some of the fields will be set // to archived metadata and objects below.
Klass *c = archived_mirror->klass();
Handle archived_mirror_h(Thread::current(), archived_mirror);
ResetMirrorField reset(archived_mirror_h);
InstanceKlass::cast(c)->do_nonstatic_fields(&reset);
if (k->is_array_klass()) {
oop archived_comp_mirror; if (k->is_typeArray_klass()) { // The primitive type mirrors are already archived. Get the archived mirror.
oop comp_mirror = component_mirror(mirror);
archived_comp_mirror = HeapShared::find_archived_heap_object(comp_mirror);
assert(archived_comp_mirror != NULL, "Must be");
} else {
assert(k->is_objArray_klass(), "Must be");
Klass* element_klass = ObjArrayKlass::cast(k)->element_klass();
assert(element_klass != NULL, "Must have an element klass");
archived_comp_mirror = archive_mirror(element_klass); if (archived_comp_mirror == NULL) { return NULL;
}
}
set_component_mirror(archived_mirror, archived_comp_mirror);
} else {
assert(k->is_instance_klass(), "Must be");
// Reset local static fields in the mirror
InstanceKlass::cast(k)->do_local_static_fields(&reset);
// clear class loader and mirror_module_field
set_class_loader(archived_mirror, NULL);
set_module(archived_mirror, NULL);
return archived_mirror;
}
// Returns true if the mirror is updated, false if no archived mirror // data is present. After the archived mirror object is restored, the // shared klass' _has_raw_archived_mirror flag is cleared. bool java_lang_Class::restore_archived_mirror(Klass *k,
Handle class_loader, Handle module,
Handle protection_domain, TRAPS) { // Postpone restoring archived mirror until java.lang.Class is loaded. Please // see more details in vmClasses::resolve_all(). if (!vmClasses::Class_klass_loaded()) {
assert(fixup_mirror_list() != NULL, "fixup_mirror_list not initialized");
fixup_mirror_list()->push(k); returntrue;
}
oop m = k->archived_java_mirror();
assert(m != NULL, "must have stored non-null archived mirror");
// Sanity: clear it now to prevent re-initialization if any of the following fails
k->clear_archived_mirror_index();
// mirror is archived, restore
log_debug(cds, mirror)("Archived mirror is: " PTR_FORMAT, p2i(m)); if (ArchiveHeapLoader::is_mapped()) {
assert(Universe::heap()->is_archived_object(m), "must be archived mirror object");
}
assert(as_Klass(m) == k, "must be");
Handle mirror(THREAD, m);
if (!k->is_array_klass()) { // - local static final fields with initial values were initialized at dump time
if (protection_domain.not_null()) {
set_protection_domain(mirror(), protection_domain());
}
}
assert(class_loader() == k->class_loader(), "should be same"); if (class_loader.not_null()) {
set_class_loader(mirror(), class_loader());
}
oop java_lang_Class::create_basic_type_mirror(constchar* basic_type_name, BasicType type, TRAPS) { // This should be improved by adding a field at the Java level or by // introducing a new VM klass (see comment in ClassFileParser)
oop java_class = InstanceMirrorKlass::cast(vmClasses::Class_klass())->allocate_instance(NULL, CHECK_NULL); if (type != T_VOID) {
Klass* aklass = Universe::typeArrayKlassObj(type);
assert(aklass != NULL, "correct bootstrap");
release_set_array_klass(java_class, aklass);
} #ifdef ASSERT
InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(vmClasses::Class_klass());
assert(static_oop_field_count(java_class) == 0, "should have been zeroed by allocation"); #endif return java_class;
}
void java_lang_Class::set_klass(oop java_class, Klass* klass) {
assert(is_instance(java_class), "must be a Class object");
java_class->metadata_field_put(_klass_offset, klass);
}
void java_lang_Class::print_signature(oop java_class, outputStream* st) {
assert(is_instance(java_class), "must be a Class object");
Symbol* name = NULL; bool is_instance = false; if (is_primitive(java_class)) {
name = vmSymbols::type_signature(primitive_type(java_class));
} else {
Klass* k = as_Klass(java_class);
is_instance = k->is_instance_klass();
name = k->name();
} if (name == NULL) {
st->print("<null>"); return;
} if (is_instance) st->print("L");
st->write((char*) name->base(), (int) name->utf8_length()); if (is_instance) st->print(";");
}
Symbol* java_lang_Class::as_signature(oop java_class, bool intern_if_not_found) {
assert(is_instance(java_class), "must be a Class object");
Symbol* name; if (is_primitive(java_class)) {
name = vmSymbols::type_signature(primitive_type(java_class)); // Because this can create a new symbol, the caller has to decrement // the refcount, so make adjustment here and below for symbols returned // that are not created or incremented due to a successful lookup.
name->increment_refcount();
} else {
Klass* k = as_Klass(java_class); if (!k->is_instance_klass()) {
name = k->name();
name->increment_refcount();
} else {
ResourceMark rm; constchar* sigstr = k->signature_name(); int siglen = (int) strlen(sigstr); if (!intern_if_not_found) {
name = SymbolTable::probe(sigstr, siglen);
} else {
name = SymbolTable::new_symbol(sigstr, siglen);
}
}
} return name;
}
// Returns the Java name for this Java mirror (Resource allocated) // See Klass::external_name(). // For primitive type Java mirrors, its type name is returned. constchar* java_lang_Class::as_external_name(oop java_class) {
assert(is_instance(java_class), "must be a Class object"); constchar* name = NULL; if (is_primitive(java_class)) {
name = type2name(primitive_type(java_class));
} else {
name = as_Klass(java_class)->external_name();
} if (name == NULL) {
name = "<null>";
} return name;
}
int java_lang_Class::classRedefinedCount(oop the_class_mirror) {
assert(_classRedefinedCount_offset != 0, "offsets should have been initialized"); return the_class_mirror->int_field(_classRedefinedCount_offset);
}
void java_lang_Class::set_classRedefinedCount(oop the_class_mirror, int value) {
assert(_classRedefinedCount_offset != 0, "offsets should have been initialized");
the_class_mirror->int_field_put(_classRedefinedCount_offset, value);
}
// Note: JDK1.1 and before had a privateInfo_offset field which was used for the // platform thread structure, and a eetop offset which was used for thread // local storage (and unused by the HotSpot VM). In JDK1.2 the two structures // merged, so in the HotSpot VM we just use the eetop field for the thread // instead of the privateInfo_offset. // // Note: The stackSize field is only present starting in 1.4.
int java_lang_Thread_FieldHolder::_group_offset; int java_lang_Thread_FieldHolder::_priority_offset; int java_lang_Thread_FieldHolder::_stackSize_offset; int java_lang_Thread_FieldHolder::_daemon_offset; int java_lang_Thread_FieldHolder::_thread_status_offset;
oop java_lang_Thread_Constants::get_VTHREAD_GROUP() {
InstanceKlass* k = vmClasses::Thread_Constants_klass();
oop base = k->static_field_base_raw(); return base->obj_field(_static_VTHREAD_GROUP_offset);
}
oop java_lang_Thread_Constants::get_NOT_SUPPORTED_CLASSLOADER() {
InstanceKlass* k = vmClasses::Thread_Constants_klass();
oop base = k->static_field_base_raw(); return base->obj_field(_static_NOT_SUPPORTED_CLASSLOADER_offset);
}
int java_lang_Thread::_holder_offset; int java_lang_Thread::_name_offset; int java_lang_Thread::_contextClassLoader_offset; int java_lang_Thread::_inheritedAccessControlContext_offset; int java_lang_Thread::_eetop_offset; int java_lang_Thread::_jvmti_thread_state_offset; int java_lang_Thread::_interrupted_offset; int java_lang_Thread::_tid_offset; int java_lang_Thread::_continuation_offset; int java_lang_Thread::_park_blocker_offset; int java_lang_Thread::_scopedValueBindings_offset;
JFR_ONLY(int java_lang_Thread::_jfr_epoch_offset;)
// Write the thread status value to threadStatus field in java.lang.Thread java class. void java_lang_Thread::set_thread_status(oop java_thread, JavaThreadStatus status) {
oop holder = java_lang_Thread::holder(java_thread);
assert(holder != NULL, "Java Thread not initialized");
java_lang_Thread_FieldHolder::set_thread_status(holder, status);
}
// Read thread status value from threadStatus field in java.lang.Thread java class.
JavaThreadStatus java_lang_Thread::get_thread_status(oop java_thread) { // Make sure the caller is operating on behalf of the VM or is // running VM code (state == _thread_in_vm).
assert(Threads_lock->owned_by_self() || Thread::current()->is_VM_thread() ||
JavaThread::current()->thread_state() == _thread_in_vm, "Java Thread is not running in vm");
oop holder = java_lang_Thread::holder(java_thread); if (holder == NULL) { return JavaThreadStatus::NEW; // Java Thread not initialized
} else { return java_lang_Thread_FieldHolder::get_thread_status(holder);
}
}
bool read_reset_retry() { bool ret = _retry_handshake; // If we re-execute the handshake this method need to return false // when the handshake cannot be performed. (E.g. thread terminating)
_retry_handshake = false; return ret;
}
// Pick minimum length that will cover most cases int init_length = 64;
_methods = new (mtInternal) GrowableArray<Method*>(init_length, mtInternal);
_bcis = new (mtInternal) GrowableArray<int>(init_length, mtInternal);
int total_count = 0; for (vframeStream vfst(thread, false, false, carrier); // we don't process frames as we don't care about oops
!vfst.at_end() && (max_depth == 0 || max_depth != total_count);
vfst.next()) {
if (skip_hidden && (vfst.method()->is_hidden() ||
vfst.method()->is_continuation_enter_intrinsic())) { continue;
}
// Handshake with target
ResourceMark rm(THREAD);
HandleMark hm(THREAD);
GetStackTraceClosure gstc(Handle(THREAD, java_thread)); do {
Handshake::execute(&gstc, &tlh, thread);
} while (gstc.read_reset_retry());
// Stop if no stack trace is found. if (gstc._depth == 0) { return NULL;
}
// Convert to StackTraceElement array
InstanceKlass* k = vmClasses::StackTraceElement_klass();
assert(k != NULL, "must be loaded in 1.4+"); if (k->should_be_initialized()) {
k->initialize(CHECK_NULL);
}
objArrayHandle trace = oopFactory::new_objArray_handle(k, gstc._depth, CHECK_NULL);
for (int i = 0; i < gstc._depth; i++) {
methodHandle method(THREAD, gstc._methods->at(i));
oop element = java_lang_StackTraceElement::create(method,
gstc._bcis->at(i),
CHECK_NULL);
trace->obj_at_put(i, element);
}
return trace();
}
constchar* java_lang_Thread::thread_status_name(oop java_thread) {
oop holder = java_lang_Thread::holder(java_thread);
assert(holder != NULL, "Java Thread not initialized");
JavaThreadStatus status = java_lang_Thread_FieldHolder::get_thread_status(holder); switch (status) { case JavaThreadStatus::NEW : return"NEW"; case JavaThreadStatus::RUNNABLE : return"RUNNABLE"; case JavaThreadStatus::SLEEPING : return"TIMED_WAITING (sleeping)"; case JavaThreadStatus::IN_OBJECT_WAIT : return"WAITING (on object monitor)"; case JavaThreadStatus::IN_OBJECT_WAIT_TIMED : return"TIMED_WAITING (on object monitor)"; case JavaThreadStatus::PARKED : return"WAITING (parking)"; case JavaThreadStatus::PARKED_TIMED : return"TIMED_WAITING (parking)"; case JavaThreadStatus::BLOCKED_ON_MONITOR_ENTER : return"BLOCKED (on object monitor)"; case JavaThreadStatus::TERMINATED : return"TERMINATED"; default : return"UNKNOWN";
};
} int java_lang_ThreadGroup::_parent_offset; int java_lang_ThreadGroup::_name_offset; int java_lang_ThreadGroup::_maxPriority_offset; int java_lang_ThreadGroup::_daemon_offset;
oop java_lang_ThreadGroup::parent(oop java_thread_group) {
assert(oopDesc::is_oop(java_thread_group), "thread group must be oop"); return java_thread_group->obj_field(_parent_offset);
}
// ("name as oop" accessor is not necessary)
constchar* java_lang_ThreadGroup::name(oop java_thread_group) {
oop name = java_thread_group->obj_field(_name_offset); // ThreadGroup.name can be null if (name != NULL) { return java_lang_String::as_utf8_string(name);
} return NULL;
}
ThreadPriority java_lang_ThreadGroup::maxPriority(oop java_thread_group) {
assert(oopDesc::is_oop(java_thread_group), "thread group must be oop"); return (ThreadPriority) java_thread_group->int_field(_maxPriority_offset);
}
bool java_lang_ThreadGroup::is_daemon(oop java_thread_group) {
assert(oopDesc::is_oop(java_thread_group), "thread group must be oop"); return java_thread_group->bool_field(_daemon_offset) != 0;
}
int java_lang_VirtualThread::static_notify_jvmti_events_offset; int java_lang_VirtualThread::static_vthread_scope_offset; int java_lang_VirtualThread::_carrierThread_offset; int java_lang_VirtualThread::_continuation_offset; int java_lang_VirtualThread::_state_offset;
int java_lang_VirtualThread::state(oop vthread) { return vthread->int_field_acquire(_state_offset);
}
JavaThreadStatus java_lang_VirtualThread::map_state_to_thread_status(int state) {
JavaThreadStatus status = JavaThreadStatus::NEW; switch (state) { caseNEW :
status = JavaThreadStatus::NEW; break; case STARTED : case RUNNABLE : case RUNNABLE_SUSPENDED : case RUNNING : case PARKING : case YIELDING :
status = JavaThreadStatus::RUNNABLE; break; case PARKED : case PARKED_SUSPENDED : case PINNED :
status = JavaThreadStatus::PARKED; break; case TERMINATED :
status = JavaThreadStatus::TERMINATED; break; default:
ShouldNotReachHere();
} return status;
}
int java_lang_Throwable::_backtrace_offset; int java_lang_Throwable::_detailMessage_offset; int java_lang_Throwable::_stackTrace_offset; int java_lang_Throwable::_depth_offset; int java_lang_Throwable::_cause_offset; int java_lang_Throwable::_static_unassigned_stacktrace_offset;
// After this many redefines, the stack trace is unreliable. constint MAX_VERSION = USHRT_MAX;
staticinlinebool version_matches(Method* method, int version) {
assert(version < MAX_VERSION, "version is too big"); return method != NULL && (method->constants()->version() == version);
}
// This class provides a simple wrapper over the internal structure of // exception backtrace to insulate users of the backtrace from needing // to know what it looks like. // The code of this class is not GC safe. Allocations can only happen // in expand(). class BacktraceBuilder: public StackObj { friendclass BacktraceIterator; private:
Handle _backtrace;
objArrayOop _head;
typeArrayOop _methods;
typeArrayOop _bcis;
objArrayOop _mirrors;
typeArrayOop _names; // Needed to insulate method name against redefinition. // True if the top frame of the backtrace is omitted because it shall be hidden. bool _has_hidden_top_frame; int _index;
NoSafepointVerifier _nsv;
inlinevoid push(Method* method, int bci, TRAPS) { // Smear the -1 bci to 0 since the array only holds unsigned // shorts. The later line number lookup would just smear the -1 // to a 0 even if it could be recorded. if (bci == SynchronizationEntryBCI) bci = 0;
// Note:this doesn't leak symbols because the mirror in the backtrace keeps the // klass owning the symbols alive so their refcounts aren't decremented.
Symbol* name = method->name();
_names->symbol_at_put(_index, name);
// We need to save the mirrors in the backtrace to keep the class // from being unloaded while we still have this stack trace.
assert(method->method_holder()->java_mirror() != NULL, "never push null for mirror");
_mirrors->obj_at_put(_index, method->method_holder()->java_mirror());
_index++;
}
void set_has_hidden_top_frame() { if (!_has_hidden_top_frame) { // It would be nice to add java/lang/Boolean::TRUE here // to indicate that this backtrace has a hidden top frame. // But this code is used before TRUE is allocated. // Therefore let's just use an arbitrary legal oop // available right here. _methods is a short[].
assert(_methods != NULL, "we need a legal oop");
_has_hidden_top_frame = true;
_head->obj_at_put(trace_hidden_offset, _methods);
}
}
};
struct BacktraceElement : public StackObj { int _method_id; int _bci; int _version;
Symbol* _name;
Handle _mirror;
BacktraceElement(Handle mirror, int mid, int version, int bci, Symbol* name) :
_method_id(mid), _bci(bci), _version(version), _name(name), _mirror(mirror) {}
};
class BacktraceIterator : public StackObj { int _index;
objArrayHandle _result;
objArrayHandle _mirrors;
typeArrayHandle _methods;
typeArrayHandle _bcis;
typeArrayHandle _names;
if (_index >= java_lang_Throwable::trace_chunk_size) { int next_offset = java_lang_Throwable::trace_next_offset; // Get next chunk
objArrayHandle result (thread, objArrayOop(_result->obj_at(next_offset)));
init(result, thread);
} return e;
}
// Print stack trace element to resource allocated buffer staticvoid print_stack_element_to_stream(outputStream* st, Handle mirror, int method_id, int version, int bci, Symbol* name) {
ResourceMark rm;
// Get strings and string lengths
InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); constchar* klass_name = holder->external_name(); int buf_len = (int)strlen(klass_name);
// Allocate temporary buffer with extra space for formatting and line number char* buf = NEW_RESOURCE_ARRAY(char, buf_len + 64);
// Print stack trace line in buffer
sprintf(buf, "\tat %s.%s(", klass_name, method_name);
// Print module information if (module_name != NULL) { if (module_version != NULL) {
sprintf(buf + (int)strlen(buf), "%s@%s/", module_name, module_version);
} else {
sprintf(buf + (int)strlen(buf), "%s/", module_name);
}
}
// The method can be NULL if the requested class version is gone
Method* method = holder->method_with_orig_idnum(method_id, version); if (!version_matches(method, version)) {
strcat(buf, "Redefined)");
} else { int line_number = Backtrace::get_line_number(method, bci); if (line_number == -2) {
strcat(buf, "Native Method)");
} else { if (source_file_name != NULL && (line_number != -1)) { // Sourcename and linenumber
sprintf(buf + (int)strlen(buf), "%s:%d)", source_file_name, line_number);
} elseif (source_file_name != NULL) { // Just sourcename
sprintf(buf + (int)strlen(buf), "%s)", source_file_name);
} else { // Neither sourcename nor linenumber
sprintf(buf + (int)strlen(buf), "Unknown Source)");
}
CompiledMethod* nm = method->code(); if (WizardMode && nm != NULL) {
sprintf(buf + (int)strlen(buf), "(nmethod " INTPTR_FORMAT ")", (intptr_t)nm);
}
}
}
st->print_cr("%s", buf);
}
void java_lang_Throwable::print_stack_element(outputStream *st, Method* method, int bci) {
Handle mirror (Thread::current(), method->method_holder()->java_mirror()); int method_id = method->orig_method_idnum(); int version = method->constants()->version();
print_stack_element_to_stream(st, mirror, method_id, version, bci, method->name());
}
/** * Print the throwable message and its stack trace plus all causes by walking the * cause chain. The output looks the same as of Throwable.printStackTrace().
*/ void java_lang_Throwable::print_stack_trace(Handle throwable, outputStream* st) { // First, print the message.
print(throwable(), st);
st->cr();
// Now print the stack trace.
JavaThread* THREAD = JavaThread::current(); // For exception macros. while (throwable.not_null()) {
objArrayHandle result (THREAD, objArrayOop(backtrace(throwable()))); if (result.is_null()) {
st->print_raw_cr("\t<<no stack trace available>>"); return;
}
BacktraceIterator iter(result, THREAD);
while (iter.repeat()) {
BacktraceElement bte = iter.next(THREAD);
print_stack_element_to_stream(st, bte._mirror, bte._method_id, bte._version, bte._bci, bte._name);
}
{ // Call getCause() which doesn't necessarily return the _cause field.
ExceptionMark em(THREAD);
JavaValue cause(T_OBJECT);
JavaCalls::call_virtual(&cause,
throwable,
throwable->klass(),
vmSymbols::getCause_name(),
vmSymbols::void_throwable_signature(),
THREAD); // Ignore any exceptions. we are in the middle of exception handling. Same as classic VM. if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
throwable = Handle();
} else {
throwable = Handle(THREAD, cause.get_oop()); if (throwable.not_null()) {
st->print("Caused by: ");
print(throwable(), st);
st->cr();
}
}
}
}
}
// Start out by clearing the backtrace for this object, in case the VM // runs out of memory while allocating the stack trace
set_backtrace(throwable(), NULL); // Clear lazily constructed Java level stacktrace if refilling occurs // This is unnecessary in 1.7+ but harmless
clear_stacktrace(throwable());
int max_depth = MaxJavaStackTraceDepth;
JavaThread* thread = THREAD;
BacktraceBuilder bt(CHECK);
// If there is no Java frame just return the method that was being called // with bci 0 if (!thread->has_last_Java_frame()) { if (max_depth >= 1 && method() != NULL) {
bt.push(method(), 0, CHECK);
log_info(stacktrace)("%s, %d", throwable->klass()->external_name(), 1);
set_depth(throwable(), 1);
set_backtrace(throwable(), bt.backtrace());
} return;
}
// Instead of using vframe directly, this version of fill_in_stack_trace // basically handles everything by hand. This significantly improved the // speed of this method call up to 28.5% on Solaris sparc. 27.1% on Windows. // See bug 6333838 for more details. // The "ASSERT" here is to verify this method generates the exactly same stack // trace as utilizing vframe. #ifdef ASSERT
vframeStream st(thread, false/* stop_at_java_call_stub */, false /* process_frames */); #endif int total_count = 0;
RegisterMap map(thread,
RegisterMap::UpdateMap::skip,
RegisterMap::ProcessFrames::skip,
RegisterMap::WalkContinuation::include); int decode_offset = 0;
CompiledMethod* nm = NULL; bool skip_fillInStackTrace_check = false; bool skip_throwableInit_check = false; bool skip_hidden = !ShowHiddenFrames; bool show_carrier = ShowCarrierFrames;
ContinuationEntry* cont_entry = thread->last_continuation(); for (frame fr = thread->last_frame(); max_depth == 0 || max_depth != total_count;) {
Method* method = NULL; int bci = 0;
if (Continuation::is_continuation_enterSpecial(fr)) {
assert(cont_entry == Continuation::get_continuation_entry_for_entry_frame(thread, fr), ""); if (!show_carrier && cont_entry->is_virtual_thread()) { break;
}
cont_entry = cont_entry->parent();
}
address pc = fr.pc(); if (fr.is_interpreted_frame()) {
address bcp; if (!map.in_cont()) {
bcp = fr.interpreter_frame_bcp();
method = fr.interpreter_frame_method();
} else {
bcp = map.stack_chunk()->interpreter_frame_bcp(fr);
method = map.stack_chunk()->interpreter_frame_method(fr);
}
bci = method->bci_from(bcp);
fr = fr.sender(&map);
} else {
CodeBlob* cb = fr.cb(); // HMMM QQQ might be nice to have frame return nm as NULL if cb is non-NULL // but non nmethod
fr = fr.sender(&map); if (cb == NULL || !cb->is_compiled()) { continue;
}
nm = cb->as_compiled_method();
assert(nm->method() != NULL, "must be"); if (nm->method()->is_native()) {
method = nm->method();
bci = 0;
} else {
PcDesc* pd = nm->pc_desc_at(pc);
decode_offset = pd->scope_decode_offset(); // if decode_offset is not equal to 0, it will execute the // "compiled java method case" at the beginning of the loop. continue;
}
}
} #ifdef ASSERT if (!st.at_end()) { // TODO LOOM remove once we show only vthread trace
assert(st.method() == method && st.bci() == bci, "Wrong stack trace");
st.next();
} #endif
// the format of the stacktrace will be: // - 1 or more fillInStackTrace frames for the exception class (skipped) // - 0 or more <init> methods for the exception class (skipped) // - rest of the stack
if (!skip_fillInStackTrace_check) { if (method->name() == vmSymbols::fillInStackTrace_name() &&
throwable->is_a(method->method_holder())) { continue;
} else {
skip_fillInStackTrace_check = true; // gone past them all
}
} if (!skip_throwableInit_check) {
assert(skip_fillInStackTrace_check, "logic error in backtrace filtering");
// skip <init> methods of the exception class and superclasses // This is similar to classic VM. if (method->name() == vmSymbols::object_initializer_name() &&
throwable->is_a(method->method_holder())) { continue;
} else { // there are none or we've seen them all - either way stop checking
skip_throwableInit_check = true;
}
} if (method->is_hidden() || method->is_continuation_enter_intrinsic()) { if (skip_hidden) { if (total_count == 0) { // The top frame will be hidden from the stack trace.
bt.set_has_hidden_top_frame();
} continue;
}
}
// Put completed stack trace into throwable object
set_backtrace(throwable(), bt.backtrace());
set_depth(throwable(), total_count);
}
void java_lang_Throwable::fill_in_stack_trace(Handle throwable, const methodHandle& method) { // No-op if stack trace is disabled if (!StackTraceInThrowable) { return;
}
// Disable stack traces for some preallocated out of memory errors if (!Universe::should_fill_in_stack_trace(throwable)) { return;
}
JavaThread* THREAD = JavaThread::current(); // For exception macros.
PreserveExceptionMark pm(THREAD);
fill_in_stack_trace(throwable, method, THREAD); // Ignore exceptions thrown during stack trace filling (OOM) and reinstall the // original exception via the PreserveExceptionMark destructor.
CLEAR_PENDING_EXCEPTION;
}
void java_lang_Throwable::allocate_backtrace(Handle throwable, TRAPS) { // Allocate stack trace - backtrace is created but not filled in
// No-op if stack trace is disabled if (!StackTraceInThrowable) return;
BacktraceBuilder bt(CHECK); // creates a backtrace
set_backtrace(throwable(), bt.backtrace());
}
void java_lang_Throwable::fill_in_stack_trace_of_preallocated_backtrace(Handle throwable) { // Fill in stack trace into preallocated backtrace (no GC)
// No-op if stack trace is disabled if (!StackTraceInThrowable) return;
JavaThread* THREAD = JavaThread::current(); // For exception macros.
objArrayHandle backtrace (THREAD, (objArrayOop)java_lang_Throwable::backtrace(throwable()));
assert(backtrace.not_null(), "backtrace should have been preallocated");
// Unlike fill_in_stack_trace we do not skip fillInStackTrace or throwable init // methods as preallocated errors aren't created by "java" code.
// fill in as much stack trace as possible int chunk_count = 0; for (;!st.at_end(); st.next()) {
bt.push(st.method(), st.bci(), CHECK);
chunk_count++;
// Bail-out for deep stacks if (chunk_count >= trace_chunk_size) break;
}
set_depth(throwable(), chunk_count);
log_info(stacktrace)("%s, %d", throwable->klass()->external_name(), chunk_count);
// We support the Throwable immutability protocol defined for Java 7.
java_lang_Throwable::set_stacktrace(throwable(), java_lang_Throwable::unassigned_stacktrace());
assert(java_lang_Throwable::unassigned_stacktrace() != NULL, "not initialized");
}
Handle java_lang_Throwable::get_cause_with_stack_trace(Handle throwable, TRAPS) { // Call to JVM to fill in the stack trace and clear declaringClassObject to // not keep classes alive in the stack trace. // call this: public StackTraceElement[] getStackTrace()
assert(throwable.not_null(), "shouldn't be");
JavaValue result(T_ARRAY);
JavaCalls::call_virtual(&result, throwable,
vmClasses::Throwable_klass(),
vmSymbols::getStackTrace_name(),
vmSymbols::getStackTrace_signature(),
CHECK_NH);
Handle stack_trace(THREAD, result.get_oop());
assert(stack_trace->is_objArray(), "Should be an array");
// Throw ExceptionInInitializerError as the cause with this exception in // the message and stack trace.
// Now create the message with the original exception and thread name.
Symbol* message = java_lang_Throwable::detail_message(throwable());
ResourceMark rm(THREAD);
stringStream st;
st.print("Exception %s%s ", throwable()->klass()->name()->as_klass_external_name(),
message == nullptr ? "" : ":"); if (message == NULL) {
st.print("[in thread \"%s\"]", THREAD->name());
} else {
st.print("%s [in thread \"%s\"]", message->as_C_string(), THREAD->name());
}
// If new_exception returns a different exception while creating the exception, return null. if (h_cause->klass()->name() != exception_name) {
log_info(class, init)("Exception thrown while saving initialization exception %s",
h_cause->klass()->external_name()); return Handle();
}
java_lang_Throwable::set_stacktrace(h_cause(), stack_trace()); // Clear backtrace because the stacktrace should be used instead.
set_backtrace(h_cause(), NULL); return h_cause;
}
bool java_lang_Throwable::get_top_method_and_bci(oop throwable, Method** method, int* bci) {
JavaThread* current = JavaThread::current();
objArrayHandle result(current, objArrayOop(backtrace(throwable)));
BacktraceIterator iter(result, current); // No backtrace available. if (!iter.repeat()) returnfalse;
// If the exception happened in a frame that has been hidden, i.e., // omitted from the back trace, we can not compute the message.
oop hidden = ((objArrayOop)backtrace(throwable))->obj_at(trace_hidden_offset); if (hidden != NULL) { returnfalse;
}
// Get first backtrace element.
BacktraceElement bte = iter.next(current);
InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(bte._mirror()));
assert(holder != NULL, "first element should be non-null");
Method* m = holder->method_with_orig_idnum(bte._method_id, bte._version);
// Original version is no longer available. if (m == NULL || !version_matches(m, bte._version)) { returnfalse;
}
*method = m;
*bci = bte._bci; returntrue;
}
oop java_lang_StackTraceElement::create(const methodHandle& method, int bci, TRAPS) { // Allocate java.lang.StackTraceElement instance
InstanceKlass* k = vmClasses::StackTraceElement_klass();
assert(k != NULL, "must be loaded in 1.4+"); if (k->should_be_initialized()) {
k->initialize(CHECK_NULL);
}
Handle element = k->allocate_instance_handle(CHECK_NULL);
int version = method->constants()->version();
fill_in(element, method->method_holder(), method, version, bci, method->name(), CHECK_NULL); return element();
}
void java_lang_StackTraceElement::fill_in(Handle element,
InstanceKlass* holder, const methodHandle& method, int version, int bci, Symbol* name, TRAPS) {
assert(element->is_a(vmClasses::StackTraceElement_klass()), "sanity check");
ResourceMark rm(THREAD);
HandleMark hm(THREAD);
// Fill in class name
Handle java_class(THREAD, holder->java_mirror());
oop classname = java_lang_Class::name(java_class, CHECK);
java_lang_StackTraceElement::set_declaringClass(element(), classname);
java_lang_StackTraceElement::set_declaringClassObject(element(), java_class());
oop loader = holder->class_loader(); if (loader != NULL) {
oop loader_name = java_lang_ClassLoader::name(loader); if (loader_name != NULL)
java_lang_StackTraceElement::set_classLoaderName(element(), loader_name);
}
// Fill in method name
oop methodname = StringTable::intern(name, CHECK);
java_lang_StackTraceElement::set_methodName(element(), methodname);
// Fill in module name and version
ModuleEntry* module = holder->module(); if (module->is_named()) {
oop module_name = StringTable::intern(module->name(), CHECK);
java_lang_StackTraceElement::set_moduleName(element(), module_name);
oop module_version; if (module->version() != NULL) {
module_version = StringTable::intern(module->version(), CHECK);
} else {
module_version = NULL;
}
java_lang_StackTraceElement::set_moduleVersion(element(), module_version);
}
if (method() == NULL || !version_matches(method(), version)) { // The method was redefined, accurate line number information isn't available
java_lang_StackTraceElement::set_fileName(element(), NULL);
java_lang_StackTraceElement::set_lineNumber(element(), -1);
} else {
Symbol* source;
oop source_file; int line_number;
decode_file_and_line(java_class, holder, version, method, bci, source, source_file, line_number, CHECK);
void java_lang_StackTraceElement::decode_file_and_line(Handle java_class,
InstanceKlass* holder, int version, const methodHandle& method, int bci,
Symbol*& source,
oop& source_file, int& line_number, TRAPS) { // Fill in source file name and line number.
source = Backtrace::get_source_file_name(holder, version);
source_file = java_lang_Class::source_file(java_class()); if (source != NULL) { // Class was not redefined. We can trust its cache if set, // else we have to initialize it. if (source_file == NULL) {
source_file = StringTable::intern(source, CHECK);
java_lang_Class::set_source_file(java_class(), source_file);
}
} else { // Class was redefined. Dump the cache if it was set. if (source_file != NULL) {
source_file = NULL;
java_lang_Class::set_source_file(java_class(), source_file);
}
}
line_number = Backtrace::get_line_number(method(), bci);
}
int java_lang_StackFrameInfo::_memberName_offset; int java_lang_StackFrameInfo::_bci_offset; int java_lang_StackFrameInfo::_version_offset; int java_lang_StackFrameInfo::_contScope_offset;
void java_lang_StackFrameInfo::set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci, oop cont, TRAPS) { // set Method* or mid/cpref
HandleMark hm(THREAD);
Handle mname(THREAD, stackFrame->obj_field(_memberName_offset));
Handle cont_h (THREAD, cont);
InstanceKlass* ik = method->method_holder();
CallInfo info(method(), ik, CHECK);
MethodHandles::init_method_MemberName(mname, info); // set bci
java_lang_StackFrameInfo::set_bci(stackFrame(), bci); // method may be redefined; store the version int version = method->constants()->version();
assert((jushort)version == version, "version should be short");
java_lang_StackFrameInfo::set_version(stackFrame(), (short)version);
int java_lang_LiveStackFrameInfo::_monitors_offset; int java_lang_LiveStackFrameInfo::_locals_offset; int java_lang_LiveStackFrameInfo::_operands_offset; int java_lang_LiveStackFrameInfo::_mode_offset;
int java_lang_reflect_Method::_clazz_offset; int java_lang_reflect_Method::_name_offset; int java_lang_reflect_Method::_returnType_offset; int java_lang_reflect_Method::_parameterTypes_offset; int java_lang_reflect_Method::_exceptionTypes_offset; int java_lang_reflect_Method::_slot_offset; int java_lang_reflect_Method::_modifiers_offset; int java_lang_reflect_Method::_signature_offset; int java_lang_reflect_Method::_annotations_offset; int java_lang_reflect_Method::_parameter_annotations_offset; int java_lang_reflect_Method::_annotation_default_offset;
Handle java_lang_reflect_Method::create(TRAPS) {
assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
Klass* klass = vmClasses::reflect_Method_klass(); // This class is eagerly initialized during VM initialization, since we keep a reference // to one of the methods
assert(InstanceKlass::cast(klass)->is_initialized(), "must be initialized"); return InstanceKlass::cast(klass)->allocate_instance_handle(THREAD);
}
int java_lang_reflect_Constructor::_clazz_offset; int java_lang_reflect_Constructor::_parameterTypes_offset; int java_lang_reflect_Constructor::_exceptionTypes_offset; int java_lang_reflect_Constructor::_slot_offset; int java_lang_reflect_Constructor::_modifiers_offset; int java_lang_reflect_Constructor::_signature_offset; int java_lang_reflect_Constructor::_annotations_offset; int java_lang_reflect_Constructor::_parameter_annotations_offset;
Handle java_lang_reflect_Constructor::create(TRAPS) {
assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
Symbol* name = vmSymbols::java_lang_reflect_Constructor();
Klass* k = SystemDictionary::resolve_or_fail(name, true, CHECK_NH);
InstanceKlass* ik = InstanceKlass::cast(k); // Ensure it is initialized
ik->initialize(CHECK_NH); return ik->allocate_instance_handle(THREAD);
}
int java_lang_reflect_Field::_clazz_offset; int java_lang_reflect_Field::_name_offset; int java_lang_reflect_Field::_type_offset; int java_lang_reflect_Field::_slot_offset; int java_lang_reflect_Field::_modifiers_offset; int java_lang_reflect_Field::_trusted_final_offset; int java_lang_reflect_Field::_signature_offset; int java_lang_reflect_Field::_annotations_offset;
Handle java_lang_reflect_Field::create(TRAPS) {
assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
Symbol* name = vmSymbols::java_lang_reflect_Field();
Klass* k = SystemDictionary::resolve_or_fail(name, true, CHECK_NH);
InstanceKlass* ik = InstanceKlass::cast(k); // Ensure it is initialized
ik->initialize(CHECK_NH); return ik->allocate_instance_handle(THREAD);
}
void reflect_ConstantPool::compute_offsets() {
InstanceKlass* k = vmClasses::reflect_ConstantPool_klass(); // The field is called ConstantPool* in the sun.reflect.ConstantPool class.
CONSTANTPOOL_FIELDS_DO(FIELD_COMPUTE_OFFSET);
}
int java_lang_reflect_Parameter::_name_offset; int java_lang_reflect_Parameter::_modifiers_offset; int java_lang_reflect_Parameter::_index_offset; int java_lang_reflect_Parameter::_executable_offset;
Handle java_lang_reflect_Parameter::create(TRAPS) {
assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
Symbol* name = vmSymbols::java_lang_reflect_Parameter();
Klass* k = SystemDictionary::resolve_or_fail(name, true, CHECK_NH);
InstanceKlass* ik = InstanceKlass::cast(k); // Ensure it is initialized
ik->initialize(CHECK_NH); return ik->allocate_instance_handle(THREAD);
}
ModuleEntry* java_lang_Module::module_entry(oop module) {
ModuleEntry* module_entry = module_entry_raw(module); if (module_entry == NULL) { // If the inject field containing the ModuleEntry* is null then return the // class loader's unnamed module.
oop loader = java_lang_Module::loader(module);
Handle h_loader = Handle(Thread::current(), loader);
ClassLoaderData* loader_cld = SystemDictionary::register_loader(h_loader); return loader_cld->unnamed_module();
} return module_entry;
}
void java_lang_Module::set_module_entry(oop module, ModuleEntry* module_entry) {
assert(_module_entry_offset != 0, "Uninitialized module_entry_offset");
assert(module != NULL, "module can't be null");
assert(oopDesc::is_oop(module), "module must be oop");
module->address_field_put(_module_entry_offset, (address)module_entry);
}
Handle reflect_ConstantPool::create(TRAPS) {
assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
InstanceKlass* k = vmClasses::reflect_ConstantPool_klass(); // Ensure it is initialized
k->initialize(CHECK_NH); return k->allocate_instance_handle(THREAD);
}
void reflect_ConstantPool::set_cp(oop reflect, ConstantPool* value) {
oop mirror = value->pool_holder()->java_mirror(); // Save the mirror to get back the constant pool.
reflect->obj_field_put(_oop_offset, mirror);
}
// Get the constant pool back from the klass. Since class redefinition // merges the new constant pool into the old, this is essentially the // same constant pool as the original. If constant pool merging is // no longer done in the future, this will have to change to save // the original. return InstanceKlass::cast(k)->constants();
}
int reflect_UnsafeStaticFieldAccessorImpl::_base_offset;
int java_lang_ref_Reference::_referent_offset; int java_lang_ref_Reference::_queue_offset; int java_lang_ref_Reference::_next_offset; int java_lang_ref_Reference::_discovered_offset;
oop java_lang_boxing_object::initialize_and_allocate(BasicType type, TRAPS) {
Klass* k = vmClasses::box_klass(type); if (k == NULL) return NULL;
InstanceKlass* ik = InstanceKlass::cast(k); if (!ik->is_initialized()) {
ik->initialize(CHECK_NULL);
} return ik->allocate_instance(THREAD);
}
oop java_lang_boxing_object::create(BasicType type, jvalue* value, TRAPS) {
oop box = initialize_and_allocate(type, CHECK_NULL); if (box == NULL) return NULL; switch (type) { case T_BOOLEAN:
box->bool_field_put(_value_offset, value->z); break; case T_CHAR:
box->char_field_put(_value_offset, value->c); break; case T_FLOAT:
box->float_field_put(_value_offset, value->f); break; case T_DOUBLE:
box->double_field_put(_long_value_offset, value->d); break; case T_BYTE:
box->byte_field_put(_value_offset, value->b); break; case T_SHORT:
box->short_field_put(_value_offset, value->s); break; case T_INT:
box->int_field_put(_value_offset, value->i); break; case T_LONG:
box->long_field_put(_long_value_offset, value->j); break; default: return NULL;
} return box;
}
BasicType java_lang_boxing_object::basic_type(oop box) { if (box == NULL) return T_ILLEGAL;
BasicType type = vmClasses::box_klass_type(box->klass()); if (type == T_OBJECT) // 'unknown' value returned by SD::bkt return T_ILLEGAL; return type;
}
BasicType java_lang_boxing_object::get_value(oop box, jvalue* value) {
BasicType type = vmClasses::box_klass_type(box->klass()); switch (type) { case T_BOOLEAN:
value->z = box->bool_field(_value_offset); break; case T_CHAR:
value->c = box->char_field(_value_offset); break; case T_FLOAT:
value->f = box->float_field(_value_offset); break; case T_DOUBLE:
value->d = box->double_field(_long_value_offset); break; case T_BYTE:
value->b = box->byte_field(_value_offset); break; case T_SHORT:
value->s = box->short_field(_value_offset); break; case T_INT:
value->i = box->int_field(_value_offset); break; case T_LONG:
value->j = box->long_field(_long_value_offset); break; default: return T_ILLEGAL;
} // end switch return type;
}
BasicType java_lang_boxing_object::set_value(oop box, jvalue* value) {
BasicType type = vmClasses::box_klass_type(box->klass()); switch (type) { case T_BOOLEAN:
box->bool_field_put(_value_offset, value->z); break; case T_CHAR:
box->char_field_put(_value_offset, value->c); break; case T_FLOAT:
box->float_field_put(_value_offset, value->f); break; case T_DOUBLE:
box->double_field_put(_long_value_offset, value->d); break; case T_BYTE:
box->byte_field_put(_value_offset, value->b); break; case T_SHORT:
box->short_field_put(_value_offset, value->s); break; case T_INT:
box->int_field_put(_value_offset, value->i); break; case T_LONG:
box->long_field_put(_long_value_offset, value->j); break; default: return T_ILLEGAL;
} // end switch return type;
}
void java_lang_boxing_object::print(BasicType type, jvalue* value, outputStream* st) { switch (type) { case T_BOOLEAN: st->print("%s", value->z ? "true" : "false"); break; case T_CHAR: st->print("%d", value->c); break; case T_BYTE: st->print("%d", value->b); break; case T_SHORT: st->print("%d", value->s); break; case T_INT: st->print("%d", value->i); break; case T_LONG: st->print(JLONG_FORMAT, value->j); break; case T_FLOAT: st->print("%f", value->f); break; case T_DOUBLE: st->print("%lf", value->d); break; default: st->print("type %d?", type); break;
}
}
// Support for java_lang_ref_SoftReference //
int java_lang_ref_SoftReference::_timestamp_offset; int java_lang_ref_SoftReference::_static_clock_offset;
int java_lang_invoke_MethodHandle::_type_offset; int java_lang_invoke_MethodHandle::_form_offset;
int java_lang_invoke_MemberName::_clazz_offset; int java_lang_invoke_MemberName::_name_offset; int java_lang_invoke_MemberName::_type_offset; int java_lang_invoke_MemberName::_flags_offset; int java_lang_invoke_MemberName::_method_offset; int java_lang_invoke_MemberName::_vmindex_offset;
int java_lang_invoke_ResolvedMethodName::_vmtarget_offset; int java_lang_invoke_ResolvedMethodName::_vmholder_offset;
int jdk_internal_foreign_abi_ABIDescriptor::_inputStorage_offset; int jdk_internal_foreign_abi_ABIDescriptor::_outputStorage_offset; int jdk_internal_foreign_abi_ABIDescriptor::_volatileStorage_offset; int jdk_internal_foreign_abi_ABIDescriptor::_stackAlignment_offset; int jdk_internal_foreign_abi_ABIDescriptor::_shadowSpace_offset; int jdk_internal_foreign_abi_ABIDescriptor::_scratch1_offset; int jdk_internal_foreign_abi_ABIDescriptor::_scratch2_offset;
int jdk_internal_foreign_abi_VMStorage::_type_offset; int jdk_internal_foreign_abi_VMStorage::_indexOrOffset_offset; int jdk_internal_foreign_abi_VMStorage::_segmentMaskOrSize_offset; int jdk_internal_foreign_abi_VMStorage::_debugName_offset;
Method* java_lang_invoke_ResolvedMethodName::vmtarget(oop resolved_method) {
assert(is_instance(resolved_method), "wrong type");
Method* m = (Method*)resolved_method->address_field(_vmtarget_offset);
assert(m->is_method(), "must be"); return m;
}
// Used by redefinition to change Method* to new Method* with same hash (name, signature) void java_lang_invoke_ResolvedMethodName::set_vmtarget(oop resolved_method, Method* m) {
assert(is_instance(resolved_method), "wrong type");
resolved_method->address_field_put(_vmtarget_offset, (address)m);
}
// lookup ResolvedMethod oop in the table, or create a new one and intern it
oop resolved_method = ResolvedMethodTable::find_method(method); if (resolved_method != NULL) { return resolved_method;
}
InstanceKlass* k = vmClasses::ResolvedMethodName_klass(); if (!k->is_initialized()) {
k->initialize(CHECK_NULL);
}
set_vmtarget(new_resolved_method, const_cast<Method*>(method)); // Add a reference to the loader (actually mirror because hidden classes may not have // distinct loaders) to ensure the metadata is kept alive. // This mirror may be different than the one in clazz field.
set_vmholder(new_resolved_method, holder->java_mirror());
// Set flag in class to indicate this InstanceKlass has entries in the table // to avoid walking table during redefinition if none of the redefined classes // have any membernames in the table.
holder->set_has_resolved_methods();
// Support for java_lang_invoke_MethodHandleNatives_CallSiteContext
int java_lang_invoke_MethodHandleNatives_CallSiteContext::_vmdependencies_offset; int java_lang_invoke_MethodHandleNatives_CallSiteContext::_last_cleanup_offset;
void java_lang_invoke_MethodHandleNatives_CallSiteContext::compute_offsets() {
InstanceKlass* k = vmClasses::Context_klass();
CALLSITECONTEXT_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
}
int java_security_AccessControlContext::_context_offset; int java_security_AccessControlContext::_privilegedContext_offset; int java_security_AccessControlContext::_isPrivileged_offset; int java_security_AccessControlContext::_isAuthorized_offset;
void java_security_AccessControlContext::compute_offsets() {
assert(_isPrivileged_offset == 0, "offsets should be initialized only once");
InstanceKlass* k = vmClasses::AccessControlContext_klass();
ACCESSCONTROLCONTEXT_FIELDS_DO(FIELD_COMPUTE_OFFSET);
}
oop java_security_AccessControlContext::create(objArrayHandle context, bool isPrivileged, Handle privileged_context, TRAPS) {
assert(_isPrivileged_offset != 0, "offsets should have been initialized");
assert(_isAuthorized_offset != 0, "offsets should have been initialized"); // Ensure klass is initialized
vmClasses::AccessControlContext_klass()->initialize(CHECK_NULL); // Allocate result
oop result = vmClasses::AccessControlContext_klass()->allocate_instance(CHECK_NULL); // Fill in values
result->obj_field_put(_context_offset, context());
result->obj_field_put(_privilegedContext_offset, privileged_context());
result->bool_field_put(_isPrivileged_offset, isPrivileged);
result->bool_field_put(_isAuthorized_offset, true); return result;
}
// Support for java_lang_ClassLoader
int java_lang_ClassLoader::_loader_data_offset; int java_lang_ClassLoader::_parallelCapable_offset; int java_lang_ClassLoader::_name_offset; int java_lang_ClassLoader::_nameAndId_offset; int java_lang_ClassLoader::_unnamedModule_offset; int java_lang_ClassLoader::_parent_offset;
ClassLoaderData* java_lang_ClassLoader::loader_data_acquire(oop loader) {
assert(loader != NULL, "loader must not be NULL");
assert(oopDesc::is_oop(loader), "loader must be oop"); return Atomic::load_acquire(loader->field_addr<ClassLoaderData*>(_loader_data_offset));
}
ClassLoaderData* java_lang_ClassLoader::loader_data(oop loader) {
assert(loader != NULL, "loader must not be NULL");
assert(oopDesc::is_oop(loader), "loader must be oop"); return *loader->field_addr<ClassLoaderData*>(_loader_data_offset);
}
void java_lang_ClassLoader::release_set_loader_data(oop loader, ClassLoaderData* new_data) {
assert(loader != NULL, "loader must not be NULL");
assert(oopDesc::is_oop(loader), "loader must be oop");
Atomic::release_store(loader->field_addr<ClassLoaderData*>(_loader_data_offset), new_data);
}
oop java_lang_ClassLoader::parent(oop loader) {
assert(is_instance(loader), "loader must be oop"); return loader->obj_field(_parent_offset);
}
oop java_lang_ClassLoader::parent_no_keepalive(oop loader) {
assert(is_instance(loader), "loader must be oop"); return loader->obj_field_access<AS_NO_KEEPALIVE>(_parent_offset);
}
// Returns the name field of this class loader. If the name field has not // been set, null will be returned.
oop java_lang_ClassLoader::name(oop loader) {
assert(is_instance(loader), "loader must be oop"); return loader->obj_field(_name_offset);
}
// Returns the nameAndId field of this class loader. The format is // as follows: // If the defining loader has a name explicitly set then '<loader-name>' @<id> // If the defining loader has no name then <qualified-class-name> @<id> // If built-in loader, then omit '@<id>' as there is only one instance. // Use ClassLoader::loader_name_id() to obtain this String as a char*.
oop java_lang_ClassLoader::nameAndId(oop loader) {
assert(is_instance(loader), "loader must be oop"); return loader->obj_field(_nameAndId_offset);
}
bool java_lang_ClassLoader::isAncestor(oop loader, oop cl) {
assert(is_instance(loader), "loader must be oop");
assert(cl == NULL || is_instance(cl), "cl argument must be oop");
oop acl = loader;
debug_only(jint loop_count = 0); // This loop taken verbatim from ClassLoader.java: do {
acl = parent(acl); if (cl == acl) { returntrue;
}
assert(++loop_count > 0, "loop_count overflow");
} while (acl != NULL); returnfalse;
}
// For class loader classes, parallelCapable defined // based on non-null field // Written to by java.lang.ClassLoader, vm only reads this field, doesn't set it bool java_lang_ClassLoader::parallelCapable(oop class_loader) {
assert(_parallelCapable_offset != 0, "offsets should have been initialized"); return (class_loader->obj_field(_parallelCapable_offset) != NULL);
}
bool java_lang_ClassLoader::is_trusted_loader(oop loader) { // Fix for 4474172; see evaluation for more details
loader = non_reflection_class_loader(loader);
// Return true if this is one of the class loaders associated with // the generated bytecodes for reflection. bool java_lang_ClassLoader::is_reflection_class_loader(oop loader) { if (loader != NULL) {
Klass* delegating_cl_class = vmClasses::reflect_DelegatingClassLoader_klass(); // This might be null in non-1.4 JDKs return (delegating_cl_class != NULL && loader->is_a(delegating_cl_class));
} returnfalse;
}
oop java_lang_ClassLoader::non_reflection_class_loader(oop loader) { // See whether this is one of the class loaders associated with // the generated bytecodes for reflection, and if so, "magically" // delegate to its parent to prevent class loading from occurring // in places where applications using reflection didn't expect it. if (is_reflection_class_loader(loader)) { return parent(loader);
} return loader;
}
oop java_lang_ClassLoader::unnamedModule(oop loader) {
assert(is_instance(loader), "loader must be oop"); return loader->obj_field(_unnamedModule_offset);
}
// Support for java_lang_System //
int java_lang_System::_static_in_offset; int java_lang_System::_static_out_offset; int java_lang_System::_static_err_offset; int java_lang_System::_static_security_offset; int java_lang_System::_static_allow_security_offset; int java_lang_System::_static_never_offset;
void java_lang_System::compute_offsets() {
InstanceKlass* k = vmClasses::System_klass();
SYSTEM_FIELDS_DO(FIELD_COMPUTE_OFFSET);
}
// This field tells us that a security manager can never be installed so we // can completely skip populating the ProtectionDomainCacheTable. bool java_lang_System::allow_security_manager() { staticint initialized = false; staticbool allowed = true; // default if (!initialized) {
oop base = vmClasses::System_klass()->static_field_base_raw(); int never = base->int_field(_static_never_offset);
allowed = (base->int_field(_static_allow_security_offset) != never);
initialized = true;
} return allowed;
}
// This field tells us that a security manager is installed. bool java_lang_System::has_security_manager() {
oop base = vmClasses::System_klass()->static_field_base_raw(); return base->obj_field(_static_security_offset) != NULL;
}
// Support for jdk_internal_misc_UnsafeConstants // class UnsafeConstantsFixup : public FieldClosure { private: int _address_size; int _page_size; bool _big_endian; bool _use_unaligned_access; int _data_cache_line_flush_size; public:
UnsafeConstantsFixup() { // round up values for all static final fields
_address_size = sizeof(void*);
_page_size = os::vm_page_size();
_big_endian = LITTLE_ENDIAN_ONLY(false) BIG_ENDIAN_ONLY(true);
_use_unaligned_access = UseUnalignedAccesses;
_data_cache_line_flush_size = (int)VM_Version::data_cache_line_flush_size();
}
void do_field(fieldDescriptor* fd) {
oop mirror = fd->field_holder()->java_mirror();
assert(mirror != NULL, "UnsafeConstants must have mirror already");
assert(fd->field_holder() == vmClasses::UnsafeConstants_klass(), "Should be UnsafeConstants");
assert(fd->is_final(), "fields of UnsafeConstants must be final");
assert(fd->is_static(), "fields of UnsafeConstants must be static"); if (fd->name() == vmSymbols::address_size_name()) {
mirror->int_field_put(fd->offset(), _address_size);
} elseif (fd->name() == vmSymbols::page_size_name()) {
mirror->int_field_put(fd->offset(), _page_size);
} elseif (fd->name() == vmSymbols::big_endian_name()) {
mirror->bool_field_put(fd->offset(), _big_endian);
} elseif (fd->name() == vmSymbols::use_unaligned_access_name()) {
mirror->bool_field_put(fd->offset(), _use_unaligned_access);
} elseif (fd->name() == vmSymbols::data_cache_line_flush_size_name()) {
mirror->int_field_put(fd->offset(), _data_cache_line_flush_size);
} else {
assert(false, "unexpected UnsafeConstants field");
}
}
};
int java_lang_StackTraceElement::_methodName_offset; int java_lang_StackTraceElement::_fileName_offset; int java_lang_StackTraceElement::_lineNumber_offset; int java_lang_StackTraceElement::_moduleName_offset; int java_lang_StackTraceElement::_moduleVersion_offset; int java_lang_StackTraceElement::_classLoaderName_offset; int java_lang_StackTraceElement::_declaringClass_offset; int java_lang_StackTraceElement::_declaringClassObject_offset;
// Support for java_lang_StackTraceElement void java_lang_StackTraceElement::compute_offsets() {
InstanceKlass* k = vmClasses::StackTraceElement_klass();
STACKTRACEELEMENT_FIELDS_DO(FIELD_COMPUTE_OFFSET);
}
int java_lang_AssertionStatusDirectives::_classes_offset; int java_lang_AssertionStatusDirectives::_classEnabled_offset; int java_lang_AssertionStatusDirectives::_packages_offset; int java_lang_AssertionStatusDirectives::_packageEnabled_offset; int java_lang_AssertionStatusDirectives::_deflt_offset;
int java_lang_Integer_IntegerCache::_static_cache_offset; int java_lang_Long_LongCache::_static_cache_offset; int java_lang_Character_CharacterCache::_static_cache_offset; int java_lang_Short_ShortCache::_static_cache_offset; int java_lang_Byte_ByteCache::_static_cache_offset;
int java_lang_reflect_RecordComponent::_clazz_offset; int java_lang_reflect_RecordComponent::_name_offset; int java_lang_reflect_RecordComponent::_type_offset; int java_lang_reflect_RecordComponent::_accessor_offset; int java_lang_reflect_RecordComponent::_signature_offset; int java_lang_reflect_RecordComponent::_annotations_offset; int java_lang_reflect_RecordComponent::_typeAnnotations_offset;
// Support for java_lang_reflect_RecordComponent void java_lang_reflect_RecordComponent::compute_offsets() {
InstanceKlass* k = vmClasses::RecordComponent_klass();
RECORDCOMPONENT_FIELDS_DO(FIELD_COMPUTE_OFFSET);
}
// Compute field offsets of all the classes in this file void JavaClasses::compute_offsets() { if (UseSharedSpaces) {
JVMTI_ONLY(assert(JvmtiExport::is_early_phase() && !(JvmtiExport::should_post_class_file_load_hook() &&
JvmtiExport::has_early_class_hook_env()), "JavaClasses::compute_offsets() must be called in early JVMTI phase.")); // None of the classes used by the rest of this function can be replaced by // JVMTI ClassFileLoadHook. // We are safe to use the archived offsets, which have already been restored // by JavaClasses::serialize_offsets, without computing the offsets again. return;
}
// We have already called the compute_offsets() of the // BASIC_JAVA_CLASSES_DO_PART1 classes (java_lang_String, java_lang_Class and // java_lang_ref_Reference) earlier inside vmClasses::resolve_all()
BASIC_JAVA_CLASSES_DO_PART2(DO_COMPUTE_OFFSETS);
}
#if INCLUDE_CDS_JAVA_HEAP bool JavaClasses::is_supported_for_archiving(oop obj) {
Klass* klass = obj->klass();
if (klass == vmClasses::ClassLoader_klass() || // ClassLoader::loader_data is malloc'ed. // The next 3 classes are used to implement java.lang.invoke, and are not used directly in // regular Java code. The implementation of java.lang.invoke uses generated hidden classes // (e.g., as referenced by ResolvedMethodName::vmholder) that are not yet supported by CDS. // So for now we cannot not support these classes for archiving. // // These objects typically are not referenced by static fields, but rather by resolved // constant pool entries, so excluding them shouldn't affect the archiving of static fields.
klass == vmClasses::ResolvedMethodName_klass() ||
klass == vmClasses::MemberName_klass() ||
klass == vmClasses::Context_klass() || // It's problematic to archive Reference objects. One of the reasons is that // Reference::discovered may pull in unwanted objects (see JDK-8284336)
klass->is_subclass_of(vmClasses::Reference_klass())) { returnfalse;
}
returntrue;
} #endif
#ifndef PRODUCT
// These functions exist to assert the validity of de-serialized offsets in boxing object as a sanity check.
bool JavaClasses::check_offset(constchar *klass_name, int deserialized_offset, constchar *field_name, constchar* field_sig) {
EXCEPTION_MARK;
fieldDescriptor fd;
TempNewSymbol klass_sym = SymbolTable::new_symbol(klass_name);
Klass* k = SystemDictionary::resolve_or_fail(klass_sym, true, CATCH);
InstanceKlass* ik = InstanceKlass::cast(k);
TempNewSymbol f_name = SymbolTable::new_symbol(field_name);
TempNewSymbol f_sig = SymbolTable::new_symbol(field_sig); if (!ik->find_local_field(f_name, f_sig, &fd)) {
tty->print_cr("Nonstatic field %s.%s not found", klass_name, field_name); returnfalse;
} if (fd.is_static()) {
tty->print_cr("Nonstatic field %s.%s appears to be static", klass_name, field_name); returnfalse;
} if (fd.offset() == deserialized_offset ) { returntrue;
} else {
tty->print_cr("Offset of nonstatic field %s.%s is deserialized as %d but should really be %d.",
klass_name, field_name, deserialized_offset, fd.offset()); returnfalse;
}
}
if (!valid) vm_exit_during_initialization("Field offset verification failed");
}
#endif// PRODUCT
int InjectedField::compute_offset() {
InstanceKlass* ik = InstanceKlass::cast(klass()); for (AllFieldStream fs(ik); !fs.done(); fs.next()) { if (!may_be_java && !fs.access_flags().is_internal()) { // Only look at injected fields continue;
} if (fs.name() == name() && fs.signature() == signature()) { return fs.offset();
}
}
ResourceMark rm;
tty->print_cr("Invalid layout of %s at %s/%s%s", ik->external_name(), name()->as_C_string(), signature()->as_C_string(), may_be_java ? " (may_be_java)" : ""); #ifndef PRODUCT
ik->print();
tty->print_cr("all fields:"); for (AllFieldStream fs(ik); !fs.done(); fs.next()) {
tty->print_cr(" name: %s, sig: %s, flags: %08x", fs.name()->as_C_string(), fs.signature()->as_C_string(), fs.access_flags().as_int());
} #endif//PRODUCT
vm_exit_during_initialization("Invalid layout of well-known class: use -Xlog:class+load=info to see the origin of the problem class"); return -1;
}
void javaClasses_init() {
JavaClasses::compute_offsets();
JavaClasses::check_offsets();
java_lang_VirtualThread::init_static_notify_jvmti_events();
FilteredFieldsMap::initialize(); // must be done after computing offsets.
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.76 Sekunden
(vorverarbeitet am 2026-05-02)
¤
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 und die Messung sind noch experimentell.