< prev index next >

jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java

Print this page




   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.invoke;
  27 
  28 import jdk.experimental.value.ValueType;
  29 import jdk.internal.misc.SharedSecrets;
  30 import jdk.internal.module.IllegalAccessLogger;
  31 import jdk.internal.org.objectweb.asm.ClassReader;
  32 import jdk.internal.reflect.CallerSensitive;
  33 import jdk.internal.reflect.Reflection;
  34 import jdk.internal.vm.annotation.ForceInline;
  35 import sun.invoke.util.ValueConversions;
  36 import sun.invoke.util.VerifyAccess;
  37 import sun.invoke.util.Wrapper;
  38 import sun.reflect.misc.ReflectUtil;
  39 import sun.security.util.SecurityConstants;
  40 import valhalla.shady.MinimalValueTypes_1_0;

  41 
  42 import java.lang.invoke.LambdaForm.BasicType;
  43 import java.lang.reflect.Constructor;
  44 import java.lang.reflect.Field;
  45 import java.lang.reflect.Member;
  46 import java.lang.reflect.Method;
  47 import java.lang.reflect.Modifier;
  48 import java.lang.reflect.ReflectPermission;
  49 import java.nio.ByteOrder;
  50 import java.security.AccessController;
  51 import java.security.PrivilegedAction;
  52 import java.security.ProtectionDomain;
  53 import java.util.ArrayList;
  54 import java.util.Arrays;
  55 import java.util.BitSet;
  56 import java.util.Iterator;
  57 import java.util.List;
  58 import java.util.Objects;
  59 import java.util.*;
  60 import java.util.concurrent.ConcurrentHashMap;
  61 import java.util.stream.Collectors;
  62 import java.util.stream.Stream;
  63 
  64 import static java.lang.invoke.MethodHandleImpl.Intrinsic;
  65 import static java.lang.invoke.MethodHandleNatives.Constants.*;
  66 import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
  67 import static java.lang.invoke.MethodType.methodType;
  68 
  69 /**
  70  * This class consists exclusively of static methods that operate on or return
  71  * method handles. They fall into several categories:
  72  * <ul>
  73  * <li>Lookup methods which help create method handles for methods and fields.
  74  * <li>Combinator methods, which combine or transform pre-existing method handles into new ones.
  75  * <li>Other factory methods to create method handles that emulate other common JVM operations or control flow patterns.
  76  * </ul>
  77  *
  78  * @author John Rose, JSR 292 EG
  79  * @since 1.7


1410         /**
1411          * Produces a method handle giving read access to a non-static field.
1412          * The type of the method handle will have a return type of the field's
1413          * value type.
1414          * The method handle's single argument will be the instance containing
1415          * the field.
1416          * Access checking is performed immediately on behalf of the lookup class.
1417          * @param refc the class or interface from which the method is accessed
1418          * @param name the field's name
1419          * @param type the field's type
1420          * @return a method handle which can load values from the field
1421          * @throws NoSuchFieldException if the field does not exist
1422          * @throws IllegalAccessException if access checking fails, or if the field is {@code static}
1423          * @exception SecurityException if a security manager is present and it
1424          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
1425          * @throws NullPointerException if any argument is null
1426          * @see #findVarHandle(Class, String, Class)
1427          */
1428         public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
1429             if (MinimalValueTypes_1_0.isValueType(refc)) {
1430                 return ValueType.forClass(MinimalValueTypes_1_0.getValueCapableClass(refc)).findGetter(this, name, type);
1431             } else {
1432                 MemberName field = resolveOrFail(REF_getField, refc, name, type);
1433                 return getDirectField(REF_getField, refc, field);
1434             }
1435         }
1436 
1437         /**
1438          * Produces a method handle giving write access to a non-static field.
1439          * The type of the method handle will have a void return type.
1440          * The method handle will take two arguments, the instance containing
1441          * the field, and the value to be stored.
1442          * The second argument will be of the field's value type.
1443          * Access checking is performed immediately on behalf of the lookup class.
1444          * @param refc the class or interface from which the method is accessed
1445          * @param name the field's name
1446          * @param type the field's type
1447          * @return a method handle which can store values into the field
1448          * @throws NoSuchFieldException if the field does not exist
1449          * @throws IllegalAccessException if access checking fails, or if the field is {@code static}
1450          * @exception SecurityException if a security manager is present and it


2522             // oops
2523             throw newIllegalArgumentException("bad MethodHandle constant #"+member);
2524         }
2525 
2526         static ConcurrentHashMap<MemberName, DirectMethodHandle> LOOKASIDE_TABLE = new ConcurrentHashMap<>();
2527     }
2528 
2529     /**
2530      * Produces a method handle constructing arrays of a desired type.
2531      * The return type of the method handle will be the array type.
2532      * The type of its sole argument will be {@code int}, which specifies the size of the array.
2533      * @param arrayClass an array type
2534      * @return a method handle which can create arrays of the given type
2535      * @throws NullPointerException if the argument is {@code null}
2536      * @throws IllegalArgumentException if {@code arrayClass} is not an array type
2537      * @see java.lang.reflect.Array#newInstance(Class, int)
2538      * @since 9
2539      */
2540     public static
2541     MethodHandle arrayConstructor(Class<?> arrayClass) throws IllegalArgumentException {
2542         ValueType<?> compValue = valueComponent(arrayClass);
2543         if (compValue != null) {
2544             return compValue.newArray();
2545         } else {
2546             MethodHandle ani = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_Array_newInstance).
2547                     bindTo(arrayClass.getComponentType());
2548             return ani.asType(ani.type().changeReturnType(arrayClass));
2549         }
2550     }
2551 
2552     /**
2553      * Produces a method handle returning the length of an array.
2554      * The type of the method handle will have {@code int} as return type,
2555      * and its sole argument will be the array type.
2556      * @param arrayClass an array type
2557      * @return a method handle which can retrieve the length of an array of the given array type
2558      * @throws NullPointerException if the argument is {@code null}
2559      * @throws IllegalArgumentException if arrayClass is not an array type
2560      * @since 9
2561      */
2562     public static
2563     MethodHandle arrayLength(Class<?> arrayClass) throws IllegalArgumentException {
2564         ValueType<?> compValue = valueComponent(arrayClass);
2565         return (compValue != null) ?
2566                 compValue.arrayLength() :
2567                 MethodHandleImpl.makeArrayElementAccessor(arrayClass, MethodHandleImpl.ArrayAccess.LENGTH);
2568     }
2569 
2570     /**
2571      * Produces a method handle giving read access to elements of an array.
2572      * The type of the method handle will have a return type of the array's
2573      * element type.  Its first argument will be the array type,
2574      * and the second will be {@code int}.
2575      * @param arrayClass an array type
2576      * @return a method handle which can load values from the given array type
2577      * @throws NullPointerException if the argument is null
2578      * @throws  IllegalArgumentException if arrayClass is not an array type
2579      */
2580     public static
2581     MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException {
2582         ValueType<?> compValue = valueComponent(arrayClass);
2583         return (compValue != null) ?
2584                 compValue.arrayGetter() :
2585                 MethodHandleImpl.makeArrayElementAccessor(arrayClass, MethodHandleImpl.ArrayAccess.GET);
2586     }
2587 
2588     /**
2589      * Produces a method handle giving write access to elements of an array.
2590      * The type of the method handle will have a void return type.
2591      * Its last argument will be the array's element type.
2592      * The first and second arguments will be the array type and int.
2593      * @param arrayClass the class of an array
2594      * @return a method handle which can store values into the array type
2595      * @throws NullPointerException if the argument is null
2596      * @throws IllegalArgumentException if arrayClass is not an array type
2597      */
2598     public static
2599     MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException {
2600         ValueType<?> compValue = valueComponent(arrayClass);
2601         return (compValue != null) ?
2602                 compValue.arraySetter() :
2603                 MethodHandleImpl.makeArrayElementAccessor(arrayClass, MethodHandleImpl.ArrayAccess.SET);
2604     }
2605 
2606     @SuppressWarnings("unchecked")
2607     private static <Z> ValueType<Z> valueComponent(Class<Z> arrayClass) {
2608         if (!arrayClass.isArray()) {
2609             throw newIllegalArgumentException("not an array class: " + arrayClass.getName());
2610         }
2611 
2612         Class<?> comp = arrayClass.getComponentType();
2613         if (MinimalValueTypes_1_0.isValueType(comp)) {
2614             return (ValueType<Z>)ValueType.forClass(MinimalValueTypes_1_0.getValueCapableClass(comp));
2615         } else {
2616             return null;
2617         }
2618     }
2619 
2620     /**
2621      * Produces a VarHandle giving access to elements of an array of type
2622      * {@code arrayClass}.  The VarHandle's variable type is the component type
2623      * of {@code arrayClass} and the list of coordinate types is
2624      * {@code (arrayClass, int)}, where the {@code int} coordinate type
2625      * corresponds to an argument that is an index into an array.
2626      * <p>
2627      * Certain access modes of the returned VarHandle are unsupported under
2628      * the following conditions:
2629      * <ul>
2630      * <li>if the component type is anything other than {@code byte},
2631      *     {@code short}, {@code char}, {@code int}, {@code long},
2632      *     {@code float}, or {@code double} then numeric atomic update access
2633      *     modes are unsupported.
2634      * <li>if the field type is anything other than {@code boolean},


3366      * Produces a constant method handle of the requested return type which
3367      * returns the default value for that type every time it is invoked.
3368      * The resulting constant method handle will have no side effects.
3369      * <p>The returned method handle is equivalent to {@code empty(methodType(type))}.
3370      * It is also equivalent to {@code explicitCastArguments(constant(Object.class, null), methodType(type))},
3371      * since {@code explicitCastArguments} converts {@code null} to default values.
3372      * @param type the expected return type of the desired method handle
3373      * @return a constant method handle that takes no arguments
3374      *         and returns the default value of the given type (or void, if the type is void)
3375      * @throws NullPointerException if the argument is null
3376      * @see MethodHandles#constant
3377      * @see MethodHandles#empty
3378      * @see MethodHandles#explicitCastArguments
3379      * @since 9
3380      */
3381     public static MethodHandle zero(Class<?> type) {
3382         Objects.requireNonNull(type);
3383         if (type.isPrimitive()) {
3384             return zero(Wrapper.forPrimitiveType(type), type);
3385         } else if (MinimalValueTypes_1_0.isValueType(type)) {
3386             return ValueType.forClass(MinimalValueTypes_1_0.getValueCapableClass(type)).defaultValueConstant();
3387         } else {
3388             return zero(Wrapper.OBJECT, type);
3389         }
3390     }
3391 
3392     private static MethodHandle identityOrVoid(Class<?> type) {
3393         return type == void.class ? zero(type) : identity(type);
3394     }
3395 
3396     /**
3397      * Produces a method handle of the requested type which ignores any arguments, does nothing,
3398      * and returns a suitable default depending on the return type.
3399      * That is, it returns a zero primitive value, a {@code null}, or {@code void}.
3400      * <p>The returned method handle is equivalent to
3401      * {@code dropArguments(zero(type.returnType()), 0, type.parameterList())}.
3402      *
3403      * @apiNote Given a predicate and target, a useful "if-then" construct can be produced as
3404      * {@code guardWithTest(pred, target, empty(target.type())}.
3405      * @param type the type of the desired method handle
3406      * @return a constant method handle of the given type, which returns a default value of the given return type
3407      * @throws NullPointerException if the argument is null
3408      * @see MethodHandles#zero
3409      * @see MethodHandles#constant
3410      * @since 9
3411      */
3412     public static  MethodHandle empty(MethodType type) {
3413         Objects.requireNonNull(type);
3414         return dropArguments(zero(type.returnType()), 0, type.parameterList());
3415     }
3416 
3417     private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.COUNT];
3418     private static MethodHandle makeIdentity(Class<?> ptype) {
3419         if (!MinimalValueTypes_1_0.isValueType(ptype)) {
3420             MethodType mtype = MethodType.methodType(ptype, ptype);
3421             LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype));
3422             return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY);
3423         } else {
3424             return ValueType.forClass(MinimalValueTypes_1_0.getValueCapableClass(ptype)).identity();
3425         }
3426     }
3427 
3428     private static MethodHandle zero(Wrapper btw, Class<?> rtype) {
3429         int pos = btw.ordinal();
3430         MethodHandle zero = ZERO_MHS[pos];
3431         if (zero == null) {
3432             zero = setCachedMethodHandle(ZERO_MHS, pos, makeZero(btw.primitiveType()));
3433         }
3434         if (zero.type().returnType() == rtype)
3435             return zero;
3436         assert(btw == Wrapper.OBJECT);
3437         return makeZero(rtype);
3438     }
3439     private static final MethodHandle[] ZERO_MHS = new MethodHandle[Wrapper.COUNT];
3440     private static MethodHandle makeZero(Class<?> rtype) {
3441         MethodType mtype = methodType(rtype);
3442         LambdaForm lform = LambdaForm.zeroForm(BasicType.basicType(rtype));
3443         return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.ZERO);
3444     }


