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

Merge

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