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