JDK-8317659 : [lworld] Incorrect unsafe put operation over value objects.
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: repo-valhalla
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • CPU: generic
  • Submitted: 2023-10-06
  • Updated: 2024-07-04
  • Resolved: 2024-07-04
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
repo-valhallaResolved
Related Reports
Duplicate :  
Relates :  
Description
Following test case shows different results when compiled with C2 compiler and interpreter.

public class unsafe_bug {
     primitive class Pair {
         final double d1, d2;
         public Pair(double d1, double d2) {
             this.d1 = d1;
             this.d2 = d2;
         }
     }

     static final long[] OFFSETS = new long[] { 16, 24 };

     public static Pair helper(double[] values, boolean[] mask) {
         Pair p = Unsafe.getUnsafe().makePrivateBuffer(Pair.default);

         for (int i = 0; i < OFFSETS.length; i++) {
             if (mask[i]) {
                 Unsafe.getUnsafe().putDouble(p, OFFSETS[i], values[i]);
             }
         }
         return Unsafe.getUnsafe().finishPrivateBuffer(p);
    }


    public static double test(double[] values, boolean[] mask) {
         Pair p = helper(values, mask);
         return p.d1 + p.d2;
    }

    public static void main(String[] args) {
        double[]  values = new  double[] {  1.0,   2.0 };
        boolean[] mask   = new boolean[] { true, false };

        double d = 0.0;
        for (int i = 0; i < 10000; i++) {
            d = test(values, mask);
        }
        System.out.printf("test: %f\n", d);
     }
}

CPROMPT>java -Xbatch -XX:-TieredCompilation -XX:+EnablePrimitiveClasses --add-exports java.base/jdk.internal.misc=ALL-UNNAMED -cp . unsafe_bug
test: 0.000000

CPROMPT>java -Xbatch -Xint -XX:+EnablePrimitiveClasses --add-exports java.base/jdk.internal.misc=ALL-UNNAMED -cp . unsafe_bug
test: 1.000000

Comments
This is a duplicate of JDK-8239003. The root cause is that the makePrivateBuffer/finishPrivateBuffer functionality conflicts with C2 scalarization.
04-07-2024

Also, I don't think this is correct for flat accesses: if (is_reference_type(type)) { decorators |= ON_UNKNOWN_OOP_REF; }
21-11-2023

Seems the root cause is the field values of the returned "InlineTypeNode" are not updated to the values in changed oop buffer with "Unsafe.put()". Just applying such change can fix it: ``` diff --git a/src/hotspot/share/opto/inlinetypenode.cpp b/src/hotspot/share/opto/inlinetypenode.cpp index d9c0ceeb0..2bc00b358 100644 --- a/src/hotspot/share/opto/inlinetypenode.cpp +++ b/src/hotspot/share/opto/inlinetypenode.cpp @@ -1049,14 +1049,7 @@ InlineTypeNode* InlineTypeNode::finish_larval(GraphKit* kit) const { kit->insert_mem_bar(Op_MemBarStoreStore, alloc->proj_out_or_null(AllocateNode::RawAddress)); ciInlineKlass* vk = inline_klass(); - InlineTypeNode* res = make_uninitialized(kit->gvn(), vk); - for (uint i = 1; i < req(); ++i) { - res->set_req(i, in(i)); - } - // TODO 8239003 - //res->set_type(TypeInlineType::make(vk, false)); - res = kit->gvn().transform(res)->as_InlineType(); - return res; + return InlineTypeNode::make_from_oop(kit, obj, vk, true); } bool InlineTypeNode::is_larval(PhaseGVN* gvn) const { ``` Inspired by PR: https://github.com/openjdk/valhalla/pull/952
15-11-2023

I analyzed this further and it seems that problem is due to incorrect merging of JVM state. Current IR ======== mask = { true, false} P0 = INIT for (…) { P3 = Phi (P0, P4) // 339 If (mask[i]) { P1 = … } P4 = Phi(P0, P1) // 317 } P0, P1, P2 are all Value objects i.e. InlineTypeNode with scalarized inputs. While parsing JVM states of converging control flows are merged and Phi nodes are created to converge different value of same local variable from different control paths. In this case when else block merges with loop header then Phi node in header gets appropriately connected to latch block input, but then it should all replace all uses of original InlineTypeNode with newly created merged InlineTypeNode in downstream graph which is missing. Therefore P2 still receives P0 as one of its input where as it should be receiving P2 . Correct IR ========= mask = {true, false} P0 = INIT for (…) { P3 = Phi (P0, P4) // 339 If (mask[i]) { P1 = … } P4 = Phi(P2, P3) // 317 }
02-11-2023

Might be related to JDK-8239003.
01-11-2023

Problem was initially seen with lworld+vector branch in fallback vector API implementations which uses unsafe API to update multifield based payload, as a workaround we disabled intrinsification of Unsafe.finishPrivateBuffer for vector payload objects. Please find more details at following link https://github.com/openjdk/valhalla/pull/909#:~:text=Disable%20inline%20expansion,updated%20buffer%20argument. But, it seems the problem is generic and may occur with unsafe put operations over any non-vector value object.
28-10-2023