> On Apr 19, 2023, at 3:51 PM, John Rose <[email protected]> wrote:
> 
> “Stamping out” zeroes is fundamentally simpler to do than “stamping out” some 
> other pattern. Especially managed references: If you “stamp out” GC-managed 
> references, you have to have a store-barrier conversation with the GC at each 
> reference, if the GC is designed that way. This factor all by itself will 
> slow array creation down, no matter what other design decisions are taken.


> In any case, array creation performance is likely to take some kind of 
> performance hit. The issue is that a every array type will have to store the 
> bit pattern to “stamp out” when creating an array that has an element class 
> with a non-zero default. One might think that this is a pay-as-you go 
> feature, incurring cost only to classes which default non-zero defaults, but 
> that it not completely true. There are places in the JVM and JDK where arrays 
> (and other objects) are created from dynamically selected types. Such places 
> are likely to need a new slow-path branch to handle the possibility that the 
> selected type requires special special handling for a non-zero default. Tests 
> and branches are cheap but it cannot be assumed that they are free.

> As noted above, managed references are a particularly difficult cost to 
> control, whe considering the initialization of non-zero defaults, 
> particularly for arrays. It is somewhat dispiriting to contemplate a flurry 
> of GC activity to create the default state of an array, immediately followed 
> by a copy of non-default values, initiating a second flurry on the same 
> locations. One might avoid this particular problem by allowing only primitive 
> values to be “stamped out”, but that reduces the utility of a user-defined 
> default, and forces users into workarounds anyway.

This discussion about arrays should acknowledge that we *do*, in fact, "stamp 
out" non-zero pointers to default instances when the class has been deemed 
unsuitable for flattening. At an implementation level, there are 3 kinds of 
value classes and !-typed value class arrays:

1) The happy case that we'll flatten, in which case the array stores a bunch of 
zeros

2) Value classes that are too big or atomic (or maybe fail some other 
criteria?) and so won't be flattened, in which the array stores a repeated 
non-zero pointer (an alternative strategy would check for null on read and swap 
in the pointer; that's what happens with fields)

3) Value classes that don't have a default instance, in which case the array 
stores a bunch of nulls and the '!' is erased (an alternative VM design would 
check for null on read and throw)

We can argue that case (1) is expecting the best performance, so in that case 
we don't want to do anything to slow down its array allocations, but I think 
it's fair to say that examples of case (1) wouldn't mind the trade-off of 
moving into case (2) and getting a custom default value instead—especially when 
their alternative workaround is to move into case (3) instead.

(I'm not advocating for this outcome, just critiquing the argument.)

>     • Also, the all-zero value will be visible in some states, even though we 
> are trying to make it disappear. At least while initial field initializers 
> are executed, and probably at other times as well. That will lead to 
> confusion.

Because of case (2), this should never happen (although we've had to do extra 
work in order to properly hide the null pointer in case (2)).

>     • The simplest workaround is not to expose the default value. Allow null 
> to be the default value of your class, just as with all pre-Valhalla classes. 
> The standard workarounds for the null value apply in all cases. Valhalla can 
> succeed even if it doesn’t fully solve all problems with null.

I'd add some acknowledgement of the role '!' has here, and refine the 
analogy—instead of "allow null to be the default value of your class", you mean 
"don't give the class a default instance". Then your '!' types operate in case 
(3) instead of case (1) or (2), and the arrays store null. (Your nullable type, 
meanwhile, continues to have '!' as its default value.)

Reply via email to