提交 33ee9ccf 编写于 作者: J jrose

Merge

......@@ -54,9 +54,6 @@ EXCLUDE_PROPWARN_PKGS = com.sun.java.swing.plaf.windows \
com.sun.java.swing.plaf.motif \
com.sun.java.swing.plaf.gtk
# This is a stopgap until 6839872 is fixed.
EXCLUDE_PROPWARN_PKGS += sun.dyn
#
# Include the exported private packages in ct.sym.
# This is an interim solution until the ct.sym is replaced
......
#
# Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2001, 2011, 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
......@@ -55,7 +55,7 @@ EXCLUDE_PKGS = \
# This is a list of regular expressions. So foo.* matches "foo" and "foo.bar".
#
ACTIVE_JSR_PKGS= \
java.dyn \
java.lang.invoke \
java.sql \
javax.activation \
javax.annotation.* \
......@@ -97,11 +97,11 @@ CORE_PKGS = \
java.awt.print \
java.beans \
java.beans.beancontext \
java.dyn \
java.io \
java.lang \
java.lang.annotation \
java.lang.instrument \
java.lang.invoke \
java.lang.management \
java.lang.ref \
java.lang.reflect \
......
#
# Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 1995, 2011, 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
......@@ -44,7 +44,7 @@ SUBDIRS += security math util text net nio jar
SUBDIRS_desktop = awt applet beans
SUBDIRS_management = management
SUBDIRS_misc = npt java_crw_demo java_hprof_demo \
logging instrument dyn sql rmi
logging instrument invoke sql rmi
ifeq ($(PLATFORM), solaris)
......
#
# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2008, 2011, 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
......@@ -25,18 +25,18 @@
BUILDDIR = ../..
PACKAGE = java.dyn
PACKAGE = java.lang.invoke
PRODUCT = java
include $(BUILDDIR)/common/Defs.gmk
AUTO_FILES_JAVA_DIRS = java/dyn sun/dyn
AUTO_FILES_JAVA_DIRS = java/lang/invoke sun/invoke
FILES_java = \
java/lang/ClassValue.java \
java/lang/BootstrapMethodError.java
# The sources built here use new language syntax to generate
# method handle calls. Let's be sure we are using that format.
LANGUAGE_VERSION = -source 7
CLASS_VERSION = -target 7
# Tell the compiler not to accept transitional forms.
OTHER_JAVACFLAGS = -XDallowTransitionalJSR292=no
include $(BUILDDIR)/common/Classes.gmk
/*
* 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.dyn.MethodHandles.Lookup;
import java.util.WeakHashMap;
import sun.dyn.Access;
import sun.dyn.MethodHandleImpl;
import sun.dyn.util.VerifyAccess;
import sun.reflect.Reflection;
import static sun.dyn.MemberName.newIllegalArgumentException;
/**
* <em>CLASS WILL BE REMOVED FOR PFD:</em>
* Static routines for controlling invokedynamic behavior.
* Replaced by non-static APIs.
* @author John Rose, JSR 292 EG
* @deprecated This class will be removed in the Public Final Draft.
*/
public class Linkage {
private static final Access IMPL_TOKEN = Access.getToken();
private Linkage() {} // do not instantiate
/**
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
* Register a <em>bootstrap method</em> to use when linking dynamic call sites within
* a given caller class.
* @deprecated Use @{@link BootstrapMethod} annotations instead.
*/
public static
void registerBootstrapMethod(Class callerClass, MethodHandle bootstrapMethod) {
Class callc = Reflection.getCallerClass(2);
if (callc != null && !VerifyAccess.isSamePackage(callerClass, callc))
throw new IllegalArgumentException("cannot set bootstrap method on "+callerClass);
MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
}
/**
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
* Simplified version of {@code registerBootstrapMethod} for self-registration,
* to be called from a static initializer.
* @deprecated Use @{@link BootstrapMethod} annotations instead.
*/
public static
void registerBootstrapMethod(Class<?> runtime, String name) {
Class callerClass = Reflection.getCallerClass(2);
registerBootstrapMethodLookup(callerClass, runtime, name);
}
/**
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
* Simplified version of {@code registerBootstrapMethod} for self-registration,
* @deprecated Use @{@link BootstrapMethod} annotations instead.
*/
public static
void registerBootstrapMethod(String name) {
Class callerClass = Reflection.getCallerClass(2);
registerBootstrapMethodLookup(callerClass, callerClass, name);
}
private static
void registerBootstrapMethodLookup(Class<?> callerClass, Class<?> runtime, String name) {
Lookup lookup = new Lookup(IMPL_TOKEN, callerClass);
MethodHandle bootstrapMethod;
try {
bootstrapMethod = lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE);
} catch (ReflectiveOperationException ex) {
throw new IllegalArgumentException("no such bootstrap method in "+runtime+": "+name, ex);
}
MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
}
private static final MethodType BOOTSTRAP_METHOD_TYPE
= MethodType.methodType(CallSite.class,
Class.class, String.class, MethodType.class);
/**
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
* Invalidate all <code>invokedynamic</code> call sites everywhere.
* @deprecated Use {@linkplain MutableCallSite#setTarget call site target setting},
* {@link MutableCallSite#syncAll call site update pushing},
* and {@link SwitchPoint#guardWithTest target switching} instead.
*/
public static
Object invalidateAll() {
throw new UnsupportedOperationException();
}
/**
* <em>METHOD WILL BE REMOVED FOR PFD:</em>
* Invalidate all {@code invokedynamic} call sites in the bytecodes
* of any methods of the given class.
* @deprecated Use {@linkplain MutableCallSite#setTarget call site target setting},
* {@link MutableCallSite#syncAll call site update pushing},
* and {@link SwitchPoint#guardWithTest target switching} instead.
*/
public static
Object invalidateCallerClass(Class<?> callerClass) {
throw new UnsupportedOperationException();
}
}
/*
* 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 java.dyn;
/**
* TO DO: Temporary shim; remove after refactoring effects are complete in JVM.
* @author John Rose
*/
import sun.dyn.MethodTypeImpl;
class MethodTypeForm extends MethodTypeImpl {
MethodTypeForm(MethodType erasedType) {
super(erasedType);
}
}
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,58 +23,56 @@
* questions.
*/
package java.dyn;
package java.lang;
/**
* Thrown to indicate that an {@code invokedynamic} instruction has
* failed to find its
* {@linkplain BootstrapMethod bootstrap method},
* or the bootstrap method has
* failed to provide a
* {@linkplain CallSite call site} with a {@linkplain CallSite#getTarget target}
* of the correct {@linkplain MethodHandle#type method type}.
* failed to find its bootstrap method,
* or the bootstrap method has failed to provide a
* {@linkplain java.lang.invoke.CallSite call site} with a {@linkplain java.lang.invoke.CallSite#getTarget target}
* of the correct {@linkplain java.lang.invoke.MethodHandle#type method type}.
*
* @author John Rose, JSR 292 EG
* @since 1.7
*/
public class InvokeDynamicBootstrapError extends LinkageError {
public class BootstrapMethodError extends LinkageError {
private static final long serialVersionUID = 292L;
/**
* Constructs an {@code InvokeDynamicBootstrapError} with no detail message.
* Constructs an {@code BootstrapMethodError} with no detail message.
*/
public InvokeDynamicBootstrapError() {
public BootstrapMethodError() {
super();
}
/**
* Constructs an {@code InvokeDynamicBootstrapError} with the specified
* Constructs an {@code BootstrapMethodError} with the specified
* detail message.
*
* @param s the detail message.
*/
public InvokeDynamicBootstrapError(String s) {
public BootstrapMethodError(String s) {
super(s);
}
/**
* Constructs a {@code InvokeDynamicBootstrapError} with the specified
* Constructs a {@code BootstrapMethodError} with the specified
* detail message and cause.
*
* @param s the detail message.
* @param cause the cause, may be {@code null}.
*/
public InvokeDynamicBootstrapError(String s, Throwable cause) {
public BootstrapMethodError(String s, Throwable cause) {
super(s, cause);
}
/**
* Constructs a {@code InvokeDynamicBootstrapError} with the specified
* Constructs a {@code BootstrapMethodError} with the specified
* cause.
*
* @param cause the cause, may be {@code null}.
*/
public InvokeDynamicBootstrapError(Throwable cause) {
public BootstrapMethodError(Throwable cause) {
// cf. Throwable(Throwable cause) constructor.
super(cause == null ? null : cause.toString());
initCause(cause);
......
......@@ -23,12 +23,10 @@
* questions.
*/
package java.dyn;
package java.lang;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.lang.reflect.UndeclaredThrowableException;
/**
* Lazily associate a computed value with (potentially) every type.
......@@ -37,10 +35,11 @@ import java.lang.reflect.UndeclaredThrowableException;
* it can use a {@code ClassValue} to cache information needed to
* perform the message send quickly, for each class encountered.
* @author John Rose, JSR 292 EG
* @since 1.7
*/
public abstract class ClassValue<T> {
/**
* Compute the given class's derived value for this {@code ClassValue}.
* Computes the given class's derived value for this {@code ClassValue}.
* <p>
* This method will be invoked within the first thread that accesses
* the value with the {@link #get get} method.
......@@ -159,13 +158,7 @@ public abstract class ClassValue<T> {
}
/// Implementation...
// The hash code for this type is based on the identity of the object,
// and is well-dispersed for power-of-two tables.
/** @deprecated This override, which is implementation-specific, will be removed for PFD. */
public final int hashCode() { return hashCode; }
private final int hashCode = HASH_CODES.getAndAdd(0x61c88647);
private static final AtomicInteger HASH_CODES = new AtomicInteger();
// FIXME: Use a data structure here similar that of ThreadLocal (7030453).
private static final AtomicInteger STORE_BARRIER = new AtomicInteger();
......
......@@ -23,20 +23,19 @@
* questions.
*/
package sun.dyn;
package java.lang.invoke;
import sun.dyn.util.VerifyType;
import sun.dyn.util.Wrapper;
import java.dyn.*;
import sun.invoke.util.VerifyType;
import sun.invoke.util.Wrapper;
import java.util.Arrays;
import static sun.dyn.MethodHandleNatives.Constants.*;
import static sun.dyn.MemberName.newIllegalArgumentException;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandleStatics.*;
/**
* This method handle performs simple conversion or checking of a single argument.
* @author jrose
*/
public class AdapterMethodHandle extends BoundMethodHandle {
class AdapterMethodHandle extends BoundMethodHandle {
//MethodHandle vmtarget; // next AMH or BMH in chain or final DMH
//Object argument; // parameter to the conversion if needed
......@@ -48,25 +47,21 @@ public class AdapterMethodHandle extends BoundMethodHandle {
long conv, Object convArg) {
super(newType, convArg, newType.parameterSlotDepth(1+convArgPos(conv)));
this.conversion = convCode(conv);
if (MethodHandleNatives.JVM_SUPPORT) {
// JVM might update VM-specific bits of conversion (ignore)
MethodHandleNatives.init(this, target, convArgPos(conv));
}
}
private AdapterMethodHandle(MethodHandle target, MethodType newType,
long conv) {
this(target, newType, conv, null);
}
private static final Access IMPL_TOKEN = Access.getToken();
// TO DO: When adapting another MH with a null conversion, clone
// the target and change its type, instead of adding another layer.
/** Can a JVM-level adapter directly implement the proposed
* argument conversions, as if by MethodHandles.convertArguments?
*/
public static boolean canPairwiseConvert(MethodType newType, MethodType oldType) {
static boolean canPairwiseConvert(MethodType newType, MethodType oldType) {
// same number of args, of course
int len = newType.parameterCount();
if (len != oldType.parameterCount())
......@@ -92,7 +87,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
/** Can a JVM-level adapter directly implement the proposed
* argument conversion, as if by MethodHandles.convertArguments?
*/
public static boolean canConvertArgument(Class<?> src, Class<?> dst) {
static boolean canConvertArgument(Class<?> src, Class<?> dst) {
// ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
// so we don't need to repeat so much decision making.
if (VerifyType.isNullConversion(src, dst)) {
......@@ -118,16 +113,13 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* the JVM supports ricochet adapters).
* The argument conversions allowed are casting, unboxing,
* integral widening or narrowing, and floating point widening or narrowing.
* @param token access check
* @param newType required call type
* @param target original method handle
* @return an adapter to the original handle with the desired new type,
* or the original target if the types are already identical
* or null if the adaptation cannot be made
*/
public static MethodHandle makePairwiseConvert(Access token,
MethodType newType, MethodHandle target) {
Access.check(token);
static MethodHandle makePairwiseConvert(MethodType newType, MethodHandle target) {
MethodType oldType = target.type();
if (newType == oldType) return target;
......@@ -170,9 +162,9 @@ public class AdapterMethodHandle extends BoundMethodHandle {
// It parallels canConvertArgument() above.
if (src.isPrimitive()) {
if (dst.isPrimitive()) {
adapter = makePrimCast(token, midType, adapter, i, dst);
adapter = makePrimCast(midType, adapter, i, dst);
} else {
adapter = makeBoxArgument(token, midType, adapter, i, dst);
adapter = makeBoxArgument(midType, adapter, i, dst);
}
} else {
if (dst.isPrimitive()) {
......@@ -182,13 +174,13 @@ public class AdapterMethodHandle extends BoundMethodHandle {
// conversions supported by reflect.Method.invoke.
// Those conversions require a big nest of if/then/else logic,
// which we prefer to make a user responsibility.
adapter = makeUnboxArgument(token, midType, adapter, i, dst);
adapter = makeUnboxArgument(midType, adapter, i, dst);
} else {
// Simple reference conversion.
// Note: Do not check for a class hierarchy relation
// between src and dst. In all cases a 'null' argument
// will pass the cast conversion.
adapter = makeCheckCast(token, midType, adapter, i, dst);
adapter = makeCheckCast(midType, adapter, i, dst);
}
}
assert(adapter != null);
......@@ -196,7 +188,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
}
if (adapter.type() != newType) {
// Only trivial conversions remain.
adapter = makeRetypeOnly(IMPL_TOKEN, newType, adapter);
adapter = makeRetypeOnly(newType, adapter);
assert(adapter != null);
// Actually, that's because there were no non-trivial ones:
assert(lastConv == -1);
......@@ -208,7 +200,6 @@ public class AdapterMethodHandle extends BoundMethodHandle {
/**
* Create a JVM-level adapter method handle to permute the arguments
* of the given method.
* @param token access check
* @param newType required call type
* @param target original method handle
* @param argumentMap for each target argument, position of its source in newType
......@@ -218,8 +209,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* @throws IllegalArgumentException if the adaptation cannot be made
* directly by a JVM-level adapter, without help from Java code
*/
public static MethodHandle makePermutation(Access token,
MethodType newType, MethodHandle target,
static MethodHandle makePermutation(MethodType newType, MethodHandle target,
int[] argumentMap) {
MethodType oldType = target.type();
boolean nullPermutation = true;
......@@ -234,7 +224,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
if (argumentMap.length != oldType.parameterCount())
throw newIllegalArgumentException("bad permutation: "+Arrays.toString(argumentMap));
if (nullPermutation) {
MethodHandle res = makePairwiseConvert(token, newType, target);
MethodHandle res = makePairwiseConvert(newType, target);
// well, that was easy
if (res == null)
throw newIllegalArgumentException("cannot convert pairwise: "+newType);
......@@ -435,7 +425,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
}
/** Can a retyping adapter (alone) validly convert the target to newType? */
public static boolean canRetypeOnly(MethodType newType, MethodType targetType) {
static boolean canRetypeOnly(MethodType newType, MethodType targetType) {
return canRetype(newType, targetType, false);
}
/** Can a retyping adapter (alone) convert the target to newType?
......@@ -444,7 +434,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* reference conversions on return. This last feature requires that the
* caller be trusted, and perform explicit cast conversions on return values.
*/
public static boolean canRetypeRaw(MethodType newType, MethodType targetType) {
static boolean canRetypeRaw(MethodType newType, MethodType targetType) {
return canRetype(newType, targetType, true);
}
static boolean canRetype(MethodType newType, MethodType targetType, boolean raw) {
......@@ -459,17 +449,13 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* Allows unchecked argument conversions pairwise, if they are safe.
* Returns null if not possible.
*/
public static MethodHandle makeRetypeOnly(Access token,
MethodType newType, MethodHandle target) {
return makeRetype(token, newType, target, false);
static MethodHandle makeRetypeOnly(MethodType newType, MethodHandle target) {
return makeRetype(newType, target, false);
}
public static MethodHandle makeRetypeRaw(Access token,
MethodType newType, MethodHandle target) {
return makeRetype(token, newType, target, true);
static MethodHandle makeRetypeRaw(MethodType newType, MethodHandle target) {
return makeRetype(newType, target, true);
}
static MethodHandle makeRetype(Access token,
MethodType newType, MethodHandle target, boolean raw) {
Access.check(token);
static MethodHandle makeRetype(MethodType newType, MethodHandle target, boolean raw) {
MethodType oldType = target.type();
if (oldType == newType) return target;
if (!canRetype(newType, oldType, raw))
......@@ -478,9 +464,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
return new AdapterMethodHandle(target, newType, makeConv(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY));
}
static MethodHandle makeVarargsCollector(Access token,
MethodHandle target, Class<?> arrayType) {
Access.check(token);
static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
return new AsVarargsCollector(target, arrayType);
}
......@@ -526,6 +510,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
return collector.asType(newType);
}
@Override
public MethodHandle asVarargsCollector(Class<?> arrayType) {
MethodType type = this.type();
if (type.parameterType(type.parameterCount()-1) == arrayType)
......@@ -537,7 +522,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
/** Can a checkcast adapter validly convert the target to newType?
* The JVM supports all kind of reference casts, even silly ones.
*/
public static boolean canCheckCast(MethodType newType, MethodType targetType,
static boolean canCheckCast(MethodType newType, MethodType targetType,
int arg, Class<?> castType) {
if (!convOpSupported(OP_CHECK_CAST)) return false;
Class<?> src = newType.parameterType(arg);
......@@ -549,7 +534,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
return (diff == arg+1); // arg is sole non-trivial diff
}
/** Can an primitive conversion adapter validly convert src to dst? */
public static boolean canCheckCast(Class<?> src, Class<?> dst) {
static boolean canCheckCast(Class<?> src, Class<?> dst) {
return (!src.isPrimitive() && !dst.isPrimitive());
}
......@@ -558,10 +543,8 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* with a null conversion to the corresponding target parameter.
* Return null if this cannot be done.
*/
public static MethodHandle makeCheckCast(Access token,
MethodType newType, MethodHandle target,
static MethodHandle makeCheckCast(MethodType newType, MethodHandle target,
int arg, Class<?> castType) {
Access.check(token);
if (!canCheckCast(newType, target.type(), arg, castType))
return null;
long conv = makeConv(OP_CHECK_CAST, arg, T_OBJECT, T_OBJECT);
......@@ -572,7 +555,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* The JVM currently supports all conversions except those between
* floating and integral types.
*/
public static boolean canPrimCast(MethodType newType, MethodType targetType,
static boolean canPrimCast(MethodType newType, MethodType targetType,
int arg, Class<?> convType) {
if (!convOpSupported(OP_PRIM_TO_PRIM)) return false;
Class<?> src = newType.parameterType(arg);
......@@ -584,7 +567,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
return (diff == arg+1); // arg is sole non-trivial diff
}
/** Can an primitive conversion adapter validly convert src to dst? */
public static boolean canPrimCast(Class<?> src, Class<?> dst) {
static boolean canPrimCast(Class<?> src, Class<?> dst) {
if (src == dst || !src.isPrimitive() || !dst.isPrimitive()) {
return false;
} else if (Wrapper.forPrimitiveType(dst).isFloating()) {
......@@ -604,10 +587,8 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* with a null conversion to the corresponding target parameter.
* Return null if this cannot be done.
*/
public static MethodHandle makePrimCast(Access token,
MethodType newType, MethodHandle target,
static MethodHandle makePrimCast(MethodType newType, MethodHandle target,
int arg, Class<?> convType) {
Access.check(token);
MethodType oldType = target.type();
if (!canPrimCast(newType, oldType, arg, convType))
return null;
......@@ -620,7 +601,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* The JVM currently supports all kinds of casting and unboxing.
* The convType is the unboxed type; it can be either a primitive or wrapper.
*/
public static boolean canUnboxArgument(MethodType newType, MethodType targetType,
static boolean canUnboxArgument(MethodType newType, MethodType targetType,
int arg, Class<?> convType) {
if (!convOpSupported(OP_REF_TO_PRIM)) return false;
Class<?> src = newType.parameterType(arg);
......@@ -635,15 +616,14 @@ public class AdapterMethodHandle extends BoundMethodHandle {
return (diff == arg+1); // arg is sole non-trivial diff
}
/** Can an primitive unboxing adapter validly convert src to dst? */
public static boolean canUnboxArgument(Class<?> src, Class<?> dst) {
static boolean canUnboxArgument(Class<?> src, Class<?> dst) {
return (!src.isPrimitive() && Wrapper.asPrimitiveType(dst).isPrimitive());
}
/** Factory method: Unbox the given argument.
* Return null if this cannot be done.
*/
public static MethodHandle makeUnboxArgument(Access token,
MethodType newType, MethodHandle target,
static MethodHandle makeUnboxArgument(MethodType newType, MethodHandle target,
int arg, Class<?> convType) {
MethodType oldType = target.type();
Class<?> src = newType.parameterType(arg);
......@@ -659,11 +639,11 @@ public class AdapterMethodHandle extends BoundMethodHandle {
MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType);
if (castDone == newType)
return adapter;
return makeCheckCast(token, newType, adapter, arg, boxType);
return makeCheckCast(newType, adapter, arg, boxType);
}
/** Can an primitive boxing adapter validly convert src to dst? */
public static boolean canBoxArgument(Class<?> src, Class<?> dst) {
static boolean canBoxArgument(Class<?> src, Class<?> dst) {
if (!convOpSupported(OP_PRIM_TO_REF)) return false;
throw new UnsupportedOperationException("NYI");
}
......@@ -671,15 +651,14 @@ public class AdapterMethodHandle extends BoundMethodHandle {
/** Factory method: Unbox the given argument.
* Return null if this cannot be done.
*/
public static MethodHandle makeBoxArgument(Access token,
MethodType newType, MethodHandle target,
static MethodHandle makeBoxArgument(MethodType newType, MethodHandle target,
int arg, Class<?> convType) {
// this is difficult to do in the JVM because it must GC
return null;
}
/** Can an adapter simply drop arguments to convert the target to newType? */
public static boolean canDropArguments(MethodType newType, MethodType targetType,
static boolean canDropArguments(MethodType newType, MethodType targetType,
int dropArgPos, int dropArgCount) {
if (dropArgCount == 0)
return canRetypeOnly(newType, targetType);
......@@ -706,12 +685,10 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* Allow unchecked retyping of remaining arguments, pairwise.
* Return null if this is not possible.
*/
public static MethodHandle makeDropArguments(Access token,
MethodType newType, MethodHandle target,
static MethodHandle makeDropArguments(MethodType newType, MethodHandle target,
int dropArgPos, int dropArgCount) {
Access.check(token);
if (dropArgCount == 0)
return makeRetypeOnly(IMPL_TOKEN, newType, target);
return makeRetypeOnly(newType, target);
if (!canDropArguments(newType, target.type(), dropArgPos, dropArgCount))
return null;
// in arglist: [0: ...keep1 | dpos: drop... | dpos+dcount: keep2... ]
......@@ -727,7 +704,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
}
/** Can an adapter duplicate an argument to convert the target to newType? */
public static boolean canDupArguments(MethodType newType, MethodType targetType,
static boolean canDupArguments(MethodType newType, MethodType targetType,
int dupArgPos, int dupArgCount) {
if (!convOpSupported(OP_DUP_ARGS)) return false;
if (diffReturnTypes(newType, targetType, false) != 0)
......@@ -749,10 +726,8 @@ public class AdapterMethodHandle extends BoundMethodHandle {
/** Factory method: Duplicate the selected argument.
* Return null if this is not possible.
*/
public static MethodHandle makeDupArguments(Access token,
MethodType newType, MethodHandle target,
static MethodHandle makeDupArguments(MethodType newType, MethodHandle target,
int dupArgPos, int dupArgCount) {
Access.check(token);
if (!canDupArguments(newType, target.type(), dupArgPos, dupArgCount))
return null;
if (dupArgCount == 0)
......@@ -769,7 +744,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
}
/** Can an adapter swap two arguments to convert the target to newType? */
public static boolean canSwapArguments(MethodType newType, MethodType targetType,
static boolean canSwapArguments(MethodType newType, MethodType targetType,
int swapArg1, int swapArg2) {
if (!convOpSupported(OP_SWAP_ARGS)) return false;
if (diffReturnTypes(newType, targetType, false) != 0)
......@@ -796,10 +771,8 @@ public class AdapterMethodHandle extends BoundMethodHandle {
/** Factory method: Swap the selected arguments.
* Return null if this is not possible.
*/
public static MethodHandle makeSwapArguments(Access token,
MethodType newType, MethodHandle target,
static MethodHandle makeSwapArguments(MethodType newType, MethodHandle target,
int swapArg1, int swapArg2) {
Access.check(token);
if (swapArg1 == swapArg2)
return target;
if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; }
......@@ -829,7 +802,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
final static int MAX_ARG_ROTATION = 1;
/** Can an adapter rotate arguments to convert the target to newType? */
public static boolean canRotateArguments(MethodType newType, MethodType targetType,
static boolean canRotateArguments(MethodType newType, MethodType targetType,
int firstArg, int argCount, int rotateBy) {
if (!convOpSupported(OP_ROT_ARGS)) return false;
if (argCount <= 2) return false; // must be a swap, not a rotate
......@@ -861,10 +834,8 @@ public class AdapterMethodHandle extends BoundMethodHandle {
/** Factory method: Rotate the selected argument range.
* Return null if this is not possible.
*/
public static MethodHandle makeRotateArguments(Access token,
MethodType newType, MethodHandle target,
static MethodHandle makeRotateArguments(MethodType newType, MethodHandle target,
int firstArg, int argCount, int rotateBy) {
Access.check(token);
rotateBy = positiveRotation(argCount, rotateBy);
if (!canRotateArguments(newType, target.type(), firstArg, argCount, rotateBy))
return null;
......@@ -904,7 +875,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
}
/** Can an adapter spread an argument to convert the target to newType? */
public static boolean canSpreadArguments(MethodType newType, MethodType targetType,
static boolean canSpreadArguments(MethodType newType, MethodType targetType,
Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
if (!convOpSupported(OP_SPREAD_ARGS)) return false;
if (diffReturnTypes(newType, targetType, false) != 0)
......@@ -937,10 +908,8 @@ public class AdapterMethodHandle extends BoundMethodHandle {
/** Factory method: Spread selected argument. */
public static MethodHandle makeSpreadArguments(Access token,
MethodType newType, MethodHandle target,
static MethodHandle makeSpreadArguments(MethodType newType, MethodHandle target,
Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
Access.check(token);
MethodType targetType = target.type();
if (!canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount))
return null;
......@@ -962,7 +931,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
@Override
public String toString() {
return MethodHandleImpl.getNameString(IMPL_TOKEN, nonAdapter((MethodHandle)vmtarget), this);
return getNameString(nonAdapter((MethodHandle)vmtarget), this);
}
private static MethodHandle nonAdapter(MethodHandle mh) {
......
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,15 +23,11 @@
* questions.
*/
package sun.dyn;
package java.lang.invoke;
import sun.dyn.util.VerifyType;
import sun.dyn.util.Wrapper;
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;
import sun.invoke.util.VerifyType;
import sun.invoke.util.Wrapper;
import static java.lang.invoke.MethodHandleStatics.*;
/**
* The flavor of method handle which emulates an invoke instruction
......@@ -39,37 +35,29 @@ import static sun.dyn.MemberName.newIllegalArgumentException;
* when the handle is created, not when it is invoked.
* @author jrose
*/
public class BoundMethodHandle extends MethodHandle {
class BoundMethodHandle extends MethodHandle {
//MethodHandle vmtarget; // next BMH or final DMH or methodOop
private final Object argument; // argument to insert
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.
/** Bind a direct MH to its receiver (or first ref. argument).
* The JVM will pre-dispatch the MH if it is not already static.
*/
BoundMethodHandle(DirectMethodHandle mh, Object argument) {
super(Access.TOKEN, mh.type().dropParameterTypes(0, 1));
/*non-public*/ BoundMethodHandle(DirectMethodHandle mh, Object argument) {
super(mh.type().dropParameterTypes(0, 1));
// check the type now, once for all:
this.argument = checkReferenceArgument(argument, mh, 0);
this.vmargslot = this.type().parameterSlotCount();
if (MethodHandleNatives.JVM_SUPPORT) {
this.vmtarget = null; // maybe updated by JVM
MethodHandleNatives.init(this, mh, 0);
} else {
this.vmtarget = mh;
}
initTarget(mh, 0);
}
/** Insert an argument into an arbitrary method handle.
* If argnum is zero, inserts the first argument, etc.
* The argument type must be a reference.
*/
BoundMethodHandle(MethodHandle mh, Object argument, int argnum) {
/*non-public*/ BoundMethodHandle(MethodHandle mh, Object argument, int argnum) {
this(mh.type().dropParameterTypes(argnum, argnum+1),
mh, argument, argnum);
}
......@@ -77,8 +65,8 @@ public class BoundMethodHandle extends MethodHandle {
/** Insert an argument into an arbitrary method handle.
* If argnum is zero, inserts the first argument, etc.
*/
BoundMethodHandle(MethodType type, MethodHandle mh, Object argument, int argnum) {
super(Access.TOKEN, type);
/*non-public*/ BoundMethodHandle(MethodType type, MethodHandle mh, Object argument, int argnum) {
super(type);
if (mh.type().parameterType(argnum).isPrimitive())
this.argument = bindPrimitiveArgument(argument, mh, argnum);
else {
......@@ -89,18 +77,14 @@ public class BoundMethodHandle extends MethodHandle {
}
private void initTarget(MethodHandle mh, int argnum) {
if (MethodHandleNatives.JVM_SUPPORT) {
this.vmtarget = null; // maybe updated by JVM
//this.vmtarget = mh; // maybe updated by JVM
MethodHandleNatives.init(this, mh, argnum);
} else {
this.vmtarget = mh;
}
}
/** For the AdapterMethodHandle subclass.
*/
BoundMethodHandle(MethodType type, Object argument, int vmargslot) {
super(Access.TOKEN, type);
/*non-public*/ BoundMethodHandle(MethodType type, Object argument, int vmargslot) {
super(type);
this.argument = argument;
this.vmargslot = vmargslot;
assert(this instanceof AdapterMethodHandle);
......@@ -112,8 +96,8 @@ public class BoundMethodHandle extends MethodHandle {
* same as {@code entryPoint}, except that the first argument
* type will be dropped.
*/
protected BoundMethodHandle(Access token, MethodHandle entryPoint) {
super(token, entryPoint.type().dropParameterTypes(0, 1));
/*non-public*/ BoundMethodHandle(MethodHandle entryPoint) {
super(entryPoint.type().dropParameterTypes(0, 1));
this.argument = this; // kludge; get rid of
this.vmargslot = this.type().parameterSlotDepth(0);
initTarget(entryPoint, 0);
......@@ -172,7 +156,7 @@ public class BoundMethodHandle extends MethodHandle {
@Override
public String toString() {
return MethodHandleImpl.addTypeString(baseName(), this);
return addTypeString(baseName(), this);
}
/** Component of toString() before the type string. */
......
......@@ -23,12 +23,12 @@
* questions.
*/
package java.dyn;
package java.lang.invoke;
import sun.dyn.*;
import sun.dyn.empty.Empty;
import sun.invoke.empty.Empty;
import sun.misc.Unsafe;
import java.util.Collection;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* A {@code CallSite} is a holder for a variable {@link MethodHandle},
......@@ -85,7 +85,6 @@ private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String nam
*/
abstract
public class CallSite {
private static final Access IMPL_TOKEN = Access.getToken();
static { MethodHandleImpl.initStatics(); }
// Fields used only by the JVM. Do not use or change.
......@@ -96,9 +95,6 @@ public class CallSite {
/*package-private*/
MethodHandle target;
// Remove this field for PFD and delete deprecated methods:
private MemberName calleeNameRemoveForPFD;
/**
* Make a blank call site object with the given method type.
* An initial target method is supplied which will throw
......@@ -111,7 +107,7 @@ public class CallSite {
*/
/*package-private*/
CallSite(MethodType type) {
target = MethodHandles.invokers(type).uninitializedCallSite();
target = type.invokers().uninitializedCallSite();
}
/**
......@@ -145,7 +141,7 @@ public class CallSite {
int callerBCI) {
if (this.vmmethod != null) {
// FIXME
throw new InvokeDynamicBootstrapError("call site has already been linked to an invokedynamic instruction");
throw new BootstrapMethodError("call site has already been linked to an invokedynamic instruction");
}
if (!this.type().equals(type)) {
throw wrongTargetType(target, type);
......@@ -202,7 +198,7 @@ public class CallSite {
}
/**
* Produce a method handle equivalent to an invokedynamic instruction
* Produces a method handle equivalent to an invokedynamic instruction
* which has been linked to this call site.
* <p>
* This method is equivalent to the following code:
......@@ -218,7 +214,7 @@ public class CallSite {
public abstract MethodHandle dynamicInvoker();
/*non-public*/ MethodHandle makeDynamicInvoker() {
MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, GET_TARGET, this);
MethodHandle getTarget = MethodHandleImpl.bindReceiver(GET_TARGET, this);
MethodHandle invoker = MethodHandles.exactInvoker(this.type());
return MethodHandles.foldArguments(invoker, getTarget);
}
......@@ -226,7 +222,7 @@ public class CallSite {
private static final MethodHandle GET_TARGET;
static {
try {
GET_TARGET = MethodHandles.Lookup.IMPL_LOOKUP.
GET_TARGET = IMPL_LOOKUP.
findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
} catch (ReflectiveOperationException ignore) {
throw new InternalError();
......@@ -252,7 +248,6 @@ public class CallSite {
/*package-private*/
void setTargetNormal(MethodHandle newTarget) {
target = newTarget;
//CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget);
}
/*package-private*/
MethodHandle getTargetVolatile() {
......@@ -261,6 +256,68 @@ public class CallSite {
/*package-private*/
void setTargetVolatile(MethodHandle newTarget) {
unsafe.putObjectVolatile(this, TARGET_OFFSET, newTarget);
//CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget);
}
// this implements the upcall from the JVM, MethodHandleNatives.makeDynamicCallSite:
static CallSite makeSite(MethodHandle bootstrapMethod,
// Callee information:
String name, MethodType type,
// Extra arguments for BSM, if any:
Object info,
// Caller information:
MemberName callerMethod, int callerBCI) {
Class<?> callerClass = callerMethod.getDeclaringClass();
Object caller = IMPL_LOOKUP.in(callerClass);
CallSite site;
try {
Object binding;
info = maybeReBox(info);
if (info == null) {
binding = bootstrapMethod.invokeGeneric(caller, name, type);
} else if (!info.getClass().isArray()) {
binding = bootstrapMethod.invokeGeneric(caller, name, type, info);
} else {
Object[] argv = (Object[]) info;
maybeReBoxElements(argv);
if (3 + argv.length > 255)
throw new BootstrapMethodError("too many bootstrap method arguments");
MethodType bsmType = bootstrapMethod.type();
if (bsmType.parameterCount() == 4 && bsmType.parameterType(3) == Object[].class)
binding = bootstrapMethod.invokeGeneric(caller, name, type, argv);
else
binding = MethodHandles.spreadInvoker(bsmType, 3)
.invokeGeneric(bootstrapMethod, caller, name, type, argv);
}
//System.out.println("BSM for "+name+type+" => "+binding);
if (binding instanceof CallSite) {
site = (CallSite) binding;
} else {
throw new ClassCastException("bootstrap method failed to produce a CallSite");
}
assert(site.getTarget() != null);
assert(site.getTarget().type().equals(type));
} catch (Throwable ex) {
BootstrapMethodError bex;
if (ex instanceof BootstrapMethodError)
bex = (BootstrapMethodError) ex;
else
bex = new BootstrapMethodError("call site initialization exception", ex);
throw bex;
}
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;
}
private static void maybeReBoxElements(Object[] xa) {
for (int i = 0; i < xa.length; i++) {
xa[i] = maybeReBox(xa[i]);
}
}
}
......@@ -23,7 +23,7 @@
* questions.
*/
package java.dyn;
package java.lang.invoke;
/**
* A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed.
......
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,10 +23,9 @@
* questions.
*/
package sun.dyn;
package java.lang.invoke;
import java.dyn.*;
import static sun.dyn.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
/**
* The flavor of method handle which emulates invokespecial or invokestatic.
......@@ -39,7 +38,7 @@ class DirectMethodHandle extends MethodHandle {
// Constructors in this class *must* be package scoped or private.
DirectMethodHandle(MethodType mtype, MemberName m, boolean doDispatch, Class<?> lookupClass) {
super(Access.TOKEN, mtype);
super(mtype);
assert(m.isMethod() || !doDispatch && m.isConstructor());
if (!m.isResolved())
......
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,11 +23,11 @@
* questions.
*/
package sun.dyn;
package java.lang.invoke;
import java.dyn.*;
import java.lang.reflect.*;
import static sun.dyn.MemberName.newIllegalArgumentException;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* These adapters apply arbitrary conversions to arguments
......@@ -123,7 +123,7 @@ class FilterGeneric {
MethodType entryType = entryType(kind, pos, filterType, targetType);
if (entryType.generic() != entryType)
throw newIllegalArgumentException("must be generic: "+entryType);
MethodTypeImpl form = MethodTypeImpl.of(entryType);
MethodTypeForm form = entryType.form();
FilterGeneric filterGen = form.filterGeneric;
if (filterGen == null)
form.filterGeneric = filterGen = new FilterGeneric(entryType);
......@@ -186,7 +186,7 @@ class FilterGeneric {
// see if it has the required invoke method
MethodHandle entryPoint = null;
try {
entryPoint = MethodHandleImpl.IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
entryPoint = IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
} catch (ReflectiveOperationException ex) {
}
if (entryPoint == null) continue;
......@@ -231,7 +231,7 @@ class FilterGeneric {
@Override
public String toString() {
return MethodHandleImpl.addTypeString(target, this);
return addTypeString(target, this);
}
protected boolean isPrototype() { return target == null; }
......@@ -246,7 +246,7 @@ class FilterGeneric {
protected Adapter(MethodHandle entryPoint,
MethodHandle filter, MethodHandle target) {
super(Access.TOKEN, entryPoint);
super(entryPoint);
this.filter = filter;
this.target = target;
}
......@@ -256,7 +256,7 @@ class FilterGeneric {
MethodHandle filter, MethodHandle target);
// { return new ThisType(entryPoint, filter, target); }
static private final String CLASS_PREFIX; // "sun.dyn.FilterGeneric$"
static private final String CLASS_PREFIX; // "java.lang.invoke.FilterGeneric$"
static {
String aname = Adapter.class.getName();
String sname = Adapter.class.getSimpleName();
......
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,10 +23,10 @@
* questions.
*/
package sun.dyn;
package java.lang.invoke;
import java.dyn.*;
import static sun.dyn.MemberName.uncaughtException;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* Unary function composition, useful for many small plumbing jobs.
......@@ -36,7 +36,7 @@ import static sun.dyn.MemberName.uncaughtException;
* final method type is the responsibility of a JVM-level adapter.
* @author jrose
*/
public class FilterOneArgument extends BoundMethodHandle {
class FilterOneArgument extends BoundMethodHandle {
protected final MethodHandle filter; // Object -> Object
protected final MethodHandle target; // Object -> Object
......@@ -54,7 +54,7 @@ public class FilterOneArgument extends BoundMethodHandle {
static {
try {
INVOKE =
MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "invoke",
IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "invoke",
MethodType.genericMethodType(1));
} catch (ReflectiveOperationException ex) {
throw uncaughtException(ex);
......@@ -62,7 +62,7 @@ public class FilterOneArgument extends BoundMethodHandle {
}
protected FilterOneArgument(MethodHandle filter, MethodHandle target) {
super(Access.TOKEN, INVOKE);
super(INVOKE);
this.filter = filter;
this.target = target;
}
......
......@@ -23,12 +23,13 @@
* questions.
*/
package sun.dyn;
package java.lang.invoke;
import java.dyn.*;
import sun.invoke.util.ValueConversions;
import sun.invoke.util.Wrapper;
import java.lang.reflect.*;
import sun.dyn.util.*;
import static sun.dyn.MethodTypeImpl.invokers;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* Adapters which mediate between incoming calls which are generic
......@@ -82,8 +83,8 @@ class FromGeneric {
}
// outgoing primitive arguments will be wrapped; unwrap them
MethodType primsAsObj = MethodTypeImpl.of(targetType).primArgsAsBoxes();
MethodType objArgsRawRet = MethodTypeImpl.of(primsAsObj).primsAsInts();
MethodType primsAsObj = targetType.form().primArgsAsBoxes();
MethodType objArgsRawRet = primsAsObj.form().primsAsInts();
if (objArgsRawRet != targetType)
ad = findAdapter(internalType0 = objArgsRawRet);
if (ad == null) {
......@@ -129,16 +130,16 @@ class FromGeneric {
MethodType targetType, MethodType internalType) {
// All the adapters we have here have reference-untyped internal calls.
assert(internalType == internalType.erase());
MethodHandle invoker = invokers(targetType).exactInvoker();
MethodHandle invoker = targetType.invokers().exactInvoker();
// cast all narrow reference types, unbox all primitive arguments:
MethodType fixArgsType = internalType.changeReturnType(targetType.returnType());
MethodHandle fixArgs = AdapterMethodHandle.convertArguments(Access.TOKEN,
MethodHandle fixArgs = MethodHandleImpl.convertArguments(
invoker, Invokers.invokerType(fixArgsType),
invoker.type(), null);
if (fixArgs == null)
throw new InternalError("bad fixArgs");
// reinterpret the calling sequence as raw:
MethodHandle retyper = AdapterMethodHandle.makeRetypeRaw(Access.TOKEN,
MethodHandle retyper = AdapterMethodHandle.makeRetypeRaw(
Invokers.invokerType(internalType), fixArgs);
if (retyper == null)
throw new InternalError("bad retyper");
......@@ -171,7 +172,7 @@ class FromGeneric {
/** Return the adapter information for this type's erasure. */
static FromGeneric of(MethodType type) {
MethodTypeImpl form = MethodTypeImpl.of(type);
MethodTypeForm form = type.form();
FromGeneric fromGen = form.fromGeneric;
if (fromGen == null)
form.fromGeneric = fromGen = new FromGeneric(form.erasedType());
......@@ -185,7 +186,7 @@ class FromGeneric {
/* Create an adapter that handles spreading calls for the given type. */
static Adapter findAdapter(MethodType internalType) {
MethodType entryType = internalType.generic();
MethodTypeImpl form = MethodTypeImpl.of(internalType);
MethodTypeForm form = internalType.form();
Class<?> rtype = internalType.returnType();
int argc = form.parameterCount();
int lac = form.longPrimitiveParameterCount();
......@@ -203,7 +204,7 @@ class FromGeneric {
// see if it has the required invoke method
MethodHandle entryPoint = null;
try {
entryPoint = MethodHandleImpl.IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
entryPoint = IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
} catch (ReflectiveOperationException ex) {
}
if (entryPoint == null) continue;
......@@ -257,7 +258,7 @@ class FromGeneric {
@Override
public String toString() {
return MethodHandleImpl.addTypeString(target, this);
return addTypeString(target, this);
}
protected boolean isPrototype() { return target == null; }
......@@ -272,7 +273,7 @@ class FromGeneric {
protected Adapter(MethodHandle entryPoint,
MethodHandle invoker, MethodHandle convert, MethodHandle target) {
super(Access.TOKEN, entryPoint);
super(entryPoint);
this.invoker = invoker;
this.convert = convert;
this.target = target;
......@@ -290,7 +291,7 @@ class FromGeneric {
protected Object convert_F(float result) throws Throwable { return convert.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; // "java.lang.invoke.FromGeneric$"
static {
String aname = Adapter.class.getName();
String sname = Adapter.class.getSimpleName();
......
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,7 +23,7 @@
* questions.
*/
package java.dyn;
package java.lang.invoke;
/**
* This is a place-holder class. Some HotSpot implementations need to see it.
......
......@@ -23,15 +23,13 @@
* questions.
*/
package sun.dyn;
package java.lang.invoke;
import java.dyn.*;
import java.lang.reflect.*;
import sun.dyn.util.*;
import static sun.dyn.MethodTypeImpl.invokers;
import sun.invoke.util.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* Adapters which manage MethodHanndle.invokeGeneric calls.
* Adapters which manage MethodHandle.invokeGeneric calls.
* The JVM calls one of these when the exact type match fails.
* @author jrose
*/
......@@ -44,7 +42,8 @@ class InvokeGeneric {
/** 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 ReflectiveOperationException {
/*non-public*/ InvokeGeneric(MethodType erasedCallerType) throws ReflectiveOperationException {
assert(erasedCallerType.equals(erasedCallerType.erase()));
this.erasedCallerType = erasedCallerType;
this.initialInvoker = makeInitialInvoker();
assert initialInvoker.type().equals(erasedCallerType
......@@ -53,22 +52,13 @@ class InvokeGeneric {
}
private static MethodHandles.Lookup lookup() {
return MethodHandleImpl.IMPL_LOOKUP;
return 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 (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
}
return genericInvoker;
/*non-public*/ static MethodHandle genericInvokerOf(MethodType erasedCallerType) throws ReflectiveOperationException {
InvokeGeneric gen = new InvokeGeneric(erasedCallerType);
return gen.initialInvoker;
}
private MethodHandle makeInitialInvoker() throws ReflectiveOperationException {
......@@ -88,7 +78,7 @@ class InvokeGeneric {
private MethodHandle makePostDispatchInvoker() {
// Take (MH'; MT, MH; A...) and run MH'(MT, MH; A...).
MethodType invokerType = erasedCallerType.insertParameterTypes(0, EXTRA_ARGS);
return invokers(invokerType).exactInvoker();
return invokerType.invokers().exactInvoker();
}
private MethodHandle dropDispatchArguments(MethodHandle targetInvoker) {
assert(targetInvoker.type().parameterType(0) == MethodHandle.class);
......@@ -112,7 +102,7 @@ class InvokeGeneric {
if (USE_AS_TYPE_PATH || target.isVarargsCollector()) {
MethodHandle newTarget = target.asType(callerType);
targetType = callerType;
Invokers invokers = MethodTypeImpl.invokers(Access.TOKEN, targetType);
Invokers invokers = targetType.invokers();
MethodHandle invoker = invokers.erasedInvokerWithDrops;
if (invoker == null) {
invokers.erasedInvokerWithDrops = invoker =
......
......@@ -23,16 +23,16 @@
* questions.
*/
package sun.dyn;
package java.lang.invoke;
import java.dyn.*;
import sun.dyn.empty.Empty;
import sun.invoke.empty.Empty;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* Construction and caching of often-used invokers.
* @author jrose
*/
public class Invokers {
class Invokers {
// exact type (sans leading taget MH) for the outgoing call
private final MethodType targetType;
......@@ -60,15 +60,15 @@ public class Invokers {
this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1];
}
public static MethodType invokerType(MethodType targetType) {
/*non-public*/ static MethodType invokerType(MethodType targetType) {
return targetType.insertParameterTypes(0, MethodHandle.class);
}
public MethodHandle exactInvoker() {
/*non-public*/ MethodHandle exactInvoker() {
MethodHandle invoker = exactInvoker;
if (invoker != null) return invoker;
try {
invoker = MethodHandleImpl.IMPL_LOOKUP.findVirtual(MethodHandle.class, "invokeExact", targetType);
invoker = IMPL_LOOKUP.findVirtual(MethodHandle.class, "invokeExact", targetType);
} catch (ReflectiveOperationException ex) {
throw new InternalError("JVM cannot find invoker for "+targetType);
}
......@@ -77,7 +77,7 @@ public class Invokers {
return invoker;
}
public MethodHandle genericInvoker() {
/*non-public*/ MethodHandle genericInvoker() {
MethodHandle invoker1 = exactInvoker();
MethodHandle invoker = genericInvoker;
if (invoker != null) return invoker;
......@@ -87,7 +87,7 @@ public class Invokers {
return invoker;
}
public MethodHandle erasedInvoker() {
/*non-public*/ MethodHandle erasedInvoker() {
MethodHandle invoker1 = exactInvoker();
MethodHandle invoker = erasedInvoker;
if (invoker != null) return invoker;
......@@ -100,7 +100,7 @@ public class Invokers {
return invoker;
}
public MethodHandle spreadInvoker(int objectArgCount) {
/*non-public*/ MethodHandle spreadInvoker(int objectArgCount) {
MethodHandle vaInvoker = spreadInvokers[objectArgCount];
if (vaInvoker != null) return vaInvoker;
MethodHandle gInvoker = genericInvoker();
......@@ -111,12 +111,12 @@ public class Invokers {
private static MethodHandle THROW_UCS = null;
public MethodHandle uninitializedCallSite() {
/*non-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(type0);
Invokers invokers0 = type0.invokers();
invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(),
0, targetType.parameterList());
assert(invoker.type().equals(targetType));
......@@ -125,14 +125,14 @@ public class Invokers {
}
if (THROW_UCS == null) {
try {
THROW_UCS = MethodHandleImpl.IMPL_LOOKUP
THROW_UCS = IMPL_LOOKUP
.findStatic(CallSite.class, "uninitializedCallSite",
MethodType.methodType(Empty.class));
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
}
invoker = AdapterMethodHandle.makeRetypeRaw(Access.TOKEN, targetType, THROW_UCS);
invoker = AdapterMethodHandle.makeRetypeRaw(targetType, THROW_UCS);
assert(invoker.type().equals(targetType));
uninitializedCallSite = invoker;
return invoker;
......
......@@ -23,10 +23,9 @@
* questions.
*/
package sun.dyn;
package java.lang.invoke;
import sun.dyn.util.BytecodeDescriptor;
import java.dyn.*;
import sun.invoke.util.BytecodeDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
......@@ -37,7 +36,8 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import static sun.dyn.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandleStatics.*;
/**
* A {@code MemberName} is a compact symbolic datum which fully characterizes
......@@ -66,7 +66,7 @@ import static sun.dyn.MethodHandleNatives.Constants.*;
* and those seven fields omit much of the information in Method.
* @author jrose
*/
public final class MemberName implements Member, Cloneable {
/*non-public*/ final class MemberName implements Member, Cloneable {
private Class<?> clazz; // class in which the method is defined
private String name; // may be null if not yet materialized
private Object type; // may be null if not yet materialized
......@@ -435,7 +435,7 @@ public final class MemberName implements Member, Cloneable {
/** Query whether this member name is resolved to a non-static, non-final method.
*/
public boolean hasReceiverTypeDispatch() {
return (isMethod() && getVMIndex(Access.TOKEN) >= 0);
return (isMethod() && getVMIndex() >= 0);
}
/** Produce a string form of this member name.
......@@ -490,59 +490,38 @@ public final class MemberName implements Member, Cloneable {
// Queries to the JVM:
/** Document? */
public int getVMIndex(Access token) {
Access.check(token);
/*non-public*/ int getVMIndex() {
if (!isResolved())
throw newIllegalStateException("not resolved");
throw newIllegalStateException("not resolved", this);
return vmindex;
}
// public Object getVMTarget(Access token) {
// Access.check(token);
// /*non-public*/ Object getVMTarget() {
// if (!isResolved())
// throw newIllegalStateException("not resolved");
// throw newIllegalStateException("not resolved", this);
// return vmtarget;
// }
private RuntimeException newIllegalStateException(String message) {
return new IllegalStateException(message+": "+this);
}
// handy shared exception makers (they simplify the common case code)
public static RuntimeException newIllegalArgumentException(String message) {
return new IllegalArgumentException(message);
}
public static IllegalAccessException newNoAccessException(MemberName name, Object from) {
return newNoAccessException("cannot access", name, from);
}
public static IllegalAccessException newNoAccessException(String message,
MemberName name, Object from) {
message += ": " + name;
public IllegalAccessException makeAccessException(String message, Object from) {
message = message + ": "+ toString();
if (from != null) message += ", from " + from;
return new IllegalAccessException(message);
}
public static ReflectiveOperationException newNoAccessException(MemberName name) {
if (name.isResolved())
return new IllegalAccessException(name.toString());
else if (name.isConstructor())
return new NoSuchMethodException(name.toString());
else if (name.isMethod())
return new NoSuchMethodException(name.toString());
public ReflectiveOperationException makeAccessException(String message) {
message = message + ": "+ toString();
if (isResolved())
return new IllegalAccessException(message);
else if (isConstructor())
return new NoSuchMethodException(message);
else if (isMethod())
return new NoSuchMethodException(message);
else
return new NoSuchFieldException(name.toString());
}
public static Error uncaughtException(Exception ex) {
Error err = new InternalError("uncaught exception");
err.initCause(ex);
return err;
return new NoSuchFieldException(message);
}
/** Actually making a query requires an access check. */
public static Factory getFactory(Access token) {
Access.check(token);
/*non-public*/ static Factory getFactory() {
return Factory.INSTANCE;
}
public static Factory getFactory() {
return getFactory(Access.getToken());
}
/** A factory type for resolving member names with the help of the VM.
* TBD: Define access-safe public constructors for this factory.
*/
......@@ -662,7 +641,7 @@ public final class MemberName implements Member, Cloneable {
MemberName result = resolveOrNull(m, searchSupers, lookupClass);
if (result != null)
return result;
ReflectiveOperationException ex = newNoAccessException(m);
ReflectiveOperationException ex = m.makeAccessException("no access");
if (ex instanceof IllegalAccessException) throw (IllegalAccessException) ex;
throw nsmClass.cast(ex);
}
......
......@@ -23,15 +23,10 @@
* questions.
*/
package java.dyn;
package java.lang.invoke;
//import sun.dyn.*;
import sun.dyn.Access;
import sun.dyn.MethodHandleImpl;
import static java.dyn.MethodHandles.invokers; // package-private API
import static sun.dyn.MemberName.newIllegalArgumentException; // utility
import static java.lang.invoke.MethodHandleStatics.*;
/**
* A method handle is a typed, directly executable reference to an underlying method,
......@@ -40,14 +35,8 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* These transformations are quite general, and include such patterns as
* {@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>
* {@linkplain java.lang.invoke.MethodHandles#dropArguments deletion},
* and {@linkplain java.lang.invoke.MethodHandles#filterArguments substitution}.
*
* <h3>Method handle contents</h3>
* Method handles are dynamically and strongly typed according to type descriptor.
......@@ -56,7 +45,7 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* the method handle's own {@linkplain #type method type}.
* <p>
* Every method handle reports its type via the {@link #type type} accessor.
* This type descriptor is a {@link java.dyn.MethodType MethodType} object,
* This type descriptor is a {@link java.lang.invoke.MethodType MethodType} object,
* whose structure is a series of classes, one of which is
* the return type of the method (or {@code void.class} if none).
* <p>
......@@ -156,7 +145,7 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* This allows a more powerful negotiation of method type
* between caller and callee.
* <p>
* (Note: The adjusted method handle {@code M2} is not directly observable,
* (<em>Note:</em> The adjusted method handle {@code M2} is not directly observable,
* and implementations are therefore not required to materialize it.)
*
* <h3>Invocation checking</h3>
......@@ -204,11 +193,11 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* Java code can create a method handle that directly accesses
* any method, constructor, or field that is accessible to that code.
* This is done via a reflective, capability-based API called
* {@link java.dyn.MethodHandles.Lookup MethodHandles.Lookup}
* {@link java.lang.invoke.MethodHandles.Lookup MethodHandles.Lookup}
* For example, a static method handle can be obtained
* from {@link java.dyn.MethodHandles.Lookup#findStatic Lookup.findStatic}.
* from {@link java.lang.invoke.MethodHandles.Lookup#findStatic Lookup.findStatic}.
* There are also conversion methods from Core Reflection API objects,
* such as {@link java.dyn.MethodHandles.Lookup#unreflect Lookup.unreflect}.
* such as {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect}.
* <p>
* Like classes and strings, method handles that correspond to accessible
* fields, methods, and constructors can also be represented directly
......@@ -269,7 +258,7 @@ mh = mh.asType(mt);
x = mh.invokeExact((Object)1, (Object)2, (Object)3);
// invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
assert(x.equals(java.util.Arrays.asList(1,2,3)));
// mt is { =&gt; int}
// mt is int()
mt = MethodType.methodType(int.class);
mh = lookup.findVirtual(java.util.List.class, "size", mt);
i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));
......@@ -325,15 +314,15 @@ mh.invokeExact(System.out, "Hello, world.");
* <p>
* For the sake of tools (but not as a programming API), the signature polymorphic
* methods are marked with a private yet standard annotation,
* {@code @java.dyn.MethodHandle.PolymorphicSignature}.
* {@code @java.lang.invoke.MethodHandle.PolymorphicSignature}.
* The annotation's retention is {@code RUNTIME}, so that all tools can see it.
*
* <h3>Formal rules for processing signature polymorphic methods</h3>
* <p>
* The following methods (and no others) are signature polymorphic:
* <ul>
* <li>{@link java.dyn.MethodHandle#invokeExact MethodHandle.invokeExact}
* <li>{@link java.dyn.MethodHandle#invokeGeneric MethodHandle.invokeGeneric}
* <li>{@link java.lang.invoke.MethodHandle#invokeExact MethodHandle.invokeExact}
* <li>{@link java.lang.invoke.MethodHandle#invokeGeneric MethodHandle.invokeGeneric}
* </ul>
* <p>
* A signature polymorphic method will be declared with the following properties:
......@@ -341,7 +330,7 @@ mh.invokeExact(System.out, "Hello, world.");
* <li>It must be native.
* <li>It must take a single varargs parameter of the form {@code Object...}.
* <li>It must produce a return value of type {@code Object}.
* <li>It must be contained within the {@code java.dyn} package.
* <li>It must be contained within the {@code java.lang.invoke} package.
* </ul>
* Because of these requirements, a signature polymorphic method is able to accept
* any number and type of actual arguments, and can, with a cast, produce a value of any type.
......@@ -354,7 +343,7 @@ mh.invokeExact(System.out, "Hello, world.");
* <p>
* In an argument position of a method invocation on a signature polymorphic method,
* a null literal has type {@code java.lang.Void}, unless cast to a reference type.
* (Note: This typing rule allows the null type to have its own encoding in linkage information
* (<em>Note:</em> This typing rule allows the null type to have its own encoding in linkage information
* distinct from other types.
* <p>
* The linkage information for the return type is derived from a context-dependent target typing convention.
......@@ -374,12 +363,12 @@ mh.invokeExact(System.out, "Hello, world.");
* and without implicit boxing or unboxing.
*
* <h3>Interoperation between method handles and the Core Reflection API</h3>
* Using factory methods in the {@link java.dyn.MethodHandles.Lookup Lookup} API,
* Using factory methods in the {@link java.lang.invoke.MethodHandles.Lookup Lookup} API,
* any class member represented by a Core Reflection API object
* can be converted to a behaviorally equivalent method handle.
* For example, a reflective {@link java.lang.reflect.Method Method} can
* be converted to a method handle using
* {@link java.dyn.MethodHandles.Lookup#unreflect Lookup.unreflect}.
* {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect}.
* The resulting method handles generally provide more direct and efficient
* access to the underlying class members.
* <p>
......@@ -398,9 +387,9 @@ mh.invokeExact(System.out, "Hello, world.");
* they will throw {@code UnsupportedOperationException}.
* <p>
* In order to obtain an invoker method for a particular type descriptor,
* use {@link java.dyn.MethodHandles#exactInvoker MethodHandles.exactInvoker},
* or {@link java.dyn.MethodHandles#genericInvoker MethodHandles.genericInvoker}.
* The {@link java.dyn.MethodHandles.Lookup#findVirtual Lookup.findVirtual}
* use {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker},
* or {@link java.lang.invoke.MethodHandles#genericInvoker MethodHandles.genericInvoker}.
* The {@link java.lang.invoke.MethodHandles.Lookup#findVirtual Lookup.findVirtual}
* API is also able to return a method handle
* to call {@code invokeExact} or {@code invokeGeneric},
* for any specified type descriptor .
......@@ -436,12 +425,35 @@ mh.invokeExact(System.out, "Hello, world.");
* @see MethodHandles
* @author John Rose, JSR 292 EG
*/
public abstract class MethodHandle
// 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 MethodHandleImpl
{
private static Access IMPL_TOKEN = Access.getToken();
public abstract class MethodHandle {
// { JVM internals:
private byte vmentry; // adapter stub or method entry point
//private int vmslots; // optionally, hoist type.form.vmslots
/*non-public*/ Object vmtarget; // VM-specific, class-specific target value
// TO DO: vmtarget should be invisible to Java, since the JVM puts internal
// managed pointers into it. Making it visible exposes it to debuggers,
// which can cause errors when they treat the pointer as an Object.
// These two dummy fields are present to force 'I' and 'J' signatures
// into this class's constant pool, so they can be transferred
// to vmentry when this class is loaded.
static final int INT_FIELD = 0;
static final long LONG_FIELD = 0;
// vmentry (a void* field) is used *only* by the JVM.
// The JVM adjusts its type to int or long depending on system wordsize.
// Since it is statically typed as neither int nor long, it is impossible
// to use this field from Java bytecode. (Please don't try to, either.)
// The vmentry is an assembly-language stub which is jumped to
// immediately after the method type is verified.
// For a direct MH, this stub loads the vmtarget's entry point
// and jumps to it.
// } End of JVM internals.
static { MethodHandleImpl.initStatics(); }
// interface MethodHandle<R throws X extends Exception,A...>
......@@ -458,7 +470,7 @@ public abstract class MethodHandle
private MethodType type;
/**
* Report the type of this method handle.
* Reports the type of this method handle.
* Every invocation of this method handle via {@code invokeExact} must exactly match this type.
* @return the method handle type
*/
......@@ -467,39 +479,18 @@ public abstract class MethodHandle
}
/**
* <em>CONSTRUCTOR WILL BE REMOVED FOR PFD:</em>
* Temporary constructor in early versions of the Reference Implementation.
* Method handle inheritance (if any) will be contained completely within
* the {@code java.dyn} package.
* Package-private constructor for the method handle implementation hierarchy.
* Method handle inheritance will be contained completely within
* the {@code java.lang.invoke} package.
*/
// 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) {
super(token);
Access.check(token);
this.type = type;
}
private void initType(MethodType type) {
/*non-public*/ MethodHandle(MethodType type) {
type.getClass(); // elicit NPE
if (this.type != null) throw new InternalError();
this.type = type;
}
static {
// This hack allows the implementation package special access to
// the internals of MethodHandle. In particular, the MTImpl has all sorts
// of cached information useful to the implementation code.
MethodHandleImpl.setMethodHandleFriend(IMPL_TOKEN, new MethodHandleImpl.MethodHandleFriend() {
public void initType(MethodHandle mh, MethodType type) { mh.initType(type); }
});
}
/**
* Invoke the method handle, allowing any caller type descriptor, but requiring an exact type match.
* Invokes the method handle, allowing any caller type descriptor, but requiring an exact type match.
* The type descriptor at the call site of {@code invokeExact} must
* exactly match this method handle's {@link #type type}.
* No conversions are allowed on arguments or return values.
......@@ -508,7 +499,7 @@ public abstract class MethodHandle
* it will appear as a single native method, taking an object array and returning an object.
* If this native method is invoked directly via
* {@link java.lang.reflect.Method#invoke Method.invoke}, via JNI,
* or indirectly via {@link java.dyn.MethodHandles.Lookup#unreflect Lookup.unreflect},
* or indirectly via {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect},
* it will throw an {@code UnsupportedOperationException}.
* @throws WrongMethodTypeException if the target's type is not identical with the caller's type descriptor
* @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
......@@ -516,7 +507,7 @@ public abstract class MethodHandle
public final native @PolymorphicSignature Object invokeExact(Object... args) throws Throwable;
/**
* Invoke the method handle, allowing any caller type descriptor,
* Invokes the method handle, allowing any caller type descriptor,
* and optionally performing conversions on arguments and return values.
* <p>
* If the call site type descriptor exactly matches this method handle's {@link #type type},
......@@ -542,7 +533,7 @@ public abstract class MethodHandle
* it will appear as a single native method, taking an object array and returning an object.
* If this native method is invoked directly via
* {@link java.lang.reflect.Method#invoke Method.invoke}, via JNI,
* or indirectly via {@link java.dyn.MethodHandles.Lookup#unreflect Lookup.unreflect},
* or indirectly via {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect},
* it will throw an {@code UnsupportedOperationException}.
* @throws WrongMethodTypeException if the target's type cannot be adjusted to the caller's type descriptor
* @throws ClassCastException if the target's type can be adjusted to the caller, but a reference cast fails
......@@ -551,7 +542,7 @@ public abstract class MethodHandle
public final native @PolymorphicSignature Object invokeGeneric(Object... args) throws Throwable;
/**
* Perform a varargs invocation, passing the arguments in the given array
* Performs a varargs invocation, passing the arguments in the given array
* 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
* of the argument array.
......@@ -608,7 +599,7 @@ public abstract class MethodHandle
return asType(MethodType.genericMethodType(argc)).invokeWithArguments(arguments);
}
if (argc <= 10) {
MethodHandle invoker = invokers(type).genericInvoker();
MethodHandle invoker = type.invokers().genericInvoker();
switch (argc) {
case 0: return invoker.invokeExact(this);
case 1: return invoker.invokeExact(this,
......@@ -647,17 +638,34 @@ public abstract class MethodHandle
}
// more than ten arguments get boxed in a varargs list:
MethodHandle invoker = invokers(type).spreadInvoker(0);
MethodHandle invoker = type.invokers().spreadInvoker(0);
return invoker.invokeExact(this, arguments);
}
/** Equivalent to {@code invokeWithArguments(arguments.toArray())}. */
/**
* Performs a varargs invocation, passing the arguments in the given array
* 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
* of the argument array.
* <p>
* This method is also equivalent to the following code:
* <p><blockquote><pre>
* {@link #invokeWithArguments(Object...) invokeWithArguments}(arguments.toArray())
* </pre></blockquote>
*
* @param arguments the arguments to pass to the target
* @return the result returned by the target
* @throws ClassCastException if an argument cannot be converted by reference casting
* @throws WrongMethodTypeException if the target's type cannot be adjusted to take the given number of {@code Object} arguments
* @throws Throwable anything thrown by the target method invocation
*/
public Object invokeWithArguments(java.util.List<?> arguments) throws Throwable {
return invokeWithArguments(arguments.toArray());
}
/**
* Produce an adapter method handle which adapts the type of the
* current method handle to a new type
* Produces an adapter method handle which adapts the type of the
* current method handle to a new type.
* The resulting method handle is guaranteed to report a type
* which is equal to the desired new type.
* <p>
......@@ -685,7 +693,7 @@ public abstract class MethodHandle
}
/**
* Make an adapter which accepts a trailing array argument
* Makes an adapter which accepts a trailing array argument
* and spreads its elements as positional arguments.
* The new method handle adapts, as its <i>target</i>,
* the current method handle. The type of the adapter will be
......@@ -733,7 +741,7 @@ public abstract class MethodHandle
}
/**
* Make an adapter which accepts a given number of trailing
* Makes an adapter which accepts a given number of trailing
* positional arguments and collects them into an array argument.
* The new method handle adapts, as its <i>target</i>,
* the current method handle. The type of the adapter will be
......@@ -784,7 +792,7 @@ public abstract class MethodHandle
}
/**
* Make a <em>variable arity</em> adapter which is able to accept
* Makes a <em>variable arity</em> adapter which is able to accept
* any number of trailing positional arguments and collect them
* into an array argument.
* <p>
......@@ -942,12 +950,12 @@ assert(failed);
}
/**
* Determine if this method handle
* Determines if this method handle
* supports {@linkplain #asVarargsCollector variable arity} calls.
* Such method handles arise from the following sources:
* <ul>
* <li>a call to {@linkplain #asVarargsCollector asVarargsCollector}
* <li>a call to a {@linkplain java.dyn.MethodHandles.Lookup lookup method}
* <li>a call to a {@linkplain java.lang.invoke.MethodHandles.Lookup lookup method}
* which resolves to a variable arity Java method or constructor
* <li>an {@code ldc} instruction of a {@code CONSTANT_MethodHandle}
* which resolves to a variable arity Java method or constructor
......@@ -960,9 +968,9 @@ assert(failed);
}
/**
* Bind a value {@code x} to the first argument of a method handle, without invoking it.
* Binds a value {@code x} to the first argument of a method handle, without invoking it.
* The new method handle adapts, as its <i>target</i>,
* to the current method handle.
* the current method handle by binding it to the given argument.
* The type of the bound handle will be
* the same as the type of the target, except that a single leading
* reference parameter will be omitted.
......@@ -974,9 +982,12 @@ assert(failed);
* <p>
* The reference {@code x} must be convertible to the first parameter
* type of the target.
* <p>
* (<em>Note:</em> Because method handles are immutable, the target method handle
* retains its original type and behavior.)
* @param x the value to bind to the first argument of the target
* @return a new method handle which collects some trailing argument
* into an array, before calling the original method handle
* @return a new method handle which prepends the given value to the incoming
* argument list, before calling the original method handle
* @throws IllegalArgumentException if the target does not have a
* leading parameter type that is a reference type
* @throws ClassCastException if {@code x} cannot be converted
......@@ -984,7 +995,15 @@ assert(failed);
* @see MethodHandles#insertArguments
*/
public MethodHandle bindTo(Object x) {
return MethodHandles.insertArguments(this, 0, x);
Class<?> ptype;
if (type().parameterCount() == 0 ||
(ptype = type().parameterType(0)).isPrimitive())
throw newIllegalArgumentException("no leading reference parameter", x);
x = MethodHandles.checkValue(ptype, x);
// Cf. MethodHandles.insertArguments for the following logic:
MethodHandle bmh = MethodHandleImpl.bindReceiver(this, x);
if (bmh != null) return bmh;
return MethodHandleImpl.bindArgument(this, 0, x);
}
/**
......@@ -996,14 +1015,14 @@ assert(failed);
* "MethodHandle" + type().toString()
* </pre></blockquote>
* <p>
* Note: Future releases of this API may add further information
* (<em>Note:</em> Future releases of this API may add further information
* to the string representation.
* Therefore, the present syntax should not be parsed by applications.
* Therefore, the present syntax should not be parsed by applications.)
*
* @return a string representation of the method handle
*/
@Override
public String toString() {
return MethodHandleImpl.getNameString(IMPL_TOKEN, this);
return getNameString(this);
}
}
......@@ -23,136 +23,36 @@
* questions.
*/
package sun.dyn;
package java.lang.invoke;
import java.dyn.*;
import java.dyn.MethodHandles.Lookup;
import java.util.logging.Level;
import java.util.logging.Logger;
import sun.dyn.util.VerifyType;
import sun.invoke.util.VerifyType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import sun.dyn.empty.Empty;
import sun.dyn.util.ValueConversions;
import sun.dyn.util.Wrapper;
import sun.invoke.empty.Empty;
import sun.invoke.util.ValueConversions;
import sun.invoke.util.Wrapper;
import sun.misc.Unsafe;
import static sun.dyn.MemberName.newIllegalArgumentException;
import static sun.dyn.MemberName.newNoAccessException;
import static sun.dyn.MemberName.uncaughtException;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* Base class for method handles, containing JVM-specific fields and logic.
* TO DO: It should not be a base class.
* Trusted implementation code for MethodHandle.
* @author jrose
*/
public abstract class MethodHandleImpl {
// Fields which really belong in MethodHandle:
private byte vmentry; // adapter stub or method entry point
//private int vmslots; // optionally, hoist type.form.vmslots
protected Object vmtarget; // VM-specific, class-specific target value
//MethodType type; // defined in MethodHandle
// TO DO: vmtarget should be invisible to Java, since the JVM puts internal
// managed pointers into it. Making it visible exposes it to debuggers,
// which can cause errors when they treat the pointer as an Object.
// These two dummy fields are present to force 'I' and 'J' signatures
// into this class's constant pool, so they can be transferred
// to vmentry when this class is loaded.
static final int INT_FIELD = 0;
static final long LONG_FIELD = 0;
/** Access methods for the internals of MethodHandle, supplied to
* MethodHandleImpl as a trusted agent.
*/
static public interface MethodHandleFriend {
void initType(MethodHandle mh, MethodType type);
}
public static void setMethodHandleFriend(Access token, MethodHandleFriend am) {
Access.check(token);
if (METHOD_HANDLE_FRIEND != null)
throw new InternalError(); // just once
METHOD_HANDLE_FRIEND = am;
}
static private MethodHandleFriend METHOD_HANDLE_FRIEND;
// NOT public
static void initType(MethodHandle mh, MethodType type) {
METHOD_HANDLE_FRIEND.initType(mh, type);
}
// type is defined in java.dyn.MethodHandle, which is platform-independent
// vmentry (a void* field) is used *only* by by the JVM.
// The JVM adjusts its type to int or long depending on system wordsize.
// Since it is statically typed as neither int nor long, it is impossible
// to use this field from Java bytecode. (Please don't try to, either.)
// The vmentry is an assembly-language stub which is jumped to
// immediately after the method type is verified.
// For a direct MH, this stub loads the vmtarget's entry point
// and jumps to it.
/**
* VM-based method handles must have a security token.
* This security token can only be obtained by trusted code.
* Do not create method handles directly; use factory methods.
*/
public MethodHandleImpl(Access token) {
Access.check(token);
}
/** Initialize the method type form to participate in JVM calls.
* This is done once for each erased type.
*/
public static void init(Access token, MethodType self) {
Access.check(token);
if (MethodHandleNatives.JVM_SUPPORT)
MethodHandleNatives.init(self);
}
/*non-public*/ abstract class MethodHandleImpl {
/// Factory methods to create method handles:
private static final MemberName.Factory LOOKUP = MemberName.Factory.INSTANCE;
static private Lookup IMPL_LOOKUP_INIT;
public static void initLookup(Access token, Lookup lookup) {
Access.check(token);
if (IMPL_LOOKUP_INIT != null)
throw new InternalError();
IMPL_LOOKUP_INIT = lookup;
}
public static Lookup getLookup(Access token) {
Access.check(token);
return IMPL_LOOKUP;
}
static {
if (!MethodHandleNatives.JVM_SUPPORT) // force init of native API
throw new InternalError("No JVM support for JSR 292");
// Force initialization of Lookup, so it calls us back as initLookup:
MethodHandles.publicLookup();
if (IMPL_LOOKUP_INIT == null)
throw new InternalError();
}
public static void initStatics() {
static void initStatics() {
// Trigger preceding sequence.
}
/** Shared secret with MethodHandles.Lookup, a copy of Lookup.IMPL_LOOKUP. */
static final Lookup IMPL_LOOKUP = IMPL_LOOKUP_INIT;
/** Look up a given method.
* Callable only from java.dyn and related packages.
* Callable only from sun.invoke and related packages.
* <p>
* The resulting method handle type will be of the given type,
* with a receiver type {@code rcvc} prepended if the member is not static.
......@@ -170,10 +70,9 @@ public abstract class MethodHandleImpl {
* @return a direct handle to the matching method
* @throws IllegalAccessException if the given method cannot be accessed by the lookup class
*/
public static
MethodHandle findMethod(Access token, MemberName method,
static
MethodHandle findMethod(MemberName method,
boolean doDispatch, Class<?> lookupClass) throws IllegalAccessException {
Access.check(token); // only trusted calls
MethodType mtype = method.getMethodType();
if (!method.isStatic()) {
// adjust the advertised receiver type to be exactly the one requested
......@@ -183,7 +82,7 @@ public abstract class MethodHandleImpl {
}
DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
if (!mh.isValid())
throw newNoAccessException(method, lookupClass);
throw method.makeAccessException("no access", lookupClass);
assert(mh.type() == mtype);
if (!method.isVarargs())
return mh;
......@@ -191,13 +90,12 @@ public abstract class MethodHandleImpl {
return mh.asVarargsCollector(mtype.parameterType(mtype.parameterCount()-1));
}
public static
MethodHandle makeAllocator(Access token, MethodHandle rawConstructor) {
Access.check(token);
static
MethodHandle makeAllocator(MethodHandle rawConstructor) {
MethodType rawConType = rawConstructor.type();
// Wrap the raw (unsafe) constructor with the allocation of a suitable object.
MethodHandle allocator
= AllocateObject.make(token, rawConType.parameterType(0), rawConstructor);
= AllocateObject.make(rawConType.parameterType(0), rawConstructor);
assert(allocator.type()
.equals(rawConType.dropParameterTypes(0, 1).changeReturnType(rawConType.parameterType(0))));
return allocator;
......@@ -211,13 +109,11 @@ public abstract class MethodHandleImpl {
private AllocateObject(MethodHandle invoker,
Class<C> allocateClass, MethodHandle rawConstructor) {
super(Access.TOKEN, invoker);
super(invoker);
this.allocateClass = allocateClass;
this.rawConstructor = rawConstructor;
}
static MethodHandle make(Access token,
Class<?> allocateClass, MethodHandle rawConstructor) {
Access.check(token);
static MethodHandle make(Class<?> allocateClass, MethodHandle rawConstructor) {
MethodType rawConType = rawConstructor.type();
assert(rawConType.parameterType(0) == allocateClass);
MethodType newType = rawConType.dropParameterTypes(0, 1).changeReturnType(allocateClass);
......@@ -225,18 +121,18 @@ public abstract class MethodHandleImpl {
if (nargs < INVOKES.length) {
MethodHandle invoke = INVOKES[nargs];
MethodType conType = CON_TYPES[nargs];
MethodHandle gcon = convertArguments(token, rawConstructor, conType, rawConType, null);
MethodHandle gcon = convertArguments(rawConstructor, conType, rawConType, null);
if (gcon == null) return null;
MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
assert(galloc.type() == newType.generic());
return convertArguments(token, galloc, newType, galloc.type(), null);
return convertArguments(galloc, newType, galloc.type(), null);
} else {
MethodHandle invoke = VARARGS_INVOKE;
MethodType conType = CON_TYPES[nargs];
MethodHandle gcon = spreadArguments(token, rawConstructor, conType, 1);
MethodHandle gcon = spreadArguments(rawConstructor, conType, 1);
if (gcon == null) return null;
MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
return collectArguments(token, galloc, newType, 1, null);
return collectArguments(galloc, newType, 1, null);
}
}
@Override
......@@ -338,20 +234,16 @@ public abstract class MethodHandleImpl {
}
}
public static
MethodHandle accessField(Access token,
MemberName member, boolean isSetter,
static
MethodHandle accessField(MemberName member, boolean isSetter,
Class<?> lookupClass) {
Access.check(token);
// Use sun. misc.Unsafe to dig up the dirt on the field.
MethodHandle mh = new FieldAccessor(token, member, isSetter);
MethodHandle mh = new FieldAccessor(member, isSetter);
return mh;
}
public static
MethodHandle accessArrayElement(Access token,
Class<?> arrayClass, boolean isSetter) {
Access.check(token);
static
MethodHandle accessArrayElement(Class<?> arrayClass, boolean isSetter) {
if (!arrayClass.isArray())
throw newIllegalArgumentException("not an array: "+arrayClass);
Class<?> elemClass = arrayClass.getComponentType();
......@@ -379,12 +271,13 @@ public abstract class MethodHandleImpl {
final long offset;
final String name;
public FieldAccessor(Access token, MemberName field, boolean isSetter) {
super(Access.TOKEN, fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic()));
this.offset = (long) field.getVMIndex(token);
FieldAccessor(MemberName field, boolean isSetter) {
super(fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic()));
this.offset = (long) field.getVMIndex();
this.name = field.getName();
this.base = staticBase(field);
}
@Override
public String toString() { return addTypeString(name, this); }
int getFieldI(C obj) { return unsafe.getInt(obj, offset); }
......@@ -560,10 +453,8 @@ public abstract class MethodHandleImpl {
* @param receiver Receiver (or first static method argument) to pre-bind.
* @return a BoundMethodHandle for the given DirectMethodHandle, or null if it does not exist
*/
public static
MethodHandle bindReceiver(Access token,
MethodHandle target, Object receiver) {
Access.check(token);
static
MethodHandle bindReceiver(MethodHandle target, Object receiver) {
if (target instanceof AdapterMethodHandle &&
((AdapterMethodHandle)target).conversionOp() == MethodHandleNatives.Constants.OP_RETYPE_ONLY
) {
......@@ -574,7 +465,7 @@ public abstract class MethodHandleImpl {
dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0);
MethodType newType = target.type().dropParameterTypes(0, 1);
return convertArguments(token, bmh, newType, bmh.type(), null);
return convertArguments(bmh, newType, bmh.type(), null);
}
}
}
......@@ -590,19 +481,15 @@ public abstract class MethodHandleImpl {
* @param receiver Argument (which can be a boxed primitive) to pre-bind.
* @return a suitable BoundMethodHandle
*/
public static
MethodHandle bindArgument(Access token,
MethodHandle target, int argnum, Object receiver) {
Access.check(token);
static
MethodHandle bindArgument(MethodHandle target, int argnum, Object receiver) {
return new BoundMethodHandle(target, receiver, argnum);
}
public static MethodHandle convertArguments(Access token,
MethodHandle target,
static MethodHandle convertArguments(MethodHandle target,
MethodType newType,
MethodType oldType,
int[] permutationOrNull) {
Access.check(token);
assert(oldType.parameterCount() == target.type().parameterCount());
if (permutationOrNull != null) {
int outargs = oldType.parameterCount(), inargs = newType.parameterCount();
......@@ -613,7 +500,7 @@ public abstract class MethodHandleImpl {
for (int i = 0; i < outargs; i++)
callTypeArgs[i] = newType.parameterType(permutationOrNull[i]);
MethodType callType = MethodType.methodType(oldType.returnType(), callTypeArgs);
target = convertArguments(token, target, callType, oldType, null);
target = convertArguments(target, callType, oldType, null);
assert(target != null);
oldType = target.type();
List<Integer> goal = new ArrayList<Integer>(); // i*TOKEN
......@@ -710,7 +597,7 @@ public abstract class MethodHandleImpl {
Collections.rotate(ptypes.subList(rotBeg, rotEnd+1), -rotBy);
MethodType rotType = MethodType.methodType(oldType.returnType(), ptypes);
MethodHandle nextTarget
= AdapterMethodHandle.makeRotateArguments(token, rotType, target,
= AdapterMethodHandle.makeRotateArguments(rotType, target,
rotBeg, rotSpan.size(), rotBy);
if (nextTarget != null) {
//System.out.println("Rot: "+rotSpan+" by "+rotBy);
......@@ -733,7 +620,7 @@ public abstract class MethodHandleImpl {
int j = state.indexOf(arg);
Collections.swap(ptypes, i, j);
MethodType swapType = MethodType.methodType(oldType.returnType(), ptypes);
target = AdapterMethodHandle.makeSwapArguments(token, swapType, target, i, j);
target = AdapterMethodHandle.makeSwapArguments(swapType, target, i, j);
if (target == null) throw newIllegalArgumentException("cannot swap");
assert(target.type() == swapType);
oldType = swapType;
......@@ -760,7 +647,7 @@ public abstract class MethodHandleImpl {
List<Class<?>> ptypes = oldType.parameterList();
ptypes = ptypes.subList(0, ptypes.size() - dupArgCount);
MethodType dupType = MethodType.methodType(oldType.returnType(), ptypes);
target = AdapterMethodHandle.makeDupArguments(token, dupType, target, dupArgPos, dupArgCount);
target = AdapterMethodHandle.makeDupArguments(dupType, target, dupArgPos, dupArgCount);
if (target == null)
throw newIllegalArgumentException("cannot dup");
oldType = target.type();
......@@ -778,7 +665,7 @@ public abstract class MethodHandleImpl {
List<Class<?>> dropTypes = newType.parameterList()
.subList(dropArgPos, dropArgPos + dropArgCount);
MethodType dropType = oldType.insertParameterTypes(dropArgPos, dropTypes);
target = AdapterMethodHandle.makeDropArguments(token, dropType, target, dropArgPos, dropArgCount);
target = AdapterMethodHandle.makeDropArguments(dropType, target, dropArgPos, dropArgCount);
if (target == null) throw newIllegalArgumentException("cannot drop");
oldType = target.type();
}
......@@ -787,7 +674,7 @@ public abstract class MethodHandleImpl {
return target;
if (oldType.parameterCount() != newType.parameterCount())
throw newIllegalArgumentException("mismatched parameter count");
MethodHandle res = AdapterMethodHandle.makePairwiseConvert(token, newType, target);
MethodHandle res = AdapterMethodHandle.makePairwiseConvert(newType, target);
if (res != null)
return res;
int argc = oldType.parameterCount();
......@@ -797,26 +684,24 @@ public abstract class MethodHandleImpl {
// then back to the desired types. We might have to use Java-based
// method handles to do this.
MethodType objType = MethodType.genericMethodType(argc);
MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(token, objType, target);
MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(objType, target);
if (objTarget == null)
objTarget = FromGeneric.make(target);
res = AdapterMethodHandle.makePairwiseConvert(token, newType, objTarget);
res = AdapterMethodHandle.makePairwiseConvert(newType, objTarget);
if (res != null)
return res;
return ToGeneric.make(newType, objTarget);
}
public static MethodHandle spreadArguments(Access token,
MethodHandle target,
static MethodHandle spreadArguments(MethodHandle target,
MethodType newType,
int spreadArg) {
Access.check(token);
// TO DO: maybe allow the restarg to be Object and implicitly cast to Object[]
MethodType oldType = target.type();
// spread the last argument of newType to oldType
int spreadCount = oldType.parameterCount() - spreadArg;
Class<Object[]> spreadArgType = Object[].class;
MethodHandle res = AdapterMethodHandle.makeSpreadArguments(token, newType, target, spreadArgType, spreadArg, spreadCount);
MethodHandle res = AdapterMethodHandle.makeSpreadArguments(newType, target, spreadArgType, spreadArg, spreadCount);
if (res != null)
return res;
// try an intermediate adapter
......@@ -829,20 +714,19 @@ public abstract class MethodHandleImpl {
ptypes[spreadArg + i] = VerifyType.spreadArgElementType(spreadType, i);
MethodType midType = MethodType.methodType(newType.returnType(), ptypes);
// after spreading, some arguments may need further conversion
MethodHandle target2 = convertArguments(token, target, midType, oldType, null);
MethodHandle target2 = convertArguments(target, midType, oldType, null);
if (target2 == null)
throw new UnsupportedOperationException("NYI: convert "+midType+" =calls=> "+oldType);
res = AdapterMethodHandle.makeSpreadArguments(token, newType, target2, spreadArgType, spreadArg, spreadCount);
res = AdapterMethodHandle.makeSpreadArguments(newType, target2, spreadArgType, spreadArg, spreadCount);
if (res != null)
return res;
res = SpreadGeneric.make(target2, spreadCount);
if (res != null)
res = convertArguments(token, res, newType, res.type(), null);
res = convertArguments(res, newType, res.type(), null);
return res;
}
public static MethodHandle collectArguments(Access token,
MethodHandle target,
static MethodHandle collectArguments(MethodHandle target,
MethodType newType,
int collectArg,
MethodHandle collector) {
......@@ -856,29 +740,27 @@ public abstract class MethodHandleImpl {
// oldType // (a..., b...)=>r
assert(newType.parameterCount() == collectArg + colType.parameterCount());
assert(oldType.parameterCount() == collectArg + 1);
MethodHandle gtarget = convertArguments(token, target, oldType.generic(), oldType, null);
MethodHandle gcollector = convertArguments(token, collector, colType.generic(), colType, null);
MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, null);
MethodHandle gcollector = convertArguments(collector, colType.generic(), colType, null);
if (gtarget == null || gcollector == null) return null;
MethodHandle gresult = FilterGeneric.makeArgumentCollector(gcollector, gtarget);
MethodHandle result = convertArguments(token, gresult, newType, gresult.type(), null);
MethodHandle result = convertArguments(gresult, newType, gresult.type(), null);
return result;
}
public static MethodHandle filterArgument(Access token,
MethodHandle target,
static MethodHandle filterArgument(MethodHandle target,
int pos,
MethodHandle filter) {
Access.check(token);
MethodType ttype = target.type(), gttype = ttype.generic();
if (ttype != gttype) {
target = convertArguments(token, target, gttype, ttype, null);
target = convertArguments(target, gttype, ttype, null);
ttype = gttype;
}
MethodType ftype = filter.type(), gftype = ftype.generic();
if (ftype.parameterCount() != 1)
throw new InternalError();
if (ftype != gftype) {
filter = convertArguments(token, filter, gftype, ftype, null);
filter = convertArguments(filter, gftype, ftype, null);
ftype = gftype;
}
if (ftype == ttype) {
......@@ -888,27 +770,24 @@ public abstract class MethodHandleImpl {
return FilterGeneric.makeArgumentFilter(pos, filter, target);
}
public static MethodHandle foldArguments(Access token,
MethodHandle target,
static MethodHandle foldArguments(MethodHandle target,
MethodType newType,
MethodHandle combiner) {
Access.check(token);
MethodType oldType = target.type();
MethodType ctype = combiner.type();
MethodHandle gtarget = convertArguments(token, target, oldType.generic(), oldType, null);
MethodHandle gcombiner = convertArguments(token, combiner, ctype.generic(), ctype, null);
MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, null);
MethodHandle gcombiner = convertArguments(combiner, ctype.generic(), ctype, null);
if (gtarget == null || gcombiner == null) return null;
MethodHandle gresult = FilterGeneric.makeArgumentFolder(gcombiner, gtarget);
MethodHandle result = convertArguments(token, gresult, newType, gresult.type(), null);
MethodHandle result = convertArguments(gresult, newType, gresult.type(), null);
return result;
}
public static
MethodHandle dropArguments(Access token, MethodHandle target,
static
MethodHandle dropArguments(MethodHandle target,
MethodType newType, int argnum) {
Access.check(token);
int drops = newType.parameterCount() - target.type().parameterCount();
MethodHandle res = AdapterMethodHandle.makeDropArguments(token, newType, target, argnum, drops);
MethodHandle res = AdapterMethodHandle.makeDropArguments(newType, target, argnum, drops);
if (res != null)
return res;
throw new UnsupportedOperationException("NYI");
......@@ -918,36 +797,34 @@ public abstract class MethodHandleImpl {
private final MethodHandle test, target, fallback;
private GuardWithTest(MethodHandle invoker,
MethodHandle test, MethodHandle target, MethodHandle fallback) {
super(Access.TOKEN, invoker);
super(invoker);
this.test = test;
this.target = target;
this.fallback = fallback;
}
static MethodHandle make(Access token,
MethodHandle test, MethodHandle target, MethodHandle fallback) {
Access.check(token);
static MethodHandle make(MethodHandle test, MethodHandle target, MethodHandle fallback) {
MethodType type = target.type();
int nargs = type.parameterCount();
if (nargs < INVOKES.length) {
MethodHandle invoke = INVOKES[nargs];
MethodType gtype = type.generic();
assert(invoke.type().dropParameterTypes(0,1) == gtype);
MethodHandle gtest = convertArguments(token, test, gtype.changeReturnType(boolean.class), test.type(), null);
MethodHandle gtarget = convertArguments(token, target, gtype, type, null);
MethodHandle gfallback = convertArguments(token, fallback, gtype, type, null);
MethodHandle gtest = convertArguments(test, gtype.changeReturnType(boolean.class), test.type(), null);
MethodHandle gtarget = convertArguments(target, gtype, type, null);
MethodHandle gfallback = convertArguments(fallback, gtype, type, null);
if (gtest == null || gtarget == null || gfallback == null) return null;
MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
return convertArguments(token, gguard, type, gtype, null);
return convertArguments(gguard, type, gtype, null);
} else {
MethodHandle invoke = VARARGS_INVOKE;
MethodType gtype = MethodType.genericMethodType(1);
assert(invoke.type().dropParameterTypes(0,1) == gtype);
MethodHandle gtest = spreadArguments(token, test, gtype.changeReturnType(boolean.class), 0);
MethodHandle gtarget = spreadArguments(token, target, gtype, 0);
MethodHandle gfallback = spreadArguments(token, fallback, gtype, 0);
MethodHandle gtest = spreadArguments(test, gtype.changeReturnType(boolean.class), 0);
MethodHandle gtarget = spreadArguments(target, gtype, 0);
MethodHandle gfallback = spreadArguments(fallback, gtype, 0);
MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
if (gtest == null || gtarget == null || gfallback == null) return null;
return collectArguments(token, gguard, type, 0, null);
return collectArguments(gguard, type, 0, null);
}
}
@Override
......@@ -1034,24 +911,23 @@ public abstract class MethodHandleImpl {
}
}
public static
MethodHandle makeGuardWithTest(Access token,
MethodHandle test,
static
MethodHandle makeGuardWithTest(MethodHandle test,
MethodHandle target,
MethodHandle fallback) {
return GuardWithTest.make(token, test, target, fallback);
return GuardWithTest.make(test, target, fallback);
}
private static class GuardWithCatch extends BoundMethodHandle {
private final MethodHandle target;
private final Class<? extends Throwable> exType;
private final MethodHandle catcher;
public GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
this(INVOKES[target.type().parameterCount()], target, exType, catcher);
}
public GuardWithCatch(MethodHandle invoker,
GuardWithCatch(MethodHandle invoker,
MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
super(Access.TOKEN, invoker);
super(invoker);
this.target = target;
this.exType = exType;
this.catcher = catcher;
......@@ -1171,42 +1047,40 @@ public abstract class MethodHandleImpl {
}
public static
MethodHandle makeGuardWithCatch(Access token,
MethodHandle target,
static
MethodHandle makeGuardWithCatch(MethodHandle target,
Class<? extends Throwable> exType,
MethodHandle catcher) {
Access.check(token);
MethodType type = target.type();
MethodType ctype = catcher.type();
int nargs = type.parameterCount();
if (nargs < GuardWithCatch.INVOKES.length) {
MethodType gtype = type.generic();
MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
MethodHandle gtarget = convertArguments(token, target, gtype, type, null);
MethodHandle gcatcher = convertArguments(token, catcher, gcatchType, ctype, null);
MethodHandle gtarget = convertArguments(target, gtype, type, null);
MethodHandle gcatcher = convertArguments(catcher, gcatchType, ctype, null);
MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher);
if (gtarget == null || gcatcher == null || gguard == null) return null;
return convertArguments(token, gguard, type, gtype, null);
return convertArguments(gguard, type, gtype, null);
} else {
MethodType gtype = MethodType.genericMethodType(0, true);
MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
MethodHandle gtarget = spreadArguments(token, target, gtype, 0);
MethodHandle gcatcher = spreadArguments(token, catcher, gcatchType, 1);
MethodHandle gtarget = spreadArguments(target, gtype, 0);
MethodHandle gcatcher = spreadArguments(catcher, gcatchType, 1);
MethodHandle gguard = new GuardWithCatch(GuardWithCatch.VARARGS_INVOKE, gtarget, exType, gcatcher);
if (gtarget == null || gcatcher == null || gguard == null) return null;
return collectArguments(token, gguard, type, 0, null);
return collectArguments(gguard, type, 0, null);
}
}
public static
MethodHandle throwException(Access token, MethodType type) {
Access.check(token);
return AdapterMethodHandle.makeRetypeRaw(token, type, THROW_EXCEPTION);
static
MethodHandle throwException(MethodType type) {
return AdapterMethodHandle.makeRetypeRaw(type, throwException());
}
static final MethodHandle THROW_EXCEPTION;
static {
static MethodHandle THROW_EXCEPTION;
static MethodHandle throwException() {
if (THROW_EXCEPTION != null) return THROW_EXCEPTION;
try {
THROW_EXCEPTION
= IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
......@@ -1214,71 +1088,19 @@ public abstract class MethodHandleImpl {
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
return THROW_EXCEPTION;
}
static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
public static String getNameString(Access token, MethodHandle target, Object type) {
Access.check(token);
if (!(type instanceof MethodType)) {
if (type == null)
type = target.type();
else if (type instanceof MethodHandle)
type = ((MethodHandle)type).type();
}
MemberName name = null;
if (target != null)
name = MethodHandleNatives.getMethodName(target);
if (name == null)
return "invoke" + type;
return name.getName() + type;
}
public static String getNameString(Access token, MethodHandle target) {
return getNameString(token, target, null);
}
static String addTypeString(Object obj, MethodHandle target) {
String str = String.valueOf(obj);
if (target == null) return str;
int paren = str.indexOf('(');
if (paren >= 0) str = str.substring(0, paren);
return str + target.type();
}
static void checkSpreadArgument(Object av, int n) {
if (av == null ? n != 0 : ((Object[])av).length != n)
throw newIllegalArgumentException("Array is not of length "+n);
}
static void raiseException(int code, Object actual, Object required) {
String message;
// disregard the identity of the actual object, if it is not a class:
if (!(actual instanceof Class) && !(actual instanceof MethodType))
actual = actual.getClass();
if (actual != null)
message = "required "+required+" but encountered "+actual;
else
message = "required "+required;
switch (code) {
case 192: // checkcast
throw new ClassCastException(message);
default:
throw new InternalError("unexpected code "+code+": "+message);
}
}
// Linkage support:
public static void registerBootstrap(Access token, Class<?> callerClass, MethodHandle bootstrapMethod) {
Access.check(token);
static void registerBootstrap(Class<?> callerClass, MethodHandle bootstrapMethod) {
MethodHandleNatives.registerBootstrap(callerClass, bootstrapMethod);
}
public static MethodHandle getBootstrap(Access token, Class<?> callerClass) {
Access.check(token);
static MethodHandle getBootstrap(Class<?> callerClass) {
return MethodHandleNatives.getBootstrap(callerClass);
}
public static MethodHandle asVarargsCollector(Access token, MethodHandle target, Class<?> arrayType) {
Access.check(token);
return AdapterMethodHandle.makeVarargsCollector(token, target, arrayType);
static MethodHandle asVarargsCollector(MethodHandle target, Class<?> arrayType) {
return AdapterMethodHandle.makeVarargsCollector(target, arrayType);
}
}
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,14 +23,13 @@
* questions.
*/
package sun.dyn;
package java.lang.invoke;
import java.dyn.*;
import java.dyn.MethodHandles.Lookup;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import static sun.dyn.MethodHandleNatives.Constants.*;
import static sun.dyn.MethodHandleImpl.IMPL_LOOKUP;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* The JVM interface for the method handles package is all here.
......@@ -81,14 +80,12 @@ class MethodHandleNatives {
* This routine is for debugging and reflection.
*/
static MemberName getMethodName(MethodHandle self) {
if (!JVM_SUPPORT) return null;
return (MemberName) getTarget(self, ETF_METHOD_NAME);
}
/** Fetch the reflective version of the handled method, if available.
*/
static AccessibleObject getTargetMethod(MethodHandle self) {
if (!JVM_SUPPORT) return null;
return (AccessibleObject) getTarget(self, ETF_REFLECT_METHOD);
}
......@@ -97,7 +94,6 @@ class MethodHandleNatives {
* If it is chained to another method handle, return that handle.
*/
static Object getTargetInfo(MethodHandle self) {
if (!JVM_SUPPORT) return null;
return getTarget(self, ETF_HANDLE_OR_METHOD_NAME);
}
......@@ -111,11 +107,6 @@ class MethodHandleNatives {
*/
static native int getConstant(int which);
/** True iff this HotSpot JVM has built-in support for method handles.
* If false, some test cases might run, but functionality will be missing.
*/
public static final boolean JVM_SUPPORT;
/** Java copy of MethodHandlePushLimit in range 2..255. */
static final int JVM_PUSH_LIMIT;
/** JVM stack motion (in words) after one slot is pushed, usually -1.
......@@ -127,31 +118,24 @@ class MethodHandleNatives {
private static native void registerNatives();
static {
boolean JVM_SUPPORT_;
int JVM_PUSH_LIMIT_;
int JVM_STACK_MOVE_UNIT_;
int CONV_OP_IMPLEMENTED_MASK_;
try {
registerNatives();
JVM_SUPPORT_ = true;
JVM_PUSH_LIMIT_ = getConstant(Constants.GC_JVM_PUSH_LIMIT);
JVM_STACK_MOVE_UNIT_ = getConstant(Constants.GC_JVM_STACK_MOVE_UNIT);
CONV_OP_IMPLEMENTED_MASK_ = getConstant(Constants.GC_CONV_OP_IMPLEMENTED_MASK);
//sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init");
} catch (UnsatisfiedLinkError ee) {
// ignore; if we use init() methods later we'll see linkage errors
JVM_SUPPORT_ = false;
JVM_PUSH_LIMIT_ = 3; // arbitrary
JVM_STACK_MOVE_UNIT_ = -1; // arbitrary
CONV_OP_IMPLEMENTED_MASK_ = 0;
//System.out.println("Warning: Running with JVM_SUPPORT=false");
//System.out.println(ee);
JVM_SUPPORT = JVM_SUPPORT_;
JVM_PUSH_LIMIT = JVM_PUSH_LIMIT_;
JVM_STACK_MOVE_UNIT = JVM_STACK_MOVE_UNIT_;
throw ee; // just die; hopeless to try to run with an older JVM
}
JVM_SUPPORT = JVM_SUPPORT_;
JVM_PUSH_LIMIT = JVM_PUSH_LIMIT_;
JVM_STACK_MOVE_UNIT = JVM_STACK_MOVE_UNIT_;
if (CONV_OP_IMPLEMENTED_MASK_ == 0)
......@@ -189,9 +173,15 @@ class MethodHandleNatives {
MN_SEARCH_INTERFACES = 0x00200000, // for MHN.getMembers
VM_INDEX_UNINITIALIZED = -99;
// BoundMethodHandle
/** Constants for decoding the vmargslot field, which contains 2 values. */
static final int
ARG_SLOT_PUSH_SHIFT = 16,
ARG_SLOT_MASK = (1<<ARG_SLOT_PUSH_SHIFT)-1;
// AdapterMethodHandle
/** Conversions recognized by the JVM.
* They must align with the constants in sun.dyn_AdapterMethodHandle,
* They must align with the constants in java.lang.invoke.AdapterMethodHandle,
* in the JVM file hotspot/src/share/vm/classfile/javaClasses.hpp.
*/
static final int
......@@ -292,7 +282,7 @@ class MethodHandleNatives {
return true;
}
static {
if (JVM_SUPPORT) verifyConstants();
verifyConstants();
}
// Up-calls from the JVM.
......@@ -305,28 +295,47 @@ class MethodHandleNatives {
String name, MethodType type,
Object info,
MemberName callerMethod, int callerBCI) {
return CallSiteImpl.makeSite(bootstrapMethod, name, type, info, callerMethod, callerBCI);
return CallSite.makeSite(bootstrapMethod, name, type, info, callerMethod, callerBCI);
}
/**
* Called by the JVM to check the length of a spread array.
*/
static void checkSpreadArgument(Object av, int n) {
MethodHandleStatics.checkSpreadArgument(av, n);
}
/**
* The JVM wants a pointer to a MethodType. Oblige it by finding or creating one.
*/
static MethodType findMethodHandleType(Class<?> rtype, Class<?>[] ptypes) {
MethodType.genericMethodType(0); // trigger initialization
return MethodTypeImpl.makeImpl(Access.TOKEN, rtype, ptypes, true);
return MethodType.makeImpl(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;
type.form().notifyGenericMethodType();
}
/**
* The JVM wants to raise an exception. Here's the path.
*/
static void raiseException(int code, Object actual, Object required) {
String message;
// disregard the identity of the actual object, if it is not a class:
if (!(actual instanceof Class) && !(actual instanceof MethodType))
actual = actual.getClass();
if (actual != null)
message = "required "+required+" but encountered "+actual;
else
message = "required "+required;
switch (code) {
case 192: // checkcast
throw new ClassCastException(message);
default:
throw new InternalError("unexpected code "+code+": "+message);
}
}
......
/*
* Copyright (c) 2011, 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.lang.invoke;
/**
* This class consists exclusively of static names internal to the
* method handle implementation.
* Usage: {@code import static java.lang.invoke.MethodHandleStatics.*}
* @author John Rose, JSR 292 EG
*/
/*non-public*/ class MethodHandleStatics {
private MethodHandleStatics() { } // do not instantiate
/*non-public*/ static String getNameString(MethodHandle target, MethodType type) {
if (type == null)
type = target.type();
MemberName name = null;
if (target != null)
name = MethodHandleNatives.getMethodName(target);
if (name == null)
return "invoke" + type;
return name.getName() + type;
}
/*non-public*/ static String getNameString(MethodHandle target, MethodHandle typeHolder) {
return getNameString(target, typeHolder == null ? (MethodType) null : typeHolder.type());
}
/*non-public*/ static String getNameString(MethodHandle target) {
return getNameString(target, (MethodType) null);
}
/*non-public*/ static String addTypeString(Object obj, MethodHandle target) {
String str = String.valueOf(obj);
if (target == null) return str;
int paren = str.indexOf('(');
if (paren >= 0) str = str.substring(0, paren);
return str + target.type();
}
static void checkSpreadArgument(Object av, int n) {
if (av == null ? n != 0 : ((Object[])av).length != n)
throw newIllegalArgumentException("Array is not of length "+n);
}
// handy shared exception makers (they simplify the common case code)
/*non-public*/ static RuntimeException newIllegalStateException(String message) {
return new IllegalStateException(message);
}
/*non-public*/ static RuntimeException newIllegalStateException(String message, Object obj) {
return new IllegalStateException(message(message, obj));
}
/*non-public*/ static RuntimeException newIllegalArgumentException(String message) {
return new IllegalArgumentException(message);
}
/*non-public*/ static RuntimeException newIllegalArgumentException(String message, Object obj) {
return new IllegalArgumentException(message(message, obj));
}
/*non-public*/ static Error uncaughtException(Exception ex) {
Error err = new InternalError("uncaught exception");
err.initCause(ex);
return err;
}
private static String message(String message, Object obj) {
if (obj != null) message = message + ": " + obj;
return message;
}
}
......@@ -23,24 +23,18 @@
* questions.
*/
package java.dyn;
package java.lang.invoke;
import java.lang.reflect.*;
import sun.dyn.Access;
import sun.dyn.MemberName;
import sun.dyn.MethodHandleImpl;
import sun.dyn.WrapperInstance;
import sun.dyn.util.ValueConversions;
import sun.dyn.util.VerifyAccess;
import sun.dyn.util.Wrapper;
import sun.invoke.WrapperInstance;
import sun.invoke.util.ValueConversions;
import sun.invoke.util.VerifyAccess;
import sun.invoke.util.Wrapper;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import sun.dyn.Invokers;
import sun.dyn.MethodTypeImpl;
import sun.reflect.Reflection;
import static sun.dyn.MemberName.newIllegalArgumentException;
import static sun.dyn.MemberName.newNoAccessException;
import static java.lang.invoke.MethodHandleStatics.*;
/**
* This class consists exclusively of static methods that operate on or return
......@@ -49,7 +43,7 @@ import static sun.dyn.MemberName.newNoAccessException;
* <li>Lookup methods which help create method handles for methods and fields.
* <li>Combinator methods, which combine or transform pre-existing method handles into new ones.
* <li>Other factory methods to create method handles that emulate other common JVM operations or control flow patterns.
* <li>Wrapper methods which can convert between method handles and other function-like "SAM types".
* <li>Wrapper methods which can convert between method handles and interface types.
* </ul>
* <p>
* @author John Rose, JSR 292 EG
......@@ -58,15 +52,14 @@ public class MethodHandles {
private MethodHandles() { } // do not instantiate
private static final Access IMPL_TOKEN = Access.getToken();
private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(IMPL_TOKEN);
private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
static { MethodHandleImpl.initStatics(); }
// See IMPL_LOOKUP below.
//// Method handle creation from ordinary methods.
/**
* Return a {@link Lookup lookup object} on the caller,
* Returns a {@link Lookup lookup object} on the caller,
* which has the capability to access any method handle that the caller has access to,
* including direct method handles to private fields and methods.
* This lookup object is a <em>capability</em> which may be delegated to trusted agents.
......@@ -77,7 +70,7 @@ public class MethodHandles {
}
/**
* Return a {@link Lookup lookup object} which is trusted minimally.
* Returns a {@link Lookup lookup object} which is trusted minimally.
* It can only be used to create method handles to
* publicly accessible fields and methods.
* <p>
......@@ -120,55 +113,55 @@ public class MethodHandles {
* <table border=1 cellpadding=5 summary="lookup method behaviors">
* <tr><th>lookup expression</th><th>member</th><th>behavior</th></tr>
* <tr>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)}</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)}</td>
* <td>FT f;</td><td>(T) this.f;</td>
* </tr>
* <tr>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#findStaticGetter lookup.findStaticGetter(C.class,"f",FT.class)}</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findStaticGetter lookup.findStaticGetter(C.class,"f",FT.class)}</td>
* <td>static<br>FT f;</td><td>(T) C.f;</td>
* </tr>
* <tr>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#findSetter lookup.findSetter(C.class,"f",FT.class)}</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findSetter lookup.findSetter(C.class,"f",FT.class)}</td>
* <td>FT f;</td><td>this.f = x;</td>
* </tr>
* <tr>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#findStaticSetter lookup.findStaticSetter(C.class,"f",FT.class)}</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findStaticSetter lookup.findStaticSetter(C.class,"f",FT.class)}</td>
* <td>static<br>FT f;</td><td>C.f = arg;</td>
* </tr>
* <tr>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#findVirtual lookup.findVirtual(C.class,"m",MT)}</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findVirtual lookup.findVirtual(C.class,"m",MT)}</td>
* <td>T m(A*);</td><td>(T) this.m(arg*);</td>
* </tr>
* <tr>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#findStatic lookup.findStatic(C.class,"m",MT)}</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findStatic lookup.findStatic(C.class,"m",MT)}</td>
* <td>static<br>T m(A*);</td><td>(T) C.m(arg*);</td>
* </tr>
* <tr>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#findSpecial lookup.findSpecial(C.class,"m",MT,this.class)}</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findSpecial lookup.findSpecial(C.class,"m",MT,this.class)}</td>
* <td>T m(A*);</td><td>(T) super.m(arg*);</td>
* </tr>
* <tr>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#findConstructor lookup.findConstructor(C.class,MT)}</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findConstructor lookup.findConstructor(C.class,MT)}</td>
* <td>C(A*);</td><td>(T) new C(arg*);</td>
* </tr>
* <tr>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#unreflectGetter lookup.unreflectGetter(aField)}</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#unreflectGetter lookup.unreflectGetter(aField)}</td>
* <td>(static)?<br>FT f;</td><td>(FT) aField.get(thisOrNull);</td>
* </tr>
* <tr>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#unreflectSetter lookup.unreflectSetter(aField)}</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#unreflectSetter lookup.unreflectSetter(aField)}</td>
* <td>(static)?<br>FT f;</td><td>aField.set(thisOrNull, arg);</td>
* </tr>
* <tr>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}</td>
* <td>(static)?<br>T m(A*);</td><td>(T) aMethod.invoke(thisOrNull, arg*);</td>
* </tr>
* <tr>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#unreflectConstructor lookup.unreflectConstructor(aConstructor)}</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#unreflectConstructor lookup.unreflectConstructor(aConstructor)}</td>
* <td>C(A*);</td><td>(C) aConstructor.newInstance(arg*);</td>
* </tr>
* <tr>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}</td>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}</td>
* <td>(static)?<br>T m(A*);</td><td>(T) aMethod.invoke(thisOrNull, arg*);</td>
* </tr>
* </table>
......@@ -383,10 +376,10 @@ public class MethodHandles {
* and {@linkplain #PACKAGE PACKAGE (0x08)}.
* <p>
* A freshly-created lookup object
* on the {@linkplain java.dyn.MethodHandles#lookup() caller's class}
* on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class}
* has all possible bits set, since the caller class can access all its own members.
* A lookup object on a new lookup class
* {@linkplain java.dyn.MethodHandles.Lookup#in created from a previous lookup object}
* {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object}
* may have some mode bits set to zero.
* The purpose of this is to restrict access via the new lookup object,
* so that it can access only names which can be reached by the original
......@@ -410,9 +403,8 @@ public class MethodHandles {
checkUnprivilegedlookupClass(lookupClass);
}
Lookup(Access token, Class<?> lookupClass) {
Lookup(Class<?> lookupClass) {
this(lookupClass, ALL_MODES);
Access.check(token);
}
private Lookup(Class<?> lookupClass, int allowedModes) {
......@@ -471,7 +463,7 @@ public class MethodHandles {
}
// Make sure outer class is initialized first.
static { IMPL_TOKEN.getClass(); }
static { IMPL_NAMES.getClass(); }
/** Version of lookup which is trusted minimally.
* It can only be used to create method handles to
......@@ -481,11 +473,10 @@ public class MethodHandles {
/** Package-private version of lookup which is trusted. */
static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED);
static { MethodHandleImpl.initLookup(IMPL_TOKEN, IMPL_LOOKUP); }
private static void checkUnprivilegedlookupClass(Class<?> lookupClass) {
String name = lookupClass.getName();
if (name.startsWith("java.dyn.") || name.startsWith("sun.dyn."))
if (name.startsWith("java.lang.invoke."))
throw newIllegalArgumentException("illegal lookupClass: "+lookupClass);
}
......@@ -506,8 +497,8 @@ public class MethodHandles {
* access (public, package, private, and protected) is allowed.
* In this case, no suffix is added.
* This is true only of an object obtained originally from
* {@link java.dyn.MethodHandles#lookup MethodHandles.lookup}.
* Objects created by {@link java.dyn.MethodHandles.Lookup#in Lookup.in}
* {@link java.lang.invoke.MethodHandles#lookup MethodHandles.lookup}.
* Objects created by {@link java.lang.invoke.MethodHandles.Lookup#in Lookup.in}
* always have restricted access, and will display a suffix.
* <p>
* (It may seem strange that protected access should be
......@@ -577,7 +568,7 @@ public class MethodHandles {
MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
MemberName method = resolveOrFail(refc, name, type, true);
checkMethod(refc, method, true);
return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClassOrNull());
return MethodHandleImpl.findMethod(method, false, lookupClassOrNull());
}
/**
......@@ -601,8 +592,8 @@ public class MethodHandles {
* if the class is {@code MethodHandle} and the name string is
* {@code invokeExact} or {@code invokeGeneric}, the resulting
* method handle is equivalent to one produced by
* {@link java.dyn.MethodHandles#exactInvoker MethodHandles.exactInvoker} or
* {@link java.dyn.MethodHandles#genericInvoker MethodHandles.genericInvoker}
* {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker} or
* {@link java.lang.invoke.MethodHandles#genericInvoker MethodHandles.genericInvoker}
* with the same {@code type} argument.
*
* @param refc the class or interface from which the method is accessed
......@@ -618,7 +609,7 @@ public class MethodHandles {
public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
MemberName method = resolveOrFail(refc, name, type, false);
checkMethod(refc, method, false);
MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull());
MethodHandle mh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull());
return restrictProtectedReceiver(method, mh);
}
......@@ -651,8 +642,8 @@ public class MethodHandles {
MemberName ctor = resolveOrFail(refc, name, type, false, false, lookupClassOrNull());
assert(ctor.isConstructor());
checkAccess(refc, ctor);
MethodHandle rawMH = MethodHandleImpl.findMethod(IMPL_TOKEN, ctor, false, lookupClassOrNull());
MethodHandle allocMH = MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawMH);
MethodHandle rawMH = MethodHandleImpl.findMethod(ctor, false, lookupClassOrNull());
MethodHandle allocMH = MethodHandleImpl.makeAllocator(rawMH);
return fixVarargs(allocMH, rawMH);
}
......@@ -708,7 +699,7 @@ public class MethodHandles {
checkSpecialCaller(specialCaller);
MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller);
checkMethod(refc, method, false);
MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, specialCaller);
MethodHandle mh = MethodHandleImpl.findMethod(method, false, specialCaller);
return restrictReceiver(method, mh, specialCaller);
}
......@@ -839,17 +830,17 @@ return mh1;
Class<? extends Object> refc = receiver.getClass(); // may get NPE
MemberName method = resolveOrFail(refc, name, type, false);
checkMethod(refc, method, false);
MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull());
MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, dmh, receiver);
MethodHandle dmh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull());
MethodHandle bmh = MethodHandleImpl.bindReceiver(dmh, receiver);
if (bmh == null)
throw newNoAccessException(method, this);
throw method.makeAccessException("no access", this);
if (dmh.type().parameterCount() == 0)
return dmh; // bound the trailing parameter; no varargs possible
return fixVarargs(bmh, dmh);
}
/**
* Make a direct method handle to <i>m</i>, if the lookup class has permission.
* Makes a direct method handle to <i>m</i>, if the lookup class has permission.
* If <i>m</i> is non-static, the receiver argument is treated as an initial argument.
* If <i>m</i> is virtual, overriding is respected on every call.
* Unlike the Core Reflection API, exceptions are <em>not</em> wrapped.
......@@ -871,7 +862,7 @@ return mh1;
MemberName method = new MemberName(m);
assert(method.isMethod());
if (!m.isAccessible()) checkMethod(method.getDeclaringClass(), method, method.isStatic());
MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull());
MethodHandle mh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull());
if (!m.isAccessible()) mh = restrictProtectedReceiver(method, mh);
return mh;
}
......@@ -901,7 +892,7 @@ return mh1;
assert(method.isMethod());
// ignore m.isAccessible: this is a new kind of access
checkMethod(m.getDeclaringClass(), method, false);
MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClassOrNull());
MethodHandle mh = MethodHandleImpl.findMethod(method, false, lookupClassOrNull());
return restrictReceiver(method, mh, specialCaller);
}
......@@ -928,8 +919,8 @@ return mh1;
MemberName ctor = new MemberName(c);
assert(ctor.isConstructor());
if (!c.isAccessible()) checkAccess(c.getDeclaringClass(), ctor);
MethodHandle rawCtor = MethodHandleImpl.findMethod(IMPL_TOKEN, ctor, false, lookupClassOrNull());
MethodHandle allocator = MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawCtor);
MethodHandle rawCtor = MethodHandleImpl.findMethod(ctor, false, lookupClassOrNull());
MethodHandle allocator = MethodHandleImpl.makeAllocator(rawCtor);
return fixVarargs(allocator, rawCtor);
}
......@@ -940,7 +931,7 @@ return mh1;
* If the field is static, the method handle will take no arguments.
* Otherwise, its single argument will be the instance containing
* the field.
* If the method's {@code accessible} flag is not set,
* If the field's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class.
* @param f the reflected field
* @return a method handle which can load values from the reflected field
......@@ -958,7 +949,7 @@ return mh1;
* argument, of the field's value type, the value to be stored.
* Otherwise, the two arguments will be the instance containing
* the field, and the value to be stored.
* If the method's {@code accessible} flag is not set,
* If the field's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class.
* @param f the reflected field
* @return a method handle which can store values into the reflected field
......@@ -999,7 +990,7 @@ return mh1;
void checkSymbolicClass(Class<?> refc) throws IllegalAccessException {
Class<?> caller = lookupClassOrNull();
if (caller != null && !VerifyAccess.isClassAccessible(refc, caller))
throw newNoAccessException("symbolic reference class is not public", new MemberName(refc), this);
throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this);
}
void checkMethod(Class<?> refc, MemberName m, boolean wantStatic) throws IllegalAccessException {
......@@ -1012,7 +1003,7 @@ return mh1;
message = wantStatic ? "expected a static method" : "expected a non-static method";
else
{ checkAccess(refc, m); return; }
throw newNoAccessException(message, m, this);
throw m.makeAccessException(message, this);
}
void checkAccess(Class<?> refc, MemberName m) throws IllegalAccessException {
......@@ -1030,7 +1021,7 @@ return mh1;
&& VerifyAccess.isSamePackage(m.getDeclaringClass(), lookupClass()))
// Protected members can also be checked as if they were package-private.
return;
throw newNoAccessException(accessFailedMessage(refc, m), m, this);
throw m.makeAccessException(accessFailedMessage(refc, m), this);
}
String accessFailedMessage(Class<?> refc, MemberName m) {
......@@ -1064,8 +1055,8 @@ return mh1;
|| (specialCaller != lookupClass()
&& !(ALLOW_NESTMATE_ACCESS &&
VerifyAccess.isSamePackageMember(specialCaller, lookupClass()))))
throw newNoAccessException("no private access for invokespecial",
new MemberName(specialCaller), this);
throw new MemberName(specialCaller).
makeAccessException("no private access for invokespecial", this);
}
MethodHandle restrictProtectedReceiver(MemberName method, MethodHandle mh) throws IllegalAccessException {
......@@ -1084,12 +1075,12 @@ return mh1;
assert(!method.isStatic());
Class<?> defc = method.getDeclaringClass(); // receiver type of mh is too wide
if (defc.isInterface() || !defc.isAssignableFrom(caller)) {
throw newNoAccessException("caller class must be a subclass below the method", method, caller);
throw method.makeAccessException("caller class must be a subclass below the method", caller);
}
MethodType rawType = mh.type();
if (rawType.parameterType(0) == caller) return mh;
MethodType narrowType = rawType.changeParameterType(0, caller);
MethodHandle narrowMH = MethodHandleImpl.convertArguments(IMPL_TOKEN, mh, narrowType, rawType, null);
MethodHandle narrowMH = MethodHandleImpl.convertArguments(mh, narrowType, rawType, null);
return fixVarargs(narrowMH, mh);
}
......@@ -1097,10 +1088,9 @@ return mh1;
boolean isStatic, boolean isSetter) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(refc, name, type, isStatic);
if (isStatic != field.isStatic())
throw newNoAccessException(isStatic
throw field.makeAccessException(isStatic
? "expected a static field"
: "expected a non-static field",
field, this);
: "expected a non-static field", this);
return makeAccessor(refc, field, false, isSetter);
}
......@@ -1108,9 +1098,9 @@ return mh1;
boolean trusted, boolean isSetter) throws IllegalAccessException {
assert(field.isField());
if (trusted)
return MethodHandleImpl.accessField(IMPL_TOKEN, field, isSetter, lookupClassOrNull());
return MethodHandleImpl.accessField(field, isSetter, lookupClassOrNull());
checkAccess(refc, field);
MethodHandle mh = MethodHandleImpl.accessField(IMPL_TOKEN, field, isSetter, lookupClassOrNull());
MethodHandle mh = MethodHandleImpl.accessField(field, isSetter, lookupClassOrNull());
return restrictProtectedReceiver(field, mh);
}
}
......@@ -1127,7 +1117,7 @@ return mh1;
*/
public static
MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException {
return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, false);
return MethodHandleImpl.accessArrayElement(arrayClass, false);
}
/**
......@@ -1141,7 +1131,7 @@ return mh1;
*/
public static
MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException {
return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, true);
return MethodHandleImpl.accessArrayElement(arrayClass, true);
}
/// method handle invocation (reflective style)
......@@ -1191,7 +1181,7 @@ return invoker;
MethodHandle spreadInvoker(MethodType type, int objectArgCount) {
if (objectArgCount < 0 || objectArgCount > type.parameterCount())
throw new IllegalArgumentException("bad argument count "+objectArgCount);
return invokers(type).spreadInvoker(objectArgCount);
return type.invokers().spreadInvoker(objectArgCount);
}
/**
......@@ -1231,7 +1221,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
*/
static public
MethodHandle exactInvoker(MethodType type) {
return invokers(type).exactInvoker();
return type.invokers().exactInvoker();
}
/**
......@@ -1258,11 +1248,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type)
*/
static public
MethodHandle genericInvoker(MethodType type) {
return invokers(type).genericInvoker();
}
static Invokers invokers(MethodType type) {
return MethodTypeImpl.invokers(IMPL_TOKEN, type);
return type.invokers().genericInvoker();
}
/**
......@@ -1387,7 +1373,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type)
return target;
MethodHandle res = null;
try {
res = MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
res = MethodHandleImpl.convertArguments(target,
newType, oldType, null);
} catch (IllegalArgumentException ex) {
}
......@@ -1531,7 +1517,7 @@ assert((int)twice.invokeExact(21) == 42);
MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) {
MethodType oldType = target.type();
checkReorder(reorder, newType, oldType);
return MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
return MethodHandleImpl.convertArguments(target,
newType, oldType,
reorder);
}
......@@ -1574,7 +1560,7 @@ assert((int)twice.invokeExact(21) == 42);
int numSpread = (outargs - spreadPos);
MethodHandle res = null;
if (spreadPos >= 0 && numSpread >= 0) {
res = MethodHandleImpl.spreadArguments(IMPL_TOKEN, target, newType, spreadPos);
res = MethodHandleImpl.spreadArguments(target, newType, spreadPos);
}
if (res == null) {
throw newIllegalArgumentException("cannot spread "+newType+" to " +oldType);
......@@ -1607,7 +1593,7 @@ assert((int)twice.invokeExact(21) == 42);
int numCollect = (inargs - collectPos);
if (collectPos < 0 || numCollect < 0)
throw newIllegalArgumentException("wrong number of arguments");
MethodHandle res = MethodHandleImpl.collectArguments(IMPL_TOKEN, target, newType, collectPos, null);
MethodHandle res = MethodHandleImpl.collectArguments(target, newType, collectPos, null);
if (res == null) {
throw newIllegalArgumentException("cannot collect from "+newType+" to " +oldType);
}
......@@ -1654,7 +1640,13 @@ assert((int)twice.invokeExact(21) == 42);
MethodHandle identity(Class<?> type) {
if (type == void.class)
throw newIllegalArgumentException("void type");
return ValueConversions.identity(type);
else if (type == Object.class)
return ValueConversions.identity();
else if (type.isPrimitive())
return ValueConversions.identity(Wrapper.forPrimitiveType(type));
else
return AdapterMethodHandle.makeRetypeRaw(
MethodType.methodType(type, type), ValueConversions.identity());
}
/**
......@@ -1686,8 +1678,6 @@ assert((int)twice.invokeExact(21) == 42);
MethodHandle insertArguments(MethodHandle target, int pos, Object... values) {
int insCount = values.length;
MethodType oldType = target.type();
ArrayList<Class<?>> ptypes =
new ArrayList<Class<?>>(oldType.parameterList());
int outargs = oldType.parameterCount();
int inargs = outargs - insCount;
if (inargs < 0)
......@@ -1701,14 +1691,14 @@ assert((int)twice.invokeExact(21) == 42);
value = checkValue(valueType, value);
if (pos == 0 && !valueType.isPrimitive()) {
// At least for now, make bound method handles a special case.
MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, result, value);
MethodHandle bmh = MethodHandleImpl.bindReceiver(result, value);
if (bmh != null) {
result = bmh;
continue;
}
// else fall through to general adapter machinery
}
result = MethodHandleImpl.bindArgument(IMPL_TOKEN, result, pos, value);
result = MethodHandleImpl.bindArgument(result, pos, value);
}
return result;
}
......@@ -1726,20 +1716,21 @@ assert((int)twice.invokeExact(21) == 42);
* <p>
* <b>Example:</b>
* <p><blockquote><pre>
import static java.dyn.MethodHandles.*;
import static java.dyn.MethodType.*;
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
assertEquals("xy", (String) cat.invokeExact("x", "y"));
MethodHandle d0 = dropArguments(cat, 0, String.class);
assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
MethodHandle d1 = dropArguments(cat, 1, String.class);
assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));
MethodHandle d2 = dropArguments(cat, 2, String.class);
assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class);
MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2));
assertEquals(bigType, d0.type());
assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
* </pre></blockquote>
* <p>
* This method is also equivalent to the following code:
* <p><blockquote><pre>
* {@link #dropArguments(MethodHandle,int,Class...) dropArguments}(target, pos, valueTypes.toArray(new Class[0]))
* </pre></blockquote>
* @param target the method handle to invoke after the arguments are dropped
* @param valueTypes the type(s) of the argument(s) to drop
......@@ -1762,7 +1753,7 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
new ArrayList<Class<?>>(oldType.parameterList());
ptypes.addAll(pos, valueTypes);
MethodType newType = MethodType.methodType(oldType.returnType(), ptypes);
return MethodHandleImpl.dropArguments(IMPL_TOKEN, target, newType, pos);
return MethodHandleImpl.dropArguments(target, newType, pos);
}
/**
......@@ -1770,10 +1761,34 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
* after dropping the given argument(s) at the given position.
* The type of the new method handle will insert the given argument
* type(s), at that position, into the original handle's type.
* This method is equivalent to the following code:
* <code>
* <p>
* The <i>pos</i> may range between zero and <i>N</i>,
* where <i>N</i> is the number of argument types in <i>target</i>,
* meaning to drop the first or last argument (respectively),
* or an argument somewhere in between.
* <p>
* <b>Example:</b>
* <p><blockquote><pre>
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
assertEquals("xy", (String) cat.invokeExact("x", "y"));
MethodHandle d0 = dropArguments(cat, 0, String.class);
assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
MethodHandle d1 = dropArguments(cat, 1, String.class);
assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));
MethodHandle d2 = dropArguments(cat, 2, String.class);
assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
* </pre></blockquote>
* <p>
* This method is also equivalent to the following code:
* <p><blockquote><pre>
* {@link #dropArguments(MethodHandle,int,List) dropArguments}(target, pos, Arrays.asList(valueTypes))
* </code>
* </pre></blockquote>
* @param target the method handle to invoke after the arguments are dropped
* @param valueTypes the type(s) of the argument(s) to drop
* @param pos position of first argument to drop (zero for the leftmost)
......@@ -1789,7 +1804,7 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
}
/**
* Adapt a target method handle {@code target} by pre-processing
* Adapts a target method handle {@code target} by pre-processing
* one or more of its arguments, each with its own unary filter function,
* and then calling the target with each pre-processed argument
* replaced by the result of its corresponding filter function.
......@@ -1812,8 +1827,8 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
* which do not correspond to argument positions in the target.
* <b>Example:</b>
* <p><blockquote><pre>
import static java.dyn.MethodHandles.*;
import static java.dyn.MethodType.*;
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
......@@ -1855,16 +1870,16 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
|| filterType.returnType() != targetType.parameterType(curPos))
throw newIllegalArgumentException("target and filter types do not match");
adapterType = adapterType.changeParameterType(curPos, filterType.parameterType(0));
adapter = MethodHandleImpl.filterArgument(IMPL_TOKEN, adapter, curPos, filter);
adapter = MethodHandleImpl.filterArgument(adapter, curPos, filter);
}
MethodType midType = adapter.type();
if (midType != adapterType)
adapter = MethodHandleImpl.convertArguments(IMPL_TOKEN, adapter, adapterType, midType, null);
adapter = MethodHandleImpl.convertArguments(adapter, adapterType, midType, null);
return adapter;
}
/**
* Adapt a target method handle {@code target} by post-processing
* Adapts a target method handle {@code target} by post-processing
* its return value with a unary filter function.
* <p>
* If a filter {@code F} applies to the return value of
......@@ -1876,8 +1891,8 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
* return type of the target.
* <b>Example:</b>
* <p><blockquote><pre>
import static java.dyn.MethodHandles.*;
import static java.dyn.MethodType.*;
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
......@@ -1909,7 +1924,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
}
/**
* Adapt a target method handle {@code target} by pre-processing
* Adapts a target method handle {@code target} by pre-processing
* some of its arguments, and then calling the target with
* the result of the pre-processing, plus all original arguments.
* <p>
......@@ -1966,11 +1981,11 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
if (!ok)
throw misMatchedTypes("target and combiner types", targetType, combinerType);
MethodType newType = targetType.dropParameterTypes(0, 1);
return MethodHandleImpl.foldArguments(IMPL_TOKEN, target, newType, combiner);
return MethodHandleImpl.foldArguments(target, newType, combiner);
}
/**
* Make a method handle which adapts a target method handle,
* Makes a method handle which adapts a target method handle,
* by guarding it with a test, a boolean-valued method handle.
* If the guard fails, a fallback handle is called instead.
* All three method handles must have the same corresponding
......@@ -2021,7 +2036,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
test = dropArguments(test, gpc, targs.subList(gpc, tpc));
gtype = test.type();
}
return MethodHandleImpl.makeGuardWithTest(IMPL_TOKEN, test, target, fallback);
return MethodHandleImpl.makeGuardWithTest(test, target, fallback);
}
static RuntimeException misMatchedTypes(String what, MethodType t1, MethodType t2) {
......@@ -2029,7 +2044,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
}
/**
* Make a method handle which adapts a target method handle,
* Makes a method handle which adapts a target method handle,
* by running it inside an exception handler.
* If the target returns normally, the adapter returns that value.
* If an exception matching the specified type is thrown, the fallback
......@@ -2092,7 +2107,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
handler = dropArguments(handler, hpc, hargs.subList(hpc, tpc));
htype = handler.type();
}
return MethodHandleImpl.makeGuardWithCatch(IMPL_TOKEN, target, exType, handler);
return MethodHandleImpl.makeGuardWithCatch(target, exType, handler);
}
/**
......@@ -2107,51 +2122,45 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
*/
public static
MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType) {
return MethodHandleImpl.throwException(IMPL_TOKEN, MethodType.methodType(returnType, exType));
return MethodHandleImpl.throwException(MethodType.methodType(returnType, exType));
}
/**
* Produces an instance of the given "SAM" interface which redirects
* Produces an instance of the given single-method interface which redirects
* its calls to the given method handle.
* <p>
* A SAM interface is an interface which declares a single abstract method.
* When determining the unique abstract method of a SAM interface,
* A single-method interface is an interface which declares a unique method.
* When determining the unique method of a single-method interface,
* the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode})
* are disregarded. For example, {@link java.util.Comparator} is a SAM interface,
* are disregarded. For example, {@link java.util.Comparator} is a single-method interface,
* even though it re-declares the {@code Object.equals} method.
* Also, if the SAM interface has a supertype,
* the SAM interface may override an inherited method.
* Any such overrides are respected, and the method handle will be accessible
* by either the inherited method or the SAM method.
* In particular, a {@linkplain java.lang.reflect.Method#isBridge bridge method}
* may be created if the methods have different return types.
* <p>
* The type must be public. No additional access checks are performed.
* <p>
* The resulting instance of the required SAM type will respond to
* invocation of the SAM type's single abstract method by calling
* The resulting instance of the required type will respond to
* invocation of the type's single abstract method by calling
* the given {@code target} on the incoming arguments,
* and returning or throwing whatever the {@code target}
* returns or throws. The invocation will be as if by
* {@code target.invokeGeneric}.
* The target's type will be checked before the SAM
* The target's type will be checked before the
* instance is created, as if by a call to {@code asType},
* which may result in a {@code WrongMethodTypeException}.
* <p>
* The wrapper instance will implement the requested SAM interface
* and its super-types, but no other SAM types.
* This means that the SAM instance will not unexpectedly
* The wrapper instance will implement the requested interface
* and its super-types, but no other single-method interfaces.
* This means that the instance will not unexpectedly
* pass an {@code instanceof} test for any unrequested type.
* <p style="font-size:smaller;">
* <em>Implementation Note:</em>
* Therefore, each SAM instance must implement a unique SAM type.
* Therefore, each instance must implement a unique single-method interface.
* Implementations may not bundle together
* multiple SAM types onto single implementation classes
* multiple single-method interfaces onto single implementation classes
* in the style of {@link java.awt.AWTEventMulticaster}.
* <p>
* The method handle may throw an <em>undeclared exception</em>,
* which means any checked exception (or other checked throwable)
* not declared by the SAM type's single abstract method.
* not declared by the requested type's single abstract method.
* If this happens, the throwable will be wrapped in an instance of
* {@link java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException}
* and thrown in that wrapped form.
......@@ -2161,28 +2170,37 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
* by their behavior.
* It is not guaranteed to return a new instance for every call.
* <p>
* Because of the possibility of {@linkplain java.lang.reflect.Method#isBridge bridge methods}
* and other corner cases, the interface may also have several abstract methods
* with the same name but having distinct descriptors (types of returns and parameters).
* In this case, all the methods are bound in common to the one given {@code target}.
* The type check and effective {@code asType} conversion is applied to each
* method type descriptor, and all abstract methods are bound to the {@code target} in common.
* Beyond this type check, no further checks are made to determine that the
* abstract methods are related in any way.
* <p>
* Future versions of this API may accept additional types,
* such as abstract classes with single abstract methods.
* Future versions of this API may also equip wrapper instances
* with one or more additional public "marker" interfaces.
*
* @param target the method handle to invoke from the wrapper
* @param samType the desired type of the wrapper, a SAM type
* @param smType the desired type of the wrapper, a single-method interface
* @return a correctly-typed wrapper for the given {@code target}
* @throws NullPointerException if either argument is null
* @throws IllegalArgumentException if the {@code samType} is not a
* @throws IllegalArgumentException if the {@code smType} is not a
* valid argument to this method
* @throws WrongMethodTypeException if the {@code target} cannot
* be converted to the type required by the SAM type
* be converted to the type required by the requested interface
*/
// Other notes to implementors:
// <p>
// No stable mapping is promised between the SAM type and
// No stable mapping is promised between the single-method interface and
// the implementation class C. Over time, several implementation
// classes might be used for the same SAM type.
// classes might be used for the same type.
// <p>
// If the implementation is able
// to prove that a wrapper of the required SAM type
// to prove that a wrapper of the required type
// has already been created for a given
// method handle, or for another method handle with the
// same behavior, the implementation may return that wrapper in place of
......@@ -2191,34 +2209,34 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
// This method is designed to apply to common use cases
// where a single method handle must interoperate with
// an interface that implements a function-like
// API. Additional variations, such as SAM classes with
// API. Additional variations, such as single-abstract-method classes with
// private constructors, or interfaces with multiple but related
// entry points, must be covered by hand-written or automatically
// generated adapter classes.
//
public static
<T> T asInstance(final MethodHandle target, final Class<T> samType) {
<T> T asInstance(final MethodHandle target, final Class<T> smType) {
// POC implementation only; violates the above contract several ways
final Method sam = getSamMethod(samType);
if (sam == null)
throw new IllegalArgumentException("not a SAM type: "+samType.getName());
MethodType samMT = MethodType.methodType(sam.getReturnType(), sam.getParameterTypes());
MethodHandle checkTarget = target.asType(samMT); // make throw WMT
final Method sm = getSingleMethod(smType);
if (sm == null)
throw new IllegalArgumentException("not a single-method interface: "+smType.getName());
MethodType smMT = MethodType.methodType(sm.getReturnType(), sm.getParameterTypes());
MethodHandle checkTarget = target.asType(smMT); // make throw WMT
checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class));
final MethodHandle vaTarget = checkTarget.asSpreader(Object[].class, samMT.parameterCount());
return samType.cast(Proxy.newProxyInstance(
samType.getClassLoader(),
new Class[]{ samType, WrapperInstance.class },
final MethodHandle vaTarget = checkTarget.asSpreader(Object[].class, smMT.parameterCount());
return smType.cast(Proxy.newProxyInstance(
smType.getClassLoader(),
new Class[]{ smType, WrapperInstance.class },
new InvocationHandler() {
private Object getArg(String name) {
if ((Object)name == "getWrapperInstanceTarget") return target;
if ((Object)name == "getWrapperInstanceType") return samType;
if ((Object)name == "getWrapperInstanceType") return smType;
throw new AssertionError();
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == WrapperInstance.class)
return getArg(method.getName());
if (method.equals(sam))
if (method.equals(sm))
return vaTarget.invokeExact(args);
if (isObjectMethod(method))
return callObjectMethod(this, method, args);
......@@ -2228,7 +2246,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
}
/**
* Determine if the given object was produced by a call to {@link #asInstance asInstance}.
* Determines if the given object was produced by a call to {@link #asInstance asInstance}.
* @param x any reference
* @return true if the reference is not null and points to an object produced by {@code asInstance}
*/
......@@ -2248,11 +2266,11 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
/**
* Produces or recovers a target method handle which is behaviorally
* equivalent to the SAM method of this wrapper instance.
* equivalent to the unique method of this wrapper instance.
* The object {@code x} must have been produced by a call to {@link #asInstance asInstance}.
* This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
* @param x any reference
* @return a method handle implementing the SAM method
* @return a method handle implementing the unique method
* @throws IllegalArgumentException if the reference x is not to a wrapper instance
*/
public static
......@@ -2261,11 +2279,11 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
}
/**
* Recover the SAM type for which this wrapper instance was created.
* Recovers the unique single-method interface type for which this wrapper instance was created.
* The object {@code x} must have been produced by a call to {@link #asInstance asInstance}.
* This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
* @param x any reference
* @return the SAM type for which the wrapper was created
* @return the single-method interface type for which the wrapper was created
* @throws IllegalArgumentException if the reference x is not to a wrapper instance
*/
public static
......@@ -2305,24 +2323,24 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
}
private static
Method getSamMethod(Class<?> samType) {
Method sam = null;
for (Method m : samType.getMethods()) {
Method getSingleMethod(Class<?> smType) {
Method sm = null;
for (Method m : smType.getMethods()) {
int mod = m.getModifiers();
if (Modifier.isAbstract(mod)) {
if (sam != null && !isObjectMethod(sam))
if (sm != null && !isObjectMethod(sm))
return null; // too many abstract methods
sam = m;
sm = m;
}
}
if (!samType.isInterface() && getSamConstructor(samType) == null)
if (!smType.isInterface() && getSingleConstructor(smType) == null)
return null; // wrong kind of constructor
return sam;
return sm;
}
private static
Constructor getSamConstructor(Class<?> samType) {
for (Constructor c : samType.getDeclaredConstructors()) {
Constructor getSingleConstructor(Class<?> smType) {
for (Constructor c : smType.getDeclaredConstructors()) {
if (c.getParameterTypes().length == 0) {
int mod = c.getModifiers();
if (Modifier.isPublic(mod) || Modifier.isProtected(mod))
......@@ -2334,6 +2352,6 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
/*non-public*/
static MethodHandle asVarargsCollector(MethodHandle target, Class<?> arrayType) {
return MethodHandleImpl.asVarargsCollector(IMPL_TOKEN, target, arrayType);
return MethodHandleImpl.asVarargsCollector(target, arrayType);
}
}
......@@ -23,18 +23,14 @@
* questions.
*/
package java.dyn;
package java.lang.invoke;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import sun.dyn.Access;
import sun.dyn.Invokers;
import sun.dyn.MethodHandleImpl;
import sun.dyn.MethodTypeImpl;
import sun.dyn.util.BytecodeDescriptor;
import static sun.dyn.MemberName.newIllegalArgumentException;
import sun.invoke.util.BytecodeDescriptor;
import static java.lang.invoke.MethodHandleStatics.*;
/**
* A method type represents the arguments and return type accepted and
......@@ -96,34 +92,6 @@ class MethodType implements java.io.Serializable {
private MethodType wrapAlt; // alternative wrapped/unwrapped version
private Invokers invokers; // cache of handy higher-order adapters
private static final Access IMPL_TOKEN = Access.getToken();
// share a cache with a friend in this package
Invokers getInvokers() { return invokers; }
void setInvokers(Invokers inv) { invokers = inv; }
static {
// This hack allows the implementation package special access to
// the internals of MethodType. In particular, the MTImpl has all sorts
// of cached information useful to the implementation code.
MethodTypeImpl.setMethodTypeFriend(IMPL_TOKEN, new MethodTypeImpl.MethodTypeFriend() {
public Class<?>[] ptypes(MethodType mt) { return mt.ptypes; }
public MethodTypeImpl form(MethodType mt) { return mt.form; }
public void setForm(MethodType mt, MethodTypeImpl form) {
assert(mt.form == null);
mt.form = (MethodTypeForm) form;
}
public MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
return MethodType.makeImpl(rtype, ptypes, trusted);
}
public MethodTypeImpl newMethodTypeForm(MethodType mt) {
return new MethodTypeForm(mt);
}
public Invokers getInvokers(MethodType mt) { return mt.invokers; }
public void setInvokers(MethodType mt, Invokers inv) { mt.invokers = inv; }
});
}
/**
* Check the given parameters for validity and store them into the final fields.
*/
......@@ -134,6 +102,10 @@ class MethodType implements java.io.Serializable {
this.ptypes = ptypes;
}
/*trusted*/ MethodTypeForm form() { return form; }
/*trusted*/ Class<?> rtype() { return rtype; }
/*trusted*/ Class<?>[] ptypes() { return ptypes; }
private static void checkRtype(Class<?> rtype) {
rtype.equals(rtype); // null check
}
......@@ -168,7 +140,7 @@ class MethodType implements java.io.Serializable {
static final Class<?>[] NO_PTYPES = {};
/**
* Find or create an instance of the given method type.
* Finds or creates an instance of the given method type.
* @param rtype the return type
* @param ptypes the parameter types
* @return a method type with the given components
......@@ -253,7 +225,7 @@ class MethodType implements java.io.Serializable {
* @param trusted whether the ptypes can be used without cloning
* @return the unique method type of the desired structure
*/
private static
/*trusted*/ static
MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
if (ptypes == null || ptypes.length == 0) {
ptypes = NO_PTYPES; trusted = true;
......@@ -269,7 +241,12 @@ class MethodType implements java.io.Serializable {
// defensively copy the array passed in by the user
mt1 = new MethodType(rtype, ptypes.clone());
// promote the object to the Real Thing, and reprobe
MethodTypeImpl.initForm(IMPL_TOKEN, mt1);
MethodTypeForm form = MethodTypeForm.findForm(mt1);
mt1.form = form;
if (form.erasedType == mt1) {
// This is a principal (erased) type; show it to the JVM.
MethodHandleNatives.init(mt1);
}
synchronized (internTable) {
mt0 = internTable.get(mt1);
if (mt0 != null)
......@@ -279,12 +256,6 @@ class MethodType implements java.io.Serializable {
return mt1;
}
// Entry point from JVM. TODO: Change the name & signature.
private static MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes,
boolean ignore1, boolean ignore2) {
return makeImpl(rtype, ptypes, true);
}
private static final MethodType[] objectOnlyTypes = new MethodType[20];
/**
......@@ -519,7 +490,7 @@ class MethodType implements java.io.Serializable {
}
/**
* Convert all wrapper types to their corresponding primitive types.
* Converts all wrapper types to their corresponding primitive types.
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
* All primitive types (including {@code void}) will remain unchanged.
* A return type of {@code java.lang.Void} is changed to {@code void}.
......@@ -535,7 +506,7 @@ class MethodType implements java.io.Serializable {
MethodType wt = pt.wrapAlt;
if (wt == null) {
// fill in lazily
wt = MethodTypeImpl.canonicalize(pt, MethodTypeImpl.WRAP, MethodTypeImpl.WRAP);
wt = MethodTypeForm.canonicalize(pt, MethodTypeForm.WRAP, MethodTypeForm.WRAP);
assert(wt != null);
pt.wrapAlt = wt;
}
......@@ -547,7 +518,7 @@ class MethodType implements java.io.Serializable {
MethodType uwt = wt.wrapAlt;
if (uwt == null) {
// fill in lazily
uwt = MethodTypeImpl.canonicalize(wt, MethodTypeImpl.UNWRAP, MethodTypeImpl.UNWRAP);
uwt = MethodTypeForm.canonicalize(wt, MethodTypeForm.UNWRAP, MethodTypeForm.UNWRAP);
if (uwt == null)
uwt = wt; // type has no wrappers or prims at all
wt.wrapAlt = uwt;
......@@ -658,7 +629,7 @@ class MethodType implements java.io.Serializable {
/// Queries which have to do with the bytecode architecture
/** Reports the number of JVM stack slots required to invoke a method
* of this type. Note that (for historic reasons) the JVM requires
* of this type. Note that (for historical reasons) the JVM requires
* a second stack slot to pass long and double arguments.
* So this method returns {@link #parameterCount() parameterCount} plus the
* number of long and double parameters (if any).
......@@ -666,12 +637,18 @@ class MethodType implements java.io.Serializable {
* This method is included for the benfit of applications that must
* generate bytecodes that process method handles and invokedynamic.
* @return the number of JVM stack slots for this type's parameters
* @deprecated Will be removed for PFD.
*/
public int parameterSlotCount() {
/*non-public*/ int parameterSlotCount() {
return form.parameterSlotCount();
}
/*non-public*/ Invokers invokers() {
Invokers inv = invokers;
if (inv != null) return inv;
invokers = inv = new Invokers(this);
return inv;
}
/** Reports the number of JVM stack slots which carry all parameters including and after
* the given position, which must be in the range of 0 to
* {@code parameterCount} inclusive. Successive parameters are
......@@ -694,9 +671,8 @@ class MethodType implements java.io.Serializable {
* @return the index of the (shallowest) JVM stack slot transmitting the
* given parameter
* @throws IllegalArgumentException if {@code num} is negative or greater than {@code parameterCount()}
* @deprecated Will be removed for PFD.
*/
public int parameterSlotDepth(int num) {
/*non-public*/ int parameterSlotDepth(int num) {
if (num < 0 || num > ptypes.length)
parameterType(num); // force a range check
return form.parameterToArgSlot(num-1);
......@@ -710,14 +686,14 @@ class MethodType implements java.io.Serializable {
* This method is included for the benfit of applications that must
* generate bytecodes that process method handles and invokedynamic.
* @return the number of JVM stack slots (0, 1, or 2) for this type's return value
* @deprecated Will be removed for PFD.
* Will be removed for PFD.
*/
public int returnSlotCount() {
/*non-public*/ int returnSlotCount() {
return form.returnSlotCount();
}
/**
* Find or create an instance of a method type, given the spelling of its bytecode descriptor.
* Finds or creates an instance of a method type, given the spelling of its bytecode descriptor.
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
* Any class or interface name embedded in the descriptor string
* will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)}
......
......@@ -23,11 +23,10 @@
* questions.
*/
package sun.dyn;
package java.lang.invoke;
import java.dyn.*;
import sun.dyn.util.Wrapper;
import static sun.dyn.MemberName.newIllegalArgumentException;
import sun.invoke.util.Wrapper;
import static java.lang.invoke.MethodHandleStatics.*;
/**
* Shared information for a group of method types, which differ
......@@ -42,7 +41,7 @@ import static sun.dyn.MemberName.newIllegalArgumentException;
* No more than half of these are likely to be loaded at once.
* @author John Rose
*/
public class MethodTypeImpl {
class MethodTypeForm {
final int[] argToSlotTable, slotToArgTable;
final long argCounts; // packed slot & value counts
final long primCounts; // packed prim & double counts
......@@ -66,39 +65,10 @@ public class MethodTypeImpl {
return erasedType;
}
public static MethodTypeImpl of(MethodType type) {
return METHOD_TYPE_FRIEND.form(type);
}
/** Access methods for the internals of MethodType, supplied to
* MethodTypeImpl as a trusted agent.
*/
static public interface MethodTypeFriend {
Class<?>[] ptypes(MethodType mt);
MethodTypeImpl form(MethodType mt);
void setForm(MethodType mt, MethodTypeImpl form);
MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted);
MethodTypeImpl newMethodTypeForm(MethodType mt);
Invokers getInvokers(MethodType mt);
void setInvokers(MethodType mt, Invokers inv);
}
public static void setMethodTypeFriend(Access token, MethodTypeFriend am) {
Access.check(token);
if (METHOD_TYPE_FRIEND != null)
throw new InternalError(); // just once
METHOD_TYPE_FRIEND = am;
}
static private MethodTypeFriend METHOD_TYPE_FRIEND;
static MethodType makeImpl(Access token, Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
Access.check(token);
return METHOD_TYPE_FRIEND.makeImpl(rtype, ptypes, trusted);
}
protected MethodTypeImpl(MethodType erasedType) {
protected MethodTypeForm(MethodType erasedType) {
this.erasedType = erasedType;
Class<?>[] ptypes = METHOD_TYPE_FRIEND.ptypes(erasedType);
Class<?>[] ptypes = erasedType.ptypes();
int ptypeCount = ptypes.length;
int pslotCount = ptypeCount; // temp. estimate
int rtypeCount = 1; // temp. estimate
......@@ -260,7 +230,7 @@ public class MethodTypeImpl {
* the type {@code (Object,int)Object} produces {@code null}.
*/
public static int[] primsAtEndOrder(MethodType mt) {
MethodTypeImpl form = METHOD_TYPE_FRIEND.form(mt);
MethodTypeForm form = mt.form();
if (form.primsAtEnd == form.erasedType)
// quick check shows no reordering is necessary
return null;
......@@ -273,7 +243,7 @@ public class MethodTypeImpl {
int lac = form.longPrimitiveParameterCount();
int rfill = 0, ifill = argc - pac, lfill = argc - lac;
Class<?>[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt);
Class<?>[] ptypes = mt.ptypes();
boolean changed = false;
for (int i = 0; i < ptypes.length; i++) {
Class<?> pt = ptypes[i];
......@@ -300,7 +270,7 @@ public class MethodTypeImpl {
*/
public static MethodType reorderParameters(MethodType mt, int[] newParamOrder, Class<?>[] moreParams) {
if (newParamOrder == null) return mt; // no-op reordering
Class<?>[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt);
Class<?>[] ptypes = mt.ptypes();
Class<?>[] ntypes = new Class<?>[newParamOrder.length];
int maxParam = ptypes.length + (moreParams == null ? 0 : moreParams.length);
boolean changed = (ntypes.length != ptypes.length);
......@@ -314,7 +284,7 @@ public class MethodTypeImpl {
ntypes[i] = nt;
}
if (!changed) return mt;
return METHOD_TYPE_FRIEND.makeImpl(mt.returnType(), ntypes, true);
return MethodType.makeImpl(mt.returnType(), ntypes, true);
}
private static boolean hasTwoArgSlots(Class<?> type) {
......@@ -376,28 +346,18 @@ public class MethodTypeImpl {
return slotToArgTable[argSlot] - 1;
}
public static void initForm(Access token, MethodType mt) {
Access.check(token);
MethodTypeImpl form = findForm(mt);
METHOD_TYPE_FRIEND.setForm(mt, form);
if (form.erasedType == mt) {
// This is a principal (erased) type; show it to the JVM.
MethodHandleImpl.init(token, mt);
}
}
static MethodTypeImpl findForm(MethodType mt) {
static MethodTypeForm findForm(MethodType mt) {
MethodType erased = canonicalize(mt, ERASE, ERASE);
if (erased == null) {
// It is already erased. Make a new MethodTypeImpl.
return METHOD_TYPE_FRIEND.newMethodTypeForm(mt);
// It is already erased. Make a new MethodTypeForm.
return new MethodTypeForm(mt);
} else {
// Share the MethodTypeImpl with the erased version.
return METHOD_TYPE_FRIEND.form(erased);
// Share the MethodTypeForm with the erased version.
return erased.form();
}
}
/** Codes for {@link #canonicalize(java.lang.Class, int).
/** Codes for {@link #canonicalize(java.lang.Class, int)}.
* ERASE means change every reference to {@code Object}.
* WRAP means convert primitives (including {@code void} to their
* corresponding wrapper types. UNWRAP means the reverse of WRAP.
......@@ -414,10 +374,10 @@ public class MethodTypeImpl {
* Otherwise return null.
*/
public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) {
Class<?>[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt);
Class<?>[] ptc = MethodTypeImpl.canonicalizes(ptypes, howArgs);
Class<?>[] ptypes = mt.ptypes();
Class<?>[] ptc = MethodTypeForm.canonicalizes(ptypes, howArgs);
Class<?> rtype = mt.returnType();
Class<?> rtc = MethodTypeImpl.canonicalize(rtype, howRet);
Class<?> rtc = MethodTypeForm.canonicalize(rtype, howRet);
if (ptc == null && rtc == null) {
// It is already canonical.
return null;
......@@ -425,7 +385,7 @@ public class MethodTypeImpl {
// Find the erased version of the method type:
if (rtc == null) rtc = rtype;
if (ptc == null) ptc = ptypes;
return METHOD_TYPE_FRIEND.makeImpl(rtc, ptc, true);
return MethodType.makeImpl(rtc, ptc, true);
}
/** Canonicalize the given return or param type.
......@@ -496,16 +456,16 @@ public class MethodTypeImpl {
return cs;
}
public static Invokers invokers(Access token, MethodType type) {
Access.check(token);
return invokers(type);
/*non-public*/ void notifyGenericMethodType() {
if (genericInvoker != null) return;
try {
// Trigger adapter creation.
genericInvoker = InvokeGeneric.genericInvokerOf(erasedType);
} catch (Exception ex) {
Error err = new InternalError("Exception while resolving invokeGeneric");
err.initCause(ex);
throw err;
}
/*non-public*/ static Invokers invokers(MethodType type) {
Invokers inv = METHOD_TYPE_FRIEND.getInvokers(type);
if (inv != null) return inv;
inv = new Invokers(type);
METHOD_TYPE_FRIEND.setInvokers(type, inv);
return inv;
}
@Override
......
......@@ -23,10 +23,8 @@
* questions.
*/
package java.dyn;
package java.lang.invoke;
import sun.dyn.*;
import sun.dyn.empty.Empty;
import java.util.concurrent.atomic.AtomicInteger;
/**
......
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,14 +23,14 @@
* questions.
*/
package sun.dyn;
package java.lang.invoke;
import java.dyn.*;
import sun.invoke.util.ValueConversions;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import sun.dyn.util.ValueConversions;
import static sun.dyn.MemberName.newIllegalArgumentException;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* Generic spread adapter.
......@@ -110,7 +110,7 @@ class SpreadGeneric {
static SpreadGeneric of(MethodType targetType, int spreadCount) {
if (targetType != targetType.generic())
throw new UnsupportedOperationException("NYI type="+targetType);
MethodTypeImpl form = MethodTypeImpl.of(targetType);
MethodTypeForm form = targetType.form();
int outcount = form.parameterCount();
assert(spreadCount <= outcount);
SpreadGeneric[] spreadGens = form.spreadGeneric;
......@@ -129,7 +129,7 @@ class SpreadGeneric {
// This mini-api is called from an Adapter to manage the spread.
/** A check/coercion that happens once before any selections. */
protected Object check(Object av, int n) {
MethodHandleImpl.checkSpreadArgument(av, n);
checkSpreadArgument(av, n);
return av;
}
......@@ -166,7 +166,7 @@ class SpreadGeneric {
// see if it has the required invoke method
MethodHandle entryPoint = null;
try {
entryPoint = MethodHandleImpl.IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
entryPoint = IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
} catch (ReflectiveOperationException ex) {
}
if (entryPoint == null) continue;
......@@ -221,21 +221,21 @@ class SpreadGeneric {
@Override
public String toString() {
return MethodHandleImpl.addTypeString(target, this);
return addTypeString(target, this);
}
static final MethodHandle NO_ENTRY = ValueConversions.identity();
protected boolean isPrototype() { return target == null; }
protected Adapter(SpreadGeneric outer) {
super(Access.TOKEN, NO_ENTRY);
super(NO_ENTRY);
this.outer = outer;
this.target = null;
assert(isPrototype());
}
protected Adapter(SpreadGeneric outer, MethodHandle target) {
super(Access.TOKEN, outer.entryPoint);
super(outer.entryPoint);
this.outer = outer;
this.target = target;
}
......@@ -251,7 +251,7 @@ class SpreadGeneric {
return outer.select(av, n);
}
static private final String CLASS_PREFIX; // "sun.dyn.SpreadGeneric$"
static private final String CLASS_PREFIX; // "java.lang.invoke.SpreadGeneric$"
static {
String aname = Adapter.class.getName();
String sname = Adapter.class.getSimpleName();
......
......@@ -23,7 +23,7 @@
* questions.
*/
package java.dyn;
package java.lang.invoke;
/**
* <p>
......@@ -73,6 +73,10 @@ assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
* Switch points are useful without subclassing. They may also be subclassed.
* This may be useful in order to associate application-specific invalidation logic
* with the switch point.
* Notice that there is no permanent association between a switch point and
* the method handles it produces and consumes.
* The garbage collector may collect method handles produced or consumed
* by a switch point independently of the lifetime of the switch point itself.
* <p style="font-size:smaller;">
* <em>Implementation Note:</em>
* A switch point behaves as if implemented on top of {@link MutableCallSite},
......
......@@ -23,15 +23,14 @@
* questions.
*/
package sun.dyn;
package java.lang.invoke;
import java.dyn.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import sun.dyn.util.ValueConversions;
import sun.dyn.util.Wrapper;
import static sun.dyn.MemberName.newIllegalArgumentException;
import static sun.dyn.MethodTypeImpl.invokers;
import sun.invoke.util.ValueConversions;
import sun.invoke.util.Wrapper;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* Adapters which mediate between incoming calls which are not generic
......@@ -73,7 +72,7 @@ class ToGeneric {
assert(entryType.erase() == entryType); // for now
// incoming call will first "forget" all reference types except Object
this.entryType = entryType;
MethodHandle invoker0 = invokers(entryType.generic()).exactInvoker();
MethodHandle invoker0 = entryType.generic().invokers().exactInvoker();
MethodType rawEntryTypeInit;
Adapter ad = findAdapter(rawEntryTypeInit = entryType);
if (ad != null) {
......@@ -89,15 +88,15 @@ class ToGeneric {
}
// next, it will reorder primitives after references
MethodType primsAtEnd = MethodTypeImpl.of(entryType).primsAtEnd();
MethodType primsAtEnd = entryType.form().primsAtEnd();
// at the same time, it will "forget" all primitive types except int/long
this.primsAtEndOrder = MethodTypeImpl.primsAtEndOrder(entryType);
this.primsAtEndOrder = MethodTypeForm.primsAtEndOrder(entryType);
if (primsAtEndOrder != null) {
// reordering is required; build on top of a simpler ToGeneric
ToGeneric va2 = ToGeneric.of(primsAtEnd);
this.adapter = va2.adapter;
if (true) throw new UnsupportedOperationException("NYI: primitive parameters must follow references; entryType = "+entryType);
this.entryPoint = MethodHandleImpl.convertArguments(Access.TOKEN,
this.entryPoint = MethodHandleImpl.convertArguments(
va2.entryPoint, primsAtEnd, entryType, primsAtEndOrder);
// example: for entryType of (int,Object,Object), the reordered
// type is (Object,Object,int) and the order is {1,2,0},
......@@ -107,7 +106,7 @@ class ToGeneric {
// after any needed argument reordering, it will reinterpret
// primitive arguments according to their "raw" types int/long
MethodType intsAtEnd = MethodTypeImpl.of(primsAtEnd).primsAsInts();
MethodType intsAtEnd = primsAtEnd.form().primsAsInts();
ad = findAdapter(rawEntryTypeInit = intsAtEnd);
MethodHandle rawEntryPoint;
if (ad != null) {
......@@ -116,7 +115,7 @@ class ToGeneric {
// Perhaps the adapter is available only for longs.
// If so, we can use it, but there will have to be a little
// more stack motion on each call.
MethodType longsAtEnd = MethodTypeImpl.of(primsAtEnd).primsAsLongs();
MethodType longsAtEnd = primsAtEnd.form().primsAsLongs();
ad = findAdapter(rawEntryTypeInit = longsAtEnd);
if (ad != null) {
MethodType eptWithLongs = longsAtEnd.insertParameterTypes(0, ad.getClass());
......@@ -128,7 +127,7 @@ class ToGeneric {
assert(midType.parameterType(i) == long.class);
assert(eptWithInts.parameterType(i) == int.class);
MethodType nextType = midType.changeParameterType(i, int.class);
rawEntryPoint = MethodHandle.convertArguments(Access.TOKEN,
rawEntryPoint = MethodHandleImpl.convertArguments(
rawEntryPoint, nextType, midType, null);
midType = nextType;
}
......@@ -143,7 +142,7 @@ class ToGeneric {
}
MethodType tepType = entryType.insertParameterTypes(0, ad.getClass());
this.entryPoint =
AdapterMethodHandle.makeRetypeRaw(Access.TOKEN, tepType, rawEntryPoint);
AdapterMethodHandle.makeRetypeRaw(tepType, rawEntryPoint);
if (this.entryPoint == null)
throw new UnsupportedOperationException("cannot retype to "+entryType
+" from "+rawEntryPoint.type().dropParameterTypes(0, 1));
......@@ -168,7 +167,7 @@ class ToGeneric {
assert(src.isPrimitive() && dst.isPrimitive());
if (filteredInvoker == null) {
filteredInvoker =
AdapterMethodHandle.makeCheckCast(Access.TOKEN,
AdapterMethodHandle.makeCheckCast(
invoker.type().generic(), invoker, 0, MethodHandle.class);
if (filteredInvoker == null) throw new UnsupportedOperationException("NYI");
}
......@@ -177,7 +176,7 @@ class ToGeneric {
if (filteredInvoker == null) throw new InternalError();
}
if (filteredInvoker == null) return invoker;
return AdapterMethodHandle.makeRetypeOnly(Access.TOKEN, invoker.type(), filteredInvoker);
return AdapterMethodHandle.makeRetypeOnly(invoker.type(), filteredInvoker);
}
/**
......@@ -227,7 +226,7 @@ class ToGeneric {
// retype erased reference arguments (the cast makes it safe to do this)
MethodType tepType = type.insertParameterTypes(0, adapter.getClass());
MethodHandle typedEntryPoint =
AdapterMethodHandle.makeRetypeRaw(Access.TOKEN, tepType, entryPoint);
AdapterMethodHandle.makeRetypeRaw(tepType, entryPoint);
return adapter.makeInstance(typedEntryPoint, invoker, convert, genericTarget);
}
......@@ -248,7 +247,7 @@ class ToGeneric {
/** Return the adapter information for this type's erasure. */
static ToGeneric of(MethodType type) {
MethodTypeImpl form = MethodTypeImpl.of(type);
MethodTypeForm form = type.form();
ToGeneric toGen = form.toGeneric;
if (toGen == null)
form.toGeneric = toGen = new ToGeneric(form.erasedType());
......@@ -262,7 +261,7 @@ class ToGeneric {
/* Create an adapter for the given incoming call type. */
static Adapter findAdapter(MethodType entryPointType) {
MethodTypeImpl form = MethodTypeImpl.of(entryPointType);
MethodTypeForm form = entryPointType.form();
Class<?> rtype = entryPointType.returnType();
int argc = form.parameterCount();
int lac = form.longPrimitiveParameterCount();
......@@ -283,7 +282,7 @@ class ToGeneric {
for (String iname : inames) {
MethodHandle entryPoint = null;
try {
entryPoint = MethodHandleImpl.IMPL_LOOKUP.
entryPoint = IMPL_LOOKUP.
findSpecial(acls, iname, entryPointType, acls);
} catch (ReflectiveOperationException ex) {
}
......@@ -338,13 +337,13 @@ class ToGeneric {
@Override
public String toString() {
return target == null ? "prototype:"+convert : MethodHandleImpl.addTypeString(target, this);
return target == null ? "prototype:"+convert : addTypeString(target, this);
}
protected boolean isPrototype() { return target == null; }
/* Prototype constructor. */
protected Adapter(MethodHandle entryPoint) {
super(Access.TOKEN, entryPoint);
super(entryPoint);
this.invoker = null;
this.convert = entryPoint;
this.target = null;
......@@ -356,7 +355,7 @@ class ToGeneric {
}
protected Adapter(MethodHandle entryPoint, MethodHandle invoker, MethodHandle convert, MethodHandle target) {
super(Access.TOKEN, entryPoint);
super(entryPoint);
this.invoker = invoker;
this.convert = convert;
this.target = target;
......@@ -396,7 +395,7 @@ class ToGeneric {
protected float return_F(Object res) throws Throwable { return (float) convert.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; // "java.lang.invoke.ToGeneric$"
static {
String aname = Adapter.class.getName();
String sname = Adapter.class.getSimpleName();
......@@ -452,14 +451,15 @@ class genclasses {
static String[] TCHARS = { "L", "I", "J", "F", "D", "A" };
static String[][] TEMPLATES = { {
"@for@ arity=0..3 rcat<=4 nrefs<=99 nints<=99 nlongs<=99",
"@for@ arity=4..5 rcat<=2 nrefs<=99 nints<=99 nlongs<=99",
"@for@ arity=4..4 rcat<=4 nrefs<=99 nints<=99 nlongs<=99",
"@for@ arity=5..5 rcat<=2 nrefs<=99 nints<=99 nlongs<=99",
"@for@ arity=6..10 rcat<=2 nrefs<=99 nints=0 nlongs<=99",
" //@each-cat@",
" static class @cat@ extends Adapter {",
" 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@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new @cat@(e, i, c, t); }",
" protected Object target(@Ovav@) throws Throwable { return invoker.invokeExact(target, @av@); }",
" protected Object target(@Ovav@) throws Throwable { return invoker.invokeExact(target@comma@@av@); }",
" //@each-Tv@",
" protected Object target@cat@(@Tvav@) throws Throwable { return target(@av@); }",
" //@end-Tv@",
......@@ -471,7 +471,7 @@ class genclasses {
" }",
} };
enum VAR {
cat, R, Rc, Tv, av, Tvav, Ovav;
cat, R, Rc, Tv, av, comma, Tvav, Ovav;
public final String pattern = "@"+toString().replace('_','.')+"@";
public String binding;
static void makeBindings(boolean topLevel, int rcat, int nrefs, int nints, int nlongs) {
......@@ -493,12 +493,13 @@ class genclasses {
}
VAR.Tv.binding = comma(Tv);
VAR.av.binding = comma(av);
VAR.comma.binding = (av.length == 0 ? "" : ", ");
VAR.Tvav.binding = comma(Tvav);
VAR.Ovav.binding = comma(Ovav);
}
static String arg(int i) { return "a"+i; }
static String param(String t, String a) { return t+" "+a; }
static String comma(String[] v) { return comma(v, ""); }
static String comma(String[] v) { return comma("", v); }
static String comma(String sep, String[] v) {
if (v.length == 0) return "";
String res = sep+v[0];
......@@ -735,7 +736,7 @@ class genclasses {
protected float invoke_F(long a0, long a1, long a2) throws Throwable { return return_F(targetA3(a0, a1, a2)); }
protected double invoke_D(long a0, long a1, long a2) throws Throwable { return return_D(targetA3(a0, a1, a2)); }
}
//params=[4, 5, 2, 99, 99, 99]
//params=[4, 4, 4, 99, 99, 99]
static class A4 extends Adapter {
protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A4(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
......@@ -753,31 +754,50 @@ class genclasses {
protected Object invoke_L(Object a0, Object a1, Object a2, Object a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(Object a0, Object a1, Object a2, Object a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(Object a0, Object a1, Object a2, Object a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
protected float invoke_F(Object a0, Object a1, Object a2, Object a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
protected double invoke_D(Object a0, Object a1, Object a2, Object a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
protected Object invoke_L(Object a0, Object a1, Object a2, int a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(Object a0, Object a1, Object a2, int a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(Object a0, Object a1, Object a2, int a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
protected float invoke_F(Object a0, Object a1, Object a2, int a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
protected double invoke_D(Object a0, Object a1, Object a2, int a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
protected Object invoke_L(Object a0, Object a1, int a2, int a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(Object a0, Object a1, int a2, int a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(Object a0, Object a1, int a2, int a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
protected float invoke_F(Object a0, Object a1, int a2, int a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
protected double invoke_D(Object a0, Object a1, int a2, int a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
protected Object invoke_L(Object a0, int a1, int a2, int a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(Object a0, int a1, int a2, int a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(Object a0, int a1, int a2, int a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
protected float invoke_F(Object a0, int a1, int a2, int a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
protected double invoke_D(Object a0, int a1, int a2, int a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
protected Object invoke_L(int a0, int a1, int a2, int a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(int a0, int a1, int a2, int a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(int a0, int a1, int a2, int a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
protected float invoke_F(int a0, int a1, int a2, int a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
protected double invoke_D(int a0, int a1, int a2, int a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
protected Object invoke_L(Object a0, Object a1, Object a2, long a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(Object a0, Object a1, Object a2, long a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(Object a0, Object a1, Object a2, long a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
protected float invoke_F(Object a0, Object a1, Object a2, long a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
protected double invoke_D(Object a0, Object a1, Object a2, long a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
protected Object invoke_L(Object a0, Object a1, long a2, long a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(Object a0, Object a1, long a2, long a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(Object a0, Object a1, long a2, long a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
protected float invoke_F(Object a0, Object a1, long a2, long a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
protected double invoke_D(Object a0, Object a1, long a2, long a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
protected Object invoke_L(Object a0, long a1, long a2, long a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(Object a0, long a1, long a2, long a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(Object a0, long a1, long a2, long a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
protected float invoke_F(Object a0, long a1, long a2, long a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
protected double invoke_D(Object a0, long a1, long a2, long a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
protected Object invoke_L(long a0, long a1, long a2, long a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(long a0, long a1, long a2, long a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(long a0, long a1, long a2, long a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
protected float invoke_F(long a0, long a1, long a2, long a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
protected double invoke_D(long a0, long a1, long a2, long a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
}
//params=[5, 5, 2, 99, 99, 99]
static class A5 extends Adapter {
protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A5(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
......
......@@ -23,9 +23,7 @@
* questions.
*/
package java.dyn;
import java.util.List;
package java.lang.invoke;
/**
* A {@code VolatileCallSite} is a {@link CallSite} whose target acts like a volatile variable.
......
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,7 +23,7 @@
* questions.
*/
package java.dyn;
package java.lang.invoke;
/**
* Thrown to indicate that code has attempted to call a method handle
......
......@@ -27,21 +27,18 @@
* The {@code java.lang.invoke} package contains dynamic language support provided directly by
* the Java core class libraries and virtual machine.
*
* <p style="font-size:smaller;">
* <em>Historic Note:</em> In some early versions of Java SE 7,
* the name of this package is {@code java.dyn}.
* <p>
* Certain types in this package have special relations to dynamic
* language support in the virtual machine:
* <ul>
* <li>The class {@link java.dyn.MethodHandle MethodHandle} contains
* <li>The class {@link java.lang.invoke.MethodHandle MethodHandle} contains
* <a href="MethodHandle.html#sigpoly">signature polymorphic methods</a>
* which can be linked regardless of their type descriptor.
* Normally, method linkage requires exact matching of type descriptors.
* </li>
*
* <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.lang.invoke.MethodHandle MethodHandle} and {@link java.lang.invoke.MethodType MethodType}.
* </li>
* </ul>
*
......@@ -59,7 +56,7 @@
* with tag {@code CONSTANT_InvokeDynamic} (decimal 18). See below for its format.
* The entry specifies the following information:
* <ul>
* <li>a bootstrap method (a {@link java.dyn.MethodHandle MethodHandle} constant)</li>
* <li>a bootstrap method (a {@link java.lang.invoke.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 type descriptor in a UTF8 string)</li>
* <li>optionally, a sequence of additional <em>static arguments</em> to the bootstrap method ({@code ldc}-type constants)</li>
......@@ -75,11 +72,6 @@
* A dynamic call site is linked by means of a bootstrap method,
* as <a href="#bsm">described below</a>.
*
* <p style="font-size:smaller;">
* <em>Historic Note:</em> 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.
*
* <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.
......@@ -95,20 +87,20 @@
* except that the bootstrap method specifier reference replaces
* the {@code CONSTANT_Class} reference of a {@code CONSTANT_Methodref} entry.
*
* <h3><a name="mtcon"></a>constant pool entries for {@linkplain java.dyn.MethodType method types}</h3>
* <h3><a name="mtcon"></a>constant pool entries for {@linkplain java.lang.invoke.MethodType method types}</h3>
* 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}
* entry which represents a method type descriptor.
* <p>
* The JVM will ensure that on first
* execution of an {@code ldc} instruction for this entry, a {@link java.dyn.MethodType MethodType}
* execution of an {@code ldc} instruction for this entry, a {@link java.lang.invoke.MethodType MethodType}
* will be created which represents the type descriptor.
* Any classes mentioned in the {@code MethodType} will be loaded if necessary,
* but not initialized.
* Access checking and error reporting is performed exactly as it is for
* references by {@code ldc} instructions to {@code CONSTANT_Class} constants.
*
* <h3><a name="mhcon"></a>constant pool entries for {@linkplain java.dyn.MethodHandle method handles}</h3>
* <h3><a name="mhcon"></a>constant pool entries for {@linkplain java.lang.invoke.MethodHandle method handles}</h3>
* 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
* value which must be in the range 1 through 9, and the last two must be an index to a
......@@ -119,7 +111,7 @@
* must agree according to the table below.
* <p>
* The JVM will ensure that on first execution of an {@code ldc} instruction
* for this entry, a {@link java.dyn.MethodHandle MethodHandle} will be created which represents
* for this entry, a {@link java.lang.invoke.MethodHandle MethodHandle} will be created which represents
* the field or method reference, according to the specific mode implied by the subtag.
* <p>
* As with {@code CONSTANT_Class} and {@code CONSTANT_MethodType} constants,
......@@ -135,23 +127,23 @@
* <table border=1 cellpadding=5 summary="CONSTANT_MethodHandle subtypes">
* <tr><th>N</th><th>subtag name</th><th>member</th><th>MH type</th><th>bytecode behavior</th><th>lookup expression</th></tr>
* <tr><td>1</td><td>REF_getField</td><td>C.f:T</td><td>(C)T</td><td>getfield C.f:T</td>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#findGetter findGetter(C.class,"f",T.class)}</td></tr>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findGetter findGetter(C.class,"f",T.class)}</td></tr>
* <tr><td>2</td><td>REF_getStatic</td><td>C.f:T</td><td>(&nbsp;)T</td><td>getstatic C.f:T</td>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#findStaticGetter findStaticGetter(C.class,"f",T.class)}</td></tr>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findStaticGetter findStaticGetter(C.class,"f",T.class)}</td></tr>
* <tr><td>3</td><td>REF_putField</td><td>C.f:T</td><td>(C,T)void</td><td>putfield C.f:T</td>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#findSetter findSetter(C.class,"f",T.class)}</td></tr>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findSetter findSetter(C.class,"f",T.class)}</td></tr>
* <tr><td>4</td><td>REF_putStatic</td><td>C.f:T</td><td>(T)void</td><td>putstatic C.f:T</td>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#findStaticSetter findStaticSetter(C.class,"f",T.class)}</td></tr>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findStaticSetter findStaticSetter(C.class,"f",T.class)}</td></tr>
* <tr><td>5</td><td>REF_invokeVirtual</td><td>C.m(A*)T</td><td>(C,A*)T</td><td>invokevirtual C.m(A*)T</td>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#findVirtual findVirtual(C.class,"m",MT)}</td></tr>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findVirtual findVirtual(C.class,"m",MT)}</td></tr>
* <tr><td>6</td><td>REF_invokeStatic</td><td>C.m(A*)T</td><td>(C,A*)T</td><td>invokestatic C.m(A*)T</td>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#findStatic findStatic(C.class,"m",MT)}</td></tr>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findStatic findStatic(C.class,"m",MT)}</td></tr>
* <tr><td>7</td><td>REF_invokeSpecial</td><td>C.m(A*)T</td><td>(C,A*)T</td><td>invokespecial C.m(A*)T</td>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#findSpecial findSpecial(C.class,"m",MT,this.class)}</td></tr>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findSpecial findSpecial(C.class,"m",MT,this.class)}</td></tr>
* <tr><td>8</td><td>REF_newInvokeSpecial</td><td>C.&lt;init&gt;(A*)void</td><td>(A*)C</td><td>new C; dup; invokespecial C.&lt;init&gt;(A*)void</td>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#findConstructor findConstructor(C.class,MT)}</td></tr>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findConstructor findConstructor(C.class,MT)}</td></tr>
* <tr><td>9</td><td>REF_invokeInterface</td><td>C.m(A*)T</td><td>(C,A*)T</td><td>invokeinterface C.m(A*)T</td>
* <td>{@linkplain java.dyn.MethodHandles.Lookup#findVirtual findVirtual(C.class,"m",MT)}</td></tr>
* <td>{@linkplain java.lang.invoke.MethodHandles.Lookup#findVirtual findVirtual(C.class,"m",MT)}</td></tr>
* </table>
* </code>
* Here, the type {@code C} is taken from the {@code CONSTANT_Class} reference associated
......@@ -169,7 +161,7 @@
* and returns the same result (if any) as the corresponding <em>bytecode behavior</em>.
* <p>
* Each method handle constant also has an equivalent reflective <em>lookup expression</em>,
* which is a query to a method in {@link java.dyn.MethodHandles.Lookup}.
* which is a query to a method in {@link java.lang.invoke.MethodHandles.Lookup}.
* In the example lookup method expression given in the table above, the name {@code MT}
* stands for a {@code MethodType} built from {@code T} and the sequence of argument types {@code A*}.
* (Note that the type {@code C} is not prepended to the query type {@code MT} even if the member is non-static.)
......@@ -191,7 +183,7 @@
* A constant may refer to a method or constructor with the {@code varargs}
* bit (hexadecimal {@code 0x0080}) set in its modifier bitmask.
* The method handle constant produced for such a method behaves as if
* it were created by {@link java.dyn.MethodHandle#asVarargsCollector asVarargsCollector}.
* it were created by {@link java.lang.invoke.MethodHandle#asVarargsCollector asVarargsCollector}.
* In other words, the constant method handle will exhibit variable arity,
* when invoked via {@code invokeGeneric}.
* On the other hand, its behavior with respect to {@code invokeExact} will be the same
......@@ -225,7 +217,7 @@
* the call site must first be <em>linked</em>.
* Linking is accomplished by calling a <em>bootstrap method</em>
* which is given the static information content of the call site,
* and which must produce a {@link java.dyn.MethodHandle method handle}
* and which must produce a {@link java.lang.invoke.MethodHandle method handle}
* that gives the behavior of the call site.
* <p>
* Each {@code invokedynamic} instruction statically specifies its own
......@@ -234,7 +226,7 @@
* just like {@code invokevirtual} and the other invoke instructions.
* <p>
* Linking starts with resolving the constant pool entry for the
* bootstrap method, and resolving a {@link java.dyn.MethodType MethodType} object for
* bootstrap method, and resolving a {@link java.lang.invoke.MethodType MethodType} object for
* the type descriptor of the dynamic call site.
* This resolution process may trigger class loading.
* It may therefore throw an error if a class fails to load.
......@@ -251,8 +243,8 @@
* <li>optionally, one or more <a href="#args">additional static arguments</a> </li>
* </ul>
* The method handle is then applied to the other values as if by
* {@link java.dyn.MethodHandle#invokeGeneric invokeGeneric}.
* The returned result must be a {@link java.dyn.CallSite CallSite} (or a subclass).
* {@link java.lang.invoke.MethodHandle#invokeGeneric invokeGeneric}.
* The returned result must be a {@link java.lang.invoke.CallSite CallSite} (or a subclass).
* The type of the call site's target must be exactly equal to the type
* derived from the dynamic call site's type descriptor and passed to
* the bootstrap method.
......@@ -263,18 +255,12 @@
* 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.)
* (Note that the types and number of the stacked arguments limit
* the legal kinds of bootstrap methods to appropriately typed
* static methods and constructors of {@code CallSite} subclasses.)
* <p>
* 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 a {@link java.lang.BootstrapMethodError BootstrapMethodError},
* which is thrown as the abnormal termination of the dynamic call
* site execution.
* The following circumstances will cause this:
......@@ -290,7 +276,7 @@
* <li>the bootstrap method has a wrong argument or return type </li>
* <li>the bootstrap method invocation completes abnormally </li>
* <li>the result from the bootstrap invocation is not a reference to
* an object of type {@link java.dyn.CallSite CallSite} </li>
* an object of type {@link java.lang.invoke.CallSite CallSite} </li>
* <li>the target of the {@code CallSite} does not have a target of
* the expected {@code MethodType} </li>
* </ul>
......@@ -309,7 +295,7 @@
* <p>
* In an application which requires dynamic call sites with individually
* mutable behaviors, their bootstrap methods should produce distinct
* {@link java.dyn.CallSite CallSite} objects, one for each linkage request.
* {@link java.lang.invoke.CallSite CallSite} objects, one for each linkage request.
* Alternatively, an application can link a single {@code CallSite} object
* to several {@code invokedynamic} instructions, in which case
* a change to the target method will become visible at each of
......@@ -322,11 +308,12 @@
* chosen target object.
*
* <p style="font-size:smaller;">
* <em>Historic Note:</em> Unlike some previous versions of this specification,
* these rules do not enable the JVM to duplicate dynamic call sites,
* <em>Discussion:</em>
* These rules do not enable the JVM to duplicate dynamic call sites,
* or to issue &ldquo;causeless&rdquo; bootstrap method calls.
* Every dynamic call site transitions at most once from unlinked to linked,
* just before its first invocation.
* There is no way to undo the effect of a completed bootstrap method call.
*
* <h3><a name="bsmattr">the {@code BootstrapMethods} attribute </h3>
* Each {@code CONSTANT_InvokeDynamic} entry contains an index which references
......@@ -354,7 +341,7 @@
* <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 caller class (expressed as a {@link java.lang.invoke.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
......@@ -382,8 +369,8 @@
* <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>
* <tr><td>CONSTANT_MethodHandle</td><td><code>java.lang.invoke.MethodHandle</code></td><td>the indexed method handle constant</td></tr>
* <tr><td>CONSTANT_MethodType</td><td><code>java.lang.invoke.MethodType</code></td><td>the indexed method type constant</td></tr>
* </table>
* </code>
* <p>
......@@ -403,7 +390,7 @@
* then some or all of the arguments specified here may be collected into a trailing array parameter.
* (This is not a special rule, but rather a useful consequence of the interaction
* between {@code CONSTANT_MethodHandle} constants, the modifier bit for variable arity methods,
* and the {@code java.dyn.MethodHandle#asVarargsCollector asVarargsCollector} transformation.)
* and the {@code java.lang.invoke.MethodHandle#asVarargsCollector asVarargsCollector} transformation.)
* <p>
* Given these rules, here are examples of legal bootstrap method declarations,
* given various numbers {@code N} of extra arguments.
......@@ -436,7 +423,7 @@
* 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,
* resulting in an {@code InvokeDynamicBootstrapError}.)
* resulting in a {@code BootstrapMethodError}.)
* <p>
* Extra bootstrap method arguments are intended to allow language implementors
* to safely and compactly encode metadata.
......@@ -473,6 +460,7 @@ struct BootstrapMethods_attr {
* </pre></blockquote>
*
* @author John Rose, JSR 292 EG
* @since 1.7
*/
package java.dyn;
package java.lang.invoke;
/*
* 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 sun.reflect.Reflection;
/**
* Access control to this package.
* Classes in other packages can attempt to acquire the access token,
* but will fail if they are not recognized as friends.
* Certain methods in this package, although public, require a non-null
* access token in order to proceed; they act like package-private methods.
* @author jrose
*/
public class Access {
private Access() { }
/**
* The heart of this pattern: The list of classes which are
* permitted to acquire the access token, and become honorary
* members of this package.
*/
private static final String[] FRIENDS = {
"java.dyn.", "sun.dyn."
};
/**
* The following object is NOT public. That's the point of the pattern.
* It is package-private, so that any member of this package
* can acquire the access token, and give it away to trusted friends.
*/
static final Access TOKEN = new Access();
/**
* @return Access.TOKEN, if the caller is a friend of this package
*/
public static Access getToken() {
Class<?> callc = Reflection.getCallerClass(2);
if (isFriend(callc))
return TOKEN;
else
throw new IllegalAccessError("bad caller: " + callc);
}
/** Is the given name the name of a class which could be our friend? */
public static boolean isFriendName(String name) {
for (String friend : FRIENDS) {
if (name.startsWith(friend))
return true;
}
return false;
}
/** Is the given class a friend? True if {@link #isFriendName},
* and the given class also shares a class loader with us.
*/
public static boolean isFriend(Class<?> c) {
return isFriendName(c.getName()) && c.getClassLoader() == CLASS_LOADER;
}
private static final ClassLoader CLASS_LOADER = Access.class.getClassLoader();
/**
* Throw an IllegalAccessError if the caller does not possess
* the Access.TOKEN.
* @param must be Access.TOKEN
*/
public static void check(Access token) {
if (token == null)
fail();
// else it must be the unique Access.TOKEN
assert(token == Access.TOKEN);
}
private static void fail() {
final int CALLER_DEPTH = 3;
// 0: Reflection.getCC, 1: this.fail, 2: Access.*, 3: caller
Class<?> callc = Reflection.getCallerClass(CALLER_DEPTH);
throw new IllegalAccessError("bad caller: " + callc);
}
static {
//sun.reflect.Reflection.registerMethodsToFilter(MH.class, "getToken");
}
}
/*
* 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 sun.dyn;
import java.dyn.*;
import static sun.dyn.MemberName.uncaughtException;
/**
* Parts of CallSite known to the JVM.
* @author jrose
*/
public class CallSiteImpl {
// this implements the upcall from the JVM, MethodHandleNatives.makeDynamicCallSite:
static CallSite makeSite(MethodHandle bootstrapMethod,
// Callee information:
String name, MethodType type,
// Extra arguments for BSM, if any:
Object info,
// Caller information:
MemberName callerMethod, int callerBCI) {
Class<?> callerClass = callerMethod.getDeclaringClass();
Object caller;
if (bootstrapMethod.type().parameterType(0) == Class.class && TRANSITIONAL_BEFORE_PFD)
caller = callerClass; // remove for PFD
else
caller = MethodHandleImpl.IMPL_LOOKUP.in(callerClass);
if (bootstrapMethod == null && TRANSITIONAL_BEFORE_PFD) {
// If there is no bootstrap method, throw IncompatibleClassChangeError.
// This is a valid generic error type for resolution (JLS 12.3.3).
throw new IncompatibleClassChangeError
("Class "+callerClass.getName()+" has not declared a bootstrap method for invokedynamic");
}
CallSite site;
try {
Object binding;
info = maybeReBox(info);
if (info == null) {
binding = bootstrapMethod.invokeGeneric(caller, name, type);
} else if (!info.getClass().isArray()) {
binding = bootstrapMethod.invokeGeneric(caller, name, type, info);
} else {
Object[] argv = (Object[]) info;
if (3 + argv.length > 255)
new InvokeDynamicBootstrapError("too many bootstrap method arguments");
MethodType bsmType = bootstrapMethod.type();
if (bsmType.parameterCount() == 4 && bsmType.parameterType(3) == Object[].class)
binding = bootstrapMethod.invokeGeneric(caller, name, type, argv);
else
binding = MethodHandles.spreadInvoker(bsmType, 3)
.invokeGeneric(bootstrapMethod, caller, name, type, argv);
}
//System.out.println("BSM for "+name+type+" => "+binding);
if (binding instanceof CallSite) {
site = (CallSite) binding;
} else if (binding instanceof MethodHandle && TRANSITIONAL_BEFORE_PFD) {
// Transitional!
MethodHandle target = (MethodHandle) binding;
site = new ConstantCallSite(target);
} else {
throw new ClassCastException("bootstrap method failed to produce a CallSite");
}
if (TRANSITIONAL_BEFORE_PFD)
PRIVATE_INITIALIZE_CALL_SITE.invokeExact(site, name, type,
callerMethod, callerBCI);
assert(site.getTarget() != null);
assert(site.getTarget().type().equals(type));
} catch (Throwable ex) {
InvokeDynamicBootstrapError bex;
if (ex instanceof InvokeDynamicBootstrapError)
bex = (InvokeDynamicBootstrapError) ex;
else
bex = new InvokeDynamicBootstrapError("call site initialization exception", ex);
throw bex;
}
return site;
}
private static boolean TRANSITIONAL_BEFORE_PFD = true; // FIXME: remove for PFD
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.
// These private fields (vmmethod, vmindex) are specific to the JVM.
private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE;
static {
try {
PRIVATE_INITIALIZE_CALL_SITE =
!TRANSITIONAL_BEFORE_PFD ? null :
MethodHandleImpl.IMPL_LOOKUP.findVirtual(CallSite.class, "initializeFromJVM",
MethodType.methodType(void.class,
String.class, MethodType.class,
MemberName.class, int.class));
} catch (ReflectiveOperationException ex) {
throw uncaughtException(ex);
}
}
public static void setCallSiteTarget(Access token, CallSite site, MethodHandle target) {
Access.check(token);
MethodHandleNatives.setCallSiteTarget(site, target);
}
}
......@@ -23,14 +23,14 @@
* questions.
*/
package sun.dyn;
package sun.invoke;
import java.dyn.MethodHandle;
import java.lang.invoke.MethodHandle;
/**
* Private API used inside of java.dyn.MethodHandles.
* Private API used inside of java.lang.invoke.MethodHandles.
* Interface implemented by every object which is produced by
* {@link java.dyn.MethodHandles#asInstance MethodHandles.asInstance}.
* {@link java.lang.invoke.MethodHandles#asInstance MethodHandles.asInstance}.
* The methods of this interface allow a caller to recover the parameters
* to {@code asInstance}.
* This allows applications to repeatedly convert between method handles
......
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,7 +23,7 @@
* questions.
*/
package sun.dyn.anon;
package sun.invoke.anon;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
......
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,14 +23,14 @@
* questions.
*/
package sun.dyn.anon;
package sun.invoke.anon;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import static sun.dyn.anon.ConstantPoolVisitor.*;
import static sun.invoke.anon.ConstantPoolVisitor.*;
/** A constant pool parser.
*/
......
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,7 +23,7 @@
* questions.
*/
package sun.dyn.anon;
package sun.invoke.anon;
import java.io.IOException;
import java.io.OutputStream;
......@@ -32,7 +32,7 @@ import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
import static sun.dyn.anon.ConstantPoolVisitor.*;
import static sun.invoke.anon.ConstantPoolVisitor.*;
/** A class and its patched constant pool.
*
......
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,7 +23,7 @@
* questions.
*/
package sun.dyn.anon;
package sun.invoke.anon;
/**
* A visitor called by {@link ConstantPoolParser#parse(ConstantPoolVisitor)}
......
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,7 +23,7 @@
* questions.
*/
package sun.dyn.anon;
package sun.invoke.anon;
/** Exception used when there is an error in the constant pool
* format.
......
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2011, 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
......@@ -23,14 +23,14 @@
* questions.
*/
package sun.dyn.empty;
package sun.invoke.empty;
/**
* An empty class in an empty package.
* Used as a proxy for unprivileged code, since making access checks
* 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
* This class also stands (internally to sun.invoke) 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
......
......@@ -24,8 +24,8 @@
*/
/**
* Implementation details for JSR 292 RI, package java.dyn.
* Implementation details for JSR 292 RI, package java.lang.invoke.
* @author jrose
*/
package sun.dyn;
package sun.invoke;
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,9 +23,9 @@
* questions.
*/
package sun.dyn.util;
package sun.invoke.util;
import java.dyn.MethodType;
import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.List;
......
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2011, 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
......@@ -23,7 +23,7 @@
* questions.
*/
package sun.dyn.util;
package sun.invoke.util;
/**
* Utility routines for dealing with bytecode-level names.
......
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,22 +23,19 @@
* questions.
*/
package sun.dyn.util;
package sun.invoke.util;
import java.dyn.*;
import java.dyn.MethodHandles.Lookup;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.List;
import sun.dyn.Access;
import sun.dyn.AdapterMethodHandle;
import sun.dyn.MethodHandleImpl;
import static sun.dyn.MemberName.uncaughtException;
public class ValueConversions {
private static final Access IMPL_TOKEN = Access.getToken();
private static final Lookup IMPL_LOOKUP = MethodHandleImpl.getLookup(IMPL_TOKEN);
private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) {
@SuppressWarnings("unchecked")
......@@ -157,7 +154,7 @@ public class ValueConversions {
mh = null;
}
} else {
mh = retype(type, unbox(wrap, !exact, raw));
mh = unbox(wrap, !exact, raw).asType(type);
}
if (mh != null) {
cache.put(wrap, mh);
......@@ -293,7 +290,7 @@ public class ValueConversions {
mh = null;
}
} else {
mh = retype(type.erase(), box(wrap, !exact, raw));
mh = box(wrap, !exact, raw).asType(type.erase());
}
if (mh != null) {
cache.put(wrap, mh);
......@@ -412,7 +409,7 @@ public class ValueConversions {
mh = null;
}
} else {
mh = retype(IDENTITY.type(), rebox(wrap, !exact));
mh = rebox(wrap, !exact).asType(IDENTITY.type());
}
if (mh != null) {
cache.put(wrap, mh);
......@@ -504,8 +501,8 @@ public class ValueConversions {
// use the raw method
Wrapper rawWrap = wrap.rawPrimitive();
if (rawWrap != wrap) {
mh = retype(type, zeroConstantFunction(rawWrap));
if (mh == null && rawWrap != wrap) {
mh = MethodHandles.explicitCastArguments(zeroConstantFunction(rawWrap), type);
}
if (mh != null) {
cache.put(wrap, mh);
......@@ -552,6 +549,22 @@ public class ValueConversions {
return x;
}
static byte identity(byte x) {
return x;
}
static short identity(short x) {
return x;
}
static boolean identity(boolean x) {
return x;
}
static char identity(char x) {
return x;
}
/**
* Identity function on longs.
* @param x an arbitrary long value
......@@ -561,6 +574,14 @@ public class ValueConversions {
return x;
}
static float identity(float x) {
return x;
}
static double identity(double x) {
return x;
}
/**
* Identity function, with reference cast.
* @param t an arbitrary reference type
......@@ -590,7 +611,9 @@ public class ValueConversions {
IGNORE = IMPL_LOOKUP.findStatic(ValueConversions.class, "ignore", ignoreType);
EMPTY = IMPL_LOOKUP.findStatic(ValueConversions.class, "empty", ignoreType.dropParameterTypes(0, 1));
} catch (Exception ex) {
throw uncaughtException(ex);
Error err = new InternalError("uncaught exception");
err.initCause(ex);
throw err;
}
}
......@@ -622,7 +645,8 @@ public class ValueConversions {
mh = MethodHandles.insertArguments(CAST_REFERENCE, 0, type);
if (exact) {
MethodType xmt = MethodType.methodType(type, Object.class);
mh = AdapterMethodHandle.makeRetypeRaw(IMPL_TOKEN, xmt, mh);
mh = MethodHandles.explicitCastArguments(mh, xmt);
//mh = AdapterMethodHandle.makeRetypeRaw(IMPL_TOKEN, xmt, mh);
}
if (cache != null)
cache.put(wrap, mh);
......@@ -634,15 +658,11 @@ public class ValueConversions {
}
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));
// This stuff has been moved into MethodHandles:
return MethodHandles.identity(type);
}
static MethodHandle identity(Wrapper wrap) {
public static MethodHandle identity(Wrapper wrap) {
EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[1];
MethodHandle mh = cache.get(wrap);
if (mh != null) {
......@@ -665,12 +685,6 @@ public class ValueConversions {
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;
......@@ -678,10 +692,6 @@ public class ValueConversions {
throw new IllegalArgumentException("cannot find identity for " + wrap);
}
private static MethodHandle retype(MethodType type, MethodHandle mh) {
return AdapterMethodHandle.makeRetypeRaw(IMPL_TOKEN, type, mh);
}
private static final Object[] NO_ARGS_ARRAY = {};
private static Object[] makeArray(Object... args) { return args; }
private static Object[] array() { return NO_ARGS_ARRAY; }
......
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,12 +23,9 @@
* questions.
*/
package sun.dyn.util;
package sun.invoke.util;
import java.lang.reflect.Modifier;
import sun.dyn.MemberName;
import sun.dyn.MethodHandleImpl;
import sun.dyn.empty.Empty;
import static java.lang.reflect.Modifier.*;
/**
......
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,10 +23,10 @@
* questions.
*/
package sun.dyn.util;
package sun.invoke.util;
import java.dyn.MethodType;
import sun.dyn.empty.Empty;
import java.lang.invoke.MethodType;
import sun.invoke.empty.Empty;
/**
* This class centralizes information about the JVM verifier
......
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -23,7 +23,7 @@
* questions.
*/
package sun.dyn.util;
package sun.invoke.util;
public enum Wrapper {
BOOLEAN(Boolean.class, boolean.class, 'Z', (Boolean)false, Format.unsigned(1)),
......@@ -267,7 +267,7 @@ public enum Wrapper {
FROM_WRAP[wi] = w;
FROM_CHAR[ci] = w;
}
//assert(jdk.sun.dyn.util.WrapperTest.test(false));
//assert(jdk.sun.invoke.util.WrapperTest.test(false));
}
/** What is the primitive type wrapped by this wrapper? */
......
/*
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2011, 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
......@@ -24,8 +24,8 @@
*/
/**
* Extra support for using JSR 292 RI, package java.dyn.
* Extra support for using JSR 292 RI, package java.lang.invoke.
* @author jrose
*/
package sun.dyn.util;
package sun.invoke.util;
......@@ -2685,11 +2685,11 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta
switch (type_table[operand]) {
case JVM_CONSTANT_MethodType:
full_info = make_class_info_from_name(context,
"java/dyn/MethodType");
"java/lang/invoke/MethodType");
break;
default: //JVM_CONSTANT_MethodHandle
full_info = make_class_info_from_name(context,
"java/dyn/MethodHandle");
"java/lang/invoke/MethodHandle");
break;
}
break;
......
/*
* Copyright (c) 2010, 2011, 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
* @bug 6987555
* @summary JSR 292 unboxing to a boolean value fails on big-endian SPARC
*
* @run main/othervm -Xint -ea -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic -XX:+UnlockDiagnosticVMOptions -XX:+VerifyMethodHandles Test6987555
*/
import java.lang.invoke.*;
public class Test6987555 {
private static final Class CLASS = Test6987555.class;
private static final String NAME = "foo";
private static final boolean DEBUG = false;
public static void main(String[] args) throws Throwable {
testboolean();
testbyte();
testchar();
testshort();
testint();
}
// boolean
static void testboolean() throws Throwable {
doboolean(false);
doboolean(true);
}
static void doboolean(boolean x) throws Throwable {
if (DEBUG) System.out.println("boolean=" + x);
MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(boolean.class, boolean.class));
MethodHandle mh2 = mh1.asType(MethodType.methodType(boolean.class, Boolean.class));
boolean a = (boolean) mh1.invokeExact(x);
boolean b = (boolean) mh2.invokeExact(Boolean.valueOf(x));
assert a == b : a + " != " + b;
}
// byte
static void testbyte() throws Throwable {
byte[] a = new byte[] {
Byte.MIN_VALUE,
Byte.MIN_VALUE + 1,
-0x0F,
-1,
0,
1,
0x0F,
Byte.MAX_VALUE - 1,
Byte.MAX_VALUE
};
for (int i = 0; i < a.length; i++) {
dobyte(a[i]);
}
}
static void dobyte(byte x) throws Throwable {
if (DEBUG) System.out.println("byte=" + x);
MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(byte.class, byte.class));
MethodHandle mh2 = mh1.asType(MethodType.methodType(byte.class, Byte.class));
byte a = (byte) mh1.invokeExact(x);
byte b = (byte) mh2.invokeExact(Byte.valueOf(x));
assert a == b : a + " != " + b;
}
// char
static void testchar() throws Throwable {
char[] a = new char[] {
Character.MIN_VALUE,
Character.MIN_VALUE + 1,
0x000F,
0x00FF,
0x0FFF,
Character.MAX_VALUE - 1,
Character.MAX_VALUE
};
for (int i = 0; i < a.length; i++) {
dochar(a[i]);
}
}
static void dochar(char x) throws Throwable {
if (DEBUG) System.out.println("char=" + x);
MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(char.class, char.class));
MethodHandle mh2 = mh1.asType(MethodType.methodType(char.class, Character.class));
char a = (char) mh1.invokeExact(x);
char b = (char) mh2.invokeExact(Character.valueOf(x));
assert a == b : a + " != " + b;
}
// short
static void testshort() throws Throwable {
short[] a = new short[] {
Short.MIN_VALUE,
Short.MIN_VALUE + 1,
-0x0FFF,
-0x00FF,
-0x000F,
-1,
0,
1,
0x000F,
0x00FF,
0x0FFF,
Short.MAX_VALUE - 1,
Short.MAX_VALUE
};
for (int i = 0; i < a.length; i++) {
doshort(a[i]);
}
}
static void doshort(short x) throws Throwable {
if (DEBUG) System.out.println("short=" + x);
MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(short.class, short.class));
MethodHandle mh2 = mh1.asType(MethodType.methodType(short.class, Short.class));
short a = (short) mh1.invokeExact(x);
short b = (short) mh2.invokeExact(Short.valueOf(x));
assert a == b : a + " != " + b;
}
// int
static void testint() throws Throwable {
int[] a = new int[] {
Integer.MIN_VALUE,
Integer.MIN_VALUE + 1,
-0x00000FFF,
-0x000000FF,
-0x0000000F,
-1,
0,
1,
0x0000000F,
0x000000FF,
0x00000FFF,
Integer.MAX_VALUE - 1,
Integer.MAX_VALUE
};
for (int i = 0; i < a.length; i++) {
doint(a[i]);
}
}
static void doint(int x) throws Throwable {
if (DEBUG) System.out.println("int=" + x);
MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(int.class, int.class));
MethodHandle mh2 = mh1.asType(MethodType.methodType(int.class, Integer.class));
int a = (int) mh1.invokeExact(x);
int b = (int) mh2.invokeExact(Integer.valueOf(x));
assert a == b : a + " != " + b;
}
public static boolean foo(boolean i) { return i; }
public static byte foo(byte i) { return i; }
public static char foo(char i) { return i; }
public static short foo(short i) { return i; }
public static int foo(int i) { return i; }
}
/*
* Copyright (c) 2010, 2011, 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
* @bug 6991596
* @summary JSR 292 unimplemented adapter_opt_i2i and adapter_opt_l2i on SPARC
*
* @run main/othervm -ea -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic -XX:+UnlockDiagnosticVMOptions -XX:+VerifyMethodHandles Test6991596
*/
import java.lang.invoke.*;
public class Test6991596 {
private static final Class CLASS = Test6991596.class;
private static final String NAME = "foo";
private static final boolean DEBUG = System.getProperty("DEBUG", "false").equals("true");
public static void main(String[] args) throws Throwable {
testboolean();
testbyte();
testchar();
testshort();
testint();
testlong();
}
// Helpers to get various methods.
static MethodHandle getmh1(Class ret, Class arg) throws ReflectiveOperationException {
return MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(ret, arg));
}
static MethodHandle getmh2(MethodHandle mh1, Class ret, Class arg) {
return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg));
}
static MethodHandle getmh3(MethodHandle mh1, Class ret, Class arg) {
return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg));
}
// test adapter_opt_i2i
static void testboolean() throws Throwable {
boolean[] a = new boolean[] {
true,
false
};
for (int i = 0; i < a.length; i++) {
doboolean(a[i]);
}
}
static void doboolean(boolean x) throws Throwable {
if (DEBUG) System.out.println("boolean=" + x);
// boolean
{
MethodHandle mh1 = getmh1( boolean.class, boolean.class);
MethodHandle mh2 = getmh2(mh1, boolean.class, boolean.class);
// TODO add this for all cases when the bugs are fixed.
//MethodHandle mh3 = getmh3(mh1, boolean.class, boolean.class);
boolean a = (boolean) mh1.invokeExact((boolean) x);
boolean b = (boolean) mh2.invokeExact(x);
//boolean c = mh3.<boolean>invokeExact((boolean) x);
check(x, a, b);
//check(x, c, x);
}
// byte
{
MethodHandle mh1 = getmh1( byte.class, byte.class );
MethodHandle mh2 = getmh2(mh1, byte.class, boolean.class);
byte a = (byte) mh1.invokeExact((byte) (x ? 1 : 0));
byte b = (byte) mh2.invokeExact(x);
check(x, a, b);
}
// char
{
MethodHandle mh1 = getmh1( char.class, char.class);
MethodHandle mh2 = getmh2(mh1, char.class, boolean.class);
char a = (char) mh1.invokeExact((char) (x ? 1 : 0));
char b = (char) mh2.invokeExact(x);
check(x, a, b);
}
// short
{
MethodHandle mh1 = getmh1( short.class, short.class);
MethodHandle mh2 = getmh2(mh1, short.class, boolean.class);
short a = (short) mh1.invokeExact((short) (x ? 1 : 0));
short b = (short) mh2.invokeExact(x);
check(x, a, b);
}
}
static void testbyte() throws Throwable {
byte[] a = new byte[] {
Byte.MIN_VALUE,
Byte.MIN_VALUE + 1,
-0x0F,
-1,
0,
1,
0x0F,
Byte.MAX_VALUE - 1,
Byte.MAX_VALUE
};
for (int i = 0; i < a.length; i++) {
dobyte(a[i]);
}
}
static void dobyte(byte x) throws Throwable {
if (DEBUG) System.out.println("byte=" + x);
// boolean
{
MethodHandle mh1 = getmh1( boolean.class, boolean.class);
MethodHandle mh2 = getmh2(mh1, boolean.class, byte.class);
boolean a = (boolean) mh1.invokeExact((x & 1) == 1);
boolean b = (boolean) mh2.invokeExact(x);
check(x, a, b);
}
// byte
{
MethodHandle mh1 = getmh1( byte.class, byte.class);
MethodHandle mh2 = getmh2(mh1, byte.class, byte.class);
byte a = (byte) mh1.invokeExact((byte) x);
byte b = (byte) mh2.invokeExact(x);
check(x, a, b);
}
// char
{
MethodHandle mh1 = getmh1( char.class, char.class);
MethodHandle mh2 = getmh2(mh1, char.class, byte.class);
char a = (char) mh1.invokeExact((char) x);
char b = (char) mh2.invokeExact(x);
check(x, a, b);
}
// short
{
MethodHandle mh1 = getmh1( short.class, short.class);
MethodHandle mh2 = getmh2(mh1, short.class, byte.class);
short a = (short) mh1.invokeExact((short) x);
short b = (short) mh2.invokeExact(x);
check(x, a, b);
}
}
static void testchar() throws Throwable {
char[] a = new char[] {
Character.MIN_VALUE,
Character.MIN_VALUE + 1,
0x000F,
0x00FF,
0x0FFF,
Character.MAX_VALUE - 1,
Character.MAX_VALUE
};
for (int i = 0; i < a.length; i++) {
dochar(a[i]);
}
}
static void dochar(char x) throws Throwable {
if (DEBUG) System.out.println("char=" + x);
// boolean
{
MethodHandle mh1 = getmh1( boolean.class, boolean.class);
MethodHandle mh2 = getmh2(mh1, boolean.class, char.class);
boolean a = (boolean) mh1.invokeExact((x & 1) == 1);
boolean b = (boolean) mh2.invokeExact(x);
check(x, a, b);
}
// byte
{
MethodHandle mh1 = getmh1( byte.class, byte.class);
MethodHandle mh2 = getmh2(mh1, byte.class, char.class);
byte a = (byte) mh1.invokeExact((byte) x);
byte b = (byte) mh2.invokeExact(x);
check(x, a, b);
}
// char
{
MethodHandle mh1 = getmh1( char.class, char.class);
MethodHandle mh2 = getmh2(mh1, char.class, char.class);
char a = (char) mh1.invokeExact((char) x);
char b = (char) mh2.invokeExact(x);
check(x, a, b);
}
// short
{
MethodHandle mh1 = getmh1( short.class, short.class);
MethodHandle mh2 = getmh2(mh1, short.class, char.class);
short a = (short) mh1.invokeExact((short) x);
short b = (short) mh2.invokeExact(x);
check(x, a, b);
}
}
static void testshort() throws Throwable {
short[] a = new short[] {
Short.MIN_VALUE,
Short.MIN_VALUE + 1,
-0x0FFF,
-0x00FF,
-0x000F,
-1,
0,
1,
0x000F,
0x00FF,
0x0FFF,
Short.MAX_VALUE - 1,
Short.MAX_VALUE
};
for (int i = 0; i < a.length; i++) {
doshort(a[i]);
}
}
static void doshort(short x) throws Throwable {
if (DEBUG) System.out.println("short=" + x);
// boolean
{
MethodHandle mh1 = getmh1( boolean.class, boolean.class);
MethodHandle mh2 = getmh2(mh1, boolean.class, short.class);
boolean a = (boolean) mh1.invokeExact((x & 1) == 1);
boolean b = (boolean) mh2.invokeExact(x);
check(x, a, b);
}
// byte
{
MethodHandle mh1 = getmh1( byte.class, byte.class);
MethodHandle mh2 = getmh2(mh1, byte.class, short.class);
byte a = (byte) mh1.invokeExact((byte) x);
byte b = (byte) mh2.invokeExact(x);
check(x, a, b);
}
// char
{
MethodHandle mh1 = getmh1( char.class, char.class);
MethodHandle mh2 = getmh2(mh1, char.class, short.class);
char a = (char) mh1.invokeExact((char) x);
char b = (char) mh2.invokeExact(x);
check(x, a, b);
}
// short
{
MethodHandle mh1 = getmh1( short.class, short.class);
MethodHandle mh2 = getmh2(mh1, short.class, short.class);
short a = (short) mh1.invokeExact((short) x);
short b = (short) mh2.invokeExact(x);
check(x, a, b);
}
}
static void testint() throws Throwable {
int[] a = new int[] {
Integer.MIN_VALUE,
Integer.MIN_VALUE + 1,
-0x0FFFFFFF,
-0x00FFFFFF,
-0x000FFFFF,
-0x0000FFFF,
-0x00000FFF,
-0x000000FF,
-0x0000000F,
-1,
0,
1,
0x0000000F,
0x000000FF,
0x00000FFF,
0x0000FFFF,
0x000FFFFF,
0x00FFFFFF,
0x0FFFFFFF,
Integer.MAX_VALUE - 1,
Integer.MAX_VALUE
};
for (int i = 0; i < a.length; i++) {
doint(a[i]);
}
}
static void doint(int x) throws Throwable {
if (DEBUG) System.out.println("int=" + x);
// boolean
{
MethodHandle mh1 = getmh1( boolean.class, boolean.class);
MethodHandle mh2 = getmh2(mh1, boolean.class, int.class);
boolean a = (boolean) mh1.invokeExact((x & 1) == 1);
boolean b = (boolean) mh2.invokeExact(x);
check(x, a, b);
}
// byte
{
MethodHandle mh1 = getmh1( byte.class, byte.class);
MethodHandle mh2 = getmh2(mh1, byte.class, int.class);
byte a = (byte) mh1.invokeExact((byte) x);
byte b = (byte) mh2.invokeExact(x);
check(x, a, b);
}
// char
{
MethodHandle mh1 = getmh1( char.class, char.class);
MethodHandle mh2 = getmh2(mh1, char.class, int.class);
char a = (char) mh1.invokeExact((char) x);
char b = (char) mh2.invokeExact(x);
check(x, a, b);
}
// short
{
MethodHandle mh1 = getmh1( short.class, short.class);
MethodHandle mh2 = getmh2(mh1, short.class, int.class);
short a = (short) mh1.invokeExact((short) x);
short b = (short) mh2.invokeExact(x);
assert a == b : a + " != " + b;
check(x, a, b);
}
// int
{
MethodHandle mh1 = getmh1( int.class, int.class);
MethodHandle mh2 = getmh2(mh1, int.class, int.class);
int a = (int) mh1.invokeExact((int) x);
int b = (int) mh2.invokeExact(x);
check(x, a, b);
}
}
// test adapter_opt_l2i
static void testlong() throws Throwable {
long[] a = new long[] {
Long.MIN_VALUE,
Long.MIN_VALUE + 1,
-0x000000000FFFFFFFL,
-0x0000000000FFFFFFL,
-0x00000000000FFFFFL,
-0x000000000000FFFFL,
-0x0000000000000FFFL,
-0x00000000000000FFL,
-0x000000000000000FL,
-1L,
0L,
1L,
0x000000000000000FL,
0x00000000000000FFL,
0x0000000000000FFFL,
0x0000000000000FFFL,
0x000000000000FFFFL,
0x00000000000FFFFFL,
0x0000000000FFFFFFL,
0x000000000FFFFFFFL,
Long.MAX_VALUE - 1,
Long.MAX_VALUE
};
for (int i = 0; i < a.length; i++) {
dolong(a[i]);
}
}
static void dolong(long x) throws Throwable {
if (DEBUG) System.out.println("long=" + x);
// boolean
{
MethodHandle mh1 = getmh1( boolean.class, boolean.class);
MethodHandle mh2 = getmh2(mh1, boolean.class, long.class);
boolean a = (boolean) mh1.invokeExact((x & 1L) == 1L);
boolean b = (boolean) mh2.invokeExact(x);
check(x, a, b);
}
// byte
{
MethodHandle mh1 = getmh1( byte.class, byte.class);
MethodHandle mh2 = getmh2(mh1, byte.class, long.class);
byte a = (byte) mh1.invokeExact((byte) x);
byte b = (byte) mh2.invokeExact(x);
check(x, a, b);
}
// char
{
MethodHandle mh1 = getmh1( char.class, char.class);
MethodHandle mh2 = getmh2(mh1, char.class, long.class);
char a = (char) mh1.invokeExact((char) x);
char b = (char) mh2.invokeExact(x);
check(x, a, b);
}
// short
{
MethodHandle mh1 = getmh1( short.class, short.class);
MethodHandle mh2 = getmh2(mh1, short.class, long.class);
short a = (short) mh1.invokeExact((short) x);
short b = (short) mh2.invokeExact(x);
check(x, a, b);
}
// int
{
MethodHandle mh1 = getmh1( int.class, int.class);
MethodHandle mh2 = getmh2(mh1, int.class, long.class);
int a = (int) mh1.invokeExact((int) x);
int b = (int) mh2.invokeExact(x);
check(x, a, b);
}
}
static void check(boolean x, boolean e, boolean a) { p(z2h(x), z2h(e), z2h(a)); assert e == a : z2h(x) + ": " + z2h(e) + " != " + z2h(a); }
static void check(boolean x, byte e, byte a) { p(z2h(x), i2h(e), i2h(a)); assert e == a : z2h(x) + ": " + i2h(e) + " != " + i2h(a); }
static void check(boolean x, int e, int a) { p(z2h(x), i2h(e), i2h(a)); assert e == a : z2h(x) + ": " + i2h(e) + " != " + i2h(a); }
static void check(int x, boolean e, boolean a) { p(i2h(x), z2h(e), z2h(a)); assert e == a : i2h(x) + ": " + z2h(e) + " != " + z2h(a); }
static void check(int x, byte e, byte a) { p(i2h(x), i2h(e), i2h(a)); assert e == a : i2h(x) + ": " + i2h(e) + " != " + i2h(a); }
static void check(int x, int e, int a) { p(i2h(x), i2h(e), i2h(a)); assert e == a : i2h(x) + ": " + i2h(e) + " != " + i2h(a); }
static void check(long x, boolean e, boolean a) { p(l2h(x), z2h(e), z2h(a)); assert e == a : l2h(x) + ": " + z2h(e) + " != " + z2h(a); }
static void check(long x, byte e, byte a) { p(l2h(x), i2h(e), i2h(a)); assert e == a : l2h(x) + ": " + i2h(e) + " != " + i2h(a); }
static void check(long x, int e, int a) { p(l2h(x), i2h(e), i2h(a)); assert e == a : l2h(x) + ": " + i2h(e) + " != " + i2h(a); }
static void p(String x, String e, String a) { if (DEBUG) System.out.println(x + ": expected: " + e + ", actual: " + a); }
static String z2h(boolean x) { return x ? "1" : "0"; }
static String i2h(int x) { return Integer.toHexString(x); }
static String l2h(long x) { return Long.toHexString(x); }
// to int
public static boolean foo(boolean i) { return i; }
public static byte foo(byte i) { return i; }
public static char foo(char i) { return i; }
public static short foo(short i) { return i; }
public static int foo(int i) { return i; }
}
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 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
......@@ -26,21 +26,21 @@
/* @test
* @summary tests for class-specific values
* @compile ClassValueTest.java
* @run junit/othervm test.java.dyn.ClassValueTest
* @run junit/othervm test.java.lang.invoke.ClassValueTest
*/
/*
Manually:
$ $JAVA7X_HOME/bin/javac -d foo -cp $JUNIT4_JAR test/java/dyn/ClassValueTest.java
$ $JAVA7X_HOME/bin/java -cp foo:$JUNIT4_JAR org.junit.runner.JUnitCore test.java.dyn.ClassValueTest
$ $JAVA7X_HOME/bin/javac -d foo -cp $JUNIT4_JAR test/java/lang/invoke/ClassValueTest.java
$ $JAVA7X_HOME/bin/java -cp foo:$JUNIT4_JAR org.junit.runner.JUnitCore test.java.lang.invoke.ClassValueTest
Output: .testAdd => 1000 : Integer
*/
package test.java.dyn;
package test.java.lang.invoke;
import java.util.*;
import java.dyn.*;
import java.lang.invoke.*;
import org.junit.*;
import static org.junit.Assert.*;
......
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2011, 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
......@@ -29,19 +29,19 @@
* indify.Indify
* --verify-specifier-count=3 --transitionalJSR292=false
* --expand-properties --classpath ${test.classes}
* --java test.java.dyn.InvokeDynamicPrintArgs --check-output
* --java test.java.lang.invoke.InvokeDynamicPrintArgs --check-output
*/
package test.java.dyn;
package test.java.lang.invoke;
import org.junit.Test;
import java.util.*;
import java.io.*;
import java.dyn.*;
import static java.dyn.MethodHandles.*;
import static java.dyn.MethodType.*;
import java.lang.invoke.*;
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
public class InvokeDynamicPrintArgs {
public static void main(String... av) throws Throwable {
......@@ -65,7 +65,7 @@ public class InvokeDynamicPrintArgs {
String[] args = new String[]{
"--verify-specifier-count=3", "--transitionalJSR292=false",
"--expand-properties", "--classpath", testClassPath,
"--java", "test.java.dyn.InvokeDynamicPrintArgs", "--check-output"
"--java", "test.java.lang.invoke.InvokeDynamicPrintArgs", "--check-output"
};
System.err.println("Indify: "+Arrays.toString(args));
indify.Indify.main(args);
......@@ -97,11 +97,11 @@ public class InvokeDynamicPrintArgs {
}
private static final String[] EXPECT_OUTPUT = {
"Printing some argument lists, starting with a empty one:",
"[test.java.dyn.InvokeDynamicPrintArgs, nothing, ()void][]",
"[test.java.dyn.InvokeDynamicPrintArgs, bar, (String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar arg, 1]",
"[test.java.dyn.InvokeDynamicPrintArgs, bar2, (String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar2 arg, 222]",
"[test.java.dyn.InvokeDynamicPrintArgs, baz, (String,int,double)void, 1234.5][baz arg, 2, 3.14]",
"[test.java.dyn.InvokeDynamicPrintArgs, foo, (String)void][foo arg]",
"[test.java.lang.invoke.InvokeDynamicPrintArgs, nothing, ()void][]",
"[test.java.lang.invoke.InvokeDynamicPrintArgs, bar, (String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar arg, 1]",
"[test.java.lang.invoke.InvokeDynamicPrintArgs, bar2, (String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar2 arg, 222]",
"[test.java.lang.invoke.InvokeDynamicPrintArgs, baz, (String,int,double)void, 1234.5][baz arg, 2, 3.14]",
"[test.java.lang.invoke.InvokeDynamicPrintArgs, foo, (String)void][foo arg]",
"Done printing argument lists."
};
......
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2011, 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
......@@ -24,16 +24,16 @@
*/
/* @test
* @summary unit tests for java.dyn.MethodHandle.invokeGeneric
* @summary unit tests for java.lang.invoke.MethodHandle.invokeGeneric
* @compile -XDallowTransitionalJSR292=no -target 7 InvokeGenericTest.java
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.InvokeGenericTest
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.lang.invoke.InvokeGenericTest
*/
package test.java.dyn;
package test.java.lang.invoke;
import java.dyn.*;
import static java.dyn.MethodHandles.*;
import static java.dyn.MethodType.*;
import java.lang.invoke.*;
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
import java.lang.reflect.*;
import java.util.*;
import org.junit.*;
......@@ -49,7 +49,7 @@ public class InvokeGenericTest {
// How much output?
static int verbosity = 0;
static {
String vstr = System.getProperty("test.java.dyn.InvokeGenericTest.verbosity");
String vstr = System.getProperty("test.java.lang.invoke.InvokeGenericTest.verbosity");
if (vstr != null) verbosity = Integer.parseInt(vstr);
}
......@@ -216,7 +216,7 @@ public class InvokeGenericTest {
if (wrap != null) {
return wrap;
}
// import sun.dyn.util.Wrapper;
// import sun.invoke.util.Wrapper;
// Wrapper wrap = Wrapper.forBasicType(dst);
// if (wrap == Wrapper.OBJECT && Wrapper.isWrapperType(dst))
// wrap = Wrapper.forWrapperType(dst);
......
......@@ -24,27 +24,27 @@
*/
/* @test
* @summary example code used in javadoc for java.dyn API
* @summary example code used in javadoc for java.lang.invoke API
* @compile -XDallowTransitionalJSR292=no JavaDocExamplesTest.java
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.JavaDocExamplesTest
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.lang.invoke.JavaDocExamplesTest
*/
/*
---- To run outside jtreg:
$ $JAVA7X_HOME/bin/javac -cp $JUNIT4_JAR -d /tmp/Classes \
$DAVINCI/sources/jdk/test/java/dyn/JavaDocExamplesTest.java
$DAVINCI/sources/jdk/test/java/lang/invoke/JavaDocExamplesTest.java
$ $JAVA7X_HOME/bin/java -cp $JUNIT4_JAR:/tmp/Classes \
-XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles \
-Dtest.java.dyn.JavaDocExamplesTest.verbosity=1 \
test.java.dyn.JavaDocExamplesTest
-Dtest.java.lang.invoke.JavaDocExamplesTest.verbosity=1 \
test.java.lang.invoke.JavaDocExamplesTest
----
*/
package test.java.dyn;
package test.java.lang.invoke;
import java.dyn.*;
import static java.dyn.MethodHandles.*;
import static java.dyn.MethodType.*;
import java.lang.invoke.*;
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
import java.lang.reflect.*;
import java.util.*;
......@@ -65,7 +65,7 @@ public class JavaDocExamplesTest {
org.junit.runner.JUnitCore.runClasses(JavaDocExamplesTest.class);
}
// How much output?
static int verbosity = Integer.getInteger("test.java.dyn.JavaDocExamplesTest.verbosity", 0);
static int verbosity = Integer.getInteger("test.java.lang.invoke.JavaDocExamplesTest.verbosity", 0);
{}
static final private Lookup LOOKUP = lookup();
......@@ -108,6 +108,16 @@ assertEquals("xy".hashCode(), (int) HASHCODE_3.invokeExact((Object)"xy"));
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
assertEquals("xy", (String) cat.invokeExact("x", "y"));
MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class);
MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2));
assertEquals(bigType, d0.type());
assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
}}
{{
{} /// JAVADOC
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
assertEquals("xy", (String) cat.invokeExact("x", "y"));
MethodHandle d0 = dropArguments(cat, 0, String.class);
assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
MethodHandle d1 = dropArguments(cat, 1, String.class);
......
......@@ -24,15 +24,15 @@
*/
/* @test
* @summary unit tests for java.dyn.MethodHandles
* @summary unit tests for java.lang.invoke.MethodHandles
* @compile -source 7 -target 7 -XDallowTransitionalJSR292=no MethodHandlesTest.java
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.MethodHandlesTest
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.lang.invoke.MethodHandlesTest
*/
package test.java.dyn;
package test.java.lang.invoke;
import java.dyn.*;
import java.dyn.MethodHandles.Lookup;
import java.lang.invoke.*;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.*;
import java.util.*;
import org.junit.*;
......@@ -48,7 +48,7 @@ public class MethodHandlesTest {
// How much output?
static int verbosity = 0;
static {
String vstr = System.getProperty("test.java.dyn.MethodHandlesTest.verbosity");
String vstr = System.getProperty("test.java.lang.invoke.MethodHandlesTest.verbosity");
if (vstr != null) verbosity = Integer.parseInt(vstr);
}
......@@ -258,7 +258,7 @@ public class MethodHandlesTest {
if (wrap != null) {
return wrap;
}
// import sun.dyn.util.Wrapper;
// import sun.invoke.util.Wrapper;
// Wrapper wrap = Wrapper.forBasicType(dst);
// if (wrap == Wrapper.OBJECT && Wrapper.isWrapperType(dst))
// wrap = Wrapper.forWrapperType(dst);
......@@ -2264,7 +2264,7 @@ public class MethodHandlesTest {
}
}
}
// Local abbreviated copy of sun.dyn.util.ValueConversions
// Local abbreviated copy of sun.invoke.util.ValueConversions
class ValueConversions {
private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
private static final Object[] NO_ARGS_ARRAY = {};
......
......@@ -24,15 +24,14 @@
*/
/* @test
* @summary unit tests for java.dyn.MethodType
* @summary unit tests for java.lang.invoke.MethodType
* @compile MethodTypeTest.java
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.MethodTypeTest
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.lang.invoke.MethodTypeTest
*/
package test.java.dyn;
package test.java.lang.invoke;
import sun.dyn.MemberName;
import java.dyn.MethodType;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.*;
......@@ -163,18 +162,6 @@ public class MethodTypeTest {
assertSame(expResult, result);
}
/**
* Test of make method, of class MethodType.
*/
@Test
public void testMake_Method() {
System.out.println("make (via MemberName.getMethodType)");
MethodType expResult = MethodType.methodType(int.class, String.class);
MemberName name = new MemberName(compareTo);
MethodType result = name.getMethodType();
assertSame(expResult, result);
}
/**
* Test of make method, of class MethodType.
*/
......@@ -476,10 +463,13 @@ public class MethodTypeTest {
@Test
public void testPortableSerialFormat() throws Throwable {
System.out.println("portable serial format");
boolean generateData = false;
//generateData = true; // set this true to generate the following input data:
Object[][] cases = {
{ mt_vv, new byte[] { // ()void
(byte)0xac, (byte)0xed, (byte)0x00, (byte)0x05, (byte)0x73, (byte)0x72, (byte)0x00, (byte)0x13,
(byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x64, (byte)0x79, (byte)0x6e,
(byte)0xac, (byte)0xed, (byte)0x00, (byte)0x05, (byte)0x73, (byte)0x72, (byte)0x00, (byte)0x1b,
(byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e,
(byte)0x67, (byte)0x2e, (byte)0x69, (byte)0x6e, (byte)0x76, (byte)0x6f, (byte)0x6b, (byte)0x65,
(byte)0x2e, (byte)0x4d, (byte)0x65, (byte)0x74, (byte)0x68, (byte)0x6f, (byte)0x64, (byte)0x54,
(byte)0x79, (byte)0x70, (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x01, (byte)0x24, (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70,
......@@ -493,8 +483,9 @@ public class MethodTypeTest {
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x78,
} },
{ mt_OO, new byte[] { // (Object)Object
(byte)0xac, (byte)0xed, (byte)0x00, (byte)0x05, (byte)0x73, (byte)0x72, (byte)0x00, (byte)0x13,
(byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x64, (byte)0x79, (byte)0x6e,
(byte)0xac, (byte)0xed, (byte)0x00, (byte)0x05, (byte)0x73, (byte)0x72, (byte)0x00, (byte)0x1b,
(byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e,
(byte)0x67, (byte)0x2e, (byte)0x69, (byte)0x6e, (byte)0x76, (byte)0x6f, (byte)0x6b, (byte)0x65,
(byte)0x2e, (byte)0x4d, (byte)0x65, (byte)0x74, (byte)0x68, (byte)0x6f, (byte)0x64, (byte)0x54,
(byte)0x79, (byte)0x70, (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x01, (byte)0x24, (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70,
......@@ -509,14 +500,47 @@ public class MethodTypeTest {
(byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01,
(byte)0x71, (byte)0x00, (byte)0x7e, (byte)0x00, (byte)0x03, (byte)0x78,
} },
{ mt_vOiSzA, new byte[] { // (Object,int,String,boolean,Object[])void
(byte)0xac, (byte)0xed, (byte)0x00, (byte)0x05, (byte)0x73, (byte)0x72, (byte)0x00, (byte)0x1b,
(byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e,
(byte)0x67, (byte)0x2e, (byte)0x69, (byte)0x6e, (byte)0x76, (byte)0x6f, (byte)0x6b, (byte)0x65,
(byte)0x2e, (byte)0x4d, (byte)0x65, (byte)0x74, (byte)0x68, (byte)0x6f, (byte)0x64, (byte)0x54,
(byte)0x79, (byte)0x70, (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x01, (byte)0x24, (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70,
(byte)0x76, (byte)0x72, (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x6f, (byte)0x69, (byte)0x64,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70, (byte)0x75, (byte)0x72, (byte)0x00,
(byte)0x12, (byte)0x5b, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e,
(byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2e, (byte)0x43, (byte)0x6c, (byte)0x61,
(byte)0x73, (byte)0x73, (byte)0x3b, (byte)0xab, (byte)0x16, (byte)0xd7, (byte)0xae, (byte)0xcb,
(byte)0xcd, (byte)0x5a, (byte)0x99, (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x05, (byte)0x76, (byte)0x72, (byte)0x00, (byte)0x10,
(byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e,
(byte)0x67, (byte)0x2e, (byte)0x4f, (byte)0x62, (byte)0x6a, (byte)0x65, (byte)0x63, (byte)0x74,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70, (byte)0x76, (byte)0x72, (byte)0x00,
(byte)0x03, (byte)0x69, (byte)0x6e, (byte)0x74, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x78,
(byte)0x70, (byte)0x76, (byte)0x72, (byte)0x00, (byte)0x10, (byte)0x6a, (byte)0x61, (byte)0x76,
(byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2e, (byte)0x53,
(byte)0x74, (byte)0x72, (byte)0x69, (byte)0x6e, (byte)0x67, (byte)0xa0, (byte)0xf0, (byte)0xa4,
(byte)0x38, (byte)0x7a, (byte)0x3b, (byte)0xb3, (byte)0x42, (byte)0x02, (byte)0x00, (byte)0x00,
(byte)0x78, (byte)0x70, (byte)0x76, (byte)0x72, (byte)0x00, (byte)0x07, (byte)0x62, (byte)0x6f,
(byte)0x6f, (byte)0x6c, (byte)0x65, (byte)0x61, (byte)0x6e, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x78, (byte)0x70, (byte)0x76, (byte)0x72, (byte)0x00, (byte)0x13, (byte)0x5b, (byte)0x4c,
(byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e,
(byte)0x67, (byte)0x2e, (byte)0x4f, (byte)0x62, (byte)0x6a, (byte)0x65, (byte)0x63, (byte)0x74,
(byte)0x3b, (byte)0x90, (byte)0xce, (byte)0x58, (byte)0x9f, (byte)0x10, (byte)0x73, (byte)0x29,
(byte)0x6c, (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70, (byte)0x78,
} },
};
boolean generateData = false;
//generateData = true;
for (Object[] c : cases) {
MethodType mt = (MethodType) c[0];
System.out.println("deserialize "+mt);
byte[] wire = (byte[]) c[1];
if (generateData) {
System.out.println("<generateData>");
wire = writeSerial(mt);
final String INDENT = " ";
System.out.print("{ // "+mt);
......@@ -528,6 +552,7 @@ public class MethodTypeTest {
}
System.out.println();
System.out.println(INDENT+"}");
System.out.println("</generateData>");
System.out.flush();
}
Object decode;
......
......@@ -47,9 +47,9 @@ import java.util.regex.*;
* and {@code CONSTANT_MethodType} "ldc" instructions.
* The stereotyped code must create method types by calls to {@code methodType} or
* {@code fromMethodDescriptorString}. The "lookup" argument must be created
* by calls to {@code java.dyn.MethodHandles#lookup MethodHandles.lookup}.
* by calls to {@code java.lang.invoke.MethodHandles#lookup MethodHandles.lookup}.
* The class and string arguments must be constant.
* The following methods of {@code java.dyn.MethodHandle.Lookup Lookup} are
* The following methods of {@code java.lang.invoke.MethodHandle.Lookup Lookup} are
* allowed for method handle creation: {@code findStatic}, {@code findVirtual},
* {@code findConstructor}, {@code findSpecial},
* {@code findGetter}, {@code findSetter},
......@@ -350,10 +350,15 @@ public class Indify {
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
return transformAndLoadClass(findClassInPath(name));
File f = findClassInPath(name);
if (f != null) {
Class<?> c = transformAndLoadClass(f);
if (c != null) return c;
}
} catch (IOException ex) {
throw new ClassNotFoundException("IO error", ex);
}
throw new ClassNotFoundException();
}
private Class<?> transformAndLoadClass(File f) throws ClassNotFoundException, IOException {
if (verbose) System.err.println("Loading class from "+f);
......@@ -592,7 +597,9 @@ public class Indify {
if (s.startsWith("MT_")) return 'T';
else if (s.startsWith("MH_")) return 'H';
else if (s.startsWith("INDY_")) return 'I';
else if (s.startsWith("java/dyn/")) return 'D';
else if (transitionalJSR292 &&
s.startsWith("java/dyn/")) return 'D';
else if (s.startsWith("java/lang/invoke/")) return 'D';
else if (s.startsWith("java/lang/")) return 'J';
return 0;
}
......@@ -605,15 +612,24 @@ public class Indify {
String descr = cf.pool.getString(CONSTANT_Utf8, n2);
String requiredType;
switch (poolMarks[(char)n1]) {
case 'H': requiredType = "()Ljava/dyn/MethodHandle;"; break;
case 'T': requiredType = "()Ljava/dyn/MethodType;"; break;
case 'I': requiredType = "()Ljava/dyn/MethodHandle;"; break;
case 'H': requiredType = "()Ljava/lang/invoke/MethodHandle;"; break;
case 'T': requiredType = "()Ljava/lang/invoke/MethodType;"; break;
case 'I': requiredType = "()Ljava/lang/invoke/MethodHandle;"; break;
default: return 0;
}
if (descr.equals(requiredType)) return mark;
if (matchType(descr, requiredType)) return mark;
return 0;
}
boolean matchType(String descr, String requiredType) {
if (descr.equals(requiredType)) return true;
if (transitionalJSR292) {
String oldType = requiredType.replace("Ljava/lang/invoke/", "Ljava/dyn/");
if (descr.equals(oldType)) return true;
}
return false;
}
private class JVMState {
final List<Object> stack = new ArrayList<>();
int sp() { return stack.size(); }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册