ConstantDynamic JVMS comments
john.r.rose at oracle.com
Thu Aug 31 22:08:32 UTC 2017
(Going back to a dropped response!)
On Jul 19, 2017, at 8:48 AM, Karen Kinnear <karen.kinnear at oracle.com> wrote:
> ...small questions/comments:
> 1. 4.5 fields
> in 220.127.116.11 you have a much clearer description of the argument types
> could you either reference that or include the bullets here? (the syntax is not clear from the sentence structure)
The brevity of the diffs at that point reflects the small size of the
change to the syntax of the BootstrapMethods attribute.
There are three changes:
1. the attribute is used by condy as well as indy
2. the BSM is allowed to be a non-varargs of arity 2
3. it is still the case that anything you can "ldc" you can put into a static BSM argument
Making 3 true requires adding an item to a laundry list of allowable
constant pool types for static arguments. (It's a duplicate of the list
of allowed types for "ldc", modulo the one slot vs. two slot distinction.)
Point 2 is future work, which will not land in the first cut of condy.
That is support for BootstrapCallInfo, which allows BSM arguments
to be resolved under programmer control instead of eagerly.
(I have also pasted a summary at the end, FTR.)
That whole section just shows spot-edits for 1/2/3 above. It's a diff patch
to the existing spec. There's nothing else there other than the pre-existing
stuff. The "@@" marker is a diff-hunk boundary whose placement is arbitrary.
I wasn't clever or industrious enough to the diff hunk boundaries be logical.
That's why Dan's spec. proposals read better: He hand-edits in the diffs.
I'm experimenting with a more webrev-like presentation here. The downside
is the confusing transitions you are seeing. The upside is less hand-work.
> 2. instructions that can use condy
> The JVMS lists ldc/ldc_w
> I think you mentioned that a bootstrap method specifier could contain a condy CP reference
> Are there other places these can appear today?
No, the spec. mentions only BSM arguments and ldc.
Future use: I would like to put them into ConstantValue attributes also,
on static final fields. This will let us express lazy constants in the JVM.
The actual proposal is a new attribute, ConstantDynamicValue.
Please see https://bugs.openjdk.java.net/browse/JDK-8186006
> 3. We need to discuss redefineclasses and BootstrapMethod Attributes
> - Lois and I think we may already have an issue here with indy and condy could just
> make this more common
> - we may want to enhance the redefineclasses documentation restrictions on attributes
> The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields or methods, change the signatures of methods, or change inheritance. These restrictions maybe be lifted in future versions. The class file bytes are not checked, verified and installed until after the transformations have been applied, if the resultant bytes are in error this method will throw an exception.
I think we touched on this in a recent con-call. The worst case risk
with redefinitions is probably having an index into the BootstrapMethods
attribute change its meaning, in a way that breaks the type correctness
of an indy or a condy that uses it. I think this is a pre-existing condition.
We currently preserve pre-existing indexes into the constant pool and
into the BsMs attribute. If this changes, we will have to do more editing
to maintain referential integrity.
Another issue, with "pull mode" (BootstrapCallInfo, item 2 above) is that
the lazy pulling of constants provided by BootstrapCallInfo has to be robust
across class redefinitions. The BCI object is created by the JVM and equipped
with some sort of internal "cookie" that lets it refer to a particular sequence
of BSM arguments. (Currently this is a simple integer index, just like
everything else.) If we allow redefinitions to change pre-existing indexes,
then the referential integrity of the BCI will have to be maintained, probably
by means of a JVM-managed handle. In my view, the cost is so large
and the benefit so small, that we will never choose to support classfile
redefinitions which change pre-existing indexes into the CP or BsMs table.
(The benefit, AFAIKS, is to allow longer chains of redefinitions without
running over the limit of 2*16-1 CP entries. This does not impress me
as a worthy goal. The user can just restart the app. if the debugging
session gets too long. This feature will never be bulletproof, so
restarting the app. is always on the table. Also, we may have a trick
or two up our sleeves to raise the 16-bit limit on CP indexes, which
would remove objections to index preservation. I'd rather solve that
Summary of the BootstrapCallInfo feature (copied from JDK-8186210):
If the bootstrap method accepts two parameters, and it is *not* a
variable-arity method handle, then the linkage information is
presented to the bootstrap method by a API which allows it to *pull*
the static arguments. This allows the bootstrap logic the ability to
order the resolution of constants and catch linkage exceptions. For
this mode of linkage, the bootstrap method is is invoked on just two
* a `MethodHandles.Lookup`, a lookup object on the *caller class*
(as in the "push" mode)
* a `BootstrapCallInfo` object describing the linkage parameters of
the dynamic call site or constant
## Java APIs
`public interface BootstrapCallInfo<T> extends ConstantGroup`
An interface providing full static information about a particular call
to a bootstrap method of an dynamic call site or dynamic
constant. This information include the method itself, the associated
name and type, and any associated static arguments. If a bootstrap
method declares exactly two arguments, and is not of variable arity,
then it is fed only two arguments by the JVM, the lookup object and an
instance of `BootstrapCallInfo` which supplies the rest of the
information about the call.
The API for accessing the static arguments allows the bootstrap method
to reorder the resolution (in the constant pool) of the static
arguments, and to catch errors resulting from the resolution. This
mode of evaluation pulls bootstrap parameters from the JVM under
control of the bootstrap method, as opposed to the JVM pushing
parameters to a bootstrap method by resolving them all before the
bootstrap method is called.
The lookup object is not included in this bundle of information, so as
not to obscure the access control logic of the program. In cases where
there are many thousands of parameters, it may be preferable to pull
their resolved values, either singly or in batches, rather than wait
until all of them have been resolved before a constant or call site
can be used.
* `MethodHandle bootstrapMethod()`
Returns the bootstrap method for this call.
* `String invocationName()`
Returns the method name or constant name for this call.
* `T invocationType()`
Returns the method type or constant type for this call.
* `static <T> BootstrapCallInfo<T> makeBootstrapCallInfo(MethodHandle bsm, String name, T type, ConstantGroup constants)`
Make a new bootstrap call descriptor with the given components.
`public interface ConstantGroup`
An ordered sequence of constants, some of which may not yet be
present. This type is used by `BootstrapCallInfo` to represent the
sequence of bootstrap arguments associated with a bootstrap method,
without forcing their immediate resolution. If you use the simple
`get` method, the constant will be resolved, if this has not already
happened. An occasional side effect of resolution is a `LinkageError`,
which happens if the system could not resolve the constant in
In order to peek at a constant without necessarily resolving it, use
the non-throwing `get` method. This method will never throw a
resolution error. Instead, if the resolution would result in an error,
or if the implementation elects not to attempt resolution at this
point, then the method will return the user-supplied sentinel value.
To iterate through the constants, resolving as you go, use the
iterator provided on the `List`-typed view. If you supply a sentinel,
resolution will be suppressed.
Typically the constant is drawn from a constant pool entry in the
virtual machine. Constant pool entries undergo a one-time state
transition from unresolved to resolved, with a permanently recorded
result. Usually that result is the desired constant value, but it may
also be an error. In any case, the results displayed by a
`ConstantGroup` are stable in the same way. If a query to a particular
constant in a `ConstantGroup` throws an exception once, it will throw
the same kind of exception forever after. If the query returns a
constant value once, it will return the same value forever after.
The only possible change in the status of a constant is from the
unresolved to the resolved state, and that happens exactly once. A
constant will never revert to an unlinked state. However, from the
point of view of this interface, constants may appear to spontaneously
resolve. This is so because constant pools are global structures
shared across threads, and because prefetching of some constants may
occur, there are no strong guarantees when the virtual machine may
When choosing sentinel values, be aware that a constant pool which has
`CONSTANT_ConstantDynamic` entries can contain potentially any
representable value, and arbitrary implementations of `ConstantGroup`
are also free to produce arbitrary values. This means some obvious
choices for sentinel values, such as `null`, may sometimes fail to
distinguish a resolved from an unresolved constant in the group. The
most reliable sentinel is a privately created object, or perhaps the
* `default List<Object> asList()`
Create a view on this group as a `List` view.
* `default List<Object> asList(Object ifNotPresent)`
Create a view on this group as a `List` view.
* `default int copyConstants(int start, int end, Object buf, int pos)`
Copy a sequence of constant values into a given buffer.
* `default int copyConstants(int start, int end, Object buf, int pos, Object ifNotPresent)`
Copy a sequence of constant values into a given buffer.
* `Object get(int index)`
Returns the selected constant, resolving it if necessary.
* `Object get(int index, Object ifNotPresent)`
Returns the selected constant, or the given sentinel value if there is none available.
* `boolean isPresent(int index)`
Returns an indication of whether a constant may be available.
* `static ConstantGroup makeConstantGroup(List<Object> constants, Object ifNotPresent, IntFunction<Object> constantProvider)`
Make a new constant group with the given elements.
* `int size()`
Returns the number of constants in this group.
* `default ConstantGroup subGroup(int start, int end)`
Create a view on a sub-sequence of this group.
More information about the valhalla-spec-observers