[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