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