Skip to content
Permalink
Browse files
8264538: Rename SystemDictionary::parse_stream
Reviewed-by: lfoltan, hseigel
  • Loading branch information
coleenp committed Apr 1, 2021
1 parent 80681b5 commit 1dc75e9ef58271021c1fb1719a147aec3f6cc068
@@ -879,15 +879,15 @@ Klass* SystemDictionary::find_instance_or_array_klass(Symbol* class_name,
return k;
}

// Note: this method is much like resolve_from_stream, but
// does not publish the classes via the SystemDictionary.
// Handles Lookup.defineClass hidden, unsafe_DefineAnonymousClass
// and redefineclasses. RedefinedClasses do not add to the class hierarchy.
InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
Handle class_loader,
ClassFileStream* st,
const ClassLoadInfo& cl_info,
TRAPS) {
// Note: this method is much like resolve_class_from_stream, but
// does not publish the classes in the SystemDictionary.
// Handles Lookup.defineClass hidden and unsafe_DefineAnonymousClass.
InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream(
ClassFileStream* st,
Symbol* class_name,
Handle class_loader,
const ClassLoadInfo& cl_info,
TRAPS) {

EventClassLoad class_load_start_event;
ClassLoaderData* loader_data;
@@ -898,64 +898,56 @@ InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
// - for hidden classes that are not strong: create a new CLD that has a class holder and
// whose loader is the Lookup class's loader.
// - for hidden class: add the class to the Lookup class's loader's CLD.
if (is_unsafe_anon_class || cl_info.is_hidden()) {
guarantee(!is_unsafe_anon_class || cl_info.unsafe_anonymous_host()->class_loader() == class_loader(),
assert (is_unsafe_anon_class || cl_info.is_hidden(), "only used for hidden classes");
guarantee(!is_unsafe_anon_class || cl_info.unsafe_anonymous_host()->class_loader() == class_loader(),
"should be NULL or the same");
bool create_mirror_cld = is_unsafe_anon_class || !cl_info.is_strong_hidden();
loader_data = register_loader(class_loader, create_mirror_cld);
} else {
loader_data = ClassLoaderData::class_loader_data(class_loader());
}
bool create_mirror_cld = is_unsafe_anon_class || !cl_info.is_strong_hidden();
loader_data = register_loader(class_loader, create_mirror_cld);

assert(st != NULL, "invariant");
assert(st->need_verify(), "invariant");

// Parse stream and create a klass.
// Note that we do this even though this klass might
// already be present in the SystemDictionary, otherwise we would not
// throw potential ClassFormatErrors.

InstanceKlass* k = KlassFactory::create_from_stream(st,
class_name,
loader_data,
cl_info,
CHECK_NULL);
assert(k != NULL, "no klass created");

if (cl_info.is_hidden() || is_unsafe_anon_class) {
// Hidden classes that are not strong and unsafe anonymous classes must update
// ClassLoaderData holder so that they can be unloaded when the mirror is no
// longer referenced.
if (!cl_info.is_strong_hidden() || is_unsafe_anon_class) {
k->class_loader_data()->initialize_holder(Handle(THREAD, k->java_mirror()));
}
// Hidden classes that are not strong and unsafe anonymous classes must update
// ClassLoaderData holder so that they can be unloaded when the mirror is no
// longer referenced.
if (!cl_info.is_strong_hidden() || is_unsafe_anon_class) {
k->class_loader_data()->initialize_holder(Handle(THREAD, k->java_mirror()));
}

{
MutexLocker mu_r(THREAD, Compile_lock);
// Add to class hierarchy, and do possible deoptimizations.
add_to_hierarchy(k);
// But, do not add to dictionary.
}
{
MutexLocker mu_r(THREAD, Compile_lock);
// Add to class hierarchy, and do possible deoptimizations.
add_to_hierarchy(k);
// But, do not add to dictionary.
}

// Rewrite and patch constant pool here.
k->link_class(CHECK_NULL);
if (cl_info.cp_patches() != NULL) {
k->constants()->patch_resolved_references(cl_info.cp_patches());
}
// Rewrite and patch constant pool here.
k->link_class(CHECK_NULL);
if (cl_info.cp_patches() != NULL) {
k->constants()->patch_resolved_references(cl_info.cp_patches());
}

// If it's anonymous, initialize it now, since nobody else will.
if (is_unsafe_anon_class) {
k->eager_initialize(CHECK_NULL);
}
// If it's anonymous, initialize it now, since nobody else will.
if (is_unsafe_anon_class) {
k->eager_initialize(CHECK_NULL);
}

// notify jvmti
if (JvmtiExport::should_post_class_load()) {
JvmtiExport::post_class_load(THREAD->as_Java_thread(), k);
}
if (class_load_start_event.should_commit()) {
post_class_load_event(&class_load_start_event, k, loader_data);
}
// notify jvmti
if (JvmtiExport::should_post_class_load()) {
JvmtiExport::post_class_load(THREAD->as_Java_thread(), k);
}
if (class_load_start_event.should_commit()) {
post_class_load_event(&class_load_start_event, k, loader_data);
}

assert(is_unsafe_anon_class || NULL == cl_info.cp_patches(),
"cp_patches only found with unsafe_anonymous_host");

@@ -968,10 +960,11 @@ InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
// the class until we have parsed the stream.
// This function either returns an InstanceKlass or throws an exception. It does
// not return NULL without a pending exception.
InstanceKlass* SystemDictionary::resolve_from_stream(Symbol* class_name,
Handle class_loader,
Handle protection_domain,
InstanceKlass* SystemDictionary::resolve_class_from_stream(
ClassFileStream* st,
Symbol* class_name,
Handle class_loader,
const ClassLoadInfo& cl_info,
TRAPS) {

HandleMark hm(THREAD);
@@ -993,14 +986,13 @@ InstanceKlass* SystemDictionary::resolve_from_stream(Symbol* class_name,
if (!DumpSharedSpaces) {
k = SystemDictionaryShared::lookup_from_stream(class_name,
class_loader,
protection_domain,
cl_info.protection_domain(),
st,
CHECK_NULL);
}
#endif

if (k == NULL) {
ClassLoadInfo cl_info(protection_domain);
k = KlassFactory::create_from_stream(st, class_name, loader_data, cl_info, CHECK_NULL);
}

@@ -1031,6 +1023,20 @@ InstanceKlass* SystemDictionary::resolve_from_stream(Symbol* class_name,
return k;
}

InstanceKlass* SystemDictionary::resolve_from_stream(ClassFileStream* st,
Symbol* class_name,
Handle class_loader,
const ClassLoadInfo& cl_info,
TRAPS) {
bool is_unsafe_anon_class = cl_info.unsafe_anonymous_host() != NULL;
if (cl_info.is_hidden() || is_unsafe_anon_class) {
return resolve_hidden_class_from_stream(st, class_name, class_loader, cl_info, CHECK_NULL);
} else {
return resolve_class_from_stream(st, class_name, class_loader, cl_info, CHECK_NULL);
}
}


#if INCLUDE_CDS
// Load a class for boot loader from the shared spaces. This also
// forces the super class and all interfaces to be loaded.
@@ -121,21 +121,29 @@ class SystemDictionary : AllStatic {
Handle protection_domain,
bool is_superclass,
TRAPS);
private:
// Parse the stream to create an unsafe anonymous or hidden class.
// Used by Unsafe_DefineAnonymousClass and jvm_lookup_define_class.
static InstanceKlass* resolve_hidden_class_from_stream(ClassFileStream* st,
Symbol* class_name,
Handle class_loader,
const ClassLoadInfo& cl_info,
TRAPS);

// Resolve a class from stream (called by jni_DefineClass and JVM_DefineClass)
// This class is added to the SystemDictionary.
static InstanceKlass* resolve_class_from_stream(ClassFileStream* st,
Symbol* class_name,
Handle class_loader,
const ClassLoadInfo& cl_info,
TRAPS);

// Parse new stream. This won't update the dictionary or class
// hierarchy, simply parse the stream. Used by JVMTI RedefineClasses
// and by Unsafe_DefineAnonymousClass and jvm_lookup_define_class.
static InstanceKlass* parse_stream(Symbol* class_name,
Handle class_loader,
ClassFileStream* st,
const ClassLoadInfo& cl_info,
TRAPS);

// Resolve from stream (called by jni_DefineClass and JVM_DefineClass)
static InstanceKlass* resolve_from_stream(Symbol* class_name,
public:
// Resolve either a hidden or normal class from a stream of bytes, based on ClassLoadInfo
static InstanceKlass* resolve_from_stream(ClassFileStream* st,
Symbol* class_name,
Handle class_loader,
Handle protection_domain,
ClassFileStream* st,
const ClassLoadInfo& cl_info,
TRAPS);

// Lookup an already loaded class. If not found NULL is returned.
@@ -30,6 +30,8 @@
#include "ci/ciReplay.hpp"
#include "classfile/altHashing.hpp"
#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoadInfo.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/javaThreadStatus.hpp"
@@ -283,10 +285,11 @@ JNI_ENTRY(jclass, jni_DefineClass(JNIEnv *env, const char *name, jobject loaderR
ResourceMark rm(THREAD);
ClassFileStream st((u1*)buf, bufLen, NULL, ClassFileStream::verify);
Handle class_loader (THREAD, JNIHandles::resolve(loaderRef));
Klass* k = SystemDictionary::resolve_from_stream(class_name,
Handle protection_domain;
ClassLoadInfo cl_info(protection_domain);
Klass* k = SystemDictionary::resolve_from_stream(&st, class_name,
class_loader,
Handle(),
&st,
cl_info,
CHECK_NULL);

if (log_is_enabled(Debug, class, resolve)) {
@@ -860,10 +860,10 @@ static jclass jvm_define_class_common(const char *name,
ClassFileStream st((u1*)buf, len, source, ClassFileStream::verify);
Handle class_loader (THREAD, JNIHandles::resolve(loader));
Handle protection_domain (THREAD, JNIHandles::resolve(pd));
Klass* k = SystemDictionary::resolve_from_stream(class_name,
ClassLoadInfo cl_info(protection_domain);
Klass* k = SystemDictionary::resolve_from_stream(&st, class_name,
class_loader,
protection_domain,
&st,
cl_info,
CHECK_NULL);

if (log_is_enabled(Debug, class, resolve)) {
@@ -947,10 +947,10 @@ static jclass jvm_lookup_define_class(jclass lookup, const char *name,

InstanceKlass* ik = NULL;
if (!is_hidden) {
ik = SystemDictionary::resolve_from_stream(class_name,
ClassLoadInfo cl_info(protection_domain);
ik = SystemDictionary::resolve_from_stream(&st, class_name,
class_loader,
protection_domain,
&st,
cl_info,
CHECK_NULL);

if (log_is_enabled(Debug, class, resolve)) {
@@ -966,11 +966,10 @@ static jclass jvm_lookup_define_class(jclass lookup, const char *name,
is_hidden,
is_strong,
vm_annotations);
ik = SystemDictionary::parse_stream(class_name,
class_loader,
&st,
cl_info,
CHECK_NULL);
ik = SystemDictionary::resolve_from_stream(&st, class_name,
class_loader,
cl_info,
CHECK_NULL);

// The hidden class loader data has been artificially been kept alive to
// this point. The mirror and any instances of this class have to keep
@@ -30,7 +30,7 @@
#include "classfile/javaClasses.inline.hpp"
#include "classfile/metadataOnStackMark.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/klassFactory.hpp"
#include "classfile/verifier.hpp"
#include "classfile/vmClasses.hpp"
#include "classfile/vmSymbols.hpp"
@@ -1367,7 +1367,6 @@ jvmtiError VM_RedefineClasses::load_new_class_versions() {
// constant pools
HandleMark hm(current);
InstanceKlass* the_class = get_ik(_class_defs[i].klass);
Symbol* the_class_sym = the_class->name();

log_debug(redefine, class, load)
("loading name=%s kind=%d (avail_mem=" UINT64_FORMAT "K)",
@@ -1378,23 +1377,23 @@ jvmtiError VM_RedefineClasses::load_new_class_versions() {
"__VM_RedefineClasses__",
ClassFileStream::verify);

// Parse the stream.
Handle the_class_loader(current, the_class->class_loader());
Handle protection_domain(current, the_class->protection_domain());
// Set redefined class handle in JvmtiThreadState class.
// This redefined class is sent to agent event handler for class file
// load hook event.
state->set_class_being_redefined(the_class, _class_load_kind);

Thread* THREAD = current; // for exception processing
ExceptionMark em(THREAD);
Handle protection_domain(THREAD, the_class->protection_domain());
ClassLoadInfo cl_info(protection_domain);
InstanceKlass* scratch_class = SystemDictionary::parse_stream(
the_class_sym,
the_class_loader,
&st,
// Parse and create a class from the bytes, but this class isn't added
// to the dictionary, so do not call resolve_from_stream.
InstanceKlass* scratch_class = KlassFactory::create_from_stream(&st,
the_class->name(),
the_class->class_loader_data(),
cl_info,
THREAD);

// Clear class_being_redefined just to be sure.
state->clear_class_being_redefined();

@@ -1407,7 +1406,7 @@ jvmtiError VM_RedefineClasses::load_new_class_versions() {

if (HAS_PENDING_EXCEPTION) {
Symbol* ex_name = PENDING_EXCEPTION->klass()->name();
log_info(redefine, class, load, exceptions)("parse_stream exception: '%s'", ex_name->as_C_string());
log_info(redefine, class, load, exceptions)("create_from_stream exception: '%s'", ex_name->as_C_string());
CLEAR_PENDING_EXCEPTION;

if (ex_name == vmSymbols::java_lang_UnsupportedClassVersionError()) {
@@ -302,12 +302,6 @@
//
// - How do we serialize the RedefineClasses() API without deadlocking?
//
// - SystemDictionary::parse_stream() was called with a NULL protection
// domain since the initial version. This has been changed to pass
// the_class->protection_domain(). This change has been tested with
// all NSK tests and nothing broke, but what will adding it now break
// in ways that we don't test?
//
// - GenerateOopMap::rewrite_load_or_store() has a comment in its
// (indirect) use of the Relocator class that the max instruction
// size is 4 bytes. goto_w and jsr_w are 5 bytes and wide/iinc is
@@ -865,11 +865,10 @@ Unsafe_DefineAnonymousClass_impl(JNIEnv *env,
false, // is_strong_hidden
true); // can_access_vm_annotations

InstanceKlass* anonk = SystemDictionary::parse_stream(no_class_name,
host_loader,
&st,
cl_info,
CHECK_NULL);
InstanceKlass* anonk = SystemDictionary::resolve_from_stream(&st, no_class_name,
host_loader,
cl_info,
CHECK_NULL);
assert(anonk != NULL, "no klass created");
return anonk;
}

1 comment on commit 1dc75e9

@openjdk-notifier

This comment has been minimized.

Copy link

@openjdk-notifier openjdk-notifier bot commented on 1dc75e9 Apr 1, 2021

Please sign in to comment.