Re: Proposal: Static/final constructors for bucket-3 primitive classes.

2021-12-08 Thread Remi Forax
> From: "John Rose" 
> To: "Brian Goetz" 
> Cc: "valhalla-spec-experts" , "clement
> cherlin" 
> Sent: Thursday, December 9, 2021 5:30:50 AM
> Subject: Re: Proposal: Static/final constructors for bucket-3 primitive 
> classes.

> We have considered, at various points in the last six years or more, allowing
> user-defined primitive types to define (under user control) their own default
> values. The syntax is unimportant, but the concept is simple: Surely the user
> who defines a primitive type can also define default initializer expressions
> for each of the fields.

> But this would be a trail of tears, which we have chosen to avoid, each time 
> the
> suggestion comes up.

> This feature is often visualized as a predefined bit pattern, which the JVM
> would keep handy, and just stamp down wherever a default initializer is 
> needed.
> It’s can’t really be that simple, but even such a bit pattern is problematic.

> First of all is the problem of declaring the bit pattern. Java natively uses 
> the
> side effects of  to define constants using ad hoc bytecodes; it also
> defines (for some types but not others) a concept of constant expression.
> Neither of those fits well into a classfile that would define a primitive with
> a default bit pattern.

> If the bit pattern is defined using ad hoc bytecode, it must be defined in a 
> new
> pseudo-method (not  ), to execute not during the initialization of the
> newly-declared primitive class, but before . (Surely not! a reader might
> exclaim, but this is the sort of subtlety we have to deal with.) During
> initialization of a class C, all fields of its own type C must be initialized
> before the first bytecode of  executes, so that the static initializer
> code has something to write on. So there must be a “default value definition”
> phase, call it  , added after linking and before
> initialization of C, so C’s  method has something to work with. This
>  is really the body of a no-argument constructor of C, or 
> its
> twin. A no-argument constructor of C is not a problem, but having it execute
> before C’s  block is a huge irregularity, which the JVM spec is not
> organized to support, at present.

> This would turn into both JVMS and JLS spec. complexity, and more odd corners
> (and odd states) in the Java user experience. Sure, a user will say, “but I
> promise not to do anything odd; I just want this field to be the value (int)1
> ”. Yes, but a spec. must define not only the expected usages, but all possible
> usages, with no poorly-defined states.

> OK, so if  is not the place to define to define this elusive
> bit pattern, what about something more declarative, like a ConstantValue
> attribute? Surely we could put a similarly structured DefaultValue attribute 
> on
> every non-static field of a value type, and that would give the JVM enough
> information to synthesize the required bit pattern before it runs  .

> Consider the user model here: A primitive declaration would allow its fields 
> to
> have non-zero default values, but only drawn from the restricted set of
> constant expressions , because those are the ones which fit in the
> ConstantValue attribute. (They are true bit patterns in the constant pool, 
> plus
> String constants.) There is no previous place in Java where we make such a
> restriction, except case labels. Can you hear the groans of users as we try to
> explain why only constant expressions are allowed in that context? That’s the
> muzak of the trail of tears I mentioned above.

> But we have condy to fix that (someone will surely say).

you read my mind :) 

> But that’s problematic, because the resolution of constant pool constants of a
> class C requires C to be at least linked, and if the condy expression makes a
> self-reference to C itself, that will trigger C’s initialization, at an 
> awkward
> moment. Have you ever debugged a tangled initialization circularity, marked by
> mysterious NPEs on variables you know you initialized? I have. It’s a stop on
> the trail of tears I mentioned.

> But if we really worked hard, and added a bunch of stuff to the JVMS and JLS,
> and persuaded users not to bother us about the odd restrictions (to constant
> expressions, or expressions which “don’t touch the class itself”), we could
> define some sort of declarative default value initialization.

