----- Original Message ----- > From: "Dan Heidinga" <heidi...@redhat.com> > To: "Brian Goetz" <brian.go...@oracle.com> > Cc: "valhalla-spec-experts" <valhalla-spec-experts@openjdk.java.net> > Sent: Wednesday, April 27, 2022 8:51:15 PM > Subject: Re: User model stacking
> I'm trying to understand how this refactoring fits the VM physics. > > In particular, __non-atomic & __zero-ok fit together at the VM level > because the VM's natural state for non-atomic (flattened) data is zero > filled. When those two items are decoupled, I'm unclear on what the > VM would offer in that case. Thoughts? __non-atomic but ! __zero-ok means you have an additional bit that indicate if it's null or not. from the VM POV, fields are still zero filled but you have a way to encode null. > > How does "__non-atomic __non-id class B2a { }" fit with the "no new > nulls" requirements? For me, i may be wrong, the "no new nulls" requirements is from the POV of the language / user, not from the POV of the VM. The VM may have several encodings of null internally. > > --Dan Rémi > > On Wed, Apr 27, 2022 at 12:45 PM Brian Goetz <brian.go...@oracle.com> wrote: >> >> Here’s some considerations for stacking the user model. (Again, please let’s >> resist the temptation to jump to the answer and then defend it.) >> >> We have a stacking today which says: >> >> - B1 is ordinary identity classes, giving rise to a single reference type >> - B2 are identity-free classes, giving rise to a single reference type >> - B3 are flattenable identity-free classes, giving rise to both a reference >> (L/ref) and primitive (Q/val) type. >> >> This stacking has some pleasant aspects. B2 differs from B1 by “only one >> bit”: >> identity. The constraints on B2 are those that come from the lack of >> identity >> (mutability, extensibility, locking, etc.) B2 references behave like the >> object references we are familiar with; nullability, final field guarantees, >> etc. B3 further makes reference-ness optional; reference-free B3 values give >> up the affordances of references: they are zero-default and tearable. This >> stacking is nice because it can framed as a sequence of “give up some X, get >> some Y”. >> >> People keep asking “do we need B2, or could we get away with B1/B3”. The >> main >> reason for having this distinction is that some id-free classes have no >> sensible default, and so want to use null as their default. This is a >> declaration-site property; B3 means that the zero value is reasonable, and >> use >> sites can opt into / out of zero-default / nullity. We’d love to compress >> away this bucket but forcing a zero on classes that can’t give it a >> reasonable >> interpretation is problematic. But perhaps we can reduce the visibility of >> this in the model. >> >> The degrees of freedom we could conceivably offer are >> >> { identity or not, zero-capable or not, atomic or not } x { use-site, >> declaration-site } >> >> In actuality, not all of these boxes make sense (disavowing the identity of >> an >> ArrayList at the use site), and some have been disallowed by the stacking >> (some >> characteristics have been lumped.) Here’s another way to stack the >> declaration: >> >> - Some classes can disavow identity >> - Identity-free classes can further opt into zero-default (currently, B3, >> polarity chosen at use site) >> - Identity-free classes can further opt into tearability (currently, B3, >> polarity chosen at use site) >> >> It might seem the sensible move here is to further split B3 into B3a and B3b >> (where all B3 support zero default, and a/b differ with regard to whether >> immediate values are tearable). But that may not be the ideal stacking, >> because we want good flattening for B2 (and B3.ref) also. Ideally, the >> difference between B2 and B3.val is nullity only (Kevin’s antennae just went >> up.) >> >> So another possible restacking is to say that atomicity is something that >> has to >> be *opted out of* at the declaration site (and maybe also at the use site.) >> With deliberately-wrong syntax: >> >> __non-id class B2 { } >> >> __non-atomic __non-id class B2a { } >> >> __zero-ok __non-id class B3 { } >> >> __non-atomic __zero-ok __non-id class B3a { } >> >> In this model, you can opt out of identity, and then you can further opt out >> of >> atomicity and/or null-default. This “pulls up” the atomicity/tearaiblity to >> a >> property of the class (I’d prefer safe by default, with opt out), and makes >> zero-*capability* an opt-in property of the class. Then for those that have >> opted into zero-capability, at the use site, you can select .ref (null) / >> .val >> (zero). Obviously these all need better spellings. This model frames >> specific >> capabilities as modifiers on the main bucket, so it could be considered >> either >> a two bucket, or a four bucket model, depending on how you look. >> >> The author is in the best place to make the atomicity decision, since they >> know >> the integrity constraints. Single field classes, or classes with only single >> field invariants (denominator != 0), do not need atomicity. Classes with >> multi-field invariants do. >> >> This differs from the previous stacking in that it moves the spotlight from >> _references_ and their properties, to the properties themselves. It says to >> class writers: you should declare the ways in which you are willing to trade >> safety for performance; you can opt out of the requirement for references and >> nulls (saving some footprint) and atomicity (faster access). It says to >> class >> *users*, you can pick the combination of characteristics, allowed by the >> author, that meet your needs (can always choose null default if you want, >> just >> use a ref.) >> >> There are many choices here about “what are the defaults”. More opting in at >> the declaration site might mean less need to opt in at the use site. Or not. >> >> (We are now in the stage which I call “shake the box”; we’ve named all the >> moving parts, and now we’re looking for the lowest-energy state we can get >> them >> into.)