changeset 651:5caef2219893

Merge
author dcubed
date Mon, 02 Mar 2009 16:56:51 -0700
parents 1fa16c3565be afa80fa86d22
children 3db67f76d308
files src/share/vm/includeDB_core
diffstat 21 files changed, 208 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/src/cpu/sparc/vm/interp_masm_sparc.cpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/cpu/sparc/vm/interp_masm_sparc.cpp	Mon Mar 02 16:56:51 2009 -0700
@@ -2465,7 +2465,10 @@
 //   InterpreterRuntime::post_method_entry();
 // }
 // if (DTraceMethodProbes) {
-//   SharedRuntime::dtrace_method_entry(method, reciever);
+//   SharedRuntime::dtrace_method_entry(method, receiver);
+// }
+// if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) {
+//   SharedRuntime::rc_trace_method_entry(method, receiver);
 // }
 
 void InterpreterMacroAssembler::notify_method_entry() {
@@ -2497,6 +2500,13 @@
       CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry),
       G2_thread, Lmethod);
   }
+
+  // RedefineClasses() tracing support for obsolete method entry
+  if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) {
+    call_VM_leaf(noreg,
+      CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry),
+      G2_thread, Lmethod);
+  }
 }
 
 
--- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Mon Mar 02 16:56:51 2009 -0700
@@ -2161,6 +2161,18 @@
     __ restore();
   }
 
+  // RedefineClasses() tracing support for obsolete method entry
+  if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) {
+    // create inner frame
+    __ save_frame(0);
+    __ mov(G2_thread, L7_thread_cache);
+    __ set_oop_constant(JNIHandles::make_local(method()), O1);
+    __ call_VM_leaf(L7_thread_cache,
+         CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry),
+         G2_thread, O1);
+    __ restore();
+  }
+
   // We are in the jni frame unless saved_frame is true in which case
   // we are in one frame deeper (the "inner" frame). If we are in the
   // "inner" frames the args are in the Iregs and if the jni frame then
--- a/src/cpu/x86/vm/interp_masm_x86_32.cpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp	Mon Mar 02 16:56:51 2009 -0700
@@ -1512,6 +1512,15 @@
     call_VM_leaf(
       CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), rcx, rbx);
   }
+
+  // RedefineClasses() tracing support for obsolete method entry
+  if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) {
+    get_thread(rcx);
+    get_method(rbx);
+    call_VM_leaf(
+      CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry),
+      rcx, rbx);
+  }
 }
 
 
--- a/src/cpu/x86/vm/interp_masm_x86_64.cpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp	Mon Mar 02 16:56:51 2009 -0700
@@ -1593,6 +1593,14 @@
     call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry),
                  r15_thread, c_rarg1);
   }
+
+  // RedefineClasses() tracing support for obsolete method entry
+  if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) {
+    get_method(c_rarg1);
+    call_VM_leaf(
+      CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry),
+      r15_thread, c_rarg1);
+  }
 }
 
 
--- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp	Mon Mar 02 16:56:51 2009 -0700
@@ -1534,6 +1534,13 @@
          thread, rax);
   }
 
+  // RedefineClasses() tracing support for obsolete method entry
+  if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) {
+    __ movoop(rax, JNIHandles::make_local(method()));
+    __ call_VM_leaf(
+         CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry),
+         thread, rax);
+  }
 
   // These are register definitions we need for locking/unlocking
   const Register swap_reg = rax;  // Must use rax, for cmpxchg instruction
--- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Mon Mar 02 16:56:51 2009 -0700
@@ -1508,6 +1508,17 @@
     restore_args(masm, total_c_args, c_arg, out_regs);
   }
 
+  // RedefineClasses() tracing support for obsolete method entry
+  if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) {
+    // protect the args we've loaded
+    save_args(masm, total_c_args, c_arg, out_regs);
+    __ movoop(c_rarg1, JNIHandles::make_local(method()));
+    __ call_VM_leaf(
+      CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry),
+      r15_thread, c_rarg1);
+    restore_args(masm, total_c_args, c_arg, out_regs);
+  }
+
   // Lock a synchronized method
 
   // Register definitions used by locking and unlocking
