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
if (bc_raw == Bytecodes::_invokespecial && !target->is_object_initializer()) {
ciInstanceKlass* sender_klass =
calling_klass->is_unsafe_anonymous() ? calling_klass->unsafe_anonymous_host() :
calling_klass;
ciInstanceKlass* sender_klass = calling_klass;
if (sender_klass->is_interface()) {
int index = state()->stack_size() - (target->arg_size_no_receiver() + 1);
Value receiver = state()->stack_at(index);

View File

@ -641,15 +641,11 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool,
} else if (tag.is_string()) {
oop string = NULL;
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);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
record_out_of_memory_failure();
return ciConstant();
}
string = cpool->string_at(index, cache_index, THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
record_out_of_memory_failure();
return ciConstant();
}
ciObject* constant = get_object(string);
if (constant->is_array()) {

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("java/lang"))
return true;
// Trust hidden classes and VM unsafe anonymous classes. They are created via
// Lookup.defineHiddenClass or the private jdk.internal.misc.Unsafe API and
// Trust hidden classes. They are created via Lookup.defineHiddenClass and
// 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;
// Trust final fields in all boxed classes
if (holder->is_box_klass())

View File

@ -66,7 +66,6 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) :
_nonstatic_field_size = ik->nonstatic_field_size();
_has_nonstatic_fields = ik->has_nonstatic_fields();
_has_nonstatic_concrete_methods = ik->has_nonstatic_concrete_methods();
_is_unsafe_anonymous = ik->is_unsafe_anonymous();
_is_hidden = ik->is_hidden();
_is_record = ik->is_record();
_nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields:
@ -81,11 +80,11 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) :
oop holder = ik->klass_holder();
if (ik->class_loader_data()->has_class_mirror_holder()) {
// 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
// during ciObjectFactory lifetime. ciObjectFactory itself is created for
// 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);
}
@ -128,7 +127,6 @@ ciInstanceKlass::ciInstanceKlass(ciSymbol* name,
_has_nonstatic_fields = false;
_nonstatic_fields = NULL;
_has_injected_fields = -1;
_is_unsafe_anonymous = false;
_is_hidden = false;
_is_record = false;
_loader = loader;
@ -660,16 +658,6 @@ ciInstanceKlass* ciInstanceKlass::implementor() {
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
// use by compilation replay. It only prints out the information that
// 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
Klass* sub = ik->subklass();
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());
}
sub = sub->next_sibling();

View File

