8014013: CallInfo structure no longer accurately reports the result of a LinkResolver operation

Enhance method resolution and resulting data structures, plus some refactoring.

Reviewed-by: twisti, acorn, jrose
This commit is contained in:
David Chase 2013-09-13 22:38:02 -04:00
parent 98d8f57603
commit 222c735458
40 changed files with 715 additions and 601 deletions

View file

@ -709,10 +709,10 @@ static Klass* resolve_field_return_klass(methodHandle caller, int bci, TRAPS) {
Bytecodes::Code code = field_access.code(); Bytecodes::Code code = field_access.code();
// We must load class, initialize class and resolvethe field // We must load class, initialize class and resolvethe field
FieldAccessInfo result; // initialize class if needed fieldDescriptor result; // initialize class if needed
constantPoolHandle constants(THREAD, caller->constants()); constantPoolHandle constants(THREAD, caller->constants());
LinkResolver::resolve_field(result, constants, field_access.index(), Bytecodes::java_code(code), false, CHECK_NULL); LinkResolver::resolve_field_access(result, constants, field_access.index(), Bytecodes::java_code(code), CHECK_NULL);
return result.klass()(); return result.field_holder();
} }
@ -826,11 +826,11 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i
if (stub_id == Runtime1::access_field_patching_id) { if (stub_id == Runtime1::access_field_patching_id) {
Bytecode_field field_access(caller_method, bci); Bytecode_field field_access(caller_method, bci);
FieldAccessInfo result; // initialize class if needed fieldDescriptor result; // initialize class if needed
Bytecodes::Code code = field_access.code(); Bytecodes::Code code = field_access.code();
constantPoolHandle constants(THREAD, caller_method->constants()); constantPoolHandle constants(THREAD, caller_method->constants());
LinkResolver::resolve_field(result, constants, field_access.index(), Bytecodes::java_code(code), false, CHECK); LinkResolver::resolve_field_access(result, constants, field_access.index(), Bytecodes::java_code(code), CHECK);
patch_field_offset = result.field_offset(); patch_field_offset = result.offset();
// If we're patching a field which is volatile then at compile it // If we're patching a field which is volatile then at compile it
// must not have been know to be volatile, so the generated code // must not have been know to be volatile, so the generated code

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -75,7 +75,6 @@ ciField::ciField(ciInstanceKlass* klass, int index): _known_to_link_with_put(NUL
assert(klass->get_instanceKlass()->is_linked(), "must be linked before using its constan-pool"); assert(klass->get_instanceKlass()->is_linked(), "must be linked before using its constan-pool");
_cp_index = index;
constantPoolHandle cpool(thread, klass->get_instanceKlass()->constants()); constantPoolHandle cpool(thread, klass->get_instanceKlass()->constants());
// Get the field's name, signature, and type. // Get the field's name, signature, and type.
@ -116,7 +115,7 @@ ciField::ciField(ciInstanceKlass* klass, int index): _known_to_link_with_put(NUL
// The declared holder of this field may not have been loaded. // The declared holder of this field may not have been loaded.
// Bail out with partial field information. // Bail out with partial field information.
if (!holder_is_accessible) { if (!holder_is_accessible) {
// _cp_index and _type have already been set. // _type has already been set.
// The default values for _flags and _constant_value will suffice. // The default values for _flags and _constant_value will suffice.
// We need values for _holder, _offset, and _is_constant, // We need values for _holder, _offset, and _is_constant,
_holder = declared_holder; _holder = declared_holder;
@ -146,8 +145,6 @@ ciField::ciField(ciInstanceKlass* klass, int index): _known_to_link_with_put(NUL
ciField::ciField(fieldDescriptor *fd): _known_to_link_with_put(NULL), _known_to_link_with_get(NULL) { ciField::ciField(fieldDescriptor *fd): _known_to_link_with_put(NULL), _known_to_link_with_get(NULL) {
ASSERT_IN_VM; ASSERT_IN_VM;
_cp_index = -1;
// Get the field's name, signature, and type. // Get the field's name, signature, and type.
ciEnv* env = CURRENT_ENV; ciEnv* env = CURRENT_ENV;
_name = env->get_symbol(fd->name()); _name = env->get_symbol(fd->name());
@ -351,12 +348,11 @@ bool ciField::will_link(ciInstanceKlass* accessing_klass,
} }
} }
FieldAccessInfo result; fieldDescriptor result;
constantPoolHandle c_pool(THREAD, LinkResolver::resolve_field(result, _holder->get_instanceKlass(),
accessing_klass->get_instanceKlass()->constants()); _name->get_symbol(), _signature->get_symbol(),
LinkResolver::resolve_field(result, c_pool, _cp_index, accessing_klass->get_Klass(), bc, true, false,
Bytecodes::java_code(bc), KILL_COMPILE_ON_FATAL_(false));
true, false, KILL_COMPILE_ON_FATAL_(false));
// update the hit-cache, unless there is a problem with memory scoping: // update the hit-cache, unless there is a problem with memory scoping:
if (accessing_klass->is_shared() || !is_shared()) { if (accessing_klass->is_shared() || !is_shared()) {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -53,9 +53,6 @@ private:
ciInstanceKlass* _known_to_link_with_get; ciInstanceKlass* _known_to_link_with_get;
ciConstant _constant_value; ciConstant _constant_value;
// Used for will_link
int _cp_index;
ciType* compute_type(); ciType* compute_type();
ciType* compute_type_impl(); ciType* compute_type_impl();

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -522,8 +522,7 @@ ciInstanceKlass::compute_nonstatic_fields_impl(GrowableArray<ciField*>*
for (JavaFieldStream fs(k); !fs.done(); fs.next()) { for (JavaFieldStream fs(k); !fs.done(); fs.next()) {
if (fs.access_flags().is_static()) continue; if (fs.access_flags().is_static()) continue;
fieldDescriptor fd; fieldDescriptor& fd = fs.field_descriptor();
fd.initialize(k, fs.index());
ciField* field = new (arena) ciField(&fd); ciField* field = new (arena) ciField(&fd);
fields->append(field); fields->append(field);
} }

View file

@ -286,7 +286,10 @@ int ciMethod::itable_index() {
check_is_loaded(); check_is_loaded();
assert(holder()->is_linked(), "must be linked"); assert(holder()->is_linked(), "must be linked");
VM_ENTRY_MARK; VM_ENTRY_MARK;
return klassItable::compute_itable_index(get_Method()); Method* m = get_Method();
if (!m->has_itable_index())
return Method::nonvirtual_vtable_index;
return m->itable_index();
} }
#endif // SHARK #endif // SHARK
@ -1137,6 +1140,10 @@ bool ciMethod::is_klass_loaded(int refinfo_index, bool must_be_resolved) const {
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// ciMethod::check_call // ciMethod::check_call
bool ciMethod::check_call(int refinfo_index, bool is_static) const { bool ciMethod::check_call(int refinfo_index, bool is_static) const {
// This method is used only in C2 from InlineTree::ok_to_inline,
// and is only used under -Xcomp or -XX:CompileTheWorld.
// It appears to fail when applied to an invokeinterface call site.
// FIXME: Remove this method and resolve_method_statically; refactor to use the other LinkResolver entry points.
VM_ENTRY_MARK; VM_ENTRY_MARK;
{ {
EXCEPTION_MARK; EXCEPTION_MARK;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -44,6 +44,7 @@ class ciSymbol : public ciBaseObject {
friend class ciInstanceKlass; friend class ciInstanceKlass;
friend class ciSignature; friend class ciSignature;
friend class ciMethod; friend class ciMethod;
friend class ciField;
friend class ciObjArrayKlass; friend class ciObjArrayKlass;
private: private:

View file

@ -3954,9 +3954,8 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
this_klass->set_has_final_method(); this_klass->set_has_final_method();
} }
this_klass->copy_method_ordering(method_ordering, CHECK_NULL); this_klass->copy_method_ordering(method_ordering, CHECK_NULL);
// The InstanceKlass::_methods_jmethod_ids cache and the // The InstanceKlass::_methods_jmethod_ids cache
// InstanceKlass::_methods_cached_itable_indices cache are // is managed on the assumption that the initial cache
// both managed on the assumption that the initial cache
// size is equal to the number of methods in the class. If // size is equal to the number of methods in the class. If
// that changes, then InstanceKlass::idnum_can_increment() // that changes, then InstanceKlass::idnum_can_increment()
// has to be changed accordingly. // has to be changed accordingly.

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -161,31 +161,36 @@ address CompiledIC::stub_address() const {
void CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecode, TRAPS) { void CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecode, TRAPS) {
methodHandle method = call_info->selected_method();
bool is_invoke_interface = (bytecode == Bytecodes::_invokeinterface && !call_info->has_vtable_index());
assert(CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), ""); assert(CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
assert(!is_optimized(), "cannot set an optimized virtual call to megamorphic"); assert(!is_optimized(), "cannot set an optimized virtual call to megamorphic");
assert(is_call_to_compiled() || is_call_to_interpreted(), "going directly to megamorphic?"); assert(is_call_to_compiled() || is_call_to_interpreted(), "going directly to megamorphic?");
address entry; address entry;
if (is_invoke_interface) { if (call_info->call_kind() == CallInfo::itable_call) {
int index = klassItable::compute_itable_index(call_info->resolved_method()()); assert(bytecode == Bytecodes::_invokeinterface, "");
entry = VtableStubs::create_stub(false, index, method()); int itable_index = call_info->itable_index();
entry = VtableStubs::find_itable_stub(itable_index);
#ifdef ASSERT
assert(entry != NULL, "entry not computed"); assert(entry != NULL, "entry not computed");
int index = call_info->resolved_method()->itable_index();
assert(index == itable_index, "CallInfo pre-computes this");
#endif //ASSERT
InstanceKlass* k = call_info->resolved_method()->method_holder(); InstanceKlass* k = call_info->resolved_method()->method_holder();
assert(k->is_interface(), "sanity check"); assert(k->verify_itable_index(itable_index), "sanity check");
InlineCacheBuffer::create_transition_stub(this, k, entry); InlineCacheBuffer::create_transition_stub(this, k, entry);
} else { } else {
// Can be different than method->vtable_index(), due to package-private etc. assert(call_info->call_kind() == CallInfo::vtable_call, "either itable or vtable");
// Can be different than selected_method->vtable_index(), due to package-private etc.
int vtable_index = call_info->vtable_index(); int vtable_index = call_info->vtable_index();
entry = VtableStubs::create_stub(true, vtable_index, method()); assert(call_info->resolved_klass()->verify_vtable_index(vtable_index), "sanity check");
InlineCacheBuffer::create_transition_stub(this, method(), entry); entry = VtableStubs::find_vtable_stub(vtable_index);
InlineCacheBuffer::create_transition_stub(this, NULL, entry);
} }
if (TraceICs) { if (TraceICs) {
ResourceMark rm; ResourceMark rm;
tty->print_cr ("IC@" INTPTR_FORMAT ": to megamorphic %s entry: " INTPTR_FORMAT, tty->print_cr ("IC@" INTPTR_FORMAT ": to megamorphic %s entry: " INTPTR_FORMAT,
instruction_address(), method->print_value_string(), entry); instruction_address(), call_info->selected_method()->print_value_string(), entry);
} }
// We can't check this anymore. With lazy deopt we could have already // We can't check this anymore. With lazy deopt we could have already

View file

@ -111,7 +111,7 @@ void VtableStubs::initialize() {
} }
address VtableStubs::create_stub(bool is_vtable_stub, int vtable_index, Method* method) { address VtableStubs::find_stub(bool is_vtable_stub, int vtable_index) {
assert(vtable_index >= 0, "must be positive"); assert(vtable_index >= 0, "must be positive");
VtableStub* s = ShareVtableStubs ? lookup(is_vtable_stub, vtable_index) : NULL; VtableStub* s = ShareVtableStubs ? lookup(is_vtable_stub, vtable_index) : NULL;

View file

@ -121,9 +121,11 @@ class VtableStubs : AllStatic {
static VtableStub* lookup (bool is_vtable_stub, int vtable_index); static VtableStub* lookup (bool is_vtable_stub, int vtable_index);
static void enter (bool is_vtable_stub, int vtable_index, VtableStub* s); static void enter (bool is_vtable_stub, int vtable_index, VtableStub* s);
static inline uint hash (bool is_vtable_stub, int vtable_index); static inline uint hash (bool is_vtable_stub, int vtable_index);
static address find_stub (bool is_vtable_stub, int vtable_index);
public: public:
static address create_stub(bool is_vtable_stub, int vtable_index, Method* method); // return the entry point of a stub for this call static address find_vtable_stub(int vtable_index) { return find_stub(true, vtable_index); }
static address find_itable_stub(int itable_index) { return find_stub(false, itable_index); }
static bool is_entry_point(address pc); // is pc a vtable stub entry point? static bool is_entry_point(address pc); // is pc a vtable stub entry point?
static bool contains(address pc); // is pc within any stub? static bool contains(address pc); // is pc within any stub?
static VtableStub* stub_containing(address pc); // stub containing pc or NULL static VtableStub* stub_containing(address pc); // stub containing pc or NULL

View file

@ -496,15 +496,15 @@ IRT_END
IRT_ENTRY(void, InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecodes::Code bytecode)) IRT_ENTRY(void, InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecodes::Code bytecode))
// resolve field // resolve field
FieldAccessInfo info; fieldDescriptor info;
constantPoolHandle pool(thread, method(thread)->constants()); constantPoolHandle pool(thread, method(thread)->constants());
bool is_put = (bytecode == Bytecodes::_putfield || bytecode == Bytecodes::_putstatic); bool is_put = (bytecode == Bytecodes::_putfield || bytecode == Bytecodes::_putstatic);
bool is_static = (bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic); bool is_static = (bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic);
{ {
JvmtiHideSingleStepping jhss(thread); JvmtiHideSingleStepping jhss(thread);
LinkResolver::resolve_field(info, pool, get_index_u2_cpcache(thread, bytecode), LinkResolver::resolve_field_access(info, pool, get_index_u2_cpcache(thread, bytecode),
bytecode, false, CHECK); bytecode, CHECK);
} // end JvmtiHideSingleStepping } // end JvmtiHideSingleStepping
// check if link resolution caused cpCache to be updated // check if link resolution caused cpCache to be updated
@ -524,7 +524,7 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecode
// class is intitialized. This is required so that access to the static // class is intitialized. This is required so that access to the static
// field will call the initialization function every time until the class // field will call the initialization function every time until the class
// is completely initialized ala. in 2.17.5 in JVM Specification. // 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) && bool uninitialized_static = ((bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic) &&
!klass->is_initialized()); !klass->is_initialized());
Bytecodes::Code get_code = (Bytecodes::Code)0; Bytecodes::Code get_code = (Bytecodes::Code)0;
@ -539,9 +539,9 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecode
cache_entry(thread)->set_field( cache_entry(thread)->set_field(
get_code, get_code,
put_code, put_code,
info.klass(), info.field_holder(),
info.field_index(), info.index(),
info.field_offset(), info.offset(),
state, state,
info.access_flags().is_final(), info.access_flags().is_final(),
info.access_flags().is_volatile(), info.access_flags().is_volatile(),
@ -686,29 +686,55 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes
if (already_resolved(thread)) return; if (already_resolved(thread)) return;
if (bytecode == Bytecodes::_invokeinterface) { if (bytecode == Bytecodes::_invokeinterface) {
if (TraceItables && Verbose) { if (TraceItables && Verbose) {
ResourceMark rm(thread); 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()); 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() == if (info.resolved_method()->method_holder() ==
SystemDictionary::Object_klass()) { SystemDictionary::Object_klass()) {
// NOTE: THIS IS A FIX FOR A CORNER CASE in the JVM spec // 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(); methodHandle rm = info.resolved_method();
assert(rm->is_final() || info.has_vtable_index(), assert(rm->is_final() || info.has_vtable_index(),
"should have been set already"); "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 { } else {
// Setup itable entry // Setup itable entry
int index = klassItable::compute_itable_index(info.resolved_method()()); assert(info.call_kind() == CallInfo::itable_call, "");
cache_entry(thread)->set_interface_call(info.resolved_method(), index); int index = info.resolved_method()->itable_index();
assert(info.itable_index() == index, "");
} }
} else { } 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, bytecode,
info.resolved_method(), info.resolved_method(),
info.vtable_index()); 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 IRT_END

View file

@ -46,19 +46,6 @@
#include "runtime/thread.inline.hpp" #include "runtime/thread.inline.hpp"
#include "runtime/vmThread.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 // Implementation of CallInfo
@ -66,26 +53,25 @@ BasicType field_type, AccessFlags access_flags) {
void CallInfo::set_static(KlassHandle resolved_klass, methodHandle resolved_method, TRAPS) { void CallInfo::set_static(KlassHandle resolved_klass, methodHandle resolved_method, TRAPS) {
int vtable_index = Method::nonvirtual_vtable_index; 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 // 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 // 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. // we should pick the vtable index from the resolved method.
// Other than that case, there is no valid vtable index to specify. // In that case, the caller must call set_virtual instead of set_interface.
int vtable_index = Method::invalid_vtable_index; assert(resolved_method->method_holder()->is_interface(), "");
if (resolved_method->method_holder() == SystemDictionary::Object_klass()) { assert(itable_index == resolved_method()->itable_index(), "");
assert(resolved_method->vtable_index() == selected_method->vtable_index(), "sanity check"); set_common(resolved_klass, selected_klass, resolved_method, selected_method, CallInfo::itable_call, itable_index, CHECK);
vtable_index = resolved_method->vtable_index();
}
set_common(resolved_klass, selected_klass, resolved_method, selected_method, vtable_index, CHECK);
} }
void CallInfo::set_virtual(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS) { 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"); 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"); 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(), resolved_method->is_compiled_lambda_form(),
"linkMethod must return one of these"); "linkMethod must return one of these");
int vtable_index = Method::nonvirtual_vtable_index; int vtable_index = Method::nonvirtual_vtable_index;
assert(resolved_method->vtable_index() == vtable_index, ""); assert(!resolved_method->has_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);
_resolved_appendix = resolved_appendix; _resolved_appendix = resolved_appendix;
_resolved_method_type = resolved_method_type; _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"); assert(resolved_method->signature() == selected_method->signature(), "signatures must correspond");
_resolved_klass = resolved_klass; _resolved_klass = resolved_klass;
_selected_klass = selected_klass; _selected_klass = selected_klass;
_resolved_method = resolved_method; _resolved_method = resolved_method;
_selected_method = selected_method; _selected_method = selected_method;
_vtable_index = vtable_index; _call_kind = kind;
_call_index = index;
_resolved_appendix = Handle(); _resolved_appendix = Handle();
DEBUG_ONLY(verify()); // verify before making side effects
if (CompilationPolicy::must_be_compiled(selected_method)) { if (CompilationPolicy::must_be_compiled(selected_method)) {
// This path is unusual, mostly used by the '-Xcomp' stress test mode. // This path is unusual, mostly used by the '-Xcomp' stress test mode.
@ -138,6 +133,65 @@ 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 {
// 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 // Klass resolution
@ -163,13 +217,6 @@ void LinkResolver::resolve_klass(KlassHandle& result, constantPoolHandle pool, i
result = KlassHandle(THREAD, result_oop); 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 // Method resolution
// //
@ -360,7 +407,12 @@ void LinkResolver::check_method_accessability(KlassHandle ref_klass,
void LinkResolver::resolve_method_statically(methodHandle& resolved_method, KlassHandle& resolved_klass, void LinkResolver::resolve_method_statically(methodHandle& resolved_method, KlassHandle& resolved_klass,
Bytecodes::Code code, constantPoolHandle pool, int index, TRAPS) { 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 // resolve klass
if (code == Bytecodes::_invokedynamic) { if (code == Bytecodes::_invokedynamic) {
resolved_klass = SystemDictionary::MethodHandle_klass(); resolved_klass = SystemDictionary::MethodHandle_klass();
@ -580,45 +632,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) { void LinkResolver::resolve_field_access(fieldDescriptor& result, constantPoolHandle pool, int index, Bytecodes::Code byte, TRAPS) {
resolve_field(result, pool, index, byte, check_only, true, 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);
// 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 || 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_static = (byte == Bytecodes::_getstatic || byte == Bytecodes::_putstatic);
bool is_put = (byte == Bytecodes::_putfield || 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 // Check if there's a resolved klass containing the field
if( resolved_klass.is_null() ) { if (resolved_klass.is_null()) {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), field->as_C_string()); THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), field->as_C_string());
} }
// Resolve instance field // Resolve instance field
fieldDescriptor fd; // find_field initializes fd if found
KlassHandle sel_klass(THREAD, InstanceKlass::cast(resolved_klass())->find_field(field, sig, &fd)); 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 // 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); ResourceMark rm(THREAD);
THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), field->as_C_string()); 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 // check access
KlassHandle ref_klass(THREAD, pool->pool_holder()); check_field_accessability(current_klass, resolved_klass, sel_klass, fd, CHECK);
check_field_accessability(ref_klass, resolved_klass, sel_klass, fd, CHECK);
// check for errors // check for errors
if (is_static != fd.is_static()) { if (is_static != fd.is_static()) {
@ -629,7 +685,7 @@ void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle poo
} }
// Final fields can only be accessed from its own class. // 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()); THROW(vmSymbols::java_lang_IllegalAccessError());
} }
@ -639,19 +695,18 @@ void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle poo
// //
// note 2: we don't want to force initialization if we are just checking // 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 the field access is legal; e.g., during compilation
if (is_static && !check_only) { if (is_static && initialize_class) {
sel_klass->initialize(CHECK); sel_klass->initialize(CHECK);
} }
{ if (sel_klass() != current_klass()) {
HandleMark hm(THREAD); 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()); Handle sel_loader (THREAD, InstanceKlass::cast(sel_klass())->class_loader());
Symbol* signature_ref = pool->signature_ref_at(index);
{ {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
Symbol* failed_type_symbol = Symbol* failed_type_symbol =
SystemDictionary::check_signature_loaders(signature_ref, SystemDictionary::check_signature_loaders(sig,
ref_loader, sel_loader, ref_loader, sel_loader,
false, false,
CHECK); CHECK);
@ -677,9 +732,6 @@ void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle poo
// return information. note that the klass is set to the actual klass containing the // 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. // 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());
} }
@ -906,10 +958,6 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
THROW(vmSymbols::java_lang_NullPointerException()); 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 // 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 // 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. // a missing receiver might result in a bogus lookup.
@ -920,6 +968,7 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
vtable_index = vtable_index_of_miranda_method(resolved_klass, vtable_index = vtable_index_of_miranda_method(resolved_klass,
resolved_method->name(), resolved_method->name(),
resolved_method->signature(), CHECK); resolved_method->signature(), CHECK);
assert(vtable_index >= 0 , "we should have valid vtable index at this point"); assert(vtable_index >= 0 , "we should have valid vtable index at this point");
InstanceKlass* inst = InstanceKlass::cast(recv_klass()); InstanceKlass* inst = InstanceKlass::cast(recv_klass());
@ -927,6 +976,7 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
} else { } else {
// at this point we are sure that resolved_method is virtual and not // at this point we are sure that resolved_method is virtual and not
// a miranda method; therefore, it must have a valid vtable index. // a miranda method; therefore, it must have a valid vtable index.
assert(!resolved_method->has_itable_index(), "");
vtable_index = resolved_method->vtable_index(); vtable_index = resolved_method->vtable_index();
// We could get a negative vtable_index for final methods, // We could get a negative vtable_index for final methods,
// because as an optimization they are they are never put in the vtable, // because as an optimization they are they are never put in the vtable,
@ -1006,6 +1056,12 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHand
lookup_instance_method_in_klasses(sel_method, recv_klass, lookup_instance_method_in_klasses(sel_method, recv_klass,
resolved_method->name(), resolved_method->name(),
resolved_method->signature(), CHECK); 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 // check if method exists
if (sel_method.is_null()) { if (sel_method.is_null()) {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
@ -1046,7 +1102,14 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHand
sel_method->signature())); sel_method->signature()));
} }
// setup result // 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();
result.set_interface(resolved_klass, recv_klass, resolved_method, sel_method, itable_index, CHECK);
} }
@ -1293,7 +1356,8 @@ void LinkResolver::resolve_invokedynamic(CallInfo& result, constantPoolHandle po
} }
if (TraceMethodHandles) { 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), ConstantPool::decode_invokedynamic_index(index),
method_name->as_C_string(), method_signature->as_C_string()); method_name->as_C_string(), method_signature->as_C_string());
tty->print(" BSM info: "); bootstrap_specifier->print(); tty->print(" BSM info: "); bootstrap_specifier->print();
@ -1342,9 +1406,16 @@ void LinkResolver::resolve_dynamic_call(CallInfo& result,
//------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------
#ifndef PRODUCT #ifndef PRODUCT
void FieldAccessInfo::print() { void CallInfo::print() {
ResourceMark rm; 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 #endif

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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. // All the necessary definitions for run-time link resolution.
// LinkInfo & its subclasses provide all the information gathered // CallInfo provides all the information gathered for a particular
// for a particular link after resolving it. A link is any reference // linked call site after resolving it. A link is any reference
// made from within the bytecodes of a method to an object outside of // 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 // that method. If the info is invalid, the link has not been resolved
// successfully. // successfully.
class LinkInfo VALUE_OBJ_CLASS_SPEC { class CallInfo 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;
public: public:
void set(KlassHandle klass, Symbol* name, int field_index, int field_offset, // Ways that a method call might be selected (or not) based on receiver type.
BasicType field_type, AccessFlags access_flags); // Note that an invokevirtual instruction might be linked with no_dispatch,
KlassHandle klass() const { return _klass; } // and an invokeinterface instruction might be linked with any of the three options
Symbol* name() const { return _name; } enum CallKind {
int field_index() const { return _field_index; } direct_call, // jump into resolved_method (must be concrete)
int field_offset() const { return _field_offset; } vtable_call, // select recv.klass.method_at_vtable(index)
BasicType field_type() const { return _field_type; } itable_call, // select recv.klass.method_at_itable(resolved_method.holder, index)
AccessFlags access_flags() const { return _access_flags; } unknown_kind = -1
};
// debugging
void print() PRODUCT_RETURN;
};
// Link information for all calls.
class CallInfo: public LinkInfo {
private: 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) KlassHandle _selected_klass; // dynamic receiver class (same as static, or subklass)
methodHandle _resolved_method; // static target method methodHandle _resolved_method; // static target method
methodHandle _selected_method; // dynamic (actual) 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_appendix; // extra argument in constant pool (if CPCE::has_appendix)
Handle _resolved_method_type; // MethodType (for invokedynamic and invokehandle call sites) Handle _resolved_method_type; // MethodType (for invokedynamic and invokehandle call sites)
void set_static( KlassHandle resolved_klass, methodHandle resolved_method , TRAPS); 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_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_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; friend class LinkResolver;
public: 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 resolved_klass() const { return _resolved_klass; }
KlassHandle selected_klass() const { return _selected_klass; } KlassHandle selected_klass() const { return _selected_klass; }
methodHandle resolved_method() const { return _resolved_method; } methodHandle resolved_method() const { return _resolved_method; }
@ -95,21 +86,43 @@ class CallInfo: public LinkInfo {
Handle resolved_method_type() const { return _resolved_method_type; } Handle resolved_method_type() const { return _resolved_method_type; }
BasicType result_type() const { return selected_method()->result_type(); } BasicType result_type() const { return selected_method()->result_type(); }
bool has_vtable_index() const { return _vtable_index >= 0; } CallKind call_kind() const { return _call_kind; }
bool is_statically_bound() const { return _vtable_index == Method::nonvirtual_vtable_index; } int call_index() const { return _call_index; }
int vtable_index() const { int vtable_index() const {
// Even for interface calls the vtable index could be non-negative. // Even for interface calls the vtable index could be non-negative.
// See CallInfo::set_interface. // See CallInfo::set_interface.
assert(has_vtable_index() || is_statically_bound(), ""); 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. // The LinkResolver is used to resolve constant-pool references at run-time.
// It does all necessary link-time checks & throws exceptions if necessary. // It does all necessary link-time checks & throws exceptions if necessary.
class LinkResolver: AllStatic { class LinkResolver: AllStatic {
friend class klassVtable;
friend class klassItable;
private: private:
static void lookup_method_in_klasses (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS); 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); static void lookup_instance_method_in_klasses (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
@ -120,7 +133,6 @@ class LinkResolver: AllStatic {
static int vtable_index_of_miranda_method(KlassHandle klass, Symbol* name, Symbol* signature, TRAPS); static int vtable_index_of_miranda_method(KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
static void resolve_klass (KlassHandle& result, constantPoolHandle pool, int index, 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_pool (KlassHandle& resolved_klass, Symbol*& method_name, Symbol*& method_signature, KlassHandle& current_klass, constantPoolHandle pool, int index, TRAPS);
@ -148,9 +160,16 @@ class LinkResolver: AllStatic {
Bytecodes::Code code, constantPoolHandle pool, int index, TRAPS); Bytecodes::Code code, constantPoolHandle pool, int index, TRAPS);
// runtime/static resolving for fields // runtime/static resolving for fields
static void resolve_field(FieldAccessInfo& result, constantPoolHandle pool, int index, Bytecodes::Code byte, bool check_only, TRAPS); static void resolve_field_access(fieldDescriptor& result, constantPoolHandle pool, int index, Bytecodes::Code byte, TRAPS);
// takes an extra bool argument "update_pool" to decide whether to update the constantPool during klass resolution. static void resolve_field(fieldDescriptor& result, KlassHandle resolved_klass, Symbol* field_name, Symbol* field_signature,
static void resolve_field(FieldAccessInfo& result, constantPoolHandle pool, int index, Bytecodes::Code byte, bool check_only, bool update_pool, TRAPS); 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: // runtime resolving:
// resolved_klass = specified class (i.e., static receiver class) // resolved_klass = specified class (i.e., static receiver class)

View file

@ -396,32 +396,6 @@ Klass* ConstantPool::klass_ref_at_if_loaded(constantPoolHandle this_oop, int whi
} }
// This is an interface for the compiler that allows accessing non-resolved entries
// in the constant pool - but still performs the validations tests. Must be used
// in a pre-parse of the compiler - to determine what it can do and not do.
// Note: We cannot update the ConstantPool from the vm_thread.
Klass* ConstantPool::klass_ref_at_if_loaded_check(constantPoolHandle this_oop, int index, TRAPS) {
int which = this_oop->klass_ref_index_at(index);
CPSlot entry = this_oop->slot_at(which);
if (entry.is_resolved()) {
assert(entry.get_klass()->is_klass(), "must be");
return entry.get_klass();
} else {
assert(entry.is_unresolved(), "must be either symbol or klass");
Symbol* name = entry.get_symbol();
oop loader = this_oop->pool_holder()->class_loader();
oop protection_domain = this_oop->pool_holder()->protection_domain();
Handle h_loader(THREAD, loader);
Handle h_prot (THREAD, protection_domain);
KlassHandle k(THREAD, SystemDictionary::find(name, h_loader, h_prot, THREAD));
// Do access check for klasses
if( k.not_null() ) verify_constant_pool_resolve(this_oop, k, CHECK_NULL);
return k();
}
}
Method* ConstantPool::method_at_if_loaded(constantPoolHandle cpool, Method* ConstantPool::method_at_if_loaded(constantPoolHandle cpool,
int which) { int which) {
if (cpool->cache() == NULL) return NULL; // nothing to load yet if (cpool->cache() == NULL) return NULL; // nothing to load yet

View file

@ -730,8 +730,6 @@ class ConstantPool : public Metadata {
static oop method_type_at_if_loaded (constantPoolHandle this_oop, int which); static oop method_type_at_if_loaded (constantPoolHandle this_oop, int which);
static Klass* klass_at_if_loaded (constantPoolHandle this_oop, int which); static Klass* klass_at_if_loaded (constantPoolHandle this_oop, int which);
static Klass* klass_ref_at_if_loaded (constantPoolHandle this_oop, int which); static Klass* klass_ref_at_if_loaded (constantPoolHandle this_oop, int which);
// Same as above - but does LinkResolving.
static Klass* klass_ref_at_if_loaded_check(constantPoolHandle this_oop, int which, TRAPS);
// Routines currently used for annotations (only called by jvm.cpp) but which might be used in the // Routines currently used for annotations (only called by jvm.cpp) but which might be used in the
// future by other Java code. These take constant pool indices rather than // future by other Java code. These take constant pool indices rather than

View file

@ -140,9 +140,10 @@ void ConstantPoolCacheEntry::set_parameter_size(int value) {
err_msg("size must not change: parameter_size=%d, value=%d", parameter_size(), value)); err_msg("size must not change: parameter_size=%d, value=%d", parameter_size(), value));
} }
void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code, void ConstantPoolCacheEntry::set_direct_or_vtable_call(Bytecodes::Code invoke_code,
methodHandle method, methodHandle method,
int vtable_index) { int vtable_index) {
bool is_vtable_call = (vtable_index >= 0); // FIXME: split this method on this boolean
assert(method->interpreter_entry() != NULL, "should have been set at this point"); assert(method->interpreter_entry() != NULL, "should have been set at this point");
assert(!method->is_obsolete(), "attempt to write obsolete method to cpCache"); assert(!method->is_obsolete(), "attempt to write obsolete method to cpCache");
@ -160,7 +161,8 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code,
// ...and fall through as if we were handling invokevirtual: // ...and fall through as if we were handling invokevirtual:
case Bytecodes::_invokevirtual: case Bytecodes::_invokevirtual:
{ {
if (method->can_be_statically_bound()) { if (!is_vtable_call) {
assert(method->can_be_statically_bound(), "");
// set_f2_as_vfinal_method checks if is_vfinal flag is true. // set_f2_as_vfinal_method checks if is_vfinal flag is true.
set_method_flags(as_TosState(method->result_type()), set_method_flags(as_TosState(method->result_type()),
( 1 << is_vfinal_shift) | ( 1 << is_vfinal_shift) |
@ -169,6 +171,7 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code,
method()->size_of_parameters()); method()->size_of_parameters());
set_f2_as_vfinal_method(method()); set_f2_as_vfinal_method(method());
} else { } else {
assert(!method->can_be_statically_bound(), "");
assert(vtable_index >= 0, "valid index"); assert(vtable_index >= 0, "valid index");
assert(!method->is_final_method(), "sanity"); assert(!method->is_final_method(), "sanity");
set_method_flags(as_TosState(method->result_type()), set_method_flags(as_TosState(method->result_type()),
@ -182,6 +185,7 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code,
case Bytecodes::_invokespecial: case Bytecodes::_invokespecial:
case Bytecodes::_invokestatic: case Bytecodes::_invokestatic:
assert(!is_vtable_call, "");
// Note: Read and preserve the value of the is_vfinal flag on any // Note: Read and preserve the value of the is_vfinal flag on any
// invokevirtual bytecode shared with this constant pool cache entry. // invokevirtual bytecode shared with this constant pool cache entry.
// It is cheap and safe to consult is_vfinal() at all times. // It is cheap and safe to consult is_vfinal() at all times.
@ -232,8 +236,22 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code,
NOT_PRODUCT(verify(tty)); NOT_PRODUCT(verify(tty));
} }
void ConstantPoolCacheEntry::set_direct_call(Bytecodes::Code invoke_code, methodHandle method) {
int index = Method::nonvirtual_vtable_index;
// index < 0; FIXME: inline and customize set_direct_or_vtable_call
set_direct_or_vtable_call(invoke_code, method, index);
}
void ConstantPoolCacheEntry::set_interface_call(methodHandle method, int index) { void ConstantPoolCacheEntry::set_vtable_call(Bytecodes::Code invoke_code, methodHandle method, int index) {
// either the method is a miranda or its holder should accept the given index
assert(method->method_holder()->is_interface() || method->method_holder()->verify_vtable_index(index), "");
// index >= 0; FIXME: inline and customize set_direct_or_vtable_call
set_direct_or_vtable_call(invoke_code, method, index);
}
void ConstantPoolCacheEntry::set_itable_call(Bytecodes::Code invoke_code, methodHandle method, int index) {
assert(method->method_holder()->verify_itable_index(index), "");
assert(invoke_code == Bytecodes::_invokeinterface, "");
InstanceKlass* interf = method->method_holder(); InstanceKlass* interf = method->method_holder();
assert(interf->is_interface(), "must be an interface"); assert(interf->is_interface(), "must be an interface");
assert(!method->is_final_method(), "interfaces do not have final methods; cannot link to one here"); assert(!method->is_final_method(), "interfaces do not have final methods; cannot link to one here");

View file

@ -219,15 +219,29 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
Klass* root_klass // needed by the GC to dirty the klass Klass* root_klass // needed by the GC to dirty the klass
); );
void set_method( // sets entry to resolved method entry private:
void set_direct_or_vtable_call(
Bytecodes::Code invoke_code, // the bytecode used for invoking the method Bytecodes::Code invoke_code, // the bytecode used for invoking the method
methodHandle method, // the method/prototype if any (NULL, otherwise) methodHandle method, // the method/prototype if any (NULL, otherwise)
int vtable_index // the vtable index if any, else negative int vtable_index // the vtable index if any, else negative
); );
void set_interface_call( public:
methodHandle method, // Resolved method void set_direct_call( // sets entry to exact concrete method entry
int index // Method index into interface Bytecodes::Code invoke_code, // the bytecode used for invoking the method
methodHandle method // the method to call
);
void set_vtable_call( // sets entry to vtable index
Bytecodes::Code invoke_code, // the bytecode used for invoking the method
methodHandle method, // resolved method which declares the vtable index
int vtable_index // the vtable index
);
void set_itable_call(
Bytecodes::Code invoke_code, // the bytecode used; must be invokeinterface
methodHandle method, // the resolved interface method
int itable_index // index into itable for the method
); );
void set_method_handle( void set_method_handle(

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,7 @@
#include "oops/instanceKlass.hpp" #include "oops/instanceKlass.hpp"
#include "oops/fieldInfo.hpp" #include "oops/fieldInfo.hpp"
#include "runtime/fieldDescriptor.hpp"
// The is the base class for iteration over the fields array // The is the base class for iteration over the fields array
// describing the declared fields in the class. Several subclasses // describing the declared fields in the class. Several subclasses
@ -43,8 +44,10 @@ class FieldStreamBase : public StackObj {
int _index; int _index;
int _limit; int _limit;
int _generic_signature_slot; int _generic_signature_slot;
fieldDescriptor _fd_buf;
FieldInfo* field() const { return FieldInfo::from_field_array(_fields, _index); } FieldInfo* field() const { return FieldInfo::from_field_array(_fields, _index); }
InstanceKlass* field_holder() const { return _constants->pool_holder(); }
int init_generic_signature_start_slot() { int init_generic_signature_start_slot() {
int length = _fields->length(); int length = _fields->length();
@ -102,6 +105,7 @@ class FieldStreamBase : public StackObj {
_index = 0; _index = 0;
_limit = klass->java_fields_count(); _limit = klass->java_fields_count();
init_generic_signature_start_slot(); init_generic_signature_start_slot();
assert(klass == field_holder(), "");
} }
FieldStreamBase(instanceKlassHandle klass) { FieldStreamBase(instanceKlassHandle klass) {
_fields = klass->fields(); _fields = klass->fields();
@ -109,6 +113,7 @@ class FieldStreamBase : public StackObj {
_index = 0; _index = 0;
_limit = klass->java_fields_count(); _limit = klass->java_fields_count();
init_generic_signature_start_slot(); init_generic_signature_start_slot();
assert(klass == field_holder(), "");
} }
// accessors // accessors
@ -180,6 +185,12 @@ class FieldStreamBase : public StackObj {
return field()->contended_group(); return field()->contended_group();
} }
// bridge to a heavier API:
fieldDescriptor& field_descriptor() const {
fieldDescriptor& field = const_cast<fieldDescriptor&>(_fd_buf);
field.reinitialize(field_holder(), _index);
return field;
}
}; };
// Iterate over only the internal fields // Iterate over only the internal fields

View file

@ -286,7 +286,6 @@ InstanceKlass::InstanceKlass(int vtable_len,
init_previous_versions(); init_previous_versions();
set_generic_signature_index(0); set_generic_signature_index(0);
release_set_methods_jmethod_ids(NULL); release_set_methods_jmethod_ids(NULL);
release_set_methods_cached_itable_indices(NULL);
set_annotations(NULL); set_annotations(NULL);
set_jvmti_cached_class_field_map(NULL); set_jvmti_cached_class_field_map(NULL);
set_initial_method_idnum(0); set_initial_method_idnum(0);
@ -1149,7 +1148,7 @@ bool InstanceKlass::find_local_field(Symbol* name, Symbol* sig, fieldDescriptor*
Symbol* f_name = fs.name(); Symbol* f_name = fs.name();
Symbol* f_sig = fs.signature(); Symbol* f_sig = fs.signature();
if (f_name == name && f_sig == sig) { if (f_name == name && f_sig == sig) {
fd->initialize(const_cast<InstanceKlass*>(this), fs.index()); fd->reinitialize(const_cast<InstanceKlass*>(this), fs.index());
return true; return true;
} }
} }
@ -1218,7 +1217,7 @@ Klass* InstanceKlass::find_field(Symbol* name, Symbol* sig, bool is_static, fiel
bool InstanceKlass::find_local_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const { bool InstanceKlass::find_local_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const {
for (JavaFieldStream fs(this); !fs.done(); fs.next()) { for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
if (fs.offset() == offset) { if (fs.offset() == offset) {
fd->initialize(const_cast<InstanceKlass*>(this), fs.index()); fd->reinitialize(const_cast<InstanceKlass*>(this), fs.index());
if (fd->is_static() == is_static) return true; if (fd->is_static() == is_static) return true;
} }
} }
@ -1251,8 +1250,7 @@ void InstanceKlass::methods_do(void f(Method* method)) {
void InstanceKlass::do_local_static_fields(FieldClosure* cl) { void InstanceKlass::do_local_static_fields(FieldClosure* cl) {
for (JavaFieldStream fs(this); !fs.done(); fs.next()) { for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
if (fs.access_flags().is_static()) { if (fs.access_flags().is_static()) {
fieldDescriptor fd; fieldDescriptor& fd = fs.field_descriptor();
fd.initialize(this, fs.index());
cl->do_field(&fd); cl->do_field(&fd);
} }
} }
@ -1268,8 +1266,7 @@ void InstanceKlass::do_local_static_fields(void f(fieldDescriptor*, TRAPS), TRAP
void InstanceKlass::do_local_static_fields_impl(instanceKlassHandle this_oop, void f(fieldDescriptor* fd, TRAPS), TRAPS) { void InstanceKlass::do_local_static_fields_impl(instanceKlassHandle this_oop, void f(fieldDescriptor* fd, TRAPS), TRAPS) {
for (JavaFieldStream fs(this_oop()); !fs.done(); fs.next()) { for (JavaFieldStream fs(this_oop()); !fs.done(); fs.next()) {
if (fs.access_flags().is_static()) { if (fs.access_flags().is_static()) {
fieldDescriptor fd; fieldDescriptor& fd = fs.field_descriptor();
fd.initialize(this_oop(), fs.index());
f(&fd, CHECK); f(&fd, CHECK);
} }
} }
@ -1291,7 +1288,7 @@ void InstanceKlass::do_nonstatic_fields(FieldClosure* cl) {
int* fields_sorted = NEW_C_HEAP_ARRAY(int, 2*(length+1), mtClass); int* fields_sorted = NEW_C_HEAP_ARRAY(int, 2*(length+1), mtClass);
int j = 0; int j = 0;
for (int i = 0; i < length; i += 1) { for (int i = 0; i < length; i += 1) {
fd.initialize(this, i); fd.reinitialize(this, i);
if (!fd.is_static()) { if (!fd.is_static()) {
fields_sorted[j + 0] = fd.offset(); fields_sorted[j + 0] = fd.offset();
fields_sorted[j + 1] = i; fields_sorted[j + 1] = i;
@ -1303,7 +1300,7 @@ void InstanceKlass::do_nonstatic_fields(FieldClosure* cl) {
// _sort_Fn is defined in growableArray.hpp. // _sort_Fn is defined in growableArray.hpp.
qsort(fields_sorted, length/2, 2*sizeof(int), (_sort_Fn)compare_fields_by_offset); qsort(fields_sorted, length/2, 2*sizeof(int), (_sort_Fn)compare_fields_by_offset);
for (int i = 0; i < length; i += 2) { for (int i = 0; i < length; i += 2) {
fd.initialize(this, fields_sorted[i + 1]); fd.reinitialize(this, fields_sorted[i + 1]);
assert(!fd.is_static() && fd.offset() == fields_sorted[i], "only nonstatic fields"); assert(!fd.is_static() && fd.offset() == fields_sorted[i], "only nonstatic fields");
cl->do_field(&fd); cl->do_field(&fd);
} }
@ -1686,87 +1683,6 @@ jmethodID InstanceKlass::jmethod_id_or_null(Method* method) {
} }
// Cache an itable index
void InstanceKlass::set_cached_itable_index(size_t idnum, int index) {
int* indices = methods_cached_itable_indices_acquire();
int* to_dealloc_indices = NULL;
// We use a double-check locking idiom here because this cache is
// performance sensitive. In the normal system, this cache only
// transitions from NULL to non-NULL which is safe because we use
// release_set_methods_cached_itable_indices() to advertise the
// new cache. A partially constructed cache should never be seen
// by a racing thread. Cache reads and writes proceed without a
// lock, but creation of the cache itself requires no leaks so a
// lock is generally acquired in that case.
//
// If the RedefineClasses() API has been used, then this cache can
// grow and we'll have transitions from non-NULL to bigger non-NULL.
// Cache creation requires no leaks and we require safety between all
// cache accesses and freeing of the old cache so a lock is generally
// acquired when the RedefineClasses() API has been used.
if (indices == NULL || idnum_can_increment()) {
// we need a cache or the cache can grow
MutexLocker ml(JNICachedItableIndex_lock);
// reacquire the cache to see if another thread already did the work
indices = methods_cached_itable_indices_acquire();
size_t length = 0;
// cache size is stored in element[0], other elements offset by one
if (indices == NULL || (length = (size_t)indices[0]) <= idnum) {
size_t size = MAX2(idnum+1, (size_t)idnum_allocated_count());
int* new_indices = NEW_C_HEAP_ARRAY(int, size+1, mtClass);
new_indices[0] = (int)size;
// copy any existing entries
size_t i;
for (i = 0; i < length; i++) {
new_indices[i+1] = indices[i+1];
}
// Set all the rest to -1
for (i = length; i < size; i++) {
new_indices[i+1] = -1;
}
if (indices != NULL) {
// We have an old cache to delete so save it for after we
// drop the lock.
to_dealloc_indices = indices;
}
release_set_methods_cached_itable_indices(indices = new_indices);
}
if (idnum_can_increment()) {
// this cache can grow so we have to write to it safely
indices[idnum+1] = index;
}
} else {
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
}
if (!idnum_can_increment()) {
// The cache cannot grow and this JNI itable index value does not
// have to be unique like a jmethodID. If there is a race to set it,
// it doesn't matter.
indices[idnum+1] = index;
}
if (to_dealloc_indices != NULL) {
// we allocated a new cache so free the old one
FreeHeap(to_dealloc_indices);
}
}
// Retrieve a cached itable index
int InstanceKlass::cached_itable_index(size_t idnum) {
int* indices = methods_cached_itable_indices_acquire();
if (indices != NULL && ((size_t)indices[0]) > idnum) {
// indices exist and are long enough, retrieve possible cached
return indices[idnum+1];
}
return -1;
}
// //
// Walk the list of dependent nmethods searching for nmethods which // Walk the list of dependent nmethods searching for nmethods which
// are dependent on the changes that were passed in and mark them for // are dependent on the changes that were passed in and mark them for
@ -2326,12 +2242,6 @@ void InstanceKlass::release_C_heap_structures() {
} }
} }
int* indices = methods_cached_itable_indices_acquire();
if (indices != (int*)NULL) {
release_set_methods_cached_itable_indices(NULL);
FreeHeap(indices);
}
// release dependencies // release dependencies
nmethodBucket* b = _dependencies; nmethodBucket* b = _dependencies;
_dependencies = NULL; _dependencies = NULL;
@ -2782,6 +2692,18 @@ static const char* state_names[] = {
"allocated", "loaded", "linked", "being_initialized", "fully_initialized", "initialization_error" "allocated", "loaded", "linked", "being_initialized", "fully_initialized", "initialization_error"
}; };
static void print_vtable(intptr_t* start, int len, outputStream* st) {
for (int i = 0; i < len; i++) {
intptr_t e = start[i];
st->print("%d : " INTPTR_FORMAT, i, e);
if (e != 0 && ((Metadata*)e)->is_metaspace_object()) {
st->print(" ");
((Metadata*)e)->print_value_on(st);
}
st->cr();
}
}
void InstanceKlass::print_on(outputStream* st) const { void InstanceKlass::print_on(outputStream* st) const {
assert(is_klass(), "must be klass"); assert(is_klass(), "must be klass");
Klass::print_on(st); Klass::print_on(st);
@ -2816,7 +2738,7 @@ void InstanceKlass::print_on(outputStream* st) const {
st->print(BULLET"arrays: "); array_klasses()->print_value_on_maybe_null(st); st->cr(); st->print(BULLET"arrays: "); array_klasses()->print_value_on_maybe_null(st); st->cr();
st->print(BULLET"methods: "); methods()->print_value_on(st); st->cr(); st->print(BULLET"methods: "); methods()->print_value_on(st); st->cr();
if (Verbose) { if (Verbose || WizardMode) {
Array<Method*>* method_array = methods(); Array<Method*>* method_array = methods();
for(int i = 0; i < method_array->length(); i++) { for(int i = 0; i < method_array->length(); i++) {
st->print("%d : ", i); method_array->at(i)->print_value(); st->cr(); st->print("%d : ", i); method_array->at(i)->print_value(); st->cr();
@ -2874,7 +2796,9 @@ void InstanceKlass::print_on(outputStream* st) const {
st->print(BULLET"inner classes: "); inner_classes()->print_value_on(st); st->cr(); st->print(BULLET"inner classes: "); inner_classes()->print_value_on(st); st->cr();
st->print(BULLET"java mirror: "); java_mirror()->print_value_on(st); st->cr(); st->print(BULLET"java mirror: "); java_mirror()->print_value_on(st); st->cr();
st->print(BULLET"vtable length %d (start addr: " INTPTR_FORMAT ")", vtable_length(), start_of_vtable()); st->cr(); st->print(BULLET"vtable length %d (start addr: " INTPTR_FORMAT ")", vtable_length(), start_of_vtable()); st->cr();
if (vtable_length() > 0 && (Verbose || WizardMode)) print_vtable(start_of_vtable(), vtable_length(), st);
st->print(BULLET"itable length %d (start addr: " INTPTR_FORMAT ")", itable_length(), start_of_itable()); st->cr(); st->print(BULLET"itable length %d (start addr: " INTPTR_FORMAT ")", itable_length(), start_of_itable()); st->cr();
if (itable_length() > 0 && (Verbose || WizardMode)) print_vtable(start_of_itable(), itable_length(), st);
st->print_cr(BULLET"---- static fields (%d words):", static_field_size()); st->print_cr(BULLET"---- static fields (%d words):", static_field_size());
FieldPrinter print_static_field(st); FieldPrinter print_static_field(st);
((InstanceKlass*)this)->do_local_static_fields(&print_static_field); ((InstanceKlass*)this)->do_local_static_fields(&print_static_field);
@ -2896,6 +2820,7 @@ void InstanceKlass::print_on(outputStream* st) const {
void InstanceKlass::print_value_on(outputStream* st) const { void InstanceKlass::print_value_on(outputStream* st) const {
assert(is_klass(), "must be klass"); assert(is_klass(), "must be klass");
if (Verbose || WizardMode) access_flags().print_on(st);
name()->print_value_on(st); name()->print_value_on(st);
} }

View file

@ -245,7 +245,6 @@ class InstanceKlass: public Klass {
MemberNameTable* _member_names; // Member names MemberNameTable* _member_names; // Member names
JNIid* _jni_ids; // First JNI identifier for static fields in this class JNIid* _jni_ids; // First JNI identifier for static fields in this class
jmethodID* _methods_jmethod_ids; // jmethodIDs corresponding to method_idnum, or NULL if none jmethodID* _methods_jmethod_ids; // jmethodIDs corresponding to method_idnum, or NULL if none
int* _methods_cached_itable_indices; // itable_index cache for JNI invoke corresponding to methods idnum, or NULL
nmethodBucket* _dependencies; // list of dependent nmethods nmethodBucket* _dependencies; // list of dependent nmethods
nmethod* _osr_nmethods_head; // Head of list of on-stack replacement nmethods for this class nmethod* _osr_nmethods_head; // Head of list of on-stack replacement nmethods for this class
BreakpointInfo* _breakpoints; // bpt lists, managed by Method* BreakpointInfo* _breakpoints; // bpt lists, managed by Method*
@ -690,10 +689,6 @@ class InstanceKlass: public Klass {
size_t *length_p, jmethodID* id_p); size_t *length_p, jmethodID* id_p);
jmethodID jmethod_id_or_null(Method* method); jmethodID jmethod_id_or_null(Method* method);
// cached itable index support
void set_cached_itable_index(size_t idnum, int index);
int cached_itable_index(size_t idnum);
// annotations support // annotations support
Annotations* annotations() const { return _annotations; } Annotations* annotations() const { return _annotations; }
void set_annotations(Annotations* anno) { _annotations = anno; } void set_annotations(Annotations* anno) { _annotations = anno; }
@ -994,11 +989,6 @@ private:
void release_set_methods_jmethod_ids(jmethodID* jmeths) void release_set_methods_jmethod_ids(jmethodID* jmeths)
{ OrderAccess::release_store_ptr(&_methods_jmethod_ids, jmeths); } { OrderAccess::release_store_ptr(&_methods_jmethod_ids, jmeths); }
int* methods_cached_itable_indices_acquire() const
{ return (int*)OrderAccess::load_ptr_acquire(&_methods_cached_itable_indices); }
void release_set_methods_cached_itable_indices(int* indices)
{ OrderAccess::release_store_ptr(&_methods_cached_itable_indices, indices); }
// Lock during initialization // Lock during initialization
public: public:
// Lock for (1) initialization; (2) access to the ConstantPool of this class. // Lock for (1) initialization; (2) access to the ConstantPool of this class.

View file

@ -674,13 +674,23 @@ void Klass::oop_verify_on(oop obj, outputStream* st) {
#ifndef PRODUCT #ifndef PRODUCT
void Klass::verify_vtable_index(int i) { bool Klass::verify_vtable_index(int i) {
if (oop_is_instance()) { if (oop_is_instance()) {
assert(i>=0 && i<((InstanceKlass*)this)->vtable_length()/vtableEntry::size(), "index out of bounds"); int limit = ((InstanceKlass*)this)->vtable_length()/vtableEntry::size();
assert(i >= 0 && i < limit, err_msg("index %d out of bounds %d", i, limit));
} else { } else {
assert(oop_is_array(), "Must be"); assert(oop_is_array(), "Must be");
assert(i>=0 && i<((ArrayKlass*)this)->vtable_length()/vtableEntry::size(), "index out of bounds"); int limit = ((ArrayKlass*)this)->vtable_length()/vtableEntry::size();
assert(i >= 0 && i < limit, err_msg("index %d out of bounds %d", i, limit));
} }
return true;
}
bool Klass::verify_itable_index(int i) {
assert(oop_is_instance(), "");
int method_count = klassItable::method_count_for_interface(this);
assert(i >= 0 && i < method_count, "index out of bounds");
return true;
} }
#endif #endif

View file

@ -699,7 +699,8 @@ class Klass : public Metadata {
void verify(bool check_dictionary = true) { verify_on(tty, check_dictionary); } void verify(bool check_dictionary = true) { verify_on(tty, check_dictionary); }
#ifndef PRODUCT #ifndef PRODUCT
void verify_vtable_index(int index); bool verify_vtable_index(int index);
bool verify_itable_index(int index);
#endif #endif
virtual void oop_verify_on(oop obj, outputStream* st); virtual void oop_verify_on(oop obj, outputStream* st);

View file

@ -47,11 +47,12 @@ inline InstanceKlass* klassVtable::ik() const {
// this function computes the vtable size (including the size needed for miranda // this function computes the vtable size (including the size needed for miranda
// methods) and the number of miranda methods in this class // methods) and the number of miranda methods in this class.
// Note on Miranda methods: Let's say there is a class C that implements // Note on Miranda methods: Let's say there is a class C that implements
// interface I. Let's say there is a method m in I that neither C nor any // interface I, and none of C's superclasses implements I.
// of its super classes implement (i.e there is no method of any access, with // Let's say there is an abstract method m in I that neither C
// the same name and signature as m), then m is a Miranda method which is // nor any of its super classes implement (i.e there is no method of any access,
// with the same name and signature as m), then m is a Miranda method which is
// entered as a public abstract method in C's vtable. From then on it should // entered as a public abstract method in C's vtable. From then on it should
// treated as any other public method in C for method over-ride purposes. // treated as any other public method in C for method over-ride purposes.
void klassVtable::compute_vtable_size_and_num_mirandas( void klassVtable::compute_vtable_size_and_num_mirandas(
@ -111,10 +112,13 @@ void klassVtable::compute_vtable_size_and_num_mirandas(
} }
int klassVtable::index_of(Method* m, int len) const { int klassVtable::index_of(Method* m, int len) const {
assert(m->vtable_index() >= 0, "do not ask this of non-vtable methods"); assert(m->has_vtable_index(), "do not ask this of non-vtable methods");
return m->vtable_index(); return m->vtable_index();
} }
// Copy super class's vtable to the first part (prefix) of this class's vtable,
// and return the number of entries copied. Expects that 'super' is the Java
// super class (arrays can have "array" super classes that must be skipped).
int klassVtable::initialize_from_super(KlassHandle super) { int klassVtable::initialize_from_super(KlassHandle super) {
if (super.is_null()) { if (super.is_null()) {
return 0; return 0;
@ -139,14 +143,14 @@ int klassVtable::initialize_from_super(KlassHandle super) {
} }
} }
// Revised lookup semantics introduced 1.3 (Kestral beta) //
// Revised lookup semantics introduced 1.3 (Kestrel beta)
void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) { void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
// Note: Arrays can have intermediate array supers. Use java_super to skip them. // Note: Arrays can have intermediate array supers. Use java_super to skip them.
KlassHandle super (THREAD, klass()->java_super()); KlassHandle super (THREAD, klass()->java_super());
int nofNewEntries = 0; int nofNewEntries = 0;
if (PrintVtables && !klass()->oop_is_array()) { if (PrintVtables && !klass()->oop_is_array()) {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
tty->print_cr("Initializing: %s", _klass->name()->as_C_string()); tty->print_cr("Initializing: %s", _klass->name()->as_C_string());
@ -174,8 +178,10 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
int len = methods->length(); int len = methods->length();
int initialized = super_vtable_len; int initialized = super_vtable_len;
// update_inherited_vtable can stop for gc - ensure using handles // Check each of this class's methods against super;
// if override, replace in copy of super vtable, otherwise append to end
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
// update_inherited_vtable can stop for gc - ensure using handles
HandleMark hm(THREAD); HandleMark hm(THREAD);
assert(methods->at(i)->is_method(), "must be a Method*"); assert(methods->at(i)->is_method(), "must be a Method*");
methodHandle mh(THREAD, methods->at(i)); methodHandle mh(THREAD, methods->at(i));
@ -189,11 +195,11 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
} }
} }
// add miranda methods; it will also update the value of initialized // add miranda methods to end of vtable.
fill_in_mirandas(&initialized); initialized = fill_in_mirandas(initialized);
// In class hierarchies where the accessibility is not increasing (i.e., going from private -> // In class hierarchies where the accessibility is not increasing (i.e., going from private ->
// package_private -> publicprotected), the vtable might actually be smaller than our initial // package_private -> public/protected), the vtable might actually be smaller than our initial
// calculation. // calculation.
assert(initialized <= _length, "vtable initialization failed"); assert(initialized <= _length, "vtable initialization failed");
for(;initialized < _length; initialized++) { for(;initialized < _length; initialized++) {
@ -248,14 +254,8 @@ InstanceKlass* klassVtable::find_transitive_override(InstanceKlass* initialsuper
return superk; return superk;
} }
// Methods that are "effectively" final don't need vtable entries.
bool method_is_effectively_final(
AccessFlags klass_flags, methodHandle target) {
return target->is_final() || klass_flags.is_final() && !target->is_overpass();
}
// Update child's copy of super vtable for overrides // Update child's copy of super vtable for overrides
// OR return true if a new vtable entry is required // OR return true if a new vtable entry is required.
// Only called for InstanceKlass's, i.e. not for arrays // Only called for InstanceKlass's, i.e. not for arrays
// If that changed, could not use _klass as handle for klass // If that changed, could not use _klass as handle for klass
bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle target_method, int super_vtable_len, bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle target_method, int super_vtable_len,
@ -263,6 +263,7 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar
ResourceMark rm; ResourceMark rm;
bool allocate_new = true; bool allocate_new = true;
assert(klass->oop_is_instance(), "must be InstanceKlass"); assert(klass->oop_is_instance(), "must be InstanceKlass");
assert(klass == target_method()->method_holder(), "caller resp.");
// Initialize the method's vtable index to "nonvirtual". // Initialize the method's vtable index to "nonvirtual".
// If we allocate a vtable entry, we will update it to a non-negative number. // If we allocate a vtable entry, we will update it to a non-negative number.
@ -273,11 +274,17 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar
return false; return false;
} }
if (method_is_effectively_final(klass->access_flags(), target_method)) { if (target_method->is_final_method(klass->access_flags())) {
// a final method never needs a new entry; final methods can be statically // a final method never needs a new entry; final methods can be statically
// resolved and they have to be present in the vtable only if they override // resolved and they have to be present in the vtable only if they override
// a super's method, in which case they re-use its entry // a super's method, in which case they re-use its entry
allocate_new = false; allocate_new = false;
} else if (klass->is_interface()) {
allocate_new = false; // see note below in needs_new_vtable_entry
// An interface never allocates new vtable slots, only inherits old ones.
// This method will either be assigned its own itable index later,
// or be assigned an inherited vtable index in the loop below.
target_method()->set_vtable_index(Method::pending_itable_index);
} }
// we need a new entry if there is no superclass // we need a new entry if there is no superclass
@ -411,8 +418,14 @@ bool klassVtable::needs_new_vtable_entry(methodHandle target_method,
Symbol* classname, Symbol* classname,
AccessFlags class_flags, AccessFlags class_flags,
TRAPS) { TRAPS) {
if (class_flags.is_interface()) {
// Interfaces do not use vtables, so there is no point to assigning
// a vtable index to any of their methods. If we refrain from doing this,
// we can use Method::_vtable_index to hold the itable index
return false;
}
if (method_is_effectively_final(class_flags, target_method) || if (target_method->is_final_method(class_flags) ||
// a final method never needs a new entry; final methods can be statically // a final method never needs a new entry; final methods can be statically
// resolved and they have to be present in the vtable only if they override // resolved and they have to be present in the vtable only if they override
// a super's method, in which case they re-use its entry // a super's method, in which case they re-use its entry
@ -500,7 +513,8 @@ int klassVtable::index_of_miranda(Symbol* name, Symbol* signature) {
return Method::invalid_vtable_index; return Method::invalid_vtable_index;
} }
// check if an entry is miranda // check if an entry at an index is miranda
// requires that method m at entry be declared ("held") by an interface.
bool klassVtable::is_miranda_entry_at(int i) { bool klassVtable::is_miranda_entry_at(int i) {
Method* m = method_at(i); Method* m = method_at(i);
Klass* method_holder = m->method_holder(); Klass* method_holder = m->method_holder();
@ -516,7 +530,9 @@ bool klassVtable::is_miranda_entry_at(int i) {
return false; return false;
} }
// check if a method is a miranda method, given a class's methods table and it's super // check if a method is a miranda method, given a class's methods table and its super
// "miranda" means not static, not defined by this class, and not defined
// in super unless it is private and therefore inaccessible to this class.
// the caller must make sure that the method belongs to an interface implemented by the class // the caller must make sure that the method belongs to an interface implemented by the class
bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods, Klass* super) { bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods, Klass* super) {
if (m->is_static()) { if (m->is_static()) {
@ -541,6 +557,14 @@ bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods, Klass* su
return false; return false;
} }
// Scans current_interface_methods for miranda methods that do not
// already appear in new_mirandas and are also not defined-and-non-private
// in super (superclass). These mirandas are added to all_mirandas if it is
// not null; in addition, those that are not duplicates of miranda methods
// inherited by super from its interfaces are added to new_mirandas.
// Thus, new_mirandas will be the set of mirandas that this class introduces,
// all_mirandas will be the set of all mirandas applicable to this class
// including all defined in superclasses.
void klassVtable::add_new_mirandas_to_lists( void klassVtable::add_new_mirandas_to_lists(
GrowableArray<Method*>* new_mirandas, GrowableArray<Method*>* all_mirandas, GrowableArray<Method*>* new_mirandas, GrowableArray<Method*>* all_mirandas,
Array<Method*>* current_interface_methods, Array<Method*>* class_methods, Array<Method*>* current_interface_methods, Array<Method*>* class_methods,
@ -599,17 +623,22 @@ void klassVtable::get_mirandas(GrowableArray<Method*>* new_mirandas,
} }
} }
// fill in mirandas // Discover miranda methods ("miranda" = "interface abstract, no binding"),
void klassVtable::fill_in_mirandas(int* initialized) { // and append them into the vtable starting at index initialized,
// return the new value of initialized.
int klassVtable::fill_in_mirandas(int initialized) {
GrowableArray<Method*> mirandas(20); GrowableArray<Method*> mirandas(20);
get_mirandas(&mirandas, NULL, ik()->super(), ik()->methods(), get_mirandas(&mirandas, NULL, ik()->super(), ik()->methods(),
ik()->local_interfaces()); ik()->local_interfaces());
for (int i = 0; i < mirandas.length(); i++) { for (int i = 0; i < mirandas.length(); i++) {
put_method_at(mirandas.at(i), *initialized); put_method_at(mirandas.at(i), initialized);
++(*initialized); ++initialized;
} }
return initialized;
} }
// Copy this class's vtable to the vtable beginning at start.
// Used to copy superclass vtable to prefix of subclass's vtable.
void klassVtable::copy_vtable_to(vtableEntry* start) { void klassVtable::copy_vtable_to(vtableEntry* start) {
Copy::disjoint_words((HeapWord*)table(), (HeapWord*)start, _length * vtableEntry::size()); Copy::disjoint_words((HeapWord*)table(), (HeapWord*)start, _length * vtableEntry::size());
} }
@ -723,6 +752,12 @@ static int initialize_count = 0;
// Initialization // Initialization
void klassItable::initialize_itable(bool checkconstraints, TRAPS) { void klassItable::initialize_itable(bool checkconstraints, TRAPS) {
if (_klass->is_interface()) {
// This needs to go after vtable indexes are assigned but
// before implementors need to know the number of itable indexes.
assign_itable_indexes_for_interface(_klass());
}
// Cannot be setup doing bootstrapping, interfaces don't have // Cannot be setup doing bootstrapping, interfaces don't have
// itables, and klass with only ones entry have empty itables // itables, and klass with only ones entry have empty itables
if (Universe::is_bootstrapping() || if (Universe::is_bootstrapping() ||
@ -754,45 +789,89 @@ void klassItable::initialize_itable(bool checkconstraints, TRAPS) {
} }
inline bool interface_method_needs_itable_index(Method* m) {
if (m->is_static()) return false; // e.g., Stream.empty
if (m->is_initializer()) return false; // <init> or <clinit>
// If an interface redeclares a method from java.lang.Object,
// it should already have a vtable index, don't touch it.
// e.g., CharSequence.toString (from initialize_vtable)
// if (m->has_vtable_index()) return false; // NO!
return true;
}
int klassItable::assign_itable_indexes_for_interface(Klass* klass) {
// an interface does not have an itable, but its methods need to be numbered
if (TraceItables) tty->print_cr("%3d: Initializing itable for interface %s", ++initialize_count,
klass->name()->as_C_string());
Array<Method*>* methods = InstanceKlass::cast(klass)->methods();
int nof_methods = methods->length();
int ime_num = 0;
for (int i = 0; i < nof_methods; i++) {
Method* m = methods->at(i);
if (interface_method_needs_itable_index(m)) {
assert(!m->is_final_method(), "no final interface methods");
// If m is already assigned a vtable index, do not disturb it.
if (!m->has_vtable_index()) {
assert(m->vtable_index() == Method::pending_itable_index, "set by initialize_vtable");
m->set_itable_index(ime_num);
// Progress to next itable entry
ime_num++;
}
}
}
assert(ime_num == method_count_for_interface(klass), "proper sizing");
return ime_num;
}
int klassItable::method_count_for_interface(Klass* interf) {
assert(interf->oop_is_instance(), "must be");
assert(interf->is_interface(), "must be");
Array<Method*>* methods = InstanceKlass::cast(interf)->methods();
int nof_methods = methods->length();
while (nof_methods > 0) {
Method* m = methods->at(nof_methods-1);
if (m->has_itable_index()) {
int length = m->itable_index() + 1;
#ifdef ASSERT
while (nof_methods = 0) {
m = methods->at(--nof_methods);
assert(!m->has_itable_index() || m->itable_index() < length, "");
}
#endif //ASSERT
return length; // return the rightmost itable index, plus one
}
nof_methods -= 1;
}
// no methods have itable indexes
return 0;
}
void klassItable::initialize_itable_for_interface(int method_table_offset, KlassHandle interf_h, bool checkconstraints, TRAPS) { void klassItable::initialize_itable_for_interface(int method_table_offset, KlassHandle interf_h, bool checkconstraints, TRAPS) {
Array<Method*>* methods = InstanceKlass::cast(interf_h())->methods(); Array<Method*>* methods = InstanceKlass::cast(interf_h())->methods();
int nof_methods = methods->length(); int nof_methods = methods->length();
HandleMark hm; HandleMark hm;
KlassHandle klass = _klass;
assert(nof_methods > 0, "at least one method must exist for interface to be in vtable"); assert(nof_methods > 0, "at least one method must exist for interface to be in vtable");
Handle interface_loader (THREAD, InstanceKlass::cast(interf_h())->class_loader()); Handle interface_loader (THREAD, InstanceKlass::cast(interf_h())->class_loader());
int ime_num = 0;
// Skip first Method* if it is a class initializer int ime_count = method_count_for_interface(interf_h());
int i = methods->at(0)->is_static_initializer() ? 1 : 0; for (int i = 0; i < nof_methods; i++) {
// m, method_name, method_signature, klass reset each loop so they
// don't need preserving across check_signature_loaders call
// methods needs a handle in case of gc from check_signature_loaders
for(; i < nof_methods; i++) {
Method* m = methods->at(i); Method* m = methods->at(i);
Symbol* method_name = m->name(); methodHandle target;
Symbol* method_signature = m->signature(); if (m->has_itable_index()) {
LinkResolver::lookup_instance_method_in_klasses(target, _klass, m->name(), m->signature(), CHECK);
// This is same code as in Linkresolver::lookup_instance_method_in_klasses
Method* target = klass->uncached_lookup_method(method_name, method_signature);
while (target != NULL && target->is_static()) {
// continue with recursive lookup through the superclass
Klass* super = target->method_holder()->super();
target = (super == NULL) ? (Method*)NULL : super->uncached_lookup_method(method_name, method_signature);
} }
if (target == NULL || !target->is_public() || target->is_abstract()) { if (target == NULL || !target->is_public() || target->is_abstract()) {
// Entry do not resolve. Leave it empty // Entry do not resolve. Leave it empty
} else { } else {
// Entry did resolve, check loader constraints before initializing // Entry did resolve, check loader constraints before initializing
// if checkconstraints requested // if checkconstraints requested
methodHandle target_h (THREAD, target); // preserve across gc
if (checkconstraints) { if (checkconstraints) {
Handle method_holder_loader (THREAD, target->method_holder()->class_loader()); Handle method_holder_loader (THREAD, target->method_holder()->class_loader());
if (method_holder_loader() != interface_loader()) { if (method_holder_loader() != interface_loader()) {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
Symbol* failed_type_symbol = Symbol* failed_type_symbol =
SystemDictionary::check_signature_loaders(method_signature, SystemDictionary::check_signature_loaders(m->signature(),
method_holder_loader, method_holder_loader,
interface_loader, interface_loader,
true, CHECK); true, CHECK);
@ -803,9 +882,9 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass
"and the class loader (instance of %s) for interface " "and the class loader (instance of %s) for interface "
"%s have different Class objects for the type %s " "%s have different Class objects for the type %s "
"used in the signature"; "used in the signature";
char* sig = target_h()->name_and_sig_as_C_string(); char* sig = target()->name_and_sig_as_C_string();
const char* loader1 = SystemDictionary::loader_name(method_holder_loader()); const char* loader1 = SystemDictionary::loader_name(method_holder_loader());
char* current = klass->name()->as_C_string(); char* current = _klass->name()->as_C_string();
const char* loader2 = SystemDictionary::loader_name(interface_loader()); const char* loader2 = SystemDictionary::loader_name(interface_loader());
char* iface = InstanceKlass::cast(interf_h())->name()->as_C_string(); char* iface = InstanceKlass::cast(interf_h())->name()->as_C_string();
char* failed_type_name = failed_type_symbol->as_C_string(); char* failed_type_name = failed_type_symbol->as_C_string();
@ -821,10 +900,10 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass
} }
// ime may have moved during GC so recalculate address // ime may have moved during GC so recalculate address
itableOffsetEntry::method_entry(_klass(), method_table_offset)[ime_num].initialize(target_h()); int ime_num = m->itable_index();
assert(ime_num < ime_count, "oob");
itableOffsetEntry::method_entry(_klass(), method_table_offset)[ime_num].initialize(target());
} }
// Progress to next entry
ime_num++;
} }
} }
@ -913,20 +992,22 @@ class InterfaceVisiterClosure : public StackObj {
virtual void doit(Klass* intf, int method_count) = 0; virtual void doit(Klass* intf, int method_count) = 0;
}; };
// Visit all interfaces with at-least one method (excluding <clinit>) // Visit all interfaces with at least one itable method
void visit_all_interfaces(Array<Klass*>* transitive_intf, InterfaceVisiterClosure *blk) { void visit_all_interfaces(Array<Klass*>* transitive_intf, InterfaceVisiterClosure *blk) {
// Handle array argument // Handle array argument
for(int i = 0; i < transitive_intf->length(); i++) { for(int i = 0; i < transitive_intf->length(); i++) {
Klass* intf = transitive_intf->at(i); Klass* intf = transitive_intf->at(i);
assert(intf->is_interface(), "sanity check"); assert(intf->is_interface(), "sanity check");
// Find no. of methods excluding a <clinit> // Find no. of itable methods
int method_count = InstanceKlass::cast(intf)->methods()->length(); int method_count = 0;
if (method_count > 0) { // method_count = klassItable::method_count_for_interface(intf);
Method* m = InstanceKlass::cast(intf)->methods()->at(0); Array<Method*>* methods = InstanceKlass::cast(intf)->methods();
assert(m != NULL && m->is_method(), "sanity check"); if (methods->length() > 0) {
if (m->name() == vmSymbols::object_initializer_name()) { for (int i = methods->length(); --i >= 0; ) {
method_count--; if (interface_method_needs_itable_index(methods->at(i))) {
method_count++;
}
} }
} }
@ -1024,40 +1105,26 @@ void klassItable::setup_itable_offset_table(instanceKlassHandle klass) {
} }
// m must be a method in an interface // inverse to itable_index
int klassItable::compute_itable_index(Method* m) {
InstanceKlass* intf = m->method_holder();
assert(intf->is_interface(), "sanity check");
Array<Method*>* methods = intf->methods();
int index = 0;
while(methods->at(index) != m) {
index++;
assert(index < methods->length(), "should find index for resolve_invoke");
}
// Adjust for <clinit>, which is left out of table if first method
if (methods->length() > 0 && methods->at(0)->is_static_initializer()) {
index--;
}
return index;
}
// inverse to compute_itable_index
Method* klassItable::method_for_itable_index(Klass* intf, int itable_index) { Method* klassItable::method_for_itable_index(Klass* intf, int itable_index) {
assert(InstanceKlass::cast(intf)->is_interface(), "sanity check"); assert(InstanceKlass::cast(intf)->is_interface(), "sanity check");
assert(intf->verify_itable_index(itable_index), "");
Array<Method*>* methods = InstanceKlass::cast(intf)->methods(); Array<Method*>* methods = InstanceKlass::cast(intf)->methods();
int index = itable_index; if (itable_index < 0 || itable_index >= method_count_for_interface(intf))
// Adjust for <clinit>, which is left out of table if first method
if (methods->length() > 0 && methods->at(0)->is_static_initializer()) {
index++;
}
if (itable_index < 0 || index >= methods->length())
return NULL; // help caller defend against bad indexes return NULL; // help caller defend against bad indexes
int index = itable_index;
Method* m = methods->at(index); Method* m = methods->at(index);
assert(compute_itable_index(m) == itable_index, "correct inverse"); int index2 = -1;
while (!m->has_itable_index() ||
(index2 = m->itable_index()) != itable_index) {
assert(index2 < itable_index, "monotonic");
if (++index == methods->length())
return NULL;
m = methods->at(index);
}
assert(m->itable_index() == itable_index, "correct inverse");
return m; return m;
} }

View file

@ -124,7 +124,7 @@ class klassVtable : public ResourceObj {
// support for miranda methods // support for miranda methods
bool is_miranda_entry_at(int i); bool is_miranda_entry_at(int i);
void fill_in_mirandas(int* initialized); int fill_in_mirandas(int initialized);
static bool is_miranda(Method* m, Array<Method*>* class_methods, Klass* super); static bool is_miranda(Method* m, Array<Method*>* class_methods, Klass* super);
static void add_new_mirandas_to_lists( static void add_new_mirandas_to_lists(
GrowableArray<Method*>* new_mirandas, GrowableArray<Method*>* new_mirandas,
@ -290,12 +290,12 @@ class klassItable : public ResourceObj {
#endif // INCLUDE_JVMTI #endif // INCLUDE_JVMTI
// Setup of itable // Setup of itable
static int assign_itable_indexes_for_interface(Klass* klass);
static int method_count_for_interface(Klass* klass);
static int compute_itable_size(Array<Klass*>* transitive_interfaces); static int compute_itable_size(Array<Klass*>* transitive_interfaces);
static void setup_itable_offset_table(instanceKlassHandle klass); static void setup_itable_offset_table(instanceKlassHandle klass);
// Resolving of method to index // Resolving of method to index
static int compute_itable_index(Method* m);
// ...and back again:
static Method* method_for_itable_index(Klass* klass, int itable_index); static Method* method_for_itable_index(Klass* klass, int itable_index);
// Debugging/Statistics // Debugging/Statistics

View file

@ -509,24 +509,31 @@ bool Method::compute_has_loops_flag() {
return _access_flags.has_loops(); return _access_flags.has_loops();
} }
bool Method::is_final_method(AccessFlags class_access_flags) const {
// or "does_not_require_vtable_entry"
// overpass can occur, is not final (reuses vtable entry)
// private methods get vtable entries for backward class compatibility.
if (is_overpass()) return false;
return is_final() || class_access_flags.is_final();
}
bool Method::is_final_method() const { bool Method::is_final_method() const {
// %%% Should return true for private methods also, return is_final_method(method_holder()->access_flags());
// since there is no way to override them.
return is_final() || method_holder()->is_final();
} }
bool Method::can_be_statically_bound(AccessFlags class_access_flags) const {
bool Method::is_strict_method() const { if (is_final_method(class_access_flags)) return true;
return is_strict(); #ifdef ASSERT
} bool is_nonv = (vtable_index() == nonvirtual_vtable_index);
if (class_access_flags.is_interface()) assert(is_nonv == is_static(), err_msg("is_nonv=%s", is_nonv));
#endif
bool Method::can_be_statically_bound() const { assert(valid_vtable_index() || valid_itable_index(), "method must be linked before we ask this question");
if (is_final_method()) return true;
return vtable_index() == nonvirtual_vtable_index; return vtable_index() == nonvirtual_vtable_index;
} }
bool Method::can_be_statically_bound() const {
return can_be_statically_bound(method_holder()->access_flags());
}
bool Method::is_accessor() const { bool Method::is_accessor() const {
if (code_size() != 5) return false; if (code_size() != 5) return false;
@ -967,7 +974,7 @@ bool Method::is_overridden_in(Klass* k) const {
assert(ik->is_subclass_of(method_holder()), "should be subklass"); assert(ik->is_subclass_of(method_holder()), "should be subklass");
assert(ik->vtable() != NULL, "vtable should exist"); assert(ik->vtable() != NULL, "vtable should exist");
if (vtable_index() == nonvirtual_vtable_index) { if (!has_vtable_index()) {
return false; return false;
} else { } else {
Method* vt_m = ik->method_at_vtable(vtable_index()); Method* vt_m = ik->method_at_vtable(vtable_index());
@ -1959,7 +1966,7 @@ void Method::print_on(outputStream* st) const {
void Method::print_value_on(outputStream* st) const { void Method::print_value_on(outputStream* st) const {
assert(is_method(), "must be method"); assert(is_method(), "must be method");
st->print_cr(internal_name()); st->print(internal_name());
print_address_on(st); print_address_on(st);
st->print(" "); st->print(" ");
name()->print_value_on(st); name()->print_value_on(st);
@ -1967,6 +1974,7 @@ void Method::print_value_on(outputStream* st) const {
signature()->print_value_on(st); signature()->print_value_on(st);
st->print(" in "); st->print(" in ");
method_holder()->print_value_on(st); method_holder()->print_value_on(st);
if (WizardMode) st->print("#%d", _vtable_index);
if (WizardMode) st->print("[%d,%d]", size_of_parameters(), max_locals()); if (WizardMode) st->print("[%d,%d]", size_of_parameters(), max_locals());
if (WizardMode && code() != NULL) st->print(" ((nmethod*)%p)", code()); if (WizardMode && code() != NULL) st->print(" ((nmethod*)%p)", code());
} }

View file

@ -448,16 +448,22 @@ class Method : public Metadata {
enum VtableIndexFlag { enum VtableIndexFlag {
// Valid vtable indexes are non-negative (>= 0). // Valid vtable indexes are non-negative (>= 0).
// These few negative values are used as sentinels. // These few negative values are used as sentinels.
highest_unused_vtable_index_value = -5, itable_index_max = -10, // first itable index, growing downward
pending_itable_index = -9, // itable index will be assigned
invalid_vtable_index = -4, // distinct from any valid vtable index invalid_vtable_index = -4, // distinct from any valid vtable index
garbage_vtable_index = -3, // not yet linked; no vtable layout yet garbage_vtable_index = -3, // not yet linked; no vtable layout yet
nonvirtual_vtable_index = -2 // there is no need for vtable dispatch nonvirtual_vtable_index = -2 // there is no need for vtable dispatch
// 6330203 Note: Do not use -1, which was overloaded with many meanings. // 6330203 Note: Do not use -1, which was overloaded with many meanings.
}; };
DEBUG_ONLY(bool valid_vtable_index() const { return _vtable_index >= nonvirtual_vtable_index; }) DEBUG_ONLY(bool valid_vtable_index() const { return _vtable_index >= nonvirtual_vtable_index; })
int vtable_index() const { assert(valid_vtable_index(), ""); bool has_vtable_index() const { return _vtable_index >= 0; }
return _vtable_index; } int vtable_index() const { return _vtable_index; }
void set_vtable_index(int index) { _vtable_index = index; } void set_vtable_index(int index) { _vtable_index = index; }
DEBUG_ONLY(bool valid_itable_index() const { return _vtable_index <= pending_itable_index; })
bool has_itable_index() const { return _vtable_index <= itable_index_max; }
int itable_index() const { assert(valid_itable_index(), "");
return itable_index_max - _vtable_index; }
void set_itable_index(int index) { _vtable_index = itable_index_max - index; assert(valid_itable_index(), ""); }
// interpreter entry // interpreter entry
address interpreter_entry() const { return _i2i_entry; } address interpreter_entry() const { return _i2i_entry; }
@ -560,10 +566,11 @@ class Method : public Metadata {
// checks method and its method holder // checks method and its method holder
bool is_final_method() const; bool is_final_method() const;
bool is_strict_method() const; bool is_final_method(AccessFlags class_access_flags) const;
// true if method needs no dynamic dispatch (final and/or no vtable entry) // true if method needs no dynamic dispatch (final and/or no vtable entry)
bool can_be_statically_bound() const; bool can_be_statically_bound() const;
bool can_be_statically_bound(AccessFlags class_access_flags) const;
// returns true if the method has any backward branches. // returns true if the method has any backward branches.
bool has_loops() { bool has_loops() {
@ -740,10 +747,6 @@ class Method : public Metadata {
// so handles are not used to avoid deadlock. // so handles are not used to avoid deadlock.
jmethodID find_jmethod_id_or_null() { return method_holder()->jmethod_id_or_null(this); } jmethodID find_jmethod_id_or_null() { return method_holder()->jmethod_id_or_null(this); }
// JNI static invoke cached itable index accessors
int cached_itable_index() { return method_holder()->cached_itable_index(method_idnum()); }
void set_cached_itable_index(int index) { method_holder()->set_cached_itable_index(method_idnum(), index); }
// Support for inlining of intrinsic methods // Support for inlining of intrinsic methods
vmIntrinsics::ID intrinsic_id() const { return (vmIntrinsics::ID) _intrinsic_id; } vmIntrinsics::ID intrinsic_id() const { return (vmIntrinsics::ID) _intrinsic_id; }
void set_intrinsic_id(vmIntrinsics::ID id) { _intrinsic_id = (u1) id; } void set_intrinsic_id(vmIntrinsics::ID id) { _intrinsic_id = (u1) id; }

View file

@ -45,7 +45,7 @@
// in the SymbolTable bucket (the _literal field in HashtableEntry) // in the SymbolTable bucket (the _literal field in HashtableEntry)
// that points to the Symbol. All other stores of a Symbol* // that points to the Symbol. All other stores of a Symbol*
// to a field of a persistent variable (e.g., the _name filed in // to a field of a persistent variable (e.g., the _name filed in
// FieldAccessInfo or _ptr in a CPSlot) is reference counted. // fieldDescriptor or _ptr in a CPSlot) is reference counted.
// //
// 1) The lookup of a "name" in the SymbolTable either creates a Symbol F for // 1) The lookup of a "name" in the SymbolTable either creates a Symbol F for
// "name" and returns a pointer to F or finds a pre-existing Symbol F for // "name" and returns a pointer to F or finds a pre-existing Symbol F for

View file

@ -3734,6 +3734,8 @@ Node* LibraryCallKit::generate_virtual_guard(Node* obj_klass,
RegionNode* slow_region) { RegionNode* slow_region) {
ciMethod* method = callee(); ciMethod* method = callee();
int vtable_index = method->vtable_index(); int vtable_index = method->vtable_index();
assert(vtable_index >= 0 || vtable_index == Method::nonvirtual_vtable_index,
err_msg_res("bad index %d", vtable_index));
// Get the Method* out of the appropriate vtable entry. // Get the Method* out of the appropriate vtable entry.
int entry_offset = (InstanceKlass::vtable_start_offset() + int entry_offset = (InstanceKlass::vtable_start_offset() +
vtable_index*vtableEntry::size()) * wordSize + vtable_index*vtableEntry::size()) * wordSize +
@ -3784,6 +3786,8 @@ LibraryCallKit::generate_method_call(vmIntrinsics::ID method_id, bool is_virtual
// so the vtable index is fixed. // so the vtable index is fixed.
// No need to use the linkResolver to get it. // No need to use the linkResolver to get it.
vtable_index = method->vtable_index(); vtable_index = method->vtable_index();
assert(vtable_index >= 0 || vtable_index == Method::nonvirtual_vtable_index,
err_msg_res("bad index %d", vtable_index));
} }
slow_call = new(C) CallDynamicJavaNode(tf, slow_call = new(C) CallDynamicJavaNode(tf,
SharedRuntime::get_resolve_virtual_call_stub(), SharedRuntime::get_resolve_virtual_call_stub(),

View file

@ -1336,6 +1336,7 @@ static void jni_invoke_nonstatic(JNIEnv *env, JavaValue* result, jobject receive
if (call_type == JNI_VIRTUAL) { if (call_type == JNI_VIRTUAL) {
// jni_GetMethodID makes sure class is linked and initialized // jni_GetMethodID makes sure class is linked and initialized
// so m should have a valid vtable index. // so m should have a valid vtable index.
assert(!m->has_itable_index(), "");
int vtbl_index = m->vtable_index(); int vtbl_index = m->vtable_index();
if (vtbl_index != Method::nonvirtual_vtable_index) { if (vtbl_index != Method::nonvirtual_vtable_index) {
Klass* k = h_recv->klass(); Klass* k = h_recv->klass();
@ -1355,12 +1356,7 @@ static void jni_invoke_nonstatic(JNIEnv *env, JavaValue* result, jobject receive
// interface call // interface call
KlassHandle h_holder(THREAD, holder); KlassHandle h_holder(THREAD, holder);
int itbl_index = m->cached_itable_index(); int itbl_index = m->itable_index();
if (itbl_index == -1) {
itbl_index = klassItable::compute_itable_index(m);
m->set_cached_itable_index(itbl_index);
// the above may have grabbed a lock, 'm' and anything non-handlized can't be used again
}
Klass* k = h_recv->klass(); Klass* k = h_recv->klass();
selected_method = InstanceKlass::cast(k)->method_at_itable(h_holder(), itbl_index, CHECK); selected_method = InstanceKlass::cast(k)->method_at_itable(h_holder(), itbl_index, CHECK);
} }

View file

@ -1824,7 +1824,7 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass,
} }
if (!publicOnly || fs.access_flags().is_public()) { if (!publicOnly || fs.access_flags().is_public()) {
fd.initialize(k(), fs.index()); fd.reinitialize(k(), fs.index());
oop field = Reflection::new_field(&fd, UseNewReflection, CHECK_NULL); oop field = Reflection::new_field(&fd, UseNewReflection, CHECK_NULL);
result->obj_at_put(out_idx, field); result->obj_at_put(out_idx, field);
++out_idx; ++out_idx;

View file

@ -2930,7 +2930,7 @@ void VM_RedefineClasses::check_methods_and_mark_as_obsolete(
for (int i = 0; i < _deleted_methods_length; ++i) { for (int i = 0; i < _deleted_methods_length; ++i) {
Method* old_method = _deleted_methods[i]; Method* old_method = _deleted_methods[i];
assert(old_method->vtable_index() < 0, assert(!old_method->has_vtable_index(),
"cannot delete methods with vtable entries");; "cannot delete methods with vtable entries");;
// Mark all deleted methods as old and obsolete // Mark all deleted methods as old and obsolete

View file

@ -127,25 +127,37 @@ Handle MethodHandles::new_MemberName(TRAPS) {
} }
oop MethodHandles::init_MemberName(Handle mname, Handle target) { oop MethodHandles::init_MemberName(Handle mname, Handle target) {
// This method is used from java.lang.invoke.MemberName constructors.
// It fills in the new MemberName from a java.lang.reflect.Member.
Thread* thread = Thread::current(); Thread* thread = Thread::current();
oop target_oop = target(); oop target_oop = target();
Klass* target_klass = target_oop->klass(); Klass* target_klass = target_oop->klass();
if (target_klass == SystemDictionary::reflect_Field_klass()) { if (target_klass == SystemDictionary::reflect_Field_klass()) {
oop clazz = java_lang_reflect_Field::clazz(target_oop); // fd.field_holder() oop clazz = java_lang_reflect_Field::clazz(target_oop); // fd.field_holder()
int slot = java_lang_reflect_Field::slot(target_oop); // fd.index() int slot = java_lang_reflect_Field::slot(target_oop); // fd.index()
int mods = java_lang_reflect_Field::modifiers(target_oop);
oop type = java_lang_reflect_Field::type(target_oop);
oop name = java_lang_reflect_Field::name(target_oop);
KlassHandle k(thread, java_lang_Class::as_Klass(clazz)); KlassHandle k(thread, java_lang_Class::as_Klass(clazz));
intptr_t offset = InstanceKlass::cast(k())->field_offset(slot); if (!k.is_null() && k->oop_is_instance()) {
return init_field_MemberName(mname, k, accessFlags_from(mods), type, name, offset); fieldDescriptor fd(InstanceKlass::cast(k()), slot);
oop mname2 = init_field_MemberName(mname, fd);
if (mname2 != NULL) {
// Since we have the reified name and type handy, add them to the result.
if (java_lang_invoke_MemberName::name(mname2) == NULL)
java_lang_invoke_MemberName::set_name(mname2, java_lang_reflect_Field::name(target_oop));
if (java_lang_invoke_MemberName::type(mname2) == NULL)
java_lang_invoke_MemberName::set_type(mname2, java_lang_reflect_Field::type(target_oop));
}
return mname2;
}
} else if (target_klass == SystemDictionary::reflect_Method_klass()) { } else if (target_klass == SystemDictionary::reflect_Method_klass()) {
oop clazz = java_lang_reflect_Method::clazz(target_oop); oop clazz = java_lang_reflect_Method::clazz(target_oop);
int slot = java_lang_reflect_Method::slot(target_oop); int slot = java_lang_reflect_Method::slot(target_oop);
KlassHandle k(thread, java_lang_Class::as_Klass(clazz)); KlassHandle k(thread, java_lang_Class::as_Klass(clazz));
if (!k.is_null() && k->oop_is_instance()) { if (!k.is_null() && k->oop_is_instance()) {
Method* m = InstanceKlass::cast(k())->method_with_idnum(slot); Method* m = InstanceKlass::cast(k())->method_with_idnum(slot);
return init_method_MemberName(mname, m, true, k); if (m == NULL || is_signature_polymorphic(m->intrinsic_id()))
return NULL; // do not resolve unless there is a concrete signature
CallInfo info(m, k());
return init_method_MemberName(mname, info);
} }
} else if (target_klass == SystemDictionary::reflect_Constructor_klass()) { } else if (target_klass == SystemDictionary::reflect_Constructor_klass()) {
oop clazz = java_lang_reflect_Constructor::clazz(target_oop); oop clazz = java_lang_reflect_Constructor::clazz(target_oop);
@ -153,65 +165,50 @@ oop MethodHandles::init_MemberName(Handle mname, Handle target) {
KlassHandle k(thread, java_lang_Class::as_Klass(clazz)); KlassHandle k(thread, java_lang_Class::as_Klass(clazz));
if (!k.is_null() && k->oop_is_instance()) { if (!k.is_null() && k->oop_is_instance()) {
Method* m = InstanceKlass::cast(k())->method_with_idnum(slot); Method* m = InstanceKlass::cast(k())->method_with_idnum(slot);
return init_method_MemberName(mname, m, false, k); if (m == NULL) return NULL;
} CallInfo info(m, k());
} else if (target_klass == SystemDictionary::MemberName_klass()) { return init_method_MemberName(mname, info);
// Note: This only works if the MemberName has already been resolved.
oop clazz = java_lang_invoke_MemberName::clazz(target_oop);
int flags = java_lang_invoke_MemberName::flags(target_oop);
Metadata* vmtarget=java_lang_invoke_MemberName::vmtarget(target_oop);
intptr_t vmindex = java_lang_invoke_MemberName::vmindex(target_oop);
KlassHandle k(thread, java_lang_Class::as_Klass(clazz));
int ref_kind = (flags >> REFERENCE_KIND_SHIFT) & REFERENCE_KIND_MASK;
if (vmtarget == NULL) return NULL; // not resolved
if ((flags & IS_FIELD) != 0) {
assert(vmtarget->is_klass(), "field vmtarget is Klass*");
int basic_mods = (ref_kind_is_static(ref_kind) ? JVM_ACC_STATIC : 0);
// FIXME: how does k (receiver_limit) contribute?
KlassHandle k_vmtarget(thread, (Klass*)vmtarget);
return init_field_MemberName(mname, k_vmtarget, accessFlags_from(basic_mods), NULL, NULL, vmindex);
} else if ((flags & (IS_METHOD | IS_CONSTRUCTOR)) != 0) {
assert(vmtarget->is_method(), "method or constructor vmtarget is Method*");
return init_method_MemberName(mname, (Method*)vmtarget, ref_kind_does_dispatch(ref_kind), k);
} else {
return NULL;
} }
} }
return NULL; return NULL;
} }
oop MethodHandles::init_method_MemberName(Handle mname, Method* m, bool do_dispatch, oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info) {
KlassHandle receiver_limit_h) { assert(info.resolved_appendix().is_null(), "only normal methods here");
Klass* receiver_limit = receiver_limit_h(); KlassHandle receiver_limit = info.resolved_klass();
AccessFlags mods = m->access_flags(); methodHandle m = info.resolved_method();
int flags = (jushort)( mods.as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS ); int flags = (jushort)( m->access_flags().as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS );
int vmindex = Method::nonvirtual_vtable_index; // implies never any dispatch int vmindex = Method::invalid_vtable_index;
Klass* mklass = m->method_holder();
if (receiver_limit == NULL) switch (info.call_kind()) {
receiver_limit = mklass; case CallInfo::itable_call:
if (m->is_initializer()) { vmindex = info.itable_index();
flags |= IS_CONSTRUCTOR | (JVM_REF_invokeSpecial << REFERENCE_KIND_SHIFT); // More importantly, the itable index only works with the method holder.
} else if (mods.is_static()) { receiver_limit = m->method_holder();
flags |= IS_METHOD | (JVM_REF_invokeStatic << REFERENCE_KIND_SHIFT); assert(receiver_limit->verify_itable_index(vmindex), "");
} else if (receiver_limit != mklass &&
!receiver_limit->is_subtype_of(mklass)) {
return NULL; // bad receiver limit
} else if (do_dispatch && receiver_limit->is_interface() &&
mklass->is_interface()) {
flags |= IS_METHOD | (JVM_REF_invokeInterface << REFERENCE_KIND_SHIFT); flags |= IS_METHOD | (JVM_REF_invokeInterface << REFERENCE_KIND_SHIFT);
receiver_limit = mklass; // ignore passed-in limit; interfaces are interconvertible break;
vmindex = klassItable::compute_itable_index(m);
} else if (do_dispatch && mklass != receiver_limit && mklass->is_interface()) { case CallInfo::vtable_call:
vmindex = info.vtable_index();
flags |= IS_METHOD | (JVM_REF_invokeVirtual << REFERENCE_KIND_SHIFT); flags |= IS_METHOD | (JVM_REF_invokeVirtual << REFERENCE_KIND_SHIFT);
// it is a miranda method, so m->vtable_index is not what we want assert(receiver_limit->is_subtype_of(m->method_holder()), "virtual call must be type-safe");
ResourceMark rm; break;
klassVtable* vt = InstanceKlass::cast(receiver_limit)->vtable();
vmindex = vt->index_of_miranda(m->name(), m->signature()); case CallInfo::direct_call:
} else if (!do_dispatch || m->can_be_statically_bound()) { vmindex = Method::nonvirtual_vtable_index;
flags |= IS_METHOD | (JVM_REF_invokeSpecial << REFERENCE_KIND_SHIFT); if (m->is_static()) {
} else { flags |= IS_METHOD | (JVM_REF_invokeStatic << REFERENCE_KIND_SHIFT);
flags |= IS_METHOD | (JVM_REF_invokeVirtual << REFERENCE_KIND_SHIFT); } else if (m->is_initializer()) {
vmindex = m->vtable_index(); flags |= IS_CONSTRUCTOR | (JVM_REF_invokeSpecial << REFERENCE_KIND_SHIFT);
assert(receiver_limit == m->method_holder(), "constructor call must be exactly typed");
} else {
flags |= IS_METHOD | (JVM_REF_invokeSpecial << REFERENCE_KIND_SHIFT);
assert(receiver_limit->is_subtype_of(m->method_holder()), "special call must be type-safe");
}
break;
default: assert(false, "bad CallInfo"); return NULL;
} }
// @CallerSensitive annotation detected // @CallerSensitive annotation detected
@ -221,7 +218,7 @@ oop MethodHandles::init_method_MemberName(Handle mname, Method* m, bool do_dispa
oop mname_oop = mname(); oop mname_oop = mname();
java_lang_invoke_MemberName::set_flags( mname_oop, flags); java_lang_invoke_MemberName::set_flags( mname_oop, flags);
java_lang_invoke_MemberName::set_vmtarget(mname_oop, m); java_lang_invoke_MemberName::set_vmtarget(mname_oop, m());
java_lang_invoke_MemberName::set_vmindex( mname_oop, vmindex); // vtable/itable index java_lang_invoke_MemberName::set_vmindex( mname_oop, vmindex); // vtable/itable index
java_lang_invoke_MemberName::set_clazz( mname_oop, receiver_limit->java_mirror()); java_lang_invoke_MemberName::set_clazz( mname_oop, receiver_limit->java_mirror());
// Note: name and type can be lazily computed by resolve_MemberName, // Note: name and type can be lazily computed by resolve_MemberName,
@ -237,59 +234,19 @@ oop MethodHandles::init_method_MemberName(Handle mname, Method* m, bool do_dispa
return mname(); return mname();
} }
Handle MethodHandles::init_method_MemberName(Handle mname, CallInfo& info, TRAPS) { oop MethodHandles::init_field_MemberName(Handle mname, fieldDescriptor& fd, bool is_setter) {
Handle empty; int flags = (jushort)( fd.access_flags().as_short() & JVM_RECOGNIZED_FIELD_MODIFIERS );
if (info.resolved_appendix().not_null()) { flags |= IS_FIELD | ((fd.is_static() ? JVM_REF_getStatic : JVM_REF_getField) << REFERENCE_KIND_SHIFT);
// The resolved MemberName must not be accompanied by an appendix argument,
// since there is no way to bind this value into the MemberName.
// Caller is responsible to prevent this from happening.
THROW_MSG_(vmSymbols::java_lang_InternalError(), "appendix", empty);
}
methodHandle m = info.resolved_method();
KlassHandle defc = info.resolved_klass();
int vmindex = Method::invalid_vtable_index;
if (defc->is_interface() && m->method_holder()->is_interface()) {
// static interface methods do not reference vtable or itable
if (m->is_static()) {
vmindex = Method::nonvirtual_vtable_index;
}
// interface methods invoked via invokespecial also
// do not reference vtable or itable.
int ref_kind = ((java_lang_invoke_MemberName::flags(mname()) >>
REFERENCE_KIND_SHIFT) & REFERENCE_KIND_MASK);
if (ref_kind == JVM_REF_invokeSpecial) {
vmindex = Method::nonvirtual_vtable_index;
}
// If neither m is static nor ref_kind is invokespecial,
// set it to itable index.
if (vmindex == Method::invalid_vtable_index) {
// LinkResolver does not report itable indexes! (fix this?)
vmindex = klassItable::compute_itable_index(m());
}
} else if (m->can_be_statically_bound()) {
// LinkResolver reports vtable index even for final methods!
vmindex = Method::nonvirtual_vtable_index;
} else {
vmindex = info.vtable_index();
}
oop res = init_method_MemberName(mname, m(), (vmindex >= 0), defc());
assert(res == NULL || (java_lang_invoke_MemberName::vmindex(res) == vmindex), "");
return Handle(THREAD, res);
}
oop MethodHandles::init_field_MemberName(Handle mname, KlassHandle field_holder,
AccessFlags mods, oop type, oop name,
intptr_t offset, bool is_setter) {
int flags = (jushort)( mods.as_short() & JVM_RECOGNIZED_FIELD_MODIFIERS );
flags |= IS_FIELD | ((mods.is_static() ? JVM_REF_getStatic : JVM_REF_getField) << REFERENCE_KIND_SHIFT);
if (is_setter) flags += ((JVM_REF_putField - JVM_REF_getField) << REFERENCE_KIND_SHIFT); if (is_setter) flags += ((JVM_REF_putField - JVM_REF_getField) << REFERENCE_KIND_SHIFT);
Metadata* vmtarget = field_holder(); Metadata* vmtarget = fd.field_holder();
int vmindex = offset; // determines the field uniquely when combined with static bit int vmindex = fd.offset(); // determines the field uniquely when combined with static bit
oop mname_oop = mname(); oop mname_oop = mname();
java_lang_invoke_MemberName::set_flags(mname_oop, flags); java_lang_invoke_MemberName::set_flags(mname_oop, flags);
java_lang_invoke_MemberName::set_vmtarget(mname_oop, vmtarget); java_lang_invoke_MemberName::set_vmtarget(mname_oop, vmtarget);
java_lang_invoke_MemberName::set_vmindex(mname_oop, vmindex); java_lang_invoke_MemberName::set_vmindex(mname_oop, vmindex);
java_lang_invoke_MemberName::set_clazz(mname_oop, field_holder->java_mirror()); java_lang_invoke_MemberName::set_clazz(mname_oop, fd.field_holder()->java_mirror());
oop type = field_signature_type_or_null(fd.signature());
oop name = field_name_or_null(fd.name());
if (name != NULL) if (name != NULL)
java_lang_invoke_MemberName::set_name(mname_oop, name); java_lang_invoke_MemberName::set_name(mname_oop, name);
if (type != NULL) if (type != NULL)
@ -305,19 +262,6 @@ oop MethodHandles::init_field_MemberName(Handle mname, KlassHandle field_holder,
return mname(); return mname();
} }
Handle MethodHandles::init_field_MemberName(Handle mname, FieldAccessInfo& info, TRAPS) {
return Handle();
#if 0 // FIXME
KlassHandle field_holder = info.klass();
intptr_t field_offset = info.field_offset();
return init_field_MemberName(mname_oop, field_holder(),
info.access_flags(),
type, name,
field_offset, false /*is_setter*/);
#endif
}
// JVM 2.9 Special Methods: // JVM 2.9 Special Methods:
// A method is signature polymorphic if and only if all of the following conditions hold : // A method is signature polymorphic if and only if all of the following conditions hold :
// * It is declared in the java.lang.invoke.MethodHandle class. // * It is declared in the java.lang.invoke.MethodHandle class.
@ -573,12 +517,12 @@ static oop object_java_mirror() {
return SystemDictionary::Object_klass()->java_mirror(); return SystemDictionary::Object_klass()->java_mirror();
} }
static oop field_name_or_null(Symbol* s) { oop MethodHandles::field_name_or_null(Symbol* s) {
if (s == NULL) return NULL; if (s == NULL) return NULL;
return StringTable::lookup(s); return StringTable::lookup(s);
} }
static oop field_signature_type_or_null(Symbol* s) { oop MethodHandles::field_signature_type_or_null(Symbol* s) {
if (s == NULL) return NULL; if (s == NULL) return NULL;
BasicType bt = FieldType::basic_type(s); BasicType bt = FieldType::basic_type(s);
if (is_java_primitive(bt)) { if (is_java_primitive(bt)) {
@ -701,7 +645,14 @@ Handle MethodHandles::resolve_MemberName(Handle mname, TRAPS) {
return empty; return empty;
} }
} }
return init_method_MemberName(mname, result, THREAD); if (result.resolved_appendix().not_null()) {
// The resolved MemberName must not be accompanied by an appendix argument,
// since there is no way to bind this value into the MemberName.
// Caller is responsible to prevent this from happening.
THROW_MSG_(vmSymbols::java_lang_InternalError(), "appendix", empty);
}
oop mname2 = init_method_MemberName(mname, result);
return Handle(THREAD, mname2);
} }
case IS_CONSTRUCTOR: case IS_CONSTRUCTOR:
{ {
@ -719,22 +670,21 @@ Handle MethodHandles::resolve_MemberName(Handle mname, TRAPS) {
} }
} }
assert(result.is_statically_bound(), ""); assert(result.is_statically_bound(), "");
return init_method_MemberName(mname, result, THREAD); oop mname2 = init_method_MemberName(mname, result);
return Handle(THREAD, mname2);
} }
case IS_FIELD: case IS_FIELD:
{ {
// This is taken from LinkResolver::resolve_field, sans access checks. fieldDescriptor result; // find_field initializes fd if found
fieldDescriptor fd; // find_field initializes fd if found {
KlassHandle sel_klass(THREAD, InstanceKlass::cast(defc())->find_field(name, type, &fd)); assert(!HAS_PENDING_EXCEPTION, "");
// check if field exists; i.e., if a klass containing the field def has been selected LinkResolver::resolve_field(result, defc, name, type, KlassHandle(), Bytecodes::_nop, false, false, THREAD);
if (sel_klass.is_null()) return empty; // should not happen if (HAS_PENDING_EXCEPTION) {
oop type = field_signature_type_or_null(fd.signature()); return empty;
oop name = field_name_or_null(fd.name()); }
bool is_setter = (ref_kind_is_valid(ref_kind) && ref_kind_is_setter(ref_kind)); }
mname = Handle(THREAD, oop mname2 = init_field_MemberName(mname, result, ref_kind_is_setter(ref_kind));
init_field_MemberName(mname, sel_klass, return Handle(THREAD, mname2);
fd.access_flags(), type, name, fd.offset(), is_setter));
return mname;
} }
default: default:
THROW_MSG_(vmSymbols::java_lang_InternalError(), "unrecognized MemberName format", empty); THROW_MSG_(vmSymbols::java_lang_InternalError(), "unrecognized MemberName format", empty);
@ -793,7 +743,6 @@ void MethodHandles::expand_MemberName(Handle mname, int suppress, TRAPS) {
} }
case IS_FIELD: case IS_FIELD:
{ {
// This is taken from LinkResolver::resolve_field, sans access checks.
assert(vmtarget->is_klass(), "field vmtarget is Klass*"); assert(vmtarget->is_klass(), "field vmtarget is Klass*");
if (!((Klass*) vmtarget)->oop_is_instance()) break; if (!((Klass*) vmtarget)->oop_is_instance()) break;
instanceKlassHandle defc(THREAD, (Klass*) vmtarget); instanceKlassHandle defc(THREAD, (Klass*) vmtarget);
@ -872,11 +821,7 @@ int MethodHandles::find_MemberNames(KlassHandle k,
Handle result(thread, results->obj_at(rfill++)); Handle result(thread, results->obj_at(rfill++));
if (!java_lang_invoke_MemberName::is_instance(result())) if (!java_lang_invoke_MemberName::is_instance(result()))
return -99; // caller bug! return -99; // caller bug!
oop type = field_signature_type_or_null(st.signature()); oop saved = MethodHandles::init_field_MemberName(result, st.field_descriptor());
oop name = field_name_or_null(st.name());
oop saved = MethodHandles::init_field_MemberName(result, st.klass(),
st.access_flags(), type, name,
st.offset());
if (saved != result()) if (saved != result())
results->obj_at_put(rfill-1, saved); // show saved instance to user results->obj_at_put(rfill-1, saved); // show saved instance to user
} else if (++overflow >= overflow_limit) { } else if (++overflow >= overflow_limit) {
@ -926,7 +871,8 @@ int MethodHandles::find_MemberNames(KlassHandle k,
Handle result(thread, results->obj_at(rfill++)); Handle result(thread, results->obj_at(rfill++));
if (!java_lang_invoke_MemberName::is_instance(result())) if (!java_lang_invoke_MemberName::is_instance(result()))
return -99; // caller bug! return -99; // caller bug!
oop saved = MethodHandles::init_method_MemberName(result, m, true, NULL); CallInfo info(m);
oop saved = MethodHandles::init_method_MemberName(result, info);
if (saved != result()) if (saved != result())
results->obj_at_put(rfill-1, saved); // show saved instance to user results->obj_at_put(rfill-1, saved); // show saved instance to user
} else if (++overflow >= overflow_limit) { } else if (++overflow >= overflow_limit) {
@ -1227,7 +1173,8 @@ JVM_ENTRY(jobject, MHN_getMemberVMInfo(JNIEnv *env, jobject igcls, jobject mname
x = ((Klass*) vmtarget)->java_mirror(); x = ((Klass*) vmtarget)->java_mirror();
} else if (vmtarget->is_method()) { } else if (vmtarget->is_method()) {
Handle mname2 = MethodHandles::new_MemberName(CHECK_NULL); Handle mname2 = MethodHandles::new_MemberName(CHECK_NULL);
x = MethodHandles::init_method_MemberName(mname2, (Method*)vmtarget, false, NULL); CallInfo info((Method*)vmtarget);
x = MethodHandles::init_method_MemberName(mname2, info);
} }
result->obj_at_put(1, x); result->obj_at_put(1, x);
return JNIHandles::make_local(env, result()); return JNIHandles::make_local(env, result());

View file

@ -49,19 +49,18 @@ class MethodHandles: AllStatic {
// Adapters. // Adapters.
static MethodHandlesAdapterBlob* _adapter_code; static MethodHandlesAdapterBlob* _adapter_code;
// utility functions for reifying names and types
static oop field_name_or_null(Symbol* s);
static oop field_signature_type_or_null(Symbol* s);
public: public:
// working with member names // working with member names
static Handle resolve_MemberName(Handle mname, TRAPS); // compute vmtarget/vmindex from name/type static Handle resolve_MemberName(Handle mname, TRAPS); // compute vmtarget/vmindex from name/type
static void expand_MemberName(Handle mname, int suppress, TRAPS); // expand defc/name/type if missing static void expand_MemberName(Handle mname, int suppress, TRAPS); // expand defc/name/type if missing
static Handle new_MemberName(TRAPS); // must be followed by init_MemberName static Handle new_MemberName(TRAPS); // must be followed by init_MemberName
static oop init_MemberName(Handle mname_h, Handle target_h); // compute vmtarget/vmindex from target static oop init_MemberName(Handle mname_h, Handle target_h); // compute vmtarget/vmindex from target
static oop init_method_MemberName(Handle mname_h, Method* m, bool do_dispatch, static oop init_field_MemberName(Handle mname_h, fieldDescriptor& fd, bool is_setter = false);
KlassHandle receiver_limit_h); static oop init_method_MemberName(Handle mname_h, CallInfo& info);
static oop init_field_MemberName(Handle mname_h, KlassHandle field_holder_h,
AccessFlags mods, oop type, oop name,
intptr_t offset, bool is_setter = false);
static Handle init_method_MemberName(Handle mname_h, CallInfo& info, TRAPS);
static Handle init_field_MemberName(Handle mname_h, FieldAccessInfo& info, TRAPS);
static int method_ref_kind(Method* m, bool do_dispatch_if_possible = true); static int method_ref_kind(Method* m, bool do_dispatch_if_possible = true);
static int find_MemberNames(KlassHandle k, Symbol* name, Symbol* sig, static int find_MemberNames(KlassHandle k, Symbol* name, Symbol* sig,
int mflags, KlassHandle caller, int mflags, KlassHandle caller,

View file

@ -97,18 +97,32 @@ oop fieldDescriptor::string_initial_value(TRAPS) const {
return constants()->uncached_string_at(initial_value_index(), CHECK_0); return constants()->uncached_string_at(initial_value_index(), CHECK_0);
} }
void fieldDescriptor::initialize(InstanceKlass* ik, int index) { void fieldDescriptor::reinitialize(InstanceKlass* ik, int index) {
_cp = ik->constants(); if (_cp.is_null() || field_holder() != ik) {
_cp = constantPoolHandle(Thread::current(), ik->constants());
// _cp should now reference ik's constant pool; i.e., ik is now field_holder.
assert(field_holder() == ik, "must be already initialized to this class");
}
FieldInfo* f = ik->field(index); FieldInfo* f = ik->field(index);
assert(!f->is_internal(), "regular Java fields only"); assert(!f->is_internal(), "regular Java fields only");
_access_flags = accessFlags_from(f->access_flags()); _access_flags = accessFlags_from(f->access_flags());
guarantee(f->name_index() != 0 && f->signature_index() != 0, "bad constant pool index for fieldDescriptor"); guarantee(f->name_index() != 0 && f->signature_index() != 0, "bad constant pool index for fieldDescriptor");
_index = index; _index = index;
verify();
} }
#ifndef PRODUCT #ifndef PRODUCT
void fieldDescriptor::verify() const {
if (_cp.is_null()) {
assert(_index == badInt, "constructor must be called"); // see constructor
} else {
assert(_index >= 0, "good index");
assert(_index < field_holder()->java_fields_count(), "oob");
}
}
void fieldDescriptor::print_on(outputStream* st) const { void fieldDescriptor::print_on(outputStream* st) const {
access_flags().print_on(st); access_flags().print_on(st);
name()->print_value_on(st); name()->print_value_on(st);

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -53,6 +53,13 @@ class fieldDescriptor VALUE_OBJ_CLASS_SPEC {
} }
public: public:
fieldDescriptor() {
DEBUG_ONLY(_index = badInt);
}
fieldDescriptor(InstanceKlass* ik, int index) {
DEBUG_ONLY(_index = badInt);
reinitialize(ik, index);
}
Symbol* name() const { Symbol* name() const {
return field()->name(_cp); return field()->name(_cp);
} }
@ -112,12 +119,13 @@ class fieldDescriptor VALUE_OBJ_CLASS_SPEC {
} }
// Initialization // Initialization
void initialize(InstanceKlass* ik, int index); void reinitialize(InstanceKlass* ik, int index);
// Print // Print
void print() { print_on(tty); } void print() { print_on(tty); }
void print_on(outputStream* st) const PRODUCT_RETURN; void print_on(outputStream* st) const PRODUCT_RETURN;
void print_on_for(outputStream* st, oop obj) PRODUCT_RETURN; void print_on_for(outputStream* st, oop obj) PRODUCT_RETURN;
void verify() const PRODUCT_RETURN;
}; };
#endif // SHARE_VM_RUNTIME_FIELDDESCRIPTOR_HPP #endif // SHARE_VM_RUNTIME_FIELDDESCRIPTOR_HPP

View file

@ -45,7 +45,6 @@ Mutex* InlineCacheBuffer_lock = NULL;
Mutex* VMStatistic_lock = NULL; Mutex* VMStatistic_lock = NULL;
Mutex* JNIGlobalHandle_lock = NULL; Mutex* JNIGlobalHandle_lock = NULL;
Mutex* JNIHandleBlockFreeList_lock = NULL; Mutex* JNIHandleBlockFreeList_lock = NULL;
Mutex* JNICachedItableIndex_lock = NULL;
Mutex* MemberNameTable_lock = NULL; Mutex* MemberNameTable_lock = NULL;
Mutex* JmethodIdCreation_lock = NULL; Mutex* JmethodIdCreation_lock = NULL;
Mutex* JfieldIdCreation_lock = NULL; Mutex* JfieldIdCreation_lock = NULL;
@ -253,7 +252,6 @@ void mutex_init() {
} }
def(Heap_lock , Monitor, nonleaf+1, false); def(Heap_lock , Monitor, nonleaf+1, false);
def(JfieldIdCreation_lock , Mutex , nonleaf+1, true ); // jfieldID, Used in VM_Operation def(JfieldIdCreation_lock , Mutex , nonleaf+1, true ); // jfieldID, Used in VM_Operation
def(JNICachedItableIndex_lock , Mutex , nonleaf+1, false); // Used to cache an itable index during JNI invoke
def(MemberNameTable_lock , Mutex , nonleaf+1, false); // Used to protect MemberNameTable def(MemberNameTable_lock , Mutex , nonleaf+1, false); // Used to protect MemberNameTable
def(CompiledIC_lock , Mutex , nonleaf+2, false); // locks VtableStubs_lock, InlineCacheBuffer_lock def(CompiledIC_lock , Mutex , nonleaf+2, false); // locks VtableStubs_lock, InlineCacheBuffer_lock

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -50,7 +50,6 @@ extern Mutex* InlineCacheBuffer_lock; // a lock used to guard the Inl
extern Mutex* VMStatistic_lock; // a lock used to guard statistics count increment extern Mutex* VMStatistic_lock; // a lock used to guard statistics count increment
extern Mutex* JNIGlobalHandle_lock; // a lock on creating JNI global handles extern Mutex* JNIGlobalHandle_lock; // a lock on creating JNI global handles
extern Mutex* JNIHandleBlockFreeList_lock; // a lock on the JNI handle block free list extern Mutex* JNIHandleBlockFreeList_lock; // a lock on the JNI handle block free list
extern Mutex* JNICachedItableIndex_lock; // a lock on caching an itable index during JNI invoke
extern Mutex* MemberNameTable_lock; // a lock on the MemberNameTable updates extern Mutex* MemberNameTable_lock; // a lock on the MemberNameTable updates
extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers
extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers

View file

@ -952,7 +952,8 @@ oop Reflection::invoke(instanceKlassHandle klass, methodHandle reflected_method,
} }
} else { } else {
// if the method can be overridden, we resolve using the vtable index. // if the method can be overridden, we resolve using the vtable index.
int index = reflected_method->vtable_index(); assert(!reflected_method->has_itable_index(), "");
int index = reflected_method->vtable_index();
method = reflected_method; method = reflected_method;
if (index != Method::nonvirtual_vtable_index) { if (index != Method::nonvirtual_vtable_index) {
// target_klass might be an arrayKlassOop but all vtables start at // target_klass might be an arrayKlassOop but all vtables start at

View file

@ -109,6 +109,8 @@ class FieldStream : public KlassStream {
private: private:
int length() const { return _klass->java_fields_count(); } int length() const { return _klass->java_fields_count(); }
fieldDescriptor _fd_buf;
public: public:
FieldStream(instanceKlassHandle klass, bool local_only, bool classes_only) FieldStream(instanceKlassHandle klass, bool local_only, bool classes_only)
: KlassStream(klass, local_only, classes_only) { : KlassStream(klass, local_only, classes_only) {
@ -134,6 +136,12 @@ class FieldStream : public KlassStream {
int offset() const { int offset() const {
return _klass->field_offset( index() ); return _klass->field_offset( index() );
} }
// bridge to a heavier API:
fieldDescriptor& field_descriptor() const {
fieldDescriptor& field = const_cast<fieldDescriptor&>(_fd_buf);
field.reinitialize(_klass(), _index);
return field;
}
}; };
class FilteredField : public CHeapObj<mtInternal> { class FilteredField : public CHeapObj<mtInternal> {

View file

@ -315,7 +315,6 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
nonstatic_field(InstanceKlass, _breakpoints, BreakpointInfo*) \ nonstatic_field(InstanceKlass, _breakpoints, BreakpointInfo*) \
nonstatic_field(InstanceKlass, _generic_signature_index, u2) \ nonstatic_field(InstanceKlass, _generic_signature_index, u2) \
nonstatic_field(InstanceKlass, _methods_jmethod_ids, jmethodID*) \ nonstatic_field(InstanceKlass, _methods_jmethod_ids, jmethodID*) \
nonstatic_field(InstanceKlass, _methods_cached_itable_indices, int*) \
volatile_nonstatic_field(InstanceKlass, _idnum_allocated_count, u2) \ volatile_nonstatic_field(InstanceKlass, _idnum_allocated_count, u2) \
nonstatic_field(InstanceKlass, _annotations, Annotations*) \ nonstatic_field(InstanceKlass, _annotations, Annotations*) \
nonstatic_field(InstanceKlass, _dependencies, nmethodBucket*) \ nonstatic_field(InstanceKlass, _dependencies, nmethodBucket*) \