< prev index next >
src/hotspot/share/classfile/classFileParser.cpp
Print this page
rev 58872 : 8238358: Implementation of JEP 371: Hidden Classes
Reviewed-by: alanb, cjplummer, coleenp, dholmes, dlong, forax, jlahoda, psandoz, plevart, sspitsyn, vromero
Contributed-by: mandy.chung@oracle.com, lois.foltan@oracle.com, david.holmes@oracle.com, harold.seigel@oracle.com, serguei.spitsyn@oracle.com, alex.buckley@oracle.com, jamsheed.c.m@oracle.com, jan.lahoda@oracle.com, amy.lu@oracle.com
*** 1090,1100 ****
: _location(location), _annotations_present(0)
{
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);
// Set the annotation name:
void set_annotation(ID id) {
assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
_annotations_present |= nth_bit((int)id);
}
--- 1090,1100 ----
: _location(location), _annotations_present(0)
{
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, bool can_access_vm_annotations);
// Set the annotation name:
void set_annotation(ID id) {
assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
_annotations_present |= nth_bit((int)id);
}
*** 1223,1232 ****
--- 1223,1233 ----
// Sift through annotations, looking for those significant to the VM:
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");
assert(buffer != NULL, "invariant");
assert(coll != NULL, "invariant");
*** 1268,1278 ****
member = check_symbol_at(cp, member_index);
if (member == NULL) break; // invalid member name
}
// Here is where parsing particular annotations will take place.
! AnnotationCollector::ID id = coll->annotation_index(loader_data, aname);
if (AnnotationCollector::_unknown == id) continue;
coll->set_annotation(id);
if (AnnotationCollector::_jdk_internal_vm_annotation_Contended == id) {
// @Contended can optionally specify the contention group.
--- 1269,1279 ----
member = check_symbol_at(cp, member_index);
if (member == NULL) break; // invalid member name
}
// Here is where parsing particular annotations will take place.
! AnnotationCollector::ID id = coll->annotation_index(loader_data, aname, can_access_vm_annotations);
if (AnnotationCollector::_unknown == id) continue;
coll->set_annotation(id);
if (AnnotationCollector::_jdk_internal_vm_annotation_Contended == id) {
// @Contended can optionally specify the contention group.
*** 1394,1403 ****
--- 1395,1405 ----
parse_annotations(cp,
runtime_visible_annotations,
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()) {
if (runtime_invisible_annotations_exists) {
classfile_parse_error(
*** 2057,2072 ****
name->as_C_string(), _class_name->as_C_string(), sig->as_C_string());
}
AnnotationCollector::ID
AnnotationCollector::annotation_index(const ClassLoaderData* loader_data,
! const Symbol* name) {
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() ||
loader_data->is_platform_class_loader_data() ||
! loader_data->is_unsafe_anonymous();
switch (sid) {
case vmSymbols::VM_SYMBOL_ENUM_NAME(reflect_CallerSensitive_signature): {
if (_location != _in_method) break; // only allow for methods
if (!privileged) break; // only allow in privileged code
return _method_CallerSensitive;
--- 2059,2075 ----
name->as_C_string(), _class_name->as_C_string(), sig->as_C_string());
}
AnnotationCollector::ID
AnnotationCollector::annotation_index(const ClassLoaderData* loader_data,
! 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_boot_class_loader_data() ||
loader_data->is_platform_class_loader_data() ||
! can_access_vm_annotations;
switch (sid) {
case vmSymbols::VM_SYMBOL_ENUM_NAME(reflect_CallerSensitive_signature): {
if (_location != _in_method) break; // only allow for methods
if (!privileged) break; // only allow in privileged code
return _method_CallerSensitive;
*** 2669,2678 ****
--- 2672,2682 ----
parse_annotations(cp,
runtime_visible_annotations,
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()) {
if (runtime_invisible_annotations_exists) {
classfile_parse_error(
*** 2863,2872 ****
--- 2867,2880 ----
}
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,
runtime_visible_annotations_length,
runtime_invisible_annotations,
*** 3594,3603 ****
--- 3602,3612 ----
parse_annotations(cp,
runtime_visible_annotations,
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()) {
if (runtime_invisible_annotations_exists) {
classfile_parse_error(
*** 5590,5608 ****
} // CheckIntrinsics
#endif // ASSERT
}
}
! InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook, TRAPS) {
if (_klass != NULL) {
return _klass;
}
InstanceKlass* const ik =
InstanceKlass::allocate_instance_klass(*this, CHECK_NULL);
! fill_instance_klass(ik, changed_by_loadhook, CHECK_NULL);
assert(_klass == ik, "invariant");
if (ik->should_store_fingerprint()) {
--- 5599,5623 ----
} // CheckIntrinsics
#endif // ASSERT
}
}
! InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook,
! const ClassInstanceInfo& cl_inst_info,
! TRAPS) {
if (_klass != NULL) {
return _klass;
}
InstanceKlass* const ik =
InstanceKlass::allocate_instance_klass(*this, 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");
if (ik->should_store_fingerprint()) {
*** 5624,5634 ****
}
return ik;
}
! void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loadhook, TRAPS) {
assert(ik != NULL, "invariant");
// Set name and CLD before adding to CLD
ik->set_class_loader_data(_loader_data);
ik->set_name(_class_name);
--- 5639,5652 ----
}
return ik;
}
! 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
ik->set_class_loader_data(_loader_data);
ik->set_name(_class_name);
*** 5660,5669 ****
--- 5678,5692 ----
// this transfers ownership of a lot of arrays from
// 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");
assert(NULL == _methods, "invariant");
assert(NULL == _inner_classes, "invariant");
*** 5684,5698 ****
// has to be changed accordingly.
ik->set_initial_method_idnum(ik->methods()->length());
ik->set_this_class_index(_this_class_index);
! if (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
// 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.
ik->constants()->klass_at_put(_this_class_index, ik);
}
--- 5707,5721 ----
// has to be changed accordingly.
ik->set_initial_method_idnum(ik->methods()->length());
ik->set_this_class_index(_this_class_index);
! if (_is_hidden || is_unsafe_anonymous()) {
// _this_class_index is a CONSTANT_Class entry that refers to this
! // 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.
ik->constants()->klass_at_put(_this_class_index, ik);
}
*** 5704,5713 ****
--- 5727,5739 ----
if (_unsafe_anonymous_host != NULL) {
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();
Handle clh = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(cl));
ClassLoaderData* cld = ClassLoaderData::class_loader_data_or_null(clh());
*** 5783,5792 ****
--- 5809,5819 ----
// The create_mirror() call will also call compute_modifiers()
java_lang_Class::create_mirror(ik,
Handle(THREAD, _loader_data->class_loader()),
module_handle,
_protection_domain,
+ cl_inst_info.class_data(),
CHECK);
assert(_all_mirandas != NULL, "invariant");
// Generate any default methods - default methods are public interface methods
*** 5867,5877 ****
// Now the ClassFileParser owns this name and will decrement in
// the destructor.
_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.
void ClassFileParser::prepend_host_package_name(const InstanceKlass* unsafe_anonymous_host, TRAPS) {
ResourceMark rm(THREAD);
--- 5894,5903 ----
*** 5920,5931 ****
}
}
}
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 need_verify =
// verifyAll
(BytecodeVerificationLocal && BytecodeVerificationRemote) ||
// verifyRemote
(!BytecodeVerificationLocal && BytecodeVerificationRemote && !trusted);
--- 5946,5957 ----
}
}
}
static bool relax_format_check_for(ClassLoaderData* loader_data) {
! bool trusted = loader_data->is_boot_class_loader_data() ||
! loader_data->is_platform_class_loader_data();
bool need_verify =
// verifyAll
(BytecodeVerificationLocal && BytecodeVerificationRemote) ||
// verifyRemote
(!BytecodeVerificationLocal && BytecodeVerificationRemote && !trusted);
*** 5933,5953 ****
}
ClassFileParser::ClassFileParser(ClassFileStream* stream,
Symbol* name,
ClassLoaderData* loader_data,
! Handle protection_domain,
! const InstanceKlass* unsafe_anonymous_host,
! GrowableArray<Handle>* cp_patches,
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),
_num_patched_klasses(0),
_max_num_patched_klasses(0),
_orig_cp_size(0),
_first_patched_klass_resolved_index(0),
_super_klass(),
--- 5959,5978 ----
}
ClassFileParser::ClassFileParser(ClassFileStream* stream,
Symbol* name,
ClassLoaderData* loader_data,
! const ClassLoadInfo* cl_info,
Publicity pub_level,
TRAPS) :
_stream(stream),
_class_name(NULL),
_loader_data(loader_data),
! _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),
_first_patched_klass_resolved_index(0),
_super_klass(),
*** 5974,5984 ****
_all_mirandas(NULL),
_vtable_size(0),
_itable_size(0),
_num_miranda_methods(0),
_rt(REF_NONE),
! _protection_domain(protection_domain),
_access_flags(),
_pub_level(pub_level),
_bad_constant_seen(0),
_synthetic_flag(false),
_sde_length(false),
--- 5999,6009 ----
_all_mirandas(NULL),
_vtable_size(0),
_itable_size(0),
_num_miranda_methods(0),
_rt(REF_NONE),
! _protection_domain(cl_info->protection_domain()),
_access_flags(),
_pub_level(pub_level),
_bad_constant_seen(0),
_synthetic_flag(false),
_sde_length(false),
*** 6177,6190 ****
--- 6202,6220 ----
guarantee_property(
cp_size >= 1, "Illegal constant pool size %u in class file %s",
cp_size, CHECK);
_orig_cp_size = cp_size;
+ 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 = ConstantPool::allocate(_loader_data,
cp_size,
CHECK);
*** 6231,6270 ****
_this_class_index, CHECK);
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,
"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;
}
-
- // if this is an anonymous class fix up its name if it's in the unnamed
- // package. Otherwise, throw IAE if it is in a different package than
- // its host class.
- if (_unsafe_anonymous_host != NULL) {
- fix_unsafe_anonymous_class_name(CHECK);
}
// Verification prevents us from creating names with dots in them, this
// asserts that that's the case.
assert(is_internal_format(_class_name), "external class name format used internally");
--- 6261,6331 ----
_this_class_index, CHECK);
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");
// 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_in_cp->char_at(0) != JVM_SIGNATURE_ARRAY,
"Bad class name in class file %s",
CHECK);
}
! #ifdef ASSERT
! // Basic sanity checks
! assert(!(_is_hidden && (_unsafe_anonymous_host != NULL)), "mutually exclusive variants");
!
! 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.
! } 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
// asserts that that's the case.
assert(is_internal_format(_class_name), "external class name format used internally");
*** 6285,6297 ****
if (DumpLoadedClassList != NULL && stream->source() != NULL && classlist_file->is_open()) {
if (!ClassLoader::has_jrt_entry()) {
warning("DumpLoadedClassList and CDS are not supported in exploded build");
DumpLoadedClassList = NULL;
} else if (SystemDictionaryShared::is_sharing_possible(_loader_data) &&
_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.
oop class_loader = _loader_data->class_loader();
ResourceMark rm(THREAD);
bool skip = false;
if (class_loader == NULL || SystemDictionary::is_platform_class_loader(class_loader)) {
// For the boot and platform class loaders, skip classes that are not found in the
--- 6346,6359 ----
if (DumpLoadedClassList != NULL && stream->source() != NULL && classlist_file->is_open()) {
if (!ClassLoader::has_jrt_entry()) {
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.
! // 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;
if (class_loader == NULL || SystemDictionary::is_platform_class_loader(class_loader)) {
// For the boot and platform class loaders, skip classes that are not found in the
*** 6382,6391 ****
--- 6444,6482 ----
CHECK);
// 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) {
assert(stream != NULL, "invariant");
assert(stream->at_eos(), "invariant");
< prev index next >