Le 22/10/2010 10:43, John Rose a écrit :
> Based partly on our discussions at the Summit about "live constants", and 
> also based on the likely requirements of Project Lambda, the JSR 292 EG is 
> likely to allow any single invokedynamic instruction to pass one or more 
> extra constant values into the bootstrap method invocation.
>
> Here is the current thinking.  Language implementors, please tell us if we 
> are missing anything.
>
> We call these "static arguments", in contrast to the normal "dynamic 
> arguments" that are received on every method call.  For invokedynamic, the 
> dynamic arguments are received as if by 'invokeExact' on the method handle 
> bound to the invokedynamic instruction instance, by the BSM.  The BSM 
> decides, once at link time, which method handle to choose based on the static 
> arguments.
>
> There are three standard static arguments always passed to the BSM:
>   1. an indication of the caller class (note: this is likely to change to a 
> MethodHandles.Lookup capability)
>   2. a String naming the method apparently being called
>   3. a MethodType indicating the dynamic arguments and return value types
>
> The String and MethodType are extracted from the NameAndType constant at the 
> invokedynamic site.
>
> The invokedynamic instruction points to a constant pool entry that looks like 
> this:
>
> struct InvokeDynamic_info {
>    u1 tag; // always CONSTANT_InvokeDynamic = 18
>    u2 bsm_index;   // ref to CONSTANT_MethodHandle
>    u2 descr_index; // ref to CONSTANT_NameAndType
>    u2 argc;  // count of optional static arguments
>    u2 argv[argc];  // refs to anything 'ldc' can refer to (int, long, float, 
> double, class, method handle, method type)
> }
>
> If we take this path, we will switch to the tag '18', to reduce confusion 
> when old and new class files are mixed.
>
> The existing tag '17' for the no-extra-args format will drop out of use and 
> be illegal in JDK7 FCS.
>
> Depending on the value of argc, the BSM will be invoked in one of three ways:
>    if (argc = 0)  binding = bsm.invokeGeneric(lookup, name, type);
>    if (argc = 1)  binding = bsm.invokeGeneric(lookup, name, type, (Object) 
> argv[0]);
>    if (argc>  1)  binding = bsm.invokeGeneric(lookup, name, type, (Object[]) 
> argv);
>
> Note that the BSM, since it is derived from a CONSTANT_MethodHandle, can only 
> be a "direct method handle", a pointer to a Java method.  It cannot be 
> adapted (e.g., as a spreader or collector).  But in user-visible code, it 
> would be reasonable to express a typical BSM as an overloaded method, whose 
> third overloading takes a varargs array:
>    MethodHandle myBSM(MethodHandles.Lookup look, String name, MethodType 
> type);
>    MethodHandle myBSM(MethodHandles.Lookup look, String name, MethodType 
> type, Object arg);
>    MethodHandle myBSM(MethodHandles.Lookup look, String name, MethodType 
> type, Object... args);
>    

And also:

   CallSite myBSM(MethodHandles.Lookup look, String name, MethodType type);
   CallSite myBSM(MethodHandles.Lookup look, String name, MethodType type, 
Object arg);
   CallSite myBSM(MethodHandles.Lookup look, String name, MethodType type, 
Object... args);


A bootstrap method can return a call site (CallSite) or a method handle 
(MethodHandle).
The idea is to return a CallSite if the target method can change and a 
MethodHandle
if the target of an invokedynamic never change.

