Skip to content

Commit eae2c52

Browse files
committed
8352613: [lworld] New Unsafe API for special array creation needed by VarHandle
Reviewed-by: mcimadamore
1 parent c394d17 commit eae2c52

File tree

3 files changed

+130
-0
lines changed

3 files changed

+130
-0
lines changed

src/hotspot/share/prims/unsafe.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "jni.h"
3333
#include "jvm.h"
3434
#include "memory/allocation.inline.hpp"
35+
#include "memory/oopFactory.hpp"
3536
#include "memory/resourceArea.hpp"
3637
#include "logging/log.hpp"
3738
#include "logging/logStream.hpp"
@@ -405,6 +406,33 @@ UNSAFE_ENTRY(jint, Unsafe_FieldLayout(JNIEnv *env, jobject unsafe, jobject field
405406
}
406407
} UNSAFE_END
407408

409+
UNSAFE_ENTRY(jarray, Unsafe_NewSpecialArray(JNIEnv *env, jobject unsafe, jclass elmClass, jint len, jint layoutKind)) {
410+
oop mirror = JNIHandles::resolve_non_null(elmClass);
411+
Klass* klass = java_lang_Class::as_Klass(mirror);
412+
klass->initialize(CHECK_NULL);
413+
if (len < 0) {
414+
THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Array length is negative");
415+
}
416+
if (klass->is_identity_class()) {
417+
THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Element class is not a value class");
418+
}
419+
if (klass->is_abstract()) {
420+
THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Element class is abstract");
421+
}
422+
LayoutKind lk = static_cast<LayoutKind>(layoutKind);
423+
if (lk <= LayoutKind::REFERENCE || lk >= LayoutKind::UNKNOWN) {
424+
THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Invalid layout kind");
425+
}
426+
InlineKlass* vk = InlineKlass::cast(klass);
427+
// WARNING: test below will need modifications when flat layouts supported for fields
428+
// but not for arrays are introduce (NULLABLE_NON_ATOMIC_FLAT for instance)
429+
if (!UseArrayFlattening || !vk->is_layout_supported(lk)) {
430+
THROW_MSG_NULL(vmSymbols::java_lang_UnsupportedOperationException(), "Layout not supported");
431+
}
432+
oop array = oopFactory::new_flatArray(vk, len, lk, CHECK_NULL);
433+
return (jarray) JNIHandles::make_local(THREAD, array);
434+
} UNSAFE_END
435+
408436
UNSAFE_ENTRY(jboolean, Unsafe_IsFlatArray(JNIEnv *env, jobject unsafe, jclass c)) {
409437
Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(c));
410438
return k->is_flatArray_klass();
@@ -1114,6 +1142,7 @@ static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = {
11141142
{CC "nullMarkerOffset0", CC "(" OBJ ")I", FN_PTR(Unsafe_NullMarkerOffset)},
11151143
{CC "arrayLayout0", CC "(" OBJ ")I", FN_PTR(Unsafe_ArrayLayout)},
11161144
{CC "fieldLayout0", CC "(" OBJ ")I", FN_PTR(Unsafe_FieldLayout)},
1145+
{CC "newSpecialArray", CC "(" CLS "II)[" OBJ, FN_PTR(Unsafe_NewSpecialArray)},
11171146
{CC "getValue", CC "(" OBJ "J" CLS ")" OBJ, FN_PTR(Unsafe_GetValue)},
11181147
{CC "getFlatValue", CC "(" OBJ "JI" CLS ")" OBJ, FN_PTR(Unsafe_GetFlatValue)},
11191148
{CC "putValue", CC "(" OBJ "J" CLS OBJ ")V", FN_PTR(Unsafe_PutValue)},

src/java.base/share/classes/jdk/internal/misc/Unsafe.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,9 @@ public int fieldLayout(Field f) {
259259

260260
private native int fieldLayout0(Object o);
261261

262+
public native Object[] newSpecialArray(Class<?> componentType,
263+
int length, int layoutKind);
264+
262265
/**
263266
* Returns true if the given class is a flattened array.
264267
*/

test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArraysTest.java

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,15 @@
2323

2424
package runtime.valhalla.inlinetypes;
2525

26+
import jdk.internal.misc.Unsafe;
2627
import jdk.internal.value.ValueClass;
2728
import jdk.internal.vm.annotation.ImplicitlyConstructible;
2829
import jdk.internal.vm.annotation.LooselyConsistentValue;
2930
import jdk.internal.vm.annotation.NullRestricted;
3031
import java.lang.management.ManagementFactory;
3132
import java.lang.management.RuntimeMXBean;
3233
import java.lang.reflect.Array;
34+
import java.lang.reflect.Field;
3335
import java.lang.reflect.InvocationTargetException;
3436
import java.lang.reflect.Method;
3537
import java.util.Arrays;
@@ -43,8 +45,10 @@
4345
/*
4446
* @test FlatArraysTest
4547
* @summary Plain array test for Inline Types
48+
* @requires vm.flagless
4649
* @modules java.base/jdk.internal.value
4750
* java.base/jdk.internal.vm.annotation
51+
* java.base/jdk.internal.misc
4852
* @library /test/lib
4953
* @enablePreview
5054
* @compile --source 25 FlatArraysTest.java
@@ -54,6 +58,7 @@
5458

5559
public class FlatArraysTest {
5660
static final int ARRAY_SIZE = 100;
61+
static final Unsafe UNSAFE = Unsafe.getUnsafe();
5762

5863
@ImplicitlyConstructible
5964
@LooselyConsistentValue
@@ -451,10 +456,103 @@ static void testArrayAccesses() throws NoSuchMethodException, InstantiationExcep
451456
}
452457
}
453458

459+
@ImplicitlyConstructible
460+
static value class AtomicValue {
461+
int i = 0;
462+
}
463+
464+
static value class FieldsHolder {
465+
@NullRestricted
466+
SmallValue sv = new SmallValue();
467+
468+
@NullRestricted
469+
AtomicValue av = new AtomicValue();
470+
471+
AtomicValue nav = new AtomicValue();
472+
}
473+
474+
static void testSpecialArrayLayoutFromArray(Object[] array, boolean expectException) {
475+
int lk = UNSAFE.arrayLayout(array.getClass());
476+
boolean exception = false;
477+
try {
478+
Object[] newArray = UNSAFE.newSpecialArray(array.getClass().getComponentType(), 10, lk);
479+
int newLk = UNSAFE.arrayLayout(newArray.getClass());
480+
assertEquals(newLk, lk);
481+
} catch(IllegalArgumentException e) {
482+
e.printStackTrace();
483+
exception = true;
484+
}
485+
assertEquals(exception, expectException, "Exception not matching expectations");
486+
}
487+
488+
static void testSpecialArrayFromFieldLayout(Class c, int layout, boolean expectException) {
489+
boolean exception = false;
490+
try {
491+
Object[] array = UNSAFE.newSpecialArray(c, 10, layout);
492+
int lk = UNSAFE.arrayLayout(array.getClass());
493+
assertEquals(lk, layout);
494+
} catch (IllegalArgumentException e) {
495+
e.printStackTrace();
496+
throw new RuntimeException(e);
497+
} catch (UnsupportedOperationException e) {
498+
e.printStackTrace();
499+
exception = true;
500+
}
501+
assertEquals(exception, expectException, "Exception not matching expectations");
502+
}
503+
504+
static void testSpecialArrayCreation() {
505+
RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
506+
List<String> jvmArgs = runtimeMXBean.getInputArguments();
507+
boolean arrayFlatteningEnabled = true;
508+
for (String s : jvmArgs) {
509+
if (s.compareTo("-XX:-UseArrayFlattening") == 0) arrayFlatteningEnabled = false;
510+
}
511+
512+
// Test array creation from another array
513+
Object[] array0 = new SmallValue[10];
514+
testSpecialArrayLayoutFromArray(array0, true);
515+
if (arrayFlatteningEnabled) {
516+
Object[] array1 = ValueClass.newNullRestrictedArray(SmallValue.class, 10);
517+
testSpecialArrayLayoutFromArray(array1, false);
518+
Object[] array2 = ValueClass.newNullRestrictedAtomicArray(SmallValue.class, 10);
519+
testSpecialArrayLayoutFromArray(array2, false);
520+
Object[] array3 = ValueClass.newNullableAtomicArray(SmallValue.class, 10);
521+
testSpecialArrayLayoutFromArray(array3, false);
522+
}
523+
524+
// Test array creation from a field layout
525+
try {
526+
Class c = FieldsHolder.class;
527+
Field f0 = c.getDeclaredField("sv");
528+
int layout0 = UNSAFE.fieldLayout(f0);
529+
testSpecialArrayFromFieldLayout(f0.getType(), layout0, !arrayFlatteningEnabled);
530+
Field f1 = c.getDeclaredField("av");
531+
int layout1 = UNSAFE.fieldLayout(f1);
532+
testSpecialArrayFromFieldLayout(f1.getType(), layout1, !arrayFlatteningEnabled);
533+
Field f2 = c.getDeclaredField("nav");
534+
int layout2 = UNSAFE.fieldLayout(f2);
535+
testSpecialArrayFromFieldLayout(f2.getType(), layout2, !arrayFlatteningEnabled);
536+
} catch(NoSuchFieldException e) {
537+
e.printStackTrace();
538+
}
539+
540+
// Testing an invalid layout value
541+
boolean exception = false;
542+
try {
543+
UNSAFE.newSpecialArray(SmallValue.class, 10, 100);
544+
} catch(IllegalArgumentException e) {
545+
e.printStackTrace();
546+
exception = true;
547+
}
548+
assertEquals(exception, true, "Exception not received");
549+
}
550+
454551
public static void main(String[] args) throws NoSuchMethodException, InstantiationException,
455552
IllegalAccessException, InvocationTargetException {
456553
testArrayAccesses();
457554
testArrayCopy();
555+
testSpecialArrayCreation();
458556
}
459557

460558
}

0 commit comments

Comments
 (0)