--- a/src/share/vm/includeDB_core	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/share/vm/includeDB_core	Mon Mar 02 16:56:51 2009 -0700
@@ -2094,6 +2094,7 @@
 interp_masm_<arch_model>.cpp            interpreterRuntime.hpp
 interp_masm_<arch_model>.cpp            interpreter.hpp
 interp_masm_<arch_model>.cpp            jvmtiExport.hpp
+interp_masm_<arch_model>.cpp            jvmtiRedefineClassesTrace.hpp
 interp_masm_<arch_model>.cpp            jvmtiThreadState.hpp
 interp_masm_<arch_model>.cpp            markOop.hpp
 interp_masm_<arch_model>.cpp            methodDataOop.hpp
@@ -3670,6 +3671,7 @@
 sharedRuntime.cpp                       interpreter.hpp
 sharedRuntime.cpp                       javaCalls.hpp
 sharedRuntime.cpp                       jvmtiExport.hpp
+sharedRuntime.cpp                       jvmtiRedefineClassesTrace.hpp
 sharedRuntime.cpp                       nativeInst_<arch>.hpp
 sharedRuntime.cpp                       nativeLookup.hpp
 sharedRuntime.cpp                       oop.inline.hpp
@@ -3699,6 +3701,7 @@
 sharedRuntime_<arch_model>.cpp          debugInfoRec.hpp
 sharedRuntime_<arch_model>.cpp          icBuffer.hpp
 sharedRuntime_<arch_model>.cpp          interpreter.hpp
+sharedRuntime_<arch_model>.cpp          jvmtiRedefineClassesTrace.hpp
 sharedRuntime_<arch_model>.cpp          sharedRuntime.hpp
 sharedRuntime_<arch_model>.cpp          vframeArray.hpp
 sharedRuntime_<arch_model>.cpp          vmreg_<arch>.inline.hpp
--- a/src/share/vm/oops/klassVtable.cpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/share/vm/oops/klassVtable.cpp	Mon Mar 02 16:56:51 2009 -0700
@@ -992,6 +992,10 @@
     methodOop new_method = new_methods[j];
     itableMethodEntry* ime = method_entry(0);
 
+    // The itable can describe more than one interface and the same
+    // method signature can be specified by more than one interface.
+    // This means we have to do an exhaustive search to find all the
+    // old_method references.
     for (int i = 0; i < _size_method_table; i++) {
       if (ime->method() == old_method) {
         ime->initialize(new_method);
@@ -1008,7 +1012,6 @@
             new_method->name()->as_C_string(),
             new_method->signature()->as_C_string()));
         }
-        break;
       }
       ime++;
     }
--- a/src/share/vm/prims/jvmtiEnv.cpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/share/vm/prims/jvmtiEnv.cpp	Mon Mar 02 16:56:51 2009 -0700
@@ -99,6 +99,9 @@
     }
     // otherwise, create the state
     state = JvmtiThreadState::state_for(java_thread);
+    if (state == NULL) {
+      return JVMTI_ERROR_THREAD_NOT_ALIVE;
+    }
   }
   state->env_thread_state(this)->set_agent_thread_local_storage_data((void*)data);
   return JVMTI_ERROR_NONE;
@@ -1308,6 +1311,9 @@
 
   // retrieve or create JvmtiThreadState.
   JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread);
+  if (state == NULL) {
+    return JVMTI_ERROR_THREAD_NOT_ALIVE;
+  }
   uint32_t debug_bits = 0;
   if (is_thread_fully_suspended(java_thread, true, &debug_bits)) {
     err = get_frame_count(state, count_ptr);
@@ -1329,6 +1335,12 @@
   HandleMark hm(current_thread);
   uint32_t debug_bits = 0;
 
+  // retrieve or create the state
+  JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread);
+  if (state == NULL) {
+    return JVMTI_ERROR_THREAD_NOT_ALIVE;
+  }
+
   // Check if java_thread is fully suspended
   if (!is_thread_fully_suspended(java_thread, true /* wait for suspend completion */, &debug_bits)) {
     return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
@@ -1399,9 +1411,6 @@
     // It's fine to update the thread state here because no JVMTI events
     // shall be posted for this PopFrame.
 
-    // retreive or create the state
-    JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread);
-
     state->update_for_pop_top_frame();
     java_thread->set_popframe_condition(JavaThread::popframe_pending_bit);
     // Set pending step flag for this popframe and it is cleared when next
@@ -1445,6 +1454,11 @@
   ResourceMark rm;
   uint32_t debug_bits = 0;
 
