< prev index next > src/hotspot/share/prims/methodHandles.cpp
Print this page
* questions.
*
*/
#include "precompiled.hpp"
+ #include "cds/cds_globals.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
+ #include "classfile/systemDictionaryShared.hpp"
#include "classfile/vmClasses.hpp"
#include "code/codeCache.hpp"
#include "code/dependencyContext.hpp"
#include "compiler/compileBroker.hpp"
#include "interpreter/interpreter.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
+ #include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/jniHandles.inline.hpp"
+ #include "runtime/perfData.inline.hpp"
#include "runtime/timerTrace.hpp"
#include "runtime/reflection.hpp"
#include "runtime/safepointVerifiers.hpp"
#include "runtime/signature.hpp"
#include "runtime/stubRoutines.hpp"
#include "sanitizers/leak.hpp"
+ #include "services/management.hpp"
#include "utilities/exceptions.hpp"
/*
* JSR 292 reference implementation: method handles
#undef VALUE_COMMA
#undef STRING_NULL
#undef EACH_NAMED_CON
#endif // PRODUCT
! JVM_ENTRY(jint, MHN_getNamedCon(JNIEnv *env, jobject igcls, jint which, jobjectArray box_jh)) {
#ifndef PRODUCT
if (advertise_con_value(which)) {
assert(which >= 0 && which < con_value_count, "");
int con = con_values[which];
objArrayHandle box(THREAD, (objArrayOop) JNIHandles::resolve(box_jh));
#undef VALUE_COMMA
#undef STRING_NULL
#undef EACH_NAMED_CON
#endif // PRODUCT
! JVM_ENTRY_PROF(jint, MHN_getNamedCon, MHN_getNamedCon(JNIEnv *env, jobject igcls, jint which, jobjectArray box_jh)) {
#ifndef PRODUCT
if (advertise_con_value(which)) {
assert(which >= 0 && which < con_value_count, "");
int con = con_values[which];
objArrayHandle box(THREAD, (objArrayOop) JNIHandles::resolve(box_jh));
return 0;
}
JVM_END
// void init(MemberName self, AccessibleObject ref)
! JVM_ENTRY(void, MHN_init_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jobject target_jh)) {
if (mname_jh == nullptr) { THROW_MSG(vmSymbols::java_lang_InternalError(), "mname is null"); }
if (target_jh == nullptr) { THROW_MSG(vmSymbols::java_lang_InternalError(), "target is null"); }
Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh));
Handle target(THREAD, JNIHandles::resolve_non_null(target_jh));
MethodHandles::init_MemberName(mname, target, CHECK);
}
JVM_END
// void expand(MemberName self)
! JVM_ENTRY(void, MHN_expand_Mem(JNIEnv *env, jobject igcls, jobject mname_jh)) {
if (mname_jh == nullptr) { THROW_MSG(vmSymbols::java_lang_InternalError(), "mname is null"); }
Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh));
MethodHandles::expand_MemberName(mname, 0, CHECK);
}
JVM_END
// void resolve(MemberName self, Class<?> caller)
! JVM_ENTRY(jobject, MHN_resolve_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jclass caller_jh,
jint lookup_mode, jboolean speculative_resolve)) {
if (mname_jh == nullptr) { THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "mname is null"); }
Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh));
// The trusted Java code that calls this method should already have performed
return 0;
}
JVM_END
// void init(MemberName self, AccessibleObject ref)
! JVM_ENTRY_PROF(void, MHN_init_Mem, MHN_init_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jobject target_jh)) {
if (mname_jh == nullptr) { THROW_MSG(vmSymbols::java_lang_InternalError(), "mname is null"); }
if (target_jh == nullptr) { THROW_MSG(vmSymbols::java_lang_InternalError(), "target is null"); }
Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh));
Handle target(THREAD, JNIHandles::resolve_non_null(target_jh));
MethodHandles::init_MemberName(mname, target, CHECK);
}
JVM_END
// void expand(MemberName self)
! JVM_ENTRY_PROF(void, MHN_expand_Mem, MHN_expand_Mem(JNIEnv *env, jobject igcls, jobject mname_jh)) {
if (mname_jh == nullptr) { THROW_MSG(vmSymbols::java_lang_InternalError(), "mname is null"); }
Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh));
MethodHandles::expand_MemberName(mname, 0, CHECK);
}
JVM_END
// void resolve(MemberName self, Class<?> caller)
! JVM_ENTRY_PROF(jobject, MHN_resolve_Mem, MHN_resolve_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jclass caller_jh,
jint lookup_mode, jboolean speculative_resolve)) {
if (mname_jh == nullptr) { THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "mname is null"); }
Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh));
// The trusted Java code that calls this method should already have performed
const char* msg = (must_be_static ? "static field required" : "non-static field required");
THROW_MSG_0(vmSymbols::java_lang_InternalError(), msg);
return 0;
}
! JVM_ENTRY(jlong, MHN_objectFieldOffset(JNIEnv *env, jobject igcls, jobject mname_jh)) {
return find_member_field_offset(JNIHandles::resolve(mname_jh), false, THREAD);
}
JVM_END
! JVM_ENTRY(jlong, MHN_staticFieldOffset(JNIEnv *env, jobject igcls, jobject mname_jh)) {
return find_member_field_offset(JNIHandles::resolve(mname_jh), true, THREAD);
}
JVM_END
! JVM_ENTRY(jobject, MHN_staticFieldBase(JNIEnv *env, jobject igcls, jobject mname_jh)) {
// use the other function to perform sanity checks:
jlong ignore = find_member_field_offset(JNIHandles::resolve(mname_jh), true, CHECK_NULL);
oop clazz = java_lang_invoke_MemberName::clazz(JNIHandles::resolve_non_null(mname_jh));
return JNIHandles::make_local(THREAD, clazz);
}
JVM_END
! JVM_ENTRY(jobject, MHN_getMemberVMInfo(JNIEnv *env, jobject igcls, jobject mname_jh)) {
if (mname_jh == nullptr) return nullptr;
Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh));
intptr_t vmindex = java_lang_invoke_MemberName::vmindex(mname());
objArrayHandle result = oopFactory::new_objArray_handle(vmClasses::Object_klass(), 2, CHECK_NULL);
jvalue vmindex_value; vmindex_value.j = (long)vmindex;
const char* msg = (must_be_static ? "static field required" : "non-static field required");
THROW_MSG_0(vmSymbols::java_lang_InternalError(), msg);
return 0;
}
! JVM_ENTRY_PROF(jlong, MHN_objectFieldOffset, MHN_objectFieldOffset(JNIEnv *env, jobject igcls, jobject mname_jh)) {
return find_member_field_offset(JNIHandles::resolve(mname_jh), false, THREAD);
}
JVM_END
! JVM_ENTRY_PROF(jlong, MHN_staticFieldOffset, MHN_staticFieldOffset(JNIEnv *env, jobject igcls, jobject mname_jh)) {
return find_member_field_offset(JNIHandles::resolve(mname_jh), true, THREAD);
}
JVM_END
! JVM_ENTRY_PROF(jobject, MHN_staticFieldBase, MHN_staticFieldBase(JNIEnv *env, jobject igcls, jobject mname_jh)) {
// use the other function to perform sanity checks:
jlong ignore = find_member_field_offset(JNIHandles::resolve(mname_jh), true, CHECK_NULL);
oop clazz = java_lang_invoke_MemberName::clazz(JNIHandles::resolve_non_null(mname_jh));
return JNIHandles::make_local(THREAD, clazz);
}
JVM_END
! JVM_ENTRY_PROF(jobject, MHN_getMemberVMInfo, MHN_getMemberVMInfo(JNIEnv *env, jobject igcls, jobject mname_jh)) {
if (mname_jh == nullptr) return nullptr;
Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh));
intptr_t vmindex = java_lang_invoke_MemberName::vmindex(mname());
objArrayHandle result = oopFactory::new_objArray_handle(vmClasses::Object_klass(), 2, CHECK_NULL);
jvalue vmindex_value; vmindex_value.j = (long)vmindex;
result->obj_at_put(1, x);
return JNIHandles::make_local(THREAD, result());
}
JVM_END
! JVM_ENTRY(void, MHN_setCallSiteTargetNormal(JNIEnv* env, jobject igcls, jobject call_site_jh, jobject target_jh)) {
Handle call_site(THREAD, JNIHandles::resolve_non_null(call_site_jh));
Handle target (THREAD, JNIHandles::resolve_non_null(target_jh));
DeoptimizationScope deopt_scope;
{
// Walk all nmethods depending on this call site.
result->obj_at_put(1, x);
return JNIHandles::make_local(THREAD, result());
}
JVM_END
! JVM_ENTRY_PROF(void, MHN_setCallSiteTargetNormal, MHN_setCallSiteTargetNormal(JNIEnv* env, jobject igcls, jobject call_site_jh, jobject target_jh)) {
Handle call_site(THREAD, JNIHandles::resolve_non_null(call_site_jh));
Handle target (THREAD, JNIHandles::resolve_non_null(target_jh));
DeoptimizationScope deopt_scope;
{
// Walk all nmethods depending on this call site.
deopt_scope.deoptimize_marked();
}
}
JVM_END
! JVM_ENTRY(void, MHN_setCallSiteTargetVolatile(JNIEnv* env, jobject igcls, jobject call_site_jh, jobject target_jh)) {
Handle call_site(THREAD, JNIHandles::resolve_non_null(call_site_jh));
Handle target (THREAD, JNIHandles::resolve_non_null(target_jh));
DeoptimizationScope deopt_scope;
{
// Walk all nmethods depending on this call site.
deopt_scope.deoptimize_marked();
}
}
JVM_END
! // Make sure the class is linked. If the class cannot be verified, etc, an exception will be thrown.
+ JVM_ENTRY_PROF(void, MHN_checkArchivable, MHN_checkArchivable(JNIEnv *env, jobject igcls, jclass klass_jh)) {
+ if (klass_jh == nullptr) { THROW_MSG(vmSymbols::java_lang_InternalError(), "klass is null"); }
+
+ if (CDSConfig::is_dumping_invokedynamic()) {
+ Klass* klass = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(klass_jh));
+ if (klass != nullptr && klass->is_instance_klass()) {
+ // klass could be null during very early VM start-up
+ InstanceKlass* ik = InstanceKlass::cast(klass);
+ ik->link_class(THREAD); // exception will be thrown if unverifiable
+ if (!ik->is_linked()) {
+ assert(HAS_PENDING_EXCEPTION, "must be");
+ ResourceMark rm;
+ log_warning(cds)("Cannot use unverifiable class %s in MethodType",
+ klass->external_name());
+ return;
+ }
+
+ if (SystemDictionaryShared::is_jfr_event_class(ik)) {
+ ResourceMark rm;
+ log_warning(cds)("Cannot use JFR event class %s in MethodType",
+ klass->external_name());
+ Exceptions::fthrow(THREAD_AND_LOCATION,
+ vmSymbols::java_lang_NoClassDefFoundError(),
+ "Class %s, or one of its supertypes, is a JFR event class",
+ klass->external_name());
+ }
+ }
+ }
+ }
+ JVM_END
+
+ JVM_ENTRY_PROF(void, MHN_setCallSiteTargetVolatile, MHN_setCallSiteTargetVolatile(JNIEnv* env, jobject igcls, jobject call_site_jh, jobject target_jh)) {
Handle call_site(THREAD, JNIHandles::resolve_non_null(call_site_jh));
Handle target (THREAD, JNIHandles::resolve_non_null(target_jh));
DeoptimizationScope deopt_scope;
{
// Walk all nmethods depending on this call site.
deopt_scope.deoptimize_marked();
}
}
JVM_END
! JVM_ENTRY(void, MHN_copyOutBootstrapArguments(JNIEnv* env, jobject igcls,
jobject caller_jh, jintArray index_info_jh,
jint start, jint end,
jobjectArray buf_jh, jint pos,
jboolean resolve, jobject ifna_jh)) {
Klass* caller_k = java_lang_Class::as_Klass(JNIHandles::resolve(caller_jh));
deopt_scope.deoptimize_marked();
}
}
JVM_END
! JVM_ENTRY_PROF(void, MHN_copyOutBootstrapArguments, MHN_copyOutBootstrapArguments(JNIEnv* env, jobject igcls,
jobject caller_jh, jintArray index_info_jh,
jint start, jint end,
jobjectArray buf_jh, jint pos,
jboolean resolve, jobject ifna_jh)) {
Klass* caller_k = java_lang_Class::as_Klass(JNIHandles::resolve(caller_jh));
}
JVM_END
// It is called by a Cleaner object which ensures that dropped CallSites properly
// deallocate their dependency information.
! JVM_ENTRY(void, MHN_clearCallSiteContext(JNIEnv* env, jobject igcls, jobject context_jh)) {
Handle context(THREAD, JNIHandles::resolve_non_null(context_jh));
DeoptimizationScope deopt_scope;
{
NoSafepointVerifier nsv;
MutexLocker ml(THREAD, CodeCache_lock, Mutex::_no_safepoint_check_flag);
}
JVM_END
// It is called by a Cleaner object which ensures that dropped CallSites properly
// deallocate their dependency information.
! JVM_ENTRY_PROF(void, MHN_clearCallSiteContext, MHN_clearCallSiteContext(JNIEnv* env, jobject igcls, jobject context_jh)) {
Handle context(THREAD, JNIHandles::resolve_non_null(context_jh));
DeoptimizationScope deopt_scope;
{
NoSafepointVerifier nsv;
MutexLocker ml(THREAD, CodeCache_lock, Mutex::_no_safepoint_check_flag);
/**
* Throws a java/lang/UnsupportedOperationException unconditionally.
* This is required by the specification of MethodHandle.invoke if
* invoked directly.
*/
! JVM_ENTRY(jobject, MH_invoke_UOE(JNIEnv* env, jobject mh, jobjectArray args)) {
THROW_MSG_NULL(vmSymbols::java_lang_UnsupportedOperationException(), "MethodHandle.invoke cannot be invoked reflectively");
return nullptr;
}
JVM_END
/**
* Throws a java/lang/UnsupportedOperationException unconditionally.
* This is required by the specification of MethodHandle.invokeExact if
* invoked directly.
*/
! JVM_ENTRY(jobject, MH_invokeExact_UOE(JNIEnv* env, jobject mh, jobjectArray args)) {
THROW_MSG_NULL(vmSymbols::java_lang_UnsupportedOperationException(), "MethodHandle.invokeExact cannot be invoked reflectively");
return nullptr;
}
JVM_END
/**
* Throws a java/lang/UnsupportedOperationException unconditionally.
* This is required by the specification of MethodHandle.invoke if
* invoked directly.
*/
! JVM_ENTRY_PROF(jobject, MH_invoke_UOE, MH_invoke_UOE(JNIEnv* env, jobject mh, jobjectArray args)) {
THROW_MSG_NULL(vmSymbols::java_lang_UnsupportedOperationException(), "MethodHandle.invoke cannot be invoked reflectively");
return nullptr;
}
JVM_END
/**
* Throws a java/lang/UnsupportedOperationException unconditionally.
* This is required by the specification of MethodHandle.invokeExact if
* invoked directly.
*/
! JVM_ENTRY_PROF(jobject, MH_invokeExact_UOE, MH_invokeExact_UOE(JNIEnv* env, jobject mh, jobjectArray args)) {
THROW_MSG_NULL(vmSymbols::java_lang_UnsupportedOperationException(), "MethodHandle.invokeExact cannot be invoked reflectively");
return nullptr;
}
JVM_END
// These are the native methods on java.lang.invoke.MethodHandleNatives.
static JNINativeMethod MHN_methods[] = {
{CC "init", CC "(" MEM "" OBJ ")V", FN_PTR(MHN_init_Mem)},
{CC "expand", CC "(" MEM ")V", FN_PTR(MHN_expand_Mem)},
{CC "resolve", CC "(" MEM "" CLS "IZ)" MEM, FN_PTR(MHN_resolve_Mem)},
+ {CC "checkArchivable", CC "(" CLS ")V", FN_PTR(MHN_checkArchivable)},
// static native int getNamedCon(int which, Object[] name)
{CC "getNamedCon", CC "(I[" OBJ ")I", FN_PTR(MHN_getNamedCon)},
{CC "objectFieldOffset", CC "(" MEM ")J", FN_PTR(MHN_objectFieldOffset)},
{CC "setCallSiteTargetNormal", CC "(" CS "" MH ")V", FN_PTR(MHN_setCallSiteTargetNormal)},
{CC "setCallSiteTargetVolatile", CC "(" CS "" MH ")V", FN_PTR(MHN_setCallSiteTargetVolatile)},
};
/**
* This one function is exported, used by NativeLookup.
*/
! JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) {
assert(!MethodHandles::enabled(), "must not be enabled");
assert(vmClasses::MethodHandle_klass() != nullptr, "should be present");
assert(vmClasses::VarHandle_klass() != nullptr, "should be present");
oop mh_mirror = vmClasses::MethodHandle_klass()->java_mirror();
};
/**
* This one function is exported, used by NativeLookup.
*/
! JVM_ENTRY_PROF(void, JVM_RegisterMethodHandleMethods, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) {
assert(!MethodHandles::enabled(), "must not be enabled");
assert(vmClasses::MethodHandle_klass() != nullptr, "should be present");
assert(vmClasses::VarHandle_klass() != nullptr, "should be present");
oop mh_mirror = vmClasses::MethodHandle_klass()->java_mirror();
log_debug(methodhandles, indy)("MethodHandle support loaded (using LambdaForms)");
MethodHandles::set_enabled(true);
}
JVM_END
+
+ #define DO_COUNTERS(macro) \
+ macro(MHN_init_Mem) \
+ macro(MHN_expand_Mem) \
+ macro(MHN_resolve_Mem) \
+ macro(MHN_checkArchivable) \
+ macro(MHN_getNamedCon) \
+ macro(MHN_objectFieldOffset) \
+ macro(MHN_setCallSiteTargetNormal) \
+ macro(MHN_setCallSiteTargetVolatile) \
+ macro(MHN_copyOutBootstrapArguments) \
+ macro(MHN_clearCallSiteContext) \
+ macro(MHN_staticFieldOffset) \
+ macro(MHN_staticFieldBase) \
+ macro(MHN_getMemberVMInfo) \
+ macro(MH_invoke_UOE) \
+ macro(MH_invokeExact_UOE) \
+ macro(JVM_RegisterMethodHandleMethods)
+
+ #define INIT_COUNTER(name) \
+ NEWPERFTICKCOUNTERS(_perf_##name##_timer, SUN_RT, #name); \
+ NEWPERFEVENTCOUNTER(_perf_##name##_count, SUN_RT, #name "_count"); \
+
+ void MethodHandles::init_counters() {
+ if (UsePerfData) {
+ EXCEPTION_MARK;
+
+ DO_COUNTERS(INIT_COUNTER)
+
+ if (HAS_PENDING_EXCEPTION) {
+ vm_exit_during_initialization("perf_mhn_init failed unexpectedly");
+ }
+ }
+ }
+
+ #undef INIT_COUNTER
+
+ #define PRINT_COUNTER(name) {\
+ jlong count = _perf_##name##_count->get_value(); \
+ if (count > 0) { \
+ st->print_cr(" %-40s = " JLONG_FORMAT_W(6) "us (elapsed) " JLONG_FORMAT_W(6) "us (thread) (" JLONG_FORMAT_W(5) " events)", #name, \
+ _perf_##name##_timer->elapsed_counter_value_us(), \
+ _perf_##name##_timer->thread_counter_value_us(), \
+ count); \
+ }}
+
+ void MethodHandles::print_counters_on(outputStream* st) {
+ if (ProfileVMCalls && UsePerfData) {
+ DO_COUNTERS(PRINT_COUNTER)
+ } else {
+ st->print_cr(" MHN: no info (%s is disabled)", (UsePerfData ? "ProfileVMCalls" : "UsePerfData"));
+ }
+ }
+
+ #undef PRINT_COUNTER
< prev index next >