mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
8347564: ZGC: Crash in DependencyContext::clean_unloading_dependents
Reviewed-by: rrich
Backport-of: 14136f8b11
This commit is contained in:
committed by
Vitaly Provodin
parent
40cccf68a2
commit
33e89943f7
@@ -4496,28 +4496,31 @@ int java_lang_invoke_MethodType::rtype_slot_count(oop mt) {
|
||||
// Support for java_lang_invoke_CallSite
|
||||
|
||||
int java_lang_invoke_CallSite::_target_offset;
|
||||
int java_lang_invoke_CallSite::_context_offset;
|
||||
int java_lang_invoke_CallSite::_vmdependencies_offset;
|
||||
int java_lang_invoke_CallSite::_last_cleanup_offset;
|
||||
|
||||
#define CALLSITE_FIELDS_DO(macro) \
|
||||
macro(_target_offset, k, "target", java_lang_invoke_MethodHandle_signature, false); \
|
||||
macro(_context_offset, k, "context", java_lang_invoke_MethodHandleNatives_CallSiteContext_signature, false)
|
||||
|
||||
void java_lang_invoke_CallSite::compute_offsets() {
|
||||
InstanceKlass* k = vmClasses::CallSite_klass();
|
||||
CALLSITE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
|
||||
CALLSITE_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
void java_lang_invoke_CallSite::serialize_offsets(SerializeClosure* f) {
|
||||
CALLSITE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
|
||||
CALLSITE_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET);
|
||||
}
|
||||
#endif
|
||||
|
||||
oop java_lang_invoke_CallSite::context_no_keepalive(oop call_site) {
|
||||
DependencyContext java_lang_invoke_CallSite::vmdependencies(oop call_site) {
|
||||
assert(java_lang_invoke_CallSite::is_instance(call_site), "");
|
||||
|
||||
oop dep_oop = call_site->obj_field_access<AS_NO_KEEPALIVE>(_context_offset);
|
||||
return dep_oop;
|
||||
nmethodBucket* volatile* vmdeps_addr = call_site->field_addr<nmethodBucket* volatile>(_vmdependencies_offset);
|
||||
volatile uint64_t* last_cleanup_addr = call_site->field_addr<volatile uint64_t>(_last_cleanup_offset);
|
||||
DependencyContext dep_ctx(vmdeps_addr, last_cleanup_addr);
|
||||
return dep_ctx;
|
||||
}
|
||||
|
||||
// Support for java_lang_invoke_ConstantCallSite
|
||||
@@ -4538,30 +4541,6 @@ void java_lang_invoke_ConstantCallSite::serialize_offsets(SerializeClosure* f) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Support for java_lang_invoke_MethodHandleNatives_CallSiteContext
|
||||
|
||||
int java_lang_invoke_MethodHandleNatives_CallSiteContext::_vmdependencies_offset;
|
||||
int java_lang_invoke_MethodHandleNatives_CallSiteContext::_last_cleanup_offset;
|
||||
|
||||
void java_lang_invoke_MethodHandleNatives_CallSiteContext::compute_offsets() {
|
||||
InstanceKlass* k = vmClasses::Context_klass();
|
||||
CALLSITECONTEXT_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
void java_lang_invoke_MethodHandleNatives_CallSiteContext::serialize_offsets(SerializeClosure* f) {
|
||||
CALLSITECONTEXT_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET);
|
||||
}
|
||||
#endif
|
||||
|
||||
DependencyContext java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(oop call_site) {
|
||||
assert(java_lang_invoke_MethodHandleNatives_CallSiteContext::is_instance(call_site), "");
|
||||
nmethodBucket* volatile* vmdeps_addr = call_site->field_addr<nmethodBucket* volatile>(_vmdependencies_offset);
|
||||
volatile uint64_t* last_cleanup_addr = call_site->field_addr<volatile uint64_t>(_last_cleanup_offset);
|
||||
DependencyContext dep_ctx(vmdeps_addr, last_cleanup_addr);
|
||||
return dep_ctx;
|
||||
}
|
||||
|
||||
// Support for java_security_AccessControlContext
|
||||
|
||||
int java_security_AccessControlContext::_context_offset;
|
||||
@@ -5305,7 +5284,6 @@ void java_lang_InternalError::serialize_offsets(SerializeClosure* f) {
|
||||
f(java_lang_invoke_ConstantCallSite) \
|
||||
f(java_lang_invoke_DirectMethodHandle_StaticAccessor) \
|
||||
f(java_lang_invoke_DirectMethodHandle_Accessor) \
|
||||
f(java_lang_invoke_MethodHandleNatives_CallSiteContext) \
|
||||
f(java_security_AccessControlContext) \
|
||||
f(java_lang_reflect_AccessibleObject) \
|
||||
f(java_lang_reflect_Method) \
|
||||
@@ -5379,7 +5357,6 @@ bool JavaClasses::is_supported_for_archiving(oop obj) {
|
||||
// constant pool entries, so excluding them shouldn't affect the archiving of static fields.
|
||||
klass == vmClasses::ResolvedMethodName_klass() ||
|
||||
klass == vmClasses::MemberName_klass() ||
|
||||
klass == vmClasses::Context_klass() ||
|
||||
// It's problematic to archive Reference objects. One of the reasons is that
|
||||
// Reference::discovered may pull in unwanted objects (see JDK-8284336)
|
||||
klass->is_subclass_of(vmClasses::Reference_klass())) {
|
||||
|
||||
@@ -1419,13 +1419,17 @@ class java_lang_invoke_MethodType: AllStatic {
|
||||
|
||||
|
||||
// Interface to java.lang.invoke.CallSite objects
|
||||
#define CALLSITE_INJECTED_FIELDS(macro) \
|
||||
macro(java_lang_invoke_CallSite, vmdependencies, intptr_signature, false) \
|
||||
macro(java_lang_invoke_CallSite, last_cleanup, long_signature, false)
|
||||
|
||||
class java_lang_invoke_CallSite: AllStatic {
|
||||
friend class JavaClasses;
|
||||
|
||||
private:
|
||||
static int _target_offset;
|
||||
static int _context_offset;
|
||||
static int _vmdependencies_offset;
|
||||
static int _last_cleanup_offset;
|
||||
|
||||
static void compute_offsets();
|
||||
|
||||
@@ -1436,7 +1440,7 @@ public:
|
||||
static void set_target( oop site, oop target);
|
||||
static void set_target_volatile( oop site, oop target);
|
||||
|
||||
static oop context_no_keepalive(oop site);
|
||||
static DependencyContext vmdependencies(oop call_site);
|
||||
|
||||
// Testers
|
||||
static bool is_subclass(Klass* klass) {
|
||||
@@ -1446,7 +1450,6 @@ public:
|
||||
|
||||
// Accessors for code generation:
|
||||
static int target_offset() { CHECK_INIT(_target_offset); }
|
||||
static int context_offset() { CHECK_INIT(_context_offset); }
|
||||
};
|
||||
|
||||
// Interface to java.lang.invoke.ConstantCallSite objects
|
||||
@@ -1471,35 +1474,6 @@ public:
|
||||
static bool is_instance(oop obj);
|
||||
};
|
||||
|
||||
// Interface to java.lang.invoke.MethodHandleNatives$CallSiteContext objects
|
||||
|
||||
#define CALLSITECONTEXT_INJECTED_FIELDS(macro) \
|
||||
macro(java_lang_invoke_MethodHandleNatives_CallSiteContext, vmdependencies, intptr_signature, false) \
|
||||
macro(java_lang_invoke_MethodHandleNatives_CallSiteContext, last_cleanup, long_signature, false)
|
||||
|
||||
class DependencyContext;
|
||||
|
||||
class java_lang_invoke_MethodHandleNatives_CallSiteContext : AllStatic {
|
||||
friend class JavaClasses;
|
||||
|
||||
private:
|
||||
static int _vmdependencies_offset;
|
||||
static int _last_cleanup_offset;
|
||||
|
||||
static void compute_offsets();
|
||||
|
||||
public:
|
||||
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
|
||||
// Accessors
|
||||
static DependencyContext vmdependencies(oop context);
|
||||
|
||||
// Testers
|
||||
static bool is_subclass(Klass* klass) {
|
||||
return klass->is_subclass_of(vmClasses::Context_klass());
|
||||
}
|
||||
static bool is_instance(oop obj);
|
||||
};
|
||||
|
||||
// Interface to java.security.AccessControlContext objects
|
||||
|
||||
class java_security_AccessControlContext: AllStatic {
|
||||
|
||||
@@ -261,10 +261,6 @@ inline bool java_lang_invoke_ConstantCallSite::is_instance(oop obj) {
|
||||
return obj != nullptr && is_subclass(obj->klass());
|
||||
}
|
||||
|
||||
inline bool java_lang_invoke_MethodHandleNatives_CallSiteContext::is_instance(oop obj) {
|
||||
return obj != nullptr && is_subclass(obj->klass());
|
||||
}
|
||||
|
||||
inline bool java_lang_invoke_MemberName::is_instance(oop obj) {
|
||||
return obj != nullptr && (obj->klass() == vmClasses::MemberName_klass()
|
||||
|| (Universe::is_inside_redefinition() && obj->klass()->newest_version() == vmClasses::MemberName_klass()));
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
CLASSLOADER_INJECTED_FIELDS(macro) \
|
||||
RESOLVEDMETHOD_INJECTED_FIELDS(macro) \
|
||||
MEMBERNAME_INJECTED_FIELDS(macro) \
|
||||
CALLSITECONTEXT_INJECTED_FIELDS(macro) \
|
||||
CALLSITE_INJECTED_FIELDS(macro) \
|
||||
STACKFRAMEINFO_INJECTED_FIELDS(macro) \
|
||||
MODULE_INJECTED_FIELDS(macro) \
|
||||
THREAD_INJECTED_FIELDS(macro) \
|
||||
|
||||
@@ -131,7 +131,6 @@
|
||||
do_klass(ABIDescriptor_klass, jdk_internal_foreign_abi_ABIDescriptor ) \
|
||||
do_klass(VMStorage_klass, jdk_internal_foreign_abi_VMStorage ) \
|
||||
do_klass(CallConv_klass, jdk_internal_foreign_abi_CallConv ) \
|
||||
do_klass(Context_klass, java_lang_invoke_MethodHandleNatives_CallSiteContext ) \
|
||||
do_klass(ConstantCallSite_klass, java_lang_invoke_ConstantCallSite ) \
|
||||
do_klass(MutableCallSite_klass, java_lang_invoke_MutableCallSite ) \
|
||||
do_klass(VolatileCallSite_klass, java_lang_invoke_VolatileCallSite ) \
|
||||
|
||||
@@ -343,11 +343,9 @@
|
||||
template(java_lang_invoke_MemberName, "java/lang/invoke/MemberName") \
|
||||
template(java_lang_invoke_ResolvedMethodName, "java/lang/invoke/ResolvedMethodName") \
|
||||
template(java_lang_invoke_MethodHandleNatives, "java/lang/invoke/MethodHandleNatives") \
|
||||
template(java_lang_invoke_MethodHandleNatives_CallSiteContext, "java/lang/invoke/MethodHandleNatives$CallSiteContext") \
|
||||
template(java_lang_invoke_LambdaForm, "java/lang/invoke/LambdaForm") \
|
||||
template(java_lang_invoke_InjectedProfile_signature, "Ljava/lang/invoke/InjectedProfile;") \
|
||||
template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \
|
||||
template(java_lang_invoke_MethodHandleNatives_CallSiteContext_signature, "Ljava/lang/invoke/MethodHandleNatives$CallSiteContext;") \
|
||||
/* internal up-calls made only by the JVM, via class sun.invoke.MethodHandleNatives: */ \
|
||||
template(findMethodHandleType_name, "findMethodHandleType") \
|
||||
template(findMethodHandleType_signature, "(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/invoke/MethodType;") \
|
||||
|
||||
@@ -168,12 +168,6 @@ void DependencyContext::clean_unloading_dependents() {
|
||||
}
|
||||
}
|
||||
|
||||
nmethodBucket* DependencyContext::release_and_get_next_not_unloading(nmethodBucket* b) {
|
||||
nmethodBucket* next = b->next_not_unloading();
|
||||
release(b);
|
||||
return next;
|
||||
}
|
||||
|
||||
//
|
||||
// Invalidate all dependencies in the context
|
||||
void DependencyContext::remove_all_dependents() {
|
||||
@@ -214,18 +208,6 @@ void DependencyContext::remove_all_dependents() {
|
||||
set_dependencies(nullptr);
|
||||
}
|
||||
|
||||
void DependencyContext::remove_and_mark_for_deoptimization_all_dependents(DeoptimizationScope* deopt_scope) {
|
||||
nmethodBucket* b = dependencies_not_unloading();
|
||||
set_dependencies(nullptr);
|
||||
while (b != nullptr) {
|
||||
nmethod* nm = b->get_nmethod();
|
||||
// Also count already (concurrently) marked nmethods to make sure
|
||||
// deoptimization is triggered before execution in this thread continues.
|
||||
deopt_scope->mark(nm);
|
||||
b = release_and_get_next_not_unloading(b);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void DependencyContext::print_dependent_nmethods(bool verbose) {
|
||||
int idx = 0;
|
||||
|
||||
@@ -63,7 +63,7 @@ class nmethodBucket: public CHeapObj<mtClass> {
|
||||
//
|
||||
// Utility class to manipulate nmethod dependency context.
|
||||
// Dependency context can be attached either to an InstanceKlass (_dep_context field)
|
||||
// or CallSiteContext oop for call_site_target dependencies (see javaClasses.hpp).
|
||||
// or CallSite oop for call_site_target dependencies (see javaClasses.hpp).
|
||||
// DependencyContext class operates on some location which holds a nmethodBucket* value
|
||||
// and uint64_t integer recording the safepoint counter at the last cleanup.
|
||||
//
|
||||
@@ -92,7 +92,6 @@ class DependencyContext : public StackObj {
|
||||
#ifdef ASSERT
|
||||
// Safepoints are forbidden during DC lifetime. GC can invalidate
|
||||
// _dependency_context_addr if it relocates the holder
|
||||
// (e.g. CallSiteContext Java object).
|
||||
SafepointStateTracker _safepoint_tracker;
|
||||
|
||||
DependencyContext(nmethodBucket* volatile* bucket_addr, volatile uint64_t* last_cleanup_addr)
|
||||
@@ -114,9 +113,7 @@ class DependencyContext : public StackObj {
|
||||
void mark_dependent_nmethods(DeoptimizationScope* deopt_scope, DepChange& changes);
|
||||
void add_dependent_nmethod(nmethod* nm);
|
||||
void remove_all_dependents();
|
||||
void remove_and_mark_for_deoptimization_all_dependents(DeoptimizationScope* deopt_scope);
|
||||
void clean_unloading_dependents();
|
||||
static nmethodBucket* release_and_get_next_not_unloading(nmethodBucket* b);
|
||||
static void purge_dependency_contexts();
|
||||
static void release(nmethodBucket* b);
|
||||
static void cleaning_start();
|
||||
|
||||
@@ -934,19 +934,12 @@ void MethodHandles::expand_MemberName(Handle mname, int suppress, TRAPS) {
|
||||
void MethodHandles::add_dependent_nmethod(oop call_site, nmethod* nm) {
|
||||
assert_locked_or_safepoint(CodeCache_lock);
|
||||
|
||||
oop context = java_lang_invoke_CallSite::context_no_keepalive(call_site);
|
||||
DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context);
|
||||
// Try to purge stale entries on updates.
|
||||
// Since GC doesn't clean dependency contexts rooted at CallSiteContext objects,
|
||||
// in order to avoid memory leak, stale entries are purged whenever a dependency list
|
||||
// is changed (both on addition and removal). Though memory reclamation is delayed,
|
||||
// it avoids indefinite memory usage growth.
|
||||
DependencyContext deps = java_lang_invoke_CallSite::vmdependencies(call_site);
|
||||
deps.add_dependent_nmethod(nm);
|
||||
}
|
||||
|
||||
void MethodHandles::clean_dependency_context(oop call_site) {
|
||||
oop context = java_lang_invoke_CallSite::context_no_keepalive(call_site);
|
||||
DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context);
|
||||
DependencyContext deps = java_lang_invoke_CallSite::vmdependencies(call_site);
|
||||
deps.clean_unloading_dependents();
|
||||
}
|
||||
|
||||
@@ -958,8 +951,7 @@ void MethodHandles::mark_dependent_nmethods(DeoptimizationScope* deopt_scope, Ha
|
||||
NoSafepointVerifier nsv;
|
||||
MutexLocker ml(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
|
||||
oop context = java_lang_invoke_CallSite::context_no_keepalive(call_site());
|
||||
DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context);
|
||||
DependencyContext deps = java_lang_invoke_CallSite::vmdependencies(call_site());
|
||||
deps.mark_dependent_nmethods(deopt_scope, changes);
|
||||
}
|
||||
}
|
||||
@@ -1323,23 +1315,6 @@ JVM_ENTRY(void, MHN_copyOutBootstrapArguments(JNIEnv* env, jobject igcls,
|
||||
}
|
||||
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);
|
||||
DependencyContext deps = java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(context());
|
||||
deps.remove_and_mark_for_deoptimization_all_dependents(&deopt_scope);
|
||||
// This is assumed to be an 'atomic' operation by verification.
|
||||
// So keep it under lock for now.
|
||||
deopt_scope.deoptimize_marked();
|
||||
}
|
||||
}
|
||||
JVM_END
|
||||
|
||||
/**
|
||||
* Throws a java/lang/UnsupportedOperationException unconditionally.
|
||||
* This is required by the specification of MethodHandle.invoke if
|
||||
@@ -1374,7 +1349,6 @@ JVM_END
|
||||
#define MT JLINV "MethodType;"
|
||||
#define MH JLINV "MethodHandle;"
|
||||
#define MEM JLINV "MemberName;"
|
||||
#define CTX JLINV "MethodHandleNatives$CallSiteContext;"
|
||||
|
||||
#define CC (char*) /*cast a literal from (const char*)*/
|
||||
#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
|
||||
@@ -1390,7 +1364,6 @@ static JNINativeMethod MHN_methods[] = {
|
||||
{CC "setCallSiteTargetNormal", CC "(" CS "" MH ")V", FN_PTR(MHN_setCallSiteTargetNormal)},
|
||||
{CC "setCallSiteTargetVolatile", CC "(" CS "" MH ")V", FN_PTR(MHN_setCallSiteTargetVolatile)},
|
||||
{CC "copyOutBootstrapArguments", CC "(" CLS "[III[" OBJ "IZ" OBJ ")V", FN_PTR(MHN_copyOutBootstrapArguments)},
|
||||
{CC "clearCallSiteContext", CC "(" CTX ")V", FN_PTR(MHN_clearCallSiteContext)},
|
||||
{CC "staticFieldOffset", CC "(" MEM ")J", FN_PTR(MHN_staticFieldOffset)},
|
||||
{CC "staticFieldBase", CC "(" MEM ")" OBJ, FN_PTR(MHN_staticFieldBase)},
|
||||
{CC "getMemberVMInfo", CC "(" MEM ")" OBJ, FN_PTR(MHN_getMemberVMInfo)}
|
||||
|
||||
@@ -138,12 +138,6 @@ abstract sealed class CallSite permits ConstantCallSite, MutableCallSite, Volati
|
||||
UNSAFE.storeStoreFence(); // barrier between target and isFrozen updates
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code CallSite} dependency context.
|
||||
* JVM uses CallSite.context to store nmethod dependencies on the call site target.
|
||||
*/
|
||||
private final MethodHandleNatives.CallSiteContext context = MethodHandleNatives.CallSiteContext.make(this);
|
||||
|
||||
/**
|
||||
* Returns the type of this call site's target.
|
||||
* Although targets may change, any call site's type is permanent, and can never change to an unequal type.
|
||||
|
||||
@@ -71,31 +71,6 @@ class MethodHandleNatives {
|
||||
boolean resolve,
|
||||
Object ifNotAvailable);
|
||||
|
||||
/** Represents a context to track nmethod dependencies on CallSite instance target. */
|
||||
static class CallSiteContext implements Runnable {
|
||||
//@Injected JVM_nmethodBucket* vmdependencies;
|
||||
//@Injected jlong last_cleanup;
|
||||
|
||||
static CallSiteContext make(CallSite cs) {
|
||||
final CallSiteContext newContext = new CallSiteContext();
|
||||
// CallSite instance is tracked by a Cleanable which clears native
|
||||
// structures allocated for CallSite context. Though the CallSite can
|
||||
// become unreachable, its Context is retained by the Cleanable instance
|
||||
// (which is referenced from Cleaner instance which is referenced from
|
||||
// CleanerFactory class) until cleanup is performed.
|
||||
CleanerFactory.cleaner().register(cs, newContext);
|
||||
return newContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
MethodHandleNatives.clearCallSiteContext(this);
|
||||
}
|
||||
}
|
||||
|
||||
/** Invalidate all recorded nmethods. */
|
||||
private static native void clearCallSiteContext(CallSiteContext context);
|
||||
|
||||
private static native void registerNatives();
|
||||
static {
|
||||
registerNatives();
|
||||
|
||||
@@ -123,8 +123,8 @@ public class CallSiteDepContextTest {
|
||||
|
||||
public static void testHiddenDepField() {
|
||||
try {
|
||||
Field f = MethodHandleHelper.MHN_CALL_SITE_CONTEXT_CLASS.getDeclaredField("vmdependencies");
|
||||
throw new AssertionError("Context.dependencies field should be hidden");
|
||||
Field f = MethodHandleHelper.JLI_CALL_SITE_CLASS.getDeclaredField("vmdependencies");
|
||||
throw new AssertionError("CallSite.dependencies field should be hidden");
|
||||
} catch(NoSuchFieldException e) { /* expected */ }
|
||||
}
|
||||
|
||||
|
||||
@@ -36,8 +36,8 @@ public class MethodHandleHelper {
|
||||
private MethodHandleHelper() { }
|
||||
|
||||
public static final Lookup IMPL_LOOKUP = Lookup.IMPL_LOOKUP;
|
||||
public static final Class<?> MHN_CALL_SITE_CONTEXT_CLASS
|
||||
= MethodHandleNatives.CallSiteContext.class;
|
||||
public static final Class<?> JLI_CALL_SITE_CLASS
|
||||
= java.lang.invoke.CallSite.class;
|
||||
|
||||
public static void customize(MethodHandle mh) {
|
||||
mh.customize();
|
||||
|
||||
Reference in New Issue
Block a user