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

Brian Goetz brian.goetz at oracle.com
Fri Nov 30 15:46:42 UTC 2018


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