On Tue, 27 Jan 2026 16:26:19 GMT, Damon Fenacci <[email protected]> wrote:

>> ## Issue
>> 
>> This is a redo of [JDK-8361842](https://bugs.openjdk.org/browse/JDK-8361842) 
>> which was backed out by 
>> [JDK-8374210](https://bugs.openjdk.org/browse/JDK-8374210) due to C2-related 
>> regressions. The original change moved input validation checks for 
>> java.lang.StringCoding from the intrinsic to Java code (leaving the 
>> intrinsic check only with the `VerifyIntrinsicChecks` flag). Refer to the 
>> [original PR](https://github.com/openjdk/jdk/pull/25998) for details.
>> 
>> This additional issue happens because, in some cases, for instance when the 
>> Java checking code is not inlined and we give an out-of-range constant as 
>> input, we fold the data path but not the control path and we crash in the 
>> backend.
>> 
>> ## Causes
>> 
>> The cause of this is that the out-of-range constant (e.g. -1) floats into 
>> the intrinsic and there (assuming the input is valid) we add a constraint to 
>> its type to positive integers (e.g. to compute the array address) which 
>> makes it top.
>> 
>> ## Fix
>> 
>> A possible fix is to introduce an opaque node (OpaqueGuardNode) similar to 
>> what we do in `must_be_not_null` for values that we know cannot be null:
>> https://github.com/openjdk/jdk/blob/ce721665cd61d9a319c667d50d9917c359d6c104/src/hotspot/share/opto/graphKit.cpp#L1484
>> This will temporarily add the range check to ensure that C2 figures that 
>> out-of-range values cannot reach the intrinsic. Then, during macro 
>> expansion, we replace the opaque node with the corresponding constant 
>> (true/false) in product builds such that the actually unneeded guards are 
>> folded and do not end up in the emitted code.
>> 
>> # Testing
>> 
>> * Tier 1-3+
>> * 2 JTReg tests added
>>   * `TestRangeCheck.java` as regression test for the reported issue
>>   * `TestOpaqueGuardNodes.java` to check that opaque guard nodes are added 
>> when parsing and removed at macro expansion
>
> Damon Fenacci has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   JDK-8374852: fix star layout
>   
>   Co-authored-by: Christian Hagedorn <[email protected]>

Thanks for unifying the two opaque nodes! I have some more comments.

src/hotspot/share/opto/macro.cpp line 2559:

> 2557: #else
> 2558:         bool is_positive = n->as_OpaqueCheck()->is_positive();
> 2559:         _igvn.replace_node(n, _igvn.intcon(is_positive?1:0));

Suggestion:

        _igvn.replace_node(n, _igvn.intcon(is_positive ? 1 : 0));

src/hotspot/share/opto/opaquenode.hpp line 146:

> 144: // builds, we keep the actual checks as additional verification code 
> (i.e. removing OpaqueCheckNodes and use the
> 145: // BoolNode inputs instead).
> 146: class OpaqueCheckNode : public Node {

I've also thought about the name. `OpaqueCheck` is already a good indication 
what the node is about. Maybe we could go a step further and call it 
`OpaqueConstantBoolNode` to emphasize more that it is belonging to a `BoolNode` 
whose result we already know. What do you think?

Then we could also think about changing `_positive` to `_constant` (still can 
be a boolean to just pass true and false which seems more intuitive then 
passing in 1 and 0).

src/hotspot/share/opto/opaquenode.hpp line 148:

> 146: class OpaqueCheckNode : public Node {
> 147:  private:
> 148:   bool _positive;

Now that we define a field, we also need to override `size_of()` (see for 
example `OpaqueMultiversioningNode`).

src/hotspot/share/opto/opaquenode.hpp line 150:

> 148:   bool _positive;
> 149:  public:
> 150:   OpaqueCheckNode(Compile* C, Node* tst, bool positive) : Node(nullptr, 
> tst), _positive(positive) {

`tst` is probably almost always a `BoolNode`. I'm wondering if it could also be 
a constant because we already folded the `BoolNode`? But then it's probably 
also useless to create the opaque node in the first place.

src/hotspot/share/opto/opaquenode.hpp line 159:

> 157:   virtual const Type* Value(PhaseGVN* phase) const;
> 158:   virtual const Type* bottom_type() const { return TypeInt::BOOL; }
> 159:   bool is_positive() { return _positive; }

When going with `_constant`, we could turn this into

int constant() const { return _constant ? 1 : 0; }

-------------

PR Review: https://git.openjdk.org/jdk/pull/29164#pullrequestreview-3715097474
PR Review Comment: https://git.openjdk.org/jdk/pull/29164#discussion_r2735306919
PR Review Comment: https://git.openjdk.org/jdk/pull/29164#discussion_r2735376625
PR Review Comment: https://git.openjdk.org/jdk/pull/29164#discussion_r2735315675
PR Review Comment: https://git.openjdk.org/jdk/pull/29164#discussion_r2735369034
PR Review Comment: https://git.openjdk.org/jdk/pull/29164#discussion_r2735392835

Reply via email to