/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "compiler/compileBroker.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "interpreter/bytecode.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "interpreter/linkResolver.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.inline.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/objArrayOop.hpp"
#include "prims/methodHandles.hpp"
#include "prims/nativeLookup.hpp"
#include "runtime/compilationPolicy.hpp"
#include "runtime/fieldDescriptor.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/reflection.hpp"
#include "runtime/signature.hpp"
#include "runtime/vmThread.hpp"
#ifdef TARGET_OS_FAMILY_linux
# include "thread_linux.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_solaris
# include "thread_solaris.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_windows
# include "thread_windows.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_bsd
# include "thread_bsd.inline.hpp"
#endif
//------------------------------------------------------------------------------------------------------------------------
// Implementation of FieldAccessInfo
}
//------------------------------------------------------------------------------------------------------------------------
// Implementation of CallInfo
}
void CallInfo::set_interface(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, TRAPS) {
// This is only called for interface methods. If 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.
}
}
void CallInfo::set_virtual(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS) {
assert(!resolved_method->is_compiled_lambda_form(), "these must be handled via an invokehandle call");
}
void CallInfo::set_handle(methodHandle resolved_method, Handle resolved_appendix, Handle resolved_method_type, TRAPS) {
if (resolved_method.is_null()) {
}
"linkMethod must return one of these");
}
void CallInfo::set_common(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS) {
_resolved_appendix = Handle();
// This path is unusual, mostly used by the '-Xcomp' stress test mode.
// Note: with several active threads, the must_be_compiled may be true
// while can_be_compiled is false; remove assert
// assert(CompilationPolicy::can_be_compiled(selected_method), "cannot compile");
if (THREAD->is_Compiler_thread()) {
// don't force compilation, resolve was on behalf of compiler
return;
}
// 'is_not_initialized' means not only '!is_initialized', but also that
// initialization has not been started yet ('!being_initialized')
// Do not force compilation of methods in uninitialized classes.
// Note that doing this would throw an assert later,
// in CompileBroker::compile_method.
// We sometimes use the link resolver to do reflective lookups
// even before classes are initialized.
return;
}
}
}
//------------------------------------------------------------------------------------------------------------------------
// Klass resolution
sel_klass->as_klassOop(),
true)) {
"tried to access class %s from class %s",
);
return;
}
}
}
void LinkResolver::resolve_klass_no_update(KlassHandle& result, constantPoolHandle pool, int index, TRAPS) {
}
//------------------------------------------------------------------------------------------------------------------------
// Method resolution
//
// According to JVM spec. $5.4.3c & $5.4.3d
void LinkResolver::lookup_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) {
// Do not link directly to these. The VM must produce a synthetic one using lookup_polymorphic_method.
return;
}
}
}
// returns first instance method
void LinkResolver::lookup_instance_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) {
}
}
int LinkResolver::vtable_index_of_miranda_method(KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) {
}
void LinkResolver::lookup_method_in_interfaces(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) {
}
TRAPS) {
if (TraceMethodHandles) {
}
if (EnableInvokeDynamic &&
// Most of these do not need an up-call to Java to resolve, so can be done anywhere.
// Do not erase last argument type (MemberName) if it is a static linkTo method.
if (TraceMethodHandles) {
name->as_C_string(),
}
CHECK);
if (TraceMethodHandles) {
}
return;
}
&& !THREAD->is_Compiler_thread()
&& appendix_result_or_null != NULL) {
// This is a method with type-checking semantics.
// We will ask Java code to spin an adapter method for it.
if (!MethodHandles::enabled()) {
// Make sure the Java part of the runtime has been booted up.
Handle(),
Handle(),
true,
CHECK);
}
}
&appendix,
CHECK);
if (TraceMethodHandles) {
}
#ifdef ASSERT
// +1 for MethodHandle.this, +1 for trailing MethodType
if (actual_size_of_params != expected_size_of_params) {
}
#endif //ASSERT
return;
}
}
}
}
TRAPS) {
// Special case: arrays always override "clone". JVMS 2.15.
// If the resolved klass is an array class, and the declaring class
// is java.lang.Object and the method is "clone", set the flags
// to public.
//
// We'll check for the method name first, as that's most likely
// to be false (so we'll short-circuit out of these tests).
resolved_klass->oop_is_array()) {
// We need to change "protected" to "public".
}
// assert(extra_arg_result_or_null != NULL, "must be able to return extra argument");
sel_klass->as_klassOop(),
true)) {
"tried to access method %s.%s%s from class %s",
);
return;
}
}
void LinkResolver::resolve_method_statically(methodHandle& resolved_method, KlassHandle& resolved_klass,
// resolve klass
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK);
return;
}
if (pool->has_preresolution()
if (result_oop != NULL) {
return;
}
}
resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK);
} else {
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK);
}
}
// 1. check if klass is not interface
if (resolved_klass->is_interface()) {
jio_snprintf(buf, sizeof(buf), "Found interface %s, but class was expected", Klass::cast(resolved_klass())->external_name());
}
// 2. lookup method in resolved klass and its super klasses
// 3. lookup method in all the interfaces implemented by the resolved klass
if (resolved_method.is_null()) {
// JSR 292: see if this is an implicitly generated method MethodHandle.linkToVirtual(*...), etc
if (HAS_PENDING_EXCEPTION) {
}
}
if (resolved_method.is_null()) {
// 4. method lookup failed
}
}
// 5. check if method is concrete
}
// 6. access checks, access checking may be turned off when calling from within the VM.
if (check_access) {
// check if method can be accessed by the referring class
CHECK);
// check loader constraints
Handle class_loader (THREAD, instanceKlass::cast(resolved_method->method_holder())->class_loader());
{
char* failed_type_name =
class_loader, true, CHECK);
if (failed_type_name != NULL) {
" \"%s\" the class loader (instance of %s) of the current class, %s,"
" and the class loader (instance of %s) for resolved class, %s, have"
" different Class objects for the type %s used in the signature";
char* sig = methodOopDesc::name_and_sig_as_C_string(Klass::cast(resolved_klass()),method_name,method_signature);
}
}
}
}
bool check_access, TRAPS) {
// check if klass is interface
if (!resolved_klass->is_interface()) {
jio_snprintf(buf, sizeof(buf), "Found class %s, but interface was expected", Klass::cast(resolved_klass())->external_name());
}
// lookup method in this interface or its super, java.lang.Object
lookup_instance_method_in_klasses(resolved_method, resolved_klass, method_name, method_signature, CHECK);
if (resolved_method.is_null()) {
// lookup method in all the super-interfaces
if (resolved_method.is_null()) {
// no method found
}
}
if (check_access) {
Handle class_loader (THREAD, instanceKlass::cast(resolved_method->method_holder())->class_loader());
{
char* failed_type_name =
class_loader, true, CHECK);
if (failed_type_name != NULL) {
"interface method \"%s\" the class loader (instance of %s) of the "
"current class, %s, and the class loader (instance of %s) for "
"resolved class, %s, have different Class objects for the type %s "
"used in the signature";
char* sig = methodOopDesc::name_and_sig_as_C_string(Klass::cast(resolved_klass()),method_name,method_signature);
}
}
}
}
//------------------------------------------------------------------------------------------------------------------------
// Field resolution
TRAPS) {
sel_klass->as_klassOop(),
fd.access_flags(),
true)) {
"tried to access field %s.%s from class %s",
);
return;
}
}
void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle pool, int index, Bytecodes::Code byte, bool check_only, TRAPS) {
}
void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle pool, int index, Bytecodes::Code byte, bool check_only, bool update_pool, TRAPS) {
// resolve specified klass
if (update_pool) {
} else {
}
// Load these early in case the resolve of the containing klass fails
// Check if there's a resolved klass containing the field
if( resolved_klass.is_null() ) {
}
// Resolve instance field
// check if field exists; i.e., if a klass containing the field def has been selected
}
// check access
// check for errors
jio_snprintf(msg, sizeof(msg), "Expected %s field %s.%s", is_static ? "static" : "non-static", Klass::cast(resolved_klass())->external_name(), fd.name()->as_C_string());
}
// Final fields can only be accessed from its own class.
}
// initialize resolved_klass if necessary
// note 1: the klass which declared the field must be initialized (i.e, sel_klass)
// according to the newest JVM spec (5.5, p.170) - was bug (gri 7/28/99)
//
// note 2: we don't want to force initialization if we are just checking
// if the field access is legal; e.g., during compilation
if (is_static && !check_only) {
}
{
{
char* failed_type_name =
false,
CHECK);
if (failed_type_name != NULL) {
" \"%s\" the class loader (instance of %s) of the referring class, "
"%s, and the class loader (instance of %s) for the field's resolved "
"type, %s, have different Class objects for that type";
}
}
}
// 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.
}
//------------------------------------------------------------------------------------------------------------------------
// Invoke resolution
//
// Naming conventions:
//
// resolved_method the specified method (i.e., static receiver specified via constant pool index)
// sel_method the selected method (selected via run-time lookup; e.g., based on dynamic receiver class)
// resolved_klass the specified klass (i.e., specified via constant pool index)
// recv_klass the receiver klass
void LinkResolver::resolve_static_call(CallInfo& result, KlassHandle& resolved_klass, Symbol* method_name,
linktime_resolve_static_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK);
// Initialize klass (this should only happen if everything is ok)
linktime_resolve_static_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK);
}
// setup result
}
// throws linktime exceptions
void LinkResolver::linktime_resolve_static_method(methodHandle& resolved_method, KlassHandle resolved_klass,
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK);
assert(resolved_method->name() != vmSymbols::class_initializer_name(), "should have been checked in verifier");
// check if static
if (!resolved_method->is_static()) {
jio_snprintf(buf, sizeof(buf), "Expected static method %s", methodOopDesc::name_and_sig_as_C_string(Klass::cast(resolved_klass()),
resolved_method->name(),
resolved_method->signature()));
}
}
void LinkResolver::resolve_special_call(CallInfo& result, KlassHandle resolved_klass, Symbol* method_name,
linktime_resolve_special_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK);
runtime_resolve_special_method(result, resolved_method, resolved_klass, current_klass, check_access, CHECK);
}
// throws linktime exceptions
void LinkResolver::linktime_resolve_special_method(methodHandle& resolved_method, KlassHandle resolved_klass,
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK);
// check if method name is <init>, that it is found in same klass as static type
"%s: method %s%s not found",
);
return;
}
// check if not static
if (resolved_method->is_static()) {
"Expecting non-static method %s",
resolved_method->name(),
resolved_method->signature()));
}
}
// throws runtime exceptions
void LinkResolver::runtime_resolve_special_method(CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass,
// resolved method is selected method unless we have an old-style lookup
// check if this is an old-style super call and do a new lookup if so
if (check_access &&
// a) check if ACC_SUPER flag is set for the current class
// b) check if the method class is a superclass of the current class (superclass relation is not reflexive!)
// c) check if the method is not <init>
// Lookup super method
resolved_method->name(),
// check if found
if (sel_method.is_null()) {
resolved_method->name(),
resolved_method->signature()));
}
}
}
// check if not static
if (sel_method->is_static()) {
jio_snprintf(buf, sizeof(buf), "Expecting non-static method %s", methodOopDesc::name_and_sig_as_C_string(Klass::cast(resolved_klass()),
resolved_method->name(),
resolved_method->signature()));
}
// check if abstract
if (sel_method->is_abstract()) {
sel_method->name(),
sel_method->signature()));
}
// setup result
}
void LinkResolver::resolve_virtual_call(CallInfo& result, Handle recv, KlassHandle receiver_klass, KlassHandle resolved_klass,
linktime_resolve_virtual_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK);
runtime_resolve_virtual_method(result, resolved_method, resolved_klass, recv, receiver_klass, check_null_and_abstract, CHECK);
}
// throws linktime exceptions
void LinkResolver::linktime_resolve_virtual_method(methodHandle &resolved_method, KlassHandle resolved_klass,
// normal method resolution
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK);
assert(resolved_method->name() != vmSymbols::object_initializer_name(), "should have been checked in verifier");
assert(resolved_method->name() != vmSymbols::class_initializer_name (), "should have been checked in verifier");
// check if not static
if (resolved_method->is_static()) {
jio_snprintf(buf, sizeof(buf), "Expecting non-static method %s", methodOopDesc::name_and_sig_as_C_string(Klass::cast(resolved_klass()),
resolved_method->name(),
resolved_method->signature()));
}
}
// throws runtime exceptions
bool check_null_and_abstract,
TRAPS) {
// setup default return values
// runtime method resolution
}
// Virtual methods cannot be resolved before its klass has been linked, for otherwise the methodOop's
// has not been rewritten, and the vtable initialized.
// Virtual methods cannot be resolved before its klass has been linked, for otherwise the methodOop's
// has not been rewritten, and the vtable initialized. Make sure to do this after the nullcheck, since
// a missing receiver might result in a bogus lookup.
// do lookup based on receiver klass using the vtable index
resolved_method->name(),
} else {
// at this point we are sure that resolved_method is virtual and not
// a miranda method; therefore, it must have a valid vtable index.
// We could get a negative vtable_index for final methods,
// because as an optimization they are they are never put in the vtable,
// unless they override an existing method.
// If we do get a negative, it means the resolved method is the the selected
// method, and it can never be changed by an override.
} else {
// recv_klass might be an arrayKlassOop but all vtables start at
// the same place. The cast is to avoid virtual call and assertion.
}
}
// check if method exists
if (selected_method.is_null()) {
resolved_method->name(),
resolved_method->signature()));
}
// check if abstract
selected_method->name(),
selected_method->signature()));
}
// setup result
result.set_virtual(resolved_klass, recv_klass, resolved_method, selected_method, vtable_index, CHECK);
}
void LinkResolver::resolve_interface_call(CallInfo& result, Handle recv, KlassHandle recv_klass, KlassHandle resolved_klass,
linktime_resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK);
runtime_resolve_interface_method(result, resolved_method, resolved_klass, recv, recv_klass, check_null_and_abstract, CHECK);
}
// throws linktime exceptions
void LinkResolver::linktime_resolve_interface_method(methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name,
// normal interface method resolution
resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK);
assert(resolved_method->name() != vmSymbols::object_initializer_name(), "should have been checked in verifier");
assert(resolved_method->name() != vmSymbols::class_initializer_name (), "should have been checked in verifier");
}
// throws runtime exceptions
void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHandle resolved_method, KlassHandle resolved_klass,
// check if receiver exists
}
// check if receiver klass implements the resolved interface
}
// do lookup based on receiver klass
resolved_method->name(),
// check if method exists
if (sel_method.is_null()) {
resolved_method->name(),
resolved_method->signature()));
}
// check if public
if (!sel_method->is_public()) {
sel_method->name(),
sel_method->signature()));
}
// check if abstract
sel_method->name(),
sel_method->signature()));
}
// setup result
}
bool check_access) {
linktime_resolve_interface_method(method_result, resolved_klass, method_name, method_signature, current_klass, check_access, THREAD);
if (HAS_PENDING_EXCEPTION) {
return methodHandle();
} else {
return method_result;
}
}
bool check_access) {
linktime_resolve_virtual_method(method_result, resolved_klass, method_name, method_signature, current_klass, check_access, THREAD);
if (HAS_PENDING_EXCEPTION) {
return methodHandle();
} else {
return method_result;
}
}
resolve_virtual_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, true, false, THREAD);
if (HAS_PENDING_EXCEPTION) {
return methodHandle();
}
return info.selected_method();
}
resolve_interface_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, true, false, THREAD);
if (HAS_PENDING_EXCEPTION) {
return methodHandle();
}
return info.selected_method();
}
resolve_virtual_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, true, false, THREAD);
if (HAS_PENDING_EXCEPTION) {
return methodOopDesc::invalid_vtable_index;
}
return info.vtable_index();
}
if (HAS_PENDING_EXCEPTION) {
return methodHandle();
}
return info.selected_method();
}
methodHandle LinkResolver::resolve_special_call_or_null(KlassHandle resolved_klass, Symbol* name, Symbol* signature,
if (HAS_PENDING_EXCEPTION) {
return methodHandle();
}
return info.selected_method();
}
//------------------------------------------------------------------------------------------------------------------------
// ConstantPool entries
void LinkResolver::resolve_invoke(CallInfo& result, Handle recv, constantPoolHandle pool, int index, Bytecodes::Code byte, TRAPS) {
switch (byte) {
}
return;
}
void LinkResolver::resolve_pool(KlassHandle& resolved_klass, Symbol*& method_name, Symbol*& method_signature,
// resolve klass
// Get name, signature, and static klass
}
void LinkResolver::resolve_invokestatic(CallInfo& result, constantPoolHandle pool, int index, TRAPS) {
resolve_static_call(result, resolved_klass, method_name, method_signature, current_klass, true, true, CHECK);
}
void LinkResolver::resolve_invokespecial(CallInfo& result, constantPoolHandle pool, int index, TRAPS) {
resolve_special_call(result, resolved_klass, method_name, method_signature, current_klass, true, CHECK);
}
TRAPS) {
resolve_virtual_call(result, recv, recvrKlass, resolved_klass, method_name, method_signature, current_klass, true, true, CHECK);
}
void LinkResolver::resolve_invokeinterface(CallInfo& result, Handle recv, constantPoolHandle pool, int index, TRAPS) {
resolve_interface_call(result, recv, recvrKlass, resolved_klass, method_name, method_signature, current_klass, true, true, CHECK);
}
void LinkResolver::resolve_invokehandle(CallInfo& result, constantPoolHandle pool, int index, TRAPS) {
// This guy is reached from InterpreterRuntime::resolve_invokehandle.
if (TraceMethodHandles) {
tty->print_cr("resolve_invokehandle %s %s", method_name->as_C_string(), method_signature->as_C_string());
}
}
TRAPS) {
// JSR 292: this must be an implicitly generated method MethodHandle.invokeExact(*...) or similar
}
void LinkResolver::resolve_invokedynamic(CallInfo& result, constantPoolHandle pool, int index, TRAPS) {
//resolve_pool(<resolved_klass>, method_name, method_signature, current_klass, pool, index, CHECK);
// Resolve the bootstrap specifier (BSM + optional arguments).
// Check if CallSite has been bound already:
if (cpce->is_f1_null()) {
// FIXME: Cache this once per BootstrapMethods entry, not once per CONSTANT_InvokeDynamic.
}
if (!cpce->is_f1_null()) {
return;
}
if (TraceMethodHandles) {
}
resolve_dynamic_call(result, bootstrap_specifier, method_name, method_signature, current_klass, CHECK);
}
TRAPS) {
// JSR 292: this must resolve to an implicitly generated method MH.linkToCallSite(*...)
// The appendix argument is likely to be a freshly-created CallSite.
THREAD);
if (HAS_PENDING_EXCEPTION) {
if (TraceMethodHandles) {
}
// throw these guys, since they are already wrapped
return;
}
// intercept only LinkageErrors which might have failed to wrap
return;
}
// See the "Linking Exceptions" section for the invokedynamic instruction in the JVMS.
}
}
//------------------------------------------------------------------------------------------------------------------------
#ifndef PRODUCT
}
#endif