> It is natural to ask why we are using varargs, when we could just specify 
> that the extra static arguments could be passed positionally.  The simple 
> answer is positional arguments are of limited use, but a varargs array can be 
> used to encode very rich and useful BSM arguments.
>
> Since very few Java methods take more than 10 parameters, allowing up to 255 
> extra arguments is not very interesting.  (Actually the limit would be 251 
> non-long non-double arguments, since there are three to start with, plus the 
> BSM itself.)  Writing a BSM which takes (say) 100 arguments would be silly.  
> (Note that BSMs cannot be collectArguments adapters; they have to be simple 
> JVM methods or constructors.)  And a related one that takes 99 arguments 
> would have to be a completely distinct method.  It is clear that any large 
> number of arguments has to be passed in an array.  So let's pass them all in 
> a trailing varargs parameter.
>
> Will users want more than a couple of extra static arguments?  I think so.  
> It will provide a way to bind interesting specifications directly into the 
> classfile, without cumbersome bytecode-based construction.  Examples:
>   - a serialized AST structure, built from a mix of strings and method 
> handles, to be interpreted
>   - complex application-defined constants, such as lists or sets
>   - similarly, templates for partly-constant data structures (the 
> invokedynamic builds a factory method for the template)
>   - vtables (i.e., maps of names to method handles)
>
> All of these things can be created by executable bytecodes in<clinit>, but 
> implementors will (in many cases) be able to create them more compactly from 
> series of constants.  For example, a list of integer values will occupy 2+1+4 
> bytes per element if encoded as a sequence of static arguments.  (The '2' is 
> the argv element; the 1+4 is the CONSTANT_Integer.)  Using<clinit>  style 
> bytecodes, the same element will require (1+2+3+1)+1+4 bytes, where the 
> parenthesized numbers stand for a sequence of "aload buf; bipush J; ldc N; 
> aastore".  (This sequence stores the element into an object array, which is 
> going to be passed to something like Arrays.asList.)  The ratio is 7 to 11.  
> For integer values which repeat, the ratio is closer to 2 to 6.
>
> There is a limit to this technique, of course, since the constant pool has 
> only 65535 constants.  But this limit is shared with the<clinit>  style 
> technique.
>
> A key use case for one or two BSM arguments is closure construction for 
> Project Lambda.  Here, an extra static argument can specify a private 
> synthetic method which gives the body (code, not data) of the closure.  The 
> data parts are normal dynamic arguments.  The BSM produces a factory function 
> which (efficiently) binds the data values to the statically specified closure 
> body.  A second BSM argument might be the SAM type intended for the closure.  
> (That could also be inferred from the MethodType.)
>
> Another key use case is an invokedynamic instruction that implements an 
> arbitrary live constant, by linking the call site (of zero arguments) to a 
> method handle which always returns the desired constant.  
> (MethodHandles.constant will do this.)  The only missing bit is the 
> serialized data behind the live constant.  Again, allowing an essentially 
> unbounded array gives implementors the right degree (I think) of flexibility.
>
> If, instead of constants, we want templated values (think Groovy strings like 
> "hello, $name"), the statically determined structure of the value can be 
> expressed in static arguments to an invokedynamic, with the inserted values 
> ("$name") passed on the stack.  The BSM produces a factory function which 
> builds the desired result.  The BSM might use a templating engine to 
> partially evaluate the static structure, so that the dynamically changing 
> parts can be combined in at full speed.
>
> (A useful thing missing here is substructure sharing:  What if two 
> invokedynamic instructions need almost the same static arguments?  This can 
> be dealt in user code, with via a static table created in<clinit>  or a 
> similar method.  Shared values can be referred to by small integers assigned 
> by the language backend.  In essence, the components we are proposing help 
> language implementors to build better versions of constant pools and vtables, 
> with compactness and efficiency similar to the corresponding native 
> structures.)
>
> In conclusion:  It is true that most use cases for BSM arguments will only 
> need one or two extra arguments.  But if we allow an array of strings, 
> integer, method handles, etc., with a reasonable length, suddenly our 
> language implementor friends have a flexible and natural way to use for 
> encoding the "serialized" version of their live constants.
>
> So, let's not just one or two static arguments, and not a useless 251, 
> either, but rather a useful 65535.
>
> (I'd go for a larger number, 2**31-1, but it would not mesh with the other 
> 16-bit numbers in the class file format.  That's got to be fixed in a big 
> format revision, another day.)
>
> -- John
>    

Rémi
_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

Reply via email to