Re: null checks vs. class resolution, and translation strategy for casts

2020-04-14 Thread forax
> De: "Brian Goetz" 
> À: "Remi Forax" 
> Cc: "Frederic Parain" , "valhalla-spec-experts"
> 
> Envoyé: Mardi 14 Avril 2020 15:56:06
> Objet: Re: null checks vs. class resolution, and translation strategy for 
> casts

>> How it is better than a new opcode "unbox" with exactly the same semantics ?

> For one, an “unbox” opcode assumes that the VM understands the fictitious
> relationship between the val and ref projections. But these are language
> fictions; the VM sees only classes related by extension and sealing.

No, 
your assuming that the semantics of unbox implies that the verifier will check 
for 'sealness', this is not the case, unbox <==> checkcast restricted to inline 
type (so with eager loading). 

You're free to unbox an Object to a Point, by example. 

Rémi 


Re: null checks vs. class resolution, and translation strategy for casts

2020-04-14 Thread Brian Goetz
Then it’s a terrible and confusing name for an opcode :)



> On Apr 14, 2020, at 10:08 AM, fo...@univ-mlv.fr wrote:
> 
> 
> 
> De: "Brian Goetz" 
> À: "Remi Forax" 
> Cc: "Frederic Parain" , "valhalla-spec-experts" 
> 
> Envoyé: Mardi 14 Avril 2020 15:56:06
> Objet: Re: null checks vs. class resolution, and translation strategy for 
> casts
> 
> How it is better than a new opcode "unbox" with exactly the same semantics ?
> 
> For one, an “unbox” opcode assumes that the VM understands the fictitious 
> relationship between the val and ref projections.  But these are language 
> fictions; the VM sees only classes related by extension and sealing.
> 
> No,
> your assuming that the semantics of unbox implies that the verifier will 
> check for 'sealness', this is not the case, unbox <==> checkcast restricted 
> to inline type (so with eager loading).
> 
> You're free to unbox an Object to a Point, by example.
> 
> Rémi
> 



Re: null checks vs. class resolution, and translation strategy for casts

2020-04-14 Thread Brian Goetz
> 
> How it is better than a new opcode "unbox" with exactly the same semantics ?

For one, an “unbox” opcode assumes that the VM understands the fictitious 
relationship between the val and ref projections.  But these are language 
fictions; the VM sees only classes related by extension and sealing.

Re: null checks vs. class resolution, and translation strategy for casts

2020-04-13 Thread Remi Forax
- Mail original -
> De: "Frederic Parain" 
> À: "valhalla-spec-experts" 
> Envoyé: Lundi 13 Avril 2020 15:24:18
> Objet: Re: null checks vs. class resolution, and translation strategy for 
> casts

>> On Apr 8, 2020, at 14:43, John Rose  wrote:
>> 
>> I have a proposal for a translation strategy:
>> 
>> 1. Translate casts to inline classes differently from “classic”
>> casts.  Add an extra step of null hostility.  For very low-level
>> reasons, I suggest using “ldc X” followed by Class::cast.
>> 
>> Generally speaking, it’s a reasonable move to use reflective
>> API points (like Class::cast) on constant metadata (like X.class)
>> to implement language semantics.
> 
> 
> There’s an alternative way to implement this:
> 
> Casts to inline classes C can be translated to
>#ldc C
>#checkcast C
> 
> with this new definition of checkast:
> 
> "If objectref is null then:
>   - if type C has not been loaded yet, the operand stack is unchanged,
>   - if type C has already been loaded:
>   - if type C is not an inline type, the operand stack is unchanged
>   - otherwise the checkcast instruction throws a ClassCastException

so it's more:
   #ldc C
   #checkcast 0<---

