From 6652d6ac332f34a2a222639b6438f64a9138075e Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 15 May 2015 19:23:27 +0300 Subject: [PATCH] 8079205: CallSite dependency tracking is broken after sun.misc.Cleaner became automatically cleared Reviewed-by: roland, psandoz, plevart, kbarrett, jrose --- .../classes/java/lang/invoke/CallSite.java | 44 +------------------ .../java/lang/invoke/MethodHandleNatives.java | 25 +++++++++-- 2 files changed, 24 insertions(+), 45 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java b/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java index 11e452b96c9..13cf24ca0f2 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java @@ -27,8 +27,6 @@ package java.lang.invoke; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; -import java.lang.reflect.Field; -import sun.misc.Cleaner; /** * A {@code CallSite} is a holder for a variable {@link MethodHandle}, @@ -138,47 +136,9 @@ public class CallSite { /** * {@code CallSite} dependency context. - * VM uses context class to store nmethod dependencies on the call site target. - * Can be in 2 states: (a) null; or (b) {@code Cleaner} instance pointing to some Class instance. - * Lazily initialized when CallSite instance is linked to some indy call site or VM needs - * it to store dependencies. As a corollary, "null" context means there are no dependencies - * registered yet. {@code Cleaner} is used in 2 roles: - * (a) context class access for VM; - * (b) stale context class cleanup. - * {@code Cleaner} holds the context class until cleanup action is finished (see {@code PhantomReference}). - * Though it's impossible to get the context class using {@code Reference.get()}, VM extracts it directly - * from {@code Reference.referent} field. + * JVM uses CallSite.context to store nmethod dependencies on the call site target. */ - private volatile Cleaner context = null; - - /** - * Default context. - * VM uses it to initialize non-linked CallSite context. - */ - private static class DefaultContext {} - private static final Cleaner DEFAULT_CONTEXT = makeContext(DefaultContext.class, null); - - private static Cleaner makeContext(Class referent, final CallSite holder) { - return Cleaner.create(referent, - new Runnable() { - @Override public void run() { - MethodHandleNatives.invalidateDependentNMethods(holder); - } - }); - } - - /** Initialize context class used for nmethod dependency tracking */ - /*package-private*/ - void initContext(Class newContext) { - // If there are concurrent actions, exactly one succeeds. - if (context == null) { - UNSAFE.compareAndSwapObject(this, CONTEXT_OFFSET, /*expected=*/null, makeContext(newContext, this)); - // No need to care about failed CAS attempt. - // Since initContext is called from indy call site linkage in newContext class, there's no risk - // that the context class becomes dead while corresponding context cleaner is alive (causing cleanup - // action in the wrong context). - } - } + private final MethodHandleNatives.CallSiteContext context = MethodHandleNatives.CallSiteContext.make(this); /** * Returns the type of this call site's target. diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java index 3d3c47f689c..b53b44b99b1 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java @@ -30,6 +30,7 @@ import java.lang.reflect.Field; import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; +import sun.misc.Cleaner; /** * The JVM interface for the method handles package is all here. @@ -61,8 +62,27 @@ class MethodHandleNatives { static native void setCallSiteTargetNormal(CallSite site, MethodHandle target); static native void setCallSiteTargetVolatile(CallSite site, MethodHandle target); - /** Invalidate CallSite context: clean up dependent nmethods and reset call site context to initial state (null). */ - static native void invalidateDependentNMethods(CallSite site); + /** Represents a context to track nmethod dependencies on CallSite instance target. */ + static class CallSiteContext implements Runnable { + //@Injected JVM_nmethodBucket* vmdependencies; + + static CallSiteContext make(CallSite cs) { + final CallSiteContext newContext = new CallSiteContext(); + // Cleaner is attached to CallSite instance and it clears native structures allocated for CallSite context. + // Though the CallSite can become unreachable, its Context is retained by the Cleaner instance (which is + // referenced from Cleaner class) until cleanup is performed. + Cleaner.create(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 { @@ -235,7 +255,6 @@ class MethodHandleNatives { return Invokers.linkToTargetMethod(type); } else { appendixResult[0] = callSite; - callSite.initContext(caller); return Invokers.linkToCallSiteMethod(type); } }