mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8234401: ConstantCallSite may stuck in non-frozen state
Reviewed-by: psandoz
This commit is contained in:
parent
d5c759accb
commit
e515a609e9
5 changed files with 94 additions and 24 deletions
|
@ -87,9 +87,10 @@ private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String nam
|
|||
abstract
|
||||
public class CallSite {
|
||||
|
||||
// The actual payload of this call site:
|
||||
// The actual payload of this call site.
|
||||
// Can be modified using {@link MethodHandleNatives#setCallSiteTargetNormal} or {@link MethodHandleNatives#setCallSiteTargetVolatile}.
|
||||
/*package-private*/
|
||||
MethodHandle target; // Note: This field is known to the JVM. Do not change.
|
||||
final MethodHandle target; // Note: This field is known to the JVM.
|
||||
|
||||
/**
|
||||
* Make a blank call site object with the given method type.
|
||||
|
@ -129,11 +130,11 @@ public class CallSite {
|
|||
*/
|
||||
/*package-private*/
|
||||
CallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
|
||||
this(targetType);
|
||||
this(targetType); // need to initialize target to make CallSite.type() work in createTargetHook
|
||||
ConstantCallSite selfCCS = (ConstantCallSite) this;
|
||||
MethodHandle boundTarget = (MethodHandle) createTargetHook.invokeWithArguments(selfCCS);
|
||||
checkTargetChange(this.target, boundTarget);
|
||||
this.target = boundTarget;
|
||||
setTargetNormal(boundTarget); // ConstantCallSite doesn't publish CallSite.target
|
||||
UNSAFE.storeStoreFence(); // barrier between target and isFrozen updates
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -190,11 +191,12 @@ public class CallSite {
|
|||
*/
|
||||
public abstract void setTarget(MethodHandle newTarget);
|
||||
|
||||
void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) {
|
||||
MethodType oldType = oldTarget.type();
|
||||
private void checkTargetChange(MethodHandle newTarget) {
|
||||
MethodType oldType = target.type(); // target is always present
|
||||
MethodType newType = newTarget.type(); // null check!
|
||||
if (!newType.equals(oldType))
|
||||
if (newType != oldType) {
|
||||
throw wrongTargetType(newTarget, oldType);
|
||||
}
|
||||
}
|
||||
|
||||
private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) {
|
||||
|
@ -217,7 +219,7 @@ public class CallSite {
|
|||
*/
|
||||
public abstract MethodHandle dynamicInvoker();
|
||||
|
||||
/*non-public*/
|
||||
/*package-private*/
|
||||
MethodHandle makeDynamicInvoker() {
|
||||
MethodHandle getTarget = getTargetHandle().bindArgumentL(0, this);
|
||||
MethodHandle invoker = MethodHandles.exactInvoker(this.type());
|
||||
|
@ -283,19 +285,24 @@ public class CallSite {
|
|||
}
|
||||
|
||||
/*package-private*/
|
||||
void setTargetNormal(MethodHandle newTarget) {
|
||||
final void setTargetNormal(MethodHandle newTarget) {
|
||||
checkTargetChange(newTarget);
|
||||
MethodHandleNatives.setCallSiteTargetNormal(this, newTarget);
|
||||
}
|
||||
|
||||
/*package-private*/
|
||||
MethodHandle getTargetVolatile() {
|
||||
final MethodHandle getTargetVolatile() {
|
||||
return (MethodHandle) UNSAFE.getReferenceVolatile(this, getTargetOffset());
|
||||
}
|
||||
|
||||
/*package-private*/
|
||||
void setTargetVolatile(MethodHandle newTarget) {
|
||||
final void setTargetVolatile(MethodHandle newTarget) {
|
||||
checkTargetChange(newTarget);
|
||||
MethodHandleNatives.setCallSiteTargetVolatile(this, newTarget);
|
||||
}
|
||||
|
||||
// this implements the upcall from the JVM, MethodHandleNatives.linkCallSite:
|
||||
/*package-private*/
|
||||
static CallSite makeSite(MethodHandle bootstrapMethod,
|
||||
// Callee information:
|
||||
String name, MethodType type,
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
|
||||
package java.lang.invoke;
|
||||
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
/**
|
||||
* A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed.
|
||||
* An {@code invokedynamic} instruction linked to a {@code ConstantCallSite} is permanently
|
||||
|
@ -33,7 +36,10 @@ package java.lang.invoke;
|
|||
* @since 1.7
|
||||
*/
|
||||
public class ConstantCallSite extends CallSite {
|
||||
private final boolean isFrozen;
|
||||
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
|
||||
@Stable // should NOT be constant folded during instance initialization (isFrozen == false)
|
||||
/*final*/ private boolean isFrozen;
|
||||
|
||||
/**
|
||||
* Creates a call site with a permanent target.
|
||||
|
@ -43,6 +49,7 @@ public class ConstantCallSite extends CallSite {
|
|||
public ConstantCallSite(MethodHandle target) {
|
||||
super(target);
|
||||
isFrozen = true;
|
||||
UNSAFE.storeStoreFence(); // properly publish isFrozen update
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,8 +86,9 @@ public class ConstantCallSite extends CallSite {
|
|||
* @throws Throwable anything else thrown by the hook function
|
||||
*/
|
||||
protected ConstantCallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
|
||||
super(targetType, createTargetHook);
|
||||
super(targetType, createTargetHook); // "this" instance leaks into createTargetHook
|
||||
isFrozen = true;
|
||||
UNSAFE.storeStoreFence(); // properly publish isFrozen
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -152,7 +152,6 @@ public class MutableCallSite extends CallSite {
|
|||
* @see #getTarget
|
||||
*/
|
||||
@Override public void setTarget(MethodHandle newTarget) {
|
||||
checkTargetChange(this.target, newTarget);
|
||||
setTargetNormal(newTarget);
|
||||
}
|
||||
|
||||
|
|
|
@ -96,7 +96,6 @@ public class VolatileCallSite extends CallSite {
|
|||
* @see #getTarget
|
||||
*/
|
||||
@Override public void setTarget(MethodHandle newTarget) {
|
||||
checkTargetChange(getTargetVolatile(), newTarget);
|
||||
setTargetVolatile(newTarget);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue