mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-26 10:10:19 +00:00
8139270: Drastically reduce memory footprint of ChainedCallSite
Reviewed-by: hannesw, sundar
This commit is contained in:
parent
53051d4e34
commit
89fa209a47
@ -85,9 +85,9 @@ package jdk.internal.dynalink;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
import jdk.internal.dynalink.support.AbstractRelinkableCallSite;
|
||||
import jdk.internal.dynalink.support.Lookup;
|
||||
@ -112,7 +112,14 @@ public class ChainedCallSite extends AbstractRelinkableCallSite {
|
||||
PRUNE_SWITCHPOINTS = MethodHandles.insertArguments(PRUNE, 2, false);
|
||||
}
|
||||
|
||||
private final AtomicReference<LinkedList<GuardedInvocation>> invocations = new AtomicReference<>();
|
||||
/**
|
||||
* Contains the invocations currently linked into this call site's target. They are used when we are
|
||||
* relinking to rebuild the guardWithTest chain. Valid values for this field are: {@code null} if there's
|
||||
* no linked invocations, or an instance of {@link GuardedInvocation} if there is exactly one previous
|
||||
* invocation, or an instance of {@code GuardedInvocation[]} if there is more than one previous
|
||||
* invocation.
|
||||
*/
|
||||
private Object invocations;
|
||||
|
||||
/**
|
||||
* Creates a new chained call site.
|
||||
@ -142,10 +149,18 @@ public class ChainedCallSite extends AbstractRelinkableCallSite {
|
||||
}
|
||||
|
||||
private MethodHandle relinkInternal(final GuardedInvocation invocation, final MethodHandle relink, final boolean reset, final boolean removeCatches) {
|
||||
final LinkedList<GuardedInvocation> currentInvocations = invocations.get();
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
final LinkedList<GuardedInvocation> newInvocations =
|
||||
currentInvocations == null || reset ? new LinkedList<>() : (LinkedList)currentInvocations.clone();
|
||||
final Object currentInvocations = invocations;
|
||||
final LinkedList<GuardedInvocation> newInvocations;
|
||||
if (currentInvocations == null || reset) {
|
||||
newInvocations = new LinkedList<>();
|
||||
} else if (currentInvocations instanceof GuardedInvocation) {
|
||||
newInvocations = new LinkedList<>();
|
||||
newInvocations.add((GuardedInvocation)currentInvocations);
|
||||
} else if (currentInvocations instanceof GuardedInvocation[]) {
|
||||
newInvocations = new LinkedList<>(Arrays.asList(((GuardedInvocation[])currentInvocations)));
|
||||
} else {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
// First, prune the chain of invalidated switchpoints, we always do this
|
||||
// We also remove any catches if the remove catches flag is set
|
||||
@ -177,12 +192,17 @@ public class ChainedCallSite extends AbstractRelinkableCallSite {
|
||||
target = inv.compose(target, pruneAndInvokeSwitchPoints, pruneAndInvokeCatches);
|
||||
}
|
||||
|
||||
// If nobody else updated the call site while we were rebuilding the chain, set the target to our chain. In case
|
||||
// we lost the race for multithreaded update, just do nothing. Either the other thread installed the same thing
|
||||
// we wanted to install, or otherwise, we'll be asked to relink again.
|
||||
if(invocations.compareAndSet(currentInvocations, newInvocations)) {
|
||||
setTarget(target);
|
||||
switch (newInvocations.size()) {
|
||||
case 0:
|
||||
invocations = null;
|
||||
break;
|
||||
case 1:
|
||||
invocations = newInvocations.getFirst();
|
||||
break;
|
||||
default:
|
||||
invocations = newInvocations.toArray(new GuardedInvocation[newInvocations.size()]);
|
||||
}
|
||||
setTarget(target);
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user