--- /dev/null 2018-12-11 10:44:15.000000000 -0800 +++ new/test/hotspot/jtreg/runtime/valhalla/valuetypes/UnsafeTest.java 2018-12-11 10:44:13.000000000 -0800 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package runtime.valhalla.valuetypes; + +/* + * @test UnsafeTest + * @summary unsafe get/put/with value + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @compile -XDallowWithFieldOperator Point.java UnsafeTest.java + * @run main/othervm -Xint -XX:+EnableValhalla runtime.valhalla.valuetypes.UnsafeTest + * @run main/othervm -Xcomp -XX:+EnableValhalla runtime.valhalla.valuetypes.UnsafeTest + */ + +import jdk.internal.misc.Unsafe; + +import java.lang.reflect.*; +import java.util.List; +import static jdk.test.lib.Asserts.*; + +public class UnsafeTest { + static final Unsafe U = Unsafe.getUnsafe(); + + static value class Value1 { + Point point; + Point[] array; + Value1() { + this.point = Point.createPoint(1, 1); + this.array = new Point[0]; + } + + static Value1 create(Point p, Point... points) { + Value1 o = Value1.default; + o = __WithField(o.point, p); + o = __WithField(o.array, points); + return o; + } + } + + static value class Value2 { + int i; + Value1 v; + + Value2() { + this.i = 0; + this.v = Value1.create(Point.createPoint(0,0), new Point[0]); + } + + static Value2 create(Value1 v, int i) { + Value2 o = Value2.default; + o = __WithField(o.v, v); + o = __WithField(o.i, i); + return o; + } + } + + static value class Value3 { + Object o; + Value2 v; + + Value3() { + this.v = Value2.create(Value1.create(Point.createPoint(0,0), new Point[0]), 0); + this.o = new Object(); + } + + static Value3 create(Value2 v, Object ref) { + Value3 o = Value3.default; + o = __WithField(o.v, v); + o = __WithField(o.o, ref); + return o; + } + } + + + public static void main(String[] args) throws Throwable { + printValueClass(Value3.class, 0); + + Value1 v1 = Value1.create(Point.createPoint(10,10), Point.createPoint(20,20), Point.createPoint(30,30)); + Value2 v2 = Value2.create(v1, 20); + Value3 v3 = Value3.create(v2, List.of("Value3")); + long off_o = U.objectFieldOffset(Value3.class, "o"); + long off_v = U.objectFieldOffset(Value3.class, "v"); + long off_i = U.objectFieldOffset(Value2.class, "i"); + long off_v2 = U.objectFieldOffset(Value2.class, "v"); + + long off_point = U.objectFieldOffset(Value1.class, "point"); + + /* + * Layout of Value3 + * + * | valueheader | o | i | x | y | array | + * ^-------^ + * Point + * ^---------------^ + * Value1 + * + * ^-------------------^ + * Value2 + */ + Value3 v = v3; + try { + v = U.makePrivateBuffer(v); + // patch v3.o + U.putObject(v, off_o, List.of("Value1", "Value2", "Value3")); + // patch v3.v.i; + U.putInt(v, off_v + off_i - U.valueHeaderSize(Value2.class), 999); + // patch v3.v.v.point + U.putValue(v, off_v + off_v2 - U.valueHeaderSize(Value2.class) + off_point - U.valueHeaderSize(Value1.class), + Point.class, Point.createPoint(100, 100)); + } finally { + v = U.finishPrivateBuffer(v); + } + + assertEquals(v.v.v.point, Point.createPoint(100, 100)); + assertEquals(v.v.i, 999); + assertEquals(v.o, List.of("Value1", "Value2", "Value3")); + assertEquals(v.v.v.array, v1.array); + + Value1 nv1 = Value1.create(Point.createPoint(70,70), Point.createPoint(80,80), Point.createPoint(90,90)); + Value2 nv2 = Value2.create(nv1, 100); + Value3 nv3 = Value3.create(nv2, List.of("Value1", "Value2", "Value3")); + + try { + v = U.makePrivateBuffer(v); + // patch v3.v + U.putValue(v, off_v2, Value2.class, nv2); + } finally { + v = U.finishPrivateBuffer(v); + } + assertEquals(v, nv3); + } + + static void printValueClass(Class vc, int level) { + String indent = ""; + for (int i=0; i < level; i++) { + indent += " "; + } + System.out.format("%s%s header size %d%n", indent, vc, U.valueHeaderSize(vc)); + for (Field f : vc.getDeclaredFields()) { + System.out.format("%s%s: %s%s offset %d%n", indent, f.getName(), + U.isFlattened(f) ? "flattened " : "", f.getType(), + U.objectFieldOffset(vc, f.getName())); + if (U.isFlattened(f)) { + printValueClass(f.getType(), level+1); + } + } + } +}