/* * Copyright (c) 2023, 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.runtime; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import jdk.internal.misc.Unsafe; import jdk.internal.util.ReferencedKeyMap; import static java.lang.invoke.MethodType.methodType; /** * A carrier is an opaque object that can be used to store component values * while avoiding primitive boxing associated with collection objects. Component values * can be primitive or Object. *

* Clients can create new carrier instances by describing a carrier shape, that * is, a {@linkplain MethodType method type} whose parameter types describe the types of * the carrier component values, or by providing the parameter types directly. * * {@snippet : * // Create a carrier for a string and an integer * CarrierElements elements = CarrierFactory.of(String.class, int.class); * // Fetch the carrier constructor MethodHandle * MethodHandle initializingConstructor = elements.initializingConstructor(); * // Fetch the list of carrier component MethodHandles * List components = elements.components(); * * // Create an instance of the carrier with a string and an integer * Object carrier = initializingConstructor.invokeExact("abc", 10); * // Extract the first component, type string * String string = (String)components.get(0).invokeExact(carrier); * // Extract the second component, type int * int i = (int)components.get(1).invokeExact(carrier); * } * * Alternatively, the client can use static methods when the carrier use is scattered. * This is possible since {@link Carriers} ensures that the same underlying carrier * class is used when the same component types are provided. * * {@snippet : * // Describe carrier using a MethodType * MethodType mt = MethodType.methodType(Object.class, String.class, int.class); * // Fetch the carrier constructor MethodHandle * MethodHandle constructor = Carriers.constructor(mt); * // Fetch the list of carrier component MethodHandles * List components = Carriers.components(mt); * } * * @implNote The strategy for storing components is deliberately left unspecified * so that future improvements will not be hampered by issues of backward compatibility. * * @since 21 * * Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES. * Do not rely on its availability. */ final class Carriers { /** * Maximum number of components in a carrier (based on the maximum * number of args to a constructor.) */ public static final int MAX_COMPONENTS = 255 - /* this */ 1; /** * Number of integer slots used by a long. */ static final int LONG_SLOTS = Long.SIZE / Integer.SIZE; /* * Initialize {@link MethodHandle} constants. */ static { try { Lookup lookup = MethodHandles.lookup(); FLOAT_TO_INT = lookup.findStatic(Float.class, "floatToRawIntBits", methodType(int.class, float.class)); INT_TO_FLOAT = lookup.findStatic(Float.class, "intBitsToFloat", methodType(float.class, int.class)); DOUBLE_TO_LONG = lookup.findStatic(Double.class, "doubleToRawLongBits", methodType(long.class, double.class)); LONG_TO_DOUBLE = lookup.findStatic(Double.class, "longBitsToDouble", methodType(double.class, long.class)); } catch (ReflectiveOperationException ex) { throw new AssertionError("carrier static init fail", ex); } } /* * float/double conversions. */ private static final MethodHandle FLOAT_TO_INT; private static final MethodHandle INT_TO_FLOAT; private static final MethodHandle DOUBLE_TO_LONG; private static final MethodHandle LONG_TO_DOUBLE; /** * Given an initializer {@link MethodHandle} recast and reorder arguments to * match shape. * * @param carrierShape carrier shape * @param initializer carrier constructor to reshape * * @return constructor with arguments recasted and reordered */ static MethodHandle reshapeInitializer(CarrierShape carrierShape, MethodHandle initializer) { int count = carrierShape.count(); Class[] ptypes = carrierShape.ptypes(); int objectIndex = carrierShape.objectOffset() + 1; int intIndex = carrierShape.intOffset() + 1; int longIndex = carrierShape.longOffset() + 1; int[] reorder = new int[count + 1]; Class[] permutePTypes = new Class[count + 1]; MethodHandle[] filters = new MethodHandle[count + 1]; boolean hasFilters = false; permutePTypes[0] = CarrierObject.class; reorder[0] = 0; int index = 1; for (Class ptype : ptypes) { MethodHandle filter = null; int from; if (!ptype.isPrimitive()) { from = objectIndex++; ptype = Object.class; } else if (ptype == double.class) { from = longIndex++; filter = DOUBLE_TO_LONG; } else if (ptype == float.class) { from = intIndex++; filter = FLOAT_TO_INT; } else if (ptype == long.class) { from = longIndex++; } else { from = intIndex++; ptype = int.class; } permutePTypes[index] = ptype; reorder[from] = index++; if (filter != null) { filters[from] = filter; hasFilters = true; } } if (hasFilters) { initializer = MethodHandles.filterArguments(initializer, 0, filters); } MethodType permutedMethodType = methodType(initializer.type().returnType(), permutePTypes); initializer = MethodHandles.permuteArguments(initializer, permutedMethodType, reorder); initializer = MethodHandles.explicitCastArguments(initializer, methodType(CarrierObject.class, ptypes).insertParameterTypes(0, CarrierObject.class)); return initializer; } /** * Given components array, recast and reorder components to match shape. * * @param carrierShape carrier reshape * @param components carrier components to reshape * * @return list of components reshaped */ static List reshapeComponents(CarrierShape carrierShape, MethodHandle[] components) { int count = carrierShape.count(); Class[] ptypes = carrierShape.ptypes(); MethodHandle[] reorder = new MethodHandle[count]; int objectIndex = carrierShape.objectOffset(); int intIndex = carrierShape.intOffset(); int longIndex = carrierShape.longOffset(); int index = 0; for (Class ptype : ptypes) { MethodHandle component; if (!ptype.isPrimitive()) { component = components[objectIndex++]; } else if (ptype == double.class) { component = MethodHandles.filterReturnValue( components[longIndex++], LONG_TO_DOUBLE); } else if (ptype == float.class) { component = MethodHandles.filterReturnValue( components[intIndex++], INT_TO_FLOAT); } else if (ptype == long.class) { component = components[longIndex++]; } else { component = components[intIndex++]; } MethodType methodType = methodType(ptype, CarrierObject.class); reorder[index++] = MethodHandles.explicitCastArguments(component, methodType); } return List.of(reorder); } /** * Factory for carriers that are backed by long[] and Object[]. */ static final class CarrierObjectFactory { /** * Unsafe access. */ private static final Unsafe UNSAFE; /* * Constructor accessor MethodHandles. */ private static final MethodHandle CONSTRUCTOR; private static final MethodHandle GET_LONG; private static final MethodHandle PUT_LONG; private static final MethodHandle GET_INTEGER; private static final MethodHandle PUT_INTEGER; private static final MethodHandle GET_OBJECT; private static final MethodHandle PUT_OBJECT; static { try { UNSAFE = Unsafe.getUnsafe(); Lookup lookup = MethodHandles.lookup(); CONSTRUCTOR = lookup.findConstructor(CarrierObject.class, methodType(void.class, int.class, int.class)); GET_LONG = lookup.findVirtual(CarrierObject.class, "getLong", methodType(long.class, int.class)); PUT_LONG = lookup.findVirtual(CarrierObject.class, "putLong", methodType(CarrierObject.class, int.class, long.class)); GET_INTEGER = lookup.findVirtual(CarrierObject.class, "getInteger", methodType(int.class, int.class)); PUT_INTEGER = lookup.findVirtual(CarrierObject.class, "putInteger", methodType(CarrierObject.class, int.class, int.class)); GET_OBJECT = lookup.findVirtual(CarrierObject.class, "getObject", methodType(Object.class, int.class)); PUT_OBJECT = lookup.findVirtual(CarrierObject.class, "putObject", methodType(CarrierObject.class, int.class, Object.class)); } catch (ReflectiveOperationException ex) { throw new AssertionError("carrier static init fail", ex); } } /** * Constructor builder. * * @param carrierShape carrier object shape * * @return {@link MethodHandle} to generic carrier constructor. */ MethodHandle constructor(CarrierShape carrierShape) { int objectCount = carrierShape.objectCount(); int primitiveCount = carrierShape.primitiveCount(); MethodHandle constructor = MethodHandles.insertArguments(CONSTRUCTOR, 0, primitiveCount, objectCount); return constructor; } /** * Adds constructor arguments for each of the allocated slots. * * @param carrierShape carrier object shape * * @return {@link MethodHandle} to specific carrier constructor. */ MethodHandle initializer(CarrierShape carrierShape) { int longCount = carrierShape.longCount(); int intCount = carrierShape.intCount(); int objectCount = carrierShape.objectCount(); MethodHandle initializer = MethodHandles.identity(CarrierObject.class); // long array index int index = 0; for (int i = 0; i < longCount; i++) { MethodHandle put = MethodHandles.insertArguments(PUT_LONG, 1, index++); initializer = MethodHandles.collectArguments(put, 0, initializer); } // transition to int array index (double number of longs) index *= LONG_SLOTS; for (int i = 0; i < intCount; i++) { MethodHandle put = MethodHandles.insertArguments(PUT_INTEGER, 1, index++); initializer = MethodHandles.collectArguments(put, 0, initializer); } for (int i = 0; i < objectCount; i++) { MethodHandle put = MethodHandles.insertArguments(PUT_OBJECT, 1, i); initializer = MethodHandles.collectArguments(put, 0, initializer); } return initializer; } /** * Utility to construct the basic accessors from the components. * * @param carrierShape carrier object shape * * @return array of carrier accessors */ MethodHandle[] createComponents(CarrierShape carrierShape) { int longCount = carrierShape.longCount(); int intCount = carrierShape.intCount(); int objectCount = carrierShape.objectCount(); MethodHandle[] components = new MethodHandle[carrierShape.ptypes().length]; // long array index int index = 0; // component index int comIndex = 0; for (int i = 0; i < longCount; i++) { components[comIndex++] = MethodHandles.insertArguments(GET_LONG, 1, index++); } // transition to int array index (double number of longs) index *= LONG_SLOTS; for (int i = 0; i < intCount; i++) { components[comIndex++] = MethodHandles.insertArguments(GET_INTEGER, 1, index++); } for (int i = 0; i < objectCount; i++) { components[comIndex++] = MethodHandles.insertArguments(GET_OBJECT, 1, i); } return components; } /** * Cache mapping {@link MethodType} to previously defined {@link CarrierElements}. */ private static final Map methodTypeCache = ReferencedKeyMap.create(false, ConcurrentHashMap::new); /** * Permute a raw constructor and component accessor {@link MethodHandle MethodHandles} to * match the order and types of the parameter types. * * @param carrierShape carrier object shape * * @return {@link CarrierElements} instance */ CarrierElements carrier(CarrierShape carrierShape) { return methodTypeCache.computeIfAbsent(carrierShape.methodType, (mt) -> { MethodHandle constructor = constructor(carrierShape); MethodHandle initializer = initializer(carrierShape); MethodHandle[] components = createComponents(carrierShape); return new CarrierElements( carrierShape, CarrierObject.class, constructor, reshapeInitializer(carrierShape, initializer), reshapeComponents(carrierShape, components)); }); } } /** * Wrapper object for carrier data. Instance types are stored in the {@code objects} * array, while primitive types are recast to {@code int/long} and stored in the * {@code primitives} array. Primitive byte, short, char, boolean and int are stored as * integers. Longs and doubles are stored as longs. Longs take up the first part of the * primitives array using normal indices. Integers follow using int[] indices offset beyond * the longs using unsafe getInt/putInt. */ static class CarrierObject { /** * Carrier for primitive values. */ private final long[] primitives; /** * Carrier for objects; */ private final Object[] objects; /** * Constructor. * * @param primitiveCount slot count required for primitives * @param objectCount slot count required for objects */ protected CarrierObject(int primitiveCount, int objectCount) { this.primitives = createPrimitivesArray(primitiveCount); this.objects = createObjectsArray(objectCount); } /** * Create a primitives array of an appropriate length. * * @param primitiveCount slot count required for primitives * * @return primitives array of an appropriate length. */ private long[] createPrimitivesArray(int primitiveCount) { return primitiveCount != 0 ? new long[(primitiveCount + 1) / LONG_SLOTS] : null; } /** * Create a objects array of an appropriate length. * * @param objectCount slot count required for objects * * @return objects array of an appropriate length. */ private Object[] createObjectsArray(int objectCount) { return objectCount != 0 ? new Object[objectCount] : null; } /** * Compute offset for unsafe access to long. * * @param i index in primitive[] * * @return offset for unsafe access */ private static long offsetToLong(int i) { return Unsafe.ARRAY_LONG_BASE_OFFSET + (long)i * Unsafe.ARRAY_LONG_INDEX_SCALE; } /** * Compute offset for unsafe access to int. * * @param i index in primitive[] * * @return offset for unsafe access */ private static long offsetToInt(int i) { return Unsafe.ARRAY_LONG_BASE_OFFSET + (long)i * Unsafe.ARRAY_INT_INDEX_SCALE; } /** * Compute offset for unsafe access to object. * * @param i index in objects[] * * @return offset for unsafe access */ private static long offsetToObject(int i) { return Unsafe.ARRAY_OBJECT_BASE_OFFSET + (long)i * Unsafe.ARRAY_OBJECT_INDEX_SCALE; } /** * {@return long value at index} * * @param i array index */ private long getLong(int i) { return CarrierObjectFactory.UNSAFE.getLong(primitives, offsetToLong(i)); } /** * Put a long value into the primitive[]. * * @param i array index * @param value long value to store * * @return this object */ private CarrierObject putLong(int i, long value) { CarrierObjectFactory.UNSAFE.putLong(primitives, offsetToLong(i), value); return this; } /** * {@return int value at index} * * @param i array index */ private int getInteger(int i) { return CarrierObjectFactory.UNSAFE.getInt(primitives, offsetToInt(i)); } /** * Put a int value into the int[]. * * @param i array index * @param value int value to store * * @return this object */ private CarrierObject putInteger(int i, int value) { CarrierObjectFactory.UNSAFE.putInt(primitives, offsetToInt(i), value); return this; } /** * {@return Object value at index} * * @param i array index */ private Object getObject(int i) { return CarrierObjectFactory.UNSAFE.getReference(objects, offsetToObject(i)); } /** * Put a object value into the objects[]. * * @param i array index * @param value object value to store * * @return this object */ private CarrierObject putObject(int i, Object value) { CarrierObjectFactory.UNSAFE.putReference(objects, offsetToObject(i), value); return this; } } /** * Class used to tally and track the number of ints, longs and objects. * * @param longCount number of longs and doubles * @param intCount number of byte, short, int, chars and booleans * @param objectCount number of objects */ private record CarrierCounts(int longCount, int intCount, int objectCount) { /** * Count the number of fields required in each of Object, int and long. * * @param ptypes parameter types * * @return a {@link CarrierCounts} instance containing counts */ static CarrierCounts tally(Class[] ptypes) { return tally(ptypes, ptypes.length); } /** * Count the number of fields required in each of Object, int and long * limited to the first {@code n} parameters. * * @param ptypes parameter types * @param n number of parameters to check * * @return a {@link CarrierCounts} instance containing counts */ private static CarrierCounts tally(Class[] ptypes, int n) { int longCount = 0; int intCount = 0; int objectCount = 0; for (int i = 0; i < n; i++) { Class ptype = ptypes[i]; if (!ptype.isPrimitive()) { objectCount++; } else if (ptype == long.class || ptype == double.class) { longCount++; } else { intCount++; } } return new CarrierCounts(longCount, intCount, objectCount); } /** * {@return total number of components} */ private int count() { return longCount + intCount + objectCount; } /** * {@return total number of slots} */ private int slotCount() { return longCount * LONG_SLOTS + intCount + objectCount; } } /** * Constructor */ private Carriers() { throw new AssertionError("private constructor"); } /** * Shape of carrier based on counts of each of the three fundamental data * types. */ private static class CarrierShape { /** * {@link MethodType} providing types for the carrier's components. */ final MethodType methodType; /** * Counts of different parameter types. */ final CarrierCounts counts; /** * Constructor. * * @param methodType {@link MethodType} providing types for the * carrier's components */ public CarrierShape(MethodType methodType) { this.methodType = methodType; this.counts = CarrierCounts.tally(methodType.parameterArray()); } /** * {@return number of long fields needed} */ int longCount() { return counts.longCount(); } /** * {@return number of int fields needed} */ int intCount() { return counts.intCount(); } /** * {@return number of object fields needed} */ int objectCount() { return counts.objectCount(); } /** * {@return slot count required for primitives} */ int primitiveCount() { return counts.longCount() * LONG_SLOTS + counts.intCount(); } /** * {@return array of parameter types} */ Class[] ptypes() { return methodType.parameterArray(); } /** * {@return number of components} */ int count() { return counts.count(); } /** * {@return number of slots used} */ int slotCount() { return counts.slotCount(); } /** * {@return index of first long component} */ int longOffset() { return 0; } /** * {@return index of first int component} */ int intOffset() { return longCount(); } /** * {@return index of first object component} */ int objectOffset() { return longCount() + intCount(); } } /** * This factory class generates {@link CarrierElements} instances containing the * {@link MethodHandle MethodHandles} to the constructor and accessors of a carrier * object. *

* Clients can create instances by describing a carrier shape, that * is, a {@linkplain MethodType method type} whose parameter types describe the types of * the carrier component values, or by providing the parameter types directly. */ static final class CarrierFactory { /** * Constructor */ private CarrierFactory() { throw new AssertionError("private constructor"); } private static final CarrierObjectFactory FACTORY = new CarrierObjectFactory(); /** * Factory method to return a {@link CarrierElements} instance that matches the shape of * the supplied {@link MethodType}. The return type of the {@link MethodType} is ignored. * * @param methodType {@link MethodType} whose parameter types supply the * the shape of the carrier's components * * @return {@link CarrierElements} instance * * @throws NullPointerException is methodType is null * @throws IllegalArgumentException if number of component slots exceeds maximum */ static CarrierElements of(MethodType methodType) { Objects.requireNonNull(methodType, "methodType must not be null"); MethodType constructorMT = methodType.changeReturnType(Object.class); CarrierShape carrierShape = new CarrierShape(constructorMT); int slotCount = carrierShape.slotCount(); if (MAX_COMPONENTS < slotCount) { throw new IllegalArgumentException("Exceeds maximum number of component slots"); } return FACTORY.carrier(carrierShape); } /** * Factory method to return a {@link CarrierElements} instance that matches the shape of * the supplied parameter types. * * @param ptypes parameter types that supply the shape of the carrier's components * * @return {@link CarrierElements} instance * * @throws NullPointerException is ptypes is null * @throws IllegalArgumentException if number of component slots exceeds maximum */ static CarrierElements of(Class...ptypes) { Objects.requireNonNull(ptypes, "ptypes must not be null"); return of(methodType(Object.class, ptypes)); } } /** * Instances of this class provide the {@link MethodHandle MethodHandles} to the * constructor and accessors of a carrier object. The original component types can be * gleaned from the parameter types of the constructor {@link MethodHandle} or by the * return types of the components' {@link MethodHandle MethodHandles}. */ static final class CarrierElements { /** * Slot count required for objects. */ private final int objectCount; /** * Slot count required for primitives. */ private final int primitiveCount; /** * Underlying carrier class. */ private final Class carrierClass; /** * Constructor {@link MethodHandle}. */ private final MethodHandle constructor; /** * Initializer {@link MethodHandle}. */ private final MethodHandle initializer; /** * List of component {@link MethodHandle MethodHandles} */ private final List components; /** * Constructor */ private CarrierElements() { throw new AssertionError("private constructor"); } /** * Constructor */ CarrierElements(CarrierShape carrierShape, Class carrierClass, MethodHandle constructor, MethodHandle initializer, List components) { this.objectCount = carrierShape.objectCount(); this.primitiveCount = carrierShape.primitiveCount(); this.carrierClass = carrierClass; this.constructor = constructor; this.initializer = initializer; this.components = components; } /** * {@return slot count required for objects} */ int objectCount() { return objectCount; } /** * {@return slot count required for primitives} */ int primitiveCount() { return primitiveCount; } /** * {@return the underlying carrier class} */ Class carrierClass() { return carrierClass; } /** * {@return the constructor {@link MethodHandle} for the carrier. The * carrier constructor will always have a return type of {@link Object} } */ MethodHandle constructor() { return constructor; } /** * {@return the initializer {@link MethodHandle} for the carrier} */ MethodHandle initializer() { return initializer; } /** * Return the constructor plus initializer {@link MethodHandle} for the carrier. * The {@link MethodHandle} will always have a return type of {@link Object}. * @return the constructor plus initializer {@link MethodHandle} */ MethodHandle initializingConstructor() { return MethodHandles.foldArguments(initializer, 0, constructor); } /** * {@return immutable list of component accessor {@link MethodHandle MethodHandles} * for all the carrier's components. The receiver type of the accessors * will always be {@link Object} } */ List components() { return components; } /** * {@return a component accessor {@link MethodHandle} for component {@code i}. * The receiver type of the accessor will be {@link Object} } * * @param i component index * * @throws IllegalArgumentException if {@code i} is out of bounds */ MethodHandle component(int i) { if (i < 0 || components.size() <= i) { throw new IllegalArgumentException("i is out of bounds " + i + " of " + components.size()); } return components.get(i); } @Override public String toString() { return "Carrier" + constructor.type().parameterList(); } } /** * {@return the underlying carrier class of the carrier representing {@code methodType} } * * @param methodType {@link MethodType} whose parameter types supply the shape of the * carrier's components */ static Class carrierClass(MethodType methodType) { return CarrierFactory.of(methodType).carrierClass(); } /** * {@return the constructor {@link MethodHandle} for the carrier representing {@code * methodType}. The carrier constructor will always have a return type of {@link Object} } * * @param methodType {@link MethodType} whose parameter types supply the shape of the * carrier's components */ static MethodHandle constructor(MethodType methodType) { MethodHandle constructor = CarrierFactory.of(methodType).constructor(); constructor = constructor.asType(constructor.type().changeReturnType(Object.class)); return constructor; } /** * {@return the initializer {@link MethodHandle} for the carrier representing {@code * methodType}. The carrier initializer will always take an {@link Object} along with * component values and a return type of {@link Object} } * * @param methodType {@link MethodType} whose parameter types supply the shape of the * carrier's components */ static MethodHandle initializer(MethodType methodType) { MethodHandle initializer = CarrierFactory.of(methodType).initializer(); initializer = initializer.asType(initializer.type() .changeReturnType(Object.class).changeParameterType(0, Object.class)); return initializer; } /** * {@return the combination {@link MethodHandle} of the constructor and initializer * for the carrier representing {@code methodType}. The carrier constructor/initializer * will always take the component values and a return type of {@link Object} } * * @param methodType {@link MethodType} whose parameter types supply the shape of the * carrier's components */ static MethodHandle initializingConstructor(MethodType methodType) { MethodHandle constructor = CarrierFactory.of(methodType).initializingConstructor(); constructor = constructor.asType(constructor.type().changeReturnType(Object.class)); return constructor; } /** * {@return immutable list of component accessor {@link MethodHandle MethodHandles} for * all the components of the carrier representing {@code methodType}. The receiver type of * the accessors will always be {@link Object} } * * @param methodType {@link MethodType} whose parameter types supply the shape of the * carrier's components */ static List components(MethodType methodType) { return CarrierFactory .of(methodType) .components() .stream() .map(c -> c.asType(c.type().changeParameterType(0, Object.class))) .toList(); } /** * {@return a component accessor {@link MethodHandle} for component {@code i} of the * carrier representing {@code methodType}. The receiver type of the accessor will always * be {@link Object} } * * @param methodType {@link MethodType} whose parameter types supply the shape of the * carrier's components * @param i component index * * @throws IllegalArgumentException if {@code i} is out of bounds */ static MethodHandle component(MethodType methodType, int i) { MethodHandle component = CarrierFactory.of(methodType).component(i); component = component.asType(component.type().changeParameterType(0, Object.class)); return component; } }