Some proposed modifications of CarrierClass

Jim Laskey james.laskey at oracle.com
Sat Nov 6 01:05:44 UTC 2021


Merci Rémi. 

��

> On Nov 5, 2021, at 9:52 PM, Remi Forax <forax at univ-mlv.fr> wrote:
> 
> Hi Jim,
> I've taken a look to the Carrier class.
> 
> Here are some small modifications,
> - the computation of max locals/max stack for the constructor.
> - use hidden class instead of classical class.
> - use the Lookup of the hidden class instead of using reflection to get the constructor and the array of components.
> - store the constructors and the components in the CarrierClass to avoid to recompute them at each call.
> 
> Obviously, feel free to use whatever parts you want.
> 
> regards,
> Rémi
> 
> 
> /*
> * Copyright (c) 2021, 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.MethodHandles.Lookup.ClassOption;
> import java.lang.invoke.MethodType;
> import java.util.Arrays;
> import java.util.Objects;
> import java.util.concurrent.ConcurrentHashMap;
> 
> import org.objectweb.asm.ClassWriter;
> import org.objectweb.asm.MethodVisitor;
> import org.objectweb.asm.Type;
> 
> import static org.objectweb.asm.Opcodes.*;
> 
> /**
> * This  class is used to create objects that have number and types of
> * components determined at runtime.
> */
> public final class Carrier {
>    /**
>     * Lookup used to define and reference the carrier object classes.
>     */
>    private static final Lookup LOOKUP;
> 
>    /**
>     * Maximum number of components in a carrier (based on the maximum
>     * number of args to a constructor.)
>     */
>    private static final int MAX_COMPONENTS = 254;
> 
>    /**
>     * Maximum number of components in a CarrierClass.
>     */
>    private static final int MAX_OBJECT_COMPONENTS = 32;
> 
>    /*
>     * Initialize {@link MethodHandle} constants.
>     */
>    static {
>        Lookup lookup = MethodHandles.lookup();
>        LOOKUP = lookup;
>        try {
>            FLOAT_TO_INT = lookup.findStatic(Float.class, "floatToRawIntBits",
>                    MethodType.methodType(int.class, float.class));
>            INT_TO_FLOAT = lookup.findStatic(Float.class, "intBitsToFloat",
>                    MethodType.methodType(float.class, int.class));
>            DOUBLE_TO_LONG = lookup.findStatic(Double.class, "doubleToRawLongBits",
>                    MethodType.methodType(long.class, double.class));
>            LONG_TO_DOUBLE = lookup.findStatic(Double.class, "longBitsToDouble",
>                    MethodType.methodType(double.class, long.class));
> 
>            BOOLEAN_TO_INT = lookup.findStatic(Carrier.class, "booleanToInt",
>                    MethodType.methodType(int.class, boolean.class));
>            INT_TO_BOOLEAN = lookup.findStatic(Carrier.class, "intToBoolean",
>                    MethodType.methodType(boolean.class, int.class));
>            BYTE_TO_INT = lookup.findStatic(Carrier.class, "byteToInt",
>                    MethodType.methodType(int.class, byte.class));
>            INT_TO_BYTE = lookup.findStatic(Carrier.class, "intToByte",
>                    MethodType.methodType(byte.class, int.class));
>            SHORT_TO_INT = lookup.findStatic(Carrier.class, "shortToInt",
>                    MethodType.methodType(int.class, short.class));
>            INT_TO_SHORT = lookup.findStatic(Carrier.class, "intToShort",
>                    MethodType.methodType(short.class, int.class));
>            CHAR_TO_INT = lookup.findStatic(Carrier.class, "charToInt",
>                    MethodType.methodType(int.class, char.class));
>            INT_TO_CHAR = lookup.findStatic(Carrier.class, "intToChar",
>                    MethodType.methodType(char.class, int.class));
>        } catch (NoSuchMethodException | IllegalAccessException e) {
>            throw new AssertionError(e);
>        }
>    }
> 
>    /*
>     * Primitive 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;
>    private static final MethodHandle BOOLEAN_TO_INT;
>    private static final MethodHandle INT_TO_BOOLEAN;
>    private static final MethodHandle BYTE_TO_INT;
>    private static final MethodHandle INT_TO_BYTE;
>    private static final MethodHandle SHORT_TO_INT;
>    private static final MethodHandle INT_TO_SHORT;
>    private static final MethodHandle CHAR_TO_INT;
>    private static final MethodHandle INT_TO_CHAR;
> 
>    private static int booleanToInt(boolean b) {
>        return b ? 1 : 0;
>    }
> 
>    private static boolean intToBoolean(int i) {
>        return i != 0;
>    }
> 
>    private static int byteToInt(byte b) {
>        return b;
>    }
> 
>    private static byte intToByte(int i) {
>        return (byte)i;
>    }
> 
>    private static int shortToInt(short s) {
>        return s;
>    }
> 
>    private static short intToShort(int i) {
>        return (short)i;
>    }
> 
>    private static int charToInt(char c) {
>        return c;
>    }
> 
>    private static char intToChar(int i) {
>        return (char)i;
>    }
> 
>    /**
>     * Object signature descriptor.
>     */
>    private static final String OBJECT_DESCRIPTOR =
>            Type.getDescriptor(Object.class);
> 
>    /**
>     * int signature descriptor.
>     */
>    private static final String INT_DESCRIPTOR =
>            Type.getDescriptor(int.class);
> 
>    /**
>     * long signature descriptor.
>     */
>    private static final String LONG_DESCRIPTOR =
>            Type.getDescriptor(long.class);
> 
>    /**
>     * Shape of carrier based on counts of each of the three fundamental data
>     * types.
>     */
>    private record CarrierShape(int objectCount, int intCount, int longCount) {
>        /**
>         * Total number of slots used in a {@link CarrierClass} instance.
>         *
>         * @return number of slots used
>         */
>        int slotCount() {
>            return objectCount + intCount + longCount * 2;
>        }
> 
>        /**
>         * Returns index of first object component.
>         *
>         * @return index of first object component
>         */
>        int objectOffset() {
>            return 0;
>        }
> 
>        /**
>         * Returns index of first int component.
>         *
>         * @return index of first int component
>         */
>        int intOffset() {
>            return objectCount;
>        }
> 
> 
>        /**
>         * Returns index of first long component.
>         *
>         * @return index of first long component
>         */
>        int longOffset() {
>            return objectCount + intCount;
>        }
> 
>        /**
>         * Returns the constructor method type.
>         *
>         * @return the constructor method type.
>         */
>        MethodType constructorMethodType() {
>            Class<?>[] array = new Class<?>[objectCount + intCount + longCount];
>            int arg = 0;
>            for(int i = 0; i < objectCount; i++) {
>                array[arg++] = Object.class;
>            }
>            for(int i = 0; i < intCount; i++) {
>                array[arg++] = int.class;
>            }
>            for(int i = 0; i < longCount; i++) {
>                array[arg++] = long.class;
>            }
>          return MethodType.methodType(void.class, array);
>        }
>    }
> 
>    /**
>     * Factory for array based carrier. Array wrapped in object to provide
>     * immutability.
>     */
>    static class CarrierArrayFactory {
>        /**
>         * Constructor
>         *
>         * @param ptypes types of carrier constructor arguments
>         *
>         * @return {@link MethodHandle} to generic carrier constructor.
>         */
>        static MethodHandle constructor(Class<?>[] ptypes) {
>            MethodType methodType = MethodType.methodType(Object.class, ptypes);
>            MethodHandle collector = MethodHandles.identity(Object[].class)
>                    .withVarargs(true);
> 
>            return collector.asType(methodType);
>        }
> 
>        /**
>         * Return an array of carrier component getters, aligning with types in
>         * {@code ptypes}.
>         *
>         * @param ptypes  types of carrier constructor arguments
>         *
>         * @return array of carrier getters
>         */
>        static MethodHandle[] components(Class<?>[] ptypes) {
>            int length = ptypes.length;
>            MethodHandle[] getters = new MethodHandle[length];
> 
>            for (int i = 0; i < length; i++) {
>                getters[i] = component(ptypes, i);
>            }
> 
>            return getters;
>        }
> 
>        /**
>         * Return a carrier getter for component {@code i}.
>         *
>         * @param ptypes  types of carrier constructor arguments
>         * @param i       index of parameter to get
>         *
>         * @return carrier component {@code i} getter {@link MethodHandle}
>         */
>        static MethodHandle component(Class<?>[] ptypes, int i) {
>            MethodType methodType =
>                    MethodType.methodType(ptypes[i], Object.class);
>            MethodHandle getter =
>                    MethodHandles.arrayElementGetter(Object[].class);
> 
>            return MethodHandles.insertArguments(
>                    getter, 1, i).asType(methodType);
>        }
>    }
> 
>    /**
>     * Factory for object based carrier.
>     */
>    static class CarrierObjectFactory {
>        /**
>         * Define the hidden class Lookup object
>         *
>         * @param bytes  class content
>         *
>         * @return the Lookup object of the hidden class
>         */
>        static Lookup defineHiddenClass(byte[] bytes) {
>            try {
>                return LOOKUP.defineHiddenClass(bytes, false, ClassOption.STRONG);
>            } catch (IllegalAccessException e) {
>                throw new AssertionError(e);
>            }
>        }
> 
>        /**
>         * Generate the name of an object component.
>         *
>         * @param index field/component index
>         *
>         * @return name of object component
>         */
>        private static String objectFieldName(int index) {
>            return "o" + index;
>        }
> 
>        /**
>         * Generate the name of an int component.
>         *
>         * @param index field/component index
>         *
>         * @return name of int component
>         */
>        private static String intFieldName(int index) {
>            return "i" + index;
>        }
> 
>        /**
>         * Generate the name of a long component.
>         *
>         * @param index field/component index
>         *
>         * @return name of long component
>         */
>        private static String longFieldName(int index) {
>            return "l" + index;
>        }
> 
>        /**
>         * Generate the full name of a carrier class based on shape.
>         *
>         * @param carrierShape  shape of carrier
>         *
>         * @return name of a carrier class
>         */
>        static String carrierClassName(CarrierShape carrierShape) {
>            String packageName = Carrier.class.getPackageName().replace('.', '/');
>            String className = "Carrier$" +
>                    objectFieldName(carrierShape.objectCount) +
>                    intFieldName(carrierShape.intCount) +
>                    longFieldName(carrierShape.longCount);
> 
>            return packageName.isEmpty() ? className :
>                    packageName + "/" + className;
>        }
> 
>        /**
>         * Construct a new object carrier class based on shape.
>         *
>         * @param carrierShape  shape of carrier
>         *
>         * @return a {@link CarrierClass} object containing constructor and
>         *         component getters.
>         */
>        static CarrierClass newCarrierClass(CarrierShape carrierShape) {
>            String carrierClassName = carrierClassName(carrierShape);
> 
>            StringBuilder initDescriptor = new StringBuilder("(");
> 
>            ClassWriter cw = new ClassWriter(0);
>            cw.visit(V17, ACC_PUBLIC | ACC_FINAL, carrierClassName,
>                    null, "java/lang/Object", null);
>            int fieldFlags = ACC_PUBLIC | ACC_FINAL;
> 
>            for (int i = 0; i < carrierShape.objectCount; i++) {
>                cw.visitField(fieldFlags, objectFieldName(i), OBJECT_DESCRIPTOR,
>                        null, null);
>                initDescriptor.append(OBJECT_DESCRIPTOR);
>            }
> 
>            for (int i = 0; i < carrierShape.intCount; i++) {
>                cw.visitField(fieldFlags, intFieldName(i), INT_DESCRIPTOR,
>                        null, null);
>                initDescriptor.append(INT_DESCRIPTOR);
>            }
> 
>            for (int i = 0; i < carrierShape.longCount; i++) {
>                cw.visitField(fieldFlags, longFieldName(i), LONG_DESCRIPTOR,
>                        null, null);
>                initDescriptor.append(LONG_DESCRIPTOR);
>            }
> 
>            initDescriptor.append(")V");
> 
>            {
>                MethodVisitor init = cw.visitMethod(ACC_PUBLIC,
>                    "<init>", initDescriptor.toString(), null, null);
>                init.visitVarInsn(ALOAD, 0);
>                init.visitMethodInsn(INVOKESPECIAL,
>                    "java/lang/Object", "<init>", "()V", false);
> 
>                int arg = 1;
>                for (int i = 0; i < carrierShape.objectCount; i++) {
>                    init.visitVarInsn(ALOAD, 0);
>                    init.visitVarInsn(ALOAD, arg++);
>                    init.visitFieldInsn(PUTFIELD, carrierClassName,
>                        objectFieldName(i), OBJECT_DESCRIPTOR);
>                }
> 
>                for (int i = 0; i < carrierShape.intCount; i++) {
>                    init.visitVarInsn(ALOAD, 0);
>                    init.visitVarInsn(ILOAD, arg++);
>                    init.visitFieldInsn(PUTFIELD, carrierClassName,
>                        intFieldName(i), INT_DESCRIPTOR);
>                }
> 
>                for (int i = 0; i < carrierShape.longCount; i++) {
>                    init.visitVarInsn(ALOAD, 0);
>                    init.visitVarInsn(LLOAD, arg);
>                    arg += 2;
>                    init.visitFieldInsn(PUTFIELD, carrierClassName,
>                        longFieldName(i), LONG_DESCRIPTOR);
>                }
> 
>                init.visitInsn(RETURN);
>                init.visitMaxs(
>                    carrierShape.longCount != 0? 3: ((carrierShape.objectCount != 0 || carrierShape.intCount != 0)? 2: 1)  ,
>                    1 /* this */ + carrierShape.slotCount());
>                init.visitEnd();
>            }
> 
>            cw.visitEnd();
>            byte[] bytes = cw.toByteArray();
> 
>            Lookup hiddenClassLookup = defineHiddenClass(bytes);
>            Class<?> hiddenClass = hiddenClassLookup.lookupClass();
>            MethodType constructorMethodType = carrierShape.constructorMethodType();
>            MethodHandle constructor;
>            MethodHandle[] components;
>            try {
>                constructor = hiddenClassLookup.findConstructor(hiddenClass, constructorMethodType);
> 
>                components = new MethodHandle[constructorMethodType.parameterCount()];
>                int arg = 0;
>                for(int i = 0; i < carrierShape.objectCount; i++) {
>                    components[arg++] = hiddenClassLookup.findGetter(hiddenClass,
>                        CarrierObjectFactory.objectFieldName(i), Object.class);
>                }
>                for(int i = 0; i < carrierShape.intCount; i++) {
>                    components[arg++] = hiddenClassLookup.findGetter(hiddenClass,
>                        CarrierObjectFactory.intFieldName(i), int.class);
>                }
>                for(int i = 0; i < carrierShape.longCount; i++) {
>                    components[arg++] = hiddenClassLookup.findGetter(hiddenClass,
>                        CarrierObjectFactory.longFieldName(i), long.class);
>                }
>            } catch (NoSuchMethodException | NoSuchFieldException | IllegalAccessException e) {
>                throw new AssertionError(e);
>            }
> 
>            return new CarrierClass(constructor, components);
>        }
>    }
> 
>    /**
>     * Provides constructor and component MethodHandles for a constructed
>     * carrier class.
>     */
>    record CarrierClass(
>        /**
>         * A raw {@link MethodHandle} for a carrier object constructor.
>         * This constructor will only have Object, int and long type arguments.
>         *
>         */
>        MethodHandle constructor,
> 
>        /**
>         * All the raw {@link MethodHandle MethodHandles} for a carrier
>         * component getters. These getters will only return Object, int and
>         * long types.
>         */
>        MethodHandle[] components) {
> 
>        /**
>         * Create a single raw {@link MethodHandle} for a carrier component
>         * getter.
>         *
>         * @param i  index of component to get
>         *
>         * @return raw {@link MethodHandle} for the component getter
>         */
>        MethodHandle component(int i) {
>            return components[i];
>        }
>    }
> 
>    /**
>     * Cache for all constructed carrier object classes, keyed on class
>     * name (i.e., carrier shape.)
>     */
>    private static final ConcurrentHashMap<String, CarrierClass> carrierCache =
>            new ConcurrentHashMap<>();
> 
>    /**
>     * Constructor
>     */
>    private Carrier() {
>    }
> 
>    /**
>     * Find or create carrier class for a carrioer shape.
>     *
>     * @param carrierShape  shape of carrier
>     *
>     * @return {@link Class<>} of carrier class matching carrier shape
>     */
>    private static CarrierClass findCarrierClass(CarrierShape carrierShape) {
>        String carrierClassName =
>                CarrierObjectFactory.carrierClassName(carrierShape);
> 
>        return carrierCache.computeIfAbsent(carrierClassName,
>                cn -> CarrierObjectFactory.newCarrierClass(carrierShape));
>    }
> 
>    /**
>     * Get the carrier shape based on parameter types.
>     *
>     * @param ptypes  parameter types
>     *
>     * @return carrier object shape
>     *
>     * @throws IllegalArgumentException if number of component slots exceeds maximum
>     */
>    private static CarrierShape getCarrierShape(Class<?>[] ptypes) {
>        int objectCount = 0;
>        int intCount = 0;
>        int longCount = 0;
> 
>        for (Class<?> ptype : ptypes) {
>            if (!ptype.isPrimitive()) {
>                objectCount++;
>            } else if (ptype == long.class || ptype == double.class) {
>                longCount++;
>            } else {
>                intCount++;
>            }
>        }
> 
>        CarrierShape carrierShape = new CarrierShape(objectCount, intCount, longCount);
> 
>        if (MAX_COMPONENTS < carrierShape.slotCount()) {
>            throw new IllegalArgumentException("Exceeds maximum number of component slots");
>        }
> 
>        return carrierShape;
>    }
> 
>    /**
>     * Permute a raw constructor {@link MethodHandle} to match the order and
>     * types of the parameter types.
>     *
>     * @param newPTypes     given parameter types
>     * @param carrierShape  carrier object shape
>     * @param constructor   {@link MethodHandle} to raw carrier object constructor
>     *
>     * @return {@link MethodHandle} constructor matching parameter types
>     */
>    private static MethodHandle constructor(Class<?>[] newPTypes,
>                                            CarrierShape carrierShape,
>                                            MethodHandle constructor) {
>        int objectIndex = carrierShape.objectOffset();
>        int intIndex = carrierShape.intOffset();
>        int longIndex = carrierShape.longOffset();
>        int[] reorder = new int[newPTypes.length];
>        int index = 0;
>        Class<?>[] permutePTypes = new Class<?>[newPTypes.length];
> 
>        for (Class<?> ptype : newPTypes) {
>            MethodHandle filter = null;
>            int from;
> 
>            if (!ptype.isPrimitive()) {
>                from = objectIndex++;
>                ptype = Object.class;
>            } else if (ptype == long.class || ptype == double.class) {
>                from = longIndex++;
>                filter = ptype == double.class ? DOUBLE_TO_LONG : null;
>            } else {
>                from = intIndex++;
> 
>                if (ptype == float.class) {
>                    filter = FLOAT_TO_INT;
>                } else if (ptype == boolean.class) {
>                    filter = BOOLEAN_TO_INT;
>                } else if (ptype == byte.class) {
>                    filter = BYTE_TO_INT;
>                } else if (ptype == short.class) {
>                    filter = SHORT_TO_INT;
>                } else if (ptype == char.class) {
>                    filter = CHAR_TO_INT;
>                }
>            }
> 
>            permutePTypes[index] = ptype;
>            reorder[from] = index++;
>            constructor = filter == null ? constructor :
>                    MethodHandles.filterArguments(constructor, from, filter);
>        }
> 
>        MethodType permutedMethodType =
>                MethodType.methodType(constructor.type().returnType(),
>                        permutePTypes);
>        MethodType castMethodType =
>                MethodType.methodType(Object.class, newPTypes);
>        constructor = MethodHandles.permuteArguments(constructor,
>                permutedMethodType, reorder);
>        constructor = constructor.asType(castMethodType);
> 
>        return constructor;
>    }
> 
>    /**
>     * Permute raw component getters to match order and types of the parameter
>     * types.
>     *
>     * @param ptypes        given parameter types
>     * @param carrierShape  carrier object shape
>     * @param components    raw {@link MethodHandle MethodHandles} to raw
>     *                      carrier component getters
>     *
>     * @return array of components matching parameter types
>     */
>    private static MethodHandle[] components(Class<?>[] ptypes,
>                                             CarrierShape carrierShape,
>                                             MethodHandle[] components) {
>        MethodHandle[] reorder = new MethodHandle[ptypes.length];
>        int objectIndex = 0;
>        int intIndex = carrierShape.objectCount;
>        int longIndex = carrierShape.objectCount + carrierShape.intCount;
>        int index = 0;
> 
>        for (Class<?> ptype : ptypes) {
>            MethodHandle component;
>            MethodHandle filter = null;
> 
>            if (!ptype.isPrimitive()) {
>                component = components[objectIndex++];
>            } else if (ptype == long.class || ptype == double.class) {
>                component = components[longIndex++];
>                filter = ptype == double.class ? LONG_TO_DOUBLE : null;
>            } else {
>                component = components[intIndex++];
> 
>                if (ptype == float.class) {
>                    filter = INT_TO_FLOAT;
>                } else if (ptype == boolean.class) {
>                    filter = INT_TO_BOOLEAN;
>                } else if (ptype == byte.class) {
>                    filter = INT_TO_BYTE;
>                } else if (ptype == short.class) {
>                    filter = INT_TO_SHORT;
>                } else if (ptype == char.class) {
>                    filter = INT_TO_CHAR;
>                }
>            }
> 
>            component = filter == null ? component :
>                    MethodHandles.filterReturnValue(component, filter);
>            MethodType methodType = MethodType.methodType(ptype, Object.class);
>            reorder[index++] = component.asType(methodType);
>        }
> 
>        return reorder;
>    }
> 
>    /**
>     * Returns a carrier component getter {@link MethodHandle} for the
>     * component {@code i}.
>     *
>     * @param ptypes        given parameter types
>     * @param carrierShape  shape of the carrier object
>     * @param carrierClass  carrier object class
>     * @param i             index to the component
>     *
>     * @return carrier component getter {@link MethodHandle}
>     *
>     * @throws IllegalArgumentException if number of component slots exceeds maximum
>     */
>    private static MethodHandle component(Class<?>[] ptypes,
>                                          CarrierShape carrierShape,
>                                          CarrierClass carrierClass,
>                                          int i) {
>        CarrierShape componentShape = getCarrierShape(Arrays.copyOf(ptypes, i));
>        Class<?> ptype = ptypes[i];
>        int index;
>        MethodHandle filter = null;
> 
>        if (!ptype.isPrimitive()) {
>            index = carrierShape.objectOffset() + componentShape.objectCount();
>        } else if (ptype == long.class || ptype == double.class) {
>            index = carrierShape.longOffset() + componentShape.longCount();
>            filter = ptype == double.class ? LONG_TO_DOUBLE : null;
>        } else {
>            index = carrierShape.intOffset() + componentShape.intCount();
> 
>            if (ptype == float.class) {
>                filter = INT_TO_FLOAT;
>            } else if (ptype == boolean.class) {
>                filter = INT_TO_BOOLEAN;
>            } else if (ptype == byte.class) {
>                filter = INT_TO_BYTE;
>            } else if (ptype == short.class) {
>                filter = INT_TO_SHORT;
>            } else if (ptype == char.class) {
>                filter = INT_TO_CHAR;
>            }
>        }
> 
>        MethodHandle component = carrierClass.component(index);
>        component = filter == null ? component :
>                MethodHandles.filterReturnValue(component, filter);
> 
>        return component.asType(MethodType.methodType(ptype, Object.class));
>    }
> 
>    /**
>     * Return a constructor {@link MethodHandle} for a carrier with components
>     * aligning with the parameter types of the supplied
>     * {@link MethodType methodType}.
>     *
>     * @param methodType {@link MethodType} providing types for the carrier's
>     *                   components.
>     *
>     * @return carrier constructor {@link MethodHandle}
>     *
>     * @throws NullPointerException is methodType is null
>     * @throws IllegalArgumentException if number of component slots exceeds maximum
>     */
>    public static MethodHandle constructor(MethodType methodType) {
>        Objects.requireNonNull(methodType);
> 
>        Class<?>[] ptypes = methodType.parameterArray();
>        CarrierShape carrierShape = getCarrierShape(ptypes);
> 
>        if (carrierShape.slotCount() <= MAX_OBJECT_COMPONENTS) {
>            CarrierClass carrierClass = findCarrierClass(carrierShape);
> 
>            return constructor(ptypes, carrierShape, carrierClass.constructor());
>        } else {
>            return CarrierArrayFactory.constructor(ptypes);
>        }
>    }
> 
>    /**
>     * Return component getter {@link MethodHandle MethodHandles} for all the
>     * carrier's components.
>     *
>     * @param methodType {@link MethodType} providing types for the carrier's
>     *                   components.
>     *
>     * @return  array of get component {@link MethodHandle MethodHandles}
>     *
>     * @throws NullPointerException is methodType is null
>     * @throws IllegalArgumentException if number of component slots exceeds maximum
>     *
>     */
>    public static MethodHandle[] components(MethodType methodType) {
>        Objects.requireNonNull(methodType);
>        Class<?>[] ptypes = methodType.parameterArray();
>        CarrierShape carrierShape = getCarrierShape(ptypes);
>        int slotCount = carrierShape.slotCount();
>        MethodHandle[] components;
> 
>        if (slotCount <= MAX_OBJECT_COMPONENTS) {
>            Carrier.CarrierClass carrierClass = findCarrierClass(carrierShape);
>            components = components(ptypes, carrierShape, carrierClass.components());
>        } else {
>            components = Carrier.CarrierArrayFactory.components(ptypes);
>        }
> 
>        return components;
>    }
> 
>    /**
>     * Return a component getter {@link MethodHandle} for component {@code i}.
>     *
>     * @param methodType {@link MethodType} providing types for the carrier's
>     *                   components.
>     * @param i          component index
>     *
>     * @return a component getter {@link MethodHandle} for component {@code i}
>     *
>     * @throws NullPointerException is methodType is null
>     * @throws IllegalArgumentException if number of component slots exceeds maximum
>     *                                  or if {@code i} is out of bounds
>     */
>    public static MethodHandle component(MethodType methodType, int i) {
>        Objects.requireNonNull(methodType);
>        Class<?>[] ptypes = methodType.parameterArray();
> 
>        if (i < 0 || i >= ptypes.length) {
>            throw new IllegalArgumentException("i is out of bounds for ptypes");
>        }
> 
>        CarrierShape carrierShape = getCarrierShape(ptypes);
> 
>        if (carrierShape.slotCount() <= MAX_OBJECT_COMPONENTS) {
>            CarrierClass carrierClass = findCarrierClass(carrierShape);
> 
>            return component(ptypes, carrierShape, carrierClass, i);
>        } else {
>            return CarrierArrayFactory.component(ptypes, i);
>        }
>    }
> }


More information about the amber-dev mailing list