Bootstrap method question
Howard Lovatt
howard.lovatt at gmail.com
Tue Jun 22 03:40:00 PDT 2010
Rémi,
Many thanks, collectArguments was indeed the bug. My multiple dispatch
example is now working.
As an aside I am still surprised that neither collectArguments or the
call to the MethodHandle threw an exception.
-- Howard.
On 21 June 2010 18:15, Rémi Forax <forax at univ-mlv.fr> wrote:
> I think I 've found the bug,
> in Dispatcher you use collectArguments instead of convertArguments.
>
> Rémi
>
>
> Le 21/06/2010 04:26, Howard Lovatt a écrit :
>>
>> Hi Rémi,
>>
>> A more complete listing is:
>>
>> public final class CostCalculatorDispatcher {
>> private static final Map<MethodType, MethodHandle> mhs = new
>> HashMap<>();
>>
>> private static final String costName = "cost";
>>
>> private static final MethodHandle slowPathHandle =
>> MethodHandles.lookup().findStatic(
>> CostCalculatorDispatcher.class, "slowPath",
>> MethodType.methodType( double.class, CallSite.class,
>> CostCalculator.class, Item.class ) );
>>
>> public static void register( final MethodHandle from ) {
>> Dispatchers.add( mhs, from, costName ); }
>>
>> public static CallSite bootstrap( final Class<?> notUsed, final
>> String name, final MethodType type ) {
>> Dispatchers.checkName( name, costName );
>> return Dispatchers.dispatcher( slowPathHandle, type );
>> }
>>
>> private static double slowPath( final CallSite cS, final
>> CostCalculator cC, final Item i )
>> throws Throwable {
>> System.out.println( "cS = " + cS );
>> System.out.println( "cC = " + cC );
>> System.out.println( "i = " + i );
>> final MethodHandle nearest = Dispatchers.nearest( mhs.values(),
>> double.class, cC, i );
>> System.out.println( "nearest = " + Dispatchers.toString( nearest )
>> );
>> final MethodHandle converted = MethodHandles.collectArguments(
>> nearest, cS.getTarget().type() );
>> System.out.println( "converted = " + Dispatchers.toString( converted )
>> );
>> cS.setTarget( converted );
>> return converted.<double>invokeExact( cC, i );
>> }
>> }
>>
>>
>>
>>
>> public final class Dispatchers {
>> [snip]
>>
>> /**
>> * Add given {@code MethodHandle} to given {@code Map} and throw an
>> exception if it is already
>> * in the {@code Map} or if it has the wrong name.
>> *
>> * @param mhs {@code Map} of {@code MethodType}s to
>> {@code MethodHandle}s to be added to
>> * @param mh {@code MethodHandle} to add to {@code Map}
>> * @param expectedName the name {@code mh} should have
>> *
>> * @throws PECBug if {@code mh} is already in {@code mhs} or
>> if the name of {@code mh}
>> * isn't {@code expectedName}
>> */
>> public static void add( final Map<MethodType, MethodHandle> mhs,
>> final MethodHandle mh, final String expectedName ) {
>> if ( !mh.toString().equals( expectedName ) ) {
>> throw new PECBug( "MethodHandle, " + toString( mh ) + ", doesn't
>> have expected name, " + expectedName );
>> }
>> if ( mhs.put( mh.type(), mh ) != null ) {
>> throw new PECBug( "Given MethodHandle, " + toString( mh ) + ",
>> already in map, " + toString( mhs.values() ) );
>> }
>> }
>>
>> /**
>> * Check that the name given matches the expected name.
>> *
>> * @param name given name
>> * @param expectedName expected name
>> *
>> * @throws PECBug if names don't match
>> */
>> public static void checkName( final String name, final String
>> expectedName ) throws PECBug {
>> if ( !name.equals( expectedName ) ) {
>> throw new PECBug( "Name, " + name + ", isn't " + expectedName );
>> }
>> }
>>
>> /**
>> * Return a call site that calls the given {@code MethodHandle}, the
>> purpose is to delay calling
>> * an actual method until the runtime types are known. The given
>> handle when called returns the
>> * a handle to the nearest available method (in a
>> symmetric-multiple-dispatch sense).
>> * Details: wrap the given {@code MethodHandle} in another handle
>> that binds the first
>> * argument of the given handle to the returned {@code CallSite} and
>> then set the site
>> * to call this second handle and return the site.
>> *
>> * @param slowPath handle to a method that returns a handle to
>> the nearest fit
>> * multiple-dispatch method
>> * @param type the declared, not dynamic, type of the
>> required multiple dispatch method
>> *
>> * @return the {@code MethodHandle} wrapped in a call site and with
>> its first argument bound to
>> * the call site
>> */
>> public static CallSite dispatcher( final MethodHandle slowPath,
>> final MethodType type) {
>> final CallSite callSite = new CallSite();
>> final MethodHandle bound = MethodHandles.insertArguments(
>> slowPath, 0, callSite );
>> System.out.println( "bound = " + toString( bound ) );
>> final MethodHandle converted = MethodHandles.collectArguments(
>> bound, type );
>> System.out.println( "converted = " + toString( converted ) );
>> callSite.setTarget( converted );
>> return callSite;
>> }
>>
>> /**
>> * Find the {@code MethodHandle} in the given {@code Collection}
>> that has the closest type match,
>> * in a symmetric multiple dispatch sense, to the given arguments.
>> *
>> * @param mhs {@code Collection} of {@code MethodHandle}s
>> that are compared to {@code type}
>> * @param returnType the return type of the returned {@code
>> MethodHandle}
>> * @param args the arguments for the returned {@code
>> MethodHandle} (used for types only)
>> *
>> * @return the nearest {@code MethodHandle}
>> *
>> * @throws MultipleDispatchException if no unique, compatible method
>> exists
>> * @throws PECBug if there is a bug in the the
>> code to find the nearest
>> * multiple dispatch method
>> */
>> public static MethodHandle nearest( final Collection<MethodHandle> mhs,
>> final Class<?> returnType, final Object... args ) throws
>> MultipleDispatchException, PECBug {
>> final Class<?>[] argTypes = new Class<?>[ args.length ];
>> for ( int i = 0; i< args.length; i++ ) { argTypes[ i ] = args[ i
>> ].getClass(); }
>> final MethodType mt = MethodType.methodType( returnType, argTypes );
>> return nearest( mhs, mt );
>> }
>>
>> /**
>> * Find the {@code MethodHandle} in the given {@code Collection}
>> that has the closest type match,
>> * in a symmetric multiple dispatch sense, to the given type.
>> *
>> * @param mhs {@code Collection} of {@code MethodHandle}s that
>> are compared to {@code type}
>> * @param type the required type for the returned method handle
>> *
>> * @return the nearest {@code MethodHandle}
>> *
>> * @throws MultipleDispatchException if no unique, compatible method
>> exists
>> * @throws PECBug if there is a bug in the the
>> code to find the nearest
>> * multiple dispatch method
>> */
>> private static MethodHandle nearest( final Collection<MethodHandle>
>> mhs, final MethodType type )
>> throws MultipleDispatchException, PECBug {
>> [snip]
>> }
>> [snip]
>> }
>>
>> Your help is much appreciated,
>>
>> -- Howard.
>>
>> On 19 June 2010 21:00, Rémi Forax<forax at univ-mlv.fr> wrote:
>>
>>>
>>> Le 19/06/2010 08:40, Howard Lovatt a écrit :
>>>
>>>>
>>>> @Rémi,
>>>>
>>>> Thanks for the advise about using a "slowPath" method to discover the
>>>> runtime types. I have coded up something along the lines you
>>>> suggested:
>>>>
>>>> private static double slowPath( final CallSite callSite, final
>>>> CostCalculator cC, final Item i ) throws Throwable {
>>>> System.out.println("callSite = " + callSite + ", CostCalculator =
>>>> " + cC + ", i = " + i );
>>>> final MethodHandle nearest = Dispatchers.nearest( mhs.values(),
>>>> double.class, cC, i );
>>>> System.out.println( "nearest = " + Dispatchers.toString( nearest )
>>>> );
>>>> final MethodHandle converted = MethodHandles.collectArguments(
>>>> nearest, callSite.getTarget().type() );
>>>> System.out.println( "converted = " + Dispatchers.toString( converted
>>>> )
>>>> );
>>>> callSite.setTarget( converted );
>>>> return converted.<double>invokeExact( cC, i );
>>>> }
>>>>
>>>> When run I get the following:
>>>>
>>>> callSite = CallSite#29596205[from invokedynamicmultipledispatch.Cost :
>>>>
>>>>
>>>> (invokedynamicmultipledispatch.CostCalculator,invokedynamicmultipledispatch.Item)double
>>>> => slowPath], CostCalculator =
>>>> invokedynamicmultipledispatch.Price at bf2d5e, i =
>>>> [Ljava.lang.Object;@13bad12
>>>> Exception in thread "main"
>>>> invokedynamicmultipledispatch.MultipleDispatchException
>>>> at invokedynamicmultipledispatch.Cost.cost(Cost.java:62)
>>>> at invokedynamicmultipledispatch.Cost.main(Cost.java:51)
>>>> Caused by: invokedynamicmultipledispatch.MultipleDispatchException:
>>>> Cannot find type,
>>>> (invokedynamicmultipledispatch.Price,java.lang.Object[])double,
>>>> compatible method in,
>>>>
>>>>
>>>> [cost(invokedynamicmultipledispatch.Postage,invokedynamicmultipledispatch.CD)double,
>>>>
>>>>
>>>> cost(invokedynamicmultipledispatch.CostCalculator,invokedynamicmultipledispatch.Item)double,
>>>>
>>>>
>>>> cost(invokedynamicmultipledispatch.Price,invokedynamicmultipledispatch.Book)double,
>>>>
>>>>
>>>> cost(invokedynamicmultipledispatch.Price,invokedynamicmultipledispatch.CD)double,
>>>>
>>>>
>>>> cost(invokedynamicmultipledispatch.Postage,invokedynamicmultipledispatch.Book)double]
>>>> at
>>>> invokedynamicmultipledispatch.Dispatchers.nearest(Dispatchers.java:182)
>>>> at
>>>> invokedynamicmultipledispatch.Dispatchers.nearest(Dispatchers.java:145)
>>>> at
>>>>
>>>> invokedynamicmultipledispatch.CostCalculatorDispatcher.slowPath(CostCalculatorDispatcher.java:35)
>>>> at sun.dyn.FromGeneric$A2.invoke_D2(FromGeneric.java:534)
>>>> at sun.dyn.FilterGeneric$F2.invoke_C1(FilterGeneric.java:550)
>>>> at sun.dyn.ToGeneric$A2.target(ToGeneric.java:661)
>>>> at sun.dyn.ToGeneric$A2.targetA2(ToGeneric.java:662)
>>>> at sun.dyn.ToGeneric$A2.invoke_D(ToGeneric.java:671)
>>>> at invokedynamicmultipledispatch.Cost.cost(Cost.java:60)
>>>> ... 1 more
>>>>
>>>> The interesting bit is "i = [Ljava.lang.Object;@13bad12" on the first
>>>> line of the printout (ignoring wrapping). This Object[] contains 1
>>>> element, the expected Item. What is not expected is wrapping this in
>>>> an array. Also this is a type unsafe at runtime since an array is
>>>> passed into a method in a position where an Item is coded.
>>>>
>>>> Any idea what is going on?
>>>>
>>>> -- Howard.
>>>>
>>>>
>>>
>>> And what is the code of the bootstrap method ?
>>>
>>> Rémi
>>>
>>>
>>
>>
>>
>
>
--
-- Howard.
More information about the mlvm-dev
mailing list