> 
> Otherwise, the named class, array, or interface type is resolved (§5.4.3.1). 
> If
> objectref can be cast to the resolved class, array, or interface type, the
> operand stack is unchanged; otherwise, the checkcast instruction throws a
> ClassCastException."
> 
> 
> This new definition doesn’t change the behavior of checkcast for old class
> files,
> and doesn’t change the behavior nor the translation strategy for casts to
> non-inline types.
> 
> In new class files, javac will use the ldc/checkcast sequence whenever a cast 
> to
> an
> inline type is required. Note that in many cases, type C would have already be
> loaded
> before ldc is executed (by pre-loading or eager loading).
> 
> With migrated types, an old class file can still have a standalone checkcast
> (without ldc)
> referencing a type which is now an inline type, causing the null reference to
> pass the checkcast
> successfully. This is not a new issue. The same situation can be created by
> reading a field
> declared as ‘LC;’, getfield would simply read the field (only possible value 
> is
> null) and push
> it on the stack without checking if C is an inline type or not. This ’null’
> reference to an
> invalid type can only be used by code that have the wrong information about 
> type
> C, and this
> is in fact the only possible value for this type (any attempt to create a real
> instance of
> ‘LC;’ would fail). In order to use this reference as a legitimate reference to
> the real
> type ‘QC;’, another checkcast, using the proper sequence above, would be
> required and would
> throw an exception.
> 
> Ill formed or malicious class files could be aware that C is an inline type, 
> but
> use a
> single checkcast instruction (without preceding ldc) anyway. This is part of a
> bigger
> problem that has not been discussed yet: L/Q consistency inside a class file.
> the SoV
> document stipules that the value projection only exists in the Q-form and the
> reference
> projection only exists in the L-form. As of today, there’s no verification of
> such kind
> performed on class files. Nothing prevent a class file from declaring a field 
> of
> type
> ‘LC;’ and another of type ‘QC;’, and the same remark applies to method
> arguments.
> 
> 
> Going back to the modified specification of checkcast, new tests are easy to
> implement
> in the interpreter, and can easily be optimized by JIT compilers (most types
> would be
> loaded at compilation time), and there’s no bootstrapping issues.
>

How it is better than a new opcode "unbox" with exactly the same semantics ?
 

> Fred

Rémi


Re: null checks vs. class resolution, and translation strategy for casts

2020-04-13 Thread Brian Goetz





There’s an alternative way to implement this:

Casts to inline classes C can be translated to
 #ldc C
 #checkcast C


And, the ldc can be hoisted statically if desired, to the top of the 
method, or even into a static initializer.




Re: null checks vs. class resolution, and translation strategy for casts

2020-04-13 Thread Frederic Parain



> On Apr 8, 2020, at 14:43, John Rose  wrote:
> 
> I have a proposal for a translation strategy:
> 
> 1. Translate casts to inline classes differently from “classic”
> casts.  Add an extra step of null hostility.  For very low-level
> reasons, I suggest using “ldc X” followed by Class::cast.
> 
> Generally speaking, it’s a reasonable move to use reflective
> API points (like Class::cast) on constant metadata (like X.class)
> to implement language semantics.


There’s an alternative way to implement this:

Casts to inline classes C can be translated to
#ldc C
#checkcast C

with this new definition of checkast:

"If objectref is null then:
   - if type C has not been loaded yet, the operand stack is unchanged,
   - if type C has already been loaded:
   - if type C is not an inline type, the operand stack is unchanged
   - otherwise the checkcast instruction throws a ClassCastException

Otherwise, the named class, array, or interface type is resolved (§5.4.3.1). If 
objectref can be cast to the resolved class, array, or interface type, the 
operand stack is unchanged; otherwise, the checkcast instruction throws a 
ClassCastException."


This new definition doesn’t change the behavior of checkcast for old class 
files,
and doesn’t change the behavior nor the translation strategy for casts to 
non-inline types.

In new class files, javac will use the ldc/checkcast sequence whenever a cast 
to an
inline type is required. Note that in many cases, type C would have already be 
loaded
before ldc is executed (by pre-loading or eager loading).

With migrated types, an old class file can still have a standalone checkcast 
(without ldc)
referencing a type which is now an inline type, causing the null reference to 
pass the checkcast
successfully. This is not a new issue. The same situation can be created by 
reading a field
declared as ‘LC;’, getfield would simply read the field (only possible value is 
null) and push
it on the stack without checking if C is an inline type or not. This ’null’ 
reference to an
invalid type can only be used by code that have the wrong information about 
type C, and this
is in fact the only possible value for this type (any attempt to create a real 
instance of
‘LC;’ would fail). In order to use this reference as a legitimate reference to 
the real
type ‘QC;’, another checkcast, using the proper sequence above, would be 
required and would 
throw an exception.

