mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8243287: Removal of Unsafe::defineAnonymousClass
Reviewed-by: iklam, mchung, alanb, dholmes
This commit is contained in:
parent
a564f2cbd5
commit
e14b026841
122 changed files with 328 additions and 3679 deletions
|
@ -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) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue