[jep-334] Asymmetric method types of MHD vs MH
Brian Goetz
brian.goetz at oracle.com
Fri Nov 30 20:02:51 UTC 2018
Pushed; give it a try.
On 11/30/2018 10:46 AM, Brian Goetz wrote:
> This suggests to me a much better stacking than my first proposal:
>
> - We already have ofField() and ofConstructor, complete the set by
> adding ofMethod(), for which the lookup descriptor is now completely
> compatible with what is used in Lookup / reflection / CP;
> - Eliminate the total of() variant that takes a MTDesc;
> - Make the total of() variant that takes a String accept method
> descriptor strings for method/ctor and field descriptor strings for
> fields;
> - Provide a lookupDescriptor() accessor that will yield the
> descriptor accepted by of()
>
>
>
> On 11/30/2018 3:27 AM, Michael van Acken wrote:
>> Brian Goetz <brian.goetz at oracle.com <mailto:brian.goetz at oracle.com>>
>> schrieb am Do., 29. Nov. 2018 um 17:27 Uhr:
>>
>> MemberName calls them type and invocationType; unfortunately, what
>> MethodHandle calls type() is the invocation type, and this seems
>> pretty
>> natural for MethodHandle (what else are you going to do with a MH,
>> except invoke it?) Which suggests either:
>>
>> - MHDesc has a method called type(), and it is also be the
>> invocation
>> type;
>> - MHDesc has no method called type(), but instead has
>> invocationType()
>> and lookupType(), or some other better name.
>>
>>
>> I believe this would match the usage of invocationType() in
>> DynamicCallSiteDesc as well.
>>
>> Is the distinction "invocationType() is a thing of the operand stack"
>> while
>> "lookupType() is a thing of the constant pool" a useful mental model
>> here?
>>
>>
>> I think the latter is probably safer.
>>
>> Now, what should the lookupType() be? There's again two ways to go:
>> - Return a ClassDesc for field ops, and a MethodTypeDesc for
>> method ops;
>> - Return a MethodTypeDesc for both
>>
>>
>> My first association for "lookupType()" was the table of
>> lookup.findXXX()
>> methods with its clear separation MethodType / Class here:
>> https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/invoke/MethodHandles.Lookup.html
>>
>>
>>
>> The latter is nicer from an API design perspective (there's a single
>> type), but less nice for those who want to use the API.
>>
>> Michael has already given one example of where you'd want to use
>> this --
>> when calling ASM. Here, there's lots of gymanstics needed to turn
>> the
>> method type into the right thing.
>>
>> Another is if you want to feed a MHDesc back into the lookup
>> methods:
>>
>> MHDesc.of(mhd.kind(), mhd.owner(), mhd.name
>> <http://mhd.name>(), mhd.lookupType())
>>
>>
>> Looks to me like this could be made to work with lookupType() returning
>> either of String, TypeDescriptor, or MethodTypeDesc.
>>
>> Trying to understand the implications, I have two questions:
>>
>> What should the descriptorString overload of MHDesc.of() take e.g.
>> for an
>> instance getter? In MHDesc.of(GETTER, clazz, name, X) the X could be
>> one of "(R)T", "()T", or "T". From my experience with ASM, I assume
>> that
>> the field descriptor variant "T" is closest to both constant pool
>> representation
>> and lookup.findGetter(), but there seem to be reasons for all three
>> of them.
>>
>> Related to this: What is it of benefit in looking at a *field*
>> DMHDesc through
>> the lens of a method descriptor/MethodTypeDesc, outside of the point of
>> view offered by invocationType()?
>>
>> -- Michael van Acken
>>
>>
>>
>>
>>
>> On 11/23/2018 5:05 PM, John Rose wrote:
>> > I think MemberName calls them type and invocationType. That
>> seems like a good division of labor to me, but then I wrote it. :-)
>> >
>> >> On Nov 20, 2018, at 3:26 PM, Maurizio Cimadamore
>> <maurizio.cimadamore at oracle.com
>> <mailto:maurizio.cimadamore at oracle.com>> wrote:
>> >>
>> >> I agree - there are two types: the one based on real classfile
>> descriptor and the unified, curried one exposed by
>> MethodHandle::type(). The former is used for lookup, the latter
>> for invocation. Maybe lookupType() and invocationType() ?
>> >>
>> >> Maurizio
>> >>
>> >>> On 20/11/2018 18:40, Brian Goetz wrote:
>> >>> There are actually two types here, and they both should be
>> exposed. One is a property of MHDesc (which is correctly called
>> type()) which describes the invocation type of the MH; the other
>> is a propertly of DirectMHDesc (which needs a new name) and which
>> is the type that one would provide to the lookup / place in the
>> NameAndType. We're currently in an inconsistent situation.
>> >>>
>> >>>> On 11/20/2018 10:20 AM, Remi Forax wrote:
>> >>>> Hi Brian,
>> >>>> while i agree that the API is primarily a mirror the JVMS
>> view and not the java.lang.invoke view,
>> >>>> one way to avoid that ambiguity is to rename methodType() to
>> type() (as in NameAndType).
>> >>>>
>> >>>> Rémi
>> >>>>
>> >>>> ----- Mail original -----
>> >>>>> De: "Brian Goetz" <brian.goetz at oracle.com
>> <mailto:brian.goetz at oracle.com>>
>> >>>>> À: "Michael van Acken" <michael.van.acken at gmail.com
>> <mailto:michael.van.acken at gmail.com>>, "amber-dev"
>> <amber-dev at openjdk.java.net <mailto:amber-dev at openjdk.java.net>>
>> >>>>> Envoyé: Mardi 20 Novembre 2018 14:28:06
>> >>>>> Objet: Re: [jep-334] Asymmetric method types of MHD vs MH
>> >>>>> Thanks for poking into these new APIs. This is a good
>> question.
>> >>>>>
>> >>>>> Your mental model is a good first-order approximation, but
>> it has some
>> >>>>> risk; in the event of conflict, XxDesc's classes loyalty
>> will be to
>> >>>>> Constant_Xxx_info (the classfile format), rather than its
>> live-type
>> >>>>> counterpart.
>> >>>>>
>> >>>>> MethodHandle embeds the invocation mode (static, virtual,
>> interface,
>> >>>>> special) in the MH itself, so that you can treat the
>> receiver as just
>> >>>>> another parameter. This is tremendously useful as the
>> primary purpose
>> >>>>> of method handles is to be invoked; it collapse four
>> invocation modes
>> >>>>> into one.
>> >>>>>
>> >>>>> DirectMethodHandleDesc models the classfile structure of an
>> invocation;
>> >>>>> the MethodRef_info/NameAndType/invocation bytecode -- as
>> shown in your
>> >>>>> example:
>> >>>>>
>> >>>>> jshell> var mhd =
>> (MethodHandleDesc)mh.describeConstable().get()
>> >>>>> mhd ==>
>> MethodHandleDesc[VIRTUAL/PrintStream::println()void]
>> >>>>>
>> >>>>> I think what you're saying is: there is enough information
>> here to correctly
>> >>>>> compose the type() -- for virtual/special/interface, curry
>> the owner type on --
>> >>>>> and that this would provide alignment with the live
>> MethodHandle behavior.
>> >>>>>
>> >>>>> But, it would separate from the classfile
>> Constant_MethodHandle_info behavior;
>> >>>>> what goes in the NameAndType here (for instance methods) is
>> the receiver-less
>> >>>>> version. Hence the conflict.
>> >>>>>
>> >>>>> I think what is really going on here is that there are two
>> types -- the MH type,
>> >>>>> and the lookup type; the latter is a property of the
>> DMHDesc, while the former
>> >>>>> is a property of the MHDesc?
>> >>>>>
>> >>>>>
>> >>>>>> On 11/20/2018 7:06 AM, Michael van Acken wrote:
>> >>>>>> While tracking down unexpected behavior in my compiler, I
>> noticed that
>> >>>>>> MethodHandleDesc and MethodHandle differ in what they list
>> in their
>> >>>>>> method type. I was expecting that the MHD matches the MH,
>> in that
>> >>>>>> the receiver of a virtual method is included in the
>> parameter list.
>> >>>>>> Instead,
>> >>>>>> it is omitted. (See below for a jshell example.)
>> >>>>>>
>> >>>>>> As a compiler writer, I find the MH's unified view on
>> static and virtual
>> >>>>>> method types very helpful. The current implementation's
>> MHD class
>> >>>>>> does not mirror this view, which means I would have to
>> special case the
>> >>>>>> method types for some operations.
>> >>>>>>
>> >>>>>> My mental model of the descriptor classes is, that they are
>> one-to-one
>> >>>>>> symbolic representations of their handle counterparts. I
>> am very confused
>> >>>>>> by the difference in structure, with the receiver dropping
>> out of the
>> >>>>>> method type.
>> >>>>>>
>> >>>>>>
>> >>>>>> | Welcome to JShell -- Version 12-internal
>> >>>>>> | For an introduction type: /help intro
>> >>>>>>
>> >>>>>> jshell> import java.lang.invoke.*
>> >>>>>>
>> >>>>>> jshell> import java.lang.constant.*
>> >>>>>>
>> >>>>>> jshell> var l = MethodHandles.lookup()
>> >>>>>> l ==>
>> >>>>>>
>> >>>>>> jshell> var mt = MethodType.methodType(Void.TYPE)
>> >>>>>> mt ==> ()void
>> >>>>>>
>> >>>>>> jshell> var mh = l.findVirtual(java.io
>> <http://java.io>.PrintStream.class, "println", mt)
>> >>>>>> mh ==> MethodHandle(PrintStream)void
>> >>>>>>
>> >>>>>> jshell> mh.type()
>> >>>>>> $6 ==> (PrintStream)void
>> >>>>>>
>> >>>>>> jshell> mh.type().parameterCount()
>> >>>>>> $7 ==> 1
>> >>>>>>
>> >>>>>> jshell> var mhd =
>> (MethodHandleDesc)mh.describeConstable().get()
>> >>>>>> mhd ==> MethodHandleDesc[VIRTUAL/PrintStream::println()void]
>> >>>>>>
>> >>>>>> jshell> mhd.methodType()
>> >>>>>> $9 ==> MethodTypeDesc[()void]
>> >>>>>>
>> >>>>>> jshell> mhd.methodType().parameterCount()
>> >>>>>> $10 ==> 0
>> >>>>>>
>> >>>>>>
>> >>>>>> Regards,
>> >>>>>> Michael van Acken
>>
>
More information about the amber-dev
mailing list