Ill formed or malicious class files could be aware that C is an inline type, 
but use a
single checkcast instruction (without preceding ldc) anyway. This is part of a 
bigger
problem that has not been discussed yet: L/Q consistency inside a class file. 
the SoV
document stipules that the value projection only exists in the Q-form and the 
reference
projection only exists in the L-form. As of today, there’s no verification of 
such kind
performed on class files. Nothing prevent a class file from declaring a field 
of type
‘LC;’ and another of type ‘QC;’, and the same remark applies to method 
arguments.


Going back to the modified specification of checkcast, new tests are easy to 
implement
in the interpreter, and can easily be optimized by JIT compilers (most types 
would be
loaded at compilation time), and there’s no bootstrapping issues.

Fred





Re: null checks vs. class resolution, and translation strategy for casts

2020-04-12 Thread forax
> De: "John Rose" 
> À: "Remi Forax" 
> Cc: "Brian Goetz" , "valhalla-spec-experts"
> 
> Envoyé: Samedi 11 Avril 2020 07:43:28
> Objet: Re: null checks vs. class resolution, and translation strategy for 
> casts

> On Apr 10, 2020, at 4:19 AM, [ mailto:fo...@univ-mlv.fr | fo...@univ-mlv.fr ]
> wrote:

>>> So, here’s a recommendation: Use indy, and use a clunkier
>>> fallback in the same places that today use a clunkier fallback
>>> for string concatenation. And, record a line item of technical
>>> debt that we should further explore indy intrinsics, after we
>>> figure out what javac intrinsics look like.

>> What is not clear to me is that javac can replace unbox by a nullcheck, for 
>> the
>> VM, the input is an interface and the output is an inline type, given that
>> interfaces are not checked until runtime, how the VM can validate that only a
>> nullcheck is enough ?

> It can’t; that’s why I’m saying javac needs to ask for a null check,
> *and* somehow affirm the inline type (subtype of interface).
> This is two bytecodes, invokestatic Objects.requireNN, plus
> checkcast C.

Ok, 

>> Also it's still not clear to me what indy provide in this case.

> It provides both of the above effects in one bytecode. The bytecode,
> in turn, can expand to some internal JVM intrinsic which the runtime
> will optimize better than a back-to-back combo of the two standard
> instructions. That intrinsic never has to be admitted to by any spec.

>> So i still think that doing a checkcast (reusing checkcast being a trick to
>> avoid to introduce a new bytecode) or having a special unbox opcode is a 
>> better
>> idea.

> Changing opcode behaviors and/or adding new opcodes is always
> more expensive than appealing to indy, even if we have to add secret
> optimizations to indy. Specs are almost always harder to change than
> optimizations.

Why do we have the new opcodes defaultvalue and withfield in that case ? 
In both case, the semantics "new inline type" and "unbox inline type" can be 
express with an indy, but for the former we have chosen to go with 2 new 
bytecodes and for the later you want to use indy, that doesn't seem logical. 
I understand why you want to use indy but from my armchair it seems like paying 
the cost upfront (with a new bytecode) or later (when optimizing). 

Indy is good when the linking is complex, for lambdas when you need to create a 
proxy class out of thin air, for the string concatenation or for the pattern 
matching because you have a lot of code shapes to link together. 
Indy has three major drawbacks, calling the BSM is slow, it's only fully 
inlined by c2 and you can not use it before it has been bootstraped. 
Those issues are all severe in our case, i don't see how we can use an inline 
type to express the entry (the pair of K,V) of a HashMap without being stopped 
by these issues. 

I heard you about the cost, but here indy is not the silver bullet, it's a 
shiny tool with its own weaknesses. 
And yes, adding a new opcode has a more upfront cost. 

> — John

Rémi 


Re: null checks vs. class resolution, and translation strategy for casts

2020-04-10 Thread John Rose
On Apr 10, 2020, at 4:19 AM, fo...@univ-mlv.fr wrote:
> 
>> So, here’s a recommendation:  Use indy, and use a clunkier
>> fallback in the same places that today use a clunkier fallback
>> for string concatenation.  And, record a line item of technical
>> debt that we should further explore indy intrinsics, after we
>> figure out what javac intrinsics look like.
> 
> What is not clear to me is that javac can replace unbox by a nullcheck, for 
> the VM, the input is an interface and the output is an inline type, given 
> that interfaces are not checked until runtime, how the VM can validate that 
> only a nullcheck is enough ?

