mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-23 04:24:49 +02:00
Merge
This commit is contained in:
commit
39b0e57fdd
5098 changed files with 176905 additions and 81175 deletions
|
@ -30,11 +30,8 @@
|
|||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
#include "utilities/top.hpp"
|
||||
#ifdef TARGET_ARCH_MODEL_x86_32
|
||||
# include "interp_masm_x86_32.hpp"
|
||||
#endif
|
||||
#ifdef TARGET_ARCH_MODEL_x86_64
|
||||
# include "interp_masm_x86_64.hpp"
|
||||
#ifdef TARGET_ARCH_x86
|
||||
# include "interp_masm_x86.hpp"
|
||||
#endif
|
||||
#ifdef TARGET_ARCH_MODEL_sparc
|
||||
# include "interp_masm_sparc.hpp"
|
||||
|
@ -164,8 +161,8 @@ class AbstractInterpreter: AllStatic {
|
|||
// Runtime support
|
||||
|
||||
// length = invoke bytecode length (to advance to next bytecode)
|
||||
static address deopt_entry (TosState state, int length) { ShouldNotReachHere(); return NULL; }
|
||||
static address return_entry (TosState state, int length) { ShouldNotReachHere(); return NULL; }
|
||||
static address deopt_entry(TosState state, int length) { ShouldNotReachHere(); return NULL; }
|
||||
static address return_entry(TosState state, int length, Bytecodes::Code code) { ShouldNotReachHere(); return NULL; }
|
||||
|
||||
static address rethrow_exception_entry() { return _rethrow_exception_entry; }
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ void print_oop(oop value, outputStream* st) {
|
|||
st->print_cr(" %s", buf);
|
||||
}
|
||||
} else {
|
||||
st->print_cr(" " PTR_FORMAT, (intptr_t) value);
|
||||
st->print_cr(" " PTR_FORMAT, (void *)value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ class CppInterpreter: public AbstractInterpreter {
|
|||
static address stack_result_to_stack(int index) { return _stack_to_stack[index]; }
|
||||
static address stack_result_to_native(int index) { return _stack_to_native_abi[index]; }
|
||||
|
||||
static address return_entry (TosState state, int length);
|
||||
static address return_entry (TosState state, int length, Bytecodes::Code code);
|
||||
static address deopt_entry (TosState state, int length);
|
||||
|
||||
#ifdef TARGET_ARCH_x86
|
||||
|
|
|
@ -329,15 +329,21 @@ void AbstractInterpreter::print_method_kind(MethodKind kind) {
|
|||
//------------------------------------------------------------------------------------------------------------------------
|
||||
// Deoptimization support
|
||||
|
||||
// If deoptimization happens, this function returns the point of next bytecode to continue execution
|
||||
/**
|
||||
* If a deoptimization happens, this function returns the point of next bytecode to continue execution.
|
||||
*/
|
||||
address AbstractInterpreter::deopt_continue_after_entry(Method* method, address bcp, int callee_parameters, bool is_top_frame) {
|
||||
assert(method->contains(bcp), "just checkin'");
|
||||
Bytecodes::Code code = Bytecodes::java_code_at(method, bcp);
|
||||
|
||||
// Get the original and rewritten bytecode.
|
||||
Bytecodes::Code code = Bytecodes::java_code_at(method, bcp);
|
||||
assert(!Interpreter::bytecode_should_reexecute(code), "should not reexecute");
|
||||
int bci = method->bci_from(bcp);
|
||||
int length = -1; // initial value for debugging
|
||||
|
||||
const int bci = method->bci_from(bcp);
|
||||
|
||||
// compute continuation length
|
||||
length = Bytecodes::length_at(method, bcp);
|
||||
const int length = Bytecodes::length_at(method, bcp);
|
||||
|
||||
// compute result type
|
||||
BasicType type = T_ILLEGAL;
|
||||
|
||||
|
@ -393,7 +399,7 @@ address AbstractInterpreter::deopt_continue_after_entry(Method* method, address
|
|||
return
|
||||
is_top_frame
|
||||
? Interpreter::deopt_entry (as_TosState(type), length)
|
||||
: Interpreter::return_entry(as_TosState(type), length);
|
||||
: Interpreter::return_entry(as_TosState(type), length, code);
|
||||
}
|
||||
|
||||
// If deoptimization happens, this function returns the point where the interpreter reexecutes
|
||||
|
|
|
@ -523,15 +523,15 @@ IRT_END
|
|||
|
||||
IRT_ENTRY(void, InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecodes::Code bytecode))
|
||||
// resolve field
|
||||
FieldAccessInfo info;
|
||||
fieldDescriptor info;
|
||||
constantPoolHandle pool(thread, method(thread)->constants());
|
||||
bool is_put = (bytecode == Bytecodes::_putfield || bytecode == Bytecodes::_putstatic);
|
||||
bool is_static = (bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic);
|
||||
|
||||
{
|
||||
JvmtiHideSingleStepping jhss(thread);
|
||||
LinkResolver::resolve_field(info, pool, get_index_u2_cpcache(thread, bytecode),
|
||||
bytecode, false, CHECK);
|
||||
LinkResolver::resolve_field_access(info, pool, get_index_u2_cpcache(thread, bytecode),
|
||||
bytecode, CHECK);
|
||||
} // end JvmtiHideSingleStepping
|
||||
|
||||
// check if link resolution caused cpCache to be updated
|
||||
|
@ -551,7 +551,7 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecode
|
|||
// class is intitialized. This is required so that access to the static
|
||||
// field will call the initialization function every time until the class
|
||||
// is completely initialized ala. in 2.17.5 in JVM Specification.
|
||||
InstanceKlass *klass = InstanceKlass::cast(info.klass()());
|
||||
InstanceKlass* klass = InstanceKlass::cast(info.field_holder());
|
||||
bool uninitialized_static = ((bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic) &&
|
||||
!klass->is_initialized());
|
||||
Bytecodes::Code get_code = (Bytecodes::Code)0;
|
||||
|
@ -566,9 +566,9 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecode
|
|||
cache_entry(thread)->set_field(
|
||||
get_code,
|
||||
put_code,
|
||||
info.klass(),
|
||||
info.field_index(),
|
||||
info.field_offset(),
|
||||
info.field_holder(),
|
||||
info.index(),
|
||||
info.offset(),
|
||||
state,
|
||||
info.access_flags().is_final(),
|
||||
info.access_flags().is_volatile(),
|
||||
|
@ -713,29 +713,55 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes
|
|||
if (already_resolved(thread)) return;
|
||||
|
||||
if (bytecode == Bytecodes::_invokeinterface) {
|
||||
|
||||
if (TraceItables && Verbose) {
|
||||
ResourceMark rm(thread);
|
||||
tty->print_cr("Resolving: klass: %s to method: %s", info.resolved_klass()->name()->as_C_string(), info.resolved_method()->name()->as_C_string());
|
||||
}
|
||||
}
|
||||
#ifdef ASSERT
|
||||
if (bytecode == Bytecodes::_invokeinterface) {
|
||||
if (info.resolved_method()->method_holder() ==
|
||||
SystemDictionary::Object_klass()) {
|
||||
// NOTE: THIS IS A FIX FOR A CORNER CASE in the JVM spec
|
||||
// (see also cpCacheOop.cpp for details)
|
||||
// (see also CallInfo::set_interface for details)
|
||||
assert(info.call_kind() == CallInfo::vtable_call ||
|
||||
info.call_kind() == CallInfo::direct_call, "");
|
||||
methodHandle rm = info.resolved_method();
|
||||
assert(rm->is_final() || info.has_vtable_index(),
|
||||
"should have been set already");
|
||||
cache_entry(thread)->set_method(bytecode, rm, info.vtable_index());
|
||||
} else if (!info.resolved_method()->has_itable_index()) {
|
||||
// Resolved something like CharSequence.toString. Use vtable not itable.
|
||||
assert(info.call_kind() != CallInfo::itable_call, "");
|
||||
} else {
|
||||
// Setup itable entry
|
||||
int index = klassItable::compute_itable_index(info.resolved_method()());
|
||||
cache_entry(thread)->set_interface_call(info.resolved_method(), index);
|
||||
assert(info.call_kind() == CallInfo::itable_call, "");
|
||||
int index = info.resolved_method()->itable_index();
|
||||
assert(info.itable_index() == index, "");
|
||||
}
|
||||
} else {
|
||||
cache_entry(thread)->set_method(
|
||||
assert(info.call_kind() == CallInfo::direct_call ||
|
||||
info.call_kind() == CallInfo::vtable_call, "");
|
||||
}
|
||||
#endif
|
||||
switch (info.call_kind()) {
|
||||
case CallInfo::direct_call:
|
||||
cache_entry(thread)->set_direct_call(
|
||||
bytecode,
|
||||
info.resolved_method());
|
||||
break;
|
||||
case CallInfo::vtable_call:
|
||||
cache_entry(thread)->set_vtable_call(
|
||||
bytecode,
|
||||
info.resolved_method(),
|
||||
info.vtable_index());
|
||||
break;
|
||||
case CallInfo::itable_call:
|
||||
cache_entry(thread)->set_itable_call(
|
||||
bytecode,
|
||||
info.resolved_method(),
|
||||
info.itable_index());
|
||||
break;
|
||||
default: ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
IRT_END
|
||||
|
|
|
@ -46,19 +46,6 @@
|
|||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
// Implementation of FieldAccessInfo
|
||||
|
||||
void FieldAccessInfo::set(KlassHandle klass, Symbol* name, int field_index, int field_offset,
|
||||
BasicType field_type, AccessFlags access_flags) {
|
||||
_klass = klass;
|
||||
_name = name;
|
||||
_field_index = field_index;
|
||||
_field_offset = field_offset;
|
||||
_field_type = field_type;
|
||||
_access_flags = access_flags;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
// Implementation of CallInfo
|
||||
|
@ -66,26 +53,25 @@ BasicType field_type, AccessFlags access_flags) {
|
|||
|
||||
void CallInfo::set_static(KlassHandle resolved_klass, methodHandle resolved_method, TRAPS) {
|
||||
int vtable_index = Method::nonvirtual_vtable_index;
|
||||
set_common(resolved_klass, resolved_klass, resolved_method, resolved_method, vtable_index, CHECK);
|
||||
set_common(resolved_klass, resolved_klass, resolved_method, resolved_method, CallInfo::direct_call, vtable_index, CHECK);
|
||||
}
|
||||
|
||||
|
||||
void CallInfo::set_interface(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, TRAPS) {
|
||||
void CallInfo::set_interface(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int itable_index, TRAPS) {
|
||||
// This is only called for interface methods. If the resolved_method
|
||||
// comes from java/lang/Object, it can be the subject of a virtual call, so
|
||||
// we should pick the vtable index from the resolved method.
|
||||
// Other than that case, there is no valid vtable index to specify.
|
||||
int vtable_index = Method::invalid_vtable_index;
|
||||
if (resolved_method->method_holder() == SystemDictionary::Object_klass()) {
|
||||
assert(resolved_method->vtable_index() == selected_method->vtable_index(), "sanity check");
|
||||
vtable_index = resolved_method->vtable_index();
|
||||
}
|
||||
set_common(resolved_klass, selected_klass, resolved_method, selected_method, vtable_index, CHECK);
|
||||
// In that case, the caller must call set_virtual instead of set_interface.
|
||||
assert(resolved_method->method_holder()->is_interface(), "");
|
||||
assert(itable_index == resolved_method()->itable_index(), "");
|
||||
set_common(resolved_klass, selected_klass, resolved_method, selected_method, CallInfo::itable_call, itable_index, CHECK);
|
||||
}
|
||||
|
||||
void CallInfo::set_virtual(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS) {
|
||||
assert(vtable_index >= 0 || vtable_index == Method::nonvirtual_vtable_index, "valid index");
|
||||
set_common(resolved_klass, selected_klass, resolved_method, selected_method, vtable_index, CHECK);
|
||||
assert(vtable_index < 0 || !resolved_method->has_vtable_index() || vtable_index == resolved_method->vtable_index(), "");
|
||||
CallKind kind = (vtable_index >= 0 && !resolved_method->can_be_statically_bound() ? CallInfo::vtable_call : CallInfo::direct_call);
|
||||
set_common(resolved_klass, selected_klass, resolved_method, selected_method, kind, vtable_index, CHECK);
|
||||
assert(!resolved_method->is_compiled_lambda_form(), "these must be handled via an invokehandle call");
|
||||
}
|
||||
|
||||
|
@ -98,20 +84,29 @@ void CallInfo::set_handle(methodHandle resolved_method, Handle resolved_appendix
|
|||
resolved_method->is_compiled_lambda_form(),
|
||||
"linkMethod must return one of these");
|
||||
int vtable_index = Method::nonvirtual_vtable_index;
|
||||
assert(resolved_method->vtable_index() == vtable_index, "");
|
||||
set_common(resolved_klass, resolved_klass, resolved_method, resolved_method, vtable_index, CHECK);
|
||||
assert(!resolved_method->has_vtable_index(), "");
|
||||
set_common(resolved_klass, resolved_klass, resolved_method, resolved_method, CallInfo::direct_call, vtable_index, CHECK);
|
||||
_resolved_appendix = resolved_appendix;
|
||||
_resolved_method_type = resolved_method_type;
|
||||
}
|
||||
|
||||
void CallInfo::set_common(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS) {
|
||||
void CallInfo::set_common(KlassHandle resolved_klass,
|
||||
KlassHandle selected_klass,
|
||||
methodHandle resolved_method,
|
||||
methodHandle selected_method,
|
||||
CallKind kind,
|
||||
int index,
|
||||
TRAPS) {
|
||||
assert(resolved_method->signature() == selected_method->signature(), "signatures must correspond");
|
||||
_resolved_klass = resolved_klass;
|
||||
_selected_klass = selected_klass;
|
||||
_resolved_method = resolved_method;
|
||||
_selected_method = selected_method;
|
||||
_vtable_index = vtable_index;
|
||||
_call_kind = kind;
|
||||
_call_index = index;
|
||||
_resolved_appendix = Handle();
|
||||
DEBUG_ONLY(verify()); // verify before making side effects
|
||||
|
||||
if (CompilationPolicy::must_be_compiled(selected_method)) {
|
||||
// This path is unusual, mostly used by the '-Xcomp' stress test mode.
|
||||
|
||||
|
@ -138,6 +133,81 @@ void CallInfo::set_common(KlassHandle resolved_klass, KlassHandle selected_klass
|
|||
}
|
||||
}
|
||||
|
||||
// utility query for unreflecting a method
|
||||
CallInfo::CallInfo(Method* resolved_method, Klass* resolved_klass) {
|
||||
Klass* resolved_method_holder = resolved_method->method_holder();
|
||||
if (resolved_klass == NULL) { // 2nd argument defaults to holder of 1st
|
||||
resolved_klass = resolved_method_holder;
|
||||
}
|
||||
_resolved_klass = resolved_klass;
|
||||
_selected_klass = resolved_klass;
|
||||
_resolved_method = resolved_method;
|
||||
_selected_method = resolved_method;
|
||||
// classify:
|
||||
CallKind kind = CallInfo::unknown_kind;
|
||||
int index = resolved_method->vtable_index();
|
||||
if (resolved_method->can_be_statically_bound()) {
|
||||
kind = CallInfo::direct_call;
|
||||
} else if (!resolved_method_holder->is_interface()) {
|
||||
// Could be an Object method inherited into an interface, but still a vtable call.
|
||||
kind = CallInfo::vtable_call;
|
||||
} else if (!resolved_klass->is_interface()) {
|
||||
// A miranda method. Compute the vtable index.
|
||||
ResourceMark rm;
|
||||
klassVtable* vt = InstanceKlass::cast(resolved_klass)->vtable();
|
||||
index = vt->index_of_miranda(resolved_method->name(),
|
||||
resolved_method->signature());
|
||||
kind = CallInfo::vtable_call;
|
||||
} else if (resolved_method->has_vtable_index()) {
|
||||
// Can occur if an interface redeclares a method of Object.
|
||||
|
||||
#ifdef ASSERT
|
||||
// Ensure that this is really the case.
|
||||
KlassHandle object_klass = SystemDictionary::Object_klass();
|
||||
Method * object_resolved_method = object_klass()->vtable()->method_at(index);
|
||||
assert(object_resolved_method->name() == resolved_method->name(),
|
||||
err_msg("Object and interface method names should match at vtable index %d, %s != %s",
|
||||
index, object_resolved_method->name()->as_C_string(), resolved_method->name()->as_C_string()));
|
||||
assert(object_resolved_method->signature() == resolved_method->signature(),
|
||||
err_msg("Object and interface method signatures should match at vtable index %d, %s != %s",
|
||||
index, object_resolved_method->signature()->as_C_string(), resolved_method->signature()->as_C_string()));
|
||||
#endif // ASSERT
|
||||
|
||||
kind = CallInfo::vtable_call;
|
||||
} else {
|
||||
// A regular interface call.
|
||||
kind = CallInfo::itable_call;
|
||||
index = resolved_method->itable_index();
|
||||
}
|
||||
assert(index == Method::nonvirtual_vtable_index || index >= 0, err_msg("bad index %d", index));
|
||||
_call_kind = kind;
|
||||
_call_index = index;
|
||||
_resolved_appendix = Handle();
|
||||
DEBUG_ONLY(verify());
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
void CallInfo::verify() {
|
||||
switch (call_kind()) { // the meaning and allowed value of index depends on kind
|
||||
case CallInfo::direct_call:
|
||||
if (_call_index == Method::nonvirtual_vtable_index) break;
|
||||
// else fall through to check vtable index:
|
||||
case CallInfo::vtable_call:
|
||||
assert(resolved_klass()->verify_vtable_index(_call_index), "");
|
||||
break;
|
||||
case CallInfo::itable_call:
|
||||
assert(resolved_method()->method_holder()->verify_itable_index(_call_index), "");
|
||||
break;
|
||||
case CallInfo::unknown_kind:
|
||||
assert(call_kind() != CallInfo::unknown_kind, "CallInfo must be set");
|
||||
break;
|
||||
default:
|
||||
fatal(err_msg_res("Unexpected call kind %d", call_kind()));
|
||||
}
|
||||
}
|
||||
#endif //ASSERT
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
// Klass resolution
|
||||
|
@ -163,20 +233,22 @@ void LinkResolver::resolve_klass(KlassHandle& result, constantPoolHandle pool, i
|
|||
result = KlassHandle(THREAD, result_oop);
|
||||
}
|
||||
|
||||
void LinkResolver::resolve_klass_no_update(KlassHandle& result, constantPoolHandle pool, int index, TRAPS) {
|
||||
Klass* result_oop =
|
||||
ConstantPool::klass_ref_at_if_loaded_check(pool, index, CHECK);
|
||||
result = KlassHandle(THREAD, result_oop);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
// Method resolution
|
||||
//
|
||||
// According to JVM spec. $5.4.3c & $5.4.3d
|
||||
|
||||
// Look up method in klasses, including static methods
|
||||
// Then look up local default methods
|
||||
void LinkResolver::lookup_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) {
|
||||
Method* result_oop = klass->uncached_lookup_method(name, signature);
|
||||
if (result_oop == NULL) {
|
||||
Array<Method*>* default_methods = InstanceKlass::cast(klass())->default_methods();
|
||||
if (default_methods != NULL) {
|
||||
result_oop = InstanceKlass::find_method(default_methods, name, signature);
|
||||
}
|
||||
}
|
||||
|
||||
if (EnableInvokeDynamic && result_oop != NULL) {
|
||||
vmIntrinsics::ID iid = result_oop->intrinsic_id();
|
||||
if (MethodHandles::is_signature_polymorphic(iid)) {
|
||||
|
@ -188,20 +260,46 @@ void LinkResolver::lookup_method_in_klasses(methodHandle& result, KlassHandle kl
|
|||
}
|
||||
|
||||
// returns first instance method
|
||||
// Looks up method in classes, then looks up local default methods
|
||||
void LinkResolver::lookup_instance_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) {
|
||||
Method* result_oop = klass->uncached_lookup_method(name, signature);
|
||||
result = methodHandle(THREAD, result_oop);
|
||||
while (!result.is_null() && result->is_static()) {
|
||||
while (!result.is_null() && result->is_static() && result->method_holder()->super() != NULL) {
|
||||
klass = KlassHandle(THREAD, result->method_holder()->super());
|
||||
result = methodHandle(THREAD, klass->uncached_lookup_method(name, signature));
|
||||
}
|
||||
|
||||
if (result.is_null()) {
|
||||
Array<Method*>* default_methods = InstanceKlass::cast(klass())->default_methods();
|
||||
if (default_methods != NULL) {
|
||||
result = methodHandle(InstanceKlass::find_method(default_methods, name, signature));
|
||||
assert(result.is_null() || !result->is_static(), "static defaults not allowed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int LinkResolver::vtable_index_of_interface_method(KlassHandle klass,
|
||||
methodHandle resolved_method, TRAPS) {
|
||||
|
||||
int LinkResolver::vtable_index_of_miranda_method(KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) {
|
||||
ResourceMark rm(THREAD);
|
||||
klassVtable *vt = InstanceKlass::cast(klass())->vtable();
|
||||
return vt->index_of_miranda(name, signature);
|
||||
int vtable_index = Method::invalid_vtable_index;
|
||||
Symbol* name = resolved_method->name();
|
||||
Symbol* signature = resolved_method->signature();
|
||||
|
||||
// First check in default method array
|
||||
if (!resolved_method->is_abstract() &&
|
||||
(InstanceKlass::cast(klass())->default_methods() != NULL)) {
|
||||
int index = InstanceKlass::find_method_index(InstanceKlass::cast(klass())->default_methods(), name, signature);
|
||||
if (index >= 0 ) {
|
||||
vtable_index = InstanceKlass::cast(klass())->default_vtable_indices()->at(index);
|
||||
}
|
||||
}
|
||||
if (vtable_index == Method::invalid_vtable_index) {
|
||||
// get vtable_index for miranda methods
|
||||
ResourceMark rm(THREAD);
|
||||
klassVtable *vt = InstanceKlass::cast(klass())->vtable();
|
||||
vtable_index = vt->index_of_miranda(name, signature);
|
||||
}
|
||||
return vtable_index;
|
||||
}
|
||||
|
||||
void LinkResolver::lookup_method_in_interfaces(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) {
|
||||
|
@ -320,18 +418,28 @@ void LinkResolver::check_method_accessability(KlassHandle ref_klass,
|
|||
|
||||
AccessFlags flags = sel_method->access_flags();
|
||||
|
||||
// Special case: arrays always override "clone". JVMS 2.15.
|
||||
// Special case #1: arrays always override "clone". JVMS 2.15.
|
||||
// If the resolved klass is an array class, and the declaring class
|
||||
// is java.lang.Object and the method is "clone", set the flags
|
||||
// to public.
|
||||
// Special case #2: If the resolved klass is an interface, and
|
||||
// the declaring class is java.lang.Object, and the method is
|
||||
// "clone" or "finalize", set the flags to public. If the
|
||||
// resolved interface does not contain "clone" or "finalize"
|
||||
// methods, the method/interface method resolution looks to
|
||||
// the interface's super class, java.lang.Object. With JDK 8
|
||||
// interface accessability check requirement, special casing
|
||||
// this scenario is necessary to avoid an IAE.
|
||||
//
|
||||
// We'll check for the method name first, as that's most likely
|
||||
// to be false (so we'll short-circuit out of these tests).
|
||||
if (sel_method->name() == vmSymbols::clone_name() &&
|
||||
sel_klass() == SystemDictionary::Object_klass() &&
|
||||
resolved_klass->oop_is_array()) {
|
||||
// We'll check for each method name first and then java.lang.Object
|
||||
// to best short-circuit out of these tests.
|
||||
if (((sel_method->name() == vmSymbols::clone_name() &&
|
||||
(resolved_klass->oop_is_array() || resolved_klass->is_interface())) ||
|
||||
(sel_method->name() == vmSymbols::finalize_method_name() &&
|
||||
resolved_klass->is_interface())) &&
|
||||
sel_klass() == SystemDictionary::Object_klass()) {
|
||||
// We need to change "protected" to "public".
|
||||
assert(flags.is_protected(), "clone not protected?");
|
||||
assert(flags.is_protected(), "clone or finalize not protected?");
|
||||
jint new_flags = flags.as_int();
|
||||
new_flags = new_flags & (~JVM_ACC_PROTECTED);
|
||||
new_flags = new_flags | JVM_ACC_PUBLIC;
|
||||
|
@ -360,14 +468,19 @@ void LinkResolver::check_method_accessability(KlassHandle ref_klass,
|
|||
|
||||
void LinkResolver::resolve_method_statically(methodHandle& resolved_method, KlassHandle& resolved_klass,
|
||||
Bytecodes::Code code, constantPoolHandle pool, int index, TRAPS) {
|
||||
|
||||
// This method is used only
|
||||
// (1) in C2 from InlineTree::ok_to_inline (via ciMethod::check_call),
|
||||
// and
|
||||
// (2) in Bytecode_invoke::static_target
|
||||
// It appears to fail when applied to an invokeinterface call site.
|
||||
// FIXME: Remove this method and ciMethod::check_call; refactor to use the other LinkResolver entry points.
|
||||
// resolve klass
|
||||
if (code == Bytecodes::_invokedynamic) {
|
||||
resolved_klass = SystemDictionary::MethodHandle_klass();
|
||||
Symbol* method_name = vmSymbols::invoke_name();
|
||||
Symbol* method_signature = pool->signature_ref_at(index);
|
||||
KlassHandle current_klass(THREAD, pool->pool_holder());
|
||||
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK);
|
||||
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, false, CHECK);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -389,22 +502,34 @@ void LinkResolver::resolve_method_statically(methodHandle& resolved_method, Klas
|
|||
|
||||
if (code == Bytecodes::_invokeinterface) {
|
||||
resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK);
|
||||
} else if (code == Bytecodes::_invokevirtual) {
|
||||
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, true, CHECK);
|
||||
} else {
|
||||
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK);
|
||||
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, false, CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
void LinkResolver::resolve_method(methodHandle& resolved_method, KlassHandle resolved_klass,
|
||||
Symbol* method_name, Symbol* method_signature,
|
||||
KlassHandle current_klass, bool check_access, TRAPS) {
|
||||
KlassHandle current_klass, bool check_access,
|
||||
bool require_methodref, TRAPS) {
|
||||
|
||||
Handle nested_exception;
|
||||
|
||||
// 1. lookup method in resolved klass and its super klasses
|
||||
// 1. check if methodref required, that resolved_klass is not interfacemethodref
|
||||
if (require_methodref && resolved_klass->is_interface()) {
|
||||
ResourceMark rm(THREAD);
|
||||
char buf[200];
|
||||
jio_snprintf(buf, sizeof(buf), "Found interface %s, but class was expected",
|
||||
resolved_klass()->external_name());
|
||||
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
||||
}
|
||||
|
||||
// 2. lookup method in resolved klass and its super klasses
|
||||
lookup_method_in_klasses(resolved_method, resolved_klass, method_name, method_signature, CHECK);
|
||||
|
||||
if (resolved_method.is_null()) { // not found in the class hierarchy
|
||||
// 2. lookup method in all the interfaces implemented by the resolved klass
|
||||
// 3. lookup method in all the interfaces implemented by the resolved klass
|
||||
lookup_method_in_interfaces(resolved_method, resolved_klass, method_name, method_signature, CHECK);
|
||||
|
||||
if (resolved_method.is_null()) {
|
||||
|
@ -418,7 +543,7 @@ void LinkResolver::resolve_method(methodHandle& resolved_method, KlassHandle res
|
|||
}
|
||||
|
||||
if (resolved_method.is_null()) {
|
||||
// 3. method lookup failed
|
||||
// 4. method lookup failed
|
||||
ResourceMark rm(THREAD);
|
||||
THROW_MSG_CAUSE(vmSymbols::java_lang_NoSuchMethodError(),
|
||||
Method::name_and_sig_as_C_string(resolved_klass(),
|
||||
|
@ -428,15 +553,6 @@ void LinkResolver::resolve_method(methodHandle& resolved_method, KlassHandle res
|
|||
}
|
||||
}
|
||||
|
||||
// 4. check if klass is not interface
|
||||
if (resolved_klass->is_interface() && resolved_method->is_abstract()) {
|
||||
ResourceMark rm(THREAD);
|
||||
char buf[200];
|
||||
jio_snprintf(buf, sizeof(buf), "Found interface %s, but class was expected",
|
||||
resolved_klass()->external_name());
|
||||
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
||||
}
|
||||
|
||||
// 5. check if method is concrete
|
||||
if (resolved_method->is_abstract() && !resolved_klass->is_abstract()) {
|
||||
ResourceMark rm(THREAD);
|
||||
|
@ -521,6 +637,16 @@ void LinkResolver::resolve_interface_method(methodHandle& resolved_method,
|
|||
}
|
||||
|
||||
if (check_access) {
|
||||
// JDK8 adds non-public interface methods, and accessability check requirement
|
||||
assert(current_klass.not_null() , "current_klass should not be null");
|
||||
|
||||
// check if method can be accessed by the referring class
|
||||
check_method_accessability(current_klass,
|
||||
resolved_klass,
|
||||
KlassHandle(THREAD, resolved_method->method_holder()),
|
||||
resolved_method,
|
||||
CHECK);
|
||||
|
||||
HandleMark hm(THREAD);
|
||||
Handle loader (THREAD, InstanceKlass::cast(current_klass())->class_loader());
|
||||
Handle class_loader (THREAD, resolved_method->method_holder()->class_loader());
|
||||
|
@ -552,6 +678,26 @@ void LinkResolver::resolve_interface_method(methodHandle& resolved_method,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (TraceItables && Verbose) {
|
||||
ResourceMark rm(THREAD);
|
||||
tty->print("invokeinterface resolved method: caller-class:%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ",
|
||||
(current_klass.is_null() ? "<NULL>" : current_klass->internal_name()),
|
||||
(resolved_klass.is_null() ? "<NULL>" : resolved_klass->internal_name()),
|
||||
Method::name_and_sig_as_C_string(resolved_klass(),
|
||||
resolved_method->name(),
|
||||
resolved_method->signature()),
|
||||
resolved_method->method_holder()->internal_name()
|
||||
);
|
||||
resolved_method->access_flags().print_on(tty);
|
||||
if (resolved_method->is_default_method()) {
|
||||
tty->print("default");
|
||||
}
|
||||
if (resolved_method->is_overpass()) {
|
||||
tty->print("overpass");
|
||||
}
|
||||
tty->cr();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
|
@ -580,45 +726,49 @@ void LinkResolver::check_field_accessability(KlassHandle ref_klass,
|
|||
}
|
||||
}
|
||||
|
||||
void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle pool, int index, Bytecodes::Code byte, bool check_only, TRAPS) {
|
||||
resolve_field(result, pool, index, byte, check_only, true, CHECK);
|
||||
void LinkResolver::resolve_field_access(fieldDescriptor& result, constantPoolHandle pool, int index, Bytecodes::Code byte, TRAPS) {
|
||||
// Load these early in case the resolve of the containing klass fails
|
||||
Symbol* field = pool->name_ref_at(index);
|
||||
Symbol* sig = pool->signature_ref_at(index);
|
||||
|
||||
// resolve specified klass
|
||||
KlassHandle resolved_klass;
|
||||
resolve_klass(resolved_klass, pool, index, CHECK);
|
||||
|
||||
KlassHandle current_klass(THREAD, pool->pool_holder());
|
||||
resolve_field(result, resolved_klass, field, sig, current_klass, byte, true, true, CHECK);
|
||||
}
|
||||
|
||||
void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle pool, int index, Bytecodes::Code byte, bool check_only, bool update_pool, TRAPS) {
|
||||
void LinkResolver::resolve_field(fieldDescriptor& fd, KlassHandle resolved_klass, Symbol* field, Symbol* sig,
|
||||
KlassHandle current_klass, Bytecodes::Code byte, bool check_access, bool initialize_class,
|
||||
TRAPS) {
|
||||
assert(byte == Bytecodes::_getstatic || byte == Bytecodes::_putstatic ||
|
||||
byte == Bytecodes::_getfield || byte == Bytecodes::_putfield, "bad bytecode");
|
||||
byte == Bytecodes::_getfield || byte == Bytecodes::_putfield ||
|
||||
(byte == Bytecodes::_nop && !check_access), "bad field access bytecode");
|
||||
|
||||
bool is_static = (byte == Bytecodes::_getstatic || byte == Bytecodes::_putstatic);
|
||||
bool is_put = (byte == Bytecodes::_putfield || byte == Bytecodes::_putstatic);
|
||||
|
||||
// resolve specified klass
|
||||
KlassHandle resolved_klass;
|
||||
if (update_pool) {
|
||||
resolve_klass(resolved_klass, pool, index, CHECK);
|
||||
} else {
|
||||
resolve_klass_no_update(resolved_klass, pool, index, CHECK);
|
||||
}
|
||||
// Load these early in case the resolve of the containing klass fails
|
||||
Symbol* field = pool->name_ref_at(index);
|
||||
Symbol* sig = pool->signature_ref_at(index);
|
||||
// Check if there's a resolved klass containing the field
|
||||
if( resolved_klass.is_null() ) {
|
||||
if (resolved_klass.is_null()) {
|
||||
ResourceMark rm(THREAD);
|
||||
THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), field->as_C_string());
|
||||
}
|
||||
|
||||
// Resolve instance field
|
||||
fieldDescriptor fd; // find_field initializes fd if found
|
||||
KlassHandle sel_klass(THREAD, InstanceKlass::cast(resolved_klass())->find_field(field, sig, &fd));
|
||||
// check if field exists; i.e., if a klass containing the field def has been selected
|
||||
if (sel_klass.is_null()){
|
||||
if (sel_klass.is_null()) {
|
||||
ResourceMark rm(THREAD);
|
||||
THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), field->as_C_string());
|
||||
}
|
||||
|
||||
if (!check_access)
|
||||
// Access checking may be turned off when calling from within the VM.
|
||||
return;
|
||||
|
||||
// check access
|
||||
KlassHandle ref_klass(THREAD, pool->pool_holder());
|
||||
check_field_accessability(ref_klass, resolved_klass, sel_klass, fd, CHECK);
|
||||
check_field_accessability(current_klass, resolved_klass, sel_klass, fd, CHECK);
|
||||
|
||||
// check for errors
|
||||
if (is_static != fd.is_static()) {
|
||||
|
@ -629,7 +779,7 @@ void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle poo
|
|||
}
|
||||
|
||||
// Final fields can only be accessed from its own class.
|
||||
if (is_put && fd.access_flags().is_final() && sel_klass() != pool->pool_holder()) {
|
||||
if (is_put && fd.access_flags().is_final() && sel_klass() != current_klass()) {
|
||||
THROW(vmSymbols::java_lang_IllegalAccessError());
|
||||
}
|
||||
|
||||
|
@ -639,19 +789,18 @@ void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle poo
|
|||
//
|
||||
// note 2: we don't want to force initialization if we are just checking
|
||||
// if the field access is legal; e.g., during compilation
|
||||
if (is_static && !check_only) {
|
||||
if (is_static && initialize_class) {
|
||||
sel_klass->initialize(CHECK);
|
||||
}
|
||||
|
||||
{
|
||||
if (sel_klass() != current_klass()) {
|
||||
HandleMark hm(THREAD);
|
||||
Handle ref_loader (THREAD, InstanceKlass::cast(ref_klass())->class_loader());
|
||||
Handle ref_loader (THREAD, InstanceKlass::cast(current_klass())->class_loader());
|
||||
Handle sel_loader (THREAD, InstanceKlass::cast(sel_klass())->class_loader());
|
||||
Symbol* signature_ref = pool->signature_ref_at(index);
|
||||
{
|
||||
ResourceMark rm(THREAD);
|
||||
Symbol* failed_type_symbol =
|
||||
SystemDictionary::check_signature_loaders(signature_ref,
|
||||
SystemDictionary::check_signature_loaders(sig,
|
||||
ref_loader, sel_loader,
|
||||
false,
|
||||
CHECK);
|
||||
|
@ -677,9 +826,6 @@ void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle poo
|
|||
|
||||
// return information. note that the klass is set to the actual klass containing the
|
||||
// field, otherwise access of static fields in superclasses will not work.
|
||||
KlassHandle holder (THREAD, fd.field_holder());
|
||||
Symbol* name = fd.name();
|
||||
result.set(holder, name, fd.index(), fd.offset(), fd.field_type(), fd.access_flags());
|
||||
}
|
||||
|
||||
|
||||
|
@ -716,7 +862,7 @@ void LinkResolver::linktime_resolve_static_method(methodHandle& resolved_method,
|
|||
Symbol* method_name, Symbol* method_signature,
|
||||
KlassHandle current_klass, bool check_access, TRAPS) {
|
||||
|
||||
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK);
|
||||
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, false, CHECK);
|
||||
assert(resolved_method->name() != vmSymbols::class_initializer_name(), "should have been checked in verifier");
|
||||
|
||||
// check if static
|
||||
|
@ -743,28 +889,14 @@ void LinkResolver::linktime_resolve_special_method(methodHandle& resolved_method
|
|||
Symbol* method_name, Symbol* method_signature,
|
||||
KlassHandle current_klass, bool check_access, TRAPS) {
|
||||
|
||||
if (resolved_klass->is_interface() && current_klass() != NULL) {
|
||||
// If the target class is a direct interface, treat this as a "super"
|
||||
// default call.
|
||||
//
|
||||
// If the current method is an overpass that happens to call a direct
|
||||
// super-interface's method, then we'll end up rerunning the default method
|
||||
// analysis even though we don't need to, but that's ok since it will end
|
||||
// up with the same answer.
|
||||
InstanceKlass* ik = InstanceKlass::cast(current_klass());
|
||||
Array<Klass*>* interfaces = ik->local_interfaces();
|
||||
int num_interfaces = interfaces->length();
|
||||
for (int index = 0; index < num_interfaces; index++) {
|
||||
if (interfaces->at(index) == resolved_klass()) {
|
||||
Method* method = DefaultMethods::find_super_default(current_klass(),
|
||||
resolved_klass(), method_name, method_signature, CHECK);
|
||||
resolved_method = methodHandle(THREAD, method);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Invokespecial is called for multiple special reasons:
|
||||
// <init>
|
||||
// local private method invocation, for classes and interfaces
|
||||
// superclass.method, which can also resolve to a default method
|
||||
// and the selected method is recalculated relative to the direct superclass
|
||||
// superinterface.method, which explicitly does not check shadowing
|
||||
|
||||
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK);
|
||||
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, false, CHECK);
|
||||
|
||||
// check if method name is <init>, that it is found in same klass as static type
|
||||
if (resolved_method->name() == vmSymbols::object_initializer_name() &&
|
||||
|
@ -792,6 +924,26 @@ void LinkResolver::linktime_resolve_special_method(methodHandle& resolved_method
|
|||
resolved_method->signature()));
|
||||
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
||||
}
|
||||
|
||||
if (TraceItables && Verbose) {
|
||||
ResourceMark rm(THREAD);
|
||||
tty->print("invokespecial resolved method: caller-class:%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ",
|
||||
(current_klass.is_null() ? "<NULL>" : current_klass->internal_name()),
|
||||
(resolved_klass.is_null() ? "<NULL>" : resolved_klass->internal_name()),
|
||||
Method::name_and_sig_as_C_string(resolved_klass(),
|
||||
resolved_method->name(),
|
||||
resolved_method->signature()),
|
||||
resolved_method->method_holder()->internal_name()
|
||||
);
|
||||
resolved_method->access_flags().print_on(tty);
|
||||
if (resolved_method->is_default_method()) {
|
||||
tty->print("default");
|
||||
}
|
||||
if (resolved_method->is_overpass()) {
|
||||
tty->print("overpass");
|
||||
}
|
||||
tty->cr();
|
||||
}
|
||||
}
|
||||
|
||||
// throws runtime exceptions
|
||||
|
@ -799,23 +951,24 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result, methodHandle
|
|||
KlassHandle current_klass, bool check_access, TRAPS) {
|
||||
|
||||
// resolved method is selected method unless we have an old-style lookup
|
||||
// for a superclass method
|
||||
// Invokespecial for a superinterface, resolved method is selected method,
|
||||
// no checks for shadowing
|
||||
methodHandle sel_method(THREAD, resolved_method());
|
||||
|
||||
// check if this is an old-style super call and do a new lookup if so
|
||||
{ KlassHandle method_klass = KlassHandle(THREAD,
|
||||
resolved_method->method_holder());
|
||||
|
||||
const bool direct_calling_default_method =
|
||||
resolved_klass() != NULL && resolved_method() != NULL &&
|
||||
resolved_klass->is_interface() && !resolved_method->is_abstract();
|
||||
|
||||
if (!direct_calling_default_method &&
|
||||
check_access &&
|
||||
if (check_access &&
|
||||
// a) check if ACC_SUPER flag is set for the current class
|
||||
(current_klass->is_super() || !AllowNonVirtualCalls) &&
|
||||
// b) check if the method class is a superclass of the current class (superclass relation is not reflexive!)
|
||||
current_klass->is_subtype_of(method_klass()) &&
|
||||
current_klass() != method_klass() &&
|
||||
// b) check if the class of the resolved_klass is a superclass
|
||||
// (not supertype in order to exclude interface classes) of the current class.
|
||||
// This check is not performed for super.invoke for interface methods
|
||||
// in super interfaces.
|
||||
current_klass->is_subclass_of(resolved_klass()) &&
|
||||
current_klass() != resolved_klass() &&
|
||||
// c) check if the method is not <init>
|
||||
resolved_method->name() != vmSymbols::object_initializer_name()) {
|
||||
// Lookup super method
|
||||
|
@ -853,6 +1006,25 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result, methodHandle
|
|||
sel_method->signature()));
|
||||
}
|
||||
|
||||
if (TraceItables && Verbose) {
|
||||
ResourceMark rm(THREAD);
|
||||
tty->print("invokespecial selected method: resolved-class:%s, method:%s, method_holder:%s, access_flags: ",
|
||||
(resolved_klass.is_null() ? "<NULL>" : resolved_klass->internal_name()),
|
||||
Method::name_and_sig_as_C_string(resolved_klass(),
|
||||
sel_method->name(),
|
||||
sel_method->signature()),
|
||||
sel_method->method_holder()->internal_name()
|
||||
);
|
||||
sel_method->access_flags().print_on(tty);
|
||||
if (sel_method->is_default_method()) {
|
||||
tty->print("default");
|
||||
}
|
||||
if (sel_method->is_overpass()) {
|
||||
tty->print("overpass");
|
||||
}
|
||||
tty->cr();
|
||||
}
|
||||
|
||||
// setup result
|
||||
result.set_static(resolved_klass, sel_method, CHECK);
|
||||
}
|
||||
|
@ -870,11 +1042,23 @@ void LinkResolver::linktime_resolve_virtual_method(methodHandle &resolved_method
|
|||
Symbol* method_name, Symbol* method_signature,
|
||||
KlassHandle current_klass, bool check_access, TRAPS) {
|
||||
// normal method resolution
|
||||
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK);
|
||||
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, true, CHECK);
|
||||
|
||||
assert(resolved_method->name() != vmSymbols::object_initializer_name(), "should have been checked in verifier");
|
||||
assert(resolved_method->name() != vmSymbols::class_initializer_name (), "should have been checked in verifier");
|
||||
|
||||
// check if private interface method
|
||||
if (resolved_klass->is_interface() && resolved_method->is_private()) {
|
||||
ResourceMark rm(THREAD);
|
||||
char buf[200];
|
||||
jio_snprintf(buf, sizeof(buf), "private interface method requires invokespecial, not invokevirtual: method %s, caller-class:%s",
|
||||
Method::name_and_sig_as_C_string(resolved_klass(),
|
||||
resolved_method->name(),
|
||||
resolved_method->signature()),
|
||||
(current_klass.is_null() ? "<NULL>" : current_klass->internal_name()));
|
||||
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
||||
}
|
||||
|
||||
// check if not static
|
||||
if (resolved_method->is_static()) {
|
||||
ResourceMark rm(THREAD);
|
||||
|
@ -884,6 +1068,26 @@ void LinkResolver::linktime_resolve_virtual_method(methodHandle &resolved_method
|
|||
resolved_method->signature()));
|
||||
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
||||
}
|
||||
|
||||
if (PrintVtables && Verbose) {
|
||||
ResourceMark rm(THREAD);
|
||||
tty->print("invokevirtual resolved method: caller-class:%s, compile-time-class:%s, method:%s, method_holder:%s, access_flags: ",
|
||||
(current_klass.is_null() ? "<NULL>" : current_klass->internal_name()),
|
||||
(resolved_klass.is_null() ? "<NULL>" : resolved_klass->internal_name()),
|
||||
Method::name_and_sig_as_C_string(resolved_klass(),
|
||||
resolved_method->name(),
|
||||
resolved_method->signature()),
|
||||
resolved_method->method_holder()->internal_name()
|
||||
);
|
||||
resolved_method->access_flags().print_on(tty);
|
||||
if (resolved_method->is_default_method()) {
|
||||
tty->print("default");
|
||||
}
|
||||
if (resolved_method->is_overpass()) {
|
||||
tty->print("overpass");
|
||||
}
|
||||
tty->cr();
|
||||
}
|
||||
}
|
||||
|
||||
// throws runtime exceptions
|
||||
|
@ -906,10 +1110,6 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
|
|||
THROW(vmSymbols::java_lang_NullPointerException());
|
||||
}
|
||||
|
||||
// Virtual methods cannot be resolved before its klass has been linked, for otherwise the Method*'s
|
||||
// has not been rewritten, and the vtable initialized.
|
||||
assert(resolved_method->method_holder()->is_linked(), "must be linked");
|
||||
|
||||
// Virtual methods cannot be resolved before its klass has been linked, for otherwise the Method*'s
|
||||
// has not been rewritten, and the vtable initialized. Make sure to do this after the nullcheck, since
|
||||
// a missing receiver might result in a bogus lookup.
|
||||
|
@ -917,9 +1117,8 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
|
|||
|
||||
// do lookup based on receiver klass using the vtable index
|
||||
if (resolved_method->method_holder()->is_interface()) { // miranda method
|
||||
vtable_index = vtable_index_of_miranda_method(resolved_klass,
|
||||
resolved_method->name(),
|
||||
resolved_method->signature(), CHECK);
|
||||
vtable_index = vtable_index_of_interface_method(resolved_klass,
|
||||
resolved_method, CHECK);
|
||||
assert(vtable_index >= 0 , "we should have valid vtable index at this point");
|
||||
|
||||
InstanceKlass* inst = InstanceKlass::cast(recv_klass());
|
||||
|
@ -927,6 +1126,7 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
|
|||
} else {
|
||||
// at this point we are sure that resolved_method is virtual and not
|
||||
// a miranda method; therefore, it must have a valid vtable index.
|
||||
assert(!resolved_method->has_itable_index(), "");
|
||||
vtable_index = resolved_method->vtable_index();
|
||||
// We could get a negative vtable_index for final methods,
|
||||
// because as an optimization they are they are never put in the vtable,
|
||||
|
@ -962,6 +1162,26 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
|
|||
selected_method->signature()));
|
||||
}
|
||||
|
||||
if (PrintVtables && Verbose) {
|
||||
ResourceMark rm(THREAD);
|
||||
tty->print("invokevirtual selected method: receiver-class:%s, resolved-class:%s, method:%s, method_holder:%s, vtable_index:%d, access_flags: ",
|
||||
(recv_klass.is_null() ? "<NULL>" : recv_klass->internal_name()),
|
||||
(resolved_klass.is_null() ? "<NULL>" : resolved_klass->internal_name()),
|
||||
Method::name_and_sig_as_C_string(resolved_klass(),
|
||||
resolved_method->name(),
|
||||
resolved_method->signature()),
|
||||
selected_method->method_holder()->internal_name(),
|
||||
vtable_index
|
||||
);
|
||||
selected_method->access_flags().print_on(tty);
|
||||
if (selected_method->is_default_method()) {
|
||||
tty->print("default");
|
||||
}
|
||||
if (selected_method->is_overpass()) {
|
||||
tty->print("overpass");
|
||||
}
|
||||
tty->cr();
|
||||
}
|
||||
// setup result
|
||||
result.set_virtual(resolved_klass, recv_klass, resolved_method, selected_method, vtable_index, CHECK);
|
||||
}
|
||||
|
@ -992,6 +1212,17 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHand
|
|||
THROW(vmSymbols::java_lang_NullPointerException());
|
||||
}
|
||||
|
||||
// check if private interface method
|
||||
if (resolved_klass->is_interface() && resolved_method->is_private()) {
|
||||
ResourceMark rm(THREAD);
|
||||
char buf[200];
|
||||
jio_snprintf(buf, sizeof(buf), "private interface method requires invokespecial, not invokeinterface: method %s",
|
||||
Method::name_and_sig_as_C_string(resolved_klass(),
|
||||
resolved_method->name(),
|
||||
resolved_method->signature()));
|
||||
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
||||
}
|
||||
|
||||
// check if receiver klass implements the resolved interface
|
||||
if (!recv_klass->is_subtype_of(resolved_klass())) {
|
||||
ResourceMark rm(THREAD);
|
||||
|
@ -1006,6 +1237,12 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHand
|
|||
lookup_instance_method_in_klasses(sel_method, recv_klass,
|
||||
resolved_method->name(),
|
||||
resolved_method->signature(), CHECK);
|
||||
if (sel_method.is_null() && !check_null_and_abstract) {
|
||||
// In theory this is a harmless placeholder value, but
|
||||
// in practice leaving in null affects the nsk default method tests.
|
||||
// This needs further study.
|
||||
sel_method = resolved_method;
|
||||
}
|
||||
// check if method exists
|
||||
if (sel_method.is_null()) {
|
||||
ResourceMark rm(THREAD);
|
||||
|
@ -1015,27 +1252,13 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHand
|
|||
resolved_method->signature()));
|
||||
}
|
||||
// check access
|
||||
if (sel_method->method_holder()->is_interface()) {
|
||||
// Method holder is an interface. Throw Illegal Access Error if sel_method
|
||||
// is neither public nor private.
|
||||
if (!(sel_method->is_public() || sel_method->is_private())) {
|
||||
ResourceMark rm(THREAD);
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(),
|
||||
Method::name_and_sig_as_C_string(recv_klass(),
|
||||
sel_method->name(),
|
||||
sel_method->signature()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Method holder is a class. Throw Illegal Access Error if sel_method
|
||||
// is not public.
|
||||
if (!sel_method->is_public()) {
|
||||
ResourceMark rm(THREAD);
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(),
|
||||
Method::name_and_sig_as_C_string(recv_klass(),
|
||||
sel_method->name(),
|
||||
sel_method->signature()));
|
||||
}
|
||||
// Throw Illegal Access Error if sel_method is not public.
|
||||
if (!sel_method->is_public()) {
|
||||
ResourceMark rm(THREAD);
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(),
|
||||
Method::name_and_sig_as_C_string(recv_klass(),
|
||||
sel_method->name(),
|
||||
sel_method->signature()));
|
||||
}
|
||||
// check if abstract
|
||||
if (check_null_and_abstract && sel_method->is_abstract()) {
|
||||
|
@ -1046,7 +1269,34 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHand
|
|||
sel_method->signature()));
|
||||
}
|
||||
// setup result
|
||||
result.set_interface(resolved_klass, recv_klass, resolved_method, sel_method, CHECK);
|
||||
if (!resolved_method->has_itable_index()) {
|
||||
int vtable_index = resolved_method->vtable_index();
|
||||
assert(vtable_index == sel_method->vtable_index(), "sanity check");
|
||||
result.set_virtual(resolved_klass, recv_klass, resolved_method, sel_method, vtable_index, CHECK);
|
||||
return;
|
||||
}
|
||||
int itable_index = resolved_method()->itable_index();
|
||||
|
||||
if (TraceItables && Verbose) {
|
||||
ResourceMark rm(THREAD);
|
||||
tty->print("invokeinterface selected method: receiver-class:%s, resolved-class:%s, method:%s, method_holder:%s, access_flags: ",
|
||||
(recv_klass.is_null() ? "<NULL>" : recv_klass->internal_name()),
|
||||
(resolved_klass.is_null() ? "<NULL>" : resolved_klass->internal_name()),
|
||||
Method::name_and_sig_as_C_string(resolved_klass(),
|
||||
resolved_method->name(),
|
||||
resolved_method->signature()),
|
||||
sel_method->method_holder()->internal_name()
|
||||
);
|
||||
sel_method->access_flags().print_on(tty);
|
||||
if (sel_method->is_default_method()) {
|
||||
tty->print("default");
|
||||
}
|
||||
if (sel_method->is_overpass()) {
|
||||
tty->print("overpass");
|
||||
}
|
||||
tty->cr();
|
||||
}
|
||||
result.set_interface(resolved_klass, recv_klass, resolved_method, sel_method, itable_index, CHECK);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1293,7 +1543,8 @@ void LinkResolver::resolve_invokedynamic(CallInfo& result, constantPoolHandle po
|
|||
}
|
||||
|
||||
if (TraceMethodHandles) {
|
||||
tty->print_cr("resolve_invokedynamic #%d %s %s",
|
||||
ResourceMark rm(THREAD);
|
||||
tty->print_cr("resolve_invokedynamic #%d %s %s",
|
||||
ConstantPool::decode_invokedynamic_index(index),
|
||||
method_name->as_C_string(), method_signature->as_C_string());
|
||||
tty->print(" BSM info: "); bootstrap_specifier->print();
|
||||
|
@ -1320,7 +1571,7 @@ void LinkResolver::resolve_dynamic_call(CallInfo& result,
|
|||
THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
if (TraceMethodHandles) {
|
||||
tty->print_cr("invokedynamic throws BSME for "INTPTR_FORMAT, PENDING_EXCEPTION);
|
||||
tty->print_cr("invokedynamic throws BSME for "INTPTR_FORMAT, (void *)PENDING_EXCEPTION);
|
||||
PENDING_EXCEPTION->print();
|
||||
}
|
||||
if (PENDING_EXCEPTION->is_a(SystemDictionary::BootstrapMethodError_klass())) {
|
||||
|
@ -1342,9 +1593,16 @@ void LinkResolver::resolve_dynamic_call(CallInfo& result,
|
|||
//------------------------------------------------------------------------------------------------------------------------
|
||||
#ifndef PRODUCT
|
||||
|
||||
void FieldAccessInfo::print() {
|
||||
void CallInfo::print() {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("Field %s@%d", name()->as_C_string(), field_offset());
|
||||
const char* kindstr = "unknown";
|
||||
switch (_call_kind) {
|
||||
case direct_call: kindstr = "direct"; break;
|
||||
case vtable_call: kindstr = "vtable"; break;
|
||||
case itable_call: kindstr = "itable"; break;
|
||||
}
|
||||
tty->print_cr("Call %s@%d %s", kindstr, _call_index,
|
||||
_resolved_method.is_null() ? "(none)" : _resolved_method->name_and_sig_as_C_string());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2013, 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
|
||||
|
@ -30,63 +30,54 @@
|
|||
|
||||
// All the necessary definitions for run-time link resolution.
|
||||
|
||||
// LinkInfo & its subclasses provide all the information gathered
|
||||
// for a particular link after resolving it. A link is any reference
|
||||
// CallInfo provides all the information gathered for a particular
|
||||
// linked call site after resolving it. A link is any reference
|
||||
// made from within the bytecodes of a method to an object outside of
|
||||
// that method. If the info is invalid, the link has not been resolved
|
||||
// successfully.
|
||||
|
||||
class LinkInfo VALUE_OBJ_CLASS_SPEC {
|
||||
};
|
||||
|
||||
|
||||
// Link information for getfield/putfield & getstatic/putstatic bytecodes.
|
||||
|
||||
class FieldAccessInfo: public LinkInfo {
|
||||
protected:
|
||||
KlassHandle _klass;
|
||||
Symbol* _name;
|
||||
AccessFlags _access_flags;
|
||||
int _field_index; // original index in the klass
|
||||
int _field_offset;
|
||||
BasicType _field_type;
|
||||
|
||||
class CallInfo VALUE_OBJ_CLASS_SPEC {
|
||||
public:
|
||||
void set(KlassHandle klass, Symbol* name, int field_index, int field_offset,
|
||||
BasicType field_type, AccessFlags access_flags);
|
||||
KlassHandle klass() const { return _klass; }
|
||||
Symbol* name() const { return _name; }
|
||||
int field_index() const { return _field_index; }
|
||||
int field_offset() const { return _field_offset; }
|
||||
BasicType field_type() const { return _field_type; }
|
||||
AccessFlags access_flags() const { return _access_flags; }
|
||||
|
||||
// debugging
|
||||
void print() PRODUCT_RETURN;
|
||||
};
|
||||
|
||||
|
||||
// Link information for all calls.
|
||||
|
||||
class CallInfo: public LinkInfo {
|
||||
// Ways that a method call might be selected (or not) based on receiver type.
|
||||
// Note that an invokevirtual instruction might be linked with no_dispatch,
|
||||
// and an invokeinterface instruction might be linked with any of the three options
|
||||
enum CallKind {
|
||||
direct_call, // jump into resolved_method (must be concrete)
|
||||
vtable_call, // select recv.klass.method_at_vtable(index)
|
||||
itable_call, // select recv.klass.method_at_itable(resolved_method.holder, index)
|
||||
unknown_kind = -1
|
||||
};
|
||||
private:
|
||||
KlassHandle _resolved_klass; // static receiver klass
|
||||
KlassHandle _resolved_klass; // static receiver klass, resolved from a symbolic reference
|
||||
KlassHandle _selected_klass; // dynamic receiver class (same as static, or subklass)
|
||||
methodHandle _resolved_method; // static target method
|
||||
methodHandle _selected_method; // dynamic (actual) target method
|
||||
int _vtable_index; // vtable index of selected method
|
||||
CallKind _call_kind; // kind of call (static(=bytecode static/special +
|
||||
// others inferred), vtable, itable)
|
||||
int _call_index; // vtable or itable index of selected class method (if any)
|
||||
Handle _resolved_appendix; // extra argument in constant pool (if CPCE::has_appendix)
|
||||
Handle _resolved_method_type; // MethodType (for invokedynamic and invokehandle call sites)
|
||||
|
||||
void set_static( KlassHandle resolved_klass, methodHandle resolved_method , TRAPS);
|
||||
void set_interface(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method , TRAPS);
|
||||
void set_interface(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int itable_index , TRAPS);
|
||||
void set_virtual( KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index , TRAPS);
|
||||
void set_handle( methodHandle resolved_method, Handle resolved_appendix, Handle resolved_method_type, TRAPS);
|
||||
void set_common( KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index , TRAPS);
|
||||
void set_common( KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, CallKind kind, int index, TRAPS);
|
||||
|
||||
friend class LinkResolver;
|
||||
|
||||
public:
|
||||
CallInfo() {
|
||||
#ifndef PRODUCT
|
||||
_call_kind = CallInfo::unknown_kind;
|
||||
_call_index = Method::garbage_vtable_index;
|
||||
#endif //PRODUCT
|
||||
}
|
||||
|
||||
// utility to extract an effective CallInfo from a method and an optional receiver limit
|
||||
// does not queue the method for compilation
|
||||
CallInfo(Method* resolved_method, Klass* resolved_klass = NULL);
|
||||
|
||||
KlassHandle resolved_klass() const { return _resolved_klass; }
|
||||
KlassHandle selected_klass() const { return _selected_klass; }
|
||||
methodHandle resolved_method() const { return _resolved_method; }
|
||||
|
@ -95,21 +86,43 @@ class CallInfo: public LinkInfo {
|
|||
Handle resolved_method_type() const { return _resolved_method_type; }
|
||||
|
||||
BasicType result_type() const { return selected_method()->result_type(); }
|
||||
bool has_vtable_index() const { return _vtable_index >= 0; }
|
||||
bool is_statically_bound() const { return _vtable_index == Method::nonvirtual_vtable_index; }
|
||||
CallKind call_kind() const { return _call_kind; }
|
||||
int call_index() const { return _call_index; }
|
||||
int vtable_index() const {
|
||||
// Even for interface calls the vtable index could be non-negative.
|
||||
// See CallInfo::set_interface.
|
||||
assert(has_vtable_index() || is_statically_bound(), "");
|
||||
return _vtable_index;
|
||||
assert(call_kind() == vtable_call || call_kind() == direct_call, "");
|
||||
// The returned value is < 0 if the call is statically bound.
|
||||
// But, the returned value may be >= 0 even if the kind is direct_call.
|
||||
// It is up to the caller to decide which way to go.
|
||||
return _call_index;
|
||||
}
|
||||
int itable_index() const {
|
||||
assert(call_kind() == itable_call, "");
|
||||
// The returned value is always >= 0, a valid itable index.
|
||||
return _call_index;
|
||||
}
|
||||
|
||||
// debugging
|
||||
#ifdef ASSERT
|
||||
bool has_vtable_index() const { return _call_index >= 0 && _call_kind != CallInfo::itable_call; }
|
||||
bool is_statically_bound() const { return _call_index == Method::nonvirtual_vtable_index; }
|
||||
#endif //ASSERT
|
||||
void verify() PRODUCT_RETURN;
|
||||
void print() PRODUCT_RETURN;
|
||||
};
|
||||
|
||||
// Link information for getfield/putfield & getstatic/putstatic bytecodes
|
||||
// is represented using a fieldDescriptor.
|
||||
|
||||
// The LinkResolver is used to resolve constant-pool references at run-time.
|
||||
// It does all necessary link-time checks & throws exceptions if necessary.
|
||||
|
||||
class LinkResolver: AllStatic {
|
||||
friend class klassVtable;
|
||||
friend class klassItable;
|
||||
|
||||
private:
|
||||
static void lookup_method_in_klasses (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
|
||||
static void lookup_instance_method_in_klasses (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
|
||||
|
@ -117,15 +130,13 @@ class LinkResolver: AllStatic {
|
|||
static void lookup_polymorphic_method (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature,
|
||||
KlassHandle current_klass, Handle *appendix_result_or_null, Handle *method_type_result, TRAPS);
|
||||
|
||||
static int vtable_index_of_miranda_method(KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
|
||||
|
||||
static int vtable_index_of_interface_method(KlassHandle klass, methodHandle resolved_method, TRAPS);
|
||||
static void resolve_klass (KlassHandle& result, constantPoolHandle pool, int index, TRAPS);
|
||||
static void resolve_klass_no_update (KlassHandle& result, constantPoolHandle pool, int index, TRAPS); // no update of constantPool entry
|
||||
|
||||
static void resolve_pool (KlassHandle& resolved_klass, Symbol*& method_name, Symbol*& method_signature, KlassHandle& current_klass, constantPoolHandle pool, int index, TRAPS);
|
||||
|
||||
static void resolve_interface_method(methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS);
|
||||
static void resolve_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS);
|
||||
static void resolve_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, bool require_methodref, TRAPS);
|
||||
|
||||
static void linktime_resolve_static_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS);
|
||||
static void linktime_resolve_special_method (methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS);
|
||||
|
@ -148,9 +159,16 @@ class LinkResolver: AllStatic {
|
|||
Bytecodes::Code code, constantPoolHandle pool, int index, TRAPS);
|
||||
|
||||
// runtime/static resolving for fields
|
||||
static void resolve_field(FieldAccessInfo& result, constantPoolHandle pool, int index, Bytecodes::Code byte, bool check_only, TRAPS);
|
||||
// takes an extra bool argument "update_pool" to decide whether to update the constantPool during klass resolution.
|
||||
static void resolve_field(FieldAccessInfo& result, constantPoolHandle pool, int index, Bytecodes::Code byte, bool check_only, bool update_pool, TRAPS);
|
||||
static void resolve_field_access(fieldDescriptor& result, constantPoolHandle pool, int index, Bytecodes::Code byte, TRAPS);
|
||||
static void resolve_field(fieldDescriptor& result, KlassHandle resolved_klass, Symbol* field_name, Symbol* field_signature,
|
||||
KlassHandle current_klass, Bytecodes::Code access_kind, bool check_access, bool initialize_class, TRAPS);
|
||||
|
||||
// source of access_kind codes:
|
||||
static Bytecodes::Code field_access_kind(bool is_static, bool is_put) {
|
||||
return (is_static
|
||||
? (is_put ? Bytecodes::_putstatic : Bytecodes::_getstatic)
|
||||
: (is_put ? Bytecodes::_putfield : Bytecodes::_getfield ));
|
||||
}
|
||||
|
||||
// runtime resolving:
|
||||
// resolved_klass = specified class (i.e., static receiver class)
|
||||
|
|
|
@ -184,8 +184,9 @@ EntryPoint TemplateInterpreter::_deopt_entry [TemplateInterpreter::number_of_deo
|
|||
EntryPoint TemplateInterpreter::_continuation_entry;
|
||||
EntryPoint TemplateInterpreter::_safept_entry;
|
||||
|
||||
address TemplateInterpreter::_return_3_addrs_by_index[TemplateInterpreter::number_of_return_addrs];
|
||||
address TemplateInterpreter::_return_5_addrs_by_index[TemplateInterpreter::number_of_return_addrs];
|
||||
address TemplateInterpreter::_invoke_return_entry[TemplateInterpreter::number_of_return_addrs];
|
||||
address TemplateInterpreter::_invokeinterface_return_entry[TemplateInterpreter::number_of_return_addrs];
|
||||
address TemplateInterpreter::_invokedynamic_return_entry[TemplateInterpreter::number_of_return_addrs];
|
||||
|
||||
DispatchTable TemplateInterpreter::_active_table;
|
||||
DispatchTable TemplateInterpreter::_normal_table;
|
||||
|
@ -237,22 +238,37 @@ void TemplateInterpreterGenerator::generate_all() {
|
|||
#endif // !PRODUCT
|
||||
|
||||
{ CodeletMark cm(_masm, "return entry points");
|
||||
const int index_size = sizeof(u2);
|
||||
for (int i = 0; i < Interpreter::number_of_return_entries; i++) {
|
||||
Interpreter::_return_entry[i] =
|
||||
EntryPoint(
|
||||
generate_return_entry_for(itos, i),
|
||||
generate_return_entry_for(itos, i),
|
||||
generate_return_entry_for(itos, i),
|
||||
generate_return_entry_for(atos, i),
|
||||
generate_return_entry_for(itos, i),
|
||||
generate_return_entry_for(ltos, i),
|
||||
generate_return_entry_for(ftos, i),
|
||||
generate_return_entry_for(dtos, i),
|
||||
generate_return_entry_for(vtos, i)
|
||||
generate_return_entry_for(itos, i, index_size),
|
||||
generate_return_entry_for(itos, i, index_size),
|
||||
generate_return_entry_for(itos, i, index_size),
|
||||
generate_return_entry_for(atos, i, index_size),
|
||||
generate_return_entry_for(itos, i, index_size),
|
||||
generate_return_entry_for(ltos, i, index_size),
|
||||
generate_return_entry_for(ftos, i, index_size),
|
||||
generate_return_entry_for(dtos, i, index_size),
|
||||
generate_return_entry_for(vtos, i, index_size)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
{ CodeletMark cm(_masm, "invoke return entry points");
|
||||
const TosState states[] = {itos, itos, itos, itos, ltos, ftos, dtos, atos, vtos};
|
||||
const int invoke_length = Bytecodes::length_for(Bytecodes::_invokestatic);
|
||||
const int invokeinterface_length = Bytecodes::length_for(Bytecodes::_invokeinterface);
|
||||
const int invokedynamic_length = Bytecodes::length_for(Bytecodes::_invokedynamic);
|
||||
|
||||
for (int i = 0; i < Interpreter::number_of_return_addrs; i++) {
|
||||
TosState state = states[i];
|
||||
Interpreter::_invoke_return_entry[i] = generate_return_entry_for(state, invoke_length, sizeof(u2));
|
||||
Interpreter::_invokeinterface_return_entry[i] = generate_return_entry_for(state, invokeinterface_length, sizeof(u2));
|
||||
Interpreter::_invokedynamic_return_entry[i] = generate_return_entry_for(state, invokedynamic_length, sizeof(u4));
|
||||
}
|
||||
}
|
||||
|
||||
{ CodeletMark cm(_masm, "earlyret entry points");
|
||||
Interpreter::_earlyret_entry =
|
||||
EntryPoint(
|
||||
|
@ -298,13 +314,6 @@ void TemplateInterpreterGenerator::generate_all() {
|
|||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < number_of_states; j++) {
|
||||
const TosState states[] = {btos, ctos, stos, itos, ltos, ftos, dtos, atos, vtos};
|
||||
int index = Interpreter::TosState_as_index(states[j]);
|
||||
Interpreter::_return_3_addrs_by_index[index] = Interpreter::return_entry(states[j], 3);
|
||||
Interpreter::_return_5_addrs_by_index[index] = Interpreter::return_entry(states[j], 5);
|
||||
}
|
||||
|
||||
{ CodeletMark cm(_masm, "continuation entry points");
|
||||
Interpreter::_continuation_entry =
|
||||
EntryPoint(
|
||||
|
@ -534,9 +543,46 @@ void TemplateInterpreterGenerator::generate_and_dispatch(Template* t, TosState t
|
|||
//------------------------------------------------------------------------------------------------------------------------
|
||||
// Entry points
|
||||
|
||||
address TemplateInterpreter::return_entry(TosState state, int length) {
|
||||
/**
|
||||
* Returns the return entry table for the given invoke bytecode.
|
||||
*/
|
||||
address* TemplateInterpreter::invoke_return_entry_table_for(Bytecodes::Code code) {
|
||||
switch (code) {
|
||||
case Bytecodes::_invokestatic:
|
||||
case Bytecodes::_invokespecial:
|
||||
case Bytecodes::_invokevirtual:
|
||||
case Bytecodes::_invokehandle:
|
||||
return Interpreter::invoke_return_entry_table();
|
||||
case Bytecodes::_invokeinterface:
|
||||
return Interpreter::invokeinterface_return_entry_table();
|
||||
case Bytecodes::_invokedynamic:
|
||||
return Interpreter::invokedynamic_return_entry_table();
|
||||
default:
|
||||
fatal(err_msg("invalid bytecode: %s", Bytecodes::name(code)));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the return entry address for the given top-of-stack state and bytecode.
|
||||
*/
|
||||
address TemplateInterpreter::return_entry(TosState state, int length, Bytecodes::Code code) {
|
||||
guarantee(0 <= length && length < Interpreter::number_of_return_entries, "illegal length");
|
||||
return _return_entry[length].entry(state);
|
||||
const int index = TosState_as_index(state);
|
||||
switch (code) {
|
||||
case Bytecodes::_invokestatic:
|
||||
case Bytecodes::_invokespecial:
|
||||
case Bytecodes::_invokevirtual:
|
||||
case Bytecodes::_invokehandle:
|
||||
return _invoke_return_entry[index];
|
||||
case Bytecodes::_invokeinterface:
|
||||
return _invokeinterface_return_entry[index];
|
||||
case Bytecodes::_invokedynamic:
|
||||
return _invokedynamic_return_entry[index];
|
||||
default:
|
||||
assert(!Bytecodes::is_invoke(code), err_msg("invoke instructions should be handled separately: %s", Bytecodes::name(code)));
|
||||
return _return_entry[length].entry(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -120,8 +120,9 @@ class TemplateInterpreter: public AbstractInterpreter {
|
|||
static EntryPoint _continuation_entry;
|
||||
static EntryPoint _safept_entry;
|
||||
|
||||
static address _return_3_addrs_by_index[number_of_return_addrs]; // for invokevirtual return entries
|
||||
static address _return_5_addrs_by_index[number_of_return_addrs]; // for invokeinterface return entries
|
||||
static address _invoke_return_entry[number_of_return_addrs]; // for invokestatic, invokespecial, invokevirtual return entries
|
||||
static address _invokeinterface_return_entry[number_of_return_addrs]; // for invokeinterface return entries
|
||||
static address _invokedynamic_return_entry[number_of_return_addrs]; // for invokedynamic return entries
|
||||
|
||||
static DispatchTable _active_table; // the active dispatch table (used by the interpreter for dispatch)
|
||||
static DispatchTable _normal_table; // the normal dispatch table (used to set the active table in normal mode)
|
||||
|
@ -161,12 +162,15 @@ class TemplateInterpreter: public AbstractInterpreter {
|
|||
static address* normal_table() { return _normal_table.table_for(); }
|
||||
|
||||
// Support for invokes
|
||||
static address* return_3_addrs_by_index_table() { return _return_3_addrs_by_index; }
|
||||
static address* return_5_addrs_by_index_table() { return _return_5_addrs_by_index; }
|
||||
static int TosState_as_index(TosState state); // computes index into return_3_entry_by_index table
|
||||
static address* invoke_return_entry_table() { return _invoke_return_entry; }
|
||||
static address* invokeinterface_return_entry_table() { return _invokeinterface_return_entry; }
|
||||
static address* invokedynamic_return_entry_table() { return _invokedynamic_return_entry; }
|
||||
static int TosState_as_index(TosState state);
|
||||
|
||||
static address return_entry (TosState state, int length);
|
||||
static address deopt_entry (TosState state, int length);
|
||||
static address* invoke_return_entry_table_for(Bytecodes::Code code);
|
||||
|
||||
static address deopt_entry(TosState state, int length);
|
||||
static address return_entry(TosState state, int length, Bytecodes::Code code);
|
||||
|
||||
// Safepoint support
|
||||
static void notice_safepoints(); // stops the thread when reaching a safepoint
|
||||
|
|
|
@ -53,7 +53,7 @@ class TemplateInterpreterGenerator: public AbstractInterpreterGenerator {
|
|||
address generate_ClassCastException_handler();
|
||||
address generate_ArrayIndexOutOfBounds_handler(const char* name);
|
||||
address generate_continuation_for(TosState state);
|
||||
address generate_return_entry_for(TosState state, int step);
|
||||
address generate_return_entry_for(TosState state, int step, size_t index_size);
|
||||
address generate_earlyret_entry_for(TosState state);
|
||||
address generate_deopt_entry_for(TosState state, int step);
|
||||
address generate_safept_entry_for(TosState state, address runtime_entry);
|
||||
|
|
|
@ -28,11 +28,8 @@
|
|||
#include "interpreter/bytecodes.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "runtime/frame.hpp"
|
||||
#ifdef TARGET_ARCH_MODEL_x86_32
|
||||
# include "interp_masm_x86_32.hpp"
|
||||
#endif
|
||||
#ifdef TARGET_ARCH_MODEL_x86_64
|
||||
# include "interp_masm_x86_64.hpp"
|
||||
#ifdef TARGET_ARCH_x86
|
||||
# include "interp_masm_x86.hpp"
|
||||
#endif
|
||||
#ifdef TARGET_ARCH_MODEL_sparc
|
||||
# include "interp_masm_sparc.hpp"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue