8243287: Removal of Unsafe::defineAnonymousClass

Reviewed-by: iklam, mchung, alanb, dholmes
This commit is contained in:
Harold Seigel 2021-05-13 12:46:54 +00:00
parent a564f2cbd5
commit e14b026841
122 changed files with 328 additions and 3679 deletions

View File

@ -1871,9 +1871,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
// invoke-special-super // invoke-special-super
if (bc_raw == Bytecodes::_invokespecial && !target->is_object_initializer()) { if (bc_raw == Bytecodes::_invokespecial && !target->is_object_initializer()) {
ciInstanceKlass* sender_klass = ciInstanceKlass* sender_klass = calling_klass;
calling_klass->is_unsafe_anonymous() ? calling_klass->unsafe_anonymous_host() :
calling_klass;
if (sender_klass->is_interface()) { if (sender_klass->is_interface()) {
int index = state()->stack_size() - (target->arg_size_no_receiver() + 1); int index = state()->stack_size() - (target->arg_size_no_receiver() + 1);
Value receiver = state()->stack_at(index); Value receiver = state()->stack_at(index);

View File

@ -641,16 +641,12 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool,
} else if (tag.is_string()) { } else if (tag.is_string()) {
oop string = NULL; oop string = NULL;
assert(cache_index >= 0, "should have a cache index"); assert(cache_index >= 0, "should have a cache index");
if (cpool->is_pseudo_string_at(index)) {
string = cpool->pseudo_string_at(index, cache_index);
} else {
string = cpool->string_at(index, cache_index, THREAD); string = cpool->string_at(index, cache_index, THREAD);
if (HAS_PENDING_EXCEPTION) { if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION; CLEAR_PENDING_EXCEPTION;
record_out_of_memory_failure(); record_out_of_memory_failure();
return ciConstant(); return ciConstant();
} }
}
ciObject* constant = get_object(string); ciObject* constant = get_object(string);
if (constant->is_array()) { if (constant->is_array()) {
return ciConstant(T_ARRAY, constant); return ciConstant(T_ARRAY, constant);

View File

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

View File

@ -66,7 +66,6 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) :
_nonstatic_field_size = ik->nonstatic_field_size(); _nonstatic_field_size = ik->nonstatic_field_size();
_has_nonstatic_fields = ik->has_nonstatic_fields(); _has_nonstatic_fields = ik->has_nonstatic_fields();
_has_nonstatic_concrete_methods = ik->has_nonstatic_concrete_methods(); _has_nonstatic_concrete_methods = ik->has_nonstatic_concrete_methods();
_is_unsafe_anonymous = ik->is_unsafe_anonymous();
_is_hidden = ik->is_hidden(); _is_hidden = ik->is_hidden();
_is_record = ik->is_record(); _is_record = ik->is_record();
_nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields: _nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields:
@ -81,11 +80,11 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) :
oop holder = ik->klass_holder(); oop holder = ik->klass_holder();
if (ik->class_loader_data()->has_class_mirror_holder()) { if (ik->class_loader_data()->has_class_mirror_holder()) {
// Though ciInstanceKlass records class loader oop, it's not enough to keep // Though ciInstanceKlass records class loader oop, it's not enough to keep
// non-strong hidden classes and VM unsafe anonymous classes alive (loader == NULL). Klass holder should // non-strong hidden classes alive (loader == NULL). Klass holder should
// be used instead. It is enough to record a ciObject, since cached elements are never removed // be used instead. It is enough to record a ciObject, since cached elements are never removed
// during ciObjectFactory lifetime. ciObjectFactory itself is created for // during ciObjectFactory lifetime. ciObjectFactory itself is created for
// every compilation and lives for the whole duration of the compilation. // every compilation and lives for the whole duration of the compilation.
assert(holder != NULL, "holder of hidden or unsafe anonymous class is the mirror which is never null"); assert(holder != NULL, "holder of hidden class is the mirror which is never null");
(void)CURRENT_ENV->get_object(holder); (void)CURRENT_ENV->get_object(holder);
} }
@ -128,7 +127,6 @@ ciInstanceKlass::ciInstanceKlass(ciSymbol* name,
_has_nonstatic_fields = false; _has_nonstatic_fields = false;
_nonstatic_fields = NULL; _nonstatic_fields = NULL;
_has_injected_fields = -1; _has_injected_fields = -1;
_is_unsafe_anonymous = false;
_is_hidden = false; _is_hidden = false;
_is_record = false; _is_record = false;
_loader = loader; _loader = loader;
@ -660,16 +658,6 @@ ciInstanceKlass* ciInstanceKlass::implementor() {
return impl; return impl;
} }
ciInstanceKlass* ciInstanceKlass::unsafe_anonymous_host() {
assert(is_loaded(), "must be loaded");
if (is_unsafe_anonymous()) {
VM_ENTRY_MARK
Klass* unsafe_anonymous_host = get_instanceKlass()->unsafe_anonymous_host();
return CURRENT_ENV->get_instance_klass(unsafe_anonymous_host);
}
return NULL;
}
// Utility class for printing of the contents of the static fields for // Utility class for printing of the contents of the static fields for
// use by compilation replay. It only prints out the information that // use by compilation replay. It only prints out the information that
// could be consumed by the compiler, so for primitive types it prints // could be consumed by the compiler, so for primitive types it prints
@ -753,7 +741,7 @@ void ciInstanceKlass::dump_replay_data(outputStream* out) {
// Try to record related loaded classes // Try to record related loaded classes
Klass* sub = ik->subklass(); Klass* sub = ik->subklass();
while (sub != NULL) { while (sub != NULL) {
if (sub->is_instance_klass() && !sub->is_hidden() && !InstanceKlass::cast(sub)->is_unsafe_anonymous()) { if (sub->is_instance_klass() && !sub->is_hidden()) {
out->print_cr("instanceKlass %s", sub->name()->as_quoted_ascii()); out->print_cr("instanceKlass %s", sub->name()->as_quoted_ascii());
} }
sub = sub->next_sibling(); sub = sub->next_sibling();

View File

@ -56,7 +56,6 @@ private:
SubklassValue _has_subklass; SubklassValue _has_subklass;
bool _has_nonstatic_fields; bool _has_nonstatic_fields;
bool _has_nonstatic_concrete_methods; bool _has_nonstatic_concrete_methods;
bool _is_unsafe_anonymous;
bool _is_hidden; bool _is_hidden;
bool _is_record; bool _is_record;
@ -194,10 +193,6 @@ public:
return _has_nonstatic_concrete_methods; return _has_nonstatic_concrete_methods;
} }
bool is_unsafe_anonymous() const {
return _is_unsafe_anonymous;
}
bool is_hidden() const { bool is_hidden() const {
return _is_hidden; return _is_hidden;
} }
@ -290,8 +285,6 @@ public:
return NULL; return NULL;
} }
ciInstanceKlass* unsafe_anonymous_host();
bool can_be_instantiated() { bool can_be_instantiated() {
assert(is_loaded(), "must be loaded"); assert(is_loaded(), "must be loaded");
return !is_interface() && !is_abstract(); return !is_interface() && !is_abstract();

View File

@ -322,18 +322,6 @@ void ClassFileParser::parse_constant_pool_entries(const ClassFileStream* const s
verify_legal_utf8(utf8_buffer, utf8_length, CHECK); verify_legal_utf8(utf8_buffer, utf8_length, CHECK);
} }
if (has_cp_patch_at(index)) {
Handle patch = clear_cp_patch_at(index);
guarantee_property(java_lang_String::is_instance(patch()),
"Illegal utf8 patch at %d in class file %s",
index,
CHECK);
const char* const str = java_lang_String::as_utf8_string(patch());
// (could use java_lang_String::as_symbol instead, but might as well batch them)
utf8_buffer = (const u1*) str;
utf8_length = (u2) strlen(str);
}
unsigned int hash; unsigned int hash;
Symbol* const result = SymbolTable::lookup_only((const char*)utf8_buffer, Symbol* const result = SymbolTable::lookup_only((const char*)utf8_buffer,
utf8_length, utf8_length,
@ -616,37 +604,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
} // switch(tag) } // switch(tag)
} // end of for } // end of for
_first_patched_klass_resolved_index = num_klasses; cp->allocate_resolved_klasses(_loader_data, num_klasses, CHECK);
cp->allocate_resolved_klasses(_loader_data, num_klasses + _max_num_patched_klasses, CHECK);
if (_cp_patches != NULL) {
// need to treat this_class specially...
// Add dummy utf8 entries in the space reserved for names of patched classes. We'll use "*"
// for now. These will be replaced with actual names of the patched classes in patch_class().
Symbol* s = vmSymbols::star_name();
for (int n=_orig_cp_size; n<cp->length(); n++) {
cp->symbol_at_put(n, s);
}
int this_class_index;
{
stream->guarantee_more(8, CHECK); // flags, this_class, super_class, infs_len
const u1* const mark = stream->current();
stream->skip_u2_fast(1); // skip flags
this_class_index = stream->get_u2_fast();
stream->set_current(mark); // revert to mark
}
for (index = 1; index < length; index++) { // Index 0 is unused
if (has_cp_patch_at(index)) {
guarantee_property(index != this_class_index,
"Illegal constant pool patch to self at %d in class file %s",
index, CHECK);
patch_constant_pool(cp, index, cp_patch_at(index), CHECK);
}
}
}
if (!_need_verify) { if (!_need_verify) {
return; return;
@ -659,7 +617,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
switch (tag) { switch (tag) {
case JVM_CONSTANT_UnresolvedClass: { case JVM_CONSTANT_UnresolvedClass: {
const Symbol* const class_name = cp->klass_name_at(index); const Symbol* const class_name = cp->klass_name_at(index);
// check the name, even if _cp_patches will overwrite it // check the name
verify_legal_class_name(class_name, CHECK); verify_legal_class_name(class_name, CHECK);
break; break;
} }
@ -799,88 +757,6 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
} // end of for } // end of for
} }
Handle ClassFileParser::clear_cp_patch_at(int index) {
Handle patch = cp_patch_at(index);
_cp_patches->at_put(index, Handle());
assert(!has_cp_patch_at(index), "");
return patch;
}
void ClassFileParser::patch_class(ConstantPool* cp, int class_index, Klass* k, Symbol* name) {
int name_index = _orig_cp_size + _num_patched_klasses;
int resolved_klass_index = _first_patched_klass_resolved_index + _num_patched_klasses;
cp->klass_at_put(class_index, name_index, resolved_klass_index, k, name);
_num_patched_klasses ++;
}
void ClassFileParser::patch_constant_pool(ConstantPool* cp,
int index,
Handle patch,
TRAPS) {
assert(cp != NULL, "invariant");
BasicType patch_type = T_VOID;
switch (cp->tag_at(index).value()) {
case JVM_CONSTANT_UnresolvedClass: {
// Patching a class means pre-resolving it.
// The name in the constant pool is ignored.
if (java_lang_Class::is_instance(patch())) {
guarantee_property(!java_lang_Class::is_primitive(patch()),
"Illegal class patch at %d in class file %s",
index, CHECK);
Klass* k = java_lang_Class::as_Klass(patch());
patch_class(cp, index, k, k->name());
} else {
guarantee_property(java_lang_String::is_instance(patch()),
"Illegal class patch at %d in class file %s",
index, CHECK);
Symbol* const name = java_lang_String::as_symbol(patch());
patch_class(cp, index, NULL, name);
}
break;
}
case JVM_CONSTANT_String: {
// skip this patch and don't clear it. Needs the oop array for resolved
// references to be created first.
return;
}
case JVM_CONSTANT_Integer: patch_type = T_INT; goto patch_prim;
case JVM_CONSTANT_Float: patch_type = T_FLOAT; goto patch_prim;
case JVM_CONSTANT_Long: patch_type = T_LONG; goto patch_prim;
case JVM_CONSTANT_Double: patch_type = T_DOUBLE; goto patch_prim;
patch_prim:
{
jvalue value;
BasicType value_type = java_lang_boxing_object::get_value(patch(), &value);
guarantee_property(value_type == patch_type,
"Illegal primitive patch at %d in class file %s",
index, CHECK);
switch (value_type) {
case T_INT: cp->int_at_put(index, value.i); break;
case T_FLOAT: cp->float_at_put(index, value.f); break;
case T_LONG: cp->long_at_put(index, value.j); break;
case T_DOUBLE: cp->double_at_put(index, value.d); break;
default: assert(false, "");
}
} // end patch_prim label
break;
default: {
// %%% TODO: put method handles into CONSTANT_InterfaceMethodref, etc.
guarantee_property(!has_cp_patch_at(index),
"Illegal unexpected patch at %d in class file %s",
index, CHECK);
return;
}
} // end of switch(tag)
// On fall-through, mark the patch as used.
clear_cp_patch_at(index);
}
class NameSigHash: public ResourceObj { class NameSigHash: public ResourceObj {
public: public:
const Symbol* _name; // name const Symbol* _name; // name
@ -5429,11 +5305,11 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
ik->set_this_class_index(_this_class_index); ik->set_this_class_index(_this_class_index);
if (_is_hidden || is_unsafe_anonymous()) { if (_is_hidden) {
// _this_class_index is a CONSTANT_Class entry that refers to this // _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 // hidden class itself. If this class needs to refer to its own methods
// methods or fields, it would use a CONSTANT_MethodRef, etc, which would reference // 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 // _this_class_index. However, because this class is hidden (it's
// not stored in SystemDictionary), _this_class_index cannot be resolved // not stored in SystemDictionary), _this_class_index cannot be resolved
// with ConstantPool::klass_at_impl, which does a SystemDictionary lookup. // with ConstantPool::klass_at_impl, which does a SystemDictionary lookup.
// Therefore, we must eagerly resolve _this_class_index now. // Therefore, we must eagerly resolve _this_class_index now.
@ -5445,10 +5321,6 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
ik->set_has_nonstatic_concrete_methods(_has_nonstatic_concrete_methods); ik->set_has_nonstatic_concrete_methods(_has_nonstatic_concrete_methods);
ik->set_declares_nonstatic_concrete_methods(_declares_nonstatic_concrete_methods); ik->set_declares_nonstatic_concrete_methods(_declares_nonstatic_concrete_methods);
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) { if (_is_hidden) {
ik->set_is_hidden(); ik->set_is_hidden();
} }
@ -5614,57 +5486,6 @@ void ClassFileParser::update_class_name(Symbol* new_class_name) {
_class_name->increment_refcount(); _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(Thread* current, const InstanceKlass* unsafe_anonymous_host) {
ResourceMark rm(current);
assert(strrchr(_class_name->as_C_string(), JVM_SIGNATURE_SLASH) == NULL,
"Unsafe anonymous class should not be in a package");
TempNewSymbol host_pkg_name =
ClassLoader::package_from_class_name(unsafe_anonymous_host->name());
if (host_pkg_name != NULL) {
int host_pkg_len = host_pkg_name->utf8_length();
int class_name_len = _class_name->utf8_length();
int symbol_len = host_pkg_len + 1 + class_name_len;
char* new_anon_name = NEW_RESOURCE_ARRAY(char, symbol_len + 1);
int n = os::snprintf(new_anon_name, symbol_len + 1, "%.*s/%.*s",
host_pkg_len, host_pkg_name->base(), class_name_len, _class_name->base());
assert(n == symbol_len, "Unexpected number of characters in string");
// Decrement old _class_name to avoid leaking.
_class_name->decrement_refcount();
// Create a symbol and update the anonymous class name.
// The new class name is created with a refcount of one. When installed into the InstanceKlass,
// it'll be two and when the ClassFileParser destructor runs, it'll go back to one and get deleted
// when the class is unloaded.
_class_name = SymbolTable::new_symbol(new_anon_name, symbol_len);
}
}
// If the host class and the anonymous class are in the same package then do
// nothing. If the anonymous class is in the unnamed package then move it to its
// host's package. If the classes are in different packages then throw an IAE
// exception.
void ClassFileParser::fix_unsafe_anonymous_class_name(TRAPS) {
assert(_unsafe_anonymous_host != NULL, "Expected an unsafe anonymous class");
const jbyte* anon_last_slash = UTF8::strrchr((const jbyte*)_class_name->base(),
_class_name->utf8_length(), JVM_SIGNATURE_SLASH);
if (anon_last_slash == NULL) { // Unnamed package
prepend_host_package_name(THREAD, _unsafe_anonymous_host);
} else {
if (!_unsafe_anonymous_host->is_same_class_package(_unsafe_anonymous_host->class_loader(), _class_name)) {
ResourceMark rm(THREAD);
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
err_msg("Host class %s and anonymous class %s are in different packages",
_unsafe_anonymous_host->name()->as_C_string(), _class_name->as_C_string()));
}
}
}
static bool relax_format_check_for(ClassLoaderData* loader_data) { static bool relax_format_check_for(ClassLoaderData* loader_data) {
bool trusted = loader_data->is_boot_class_loader_data() || bool trusted = loader_data->is_boot_class_loader_data() ||
loader_data->is_platform_class_loader_data(); loader_data->is_platform_class_loader_data();
@ -5685,14 +5506,9 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_stream(stream), _stream(stream),
_class_name(NULL), _class_name(NULL),
_loader_data(loader_data), _loader_data(loader_data),
_unsafe_anonymous_host(cl_info->unsafe_anonymous_host()),
_cp_patches(cl_info->cp_patches()),
_is_hidden(cl_info->is_hidden()), _is_hidden(cl_info->is_hidden()),
_can_access_vm_annotations(cl_info->can_access_vm_annotations()), _can_access_vm_annotations(cl_info->can_access_vm_annotations()),
_num_patched_klasses(0),
_max_num_patched_klasses(0),
_orig_cp_size(0), _orig_cp_size(0),
_first_patched_klass_resolved_index(0),
_super_klass(), _super_klass(),
_cp(NULL), _cp(NULL),
_fields(NULL), _fields(NULL),
@ -5769,25 +5585,6 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_need_verify = Verifier::should_verify_for(_loader_data->class_loader(), _need_verify = Verifier::should_verify_for(_loader_data->class_loader(),
stream->need_verify()); stream->need_verify());
} }
if (_cp_patches != NULL) {
int len = _cp_patches->length();
for (int i=0; i<len; i++) {
if (has_cp_patch_at(i)) {
Handle patch = cp_patch_at(i);
if (java_lang_String::is_instance(patch()) || java_lang_Class::is_instance(patch())) {
// We need to append the names of the patched classes to the end of the constant pool,
// because a patched class may have a Utf8 name that's not already included in the
// original constant pool. These class names are used when patch_constant_pool()
// calls patch_class().
//
// Note that a String in cp_patch_at(i) may be used to patch a Utf8, a String, or a Class.
// At this point, we don't know the tag for index i yet, because we haven't parsed the
// constant pool. So we can only assume the worst -- every String is used to patch a Class.
_max_num_patched_klasses++;
}
}
}
}
// synch back verification state to stream // synch back verification state to stream
stream->set_verify(_need_verify); stream->set_verify(_need_verify);
@ -5917,13 +5714,7 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
_orig_cp_size = cp_size; _orig_cp_size = cp_size;
if (is_hidden()) { // Add a slot for hidden class name. if (is_hidden()) { // Add a slot for hidden class name.
assert(_max_num_patched_klasses == 0, "Sanity check");
cp_size++; 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 = ConstantPool::allocate(_loader_data,
@ -5987,18 +5778,12 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
#ifdef ASSERT #ifdef ASSERT
// Basic sanity checks // 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) { if (_is_hidden) {
assert(_class_name != vmSymbols::unknown_class_name(), "hidden classes should have a special name"); assert(_class_name != vmSymbols::unknown_class_name(), "hidden classes should have a special name");
} }
#endif #endif
// Update the _class_name as needed depending on whether this is a named, // Update the _class_name as needed depending on whether this is a named, un-named, or hidden class.
// un-named, hidden or unsafe-anonymous class.
if (_is_hidden) { if (_is_hidden) {
assert(_class_name != NULL, "Unexpected null _class_name"); assert(_class_name != NULL, "Unexpected null _class_name");
@ -6008,16 +5793,6 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
} }
#endif #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 { } else {
// Check if name in class file matches given name // Check if name in class file matches given name
if (_class_name != class_name_in_cp) { if (_class_name != class_name_in_cp) {

View File

@ -113,14 +113,9 @@ class ClassFileParser {
const ClassFileStream* _stream; // Actual input stream const ClassFileStream* _stream; // Actual input stream
Symbol* _class_name; Symbol* _class_name;
mutable ClassLoaderData* _loader_data; mutable ClassLoaderData* _loader_data;
const InstanceKlass* _unsafe_anonymous_host;
GrowableArray<Handle>* _cp_patches; // overrides for CP entries
const bool _is_hidden; const bool _is_hidden;
const bool _can_access_vm_annotations; const bool _can_access_vm_annotations;
int _num_patched_klasses;
int _max_num_patched_klasses;
int _orig_cp_size; int _orig_cp_size;
int _first_patched_klass_resolved_index;
// Metadata created before the instance klass is created. Must be deallocated // Metadata created before the instance klass is created. Must be deallocated
// if not transferred to the InstanceKlass upon successful class loading // if not transferred to the InstanceKlass upon successful class loading
@ -211,9 +206,6 @@ class ClassFileParser {
ConstantPool* cp, ConstantPool* cp,
TRAPS); TRAPS);
void prepend_host_package_name(Thread* current, const InstanceKlass* unsafe_anonymous_host);
void fix_unsafe_anonymous_class_name(TRAPS);
void fill_instance_klass(InstanceKlass* ik, bool cf_changed_in_CFLH, void fill_instance_klass(InstanceKlass* ik, bool cf_changed_in_CFLH,
const ClassInstanceInfo& cl_inst_info, TRAPS); const ClassInstanceInfo& cl_inst_info, TRAPS);
@ -494,26 +486,6 @@ class ClassFileParser {
unsigned int length, unsigned int length,
TRAPS) const; TRAPS) const;
bool has_cp_patch_at(int index) const {
assert(index >= 0, "oob");
return (_cp_patches != NULL
&& index < _cp_patches->length()
&& _cp_patches->adr_at(index)->not_null());
}
Handle cp_patch_at(int index) const {
assert(has_cp_patch_at(index), "oob");
return _cp_patches->at(index);
}
Handle clear_cp_patch_at(int index);
void patch_class(ConstantPool* cp, int class_index, Klass* k, Symbol* name);
void patch_constant_pool(ConstantPool* cp,
int index,
Handle patch,
TRAPS);
// Wrapper for constantTag.is_klass_[or_]reference. // Wrapper for constantTag.is_klass_[or_]reference.
// In older versions of the VM, Klass*s cannot sneak into early phases of // In older versions of the VM, Klass*s cannot sneak into early phases of
// constant pool construction, but in later versions they can. // constant pool construction, but in later versions they can.
@ -582,12 +554,9 @@ class ClassFileParser {
u2 this_class_index() const { return _this_class_index; } 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_hidden() const { return _is_hidden; }
bool is_interface() const { return _access_flags.is_interface(); } bool is_interface() const { return _access_flags.is_interface(); }
const InstanceKlass* unsafe_anonymous_host() const { return _unsafe_anonymous_host; }
const GrowableArray<Handle>* cp_patches() const { return _cp_patches; }
ClassLoaderData* loader_data() const { return _loader_data; } ClassLoaderData* loader_data() const { return _loader_data; }
const Symbol* class_name() const { return _class_name; } const Symbol* class_name() const { return _class_name; }
const InstanceKlass* super_klass() const { return _super_klass; } const InstanceKlass* super_klass() const { return _super_klass; }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -54,8 +54,6 @@ class ClassInstanceInfo : public StackObj {
class ClassLoadInfo : public StackObj { class ClassLoadInfo : public StackObj {
private: private:
Handle _protection_domain; Handle _protection_domain;
const InstanceKlass* _unsafe_anonymous_host;
GrowableArray<Handle>* _cp_patches;
ClassInstanceInfo _class_hidden_info; ClassInstanceInfo _class_hidden_info;
bool _is_hidden; bool _is_hidden;
bool _is_strong_hidden; bool _is_strong_hidden;
@ -64,8 +62,6 @@ class ClassLoadInfo : public StackObj {
public: public:
ClassLoadInfo(Handle protection_domain) { ClassLoadInfo(Handle protection_domain) {
_protection_domain = protection_domain; _protection_domain = protection_domain;
_unsafe_anonymous_host = NULL;
_cp_patches = NULL;
_class_hidden_info._dynamic_nest_host = NULL; _class_hidden_info._dynamic_nest_host = NULL;
_class_hidden_info._class_data = Handle(); _class_hidden_info._class_data = Handle();
_is_hidden = false; _is_hidden = false;
@ -73,13 +69,10 @@ class ClassLoadInfo : public StackObj {
_can_access_vm_annotations = false; _can_access_vm_annotations = false;
} }
ClassLoadInfo(Handle protection_domain, const InstanceKlass* unsafe_anonymous_host, ClassLoadInfo(Handle protection_domain, InstanceKlass* dynamic_nest_host,
GrowableArray<Handle>* cp_patches, InstanceKlass* dynamic_nest_host,
Handle class_data, bool is_hidden, bool is_strong_hidden, Handle class_data, bool is_hidden, bool is_strong_hidden,
bool can_access_vm_annotations) { bool can_access_vm_annotations) {
_protection_domain = protection_domain; _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._dynamic_nest_host = dynamic_nest_host;
_class_hidden_info._class_data = class_data; _class_hidden_info._class_data = class_data;
_is_hidden = is_hidden; _is_hidden = is_hidden;
@ -88,8 +81,6 @@ class ClassLoadInfo : public StackObj {
} }
Handle protection_domain() const { return _protection_domain; } 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; } const ClassInstanceInfo* class_hidden_info_ptr() const { return &_class_hidden_info; }
bool is_hidden() const { return _is_hidden; } bool is_hidden() const { return _is_hidden; }
bool is_strong_hidden() const { return _is_strong_hidden; } bool is_strong_hidden() const { return _is_strong_hidden; }

View File

@ -1256,8 +1256,8 @@ void ClassLoader::record_result(Thread* current, InstanceKlass* ik, const ClassF
Arguments::assert_is_dumping_archive(); Arguments::assert_is_dumping_archive();
assert(stream != NULL, "sanity"); assert(stream != NULL, "sanity");
if (ik->is_hidden() || ik->is_unsafe_anonymous()) { if (ik->is_hidden()) {
// We do not archive hidden or unsafe anonymous classes. // We do not archive hidden classes.
return; return;
} }

View File

@ -138,8 +138,8 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool has_class_mirror_ho
Mutex::_safepoint_check_never)), Mutex::_safepoint_check_never)),
_unloading(false), _has_class_mirror_holder(has_class_mirror_holder), _unloading(false), _has_class_mirror_holder(has_class_mirror_holder),
_modified_oops(true), _modified_oops(true),
// An unsafe anonymous class loader data doesn't have anything to keep // A non-strong hidden class loader data doesn't have anything to keep
// it from being unloaded during parsing of the unsafe anonymous class. // it from being unloaded during parsing of the non-strong hidden class.
// The null-class-loader should always be kept alive. // The null-class-loader should always be kept alive.
_keep_alive((has_class_mirror_holder || h_class_loader.is_null()) ? 1 : 0), _keep_alive((has_class_mirror_holder || h_class_loader.is_null()) ? 1 : 0),
_claim(0), _claim(0),
@ -157,13 +157,12 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool has_class_mirror_ho
} }
if (!has_class_mirror_holder) { if (!has_class_mirror_holder) {
// The holder is initialized later for non-strong hidden classes and unsafe anonymous classes, // The holder is initialized later for non-strong hidden classes,
// and before calling anything that call class_loader(). // and before calling anything that call class_loader().
initialize_holder(h_class_loader); initialize_holder(h_class_loader);
// A ClassLoaderData created solely for a non-strong hidden class or unsafe anonymous class should // A ClassLoaderData created solely for a non-strong hidden class should never
// never have a ModuleEntryTable or PackageEntryTable created for it. The defining package // have a ModuleEntryTable or PackageEntryTable created for it.
// and module for an unsafe anonymous class will be found in its host class.
_packages = new PackageEntryTable(PackageEntryTable::_packagetable_entry_size); _packages = new PackageEntryTable(PackageEntryTable::_packagetable_entry_size);
if (h_class_loader.is_null()) { if (h_class_loader.is_null()) {
// Create unnamed module for boot loader // Create unnamed module for boot loader
@ -297,10 +296,10 @@ bool ClassLoaderData::try_claim(int claim) {
} }
} }
// Weak hidden and unsafe anonymous classes have their own ClassLoaderData that is marked to keep alive // Non-strong hidden 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. // 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 hidden or unsafe anonymous class' name or // Due to the uniqueness that no other class shares the hidden class' name or
// ClassLoaderData, no other non-GC thread has knowledge of the hidden or unsafe anonymous class while // ClassLoaderData, no other non-GC thread has knowledge of the hidden class while
// it is being defined, therefore _keep_alive is not volatile or atomic. // it is being defined, therefore _keep_alive is not volatile or atomic.
void ClassLoaderData::inc_keep_alive() { void ClassLoaderData::inc_keep_alive() {
if (has_class_mirror_holder()) { if (has_class_mirror_holder()) {
@ -426,13 +425,13 @@ void ClassLoaderData::record_dependency(const Klass* k) {
oop to; oop to;
if (to_cld->has_class_mirror_holder()) { 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 // Just return if a non-strong hidden class 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 // to itself. (Note that every non-strong hidden class has its own unique class
// loader data.) // loader data.)
if (to_cld == from_cld) { if (to_cld == from_cld) {
return; return;
} }
// Hidden and unsafe anonymous class dependencies are through the mirror. // Hidden class dependencies are through the mirror.
to = k->java_mirror(); to = k->java_mirror();
} else { } else {
to = to_cld->class_loader(); to = to_cld->class_loader();
@ -626,7 +625,7 @@ oop ClassLoaderData::holder_no_keepalive() const {
// Unloading support // Unloading support
bool ClassLoaderData::is_alive() const { bool ClassLoaderData::is_alive() const {
bool alive = keep_alive() // null class loader and incomplete non-strong hidden class or unsafe anonymous class. bool alive = keep_alive() // null class loader and incomplete non-strong hidden class.
|| (_holder.peek() != NULL); // and not cleaned by the GC weak handle processing. || (_holder.peek() != NULL); // and not cleaned by the GC weak handle processing.
return alive; return alive;
@ -738,7 +737,7 @@ bool ClassLoaderData::is_platform_class_loader_data() const {
// Returns true if the class loader for this class loader data is one of // Returns true if the class loader for this class loader data is one of
// the 3 builtin (boot application/system or platform) class loaders, // the 3 builtin (boot application/system or platform) class loaders,
// including a user-defined system class loader. Note that if the class // including a user-defined system class loader. Note that if the class
// loader data is for a non-strong hidden class or unsafe anonymous class then it may // loader data is for a non-strong hidden class then it may
// get freed by a GC even if its class loader is one of these loaders. // get freed by a GC even if its class loader is one of these loaders.
bool ClassLoaderData::is_builtin_class_loader_data() const { bool ClassLoaderData::is_builtin_class_loader_data() const {
return (is_boot_class_loader_data() || return (is_boot_class_loader_data() ||
@ -748,7 +747,7 @@ bool ClassLoaderData::is_builtin_class_loader_data() const {
// Returns true if this class loader data is a class loader data // 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 // 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 a non-strong hidden class or unsafe anonymous class. // class loaders and not the CLD for a non-strong hidden class.
bool ClassLoaderData::is_permanent_class_loader_data() const { bool ClassLoaderData::is_permanent_class_loader_data() const {
return is_builtin_class_loader_data() && !has_class_mirror_holder(); return is_builtin_class_loader_data() && !has_class_mirror_holder();
} }

View File

@ -117,18 +117,17 @@ class ClassLoaderData : public CHeapObj<mtClass> {
Mutex* _metaspace_lock; // Locks the metaspace for allocations and setup. Mutex* _metaspace_lock; // Locks the metaspace for allocations and setup.
bool _unloading; // true if this class loader goes away bool _unloading; // true if this class loader goes away
bool _has_class_mirror_holder; // If true, CLD is dedicated to one class and that class determines 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 // the CLDs lifecycle. For example, a non-strong hidden class.
// unsafe anonymous class. Arrays of these classes are also assigned // Arrays of these classes are also assigned
// to these class loader datas. // to these class loader datas.
// Remembered sets support for the oops in the class loader data. // Remembered sets support for the oops in the class loader data.
bool _modified_oops; // Card Table Equivalent bool _modified_oops; // Card Table Equivalent
int _keep_alive; // if this CLD is kept alive. int _keep_alive; // if this CLD is kept alive.
// Used for non-strong hidden classes, unsafe anonymous classes and the // Used for non-strong hidden classes and the
// boot class loader. _keep_alive does not need to be volatile or // boot class loader. _keep_alive does not need to be volatile or
// atomic since there is one unique CLD per non-strong hidden class // 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. volatile int _claim; // non-zero if claimed, for example during GC traces.
// To avoid applying oop closure more than once. // To avoid applying oop closure more than once.
@ -238,15 +237,15 @@ class ClassLoaderData : public CHeapObj<mtClass> {
} }
// Returns true if this class loader data is for the system class loader. // Returns true if this class loader data is for the system class loader.
// (Note that the class loader data may be for a non-strong hidden class or unsafe anonymous class) // (Note that the class loader data may be for a non-strong hidden class)
bool is_system_class_loader_data() const; bool is_system_class_loader_data() const;
// Returns true if this class loader data is for the platform class loader. // Returns true if this class loader data is for the platform class loader.
// (Note that the class loader data may be for a non-strong hidden class or unsafe anonymous class) // (Note that the class loader data may be for a non-strong hidden class)
bool is_platform_class_loader_data() const; bool is_platform_class_loader_data() const;
// Returns true if this class loader data is for the boot class loader. // Returns true if this class loader data is for the boot class loader.
// (Note that the class loader data may be for a non-strong hidden class or unsafe anonymous class) // (Note that the class loader data may be for a non-strong hidden class)
inline bool is_boot_class_loader_data() const; inline bool is_boot_class_loader_data() const;
bool is_builtin_class_loader_data() const; bool is_builtin_class_loader_data() const;
@ -267,8 +266,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
return _unloading; return _unloading;
} }
// Used to refcount a non-strong hidden class's or unsafe anonymous class's CLD in order to // Used to refcount a non-strong hidden class's s CLD in order to indicate their aliveness.
// indicate their aliveness.
void inc_keep_alive(); void inc_keep_alive();
void dec_keep_alive(); void dec_keep_alive();

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -76,7 +76,7 @@ class ClassLoaderDataGraph : public AllStatic {
// Walking classes through the ClassLoaderDataGraph include array classes. It also includes // 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 // 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. // for redefinition. These classes are removed during the next class unloading.
// Walking the ClassLoaderDataGraph also includes hidden and unsafe anonymous classes. // Walking the ClassLoaderDataGraph also includes hidden classes.
static void classes_do(KlassClosure* klass_closure); static void classes_do(KlassClosure* klass_closure);
static void classes_do(void f(Klass* const)); static void classes_do(void f(Klass* const));
static void methods_do(void f(Method*)); static void methods_do(void f(Method*));

View File

@ -45,7 +45,7 @@ class ArchivedClassLoaderData {
// system loaders (e.g., if you create a custom JDK image with only java.base). // system loaders (e.g., if you create a custom JDK image with only java.base).
if (loader_data != NULL) { if (loader_data != NULL) {
assert(!loader_data->has_class_mirror_holder(), assert(!loader_data->has_class_mirror_holder(),
"loaders for non-strong hidden classes or unsafe anonymous classes not supported"); "loaders for non-strong hidden classes not supported");
} }
} }
public: public:

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018 SAP SE. All rights reserved. * Copyright (c) 2018 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
@ -221,7 +221,7 @@ class LoaderTreeNode : public ResourceObj {
if (print_classes) { if (print_classes) {
if (_classes != NULL) { if (_classes != NULL) {
for (LoadedClassInfo* lci = _classes; lci; lci = lci->_next) { for (LoadedClassInfo* lci = _classes; lci; lci = lci->_next) {
// non-strong hidden and unsafe anonymous classes should not live in // non-strong hidden classes should not live in
// the primary CLD of their loaders. // the primary CLD of their loaders.
assert(lci->_cld == _cld, "must be"); assert(lci->_cld == _cld, "must be");

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -49,7 +49,7 @@ void ClassLoaderStatsClosure::do_cld(ClassLoaderData* cld) {
oop cl = cld->class_loader(); oop cl = cld->class_loader();
// The hashtable key is the ClassLoader oop since we want to account // The hashtable key is the ClassLoader oop since we want to account
// for "real" classes and anonymous classes together // for "real" classes and hidden classes together
bool added = false; bool added = false;
ClassLoaderStats* cls = _stats->put_if_absent(cl, &added); ClassLoaderStats* cls = _stats->put_if_absent(cl, &added);
if (added) { if (added) {
@ -71,7 +71,7 @@ void ClassLoaderStatsClosure::do_cld(ClassLoaderData* cld) {
cld->classes_do(&csc); cld->classes_do(&csc);
bool is_hidden = false; bool is_hidden = false;
if(cld->has_class_mirror_holder()) { if(cld->has_class_mirror_holder()) {
// If cld has a class holder then it must be either hidden or unsafe anonymous. // If cld has a class holder then it must be hidden.
// Either way, count it as a hidden class. // Either way, count it as a hidden class.
cls->_hidden_classes_count += csc._num_classes; cls->_hidden_classes_count += csc._num_classes;
} else { } else {

View File

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

View File

@ -4062,7 +4062,7 @@ oop java_lang_invoke_ResolvedMethodName::find_resolved_method(const methodHandle
InstanceKlass* holder = method->method_holder(); InstanceKlass* holder = method->method_holder();
set_vmtarget(new_resolved_method, const_cast<Method*>(method)); set_vmtarget(new_resolved_method, const_cast<Method*>(method));
// Add a reference to the loader (actually mirror because unsafe anonymous classes will not have // Add a reference to the loader (actually mirror because hidden classes may not have
// distinct loaders) to ensure the metadata is kept alive. // distinct loaders) to ensure the metadata is kept alive.
// This mirror may be different than the one in clazz field. // This mirror may be different than the one in clazz field.
set_vmholder(new_resolved_method, holder->java_mirror()); set_vmholder(new_resolved_method, holder->java_mirror());
@ -5008,7 +5008,7 @@ bool JavaClasses::is_supported_for_archiving(oop obj) {
if (klass == vmClasses::ClassLoader_klass() || // ClassLoader::loader_data is malloc'ed. if (klass == vmClasses::ClassLoader_klass() || // ClassLoader::loader_data is malloc'ed.
// The next 3 classes are used to implement java.lang.invoke, and are not used directly in // The next 3 classes are used to implement java.lang.invoke, and are not used directly in
// regular Java code. The implementation of java.lang.invoke uses generated anonymous classes // regular Java code. The implementation of java.lang.invoke uses generated hidden classes
// (e.g., as referenced by ResolvedMethodName::vmholder) that are not yet supported by CDS. // (e.g., as referenced by ResolvedMethodName::vmholder) that are not yet supported by CDS.
// So for now we cannot not support these classes for archiving. // So for now we cannot not support these classes for archiving.
// //

View File

@ -183,11 +183,8 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
// increment counter // increment counter
THREAD->statistical_info().incr_define_class_count(); THREAD->statistical_info().incr_define_class_count();
assert(!(cl_info.is_hidden() && (cl_info.unsafe_anonymous_host() != NULL)), // Skip this processing for VM hidden classes
"hidden class has an anonymous host"); if (!cl_info.is_hidden()) {
// 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, stream = check_class_file_load_hook(stream,
name, name,
loader_data, loader_data,

View File

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

View File

@ -818,7 +818,7 @@ Klass* SystemDictionary::find_instance_or_array_klass(Symbol* class_name,
// Note: this method is much like resolve_class_from_stream, but // Note: this method is much like resolve_class_from_stream, but
// does not publish the classes in the SystemDictionary. // does not publish the classes in the SystemDictionary.
// Handles Lookup.defineClass hidden and unsafe_DefineAnonymousClass. // Handles Lookup.defineClass hidden.
InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream( InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream(
ClassFileStream* st, ClassFileStream* st,
Symbol* class_name, Symbol* class_name,
@ -828,17 +828,12 @@ InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream(
EventClassLoad class_load_start_event; EventClassLoad class_load_start_event;
ClassLoaderData* loader_data; ClassLoaderData* loader_data;
bool is_unsafe_anon_class = cl_info.unsafe_anonymous_host() != NULL;
// - for unsafe anonymous class: create a new CLD whith a class holder that uses
// the same class loader as the unsafe_anonymous_host.
// - for hidden classes that are not strong: create a new CLD that has a class holder and // - for hidden classes that are not strong: create a new CLD that has a class holder and
// whose loader is the Lookup class's loader. // whose loader is the Lookup class's loader.
// - for hidden class: add the class to the Lookup class's loader's CLD. // - for hidden class: add the class to the Lookup class's loader's CLD.
assert (is_unsafe_anon_class || cl_info.is_hidden(), "only used for hidden classes"); assert (cl_info.is_hidden(), "only used for hidden classes");
guarantee(!is_unsafe_anon_class || cl_info.unsafe_anonymous_host()->class_loader() == class_loader(), bool create_mirror_cld = !cl_info.is_strong_hidden();
"should be NULL or the same");
bool create_mirror_cld = is_unsafe_anon_class || !cl_info.is_strong_hidden();
loader_data = register_loader(class_loader, create_mirror_cld); loader_data = register_loader(class_loader, create_mirror_cld);
assert(st != NULL, "invariant"); assert(st != NULL, "invariant");
@ -852,10 +847,9 @@ InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream(
CHECK_NULL); CHECK_NULL);
assert(k != NULL, "no klass created"); assert(k != NULL, "no klass created");
// Hidden classes that are not strong and unsafe anonymous classes must update // Hidden classes that are not strong must update ClassLoaderData holder
// ClassLoaderData holder so that they can be unloaded when the mirror is no // so that they can be unloaded when the mirror is no longer referenced.
// longer referenced. if (!cl_info.is_strong_hidden()) {
if (!cl_info.is_strong_hidden() || is_unsafe_anon_class) {
k->class_loader_data()->initialize_holder(Handle(THREAD, k->java_mirror())); k->class_loader_data()->initialize_holder(Handle(THREAD, k->java_mirror()));
} }
@ -866,16 +860,7 @@ InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream(
// But, do not add to dictionary. // But, do not add to dictionary.
} }
// Rewrite and patch constant pool here.
k->link_class(CHECK_NULL); k->link_class(CHECK_NULL);
if (cl_info.cp_patches() != NULL) {
k->constants()->patch_resolved_references(cl_info.cp_patches());
}
// If it's anonymous, initialize it now, since nobody else will.
if (is_unsafe_anon_class) {
k->eager_initialize(CHECK_NULL);
}
// notify jvmti // notify jvmti
if (JvmtiExport::should_post_class_load()) { if (JvmtiExport::should_post_class_load()) {
@ -885,9 +870,6 @@ InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream(
post_class_load_event(&class_load_start_event, k, loader_data); post_class_load_event(&class_load_start_event, k, loader_data);
} }
assert(is_unsafe_anon_class || NULL == cl_info.cp_patches(),
"cp_patches only found with unsafe_anonymous_host");
return k; return k;
} }
@ -965,8 +947,7 @@ InstanceKlass* SystemDictionary::resolve_from_stream(ClassFileStream* st,
Handle class_loader, Handle class_loader,
const ClassLoadInfo& cl_info, const ClassLoadInfo& cl_info,
TRAPS) { TRAPS) {
bool is_unsafe_anon_class = cl_info.unsafe_anonymous_host() != NULL; if (cl_info.is_hidden()) {
if (cl_info.is_hidden() || is_unsafe_anon_class) {
return resolve_hidden_class_from_stream(st, class_name, class_loader, cl_info, CHECK_NULL); return resolve_hidden_class_from_stream(st, class_name, class_loader, cl_info, CHECK_NULL);
} else { } else {
return resolve_class_from_stream(st, class_name, class_loader, cl_info, CHECK_NULL); return resolve_class_from_stream(st, class_name, class_loader, cl_info, CHECK_NULL);
@ -1183,7 +1164,7 @@ InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik,
} }
InstanceKlass* new_ik = NULL; InstanceKlass* new_ik = NULL;
// CFLH check is skipped for VM hidden or anonymous classes (see KlassFactory::create_from_stream). // CFLH check is skipped for VM hidden classes (see KlassFactory::create_from_stream).
// It will be skipped for shared VM hidden lambda proxy classes. // It will be skipped for shared VM hidden lambda proxy classes.
if (!SystemDictionaryShared::is_hidden_lambda_proxy(ik)) { if (!SystemDictionaryShared::is_hidden_lambda_proxy(ik)) {
new_ik = KlassFactory::check_shared_class_file_load_hook( new_ik = KlassFactory::check_shared_class_file_load_hook(
@ -1618,7 +1599,6 @@ void SystemDictionary::add_to_hierarchy(InstanceKlass* k) {
// GC support // GC support
// Assumes classes in the SystemDictionary are only unloaded at a safepoint // Assumes classes in the SystemDictionary are only unloaded at a safepoint
// Note: anonymous classes are not in the SD.
bool SystemDictionary::do_unloading(GCTimer* gc_timer) { bool SystemDictionary::do_unloading(GCTimer* gc_timer) {
bool unloading_occurred; bool unloading_occurred;

View File

@ -118,8 +118,8 @@ class SystemDictionary : AllStatic {
bool is_superclass, bool is_superclass,
TRAPS); TRAPS);
private: private:
// Parse the stream to create an unsafe anonymous or hidden class. // Parse the stream to create a hidden class.
// Used by Unsafe_DefineAnonymousClass and jvm_lookup_define_class. // Used by jvm_lookup_define_class.
static InstanceKlass* resolve_hidden_class_from_stream(ClassFileStream* st, static InstanceKlass* resolve_hidden_class_from_stream(ClassFileStream* st,
Symbol* class_name, Symbol* class_name,
Handle class_loader, Handle class_loader,

View File

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

View File

@ -2158,9 +2158,7 @@ void ClassVerifier::verify_ldc(
| (1 << JVM_CONSTANT_Dynamic); | (1 << JVM_CONSTANT_Dynamic);
verify_cp_type(bci, index, cp, types, CHECK_VERIFY(this)); verify_cp_type(bci, index, cp, types, CHECK_VERIFY(this));
} }
if (tag.is_string() && cp->is_pseudo_string_at(index)) { if (tag.is_string()) {
current_frame->push_stack(object_type(), CHECK_VERIFY(this));
} else if (tag.is_string()) {
current_frame->push_stack( current_frame->push_stack(
VerificationType::reference_type( VerificationType::reference_type(
vmSymbols::java_lang_String()), CHECK_VERIFY(this)); vmSymbols::java_lang_String()), CHECK_VERIFY(this));
@ -2876,21 +2874,8 @@ void ClassVerifier::verify_invoke_instructions(
current_class()->super()->name()))) { current_class()->super()->name()))) {
bool subtype = false; bool subtype = false;
bool have_imr_indirect = cp->tag_at(index).value() == JVM_CONSTANT_InterfaceMethodref; bool have_imr_indirect = cp->tag_at(index).value() == JVM_CONSTANT_InterfaceMethodref;
if (!current_class()->is_unsafe_anonymous()) {
subtype = ref_class_type.is_assignable_from( subtype = ref_class_type.is_assignable_from(
current_type(), this, false, CHECK_VERIFY(this)); current_type(), this, false, CHECK_VERIFY(this));
} else {
VerificationType unsafe_anonymous_host_type =
VerificationType::reference_type(current_class()->unsafe_anonymous_host()->name());
subtype = ref_class_type.is_assignable_from(unsafe_anonymous_host_type, this, false, CHECK_VERIFY(this));
// If invokespecial of IMR, need to recheck for same or
// direct interface relative to the host class
have_imr_indirect = (have_imr_indirect &&
!is_same_or_direct_interface(
current_class()->unsafe_anonymous_host(),
unsafe_anonymous_host_type, ref_class_type));
}
if (!subtype) { if (!subtype) {
verify_error(ErrorContext::bad_code(bci), verify_error(ErrorContext::bad_code(bci),
"Bad invokespecial instruction: " "Bad invokespecial instruction: "
@ -2925,24 +2910,7 @@ void ClassVerifier::verify_invoke_instructions(
} else { // other methods } else { // other methods
// Ensures that target class is assignable to method class. // Ensures that target class is assignable to method class.
if (opcode == Bytecodes::_invokespecial) { if (opcode == Bytecodes::_invokespecial) {
if (!current_class()->is_unsafe_anonymous()) {
current_frame->pop_stack(current_type(), CHECK_VERIFY(this)); current_frame->pop_stack(current_type(), CHECK_VERIFY(this));
} else {
// anonymous class invokespecial calls: check if the
// objectref is a subtype of the unsafe_anonymous_host of the current class
// to allow an anonymous class to reference methods in the unsafe_anonymous_host
VerificationType top = current_frame->pop_stack(CHECK_VERIFY(this));
VerificationType hosttype =
VerificationType::reference_type(current_class()->unsafe_anonymous_host()->name());
bool subtype = hosttype.is_assignable_from(top, this, false, CHECK_VERIFY(this));
if (!subtype) {
verify_error( ErrorContext::bad_type(current_frame->offset(),
current_frame->stack_top_ctx(),
TypeOrigin::implicit(top)),
"Bad type on operand stack");
return;
}
}
} else if (opcode == Bytecodes::_invokevirtual) { } else if (opcode == Bytecodes::_invokevirtual) {
VerificationType stack_object_type = VerificationType stack_object_type =
current_frame->pop_stack(ref_class_type, CHECK_VERIFY(this)); current_frame->pop_stack(ref_class_type, CHECK_VERIFY(this));

View File

@ -866,11 +866,10 @@ void InterpreterRuntime::resolve_invoke(JavaThread* current, Bytecodes::Code byt
info.call_kind() == CallInfo::vtable_call, ""); info.call_kind() == CallInfo::vtable_call, "");
} }
#endif #endif
// Get sender or sender's unsafe_anonymous_host, and only set cpCache entry to resolved if // Get sender and only set cpCache entry to resolved if it is not an
// it is not an interface. The receiver for invokespecial calls within interface // interface. The receiver for invokespecial calls within interface
// methods must be checked for every call. // methods must be checked for every call.
InstanceKlass* sender = pool->pool_holder(); InstanceKlass* sender = pool->pool_holder();
sender = sender->is_unsafe_anonymous() ? sender->unsafe_anonymous_host() : sender;
switch (info.call_kind()) { switch (info.call_kind()) {
case CallInfo::direct_call: case CallInfo::direct_call:

View File

@ -1154,10 +1154,7 @@ Method* LinkResolver::linktime_resolve_special_method(const LinkInfo& link_info,
// a direct superinterface, not an indirect superinterface // a direct superinterface, not an indirect superinterface
Klass* current_klass = link_info.current_klass(); Klass* current_klass = link_info.current_klass();
if (current_klass != NULL && resolved_klass->is_interface()) { if (current_klass != NULL && resolved_klass->is_interface()) {
InstanceKlass* ck = InstanceKlass::cast(current_klass); InstanceKlass* klass_to_check = InstanceKlass::cast(current_klass);
InstanceKlass *klass_to_check = !ck->is_unsafe_anonymous() ?
ck :
ck->unsafe_anonymous_host();
// Disable verification for the dynamically-generated reflection bytecodes. // Disable verification for the dynamically-generated reflection bytecodes.
bool is_reflect = klass_to_check->is_subclass_of( bool is_reflect = klass_to_check->is_subclass_of(
vmClasses::reflect_MagicAccessorImpl_klass()); vmClasses::reflect_MagicAccessorImpl_klass());
@ -1247,7 +1244,6 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result,
// The verifier also checks that the receiver is a subtype of the sender, if the sender is // The verifier also checks that the receiver is a subtype of the sender, if the sender is
// a class. If the sender is an interface, the check has to be performed at runtime. // a class. If the sender is an interface, the check has to be performed at runtime.
InstanceKlass* sender = InstanceKlass::cast(current_klass); InstanceKlass* sender = InstanceKlass::cast(current_klass);
sender = sender->is_unsafe_anonymous() ? sender->unsafe_anonymous_host() : sender;
if (sender->is_interface() && recv.not_null()) { if (sender->is_interface() && recv.not_null()) {
Klass* receiver_klass = recv->klass(); Klass* receiver_klass = recv->klass();
if (!receiver_klass->is_subtype_of(sender)) { if (!receiver_klass->is_subtype_of(sender)) {

View File

@ -164,7 +164,7 @@ void ObjectSampleDescription::write_class_name() {
if (k->is_instance_klass()) { if (k->is_instance_klass()) {
const InstanceKlass* ik = InstanceKlass::cast(k); const InstanceKlass* ik = InstanceKlass::cast(k);
if (ik->is_unsafe_anonymous() || ik->is_hidden()) { if (ik->is_hidden()) {
return; return;
} }
const Symbol* name = ik->name(); const Symbol* name = ik->name();

View File

@ -194,20 +194,13 @@ static u4 get_primitive_flags() {
return JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC; return JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC;
} }
static bool is_unsafe_anonymous(const Klass* klass) {
assert(klass != NULL, "invariant");
assert(!klass->is_objArray_klass(), "invariant");
return klass->is_instance_klass() && InstanceKlass::cast(klass)->is_unsafe_anonymous();
}
static ClassLoaderData* get_cld(const Klass* klass) { static ClassLoaderData* get_cld(const Klass* klass) {
assert(klass != NULL, "invariant"); assert(klass != NULL, "invariant");
if (klass->is_objArray_klass()) { if (klass->is_objArray_klass()) {
klass = ObjArrayKlass::cast(klass)->bottom_klass(); klass = ObjArrayKlass::cast(klass)->bottom_klass();
} }
if (klass->is_non_strong_hidden()) return NULL; if (klass->is_non_strong_hidden()) return NULL;
return is_unsafe_anonymous(klass) ? return klass->class_loader_data();
InstanceKlass::cast(klass)->unsafe_anonymous_host()->class_loader_data() : klass->class_loader_data();
} }
template <typename T> template <typename T>

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -184,61 +184,59 @@ traceid JfrSymbolId::mark(uintptr_t hash, const char* str, bool leakp) {
} }
/* /*
* jsr292 anonymous classes symbol is the external name + * hidden classes symbol is the external name +
* the identity_hashcode slash appended: * the address of its InstanceKlass slash appended:
* java.lang.invoke.LambdaForm$BMH/22626602 * java.lang.invoke.LambdaForm$BMH/22626602
* *
* caller needs ResourceMark * caller needs ResourceMark
*/ */
uintptr_t JfrSymbolId::hidden_or_anon_klass_name_hash(const InstanceKlass* ik) { uintptr_t JfrSymbolId::hidden_klass_name_hash(const InstanceKlass* ik) {
assert(ik != NULL, "invariant"); assert(ik != NULL, "invariant");
assert(ik->is_unsafe_anonymous() || ik->is_hidden(), "invariant"); assert(ik->is_hidden(), "invariant");
const oop mirror = ik->java_mirror_no_keepalive(); const oop mirror = ik->java_mirror_no_keepalive();
assert(mirror != NULL, "invariant"); assert(mirror != NULL, "invariant");
return (uintptr_t)mirror->identity_hash(); return (uintptr_t)mirror->identity_hash();
} }
static const char* create_hidden_or_anon_klass_symbol(const InstanceKlass* ik, uintptr_t hash) { static const char* create_hidden_klass_symbol(const InstanceKlass* ik, uintptr_t hash) {
assert(ik != NULL, "invariant"); assert(ik != NULL, "invariant");
assert(ik->is_unsafe_anonymous() || ik->is_hidden(), "invariant"); assert(ik->is_hidden(), "invariant");
assert(hash != 0, "invariant"); assert(hash != 0, "invariant");
char* hidden_or_anon_symbol = NULL; char* hidden_symbol = NULL;
const oop mirror = ik->java_mirror_no_keepalive(); const oop mirror = ik->java_mirror_no_keepalive();
assert(mirror != NULL, "invariant"); assert(mirror != NULL, "invariant");
char hash_buf[40]; char hash_buf[40];
sprintf(hash_buf, "/" UINTX_FORMAT, hash); sprintf(hash_buf, "/" UINTX_FORMAT, hash);
const size_t hash_len = strlen(hash_buf); const size_t hash_len = strlen(hash_buf);
const size_t result_len = ik->name()->utf8_length(); const size_t result_len = ik->name()->utf8_length();
hidden_or_anon_symbol = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1); hidden_symbol = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1);
ik->name()->as_klass_external_name(hidden_or_anon_symbol, (int)result_len + 1); ik->name()->as_klass_external_name(hidden_symbol, (int)result_len + 1);
assert(strlen(hidden_or_anon_symbol) == result_len, "invariant"); assert(strlen(hidden_symbol) == result_len, "invariant");
strcpy(hidden_or_anon_symbol + result_len, hash_buf); strcpy(hidden_symbol + result_len, hash_buf);
assert(strlen(hidden_or_anon_symbol) == result_len + hash_len, "invariant"); assert(strlen(hidden_symbol) == result_len + hash_len, "invariant");
return hidden_or_anon_symbol; return hidden_symbol;
} }
bool JfrSymbolId::is_hidden_or_anon_klass(const Klass* k) { bool JfrSymbolId::is_hidden_klass(const Klass* k) {
assert(k != NULL, "invariant"); assert(k != NULL, "invariant");
return k->is_instance_klass() && return k->is_instance_klass() && ((const InstanceKlass*)k)->is_hidden();
(((const InstanceKlass*)k)->is_unsafe_anonymous() ||
((const InstanceKlass*)k)->is_hidden());
} }
traceid JfrSymbolId::mark_hidden_or_anon_klass_name(const InstanceKlass* ik, bool leakp) { traceid JfrSymbolId::mark_hidden_klass_name(const InstanceKlass* ik, bool leakp) {
assert(ik != NULL, "invariant"); assert(ik != NULL, "invariant");
assert(ik->is_unsafe_anonymous() || ik->is_hidden(), "invariant"); assert(ik->is_hidden(), "invariant");
const uintptr_t hash = hidden_or_anon_klass_name_hash(ik); const uintptr_t hash = hidden_klass_name_hash(ik);
const char* const hidden_or_anon_symbol = create_hidden_or_anon_klass_symbol(ik, hash); const char* const hidden_symbol = create_hidden_klass_symbol(ik, hash);
return mark(hash, hidden_or_anon_symbol, leakp); return mark(hash, hidden_symbol, leakp);
} }
traceid JfrSymbolId::mark(const Klass* k, bool leakp) { traceid JfrSymbolId::mark(const Klass* k, bool leakp) {
assert(k != NULL, "invariant"); assert(k != NULL, "invariant");
traceid symbol_id = 0; traceid symbol_id = 0;
if (is_hidden_or_anon_klass(k)) { if (is_hidden_klass(k)) {
assert(k->is_instance_klass(), "invariant"); assert(k->is_instance_klass(), "invariant");
symbol_id = mark_hidden_or_anon_klass_name((const InstanceKlass*)k, leakp); symbol_id = mark_hidden_klass_name((const InstanceKlass*)k, leakp);
} }
if (0 == symbol_id) { if (0 == symbol_id) {
Symbol* const sym = k->name(); Symbol* const sym = k->name();
@ -282,9 +280,9 @@ traceid JfrArtifactSet::bootstrap_name(bool leakp) {
return _symbol_id->bootstrap_name(leakp); return _symbol_id->bootstrap_name(leakp);
} }
traceid JfrArtifactSet::mark_hidden_or_anon_klass_name(const Klass* klass, bool leakp) { traceid JfrArtifactSet::mark_hidden_klass_name(const Klass* klass, bool leakp) {
assert(klass->is_instance_klass(), "invariant"); assert(klass->is_instance_klass(), "invariant");
return _symbol_id->mark_hidden_or_anon_klass_name((const InstanceKlass*)klass, leakp); return _symbol_id->mark_hidden_klass_name((const InstanceKlass*)klass, leakp);
} }
traceid JfrArtifactSet::mark(uintptr_t hash, const Symbol* sym, bool leakp) { traceid JfrArtifactSet::mark(uintptr_t hash, const Symbol* sym, bool leakp) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -251,9 +251,9 @@ class JfrSymbolId : public JfrCHeapObj {
} }
} }
traceid mark_hidden_or_anon_klass_name(const InstanceKlass* k, bool leakp); traceid mark_hidden_klass_name(const InstanceKlass* k, bool leakp);
bool is_hidden_or_anon_klass(const Klass* k); bool is_hidden_klass(const Klass* k);
uintptr_t hidden_or_anon_klass_name_hash(const InstanceKlass* ik); uintptr_t hidden_klass_name_hash(const InstanceKlass* ik);
public: public:
JfrSymbolId(); JfrSymbolId();
@ -315,7 +315,7 @@ class JfrArtifactSet : public JfrCHeapObj {
traceid mark(const Klass* klass, bool leakp); traceid mark(const Klass* klass, bool leakp);
traceid mark(const Symbol* symbol, bool leakp); traceid mark(const Symbol* symbol, bool leakp);
traceid mark(uintptr_t hash, const char* const str, bool leakp); traceid mark(uintptr_t hash, const char* const str, bool leakp);
traceid mark_hidden_or_anon_klass_name(const Klass* klass, bool leakp); traceid mark_hidden_klass_name(const Klass* klass, bool leakp);
traceid bootstrap_name(bool leakp); traceid bootstrap_name(bool leakp);
const JfrSymbolId::SymbolEntry* map_symbol(const Symbol* symbol) const; const JfrSymbolId::SymbolEntry* map_symbol(const Symbol* symbol) const;

View File

@ -1569,14 +1569,6 @@ C2V_VMENTRY_0(jlong, getFingerprint, (JNIEnv* env, jobject, jlong metaspace_klas
JVMCI_THROW_MSG_0(InternalError, "unimplemented"); JVMCI_THROW_MSG_0(InternalError, "unimplemented");
C2V_END C2V_END
C2V_VMENTRY_NULL(jobject, getHostClass, (JNIEnv* env, jobject, jobject jvmci_type))
InstanceKlass* k = InstanceKlass::cast(JVMCIENV->asKlass(jvmci_type));
InstanceKlass* host = k->unsafe_anonymous_host();
JVMCIKlassHandle handle(THREAD, host);
JVMCIObject result = JVMCIENV->get_jvmci_type(handle, JVMCI_CHECK_NULL);
return JVMCIENV->get_jobject(result);
C2V_END
C2V_VMENTRY_NULL(jobject, getInterfaces, (JNIEnv* env, jobject, jobject jvmci_type)) C2V_VMENTRY_NULL(jobject, getInterfaces, (JNIEnv* env, jobject, jobject jvmci_type))
if (jvmci_type == NULL) { if (jvmci_type == NULL) {
JVMCI_THROW_0(NullPointerException); JVMCI_THROW_0(NullPointerException);
@ -2673,7 +2665,6 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "flushDebugOutput", CC "()V", FN_PTR(flushDebugOutput)}, {CC "flushDebugOutput", CC "()V", FN_PTR(flushDebugOutput)},
{CC "methodDataProfileDataSize", CC "(JI)I", FN_PTR(methodDataProfileDataSize)}, {CC "methodDataProfileDataSize", CC "(JI)I", FN_PTR(methodDataProfileDataSize)},
{CC "getFingerprint", CC "(J)J", FN_PTR(getFingerprint)}, {CC "getFingerprint", CC "(J)J", FN_PTR(getFingerprint)},
{CC "getHostClass", CC "(" HS_RESOLVED_KLASS ")" HS_RESOLVED_KLASS, FN_PTR(getHostClass)},
{CC "interpreterFrameSize", CC "(" BYTECODE_FRAME ")I", FN_PTR(interpreterFrameSize)}, {CC "interpreterFrameSize", CC "(" BYTECODE_FRAME ")I", FN_PTR(interpreterFrameSize)},
{CC "compileToBytecode", CC "(" OBJECTCONSTANT ")V", FN_PTR(compileToBytecode)}, {CC "compileToBytecode", CC "(" OBJECTCONSTANT ")V", FN_PTR(compileToBytecode)},
{CC "getFlagValue", CC "(" STRING ")" OBJECT, FN_PTR(getFlagValue)}, {CC "getFlagValue", CC "(" STRING ")" OBJECT, FN_PTR(getFlagValue)},

View File

@ -585,7 +585,6 @@
/* InstanceKlass _misc_flags */ \ /* InstanceKlass _misc_flags */ \
/*********************************/ \ /*********************************/ \
\ \
declare_constant(InstanceKlass::_misc_is_unsafe_anonymous) \
declare_constant(InstanceKlass::_misc_has_nonstatic_concrete_methods) \ declare_constant(InstanceKlass::_misc_has_nonstatic_concrete_methods) \
declare_constant(InstanceKlass::_misc_declares_nonstatic_concrete_methods) \ declare_constant(InstanceKlass::_misc_declares_nonstatic_concrete_methods) \
\ \

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020 SAP SE. All rights reserved. * Copyright (c) 2018, 2020 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
@ -109,7 +109,7 @@ void PrintCLDMetaspaceInfoClosure::do_cld(ClassLoaderData* cld) {
_out->print(UINTX_FORMAT_W(4) ": ", _num_loaders); _out->print(UINTX_FORMAT_W(4) ": ", _num_loaders);
// Print "CLD for [<loader name>,] instance of <loader class name>" // Print "CLD for [<loader name>,] instance of <loader class name>"
// or "CLD for <hidden or anonymous class>, loaded by [<loader name>,] instance of <loader class name>" // or "CLD for <hidden>, loaded by [<loader name>,] instance of <loader class name>"
ResourceMark rm; ResourceMark rm;
const char* name = NULL; const char* name = NULL;
const char* class_name = NULL; const char* class_name = NULL;
@ -133,7 +133,7 @@ void PrintCLDMetaspaceInfoClosure::do_cld(ClassLoaderData* cld) {
} }
_out->print(":"); _out->print(":");
if (cld->has_class_mirror_holder()) { if (cld->has_class_mirror_holder()) {
_out->print(" <hidden or anonymous class>, loaded by"); _out->print(" <hidden class>, loaded by");
} }
if (name != NULL) { if (name != NULL) {
_out->print(" \"%s\"", name); _out->print(" \"%s\"", name);

View File

@ -238,29 +238,7 @@ void ConstantPool::initialize_unresolved_klasses(ClassLoaderData* loader_data, T
allocate_resolved_klasses(loader_data, num_klasses, THREAD); allocate_resolved_klasses(loader_data, num_klasses, THREAD);
} }
// Unsafe anonymous class support: // Hidden class support:
void ConstantPool::klass_at_put(int class_index, int name_index, int resolved_klass_index, Klass* k, Symbol* name) {
assert(is_within_bounds(class_index), "index out of bounds");
assert(is_within_bounds(name_index), "index out of bounds");
assert((resolved_klass_index & 0xffff0000) == 0, "must be");
*int_at_addr(class_index) =
build_int_from_shorts((jushort)resolved_klass_index, (jushort)name_index);
symbol_at_put(name_index, name);
name->increment_refcount();
Klass** adr = resolved_klasses()->adr_at(resolved_klass_index);
Atomic::release_store(adr, k);
// The interpreter assumes when the tag is stored, the klass is resolved
// and the Klass* non-NULL, so we need hardware store ordering here.
if (k != NULL) {
release_tag_at_put(class_index, JVM_CONSTANT_Class);
} else {
release_tag_at_put(class_index, JVM_CONSTANT_UnresolvedClass);
}
}
// Unsafe anonymous class support:
void ConstantPool::klass_at_put(int class_index, Klass* k) { void ConstantPool::klass_at_put(int class_index, Klass* k) {
assert(k != NULL, "must be valid klass"); assert(k != NULL, "must be valid klass");
CPKlassSlot kslot = klass_slot_at(class_index); CPKlassSlot kslot = klass_slot_at(class_index);
@ -330,7 +308,7 @@ void ConstantPool::resolve_class_constants(TRAPS) {
constantPoolHandle cp(THREAD, this); constantPoolHandle cp(THREAD, this);
for (int index = 1; index < length(); index++) { // Index 0 is unused for (int index = 1; index < length(); index++) { // Index 0 is unused
if (tag_at(index).is_string() && !cp->is_pseudo_string_at(index)) { if (tag_at(index).is_string()) {
int cache_index = cp->cp_to_object_index(index); int cache_index = cp->cp_to_object_index(index);
string_at_impl(cp, index, cache_index, CHECK); string_at_impl(cp, index, cache_index, CHECK);
} }
@ -1063,10 +1041,6 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp,
case JVM_CONSTANT_String: case JVM_CONSTANT_String:
assert(cache_index != _no_index_sentinel, "should have been set"); assert(cache_index != _no_index_sentinel, "should have been set");
if (this_cp->is_pseudo_string_at(index)) {
result_oop = this_cp->pseudo_string_at(index, cache_index);
break;
}
result_oop = string_at_impl(this_cp, index, cache_index, CHECK_NULL); result_oop = string_at_impl(this_cp, index, cache_index, CHECK_NULL);
break; break;
@ -2258,38 +2232,6 @@ void ConstantPool::set_on_stack(const bool value) {
} }
} }
// JSR 292 support for patching constant pool oops after the class is linked and
// the oop array for resolved references are created.
// We can't do this during classfile parsing, which is how the other indexes are
// patched. The other patches are applied early for some error checking
// so only defer the pseudo_strings.
void ConstantPool::patch_resolved_references(GrowableArray<Handle>* cp_patches) {
for (int index = 1; index < cp_patches->length(); index++) { // Index 0 is unused
Handle patch = cp_patches->at(index);
if (patch.not_null()) {
assert (tag_at(index).is_string(), "should only be string left");
// Patching a string means pre-resolving it.
// The spelling in the constant pool is ignored.
// The constant reference may be any object whatever.
// If it is not a real interned string, the constant is referred
// to as a "pseudo-string", and must be presented to the CP
// explicitly, because it may require scavenging.
int obj_index = cp_to_object_index(index);
pseudo_string_at_put(index, obj_index, patch());
DEBUG_ONLY(cp_patches->at_put(index, Handle());)
}
}
#ifdef ASSERT
// Ensure that all the patches have been used.
for (int index = 0; index < cp_patches->length(); index++) {
assert(cp_patches->at(index).is_null(),
"Unused constant pool patch at %d in class file %s",
index,
pool_holder()->external_name());
}
#endif // ASSERT
}
// Printing // Printing
void ConstantPool::print_on(outputStream* st) const { void ConstantPool::print_on(outputStream* st) const {
@ -2342,13 +2284,7 @@ void ConstantPool::print_entry_on(const int index, outputStream* st) {
st->print(" name_and_type_index=%d", uncached_name_and_type_ref_index_at(index)); st->print(" name_and_type_index=%d", uncached_name_and_type_ref_index_at(index));
break; break;
case JVM_CONSTANT_String : case JVM_CONSTANT_String :
if (is_pseudo_string_at(index)) {
oop anObj = pseudo_string_at(index);
anObj->print_value_on(st);
st->print(" {" PTR_FORMAT "}", p2i(anObj));
} else {
unresolved_string_at(index)->print_value_on(st); unresolved_string_at(index)->print_value_on(st);
}
break; break;
case JVM_CONSTANT_Integer : case JVM_CONSTANT_Integer :
st->print("%d", int_at(index)); st->print("%d", int_at(index));

View File

@ -58,7 +58,6 @@ class CPSlot {
CPSlot(Symbol* ptr, int tag_bits = 0): _ptr((intptr_t)ptr | tag_bits) {} CPSlot(Symbol* ptr, int tag_bits = 0): _ptr((intptr_t)ptr | tag_bits) {}
intptr_t value() { return _ptr; } intptr_t value() { return _ptr; }
bool is_pseudo_string() { return (_ptr & _pseudo_bit) != 0; }
Symbol* get_symbol() { Symbol* get_symbol() {
return (Symbol*)(_ptr & ~_pseudo_bit); return (Symbol*)(_ptr & ~_pseudo_bit);
@ -310,8 +309,7 @@ class ConstantPool : public Metadata {
*int_at_addr(which) = name_index; *int_at_addr(which) = name_index;
} }
// Unsafe anonymous class support: // Hidden class support:
void klass_at_put(int class_index, int name_index, int resolved_klass_index, Klass* k, Symbol* name);
void klass_at_put(int class_index, Klass* k); void klass_at_put(int class_index, Klass* k);
void unresolved_klass_at_put(int which, int name_index, int resolved_klass_index) { void unresolved_klass_at_put(int which, int name_index, int resolved_klass_index) {
@ -485,26 +483,6 @@ class ConstantPool : public Metadata {
// Version that can be used before string oop array is created. // Version that can be used before string oop array is created.
oop uncached_string_at(int which, TRAPS); oop uncached_string_at(int which, TRAPS);
// A "pseudo-string" is an non-string oop that has found its way into
// a String entry.
// This can happen if the user patches a live
// object into a CONSTANT_String entry of an unsafe anonymous class.
// Methods internally created for method handles may also
// use pseudo-strings to link themselves to related metaobjects.
bool is_pseudo_string_at(int which);
oop pseudo_string_at(int which, int obj_index);
oop pseudo_string_at(int which);
void pseudo_string_at_put(int which, int obj_index, oop x) {
assert(tag_at(which).is_string(), "Corrupted constant pool");
Symbol* sym = unresolved_string_at(which);
slot_at_put(which, CPSlot(sym, CPSlot::_pseudo_bit));
string_at_put(which, obj_index, x); // this works just fine
}
// only called when we are sure a string entry is already resolved (via an // only called when we are sure a string entry is already resolved (via an
// earlier string_at call. // earlier string_at call.
oop resolved_string_at(int which) { oop resolved_string_at(int which) {
@ -854,9 +832,6 @@ class ConstantPool : public Metadata {
Array<u2>* reference_map() const { return (_cache == NULL) ? NULL : _cache->reference_map(); } Array<u2>* reference_map() const { return (_cache == NULL) ? NULL : _cache->reference_map(); }
void set_reference_map(Array<u2>* o) { _cache->set_reference_map(o); } void set_reference_map(Array<u2>* o) { _cache->set_reference_map(o); }
// patch JSR 292 resolved references after the class is linked.
void patch_resolved_references(GrowableArray<Handle>* cp_patches);
Symbol* impl_name_ref_at(int which, bool uncached); Symbol* impl_name_ref_at(int which, bool uncached);
Symbol* impl_signature_ref_at(int which, bool uncached); Symbol* impl_signature_ref_at(int which, bool uncached);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -49,22 +49,4 @@ inline Klass* ConstantPool::resolved_klass_at(int which) const { // Used by Com
return Atomic::load_acquire(adr); return Atomic::load_acquire(adr);
} }
inline bool ConstantPool::is_pseudo_string_at(int which) {
assert(tag_at(which).is_string(), "Corrupted constant pool");
return slot_at(which).is_pseudo_string();
}
inline oop ConstantPool::pseudo_string_at(int which, int obj_index) {
assert(is_pseudo_string_at(which), "must be a pseudo-string");
oop s = resolved_references()->obj_at(obj_index);
return s;
}
inline oop ConstantPool::pseudo_string_at(int which) {
assert(is_pseudo_string_at(which), "must be a pseudo-string");
int obj_index = cp_to_object_index(which);
oop s = resolved_references()->obj_at(obj_index);
return s;
}
#endif // SHARE_OOPS_CONSTANTPOOL_INLINE_HPP #endif // SHARE_OOPS_CONSTANTPOOL_INLINE_HPP

View File

@ -50,7 +50,7 @@ public:
// Oop fields (and metadata) iterators // Oop fields (and metadata) iterators
// //
// The InstanceClassLoaderKlass iterators also visit the CLD pointer (or mirror of anonymous klasses.) // The InstanceClassLoaderKlass iterators also visit the CLD pointer (or mirror of hidden klasses.)
// Forward iteration // Forward iteration
// Iterate over the oop fields and metadata. // Iterate over the oop fields and metadata.

View File

@ -423,12 +423,10 @@ const char* InstanceKlass::nest_host_error() {
} }
InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& parser, TRAPS) { 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(), const int size = InstanceKlass::size(parser.vtable_size(),
parser.itable_size(), parser.itable_size(),
nonstatic_oop_map_size(parser.total_oop_map_count()), nonstatic_oop_map_size(parser.total_oop_map_count()),
parser.is_interface(), parser.is_interface());
parser.is_unsafe_anonymous());
const Symbol* const class_name = parser.class_name(); const Symbol* const class_name = parser.class_name();
assert(class_name != NULL, "invariant"); assert(class_name != NULL, "invariant");
@ -504,7 +502,6 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, unsigned kind, Klass
set_kind(kind); set_kind(kind);
set_access_flags(parser.access_flags()); set_access_flags(parser.access_flags());
if (parser.is_hidden()) set_is_hidden(); 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(), set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
false)); false));
@ -2709,13 +2706,6 @@ const char* InstanceKlass::signature_name() const {
int hash_len = 0; int hash_len = 0;
char hash_buf[40]; char hash_buf[40];
// If this is an unsafe anonymous class, append a hash to make the name unique
if (is_unsafe_anonymous()) {
intptr_t hash = (java_mirror() != NULL) ? java_mirror()->identity_hash() : 0;
jio_snprintf(hash_buf, sizeof(hash_buf), "/" UINTX_FORMAT, (uintx)hash);
hash_len = (int)strlen(hash_buf);
}
// Get the internal name as a c string // Get the internal name as a c string
const char* src = (const char*) (name()->as_C_string()); const char* src = (const char*) (name()->as_C_string());
const int src_length = (int)strlen(src); const int src_length = (int)strlen(src);
@ -2752,12 +2742,6 @@ const char* InstanceKlass::signature_name() const {
} }
ModuleEntry* InstanceKlass::module() const { ModuleEntry* InstanceKlass::module() const {
// For an unsafe anonymous class return the host class' module
if (is_unsafe_anonymous()) {
assert(unsafe_anonymous_host() != NULL, "unsafe anonymous class must have a host class");
return unsafe_anonymous_host()->module();
}
if (is_hidden() && if (is_hidden() &&
in_unnamed_package() && in_unnamed_package() &&
class_loader_data()->has_class_mirror_holder()) { class_loader_data()->has_class_mirror_holder()) {
@ -3026,7 +3010,7 @@ InstanceKlass* InstanceKlass::compute_enclosing_class(bool* inner_is_member, TRA
*inner_is_member = true; *inner_is_member = true;
} }
if (NULL == outer_klass) { if (NULL == outer_klass) {
// It may be a local or anonymous class; try for that. // It may be a local class; try for that.
int encl_method_class_idx = enclosing_method_class_index(); int encl_method_class_idx = enclosing_method_class_index();
if (encl_method_class_idx != 0) { if (encl_method_class_idx != 0) {
Klass* ok = i_cp->klass_at(encl_method_class_idx, CHECK_NULL); Klass* ok = i_cp->klass_at(encl_method_class_idx, CHECK_NULL);
@ -3401,7 +3385,6 @@ void InstanceKlass::print_on(outputStream* st) const {
class_loader_data()->print_value_on(st); class_loader_data()->print_value_on(st);
st->cr(); st->cr();
} }
st->print(BULLET"unsafe anonymous host class: "); Metadata::print_value_on_maybe_null(st, unsafe_anonymous_host()); st->cr();
if (source_file_name() != NULL) { if (source_file_name() != NULL) {
st->print(BULLET"source file: "); st->print(BULLET"source file: ");
source_file_name()->print_value_on(st); source_file_name()->print_value_on(st);
@ -3827,10 +3810,6 @@ void InstanceKlass::verify_on(outputStream* st) {
if (constants() != NULL) { if (constants() != NULL) {
guarantee(constants()->is_constantPool(), "should be constant pool"); guarantee(constants()->is_constantPool(), "should be constant pool");
} }
const Klass* anonymous_host = unsafe_anonymous_host();
if (anonymous_host != NULL) {
guarantee(anonymous_host->is_klass(), "should be klass");
}
} }
void InstanceKlass::oop_verify_on(oop obj, outputStream* st) { void InstanceKlass::oop_verify_on(oop obj, outputStream* st) {
@ -4162,7 +4141,7 @@ bool InstanceKlass::is_shareable() const {
return false; return false;
} }
if (is_hidden() || unsafe_anonymous_host() != NULL) { if (is_hidden()) {
return false; return false;
} }

View File

@ -50,7 +50,6 @@ class RecordComponent;
// The embedded nonstatic oop-map blocks are short pairs (offset, length) // The embedded nonstatic oop-map blocks are short pairs (offset, length)
// indicating where oops are located in instances of this klass. // indicating where oops are located in instances of this klass.
// [EMBEDDED implementor of the interface] only exist for interface // [EMBEDDED implementor of the interface] only exist for interface
// [EMBEDDED unsafe_anonymous_host klass] only exist for an unsafe anonymous class (JSR 292 enabled)
// forward declaration for class -- see below for definition // forward declaration for class -- see below for definition
@ -248,7 +247,7 @@ class InstanceKlass: public Klass {
_misc_rewritten = 1 << 0, // methods rewritten. _misc_rewritten = 1 << 0, // methods rewritten.
_misc_has_nonstatic_fields = 1 << 1, // for sizing with UseCompressedOops _misc_has_nonstatic_fields = 1 << 1, // for sizing with UseCompressedOops
_misc_should_verify_class = 1 << 2, // allow caching of preverification _misc_should_verify_class = 1 << 2, // allow caching of preverification
_misc_is_unsafe_anonymous = 1 << 3, // has embedded _unsafe_anonymous_host field _misc_unused = 1 << 3, // not currently used
_misc_is_contended = 1 << 4, // marked with contended annotation _misc_is_contended = 1 << 4, // marked with contended annotation
_misc_has_nonstatic_concrete_methods = 1 << 5, // class/superclass/implemented interfaces has non-static, concrete methods _misc_has_nonstatic_concrete_methods = 1 << 5, // class/superclass/implemented interfaces has non-static, concrete methods
_misc_declares_nonstatic_concrete_methods = 1 << 6, // directly declares non-static, concrete methods _misc_declares_nonstatic_concrete_methods = 1 << 6, // directly declares non-static, concrete methods
@ -329,13 +328,6 @@ class InstanceKlass: public Klass {
// NULL: no implementor. // NULL: no implementor.
// A Klass* that's not itself: one implementor. // A Klass* that's not itself: one implementor.
// Itself: more than one implementors. // Itself: more than one implementors.
// embedded unsafe_anonymous_host klass follows here
// The embedded host klass only exists in an unsafe anonymous class for
// dynamic language support (JSR 292 enabled). The host class grants
// its access privileges to this class also. The host class is either
// named, or a previously loaded unsafe anonymous class. A non-anonymous class
// or an anonymous class loaded through normal classloading does not
// have this embedded field.
// //
friend class SystemDictionary; friend class SystemDictionary;
@ -687,20 +679,6 @@ public:
// signers // signers
objArrayOop signers() const; objArrayOop signers() const;
// host class
inline InstanceKlass* unsafe_anonymous_host() const;
inline void set_unsafe_anonymous_host(const InstanceKlass* host);
bool is_unsafe_anonymous() const {
return (_misc_flags & _misc_is_unsafe_anonymous) != 0;
}
void set_is_unsafe_anonymous(bool value) {
if (value) {
_misc_flags |= _misc_is_unsafe_anonymous;
} else {
_misc_flags &= ~_misc_is_unsafe_anonymous;
}
}
bool is_contended() const { bool is_contended() const {
return (_misc_flags & _misc_is_contended) != 0; return (_misc_flags & _misc_is_contended) != 0;
} }
@ -1045,21 +1023,21 @@ public:
static int size(int vtable_length, int itable_length, static int size(int vtable_length, int itable_length,
int nonstatic_oop_map_size, int nonstatic_oop_map_size,
bool is_interface, bool is_unsafe_anonymous) { bool is_interface) {
return align_metadata_size(header_size() + return align_metadata_size(header_size() +
vtable_length + vtable_length +
itable_length + itable_length +
nonstatic_oop_map_size + nonstatic_oop_map_size +
(is_interface ? (int)sizeof(Klass*)/wordSize : 0) + (is_interface ? (int)sizeof(Klass*)/wordSize : 0));
(is_unsafe_anonymous ? (int)sizeof(Klass*)/wordSize : 0));
} }
int size() const { return size(vtable_length(), int size() const { return size(vtable_length(),
itable_length(), itable_length(),
nonstatic_oop_map_size(), nonstatic_oop_map_size(),
is_interface(), is_interface());
is_unsafe_anonymous());
} }
inline intptr_t* start_of_itable() const; inline intptr_t* start_of_itable() const;
inline intptr_t* end_of_itable() const; inline intptr_t* end_of_itable() const;
inline int itable_offset_in_words() const; inline int itable_offset_in_words() const;
@ -1069,7 +1047,6 @@ public:
inline Klass** end_of_nonstatic_oop_maps() const; inline Klass** end_of_nonstatic_oop_maps() const;
inline InstanceKlass* volatile* adr_implementor() const; inline InstanceKlass* volatile* adr_implementor() const;
inline InstanceKlass** adr_unsafe_anonymous_host() const;
// Use this to return the size of an instance in heap words: // Use this to return the size of an instance in heap words:
int size_helper() const { int size_helper() const {

View File

@ -37,27 +37,6 @@
#include "utilities/globalDefinitions.hpp" #include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp" #include "utilities/macros.hpp"
inline InstanceKlass* InstanceKlass::unsafe_anonymous_host() const {
InstanceKlass** hk = adr_unsafe_anonymous_host();
if (hk == NULL) {
assert(!is_unsafe_anonymous(), "Unsafe anonymous classes have host klasses");
return NULL;
} else {
assert(*hk != NULL, "host klass should always be set if the address is not null");
assert(is_unsafe_anonymous(), "Only unsafe anonymous classes have host klasses");
return *hk;
}
}
inline void InstanceKlass::set_unsafe_anonymous_host(const InstanceKlass* host) {
assert(is_unsafe_anonymous(), "not unsafe anonymous");
const InstanceKlass** addr = (const InstanceKlass **)adr_unsafe_anonymous_host();
assert(addr != NULL, "no reversed space");
if (addr != NULL) {
*addr = host;
}
}
inline intptr_t* InstanceKlass::start_of_itable() const { return (intptr_t*)start_of_vtable() + vtable_length(); } inline intptr_t* InstanceKlass::start_of_itable() const { return (intptr_t*)start_of_vtable() + vtable_length(); }
inline intptr_t* InstanceKlass::end_of_itable() const { return start_of_itable() + itable_length(); } inline intptr_t* InstanceKlass::end_of_itable() const { return start_of_itable() + itable_length(); }
@ -82,19 +61,6 @@ inline InstanceKlass* volatile* InstanceKlass::adr_implementor() const {
} }
} }
inline InstanceKlass** InstanceKlass::adr_unsafe_anonymous_host() const {
if (is_unsafe_anonymous()) {
InstanceKlass** adr_impl = (InstanceKlass**)adr_implementor();
if (adr_impl != NULL) {
return adr_impl + 1;
} else {
return (InstanceKlass **)end_of_nonstatic_oop_maps();
}
} else {
return NULL;
}
}
inline ObjArrayKlass* InstanceKlass::array_klasses_acquire() const { inline ObjArrayKlass* InstanceKlass::array_klasses_acquire() const {
return Atomic::load_acquire(&_array_klasses); return Atomic::load_acquire(&_array_klasses);
} }

View File

@ -59,10 +59,10 @@ void InstanceMirrorKlass::oop_oop_iterate(oop obj, OopClosureType* closure) {
assert(klass->is_shared(), "must be"); assert(klass->is_shared(), "must be");
return; return;
} else if (klass->is_instance_klass() && klass->class_loader_data()->has_class_mirror_holder()) { } else 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, // A non-strong hidden class doesn't have its own class loader,
// so when handling the java mirror for the class we need to make sure its class // 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. // 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 // For non-strong hidden classes the call to do_cld is made when the class
// loader itself is handled. // loader itself is handled.
Devirtualizer::do_cld(closure, klass->class_loader_data()); Devirtualizer::do_cld(closure, klass->class_loader_data());
} else { } else {

View File

@ -677,19 +677,7 @@ static char* convert_hidden_name_to_java(Symbol* name) {
const char* Klass::external_name() const { const char* Klass::external_name() const {
if (is_instance_klass()) { if (is_instance_klass()) {
const InstanceKlass* ik = static_cast<const InstanceKlass*>(this); const InstanceKlass* ik = static_cast<const InstanceKlass*>(this);
if (ik->is_unsafe_anonymous()) { if (ik->is_hidden()) {
char addr_buf[20];
jio_snprintf(addr_buf, 20, "/" INTPTR_FORMAT, p2i(ik));
size_t addr_len = strlen(addr_buf);
size_t name_len = name()->utf8_length();
char* result = NEW_RESOURCE_ARRAY(char, name_len + addr_len + 1);
name()->as_klass_external_name(result, (int) name_len + 1);
assert(strlen(result) == name_len, "");
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()); char* result = convert_hidden_name_to_java(name());
return result; return result;
} }

View File

@ -43,7 +43,7 @@ inline bool Klass::is_non_strong_hidden() const {
class_loader_data()->has_class_mirror_holder(); class_loader_data()->has_class_mirror_holder();
} }
// Iff the class loader (or mirror for unsafe anonymous classes) is alive the // Iff the class loader (or mirror for non-strong hidden classes) is alive the
// Klass is considered alive. This is safe to call before the CLD is marked as // Klass is considered alive. This is safe to call before the CLD is marked as
// unloading, and hence during concurrent class unloading. // unloading, and hence during concurrent class unloading.
inline bool Klass::is_loader_alive() const { inline bool Klass::is_loader_alive() const {

View File

@ -562,9 +562,7 @@ void Parse::do_call() {
ciKlass* receiver_constraint = NULL; ciKlass* receiver_constraint = NULL;
if (iter().cur_bc_raw() == Bytecodes::_invokespecial && !orig_callee->is_object_initializer()) { if (iter().cur_bc_raw() == Bytecodes::_invokespecial && !orig_callee->is_object_initializer()) {
ciInstanceKlass* calling_klass = method()->holder(); ciInstanceKlass* calling_klass = method()->holder();
ciInstanceKlass* sender_klass = ciInstanceKlass* sender_klass = calling_klass;
calling_klass->is_unsafe_anonymous() ? calling_klass->unsafe_anonymous_host() :
calling_klass;
if (sender_klass->is_interface()) { if (sender_klass->is_interface()) {
receiver_constraint = sender_klass; receiver_constraint = sender_klass;
} }

View File

@ -959,8 +959,6 @@ static jclass jvm_lookup_define_class(jclass lookup, const char *name,
} else { // hidden } else { // hidden
Handle classData_h(THREAD, JNIHandles::resolve(classData)); Handle classData_h(THREAD, JNIHandles::resolve(classData));
ClassLoadInfo cl_info(protection_domain, ClassLoadInfo cl_info(protection_domain,
NULL, // unsafe_anonymous_host
NULL, // cp_patches
host_class, host_class,
classData_h, classData_h,
is_hidden, is_hidden,
@ -1439,7 +1437,7 @@ JVM_ENTRY(jclass, JVM_GetDeclaringClass(JNIEnv *env, jclass ofClass))
Klass* outer_klass Klass* outer_klass
= InstanceKlass::cast(klass)->compute_enclosing_class(&inner_is_member, CHECK_NULL); = InstanceKlass::cast(klass)->compute_enclosing_class(&inner_is_member, CHECK_NULL);
if (outer_klass == NULL) return NULL; // already a top-level class if (outer_klass == NULL) return NULL; // already a top-level class
if (!inner_is_member) return NULL; // a hidden or unsafe anonymous class (inside a method) if (!inner_is_member) return NULL; // a hidden class (inside a method)
return (jclass) JNIHandles::make_local(THREAD, outer_klass->java_mirror()); return (jclass) JNIHandles::make_local(THREAD, outer_klass->java_mirror());
} }
JVM_END JVM_END
@ -3532,8 +3530,8 @@ JVM_ENTRY(void, JVM_RegisterLambdaProxyClassForArchiving(JNIEnv* env,
Klass* caller_k = java_lang_Class::as_Klass(JNIHandles::resolve(caller)); Klass* caller_k = java_lang_Class::as_Klass(JNIHandles::resolve(caller));
InstanceKlass* caller_ik = InstanceKlass::cast(caller_k); InstanceKlass* caller_ik = InstanceKlass::cast(caller_k);
if (caller_ik->is_hidden() || caller_ik->is_unsafe_anonymous()) { if (caller_ik->is_hidden()) {
// VM anonymous classes and hidden classes not of type lambda proxy classes are currently not being archived. // Hidden classes not of type lambda proxy classes are currently not being archived.
// If the caller_ik is of one of the above types, the corresponding lambda proxy class won't be // If the caller_ik is of one of the above types, the corresponding lambda proxy class won't be
// registered for archiving. // registered for archiving.
return; return;

View File

@ -190,7 +190,7 @@ bool VM_RedefineClasses::doit_prologue() {
} }
oop mirror = JNIHandles::resolve_non_null(_class_defs[i].klass); oop mirror = JNIHandles::resolve_non_null(_class_defs[i].klass);
// classes for primitives, arrays, hidden and vm unsafe anonymous classes // classes for primitives, arrays, and hidden classes
// cannot be redefined. // cannot be redefined.
if (!is_modifiable_class(mirror)) { if (!is_modifiable_class(mirror)) {
_res = JVMTI_ERROR_UNMODIFIABLE_CLASS; _res = JVMTI_ERROR_UNMODIFIABLE_CLASS;
@ -333,9 +333,8 @@ bool VM_RedefineClasses::is_modifiable_class(oop klass_mirror) {
return false; return false;
} }
// Cannot redefine or retransform a hidden or an unsafe anonymous class. // Cannot redefine or retransform a hidden class.
if (InstanceKlass::cast(k)->is_hidden() || if (InstanceKlass::cast(k)->is_hidden()) {
InstanceKlass::cast(k)->is_unsafe_anonymous()) {
return false; return false;
} }
return true; return true;
@ -2939,7 +2938,6 @@ bool VM_RedefineClasses::skip_type_annotation_target(
case 0x10: case 0x10:
// kind: type in extends clause of class or interface declaration // kind: type in extends clause of class or interface declaration
// (including the direct superclass of an unsafe anonymous class declaration),
// or in implements clause of interface declaration // or in implements clause of interface declaration
// location: ClassFile // location: ClassFile

View File

@ -279,8 +279,6 @@ bool MethodComparator::pool_constants_same(const int cpi_old, const int cpi_new,
if (strcmp(old_cp->string_at_noresolve(cpi_old), if (strcmp(old_cp->string_at_noresolve(cpi_old),
new_cp->string_at_noresolve(cpi_new)) != 0) new_cp->string_at_noresolve(cpi_new)) != 0)
return false; return false;
if (old_cp->is_pseudo_string_at(cpi_old) || new_cp->is_pseudo_string_at(cpi_new))
return (old_cp->is_pseudo_string_at(cpi_old) == new_cp->is_pseudo_string_at(cpi_new));
} else if (tag_old.is_klass() || tag_old.is_unresolved_klass()) { } else if (tag_old.is_klass() || tag_old.is_unresolved_klass()) {
// tag_old should be klass - 4881222 // tag_old should be klass - 4881222
if (! (tag_new.is_unresolved_klass() || tag_new.is_klass())) if (! (tag_new.is_unresolved_klass() || tag_new.is_klass()))

View File

@ -727,180 +727,6 @@ UNSAFE_ENTRY(jclass, Unsafe_DefineClass0(JNIEnv *env, jobject unsafe, jstring na
} UNSAFE_END } UNSAFE_END
// define a class but do not make it known to the class loader or system dictionary
// - host_class: supplies context for linkage, access control, protection domain, and class loader
// if host_class is itself anonymous then it is replaced with its host class.
// - data: bytes of a class file, a raw memory address (length gives the number of bytes)
// - cp_patches: where non-null entries exist, they replace corresponding CP entries in data
// When you load an anonymous class U, it works as if you changed its name just before loading,
// to a name that you will never use again. Since the name is lost, no other class can directly
// link to any member of U. Just after U is loaded, the only way to use it is reflectively,
// through java.lang.Class methods like Class.newInstance.
// The package of an anonymous class must either match its host's class's package or be in the
// unnamed package. If it is in the unnamed package then it will be put in its host class's
// package.
//
// Access checks for linkage sites within U continue to follow the same rules as for named classes.
// An anonymous class also has special privileges to access any member of its host class.
// This is the main reason why this loading operation is unsafe. The purpose of this is to
// allow language implementations to simulate "open classes"; a host class in effect gets
// new code when an anonymous class is loaded alongside it. A less convenient but more
// standard way to do this is with reflection, which can also be set to ignore access
// restrictions.
// Access into an anonymous class is possible only through reflection. Therefore, there
// are no special access rules for calling into an anonymous class. The relaxed access
// rule for the host class is applied in the opposite direction: A host class reflectively
// access one of its anonymous classes.
// If you load the same bytecodes twice, you get two different classes. You can reload
// the same bytecodes with or without varying CP patches.
// By using the CP patching array, you can have a new anonymous class U2 refer to an older one U1.
// The bytecodes for U2 should refer to U1 by a symbolic name (doesn't matter what the name is).
// The CONSTANT_Class entry for that name can be patched to refer directly to U1.
// This allows, for example, U2 to use U1 as a superclass or super-interface, or as
// an outer class (so that U2 is an anonymous inner class of anonymous U1).
// It is not possible for a named class, or an older anonymous class, to refer by
// name (via its CP) to a newer anonymous class.
// CP patching may also be used to modify (i.e., hack) the names of methods, classes,
// or type descriptors used in the loaded anonymous class.
// Finally, CP patching may be used to introduce "live" objects into the constant pool,
// instead of "dead" strings. A compiled statement like println((Object)"hello") can
// be changed to println(greeting), where greeting is an arbitrary object created before
// the anonymous class is loaded. This is useful in dynamic languages, in which
// various kinds of metaobjects must be introduced as constants into bytecode.
// Note the cast (Object), which tells the verifier to expect an arbitrary object,
// not just a literal string. For such ldc instructions, the verifier uses the
// type Object instead of String, if the loaded constant is not in fact a String.
static InstanceKlass*
Unsafe_DefineAnonymousClass_impl(JNIEnv *env,
jclass host_class, jbyteArray data, jobjectArray cp_patches_jh,
u1** temp_alloc,
TRAPS) {
assert(host_class != NULL, "host_class must not be NULL");
assert(data != NULL, "data must not be NULL");
if (UsePerfData) {
ClassLoader::unsafe_defineClassCallCounter()->inc();
}
jint length = typeArrayOop(JNIHandles::resolve_non_null(data))->length();
assert(length >= 0, "class_bytes_length must not be negative: %d", length);
int class_bytes_length = (int) length;
u1* class_bytes = NEW_C_HEAP_ARRAY_RETURN_NULL(u1, length, mtInternal);
if (class_bytes == NULL) {
THROW_0(vmSymbols::java_lang_OutOfMemoryError());
}
// caller responsible to free it:
*temp_alloc = class_bytes;
ArrayAccess<>::arraycopy_to_native(arrayOop(JNIHandles::resolve_non_null(data)), typeArrayOopDesc::element_offset<jbyte>(0),
reinterpret_cast<jbyte*>(class_bytes), length);
objArrayHandle cp_patches_h;
if (cp_patches_jh != NULL) {
oop p = JNIHandles::resolve_non_null(cp_patches_jh);
assert(p->is_objArray(), "cp_patches must be an object[]");
cp_patches_h = objArrayHandle(THREAD, (objArrayOop)p);
}
const Klass* host_klass = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(host_class));
// Make sure it's the real host class, not another anonymous class.
while (host_klass != NULL && host_klass->is_instance_klass() &&
InstanceKlass::cast(host_klass)->is_unsafe_anonymous()) {
host_klass = InstanceKlass::cast(host_klass)->unsafe_anonymous_host();
}
// Primitive types have NULL Klass* fields in their java.lang.Class instances.
if (host_klass == NULL) {
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Host class is null");
}
assert(host_klass->is_instance_klass(), "Host class must be an instance class");
const char* host_source = host_klass->external_name();
Handle host_loader(THREAD, host_klass->class_loader());
Handle host_domain(THREAD, host_klass->protection_domain());
GrowableArray<Handle>* cp_patches = NULL;
if (cp_patches_h.not_null()) {
int alen = cp_patches_h->length();
for (int i = alen-1; i >= 0; i--) {
oop p = cp_patches_h->obj_at(i);
if (p != NULL) {
Handle patch(THREAD, p);
if (cp_patches == NULL) {
cp_patches = new GrowableArray<Handle>(i+1, i+1, Handle());
}
cp_patches->at_put(i, patch);
}
}
}
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
InstanceKlass* anonk = SystemDictionary::resolve_from_stream(&st, no_class_name,
host_loader,
cl_info,
CHECK_NULL);
assert(anonk != NULL, "no klass created");
return anonk;
}
UNSAFE_ENTRY(jclass, Unsafe_DefineAnonymousClass0(JNIEnv *env, jobject unsafe, jclass host_class, jbyteArray data, jobjectArray cp_patches_jh)) {
ResourceMark rm(THREAD);
jobject res_jh = NULL;
u1* temp_alloc = NULL;
InstanceKlass* anon_klass = Unsafe_DefineAnonymousClass_impl(env, host_class, data, cp_patches_jh, &temp_alloc, THREAD);
if (anon_klass != NULL) {
res_jh = JNIHandles::make_local(THREAD, anon_klass->java_mirror());
}
// try/finally clause:
FREE_C_HEAP_ARRAY(u1, temp_alloc);
// The anonymous 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.
if (anon_klass != NULL) {
anon_klass->class_loader_data()->dec_keep_alive();
}
// let caller initialize it as needed...
return (jclass) res_jh;
} UNSAFE_END
UNSAFE_ENTRY(void, Unsafe_ThrowException(JNIEnv *env, jobject unsafe, jthrowable thr)) { UNSAFE_ENTRY(void, Unsafe_ThrowException(JNIEnv *env, jobject unsafe, jthrowable thr)) {
ThreadToNativeFromVM ttnfv(thread); ThreadToNativeFromVM ttnfv(thread);
env->Throw(thr); env->Throw(thr);
@ -1120,8 +946,6 @@ static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = {
{CC "writebackPostSync0", CC "()V", FN_PTR(Unsafe_WriteBackPostSync0)}, {CC "writebackPostSync0", CC "()V", FN_PTR(Unsafe_WriteBackPostSync0)},
{CC "setMemory0", CC "(" OBJ "JJB)V", FN_PTR(Unsafe_SetMemory0)}, {CC "setMemory0", CC "(" OBJ "JJB)V", FN_PTR(Unsafe_SetMemory0)},
{CC "defineAnonymousClass0", CC "(" DAC_Args ")" CLS, FN_PTR(Unsafe_DefineAnonymousClass0)},
{CC "shouldBeInitialized0", CC "(" CLS ")Z", FN_PTR(Unsafe_ShouldBeInitialized0)}, {CC "shouldBeInitialized0", CC "(" CLS ")Z", FN_PTR(Unsafe_ShouldBeInitialized0)},
{CC "loadFence", CC "()V", FN_PTR(Unsafe_LoadFence)}, {CC "loadFence", CC "()V", FN_PTR(Unsafe_LoadFence)},

View File

@ -395,21 +395,6 @@ arrayOop Reflection::reflect_new_multi_array(oop element_mirror, typeArrayOop di
} }
static bool under_unsafe_anonymous_host(const InstanceKlass* ik, const InstanceKlass* unsafe_anonymous_host) {
DEBUG_ONLY(int inf_loop_check = 1000 * 1000 * 1000);
for (;;) {
const InstanceKlass* hc = ik->unsafe_anonymous_host();
if (hc == NULL) return false;
if (hc == unsafe_anonymous_host) return true;
ik = hc;
// There's no way to make a host class loop short of patching memory.
// Therefore there cannot be a loop here unless there's another bug.
// Still, let's check for it.
assert(--inf_loop_check > 0, "no unsafe_anonymous_host loop");
}
}
static bool can_relax_access_check_for(const Klass* accessor, static bool can_relax_access_check_for(const Klass* accessor,
const Klass* accessee, const Klass* accessee,
bool classloader_only) { bool classloader_only) {
@ -417,12 +402,6 @@ static bool can_relax_access_check_for(const Klass* accessor,
const InstanceKlass* accessor_ik = InstanceKlass::cast(accessor); const InstanceKlass* accessor_ik = InstanceKlass::cast(accessor);
const InstanceKlass* accessee_ik = InstanceKlass::cast(accessee); const InstanceKlass* accessee_ik = InstanceKlass::cast(accessee);
// If either is on the other's unsafe_anonymous_host chain, access is OK,
// because one is inside the other.
if (under_unsafe_anonymous_host(accessor_ik, accessee_ik) ||
under_unsafe_anonymous_host(accessee_ik, accessor_ik))
return true;
if (RelaxAccessControlCheck && if (RelaxAccessControlCheck &&
accessor_ik->major_version() < Verifier::NO_RELAX_ACCESS_CTRL_CHECK_VERSION && accessor_ik->major_version() < Verifier::NO_RELAX_ACCESS_CTRL_CHECK_VERSION &&
accessee_ik->major_version() < Verifier::NO_RELAX_ACCESS_CTRL_CHECK_VERSION) { accessee_ik->major_version() < Verifier::NO_RELAX_ACCESS_CTRL_CHECK_VERSION) {
@ -645,16 +624,7 @@ bool Reflection::verify_member_access(const Klass* current_class,
return true; return true;
} }
const Klass* host_class = current_class; if (current_class == member_class) {
if (current_class->is_instance_klass() &&
InstanceKlass::cast(current_class)->is_unsafe_anonymous()) {
host_class = InstanceKlass::cast(current_class)->unsafe_anonymous_host();
assert(host_class != NULL, "Unsafe anonymous class has null host class");
assert(!(host_class->is_instance_klass() &&
InstanceKlass::cast(host_class)->is_unsafe_anonymous()),
"unsafe_anonymous_host should not be unsafe anonymous itself");
}
if (host_class == member_class) {
return true; return true;
} }
@ -662,12 +632,12 @@ bool Reflection::verify_member_access(const Klass* current_class,
if (!protected_restriction) { if (!protected_restriction) {
// See if current_class (or outermost host class) is a subclass of member_class // See if current_class (or outermost host class) is a subclass of member_class
// An interface may not access protected members of j.l.Object // An interface may not access protected members of j.l.Object
if (!host_class->is_interface() && host_class->is_subclass_of(member_class)) { if (!current_class->is_interface() && current_class->is_subclass_of(member_class)) {
if (access.is_static() || // static fields are ok, see 6622385 if (access.is_static() || // static fields are ok, see 6622385
current_class == resolved_class || current_class == resolved_class ||
member_class == resolved_class || member_class == resolved_class ||
host_class->is_subclass_of(resolved_class) || current_class->is_subclass_of(resolved_class) ||
resolved_class->is_subclass_of(host_class)) { resolved_class->is_subclass_of(current_class)) {
return true; return true;
} }
} }
@ -679,9 +649,8 @@ bool Reflection::verify_member_access(const Klass* current_class,
return true; return true;
} }
// private access between different classes needs a nestmate check, but // private access between different classes needs a nestmate check.
// not for unsafe anonymous classes - so check host_class if (access.is_private()) {
if (access.is_private() && host_class == current_class) {
if (current_class->is_instance_klass() && member_class->is_instance_klass() ) { if (current_class->is_instance_klass() && member_class->is_instance_klass() ) {
InstanceKlass* cur_ik = const_cast<InstanceKlass*>(InstanceKlass::cast(current_class)); InstanceKlass* cur_ik = const_cast<InstanceKlass*>(InstanceKlass::cast(current_class));
InstanceKlass* field_ik = const_cast<InstanceKlass*>(InstanceKlass::cast(member_class)); InstanceKlass* field_ik = const_cast<InstanceKlass*>(InstanceKlass::cast(member_class));
@ -712,7 +681,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, // Checks that the 'outer' klass has declared 'inner' as being an inner klass. If not,
// throw an incompatible class change exception // 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 a member of the outer.
// If !inner_is_member, require the inner to be hidden or unsafe anonymous (non-members). // If !inner_is_member, require the inner to be hidden (non-member).
// Caller is responsible for figuring out in advance which case must be true. // 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, void Reflection::check_for_inner_class(const InstanceKlass* outer, const InstanceKlass* inner,
bool inner_is_member, TRAPS) { bool inner_is_member, TRAPS) {

View File

@ -2296,7 +2296,6 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
declare_constant(InstanceKlass::_misc_rewritten) \ declare_constant(InstanceKlass::_misc_rewritten) \
declare_constant(InstanceKlass::_misc_has_nonstatic_fields) \ declare_constant(InstanceKlass::_misc_has_nonstatic_fields) \
declare_constant(InstanceKlass::_misc_should_verify_class) \ declare_constant(InstanceKlass::_misc_should_verify_class) \
declare_constant(InstanceKlass::_misc_is_unsafe_anonymous) \
declare_constant(InstanceKlass::_misc_is_contended) \ declare_constant(InstanceKlass::_misc_is_contended) \
declare_constant(InstanceKlass::_misc_has_nonstatic_concrete_methods) \ declare_constant(InstanceKlass::_misc_has_nonstatic_concrete_methods) \
declare_constant(InstanceKlass::_misc_declares_nonstatic_concrete_methods)\ declare_constant(InstanceKlass::_misc_declares_nonstatic_concrete_methods)\

View File

@ -1012,8 +1012,6 @@ class InvokerBytecodeGenerator {
return false; // not on BCP return false; // not on BCP
if (cls.isHidden()) if (cls.isHidden())
return false; return false;
if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: Unsafe::defineAnonymousClass to be removed
return false;
if (!isStaticallyInvocableType(member.getMethodOrFieldType())) if (!isStaticallyInvocableType(member.getMethodOrFieldType()))
return false; return false;
if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls)) if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls))
@ -1045,8 +1043,6 @@ class InvokerBytecodeGenerator {
return true; // int[].class, for example return true; // int[].class, for example
if (cls.isHidden()) if (cls.isHidden())
return false; 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 // could use VerifyAccess.isClassAccessible but the following is a safe approximation
if (cls.getClassLoader() != Object.class.getClassLoader()) if (cls.getClassLoader() != Object.class.getClassLoader())
return false; return false;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -1329,34 +1329,6 @@ public final class Unsafe {
ClassLoader loader, ClassLoader loader,
ProtectionDomain protectionDomain); ProtectionDomain protectionDomain);
/**
* Defines a class but does not make it known to the class loader or system dictionary.
* <p>
* For each CP entry, the corresponding CP patch must either be null or have
* the a format that matches its tag:
* <ul>
* <li>Integer, Long, Float, Double: the corresponding wrapper object type from java.lang
* <li>Utf8: a string (must have suitable syntax if used as signature or name)
* <li>Class: any java.lang.Class object
* <li>String: any object (not just a java.lang.String)
* <li>InterfaceMethodRef: (NYI) a method handle to invoke on that call site's arguments
* </ul>
* @param hostClass context for linkage, access control, protection domain, and class loader
* @param data bytes of a class file
* @param cpPatches where non-null entries exist, they replace corresponding CP entries in data
*/
@Deprecated(since = "15", forRemoval = true)
public Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches) {
if (hostClass == null || data == null) {
throw new NullPointerException();
}
if (hostClass.isArray() || hostClass.isPrimitive()) {
throw new IllegalArgumentException();
}
return defineAnonymousClass0(hostClass, data, cpPatches);
}
/** /**
* Allocates an instance but does not run any constructor. * Allocates an instance but does not run any constructor.
* Initializes the class if it has not yet been. * Initializes the class if it has not yet been.
@ -3855,7 +3827,6 @@ public final class Unsafe {
private native void ensureClassInitialized0(Class<?> c); private native void ensureClassInitialized0(Class<?> c);
private native int arrayBaseOffset0(Class<?> arrayClass); private native int arrayBaseOffset0(Class<?> arrayClass);
private native int arrayIndexScale0(Class<?> arrayClass); private native int arrayIndexScale0(Class<?> arrayClass);
private native Class<?> defineAnonymousClass0(Class<?> hostClass, byte[] data, Object[] cpPatches);
private native int getLoadAverage0(double[] loadavg, int nelems); private native int getLoadAverage0(double[] loadavg, int nelems);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -57,7 +57,6 @@ class NativeConstructorAccessorImpl extends ConstructorAccessorImpl {
// be found from the generated bytecode. // be found from the generated bytecode.
if (++numInvocations > ReflectionFactory.inflationThreshold() if (++numInvocations > ReflectionFactory.inflationThreshold()
&& !c.getDeclaringClass().isHidden() && !c.getDeclaringClass().isHidden()
&& !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())
&& generated == 0 && generated == 0
&& U.compareAndSetInt(this, GENERATED_OFFSET, 0, 1)) { && U.compareAndSetInt(this, GENERATED_OFFSET, 0, 1)) {
try { try {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -55,7 +55,6 @@ class NativeMethodAccessorImpl extends MethodAccessorImpl {
// found from the generated bytecode. // found from the generated bytecode.
if (++numInvocations > ReflectionFactory.inflationThreshold() if (++numInvocations > ReflectionFactory.inflationThreshold()
&& !method.getDeclaringClass().isHidden() && !method.getDeclaringClass().isHidden()
&& !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())
&& generated == 0 && generated == 0
&& U.compareAndSetInt(this, GENERATED_OFFSET, 0, 1)) { && U.compareAndSetInt(this, GENERATED_OFFSET, 0, 1)) {
try { try {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -202,8 +202,7 @@ public class ReflectionFactory {
method = root; method = root;
} }
if (noInflation && !method.getDeclaringClass().isHidden() if (noInflation && !method.getDeclaringClass().isHidden()) {
&& !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
return new MethodAccessorGenerator(). return new MethodAccessorGenerator().
generateMethod(method.getDeclaringClass(), generateMethod(method.getDeclaringClass(),
method.getName(), method.getName(),
@ -247,8 +246,7 @@ public class ReflectionFactory {
return new BootstrapConstructorAccessorImpl(c); return new BootstrapConstructorAccessorImpl(c);
} }
if (noInflation && !c.getDeclaringClass().isHidden() if (noInflation && !c.getDeclaringClass().isHidden()) {
&& !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) {
return new MethodAccessorGenerator(). return new MethodAccessorGenerator().
generateConstructor(c.getDeclaringClass(), generateConstructor(c.getDeclaringClass(),
c.getParameterTypes(), c.getParameterTypes(),

View File

@ -312,12 +312,4 @@ public final class ReflectUtil {
return false; return false;
} }
/**
* Checks if {@code Class cls} is a VM-anonymous class
* as defined by {@link jdk.internal.misc.Unsafe#defineAnonymousClass}
* (not to be confused with a Java Language anonymous inner class).
*/
public static boolean isVMAnonymousClass(Class<?> cls) {
return cls.getName().indexOf('/') > -1;
}
} }

View File

@ -70,7 +70,6 @@ public class InstanceKlass extends Klass {
private static int MISC_REWRITTEN; private static int MISC_REWRITTEN;
private static int MISC_HAS_NONSTATIC_FIELDS; private static int MISC_HAS_NONSTATIC_FIELDS;
private static int MISC_SHOULD_VERIFY_CLASS; private static int MISC_SHOULD_VERIFY_CLASS;
private static int MISC_IS_UNSAFE_ANONYMOUS;
private static int MISC_IS_CONTENDED; private static int MISC_IS_CONTENDED;
private static int MISC_HAS_NONSTATIC_CONCRETE_METHODS; private static int MISC_HAS_NONSTATIC_CONCRETE_METHODS;
private static int MISC_DECLARES_NONSTATIC_CONCRETE_METHODS; private static int MISC_DECLARES_NONSTATIC_CONCRETE_METHODS;
@ -128,7 +127,6 @@ public class InstanceKlass extends Klass {
MISC_REWRITTEN = db.lookupIntConstant("InstanceKlass::_misc_rewritten").intValue(); MISC_REWRITTEN = db.lookupIntConstant("InstanceKlass::_misc_rewritten").intValue();
MISC_HAS_NONSTATIC_FIELDS = db.lookupIntConstant("InstanceKlass::_misc_has_nonstatic_fields").intValue(); MISC_HAS_NONSTATIC_FIELDS = db.lookupIntConstant("InstanceKlass::_misc_has_nonstatic_fields").intValue();
MISC_SHOULD_VERIFY_CLASS = db.lookupIntConstant("InstanceKlass::_misc_should_verify_class").intValue(); MISC_SHOULD_VERIFY_CLASS = db.lookupIntConstant("InstanceKlass::_misc_should_verify_class").intValue();
MISC_IS_UNSAFE_ANONYMOUS = db.lookupIntConstant("InstanceKlass::_misc_is_unsafe_anonymous").intValue();
MISC_IS_CONTENDED = db.lookupIntConstant("InstanceKlass::_misc_is_contended").intValue(); MISC_IS_CONTENDED = db.lookupIntConstant("InstanceKlass::_misc_is_contended").intValue();
MISC_HAS_NONSTATIC_CONCRETE_METHODS = db.lookupIntConstant("InstanceKlass::_misc_has_nonstatic_concrete_methods").intValue(); MISC_HAS_NONSTATIC_CONCRETE_METHODS = db.lookupIntConstant("InstanceKlass::_misc_has_nonstatic_concrete_methods").intValue();
MISC_DECLARES_NONSTATIC_CONCRETE_METHODS = db.lookupIntConstant("InstanceKlass::_misc_declares_nonstatic_concrete_methods").intValue(); MISC_DECLARES_NONSTATIC_CONCRETE_METHODS = db.lookupIntConstant("InstanceKlass::_misc_declares_nonstatic_concrete_methods").intValue();
@ -283,9 +281,6 @@ public class InstanceKlass extends Klass {
if (isInterface()) { if (isInterface()) {
size += wordLength; size += wordLength;
} }
if (isUnsafeAnonymous()) {
size += wordLength;
}
return alignSize(size); return alignSize(size);
} }
@ -293,10 +288,6 @@ public class InstanceKlass extends Klass {
return (int) miscFlags.getValue(this); return (int) miscFlags.getValue(this);
} }
public boolean isUnsafeAnonymous() {
return (getMiscFlags() & MISC_IS_UNSAFE_ANONYMOUS) != 0;
}
public static long getHeaderSize() { return headerSize; } public static long getHeaderSize() { return headerSize; }
public short getFieldAccessFlags(int index) { public short getFieldAccessFlags(int index) {

View File

@ -723,11 +723,6 @@ final class CompilerToVM {
*/ */
native Object getFlagValue(String name); native Object getFlagValue(String name);
/**
* Gets the host class for {@code type}.
*/
native HotSpotResolvedObjectTypeImpl getHostClass(HotSpotResolvedObjectTypeImpl type);
/** /**
* @see ResolvedJavaType#getInterfaces() * @see ResolvedJavaType#getInterfaces()
*/ */
@ -739,7 +734,7 @@ final class CompilerToVM {
native HotSpotResolvedJavaType getComponentType(HotSpotResolvedObjectTypeImpl type); native HotSpotResolvedJavaType getComponentType(HotSpotResolvedObjectTypeImpl type);
/** /**
* Get the array class for {@code type}. This can't be done symbolically since anonymous types * Get the array class for {@code type}. This can't be done symbolically since hidden classes
* can't be looked up by name. * can't be looked up by name.
*/ */
native HotSpotResolvedObjectTypeImpl getArrayType(HotSpotResolvedJavaType type); native HotSpotResolvedObjectTypeImpl getArrayType(HotSpotResolvedJavaType type);

View File

@ -108,23 +108,6 @@ public interface HotSpotResolvedObjectType extends ResolvedJavaType {
@Override @Override
ResolvedJavaMethod getClassInitializer(); ResolvedJavaMethod getClassInitializer();
/**
* Checks whether this type is an unsafe anonymous class.
*
* @return {@code true} if this type is an unsafe anonymous class
*/
boolean isUnsafeAnonymous();
/**
* Checks whether this type is an unsafe anonymous class.
* This method is here to maintain compatibility with JDK11.
*
* @return {@code true} if this type is an unsafe anonymous class
*/
default boolean isAnonymous() {
return isUnsafeAnonymous();
}
/** /**
* Gets the fingerprint for this type. * Gets the fingerprint for this type.
* *

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -448,14 +448,6 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
return false; return false;
} }
@Override
public ResolvedJavaType getHostClass() {
if (isArray()) {
return null;
}
return compilerToVM().getHostClass(this);
}
@Override @Override
public boolean isJavaLangObject() { public boolean isJavaLangObject() {
return getName().equals("Ljava/lang/Object;"); return getName().equals("Ljava/lang/Object;");
@ -1040,9 +1032,4 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
return UNSAFE.getInt(getMetaspaceKlass() + config().instanceKlassMiscFlagsOffset); return UNSAFE.getInt(getMetaspaceKlass() + config().instanceKlassMiscFlagsOffset);
} }
@Override
public boolean isUnsafeAnonymous() {
return (getMiscFlags() & config().instanceKlassMiscIsUnsafeAnonymous) != 0;
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -179,11 +179,6 @@ public final class HotSpotResolvedPrimitiveType extends HotSpotResolvedJavaType
return other.equals(this); return other.equals(this);
} }
@Override
public ResolvedJavaType getHostClass() {
return null;
}
@Override @Override
public JavaKind getJavaKind() { public JavaKind getJavaKind() {
return kind; return kind;

View File

@ -109,7 +109,6 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess {
final int instanceKlassStateLinked = getConstant("InstanceKlass::linked", Integer.class); final int instanceKlassStateLinked = getConstant("InstanceKlass::linked", Integer.class);
final int instanceKlassStateFullyInitialized = getConstant("InstanceKlass::fully_initialized", Integer.class); final int instanceKlassStateFullyInitialized = getConstant("InstanceKlass::fully_initialized", Integer.class);
final int instanceKlassStateBeingInitialized = getConstant("InstanceKlass::being_initialized", Integer.class); final int instanceKlassStateBeingInitialized = getConstant("InstanceKlass::being_initialized", Integer.class);
final int instanceKlassMiscIsUnsafeAnonymous = getConstant("InstanceKlass::_misc_is_unsafe_anonymous", Integer.class);
final int annotationsFieldAnnotationsOffset = getFieldOffset("Annotations::_fields_annotations", Integer.class, "Array<AnnotationArray*>*"); final int annotationsFieldAnnotationsOffset = getFieldOffset("Annotations::_fields_annotations", Integer.class, "Array<AnnotationArray*>*");
final int fieldsAnnotationsBaseOffset = getFieldValue("CompilerToVM::Data::_fields_annotations_base_offset", Integer.class, "int"); final int fieldsAnnotationsBaseOffset = getFieldValue("CompilerToVM::Data::_fields_annotations_base_offset", Integer.class, "int");

View File

@ -136,13 +136,6 @@ public interface ResolvedJavaType extends JavaType, ModifiersProvider, Annotated
*/ */
boolean isAssignableFrom(ResolvedJavaType other); boolean isAssignableFrom(ResolvedJavaType other);
/**
* Returns the {@link ResolvedJavaType} object representing the host class of this VM anonymous
* class (as opposed to the unrelated concept specified by {@link Class#isAnonymousClass()}) or
* {@code null} if this object does not represent a VM anonymous class.
*/
ResolvedJavaType getHostClass();
/** /**
* Returns true if this type is exactly the type {@link java.lang.Object}. * Returns true if this type is exactly the type {@link java.lang.Object}.
*/ */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -44,7 +44,7 @@ public abstract class Value {
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
// Due to de-serialization this object may exist multiple times. So we compare classes // Due to de-serialization this object may exist multiple times. So we compare classes
// instead of the individual objects. (This anonymous class has always the same meaning) // instead of the individual objects.
return other instanceof IllegalValue; return other instanceof IllegalValue;
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -854,34 +854,6 @@ public final class Unsafe {
/// random trusted operations from JNI: /// random trusted operations from JNI:
/**
* Defines a class but does not make it known to the class loader or system dictionary.
* <p>
* For each CP entry, the corresponding CP patch must either be null or have
* the a format that matches its tag:
* <ul>
* <li>Integer, Long, Float, Double: the corresponding wrapper object type from java.lang
* <li>Utf8: a string (must have suitable syntax if used as signature or name)
* <li>Class: any java.lang.Class object
* <li>String: any object (not just a java.lang.String)
* <li>InterfaceMethodRef: (NYI) a method handle to invoke on that call site's arguments
* </ul>
*
* @deprecated Use {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...)}
* or {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClassWithClassData(byte[], Object, boolean, MethodHandles.Lookup.ClassOption...)}
* instead.
*
* @param hostClass context for linkage, access control, protection domain, and class loader
* @param data bytes of a class file
* @param cpPatches where non-null entries exist, they replace corresponding CP entries in data
*/
@ForceInline
@Deprecated(since = "15", forRemoval = true)
@SuppressWarnings("removal")
public Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches) {
return theInternalUnsafe.defineAnonymousClass(hostClass, data, cpPatches);
}
/** /**
* Allocates an instance but does not run any constructor. * Allocates an instance but does not run any constructor.
* Initializes the class if it has not yet been. * Initializes the class if it has not yet been.

View File

@ -1,141 +0,0 @@
/*
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8054402
* @summary "Tests unloading of anonymous classes."
* @library /test/lib /
* @modules java.base/jdk.internal.misc
* @build sun.hotspot.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
*
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:-BackgroundCompilation
* compiler.classUnloading.anonymousClass.TestAnonymousClassUnloading
*/
package compiler.classUnloading.anonymousClass;
import jdk.internal.misc.Unsafe;
import sun.hotspot.WhiteBox;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLConnection;
import compiler.whitebox.CompilerWhiteBoxTest;
public class TestAnonymousClassUnloading {
private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
/**
* We override hashCode here to be able to access this implementation
* via an Object reference (we cannot cast to TestAnonymousClassUnloading).
*/
@Override
public int hashCode() {
return 42;
}
/**
* Does some work by using the anonymousClass.
* @param anonymousClass Class performing some work (will be unloaded)
*/
static private void doWork(Class<?> anonymousClass) throws InstantiationException, IllegalAccessException {
// Create a new instance
Object anon = anonymousClass.newInstance();
// We would like to call a method of anonymousClass here but we cannot cast because the class
// was loaded by a different class loader. One solution would be to use reflection but since
// we want C2 to implement the call as an IC we call Object::hashCode() here which actually
// calls anonymousClass::hashCode(). C2 will then implement this call as an IC.
if (anon.hashCode() != 42) {
new RuntimeException("Work not done");
}
}
/**
* Makes sure that method is compiled by forcing compilation if not yet compiled.
* @param m Method to be checked
*/
static private void makeSureIsCompiled(Method m) {
// Make sure background compilation is disabled
if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) {
throw new RuntimeException("Background compilation enabled");
}
// Check if already compiled
if (!WHITE_BOX.isMethodCompiled(m)) {
// If not, try to compile it with C2
if(!WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) {
// C2 compiler not available, try to compile with C1
WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE);
}
// Because background compilation is disabled, method should now be compiled
if(!WHITE_BOX.isMethodCompiled(m)) {
throw new RuntimeException(m + " not compiled");
}
}
}
/**
* This test creates stale Klass* metadata referenced by a compiled IC.
*
* The following steps are performed:
* (1) An anonymous version of TestAnonymousClassUnloading is loaded by a custom class loader
* (2) The method doWork that calls a method of the anonymous class is compiled. The call
* is implemented as an IC referencing Klass* metadata of the anonymous class.
* (3) Unloading of the anonymous class is enforced. The IC now references dead metadata.
*/
static public void main(String[] args) throws Exception {
// (1) Load an anonymous version of this class using the corresponding Unsafe method
String rn = TestAnonymousClassUnloading.class.getSimpleName() + ".class";
URL classUrl = TestAnonymousClassUnloading.class.getResource(rn);
URLConnection connection = classUrl.openConnection();
int length = connection.getContentLength();
byte[] classBytes = connection.getInputStream().readAllBytes();
if (length != -1 && classBytes.length != length) {
throw new IOException("Expected:" + length + ", actual: " + classBytes.length);
}
Class<?> anonymousClass = UNSAFE.defineAnonymousClass(TestAnonymousClassUnloading.class, classBytes, null);
// (2) Make sure all paths of doWork are profiled and compiled
for (int i = 0; i < 100000; ++i) {
doWork(anonymousClass);
}
// Make sure doWork is compiled now
Method doWork = TestAnonymousClassUnloading.class.getDeclaredMethod("doWork", Class.class);
makeSureIsCompiled(doWork);
// (3) Throw away reference to anonymousClass to allow unloading
anonymousClass = null;
// Force garbage collection to trigger unloading of anonymousClass
// Dead metadata reference to anonymousClass triggers JDK-8054402
WHITE_BOX.fullGC();
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -38,7 +38,6 @@
package compiler.jsr292; package compiler.jsr292;
import jdk.internal.misc.Unsafe;
import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Handle; import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor;
@ -47,6 +46,7 @@ import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandleHelper; import java.lang.invoke.MethodHandleHelper;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite; import java.lang.invoke.MutableCallSite;
import java.lang.ref.PhantomReference; import java.lang.ref.PhantomReference;
@ -61,7 +61,6 @@ import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN; import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN;
public class CallSiteDepContextTest { public class CallSiteDepContextTest {
static final Unsafe UNSAFE = Unsafe.getUnsafe();
static final MethodHandles.Lookup LOOKUP = MethodHandleHelper.IMPL_LOOKUP; static final MethodHandles.Lookup LOOKUP = MethodHandleHelper.IMPL_LOOKUP;
static final String CLASS_NAME = "compiler/jsr292/Test"; static final String CLASS_NAME = "compiler/jsr292/Test";
static final String METHOD_NAME = "m"; static final String METHOD_NAME = "m";
@ -130,8 +129,9 @@ public class CallSiteDepContextTest {
} }
public static void testSharedCallSite() throws Throwable { public static void testSharedCallSite() throws Throwable {
Class<?> cls1 = UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("CS_1"), null); Lookup lookup = MethodHandles.lookup();
Class<?> cls2 = UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("CS_2"), null); Class<?> cls1 = lookup.defineHiddenClass(getClassFile("CS_1"), true).lookupClass();
Class<?> cls2 = lookup.defineHiddenClass(getClassFile("CS_2"), true).lookupClass();
MethodHandle[] mhs = new MethodHandle[] { MethodHandle[] mhs = new MethodHandle[] {
LOOKUP.findStatic(cls1, METHOD_NAME, TYPE), LOOKUP.findStatic(cls1, METHOD_NAME, TYPE),
@ -152,7 +152,8 @@ public class CallSiteDepContextTest {
execute(1, mh); execute(1, mh);
// mcs.context == cls1 // mcs.context == cls1
Class<?> cls1 = UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("NonBound_1"), null); Lookup lookup = MethodHandles.lookup();
Class<?> cls1 = lookup.defineHiddenClass(getClassFile("NonBound_1"), true).lookupClass();
MethodHandle mh1 = LOOKUP.findStatic(cls1, METHOD_NAME, TYPE); MethodHandle mh1 = LOOKUP.findStatic(cls1, METHOD_NAME, TYPE);
execute(1, mh1); execute(1, mh1);
@ -170,9 +171,10 @@ public class CallSiteDepContextTest {
mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE)); mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE));
Lookup lookup = MethodHandles.lookup();
Class<?>[] cls = new Class[] { Class<?>[] cls = new Class[] {
UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("GC_1" + id), null), lookup.defineHiddenClass(getClassFile("GC_1"), true).lookupClass(),
UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("GC_2" + id), null), lookup.defineHiddenClass(getClassFile("GC_2"), true).lookupClass(),
}; };
MethodHandle[] mhs = new MethodHandle[] { MethodHandle[] mhs = new MethodHandle[] {
@ -186,7 +188,7 @@ public class CallSiteDepContextTest {
execute(1, mhs); execute(1, mhs);
ref = new PhantomReference<>(cls[0], rq); ref = new PhantomReference<>(cls[0], rq);
cls[0] = UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("GC_3" + id), null); cls[0] = lookup.defineHiddenClass(getClassFile("GC_3"), true).lookupClass();
mhs[0] = LOOKUP.findStatic(cls[0], METHOD_NAME, TYPE); mhs[0] = LOOKUP.findStatic(cls[0], METHOD_NAME, TYPE);
do { do {

View File

@ -1,130 +0,0 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8058828
* @modules java.base/jdk.internal.org.objectweb.asm
* java.base/jdk.internal.misc
*
* @run main/bootclasspath/othervm -Xbatch compiler.jsr292.VMAnonymousClasses
*/
package compiler.jsr292;
import jdk.internal.misc.Unsafe;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite;
import java.lang.invoke.VolatileCallSite;
public class VMAnonymousClasses {
static final String TEST_METHOD_NAME = "constant";
static final Unsafe UNSAFE = Unsafe.getUnsafe();
static int getConstantPoolSize(byte[] classFile) {
// The first few bytes:
// u4 magic;
// u2 minor_version;
// u2 major_version;
// u2 constant_pool_count;
return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF);
}
static void test(Object value) throws ReflectiveOperationException {
System.out.printf("Test: %s", value != null ? value.getClass() : "null");
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, "Test", null, "java/lang/Object", null);
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC, TEST_METHOD_NAME, "()Ljava/lang/Object;", null, null);
String placeholder = "CONSTANT";
int index = cw.newConst(placeholder);
mv.visitLdcInsn(placeholder);
mv.visitInsn(Opcodes.ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
byte[] classFile = cw.toByteArray();
Object[] cpPatches = new Object[getConstantPoolSize(classFile)];
cpPatches[index] = value;
Class<?> test = UNSAFE.defineAnonymousClass(VMAnonymousClasses.class, classFile, cpPatches);
Object expectedResult = (value != null) ? value : placeholder;
for (int i = 0; i<15000; i++) {
Object result = test.getMethod(TEST_METHOD_NAME).invoke(null);
if (result != expectedResult) {
throw new AssertionError(String.format("Wrong value returned: %s != %s", value, result));
}
}
System.out.println(" PASSED");
}
public static void main(String[] args) throws ReflectiveOperationException {
// Objects
test(new Object());
test("TEST");
test(new VMAnonymousClasses());
test(null);
// Class
test(String.class);
// Arrays
test(new boolean[0]);
test(new byte[0]);
test(new char[0]);
test(new short[0]);
test(new int[0]);
test(new long[0]);
test(new float[0]);
test(new double[0]);
test(new Object[0]);
// Multi-dimensional arrays
test(new byte[0][0]);
test(new Object[0][0]);
// MethodHandle-related
MethodType mt = MethodType.methodType(void.class, String[].class);
MethodHandle mh = MethodHandles.lookup().findStatic(VMAnonymousClasses.class, "main", mt);
test(mt);
test(mh);
test(new ConstantCallSite(mh));
test(new MutableCallSite(MethodType.methodType(void.class)));
test(new VolatileCallSite(MethodType.methodType(void.class)));
System.out.println("TEST PASSED");
}
}

View File

@ -84,16 +84,12 @@ public class TestMetaAccessProvider extends TypeUniverse {
return false; return false;
} }
private static boolean isUnsafeAnonymous(ResolvedJavaType type) {
return type.getHostClass() != null;
}
@Test @Test
public void lookupJavaTypeTest() { public void lookupJavaTypeTest() {
for (Class<?> c : classes) { for (Class<?> c : classes) {
ResolvedJavaType type = metaAccess.lookupJavaType(c); ResolvedJavaType type = metaAccess.lookupJavaType(c);
assertNotNull(c.toString(), type); assertNotNull(c.toString(), type);
if (!isHiddenClass(c) && !isUnsafeAnonymous(type)) { if (!isHiddenClass(c)) {
assertEquals(c.toString(), type.getName(), toInternalName(c.getName())); assertEquals(c.toString(), type.getName(), toInternalName(c.getName()));
assertEquals(c.toString(), type.getName(), toInternalName(type.toJavaName())); assertEquals(c.toString(), type.getName(), toInternalName(type.toJavaName()));
assertEquals(c.toString(), c.getName(), type.toClassName()); assertEquals(c.toString(), c.getName(), type.toClassName());
@ -114,7 +110,7 @@ public class TestMetaAccessProvider extends TypeUniverse {
ResolvedJavaType[] result = metaAccess.lookupJavaTypes(classes.toArray(new Class<?>[classes.size()])); ResolvedJavaType[] result = metaAccess.lookupJavaTypes(classes.toArray(new Class<?>[classes.size()]));
int counter = 0; int counter = 0;
for (Class<?> aClass : classes) { for (Class<?> aClass : classes) {
if (!isHiddenClass(aClass) && !isUnsafeAnonymous(result[counter])) { if (!isHiddenClass(aClass)) {
assertEquals("Unexpected javaType: " + result[counter] + " while expecting of class: " + aClass, result[counter].toClassName(), aClass.getName()); assertEquals("Unexpected javaType: " + result[counter] + " while expecting of class: " + aClass, result[counter].toClassName(), aClass.getName());
} }
counter++; counter++;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -162,45 +162,6 @@ public class TestResolvedJavaType extends TypeUniverse {
} }
} }
private static Class<?> anonClass() throws Exception {
ClassWriter cw = new ClassWriter(0);
cw.visit(Opcodes.V1_8, Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, "Anon", null, "java/lang/Object", null);
FieldVisitor intField = cw.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "intField", "I", null, 0);
intField.visitEnd();
cw.visitEnd();
return unsafe.defineAnonymousClass(TypeUniverse.class, cw.toByteArray(), null);
}
@Test
public void getHostClassTest() throws Exception {
ResolvedJavaType type = metaAccess.lookupJavaType(anonClass());
ResolvedJavaType host = type.getHostClass();
assertNotNull(host);
for (Class<?> c : classes) {
type = metaAccess.lookupJavaType(c);
host = type.getHostClass();
assertNull(host);
if (type.equals(predicateType)) {
assertTrue(c.isHidden());
}
}
class LocalClass {
}
Cloneable clone = new Cloneable() {
};
assertNull(metaAccess.lookupJavaType(LocalClass.class).getHostClass());
assertNull(metaAccess.lookupJavaType(clone.getClass()).getHostClass());
Supplier<Runnable> lambda = () -> () -> System.out.println("run");
ResolvedJavaType lambdaType = metaAccess.lookupJavaType(lambda.getClass());
ResolvedJavaType nestedLambdaType = metaAccess.lookupJavaType(lambda.get().getClass());
assertNull(lambdaType.getHostClass());
assertTrue(lambda.getClass().isHidden());
assertNull(nestedLambdaType.getHostClass());
assertTrue(lambda.get().getClass().isHidden());
}
@Test @Test
public void getModifiersTest() { public void getModifiersTest() {
for (Class<?> c : classes) { for (Class<?> c : classes) {

View File

@ -1,93 +0,0 @@
/*
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8026365
* @summary Test invokespecial of host class method from an anonymous class
* @author Robert Field
* @library /test/lib
* @modules java.base/jdk.internal.org.objectweb.asm
* java.base/jdk.internal.misc
* @compile -XDignore.symbol.file InvokeSpecialAnonTest.java
* @run driver jdk.test.lib.helpers.ClassFileInstaller InvokeSpecialAnonTest AnonTester
* @run main/othervm -Xbootclasspath/a:. -Xverify:all InvokeSpecialAnonTest
*/
import jdk.internal.org.objectweb.asm.*;
import java.lang.reflect.Constructor;
import jdk.internal.misc.Unsafe;
public class InvokeSpecialAnonTest implements Opcodes {
static byte[] anonClassBytes() throws Exception {
ClassWriter cw = new ClassWriter(0);
MethodVisitor mv;
cw.visit(V1_8, ACC_FINAL + ACC_SUPER, "Anon", null, "java/lang/Object", null);
{
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "m", "(LInvokeSpecialAnonTest;)I", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKESPECIAL, "InvokeSpecialAnonTest", "privMethod", "()I");
mv.visitInsn(IRETURN);
mv.visitMaxs(2, 3);
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
private int privMethod() { return 1234; }
public static void main(String[] args) throws Exception {
Class<?> klass = InvokeSpecialAnonTest.class;
try {
Class<?> result = AnonTester.defineTest(klass, anonClassBytes());
System.out.println("Passed.");
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
class AnonTester {
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
public static Class<?> defineTest(Class<?> targetClass, byte[] classBytes) throws Exception {
return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -24,6 +24,12 @@
/* /*
* @test * @test
* @summary Test that a hidden class can be cast to its parent. * @summary Test that a hidden class can be cast to its parent.
* DESCRIPTION
* Try to cast an object of a hidden class to its parent (called CastToParentTest)
* - (CastToParentTest) o
* - o.getClass().cast(<hiddenClassObj>);
* and cast to its grandparent (java.lang.Object).
*
* @library /test/lib * @library /test/lib
* @modules jdk.compiler * @modules jdk.compiler
* @run main CastToParentTest * @run main CastToParentTest
@ -35,7 +41,6 @@ import java.lang.invoke.MethodHandles.Lookup;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
import jdk.test.lib.compiler.InMemoryJavaCompiler; import jdk.test.lib.compiler.InMemoryJavaCompiler;
// This test is based on vmTestbase/vm/mlvm/anonloader/func/castToGrandparent/Test.java
public class CastToParentTest { public class CastToParentTest {
static byte klassbuf[] = InMemoryJavaCompiler.compile("TestClass", static byte klassbuf[] = InMemoryJavaCompiler.compile("TestClass",
@ -58,5 +63,17 @@ public class CastToParentTest {
// Try to cast using a different mechanism. // Try to cast using a different mechanism.
new CastToParentTest().getClass().cast(hiddenClassObj); new CastToParentTest().getClass().cast(hiddenClassObj);
// Cast hidden class to its grandparent.
java.lang.Object grandparentObj = (java.lang.Object)hiddenClassObj;
if (!grandparentObj.equals(hiddenClassObj)) {
throw new RuntimeException("Hidden class object cannot be cast to grandparent");
} }
// Try to cast using a different mechanism.
new java.lang.Object().getClass().cast(hiddenClassObj);
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -40,7 +40,6 @@ import java.lang.ref.ReferenceQueue;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
import jdk.test.lib.compiler.InMemoryJavaCompiler; import jdk.test.lib.compiler.InMemoryJavaCompiler;
// This test is based on test vmTestbase/vm/mlvm/anonloader/func/isGarbageCollected/Test.java
public class GCHiddenClass { public class GCHiddenClass {
static byte klassbuf[] = InMemoryJavaCompiler.compile("TestClass", static byte klassbuf[] = InMemoryJavaCompiler.compile("TestClass",

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,10 @@
* @test * @test
* @summary Test that stack tracing isn't broken if an exception is thrown * @summary Test that stack tracing isn't broken if an exception is thrown
* in a hidden class. * in a hidden class.
* DESCRIPTION
* An exception is thrown by a hidden class. Verify that the exception's
* stack trace contains the name of the current test class (i.e., verify
* that the stack trace is not broken).
* @library /test/lib * @library /test/lib
* @modules jdk.compiler * @modules jdk.compiler
* @run main HiddenClassStack * @run main HiddenClassStack
@ -38,7 +42,6 @@ import java.lang.invoke.MethodHandles.Lookup;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
import jdk.test.lib.compiler.InMemoryJavaCompiler; import jdk.test.lib.compiler.InMemoryJavaCompiler;
// This test is based on vmTestbase/vm/mlvm/anonloader/func/classNameInStackTrace/Test.java
public class HiddenClassStack { public class HiddenClassStack {
static byte klassbuf[] = InMemoryJavaCompiler.compile("TestClass", static byte klassbuf[] = InMemoryJavaCompiler.compile("TestClass",

View File

@ -36,7 +36,6 @@ import java.lang.invoke.MethodHandles.Lookup;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
import jdk.test.lib.compiler.InMemoryJavaCompiler; import jdk.test.lib.compiler.InMemoryJavaCompiler;
// This test is based on vmTestbase/vm/mlvm/anonloader/share/StressClassLoadingTest.java
public class StressHiddenClasses { public class StressHiddenClasses {
private static final int PARSE_TIMEOUT = 0; private static final int PARSE_TIMEOUT = 0;

View File

@ -47,7 +47,6 @@ import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import compiler.whitebox.CompilerWhiteBoxTest; import compiler.whitebox.CompilerWhiteBoxTest;
// This is based on test compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java
public class TestHiddenClassUnloading { public class TestHiddenClassUnloading {
private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();

View File

@ -1,87 +0,0 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary Creates an anonymous class inside of an anonymous class.
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
* @run main NestedUnsafe
*/
import java.lang.*;
import jdk.test.lib.compiler.InMemoryJavaCompiler;
import jdk.internal.misc.Unsafe;
// package p;
public class NestedUnsafe {
// The String concatenation should create the nested anonymous class.
static byte klassbuf[] = InMemoryJavaCompiler.compile("TestClass",
"public class TestClass { " +
" public static void concat(String one, String two) throws Throwable { " +
" System.out.println(one + two);" +
" } } ");
public static void main(String args[]) throws Exception {
Unsafe unsafe = Unsafe.getUnsafe();
Class klass = unsafe.defineAnonymousClass(NestedUnsafe.class, klassbuf, new Object[0]);
unsafe.ensureClassInitialized(klass);
Class[] cArgs = new Class[2];
cArgs[0] = String.class;
cArgs[1] = String.class;
try {
klass.getMethod("concat", cArgs).invoke(null, "AA", "BB");
} catch (Throwable ex) {
throw new RuntimeException("Exception: " + ex.toString());
}
// The anonymous class calls defineAnonymousClass creating a nested anonymous class.
byte klassbuf2[] = InMemoryJavaCompiler.compile("TestClass2",
"import jdk.internal.misc.Unsafe; " +
"public class TestClass2 { " +
" public static void doit() throws Throwable { " +
" Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe(); " +
" Class klass2 = unsafe.defineAnonymousClass(TestClass2.class, NestedUnsafe.klassbuf, new Object[0]); " +
" unsafe.ensureClassInitialized(klass2); " +
" Class[] dArgs = new Class[2]; " +
" dArgs[0] = String.class; " +
" dArgs[1] = String.class; " +
" try { " +
" klass2.getMethod(\"concat\", dArgs).invoke(null, \"CC\", \"DD\"); " +
" } catch (Throwable ex) { " +
" throw new RuntimeException(\"Exception: \" + ex.toString()); " +
" } " +
"} } ",
"--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED");
Class klass2 = unsafe.defineAnonymousClass(NestedUnsafe.class, klassbuf2, new Object[0]);
try {
klass2.getMethod("doit").invoke(null);
} catch (Throwable ex) {
throw new RuntimeException("Exception: " + ex.toString());
}
}
}

View File

@ -1,89 +0,0 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.Component;
import java.lang.reflect.Field;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import jdk.internal.org.objectweb.asm.*;
import jdk.internal.misc.Unsafe;
/*
* @test PrimitiveHostClass
* @bug 8140665
* @summary Throws IllegalArgumentException if host class is a primitive class.
* @modules java.base/jdk.internal.org.objectweb.asm
* java.base/jdk.internal.misc
* @compile -XDignore.symbol.file PrimitiveHostClass.java
* @run main/othervm PrimitiveHostClass
*/
public class PrimitiveHostClass {
static final Unsafe U = Unsafe.getUnsafe();
public static void testVMAnonymousClass(Class<?> hostClass) {
// choose a class name in the same package as the host class
String prefix = packageName(hostClass);
if (prefix.length() > 0)
prefix = prefix.replace('.', '/') + "/";
String className = prefix + "Anon";
// create the class
String superName = "java/lang/Object";
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+ ClassWriter.COMPUTE_FRAMES);
cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER,
className, null, superName, null);
byte[] classBytes = cw.toByteArray();
int cpPoolSize = constantPoolSize(classBytes);
Class<?> anonClass =
U.defineAnonymousClass(hostClass, classBytes, new Object[cpPoolSize]);
}
private static String packageName(Class<?> c) {
if (c.isArray()) {
return packageName(c.getComponentType());
} else {
String name = c.getName();
int dot = name.lastIndexOf('.');
if (dot == -1) return "";
return name.substring(0, dot);
}
}
private static int constantPoolSize(byte[] classFile) {
return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF);
}
public static void main(String args[]) {
testVMAnonymousClass(PrimitiveHostClass.class);
try {
testVMAnonymousClass(int.class);
throw new RuntimeException(
"Expected IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
// Expected
}
}
}

View File

@ -1,76 +0,0 @@
/*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
/*
* @test
* @summary LambdaMetafactory does not support VM anonymous classes.
* This is a sanity test to make sure CDS can handle this case and
* the VM anonymous class should not be archived.
* @requires vm.cds
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes
* @modules java.base/jdk.internal.misc
* @compile test-classes/UnsafeAndLambdaApp.java
* ../../../../../../lib/jdk/test/lib/compiler/InMemoryJavaCompiler.java
* @build sun.hotspot.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar unsafeandlambda.jar UnsafeAndLambdaApp
* jdk/test/lib/compiler/InMemoryJavaCompiler
* jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper$1
* jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper
* jdk/test/lib/compiler/InMemoryJavaCompiler$MemoryJavaFileObject
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. UnsafeAndLambda
*/
import jdk.test.lib.helpers.ClassFileInstaller;
public class UnsafeAndLambda extends DynamicArchiveTestBase {
public static void main(String[] args) throws Exception {
runTest(UnsafeAndLambda::test);
}
static void test() throws Exception {
String topArchiveName = getNewArchiveName();
String appJar = ClassFileInstaller.getJarPath("unsafeandlambda.jar");
String mainClass = "UnsafeAndLambdaApp";
dump(topArchiveName,
"-Xlog:class+load=debug,cds+dynamic,cds",
"--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED",
"-cp", appJar, mainClass)
.assertNormalExit(output -> {
output.shouldContain("Skipping LambdaHello: Unsafe anonymous class")
.shouldHaveExitValue(0);
});
run(topArchiveName,
"-Xlog:class+load=debug,cds+dynamic,cds",
"--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED",
"-cp", appJar, mainClass)
.assertNormalExit(output -> {
output.shouldMatch("class.load.*LambdaHello/0x.*source.*UnsafeAndLambdaApp")
.shouldHaveExitValue(0);
});
}
}

View File

@ -1,74 +0,0 @@
/*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
/*
* @test
* @summary VM unsafe anonymous classes will not be archived.
* @requires vm.cds
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes
* @modules java.base/jdk.internal.misc
* @compile test-classes/UnsafeAnonymousApp.java
* ../../../../../../lib/jdk/test/lib/compiler/InMemoryJavaCompiler.java
* @build sun.hotspot.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar unsafe.jar UnsafeAnonymousApp
* jdk/test/lib/compiler/InMemoryJavaCompiler
* jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper$1
* jdk/test/lib/compiler/InMemoryJavaCompiler$FileManagerWrapper
* jdk/test/lib/compiler/InMemoryJavaCompiler$MemoryJavaFileObject
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. UnsafeAnonymous
*/
import jdk.test.lib.helpers.ClassFileInstaller;
public class UnsafeAnonymous extends DynamicArchiveTestBase {
public static void main(String[] args) throws Exception {
runTest(UnsafeAnonymous::test);
}
static void test() throws Exception {
String topArchiveName = getNewArchiveName();
String appJar = ClassFileInstaller.getJarPath("unsafe.jar");
String mainClass = "UnsafeAnonymousApp";
dump(topArchiveName,
"-Xlog:class+load=debug,cds+dynamic,cds",
"--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED",
"-cp", appJar, mainClass)
.assertNormalExit(output -> {
output.shouldContain("Skipping TestClass: Unsafe anonymous class")
.shouldHaveExitValue(0);
});
run(topArchiveName,
"-Xlog:class+load=debug,cds+dynamic,cds",
"--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED",
"-cp", appJar, mainClass)
.assertNormalExit(output -> {
output.shouldMatch("class.load.*TestClass/0x.*source.*UnsafeAnonymousApp")
.shouldHaveExitValue(0);
});
}
}

View File

@ -1,54 +0,0 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
import jdk.test.lib.compiler.InMemoryJavaCompiler;
import jdk.internal.misc.Unsafe;
public class UnsafeAndLambdaApp {
static byte klassbuf[] = InMemoryJavaCompiler.compile("LambdaHello",
"public class LambdaHello { " +
" public LambdaHello() { " +
" doit(() -> { " +
" System.out.println(\"Hello from Lambda\"); " +
" }); " +
" } " +
" static void doit (Runnable r) { " +
" r.run(); " +
" } " +
"} ");
public static void main(String args[]) throws Exception {
Unsafe unsafe = Unsafe.getUnsafe();
Class klass = unsafe.defineAnonymousClass(UnsafeAndLambdaApp.class, klassbuf, new Object[0]);
try {
Object obj = klass.newInstance();
// If we come to here, LambdaMetafactory has probably been modified
// to support vm-anon classes. In that case, we will need more tests for CDS.
throw new RuntimeException("Unexpected support for lambda classes in VM anonymous classes");
} catch (java.lang.InternalError expected) {
System.out.println("Caught expected java.lang.InternalError");
}
}
}

View File

@ -1,39 +0,0 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
import jdk.test.lib.compiler.InMemoryJavaCompiler;
import jdk.internal.misc.Unsafe;
public class UnsafeAnonymousApp {
static byte klassbuf[] = InMemoryJavaCompiler.compile("TestClass",
"public class TestClass { " +
"} ");
public static void main(String args[]) throws Exception {
Unsafe unsafe = Unsafe.getUnsafe();
Class klass = unsafe.defineAnonymousClass(UnsafeAnonymousApp.class, klassbuf, new Object[0]);
Object obj = klass.newInstance();
}
}

View File

@ -1,75 +0,0 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// This is copied from DefineAnon to test Symbol Refcounting for the package prepended name.
package p1;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.misc.Unsafe;
class T {
static protected void test0() { System.out.println("test0 (public)"); }
static protected void test1() { System.out.println("test1 (protected)"); }
static /*package-private*/ void test2() { System.out.println("test2 (package)"); }
static private void test3() { System.out.println("test3 (private)"); }
}
public class AnonSymbolLeak {
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
static Class<?> getAnonClass(Class<?> hostClass, final String className) {
final String superName = "java/lang/Object";
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, className, null, superName, null);
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC, "test", "()V", null, null);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "p1/T", "test0", "()V", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "p1/T", "test1", "()V", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "p1/T", "test2", "()V", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "p1/T", "test3", "()V", false);
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
final byte[] classBytes = cw.toByteArray();
Class<?> invokerClass = UNSAFE.defineAnonymousClass(hostClass, classBytes, new Object[0]);
UNSAFE.ensureClassInitialized(invokerClass);
return invokerClass;
}
public static void test() throws Throwable {
// AnonClass is injected into package p1.
System.out.println("Injecting from the same package (p1):");
Class<?> p1cls = getAnonClass(T.class, "AnonClass");
p1cls.getMethod("test").invoke(null);
}
public static void main(java.lang.String[] unused) throws Throwable {
test();
}
}

View File

@ -1,125 +0,0 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test DefineAnon
* @bug 8058575
* @library /testlibrary
* @modules java.base/jdk.internal.org.objectweb.asm
* java.management
* java.base/jdk.internal.misc
* @compile -XDignore.symbol.file=true DefineAnon.java
* @run main/othervm p1.DefineAnon
*/
package p1;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.misc.Unsafe;
class T {
static protected void test0() { System.out.println("test0 (public)"); }
static protected void test1() { System.out.println("test1 (protected)"); }
static /*package-private*/ void test2() { System.out.println("test2 (package)"); }
static private void test3() { System.out.println("test3 (private)"); }
}
public class DefineAnon {
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
static Class<?> getAnonClass(Class<?> hostClass, final String className) {
final String superName = "java/lang/Object";
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, className, null, superName, null);
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC, "test", "()V", null, null);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "p1/T", "test0", "()V", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "p1/T", "test1", "()V", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "p1/T", "test2", "()V", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "p1/T", "test3", "()V", false);
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
final byte[] classBytes = cw.toByteArray();
Class<?> invokerClass = UNSAFE.defineAnonymousClass(hostClass, classBytes, new Object[0]);
UNSAFE.ensureClassInitialized(invokerClass);
return invokerClass;
}
public static void main(String[] args) throws Throwable {
Throwable fail = null;
// Anonymous class has the privileges of its host class, so test[0123] should all work.
System.out.println("Injecting from the same package (p1):");
Class<?> p1cls = getAnonClass(T.class, "p1/AnonClass");
try {
p1cls.getMethod("test").invoke(null);
} catch (Throwable ex) {
ex.printStackTrace();
fail = ex; // throw this to make test fail, since subtest failed
}
// Anonymous class has different package name from host class. Should throw
// IllegalArgumentException.
System.out.println("Injecting from the wrong package (p2):");
try {
Class<?> p2cls = getAnonClass(DefineAnon.class, "p2/AnonClass");
p2cls.getMethod("test").invoke(null);
System.out.println("Failed, did not get expected IllegalArgumentException");
} catch (java.lang.IllegalArgumentException e) {
if (e.getMessage().contains("Host class p1/DefineAnon and anonymous class p2/AnonClass")) {
System.out.println("Got expected IllegalArgumentException: " + e.getMessage());
} else {
throw new RuntimeException("Unexpected message: " + e.getMessage());
}
} catch (Throwable ex) {
ex.printStackTrace();
fail = ex; // throw this to make test fail, since subtest failed
}
// Inject a class in the unnamed package into p1.T. It should be able
// to access all methods in p1.T.
System.out.println("Injecting unnamed package into correct host class:");
try {
Class<?> p3cls = getAnonClass(T.class, "AnonClass");
p3cls.getMethod("test").invoke(null);
} catch (Throwable ex) {
ex.printStackTrace();
fail = ex; // throw this to make test fail, since subtest failed
}
// Try using an array class as the host class. This should throw IllegalArgumentException.
try {
Class<?> p3cls = getAnonClass(String[].class, "AnonClass");
throw new RuntimeException("Expected IllegalArgumentException not thrown");
} catch (IllegalArgumentException ex) {
}
if (fail != null) throw fail; // make test fail, since subtest failed
}
}

View File

@ -1,89 +0,0 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8058575
* @summary Creates an anonymous class inside of an anonymous class.
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
* @run main p.NestedUnsafe
*/
package p;
import java.lang.*;
import jdk.internal.misc.Unsafe;
import jdk.test.lib.compiler.InMemoryJavaCompiler;
// Test that an anonymous class in package 'p' cannot define its own anonymous class
// in another package.
public class NestedUnsafe {
// The String concatenation should create the nested anonymous class.
static byte klassbuf[] = InMemoryJavaCompiler.compile("q.TestClass",
"package q; " +
"public class TestClass { " +
" public static void concat(String one, String two) throws Throwable { " +
" System.out.println(one + two);" +
" } } ");
public static void main(String args[]) throws Exception {
Unsafe unsafe = Unsafe.getUnsafe();
// The anonymous class calls defineAnonymousClass creating a nested anonymous class.
byte klassbuf2[] = InMemoryJavaCompiler.compile("p.TestClass2",
"package p; " +
"import jdk.internal.misc.Unsafe; " +
"public class TestClass2 { " +
" public static void doit() throws Throwable { " +
" Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe(); " +
" Class klass2 = unsafe.defineAnonymousClass(TestClass2.class, p.NestedUnsafe.klassbuf, new Object[0]); " +
" unsafe.ensureClassInitialized(klass2); " +
" Class[] dArgs = new Class[2]; " +
" dArgs[0] = String.class; " +
" dArgs[1] = String.class; " +
" try { " +
" klass2.getMethod(\"concat\", dArgs).invoke(null, \"CC\", \"DD\"); " +
" } catch (Throwable ex) { " +
" throw new RuntimeException(\"Exception: \" + ex.toString()); " +
" } " +
"} } ",
"--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED");
Class klass2 = unsafe.defineAnonymousClass(p.NestedUnsafe.class, klassbuf2, new Object[0]);
try {
klass2.getMethod("doit").invoke(null);
throw new RuntimeException("Expected exception not thrown");
} catch (Throwable ex) {
Throwable iae = ex.getCause();
if (!iae.toString().contains(
"IllegalArgumentException: Host class p/NestedUnsafe and anonymous class q/TestClass")) {
throw new RuntimeException("Exception: " + iae.toString());
}
}
}
}

View File

@ -1,88 +0,0 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8058575
* @summary Creates an anonymous class inside of an anonymous class.
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
* @run main p.NestedUnsafe2
*/
package p;
import java.lang.*;
import jdk.internal.misc.Unsafe;
import jdk.test.lib.compiler.InMemoryJavaCompiler;
// Test that an anonymous class that gets put in its host's package cannot define
// an anonymous class in another package.
public class NestedUnsafe2 {
// The String concatenation should create the nested anonymous class.
public static byte klassbuf[] = InMemoryJavaCompiler.compile("q.TestClass",
"package q; " +
"public class TestClass { " +
" public static void concat(String one, String two) throws Throwable { " +
" System.out.println(one + two);" +
" } } ");
public static void main(String args[]) throws Exception {
Unsafe unsafe = Unsafe.getUnsafe();
// The anonymous class calls defineAnonymousClass creating a nested anonymous class.
byte klassbuf2[] = InMemoryJavaCompiler.compile("TestClass2",
"import jdk.internal.misc.Unsafe; " +
"public class TestClass2 { " +
" public static void doit() throws Throwable { " +
" Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe(); " +
" Class klass2 = unsafe.defineAnonymousClass(TestClass2.class, p.NestedUnsafe2.klassbuf, new Object[0]); " +
" unsafe.ensureClassInitialized(klass2); " +
" Class[] dArgs = new Class[2]; " +
" dArgs[0] = String.class; " +
" dArgs[1] = String.class; " +
" try { " +
" klass2.getMethod(\"concat\", dArgs).invoke(null, \"CC\", \"DD\"); " +
" } catch (Throwable ex) { " +
" throw new RuntimeException(\"Exception: \" + ex.toString()); " +
" } " +
"} } ",
"--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED");
Class klass2 = unsafe.defineAnonymousClass(p.NestedUnsafe2.class, klassbuf2, new Object[0]);
try {
klass2.getMethod("doit").invoke(null);
throw new RuntimeException("Expected exception not thrown");
} catch (Throwable ex) {
Throwable iae = ex.getCause();
if (!iae.toString().contains(
"IllegalArgumentException: Host class p/NestedUnsafe2 and anonymous class q/TestClass")) {
throw new RuntimeException("Exception: " + iae.toString());
}
}
}
}

View File

@ -1,77 +0,0 @@
/*
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test TestAnonSymbolLeak
* @bug 8218755
* @requires vm.opt.final.ClassUnloading
* @modules java.base/jdk.internal.misc
* java.base/jdk.internal.org.objectweb.asm
* java.management
* @library /test/lib
* @build p1.AnonSymbolLeak
* @build sun.hotspot.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -Xlog:class+unload -XX:+WhiteBoxAPI TestAnonSymbolLeak
*/
import java.lang.reflect.Method;
import sun.hotspot.WhiteBox;
import jdk.test.lib.Asserts;
import jdk.test.lib.classloader.ClassUnloadCommon;
public class TestAnonSymbolLeak {
static String className = "p1.AnonSymbolLeak";
private static class ClassUnloadTestMain {
public static void test() throws Exception {
// Load the AnonSymbolLeak class in a new class loader, run it, which loads
// an unsafe anonymous class in the same package p1. Then unload it.
// Then test that the refcount of the symbol created for the prepended name doesn't leak.
ClassLoader cl = ClassUnloadCommon.newClassLoader();
Class<?> c = cl.loadClass(className);
c.getMethod("test").invoke(null);
cl = null; c = null;
ClassUnloadCommon.triggerUnloading();
}
}
public static WhiteBox wb = WhiteBox.getWhiteBox();
public static void main(String... args) throws Exception {
String oldName = "AnonClass";
String prependedName = "p1/AnonClass";
ClassUnloadCommon.failIf(wb.isClassAlive(className), "should not be loaded");
int countBeforeOld = wb.getSymbolRefcount(oldName);
int countBefore = wb.getSymbolRefcount(prependedName);
ClassUnloadTestMain.test();
ClassUnloadCommon.failIf(wb.isClassAlive(className), "should be unloaded");
int countAfterOld = wb.getSymbolRefcount(oldName);
int countAfter = wb.getSymbolRefcount(prependedName);
Asserts.assertEquals(countBeforeOld, countAfterOld); // no leaks to the old name
System.out.println("count before and after " + countBeforeOld + " " + countAfterOld);
Asserts.assertEquals(countBefore, countAfter); // no leaks to the prepended name
System.out.println("count before and after " + countBefore + " " + countAfter);
}
}

View File

@ -1,175 +0,0 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8200261
* @summary Tests an anonymous class that implements interfaces with default methods.
* @library /testlibrary
* @modules java.base/jdk.internal.org.objectweb.asm
* java.management
* java.base/jdk.internal.misc
* @compile -XDignore.symbol.file=true UnsafeDefMeths.java
* @run main UnsafeDefMeths
*/
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.misc.Unsafe;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER;
import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN;
import static jdk.internal.org.objectweb.asm.Opcodes.DUP;
import static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD;
import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
import static jdk.internal.org.objectweb.asm.Opcodes.V1_8;
public class UnsafeDefMeths {
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
interface Resource {
Pointer ptr();
}
interface Struct extends Resource {
StructPointer ptr();
}
interface Pointer { }
interface StructPointer extends Pointer { }
interface I extends Struct {
void m();
}
static String IMPL_PREFIX = "$$impl";
static String PTR_FIELD_NAME = "ptr";
public static void main(String[] args) throws Throwable {
byte[] bytes = new UnsafeDefMeths().generate(I.class);
Class<?> cl = UNSAFE.defineAnonymousClass(I.class, bytes, new Object[0]);
I i = (I)cl.getConstructors()[0].newInstance(new Object[] { null }); //exception here!
}
// Generate a class similar to:
//
// public class UnsafeDefMeths$I$$impl implements UnsafeDefMeths$I, UnsafeDefMeths$Struct {
//
// public UnsafeDefMeths$StructPointer ptr;
//
// public UnsafeDefMeths$I$$impl(UnsafeDefMeths$StructPointer p) {
// ptr = p;
// }
//
// public UnsafeDefMeths$StructPointer ptr() {
// return ptr;
// }
// }
//
byte[] generate(Class<?> iface) {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
String ifaceTypeName = Type.getInternalName(iface);
String proxyClassName = ifaceTypeName + IMPL_PREFIX;
// class definition
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, proxyClassName,
desc(Object.class) + desc(ifaceTypeName) + desc(Struct.class),
name(Object.class),
new String[] { ifaceTypeName, name(Struct.class) });
cw.visitField(ACC_PUBLIC, PTR_FIELD_NAME, desc(StructPointer.class), desc(StructPointer.class), null);
cw.visitEnd();
// constructor
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>",
meth(desc(void.class), desc(StructPointer.class)),
meth(desc(void.class), desc(StructPointer.class)), null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, name(Object.class), "<init>", meth(desc(void.class)), false);
mv.visitVarInsn(ALOAD, 1);
// Execution of this PUTFIELD instruction causes the bug's ClassNotFoundException.
mv.visitFieldInsn(PUTFIELD, proxyClassName, PTR_FIELD_NAME, desc(StructPointer.class));
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
// ptr() impl
mv = cw.visitMethod(ACC_PUBLIC, PTR_FIELD_NAME, meth(desc(StructPointer.class)),
meth(desc(StructPointer.class)), null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, proxyClassName, PTR_FIELD_NAME, desc(StructPointer.class));
mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
return cw.toByteArray();
}
String name(Class<?> clazz) {
if (clazz.isPrimitive()) {
throw new IllegalStateException();
} else if (clazz.isArray()) {
return desc(clazz);
} else {
return clazz.getName().replaceAll("\\.", "/");
}
}
String desc(Class<?> clazz) {
String mdesc = MethodType.methodType(clazz).toMethodDescriptorString();
return mdesc.substring(mdesc.indexOf(')') + 1);
}
String desc(String clazzName) {
return "L" + clazzName + ";";
}
String gen(String clazz, String... typeargs) {
return clazz.substring(0, clazz.length() - 1) + Stream.of(typeargs).collect(Collectors.joining("", "<", ">")) + ";";
}
String meth(String restype, String... argtypes) {
return Stream.of(argtypes).collect(Collectors.joining("", "(", ")")) + restype;
}
String meth(Method m) {
return MethodType.methodType(m.getReturnType(), m.getParameterTypes()).toMethodDescriptorString();
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -54,14 +54,12 @@ import java.util.Iterator;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import jdk.internal.misc.Unsafe;
public class ClassLoaderStatsTest { public class ClassLoaderStatsTest {
// Expected output from VM.classloader_stats: // Expected output from VM.classloader_stats:
// ClassLoader Parent CLD* Classes ChunkSz BlockSz Type // ClassLoader Parent CLD* Classes ChunkSz BlockSz Type
// 0x0000000800bd3830 0x000000080037f468 0x00007f001c2ea170 1 10240 4672 ClassLoaderStatsTest$DummyClassLoader // 0x0000000800bd3830 0x000000080037f468 0x00007f001c2ea170 1 10240 4672 ClassLoaderStatsTest$DummyClassLoader
// 2 2048 1088 + hidden classes // 1 256 131 + hidden classes
// 0x0000000000000000 0x0000000000000000 0x00007f00e852d190 1607 4628480 3931216 <boot class loader> // 0x0000000000000000 0x0000000000000000 0x00007f00e852d190 1607 4628480 3931216 <boot class loader>
// 38 124928 85856 + hidden classes // 38 124928 85856 + hidden classes
// 0x00000008003b5508 0x0000000000000000 0x00007f001c2d4760 1 6144 4040 jdk.internal.reflect.DelegatingClassLoader // 0x00000008003b5508 0x0000000000000000 0x00007f001c2d4760 1 6144 4040 jdk.internal.reflect.DelegatingClassLoader
@ -104,9 +102,8 @@ public class ClassLoaderStatsTest {
} }
Matcher m2 = hiddenLine.matcher(next); Matcher m2 = hiddenLine.matcher(next);
m2.matches(); m2.matches();
if (!m2.group(1).equals("2")) { if (!m2.group(1).equals("1")) {
// anonymous classes are included in the hidden classes count. Assert.fail("Should have loaded 1 hidden class, but found : " + m2.group(1));
Assert.fail("Should have loaded 2 hidden classes, but found : " + m2.group(1));
} }
checkPositiveInt(m2.group(2)); checkPositiveInt(m2.group(2));
checkPositiveInt(m2.group(3)); checkPositiveInt(m2.group(3));
@ -123,8 +120,6 @@ public class ClassLoaderStatsTest {
public static class DummyClassLoader extends ClassLoader { public static class DummyClassLoader extends ClassLoader {
public static final String CLASS_NAME = "TestClass";
static ByteBuffer readClassFile(String name) static ByteBuffer readClassFile(String name)
{ {
File f = new File(System.getProperty("test.classes", "."), name); File f = new File(System.getProperty("test.classes", "."), name);
@ -177,14 +172,12 @@ class HiddenClass { }
class TestClass { class TestClass {
private static final String HCName = "HiddenClass.class"; private static final String HCName = "HiddenClass.class";
private static final String DIR = System.getProperty("test.classes"); private static final String DIR = System.getProperty("test.classes");
static Unsafe unsafe = Unsafe.getUnsafe();
static { static {
try { try {
// Create a hidden non-strong class and an anonymous class. // Create a hidden non-strong class
byte[] klassBuf = readClassFile(DIR + File.separator + HCName); byte[] klassBuf = readClassFile(DIR + File.separator + HCName);
Class<?> hc = defineHiddenClass(klassBuf); Class<?> hc = defineHiddenClass(klassBuf);
Class ac = unsafe.defineAnonymousClass(TestClass.class, klassBuf, new Object[0]);
} catch (Throwable e) { } catch (Throwable e) {
throw new RuntimeException("Unexpected exception in TestClass: " + e.getMessage()); throw new RuntimeException("Unexpected exception in TestClass: " + e.getMessage());
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -66,7 +66,6 @@ public class TestIntConstant {
"CollectedHeap::G1 3", "CollectedHeap::G1 3",
"RUNNABLE 2", "RUNNABLE 2",
"Deoptimization::Reason_class_check 4", "Deoptimization::Reason_class_check 4",
"InstanceKlass::_misc_is_unsafe_anonymous 8",
"_thread_uninitialized 0")); "_thread_uninitialized 0"));
expStrMap.put("intConstant _temp_constant", List.of( expStrMap.put("intConstant _temp_constant", List.of(
"intConstant _temp_constant 45")); "intConstant _temp_constant 45"));

View File

@ -1,4 +1,4 @@
Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
This code is free software; you can redistribute it and/or modify it This code is free software; you can redistribute it and/or modify it
@ -50,7 +50,7 @@ keep classloader alive.
"plain", "plain",
"reflection", "reflection",
"jni", "jni",
"anonymous_classloader". "hidden_classloader".
- classloaders that we expect to live can be referenced in several ways. - classloaders that we expect to live can be referenced in several ways.
This behavior can be adjusted with flag "-keepRefMode" that has valid options: This behavior can be adjusted with flag "-keepRefMode" that has valid options:
"strong_reference" for starighforward keeping strong reference, "strong_reference" for starighforward keeping strong reference,

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -24,6 +24,6 @@ package gc.g1.unloading.configuration;
public enum ClassloadingMethod { public enum ClassloadingMethod {
PLAIN, REFLECTION, JNI, ANONYMOUS_CLASSLOADER PLAIN, REFLECTION, JNI, HIDDEN_CLASSLOADER
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -24,7 +24,6 @@ package gc.g1.unloading.loading;
import gc.g1.unloading.ExecutionTask; import gc.g1.unloading.ExecutionTask;
import gc.g1.unloading.bytecode.*; import gc.g1.unloading.bytecode.*;
//import gc.g1.unloading.check.*;
import gc.g1.unloading.check.Assertion; import gc.g1.unloading.check.Assertion;
import gc.g1.unloading.check.ClassAssertion; import gc.g1.unloading.check.ClassAssertion;
import gc.g1.unloading.check.PhantomizedAssertion; import gc.g1.unloading.check.PhantomizedAssertion;
@ -42,7 +41,9 @@ import gc.g1.unloading.configuration.TestConfiguration;
import gc.g1.unloading.keepref.*; import gc.g1.unloading.keepref.*;
import nsk.share.test.ExecutionController; import nsk.share.test.ExecutionController;
import sun.hotspot.WhiteBox; import sun.hotspot.WhiteBox;
import jdk.internal.misc.Unsafe;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.ref.*; import java.lang.ref.*;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@ -71,6 +72,10 @@ public class ClassLoadingHelper {
private TestConfiguration configuration; private TestConfiguration configuration;
// This should be TRUE for bytecode generators that use ASM to create the bytecodes
// instead of creating Java source and then compiling with InMemoryJavaCompiler.
private boolean prepend_package = true;
/** /**
* Constructor that creates instance of helper. All arguments are self-explaining. * Constructor that creates instance of helper. All arguments are self-explaining.
* @param executionController * @param executionController
@ -89,6 +94,7 @@ public class ClassLoadingHelper {
thread.start(); thread.start();
if (configuration.isInMemoryCompilation() && !configuration.isHumongousClass() && !(configuration.getKeepRefMode() == KeepRefMode.THREAD_ITSELF)) { if (configuration.isInMemoryCompilation() && !configuration.isHumongousClass() && !(configuration.getKeepRefMode() == KeepRefMode.THREAD_ITSELF)) {
prepend_package = false;
bf = new BytecodeGeneratorFactory(random.nextLong()); bf = new BytecodeGeneratorFactory(random.nextLong());
} else { } else {
if (configuration.isHumongousClass()) { if (configuration.isHumongousClass()) {
@ -107,7 +113,11 @@ public class ClassLoadingHelper {
* @return * @return
*/ */
public Collection<Assertion> loadClassThatGonnaLive(String className_) { public Collection<Assertion> loadClassThatGonnaLive(String className_) {
Bytecode kit = bf.createBytecode(className_); // if generating the bytecodes using ASM then prepend the package name to
// the classname so that, when created as a hidden class, it will be in the
// same package as its lookup class.
Bytecode kit = bf.createBytecode(prepend_package ?
"gc.g1.unloading.loading." + className_ : className_);
String className = kit.getClassName(); String className = kit.getClassName();
byte[] bytecode = kit.getBytecode(); byte[] bytecode = kit.getBytecode();
Class<?> clazz = loadClass(className, bytecode); Class<?> clazz = loadClass(className, bytecode);
@ -118,12 +128,8 @@ public class ClassLoadingHelper {
warmUpClassIfNeeded(object); warmUpClassIfNeeded(object);
Assertion assertion; Assertion assertion;
// The JVM prepends the host class's package to the anonymous class name.
if (configuration.getClassloadingMethod() != ClassloadingMethod.ANONYMOUS_CLASSLOADER) {
assertion = new ClassAssertion(className, true); assertion = new ClassAssertion(className, true);
} else {
assertion = new ClassAssertion("gc/g1/unloading/loading/" + className, true);
}
switch (configuration.getKeepRefMode()) { switch (configuration.getKeepRefMode()) {
case STRONG_REFERENCE: case STRONG_REFERENCE:
assertion.keepLink(referenceToKeep); assertion.keepLink(referenceToKeep);
@ -178,7 +184,11 @@ public class ClassLoadingHelper {
*/ */
public Collection<Assertion> loadClassThatGonnaDie(String className_) { public Collection<Assertion> loadClassThatGonnaDie(String className_) {
Collection<Assertion> returnValue = new LinkedList<>(); Collection<Assertion> returnValue = new LinkedList<>();
Bytecode kit = bf.createBytecode(className_); // if generating the bytecodes using ASM then prepend the package name to
// the classname so that, when created as a hidden class, it will be in the
// same package as its lookup class.
Bytecode kit = bf.createBytecode(prepend_package ?
"gc.g1.unloading.loading." + className_ : className_);
String className = kit.getClassName(); String className = kit.getClassName();
byte[] bytecode = kit.getBytecode(); byte[] bytecode = kit.getBytecode();
Class<?> clazz = loadClass(className, bytecode); Class<?> clazz = loadClass(className, bytecode);
@ -193,12 +203,7 @@ public class ClassLoadingHelper {
warmUpClassIfNeeded(object); warmUpClassIfNeeded(object);
Assertion assertion; Assertion assertion;
// The JVM prepends the host class's package to the anonymous class name.
if (configuration.getClassloadingMethod() != ClassloadingMethod.ANONYMOUS_CLASSLOADER) {
assertion = new ClassAssertion(className, false); assertion = new ClassAssertion(className, false);
} else {
assertion = new ClassAssertion("gc/g1/unloading/loading/" + className, false);
}
switch (configuration.getReleaseRefMode()) { switch (configuration.getReleaseRefMode()) {
case WEAK: case WEAK:
assertion.keepLink(new WeakReference<Object>(referenceToKeep)); assertion.keepLink(new WeakReference<Object>(referenceToKeep));
@ -246,11 +251,12 @@ public class ClassLoadingHelper {
return Class.forName(className, true, new ReflectionClassloader(bytecode, className)); return Class.forName(className, true, new ReflectionClassloader(bytecode, className));
case JNI: case JNI:
return JNIClassloader.loadThroughJNI(className, bytecode); return JNIClassloader.loadThroughJNI(className, bytecode);
case ANONYMOUS_CLASSLOADER: case HIDDEN_CLASSLOADER:
return getUnsafe().defineAnonymousClass(ClassLoadingHelper.class, bytecode, NO_CP_PATCHES); Lookup lookup = MethodHandles.lookup();
return lookup.defineHiddenClass(bytecode, true).lookupClass();
} }
return null; return null;
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException | IllegalAccessException e) {
throw new RuntimeException("Test bug!", e); throw new RuntimeException("Test bug!", e);
} }
} }
@ -324,10 +330,6 @@ public class ClassLoadingHelper {
} }
} }
private static Unsafe getUnsafe() {
return Unsafe.getUnsafe();
}
} }
class ReferenceCleaningThread extends ExecutionTask { class ReferenceCleaningThread extends ExecutionTask {

View File

@ -52,7 +52,7 @@
* -Xlog:gc:gc.log * -Xlog:gc:gc.log
* -XX:-UseGCOverheadLimit * -XX:-UseGCOverheadLimit
* gc.g1.unloading.UnloadingTest * gc.g1.unloading.UnloadingTest
* -classloadingMethod anonymous_classloader * -classloadingMethod hidden_classloader
* -inMemoryCompilation * -inMemoryCompilation
* -keep class * -keep class
* -numberOfChecksLimit 4 * -numberOfChecksLimit 4

View File

@ -52,7 +52,7 @@
* -Xlog:gc:gc.log * -Xlog:gc:gc.log
* -XX:-UseGCOverheadLimit * -XX:-UseGCOverheadLimit
* gc.g1.unloading.UnloadingTest * gc.g1.unloading.UnloadingTest
* -classloadingMethod anonymous_classloader * -classloadingMethod hidden_classloader
* -inMemoryCompilation * -inMemoryCompilation
* -keep object * -keep object
* -numberOfChecksLimit 4 * -numberOfChecksLimit 4

View File

@ -52,7 +52,7 @@
* -Xlog:gc:gc.log * -Xlog:gc:gc.log
* -XX:-UseGCOverheadLimit * -XX:-UseGCOverheadLimit
* gc.g1.unloading.UnloadingTest * gc.g1.unloading.UnloadingTest
* -classloadingMethod anonymous_classloader * -classloadingMethod hidden_classloader
* -keep class * -keep class
* -numberOfChecksLimit 4 * -numberOfChecksLimit 4
* -stressTime 180 * -stressTime 180

View File

@ -52,7 +52,7 @@
* -Xlog:gc:gc.log * -Xlog:gc:gc.log
* -XX:-UseGCOverheadLimit * -XX:-UseGCOverheadLimit
* gc.g1.unloading.UnloadingTest * gc.g1.unloading.UnloadingTest
* -classloadingMethod anonymous_classloader * -classloadingMethod hidden_classloader
* -keep object * -keep object
* -numberOfChecksLimit 4 * -numberOfChecksLimit 4
* -stressTime 180 * -stressTime 180

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -20,8 +20,6 @@
* or visit www.oracle.com if you need additional information or have any * or visit www.oracle.com if you need additional information or have any
* questions. * questions.
*/ */
package metaspace.staticReferences;
public class OneUsageClassloader extends ClassLoader { public class OneUsageClassloader extends ClassLoader {

View File

@ -38,11 +38,11 @@
* -Xbootclasspath/a:. * -Xbootclasspath/a:.
* -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI * -XX:+WhiteBoxAPI
* metaspace.staticReferences.StaticReferences * StaticReferences
*/ */
package metaspace.staticReferences; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.lang.ref.Reference; import java.lang.ref.Reference;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@ -59,13 +59,12 @@ import nsk.share.test.ExecutionController;
import nsk.share.test.Stresser; import nsk.share.test.Stresser;
import nsk.share.test.TestBase; import nsk.share.test.TestBase;
import nsk.share.test.Tests; import nsk.share.test.Tests;
import jdk.internal.misc.Unsafe;
import vm.share.gc.TriggerUnloadingHelper; import vm.share.gc.TriggerUnloadingHelper;
import vm.share.gc.TriggerUnloadingWithWhiteBox; import vm.share.gc.TriggerUnloadingWithWhiteBox;
/** /**
* Test checks that static fields will be initialized in new loaded class. Test performs in loop the following routine: * Test checks that static fields will be initialized in new loaded class. Test performs in loop the following routine:
* 1.) Load class either by regular classloader or by Unsafe.defineAnonymousClass. * 1.) Load class either by regular classloader or by defineHiddenClass.
* 2.) Trigger unloading. Class must be alive. Next step will check that static fields were not lost. * 2.) Trigger unloading. Class must be alive. Next step will check that static fields were not lost.
* 3.) Change static fields. * 3.) Change static fields.
* 4.) Unload class. * 4.) Unload class.
@ -96,10 +95,6 @@ public class StaticReferences extends GCTestBase {
Tests.runTest(new StaticReferences(), args); Tests.runTest(new StaticReferences(), args);
} }
private static Unsafe getUnsafe() {
return Unsafe.getUnsafe();
}
@Override @Override
public void run() { public void run() {
random = new Random(runParams.getSeed()); random = new Random(runParams.getSeed());
@ -123,10 +118,10 @@ public class StaticReferences extends GCTestBase {
// Core of test // Core of test
for (byte[] classBytecode : bytecodeList) { for (byte[] classBytecode : bytecodeList) {
boolean anonymous = random.nextBoolean(); boolean hidden = random.nextBoolean();
log.info("Load class first time"); log.info("Load class first time");
Class clazz = loadClass(classBytecode, anonymous); Class clazz = loadClass(classBytecode, hidden);
log.info("Trigger unloading"); log.info("Trigger unloading");
triggerUnloadingHelper.triggerUnloading(stresser); triggerUnloadingHelper.triggerUnloading(stresser);
@ -155,7 +150,7 @@ public class StaticReferences extends GCTestBase {
} }
log.info("Load class second time"); log.info("Load class second time");
clazz = loadClass(classBytecode, anonymous); clazz = loadClass(classBytecode, hidden);
log.info("check fields reinitialized"); log.info("check fields reinitialized");
checkStaticFields(clazz); checkStaticFields(clazz);
@ -164,11 +159,17 @@ public class StaticReferences extends GCTestBase {
} }
} }
private Class loadClass(byte[] classBytecode, private Class loadClass(byte[] classBytecode, boolean hidden) {
boolean anonymous) {
Class clazz; Class clazz;
if (anonymous) { if (hidden) {
clazz = getUnsafe().defineAnonymousClass(StaticReferences.class, classBytecode, NO_CP_PATCHES); Lookup lookup = MethodHandles.lookup();
try {
clazz = lookup.defineHiddenClass(classBytecode, false).lookupClass();
} catch (IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException(
"Lookup.defineHiddenClass failed: " + e.getMessage());
}
} else { } else {
OneUsageClassloader classloader = new OneUsageClassloader(); OneUsageClassloader classloader = new OneUsageClassloader();
clazz = classloader.define(classBytecode); clazz = classloader.define(classBytecode);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -22,10 +22,11 @@
*/ */
package vm.compiler.coverage.parentheses.share; package vm.compiler.coverage.parentheses.share;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.misc.Unsafe;
import static jdk.internal.org.objectweb.asm.Opcodes.*; import static jdk.internal.org.objectweb.asm.Opcodes.*;
@ -35,7 +36,7 @@ import java.util.List;
/** /**
* This class convert instructions sequence to java class file, load it to same JVM and then execute. * This class convert instructions sequence to java class file, load it to same JVM and then execute.
* This class uses Unsafe.defineAnonymousClass for class loading * This class uses hidden classes for class loading
*/ */
public class HotspotInstructionsExecutor implements InstructionsExecutor { public class HotspotInstructionsExecutor implements InstructionsExecutor {
@ -54,8 +55,9 @@ public class HotspotInstructionsExecutor implements InstructionsExecutor {
return (Integer) execMethod.invoke(null); return (Integer) execMethod.invoke(null);
} }
private Class generateClass(List<Instruction> instructions) throws ClassNotFoundException { private Class generateClass(List<Instruction> instructions) throws ReflectiveOperationException {
String classNameForASM = "ExecClass"; // Needs to be in the same package as the lookup class.
String classNameForASM = "vm/compiler/coverage/parentheses/share/ExecClass";
ClassWriter cw = new ClassWriter(0); ClassWriter cw = new ClassWriter(0);
cw.visit(V1_1, ACC_PUBLIC, classNameForASM, null, "java/lang/Object", null); cw.visit(V1_1, ACC_PUBLIC, classNameForASM, null, "java/lang/Object", null);
@ -71,10 +73,8 @@ public class HotspotInstructionsExecutor implements InstructionsExecutor {
mw.visitMaxs(stackSize, 2); mw.visitMaxs(stackSize, 2);
mw.visitEnd(); mw.visitEnd();
return getUnsafe().defineAnonymousClass(ClassWriter.class, cw.toByteArray(), NO_CP_PATCHES); Lookup lookup = MethodHandles.lookup();
} Class<?> hc = lookup.defineHiddenClass(cw.toByteArray(), false).lookupClass();
return hc;
private static Unsafe getUnsafe() {
return Unsafe.getUnsafe();
} }
} }

View File

@ -1,78 +0,0 @@
/*
* Copyright (c) 2010, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @key randomness
* @modules java.base/jdk.internal.misc
*
* @summary converted from VM Testbase vm/mlvm/anonloader/func/castToGrandparent.
* VM Testbase keywords: [feature_mlvm]
* VM Testbase readme:
* DESCRIPTION
* Cast an object loaded with Unsafe.defineAnonymousClass to superclass of its parent class. This cast should succeed.
*
* @library /vmTestbase
* /test/lib
*
* @comment build test class and indify classes
* @build vm.mlvm.anonloader.func.castToGrandparent.Test
* @run driver vm.mlvm.share.IndifiedClassesBuilder
*
* @run main/othervm vm.mlvm.anonloader.func.castToGrandparent.Test
*/
package vm.mlvm.anonloader.func.castToGrandparent;
import vm.mlvm.anonloader.share.AnonkTestee01;
import vm.mlvm.anonloader.share.AnonkTestee02;
import vm.mlvm.share.Env;
import vm.mlvm.share.MlvmTest;
import vm.share.FileUtils;
import vm.share.UnsafeAccess;
public class Test extends MlvmTest {
private static final Class<?> PARENT = AnonkTestee02.class;
@Override
public boolean run() throws Exception {
byte[] classBytes = FileUtils.readClass(PARENT.getName());
Class<?> cls = UnsafeAccess.unsafe.defineAnonymousClass(
PARENT, classBytes, null);
Object anonObject = cls.newInstance();
// Try to cast anonymous class to its grandparent
AnonkTestee01 anonCastToParent = (AnonkTestee01) anonObject;
if ( anonCastToParent.equals(anonObject) )
Env.traceNormal("Anonymous object can be cast to original one");
// Try to cast using another method
new AnonkTestee01().getClass().cast(anonObject);
Env.traceNormal("Anonymous class can be cast to original one");
return true;
}
public static void main(String[] args) { MlvmTest.launch(args); }
}

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