It can’t; that’s why I’m saying javac needs to ask for a null check,
*and* somehow affirm the inline type (subtype of interface).
This is two bytecodes, invokestatic Objects.requireNN, plus
checkcast C.

> Also it's still not clear to me what indy provide in this case.

It provides both of the above effects in one bytecode.  The bytecode,
in turn, can expand to some internal JVM intrinsic which the runtime
will optimize better than a back-to-back combo of the two standard
instructions.  That intrinsic never has to be admitted to by any spec.

> So i still think that doing a checkcast  (reusing checkcast being a trick to 
> avoid to introduce a new bytecode) or having a special unbox opcode is a 
> better idea. 

Changing opcode behaviors and/or adding new opcodes is always
more expensive than appealing to indy, even if we have to add secret
optimizations to indy.  Specs are almost always harder to change than
optimizations.

— John

Re: null checks vs. class resolution, and translation strategy for casts

2020-04-10 Thread forax
- Mail original -
> De: "John Rose" 
> À: "Remi Forax" 
> Cc: "Brian Goetz" , "valhalla-spec-experts" 
> 
> Envoyé: Jeudi 9 Avril 2020 23:56:45
> Objet: Re: null checks vs. class resolution, and translation strategy for 
> casts

> On Apr 9, 2020, at 2:31 PM, fo...@univ-mlv.fr wrote:
>> 
>> yes, indy is a way to create any new bytecode, but it also has some
>> restrictions,
>> the major one being that you can not using it before it has been 
>> bootstrapped.
> 
> Good point; we found that with string concatenation, didn’t we?
> If we use indy for this, we’ll run into similar bootstrapping issues.

Replacing an inner class by a lambda when calling AccessController.doPrivileged 
early in the boot process was my first encounter with this issue.

> 
> Which reminds me that Brian has been pondering javac intrinsics
> for some time, as a way of replacing method calls that would
> ordinarily be linked and run the normal way, with preferable
> alternative implementations.  This game could also be played
> (very carefully) with BSMs.  That (like javac intrinsics) would
> sidestep the usual bootstrapping orders.

javac intrinsics doesn't work well because of profile pollution, by example 
with String.valueOf(), if the format is a constant, you can transform the 
format (if it is non Locale sensitive) to a string concatenation, but there is 
no way to express "if it's a constant" at indy level. Either you capture the 
format string and hope you will see the same, here you have a profile pollution 
issue or you have a magic combinator that say if it's constant use this method 
handle and not the other one but in that case, the method handle called if the 
argument is a constant has never been called and so has no profile further 
down.  

> 
> So, here’s a recommendation:  Use indy, and use a clunkier
> fallback in the same places that today use a clunkier fallback
> for string concatenation.  And, record a line item of technical
> debt that we should further explore indy intrinsics, after we
> figure out what javac intrinsics look like.

What is not clear to me is that javac can replace unbox by a nullcheck, for the 
VM, the input is an interface and the output is an inline type, given that 
interfaces are not checked until runtime, how the VM can validate that only a 
nullcheck is enough ?

Also it's still not clear to me what indy provide in this case. So i still 
think that doing a checkcast  (reusing checkcast being a trick to avoid to 
introduce a new bytecode) or having a special unbox opcode is a better idea. 

> 
> — John

Rémi


Re: null checks vs. class resolution, and translation strategy for casts

2020-04-09 Thread John Rose
On Apr 9, 2020, at 2:31 PM, fo...@univ-mlv.fr wrote:
> 
> yes, indy is a way to create any new bytecode, but it also has some 
> restrictions,
> the major one being that you can not using it before it has been bootstrapped.

Good point; we found that with string concatenation, didn’t we?
If we use indy for this, we’ll run into similar bootstrapping issues.

Which reminds me that Brian has been pondering javac intrinsics
for some time, as a way of replacing method calls that would
ordinarily be linked and run the normal way, with preferable
alternative implementations.  This game could also be played
(very carefully) with BSMs.  That (like javac intrinsics) would
sidestep the usual bootstrapping orders.

