Bootstrap method question

Howard Lovatt howard.lovatt at gmail.com
Sun Jun 20 19:26:59 PDT 2010


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