[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