So, here’s a recommendation:  Use indy, and use a clunkier
fallback in the same places that today use a clunkier fallback
for string concatenation.  And, record a line item of technical
debt that we should further explore indy intrinsics, after we
figure out what javac intrinsics look like.

— John

Re: null checks vs. class resolution, and translation strategy for casts

2020-04-09 Thread forax
> De: "John Rose" 
> À: "Remi Forax" 
> Cc: "Brian Goetz" , "valhalla-spec-experts"
> 
> Envoyé: Jeudi 9 Avril 2020 23:07:10
> Objet: Re: null checks vs. class resolution, and translation strategy for 
> casts

> On Apr 9, 2020, at 1:58 PM, Remi Forax < [ mailto:fo...@univ-mlv.fr |
> fo...@univ-mlv.fr ] > wrote:

>> I don't fully understand why not using checkcast because from the user POV 
>> the
>> message will be better than just NPE.

> When today I try unbox an Integer but encounter a null,
> my experience is “NPE” rather than a more informative
> “failed to unbox this int because you handed me a null”.

> I agree, generally speaking, that messages should be more
> informative. But surely the bar is low here, and “NPE” is
> not out of bounds?

Not if JEP 358 is enable, you have a NPE on Integer.intValue(). 
Anyway, it's not because error message can be improved in an area that it 
should not be there in another area. 

Users on the Java side are writing a cast, so having a class cast exception 
because the value is null seems to be a good error message. 

> That said, an indy-based solution has full information
> about the use site, and can be coaxed to generate whatever
> user experience we desire. And so would intrinsic based
> solutions, of which I am favorable to some but not all.
> Perhaps we want another (intrinsically optimized) version
> of Objects::requireNonNull, which takes a second argument
> that assists in generating a better diagnostic.

yes, indy is a way to create any new bytecode, but it also has some 
restrictions, 
the major one being that you can not using it before it has been bootstrapped. 

> — John

Rémi 


Re: null checks vs. class resolution, and translation strategy for casts

2020-04-09 Thread John Rose
On Apr 9, 2020, at 2:07 PM, John Rose  wrote:
> 
> Perhaps we want another (intrinsically optimized) version
> of Objects::requireNonNull, which takes a second argument
> that assists in generating a better diagnostic.

(D’oh; there it stands in the the JDK already.)



Re: null checks vs. class resolution, and translation strategy for casts

2020-04-09 Thread John Rose
On Apr 9, 2020, at 1:58 PM, Remi Forax  wrote:
> 
> I don't fully understand why not using checkcast because from the user POV 
> the message will be better than just NPE.

When today I try unbox an Integer but encounter a null,
my experience is “NPE” rather than a more informative
“failed to unbox this int because you handed me a null”.

I agree, generally speaking, that messages should be more
informative.  But surely the bar is low here, and “NPE” is
not out of bounds?

That said, an indy-based solution has full information
about the use site, and can be coaxed to generate whatever
user experience we desire.  And so would intrinsic based
solutions, of which I am favorable to some but not all.
Perhaps we want another (intrinsically optimized) version
of Objects::requireNonNull, which takes a second argument
that assists in generating a better diagnostic.

— John

Re: null checks vs. class resolution, and translation strategy for casts

2020-04-09 Thread Remi Forax
I don't fully understand why not using checkcast because from the user POV the 
message will be better than just NPE.

Rémi

- Mail original -
> De: "John Rose" 
> À: "Brian Goetz" 
> Cc: "valhalla-spec-experts" 
> Envoyé: Jeudi 9 Avril 2020 22:16:06
> Objet: Re: null checks vs. class resolution, and translation strategy for 
> casts

