Le 22/06/2010 12:40, Howard Lovatt a écrit : > 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. >
It's a bug, collectArguments should throw an exception because the last parameter type of the method handle is not an array or a supertype of an array (Object, Serializable, Cloneable). The open question is why it doesn't throw a ClassCastException ? Rémi > 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 >>>> >>>> >>>> >>> >>> >>> >> >> > > > _______________________________________________ mlvm-dev mailing list [email protected] http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
