Bootstrap method question

Rémi Forax forax at univ-mlv.fr
Mon Jun 21 01:15:08 PDT 2010


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
>>
>>      
>
>
>    



More information about the mlvm-dev mailing list