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 <[email protected]> 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<[email protected]> 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.pr...@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. _______________________________________________ mlvm-dev mailing list [email protected] http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
