1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package runtime.valhalla.valuetypes;
  25 
  26 /*
  27  * @test UnsafeTest
  28  * @summary unsafe get/put/with value
  29  * @modules java.base/jdk.internal.misc
  30  * @library /test/lib
  31  * @compile -XDallowWithFieldOperator Point.java UnsafeTest.java
  32  * @run main/othervm -Xint -XX:+EnableValhalla runtime.valhalla.valuetypes.UnsafeTest
  33  * @run main/othervm -Xcomp -XX:+EnableValhalla runtime.valhalla.valuetypes.UnsafeTest
  34  */
  35 
  36 import jdk.internal.misc.Unsafe;
  37 
  38 import java.lang.reflect.*;
  39 import java.util.List;
  40 import static jdk.test.lib.Asserts.*;
  41 
  42 public class UnsafeTest {
  43     static final Unsafe U = Unsafe.getUnsafe();
  44 
  45     static value class Value1 {
  46         Point point;
  47         Point[] array;
  48         Value1() {
  49             this.point = Point.createPoint(1, 1);
  50             this.array = new Point[0];
  51         }
  52 
  53         static Value1 create(Point p, Point... points) {
  54             Value1 o = Value1.default;
  55             o = __WithField(o.point, p);
  56             o = __WithField(o.array, points);
  57             return o;
  58         }
  59     }
  60 
  61     static value class Value2 {
  62         int i;
  63         Value1 v;
  64 
  65         Value2() {
  66             this.i = 0;
  67             this.v = Value1.create(Point.createPoint(0,0), new Point[0]);
  68         }
  69 
  70         static Value2 create(Value1 v, int i) {
  71             Value2 o = Value2.default;
  72             o = __WithField(o.v, v);
  73             o = __WithField(o.i, i);
  74             return o;
  75         }
  76     }
  77 
  78     static value class Value3 {
  79         Object o;
  80         Value2 v;
  81 
  82         Value3() {
  83             this.v = Value2.create(Value1.create(Point.createPoint(0,0), new Point[0]), 0);
  84             this.o = new Object();
  85         }
  86 
  87         static Value3 create(Value2 v, Object ref) {
  88             Value3 o = Value3.default;
  89             o = __WithField(o.v, v);
  90             o = __WithField(o.o, ref);
  91             return o;
  92         }
  93     }
  94 
  95 
  96     public static void main(String[] args) throws Throwable {
  97         printValueClass(Value3.class, 0);
  98 
  99         Value1 v1 = Value1.create(Point.createPoint(10,10), Point.createPoint(20,20), Point.createPoint(30,30));
 100         Value2 v2 = Value2.create(v1, 20);
 101         Value3 v3 = Value3.create(v2, List.of("Value3"));
 102         long off_o = U.objectFieldOffset(Value3.class, "o");
 103         long off_v = U.objectFieldOffset(Value3.class, "v");
 104         long off_i = U.objectFieldOffset(Value2.class, "i");
 105         long off_v2 = U.objectFieldOffset(Value2.class, "v");
 106 
 107         long off_point = U.objectFieldOffset(Value1.class, "point");
 108 
 109         /*
 110          * Layout of Value3
 111          *
 112          * | valueheader | o | i | x | y | array |
 113          *                       ^-------^
 114          *                        Point
 115          *                       ^---------------^
 116          *                        Value1
 117          *
 118          *                   ^-------------------^
 119          *                    Value2
 120          */
 121         Value3 v = v3;
 122         try {
 123             v = U.makePrivateBuffer(v);
 124             // patch v3.o
 125             U.putObject(v, off_o, List.of("Value1", "Value2", "Value3"));
 126             // patch v3.v.i;
 127             U.putInt(v, off_v + off_i - U.valueHeaderSize(Value2.class), 999);
 128             // patch v3.v.v.point
 129             U.putValue(v, off_v + off_v2 - U.valueHeaderSize(Value2.class) + off_point - U.valueHeaderSize(Value1.class),
 130                        Point.class, Point.createPoint(100, 100));
 131         } finally {
 132             v = U.finishPrivateBuffer(v);
 133         }
 134 
 135         assertEquals(v.v.v.point, Point.createPoint(100, 100));
 136         assertEquals(v.v.i, 999);
 137         assertEquals(v.o, List.of("Value1", "Value2", "Value3"));
 138         assertEquals(v.v.v.array, v1.array);
 139 
 140         Value1 nv1 = Value1.create(Point.createPoint(70,70), Point.createPoint(80,80), Point.createPoint(90,90));
 141         Value2 nv2 = Value2.create(nv1, 100);
 142         Value3 nv3 = Value3.create(nv2, List.of("Value1", "Value2", "Value3"));
 143 
 144         try {
 145             v = U.makePrivateBuffer(v);
 146             // patch v3.v
 147             U.putValue(v, off_v2, Value2.class, nv2);
 148         } finally {
 149             v = U.finishPrivateBuffer(v);
 150         }
 151         assertEquals(v, nv3);
 152     }
 153 
 154     static void printValueClass(Class<?> vc, int level) {
 155         String indent = "";
 156         for (int i=0; i < level; i++) {
 157             indent += "  ";
 158         }
 159         System.out.format("%s%s header size %d%n", indent, vc, U.valueHeaderSize(vc));
 160         for (Field f : vc.getDeclaredFields()) {
 161             System.out.format("%s%s: %s%s offset %d%n", indent, f.getName(),
 162                               U.isFlattened(f) ? "flattened " : "", f.getType(),
 163                               U.objectFieldOffset(vc, f.getName()));
 164             if (U.isFlattened(f)) {
 165                 printValueClass(f.getType(), level+1);
 166             }
 167         }
 168     }
 169 }