User model stacking: current status
Brian Goetz
brian.goetz at oracle.com
Tue Jun 14 19:18:39 UTC 2022
On 6/14/2022 2:54 PM, Dan Heidinga wrote:
>> But (and there's a whole conversation to be had here) it does mean that
>> there is separate access control on LFoo vs QFoo,
> Pulling on this thread a little, is it the class that has different
> access control or something else?
We've meandered a bit over the years on the distinction between the
class Foo, the types Foo.ref and Foo.val, and their respective mirrors.
It's probably time for a check-in on where we are there.
Today, Integer is a class, with a full-power mirror Integer.class; int
is a type, with a limited mirror int.class, whose job is mostly limited
to reflecting over field and method descriptors.
With Valhalla, Point is a class, with types Point.ref and Point.val;
Point.class is a full-power mirror for Point.ref, and Point.val.class is
a limited mirror that is analogous to the int mirror. If you ask a
Point for its getClass(), it always returns Point.class. It would not
bother me if the Point.val.class mirror is fully limited, and the only
way to do lookups (e.g., getMethods) is to switch over to the class
mirror (for which we'd probably have a `Class::getPrimaryClass` method.)
Having the two encode separate accessibilities sounds a little messy,
but the various Lookup::checkAccess methods key off of a Class, so that
seems a reasonable place to hang this information. I would assume such
checks would check both the primary class and then the secondary class,
or we'd arrange that the primary mirror always was at least as
accessible as the secondary mirror. (Protected isn't a useful option,
and public/package/private are suitably ordered.)
At the language level, there is a question about how to present the val
class. One obvious (but possibly bad) idea is to pretend it is a
special kind of nested class (which is supported by the Point.val naming
convention):
value class Rational {
private class val { }
}
This is a little cheesy, but may fit mostly cleanly into user's mental
models. In this case, the accessibility is going on something that
looks like a class declaration at the source level, and which has a
class mirror at the VM level, but it really a "shadow class", just like
the class described by int.class (or String[].class.) This might be OK.
At one point I considered whether we could hang this on the
accessibility of the no-arg constructor, but I quickly soured on this
idea. But that has an accessibility too.
Or we could invent a new kind of member, to describe the val projection,
and hang accessibility on that.
> To create an identity object, we do access control on the both class
> (public/package) and the constructor (public/package/private (aka
> nest)).
> To create a value object, we do nest mate access control (aka private)
> on the bytecodes that create values (aconst_init / withfield). This
> proposal extends the nest mates access check to the default values of
> Qs.
It's not just nestmate access control; it would be reasonable to declare
the val as package-access, and trust your package mates too.
> In both cases, we're looking at the access control of two things - the
> class and the "creator of instances". Are we applying different
> access control to LFoo vs QFoo, or to construction mechanisms?
The thing we're trying to protect is creation of uninitialized
heap-based instances. But it felt a little weird to draw such a complex
line; seemed simpler (and not giving up much) to access-control the type
name. But we can explore this some more. Maybe we are
access-controlling the `defaultvalue` bytecode, since its effectively
public if someone can create a flat array.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-spec-observers/attachments/20220614/f37978a3/attachment.htm>
More information about the valhalla-spec-observers
mailing list