< prev index next >

src/hotspot/share/prims/methodHandles.cpp

Print this page
*** 21,14 ***
--- 21,16 ---
   * 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"

*** 49,18 ***
--- 51,21 ---
  #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

*** 1044,11 ***
  #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));
--- 1049,11 ---
  #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));

*** 1065,29 ***
    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
--- 1070,29 ---
    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

*** 1169,29 ***
    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;
--- 1174,29 ---
    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;

*** 1209,11 ***
    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.
--- 1214,11 ---
    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.

*** 1225,11 ***
      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.
--- 1230,43 ---
      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 (ArchiveInvokeDynamic) {
+     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.

*** 1241,11 ***
      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));
--- 1278,11 ---
      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));

*** 1324,11 ***
  }
  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);
--- 1361,11 ---
  }
  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);

*** 1344,22 ***
  /**
   * 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
  
--- 1381,22 ---
  /**
   * 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
  

*** 1383,10 ***
--- 1420,11 ---
  // 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)},

*** 1404,11 ***
  };
  
  /**
   * 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");
  
    oop mirror = vmClasses::MethodHandle_klass()->java_mirror();
    jclass MH_class = (jclass) JNIHandles::make_local(THREAD, mirror);
--- 1442,11 ---
  };
  
  /**
   * 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");
  
    oop mirror = vmClasses::MethodHandle_klass()->java_mirror();
    jclass MH_class = (jclass) JNIHandles::make_local(THREAD, mirror);

*** 1428,5 ***
--- 1466,60 ---
    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 = %4ldms (elapsed) %4ldms (thread) (%5ld events)", #name, \
+                  _perf_##name##_timer->elapsed_counter_value_ms(), \
+                  _perf_##name##_timer->thread_counter_value_ms(), \
+                  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 >