(The name _wither_ method does not mean a way to blight or shrivel
something--certainly a shady activity. It refers to a naming
convention for methods that perform functional update of record
values. Asking a complex number `c.withRe(0)` would return a new
pure-imaginary complex number. By contrast, `c.setRe(0)`, a call to a
_setter_ method, would seem to mutate the complex number, removing any
non-zero real component. Setter methods are appropriate to mutable
objects, while wither methods are appropriate to values. Note that a
method can in fact be a getter, setter, or wither method even if it
does not begin with one of those standard words. The eventual
conventions for value types may well discourage forms like `withRe(0)`
in favor of simply `re(0)`.)
It is likely that these methods in `ValueTypeSupport` will eventually
become virtual methods of `Lookup` itself (if that is the leading
argument), else static methods of `MethodHandles`.
## Future work
This minimal proposal is by nature temporary and provisional. It
gives a necessary foundation for further work, rather than a final
specification. Some of the further work will be similarly provisional
in nature, but over time we will build on our successes and learn
from our mistakes, eventually creating a well-designed specification
that can takes its place in the sun.
This present set of features that support value types will be
difficult to work with; this is intentional. The rest of this
document sketches a few additional features which may enable
experiments not practical or possible in the minimized proposal.
Therefore, this last section may be safely skipped. Any such features
will be given their own supporting documentation if they are pursued.
It may be of interest, however, to people who have noticed missing
features in the minimal values proposal.
### Denoting Q-types in Java source code
At a minimum, no language changes are needed to work with Q-types. A
combination of JVM hacks (value-capable classes), annotation-driven
classfile transformations, and direct bytecode generation are enough
to exercise interesting micro-benchmarks. Method handles supply a
useful alternative to direct bytecode generation, and they will be
made fully capable of working with Q-types (as described below).
Nevertheless, there is nothing like language support. It is likely
that very early experiments with `javac` will create simple ways to
refer to Q-types and create variables for them, directly in Java code
(subject to contextual restrictions, of course).
In particular, constructors for objects have a very different bytecode
shape than seemingly-equivalent constructors for value types. (The
syntax for Java object constructors is a perfectly fine notation for
value type constructors, as long as all fields are final.) It would
be reasonable for javac to take on the burden of byte-compiling both
versions of each constructor of a value-capable class.
Likewise, direct invocation of value type constructors, and direct
access of value type methods and fields, would be convenient to use
from Java source code, even if they had to be compiled to
invokedynamic calls, until bytecode support was completed.
### More constants
Additional enhancements to the constant pool may allow creation of
constants derived from bootstrap methods. Such features are not in
the scope of present document. They are described in the OpenJDK RFE
[JDK-8161256][]. This RFE mentions the present enhancement of
`CONSTANT_Class`.
If this RFE is implemented, it may be possible to delay a few of the
steps described in this section, such as using Q-types as receiver
types for `CONSTANT_MethodHandles`. The key requirement, in any case,
is that invokedynamic instructions be able to refer to a full range of
operations on Q-types, since the invokedyanmic instructions are
standing in as temporarily place-holders for bytecodes we are not yet
implementing.
Independently of user-bootstrapped constants, Q-types in the constant
pool might be carried, most gracefully, by variations on the
`CONSTANT_Class` constant. Right now, we choose to mangle type
descriptors in `CONSTANT_Class` constants as an easy-to-implement
place-holder, but the final design could introduce new constant pool
types to carry the required distinctions.
For example, `CONSTANT_Class` could be kept as-is, and re-labeled
`CONSTANT_ReferenceType`. Then, a new `CONSTANT_Type` constant could
support arbitrary descriptors. (Perhaps it would have other
substructure required by reified generic parameters, but that's
probably yet another kind of constant.) Or, a `CONSTANT_ValueType`
tag could be introduced for symmetry with `CONSTANT_ReferenceType`,
and some other way could be found for mentioning primitive
pseudo-classes. (They are useful as parameters to BSMs.)
### Q-replacement within value-capable classes
A value-capable class, compiled from Java source, may have additional
annotations (or perhaps attributes) on selected fields and methods
which cause the introduction of Q-types, as a bytecode-level
transformation when the value-capable class's file is loaded or
compiled.
Two transformations which seem useful may be called _Q-replacement_
and _Q-overloading_. The first deletes L-types and replaces them by
Q-types, while the second simply copies methods, replacing some or all
of the L-types in their descriptors by corresponding Q-types. This
set of ideas is tracked as [JDK-8164889][].
An alternative to annotation-driven Q-replacment would be an
experimental language feature allowing Q-types to be mentioned
directly in Java source. Such experiments are likely to happen
as part of Project Valhalla, and may happen early enough to make
transformation unnecessary.
### More bytecodes
The library method handle `defaultValueConstant` could be replaced by
a new `vnew` bytecode, or by a prefixed `aconst_null` bytecode.
The library method handle `substitutabilityTest` could be replaced by
a new `vcmp` bytecode, or by a prefixed `if_acmpeq` bytecode.
The library method handle `findWither` could be replaced by a new
`vwithfield` bytecode.
The library method handle `findGetter` could be replaced by a suitably
enhanced `getfield` bytecode.
The library method handle `arrayConstructor` could be replaced by a
suitably enhanced `anewarray` or `multianewarray` bytecode.
The library method handle `arrayElementGetter` could be replaced by a
new `vaload` bytecode, or a prefixed `aaload` bytecode.
The library method handle `arrayElementSetter` could be replaced by a
new `vastore` bytecode, or a prefixed `aastore` bytecode.
The library method handle `arrayLength` could be replaced by a
suitably enhanced `arraylength` bytecode.
### Bridge-o-matic
In some cases, supplying Q-replaced API points in classes is just a
matter of providing suitable bridge methods. Bytecode transformers or
generators can avoid the need to specify the bodies of such bridge
methods if the bridges are (instead of bytecodes) endowed with
suitably organized bootstrap methods. This set of ideas has many
additional uses, including auto-generation of standard `equals`,
`hashCode`, and `toString` methods. It is tracked as [JDK-8164891][].
### Heisenboxes
As suggested above, L-types for values are value-based, and some
version of the JVM may attempt to enforce this in various ways, such
as the following:
* Synchronizing a boxed Q-type value may throw an exception like
`IllegalMonitorStateException`.
* Reference comparision (Java operator `==`, or the `acmp`
instruction) may report "true" on two equivalent boxed Q-type
values, even if the references previously returned false, or
"false" when they previously returned "true". Such variation
would of course be subject to the logic of substitutability, of the
underlying Q-types. Two boxes that were once detected as equal
references would be permanently substitutable for each other.
* Attempts to reflectively store values into the fields of boxed
Q-type values may fail, even after `setAccessible` is called.
* Attempts to reflectively invoke the constructor for the box may
fail, even after `setAccessible` is called.
A box whose identity status is uncertain from observation to
observation is called a "heisenbox". To pursue the analogy, a
reference equality (`==`, `acmp`) observation of `true` for two
heisenboxes "collapses" them into the same object, since they are then
proven fully inter-substitutable, hence their Q-values are equivalent
also. Two copies of the reference can later decohere, reporting
inequality, despite the continued inter-substitutability of the boxed
values. The equality predicate could be investigated by wiring it to
a box containing Schrödinger's cat, with many puzzling and sad
results...
This set of ideas is tracked as [JDK-8163133][].
## References
[values]:
[valhalla-dev]:
[goetz-jvmls15]:
[valsem-0411]:
[simms-vbcs]:
[graves-jvmls16]:
[value-based]:
[Long2.java]:
[cimadamore-refman]:
[JDK-8164891]:
[JDK-8161256]:
[JDK-8164889]:
[JDK-8163133]:
\[values]:
\[valhalla-dev]:
\[goetz-jvmls15]:
\[valsem-0411]:
\[simms-vbcs]:
\[graves-jvmls16]:
\[value-based]:
\[goetz-jvmls16]:
\[Long2.java]:
\[cimadamore-refman]:
\[JDK-8164891]:
\[JDK-8161256]:
\[JDK-8164889]:
\[JDK-8163133]:
From john.r.rose at oracle.com Sat Aug 27 05:32:20 2016
From: john.r.rose at oracle.com (John Rose)
Date: Fri, 26 Aug 2016 22:32:20 -0700
Subject: minimal value types proposal
Message-ID: <2B1F10B9-45B6-466D-8D4B-A872DA0A01DB@oracle.com>
Brian and I have been working on finding a minimal subset
of value-type functionality that will allow current experiments
to move forward. Here is what we have come up with.
Please let us know what you think.
? John
P.S. This is a resend with the HTML enclosed. Previous version
had markdown source inline.
Link: http://cr.openjdk.java.net/~jrose/values/shady-values.html
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
From daniel.smith at oracle.com Mon Aug 29 23:17:13 2016
From: daniel.smith at oracle.com (Dan Smith)
Date: Mon, 29 Aug 2016 17:17:13 -0600
Subject: minimal value types proposal
In-Reply-To: <2B1F10B9-45B6-466D-8D4B-A872DA0A01DB@oracle.com>
References: <2B1F10B9-45B6-466D-8D4B-A872DA0A01DB@oracle.com>
Message-ID: <76C94501-BA0C-4833-8ADB-338C6C05C43F@oracle.com>
Some high-level feedback from me:
I think the idea is reasonable. In other circles, we might call this a "milestone". Should we define a first milestone that we're willing to commit to strongly, with some sort of distribution channel (something better than build-your-own-JDK) and some level of support commitment to users who want to get their hands dirty? Sure, absolutely.
There are some design decisions that surprise/confuse me. Basically, this is me saying "YAGNI" over and over again:
1) Automatic boxing adds tons of complexity, and I don't see the benefit. The feature eliminates boilerplate and supports migration, but I'm not looking for either of those in a minimal first step. We're talking about a handful of value types, which can easily be defined like this:
class Val {
public final int i;
public final int j;
public static ValBox box(Val x) { return new ValBox(x); }
public static Val unbox(ValBox b) { return b.x; }
}
class ValBox implements Foo {
public final Val x;
public ValBox(Val x) { this.x = x; }
}
Get rid of boxes, and you can get rid of interfaces, default methods, automatic conversions, constructors, ...
2) Instance methods also add tons of complexity. Again, they only exist for convenience and migration. If static methods can operate on value types, that's all you need. No longer necessary to deal with bytecode written to operate on an L-typed 'this' and somehow re-interpret it for a Q-typed 'this'. No longer necessary to deal with Object methods (because no operation supports invoking them).
(If we really do want instance methods, I suggest making 'this' Q-typed to begin with, not diverting resources into figuring out how to make L-typed instance methods efficient.)
3) The minimal feature set for basic operations -- field getters, default value, withers, comparison, arrays -- is a class (e.g., ValueTypeSupport) with bootstrap methods that can be called via invokedynamic. No need to touch MethodHandles.Lookup, etc.
More generally, why so much attention given to reflection? Sure, you need class objects to represent all the JVM's types. But member lookup? Fields, Methods, Constructors? These do not seem necessary.
If I squint, I can kind of see how the idea is that somebody might want to write reflective code to operate on values, since they don't have language support. But almost everything has to be boxed when using these libraries, which means if you care about performance (which is why you're using this prototype), you're going to be spinning bytecode to do your low-level operations. If this is the use case, I think a better use of resources would be to surface Q types in the language.
4) I don't love hacking CONSTANT_Class to encode new types, but I can probably live with it. My preference is to design it the "right" way -- however we envision these ultimately being expressed -- rather than this intermediate step in which everybody learns to interpret some new syntax, only to turn around and deprecate that syntax a little while later. (I realize it's probably easier to change string formats than it is to add a new constant pool form.)
I don't think it's necessary to support Q types as the receivers of CONSTANT_Fieldrefs and CONSTANT_Methodrefs. The receiver can be a vanilla CONSTANT_Class, and the client (in this case, the 'vgetfield' API point) can figure out what to do with the resolved reference.
?Dan
From john.r.rose at oracle.com Tue Aug 30 00:04:18 2016
From: john.r.rose at oracle.com (John Rose)
Date: Mon, 29 Aug 2016 17:04:18 -0700
Subject: minimal value types proposal
In-Reply-To: <76C94501-BA0C-4833-8ADB-338C6C05C43F@oracle.com>
References: <2B1F10B9-45B6-466D-8D4B-A872DA0A01DB@oracle.com>
<76C94501-BA0C-4833-8ADB-338C6C05C43F@oracle.com>
Message-ID: <143CCD88-8325-45EF-86A5-C34F0FB3BBF6@oracle.com>
On Aug 29, 2016, at 4:17 PM, Dan Smith wrote:
>
> Some high-level feedback from me:
>
> I think the idea is reasonable. In other circles, we might call this a "milestone". Should we define a first milestone that we're willing to commit to strongly, with some sort of distribution channel (something better than build-your-own-JDK) and some level of support commitment to users who want to get their hands dirty? Sure, absolutely.
>
> There are some design decisions that surprise/confuse me. Basically, this is me saying "YAGNI" over and over again:
>
> 1) Automatic boxing adds tons of complexity, and I don't see the benefit. The feature eliminates boilerplate and supports migration, but I'm not looking for either of those in a minimal first step. We're talking about a handful of value types, which can easily be defined like this:
>
> class Val {
> public final int i;
> public final int j;
> public static ValBox box(Val x) { return new ValBox(x); }
> public static Val unbox(ValBox b) { return b.x; }
> }
>
> class ValBox implements Foo {
> public final Val x;
> public ValBox(Val x) { this.x = x; }
> }
>
> Get rid of boxes, and you can get rid of interfaces, default methods, automatic conversions, constructors, ?
It's worth thinking about, and Brian has encouraged me to think about it also.
Boxes (and the other stuff you mention) are so useful that removing them may well cause more trouble than supporting them up front. Inside the JVM, we need a boxed representation for some data flows (unless we make all data flows radically value-safe up front). For the user, a boxed representation is needed for basic debuggability. What does println or JVMTI do unless there's a box?
I do like the idea of requiring the user to set up both classes manually, at first. It has the advantage of making very clear (all too clear) the distinction between the Q-type and the L-type: No source code defines both; the Val guy would (presumably) disable its L-type so people could not use it. (Maybe the JVM would use that for an internal box: But see where that string leads!) Maybe that's the way to go, if the JVM implementation of the single-source-class solution turns out to be difficult.
> 2) Instance methods also add tons of complexity.
I disagree; I think the incremental complexity is comparable to trying to do everything with statics, which is why I'm recommending this in the minimal model.
The only invocation paths for instance methods (and instance fields) on Q-types is through method handles. Method handles treat all arguments (including 'this') symmetrically, so any effort applied to have them work on Q-types *at all* will apply to 'this' parameters for Q-types.
Perhaps you are objecting to the inefficiency of operating on 'this' in the boxed L-type form, when the operation starts as a MH-based invocation of a Q-type? That's only a startup transient; there are several tactics we can use to remove it. For example, box elision (already in the JITs, though not value-friendly yet) would remove boxing overheads without requiring any manual recoding at all.
> Again, they only exist for convenience and migration. If static methods can operate on value types, that's all you need. No longer necessary to deal with bytecode written to operate on an L-typed 'this' and somehow re-interpret it for a Q-typed 'this'. No longer necessary to deal with Object methods (because no operation supports invoking them).
Convenience and migration cannot be driven to zero; that optimizes for "minimal" at the expense of "viable". To preserve viability, there are at least a few really basic conventions, like Object.toString, that would have to be re-encoded using such statics. Re-building virtuals (at least some of the) on top of statics has its own cost, in wasted motion and confusion.
> (If we really do want instance methods, I suggest making 'this' Q-typed to begin with, not diverting resources into figuring out how to make L-typed instance methods efficient.)
Making L-typed instance methods efficient is a sunk cost; it's something the JITs are already good at.
We can and should work towards real Q-typed 'this'. The simplest way is what I'm proposing with the method handle hack. In addition, I suggest experimentally modifying javac to emit two copies of non-static methods in value-capable classes, one with the standard bytecodes, and one as a static (with mangled name) which takes a Q-typed 'this' in local 0. Then teach the method handle resolver to find these guys and bind them, in preference to the boxed-this dance. Users can get on with their business, unaware of all of this.
> 3) The minimal feature set for basic operations -- field getters, default value, withers, comparison, arrays -- is a class (e.g., ValueTypeSupport) with bootstrap methods that can be called via invokedynamic. No need to touch MethodHandles.Lookup, etc.
I don't think the cost of touching MH.Lookup is great, especially given that the MH runtime will have to be able to work with Q-types more or less pervasively. I agree that all the extended lookup functionality could be placed on a new class (alongside findWither etc.), but I don't see any benefit to doing that. Given that we are touching the MH runtime, it's better to put the new stuff in one place. The new class will probably just be a wormhole back in to java.lang.invoke, to call non-public API points (which will eventually be public).
> More generally, why so much attention given to reflection? Sure, you need class objects to represent all the JVM's types. But member lookup? Fields, Methods, Constructors? These do not seem necessary.
Because method handles are where the functionality comes from; you need basic reflection in order to mention the method handles you want. Bytecode spinning is not enough, since that would require us to invent a full bytecode set and implement it. The MH runtime is more malleable than the JVM's interpreter, so we are starting with MHs. Hence the need for MHs.
> If I squint, I can kind of see how the idea is that somebody might want to write reflective code to operate on values, since they don't have language support.
And they don't have bytecode support either. The javac runtime (indy BSMs for vgetfield, etc.) will have to do some of this stuff too.
> But almost everything has to be boxed when using these libraries, which means if you care about performance (which is why you're using this prototype), you're going to be spinning bytecode to do your low-level operations.
Not completely. The bytecode will use MHs or indy do low-level stuff.
> If this is the use case, I think a better use of resources would be to surface Q types in the language.
Yes, surface them, but don't require a full set of bytecodes to operate on them. That's the slow way to do it.
> 4) I don't love hacking CONSTANT_Class to encode new types, but I can probably live with it. My preference is to design it the "right" way -- however we envision these ultimately being expressed -- rather than this intermediate step in which everybody learns to interpret some new syntax, only to turn around and deprecate that syntax a little while later. (I realize it's probably easier to change string formats than it is to add a new constant pool form.)
Yes, that's why we are starting this way. CONSTANT_Class CP entries get overloaded; a bunch of other legacy API points get overloaded. It's an expedient when the data flows in and out of the APIs can be augmented more easily than we can invent new API points. But (as the shady-values document says several times) the final API is likely to be different, and in particular to make the new distinctions in more principled ways.
> I don't think it's necessary to support Q types as the receivers of CONSTANT_Fieldrefs and CONSTANT_Methodrefs. The receiver can be a vanilla CONSTANT_Class, and the client (in this case, the 'vgetfield' API point) can figure out what to do with the resolved reference.
Yes, that's one way to go. But representing Q-types as java.lang.Class objects will be a sunk cost, so passing the L/Q distinction through existing data flows (on "overloaded" API points) is a reasonable design pattern, for a prototype.
I also think (in this case) the Lookup API will, in the long term, look something like the current sketch; there won't be a separate Lookup.findValueGetter any more than there is a separate Lookup.findInterfaceVirtual.
? John
From daniel.smith at oracle.com Tue Aug 30 17:56:45 2016
From: daniel.smith at oracle.com (Dan Smith)
Date: Tue, 30 Aug 2016 11:56:45 -0600
Subject: minimal value types proposal
In-Reply-To: <143CCD88-8325-45EF-86A5-C34F0FB3BBF6@oracle.com>
References: <2B1F10B9-45B6-466D-8D4B-A872DA0A01DB@oracle.com>
<76C94501-BA0C-4833-8ADB-338C6C05C43F@oracle.com>
<143CCD88-8325-45EF-86A5-C34F0FB3BBF6@oracle.com>
Message-ID:
> On Aug 29, 2016, at 6:04 PM, John Rose wrote:
>
> On Aug 29, 2016, at 4:17 PM, Dan Smith wrote:
>>
>> Get rid of boxes, and you can get rid of interfaces, default methods, automatic conversions, constructors, ?
>
> It's worth thinking about, and Brian has encouraged me to think about it also.
>
> Boxes (and the other stuff you mention) are so useful that removing them may well cause more trouble than supporting them up front. Inside the JVM, we need a boxed representation for some data flows (unless we make all data flows radically value-safe up front).
By all means, let your encoding of a Q-typed instance be an object pointer. I'm just talking about the user's interface with the declaration.
> For the user, a boxed representation is needed for basic debuggability. What does println or JVMTI do unless there's a box?
One option is that JVMTI knows about value types, as it does primitives, and provides a printout of the fields. Or maybe ValueTypeSupport has a debugString operation that does this.
Or we use a naming convention -- value types are expected to provide 'toString', and/or 'box'. (I don't mind the boxes themselves, just the automatic aspect of them.)
> I do like the idea of requiring the user to set up both classes manually, at first. It has the advantage of making very clear (all too clear) the distinction between the Q-type and the L-type: No source code defines both; the Val guy would (presumably) disable its L-type so people could not use it.
Yes, that's what I have in mind.
>> 2) Instance methods also add tons of complexity.
>
> I disagree; I think the incremental complexity is comparable to trying to do everything with statics, which is why I'm recommending this in the minimal model.
>
> The only invocation paths for instance methods (and instance fields) on Q-types is through method handles. Method handles treat all arguments (including 'this') symmetrically, so any effort applied to have them work on Q-types *at all* will apply to 'this' parameters for Q-types.
It's a given that you have statics (see your Int128 declaration, for example). If instance methods are practically free after that, fine. But if not, there's no particular reason to support them. We don't have polymorphism (for Q types, anyway -- I'm assuming no automatic boxes, per (1)), and it's just as easy -- easier, in fact -- for a client to do "invokestatic Val.m(QVal;)I" as it is to do "invokedynamic [vinvoke ...]".
> Perhaps you are objecting to the inefficiency of operating on 'this' in the boxed L-type form, when the operation starts as a MH-based invocation of a Q-type? That's only a startup transient; there are several tactics we can use to remove it. For example, box elision (already in the JITs, though not value-friendly yet) would remove boxing overheads without requiring any manual recoding at all.
Yeah, this is one of the big things that jumps out at me. Our end goal is to define instance methods with a Q-typed 'this'. Having an intermediate step of instance methods with an L-typed 'this' doesn't seem productive. Yeah, there's some engineering we may want to do anyway to get default methods with L-typed 'this' to be efficient, but I'd prefer to keep that engineering off of the critical path. Write your bytecode with a Q-typed 'this' (or static, with no 'this' at all), and we don't have to hope that the JIT will optimize.
> Convenience and migration cannot be driven to zero; that optimizes for "minimal" at the expense of "viable". To preserve viability, there are at least a few really basic conventions, like Object.toString, that would have to be re-encoded using such statics.
As I commented above, I'm not opposed to naming conventions that ensure a 'toString' or 'box' method exists. And if you're invoking Object.toString, you're first going to have to box, anyway. It's just as easy to do "invokestatic Val.box(QVal;)LObject;" as it is to do "invokedynamic [asType ...]".
> Re-building virtuals (at least some of the) on top of statics has its own cost, in wasted motion and confusion.
I'd like to understand this better. You're talking about the confusion involved with training people to invoke static methods, only to tell them later that they can use instance methods, too?
> We can and should work towards real Q-typed 'this'. The simplest way is what I'm proposing with the method handle hack. In addition, I suggest experimentally modifying javac to emit two copies of non-static methods in value-capable classes, one with the standard bytecodes, and one as a static (with mangled name) which takes a Q-typed 'this' in local 0. Then teach the method handle resolver to find these guys and bind them, in preference to the boxed-this dance. Users can get on with their business, unaware of all of this.
javac doesn't generate value classes at all (at least in the first cut). That aside, yes, any scheme in which a Q-typed 'this' is expressed directly is an improvement in my book.
>> 3) The minimal feature set for basic operations -- field getters, default value, withers, comparison, arrays -- is a class (e.g., ValueTypeSupport) with bootstrap methods that can be called via invokedynamic. No need to touch MethodHandles.Lookup, etc.
>
> I don't think the cost of touching MH.Lookup is great, especially given that the MH runtime will have to be able to work with Q-types more or less pervasively. I agree that all the extended lookup functionality could be placed on a new class (alongside findWither etc.), but I don't see any benefit to doing that.
Okay, cool. I suppose my main discomfort is that, if we embed behavior in existing APIs, it's easier to overlook that change later and forget to put the proper design & specification effort into it. Things get baked in just because they're already there. But if we can avoid that problem, great.
>> More generally, why so much attention given to reflection? Sure, you need class objects to represent all the JVM's types. But member lookup? Fields, Methods, Constructors? These do not seem necessary.
>
> Because method handles are where the functionality comes from; you need basic reflection in order to mention the method handles you want. Bytecode spinning is not enough, since that would require us to invent a full bytecode set and implement it. The MH runtime is more malleable than the JVM's interpreter, so we are starting with MHs. Hence the need for MHs.
I'm unfairly lumping two things together.
java.lang.reflect: We need java.lang.Class objects that represent value types. Beyond that, I don't see any point in touching this API. Eventually, sure. Not in the first cut. (For example: Class.getMethod can behave just like it does for primitives, throwing NSME. Or just operating on statics. And we certainly don't need to put any effort into a special-purpose Constructor.newInstance method.)
java.lang.invoke: Accept Q-typed values as inputs/outputs? Yes. Most of the rest of your proposed changes make sense to me, subject to the discussion above (maybe no box/unbox conversions; maybe no instance methods). I wouldn't bother with findConstructor on a Q type.
>> If I squint, I can kind of see how the idea is that somebody might want to write reflective code to operate on values, since they don't have language support.
>
>> If this is the use case, I think a better use of resources would be to surface Q types in the language.
>
> Yes, surface them, but don't require a full set of bytecodes to operate on them. That's the slow way to do it.
Sure, absolutely. I definitely buy into the idea that we need enough support in java.lang.invoke to provide library-defined operations, rather than having to introduce new opcodes.
>> I don't think it's necessary to support Q types as the receivers of CONSTANT_Fieldrefs and CONSTANT_Methodrefs. The receiver can be a vanilla CONSTANT_Class, and the client (in this case, the 'vgetfield' API point) can figure out what to do with the resolved reference.
>
> Yes, that's one way to go. But representing Q-types as java.lang.Class objects will be a sunk cost, so passing the L/Q distinction through existing data flows (on "overloaded" API points) is a reasonable design pattern, for a prototype.
My thinking is that, for example, I'd rather not touch method resolution at all. Maybe that saves us some work. (And as I've thought about the ultimate bytecode design, I'm leaning that way as the ultimate solution, meaning maybe less work to undo things later.)
> I also think (in this case) the Lookup API will, in the long term, look something like the current sketch; there won't be a separate Lookup.findValueGetter any more than there is a separate Lookup.findInterfaceVirtual.
Yeah, that makes sense. The inputs to these methods are Class objects, so you'll have the extra type information you need.
?Dan