> What then? Well, ask the JVM engineers how they initialize heap variables,
> because those are the affected paths. Those parts of the JVM are among the 
> most
> performance-sensitive. Currently, when a new object or array is created, its
> whole body (except the header) is sprayed with a nice even coat of 
> all-zero-bit
> machine words. This is pretty fast, and it’s important to keep it fast. What 
> if
> creating an array required painting some beautifully crafted arabesque of a 
> bit
> pattern defined by a creative user? Well, it’s doable, but much more
> complicated. You need to load the bit pattern into live registers and (if it’s
> an 

Re: Proposal: Static/final constructors for bucket-3 primitive classes.

2021-12-08 Thread John Rose
We have considered, at various points in the last six years or more, 
allowing user-defined primitive types to define (under user control) 
their own default values.  The syntax is unimportant, but the concept is 
simple:  Surely the user who defines a primitive type can also define 
default initializer expressions for each of the fields.


But this would be a trail of tears, which we have chosen to avoid, each 
time the suggestion comes up.


This feature is often visualized as a predefined bit pattern, which the 
JVM would keep handy, and just stamp down wherever a default initializer 
is needed.  It’s can’t really be that simple, but even such a bit 
pattern is problematic.


First of all is the problem of declaring the bit pattern.  Java natively 
uses the side effects of `` to define constants using ad hoc 
bytecodes; it also defines (for some types but not others) a concept of 
constant expression.  Neither of those fits well into a classfile that 
would define a primitive with a default bit pattern.


If the bit pattern is defined using ad hoc bytecode, it must be defined 
in a new pseudo-method (not ``), to execute not *during* the 
initialization of the newly-declared primitive class, but *before*.  
(Surely not! a reader might exclaim, but this is the sort of subtlety we 
have to deal with.)  During initialization of a class C, all fields of 
its own type C must be initialized *before* the first bytecode of 
`` executes, so that the static initializer code has something 
to write on.  So there must be a “default value definition” phase, 
call it ``, added after linking and before 
initialization of C, so C’s `` method has something to work 
with.  This `` is really the body of a no-argument 
constructor of C, or its twin.  A no-argument constructor of C is not a 
problem, but having it execute before C’s `` block is a huge 
irregularity, which the JVM spec is not organized to support, at 
present.


This would turn into both JVMS and JLS spec. complexity, and more odd 
corners (and odd states) in the Java user experience.  Sure, a user will 
say, “but I promise not to do anything odd; I just want *this field* 
to be the value `(int)1`”.  Yes, but a spec. must define not only the 
expected usages, but all possible usages, with no poorly-defined states.


OK, so if `` is not the place to define to define this 
elusive bit pattern, what about something more declarative, like a 
`ConstantValue` attribute?  Surely we could put a similarly structured 
`DefaultValue` attribute on every non-static field of a value type, and 
that would give the JVM enough information to synthesize the required 
bit pattern *before* it runs ``.


Consider the user model here:  A primitive declaration would allow its 
fields to have non-zero default values, *but only drawn from the 
restricted set of constant expressions*, because those are the ones 
which fit in the `ConstantValue` attribute.  (They are true bit patterns 
in the constant pool, plus `String` constants.)  There is no previous 
place in Java where we make such a restriction, except `case` labels.  
Can you hear the groans of users as we try to explain why only constant 
expressions are allowed in that context?  That’s the muzak of the 
trail of tears I mentioned above.


But we have condy to fix that (someone will surely say).  But that’s 
problematic, because the resolution of constant pool constants of a 
class C requires C to be at least linked, and if the condy expression 
makes a self-reference to C itself, that will trigger C’s 
initialization, at an awkward moment.  Have you ever debugged a tangled 
initialization circularity, marked by mysterious NPEs on variables you 
*know* you initialized?  I have.  It’s a stop on the trail of tears I 
mentioned.


But if we really worked hard, and added a bunch of stuff to the JVMS and 
JLS, and persuaded users not to bother us about the odd restrictions (to 
constant expressions, or expressions which “don’t touch the class 
itself”), we *could* define some sort of declarative default value 
initialization.


What then?  Well, ask the JVM engineers how they initialize heap 
variables, because those are the affected paths.  Those parts of the JVM 
are among the most performance-sensitive.  Currently, when a new object 
or array is created, its whole body (except the header) is sprayed with 
a nice even coat of all-zero-bit machine words.  This is pretty fast, 
and it’s important to keep it fast.  What if creating an array 
required painting some beautifully crafted arabesque of a bit pattern 
defined by a creative user?  Well, it’s doable, but much more 
complicated.  You need to load the bit pattern into live registers and 
(if it’s an array of C) keep them live while you paint the whole 
array.  That’s got to be more expensive than spraying zeroes.  
(There’s even hardware that’s good for spraying zeroes, on some 
machines.)  Basically, if we generously allowed users even a limited set 
of pre-defined default