mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8143324: Backout JDK-8087223
Reviewed-by: coleenp, acorn
This commit is contained in:
parent
dcd4a03963
commit
c02b26ee45
15 changed files with 22 additions and 496 deletions
|
@ -704,14 +704,13 @@ Method* ciEnv::lookup_method(InstanceKlass* accessor,
|
||||||
InstanceKlass* holder,
|
InstanceKlass* holder,
|
||||||
Symbol* name,
|
Symbol* name,
|
||||||
Symbol* sig,
|
Symbol* sig,
|
||||||
Bytecodes::Code bc,
|
Bytecodes::Code bc) {
|
||||||
constantTag tag) {
|
|
||||||
EXCEPTION_CONTEXT;
|
EXCEPTION_CONTEXT;
|
||||||
KlassHandle h_accessor(THREAD, accessor);
|
KlassHandle h_accessor(THREAD, accessor);
|
||||||
KlassHandle h_holder(THREAD, holder);
|
KlassHandle h_holder(THREAD, holder);
|
||||||
LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL));
|
LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL));
|
||||||
methodHandle dest_method;
|
methodHandle dest_method;
|
||||||
LinkInfo link_info(h_holder, name, sig, h_accessor, LinkInfo::needs_access_check, tag);
|
LinkInfo link_info(h_holder, name, sig, h_accessor, /*check_access*/true);
|
||||||
switch (bc) {
|
switch (bc) {
|
||||||
case Bytecodes::_invokestatic:
|
case Bytecodes::_invokestatic:
|
||||||
dest_method =
|
dest_method =
|
||||||
|
@ -797,9 +796,7 @@ ciMethod* ciEnv::get_method_by_index_impl(const constantPoolHandle& cpool,
|
||||||
|
|
||||||
if (holder_is_accessible) { // Our declared holder is loaded.
|
if (holder_is_accessible) { // Our declared holder is loaded.
|
||||||
InstanceKlass* lookup = declared_holder->get_instanceKlass();
|
InstanceKlass* lookup = declared_holder->get_instanceKlass();
|
||||||
constantTag tag = cpool->tag_ref_at(index);
|
Method* m = lookup_method(accessor->get_instanceKlass(), lookup, name_sym, sig_sym, bc);
|
||||||
assert(accessor->get_instanceKlass() == cpool->pool_holder(), "not the pool holder?");
|
|
||||||
Method* m = lookup_method(accessor->get_instanceKlass(), lookup, name_sym, sig_sym, bc, tag);
|
|
||||||
if (m != NULL &&
|
if (m != NULL &&
|
||||||
(bc == Bytecodes::_invokestatic
|
(bc == Bytecodes::_invokestatic
|
||||||
? m->method_holder()->is_not_initialized()
|
? m->method_holder()->is_not_initialized()
|
||||||
|
|
|
@ -158,8 +158,7 @@ private:
|
||||||
InstanceKlass* holder,
|
InstanceKlass* holder,
|
||||||
Symbol* name,
|
Symbol* name,
|
||||||
Symbol* sig,
|
Symbol* sig,
|
||||||
Bytecodes::Code bc,
|
Bytecodes::Code bc);
|
||||||
constantTag tag);
|
|
||||||
|
|
||||||
// Get a ciObject from the object factory. Ensures uniqueness
|
// Get a ciObject from the object factory. Ensures uniqueness
|
||||||
// of ciObjects.
|
// of ciObjects.
|
||||||
|
|
|
@ -786,8 +786,7 @@ ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver, boo
|
||||||
Symbol* h_name = name()->get_symbol();
|
Symbol* h_name = name()->get_symbol();
|
||||||
Symbol* h_signature = signature()->get_symbol();
|
Symbol* h_signature = signature()->get_symbol();
|
||||||
|
|
||||||
LinkInfo link_info(h_resolved, h_name, h_signature, caller_klass,
|
LinkInfo link_info(h_resolved, h_name, h_signature, caller_klass, check_access);
|
||||||
check_access ? LinkInfo::needs_access_check : LinkInfo::skip_access_check);
|
|
||||||
methodHandle m;
|
methodHandle m;
|
||||||
// Only do exact lookup if receiver klass has been linked. Otherwise,
|
// Only do exact lookup if receiver klass has been linked. Otherwise,
|
||||||
// the vtable has not been setup, and the LinkResolver will fail.
|
// the vtable has not been setup, and the LinkResolver will fail.
|
||||||
|
|
|
@ -245,7 +245,6 @@ LinkInfo::LinkInfo(const constantPoolHandle& pool, int index, TRAPS) {
|
||||||
// Get name, signature, and static klass
|
// Get name, signature, and static klass
|
||||||
_name = pool->name_ref_at(index);
|
_name = pool->name_ref_at(index);
|
||||||
_signature = pool->signature_ref_at(index);
|
_signature = pool->signature_ref_at(index);
|
||||||
_tag = pool->tag_ref_at(index);
|
|
||||||
_current_klass = KlassHandle(THREAD, pool->pool_holder());
|
_current_klass = KlassHandle(THREAD, pool->pool_holder());
|
||||||
|
|
||||||
// Coming from the constant pool always checks access
|
// Coming from the constant pool always checks access
|
||||||
|
@ -682,15 +681,6 @@ methodHandle LinkResolver::resolve_method(const LinkInfo& link_info,
|
||||||
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check tag at call is method
|
|
||||||
if (!link_info.tag().is_invalid() && !link_info.tag().is_method()) {
|
|
||||||
ResourceMark rm(THREAD);
|
|
||||||
char buf[200];
|
|
||||||
jio_snprintf(buf, sizeof(buf), "Resolving to non regular method %s", link_info.method_string());
|
|
||||||
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 2. lookup method in resolved klass and its super klasses
|
// 2. lookup method in resolved klass and its super klasses
|
||||||
methodHandle resolved_method = lookup_method_in_klasses(link_info, true, false, CHECK_NULL);
|
methodHandle resolved_method = lookup_method_in_klasses(link_info, true, false, CHECK_NULL);
|
||||||
|
|
||||||
|
@ -750,14 +740,6 @@ methodHandle LinkResolver::resolve_interface_method(const LinkInfo& link_info,
|
||||||
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check tag at call is an interface method
|
|
||||||
if (!link_info.tag().is_invalid() && !link_info.tag().is_interface_method()) {
|
|
||||||
ResourceMark rm(THREAD);
|
|
||||||
char buf[200];
|
|
||||||
jio_snprintf(buf, sizeof(buf), "Resolving to non interface method %s", link_info.method_string());
|
|
||||||
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// lookup method in this interface or its super, java.lang.Object
|
// lookup method in this interface or its super, java.lang.Object
|
||||||
// JDK8: also look for static methods
|
// JDK8: also look for static methods
|
||||||
methodHandle resolved_method = lookup_method_in_klasses(link_info, false, true, CHECK_NULL);
|
methodHandle resolved_method = lookup_method_in_klasses(link_info, false, true, CHECK_NULL);
|
||||||
|
@ -935,8 +917,7 @@ void LinkResolver::resolve_static_call(CallInfo& result,
|
||||||
resolved_klass->initialize(CHECK);
|
resolved_klass->initialize(CHECK);
|
||||||
// Use updated LinkInfo (to reresolve with resolved_klass as method_holder?)
|
// Use updated LinkInfo (to reresolve with resolved_klass as method_holder?)
|
||||||
LinkInfo new_info(resolved_klass, link_info.name(), link_info.signature(),
|
LinkInfo new_info(resolved_klass, link_info.name(), link_info.signature(),
|
||||||
link_info.current_klass(),
|
link_info.current_klass(), link_info.check_access());
|
||||||
link_info.check_access() ? LinkInfo::needs_access_check : LinkInfo::skip_access_check);
|
|
||||||
resolved_method = linktime_resolve_static_method(new_info, CHECK);
|
resolved_method = linktime_resolve_static_method(new_info, CHECK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -135,35 +135,20 @@ class LinkInfo : public StackObj {
|
||||||
KlassHandle _resolved_klass; // class that the constant pool entry points to
|
KlassHandle _resolved_klass; // class that the constant pool entry points to
|
||||||
KlassHandle _current_klass; // class that owns the constant pool
|
KlassHandle _current_klass; // class that owns the constant pool
|
||||||
bool _check_access;
|
bool _check_access;
|
||||||
constantTag _tag;
|
|
||||||
public:
|
public:
|
||||||
enum AccessCheck {
|
|
||||||
needs_access_check,
|
|
||||||
skip_access_check
|
|
||||||
};
|
|
||||||
|
|
||||||
LinkInfo(const constantPoolHandle& pool, int index, TRAPS);
|
LinkInfo(const constantPoolHandle& pool, int index, TRAPS);
|
||||||
|
|
||||||
// Condensed information from other call sites within the vm.
|
// Condensed information from other call sites within the vm.
|
||||||
LinkInfo(KlassHandle resolved_klass, Symbol* name, Symbol* signature, KlassHandle current_klass,
|
LinkInfo(KlassHandle resolved_klass, Symbol* name, Symbol* signature,
|
||||||
AccessCheck check_access = needs_access_check,
|
KlassHandle current_klass, bool check_access = true) :
|
||||||
constantTag tag = JVM_CONSTANT_Invalid) :
|
|
||||||
_resolved_klass(resolved_klass),
|
_resolved_klass(resolved_klass),
|
||||||
_name(name), _signature(signature), _current_klass(current_klass),
|
_name(name), _signature(signature), _current_klass(current_klass),
|
||||||
_check_access(check_access == needs_access_check && current_klass.not_null()), _tag(tag) {}
|
_check_access(check_access) {}
|
||||||
|
|
||||||
// Case where we just find the method and don't check access against the current class
|
|
||||||
LinkInfo(KlassHandle resolved_klass, Symbol*name, Symbol* signature) :
|
|
||||||
_resolved_klass(resolved_klass),
|
|
||||||
_name(name), _signature(signature), _current_klass(NULL),
|
|
||||||
_check_access(false), _tag(JVM_CONSTANT_Invalid) {}
|
|
||||||
|
|
||||||
// accessors
|
// accessors
|
||||||
Symbol* name() const { return _name; }
|
Symbol* name() const { return _name; }
|
||||||
Symbol* signature() const { return _signature; }
|
Symbol* signature() const { return _signature; }
|
||||||
KlassHandle resolved_klass() const { return _resolved_klass; }
|
KlassHandle resolved_klass() const { return _resolved_klass; }
|
||||||
KlassHandle current_klass() const { return _current_klass; }
|
KlassHandle current_klass() const { return _current_klass; }
|
||||||
constantTag tag() const { return _tag; }
|
|
||||||
bool check_access() const { return _check_access; }
|
bool check_access() const { return _check_access; }
|
||||||
char* method_string() const;
|
char* method_string() const;
|
||||||
|
|
||||||
|
|
|
@ -574,7 +574,7 @@ C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_t
|
||||||
|
|
||||||
if (holder_klass->is_interface()) {
|
if (holder_klass->is_interface()) {
|
||||||
// do link-time resolution to check all access rules.
|
// do link-time resolution to check all access rules.
|
||||||
LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass);
|
LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass, true);
|
||||||
methodHandle resolved_method = LinkResolver::linktime_resolve_interface_method_or_null(link_info);
|
methodHandle resolved_method = LinkResolver::linktime_resolve_interface_method_or_null(link_info);
|
||||||
if (resolved_method.is_null() || resolved_method->is_private()) {
|
if (resolved_method.is_null() || resolved_method->is_private()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -586,7 +586,7 @@ C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_t
|
||||||
return JNIHandles::make_local(THREAD, result);
|
return JNIHandles::make_local(THREAD, result);
|
||||||
} else {
|
} else {
|
||||||
// do link-time resolution to check all access rules.
|
// do link-time resolution to check all access rules.
|
||||||
LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass);
|
LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass, true);
|
||||||
methodHandle resolved_method = LinkResolver::linktime_resolve_virtual_method_or_null(link_info);
|
methodHandle resolved_method = LinkResolver::linktime_resolve_virtual_method_or_null(link_info);
|
||||||
if (resolved_method.is_null()) {
|
if (resolved_method.is_null()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -282,12 +282,11 @@ methodHandle JVMCIEnv::lookup_method(instanceKlassHandle& h_accessor,
|
||||||
instanceKlassHandle& h_holder,
|
instanceKlassHandle& h_holder,
|
||||||
Symbol* name,
|
Symbol* name,
|
||||||
Symbol* sig,
|
Symbol* sig,
|
||||||
Bytecodes::Code bc,
|
Bytecodes::Code bc) {
|
||||||
constantTag tag) {
|
|
||||||
JVMCI_EXCEPTION_CONTEXT;
|
JVMCI_EXCEPTION_CONTEXT;
|
||||||
LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL));
|
LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL));
|
||||||
methodHandle dest_method;
|
methodHandle dest_method;
|
||||||
LinkInfo link_info(h_holder, name, sig, h_accessor, LinkInfo::needs_access_check, tag);
|
LinkInfo link_info(h_holder, name, sig, h_accessor, /*check_access*/true);
|
||||||
switch (bc) {
|
switch (bc) {
|
||||||
case Bytecodes::_invokestatic:
|
case Bytecodes::_invokestatic:
|
||||||
dest_method =
|
dest_method =
|
||||||
|
@ -360,8 +359,7 @@ methodHandle JVMCIEnv::get_method_by_index_impl(const constantPoolHandle& cpool,
|
||||||
|
|
||||||
if (holder_is_accessible) { // Our declared holder is loaded.
|
if (holder_is_accessible) { // Our declared holder is loaded.
|
||||||
instanceKlassHandle lookup = get_instance_klass_for_declared_method_holder(holder);
|
instanceKlassHandle lookup = get_instance_klass_for_declared_method_holder(holder);
|
||||||
constantTag tag = cpool->tag_ref_at(index);
|
methodHandle m = lookup_method(accessor, lookup, name_sym, sig_sym, bc);
|
||||||
methodHandle m = lookup_method(accessor, lookup, name_sym, sig_sym, bc, tag);
|
|
||||||
if (!m.is_null() &&
|
if (!m.is_null() &&
|
||||||
(bc == Bytecodes::_invokestatic
|
(bc == Bytecodes::_invokestatic
|
||||||
? InstanceKlass::cast(m->method_holder())->is_not_initialized()
|
? InstanceKlass::cast(m->method_holder())->is_not_initialized()
|
||||||
|
|
|
@ -125,8 +125,7 @@ private:
|
||||||
instanceKlassHandle& holder,
|
instanceKlassHandle& holder,
|
||||||
Symbol* name,
|
Symbol* name,
|
||||||
Symbol* sig,
|
Symbol* sig,
|
||||||
Bytecodes::Code bc,
|
Bytecodes::Code bc);
|
||||||
constantTag tag);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -409,19 +409,6 @@ int ConstantPool::impl_name_and_type_ref_index_at(int which, bool uncached) {
|
||||||
return extract_high_short_from_int(ref_index);
|
return extract_high_short_from_int(ref_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
constantTag ConstantPool::impl_tag_ref_at(int which, bool uncached) {
|
|
||||||
int pool_index = which;
|
|
||||||
if (!uncached && cache() != NULL) {
|
|
||||||
if (ConstantPool::is_invokedynamic_index(which)) {
|
|
||||||
// Invokedynamic index is index into resolved_references
|
|
||||||
pool_index = invokedynamic_cp_cache_entry_at(which)->constant_pool_index();
|
|
||||||
} else {
|
|
||||||
// change byte-ordering and go via cache
|
|
||||||
pool_index = remap_instruction_operand_from_cache(which);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tag_at(pool_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ConstantPool::impl_klass_ref_index_at(int which, bool uncached) {
|
int ConstantPool::impl_klass_ref_index_at(int which, bool uncached) {
|
||||||
guarantee(!ConstantPool::is_invokedynamic_index(which),
|
guarantee(!ConstantPool::is_invokedynamic_index(which),
|
||||||
|
@ -677,7 +664,6 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, in
|
||||||
int callee_index = this_cp->method_handle_klass_index_at(index);
|
int callee_index = this_cp->method_handle_klass_index_at(index);
|
||||||
Symbol* name = this_cp->method_handle_name_ref_at(index);
|
Symbol* name = this_cp->method_handle_name_ref_at(index);
|
||||||
Symbol* signature = this_cp->method_handle_signature_ref_at(index);
|
Symbol* signature = this_cp->method_handle_signature_ref_at(index);
|
||||||
constantTag m_tag = this_cp->tag_at(this_cp->method_handle_index_at(index));
|
|
||||||
if (PrintMiscellaneous)
|
if (PrintMiscellaneous)
|
||||||
tty->print_cr("resolve JVM_CONSTANT_MethodHandle:%d [%d/%d/%d] %s.%s",
|
tty->print_cr("resolve JVM_CONSTANT_MethodHandle:%d [%d/%d/%d] %s.%s",
|
||||||
ref_kind, index, this_cp->method_handle_index_at(index),
|
ref_kind, index, this_cp->method_handle_index_at(index),
|
||||||
|
@ -686,15 +672,6 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, in
|
||||||
{ Klass* k = klass_at_impl(this_cp, callee_index, true, CHECK_NULL);
|
{ Klass* k = klass_at_impl(this_cp, callee_index, true, CHECK_NULL);
|
||||||
callee = KlassHandle(THREAD, k);
|
callee = KlassHandle(THREAD, k);
|
||||||
}
|
}
|
||||||
if ((callee->is_interface() && m_tag.is_method()) ||
|
|
||||||
(!callee->is_interface() && m_tag.is_interface_method())) {
|
|
||||||
ResourceMark rm(THREAD);
|
|
||||||
char buf[200];
|
|
||||||
jio_snprintf(buf, sizeof(buf), "Inconsistent constant data for %s.%s%s at index %d",
|
|
||||||
callee->name()->as_C_string(), name->as_C_string(), signature->as_C_string(), index);
|
|
||||||
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
KlassHandle klass(THREAD, this_cp->pool_holder());
|
KlassHandle klass(THREAD, this_cp->pool_holder());
|
||||||
Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind,
|
Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind,
|
||||||
callee, name, signature,
|
callee, name, signature,
|
||||||
|
|
|
@ -664,8 +664,6 @@ class ConstantPool : public Metadata {
|
||||||
|
|
||||||
int remap_instruction_operand_from_cache(int operand); // operand must be biased by CPCACHE_INDEX_TAG
|
int remap_instruction_operand_from_cache(int operand); // operand must be biased by CPCACHE_INDEX_TAG
|
||||||
|
|
||||||
constantTag tag_ref_at(int cp_cache_index) { return impl_tag_ref_at(cp_cache_index, false); }
|
|
||||||
|
|
||||||
// Lookup for entries consisting of (name_index, signature_index)
|
// Lookup for entries consisting of (name_index, signature_index)
|
||||||
int name_ref_index_at(int which_nt); // == low-order jshort of name_and_type_at(which_nt)
|
int name_ref_index_at(int which_nt); // == low-order jshort of name_and_type_at(which_nt)
|
||||||
int signature_ref_index_at(int which_nt); // == high-order jshort of name_and_type_at(which_nt)
|
int signature_ref_index_at(int which_nt); // == high-order jshort of name_and_type_at(which_nt)
|
||||||
|
@ -786,7 +784,6 @@ class ConstantPool : public Metadata {
|
||||||
Symbol* impl_signature_ref_at(int which, bool uncached);
|
Symbol* impl_signature_ref_at(int which, bool uncached);
|
||||||
int impl_klass_ref_index_at(int which, bool uncached);
|
int impl_klass_ref_index_at(int which, bool uncached);
|
||||||
int impl_name_and_type_ref_index_at(int which, bool uncached);
|
int impl_name_and_type_ref_index_at(int which, bool uncached);
|
||||||
constantTag impl_tag_ref_at(int which, bool uncached);
|
|
||||||
|
|
||||||
// Used while constructing constant pool (only by ClassFileParser)
|
// Used while constructing constant pool (only by ClassFileParser)
|
||||||
jint klass_index_at(int which) {
|
jint klass_index_at(int which) {
|
||||||
|
|
|
@ -679,7 +679,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS
|
||||||
case IS_METHOD:
|
case IS_METHOD:
|
||||||
{
|
{
|
||||||
CallInfo result;
|
CallInfo result;
|
||||||
LinkInfo link_info(defc, name, type, caller);
|
LinkInfo link_info(defc, name, type, caller, caller.not_null());
|
||||||
{
|
{
|
||||||
assert(!HAS_PENDING_EXCEPTION, "");
|
assert(!HAS_PENDING_EXCEPTION, "");
|
||||||
if (ref_kind == JVM_REF_invokeStatic) {
|
if (ref_kind == JVM_REF_invokeStatic) {
|
||||||
|
@ -716,7 +716,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS
|
||||||
case IS_CONSTRUCTOR:
|
case IS_CONSTRUCTOR:
|
||||||
{
|
{
|
||||||
CallInfo result;
|
CallInfo result;
|
||||||
LinkInfo link_info(defc, name, type, caller);
|
LinkInfo link_info(defc, name, type, caller, caller.not_null());
|
||||||
{
|
{
|
||||||
assert(!HAS_PENDING_EXCEPTION, "");
|
assert(!HAS_PENDING_EXCEPTION, "");
|
||||||
if (name == vmSymbols::object_initializer_name()) {
|
if (name == vmSymbols::object_initializer_name()) {
|
||||||
|
@ -737,7 +737,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS
|
||||||
fieldDescriptor result; // find_field initializes fd if found
|
fieldDescriptor result; // find_field initializes fd if found
|
||||||
{
|
{
|
||||||
assert(!HAS_PENDING_EXCEPTION, "");
|
assert(!HAS_PENDING_EXCEPTION, "");
|
||||||
LinkInfo link_info(defc, name, type, caller, LinkInfo::skip_access_check);
|
LinkInfo link_info(defc, name, type, caller, /*check_access*/false);
|
||||||
LinkResolver::resolve_field(result, link_info, Bytecodes::_nop, false, THREAD);
|
LinkResolver::resolve_field(result, link_info, Bytecodes::_nop, false, THREAD);
|
||||||
if (HAS_PENDING_EXCEPTION) {
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
return empty;
|
return empty;
|
||||||
|
|
|
@ -183,7 +183,7 @@ void JavaCalls::call_virtual(JavaValue* result, KlassHandle spec_klass, Symbol*
|
||||||
CallInfo callinfo;
|
CallInfo callinfo;
|
||||||
Handle receiver = args->receiver();
|
Handle receiver = args->receiver();
|
||||||
KlassHandle recvrKlass(THREAD, receiver.is_null() ? (Klass*)NULL : receiver->klass());
|
KlassHandle recvrKlass(THREAD, receiver.is_null() ? (Klass*)NULL : receiver->klass());
|
||||||
LinkInfo link_info(spec_klass, name, signature);
|
LinkInfo link_info(spec_klass, name, signature, KlassHandle(), /*check_access*/false);
|
||||||
LinkResolver::resolve_virtual_call(
|
LinkResolver::resolve_virtual_call(
|
||||||
callinfo, receiver, recvrKlass, link_info, true, CHECK);
|
callinfo, receiver, recvrKlass, link_info, true, CHECK);
|
||||||
methodHandle method = callinfo.selected_method();
|
methodHandle method = callinfo.selected_method();
|
||||||
|
@ -220,7 +220,7 @@ void JavaCalls::call_virtual(JavaValue* result, Handle receiver, KlassHandle spe
|
||||||
|
|
||||||
void JavaCalls::call_special(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) {
|
void JavaCalls::call_special(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) {
|
||||||
CallInfo callinfo;
|
CallInfo callinfo;
|
||||||
LinkInfo link_info(klass, name, signature);
|
LinkInfo link_info(klass, name, signature, KlassHandle(), /*check_access*/false);
|
||||||
LinkResolver::resolve_special_call(callinfo, link_info, CHECK);
|
LinkResolver::resolve_special_call(callinfo, link_info, CHECK);
|
||||||
methodHandle method = callinfo.selected_method();
|
methodHandle method = callinfo.selected_method();
|
||||||
assert(method.not_null(), "should have thrown exception");
|
assert(method.not_null(), "should have thrown exception");
|
||||||
|
@ -255,7 +255,7 @@ void JavaCalls::call_special(JavaValue* result, Handle receiver, KlassHandle kla
|
||||||
|
|
||||||
void JavaCalls::call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) {
|
void JavaCalls::call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) {
|
||||||
CallInfo callinfo;
|
CallInfo callinfo;
|
||||||
LinkInfo link_info(klass, name, signature);
|
LinkInfo link_info(klass, name, signature, KlassHandle(), /*check_access*/false);
|
||||||
LinkResolver::resolve_static_call(callinfo, link_info, true, CHECK);
|
LinkResolver::resolve_static_call(callinfo, link_info, true, CHECK);
|
||||||
methodHandle method = callinfo.selected_method();
|
methodHandle method = callinfo.selected_method();
|
||||||
assert(method.not_null(), "should have thrown exception");
|
assert(method.not_null(), "should have thrown exception");
|
||||||
|
|
|
@ -830,7 +830,7 @@ methodHandle Reflection::resolve_interface_call(instanceKlassHandle klass, const
|
||||||
Symbol* signature = method->signature();
|
Symbol* signature = method->signature();
|
||||||
Symbol* name = method->name();
|
Symbol* name = method->name();
|
||||||
LinkResolver::resolve_interface_call(info, receiver, recv_klass,
|
LinkResolver::resolve_interface_call(info, receiver, recv_klass,
|
||||||
LinkInfo(klass, name, signature),
|
LinkInfo(klass, name, signature, KlassHandle(), false),
|
||||||
true,
|
true,
|
||||||
CHECK_(methodHandle()));
|
CHECK_(methodHandle()));
|
||||||
return info.selected_method();
|
return info.selected_method();
|
||||||
|
|
|
@ -1,250 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 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 8087223
|
|
||||||
* @summary Adding constantTag to keep method call consistent with it.
|
|
||||||
* @compile -XDignore.symbol.file BadMethodHandles.java
|
|
||||||
* @run main/othervm BadMethodHandles
|
|
||||||
*/
|
|
||||||
|
|
||||||
import jdk.internal.org.objectweb.asm.*;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.invoke.MethodType;
|
|
||||||
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|
||||||
|
|
||||||
public class BadMethodHandles {
|
|
||||||
|
|
||||||
static byte[] dumpBadInterfaceMethodref() {
|
|
||||||
ClassWriter cw = new ClassWriter(0);
|
|
||||||
cw.visit(52, ACC_PUBLIC | ACC_SUPER, "BadInterfaceMethodref", null, "java/lang/Object", null);
|
|
||||||
Handle handle1 =
|
|
||||||
new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "m", "()V");
|
|
||||||
Handle handle2 =
|
|
||||||
new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "staticM", "()V");
|
|
||||||
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
|
||||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(1, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
|
|
||||||
mv.visitLdcInsn("hello from m");
|
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(3, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
|
|
||||||
mv.visitLdcInsn("hello from staticM");
|
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(3, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
// REF_invokeStatic
|
|
||||||
mv.visitLdcInsn(handle1);
|
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(1, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
// REF_invokeStatic
|
|
||||||
mv.visitLdcInsn(handle2);
|
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(1, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
cw.visitEnd();
|
|
||||||
return cw.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
static byte[] dumpIBad() {
|
|
||||||
ClassWriter cw = new ClassWriter(0);
|
|
||||||
cw.visit(52, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "IBad", null, "java/lang/Object", null);
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
|
|
||||||
mv.visitLdcInsn("hello from m");
|
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(3, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
|
|
||||||
mv.visitLdcInsn("hello from staticM");
|
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(3, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
cw.visitEnd();
|
|
||||||
return cw.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
static byte[] dumpBadMethodref() {
|
|
||||||
ClassWriter cw = new ClassWriter(0);
|
|
||||||
cw.visit(52, ACC_PUBLIC | ACC_SUPER, "BadMethodref", null, "java/lang/Object", new String[]{"IBad"});
|
|
||||||
Handle handle1 =
|
|
||||||
new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "m", "()V");
|
|
||||||
Handle handle2 =
|
|
||||||
new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "staticM", "()V");
|
|
||||||
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
|
||||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(1, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
// REF_invokeStatic
|
|
||||||
mv.visitLdcInsn(handle1);
|
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(1, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
// REF_invokeStatic
|
|
||||||
mv.visitLdcInsn(handle2);
|
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(1, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
cw.visitEnd();
|
|
||||||
return cw.toByteArray();
|
|
||||||
}
|
|
||||||
static class CL extends ClassLoader {
|
|
||||||
@Override
|
|
||||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
|
||||||
byte[] classBytes = null;
|
|
||||||
switch (name) {
|
|
||||||
case "BadInterfaceMethodref": classBytes = dumpBadInterfaceMethodref(); break;
|
|
||||||
case "BadMethodref" : classBytes = dumpBadMethodref(); break;
|
|
||||||
case "IBad" : classBytes = dumpIBad(); break;
|
|
||||||
default : throw new ClassNotFoundException(name);
|
|
||||||
}
|
|
||||||
return defineClass(name, classBytes, 0, classBytes.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Throwable {
|
|
||||||
try (FileOutputStream fos = new FileOutputStream("BadInterfaceMethodref.class")) {
|
|
||||||
fos.write(dumpBadInterfaceMethodref());
|
|
||||||
}
|
|
||||||
try (FileOutputStream fos = new FileOutputStream("IBad.class")) {
|
|
||||||
fos.write(dumpIBad());
|
|
||||||
}
|
|
||||||
try (FileOutputStream fos = new FileOutputStream("BadMethodref.class")) {
|
|
||||||
fos.write(dumpBadMethodref());
|
|
||||||
}
|
|
||||||
|
|
||||||
Class<?> cls = (new CL()).loadClass("BadInterfaceMethodref");
|
|
||||||
String[] methods = {"runm", "runStaticM"};
|
|
||||||
System.out.println("Test BadInterfaceMethodref:");
|
|
||||||
int success = 0;
|
|
||||||
for (String name : methods) {
|
|
||||||
try {
|
|
||||||
System.out.printf("invoke %s: \n", name);
|
|
||||||
cls.getMethod(name).invoke(cls.newInstance());
|
|
||||||
System.out.println("FAILED (no exception)"); // ICCE should be thrown
|
|
||||||
} catch (Throwable e) {
|
|
||||||
if (e instanceof InvocationTargetException && e.getCause() != null &&
|
|
||||||
e.getCause() instanceof IncompatibleClassChangeError) {
|
|
||||||
System.out.println("PASSED");
|
|
||||||
success++;
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
System.out.println("FAILED with exception");
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (success != methods.length) {
|
|
||||||
throw new Exception("BadInterfaceMethodRef Failed to catch IncompatibleClassChangeError");
|
|
||||||
}
|
|
||||||
System.out.println("Test BadMethodref:");
|
|
||||||
cls = (new CL()).loadClass("BadMethodref");
|
|
||||||
success = 0;
|
|
||||||
for (String name : methods) {
|
|
||||||
try {
|
|
||||||
System.out.printf("invoke %s: \n", name);
|
|
||||||
cls.getMethod(name).invoke(cls.newInstance());
|
|
||||||
System.out.println("FAILED (no exception)"); // ICCE should be thrown
|
|
||||||
} catch (Throwable e) {
|
|
||||||
if (e instanceof InvocationTargetException && e.getCause() != null &&
|
|
||||||
e.getCause() instanceof IncompatibleClassChangeError) {
|
|
||||||
System.out.println("PASSED");
|
|
||||||
success++;
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
System.out.println("FAILED with exception");
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (success != methods.length) {
|
|
||||||
throw new Exception("BadMethodRef Failed to catch IncompatibleClassChangeError");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,156 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 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 8087223
|
|
||||||
* @summary Adding constantTag to keep method call consistent with it.
|
|
||||||
* @compile -XDignore.symbol.file IntfMethod.java
|
|
||||||
* @run main/othervm IntfMethod
|
|
||||||
* @run main/othervm -Xint IntfMethod
|
|
||||||
* @run main/othervm -Xcomp IntfMethod
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
import jdk.internal.org.objectweb.asm.*;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
|
||||||
|
|
||||||
public class IntfMethod {
|
|
||||||
static byte[] dumpC() {
|
|
||||||
ClassWriter cw = new ClassWriter(0);
|
|
||||||
cw.visit(52, ACC_PUBLIC | ACC_SUPER, "C", null, "java/lang/Object", new String[]{"I"});
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
|
||||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(1, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testSpecialIntf", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
|
||||||
mv.visitMethodInsn(INVOKESPECIAL, "I", "f1", "()V", /*itf=*/false);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(1, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testStaticIntf", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitMethodInsn(INVOKESTATIC, "I", "f2", "()V", /*itf=*/false);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(1, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testSpecialClass", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
|
||||||
mv.visitMethodInsn(INVOKESPECIAL, "C", "f1", "()V", /*itf=*/true);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(1, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f2", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(0, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testStaticClass", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitMethodInsn(INVOKESTATIC, "C", "f2", "()V", /*itf=*/true);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(1, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
cw.visitEnd();
|
|
||||||
return cw.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
static byte[] dumpI() {
|
|
||||||
ClassWriter cw = new ClassWriter(0);
|
|
||||||
cw.visit(52, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "I", null, "java/lang/Object", null);
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "f1", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(0, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f2", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(0, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
cw.visitEnd();
|
|
||||||
return cw.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
static class CL extends ClassLoader {
|
|
||||||
@Override
|
|
||||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
|
||||||
byte[] classFile;
|
|
||||||
switch (name) {
|
|
||||||
case "I": classFile = dumpI(); break;
|
|
||||||
case "C": classFile = dumpC(); break;
|
|
||||||
default:
|
|
||||||
throw new ClassNotFoundException(name);
|
|
||||||
}
|
|
||||||
return defineClass(name, classFile, 0, classFile.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Throwable {
|
|
||||||
Class<?> cls = (new CL()).loadClass("C");
|
|
||||||
try (FileOutputStream fos = new FileOutputStream("I.class")) { fos.write(dumpI()); }
|
|
||||||
try (FileOutputStream fos = new FileOutputStream("C.class")) { fos.write(dumpC()); }
|
|
||||||
|
|
||||||
int success = 0;
|
|
||||||
for (String name : new String[] { "testSpecialIntf", "testStaticIntf", "testSpecialClass", "testStaticClass"}) {
|
|
||||||
System.out.printf("%s: ", name);
|
|
||||||
try {
|
|
||||||
cls.getMethod(name).invoke(cls.newInstance());
|
|
||||||
System.out.println("FAILED");
|
|
||||||
} catch (Throwable e) {
|
|
||||||
if (e instanceof InvocationTargetException &&
|
|
||||||
e.getCause() != null && e.getCause() instanceof IncompatibleClassChangeError) {
|
|
||||||
System.out.println("PASSED");
|
|
||||||
success++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (success != 4) throw new Exception("Failed to catch ICCE");
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue