Skip to content

Commit

Permalink
Force call sites to throw away their previous linkage when they becom…
Browse files Browse the repository at this point in the history
…e unstable.

Also changed the names of methods in RelinkableCallSite to be more intuitive.
  • Loading branch information
szegedi committed Nov 7, 2012
1 parent 3fe1d25 commit 567450a
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 24 deletions.
15 changes: 10 additions & 5 deletions src/main/java/org/dynalang/dynalink/ChainedCallSite.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,20 @@ protected int getMaxChainLength() {
}

@Override
public void setGuardedInvocation(GuardedInvocation invocation, MethodHandle relink) {
setGuardedInvocationInternal(invocation, relink);
public void relink(GuardedInvocation guardedInvocation, MethodHandle fallback) {
relinkInternal(guardedInvocation, fallback, false);
}

private MethodHandle setGuardedInvocationInternal(GuardedInvocation invocation, MethodHandle relink) {
@Override
public void resetAndRelink(GuardedInvocation guardedInvocation, MethodHandle fallback) {
relinkInternal(guardedInvocation, fallback, true);
}

private MethodHandle relinkInternal(GuardedInvocation invocation, MethodHandle relink, boolean reset) {
final LinkedList<GuardedInvocation> currentInvocations = invocations.get();
@SuppressWarnings({ "unchecked", "rawtypes" })
final LinkedList<GuardedInvocation> newInvocations =
currentInvocations == null ? new LinkedList<>() : (LinkedList)currentInvocations.clone();
currentInvocations == null || reset ? new LinkedList<>() : (LinkedList)currentInvocations.clone();

// First, prune the chain of invalidated switchpoints.
for(Iterator<GuardedInvocation> it = newInvocations.iterator(); it.hasNext();) {
Expand Down Expand Up @@ -105,7 +110,7 @@ private MethodHandle makePruneAndInvokeMethod(MethodHandle relink) {

@SuppressWarnings("unused")
private MethodHandle prune(MethodHandle relink) {
return setGuardedInvocationInternal(null, relink);
return relinkInternal(null, relink, false);
}

private static final MethodHandle PRUNE;
Expand Down
14 changes: 10 additions & 4 deletions src/main/java/org/dynalang/dynalink/DynamicLinker.java
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public class DynamicLinker {
* @return the callSite, for easy call chaining.
*/
public <T extends RelinkableCallSite> T link(final T callSite) {
callSite.setRelinkAndInvoke(createRelinkAndInvokeMethod(callSite, 0));
callSite.initialize(createRelinkAndInvokeMethod(callSite, 0));
return callSite;
}

Expand Down Expand Up @@ -179,9 +179,15 @@ private MethodHandle relink(RelinkableCallSite callSite, int relinkCount, Object
}
}

// Allow the call site to relink and execute its inline caching strategy.
callSite.setGuardedInvocation(guardedInvocation, createRelinkAndInvokeMethod(callSite,
!unstableDetectionEnabled || callSiteUnstable ? relinkCount : relinkCount + 1));
if(unstableDetectionEnabled && relinkCount <= unstableRelinkThreshold && relinkCount++ == unstableRelinkThreshold) {
// Note that we'll increase the relinkCount until threshold+1 and not increase it beyond that. Threshold+1
// is treated as a special value to signal that resetAndRelink has already executed once for the unstable
// call site; we only want the call site to throw away its current linkage once, when it transitions to
// unstable.
callSite.resetAndRelink(guardedInvocation, createRelinkAndInvokeMethod(callSite, relinkCount));
} else {
callSite.relink(guardedInvocation, createRelinkAndInvokeMethod(callSite, relinkCount));
}
if(syncOnRelink) {
MutableCallSite.syncAll(new MutableCallSite[] { (MutableCallSite)callSite });
}
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/org/dynalang/dynalink/MonomorphicCallSite.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ public MonomorphicCallSite(CallSiteDescriptor descriptor) {
}

@Override
public void setGuardedInvocation(GuardedInvocation guardedInvocation, MethodHandle relink) {
public void relink(GuardedInvocation guardedInvocation, MethodHandle relink) {
setTarget(guardedInvocation.compose(relink));
}

public void resetAndRelink(GuardedInvocation guardedInvocation, MethodHandle relink) {
relink(guardedInvocation, relink);
}
}
36 changes: 27 additions & 9 deletions src/main/java/org/dynalang/dynalink/RelinkableCallSite.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@
*/
public interface RelinkableCallSite {
/**
* Sets the initial target to a relink-and-invoke method.
* Initializes the relinkable call site by setting a relink-and-invoke method handle. The call site implementation
* is supposed to set this method handle as its target.
* @param relinkAndInvoke a relink-and-invoke method handle supplied by the {@link DynamicLinker}.
*/
public void setRelinkAndInvoke(MethodHandle relinkAndInvoke);
public void initialize(MethodHandle relinkAndInvoke);

/**
* Returns the descriptor for this call site.
Expand All @@ -48,16 +49,33 @@ public interface RelinkableCallSite {
public CallSiteDescriptor getDescriptor();

/**
* This method will be called once by the dynamic linker every time the call site is relinked.
* This method will be called by the dynamic linker every time the call site is normally relinked. It will be passed
* a {@code GuardedInvocation} that the call site should incorporate into its target method handle. When this method
* is called, the call site is allowed to keep other non-invalidated invocations around for implementation of
* polymorphic inline caches and compose them with this invocation to form its final target.
*
* @param guardedInvocation the guarded invocation that the call site should set as its current target. Note that
* the call sites are allowed to keep other non-invalidated invocations around for implementation of polymorphic
* inline caches.
* @param guardedInvocation the guarded invocation that the call site should incorporate into its target method
* handle.
* @param fallback the fallback method. This is a method matching the method type of the call site that is supplied
* by the {@link DynamicLinker} to be used by this call site as a fallback when it can't invoke its target with the
* passed arguments. The fallback method is such that when it's invoked, it'll try to discover the adequate target
* for the invocation, subsequently invoke {@link #setGuardedInvocation(GuardedInvocation, MethodHandle)}, and
* finally invoke the target.
* for the invocation, subsequently invoke {@link #relink(GuardedInvocation, MethodHandle)} or
* {@link #resetAndRelink(GuardedInvocation, MethodHandle)}, and finally invoke the target.
*/
public void setGuardedInvocation(GuardedInvocation guardedInvocation, MethodHandle fallback);
public void relink(GuardedInvocation guardedInvocation, MethodHandle fallback);

/**
* This method will be called by the dynamic linker every time the call site is relinked and the linker wishes the
* call site to throw away any prior linkage state. It will be passed a {@code GuardedInvocation} that the call site
* should use to build its target method handle. When this method is called, the call site is discouraged from
* keeping previous state around, and is supposed to only link the current invocation.
*
* @param guardedInvocation the guarded invocation that the call site should use to build its target method handle.
* @param fallback the fallback method. This is a method matching the method type of the call site that is supplied
* by the {@link DynamicLinker} to be used by this call site as a fallback when it can't invoke its target with the
* passed arguments. The fallback method is such that when it's invoked, it'll try to discover the adequate target
* for the invocation, subsequently invoke {@link #relink(GuardedInvocation, MethodHandle)} or
* {@link #resetAndRelink(GuardedInvocation, MethodHandle)}, and finally invoke the target.
*/
public void resetAndRelink(GuardedInvocation guardedInvocation, MethodHandle fallback);
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public CallSiteDescriptor getDescriptor() {
}

@Override
public void setRelinkAndInvoke(MethodHandle relinkAndInvoke) {
public void initialize(MethodHandle relinkAndInvoke) {
setTarget(relinkAndInvoke);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class TestMonomorphicCallSite extends TestCase {
*/
public static void testSetNull() {
try {
createCallSite(MethodType.methodType(Void.TYPE)).setGuardedInvocation(null, null);
createCallSite(MethodType.methodType(Void.TYPE)).relink(null, null);
fail();
} catch(NullPointerException e) {
// This is expected
Expand All @@ -53,7 +53,7 @@ public static void testSetNull() {
public static void testSetGuardless() {
final MethodHandle mh = MethodHandles.identity(Object.class);
final MonomorphicCallSite mcs = createCallSite(mh.type());
mcs.setGuardedInvocation(new GuardedInvocation(mh, null), null);
mcs.relink(new GuardedInvocation(mh, null), null);
assertSame(mh, mcs.getTarget());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ public RelinkCountingCallSite(String name, MethodType type) {
}

@Override
public void setGuardedInvocation(GuardedInvocation guardedInvocation, MethodHandle relink) {
super.setGuardedInvocation(guardedInvocation, relink);
public void relink(GuardedInvocation guardedInvocation, MethodHandle relink) {
super.relink(guardedInvocation, relink);
++relinkCount;
}

Expand Down

0 comments on commit 567450a

Please sign in to comment.