8243287: Removal of Unsafe::defineAnonymousClass
Reviewed-by: iklam, mchung, alanb, dholmes
This commit is contained in:
parent
a564f2cbd5
commit
e14b026841
@ -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);
|
||||
|
@ -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()) {
|
||||
|
@ -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())
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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; }
|
||||
|
@ -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; }
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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*));
|
||||
|
@ -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:
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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());
|
||||
|
@ -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.
|
||||
//
|
||||
|
@ -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,
|
||||
|
@ -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++) {
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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:
|
||||
|
@ -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)) {
|
||||
|
@ -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();
|
||||
|
@ -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>
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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)},
|
||||
|
@ -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) \
|
||||
\
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()))
|
||||
|
@ -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)},
|
||||
|
@ -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) {
|
||||
|
@ -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)\
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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(),
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -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}.
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
@ -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++;
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
@ -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"));
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user