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));
|