Merge
This commit is contained in:
commit
0f8bafe829
@ -36,9 +36,7 @@ AUTO_FILES_JAVA_DIRS = java/dyn sun/dyn
|
|||||||
LANGUAGE_VERSION = -source 7
|
LANGUAGE_VERSION = -source 7
|
||||||
CLASS_VERSION = -target 7
|
CLASS_VERSION = -target 7
|
||||||
|
|
||||||
# Actually, it will be less disruptive to compile with the same
|
# Tell the compiler not to accept transitional forms.
|
||||||
# -target option as the rest of the system, and just turn on
|
OTHER_JAVACFLAGS = -XDallowTransitionalJSR292=no
|
||||||
# the specific compiler option we need here:
|
|
||||||
OTHER_JAVACFLAGS = -XDinvokedynamic
|
|
||||||
|
|
||||||
include $(BUILDDIR)/common/Classes.gmk
|
include $(BUILDDIR)/common/Classes.gmk
|
||||||
|
@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package java.dyn;
|
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Annotation on InvokeDynamic method calls which requests the JVM to use a specific
|
|
||||||
* <a href="package-summary.html#bsm">bootstrap method</a>
|
|
||||||
* to link the call. This annotation is not retained as such in the class file,
|
|
||||||
* but is transformed into a constant-pool entry for the invokedynamic instruction which
|
|
||||||
* specifies the desired bootstrap method.
|
|
||||||
* <p>
|
|
||||||
* If only the <code>value</code> is given, it must name a subclass of {@link CallSite}
|
|
||||||
* with a constructor which accepts a class, string, and method type.
|
|
||||||
* If the <code>value</code> and <code>name</code> are both given, there must be
|
|
||||||
* a static method in the given class of the given name which accepts a class, string,
|
|
||||||
* and method type, and returns a reference coercible to {@link CallSite}.
|
|
||||||
* <p>
|
|
||||||
* This annotation can be placed either on the return type of a single {@link InvokeDynamic}
|
|
||||||
* call (see examples) or else it can be placed on an enclosing class or method, where it
|
|
||||||
* determines a default bootstrap method for any {@link InvokeDynamic} calls which are not
|
|
||||||
* specifically annotated with a bootstrap method.
|
|
||||||
* Every {@link InvokeDynamic} call must be given a bootstrap method.
|
|
||||||
* <p>
|
|
||||||
* Examples:
|
|
||||||
<blockquote><pre>
|
|
||||||
@BootstrapMethod(value=MyLanguageRuntime.class, name="bootstrapDynamic")
|
|
||||||
String x = (String) InvokeDynamic.greet();
|
|
||||||
//BSM => MyLanguageRuntime.bootstrapDynamic(Here.class, "greet", methodType(String.class))
|
|
||||||
@BootstrapMethod(MyCallSite.class)
|
|
||||||
void example() throws Throwable {
|
|
||||||
InvokeDynamic.greet();
|
|
||||||
//BSM => new MyCallSite(Here.class, "greet", methodType(void.class))
|
|
||||||
}
|
|
||||||
</pre></blockquote>
|
|
||||||
* <p>
|
|
||||||
*/
|
|
||||||
@Target({ElementType.TYPE_USE,
|
|
||||||
// For defaulting every indy site within a class or method; cf. @SuppressWarnings:
|
|
||||||
ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR
|
|
||||||
})
|
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
|
||||||
public @interface BootstrapMethod {
|
|
||||||
/** The class containing the bootstrap method. */
|
|
||||||
Class<?> value();
|
|
||||||
|
|
||||||
/** The name of the bootstrap method.
|
|
||||||
* If this is the empty string, an instance of the bootstrap class is created,
|
|
||||||
* and a constructor is invoked.
|
|
||||||
* Otherwise, there must be a static method of the required name.
|
|
||||||
*/
|
|
||||||
String name() default ""; // empty string denotes a constructor with 'new'
|
|
||||||
|
|
||||||
/** The argument types of the bootstrap method, as passed out by the JVM.
|
|
||||||
* There is usually no reason to override the default.
|
|
||||||
*/
|
|
||||||
Class<?>[] arguments() default {Class.class, String.class, MethodType.class};
|
|
||||||
}
|
|
@ -26,40 +26,45 @@
|
|||||||
package java.dyn;
|
package java.dyn;
|
||||||
|
|
||||||
import sun.dyn.*;
|
import sun.dyn.*;
|
||||||
|
import sun.dyn.empty.Empty;
|
||||||
|
import sun.misc.Unsafe;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@code CallSite} is a holder for a variable {@link MethodHandle},
|
* A {@code CallSite} is a holder for a variable {@link MethodHandle},
|
||||||
* which is called its {@code target}.
|
* which is called its {@code target}.
|
||||||
* Every call to a {@code CallSite} is delegated to the site's current target.
|
* An {@code invokedynamic} instruction linked to a {@code CallSite} delegates
|
||||||
|
* all calls to the site's current target.
|
||||||
|
* A {@code CallSite} may be associated with several {@code invokedynamic}
|
||||||
|
* instructions, or it may be "free floating", associated with none.
|
||||||
|
* In any case, it may be invoked through an associated method handle
|
||||||
|
* called its {@linkplain #dynamicInvoker dynamic invoker}.
|
||||||
* <p>
|
* <p>
|
||||||
* A call site is initially created in an <em>unlinked</em> state,
|
* {@code CallSite} is an abstract class which does not allow
|
||||||
* which is distinguished by a null target variable.
|
* direct subclassing by users. It has three immediate,
|
||||||
* Before the call site may be invoked (and before certain other
|
* concrete subclasses that may be either instantiated or subclassed.
|
||||||
* operations are attempted), the call site must be linked to
|
* <ul>
|
||||||
* a non-null target.
|
* <li>If a mutable target is not required, an {@code invokedynamic} instruction
|
||||||
|
* may be permanently bound by means of a {@linkplain ConstantCallSite constant call site}.
|
||||||
|
* <li>If a mutable target is required which has volatile variable semantics,
|
||||||
|
* because updates to the target must be immediately and reliably witnessed by other threads,
|
||||||
|
* a {@linkplain VolatileCallSite volatile call site} may be used.
|
||||||
|
* <li>Otherwise, if a mutable target is required,
|
||||||
|
* a {@linkplain MutableCallSite mutable call site} may be used.
|
||||||
|
* </ul>
|
||||||
* <p>
|
* <p>
|
||||||
* A call site may be <em>relinked</em> by changing its target.
|
* A non-constant call site may be <em>relinked</em> by changing its target.
|
||||||
* The new target must be non-null and must have the same
|
* The new target must have the same {@linkplain MethodHandle#type() type}
|
||||||
* {@linkplain MethodHandle#type() type}
|
|
||||||
* as the previous target.
|
* as the previous target.
|
||||||
* Thus, though a call site can be relinked to a series of
|
* Thus, though a call site can be relinked to a series of
|
||||||
* successive targets, it cannot change its type.
|
* successive targets, it cannot change its type.
|
||||||
* <p>
|
* <p>
|
||||||
* Linkage happens once in the lifetime of any given {@code CallSite} object.
|
|
||||||
* Because of call site invalidation, this linkage can be repeated for
|
|
||||||
* a single {@code invokedynamic} instruction, with multiple {@code CallSite} objects.
|
|
||||||
* When a {@code CallSite} is unlinked from an {@code invokedynamic} instruction,
|
|
||||||
* the instruction is reset so that it is no longer associated with
|
|
||||||
* the {@code CallSite} object, but the {@code CallSite} does not change
|
|
||||||
* state.
|
|
||||||
* <p>
|
|
||||||
* Here is a sample use of call sites and bootstrap methods which links every
|
* Here is a sample use of call sites and bootstrap methods which links every
|
||||||
* dynamic call site to print its arguments:
|
* dynamic call site to print its arguments:
|
||||||
<blockquote><pre><!-- see indy-demo/src/PrintArgsDemo.java -->
|
<blockquote><pre><!-- see indy-demo/src/PrintArgsDemo.java -->
|
||||||
@BootstrapMethod(value=PrintArgsDemo.class, name="bootstrapDynamic")
|
|
||||||
static void test() throws Throwable {
|
static void test() throws Throwable {
|
||||||
InvokeDynamic.baz("baz arg", 2, 3.14);
|
// THE FOLLOWING LINE IS PSEUDOCODE FOR A JVM INSTRUCTION
|
||||||
|
InvokeDynamic[#bootstrapDynamic].baz("baz arg", 2, 3.14);
|
||||||
}
|
}
|
||||||
private static void printArgs(Object... args) {
|
private static void printArgs(Object... args) {
|
||||||
System.out.println(java.util.Arrays.deepToString(args));
|
System.out.println(java.util.Arrays.deepToString(args));
|
||||||
@ -71,16 +76,15 @@ static {
|
|||||||
printArgs = lookup.findStatic(thisClass,
|
printArgs = lookup.findStatic(thisClass,
|
||||||
"printArgs", MethodType.methodType(void.class, Object[].class));
|
"printArgs", MethodType.methodType(void.class, Object[].class));
|
||||||
}
|
}
|
||||||
private static CallSite bootstrapDynamic(Class caller, String name, MethodType type) {
|
private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) {
|
||||||
// ignore caller and name, but match the type:
|
// ignore caller and name, but match the type:
|
||||||
return new CallSite(MethodHandles.collectArguments(printArgs, type));
|
return new ConstantCallSite(MethodHandles.collectArguments(printArgs, type));
|
||||||
}
|
}
|
||||||
</pre></blockquote>
|
</pre></blockquote>
|
||||||
* @author John Rose, JSR 292 EG
|
* @author John Rose, JSR 292 EG
|
||||||
*/
|
*/
|
||||||
public class CallSite
|
abstract
|
||||||
implements MethodHandleProvider
|
public class CallSite {
|
||||||
{
|
|
||||||
private static final Access IMPL_TOKEN = Access.getToken();
|
private static final Access IMPL_TOKEN = Access.getToken();
|
||||||
|
|
||||||
// Fields used only by the JVM. Do not use or change.
|
// Fields used only by the JVM. Do not use or change.
|
||||||
@ -88,61 +92,47 @@ public class CallSite
|
|||||||
private int vmindex; // supplied by the JVM (BCI within calling method)
|
private int vmindex; // supplied by the JVM (BCI within calling method)
|
||||||
|
|
||||||
// The actual payload of this call site:
|
// The actual payload of this call site:
|
||||||
private MethodHandle target;
|
/*package-private*/
|
||||||
|
MethodHandle target;
|
||||||
|
|
||||||
// Remove this field for PFD and delete deprecated methods:
|
// Remove this field for PFD and delete deprecated methods:
|
||||||
private MemberName calleeNameRemoveForPFD;
|
private MemberName calleeNameRemoveForPFD;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a blank call site object.
|
* Make a blank call site object with the given method type.
|
||||||
* Before it is returned from a bootstrap method, this {@code CallSite} object
|
* An initial target method is supplied which will throw
|
||||||
* must be provided with
|
* an {@link IllegalStateException} if called.
|
||||||
* a target method via a call to {@link CallSite#setTarget(MethodHandle) setTarget},
|
* <p>
|
||||||
* or by a subclass override of {@link CallSite#initialTarget(Class,String,MethodType) initialTarget}.
|
* Before this {@code CallSite} object is returned from a bootstrap method,
|
||||||
|
* it is usually provided with a more useful target method,
|
||||||
|
* via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
|
||||||
|
* @throws NullPointerException if the proposed type is null
|
||||||
*/
|
*/
|
||||||
public CallSite() {
|
/*package-private*/
|
||||||
|
CallSite(MethodType type) {
|
||||||
|
target = MethodHandles.invokers(type).uninitializedCallSite();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a blank call site object, possibly equipped with an initial target method handle.
|
* Make a blank call site object, possibly equipped with an initial target method handle.
|
||||||
* The initial target reference may be null, in which case the {@code CallSite} object
|
* @param target the method handle which will be the initial target of the call site
|
||||||
* must be provided with a target method via a call to {@link CallSite#setTarget},
|
* @throws NullPointerException if the proposed target is null
|
||||||
* or by a subclass override of {@link CallSite#initialTarget}.
|
|
||||||
* @param target the method handle which will be the initial target of the call site, or null if there is none yet
|
|
||||||
*/
|
*/
|
||||||
public CallSite(MethodHandle target) {
|
/*package-private*/
|
||||||
|
CallSite(MethodHandle target) {
|
||||||
|
target.type(); // null check
|
||||||
this.target = target;
|
this.target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @deprecated transitional form defined in EDR but removed in PFD */
|
/**
|
||||||
public CallSite(Class<?> caller, String name, MethodType type) {
|
* Report the type of this call site's target.
|
||||||
this.calleeNameRemoveForPFD = new MemberName(caller, name, type);
|
* Although targets may change, the call site's type can never change.
|
||||||
}
|
* The {@code setTarget} method enforces this invariant by refusing any new target that does
|
||||||
/** @deprecated transitional form defined in EDR but removed in PFD */
|
* not have the previous target's type.
|
||||||
public Class<?> callerClass() {
|
* @return the type of the current target, which is also the type of any future target
|
||||||
MemberName callee = this.calleeNameRemoveForPFD;
|
|
||||||
return callee == null ? null : callee.getDeclaringClass();
|
|
||||||
}
|
|
||||||
/** @deprecated transitional form defined in EDR but removed in PFD */
|
|
||||||
public String name() {
|
|
||||||
MemberName callee = this.calleeNameRemoveForPFD;
|
|
||||||
return callee == null ? null : callee.getName();
|
|
||||||
}
|
|
||||||
/** @deprecated transitional form defined in EDR but removed in PFD */
|
|
||||||
public MethodType type() {
|
|
||||||
MemberName callee = this.calleeNameRemoveForPFD;
|
|
||||||
return callee == null ? (target == null ? null : target.type()) : callee.getMethodType();
|
|
||||||
}
|
|
||||||
/** @deprecated transitional form defined in EDR but removed in PFD */
|
|
||||||
protected MethodHandle initialTarget() {
|
|
||||||
return initialTarget(callerClass(), name(), type());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Report if the JVM has linked this {@code CallSite} object to a dynamic call site instruction.
|
|
||||||
* Once it is linked, it is never unlinked.
|
|
||||||
*/
|
*/
|
||||||
private boolean isLinked() {
|
public MethodType type() {
|
||||||
return vmmethod != null;
|
return target.type();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called from JVM (or low-level Java code) after the BSM returns the newly created CallSite.
|
/** Called from JVM (or low-level Java code) after the BSM returns the newly created CallSite.
|
||||||
@ -152,68 +142,66 @@ public class CallSite
|
|||||||
MethodType type,
|
MethodType type,
|
||||||
MemberName callerMethod,
|
MemberName callerMethod,
|
||||||
int callerBCI) {
|
int callerBCI) {
|
||||||
if (this.isLinked()) {
|
if (this.vmmethod != null) {
|
||||||
|
// FIXME
|
||||||
throw new InvokeDynamicBootstrapError("call site has already been linked to an invokedynamic instruction");
|
throw new InvokeDynamicBootstrapError("call site has already been linked to an invokedynamic instruction");
|
||||||
}
|
}
|
||||||
MethodHandle target = this.target;
|
if (!this.type().equals(type)) {
|
||||||
if (target == null) {
|
|
||||||
this.target = target = this.initialTarget(callerMethod.getDeclaringClass(), name, type);
|
|
||||||
}
|
|
||||||
if (!target.type().equals(type)) {
|
|
||||||
throw wrongTargetType(target, type);
|
throw wrongTargetType(target, type);
|
||||||
}
|
}
|
||||||
this.vmindex = callerBCI;
|
this.vmindex = callerBCI;
|
||||||
this.vmmethod = callerMethod;
|
this.vmmethod = callerMethod;
|
||||||
assert(this.isLinked());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Just after a call site is created by a bootstrap method handle,
|
* Report the current linkage state of the call site, a value which may change over time.
|
||||||
* if the target has not been initialized by the factory method itself,
|
|
||||||
* the method {@code initialTarget} is called to produce an initial
|
|
||||||
* non-null target. (Live call sites must never have null targets.)
|
|
||||||
* <p>
|
* <p>
|
||||||
* The arguments are the same as those passed to the bootstrap method.
|
* If a {@code CallSite} object is returned
|
||||||
* Thus, a bootstrap method is free to ignore the arguments and simply
|
* from the bootstrap method of the {@code invokedynamic} instruction,
|
||||||
* create a "blank" {@code CallSite} object of an appropriate subclass.
|
* the {@code CallSite} is permanently bound to that instruction.
|
||||||
|
* When the {@code invokedynamic} instruction is executed, the target method
|
||||||
|
* of its associated call site object is invoked directly.
|
||||||
|
* It is as if the instruction calls {@code getTarget} and then
|
||||||
|
* calls {@link MethodHandle#invokeExact invokeExact} on the result.
|
||||||
* <p>
|
* <p>
|
||||||
* If the bootstrap method itself does not initialize the call site,
|
* Unless specified differently by a subclass,
|
||||||
* this method must be overridden, because it just raises an
|
* the interactions of {@code getTarget} with memory are the same
|
||||||
* {@code InvokeDynamicBootstrapError}, which in turn causes the
|
|
||||||
* linkage of the {@code invokedynamic} instruction to terminate
|
|
||||||
* abnormally.
|
|
||||||
* @deprecated transitional form defined in EDR but removed in PFD
|
|
||||||
*/
|
|
||||||
protected MethodHandle initialTarget(Class<?> callerClass, String name, MethodType type) {
|
|
||||||
throw new InvokeDynamicBootstrapError("target must be initialized before call site is linked: "+name+type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Report the current linkage state of the call site. (This is mutable.)
|
|
||||||
* The value may not be null after the {@code CallSite} object is returned
|
|
||||||
* from the bootstrap method of the {@code invokedynamic} instruction.
|
|
||||||
* When an {@code invokedynamic} instruction is executed, the target method
|
|
||||||
* of its associated {@code call site} object is invoked directly,
|
|
||||||
* as if via {@link MethodHandle}{@code .invoke}.
|
|
||||||
* <p>
|
|
||||||
* The interactions of {@code getTarget} with memory are the same
|
|
||||||
* as of a read from an ordinary variable, such as an array element or a
|
* as of a read from an ordinary variable, such as an array element or a
|
||||||
* non-volatile, non-final field.
|
* non-volatile, non-final field.
|
||||||
* <p>
|
* <p>
|
||||||
* In particular, the current thread may choose to reuse the result
|
* In particular, the current thread may choose to reuse the result
|
||||||
* of a previous read of the target from memory, and may fail to see
|
* of a previous read of the target from memory, and may fail to see
|
||||||
* a recent update to the target by another thread.
|
* a recent update to the target by another thread.
|
||||||
* @return the current linkage state of the call site
|
* <p>
|
||||||
|
* In a {@linkplain ConstantCallSite constant call site}, the {@code getTarget} method behaves
|
||||||
|
* like a read from a {@code final} field of the {@code CallSite}.
|
||||||
|
* <p>
|
||||||
|
* In a {@linkplain VolatileCallSite volatile call site}, the {@code getTarget} method behaves
|
||||||
|
* like a read from a {@code volatile} field of the {@code CallSite}.
|
||||||
|
* <p>
|
||||||
|
* This method may not be overridden by application code.
|
||||||
|
* @return the current linkage state of the call site, its target method handle
|
||||||
|
* @see ConstantCallSite
|
||||||
|
* @see VolatileCallSite
|
||||||
* @see #setTarget
|
* @see #setTarget
|
||||||
*/
|
*/
|
||||||
public MethodHandle getTarget() {
|
public final MethodHandle getTarget() {
|
||||||
|
return getTarget0();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privileged implementations can override this to force final or volatile semantics on getTarget.
|
||||||
|
*/
|
||||||
|
/*package-private*/
|
||||||
|
MethodHandle getTarget0() {
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the target method of this call site.
|
* Set the target method of this call site.
|
||||||
* <p>
|
* <p>
|
||||||
* The interactions of {@code setTarget} with memory are the same
|
* Unless a subclass of CallSite documents otherwise,
|
||||||
|
* the interactions of {@code setTarget} with memory are the same
|
||||||
* as of a write to an ordinary variable, such as an array element or a
|
* as of a write to an ordinary variable, such as an array element or a
|
||||||
* non-volatile, non-final field.
|
* non-volatile, non-final field.
|
||||||
* <p>
|
* <p>
|
||||||
@ -224,43 +212,32 @@ public class CallSite
|
|||||||
* at any given call site.
|
* at any given call site.
|
||||||
* @param newTarget the new target
|
* @param newTarget the new target
|
||||||
* @throws NullPointerException if the proposed new target is null
|
* @throws NullPointerException if the proposed new target is null
|
||||||
* @throws WrongMethodTypeException if the call site is linked and the proposed new target
|
* @throws WrongMethodTypeException if the proposed new target
|
||||||
* has a method type that differs from the previous target
|
* has a method type that differs from the previous target
|
||||||
|
* @throws UnsupportedOperationException if the call site is
|
||||||
|
* in fact a {@link ConstantCallSite}
|
||||||
*/
|
*/
|
||||||
public void setTarget(MethodHandle newTarget) {
|
public void setTarget(MethodHandle newTarget) {
|
||||||
MethodType newType = newTarget.type(); // null check!
|
checkTargetChange(this.target, newTarget);
|
||||||
MethodHandle oldTarget = this.target;
|
setTargetNormal(newTarget);
|
||||||
if (oldTarget == null) {
|
}
|
||||||
// CallSite is not yet linked.
|
|
||||||
assert(!isLinked());
|
void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) {
|
||||||
this.target = newTarget; // might be null!
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MethodType oldType = oldTarget.type();
|
MethodType oldType = oldTarget.type();
|
||||||
if (!newTarget.type().equals(oldType))
|
MethodType newType = newTarget.type(); // null check!
|
||||||
|
if (!newType.equals(oldType))
|
||||||
throw wrongTargetType(newTarget, oldType);
|
throw wrongTargetType(newTarget, oldType);
|
||||||
if (oldTarget != newTarget)
|
|
||||||
CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) {
|
private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) {
|
||||||
return new WrongMethodTypeException(String.valueOf(target)+target.type()+" should be of type "+type);
|
return new WrongMethodTypeException(String.valueOf(target)+" should be of type "+type);
|
||||||
}
|
|
||||||
|
|
||||||
/** Produce a printed representation that displays information about this call site
|
|
||||||
* that may be useful to the human reader.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "CallSite"+(target == null ? "" : target.type());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
|
||||||
* Produce a method handle equivalent to an invokedynamic instruction
|
* Produce a method handle equivalent to an invokedynamic instruction
|
||||||
* which has been linked to this call site.
|
* which has been linked to this call site.
|
||||||
* <p>If this call site is a {@link ConstantCallSite}, this method
|
* <p>If this call site is a {@linkplain ConstantCallSite constant call site},
|
||||||
* simply returns the call site's target, since that will not change.
|
* this method simply returns the call site's target, since that will never change.
|
||||||
* <p>Otherwise, this method is equivalent to the following code:
|
* <p>Otherwise, this method is equivalent to the following code:
|
||||||
* <p><blockquote><pre>
|
* <p><blockquote><pre>
|
||||||
* MethodHandle getTarget, invoker, result;
|
* MethodHandle getTarget, invoker, result;
|
||||||
@ -271,8 +248,9 @@ public class CallSite
|
|||||||
* @return a method handle which always invokes this call site's current target
|
* @return a method handle which always invokes this call site's current target
|
||||||
*/
|
*/
|
||||||
public final MethodHandle dynamicInvoker() {
|
public final MethodHandle dynamicInvoker() {
|
||||||
if (this instanceof ConstantCallSite)
|
if (this instanceof ConstantCallSite) {
|
||||||
return getTarget(); // will not change dynamically
|
return getTarget0(); // will not change dynamically
|
||||||
|
}
|
||||||
MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, GET_TARGET, this);
|
MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, GET_TARGET, this);
|
||||||
MethodHandle invoker = MethodHandles.exactInvoker(this.type());
|
MethodHandle invoker = MethodHandles.exactInvoker(this.type());
|
||||||
return MethodHandles.foldArguments(invoker, getTarget);
|
return MethodHandles.foldArguments(invoker, getTarget);
|
||||||
@ -287,9 +265,34 @@ public class CallSite
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Implementation of {@link MethodHandleProvider} which returns {@code this.dynamicInvoker()}. */
|
/** This guy is rolled into the default target if a MethodType is supplied to the constructor. */
|
||||||
public final MethodHandle asMethodHandle() { return dynamicInvoker(); }
|
/*package-private*/
|
||||||
|
static Empty uninitializedCallSite() {
|
||||||
|
throw new IllegalStateException("uninitialized call site");
|
||||||
|
}
|
||||||
|
|
||||||
/** Implementation of {@link MethodHandleProvider}, which returns {@code this.dynamicInvoker().asType(type)}. */
|
// unsafe stuff:
|
||||||
public final MethodHandle asMethodHandle(MethodType type) { return dynamicInvoker().asType(type); }
|
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||||
|
private static final long TARGET_OFFSET;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
TARGET_OFFSET = unsafe.objectFieldOffset(CallSite.class.getDeclaredField("target"));
|
||||||
|
} catch (Exception ex) { throw new Error(ex); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package-private*/
|
||||||
|
void setTargetNormal(MethodHandle newTarget) {
|
||||||
|
target = newTarget;
|
||||||
|
//CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget);
|
||||||
|
}
|
||||||
|
/*package-private*/
|
||||||
|
MethodHandle getTargetVolatile() {
|
||||||
|
return (MethodHandle) unsafe.getObjectVolatile(this, TARGET_OFFSET);
|
||||||
|
}
|
||||||
|
/*package-private*/
|
||||||
|
void setTargetVolatile(MethodHandle newTarget) {
|
||||||
|
unsafe.putObjectVolatile(this, TARGET_OFFSET, newTarget);
|
||||||
|
//CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,44 +28,78 @@ package java.dyn;
|
|||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.lang.reflect.UndeclaredThrowableException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lazily associate a computed value with (potentially) every class.
|
* Lazily associate a computed value with (potentially) every class.
|
||||||
* @author John Rose, JSR 292 EG
|
* @author John Rose, JSR 292 EG
|
||||||
*/
|
*/
|
||||||
public abstract class ClassValue<T> {
|
public class ClassValue<T> {
|
||||||
/**
|
/**
|
||||||
* Compute the given class's derived value for this {@code ClassValue}.
|
* Compute the given class's derived value for this {@code ClassValue}.
|
||||||
* <p>
|
* <p>
|
||||||
* This method will be invoked within the first thread that accesses
|
* This method will be invoked within the first thread that accesses
|
||||||
* the value with the {@link #get}.
|
* the value with the {@link #get get} method.
|
||||||
* <p>
|
* <p>
|
||||||
* Normally, this method is invoked at most once per class,
|
* Normally, this method is invoked at most once per class,
|
||||||
* but it may be invoked again in case of subsequent invocations
|
* but it may be invoked again if there has been a call to
|
||||||
* of {@link #remove} followed by {@link #get}.
|
* {@link #remove remove}.
|
||||||
|
* <p>
|
||||||
|
* If there is no override from a subclass, this method returns
|
||||||
|
* the result of applying the {@code ClassValue}'s {@code computeValue}
|
||||||
|
* method handle, which was supplied at construction time.
|
||||||
*
|
*
|
||||||
* @return the computed value for this thread-local
|
* @return the newly computed value associated with this {@code ClassValue}, for the given class or interface
|
||||||
|
* @throws UndeclaredThrowableException if the {@code computeValue} method handle invocation throws something other than a {@code RuntimeException} or {@code Error}
|
||||||
|
* @throws UnsupportedOperationException if the {@code computeValue} method handle is null (subclasses must override)
|
||||||
*/
|
*/
|
||||||
protected abstract T computeValue(Class<?> type);
|
protected T computeValue(Class<?> type) {
|
||||||
|
if (computeValue == null)
|
||||||
|
return null;
|
||||||
|
try {
|
||||||
|
return (T) (Object) computeValue.invokeGeneric(type);
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
if (ex instanceof Error) throw (Error) ex;
|
||||||
|
if (ex instanceof RuntimeException) throw (RuntimeException) ex;
|
||||||
|
throw new UndeclaredThrowableException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final MethodHandle computeValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new class value.
|
* Creates a new class value.
|
||||||
|
* Subclasses which use this constructor must override
|
||||||
|
* the {@link #computeValue computeValue} method,
|
||||||
|
* since the default {@code computeValue} method requires a method handle,
|
||||||
|
* which this constructor does not provide.
|
||||||
*/
|
*/
|
||||||
protected ClassValue() {
|
protected ClassValue() {
|
||||||
|
this.computeValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new class value, whose {@link #computeValue computeValue} method
|
||||||
|
* will return the result of {@code computeValue.invokeGeneric(type)}.
|
||||||
|
* @throws NullPointerException if the method handle parameter is null
|
||||||
|
*/
|
||||||
|
public ClassValue(MethodHandle computeValue) {
|
||||||
|
computeValue.getClass(); // trigger NPE if null
|
||||||
|
this.computeValue = computeValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value for the given class.
|
* Returns the value for the given class.
|
||||||
* If no value has yet been computed, it is obtained by
|
* If no value has yet been computed, it is obtained by
|
||||||
* by an invocation of the {@link #computeValue} method.
|
* by an invocation of the {@link #computeValue computeValue} method.
|
||||||
* <p>
|
* <p>
|
||||||
* The actual installation of the value on the class
|
* The actual installation of the value on the class
|
||||||
* is performed while the class's synchronization lock
|
* is performed atomically.
|
||||||
* is held. At that point, if racing threads have
|
* At that point, if racing threads have
|
||||||
* computed values, one is chosen, and returned to
|
* computed values, one is chosen, and returned to
|
||||||
* all the racing threads.
|
* all the racing threads.
|
||||||
*
|
*
|
||||||
* @return the current thread's value of this thread-local
|
* @return the current value associated with this {@code ClassValue}, for the given class or interface
|
||||||
*/
|
*/
|
||||||
public T get(Class<?> type) {
|
public T get(Class<?> type) {
|
||||||
ClassValueMap map = getMap(type);
|
ClassValueMap map = getMap(type);
|
||||||
@ -81,9 +115,16 @@ public abstract class ClassValue<T> {
|
|||||||
/**
|
/**
|
||||||
* Removes the associated value for the given class.
|
* Removes the associated value for the given class.
|
||||||
* If this value is subsequently {@linkplain #get read} for the same class,
|
* If this value is subsequently {@linkplain #get read} for the same class,
|
||||||
* its value will be reinitialized by invoking its {@link #computeValue} method.
|
* its value will be reinitialized by invoking its {@link #computeValue computeValue} method.
|
||||||
* This may result in an additional invocation of the
|
* This may result in an additional invocation of the
|
||||||
* {@code computeValue} method for the given class.
|
* {@code computeValue computeValue} method for the given class.
|
||||||
|
* <p>
|
||||||
|
* If racing threads perform a combination of {@code get} and {@code remove} calls,
|
||||||
|
* the calls are serialized.
|
||||||
|
* A value produced by a call to {@code computeValue} will be discarded, if
|
||||||
|
* the corresponding {@code get} call was followed by a {@code remove} call
|
||||||
|
* before the {@code computeValue} could complete.
|
||||||
|
* In such a case, the {@code get} call will re-invoke {@code computeValue}.
|
||||||
*/
|
*/
|
||||||
public void remove(Class<?> type) {
|
public void remove(Class<?> type) {
|
||||||
ClassValueMap map = getMap(type);
|
ClassValueMap map = getMap(type);
|
||||||
@ -118,6 +159,7 @@ public abstract class ClassValue<T> {
|
|||||||
// Warm up the table with a null entry.
|
// Warm up the table with a null entry.
|
||||||
map.preInitializeEntry(this);
|
map.preInitializeEntry(this);
|
||||||
}
|
}
|
||||||
|
STORE_BARRIER.lazySet(0);
|
||||||
// All stores pending from table expansion are completed.
|
// All stores pending from table expansion are completed.
|
||||||
synchronized (map) {
|
synchronized (map) {
|
||||||
value = (T) map.initializeEntry(this, value);
|
value = (T) map.initializeEntry(this, value);
|
||||||
|
@ -27,17 +27,21 @@ package java.dyn;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed.
|
* A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed.
|
||||||
* The only way to relink an {@code invokedynamic} instruction bound to a {@code ConstantCallSite} is
|
* An {@code invokedynamic} instruction linked to a {@code ConstantCallSite} is permanently
|
||||||
* to invalidate the instruction as a whole.
|
* bound to the call site's target.
|
||||||
* @author John Rose, JSR 292 EG
|
* @author John Rose, JSR 292 EG
|
||||||
*/
|
*/
|
||||||
public class ConstantCallSite extends CallSite {
|
public class ConstantCallSite extends CallSite {
|
||||||
/** Create a call site with a permanent target. */
|
/** Create a call site with a permanent target.
|
||||||
|
* @throws NullPointerException if the proposed target is null
|
||||||
|
*/
|
||||||
public ConstantCallSite(MethodHandle target) {
|
public ConstantCallSite(MethodHandle target) {
|
||||||
super(target);
|
super(target);
|
||||||
}
|
}
|
||||||
/** Throw an {@link IllegalArgumentException}, because this kind of call site cannot change its target. */
|
/**
|
||||||
|
* Throw an {@link UnsupportedOperationException}, because this kind of call site cannot change its target.
|
||||||
|
*/
|
||||||
@Override public final void setTarget(MethodHandle ignore) {
|
@Override public final void setTarget(MethodHandle ignore) {
|
||||||
throw new IllegalArgumentException("ConstantCallSite");
|
throw new UnsupportedOperationException("ConstantCallSite");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -26,55 +26,8 @@
|
|||||||
package java.dyn;
|
package java.dyn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code InvokeDynamic} is a class with neither methods nor instances,
|
* This is a place-holder class. Some HotSpot implementations need to see it.
|
||||||
* which serves only as a syntactic marker in Java source code for
|
|
||||||
* an {@code invokedynamic} instruction.
|
|
||||||
* (See <a href="package-summary.html#jvm_mods">the package information</a> for specifics on this instruction.)
|
|
||||||
* <p>
|
|
||||||
* The {@code invokedynamic} instruction is incomplete without a target method.
|
|
||||||
* The target method is a property of the reified {@linkplain CallSite call site object}
|
|
||||||
* which is linked to each active {@code invokedynamic} instruction.
|
|
||||||
* The call site object is initially produced by a
|
|
||||||
* {@linkplain BootstrapMethod bootstrap method}
|
|
||||||
* associated with the class whose bytecodes include the dynamic call site.
|
|
||||||
* <p>
|
|
||||||
* The type {@code InvokeDynamic} has no particular meaning as a
|
|
||||||
* class or interface supertype, or an object type; it can never be instantiated.
|
|
||||||
* Logically, it denotes a source of all dynamically typed methods.
|
|
||||||
* It may be viewed as a pure syntactic marker of static calls.
|
|
||||||
* It may be imported for ease of use.
|
|
||||||
* <p>
|
|
||||||
* Here are some examples:
|
|
||||||
<blockquote><pre><!-- see indy-demo/src/JavaDocExamples.java -->
|
|
||||||
@BootstrapMethod(value=Here.class, name="bootstrapDynamic")
|
|
||||||
static void example() throws Throwable {
|
|
||||||
Object x; String s; int i;
|
|
||||||
x = InvokeDynamic.greet("world"); // greet(Ljava/lang/String;)Ljava/lang/Object;
|
|
||||||
s = (String) InvokeDynamic.hail(x); // hail(Ljava/lang/Object;)Ljava/lang/String;
|
|
||||||
InvokeDynamic.cogito(); // cogito()V
|
|
||||||
i = (int) InvokeDynamic.#"op:+"(2, 3); // "op:+"(II)I
|
|
||||||
}
|
|
||||||
static MethodHandle bootstrapDynamic(Class caller, String name, MethodType type) { ... }
|
|
||||||
</pre></blockquote>
|
|
||||||
* Each of the above calls generates a single invokedynamic instruction
|
|
||||||
* with the name-and-type descriptors indicated in the comments.
|
|
||||||
* <p>
|
|
||||||
* The argument types are taken directly from the actual arguments,
|
|
||||||
* while the return type corresponds to the target of the assignment.
|
|
||||||
* (Currently, the return type must be given as a false type parameter.
|
|
||||||
* This type parameter is an irregular use of the generic type syntax,
|
|
||||||
* and is likely to change in favor of a convention based on target typing.)
|
|
||||||
* <p>
|
|
||||||
* The final example uses a special syntax for uttering non-Java names.
|
|
||||||
* Any name legal to the JVM may be given between the double quotes.
|
|
||||||
* <p>
|
|
||||||
* None of these calls is complete without a bootstrap method,
|
|
||||||
* which must be declared for the enclosing class or method.
|
|
||||||
* @author John Rose, JSR 292 EG
|
|
||||||
*/
|
*/
|
||||||
@MethodHandle.PolymorphicSignature
|
final class InvokeDynamic {
|
||||||
public final class InvokeDynamic {
|
|
||||||
private InvokeDynamic() { throw new InternalError(); } // do not instantiate
|
private InvokeDynamic() { throw new InternalError(); } // do not instantiate
|
||||||
|
|
||||||
// no statically defined static methods
|
|
||||||
}
|
}
|
||||||
|
@ -67,4 +67,16 @@ public class InvokeDynamicBootstrapError extends LinkageError {
|
|||||||
public InvokeDynamicBootstrapError(String s, Throwable cause) {
|
public InvokeDynamicBootstrapError(String s, Throwable cause) {
|
||||||
super(s, cause);
|
super(s, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a {@code InvokeDynamicBootstrapError} with the specified
|
||||||
|
* cause.
|
||||||
|
*
|
||||||
|
* @param cause the cause, may be {@code null}.
|
||||||
|
*/
|
||||||
|
public InvokeDynamicBootstrapError(Throwable cause) {
|
||||||
|
// cf. Throwable(Throwable cause) constructor.
|
||||||
|
super(cause == null ? null : cause.toString());
|
||||||
|
initCause(cause);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,15 +29,16 @@ import java.dyn.MethodHandles.Lookup;
|
|||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
import sun.dyn.Access;
|
import sun.dyn.Access;
|
||||||
import sun.dyn.MethodHandleImpl;
|
import sun.dyn.MethodHandleImpl;
|
||||||
|
import sun.dyn.util.VerifyAccess;
|
||||||
import sun.reflect.Reflection;
|
import sun.reflect.Reflection;
|
||||||
import static sun.dyn.util.VerifyAccess.checkBootstrapPrivilege;
|
|
||||||
import static sun.dyn.MemberName.newIllegalArgumentException;
|
import static sun.dyn.MemberName.newIllegalArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class consists exclusively of static methods that control
|
* <em>CLASS WILL BE REMOVED FOR PFD:</em>
|
||||||
* the linkage of {@code invokedynamic} instructions, and specifically
|
* Static routines for controlling invokedynamic behavior.
|
||||||
* their reification as {@link CallSite} objects.
|
* Replaced by non-static APIs.
|
||||||
* @author John Rose, JSR 292 EG
|
* @author John Rose, JSR 292 EG
|
||||||
|
* @deprecated This class will be removed in the Public Final Draft.
|
||||||
*/
|
*/
|
||||||
public class Linkage {
|
public class Linkage {
|
||||||
private static final Access IMPL_TOKEN = Access.getToken();
|
private static final Access IMPL_TOKEN = Access.getToken();
|
||||||
@ -45,68 +46,24 @@ public class Linkage {
|
|||||||
private Linkage() {} // do not instantiate
|
private Linkage() {} // do not instantiate
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
|
||||||
* Register a <em>bootstrap method</em> to use when linking dynamic call sites within
|
* Register a <em>bootstrap method</em> to use when linking dynamic call sites within
|
||||||
* a given caller class.
|
* a given caller class.
|
||||||
* <p>
|
* @deprecated Use @{@link BootstrapMethod} annotations instead.
|
||||||
* A bootstrap method must be a method handle with a return type of {@link CallSite}
|
|
||||||
* and the following arguments:
|
|
||||||
* <ul>
|
|
||||||
* <li>the class containing the {@code invokedynamic} instruction, for which the bootstrap method was registered
|
|
||||||
* <li>the name of the method being invoked (a {@link String})
|
|
||||||
* <li>the type of the method being invoked (a {@link MethodType})
|
|
||||||
* </ul>
|
|
||||||
* The bootstrap method acts as a factory method which accepts the given arguments
|
|
||||||
* and returns a {@code CallSite} object (possibly of a subclass of {@code CallSite}).
|
|
||||||
* <p>
|
|
||||||
* The registration must take place exactly once, either before the class has begun
|
|
||||||
* being initialized, or from within the class's static initializer.
|
|
||||||
* Registration will fail with an exception if any of the following conditions hold:
|
|
||||||
* <ul>
|
|
||||||
* <li>The immediate caller of this method is in a different package than the given caller class,
|
|
||||||
* and there is a security manager, and its {@code checkPermission} call throws
|
|
||||||
* when passed {@link LinkagePermission}("registerBootstrapMethod",callerClass).
|
|
||||||
* <li>The given caller class already has a bootstrap method registered.
|
|
||||||
* <li>The given caller class is already fully initialized.
|
|
||||||
* <li>The given caller class is in the process of initialization, in another thread.
|
|
||||||
* </ul>
|
|
||||||
* Because of these rules, a class may install its own bootstrap method in
|
|
||||||
* a static initializer.
|
|
||||||
* @param callerClass a class that may have {@code invokedynamic} sites
|
|
||||||
* @param bootstrapMethod the method to use to bootstrap all such sites
|
|
||||||
* @exception IllegalArgumentException if the class argument is null or
|
|
||||||
* a primitive class, or if the bootstrap method is the wrong type
|
|
||||||
* @exception IllegalStateException if the class already has a bootstrap
|
|
||||||
* method, or if the its static initializer has already run
|
|
||||||
* or is already running in another thread
|
|
||||||
* @exception SecurityException if there is a security manager installed,
|
|
||||||
* and a {@link LinkagePermission} check fails for "registerBootstrapMethod"
|
|
||||||
* @deprecated Use @{@link BootstrapMethod} annotations instead
|
|
||||||
*/
|
*/
|
||||||
public static
|
public static
|
||||||
void registerBootstrapMethod(Class callerClass, MethodHandle bootstrapMethod) {
|
void registerBootstrapMethod(Class callerClass, MethodHandle bootstrapMethod) {
|
||||||
Class callc = Reflection.getCallerClass(2);
|
Class callc = Reflection.getCallerClass(2);
|
||||||
checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod");
|
if (callc != null && !VerifyAccess.isSamePackage(callerClass, callc))
|
||||||
checkBSM(bootstrapMethod);
|
throw new IllegalArgumentException("cannot set bootstrap method on "+callerClass);
|
||||||
MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
|
MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
static private void checkBSM(MethodHandle mh) {
|
|
||||||
if (mh == null) throw newIllegalArgumentException("null bootstrap method");
|
|
||||||
if (mh.type() == BOOTSTRAP_METHOD_TYPE) return;
|
|
||||||
throw new WrongMethodTypeException(mh.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
|
||||||
* Simplified version of {@code registerBootstrapMethod} for self-registration,
|
* Simplified version of {@code registerBootstrapMethod} for self-registration,
|
||||||
* to be called from a static initializer.
|
* to be called from a static initializer.
|
||||||
* Finds a static method of the required type in the
|
* @deprecated Use @{@link BootstrapMethod} annotations instead.
|
||||||
* given runtime class, and installs it on the caller class.
|
|
||||||
* @throws NoSuchMethodException if there is no such method
|
|
||||||
* @throws IllegalStateException if the caller class's static initializer
|
|
||||||
* has already run, or is already running in another thread
|
|
||||||
* @deprecated Use @{@link BootstrapMethod} annotations instead
|
|
||||||
*/
|
*/
|
||||||
public static
|
public static
|
||||||
void registerBootstrapMethod(Class<?> runtime, String name) {
|
void registerBootstrapMethod(Class<?> runtime, String name) {
|
||||||
@ -115,15 +72,9 @@ public class Linkage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
|
||||||
* Simplified version of {@code registerBootstrapMethod} for self-registration,
|
* Simplified version of {@code registerBootstrapMethod} for self-registration,
|
||||||
* to be called from a static initializer.
|
* @deprecated Use @{@link BootstrapMethod} annotations instead.
|
||||||
* Finds a static method of the required type in the
|
|
||||||
* caller class itself, and installs it on the caller class.
|
|
||||||
* @throws IllegalArgumentException if there is no such method
|
|
||||||
* @throws IllegalStateException if the caller class's static initializer
|
|
||||||
* has already run, or is already running in another thread
|
|
||||||
* @deprecated Use @{@link BootstrapMethod} annotations instead
|
|
||||||
*/
|
*/
|
||||||
public static
|
public static
|
||||||
void registerBootstrapMethod(String name) {
|
void registerBootstrapMethod(String name) {
|
||||||
@ -140,82 +91,33 @@ public class Linkage {
|
|||||||
} catch (NoAccessException ex) {
|
} catch (NoAccessException ex) {
|
||||||
throw new IllegalArgumentException("no such bootstrap method in "+runtime+": "+name, ex);
|
throw new IllegalArgumentException("no such bootstrap method in "+runtime+": "+name, ex);
|
||||||
}
|
}
|
||||||
checkBSM(bootstrapMethod);
|
|
||||||
MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
|
MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static final MethodType BOOTSTRAP_METHOD_TYPE
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
|
||||||
* Report the bootstrap method registered for a given caller class.
|
|
||||||
* Returns null if the class has never yet registered a bootstrap method.
|
|
||||||
* Only callers privileged to set the bootstrap method may inquire
|
|
||||||
* about it, because a bootstrap method is potentially a back-door entry
|
|
||||||
* point into its class.
|
|
||||||
* @exception IllegalArgumentException if the argument is null or
|
|
||||||
* a primitive class
|
|
||||||
* @exception SecurityException if there is a security manager installed,
|
|
||||||
* and the immediate caller of this method is not in the same
|
|
||||||
* package as the caller class
|
|
||||||
* and a {@link LinkagePermission} check fails for "getBootstrapMethod"
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
public static
|
|
||||||
MethodHandle getBootstrapMethod(Class callerClass) {
|
|
||||||
Class callc = Reflection.getCallerClass(2);
|
|
||||||
checkBootstrapPrivilege(callc, callerClass, "getBootstrapMethod");
|
|
||||||
return MethodHandleImpl.getBootstrap(IMPL_TOKEN, callerClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
|
||||||
* The type of any bootstrap method is a three-argument method
|
|
||||||
* {@code (Class, String, MethodType)} returning a {@code CallSite}.
|
|
||||||
*/
|
|
||||||
public static final MethodType BOOTSTRAP_METHOD_TYPE
|
|
||||||
= MethodType.methodType(CallSite.class,
|
= MethodType.methodType(CallSite.class,
|
||||||
Class.class, String.class, MethodType.class);
|
Class.class, String.class, MethodType.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
|
||||||
* Invalidate all <code>invokedynamic</code> call sites everywhere.
|
* Invalidate all <code>invokedynamic</code> call sites everywhere.
|
||||||
* <p>
|
* @deprecated Use {@linkplain CallSite#setTarget call site target setting}
|
||||||
* When this method returns, every <code>invokedynamic</code> instruction
|
* and {@link VolatileCallSite#invalidateAll call site invalidation} instead.
|
||||||
* will invoke its bootstrap method on next call.
|
|
||||||
* <p>
|
|
||||||
* It is unspecified whether call sites already known to the Java
|
|
||||||
* code will continue to be associated with <code>invokedynamic</code>
|
|
||||||
* instructions. If any call site is still so associated, its
|
|
||||||
* {@link CallSite#getTarget()} method is guaranteed to return null
|
|
||||||
* the invalidation operation completes.
|
|
||||||
* <p>
|
|
||||||
* Invalidation operations are likely to be slow. Use them sparingly.
|
|
||||||
*/
|
*/
|
||||||
public static
|
public static
|
||||||
Object invalidateAll() {
|
Object invalidateAll() {
|
||||||
SecurityManager security = System.getSecurityManager();
|
throw new UnsupportedOperationException();
|
||||||
if (security != null) {
|
|
||||||
security.checkPermission(new LinkagePermission("invalidateAll"));
|
|
||||||
}
|
|
||||||
throw new UnsupportedOperationException("NYI");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
|
||||||
* Invalidate all {@code invokedynamic} call sites in the bytecodes
|
* Invalidate all {@code invokedynamic} call sites in the bytecodes
|
||||||
* of any methods of the given class.
|
* of any methods of the given class.
|
||||||
* <p>
|
* @deprecated Use {@linkplain CallSite#setTarget call site target setting}
|
||||||
* When this method returns, every matching <code>invokedynamic</code>
|
* and {@link VolatileCallSite#invalidateAll call site invalidation} instead.
|
||||||
* instruction will invoke its bootstrap method on next call.
|
|
||||||
* <p>
|
|
||||||
* For additional semantics of call site invalidation,
|
|
||||||
* see {@link #invalidateAll()}.
|
|
||||||
*/
|
*/
|
||||||
public static
|
public static
|
||||||
Object invalidateCallerClass(Class<?> callerClass) {
|
Object invalidateCallerClass(Class<?> callerClass) {
|
||||||
SecurityManager security = System.getSecurityManager();
|
throw new UnsupportedOperationException();
|
||||||
if (security != null) {
|
|
||||||
security.checkPermission(new LinkagePermission("invalidateAll", callerClass));
|
|
||||||
}
|
|
||||||
throw new UnsupportedOperationException("NYI");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,104 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package java.dyn;
|
|
||||||
|
|
||||||
import java.security.*;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.StringTokenizer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
|
||||||
* This class is for managing runtime permission checking for
|
|
||||||
* operations performed by methods in the {@link Linkage} class.
|
|
||||||
* Like a {@link RuntimePermission}, on which it is modeled,
|
|
||||||
* a {@code LinkagePermission} contains a target name but
|
|
||||||
* no actions list; you either have the named permission
|
|
||||||
* or you don't.
|
|
||||||
* <p>
|
|
||||||
* The following table lists all the possible {@code LinkagePermission} target names,
|
|
||||||
* and for each provides a description of what the permission allows
|
|
||||||
* and a discussion of the risks of granting code the permission.
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* <table border=1 cellpadding=5 summary="permission target name,
|
|
||||||
* what the target allows,and associated risks">
|
|
||||||
* <tr>
|
|
||||||
* <th>Permission Target Name</th>
|
|
||||||
* <th>What the Permission Allows</th>
|
|
||||||
* <th>Risks of Allowing this Permission</th>
|
|
||||||
* </tr>
|
|
||||||
*
|
|
||||||
* <tr>
|
|
||||||
* <td>invalidateAll</td>
|
|
||||||
* <td>Force the relinking of invokedynamic call sites everywhere.</td>
|
|
||||||
* <td>This could allow an attacker to slow down the system,
|
|
||||||
* or perhaps expose timing bugs in a dynamic language implementations,
|
|
||||||
* by forcing redundant relinking operations.</td>
|
|
||||||
* </tr>
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* <tr>
|
|
||||||
* <td>invalidateCallerClass.{class name}</td>
|
|
||||||
* <td>Force the relinking of invokedynamic call sites in the given class.</td>
|
|
||||||
* <td>See {@code invalidateAll}.</td>
|
|
||||||
* </tr>
|
|
||||||
* </table>
|
|
||||||
* <p>ISSUE: Is this still needed?
|
|
||||||
*
|
|
||||||
* @see java.lang.RuntimePermission
|
|
||||||
* @see java.lang.SecurityManager
|
|
||||||
*
|
|
||||||
* @author John Rose, JSR 292 EG
|
|
||||||
*/
|
|
||||||
|
|
||||||
public final class LinkagePermission extends BasicPermission {
|
|
||||||
private static final long serialVersionUID = 292L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new LinkagePermission with the given name.
|
|
||||||
* The name is the symbolic name of the LinkagePermission, such as
|
|
||||||
* "invalidateCallerClass.*", etc. An asterisk
|
|
||||||
* may appear at the end of the name, following a ".", or by itself, to
|
|
||||||
* signify a wildcard match.
|
|
||||||
*
|
|
||||||
* @param name the name of the LinkagePermission
|
|
||||||
*/
|
|
||||||
public LinkagePermission(String name) {
|
|
||||||
super(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new LinkagePermission with the given name on the given class.
|
|
||||||
* Equivalent to {@code LinkagePermission(name+"."+clazz.getName())}.
|
|
||||||
*
|
|
||||||
* @param name the name of the LinkagePermission
|
|
||||||
* @param clazz the class affected by the permission
|
|
||||||
*/
|
|
||||||
public LinkagePermission(String name, Class<?> clazz) {
|
|
||||||
super(name + "." + clazz.getName());
|
|
||||||
}
|
|
||||||
}
|
|
@ -37,20 +37,29 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
|
|||||||
* A method handle is a typed, directly executable reference to a method,
|
* A method handle is a typed, directly executable reference to a method,
|
||||||
* constructor, field, or similar low-level operation, with optional
|
* constructor, field, or similar low-level operation, with optional
|
||||||
* transformations of arguments or return values.
|
* transformations of arguments or return values.
|
||||||
* (These transformations include conversion, insertion, deletion,
|
* These transformations are quite general, and include such patterns as
|
||||||
* substitution. See the methods of this class and of {@link MethodHandles}.)
|
* {@linkplain #asType conversion},
|
||||||
|
* {@linkplain #bindTo insertion},
|
||||||
|
* {@linkplain java.dyn.MethodHandles#dropArguments deletion},
|
||||||
|
* and {@linkplain java.dyn.MethodHandles#filterArguments substitution}.
|
||||||
|
* <p>
|
||||||
|
* <em>Note: The super-class of MethodHandle is Object.
|
||||||
|
* Any other super-class visible in the Reference Implementation
|
||||||
|
* will be removed before the Proposed Final Draft.
|
||||||
|
* Also, the final version will not include any public or
|
||||||
|
* protected constructors.</em>
|
||||||
* <p>
|
* <p>
|
||||||
* Method handles are strongly typed according to signature.
|
* Method handles are strongly typed according to signature.
|
||||||
* They are not distinguished by method name or enclosing class.
|
* They are not distinguished by method name or enclosing class.
|
||||||
* A method handle must be invoked under a signature which matches
|
* A method handle must be invoked under a signature which matches
|
||||||
* the method handle's own {@link MethodType method type}.
|
* the method handle's own {@linkplain MethodType method type}.
|
||||||
* <p>
|
* <p>
|
||||||
* Every method handle confesses its type via the {@code type} accessor.
|
* Every method handle reports its type via the {@link #type type} accessor.
|
||||||
* The structure of this type is a series of classes, one of which is
|
* The structure of this type is a series of classes, one of which is
|
||||||
* the return type of the method (or {@code void.class} if none).
|
* the return type of the method (or {@code void.class} if none).
|
||||||
* <p>
|
* <p>
|
||||||
* Every method handle appears as an object containing a method named
|
* Every method handle appears as an object containing a method named
|
||||||
* {@code invoke}, whose signature exactly matches
|
* {@link #invokeExact invokeExact}, whose signature exactly matches
|
||||||
* the method handle's type.
|
* the method handle's type.
|
||||||
* A Java method call expression, which compiles to an
|
* A Java method call expression, which compiles to an
|
||||||
* {@code invokevirtual} instruction,
|
* {@code invokevirtual} instruction,
|
||||||
@ -61,15 +70,29 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
|
|||||||
* (The type is specified in the {@code invokevirtual} instruction,
|
* (The type is specified in the {@code invokevirtual} instruction,
|
||||||
* via a {@code CONSTANT_NameAndType} constant pool entry.)
|
* via a {@code CONSTANT_NameAndType} constant pool entry.)
|
||||||
* The call looks within the receiver object for a method
|
* The call looks within the receiver object for a method
|
||||||
* named {@code invoke} of the intended method type.
|
* named {@code invokeExact} of the intended method type.
|
||||||
* The call fails with a {@link WrongMethodTypeException}
|
* The call fails with a {@link WrongMethodTypeException}
|
||||||
* if the method does not exist, even if there is an {@code invoke}
|
* if the method does not exist, even if there is an {@code invokeExact}
|
||||||
* method of a closely similar signature.
|
* method of a closely similar signature.
|
||||||
* As with other kinds
|
* As with other kinds
|
||||||
* of methods in the JVM, signature matching during method linkage
|
* of methods in the JVM, signature matching during method linkage
|
||||||
* is exact, and does not allow for language-level implicit conversions
|
* is exact, and does not allow for language-level implicit conversions
|
||||||
* such as {@code String} to {@code Object} or {@code short} to {@code int}.
|
* such as {@code String} to {@code Object} or {@code short} to {@code int}.
|
||||||
* <p>
|
* <p>
|
||||||
|
* Each individual method handle also contains a method named
|
||||||
|
* {@link #invokeGeneric invokeGeneric}, whose type is the same
|
||||||
|
* as {@code invokeExact}, and is therefore also reported by
|
||||||
|
* the {@link #type type} accessor.
|
||||||
|
* A call to {@code invokeGeneric} works the same as a call to
|
||||||
|
* {@code invokeExact}, if the signature specified by the caller
|
||||||
|
* exactly matches the method handle's own type.
|
||||||
|
* If there is a type mismatch, {@code invokeGeneric} attempts
|
||||||
|
* to adjust the type of the target method handle
|
||||||
|
* (as if by a call to {@link #asType asType})
|
||||||
|
* to obtain an exactly invokable target.
|
||||||
|
* This allows a more powerful negotiation of method type
|
||||||
|
* between caller and callee.
|
||||||
|
* <p>
|
||||||
* A method handle is an unrestricted capability to call a method.
|
* A method handle is an unrestricted capability to call a method.
|
||||||
* A method handle can be formed on a non-public method by a class
|
* A method handle can be formed on a non-public method by a class
|
||||||
* that has access to that method; the resulting handle can be used
|
* that has access to that method; the resulting handle can be used
|
||||||
@ -77,31 +100,47 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
|
|||||||
* checking is performed when the method handle is created, not
|
* checking is performed when the method handle is created, not
|
||||||
* (as in reflection) every time it is called. Handles to non-public
|
* (as in reflection) every time it is called. Handles to non-public
|
||||||
* methods, or in non-public classes, should generally be kept secret.
|
* methods, or in non-public classes, should generally be kept secret.
|
||||||
* They should not be passed to untrusted code.
|
* They should not be passed to untrusted code unless their use from
|
||||||
|
* the untrusted code would be harmless.
|
||||||
* <p>
|
* <p>
|
||||||
* Bytecode in an extended JVM can directly call a method handle's
|
* Bytecode in the JVM can directly call a method handle's
|
||||||
* {@code invoke} from an {@code invokevirtual} instruction.
|
* {@code invokeExact} method from an {@code invokevirtual} instruction.
|
||||||
* The receiver class type must be {@code MethodHandle} and the method name
|
* The receiver class type must be {@code MethodHandle} and the method name
|
||||||
* must be {@code invoke}. The signature of the invocation
|
* must be {@code invokeExact}. The signature of the invocation
|
||||||
* (after resolving symbolic type names) must exactly match the method type
|
* (after resolving symbolic type names) must exactly match the method type
|
||||||
* of the target method.
|
* of the target method.
|
||||||
|
* Similarly, bytecode can directly call a method handle's {@code invokeGeneric}
|
||||||
|
* method. The signature of the invocation (after resolving symbolic type names)
|
||||||
|
* must either exactly match the method type or be a valid argument to
|
||||||
|
* the target's {@link #asType asType} method.
|
||||||
* <p>
|
* <p>
|
||||||
* Every {@code invoke} method always throws {@link Exception},
|
* Every {@code invokeExact} and {@code invokeGeneric} method always
|
||||||
|
* throws {@link java.lang.Throwable Throwable},
|
||||||
* which is to say that there is no static restriction on what a method handle
|
* which is to say that there is no static restriction on what a method handle
|
||||||
* can throw. Since the JVM does not distinguish between checked
|
* can throw. Since the JVM does not distinguish between checked
|
||||||
* and unchecked exceptions (other than by their class, of course),
|
* and unchecked exceptions (other than by their class, of course),
|
||||||
* there is no particular effect on bytecode shape from ascribing
|
* there is no particular effect on bytecode shape from ascribing
|
||||||
* checked exceptions to method handle invocations. But in Java source
|
* checked exceptions to method handle invocations. But in Java source
|
||||||
* code, methods which perform method handle calls must either explicitly
|
* code, methods which perform method handle calls must either explicitly
|
||||||
* throw {@code Exception}, or else must catch all checked exceptions locally.
|
* throw {@code java.lang.Throwable Throwable}, or else must catch all
|
||||||
|
* throwables locally, rethrowing only those which are legal in the context,
|
||||||
|
* and wrapping ones which are illegal.
|
||||||
* <p>
|
* <p>
|
||||||
* Bytecode in an extended JVM can directly obtain a method handle
|
* Bytecode in the JVM can directly obtain a method handle
|
||||||
* for any accessible method from a {@code ldc} instruction
|
* for any accessible method from a {@code ldc} instruction
|
||||||
* which refers to a {@code CONSTANT_Methodref} or
|
* which refers to a {@code CONSTANT_MethodHandle} constant pool entry.
|
||||||
* {@code CONSTANT_InterfaceMethodref} constant pool entry.
|
* (Each such entry refers directly to a {@code CONSTANT_Methodref},
|
||||||
|
* {@code CONSTANT_InterfaceMethodref}, or {@code CONSTANT_Fieldref}
|
||||||
|
* constant pool entry.
|
||||||
|
* For more details, see the <a href="package-summary.html#mhcon">package summary</a>.)
|
||||||
* <p>
|
* <p>
|
||||||
* All JVMs can also use a reflective API called {@code MethodHandles}
|
* Java code can also use a reflective API called
|
||||||
|
* {@link java.dyn.MethodHandles.Lookup MethodHandles.Lookup}
|
||||||
* for creating and calling method handles.
|
* for creating and calling method handles.
|
||||||
|
* For example, a static method handle can be obtained
|
||||||
|
* from {@link java.dyn.MethodHandles.Lookup#findStatic Lookup.findStatic}.
|
||||||
|
* There are also bridge methods from Core Reflection API objects,
|
||||||
|
* such as {@link java.dyn.MethodHandles.Lookup#unreflect Lookup.ureflect}.
|
||||||
* <p>
|
* <p>
|
||||||
* A method reference may refer either to a static or non-static method.
|
* A method reference may refer either to a static or non-static method.
|
||||||
* In the non-static case, the method handle type includes an explicit
|
* In the non-static case, the method handle type includes an explicit
|
||||||
@ -128,10 +167,10 @@ MethodHandles.Lookup lookup = MethodHandles.lookup();
|
|||||||
mt = MethodType.methodType(String.class, char.class, char.class);
|
mt = MethodType.methodType(String.class, char.class, char.class);
|
||||||
mh = lookup.findVirtual(String.class, "replace", mt);
|
mh = lookup.findVirtual(String.class, "replace", mt);
|
||||||
// (Ljava/lang/String;CC)Ljava/lang/String;
|
// (Ljava/lang/String;CC)Ljava/lang/String;
|
||||||
s = mh.<String>invokeExact("daddy",'d','n');
|
s = (String) mh.invokeExact("daddy",'d','n');
|
||||||
assert(s.equals("nanny"));
|
assert(s.equals("nanny"));
|
||||||
// weakly typed invocation (using MHs.invoke)
|
// weakly typed invocation (using MHs.invoke)
|
||||||
s = (String) mh.invokeVarargs("sappy", 'p', 'v');
|
s = (String) mh.invokeWithArguments("sappy", 'p', 'v');
|
||||||
assert(s.equals("savvy"));
|
assert(s.equals("savvy"));
|
||||||
// mt is {Object[] => List}
|
// mt is {Object[] => List}
|
||||||
mt = MethodType.methodType(java.util.List.class, Object[].class);
|
mt = MethodType.methodType(java.util.List.class, Object[].class);
|
||||||
@ -147,14 +186,22 @@ assert(x.equals(java.util.Arrays.asList(1,2,3)));
|
|||||||
mt = MethodType.methodType(int.class);
|
mt = MethodType.methodType(int.class);
|
||||||
mh = lookup.findVirtual(java.util.List.class, "size", mt);
|
mh = lookup.findVirtual(java.util.List.class, "size", mt);
|
||||||
// (Ljava/util/List;)I
|
// (Ljava/util/List;)I
|
||||||
i = mh.<int>invokeExact(java.util.Arrays.asList(1,2,3));
|
i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));
|
||||||
assert(i == 3);
|
assert(i == 3);
|
||||||
|
mt = MethodType.methodType(void.class, String.class);
|
||||||
|
mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt);
|
||||||
|
mh.invokeExact(System.out, "Hello, world.");
|
||||||
|
// (Ljava/io/PrintStream;Ljava/lang/String;)V
|
||||||
* </pre></blockquote>
|
* </pre></blockquote>
|
||||||
* Each of the above calls generates a single invokevirtual instruction
|
* Each of the above calls generates a single invokevirtual instruction
|
||||||
* with the name {@code invoke} and the type descriptors indicated in the comments.
|
* with the name {@code invoke} and the type descriptors indicated in the comments.
|
||||||
* The argument types are taken directly from the actual arguments,
|
* The argument types are taken directly from the actual arguments,
|
||||||
* while the return type is taken from the type parameter.
|
* while the return type is taken from the cast immediately applied to the call.
|
||||||
* (This type parameter may be a primitive, and it defaults to {@code Object}.)
|
* This cast may be to a primitive.
|
||||||
|
* If it is missing, the type defaults to {@code Object} if the call
|
||||||
|
* occurs in a context which uses the return value.
|
||||||
|
* If the call occurs as a statement, a cast is impossible,
|
||||||
|
* and there is no return type; the call is {@code void}.
|
||||||
* <p>
|
* <p>
|
||||||
* <em>A note on generic typing:</em> Method handles do not represent
|
* <em>A note on generic typing:</em> Method handles do not represent
|
||||||
* their function types in terms of Java parameterized (generic) types,
|
* their function types in terms of Java parameterized (generic) types,
|
||||||
@ -162,7 +209,7 @@ assert(i == 3);
|
|||||||
* Java types.
|
* Java types.
|
||||||
* <ol>
|
* <ol>
|
||||||
* <li>Method types range over all possible arities,
|
* <li>Method types range over all possible arities,
|
||||||
* from no arguments to an arbitrary number of arguments.
|
* from no arguments to up to 255 of arguments (a limit imposed by the JVM).
|
||||||
* Generics are not variadic, and so cannot represent this.</li>
|
* Generics are not variadic, and so cannot represent this.</li>
|
||||||
* <li>Method types can specify arguments of primitive types,
|
* <li>Method types can specify arguments of primitive types,
|
||||||
* which Java generic types cannot range over.</li>
|
* which Java generic types cannot range over.</li>
|
||||||
@ -180,6 +227,19 @@ assert(i == 3);
|
|||||||
* fields, methods, and constructors can be represented directly
|
* fields, methods, and constructors can be represented directly
|
||||||
* in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes.
|
* in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes.
|
||||||
* Loading such a constant causes the component classes of its type to be loaded as necessary.
|
* Loading such a constant causes the component classes of its type to be loaded as necessary.
|
||||||
|
* <p>
|
||||||
|
* Method handles cannot be subclassed by the user.
|
||||||
|
* Implementations may (or may not) create internal subclasses of {@code MethodHandle}
|
||||||
|
* which may be visible via the {@code java.lang.Object#getClass Object.getClass}
|
||||||
|
* operation. The programmer should not draw conclusions about a method handle
|
||||||
|
* from its specific class, as the method handle class hierarchy (if any)
|
||||||
|
* may change from time to time or across implementations from different vendors.
|
||||||
|
* <p>
|
||||||
|
* With respect to the Java Memory Model, any method handle will behave
|
||||||
|
* as if all of its fields are final variables. This means that any method
|
||||||
|
* handle made visible to the application will always be fully formed.
|
||||||
|
* This is true even if the method handle is published through a shared
|
||||||
|
* variables in a data race.
|
||||||
*
|
*
|
||||||
* @see MethodType
|
* @see MethodType
|
||||||
* @see MethodHandles
|
* @see MethodHandles
|
||||||
@ -189,7 +249,6 @@ public abstract class MethodHandle
|
|||||||
// Note: This is an implementation inheritance hack, and will be removed
|
// Note: This is an implementation inheritance hack, and will be removed
|
||||||
// with a JVM change which moves the required hidden state onto this class.
|
// with a JVM change which moves the required hidden state onto this class.
|
||||||
extends MethodHandleImpl
|
extends MethodHandleImpl
|
||||||
implements MethodHandleProvider
|
|
||||||
{
|
{
|
||||||
private static Access IMPL_TOKEN = Access.getToken();
|
private static Access IMPL_TOKEN = Access.getToken();
|
||||||
|
|
||||||
@ -208,7 +267,7 @@ public abstract class MethodHandle
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Report the type of this method handle.
|
* Report the type of this method handle.
|
||||||
* Every invocation of this method handle must exactly match this type.
|
* Every invocation of this method handle via {@code invokeExact} must exactly match this type.
|
||||||
* @return the method handle type
|
* @return the method handle type
|
||||||
*/
|
*/
|
||||||
public final MethodType type() {
|
public final MethodType type() {
|
||||||
@ -216,12 +275,16 @@ public abstract class MethodHandle
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The constructor for MethodHandle may only be called by privileged code.
|
* <em>CONSTRUCTOR WILL BE REMOVED FOR PFD:</em>
|
||||||
* Subclasses may be in other packages, but must possess
|
* Temporary constructor in early versions of the Reference Implementation.
|
||||||
* a token which they obtained from MH with a security check.
|
* Method handle inheritance (if any) will be contained completely within
|
||||||
* @param token non-null object which proves access permission
|
* the {@code java.dyn} package.
|
||||||
* @param type type (permanently assigned) of the new method handle
|
|
||||||
*/
|
*/
|
||||||
|
// The constructor for MethodHandle may only be called by privileged code.
|
||||||
|
// Subclasses may be in other packages, but must possess
|
||||||
|
// a token which they obtained from MH with a security check.
|
||||||
|
// @param token non-null object which proves access permission
|
||||||
|
// @param type type (permanently assigned) of the new method handle
|
||||||
protected MethodHandle(Access token, MethodType type) {
|
protected MethodHandle(Access token, MethodType type) {
|
||||||
super(token);
|
super(token);
|
||||||
Access.check(token);
|
Access.check(token);
|
||||||
@ -243,92 +306,116 @@ public abstract class MethodHandle
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The string of a direct method handle is the simple name of its target method.
|
/**
|
||||||
* The string of an adapter or bound method handle is the string of its
|
* Returns a string representation of the method handle,
|
||||||
* target method handle.
|
* starting with the string {@code "MethodHandle"} and
|
||||||
* The string of a Java method handle is the string of its entry point method,
|
* ending with the string representation of the method handle's type.
|
||||||
* unless the Java method handle overrides the toString method.
|
* In other words, this method returns a string equal to the value of:
|
||||||
|
* <blockquote><pre>
|
||||||
|
* "MethodHandle" + type().toString()
|
||||||
|
* </pre></blockquote>
|
||||||
|
* <p>
|
||||||
|
* Note: Future releases of this API may add further information
|
||||||
|
* to the string representation.
|
||||||
|
* Therefore, the present syntax should not be parsed by applications.
|
||||||
|
*
|
||||||
|
* @return a string representation of the method handle
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return MethodHandleImpl.getNameString(IMPL_TOKEN, this);
|
return MethodHandleImpl.getNameString(IMPL_TOKEN, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//// This is the "Method Handle Kernel API" discussed at the JVM Language Summit, 9/2009.
|
|
||||||
//// Implementations here currently delegate to statics in MethodHandles. Some of those statics
|
|
||||||
//// will be deprecated. Others will be kept as "algorithms" to supply degrees of freedom
|
|
||||||
//// not present in the Kernel API.
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
|
||||||
* Invoke the method handle, allowing any caller signature, but requiring an exact signature match.
|
* Invoke the method handle, allowing any caller signature, but requiring an exact signature match.
|
||||||
* The signature at the call site of {@code invokeExact} must
|
* The signature at the call site of {@code invokeExact} must
|
||||||
* exactly match this method handle's {@code type}.
|
* exactly match this method handle's {@link #type type}.
|
||||||
* No conversions are allowed on arguments or return values.
|
* No conversions are allowed on arguments or return values.
|
||||||
|
* @throws WrongMethodTypeException if the target's type is not identical with the caller's type signature
|
||||||
|
* @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
|
||||||
*/
|
*/
|
||||||
public final native @PolymorphicSignature <R,A> R invokeExact(A... args) throws Throwable;
|
public final native @PolymorphicSignature Object invokeExact(Object... args) throws Throwable;
|
||||||
|
|
||||||
// FIXME: remove this transitional form
|
|
||||||
/** @deprecated transitional form defined in EDR but removed in PFD */
|
|
||||||
public final native @PolymorphicSignature <R,A> R invoke(A... args) throws Throwable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
|
||||||
* Invoke the method handle, allowing any caller signature,
|
* Invoke the method handle, allowing any caller signature,
|
||||||
* and performing simple conversions for arguments and return types.
|
* and optionally performing conversions for arguments and return types.
|
||||||
* The signature at the call site of {@code invokeGeneric} must
|
|
||||||
* have the same arity as this method handle's {@code type}.
|
|
||||||
* <p>
|
* <p>
|
||||||
* If the call site signature exactly matches this method handle's {@code type},
|
* If the call site signature exactly matches this method handle's {@link #type type},
|
||||||
* the call proceeds as if by {@link #invokeExact}.
|
* the call proceeds as if by {@link #invokeExact invokeExact}.
|
||||||
* <p>
|
* <p>
|
||||||
* Otherwise, the call proceeds as if this method handle were first
|
* Otherwise, the call proceeds as if this method handle were first
|
||||||
* adjusted by calling {@link #asType} to adjust this method handle
|
* adjusted by calling {@link #asType asType} to adjust this method handle
|
||||||
* to the required type, and then the call proceeds as if by
|
* to the required type, and then the call proceeds as if by
|
||||||
* {@link #invokeExact} on the adjusted method handle.
|
* {@link #invokeExact invokeExact} on the adjusted method handle.
|
||||||
|
* <p>
|
||||||
|
* There is no guarantee that the {@code asType} call is actually made.
|
||||||
|
* If the JVM can predict the results of making the call, it may perform
|
||||||
|
* adaptations directly on the caller's arguments,
|
||||||
|
* and call the target method handle according to its own exact type.
|
||||||
|
* <p>
|
||||||
|
* If the method handle is equipped with a
|
||||||
|
* {@linkplain #withTypeHandler type handler}, the handler must produce
|
||||||
|
* an entry point of the call site's exact type.
|
||||||
|
* Otherwise, the signature at the call site of {@code invokeGeneric} must
|
||||||
|
* be a valid argument to the standard {@code asType} method.
|
||||||
|
* In particular, the caller must specify the same argument arity
|
||||||
|
* as the callee's type.
|
||||||
|
* @throws WrongMethodTypeException if the target's type cannot be adjusted to the caller's type signature
|
||||||
|
* @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
|
||||||
*/
|
*/
|
||||||
public final native @PolymorphicSignature <R,A> R invokeGeneric(A... args) throws Throwable;
|
public final native @PolymorphicSignature Object invokeGeneric(Object... args) throws Throwable;
|
||||||
|
|
||||||
// ?? public final native @PolymorphicSignature <R,A,V> R invokeVarargs(A args, V[] varargs) throws Throwable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
|
||||||
* Perform a varargs invocation, passing the arguments in the given array
|
* Perform a varargs invocation, passing the arguments in the given array
|
||||||
* to the method handle, as if via {@link #invokeGeneric} from a call site
|
* to the method handle, as if via {@link #invokeGeneric invokeGeneric} from a call site
|
||||||
* which mentions only the type {@code Object}, and whose arity is the length
|
* which mentions only the type {@code Object}, and whose arity is the length
|
||||||
* of the argument array.
|
* of the argument array.
|
||||||
* <p>
|
* <p>
|
||||||
* The length of the arguments array must equal the parameter count
|
* Specifically, execution proceeds as if by the following steps,
|
||||||
* of the target's type.
|
* although the methods are not guaranteed to be called if the JVM
|
||||||
* The arguments array is spread into separate arguments.
|
* can predict their effects.
|
||||||
|
* <ul>
|
||||||
|
* <li>Determine the length of the argument array as {@code N}.
|
||||||
|
* For a null reference, {@code N=0}. </li>
|
||||||
|
* <li>Determine the generic type {@code TN} of {@code N} arguments as
|
||||||
|
* as {@code TN=MethodType.genericMethodType(N)}.</li>
|
||||||
|
* <li>Force the original target method handle {@code MH0} to the
|
||||||
|
* required type, as {@code MH1 = MH0.asType(TN)}. </li>
|
||||||
|
* <li>Spread the array into {@code N} separate arguments {@code A0, ...}. </li>
|
||||||
|
* <li>Invoke the type-adjusted method handle on the unpacked arguments:
|
||||||
|
* MH1.invokeExact(A0, ...). </li>
|
||||||
|
* <li>Take the return value as an {@code Object} reference. </li>
|
||||||
|
* </ul>
|
||||||
* <p>
|
* <p>
|
||||||
* In order to match the type of the target, the following argument
|
* Because of the action of the {@code asType} step, the following argument
|
||||||
* conversions are applied as necessary:
|
* conversions are applied as necessary:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>reference casting
|
* <li>reference casting
|
||||||
* <li>unboxing
|
* <li>unboxing
|
||||||
|
* <li>widening primitive conversions
|
||||||
* </ul>
|
* </ul>
|
||||||
* The following conversions are not applied:
|
* <p>
|
||||||
* <ul>
|
|
||||||
* <li>primitive conversions (e.g., {@code byte} to {@code int}
|
|
||||||
* <li>varargs conversions other than the initial spread
|
|
||||||
* <li>any application-specific conversions (e.g., string to number)
|
|
||||||
* </ul>
|
|
||||||
* The result returned by the call is boxed if it is a primitive,
|
* The result returned by the call is boxed if it is a primitive,
|
||||||
* or forced to null if the return type is void.
|
* or forced to null if the return type is void.
|
||||||
* <p>
|
* <p>
|
||||||
* This call is equivalent to the following code:
|
* This call is equivalent to the following code:
|
||||||
* <p><blockquote><pre>
|
* <p><blockquote><pre>
|
||||||
* MethodHandle invoker = MethodHandles.genericInvoker(this.type(), 0, true);
|
* MethodHandle invoker = MethodHandles.varargsInvoker(this.type(), 0);
|
||||||
* Object result = invoker.invokeExact(this, arguments);
|
* Object result = invoker.invokeExact(this, arguments);
|
||||||
* </pre></blockquote>
|
* </pre></blockquote>
|
||||||
* @param arguments the arguments to pass to the target
|
* @param arguments the arguments to pass to the target
|
||||||
* @return the result returned by the target
|
* @return the result returned by the target
|
||||||
* @see MethodHandles#genericInvoker
|
* @throws WrongMethodTypeException if the target's type cannot be adjusted to take the arguments
|
||||||
|
* @throws Throwable anything thrown by the target method invocation
|
||||||
|
* @see MethodHandles#varargsInvoker
|
||||||
*/
|
*/
|
||||||
public final Object invokeVarargs(Object... arguments) throws Throwable {
|
public final Object invokeWithArguments(Object... arguments) throws Throwable {
|
||||||
int argc = arguments == null ? 0 : arguments.length;
|
int argc = arguments == null ? 0 : arguments.length;
|
||||||
MethodType type = type();
|
MethodType type = type();
|
||||||
|
if (type.parameterCount() != argc) {
|
||||||
|
// simulate invokeGeneric
|
||||||
|
return asType(MethodType.genericMethodType(argc)).invokeWithArguments(arguments);
|
||||||
|
}
|
||||||
if (argc <= 10) {
|
if (argc <= 10) {
|
||||||
MethodHandle invoker = MethodHandles.invokers(type).genericInvoker();
|
MethodHandle invoker = MethodHandles.invokers(type).genericInvoker();
|
||||||
switch (argc) {
|
switch (argc) {
|
||||||
@ -372,99 +459,70 @@ public abstract class MethodHandle
|
|||||||
MethodHandle invoker = MethodHandles.invokers(type).varargsInvoker(0);
|
MethodHandle invoker = MethodHandles.invokers(type).varargsInvoker(0);
|
||||||
return invoker.invokeExact(this, arguments);
|
return invoker.invokeExact(this, arguments);
|
||||||
}
|
}
|
||||||
/** Equivalent to {@code invokeVarargs(arguments.toArray())}. */
|
/** Equivalent to {@code invokeWithArguments(arguments.toArray())}. */
|
||||||
|
public final Object invokeWithArguments(java.util.List<?> arguments) throws Throwable {
|
||||||
|
return invokeWithArguments(arguments.toArray());
|
||||||
|
}
|
||||||
|
@Deprecated
|
||||||
|
public final Object invokeVarargs(Object... arguments) throws Throwable {
|
||||||
|
return invokeWithArguments(arguments);
|
||||||
|
}
|
||||||
|
@Deprecated
|
||||||
public final Object invokeVarargs(java.util.List<?> arguments) throws Throwable {
|
public final Object invokeVarargs(java.util.List<?> arguments) throws Throwable {
|
||||||
return invokeVarargs(arguments.toArray());
|
return invokeWithArguments(arguments.toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- this is intentionally NOT a javadoc yet ---
|
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
|
||||||
* Produce an adapter method handle which adapts the type of the
|
|
||||||
* current method handle to a new type by pairwise argument conversion.
|
|
||||||
* The original type and new type must have the same number of arguments.
|
|
||||||
* The resulting method handle is guaranteed to confess a type
|
|
||||||
* which is equal to the desired new type.
|
|
||||||
* <p>
|
|
||||||
* If the original type and new type are equal, returns {@code this}.
|
|
||||||
* <p>
|
|
||||||
* The following conversions are applied as needed both to
|
|
||||||
* arguments and return types. Let T0 and T1 be the differing
|
|
||||||
* new and old parameter types (or old and new return types)
|
|
||||||
* for corresponding values passed by the new and old method types.
|
|
||||||
* Given those types T0, T1, one of the following conversions is applied
|
|
||||||
* if possible:
|
|
||||||
* <ul>
|
|
||||||
* <li>If T0 and T1 are references, and T1 is not an interface type,
|
|
||||||
* then a cast to T1 is applied.
|
|
||||||
* (The types do not need to be related in any particular way.)
|
|
||||||
* <li>If T0 and T1 are references, and T1 is an interface type,
|
|
||||||
* then the value of type T0 is passed as a T1 without a cast.
|
|
||||||
* (This treatment of interfaces follows the usage of the bytecode verifier.)
|
|
||||||
* <li>If T0 and T1 are primitives, then a Java casting
|
|
||||||
* conversion (JLS 5.5) is applied, if one exists.
|
|
||||||
* <li>If T0 and T1 are primitives and one is boolean,
|
|
||||||
* the boolean is treated as a one-bit unsigned integer.
|
|
||||||
* (This treatment follows the usage of the bytecode verifier.)
|
|
||||||
* A conversion from another primitive type behaves as if
|
|
||||||
* it first converts to byte, and then masks all but the low bit.
|
|
||||||
* <li>If T0 is a primitive and T1 a reference, a boxing
|
|
||||||
* conversion is applied if one exists, possibly followed by
|
|
||||||
* an reference conversion to a superclass.
|
|
||||||
* T1 must be a wrapper class or a supertype of one.
|
|
||||||
* If T1 is a wrapper class, T0 is converted if necessary
|
|
||||||
* to T1's primitive type by one of the preceding conversions.
|
|
||||||
* Otherwise, T0 is boxed, and its wrapper converted to T1.
|
|
||||||
* <li>If T0 is a reference and T1 a primitive, an unboxing
|
|
||||||
* conversion is applied if one exists, possibly preceded by
|
|
||||||
* a reference conversion to a wrapper class.
|
|
||||||
* T0 must be a wrapper class or a supertype of one.
|
|
||||||
* If T0 is a wrapper class, its primitive value is converted
|
|
||||||
* if necessary to T1 by one of the preceding conversions.
|
|
||||||
* Otherwise, T0 is converted directly to the wrapper type for T1,
|
|
||||||
* which is then unboxed.
|
|
||||||
* <li>If the return type T1 is void, any returned value is discarded
|
|
||||||
* <li>If the return type T0 is void and T1 a reference, a null value is introduced.
|
|
||||||
* <li>If the return type T0 is void and T1 a primitive, a zero value is introduced.
|
|
||||||
* </ul>
|
|
||||||
* <p>
|
|
||||||
*/
|
|
||||||
/**
|
/**
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
|
||||||
* Produce an adapter method handle which adapts the type of the
|
* Produce an adapter method handle which adapts the type of the
|
||||||
* current method handle to a new type by pairwise argument conversion.
|
* current method handle to a new type
|
||||||
* The original type and new type must have the same number of arguments.
|
* The resulting method handle is guaranteed to report a type
|
||||||
* The resulting method handle is guaranteed to confess a type
|
|
||||||
* which is equal to the desired new type.
|
* which is equal to the desired new type.
|
||||||
* <p>
|
* <p>
|
||||||
* If the original type and new type are equal, returns {@code this}.
|
* If the original type and new type are equal, returns {@code this}.
|
||||||
* <p>
|
* <p>
|
||||||
* This method is equivalent to {@link MethodHandles#convertArguments}.
|
* This method provides the crucial behavioral difference between
|
||||||
|
* {@link #invokeExact invokeExact} and {@link #invokeGeneric invokeGeneric}. The two methods
|
||||||
|
* perform the same steps when the caller's type descriptor is identical
|
||||||
|
* with the callee's, but when the types differ, {@link #invokeGeneric invokeGeneric}
|
||||||
|
* also calls {@code asType} (or some internal equivalent) in order
|
||||||
|
* to match up the caller's and callee's types.
|
||||||
|
* <p>
|
||||||
|
* This method is equivalent to {@link MethodHandles#convertArguments convertArguments},
|
||||||
|
* except for method handles produced by {@link #withTypeHandler withTypeHandler},
|
||||||
|
* in which case the specified type handler is used for calls to {@code asType}.
|
||||||
|
* <p>
|
||||||
|
* Note that the default behavior of {@code asType} only performs
|
||||||
|
* pairwise argument conversion and return value conversion.
|
||||||
|
* Because of this, unless the method handle has a type handler,
|
||||||
|
* the original type and new type must have the same number of arguments.
|
||||||
|
*
|
||||||
* @param newType the expected type of the new method handle
|
* @param newType the expected type of the new method handle
|
||||||
* @return a method handle which delegates to {@code this} after performing
|
* @return a method handle which delegates to {@code this} after performing
|
||||||
* any necessary argument conversions, and arranges for any
|
* any necessary argument conversions, and arranges for any
|
||||||
* necessary return value conversions
|
* necessary return value conversions
|
||||||
* @throws IllegalArgumentException if the conversion cannot be made
|
* @throws WrongMethodTypeException if the conversion cannot be made
|
||||||
* @see MethodHandles#convertArguments
|
* @see MethodHandles#convertArguments
|
||||||
*/
|
*/
|
||||||
public final MethodHandle asType(MethodType newType) {
|
public MethodHandle asType(MethodType newType) {
|
||||||
return MethodHandles.convertArguments(this, newType);
|
return MethodHandles.convertArguments(this, newType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
|
||||||
* Produce a method handle which adapts, as its <i>target</i>,
|
* Produce a method handle which adapts, as its <i>target</i>,
|
||||||
* the current method handle. The type of the adapter will be
|
* the current method handle. The type of the adapter will be
|
||||||
* the same as the type of the target, except that all but the first
|
* the same as the type of the target, except that the final
|
||||||
* {@code keepPosArgs} parameters of the target's type are replaced
|
* {@code arrayLength} parameters of the target's type are replaced
|
||||||
* by a single array parameter of type {@code Object[]}.
|
* by a single array parameter of type {@code arrayType}.
|
||||||
* Thus, if {@code keepPosArgs} is zero, the adapter will take all
|
* <p>
|
||||||
* arguments in a single object array.
|
* If the array element type differs from any of the corresponding
|
||||||
|
* argument types on original target,
|
||||||
|
* the original target is adapted to take the array elements directly,
|
||||||
|
* as if by a call to {@link #asType asType}.
|
||||||
* <p>
|
* <p>
|
||||||
* When called, the adapter replaces a trailing array argument
|
* When called, the adapter replaces a trailing array argument
|
||||||
* by the array's elements, each as its own argument to the target.
|
* by the array's elements, each as its own argument to the target.
|
||||||
* (The order of the arguments is preserved.)
|
* (The order of the arguments is preserved.)
|
||||||
* They are converted pairwise by casting and/or unboxing
|
* They are converted pairwise by casting and/or unboxing
|
||||||
* (as if by {@link MethodHandles#convertArguments})
|
|
||||||
* to the types of the trailing parameters of the target.
|
* to the types of the trailing parameters of the target.
|
||||||
* Finally the target is called.
|
* Finally the target is called.
|
||||||
* What the target eventually returns is returned unchanged by the adapter.
|
* What the target eventually returns is returned unchanged by the adapter.
|
||||||
@ -473,54 +531,67 @@ public abstract class MethodHandle
|
|||||||
* contains exactly enough elements to provide a correct argument count
|
* contains exactly enough elements to provide a correct argument count
|
||||||
* to the target method handle.
|
* to the target method handle.
|
||||||
* (The array may also be null when zero elements are required.)
|
* (The array may also be null when zero elements are required.)
|
||||||
* @param keepPosArgs the number of leading positional arguments to preserve
|
* @param arrayType usually {@code Object[]}, the type of the array argument from which to extract the spread arguments
|
||||||
* @return a new method handle which spreads its final argument,
|
* @param arrayLength the number of arguments to spread from an incoming array argument
|
||||||
|
* @return a new method handle which spreads its final array argument,
|
||||||
* before calling the original method handle
|
* before calling the original method handle
|
||||||
|
* @throws IllegalArgumentException if {@code arrayType} is not an array type
|
||||||
* @throws IllegalArgumentException if target does not have at least
|
* @throws IllegalArgumentException if target does not have at least
|
||||||
* {@code keepPosArgs} parameter types
|
* {@code arrayLength} parameter types
|
||||||
|
* @throws WrongMethodTypeException if the implied {@code asType} call fails
|
||||||
*/
|
*/
|
||||||
public final MethodHandle asSpreader(int keepPosArgs) {
|
public final MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
|
||||||
|
Class<?> arrayElement = arrayType.getComponentType();
|
||||||
|
if (arrayElement == null) throw newIllegalArgumentException("not an array type");
|
||||||
MethodType oldType = type();
|
MethodType oldType = type();
|
||||||
int nargs = oldType.parameterCount();
|
int nargs = oldType.parameterCount();
|
||||||
|
if (nargs < arrayLength) throw newIllegalArgumentException("bad spread array length");
|
||||||
|
int keepPosArgs = nargs - arrayLength;
|
||||||
MethodType newType = oldType.dropParameterTypes(keepPosArgs, nargs);
|
MethodType newType = oldType.dropParameterTypes(keepPosArgs, nargs);
|
||||||
newType = newType.insertParameterTypes(keepPosArgs, Object[].class);
|
newType = newType.insertParameterTypes(keepPosArgs, arrayType);
|
||||||
return MethodHandles.spreadArguments(this, newType);
|
return MethodHandles.spreadArguments(this, newType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
|
||||||
* Produce a method handle which adapts, as its <i>target</i>,
|
* Produce a method handle which adapts, as its <i>target</i>,
|
||||||
* the current method handle. The type of the adapter will be
|
* the current method handle. The type of the adapter will be
|
||||||
* the same as the type of the target, except that a single trailing
|
* the same as the type of the target, except that a single trailing
|
||||||
* array parameter of type {@code Object[]} is replaced by
|
* parameter (usually of type {@code arrayType}) is replaced by
|
||||||
* {@code spreadArrayArgs} parameters of type {@code Object}.
|
* {@code arrayLength} parameters whose type is element type of {@code arrayType}.
|
||||||
* <p>
|
* <p>
|
||||||
* When called, the adapter replaces its trailing {@code spreadArrayArgs}
|
* If the array type differs from the final argument type on original target,
|
||||||
* arguments by a single new {@code Object} array, whose elements
|
* the original target is adapted to take the array type directly,
|
||||||
|
* as if by a call to {@link #asType asType}.
|
||||||
|
* <p>
|
||||||
|
* When called, the adapter replaces its trailing {@code arrayLength}
|
||||||
|
* arguments by a single new array of type {@code arrayType}, whose elements
|
||||||
* comprise (in order) the replaced arguments.
|
* comprise (in order) the replaced arguments.
|
||||||
* Finally the target is called.
|
* Finally the target is called.
|
||||||
* What the target eventually returns is returned unchanged by the adapter.
|
* What the target eventually returns is returned unchanged by the adapter.
|
||||||
* <p>
|
* <p>
|
||||||
* (The array may also be a shared constant when {@code spreadArrayArgs} is zero.)
|
* (The array may also be a shared constant when {@code arrayLength} is zero.)
|
||||||
* @param spreadArrayArgs the number of arguments to spread from the trailing array
|
* @param arrayType usually {@code Object[]}, the type of the array argument which will collect the arguments
|
||||||
|
* @param arrayLength the number of arguments to collect into a new array argument
|
||||||
* @return a new method handle which collects some trailing argument
|
* @return a new method handle which collects some trailing argument
|
||||||
* into an array, before calling the original method handle
|
* into an array, before calling the original method handle
|
||||||
* @throws IllegalArgumentException if the last argument of the target
|
* @throws IllegalArgumentException if {@code arrayType} is not an array type
|
||||||
* is not {@code Object[]}
|
or {@code arrayType} is not assignable to this method handle's trailing parameter type
|
||||||
* @throws IllegalArgumentException if {@code spreadArrayArgs} is not
|
* @throws IllegalArgumentException if {@code arrayLength} is not
|
||||||
* a legal array size
|
* a legal array size
|
||||||
* @deprecated Provisional and unstable; use {@link MethodHandles#collectArguments}.
|
* @throws WrongMethodTypeException if the implied {@code asType} call fails
|
||||||
*/
|
*/
|
||||||
public final MethodHandle asCollector(int spreadArrayArgs) {
|
public final MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
|
||||||
|
Class<?> arrayElement = arrayType.getComponentType();
|
||||||
|
if (arrayElement == null) throw newIllegalArgumentException("not an array type");
|
||||||
MethodType oldType = type();
|
MethodType oldType = type();
|
||||||
int nargs = oldType.parameterCount();
|
int nargs = oldType.parameterCount();
|
||||||
MethodType newType = oldType.dropParameterTypes(nargs-1, nargs);
|
MethodType newType = oldType.dropParameterTypes(nargs-1, nargs);
|
||||||
newType = newType.insertParameterTypes(nargs-1, MethodType.genericMethodType(spreadArrayArgs).parameterArray());
|
newType = newType.insertParameterTypes(nargs-1,
|
||||||
|
java.util.Collections.<Class<?>>nCopies(arrayLength, arrayElement));
|
||||||
return MethodHandles.collectArguments(this, newType);
|
return MethodHandles.collectArguments(this, newType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
|
||||||
* Produce a method handle which binds the given argument
|
* Produce a method handle which binds the given argument
|
||||||
* to the current method handle as <i>target</i>.
|
* to the current method handle as <i>target</i>.
|
||||||
* The type of the bound handle will be
|
* The type of the bound handle will be
|
||||||
@ -541,15 +612,81 @@ public abstract class MethodHandle
|
|||||||
* leading parameter type that is a reference type
|
* leading parameter type that is a reference type
|
||||||
* @throws ClassCastException if {@code x} cannot be converted
|
* @throws ClassCastException if {@code x} cannot be converted
|
||||||
* to the leading parameter type of the target
|
* to the leading parameter type of the target
|
||||||
* @deprecated Provisional and unstable; use {@link MethodHandles#insertArguments}.
|
* @see MethodHandles#insertArguments
|
||||||
*/
|
*/
|
||||||
public final MethodHandle bindTo(Object x) {
|
public final MethodHandle bindTo(Object x) {
|
||||||
return MethodHandles.insertArguments(this, 0, x);
|
return MethodHandles.insertArguments(this, 0, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Implementation of {@link MethodHandleProvider}, which returns {@code this}. */
|
/**
|
||||||
public final MethodHandle asMethodHandle() { return this; }
|
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
||||||
|
* Create a new method handle with the same type as this one,
|
||||||
/** Implementation of {@link MethodHandleProvider}, which returns {@code this.asType(type)}. */
|
* but whose {@code asType} method invokes the given
|
||||||
public final MethodHandle asMethodHandle(MethodType type) { return this.asType(type); }
|
* {@code typeHandler} on this method handle,
|
||||||
|
* instead of the standard {@code MethodHandles.convertArguments}.
|
||||||
|
* <p>
|
||||||
|
* The new method handle will have the same behavior as the
|
||||||
|
* old one when invoked by {@code invokeExact}.
|
||||||
|
* For {@code invokeGeneric} calls which exactly match
|
||||||
|
* the method type, the two method handles will also
|
||||||
|
* have the same behavior.
|
||||||
|
* For other {@code invokeGeneric} calls, the {@code typeHandler}
|
||||||
|
* will control the behavior of the new method handle.
|
||||||
|
* <p>
|
||||||
|
* Thus, a method handle with an {@code asType} handler can
|
||||||
|
* be configured to accept more than one arity of {@code invokeGeneric}
|
||||||
|
* call, and potentially every possible arity.
|
||||||
|
* It can also be configured to supply default values for
|
||||||
|
* optional arguments, when the caller does not specify them.
|
||||||
|
* <p>
|
||||||
|
* The given method handle must take two arguments and return
|
||||||
|
* one result. The result it returns must be a method handle
|
||||||
|
* of exactly the requested type. If the result returned by
|
||||||
|
* the target is null, a {@link NullPointerException} is thrown,
|
||||||
|
* else if the type of the target does not exactly match
|
||||||
|
* the requested type, a {@link WrongMethodTypeException} is thrown.
|
||||||
|
* <p>
|
||||||
|
* A method handle's type handler is not guaranteed to be called every
|
||||||
|
* time its {@code asType} or {@code invokeGeneric} method is called.
|
||||||
|
* If the implementation is faced is able to prove that an equivalent
|
||||||
|
* type handler call has already occurred (on the same two arguments),
|
||||||
|
* it may substitute the result of that previous invocation, without
|
||||||
|
* making a new invocation. Thus, type handlers should not (in general)
|
||||||
|
* perform significant side effects.
|
||||||
|
* <p>
|
||||||
|
* Therefore, the type handler is invoked as if by this code:
|
||||||
|
* <blockquote><pre>
|
||||||
|
* MethodHandle target = this; // original method handle
|
||||||
|
* MethodHandle adapter = ...; // adapted method handle
|
||||||
|
* MethodType requestedType = ...; // argument to asType()
|
||||||
|
* if (type().equals(requestedType))
|
||||||
|
* return adapter;
|
||||||
|
* MethodHandle result = (MethodHandle)
|
||||||
|
* typeHandler.invokeGeneric(target, requestedType);
|
||||||
|
* if (!result.type().equals(requestedType))
|
||||||
|
* throw new WrongMethodTypeException();
|
||||||
|
* return result;
|
||||||
|
* </pre></blockquote>
|
||||||
|
* <p>
|
||||||
|
* For example, here is a list-making variable-arity method handle:
|
||||||
|
* <blockquote><pre>
|
||||||
|
MethodHandle makeEmptyList = MethodHandles.constant(List.class, Arrays.asList());
|
||||||
|
MethodHandle asList = lookup()
|
||||||
|
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class));
|
||||||
|
static MethodHandle collectingTypeHandler(MethodHandle base, MethodType newType) {
|
||||||
|
return asList.asCollector(Object[].class, newType.parameterCount()).asType(newType);
|
||||||
|
}
|
||||||
|
MethodHandle collectingTypeHandler = lookup()
|
||||||
|
.findStatic(lookup().lookupClass(), "collectingTypeHandler",
|
||||||
|
methodType(MethodHandle.class, MethodHandle.class, MethodType.class));
|
||||||
|
MethodHandle makeAnyList = makeEmptyList.withTypeHandler(collectingTypeHandler);
|
||||||
|
|
||||||
|
assertEquals("[]", makeAnyList.invokeGeneric().toString());
|
||||||
|
assertEquals("[1]", makeAnyList.invokeGeneric(1).toString());
|
||||||
|
assertEquals("[two, too]", makeAnyList.invokeGeneric("two", "too").toString());
|
||||||
|
* <pre><blockquote>
|
||||||
|
*/
|
||||||
|
public MethodHandle withTypeHandler(MethodHandle typeHandler) {
|
||||||
|
return MethodHandles.withTypeHandler(this, typeHandler);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package java.dyn;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface for an object to provide a target {@linkplain MethodHandle method handle} to a {@code invokedynamic} instruction.
|
|
||||||
* There are many function-like objects in various Java APIs.
|
|
||||||
* This interface provides a standard way for such function-like objects to be bound
|
|
||||||
* to a dynamic call site, by providing a view of their behavior in the form of a low-level method handle.
|
|
||||||
* <p>
|
|
||||||
* The type {@link MethodHandle} is a concrete class whose implementation
|
|
||||||
* hierarchy (if any) may be tightly coupled to the underlying JVM implementation.
|
|
||||||
* It cannot also serve as a base type for user-defined functional APIs.
|
|
||||||
* For this reason, {@code MethodHandle} cannot be subclassed to add new
|
|
||||||
* behavior to method handles. But this interface can be used to provide
|
|
||||||
* a link between a user-defined function and the {@code invokedynamic}
|
|
||||||
* instruction and the method handle API.
|
|
||||||
*/
|
|
||||||
public interface MethodHandleProvider {
|
|
||||||
/** Produce a method handle which will serve as a behavioral proxy for the current object.
|
|
||||||
* The type and invocation behavior of the proxy method handle are user-defined,
|
|
||||||
* and should have some relation to the intended meaning of the original object itself.
|
|
||||||
* <p>
|
|
||||||
* The current object may have a changeable behavior.
|
|
||||||
* For example, {@link CallSite} has a {@code setTarget} method which changes its invocation.
|
|
||||||
* In such a case, it is <em>incorrect</em> for {@code asMethodHandle} to return
|
|
||||||
* a method handle whose behavior may diverge from that of the current object.
|
|
||||||
* Rather, the returned method handle must stably and permanently access
|
|
||||||
* the behavior of the current object, even if that behavior is changeable.
|
|
||||||
* <p>
|
|
||||||
* The reference identity of the proxy method handle is not guaranteed to
|
|
||||||
* have any particular relation to the reference identity of the object.
|
|
||||||
* In particular, several objects with the same intended meaning could
|
|
||||||
* share a common method handle, or the same object could return different
|
|
||||||
* method handles at different times. In the latter case, the different
|
|
||||||
* method handles should have the same type and invocation behavior,
|
|
||||||
* and be usable from any thread at any time.
|
|
||||||
* In particular, if a MethodHandleProvider is bound to an <code>invokedynamic</code>
|
|
||||||
* call site, the proxy method handle extracted at the time of binding
|
|
||||||
* will be used for an unlimited time, until the call site is rebound.
|
|
||||||
* <p>
|
|
||||||
* The type {@link MethodHandle} itself implements {@code MethodHandleProvider}, and
|
|
||||||
* for this method simply returns {@code this}.
|
|
||||||
*/
|
|
||||||
public MethodHandle asMethodHandle();
|
|
||||||
|
|
||||||
/** Produce a method handle of a given type which will serve as a behavioral proxy for the current object.
|
|
||||||
* As for the no-argument version {@link #asMethodHandle()}, the invocation behavior of the
|
|
||||||
* proxy method handle is user-defined. But the type must be the given type,
|
|
||||||
* or else a {@link WrongMethodTypeException} must be thrown.
|
|
||||||
* <p>
|
|
||||||
* If the current object somehow represents a variadic or overloaded behavior,
|
|
||||||
* the method handle returned for a given type might represent only a subset of
|
|
||||||
* the current object's repertoire of behaviors, which correspond to that type.
|
|
||||||
*/
|
|
||||||
public MethodHandle asMethodHandle(MethodType type) throws WrongMethodTypeException;
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -56,21 +56,33 @@ import static sun.dyn.MemberName.newIllegalArgumentException;
|
|||||||
* <p>
|
* <p>
|
||||||
* This type can be created only by factory methods.
|
* This type can be created only by factory methods.
|
||||||
* All factory methods may cache values, though caching is not guaranteed.
|
* All factory methods may cache values, though caching is not guaranteed.
|
||||||
|
* Some factory methods are static, while others are virtual methods which
|
||||||
|
* modify precursor method types, e.g., by changing a selected parameter.
|
||||||
|
* <p>
|
||||||
|
* Factory methods which operate on groups of parameter types
|
||||||
|
* are systematically presented in two versions, so that both Java arrays and
|
||||||
|
* Java lists can be used to work with groups of parameter types.
|
||||||
|
* The query methods {@code parameterArray} and {@code parameterList}
|
||||||
|
* also provide a choice between arrays and lists.
|
||||||
* <p>
|
* <p>
|
||||||
* {@code MethodType} objects are sometimes derived from bytecode instructions
|
* {@code MethodType} objects are sometimes derived from bytecode instructions
|
||||||
* such as {@code invokedynamic}, specifically from the type descriptor strings associated
|
* such as {@code invokedynamic}, specifically from the type descriptor strings associated
|
||||||
* with the instructions in a class file's constant pool.
|
* with the instructions in a class file's constant pool.
|
||||||
* When this occurs, any classes named in the descriptor strings must be loaded.
|
|
||||||
* (But they need not be initialized.)
|
|
||||||
* This loading may occur at any time before the {@code MethodType} object is first derived.
|
|
||||||
* <p>
|
* <p>
|
||||||
* Like classes and strings, method types can be represented directly
|
* Like classes and strings, method types can also be represented directly
|
||||||
* in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes.
|
* in a class file's constant pool as constants. The may be loaded by an {@code ldc}
|
||||||
* Loading such a constant causes its component classes to be loaded as necessary.
|
* instruction which refers to a suitable {@code CONSTANT_MethodType} constant pool entry.
|
||||||
|
* The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string.
|
||||||
|
* For more details, see the <a href="package-summary.html#mtcon">package summary</a>.
|
||||||
|
* <p>
|
||||||
|
* When the JVM materializes a {@code MethodType} from a descriptor string,
|
||||||
|
* all classes named in the descriptor must be accessible, and will be loaded.
|
||||||
|
* (But the classes need not be initialized, as is the case with a {@code CONSTANT_Class}.)
|
||||||
|
* This loading may occur at any time before the {@code MethodType} object is first derived.
|
||||||
* @author John Rose, JSR 292 EG
|
* @author John Rose, JSR 292 EG
|
||||||
*/
|
*/
|
||||||
public final
|
public final
|
||||||
class MethodType implements java.lang.reflect.Type {
|
class MethodType {
|
||||||
private final Class<?> rtype;
|
private final Class<?> rtype;
|
||||||
private final Class<?>[] ptypes;
|
private final Class<?>[] ptypes;
|
||||||
private MethodTypeForm form; // erased form, plus cached data about primitives
|
private MethodTypeForm form; // erased form, plus cached data about primitives
|
||||||
@ -119,7 +131,7 @@ class MethodType implements java.lang.reflect.Type {
|
|||||||
for (Class<?> ptype : ptypes) {
|
for (Class<?> ptype : ptypes) {
|
||||||
ptype.equals(ptype); // null check
|
ptype.equals(ptype); // null check
|
||||||
if (ptype == void.class)
|
if (ptype == void.class)
|
||||||
throw newIllegalArgumentException("void parameter: "+this);
|
throw newIllegalArgumentException("parameter type cannot be void");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,10 +151,6 @@ class MethodType implements java.lang.reflect.Type {
|
|||||||
MethodType methodType(Class<?> rtype, Class<?>[] ptypes) {
|
MethodType methodType(Class<?> rtype, Class<?>[] ptypes) {
|
||||||
return makeImpl(rtype, ptypes, false);
|
return makeImpl(rtype, ptypes, false);
|
||||||
}
|
}
|
||||||
@Deprecated public static
|
|
||||||
MethodType make(Class<?> rtype, Class<?>[] ptypes) {
|
|
||||||
return methodType(rtype, ptypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. */
|
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. */
|
||||||
public static
|
public static
|
||||||
@ -150,10 +158,6 @@ class MethodType implements java.lang.reflect.Type {
|
|||||||
boolean notrust = false; // random List impl. could return evil ptypes array
|
boolean notrust = false; // random List impl. could return evil ptypes array
|
||||||
return makeImpl(rtype, ptypes.toArray(NO_PTYPES), notrust);
|
return makeImpl(rtype, ptypes.toArray(NO_PTYPES), notrust);
|
||||||
}
|
}
|
||||||
@Deprecated public static
|
|
||||||
MethodType make(Class<?> rtype, List<? extends Class<?>> ptypes) {
|
|
||||||
return methodType(rtype, ptypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||||
* The leading parameter type is prepended to the remaining array.
|
* The leading parameter type is prepended to the remaining array.
|
||||||
@ -165,10 +169,6 @@ class MethodType implements java.lang.reflect.Type {
|
|||||||
System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
|
System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
|
||||||
return makeImpl(rtype, ptypes1, true);
|
return makeImpl(rtype, ptypes1, true);
|
||||||
}
|
}
|
||||||
@Deprecated public static
|
|
||||||
MethodType make(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
|
|
||||||
return methodType(rtype, ptype0, ptypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||||
* The resulting method has no parameter types.
|
* The resulting method has no parameter types.
|
||||||
@ -177,10 +177,6 @@ class MethodType implements java.lang.reflect.Type {
|
|||||||
MethodType methodType(Class<?> rtype) {
|
MethodType methodType(Class<?> rtype) {
|
||||||
return makeImpl(rtype, NO_PTYPES, true);
|
return makeImpl(rtype, NO_PTYPES, true);
|
||||||
}
|
}
|
||||||
@Deprecated public static
|
|
||||||
MethodType make(Class<?> rtype) {
|
|
||||||
return methodType(rtype);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||||
* The resulting method has the single given parameter type.
|
* The resulting method has the single given parameter type.
|
||||||
@ -189,10 +185,6 @@ class MethodType implements java.lang.reflect.Type {
|
|||||||
MethodType methodType(Class<?> rtype, Class<?> ptype0) {
|
MethodType methodType(Class<?> rtype, Class<?> ptype0) {
|
||||||
return makeImpl(rtype, new Class<?>[]{ ptype0 }, true);
|
return makeImpl(rtype, new Class<?>[]{ ptype0 }, true);
|
||||||
}
|
}
|
||||||
@Deprecated public static
|
|
||||||
MethodType make(Class<?> rtype, Class<?> ptype0) {
|
|
||||||
return methodType(rtype, ptype0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||||
* The resulting method has the same parameter types as {@code ptypes},
|
* The resulting method has the same parameter types as {@code ptypes},
|
||||||
@ -202,10 +194,6 @@ class MethodType implements java.lang.reflect.Type {
|
|||||||
MethodType methodType(Class<?> rtype, MethodType ptypes) {
|
MethodType methodType(Class<?> rtype, MethodType ptypes) {
|
||||||
return makeImpl(rtype, ptypes.ptypes, true);
|
return makeImpl(rtype, ptypes.ptypes, true);
|
||||||
}
|
}
|
||||||
@Deprecated public static
|
|
||||||
MethodType make(Class<?> rtype, MethodType ptypes) {
|
|
||||||
return methodType(rtype, ptypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sole factory method to find or create an interned method type.
|
* Sole factory method to find or create an interned method type.
|
||||||
@ -275,10 +263,6 @@ class MethodType implements java.lang.reflect.Type {
|
|||||||
}
|
}
|
||||||
return mt;
|
return mt;
|
||||||
}
|
}
|
||||||
@Deprecated public static
|
|
||||||
MethodType makeGeneric(int objectArgCount, boolean varargs) {
|
|
||||||
return genericMethodType(objectArgCount, varargs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All parameters and the return type will be Object.
|
* All parameters and the return type will be Object.
|
||||||
@ -290,10 +274,6 @@ class MethodType implements java.lang.reflect.Type {
|
|||||||
MethodType genericMethodType(int objectArgCount) {
|
MethodType genericMethodType(int objectArgCount) {
|
||||||
return genericMethodType(objectArgCount, false);
|
return genericMethodType(objectArgCount, false);
|
||||||
}
|
}
|
||||||
@Deprecated public static
|
|
||||||
MethodType makeGeneric(int objectArgCount) {
|
|
||||||
return genericMethodType(objectArgCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||||
* @param num the index (zero-based) of the parameter type to change
|
* @param num the index (zero-based) of the parameter type to change
|
||||||
@ -307,18 +287,6 @@ class MethodType implements java.lang.reflect.Type {
|
|||||||
return makeImpl(rtype, nptypes, true);
|
return makeImpl(rtype, nptypes, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Convenience method for {@link #insertParameterTypes}.
|
|
||||||
* @deprecated Use {@link #insertParameterTypes} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public MethodType insertParameterType(int num, Class<?> nptype) {
|
|
||||||
int len = ptypes.length;
|
|
||||||
Class<?>[] nptypes = Arrays.copyOfRange(ptypes, 0, len+1);
|
|
||||||
System.arraycopy(nptypes, num, nptypes, num+1, len-num);
|
|
||||||
nptypes[num] = nptype;
|
|
||||||
return makeImpl(rtype, nptypes, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||||
* @param num the position (zero-based) of the inserted parameter type(s)
|
* @param num the position (zero-based) of the inserted parameter type(s)
|
||||||
* @param ptypesToInsert zero or more a new parameter types to insert into the parameter list
|
* @param ptypesToInsert zero or more a new parameter types to insert into the parameter list
|
||||||
@ -336,6 +304,22 @@ class MethodType implements java.lang.reflect.Type {
|
|||||||
return makeImpl(rtype, nptypes, true);
|
return makeImpl(rtype, nptypes, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||||
|
* @param ptypesToInsert zero or more a new parameter types to insert after the end of the parameter list
|
||||||
|
* @return the same type, except with the selected parameter(s) appended
|
||||||
|
*/
|
||||||
|
public MethodType appendParameterTypes(Class<?>... ptypesToInsert) {
|
||||||
|
return insertParameterTypes(parameterCount(), ptypesToInsert);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||||
|
* @param ptypesToInsert zero or more a new parameter types to insert after the end of the parameter list
|
||||||
|
* @return the same type, except with the selected parameter(s) appended
|
||||||
|
*/
|
||||||
|
public MethodType appendParameterTypes(List<Class<?>> ptypesToInsert) {
|
||||||
|
return insertParameterTypes(parameterCount(), ptypesToInsert);
|
||||||
|
}
|
||||||
|
|
||||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||||
* @param num the position (zero-based) of the inserted parameter type(s)
|
* @param num the position (zero-based) of the inserted parameter type(s)
|
||||||
* @param ptypesToInsert zero or more a new parameter types to insert into the parameter list
|
* @param ptypesToInsert zero or more a new parameter types to insert into the parameter list
|
||||||
@ -377,14 +361,6 @@ class MethodType implements java.lang.reflect.Type {
|
|||||||
return makeImpl(rtype, nptypes, true);
|
return makeImpl(rtype, nptypes, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Convenience method for {@link #dropParameterTypes}.
|
|
||||||
* @deprecated Use {@link #dropParameterTypes} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public MethodType dropParameterType(int num) {
|
|
||||||
return dropParameterTypes(num, num+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
|
||||||
* @param nrtype a return parameter type to replace the old one with
|
* @param nrtype a return parameter type to replace the old one with
|
||||||
* @return the same type, except with the return type change
|
* @return the same type, except with the return type change
|
||||||
@ -552,7 +528,9 @@ class MethodType implements java.lang.reflect.Type {
|
|||||||
* parenthesis enclosed, comma separated list of type names,
|
* parenthesis enclosed, comma separated list of type names,
|
||||||
* followed immediately by the return type.
|
* followed immediately by the return type.
|
||||||
* <p>
|
* <p>
|
||||||
* If a type name is array, it the base type followed
|
* Each type is represented by its
|
||||||
|
* {@link java.lang.Class#getSimpleName simple name}.
|
||||||
|
* If a type name name is array, it the base type followed
|
||||||
* by [], rather than the Class.getName of the array type.
|
* by [], rather than the Class.getName of the array type.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@ -561,35 +539,13 @@ class MethodType implements java.lang.reflect.Type {
|
|||||||
sb.append("(");
|
sb.append("(");
|
||||||
for (int i = 0; i < ptypes.length; i++) {
|
for (int i = 0; i < ptypes.length; i++) {
|
||||||
if (i > 0) sb.append(",");
|
if (i > 0) sb.append(",");
|
||||||
putName(sb, ptypes[i]);
|
sb.append(ptypes[i].getSimpleName());
|
||||||
}
|
}
|
||||||
sb.append(")");
|
sb.append(")");
|
||||||
putName(sb, rtype);
|
sb.append(rtype.getSimpleName());
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void putName(StringBuilder sb, Class<?> cls) {
|
|
||||||
int brackets = 0;
|
|
||||||
while (cls.isArray()) {
|
|
||||||
cls = cls.getComponentType();
|
|
||||||
brackets++;
|
|
||||||
}
|
|
||||||
String n = cls.getName();
|
|
||||||
/*
|
|
||||||
if (n.startsWith("java.lang.")) {
|
|
||||||
String nb = n.substring("java.lang.".length());
|
|
||||||
if (nb.indexOf('.') < 0) n = nb;
|
|
||||||
} else if (n.indexOf('.') < 0) {
|
|
||||||
n = "."+n; // anonymous package
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
sb.append(n);
|
|
||||||
while (brackets > 0) {
|
|
||||||
sb.append("[]");
|
|
||||||
brackets--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Queries which have to do with the bytecode architecture
|
/// Queries which have to do with the bytecode architecture
|
||||||
|
|
||||||
/** The number of JVM stack slots required to invoke a method
|
/** The number of JVM stack slots required to invoke a method
|
||||||
@ -690,14 +646,4 @@ class MethodType implements java.lang.reflect.Type {
|
|||||||
public String toMethodDescriptorString() {
|
public String toMethodDescriptorString() {
|
||||||
return BytecodeDescriptor.unparse(this);
|
return BytecodeDescriptor.unparse(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Temporary alias for toMethodDescriptorString; delete after M3. */
|
|
||||||
public String toBytecodeString() {
|
|
||||||
return toMethodDescriptorString();
|
|
||||||
}
|
|
||||||
/** Temporary alias for fromMethodDescriptorString; delete after M3. */
|
|
||||||
public static MethodType fromBytecodeString(String descriptor, ClassLoader loader)
|
|
||||||
throws IllegalArgumentException, TypeNotPresentException {
|
|
||||||
return fromMethodDescriptorString(descriptor, loader);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
206
jdk/src/share/classes/java/dyn/MutableCallSite.java
Normal file
206
jdk/src/share/classes/java/dyn/MutableCallSite.java
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package java.dyn;
|
||||||
|
|
||||||
|
import sun.dyn.*;
|
||||||
|
import sun.dyn.empty.Empty;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@code MutableCallSite} is a {@link CallSite} whose target variable
|
||||||
|
* behaves like an ordinary field.
|
||||||
|
* An {@code invokedynamic} instruction linked to a {@code MutableCallSite} delegates
|
||||||
|
* all calls to the site's current target.
|
||||||
|
* The {@linkplain CallSite#dynamicInvoker dynamic invoker} of a mutable call site
|
||||||
|
* also delegates each call to the site's current target.
|
||||||
|
* <p>
|
||||||
|
* Here is an example of a mutable call site which introduces a
|
||||||
|
* state variable into a method handle chain.
|
||||||
|
* <blockquote><pre>
|
||||||
|
MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
|
||||||
|
MethodHandle MH_name = name.dynamicInvoker();
|
||||||
|
MethodType MT_str2 = MethodType.methodType(String.class, String.class);
|
||||||
|
MethodHandle MH_upcase = MethodHandles.lookup()
|
||||||
|
.findVirtual(String.class, "toUpperCase", MT_str2);
|
||||||
|
MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
|
||||||
|
name.setTarget(MethodHandles.constant(String.class, "Rocky"));
|
||||||
|
assertEquals("ROCKY", (String) worker1.invokeExact());
|
||||||
|
name.setTarget(MethodHandles.constant(String.class, "Fred"));
|
||||||
|
assertEquals("FRED", (String) worker1.invokeExact());
|
||||||
|
// (mutation can be continued indefinitely)
|
||||||
|
* </pre></blockquote>
|
||||||
|
* <p>
|
||||||
|
* The same call site may be used in several places at once.
|
||||||
|
* <blockquote><pre>
|
||||||
|
MethodHandle MH_dear = MethodHandles.lookup()
|
||||||
|
.findVirtual(String.class, "concat", MT_str2).bindTo(", dear?");
|
||||||
|
MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear);
|
||||||
|
assertEquals("Fred, dear?", (String) worker2.invokeExact());
|
||||||
|
name.setTarget(MethodHandles.constant(String.class, "Wilma"));
|
||||||
|
assertEquals("WILMA", (String) worker1.invokeExact());
|
||||||
|
assertEquals("Wilma, dear?", (String) worker2.invokeExact());
|
||||||
|
* </pre></blockquote>
|
||||||
|
* <p>
|
||||||
|
* <em>Non-synchronization of target values:</em>
|
||||||
|
* A write to a mutable call site's target does not force other threads
|
||||||
|
* to become aware of the updated value. Threads which do not perform
|
||||||
|
* suitable synchronization actions relative to the updated call site
|
||||||
|
* may cache the old target value and delay their use of the new target
|
||||||
|
* value indefinitely.
|
||||||
|
* (This is a normal consequence of the Java Memory Model as applied
|
||||||
|
* to object fields.)
|
||||||
|
* <p>
|
||||||
|
* The {@link #sync sync} operation provides a way to force threads
|
||||||
|
* to accept a new target value, even if there is no other synchronization.
|
||||||
|
* <p>
|
||||||
|
* For target values which will be frequently updated, consider using
|
||||||
|
* a {@linkplain VolatileCallSite volatile call site} instead.
|
||||||
|
* @author John Rose, JSR 292 EG
|
||||||
|
*/
|
||||||
|
public class MutableCallSite extends CallSite {
|
||||||
|
/**
|
||||||
|
* Make a blank call site object with the given method type.
|
||||||
|
* An initial target method is supplied which will throw
|
||||||
|
* an {@link IllegalStateException} if called.
|
||||||
|
* <p>
|
||||||
|
* Before this {@code CallSite} object is returned from a bootstrap method,
|
||||||
|
* it is usually provided with a more useful target method,
|
||||||
|
* via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
|
||||||
|
* @throws NullPointerException if the proposed type is null
|
||||||
|
*/
|
||||||
|
public MutableCallSite(MethodType type) {
|
||||||
|
super(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a blank call site object, possibly equipped with an initial target method handle.
|
||||||
|
* @param target the method handle which will be the initial target of the call site
|
||||||
|
* @throws NullPointerException if the proposed target is null
|
||||||
|
*/
|
||||||
|
public MutableCallSite(MethodHandle target) {
|
||||||
|
super(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a synchronization operation on each call site in the given array,
|
||||||
|
* forcing all other threads to throw away any cached values previously
|
||||||
|
* loaded from the target of any of the call sites.
|
||||||
|
* <p>
|
||||||
|
* This operation does not reverse any calls that have already started
|
||||||
|
* on an old target value.
|
||||||
|
* (Java supports {@linkplain java.lang.Object#wait() forward time travel} only.)
|
||||||
|
* <p>
|
||||||
|
* The overall effect is to force all future readers of each call site's target
|
||||||
|
* to accept the most recently stored value.
|
||||||
|
* ("Most recently" is reckoned relative to the {@code sync} itself.)
|
||||||
|
* Conversely, the {@code sync} call may block until all readers have
|
||||||
|
* (somehow) decached all previous versions of each call site's target.
|
||||||
|
* <p>
|
||||||
|
* To avoid race conditions, calls to {@code setTarget} and {@code sync}
|
||||||
|
* should generally be performed under some sort of mutual exclusion.
|
||||||
|
* Note that reader threads may observe an updated target as early
|
||||||
|
* as the {@code setTarget} call that install the value
|
||||||
|
* (and before the {@code sync} that confirms the value).
|
||||||
|
* On the other hand, reader threads may observe previous versions of
|
||||||
|
* the target until the {@code sync} call returns
|
||||||
|
* (and after the {@code setTarget} that attempts to convey the updated version).
|
||||||
|
* <p>
|
||||||
|
* In terms of the Java Memory Model, this operation performs a synchronization
|
||||||
|
* action which is comparable in effect to the writing of a volatile variable
|
||||||
|
* by the current thread, and an eventual volatile read by every other thread
|
||||||
|
* that may access one of the affected call sites.
|
||||||
|
* <p>
|
||||||
|
* The following effects are apparent, for each individual call site {@code S}:
|
||||||
|
* <ul>
|
||||||
|
* <li>A new volatile variable {@code V} is created, and written by the current thread.
|
||||||
|
* As defined by the JMM, this write is a global synchronization event.
|
||||||
|
* <li>As is normal with thread-local ordering of write events,
|
||||||
|
* every action already performed by the current thread is
|
||||||
|
* taken to happen before the volatile write to {@code V}.
|
||||||
|
* (In some implementations, this means that the current thread
|
||||||
|
* performs a global release operation.)
|
||||||
|
* <li>Specifically, the write to the current target of {@code S} is
|
||||||
|
* taken to happen before the volatile write to {@code V}.
|
||||||
|
* <li>The volatile write to {@code V} is placed
|
||||||
|
* (in an implementation specific manner)
|
||||||
|
* in the global synchronization order.
|
||||||
|
* <li>Consider an arbitrary thread {@code T} (other than the current thread).
|
||||||
|
* If {@code T} executes a synchronization action {@code A}
|
||||||
|
* after the volatile write to {@code V} (in the global synchronization order),
|
||||||
|
* it is therefore required to see either the current target
|
||||||
|
* of {@code S}, or a later write to that target,
|
||||||
|
* if it executes a read on the target of {@code S}.
|
||||||
|
* (This constraint is called "synchronization-order consistency".)
|
||||||
|
* <li>The JMM specifically allows optimizing compilers to elide
|
||||||
|
* reads or writes of variables that are known to be useless.
|
||||||
|
* Such elided reads and writes have no effect on the happens-before
|
||||||
|
* relation. Regardless of this fact, the volatile {@code V}
|
||||||
|
* will not be elided, even though its written value is
|
||||||
|
* indeterminate and its read value is not used.
|
||||||
|
* </ul>
|
||||||
|
* Because of the last point, the implementation behaves as if a
|
||||||
|
* volatile read of {@code V} were performed by {@code T}
|
||||||
|
* immediately after its action {@code A}. In the local ordering
|
||||||
|
* of actions in {@code T}, this read happens before any future
|
||||||
|
* read of the target of {@code S}. It is as if the
|
||||||
|
* implementation arbitrarily picked a read of {@code S}'s target
|
||||||
|
* by {@code T}, and forced a read of {@code V} to precede it,
|
||||||
|
* thereby ensuring communication of the new target value.
|
||||||
|
* <p>
|
||||||
|
* As long as the constraints of the Java Memory Model are obeyed,
|
||||||
|
* implementations may delay the completion of a {@code sync}
|
||||||
|
* operation while other threads ({@code T} above) continue to
|
||||||
|
* use previous values of {@code S}'s target.
|
||||||
|
* However, implementations are (as always) encouraged to avoid
|
||||||
|
* livelock, and to eventually require all threads to take account
|
||||||
|
* of the updated target.
|
||||||
|
* <p>
|
||||||
|
* This operation is likely to be expensive and should be used sparingly.
|
||||||
|
* If possible, it should be buffered for batch processing on sets of call sites.
|
||||||
|
* <p style="font-size:smaller;">
|
||||||
|
* (This is a static method on a set of call sites, not a
|
||||||
|
* virtual method on a single call site, for performance reasons.
|
||||||
|
* Some implementations may incur a large fixed overhead cost
|
||||||
|
* for processing one or more synchronization operations,
|
||||||
|
* but a small incremental cost for each additional call site.
|
||||||
|
* In any case, this operation is likely to be costly, since
|
||||||
|
* other threads may have to be somehow interrupted
|
||||||
|
* in order to make them notice the updated target value.
|
||||||
|
* However, it may be observed that a single call to synchronize
|
||||||
|
* several sites has the same formal effect as many calls,
|
||||||
|
* each on just one of the sites.)
|
||||||
|
* <p>
|
||||||
|
* Simple implementations of {@code MutableCallSite} may use
|
||||||
|
* a volatile variable for the target of a mutable call site.
|
||||||
|
* In such an implementation, the {@code sync} method can be a no-op,
|
||||||
|
* and yet it will conform to the JMM behavior documented above.
|
||||||
|
*/
|
||||||
|
public static void sync(MutableCallSite[] sites) {
|
||||||
|
STORE_BARRIER.lazySet(0);
|
||||||
|
// FIXME: NYI
|
||||||
|
}
|
||||||
|
private static final AtomicInteger STORE_BARRIER = new AtomicInteger();
|
||||||
|
}
|
130
jdk/src/share/classes/java/dyn/Switcher.java
Normal file
130
jdk/src/share/classes/java/dyn/Switcher.java
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package java.dyn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* A {@code Switcher} is an object which can publish state transitions to other threads.
|
||||||
|
* A switcher is initially in the <em>valid</em> state, but may at any time be
|
||||||
|
* changed to the <em>invalid</em> state. Invalidation cannot be reversed.
|
||||||
|
* <p>
|
||||||
|
* A single switcher may be used to create any number of guarded method handle pairs.
|
||||||
|
* Each guarded pair is wrapped in a new method handle {@code M},
|
||||||
|
* which is permanently associated with the switcher that created it.
|
||||||
|
* Each pair consists of a target {@code T} and a fallback {@code F}.
|
||||||
|
* While the switcher is valid, invocations to {@code M} are delegated to {@code T}.
|
||||||
|
* After it is invalidated, invocations are delegated to {@code F}.
|
||||||
|
* <p>
|
||||||
|
* Invalidation is global and immediate, as if the switcher contained a
|
||||||
|
* volatile boolean variable consulted on every call to {@code M}.
|
||||||
|
* The invalidation is also permanent, which means the switcher
|
||||||
|
* can change state only once.
|
||||||
|
* <p>
|
||||||
|
* Here is an example of a switcher in action:
|
||||||
|
* <blockquote><pre>
|
||||||
|
MethodType MT_str2 = MethodType.methodType(String.class, String.class);
|
||||||
|
MethodHandle MH_strcat = MethodHandles.lookup()
|
||||||
|
.findVirtual(String.class, "concat", MT_str2);
|
||||||
|
Switcher switcher = new Switcher();
|
||||||
|
// the following steps may be repeated to re-use the same switcher:
|
||||||
|
MethodHandle worker1 = strcat;
|
||||||
|
MethodHandle worker2 = MethodHandles.permuteArguments(strcat, MT_str2, 1, 0);
|
||||||
|
MethodHandle worker = switcher.guardWithTest(worker1, worker2);
|
||||||
|
assertEquals("method", (String) worker.invokeExact("met", "hod"));
|
||||||
|
switcher.invalidate();
|
||||||
|
assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
|
||||||
|
* </pre></blockquote>
|
||||||
|
* <p>
|
||||||
|
* <em>Implementation Note:</em>
|
||||||
|
* A switcher behaves as if implemented on top of {@link MutableCallSite},
|
||||||
|
* approximately as follows:
|
||||||
|
* <blockquote><pre>
|
||||||
|
public class Switcher {
|
||||||
|
private static final MethodHandle
|
||||||
|
K_true = MethodHandles.constant(boolean.class, true),
|
||||||
|
K_false = MethodHandles.constant(boolean.class, false);
|
||||||
|
private final MutableCallSite mcs;
|
||||||
|
private final MethodHandle mcsInvoker;
|
||||||
|
public Switcher() {
|
||||||
|
this.mcs = new MutableCallSite(K_true);
|
||||||
|
this.mcsInvoker = mcs.dynamicInvoker();
|
||||||
|
}
|
||||||
|
public MethodHandle guardWithTest(
|
||||||
|
MethodHandle target, MethodHandle fallback) {
|
||||||
|
// Note: mcsInvoker is of type boolean().
|
||||||
|
// Target and fallback may take any arguments, but must have the same type.
|
||||||
|
return MethodHandles.guardWithTest(this.mcsInvoker, target, fallback);
|
||||||
|
}
|
||||||
|
public static void invalidateAll(Switcher[] switchers) {
|
||||||
|
List<MutableCallSite> mcss = new ArrayList<>();
|
||||||
|
for (Switcher s : switchers) mcss.add(s.mcs);
|
||||||
|
for (MutableCallSite mcs : mcss) mcs.setTarget(K_false);
|
||||||
|
MutableCallSite.sync(mcss.toArray(new MutableCallSite[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
* </pre></blockquote>
|
||||||
|
* @author Remi Forax, JSR 292 EG
|
||||||
|
*/
|
||||||
|
public class Switcher {
|
||||||
|
private static final MethodHandle
|
||||||
|
K_true = MethodHandles.constant(boolean.class, true),
|
||||||
|
K_false = MethodHandles.constant(boolean.class, false);
|
||||||
|
|
||||||
|
private final MutableCallSite mcs;
|
||||||
|
private final MethodHandle mcsInvoker;
|
||||||
|
|
||||||
|
/** Create a switcher. */
|
||||||
|
public Switcher() {
|
||||||
|
this.mcs = new MutableCallSite(K_true);
|
||||||
|
this.mcsInvoker = mcs.dynamicInvoker();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a method handle which always delegates either to the target or the fallback.
|
||||||
|
* The method handle will delegate to the target exactly as long as the switcher is valid.
|
||||||
|
* After that, it will permanently delegate to the fallback.
|
||||||
|
* <p>
|
||||||
|
* The target and fallback must be of exactly the same method type,
|
||||||
|
* and the resulting combined method handle will also be of this type.
|
||||||
|
* @see MethodHandles#guardWithTest
|
||||||
|
*/
|
||||||
|
public MethodHandle guardWithTest(MethodHandle target, MethodHandle fallback) {
|
||||||
|
if (mcs.getTarget() == K_false)
|
||||||
|
return fallback; // already invalid
|
||||||
|
return MethodHandles.guardWithTest(mcsInvoker, target, fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set all of the given switchers into the invalid state. */
|
||||||
|
public static void invalidateAll(Switcher[] switchers) {
|
||||||
|
MutableCallSite[] sites = new MutableCallSite[switchers.length];
|
||||||
|
int fillp = 0;
|
||||||
|
for (Switcher switcher : switchers) {
|
||||||
|
sites[fillp++] = switcher.mcs;
|
||||||
|
switcher.mcs.setTarget(K_false);
|
||||||
|
}
|
||||||
|
MutableCallSite.sync(sites);
|
||||||
|
}
|
||||||
|
}
|
79
jdk/src/share/classes/java/dyn/VolatileCallSite.java
Normal file
79
jdk/src/share/classes/java/dyn/VolatileCallSite.java
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package java.dyn;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@code VolatileCallSite} is a {@link CallSite} whose target acts like a volatile variable.
|
||||||
|
* An {@code invokedynamic} instruction linked to a {@code VolatileCallSite} sees updates
|
||||||
|
* to its call site target immediately, even if the update occurs in another thread.
|
||||||
|
* There may be a performance penalty for such tight coupling between threads.
|
||||||
|
* <p>
|
||||||
|
* Unlike {@code MutableCallSite}, there is no
|
||||||
|
* {@linkplain MutableCallSite#sync sync operation} on volatile
|
||||||
|
* call sites, since every write to a volatile variable is implicitly
|
||||||
|
* synchronized with reader threads.
|
||||||
|
* <p>
|
||||||
|
* In other respects, a {@code VolatileCallSite} is interchangeable
|
||||||
|
* with {@code MutableCallSite}.
|
||||||
|
* @see MutableCallSite
|
||||||
|
* @author John Rose, JSR 292 EG
|
||||||
|
*/
|
||||||
|
public class VolatileCallSite extends CallSite {
|
||||||
|
/** Create a call site with a volatile target.
|
||||||
|
* The initial target is set to a method handle
|
||||||
|
* of the given type which will throw {@code IllegalStateException}.
|
||||||
|
* @throws NullPointerException if the proposed type is null
|
||||||
|
*/
|
||||||
|
public VolatileCallSite(MethodType type) {
|
||||||
|
super(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create a call site with a volatile target.
|
||||||
|
* The target is set to the given value.
|
||||||
|
* @throws NullPointerException if the proposed target is null
|
||||||
|
*/
|
||||||
|
public VolatileCallSite(MethodHandle target) {
|
||||||
|
super(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Internal override to nominally final getTarget. */
|
||||||
|
@Override
|
||||||
|
MethodHandle getTarget0() {
|
||||||
|
return getTargetVolatile();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the target method of this call site, as a volatile variable.
|
||||||
|
* Has the same effect as {@link CallSite#setTarget CallSite.setTarget}, with the additional
|
||||||
|
* effects associated with volatiles, in the Java Memory Model.
|
||||||
|
*/
|
||||||
|
@Override public void setTarget(MethodHandle newTarget) {
|
||||||
|
checkTargetChange(getTargetVolatile(), newTarget);
|
||||||
|
setTargetVolatile(newTarget);
|
||||||
|
}
|
||||||
|
}
|
@ -24,7 +24,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
|
||||||
* This package contains dynamic language support provided directly by
|
* This package contains dynamic language support provided directly by
|
||||||
* the Java core class libraries and virtual machine.
|
* the Java core class libraries and virtual machine.
|
||||||
* <p>
|
* <p>
|
||||||
@ -42,13 +41,6 @@
|
|||||||
* argument and return value conversions are applied.
|
* argument and return value conversions are applied.
|
||||||
* </li>
|
* </li>
|
||||||
*
|
*
|
||||||
* <li>In source code, the class {@link java.dyn.InvokeDynamic InvokeDynamic} appears to accept
|
|
||||||
* any static method invocation, of any name and any signature.
|
|
||||||
* But instead of emitting
|
|
||||||
* an {@code invokestatic} instruction for such a call, the Java compiler emits
|
|
||||||
* an {@code invokedynamic} instruction with the given name and signature.
|
|
||||||
* </li>
|
|
||||||
*
|
|
||||||
* <li>The JVM bytecode format supports immediate constants of
|
* <li>The JVM bytecode format supports immediate constants of
|
||||||
* the classes {@link java.dyn.MethodHandle MethodHandle} and {@link java.dyn.MethodType MethodType}.
|
* the classes {@link java.dyn.MethodHandle MethodHandle} and {@link java.dyn.MethodType MethodType}.
|
||||||
* </li>
|
* </li>
|
||||||
@ -56,51 +48,68 @@
|
|||||||
*
|
*
|
||||||
* <h2><a name="jvm_mods"></a>Corresponding JVM bytecode format changes</h2>
|
* <h2><a name="jvm_mods"></a>Corresponding JVM bytecode format changes</h2>
|
||||||
* <em>The following low-level information is presented here as a preview of
|
* <em>The following low-level information is presented here as a preview of
|
||||||
* changes being made to the Java Virtual Machine specification for JSR 292.</em>
|
* changes being made to the Java Virtual Machine specification for JSR 292.
|
||||||
|
* This information will be incorporated in a future version of the JVM specification.</em>
|
||||||
*
|
*
|
||||||
* <h3>{@code invokedynamic} instruction format</h3>
|
* <h3><a name="indyinsn"></a>{@code invokedynamic} instruction format</h3>
|
||||||
* In bytecode, an {@code invokedynamic} instruction is formatted as five bytes.
|
* In bytecode, an {@code invokedynamic} instruction is formatted as five bytes.
|
||||||
* The first byte is the opcode 186 (hexadecimal {@code BA}).
|
* The first byte is the opcode 186 (hexadecimal {@code BA}).
|
||||||
* The next two bytes are a constant pool index (in the same format as for the other {@code invoke} instructions).
|
* The next two bytes are a constant pool index (in the same format as for the other {@code invoke} instructions).
|
||||||
* The final two bytes are reserved for future use and required to be zero.
|
* The final two bytes are reserved for future use and required to be zero.
|
||||||
* The constant pool reference of an {@code invokedynamic} instruction is to a entry
|
* The constant pool reference of an {@code invokedynamic} instruction is to a entry
|
||||||
* with tag {@code CONSTANT_InvokeDynamic} (decimal 17). See below for its format.
|
* with tag {@code CONSTANT_InvokeDynamic} (decimal 18). See below for its format.
|
||||||
* The entry specifies the bootstrap method (a {@link java.dyn.MethodHandle MethodHandle} constant),
|
* (The tag value 17 is also temporarily allowed. See below.)
|
||||||
* the dynamic invocation name, and the argument types and return type of the call.
|
* The entry specifies the following information:
|
||||||
|
* <ul>
|
||||||
|
* <li>a bootstrap method (a {@link java.dyn.MethodHandle MethodHandle} constant)</li>
|
||||||
|
* <li>the dynamic invocation name (a UTF8 string)</li>
|
||||||
|
* <li>the argument and return types of the call (encoded as a signature in a UTF8 string)</li>
|
||||||
|
* <li>optionally, a sequence of additional <em>static arguments</em> to the bootstrap method ({@code ldc}-type constants)</li>
|
||||||
|
* </ul>
|
||||||
* <p>
|
* <p>
|
||||||
* Each instance of an {@code invokedynamic} instruction is called a <em>dynamic call site</em>.
|
* Each instance of an {@code invokedynamic} instruction is called a <em>dynamic call site</em>.
|
||||||
* Multiple instances of an {@code invokedynamic} instruction can share a single
|
* Multiple instances of an {@code invokedynamic} instruction can share a single
|
||||||
* {@code CONSTANT_InvokeDynamic} entry.
|
* {@code CONSTANT_InvokeDynamic} entry.
|
||||||
* In any case, distinct call sites always have distinct linkage state.
|
* In any case, distinct call sites always have distinct linkage state.
|
||||||
* <p>
|
* <p>
|
||||||
* Moreover, for the purpose of distinguishing dynamic call sites,
|
|
||||||
* the JVM is allowed (but not required) to make internal copies
|
|
||||||
* of {@code invokedynamic} instructions, each one
|
|
||||||
* constituting a separate dynamic call site with its own linkage state.
|
|
||||||
* Such copying, if it occurs, cannot be observed except indirectly via
|
|
||||||
* execution of bootstrap methods and target methods.
|
|
||||||
* <p>
|
|
||||||
* A dynamic call site is originally in an unlinked state. In this state, there is
|
* A dynamic call site is originally in an unlinked state. In this state, there is
|
||||||
* no target method for the call site to invoke.
|
* no target method for the call site to invoke.
|
||||||
* A dynamic call site is linked by means of a bootstrap method,
|
* A dynamic call site is linked by means of a bootstrap method,
|
||||||
* as <a href="#bsm">described below</a>.
|
* as <a href="#bsm">described below</a>.
|
||||||
* <p>
|
|
||||||
* <em>(Historic Note: Some older JVMs may allow the index of a {@code CONSTANT_NameAndType}
|
|
||||||
* instead of a {@code CONSTANT_InvokeDynamic}. In earlier, obsolete versions of this API, the
|
|
||||||
* bootstrap method was specified dynamically, in a per-class basis, during class initialization.)</em>
|
|
||||||
*
|
*
|
||||||
* <h3>constant pool entries for {@code invokedynamic} instructions</h3>
|
* <p style="font-size:smaller;">
|
||||||
* If a constant pool entry has the tag {@code CONSTANT_InvokeDynamic} (decimal 17),
|
* (Historic Note: Some older JVMs may allow the index of a {@code CONSTANT_NameAndType}
|
||||||
* it must contain exactly four more bytes.
|
* instead of a {@code CONSTANT_InvokeDynamic}. In earlier, obsolete versions of this API, the
|
||||||
* The first two bytes after the tag must be an index to a {@code CONSTANT_MethodHandle}
|
* bootstrap method was specified dynamically, in a per-class basis, during class initialization.)
|
||||||
* entry, and the second two bytes must be an index to a {@code CONSTANT_NameAndType}.
|
*
|
||||||
|
* <h3><a name="indycon"></a>constant pool entries for {@code invokedynamic} instructions</h3>
|
||||||
|
* If a constant pool entry has the tag {@code CONSTANT_InvokeDynamic} (decimal 18),
|
||||||
|
* it must contain exactly four more bytes after the tag.
|
||||||
|
* These bytes are interpreted as two 16-bit indexes, in the usual {@code u2} format.
|
||||||
|
* The first pair of bytes after the tag must be an index into a side table called the
|
||||||
|
* <em>bootstrap method table</em>, which is stored in the {@code BootstrapMethods}
|
||||||
|
* attribute as <a href="#bsmattr">described below</a>.
|
||||||
|
* The second pair of bytes must be an index to a {@code CONSTANT_NameAndType}.
|
||||||
|
* This table is not part of the constant pool. Instead, it is stored
|
||||||
|
* in a class attribute named {@code BootstrapMethods}, described below.
|
||||||
|
* <p>
|
||||||
* The first index specifies a bootstrap method used by the associated dynamic call sites.
|
* The first index specifies a bootstrap method used by the associated dynamic call sites.
|
||||||
* The second index specifies the method name, argument types, and return type of the dynamic call site.
|
* The second index specifies the method name, argument types, and return type of the dynamic call site.
|
||||||
* The structure of such an entry is therefore analogous to a {@code CONSTANT_Methodref},
|
* The structure of such an entry is therefore analogous to a {@code CONSTANT_Methodref},
|
||||||
* except that the {@code CONSTANT_Class} reference in a {@code CONSTANT_Methodref} entry
|
* except that the bootstrap method specifier reference replaces
|
||||||
* is replaced by a bootstrap method reference.
|
* the {@code CONSTANT_Class} reference of a {@code CONSTANT_Methodref} entry.
|
||||||
|
* <p>
|
||||||
|
* Some older JVMs may allow an older constant pool entry tag of decimal 17.
|
||||||
|
* The format and behavior of a constant pool entry with this tag is identical to
|
||||||
|
* an entry with a tag of decimal 18, except that the first index refers directly
|
||||||
|
* to a {@code CONSTANT_MethodHandle} to use as the bootstrap method.
|
||||||
|
* This format does not require the bootstrap method table.
|
||||||
*
|
*
|
||||||
* <h3>constant pool entries for {@code MethodType}s</h3>
|
* <p style="font-size:smaller;">
|
||||||
|
* <em>(Note: The Proposed Final Draft of this specification is likely to support
|
||||||
|
* only the tag 18, not the tag 17.)</em>
|
||||||
|
*
|
||||||
|
* <h3><a name="mtcon"></a>constant pool entries for {@linkplain java.dyn.MethodType method types}</h3>
|
||||||
* If a constant pool entry has the tag {@code CONSTANT_MethodType} (decimal 16),
|
* If a constant pool entry has the tag {@code CONSTANT_MethodType} (decimal 16),
|
||||||
* it must contain exactly two more bytes, which must be an index to a {@code CONSTANT_Utf8}
|
* it must contain exactly two more bytes, which must be an index to a {@code CONSTANT_Utf8}
|
||||||
* entry which represents a method type signature.
|
* entry which represents a method type signature.
|
||||||
@ -113,7 +122,7 @@
|
|||||||
* Access checking and error reporting is performed exactly as it is for
|
* Access checking and error reporting is performed exactly as it is for
|
||||||
* references by {@code ldc} instructions to {@code CONSTANT_Class} constants.
|
* references by {@code ldc} instructions to {@code CONSTANT_Class} constants.
|
||||||
*
|
*
|
||||||
* <h3>constant pool entries for {@code MethodHandle}s</h3>
|
* <h3><a name="mhcon"></a>constant pool entries for {@linkplain java.dyn.MethodHandle method handles}</h3>
|
||||||
* If a constant pool entry has the tag {@code CONSTANT_MethodHandle} (decimal 15),
|
* If a constant pool entry has the tag {@code CONSTANT_MethodHandle} (decimal 15),
|
||||||
* it must contain exactly three more bytes. The first byte after the tag is a subtag
|
* it must contain exactly three more bytes. The first byte after the tag is a subtag
|
||||||
* value which must be in the range 1 through 9, and the last two must be an index to a
|
* value which must be in the range 1 through 9, and the last two must be an index to a
|
||||||
@ -129,7 +138,7 @@
|
|||||||
* <p>
|
* <p>
|
||||||
* As with {@code CONSTANT_Class} and {@code CONSTANT_MethodType} constants,
|
* As with {@code CONSTANT_Class} and {@code CONSTANT_MethodType} constants,
|
||||||
* the {@code Class} or {@code MethodType} object which reifies the field or method's
|
* the {@code Class} or {@code MethodType} object which reifies the field or method's
|
||||||
* type is created. Any classes mentioned in this reificaiton will be loaded if necessary,
|
* type is created. Any classes mentioned in this reification will be loaded if necessary,
|
||||||
* but not initialized, and access checking and error reporting performed as usual.
|
* but not initialized, and access checking and error reporting performed as usual.
|
||||||
* <p>
|
* <p>
|
||||||
* The method handle itself will have a type and behavior determined by the subtag as follows:
|
* The method handle itself will have a type and behavior determined by the subtag as follows:
|
||||||
@ -148,16 +157,45 @@
|
|||||||
* </table>
|
* </table>
|
||||||
* </code>
|
* </code>
|
||||||
* <p>
|
* <p>
|
||||||
* The special names {@code <init>} and {@code <clinit>} are not allowed except for subtag 8 as shown.
|
* The special name {@code <clinit>} is not allowed.
|
||||||
|
* The special name {@code <init>} is not allowed except for subtag 8 as shown.
|
||||||
* <p>
|
* <p>
|
||||||
* The verifier applies the same access checks and restrictions for these references as for the hypothetical
|
* The JVM verifier and linker apply the same access checks and restrictions for these references as for the hypothetical
|
||||||
* bytecode instructions specified in the last column of the table. In particular, method handles to
|
* bytecode instructions specified in the last column of the table. In particular, method handles to
|
||||||
* private and protected members can be created in exactly those classes for which the corresponding
|
* private and protected members can be created in exactly those classes for which the corresponding
|
||||||
* normal accesses are legal.
|
* normal accesses are legal.
|
||||||
* <p>
|
* <p>
|
||||||
* None of these constant types force class initialization.
|
* A constant may refer to a method or constructor with the {@code varargs}
|
||||||
* Method handles for subtags {@code REF_getStatic}, {@code REF_putStatic}, and {@code REF_invokeStatic}
|
* bit (hexadecimal {@code 80}) set in its modifier bitmask.
|
||||||
|
* The method handle constant produced for such a method behaves the same
|
||||||
|
* as if the {@code varargs} bit were not set.
|
||||||
|
* The argument-collecting behavior of {@code varargs} can be emulated by
|
||||||
|
* adapting the method handle constant with
|
||||||
|
* {@link java.dyn.MethodHandle#asCollector asCollector}.
|
||||||
|
* There is no provision for doing this automatically.
|
||||||
|
* <p>
|
||||||
|
* Although the {@code CONSTANT_MethodHandle} and {@code CONSTANT_MethodType} constant types
|
||||||
|
* resolve class names, they do not force class initialization.
|
||||||
|
* Method handle constants for subtags {@code REF_getStatic}, {@code REF_putStatic}, and {@code REF_invokeStatic}
|
||||||
* may force class initialization on their first invocation, just like the corresponding bytecodes.
|
* may force class initialization on their first invocation, just like the corresponding bytecodes.
|
||||||
|
* <p>
|
||||||
|
* The rules of section 5.4.3 of the
|
||||||
|
* <a href="http://java.sun.com/docs/books/jvms/second_edition/html/ConstantPool.doc.html#73492">JVM Specification</a>
|
||||||
|
* apply to the resolution of {@code CONSTANT_MethodType}, {@code CONSTANT_MethodHandle},
|
||||||
|
* and {@code CONSTANT_InvokeDynamic} constants,
|
||||||
|
* by the execution of {@code invokedynamic} and {@code ldc} instructions.
|
||||||
|
* (Roughly speaking, this means that every use of a constant pool entry
|
||||||
|
* must lead to the same outcome.
|
||||||
|
* If the resoultion succeeds, the same object reference is produced
|
||||||
|
* by every subsequent execution of the same instruction.
|
||||||
|
* If the resolution of the constant causes an error to occur,
|
||||||
|
* the same error will be re-thrown on every subsequent attempt
|
||||||
|
* to use this particular constant.)
|
||||||
|
* <p>
|
||||||
|
* Constants created by the resolution of these constant pool types are not necessarily
|
||||||
|
* interned. Except for {@link CONSTANT_Class} and {@link CONSTANT_String} entries,
|
||||||
|
* two distinct constant pool entries might not resolve to the same reference
|
||||||
|
* even if they contain the same symbolic reference.
|
||||||
*
|
*
|
||||||
* <h2><a name="bsm"></a>Bootstrap Methods</h2>
|
* <h2><a name="bsm"></a>Bootstrap Methods</h2>
|
||||||
* Before the JVM can execute a dynamic call site (an {@code invokedynamic} instruction),
|
* Before the JVM can execute a dynamic call site (an {@code invokedynamic} instruction),
|
||||||
@ -181,24 +219,36 @@
|
|||||||
* call site execution.
|
* call site execution.
|
||||||
* Linkage does not trigger class initialization.
|
* Linkage does not trigger class initialization.
|
||||||
* <p>
|
* <p>
|
||||||
* Next, the bootstrap method call is started, with four values being stacked:
|
* Next, the bootstrap method call is started, with four or five values being stacked:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>a {@code MethodHandle}, the resolved bootstrap method itself </li>
|
* <li>a {@code MethodHandle}, the resolved bootstrap method itself </li>
|
||||||
* <li>a {@code Class}, the <em>caller class</em> in which dynamic call site occurs </li>
|
* <li>a {@code MethodHandles.Lookup}, a lookup object on the <em>caller class</em> in which dynamic call site occurs </li>
|
||||||
* <li>a {@code String}, the method name mentioned in the call site </li>
|
* <li>a {@code String}, the method name mentioned in the call site </li>
|
||||||
* <li>a {@code MethodType}, the resolved type signature of the call </li>
|
* <li>a {@code MethodType}, the resolved type signature of the call </li>
|
||||||
|
* <li>optionally, a single object representing one or more <a href="#args">additional static arguments</a> </li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* The method handle is then applied to the other values as if by
|
* The method handle is then applied to the other values as if by
|
||||||
* {@linkplain java.dyn.MethodHandle#invokeGeneric the <code>invokeGeneric</code> method}.
|
* {@link java.dyn.MethodHandle#invokeGeneric invokeGeneric}.
|
||||||
* The returned result must be a {@link java.dyn.CallSite CallSite}, a {@link java.dyn.MethodHandle MethodHandle},
|
* The returned result must be a {@link java.dyn.CallSite CallSite} (or a subclass).
|
||||||
* or another {@link java.dyn.MethodHandleProvider MethodHandleProvider} value.
|
* The type of the call site's target must be exactly equal to the type
|
||||||
* The method {@linkplain java.dyn.MethodHandleProvider#asMethodHandle asMethodHandle}
|
|
||||||
* is then called on the returned value. The result of that second
|
|
||||||
* call is the {@code MethodHandle} which becomes the
|
|
||||||
* permanent binding for the dynamic call site.
|
|
||||||
* That method handle's type must be exactly equal to the type
|
|
||||||
* derived from the dynamic call site signature and passed to
|
* derived from the dynamic call site signature and passed to
|
||||||
* the bootstrap method.
|
* the bootstrap method.
|
||||||
|
* The call site then becomes permanently linked to the dynamic call site.
|
||||||
|
* <p>
|
||||||
|
* As long as each bootstrap method can be correctly invoked
|
||||||
|
* by <code>invokeGeneric</code>, its detailed type is arbitrary.
|
||||||
|
* For example, the first argument could be {@code Object}
|
||||||
|
* instead of {@code MethodHandles.Lookup}, and the return type
|
||||||
|
* could also be {@code Object} instead of {@code CallSite}.
|
||||||
|
* <p>
|
||||||
|
* As with any method handle constant, a {@code varargs} modifier bit
|
||||||
|
* on the bootstrap method is ignored.
|
||||||
|
* <p>
|
||||||
|
* Note that the first argument of the bootstrap method cannot be
|
||||||
|
* a simple {@code Class} reference. (This is a change from earlier
|
||||||
|
* versions of this specification. If the caller class is needed,
|
||||||
|
* it is easy to {@linkplain java.dyn.MethodHandles.Lookup#lookupClass() extract it}
|
||||||
|
* from the {@code Lookup} object.)
|
||||||
* <p>
|
* <p>
|
||||||
* After resolution, the linkage process may fail in a variety of ways.
|
* After resolution, the linkage process may fail in a variety of ways.
|
||||||
* All failures are reported by an {@link java.dyn.InvokeDynamicBootstrapError InvokeDynamicBootstrapError},
|
* All failures are reported by an {@link java.dyn.InvokeDynamicBootstrapError InvokeDynamicBootstrapError},
|
||||||
@ -206,81 +256,209 @@
|
|||||||
* site execution.
|
* site execution.
|
||||||
* The following circumstances will cause this:
|
* The following circumstances will cause this:
|
||||||
* <ul>
|
* <ul>
|
||||||
|
* <li>the index to the bootstrap method specifier is out of range </li>
|
||||||
|
* <li>the bootstrap method cannot be resolved </li>
|
||||||
|
* <li>the {@code MethodType} to pass to the bootstrap method cannot be resolved </li>
|
||||||
|
* <li>a static argument to the bootstrap method cannot be resolved
|
||||||
|
* (i.e., a {@code CONSTANT_Class}, {@code CONSTANT_MethodType},
|
||||||
|
* or {@code CONSTANT_MethodHandle} argument cannot be linked) </li>
|
||||||
|
* <li>the bootstrap method has the wrong arity,
|
||||||
|
* causing {@code invokeGeneric} to throw {@code WrongMethodTypeException} </li>
|
||||||
|
* <li>the bootstrap method has a wrong argument or return type </li>
|
||||||
* <li>the bootstrap method invocation completes abnormally </li>
|
* <li>the bootstrap method invocation completes abnormally </li>
|
||||||
* <li>the result from the bootstrap invocation is not a reference to
|
* <li>the result from the bootstrap invocation is not a reference to
|
||||||
* an object of type {@link java.dyn.MethodHandleProvider MethodHandleProvider} </li>
|
* an object of type {@link java.dyn.CallSite CallSite} </li>
|
||||||
* <li>the call to {@code asMethodHandle} completes abnormally </li>
|
* <li>the target of the {@code CallSite} does not have a target of
|
||||||
* <li>the call to {@code asMethodHandle} fails to return a reference to
|
|
||||||
* an object of type {@link java.dyn.MethodHandle MethodHandle} </li>
|
|
||||||
* <li>the method handle produced by {@code asMethodHandle} does not have
|
|
||||||
* the expected {@code MethodType} </li>
|
* the expected {@code MethodType} </li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* <h3>timing of linkage</h3>
|
*
|
||||||
|
* <h3><a name="linktime"></a>timing of linkage</h3>
|
||||||
* A dynamic call site is linked just before its first execution.
|
* A dynamic call site is linked just before its first execution.
|
||||||
* The bootstrap method call implementing the linkage occurs within
|
* The bootstrap method call implementing the linkage occurs within
|
||||||
* a thread that is attempting a first execution.
|
* a thread that is attempting a first execution.
|
||||||
* <p>
|
* <p>
|
||||||
* If there are several such threads, the JVM picks one thread
|
* If there are several such threads, the bootstrap method may be
|
||||||
* and runs the bootstrap method while the others wait for the
|
* invoked in several threads concurrently.
|
||||||
* invocation to terminate normally or abnormally.
|
* Therefore, bootstrap methods which access global application
|
||||||
* <p>
|
* data must take the usual precautions against race conditions.
|
||||||
* After a bootstrap method is called and a method handle target
|
* In any case, every {@code invokedynamic} instruction is either
|
||||||
* successfully extracted, the JVM attempts to link the instruction
|
* unlinked or linked to a unique {@code CallSite} object.
|
||||||
* being executed to the target method handle.
|
|
||||||
* This may fail if there has been intervening linkage
|
|
||||||
* or invalidation event for the same instruction.
|
|
||||||
* If such a failure occurs, the dynamic call site must be
|
|
||||||
* re-executed from the beginning, either re-linking it
|
|
||||||
* (if it has been invalidated) or invoking the target
|
|
||||||
* (if it the instruction has been linked by some other means).
|
|
||||||
* <p>
|
|
||||||
* If the instruction is linked successfully, the target method
|
|
||||||
* handle is invoked to complete the instruction execution.
|
|
||||||
* The state of linkage continues until the method containing the
|
|
||||||
* dynamic call site is garbage collected, or the dynamic call site
|
|
||||||
* is invalidated by an explicit request,
|
|
||||||
* such as {@link java.dyn.Linkage#invalidateCallerClass Linkage.invalidateCallerClass}.
|
|
||||||
* <p>
|
* <p>
|
||||||
* In an application which requires dynamic call sites with individually
|
* In an application which requires dynamic call sites with individually
|
||||||
* mutable behaviors, their bootstrap methods should produce distinct
|
* mutable behaviors, their bootstrap methods should produce distinct
|
||||||
* {@link java.dyn.CallSite CallSite} objects, one for each linkage request.
|
* {@link java.dyn.CallSite CallSite} objects, one for each linkage request.
|
||||||
* <p>
|
* Alternatively, an application can link a single {@code CallSite} object
|
||||||
* If a class containing {@code invokedynamic} instructions
|
* to several {@code invokedynamic} instructions, in which case
|
||||||
* is {@linkplain java.dyn.Linkage#invalidateCallerClass(Class) invalidated},
|
* a change to the target method will become visible at each of
|
||||||
* subsequent execution of those {@code invokedynamic} instructions
|
* the instructions.
|
||||||
* will require linking.
|
|
||||||
* It is as if they had never been executed in the first place.
|
|
||||||
* (However, invalidation does not cause constant pool entries to be
|
|
||||||
* resolved a second time.)
|
|
||||||
* <p>
|
|
||||||
* Invalidation events and bootstrap method calls for a particular
|
|
||||||
* dynamic call site are globally ordered relative to each other.
|
|
||||||
* When an invokedynamic instruction is invalidated, if there is
|
|
||||||
* simultaneously a bootstrap method invocation in process
|
|
||||||
* (in the same thread or a different thread), the result
|
|
||||||
* eventually returned must not be used to link the call site.
|
|
||||||
* Put another way, when a call site is invalidated, its
|
|
||||||
* subsequent linkage (if any) must be performed by a bootstrap method
|
|
||||||
* call initiated after the invalidation occurred.
|
|
||||||
* <p>
|
* <p>
|
||||||
* If several threads simultaneously execute a bootstrap method for a single dynamic
|
* If several threads simultaneously execute a bootstrap method for a single dynamic
|
||||||
* call site, the JVM must choose one target object and installs it visibly to
|
* call site, the JVM must choose one {@code CallSite} object and install it visibly to
|
||||||
* all threads. Any other bootstrap method calls are allowed to complete, but their
|
* all threads. Any other bootstrap method calls are allowed to complete, but their
|
||||||
* results are ignored, and their dynamic call site invocations proceed with the originally
|
* results are ignored, and their dynamic call site invocations proceed with the originally
|
||||||
* chosen target object.
|
* chosen target object.
|
||||||
|
*
|
||||||
|
* <p style="font-size:smaller;">
|
||||||
|
* (Historic Note: Unlike some previous versions of this specification,
|
||||||
|
* these rules do not enable the JVM to duplicate dynamic call sites,
|
||||||
|
* or to issue “causeless” bootstrap method calls.
|
||||||
|
* Every dynamic call site transitions at most once from unlinked to linked,
|
||||||
|
* just before its first invocation.)
|
||||||
|
*
|
||||||
|
* <h3><a name="bsmattr">the {@code BootstrapMethods} attribute </h3>
|
||||||
|
* Each {@code CONSTANT_InvokeDynamic} entry contains an index which references
|
||||||
|
* a bootstrap method specifier; all such specifiers are contained in a separate array.
|
||||||
|
* This array is defined by a class attribute named {@code BootstrapMethods}.
|
||||||
|
* The body of this attribute consists of a sequence of byte pairs, all interpreted as
|
||||||
|
* as 16-bit counts or constant pool indexes, in the {@code u2} format.
|
||||||
|
* The attribute body starts with a count of bootstrap method specifiers,
|
||||||
|
* which is immediately followed by the sequence of specifiers.
|
||||||
* <p>
|
* <p>
|
||||||
* The JVM is free to duplicate dynamic call sites.
|
* Each bootstrap method specifier contains an index to a
|
||||||
* This means that, even if a class contains just one {@code invokedynamic}
|
* {@code CONSTANT_MethodHandle} constant, which is the bootstrap
|
||||||
* instruction, its bootstrap method may be executed several times,
|
* method itself.
|
||||||
* once for each duplicate. Thus, bootstrap method code should not
|
* This is followed by a count, and then a sequence (perhaps empty) of
|
||||||
* assume an exclusive one-to-one correspondence between particular occurrences
|
* indexes to <a href="#args">additional static arguments</a>
|
||||||
* of {@code invokedynamic} bytecodes in class files and linkage events.
|
* for the bootstrap method.
|
||||||
* <p>
|
* <p>
|
||||||
* In principle, each individual execution of an {@code invokedynamic}
|
* During class loading, the verifier must check the structure of the
|
||||||
* instruction could be deemed (by a conforming implementation) to be a separate
|
* {@code BootstrapMethods} attribute. In particular, each constant
|
||||||
* duplicate, requiring its own execution of the bootstrap method.
|
* pool index must be of the correct type. A bootstrap method index
|
||||||
* However, implementations are expected to perform code duplication
|
* must refer to a {@code CONSTANT_MethodHandle} (tag 15).
|
||||||
* (if at all) in order to improve performance, not make it worse.
|
* Every other index must refer to a valid operand of an
|
||||||
|
* {@code ldc_w} or {@code ldc2_w} instruction (tag 3..8 or 15..16).
|
||||||
|
*
|
||||||
|
* <h3><a name="args">static arguments to the bootstrap method</h3>
|
||||||
|
* An {@code invokedynamic} instruction specifies at least three arguments
|
||||||
|
* to pass to its bootstrap method:
|
||||||
|
* The caller class (expressed as a {@link java.dyn.MethodHandles.Lookup Lookup object},
|
||||||
|
* the name (extracted from the {@code CONSTANT_NameAndType} entry),
|
||||||
|
* and the type (also extracted from the {@code CONSTANT_NameAndType} entry).
|
||||||
|
* The {@code invokedynamic} instruction may specify additional metadata values
|
||||||
|
* to pass to its bootstrap method.
|
||||||
|
* Collectively, these values are called <em>static arguments</em> to the
|
||||||
|
* {@code invokedynamic} instruction, because they are used once at link
|
||||||
|
* time to determine the instruction's behavior on subsequent sets of
|
||||||
|
* <em>dynamic arguments</em>.
|
||||||
|
* <p>
|
||||||
|
* Static arguments are used to communicate application-specific meta-data
|
||||||
|
* to the bootstrap method.
|
||||||
|
* Drawn from the constant pool, they may include references to classes, method handles,
|
||||||
|
* strings, or numeric data that may be relevant to the task of linking that particular call site.
|
||||||
|
* <p>
|
||||||
|
* Static arguments are specified constant pool indexes stored in the {@code BootstrapMethods} attribute.
|
||||||
|
* Before the bootstrap method is invoked, each index is used to compute an {@code Object}
|
||||||
|
* reference to the indexed value in the constant pool.
|
||||||
|
* If the value is a primitive type, it is converted to a reference by boxing conversion.
|
||||||
|
* The valid constant pool entries are listed in this table:
|
||||||
|
* <code>
|
||||||
|
* <table border=1 cellpadding=5 summary="Static argument types">
|
||||||
|
* <tr><th>entry type</th><th>argument type</th><th>argument value</th></tr>
|
||||||
|
* <tr><td>CONSTANT_String</td><td><code>java.lang.String</code></td><td>the indexed string literal</td></tr>
|
||||||
|
* <tr><td>CONSTANT_Class</td><td><code>java.lang.Class</code></td><td>the indexed class, resolved</td></tr>
|
||||||
|
* <tr><td>CONSTANT_Integer</td><td><code>java.lang.Integer</code></td><td>the indexed int value</td></tr>
|
||||||
|
* <tr><td>CONSTANT_Long</td><td><code>java.lang.Long</code></td><td>the indexed long value</td></tr>
|
||||||
|
* <tr><td>CONSTANT_Float</td><td><code>java.lang.Float</code></td><td>the indexed float value</td></tr>
|
||||||
|
* <tr><td>CONSTANT_Double</td><td><code>java.lang.Double</code></td><td>the indexed double value</td></tr>
|
||||||
|
* <tr><td>CONSTANT_MethodHandle</td><td><code>java.dyn.MethodHandle</code></td><td>the indexed method handle constant</td></tr>
|
||||||
|
* <tr><td>CONSTANT_MethodType</td><td><code>java.dyn.MethodType</code></td><td>the indexed method type constant</td></tr>
|
||||||
|
* </table>
|
||||||
|
* </code>
|
||||||
|
* <p>
|
||||||
|
* If a given {@code invokedynamic} instruction specifies no static arguments,
|
||||||
|
* the instruction's bootstrap method will be invoked on three arguments,
|
||||||
|
* conveying the instruction's caller class, name, and method type.
|
||||||
|
* If the {@code invokedynamic} instruction specifies one or more static arguments,
|
||||||
|
* a fourth argument will be passed to the bootstrap argument,
|
||||||
|
* either an {@code Object} reference to the sole extra argument (if there is one)
|
||||||
|
* or an {@code Object} array of references to all the arguments (if there are two or more),
|
||||||
|
* as if the bootstrap method is a variable-arity method.
|
||||||
|
* <code>
|
||||||
|
* <table border=1 cellpadding=5 summary="Static argument types">
|
||||||
|
* <tr><th>N</th><th>sample bootstrap method</th></tr>
|
||||||
|
* <tr><td>0</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type)</code></td></tr>
|
||||||
|
* <tr><td>1</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type, Object arg)</code></td></tr>
|
||||||
|
* <tr><td>2</td><td><code>CallSite bootstrap(Lookup caller, String name, MethodType type, Object... args)</code></td></tr>
|
||||||
|
* </table>
|
||||||
|
* </code>
|
||||||
|
* <p>
|
||||||
|
* The argument and return types listed here are used by the {@code invokeGeneric}
|
||||||
|
* call to the bootstrap method.
|
||||||
|
* As noted above, the actual method type of the bootstrap method can vary.
|
||||||
|
* For example, the fourth argument could be {@code MethodHandle},
|
||||||
|
* if that is the type of the corresponding constant in
|
||||||
|
* the {@code CONSTANT_InvokeDynamic} entry.
|
||||||
|
* In that case, the {@code invokeGeneric} call will pass the extra method handle
|
||||||
|
* constant as an {@code Object}, but the type matching machinery of {@code invokeGeneric}
|
||||||
|
* will cast the reference back to {@code MethodHandle} before invoking the bootstrap method.
|
||||||
|
* (If a string constant were passed instead, by badly generated code, that cast would then fail.)
|
||||||
|
* <p>
|
||||||
|
* If the fourth argument is an array, the array element type must be {@code Object},
|
||||||
|
* since object arrays (as produced by the JVM at this point) cannot be converted
|
||||||
|
* to other array types.
|
||||||
|
* <p>
|
||||||
|
* If an array is provided, it will appear to be freshly allocated.
|
||||||
|
* That is, the same array will not appear to two bootstrap method calls.
|
||||||
|
* <p>
|
||||||
|
* Extra bootstrap method arguments are intended to allow language implementors
|
||||||
|
* to safely and compactly encode metadata.
|
||||||
|
* In principle, the name and extra arguments are redundant,
|
||||||
|
* since each call site could be given its own unique bootstrap method.
|
||||||
|
* Such a practice is likely to produce large class files and constant pools.
|
||||||
|
*
|
||||||
|
* <p style="font-size:smaller;">
|
||||||
|
* <em>PROVISIONAL API, WORK IN PROGRESS:</em>
|
||||||
|
* (Usage Note: There is no mechanism for specifying five or more positional arguments to the bootstrap method.
|
||||||
|
* If there are two or more arguments, the Java code of the bootstrap method is required to extract them from
|
||||||
|
* a varargs-style object array.
|
||||||
|
* This design uses varargs because it anticipates some use cases where bootstrap arguments
|
||||||
|
* contribute components of variable-length structures, such as virtual function tables
|
||||||
|
* or interpreter token streams.
|
||||||
|
* Such parameters would be awkward or impossible to manage if represented
|
||||||
|
* as normal positional method arguments,
|
||||||
|
* since there would need to be one Java method per length.
|
||||||
|
* On balance, leaving out the varargs feature would cause more trouble to users than keeping it.
|
||||||
|
* Also, this design allows bootstrap methods to be called in a limited JVM stack depth.
|
||||||
|
* At both the user and JVM level, the difference between varargs and non-varargs
|
||||||
|
* calling sequences can easily be bridged via the
|
||||||
|
* {@link java.dyn.MethodHandle#asSpreader asSpreader}
|
||||||
|
* and {@link java.dyn.MethodHandle#asSpreader asCollector} methods.)
|
||||||
|
*
|
||||||
|
* <h2><a name="structs"></a>Structure Summary</h2>
|
||||||
|
* <blockquote><pre>// summary of constant and attribute structures
|
||||||
|
struct CONSTANT_MethodHandle_info {
|
||||||
|
u1 tag = 15;
|
||||||
|
u1 reference_kind; // 1..8 (one of REF_invokeVirtual, etc.)
|
||||||
|
u2 reference_index; // index to CONSTANT_Fieldref or *Methodref
|
||||||
|
}
|
||||||
|
struct CONSTANT_MethodType_info {
|
||||||
|
u1 tag = 16;
|
||||||
|
u2 descriptor_index; // index to CONSTANT_Utf8, as in NameAndType
|
||||||
|
}
|
||||||
|
struct CONSTANT_InvokeDynamic_17_info {
|
||||||
|
u1 tag = 17;
|
||||||
|
u2 bootstrap_method_index; // index to CONSTANT_MethodHandle
|
||||||
|
u2 name_and_type_index; // same as for CONSTANT_Methodref, etc.
|
||||||
|
}
|
||||||
|
struct CONSTANT_InvokeDynamic_info {
|
||||||
|
u1 tag = 18;
|
||||||
|
u2 bootstrap_method_attr_index; // index into BootstrapMethods_attr
|
||||||
|
u2 name_and_type_index; // index to CONSTANT_NameAndType, as in Methodref
|
||||||
|
}
|
||||||
|
struct BootstrapMethods_attr {
|
||||||
|
u2 name; // CONSTANT_Utf8 = "BootstrapMethods"
|
||||||
|
u4 size;
|
||||||
|
u2 bootstrap_method_count;
|
||||||
|
struct bootstrap_method_specifier {
|
||||||
|
u2 bootstrap_method_ref; // index to CONSTANT_MethodHandle
|
||||||
|
u2 bootstrap_argument_count;
|
||||||
|
u2 bootstrap_arguments[bootstrap_argument_count]; // constant pool indexes
|
||||||
|
} bootstrap_methods[bootstrap_method_count];
|
||||||
|
}
|
||||||
|
* </pre></blockquote>
|
||||||
|
* <p>
|
||||||
|
* <em>Note: The Proposed Final Draft of JSR 292 may remove the constant tag 17,
|
||||||
|
* for the sake of simplicity.</em>
|
||||||
*
|
*
|
||||||
* @author John Rose, JSR 292 EG
|
* @author John Rose, JSR 292 EG
|
||||||
*/
|
*/
|
||||||
|
@ -478,6 +478,39 @@ public class AdapterMethodHandle extends BoundMethodHandle {
|
|||||||
return new AdapterMethodHandle(target, newType, makeConv(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY));
|
return new AdapterMethodHandle(target, newType, makeConv(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MethodHandle makeTypeHandler(Access token,
|
||||||
|
MethodHandle target, MethodHandle typeHandler) {
|
||||||
|
Access.check(token);
|
||||||
|
return new WithTypeHandler(target, typeHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class WithTypeHandler extends AdapterMethodHandle {
|
||||||
|
final MethodHandle target, typeHandler;
|
||||||
|
WithTypeHandler(MethodHandle target, MethodHandle typeHandler) {
|
||||||
|
super(target, target.type(), makeConv(OP_RETYPE_ONLY));
|
||||||
|
this.target = target;
|
||||||
|
this.typeHandler = typeHandler.asType(TYPE_HANDLER_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodHandle asType(MethodType newType) {
|
||||||
|
if (this.type() == newType)
|
||||||
|
return this;
|
||||||
|
try {
|
||||||
|
MethodHandle retyped = (MethodHandle) typeHandler.invokeExact(target, newType);
|
||||||
|
// Contract: Must return the desired type, or throw WMT
|
||||||
|
if (retyped.type() != newType)
|
||||||
|
throw new WrongMethodTypeException(retyped.toString());
|
||||||
|
return retyped;
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
if (ex instanceof Error) throw (Error)ex;
|
||||||
|
if (ex instanceof RuntimeException) throw (RuntimeException)ex;
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static final MethodType TYPE_HANDLER_TYPE
|
||||||
|
= MethodType.methodType(MethodHandle.class, MethodHandle.class, MethodType.class);
|
||||||
|
}
|
||||||
|
|
||||||
/** Can a checkcast adapter validly convert the target to newType?
|
/** Can a checkcast adapter validly convert the target to newType?
|
||||||
* The JVM supports all kind of reference casts, even silly ones.
|
* The JVM supports all kind of reference casts, even silly ones.
|
||||||
*/
|
*/
|
||||||
|
@ -103,21 +103,20 @@ public class BoundMethodHandle extends MethodHandle {
|
|||||||
super(Access.TOKEN, type);
|
super(Access.TOKEN, type);
|
||||||
this.argument = argument;
|
this.argument = argument;
|
||||||
this.vmargslot = vmargslot;
|
this.vmargslot = vmargslot;
|
||||||
assert(this.getClass() == AdapterMethodHandle.class);
|
assert(this instanceof AdapterMethodHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Initialize the current object as a Java method handle, binding it
|
/** Initialize the current object as a self-bound method handle, binding it
|
||||||
* as the first argument of the method handle {@code entryPoint}.
|
* as the first argument of the method handle {@code entryPoint}.
|
||||||
* The invocation type of the resulting method handle will be the
|
* The invocation type of the resulting method handle will be the
|
||||||
* same as {@code entryPoint}, except that the first argument
|
* same as {@code entryPoint}, except that the first argument
|
||||||
* type will be dropped.
|
* type will be dropped.
|
||||||
*/
|
*/
|
||||||
protected BoundMethodHandle(MethodHandle entryPoint) {
|
protected BoundMethodHandle(Access token, MethodHandle entryPoint) {
|
||||||
super(Access.TOKEN, entryPoint.type().dropParameterTypes(0, 1));
|
super(token, entryPoint.type().dropParameterTypes(0, 1));
|
||||||
this.argument = this; // kludge; get rid of
|
this.argument = this; // kludge; get rid of
|
||||||
this.vmargslot = this.type().parameterSlotDepth(0);
|
this.vmargslot = this.type().parameterSlotDepth(0);
|
||||||
initTarget(entryPoint, 0);
|
initTarget(entryPoint, 0);
|
||||||
assert(this instanceof JavaMethodHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Make sure the given {@code argument} can be used as {@code argnum}-th
|
/** Make sure the given {@code argument} can be used as {@code argnum}-th
|
||||||
@ -173,6 +172,11 @@ public class BoundMethodHandle extends MethodHandle {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
return MethodHandleImpl.addTypeString(baseName(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Component of toString() before the type string. */
|
||||||
|
protected String baseName() {
|
||||||
MethodHandle mh = this;
|
MethodHandle mh = this;
|
||||||
while (mh instanceof BoundMethodHandle) {
|
while (mh instanceof BoundMethodHandle) {
|
||||||
Object info = MethodHandleNatives.getTargetInfo(mh);
|
Object info = MethodHandleNatives.getTargetInfo(mh);
|
||||||
@ -185,12 +189,16 @@ public class BoundMethodHandle extends MethodHandle {
|
|||||||
if (name != null)
|
if (name != null)
|
||||||
return name;
|
return name;
|
||||||
else
|
else
|
||||||
return super.toString(); // <unknown>, probably
|
return noParens(super.toString()); // "invoke", probably
|
||||||
}
|
}
|
||||||
assert(mh != this);
|
assert(mh != this);
|
||||||
if (mh instanceof JavaMethodHandle)
|
|
||||||
break; // access JMH.toString(), not BMH.toString()
|
|
||||||
}
|
}
|
||||||
return mh.toString();
|
return noParens(mh.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String noParens(String str) {
|
||||||
|
int paren = str.indexOf('(');
|
||||||
|
if (paren >= 0) str = str.substring(0, paren);
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,31 +41,45 @@ public class CallSiteImpl {
|
|||||||
Object info,
|
Object info,
|
||||||
// Caller information:
|
// Caller information:
|
||||||
MemberName callerMethod, int callerBCI) {
|
MemberName callerMethod, int callerBCI) {
|
||||||
Class<?> caller = callerMethod.getDeclaringClass();
|
Class<?> callerClass = callerMethod.getDeclaringClass();
|
||||||
|
Object caller;
|
||||||
|
if (bootstrapMethod.type().parameterType(0) == Class.class)
|
||||||
|
caller = callerClass; // remove for PFD
|
||||||
|
else
|
||||||
|
caller = MethodHandleImpl.IMPL_LOOKUP.in(callerClass);
|
||||||
if (bootstrapMethod == null) {
|
if (bootstrapMethod == null) {
|
||||||
// If there is no bootstrap method, throw IncompatibleClassChangeError.
|
// If there is no bootstrap method, throw IncompatibleClassChangeError.
|
||||||
// This is a valid generic error type for resolution (JLS 12.3.3).
|
// This is a valid generic error type for resolution (JLS 12.3.3).
|
||||||
throw new IncompatibleClassChangeError
|
throw new IncompatibleClassChangeError
|
||||||
("Class "+caller.getName()+" has not declared a bootstrap method for invokedynamic");
|
("Class "+callerClass.getName()+" has not declared a bootstrap method for invokedynamic");
|
||||||
}
|
}
|
||||||
CallSite site;
|
CallSite site;
|
||||||
try {
|
try {
|
||||||
Object binding;
|
Object binding;
|
||||||
if (false) // switch when invokeGeneric works
|
if (info == null) {
|
||||||
binding = bootstrapMethod.invokeGeneric(caller, name, type);
|
if (false) // switch when invokeGeneric works
|
||||||
else
|
binding = bootstrapMethod.invokeGeneric(caller, name, type);
|
||||||
binding = bootstrapMethod.invokeVarargs(new Object[]{ caller, name, type });
|
else
|
||||||
|
binding = bootstrapMethod.invokeVarargs(new Object[]{ caller, name, type });
|
||||||
|
} else {
|
||||||
|
info = maybeReBox(info);
|
||||||
|
if (false) // switch when invokeGeneric works
|
||||||
|
binding = bootstrapMethod.invokeGeneric(caller, name, type, info);
|
||||||
|
else
|
||||||
|
binding = bootstrapMethod.invokeVarargs(new Object[]{ caller, name, type, info });
|
||||||
|
}
|
||||||
//System.out.println("BSM for "+name+type+" => "+binding);
|
//System.out.println("BSM for "+name+type+" => "+binding);
|
||||||
if (binding instanceof CallSite) {
|
if (binding instanceof CallSite) {
|
||||||
site = (CallSite) binding;
|
site = (CallSite) binding;
|
||||||
} else if (binding instanceof MethodHandleProvider) {
|
} else if (binding instanceof MethodHandle) {
|
||||||
MethodHandle target = ((MethodHandleProvider) binding).asMethodHandle();
|
// Transitional!
|
||||||
|
MethodHandle target = (MethodHandle) binding;
|
||||||
site = new ConstantCallSite(target);
|
site = new ConstantCallSite(target);
|
||||||
} else {
|
} else {
|
||||||
throw new ClassCastException("bootstrap method failed to produce a MethodHandle or CallSite");
|
throw new ClassCastException("bootstrap method failed to produce a MethodHandle or CallSite");
|
||||||
}
|
}
|
||||||
PRIVATE_INITIALIZE_CALL_SITE.<void>invokeExact(site, name, type,
|
PRIVATE_INITIALIZE_CALL_SITE.invokeExact(site, name, type,
|
||||||
callerMethod, callerBCI);
|
callerMethod, callerBCI);
|
||||||
assert(site.getTarget() != null);
|
assert(site.getTarget() != null);
|
||||||
assert(site.getTarget().type().equals(type));
|
assert(site.getTarget().type().equals(type));
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
@ -79,6 +93,24 @@ public class CallSiteImpl {
|
|||||||
return site;
|
return site;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Object maybeReBox(Object x) {
|
||||||
|
if (x instanceof Integer) {
|
||||||
|
int xi = (int) x;
|
||||||
|
if (xi == (byte) xi)
|
||||||
|
x = xi; // must rebox; see JLS 5.1.7
|
||||||
|
return x;
|
||||||
|
} else if (x instanceof Object[]) {
|
||||||
|
Object[] xa = (Object[]) x;
|
||||||
|
for (int i = 0; i < xa.length; i++) {
|
||||||
|
if (xa[i] instanceof Integer)
|
||||||
|
xa[i] = maybeReBox(xa[i]);
|
||||||
|
}
|
||||||
|
return xa;
|
||||||
|
} else {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This method is private in CallSite because it touches private fields in CallSite.
|
// This method is private in CallSite because it touches private fields in CallSite.
|
||||||
// These private fields (vmmethod, vmindex) are specific to the JVM.
|
// These private fields (vmmethod, vmindex) are specific to the JVM.
|
||||||
private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE;
|
private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE;
|
||||||
|
@ -115,7 +115,7 @@ class FilterGeneric {
|
|||||||
|
|
||||||
static MethodHandle make(Kind kind, int pos, MethodHandle filter, MethodHandle target) {
|
static MethodHandle make(Kind kind, int pos, MethodHandle filter, MethodHandle target) {
|
||||||
FilterGeneric fgen = of(kind, pos, filter.type(), target.type());
|
FilterGeneric fgen = of(kind, pos, filter.type(), target.type());
|
||||||
return fgen.makeInstance(kind, pos, filter, target).asMethodHandle();
|
return fgen.makeInstance(kind, pos, filter, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the adapter information for this target and filter type. */
|
/** Return the adapter information for this target and filter type. */
|
||||||
@ -225,13 +225,13 @@ class FilterGeneric {
|
|||||||
* The invoker is kept separate from the target because it can be
|
* The invoker is kept separate from the target because it can be
|
||||||
* generated once per type erasure family, and reused across adapters.
|
* generated once per type erasure family, and reused across adapters.
|
||||||
*/
|
*/
|
||||||
static abstract class Adapter extends JavaMethodHandle {
|
static abstract class Adapter extends BoundMethodHandle {
|
||||||
protected final MethodHandle filter; // transforms one or more arguments
|
protected final MethodHandle filter; // transforms one or more arguments
|
||||||
protected final MethodHandle target; // ultimate target
|
protected final MethodHandle target; // ultimate target
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return target.toString();
|
return MethodHandleImpl.addTypeString(target, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isPrototype() { return target == null; }
|
protected boolean isPrototype() { return target == null; }
|
||||||
@ -246,7 +246,7 @@ class FilterGeneric {
|
|||||||
|
|
||||||
protected Adapter(MethodHandle entryPoint,
|
protected Adapter(MethodHandle entryPoint,
|
||||||
MethodHandle filter, MethodHandle target) {
|
MethodHandle filter, MethodHandle target) {
|
||||||
super(entryPoint);
|
super(Access.TOKEN, entryPoint);
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
}
|
}
|
||||||
@ -303,7 +303,7 @@ class FilterGeneric {
|
|||||||
protected Object invoke_C0(Object a0) { return target.invokeExact(filter.invokeExact(a0)); }
|
protected Object invoke_C0(Object a0) { return target.invokeExact(filter.invokeExact(a0)); }
|
||||||
protected Object invoke_C1(Object a0) { return target.invokeExact(a0, filter.invokeExact()); }
|
protected Object invoke_C1(Object a0) { return target.invokeExact(a0, filter.invokeExact()); }
|
||||||
protected Object invoke_Y0(Object a0) { Object[] av = { a0 };
|
protected Object invoke_Y0(Object a0) { Object[] av = { a0 };
|
||||||
filter.<void>invokeExact(av); return target.invokeExact(av[0]); }
|
filter.invokeExact(av); return target.invokeExact(av[0]); }
|
||||||
}
|
}
|
||||||
static class F2X extends Adapter {
|
static class F2X extends Adapter {
|
||||||
protected F2X(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected F2X(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
@ -320,7 +320,7 @@ class FilterGeneric {
|
|||||||
protected Object invoke_C1(Object a0, Object a1) { return target.invokeExact(a0, filter.invokeExact(a1)); }
|
protected Object invoke_C1(Object a0, Object a1) { return target.invokeExact(a0, filter.invokeExact(a1)); }
|
||||||
protected Object invoke_C2(Object a0, Object a1) { return target.invokeExact(a0, a1, filter.invokeExact()); }
|
protected Object invoke_C2(Object a0, Object a1) { return target.invokeExact(a0, a1, filter.invokeExact()); }
|
||||||
protected Object invoke_Y0(Object a0, Object a1) { Object[] av = { a0, a1 };
|
protected Object invoke_Y0(Object a0, Object a1) { Object[] av = { a0, a1 };
|
||||||
filter.<void>invokeExact(av); return target.invokeExact(av[0], av[1]); }
|
filter.invokeExact(av); return target.invokeExact(av[0], av[1]); }
|
||||||
}
|
}
|
||||||
// */
|
// */
|
||||||
|
|
||||||
@ -337,7 +337,7 @@ class FilterGeneric {
|
|||||||
return target.invokeExact(filter.invokeExact()); }
|
return target.invokeExact(filter.invokeExact()); }
|
||||||
static final Object[] NO_ARGS = { };
|
static final Object[] NO_ARGS = { };
|
||||||
protected Object invoke_Y0() throws Throwable {
|
protected Object invoke_Y0() throws Throwable {
|
||||||
filter.<void>invokeExact(NO_ARGS); // make the flyby
|
filter.invokeExact(NO_ARGS); // make the flyby
|
||||||
return target.invokeExact(); }
|
return target.invokeExact(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,7 +375,7 @@ class genclasses {
|
|||||||
" return target.invokeExact(@av@, filter.invokeExact()); }",
|
" return target.invokeExact(@av@, filter.invokeExact()); }",
|
||||||
" protected Object invoke_Y0(@Tvav@) throws Throwable {",
|
" protected Object invoke_Y0(@Tvav@) throws Throwable {",
|
||||||
" Object[] av = { @av@ };",
|
" Object[] av = { @av@ };",
|
||||||
" filter.<void>invokeExact(av); // make the flyby",
|
" filter.invokeExact(av); // make the flyby",
|
||||||
" return target.invokeExact(@av[i]@); }",
|
" return target.invokeExact(@av[i]@); }",
|
||||||
" }",
|
" }",
|
||||||
} };
|
} };
|
||||||
@ -518,7 +518,7 @@ class genclasses {
|
|||||||
return target.invokeExact(a0, filter.invokeExact()); }
|
return target.invokeExact(a0, filter.invokeExact()); }
|
||||||
protected Object invoke_Y0(Object a0) throws Throwable {
|
protected Object invoke_Y0(Object a0) throws Throwable {
|
||||||
Object[] av = { a0 };
|
Object[] av = { a0 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0]); }
|
return target.invokeExact(av[0]); }
|
||||||
}
|
}
|
||||||
static class F2 extends Adapter {
|
static class F2 extends Adapter {
|
||||||
@ -548,7 +548,7 @@ class genclasses {
|
|||||||
return target.invokeExact(a0, a1, filter.invokeExact()); }
|
return target.invokeExact(a0, a1, filter.invokeExact()); }
|
||||||
protected Object invoke_Y0(Object a0, Object a1) throws Throwable {
|
protected Object invoke_Y0(Object a0, Object a1) throws Throwable {
|
||||||
Object[] av = { a0, a1 };
|
Object[] av = { a0, a1 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1]); }
|
return target.invokeExact(av[0], av[1]); }
|
||||||
}
|
}
|
||||||
static class F3 extends Adapter {
|
static class F3 extends Adapter {
|
||||||
@ -585,7 +585,7 @@ class genclasses {
|
|||||||
return target.invokeExact(a0, a1, a2, filter.invokeExact()); }
|
return target.invokeExact(a0, a1, a2, filter.invokeExact()); }
|
||||||
protected Object invoke_Y0(Object a0, Object a1, Object a2) throws Throwable {
|
protected Object invoke_Y0(Object a0, Object a1, Object a2) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2 };
|
Object[] av = { a0, a1, a2 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2]); }
|
return target.invokeExact(av[0], av[1], av[2]); }
|
||||||
}
|
}
|
||||||
static class F4 extends Adapter {
|
static class F4 extends Adapter {
|
||||||
@ -629,7 +629,7 @@ class genclasses {
|
|||||||
return target.invokeExact(a0, a1, a2, a3, filter.invokeExact()); }
|
return target.invokeExact(a0, a1, a2, a3, filter.invokeExact()); }
|
||||||
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3) throws Throwable {
|
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2, a3 };
|
Object[] av = { a0, a1, a2, a3 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2], av[3]); }
|
return target.invokeExact(av[0], av[1], av[2], av[3]); }
|
||||||
}
|
}
|
||||||
static class F5 extends Adapter {
|
static class F5 extends Adapter {
|
||||||
@ -698,7 +698,7 @@ class genclasses {
|
|||||||
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3,
|
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3,
|
||||||
Object a4) throws Throwable {
|
Object a4) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2, a3, a4 };
|
Object[] av = { a0, a1, a2, a3, a4 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2], av[3], av[4]); }
|
return target.invokeExact(av[0], av[1], av[2], av[3], av[4]); }
|
||||||
}
|
}
|
||||||
static class F6 extends Adapter {
|
static class F6 extends Adapter {
|
||||||
@ -777,7 +777,7 @@ class genclasses {
|
|||||||
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3,
|
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3,
|
||||||
Object a4, Object a5) throws Throwable {
|
Object a4, Object a5) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2, a3, a4, a5 };
|
Object[] av = { a0, a1, a2, a3, a4, a5 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5]); }
|
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5]); }
|
||||||
}
|
}
|
||||||
static class F7 extends Adapter {
|
static class F7 extends Adapter {
|
||||||
@ -866,7 +866,7 @@ class genclasses {
|
|||||||
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3,
|
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3,
|
||||||
Object a4, Object a5, Object a6) throws Throwable {
|
Object a4, Object a5, Object a6) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2, a3, a4, a5, a6 };
|
Object[] av = { a0, a1, a2, a3, a4, a5, a6 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6]); }
|
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6]); }
|
||||||
}
|
}
|
||||||
static class F8 extends Adapter {
|
static class F8 extends Adapter {
|
||||||
@ -965,7 +965,7 @@ class genclasses {
|
|||||||
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3,
|
protected Object invoke_Y0(Object a0, Object a1, Object a2, Object a3,
|
||||||
Object a4, Object a5, Object a6, Object a7) throws Throwable {
|
Object a4, Object a5, Object a6, Object a7) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7 };
|
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7]); }
|
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7]); }
|
||||||
}
|
}
|
||||||
static class F9 extends Adapter {
|
static class F9 extends Adapter {
|
||||||
@ -1104,7 +1104,7 @@ class genclasses {
|
|||||||
Object a4, Object a5, Object a6, Object a7,
|
Object a4, Object a5, Object a6, Object a7,
|
||||||
Object a8) throws Throwable {
|
Object a8) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8 };
|
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8]); }
|
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8]); }
|
||||||
}
|
}
|
||||||
static class F10 extends Adapter {
|
static class F10 extends Adapter {
|
||||||
@ -1256,7 +1256,7 @@ class genclasses {
|
|||||||
Object a4, Object a5, Object a6, Object a7,
|
Object a4, Object a5, Object a6, Object a7,
|
||||||
Object a8, Object a9) throws Throwable {
|
Object a8, Object a9) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 };
|
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9]); }
|
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9]); }
|
||||||
}
|
}
|
||||||
static class F11 extends Adapter {
|
static class F11 extends Adapter {
|
||||||
@ -1442,7 +1442,7 @@ class genclasses {
|
|||||||
Object a4, Object a5, Object a6, Object a7,
|
Object a4, Object a5, Object a6, Object a7,
|
||||||
Object a8, Object a9, Object a10) throws Throwable {
|
Object a8, Object a9, Object a10) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 };
|
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10]); }
|
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10]); }
|
||||||
}
|
}
|
||||||
static class F12 extends Adapter {
|
static class F12 extends Adapter {
|
||||||
@ -1644,7 +1644,7 @@ class genclasses {
|
|||||||
Object a4, Object a5, Object a6, Object a7,
|
Object a4, Object a5, Object a6, Object a7,
|
||||||
Object a8, Object a9, Object a10, Object a11) throws Throwable {
|
Object a8, Object a9, Object a10, Object a11) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11 };
|
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11]); }
|
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11]); }
|
||||||
}
|
}
|
||||||
static class F13 extends Adapter {
|
static class F13 extends Adapter {
|
||||||
@ -1904,7 +1904,7 @@ class genclasses {
|
|||||||
Object a8, Object a9, Object a10, Object a11,
|
Object a8, Object a9, Object a10, Object a11,
|
||||||
Object a12) throws Throwable {
|
Object a12) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 };
|
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12]); }
|
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12]); }
|
||||||
}
|
}
|
||||||
static class F14 extends Adapter {
|
static class F14 extends Adapter {
|
||||||
@ -2183,7 +2183,7 @@ class genclasses {
|
|||||||
Object a8, Object a9, Object a10, Object a11,
|
Object a8, Object a9, Object a10, Object a11,
|
||||||
Object a12, Object a13) throws Throwable {
|
Object a12, Object a13) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13 };
|
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13]); }
|
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13]); }
|
||||||
}
|
}
|
||||||
static class F15 extends Adapter {
|
static class F15 extends Adapter {
|
||||||
@ -2481,7 +2481,7 @@ class genclasses {
|
|||||||
Object a8, Object a9, Object a10, Object a11,
|
Object a8, Object a9, Object a10, Object a11,
|
||||||
Object a12, Object a13, Object a14) throws Throwable {
|
Object a12, Object a13, Object a14) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14 };
|
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14]); }
|
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14]); }
|
||||||
}
|
}
|
||||||
static class F16 extends Adapter {
|
static class F16 extends Adapter {
|
||||||
@ -2798,7 +2798,7 @@ class genclasses {
|
|||||||
Object a8, Object a9, Object a10, Object a11,
|
Object a8, Object a9, Object a10, Object a11,
|
||||||
Object a12, Object a13, Object a14, Object a15) throws Throwable {
|
Object a12, Object a13, Object a14, Object a15) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 };
|
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15]); }
|
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15]); }
|
||||||
}
|
}
|
||||||
static class F17 extends Adapter {
|
static class F17 extends Adapter {
|
||||||
@ -3188,7 +3188,7 @@ class genclasses {
|
|||||||
Object a12, Object a13, Object a14, Object a15,
|
Object a12, Object a13, Object a14, Object a15,
|
||||||
Object a16) throws Throwable {
|
Object a16) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16 };
|
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16]); }
|
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16]); }
|
||||||
}
|
}
|
||||||
static class F18 extends Adapter {
|
static class F18 extends Adapter {
|
||||||
@ -3600,7 +3600,7 @@ class genclasses {
|
|||||||
Object a12, Object a13, Object a14, Object a15,
|
Object a12, Object a13, Object a14, Object a15,
|
||||||
Object a16, Object a17) throws Throwable {
|
Object a16, Object a17) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17 };
|
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16], av[17]); }
|
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16], av[17]); }
|
||||||
}
|
}
|
||||||
static class F19 extends Adapter {
|
static class F19 extends Adapter {
|
||||||
@ -4034,7 +4034,7 @@ class genclasses {
|
|||||||
Object a12, Object a13, Object a14, Object a15,
|
Object a12, Object a13, Object a14, Object a15,
|
||||||
Object a16, Object a17, Object a18) throws Throwable {
|
Object a16, Object a17, Object a18) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 };
|
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16], av[17], av[18]); }
|
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16], av[17], av[18]); }
|
||||||
}
|
}
|
||||||
static class F20 extends Adapter {
|
static class F20 extends Adapter {
|
||||||
@ -4490,7 +4490,7 @@ class genclasses {
|
|||||||
Object a12, Object a13, Object a14, Object a15,
|
Object a12, Object a13, Object a14, Object a15,
|
||||||
Object a16, Object a17, Object a18, Object a19) throws Throwable {
|
Object a16, Object a17, Object a18, Object a19) throws Throwable {
|
||||||
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19 };
|
Object[] av = { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19 };
|
||||||
filter.<void>invokeExact(av); // make the flyby
|
filter.invokeExact(av); // make the flyby
|
||||||
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16], av[17], av[18], av[19]); }
|
return target.invokeExact(av[0], av[1], av[2], av[3], av[4], av[5], av[6], av[7], av[8], av[9], av[10], av[11], av[12], av[13], av[14], av[15], av[16], av[17], av[18], av[19]); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ import static sun.dyn.MemberName.uncaughtException;
|
|||||||
* final method type is the responsibility of a JVM-level adapter.
|
* final method type is the responsibility of a JVM-level adapter.
|
||||||
* @author jrose
|
* @author jrose
|
||||||
*/
|
*/
|
||||||
public class FilterOneArgument extends JavaMethodHandle {
|
public class FilterOneArgument extends BoundMethodHandle {
|
||||||
protected final MethodHandle filter; // Object -> Object
|
protected final MethodHandle filter; // Object -> Object
|
||||||
protected final MethodHandle target; // Object -> Object
|
protected final MethodHandle target; // Object -> Object
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ public class FilterOneArgument extends JavaMethodHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected FilterOneArgument(MethodHandle filter, MethodHandle target) {
|
protected FilterOneArgument(MethodHandle filter, MethodHandle target) {
|
||||||
super(INVOKE);
|
super(Access.TOKEN, INVOKE);
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
}
|
}
|
||||||
|
@ -241,7 +241,7 @@ class FromGeneric {
|
|||||||
* The invoker is kept separate from the target because it can be
|
* The invoker is kept separate from the target because it can be
|
||||||
* generated once per type erasure family, and reused across adapters.
|
* generated once per type erasure family, and reused across adapters.
|
||||||
*/
|
*/
|
||||||
static abstract class Adapter extends JavaMethodHandle {
|
static abstract class Adapter extends BoundMethodHandle {
|
||||||
/*
|
/*
|
||||||
* class X<<R,int N>> extends Adapter {
|
* class X<<R,int N>> extends Adapter {
|
||||||
* (MH, Object**N)=>raw(R) invoker;
|
* (MH, Object**N)=>raw(R) invoker;
|
||||||
@ -256,7 +256,7 @@ class FromGeneric {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return target.toString();
|
return MethodHandleImpl.addTypeString(target, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isPrototype() { return target == null; }
|
protected boolean isPrototype() { return target == null; }
|
||||||
@ -271,7 +271,7 @@ class FromGeneric {
|
|||||||
|
|
||||||
protected Adapter(MethodHandle entryPoint,
|
protected Adapter(MethodHandle entryPoint,
|
||||||
MethodHandle invoker, MethodHandle convert, MethodHandle target) {
|
MethodHandle invoker, MethodHandle convert, MethodHandle target) {
|
||||||
super(entryPoint);
|
super(Access.TOKEN, entryPoint);
|
||||||
this.invoker = invoker;
|
this.invoker = invoker;
|
||||||
this.convert = convert;
|
this.convert = convert;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
@ -283,11 +283,11 @@ class FromGeneric {
|
|||||||
// { return new ThisType(entryPoint, convert, target); }
|
// { return new ThisType(entryPoint, convert, target); }
|
||||||
|
|
||||||
/// Conversions on the value returned from the target.
|
/// Conversions on the value returned from the target.
|
||||||
protected Object convert_L(Object result) throws Throwable { return convert.<Object>invokeExact(result); }
|
protected Object convert_L(Object result) throws Throwable { return convert.invokeExact(result); }
|
||||||
protected Object convert_I(int result) throws Throwable { return convert.<Object>invokeExact(result); }
|
protected Object convert_I(int result) throws Throwable { return convert.invokeExact(result); }
|
||||||
protected Object convert_J(long result) throws Throwable { return convert.<Object>invokeExact(result); }
|
protected Object convert_J(long result) throws Throwable { return convert.invokeExact(result); }
|
||||||
protected Object convert_F(float result) throws Throwable { return convert.<Object>invokeExact(result); }
|
protected Object convert_F(float result) throws Throwable { return convert.invokeExact(result); }
|
||||||
protected Object convert_D(double result) throws Throwable { return convert.<Object>invokeExact(result); }
|
protected Object convert_D(double result) throws Throwable { return convert.invokeExact(result); }
|
||||||
|
|
||||||
static private final String CLASS_PREFIX; // "sun.dyn.FromGeneric$"
|
static private final String CLASS_PREFIX; // "sun.dyn.FromGeneric$"
|
||||||
static {
|
static {
|
||||||
@ -316,11 +316,11 @@ class FromGeneric {
|
|||||||
{ super(e, i, c, t); }
|
{ super(e, i, c, t); }
|
||||||
protected xA2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
protected xA2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||||
{ return new xA2(e, i, c, t); }
|
{ return new xA2(e, i, c, t); }
|
||||||
protected Object invoke_L2(Object a0, Object a1) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1)); }
|
protected Object invoke_L2(Object a0, Object a1) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1)); }
|
||||||
protected Object invoke_I2(Object a0, Object a1) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1)); }
|
protected Object invoke_I2(Object a0, Object a1) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1)); }
|
||||||
protected Object invoke_J2(Object a0, Object a1) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1)); }
|
protected Object invoke_J2(Object a0, Object a1) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1)); }
|
||||||
protected Object invoke_F2(Object a0, Object a1) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1)); }
|
protected Object invoke_F2(Object a0, Object a1) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1)); }
|
||||||
protected Object invoke_D2(Object a0, Object a1) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1)); }
|
protected Object invoke_D2(Object a0, Object a1) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1)); }
|
||||||
}
|
}
|
||||||
// */
|
// */
|
||||||
|
|
||||||
@ -329,7 +329,8 @@ class FromGeneric {
|
|||||||
//{{{
|
//{{{
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
class genclasses {
|
class genclasses {
|
||||||
static String[] TYPES = { "Object", "int ", "long ", "float ", "double" };
|
static String[] TYPES = { "Object", "int ", "long ", "float ", "double" };
|
||||||
|
static String[] WRAPS = { " ", "(Integer)", "(Long) ", "(Float) ", "(Double) " };
|
||||||
static String[] TCHARS = { "L", "I", "J", "F", "D", "A" };
|
static String[] TCHARS = { "L", "I", "J", "F", "D", "A" };
|
||||||
static String[][] TEMPLATES = { {
|
static String[][] TEMPLATES = { {
|
||||||
"@for@ arity=0..10 rcat<=4 nrefs<=99 nints=0 nlongs=0",
|
"@for@ arity=0..10 rcat<=4 nrefs<=99 nints=0 nlongs=0",
|
||||||
@ -341,13 +342,13 @@ class genclasses {
|
|||||||
" protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)",
|
" protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)",
|
||||||
" { return new @cat@(e, i, c, t); }",
|
" { return new @cat@(e, i, c, t); }",
|
||||||
" //@each-R@",
|
" //@each-R@",
|
||||||
" protected Object invoke_@catN@(@Tvav@) throws Throwable { return convert_@Rc@(invoker.<@R@>invokeExact(target@av@)); }",
|
" protected Object invoke_@catN@(@Tvav@) throws Throwable { return convert_@Rc@((@R@)@W@invoker.invokeExact(target@av@)); }",
|
||||||
" //@end-R@",
|
" //@end-R@",
|
||||||
" }",
|
" }",
|
||||||
} };
|
} };
|
||||||
static final String NEWLINE_INDENT = "\n ";
|
static final String NEWLINE_INDENT = "\n ";
|
||||||
enum VAR {
|
enum VAR {
|
||||||
cat, catN, R, Rc, av, Tvav, Ovav;
|
cat, catN, R, Rc, W, av, Tvav, Ovav;
|
||||||
public final String pattern = "@"+toString().replace('_','.')+"@";
|
public final String pattern = "@"+toString().replace('_','.')+"@";
|
||||||
public String binding;
|
public String binding;
|
||||||
static void makeBindings(boolean topLevel, int rcat, int nrefs, int nints, int nlongs) {
|
static void makeBindings(boolean topLevel, int rcat, int nrefs, int nints, int nlongs) {
|
||||||
@ -357,6 +358,7 @@ class genclasses {
|
|||||||
VAR.catN.binding = catstr(rcat, nrefs, nints, nlongs);
|
VAR.catN.binding = catstr(rcat, nrefs, nints, nlongs);
|
||||||
VAR.R.binding = TYPES[rcat];
|
VAR.R.binding = TYPES[rcat];
|
||||||
VAR.Rc.binding = TCHARS[rcat];
|
VAR.Rc.binding = TCHARS[rcat];
|
||||||
|
VAR.W.binding = WRAPS[rcat];
|
||||||
String[] Tv = new String[nargs];
|
String[] Tv = new String[nargs];
|
||||||
String[] av = new String[nargs];
|
String[] av = new String[nargs];
|
||||||
String[] Tvav = new String[nargs];
|
String[] Tvav = new String[nargs];
|
||||||
@ -497,11 +499,11 @@ class genclasses {
|
|||||||
{ super(e, i, c, t); }
|
{ super(e, i, c, t); }
|
||||||
protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||||
{ return new A0(e, i, c, t); }
|
{ return new A0(e, i, c, t); }
|
||||||
protected Object invoke_L0() throws Throwable { return convert_L(invoker.<Object>invokeExact(target)); }
|
protected Object invoke_L0() throws Throwable { return convert_L((Object)invoker.invokeExact(target)); }
|
||||||
protected Object invoke_I0() throws Throwable { return convert_I(invoker.<int >invokeExact(target)); }
|
protected Object invoke_I0() throws Throwable { return convert_I((int) invoker.invokeExact(target)); }
|
||||||
protected Object invoke_J0() throws Throwable { return convert_J(invoker.<long >invokeExact(target)); }
|
protected Object invoke_J0() throws Throwable { return convert_J((long) invoker.invokeExact(target)); }
|
||||||
protected Object invoke_F0() throws Throwable { return convert_F(invoker.<float >invokeExact(target)); }
|
protected Object invoke_F0() throws Throwable { return convert_F((float) invoker.invokeExact(target)); }
|
||||||
protected Object invoke_D0() throws Throwable { return convert_D(invoker.<double>invokeExact(target)); }
|
protected Object invoke_D0() throws Throwable { return convert_D((double)invoker.invokeExact(target)); }
|
||||||
}
|
}
|
||||||
static class A1 extends Adapter {
|
static class A1 extends Adapter {
|
||||||
protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
@ -509,11 +511,11 @@ class genclasses {
|
|||||||
{ super(e, i, c, t); }
|
{ super(e, i, c, t); }
|
||||||
protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||||
{ return new A1(e, i, c, t); }
|
{ return new A1(e, i, c, t); }
|
||||||
protected Object invoke_L1(Object a0) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0)); }
|
protected Object invoke_L1(Object a0) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0)); }
|
||||||
protected Object invoke_I1(Object a0) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0)); }
|
protected Object invoke_I1(Object a0) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0)); }
|
||||||
protected Object invoke_J1(Object a0) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0)); }
|
protected Object invoke_J1(Object a0) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0)); }
|
||||||
protected Object invoke_F1(Object a0) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0)); }
|
protected Object invoke_F1(Object a0) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0)); }
|
||||||
protected Object invoke_D1(Object a0) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0)); }
|
protected Object invoke_D1(Object a0) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0)); }
|
||||||
}
|
}
|
||||||
static class A2 extends Adapter {
|
static class A2 extends Adapter {
|
||||||
protected A2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
@ -521,11 +523,11 @@ class genclasses {
|
|||||||
{ super(e, i, c, t); }
|
{ super(e, i, c, t); }
|
||||||
protected A2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
protected A2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||||
{ return new A2(e, i, c, t); }
|
{ return new A2(e, i, c, t); }
|
||||||
protected Object invoke_L2(Object a0, Object a1) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1)); }
|
protected Object invoke_L2(Object a0, Object a1) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1)); }
|
||||||
protected Object invoke_I2(Object a0, Object a1) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1)); }
|
protected Object invoke_I2(Object a0, Object a1) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1)); }
|
||||||
protected Object invoke_J2(Object a0, Object a1) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1)); }
|
protected Object invoke_J2(Object a0, Object a1) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1)); }
|
||||||
protected Object invoke_F2(Object a0, Object a1) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1)); }
|
protected Object invoke_F2(Object a0, Object a1) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1)); }
|
||||||
protected Object invoke_D2(Object a0, Object a1) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1)); }
|
protected Object invoke_D2(Object a0, Object a1) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1)); }
|
||||||
}
|
}
|
||||||
static class A3 extends Adapter {
|
static class A3 extends Adapter {
|
||||||
protected A3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
@ -533,11 +535,11 @@ class genclasses {
|
|||||||
{ super(e, i, c, t); }
|
{ super(e, i, c, t); }
|
||||||
protected A3 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
protected A3 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||||
{ return new A3(e, i, c, t); }
|
{ return new A3(e, i, c, t); }
|
||||||
protected Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2)); }
|
protected Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2)); }
|
||||||
protected Object invoke_I3(Object a0, Object a1, Object a2) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2)); }
|
protected Object invoke_I3(Object a0, Object a1, Object a2) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2)); }
|
||||||
protected Object invoke_J3(Object a0, Object a1, Object a2) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2)); }
|
protected Object invoke_J3(Object a0, Object a1, Object a2) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2)); }
|
||||||
protected Object invoke_F3(Object a0, Object a1, Object a2) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2)); }
|
protected Object invoke_F3(Object a0, Object a1, Object a2) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2)); }
|
||||||
protected Object invoke_D3(Object a0, Object a1, Object a2) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2)); }
|
protected Object invoke_D3(Object a0, Object a1, Object a2) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2)); }
|
||||||
}
|
}
|
||||||
static class A4 extends Adapter {
|
static class A4 extends Adapter {
|
||||||
protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
@ -545,11 +547,11 @@ class genclasses {
|
|||||||
{ super(e, i, c, t); }
|
{ super(e, i, c, t); }
|
||||||
protected A4 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
protected A4 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||||
{ return new A4(e, i, c, t); }
|
{ return new A4(e, i, c, t); }
|
||||||
protected Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2, a3)); }
|
protected Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2, a3)); }
|
||||||
protected Object invoke_I4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2, a3)); }
|
protected Object invoke_I4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2, a3)); }
|
||||||
protected Object invoke_J4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2, a3)); }
|
protected Object invoke_J4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2, a3)); }
|
||||||
protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2, a3)); }
|
protected Object invoke_F4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2, a3)); }
|
||||||
protected Object invoke_D4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2, a3)); }
|
protected Object invoke_D4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2, a3)); }
|
||||||
}
|
}
|
||||||
static class A5 extends Adapter {
|
static class A5 extends Adapter {
|
||||||
protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
@ -557,11 +559,11 @@ class genclasses {
|
|||||||
{ super(e, i, c, t); }
|
{ super(e, i, c, t); }
|
||||||
protected A5 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
protected A5 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||||
{ return new A5(e, i, c, t); }
|
{ return new A5(e, i, c, t); }
|
||||||
protected Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4)); }
|
protected Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2, a3, a4)); }
|
||||||
protected Object invoke_I5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2, a3, a4)); }
|
protected Object invoke_I5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2, a3, a4)); }
|
||||||
protected Object invoke_J5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2, a3, a4)); }
|
protected Object invoke_J5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2, a3, a4)); }
|
||||||
protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2, a3, a4)); }
|
protected Object invoke_F5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2, a3, a4)); }
|
||||||
protected Object invoke_D5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2, a3, a4)); }
|
protected Object invoke_D5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2, a3, a4)); }
|
||||||
}
|
}
|
||||||
static class A6 extends Adapter {
|
static class A6 extends Adapter {
|
||||||
protected A6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
@ -569,11 +571,11 @@ class genclasses {
|
|||||||
{ super(e, i, c, t); }
|
{ super(e, i, c, t); }
|
||||||
protected A6 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
protected A6 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||||
{ return new A6(e, i, c, t); }
|
{ return new A6(e, i, c, t); }
|
||||||
protected Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5)); }
|
protected Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5)); }
|
||||||
protected Object invoke_I6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2, a3, a4, a5)); }
|
protected Object invoke_I6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5)); }
|
||||||
protected Object invoke_J6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2, a3, a4, a5)); }
|
protected Object invoke_J6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5)); }
|
||||||
protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2, a3, a4, a5)); }
|
protected Object invoke_F6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5)); }
|
||||||
protected Object invoke_D6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2, a3, a4, a5)); }
|
protected Object invoke_D6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5)); }
|
||||||
}
|
}
|
||||||
static class A7 extends Adapter {
|
static class A7 extends Adapter {
|
||||||
protected A7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
@ -581,11 +583,11 @@ class genclasses {
|
|||||||
{ super(e, i, c, t); }
|
{ super(e, i, c, t); }
|
||||||
protected A7 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
protected A7 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||||
{ return new A7(e, i, c, t); }
|
{ return new A7(e, i, c, t); }
|
||||||
protected Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
|
protected Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
|
||||||
protected Object invoke_I7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
|
protected Object invoke_I7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
|
||||||
protected Object invoke_J7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
|
protected Object invoke_J7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
|
||||||
protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
|
protected Object invoke_F7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
|
||||||
protected Object invoke_D7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
|
protected Object invoke_D7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6)); }
|
||||||
}
|
}
|
||||||
static class A8 extends Adapter {
|
static class A8 extends Adapter {
|
||||||
protected A8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
@ -593,11 +595,11 @@ class genclasses {
|
|||||||
{ super(e, i, c, t); }
|
{ super(e, i, c, t); }
|
||||||
protected A8 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
protected A8 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||||
{ return new A8(e, i, c, t); }
|
{ return new A8(e, i, c, t); }
|
||||||
protected Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
protected Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
||||||
protected Object invoke_I8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
protected Object invoke_I8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
||||||
protected Object invoke_J8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
protected Object invoke_J8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
||||||
protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
protected Object invoke_F8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
||||||
protected Object invoke_D8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
protected Object invoke_D8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7)); }
|
||||||
}
|
}
|
||||||
static class A9 extends Adapter {
|
static class A9 extends Adapter {
|
||||||
protected A9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
@ -605,11 +607,11 @@ class genclasses {
|
|||||||
{ super(e, i, c, t); }
|
{ super(e, i, c, t); }
|
||||||
protected A9 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
protected A9 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||||
{ return new A9(e, i, c, t); }
|
{ return new A9(e, i, c, t); }
|
||||||
protected Object invoke_L9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
protected Object invoke_L9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
||||||
protected Object invoke_I9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
protected Object invoke_I9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
||||||
protected Object invoke_J9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
protected Object invoke_J9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
||||||
protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
protected Object invoke_F9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
||||||
protected Object invoke_D9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
protected Object invoke_D9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8)); }
|
||||||
}
|
}
|
||||||
static class A10 extends Adapter {
|
static class A10 extends Adapter {
|
||||||
protected A10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
@ -617,10 +619,10 @@ class genclasses {
|
|||||||
{ super(e, i, c, t); }
|
{ super(e, i, c, t); }
|
||||||
protected A10 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
protected A10 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t)
|
||||||
{ return new A10(e, i, c, t); }
|
{ return new A10(e, i, c, t); }
|
||||||
protected Object invoke_L10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_L(invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
protected Object invoke_L10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_L((Object)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
||||||
protected Object invoke_I10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_I(invoker.<int >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
protected Object invoke_I10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_I((int) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
||||||
protected Object invoke_J10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_J(invoker.<long >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
protected Object invoke_J10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_J((long) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
||||||
protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_F(invoker.<float >invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
protected Object invoke_F10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_F((float) invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
||||||
protected Object invoke_D10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_D(invoker.<double>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
protected Object invoke_D10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return convert_D((double)invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
160
jdk/src/share/classes/sun/dyn/InvokeGeneric.java
Normal file
160
jdk/src/share/classes/sun/dyn/InvokeGeneric.java
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sun.dyn;
|
||||||
|
|
||||||
|
import java.dyn.*;
|
||||||
|
import java.lang.reflect.*;
|
||||||
|
import sun.dyn.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapters which manage MethodHanndle.invokeGeneric calls.
|
||||||
|
* The JVM calls one of these when the exact type match fails.
|
||||||
|
* @author jrose
|
||||||
|
*/
|
||||||
|
class InvokeGeneric {
|
||||||
|
// erased type for the call, which originates from an invokeGeneric site
|
||||||
|
private final MethodType erasedCallerType;
|
||||||
|
// an invoker of type (MT, MH; A...) -> R
|
||||||
|
private final MethodHandle initialInvoker;
|
||||||
|
|
||||||
|
/** Compute and cache information for this adapter, so that it can
|
||||||
|
* call out to targets of the erasure-family of the given erased type.
|
||||||
|
*/
|
||||||
|
private InvokeGeneric(MethodType erasedCallerType) throws NoAccessException {
|
||||||
|
this.erasedCallerType = erasedCallerType;
|
||||||
|
this.initialInvoker = makeInitialInvoker();
|
||||||
|
assert initialInvoker.type().equals(erasedCallerType
|
||||||
|
.insertParameterTypes(0, MethodType.class, MethodHandle.class))
|
||||||
|
: initialInvoker.type();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MethodHandles.Lookup lookup() {
|
||||||
|
return MethodHandleImpl.IMPL_LOOKUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return the adapter information for this type's erasure. */
|
||||||
|
static MethodHandle genericInvokerOf(MethodType type) {
|
||||||
|
MethodTypeImpl form = MethodTypeImpl.of(type);
|
||||||
|
MethodHandle genericInvoker = form.genericInvoker;
|
||||||
|
if (genericInvoker == null) {
|
||||||
|
try {
|
||||||
|
InvokeGeneric gen = new InvokeGeneric(form.erasedType());
|
||||||
|
form.genericInvoker = genericInvoker = gen.initialInvoker;
|
||||||
|
} catch (NoAccessException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return genericInvoker;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodHandle makeInitialInvoker() throws NoAccessException {
|
||||||
|
// postDispatch = #(MH'; MT, MH; A...){MH'(MT, MH; A)}
|
||||||
|
MethodHandle postDispatch = makePostDispatchInvoker();
|
||||||
|
MethodHandle invoker;
|
||||||
|
if (returnConversionPossible()) {
|
||||||
|
invoker = MethodHandles.foldArguments(postDispatch,
|
||||||
|
dispatcher("dispatchWithConversion"));
|
||||||
|
} else {
|
||||||
|
invoker = MethodHandles.foldArguments(postDispatch, dispatcher("dispatch"));
|
||||||
|
}
|
||||||
|
return invoker;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Class<?>[] EXTRA_ARGS = { MethodType.class, MethodHandle.class };
|
||||||
|
private MethodHandle makePostDispatchInvoker() {
|
||||||
|
// Take (MH'; MT, MH; A...) and run MH'(MT, MH; A...).
|
||||||
|
MethodType invokerType = erasedCallerType.insertParameterTypes(0, EXTRA_ARGS);
|
||||||
|
return MethodHandles.exactInvoker(invokerType);
|
||||||
|
}
|
||||||
|
private MethodHandle dropDispatchArguments(MethodHandle targetInvoker) {
|
||||||
|
assert(targetInvoker.type().parameterType(0) == MethodHandle.class);
|
||||||
|
return MethodHandles.dropArguments(targetInvoker, 1, EXTRA_ARGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodHandle dispatcher(String dispatchName) throws NoAccessException {
|
||||||
|
return lookup().bind(this, dispatchName,
|
||||||
|
MethodType.methodType(MethodHandle.class,
|
||||||
|
MethodType.class, MethodHandle.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
static final boolean USE_AS_TYPE_PATH = true;
|
||||||
|
|
||||||
|
/** Return a method handle to invoke on the callerType, target, and remaining arguments.
|
||||||
|
* The method handle must finish the call.
|
||||||
|
* This is the first look at the caller type and target.
|
||||||
|
*/
|
||||||
|
private MethodHandle dispatch(MethodType callerType, MethodHandle target) {
|
||||||
|
MethodType targetType = target.type();
|
||||||
|
if (USE_AS_TYPE_PATH || target instanceof AdapterMethodHandle.WithTypeHandler) {
|
||||||
|
MethodHandle newTarget = target.asType(callerType);
|
||||||
|
targetType = callerType;
|
||||||
|
Invokers invokers = MethodTypeImpl.invokers(Access.TOKEN, targetType);
|
||||||
|
MethodHandle invoker = invokers.erasedInvokerWithDrops;
|
||||||
|
if (invoker == null) {
|
||||||
|
invokers.erasedInvokerWithDrops = invoker =
|
||||||
|
dropDispatchArguments(invokers.erasedInvoker());
|
||||||
|
}
|
||||||
|
return invoker.bindTo(newTarget);
|
||||||
|
}
|
||||||
|
throw new RuntimeException("NYI");
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodHandle dispatchWithConversion(MethodType callerType, MethodHandle target) {
|
||||||
|
MethodHandle finisher = dispatch(callerType, target);
|
||||||
|
if (returnConversionNeeded(callerType, target))
|
||||||
|
finisher = addReturnConversion(finisher, callerType.returnType()); //FIXME: slow
|
||||||
|
return finisher;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean returnConversionPossible() {
|
||||||
|
Class<?> needType = erasedCallerType.returnType();
|
||||||
|
return !needType.isPrimitive();
|
||||||
|
}
|
||||||
|
private boolean returnConversionNeeded(MethodType callerType, MethodHandle target) {
|
||||||
|
Class<?> needType = callerType.returnType();
|
||||||
|
if (needType == erasedCallerType.returnType())
|
||||||
|
return false; // no conversions possible, since must be primitive or Object
|
||||||
|
Class<?> haveType = target.type().returnType();
|
||||||
|
if (VerifyType.isNullConversion(haveType, needType))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
private MethodHandle addReturnConversion(MethodHandle target, Class<?> type) {
|
||||||
|
if (true) throw new RuntimeException("NYI");
|
||||||
|
// FIXME: This is slow because it creates a closure node on every call that requires a return cast.
|
||||||
|
MethodType targetType = target.type();
|
||||||
|
MethodHandle caster = ValueConversions.identity(type);
|
||||||
|
caster = caster.asType(MethodType.methodType(type, targetType.returnType()));
|
||||||
|
// Drop irrelevant arguments, because we only care about the return value:
|
||||||
|
caster = MethodHandles.dropArguments(caster, 1, targetType.parameterList());
|
||||||
|
MethodHandle result = MethodHandles.foldArguments(caster, target);
|
||||||
|
return result.asType(target.type());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "InvokeGeneric"+erasedCallerType;
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,7 @@
|
|||||||
package sun.dyn;
|
package sun.dyn;
|
||||||
|
|
||||||
import java.dyn.*;
|
import java.dyn.*;
|
||||||
|
import sun.dyn.empty.Empty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construction and caching of often-used invokers.
|
* Construction and caching of often-used invokers.
|
||||||
@ -38,12 +39,19 @@ public class Invokers {
|
|||||||
// exact invoker for the outgoing call
|
// exact invoker for the outgoing call
|
||||||
private /*lazy*/ MethodHandle exactInvoker;
|
private /*lazy*/ MethodHandle exactInvoker;
|
||||||
|
|
||||||
|
// erased (partially untyped but with primitives) invoker for the outgoing call
|
||||||
|
private /*lazy*/ MethodHandle erasedInvoker;
|
||||||
|
/*lazy*/ MethodHandle erasedInvokerWithDrops; // for InvokeGeneric
|
||||||
|
|
||||||
// generic (untyped) invoker for the outgoing call
|
// generic (untyped) invoker for the outgoing call
|
||||||
private /*lazy*/ MethodHandle genericInvoker;
|
private /*lazy*/ MethodHandle genericInvoker;
|
||||||
|
|
||||||
// generic (untyped) invoker for the outgoing call; accepts a single Object[]
|
// generic (untyped) invoker for the outgoing call; accepts a single Object[]
|
||||||
private final /*lazy*/ MethodHandle[] varargsInvokers;
|
private final /*lazy*/ MethodHandle[] varargsInvokers;
|
||||||
|
|
||||||
|
// invoker for an unbound callsite
|
||||||
|
private /*lazy*/ MethodHandle uninitializedCallSite;
|
||||||
|
|
||||||
/** Compute and cache information common to all collecting adapters
|
/** Compute and cache information common to all collecting adapters
|
||||||
* that implement members of the erasure-family of the given erased type.
|
* that implement members of the erasure-family of the given erased type.
|
||||||
*/
|
*/
|
||||||
@ -80,6 +88,19 @@ public class Invokers {
|
|||||||
return invoker;
|
return invoker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MethodHandle erasedInvoker() {
|
||||||
|
MethodHandle invoker1 = exactInvoker();
|
||||||
|
MethodHandle invoker = erasedInvoker;
|
||||||
|
if (invoker != null) return invoker;
|
||||||
|
MethodType erasedType = targetType.erase();
|
||||||
|
if (erasedType == targetType.generic())
|
||||||
|
invoker = genericInvoker();
|
||||||
|
else
|
||||||
|
invoker = MethodHandles.convertArguments(invoker1, invokerType(erasedType));
|
||||||
|
erasedInvoker = invoker;
|
||||||
|
return invoker;
|
||||||
|
}
|
||||||
|
|
||||||
public MethodHandle varargsInvoker(int objectArgCount) {
|
public MethodHandle varargsInvoker(int objectArgCount) {
|
||||||
MethodHandle vaInvoker = varargsInvokers[objectArgCount];
|
MethodHandle vaInvoker = varargsInvokers[objectArgCount];
|
||||||
if (vaInvoker != null) return vaInvoker;
|
if (vaInvoker != null) return vaInvoker;
|
||||||
@ -90,6 +111,35 @@ public class Invokers {
|
|||||||
return vaInvoker;
|
return vaInvoker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static MethodHandle THROW_UCS = null;
|
||||||
|
|
||||||
|
public MethodHandle uninitializedCallSite() {
|
||||||
|
MethodHandle invoker = uninitializedCallSite;
|
||||||
|
if (invoker != null) return invoker;
|
||||||
|
if (targetType.parameterCount() > 0) {
|
||||||
|
MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount());
|
||||||
|
Invokers invokers0 = MethodTypeImpl.invokers(Access.TOKEN, type0);
|
||||||
|
invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(),
|
||||||
|
0, targetType.parameterList());
|
||||||
|
assert(invoker.type().equals(targetType));
|
||||||
|
uninitializedCallSite = invoker;
|
||||||
|
return invoker;
|
||||||
|
}
|
||||||
|
if (THROW_UCS == null) {
|
||||||
|
try {
|
||||||
|
THROW_UCS = MethodHandleImpl.IMPL_LOOKUP
|
||||||
|
.findStatic(CallSite.class, "uninitializedCallSite",
|
||||||
|
MethodType.methodType(Empty.class));
|
||||||
|
} catch (NoAccessException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
invoker = AdapterMethodHandle.makeRetypeRaw(Access.TOKEN, targetType, THROW_UCS);
|
||||||
|
assert(invoker.type().equals(targetType));
|
||||||
|
uninitializedCallSite = invoker;
|
||||||
|
return invoker;
|
||||||
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Invokers"+targetType;
|
return "Invokers"+targetType;
|
||||||
}
|
}
|
||||||
|
@ -1,172 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package sun.dyn;
|
|
||||||
|
|
||||||
import java.dyn.*;
|
|
||||||
import sun.dyn.Access;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Java method handle is a deprecated proposal for extending
|
|
||||||
* the basic method handle type with additional
|
|
||||||
* programmer defined methods and fields.
|
|
||||||
* Its behavior as a method handle is determined at instance creation time,
|
|
||||||
* by providing the new instance with an "entry point" method handle
|
|
||||||
* to handle calls. This entry point must accept a leading argument
|
|
||||||
* whose type is the Java method handle itself or a supertype, and the
|
|
||||||
* entry point is always called with the Java method handle itself as
|
|
||||||
* the first argument. This is similar to ordinary virtual methods, which also
|
|
||||||
* accept the receiver object {@code this} as an implicit leading argument.
|
|
||||||
* The {@code MethodType} of the Java method handle is the same as that
|
|
||||||
* of the entry point method handle, with the leading parameter type
|
|
||||||
* omitted.
|
|
||||||
* <p>
|
|
||||||
* Here is an example of usage, creating a hybrid object/functional datum:
|
|
||||||
* <p><blockquote><pre>
|
|
||||||
* class Greeter extends JavaMethodHandle {
|
|
||||||
* private String greeting = "hello";
|
|
||||||
* public void setGreeting(String s) { greeting = s; }
|
|
||||||
* public void run() { System.out.println(greeting+", "+greetee); }
|
|
||||||
* private final String greetee;
|
|
||||||
* Greeter(String greetee) {
|
|
||||||
* super(RUN); // alternatively, super("run")
|
|
||||||
* this.greetee = greetee;
|
|
||||||
* }
|
|
||||||
* // the entry point function is computed once:
|
|
||||||
* private static final MethodHandle RUN
|
|
||||||
* = MethodHandles.lookup().findVirtual(Greeter.class, "run",
|
|
||||||
* MethodType.make(void.class));
|
|
||||||
* }
|
|
||||||
* // class Main { public static void main(String... av) { ...
|
|
||||||
* Greeter greeter = new Greeter("world");
|
|
||||||
* greeter.run(); // prints "hello, world"
|
|
||||||
* // Statically typed method handle invocation (most direct):
|
|
||||||
* MethodHandle mh = greeter;
|
|
||||||
* mh.<void>invokeExact(); // also prints "hello, world"
|
|
||||||
* // Dynamically typed method handle invocation:
|
|
||||||
* MethodHandles.invokeExact(greeter); // also prints "hello, world"
|
|
||||||
* greeter.setGreeting("howdy");
|
|
||||||
* mh.invokeExact(); // prints "howdy, world" (object-like mutable behavior)
|
|
||||||
* </pre></blockquote>
|
|
||||||
* <p>
|
|
||||||
* In the example of {@code Greeter}, the method {@code run} provides the entry point.
|
|
||||||
* The entry point need not be a constant value; it may be independently
|
|
||||||
* computed in each call to the constructor. The entry point does not
|
|
||||||
* even need to be a method on the {@code Greeter} class, though
|
|
||||||
* that is the typical case.
|
|
||||||
* <p>
|
|
||||||
* The entry point may also be provided symbolically, in which case the the
|
|
||||||
* {@code JavaMethodHandle} constructor performs the lookup of the entry point.
|
|
||||||
* This makes it possible to use {@code JavaMethodHandle} to create an anonymous
|
|
||||||
* inner class:
|
|
||||||
* <p><blockquote><pre>
|
|
||||||
* // We can also do this with symbolic names and/or inner classes:
|
|
||||||
* MethodHandles.invokeExact(new JavaMethodHandle("yow") {
|
|
||||||
* void yow() { System.out.println("yow, world"); }
|
|
||||||
* });
|
|
||||||
* </pre></blockquote>
|
|
||||||
* <p>
|
|
||||||
* Here is similar lower-level code which works in terms of a bound method handle.
|
|
||||||
* <p><blockquote><pre>
|
|
||||||
* class Greeter {
|
|
||||||
* public void run() { System.out.println("hello, "+greetee); }
|
|
||||||
* private final String greetee;
|
|
||||||
* Greeter(String greetee) { this.greetee = greetee; }
|
|
||||||
* // the entry point function is computed once:
|
|
||||||
* private static final MethodHandle RUN
|
|
||||||
* = MethodHandles.findVirtual(Greeter.class, "run",
|
|
||||||
* MethodType.make(void.class));
|
|
||||||
* }
|
|
||||||
* // class Main { public static void main(String... av) { ...
|
|
||||||
* Greeter greeter = new Greeter("world");
|
|
||||||
* greeter.run(); // prints "hello, world"
|
|
||||||
* MethodHandle mh = MethodHanndles.insertArgument(Greeter.RUN, 0, greeter);
|
|
||||||
* mh.invokeExact(); // also prints "hello, world"
|
|
||||||
* </pre></blockquote>
|
|
||||||
* Note that the method handle must be separately created as a view on the base object.
|
|
||||||
* This increases footprint, complexity, and dynamic indirections.
|
|
||||||
* <p>
|
|
||||||
* Here is a pure functional value expressed most concisely as an anonymous inner class:
|
|
||||||
* <p><blockquote><pre>
|
|
||||||
* // class Main { public static void main(String... av) { ...
|
|
||||||
* final String greetee = "world";
|
|
||||||
* MethodHandle greeter = new JavaMethodHandle("run") {
|
|
||||||
* private void run() { System.out.println("hello, "+greetee); }
|
|
||||||
* }
|
|
||||||
* greeter.invokeExact(); // prints "hello, world"
|
|
||||||
* </pre></blockquote>
|
|
||||||
* <p>
|
|
||||||
* Here is an abstract parameterized lvalue, efficiently expressed as a subtype of MethodHandle,
|
|
||||||
* and instantiated as an anonymous class. The data structure is a handle to 1-D array,
|
|
||||||
* with a specialized index type (long). It is created by inner class, and uses
|
|
||||||
* signature-polymorphic APIs throughout.
|
|
||||||
* <p><blockquote><pre>
|
|
||||||
* abstract class AssignableMethodHandle extends JavaMethodHandle {
|
|
||||||
* private final MethodHandle setter;
|
|
||||||
* public MethodHandle setter() { return setter; }
|
|
||||||
* public AssignableMethodHandle(String get, String set) {
|
|
||||||
* super(get);
|
|
||||||
* MethodType getType = this.type();
|
|
||||||
* MethodType setType = getType.insertParameterType(getType.parameterCount(), getType.returnType()).changeReturnType(void.class);
|
|
||||||
* this.setter = MethodHandles.publicLookup().bind(this, set, setType);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* // class Main { public static void main(String... av) { ...
|
|
||||||
* final Number[] stuff = { 123, 456 };
|
|
||||||
* AssignableMethodHandle stuffPtr = new AssignableMethodHandle("get", "set") {
|
|
||||||
* public Number get(long i) { return stuff[(int)i]; }
|
|
||||||
* public void set(long i, Object x) { stuff[(int)i] = x; }
|
|
||||||
* }
|
|
||||||
* int x = (Integer) stuffPtr.<Number>invokeExact(1L); // 456
|
|
||||||
* stuffPtr.setter().<void>invokeExact(0L, (Number) 789); // replaces 123 with 789
|
|
||||||
* </pre></blockquote>
|
|
||||||
* @see MethodHandle
|
|
||||||
* @deprecated The JSR 292 EG intends to replace {@code JavaMethodHandle} with
|
|
||||||
* an interface-based API for mixing method handle behavior with other classes.
|
|
||||||
* @author John Rose, JSR 292 EG
|
|
||||||
*/
|
|
||||||
public abstract class JavaMethodHandle
|
|
||||||
// Note: This is an implementation inheritance hack, and will be removed
|
|
||||||
// with a JVM change which moves the required hidden behavior onto this class.
|
|
||||||
extends sun.dyn.BoundMethodHandle
|
|
||||||
{
|
|
||||||
private static final Access IMPL_TOKEN = Access.getToken();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When creating a {@code JavaMethodHandle}, the actual method handle
|
|
||||||
* invocation behavior will be delegated to the specified {@code entryPoint}.
|
|
||||||
* This may be any method handle which can take the newly constructed object
|
|
||||||
* as a leading parameter.
|
|
||||||
* <p>
|
|
||||||
* The method handle type of {@code this} (i.e, the fully constructed object)
|
|
||||||
* will be {@code entryPoint}, minus the leading argument.
|
|
||||||
* The leading argument will be bound to {@code this} on every method
|
|
||||||
* handle invocation.
|
|
||||||
* @param entryPoint the method handle to handle calls
|
|
||||||
*/
|
|
||||||
protected JavaMethodHandle(MethodHandle entryPoint) {
|
|
||||||
super(entryPoint);
|
|
||||||
}
|
|
||||||
}
|
|
@ -199,7 +199,7 @@ public abstract class MethodHandleImpl {
|
|||||||
return allocator;
|
return allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class AllocateObject<C> extends JavaMethodHandle {
|
static final class AllocateObject<C> extends BoundMethodHandle {
|
||||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||||
|
|
||||||
private final Class<C> allocateClass;
|
private final Class<C> allocateClass;
|
||||||
@ -207,7 +207,7 @@ public abstract class MethodHandleImpl {
|
|||||||
|
|
||||||
private AllocateObject(MethodHandle invoker,
|
private AllocateObject(MethodHandle invoker,
|
||||||
Class<C> allocateClass, MethodHandle rawConstructor) {
|
Class<C> allocateClass, MethodHandle rawConstructor) {
|
||||||
super(invoker);
|
super(Access.TOKEN, invoker);
|
||||||
this.allocateClass = allocateClass;
|
this.allocateClass = allocateClass;
|
||||||
this.rawConstructor = rawConstructor;
|
this.rawConstructor = rawConstructor;
|
||||||
}
|
}
|
||||||
@ -237,7 +237,7 @@ public abstract class MethodHandleImpl {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return allocateClass.getSimpleName();
|
return addTypeString(allocateClass.getSimpleName(), this);
|
||||||
}
|
}
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private C allocate() throws InstantiationException {
|
private C allocate() throws InstantiationException {
|
||||||
@ -245,52 +245,52 @@ public abstract class MethodHandleImpl {
|
|||||||
}
|
}
|
||||||
private C invoke_V(Object... av) throws Throwable {
|
private C invoke_V(Object... av) throws Throwable {
|
||||||
C obj = allocate();
|
C obj = allocate();
|
||||||
rawConstructor.<void>invokeExact((Object)obj, av);
|
rawConstructor.invokeExact((Object)obj, av);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
private C invoke_L0() throws Throwable {
|
private C invoke_L0() throws Throwable {
|
||||||
C obj = allocate();
|
C obj = allocate();
|
||||||
rawConstructor.<void>invokeExact((Object)obj);
|
rawConstructor.invokeExact((Object)obj);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
private C invoke_L1(Object a0) throws Throwable {
|
private C invoke_L1(Object a0) throws Throwable {
|
||||||
C obj = allocate();
|
C obj = allocate();
|
||||||
rawConstructor.<void>invokeExact((Object)obj, a0);
|
rawConstructor.invokeExact((Object)obj, a0);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
private C invoke_L2(Object a0, Object a1) throws Throwable {
|
private C invoke_L2(Object a0, Object a1) throws Throwable {
|
||||||
C obj = allocate();
|
C obj = allocate();
|
||||||
rawConstructor.<void>invokeExact((Object)obj, a0, a1);
|
rawConstructor.invokeExact((Object)obj, a0, a1);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
private C invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
|
private C invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
|
||||||
C obj = allocate();
|
C obj = allocate();
|
||||||
rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2);
|
rawConstructor.invokeExact((Object)obj, a0, a1, a2);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
private C invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
|
private C invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
|
||||||
C obj = allocate();
|
C obj = allocate();
|
||||||
rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2, a3);
|
rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
private C invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
|
private C invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
|
||||||
C obj = allocate();
|
C obj = allocate();
|
||||||
rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2, a3, a4);
|
rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3, a4);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
private C invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
|
private C invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
|
||||||
C obj = allocate();
|
C obj = allocate();
|
||||||
rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2, a3, a4, a5);
|
rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3, a4, a5);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
private C invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
|
private C invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
|
||||||
C obj = allocate();
|
C obj = allocate();
|
||||||
rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2, a3, a4, a5, a6);
|
rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3, a4, a5, a6);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
private C invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
|
private C invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
|
||||||
C obj = allocate();
|
C obj = allocate();
|
||||||
rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2, a3, a4, a5, a6, a7);
|
rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3, a4, a5, a6, a7);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
static MethodHandle[] makeInvokes() {
|
static MethodHandle[] makeInvokes() {
|
||||||
@ -369,19 +369,19 @@ public abstract class MethodHandleImpl {
|
|||||||
return mhs[isSetter ? 1 : 0];
|
return mhs[isSetter ? 1 : 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class FieldAccessor<C,V> extends JavaMethodHandle {
|
static final class FieldAccessor<C,V> extends BoundMethodHandle {
|
||||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||||
final Object base; // for static refs only
|
final Object base; // for static refs only
|
||||||
final long offset;
|
final long offset;
|
||||||
final String name;
|
final String name;
|
||||||
|
|
||||||
public FieldAccessor(Access token, MemberName field, boolean isSetter) {
|
public FieldAccessor(Access token, MemberName field, boolean isSetter) {
|
||||||
super(fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic()));
|
super(Access.TOKEN, fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic()));
|
||||||
this.offset = (long) field.getVMIndex(token);
|
this.offset = (long) field.getVMIndex(token);
|
||||||
this.name = field.getName();
|
this.name = field.getName();
|
||||||
this.base = staticBase(field);
|
this.base = staticBase(field);
|
||||||
}
|
}
|
||||||
public String toString() { return name; }
|
public String toString() { return addTypeString(name, this); }
|
||||||
|
|
||||||
int getFieldI(C obj) { return unsafe.getInt(obj, offset); }
|
int getFieldI(C obj) { return unsafe.getInt(obj, offset); }
|
||||||
void setFieldI(C obj, int x) { unsafe.putInt(obj, offset, x); }
|
void setFieldI(C obj, int x) { unsafe.putInt(obj, offset, x); }
|
||||||
@ -560,7 +560,9 @@ public abstract class MethodHandleImpl {
|
|||||||
MethodHandle bindReceiver(Access token,
|
MethodHandle bindReceiver(Access token,
|
||||||
MethodHandle target, Object receiver) {
|
MethodHandle target, Object receiver) {
|
||||||
Access.check(token);
|
Access.check(token);
|
||||||
if (target instanceof AdapterMethodHandle) {
|
if (target instanceof AdapterMethodHandle &&
|
||||||
|
((AdapterMethodHandle)target).conversionOp() == MethodHandleNatives.Constants.OP_RETYPE_ONLY
|
||||||
|
) {
|
||||||
Object info = MethodHandleNatives.getTargetInfo(target);
|
Object info = MethodHandleNatives.getTargetInfo(target);
|
||||||
if (info instanceof DirectMethodHandle) {
|
if (info instanceof DirectMethodHandle) {
|
||||||
DirectMethodHandle dmh = (DirectMethodHandle) info;
|
DirectMethodHandle dmh = (DirectMethodHandle) info;
|
||||||
@ -908,11 +910,11 @@ public abstract class MethodHandleImpl {
|
|||||||
throw new UnsupportedOperationException("NYI");
|
throw new UnsupportedOperationException("NYI");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class GuardWithTest extends JavaMethodHandle {
|
private static class GuardWithTest extends BoundMethodHandle {
|
||||||
private final MethodHandle test, target, fallback;
|
private final MethodHandle test, target, fallback;
|
||||||
private GuardWithTest(MethodHandle invoker,
|
private GuardWithTest(MethodHandle invoker,
|
||||||
MethodHandle test, MethodHandle target, MethodHandle fallback) {
|
MethodHandle test, MethodHandle target, MethodHandle fallback) {
|
||||||
super(invoker);
|
super(Access.TOKEN, invoker);
|
||||||
this.test = test;
|
this.test = test;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.fallback = fallback;
|
this.fallback = fallback;
|
||||||
@ -946,57 +948,57 @@ public abstract class MethodHandleImpl {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return target.toString();
|
return addTypeString(target, this);
|
||||||
}
|
}
|
||||||
private Object invoke_V(Object... av) throws Throwable {
|
private Object invoke_V(Object... av) throws Throwable {
|
||||||
if (test.<boolean>invokeExact(av))
|
if ((boolean) test.invokeExact(av))
|
||||||
return target.<Object>invokeExact(av);
|
return target.invokeExact(av);
|
||||||
return fallback.<Object>invokeExact(av);
|
return fallback.invokeExact(av);
|
||||||
}
|
}
|
||||||
private Object invoke_L0() throws Throwable {
|
private Object invoke_L0() throws Throwable {
|
||||||
if (test.<boolean>invokeExact())
|
if ((boolean) test.invokeExact())
|
||||||
return target.<Object>invokeExact();
|
return target.invokeExact();
|
||||||
return fallback.<Object>invokeExact();
|
return fallback.invokeExact();
|
||||||
}
|
}
|
||||||
private Object invoke_L1(Object a0) throws Throwable {
|
private Object invoke_L1(Object a0) throws Throwable {
|
||||||
if (test.<boolean>invokeExact(a0))
|
if ((boolean) test.invokeExact(a0))
|
||||||
return target.<Object>invokeExact(a0);
|
return target.invokeExact(a0);
|
||||||
return fallback.<Object>invokeExact(a0);
|
return fallback.invokeExact(a0);
|
||||||
}
|
}
|
||||||
private Object invoke_L2(Object a0, Object a1) throws Throwable {
|
private Object invoke_L2(Object a0, Object a1) throws Throwable {
|
||||||
if (test.<boolean>invokeExact(a0, a1))
|
if ((boolean) test.invokeExact(a0, a1))
|
||||||
return target.<Object>invokeExact(a0, a1);
|
return target.invokeExact(a0, a1);
|
||||||
return fallback.<Object>invokeExact(a0, a1);
|
return fallback.invokeExact(a0, a1);
|
||||||
}
|
}
|
||||||
private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
|
private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
|
||||||
if (test.<boolean>invokeExact(a0, a1, a2))
|
if ((boolean) test.invokeExact(a0, a1, a2))
|
||||||
return target.<Object>invokeExact(a0, a1, a2);
|
return target.invokeExact(a0, a1, a2);
|
||||||
return fallback.<Object>invokeExact(a0, a1, a2);
|
return fallback.invokeExact(a0, a1, a2);
|
||||||
}
|
}
|
||||||
private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
|
private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
|
||||||
if (test.<boolean>invokeExact(a0, a1, a2, a3))
|
if ((boolean) test.invokeExact(a0, a1, a2, a3))
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3);
|
return target.invokeExact(a0, a1, a2, a3);
|
||||||
return fallback.<Object>invokeExact(a0, a1, a2, a3);
|
return fallback.invokeExact(a0, a1, a2, a3);
|
||||||
}
|
}
|
||||||
private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
|
private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
|
||||||
if (test.<boolean>invokeExact(a0, a1, a2, a3, a4))
|
if ((boolean) test.invokeExact(a0, a1, a2, a3, a4))
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4);
|
return target.invokeExact(a0, a1, a2, a3, a4);
|
||||||
return fallback.<Object>invokeExact(a0, a1, a2, a3, a4);
|
return fallback.invokeExact(a0, a1, a2, a3, a4);
|
||||||
}
|
}
|
||||||
private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
|
private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
|
||||||
if (test.<boolean>invokeExact(a0, a1, a2, a3, a4, a5))
|
if ((boolean) test.invokeExact(a0, a1, a2, a3, a4, a5))
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5);
|
return target.invokeExact(a0, a1, a2, a3, a4, a5);
|
||||||
return fallback.<Object>invokeExact(a0, a1, a2, a3, a4, a5);
|
return fallback.invokeExact(a0, a1, a2, a3, a4, a5);
|
||||||
}
|
}
|
||||||
private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
|
private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
|
||||||
if (test.<boolean>invokeExact(a0, a1, a2, a3, a4, a5, a6))
|
if ((boolean) test.invokeExact(a0, a1, a2, a3, a4, a5, a6))
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6);
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
|
||||||
return fallback.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6);
|
return fallback.invokeExact(a0, a1, a2, a3, a4, a5, a6);
|
||||||
}
|
}
|
||||||
private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
|
private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
|
||||||
if (test.<boolean>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7))
|
if ((boolean) test.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7))
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
|
||||||
return fallback.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
|
return fallback.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
|
||||||
}
|
}
|
||||||
static MethodHandle[] makeInvokes() {
|
static MethodHandle[] makeInvokes() {
|
||||||
ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
|
ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
|
||||||
@ -1036,7 +1038,7 @@ public abstract class MethodHandleImpl {
|
|||||||
return GuardWithTest.make(token, test, target, fallback);
|
return GuardWithTest.make(token, test, target, fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class GuardWithCatch extends JavaMethodHandle {
|
private static class GuardWithCatch extends BoundMethodHandle {
|
||||||
private final MethodHandle target;
|
private final MethodHandle target;
|
||||||
private final Class<? extends Throwable> exType;
|
private final Class<? extends Throwable> exType;
|
||||||
private final MethodHandle catcher;
|
private final MethodHandle catcher;
|
||||||
@ -1045,93 +1047,93 @@ public abstract class MethodHandleImpl {
|
|||||||
}
|
}
|
||||||
public GuardWithCatch(MethodHandle invoker,
|
public GuardWithCatch(MethodHandle invoker,
|
||||||
MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
|
MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
|
||||||
super(invoker);
|
super(Access.TOKEN, invoker);
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.exType = exType;
|
this.exType = exType;
|
||||||
this.catcher = catcher;
|
this.catcher = catcher;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return target.toString();
|
return addTypeString(target, this);
|
||||||
}
|
}
|
||||||
private Object invoke_V(Object... av) throws Throwable {
|
private Object invoke_V(Object... av) throws Throwable {
|
||||||
try {
|
try {
|
||||||
return target.<Object>invokeExact(av);
|
return target.invokeExact(av);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
if (!exType.isInstance(t)) throw t;
|
if (!exType.isInstance(t)) throw t;
|
||||||
return catcher.<Object>invokeExact(t, av);
|
return catcher.invokeExact(t, av);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private Object invoke_L0() throws Throwable {
|
private Object invoke_L0() throws Throwable {
|
||||||
try {
|
try {
|
||||||
return target.<Object>invokeExact();
|
return target.invokeExact();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
if (!exType.isInstance(t)) throw t;
|
if (!exType.isInstance(t)) throw t;
|
||||||
return catcher.<Object>invokeExact(t);
|
return catcher.invokeExact(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private Object invoke_L1(Object a0) throws Throwable {
|
private Object invoke_L1(Object a0) throws Throwable {
|
||||||
try {
|
try {
|
||||||
return target.<Object>invokeExact(a0);
|
return target.invokeExact(a0);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
if (!exType.isInstance(t)) throw t;
|
if (!exType.isInstance(t)) throw t;
|
||||||
return catcher.<Object>invokeExact(t, a0);
|
return catcher.invokeExact(t, a0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private Object invoke_L2(Object a0, Object a1) throws Throwable {
|
private Object invoke_L2(Object a0, Object a1) throws Throwable {
|
||||||
try {
|
try {
|
||||||
return target.<Object>invokeExact(a0, a1);
|
return target.invokeExact(a0, a1);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
if (!exType.isInstance(t)) throw t;
|
if (!exType.isInstance(t)) throw t;
|
||||||
return catcher.<Object>invokeExact(t, a0, a1);
|
return catcher.invokeExact(t, a0, a1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
|
private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
|
||||||
try {
|
try {
|
||||||
return target.<Object>invokeExact(a0, a1, a2);
|
return target.invokeExact(a0, a1, a2);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
if (!exType.isInstance(t)) throw t;
|
if (!exType.isInstance(t)) throw t;
|
||||||
return catcher.<Object>invokeExact(t, a0, a1, a2);
|
return catcher.invokeExact(t, a0, a1, a2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
|
private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
|
||||||
try {
|
try {
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3);
|
return target.invokeExact(a0, a1, a2, a3);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
if (!exType.isInstance(t)) throw t;
|
if (!exType.isInstance(t)) throw t;
|
||||||
return catcher.<Object>invokeExact(t, a0, a1, a2, a3);
|
return catcher.invokeExact(t, a0, a1, a2, a3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
|
private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
|
||||||
try {
|
try {
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4);
|
return target.invokeExact(a0, a1, a2, a3, a4);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
if (!exType.isInstance(t)) throw t;
|
if (!exType.isInstance(t)) throw t;
|
||||||
return catcher.<Object>invokeExact(t, a0, a1, a2, a3, a4);
|
return catcher.invokeExact(t, a0, a1, a2, a3, a4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
|
private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
|
||||||
try {
|
try {
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5);
|
return target.invokeExact(a0, a1, a2, a3, a4, a5);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
if (!exType.isInstance(t)) throw t;
|
if (!exType.isInstance(t)) throw t;
|
||||||
return catcher.<Object>invokeExact(t, a0, a1, a2, a3, a4, a5);
|
return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
|
private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
|
||||||
try {
|
try {
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6);
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
if (!exType.isInstance(t)) throw t;
|
if (!exType.isInstance(t)) throw t;
|
||||||
return catcher.<Object>invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
|
return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
|
private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
|
||||||
try {
|
try {
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
if (!exType.isInstance(t)) throw t;
|
if (!exType.isInstance(t)) throw t;
|
||||||
return catcher.<Object>invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7);
|
return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static MethodHandle[] makeInvokes() {
|
static MethodHandle[] makeInvokes() {
|
||||||
@ -1217,21 +1219,24 @@ public abstract class MethodHandleImpl {
|
|||||||
if (target != null)
|
if (target != null)
|
||||||
name = MethodHandleNatives.getMethodName(target);
|
name = MethodHandleNatives.getMethodName(target);
|
||||||
if (name == null)
|
if (name == null)
|
||||||
return "<unknown>";
|
return "invoke" + target.type();
|
||||||
return name.getName();
|
return name.getName() + target.type();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String addTypeString(MethodHandle target) {
|
static String addTypeString(Object obj, MethodHandle target) {
|
||||||
if (target == null) return "null";
|
String str = String.valueOf(obj);
|
||||||
return target.toString() + target.type();
|
if (target == null) return str;
|
||||||
|
int paren = str.indexOf('(');
|
||||||
|
if (paren >= 0) str = str.substring(0, paren);
|
||||||
|
return str + target.type();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void checkSpreadArgument(Object av, int n) {
|
static void checkSpreadArgument(Object av, int n) {
|
||||||
if (av == null ? n != 0 : ((Object[])av).length != n)
|
if (av == null ? n != 0 : ((Object[])av).length != n)
|
||||||
throw newIllegalArgumentException("Array is not of length "+n);
|
throw newIllegalArgumentException("Array is not of length "+n);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void raiseException(int code, Object actual, Object required) {
|
static void raiseException(int code, Object actual, Object required) {
|
||||||
String message;
|
String message;
|
||||||
// disregard the identity of the actual object, if it is not a class:
|
// disregard the identity of the actual object, if it is not a class:
|
||||||
if (!(actual instanceof Class) && !(actual instanceof MethodType))
|
if (!(actual instanceof Class) && !(actual instanceof MethodType))
|
||||||
@ -1257,4 +1262,9 @@ public abstract class MethodHandleImpl {
|
|||||||
Access.check(token);
|
Access.check(token);
|
||||||
return MethodHandleNatives.getBootstrap(callerClass);
|
return MethodHandleNatives.getBootstrap(callerClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MethodHandle withTypeHandler(Access token, MethodHandle target, MethodHandle typeHandler) {
|
||||||
|
Access.check(token);
|
||||||
|
return AdapterMethodHandle.makeTypeHandler(token, target, typeHandler);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,6 +316,20 @@ class MethodHandleNatives {
|
|||||||
return MethodTypeImpl.makeImpl(Access.TOKEN, rtype, ptypes, true);
|
return MethodTypeImpl.makeImpl(Access.TOKEN, rtype, ptypes, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JVM wants to use a MethodType with invokeGeneric. Give the runtime fair warning.
|
||||||
|
*/
|
||||||
|
static void notifyGenericMethodType(MethodType type) {
|
||||||
|
try {
|
||||||
|
// Trigger adapter creation.
|
||||||
|
InvokeGeneric.genericInvokerOf(type);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Error err = new InternalError("Exception while resolving invokeGeneric");
|
||||||
|
err.initCause(ex);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The JVM is resolving a CONSTANT_MethodHandle CP entry. And it wants our help.
|
* The JVM is resolving a CONSTANT_MethodHandle CP entry. And it wants our help.
|
||||||
* It will make an up-call to this method. (Do not change the name or signature.)
|
* It will make an up-call to this method. (Do not change the name or signature.)
|
||||||
|
@ -48,6 +48,7 @@ public class MethodTypeImpl {
|
|||||||
final long primCounts; // packed prim & double counts
|
final long primCounts; // packed prim & double counts
|
||||||
final int vmslots; // total number of parameter slots
|
final int vmslots; // total number of parameter slots
|
||||||
final MethodType erasedType; // the canonical erasure
|
final MethodType erasedType; // the canonical erasure
|
||||||
|
|
||||||
/*lazy*/ MethodType primsAsBoxes; // replace prims by wrappers
|
/*lazy*/ MethodType primsAsBoxes; // replace prims by wrappers
|
||||||
/*lazy*/ MethodType primArgsAsBoxes; // wrap args only; make raw return
|
/*lazy*/ MethodType primArgsAsBoxes; // wrap args only; make raw return
|
||||||
/*lazy*/ MethodType primsAsInts; // replace prims by int/long
|
/*lazy*/ MethodType primsAsInts; // replace prims by int/long
|
||||||
@ -59,6 +60,7 @@ public class MethodTypeImpl {
|
|||||||
/*lazy*/ FromGeneric fromGeneric; // convert cs. w/o prims to with
|
/*lazy*/ FromGeneric fromGeneric; // convert cs. w/o prims to with
|
||||||
/*lazy*/ SpreadGeneric[] spreadGeneric; // expand one argument to many
|
/*lazy*/ SpreadGeneric[] spreadGeneric; // expand one argument to many
|
||||||
/*lazy*/ FilterGeneric filterGeneric; // convert argument(s) on the fly
|
/*lazy*/ FilterGeneric filterGeneric; // convert argument(s) on the fly
|
||||||
|
/*lazy*/ MethodHandle genericInvoker; // hook for invokeGeneric
|
||||||
|
|
||||||
public MethodType erasedType() {
|
public MethodType erasedType() {
|
||||||
return erasedType;
|
return erasedType;
|
||||||
|
@ -208,7 +208,7 @@ class SpreadGeneric {
|
|||||||
* The invoker is kept separate from the target because it can be
|
* The invoker is kept separate from the target because it can be
|
||||||
* generated once per type erasure family, and reused across adapters.
|
* generated once per type erasure family, and reused across adapters.
|
||||||
*/
|
*/
|
||||||
static abstract class Adapter extends JavaMethodHandle {
|
static abstract class Adapter extends BoundMethodHandle {
|
||||||
/*
|
/*
|
||||||
* class X<<R,int M,int N>> extends Adapter {
|
* class X<<R,int M,int N>> extends Adapter {
|
||||||
* (Object**N)=>R target;
|
* (Object**N)=>R target;
|
||||||
@ -221,21 +221,21 @@ class SpreadGeneric {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return target.toString();
|
return MethodHandleImpl.addTypeString(target, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static final MethodHandle NO_ENTRY = ValueConversions.identity();
|
static final MethodHandle NO_ENTRY = ValueConversions.identity();
|
||||||
|
|
||||||
protected boolean isPrototype() { return target == null; }
|
protected boolean isPrototype() { return target == null; }
|
||||||
protected Adapter(SpreadGeneric outer) {
|
protected Adapter(SpreadGeneric outer) {
|
||||||
super(NO_ENTRY);
|
super(Access.TOKEN, NO_ENTRY);
|
||||||
this.outer = outer;
|
this.outer = outer;
|
||||||
this.target = null;
|
this.target = null;
|
||||||
assert(isPrototype());
|
assert(isPrototype());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Adapter(SpreadGeneric outer, MethodHandle target) {
|
protected Adapter(SpreadGeneric outer, MethodHandle target) {
|
||||||
super(outer.entryPoint);
|
super(Access.TOKEN, outer.entryPoint);
|
||||||
this.outer = outer;
|
this.outer = outer;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
}
|
}
|
||||||
@ -277,12 +277,12 @@ class SpreadGeneric {
|
|||||||
protected xS2(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
protected xS2(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||||
protected xS2 makeInstance(SpreadGeneric outer, MethodHandle t) { return new xS2(outer, t); }
|
protected xS2 makeInstance(SpreadGeneric outer, MethodHandle t) { return new xS2(outer, t); }
|
||||||
protected Object invoke_S0(Object a0, Object a1, Object av) throws Throwable { av = super.check(av,0);
|
protected Object invoke_S0(Object a0, Object a1, Object av) throws Throwable { av = super.check(av,0);
|
||||||
return target.<Object>invokeExact(a0, a1)); }
|
return target.invokeExact(a0, a1)); }
|
||||||
protected Object invoke_S1(Object a0, Object av) throws Throwable { av = super.check(av,1);
|
protected Object invoke_S1(Object a0, Object av) throws Throwable { av = super.check(av,1);
|
||||||
return target.<Object>invokeExact(a0,
|
return target.invokeExact(a0,
|
||||||
super.select(av,0)); }
|
super.select(av,0)); }
|
||||||
protected Object invoke_S2(Object a0, Object av) throws Throwable { av = super.check(av,1);
|
protected Object invoke_S2(Object a0, Object av) throws Throwable { av = super.check(av,1);
|
||||||
return target.<Object>invokeExact(
|
return target.invokeExact(
|
||||||
super.select(av,0), super.select(av,1)); }
|
super.select(av,0), super.select(av,1)); }
|
||||||
}
|
}
|
||||||
// */
|
// */
|
||||||
@ -300,10 +300,10 @@ class genclasses {
|
|||||||
" protected @cat@(SpreadGeneric outer, MethodHandle t) { super(outer, t); }",
|
" protected @cat@(SpreadGeneric outer, MethodHandle t) { super(outer, t); }",
|
||||||
" protected @cat@ makeInstance(SpreadGeneric outer, MethodHandle t) { return new @cat@(outer, t); }",
|
" protected @cat@ makeInstance(SpreadGeneric outer, MethodHandle t) { return new @cat@(outer, t); }",
|
||||||
" protected Object invoke_S0(@Tvav,@Object av) throws Throwable { av = super.check(av, 0);",
|
" protected Object invoke_S0(@Tvav,@Object av) throws Throwable { av = super.check(av, 0);",
|
||||||
" return target.<Object>invokeExact(@av@); }",
|
" return target.invokeExact(@av@); }",
|
||||||
" //@each-S@",
|
" //@each-S@",
|
||||||
" protected Object invoke_S@S@(@Tvav,@Object av) throws Throwable { av = super.check(av, @S@);",
|
" protected Object invoke_S@S@(@Tvav,@Object av) throws Throwable { av = super.check(av, @S@);",
|
||||||
" return target.<Object>invokeExact(@av,@@sv@); }",
|
" return target.invokeExact(@av,@@sv@); }",
|
||||||
" //@end-S@",
|
" //@end-S@",
|
||||||
" }",
|
" }",
|
||||||
} };
|
} };
|
||||||
@ -414,16 +414,16 @@ class genclasses {
|
|||||||
protected S0(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
protected S0(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||||
protected S0 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S0(outer, t); }
|
protected S0 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S0(outer, t); }
|
||||||
protected Object invoke_S0(Object av) throws Throwable { av = super.check(av, 0);
|
protected Object invoke_S0(Object av) throws Throwable { av = super.check(av, 0);
|
||||||
return target.<Object>invokeExact(); }
|
return target.invokeExact(); }
|
||||||
}
|
}
|
||||||
static class S1 extends Adapter {
|
static class S1 extends Adapter {
|
||||||
protected S1(SpreadGeneric outer) { super(outer); } // to build prototype
|
protected S1(SpreadGeneric outer) { super(outer); } // to build prototype
|
||||||
protected S1(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
protected S1(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||||
protected S1 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S1(outer, t); }
|
protected S1 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S1(outer, t); }
|
||||||
protected Object invoke_S0(Object a0, Object av) throws Throwable { av = super.check(av, 0);
|
protected Object invoke_S0(Object a0, Object av) throws Throwable { av = super.check(av, 0);
|
||||||
return target.<Object>invokeExact(a0); }
|
return target.invokeExact(a0); }
|
||||||
protected Object invoke_S1(Object av) throws Throwable { av = super.check(av, 1);
|
protected Object invoke_S1(Object av) throws Throwable { av = super.check(av, 1);
|
||||||
return target.<Object>invokeExact(
|
return target.invokeExact(
|
||||||
super.select(av,0)); }
|
super.select(av,0)); }
|
||||||
}
|
}
|
||||||
static class S2 extends Adapter {
|
static class S2 extends Adapter {
|
||||||
@ -431,12 +431,12 @@ class genclasses {
|
|||||||
protected S2(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
protected S2(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||||
protected S2 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S2(outer, t); }
|
protected S2 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S2(outer, t); }
|
||||||
protected Object invoke_S0(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 0);
|
protected Object invoke_S0(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 0);
|
||||||
return target.<Object>invokeExact(a0, a1); }
|
return target.invokeExact(a0, a1); }
|
||||||
protected Object invoke_S1(Object a0, Object av) throws Throwable { av = super.check(av, 1);
|
protected Object invoke_S1(Object a0, Object av) throws Throwable { av = super.check(av, 1);
|
||||||
return target.<Object>invokeExact(a0,
|
return target.invokeExact(a0,
|
||||||
super.select(av,0)); }
|
super.select(av,0)); }
|
||||||
protected Object invoke_S2(Object av) throws Throwable { av = super.check(av, 2);
|
protected Object invoke_S2(Object av) throws Throwable { av = super.check(av, 2);
|
||||||
return target.<Object>invokeExact(
|
return target.invokeExact(
|
||||||
super.select(av,0), super.select(av,1)); }
|
super.select(av,0), super.select(av,1)); }
|
||||||
}
|
}
|
||||||
static class S3 extends Adapter {
|
static class S3 extends Adapter {
|
||||||
@ -444,15 +444,15 @@ class genclasses {
|
|||||||
protected S3(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
protected S3(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||||
protected S3 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S3(outer, t); }
|
protected S3 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S3(outer, t); }
|
||||||
protected Object invoke_S0(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 0);
|
protected Object invoke_S0(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 0);
|
||||||
return target.<Object>invokeExact(a0, a1, a2); }
|
return target.invokeExact(a0, a1, a2); }
|
||||||
protected Object invoke_S1(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 1);
|
protected Object invoke_S1(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 1);
|
||||||
return target.<Object>invokeExact(a0, a1,
|
return target.invokeExact(a0, a1,
|
||||||
super.select(av,0)); }
|
super.select(av,0)); }
|
||||||
protected Object invoke_S2(Object a0, Object av) throws Throwable { av = super.check(av, 2);
|
protected Object invoke_S2(Object a0, Object av) throws Throwable { av = super.check(av, 2);
|
||||||
return target.<Object>invokeExact(a0,
|
return target.invokeExact(a0,
|
||||||
super.select(av,0), super.select(av,1)); }
|
super.select(av,0), super.select(av,1)); }
|
||||||
protected Object invoke_S3(Object av) throws Throwable { av = super.check(av, 3);
|
protected Object invoke_S3(Object av) throws Throwable { av = super.check(av, 3);
|
||||||
return target.<Object>invokeExact(
|
return target.invokeExact(
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
||||||
}
|
}
|
||||||
static class S4 extends Adapter {
|
static class S4 extends Adapter {
|
||||||
@ -460,18 +460,18 @@ class genclasses {
|
|||||||
protected S4(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
protected S4(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||||
protected S4 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S4(outer, t); }
|
protected S4 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S4(outer, t); }
|
||||||
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 0);
|
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 0);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3); }
|
return target.invokeExact(a0, a1, a2, a3); }
|
||||||
protected Object invoke_S1(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 1);
|
protected Object invoke_S1(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 1);
|
||||||
return target.<Object>invokeExact(a0, a1, a2,
|
return target.invokeExact(a0, a1, a2,
|
||||||
super.select(av,0)); }
|
super.select(av,0)); }
|
||||||
protected Object invoke_S2(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 2);
|
protected Object invoke_S2(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 2);
|
||||||
return target.<Object>invokeExact(a0, a1,
|
return target.invokeExact(a0, a1,
|
||||||
super.select(av,0), super.select(av,1)); }
|
super.select(av,0), super.select(av,1)); }
|
||||||
protected Object invoke_S3(Object a0, Object av) throws Throwable { av = super.check(av, 3);
|
protected Object invoke_S3(Object a0, Object av) throws Throwable { av = super.check(av, 3);
|
||||||
return target.<Object>invokeExact(a0,
|
return target.invokeExact(a0,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
||||||
protected Object invoke_S4(Object av) throws Throwable { av = super.check(av, 4);
|
protected Object invoke_S4(Object av) throws Throwable { av = super.check(av, 4);
|
||||||
return target.<Object>invokeExact(
|
return target.invokeExact(
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
||||||
}
|
}
|
||||||
static class S5 extends Adapter {
|
static class S5 extends Adapter {
|
||||||
@ -479,21 +479,21 @@ class genclasses {
|
|||||||
protected S5(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
protected S5(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||||
protected S5 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S5(outer, t); }
|
protected S5 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S5(outer, t); }
|
||||||
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 0);
|
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 0);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4); }
|
return target.invokeExact(a0, a1, a2, a3, a4); }
|
||||||
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 1);
|
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 1);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3,
|
return target.invokeExact(a0, a1, a2, a3,
|
||||||
super.select(av,0)); }
|
super.select(av,0)); }
|
||||||
protected Object invoke_S2(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 2);
|
protected Object invoke_S2(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 2);
|
||||||
return target.<Object>invokeExact(a0, a1, a2,
|
return target.invokeExact(a0, a1, a2,
|
||||||
super.select(av,0), super.select(av,1)); }
|
super.select(av,0), super.select(av,1)); }
|
||||||
protected Object invoke_S3(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 3);
|
protected Object invoke_S3(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 3);
|
||||||
return target.<Object>invokeExact(a0, a1,
|
return target.invokeExact(a0, a1,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
||||||
protected Object invoke_S4(Object a0, Object av) throws Throwable { av = super.check(av, 4);
|
protected Object invoke_S4(Object a0, Object av) throws Throwable { av = super.check(av, 4);
|
||||||
return target.<Object>invokeExact(a0,
|
return target.invokeExact(a0,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
||||||
protected Object invoke_S5(Object av) throws Throwable { av = super.check(av, 5);
|
protected Object invoke_S5(Object av) throws Throwable { av = super.check(av, 5);
|
||||||
return target.<Object>invokeExact(
|
return target.invokeExact(
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4)); }
|
super.select(av,4)); }
|
||||||
}
|
}
|
||||||
@ -502,25 +502,25 @@ class genclasses {
|
|||||||
protected S6(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
protected S6(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||||
protected S6 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S6(outer, t); }
|
protected S6 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S6(outer, t); }
|
||||||
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 0);
|
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 0);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5); }
|
return target.invokeExact(a0, a1, a2, a3, a4, a5); }
|
||||||
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 1);
|
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 1);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4,
|
return target.invokeExact(a0, a1, a2, a3, a4,
|
||||||
super.select(av,0)); }
|
super.select(av,0)); }
|
||||||
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 2);
|
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 2);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3,
|
return target.invokeExact(a0, a1, a2, a3,
|
||||||
super.select(av,0), super.select(av,1)); }
|
super.select(av,0), super.select(av,1)); }
|
||||||
protected Object invoke_S3(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 3);
|
protected Object invoke_S3(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 3);
|
||||||
return target.<Object>invokeExact(a0, a1, a2,
|
return target.invokeExact(a0, a1, a2,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
||||||
protected Object invoke_S4(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 4);
|
protected Object invoke_S4(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 4);
|
||||||
return target.<Object>invokeExact(a0, a1,
|
return target.invokeExact(a0, a1,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
||||||
protected Object invoke_S5(Object a0, Object av) throws Throwable { av = super.check(av, 5);
|
protected Object invoke_S5(Object a0, Object av) throws Throwable { av = super.check(av, 5);
|
||||||
return target.<Object>invokeExact(a0,
|
return target.invokeExact(a0,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4)); }
|
super.select(av,4)); }
|
||||||
protected Object invoke_S6(Object av) throws Throwable { av = super.check(av, 6);
|
protected Object invoke_S6(Object av) throws Throwable { av = super.check(av, 6);
|
||||||
return target.<Object>invokeExact(
|
return target.invokeExact(
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4), super.select(av,5)); }
|
super.select(av,4), super.select(av,5)); }
|
||||||
}
|
}
|
||||||
@ -529,29 +529,29 @@ class genclasses {
|
|||||||
protected S7(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
protected S7(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||||
protected S7 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S7(outer, t); }
|
protected S7 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S7(outer, t); }
|
||||||
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 0);
|
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 0);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6); }
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6); }
|
||||||
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 1);
|
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 1);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5,
|
return target.invokeExact(a0, a1, a2, a3, a4, a5,
|
||||||
super.select(av,0)); }
|
super.select(av,0)); }
|
||||||
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 2);
|
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 2);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4,
|
return target.invokeExact(a0, a1, a2, a3, a4,
|
||||||
super.select(av,0), super.select(av,1)); }
|
super.select(av,0), super.select(av,1)); }
|
||||||
protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 3);
|
protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 3);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3,
|
return target.invokeExact(a0, a1, a2, a3,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
||||||
protected Object invoke_S4(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 4);
|
protected Object invoke_S4(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 4);
|
||||||
return target.<Object>invokeExact(a0, a1, a2,
|
return target.invokeExact(a0, a1, a2,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
||||||
protected Object invoke_S5(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 5);
|
protected Object invoke_S5(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 5);
|
||||||
return target.<Object>invokeExact(a0, a1,
|
return target.invokeExact(a0, a1,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4)); }
|
super.select(av,4)); }
|
||||||
protected Object invoke_S6(Object a0, Object av) throws Throwable { av = super.check(av, 6);
|
protected Object invoke_S6(Object a0, Object av) throws Throwable { av = super.check(av, 6);
|
||||||
return target.<Object>invokeExact(a0,
|
return target.invokeExact(a0,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4), super.select(av,5)); }
|
super.select(av,4), super.select(av,5)); }
|
||||||
protected Object invoke_S7(Object av) throws Throwable { av = super.check(av, 7);
|
protected Object invoke_S7(Object av) throws Throwable { av = super.check(av, 7);
|
||||||
return target.<Object>invokeExact(
|
return target.invokeExact(
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4), super.select(av,5), super.select(av,6)); }
|
super.select(av,4), super.select(av,5), super.select(av,6)); }
|
||||||
}
|
}
|
||||||
@ -560,33 +560,33 @@ class genclasses {
|
|||||||
protected S8(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
protected S8(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||||
protected S8 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S8(outer, t); }
|
protected S8 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S8(outer, t); }
|
||||||
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object av) throws Throwable { av = super.check(av, 0);
|
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object av) throws Throwable { av = super.check(av, 0);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7); }
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7); }
|
||||||
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 1);
|
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 1);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6,
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6,
|
||||||
super.select(av,0)); }
|
super.select(av,0)); }
|
||||||
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 2);
|
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 2);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5,
|
return target.invokeExact(a0, a1, a2, a3, a4, a5,
|
||||||
super.select(av,0), super.select(av,1)); }
|
super.select(av,0), super.select(av,1)); }
|
||||||
protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 3);
|
protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 3);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4,
|
return target.invokeExact(a0, a1, a2, a3, a4,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
||||||
protected Object invoke_S4(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 4);
|
protected Object invoke_S4(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 4);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3,
|
return target.invokeExact(a0, a1, a2, a3,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
||||||
protected Object invoke_S5(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 5);
|
protected Object invoke_S5(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 5);
|
||||||
return target.<Object>invokeExact(a0, a1, a2,
|
return target.invokeExact(a0, a1, a2,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4)); }
|
super.select(av,4)); }
|
||||||
protected Object invoke_S6(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 6);
|
protected Object invoke_S6(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 6);
|
||||||
return target.<Object>invokeExact(a0, a1,
|
return target.invokeExact(a0, a1,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4), super.select(av,5)); }
|
super.select(av,4), super.select(av,5)); }
|
||||||
protected Object invoke_S7(Object a0, Object av) throws Throwable { av = super.check(av, 7);
|
protected Object invoke_S7(Object a0, Object av) throws Throwable { av = super.check(av, 7);
|
||||||
return target.<Object>invokeExact(a0,
|
return target.invokeExact(a0,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4), super.select(av,5), super.select(av,6)); }
|
super.select(av,4), super.select(av,5), super.select(av,6)); }
|
||||||
protected Object invoke_S8(Object av) throws Throwable { av = super.check(av, 8);
|
protected Object invoke_S8(Object av) throws Throwable { av = super.check(av, 8);
|
||||||
return target.<Object>invokeExact(
|
return target.invokeExact(
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7)); }
|
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7)); }
|
||||||
}
|
}
|
||||||
@ -595,37 +595,37 @@ class genclasses {
|
|||||||
protected S9(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
protected S9(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||||
protected S9 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S9(outer, t); }
|
protected S9 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S9(outer, t); }
|
||||||
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object av) throws Throwable { av = super.check(av, 0);
|
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object av) throws Throwable { av = super.check(av, 0);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
|
||||||
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object av) throws Throwable { av = super.check(av, 1);
|
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object av) throws Throwable { av = super.check(av, 1);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7,
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7,
|
||||||
super.select(av,0)); }
|
super.select(av,0)); }
|
||||||
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 2);
|
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 2);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6,
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6,
|
||||||
super.select(av,0), super.select(av,1)); }
|
super.select(av,0), super.select(av,1)); }
|
||||||
protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 3);
|
protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 3);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5,
|
return target.invokeExact(a0, a1, a2, a3, a4, a5,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
||||||
protected Object invoke_S4(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 4);
|
protected Object invoke_S4(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 4);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4,
|
return target.invokeExact(a0, a1, a2, a3, a4,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
||||||
protected Object invoke_S5(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 5);
|
protected Object invoke_S5(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 5);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3,
|
return target.invokeExact(a0, a1, a2, a3,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4)); }
|
super.select(av,4)); }
|
||||||
protected Object invoke_S6(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 6);
|
protected Object invoke_S6(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 6);
|
||||||
return target.<Object>invokeExact(a0, a1, a2,
|
return target.invokeExact(a0, a1, a2,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4), super.select(av,5)); }
|
super.select(av,4), super.select(av,5)); }
|
||||||
protected Object invoke_S7(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 7);
|
protected Object invoke_S7(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 7);
|
||||||
return target.<Object>invokeExact(a0, a1,
|
return target.invokeExact(a0, a1,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4), super.select(av,5), super.select(av,6)); }
|
super.select(av,4), super.select(av,5), super.select(av,6)); }
|
||||||
protected Object invoke_S8(Object a0, Object av) throws Throwable { av = super.check(av, 8);
|
protected Object invoke_S8(Object a0, Object av) throws Throwable { av = super.check(av, 8);
|
||||||
return target.<Object>invokeExact(a0,
|
return target.invokeExact(a0,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7)); }
|
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7)); }
|
||||||
protected Object invoke_S9(Object av) throws Throwable { av = super.check(av, 9);
|
protected Object invoke_S9(Object av) throws Throwable { av = super.check(av, 9);
|
||||||
return target.<Object>invokeExact(
|
return target.invokeExact(
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7),
|
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7),
|
||||||
super.select(av,8)); }
|
super.select(av,8)); }
|
||||||
@ -635,42 +635,42 @@ class genclasses {
|
|||||||
protected S10(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
protected S10(SpreadGeneric outer, MethodHandle t) { super(outer, t); }
|
||||||
protected S10 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S10(outer, t); }
|
protected S10 makeInstance(SpreadGeneric outer, MethodHandle t) { return new S10(outer, t); }
|
||||||
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9, Object av) throws Throwable { av = super.check(av, 0);
|
protected Object invoke_S0(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9, Object av) throws Throwable { av = super.check(av, 0);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
|
||||||
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object av) throws Throwable { av = super.check(av, 1);
|
protected Object invoke_S1(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object av) throws Throwable { av = super.check(av, 1);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7, a8,
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7, a8,
|
||||||
super.select(av,0)); }
|
super.select(av,0)); }
|
||||||
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object av) throws Throwable { av = super.check(av, 2);
|
protected Object invoke_S2(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object av) throws Throwable { av = super.check(av, 2);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7,
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7,
|
||||||
super.select(av,0), super.select(av,1)); }
|
super.select(av,0), super.select(av,1)); }
|
||||||
protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 3);
|
protected Object invoke_S3(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object av) throws Throwable { av = super.check(av, 3);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6,
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
super.select(av,0), super.select(av,1), super.select(av,2)); }
|
||||||
protected Object invoke_S4(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 4);
|
protected Object invoke_S4(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object av) throws Throwable { av = super.check(av, 4);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5,
|
return target.invokeExact(a0, a1, a2, a3, a4, a5,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3)); }
|
||||||
protected Object invoke_S5(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 5);
|
protected Object invoke_S5(Object a0, Object a1, Object a2, Object a3, Object a4, Object av) throws Throwable { av = super.check(av, 5);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3, a4,
|
return target.invokeExact(a0, a1, a2, a3, a4,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4)); }
|
super.select(av,4)); }
|
||||||
protected Object invoke_S6(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 6);
|
protected Object invoke_S6(Object a0, Object a1, Object a2, Object a3, Object av) throws Throwable { av = super.check(av, 6);
|
||||||
return target.<Object>invokeExact(a0, a1, a2, a3,
|
return target.invokeExact(a0, a1, a2, a3,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4), super.select(av,5)); }
|
super.select(av,4), super.select(av,5)); }
|
||||||
protected Object invoke_S7(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 7);
|
protected Object invoke_S7(Object a0, Object a1, Object a2, Object av) throws Throwable { av = super.check(av, 7);
|
||||||
return target.<Object>invokeExact(a0, a1, a2,
|
return target.invokeExact(a0, a1, a2,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4), super.select(av,5), super.select(av,6)); }
|
super.select(av,4), super.select(av,5), super.select(av,6)); }
|
||||||
protected Object invoke_S8(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 8);
|
protected Object invoke_S8(Object a0, Object a1, Object av) throws Throwable { av = super.check(av, 8);
|
||||||
return target.<Object>invokeExact(a0, a1,
|
return target.invokeExact(a0, a1,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7)); }
|
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7)); }
|
||||||
protected Object invoke_S9(Object a0, Object av) throws Throwable { av = super.check(av, 9);
|
protected Object invoke_S9(Object a0, Object av) throws Throwable { av = super.check(av, 9);
|
||||||
return target.<Object>invokeExact(a0,
|
return target.invokeExact(a0,
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7),
|
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7),
|
||||||
super.select(av,8)); }
|
super.select(av,8)); }
|
||||||
protected Object invoke_S10(Object av) throws Throwable { av = super.check(av, 10);
|
protected Object invoke_S10(Object av) throws Throwable { av = super.check(av, 10);
|
||||||
return target.<Object>invokeExact(
|
return target.invokeExact(
|
||||||
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
super.select(av,0), super.select(av,1), super.select(av,2), super.select(av,3),
|
||||||
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7),
|
super.select(av,4), super.select(av,5), super.select(av,6), super.select(av,7),
|
||||||
super.select(av,8), super.select(av,9)); }
|
super.select(av,8), super.select(av,9)); }
|
||||||
|
@ -323,7 +323,7 @@ class ToGeneric {
|
|||||||
* via another method handle {@code convert}, which is responsible for
|
* via another method handle {@code convert}, which is responsible for
|
||||||
* converting the object result into the raw return value.
|
* converting the object result into the raw return value.
|
||||||
*/
|
*/
|
||||||
static abstract class Adapter extends JavaMethodHandle {
|
static abstract class Adapter extends BoundMethodHandle {
|
||||||
/*
|
/*
|
||||||
* class X<<R,A...>> extends Adapter {
|
* class X<<R,A...>> extends Adapter {
|
||||||
* Object...=>Object target;
|
* Object...=>Object target;
|
||||||
@ -337,13 +337,13 @@ class ToGeneric {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return target == null ? "prototype:"+convert : target.toString();
|
return target == null ? "prototype:"+convert : MethodHandleImpl.addTypeString(target, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isPrototype() { return target == null; }
|
protected boolean isPrototype() { return target == null; }
|
||||||
/* Prototype constructor. */
|
/* Prototype constructor. */
|
||||||
protected Adapter(MethodHandle entryPoint) {
|
protected Adapter(MethodHandle entryPoint) {
|
||||||
super(entryPoint);
|
super(Access.TOKEN, entryPoint);
|
||||||
this.invoker = null;
|
this.invoker = null;
|
||||||
this.convert = entryPoint;
|
this.convert = entryPoint;
|
||||||
this.target = null;
|
this.target = null;
|
||||||
@ -355,7 +355,7 @@ class ToGeneric {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Adapter(MethodHandle entryPoint, MethodHandle invoker, MethodHandle convert, MethodHandle target) {
|
protected Adapter(MethodHandle entryPoint, MethodHandle invoker, MethodHandle convert, MethodHandle target) {
|
||||||
super(entryPoint);
|
super(Access.TOKEN, entryPoint);
|
||||||
this.invoker = invoker;
|
this.invoker = invoker;
|
||||||
this.convert = convert;
|
this.convert = convert;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
@ -367,33 +367,33 @@ class ToGeneric {
|
|||||||
// { return new ThisType(entryPoint, convert, target); }
|
// { return new ThisType(entryPoint, convert, target); }
|
||||||
|
|
||||||
// Code to run when the arguments (<= 4) have all been boxed.
|
// Code to run when the arguments (<= 4) have all been boxed.
|
||||||
protected Object target() throws Throwable { return invoker.<Object>invokeExact(target); }
|
protected Object target() throws Throwable { return invoker.invokeExact(target); }
|
||||||
protected Object target(Object a0) throws Throwable { return invoker.<Object>invokeExact(target, a0); }
|
protected Object target(Object a0) throws Throwable { return invoker.invokeExact(target, a0); }
|
||||||
protected Object target(Object a0, Object a1)
|
protected Object target(Object a0, Object a1)
|
||||||
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1); }
|
throws Throwable { return invoker.invokeExact(target, a0, a1); }
|
||||||
protected Object target(Object a0, Object a1, Object a2)
|
protected Object target(Object a0, Object a1, Object a2)
|
||||||
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2); }
|
throws Throwable { return invoker.invokeExact(target, a0, a1, a2); }
|
||||||
protected Object target(Object a0, Object a1, Object a2, Object a3)
|
protected Object target(Object a0, Object a1, Object a2, Object a3)
|
||||||
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3); }
|
throws Throwable { return invoker.invokeExact(target, a0, a1, a2, a3); }
|
||||||
/*
|
/*
|
||||||
protected Object target_0(Object... av) throws Throwable { return invoker.<Object>invokeExact(target, av); }
|
protected Object target_0(Object... av) throws Throwable { return invoker.invokeExact(target, av); }
|
||||||
protected Object target_1(Object a0, Object... av)
|
protected Object target_1(Object a0, Object... av)
|
||||||
throws Throwable { return invoker.<Object>invokeExact(target, a0, (Object)av); }
|
throws Throwable { return invoker.invokeExact(target, a0, (Object)av); }
|
||||||
protected Object target_2(Object a0, Object a1, Object... av)
|
protected Object target_2(Object a0, Object a1, Object... av)
|
||||||
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, (Object)av); }
|
throws Throwable { return invoker.invokeExact(target, a0, a1, (Object)av); }
|
||||||
protected Object target_3(Object a0, Object a1, Object a2, Object... av)
|
protected Object target_3(Object a0, Object a1, Object a2, Object... av)
|
||||||
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, (Object)av); }
|
throws Throwable { return invoker.invokeExact(target, a0, a1, a2, (Object)av); }
|
||||||
protected Object target_4(Object a0, Object a1, Object a2, Object a3, Object... av)
|
protected Object target_4(Object a0, Object a1, Object a2, Object a3, Object... av)
|
||||||
throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3, (Object)av); }
|
throws Throwable { return invoker.invokeExact(target, a0, a1, a2, a3, (Object)av); }
|
||||||
// */
|
// */
|
||||||
// (For more than 4 arguments, generate the code in the adapter itself.)
|
// (For more than 4 arguments, generate the code in the adapter itself.)
|
||||||
|
|
||||||
// Code to run when the generic target has finished and produced a value.
|
// Code to run when the generic target has finished and produced a value.
|
||||||
protected Object return_L(Object res) throws Throwable { return convert.<Object>invokeExact(res); }
|
protected Object return_L(Object res) throws Throwable { return (Object)convert.invokeExact(res); }
|
||||||
protected int return_I(Object res) throws Throwable { return convert.<int >invokeExact(res); }
|
protected int return_I(Object res) throws Throwable { return (int) convert.invokeExact(res); }
|
||||||
protected long return_J(Object res) throws Throwable { return convert.<long >invokeExact(res); }
|
protected long return_J(Object res) throws Throwable { return (long) convert.invokeExact(res); }
|
||||||
protected float return_F(Object res) throws Throwable { return convert.<float >invokeExact(res); }
|
protected float return_F(Object res) throws Throwable { return (float) convert.invokeExact(res); }
|
||||||
protected double return_D(Object res) throws Throwable { return convert.<double>invokeExact(res); }
|
protected double return_D(Object res) throws Throwable { return (double)convert.invokeExact(res); }
|
||||||
|
|
||||||
static private final String CLASS_PREFIX; // "sun.dyn.ToGeneric$"
|
static private final String CLASS_PREFIX; // "sun.dyn.ToGeneric$"
|
||||||
static {
|
static {
|
||||||
@ -420,7 +420,7 @@ class ToGeneric {
|
|||||||
protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
||||||
protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A1(e, i, c, t); }
|
protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A1(e, i, c, t); }
|
||||||
protected Object target(Object a0) throws Throwable { return invoker.<Object>invokeExact(target, a0); }
|
protected Object target(Object a0) throws Throwable { return invoker.invokeExact(target, a0); }
|
||||||
protected Object targetA1(Object a0) throws Throwable { return target(a0); }
|
protected Object targetA1(Object a0) throws Throwable { return target(a0); }
|
||||||
protected Object targetA1(int a0) throws Throwable { return target(a0); }
|
protected Object targetA1(int a0) throws Throwable { return target(a0); }
|
||||||
protected Object targetA1(long a0) throws Throwable { return target(a0); }
|
protected Object targetA1(long a0) throws Throwable { return target(a0); }
|
||||||
@ -458,7 +458,7 @@ class genclasses {
|
|||||||
" protected @cat@(MethodHandle entryPoint) { super(entryPoint); } // to build prototype",
|
" protected @cat@(MethodHandle entryPoint) { super(entryPoint); } // to build prototype",
|
||||||
" protected @cat@(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }",
|
" protected @cat@(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }",
|
||||||
" protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new @cat@(e, i, c, t); }",
|
" protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new @cat@(e, i, c, t); }",
|
||||||
" protected Object target(@Ovav@) throws Throwable { return invoker.<Object>invokeExact(target, @av@); }",
|
" protected Object target(@Ovav@) throws Throwable { return invoker.invokeExact(target, @av@); }",
|
||||||
" //@each-Tv@",
|
" //@each-Tv@",
|
||||||
" protected Object target@cat@(@Tvav@) throws Throwable { return target(@av@); }",
|
" protected Object target@cat@(@Tvav@) throws Throwable { return target(@av@); }",
|
||||||
" //@end-Tv@",
|
" //@end-Tv@",
|
||||||
@ -618,7 +618,7 @@ class genclasses {
|
|||||||
protected A0(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A0(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
protected A0(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
protected A0(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
||||||
protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A0(e, i, c, t); }
|
protected A0 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A0(e, i, c, t); }
|
||||||
protected Object target() throws Throwable { return invoker.<Object>invokeExact(target); }
|
protected Object target() throws Throwable { return invoker.invokeExact(target); }
|
||||||
protected Object targetA0() throws Throwable { return target(); }
|
protected Object targetA0() throws Throwable { return target(); }
|
||||||
protected Object invoke_L() throws Throwable { return return_L(targetA0()); }
|
protected Object invoke_L() throws Throwable { return return_L(targetA0()); }
|
||||||
protected int invoke_I() throws Throwable { return return_I(targetA0()); }
|
protected int invoke_I() throws Throwable { return return_I(targetA0()); }
|
||||||
@ -630,7 +630,7 @@ class genclasses {
|
|||||||
protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A1(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
protected A1(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
||||||
protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A1(e, i, c, t); }
|
protected A1 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A1(e, i, c, t); }
|
||||||
protected Object target(Object a0) throws Throwable { return invoker.<Object>invokeExact(target, a0); }
|
protected Object target(Object a0) throws Throwable { return invoker.invokeExact(target, a0); }
|
||||||
protected Object targetA1(Object a0) throws Throwable { return target(a0); }
|
protected Object targetA1(Object a0) throws Throwable { return target(a0); }
|
||||||
protected Object targetA1(int a0) throws Throwable { return target(a0); }
|
protected Object targetA1(int a0) throws Throwable { return target(a0); }
|
||||||
protected Object targetA1(long a0) throws Throwable { return target(a0); }
|
protected Object targetA1(long a0) throws Throwable { return target(a0); }
|
||||||
@ -654,7 +654,7 @@ class genclasses {
|
|||||||
protected A2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A2(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
protected A2(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
protected A2(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
||||||
protected A2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A2(e, i, c, t); }
|
protected A2 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A2(e, i, c, t); }
|
||||||
protected Object target(Object a0, Object a1) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1); }
|
protected Object target(Object a0, Object a1) throws Throwable { return invoker.invokeExact(target, a0, a1); }
|
||||||
protected Object targetA2(Object a0, Object a1) throws Throwable { return target(a0, a1); }
|
protected Object targetA2(Object a0, Object a1) throws Throwable { return target(a0, a1); }
|
||||||
protected Object targetA2(Object a0, int a1) throws Throwable { return target(a0, a1); }
|
protected Object targetA2(Object a0, int a1) throws Throwable { return target(a0, a1); }
|
||||||
protected Object targetA2(int a0, int a1) throws Throwable { return target(a0, a1); }
|
protected Object targetA2(int a0, int a1) throws Throwable { return target(a0, a1); }
|
||||||
@ -690,7 +690,7 @@ class genclasses {
|
|||||||
protected A3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A3(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
protected A3(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
protected A3(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
||||||
protected A3 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A3(e, i, c, t); }
|
protected A3 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A3(e, i, c, t); }
|
||||||
protected Object target(Object a0, Object a1, Object a2) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2); }
|
protected Object target(Object a0, Object a1, Object a2) throws Throwable { return invoker.invokeExact(target, a0, a1, a2); }
|
||||||
protected Object targetA3(Object a0, Object a1, Object a2) throws Throwable { return target(a0, a1, a2); }
|
protected Object targetA3(Object a0, Object a1, Object a2) throws Throwable { return target(a0, a1, a2); }
|
||||||
protected Object targetA3(Object a0, Object a1, int a2) throws Throwable { return target(a0, a1, a2); }
|
protected Object targetA3(Object a0, Object a1, int a2) throws Throwable { return target(a0, a1, a2); }
|
||||||
protected Object targetA3(Object a0, int a1, int a2) throws Throwable { return target(a0, a1, a2); }
|
protected Object targetA3(Object a0, int a1, int a2) throws Throwable { return target(a0, a1, a2); }
|
||||||
@ -739,7 +739,7 @@ class genclasses {
|
|||||||
protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
protected A4(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
protected A4(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
||||||
protected A4 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A4(e, i, c, t); }
|
protected A4 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A4(e, i, c, t); }
|
||||||
protected Object target(Object a0, Object a1, Object a2, Object a3) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3); }
|
protected Object target(Object a0, Object a1, Object a2, Object a3) throws Throwable { return invoker.invokeExact(target, a0, a1, a2, a3); }
|
||||||
protected Object targetA4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return target(a0, a1, a2, a3); }
|
protected Object targetA4(Object a0, Object a1, Object a2, Object a3) throws Throwable { return target(a0, a1, a2, a3); }
|
||||||
protected Object targetA4(Object a0, Object a1, Object a2, int a3) throws Throwable { return target(a0, a1, a2, a3); }
|
protected Object targetA4(Object a0, Object a1, Object a2, int a3) throws Throwable { return target(a0, a1, a2, a3); }
|
||||||
protected Object targetA4(Object a0, Object a1, int a2, int a3) throws Throwable { return target(a0, a1, a2, a3); }
|
protected Object targetA4(Object a0, Object a1, int a2, int a3) throws Throwable { return target(a0, a1, a2, a3); }
|
||||||
@ -781,7 +781,7 @@ class genclasses {
|
|||||||
protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
protected A5(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
protected A5(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
||||||
protected A5 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A5(e, i, c, t); }
|
protected A5 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A5(e, i, c, t); }
|
||||||
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4); }
|
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return invoker.invokeExact(target, a0, a1, a2, a3, a4); }
|
||||||
protected Object targetA5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return target(a0, a1, a2, a3, a4); }
|
protected Object targetA5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { return target(a0, a1, a2, a3, a4); }
|
||||||
protected Object targetA5(Object a0, Object a1, Object a2, Object a3, int a4) throws Throwable { return target(a0, a1, a2, a3, a4); }
|
protected Object targetA5(Object a0, Object a1, Object a2, Object a3, int a4) throws Throwable { return target(a0, a1, a2, a3, a4); }
|
||||||
protected Object targetA5(Object a0, Object a1, Object a2, int a3, int a4) throws Throwable { return target(a0, a1, a2, a3, a4); }
|
protected Object targetA5(Object a0, Object a1, Object a2, int a3, int a4) throws Throwable { return target(a0, a1, a2, a3, a4); }
|
||||||
@ -832,7 +832,7 @@ class genclasses {
|
|||||||
protected A6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A6(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
protected A6(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
protected A6(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
||||||
protected A6 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A6(e, i, c, t); }
|
protected A6 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A6(e, i, c, t); }
|
||||||
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5); }
|
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return invoker.invokeExact(target, a0, a1, a2, a3, a4, a5); }
|
||||||
protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); }
|
protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); }
|
||||||
protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); }
|
protected Object targetA6(Object a0, Object a1, Object a2, Object a3, Object a4, long a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); }
|
||||||
protected Object targetA6(Object a0, Object a1, Object a2, Object a3, long a4, long a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); }
|
protected Object targetA6(Object a0, Object a1, Object a2, Object a3, long a4, long a5) throws Throwable { return target(a0, a1, a2, a3, a4, a5); }
|
||||||
@ -866,7 +866,7 @@ class genclasses {
|
|||||||
protected A7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A7(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
protected A7(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
protected A7(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
||||||
protected A7 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A7(e, i, c, t); }
|
protected A7 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A7(e, i, c, t); }
|
||||||
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5, a6); }
|
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6); }
|
||||||
protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); }
|
protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); }
|
||||||
protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); }
|
protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); }
|
||||||
protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); }
|
protected Object targetA7(Object a0, Object a1, Object a2, Object a3, Object a4, long a5, long a6) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6); }
|
||||||
@ -904,7 +904,7 @@ class genclasses {
|
|||||||
protected A8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A8(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
protected A8(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
protected A8(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
||||||
protected A8 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A8(e, i, c, t); }
|
protected A8 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A8(e, i, c, t); }
|
||||||
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7); }
|
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7); }
|
||||||
protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
|
protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
|
||||||
protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
|
protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
|
||||||
protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
|
protected Object targetA8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, long a6, long a7) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7); }
|
||||||
@ -946,7 +946,7 @@ class genclasses {
|
|||||||
protected A9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A9(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
protected A9(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
protected A9(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
||||||
protected A9 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A9(e, i, c, t); }
|
protected A9 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A9(e, i, c, t); }
|
||||||
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8); }
|
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8); }
|
||||||
protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
|
protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
|
||||||
protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
|
protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
|
||||||
protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
|
protected Object targetA9(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, long a7, long a8) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
|
||||||
@ -992,7 +992,7 @@ class genclasses {
|
|||||||
protected A10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
protected A10(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
|
||||||
protected A10(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
protected A10(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
|
||||||
protected A10 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A10(e, i, c, t); }
|
protected A10 makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new A10(e, i, c, t); }
|
||||||
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return invoker.<Object>invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
|
protected Object target(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return invoker.invokeExact(target, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
|
||||||
protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
|
protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
|
||||||
protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
|
protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
|
||||||
protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
|
protected Object targetA10(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, long a8, long a9) throws Throwable { return target(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
|
||||||
|
@ -377,7 +377,7 @@ public class ValueConversions {
|
|||||||
REBOX_CONVERSIONS = newWrapperCaches(2);
|
REBOX_CONVERSIONS = newWrapperCaches(2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Becase we normalize primitive types to reduce the number of signatures,
|
* Because we normalize primitive types to reduce the number of signatures,
|
||||||
* primitives are sometimes manipulated under an "erased" type,
|
* primitives are sometimes manipulated under an "erased" type,
|
||||||
* either int (for types other than long/double) or long (for all types).
|
* either int (for types other than long/double) or long (for all types).
|
||||||
* When the erased primitive value is then boxed into an Integer or Long,
|
* When the erased primitive value is then boxed into an Integer or Long,
|
||||||
@ -475,10 +475,10 @@ public class ValueConversions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final EnumMap<Wrapper, MethodHandle>[]
|
private static final EnumMap<Wrapper, MethodHandle>[]
|
||||||
ZERO_CONSTANT_FUNCTIONS = newWrapperCaches(1);
|
CONSTANT_FUNCTIONS = newWrapperCaches(2);
|
||||||
|
|
||||||
public static MethodHandle zeroConstantFunction(Wrapper wrap) {
|
public static MethodHandle zeroConstantFunction(Wrapper wrap) {
|
||||||
EnumMap<Wrapper, MethodHandle> cache = ZERO_CONSTANT_FUNCTIONS[0];
|
EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[0];
|
||||||
MethodHandle mh = cache.get(wrap);
|
MethodHandle mh = cache.get(wrap);
|
||||||
if (mh != null) {
|
if (mh != null) {
|
||||||
return mh;
|
return mh;
|
||||||
@ -543,6 +543,24 @@ public class ValueConversions {
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identity function on ints.
|
||||||
|
* @param x an arbitrary int value
|
||||||
|
* @return the same value x
|
||||||
|
*/
|
||||||
|
static int identity(int x) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identity function on longs.
|
||||||
|
* @param x an arbitrary long value
|
||||||
|
* @return the same value x
|
||||||
|
*/
|
||||||
|
static long identity(long x) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identity function, with reference cast.
|
* Identity function, with reference cast.
|
||||||
* @param t an arbitrary reference type
|
* @param t an arbitrary reference type
|
||||||
@ -553,7 +571,7 @@ public class ValueConversions {
|
|||||||
return t.cast(x);
|
return t.cast(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final MethodHandle IDENTITY, CAST_REFERENCE, ALWAYS_NULL, ALWAYS_ZERO, ZERO_OBJECT, IGNORE, EMPTY;
|
private static final MethodHandle IDENTITY, IDENTITY_I, IDENTITY_J, CAST_REFERENCE, ALWAYS_NULL, ALWAYS_ZERO, ZERO_OBJECT, IGNORE, EMPTY;
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
MethodType idType = MethodType.genericMethodType(1);
|
MethodType idType = MethodType.genericMethodType(1);
|
||||||
@ -562,6 +580,8 @@ public class ValueConversions {
|
|||||||
MethodType ignoreType = idType.changeReturnType(void.class);
|
MethodType ignoreType = idType.changeReturnType(void.class);
|
||||||
MethodType zeroObjectType = MethodType.genericMethodType(0);
|
MethodType zeroObjectType = MethodType.genericMethodType(0);
|
||||||
IDENTITY = IMPL_LOOKUP.findStatic(ValueConversions.class, "identity", idType);
|
IDENTITY = IMPL_LOOKUP.findStatic(ValueConversions.class, "identity", idType);
|
||||||
|
IDENTITY_I = IMPL_LOOKUP.findStatic(ValueConversions.class, "identity", MethodType.methodType(int.class, int.class));
|
||||||
|
IDENTITY_J = IMPL_LOOKUP.findStatic(ValueConversions.class, "identity", MethodType.methodType(long.class, long.class));
|
||||||
//CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
|
//CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
|
||||||
CAST_REFERENCE = IMPL_LOOKUP.findStatic(ValueConversions.class, "castReference", castType);
|
CAST_REFERENCE = IMPL_LOOKUP.findStatic(ValueConversions.class, "castReference", castType);
|
||||||
ALWAYS_NULL = IMPL_LOOKUP.findStatic(ValueConversions.class, "alwaysNull", idType);
|
ALWAYS_NULL = IMPL_LOOKUP.findStatic(ValueConversions.class, "alwaysNull", idType);
|
||||||
@ -613,8 +633,53 @@ public class ValueConversions {
|
|||||||
return IDENTITY;
|
return IDENTITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MethodHandle identity(Class<?> type) {
|
||||||
|
if (type == Object.class)
|
||||||
|
return IDENTITY;
|
||||||
|
else if (!type.isPrimitive())
|
||||||
|
return retype(MethodType.methodType(type, type), IDENTITY);
|
||||||
|
else
|
||||||
|
return identity(Wrapper.forPrimitiveType(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
static MethodHandle identity(Wrapper wrap) {
|
||||||
|
EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[1];
|
||||||
|
MethodHandle mh = cache.get(wrap);
|
||||||
|
if (mh != null) {
|
||||||
|
return mh;
|
||||||
|
}
|
||||||
|
// slow path
|
||||||
|
MethodType type = MethodType.methodType(wrap.primitiveType());
|
||||||
|
if (wrap != Wrapper.VOID)
|
||||||
|
type = type.appendParameterTypes(wrap.primitiveType());
|
||||||
|
try {
|
||||||
|
mh = IMPL_LOOKUP.findStatic(ValueConversions.class, "identity", type);
|
||||||
|
} catch (NoAccessException ex) {
|
||||||
|
mh = null;
|
||||||
|
}
|
||||||
|
if (mh == null && wrap == Wrapper.VOID) {
|
||||||
|
mh = EMPTY; // #(){} : #()void
|
||||||
|
}
|
||||||
|
if (mh != null) {
|
||||||
|
cache.put(wrap, mh);
|
||||||
|
return mh;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use a raw conversion
|
||||||
|
if (wrap.isSingleWord() && wrap != Wrapper.INT) {
|
||||||
|
mh = retype(type, identity(Wrapper.INT));
|
||||||
|
} else if (wrap.isDoubleWord() && wrap != Wrapper.LONG) {
|
||||||
|
mh = retype(type, identity(Wrapper.LONG));
|
||||||
|
}
|
||||||
|
if (mh != null) {
|
||||||
|
cache.put(wrap, mh);
|
||||||
|
return mh;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("cannot find identity for " + wrap);
|
||||||
|
}
|
||||||
|
|
||||||
private static MethodHandle retype(MethodType type, MethodHandle mh) {
|
private static MethodHandle retype(MethodType type, MethodHandle mh) {
|
||||||
return AdapterMethodHandle.makeRetypeOnly(IMPL_TOKEN, type, mh);
|
return AdapterMethodHandle.makeRetypeRaw(IMPL_TOKEN, type, mh);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Object[] NO_ARGS_ARRAY = {};
|
private static final Object[] NO_ARGS_ARRAY = {};
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
package sun.dyn.util;
|
package sun.dyn.util;
|
||||||
|
|
||||||
import java.dyn.LinkagePermission;
|
|
||||||
import java.dyn.NoAccessException;
|
import java.dyn.NoAccessException;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import sun.dyn.MemberName;
|
import sun.dyn.MemberName;
|
||||||
@ -43,6 +42,7 @@ public class VerifyAccess {
|
|||||||
|
|
||||||
private static final int PACKAGE_ONLY = 0;
|
private static final int PACKAGE_ONLY = 0;
|
||||||
private static final int ALL_ACCESS_MODES = (PUBLIC|PRIVATE|PROTECTED|PACKAGE_ONLY);
|
private static final int ALL_ACCESS_MODES = (PUBLIC|PRIVATE|PROTECTED|PACKAGE_ONLY);
|
||||||
|
private static final boolean ALLOW_NESTMATE_ACCESS = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluate the JVM linkage rules for access to the given method
|
* Evaluate the JVM linkage rules for access to the given method
|
||||||
@ -102,6 +102,8 @@ public class VerifyAccess {
|
|||||||
// a superclass of the lookup class.
|
// a superclass of the lookup class.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (defc == lookupClass)
|
||||||
|
return true; // easy check; all self-access is OK
|
||||||
switch (mods & ALL_ACCESS_MODES) {
|
switch (mods & ALL_ACCESS_MODES) {
|
||||||
case PUBLIC:
|
case PUBLIC:
|
||||||
if (refc != defc) return true; // already checked above
|
if (refc != defc) return true; // already checked above
|
||||||
@ -112,7 +114,8 @@ public class VerifyAccess {
|
|||||||
return isSamePackage(defc, lookupClass);
|
return isSamePackage(defc, lookupClass);
|
||||||
case PRIVATE:
|
case PRIVATE:
|
||||||
// Loosened rules for privates follows access rules for inner classes.
|
// Loosened rules for privates follows access rules for inner classes.
|
||||||
return isSamePackageMember(defc, lookupClass);
|
return (ALLOW_NESTMATE_ACCESS &&
|
||||||
|
isSamePackageMember(defc, lookupClass));
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("bad modifiers: "+Modifier.toString(mods));
|
throw new IllegalArgumentException("bad modifiers: "+Modifier.toString(mods));
|
||||||
}
|
}
|
||||||
@ -206,24 +209,4 @@ public class VerifyAccess {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensure the requesting class have privileges to perform invokedynamic
|
|
||||||
* linkage operations on subjectClass. True if requestingClass is
|
|
||||||
* Access.class (meaning the request originates from the JVM) or if the
|
|
||||||
* classes are in the same package and have consistent class loaders.
|
|
||||||
* (The subject class loader must be identical with or be a child of
|
|
||||||
* the requesting class loader.)
|
|
||||||
* @param requestingClass
|
|
||||||
* @param subjectClass
|
|
||||||
*/
|
|
||||||
public static void checkBootstrapPrivilege(Class requestingClass, Class subjectClass,
|
|
||||||
String permissionName) {
|
|
||||||
if (requestingClass == null) return;
|
|
||||||
if (requestingClass == subjectClass) return;
|
|
||||||
SecurityManager security = System.getSecurityManager();
|
|
||||||
if (security == null) return; // open season
|
|
||||||
if (isSamePackage(requestingClass, subjectClass)) return;
|
|
||||||
security.checkPermission(new LinkagePermission(permissionName, requestingClass));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -26,17 +26,19 @@
|
|||||||
package sun.dyn.util;
|
package sun.dyn.util;
|
||||||
|
|
||||||
public enum Wrapper {
|
public enum Wrapper {
|
||||||
INT(Integer.class, int.class, 'I', (Integer)(int)0, Format.signed(32)),
|
BOOLEAN(Boolean.class, boolean.class, 'Z', (Boolean)false, Format.unsigned(1)),
|
||||||
LONG(Long.class, long.class, 'J', (Long)(long)0, Format.signed(64)),
|
// These must be in the order defined for widening primitive conversions in JLS 5.1.2
|
||||||
BYTE(Byte.class, byte.class, 'B', (Byte)(byte)0, Format.signed(8)),
|
BYTE(Byte.class, byte.class, 'B', (Byte)(byte)0, Format.signed(8)),
|
||||||
SHORT(Short.class, short.class, 'S', (Short)(short)0, Format.signed(16)),
|
SHORT(Short.class, short.class, 'S', (Short)(short)0, Format.signed(16)),
|
||||||
CHAR(Character.class, char.class, 'C', (Character)(char)0, Format.unsigned(16)),
|
CHAR(Character.class, char.class, 'C', (Character)(char)0, Format.unsigned(16)),
|
||||||
BOOLEAN(Boolean.class, boolean.class, 'Z', (Boolean)false, Format.unsigned(1)),
|
INT(Integer.class, int.class, 'I', (Integer)(int)0, Format.signed(32)),
|
||||||
|
LONG(Long.class, long.class, 'J', (Long)(long)0, Format.signed(64)),
|
||||||
FLOAT(Float.class, float.class, 'F', (Float)(float)0, Format.floating(32)),
|
FLOAT(Float.class, float.class, 'F', (Float)(float)0, Format.floating(32)),
|
||||||
DOUBLE(Double.class, double.class, 'D', (Double)(double)0, Format.floating(64)),
|
DOUBLE(Double.class, double.class, 'D', (Double)(double)0, Format.floating(64)),
|
||||||
VOID(Void.class, void.class, 'V', null, Format.other(0)),
|
|
||||||
//NULL(Null.class, null.class, 'N', null, Format.other(1)),
|
//NULL(Null.class, null.class, 'N', null, Format.other(1)),
|
||||||
OBJECT(Object.class, Object.class, 'L', null, Format.other(1)),
|
OBJECT(Object.class, Object.class, 'L', null, Format.other(1)),
|
||||||
|
// VOID must be the last type, since it is "assignable" from any other type:
|
||||||
|
VOID(Void.class, void.class, 'V', null, Format.other(0)),
|
||||||
;
|
;
|
||||||
|
|
||||||
private final Class<?> wrapperType;
|
private final Class<?> wrapperType;
|
||||||
@ -76,9 +78,11 @@ public enum Wrapper {
|
|||||||
false);
|
false);
|
||||||
return kind | (size << SIZE_SHIFT) | (slots << SLOT_SHIFT);
|
return kind | (size << SIZE_SHIFT) | (slots << SLOT_SHIFT);
|
||||||
}
|
}
|
||||||
static int
|
static final int
|
||||||
INT = SIGNED | (32 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
|
INT = SIGNED | (32 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
|
||||||
|
SHORT = SIGNED | (16 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
|
||||||
BOOLEAN = UNSIGNED | (1 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
|
BOOLEAN = UNSIGNED | (1 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
|
||||||
|
CHAR = UNSIGNED | (16 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
|
||||||
FLOAT = FLOATING | (32 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
|
FLOAT = FLOATING | (32 << SIZE_SHIFT) | (1 << SLOT_SHIFT),
|
||||||
VOID = UNSIGNED | (0 << SIZE_SHIFT) | (0 << SLOT_SHIFT),
|
VOID = UNSIGNED | (0 << SIZE_SHIFT) | (0 << SLOT_SHIFT),
|
||||||
NUM_MASK = (-1) << SIZE_SHIFT;
|
NUM_MASK = (-1) << SIZE_SHIFT;
|
||||||
@ -111,6 +115,29 @@ public enum Wrapper {
|
|||||||
/** Is the wrapped type either float or double? */
|
/** Is the wrapped type either float or double? */
|
||||||
public boolean isFloating() { return format >= Format.FLOAT; }
|
public boolean isFloating() { return format >= Format.FLOAT; }
|
||||||
|
|
||||||
|
/** Does the JVM verifier allow a variable of this wrapper's
|
||||||
|
* primitive type to be assigned from a value of the given wrapper's primitive type?
|
||||||
|
* Cases:
|
||||||
|
* <ul>
|
||||||
|
* <li>unboxing followed by widening primitive conversion
|
||||||
|
* <li>any type converted to {@code void}
|
||||||
|
* <li>boxing conversion followed by widening reference conversion to {@code Object}
|
||||||
|
* <li>conversion of {@code boolean} to any type
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public boolean isConvertibleFrom(Wrapper source) {
|
||||||
|
if (this == source) return true;
|
||||||
|
if (this.compareTo(source) < 0) {
|
||||||
|
// At best, this is a narrowing conversion.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((this.format ^ source.format) == (Format.SHORT ^ Format.CHAR)) {
|
||||||
|
assert (this == SHORT && source == CHAR) || (this == CHAR && source == SHORT);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/** Produce a zero value for the given wrapper type.
|
/** Produce a zero value for the given wrapper type.
|
||||||
* This will be a numeric zero for a number or character,
|
* This will be a numeric zero for a number or character,
|
||||||
* false for a boolean, and null for a reference or void.
|
* false for a boolean, and null for a reference or void.
|
||||||
@ -122,10 +149,10 @@ public enum Wrapper {
|
|||||||
public Object zero() { return zero; }
|
public Object zero() { return zero; }
|
||||||
|
|
||||||
/** Produce a zero value for the given wrapper type T.
|
/** Produce a zero value for the given wrapper type T.
|
||||||
* The optinoal argument must a type compatible with this wrapper.
|
* The optional argument must a type compatible with this wrapper.
|
||||||
* Equivalent to {@code this.cast(this.zero(), type)}.
|
* Equivalent to {@code this.cast(this.zero(), type)}.
|
||||||
*/
|
*/
|
||||||
public <T> T zero(Class<T> type) { return cast(zero, type); }
|
public <T> T zero(Class<T> type) { return convert(zero, type); }
|
||||||
|
|
||||||
// /** Produce a wrapper for the given wrapper or primitive type. */
|
// /** Produce a wrapper for the given wrapper or primitive type. */
|
||||||
// public static Wrapper valueOf(Class<?> type) {
|
// public static Wrapper valueOf(Class<?> type) {
|
||||||
@ -264,7 +291,11 @@ public enum Wrapper {
|
|||||||
exampleType.isInterface()) {
|
exampleType.isInterface()) {
|
||||||
return forceType(wrapperType, exampleType);
|
return forceType(wrapperType, exampleType);
|
||||||
}
|
}
|
||||||
throw new ClassCastException(exampleType + " not <:" + wrapperType);
|
throw newClassCastException(exampleType, primitiveType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ClassCastException newClassCastException(Class<?> actual, Class<?> expected) {
|
||||||
|
return new ClassCastException(actual + " is not compatible with " + expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** If {@code type} is a primitive type, return the corresponding
|
/** If {@code type} is a primitive type, return the corresponding
|
||||||
@ -325,17 +356,55 @@ public enum Wrapper {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
/** Cast a wrapped value to the given type, which may be either a primitive or wrapper type.
|
/** Cast a wrapped value to the given type, which may be either a primitive or wrapper type.
|
||||||
|
* The given target type must be this wrapper's primitive or wrapper type.
|
||||||
|
* If this wrapper is OBJECT, the target type may also be an interface, perform no runtime check.
|
||||||
* Performs standard primitive conversions, including truncation and float conversions.
|
* Performs standard primitive conversions, including truncation and float conversions.
|
||||||
* The given type must be compatible with this wrapper. That is, it must either
|
* The given type must be compatible with this wrapper. That is, it must either
|
||||||
* be the wrapper type (or a subtype, in the case of {@code OBJECT}) or else
|
* be the wrapper type (or a subtype, in the case of {@code OBJECT}) or else
|
||||||
* it must be the wrapper's primitive type.
|
* it must be the wrapper's primitive type.
|
||||||
|
* Primitive conversions are only performed if the given type is itself a primitive.
|
||||||
* @throws ClassCastException if the given type is not compatible with this wrapper
|
* @throws ClassCastException if the given type is not compatible with this wrapper
|
||||||
*/
|
*/
|
||||||
public <T> T cast(Object x, Class<T> type) {
|
public <T> T cast(Object x, Class<T> type) {
|
||||||
|
return convert(x, type, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert a wrapped value to the given type.
|
||||||
|
* The given target type must be this wrapper's primitive or wrapper type.
|
||||||
|
* This is equivalent to {@link #cast}, except that it refuses to perform
|
||||||
|
* narrowing primitive conversions.
|
||||||
|
*/
|
||||||
|
public <T> T convert(Object x, Class<T> type) {
|
||||||
|
return convert(x, type, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T convert(Object x, Class<T> type, boolean isCast) {
|
||||||
|
if (this == OBJECT) {
|
||||||
|
// If the target wrapper is OBJECT, just do a reference cast.
|
||||||
|
// If the target type is an interface, perform no runtime check.
|
||||||
|
// (This loophole is safe, and is allowed by the JVM verifier.)
|
||||||
|
// If the target type is a primitive, change it to a wrapper.
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
T result = (T) x; // unchecked warning is expected here
|
||||||
|
return result;
|
||||||
|
}
|
||||||
Class<T> wtype = wrapperType(type);
|
Class<T> wtype = wrapperType(type);
|
||||||
if (wtype.isInstance(x))
|
if (wtype.isInstance(x)) {
|
||||||
return wtype.cast(x);
|
@SuppressWarnings("unchecked")
|
||||||
return wtype.cast(wrap(x));
|
T result = (T) x; // unchecked warning is expected here
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
Class<?> sourceType = x.getClass(); // throw NPE if x is null
|
||||||
|
if (!isCast) {
|
||||||
|
Wrapper source = findWrapperType(sourceType);
|
||||||
|
if (source == null || !this.isConvertibleFrom(source)) {
|
||||||
|
throw newClassCastException(wtype, sourceType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
T result = (T) wrap(x); // unchecked warning is expected here
|
||||||
|
assert result.getClass() == wtype;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Cast a reference type to another reference type.
|
/** Cast a reference type to another reference type.
|
||||||
|
@ -53,12 +53,13 @@ public class ClassValueTest {
|
|||||||
return "CV1:" + type.getName();
|
return "CV1:" + type.getName();
|
||||||
}
|
}
|
||||||
static int countForCV1;
|
static int countForCV1;
|
||||||
static final ClassValue<String> CV1 = new ClassValue<String>() {
|
static final ClassValue<String> CV1 = new CV1();
|
||||||
|
private static class CV1 extends ClassValue<String> {
|
||||||
protected String computeValue(Class<?> type) {
|
protected String computeValue(Class<?> type) {
|
||||||
countForCV1++;
|
countForCV1++;
|
||||||
return nameForCV1(type);
|
return nameForCV1(type);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static final Class[] CLASSES = {
|
static final Class[] CLASSES = {
|
||||||
String.class,
|
String.class,
|
||||||
|
172
jdk/test/java/dyn/InvokeDynamicPrintArgs.java
Normal file
172
jdk/test/java/dyn/InvokeDynamicPrintArgs.java
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @test
|
||||||
|
* @summary smoke test for invokedynamic instructions
|
||||||
|
* @library indify
|
||||||
|
* @compile InvokeDynamicPrintArgs.java
|
||||||
|
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic
|
||||||
|
* indify.Indify
|
||||||
|
* --verify-specifier-count=3 --transitionalJSR292=false
|
||||||
|
* --expand-properties --classpath ${test.classes}
|
||||||
|
* --java InvokeDynamicPrintArgs --check-output
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
import java.dyn.*;
|
||||||
|
import static java.dyn.MethodHandles.*;
|
||||||
|
import static java.dyn.MethodType.*;
|
||||||
|
|
||||||
|
public class InvokeDynamicPrintArgs {
|
||||||
|
public static void main(String... av) throws Throwable {
|
||||||
|
if (av.length > 0) openBuf(); // --check-output mode
|
||||||
|
System.out.println("Printing some argument lists, starting with a empty one:");
|
||||||
|
INDY_nothing().invokeExact(); // BSM specifier #0 = {bsm}
|
||||||
|
INDY_bar().invokeExact("bar arg", 1); // BSM specifier #1 = {bsm2, Void.class, "void type"}
|
||||||
|
INDY_bar2().invokeExact("bar2 arg", 222); // BSM specifier #1 = (same)
|
||||||
|
INDY_baz().invokeExact("baz arg", 2, 3.14); // BSM specifier #2 = {bsm2, 1234.5}
|
||||||
|
INDY_foo().invokeExact("foo arg"); // BSM specifier #0 = (same)
|
||||||
|
// Hence, BSM specifier count should be 3. See "--verify-specifier-count=3" above.
|
||||||
|
System.out.println("Done printing argument lists.");
|
||||||
|
closeBuf();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PrintStream oldOut;
|
||||||
|
private static ByteArrayOutputStream buf;
|
||||||
|
private static void openBuf() {
|
||||||
|
oldOut = System.out;
|
||||||
|
buf = new ByteArrayOutputStream();
|
||||||
|
System.setOut(new PrintStream(buf));
|
||||||
|
}
|
||||||
|
private static void closeBuf() {
|
||||||
|
if (buf == null) return;
|
||||||
|
System.out.flush();
|
||||||
|
System.setOut(oldOut);
|
||||||
|
String[] haveLines = new String(buf.toByteArray()).split("[\n\r]+");
|
||||||
|
for (String line : haveLines) System.out.println(line);
|
||||||
|
Iterator<String> iter = Arrays.asList(haveLines).iterator();
|
||||||
|
for (String want : EXPECT_OUTPUT) {
|
||||||
|
String have = iter.hasNext() ? iter.next() : "[EOF]";
|
||||||
|
if (want.equals(have)) continue;
|
||||||
|
System.err.println("want line: "+want);
|
||||||
|
System.err.println("have line: "+have);
|
||||||
|
throw new AssertionError("unexpected output: "+have);
|
||||||
|
}
|
||||||
|
if (iter.hasNext())
|
||||||
|
throw new AssertionError("unexpected output: "+iter.next());
|
||||||
|
}
|
||||||
|
private static final String[] EXPECT_OUTPUT = {
|
||||||
|
"Printing some argument lists, starting with a empty one:",
|
||||||
|
"[InvokeDynamicPrintArgs, nothing, ()void][]",
|
||||||
|
"[InvokeDynamicPrintArgs, bar, (java.lang.String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar arg, 1]",
|
||||||
|
"[InvokeDynamicPrintArgs, bar2, (java.lang.String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar2 arg, 222]",
|
||||||
|
"[InvokeDynamicPrintArgs, baz, (java.lang.String,int,double)void, 1234.5][baz arg, 2, 3.14]",
|
||||||
|
"[InvokeDynamicPrintArgs, foo, (java.lang.String)void][foo arg]",
|
||||||
|
"Done printing argument lists."
|
||||||
|
};
|
||||||
|
|
||||||
|
private static void printArgs(Object bsmInfo, Object... args) {
|
||||||
|
System.out.println(bsmInfo+Arrays.deepToString(args));
|
||||||
|
}
|
||||||
|
private static MethodHandle MH_printArgs() throws ReflectiveOperationException {
|
||||||
|
shouldNotCallThis();
|
||||||
|
return lookup().findStatic(lookup().lookupClass(),
|
||||||
|
"printArgs", methodType(void.class, Object.class, Object[].class));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CallSite bsm(Lookup caller, String name, MethodType type) throws ReflectiveOperationException {
|
||||||
|
// ignore caller and name, but match the type:
|
||||||
|
Object bsmInfo = Arrays.asList(caller, name, type);
|
||||||
|
return new ConstantCallSite(MH_printArgs().bindTo(bsmInfo).asCollector(Object[].class, type.parameterCount()).asType(type));
|
||||||
|
}
|
||||||
|
private static MethodType MT_bsm() {
|
||||||
|
shouldNotCallThis();
|
||||||
|
return methodType(CallSite.class, Lookup.class, String.class, MethodType.class);
|
||||||
|
}
|
||||||
|
private static MethodHandle MH_bsm() throws ReflectiveOperationException {
|
||||||
|
shouldNotCallThis();
|
||||||
|
return lookup().findStatic(lookup().lookupClass(), "bsm", MT_bsm());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CallSite bsm2(Lookup caller, String name, MethodType type, Object arg) throws ReflectiveOperationException {
|
||||||
|
// ignore caller and name, but match the type:
|
||||||
|
List<Object> bsmInfo = new ArrayList<>(Arrays.asList(caller, name, type));
|
||||||
|
if (arg instanceof Object[])
|
||||||
|
bsmInfo.addAll(Arrays.asList((Object[])arg));
|
||||||
|
else
|
||||||
|
bsmInfo.add(arg);
|
||||||
|
return new ConstantCallSite(MH_printArgs().bindTo(bsmInfo).asCollector(Object[].class, type.parameterCount()).asType(type));
|
||||||
|
}
|
||||||
|
private static MethodType MT_bsm2() {
|
||||||
|
shouldNotCallThis();
|
||||||
|
return methodType(CallSite.class, Lookup.class, String.class, MethodType.class, Object.class);
|
||||||
|
}
|
||||||
|
private static MethodHandle MH_bsm2() throws ReflectiveOperationException {
|
||||||
|
shouldNotCallThis();
|
||||||
|
return lookup().findStatic(lookup().lookupClass(), "bsm2", MT_bsm2());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MethodHandle INDY_nothing() throws Throwable {
|
||||||
|
shouldNotCallThis();
|
||||||
|
return ((CallSite) MH_bsm().invokeGeneric(lookup(),
|
||||||
|
"nothing", methodType(void.class)
|
||||||
|
)).dynamicInvoker();
|
||||||
|
}
|
||||||
|
private static MethodHandle INDY_foo() throws Throwable {
|
||||||
|
shouldNotCallThis();
|
||||||
|
return ((CallSite) MH_bsm().invokeGeneric(lookup(),
|
||||||
|
"foo", methodType(void.class, String.class)
|
||||||
|
)).dynamicInvoker();
|
||||||
|
}
|
||||||
|
private static MethodHandle INDY_bar() throws Throwable {
|
||||||
|
shouldNotCallThis();
|
||||||
|
return ((CallSite) MH_bsm2().invokeGeneric(lookup(),
|
||||||
|
"bar", methodType(void.class, String.class, int.class)
|
||||||
|
, new Object[] { Void.class, "void type!",
|
||||||
|
1, 234.5F, 67.5, (long)89 }
|
||||||
|
)).dynamicInvoker();
|
||||||
|
}
|
||||||
|
private static MethodHandle INDY_bar2() throws Throwable {
|
||||||
|
shouldNotCallThis();
|
||||||
|
return ((CallSite) MH_bsm2().invokeGeneric(lookup(),
|
||||||
|
"bar2", methodType(void.class, String.class, int.class)
|
||||||
|
, new Object[] { Void.class, "void type!",
|
||||||
|
1, 234.5F, 67.5, (long)89 }
|
||||||
|
)).dynamicInvoker();
|
||||||
|
}
|
||||||
|
private static MethodHandle INDY_baz() throws Throwable {
|
||||||
|
shouldNotCallThis();
|
||||||
|
return ((CallSite) MH_bsm2().invokeGeneric(lookup(),
|
||||||
|
"baz", methodType(void.class, String.class, int.class, double.class)
|
||||||
|
, 1234.5
|
||||||
|
)).dynamicInvoker();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void shouldNotCallThis() {
|
||||||
|
// if this gets called, the transformation has not taken place
|
||||||
|
if (System.getProperty("InvokeDynamicPrintArgs.allow-untransformed") != null) return;
|
||||||
|
throw new AssertionError("this code should be statically transformed away by Indify");
|
||||||
|
}
|
||||||
|
}
|
484
jdk/test/java/dyn/InvokeGenericTest.java
Normal file
484
jdk/test/java/dyn/InvokeGenericTest.java
Normal file
@ -0,0 +1,484 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @test
|
||||||
|
* @summary unit tests for java.dyn.MethodHandle.invokeGeneric
|
||||||
|
* @compile -XDallowTransitionalJSR292=no -target 7 InvokeGenericTest.java
|
||||||
|
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.InvokeGenericTest
|
||||||
|
*/
|
||||||
|
|
||||||
|
package test.java.dyn;
|
||||||
|
|
||||||
|
import java.dyn.*;
|
||||||
|
import static java.dyn.MethodHandles.*;
|
||||||
|
import static java.dyn.MethodType.*;
|
||||||
|
import java.lang.reflect.*;
|
||||||
|
import java.util.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.junit.Assume.*;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jrose
|
||||||
|
*/
|
||||||
|
public class InvokeGenericTest {
|
||||||
|
// How much output?
|
||||||
|
static int verbosity = 0;
|
||||||
|
static {
|
||||||
|
String vstr = System.getProperty("test.java.dyn.InvokeGenericTest.verbosity");
|
||||||
|
if (vstr != null) verbosity = Integer.parseInt(vstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFirst() throws Throwable {
|
||||||
|
verbosity += 9; try {
|
||||||
|
// left blank for debugging
|
||||||
|
} finally { printCounts(); verbosity -= 9; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvokeGenericTest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void checkImplementedPlatform() {
|
||||||
|
boolean platformOK = false;
|
||||||
|
Properties properties = System.getProperties();
|
||||||
|
String vers = properties.getProperty("java.vm.version");
|
||||||
|
String name = properties.getProperty("java.vm.name");
|
||||||
|
String arch = properties.getProperty("os.arch");
|
||||||
|
if ((arch.equals("amd64") || arch.equals("i386") || arch.equals("x86") ||
|
||||||
|
arch.equals("sparc") || arch.equals("sparcv9")) &&
|
||||||
|
(name.contains("Client") || name.contains("Server"))
|
||||||
|
) {
|
||||||
|
platformOK = true;
|
||||||
|
} else {
|
||||||
|
System.err.println("Skipping tests for unsupported platform: "+Arrays.asList(vers, name, arch));
|
||||||
|
}
|
||||||
|
assumeTrue(platformOK);
|
||||||
|
}
|
||||||
|
|
||||||
|
String testName;
|
||||||
|
static int allPosTests, allNegTests;
|
||||||
|
int posTests, negTests;
|
||||||
|
@After
|
||||||
|
public void printCounts() {
|
||||||
|
if (verbosity >= 2 && (posTests | negTests) != 0) {
|
||||||
|
System.out.println();
|
||||||
|
if (posTests != 0) System.out.println("=== "+testName+": "+posTests+" positive test cases run");
|
||||||
|
if (negTests != 0) System.out.println("=== "+testName+": "+negTests+" negative test cases run");
|
||||||
|
allPosTests += posTests;
|
||||||
|
allNegTests += negTests;
|
||||||
|
posTests = negTests = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void countTest(boolean positive) {
|
||||||
|
if (positive) ++posTests;
|
||||||
|
else ++negTests;
|
||||||
|
}
|
||||||
|
void countTest() { countTest(true); }
|
||||||
|
void startTest(String name) {
|
||||||
|
if (testName != null) printCounts();
|
||||||
|
if (verbosity >= 1)
|
||||||
|
System.out.println(name);
|
||||||
|
posTests = negTests = 0;
|
||||||
|
testName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpClass() throws Exception {
|
||||||
|
calledLog.clear();
|
||||||
|
calledLog.add(null);
|
||||||
|
nextArgVal = INITIAL_ARG_VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDownClass() throws Exception {
|
||||||
|
int posTests = allPosTests, negTests = allNegTests;
|
||||||
|
if (verbosity >= 2 && (posTests | negTests) != 0) {
|
||||||
|
System.out.println();
|
||||||
|
if (posTests != 0) System.out.println("=== "+posTests+" total positive test cases");
|
||||||
|
if (negTests != 0) System.out.println("=== "+negTests+" total negative test cases");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Object> calledLog = new ArrayList<Object>();
|
||||||
|
static Object logEntry(String name, Object... args) {
|
||||||
|
return Arrays.asList(name, Arrays.asList(args));
|
||||||
|
}
|
||||||
|
static Object called(String name, Object... args) {
|
||||||
|
Object entry = logEntry(name, args);
|
||||||
|
calledLog.add(entry);
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
static void assertCalled(String name, Object... args) {
|
||||||
|
Object expected = logEntry(name, args);
|
||||||
|
Object actual = calledLog.get(calledLog.size() - 1);
|
||||||
|
if (expected.equals(actual) && verbosity < 9) return;
|
||||||
|
System.out.println("assertCalled "+name+":");
|
||||||
|
System.out.println("expected: "+expected);
|
||||||
|
System.out.println("actual: "+actual);
|
||||||
|
System.out.println("ex. types: "+getClasses(expected));
|
||||||
|
System.out.println("act. types: "+getClasses(actual));
|
||||||
|
assertEquals("previous method call", expected, actual);
|
||||||
|
}
|
||||||
|
static void printCalled(MethodHandle target, String name, Object... args) {
|
||||||
|
if (verbosity >= 3)
|
||||||
|
System.out.println("calling MH="+target+" to "+name+Arrays.toString(args));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Object castToWrapper(Object value, Class<?> dst) {
|
||||||
|
Object wrap = null;
|
||||||
|
if (value instanceof Number)
|
||||||
|
wrap = castToWrapperOrNull(((Number)value).longValue(), dst);
|
||||||
|
if (value instanceof Character)
|
||||||
|
wrap = castToWrapperOrNull((char)(Character)value, dst);
|
||||||
|
if (wrap != null) return wrap;
|
||||||
|
return dst.cast(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Object castToWrapperOrNull(long value, Class<?> dst) {
|
||||||
|
if (dst == int.class || dst == Integer.class)
|
||||||
|
return (int)(value);
|
||||||
|
if (dst == long.class || dst == Long.class)
|
||||||
|
return (long)(value);
|
||||||
|
if (dst == char.class || dst == Character.class)
|
||||||
|
return (char)(value);
|
||||||
|
if (dst == short.class || dst == Short.class)
|
||||||
|
return (short)(value);
|
||||||
|
if (dst == float.class || dst == Float.class)
|
||||||
|
return (float)(value);
|
||||||
|
if (dst == double.class || dst == Double.class)
|
||||||
|
return (double)(value);
|
||||||
|
if (dst == byte.class || dst == Byte.class)
|
||||||
|
return (byte)(value);
|
||||||
|
if (dst == boolean.class || dst == boolean.class)
|
||||||
|
return ((value % 29) & 1) == 0;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final int ONE_MILLION = (1000*1000), // first int value
|
||||||
|
TEN_BILLION = (10*1000*1000*1000), // scale factor to reach upper 32 bits
|
||||||
|
INITIAL_ARG_VAL = ONE_MILLION << 1; // <<1 makes space for sign bit;
|
||||||
|
static long nextArgVal;
|
||||||
|
static long nextArg(boolean moreBits) {
|
||||||
|
long val = nextArgVal++;
|
||||||
|
long sign = -(val & 1); // alternate signs
|
||||||
|
val >>= 1;
|
||||||
|
if (moreBits)
|
||||||
|
// Guarantee some bits in the high word.
|
||||||
|
// In any case keep the decimal representation simple-looking,
|
||||||
|
// with lots of zeroes, so as not to make the printed decimal
|
||||||
|
// strings unnecessarily noisy.
|
||||||
|
val += (val % ONE_MILLION) * TEN_BILLION;
|
||||||
|
return val ^ sign;
|
||||||
|
}
|
||||||
|
static int nextArg() {
|
||||||
|
// Produce a 32-bit result something like ONE_MILLION+(smallint).
|
||||||
|
// Example: 1_000_042.
|
||||||
|
return (int) nextArg(false);
|
||||||
|
}
|
||||||
|
static long nextArg(Class<?> kind) {
|
||||||
|
if (kind == long.class || kind == Long.class ||
|
||||||
|
kind == double.class || kind == Double.class)
|
||||||
|
// produce a 64-bit result something like
|
||||||
|
// ((TEN_BILLION+1) * (ONE_MILLION+(smallint)))
|
||||||
|
// Example: 10_000_420_001_000_042.
|
||||||
|
return nextArg(true);
|
||||||
|
return (long) nextArg();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Object randomArg(Class<?> param) {
|
||||||
|
Object wrap = castToWrapperOrNull(nextArg(param), param);
|
||||||
|
if (wrap != null) {
|
||||||
|
return wrap;
|
||||||
|
}
|
||||||
|
// import sun.dyn.util.Wrapper;
|
||||||
|
// Wrapper wrap = Wrapper.forBasicType(dst);
|
||||||
|
// if (wrap == Wrapper.OBJECT && Wrapper.isWrapperType(dst))
|
||||||
|
// wrap = Wrapper.forWrapperType(dst);
|
||||||
|
// if (wrap != Wrapper.OBJECT)
|
||||||
|
// return wrap.wrap(nextArg++);
|
||||||
|
if (param.isInterface()) {
|
||||||
|
for (Class<?> c : param.getClasses()) {
|
||||||
|
if (param.isAssignableFrom(c) && !c.isInterface())
|
||||||
|
{ param = c; break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (param.isInterface() || param.isAssignableFrom(String.class))
|
||||||
|
return "#"+nextArg();
|
||||||
|
else
|
||||||
|
try {
|
||||||
|
return param.newInstance();
|
||||||
|
} catch (InstantiationException ex) {
|
||||||
|
} catch (IllegalAccessException ex) {
|
||||||
|
}
|
||||||
|
return null; // random class not Object, String, Integer, etc.
|
||||||
|
}
|
||||||
|
static Object[] randomArgs(Class<?>... params) {
|
||||||
|
Object[] args = new Object[params.length];
|
||||||
|
for (int i = 0; i < args.length; i++)
|
||||||
|
args[i] = randomArg(params[i]);
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
static Object[] randomArgs(int nargs, Class<?> param) {
|
||||||
|
Object[] args = new Object[nargs];
|
||||||
|
for (int i = 0; i < args.length; i++)
|
||||||
|
args[i] = randomArg(param);
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final Object ANON_OBJ = new Object();
|
||||||
|
static Object zeroArg(Class<?> param) {
|
||||||
|
Object x = castToWrapperOrNull(0L, param);
|
||||||
|
if (x != null) return x;
|
||||||
|
if (param.isInterface() || param.isAssignableFrom(String.class)) return "\"\"";
|
||||||
|
if (param == Object.class) return ANON_OBJ;
|
||||||
|
if (param.getComponentType() != null) return Array.newInstance(param.getComponentType(), 0);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
static Object[] zeroArgs(Class<?>... params) {
|
||||||
|
Object[] args = new Object[params.length];
|
||||||
|
for (int i = 0; i < args.length; i++)
|
||||||
|
args[i] = zeroArg(params[i]);
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
static Object[] zeroArgs(List<Class<?>> params) {
|
||||||
|
return zeroArgs(params.toArray(new Class<?>[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T, E extends T> T[] array(Class<T[]> atype, E... a) {
|
||||||
|
return Arrays.copyOf(a, a.length, atype);
|
||||||
|
}
|
||||||
|
static <T> T[] cat(T[] a, T... b) {
|
||||||
|
int alen = a.length, blen = b.length;
|
||||||
|
if (blen == 0) return a;
|
||||||
|
T[] c = Arrays.copyOf(a, alen + blen);
|
||||||
|
System.arraycopy(b, 0, c, alen, blen);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
static Integer[] boxAll(int... vx) {
|
||||||
|
Integer[] res = new Integer[vx.length];
|
||||||
|
for (int i = 0; i < res.length; i++) {
|
||||||
|
res[i] = vx[i];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
static Object getClasses(Object x) {
|
||||||
|
if (x == null) return x;
|
||||||
|
if (x instanceof String) return x; // keep the name
|
||||||
|
if (x instanceof List) {
|
||||||
|
// recursively report classes of the list elements
|
||||||
|
Object[] xa = ((List)x).toArray();
|
||||||
|
for (int i = 0; i < xa.length; i++)
|
||||||
|
xa[i] = getClasses(xa[i]);
|
||||||
|
return Arrays.asList(xa);
|
||||||
|
}
|
||||||
|
return x.getClass().getSimpleName();
|
||||||
|
}
|
||||||
|
|
||||||
|
static MethodHandle changeArgTypes(MethodHandle target, Class<?> argType) {
|
||||||
|
return changeArgTypes(target, 0, 999, argType);
|
||||||
|
}
|
||||||
|
static MethodHandle changeArgTypes(MethodHandle target,
|
||||||
|
int beg, int end, Class<?> argType) {
|
||||||
|
MethodType targetType = target.type();
|
||||||
|
end = Math.min(end, targetType.parameterCount());
|
||||||
|
ArrayList<Class<?>> argTypes = new ArrayList<Class<?>>(targetType.parameterList());
|
||||||
|
Collections.fill(argTypes.subList(beg, end), argType);
|
||||||
|
MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes);
|
||||||
|
return MethodHandles.convertArguments(target, ttype2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This lookup is good for all members in and under InvokeGenericTest.
|
||||||
|
static final Lookup LOOKUP = MethodHandles.lookup();
|
||||||
|
|
||||||
|
Map<List<Class<?>>, MethodHandle> CALLABLES = new HashMap<List<Class<?>>, MethodHandle>();
|
||||||
|
MethodHandle callable(List<Class<?>> params) {
|
||||||
|
MethodHandle mh = CALLABLES.get(params);
|
||||||
|
if (mh == null) {
|
||||||
|
mh = collectArguments(collector_MH, methodType(Object.class, params));
|
||||||
|
CALLABLES.put(params, mh);
|
||||||
|
}
|
||||||
|
return mh;
|
||||||
|
}
|
||||||
|
MethodHandle callable(Class<?>... params) {
|
||||||
|
return callable(Arrays.asList(params));
|
||||||
|
}
|
||||||
|
private static Object collector(Object... args) {
|
||||||
|
return Arrays.asList(args);
|
||||||
|
}
|
||||||
|
private static final MethodHandle collector_MH;
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
collector_MH
|
||||||
|
= LOOKUP.findStatic(LOOKUP.lookupClass(),
|
||||||
|
"collector",
|
||||||
|
methodType(Object.class, Object[].class));
|
||||||
|
} catch (NoAccessException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSimple() throws Throwable {
|
||||||
|
startTest("testSimple");
|
||||||
|
countTest();
|
||||||
|
String[] args = { "one", "two" };
|
||||||
|
MethodHandle mh = callable(Object.class, String.class);
|
||||||
|
Object res; List resl;
|
||||||
|
res = resl = (List) mh.invokeGeneric((String)args[0], (Object)args[1]);
|
||||||
|
//System.out.println(res);
|
||||||
|
assertEquals(Arrays.asList(args), res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWrongArgumentCount() throws Throwable {
|
||||||
|
startTest("testWrongArgumentCount");
|
||||||
|
for (int i = 0; i <= 10; i++) {
|
||||||
|
testWrongArgumentCount(Collections.<Class<?>>nCopies(i, Integer.class));
|
||||||
|
if (i <= 4) {
|
||||||
|
testWrongArgumentCount(Collections.<Class<?>>nCopies(i, int.class));
|
||||||
|
testWrongArgumentCount(Collections.<Class<?>>nCopies(i, long.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void testWrongArgumentCount(List<Class<?>> params) throws Throwable {
|
||||||
|
int max = params.size();
|
||||||
|
for (int i = 0; i < max; i++) {
|
||||||
|
List<Class<?>> params2 = params.subList(0, i);
|
||||||
|
for (int k = 0; k <= 2; k++) {
|
||||||
|
if (k == 1) params = methodType(Object.class, params).generic().parameterList();
|
||||||
|
if (k == 2) params2 = methodType(Object.class, params2).generic().parameterList();
|
||||||
|
testWrongArgumentCount(params, params2);
|
||||||
|
testWrongArgumentCount(params2, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void testWrongArgumentCount(List<Class<?>> expect, List<Class<?>> observe) throws Throwable {
|
||||||
|
countTest(false);
|
||||||
|
if (expect.equals(observe))
|
||||||
|
assert(false);
|
||||||
|
MethodHandle target = callable(expect);
|
||||||
|
Object[] args = zeroArgs(observe);
|
||||||
|
Object junk;
|
||||||
|
try {
|
||||||
|
switch (args.length) {
|
||||||
|
case 0:
|
||||||
|
junk = target.invokeGeneric(); break;
|
||||||
|
case 1:
|
||||||
|
junk = target.invokeGeneric(args[0]); break;
|
||||||
|
case 2:
|
||||||
|
junk = target.invokeGeneric(args[0], args[1]); break;
|
||||||
|
case 3:
|
||||||
|
junk = target.invokeGeneric(args[0], args[1], args[2]); break;
|
||||||
|
case 4:
|
||||||
|
junk = target.invokeGeneric(args[0], args[1], args[2], args[3]); break;
|
||||||
|
default:
|
||||||
|
junk = target.invokeWithArguments(args); break;
|
||||||
|
}
|
||||||
|
} catch (WrongMethodTypeException ex) {
|
||||||
|
return;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new RuntimeException("wrong exception calling "+target+target.type()+" on "+Arrays.asList(args)+" : "+ex);
|
||||||
|
}
|
||||||
|
throw new RuntimeException("bad success calling "+target+target.type()+" on "+Arrays.asList(args));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Make a list of all combinations of the given types, with the given arities.
|
||||||
|
* A void return type is possible iff the first type is void.class.
|
||||||
|
*/
|
||||||
|
static List<MethodType> allMethodTypes(int minargc, int maxargc, Class<?>... types) {
|
||||||
|
ArrayList<MethodType> result = new ArrayList<MethodType>();
|
||||||
|
if (types.length > 0) {
|
||||||
|
ArrayList<MethodType> argcTypes = new ArrayList<MethodType>();
|
||||||
|
// build arity-zero types first
|
||||||
|
for (Class<?> rtype : types) {
|
||||||
|
argcTypes.add(MethodType.methodType(rtype));
|
||||||
|
}
|
||||||
|
if (types[0] == void.class)
|
||||||
|
// void is not an argument type
|
||||||
|
types = Arrays.copyOfRange(types, 1, types.length);
|
||||||
|
for (int argc = 0; argc <= maxargc; argc++) {
|
||||||
|
if (argc >= minargc)
|
||||||
|
result.addAll(argcTypes);
|
||||||
|
if (argc >= maxargc)
|
||||||
|
break;
|
||||||
|
ArrayList<MethodType> prevTypes = argcTypes;
|
||||||
|
argcTypes = new ArrayList<MethodType>();
|
||||||
|
for (MethodType prevType : prevTypes) {
|
||||||
|
for (Class<?> ptype : types) {
|
||||||
|
argcTypes.add(prevType.insertParameterTypes(argc, ptype));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableList(result);
|
||||||
|
}
|
||||||
|
static List<MethodType> allMethodTypes(int argc, Class<?>... types) {
|
||||||
|
return allMethodTypes(argc, argc, types);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RandomInterface { }
|
||||||
|
|
||||||
|
MethodHandle toString_MH;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReferenceConversions() throws Throwable {
|
||||||
|
startTest("testReferenceConversions");
|
||||||
|
toString_MH = LOOKUP.
|
||||||
|
findVirtual(Object.class, "toString", MethodType.methodType(String.class));
|
||||||
|
String[] args = { "one", "two" };
|
||||||
|
for (MethodType type : allMethodTypes(2, Object.class, String.class, RandomInterface.class)) {
|
||||||
|
testReferenceConversions(type, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void testReferenceConversions(MethodType type, Object... args) throws Throwable {
|
||||||
|
countTest();
|
||||||
|
if (verbosity > 3) System.out.println("target type: "+type);
|
||||||
|
MethodHandle mh = callable(type.parameterList());
|
||||||
|
MethodHandle tsdrop = MethodHandles.dropArguments(toString_MH, 1, type.parameterList());
|
||||||
|
mh = MethodHandles.foldArguments(tsdrop, mh);
|
||||||
|
mh = mh.asType(type);
|
||||||
|
Object res = mh.invokeGeneric((String)args[0], (Object)args[1]);
|
||||||
|
//System.out.println(res);
|
||||||
|
assertEquals(Arrays.asList(args).toString(), res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test @Ignore("known failure pending 6939861")
|
||||||
|
public void testBoxConversions() throws Throwable {
|
||||||
|
startTest("testBoxConversions");
|
||||||
|
countTest();
|
||||||
|
Integer[] args = { 1, 2 };
|
||||||
|
MethodHandle mh = callable(Object.class, int.class);
|
||||||
|
Object res; List resl;
|
||||||
|
res = resl = (List) mh.invokeGeneric((int)args[0], (Object)args[1]);
|
||||||
|
//System.out.println(res);
|
||||||
|
assertEquals(Arrays.asList(args), res);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -25,18 +25,18 @@
|
|||||||
|
|
||||||
/* @test
|
/* @test
|
||||||
* @summary example code used in javadoc for java.dyn API
|
* @summary example code used in javadoc for java.dyn API
|
||||||
* @compile -XDallowTransitionalJSR292=no JavaDocExamples.java
|
* @compile -XDallowTransitionalJSR292=no JavaDocExamplesTest.java
|
||||||
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.JavaDocExamples
|
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.JavaDocExamplesTest
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
---- To run outside jtreg:
|
---- To run outside jtreg:
|
||||||
$ $JAVA7X_HOME/bin/javac -cp $JUNIT4_JAR -d /tmp/Classes \
|
$ $JAVA7X_HOME/bin/javac -cp $JUNIT4_JAR -d /tmp/Classes \
|
||||||
$DAVINCI/sources/jdk/test/java/dyn/JavaDocExamples.java
|
$DAVINCI/sources/jdk/test/java/dyn/JavaDocExamplesTest.java
|
||||||
$ $JAVA7X_HOME/bin/java -cp $JUNIT4_JAR:/tmp/Classes \
|
$ $JAVA7X_HOME/bin/java -cp $JUNIT4_JAR:/tmp/Classes \
|
||||||
-XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles \
|
-XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles \
|
||||||
-Dtest.java.dyn.JavaDocExamples.verbosity=1 \
|
-Dtest.java.dyn.JavaDocExamplesTest.verbosity=1 \
|
||||||
test.java.dyn.JavaDocExamples
|
test.java.dyn.JavaDocExamplesTest
|
||||||
----
|
----
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -57,15 +57,15 @@ import static org.junit.Assume.*;
|
|||||||
/**
|
/**
|
||||||
* @author jrose
|
* @author jrose
|
||||||
*/
|
*/
|
||||||
public class JavaDocExamples {
|
public class JavaDocExamplesTest {
|
||||||
/** Wrapper for running the JUnit tests in this module.
|
/** Wrapper for running the JUnit tests in this module.
|
||||||
* Put JUnit on the classpath!
|
* Put JUnit on the classpath!
|
||||||
*/
|
*/
|
||||||
public static void main(String... ignore) {
|
public static void main(String... ignore) {
|
||||||
org.junit.runner.JUnitCore.runClasses(JavaDocExamples.class);
|
org.junit.runner.JUnitCore.runClasses(JavaDocExamplesTest.class);
|
||||||
}
|
}
|
||||||
// How much output?
|
// How much output?
|
||||||
static int verbosity = Integer.getInteger("test.java.dyn.JavaDocExamples.verbosity", 0);
|
static int verbosity = Integer.getInteger("test.java.dyn.JavaDocExamplesTest.verbosity", 0);
|
||||||
|
|
||||||
{}
|
{}
|
||||||
static final private Lookup LOOKUP = lookup();
|
static final private Lookup LOOKUP = lookup();
|
||||||
@ -95,11 +95,11 @@ MethodHandle CONCAT_3 = LOOKUP.findVirtual(String.class,
|
|||||||
MethodHandle HASHCODE_3 = LOOKUP.findVirtual(Object.class,
|
MethodHandle HASHCODE_3 = LOOKUP.findVirtual(Object.class,
|
||||||
"hashCode", methodType(int.class));
|
"hashCode", methodType(int.class));
|
||||||
//assertEquals("xy", (String) CONCAT_1.invokeExact("x", "y"));
|
//assertEquals("xy", (String) CONCAT_1.invokeExact("x", "y"));
|
||||||
assertEquals("xy", (String) CONCAT_2.<String>invokeExact("x", "y"));
|
assertEquals("xy", (String) CONCAT_2.invokeExact("x", "y"));
|
||||||
assertEquals("xy", (String) CONCAT_3.<String>invokeExact("x", "y"));
|
assertEquals("xy", (String) CONCAT_3.invokeExact("x", "y"));
|
||||||
//assertEquals("xy".hashCode(), (int) HASHCODE_1.<int>invokeExact((Object)"xy"));
|
//assertEquals("xy".hashCode(), (int) HASHCODE_1.invokeExact((Object)"xy"));
|
||||||
assertEquals("xy".hashCode(), (int) HASHCODE_2.<int>invokeExact((Object)"xy"));
|
assertEquals("xy".hashCode(), (int) HASHCODE_2.invokeExact((Object)"xy"));
|
||||||
assertEquals("xy".hashCode(), (int) HASHCODE_3.<int>invokeExact((Object)"xy"));
|
assertEquals("xy".hashCode(), (int) HASHCODE_3.invokeExact((Object)"xy"));
|
||||||
{}
|
{}
|
||||||
}
|
}
|
||||||
@Test public void testDropArguments() throws Throwable {
|
@Test public void testDropArguments() throws Throwable {
|
||||||
@ -107,16 +107,32 @@ assertEquals("xy".hashCode(), (int) HASHCODE_3.<int>invokeExact((Object)"xy"));
|
|||||||
{} /// JAVADOC
|
{} /// JAVADOC
|
||||||
MethodHandle cat = lookup().findVirtual(String.class,
|
MethodHandle cat = lookup().findVirtual(String.class,
|
||||||
"concat", methodType(String.class, String.class));
|
"concat", methodType(String.class, String.class));
|
||||||
cat = cat.asType(methodType(Object.class, String.class, String.class)); /*(String)*/
|
assertEquals("xy", (String) cat.invokeExact("x", "y"));
|
||||||
assertEquals("xy", /*(String)*/ cat.invokeExact("x", "y"));
|
|
||||||
MethodHandle d0 = dropArguments(cat, 0, String.class);
|
MethodHandle d0 = dropArguments(cat, 0, String.class);
|
||||||
assertEquals("yz", /*(String)*/ d0.invokeExact("x", "y", "z"));
|
assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
|
||||||
MethodHandle d1 = dropArguments(cat, 1, String.class);
|
MethodHandle d1 = dropArguments(cat, 1, String.class);
|
||||||
assertEquals("xz", /*(String)*/ d1.invokeExact("x", "y", "z"));
|
assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));
|
||||||
MethodHandle d2 = dropArguments(cat, 2, String.class);
|
MethodHandle d2 = dropArguments(cat, 2, String.class);
|
||||||
assertEquals("xy", /*(String)*/ d2.invokeExact("x", "y", "z"));
|
assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
|
||||||
MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
|
MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
|
||||||
assertEquals("xz", /*(String)*/ d12.invokeExact("x", 12, true, "z"));
|
assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testFilterArguments() throws Throwable {
|
||||||
|
{{
|
||||||
|
{} /// JAVADOC
|
||||||
|
MethodHandle cat = lookup().findVirtual(String.class,
|
||||||
|
"concat", methodType(String.class, String.class));
|
||||||
|
MethodHandle upcase = lookup().findVirtual(String.class,
|
||||||
|
"toUpperCase", methodType(String.class));
|
||||||
|
assertEquals("xy", (String) cat.invokeExact("x", "y"));
|
||||||
|
MethodHandle f0 = filterArguments(cat, 0, upcase);
|
||||||
|
assertEquals("Xy", (String) f0.invokeExact("x", "y")); // Xy
|
||||||
|
MethodHandle f1 = filterArguments(cat, 1, upcase);
|
||||||
|
assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY
|
||||||
|
MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
|
||||||
|
assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,4 +141,38 @@ assertEquals("xz", /*(String)*/ d12.invokeExact("x", 12, true, "z"));
|
|||||||
System.out.println("result: "+act);
|
System.out.println("result: "+act);
|
||||||
Assert.assertEquals(exp, act);
|
Assert.assertEquals(exp, act);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MethodHandle asList;
|
||||||
|
@Test public void testWithTypeHandler() throws Throwable {
|
||||||
|
{{
|
||||||
|
{} /// JAVADOC
|
||||||
|
MethodHandle makeEmptyList = MethodHandles.constant(List.class, Arrays.asList());
|
||||||
|
MethodHandle asList = lookup()
|
||||||
|
.findStatic(Arrays.class, "asList", methodType(List.class, Object[].class));
|
||||||
|
|
||||||
|
JavaDocExamplesTest.asList = asList;
|
||||||
|
/*
|
||||||
|
static MethodHandle collectingTypeHandler(MethodHandle base, MethodType newType) {
|
||||||
|
return asList.asCollector(Object[].class, newType.parameterCount()).asType(newType);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
MethodHandle collectingTypeHandler = lookup()
|
||||||
|
.findStatic(lookup().lookupClass(), "collectingTypeHandler",
|
||||||
|
methodType(MethodHandle.class, MethodHandle.class, MethodType.class));
|
||||||
|
MethodHandle makeAnyList = makeEmptyList.withTypeHandler(collectingTypeHandler);
|
||||||
|
|
||||||
|
assertEquals("[]", makeAnyList.invokeGeneric().toString());
|
||||||
|
assertEquals("[1]", makeAnyList.invokeGeneric(1).toString());
|
||||||
|
assertEquals("[two, too]", makeAnyList.invokeGeneric("two", "too").toString());
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
static MethodHandle collectingTypeHandler(MethodHandle base, MethodType newType) {
|
||||||
|
//System.out.println("Converting "+asList+" to "+newType);
|
||||||
|
MethodHandle conv = asList.asCollector(Object[].class, newType.parameterCount()).asType(newType);
|
||||||
|
//System.out.println(" =>"+conv);
|
||||||
|
return conv;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -25,8 +25,8 @@
|
|||||||
|
|
||||||
/* @test
|
/* @test
|
||||||
* @summary unit tests for java.dyn.MethodHandles
|
* @summary unit tests for java.dyn.MethodHandles
|
||||||
* @compile -XDinvokedynamic MethodHandlesTest.java
|
* @compile -source 7 -target 7 -XDallowTransitionalJSR292=no MethodHandlesTest.java
|
||||||
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic test.java.dyn.MethodHandlesTest
|
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.MethodHandlesTest
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package test.java.dyn;
|
package test.java.dyn;
|
||||||
@ -62,7 +62,6 @@ public class MethodHandlesTest {
|
|||||||
// lookups, without exercising the actual method handle.
|
// lookups, without exercising the actual method handle.
|
||||||
static boolean DO_MORE_CALLS = true;
|
static boolean DO_MORE_CALLS = true;
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFirst() throws Throwable {
|
public void testFirst() throws Throwable {
|
||||||
verbosity += 9; try {
|
verbosity += 9; try {
|
||||||
@ -458,7 +457,7 @@ public class MethodHandlesTest {
|
|||||||
Exception noAccess = null;
|
Exception noAccess = null;
|
||||||
try {
|
try {
|
||||||
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
|
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
|
||||||
target = lookup.findStatic(defc, name, type);
|
target = lookup.in(defc).findStatic(defc, name, type);
|
||||||
} catch (NoAccessException ex) {
|
} catch (NoAccessException ex) {
|
||||||
noAccess = ex;
|
noAccess = ex;
|
||||||
}
|
}
|
||||||
@ -469,16 +468,22 @@ public class MethodHandlesTest {
|
|||||||
assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
|
assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
|
||||||
if (!positive) return; // negative test failed as expected
|
if (!positive) return; // negative test failed as expected
|
||||||
assertEquals(type, target.type());
|
assertEquals(type, target.type());
|
||||||
assertTrue(target.toString().contains(name)); // rough check
|
assertNameStringContains(target, name);
|
||||||
if (!DO_MORE_CALLS && lookup != PRIVATE) return;
|
if (!DO_MORE_CALLS && lookup != PRIVATE) return;
|
||||||
Object[] args = randomArgs(params);
|
Object[] args = randomArgs(params);
|
||||||
printCalled(target, name, args);
|
printCalled(target, name, args);
|
||||||
target.invokeVarargs(args);
|
target.invokeWithArguments(args);
|
||||||
assertCalled(name, args);
|
assertCalled(name, args);
|
||||||
if (verbosity >= 1)
|
if (verbosity >= 1)
|
||||||
System.out.print(':');
|
System.out.print(':');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rough check of name string
|
||||||
|
static void assertNameStringContains(Object x, String s) {
|
||||||
|
if (x.toString().contains(s)) return;
|
||||||
|
assertEquals(s, x);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFindVirtual() throws Throwable {
|
public void testFindVirtual() throws Throwable {
|
||||||
if (CAN_SKIP_WORKING) return;
|
if (CAN_SKIP_WORKING) return;
|
||||||
@ -522,7 +527,7 @@ public class MethodHandlesTest {
|
|||||||
Exception noAccess = null;
|
Exception noAccess = null;
|
||||||
try {
|
try {
|
||||||
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
|
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
|
||||||
target = lookup.findVirtual(defc, methodName, type);
|
target = lookup.in(defc).findVirtual(defc, methodName, type);
|
||||||
} catch (NoAccessException ex) {
|
} catch (NoAccessException ex) {
|
||||||
noAccess = ex;
|
noAccess = ex;
|
||||||
}
|
}
|
||||||
@ -535,12 +540,12 @@ public class MethodHandlesTest {
|
|||||||
Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)defc), params);
|
Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)defc), params);
|
||||||
MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
|
MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
|
||||||
assertEquals(typeWithSelf, target.type());
|
assertEquals(typeWithSelf, target.type());
|
||||||
assertTrue(target.toString().contains(methodName)); // rough check
|
assertNameStringContains(target, methodName);
|
||||||
if (!DO_MORE_CALLS && lookup != PRIVATE) return;
|
if (!DO_MORE_CALLS && lookup != PRIVATE) return;
|
||||||
Object[] argsWithSelf = randomArgs(paramsWithSelf);
|
Object[] argsWithSelf = randomArgs(paramsWithSelf);
|
||||||
if (rcvc != defc) argsWithSelf[0] = randomArg(rcvc);
|
if (rcvc != defc) argsWithSelf[0] = randomArg(rcvc);
|
||||||
printCalled(target, name, argsWithSelf);
|
printCalled(target, name, argsWithSelf);
|
||||||
target.invokeVarargs(argsWithSelf);
|
target.invokeWithArguments(argsWithSelf);
|
||||||
assertCalled(name, argsWithSelf);
|
assertCalled(name, argsWithSelf);
|
||||||
if (verbosity >= 1)
|
if (verbosity >= 1)
|
||||||
System.out.print(':');
|
System.out.print(':');
|
||||||
@ -576,7 +581,8 @@ public class MethodHandlesTest {
|
|||||||
Exception noAccess = null;
|
Exception noAccess = null;
|
||||||
try {
|
try {
|
||||||
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
|
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
|
||||||
target = lookup.findSpecial(defc, name, type, specialCaller);
|
if (verbosity >= 5) System.out.println(" lookup => "+lookup.in(specialCaller));
|
||||||
|
target = lookup.in(specialCaller).findSpecial(defc, name, type, specialCaller);
|
||||||
} catch (NoAccessException ex) {
|
} catch (NoAccessException ex) {
|
||||||
noAccess = ex;
|
noAccess = ex;
|
||||||
}
|
}
|
||||||
@ -591,11 +597,11 @@ public class MethodHandlesTest {
|
|||||||
assertEquals(type, target.type().dropParameterTypes(0,1));
|
assertEquals(type, target.type().dropParameterTypes(0,1));
|
||||||
Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)specialCaller), params);
|
Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)specialCaller), params);
|
||||||
MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
|
MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
|
||||||
assertTrue(target.toString().contains(name)); // rough check
|
assertNameStringContains(target, name);
|
||||||
if (!DO_MORE_CALLS && lookup != PRIVATE && lookup != EXAMPLE) return;
|
if (!DO_MORE_CALLS && lookup != PRIVATE && lookup != EXAMPLE) return;
|
||||||
Object[] args = randomArgs(paramsWithSelf);
|
Object[] args = randomArgs(paramsWithSelf);
|
||||||
printCalled(target, name, args);
|
printCalled(target, name, args);
|
||||||
target.invokeVarargs(args);
|
target.invokeWithArguments(args);
|
||||||
assertCalled(name, args);
|
assertCalled(name, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -632,7 +638,7 @@ public class MethodHandlesTest {
|
|||||||
Exception noAccess = null;
|
Exception noAccess = null;
|
||||||
try {
|
try {
|
||||||
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
|
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
|
||||||
target = lookup.bind(receiver, methodName, type);
|
target = lookup.in(defc).bind(receiver, methodName, type);
|
||||||
} catch (NoAccessException ex) {
|
} catch (NoAccessException ex) {
|
||||||
noAccess = ex;
|
noAccess = ex;
|
||||||
}
|
}
|
||||||
@ -645,7 +651,7 @@ public class MethodHandlesTest {
|
|||||||
assertEquals(type, target.type());
|
assertEquals(type, target.type());
|
||||||
Object[] args = randomArgs(params);
|
Object[] args = randomArgs(params);
|
||||||
printCalled(target, name, args);
|
printCalled(target, name, args);
|
||||||
target.invokeVarargs(args);
|
target.invokeWithArguments(args);
|
||||||
Object[] argsWithReceiver = cat(array(Object[].class, receiver), args);
|
Object[] argsWithReceiver = cat(array(Object[].class, receiver), args);
|
||||||
assertCalled(name, argsWithReceiver);
|
assertCalled(name, argsWithReceiver);
|
||||||
if (verbosity >= 1)
|
if (verbosity >= 1)
|
||||||
@ -705,9 +711,9 @@ public class MethodHandlesTest {
|
|||||||
try {
|
try {
|
||||||
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
|
if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
|
||||||
if (isSpecial)
|
if (isSpecial)
|
||||||
target = lookup.unreflectSpecial(rmethod, specialCaller);
|
target = lookup.in(specialCaller).unreflectSpecial(rmethod, specialCaller);
|
||||||
else
|
else
|
||||||
target = lookup.unreflect(rmethod);
|
target = lookup.in(defc).unreflect(rmethod);
|
||||||
} catch (NoAccessException ex) {
|
} catch (NoAccessException ex) {
|
||||||
noAccess = ex;
|
noAccess = ex;
|
||||||
}
|
}
|
||||||
@ -737,7 +743,7 @@ public class MethodHandlesTest {
|
|||||||
}
|
}
|
||||||
Object[] argsMaybeWithSelf = randomArgs(paramsMaybeWithSelf);
|
Object[] argsMaybeWithSelf = randomArgs(paramsMaybeWithSelf);
|
||||||
printCalled(target, name, argsMaybeWithSelf);
|
printCalled(target, name, argsMaybeWithSelf);
|
||||||
target.invokeVarargs(argsMaybeWithSelf);
|
target.invokeWithArguments(argsMaybeWithSelf);
|
||||||
assertCalled(name, argsMaybeWithSelf);
|
assertCalled(name, argsMaybeWithSelf);
|
||||||
if (verbosity >= 1)
|
if (verbosity >= 1)
|
||||||
System.out.print(':');
|
System.out.print(':');
|
||||||
@ -875,7 +881,7 @@ public class MethodHandlesTest {
|
|||||||
if (isStatic) expType = expType.dropParameterTypes(0, 1);
|
if (isStatic) expType = expType.dropParameterTypes(0, 1);
|
||||||
MethodHandle mh = lookup.unreflectGetter(f);
|
MethodHandle mh = lookup.unreflectGetter(f);
|
||||||
assertSame(mh.type(), expType);
|
assertSame(mh.type(), expType);
|
||||||
assertEquals(mh.toString(), fname);
|
assertNameStringContains(mh, fname);
|
||||||
HasFields fields = new HasFields();
|
HasFields fields = new HasFields();
|
||||||
Object sawValue;
|
Object sawValue;
|
||||||
Class<?> rtype = type;
|
Class<?> rtype = type;
|
||||||
@ -885,12 +891,12 @@ public class MethodHandlesTest {
|
|||||||
for (int i = 0; i <= 1; i++) {
|
for (int i = 0; i <= 1; i++) {
|
||||||
if (isStatic) {
|
if (isStatic) {
|
||||||
if (type == int.class)
|
if (type == int.class)
|
||||||
sawValue = mh.<int>invokeExact(); // do these exactly
|
sawValue = (int) mh.invokeExact(); // do these exactly
|
||||||
else
|
else
|
||||||
sawValue = mh.invokeExact();
|
sawValue = mh.invokeExact();
|
||||||
} else {
|
} else {
|
||||||
if (type == int.class)
|
if (type == int.class)
|
||||||
sawValue = mh.<int>invokeExact((Object) fields);
|
sawValue = (int) mh.invokeExact((Object) fields);
|
||||||
else
|
else
|
||||||
sawValue = mh.invokeExact((Object) fields);
|
sawValue = mh.invokeExact((Object) fields);
|
||||||
}
|
}
|
||||||
@ -947,7 +953,7 @@ public class MethodHandlesTest {
|
|||||||
mh = lookup.findStaticSetter(fclass, fname, ftype);
|
mh = lookup.findStaticSetter(fclass, fname, ftype);
|
||||||
else throw new InternalError();
|
else throw new InternalError();
|
||||||
assertSame(mh.type(), expType);
|
assertSame(mh.type(), expType);
|
||||||
assertEquals(mh.toString(), fname);
|
assertNameStringContains(mh, fname);
|
||||||
HasFields fields = new HasFields();
|
HasFields fields = new HasFields();
|
||||||
Object sawValue;
|
Object sawValue;
|
||||||
Class<?> vtype = type;
|
Class<?> vtype = type;
|
||||||
@ -959,14 +965,14 @@ public class MethodHandlesTest {
|
|||||||
Object putValue = randomArg(type);
|
Object putValue = randomArg(type);
|
||||||
if (isStatic) {
|
if (isStatic) {
|
||||||
if (type == int.class)
|
if (type == int.class)
|
||||||
mh.<void>invokeExact((int)(Integer)putValue); // do these exactly
|
mh.invokeExact((int)putValue); // do these exactly
|
||||||
else
|
else
|
||||||
mh.<void>invokeExact(putValue);
|
mh.invokeExact(putValue);
|
||||||
} else {
|
} else {
|
||||||
if (type == int.class)
|
if (type == int.class)
|
||||||
mh.<void>invokeExact((Object) fields, (int)(Integer)putValue);
|
mh.invokeExact((Object) fields, (int)putValue);
|
||||||
else
|
else
|
||||||
mh.<void>invokeExact((Object) fields, putValue);
|
mh.invokeExact((Object) fields, putValue);
|
||||||
}
|
}
|
||||||
assertEquals(f.get(fields), putValue);
|
assertEquals(f.get(fields), putValue);
|
||||||
}
|
}
|
||||||
@ -1032,11 +1038,11 @@ public class MethodHandlesTest {
|
|||||||
model.set(i, random);
|
model.set(i, random);
|
||||||
if (testSetter) {
|
if (testSetter) {
|
||||||
if (elemType == int.class)
|
if (elemType == int.class)
|
||||||
mh.<void>invokeExact((int[]) array, i, (int)(Integer)random);
|
mh.invokeExact((int[]) array, i, (int)random);
|
||||||
else if (elemType == boolean.class)
|
else if (elemType == boolean.class)
|
||||||
mh.<void>invokeExact((boolean[]) array, i, (boolean)(Boolean)random);
|
mh.invokeExact((boolean[]) array, i, (boolean)random);
|
||||||
else
|
else
|
||||||
mh.<void>invokeExact(array, i, random);
|
mh.invokeExact(array, i, random);
|
||||||
assertEquals(model, array2list(array));
|
assertEquals(model, array2list(array));
|
||||||
} else {
|
} else {
|
||||||
Array.set(array, i, random);
|
Array.set(array, i, random);
|
||||||
@ -1052,9 +1058,9 @@ public class MethodHandlesTest {
|
|||||||
if (!testSetter) {
|
if (!testSetter) {
|
||||||
expValue = sawValue;
|
expValue = sawValue;
|
||||||
if (elemType == int.class)
|
if (elemType == int.class)
|
||||||
sawValue = mh.<int>invokeExact((int[]) array, i);
|
sawValue = (int) mh.invokeExact((int[]) array, i);
|
||||||
else if (elemType == boolean.class)
|
else if (elemType == boolean.class)
|
||||||
sawValue = mh.<boolean>invokeExact((boolean[]) array, i);
|
sawValue = (boolean) mh.invokeExact((boolean[]) array, i);
|
||||||
else
|
else
|
||||||
sawValue = mh.invokeExact(array, i);
|
sawValue = mh.invokeExact(array, i);
|
||||||
assertEquals(sawValue, expValue);
|
assertEquals(sawValue, expValue);
|
||||||
@ -1102,6 +1108,18 @@ public class MethodHandlesTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MethodHandle typeHandler2(MethodHandle target, MethodType newType) {
|
||||||
|
MethodType oldType = target.type();
|
||||||
|
int oldArity = oldType.parameterCount();
|
||||||
|
int newArity = newType.parameterCount();
|
||||||
|
if (newArity < oldArity)
|
||||||
|
return MethodHandles.insertArguments(target, oldArity, "OPTIONAL");
|
||||||
|
else if (newArity > oldArity)
|
||||||
|
return MethodHandles.dropArguments(target, oldArity-1, newType.parameterType(oldArity-1));
|
||||||
|
else
|
||||||
|
return target; // attempt no further conversions
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConvertArguments() throws Throwable {
|
public void testConvertArguments() throws Throwable {
|
||||||
if (CAN_SKIP_WORKING) return;
|
if (CAN_SKIP_WORKING) return;
|
||||||
@ -1115,10 +1133,29 @@ public class MethodHandlesTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void testConvert(MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
|
void testConvert(MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
|
||||||
testConvert(true, id, rtype, name, params);
|
testConvert(true, false, id, rtype, name, params);
|
||||||
|
testConvert(true, true, id, rtype, name, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testConvert(boolean positive, MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
|
@Test
|
||||||
|
public void testTypeHandler() throws Throwable {
|
||||||
|
MethodHandle id = Callee.ofType(1);
|
||||||
|
MethodHandle th2 = PRIVATE.findStatic(MethodHandlesTest.class, "typeHandler2",
|
||||||
|
MethodType.methodType(MethodHandle.class, MethodHandle.class, MethodType.class));
|
||||||
|
MethodHandle id2 = id.withTypeHandler(th2);
|
||||||
|
testConvert(true, false, id2, null, "id", Object.class);
|
||||||
|
testConvert(true, true, id2, null, "id", Object.class);
|
||||||
|
if (true) return; //FIXME
|
||||||
|
testConvert(true, false, id2, null, "id", String.class); // FIXME: throws WMT
|
||||||
|
testConvert(false, true, id2, null, "id", String.class); // FIXME: should not succeed
|
||||||
|
testConvert(false, false, id2, null, "id", Object.class, String.class); //FIXME: array[1] line 1164
|
||||||
|
testConvert(true, true, id2, null, "id", Object.class, String.class);
|
||||||
|
testConvert(false, false, id2, null, "id");
|
||||||
|
testConvert(true, true, id2, null, "id");
|
||||||
|
}
|
||||||
|
|
||||||
|
void testConvert(boolean positive, boolean useAsType,
|
||||||
|
MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
|
||||||
countTest(positive);
|
countTest(positive);
|
||||||
MethodType idType = id.type();
|
MethodType idType = id.type();
|
||||||
if (rtype == null) rtype = idType.returnType();
|
if (rtype == null) rtype = idType.returnType();
|
||||||
@ -1135,7 +1172,7 @@ public class MethodHandlesTest {
|
|||||||
if (src != dst)
|
if (src != dst)
|
||||||
convArgs[i] = castToWrapper(convArgs[i], dst);
|
convArgs[i] = castToWrapper(convArgs[i], dst);
|
||||||
}
|
}
|
||||||
Object convResult = id.invokeVarargs(convArgs);
|
Object convResult = id.invokeWithArguments(convArgs);
|
||||||
{
|
{
|
||||||
Class<?> dst = newType.returnType();
|
Class<?> dst = newType.returnType();
|
||||||
Class<?> src = idType.returnType();
|
Class<?> src = idType.returnType();
|
||||||
@ -1145,7 +1182,10 @@ public class MethodHandlesTest {
|
|||||||
MethodHandle target = null;
|
MethodHandle target = null;
|
||||||
RuntimeException error = null;
|
RuntimeException error = null;
|
||||||
try {
|
try {
|
||||||
target = MethodHandles.convertArguments(id, newType);
|
if (useAsType)
|
||||||
|
target = MethodHandles.convertArguments(id, newType);
|
||||||
|
else
|
||||||
|
target = id.asType(newType);
|
||||||
} catch (RuntimeException ex) {
|
} catch (RuntimeException ex) {
|
||||||
error = ex;
|
error = ex;
|
||||||
}
|
}
|
||||||
@ -1157,7 +1197,7 @@ public class MethodHandlesTest {
|
|||||||
if (!positive) return; // negative test failed as expected
|
if (!positive) return; // negative test failed as expected
|
||||||
assertEquals(newType, target.type());
|
assertEquals(newType, target.type());
|
||||||
printCalled(target, id.toString(), args);
|
printCalled(target, id.toString(), args);
|
||||||
Object result = target.invokeVarargs(args);
|
Object result = target.invokeWithArguments(args);
|
||||||
assertCalled(name, convArgs);
|
assertCalled(name, convArgs);
|
||||||
assertEquals(convResult, result);
|
assertEquals(convResult, result);
|
||||||
if (verbosity >= 1)
|
if (verbosity >= 1)
|
||||||
@ -1279,7 +1319,7 @@ public class MethodHandlesTest {
|
|||||||
MethodType outType = MethodType.methodType(Object.class, permTypes);
|
MethodType outType = MethodType.methodType(Object.class, permTypes);
|
||||||
MethodHandle target = MethodHandles.convertArguments(ValueConversions.varargsList(outargs), outType);
|
MethodHandle target = MethodHandles.convertArguments(ValueConversions.varargsList(outargs), outType);
|
||||||
MethodHandle newTarget = MethodHandles.permuteArguments(target, inType, reorder);
|
MethodHandle newTarget = MethodHandles.permuteArguments(target, inType, reorder);
|
||||||
Object result = newTarget.invokeVarargs(args);
|
Object result = newTarget.invokeWithArguments(args);
|
||||||
Object expected = Arrays.asList(permArgs);
|
Object expected = Arrays.asList(permArgs);
|
||||||
assertEquals(expected, result);
|
assertEquals(expected, result);
|
||||||
}
|
}
|
||||||
@ -1311,19 +1351,19 @@ public class MethodHandlesTest {
|
|||||||
Object[] args = randomArgs(target2.type().parameterArray());
|
Object[] args = randomArgs(target2.type().parameterArray());
|
||||||
// make sure the target does what we think it does:
|
// make sure the target does what we think it does:
|
||||||
if (pos == 0 && nargs < 5) {
|
if (pos == 0 && nargs < 5) {
|
||||||
Object[] check = (Object[]) target.invokeVarargs(args);
|
Object[] check = (Object[]) target.invokeWithArguments(args);
|
||||||
assertArrayEquals(args, check);
|
assertArrayEquals(args, check);
|
||||||
switch (nargs) {
|
switch (nargs) {
|
||||||
case 0:
|
case 0:
|
||||||
check = target.<Object[]>invokeExact();
|
check = (Object[]) target.invokeExact();
|
||||||
assertArrayEquals(args, check);
|
assertArrayEquals(args, check);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
check = target.<Object[]>invokeExact(args[0]);
|
check = (Object[]) target.invokeExact(args[0]);
|
||||||
assertArrayEquals(args, check);
|
assertArrayEquals(args, check);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
check = target.<Object[]>invokeExact(args[0], args[1]);
|
check = (Object[]) target.invokeExact(args[0], args[1]);
|
||||||
assertArrayEquals(args, check);
|
assertArrayEquals(args, check);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1337,12 +1377,15 @@ public class MethodHandlesTest {
|
|||||||
MethodHandle result = MethodHandles.spreadArguments(target2, newType);
|
MethodHandle result = MethodHandles.spreadArguments(target2, newType);
|
||||||
Object[] returnValue;
|
Object[] returnValue;
|
||||||
if (pos == 0) {
|
if (pos == 0) {
|
||||||
Object rawRetVal = result.invokeExact(args);
|
// In the following line, the first cast implies
|
||||||
returnValue = (Object[]) rawRetVal;
|
// normal Object return value for the MH call (Object[])->Object,
|
||||||
|
// while the second cast dynamically converts to an Object array.
|
||||||
|
// Such a double cast is typical of MH.invokeExact.
|
||||||
|
returnValue = (Object[]) (Object) result.invokeExact(args);
|
||||||
} else {
|
} else {
|
||||||
Object[] args1 = Arrays.copyOfRange(args, 0, pos+1);
|
Object[] args1 = Arrays.copyOfRange(args, 0, pos+1);
|
||||||
args1[pos] = Arrays.copyOfRange(args, pos, args.length);
|
args1[pos] = Arrays.copyOfRange(args, pos, args.length);
|
||||||
returnValue = (Object[]) result.invokeVarargs(args1);
|
returnValue = (Object[]) result.invokeWithArguments(args1);
|
||||||
}
|
}
|
||||||
assertArrayEquals(args, returnValue);
|
assertArrayEquals(args, returnValue);
|
||||||
}
|
}
|
||||||
@ -1379,7 +1422,7 @@ public class MethodHandlesTest {
|
|||||||
if (verbosity >= 3)
|
if (verbosity >= 3)
|
||||||
System.out.println("collect from "+Arrays.asList(args)+" ["+pos+".."+nargs+"]");
|
System.out.println("collect from "+Arrays.asList(args)+" ["+pos+".."+nargs+"]");
|
||||||
MethodHandle result = MethodHandles.collectArguments(target, newType);
|
MethodHandle result = MethodHandles.collectArguments(target, newType);
|
||||||
Object[] returnValue = (Object[]) result.invokeVarargs(args);
|
Object[] returnValue = (Object[]) result.invokeWithArguments(args);
|
||||||
// assertTrue(returnValue.length == pos+1 && returnValue[pos] instanceof Object[]);
|
// assertTrue(returnValue.length == pos+1 && returnValue[pos] instanceof Object[]);
|
||||||
// returnValue[pos] = Arrays.asList((Object[]) returnValue[pos]);
|
// returnValue[pos] = Arrays.asList((Object[]) returnValue[pos]);
|
||||||
// collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]);
|
// collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]);
|
||||||
@ -1412,7 +1455,7 @@ public class MethodHandlesTest {
|
|||||||
MethodHandle target2 = MethodHandles.insertArguments(target, pos,
|
MethodHandle target2 = MethodHandles.insertArguments(target, pos,
|
||||||
(Object[]) argsToInsert.toArray());
|
(Object[]) argsToInsert.toArray());
|
||||||
argsToInsert.clear(); // remove from argsToInsert
|
argsToInsert.clear(); // remove from argsToInsert
|
||||||
Object res2 = target2.invokeVarargs(argsToPass);
|
Object res2 = target2.invokeWithArguments(argsToPass);
|
||||||
Object res2List = Arrays.asList((Object[])res2);
|
Object res2List = Arrays.asList((Object[])res2);
|
||||||
if (verbosity >= 3)
|
if (verbosity >= 3)
|
||||||
System.out.println("result: "+res2List);
|
System.out.println("result: "+res2List);
|
||||||
@ -1440,14 +1483,12 @@ public class MethodHandlesTest {
|
|||||||
Object[] argsToPass = randomArgs(nargs, Object.class);
|
Object[] argsToPass = randomArgs(nargs, Object.class);
|
||||||
if (verbosity >= 3)
|
if (verbosity >= 3)
|
||||||
System.out.println("filter "+target+" at "+pos+" with "+filter);
|
System.out.println("filter "+target+" at "+pos+" with "+filter);
|
||||||
MethodHandle[] filters = new MethodHandle[pos*2+1];
|
MethodHandle target2 = MethodHandles.filterArguments(target, pos, filter);
|
||||||
filters[pos] = filter;
|
|
||||||
MethodHandle target2 = MethodHandles.filterArguments(target, filters);
|
|
||||||
// Simulate expected effect of filter on arglist:
|
// Simulate expected effect of filter on arglist:
|
||||||
Object[] filteredArgs = argsToPass.clone();
|
Object[] filteredArgs = argsToPass.clone();
|
||||||
filteredArgs[pos] = filter.invokeExact(filteredArgs[pos]);
|
filteredArgs[pos] = filter.invokeExact(filteredArgs[pos]);
|
||||||
List<Object> expected = Arrays.asList(filteredArgs);
|
List<Object> expected = Arrays.asList(filteredArgs);
|
||||||
Object result = target2.invokeVarargs(argsToPass);
|
Object result = target2.invokeWithArguments(argsToPass);
|
||||||
if (verbosity >= 3)
|
if (verbosity >= 3)
|
||||||
System.out.println("result: "+result);
|
System.out.println("result: "+result);
|
||||||
if (!expected.equals(result))
|
if (!expected.equals(result))
|
||||||
@ -1472,7 +1513,7 @@ public class MethodHandlesTest {
|
|||||||
if (pos != 0) return; // can fold only at pos=0 for now
|
if (pos != 0) return; // can fold only at pos=0 for now
|
||||||
countTest();
|
countTest();
|
||||||
MethodHandle target = ValueConversions.varargsList(1 + nargs);
|
MethodHandle target = ValueConversions.varargsList(1 + nargs);
|
||||||
MethodHandle combine = ValueConversions.varargsList(fold);
|
MethodHandle combine = ValueConversions.varargsList(fold).asType(MethodType.genericMethodType(fold));
|
||||||
List<Object> argsToPass = Arrays.asList(randomArgs(nargs, Object.class));
|
List<Object> argsToPass = Arrays.asList(randomArgs(nargs, Object.class));
|
||||||
if (verbosity >= 3)
|
if (verbosity >= 3)
|
||||||
System.out.println("fold "+target+" with "+combine);
|
System.out.println("fold "+target+" with "+combine);
|
||||||
@ -1482,9 +1523,9 @@ public class MethodHandlesTest {
|
|||||||
List<Object> argsToFold = expected.subList(pos, pos + fold);
|
List<Object> argsToFold = expected.subList(pos, pos + fold);
|
||||||
if (verbosity >= 3)
|
if (verbosity >= 3)
|
||||||
System.out.println("fold: "+argsToFold+" into "+target2);
|
System.out.println("fold: "+argsToFold+" into "+target2);
|
||||||
Object foldedArgs = combine.invokeVarargs(argsToFold);
|
Object foldedArgs = combine.invokeWithArguments(argsToFold);
|
||||||
argsToFold.add(0, foldedArgs);
|
argsToFold.add(0, foldedArgs);
|
||||||
Object result = target2.invokeVarargs(argsToPass);
|
Object result = target2.invokeWithArguments(argsToPass);
|
||||||
if (verbosity >= 3)
|
if (verbosity >= 3)
|
||||||
System.out.println("result: "+result);
|
System.out.println("result: "+result);
|
||||||
if (!expected.equals(result))
|
if (!expected.equals(result))
|
||||||
@ -1516,7 +1557,7 @@ public class MethodHandlesTest {
|
|||||||
for (int i = drop; i > 0; i--) {
|
for (int i = drop; i > 0; i--) {
|
||||||
argsToDrop.add(pos, "blort#"+i);
|
argsToDrop.add(pos, "blort#"+i);
|
||||||
}
|
}
|
||||||
Object res2 = target2.invokeVarargs(argsToDrop);
|
Object res2 = target2.invokeWithArguments(argsToDrop);
|
||||||
Object res2List = Arrays.asList((Object[])res2);
|
Object res2List = Arrays.asList((Object[])res2);
|
||||||
//if (!resList.equals(res2List))
|
//if (!resList.equals(res2List))
|
||||||
// System.out.println("*** fail at n/p/d = "+nargs+"/"+pos+"/"+drop+": "+argsToDrop+" => "+res2List);
|
// System.out.println("*** fail at n/p/d = "+nargs+"/"+pos+"/"+drop+": "+argsToDrop+" => "+res2List);
|
||||||
@ -1572,7 +1613,7 @@ public class MethodHandlesTest {
|
|||||||
countTest();
|
countTest();
|
||||||
calledLog.clear();
|
calledLog.clear();
|
||||||
inv = MethodHandles.exactInvoker(type);
|
inv = MethodHandles.exactInvoker(type);
|
||||||
result = inv.invokeVarargs(targetPlusArgs);
|
result = inv.invokeWithArguments(targetPlusArgs);
|
||||||
if (testRetCode) assertEquals(code, result);
|
if (testRetCode) assertEquals(code, result);
|
||||||
assertCalled("invokee", args);
|
assertCalled("invokee", args);
|
||||||
// generic invoker
|
// generic invoker
|
||||||
@ -1598,7 +1639,7 @@ public class MethodHandlesTest {
|
|||||||
assertCalled("invokee", args);
|
assertCalled("invokee", args);
|
||||||
}
|
}
|
||||||
calledLog.clear();
|
calledLog.clear();
|
||||||
result = inv.invokeVarargs(targetPlusArgs);
|
result = inv.invokeWithArguments(targetPlusArgs);
|
||||||
if (testRetCode) assertEquals(code, result);
|
if (testRetCode) assertEquals(code, result);
|
||||||
assertCalled("invokee", args);
|
assertCalled("invokee", args);
|
||||||
// varargs invoker #0
|
// varargs invoker #0
|
||||||
@ -1640,17 +1681,29 @@ public class MethodHandlesTest {
|
|||||||
List<Object> tailList = targetPlusVarArgs.subList(1+k, 1+nargs);
|
List<Object> tailList = targetPlusVarArgs.subList(1+k, 1+nargs);
|
||||||
Object[] tail = tailList.toArray();
|
Object[] tail = tailList.toArray();
|
||||||
tailList.clear(); tailList.add(tail);
|
tailList.clear(); tailList.add(tail);
|
||||||
result = inv.invokeVarargs(targetPlusVarArgs);
|
result = inv.invokeWithArguments(targetPlusVarArgs);
|
||||||
if (testRetCode) assertEquals(code, result);
|
if (testRetCode) assertEquals(code, result);
|
||||||
assertCalled("invokee", args);
|
assertCalled("invokee", args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// dynamic invoker
|
// dynamic invoker
|
||||||
countTest();
|
countTest();
|
||||||
CallSite site = new CallSite(MethodHandlesTest.class, "foo", type);
|
CallSite site = new MutableCallSite(type);
|
||||||
inv = MethodHandles.dynamicInvoker(site);
|
inv = site.dynamicInvoker();
|
||||||
|
|
||||||
|
// see if we get the result of the original target:
|
||||||
|
try {
|
||||||
|
result = inv.invokeWithArguments(args);
|
||||||
|
assertTrue("should not reach here", false);
|
||||||
|
} catch (IllegalStateException ex) {
|
||||||
|
String msg = ex.getMessage();
|
||||||
|
assertTrue(msg, msg.contains("site"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// set new target after invoker is created, to make sure we track target
|
||||||
site.setTarget(target);
|
site.setTarget(target);
|
||||||
calledLog.clear();
|
calledLog.clear();
|
||||||
result = inv.invokeVarargs(args);
|
result = inv.invokeWithArguments(args);
|
||||||
if (testRetCode) assertEquals(code, result);
|
if (testRetCode) assertEquals(code, result);
|
||||||
assertCalled("invokee", args);
|
assertCalled("invokee", args);
|
||||||
}
|
}
|
||||||
@ -1734,7 +1787,7 @@ public class MethodHandlesTest {
|
|||||||
String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals");
|
String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals");
|
||||||
if (verbosity >= 3)
|
if (verbosity >= 3)
|
||||||
System.out.println(logEntry(willCall, argList));
|
System.out.println(logEntry(willCall, argList));
|
||||||
Object result = mh.invokeVarargs(argList);
|
Object result = mh.invokeWithArguments(argList);
|
||||||
assertCalled(willCall, argList);
|
assertCalled(willCall, argList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1767,16 +1820,17 @@ public class MethodHandlesTest {
|
|||||||
MethodHandle throwOrReturn
|
MethodHandle throwOrReturn
|
||||||
= PRIVATE.findStatic(MethodHandlesTest.class, "throwOrReturn",
|
= PRIVATE.findStatic(MethodHandlesTest.class, "throwOrReturn",
|
||||||
MethodType.methodType(Object.class, Object.class, Throwable.class));
|
MethodType.methodType(Object.class, Object.class, Throwable.class));
|
||||||
MethodHandle thrower = throwOrReturn;
|
MethodHandle thrower = throwOrReturn.asType(MethodType.genericMethodType(2));
|
||||||
while (thrower.type().parameterCount() < nargs)
|
while (thrower.type().parameterCount() < nargs)
|
||||||
thrower = MethodHandles.dropArguments(thrower, thrower.type().parameterCount(), Object.class);
|
thrower = MethodHandles.dropArguments(thrower, thrower.type().parameterCount(), Object.class);
|
||||||
|
MethodHandle catcher = ValueConversions.varargsList(1+nargs).asType(MethodType.genericMethodType(1+nargs));
|
||||||
MethodHandle target = MethodHandles.catchException(thrower,
|
MethodHandle target = MethodHandles.catchException(thrower,
|
||||||
thrown.getClass(), ValueConversions.varargsList(1+nargs));
|
thrown.getClass(), catcher);
|
||||||
assertEquals(thrower.type(), target.type());
|
assertEquals(thrower.type(), target.type());
|
||||||
//System.out.println("catching with "+target+" : "+throwOrReturn);
|
//System.out.println("catching with "+target+" : "+throwOrReturn);
|
||||||
Object[] args = randomArgs(nargs, Object.class);
|
Object[] args = randomArgs(nargs, Object.class);
|
||||||
args[1] = (throwIt ? thrown : null);
|
args[1] = (throwIt ? thrown : null);
|
||||||
Object returned = target.invokeVarargs(args);
|
Object returned = target.invokeWithArguments(args);
|
||||||
//System.out.println("return from "+target+" : "+returned);
|
//System.out.println("return from "+target+" : "+returned);
|
||||||
if (!throwIt) {
|
if (!throwIt) {
|
||||||
assertSame(args[0], returned);
|
assertSame(args[0], returned);
|
||||||
@ -1828,13 +1882,10 @@ public class MethodHandlesTest {
|
|||||||
testCastFailure("unbox/return", 11000);
|
testCastFailure("unbox/return", 11000);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Surprise implements MethodHandleProvider {
|
static class Surprise {
|
||||||
public MethodHandle asMethodHandle() {
|
public MethodHandle asMethodHandle() {
|
||||||
return VALUE.bindTo(this);
|
return VALUE.bindTo(this);
|
||||||
}
|
}
|
||||||
public MethodHandle asMethodHandle(MethodType type) {
|
|
||||||
return asMethodHandle().asType(type);
|
|
||||||
}
|
|
||||||
Object value(Object x) {
|
Object value(Object x) {
|
||||||
trace("value", x);
|
trace("value", x);
|
||||||
if (boo != null) return boo;
|
if (boo != null) return boo;
|
||||||
@ -1896,8 +1947,8 @@ public class MethodHandlesTest {
|
|||||||
}
|
}
|
||||||
if (callee != null) {
|
if (callee != null) {
|
||||||
callee = MethodHandles.convertArguments(callee, MethodType.genericMethodType(1));
|
callee = MethodHandles.convertArguments(callee, MethodType.genericMethodType(1));
|
||||||
surprise = MethodHandles.filterArguments(callee, surprise);
|
surprise = MethodHandles.filterArguments(callee, 0, surprise);
|
||||||
identity = MethodHandles.filterArguments(callee, identity);
|
identity = MethodHandles.filterArguments(callee, 0, identity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertNotSame(mode, surprise, surprise0);
|
assertNotSame(mode, surprise, surprise0);
|
||||||
@ -1949,7 +2000,7 @@ public class MethodHandlesTest {
|
|||||||
assertEquals(mt, mh.type());
|
assertEquals(mt, mh.type());
|
||||||
assertEquals(Example.class, mh.type().returnType());
|
assertEquals(Example.class, mh.type().returnType());
|
||||||
args = randomArgs(mh.type().parameterArray());
|
args = randomArgs(mh.type().parameterArray());
|
||||||
mh.invokeVarargs(args);
|
mh.invokeWithArguments(args);
|
||||||
assertCalled(name, args);
|
assertCalled(name, args);
|
||||||
|
|
||||||
// Try a virtual method.
|
// Try a virtual method.
|
||||||
@ -1959,7 +2010,7 @@ public class MethodHandlesTest {
|
|||||||
assertEquals(mt, mh.type().dropParameterTypes(0,1));
|
assertEquals(mt, mh.type().dropParameterTypes(0,1));
|
||||||
assertTrue(mh.type().parameterList().contains(Example.class));
|
assertTrue(mh.type().parameterList().contains(Example.class));
|
||||||
args = randomArgs(mh.type().parameterArray());
|
args = randomArgs(mh.type().parameterArray());
|
||||||
mh.invokeVarargs(args);
|
mh.invokeWithArguments(args);
|
||||||
assertCalled(name, args);
|
assertCalled(name, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1861
jdk/test/java/dyn/indify/Indify.java
Normal file
1861
jdk/test/java/dyn/indify/Indify.java
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user