3481      * @return a method handle which inserts an additional argument,
3482      *         before calling the original method handle
3483      * @throws NullPointerException if the target or the {@code values} array is null
3484      * @see MethodHandle#bindTo
3485      */
3486     public static
3487     MethodHandle insertArguments(MethodHandle target, int pos, Object... values) {
3488         int insCount = values.length;
3489         Class<?>[] ptypes = insertArgumentsChecks(target, insCount, pos);
3490         if (insCount == 0)  return target;
3491         BoundMethodHandle result = target.rebind();
3492         for (int i = 0; i < insCount; i++) {
3493             Object value = values[i];
3494             Class<?> ptype = ptypes[pos+i];
3495             if (ptype.isPrimitive()) {
3496                 result = insertArgumentPrimitive(result, pos, ptype, value);
3497             } else if (MinimalValueTypes_1_0.isValueType(ptype)) {
3498                 Class<?> vcc = MinimalValueTypes_1_0.getValueCapableClass(ptype);
3499                 Objects.requireNonNull(value); // throw NPE if needed
3500                 value = vcc.cast(value);       // throw CCE if needed
3501                 MethodHandle unbox = ValueType.forClass(vcc).unbox();
3502                 result = result.bindArgumentQ(pos, value, unbox);
3503             } else {
3504                 value = ptype.cast(value);  // throw CCE if needed
3505                 result = result.bindArgumentL(pos, value);
3506             }
3507         }
3508         return result;
3509     }
3510 
3511     private static BoundMethodHandle insertArgumentPrimitive(BoundMethodHandle result, int pos,
3512                                                              Class<?> ptype, Object value) {
3513         Wrapper w = Wrapper.forPrimitiveType(ptype);
3514         // perform unboxing and/or primitive conversion
3515         value = w.convert(value, ptype);
3516         switch (w) {
3517         case INT:     return result.bindArgumentI(pos, (int)value);
3518         case LONG:    return result.bindArgumentJ(pos, (long)value);
3519         case FLOAT:   return result.bindArgumentF(pos, (float)value);
3520         case DOUBLE:  return result.bindArgumentD(pos, (double)value);
3521         default:      return result.bindArgumentI(pos, ValueConversions.widenSubword(value));




   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.invoke;
  27 

  28 import jdk.internal.misc.SharedSecrets;
  29 import jdk.internal.module.IllegalAccessLogger;
  30 import jdk.internal.org.objectweb.asm.ClassReader;
  31 import jdk.internal.reflect.CallerSensitive;
  32 import jdk.internal.reflect.Reflection;
  33 import jdk.internal.vm.annotation.ForceInline;
  34 import sun.invoke.util.ValueConversions;
  35 import sun.invoke.util.VerifyAccess;
  36 import sun.invoke.util.Wrapper;
  37 import sun.reflect.misc.ReflectUtil;
  38 import sun.security.util.SecurityConstants;
  39 import valhalla.shady.MinimalValueTypes_1_0;
  40 import valhalla.shady.ValueTypeHolder;
  41 
  42 import java.lang.invoke.LambdaForm.BasicType;
  43 import java.lang.reflect.Constructor;
  44 import java.lang.reflect.Field;
  45 import java.lang.reflect.Member;
  46 import java.lang.reflect.Method;
  47 import java.lang.reflect.Modifier;
  48 import java.lang.reflect.ReflectPermission;
  49 import java.nio.ByteOrder;
  50 import java.security.AccessController;
  51 import java.security.PrivilegedAction;
  52 import java.security.ProtectionDomain;
  53 import java.util.ArrayList;
  54 import java.util.Arrays;
  55 import java.util.BitSet;
  56 import java.util.Iterator;
  57 import java.util.List;
  58 import java.util.Objects;

  59 import java.util.concurrent.ConcurrentHashMap;
  60 import java.util.stream.Collectors;
  61 import java.util.stream.Stream;
  62 
  63 import static java.lang.invoke.MethodHandleImpl.Intrinsic;
  64 import static java.lang.invoke.MethodHandleNatives.Constants.*;
  65 import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
  66 import static java.lang.invoke.MethodType.methodType;
  67 
  68 /**
  69  * This class consists exclusively of static methods that operate on or return
  70  * method handles. They fall into several categories:
  71  * <ul>
  72  * <li>Lookup methods which help create method handles for methods and fields.
  73  * <li>Combinator methods, which combine or transform pre-existing method handles into new ones.
  74  * <li>Other factory methods to create method handles that emulate other common JVM operations or control flow patterns.
  75  * </ul>
  76  *
  77  * @author John Rose, JSR 292 EG
  78  * @since 1.7


1409         /**
1410          * Produces a method handle giving read access to a non-static field.
1411          * The type of the method handle will have a return type of the field's
1412          * value type.
1413          * The method handle's single argument will be the instance containing
1414          * the field.
1415          * Access checking is performed immediately on behalf of the lookup class.
1416          * @param refc the class or interface from which the method is accessed
1417          * @param name the field's name
1418          * @param type the field's type
1419          * @return a method handle which can load values from the field
1420          * @throws NoSuchFieldException if the field does not exist
1421          * @throws IllegalAccessException if access checking fails, or if the field is {@code static}
1422          * @exception SecurityException if a security manager is present and it
1423          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
1424          * @throws NullPointerException if any argument is null
1425          * @see #findVarHandle(Class, String, Class)
1426          */
1427         public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
1428             if (MinimalValueTypes_1_0.isValueType(refc)) {
1429                 return MinimalValueTypes_1_0.findValueType(refc).findGetter(this, name, type);
1430             } else {
1431                 MemberName field = resolveOrFail(REF_getField, refc, name, type);
1432                 return getDirectField(REF_getField, refc, field);
1433             }
1434         }
1435 
1436         /**
1437          * Produces a method handle giving write access to a non-static field.
1438          * The type of the method handle will have a void return type.
1439          * The method handle will take two arguments, the instance containing
1440          * the field, and the value to be stored.
1441          * The second argument will be of the field's value type.
1442          * Access checking is performed immediately on behalf of the lookup class.
1443          * @param refc the class or interface from which the method is accessed
1444          * @param name the field's name
1445          * @param type the field's type
1446          * @return a method handle which can store values into the field
1447          * @throws NoSuchFieldException if the field does not exist
1448          * @throws IllegalAccessException if access checking fails, or if the field is {@code static}
1449          * @exception SecurityException if a security manager is present and it


2521             // oops
2522             throw newIllegalArgumentException("bad MethodHandle constant #"+member);
2523         }
2524 
2525         static ConcurrentHashMap<MemberName, DirectMethodHandle> LOOKASIDE_TABLE = new ConcurrentHashMap<>();
2526     }
2527 
2528     /**
2529      * Produces a method handle constructing arrays of a desired type.
2530      * The return type of the method handle will be the array type.
2531      * The type of its sole argument will be {@code int}, which specifies the size of the array.
2532      * @param arrayClass an array type
2533      * @return a method handle which can create arrays of the given type
2534      * @throws NullPointerException if the argument is {@code null}
2535      * @throws IllegalArgumentException if {@code arrayClass} is not an array type
2536      * @see java.lang.reflect.Array#newInstance(Class, int)
2537      * @since 9
2538      */
2539     public static
2540     MethodHandle arrayConstructor(Class<?> arrayClass) throws IllegalArgumentException {
2541         ValueTypeHolder<?> compValue = valueComponent(arrayClass);
2542         if (compValue != null) {
2543             return compValue.newArray();
2544         } else {
2545             MethodHandle ani = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_Array_newInstance).
2546                     bindTo(arrayClass.getComponentType());
2547             return ani.asType(ani.type().changeReturnType(arrayClass));
2548         }
2549     }
2550 
2551     /**
2552      * Produces a method handle returning the length of an array.
2553      * The type of the method handle will have {@code int} as return type,
2554      * and its sole argument will be the array type.
2555      * @param arrayClass an array type
2556      * @return a method handle which can retrieve the length of an array of the given array type
2557      * @throws NullPointerException if the argument is {@code null}
2558      * @throws IllegalArgumentException if arrayClass is not an array type
2559      * @since 9
2560      */
2561     public static
2562     MethodHandle arrayLength(Class<?> arrayClass) throws IllegalArgumentException {
2563         ValueTypeHolder<?> compValue = valueComponent(arrayClass);
2564         return (compValue != null) ?
2565                 compValue.arrayLength() :
2566                 MethodHandleImpl.makeArrayElementAccessor(arrayClass, MethodHandleImpl.ArrayAccess.LENGTH);
2567     }
2568 
2569     /**
2570      * Produces a method handle giving read access to elements of an array.
2571      * The type of the method handle will have a return type of the array's
2572      * element type.  Its first argument will be the array type,
2573      * and the second will be {@code int}.
2574      * @param arrayClass an array type
2575      * @return a method handle which can load values from the given array type
2576      * @throws NullPointerException if the argument is null
2577      * @throws  IllegalArgumentException if arrayClass is not an array type
2578      */
2579     public static
2580     MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException {
2581         ValueTypeHolder<?> compValue = valueComponent(arrayClass);
2582         return (compValue != null) ?
2583                 compValue.arrayGetter() :
2584                 MethodHandleImpl.makeArrayElementAccessor(arrayClass, MethodHandleImpl.ArrayAccess.GET);
2585     }
2586 
2587     /**
2588      * Produces a method handle giving write access to elements of an array.
2589      * The type of the method handle will have a void return type.
2590      * Its last argument will be the array's element type.
2591      * The first and second arguments will be the array type and int.
2592      * @param arrayClass the class of an array
2593      * @return a method handle which can store values into the array type
2594      * @throws NullPointerException if the argument is null
2595      * @throws IllegalArgumentException if arrayClass is not an array type
2596      */
2597     public static
2598     MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException {
2599         ValueTypeHolder<?> compValue = valueComponent(arrayClass);
2600         return (compValue != null) ?
2601                 compValue.arraySetter() :
2602                 MethodHandleImpl.makeArrayElementAccessor(arrayClass, MethodHandleImpl.ArrayAccess.SET);
2603     }
2604 
2605     @SuppressWarnings("unchecked")
2606     private static <Z> ValueTypeHolder<Z> valueComponent(Class<Z> arrayClass) {
2607         if (!arrayClass.isArray()) {
2608             throw newIllegalArgumentException("not an array class: " + arrayClass.getName());
2609         }
2610 
2611         Class<?> comp = arrayClass.getComponentType();
2612         if (MinimalValueTypes_1_0.isValueType(comp)) {
2613             return (ValueTypeHolder<Z>) MinimalValueTypes_1_0.findValueType(comp);
2614         } else {
2615             return null;
2616         }
2617     }
2618 
2619     /**
2620      * Produces a VarHandle giving access to elements of an array of type
2621      * {@code arrayClass}.  The VarHandle's variable type is the component type
2622      * of {@code arrayClass} and the list of coordinate types is
2623      * {@code (arrayClass, int)}, where the {@code int} coordinate type
2624      * corresponds to an argument that is an index into an array.
2625      * <p>
2626      * Certain access modes of the returned VarHandle are unsupported under
2627      * the following conditions:
2628      * <ul>
2629      * <li>if the component type is anything other than {@code byte},
2630      *     {@code short}, {@code char}, {@code int}, {@code long},
2631      *     {@code float}, or {@code double} then numeric atomic update access
2632      *     modes are unsupported.
2633      * <li>if the field type is anything other than {@code boolean},


3365      * Produces a constant method handle of the requested return type which
3366      * returns the default value for that type every time it is invoked.
3367      * The resulting constant method handle will have no side effects.
3368      * <p>The returned method handle is equivalent to {@code empty(methodType(type))}.
3369      * It is also equivalent to {@code explicitCastArguments(constant(Object.class, null), methodType(type))},
3370      * since {@code explicitCastArguments} converts {@code null} to default values.
3371      * @param type the expected return type of the desired method handle
3372      * @return a constant method handle that takes no arguments
3373      *         and returns the default value of the given type (or void, if the type is void)
3374      * @throws NullPointerException if the argument is null
3375      * @see MethodHandles#constant
3376      * @see MethodHandles#empty
3377      * @see MethodHandles#explicitCastArguments
3378      * @since 9
3379      */
3380     public static MethodHandle zero(Class<?> type) {
3381         Objects.requireNonNull(type);
3382         if (type.isPrimitive()) {
3383             return zero(Wrapper.forPrimitiveType(type), type);
3384         } else if (MinimalValueTypes_1_0.isValueType(type)) {
3385             return MinimalValueTypes_1_0.findValueType(type).defaultValueConstant();
3386         } else {
3387             return zero(Wrapper.OBJECT, type);
3388         }
3389     }
3390 
3391     private static MethodHandle identityOrVoid(Class<?> type) {
3392         return type == void.class ? zero(type) : identity(type);
3393     }
3394 
3395     /**
3396      * Produces a method handle of the requested type which ignores any arguments, does nothing,
3397      * and returns a suitable default depending on the return type.
3398      * That is, it returns a zero primitive value, a {@code null}, or {@code void}.
3399      * <p>The returned method handle is equivalent to
3400      * {@code dropArguments(zero(type.returnType()), 0, type.parameterList())}.
3401      *
3402      * @apiNote Given a predicate and target, a useful "if-then" construct can be produced as
3403      * {@code guardWithTest(pred, target, empty(target.type())}.
3404      * @param type the type of the desired method handle
3405      * @return a constant method handle of the given type, which returns a default value of the given return type
3406      * @throws NullPointerException if the argument is null
3407      * @see MethodHandles#zero
3408      * @see MethodHandles#constant
3409      * @since 9
3410      */
3411     public static  MethodHandle empty(MethodType type) {
3412         Objects.requireNonNull(type);
3413         return dropArguments(zero(type.returnType()), 0, type.parameterList());
3414     }
3415 
3416     private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.COUNT];
3417     private static MethodHandle makeIdentity(Class<?> ptype) {
3418         if (!MinimalValueTypes_1_0.isValueType(ptype)) {
3419             MethodType mtype = MethodType.methodType(ptype, ptype);
3420             LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype));
3421             return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY);
3422         } else {
3423             return MinimalValueTypes_1_0.findValueType(ptype).identity();
3424         }
3425     }
3426 
3427     private static MethodHandle zero(Wrapper btw, Class<?> rtype) {
3428         int pos = btw.ordinal();
3429         MethodHandle zero = ZERO_MHS[pos];
3430         if (zero == null) {
3431             zero = setCachedMethodHandle(ZERO_MHS, pos, makeZero(btw.primitiveType()));
3432         }
3433         if (zero.type().returnType() == rtype)
3434             return zero;
3435         assert(btw == Wrapper.OBJECT);
3436         return makeZero(rtype);
3437     }
3438     private static final MethodHandle[] ZERO_MHS = new MethodHandle[Wrapper.COUNT];
3439     private static MethodHandle makeZero(Class<?> rtype) {
3440         MethodType mtype = methodType(rtype);
3441         LambdaForm lform = LambdaForm.zeroForm(BasicType.basicType(rtype));
3442         return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.ZERO);
3443     }


