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