+  JvmtiThreadState *state = JvmtiThreadState::state_for(java_thread);
+  if (state == NULL) {
+    return JVMTI_ERROR_THREAD_NOT_ALIVE;
+  }
+
   if (!JvmtiEnv::is_thread_fully_suspended(java_thread, true, &debug_bits)) {
       return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
   }
@@ -1464,7 +1478,6 @@
 
   assert(vf->frame_pointer() != NULL, "frame pointer mustn't be NULL");
 
-  JvmtiThreadState *state = JvmtiThreadState::state_for(java_thread);
   int frame_number = state->count_frames() - depth;
   state->env_thread_state(this)->set_frame_pop(frame_number);
 
--- a/src/share/vm/prims/jvmtiEnvBase.cpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/share/vm/prims/jvmtiEnvBase.cpp	Mon Mar 02 16:56:51 2009 -0700
@@ -94,6 +94,35 @@
 }
 
 
+bool
+JvmtiEnvBase::is_valid() {
+  jint value = 0;
+
+  // This object might not be a JvmtiEnvBase so we can't assume
+  // the _magic field is properly aligned. Get the value in a safe
+  // way and then check against JVMTI_MAGIC.
+
+  switch (sizeof(_magic)) {
+  case 2:
+    value = Bytes::get_native_u2((address)&_magic);
+    break;
+
+  case 4:
+    value = Bytes::get_native_u4((address)&_magic);
+    break;
+
+  case 8:
+    value = Bytes::get_native_u8((address)&_magic);
+    break;
+
+  default:
+    guarantee(false, "_magic field is an unexpected size");
+  }
+
+  return value == JVMTI_MAGIC;
+}
+
+
 JvmtiEnvBase::JvmtiEnvBase() : _env_event_enable() {
   _env_local_storage = NULL;
   _tag_map = NULL;
@@ -1322,6 +1351,12 @@
   HandleMark   hm(current_thread);
   uint32_t debug_bits = 0;
 
+  // retrieve or create the state
+  JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread);
+  if (state == NULL) {
+    return JVMTI_ERROR_THREAD_NOT_ALIVE;
+  }
+
   // Check if java_thread is fully suspended
   if (!is_thread_fully_suspended(java_thread,
                                  true /* wait for suspend completion */,
@@ -1329,9 +1364,6 @@
     return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
   }
 
-  // retreive or create the state
-  JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread);
-
   // Check to see if a ForceEarlyReturn was already in progress
   if (state->is_earlyret_pending()) {
     // Probably possible for JVMTI clients to trigger this, but the
--- a/src/share/vm/prims/jvmtiEnvBase.hpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/share/vm/prims/jvmtiEnvBase.hpp	Mon Mar 02 16:56:51 2009 -0700
@@ -120,7 +120,7 @@
 
  public:
 
-  bool is_valid()                                  { return _magic == JVMTI_MAGIC; }
+  bool is_valid();
 
   bool is_retransformable()                        { return _is_retransformable; }
 
--- a/src/share/vm/prims/jvmtiEventController.cpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/share/vm/prims/jvmtiEventController.cpp	Mon Mar 02 16:56:51 2009 -0700
@@ -478,6 +478,11 @@
 // set external state accordingly.  Only thread-filtered events are included.
 jlong
 JvmtiEventControllerPrivate::recompute_thread_enabled(JvmtiThreadState *state) {
+  if (state == NULL) {
+    // associated JavaThread is exiting
+    return (jlong)0;
+  }
+
   jlong was_any_env_enabled = state->thread_event_enable()->_event_enabled.get_bits();
   jlong any_env_enabled = 0;
 
@@ -553,6 +558,7 @@
     {
       MutexLocker mu(Threads_lock);   //hold the Threads_lock for the iteration
       for (JavaThread *tp = Threads::first(); tp != NULL; tp = tp->next()) {
+        // state_for_while_locked() makes tp->is_exiting() check
         JvmtiThreadState::state_for_while_locked(tp);  // create the thread state if missing
       }
     }// release Threads_lock
--- a/src/share/vm/prims/jvmtiExport.cpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/share/vm/prims/jvmtiExport.cpp	Mon Mar 02 16:56:51 2009 -0700
@@ -1872,6 +1872,9 @@
 {
   // register the stub with the current dynamic code event collector
   JvmtiThreadState* state = JvmtiThreadState::state_for(JavaThread::current());
+  // state can only be NULL if the current thread is exiting which
+  // should not happen since we're trying to post an event
+  guarantee(state != NULL, "attempt to register stub via an exiting thread");
   JvmtiDynamicCodeEventCollector* collector = state->get_dynamic_code_event_collector();
   guarantee(collector != NULL, "attempt to register stub without event collector");
   collector->register_stub(name, code_begin, code_end);
@@ -2253,6 +2256,9 @@
 void JvmtiEventCollector::setup_jvmti_thread_state() {
   // set this event collector to be the current one.
   JvmtiThreadState* state = JvmtiThreadState::state_for(JavaThread::current());
+  // state can only be NULL if the current thread is exiting which
+  // should not happen since we're trying to configure for event collection
+  guarantee(state != NULL, "exiting thread called setup_jvmti_thread_state");
   if (is_vm_object_alloc_event()) {
     _prev = state->get_vm_object_alloc_event_collector();
     state->set_vm_object_alloc_event_collector((JvmtiVMObjectAllocEventCollector *)this);
--- a/src/share/vm/prims/jvmtiImpl.cpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/share/vm/prims/jvmtiImpl.cpp	Mon Mar 02 16:56:51 2009 -0700
@@ -238,6 +238,35 @@
 }
 
 
+bool
+JvmtiRawMonitor::is_valid() {
+  int value = 0;
+
+  // This object might not be a JvmtiRawMonitor so we can't assume
+  // the _magic field is properly aligned. Get the value in a safe
+  // way and then check against JVMTI_RM_MAGIC.
+
+  switch (sizeof(_magic)) {
+  case 2:
+    value = Bytes::get_native_u2((address)&_magic);
+    break;
+
+  case 4:
+    value = Bytes::get_native_u4((address)&_magic);
+    break;
+
+  case 8:
+    value = Bytes::get_native_u8((address)&_magic);
+    break;
+
+  default:
+    guarantee(false, "_magic field is an unexpected size");
+  }
+
+  return value == JVMTI_RM_MAGIC;
+}
+
+
 //
 // class JvmtiBreakpoint
 //
--- a/src/share/vm/prims/jvmtiImpl.hpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/share/vm/prims/jvmtiImpl.hpp	Mon Mar 02 16:56:51 2009 -0700
@@ -349,7 +349,7 @@
   ~JvmtiRawMonitor();
   int            magic()   { return _magic;  }
   const char *get_name()   { return _name; }
-  bool        is_valid()   { return _magic == JVMTI_RM_MAGIC;  }
+  bool        is_valid();
 };
 
 // Onload pending raw monitors
--- a/src/share/vm/prims/jvmtiRedefineClasses.cpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp	Mon Mar 02 16:56:51 2009 -0700
@@ -831,6 +831,9 @@
   ResourceMark rm(THREAD);
 
   JvmtiThreadState *state = JvmtiThreadState::state_for(JavaThread::current());
+  // state can only be NULL if the current thread is exiting which
+  // should not happen since we're trying to do a RedefineClasses
+  guarantee(state != NULL, "exiting thread calling load_new_class_versions");
   for (int i = 0; i < _class_count; i++) {
     oop mirror = JNIHandles::resolve_non_null(_class_defs[i].klass);
     // classes for primitives cannot be redefined
--- a/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp	Mon Mar 02 16:56:51 2009 -0700
@@ -49,8 +49,8 @@
 //    0x00000400 |       1024 - previous class weak reference mgmt during
 //                              add previous ops (GC)
 //    0x00000800 |       2048 - previous class breakpoint mgmt
-//    0x00001000 |       4096 - unused
-//    0x00002000 |       8192 - unused
+//    0x00001000 |       4096 - detect calls to obsolete methods
+//    0x00002000 |       8192 - fail a guarantee() in addition to detection
 //    0x00004000 |      16384 - unused
 //    0x00008000 |      32768 - old/new method matching/add/delete
 //    0x00010000 |      65536 - impl details: CP size info
--- a/src/share/vm/prims/jvmtiThreadState.hpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/share/vm/prims/jvmtiThreadState.hpp	Mon Mar 02 16:56:51 2009 -0700
@@ -314,17 +314,24 @@
   void update_for_pop_top_frame();
 
   // already holding JvmtiThreadState_lock - retrieve or create JvmtiThreadState
+  // Can return NULL if JavaThread is exiting.
   inline static JvmtiThreadState *state_for_while_locked(JavaThread *thread) {
     assert(JvmtiThreadState_lock->is_locked(), "sanity check");
 
     JvmtiThreadState *state = thread->jvmti_thread_state();
     if (state == NULL) {
+      if (thread->is_exiting()) {
+        // don't add a JvmtiThreadState to a thread that is exiting
+        return NULL;
+      }
+
       state = new JvmtiThreadState(thread);
     }
     return state;
   }
 
   // retrieve or create JvmtiThreadState
+  // Can return NULL if JavaThread is exiting.
   inline static JvmtiThreadState *state_for(JavaThread *thread) {
     JvmtiThreadState *state = thread->jvmti_thread_state();
     if (state == NULL) {
--- a/src/share/vm/runtime/sharedRuntime.cpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/share/vm/runtime/sharedRuntime.cpp	Mon Mar 02 16:56:51 2009 -0700
@@ -377,6 +377,32 @@
   throw_and_post_jvmti_exception(thread, h_exception);
 }
 
+// The interpreter code to call this tracing function is only
+// called/generated when TraceRedefineClasses has the right bits
+// set. Since obsolete methods are never compiled, we don't have
+// to modify the compilers to generate calls to this function.
+//
+JRT_LEAF(int, SharedRuntime::rc_trace_method_entry(
+    JavaThread* thread, methodOopDesc* method))
+  assert(RC_TRACE_IN_RANGE(0x00001000, 0x00002000), "wrong call");
+
+  if (method->is_obsolete()) {
+    // We are calling an obsolete method, but this is not necessarily
+    // an error. Our method could have been redefined just after we
+    // fetched the methodOop from the constant pool.
+
+    // RC_TRACE macro has an embedded ResourceMark
+    RC_TRACE_WITH_THREAD(0x00001000, thread,
+                         ("calling obsolete method '%s'",
+                          method->name_and_sig_as_C_string()));
+    if (RC_TRACE_ENABLED(0x00002000)) {
+      // this option is provided to debug calls to obsolete methods
+      guarantee(false, "faulting at call to an obsolete method.");
+    }
+  }
+  return 0;
+JRT_END
+
 // ret_pc points into caller; we are returning caller's exception handler
 // for given exception
 address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, Handle& exception,
--- a/src/share/vm/runtime/sharedRuntime.hpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/share/vm/runtime/sharedRuntime.hpp	Mon Mar 02 16:56:51 2009 -0700
@@ -166,6 +166,9 @@
   static void throw_and_post_jvmti_exception(JavaThread *thread, Handle h_exception);
   static void throw_and_post_jvmti_exception(JavaThread *thread, symbolOop name, const char *message = NULL);
 
+  // RedefineClasses() tracing support for obsolete method entry
+  static int rc_trace_method_entry(JavaThread* thread, methodOopDesc* m);
+
   // To be used as the entry point for unresolved native methods.
   static address native_method_throw_unsatisfied_link_error_entry();
 
--- a/src/share/vm/runtime/thread.hpp	Fri Feb 27 15:30:47 2009 -0800
+++ b/src/share/vm/runtime/thread.hpp	Mon Mar 02 16:56:51 2009 -0700
@@ -1345,6 +1345,13 @@
  public:
   // Thread local information maintained by JVMTI.
   void set_jvmti_thread_state(JvmtiThreadState *value)                           { _jvmti_thread_state = value; }
+  // A JvmtiThreadState is lazily allocated. This jvmti_thread_state()
+  // getter is used to get this JavaThread's JvmtiThreadState if it has
+  // one which means NULL can be returned. JvmtiThreadState::state_for()
+  // is used to get the specified JavaThread's JvmtiThreadState if it has
+  // one or it allocates a new JvmtiThreadState for the JavaThread and
+  // returns it. JvmtiThreadState::state_for() will return NULL only if
+  // the specified JavaThread is exiting.
   JvmtiThreadState *jvmti_thread_state() const                                   { return _jvmti_thread_state; }
   static ByteSize jvmti_thread_state_offset()                                    { return byte_offset_of(JavaThread, _jvmti_thread_state); }
   void set_jvmti_get_loaded_classes_closure(JvmtiGetLoadedClassesClosure* value) { _jvmti_get_loaded_classes_closure = value; }