提交 4eb43f64 编写于 作者: J jrose

6914665: update jdk code for JSR 292 (post 6858164)

Summary: Fill in missing API implementations, fix numerous bugs, adjust APIs towards EG design.
Reviewed-by: twisti
上级 6145be84
...@@ -26,6 +26,9 @@ ...@@ -26,6 +26,9 @@
package java.dyn; package java.dyn;
import sun.dyn.util.BytecodeName; import sun.dyn.util.BytecodeName;
import sun.dyn.Access;
import sun.dyn.CallSiteImpl;
import sun.dyn.MethodHandleImpl;
/** /**
* An {@code invokedynamic} call site, as reified by the * An {@code invokedynamic} call site, as reified by the
...@@ -52,15 +55,25 @@ import sun.dyn.util.BytecodeName; ...@@ -52,15 +55,25 @@ import sun.dyn.util.BytecodeName;
* @see Linkage#registerBootstrapMethod(java.lang.Class, java.dyn.MethodHandle) * @see Linkage#registerBootstrapMethod(java.lang.Class, java.dyn.MethodHandle)
* @author John Rose, JSR 292 EG * @author John Rose, JSR 292 EG
*/ */
public class CallSite { public class CallSite
// Note: This is an implementation inheritance hack, and will be removed
// with a JVM change which moves the required hidden state onto this class.
extends CallSiteImpl
{
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.
private Object vmmethod; private Object vmmethod;
int callerMID, callerBCI; // supplied by the JVM int callerMID, callerBCI; // supplied by the JVM
MethodHandle target; private MethodHandle target;
final Object caller; // usually a class final Object caller; // usually a class
final String name; final String name;
final MethodType type; final MethodType type;
*/
/** /**
* Make a call site given the parameters from a call to the bootstrap method. * Make a call site given the parameters from a call to the bootstrap method.
...@@ -72,16 +85,21 @@ public class CallSite { ...@@ -72,16 +85,21 @@ public class CallSite {
* @param type the method handle type derived from descriptor of the {@code invokedynamic} instruction * @param type the method handle type derived from descriptor of the {@code invokedynamic} instruction
*/ */
public CallSite(Object caller, String name, MethodType type) { public CallSite(Object caller, String name, MethodType type) {
this.caller = caller; super(IMPL_TOKEN, caller, name, type);
this.name = name;
this.type = type;
} }
private static void privateInitializeCallSite(CallSite site, int callerMID, int callerBCI) { private static void privateInitializeCallSite(CallSite site, int callerMID, int callerBCI) {
site.callerMID = callerMID; site.callerMID = callerMID;
site.callerBCI = callerBCI; site.callerBCI = callerBCI;
if (site.target == null) site.ensureTarget();
site.setTarget(site.initialTarget()); }
private void ensureTarget() {
// Note use of super, which accesses the field directly,
// without deferring to possible subclass overrides.
if (super.getTarget() == null) {
super.setTarget(this.initialTarget());
super.getTarget().type(); // provoke NPE if still null
}
} }
/** /**
...@@ -102,10 +120,11 @@ public class CallSite { ...@@ -102,10 +120,11 @@ public class CallSite {
/** /**
* Report the current linkage state of the call site. (This is mutable.) * Report the current linkage state of the call site. (This is mutable.)
* The value maybe null only if the call site is currently unlinked. * The value may not be null after the {@code CallSite} object is returned
* When a linked call site is invoked, the target method is used directly. * from the bootstrap method of the {@code invokedynamic} instruction.
* When an unlinked call site is invoked, its bootstrap method receives * When an {@code invokedynamic} instruction is executed, the target method
* the call, as if via {@link Linkage#bootstrapInvokeDynamic}. * of its associated {@code call site} object is invoked directly,
* as if via {@link MethodHandle}{@code .invoke}.
* <p> * <p>
* The interactions of {@code getTarget} with memory are the same * 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
...@@ -118,7 +137,7 @@ public class CallSite { ...@@ -118,7 +137,7 @@ public class CallSite {
* @see #setTarget * @see #setTarget
*/ */
public MethodHandle getTarget() { public MethodHandle getTarget() {
return target; return super.getTarget();
} }
/** /**
...@@ -140,13 +159,13 @@ public class CallSite { ...@@ -140,13 +159,13 @@ public class CallSite {
*/ */
public void setTarget(MethodHandle target) { public void setTarget(MethodHandle target) {
checkTarget(target); checkTarget(target);
this.target = target; super.setTarget(target);
} }
protected void checkTarget(MethodHandle target) { protected void checkTarget(MethodHandle target) {
target.type(); // provoke NPE target.type(); // provoke NPE
if (!canSetTarget(target)) if (!canSetTarget(target))
throw new WrongMethodTypeException(String.valueOf(target)); throw new WrongMethodTypeException(String.valueOf(target)+target.type()+" should be of type "+type());
} }
protected boolean canSetTarget(MethodHandle target) { protected boolean canSetTarget(MethodHandle target) {
...@@ -219,6 +238,10 @@ public class CallSite { ...@@ -219,6 +238,10 @@ public class CallSite {
@Override @Override
public String toString() { public String toString() {
return "CallSite#"+hashCode()+"["+name+type+" => "+target+"]"; return "CallSite#"+hashCode()+"["+name+type+" => "+getTarget()+"]";
} }
// Package-local constant:
static final MethodHandle GET_TARGET = MethodHandleImpl.getLookup(IMPL_TOKEN).
findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
} }
...@@ -45,6 +45,24 @@ package java.dyn; ...@@ -45,6 +45,24 @@ package java.dyn;
* class or interface supertype, or an object type; it can never be instantiated. * class or interface supertype, or an object type; it can never be instantiated.
* Logically, it denotes a source of all dynamically typed methods. * Logically, it denotes a source of all dynamically typed methods.
* It may be viewed as a pure syntactic marker (an importable one) of static calls. * It may be viewed as a pure syntactic marker (an importable one) of static calls.
* <p>
* Here are some examples of usage:
* <p><blockquote><pre>
* Object x; String s; int i;
* x = InvokeDynamic.greet("world"); // greet(Ljava/lang/String;)Ljava/lang/Object;
* s = InvokeDynamic.&lt;String&gt;hail(x); // hail(Ljava/lang/Object;)Ljava/lang/String;
* InvokeDynamic.&lt;void&gt;cogito(); // cogito()V
* i = InvokeDynamic.&lt;int&gt;#"op:+"(2, 3); // "op:+"(II)I
* </pre></blockquote>
* Each of the above calls generates a single invokedynamic instruction
* with the name-and-type descriptors indicated in the comments.
* The argument types are taken directly from the actual arguments,
* while the return type is taken from the type parameter.
* (This type parameter may be a primtive, and it defaults to {@code Object}.)
* 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.
* None of these calls is complete without a bootstrap method,
* which must be registered by the static initializer of the enclosing class.
* @author John Rose, JSR 292 EG * @author John Rose, JSR 292 EG
*/ */
public final class InvokeDynamic { public final class InvokeDynamic {
......
...@@ -52,4 +52,16 @@ public class InvokeDynamicBootstrapError extends LinkageError { ...@@ -52,4 +52,16 @@ public class InvokeDynamicBootstrapError extends LinkageError {
public InvokeDynamicBootstrapError(String s) { public InvokeDynamicBootstrapError(String s) {
super(s); super(s);
} }
/**
* Constructs a {@code InvokeDynamicBootstrapError} with the specified
* detail message and cause.
*
* @param s the detail message.
* @param cause the cause.
*/
public InvokeDynamicBootstrapError(String s, Throwable cause) {
super(s);
this.initCause(cause);
}
} }
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
package java.dyn; package java.dyn;
import sun.dyn.Access;
/** /**
* A Java method handle extends the basic method handle type with additional * A Java method handle extends the basic method handle type with additional
* programmer defined methods and fields. * programmer defined methods and fields.
...@@ -39,31 +41,105 @@ package java.dyn; ...@@ -39,31 +41,105 @@ package java.dyn;
* of the entry point method handle, with the leading parameter type * of the entry point method handle, with the leading parameter type
* omitted. * omitted.
* <p> * <p>
* Here is an example of usage: * 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.&lt;void&gt;invoke(); // also prints "hello, world"
* // Dynamically typed method handle invocation:
* MethodHandles.invoke(greeter); // also prints "hello, world"
* greeter.setGreeting("howdy");
* mh.invoke(); // 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> * <p><blockquote><pre>
* class Greeter extends JavaMethodHandle { * // We can also do this with symbolic names and/or inner classes:
* MethodHandles.invoke(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); } * public void run() { System.out.println("hello, "+greetee); }
* private final String greetee; * private final String greetee;
* Greeter(String greetee) { * Greeter(String greetee) { this.greetee = greetee; }
* super(RUN);
* this.greetee = greetee;
* }
* // the entry point function is computed once: * // the entry point function is computed once:
* private static final MethodHandle RUN * private static final MethodHandle RUN
* = MethodHandles.findVirtual(MyMethodHandle.class, "run", * = MethodHandles.findVirtual(Greeter.class, "run",
* MethodType.make(void.class)); * MethodType.make(void.class));
* } * }
* // class Main { public static void main(String... av) { ...
* Greeter greeter = new Greeter("world"); * Greeter greeter = new Greeter("world");
* greeter.run(); // prints "hello, world" * greeter.run(); // prints "hello, world"
* MethodHandle mh = greeter; * MethodHandle mh = MethodHanndles.insertArgument(Greeter.RUN, 0, greeter);
* mh.invoke(); // also prints "hello, world" * mh.invoke(); // also prints "hello, world"
* </pre></blockquote> * </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> * <p>
* In this example, the method {@code run} provides the entry point. * Here is a pure functional value expressed most concisely as an anonymous inner class:
* The entry point need not be a constant value; it may be independently * <p><blockquote><pre>
* computed in each call to the constructor. The entry point does not * // class Main { public static void main(String... av) { ...
* even need to be a method on the Java method handle class, though * final String greetee = "world";
* that is the typical case. * MethodHandle greeter = new JavaMethodHandle("run") {
* private void run() { System.out.println("hello, "+greetee); }
* }
* greeter.invoke(); // 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.&lt;Number&gt;invoke(1L); // 456
* stuffPtr.setter().&lt;void&gt;invoke(0L, (Number) 789); // replaces 123 with 789
* </pre></blockquote>
* @see MethodHandle * @see MethodHandle
* @author John Rose, JSR 292 EG * @author John Rose, JSR 292 EG
*/ */
...@@ -72,12 +148,87 @@ public abstract class JavaMethodHandle ...@@ -72,12 +148,87 @@ public abstract class JavaMethodHandle
// with a JVM change which moves the required hidden behavior onto this class. // with a JVM change which moves the required hidden behavior onto this class.
extends sun.dyn.BoundMethodHandle extends sun.dyn.BoundMethodHandle
{ {
private static final Access IMPL_TOKEN = Access.getToken();
/** /**
* When creating a, pass in {@code entryPoint}, any method handle which * When creating a {@code JavaMethodHandle}, the actual method handle
* can take the current object * invocation behavior will be delegated to the specified {@code entryPoint}.
* @param 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) { protected JavaMethodHandle(MethodHandle entryPoint) {
super(entryPoint, 0); super(entryPoint);
}
/**
* Create a method handle whose entry point is a non-static method
* visible in the exact (most specific) class of
* the newly constructed object.
* <p>
* The method is specified by name and type, as if via this expression:
* {@code MethodHandles.lookup().findVirtual(this.getClass(), name, type)}.
* The class defining the method might be an anonymous inner class.
* <p>
* The method handle type of {@code this} (i.e, the fully constructed object)
* will be the given method handle type.
* A call to {@code this} will invoke the selected method.
* The receiver argument will be bound to {@code this} on every method
* handle invocation.
* <p>
* <i>Rationale:</i>
* Although this constructor may seem to be a mere luxury,
* it is not subsumed by the more general constructor which
* takes any {@code MethodHandle} as the entry point argument.
* In order to convert an entry point name to a method handle,
* the self-class of the object is required (in order to do
* the lookup). The self-class, in turn, is generally not
* available at the time of the constructor invocation,
* due to the rules of Java and the JVM verifier.
* One cannot call {@code this.getClass()}, because
* the value of {@code this} is inaccessible at the point
* of the constructor call. (Changing this would require
* change to the Java language, verifiers, and compilers.)
* In particular, this constructor allows {@code JavaMethodHandle}s
* to be created in combination with the anonymous inner class syntax.
* @param entryPointName the name of the entry point method
* @param type (optional) the desired type of the method handle
*/
protected JavaMethodHandle(String entryPointName, MethodType type) {
super(entryPointName, type, true);
}
/**
* Create a method handle whose entry point is a non-static method
* visible in the exact (most specific) class of
* the newly constructed object.
* <p>
* The method is specified only by name.
* There must be exactly one method of that name visible in the object class,
* either inherited or locally declared.
* (That is, the method must not be overloaded.)
* <p>
* The method handle type of {@code this} (i.e, the fully constructed object)
* will be the same as the type of the selected non-static method.
* The receiver argument will be bound to {@code this} on every method
* handle invocation.
* <p>ISSUE: This signature wildcarding feature does not correspond to
* any MethodHandles.Lookup API element. Can we eliminate it?
* Alternatively, it is useful for naming non-overloaded methods.
* Shall we make type arguments optional in the Lookup methods,
* throwing an error in cases of ambiguity?
* <p>
* For this method's rationale, see the documentation
* for {@link #JavaMethodHandle(String,MethodType)}.
* @param entryPointName the name of the entry point method
*/
protected JavaMethodHandle(String entryPointName) {
super(entryPointName, (MethodType) null, false);
} }
} }
...@@ -25,7 +25,9 @@ ...@@ -25,7 +25,9 @@
package java.dyn; package java.dyn;
import java.dyn.MethodHandles.Lookup;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import sun.dyn.Access;
import sun.reflect.Reflection; import sun.reflect.Reflection;
import static sun.dyn.util.VerifyAccess.checkBootstrapPrivilege; import static sun.dyn.util.VerifyAccess.checkBootstrapPrivilege;
...@@ -34,6 +36,8 @@ import static sun.dyn.util.VerifyAccess.checkBootstrapPrivilege; ...@@ -34,6 +36,8 @@ import static sun.dyn.util.VerifyAccess.checkBootstrapPrivilege;
* @author John Rose, JSR 292 EG * @author John Rose, JSR 292 EG
*/ */
public class Linkage { public class Linkage {
private static final Access IMPL_TOKEN = Access.getToken();
private Linkage() {} // do not instantiate private Linkage() {} // do not instantiate
/** /**
...@@ -53,19 +57,23 @@ public class Linkage { ...@@ -53,19 +57,23 @@ public class Linkage {
* call to this method. * call to this method.
* <li>The given class is already fully initialized. * <li>The given class is already fully initialized.
* <li>The given class is in the process of initialization, in another thread. * <li>The given class is in the process of initialization, in another thread.
* <li>The same {@code CallSite} object has already been returned from
* a bootstrap method call to another {@code invokedynamic} call site.
* </ul> * </ul>
* Because of these rules, a class may install its own bootstrap method in * Because of these rules, a class may install its own bootstrap method in
* a static initializer. * a static initializer.
* @param callerClass a class that may have {@code invokedynamic} sites
* @param bootstrapMethod the method to use to bootstrap all such sites
*/ */
public static public static
void registerBootstrapMethod(Class callerClass, MethodHandle mh) { void registerBootstrapMethod(Class callerClass, MethodHandle bootstrapMethod) {
Class callc = Reflection.getCallerClass(2); Class callc = Reflection.getCallerClass(2);
checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod"); checkBootstrapPrivilege(callc, callerClass, "registerBootstrapMethod");
checkBSM(mh); checkBSM(bootstrapMethod);
synchronized (bootstrapMethods) { synchronized (bootstrapMethods) {
if (bootstrapMethods.containsKey(callerClass)) if (bootstrapMethods.containsKey(callerClass))
throw new IllegalStateException("bootstrap method already declared in "+callerClass); throw new IllegalStateException("bootstrap method already declared in "+callerClass);
bootstrapMethods.put(callerClass, mh); bootstrapMethods.put(callerClass, bootstrapMethod);
} }
} }
...@@ -88,8 +96,9 @@ public class Linkage { ...@@ -88,8 +96,9 @@ public class Linkage {
public static public static
void registerBootstrapMethod(Class<?> runtime, String name) { void registerBootstrapMethod(Class<?> runtime, String name) {
Class callc = Reflection.getCallerClass(2); Class callc = Reflection.getCallerClass(2);
Lookup lookup = new Lookup(IMPL_TOKEN, callc);
MethodHandle bootstrapMethod = MethodHandle bootstrapMethod =
MethodHandles.findStaticFrom(callc, runtime, name, BOOTSTRAP_METHOD_TYPE); lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE);
// FIXME: exception processing wrong here // FIXME: exception processing wrong here
checkBSM(bootstrapMethod); checkBSM(bootstrapMethod);
Linkage.registerBootstrapMethod(callc, bootstrapMethod); Linkage.registerBootstrapMethod(callc, bootstrapMethod);
...@@ -106,8 +115,9 @@ public class Linkage { ...@@ -106,8 +115,9 @@ public class Linkage {
public static public static
void registerBootstrapMethod(String name) { void registerBootstrapMethod(String name) {
Class callc = Reflection.getCallerClass(2); Class callc = Reflection.getCallerClass(2);
Lookup lookup = new Lookup(IMPL_TOKEN, callc);
MethodHandle bootstrapMethod = MethodHandle bootstrapMethod =
MethodHandles.findStaticFrom(callc, callc, name, BOOTSTRAP_METHOD_TYPE); lookup.findStatic(callc, name, BOOTSTRAP_METHOD_TYPE);
// FIXME: exception processing wrong here // FIXME: exception processing wrong here
checkBSM(bootstrapMethod); checkBSM(bootstrapMethod);
Linkage.registerBootstrapMethod(callc, bootstrapMethod); Linkage.registerBootstrapMethod(callc, bootstrapMethod);
...@@ -116,8 +126,7 @@ public class Linkage { ...@@ -116,8 +126,7 @@ public class Linkage {
/** /**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em> * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Report the bootstrap method registered for a given class. * Report the bootstrap method registered for a given class.
* Returns null if the class has never yet registered a bootstrap method, * Returns null if the class has never yet registered a bootstrap method.
* or if the class has explicitly registered a null bootstrap method.
* Only callers privileged to set the bootstrap method may inquire * Only callers privileged to set the bootstrap method may inquire
* about it, because a bootstrap method is potentially a back-door entry * about it, because a bootstrap method is potentially a back-door entry
* point into its class. * point into its class.
...@@ -137,12 +146,12 @@ public class Linkage { ...@@ -137,12 +146,12 @@ public class Linkage {
* {@code (Class, String, MethodType)} returning a {@code CallSite}. * {@code (Class, String, MethodType)} returning a {@code CallSite}.
*/ */
public static final MethodType BOOTSTRAP_METHOD_TYPE public static final MethodType BOOTSTRAP_METHOD_TYPE
= MethodType.make(CallSite.class, = MethodType.methodType(CallSite.class,
Class.class, String.class, MethodType.class); Class.class, String.class, MethodType.class);
private static final MethodType OLD_BOOTSTRAP_METHOD_TYPE private static final MethodType OLD_BOOTSTRAP_METHOD_TYPE
= MethodType.make(Object.class, = MethodType.methodType(Object.class,
CallSite.class, Object[].class); CallSite.class, Object[].class);
private static final WeakHashMap<Class, MethodHandle> bootstrapMethods = private static final WeakHashMap<Class, MethodHandle> bootstrapMethods =
new WeakHashMap<Class, MethodHandle>(); new WeakHashMap<Class, MethodHandle>();
...@@ -173,8 +182,8 @@ public class Linkage { ...@@ -173,8 +182,8 @@ public class Linkage {
/** /**
* <em>PROVISIONAL API, WORK IN PROGRESS:</em> * <em>PROVISIONAL API, WORK IN PROGRESS:</em>
* Invalidate all <code>invokedynamic</code> call sites associated * Invalidate all <code>invokedynamic</code> call sites in the bytecodes
* with the given class. * of any methods of the given class.
* (These are exactly those sites which report the given class * (These are exactly those sites which report the given class
* via the {@link CallSite#callerClass()} method.) * via the {@link CallSite#callerClass()} method.)
* <p> * <p>
......
...@@ -88,7 +88,7 @@ public final class LinkagePermission extends BasicPermission { ...@@ -88,7 +88,7 @@ public final class LinkagePermission extends BasicPermission {
/** /**
* Create a new LinkagePermission with the given name. * Create a new LinkagePermission with the given name.
* The name is the symbolic name of the LinkagePermission, such as * The name is the symbolic name of the LinkagePermission, such as
* "registerBootstrapMethod", "invalidateClass.*", etc. An asterisk * "registerBootstrapMethod", "invalidateCallerClass.*", etc. An asterisk
* may appear at the end of the name, following a ".", or by itself, to * may appear at the end of the name, following a ".", or by itself, to
* signify a wildcard match. * signify a wildcard match.
* *
......
...@@ -32,7 +32,7 @@ import java.util.List; ...@@ -32,7 +32,7 @@ import java.util.List;
import sun.dyn.Access; import sun.dyn.Access;
import sun.dyn.Invokers; import sun.dyn.Invokers;
import sun.dyn.MethodTypeImpl; import sun.dyn.MethodTypeImpl;
import sun.dyn.util.BytecodeSignature; import sun.dyn.util.BytecodeDescriptor;
import static sun.dyn.MemberName.newIllegalArgumentException; import static sun.dyn.MemberName.newIllegalArgumentException;
/** /**
...@@ -63,7 +63,7 @@ class MethodType { ...@@ -63,7 +63,7 @@ class MethodType {
static { static {
// This hack allows the implementation package special access to // This hack allows the implementation package special access to
// the internals of MethodType. In particular, the Form has all sorts // the internals of MethodType. In particular, the MTImpl has all sorts
// of cached information useful to the implementation code. // of cached information useful to the implementation code.
MethodTypeImpl.setMethodTypeFriend(IMPL_TOKEN, new MethodTypeImpl.MethodTypeFriend() { MethodTypeImpl.setMethodTypeFriend(IMPL_TOKEN, new MethodTypeImpl.MethodTypeFriend() {
public Class<?>[] ptypes(MethodType mt) { return mt.ptypes; } public Class<?>[] ptypes(MethodType mt) { return mt.ptypes; }
...@@ -114,51 +114,76 @@ class MethodType { ...@@ -114,51 +114,76 @@ class MethodType {
* @throws IllegalArgumentException if any of the ptypes is void * @throws IllegalArgumentException if any of the ptypes is void
*/ */
public static public static
MethodType make(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 #make(java.lang.Class, java.lang.Class[])}. */ /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}. */
public static public static
MethodType methodType(Class<?> rtype, List<? extends Class<?>> ptypes) {
boolean notrust = false; // random List impl. could return evil ptypes array
return makeImpl(rtype, ptypes.toArray(NO_PTYPES), notrust);
}
@Deprecated public static
MethodType make(Class<?> rtype, List<? extends Class<?>> ptypes) { MethodType make(Class<?> rtype, List<? extends Class<?>> ptypes) {
return makeImpl(rtype, ptypes.toArray(NO_PTYPES), true); return methodType(rtype, ptypes);
} }
/** Convenience method for {@link #make(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.
*/ */
public static public static
MethodType make(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) { MethodType methodType(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
Class<?>[] ptypes1 = new Class<?>[1+ptypes.length]; Class<?>[] ptypes1 = new Class<?>[1+ptypes.length];
ptypes1[0] = ptype0; ptypes1[0] = ptype0;
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 #make(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.
*/ */
public static public static
MethodType make(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 #make(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.
*/ */
public static public static
MethodType make(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 #make(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},
* and the specified return type. * and the specified return type.
*/ */
public static public static
MethodType make(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.
...@@ -202,15 +227,16 @@ class MethodType { ...@@ -202,15 +227,16 @@ class MethodType {
private static final MethodType[] objectOnlyTypes = new MethodType[20]; private static final MethodType[] objectOnlyTypes = new MethodType[20];
/** /**
* Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}. * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* All parameters and the return type will be Object, except the final varargs parameter if any. * All parameters and the return type will be {@code Object},
* except the final varargs parameter if any, which will be {@code Object[]}.
* @param objectArgCount number of parameters (excluding the varargs parameter if any) * @param objectArgCount number of parameters (excluding the varargs parameter if any)
* @param varargs whether there will be a varargs parameter, of type Object[] * @param varargs whether there will be a varargs parameter, of type {@code Object[]}
* @return a totally generic method type, given only its count of parameters and varargs * @return a totally generic method type, given only its count of parameters and varargs
* @see #makeGeneric(int) * @see #genericMethodType(int)
*/ */
public static public static
MethodType makeGeneric(int objectArgCount, boolean varargs) { MethodType genericMethodType(int objectArgCount, boolean varargs) {
MethodType mt; MethodType mt;
int ivarargs = (!varargs ? 0 : 1); int ivarargs = (!varargs ? 0 : 1);
int ootIndex = objectArgCount*2 + ivarargs; int ootIndex = objectArgCount*2 + ivarargs;
...@@ -227,19 +253,27 @@ class MethodType { ...@@ -227,19 +253,27 @@ class MethodType {
} }
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.
* @param objectArgCount number of parameters * @param objectArgCount number of parameters
* @return a totally generic method type, given only its count of parameters * @return a totally generic method type, given only its count of parameters
* @see #makeGeneric(int, boolean) * @see #genericMethodType(int, boolean)
*/ */
public static public static
MethodType genericMethodType(int objectArgCount) {
return genericMethodType(objectArgCount, false);
}
@Deprecated public static
MethodType makeGeneric(int objectArgCount) { MethodType makeGeneric(int objectArgCount) {
return makeGeneric(objectArgCount, false); return genericMethodType(objectArgCount);
} }
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}. /** 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
* @param nptype a new parameter type to replace the old one with * @param nptype a new parameter type to replace the old one with
* @return the same type, except with the selected parameter changed * @return the same type, except with the selected parameter changed
...@@ -251,11 +285,10 @@ class MethodType { ...@@ -251,11 +285,10 @@ class MethodType {
return makeImpl(rtype, nptypes, true); return makeImpl(rtype, nptypes, true);
} }
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}. /** Convenience method for {@link #insertParameterTypes}.
* @param num the position (zero-based) of the inserted parameter type * @deprecated Use {@link #insertParameterTypes} instead.
* @param nptype a new parameter type to insert into the parameter list
* @return the same type, except with the selected parameter inserted
*/ */
@Deprecated
public MethodType insertParameterType(int num, Class<?> nptype) { public MethodType insertParameterType(int num, Class<?> nptype) {
int len = ptypes.length; int len = ptypes.length;
Class<?>[] nptypes = Arrays.copyOfRange(ptypes, 0, len+1); Class<?>[] nptypes = Arrays.copyOfRange(ptypes, 0, len+1);
...@@ -264,23 +297,73 @@ class MethodType { ...@@ -264,23 +297,73 @@ class MethodType {
return makeImpl(rtype, nptypes, true); return makeImpl(rtype, nptypes, true);
} }
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}. /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param num the index (zero-based) of the parameter type to remove * @param num the position (zero-based) of the inserted parameter type(s)
* @return the same type, except with the selected parameter removed * @param ptypesToInsert zero or more a new parameter types to insert into the parameter list
* @return the same type, except with the selected parameter(s) inserted
*/ */
public MethodType dropParameterType(int num) { public MethodType insertParameterTypes(int num, Class<?>... ptypesToInsert) {
int len = ptypes.length;
if (num < 0 || num > len)
throw newIllegalArgumentException("num="+num); //SPECME
int ilen = ptypesToInsert.length;
if (ilen == 0) return this;
Class<?>[] nptypes = Arrays.copyOfRange(ptypes, 0, len+ilen);
System.arraycopy(nptypes, num, nptypes, num+ilen, len-num);
System.arraycopy(ptypesToInsert, 0, nptypes, num, ilen);
return makeImpl(rtype, nptypes, true);
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @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
* @return the same type, except with the selected parameter(s) inserted
*/
public MethodType insertParameterTypes(int num, List<Class<?>> ptypesToInsert) {
return insertParameterTypes(num, ptypesToInsert.toArray(NO_PTYPES));
}
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* @param start the index (zero-based) of the first parameter type to remove
* @param end the index (greater than {@code start}) of the first parameter type after not to remove
* @return the same type, except with the selected parameter(s) removed
*/
public MethodType dropParameterTypes(int start, int end) {
int len = ptypes.length; int len = ptypes.length;
if (!(0 <= start && start <= end && end <= len))
throw newIllegalArgumentException("start="+start+" end="+end); //SPECME
if (start == end) return this;
Class<?>[] nptypes; Class<?>[] nptypes;
if (num == 0) { if (start == 0) {
nptypes = Arrays.copyOfRange(ptypes, 1, len); if (end == len) {
// drop all parameters
nptypes = NO_PTYPES;
} else {
// drop initial parameter(s)
nptypes = Arrays.copyOfRange(ptypes, end, len);
}
} else { } else {
nptypes = Arrays.copyOfRange(ptypes, 0, len-1); if (end == len) {
System.arraycopy(ptypes, num+1, nptypes, num, (len-1)-num); // drop trailing parameter(s)
nptypes = Arrays.copyOfRange(ptypes, 0, start);
} else {
int tail = len - end;
nptypes = Arrays.copyOfRange(ptypes, 0, start + tail);
System.arraycopy(ptypes, end, nptypes, start, tail);
}
} }
return makeImpl(rtype, nptypes, true); return makeImpl(rtype, nptypes, true);
} }
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[], boolean)}. /** 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[])}.
* @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
*/ */
...@@ -291,6 +374,7 @@ class MethodType { ...@@ -291,6 +374,7 @@ class MethodType {
/** Convenience method. /** Convenience method.
* Report if this type contains a primitive argument or return value. * Report if this type contains a primitive argument or return value.
* The return type {@code void} counts as a primitive.
* @return true if any of the types are primitives * @return true if any of the types are primitives
*/ */
public boolean hasPrimitives() { public boolean hasPrimitives() {
...@@ -300,39 +384,47 @@ class MethodType { ...@@ -300,39 +384,47 @@ class MethodType {
/** Convenience method. /** Convenience method.
* Report if this type contains a wrapper argument or return value. * Report if this type contains a wrapper argument or return value.
* Wrappers are types which box primitive values, such as {@link Integer}. * Wrappers are types which box primitive values, such as {@link Integer}.
* The reference type {@code java.lang.Void} counts as a wrapper.
* @return true if any of the types are wrappers * @return true if any of the types are wrappers
*/ */
public boolean hasWrappers() { public boolean hasWrappers() {
return unwrap() != this; return unwrap() != this;
} }
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* Erase all reference types to Object. * Erase all reference types to {@code Object}.
* All primitive types (including {@code void}) will remain unchanged.
* @return a version of the original type with all reference types replaced * @return a version of the original type with all reference types replaced
*/ */
public MethodType erase() { public MethodType erase() {
return form.erasedType(); return form.erasedType();
} }
/** Convenience method for {@link #makeGeneric(int)}. /** Convenience method for {@link #genericMethodType(int)}.
* Convert all types, both reference and primitive, to Object. * Convert all types, both reference and primitive, to {@code Object}.
* The expression {@code type.wrap().erase()} produces the same value
* as {@code type.generic()}.
* @return a version of the original type with all types replaced * @return a version of the original type with all types replaced
*/ */
public MethodType generic() { public MethodType generic() {
return makeGeneric(parameterCount()); return genericMethodType(parameterCount());
} }
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* Convert all primitive types to their corresponding wrapper types. * Convert all primitive types to their corresponding wrapper types.
* All reference types (including wrapper types) will remain unchanged.
* A {@code void} return type is changed to the type {@code java.lang.Void}. * A {@code void} return type is changed to the type {@code java.lang.Void}.
* The expression {@code type.wrap().erase()} produces the same value
* as {@code type.generic()}.
* @return a version of the original type with all primitive types replaced * @return a version of the original type with all primitive types replaced
*/ */
public MethodType wrap() { public MethodType wrap() {
return hasPrimitives() ? wrapWithPrims(this) : this; return hasPrimitives() ? wrapWithPrims(this) : this;
} }
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* Convert all wrapper types to their corresponding primitive types. * Convert all wrapper types to their corresponding primitive types.
* All primitive types (including {@code void}) will remain unchanged.
* A return type of {@code java.lang.Void} is changed to {@code void}. * A return type of {@code java.lang.Void} is changed to {@code void}.
* @return a version of the original type with all wrapper types replaced * @return a version of the original type with all wrapper types replaced
*/ */
...@@ -391,6 +483,7 @@ class MethodType { ...@@ -391,6 +483,7 @@ class MethodType {
/** /**
* Convenience method to present the arguments as an array. * Convenience method to present the arguments as an array.
* Changes to the array will not result in changes to the type.
* @return the parameter types (as a fresh copy if necessary) * @return the parameter types (as a fresh copy if necessary)
*/ */
public Class<?>[] parameterArray() { public Class<?>[] parameterArray() {
...@@ -491,7 +584,7 @@ class MethodType { ...@@ -491,7 +584,7 @@ class MethodType {
return form.parameterSlotCount(); return form.parameterSlotCount();
} }
/** Number of JVM stack slots which carry all parameters after /** Number of JVM stack slots which carry all parameters including and after
* the given position, which must be in the range of 0 to * the given position, which must be in the range of 0 to
* {@code parameterCount} inclusive. Successive parameters are * {@code parameterCount} inclusive. Successive parameters are
* more shallowly stacked, and parameters are indexed in the bytecodes * more shallowly stacked, and parameters are indexed in the bytecodes
...@@ -532,7 +625,7 @@ class MethodType { ...@@ -532,7 +625,7 @@ class MethodType {
return form.returnSlotCount(); return form.returnSlotCount();
} }
/** Convenience method for {@link #make(java.lang.Class, java.lang.Class[])}. /** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* Find or create an instance (interned) of the given method type. * Find or create an instance (interned) of the given method type.
* Any class or interface name embedded in the signature string * Any class or interface name embedded in the signature string
* will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)} * will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)}
...@@ -544,16 +637,16 @@ class MethodType { ...@@ -544,16 +637,16 @@ class MethodType {
* <p> * <p>
* This method is included for the benfit of applications that must * This method is included for the benfit of applications that must
* generate bytecodes that process method handles and invokedynamic. * generate bytecodes that process method handles and invokedynamic.
* @param bytecodeSignature a bytecode-level signature string "(T...)T" * @param descriptor a bytecode-level signature string "(T...)T"
* @param loader the class loader in which to look up the types * @param loader the class loader in which to look up the types
* @return a method type matching the bytecode-level signature * @return a method type matching the bytecode-level signature
* @throws IllegalArgumentException if the string is not well-formed * @throws IllegalArgumentException if the string is not well-formed
* @throws TypeNotPresentException if a named type cannot be found * @throws TypeNotPresentException if a named type cannot be found
*/ */
public static MethodType fromBytecodeString(String bytecodeSignature, ClassLoader loader) public static MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader)
throws IllegalArgumentException, TypeNotPresentException throws IllegalArgumentException, TypeNotPresentException
{ {
List<Class<?>> types = BytecodeSignature.parseMethod(bytecodeSignature, loader); List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader);
Class<?> rtype = types.remove(types.size() - 1); Class<?> rtype = types.remove(types.size() - 1);
Class<?>[] ptypes = types.toArray(NO_PTYPES); Class<?>[] ptypes = types.toArray(NO_PTYPES);
return makeImpl(rtype, ptypes, true); return makeImpl(rtype, ptypes, true);
...@@ -565,11 +658,21 @@ class MethodType { ...@@ -565,11 +658,21 @@ class MethodType {
* <p> * <p>
* This method is included for the benfit of applications that must * This method is included for the benfit of applications that must
* generate bytecodes that process method handles and invokedynamic. * generate bytecodes that process method handles and invokedynamic.
* {@link #fromBytecodeString(java.lang.String, java.lang.ClassLoader)}, * {@link #fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader)},
* because the latter requires a suitable class loader argument. * because the latter requires a suitable class loader argument.
* @return the bytecode signature representation * @return the bytecode signature representation
*/ */
public String toMethodDescriptorString() {
return BytecodeDescriptor.unparse(this);
}
/** Temporary alias for toMethodDescriptorString; delete after M3. */
public String toBytecodeString() { public String toBytecodeString() {
return BytecodeSignature.unparse(this); return toMethodDescriptorString();
}
/** Temporary alias for fromMethodDescriptorString; delete after M3. */
public static MethodType fromBytecodeString(String descriptor, ClassLoader loader)
throws IllegalArgumentException, TypeNotPresentException {
return fromMethodDescriptorString(descriptor, loader);
} }
} }
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
*/ */
/** /**
* <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.
* @author John Rose, JSR 292 EG * @author John Rose, JSR 292 EG
......
...@@ -28,6 +28,10 @@ package sun.dyn; ...@@ -28,6 +28,10 @@ package sun.dyn;
import sun.dyn.util.VerifyType; import sun.dyn.util.VerifyType;
import sun.dyn.util.Wrapper; import sun.dyn.util.Wrapper;
import java.dyn.*; import java.dyn.*;
import java.util.List;
import sun.dyn.MethodHandleNatives.Constants;
import static sun.dyn.MethodHandleImpl.IMPL_LOOKUP;
import static sun.dyn.MemberName.newIllegalArgumentException;
/** /**
* The flavor of method handle which emulates an invoke instruction * The flavor of method handle which emulates an invoke instruction
...@@ -35,18 +39,23 @@ import java.dyn.*; ...@@ -35,18 +39,23 @@ import java.dyn.*;
* when the handle is created, not when it is invoked. * when the handle is created, not when it is invoked.
* @author jrose * @author jrose
*/ */
public class BoundMethodHandle extends MethodHandle { public class BoundMethodHandle extends MethodHandle {
//MethodHandle vmtarget; // next BMH or final DMH or methodOop //MethodHandle vmtarget; // next BMH or final DMH or methodOop
private final Object argument; // argument to insert private final Object argument; // argument to insert
private final int vmargslot; // position at which it is inserted private final int vmargslot; // position at which it is inserted
private static final Access IMPL_TOKEN = Access.getToken();
private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(IMPL_TOKEN);
// Constructors in this class *must* be package scoped or private. // Constructors in this class *must* be package scoped or private.
// Exception: JavaMethodHandle constructors are protected.
// (The link between JMH and BMH is temporary.)
/** Bind a direct MH to its receiver (or first ref. argument). /** Bind a direct MH to its receiver (or first ref. argument).
* The JVM will pre-dispatch the MH if it is not already static. * The JVM will pre-dispatch the MH if it is not already static.
*/ */
BoundMethodHandle(DirectMethodHandle mh, Object argument) { BoundMethodHandle(DirectMethodHandle mh, Object argument) {
super(Access.TOKEN, mh.type().dropParameterType(0)); super(Access.TOKEN, mh.type().dropParameterTypes(0, 1));
// check the type now, once for all: // check the type now, once for all:
this.argument = checkReferenceArgument(argument, mh, 0); this.argument = checkReferenceArgument(argument, mh, 0);
this.vmargslot = this.type().parameterSlotCount(); this.vmargslot = this.type().parameterSlotCount();
...@@ -56,32 +65,34 @@ public class BoundMethodHandle extends MethodHandle { ...@@ -56,32 +65,34 @@ public class BoundMethodHandle extends MethodHandle {
} else { } else {
this.vmtarget = mh; this.vmtarget = mh;
} }
} }
private static final int REF_ARG = 0, PRIM_ARG = 1, SELF_ARG = 2;
/** Insert an argument into an arbitrary method handle. /** Insert an argument into an arbitrary method handle.
* If argnum is zero, inserts the first argument, etc. * If argnum is zero, inserts the first argument, etc.
* The argument type must be a reference. * The argument type must be a reference.
*/ */
BoundMethodHandle(MethodHandle mh, Object argument, int argnum) { BoundMethodHandle(MethodHandle mh, Object argument, int argnum) {
this(mh, argument, argnum, mh.type().parameterType(argnum).isPrimitive() ? PRIM_ARG : REF_ARG); this(mh.type().dropParameterTypes(argnum, argnum+1),
mh, argument, argnum);
} }
/** Insert an argument into an arbitrary method handle. /** Insert an argument into an arbitrary method handle.
* If argnum is zero, inserts the first argument, etc. * If argnum is zero, inserts the first argument, etc.
*/ */
BoundMethodHandle(MethodHandle mh, Object argument, int argnum, int whichArg) { BoundMethodHandle(MethodType type, MethodHandle mh, Object argument, int argnum) {
super(Access.TOKEN, mh.type().dropParameterType(argnum)); super(Access.TOKEN, type);
if (whichArg == PRIM_ARG) if (mh.type().parameterType(argnum).isPrimitive())
this.argument = bindPrimitiveArgument(argument, mh, argnum); this.argument = bindPrimitiveArgument(argument, mh, argnum);
else { else {
if (whichArg == SELF_ARG) argument = this;
this.argument = checkReferenceArgument(argument, mh, argnum); this.argument = checkReferenceArgument(argument, mh, argnum);
} }
this.vmargslot = this.type().parameterSlotDepth(argnum); this.vmargslot = type.parameterSlotDepth(argnum);
initTarget(mh, argnum);
}
private void initTarget(MethodHandle mh, int argnum) {
if (MethodHandleNatives.JVM_SUPPORT) { if (MethodHandleNatives.JVM_SUPPORT) {
this.vmtarget = null; // maybe updated by JVM this.vmtarget = null; // maybe updated by JVM
MethodHandleNatives.init(this, mh, argnum); MethodHandleNatives.init(this, mh, argnum);
} else { } else {
this.vmtarget = mh; this.vmtarget = mh;
...@@ -97,29 +108,65 @@ public class BoundMethodHandle extends MethodHandle { ...@@ -97,29 +108,65 @@ public class BoundMethodHandle extends MethodHandle {
assert(this.getClass() == AdapterMethodHandle.class); assert(this.getClass() == AdapterMethodHandle.class);
} }
/** Initialize the current object as a method handle, binding it /** Initialize the current object as a Java method handle, binding it
* as the {@code argnum}th 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 {@code argnum}th argument * same as {@code entryPoint}, except that the first argument
* type will be dropped. * type will be dropped.
*/ */
public BoundMethodHandle(MethodHandle entryPoint, int argnum) { protected BoundMethodHandle(MethodHandle entryPoint) {
this(entryPoint, null, argnum, SELF_ARG); super(Access.TOKEN, entryPoint.type().dropParameterTypes(0, 1));
this.argument = this; // kludge; get rid of
// Note: If the conversion fails, perhaps because of a bad entryPoint, this.vmargslot = this.type().parameterSlotDepth(0);
// the MethodHandle.type field will not be filled in, and therefore initTarget(entryPoint, 0);
// no MH.invoke call will ever succeed. The caller may retain a pointer assert(this instanceof JavaMethodHandle);
// to the broken method handle, but no harm can be done with it.
} }
/** Initialize the current object as a method handle, binding it /** Initialize the current object as a Java method handle.
* as the first argument of the method handle {@code entryPoint}.
* The invocation type of the resulting method handle will be the
* same as {@code entryPoint}, except that the first argument
* type will be dropped.
*/ */
public BoundMethodHandle(MethodHandle entryPoint) { protected BoundMethodHandle(String entryPointName, MethodType type, boolean matchArity) {
this(entryPoint, null, 0, SELF_ARG); super(Access.TOKEN, null);
MethodHandle entryPoint
= findJavaMethodHandleEntryPoint(this.getClass(),
entryPointName, type, matchArity);
MethodHandleImpl.initType(this, entryPoint.type().dropParameterTypes(0, 1));
this.argument = this; // kludge; get rid of
this.vmargslot = this.type().parameterSlotDepth(0);
initTarget(entryPoint, 0);
assert(this instanceof JavaMethodHandle);
}
private static
MethodHandle findJavaMethodHandleEntryPoint(Class<?> caller,
String name,
MethodType type,
boolean matchArity) {
if (matchArity) type.getClass(); // elicit NPE
List<MemberName> methods = IMPL_NAMES.getMethods(caller, true, name, null, caller);
MethodType foundType = null;
MemberName foundMethod = null;
for (MemberName method : methods) {
MethodType mtype = method.getMethodType();
if (type != null && type.parameterCount() != mtype.parameterCount())
continue;
else if (foundType == null)
foundType = mtype;
else if (foundType != mtype)
throw newIllegalArgumentException("more than one method named "+name+" in "+caller.getName());
// discard overrides
if (foundMethod == null)
foundMethod = method;
else if (foundMethod.getDeclaringClass().isAssignableFrom(method.getDeclaringClass()))
foundMethod = method;
}
if (foundMethod == null)
throw newIllegalArgumentException("no method named "+name+" in "+caller.getName());
MethodHandle entryPoint = MethodHandleImpl.findMethod(IMPL_TOKEN, foundMethod, true, caller);
if (type != null) {
MethodType epType = type.insertParameterTypes(0, entryPoint.type().parameterType(0));
entryPoint = MethodHandles.convertArguments(entryPoint, epType);
}
return entryPoint;
} }
/** 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
...@@ -175,6 +222,24 @@ public class BoundMethodHandle extends MethodHandle { ...@@ -175,6 +222,24 @@ public class BoundMethodHandle extends MethodHandle {
@Override @Override
public String toString() { public String toString() {
return "Bound[" + super.toString() + "]"; MethodHandle mh = this;
while (mh instanceof BoundMethodHandle) {
Object info = MethodHandleNatives.getTargetInfo(mh);
if (info instanceof MethodHandle) {
mh = (MethodHandle) info;
} else {
String name = null;
if (info instanceof MemberName)
name = ((MemberName)info).getName();
if (name != null)
return name;
else
return super.toString(); // <unknown>, probably
}
assert(mh != this);
if (mh instanceof JavaMethodHandle)
break; // access JMH.toString(), not BMH.toString()
}
return mh.toString();
} }
} }
...@@ -26,34 +26,51 @@ ...@@ -26,34 +26,51 @@
package sun.dyn; package sun.dyn;
import java.dyn.*; import java.dyn.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* The CallSite privately created by the JVM at every invokedynamic instruction. * Parts of CallSite known to the JVM.
* FIXME: Merge all this into CallSite proper.
* @author jrose * @author jrose
*/ */
class CallSiteImpl extends CallSite { public class CallSiteImpl {
// Fields used only by the JVM. Do not use or change. // Field used only by the JVM. Do not use or change.
private Object vmmethod; private Object vmmethod;
// Values supplied by the JVM: // Values supplied by the JVM:
int callerMID, callerBCI; protected int callerMID, callerBCI;
private CallSiteImpl(Class<?> caller, String name, MethodType type) { private MethodHandle target;
super(caller, name, type); protected final Object caller; // usually a class
protected final String name;
protected final MethodType type;
/** called only directly from CallSite() */
protected CallSiteImpl(Access token, Object caller, String name, MethodType type) {
Access.check(token);
this.caller = caller;
this.name = name;
this.type = type;
}
/** native version of setTarget */
protected void setTarget(MethodHandle mh) {
//System.out.println("setTarget "+this+" := "+mh);
// XXX I don't know how to fix this properly.
// if (false && MethodHandleNatives.JVM_SUPPORT) // FIXME: enable this
// MethodHandleNatives.linkCallSite(this, mh);
// else
this.target = mh;
} }
@Override protected MethodHandle getTarget() {
public void setTarget(MethodHandle mh) { return target;
checkTarget(mh);
if (MethodHandleNatives.JVM_SUPPORT)
MethodHandleNatives.linkCallSite(this, (MethodHandle) mh);
else
super.setTarget(mh);
} }
private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE = private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE =
MethodHandleImpl.IMPL_LOOKUP.findStatic(CallSite.class, "privateInitializeCallSite", MethodHandleImpl.IMPL_LOOKUP.findStatic(CallSite.class, "privateInitializeCallSite",
MethodType.make(void.class, CallSite.class, int.class, int.class)); MethodType.methodType(void.class, CallSite.class, int.class, int.class));
// this is the up-call from the JVM: // this is the up-call from the JVM:
static CallSite makeSite(Class<?> caller, String name, MethodType type, static CallSite makeSite(Class<?> caller, String name, MethodType type,
...@@ -61,10 +78,25 @@ class CallSiteImpl extends CallSite { ...@@ -61,10 +78,25 @@ class CallSiteImpl extends CallSite {
MethodHandle bsm = Linkage.getBootstrapMethod(caller); MethodHandle bsm = Linkage.getBootstrapMethod(caller);
if (bsm == null) if (bsm == null)
throw new InvokeDynamicBootstrapError("class has no bootstrap method: "+caller); throw new InvokeDynamicBootstrapError("class has no bootstrap method: "+caller);
CallSite site = bsm.<CallSite>invoke(caller, name, type); CallSite site;
try {
site = bsm.<CallSite>invoke(caller, name, type);
} catch (Throwable ex) {
throw new InvokeDynamicBootstrapError("exception thrown while linking", ex);
}
if (site == null) if (site == null)
throw new InvokeDynamicBootstrapError("class bootstrap method failed to create a call site: "+caller); throw new InvokeDynamicBootstrapError("class bootstrap method failed to create a call site: "+caller);
PRIVATE_INITIALIZE_CALL_SITE.<void>invoke(site, callerMID, callerBCI); if (site.type() != type)
throw new InvokeDynamicBootstrapError("call site type not initialized correctly: "+site);
if (site.callerClass() != caller)
throw new InvokeDynamicBootstrapError("call site caller not initialized correctly: "+site);
if ((Object)site.name() != name)
throw new InvokeDynamicBootstrapError("call site name not initialized correctly: "+site);
try {
PRIVATE_INITIALIZE_CALL_SITE.<void>invoke(site, callerMID, callerBCI);
} catch (Throwable ex) {
throw new InvokeDynamicBootstrapError("call site initialization exception", ex);
}
return site; return site;
} }
} }
...@@ -27,7 +27,6 @@ package sun.dyn; ...@@ -27,7 +27,6 @@ package sun.dyn;
import java.dyn.JavaMethodHandle; import java.dyn.JavaMethodHandle;
import java.dyn.MethodHandle; import java.dyn.MethodHandle;
import java.dyn.MethodHandles;
import java.dyn.MethodType; import java.dyn.MethodType;
/** /**
...@@ -42,16 +41,21 @@ public class FilterOneArgument extends JavaMethodHandle { ...@@ -42,16 +41,21 @@ public class FilterOneArgument extends JavaMethodHandle {
protected final MethodHandle filter; // Object -> Object protected final MethodHandle filter; // Object -> Object
protected final MethodHandle target; // Object -> Object protected final MethodHandle target; // Object -> Object
protected Object entryPoint(Object argument) { @Override
Object filteredArgument = filter.<Object>invoke(argument); public String toString() {
return target.<Object>invoke(filteredArgument); return target.toString();
}
protected Object invoke(Object argument) throws Throwable {
Object filteredArgument = filter.invoke(argument);
return target.invoke(filteredArgument);
} }
private static final MethodHandle entryPoint = private static final MethodHandle INVOKE =
MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "entryPoint", MethodType.makeGeneric(1)); MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "invoke", MethodType.genericMethodType(1));
protected FilterOneArgument(MethodHandle filter, MethodHandle target) { protected FilterOneArgument(MethodHandle filter, MethodHandle target) {
super(entryPoint); super(INVOKE);
this.filter = filter; this.filter = filter;
this.target = target; this.target = target;
} }
...@@ -62,10 +66,6 @@ public class FilterOneArgument extends JavaMethodHandle { ...@@ -62,10 +66,6 @@ public class FilterOneArgument extends JavaMethodHandle {
return new FilterOneArgument(filter, target); return new FilterOneArgument(filter, target);
} }
public String toString() {
return filter + "|>" + target;
}
// MethodHandle make(MethodHandle filter1, MethodHandle filter2, MethodHandle target) { // MethodHandle make(MethodHandle filter1, MethodHandle filter2, MethodHandle target) {
// MethodHandle filter = make(filter1, filter2); // MethodHandle filter = make(filter1, filter2);
// return make(filter, target); // return make(filter, target);
......
...@@ -44,16 +44,20 @@ public class Invokers { ...@@ -44,16 +44,20 @@ public class Invokers {
// 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[]
private final /*lazy*/ MethodHandle[] varargsInvokers;
/** 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.
*/ */
public Invokers(Access token, MethodType targetType) { public Invokers(Access token, MethodType targetType) {
Access.check(token); Access.check(token);
this.targetType = targetType; this.targetType = targetType;
this.varargsInvokers = new MethodHandle[targetType.parameterCount()+1];
} }
public static MethodType invokerType(MethodType targetType) { public static MethodType invokerType(MethodType targetType) {
return targetType.insertParameterType(0, MethodHandle.class); return targetType.insertParameterTypes(0, MethodHandle.class);
} }
public MethodHandle exactInvoker() { public MethodHandle exactInvoker() {
...@@ -76,8 +80,14 @@ public class Invokers { ...@@ -76,8 +80,14 @@ public class Invokers {
return invoker; return invoker;
} }
public MethodHandle varargsInvoker() { public MethodHandle varargsInvoker(int objectArgCount) {
throw new UnsupportedOperationException("NYI"); MethodHandle vaInvoker = varargsInvokers[objectArgCount];
if (vaInvoker != null) return vaInvoker;
MethodHandle gInvoker = genericInvoker();
MethodType vaType = MethodType.genericMethodType(objectArgCount, true);
vaInvoker = MethodHandles.spreadArguments(gInvoker, invokerType(vaType));
varargsInvokers[objectArgCount] = vaInvoker;
return vaInvoker;
} }
public String toString() { public String toString() {
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
package sun.dyn; package sun.dyn;
import sun.dyn.util.BytecodeSignature; import sun.dyn.util.BytecodeDescriptor;
import java.dyn.*; import java.dyn.*;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
...@@ -33,6 +33,7 @@ import java.lang.reflect.Method; ...@@ -33,6 +33,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Member; import java.lang.reflect.Member;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
...@@ -93,7 +94,7 @@ public final class MemberName implements Member, Cloneable { ...@@ -93,7 +94,7 @@ public final class MemberName implements Member, Cloneable {
} }
if (type instanceof String) { if (type instanceof String) {
String sig = (String) type; String sig = (String) type;
MethodType res = MethodType.fromBytecodeString(sig, getClassLoader()); MethodType res = MethodType.fromMethodDescriptorString(sig, getClassLoader());
this.type = res; this.type = res;
return res; return res;
} }
...@@ -101,7 +102,7 @@ public final class MemberName implements Member, Cloneable { ...@@ -101,7 +102,7 @@ public final class MemberName implements Member, Cloneable {
Object[] typeInfo = (Object[]) type; Object[] typeInfo = (Object[]) type;
Class<?>[] ptypes = (Class<?>[]) typeInfo[1]; Class<?>[] ptypes = (Class<?>[]) typeInfo[1];
Class<?> rtype = (Class<?>) typeInfo[0]; Class<?> rtype = (Class<?>) typeInfo[0];
MethodType res = MethodType.make(rtype, ptypes); MethodType res = MethodType.methodType(rtype, ptypes);
this.type = res; this.type = res;
return res; return res;
} }
...@@ -111,7 +112,7 @@ public final class MemberName implements Member, Cloneable { ...@@ -111,7 +112,7 @@ public final class MemberName implements Member, Cloneable {
public MethodType getInvocationType() { public MethodType getInvocationType() {
MethodType itype = getMethodType(); MethodType itype = getMethodType();
if (!isStatic()) if (!isStatic())
itype = itype.insertParameterType(0, clazz); itype = itype.insertParameterTypes(0, clazz);
return itype; return itype;
} }
...@@ -135,7 +136,7 @@ public final class MemberName implements Member, Cloneable { ...@@ -135,7 +136,7 @@ public final class MemberName implements Member, Cloneable {
} }
if (type instanceof String) { if (type instanceof String) {
String sig = (String) type; String sig = (String) type;
MethodType mtype = MethodType.fromBytecodeString("()"+sig, getClassLoader()); MethodType mtype = MethodType.fromMethodDescriptorString("()"+sig, getClassLoader());
Class<?> res = mtype.returnType(); Class<?> res = mtype.returnType();
this.type = res; this.type = res;
return res; return res;
...@@ -155,9 +156,9 @@ public final class MemberName implements Member, Cloneable { ...@@ -155,9 +156,9 @@ public final class MemberName implements Member, Cloneable {
if (type instanceof String) if (type instanceof String)
return (String) type; return (String) type;
if (isInvocable()) if (isInvocable())
return BytecodeSignature.unparse(getMethodType()); return BytecodeDescriptor.unparse(getMethodType());
else else
return BytecodeSignature.unparse(getFieldType()); return BytecodeDescriptor.unparse(getFieldType());
} }
public int getModifiers() { public int getModifiers() {
...@@ -353,6 +354,8 @@ public final class MemberName implements Member, Cloneable { ...@@ -353,6 +354,8 @@ public final class MemberName implements Member, Cloneable {
return type.toString(); // class java.lang.String return type.toString(); // class java.lang.String
// else it is a field, method, or constructor // else it is a field, method, or constructor
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
if (!isResolved())
buf.append("*.");
if (getDeclaringClass() != null) { if (getDeclaringClass() != null) {
buf.append(getName(clazz)); buf.append(getName(clazz));
buf.append('.'); buf.append('.');
...@@ -381,7 +384,7 @@ public final class MemberName implements Member, Cloneable { ...@@ -381,7 +384,7 @@ public final class MemberName implements Member, Cloneable {
private static String getName(Object obj) { private static String getName(Object obj) {
if (obj instanceof Class<?>) if (obj instanceof Class<?>)
return ((Class<?>)obj).getName(); return ((Class<?>)obj).getName();
return obj.toString(); return String.valueOf(obj);
} }
// Queries to the JVM: // Queries to the JVM:
...@@ -408,6 +411,9 @@ public final class MemberName implements Member, Cloneable { ...@@ -408,6 +411,9 @@ public final class MemberName implements Member, Cloneable {
public static NoAccessException newNoAccessException(MemberName name, Class<?> lookupClass) { public static NoAccessException newNoAccessException(MemberName name, Class<?> lookupClass) {
return newNoAccessException("cannot access", name, lookupClass); return newNoAccessException("cannot access", name, lookupClass);
} }
public static NoAccessException newNoAccessException(MemberName name, MethodHandles.Lookup lookup) {
return newNoAccessException(name, lookup.lookupClass());
}
public static NoAccessException newNoAccessException(String message, public static NoAccessException newNoAccessException(String message,
MemberName name, Class<?> lookupClass) { MemberName name, Class<?> lookupClass) {
message += ": " + name; message += ": " + name;
...@@ -436,7 +442,7 @@ public final class MemberName implements Member, Cloneable { ...@@ -436,7 +442,7 @@ public final class MemberName implements Member, Cloneable {
matchFlags &= ALLOWED_FLAGS; matchFlags &= ALLOWED_FLAGS;
String matchSig = null; String matchSig = null;
if (matchType != null) { if (matchType != null) {
matchSig = BytecodeSignature.unparse(matchType); matchSig = BytecodeDescriptor.unparse(matchType);
if (matchSig.startsWith("(")) if (matchSig.startsWith("("))
matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE); matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE);
else else
...@@ -447,17 +453,18 @@ public final class MemberName implements Member, Cloneable { ...@@ -447,17 +453,18 @@ public final class MemberName implements Member, Cloneable {
MemberName[] buf = newMemberBuffer(len1); MemberName[] buf = newMemberBuffer(len1);
int totalCount = 0; int totalCount = 0;
ArrayList<MemberName[]> bufs = null; ArrayList<MemberName[]> bufs = null;
int bufCount = 0;
for (;;) { for (;;) {
int bufCount = MethodHandleNatives.getMembers(defc, bufCount = MethodHandleNatives.getMembers(defc,
matchName, matchSig, matchFlags, matchName, matchSig, matchFlags,
lookupClass, lookupClass,
totalCount, buf); totalCount, buf);
if (bufCount <= buf.length) { if (bufCount <= buf.length) {
if (bufCount >= 0) if (bufCount < 0) bufCount = 0;
totalCount += bufCount; totalCount += bufCount;
break; break;
} }
// JVM returned tp us with an intentional overflow! // JVM returned to us with an intentional overflow!
totalCount += buf.length; totalCount += buf.length;
int excess = bufCount - buf.length; int excess = bufCount - buf.length;
if (bufs == null) bufs = new ArrayList<MemberName[]>(1); if (bufs == null) bufs = new ArrayList<MemberName[]>(1);
...@@ -473,7 +480,7 @@ public final class MemberName implements Member, Cloneable { ...@@ -473,7 +480,7 @@ public final class MemberName implements Member, Cloneable {
Collections.addAll(result, buf0); Collections.addAll(result, buf0);
} }
} }
Collections.addAll(result, buf); result.addAll(Arrays.asList(buf).subList(0, bufCount));
// Signature matching is not the same as type matching, since // Signature matching is not the same as type matching, since
// one signature might correspond to several types. // one signature might correspond to several types.
// So if matchType is a Class or MethodType, refilter the results. // So if matchType is a Class or MethodType, refilter the results.
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
package sun.dyn; package sun.dyn;
import java.dyn.CallSite;
import java.dyn.MethodHandle; import java.dyn.MethodHandle;
import java.dyn.MethodType; import java.dyn.MethodType;
import java.lang.reflect.AccessibleObject; import java.lang.reflect.AccessibleObject;
...@@ -60,7 +61,7 @@ class MethodHandleNatives { ...@@ -60,7 +61,7 @@ class MethodHandleNatives {
static native void init(MethodType self); static native void init(MethodType self);
/** Tell the JVM that we need to change the target of an invokedynamic. */ /** Tell the JVM that we need to change the target of an invokedynamic. */
static native void linkCallSite(CallSiteImpl site, MethodHandle target); static native void linkCallSite(CallSite site, MethodHandle target);
/** Fetch the vmtarget field. /** Fetch the vmtarget field.
* It will be sanitized as necessary to avoid exposing non-Java references. * It will be sanitized as necessary to avoid exposing non-Java references.
...@@ -84,8 +85,7 @@ class MethodHandleNatives { ...@@ -84,8 +85,7 @@ class MethodHandleNatives {
} }
/** Fetch the target of this method handle. /** Fetch the target of this method handle.
* If it directly targets a method, return a tuple of method info. * If it directly targets a method, return a MemberName for the method.
* The info is of the form new Object[]{defclass, name, sig, refclass}.
* If it is chained to another method handle, return that handle. * If it is chained to another method handle, return that handle.
*/ */
static Object getTargetInfo(MethodHandle self) { static Object getTargetInfo(MethodHandle self) {
...@@ -123,7 +123,7 @@ class MethodHandleNatives { ...@@ -123,7 +123,7 @@ class MethodHandleNatives {
registerNatives(); registerNatives();
JVM_SUPPORT_ = true; JVM_SUPPORT_ = true;
JVM_PUSH_LIMIT_ = getConstant(Constants.GC_JVM_PUSH_LIMIT); JVM_PUSH_LIMIT_ = getConstant(Constants.GC_JVM_PUSH_LIMIT);
JVM_STACK_MOVE_UNIT_ = getConstant(Constants.GC_JVM_STACK_MOVE_LIMIT); JVM_STACK_MOVE_UNIT_ = getConstant(Constants.GC_JVM_STACK_MOVE_UNIT);
//sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init"); //sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init");
} catch (UnsatisfiedLinkError ee) { } catch (UnsatisfiedLinkError ee) {
// ignore; if we use init() methods later we'll see linkage errors // ignore; if we use init() methods later we'll see linkage errors
...@@ -149,7 +149,7 @@ class MethodHandleNatives { ...@@ -149,7 +149,7 @@ class MethodHandleNatives {
// MethodHandleImpl // MethodHandleImpl
static final int // for getConstant static final int // for getConstant
GC_JVM_PUSH_LIMIT = 0, GC_JVM_PUSH_LIMIT = 0,
GC_JVM_STACK_MOVE_LIMIT = 1; GC_JVM_STACK_MOVE_UNIT = 1;
static final int static final int
ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method) ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method)
ETF_DIRECT_HANDLE = 1, // ultimate method handle (will be a DMH, may be self) ETF_DIRECT_HANDLE = 1, // ultimate method handle (will be a DMH, may be self)
...@@ -178,19 +178,20 @@ class MethodHandleNatives { ...@@ -178,19 +178,20 @@ class MethodHandleNatives {
*/ */
static final int static final int
OP_RETYPE_ONLY = 0x0, // no argument changes; straight retype OP_RETYPE_ONLY = 0x0, // no argument changes; straight retype
OP_CHECK_CAST = 0x1, // ref-to-ref conversion; requires a Class argument OP_RETYPE_RAW = 0x1, // no argument changes; straight retype
OP_PRIM_TO_PRIM = 0x2, // converts from one primitive to another OP_CHECK_CAST = 0x2, // ref-to-ref conversion; requires a Class argument
OP_REF_TO_PRIM = 0x3, // unboxes a wrapper to produce a primitive OP_PRIM_TO_PRIM = 0x3, // converts from one primitive to another
OP_PRIM_TO_REF = 0x4, // boxes a primitive into a wrapper (NYI) OP_REF_TO_PRIM = 0x4, // unboxes a wrapper to produce a primitive
OP_SWAP_ARGS = 0x5, // swap arguments (vminfo is 2nd arg) OP_PRIM_TO_REF = 0x5, // boxes a primitive into a wrapper (NYI)
OP_ROT_ARGS = 0x6, // rotate arguments (vminfo is displaced arg) OP_SWAP_ARGS = 0x6, // swap arguments (vminfo is 2nd arg)
OP_DUP_ARGS = 0x7, // duplicates one or more arguments (at TOS) OP_ROT_ARGS = 0x7, // rotate arguments (vminfo is displaced arg)
OP_DROP_ARGS = 0x8, // remove one or more argument slots OP_DUP_ARGS = 0x8, // duplicates one or more arguments (at TOS)
OP_COLLECT_ARGS = 0x9, // combine one or more arguments into a varargs (NYI) OP_DROP_ARGS = 0x9, // remove one or more argument slots
OP_SPREAD_ARGS = 0xA, // expand in place a varargs array (of known size) OP_COLLECT_ARGS = 0xA, // combine one or more arguments into a varargs (NYI)
OP_FLYBY = 0xB, // operate first on reified argument list (NYI) OP_SPREAD_ARGS = 0xB, // expand in place a varargs array (of known size)
OP_RICOCHET = 0xC, // run an adapter chain on the return value (NYI) OP_FLYBY = 0xC, // operate first on reified argument list (NYI)
CONV_OP_LIMIT = 0xD; // limit of CONV_OP enumeration OP_RICOCHET = 0xD, // run an adapter chain on the return value (NYI)
CONV_OP_LIMIT = 0xE; // limit of CONV_OP enumeration
/** Shift and mask values for decoding the AMH.conversion field. /** Shift and mask values for decoding the AMH.conversion field.
* These numbers are shared with the JVM for creating AMHs. * These numbers are shared with the JVM for creating AMHs.
*/ */
...@@ -209,6 +210,7 @@ class MethodHandleNatives { ...@@ -209,6 +210,7 @@ class MethodHandleNatives {
// TODO: The following expression should be replaced by // TODO: The following expression should be replaced by
// a JVM query. // a JVM query.
((1<<OP_RETYPE_ONLY) ((1<<OP_RETYPE_ONLY)
|(1<<OP_RETYPE_RAW)
|(1<<OP_CHECK_CAST) |(1<<OP_CHECK_CAST)
|(1<<OP_PRIM_TO_PRIM) |(1<<OP_PRIM_TO_PRIM)
|(1<<OP_REF_TO_PRIM) |(1<<OP_REF_TO_PRIM)
...@@ -216,6 +218,7 @@ class MethodHandleNatives { ...@@ -216,6 +218,7 @@ class MethodHandleNatives {
|(1<<OP_ROT_ARGS) |(1<<OP_ROT_ARGS)
|(1<<OP_DUP_ARGS) |(1<<OP_DUP_ARGS)
|(1<<OP_DROP_ARGS) |(1<<OP_DROP_ARGS)
//|(1<<OP_SPREAD_ARGS) // FIXME: Check JVM assembly code.
); );
/** /**
......
...@@ -27,6 +27,7 @@ package sun.dyn; ...@@ -27,6 +27,7 @@ package sun.dyn;
import java.dyn.*; import java.dyn.*;
import sun.dyn.util.Wrapper; import sun.dyn.util.Wrapper;
import static sun.dyn.MemberName.newIllegalArgumentException;
/** /**
* Shared information for a group of method types, which differ * Shared information for a group of method types, which differ
...@@ -56,8 +57,8 @@ public class MethodTypeImpl { ...@@ -56,8 +57,8 @@ public class MethodTypeImpl {
// Cached adapter information: // Cached adapter information:
/*lazy*/ ToGeneric toGeneric; // convert cs. with prims to w/o /*lazy*/ ToGeneric toGeneric; // convert cs. with prims to w/o
/*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*/ FilterGeneric filterGeneric; // convert argument(s) on the fly /*lazy*/ FilterGeneric filterGeneric; // convert argument(s) on the fly
///*lazy*/ Invokers invokers; // cache of handy higher-order adapters
public MethodType erasedType() { public MethodType erasedType() {
return erasedType; return erasedType;
...@@ -68,7 +69,7 @@ public class MethodTypeImpl { ...@@ -68,7 +69,7 @@ public class MethodTypeImpl {
} }
/** Access methods for the internals of MethodType, supplied to /** Access methods for the internals of MethodType, supplied to
* MethodTypeForm as a trusted agent. * MethodTypeImpl as a trusted agent.
*/ */
static public interface MethodTypeFriend { static public interface MethodTypeFriend {
Class<?>[] ptypes(MethodType mt); Class<?>[] ptypes(MethodType mt);
...@@ -150,7 +151,7 @@ public class MethodTypeImpl { ...@@ -150,7 +151,7 @@ public class MethodTypeImpl {
this.argToSlotTable = argToSlotTab; this.argToSlotTable = argToSlotTab;
this.slotToArgTable = slotToArgTab; this.slotToArgTable = slotToArgTab;
if (pslotCount >= 256) throw new IllegalArgumentException("too many arguments"); if (pslotCount >= 256) throw newIllegalArgumentException("too many arguments");
// send a few bits down to the JVM: // send a few bits down to the JVM:
this.vmslots = parameterSlotCount(); this.vmslots = parameterSlotCount();
...@@ -378,10 +379,10 @@ public class MethodTypeImpl { ...@@ -378,10 +379,10 @@ public class MethodTypeImpl {
static MethodTypeImpl findForm(MethodType mt) { static MethodTypeImpl findForm(MethodType mt) {
MethodType erased = canonicalize(mt, ERASE, ERASE); MethodType erased = canonicalize(mt, ERASE, ERASE);
if (erased == null) { if (erased == null) {
// It is already erased. Make a new MethodTypeForm. // It is already erased. Make a new MethodTypeImpl.
return METHOD_TYPE_FRIEND.newMethodTypeForm(mt); return METHOD_TYPE_FRIEND.newMethodTypeForm(mt);
} else { } else {
// Share the MethodTypeForm with the erased version. // Share the MethodTypeImpl with the erased version.
return METHOD_TYPE_FRIEND.form(erased); return METHOD_TYPE_FRIEND.form(erased);
} }
} }
......
此差异已折叠。
...@@ -29,6 +29,10 @@ package sun.dyn.empty; ...@@ -29,6 +29,10 @@ package sun.dyn.empty;
* An empty class in an empty package. * An empty class in an empty package.
* Used as a proxy for unprivileged code, since making access checks * Used as a proxy for unprivileged code, since making access checks
* against it will only succeed against public methods in public types. * against it will only succeed against public methods in public types.
* <p>
* This class also stands (internally to sun.dyn) for the type of a
* value that cannot be produced, because the expression of this type
* always returns abnormally. (Cf. Nothing in the closures proposal.)
* @author jrose * @author jrose
*/ */
public class Empty { public class Empty {
......
...@@ -33,9 +33,9 @@ import java.util.List; ...@@ -33,9 +33,9 @@ import java.util.List;
* Utility routines for dealing with bytecode-level signatures. * Utility routines for dealing with bytecode-level signatures.
* @author jrose * @author jrose
*/ */
public class BytecodeSignature { public class BytecodeDescriptor {
private BytecodeSignature() { } // cannot instantiate private BytecodeDescriptor() { } // cannot instantiate
public static List<Class<?>> parseMethod(String bytecodeSignature, ClassLoader loader) { public static List<Class<?>> parseMethod(String bytecodeSignature, ClassLoader loader) {
return parseMethod(bytecodeSignature, 0, bytecodeSignature.length(), loader); return parseMethod(bytecodeSignature, 0, bytecodeSignature.length(), loader);
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
package sun.dyn.util; package sun.dyn.util;
import java.dyn.MethodType; import java.dyn.MethodType;
import sun.dyn.empty.Empty;
/** /**
* This class centralizes information about the JVM verifier * This class centralizes information about the JVM verifier
...@@ -73,29 +74,28 @@ public class VerifyType { ...@@ -73,29 +74,28 @@ public class VerifyType {
} }
/** /**
* Is the given type either java.lang.Void or java.lang.Null? * Is the given type java.lang.Null or an equivalent null-only type?
* These types serve as markers for bare nulls and therefore
* may be promoted to any type. This is secure, since
*/ */
public static boolean isNullType(Class<?> type) { public static boolean isNullType(Class<?> type) {
if (type == null) return false; if (type == null) return false;
return type == NULL_CLASS_1 || type == NULL_CLASS_2; return type == NULL_CLASS
// This one may also be used as a null type.
// TO DO: Decide if we really want to legitimize it here.
// Probably we do, unless java.lang.Null really makes it into Java 7
//|| type == Void.class
// Locally known null-only class:
|| type == Empty.class
;
} }
private static final Class<?> NULL_CLASS_1, NULL_CLASS_2; private static final Class<?> NULL_CLASS;
static { static {
Class<?> nullClass1 = null, nullClass2 = null; Class<?> nullClass = null;
try { try {
nullClass1 = Class.forName("java.lang.Null"); nullClass = Class.forName("java.lang.Null");
} catch (ClassNotFoundException ex) { } catch (ClassNotFoundException ex) {
// OK, we'll cope // OK, we'll cope
} }
NULL_CLASS_1 = nullClass1; NULL_CLASS = nullClass;
// This one may also be used as a null type.
// TO DO: Decide if we really want to legitimize it here.
// Probably we do, unless java.lang.Null really makes it into Java 7
nullClass2 = Void.class;
NULL_CLASS_2 = nullClass2;
} }
/** /**
...@@ -191,6 +191,11 @@ public class VerifyType { ...@@ -191,6 +191,11 @@ public class VerifyType {
// to be captured as a garbage int. // to be captured as a garbage int.
// Caller promises that the actual value will be disregarded. // Caller promises that the actual value will be disregarded.
return dst == int.class ? 1 : 0; return dst == int.class ? 1 : 0;
if (isNullType(src))
// Special permission for raw conversions: allow a null
// to be reinterpreted as anything. For objects, it is safe,
// and for primitives you get a garbage value (probably zero).
return 1;
if (!src.isPrimitive()) if (!src.isPrimitive())
return 0; return 0;
Wrapper sw = Wrapper.forPrimitiveType(src); Wrapper sw = Wrapper.forPrimitiveType(src);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册