--- a/nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java Tue Feb 25 18:56:10 2014 +0530
+++ b/nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java Wed Feb 26 13:17:57 2014 +0100
@@ -90,7 +90,9 @@
import java.lang.invoke.WrongMethodTypeException;
import java.util.List;
import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.support.CatchExceptionCombinator;
import jdk.internal.dynalink.support.Guards;
+import jdk.nashorn.internal.runtime.options.Options;
/**
* Represents a conditionally valid method handle. It is an immutable triple of an invocation method handle, a guard
@@ -102,11 +104,24 @@
* @author Attila Szegedi
*/
public class GuardedInvocation {
+ private static final boolean USE_FAST_REWRITE = Options.getBooleanProperty("nashorn.fastrewrite");
+
private final MethodHandle invocation;
private final MethodHandle guard;
+ private final Class<? extends Throwable> exception;
private final SwitchPoint switchPoint;
/**
+ * Creates a new guarded invocation. This invocation is unconditional as it has no invalidations.
+ *
+ * @param invocation the method handle representing the invocation. Must not be null.
+ * @throws NullPointerException if invocation is null.
+ */
+ public GuardedInvocation(MethodHandle invocation) {
+ this(invocation, null, null, null);
+ }
+
+ /**
* Creates a new guarded invocation.
*
* @param invocation the method handle representing the invocation. Must not be null.
@@ -116,7 +131,18 @@
* @throws NullPointerException if invocation is null.
*/
public GuardedInvocation(MethodHandle invocation, MethodHandle guard) {
- this(invocation, guard, null);
+ this(invocation, guard, null, null);
+ }
+
+ /**
+ * Creates a new guarded invocation.
+ *
+ * @param invocation the method handle representing the invocation. Must not be null.
+ * @param switchPoint the optional switch point that can be used to invalidate this linkage.
+ * @throws NullPointerException if invocation is null.
+ */
+ public GuardedInvocation(MethodHandle invocation, SwitchPoint switchPoint) {
+ this(invocation, null, switchPoint, null);
}
/**
@@ -130,25 +156,29 @@
* @throws NullPointerException if invocation is null.
*/
public GuardedInvocation(MethodHandle invocation, MethodHandle guard, SwitchPoint switchPoint) {
- invocation.getClass(); // NPE check
- this.invocation = invocation;
- this.guard = guard;
- this.switchPoint = switchPoint;
+ this(invocation, guard, switchPoint, null);
}
/**
* Creates a new guarded invocation.
*
* @param invocation the method handle representing the invocation. Must not be null.
- * @param switchPoint the optional switch point that can be used to invalidate this linkage.
* @param guard the method handle representing the guard. Must have the same method type as the invocation, except
* it must return boolean. For some useful guards, check out the {@link Guards} class. It can be null. If both it
* and the switch point are null, this represents an unconditional invocation, which is legal but unusual.
+ * @param switchPoint the optional switch point that can be used to invalidate this linkage.
+ * @param exception the optional exception type that is expected to be thrown by the invocation and that also
+ * invalidates the linkage.
* @throws NullPointerException if invocation is null.
*/
- public GuardedInvocation(MethodHandle invocation, SwitchPoint switchPoint, MethodHandle guard) {
- this(invocation, guard, switchPoint);
+ public GuardedInvocation(MethodHandle invocation, MethodHandle guard, SwitchPoint switchPoint, Class<? extends Throwable> exception) {
+ invocation.getClass(); // NPE check
+ this.invocation = invocation;
+ this.guard = guard;
+ this.switchPoint = switchPoint;
+ this.exception = exception;
}
+
/**
* Returns the invocation method handle.
*
@@ -177,6 +207,15 @@
}
/**
+ * Returns the exception type that if thrown should be used to invalidate the linkage.
+ *
+ * @return the exception type that if thrown should be used to invalidate the linkage. Can be null.
+ */
+ public Class<? extends Throwable> getException() {
+ return exception;
+ }
+
+ /**
* Returns true if and only if this guarded invocation has a switchpoint, and that switchpoint has been invalidated.
* @return true if and only if this guarded invocation has a switchpoint, and that switchpoint has been invalidated.
*/
@@ -206,7 +245,7 @@
* @return a new guarded invocation with the replaced methods and the same switch point as this invocation.
*/
public GuardedInvocation replaceMethods(MethodHandle newInvocation, MethodHandle newGuard) {
- return new GuardedInvocation(newInvocation, newGuard, switchPoint);
+ return new GuardedInvocation(newInvocation, newGuard, switchPoint, exception);
}
private GuardedInvocation replaceMethodsOrThis(MethodHandle newInvocation, MethodHandle newGuard) {
@@ -241,6 +280,20 @@
}
/**
+ * Changes the type of the invocation, as if {@link LinkerServices#asTypeLosslessReturn(MethodHandle, MethodType)} was
+ * applied to its invocation and {@link LinkerServices#asType(MethodHandle, MethodType)} applied to its guard, if it
+ * has one (with return type changed to boolean, and parameter count potentially truncated for the guard). If the
+ * invocation doesn't change its type, returns this object.
+ * @param linkerServices the linker services to use for the conversion
+ * @param newType the new type of the invocation.
+ * @return a guarded invocation with the new type applied to it.
+ */
+ public GuardedInvocation asTypeSafeReturn(LinkerServices linkerServices, MethodType newType) {
+ return replaceMethodsOrThis(linkerServices.asTypeLosslessReturn(invocation, newType), guard == null ? null :
+ Guards.asType(linkerServices, guard, newType));
+ }
+
+ /**
* Changes the type of the invocation, as if {@link MethodHandle#asType(MethodType)} was applied to its invocation
* and its guard, if it has one (with return type changed to boolean for guard). If the invocation already is of the
* required type, returns this object.
@@ -303,9 +356,17 @@
public MethodHandle compose(MethodHandle switchpointFallback, MethodHandle guardFallback) {
final MethodHandle guarded =
guard == null ? invocation : MethodHandles.guardWithTest(guard, invocation, guardFallback);
- return switchPoint == null ? guarded : switchPoint.guardWithTest(guarded, switchpointFallback);
+ final MethodHandle catchGuarded = exception == null ? guarded : catchException(guarded, exception,
+ MethodHandles.dropArguments(guardFallback, 0, exception));
+ return switchPoint == null ? catchGuarded : switchPoint.guardWithTest(catchGuarded, switchpointFallback);
}
+ private static MethodHandle catchException(final MethodHandle target, final Class<? extends Throwable> exType, final MethodHandle handler) {
+ if(USE_FAST_REWRITE) {
+ return CatchExceptionCombinator.catchException(target, exType, handler);
+ }
+ return MethodHandles.catchException(target, exType, handler);
+ }
private static void assertType(MethodHandle mh, MethodType type) {
if(!mh.type().equals(type)) {
throw new WrongMethodTypeException("Expected type: " + type + " actual type: " + mh.type());