Skip to content

Commit

Permalink
Insert Null value check if array component type is unknown during com…
Browse files Browse the repository at this point in the history
…pilation time

If the value being stored is NULL and the destination array
component is null restricted in runtime, a NPE is expected
to throw. Therefore, when the array component type is not
known to be identity type in compilation time, a NULLCHK
on store value is required.

Also add two test cases to test storing NULL into null restricted
array, and update the class name in the tests to primitive class
to reflect more accurately the type of the class.

Signed-off-by: Annabelle Huo <[email protected]>
  • Loading branch information
a7ehuo committed Oct 12, 2023
1 parent 4e1d1c6 commit e050899
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 44 deletions.
6 changes: 4 additions & 2 deletions runtime/compiler/optimizer/J9ValuePropagation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1182,8 +1182,10 @@ J9::ValuePropagation::constrainRecognizedMethod(TR::Node *node)
}

//TODO: Require the <nonNullableArrayNullStoreCheck> non-helper if !canSkipNonNullableArrayNullValueChecks(...)
if (canTransformUnflattenedArrayElementLoadStore &&
(isCompTypePrimVT != TR_no) &&
// If the value being stored is NULL and the destination array component is null restricted in runtime,
// a NPE is expected to throw. Therefore, when the array component type is not known to be identity type
// in compilation time, a NULLCHK on store value is required
if ((isCompTypePrimVT != TR_no) &&
(storeValueConstraint == NULL || !storeValueConstraint->isNonNullObject()))
{
flagsForTransform.set(ValueTypesHelperCallTransform::RequiresNullValueCheck);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,26 +357,26 @@ static public void testValueTypeArrayAssignments() throws Throwable {
}
}

static primitive class SomeVTClassWithDoubleField{
static primitive class SomePrimitiveClassWithDoubleField{
public double d;

SomeVTClassWithDoubleField(double x) {
SomePrimitiveClassWithDoubleField(double x) {
this.d = x;
}
}

static primitive class SomeVTClassWithFloatField{
static primitive class SomePrimitiveClassWithFloatField{
public float f;

SomeVTClassWithFloatField(float x) {
SomePrimitiveClassWithFloatField(float x) {
this.f = x;
}
}

static primitive class SomeVTClassWithLongField{
static primitive class SomePrimitiveClassWithLongField{
public long l;

SomeVTClassWithLongField(long x) {
SomePrimitiveClassWithLongField(long x) {
this.l = x;
}
}
Expand Down Expand Up @@ -409,11 +409,11 @@ interface SomeInterface1WithSingleImplementer {}

interface SomeInterface2WithSingleImplementer {}

static primitive class SomeVTClassImplIf implements SomeInterface1WithSingleImplementer {
static primitive class SomePrimitiveClassImplIf implements SomeInterface1WithSingleImplementer {
public double d;
public long l;

SomeVTClassImplIf(double val1, long val2) {
SomePrimitiveClassImplIf(double val1, long val2) {
this.d = val1;
this.l = val2;
}
Expand All @@ -439,37 +439,37 @@ static class SomeClassHolder {
SomeInterface2WithSingleImplementer data_5;

SomeClassHolder() {
data_1 = new SomeVTClassImplIf[ARRAY_LENGTH];
data_2 = new SomeVTClassImplIf[ARRAY_LENGTH];
data_1 = new SomePrimitiveClassImplIf[ARRAY_LENGTH];
data_2 = new SomePrimitiveClassImplIf[ARRAY_LENGTH];

data_3 = new SomeIdentityClassImplIf[ARRAY_LENGTH];
data_4 = new SomeIdentityClassImplIf[ARRAY_LENGTH];

data_5 = new SomeIdentityClassImplIf((double)(12345), (long)(12345));

for (int i = 0; i < ARRAY_LENGTH; i++) {
data_1[i] = new SomeVTClassImplIf((double)i, (long)i);
data_2[i] = new SomeVTClassImplIf((double)(i+1), (long)(i+1));
data_1[i] = new SomePrimitiveClassImplIf((double)i, (long)i);
data_2[i] = new SomePrimitiveClassImplIf((double)(i+1), (long)(i+1));

data_3[i] = data_5;
data_4[i] = new SomeIdentityClassImplIf((double)(i+1), (long)(i+1));
}
}
}

static void readArrayElementWithDoubleField(SomeVTClassWithDoubleField[] data) throws Throwable {
static void readArrayElementWithDoubleField(SomePrimitiveClassWithDoubleField[] data) throws Throwable {
for (int i=0; i<data.length; ++i) {
assertEquals(data[i].d, (double)i);
}
}

static void readArrayElementWithFloatField(SomeVTClassWithFloatField[] data) throws Throwable {
static void readArrayElementWithFloatField(SomePrimitiveClassWithFloatField[] data) throws Throwable {
for (int i=0; i<data.length; ++i) {
assertEquals(data[i].f, (float)i);
}
}

static void readArrayElementWithLongField(SomeVTClassWithLongField[] data) throws Throwable {
static void readArrayElementWithLongField(SomePrimitiveClassWithLongField[] data) throws Throwable {
for (int i=0; i<data.length; ++i) {
assertEquals(data[i].l, (long)i);
}
Expand All @@ -493,9 +493,9 @@ static void readArrayElementWithLongField(SomeIdentityClassWithLongField[] data)
}
}

static void readArrayElementWithSomeVTClassImplIf(SomeClassHolder holder) throws Throwable {
static void readArrayElementWithSomePrimitiveClassImplIf(SomeClassHolder holder) throws Throwable {
for (int i=0; i<holder.data_1.length; ++i) {
assertEquals(holder.data_1[i], new SomeVTClassImplIf((double)i, (long)i));
assertEquals(holder.data_1[i], new SomePrimitiveClassImplIf((double)i, (long)i));
}
}

Expand All @@ -505,7 +505,7 @@ static void readArrayElementWithSomeIdentityClassImplIf(SomeClassHolder holder)
}
}

static void writeArrayElementWithDoubleField(SomeVTClassWithDoubleField[] srcData, SomeVTClassWithDoubleField[] dstData) throws Throwable {
static void writeArrayElementWithDoubleField(SomePrimitiveClassWithDoubleField[] srcData, SomePrimitiveClassWithDoubleField[] dstData) throws Throwable {
for (int i=0; i<dstData.length; ++i) {
dstData[i] = srcData[i];
}
Expand All @@ -515,7 +515,7 @@ static void writeArrayElementWithDoubleField(SomeVTClassWithDoubleField[] srcDat
}
}

static void writeArrayElementWithFloatField(SomeVTClassWithFloatField[] srcData, SomeVTClassWithFloatField[] dstData) throws Throwable {
static void writeArrayElementWithFloatField(SomePrimitiveClassWithFloatField[] srcData, SomePrimitiveClassWithFloatField[] dstData) throws Throwable {
for (int i=0; i<dstData.length; ++i) {
dstData[i] = srcData[i];
}
Expand All @@ -525,7 +525,7 @@ static void writeArrayElementWithFloatField(SomeVTClassWithFloatField[] srcData,
}
}

static void writeArrayElementWithLongField(SomeVTClassWithLongField[] srcData, SomeVTClassWithLongField[] dstData) throws Throwable {
static void writeArrayElementWithLongField(SomePrimitiveClassWithLongField[] srcData, SomePrimitiveClassWithLongField[] dstData) throws Throwable {
for (int i=0; i<dstData.length; ++i) {
dstData[i] = srcData[i];
}
Expand Down Expand Up @@ -565,13 +565,13 @@ static void writeArrayElementWithLongField(SomeIdentityClassWithLongField[] srcD
}
}

static void writeArrayElementWithSomeVTClassImplIf(SomeClassHolder holder) throws Throwable {
static void writeArrayElementWithSomePrimitiveClassImplIf(SomeClassHolder holder) throws Throwable {
for (int i=0; i<holder.data_1.length; ++i) {
holder.data_1[i] = holder.data_2[i];
}

for (int i=0; i<holder.data_1.length; ++i) {
assertEquals(holder.data_1[i], new SomeVTClassImplIf((double)(i+1), (long)(i+1)));
assertEquals(holder.data_1[i], new SomePrimitiveClassImplIf((double)(i+1), (long)(i+1)));
}
}

Expand All @@ -588,9 +588,9 @@ static void writeArrayElementWithSomeIdentityClassImplIf(SomeClassHolder holder)
@Test(priority=1,invocationCount=2)
static public void testValueTypeAaload() throws Throwable {
int ARRAY_LENGTH = 10;
SomeVTClassWithDoubleField[] data1 = new SomeVTClassWithDoubleField[ARRAY_LENGTH];
SomeVTClassWithFloatField[] data2 = new SomeVTClassWithFloatField[ARRAY_LENGTH];
SomeVTClassWithLongField[] data3 = new SomeVTClassWithLongField[ARRAY_LENGTH];
SomePrimitiveClassWithDoubleField[] data1 = new SomePrimitiveClassWithDoubleField[ARRAY_LENGTH];
SomePrimitiveClassWithFloatField[] data2 = new SomePrimitiveClassWithFloatField[ARRAY_LENGTH];
SomePrimitiveClassWithLongField[] data3 = new SomePrimitiveClassWithLongField[ARRAY_LENGTH];

SomeIdentityClassWithDoubleField[] data4 = new SomeIdentityClassWithDoubleField[ARRAY_LENGTH];
SomeIdentityClassWithFloatField[] data5 = new SomeIdentityClassWithFloatField[ARRAY_LENGTH];
Expand All @@ -599,9 +599,9 @@ static public void testValueTypeAaload() throws Throwable {
SomeClassHolder holder = new SomeClassHolder();

for (int i=0; i<ARRAY_LENGTH; ++i) {
data1[i] = new SomeVTClassWithDoubleField((double)i);
data2[i] = new SomeVTClassWithFloatField((float)i);
data3[i] = new SomeVTClassWithLongField((long)i);
data1[i] = new SomePrimitiveClassWithDoubleField((double)i);
data2[i] = new SomePrimitiveClassWithFloatField((float)i);
data3[i] = new SomePrimitiveClassWithLongField((long)i);

data4[i] = new SomeIdentityClassWithDoubleField((double)i);
data5[i] = new SomeIdentityClassWithFloatField((float)i);
Expand All @@ -616,19 +616,19 @@ static public void testValueTypeAaload() throws Throwable {
readArrayElementWithFloatField(data5);
readArrayElementWithLongField(data6);

readArrayElementWithSomeVTClassImplIf(holder);
readArrayElementWithSomePrimitiveClassImplIf(holder);
readArrayElementWithSomeIdentityClassImplIf(holder);
}

@Test(priority=1,invocationCount=2)
static public void testValueTypeAastore() throws Throwable {
int ARRAY_LENGTH = 10;
SomeVTClassWithDoubleField[] srcData1 = new SomeVTClassWithDoubleField[ARRAY_LENGTH];
SomeVTClassWithDoubleField[] dstData1 = new SomeVTClassWithDoubleField[ARRAY_LENGTH];
SomeVTClassWithFloatField[] srcData2 = new SomeVTClassWithFloatField[ARRAY_LENGTH];
SomeVTClassWithFloatField[] dstData2 = new SomeVTClassWithFloatField[ARRAY_LENGTH];
SomeVTClassWithLongField[] srcData3 = new SomeVTClassWithLongField[ARRAY_LENGTH];
SomeVTClassWithLongField[] dstData3 = new SomeVTClassWithLongField[ARRAY_LENGTH];
SomePrimitiveClassWithDoubleField[] srcData1 = new SomePrimitiveClassWithDoubleField[ARRAY_LENGTH];
SomePrimitiveClassWithDoubleField[] dstData1 = new SomePrimitiveClassWithDoubleField[ARRAY_LENGTH];
SomePrimitiveClassWithFloatField[] srcData2 = new SomePrimitiveClassWithFloatField[ARRAY_LENGTH];
SomePrimitiveClassWithFloatField[] dstData2 = new SomePrimitiveClassWithFloatField[ARRAY_LENGTH];
SomePrimitiveClassWithLongField[] srcData3 = new SomePrimitiveClassWithLongField[ARRAY_LENGTH];
SomePrimitiveClassWithLongField[] dstData3 = new SomePrimitiveClassWithLongField[ARRAY_LENGTH];

SomeIdentityClassWithDoubleField[] srcData4 = new SomeIdentityClassWithDoubleField[ARRAY_LENGTH];
SomeIdentityClassWithDoubleField[] dstData4 = new SomeIdentityClassWithDoubleField[ARRAY_LENGTH];
Expand All @@ -640,13 +640,13 @@ static public void testValueTypeAastore() throws Throwable {
SomeClassHolder holder = new SomeClassHolder();

for (int i=0; i<ARRAY_LENGTH; ++i) {
srcData1[i] = new SomeVTClassWithDoubleField((double)(i+1));
srcData2[i] = new SomeVTClassWithFloatField((float)(i+1));
srcData3[i] = new SomeVTClassWithLongField((long)(i+1));
srcData1[i] = new SomePrimitiveClassWithDoubleField((double)(i+1));
srcData2[i] = new SomePrimitiveClassWithFloatField((float)(i+1));
srcData3[i] = new SomePrimitiveClassWithLongField((long)(i+1));

dstData1[i] = new SomeVTClassWithDoubleField((double)i);
dstData2[i] = new SomeVTClassWithFloatField((float)i);
dstData3[i] = new SomeVTClassWithLongField((long)i);
dstData1[i] = new SomePrimitiveClassWithDoubleField((double)i);
dstData2[i] = new SomePrimitiveClassWithFloatField((float)i);
dstData3[i] = new SomePrimitiveClassWithLongField((long)i);

srcData4[i] = new SomeIdentityClassWithDoubleField((double)(i+1));
srcData5[i] = new SomeIdentityClassWithFloatField((float)(i+1));
Expand All @@ -665,7 +665,7 @@ static public void testValueTypeAastore() throws Throwable {
writeArrayElementWithFloatField(srcData5, dstData5);
writeArrayElementWithLongField(srcData6, dstData6);

writeArrayElementWithSomeVTClassImplIf(holder);
writeArrayElementWithSomePrimitiveClassImplIf(holder);
writeArrayElementWithSomeIdentityClassImplIf(holder);
}

Expand Down Expand Up @@ -713,4 +713,41 @@ static public void testEmptyValueArrayElement() {
copyBetweenEmptyValArrays(valArr1, valArr2);
compareEmptyValArrays(valArr1, valArr2);
}

static void arrayElementStoreNull(Object[] arr, int index) {
arr[index] = null;
}

static void arrayElementStore(Object[] arr, int index, Object obj) {
arr[index] = obj;
}

@Test(priority=1,invocationCount=2)
static public void testStoreNullToNullRestrictedArrayElement1() throws Throwable {
int ARRAY_LENGTH = 10;
SomePrimitiveClassWithDoubleField[] dstData = new SomePrimitiveClassWithDoubleField[ARRAY_LENGTH];

try {
arrayElementStoreNull(dstData, ARRAY_LENGTH/2);
} catch (NullPointerException npe) {
return; /* pass */
}

Assert.fail("Expect a NullPointerException. No exception or wrong kind of exception thrown");
}

@Test(priority=1,invocationCount=2)
static public void testStoreNullToNullRestrictedArrayElement2() throws Throwable {
int ARRAY_LENGTH = 10;
SomePrimitiveClassWithDoubleField[] dstData = new SomePrimitiveClassWithDoubleField[ARRAY_LENGTH];
Object obj = null;

try {
arrayElementStore(dstData, ARRAY_LENGTH/2, obj);
} catch (NullPointerException npe) {
return; /* pass */
}

Assert.fail("Expect a NullPointerException. No exception or wrong kind of exception thrown");
}
}

0 comments on commit e050899

Please sign in to comment.