# HG changeset patch # User bharadwaj # Date 1430432101 14400 # Node ID 429945d7189cdc9e1f442612d033b0ddc8deee90 # Parent 76bb3472a9dda542c49c69820b4ec5816f6202f3# Parent bff7ca1e5d2a5265f0d83332ff22bafb9febc2ae Merge diff -r 76bb3472a9dd -r 429945d7189c jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java Mon Apr 27 09:02:48 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java Thu Apr 30 18:15:01 2015 -0400 @@ -25,9 +25,10 @@ package java.lang.invoke; -import sun.invoke.empty.Empty; 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}, @@ -136,6 +137,50 @@ } /** + * {@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. + */ + 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). + } + } + + /** * 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. * The {@code setTarget} method enforces this invariant by refusing any new target that does @@ -246,11 +291,13 @@ } // unsafe stuff: - private static final long TARGET_OFFSET; + private static final long TARGET_OFFSET; + private static final long CONTEXT_OFFSET; static { try { - TARGET_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("target")); - } catch (Exception ex) { throw new Error(ex); } + TARGET_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("target")); + CONTEXT_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("context")); + } catch (Exception ex) { throw newInternalError(ex); } } /*package-private*/ diff -r 76bb3472a9dd -r 429945d7189c jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java Mon Apr 27 09:02:48 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java Thu Apr 30 18:15:01 2015 -0400 @@ -281,7 +281,7 @@ outArgs[0] = names[CHECK_TYPE]; } if (CHECK_CUSTOM != -1) { - names[CHECK_CUSTOM] = new Name(NF_checkCustomized, names[CALL_MH]); + names[CHECK_CUSTOM] = new Name(NF_checkCustomized, outArgs[0]); } names[LINKER_CALL] = new Name(outCallType, outArgs); lform = new LambdaForm(debugName, INARG_LIMIT, names); diff -r 76bb3472a9dd -r 429945d7189c jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java Mon Apr 27 09:02:48 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java Thu Apr 30 18:15:01 2015 -0400 @@ -61,6 +61,9 @@ 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); + private static native void registerNatives(); static { registerNatives(); @@ -232,6 +235,7 @@ return Invokers.linkToTargetMethod(type); } else { appendixResult[0] = callSite; + callSite.initContext(caller); return Invokers.linkToCallSiteMethod(type); } }