3480      * @return a method handle which inserts an additional argument,
3481      *         before calling the original method handle
3482      * @throws NullPointerException if the target or the {@code values} array is null
3483      * @see MethodHandle#bindTo
3484      */
3485     public static
3486     MethodHandle insertArguments(MethodHandle target, int pos, Object... values) {
3487         int insCount = values.length;
3488         Class<?>[] ptypes = insertArgumentsChecks(target, insCount, pos);
3489         if (insCount == 0)  return target;
3490         BoundMethodHandle result = target.rebind();
3491         for (int i = 0; i < insCount; i++) {
3492             Object value = values[i];
3493             Class<?> ptype = ptypes[pos+i];
3494             if (ptype.isPrimitive()) {
3495                 result = insertArgumentPrimitive(result, pos, ptype, value);
3496             } else if (MinimalValueTypes_1_0.isValueType(ptype)) {
3497                 Class<?> vcc = MinimalValueTypes_1_0.getValueCapableClass(ptype);
3498                 Objects.requireNonNull(value); // throw NPE if needed
3499                 value = vcc.cast(value);       // throw CCE if needed
3500                 MethodHandle unbox = MinimalValueTypes_1_0.findValueType(ptype).unbox();
3501                 result = result.bindArgumentQ(pos, value, unbox);
3502             } else {
3503                 value = ptype.cast(value);  // throw CCE if needed
3504                 result = result.bindArgumentL(pos, value);
3505             }
3506         }
3507         return result;
3508     }
3509 
3510     private static BoundMethodHandle insertArgumentPrimitive(BoundMethodHandle result, int pos,
3511                                                              Class<?> ptype, Object value) {
3512         Wrapper w = Wrapper.forPrimitiveType(ptype);
3513         // perform unboxing and/or primitive conversion
3514         value = w.convert(value, ptype);
3515         switch (w) {
3516         case INT:     return result.bindArgumentI(pos, (int)value);
3517         case LONG:    return result.bindArgumentJ(pos, (long)value);
3518         case FLOAT:   return result.bindArgumentF(pos, (float)value);
3519         case DOUBLE:  return result.bindArgumentD(pos, (double)value);
3520         default:      return result.bindArgumentI(pos, ValueConversions.widenSubword(value));


< prev index next >