[code-reflection] RFR: Replace use of MethodTypeDesc with FunctionType

Paul Sandoz psandoz at openjdk.org
Wed Feb 14 16:45:07 UTC 2024


On Wed, 14 Feb 2024 01:15:53 GMT, Paul Sandoz <psandoz at openjdk.org> wrote:

> Replace use of `MethodTypeDesc` with `FunctionType` in the core API.
> 
> This pushes `MethodTypeDesc` more towards the reflective operation usages. There are convenience methods added to `MethodTypeDesc` for conversion/resolution between `FunctionType`. However, it may that the right approach here is convenience methods for conversion/resolution between `java.lang.invoke.MethodType` (or sequences of `Class<?>`) and `FunctionType`, which means we can likely remove `MethodTypeDesc`.

It will take a few more iterations and then we can likely remove `MethodTypeDesc`. Regarding names and arrangements, i wanted wait until we improve the modeling of Java types and where the conversion and resolution functionality will reside.  

My intent was that `FunctionType` is general, and therefore makes sense to use in the "meta" code model. (See also its use for the closure operation.) So far it fits better, and it has usefully highlighted the friction points on `MethodTypeDesc` usage.

I will fix the `funcCall` methods, they should accept `FunctionType` (and in fact right now its only used to obtain the return type, but not yet check the arguments against the number of parameters and their types, perhaps its not needed).

I wanted to deal with the reflective operations separately (including array operations in that category). It seems possible to determine the constructor from the parameter types and return type of a `MethodTypeDesc` (which we could replace with `FunctionType`), and conveniently the same pattern can be used for arrays. For construction the interpreter does this:

        } else if (o instanceof CoreOps.NewOp no) {
            Object[] values = o.operands().stream().map(oc::getValue).toArray();
            JavaType nType = (JavaType) no.constructorDescriptor().returnType();
            if (nType.dimensions() > 0) {
                if (values.length > nType.dimensions()) {
                    throw interpreterException(new IllegalArgumentException("Bad constructor NewOp: " + no));
                }
                int[] lengths = Stream.of(values).mapToInt(v -> (int) v).toArray();
                for (int length : lengths) {
                    nType = nType.componentType();
                }
                return Array.newInstance(resolveToClass(l, nType), lengths);
            } else {
                MethodHandle mh = constructorHandle(l, no.constructorDescriptor());
                return invoke(mh, values);
            }
        } else if (o instanceof CoreOps.QuotedOp qo) {

...

    static MethodHandle constructorHandle(MethodHandles.Lookup l, MethodTypeDesc d) {
        MethodType mt = resolveToMethodType(l, d);

        if (mt.returnType().isArray()) { // <--- this branch is probably a hangover from when only 1D arrays were supported
            if (mt.parameterCount() != 1 || mt.parameterType(0) != int.class) {
                throw interpreterException(new IllegalArgumentException("Bad constructor descriptor: " + d));
            }
            return MethodHandles.arrayConstructor(mt.returnType());
        } else {
            try {
                return l.findConstructor(mt.returnType(), mt.changeReturnType(void.class));
            } catch (NoSuchMethodException | IllegalAccessException e) {
                throw interpreterException(e);
            }
        }
    }

-------------

PR Comment: https://git.openjdk.org/babylon/pull/22#issuecomment-1944206792


More information about the babylon-dev mailing list