--- old/src/hotspot/share/prims/unsafe.cpp 2018-07-17 10:29:54.000000000 -0700 +++ new/src/hotspot/share/prims/unsafe.cpp 2018-07-17 10:29:53.000000000 -0700 @@ -280,6 +280,40 @@ } #endif // ASSERT +static void assert_and_log_unsafe_value_type_access(oop p, jlong offset, ValueKlass* vk) { + Klass* k = p->klass(); + +#ifdef ASSERT + if (k->is_instance_klass()) { + assert_field_offset_sane(p, offset); + fieldDescriptor fd; + bool found = get_field_descriptor(p, offset, &fd); + assert(found, "value field not found"); + assert(fd.is_flattened(), "field not flat"); + } else if (k->is_valueArray_klass()) { + ValueArrayKlass* vak = ValueArrayKlass::cast(k); + int index = (offset - vak->array_header_in_bytes()) / vak->element_byte_size(); + address dest = (address)((valueArrayOop)p)->value_at_addr(index, vak->layout_helper()); + assert(dest == ((address)p) + offset, "invalid offset"); + } else { + ShouldNotReachHere(); + } +#endif // ASSERT + + if (log_is_enabled(Trace, valuetypes)) { + if (k->is_valueArray_klass()) { + ValueArrayKlass* vak = ValueArrayKlass::cast(k); + int index = (offset - vak->array_header_in_bytes()) / vak->element_byte_size(); + address dest = (address)((valueArrayOop)p)->value_at_addr(index, vak->layout_helper()); + log_trace(valuetypes)("array type %s index %d element size %d offset " SIZE_FORMAT_HEX " at " INTPTR_FORMAT, + vak->external_name(), index, vak->element_byte_size(), offset, p2i(dest)); + } else { + log_trace(valuetypes)("field type %s at offset " SIZE_FORMAT_HEX, + vk->external_name(), offset); + } + } +} + // These functions allow a null base pointer with an arbitrary address. // But if the base pointer is non-null, the offset should make some sense. // That is, it should be in the range [0, MAX_OBJECT_SIZE]. @@ -297,24 +331,16 @@ HeapAccess::oop_store_at(p, offset, x); } UNSAFE_END +UNSAFE_ENTRY(jboolean, Unsafe_IsFlattenedArray(JNIEnv *env, jobject unsafe, jclass c)) { + Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(c)); + return k->is_valueArray_klass(); +} UNSAFE_END + UNSAFE_ENTRY(jobject, Unsafe_GetValue(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jclass c)) { oop p = JNIHandles::resolve(obj); Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(c)); ValueKlass* vk = ValueKlass::cast(k); - -#ifdef ASSERT - assert_field_offset_sane(p, offset); - fieldDescriptor fd; - bool found = get_field_descriptor(p, offset, &fd); - assert(found, "value field not found"); - assert(fd.is_flattened(), "field not flat"); -#endif // ASSERT - - if (log_is_enabled(Trace, valuetypes)) { - log_trace(valuetypes)("getValue: field type %s at offset " SIZE_FORMAT_HEX, - vk->external_name(), offset); - } - + assert_and_log_unsafe_value_type_access(p, offset, vk); Handle p_h(THREAD, p); bool in_heap; oop v = vk->allocate_buffered_or_heap_instance(&in_heap, CHECK_NULL); // allocate instance @@ -330,19 +356,7 @@ oop p = JNIHandles::resolve(obj); Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(c)); ValueKlass* vk = ValueKlass::cast(k); - -#ifdef ASSERT - assert_field_offset_sane(p, offset); - fieldDescriptor fd; - bool found = get_field_descriptor(p, offset, &fd); - assert(found, "value field not found"); - assert(fd.is_flattened(), "field not flat"); -#endif // ASSERT - - if (log_is_enabled(Trace, valuetypes)) { - log_trace(valuetypes)("putValue: field type %s at offset " SIZE_FORMAT_HEX, - vk->external_name(), offset); - } + assert_and_log_unsafe_value_type_access(p, offset, vk); vk->value_store(vk->data_for_oop(v), ((char*)(oopDesc*)p) + offset, true, true); } UNSAFE_END @@ -648,6 +662,11 @@ base = tak->array_header_in_bytes(); assert(base == arrayOopDesc::base_offset_in_bytes(tak->element_type()), "array_header_size semantics ok"); scale = (1 << tak->log2_element_size()); + } else if (k->is_valueArray_klass()) { + ValueArrayKlass* vak = ValueArrayKlass::cast(k); + ValueKlass* vklass = vak->element_klass(); + base = vak->array_header_in_bytes(); + scale = vak->element_byte_size(); } else { ShouldNotReachHere(); } @@ -1115,6 +1134,7 @@ {CC "getObjectVolatile",CC "(" OBJ "J)" OBJ "", FN_PTR(Unsafe_GetObjectVolatile)}, {CC "putObjectVolatile",CC "(" OBJ "J" OBJ ")V", FN_PTR(Unsafe_PutObjectVolatile)}, + {CC "isFlattenedArray", CC "(" CLS ")Z", FN_PTR(Unsafe_IsFlattenedArray)}, {CC "getValue", CC "(" OBJ "J" CLS ")" OBJ "", FN_PTR(Unsafe_GetValue)}, {CC "putValue", CC "(" OBJ "J" CLS OBJ ")V", FN_PTR(Unsafe_PutValue)}, --- old/src/java.base/share/classes/java/lang/invoke/VarHandles.java 2018-07-17 10:29:55.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/invoke/VarHandles.java 2018-07-17 10:29:54.000000000 -0700 @@ -162,7 +162,12 @@ int ashift = 31 - Integer.numberOfLeadingZeros(ascale); if (!componentType.isPrimitive()) { - return new VarHandleObjects.Array(aoffset, ashift, arrayClass); + // the redundant componentType.isValue() check is there to + // minimize the performance impact to non-value array. + // It should be removed when Unsafe::isFlattenedArray is intrinsified. + return componentType.isValue() && UNSAFE.isFlattenedArray(arrayClass) + ? new VarHandleObjects.ValueArray(aoffset, ashift, arrayClass) + : new VarHandleObjects.Array(aoffset, ashift, arrayClass); } else if (componentType == boolean.class) { return new VarHandleBooleans.Array(aoffset, ashift); --- old/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template 2018-07-17 10:29:56.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template 2018-07-17 10:29:56.000000000 -0700 @@ -1147,4 +1147,220 @@ static final VarForm FORM = new VarForm(Array.class, {#if[Object]?Object[].class:$type$[].class}, {#if[Object]?Object.class:$type$.class}, int.class); } + +#if[Object] + static final class ValueArray extends VarHandle { + final int abase; + final int ashift; + final Class arrayType; + final Class componentType; + + ValueArray(int abase, int ashift, Class arrayType) { + super(ValueArray.FORM); + this.abase = abase; + this.ashift = ashift; + this.arrayType = arrayType; + this.componentType = arrayType.getComponentType(); + } + + @Override + final MethodType accessModeTypeUncached(AccessMode accessMode) { + return accessMode.at.accessModeType(arrayType, arrayType.getComponentType(), int.class); + } + + @ForceInline + static Object runtimeTypeCheck(ValueArray handle, Object[] oarray, Object value) { + if (handle.arrayType == oarray.getClass()) { + // Fast path: static array type same as argument array type + return handle.componentType.cast(Objects.requireNonNull(value)); + } else { + // Slow path: check value against argument array component type + return reflectiveTypeCheck(oarray, value); + } + } + + @ForceInline + static Object reflectiveTypeCheck(Object[] oarray, Object value) { + try { + return oarray.getClass().getComponentType().cast(Objects.requireNonNull(value)); + } catch (ClassCastException e) { + throw new ArrayStoreException(); + } + } + + @ForceInline + static $type$ get(ValueArray handle, Object oarray, int index) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + return array[index]; + } + + @ForceInline + static void set(ValueArray handle, Object oarray, int index, $type$ value) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + array[index] = handle.componentType.cast(Objects.requireNonNull(value)); + } + + @ForceInline + static $type$ getVolatile(ValueArray handle, Object oarray, int index) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + return UNSAFE.getValueVolatile(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + handle.componentType); + } + + @ForceInline + static void setVolatile(ValueArray handle, Object oarray, int index, $type$ value) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + UNSAFE.putValueVolatile(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + handle.componentType, + runtimeTypeCheck(handle, array, value)); + } + + @ForceInline + static $type$ getOpaque(ValueArray handle, Object oarray, int index) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + return UNSAFE.getValueOpaque(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + handle.componentType); + } + + @ForceInline + static void setOpaque(ValueArray handle, Object oarray, int index, $type$ value) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + UNSAFE.putValueOpaque(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + handle.componentType, + runtimeTypeCheck(handle, array, value)); + } + + @ForceInline + static $type$ getAcquire(ValueArray handle, Object oarray, int index) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + return UNSAFE.getValueAcquire(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + handle.componentType); + } + + @ForceInline + static void setRelease(ValueArray handle, Object oarray, int index, $type$ value) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + UNSAFE.putValueRelease(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + handle.componentType, + runtimeTypeCheck(handle, array, value)); + } +#if[CAS] + + @ForceInline + static boolean compareAndSet(ValueArray handle, Object oarray, int index, $type$ expected, $type$ value) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + return UNSAFE.compareAndSetValue(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + handle.componentType, + handle.componentType.cast(Objects.requireNonNull(expected)), + runtimeTypeCheck(handle, array, value)); + } + + @ForceInline + static $type$ compareAndExchange(ValueArray handle, Object oarray, int index, $type$ expected, $type$ value) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + return UNSAFE.compareAndExchangeValue(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + handle.componentType, + handle.componentType.cast(Objects.requireNonNull(expected)), + runtimeTypeCheck(handle, array, value)); + } + + @ForceInline + static $type$ compareAndExchangeAcquire(ValueArray handle, Object oarray, int index, $type$ expected, $type$ value) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + return UNSAFE.compareAndExchangeValueAcquire(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + handle.componentType, + handle.componentType.cast(Objects.requireNonNull(expected)), + runtimeTypeCheck(handle, array, value)); + } + + @ForceInline + static $type$ compareAndExchangeRelease(ValueArray handle, Object oarray, int index, $type$ expected, $type$ value) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + return UNSAFE.compareAndExchangeValueRelease(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + handle.componentType, + handle.componentType.cast(Objects.requireNonNull(expected)), + runtimeTypeCheck(handle, array, value)); + } + + @ForceInline + static boolean weakCompareAndSetPlain(ValueArray handle, Object oarray, int index, $type$ expected, $type$ value) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + return UNSAFE.weakCompareAndSetValuePlain(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + handle.componentType, + handle.componentType.cast(Objects.requireNonNull(expected)), + runtimeTypeCheck(handle, array, value)); + } + + @ForceInline + static boolean weakCompareAndSet(ValueArray handle, Object oarray, int index, $type$ expected, $type$ value) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + return UNSAFE.weakCompareAndSetValue(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + handle.componentType, + handle.componentType.cast(Objects.requireNonNull(expected)), + runtimeTypeCheck(handle, array, value)); + } + + @ForceInline + static boolean weakCompareAndSetAcquire(ValueArray handle, Object oarray, int index, $type$ expected, $type$ value) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + return UNSAFE.weakCompareAndSetValueAcquire(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + handle.componentType, + handle.componentType.cast(Objects.requireNonNull(expected)), + runtimeTypeCheck(handle, array, value)); + } + + @ForceInline + static boolean weakCompareAndSetRelease(ValueArray handle, Object oarray, int index, $type$ expected, $type$ value) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + return UNSAFE.weakCompareAndSetValueRelease(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + handle.componentType, + handle.componentType.cast(Objects.requireNonNull(expected)), + runtimeTypeCheck(handle, array, value)); + } + + @ForceInline + static $type$ getAndSet(ValueArray handle, Object oarray, int index, $type$ value) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + return UNSAFE.getAndSetValue(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + handle.componentType, + runtimeTypeCheck(handle, array, value)); + } + + @ForceInline + static $type$ getAndSetAcquire(ValueArray handle, Object oarray, int index, $type$ value) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + return UNSAFE.getAndSetValueAcquire(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + handle.componentType, + runtimeTypeCheck(handle, array, value)); + } + + @ForceInline + static $type$ getAndSetRelease(ValueArray handle, Object oarray, int index, $type$ value) { + Object[] array = (Object[]) handle.arrayType.cast(oarray); + return UNSAFE.getAndSetValueRelease(array, + (((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase, + handle.componentType, + runtimeTypeCheck(handle, array, value)); + } +#end[CAS] + + static final VarForm FORM = new VarForm(ValueArray.class, {#if[Object]?Object[].class:$type$[].class}, {#if[Object]?Object.class:$type$.class}, int.class); + } +#end[Object] } --- old/test/jdk/valhalla/valuetypes/MethodHandleTest.java 2018-07-17 10:29:57.000000000 -0700 +++ new/test/jdk/valhalla/valuetypes/MethodHandleTest.java 2018-07-17 10:29:57.000000000 -0700 @@ -25,8 +25,7 @@ /* * @test * @summary test MethodHandle/VarHandle on value types - * @build Point Line MutablePath - * @compile -XDallowFlattenabilityModifiers MethodHandleTest.java + * @compile -XDallowFlattenabilityModifiers Point.java Line.java MutablePath.java MixedValues.java * @run testng/othervm -XX:+EnableValhalla MethodHandleTest */ @@ -34,7 +33,6 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.*; -import java.util.stream.Stream; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; @@ -85,7 +83,7 @@ public static void testMixedValues() throws Throwable { MixedValues mv = new MixedValues(P, L, PATH, "mixed", "types"); MethodHandleTest test = - new MethodHandleTest("MethodHandleTest$MixedValues", mv, "p", "l", "mutablePath", "list", "nfp"); + new MethodHandleTest("MixedValues", mv, "p", "l", "mutablePath", "list", "nfp"); test.run(); Point p = Point.makePoint(100, 200); @@ -306,22 +304,4 @@ return (f.getModifiers() & 0x00000100) == 0x00000100; } - static class MixedValues { - static Point staticPoint = Point.makePoint(10, 10); - static Line staticLine; // LW1 allows null static value field - Point p; - Line l; - MutablePath mutablePath; - List list; - __NotFlattened Point nfp; - - public MixedValues(Point p, Line l, MutablePath path, String... names) { - this.p = p; - this.l = l; - this.mutablePath = path; - this.list = List.of(names); - this.nfp = p; - } - } - } --- /dev/null 2018-07-17 10:29:59.000000000 -0700 +++ new/test/jdk/valhalla/valuetypes/ArrayElementVarHandleTest.java 2018-07-17 10:29:58.000000000 -0700 @@ -0,0 +1,122 @@ +/* + * 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. + */ + + +/* + * @test + * @summary test VarHandle on value array + * @compile -XDallowFlattenabilityModifiers Point.java Line.java MutablePath.java MixedValues.java + * @run testng/othervm -XX:+EnableValhalla -XX:+ValueArrayFlatten ArrayElementVarHandleTest + * @run testng/othervm -XX:+EnableValhalla -XX:-ValueArrayFlatten ArrayElementVarHandleTest + */ + +import java.lang.invoke.*; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +public class ArrayElementVarHandleTest { + private static final Point P = Point.makePoint(10, 20); + private static final Line L = Line.makeLine(10, 20, 30, 40); + private static final MutablePath PATH = MutablePath.makePath(10, 20, 30, 40); + + @DataProvider(name="arrayTests") + static Object[][] arrayTests() { + return new Object[][]{ + new Object[] { Point[].class, + new Point[] { Point.makePoint(1, 2), + Point.makePoint(10, 20), + Point.makePoint(100, 200)}}, + new Object[] { Line[].class, + new Line[] { Line.makeLine(1, 2, 3, 4), + Line.makeLine(10, 20, 30, 40), + Line.makeLine(15, 25, 35, 45), + Line.makeLine(20, 30, 40, 50)}}, + new Object[] { MutablePath[].class, + new MutablePath[] { MutablePath.makePath(1, 2, 3, 4), + MutablePath.makePath(10, 20, 30, 40), + MutablePath.makePath(15, 25, 35, 45), + MutablePath.makePath(20, 30, 40, 50)}}, + new Object[] { MixedValues[].class, + new MixedValues[] { new MixedValues(P, L, PATH, "mixed", "values")}}, + }; + } + + @Test(dataProvider="arrayTests") + public void set(Class arrayType, Object[] elements) throws Throwable { + VarHandle vh = MethodHandles.arrayElementVarHandle(arrayType); + MethodHandle ctor = MethodHandles.arrayConstructor(arrayType); + Object[] array = (Object[])ctor.invoke(elements.length); + for (int i=0; i < elements.length; i++) { + vh.set(array, i, elements[i]); + } + for (int i=0; i < elements.length; i++) { + Object v = (Object)vh.get(array, i); + assertEquals(v, elements[i]); + } + } + + @Test(dataProvider="arrayTests") + public void setVolatile(Class arrayType, Object[] elements) throws Throwable { + VarHandle vh = MethodHandles.arrayElementVarHandle(arrayType); + MethodHandle ctor = MethodHandles.arrayConstructor(arrayType); + Object[] array = (Object[])ctor.invoke(elements.length); + for (int i=0; i < elements.length; i++) { + vh.setVolatile(array, i, elements[i]); + } + for (int i=0; i < elements.length; i++) { + Object v = (Object)vh.getVolatile(array, i); + assertEquals(v, elements[i]); + } + } + + @Test(dataProvider="arrayTests") + public void setOpaque(Class arrayType, Object[] elements) throws Throwable { + VarHandle vh = MethodHandles.arrayElementVarHandle(arrayType); + MethodHandle ctor = MethodHandles.arrayConstructor(arrayType); + Object[] array = (Object[])ctor.invoke(elements.length); + for (int i=0; i < elements.length; i++) { + vh.setOpaque(array, i, elements[i]); + } + for (int i=0; i < elements.length; i++) { + Object v = (Object)vh.getOpaque(array, i); + assertEquals(v, elements[i]); + } + } + + @Test(dataProvider="arrayTests") + public void getAndSet(Class arrayType, Object[] elements) throws Throwable { + VarHandle vh = MethodHandles.arrayElementVarHandle(arrayType); + MethodHandle ctor = MethodHandles.arrayConstructor(arrayType); + Object[] array = (Object[])ctor.invoke(elements.length); + for (int i=0; i < elements.length; i++) { + Object o = vh.getAndSet(array, i, elements[i]); + } + for (int i=0; i < elements.length; i++) { + Object v = (Object)vh.get(array, i); + assertEquals(v, elements[i]); + } + } +} --- /dev/null 2018-07-17 10:30:00.000000000 -0700 +++ new/test/jdk/valhalla/valuetypes/MixedValues.java 2018-07-17 10:29:59.000000000 -0700 @@ -0,0 +1,42 @@ +/* + * 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. + */ + +import java.util.List; + +public class MixedValues { + static Point staticPoint = Point.makePoint(10, 10); + static Line staticLine; // LW1 allows null static value field + Point p; + Line l; + MutablePath mutablePath; + List list; + __NotFlattened Point nfp; + + public MixedValues(Point p, Line l, MutablePath path, String... names) { + this.p = p; + this.l = l; + this.mutablePath = path; + this.list = List.of(names); + this.nfp = p; + } +}