> On Apr 9, 2020, at 1:03 PM, Brian Goetz  wrote:
>> 
>> 
>>> I have a proposal for a translation strategy:
>> 
>> Casts to inline classes from their reference projections will be frequent.
>> Because the reference projection is sealed to permit only the value
>> projection, a cast is morally equivalent to a null check. We want to preserve
>> this performance model, because otherwise we're reinventing boxing.
>> 
>> Going through `ldc X.class / invokevirtual Class.cast` will surely be slow in
>> the interpreter, but also risks being slow elsewhere (as do many of the other
>> options.)
>> 
>> So let me add to your list: is it time for a `checknonnull` bytecode, which
>> throws NPE if null, or some other more flexible checking bytecode?
>> (Alternatively, if we're saving bytecodes: `invokevirtual
>> Object.`), where  is a fake method that always links 
>> to a
>> no-op, but invokevirtual NPEs on a null receiver.)
> 
> Um, this feels a lot like a premature optimization.  Let’s not add
> `checknonnull` intrinsics to the interpreter (the very most
> expensive way to do it) until we have tried the other alternatives
> (Objects.requireNonNull, etc.) and have proven that the costs
> are noticeable.  And a spec EG is not the place to evaluate such
> questions; it has to be demonstrated in a prototype.
> 
> I see now why you are angling for verifier rules that know about
> sealing relations.  I think that also is premature optimizations.
> Actually, verifier rules (not interpreter bytecodes) are the most
> costly way to get anything done.
> 
> Sorry to be a party pooper here, but that’s how it looks right now.
> 
> — John


Re: null checks vs. class resolution, and translation strategy for casts

2020-04-09 Thread John Rose
On Apr 9, 2020, at 1:20 PM, John Rose  wrote:
> 
> No specs were harmed in making this proposal.

P.P.S. Although there’s no precedent yet for it except static
code rewriters, we could also intrinsify certain indy instructions
in the same way, as early as the interpreter.  Then we’d have
customized verifier rules, based on each indy instruction signature,
at no runtime cost, even at startup, thanks to the intrinsification
logic.  There are lots of ways to skin this… orange.



Re: null checks vs. class resolution, and translation strategy for casts

2020-04-09 Thread John Rose
On Apr 9, 2020, at 1:16 PM, John Rose  wrote:
> 
> On Apr 9, 2020, at 1:03 PM, Brian Goetz  wrote:
>> 
>> 
>>> I have a proposal for a translation strategy:
>> 
>> Casts to inline classes from their reference projections will be frequent.  
>> Because the reference projection is sealed to permit only the value 
>> projection, a cast is morally equivalent to a null check. We want to 
>> preserve this performance model, because otherwise we're reinventing boxing.
>> 
>> Going through `ldc X.class / invokevirtual Class.cast` will surely be slow 
>> in the interpreter, but also risks being slow elsewhere (as do many of the 
>> other options.)
>> 
>> So let me add to your list: is it time for a `checknonnull` bytecode, which 
>> throws NPE if null, or some other more flexible checking bytecode?  
>> (Alternatively, if we're saving bytecodes: `invokevirtual 
>> Object.`), where  is a fake method that always links 
>> to a no-op, but invokevirtual NPEs on a null receiver.)
> 
> Um, this feels a lot like a premature optimization.  Let’s not add
> `checknonnull` intrinsics to the interpreter (the very most
> expensive way to do it) until we have tried the other alternatives
> (Objects.requireNonNull, etc.) and have proven that the costs
> are noticeable.  And a spec EG is not the place to evaluate such
> questions; it has to be demonstrated in a prototype.
> 
> I see now why you are angling for verifier rules that know about
> sealing relations.  I think that also is premature optimizations.
> Actually, verifier rules (not interpreter bytecodes) are the most
> costly way to get anything done.
> 
> Sorry to be a party pooper here, but that’s how it looks right now.
> 
> — John

P.S. The Object. idea is clever, and we have done
things like that in the past; the interpreter has special fast entry
points for certain math functions.  These were added due to certain
benchmarks being slow >20 years ago; who knows if they are still
relevant.  We could do the same for Objects.requireNonNull; that
would be a less intrusive (more sneaky) version of Object..
No specs were harmed in making this proposal.

Re: null checks vs. class resolution, and translation strategy for casts

2020-04-09 Thread John Rose
On Apr 9, 2020, at 1:03 PM, Brian Goetz  wrote:
> 
> 
>> I have a proposal for a translation strategy:
> 
> Casts to inline classes from their reference projections will be frequent.  
> Because the reference projection is sealed to permit only the value 
> projection, a cast is morally equivalent to a null check. We want to preserve 
> this performance model, because otherwise we're reinventing boxing.
> 
> Going through `ldc X.class / invokevirtual Class.cast` will surely be slow in 
> the interpreter, but also risks being slow elsewhere (as do many of the other 
> options.)
> 
> So let me add to your list: is it time for a `checknonnull` bytecode, which 
> throws NPE if null, or some other more flexible checking bytecode?  
> (Alternatively, if we're saving bytecodes: `invokevirtual 
> Object.`), where  is a fake method that always links to 
> a no-op, but invokevirtual NPEs on a null receiver.)

Um, this feels a lot like a premature optimization.  Let’s not add
`checknonnull` intrinsics to the interpreter (the very most
expensive way to do it) until we have tried the other alternatives
(Objects.requireNonNull, etc.) and have proven that the costs
are noticeable.  And a spec EG is not the place to evaluate such
questions; it has to be demonstrated in a prototype.

I see now why you are angling for verifier rules that know about
sealing relations.  I think that also is premature optimizations.
Actually, verifier rules (not interpreter bytecodes) are the most
costly way to get anything done.

Sorry to be a party pooper here, but that’s how it looks right now.

— John




Re: null checks vs. class resolution, and translation strategy for casts

2020-04-09 Thread Brian Goetz




I have a proposal for a translation strategy:


Casts to inline classes from their reference projections will be 
frequent.  Because the reference projection is sealed to permit only the 
value projection, a cast is morally equivalent to a null check. We want 
to preserve this performance model, because otherwise we're reinventing 
boxing.


Going through `ldc X.class / invokevirtual Class.cast` will surely be 
slow in the interpreter, but also risks being slow elsewhere (as do many 
of the other options.)


So let me add to your list: is it time for a `checknonnull` bytecode, 
which throws NPE if null, or some other more flexible checking 
bytecode?  (Alternatively, if we're saving bytecodes: `invokevirtual 
Object.`), where  is a fake method that always 
links to a no-op, but invokevirtual NPEs on a null receiver.)




Re: null checks vs. class resolution, and translation strategy for casts

2020-04-09 Thread John Rose
Correction…  The recommended reflective approach has
a flaw (easily fixed), which makes indy my real recommendation.

On Apr 8, 2020, at 11:43 AM, John Rose  wrote:
> …
> I have a proposal for a translation strategy:
> 
> 1. Translate casts to inline classes differently from “classic”
> casts.  Add an extra step of null hostility.  For very low-level
> reasons, I suggest using “ldc X” followed by Class::cast.
> 
> Generally speaking, it’s a reasonable move to use reflective
> API points (like Class::cast) on constant metadata (like X.class)
> to implement language semantics.

This suggestion is incomplete.  If the result of the cast is
going to be used as type X, then the verifier must be
pacified by adding `checkcast X`.  Basically, you have
to do both reflective and intrinsic cast operations, if you
need to get the verifier on board, as well as do a null
check.  That tips me over to recommending indy instead,
which was #2.  Indy, that Swiss army knife of an instruction,
can get it done in one.

> The following alternatives are also possible; I present them
> in decreasing order of preference:
> 
> 2. Use invokedynamic to roll our own instruction.  It will
> be a trivial BSM since we are really just doing an asType
> operation.  But I think this is probably overkill, despite
> my fondness for indy.

For a conversion to type X, where X may be a null-hostile
inline type (or any type whose semantics is not exactly
covered by native checkcast), a single invokedynamic
instruction will cover the operational semantics
required and will also feed the right type to the verifier.
It will have this signature:

  (Object) => X

It will have a utility bootstrap method which materializes
conversions, basically riffing on MethodHandles::identity
and asType.  (Not MethodHandles::explicitCastArguments,
because we are concerned with checked reference conversions.)

It will have *no extra arguments* (not even X.class), because
the BSM can easily derive X.class from the return type of
the method type signature passed to the BSM.

ConstantCallSite convertBSM(Lookup ig1, String ig2, MethodType mt) {
  var mh = MethodHandles.identity(Object.class).asType(mt);
  return new ConstantCallSite(mh);
}

As such, it is a candidate for proposed simplifications to
bootstrap method configuration (but not the simplest such
simplifications, because of the need to feed X.class into
the linkage logic).

MethodHandle simplifiedConvertBSM() {
  return MethodHandles.identity(Object.class);
}

(At some point I should write up those simplifications,
shouldn’t I?)

— John