8238358: Implementation of JEP 371: Hidden Classes

Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: David Holmes <david.holmes@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jamsheed Mohammed C M <jamsheed.c.m@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Reviewed-by: alanb, cjplummer, coleenp, dholmes, dlong, forax, jlahoda, psandoz, plevart, sspitsyn, vromero
This commit is contained in:
Mandy Chung 2020-04-21 06:55:38 -07:00
parent 642041adbc
commit 7cc1371059
198 changed files with 9526 additions and 1575 deletions
make
data/jdwp
hotspot/symbols
src
hotspot/share
java.base/share
java.instrument/share/classes/java/lang/instrument
jdk.compiler/share/classes/com/sun/tools/javac

@ -70,7 +70,8 @@ JDWP "Java(tm) Debug Wire Protocol"
)
(Command AllClasses=3
"Returns reference types for all classes currently loaded by the "
"target VM."
"target VM. "
"See <a href=\"../jvmti.html#GetLoadedClasses\">JVM TI GetLoadedClasses</a>."
(Out
)
(Reply
@ -600,14 +601,9 @@ JDWP "Java(tm) Debug Wire Protocol"
(CommandSet ReferenceType=2
(Command Signature=1
"Returns the JNI signature of a reference type. "
"JNI signature formats are described in the "
"<a href=\"../jni/index.html\">Java Native Interface Specification</a>"
"<p>
"For primitive classes "
"the returned signature is the signature of the corresponding primitive "
"type; for example, \"I\" is returned as the signature of the class "
"represented by java.lang.Integer.TYPE."
"Returns the type signature of a reference type. "
"Type signature formats are the same as specified in "
"<a href=\"../jvmti.html#GetClassSignature\">JVM TI GetClassSignature</a>."
(Out
(referenceType refType "The reference type ID.")
)
@ -2266,11 +2262,12 @@ JDWP "Java(tm) Debug Wire Protocol"
)
(CommandSet ClassLoaderReference=14
(Command VisibleClasses=1
"Returns a list of all classes which this class loader has "
"been requested to load. This class loader is considered to be "
"an <i>initiating</i> class loader for each class in the returned "
"list. The list contains each "
"reference type defined by this loader and any types for which "
"Returns a list of all classes which this class loader can find "
"by name via <code>ClassLoader::loadClass</code>, "
"<code>Class::forName</code> and bytecode linkage. That is, "
"all classes for which this class loader has been recorded as an "
"<i>initiating</i> loader. The list contains each "
"reference type created by this loader and any types for which "
"loading was delegated by this class loader to another class loader. "
"<p>"
"The visible class list has useful properties with respect to "
@ -2280,6 +2277,8 @@ JDWP "Java(tm) Debug Wire Protocol"
"this class loader must be resolved to that single type. "
"<p>"
"No ordering of the returned list is guaranteed. "
"<p>"
"See <a href=\"../jvmti.html#GetClassLoaderClasses\">JVM TI GetClassLoaderClasses</a>. "
(Out
(classLoaderObject classLoaderObject "The class loader object ID. ")
)

@ -142,6 +142,7 @@ JVM_Interrupt
JVM_InvokeMethod
JVM_IsArrayClass
JVM_IsConstructorIx
JVM_IsHiddenClass
JVM_IsInterface
JVM_IsPrimitiveClass
JVM_IsRecord
@ -151,6 +152,7 @@ JVM_IsThreadAlive
JVM_IsVMGeneratedMethodIx
JVM_LatestUserDefinedLoader
JVM_LoadLibrary
JVM_LookupDefineClass
JVM_MaxMemory
JVM_MaxObjectInspectionAge
JVM_MonitorNotify

@ -1049,7 +1049,7 @@ bool AOTCodeHeap::reconcile_dynamic_klass(AOTCompiledMethod *caller, InstanceKla
InstanceKlass* dyno = InstanceKlass::cast(dyno_klass);
if (!dyno->is_unsafe_anonymous()) {
if (!dyno->is_hidden() && !dyno->is_unsafe_anonymous()) {
if (_klasses_got[dyno_data->_got_index] != dyno) {
// compile-time class different from runtime class, fail and deoptimize
sweep_dependent_methods(holder_data);

@ -43,7 +43,7 @@ GrowableArray<AOTLib*>* AOTLoader::_libraries = new(ResourceObj::C_HEAP, mtCode)
#define FOR_ALL_AOT_LIBRARIES(lib) for (GrowableArrayIterator<AOTLib*> lib = libraries()->begin(); lib != libraries()->end(); ++lib)
void AOTLoader::load_for_klass(InstanceKlass* ik, Thread* thread) {
if (ik->is_unsafe_anonymous()) {
if (ik->is_hidden() || ik->is_unsafe_anonymous()) {
// don't even bother
return;
}
@ -58,7 +58,7 @@ void AOTLoader::load_for_klass(InstanceKlass* ik, Thread* thread) {
uint64_t AOTLoader::get_saved_fingerprint(InstanceKlass* ik) {
assert(UseAOT, "called only when AOT is enabled");
if (ik->is_unsafe_anonymous()) {
if (ik->is_hidden() || ik->is_unsafe_anonymous()) {
// don't even bother
return 0;
}

@ -223,9 +223,10 @@ static bool trust_final_non_static_fields(ciInstanceKlass* holder) {
holder->is_in_package("jdk/internal/foreign") || holder->is_in_package("jdk/incubator/foreign") ||
holder->is_in_package("java/lang"))
return true;
// Trust VM unsafe anonymous classes. They are private API (jdk.internal.misc.Unsafe)
// and can't be serialized, so there is no hacking of finals going on with them.
if (holder->is_unsafe_anonymous())
// Trust hidden classes and VM unsafe anonymous classes. They are created via
// Lookup.defineHiddenClass or the private jdk.internal.misc.Unsafe API and
// can't be serialized, so there is no hacking of finals going on with them.
if (holder->is_hidden() || holder->is_unsafe_anonymous())
return true;
// Trust final fields in all boxed classes
if (holder->is_box_klass())

@ -63,6 +63,7 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) :
_has_nonstatic_fields = ik->has_nonstatic_fields();
_has_nonstatic_concrete_methods = ik->has_nonstatic_concrete_methods();
_is_unsafe_anonymous = ik->is_unsafe_anonymous();
_is_hidden = ik->is_hidden();
_nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields:
_has_injected_fields = -1;
_implementor = NULL; // we will fill these lazily
@ -73,13 +74,13 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) :
// InstanceKlass are created for both weak and strong metadata. Ensuring this metadata
// alive covers the cases where there are weak roots without performance cost.
oop holder = ik->klass_holder();
if (ik->is_unsafe_anonymous()) {
if (ik->class_loader_data()->has_class_mirror_holder()) {
// Though ciInstanceKlass records class loader oop, it's not enough to keep
// VM unsafe anonymous classes alive (loader == NULL). Klass holder should
// non-strong hidden classes and VM unsafe anonymous classes alive (loader == NULL). Klass holder should
// be used instead. It is enough to record a ciObject, since cached elements are never removed
// during ciObjectFactory lifetime. ciObjectFactory itself is created for
// every compilation and lives for the whole duration of the compilation.
assert(holder != NULL, "holder of unsafe anonymous class is the mirror which is never null");
assert(holder != NULL, "holder of hidden or unsafe anonymous class is the mirror which is never null");
(void)CURRENT_ENV->get_object(holder);
}
@ -123,6 +124,7 @@ ciInstanceKlass::ciInstanceKlass(ciSymbol* name,
_nonstatic_fields = NULL;
_has_injected_fields = -1;
_is_unsafe_anonymous = false;
_is_hidden = false;
_loader = loader;
_protection_domain = protection_domain;
_is_shared = false;

@ -56,6 +56,7 @@ private:
bool _has_nonstatic_fields;
bool _has_nonstatic_concrete_methods;
bool _is_unsafe_anonymous;
bool _is_hidden;
ciFlags _flags;
jint _nonstatic_field_size;
@ -191,10 +192,14 @@ public:
return _has_nonstatic_concrete_methods;
}
bool is_unsafe_anonymous() {
bool is_unsafe_anonymous() const {
return _is_unsafe_anonymous;
}
bool is_hidden() const {
return _is_hidden;
}
ciInstanceKlass* get_canonical_holder(int offset);
ciField* get_field_by_offset(int field_offset, bool is_static);
ciField* get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static);

@ -1092,7 +1092,7 @@ public:
assert((int)_annotation_LIMIT <= (int)sizeof(_annotations_present) * BitsPerByte, "");
}
// If this annotation name has an ID, report it (or _none).
ID annotation_index(const ClassLoaderData* loader_data, const Symbol* name);
ID annotation_index(const ClassLoaderData* loader_data, const Symbol* name, bool can_access_vm_annotations);
// Set the annotation name:
void set_annotation(ID id) {
assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
@ -1225,6 +1225,7 @@ static void parse_annotations(const ConstantPool* const cp,
const u1* buffer, int limit,
AnnotationCollector* coll,
ClassLoaderData* loader_data,
const bool can_access_vm_annotations,
TRAPS) {
assert(cp != NULL, "invariant");
@ -1270,7 +1271,7 @@ static void parse_annotations(const ConstantPool* const cp,
}
// Here is where parsing particular annotations will take place.
AnnotationCollector::ID id = coll->annotation_index(loader_data, aname);
AnnotationCollector::ID id = coll->annotation_index(loader_data, aname, can_access_vm_annotations);
if (AnnotationCollector::_unknown == id) continue;
coll->set_annotation(id);
@ -1396,6 +1397,7 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs,
runtime_visible_annotations_length,
parsed_annotations,
_loader_data,
_can_access_vm_annotations,
CHECK);
cfs->skip_u1_fast(runtime_visible_annotations_length);
} else if (attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
@ -2059,12 +2061,13 @@ void ClassFileParser::throwIllegalSignature(const char* type,
AnnotationCollector::ID
AnnotationCollector::annotation_index(const ClassLoaderData* loader_data,
const Symbol* name) {
const Symbol* name,
const bool can_access_vm_annotations) {
const vmSymbols::SID sid = vmSymbols::find_sid(name);
// Privileged code can use all annotations. Other code silently drops some.
const bool privileged = loader_data->is_the_null_class_loader_data() ||
const bool privileged = loader_data->is_boot_class_loader_data() ||
loader_data->is_platform_class_loader_data() ||
loader_data->is_unsafe_anonymous();
can_access_vm_annotations;
switch (sid) {
case vmSymbols::VM_SYMBOL_ENUM_NAME(reflect_CallerSensitive_signature): {
if (_location != _in_method) break; // only allow for methods
@ -2671,6 +2674,7 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
runtime_visible_annotations_length,
&parsed_annotations,
_loader_data,
_can_access_vm_annotations,
CHECK_NULL);
cfs->skip_u1_fast(runtime_visible_annotations_length);
} else if (method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
@ -2865,6 +2869,10 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
if (parsed_annotations.has_any_annotations())
parsed_annotations.apply_to(methodHandle(THREAD, m));
if (is_hidden()) { // Mark methods in hidden classes as 'hidden'.
m->set_hidden(true);
}
// Copy annotations
copy_method_annotations(m->constMethod(),
runtime_visible_annotations,
@ -3596,6 +3604,7 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
runtime_visible_annotations_length,
parsed_annotations,
_loader_data,
_can_access_vm_annotations,
CHECK);
cfs->skip_u1_fast(runtime_visible_annotations_length);
} else if (tag == vmSymbols::tag_runtime_invisible_annotations()) {
@ -5592,7 +5601,9 @@ static void check_methods_for_intrinsics(const InstanceKlass* ik,
}
}
InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook, TRAPS) {
InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook,
const ClassInstanceInfo& cl_inst_info,
TRAPS) {
if (_klass != NULL) {
return _klass;
}
@ -5600,7 +5611,11 @@ InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook,
InstanceKlass* const ik =
InstanceKlass::allocate_instance_klass(*this, CHECK_NULL);
fill_instance_klass(ik, changed_by_loadhook, CHECK_NULL);
if (is_hidden()) {
mangle_hidden_class_name(ik);
}
fill_instance_klass(ik, changed_by_loadhook, cl_inst_info, CHECK_NULL);
assert(_klass == ik, "invariant");
@ -5626,7 +5641,10 @@ InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook,
return ik;
}
void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loadhook, TRAPS) {
void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
bool changed_by_loadhook,
const ClassInstanceInfo& cl_inst_info,
TRAPS) {
assert(ik != NULL, "invariant");
// Set name and CLD before adding to CLD
@ -5662,6 +5680,11 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
// the parser onto the InstanceKlass*
apply_parsed_class_metadata(ik, _java_fields_count, CHECK);
// can only set dynamic nest-host after static nest information is set
if (cl_inst_info.dynamic_nest_host() != NULL) {
ik->set_nest_host(cl_inst_info.dynamic_nest_host(), THREAD);
}
// note that is not safe to use the fields in the parser from this point on
assert(NULL == _cp, "invariant");
assert(NULL == _fields, "invariant");
@ -5686,11 +5709,11 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
ik->set_this_class_index(_this_class_index);
if (is_unsafe_anonymous()) {
if (_is_hidden || is_unsafe_anonymous()) {
// _this_class_index is a CONSTANT_Class entry that refers to this
// anonymous class itself. If this class needs to refer to its own methods or
// fields, it would use a CONSTANT_MethodRef, etc, which would reference
// _this_class_index. However, because this class is anonymous (it's
// hidden or anonymous class itself. If this class needs to refer to its own
// methods or fields, it would use a CONSTANT_MethodRef, etc, which would reference
// _this_class_index. However, because this class is hidden or anonymous (it's
// not stored in SystemDictionary), _this_class_index cannot be resolved
// with ConstantPool::klass_at_impl, which does a SystemDictionary lookup.
// Therefore, we must eagerly resolve _this_class_index now.
@ -5706,6 +5729,9 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
assert (ik->is_unsafe_anonymous(), "should be the same");
ik->set_unsafe_anonymous_host(_unsafe_anonymous_host);
}
if (_is_hidden) {
ik->set_is_hidden();
}
// Set PackageEntry for this_klass
oop cl = ik->class_loader();
@ -5785,6 +5811,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
Handle(THREAD, _loader_data->class_loader()),
module_handle,
_protection_domain,
cl_inst_info.class_data(),
CHECK);
assert(_all_mirandas != NULL, "invariant");
@ -5869,7 +5896,6 @@ void ClassFileParser::update_class_name(Symbol* new_class_name) {
_class_name->increment_refcount();
}
// For an unsafe anonymous class that is in the unnamed package, move it to its host class's
// package by prepending its host class's package name to its class name and setting
// its _class_name field.
@ -5922,8 +5948,8 @@ void ClassFileParser::fix_unsafe_anonymous_class_name(TRAPS) {
}
static bool relax_format_check_for(ClassLoaderData* loader_data) {
bool trusted = (loader_data->is_the_null_class_loader_data() ||
SystemDictionary::is_platform_class_loader(loader_data->class_loader()));
bool trusted = loader_data->is_boot_class_loader_data() ||
loader_data->is_platform_class_loader_data();
bool need_verify =
// verifyAll
(BytecodeVerificationLocal && BytecodeVerificationRemote) ||
@ -5935,17 +5961,16 @@ static bool relax_format_check_for(ClassLoaderData* loader_data) {
ClassFileParser::ClassFileParser(ClassFileStream* stream,
Symbol* name,
ClassLoaderData* loader_data,
Handle protection_domain,
const InstanceKlass* unsafe_anonymous_host,
GrowableArray<Handle>* cp_patches,
const ClassLoadInfo* cl_info,
Publicity pub_level,
TRAPS) :
_stream(stream),
_requested_name(name),
_class_name(NULL),
_loader_data(loader_data),
_unsafe_anonymous_host(unsafe_anonymous_host),
_cp_patches(cp_patches),
_unsafe_anonymous_host(cl_info->unsafe_anonymous_host()),
_cp_patches(cl_info->cp_patches()),
_is_hidden(cl_info->is_hidden()),
_can_access_vm_annotations(cl_info->can_access_vm_annotations()),
_num_patched_klasses(0),
_max_num_patched_klasses(0),
_orig_cp_size(0),
@ -5976,7 +6001,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_itable_size(0),
_num_miranda_methods(0),
_rt(REF_NONE),
_protection_domain(protection_domain),
_protection_domain(cl_info->protection_domain()),
_access_flags(),
_pub_level(pub_level),
_bad_constant_seen(0),
@ -6179,10 +6204,15 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
cp_size, CHECK);
_orig_cp_size = cp_size;
if (int(cp_size) + _max_num_patched_klasses > 0xffff) {
THROW_MSG(vmSymbols::java_lang_InternalError(), "not enough space for patched classes");
if (is_hidden()) { // Add a slot for hidden class name.
assert(_max_num_patched_klasses == 0, "Sanity check");
cp_size++;
} else {
if (int(cp_size) + _max_num_patched_klasses > 0xffff) {
THROW_MSG(vmSymbols::java_lang_InternalError(), "not enough space for patched classes");
}
cp_size += _max_num_patched_klasses;
}
cp_size += _max_num_patched_klasses;
_cp = ConstantPool::allocate(_loader_data,
cp_size,
@ -6233,36 +6263,67 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
Symbol* const class_name_in_cp = cp->klass_name_at(_this_class_index);
assert(class_name_in_cp != NULL, "class_name can't be null");
// Update _class_name to reflect the name in the constant pool
update_class_name(class_name_in_cp);
// Don't need to check whether this class name is legal or not.
// It has been checked when constant pool is parsed.
// However, make sure it is not an array type.
if (_need_verify) {
guarantee_property(_class_name->char_at(0) != JVM_SIGNATURE_ARRAY,
guarantee_property(class_name_in_cp->char_at(0) != JVM_SIGNATURE_ARRAY,
"Bad class name in class file %s",
CHECK);
}
// Checks if name in class file matches requested name
if (_requested_name != NULL && _requested_name != _class_name) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_NoClassDefFoundError(),
"%s (wrong name: %s)",
_class_name->as_C_string(),
_requested_name != NULL ? _requested_name->as_C_string() : "NoName"
);
return;
}
#ifdef ASSERT
// Basic sanity checks
assert(!(_is_hidden && (_unsafe_anonymous_host != NULL)), "mutually exclusive variants");
// if this is an anonymous class fix up its name if it's in the unnamed
if (_unsafe_anonymous_host != NULL) {
assert(_class_name == vmSymbols::unknown_class_name(), "A named anonymous class???");
}
if (_is_hidden) {
assert(_class_name != vmSymbols::unknown_class_name(), "hidden classes should have a special name");
}
#endif
// Update the _class_name as needed depending on whether this is a named,
// un-named, hidden or unsafe-anonymous class.
if (_is_hidden) {
assert(_class_name != NULL, "Unexpected null _class_name");
#ifdef ASSERT
if (_need_verify) {
verify_legal_class_name(_class_name, CHECK);
}
#endif
// NOTE: !_is_hidden does not imply "findable" as it could be an old-style
// "hidden" unsafe-anonymous class
// If this is an anonymous class fix up its name if it is in the unnamed
// package. Otherwise, throw IAE if it is in a different package than
// its host class.
if (_unsafe_anonymous_host != NULL) {
} else if (_unsafe_anonymous_host != NULL) {
update_class_name(class_name_in_cp);
fix_unsafe_anonymous_class_name(CHECK);
} else {
// Check if name in class file matches given name
if (_class_name != class_name_in_cp) {
if (_class_name != vmSymbols::unknown_class_name()) {
ResourceMark rm(THREAD);
Exceptions::fthrow(THREAD_AND_LOCATION,
vmSymbols::java_lang_NoClassDefFoundError(),
"%s (wrong name: %s)",
class_name_in_cp->as_C_string(),
_class_name->as_C_string()
);
return;
} else {
// The class name was not known by the caller so we set it from
// the value in the CP.
update_class_name(class_name_in_cp);
}
// else nothing to do: the expected class name matches what is in the CP
}
}
// Verification prevents us from creating names with dots in them, this
@ -6287,9 +6348,10 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
warning("DumpLoadedClassList and CDS are not supported in exploded build");
DumpLoadedClassList = NULL;
} else if (SystemDictionaryShared::is_sharing_possible(_loader_data) &&
!_is_hidden &&
_unsafe_anonymous_host == NULL) {
// Only dump the classes that can be stored into CDS archive.
// Unsafe anonymous classes such as generated LambdaForm classes are also not included.
// Hidden and unsafe anonymous classes such as generated LambdaForm classes are also not included.
oop class_loader = _loader_data->class_loader();
ResourceMark rm(THREAD);
bool skip = false;
@ -6384,6 +6446,35 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
// all bytes in stream read and parsed
}
void ClassFileParser::mangle_hidden_class_name(InstanceKlass* const ik) {
ResourceMark rm;
// Construct hidden name from _class_name, "+", and &ik. Note that we can't
// use a '/' because that confuses finding the class's package. Also, can't
// use an illegal char such as ';' because that causes serialization issues
// and issues with hidden classes that create their own hidden classes.
char addr_buf[20];
jio_snprintf(addr_buf, 20, INTPTR_FORMAT, p2i(ik));
size_t new_name_len = _class_name->utf8_length() + 2 + strlen(addr_buf);
char* new_name = NEW_RESOURCE_ARRAY(char, new_name_len);
jio_snprintf(new_name, new_name_len, "%s+%s",
_class_name->as_C_string(), addr_buf);
update_class_name(SymbolTable::new_symbol(new_name));
// Add a Utf8 entry containing the hidden name.
assert(_class_name != NULL, "Unexpected null _class_name");
int hidden_index = _orig_cp_size; // this is an extra slot we added
_cp->symbol_at_put(hidden_index, _class_name);
// Update this_class_index's slot in the constant pool with the new Utf8 entry.
// We have to update the resolved_klass_index and the name_index together
// so extract the existing resolved_klass_index first.
CPKlassSlot cp_klass_slot = _cp->klass_slot_at(_this_class_index);
int resolved_klass_index = cp_klass_slot.resolved_klass_index();
_cp->unresolved_klass_at_put(_this_class_index, hidden_index, resolved_klass_index);
assert(_cp->klass_slot_at(_this_class_index).name_index() == _orig_cp_size,
"Bad name_index");
}
void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const stream,
ConstantPool* cp,
TRAPS) {

@ -37,6 +37,8 @@ template <typename T>
class Array;
class ClassFileStream;
class ClassLoaderData;
class ClassLoadInfo;
class ClassInstanceInfo;
class CompressedLineNumberWriteStream;
class ConstMethod;
class FieldInfo;
@ -109,11 +111,12 @@ class ClassFileParser {
typedef void unsafe_u2;
const ClassFileStream* _stream; // Actual input stream
const Symbol* _requested_name;
Symbol* _class_name;
mutable ClassLoaderData* _loader_data;
const InstanceKlass* _unsafe_anonymous_host;
GrowableArray<Handle>* _cp_patches; // overrides for CP entries
const bool _is_hidden;
const bool _can_access_vm_annotations;
int _num_patched_klasses;
int _max_num_patched_klasses;
int _orig_cp_size;
@ -201,6 +204,8 @@ class ClassFileParser {
void parse_stream(const ClassFileStream* const stream, TRAPS);
void mangle_hidden_class_name(InstanceKlass* const ik);
void post_process_parsed_stream(const ClassFileStream* const stream,
ConstantPool* cp,
TRAPS);
@ -208,7 +213,9 @@ class ClassFileParser {
void prepend_host_package_name(const InstanceKlass* unsafe_anonymous_host, TRAPS);
void fix_unsafe_anonymous_class_name(TRAPS);
void fill_instance_klass(InstanceKlass* ik, bool cf_changed_in_CFLH, TRAPS);
void fill_instance_klass(InstanceKlass* ik, bool cf_changed_in_CFLH,
const ClassInstanceInfo& cl_inst_info, TRAPS);
void set_klass(InstanceKlass* instance);
void set_class_bad_constant_seen(short bad_constant);
@ -527,21 +534,19 @@ class ClassFileParser {
FieldLayoutInfo* info,
TRAPS);
void update_class_name(Symbol* new_name);
void update_class_name(Symbol* new_name);
public:
ClassFileParser(ClassFileStream* stream,
Symbol* name,
ClassLoaderData* loader_data,
Handle protection_domain,
const InstanceKlass* unsafe_anonymous_host,
GrowableArray<Handle>* cp_patches,
const ClassLoadInfo* cl_info,
Publicity pub_level,
TRAPS);
~ClassFileParser();
InstanceKlass* create_instance_klass(bool cf_changed_in_CFLH, TRAPS);
InstanceKlass* create_instance_klass(bool cf_changed_in_CFLH, const ClassInstanceInfo& cl_inst_info, TRAPS);
const ClassFileStream* clone_stream() const;
@ -557,6 +562,7 @@ class ClassFileParser {
u2 this_class_index() const { return _this_class_index; }
bool is_unsafe_anonymous() const { return _unsafe_anonymous_host != NULL; }
bool is_hidden() const { return _is_hidden; }
bool is_interface() const { return _access_flags.is_interface(); }
const InstanceKlass* unsafe_anonymous_host() const { return _unsafe_anonymous_host; }

@ -1257,13 +1257,12 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
Handle protection_domain;
ClassLoadInfo cl_info(protection_domain);
InstanceKlass* result = KlassFactory::create_from_stream(stream,
name,
loader_data,
protection_domain,
NULL, // unsafe_anonymous_host
NULL, // cp_patches
cl_info,
THREAD);
if (HAS_PENDING_EXCEPTION) {
if (DumpSharedSpaces) {
@ -1302,8 +1301,8 @@ void ClassLoader::record_result(InstanceKlass* ik, const ClassFileStream* stream
Arguments::assert_is_dumping_archive();
assert(stream != NULL, "sanity");
if (ik->is_unsafe_anonymous()) {
// We do not archive unsafe anonymous classes.
if (ik->is_hidden() || ik->is_unsafe_anonymous()) {
// We do not archive hidden or unsafe anonymous classes.
return;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2020, 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
@ -126,16 +126,16 @@ void ClassLoaderData::initialize_name(Handle class_loader) {
_name_and_id = SymbolTable::new_symbol(cl_instance_name_and_id);
}
ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_unsafe_anonymous) :
ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool has_class_mirror_holder) :
_metaspace(NULL),
_metaspace_lock(new Mutex(Mutex::leaf+1, "Metaspace allocation lock", true,
Mutex::_safepoint_check_never)),
_unloading(false), _is_unsafe_anonymous(is_unsafe_anonymous),
_unloading(false), _has_class_mirror_holder(has_class_mirror_holder),
_modified_oops(true), _accumulated_modified_oops(false),
// An unsafe anonymous class loader data doesn't have anything to keep
// it from being unloaded during parsing of the unsafe anonymous class.
// The null-class-loader should always be kept alive.
_keep_alive((is_unsafe_anonymous || h_class_loader.is_null()) ? 1 : 0),
_keep_alive((has_class_mirror_holder || h_class_loader.is_null()) ? 1 : 0),
_claim(0),
_handles(),
_klasses(NULL), _packages(NULL), _modules(NULL), _unnamed_module(NULL), _dictionary(NULL),
@ -150,13 +150,13 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_unsafe_anonymous
initialize_name(h_class_loader);
}
if (!is_unsafe_anonymous) {
// The holder is initialized later for unsafe anonymous classes, and before calling anything
// that call class_loader().
if (!has_class_mirror_holder) {
// The holder is initialized later for non-strong hidden classes and unsafe anonymous classes,
// and before calling anything that call class_loader().
initialize_holder(h_class_loader);
// A ClassLoaderData created solely for an unsafe anonymous class should never have a
// ModuleEntryTable or PackageEntryTable created for it. The defining package
// A ClassLoaderData created solely for a non-strong hidden class or unsafe anonymous class should
// never have a ModuleEntryTable or PackageEntryTable created for it. The defining package
// and module for an unsafe anonymous class will be found in its host class.
_packages = new PackageEntryTable(PackageEntryTable::_packagetable_entry_size);
if (h_class_loader.is_null()) {
@ -291,20 +291,20 @@ bool ClassLoaderData::try_claim(int claim) {
}
}
// Unsafe anonymous classes have their own ClassLoaderData that is marked to keep alive
// Weak hidden and unsafe anonymous classes have their own ClassLoaderData that is marked to keep alive
// while the class is being parsed, and if the class appears on the module fixup list.
// Due to the uniqueness that no other class shares the unsafe anonymous class' name or
// ClassLoaderData, no other non-GC thread has knowledge of the unsafe anonymous class while
// Due to the uniqueness that no other class shares the hidden or unsafe anonymous class' name or
// ClassLoaderData, no other non-GC thread has knowledge of the hidden or unsafe anonymous class while
// it is being defined, therefore _keep_alive is not volatile or atomic.
void ClassLoaderData::inc_keep_alive() {
if (is_unsafe_anonymous()) {
if (has_class_mirror_holder()) {
assert(_keep_alive > 0, "Invalid keep alive increment count");
_keep_alive++;
}
}
void ClassLoaderData::dec_keep_alive() {
if (is_unsafe_anonymous()) {
if (has_class_mirror_holder()) {
assert(_keep_alive > 0, "Invalid keep alive decrement count");
_keep_alive--;
}
@ -410,21 +410,21 @@ void ClassLoaderData::record_dependency(const Klass* k) {
// Do not need to record dependency if the dependency is to a class whose
// class loader data is never freed. (i.e. the dependency's class loader
// is one of the three builtin class loaders and the dependency is not
// unsafe anonymous.)
// is one of the three builtin class loaders and the dependency's class
// loader data has a ClassLoader holder, not a Class holder.)
if (to_cld->is_permanent_class_loader_data()) {
return;
}
oop to;
if (to_cld->is_unsafe_anonymous()) {
// Just return if an unsafe anonymous class is attempting to record a dependency
// to itself. (Note that every unsafe anonymous class has its own unique class
if (to_cld->has_class_mirror_holder()) {
// Just return if a non-strong hidden class or unsafe anonymous class is attempting to record a dependency
// to itself. (Note that every non-strong hidden class or unsafe anonymous class has its own unique class
// loader data.)
if (to_cld == from_cld) {
return;
}
// Unsafe anonymous class dependencies are through the mirror.
// Hidden and unsafe anonymous class dependencies are through the mirror.
to = k->java_mirror();
} else {
to = to_cld->class_loader();
@ -572,7 +572,7 @@ const int _boot_loader_dictionary_size = 1009;
const int _default_loader_dictionary_size = 107;
Dictionary* ClassLoaderData::create_dictionary() {
assert(!is_unsafe_anonymous(), "unsafe anonymous class loader data do not have a dictionary");
assert(!has_class_mirror_holder(), "class mirror holder cld does not have a dictionary");
int size;
bool resizable = false;
if (_the_null_class_loader_data == NULL) {
@ -618,7 +618,7 @@ oop ClassLoaderData::holder_no_keepalive() const {
// Unloading support
bool ClassLoaderData::is_alive() const {
bool alive = keep_alive() // null class loader and incomplete unsafe anonymous klasses.
bool alive = keep_alive() // null class loader and incomplete non-strong hidden class or unsafe anonymous class.
|| (_holder.peek() != NULL); // and not cleaned by the GC weak handle processing.
return alive;
@ -716,13 +716,13 @@ ClassLoaderData::~ClassLoaderData() {
// Returns true if this class loader data is for the app class loader
// or a user defined system class loader. (Note that the class loader
// data may be unsafe anonymous.)
// data may have a Class holder.)
bool ClassLoaderData::is_system_class_loader_data() const {
return SystemDictionary::is_system_class_loader(class_loader());
}
// Returns true if this class loader data is for the platform class loader.
// (Note that the class loader data may be unsafe anonymous.)
// (Note that the class loader data may have a Class holder.)
bool ClassLoaderData::is_platform_class_loader_data() const {
return SystemDictionary::is_platform_class_loader(class_loader());
}
@ -730,8 +730,8 @@ bool ClassLoaderData::is_platform_class_loader_data() const {
// Returns true if the class loader for this class loader data is one of
// the 3 builtin (boot application/system or platform) class loaders,
// including a user-defined system class loader. Note that if the class
// loader data is for an unsafe anonymous class then it may get freed by a GC
// even if its class loader is one of these loaders.
// loader data is for a non-strong hidden class or unsafe anonymous class then it may
// get freed by a GC even if its class loader is one of these loaders.
bool ClassLoaderData::is_builtin_class_loader_data() const {
return (is_boot_class_loader_data() ||
SystemDictionary::is_system_class_loader(class_loader()) ||
@ -740,9 +740,9 @@ bool ClassLoaderData::is_builtin_class_loader_data() const {
// Returns true if this class loader data is a class loader data
// that is not ever freed by a GC. It must be the CLD for one of the builtin
// class loaders and not the CLD for an unsafe anonymous class.
// class loaders and not the CLD for a non-strong hidden class or unsafe anonymous class.
bool ClassLoaderData::is_permanent_class_loader_data() const {
return is_builtin_class_loader_data() && !is_unsafe_anonymous();
return is_builtin_class_loader_data() && !has_class_mirror_holder();
}
ClassLoaderMetaspace* ClassLoaderData::metaspace_non_null() {
@ -759,8 +759,8 @@ ClassLoaderMetaspace* ClassLoaderData::metaspace_non_null() {
if (this == the_null_class_loader_data()) {
assert (class_loader() == NULL, "Must be");
metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::BootMetaspaceType);
} else if (is_unsafe_anonymous()) {
metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::UnsafeAnonymousMetaspaceType);
} else if (has_class_mirror_holder()) {
metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::ClassMirrorHolderMetaspaceType);
} else if (class_loader()->is_a(SystemDictionary::reflect_DelegatingClassLoader_klass())) {
metaspace = new ClassLoaderMetaspace(_metaspace_lock, Metaspace::ReflectionMetaspaceType);
} else {
@ -877,8 +877,8 @@ void ClassLoaderData::free_deallocate_list_C_heap_structures() {
}
}
// These CLDs are to contain unsafe anonymous classes used for JSR292
ClassLoaderData* ClassLoaderData::unsafe_anonymous_class_loader_data(Handle loader) {
// These CLDs are to contain non-strong hidden classes or unsafe anonymous classes used for JSR292
ClassLoaderData* ClassLoaderData::has_class_mirror_holder_cld(Handle loader) {
// Add a new class loader data to the graph.
return ClassLoaderDataGraph::add(loader, true);
}
@ -920,8 +920,8 @@ void ClassLoaderData::print_value_on(outputStream* out) const {
// loader data: 0xsomeaddr of 'bootstrap'
out->print("loader data: " INTPTR_FORMAT " of %s", p2i(this), loader_name_and_id());
}
if (is_unsafe_anonymous()) {
out->print(" unsafe anonymous");
if (_has_class_mirror_holder) {
out->print(" has a class holder");
}
}
@ -931,7 +931,7 @@ void ClassLoaderData::print_value() const { print_value_on(tty); }
void ClassLoaderData::print_on(outputStream* out) const {
out->print("ClassLoaderData CLD: " PTR_FORMAT ", loader: " PTR_FORMAT ", loader_klass: %s {",
p2i(this), p2i(_class_loader.ptr_raw()), loader_name_and_id());
if (is_unsafe_anonymous()) out->print(" unsafe anonymous");
if (has_class_mirror_holder()) out->print(" has a class holder");
if (claimed()) out->print(" claimed");
if (is_unloading()) out->print(" unloading");
out->print(" metaspace: " INTPTR_FORMAT, p2i(metaspace_or_null()));
@ -951,8 +951,8 @@ void ClassLoaderData::verify() {
assert_locked_or_safepoint(_metaspace_lock);
oop cl = class_loader();
guarantee(this == class_loader_data(cl) || is_unsafe_anonymous(), "Must be the same");
guarantee(cl != NULL || this == ClassLoaderData::the_null_class_loader_data() || is_unsafe_anonymous(), "must be");
guarantee(this == class_loader_data(cl) || has_class_mirror_holder(), "Must be the same");
guarantee(cl != NULL || this == ClassLoaderData::the_null_class_loader_data() || has_class_mirror_holder(), "must be");
// Verify the integrity of the allocated space.
if (metaspace_or_null() != NULL) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2020, 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
@ -117,17 +117,20 @@ class ClassLoaderData : public CHeapObj<mtClass> {
// classes in the class loader are allocated.
Mutex* _metaspace_lock; // Locks the metaspace for allocations and setup.
bool _unloading; // true if this class loader goes away
bool _is_unsafe_anonymous; // CLD is dedicated to one class and that class determines the CLDs lifecycle.
// For example, an unsafe anonymous class.
bool _has_class_mirror_holder; // If true, CLD is dedicated to one class and that class determines
// the CLDs lifecycle. For example, a non-strong hidden class or an
// unsafe anonymous class. Arrays of these classes are also assigned
// to these class loader datas.
// Remembered sets support for the oops in the class loader data.
bool _modified_oops; // Card Table Equivalent (YC/CMS support)
bool _accumulated_modified_oops; // Mod Union Equivalent (CMS support)
int _keep_alive; // if this CLD is kept alive.
// Used for unsafe anonymous classes and the boot class
// loader. _keep_alive does not need to be volatile or
// atomic since there is one unique CLD per unsafe anonymous class.
// Used for non-strong hidden classes, unsafe anonymous classes and the
// boot class loader. _keep_alive does not need to be volatile or
// atomic since there is one unique CLD per non-strong hidden class
// or unsafe anonymous class.
volatile int _claim; // non-zero if claimed, for example during GC traces.
// To avoid applying oop closure more than once.
@ -162,7 +165,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
void set_next(ClassLoaderData* next) { _next = next; }
ClassLoaderData* next() const { return Atomic::load(&_next); }
ClassLoaderData(Handle h_class_loader, bool is_unsafe_anonymous);
ClassLoaderData(Handle h_class_loader, bool has_class_mirror_holder);
~ClassLoaderData();
// The CLD are not placed in the Heap, so the Card Table or
@ -231,7 +234,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
Mutex* metaspace_lock() const { return _metaspace_lock; }
bool is_unsafe_anonymous() const { return _is_unsafe_anonymous; }
bool has_class_mirror_holder() const { return _has_class_mirror_holder; }
static void init_null_class_loader_data();
@ -240,15 +243,15 @@ class ClassLoaderData : public CHeapObj<mtClass> {
}
// Returns true if this class loader data is for the system class loader.
// (Note that the class loader data may be unsafe anonymous.)
// (Note that the class loader data may be for a non-strong hidden class or unsafe anonymous class)
bool is_system_class_loader_data() const;
// Returns true if this class loader data is for the platform class loader.
// (Note that the class loader data may be unsafe anonymous.)
// (Note that the class loader data may be for a non-strong hidden class or unsafe anonymous class)
bool is_platform_class_loader_data() const;
// Returns true if this class loader data is for the boot class loader.
// (Note that the class loader data may be unsafe anonymous.)
// (Note that the class loader data may be for a non-strong hidden class or unsafe anonymous class)
inline bool is_boot_class_loader_data() const;
bool is_builtin_class_loader_data() const;
@ -269,7 +272,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
return _unloading;
}
// Used to refcount an unsafe anonymous class's CLD in order to
// Used to refcount a non-strong hidden class's or unsafe anonymous class's CLD in order to
// indicate their aliveness.
void inc_keep_alive();
void dec_keep_alive();
@ -313,7 +316,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
static ClassLoaderData* class_loader_data(oop loader);
static ClassLoaderData* class_loader_data_or_null(oop loader);
static ClassLoaderData* unsafe_anonymous_class_loader_data(Handle loader);
static ClassLoaderData* has_class_mirror_holder_cld(Handle loader);
// Returns Klass* of associated class loader, or NULL if associated loader is 'bootstrap'.
// Also works if unloading.

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, 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
@ -192,7 +192,7 @@ bool ClassLoaderDataGraph::_metaspace_oom = false;
// Add a new class loader data node to the list. Assign the newly created
// ClassLoaderData into the java/lang/ClassLoader object as a hidden field
ClassLoaderData* ClassLoaderDataGraph::add_to_graph(Handle loader, bool is_unsafe_anonymous) {
ClassLoaderData* ClassLoaderDataGraph::add_to_graph(Handle loader, bool has_class_mirror_holder) {
assert_lock_strong(ClassLoaderDataGraph_lock);
@ -200,7 +200,7 @@ ClassLoaderData* ClassLoaderDataGraph::add_to_graph(Handle loader, bool is_unsaf
// First check if another thread beat us to creating the CLD and installing
// it into the loader while we were waiting for the lock.
if (!is_unsafe_anonymous && loader.not_null()) {
if (!has_class_mirror_holder && loader.not_null()) {
cld = java_lang_ClassLoader::loader_data_acquire(loader());
if (cld != NULL) {
return cld;
@ -212,14 +212,14 @@ ClassLoaderData* ClassLoaderDataGraph::add_to_graph(Handle loader, bool is_unsaf
// loader oop in all collections, particularly young collections.
NoSafepointVerifier no_safepoints;
cld = new ClassLoaderData(loader, is_unsafe_anonymous);
cld = new ClassLoaderData(loader, has_class_mirror_holder);
// First install the new CLD to the Graph.
cld->set_next(_head);
Atomic::release_store(&_head, cld);
// Next associate with the class_loader.
if (!is_unsafe_anonymous) {
if (!has_class_mirror_holder) {
// Use OrderAccess, since readers need to get the loader_data only after
// it's added to the Graph
java_lang_ClassLoader::release_set_loader_data(loader(), cld);
@ -237,9 +237,9 @@ ClassLoaderData* ClassLoaderDataGraph::add_to_graph(Handle loader, bool is_unsaf
return cld;
}
ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_unsafe_anonymous) {
ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool has_class_mirror_holder) {
MutexLocker ml(ClassLoaderDataGraph_lock);
ClassLoaderData* loader_data = add_to_graph(loader, is_unsafe_anonymous);
ClassLoaderData* loader_data = add_to_graph(loader, has_class_mirror_holder);
return loader_data;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, 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
@ -56,8 +56,8 @@ class ClassLoaderDataGraph : public AllStatic {
static volatile size_t _num_instance_classes;
static volatile size_t _num_array_classes;
static ClassLoaderData* add_to_graph(Handle class_loader, bool is_unsafe_anonymous);
static ClassLoaderData* add(Handle class_loader, bool is_unsafe_anonymous);
static ClassLoaderData* add_to_graph(Handle class_loader, bool has_class_mirror_holder);
static ClassLoaderData* add(Handle class_loader, bool has_class_mirror_holder);
public:
static ClassLoaderData* find_or_create(Handle class_loader);
@ -76,7 +76,7 @@ class ClassLoaderDataGraph : public AllStatic {
// Walking classes through the ClassLoaderDataGraph include array classes. It also includes
// classes that are allocated but not loaded, classes that have errors, and scratch classes
// for redefinition. These classes are removed during the next class unloading.
// Walking the ClassLoaderDataGraph also includes unsafe anonymous classes.
// Walking the ClassLoaderDataGraph also includes hidden and unsafe anonymous classes.
static void classes_do(KlassClosure* klass_closure);
static void classes_do(void f(Klass* const));
static void methods_do(void f(Method*));

@ -284,13 +284,12 @@ InstanceKlass* ClassLoaderExt::load_class(Symbol* name, const char* path, TRAPS)
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
Handle protection_domain;
ClassLoadInfo cl_info(protection_domain);
InstanceKlass* result = KlassFactory::create_from_stream(stream,
name,
loader_data,
protection_domain,
NULL, // unsafe_anonymous_host
NULL, // cp_patches
cl_info,
THREAD);
if (HAS_PENDING_EXCEPTION) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -129,7 +129,7 @@ public:
class LoaderTreeNode : public ResourceObj {
// We walk the CLDG and, for each CLD which is non-unsafe_anonymous, add
// We walk the CLDG and, for each CLD which is findable, add
// a tree node.
// To add a node we need its parent node; if the parent node does not yet
// exist - because we have not yet encountered the CLD for the parent loader -
@ -149,6 +149,9 @@ class LoaderTreeNode : public ResourceObj {
LoadedClassInfo* _anon_classes;
int _num_anon_classes;
LoadedClassInfo* _hidden_classes;
int _num_hidden_classes;
// In default view, similar tree nodes (same loader class, same name or no name)
// are folded into each other to make the output more readable.
// _num_folded contains the number of nodes which have been folded into this
@ -177,6 +180,7 @@ class LoaderTreeNode : public ResourceObj {
if (_cld->is_the_null_class_loader_data()) {
st->print(" <bootstrap>");
} else {
assert(!_cld->has_class_mirror_holder(), "_cld must be the primary cld");
if (loader_name != NULL) {
st->print(" \"%s\",", loader_name->as_C_string());
}
@ -220,7 +224,7 @@ class LoaderTreeNode : public ResourceObj {
if (print_classes) {
if (_classes != NULL) {
for (LoadedClassInfo* lci = _classes; lci; lci = lci->_next) {
// Non-unsafe anonymous classes should live in the primary CLD of its loader
// non-strong hidden and unsafe anonymous classes should not live in the primary CLD of their loaders.
assert(lci->_cld == _cld, "must be");
branchtracker.print(st);
@ -258,7 +262,8 @@ class LoaderTreeNode : public ResourceObj {
st->print("%*s ", indentation, "");
}
st->print("%s", lci->_klass->external_name());
// For unsafe anonymous classes, also print CLD if verbose. Should be a different one than the primary CLD.
// For unsafe anonymous classes, also print CLD if verbose. Should
// be a different one than the primary CLD.
assert(lci->_cld != _cld, "must be");
if (verbose) {
st->print(" (Loader Data: " PTR_FORMAT ")", p2i(lci->_cld));
@ -267,7 +272,35 @@ class LoaderTreeNode : public ResourceObj {
}
branchtracker.print(st);
st->print("%*s ", indentation, "");
st->print_cr("(%u unsafe anonymous class%s)", _num_anon_classes, (_num_anon_classes == 1) ? "" : "es");
st->print_cr("(%u unsafe anonymous class%s)", _num_anon_classes,
(_num_anon_classes == 1) ? "" : "es");
// Empty line
branchtracker.print(st);
st->cr();
}
if (_hidden_classes != NULL) {
for (LoadedClassInfo* lci = _hidden_classes; lci; lci = lci->_next) {
branchtracker.print(st);
if (lci == _hidden_classes) { // first iteration
st->print("%*s ", indentation, "Hidden Classes:");
} else {
st->print("%*s ", indentation, "");
}
st->print("%s", lci->_klass->external_name());
// For non-strong hidden classes, also print CLD if verbose. Should be a
// different one than the primary CLD.
assert(lci->_cld != _cld, "must be");
if (verbose) {
st->print(" (Loader Data: " PTR_FORMAT ")", p2i(lci->_cld));
}
st->cr();
}
branchtracker.print(st);
st->print("%*s ", indentation, "");
st->print_cr("(%u hidden class%s)", _num_hidden_classes,
(_num_hidden_classes == 1) ? "" : "es");
// Empty line
branchtracker.print(st);
@ -301,6 +334,7 @@ public:
LoaderTreeNode(const oop loader_oop)
: _loader_oop(loader_oop), _cld(NULL), _child(NULL), _next(NULL),
_classes(NULL), _num_classes(0), _anon_classes(NULL), _num_anon_classes(0),
_hidden_classes(NULL), _num_hidden_classes(0),
_num_folded(0)
{}
@ -319,15 +353,25 @@ public:
_next = info;
}
void add_classes(LoadedClassInfo* first_class, int num_classes, bool is_unsafe_anonymous) {
LoadedClassInfo** p_list_to_add_to = is_unsafe_anonymous ? &_anon_classes : &_classes;
void add_classes(LoadedClassInfo* first_class, int num_classes, bool has_class_mirror_holder) {
LoadedClassInfo** p_list_to_add_to;
bool is_hidden = first_class->_klass->is_hidden();
if (has_class_mirror_holder) {
p_list_to_add_to = is_hidden ? &_hidden_classes : &_anon_classes;
} else {
p_list_to_add_to = &_classes;
}
// Search tail.
while ((*p_list_to_add_to) != NULL) {
p_list_to_add_to = &(*p_list_to_add_to)->_next;
}
*p_list_to_add_to = first_class;
if (is_unsafe_anonymous) {
_num_anon_classes += num_classes;
if (has_class_mirror_holder) {
if (is_hidden) {
_num_hidden_classes += num_classes;
} else {
_num_anon_classes += num_classes;
}
} else {
_num_classes += num_classes;
}
@ -421,7 +465,7 @@ class LoaderInfoScanClosure : public CLDClosure {
LoadedClassCollectClosure lccc(cld);
const_cast<ClassLoaderData*>(cld)->classes_do(&lccc);
if (lccc._num_classes > 0) {
info->add_classes(lccc._list, lccc._num_classes, cld->is_unsafe_anonymous());
info->add_classes(lccc._list, lccc._num_classes, cld->has_class_mirror_holder());
}
}
@ -481,7 +525,7 @@ public:
assert(info != NULL, "must be");
// Update CLD in node, but only if this is the primary CLD for this loader.
if (cld->is_unsafe_anonymous() == false) {
if (cld->has_class_mirror_holder() == false) {
assert(info->cld() == NULL, "there should be only one primary CLD per loader");
info->set_cld(cld);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, 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
@ -26,6 +26,7 @@
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/classLoaderDataGraph.hpp"
#include "classfile/classLoaderStats.hpp"
#include "oops/objArrayKlass.hpp"
#include "oops/oop.inline.hpp"
#include "utilities/globalDefinitions.hpp"
@ -59,7 +60,7 @@ void ClassLoaderStatsClosure::do_cld(ClassLoaderData* cld) {
cls = *cls_ptr;
}
if (!cld->is_unsafe_anonymous()) {
if (!cld->has_class_mirror_holder()) {
cls->_cld = cld;
}
@ -71,8 +72,20 @@ void ClassLoaderStatsClosure::do_cld(ClassLoaderData* cld) {
ClassStatsClosure csc;
cld->classes_do(&csc);
if(cld->is_unsafe_anonymous()) {
cls->_anon_classes_count += csc._num_classes;
bool is_hidden = false;
if(cld->has_class_mirror_holder()) {
// if cld has a class holder then it must be either hidden or unsafe anonymous.
Klass* k = cld->klasses();
// if it's an array class then need to see if bottom class is hidden.
if (k->is_array_klass()) {
k = ObjArrayKlass::cast(k)->bottom_klass();
}
is_hidden = k->is_hidden();
if (is_hidden) {
cls->_hidden_classes_count += csc._num_classes;
} else {
cls->_anon_classes_count += csc._num_classes;
}
} else {
cls->_classes_count = csc._num_classes;
}
@ -80,9 +93,14 @@ void ClassLoaderStatsClosure::do_cld(ClassLoaderData* cld) {
ClassLoaderMetaspace* ms = cld->metaspace_or_null();
if (ms != NULL) {
if(cld->is_unsafe_anonymous()) {
cls->_anon_chunk_sz += ms->allocated_chunks_bytes();
cls->_anon_block_sz += ms->allocated_blocks_bytes();
if(cld->has_class_mirror_holder()) {
if (is_hidden) {
cls->_hidden_chunk_sz += ms->allocated_chunks_bytes();
cls->_hidden_block_sz += ms->allocated_blocks_bytes();
} else {
cls->_anon_chunk_sz += ms->allocated_chunks_bytes();
cls->_anon_block_sz += ms->allocated_blocks_bytes();
}
} else {
cls->_chunk_sz = ms->allocated_chunks_bytes();
cls->_block_sz = ms->allocated_blocks_bytes();
@ -121,6 +139,12 @@ bool ClassLoaderStatsClosure::do_entry(oop const& key, ClassLoaderStats* const&
cls->_anon_classes_count,
cls->_anon_chunk_sz, cls->_anon_block_sz);
}
if (cls->_hidden_classes_count > 0) {
_out->print_cr(SPACE SPACE SPACE " " UINTX_FORMAT_W(6) " " SIZE_FORMAT_W(8) " " SIZE_FORMAT_W(8) " + hidden classes",
"", "", "",
cls->_hidden_classes_count,
cls->_hidden_chunk_sz, cls->_hidden_block_sz);
}
return true;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, 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
@ -81,6 +81,10 @@ public:
size_t _anon_block_sz;
uintx _anon_classes_count;
size_t _hidden_chunk_sz;
size_t _hidden_block_sz;
uintx _hidden_classes_count;
ClassLoaderStats() :
_cld(0),
_class_loader(0),
@ -90,7 +94,10 @@ public:
_classes_count(0),
_anon_chunk_sz(0),
_anon_block_sz(0),
_anon_classes_count(0) {
_anon_classes_count(0),
_hidden_chunk_sz(0),
_hidden_block_sz(0),
_hidden_classes_count(0) {
}
};

@ -918,7 +918,7 @@ static void switchover_constant_pool(BytecodeConstantPool* bpool,
ConstantPool* cp = bpool->create_constant_pool(CHECK);
if (cp != klass->constants()) {
// Copy resolved anonymous class into new constant pool.
if (klass->is_unsafe_anonymous()) {
if (klass->is_unsafe_anonymous() || klass->is_hidden()) {
cp->klass_at_put(klass->this_class_index(), klass);
}
klass->class_loader_data()->add_to_deallocate_list(klass->constants());

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2020, 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
@ -354,6 +354,7 @@ bool Dictionary::is_valid_protection_domain(unsigned int hash,
// since been unreferenced, so this entry should be cleared.
void Dictionary::clean_cached_protection_domains() {
assert_locked_or_safepoint(SystemDictionary_lock);
assert(!loader_data()->has_class_mirror_holder(), "cld should have a ClassLoader holder not a Class holder");
if (loader_data()->is_the_null_class_loader_data()) {
// Classes in the boot loader are not loaded with protection domains
@ -482,6 +483,7 @@ void Dictionary::print_on(outputStream* st) const {
ResourceMark rm;
assert(loader_data() != NULL, "loader data should not be null");
assert(!loader_data()->has_class_mirror_holder(), "cld should have a ClassLoader holder not a Class holder");
st->print_cr("Java dictionary (table_size=%d, classes=%d, resizable=%s)",
table_size(), number_of_entries(), BOOL_TO_STR(_resizable));
st->print_cr("^ indicates that initiating loader is different from defining loader");

@ -880,12 +880,13 @@ void java_lang_Class::fixup_mirror(Klass* k, TRAPS) {
k->clear_has_raw_archived_mirror();
}
}
create_mirror(k, Handle(), Handle(), Handle(), CHECK);
create_mirror(k, Handle(), Handle(), Handle(), Handle(), CHECK);
}
void java_lang_Class::initialize_mirror_fields(Klass* k,
Handle mirror,
Handle protection_domain,
Handle classData,
TRAPS) {
// Allocate a simple java object for a lock.
// This needs to be a java object because during class initialization
@ -898,6 +899,9 @@ void java_lang_Class::initialize_mirror_fields(Klass* k,
// Initialize static fields
InstanceKlass::cast(k)->do_local_static_fields(&initialize_static_field, mirror, CHECK);
// Set classData
set_class_data(mirror(), classData());
}
// Set the java.lang.Module module field in the java_lang_Class mirror
@ -951,7 +955,8 @@ void java_lang_Class::allocate_fixup_lists() {
}
void java_lang_Class::create_mirror(Klass* k, Handle class_loader,
Handle module, Handle protection_domain, TRAPS) {
Handle module, Handle protection_domain,
Handle classData, TRAPS) {
assert(k != NULL, "Use create_basic_type_mirror for primitive types");
assert(k->java_mirror() == NULL, "should only assign mirror once");
@ -998,7 +1003,7 @@ void java_lang_Class::create_mirror(Klass* k, Handle class_loader,
} else {
assert(k->is_instance_klass(), "Must be");
initialize_mirror_fields(k, mirror, protection_domain, THREAD);
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.
@ -1424,6 +1429,14 @@ void java_lang_Class::set_signers(oop java_class, objArrayOop signers) {
java_class->obj_field_put(_signers_offset, (oop)signers);
}
oop java_lang_Class::class_data(oop java_class) {
assert(_classData_offset != 0, "must be set");
return java_class->obj_field(_classData_offset);
}
void java_lang_Class::set_class_data(oop java_class, oop class_data) {
assert(_classData_offset != 0, "must be set");
java_class->obj_field_put(_classData_offset, class_data);
}
void java_lang_Class::set_class_loader(oop java_class, oop loader) {
assert(_class_loader_offset != 0, "offsets should have been initialized");
@ -1627,6 +1640,7 @@ int java_lang_Class::classRedefinedCount_offset = -1;
macro(_component_mirror_offset, k, "componentType", class_signature, false); \
macro(_module_offset, k, "module", module_signature, false); \
macro(_name_offset, k, "name", string_signature, false); \
macro(_classData_offset, k, "classData", object_signature, false);
void java_lang_Class::compute_offsets() {
if (offsets_computed) {
@ -4295,6 +4309,7 @@ int java_lang_Class::_init_lock_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;
GrowableArray<Klass*>* java_lang_Class::_fixup_mirror_list = NULL;
GrowableArray<Klass*>* java_lang_Class::_fixup_module_field_list = NULL;
int java_lang_Throwable::backtrace_offset;

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, 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
@ -265,6 +265,7 @@ class java_lang_Class : AllStatic {
static int _component_mirror_offset;
static int _name_offset;
static int _source_file_offset;
static int _classData_offset;
static bool offsets_computed;
static int classRedefinedCount_offset;
@ -276,7 +277,8 @@ class java_lang_Class : AllStatic {
static void set_protection_domain(oop java_class, oop protection_domain);
static void set_class_loader(oop java_class, oop class_loader);
static void set_component_mirror(oop java_class, oop comp_mirror);
static void initialize_mirror_fields(Klass* k, Handle mirror, Handle protection_domain, TRAPS);
static void initialize_mirror_fields(Klass* k, Handle mirror, Handle protection_domain,
Handle classData, TRAPS);
static void set_mirror_module_field(Klass* K, Handle mirror, Handle module, TRAPS);
public:
static void allocate_fixup_lists();
@ -284,7 +286,7 @@ class java_lang_Class : AllStatic {
// Instance creation
static void create_mirror(Klass* k, Handle class_loader, Handle module,
Handle protection_domain, TRAPS);
Handle protection_domain, Handle classData, TRAPS);
static void fixup_mirror(Klass* k, TRAPS);
static oop create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS);
static void update_archived_primitive_mirror_native_pointers(oop archived_mirror) NOT_CDS_JAVA_HEAP_RETURN;
@ -332,6 +334,8 @@ class java_lang_Class : AllStatic {
static oop component_mirror(oop java_class);
static objArrayOop signers(oop java_class);
static void set_signers(oop java_class, objArrayOop signers);
static oop class_data(oop java_class);
static void set_class_data(oop java_class, oop classData);
static oop class_loader(oop java_class);
static void set_module(oop java_class, oop module);
@ -1144,16 +1148,20 @@ class java_lang_invoke_MemberName: AllStatic {
// Relevant integer codes (keep these in synch. with MethodHandleNatives.Constants):
enum {
MN_IS_METHOD = 0x00010000, // method (not constructor)
MN_IS_CONSTRUCTOR = 0x00020000, // constructor
MN_IS_FIELD = 0x00040000, // field
MN_IS_TYPE = 0x00080000, // nested type
MN_CALLER_SENSITIVE = 0x00100000, // @CallerSensitive annotation detected
MN_REFERENCE_KIND_SHIFT = 24, // refKind
MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT,
MN_IS_METHOD = 0x00010000, // method (not constructor)
MN_IS_CONSTRUCTOR = 0x00020000, // constructor
MN_IS_FIELD = 0x00040000, // field
MN_IS_TYPE = 0x00080000, // nested type
MN_CALLER_SENSITIVE = 0x00100000, // @CallerSensitive annotation detected
MN_REFERENCE_KIND_SHIFT = 24, // refKind
MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT,
// The SEARCH_* bits are not for MN.flags but for the matchFlags argument of MHN.getMembers:
MN_SEARCH_SUPERCLASSES = 0x00100000, // walk super classes
MN_SEARCH_INTERFACES = 0x00200000 // walk implemented interfaces
MN_SEARCH_SUPERCLASSES = 0x00100000, // walk super classes
MN_SEARCH_INTERFACES = 0x00200000, // walk implemented interfaces
MN_NESTMATE_CLASS = 0x00000001,
MN_HIDDEN_CLASS = 0x00000002,
MN_STRONG_LOADER_LINK = 0x00000004,
MN_ACCESS_VM_ANNOTATIONS = 0x00000008
};
// Accessors for code generation:

@ -79,16 +79,18 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook(
end_ptr - ptr,
cfs->source(),
ClassFileStream::verify);
ClassLoadInfo cl_info(protection_domain);
ClassFileParser parser(stream,
class_name,
loader_data,
protection_domain,
NULL,
NULL,
&cl_info,
ClassFileParser::BROADCAST, // publicity level
CHECK_NULL);
InstanceKlass* new_ik = parser.create_instance_klass(true /* changed_by_loadhook */,
const ClassInstanceInfo* cl_inst_info = cl_info.class_hidden_info_ptr();
InstanceKlass* new_ik = parser.create_instance_klass(true, // changed_by_loadhook
*cl_inst_info, // dynamic_nest_host and classData
CHECK_NULL);
if (cached_class_file != NULL) {
new_ik->set_cached_class_file(cached_class_file);
}
@ -165,9 +167,7 @@ static ClassFileStream* check_class_file_load_hook(ClassFileStream* stream,
InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
Symbol* name,
ClassLoaderData* loader_data,
Handle protection_domain,
const InstanceKlass* unsafe_anonymous_host,
GrowableArray<Handle>* cp_patches,
const ClassLoadInfo& cl_info,
TRAPS) {
assert(stream != NULL, "invariant");
assert(loader_data != NULL, "invariant");
@ -183,12 +183,15 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
// increment counter
THREAD->statistical_info().incr_define_class_count();
// Skip this processing for VM anonymous classes
if (unsafe_anonymous_host == NULL) {
assert(!(cl_info.is_hidden() && (cl_info.unsafe_anonymous_host() != NULL)),
"hidden class has an anonymous host");
// Skip this processing for VM hidden or anonymous classes
if (!cl_info.is_hidden() && (cl_info.unsafe_anonymous_host() == NULL)) {
stream = check_class_file_load_hook(stream,
name,
loader_data,
protection_domain,
cl_info.protection_domain(),
&cached_class_file,
CHECK_NULL);
}
@ -196,14 +199,12 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
ClassFileParser parser(stream,
name,
loader_data,
protection_domain,
unsafe_anonymous_host,
cp_patches,
&cl_info,
ClassFileParser::BROADCAST, // publicity level
CHECK_NULL);
InstanceKlass* result = parser.create_instance_klass(old_stream != stream, CHECK_NULL);
assert(result == parser.create_instance_klass(old_stream != stream, THREAD), "invariant");
const ClassInstanceInfo* cl_inst_info = cl_info.class_hidden_info_ptr();
InstanceKlass* result = parser.create_instance_klass(old_stream != stream, *cl_inst_info, CHECK_NULL);
if (result == NULL) {
return NULL;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, 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
@ -30,6 +30,7 @@
class ClassFileStream;
class ClassLoaderData;
class ClassLoadInfo;
template <typename>
class GrowableArray;
class Klass;
@ -71,9 +72,7 @@ class KlassFactory : AllStatic {
static InstanceKlass* create_from_stream(ClassFileStream* stream,
Symbol* name,
ClassLoaderData* loader_data,
Handle protection_domain,
const InstanceKlass* unsafe_anonymous_host,
GrowableArray<Handle>* cp_patches,
const ClassLoadInfo& cl_info,
TRAPS);
public:
static InstanceKlass* check_shared_class_file_load_hook(

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, 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
@ -75,6 +75,7 @@ bool ModuleEntry::should_show_version() {
const char* loc = location()->as_C_string();
ClassLoaderData* cld = loader_data();
assert(!cld->has_class_mirror_holder(), "module's cld should have a ClassLoader holder not a Class holder");
if ((cld->is_the_null_class_loader_data() || cld->is_platform_class_loader_data()) &&
(strncmp(loc, "jrt:/java.", 10) == 0)) {
return false;
@ -135,6 +136,7 @@ bool ModuleEntry::can_read(ModuleEntry* m) const {
// injecting dependencies that require the default read edges for resolution.
if (this->has_default_read_edges() && !m->is_named()) {
ClassLoaderData* cld = m->loader_data();
assert(!cld->has_class_mirror_holder(), "module's cld should have a ClassLoader holder not a Class holder");
if (cld->is_the_null_class_loader_data() || cld->is_system_class_loader_data()) {
return true; // default read edge
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, 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
@ -110,7 +110,7 @@ public:
ClassLoaderData* loader_data() const { return _loader_data; }
void set_loader_data(ClassLoaderData* cld) {
assert(!cld->is_unsafe_anonymous(), "Unexpected unsafe anonymous class loader data");
assert(!cld->has_class_mirror_holder(), "Unexpected has_class_mirror_holder cld");
_loader_data = cld;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2020, 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
@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/resolutionErrors.hpp"
#include "memory/allocation.hpp"
#include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/handles.inline.hpp"
@ -42,6 +43,18 @@ void ResolutionErrorTable::add_entry(int index, unsigned int hash,
add_entry(index, entry);
}
// add new entry to the table
void ResolutionErrorTable::add_entry(int index, unsigned int hash,
const constantPoolHandle& pool, int cp_index,
const char* message)
{
assert_locked_or_safepoint(SystemDictionary_lock);
assert(!pool.is_null() && message != NULL, "adding NULL obj");
ResolutionErrorEntry* entry = new_entry(hash, pool(), cp_index, message);
add_entry(index, entry);
}
// find entry in the table
ResolutionErrorEntry* ResolutionErrorTable::find_entry(int index, unsigned int hash,
const constantPoolHandle& pool, int cp_index)
@ -59,9 +72,10 @@ ResolutionErrorEntry* ResolutionErrorTable::find_entry(int index, unsigned int h
}
void ResolutionErrorEntry::set_error(Symbol* e) {
assert(e != NULL, "must set a value");
_error = e;
_error->increment_refcount();
if (_error != NULL) {
_error->increment_refcount();
}
}
void ResolutionErrorEntry::set_message(Symbol* c) {
@ -71,6 +85,10 @@ void ResolutionErrorEntry::set_message(Symbol* c) {
}
}
void ResolutionErrorEntry::set_nest_host_error(const char* message) {
_nest_host_error = message;
}
// create new error entry
ResolutionErrorEntry* ResolutionErrorTable::new_entry(int hash, ConstantPool* pool,
int cp_index, Symbol* error,
@ -80,17 +98,35 @@ ResolutionErrorEntry* ResolutionErrorTable::new_entry(int hash, ConstantPool* po
entry->set_cp_index(cp_index);
entry->set_error(error);
entry->set_message(message);
entry->set_nest_host_error(NULL);
return entry;
}
// create new nest host error entry
ResolutionErrorEntry* ResolutionErrorTable::new_entry(int hash, ConstantPool* pool,
int cp_index, const char* message)
{
ResolutionErrorEntry* entry = (ResolutionErrorEntry*)Hashtable<ConstantPool*, mtClass>::new_entry(hash, pool);
entry->set_cp_index(cp_index);
entry->set_nest_host_error(message);
entry->set_error(NULL);
entry->set_message(NULL);
return entry;
}
void ResolutionErrorTable::free_entry(ResolutionErrorEntry *entry) {
// decrement error refcount
assert(entry->error() != NULL, "error should be set");
entry->error()->decrement_refcount();
if (entry->error() != NULL) {
entry->error()->decrement_refcount();
}
if (entry->message() != NULL) {
entry->message()->decrement_refcount();
}
if (entry->nest_host_error() != NULL) {
FREE_C_HEAP_ARRAY(char, entry->nest_host_error());
}
Hashtable<ConstantPool*, mtClass>::free_entry(entry);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2020, 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
@ -46,6 +46,8 @@ public:
ResolutionErrorEntry* new_entry(int hash, ConstantPool* pool, int cp_index,
Symbol* error, Symbol* message);
ResolutionErrorEntry* new_entry(int hash, ConstantPool* pool, int cp_index,
const char* message);
void free_entry(ResolutionErrorEntry *entry);
ResolutionErrorEntry* bucket(int i) {
@ -64,6 +66,8 @@ public:
void add_entry(int index, unsigned int hash,
const constantPoolHandle& pool, int which, Symbol* error, Symbol* message);
void add_entry(int index, unsigned int hash,
const constantPoolHandle& pool, int which, const char* message);
// find error given the constant pool and constant pool index
ResolutionErrorEntry* find_entry(int index, unsigned int hash,
@ -95,6 +99,7 @@ class ResolutionErrorEntry : public HashtableEntry<ConstantPool*, mtClass> {
int _cp_index;
Symbol* _error;
Symbol* _message;
const char* _nest_host_error;
public:
ConstantPool* pool() const { return literal(); }
@ -108,6 +113,9 @@ class ResolutionErrorEntry : public HashtableEntry<ConstantPool*, mtClass> {
Symbol* message() const { return _message; }
void set_message(Symbol* c);
const char* nest_host_error() const { return _nest_host_error; }
void set_nest_host_error(const char* message);
ResolutionErrorEntry* next() const {
return (ResolutionErrorEntry*)HashtableEntry<ConstantPool*, mtClass>::next();
}

@ -459,6 +459,8 @@ Symbol* SymbolTable::lookup_only_unicode(const jchar* name, int utf16_length,
void SymbolTable::new_symbols(ClassLoaderData* loader_data, const constantPoolHandle& cp,
int names_count, const char** names, int* lengths,
int* cp_indices, unsigned int* hashValues) {
// Note that c_heap will be true for non-strong hidden classes and unsafe anonymous classes
// even if their loader is the boot loader because they will have a different cld.
bool c_heap = !loader_data->is_the_null_class_loader_data();
for (int i = 0; i < names_count; i++) {
const char *name = names[i];

@ -111,6 +111,46 @@ oop SystemDictionary::_java_platform_loader = NULL;
const int defaultProtectionDomainCacheSize = 1009;
ClassLoadInfo::ClassLoadInfo() {
_protection_domain = Handle();
_unsafe_anonymous_host = NULL;
_cp_patches = NULL;
_class_hidden_info._dynamic_nest_host = NULL;
_class_hidden_info._class_data = Handle();
_is_hidden = false;
_is_strong_hidden = false;
_can_access_vm_annotations = false;
}
ClassLoadInfo::ClassLoadInfo(Handle protection_domain) {
_protection_domain = protection_domain;
_unsafe_anonymous_host = NULL;
_cp_patches = NULL;
_class_hidden_info._dynamic_nest_host = NULL;
_class_hidden_info._class_data = Handle();
_is_hidden = false;
_is_strong_hidden = false;
_can_access_vm_annotations = false;
}
ClassLoadInfo::ClassLoadInfo(Handle protection_domain,
const InstanceKlass* unsafe_anonymous_host,
GrowableArray<Handle>* cp_patches,
InstanceKlass* dynamic_nest_host,
Handle class_data,
bool is_hidden,
bool is_strong_hidden,
bool can_access_vm_annotations) {
_protection_domain = protection_domain;
_unsafe_anonymous_host = unsafe_anonymous_host;
_cp_patches = cp_patches;
_class_hidden_info._dynamic_nest_host = dynamic_nest_host;
_class_hidden_info._class_data = class_data;
_is_hidden = is_hidden;
_is_strong_hidden = is_strong_hidden;
_can_access_vm_annotations = can_access_vm_annotations;
}
// ----------------------------------------------------------------------------
// Java-level SystemLoader and PlatformLoader
@ -822,7 +862,7 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
// class loaders holding the ObjectLock shouldn't find the class here
InstanceKlass* check = find_class(d_hash, name, dictionary);
if (check != NULL) {
// Klass is already loaded, so return it after checking/adding protection domain
// Klass is already loaded, so return it after checking/adding protection domain
k = check;
class_has_been_loaded = true;
}
@ -982,24 +1022,36 @@ Klass* SystemDictionary::find_instance_or_array_klass(Symbol* class_name,
// Note: this method is much like resolve_from_stream, but
// does not publish the classes via the SystemDictionary.
// Handles unsafe_DefineAnonymousClass and redefineclasses
// RedefinedClasses do not add to the class hierarchy
// 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,
Handle protection_domain,
ClassFileStream* st,
const InstanceKlass* unsafe_anonymous_host,
GrowableArray<Handle>* cp_patches,
const ClassLoadInfo& cl_info,
TRAPS) {
EventClassLoad class_load_start_event;
ClassLoaderData* loader_data;
if (unsafe_anonymous_host != NULL) {
// Create a new CLD for an unsafe anonymous class, that uses the same class loader
// as the unsafe_anonymous_host
guarantee(unsafe_anonymous_host->class_loader() == class_loader(), "should be the same");
loader_data = ClassLoaderData::unsafe_anonymous_class_loader_data(class_loader);
bool is_unsafe_anon_class = cl_info.unsafe_anonymous_host() != NULL;
if (is_unsafe_anon_class) {
// - for unsafe anonymous class: create a new CLD whith a class holder that uses
// the same class loader as the unsafe_anonymous_host.
guarantee(cl_info.unsafe_anonymous_host()->class_loader() == class_loader(),
"should be the same");
loader_data = ClassLoaderData::has_class_mirror_holder_cld(class_loader);
} else if (cl_info.is_hidden()) {
// - for hidden classes that are not strong: create a new CLD that has a class holder and
// whose loader is the Lookup class' loader.
// - for hidden class: add the class to the Lookup class' loader's CLD.
if (!cl_info.is_strong_hidden()) {
loader_data = ClassLoaderData::has_class_mirror_holder_cld(class_loader);
} else {
// This hidden class goes into the regular CLD pool for this loader.
loader_data = register_loader(class_loader);
}
} else {
loader_data = ClassLoaderData::class_loader_data(class_loader());
}
@ -1015,15 +1067,16 @@ InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
InstanceKlass* k = KlassFactory::create_from_stream(st,
class_name,
loader_data,
protection_domain,
unsafe_anonymous_host,
cp_patches,
cl_info,
CHECK_NULL);
if (unsafe_anonymous_host != NULL && k != NULL) {
// Unsafe anonymous classes must update ClassLoaderData holder (was unsafe_anonymous_host loader)
// so that they can be unloaded when the mirror is no longer referenced.
k->class_loader_data()->initialize_holder(Handle(THREAD, k->java_mirror()));
if ((cl_info.is_hidden() || is_unsafe_anon_class) && k != NULL) {
// 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);
@ -1036,12 +1089,14 @@ InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
// Rewrite and patch constant pool here.
k->link_class(CHECK_NULL);
if (cp_patches != NULL) {
k->constants()->patch_resolved_references(cp_patches);
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.
k->eager_initialize(CHECK_NULL);
if (is_unsafe_anon_class) {
k->eager_initialize(CHECK_NULL);
}
// notify jvmti
if (JvmtiExport::should_post_class_load()) {
@ -1052,7 +1107,7 @@ InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
post_class_load_event(&class_load_start_event, k, loader_data);
}
}
assert(unsafe_anonymous_host != NULL || NULL == cp_patches,
assert(is_unsafe_anon_class || NULL == cl_info.cp_patches(),
"cp_patches only found with unsafe_anonymous_host");
return k;
@ -1107,13 +1162,8 @@ InstanceKlass* SystemDictionary::resolve_from_stream(Symbol* class_name,
if (st->buffer() == NULL) {
return NULL;
}
k = KlassFactory::create_from_stream(st,
class_name,
loader_data,
protection_domain,
NULL, // unsafe_anonymous_host
NULL, // cp_patches
CHECK_NULL);
ClassLoadInfo cl_info(protection_domain);
k = KlassFactory::create_from_stream(st, class_name, loader_data, cl_info, CHECK_NULL);
}
assert(k != NULL, "no klass created");
@ -2327,6 +2377,42 @@ Symbol* SystemDictionary::find_resolution_error(const constantPoolHandle& pool,
}
}
// Add an entry to resolution error table to record an error in resolving or
// validating a nest host. This is used to construct informative error
// messages when IllegalAccessError's occur. If an entry already exists it will
// be updated with the nest host error message.
void SystemDictionary::add_nest_host_error(const constantPoolHandle& pool,
int which,
const char* message) {
unsigned int hash = resolution_errors()->compute_hash(pool, which);
int index = resolution_errors()->hash_to_index(hash);
{
MutexLocker ml(Thread::current(), SystemDictionary_lock);
ResolutionErrorEntry* entry = resolution_errors()->find_entry(index, hash, pool, which);
if (entry != NULL) {
assert(entry->nest_host_error() == NULL, "Nest host error message already set!");
entry->set_nest_host_error(message);
} else {
resolution_errors()->add_entry(index, hash, pool, which, message);
}
}
}
// Lookup any nest host error
const char* SystemDictionary::find_nest_host_error(const constantPoolHandle& pool, int which) {
unsigned int hash = resolution_errors()->compute_hash(pool, which);
int index = resolution_errors()->hash_to_index(hash);
{
MutexLocker ml(Thread::current(), SystemDictionary_lock);
ResolutionErrorEntry* entry = resolution_errors()->find_entry(index, hash, pool, which);
if (entry != NULL) {
return entry->nest_host_error();
} else {
return NULL;
}
}
}
// Signature constraints ensure that callers and callees agree about
// the meaning of type names in their signatures. This routine is the

@ -34,6 +34,53 @@
#include "runtime/signature.hpp"
#include "utilities/hashtable.hpp"
class ClassInstanceInfo : public StackObj {
private:
InstanceKlass* _dynamic_nest_host;
Handle _class_data;
public:
ClassInstanceInfo() {
_dynamic_nest_host = NULL;
_class_data = Handle();
}
ClassInstanceInfo(InstanceKlass* dynamic_nest_host, Handle class_data) {
_dynamic_nest_host = dynamic_nest_host;
_class_data = class_data;
}
InstanceKlass* dynamic_nest_host() const { return _dynamic_nest_host; }
Handle class_data() const { return _class_data; }
friend class ClassLoadInfo;
};
class ClassLoadInfo : public StackObj {
private:
Handle _protection_domain;
const InstanceKlass* _unsafe_anonymous_host;
GrowableArray<Handle>* _cp_patches;
ClassInstanceInfo _class_hidden_info;
bool _is_hidden;
bool _is_strong_hidden;
bool _can_access_vm_annotations;
public:
ClassLoadInfo();
ClassLoadInfo(Handle protection_domain);
ClassLoadInfo(Handle protection_domain, const InstanceKlass* unsafe_anonymous_host,
GrowableArray<Handle>* cp_patches, InstanceKlass* dynamic_nest_host,
Handle class_data, bool is_hidden, bool is_strong_hidden,
bool can_access_vm_annotations);
Handle protection_domain() const { return _protection_domain; }
const InstanceKlass* unsafe_anonymous_host() const { return _unsafe_anonymous_host; }
GrowableArray<Handle>* cp_patches() const { return _cp_patches; }
const ClassInstanceInfo* class_hidden_info_ptr() const { return &_class_hidden_info; }
bool is_hidden() const { return _is_hidden; }
bool is_strong_hidden() const { return _is_strong_hidden; }
bool can_access_vm_annotations() const { return _can_access_vm_annotations; }
};
// The dictionary in each ClassLoaderData stores all loaded classes, either
// initiatied by its class loader or defined by its class loader:
//
@ -271,28 +318,13 @@ public:
bool is_superclass,
TRAPS);
// Parse new stream. This won't update the dictionary or
// class hierarchy, simply parse the stream. Used by JVMTI RedefineClasses.
// Also used by Unsafe_DefineAnonymousClass
// 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,
Handle protection_domain,
ClassFileStream* st,
TRAPS) {
return parse_stream(class_name,
class_loader,
protection_domain,
st,
NULL, // unsafe_anonymous_host
NULL, // cp_patches
THREAD);
}
static InstanceKlass* parse_stream(Symbol* class_name,
Handle class_loader,
Handle protection_domain,
ClassFileStream* st,
const InstanceKlass* unsafe_anonymous_host,
GrowableArray<Handle>* cp_patches,
const ClassLoadInfo& cl_info,
TRAPS);
// Resolve from stream (called by jni_DefineClass and JVM_DefineClass)
@ -530,6 +562,11 @@ public:
Symbol** message);
// Record a nest host resolution/validation error
static void add_nest_host_error(const constantPoolHandle& pool, int which,
const char* message);
static const char* find_nest_host_error(const constantPoolHandle& pool, int which);
static ProtectionDomainCacheEntry* cache_get(Handle protection_domain);
protected:

@ -915,7 +915,7 @@ InstanceKlass* SystemDictionaryShared::lookup_from_stream(Symbol* class_name,
if (!UseSharedSpaces) {
return NULL;
}
if (class_name == NULL) { // don't do this for anonymous classes
if (class_name == NULL) { // don't do this for hidden and unsafe anonymous classes
return NULL;
}
if (class_loader.is_null() ||
@ -1097,9 +1097,9 @@ void SystemDictionaryShared::warn_excluded(InstanceKlass* k, const char* reason)
}
bool SystemDictionaryShared::should_be_excluded(InstanceKlass* k) {
if (k->class_loader_data()->is_unsafe_anonymous()) {
warn_excluded(k, "Unsafe anonymous class");
return true; // unsafe anonymous classes are not archived, skip
if (k->is_hidden() || k->is_unsafe_anonymous()) {
warn_excluded(k, "Hidden or Unsafe anonymous class");
return true; // hidden and unsafe anonymous classes are not archived, skip
}
if (k->is_in_error_state()) {
warn_excluded(k, "In error state");

@ -48,11 +48,16 @@ VerificationType VerificationType::from_tag(u1 tag) {
bool VerificationType::resolve_and_check_assignability(InstanceKlass* klass, Symbol* name,
Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object, TRAPS) {
HandleMark hm(THREAD);
Klass* this_class = SystemDictionary::resolve_or_fail(
Klass* this_class;
if (klass->is_hidden() && klass->name() == name) {
this_class = klass;
} else {
this_class = SystemDictionary::resolve_or_fail(
name, Handle(THREAD, klass->class_loader()),
Handle(THREAD, klass->protection_domain()), true, CHECK_false);
if (log_is_enabled(Debug, class, resolve)) {
Verifier::trace_class_resolution(this_class, klass);
if (log_is_enabled(Debug, class, resolve)) {
Verifier::trace_class_resolution(this_class, klass);
}
}
if (this_class->is_interface() && (!from_field_is_protected ||
@ -65,11 +70,16 @@ bool VerificationType::resolve_and_check_assignability(InstanceKlass* klass, Sym
this_class == SystemDictionary::Cloneable_klass() ||
this_class == SystemDictionary::Serializable_klass();
} else if (from_is_object) {
Klass* from_class = SystemDictionary::resolve_or_fail(
Klass* from_class;
if (klass->is_hidden() && klass->name() == from_name) {
from_class = klass;
} else {
from_class = SystemDictionary::resolve_or_fail(
from_name, Handle(THREAD, klass->class_loader()),
Handle(THREAD, klass->protection_domain()), true, CHECK_false);
if (log_is_enabled(Debug, class, resolve)) {
Verifier::trace_class_resolution(from_class, klass);
if (log_is_enabled(Debug, class, resolve)) {
Verifier::trace_class_resolution(from_class, klass);
}
}
return from_class->is_subclass_of(this_class);
}

@ -2081,6 +2081,8 @@ Klass* ClassVerifier::load_class(Symbol* name, TRAPS) {
oop loader = current_class()->class_loader();
oop protection_domain = current_class()->protection_domain();
assert(name_in_supers(name, current_class()), "name should be a super class");
Klass* kls = SystemDictionary::resolve_or_fail(
name, Handle(THREAD, loader), Handle(THREAD, protection_domain),
true, THREAD);

@ -546,6 +546,7 @@ bool vmIntrinsics::is_disabled_by_flags(vmIntrinsics::ID id) {
case vmIntrinsics::_isInterface:
case vmIntrinsics::_isArray:
case vmIntrinsics::_isPrimitive:
case vmIntrinsics::_isHidden:
case vmIntrinsics::_getSuperclass:
case vmIntrinsics::_Class_cast:
case vmIntrinsics::_getLength:

@ -884,6 +884,8 @@
do_name( isArray_name, "isArray") \
do_intrinsic(_isPrimitive, java_lang_Class, isPrimitive_name, void_boolean_signature, F_RN) \
do_name( isPrimitive_name, "isPrimitive") \
do_intrinsic(_isHidden, java_lang_Class, isHidden_name, void_boolean_signature, F_RN) \
do_name( isHidden_name, "isHidden") \
do_intrinsic(_getSuperclass, java_lang_Class, getSuperclass_name, void_class_signature, F_RN) \
do_name( getSuperclass_name, "getSuperclass") \
do_intrinsic(_Class_cast, java_lang_Class, Class_cast_name, object_object_signature, F_R) \

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, 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
@ -388,6 +388,21 @@ JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader,
const jbyte *buf, jsize len, jobject pd,
const char *source);
/*
* Define a class with the specified lookup class.
* lookup: Lookup class
* name: the name of the class
* buf: class bytes
* len: length of class bytes
* pd: protection domain
* init: initialize the class
* flags: properties of the class
* classData: private static pre-initialized field; may be null
*/
JNIEXPORT jclass JNICALL
JVM_LookupDefineClass(JNIEnv *env, jclass lookup, const char *name, const jbyte *buf,
jsize len, jobject pd, jboolean init, int flags, jobject classData);
/*
* Module support funcions
*/
@ -473,6 +488,9 @@ JVM_IsArrayClass(JNIEnv *env, jclass cls);
JNIEXPORT jboolean JNICALL
JVM_IsPrimitiveClass(JNIEnv *env, jclass cls);
JNIEXPORT jboolean JNICALL
JVM_IsHiddenClass(JNIEnv *env, jclass cls);
JNIEXPORT jint JNICALL
JVM_GetClassModifiers(JNIEnv *env, jclass cls);

@ -535,6 +535,21 @@ Method* LinkResolver::lookup_polymorphic_method(const LinkInfo& link_info,
return NULL;
}
static void print_nest_host_error_on(stringStream* ss, Klass* ref_klass, Klass* sel_klass, TRAPS) {
assert(ref_klass->is_instance_klass(), "must be");
assert(sel_klass->is_instance_klass(), "must be");
InstanceKlass* ref_ik = InstanceKlass::cast(ref_klass);
InstanceKlass* sel_ik = InstanceKlass::cast(sel_klass);
const char* nest_host_error_1 = ref_ik->nest_host_error(THREAD);
const char* nest_host_error_2 = sel_ik->nest_host_error(THREAD);
if (nest_host_error_1 != NULL || nest_host_error_2 != NULL) {
ss->print(", (%s%s%s)",
(nest_host_error_1 != NULL) ? nest_host_error_1 : "",
(nest_host_error_1 != NULL && nest_host_error_2 != NULL) ? ", " : "",
(nest_host_error_2 != NULL) ? nest_host_error_2 : "");
}
}
void LinkResolver::check_method_accessability(Klass* ref_klass,
Klass* resolved_klass,
Klass* sel_klass,
@ -567,24 +582,34 @@ void LinkResolver::check_method_accessability(Klass* ref_klass,
sel_klass,
flags,
true, false, CHECK);
// Any existing exceptions that may have been thrown, for example LinkageErrors
// from nest-host resolution, have been allowed to propagate.
// Any existing exceptions that may have been thrown
// have been allowed to propagate.
if (!can_access) {
ResourceMark rm(THREAD);
stringStream ss;
bool same_module = (sel_klass->module() == ref_klass->module());
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IllegalAccessError(),
"class %s tried to access %s%s%smethod '%s' (%s%s%s)",
ref_klass->external_name(),
sel_method->is_abstract() ? "abstract " : "",
sel_method->is_protected() ? "protected " : "",
sel_method->is_private() ? "private " : "",
sel_method->external_name(),
(same_module) ? ref_klass->joint_in_module_of_loader(sel_klass) : ref_klass->class_in_module_of_loader(),
(same_module) ? "" : "; ",
(same_module) ? "" : sel_klass->class_in_module_of_loader()
);
ss.print("class %s tried to access %s%s%smethod '%s' (%s%s%s)",
ref_klass->external_name(),
sel_method->is_abstract() ? "abstract " : "",
sel_method->is_protected() ? "protected " : "",
sel_method->is_private() ? "private " : "",
sel_method->external_name(),
(same_module) ? ref_klass->joint_in_module_of_loader(sel_klass) : ref_klass->class_in_module_of_loader(),
(same_module) ? "" : "; ",
(same_module) ? "" : sel_klass->class_in_module_of_loader()
);
// For private access see if there was a problem with nest host
// resolution, and if so report that as part of the message.
if (sel_method->is_private()) {
print_nest_host_error_on(&ss, ref_klass, sel_klass, THREAD);
}
Exceptions::fthrow(THREAD_AND_LOCATION,
vmSymbols::java_lang_IllegalAccessError(),
"%s",
ss.as_string()
);
return;
}
}
@ -903,19 +928,27 @@ void LinkResolver::check_field_accessability(Klass* ref_klass,
if (!can_access) {
bool same_module = (sel_klass->module() == ref_klass->module());
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IllegalAccessError(),
"class %s tried to access %s%sfield %s.%s (%s%s%s)",
ref_klass->external_name(),
fd.is_protected() ? "protected " : "",
fd.is_private() ? "private " : "",
sel_klass->external_name(),
fd.name()->as_C_string(),
(same_module) ? ref_klass->joint_in_module_of_loader(sel_klass) : ref_klass->class_in_module_of_loader(),
(same_module) ? "" : "; ",
(same_module) ? "" : sel_klass->class_in_module_of_loader()
);
stringStream ss;
ss.print("class %s tried to access %s%sfield %s.%s (%s%s%s)",
ref_klass->external_name(),
fd.is_protected() ? "protected " : "",
fd.is_private() ? "private " : "",
sel_klass->external_name(),
fd.name()->as_C_string(),
(same_module) ? ref_klass->joint_in_module_of_loader(sel_klass) : ref_klass->class_in_module_of_loader(),
(same_module) ? "" : "; ",
(same_module) ? "" : sel_klass->class_in_module_of_loader()
);
// For private access see if there was a problem with nest host
// resolution, and if so report that as part of the message.
if (fd.is_private()) {
print_nest_host_error_on(&ss, ref_klass, sel_klass, THREAD);
}
Exceptions::fthrow(THREAD_AND_LOCATION,
vmSymbols::java_lang_IllegalAccessError(),
"%s",
ss.as_string()
);
return;
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, 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
@ -1460,12 +1460,11 @@ static InstanceKlass* create_new_instance_klass(InstanceKlass* ik, ClassFileStre
Handle pd(THREAD, ik->protection_domain());
Symbol* const class_name = ik->name();
const char* const klass_name = class_name != NULL ? class_name->as_C_string() : "";
ClassLoadInfo cl_info(pd);
ClassFileParser new_parser(stream,
class_name,
cld,
pd,
NULL, // host klass
NULL, // cp_patches
&cl_info,
ClassFileParser::INTERNAL, // internal visibility
THREAD);
if (HAS_PENDING_EXCEPTION) {
@ -1473,7 +1472,8 @@ static InstanceKlass* create_new_instance_klass(InstanceKlass* ik, ClassFileStre
CLEAR_PENDING_EXCEPTION;
return NULL;
}
InstanceKlass* const new_ik = new_parser.create_instance_klass(false, THREAD);
const ClassInstanceInfo* cl_inst_info = cl_info.class_hidden_info_ptr();
InstanceKlass* const new_ik = new_parser.create_instance_klass(false, *cl_inst_info, THREAD);
if (HAS_PENDING_EXCEPTION) {
log_pending_exception(PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, 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
@ -162,10 +162,9 @@ void ObjectSampleDescription::write_class_name() {
if (k->is_instance_klass()) {
const InstanceKlass* ik = InstanceKlass::cast(k);
if (ik->is_unsafe_anonymous()) {
if (ik->is_unsafe_anonymous() || ik->is_hidden()) {
return;
}
assert(!ik->is_unsafe_anonymous(), "invariant");
const Symbol* name = ik->name();
if (name != NULL) {
write_text("Class Name: ");

@ -219,6 +219,7 @@
stackTrace="true">
<Field type="ClassLoader" name="classLoader" label="Class Loader" />
<Field type="boolean" name="unsafeAnonymousClassLoader" label="Unsafe Anonymous Class Loader" />
<Field type="boolean" name="hiddenClassLoader" label="Hidden Class Loader" />
<Field type="ulong" contentType="bytes" name="size" label="Size" />
<Field type="MetadataType" name="metadataType" label="Metadata Type" />
<Field type="MetaspaceObjectType" name="metaspaceObjectType" label="Metaspace Object Type" />
@ -227,6 +228,7 @@
<Event name="MetaspaceOOM" category="Java Virtual Machine, GC, Metaspace" label="Metaspace Out of Memory" startTime="false" stackTrace="true">
<Field type="ClassLoader" name="classLoader" label="Class Loader" />
<Field type="boolean" name="unsafeAnonymousClassLoader" label="Unsafe Anonymous Class Loader" />
<Field type="boolean" name="hiddenClassLoader" label="Hidden Class Loader" />
<Field type="ulong" contentType="bytes" name="size" label="Size" />
<Field type="MetadataType" name="metadataType" label="Metadata Type" />
<Field type="MetaspaceObjectType" name="metaspaceObjectType" label="Metaspace Object Type" />
@ -729,6 +731,11 @@
description="Total size of all allocated metaspace chunks for unsafe anonymous classes (each chunk has several blocks)" />
<Field type="ulong" contentType="bytes" name="unsafeAnonymousBlockSize" label="Total Unsafe Anonymous Classes Block Size"
description="Total size of all allocated metaspace blocks for unsafe anonymous classes (each chunk has several blocks)" />
<Field type="long" name="hiddenClassCount" label="Hidden Classes" description="Number of hidden classes" />
<Field type="ulong" contentType="bytes" name="hiddenChunkSize" label="Total Hidden Classes Chunk Size"
description="Total size of all allocated metaspace chunks for hidden classes (each chunk has several blocks)" />
<Field type="ulong" contentType="bytes" name="hiddenBlockSize" label="Total Hidden Classes Block Size"
description="Total size of all allocated metaspace blocks for hidden classes (each chunk has several blocks)" />
</Event>
<Event name="SymbolTableStatistics" category="Java Virtual Machine, Runtime, Tables" label="Symbol Table Statistics" period="everyChunk">
@ -1135,6 +1142,7 @@
<Field type="Symbol" name="name" label="Name" />
<Field type="Package" name="package" label="Package" />
<Field type="int" name="modifiers" label="Access Modifiers" />
<Field type="boolean" name="hidden" label="Hidden" />
</Type>
<Type name="ClassLoader" label="Java Class Loader">

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2020, 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
@ -483,6 +483,9 @@ public:
event.set_unsafeAnonymousClassCount(cls->_anon_classes_count);
event.set_unsafeAnonymousChunkSize(cls->_anon_chunk_sz);
event.set_unsafeAnonymousBlockSize(cls->_anon_block_sz);
event.set_hiddenClassCount(cls->_hidden_classes_count);
event.set_hiddenChunkSize(cls->_hidden_chunk_sz);
event.set_hiddenBlockSize(cls->_hidden_block_sz);
event.commit();
return true;
}

@ -137,7 +137,6 @@ static traceid method_id(KlassPtr klass, MethodPtr method) {
static traceid cld_id(CldPtr cld, bool leakp) {
assert(cld != NULL, "invariant");
assert(!cld->is_unsafe_anonymous(), "invariant");
if (leakp) {
SET_LEAKP(cld);
} else {
@ -163,6 +162,7 @@ static ClassLoaderData* get_cld(const Klass* klass) {
if (klass->is_objArray_klass()) {
klass = ObjArrayKlass::cast(klass)->bottom_klass();
}
if (klass->is_non_strong_hidden()) return NULL;
return is_unsafe_anonymous(klass) ?
InstanceKlass::cast(klass)->unsafe_anonymous_host()->class_loader_data() : klass->class_loader_data();
}
@ -188,10 +188,12 @@ static int write_klass(JfrCheckpointWriter* writer, KlassPtr klass, bool leakp)
assert(_artifacts != NULL, "invariant");
assert(klass != NULL, "invariant");
writer->write(artifact_id(klass));
writer->write(cld_id(get_cld(klass), leakp));
ClassLoaderData* cld = get_cld(klass);
writer->write(cld != NULL ? cld_id(cld, leakp) : 0);
writer->write(mark_symbol(klass, leakp));
writer->write(package_id(klass, leakp));
writer->write(get_flags(klass));
writer->write<bool>(klass->is_hidden());
return 1;
}
@ -546,7 +548,6 @@ static void clear_modules() {
static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp) {
assert(cld != NULL, "invariant");
assert(!cld->is_unsafe_anonymous(), "invariant");
// class loader type
const Klass* class_loader_klass = cld->class_loader_klass();
if (class_loader_klass == NULL) {
@ -604,7 +605,7 @@ class CLDCallback : public CLDClosure {
CLDCallback() {}
void do_cld(ClassLoaderData* cld) {
assert(cld != NULL, "invariant");
if (cld->is_unsafe_anonymous()) {
if (cld->has_class_mirror_holder()) {
return;
}
do_class_loader_data(cld);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, 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
@ -189,52 +189,54 @@ traceid JfrSymbolId::mark(uintptr_t hash, const char* str, bool leakp) {
* caller needs ResourceMark
*/
uintptr_t JfrSymbolId::unsafe_anonymous_klass_name_hash(const InstanceKlass* ik) {
uintptr_t JfrSymbolId::hidden_or_anon_klass_name_hash(const InstanceKlass* ik) {
assert(ik != NULL, "invariant");
assert(ik->is_unsafe_anonymous(), "invariant");
assert(ik->is_unsafe_anonymous() || ik->is_hidden(), "invariant");
const oop mirror = ik->java_mirror_no_keepalive();
assert(mirror != NULL, "invariant");
return (uintptr_t)mirror->identity_hash();
}
static const char* create_unsafe_anonymous_klass_symbol(const InstanceKlass* ik, uintptr_t hash) {
static const char* create_hidden_or_anon_klass_symbol(const InstanceKlass* ik, uintptr_t hash) {
assert(ik != NULL, "invariant");
assert(ik->is_unsafe_anonymous(), "invariant");
assert(ik->is_unsafe_anonymous() || ik->is_hidden(), "invariant");
assert(hash != 0, "invariant");
char* anonymous_symbol = NULL;
char* hidden_or_anon_symbol = NULL;
const oop mirror = ik->java_mirror_no_keepalive();
assert(mirror != NULL, "invariant");
char hash_buf[40];
sprintf(hash_buf, "/" UINTX_FORMAT, hash);
const size_t hash_len = strlen(hash_buf);
const size_t result_len = ik->name()->utf8_length();
anonymous_symbol = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1);
ik->name()->as_klass_external_name(anonymous_symbol, (int)result_len + 1);
assert(strlen(anonymous_symbol) == result_len, "invariant");
strcpy(anonymous_symbol + result_len, hash_buf);
assert(strlen(anonymous_symbol) == result_len + hash_len, "invariant");
return anonymous_symbol;
hidden_or_anon_symbol = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1);
ik->name()->as_klass_external_name(hidden_or_anon_symbol, (int)result_len + 1);
assert(strlen(hidden_or_anon_symbol) == result_len, "invariant");
strcpy(hidden_or_anon_symbol + result_len, hash_buf);
assert(strlen(hidden_or_anon_symbol) == result_len + hash_len, "invariant");
return hidden_or_anon_symbol;
}
bool JfrSymbolId::is_unsafe_anonymous_klass(const Klass* k) {
bool JfrSymbolId::is_hidden_or_anon_klass(const Klass* k) {
assert(k != NULL, "invariant");
return k->is_instance_klass() && ((const InstanceKlass*)k)->is_unsafe_anonymous();
return k->is_instance_klass() &&
(((const InstanceKlass*)k)->is_unsafe_anonymous() ||
((const InstanceKlass*)k)->is_hidden());
}
traceid JfrSymbolId::mark_unsafe_anonymous_klass_name(const InstanceKlass* ik, bool leakp) {
traceid JfrSymbolId::mark_hidden_or_anon_klass_name(const InstanceKlass* ik, bool leakp) {
assert(ik != NULL, "invariant");
assert(ik->is_unsafe_anonymous(), "invariant");
const uintptr_t hash = unsafe_anonymous_klass_name_hash(ik);
const char* const anonymous_klass_symbol = create_unsafe_anonymous_klass_symbol(ik, hash);
return mark(hash, anonymous_klass_symbol, leakp);
assert(ik->is_unsafe_anonymous() || ik->is_hidden(), "invariant");
const uintptr_t hash = hidden_or_anon_klass_name_hash(ik);
const char* const hidden_or_anon_symbol = create_hidden_or_anon_klass_symbol(ik, hash);
return mark(hash, hidden_or_anon_symbol, leakp);
}
traceid JfrSymbolId::mark(const Klass* k, bool leakp) {
assert(k != NULL, "invariant");
traceid symbol_id = 0;
if (is_unsafe_anonymous_klass(k)) {
if (is_hidden_or_anon_klass(k)) {
assert(k->is_instance_klass(), "invariant");
symbol_id = mark_unsafe_anonymous_klass_name((const InstanceKlass*)k, leakp);
symbol_id = mark_hidden_or_anon_klass_name((const InstanceKlass*)k, leakp);
}
if (0 == symbol_id) {
Symbol* const sym = k->name();
@ -276,9 +278,9 @@ traceid JfrArtifactSet::bootstrap_name(bool leakp) {
return _symbol_id->bootstrap_name(leakp);
}
traceid JfrArtifactSet::mark_unsafe_anonymous_klass_name(const Klass* klass, bool leakp) {
traceid JfrArtifactSet::mark_hidden_or_anon_klass_name(const Klass* klass, bool leakp) {
assert(klass->is_instance_klass(), "invariant");
return _symbol_id->mark_unsafe_anonymous_klass_name((const InstanceKlass*)klass, leakp);
return _symbol_id->mark_hidden_or_anon_klass_name((const InstanceKlass*)klass, leakp);
}
traceid JfrArtifactSet::mark(uintptr_t hash, const Symbol* sym, bool leakp) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, 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
@ -241,9 +241,9 @@ class JfrSymbolId : public JfrCHeapObj {
}
}
traceid mark_unsafe_anonymous_klass_name(const InstanceKlass* k, bool leakp);
bool is_unsafe_anonymous_klass(const Klass* k);
uintptr_t unsafe_anonymous_klass_name_hash(const InstanceKlass* ik);
traceid mark_hidden_or_anon_klass_name(const InstanceKlass* k, bool leakp);
bool is_hidden_or_anon_klass(const Klass* k);
uintptr_t hidden_or_anon_klass_name_hash(const InstanceKlass* ik);
public:
JfrSymbolId();
@ -304,7 +304,7 @@ class JfrArtifactSet : public JfrCHeapObj {
traceid mark(const Klass* klass, bool leakp);
traceid mark(const Symbol* symbol, bool leakp);
traceid mark(uintptr_t hash, const char* const str, bool leakp);
traceid mark_unsafe_anonymous_klass_name(const Klass* klass, bool leakp);
traceid mark_hidden_or_anon_klass_name(const Klass* klass, bool leakp);
traceid bootstrap_name(bool leakp);
const JfrSymbolId::SymbolEntry* map_symbol(const Symbol* symbol) const;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2020, 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
@ -140,7 +140,7 @@ void JfrTraceId::assign(const PackageEntry* package) {
void JfrTraceId::assign(const ClassLoaderData* cld) {
assert(cld != NULL, "invariant");
if (cld->is_unsafe_anonymous()) {
if (cld->has_class_mirror_holder()) {
cld->set_trace_id(0);
return;
}

@ -114,7 +114,7 @@ inline traceid JfrTraceId::use(const PackageEntry* package) {
inline traceid JfrTraceId::use(const ClassLoaderData* cld) {
assert(cld != NULL, "invariant");
return cld->is_unsafe_anonymous() ? 0 : set_used_and_get(cld);
return cld->has_class_mirror_holder() ? 0 : set_used_and_get(cld);
}
inline void JfrTraceId::set_leakp(const Klass* klass, const Method* method) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2020, 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
@ -64,7 +64,7 @@ static const char* space_type_name(Metaspace::MetaspaceType t) {
switch (t) {
case Metaspace::StandardMetaspaceType: s = "Standard"; break;
case Metaspace::BootMetaspaceType: s = "Boot"; break;
case Metaspace::UnsafeAnonymousMetaspaceType: s = "UnsafeAnonymous"; break;
case Metaspace::ClassMirrorHolderMetaspaceType: s = "ClassMirrorHolder"; break;
case Metaspace::ReflectionMetaspaceType: s = "Reflection"; break;
default: ShouldNotReachHere();
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2020, 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
@ -104,8 +104,8 @@ class Metaspace : public AllStatic {
ZeroMetaspaceType = 0,
StandardMetaspaceType = ZeroMetaspaceType,
BootMetaspaceType = StandardMetaspaceType + 1,
UnsafeAnonymousMetaspaceType = BootMetaspaceType + 1,
ReflectionMetaspaceType = UnsafeAnonymousMetaspaceType + 1,
ClassMirrorHolderMetaspaceType = BootMetaspaceType + 1,
ReflectionMetaspaceType = ClassMirrorHolderMetaspaceType + 1,
MetaspaceTypeCount
};
@ -254,7 +254,7 @@ class ClassLoaderMetaspace : public CHeapObj<mtClass> {
// Initialize the first chunk for a Metaspace. Used for
// special cases such as the boot class loader, reflection
// class loader and anonymous class loader.
// class loader and hidden class loader.
void initialize_first_chunk(Metaspace::MetaspaceType type, Metaspace::MetadataType mdtype);
metaspace::Metachunk* get_initialization_chunk(Metaspace::MetaspaceType type, Metaspace::MetadataType mdtype);
@ -399,7 +399,7 @@ public:
rf_show_loaders = (1 << 0),
// Breaks report down by chunk type (small, medium, ...).
rf_break_down_by_chunktype = (1 << 1),
// Breaks report down by space type (anonymous, reflection, ...).
// Breaks report down by space type (hidden, reflection, ...).
rf_break_down_by_spacetype = (1 << 2),
// Print details about the underlying virtual spaces.
rf_show_vslist = (1 << 3),

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, 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
@ -104,7 +104,7 @@ void PrintCLDMetaspaceInfoClosure::do_cld(ClassLoaderData* cld) {
_out->print(UINTX_FORMAT_W(4) ": ", _num_loaders);
// Print "CLD for [<loader name>,] instance of <loader class name>"
// or "CLD for <anonymous class>, loaded by [<loader name>,] instance of <loader class name>"
// or "CLD for <hidden or anonymous class>, loaded by [<loader name>,] instance of <loader class name>"
ResourceMark rm;
const char* name = NULL;
@ -128,8 +128,8 @@ void PrintCLDMetaspaceInfoClosure::do_cld(ClassLoaderData* cld) {
_out->print(" (unloading)");
}
_out->print(":");
if (cld->is_unsafe_anonymous()) {
_out->print(" <anonymous class>, loaded by");
if (cld->has_class_mirror_holder()) {
_out->print(" <hidden or anonymous class>, loaded by");
}
if (name != NULL) {
_out->print(" \"%s\"", name);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, 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
@ -75,14 +75,14 @@ size_t SpaceManager::get_initial_chunk_size(Metaspace::MetaspaceType type) const
if (is_class()) {
switch (type) {
case Metaspace::BootMetaspaceType: requested = Metaspace::first_class_chunk_word_size(); break;
case Metaspace::UnsafeAnonymousMetaspaceType: requested = ClassSpecializedChunk; break;
case Metaspace::ClassMirrorHolderMetaspaceType: requested = ClassSpecializedChunk; break;
case Metaspace::ReflectionMetaspaceType: requested = ClassSpecializedChunk; break;
default: requested = ClassSmallChunk; break;
}
} else {
switch (type) {
case Metaspace::BootMetaspaceType: requested = Metaspace::first_chunk_word_size(); break;
case Metaspace::UnsafeAnonymousMetaspaceType: requested = SpecializedChunk; break;
case Metaspace::ClassMirrorHolderMetaspaceType: requested = SpecializedChunk; break;
case Metaspace::ReflectionMetaspaceType: requested = SpecializedChunk; break;
default: requested = SmallChunk; break;
}
@ -114,15 +114,15 @@ size_t SpaceManager::calc_chunk_size(size_t word_size) {
// After that a medium chunk is preferred.
size_t chunk_word_size;
// Special case for unsafe anonymous metadata space.
// UnsafeAnonymous metadata space is usually small since it is used for
// class loader data's whose life cycle is governed by one class such as an
// unsafe anonymous class. The majority within 1K - 2K range and
// Special case for hidden metadata space.
// ClassMirrorHolder metadata space is usually small since it is used for
// class loader data's whose life cycle is governed by one class such as a
// non-strong hidden class or unsafe anonymous class. The majority within 1K - 2K range and
// rarely about 4K (64-bits JVM).
// Instead of jumping to SmallChunk after initial chunk exhausted, keeping allocation
// from SpecializeChunk up to _anon_or_delegating_metadata_specialize_chunk_limit (4)
// reduces space waste from 60+% to around 30%.
if ((_space_type == Metaspace::UnsafeAnonymousMetaspaceType || _space_type == Metaspace::ReflectionMetaspaceType) &&
if ((_space_type == Metaspace::ClassMirrorHolderMetaspaceType || _space_type == Metaspace::ReflectionMetaspaceType) &&
_mdtype == Metaspace::NonClassType &&
num_chunks_by_type(SpecializedIndex) < anon_and_delegating_metadata_specialize_chunk_limit &&
word_size + Metachunk::overhead() <= SpecializedChunk) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, 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
@ -62,10 +62,15 @@ void MetaspaceTracer::send_allocation_failure_event(ClassLoaderData *cld,
E event;
if (event.should_commit()) {
event.set_classLoader(cld);
if (cld->is_unsafe_anonymous()) {
event.set_unsafeAnonymousClassLoader(true);
} else {
event.set_unsafeAnonymousClassLoader(false);
event.set_unsafeAnonymousClassLoader(false); // initialize these
event.set_hiddenClassLoader(false);
if (cld->has_class_mirror_holder()) {
assert(cld->klasses() != NULL, "unexpected NULL for cld->klasses()");
if (cld->klasses()->is_non_strong_hidden()) {
event.set_hiddenClassLoader(true);
} else {
event.set_unsafeAnonymousClassLoader(true);
}
}
event.set_size(word_size * BytesPerWord);
event.set_metadataType((u1) mdtype);

@ -110,7 +110,7 @@ void ArrayKlass::complete_create_array_klass(ArrayKlass* k, Klass* super_klass,
assert((module_entry != NULL) || ((module_entry == NULL) && !ModuleEntryTable::javabase_defined()),
"module entry not available post " JAVA_BASE_NAME " definition");
oop module = (module_entry != NULL) ? module_entry->module() : (oop)NULL;
java_lang_Class::create_mirror(k, Handle(THREAD, k->class_loader()), Handle(THREAD, module), Handle(), CHECK);
java_lang_Class::create_mirror(k, Handle(THREAD, k->class_loader()), Handle(THREAD, module), Handle(), Handle(), CHECK);
}
GrowableArray<Klass*>* ArrayKlass::compute_secondary_supers(int num_extra_slots,

@ -31,6 +31,7 @@
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/resolutionErrors.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp"
@ -134,6 +135,7 @@
#endif // ndef DTRACE_ENABLED
static inline bool is_class_loader(const Symbol* class_name,
const ClassFileParser& parser) {
assert(class_name != NULL, "invariant");
@ -153,8 +155,11 @@ static inline bool is_class_loader(const Symbol* class_name,
return false;
}
// called to verify that k is a member of this nest
// private: called to verify that k is a static member of this nest.
// We know that k is an instance class in the same package and hence the
// same classloader.
bool InstanceKlass::has_nest_member(InstanceKlass* k, TRAPS) const {
assert(!is_hidden(), "unexpected hidden class");
if (_nest_members == NULL || _nest_members == Universe::the_empty_short_array()) {
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
@ -175,7 +180,9 @@ bool InstanceKlass::has_nest_member(InstanceKlass* k, TRAPS) const {
for (int i = 0; i < _nest_members->length(); i++) {
int cp_index = _nest_members->at(i);
if (_constants->tag_at(cp_index).is_klass()) {
Klass* k2 = _constants->klass_at(cp_index, CHECK_false);
Klass* k2 = _constants->klass_at(cp_index, THREAD);
assert(!HAS_PENDING_EXCEPTION || PENDING_EXCEPTION->is_a(SystemDictionary::VirtualMachineError_klass()),
"Exceptions should not be possible here");
if (k2 == k) {
log_trace(class, nestmates)("- class is listed at nest_members[%d] => cp[%d]", i, cp_index);
return true;
@ -186,15 +193,14 @@ bool InstanceKlass::has_nest_member(InstanceKlass* k, TRAPS) const {
if (name == k->name()) {
log_trace(class, nestmates)("- Found it at nest_members[%d] => cp[%d]", i, cp_index);
// Names match so check actual klass - this may trigger class loading if
// it doesn't match (though that should be impossible). But to be safe we
// have to check for a compiler thread executing here.
if (!THREAD->can_call_java() && !_constants->tag_at(cp_index).is_klass()) {
log_trace(class, nestmates)("- validation required resolution in an unsuitable thread");
return false;
}
Klass* k2 = _constants->klass_at(cp_index, CHECK_false);
// Names match so check actual klass. This may trigger class loading if
// it doesn't match though that should be impossible as it means one classloader
// has defined two different classes with the same name! A compiler thread won't be
// able to perform that loading but we can't exclude the compiler threads from
// executing this logic. But it should actually be impossible to trigger loading here.
Klass* k2 = _constants->klass_at(cp_index, THREAD);
assert(!HAS_PENDING_EXCEPTION || PENDING_EXCEPTION->is_a(SystemDictionary::VirtualMachineError_klass()),
"Exceptions should not be possible here");
if (k2 == k) {
log_trace(class, nestmates)("- class is listed as a nest member");
return true;
@ -213,167 +219,210 @@ bool InstanceKlass::has_nest_member(InstanceKlass* k, TRAPS) const {
}
// Return nest-host class, resolving, validating and saving it if needed.
// In cases where this is called from a thread that can not do classloading
// In cases where this is called from a thread that cannot do classloading
// (such as a native JIT thread) then we simply return NULL, which in turn
// causes the access check to return false. Such code will retry the access
// from a more suitable environment later.
InstanceKlass* InstanceKlass::nest_host(Symbol* validationException, TRAPS) {
// from a more suitable environment later. Otherwise the _nest_host is always
// set once this method returns.
// Any errors from nest-host resolution must be preserved so they can be queried
// from higher-level access checking code, and reported as part of access checking
// exceptions.
// VirtualMachineErrors are propagated with a NULL return.
// Under any conditions where the _nest_host can be set to non-NULL the resulting
// value of it and, if applicable, the nest host resolution/validation error,
// are idempotent.
InstanceKlass* InstanceKlass::nest_host(TRAPS) {
InstanceKlass* nest_host_k = _nest_host;
if (nest_host_k == NULL) {
// need to resolve and save our nest-host class. This could be attempted
// concurrently but as the result is idempotent and we don't use the class
// then we do not need any synchronization beyond what is implicitly used
// during class loading.
if (_nest_host_index != 0) { // we have a real nest_host
// Before trying to resolve check if we're in a suitable context
if (!THREAD->can_call_java() && !_constants->tag_at(_nest_host_index).is_klass()) {
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
log_trace(class, nestmates)("Rejected resolution of nest-host of %s in unsuitable thread",
this->external_name());
}
return NULL;
}
if (nest_host_k != NULL) {
return nest_host_k;
}
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
log_trace(class, nestmates)("Resolving nest-host of %s using cp entry for %s",
this->external_name(),
_constants->klass_name_at(_nest_host_index)->as_C_string());
}
ResourceMark rm(THREAD);
Klass* k = _constants->klass_at(_nest_host_index, THREAD);
if (HAS_PENDING_EXCEPTION) {
Handle exc_h = Handle(THREAD, PENDING_EXCEPTION);
if (exc_h->is_a(SystemDictionary::NoClassDefFoundError_klass())) {
// throw a new CDNFE with the original as its cause, and a clear msg
ResourceMark rm(THREAD);
char buf[200];
CLEAR_PENDING_EXCEPTION;
jio_snprintf(buf, sizeof(buf),
"Unable to load nest-host class (%s) of %s",
_constants->klass_name_at(_nest_host_index)->as_C_string(),
this->external_name());
log_trace(class, nestmates)("%s - NoClassDefFoundError", buf);
THROW_MSG_CAUSE_NULL(vmSymbols::java_lang_NoClassDefFoundError(), buf, exc_h);
}
// All other exceptions pass through (OOME, StackOverflowError, LinkageErrors etc).
return NULL;
}
// need to resolve and save our nest-host class.
if (_nest_host_index != 0) { // we have a real nest_host
// Before trying to resolve check if we're in a suitable context
if (!THREAD->can_call_java() && !_constants->tag_at(_nest_host_index).is_klass()) {
log_trace(class, nestmates)("Rejected resolution of nest-host of %s in unsuitable thread",
this->external_name());
return NULL; // sentinel to say "try again from a different context"
}
log_trace(class, nestmates)("Resolving nest-host of %s using cp entry for %s",
this->external_name(),
_constants->klass_name_at(_nest_host_index)->as_C_string());
Klass* k = _constants->klass_at(_nest_host_index, THREAD);
if (HAS_PENDING_EXCEPTION) {
if (PENDING_EXCEPTION->is_a(SystemDictionary::VirtualMachineError_klass())) {
return NULL; // propagate VMEs
}
stringStream ss;
char* target_host_class = _constants->klass_name_at(_nest_host_index)->as_C_string();
ss.print("Nest host resolution of %s with host %s failed: ",
this->external_name(), target_host_class);
java_lang_Throwable::print(PENDING_EXCEPTION, &ss);
const char* msg = ss.as_string(true /* on C-heap */);
constantPoolHandle cph(THREAD, constants());
SystemDictionary::add_nest_host_error(cph, _nest_host_index, msg);
CLEAR_PENDING_EXCEPTION;
log_trace(class, nestmates)("%s", msg);
} else {
// A valid nest-host is an instance class in the current package that lists this
// class as a nest member. If any of these conditions are not met we post the
// requested exception type (if any) and return NULL
// class as a nest member. If any of these conditions are not met the class is
// its own nest-host.
const char* error = NULL;
// JVMS 5.4.4 indicates package check comes first
if (is_same_class_package(k)) {
// Now check actual membership. We can't be a member if our "host" is
// not an instance class.
if (k->is_instance_klass()) {
nest_host_k = InstanceKlass::cast(k);
bool is_member = nest_host_k->has_nest_member(this, THREAD);
// exception is rare, perhaps impossible
if (!HAS_PENDING_EXCEPTION) {
if (is_member) {
_nest_host = nest_host_k; // save resolved nest-host value
bool is_member = nest_host_k->has_nest_member(this, CHECK_NULL);
if (is_member) {
// save resolved nest-host value
_nest_host = nest_host_k;
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
log_trace(class, nestmates)("Resolved nest-host of %s to %s",
this->external_name(), k->external_name());
return nest_host_k;
} else {
error = "current type is not listed as a nest member";
}
return nest_host_k;
} else {
if (PENDING_EXCEPTION->is_a(SystemDictionary::VirtualMachineError_klass())) {
return NULL; // propagate VMEs
}
stringStream ss;
ss.print("exception on member check: ");
java_lang_Throwable::print(PENDING_EXCEPTION, &ss);
error = ss.as_string();
}
} else {
error = "host is not an instance class";
}
error = "current type is not listed as a nest member";
} else {
error = "types are in different packages";
}
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
log_trace(class, nestmates)
("Type %s (loader: %s) is not a nest member of "
"resolved type %s (loader: %s): %s",
this->external_name(),
this->class_loader_data()->loader_name_and_id(),
k->external_name(),
k->class_loader_data()->loader_name_and_id(),
error);
// something went wrong, so record what and log it
{
stringStream ss;
ss.print("Type %s (loader: %s) is not a nest member of type %s (loader: %s): %s",
this->external_name(),
this->class_loader_data()->loader_name_and_id(),
k->external_name(),
k->class_loader_data()->loader_name_and_id(),
error);
const char* msg = ss.as_string(true /* on C-heap */);
constantPoolHandle cph(THREAD, constants());
SystemDictionary::add_nest_host_error(cph, _nest_host_index, msg);
log_trace(class, nestmates)("%s", msg);
}
if (validationException != NULL && THREAD->can_call_java()) {
ResourceMark rm(THREAD);
Exceptions::fthrow(THREAD_AND_LOCATION,
validationException,
"Type %s (loader: %s) is not a nest member of %s (loader: %s): %s",
this->external_name(),
this->class_loader_data()->loader_name_and_id(),
k->external_name(),
k->class_loader_data()->loader_name_and_id(),
error
);
}
return NULL;
} else {
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
log_trace(class, nestmates)("Type %s is not part of a nest: setting nest-host to self",
this->external_name());
}
// save resolved nest-host value
return (_nest_host = this);
}
} else {
log_trace(class, nestmates)("Type %s is not part of a nest: setting nest-host to self",
this->external_name());
}
return nest_host_k;
// Either not in an explicit nest, or else an error occurred, so
// the nest-host is set to `this`. Any thread that sees this assignment
// will also see any setting of nest_host_error(), if applicable.
return (_nest_host = this);
}
// Dynamic nest member support: set this class's nest host to the given class.
// This occurs as part of the class definition, as soon as the instanceKlass
// has been created and doesn't require further resolution. The code:
// lookup().defineHiddenClass(bytes_for_X, NESTMATE);
// results in:
// class_of_X.set_nest_host(lookup().lookupClass().getNestHost())
// If it has an explicit _nest_host_index or _nest_members, these will be ignored.
// We also know the "host" is a valid nest-host in the same package so we can
// assert some of those facts.
void InstanceKlass::set_nest_host(InstanceKlass* host, TRAPS) {
assert(is_hidden(), "must be a hidden class");
assert(host != NULL, "NULL nest host specified");
assert(_nest_host == NULL, "current class has resolved nest-host");
assert(nest_host_error(THREAD) == NULL, "unexpected nest host resolution error exists: %s",
nest_host_error(THREAD));
assert((host->_nest_host == NULL && host->_nest_host_index == 0) ||
(host->_nest_host == host), "proposed host is not a valid nest-host");
// Can't assert this as package is not set yet:
// assert(is_same_class_package(host), "proposed host is in wrong package");
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
const char* msg = "";
// a hidden class does not expect a statically defined nest-host
if (_nest_host_index > 0) {
msg = "(the NestHost attribute in the current class is ignored)";
} else if (_nest_members != NULL && _nest_members != Universe::the_empty_short_array()) {
msg = "(the NestMembers attribute in the current class is ignored)";
}
log_trace(class, nestmates)("Injected type %s into the nest of %s %s",
this->external_name(),
host->external_name(),
msg);
}
// set dynamic nest host
_nest_host = host;
// Record dependency to keep nest host from being unloaded before this class.
ClassLoaderData* this_key = class_loader_data();
this_key->record_dependency(host);
}
// check if 'this' and k are nestmates (same nest_host), or k is our nest_host,
// or we are k's nest_host - all of which is covered by comparing the two
// resolved_nest_hosts
// resolved_nest_hosts.
// Any exceptions (i.e. VMEs) are propagated.
bool InstanceKlass::has_nestmate_access_to(InstanceKlass* k, TRAPS) {
assert(this != k, "this should be handled by higher-level code");
// Per JVMS 5.4.4 we first resolve and validate the current class, then
// the target class k. Resolution exceptions will be passed on by upper
// layers. IncompatibleClassChangeErrors from membership validation failures
// will also be passed through.
// the target class k.
Symbol* icce = vmSymbols::java_lang_IncompatibleClassChangeError();
InstanceKlass* cur_host = nest_host(icce, CHECK_false);
InstanceKlass* cur_host = nest_host(CHECK_false);
if (cur_host == NULL) {
return false;
}
Klass* k_nest_host = k->nest_host(icce, CHECK_false);
Klass* k_nest_host = k->nest_host(CHECK_false);
if (k_nest_host == NULL) {
return false;
}
bool access = (cur_host == k_nest_host);
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
log_trace(class, nestmates)("Class %s does %shave nestmate access to %s",
this->external_name(),
access ? "" : "NOT ",
k->external_name());
}
ResourceMark rm(THREAD);
log_trace(class, nestmates)("Class %s does %shave nestmate access to %s",
this->external_name(),
access ? "" : "NOT ",
k->external_name());
return access;
}
const char* InstanceKlass::nest_host_error(TRAPS) {
if (_nest_host_index == 0) {
return NULL;
} else {
constantPoolHandle cph(THREAD, constants());
return SystemDictionary::find_nest_host_error(cph, (int)_nest_host_index);
}
}
InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& parser, TRAPS) {
bool is_hidden_or_anonymous = parser.is_hidden() || parser.is_unsafe_anonymous();
const int size = InstanceKlass::size(parser.vtable_size(),
parser.itable_size(),
nonstatic_oop_map_size(parser.total_oop_map_count()),
parser.is_interface(),
parser.is_unsafe_anonymous(),
should_store_fingerprint(parser.is_unsafe_anonymous()));
should_store_fingerprint(is_hidden_or_anonymous));
const Symbol* const class_name = parser.class_name();
assert(class_name != NULL, "invariant");
@ -447,6 +496,7 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, unsigned kind, Klass
set_vtable_length(parser.vtable_size());
set_kind(kind);
set_access_flags(parser.access_flags());
if (parser.is_hidden()) set_is_hidden();
set_is_unsafe_anonymous(parser.is_unsafe_anonymous());
set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
false));
@ -2276,7 +2326,7 @@ bool InstanceKlass::supers_have_passed_fingerprint_checks() {
return true;
}
bool InstanceKlass::should_store_fingerprint(bool is_unsafe_anonymous) {
bool InstanceKlass::should_store_fingerprint(bool is_hidden_or_anonymous) {
#if INCLUDE_AOT
// We store the fingerprint into the InstanceKlass only in the following 2 cases:
if (CalculateClassFingerprint) {
@ -2287,8 +2337,8 @@ bool InstanceKlass::should_store_fingerprint(bool is_unsafe_anonymous) {
// (2) We are running -Xshare:dump or -XX:ArchiveClassesAtExit to create a shared archive
return true;
}
if (UseAOT && is_unsafe_anonymous) {
// (3) We are using AOT code from a shared library and see an unsafe anonymous class
if (UseAOT && is_hidden_or_anonymous) {
// (3) We are using AOT code from a shared library and see a hidden or unsafe anonymous class
return true;
}
#endif
@ -2581,6 +2631,7 @@ void InstanceKlass::release_C_heap_structures() {
// Decrement symbol reference counts associated with the unloaded class.
if (_name != NULL) _name->decrement_refcount();
// unreference array name derived from this class name (arrays of an unloaded
// class can't be referenced anymore).
if (_array_name != NULL) _array_name->decrement_refcount();
@ -2631,6 +2682,15 @@ const char* InstanceKlass::signature_name() const {
dest[dest_index++] = src[src_index++];
}
if (is_hidden()) { // Replace the last '+' with a '.'.
for (int index = (int)src_length; index > 0; index--) {
if (dest[index] == '+') {
dest[index] = JVM_SIGNATURE_DOT;
break;
}
}
}
// If we have a hash, append it
for (int hash_index = 0; hash_index < hash_len; ) {
dest[dest_index++] = hash_buf[hash_index++];
@ -2649,6 +2709,25 @@ ModuleEntry* InstanceKlass::module() const {
return unsafe_anonymous_host()->module();
}
if (is_hidden() &&
in_unnamed_package() &&
class_loader_data()->has_class_mirror_holder()) {
// For a non-strong hidden class defined to an unnamed package,
// its (class held) CLD will not have an unnamed module created for it.
// Two choices to find the correct ModuleEntry:
// 1. If hidden class is within a nest, use nest host's module
// 2. Find the unnamed module off from the class loader
// For now option #2 is used since a nest host is not set until
// after the instance class is created in jvm_lookup_define_class().
if (class_loader_data()->is_boot_class_loader_data()) {
return ClassLoaderData::the_null_class_loader_data()->unnamed_module();
} else {
oop module = java_lang_ClassLoader::unnamedModule(class_loader_data()->class_loader());
assert(java_lang_Module::is_instance(module), "Not an instance of java.lang.Module");
return java_lang_Module::module_entry(module);
}
}
// Class is in a named package
if (!in_unnamed_package()) {
return _package_entry->module();
@ -2879,7 +2958,7 @@ InstanceKlass* InstanceKlass::compute_enclosing_class(bool* inner_is_member, TRA
*inner_is_member = true;
}
if (NULL == outer_klass) {
// It may be unsafe anonymous; try for that.
// It may be a local or anonymous class; try for that.
int encl_method_class_idx = enclosing_method_class_index();
if (encl_method_class_idx != 0) {
Klass* ok = i_cp->klass_at(encl_method_class_idx, CHECK_NULL);

@ -195,7 +195,10 @@ class InstanceKlass: public Klass {
// that is the nest-host of this class. This data has not been validated.
jushort _nest_host_index;
// Resolved nest-host klass: either true nest-host or self if we are not nested.
// Resolved nest-host klass: either true nest-host or self if we are not
// nested, or an error occurred resolving or validating the nominated
// nest-host. Can also be set directly by JDK API's that establish nest
// relationships.
// By always being set it makes nest-member access checks simpler.
InstanceKlass* _nest_host;
@ -469,6 +472,8 @@ class InstanceKlass: public Klass {
// nest-host index
jushort nest_host_index() const { return _nest_host_index; }
void set_nest_host_index(u2 i) { _nest_host_index = i; }
// dynamic nest member support
void set_nest_host(InstanceKlass* host, TRAPS);
// record components
Array<RecordComponent*>* record_components() const { return _record_components; }
@ -482,9 +487,13 @@ private:
bool has_nest_member(InstanceKlass* k, TRAPS) const;
public:
// Returns nest-host class, resolving and validating it if needed
// Returns NULL if an exception occurs during loading, or validation fails
InstanceKlass* nest_host(Symbol* validationException, TRAPS);
// Used to construct informative IllegalAccessError messages at a higher level,
// if there was an issue resolving or validating the nest host.
// Returns NULL if there was no error.
const char* nest_host_error(TRAPS);
// Returns nest-host class, resolving and validating it if needed.
// Returns NULL if resolution is not possible from the calling context.
InstanceKlass* nest_host(TRAPS);
// Check if this klass is a nestmate of k - resolves this nest-host and k's
bool has_nestmate_access_to(InstanceKlass* k, TRAPS);
@ -819,8 +828,8 @@ public:
}
bool supers_have_passed_fingerprint_checks();
static bool should_store_fingerprint(bool is_unsafe_anonymous);
bool should_store_fingerprint() const { return should_store_fingerprint(is_unsafe_anonymous()); }
static bool should_store_fingerprint(bool is_hidden_or_anonymous);
bool should_store_fingerprint() const { return should_store_fingerprint(is_hidden() || is_unsafe_anonymous()); }
bool has_stored_fingerprint() const;
uint64_t get_stored_fingerprint() const;
void store_fingerprint(uint64_t fingerprint);

@ -1,4 +1,5 @@
/* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
/*
* Copyright (c) 2015, 2020, 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
@ -51,10 +52,9 @@ void InstanceMirrorKlass::oop_oop_iterate(oop obj, OopClosureType* closure) {
Klass* klass = java_lang_Class::as_Klass_raw(obj);
// We'll get NULL for primitive mirrors.
if (klass != NULL) {
if (klass->is_instance_klass() &&
InstanceKlass::cast(klass)->is_unsafe_anonymous()) {
// An unsafe anonymous class doesn't have its own class loader, so
// when handling the java mirror for the class we need to make sure its class
if (klass->is_instance_klass() && klass->class_loader_data()->has_class_mirror_holder()) {
// A non-strong hidden class or an unsafe anonymous class doesn't have its own class loader,
// so when handling the java mirror for the class we need to make sure its class
// loader data is claimed, this is done by calling do_cld explicitly.
// For non-anonymous classes the call to do_cld is made when the class
// loader itself is handled.

@ -608,7 +608,7 @@ void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protec
// gotten an OOM later but keep the mirror if it was created.
if (java_mirror() == NULL) {
log_trace(cds, mirror)("Recreate mirror for %s", external_name());
java_lang_Class::create_mirror(this, loader, module_handle, protection_domain, CHECK);
java_lang_Class::create_mirror(this, loader, module_handle, protection_domain, Handle(), CHECK);
}
}
@ -672,6 +672,20 @@ void Klass::check_array_allocation_length(int length, int max_length, TRAPS) {
}
}
// Replace the last '+' char with '/'.
static char* convert_hidden_name_to_java(Symbol* name) {
size_t name_len = name->utf8_length();
char* result = NEW_RESOURCE_ARRAY(char, name_len + 1);
name->as_klass_external_name(result, (int)name_len + 1);
for (int index = (int)name_len; index > 0; index--) {
if (result[index] == '+') {
result[index] = JVM_SIGNATURE_SLASH;
break;
}
}
return result;
}
// In product mode, this function doesn't have virtual function calls so
// there might be some performance advantage to handling InstanceKlass here.
const char* Klass::external_name() const {
@ -688,7 +702,14 @@ const char* Klass::external_name() const {
strcpy(result + name_len, addr_buf);
assert(strlen(result) == name_len + addr_len, "");
return result;
} else if (ik->is_hidden()) {
char* result = convert_hidden_name_to_java(name());
return result;
}
} else if (is_objArray_klass() && ObjArrayKlass::cast(this)->bottom_klass()->is_hidden()) {
char* result = convert_hidden_name_to_java(name());
return result;
}
if (name() == NULL) return "<unknown>";
return name()->as_klass_external_name();
@ -696,6 +717,18 @@ const char* Klass::external_name() const {
const char* Klass::signature_name() const {
if (name() == NULL) return "<unknown>";
if (is_objArray_klass() && ObjArrayKlass::cast(this)->bottom_klass()->is_hidden()) {
size_t name_len = name()->utf8_length();
char* result = NEW_RESOURCE_ARRAY(char, name_len + 1);
name()->as_C_string(result, (int)name_len + 1);
for (int index = (int)name_len; index > 0; index--) {
if (result[index] == '+') {
result[index] = JVM_SIGNATURE_DOT;
break;
}
}
return result;
}
return name()->as_C_string();
}

@ -615,6 +615,10 @@ protected:
void set_has_miranda_methods() { _access_flags.set_has_miranda_methods(); }
bool is_shared() const { return access_flags().is_shared_class(); } // shadows MetaspaceObj::is_shared)()
void set_is_shared() { _access_flags.set_is_shared_class(); }
bool is_hidden() const { return access_flags().is_hidden_class(); }
void set_is_hidden() { _access_flags.set_is_hidden_class(); }
bool is_non_strong_hidden() const { return access_flags().is_hidden_class() &&
class_loader_data()->has_class_mirror_holder(); }
bool is_cloneable() const;
void set_is_cloneable();

@ -892,9 +892,10 @@ public:
_flags = x ? (_flags | _dont_inline) : (_flags & ~_dont_inline);
}
bool is_hidden() {
bool is_hidden() const {
return (_flags & _hidden) != 0;
}
void set_hidden(bool x) {
_flags = x ? (_flags | _hidden) : (_flags & ~_hidden);
}

@ -602,6 +602,7 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt
case vmIntrinsics::_isInterface:
case vmIntrinsics::_isArray:
case vmIntrinsics::_isPrimitive:
case vmIntrinsics::_isHidden:
case vmIntrinsics::_getSuperclass:
case vmIntrinsics::_getClassAccessFlags:
case vmIntrinsics::_floatToRawIntBits:

@ -186,6 +186,7 @@ class LibraryCallKit : public GraphKit {
int modifier_mask, int modifier_bits,
RegionNode* region);
Node* generate_interface_guard(Node* kls, RegionNode* region);
Node* generate_hidden_class_guard(Node* kls, RegionNode* region);
Node* generate_array_guard(Node* kls, RegionNode* region) {
return generate_array_guard_common(kls, region, false, false);
}
@ -783,6 +784,7 @@ bool LibraryCallKit::try_to_inline(int predicate) {
case vmIntrinsics::_isInterface:
case vmIntrinsics::_isArray:
case vmIntrinsics::_isPrimitive:
case vmIntrinsics::_isHidden:
case vmIntrinsics::_getSuperclass:
case vmIntrinsics::_getClassAccessFlags: return inline_native_Class_query(intrinsic_id());
@ -3084,6 +3086,9 @@ Node* LibraryCallKit::generate_access_flags_guard(Node* kls, int modifier_mask,
Node* LibraryCallKit::generate_interface_guard(Node* kls, RegionNode* region) {
return generate_access_flags_guard(kls, JVM_ACC_INTERFACE, 0, region);
}
Node* LibraryCallKit::generate_hidden_class_guard(Node* kls, RegionNode* region) {
return generate_access_flags_guard(kls, JVM_ACC_IS_HIDDEN_CLASS, 0, region);
}
//-------------------------inline_native_Class_query-------------------
bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) {
@ -3119,6 +3124,9 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) {
prim_return_value = intcon(1);
expect_prim = true; // obviously
break;
case vmIntrinsics::_isHidden:
prim_return_value = intcon(0);
break;
case vmIntrinsics::_getSuperclass:
prim_return_value = null();
return_type = TypeInstPtr::MIRROR->cast_to_ptr_type(TypePtr::BotPTR);
@ -3211,6 +3219,16 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) {
query_value = intcon(0); // "normal" path produces false
break;
case vmIntrinsics::_isHidden:
// (To verify this code sequence, check the asserts in JVM_IsHiddenClass.)
if (generate_hidden_class_guard(kls, region) != NULL)
// A guard was added. If the guard is taken, it was an hidden class.
phi->add_req(intcon(1));
// If we fall through, it's a plain class.
query_value = intcon(0);
break;
case vmIntrinsics::_getSuperclass:
// The rules here are somewhat unfortunate, but we can still do better
// with random logic than with a JNI call.

@ -989,6 +989,154 @@ static jclass jvm_define_class_common(JNIEnv *env, const char *name,
return (jclass) JNIHandles::make_local(env, k->java_mirror());
}
enum {
NESTMATE = java_lang_invoke_MemberName::MN_NESTMATE_CLASS,
HIDDEN_CLASS = java_lang_invoke_MemberName::MN_HIDDEN_CLASS,
STRONG_LOADER_LINK = java_lang_invoke_MemberName::MN_STRONG_LOADER_LINK,
ACCESS_VM_ANNOTATIONS = java_lang_invoke_MemberName::MN_ACCESS_VM_ANNOTATIONS
};
/*
* Define a class with the specified flags that indicates if it's a nestmate,
* hidden, or strongly referenced from class loader.
*/
static jclass jvm_lookup_define_class(JNIEnv *env, jclass lookup, const char *name,
const jbyte *buf, jsize len, jobject pd,
jboolean init, int flags, jobject classData, TRAPS) {
assert(THREAD->is_Java_thread(), "must be a JavaThread");
JavaThread* jt = (JavaThread*) THREAD;
ResourceMark rm(THREAD);
Klass* lookup_k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(lookup));
// Lookup class must be a non-null instance
if (lookup_k == NULL) {
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Lookup class is null");
}
assert(lookup_k->is_instance_klass(), "Lookup class must be an instance klass");
Handle class_loader (THREAD, lookup_k->class_loader());
bool is_nestmate = (flags & NESTMATE) == NESTMATE;
bool is_hidden = (flags & HIDDEN_CLASS) == HIDDEN_CLASS;
bool is_strong = (flags & STRONG_LOADER_LINK) == STRONG_LOADER_LINK;
bool vm_annotations = (flags & ACCESS_VM_ANNOTATIONS) == ACCESS_VM_ANNOTATIONS;
InstanceKlass* host_class = NULL;
if (is_nestmate) {
host_class = InstanceKlass::cast(lookup_k)->nest_host(CHECK_NULL);
}
log_info(class, nestmates)("LookupDefineClass: %s - %s%s, %s, %s, %s",
name,
is_nestmate ? "with dynamic nest-host " : "non-nestmate",
is_nestmate ? host_class->external_name() : "",
is_hidden ? "hidden" : "not hidden",
is_strong ? "strong" : "weak",
vm_annotations ? "with vm annotations" : "without vm annotation");
if (!is_hidden) {
// classData is only applicable for hidden classes
if (classData != NULL) {
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "classData is only applicable for hidden classes");
}
if (is_nestmate) {
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "dynamic nestmate is only applicable for hidden classes");
}
if (!is_strong) {
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "an ordinary class must be strongly referenced by its defining loader");
}
if (vm_annotations) {
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "vm annotations only allowed for hidden classes");
}
if (flags != STRONG_LOADER_LINK) {
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
err_msg("invalid flag 0x%x", flags));
}
}
// Since exceptions can be thrown, class initialization can take place
// if name is NULL no check for class name in .class stream has to be made.
TempNewSymbol class_name = NULL;
if (name != NULL) {
const int str_len = (int)strlen(name);
if (str_len > Symbol::max_length()) {
// It's impossible to create this class; the name cannot fit
// into the constant pool.
Exceptions::fthrow(THREAD_AND_LOCATION,
vmSymbols::java_lang_NoClassDefFoundError(),
"Class name exceeds maximum length of %d: %s",
Symbol::max_length(),
name);
return 0;
}
class_name = SymbolTable::new_symbol(name, str_len);
}
Handle protection_domain (THREAD, JNIHandles::resolve(pd));
const char* source = is_nestmate ? host_class->external_name() : "__JVM_LookupDefineClass__";
ClassFileStream st((u1*)buf, len, source, ClassFileStream::verify);
Klass* defined_k;
InstanceKlass* ik = NULL;
if (!is_hidden) {
defined_k = SystemDictionary::resolve_from_stream(class_name,
class_loader,
protection_domain,
&st,
CHECK_NULL);
if (log_is_enabled(Debug, class, resolve) && defined_k != NULL) {
trace_class_resolution(defined_k);
}
ik = InstanceKlass::cast(defined_k);
} else { // hidden
Handle classData_h(THREAD, JNIHandles::resolve(classData));
ClassLoadInfo cl_info(protection_domain,
NULL, // unsafe_anonymous_host
NULL, // cp_patches
host_class,
classData_h,
is_hidden,
is_strong,
vm_annotations);
defined_k = SystemDictionary::parse_stream(class_name,
class_loader,
&st,
cl_info,
CHECK_NULL);
if (defined_k == NULL) {
THROW_MSG_0(vmSymbols::java_lang_Error(), "Failure to define a hidden class");
}
ik = InstanceKlass::cast(defined_k);
// 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
// it alive afterwards.
ik->class_loader_data()->dec_keep_alive();
if (is_nestmate && log_is_enabled(Debug, class, nestmates)) {
ModuleEntry* module = ik->module();
const char * module_name = module->is_named() ? module->name()->as_C_string() : UNNAMED_MODULE;
log_debug(class, nestmates)("Dynamic nestmate: %s/%s, nest_host %s, %s",
module_name,
ik->external_name(),
host_class->external_name(),
ik->is_hidden() ? "is hidden" : "is not hidden");
}
}
assert(Reflection::is_same_class_package(lookup_k, defined_k),
"lookup class and defined class are in different packages");
if (init) {
ik->initialize(CHECK_NULL);
} else {
ik->link_class(CHECK_NULL);
}
return (jclass) JNIHandles::make_local(env, defined_k->java_mirror());
}
JVM_ENTRY(jclass, JVM_DefineClass(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd))
JVMWrapper("JVM_DefineClass");
@ -996,6 +1144,29 @@ JVM_ENTRY(jclass, JVM_DefineClass(JNIEnv *env, const char *name, jobject loader,
return jvm_define_class_common(env, name, loader, buf, len, pd, NULL, THREAD);
JVM_END
/*
* Define a class with the specified lookup class.
* lookup: Lookup class
* name: the name of the class
* buf: class bytes
* len: length of class bytes
* pd: protection domain
* init: initialize the class
* flags: properties of the class
* classData: private static pre-initialized field
*/
JVM_ENTRY(jclass, JVM_LookupDefineClass(JNIEnv *env, jclass lookup, const char *name, const jbyte *buf,
jsize len, jobject pd, jboolean initialize, int flags, jobject classData))
JVMWrapper("JVM_LookupDefineClass");
if (lookup == NULL) {
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Lookup class is null");
}
assert(buf != NULL, "buf must not be NULL");
return jvm_lookup_define_class(env, lookup, name, buf, len, pd, initialize, flags, classData, THREAD);
JVM_END
JVM_ENTRY(jclass, JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd, const char *source))
JVMWrapper("JVM_DefineClassWithSource");
@ -1158,6 +1329,15 @@ JVM_ENTRY(jboolean, JVM_IsInterface(JNIEnv *env, jclass cls))
return result;
JVM_END
JVM_ENTRY(jboolean, JVM_IsHiddenClass(JNIEnv *env, jclass cls))
JVMWrapper("JVM_IsHiddenClass");
oop mirror = JNIHandles::resolve_non_null(cls);
if (java_lang_Class::is_primitive(mirror)) {
return JNI_FALSE;
}
Klass* k = java_lang_Class::as_Klass(mirror);
return k->is_hidden();
JVM_END
JVM_ENTRY(jobjectArray, JVM_GetClassSigners(JNIEnv *env, jclass cls))
JVMWrapper("JVM_GetClassSigners");
@ -1425,7 +1605,7 @@ JVM_ENTRY(jclass, JVM_GetDeclaringClass(JNIEnv *env, jclass ofClass))
= InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))
)->compute_enclosing_class(&inner_is_member, CHECK_NULL);
if (outer_klass == NULL) return NULL; // already a top-level class
if (!inner_is_member) return NULL; // an anonymous class (inside a method)
if (!inner_is_member) return NULL; // a hidden or unsafe anonymous class (inside a method)
return (jclass) JNIHandles::make_local(env, outer_klass->java_mirror());
}
JVM_END
@ -1875,8 +2055,7 @@ JVM_ENTRY(jclass, JVM_GetNestHost(JNIEnv* env, jclass current))
Klass* c = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(current));
assert(c->is_instance_klass(), "must be");
InstanceKlass* ck = InstanceKlass::cast(c);
// Don't post exceptions if validation fails
InstanceKlass* host = ck->nest_host(NULL, THREAD);
InstanceKlass* host = ck->nest_host(THREAD);
return (jclass) (host == NULL ? NULL :
JNIHandles::make_local(THREAD, host->java_mirror()));
}
@ -1886,62 +2065,77 @@ JVM_ENTRY(jobjectArray, JVM_GetNestMembers(JNIEnv* env, jclass current))
{
// current is not a primitive or array class
JVMWrapper("JVM_GetNestMembers");
ResourceMark rm(THREAD);
Klass* c = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(current));
assert(c->is_instance_klass(), "must be");
InstanceKlass* ck = InstanceKlass::cast(c);
// Get the nest host for this nest - throw ICCE if validation fails
Symbol* icce = vmSymbols::java_lang_IncompatibleClassChangeError();
InstanceKlass* host = ck->nest_host(icce, CHECK_NULL);
InstanceKlass* host = ck->nest_host(THREAD);
log_trace(class, nestmates)("Calling GetNestMembers for type %s with nest-host %s",
ck->external_name(), host->external_name());
{
JvmtiVMObjectAllocEventCollector oam;
Array<u2>* members = host->nest_members();
int length = members == NULL ? 0 : members->length();
log_trace(class, nestmates)(" - host has %d listed nest members", length);
// nest host is first in the array so make it one bigger
objArrayOop r = oopFactory::new_objArray(SystemDictionary::Class_klass(),
length + 1, CHECK_NULL);
objArrayHandle result (THREAD, r);
objArrayHandle result(THREAD, r);
result->obj_at_put(0, host->java_mirror());
if (length != 0) {
int i;
for (i = 0; i < length; i++) {
int cp_index = members->at(i);
Klass* k = host->constants()->klass_at(cp_index, CHECK_NULL);
if (k->is_instance_klass()) {
InstanceKlass* nest_host_k =
InstanceKlass::cast(k)->nest_host(icce, CHECK_NULL);
if (nest_host_k == host) {
result->obj_at_put(i+1, k->java_mirror());
}
else {
// k's nest host is legal but it isn't our host so
// throw ICCE
ResourceMark rm(THREAD);
Exceptions::fthrow(THREAD_AND_LOCATION,
icce,
"Nest member %s in %s declares a different nest host of %s",
k->external_name(),
host->external_name(),
nest_host_k->external_name()
);
return NULL;
}
}
else {
// we have a bad nest member entry - throw ICCE
ResourceMark rm(THREAD);
Exceptions::fthrow(THREAD_AND_LOCATION,
icce,
"Class %s can not be a nest member of %s",
k->external_name(),
host->external_name()
);
return NULL;
}
int count = 0;
for (int i = 0; i < length; i++) {
int cp_index = members->at(i);
Klass* k = host->constants()->klass_at(cp_index, THREAD);
if (HAS_PENDING_EXCEPTION) {
if (PENDING_EXCEPTION->is_a(SystemDictionary::VirtualMachineError_klass())) {
return NULL; // propagate VMEs
}
if (log_is_enabled(Trace, class, nestmates)) {
stringStream ss;
char* target_member_class = host->constants()->klass_name_at(cp_index)->as_C_string();
ss.print(" - resolution of nest member %s failed: ", target_member_class);
java_lang_Throwable::print(PENDING_EXCEPTION, &ss);
log_trace(class, nestmates)("%s", ss.as_string());
}
CLEAR_PENDING_EXCEPTION;
continue;
}
if (k->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(k);
InstanceKlass* nest_host_k = ik->nest_host(CHECK_NULL);
if (nest_host_k == host) {
result->obj_at_put(count+1, k->java_mirror());
count++;
log_trace(class, nestmates)(" - [%d] = %s", count, ik->external_name());
} else {
log_trace(class, nestmates)(" - skipping member %s with different host %s",
ik->external_name(), nest_host_k->external_name());
}
} else {
log_trace(class, nestmates)(" - skipping member %s that is not an instance class",
k->external_name());
}
}
if (count < length) {
// we had invalid entries so we need to compact the array
log_trace(class, nestmates)(" - compacting array from length %d to %d",
length + 1, count + 1);
objArrayOop r2 = oopFactory::new_objArray(SystemDictionary::Class_klass(),
count + 1, CHECK_NULL);
objArrayHandle result2(THREAD, r2);
for (int i = 0; i < count + 1; i++) {
result2->obj_at_put(i, result->obj_at(i));
}
return (jobjectArray)JNIHandles::make_local(THREAD, result2());
}
}
else {
assert(host == ck, "must be singleton nest");
assert(host == ck || ck->is_hidden(), "must be singleton nest or dynamic nestmate");
}
return (jobjectArray)JNIHandles::make_local(THREAD, result());
}

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="jvmti.xsl"?>
<!--
Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2002, 2020, 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
@ -6846,10 +6846,6 @@ class C2 extends C1 implements I2 {
</category>
<category id="class" label="Class">
<intro>
</intro>
<function id="GetLoadedClasses" jkernel="yes" num="78">
<synopsis>Get Loaded Classes</synopsis>
<description>
@ -6858,9 +6854,26 @@ class C2 extends C1 implements I2 {
<code>class_count_ptr</code>, and the array itself via
<code>classes_ptr</code>.
<p/>
Array classes of all types (including arrays of primitive types) are
included in the returned list. Primitive classes (for example,
<code>java.lang.Integer.TYPE</code>) are <i>not</i> included in this list.
A class or interface creation can be triggered by one of the following:
<ul>
<li>By loading and deriving a class from a <code>class</code> file representation
using a class loader (see <vmspec chapter="5.3"/>).</li>
<li>By invoking <externallink id="../api/java.base/java/lang/invoke/MethodHandles.Lookup.html#defineHiddenClass(byte[],boolean,java.lang.invoke.MethodHandles.Lookup.ClassOption...)">Lookup::defineHiddenClass</externallink>
that creates a hidden class or interface from a <code>class</code> file representation.</li>
<li>By invoking methods in certain Java SE Platform APIs such as reflection.</li>
</ul>
<p/>
An array class is created directly by the Java virtual machine. The creation
can be triggered by using class loaders or by invoking methods in certain
Java SE Platform APIs such as reflection.
<p/>
The returned list includes all classes and interfaces, including
<externallink id="../api/java.base/java/lang/Class.html#isHidden()">
hidden classes or interfaces</externallink>,
and also array classes of all types
(including arrays of primitive types).
Primitive classes (for example, <code>java.lang.Integer.TYPE</code>) are
<i>not</i> included in the returned list.
</description>
<origin>jvmdi</origin>
<capabilities>
@ -6887,15 +6900,27 @@ class C2 extends C1 implements I2 {
<function id="GetClassLoaderClasses" jkernel="yes" num="79">
<synopsis>Get Classloader Classes</synopsis>
<description>
Returns an array of those classes for which this class loader has
been recorded as an initiating loader. Each
class in the returned array was created by this class loader,
Returns an array of all classes which this class loader
can find by name via
<externallink id="../api/java.base/java/lang/ClassLoader.html#loadClass(java.lang.String,boolean)">ClassLoader::loadClass</externallink>,
<externallink id="../api/java.base/java/lang/Class.html#forName(java.lang.String,boolean,java.lang.ClassLoader)">Class::forName</externallink> and bytecode linkage.
That is, all classes for which <code>initiating_loader</code>
has been recorded as an initiating loader.
Each class in the returned array was created by this class loader,
either by defining it directly or by delegation to another class loader.
See <vmspec chapter="5.3"/>.
<p/>
The returned list does not include
<externallink id="../api/java.base/java/lang/Class.html#isHidden()">hidden
classes or interfaces</externallink> or array classes whose
element type is a hidden class or interface as they cannot be discovered
by any class loader.
<p/>
The number of classes in the array is returned via
<code>class_count_ptr</code>, and the array itself via
<code>classes_ptr</code>.
<p/>
See <externallink id="../api/java.base/java/lang/invoke/MethodHandles.Lookup.html#defineHiddenClass(byte[],boolean,java.lang.invoke.MethodHandles.Lookup.ClassOption...)">Lookup::defineHiddenClass</externallink>.
</description>
<origin>jvmdi</origin>
<capabilities>
@ -6931,15 +6956,37 @@ class C2 extends C1 implements I2 {
<function id="GetClassSignature" phase="start" num="48">
<synopsis>Get Class Signature</synopsis>
<description>
For the class indicated by <code>klass</code>, return the
<externallink id="jni/types.html#type-signatures">JNI
type signature</externallink>
and the generic signature of the class.
For example, <code>java.util.List</code> is <code>"Ljava/util/List;"</code>
and <code>int[]</code> is <code>"[I"</code>
The returned name for primitive classes
is the type signature character of the corresponding primitive type.
For example, <code>java.lang.Integer.TYPE</code> is <code>"I"</code>.
Return the name and the generic signature of the class indicated by <code>klass</code>.
<p/>
If the class is a class or interface, then:
<ul>
<li>If the class or interface is not <externallink id="../api/java.base/java/lang/Class.html#isHidden()">hidden</externallink>,
then the returned name is the <externallink id="jni/types.html#type-signatures">
JNI type signature</externallink>.
For example, java.util.List is "Ljava/util/List;"
</li>
<li>If the class or interface is <externallink id="../api/java.base/java/lang/Class.html#isHidden()">hidden</externallink>,
then the returned name is a string of the form:
<code>"L" + N + "." + S + ";"</code>
where <code>N</code> is the binary name encoded in internal form (JVMS 4.2.1)
indicated by the <code>class</code> file passed to
<externallink id="../api/java.base/java/lang/invoke/MethodHandles.Lookup.html#defineHiddenClass(byte[],boolean,java.lang.invoke.MethodHandles.Lookup.ClassOption...)">Lookup::defineHiddenClass</externallink>,
and <code>S</code> is an unqualified name.
The returned name is not a type descriptor and does not conform to JVMS 4.3.2.
For example, com.foo.Foo/AnySuffix is "Lcom/foo/Foo.AnySuffix;"
</li>
</ul>
<p/>
If the class indicated by <code>klass</code> represents an array class, then
the returned name is a string consisting of one or more "<code>[</code>" characters
representing the depth of the array nesting, followed by the class signature
of the element type. For example the class signature of java.lang.String[] is
"[Ljava/lang/String;" and that of int[] is "[I".
<p/>
If the class indicated by <code>klass</code> represents primitive type or <code>void</code>,
then the returned name is the <externallink id="jni/types.html#type-signatures">
type signature character of the corresponding primitive type</externallink>.
For example, java.lang.Integer.TYPE is "I".
</description>
<origin>jvmdiClone</origin>
<capabilities>
@ -12712,13 +12759,16 @@ myInit() {
<event label="Class Load"
id="ClassLoad" const="JVMTI_EVENT_CLASS_LOAD" filtered="thread" phase="start" num="55">
<description>
A class load event is generated when a class is first loaded. The order
of class load events generated by a particular thread are guaranteed
to match the order of class loading within that thread.
A class load event is generated
<functionlink id="GetLoadedClasses">when a class or interface is created.</functionlink>.
<p/>
Array class creation does not generate a class load event.
The creation of a primitive class (for example, java.lang.Integer.TYPE)
does not generate a class load event.
<p/>
The order of class load events generated by a particular thread is guaranteed
to match the order of class loading within that thread.
<p/>
This event is sent at an early stage in loading the class. As
a result the class should be used carefully. Note, for example,
that methods and fields are not yet loaded, so queries for methods,

@ -150,8 +150,8 @@ bool VM_RedefineClasses::doit_prologue() {
}
oop mirror = JNIHandles::resolve_non_null(_class_defs[i].klass);
// classes for primitives and arrays and vm unsafe anonymous classes cannot be redefined
// check here so following code can assume these classes are InstanceKlass
// classes for primitives, arrays, hidden and vm unsafe anonymous classes
// cannot be redefined.
if (!is_modifiable_class(mirror)) {
_res = JVMTI_ERROR_UNMODIFIABLE_CLASS;
return false;
@ -293,8 +293,9 @@ bool VM_RedefineClasses::is_modifiable_class(oop klass_mirror) {
return false;
}
// Cannot redefine or retransform an unsafe anonymous class.
if (InstanceKlass::cast(k)->is_unsafe_anonymous()) {
// Cannot redefine or retransform a hidden or an unsafe anonymous class.
if (InstanceKlass::cast(k)->is_hidden() ||
InstanceKlass::cast(k)->is_unsafe_anonymous()) {
return false;
}
return true;
@ -1239,11 +1240,12 @@ jvmtiError VM_RedefineClasses::load_new_class_versions(TRAPS) {
// load hook event.
state->set_class_being_redefined(the_class, _class_load_kind);
ClassLoadInfo cl_info(protection_domain);
InstanceKlass* scratch_class = SystemDictionary::parse_stream(
the_class_sym,
the_class_loader,
protection_domain,
&st,
cl_info,
THREAD);
// Clear class_being_redefined just to be sure.
state->clear_class_being_redefined();

@ -1111,6 +1111,10 @@ void MethodHandles::trace_method_handle_interpreter_entry(MacroAssembler* _masm,
template(java_lang_invoke_MemberName,MN_SEARCH_INTERFACES) \
template(java_lang_invoke_MemberName,MN_REFERENCE_KIND_SHIFT) \
template(java_lang_invoke_MemberName,MN_REFERENCE_KIND_MASK) \
template(java_lang_invoke_MemberName,MN_NESTMATE_CLASS) \
template(java_lang_invoke_MemberName,MN_HIDDEN_CLASS) \
template(java_lang_invoke_MemberName,MN_STRONG_LOADER_LINK) \
template(java_lang_invoke_MemberName,MN_ACCESS_VM_ANNOTATIONS) \
/*end*/
#define IGNORE_REQ(req_expr) /* req_expr */
@ -1527,7 +1531,7 @@ static JNINativeMethod MHN_methods[] = {
{CC "clearCallSiteContext", CC "(" CTX ")V", FN_PTR(MHN_clearCallSiteContext)},
{CC "staticFieldOffset", CC "(" MEM ")J", FN_PTR(MHN_staticFieldOffset)},
{CC "staticFieldBase", CC "(" MEM ")" OBJ, FN_PTR(MHN_staticFieldBase)},
{CC "getMemberVMInfo", CC "(" MEM ")" OBJ, FN_PTR(MHN_getMemberVMInfo)}
{CC "getMemberVMInfo", CC "(" MEM ")" OBJ, FN_PTR(MHN_getMemberVMInfo)}
};
static JNINativeMethod MH_methods[] = {

@ -850,12 +850,19 @@ Unsafe_DefineAnonymousClass_impl(JNIEnv *env,
ClassFileStream st(class_bytes, class_bytes_length, host_source, ClassFileStream::verify);
Symbol* no_class_name = NULL;
ClassLoadInfo cl_info(host_domain,
InstanceKlass::cast(host_klass),
cp_patches,
NULL, // dynamic_nest_host
Handle(), // classData
false, // is_hidden
false, // is_strong_hidden
true); // can_access_vm_annotations
Klass* anonk = SystemDictionary::parse_stream(no_class_name,
host_loader,
host_domain,
&st,
InstanceKlass::cast(host_klass),
cp_patches,
cl_info,
CHECK_NULL);
if (anonk == NULL) {
return NULL;

@ -711,7 +711,7 @@ bool Reflection::is_same_class_package(const Klass* class1, const Klass* class2)
// Checks that the 'outer' klass has declared 'inner' as being an inner klass. If not,
// throw an incompatible class change exception
// If inner_is_member, require the inner to be a member of the outer.
// If !inner_is_member, require the inner to be unsafe anonymous (a non-member).
// If !inner_is_member, require the inner to be hidden or unsafe anonymous (non-members).
// Caller is responsible for figuring out in advance which case must be true.
void Reflection::check_for_inner_class(const InstanceKlass* outer, const InstanceKlass* inner,
bool inner_is_member, TRAPS) {

@ -517,6 +517,7 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
nonstatic_field(ClassLoaderData, _class_loader, OopHandle) \
nonstatic_field(ClassLoaderData, _next, ClassLoaderData*) \
volatile_nonstatic_field(ClassLoaderData, _klasses, Klass*) \
nonstatic_field(ClassLoaderData, _has_class_mirror_holder, bool) \
volatile_nonstatic_field(ClassLoaderData, _dictionary, Dictionary*) \
\
static_ptr_volatile_field(ClassLoaderDataGraph, _head, ClassLoaderData*) \

@ -66,6 +66,7 @@ enum {
JVM_ACC_IS_CLONEABLE_FAST = (int)0x80000000,// True if klass implements the Cloneable interface and can be optimized in generated code
JVM_ACC_HAS_FINAL_METHOD = 0x01000000, // True if klass has final method
JVM_ACC_IS_SHARED_CLASS = 0x02000000, // True if klass is shared
JVM_ACC_IS_HIDDEN_CLASS = 0x04000000, // True if klass is hidden
// Klass* and Method* flags
JVM_ACC_HAS_LOCAL_VARIABLE_TABLE= 0x00200000,
@ -149,6 +150,7 @@ class AccessFlags {
bool has_final_method () const { return (_flags & JVM_ACC_HAS_FINAL_METHOD ) != 0; }
bool is_cloneable_fast () const { return (_flags & JVM_ACC_IS_CLONEABLE_FAST ) != 0; }
bool is_shared_class () const { return (_flags & JVM_ACC_IS_SHARED_CLASS ) != 0; }
bool is_hidden_class () const { return (_flags & JVM_ACC_IS_HIDDEN_CLASS ) != 0; }
// Klass* and Method* flags
bool has_localvariable_table () const { return (_flags & JVM_ACC_HAS_LOCAL_VARIABLE_TABLE) != 0; }
@ -221,6 +223,7 @@ class AccessFlags {
void set_is_cloneable_fast() { atomic_set_bits(JVM_ACC_IS_CLONEABLE_FAST); }
void set_has_miranda_methods() { atomic_set_bits(JVM_ACC_HAS_MIRANDA_METHODS); }
void set_is_shared_class() { atomic_set_bits(JVM_ACC_IS_SHARED_CLASS); }
void set_is_hidden_class() { atomic_set_bits(JVM_ACC_IS_HIDDEN_CLASS); }
public:
// field flags

@ -29,6 +29,7 @@
#include "oops/oop.inline.hpp"
#include "runtime/arguments.hpp"
#include "runtime/os.inline.hpp"
#include "runtime/orderAccess.hpp"
#include "runtime/vm_version.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/macros.hpp"
@ -368,10 +369,16 @@ void stringStream::reset() {
zero_terminate();
}
char* stringStream::as_string() const {
char* copy = NEW_RESOURCE_ARRAY(char, buffer_pos + 1);
char* stringStream::as_string(bool c_heap) const {
char* copy = c_heap ?
NEW_C_HEAP_ARRAY(char, buffer_pos + 1, mtInternal) : NEW_RESOURCE_ARRAY(char, buffer_pos + 1);
strncpy(copy, buffer, buffer_pos);
copy[buffer_pos] = 0; // terminating null
if (c_heap) {
// Need to ensure our content is written to memory before we return
// the pointer to it.
OrderAccess::storestore();
}
return copy;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, 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
@ -215,7 +215,8 @@ class stringStream : public outputStream {
size_t size() const { return buffer_pos; }
const char* base() const { return buffer; }
void reset();
char* as_string() const;
// copy to a resource, or C-heap, array as requested
char* as_string(bool c_heap = false) const;
};
class fileStream : public outputStream {

@ -28,6 +28,7 @@ package java.lang;
import java.lang.annotation.Annotation;
import java.lang.constant.ClassDesc;
import java.lang.invoke.TypeDescriptor;
import java.lang.invoke.MethodHandles;
import java.lang.module.ModuleReader;
import java.lang.ref.SoftReference;
import java.io.IOException;
@ -63,8 +64,6 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.stream.Stream;
import java.util.stream.Collectors;
import jdk.internal.HotSpotIntrinsicCandidate;
@ -100,16 +99,42 @@ import sun.reflect.misc.ReflectUtil;
* keyword {@code void} are also represented as {@code Class} objects.
*
* <p> {@code Class} has no public constructor. Instead a {@code Class}
* object is constructed automatically by the Java Virtual Machine
* when a class loader invokes one of the
* {@link ClassLoader#defineClass(String,byte[], int,int) defineClass} methods
* and passes the bytes of a {@code class} file.
* object is constructed automatically by the Java Virtual Machine when
* a class is derived from the bytes of a {@code class} file through
* the invocation of one of the following methods:
* <ul>
* <li> {@link ClassLoader#defineClass(String, byte[], int, int) ClassLoader::defineClass}
* <li> {@link java.lang.invoke.MethodHandles.Lookup#defineClass(byte[])
* java.lang.invoke.MethodHandles.Lookup::defineClass}
* <li> {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...)
* java.lang.invoke.MethodHandles.Lookup::defineHiddenClass}
* </ul>
*
* <p> The methods of class {@code Class} expose many characteristics of a
* class or interface. Most characteristics are derived from the {@code class}
* file that the class loader passed to the Java Virtual Machine. A few
* characteristics are determined by the class loading environment at run time,
* such as the module returned by {@link #getModule() getModule()}.
* file that the class loader passed to the Java Virtual Machine or
* from the {@code class} file passed to {@code Lookup::defineClass}
* or {@code Lookup::defineHiddenClass}.
* A few characteristics are determined by the class loading environment
* at run time, such as the module returned by {@link #getModule() getModule()}.
*
* <p> The following example uses a {@code Class} object to print the
* class name of an object:
*
* <blockquote><pre>
* void printClassName(Object obj) {
* System.out.println("The class of " + obj +
* " is " + obj.getClass().getName());
* }
* </pre></blockquote>
*
* It is also possible to get the {@code Class} object for a named
* type (or for {@code void}) using a <i>class literal</i>.
* For example:
*
* <blockquote>
* {@code System.out.println("The name of class Foo is: "+Foo.class.getName());}
* </blockquote>
*
* <p> Some methods of class {@code Class} expose whether the declaration of
* a class or interface in Java source code was <em>enclosed</em> within
@ -128,24 +153,33 @@ import sun.reflect.misc.ReflectUtil;
* other members are the classes and interfaces whose declarations are
* enclosed within the top-level class declaration.
*
* <p> The following example uses a {@code Class} object to print the
* class name of an object:
* <p> A class or interface created by the invocation of
* {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...)
* Lookup::defineHiddenClass} is a {@linkplain Class#isHidden() <em>hidden</em>}
* class or interface.
* All kinds of class, including enum types and record types, may be
* hidden classes; all kinds of interface, including annotation types,
* may be hidden interfaces.
*
* <blockquote><pre>
* void printClassName(Object obj) {
* System.out.println("The class of " + obj +
* " is " + obj.getClass().getName());
* }
* </pre></blockquote>
* The {@linkplain #getName() name of a hidden class or interface} is
* not a <a href="ClassLoader.html#binary-name">binary name</a>,
* which means the following:
* <ul>
* <li>A hidden class or interface cannot be referenced by the constant pools
* of other classes and interfaces.
* <li>A hidden class or interface cannot be described in
* {@linkplain java.lang.constant.ConstantDesc <em>nominal form</em>} by
* {@link #describeConstable() Class::describeConstable},
* {@link ClassDesc#of(String) ClassDesc::of}, or
* {@link ClassDesc#ofDescriptor(String) ClassDesc::ofDescriptor}.
* <li>A hidden class or interface cannot be discovered by {@link #forName Class::forName}
* or {@link ClassLoader#loadClass(String, boolean) ClassLoader::loadClass}.
* </ul>
*
* <p> It is also possible to get the {@code Class} object for a named
* type (or for void) using a class literal. See Section {@jls
* 15.8.2} of <cite>The Java&trade; Language Specification</cite>.
* For example:
*
* <blockquote>
* {@code System.out.println("The name of class Foo is: " + Foo.class.getName());}
* </blockquote>
* A hidden class or interface is never an array class, but may be
* the element type of an array. In all other respects, the fact that
* a class or interface is hidden has no bearing on the characteristics
* exposed by the methods of class {@code Class}.
*
* @param <T> the type of the class modeled by this {@code Class}
* object. For example, the type of {@code String.class} is {@code
@ -155,6 +189,7 @@ import sun.reflect.misc.ReflectUtil;
* @author unascribed
* @see java.lang.ClassLoader#defineClass(byte[], int, int)
* @since 1.0
* @jls 15.8.2 Class Literals
*/
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
@ -186,9 +221,9 @@ public final class Class<T> implements java.io.Serializable,
/**
* Converts the object to a string. The string representation is the
* string "class" or "interface", followed by a space, and then by the
* fully qualified name of the class in the format returned by
* {@code getName}. If this {@code Class} object represents a
* primitive type, this method returns the name of the primitive type. If
* name of the class in the format returned by {@code getName}.
* If this {@code Class} object represents a primitive type,
* this method returns the name of the primitive type. If
* this {@code Class} object represents void this method returns
* "void". If this {@code Class} object represents an array type,
* this method returns "class " followed by {@code getName}.
@ -745,11 +780,12 @@ public final class Class<T> implements java.io.Serializable,
}
/**
* Returns {@code true} if this class is a synthetic class;
* returns {@code false} otherwise.
* @return {@code true} if and only if this class is a synthetic class as
* defined by <cite>The Java&trade; Language Specification</cite>.
* Returns {@code true} if and only if this class has the synthetic modifier
* bit set.
*
* @return {@code true} if and only if this class has the synthetic modifier bit set
* @jls 13.1 The Form of a Binary
* @jvms 4.1 The {@code ClassFile} Structure
* @since 1.5
*/
public boolean isSynthetic() {
@ -758,22 +794,26 @@ public final class Class<T> implements java.io.Serializable,
/**
* Returns the name of the entity (class, interface, array class,
* primitive type, or void) represented by this {@code Class} object,
* as a {@code String}.
* primitive type, or void) represented by this {@code Class} object.
*
* <p> If this {@code Class} object represents a reference type that is
* not an array type then the binary name of the class is
* returned, as specified by <cite>The Java&trade; Language
* Specification</cite>.
* <p> If this {@code Class} object represents a class or interface,
* not an array class, then:
* <ul>
* <li> If the class or interface is not {@linkplain #isHidden() hidden},
* then the <a href="ClassLoader.html#binary-name">binary name</a>
* of the class or interface is returned.
* <li> If the class or interface is hidden, then the result is a string
* of the form: {@code N + '/' + <suffix>}
* where {@code N} is the <a href="ClassLoader.html#binary-name">binary name</a>
* indicated by the {@code class} file passed to
* {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...)
* Lookup::defineHiddenClass}, and {@code <suffix>} is an unqualified name.
* </ul>
*
* <p> If this {@code Class} object represents a primitive type or void, then the
* name returned is a {@code String} equal to the Java language
* keyword corresponding to the primitive type or void.
*
* <p> If this {@code Class} object represents a class of arrays, then the internal
* form of the name consists of the name of the element type preceded by
* one or more '{@code [}' characters representing the depth of the array
* nesting. The encoding of element type names is as follows:
* <p> If this {@code Class} object represents an array class, then
* the result is a string consisting of one or more '{@code [}' characters
* representing the depth of the array nesting, followed by the element
* type as encoded using the following table:
*
* <blockquote><table class="striped">
* <caption style="display:none">Element types and encodings</caption>
@ -781,21 +821,22 @@ public final class Class<T> implements java.io.Serializable,
* <tr><th scope="col"> Element Type <th scope="col"> Encoding
* </thead>
* <tbody style="text-align:left">
* <tr><th scope="row"> boolean <td style="text-align:center"> Z
* <tr><th scope="row"> byte <td style="text-align:center"> B
* <tr><th scope="row"> char <td style="text-align:center"> C
* <tr><th scope="row"> class or interface
* <td style="text-align:center"> L<i>classname</i>;
* <tr><th scope="row"> double <td style="text-align:center"> D
* <tr><th scope="row"> float <td style="text-align:center"> F
* <tr><th scope="row"> int <td style="text-align:center"> I
* <tr><th scope="row"> long <td style="text-align:center"> J
* <tr><th scope="row"> short <td style="text-align:center"> S
* <tr><th scope="row"> {@code boolean} <td style="text-align:center"> {@code Z}
* <tr><th scope="row"> {@code byte} <td style="text-align:center"> {@code B}
* <tr><th scope="row"> {@code char} <td style="text-align:center"> {@code C}
* <tr><th scope="row"> class or interface with <a href="ClassLoader.html#binary-name">binary name</a> <i>N</i>
* <td style="text-align:center"> {@code L}<em>N</em>{@code ;}
* <tr><th scope="row"> {@code double} <td style="text-align:center"> {@code D}
* <tr><th scope="row"> {@code float} <td style="text-align:center"> {@code F}
* <tr><th scope="row"> {@code int} <td style="text-align:center"> {@code I}
* <tr><th scope="row"> {@code long} <td style="text-align:center"> {@code J}
* <tr><th scope="row"> {@code short} <td style="text-align:center"> {@code S}
* </tbody>
* </table></blockquote>
*
* <p> The class or interface name <i>classname</i> is the binary name of
* the class specified above.
* <p> If this {@code Class} object represents a primitive type or {@code void},
* then the result is a string with the same spelling as the Java language
* keyword which corresponds to the primitive type or {@code void}.
*
* <p> Examples:
* <blockquote><pre>
@ -809,8 +850,9 @@ public final class Class<T> implements java.io.Serializable,
* returns "[[[[[[[I"
* </pre></blockquote>
*
* @return the name of the class or interface
* @return the name of the class, interface, or other entity
* represented by this {@code Class} object.
* @jls 13.1 The Form of a Binary
*/
public String getName() {
String name = this.name;
@ -888,6 +930,14 @@ public final class Class<T> implements java.io.Serializable,
// will throw NoSuchFieldException
private final ClassLoader classLoader;
// Set by VM
private transient Object classData;
// package-private
Object getClassData() {
return classData;
}
/**
* Returns an array of {@code TypeVariable} objects that represent the
* type variables declared by the generic declaration represented by this
@ -900,7 +950,7 @@ public final class Class<T> implements java.io.Serializable,
* @throws java.lang.reflect.GenericSignatureFormatError if the generic
* signature of this generic declaration does not conform to
* the format specified in section {@jvms 4.7.9} of
* <cite>The Java&trade; Virtual Machine Specification</cite>,
* <cite>The Java&trade; Virtual Machine Specification</cite>
* @since 1.5
*/
@SuppressWarnings("unchecked")
@ -1023,10 +1073,7 @@ public final class Class<T> implements java.io.Serializable,
public String getPackageName() {
String pn = this.packageName;
if (pn == null) {
Class<?> c = this;
while (c.isArray()) {
c = c.getComponentType();
}
Class<?> c = isArray() ? elementType() : this;
if (c.isPrimitive()) {
pn = "java.lang";
} else {
@ -1184,6 +1231,20 @@ public final class Class<T> implements java.io.Serializable,
private final Class<?> componentType;
/*
* Returns the {@code Class} representing the element type of an array class.
* If this class does not represent an array class, then this method returns
* {@code null}.
*/
private Class<?> elementType() {
if (!isArray()) return null;
Class<?> c = this;
while (c.isArray()) {
c = c.getComponentType();
}
return c;
}
/**
* Returns the Java language modifiers for this class or interface, encoded
@ -1614,11 +1675,17 @@ public final class Class<T> implements java.io.Serializable,
}
/**
* Returns the canonical name of the underlying class as defined
* by <cite>The Java&trade; Language Specification</cite>, section
* {@jls 6.7}. Returns null if the underlying class does not have
* a canonical name (i.e., if it is a local or anonymous class or
* an array whose component type does not have a canonical name).
* Returns the canonical name of the underlying class as
* defined by <cite>The Java&trade; Language Specification</cite>.
* Returns {@code null} if the underlying class does not have a canonical
* name. Classes without canonical names include:
* <ul>
* <li>a {@linkplain #isLocalClass() local class}
* <li>a {@linkplain #isAnonymousClass() anonymous class}
* <li>a {@linkplain #isHidden() hidden class}
* <li>an array whose component type does not have a canonical name</li>
* </ul>
*
* @return the canonical name of the underlying class if it exists, and
* {@code null} otherwise.
* @since 1.5
@ -1640,7 +1707,7 @@ public final class Class<T> implements java.io.Serializable,
else
return ReflectionData.NULL_SENTINEL;
}
if (isLocalOrAnonymousClass())
if (isHidden() || isLocalOrAnonymousClass())
return ReflectionData.NULL_SENTINEL;
Class<?> enclosingClass = getEnclosingClass();
if (enclosingClass == null) { // top level class
@ -1657,6 +1724,9 @@ public final class Class<T> implements java.io.Serializable,
* Returns {@code true} if and only if the underlying class
* is an anonymous class.
*
* @apiNote
* An anonymous class is not a {@linkplain #isHidden() hidden class}.
*
* @return {@code true} if and only if this class is an anonymous class.
* @since 1.5
*/
@ -2882,6 +2952,11 @@ public final class Class<T> implements java.io.Serializable,
if (sm != null) {
sm.checkPermission(SecurityConstants.GET_PD_PERMISSION);
}
return protectionDomain();
}
// package-private
java.security.ProtectionDomain protectionDomain() {
java.security.ProtectionDomain pd = getProtectionDomain0();
if (pd == null) {
if (allPermDomain == null) {
@ -2896,7 +2971,6 @@ public final class Class<T> implements java.io.Serializable,
return pd;
}
/**
* Returns the ProtectionDomain of this class.
*/
@ -2968,10 +3042,7 @@ public final class Class<T> implements java.io.Serializable,
*/
private String resolveName(String name) {
if (!name.startsWith("/")) {
Class<?> c = this;
while (c.isArray()) {
c = c.getComponentType();
}
Class<?> c = isArray() ? elementType() : this;
String baseName = c.getPackageName();
if (baseName != null && !baseName.isEmpty()) {
name = baseName.replace('.', '/') + "/" + name;
@ -4042,30 +4113,23 @@ public final class Class<T> implements java.io.Serializable,
/**
* Returns the nest host of the <a href=#nest>nest</a> to which the class
* or interface represented by this {@code Class} object belongs.
* Every class and interface is a member of exactly one nest.
* A class or interface that is not recorded as belonging to a nest
* belongs to the nest consisting only of itself, and is the nest
* host.
* Every class and interface belongs to exactly one nest.
*
* <p>Each of the {@code Class} objects representing array types,
* primitive types, and {@code void} returns {@code this} to indicate
* that the represented entity belongs to the nest consisting only of
* If the nest host of this class or interface has previously
* been determined, then this method returns the nest host.
* If the nest host of this class or interface has
* not previously been determined, then this method determines the nest
* host using the algorithm of JVMS 5.4.4, and returns it.
*
* Often, a class or interface belongs to a nest consisting only of itself,
* in which case this method returns {@code this} to indicate that the class
* or interface is the nest host.
*
* <p>If this {@code Class} object represents a primitive type, an array type,
* or {@code void}, then this method returns {@code this},
* indicating that the represented entity belongs to the nest consisting only of
* itself, and is the nest host.
*
* <p>If there is a {@linkplain LinkageError linkage error} accessing
* the nest host, or if this class or interface is not enumerated as
* a member of the nest by the nest host, then it is considered to belong
* to its own nest and {@code this} is returned as the host.
*
* @apiNote A {@code class} file of version 55.0 or greater may record the
* host of the nest to which it belongs by using the {@code NestHost}
* attribute (JVMS {@jvms 4.7.28}). Alternatively, a {@code class} file of
* version 55.0 or greater may act as a nest host by enumerating the nest's
* other members with the
* {@code NestMembers} attribute (JVMS {@jvms 4.7.29}).
* A {@code class} file of version 54.0 or lower does not use these
* attributes.
*
* @return the nest host of this class or interface
*
* @throws SecurityException
@ -4085,17 +4149,9 @@ public final class Class<T> implements java.io.Serializable,
if (isPrimitive() || isArray()) {
return this;
}
Class<?> host;
try {
host = getNestHost0();
} catch (LinkageError e) {
// if we couldn't load our nest-host then we
// act as-if we have no nest-host attribute
return this;
}
// if null then nest membership validation failed, so we
// act as-if we have no nest-host attribute
if (host == null || host == this) {
Class<?> host = getNestHost0();
if (host == this) {
return this;
}
// returning a different class requires a security check
@ -4127,11 +4183,8 @@ public final class Class<T> implements java.io.Serializable,
c.isPrimitive() || c.isArray()) {
return false;
}
try {
return getNestHost0() == c.getNestHost0();
} catch (LinkageError e) {
return false;
}
return getNestHost() == c.getNestHost();
}
private native Class<?>[] getNestMembers0();
@ -4140,39 +4193,47 @@ public final class Class<T> implements java.io.Serializable,
* Returns an array containing {@code Class} objects representing all the
* classes and interfaces that are members of the nest to which the class
* or interface represented by this {@code Class} object belongs.
* The {@linkplain #getNestHost() nest host} of that nest is the zeroth
* element of the array. Subsequent elements represent any classes or
* interfaces that are recorded by the nest host as being members of
* the nest; the order of such elements is unspecified. Duplicates are
* permitted.
* If the nest host of that nest does not enumerate any members, then the
* array has a single element containing {@code this}.
*
* <p>Each of the {@code Class} objects representing array types,
* primitive types, and {@code void} returns an array containing only
* First, this method obtains the {@linkplain #getNestHost() nest host},
* {@code H}, of the nest to which the class or interface represented by
* this {@code Class} object belongs. The zeroth element of the returned
* array is {@code H}.
*
* Then, for each class or interface {@code C} which is recorded by {@code H}
* as being a member of its nest, this method attempts to obtain the {@code Class}
* object for {@code C} (using {@linkplain #getClassLoader() the defining class
* loader} of the current {@code Class} object), and then obtains the
* {@linkplain #getNestHost() nest host} of the nest to which {@code C} belongs.
* The classes and interfaces which are recorded by {@code H} as being members
* of its nest, and for which {@code H} can be determined as their nest host,
* are indicated by subsequent elements of the returned array. The order of
* such elements is unspecified. Duplicates are permitted.
*
* <p>If this {@code Class} object represents a primitive type, an array type,
* or {@code void}, then this method returns a single-element array containing
* {@code this}.
*
* <p>This method validates that, for each class or interface which is
* recorded as a member of the nest by the nest host, that class or
* interface records itself as a member of that same nest. Any exceptions
* that occur during this validation are rethrown by this method.
* @apiNote
* The returned array includes only the nest members recorded in the {@code NestMembers}
* attribute, and not any hidden classes that were added to the nest via
* {@link MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...)
* Lookup::defineHiddenClass}.
*
* @return an array of all classes and interfaces in the same nest as
* this class
* this class or interface
*
* @throws LinkageError
* If there is any problem loading or validating a nest member or
* its nest host
* @throws SecurityException
* If any returned class is not the current class, and
* if a security manager, <i>s</i>, is present and the caller's
* class loader is not the same as or an ancestor of the class
* loader for that returned class and invocation of {@link
* SecurityManager#checkPackageAccess s.checkPackageAccess()}
* denies access to the package of that returned class
* If any returned class is not the current class, and
* if a security manager, <i>s</i>, is present and the caller's
* class loader is not the same as or an ancestor of the class
* loader for that returned class and invocation of {@link
* SecurityManager#checkPackageAccess s.checkPackageAccess()}
* denies access to the package of that returned class
*
* @since 11
* @see #getNestHost()
* @jvms 4.7.28 The {@code NestHost} Attribute
* @jvms 4.7.29 The {@code NestMembers} Attribute
*/
@CallerSensitive
public Class<?>[] getNestMembers() {
@ -4196,13 +4257,57 @@ public final class Class<T> implements java.io.Serializable,
}
/**
* Returns the type descriptor string for this class.
* <p>
* Note that this is not a strict inverse of {@link #forName};
* Returns the descriptor string of the entity (class, interface, array class,
* primitive type, or {@code void}) represented by this {@code Class} object.
*
* <p> If this {@code Class} object represents a class or interface,
* not an array class, then:
* <ul>
* <li> If the class or interface is not {@linkplain Class#isHidden() hidden},
* then the result is a field descriptor (JVMS {@jvms 4.3.2})
* for the class or interface. Calling
* {@link ClassDesc#ofDescriptor(String) ClassDesc::ofDescriptor}
* with the result descriptor string produces a {@link ClassDesc ClassDesc}
* describing this class or interface.
* <li> If the class or interface is {@linkplain Class#isHidden() hidden},
* then the result is a string of the form:
* <blockquote>
* {@code "L" +} <em>N</em> {@code + "." + <suffix> + ";"}
* </blockquote>
* where <em>N</em> is the <a href="ClassLoader.html#binary-name">binary name</a>
* encoded in internal form indicated by the {@code class} file passed to
* {@link MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...)
* Lookup::defineHiddenClass}, and {@code <suffix>} is an unqualified name.
* A hidden class or interface has no {@linkplain ClassDesc nominal descriptor}.
* The result string is not a type descriptor.
* </ul>
*
* <p> If this {@code Class} object represents an array class, then
* the result is a string consisting of one or more '{@code [}' characters
* representing the depth of the array nesting, followed by the
* descriptor string of the element type.
* <ul>
* <li> If the element type is not a {@linkplain Class#isHidden() hidden} class
* or interface, then this array class can be described nominally.
* Calling {@link ClassDesc#ofDescriptor(String) ClassDesc::ofDescriptor}
* with the result descriptor string produces a {@link ClassDesc ClassDesc}
* describing this array class.
* <li> If the element type is a {@linkplain Class#isHidden() hidden} class or
* interface, then this array class cannot be described nominally.
* The result string is not a type descriptor.
* </ul>
*
* <p> If this {@code Class} object represents a primitive type or
* {@code void}, then the result is a field descriptor string which
* is a one-letter code corresponding to a primitive type or {@code void}
* ({@code "B", "C", "D", "F", "I", "J", "S", "Z", "V"}) (JVMS {@jvms 4.3.2}).
*
* @apiNote
* This is not a strict inverse of {@link #forName};
* distinct classes which share a common name but have different class loaders
* will have identical descriptor strings.
*
* @return the type descriptor representation
* @return the descriptor string for this {@code Class} object
* @jvms 4.3.2 Field Descriptors
* @since 12
*/
@ -4210,10 +4315,15 @@ public final class Class<T> implements java.io.Serializable,
public String descriptorString() {
if (isPrimitive())
return Wrapper.forPrimitiveType(this).basicTypeString();
else if (isArray()) {
if (isArray()) {
return "[" + componentType.descriptorString();
}
else {
} else if (isHidden()) {
String name = getName();
int index = name.indexOf('/');
return "L" + name.substring(0, index).replace('.', '/')
+ "." + name.substring(index+1) + ";";
} else {
return "L" + getName().replace('.', '/') + ";";
}
}
@ -4256,6 +4366,20 @@ public final class Class<T> implements java.io.Serializable,
*/
@Override
public Optional<ClassDesc> describeConstable() {
return Optional.of(ClassDesc.ofDescriptor(descriptorString()));
}
Class<?> c = isArray() ? elementType() : this;
return c.isHidden() ? Optional.empty()
: Optional.of(ClassDesc.ofDescriptor(descriptorString()));
}
/**
* Returns {@code true} if and only if the underlying class is a hidden class.
*
* @return {@code true} if and only if this class is a hidden class.
*
* @since 15
* @see MethodHandles.Lookup#defineHiddenClass
*/
@HotSpotIntrinsicCandidate
public native boolean isHidden();
}

@ -1115,6 +1115,29 @@ public abstract class ClassLoader {
int off, int len, ProtectionDomain pd,
String source);
/**
* Defines a class of the given flags via Lookup.defineClass.
*
* @param loader the defining loader
* @param lookup nest host of the Class to be defined
* @param name the binary name or {@code null} if not findable
* @param b class bytes
* @param off the start offset in {@code b} of the class bytes
* @param len the length of the class bytes
* @param pd protection domain
* @param initialize initialize the class
* @param flags flags
* @param classData class data
*/
static native Class<?> defineClass0(ClassLoader loader,
Class<?> lookup,
String name,
byte[] b, int off, int len,
ProtectionDomain pd,
boolean initialize,
int flags,
Object classData);
// true if the name is null or has the potential to be a valid binary name
private boolean checkName(String name) {
if ((name == null) || (name.isEmpty()))

@ -28,6 +28,10 @@ package java.lang;
import jdk.internal.misc.Unsafe;
import jdk.internal.vm.annotation.ForceInline;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
/**
* Helper for string concatenation. These methods are mostly looked up with private lookups
* from {@link java.lang.invoke.StringConcatFactory}, and used in {@link java.lang.invoke.MethodHandle}
@ -466,4 +470,13 @@ final class StringConcatHelper {
return String.COMPACT_STRINGS ? LATIN1 : UTF16;
}
static MethodHandle lookupStatic(String name, MethodType methodType) {
try {
return MethodHandles.lookup().findStatic(StringConcatHelper.class, name, methodType);
} catch (NoSuchMethodException|IllegalAccessException e) {
throw new AssertionError(e);
}
}
}

@ -35,6 +35,8 @@ import java.io.InputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.lang.module.ModuleDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
@ -2175,6 +2177,10 @@ public final class System {
public Class<?> defineClass(ClassLoader loader, String name, byte[] b, ProtectionDomain pd, String source) {
return ClassLoader.defineClass1(loader, name, b, 0, b.length, pd, source);
}
public Class<?> defineClass(ClassLoader loader, Class<?> lookup, String name, byte[] b, ProtectionDomain pd,
boolean initialize, int flags, Object classData) {
return ClassLoader.defineClass0(loader, lookup, name, b, 0, b.length, pd, initialize, flags, classData);
}
public Class<?> findBootstrapClassOrNull(ClassLoader cl, String name) {
return cl.findBootstrapClassOrNull(name);
}
@ -2257,6 +2263,18 @@ public final class System {
public void setCause(Throwable t, Throwable cause) {
t.setCause(cause);
}
public ProtectionDomain protectionDomain(Class<?> c) {
return c.protectionDomain();
}
public MethodHandle stringConcatHelper(String name, MethodType methodType) {
return StringConcatHelper.lookupStatic(name, methodType);
}
public Object classData(Class<?> c) {
return c.getClassData();
}
});
}
}

@ -51,6 +51,7 @@ import static sun.invoke.util.Wrapper.isWrapperType;
* System.out.printf(">>> %s\n", iii.foo(44));
* }}
*/
final MethodHandles.Lookup caller; // The caller's lookup context
final Class<?> targetClass; // The class calling the meta-factory via invokedynamic "class X"
final MethodType invokedType; // The type of the invoked method "(CC)II"
final Class<?> samBase; // The type of the returned instance "interface JJ"
@ -120,6 +121,7 @@ import static sun.invoke.util.Wrapper.isWrapperType;
"Invalid caller: %s",
caller.lookupClass().getName()));
}
this.caller = caller;
this.targetClass = caller.lookupClass();
this.invokedType = invokedType;
@ -143,8 +145,20 @@ import static sun.invoke.util.Wrapper.isWrapperType;
case REF_invokeSpecial:
// JDK-8172817: should use referenced class here, but we don't know what it was
this.implClass = implInfo.getDeclaringClass();
this.implKind = REF_invokeSpecial;
this.implIsInstanceMethod = true;
// Classes compiled prior to dynamic nestmate support invokes a private instance
// method with REF_invokeSpecial.
//
// invokespecial should only be used to invoke private nestmate constructors.
// The lambda proxy class will be defined as a nestmate of targetClass.
// If the method to be invoked is an instance method of targetClass, then
// convert to use invokevirtual or invokeinterface.
if (targetClass == implClass && !implInfo.getName().equals("<init>")) {
this.implKind = implClass.isInterface() ? REF_invokeInterface : REF_invokeVirtual;
} else {
this.implKind = REF_invokeSpecial;
}
break;
case REF_invokeStatic:
case REF_newInvokeSpecial:

@ -196,24 +196,20 @@ class GenerateJLIClassesHelper {
private static byte[] generateCodeBytesForLFs(String className,
String[] names, LambdaForm[] forms) {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
cw.visit(Opcodes.V1_8, Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER,
className, null, InvokerBytecodeGenerator.INVOKER_SUPER_NAME, null);
cw.visitSource(className.substring(className.lastIndexOf('/') + 1), null);
for (int i = 0; i < forms.length; i++) {
addMethod(className, names[i], forms[i],
forms[i].methodType(), cw);
InvokerBytecodeGenerator g
= new InvokerBytecodeGenerator(className, names[i], forms[i], forms[i].methodType());
g.setClassWriter(cw);
g.addMethod();
}
return cw.toByteArray();
}
private static void addMethod(String className, String methodName, LambdaForm form,
MethodType type, ClassWriter cw) {
InvokerBytecodeGenerator g
= new InvokerBytecodeGenerator(className, methodName, form, type);
g.setClassWriter(cw);
g.addMethod();
return cw.toByteArray();
}
private static LambdaForm makeReinvokerFor(MethodType type) {

@ -27,13 +27,14 @@ package java.lang.invoke;
import jdk.internal.org.objectweb.asm.*;
import sun.invoke.util.BytecodeDescriptor;
import jdk.internal.misc.Unsafe;
import sun.security.action.GetPropertyAction;
import sun.security.action.GetBooleanAction;
import java.io.FilePermission;
import java.io.Serializable;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.LinkedHashSet;
@ -41,6 +42,8 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.PropertyPermission;
import java.util.Set;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
/**
@ -50,13 +53,10 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
* @see LambdaMetafactory
*/
/* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
private static final int CLASSFILE_VERSION = 52;
private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
private static final String JAVA_LANG_OBJECT = "java/lang/Object";
private static final String NAME_CTOR = "<init>";
private static final String NAME_FACTORY = "get$Lambda";
//Serialization support
private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
@ -64,13 +64,17 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
private static final String DESCR_METHOD_WRITE_OBJECT = "(Ljava/io/ObjectOutputStream;)V";
private static final String DESCR_METHOD_READ_OBJECT = "(Ljava/io/ObjectInputStream;)V";
private static final String DESCR_SET_IMPL_METHOD = "(Ljava/lang/invoke/MethodHandle;)V";
private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
private static final String NAME_METHOD_READ_OBJECT = "readObject";
private static final String NAME_METHOD_WRITE_OBJECT = "writeObject";
private static final String NAME_FIELD_IMPL_METHOD = "protectedImplMethod";
private static final String DESCR_CLASS = "Ljava/lang/Class;";
private static final String DESCR_STRING = "Ljava/lang/String;";
private static final String DESCR_OBJECT = "Ljava/lang/Object;";
private static final String DESCR_METHOD_HANDLE = "Ljava/lang/invoke/MethodHandle;";
private static final String DESCR_CTOR_SERIALIZED_LAMBDA
= "(" + DESCR_CLASS + DESCR_STRING + DESCR_STRING + DESCR_STRING + "I"
+ DESCR_STRING + DESCR_STRING + DESCR_STRING + DESCR_STRING + "[" + DESCR_OBJECT + ")V";
@ -78,8 +82,6 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
private static final String DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION = "(Ljava/lang/String;)V";
private static final String[] SER_HOSTILE_EXCEPTIONS = new String[] {NAME_NOT_SERIALIZABLE_EXCEPTION};
private static final String DESCR_HIDDEN = "Ljdk/internal/vm/annotation/Hidden;";
private static final String[] EMPTY_STRING_ARRAY = new String[0];
// Used to ensure that each spun class name is unique
@ -108,6 +110,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
private final String[] argNames; // Generated names for the constructor arguments
private final String[] argDescs; // Type descriptors for the constructor arguments
private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1"
private final boolean useImplMethodHandle; // use MethodHandle invocation instead of symbolic bytecode invocation
/**
* General meta-factory constructor, supporting both standard cases and
@ -163,7 +166,9 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
implMethodName = implInfo.getName();
implMethodDesc = implInfo.getMethodType().toMethodDescriptorString();
constructorType = invokedType.changeReturnType(Void.TYPE);
lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
lambdaClassName = lambdaClassName(targetClass);
useImplMethodHandle = !implClass.getPackageName().equals(implInfo.getDeclaringClass().getPackageName())
&& !Modifier.isPublic(implInfo.getModifiers());
cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
int parameterCount = invokedType.parameterCount();
if (parameterCount > 0) {
@ -178,6 +183,15 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
}
}
private static String lambdaClassName(Class<?> targetClass) {
String name = targetClass.getName();
if (targetClass.isHidden()) {
// use the original class name
name = name.replace('/', '_');
}
return name.replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
}
/**
* Build the CallSite. Generate a class file which implements the functional
* interface, define the class, if there are no parameters create an instance
@ -217,20 +231,14 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
try {
Object inst = ctrs[0].newInstance();
return new ConstantCallSite(MethodHandles.constant(samBase, inst));
}
catch (ReflectiveOperationException e) {
} catch (ReflectiveOperationException e) {
throw new LambdaConversionException("Exception instantiating lambda object", e);
}
} else {
try {
if (!disableEagerInitialization) {
UNSAFE.ensureClassInitialized(innerClass);
}
return new ConstantCallSite(
MethodHandles.Lookup.IMPL_LOOKUP
.findStatic(innerClass, NAME_FACTORY, invokedType));
}
catch (ReflectiveOperationException e) {
MethodHandle mh = caller.findConstructor(innerClass, invokedType.changeReturnType(void.class));
return new ConstantCallSite(mh.asType(invokedType));
} catch (ReflectiveOperationException e) {
throw new LambdaConversionException("Exception finding constructor", e);
}
}
@ -283,14 +291,9 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
generateConstructor();
if (invokedType.parameterCount() != 0 || disableEagerInitialization) {
generateFactory();
}
// Forward the SAM method
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
samMethodType.toMethodDescriptorString(), null, null);
mv.visitAnnotation(DESCR_HIDDEN, true);
new ForwardingMethodGenerator(mv).generate(samMethodType);
// Forward the bridges
@ -298,11 +301,18 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
for (MethodType mt : additionalBridges) {
mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
mt.toMethodDescriptorString(), null, null);
mv.visitAnnotation(DESCR_HIDDEN, true);
new ForwardingMethodGenerator(mv).generate(mt);
}
}
if (useImplMethodHandle) {
FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_STATIC,
NAME_FIELD_IMPL_METHOD,
DESCR_METHOD_HANDLE,
null, null);
fv.visitEnd();
}
if (isSerializable)
generateSerializationFriendlyMethods();
else if (accidentallySerializable)
@ -313,7 +323,6 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
// Define the generated class in this VM.
final byte[] classBytes = cw.toByteArray();
// If requested, dump out to a file for debugging purposes
if (dumper != null) {
AccessController.doPrivileged(new PrivilegedAction<>() {
@ -327,28 +336,26 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
// createDirectories may need it
new PropertyPermission("user.dir", "read"));
}
return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
}
/**
* Generate the factory method for the class
*/
private void generateFactory() {
MethodVisitor m = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, NAME_FACTORY, invokedType.toMethodDescriptorString(), null, null);
m.visitCode();
m.visitTypeInsn(NEW, lambdaClassName);
m.visitInsn(Opcodes.DUP);
int parameterCount = invokedType.parameterCount();
for (int typeIndex = 0, varIndex = 0; typeIndex < parameterCount; typeIndex++) {
Class<?> argType = invokedType.parameterType(typeIndex);
m.visitVarInsn(getLoadOpcode(argType), varIndex);
varIndex += getParameterSize(argType);
try {
// this class is linked at the indy callsite; so define a hidden nestmate
Lookup lookup = caller.defineHiddenClass(classBytes, !disableEagerInitialization, NESTMATE, STRONG);
if (useImplMethodHandle) {
// If the target class invokes a method reference this::m which is
// resolved to a protected method inherited from a superclass in a different
// package, the target class does not have a bridge and this method reference
// has been changed from public to protected after the target class was compiled.
// This lambda proxy class has no access to the resolved method.
// So this workaround by passing the live implMethod method handle
// to the proxy class to invoke directly.
MethodHandle mh = lookup.findStaticSetter(lookup.lookupClass(), NAME_FIELD_IMPL_METHOD, MethodHandle.class);
mh.invokeExact(implMethod);
}
return lookup.lookupClass();
} catch (IllegalAccessException e) {
throw new LambdaConversionException("Exception defining lambda proxy class", e);
} catch (Throwable t) {
throw new InternalError(t);
}
m.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorType.toMethodDescriptorString(), false);
m.visitInsn(ARETURN);
m.visitMaxs(-1, -1);
m.visitEnd();
}
/**
@ -464,6 +471,10 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
visitTypeInsn(NEW, implMethodClassName);
visitInsn(DUP);
}
if (useImplMethodHandle) {
visitVarInsn(ALOAD, 0);
visitFieldInsn(GETSTATIC, lambdaClassName, NAME_FIELD_IMPL_METHOD, DESCR_METHOD_HANDLE);
}
for (int i = 0; i < argNames.length; i++) {
visitVarInsn(ALOAD, 0);
visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
@ -471,11 +482,16 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
convertArgumentTypes(methodType);
// Invoke the method we want to forward to
visitMethodInsn(invocationOpcode(), implMethodClassName,
implMethodName, implMethodDesc,
implClass.isInterface());
if (useImplMethodHandle) {
MethodType mtype = implInfo.getMethodType().insertParameterTypes(0, implClass);
visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle",
"invokeExact", mtype.descriptorString(), false);
} else {
// Invoke the method we want to forward to
visitMethodInsn(invocationOpcode(), implMethodClassName,
implMethodName, implMethodDesc,
implClass.isInterface());
}
// Convert the return value (if any) and return it
// Note: if adapting from non-void to void, the 'return'
// instruction will pop the unneeded result

@ -26,6 +26,7 @@
package java.lang.invoke;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.FieldVisitor;
import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
@ -42,6 +43,7 @@ import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Stream;
import static java.lang.invoke.LambdaForm.BasicType;
@ -49,6 +51,7 @@ import static java.lang.invoke.LambdaForm.BasicType.*;
import static java.lang.invoke.LambdaForm.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandles.Lookup.*;
/**
* Code generation backend for LambdaForm.
@ -67,6 +70,8 @@ class InvokerBytecodeGenerator {
private static final String LOOP_CLAUSES = MHI + "$LoopClauses";
private static final String MHARY2 = "[[L" + MH + ";";
private static final String MH_SIG = "L" + MH + ";";
private static final String LF_SIG = "L" + LF + ";";
private static final String LFN_SIG = "L" + LFN + ";";
@ -92,6 +97,7 @@ class InvokerBytecodeGenerator {
/** ASM bytecode generation. */
private ClassWriter cw;
private MethodVisitor mv;
private final List<ClassData> classData = new ArrayList<>();
/** Single element internal class name lookup cache. */
private Class<?> lastClass;
@ -99,6 +105,15 @@ class InvokerBytecodeGenerator {
private static final MemberName.Factory MEMBERNAME_FACTORY = MemberName.getFactory();
private static final Class<?> HOST_CLASS = LambdaForm.class;
private static final MethodHandles.Lookup LOOKUP = lookup();
private static MethodHandles.Lookup lookup() {
try {
return MethodHandles.privateLookupIn(HOST_CLASS, IMPL_LOOKUP);
} catch (IllegalAccessException e) {
throw newInternalError(e);
}
}
/** Main constructor; other constructors delegate to this one. */
private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize,
@ -221,41 +236,52 @@ class InvokerBytecodeGenerator {
return className;
}
class CpPatch {
final int index;
public static class ClassData {
final String name;
final String desc;
final Object value;
CpPatch(int index, Object value) {
this.index = index;
ClassData(String name, String desc, Object value) {
this.name = name;
this.desc = desc;
this.value = value;
}
public String name() { return name; }
public String toString() {
return "CpPatch/index="+index+",value="+value;
return name + ",value="+value;
}
}
private final ArrayList<CpPatch> cpPatches = new ArrayList<>();
String classData(Object arg) {
String desc;
if (arg instanceof Class) {
desc = "Ljava/lang/Class;";
} else if (arg instanceof MethodHandle) {
desc = MH_SIG;
} else if (arg instanceof LambdaForm) {
desc = LF_SIG;
} else {
desc = "Ljava/lang/Object;";
}
private int cph = 0; // for counting constant placeholders
String constantPlaceholder(Object arg) {
String cpPlaceholder = "CONSTANT_PLACEHOLDER_" + cph++;
if (DUMP_CLASS_FILES) cpPlaceholder += " <<" + debugString(arg) + ">>";
// TODO check if arg is already in the constant pool
// insert placeholder in CP and remember the patch
int index = cw.newConst((Object) cpPlaceholder);
cpPatches.add(new CpPatch(index, arg));
return cpPlaceholder;
Class<?> c = arg.getClass();
while (c.isArray()) {
c = c.getComponentType();
}
// unique static variable name
String name = "_DATA_" + c.getSimpleName() + "_" + classData.size();
ClassData cd = new ClassData(name, desc, arg);
classData.add(cd);
return cd.name();
}
Object[] cpPatches(byte[] classFile) {
int size = getConstantPoolSize(classFile);
Object[] res = new Object[size];
for (CpPatch p : cpPatches) {
if (p.index >= size)
throw new InternalError("in cpool["+size+"]: "+p+"\n"+Arrays.toString(Arrays.copyOf(classFile, 20)));
res[p.index] = p.value;
List<Object> classDataValues() {
Object[] data = new Object[classData.size()];
for (int i = 0; i < classData.size(); i++) {
data[i] = classData.get(i).value;
}
return res;
return List.of(data);
}
private static String debugString(Object arg) {
@ -288,19 +314,11 @@ class InvokerBytecodeGenerator {
* Extract the MemberName of a newly-defined method.
*/
private MemberName loadMethod(byte[] classFile) {
Class<?> invokerClass = loadAndInitializeInvokerClass(classFile, cpPatches(classFile));
Class<?> invokerClass = LOOKUP.makeHiddenClassDefiner(classFile)
.defineClass(true, classDataValues());
return resolveInvokerMember(invokerClass, invokerName, invokerType);
}
/**
* Define a given class as anonymous class in the runtime system.
*/
private static Class<?> loadAndInitializeInvokerClass(byte[] classBytes, Object[] patches) {
Class<?> invokerClass = UNSAFE.defineAnonymousClass(HOST_CLASS, classBytes, patches);
UNSAFE.ensureClassInitialized(invokerClass); // Make sure the class is initialized; VM might complain.
return invokerClass;
}
private static MemberName resolveInvokerMember(Class<?> invokerClass, String name, MethodType type) {
MemberName member = new MemberName(invokerClass, name, type, REF_invokeStatic);
try {
@ -316,7 +334,8 @@ class InvokerBytecodeGenerator {
*/
private ClassWriter classFilePrologue() {
final int NOT_ACC_PUBLIC = 0; // not ACC_PUBLIC
cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
setClassWriter(cw);
cw.visit(Opcodes.V1_8, NOT_ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER,
CLASS_PREFIX + className, null, INVOKER_SUPER_NAME, null);
cw.visitSource(SOURCE_PREFIX + className, null);
@ -336,6 +355,51 @@ class InvokerBytecodeGenerator {
mv.visitEnd();
}
private String className() {
return CLASS_PREFIX + className;
}
private void clinit() {
clinit(cw, className(), classData);
}
/*
* <clinit> to initialize the static final fields with the live class data
* LambdaForms can't use condy due to bootstrapping issue.
*/
static void clinit(ClassWriter cw, String className, List<ClassData> classData) {
if (classData.isEmpty())
return;
for (ClassData p : classData) {
// add the static field
FieldVisitor fv = cw.visitField(Opcodes.ACC_STATIC|Opcodes.ACC_FINAL, p.name, p.desc, null, null);
fv.visitEnd();
}
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_STATIC, "<clinit>", "()V", null, null);
mv.visitCode();
mv.visitLdcInsn(Type.getType("L" + className + ";"));
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/invoke/MethodHandleNatives",
"classData", "(Ljava/lang/Class;)Ljava/lang/Object;", false);
// we should optimize one single element case that does not need to create a List
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/util/List");
mv.visitVarInsn(Opcodes.ASTORE, 0);
int index = 0;
for (ClassData p : classData) {
// initialize the static field
mv.visitVarInsn(Opcodes.ALOAD, 0);
emitIconstInsn(mv, index++);
mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/List",
"get", "(I)Ljava/lang/Object;", true);
mv.visitTypeInsn(Opcodes.CHECKCAST, p.desc.substring(1, p.desc.length()-1));
mv.visitFieldInsn(Opcodes.PUTSTATIC, className, p.name, p.desc);
}
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(2, 1);
mv.visitEnd();
}
/*
* Low-level emit helpers.
*/
@ -408,6 +472,10 @@ class InvokerBytecodeGenerator {
}
private void emitIconstInsn(final int cst) {
emitIconstInsn(mv, cst);
}
private static void emitIconstInsn(MethodVisitor mv, int cst) {
if (cst >= -1 && cst <= 5) {
mv.visitInsn(Opcodes.ICONST_0 + cst);
} else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
@ -577,8 +645,7 @@ class InvokerBytecodeGenerator {
String sig = getInternalName(cls);
mv.visitTypeInsn(Opcodes.CHECKCAST, sig);
} else {
mv.visitLdcInsn(constantPlaceholder(cls));
mv.visitTypeInsn(Opcodes.CHECKCAST, CLS);
mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(cls), "Ljava/lang/Class;");
mv.visitInsn(Opcodes.SWAP);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CLS, "cast", LL_SIG, false);
if (Object[].class.isAssignableFrom(cls))
@ -737,6 +804,7 @@ class InvokerBytecodeGenerator {
private byte[] generateCustomizedCodeBytes() {
classFilePrologue();
addMethod();
clinit();
bogusMethod(lambdaForm);
final byte[] classFile = toByteArray();
@ -764,14 +832,14 @@ class InvokerBytecodeGenerator {
mv.visitAnnotation(DONTINLINE_SIG, true);
}
constantPlaceholder(lambdaForm); // keep LambdaForm instance & its compiled form lifetime tightly coupled.
classData(lambdaForm); // keep LambdaForm instance & its compiled form lifetime tightly coupled.
if (lambdaForm.customized != null) {
// Since LambdaForm is customized for a particular MethodHandle, it's safe to substitute
// receiver MethodHandle (at slot #0) with an embedded constant and use it instead.
// It enables more efficient code generation in some situations, since embedded constants
// are compile-time constants for JIT compiler.
mv.visitLdcInsn(constantPlaceholder(lambdaForm.customized));
mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(lambdaForm.customized), MH_SIG);
mv.visitTypeInsn(Opcodes.CHECKCAST, MH);
assert(checkActualReceiver()); // expects MethodHandle on top of the stack
mv.visitVarInsn(Opcodes.ASTORE, localsMap[0]);
@ -901,7 +969,7 @@ class InvokerBytecodeGenerator {
// push receiver
MethodHandle target = name.function.resolvedHandle();
assert(target != null) : name.exprString();
mv.visitLdcInsn(constantPlaceholder(target));
mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(target), MH_SIG);
emitReferenceCast(MethodHandle.class, target);
} else {
// load receiver
@ -957,7 +1025,9 @@ class InvokerBytecodeGenerator {
return false; // inner class of some sort
if (cls.getClassLoader() != MethodHandle.class.getClassLoader())
return false; // not on BCP
if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: switch to supported API once it is added
if (cls.isHidden())
return false;
if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: Unsafe::defineAnonymousClass to be removed
return false;
if (!isStaticallyInvocableType(member.getMethodOrFieldType()))
return false;
@ -981,14 +1051,16 @@ class InvokerBytecodeGenerator {
if (cls == Object.class)
return true;
if (MethodHandle.class.isAssignableFrom(cls)) {
assert(!ReflectUtil.isVMAnonymousClass(cls));
assert(!cls.isHidden());
return true;
}
while (cls.isArray())
cls = cls.getComponentType();
if (cls.isPrimitive())
return true; // int[].class, for example
if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: switch to supported API once it is added
if (cls.isHidden())
return false;
if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: Unsafe::defineAnonymousClass to be removed
return false;
// could use VerifyAccess.isClassAccessible but the following is a safe approximation
if (cls.getClassLoader() != Object.class.getClassLoader())
@ -1060,7 +1132,7 @@ class InvokerBytecodeGenerator {
}
assert(java.lang.reflect.Array.getLength(emptyArray) == 0);
assert(emptyArray.getClass() == rtype); // exact typing
mv.visitLdcInsn(constantPlaceholder(emptyArray));
mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(emptyArray), "Ljava/lang/Object;");
emitReferenceCast(rtype, emptyArray);
return;
}
@ -1623,7 +1695,7 @@ class InvokerBytecodeGenerator {
if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
emitConst(arg);
} else {
mv.visitLdcInsn(constantPlaceholder(arg));
mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(arg), "Ljava/lang/Object;");
emitImplicitConversion(L_TYPE, ptype, arg);
}
}
@ -1815,6 +1887,7 @@ class InvokerBytecodeGenerator {
emitReturnInsn(basicType(rtype));
methodEpilogue();
clinit();
bogusMethod(invokerType);
final byte[] classFile = cw.toByteArray();
@ -1883,6 +1956,7 @@ class InvokerBytecodeGenerator {
emitReturnInsn(L_TYPE); // NOTE: NamedFunction invokers always return a reference value.
methodEpilogue();
clinit();
bogusMethod(dstType);
final byte[] classFile = cw.toByteArray();

@ -27,7 +27,6 @@ package java.lang.invoke;
import jdk.internal.access.JavaLangInvokeAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.reflect.CallerSensitive;
@ -40,6 +39,7 @@ import sun.invoke.util.ValueConversions;
import sun.invoke.util.VerifyType;
import sun.invoke.util.Wrapper;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Array;
import java.nio.ByteOrder;
import java.util.Arrays;
@ -1157,10 +1157,24 @@ abstract class MethodHandleImpl {
return restoreToType(bccInvoker.bindTo(vamh), mh, hostClass);
}
private static MethodHandle makeInjectedInvoker(Class<?> hostClass) {
private static MethodHandle makeInjectedInvoker(Class<?> targetClass) {
try {
Class<?> invokerClass = UNSAFE.defineAnonymousClass(hostClass, INJECTED_INVOKER_TEMPLATE, null);
assert checkInjectedInvoker(hostClass, invokerClass);
/*
* The invoker class defined to the same class loader as the lookup class
* but in an unnamed package so that the class bytes can be cached and
* reused for any @CSM.
*
* @CSM must be public and exported if called by any module.
*/
String name = targetClass.getName() + "$$InjectedInvoker";
if (targetClass.isHidden()) {
// use the original class name
name = name.replace('/', '_');
}
Class<?> invokerClass = new Lookup(targetClass)
.makeHiddenClassDefiner(name, INJECTED_INVOKER_TEMPLATE)
.defineClass(true);
assert checkInjectedInvoker(targetClass, invokerClass);
return IMPL_LOOKUP.findStatic(invokerClass, "invoke_V", INVOKER_MT);
} catch (ReflectiveOperationException ex) {
throw uncaughtException(ex);
@ -1256,10 +1270,6 @@ abstract class MethodHandleImpl {
"(Ljava/lang/invoke/MethodHandle;[Ljava/lang/Object;)Ljava/lang/Object;",
null, null);
// Suppress invoker method in stack traces.
AnnotationVisitor av0 = mv.visitAnnotation(InvokerBytecodeGenerator.HIDDEN_SIG, true);
av0.visitEnd();
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);

@ -25,6 +25,8 @@
package java.lang.invoke;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.ref.CleanerFactory;
import sun.invoke.util.Wrapper;
@ -137,6 +139,15 @@ class MethodHandleNatives {
REF_newInvokeSpecial = 8,
REF_invokeInterface = 9,
REF_LIMIT = 10;
/**
* Flags for Lookup.ClassOptions
*/
static final int
NESTMATE_CLASS = 0x00000001,
HIDDEN_CLASS = 0x00000002,
STRONG_LOADER_LINK = 0x00000004,
ACCESS_VM_ANNOTATIONS = 0x00000008;
}
static boolean refKindIsValid(int refKind) {
@ -659,4 +670,13 @@ class MethodHandleNatives {
return (definingClass.isAssignableFrom(symbolicRefClass) || // Msym overrides Mdef
symbolicRefClass.isInterface()); // Mdef implements Msym
}
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
/*
* A convenient method for LambdaForms to get the class data of a given class.
* LambdaForms cannot use condy via MethodHandles.classData
*/
static Object classData(Class<?> c) {
return JLA.classData(c);
}
}

@ -25,9 +25,12 @@
package java.lang.invoke;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.VM;
import jdk.internal.module.IllegalAccessLogger;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.vm.annotation.ForceInline;
@ -45,8 +48,6 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ReflectPermission;
import java.nio.ByteOrder;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
@ -219,6 +220,10 @@ public class MethodHandles {
* @see <a href="MethodHandles.Lookup.html#cross-module-lookup">Cross-module lookups</a>
*/
public static Lookup privateLookupIn(Class<?> targetClass, Lookup caller) throws IllegalAccessException {
if (caller.allowedModes == Lookup.TRUSTED) {
return new Lookup(targetClass);
}
SecurityManager sm = System.getSecurityManager();
if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
if (targetClass.isPrimitive())
@ -262,6 +267,57 @@ public class MethodHandles {
return Lookup.newLookup(targetClass, newPreviousClass, newModes);
}
/**
* Returns the <em>class data</em> associated with the lookup class
* of the specified {@code Lookup} object, or {@code null}.
*
* <p> Classes can be created with class data by calling
* {@link Lookup#defineHiddenClassWithClassData(byte[], Object, Lookup.ClassOption...)
* Lookup::defineHiddenClassWithClassData}.
* A hidden class with a class data behaves as if the hidden class
* has a private static final unnamed field pre-initialized with
* the class data and this method is equivalent as if calling
* {@link ConstantBootstraps#getStaticFinal(Lookup, String, Class)} to
* obtain the value of such field corresponding to the class data.
*
* <p> The {@linkplain Lookup#lookupModes() lookup modes} for this lookup
* must have {@link Lookup#ORIGINAL ORIGINAL} access in order to retrieve
* the class data.
*
* @apiNote
* This method can be called as a bootstrap method for a dynamically computed
* constant. A framework can create a hidden class with class data, for
* example that can be {@code List.of(o1, o2, o3....)} containing more than
* one live object. The class data is accessible only to the lookup object
* created by the original caller but inaccessible to other members
* in the same nest. If a framework passes security sensitive live objects
* to a hidden class via class data, it is recommended to load the value
* of class data as a dynamically computed constant instead of storing
* the live objects in private fields which are accessible to other
* nestmates.
*
* @param <T> the type to cast the class data object to
* @param caller the lookup context describing the class performing the
* operation (normally stacked by the JVM)
* @param name ignored
* @param type the type of the class data
* @return the value of the class data if present in the lookup class;
* otherwise {@code null}
* @throws IllegalAccessException if the lookup context does not have
* original caller access
* @throws ClassCastException if the class data cannot be converted to
* the specified {@code type}
* @see Lookup#defineHiddenClassWithClassData(byte[], Object, Lookup.ClassOption...)
* @since 15
*/
static <T> T classData(Lookup caller, String name, Class<T> type) throws IllegalAccessException {
if (!caller.hasFullPrivilegeAccess()) {
throw new IllegalAccessException(caller + " does not have full privilege access");
}
Object classData = MethodHandleNatives.classData(caller.lookupClass);
return type.cast(classData);
}
/**
* Performs an unchecked "crack" of a
* <a href="MethodHandleInfo.html#directmh">direct method handle</a>.
@ -517,7 +573,7 @@ public class MethodHandles {
* that the receiver argument must match both the resolved method <em>and</em>
* the current class. Again, this requirement is enforced by narrowing the
* type of the leading parameter to the resulting method handle.
* (See the Java Virtual Machine Specification, section {@jmvs 4.10.1.9}.)
* (See the Java Virtual Machine Specification, section {@jvms 4.10.1.9}.)
* <p>
* The JVM represents constructors and static initializer blocks as internal methods
* with special names ({@code "<init>"} and {@code "<clinit>"}).
@ -1400,8 +1456,6 @@ public class MethodHandles {
*/
Lookup(Class<?> lookupClass) {
this(lookupClass, null, FULL_POWER_MODES);
// make sure we haven't accidentally picked up a privileged class:
checkUnprivilegedlookupClass(lookupClass);
}
private Lookup(Class<?> lookupClass, Class<?> prevLookupClass, int allowedModes) {
@ -1508,7 +1562,7 @@ public class MethodHandles {
}
// Allow nestmate lookups to be created without special privilege:
if ((newModes & PRIVATE) != 0
&& !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) {
&& !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) {
newModes &= ~(PRIVATE|PROTECTED);
}
if ((newModes & (PUBLIC|UNCONDITIONAL)) != 0
@ -1577,9 +1631,12 @@ public class MethodHandles {
}
/**
* Defines a class to the same class loader and in the same runtime package and
* Creates a class or interface from {@code bytes}
* with the same class loader and in the same runtime package and
* {@linkplain java.security.ProtectionDomain protection domain} as this lookup's
* {@linkplain #lookupClass() lookup class}.
* {@linkplain #lookupClass() lookup class} as if calling
* {@link ClassLoader#defineClass(String,byte[],int,int,ProtectionDomain)
* ClassLoader::defineClass}.
*
* <p> The {@linkplain #lookupModes() lookup modes} for this lookup must include
* {@link #PACKAGE PACKAGE} access as default (package) members will be
@ -1602,11 +1659,12 @@ public class MethodHandles {
*
* @param bytes the class bytes
* @return the {@code Class} object for the class
* @throws IllegalAccessException if this lookup does not have {@code PACKAGE} access
* @throws ClassFormatError if {@code bytes} is not a {@code ClassFile} structure
* @throws IllegalArgumentException the bytes are for a class in a different package
* to the lookup class
* @throws IllegalAccessException if this lookup does not have {@code PACKAGE} access
* @throws LinkageError if the class is malformed ({@code ClassFormatError}), cannot be
* verified ({@code VerifyError}), is already defined, or another linkage error occurs
* @throws VerifyError if the newly created class cannot be verified
* @throws LinkageError if the newly created class cannot be linked for any other reason
* @throws SecurityException if a security manager is present and it
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws NullPointerException if {@code bytes} is {@code null}
@ -1617,66 +1675,537 @@ public class MethodHandles {
* @see ClassLoader#defineClass(String,byte[],int,int,ProtectionDomain)
*/
public Class<?> defineClass(byte[] bytes) throws IllegalAccessException {
ensureDefineClassPermission();
if ((lookupModes() & PACKAGE) == 0)
throw new IllegalAccessException("Lookup does not have PACKAGE access");
return makeClassDefiner(bytes.clone()).defineClass(false);
}
private void ensureDefineClassPermission() {
if (allowedModes == TRUSTED) return;
if (!hasFullPrivilegeAccess()) {
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPermission(new RuntimePermission("defineClass"));
}
if ((lookupModes() & PACKAGE) == 0)
throw new IllegalAccessException("Lookup does not have PACKAGE access");
}
// parse class bytes to get class name (in internal form)
bytes = bytes.clone();
String name;
/**
* The set of class options that specify whether a hidden class created by
* {@link Lookup#defineHiddenClass(byte[], boolean, ClassOption...)
* Lookup::defineHiddenClass} method is dynamically added as a new member
* to the nest of a lookup class and/or whether a hidden class has
* a strong relationship with the class loader marked as its defining loader.
*
* @since 15
*/
public enum ClassOption {
/**
* Specifies that a hidden class be added to {@linkplain Class#getNestHost nest}
* of a lookup class as a nestmate.
*
* <p> A hidden nestmate class has access to the private members of all
* classes and interfaces in the same nest.
*
* @see Class#getNestHost()
*/
NESTMATE(NESTMATE_CLASS),
/**
* Specifies that a hidden class has a <em>strong</em>
* relationship with the class loader marked as its defining loader,
* as a normal class or interface has with its own defining loader.
* This means that the hidden class may be unloaded if and only if
* its defining loader is not reachable and thus may be reclaimed
* by a garbage collector (JLS 12.7).
*
* <p> By default, a hidden class or interface may be unloaded
* even if the class loader that is marked as its defining loader is
* <a href="../ref/package.html#reachability">reachable</a>.
*
* @jls 12.7 Unloading of Classes and Interfaces
*/
STRONG(STRONG_LOADER_LINK);
/* the flag value is used by VM at define class time */
private final int flag;
ClassOption(int flag) {
this.flag = flag;
}
static int optionsToFlag(Set<ClassOption> options) {
int flags = 0;
for (ClassOption cp : options) {
flags |= cp.flag;
}
return flags;
}
}
/**
* Creates a <em>hidden</em> class or interface from {@code bytes},
* returning a {@code Lookup} on the newly created class or interface.
*
* <p> Ordinarily, a class or interface {@code C} is created by a class loader,
* which either defines {@code C} directly or delegates to another class loader.
* A class loader defines {@code C} directly by invoking
* {@link ClassLoader#defineClass(String, byte[], int, int, ProtectionDomain)
* ClassLoader::defineClass}, which causes the Java Virtual Machine
* to derive {@code C} from a purported representation in {@code class} file format.
* In situations where use of a class loader is undesirable, a class or interface
* {@code C} can be created by this method instead. This method is capable of
* defining {@code C}, and thereby creating it, without invoking
* {@code ClassLoader::defineClass}.
* Instead, this method defines {@code C} as if by arranging for
* the Java Virtual Machine to derive a nonarray class or interface {@code C}
* from a purported representation in {@code class} file format
* using the following rules:
*
* <ol>
* <li> The {@linkplain #lookupModes() lookup modes} for this {@code Lookup}
* must include {@linkplain #hasFullPrivilegeAccess() full privilege} access.
* This level of access is needed to create {@code C} in the module
* of the lookup class of this {@code Lookup}.</li>
*
* <li> The purported representation in {@code bytes} must be a {@code ClassFile}
* structure of a supported major and minor version. The major and minor version
* may differ from the {@code class} file version of the lookup class of this
* {@code Lookup}.</li>
*
* <li> The value of {@code this_class} must be a valid index in the
* {@code constant_pool} table, and the entry at that index must be a valid
* {@code CONSTANT_Class_info} structure. Let {@code N} be the binary name
* encoded in internal form that is specified by this structure. {@code N} must
* denote a class or interface in the same package as the lookup class.</li>
*
* <li> Let {@code CN} be the string {@code N + "." + <suffix>},
* where {@code <suffix>} is an unqualified name.
*
* <p> Let {@code newBytes} be the {@code ClassFile} structure given by
* {@code bytes} with an additional entry in the {@code constant_pool} table,
* indicating a {@code CONSTANT_Utf8_info} structure for {@code CN}, and
* where the {@code CONSTANT_Class_info} structure indicated by {@code this_class}
* refers to the new {@code CONSTANT_Utf8_info} structure.
*
* <p> Let {@code L} be the defining class loader of the lookup class of this {@code Lookup}.
*
* <p> {@code C} is derived with name {@code CN}, class loader {@code L}, and
* purported representation {@code newBytes} as if by the rules of JVMS {@jvms 5.3.5},
* with the following adjustments:
* <ul>
* <li> The constant indicated by {@code this_class} is permitted to specify a name
* that includes a single {@code "."} character, even though this is not a valid
* binary class or interface name in internal form.</li>
*
* <li> The Java Virtual Machine marks {@code L} as the defining class loader of {@code C},
* but no class loader is recorded as an initiating class loader of {@code C}.</li>
*
* <li> {@code C} is considered to have the same runtime
* {@linkplain Class#getPackage() package}, {@linkplain Class#getModule() module}
* and {@linkplain java.security.ProtectionDomain protection domain}
* as the lookup class of this {@code Lookup}.
* <li> Let {@code GN} be the binary name obtained by taking {@code N}
* (a binary name encoded in internal form) and replacing ASCII forward slashes with
* ASCII periods. For the instance of {@link java.lang.Class} representing {@code C}:
* <ul>
* <li> {@link Class#getName()} returns the string {@code GN + "/" + <suffix>},
* even though this is not a valid binary class or interface name.</li>
* <li> {@link Class#descriptorString()} returns the string
* {@code "L" + N + "." + <suffix> + ";"},
* even though this is not a valid type descriptor name.</li>
* <li> {@link Class#describeConstable()} returns an empty optional as {@code C}
* cannot be described in {@linkplain java.lang.constant.ClassDesc nominal form}.</li>
* </ul>
* </ul>
* </li>
* </ol>
*
* <p> After {@code C} is derived, it is linked by the Java Virtual Machine.
* Linkage occurs as specified in JVMS {@jvms 5.4.3}, with the following adjustments:
* <ul>
* <li> During verification, whenever it is necessary to load the class named
* {@code CN}, the attempt succeeds, producing class {@code C}. No request is
* made of any class loader.</li>
*
* <li> On any attempt to resolve the entry in the run-time constant pool indicated
* by {@code this_class}, the symbolic reference is considered to be resolved to
* {@code C} and resolution always succeeds immediately.</li>
* </ul>
*
* <p> If the {@code initialize} parameter is {@code true},
* then {@code C} is initialized by the Java Virtual Machine.
*
* <p> The newly created class or interface {@code C} serves as the
* {@linkplain #lookupClass() lookup class} of the {@code Lookup} object
* returned by this method. {@code C} is <em>hidden</em> in the sense that
* no other class or interface can refer to {@code C} via a constant pool entry.
* That is, a hidden class or interface cannot be named as a supertype, a field type,
* a method parameter type, or a method return type by any other class.
* This is because a hidden class or interface does not have a binary name, so
* there is no internal form available to record in any class's constant pool.
* A hidden class or interface is not discoverable by {@link Class#forName(String, boolean, ClassLoader)},
* {@link ClassLoader#loadClass(String, boolean)}, or {@link #findClass(String)}, and
* is not {@linkplain java.lang.instrument.Instrumentation#isModifiableClass(Class)
* modifiable} by Java agents or tool agents using the <a href="{@docRoot}/../specs/jvmti.html">
* JVM Tool Interface</a>.
*
* <p> A class or interface created by
* {@linkplain ClassLoader#defineClass(String, byte[], int, int, ProtectionDomain)
* a class loader} has a strong relationship with that class loader.
* That is, every {@code Class} object contains a reference to the {@code ClassLoader}
* that {@linkplain Class#getClassLoader() defined it}.
* This means that a class created by a class loader may be unloaded if and
* only if its defining loader is not reachable and thus may be reclaimed
* by a garbage collector (JLS 12.7).
*
* By default, however, a hidden class or interface may be unloaded even if
* the class loader that is marked as its defining loader is
* <a href="../ref/package.html#reachability">reachable</a>.
* This behavior is useful when a hidden class or interface serves multiple
* classes defined by arbitrary class loaders. In other cases, a hidden
* class or interface may be linked to a single class (or a small number of classes)
* with the same defining loader as the hidden class or interface.
* In such cases, where the hidden class or interface must be coterminous
* with a normal class or interface, the {@link ClassOption#STRONG STRONG}
* option may be passed in {@code options}.
* This arranges for a hidden class to have the same strong relationship
* with the class loader marked as its defining loader,
* as a normal class or interface has with its own defining loader.
*
* If {@code STRONG} is not used, then the invoker of {@code defineHiddenClass}
* may still prevent a hidden class or interface from being
* unloaded by ensuring that the {@code Class} object is reachable.
*
* <p> The unloading characteristics are set for each hidden class when it is
* defined, and cannot be changed later. An advantage of allowing hidden classes
* to be unloaded independently of the class loader marked as their defining loader
* is that a very large number of hidden classes may be created by an application.
* In contrast, if {@code STRONG} is used, then the JVM may run out of memory,
* just as if normal classes were created by class loaders.
*
* <p> Classes and interfaces in a nest are allowed to have mutual access to
* their private members. The nest relationship is determined by
* the {@code NestHost} attribute (JVMS {@jvms 4.7.28}) and
* the {@code NestMembers} attribute (JVMS {@jvms 4.7.29}) in a {@code class} file.
* By default, a hidden class belongs to a nest consisting only of itself
* because a hidden class has no binary name.
* The {@link ClassOption#NESTMATE NESTMATE} option can be passed in {@code options}
* to create a hidden class or interface {@code C} as a member of a nest.
* The nest to which {@code C} belongs is not based on any {@code NestHost} attribute
* in the {@code ClassFile} structure from which {@code C} was derived.
* Instead, the following rules determine the nest host of {@code C}:
* <ul>
* <li>If the nest host of the lookup class of this {@code Lookup} has previously
* been determined, then let {@code H} be the nest host of the lookup class.
* Otherwise, the nest host of the lookup class is determined using the
* algorithm in JVMS {@jvms 5.4.4}, yielding {@code H}.</li>
* <li>The nest host of {@code C} is determined to be {@code H},
* the nest host of the lookup class.</li>
* </ul>
*
* <p> A hidden class or interface may be serializable, but this requires a custom
* serialization mechanism in order to ensure that instances are properly serialized
* and deserialized. The default serialization mechanism supports only classes and
* interfaces that are discoverable by their class name.
*
* @param bytes the bytes that make up the class data,
* in the format of a valid {@code class} file as defined by
* <cite>The Java Virtual Machine Specification</cite>.
* @param initialize if {@code true} the class will be initialized.
* @param options {@linkplain ClassOption class options}
* @return the {@code Lookup} object on the hidden class
*
* @throws IllegalAccessException if this {@code Lookup} does not have
* {@linkplain #hasFullPrivilegeAccess() full privilege} access
* @throws SecurityException if a security manager is present and it
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws ClassFormatError if {@code bytes} is not a {@code ClassFile} structure
* @throws UnsupportedClassVersionError if {@code bytes} is not of a supported major or minor version
* @throws IllegalArgumentException if {@code bytes} is not a class or interface or
* {@bytes} denotes a class in a different package than the lookup class
* @throws IncompatibleClassChangeError if the class or interface named as
* the direct superclass of {@code C} is in fact an interface, or if any of the classes
* or interfaces named as direct superinterfaces of {@code C} are not in fact interfaces
* @throws ClassCircularityError if any of the superclasses or superinterfaces of
* {@code C} is {@code C} itself
* @throws VerifyError if the newly created class cannot be verified
* @throws LinkageError if the newly created class cannot be linked for any other reason
* @throws NullPointerException if any parameter is {@code null}
*
* @since 15
* @see Class#isHidden()
* @jvms 4.2.1 Binary Class and Interface Names
* @jvms 4.2.2 Unqualified Names
* @jvms 4.7.28 The {@code NestHost} Attribute
* @jvms 4.7.29 The {@code NestMembers} Attribute
* @jvms 5.4.3.1 Class and Interface Resolution
* @jvms 5.4.4 Access Control
* @jvms 5.3.5 Deriving a {@code Class} from a {@code class} File Representation
* @jvms 5.4 Linking
* @jvms 5.5 Initialization
* @jls 12.7 Unloading of Classes and Interfaces
*/
public Lookup defineHiddenClass(byte[] bytes, boolean initialize, ClassOption... options)
throws IllegalAccessException
{
Objects.requireNonNull(bytes);
Objects.requireNonNull(options);
ensureDefineClassPermission();
if (!hasFullPrivilegeAccess()) {
throw new IllegalAccessException(this + " does not have full privilege access");
}
return makeHiddenClassDefiner(bytes.clone(), Set.of(options), false).defineClassAsLookup(initialize);
}
/**
* Creates a <em>hidden</em> class or interface from {@code bytes} with associated
* {@linkplain MethodHandles#classData(Lookup, String, Class) class data},
* returning a {@code Lookup} on the newly created class or interface.
*
* <p> This method is equivalent to calling
* {@link #defineHiddenClass(byte[], boolean, ClassOption...) defineHiddenClass(bytes, true, options)}
* as if the hidden class has a private static final unnamed field whose value
* is initialized to {@code classData} right before the class initializer is
* executed. The newly created class is linked and initialized by the Java
* Virtual Machine.
*
* <p> The {@link MethodHandles#classData(Lookup, String, Class) MethodHandles::classData}
* method can be used to retrieve the {@code classData}.
*
* @param bytes the class bytes
* @param classData pre-initialized class data
* @param options {@linkplain ClassOption class options}
* @return the {@code Lookup} object on the hidden class
*
* @throws IllegalAccessException if this {@code Lookup} does not have
* {@linkplain #hasFullPrivilegeAccess() full privilege} access
* @throws SecurityException if a security manager is present and it
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
* @throws ClassFormatError if {@code bytes} is not a {@code ClassFile} structure
* @throws UnsupportedClassVersionError if {@code bytes} is not of a supported major or minor version
* @throws IllegalArgumentException if {@code bytes} is not a class or interface or
* {@bytes} denotes a class in a different package than the lookup class
* @throws IncompatibleClassChangeError if the class or interface named as
* the direct superclass of {@code C} is in fact an interface, or if any of the classes
* or interfaces named as direct superinterfaces of {@code C} are not in fact interfaces
* @throws ClassCircularityError if any of the superclasses or superinterfaces of
* {@code C} is {@code C} itself
* @throws VerifyError if the newly created class cannot be verified
* @throws LinkageError if the newly created class cannot be linked for any other reason
* @throws NullPointerException if any parameter is {@code null}
*
* @since 15
* @see Lookup#defineHiddenClass(byte[], boolean, ClassOption...)
* @see Class#isHidden()
*/
/* package-private */ Lookup defineHiddenClassWithClassData(byte[] bytes, Object classData, ClassOption... options)
throws IllegalAccessException
{
Objects.requireNonNull(bytes);
Objects.requireNonNull(classData);
Objects.requireNonNull(options);
ensureDefineClassPermission();
if (!hasFullPrivilegeAccess()) {
throw new IllegalAccessException(this + " does not have full privilege access");
}
return makeHiddenClassDefiner(bytes.clone(), Set.of(options), false)
.defineClassAsLookup(true, classData);
}
/*
* Validates the given bytes to be a class or interface and the class name
* is in the same package as the lookup class.
*
* This method returns the class name.
*/
private String validateAndGetClassName(byte[] bytes) {
try {
ClassReader reader = new ClassReader(bytes);
name = reader.getClassName();
if ((reader.getAccess() & Opcodes.ACC_MODULE) != 0) {
throw newIllegalArgumentException("Not a class or interface: ACC_MODULE flag is set");
}
String name = reader.getClassName().replace('/', '.');
int index = name.lastIndexOf('.');
String pn = (index == -1) ? "" : name.substring(0, index);
if (!pn.equals(lookupClass.getPackageName())) {
throw newIllegalArgumentException(name + " not in same package as lookup class: " +
lookupClass.getName());
}
return name;
} catch (IllegalArgumentException e) {
throw e;
} catch (RuntimeException e) {
// ASM exceptions are poorly specified
ClassFormatError cfe = new ClassFormatError();
cfe.initCause(e);
throw cfe;
}
}
// get package and class name in binary form
String cn, pn;
int index = name.lastIndexOf('/');
if (index == -1) {
cn = name;
pn = "";
} else {
cn = name.replace('/', '.');
pn = cn.substring(0, index);
}
if (!pn.equals(lookupClass.getPackageName())) {
throw new IllegalArgumentException("Class not in same package as lookup class");
/*
* Returns a ClassDefiner that creates a {@code Class} object of a normal class
* from the given bytes.
*
* Caller should make a defensive copy of the arguments if needed
* before calling this factory method.
*
* @throws IllegalArgumentException if {@code bytes} is not a class or interface or
* {@bytes} denotes a class in a different package than the lookup class
*/
private ClassDefiner makeClassDefiner(byte[] bytes) {
return new ClassDefiner(this, validateAndGetClassName(bytes), bytes, STRONG_LOADER_LINK);
}
/**
* Returns a ClassDefiner that creates a {@code Class} object of a hidden class
* from the given bytes. The name must be in the same package as the lookup class.
*
* Caller should make a defensive copy of the arguments if needed
* before calling this factory method.
*
* @param bytes class bytes
* @return ClassDefiner that defines a hidden class of the given bytes.
*
* @throws IllegalArgumentException if {@code bytes} is not a class or interface or
* {@bytes} denotes a class in a different package than the lookup class
*/
ClassDefiner makeHiddenClassDefiner(byte[] bytes) {
return makeHiddenClassDefiner(validateAndGetClassName(bytes), bytes, Set.of(), false);
}
/**
* Returns a ClassDefiner that creates a {@code Class} object of a hidden class
* from the given bytes and options.
* The name must be in the same package as the lookup class.
*
* Caller should make a defensive copy of the arguments if needed
* before calling this factory method.
*
* @param bytes class bytes
* @param options class options
* @param accessVmAnnotations true to give the hidden class access to VM annotations
* @return ClassDefiner that defines a hidden class of the given bytes and options
*
* @throws IllegalArgumentException if {@code bytes} is not a class or interface or
* {@bytes} denotes a class in a different package than the lookup class
*/
ClassDefiner makeHiddenClassDefiner(byte[] bytes,
Set<ClassOption> options,
boolean accessVmAnnotations) {
return makeHiddenClassDefiner(validateAndGetClassName(bytes), bytes, options, accessVmAnnotations);
}
/**
* Returns a ClassDefiner that creates a {@code Class} object of a hidden class
* from the given bytes. No package name check on the given name.
*
* @param name fully-qualified name that specifies the prefix of the hidden class
* @param bytes class bytes
* @return ClassDefiner that defines a hidden class of the given bytes.
*/
ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes) {
return makeHiddenClassDefiner(name, bytes, Set.of(), false);
}
/**
* Returns a ClassDefiner that creates a {@code Class} object of a hidden class
* from the given bytes and options. No package name check on the given name.
*
* @param name the name of the class and the name in the class bytes is ignored.
* @param bytes class bytes
* @param options class options
* @param accessVmAnnotations true to give the hidden class access to VM annotations
*/
ClassDefiner makeHiddenClassDefiner(String name,
byte[] bytes,
Set<ClassOption> options,
boolean accessVmAnnotations) {
int flags = HIDDEN_CLASS | ClassOption.optionsToFlag(options);
if (accessVmAnnotations | VM.isSystemDomainLoader(lookupClass.getClassLoader())) {
// jdk.internal.vm.annotations are permitted for classes
// defined to boot loader and platform loader
flags |= ACCESS_VM_ANNOTATIONS;
}
// invoke the class loader's defineClass method
ClassLoader loader = lookupClass.getClassLoader();
ProtectionDomain pd = (loader != null) ? lookupClassProtectionDomain() : null;
String source = "__Lookup_defineClass__";
Class<?> clazz = SharedSecrets.getJavaLangAccess().defineClass(loader, cn, bytes, pd, source);
return clazz;
return new ClassDefiner(this, name, bytes, flags);
}
static class ClassDefiner {
private final Lookup lookup;
private final String name;
private final byte[] bytes;
private final int classFlags;
private ClassDefiner(Lookup lookup, String name, byte[] bytes, int flags) {
assert ((flags & HIDDEN_CLASS) != 0 || (flags & STRONG_LOADER_LINK) == STRONG_LOADER_LINK);
this.lookup = lookup;
this.bytes = bytes;
this.classFlags = flags;
this.name = name;
}
String className() {
return name;
}
Class<?> defineClass(boolean initialize) {
return defineClass(initialize, null);
}
Lookup defineClassAsLookup(boolean initialize) {
Class<?> c = defineClass(initialize, null);
return new Lookup(c, null, FULL_POWER_MODES);
}
/**
* Defines the class of the given bytes and the given classData.
* If {@code initialize} parameter is true, then the class will be initialized.
*
* @param initialize true if the class to be initialized
* @param classData classData or null
* @return the class
*
* @throws LinkageError linkage error
*/
Class<?> defineClass(boolean initialize, Object classData) {
Class<?> lookupClass = lookup.lookupClass();
ClassLoader loader = lookupClass.getClassLoader();
ProtectionDomain pd = (loader != null) ? lookup.lookupClassProtectionDomain() : null;
Class<?> c = JLA.defineClass(loader, lookupClass, name, bytes, pd, initialize, classFlags, classData);
assert !isNestmate() || c.getNestHost() == lookupClass.getNestHost();
return c;
}
Lookup defineClassAsLookup(boolean initialize, Object classData) {
// initialize must be true if classData is non-null
assert classData == null || initialize == true;
Class<?> c = defineClass(initialize, classData);
return new Lookup(c, null, FULL_POWER_MODES);
}
private boolean isNestmate() {
return (classFlags & NESTMATE_CLASS) != 0;
}
}
private ProtectionDomain lookupClassProtectionDomain() {
ProtectionDomain pd = cachedProtectionDomain;
if (pd == null) {
cachedProtectionDomain = pd = protectionDomain(lookupClass);
cachedProtectionDomain = pd = JLA.protectionDomain(lookupClass);
}
return pd;
}
private ProtectionDomain protectionDomain(Class<?> clazz) {
PrivilegedAction<ProtectionDomain> pa = clazz::getProtectionDomain;
return AccessController.doPrivileged(pa);
}
// cached protection domain
private volatile ProtectionDomain cachedProtectionDomain;
// Make sure outer class is initialized first.
static { IMPL_NAMES.getClass(); }
@ -1689,6 +2218,8 @@ public class MethodHandles {
*/
static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, null, UNCONDITIONAL);
static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
private static void checkUnprivilegedlookupClass(Class<?> lookupClass) {
String name = lookupClass.getName();
if (name.startsWith("java.lang.invoke."))
@ -1749,7 +2280,7 @@ public class MethodHandles {
return cname + "/package";
case FULL_POWER_MODES & (~PROTECTED):
case FULL_POWER_MODES & ~(PROTECTED|MODULE):
return cname + "/private";
return cname + "/private";
case FULL_POWER_MODES:
case FULL_POWER_MODES & (~MODULE):
return cname;
@ -2639,8 +3170,13 @@ return mh1;
private MethodHandle unreflectField(Field f, boolean isSetter) throws IllegalAccessException {
MemberName field = new MemberName(f, isSetter);
if (isSetter && field.isStatic() && field.isFinal())
throw field.makeAccessException("static final field has no write access", this);
if (isSetter && field.isFinal()) {
if (field.isStatic()) {
throw field.makeAccessException("static final field has no write access", this);
} else if (field.getDeclaringClass().isHidden()){
throw field.makeAccessException("final field in a hidden class has no write access", this);
}
}
assert(isSetter
? MethodHandleNatives.refKindIsSetter(field.getReferenceKind())
: MethodHandleNatives.refKindIsGetter(field.getReferenceKind()));
@ -3201,7 +3737,8 @@ return mh1;
}
refc = lookupClass();
}
return VarHandles.makeFieldHandle(getField, refc, getField.getFieldType(), this.allowedModes == TRUSTED);
return VarHandles.makeFieldHandle(getField, refc, getField.getFieldType(),
this.allowedModes == TRUSTED && !getField.getDeclaringClass().isHidden());
}
/** Check access and get the requested constructor. */
private MethodHandle getDirectConstructor(Class<?> refc, MemberName ctor) throws IllegalAccessException {

@ -99,6 +99,36 @@ import static java.lang.invoke.MethodType.fromDescriptor;
* all classes named in the descriptor must be accessible, and will be loaded.
* (But the classes need not be initialized, as is the case with a {@code CONSTANT_Class}.)
* This loading may occur at any time before the {@code MethodType} object is first derived.
* <p>
* <b><a id="descriptor">Nominal Descriptors</a></b>
* <p>
* A {@code MethodType} can be described in {@linkplain MethodTypeDesc nominal form}
* if and only if all of the parameter types and return type can be described
* with a {@link Class#describeConstable() nominal descriptor} represented by
* {@link ClassDesc}. If a method type can be described norminally, then:
* <ul>
* <li>The method type has a {@link MethodTypeDesc nominal descriptor}
* returned by {@link #describeConstable() MethodType::describeConstable}.</li>
* <li>The descriptor string returned by
* {@link #descriptorString() MethodType::descriptorString} or
* {@link #toMethodDescriptorString() MethodType::toMethodDescriptorString}
* for the method type is a method descriptor (JVMS {@jvms 4.3.3}).</li>
* </ul>
* <p>
* If any of the parameter types or return type cannot be described
* nominally, i.e. {@link Class#describeConstable() Class::describeConstable}
* returns an empty optional for that type,
* then the method type cannot be described nominally:
* <ul>
* <li>The method type has no {@link MethodTypeDesc nominal descriptor} and
* {@link #describeConstable() MethodType::describeConstable} returns
* an empty optional.</li>
* <li>The descriptor string returned by
* {@link #descriptorString() MethodType::descriptorString} or
* {@link #toMethodDescriptorString() MethodType::toMethodDescriptorString}
* for the method type is not a type descriptor.</li>
* </ul>
*
* @author John Rose, JSR 292 EG
* @since 1.7
*/
@ -1140,7 +1170,9 @@ class MethodType
}
/**
* Produces a bytecode descriptor representation of the method type.
* Returns a descriptor string for the method type. This method
* is equivalent to calling {@link #descriptorString() MethodType::descriptorString}.
*
* <p>
* Note that this is not a strict inverse of {@link #fromMethodDescriptorString fromMethodDescriptorString}.
* Two distinct classes which share a common name but have different class loaders
@ -1150,7 +1182,9 @@ class MethodType
* generate bytecodes that process method handles and {@code invokedynamic}.
* {@link #fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) fromMethodDescriptorString},
* because the latter requires a suitable class loader argument.
* @return the bytecode type descriptor representation
* @return the descriptor string for this method type
* @jvms 4.3.3 Method Descriptors
* @see <a href="#descriptor">Nominal Descriptor for {@code MethodType}</a>
*/
public String toMethodDescriptorString() {
String desc = methodDescriptor;
@ -1162,11 +1196,28 @@ class MethodType
}
/**
* Return a field type descriptor string for this type
* Returns a descriptor string for this method type.
*
* @return the descriptor string
* @jvms 4.3.2 Field Descriptors
* <p>
* If this method type can be <a href="#descriptor">described nominally</a>,
* then the result is a method type descriptor (JVMS {@jvms 4.3.3}).
* {@link MethodTypeDesc MethodTypeDesc} for this method type
* can be produced by calling {@link MethodTypeDesc#ofDescriptor(String)
* MethodTypeDesc::ofDescriptor} with the result descriptor string.
* <p>
* If this method type cannot be <a href="#descriptor">described nominally</a>
* and the result is a string of the form:
* <blockquote>{@code "(<parameter-descriptors>)<return-descriptor>"}</blockquote>
* where {@code <parameter-descriptors>} is the concatenation of the
* {@linkplain Class#descriptorString() descriptor string} of all
* of the parameter types and the {@linkplain Class#descriptorString() descriptor string}
* of the return type. No {@link java.lang.constant.MethodTypeDesc MethodTypeDesc}
* can be produced from the result string.
*
* @return the descriptor string for this method type
* @since 12
* @jvms 4.3.3 Method Descriptors
* @see <a href="#descriptor">Nominal Descriptor for {@code MethodType}</a>
*/
@Override
public String descriptorString() {
@ -1179,12 +1230,13 @@ class MethodType
}
/**
* Return a nominal descriptor for this instance, if one can be
* Returns a nominal descriptor for this instance, if one can be
* constructed, or an empty {@link Optional} if one cannot be.
*
* @return An {@link Optional} containing the resulting nominal descriptor,
* or an empty {@link Optional} if one cannot be constructed.
* @since 12
* @see <a href="#descriptor">Nominal Descriptor for {@code MethodType}</a>
*/
@Override
public Optional<MethodTypeDesc> describeConstable() {

@ -25,7 +25,8 @@
package java.lang.invoke;
import jdk.internal.misc.Unsafe;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.VM;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Label;
@ -42,6 +43,9 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import static java.lang.invoke.MethodHandles.lookup;
import static java.lang.invoke.MethodType.methodType;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
/**
@ -133,6 +137,8 @@ public final class StringConcatFactory {
*/
private static final Strategy DEFAULT_STRATEGY = Strategy.MH_INLINE_SIZED_EXACT;
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
private enum Strategy {
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder}.
@ -189,8 +195,6 @@ public final class StringConcatFactory {
*/
private static final ProxyClassesDumper DUMPER;
private static final Class<?> STRING_HELPER;
static {
// In case we need to double-back onto the StringConcatFactory during this
// static initialization, make sure we have the reasonable defaults to complete
@ -202,12 +206,6 @@ public final class StringConcatFactory {
// DEBUG = false; // implied
// DUMPER = null; // implied
try {
STRING_HELPER = Class.forName("java.lang.StringConcatHelper");
} catch (Throwable e) {
throw new AssertionError(e);
}
final String strategy =
VM.getSavedProperty("java.lang.invoke.stringConcat");
CACHE_ENABLE = Boolean.parseBoolean(
@ -718,25 +716,10 @@ public final class StringConcatFactory {
private static String getClassName(Class<?> hostClass) throws StringConcatException {
/*
The generated class is in the same package as the host class as
it's the implementation of the string concatenation for the host class.
When cache is enabled, we want to cache as much as we can.
However, there are two peculiarities:
a) The generated class should stay within the same package as the
host class, to allow Unsafe.defineAnonymousClass access controls
to work properly. JDK may choose to fail with IllegalAccessException
when accessing a VM anonymous class with non-privileged callers,
see JDK-8058575.
b) If we mark the stub with some prefix, say, derived from the package
name because of (a), we can technically use that stub in other packages.
But the call stack traces would be extremely puzzling to unsuspecting users
and profiling tools: whatever stub wins the race, would be linked in all
similar callsites.
Therefore, we set the class prefix to match the host class package, and use
the prefix as the cache key too. This only affects BC_* strategies, and only when
cache is enabled.
*/
switch (STRATEGY) {
@ -745,9 +728,11 @@ public final class StringConcatFactory {
case BC_SB_SIZED_EXACT: {
if (CACHE_ENABLE) {
String pkgName = hostClass.getPackageName();
return (pkgName != null && !pkgName.isEmpty() ? pkgName.replace('.', '/') + "/" : "") + "Stubs$$StringConcat";
return (!pkgName.isEmpty() ? pkgName.replace('.', '/') + "/" : "") + "Stubs$$StringConcat";
} else {
return hostClass.getName().replace('.', '/') + "$$StringConcat";
String name = hostClass.isHidden() ? hostClass.getName().replace('/', '_')
: hostClass.getName();
return name.replace('.', '/') + "$$StringConcat";
}
}
case MH_SB_SIZED:
@ -819,7 +804,7 @@ public final class StringConcatFactory {
* chain javac would otherwise emit. This strategy uses only the public API,
* and comes as the baseline for the current JDK behavior. On other words,
* this strategy moves the javac generated bytecode to runtime. The
* generated bytecode is loaded via Unsafe.defineAnonymousClass, but with
* generated bytecode is loaded via Lookup::defineClass, but with
* the caller class coming from the BSM -- in other words, the protection
* guarantees are inherited from the method where invokedynamic was
* originally called. This means, among other things, that the bytecode is
@ -848,7 +833,6 @@ public final class StringConcatFactory {
* private String API.
*/
private static final class BytecodeStringBuilderStrategy {
static final Unsafe UNSAFE = Unsafe.getUnsafe();
static final int CLASSFILE_VERSION = 52;
static final String METHOD_NAME = "concat";
@ -861,7 +845,7 @@ public final class StringConcatFactory {
cw.visit(CLASSFILE_VERSION,
ACC_SUPER + ACC_PUBLIC + ACC_FINAL + ACC_SYNTHETIC,
className, // Unsafe.defineAnonymousClass would append an unique ID
className,
null,
"java/lang/Object",
null
@ -874,6 +858,7 @@ public final class StringConcatFactory {
null,
null);
// use of @ForceInline no longer has any effect
mv.visitAnnotation("Ljdk/internal/vm/annotation/ForceInline;", true);
mv.visitCode();
@ -1143,11 +1128,9 @@ public final class StringConcatFactory {
byte[] classBytes = cw.toByteArray();
try {
Class<?> hostClass = lookup.lookupClass();
Class<?> innerClass = UNSAFE.defineAnonymousClass(hostClass, classBytes, null);
UNSAFE.ensureClassInitialized(innerClass);
dumpIfEnabled(innerClass.getName(), classBytes);
return Lookup.IMPL_LOOKUP.findStatic(innerClass, METHOD_NAME, args);
Class<?> innerClass = lookup.defineHiddenClass(classBytes, true, STRONG).lookupClass();
dumpIfEnabled(className, classBytes);
return lookup.findStatic(innerClass, METHOD_NAME, args);
} catch (Exception e) {
dumpIfEnabled(className + "$$FAILED", classBytes);
throw new StringConcatException("Exception while spinning the class", e);
@ -1270,8 +1253,8 @@ public final class StringConcatFactory {
* computation on MethodHandle combinators. The computation is built with
* public MethodHandle APIs, resolved from a public Lookup sequence, and
* ends up calling the public StringBuilder API. Therefore, this strategy
* does not use any private API at all, even the Unsafe.defineAnonymousClass,
* since everything is handled under cover by java.lang.invoke APIs.
* does not use any private API at all since everything is handled under
* cover by java.lang.invoke APIs.
*
* <p><b>{@link Strategy#MH_SB_SIZED_EXACT}: "MethodHandles StringBuilder,
* sized exactly".</b>
@ -1283,7 +1266,6 @@ public final class StringConcatFactory {
* private String API.
*/
private static final class MethodHandleStringBuilderStrategy {
private MethodHandleStringBuilderStrategy() {
// no instantiation
}
@ -1461,6 +1443,8 @@ public final class StringConcatFactory {
return sum;
}
private static final Lookup MHSBS_LOOKUP = lookup();
private static final ConcurrentMap<Integer, MethodHandle> SUMMERS;
// This one is deliberately non-lambdified to optimize startup time:
@ -1474,9 +1458,9 @@ public final class StringConcatFactory {
// unroll some initial sizes.
Class<?>[] cls = new Class<?>[cnt];
Arrays.fill(cls, int.class);
return lookupStatic(Lookup.IMPL_LOOKUP, MethodHandleStringBuilderStrategy.class, "sum", int.class, cls);
return lookupStatic(MHSBS_LOOKUP, MethodHandleStringBuilderStrategy.class, "sum", int.class, cls);
} else {
return lookupStatic(Lookup.IMPL_LOOKUP, MethodHandleStringBuilderStrategy.class, "sum", int.class, int.class, int[].class)
return lookupStatic(MHSBS_LOOKUP, MethodHandleStringBuilderStrategy.class, "sum", int.class, int.class, int[].class)
.asCollector(int[].class, cnt - 1);
}
}
@ -1491,8 +1475,8 @@ public final class StringConcatFactory {
STRING_LENGTH = lookupVirtual(publicLookup, String.class, "length", int.class);
BUILDER_TO_STRING = lookupVirtual(publicLookup, StringBuilder.class, "toString", String.class);
if (DEBUG) {
BUILDER_TO_STRING_CHECKED = lookupStatic(MethodHandles.Lookup.IMPL_LOOKUP,
MethodHandleStringBuilderStrategy.class, "toStringChecked", String.class, StringBuilder.class);
BUILDER_TO_STRING_CHECKED = lookupStatic(MHSBS_LOOKUP, MethodHandleStringBuilderStrategy.class,
"toStringChecked", String.class, StringBuilder.class);
} else {
BUILDER_TO_STRING_CHECKED = null;
}
@ -1516,8 +1500,6 @@ public final class StringConcatFactory {
* that requires porting if there are private JDK changes occur.
*/
private static final class MethodHandleInlineCopyStrategy {
static final Unsafe UNSAFE = Unsafe.getUnsafe();
private MethodHandleInlineCopyStrategy() {
// no instantiation
}
@ -1736,8 +1718,9 @@ public final class StringConcatFactory {
private static final Function<Class<?>, MethodHandle> PREPEND = new Function<>() {
@Override
public MethodHandle apply(Class<?> c) {
return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "prepend", long.class, long.class, byte[].class,
String.class, Wrapper.asPrimitiveType(c), String.class);
return JLA.stringConcatHelper("prepend",
methodType(long.class, long.class, byte[].class,
String.class, Wrapper.asPrimitiveType(c), String.class));
}
};
@ -1745,8 +1728,7 @@ public final class StringConcatFactory {
private static final Function<Class<?>, MethodHandle> MIX = new Function<>() {
@Override
public MethodHandle apply(Class<?> c) {
return lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "mix", long.class, long.class,
Wrapper.asPrimitiveType(c));
return JLA.stringConcatHelper("mix", methodType(long.class, long.class, Wrapper.asPrimitiveType(c)));
}
};
@ -1759,7 +1741,7 @@ public final class StringConcatFactory {
static {
try {
MethodHandle initCoder = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "initialCoder", long.class);
MethodHandle initCoder = JLA.stringConcatHelper("initialCoder", methodType(long.class));
INITIAL_CODER = (long) initCoder.invoke();
} catch (Throwable e) {
throw new AssertionError(e);
@ -1768,9 +1750,9 @@ public final class StringConcatFactory {
PREPENDERS = new ConcurrentHashMap<>();
MIXERS = new ConcurrentHashMap<>();
SIMPLE = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "simpleConcat", String.class, Object.class, Object.class);
NEW_STRING = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "newString", String.class, byte[].class, long.class);
NEW_ARRAY = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "newArray", byte[].class, long.class);
SIMPLE = JLA.stringConcatHelper("simpleConcat", methodType(String.class, Object.class, Object.class));
NEW_STRING = JLA.stringConcatHelper("newString", methodType(String.class, byte[].class, long.class));
NEW_ARRAY = JLA.stringConcatHelper( "newArray", methodType(byte[].class, long.class));
}
}
@ -1784,7 +1766,7 @@ public final class StringConcatFactory {
}
private static final MethodHandle OBJECT_INSTANCE =
lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "stringOf", String.class, Object.class);
JLA.stringConcatHelper("stringOf", methodType(String.class, Object.class));
private static class FloatStringifiers {
private static final MethodHandle FLOAT_INSTANCE =

@ -27,19 +27,24 @@ package java.lang.invoke;
import java.util.List;
/**
* An entity that has a field or method type descriptor
*
* @jvms 4.3.2 Field Descriptors
* @jvms 4.3.3 Method Descriptors
* An entity that has a type descriptor.
*
* @since 12
*/
public interface TypeDescriptor {
/**
* Return the type descriptor string for this instance, which must be either
* a field type descriptor (JVMS 4.3.2) or method type descriptor (JVMS 4.3.3).
* Returns the descriptor string for this {@code TypeDescriptor} object.
*
* @return the type descriptor
* If this {@code TypeDescriptor} object can be described in nominal form,
* then this method returns a type descriptor as specified in JVMS {@jvms 4.3}.
* The result descriptor string can be used to produce
* a {@linkplain java.lang.constant.ConstantDesc nominal descriptor}.
*
* Otherwise, the result string is not a type descriptor.
* No {@linkplain java.lang.constant.ConstantDesc nominal descriptor}
* can be produced from the result string.
*
* @return the descriptor string for this {@code TypeDescriptor} object
* @jvms 4.3.2 Field Descriptors
* @jvms 4.3.3 Method Descriptors
*/
@ -47,7 +52,10 @@ public interface TypeDescriptor {
/**
* An entity that has a field type descriptor
* An entity that has a field type descriptor.
* Field descriptors conforming to JVMS {@jvms 4.3.2} can be described
* nominally via {@link Class#describeConstable Class::describeConstable};
* otherwise they cannot be described nominally.
*
* @param <F> the class implementing {@linkplain TypeDescriptor.OfField}
* @jvms 4.3.2 Field Descriptors
@ -86,6 +94,9 @@ public interface TypeDescriptor {
/**
* An entity that has a method type descriptor
* Method descriptors conforming to JVMS {@jvms 4.3.3} can be described
* nominally via {@link MethodType#describeConstable MethodType::describeConstable};
* otherwise they cannot be described nominally.
*
* @param <F> the type representing field type descriptors
* @param <M> the class implementing {@linkplain TypeDescriptor.OfMethod}

@ -176,6 +176,12 @@ public class AccessibleObject implements AnnotatedElement {
* to the caller and the package containing the declaring class is not open
* to the caller's module. </p>
*
* <p> This method cannot be used to enable {@linkplain Field#set <em>write</em>}
* access to a final field declared in a {@linkplain Class#isHidden() hidden class},
* since such fields are not modifiable. The {@code accessible} flag when
* {@code true} suppresses Java language access control checks to only
* enable {@linkplain Field#get <em>read</em>} access to such fields.
*
* <p> If there is a security manager, its
* {@code checkPermission} method is first called with a
* {@code ReflectPermission("suppressAccessChecks")} permission.

@ -721,10 +721,19 @@ class Field extends AccessibleObject implements Member {
* the underlying field is inaccessible, the method throws an
* {@code IllegalAccessException}.
*
* <p>If the underlying field is final, the method throws an
* {@code IllegalAccessException} unless {@code setAccessible(true)}
* has succeeded for this {@code Field} object
* and the field is non-static. Setting a final field in this way
* <p>If the underlying field is final, this {@code Field} object has
* <em>write</em> access if and only if the following conditions are met:
* <ul>
* <li>{@link #setAccessible(boolean) setAccessible(true)} has succeeded for
* this {@code Field} object;</li>
* <li>the field is non-static; and</li>
* <li>the field's declaring class is not a {@linkplain Class#isHidden()
* hidden class}.</li>
* </ul>
* If any of the above checks is not met, this method throws an
* {@code IllegalAccessException}.
*
* <p> Setting a final field in this way
* is meaningful only during deserialization or reconstruction of
* instances of classes with blank final fields, before they are
* made available for access by other parts of a program. Use in
@ -756,7 +765,8 @@ class Field extends AccessibleObject implements Member {
*
* @throws IllegalAccessException if this {@code Field} object
* is enforcing Java language access control and the underlying
* field is either inaccessible or final.
* field is inaccessible or final;
* or if this {@code Field} object has no write access.
* @throws IllegalArgumentException if the specified object is not an
* instance of the class or interface declaring the underlying
* field (or a subclass or implementor thereof),
@ -791,7 +801,8 @@ class Field extends AccessibleObject implements Member {
*
* @throws IllegalAccessException if this {@code Field} object
* is enforcing Java language access control and the underlying
* field is either inaccessible or final.
* field is either inaccessible or final;
* or if this {@code Field} object has no write access.
* @throws IllegalArgumentException if the specified object is not an
* instance of the class or interface declaring the underlying
* field (or a subclass or implementor thereof),
@ -827,7 +838,8 @@ class Field extends AccessibleObject implements Member {
*
* @throws IllegalAccessException if this {@code Field} object
* is enforcing Java language access control and the underlying
* field is either inaccessible or final.
* field is either inaccessible or final;
* or if this {@code Field} object has no write access.
* @throws IllegalArgumentException if the specified object is not an
* instance of the class or interface declaring the underlying
* field (or a subclass or implementor thereof),
@ -863,7 +875,8 @@ class Field extends AccessibleObject implements Member {
*
* @throws IllegalAccessException if this {@code Field} object
* is enforcing Java language access control and the underlying
* field is either inaccessible or final.
* field is either inaccessible or final;
* or if this {@code Field} object has no write access.
* @throws IllegalArgumentException if the specified object is not an
* instance of the class or interface declaring the underlying
* field (or a subclass or implementor thereof),
@ -899,7 +912,8 @@ class Field extends AccessibleObject implements Member {
*
* @throws IllegalAccessException if this {@code Field} object
* is enforcing Java language access control and the underlying
* field is either inaccessible or final.
* field is either inaccessible or final;
* or if this {@code Field} object has no write access.
* @throws IllegalArgumentException if the specified object is not an
* instance of the class or interface declaring the underlying
* field (or a subclass or implementor thereof),
@ -935,7 +949,8 @@ class Field extends AccessibleObject implements Member {
*
* @throws IllegalAccessException if this {@code Field} object
* is enforcing Java language access control and the underlying
* field is either inaccessible or final.
* field is either inaccessible or final;
* or if this {@code Field} object has no write access.
* @throws IllegalArgumentException if the specified object is not an
* instance of the class or interface declaring the underlying
* field (or a subclass or implementor thereof),
@ -971,7 +986,8 @@ class Field extends AccessibleObject implements Member {
*
* @throws IllegalAccessException if this {@code Field} object
* is enforcing Java language access control and the underlying
* field is either inaccessible or final.
* field is either inaccessible or final;
* or if this {@code Field} object has no write access.
* @throws IllegalArgumentException if the specified object is not an
* instance of the class or interface declaring the underlying
* field (or a subclass or implementor thereof),
@ -1007,7 +1023,8 @@ class Field extends AccessibleObject implements Member {
*
* @throws IllegalAccessException if this {@code Field} object
* is enforcing Java language access control and the underlying
* field is either inaccessible or final.
* field is either inaccessible or final;
* or if this {@code Field} object has no write access.
* @throws IllegalArgumentException if the specified object is not an
* instance of the class or interface declaring the underlying
* field (or a subclass or implementor thereof),
@ -1043,7 +1060,8 @@ class Field extends AccessibleObject implements Member {
*
* @throws IllegalAccessException if this {@code Field} object
* is enforcing Java language access control and the underlying
* field is either inaccessible or final.
* field is either inaccessible or final;
* or if this {@code Field} object has no write access.
* @throws IllegalArgumentException if the specified object is not an
* instance of the class or interface declaring the underlying
* field (or a subclass or implementor thereof),

@ -26,6 +26,9 @@
package jdk.internal.access;
import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.module.ModuleDescriptor;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
@ -147,6 +150,14 @@ public interface JavaLangAccess {
*/
Class<?> defineClass(ClassLoader cl, String name, byte[] b, ProtectionDomain pd, String source);
/**
* Defines a class with the given name to a class loader with
* the given flags and class data.
*
* @see java.lang.invoke.MethodHandles.Lookup#defineClass
*/
Class<?> defineClass(ClassLoader cl, Class<?> lookup, String name, byte[] b, ProtectionDomain pd, boolean initialize, int flags, Object classData);
/**
* Returns a class loaded by the bootstrap class loader.
*/
@ -311,4 +322,21 @@ public interface JavaLangAccess {
* @param cause set t's cause to new value
*/
void setCause(Throwable t, Throwable cause);
/**
* Get protection domain of the given Class
*/
ProtectionDomain protectionDomain(Class<?> c);
/**
* Get a method handle of string concat helper method
*/
MethodHandle stringConcatHelper(String name, MethodType methodType);
/*
* Get the class data associated with the given class.
* @param c the class
* @see java.lang.invoke.MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...)
*/
Object classData(Class<?> c);
}

@ -25,9 +25,10 @@
package jdk.internal.reflect;
import java.lang.reflect.*;
import sun.reflect.misc.ReflectUtil;
import java.lang.reflect.*;
/** Used only for the first few invocations of a Constructor;
afterward, switches to bytecode-based implementation */
@ -49,6 +50,7 @@ class NativeConstructorAccessorImpl extends ConstructorAccessorImpl {
// because that kind of class can't be referred to by name, hence can't
// be found from the generated bytecode.
if (++numInvocations > ReflectionFactory.inflationThreshold()
&& !c.getDeclaringClass().isHidden()
&& !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) {
ConstructorAccessorImpl acc = (ConstructorAccessorImpl)
new MethodAccessorGenerator().

@ -25,9 +25,10 @@
package jdk.internal.reflect;
import java.lang.reflect.*;
import sun.reflect.misc.ReflectUtil;
import java.lang.reflect.*;
/** Used only for the first few invocations of a Method; afterward,
switches to bytecode-based implementation */
@ -47,6 +48,7 @@ class NativeMethodAccessorImpl extends MethodAccessorImpl {
// that kind of class can't be referred to by name, hence can't be
// found from the generated bytecode.
if (++numInvocations > ReflectionFactory.inflationThreshold()
&& !method.getDeclaringClass().isHidden()
&& !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
MethodAccessorImpl acc = (MethodAccessorImpl)
new MethodAccessorGenerator().

@ -51,7 +51,7 @@ public class Reflection {
fieldFilterMap = Map.of(
Reflection.class, ALL_MEMBERS,
AccessibleObject.class, ALL_MEMBERS,
Class.class, Set.of("classLoader"),
Class.class, Set.of("classLoader", "classData"),
ClassLoader.class, ALL_MEMBERS,
Constructor.class, ALL_MEMBERS,
Field.class, ALL_MEMBERS,

@ -200,7 +200,8 @@ public class ReflectionFactory {
method = root;
}
if (noInflation && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
if (noInflation && !method.getDeclaringClass().isHidden()
&& !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
return new MethodAccessorGenerator().
generateMethod(method.getDeclaringClass(),
method.getName(),
@ -244,7 +245,8 @@ public class ReflectionFactory {
return new BootstrapConstructorAccessorImpl(c);
}
if (noInflation && !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) {
if (noInflation && !c.getDeclaringClass().isHidden()
&& !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) {
return new MethodAccessorGenerator().
generateConstructor(c.getDeclaringClass(),
c.getParameterTypes(),

@ -35,7 +35,7 @@ class UnsafeFieldAccessorFactory {
boolean isFinal = Modifier.isFinal(field.getModifiers());
boolean isVolatile = Modifier.isVolatile(field.getModifiers());
boolean isQualified = isFinal || isVolatile;
boolean isReadOnly = isFinal && (isStatic || !override);
boolean isReadOnly = isFinal && (isStatic || !override || field.getDeclaringClass().isHidden());
if (isStatic) {
// This code path does not guarantee that the field's
// declaring class has been initialized, but it must be

@ -154,11 +154,7 @@ public class BytecodeDescriptor {
} else if (t == Object.class) {
sb.append("Ljava/lang/Object;");
} else {
boolean lsemi = (!t.isArray());
if (lsemi) sb.append('L');
sb.append(t.getName().replace('.', '/'));
if (lsemi) sb.append(';');
sb.append(t.descriptorString());
}
}
}

@ -61,6 +61,7 @@ static JNINativeMethod methods[] = {
{"getSigners", "()[" OBJ, (void *)&JVM_GetClassSigners},
{"setSigners", "([" OBJ ")V", (void *)&JVM_SetClassSigners},
{"isArray", "()Z", (void *)&JVM_IsArrayClass},
{"isHidden", "()Z", (void *)&JVM_IsHiddenClass},
{"isPrimitive", "()Z", (void *)&JVM_IsPrimitiveClass},
{"getModifiers", "()I", (void *)&JVM_GetClassModifiers},
{"getDeclaredFields0","(Z)[" FLD, (void *)&JVM_GetClassDeclaredFields},

@ -207,6 +207,66 @@ Java_java_lang_ClassLoader_defineClass2(JNIEnv *env,
return result;
}
JNIEXPORT jclass JNICALL
Java_java_lang_ClassLoader_defineClass0(JNIEnv *env,
jclass cls,
jobject loader,
jclass lookup,
jstring name,
jbyteArray data,
jint offset,
jint length,
jobject pd,
jboolean initialize,
jint flags,
jobject classData)
{
jbyte *body;
char *utfName;
jclass result = 0;
char buf[128];
if (data == NULL) {
JNU_ThrowNullPointerException(env, 0);
return 0;
}
/* Work around 4153825. malloc crashes on Solaris when passed a
* negative size.
*/
if (length < 0) {
JNU_ThrowArrayIndexOutOfBoundsException(env, 0);
return 0;
}
body = (jbyte *)malloc(length);
if (body == 0) {
JNU_ThrowOutOfMemoryError(env, 0);
return 0;
}
(*env)->GetByteArrayRegion(env, data, offset, length, body);
if ((*env)->ExceptionOccurred(env))
goto free_body;
if (name != NULL) {
utfName = getUTF(env, name, buf, sizeof(buf));
if (utfName == NULL) {
goto free_body;
}
fixClassname(utfName);
} else {
utfName = NULL;
}
return JVM_LookupDefineClass(env, lookup, utfName, body, length, pd, initialize, flags, classData);
free_body:
free(body);
return result;
}
/*
* Returns NULL if class not found.
*/

@ -387,6 +387,9 @@ public interface Instrumentation {
/**
* Returns an array of all classes currently loaded by the JVM.
* The returned array includes all classes and interfaces, including
* {@linkplain Class#isHidden hidden classes or interfaces}, and array classes
* of all types.
*
* @return an array containing all the classes loaded by the JVM, zero-length if there are none
*/
@ -395,12 +398,21 @@ public interface Instrumentation {
getAllLoadedClasses();
/**
* Returns an array of all classes for which <code>loader</code> is an initiating loader.
* If the supplied loader is <code>null</code>, classes initiated by the bootstrap class
* loader are returned.
* Returns an array of all classes which {@code loader} can find by name
* via {@link ClassLoader#loadClass(String, boolean) ClassLoader::loadClass},
* {@link Class#forName(String) Class::forName} and bytecode linkage.
* That is, all classes for which {@code loader} has been recorded as
* an initiating loader. If the supplied {@code loader} is {@code null},
* classes that the bootstrap class loader can find by name are returned.
* <p>
* The returned array does not include {@linkplain Class#isHidden()
* hidden classes or interfaces} or array classes whose
* {@linkplain Class#componentType() element type} is a
* {@linkplain Class#isHidden() hidden class or interface}.
* as they cannot be discovered by any class loader.
*
* @param loader the loader whose initiated class list will be returned
* @return an array containing all the classes for which loader is an initiating loader,
* @return an array containing all classes which {@code loader} can find by name;
* zero-length if there are none
*/
@SuppressWarnings("rawtypes")

@ -68,12 +68,14 @@ import com.sun.tools.javac.comp.Modules;
import com.sun.tools.javac.main.Arguments;
import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.model.JavacElements;
import com.sun.tools.javac.platform.PlatformDescription;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.LetExpr;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.DefinedBy;
import com.sun.tools.javac.util.DefinedBy.Api;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Options;
/**
* A pool of reusable JavacTasks. When a task is no valid anymore, it is returned to the pool,
@ -252,6 +254,7 @@ public class JavacTaskPool {
drop(JavacTask.class);
drop(JavacTrees.class);
drop(JavacElements.class);
drop(PlatformDescription.class);
if (ht.get(Log.logKey) instanceof ReusableLog) {
//log already inited - not first round
@ -266,6 +269,7 @@ public class JavacTaskPool {
Annotate.instance(this).newRound();
CompileStates.instance(this).clear();
MultiTaskListener.instance(this).clear();
Options.instance(this).clear();
//find if any of the roots have redefined java.* classes
Symtab syms = Symtab.instance(this);

@ -1231,10 +1231,14 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
public static class RootPackageSymbol extends PackageSymbol {
public final MissingInfoHandler missingInfoHandler;
public final boolean allowPrivateInvokeVirtual;
public RootPackageSymbol(Name name, Symbol owner, MissingInfoHandler missingInfoHandler) {
public RootPackageSymbol(Name name, Symbol owner,
MissingInfoHandler missingInfoHandler,
boolean allowPrivateInvokeVirtual) {
super(name, owner);
this.missingInfoHandler = missingInfoHandler;
this.allowPrivateInvokeVirtual = allowPrivateInvokeVirtual;
}
}
@ -2311,7 +2315,7 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
} else {
if (refSym.isStatic()) {
return ClassFile.REF_invokeStatic;
} else if ((refSym.flags() & PRIVATE) != 0) {
} else if ((refSym.flags() & PRIVATE) != 0 && !allowPrivateInvokeVirtual()) {
return ClassFile.REF_invokeSpecial;
} else if (refSym.enclClass().isInterface()) {
return ClassFile.REF_invokeInterface;
@ -2322,6 +2326,13 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
}
}
private boolean allowPrivateInvokeVirtual() {
Symbol rootPack = this;
while (rootPack != null && !(rootPack instanceof RootPackageSymbol)) {
rootPack = rootPack.owner;
}
return rootPack != null && ((RootPackageSymbol) rootPack).allowPrivateInvokeVirtual;
}
@Override
public int poolTag() {
return ClassFile.CONSTANT_MethodHandle;

@ -54,6 +54,7 @@ import com.sun.tools.javac.code.Type.MethodType;
import com.sun.tools.javac.code.Type.UnknownType;
import com.sun.tools.javac.code.Types.UniqueType;
import com.sun.tools.javac.comp.Modules;
import com.sun.tools.javac.jvm.Target;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Convert;
@ -389,7 +390,10 @@ public class Symtab {
MissingInfoHandler missingInfoHandler = MissingInfoHandler.instance(context);
rootPackage = new RootPackageSymbol(names.empty, null, missingInfoHandler);
Target target = Target.instance(context);
rootPackage = new RootPackageSymbol(names.empty, null,
missingInfoHandler,
target.runtimeUseNestAccess());
// create the basic builtin symbols
unnamedModule = new ModuleSymbol(names.empty, null) {

Some files were not shown because too many files have changed in this diff Show More