[jep-334] Asymmetric method types of MHD vs MH

Brian Goetz brian.goetz at oracle.com
Thu Nov 29 22:05:11 UTC 2018


Here's how I propose to resolve this.

Rename existing MHD.methodType() -> invocationType()

Add method DirectMHD.lookupType(), which supports the invariant

     dmhd === MHD.of(dmhd.kind(), dmhd.owner(), dmhd.name(), 
dmhd.lookupType())







On 11/29/2018 11:25 AM, Brian Goetz wrote:
> 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 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
>
> 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(), mhd.lookupType())
>
>
>
> 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> 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>
>>>>>> À: "Michael van Acken" <michael.van.acken at gmail.com>, "amber-dev" 
>>>>>> <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.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