@ -56,7 +56,6 @@ private:
SubklassValue _has_subklass;
bool _has_nonstatic_fields;
bool _has_nonstatic_concrete_methods;
bool _is_unsafe_anonymous;
bool _is_hidden;
bool _is_record;
@ -194,10 +193,6 @@ public:
return _has_nonstatic_concrete_methods;
}
bool is_unsafe_anonymous() const {
return _is_unsafe_anonymous;
}
bool is_hidden() const {
return _is_hidden;
}
@ -290,8 +285,6 @@ public:
return NULL;
}
ciInstanceKlass* unsafe_anonymous_host();
bool can_be_instantiated() {
assert(is_loaded(), "must be loaded");
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);
}
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;
Symbol* const result = SymbolTable::lookup_only((const char*)utf8_buffer,
utf8_length,
@ -616,37 +604,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
} // switch(tag)
} // end of for
_first_patched_klass_resolved_index = num_klasses;
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);
}
}
}
cp->allocate_resolved_klasses(_loader_data, num_klasses, CHECK);
if (!_need_verify) {
return;
@ -659,7 +617,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
switch (tag) {
case JVM_CONSTANT_UnresolvedClass: {
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);
break;
}
@ -799,88 +757,6 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
} // 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 {
public:
const Symbol* _name; // name
@ -5429,11 +5305,11 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
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
// hidden or anonymous class itself. If this class needs to refer to its own
// methods or fields, it would use a CONSTANT_MethodRef, etc, which would reference
// _this_class_index. However, because this class is hidden or anonymous (it's
// hidden class itself. If this class needs to refer to its own methods
// or fields, it would use a CONSTANT_MethodRef, etc, which would reference
// _this_class_index. However, because this class is hidden (it's
// not stored in SystemDictionary), _this_class_index cannot be resolved
// with ConstantPool::klass_at_impl, which does a SystemDictionary lookup.
// Therefore, we must eagerly resolve _this_class_index now.
@ -5445,10 +5321,6 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
ik->set_has_nonstatic_concrete_methods(_has_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) {
ik->set_is_hidden();
}
@ -5614,57 +5486,6 @@ void ClassFileParser::update_class_name(Symbol* new_class_name) {
_class_name->increment_refcount();
}
// For an unsafe anonymous class that is in the unnamed package, move it to its host class's
// package by prepending its host class's package name to its class name and setting
// its _class_name field.
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) {
bool trusted = loader_data->is_boot_class_loader_data() ||
loader_data->is_platform_class_loader_data();
@ -5685,14 +5506,9 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_stream(stream),
_class_name(NULL),
_loader_data(loader_data),
_unsafe_anonymous_host(cl_info->unsafe_anonymous_host()),
_cp_patches(cl_info->cp_patches()),
_is_hidden(cl_info->is_hidden()),
_can_access_vm_annotations(cl_info->can_access_vm_annotations()),
_num_patched_klasses(0),
_max_num_patched_klasses(0),
_orig_cp_size(0),
_first_patched_klass_resolved_index(0),
_super_klass(),
_cp(NULL),
_fields(NULL),
@ -5769,25 +5585,6 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_need_verify = Verifier::should_verify_for(_loader_data->class_loader(),
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
stream->set_verify(_need_verify);
@ -5917,13 +5714,7 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
_orig_cp_size = cp_size;
if (is_hidden()) { // Add a slot for hidden class name.
assert(_max_num_patched_klasses == 0, "Sanity check");
cp_size++;
} else {
if (int(cp_size) + _max_num_patched_klasses > 0xffff) {
THROW_MSG(vmSymbols::java_lang_InternalError(), "not enough space for patched classes");
}
cp_size += _max_num_patched_klasses;
}
_cp = ConstantPool::allocate(_loader_data,
@ -5987,18 +5778,12 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
#ifdef ASSERT
// Basic sanity checks
assert(!(_is_hidden && (_unsafe_anonymous_host != NULL)), "mutually exclusive variants");
if (_unsafe_anonymous_host != NULL) {
assert(_class_name == vmSymbols::unknown_class_name(), "A named anonymous class???");
}
if (_is_hidden) {
assert(_class_name != vmSymbols::unknown_class_name(), "hidden classes should have a special name");
}
#endif
// Update the _class_name as needed depending on whether this is a named,
// un-named, hidden or unsafe-anonymous class.
// Update the _class_name as needed depending on whether this is a named, un-named, or hidden class.
if (_is_hidden) {
assert(_class_name != NULL, "Unexpected null _class_name");
@ -6008,16 +5793,6 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
}
#endif
// NOTE: !_is_hidden does not imply "findable" as it could be an old-style
// "hidden" unsafe-anonymous class
// If this is an anonymous class fix up its name if it is in the unnamed
// package. Otherwise, throw IAE if it is in a different package than
// its host class.
} else if (_unsafe_anonymous_host != NULL) {
update_class_name(class_name_in_cp);
fix_unsafe_anonymous_class_name(CHECK);
} else {
// Check if name in class file matches given name
if (_class_name != class_name_in_cp) {

View File

@ -113,14 +113,9 @@ class ClassFileParser {
const ClassFileStream* _stream; // Actual input stream
Symbol* _class_name;
mutable ClassLoaderData* _loader_data;
const InstanceKlass* _unsafe_anonymous_host;
GrowableArray<Handle>* _cp_patches; // overrides for CP entries
const bool _is_hidden;
const bool _can_access_vm_annotations;
int _num_patched_klasses;
int _max_num_patched_klasses;
int _orig_cp_size;
int _first_patched_klass_resolved_index;
// Metadata created before the instance klass is created. Must be deallocated
// if not transferred to the InstanceKlass upon successful class loading
@ -211,9 +206,6 @@ class ClassFileParser {
ConstantPool* cp,
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,
const ClassInstanceInfo& cl_inst_info, TRAPS);
@ -494,26 +486,6 @@ class ClassFileParser {
unsigned int length,
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.
// In older versions of the VM, Klass*s cannot sneak into early phases of
// constant pool construction, but in later versions they can.
@ -582,12 +554,9 @@ class ClassFileParser {
u2 this_class_index() const { return _this_class_index; }
bool is_unsafe_anonymous() const { return _unsafe_anonymous_host != NULL; }
bool is_hidden() const { return _is_hidden; }
bool is_interface() const { return _access_flags.is_interface(); }
const InstanceKlass* unsafe_anonymous_host() const { return _unsafe_anonymous_host; }
const GrowableArray<Handle>* cp_patches() const { return _cp_patches; }
ClassLoaderData* loader_data() const { return _loader_data; }
const Symbol* class_name() const { return _class_name; }
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.
*
* 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 {
private:
Handle _protection_domain;
const InstanceKlass* _unsafe_anonymous_host;
GrowableArray<Handle>* _cp_patches;
ClassInstanceInfo _class_hidden_info;
bool _is_hidden;
bool _is_strong_hidden;
@ -64,8 +62,6 @@ class ClassLoadInfo : public StackObj {
public:
ClassLoadInfo(Handle protection_domain) {
_protection_domain = protection_domain;
_unsafe_anonymous_host = NULL;
_cp_patches = NULL;
_class_hidden_info._dynamic_nest_host = NULL;
_class_hidden_info._class_data = Handle();
_is_hidden = false;
@ -73,13 +69,10 @@ class ClassLoadInfo : public StackObj {
_can_access_vm_annotations = false;
}
ClassLoadInfo(Handle protection_domain, const InstanceKlass* unsafe_anonymous_host,
GrowableArray<Handle>* cp_patches, InstanceKlass* dynamic_nest_host,
ClassLoadInfo(Handle protection_domain, InstanceKlass* dynamic_nest_host,
Handle class_data, bool is_hidden, bool is_strong_hidden,
bool can_access_vm_annotations) {
_protection_domain = protection_domain;
_unsafe_anonymous_host = unsafe_anonymous_host;
_cp_patches = cp_patches;
_class_hidden_info._dynamic_nest_host = dynamic_nest_host;
_class_hidden_info._class_data = class_data;
_is_hidden = is_hidden;
@ -88,8 +81,6 @@ class ClassLoadInfo : public StackObj {
}
Handle protection_domain() const { return _protection_domain; }
const InstanceKlass* unsafe_anonymous_host() const { return _unsafe_anonymous_host; }
GrowableArray<Handle>* cp_patches() const { return _cp_patches; }
const ClassInstanceInfo* class_hidden_info_ptr() const { return &_class_hidden_info; }
bool is_hidden() const { return _is_hidden; }
bool is_strong_hidden() const { return _is_strong_hidden; }

View File

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

View File

@ -138,8 +138,8 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool has_class_mirror_ho
Mutex::_safepoint_check_never)),
_unloading(false), _has_class_mirror_holder(has_class_mirror_holder),
_modified_oops(true),
// An unsafe anonymous class loader data doesn't have anything to keep
// it from being unloaded during parsing of the unsafe anonymous class.
// A non-strong hidden class loader data doesn't have anything to keep
// it from being unloaded during parsing of the non-strong hidden class.
// The null-class-loader should always be kept alive.
_keep_alive((has_class_mirror_holder || h_class_loader.is_null()) ? 1 : 0),
_claim(0),
@ -157,13 +157,12 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool has_class_mirror_ho
}
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().
initialize_holder(h_class_loader);
// A ClassLoaderData created solely for a non-strong hidden class or unsafe anonymous class should
// never have a ModuleEntryTable or PackageEntryTable created for it. The defining package
// and module for an unsafe anonymous class will be found in its host class.
// A ClassLoaderData created solely for a non-strong hidden class should never
// have a ModuleEntryTable or PackageEntryTable created for it.
_packages = new PackageEntryTable(PackageEntryTable::_packagetable_entry_size);
if (h_class_loader.is_null()) {
// 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.
// Due to the uniqueness that no other class shares the hidden or unsafe anonymous class' name or
// ClassLoaderData, no other non-GC thread has knowledge of the hidden or unsafe anonymous class while
// 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 class while
// it is being defined, therefore _keep_alive is not volatile or atomic.
void ClassLoaderData::inc_keep_alive() {
if (has_class_mirror_holder()) {
@ -426,13 +425,13 @@ void ClassLoaderData::record_dependency(const Klass* k) {
oop to;
if (to_cld->has_class_mirror_holder()) {
// Just return if a non-strong hidden class or unsafe anonymous class is attempting to record a dependency
// to itself. (Note that every non-strong hidden class or unsafe anonymous class has its own unique class
// Just return if a non-strong hidden class class is attempting to record a dependency
// to itself. (Note that every non-strong hidden class has its own unique class
// loader data.)
if (to_cld == from_cld) {
return;
}
// Hidden and unsafe anonymous class dependencies are through the mirror.
// Hidden class dependencies are through the mirror.
to = k->java_mirror();
} else {
to = to_cld->class_loader();
@ -626,7 +625,7 @@ oop ClassLoaderData::holder_no_keepalive() const {
// Unloading support
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.
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
// the 3 builtin (boot application/system or platform) class loaders,
// including a user-defined system class loader. Note that if the class
// loader data is for 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.
bool ClassLoaderData::is_builtin_class_loader_data() const {
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
// 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 {
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.
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
// the CLDs lifecycle. For example, a non-strong hidden class or an
// unsafe anonymous class. Arrays of these classes are also assigned
// the CLDs lifecycle. For example, a non-strong hidden class.
// Arrays of these classes are also assigned
// to these class loader datas.
// Remembered sets support for the oops in the class loader data.
bool _modified_oops; // Card Table Equivalent
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
// atomic since there is one unique CLD per non-strong hidden class
// or unsafe anonymous class.
// atomic since there is one unique CLD per non-strong hidden class.
volatile int _claim; // non-zero if claimed, for example during GC traces.
// 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.
// (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;
// 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;
// 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;
bool is_builtin_class_loader_data() const;
@ -267,8 +266,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
return _unloading;
}
// Used to refcount a non-strong hidden class's or unsafe anonymous class's CLD in order to
// indicate their aliveness.
// Used to refcount a non-strong hidden class's s CLD in order to indicate their aliveness.
void inc_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.
*
* 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
// classes that are allocated but not loaded, classes that have errors, and scratch classes
// for redefinition. These classes are removed during the next class unloading.
// Walking the ClassLoaderDataGraph also includes hidden and unsafe anonymous classes.
// Walking the ClassLoaderDataGraph also includes hidden classes.
static void classes_do(KlassClosure* klass_closure);
static void classes_do(void f(Klass* const));
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).
if (loader_data != NULL) {
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:

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.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -221,7 +221,7 @@ class LoaderTreeNode : public ResourceObj {
if (print_classes) {
if (_classes != NULL) {
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.
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.
*
* 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();
// 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;
ClassLoaderStats* cls = _stats->put_if_absent(cl, &added);
if (added) {
@ -71,7 +71,7 @@ void ClassLoaderStatsClosure::do_cld(ClassLoaderData* cld) {
cld->classes_do(&csc);
bool is_hidden = false;
if(cld->has_class_mirror_holder()) {
// If cld has a class holder then it must be either hidden or unsafe anonymous.
// If cld has a class holder then it must be hidden.
// Either way, count it as a hidden class.
cls->_hidden_classes_count += csc._num_classes;
} else {

View File

@ -921,8 +921,8 @@ static void switchover_constant_pool(BytecodeConstantPool* bpool,
if (new_methods->length() > 0) {
ConstantPool* cp = bpool->create_constant_pool(CHECK);
if (cp != klass->constants()) {
// Copy resolved anonymous class into new constant pool.
if (klass->is_unsafe_anonymous() || klass->is_hidden()) {
// Copy resolved hidden class into new constant pool.
if (klass->is_hidden()) {
cp->klass_at_put(klass->this_class_index(), klass);
}
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();
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.
// This mirror may be different than the one in clazz field.
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.
// 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.
// 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
THREAD->statistical_info().incr_define_class_count();
assert(!(cl_info.is_hidden() && (cl_info.unsafe_anonymous_host() != NULL)),
"hidden class has an anonymous host");
// Skip this processing for VM hidden or anonymous classes
if (!cl_info.is_hidden() && (cl_info.unsafe_anonymous_host() == NULL)) {
// Skip this processing for VM hidden classes
if (!cl_info.is_hidden()) {
stream = check_class_file_load_hook(stream,
name,
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,
int names_count, const char** names, int* lengths,
int* cp_indices, unsigned int* hashValues) {
// Note that c_heap will be true for non-strong hidden classes and unsafe anonymous classes
// 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.
bool c_heap = !loader_data->is_the_null_class_loader_data();
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
// 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(
ClassFileStream* st,
Symbol* class_name,
@ -828,17 +828,12 @@ InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream(
EventClassLoad class_load_start_event;
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
// whose loader is the Lookup class's loader.
// - 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");
guarantee(!is_unsafe_anon_class || cl_info.unsafe_anonymous_host()->class_loader() == class_loader(),
"should be NULL or the same");
bool create_mirror_cld = is_unsafe_anon_class || !cl_info.is_strong_hidden();
assert (cl_info.is_hidden(), "only used for hidden classes");
bool create_mirror_cld = !cl_info.is_strong_hidden();
loader_data = register_loader(class_loader, create_mirror_cld);
assert(st != NULL, "invariant");
@ -852,10 +847,9 @@ InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream(
CHECK_NULL);
assert(k != NULL, "no klass created");
// Hidden classes that are not strong and unsafe anonymous classes must update
// ClassLoaderData holder so that they can be unloaded when the mirror is no
// longer referenced.
if (!cl_info.is_strong_hidden() || is_unsafe_anon_class) {
// Hidden classes that are not strong must update ClassLoaderData holder
// so that they can be unloaded when the mirror is no longer referenced.
if (!cl_info.is_strong_hidden()) {
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.
}
// Rewrite and patch constant pool here.
k->link_class(CHECK_NULL);
if (cl_info.cp_patches() != NULL) {
k->constants()->patch_resolved_references(cl_info.cp_patches());
}
// If it's anonymous, initialize it now, since nobody else will.
if (is_unsafe_anon_class) {
k->eager_initialize(CHECK_NULL);
}
// notify jvmti
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);
}
assert(is_unsafe_anon_class || NULL == cl_info.cp_patches(),
"cp_patches only found with unsafe_anonymous_host");
return k;
}
@ -965,8 +947,7 @@ InstanceKlass* SystemDictionary::resolve_from_stream(ClassFileStream* st,
Handle class_loader,
const ClassLoadInfo& cl_info,
TRAPS) {
bool is_unsafe_anon_class = cl_info.unsafe_anonymous_host() != NULL;
if (cl_info.is_hidden() || is_unsafe_anon_class) {
if (cl_info.is_hidden()) {
return resolve_hidden_class_from_stream(st, class_name, class_loader, cl_info, CHECK_NULL);
} else {
return resolve_class_from_stream(st, class_name, class_loader, cl_info, CHECK_NULL);
@ -1183,7 +1164,7 @@ InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik,
}
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.
if (!SystemDictionaryShared::is_hidden_lambda_proxy(ik)) {
new_ik = KlassFactory::check_shared_class_file_load_hook(
@ -1618,7 +1599,6 @@ void SystemDictionary::add_to_hierarchy(InstanceKlass* k) {
// GC support
// 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 unloading_occurred;

View File

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

View File

@ -1107,7 +1107,7 @@ InstanceKlass* SystemDictionaryShared::lookup_from_stream(Symbol* class_name,
if (!UseSharedSpaces) {
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;
}
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) {
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()) {
warn_excluded(k, "In error state");
return true;

View File

@ -2158,9 +2158,7 @@ void ClassVerifier::verify_ldc(
| (1 << JVM_CONSTANT_Dynamic);
verify_cp_type(bci, index, cp, types, CHECK_VERIFY(this));
}
if (tag.is_string() && cp->is_pseudo_string_at(index)) {
current_frame->push_stack(object_type(), CHECK_VERIFY(this));
} else if (tag.is_string()) {
if (tag.is_string()) {
current_frame->push_stack(
VerificationType::reference_type(
vmSymbols::java_lang_String()), CHECK_VERIFY(this));
@ -2876,21 +2874,8 @@ void ClassVerifier::verify_invoke_instructions(
current_class()->super()->name()))) {
bool subtype = false;
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(
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));
}
subtype = ref_class_type.is_assignable_from(
current_type(), this, false, CHECK_VERIFY(this));
if (!subtype) {
verify_error(ErrorContext::bad_code(bci),
"Bad invokespecial instruction: "
@ -2925,24 +2910,7 @@ void ClassVerifier::verify_invoke_instructions(
} else { // other methods
// Ensures that target class is assignable to method class.
if (opcode == Bytecodes::_invokespecial) {
if (!current_class()->is_unsafe_anonymous()) {
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;
}
}
current_frame->pop_stack(current_type(), CHECK_VERIFY(this));
} else if (opcode == Bytecodes::_invokevirtual) {
VerificationType stack_object_type =
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, "");
}
#endif
// Get sender or sender's unsafe_anonymous_host, and only set cpCache entry to resolved if
// it is not an interface. The receiver for invokespecial calls within interface
// Get sender and only set cpCache entry to resolved if it is not an
// interface. The receiver for invokespecial calls within interface
// methods must be checked for every call.
InstanceKlass* sender = pool->pool_holder();
sender = sender->is_unsafe_anonymous() ? sender->unsafe_anonymous_host() : sender;
switch (info.call_kind()) {
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
Klass* current_klass = link_info.current_klass();
if (current_klass != NULL && resolved_klass->is_interface()) {
InstanceKlass* ck = InstanceKlass::cast(current_klass);
InstanceKlass *klass_to_check = !ck->is_unsafe_anonymous() ?
ck :
ck->unsafe_anonymous_host();
InstanceKlass* klass_to_check = InstanceKlass::cast(current_klass);
// Disable verification for the dynamically-generated reflection bytecodes.
bool is_reflect = klass_to_check->is_subclass_of(
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
// a class. If the sender is an interface, the check has to be performed at runtime.
InstanceKlass* sender = InstanceKlass::cast(current_klass);
sender = sender->is_unsafe_anonymous() ? sender->unsafe_anonymous_host() : sender;
if (sender->is_interface() && recv.not_null()) {
Klass* receiver_klass = recv->klass();
if (!receiver_klass->is_subtype_of(sender)) {

View File

@ -164,7 +164,7 @@ void ObjectSampleDescription::write_class_name() {
if (k->is_instance_klass()) {
const InstanceKlass* ik = InstanceKlass::cast(k);
if (ik->is_unsafe_anonymous() || ik->is_hidden()) {
if (ik->is_hidden()) {
return;
}
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;
}
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) {
assert(klass != NULL, "invariant");
if (klass->is_objArray_klass()) {
klass = ObjArrayKlass::cast(klass)->bottom_klass();
}
if (klass->is_non_strong_hidden()) return NULL;
return is_unsafe_anonymous(klass) ?
InstanceKlass::cast(klass)->unsafe_anonymous_host()->class_loader_data() : klass->class_loader_data();
return klass->class_loader_data();
}
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.
*
* 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 +
* the identity_hashcode slash appended:
* hidden classes symbol is the external name +
* the address of its InstanceKlass slash appended:
* java.lang.invoke.LambdaForm$BMH/22626602
*
* 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->is_unsafe_anonymous() || ik->is_hidden(), "invariant");
assert(ik->is_hidden(), "invariant");
const oop mirror = ik->java_mirror_no_keepalive();
assert(mirror != NULL, "invariant");
return (uintptr_t)mirror->identity_hash();
}
static const char* create_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->is_unsafe_anonymous() || ik->is_hidden(), "invariant");
assert(ik->is_hidden(), "invariant");
assert(hash != 0, "invariant");
char* hidden_or_anon_symbol = NULL;
char* hidden_symbol = NULL;
const oop mirror = ik->java_mirror_no_keepalive();
assert(mirror != NULL, "invariant");
char hash_buf[40];
sprintf(hash_buf, "/" UINTX_FORMAT, hash);
const size_t hash_len = strlen(hash_buf);
const size_t result_len = ik->name()->utf8_length();
hidden_or_anon_symbol = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1);
ik->name()->as_klass_external_name(hidden_or_anon_symbol, (int)result_len + 1);
assert(strlen(hidden_or_anon_symbol) == result_len, "invariant");
strcpy(hidden_or_anon_symbol + result_len, hash_buf);
assert(strlen(hidden_or_anon_symbol) == result_len + hash_len, "invariant");
return hidden_or_anon_symbol;
hidden_symbol = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1);
ik->name()->as_klass_external_name(hidden_symbol, (int)result_len + 1);
assert(strlen(hidden_symbol) == result_len, "invariant");
strcpy(hidden_symbol + result_len, hash_buf);
assert(strlen(hidden_symbol) == result_len + hash_len, "invariant");
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");
return k->is_instance_klass() &&
(((const InstanceKlass*)k)->is_unsafe_anonymous() ||
((const InstanceKlass*)k)->is_hidden());
return k->is_instance_klass() && ((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->is_unsafe_anonymous() || ik->is_hidden(), "invariant");
const uintptr_t hash = hidden_or_anon_klass_name_hash(ik);
const char* const hidden_or_anon_symbol = create_hidden_or_anon_klass_symbol(ik, hash);
return mark(hash, hidden_or_anon_symbol, leakp);
assert(ik->is_hidden(), "invariant");
const uintptr_t hash = hidden_klass_name_hash(ik);
const char* const hidden_symbol = create_hidden_klass_symbol(ik, hash);
return mark(hash, hidden_symbol, leakp);
}
traceid JfrSymbolId::mark(const Klass* k, bool leakp) {
assert(k != NULL, "invariant");
traceid symbol_id = 0;
if (is_hidden_or_anon_klass(k)) {
if (is_hidden_klass(k)) {
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) {
Symbol* const sym = k->name();
@ -282,9 +280,9 @@ traceid JfrArtifactSet::bootstrap_name(bool 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");
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) {

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.
*
* 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);
bool is_hidden_or_anon_klass(const Klass* k);
uintptr_t hidden_or_anon_klass_name_hash(const InstanceKlass* ik);
traceid mark_hidden_klass_name(const InstanceKlass* k, bool leakp);
bool is_hidden_klass(const Klass* k);
uintptr_t hidden_klass_name_hash(const InstanceKlass* ik);
public:
JfrSymbolId();
@ -315,7 +315,7 @@ class JfrArtifactSet : public JfrCHeapObj {
traceid mark(const Klass* klass, bool leakp);
traceid mark(const Symbol* symbol, bool leakp);
traceid mark(uintptr_t hash, const char* const str, bool leakp);
traceid mark_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);
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");
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))
if (jvmci_type == NULL) {
JVMCI_THROW_0(NullPointerException);
@ -2673,7 +2665,6 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "flushDebugOutput", CC "()V", FN_PTR(flushDebugOutput)},
{CC "methodDataProfileDataSize", CC "(JI)I", FN_PTR(methodDataProfileDataSize)},
{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 "compileToBytecode", CC "(" OBJECTCONSTANT ")V", FN_PTR(compileToBytecode)},
{CC "getFlagValue", CC "(" STRING ")" OBJECT, FN_PTR(getFlagValue)},

View File

@ -585,7 +585,6 @@
/* InstanceKlass _misc_flags */ \
/*********************************/ \
\
declare_constant(InstanceKlass::_misc_is_unsafe_anonymous) \
declare_constant(InstanceKlass::_misc_has_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.
* 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);
// 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;
const char* name = NULL;
const char* class_name = NULL;
@ -133,7 +133,7 @@ void PrintCLDMetaspaceInfoClosure::do_cld(ClassLoaderData* cld) {
}
_out->print(":");
if (cld->has_class_mirror_holder()) {
_out->print(" <hidden or anonymous class>, loaded by");
_out->print(" <hidden class>, loaded by");
}
if (name != NULL) {
_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);
}
// Unsafe anonymous 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:
// Hidden class support:
void ConstantPool::klass_at_put(int class_index, Klass* k) {
assert(k != NULL, "must be valid klass");
CPKlassSlot kslot = klass_slot_at(class_index);
@ -330,7 +308,7 @@ void ConstantPool::resolve_class_constants(TRAPS) {
constantPoolHandle cp(THREAD, this);
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);
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:
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);
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
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));
break;
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;
case JVM_CONSTANT_Integer :
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) {}
intptr_t value() { return _ptr; }
bool is_pseudo_string() { return (_ptr & _pseudo_bit) != 0; }
Symbol* get_symbol() {
return (Symbol*)(_ptr & ~_pseudo_bit);
@ -310,8 +309,7 @@ class ConstantPool : public Metadata {
*int_at_addr(which) = name_index;
}
// Unsafe anonymous class support:
void klass_at_put(int class_index, int name_index, int resolved_klass_index, Klass* k, Symbol* name);
// Hidden class support:
void klass_at_put(int class_index, Klass* k);
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.
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
// earlier string_at call.
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(); }
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_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.
*
* 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);
}
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

View File

@ -50,7 +50,7 @@ public:
// 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
// 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) {
bool is_hidden_or_anonymous = parser.is_hidden() || parser.is_unsafe_anonymous();
const int size = InstanceKlass::size(parser.vtable_size(),
parser.itable_size(),
nonstatic_oop_map_size(parser.total_oop_map_count()),
parser.is_interface(),
parser.is_unsafe_anonymous());
parser.is_interface());
const Symbol* const class_name = parser.class_name();
assert(class_name != NULL, "invariant");
@ -504,7 +502,6 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, unsigned kind, Klass
set_kind(kind);
set_access_flags(parser.access_flags());
if (parser.is_hidden()) set_is_hidden();
set_is_unsafe_anonymous(parser.is_unsafe_anonymous());
set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
false));
@ -2709,13 +2706,6 @@ const char* InstanceKlass::signature_name() const {
int hash_len = 0;
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
const char* src = (const char*) (name()->as_C_string());
const int src_length = (int)strlen(src);
@ -2752,12 +2742,6 @@ const char* InstanceKlass::signature_name() 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() &&
in_unnamed_package() &&
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;
}
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();
if (encl_method_class_idx != 0) {
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);
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) {
st->print(BULLET"source file: ");
source_file_name()->print_value_on(st);
@ -3827,10 +3810,6 @@ void InstanceKlass::verify_on(outputStream* st) {
if (constants() != NULL) {
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) {
@ -4162,7 +4141,7 @@ bool InstanceKlass::is_shareable() const {
return false;
}
if (is_hidden() || unsafe_anonymous_host() != NULL) {
if (is_hidden()) {
return false;
}

View File

@ -50,7 +50,6 @@ class RecordComponent;
// The embedded nonstatic oop-map blocks are short pairs (offset, length)
// indicating where oops are located in instances of this klass.
// [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
@ -248,7 +247,7 @@ class InstanceKlass: public Klass {
_misc_rewritten = 1 << 0, // methods rewritten.
_misc_has_nonstatic_fields = 1 << 1, // for sizing with UseCompressedOops
_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_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
@ -329,13 +328,6 @@ class InstanceKlass: public Klass {
// NULL: no implementor.
// A Klass* that's not itself: one implementor.
// 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;
@ -687,20 +679,6 @@ public:
// signers
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 {
return (_misc_flags & _misc_is_contended) != 0;
}
@ -1045,21 +1023,21 @@ public:
static int size(int vtable_length, int itable_length,
int nonstatic_oop_map_size,
bool is_interface, bool is_unsafe_anonymous) {
bool is_interface) {
return align_metadata_size(header_size() +
vtable_length +
itable_length +
nonstatic_oop_map_size +
(is_interface ? (int)sizeof(Klass*)/wordSize : 0) +
(is_unsafe_anonymous ? (int)sizeof(Klass*)/wordSize : 0));
(is_interface ? (int)sizeof(Klass*)/wordSize : 0));
}
int size() const { return size(vtable_length(),
itable_length(),
nonstatic_oop_map_size(),
is_interface(),
is_unsafe_anonymous());
is_interface());
}
inline intptr_t* start_of_itable() const;
inline intptr_t* end_of_itable() const;
inline int itable_offset_in_words() const;
@ -1069,7 +1047,6 @@ public:
inline Klass** end_of_nonstatic_oop_maps() 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:
int size_helper() const {

View File

@ -37,27 +37,6 @@
#include "utilities/globalDefinitions.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::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 {
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");
return;
} 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
// 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.
Devirtualizer::do_cld(closure, klass->class_loader_data());
} else {

View File

@ -677,19 +677,7 @@ static char* convert_hidden_name_to_java(Symbol* name) {
const char* Klass::external_name() const {
if (is_instance_klass()) {
const InstanceKlass* ik = static_cast<const InstanceKlass*>(this);
if (ik->is_unsafe_anonymous()) {
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()) {
if (ik->is_hidden()) {
char* result = convert_hidden_name_to_java(name());
return result;
}

View File

@ -43,7 +43,7 @@ inline bool Klass::is_non_strong_hidden() const {
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
// unloading, and hence during concurrent class unloading.
inline bool Klass::is_loader_alive() const {

View File

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

View File

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

View File

@ -190,7 +190,7 @@ bool VM_RedefineClasses::doit_prologue() {
}
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.
if (!is_modifiable_class(mirror)) {
_res = JVMTI_ERROR_UNMODIFIABLE_CLASS;
@ -333,9 +333,8 @@ bool VM_RedefineClasses::is_modifiable_class(oop klass_mirror) {
return false;
}
// Cannot redefine or retransform a hidden or an unsafe anonymous class.
if (InstanceKlass::cast(k)->is_hidden() ||
InstanceKlass::cast(k)->is_unsafe_anonymous()) {
// Cannot redefine or retransform a hidden class.
if (InstanceKlass::cast(k)->is_hidden()) {
return false;
}
return true;
@ -2939,7 +2938,6 @@ bool VM_RedefineClasses::skip_type_annotation_target(
case 0x10:
// 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
// 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),
new_cp->string_at_noresolve(cpi_new)) != 0)
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()) {
// tag_old should be klass - 4881222
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
// 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)) {
ThreadToNativeFromVM ttnfv(thread);
env->Throw(thr);
@ -1120,8 +946,6 @@ static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = {
{CC "writebackPostSync0", CC "()V", FN_PTR(Unsafe_WriteBackPostSync0)},
{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 "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,
const Klass* accessee,
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* 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 &&
accessor_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;
}
const Klass* host_class = current_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) {
if (current_class == member_class) {
return true;
}
@ -662,12 +632,12 @@ bool Reflection::verify_member_access(const Klass* current_class,
if (!protected_restriction) {
// 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
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
current_class == resolved_class ||
member_class == resolved_class ||
host_class->is_subclass_of(resolved_class) ||
resolved_class->is_subclass_of(host_class)) {
current_class->is_subclass_of(resolved_class) ||
resolved_class->is_subclass_of(current_class)) {
return true;
}
}
@ -679,9 +649,8 @@ bool Reflection::verify_member_access(const Klass* current_class,
return true;
}
// private access between different classes needs a nestmate check, but
// not for unsafe anonymous classes - so check host_class
if (access.is_private() && host_class == current_class) {
// private access between different classes needs a nestmate check.
if (access.is_private()) {
if (current_class->is_instance_klass() && member_class->is_instance_klass() ) {
InstanceKlass* cur_ik = const_cast<InstanceKlass*>(InstanceKlass::cast(current_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,
// 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 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.
void Reflection::check_for_inner_class(const InstanceKlass* outer, const InstanceKlass* inner,
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_has_nonstatic_fields) \
declare_constant(InstanceKlass::_misc_should_verify_class) \
declare_constant(InstanceKlass::_misc_is_unsafe_anonymous) \
declare_constant(InstanceKlass::_misc_is_contended) \
declare_constant(InstanceKlass::_misc_has_nonstatic_concrete_methods) \
declare_constant(InstanceKlass::_misc_declares_nonstatic_concrete_methods)\

View File

@ -1012,8 +1012,6 @@ class InvokerBytecodeGenerator {
return false; // not on BCP
if (cls.isHidden())
return false;
if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: Unsafe::defineAnonymousClass to be removed
return false;
if (!isStaticallyInvocableType(member.getMethodOrFieldType()))
return false;
if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls))
@ -1045,8 +1043,6 @@ class InvokerBytecodeGenerator {
return true; // int[].class, for example
if (cls.isHidden())
return false;
if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: Unsafe::defineAnonymousClass to be removed
return false;
// could use VerifyAccess.isClassAccessible but the following is a safe approximation
if (cls.getClassLoader() != Object.class.getClassLoader())
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.
*
* This code is free software; you can redistribute it and/or modify it
@ -1329,34 +1329,6 @@ public final class Unsafe {
ClassLoader loader,
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.
* 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 int arrayBaseOffset0(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);

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.
*
* 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.
if (++numInvocations > ReflectionFactory.inflationThreshold()
&& !c.getDeclaringClass().isHidden()
&& !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())
&& generated == 0
&& U.compareAndSetInt(this, GENERATED_OFFSET, 0, 1)) {
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.
*
* 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.
if (++numInvocations > ReflectionFactory.inflationThreshold()
&& !method.getDeclaringClass().isHidden()
&& !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())
&& generated == 0
&& U.compareAndSetInt(this, GENERATED_OFFSET, 0, 1)) {
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.
*
* This code is free software; you can redistribute it and/or modify it
@ -202,8 +202,7 @@ public class ReflectionFactory {
method = root;
}
if (noInflation && !method.getDeclaringClass().isHidden()
&& !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
if (noInflation && !method.getDeclaringClass().isHidden()) {
return new MethodAccessorGenerator().
generateMethod(method.getDeclaringClass(),
method.getName(),
@ -247,8 +246,7 @@ public class ReflectionFactory {
return new BootstrapConstructorAccessorImpl(c);
}
if (noInflation && !c.getDeclaringClass().isHidden()
&& !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) {
if (noInflation && !c.getDeclaringClass().isHidden()) {
return new MethodAccessorGenerator().
generateConstructor(c.getDeclaringClass(),
c.getParameterTypes(),

View File

@ -312,12 +312,4 @@ public final class ReflectUtil {
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_HAS_NONSTATIC_FIELDS;
private static int MISC_SHOULD_VERIFY_CLASS;
private static int MISC_IS_UNSAFE_ANONYMOUS;
private static int MISC_IS_CONTENDED;
private static int MISC_HAS_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_HAS_NONSTATIC_FIELDS = db.lookupIntConstant("InstanceKlass::_misc_has_nonstatic_fields").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_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();
@ -283,9 +281,6 @@ public class InstanceKlass extends Klass {
if (isInterface()) {
size += wordLength;
}
if (isUnsafeAnonymous()) {
size += wordLength;
}
return alignSize(size);
}
@ -293,10 +288,6 @@ public class InstanceKlass extends Klass {
return (int) miscFlags.getValue(this);
}
public boolean isUnsafeAnonymous() {
return (getMiscFlags() & MISC_IS_UNSAFE_ANONYMOUS) != 0;
}
public static long getHeaderSize() { return headerSize; }
public short getFieldAccessFlags(int index) {

View File

@ -723,11 +723,6 @@ final class CompilerToVM {
*/
native Object getFlagValue(String name);
/**
* Gets the host class for {@code type}.
*/
native HotSpotResolvedObjectTypeImpl getHostClass(HotSpotResolvedObjectTypeImpl type);
/**
* @see ResolvedJavaType#getInterfaces()
*/
@ -739,7 +734,7 @@ final class CompilerToVM {
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.
*/
native HotSpotResolvedObjectTypeImpl getArrayType(HotSpotResolvedJavaType type);

View File

@ -108,23 +108,6 @@ public interface HotSpotResolvedObjectType extends ResolvedJavaType {
@Override
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.
*

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.
*
* 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;
}
@Override
public ResolvedJavaType getHostClass() {
if (isArray()) {
return null;
}
return compilerToVM().getHostClass(this);
}
@Override
public boolean isJavaLangObject() {
return getName().equals("Ljava/lang/Object;");
@ -1040,9 +1032,4 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
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.
*
* 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);
}
@Override
public ResolvedJavaType getHostClass() {
return null;
}
@Override
public JavaKind getJavaKind() {
return kind;

View File

@ -109,7 +109,6 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess {
final int instanceKlassStateLinked = getConstant("InstanceKlass::linked", Integer.class);
final int instanceKlassStateFullyInitialized = getConstant("InstanceKlass::fully_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 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);
/**
* 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}.
*/

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.
*
* This code is free software; you can redistribute it and/or modify it
@ -44,7 +44,7 @@ public abstract class Value {
@Override
public boolean equals(Object other) {
// 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;
}
}

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.
*
* 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:
/**
* 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.
* 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.
*
* This code is free software; you can redistribute it and/or modify it
@ -38,7 +38,6 @@
package compiler.jsr292;
import jdk.internal.misc.Unsafe;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Handle;
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.MethodHandleHelper;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite;
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;
public class CallSiteDepContextTest {
static final Unsafe UNSAFE = Unsafe.getUnsafe();
static final MethodHandles.Lookup LOOKUP = MethodHandleHelper.IMPL_LOOKUP;
static final String CLASS_NAME = "compiler/jsr292/Test";
static final String METHOD_NAME = "m";
@ -130,8 +129,9 @@ public class CallSiteDepContextTest {
}
public static void testSharedCallSite() throws Throwable {
Class<?> cls1 = UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("CS_1"), null);
Class<?> cls2 = UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("CS_2"), null);
Lookup lookup = MethodHandles.lookup();
Class<?> cls1 = lookup.defineHiddenClass(getClassFile("CS_1"), true).lookupClass();
Class<?> cls2 = lookup.defineHiddenClass(getClassFile("CS_2"), true).lookupClass();
MethodHandle[] mhs = new MethodHandle[] {
LOOKUP.findStatic(cls1, METHOD_NAME, TYPE),
@ -152,7 +152,8 @@ public class CallSiteDepContextTest {
execute(1, mh);
// 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);
execute(1, mh1);
@ -170,9 +171,10 @@ public class CallSiteDepContextTest {
mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE));
Lookup lookup = MethodHandles.lookup();
Class<?>[] cls = new Class[] {
UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("GC_1" + id), null),
UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("GC_2" + id), null),
lookup.defineHiddenClass(getClassFile("GC_1"), true).lookupClass(),
lookup.defineHiddenClass(getClassFile("GC_2"), true).lookupClass(),
};
MethodHandle[] mhs = new MethodHandle[] {
@ -186,7 +188,7 @@ public class CallSiteDepContextTest {
execute(1, mhs);
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);
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;
}
private static boolean isUnsafeAnonymous(ResolvedJavaType type) {
return type.getHostClass() != null;
}
@Test
public void lookupJavaTypeTest() {
for (Class<?> c : classes) {
ResolvedJavaType type = metaAccess.lookupJavaType(c);
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(type.toJavaName()));
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()]));
int counter = 0;
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());
}
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.
*
* 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
public void getModifiersTest() {
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.
*
* This code is free software; you can redistribute it and/or modify it
@ -24,6 +24,12 @@
/*
* @test
* @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
* @modules jdk.compiler
* @run main CastToParentTest
@ -35,7 +41,6 @@ import java.lang.invoke.MethodHandles.Lookup;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
import jdk.test.lib.compiler.InMemoryJavaCompiler;
// This test is based on vmTestbase/vm/mlvm/anonloader/func/castToGrandparent/Test.java
public class CastToParentTest {
static byte klassbuf[] = InMemoryJavaCompiler.compile("TestClass",
@ -58,5 +63,17 @@ public class CastToParentTest {
// Try to cast using a different mechanism.
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.
*
* 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 jdk.test.lib.compiler.InMemoryJavaCompiler;
// This test is based on test vmTestbase/vm/mlvm/anonloader/func/isGarbageCollected/Test.java
public class GCHiddenClass {
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.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,10 @@
* @test
* @summary Test that stack tracing isn't broken if an exception is thrown
* 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
* @modules jdk.compiler
* @run main HiddenClassStack
@ -38,7 +42,6 @@ import java.lang.invoke.MethodHandles.Lookup;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.*;
import jdk.test.lib.compiler.InMemoryJavaCompiler;
// This test is based on vmTestbase/vm/mlvm/anonloader/func/classNameInStackTrace/Test.java
public class HiddenClassStack {
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 jdk.test.lib.compiler.InMemoryJavaCompiler;
// This test is based on vmTestbase/vm/mlvm/anonloader/share/StressClassLoadingTest.java
public class StressHiddenClasses {
private static final int PARSE_TIMEOUT = 0;

View File

@ -47,7 +47,6 @@ import java.net.URL;
import java.net.URLConnection;
import compiler.whitebox.CompilerWhiteBoxTest;
// This is based on test compiler/classUnloading/anonymousClass/TestAnonymousClassUnloading.java
public class TestHiddenClassUnloading {
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.
*
* 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.Pattern;
import jdk.internal.misc.Unsafe;
public class ClassLoaderStatsTest {
// Expected output from VM.classloader_stats:
// ClassLoader Parent CLD* Classes ChunkSz BlockSz Type
// 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>
// 38 124928 85856 + hidden classes
// 0x00000008003b5508 0x0000000000000000 0x00007f001c2d4760 1 6144 4040 jdk.internal.reflect.DelegatingClassLoader
@ -104,9 +102,8 @@ public class ClassLoaderStatsTest {
}
Matcher m2 = hiddenLine.matcher(next);
m2.matches();
if (!m2.group(1).equals("2")) {
// anonymous classes are included in the hidden classes count.
Assert.fail("Should have loaded 2 hidden classes, but found : " + m2.group(1));
if (!m2.group(1).equals("1")) {
Assert.fail("Should have loaded 1 hidden class, but found : " + m2.group(1));
}
checkPositiveInt(m2.group(2));
checkPositiveInt(m2.group(3));
@ -123,8 +120,6 @@ public class ClassLoaderStatsTest {
public static class DummyClassLoader extends ClassLoader {
public static final String CLASS_NAME = "TestClass";
static ByteBuffer readClassFile(String name)
{
File f = new File(System.getProperty("test.classes", "."), name);
@ -177,14 +172,12 @@ class HiddenClass { }
class TestClass {
private static final String HCName = "HiddenClass.class";
private static final String DIR = System.getProperty("test.classes");
static Unsafe unsafe = Unsafe.getUnsafe();
static {
try {
// Create a hidden non-strong class and an anonymous class.
// Create a hidden non-strong class
byte[] klassBuf = readClassFile(DIR + File.separator + HCName);
Class<?> hc = defineHiddenClass(klassBuf);
Class ac = unsafe.defineAnonymousClass(TestClass.class, klassBuf, new Object[0]);
} catch (Throwable e) {
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.
*
* This code is free software; you can redistribute it and/or modify it
@ -66,7 +66,6 @@ public class TestIntConstant {
"CollectedHeap::G1 3",
"RUNNABLE 2",
"Deoptimization::Reason_class_check 4",
"InstanceKlass::_misc_is_unsafe_anonymous 8",
"_thread_uninitialized 0"));
expStrMap.put("intConstant _temp_constant", List.of(
"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.
This code is free software; you can redistribute it and/or modify it
@ -50,7 +50,7 @@ keep classloader alive.
"plain",
"reflection",
"jni",
"anonymous_classloader".
"hidden_classloader".
- classloaders that we expect to live can be referenced in several ways.
This behavior can be adjusted with flag "-keepRefMode" that has valid options:
"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.
*
* 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 {
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.
*
* 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.bytecode.*;
//import gc.g1.unloading.check.*;
import gc.g1.unloading.check.Assertion;
import gc.g1.unloading.check.ClassAssertion;
import gc.g1.unloading.check.PhantomizedAssertion;
@ -42,7 +41,9 @@ import gc.g1.unloading.configuration.TestConfiguration;
import gc.g1.unloading.keepref.*;
import nsk.share.test.ExecutionController;
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.reflect.Field;
@ -71,6 +72,10 @@ public class ClassLoadingHelper {
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.
* @param executionController
@ -89,6 +94,7 @@ public class ClassLoadingHelper {
thread.start();
if (configuration.isInMemoryCompilation() && !configuration.isHumongousClass() && !(configuration.getKeepRefMode() == KeepRefMode.THREAD_ITSELF)) {
prepend_package = false;
bf = new BytecodeGeneratorFactory(random.nextLong());
} else {
if (configuration.isHumongousClass()) {
@ -107,7 +113,11 @@ public class ClassLoadingHelper {
* @return
*/
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();
byte[] bytecode = kit.getBytecode();
Class<?> clazz = loadClass(className, bytecode);
@ -118,12 +128,8 @@ public class ClassLoadingHelper {
warmUpClassIfNeeded(object);
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);
} else {
assertion = new ClassAssertion("gc/g1/unloading/loading/" + className, true);
}
assertion = new ClassAssertion(className, true);
switch (configuration.getKeepRefMode()) {
case STRONG_REFERENCE:
assertion.keepLink(referenceToKeep);
@ -178,7 +184,11 @@ public class ClassLoadingHelper {
*/
public Collection<Assertion> loadClassThatGonnaDie(String className_) {
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();
byte[] bytecode = kit.getBytecode();
Class<?> clazz = loadClass(className, bytecode);
@ -193,12 +203,7 @@ public class ClassLoadingHelper {
warmUpClassIfNeeded(object);
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);
} else {
assertion = new ClassAssertion("gc/g1/unloading/loading/" + className, false);
}
assertion = new ClassAssertion(className, false);
switch (configuration.getReleaseRefMode()) {
case WEAK:
assertion.keepLink(new WeakReference<Object>(referenceToKeep));
@ -246,11 +251,12 @@ public class ClassLoadingHelper {
return Class.forName(className, true, new ReflectionClassloader(bytecode, className));
case JNI:
return JNIClassloader.loadThroughJNI(className, bytecode);
case ANONYMOUS_CLASSLOADER:
return getUnsafe().defineAnonymousClass(ClassLoadingHelper.class, bytecode, NO_CP_PATCHES);
case HIDDEN_CLASSLOADER:
Lookup lookup = MethodHandles.lookup();
return lookup.defineHiddenClass(bytecode, true).lookupClass();
}
return null;
} catch (ClassNotFoundException e) {
} catch (ClassNotFoundException | IllegalAccessException 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 {

View File

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

View File

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

View File

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

View File

@ -52,7 +52,7 @@
* -Xlog:gc:gc.log
* -XX:-UseGCOverheadLimit
* gc.g1.unloading.UnloadingTest
* -classloadingMethod anonymous_classloader
* -classloadingMethod hidden_classloader
* -keep object
* -numberOfChecksLimit 4
* -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.
*
* 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
* questions.
*/
package metaspace.staticReferences;
public class OneUsageClassloader extends ClassLoader {

View File

@ -38,11 +38,11 @@
* -Xbootclasspath/a:.
* -XX:+UnlockDiagnosticVMOptions
* -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.Reference;
import java.lang.reflect.Field;
@ -59,13 +59,12 @@ import nsk.share.test.ExecutionController;
import nsk.share.test.Stresser;
import nsk.share.test.TestBase;
import nsk.share.test.Tests;
import jdk.internal.misc.Unsafe;
import vm.share.gc.TriggerUnloadingHelper;
import vm.share.gc.TriggerUnloadingWithWhiteBox;
/**
* 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.
* 3.) Change static fields.
* 4.) Unload class.
@ -96,10 +95,6 @@ public class StaticReferences extends GCTestBase {
Tests.runTest(new StaticReferences(), args);
}
private static Unsafe getUnsafe() {
return Unsafe.getUnsafe();
}
@Override
public void run() {
random = new Random(runParams.getSeed());
@ -123,10 +118,10 @@ public class StaticReferences extends GCTestBase {
// Core of test
for (byte[] classBytecode : bytecodeList) {
boolean anonymous = random.nextBoolean();
boolean hidden = random.nextBoolean();
log.info("Load class first time");
Class clazz = loadClass(classBytecode, anonymous);
Class clazz = loadClass(classBytecode, hidden);
log.info("Trigger unloading");
triggerUnloadingHelper.triggerUnloading(stresser);
@ -155,7 +150,7 @@ public class StaticReferences extends GCTestBase {
}
log.info("Load class second time");
clazz = loadClass(classBytecode, anonymous);
clazz = loadClass(classBytecode, hidden);
log.info("check fields reinitialized");
checkStaticFields(clazz);
@ -164,11 +159,17 @@ public class StaticReferences extends GCTestBase {
}
}
private Class loadClass(byte[] classBytecode,
boolean anonymous) {
private Class loadClass(byte[] classBytecode, boolean hidden) {
Class clazz;
if (anonymous) {
clazz = getUnsafe().defineAnonymousClass(StaticReferences.class, classBytecode, NO_CP_PATCHES);
if (hidden) {
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 {
OneUsageClassloader classloader = new OneUsageClassloader();
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.
*
* This code is free software; you can redistribute it and/or modify it
@ -22,10 +22,11 @@
*/
package vm.compiler.coverage.parentheses.share;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Field;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.misc.Unsafe;
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 uses Unsafe.defineAnonymousClass for class loading
* This class uses hidden classes for class loading
*/
public class HotspotInstructionsExecutor implements InstructionsExecutor {
@ -54,8 +55,9 @@ public class HotspotInstructionsExecutor implements InstructionsExecutor {
return (Integer) execMethod.invoke(null);
}
private Class generateClass(List<Instruction> instructions) throws ClassNotFoundException {
String classNameForASM = "ExecClass";
private Class generateClass(List<Instruction> instructions) throws ReflectiveOperationException {
// Needs to be in the same package as the lookup class.
String classNameForASM = "vm/compiler/coverage/parentheses/share/ExecClass";
ClassWriter cw = new ClassWriter(0);
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.visitEnd();
return getUnsafe().defineAnonymousClass(ClassWriter.class, cw.toByteArray(), NO_CP_PATCHES);
}
private static Unsafe getUnsafe() {
return Unsafe.getUnsafe();
Lookup lookup = MethodHandles.lookup();
Class<?> hc = lookup.defineHiddenClass(cw.toByteArray(), false).lookupClass();
return hc;
}
}

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