Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lworld] Field::get should return default value instead of null on non-flattened inline field #314

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -35,7 +35,7 @@ class UnsafeObjectFieldAccessorImpl extends UnsafeFieldAccessorImpl {
public Object get(Object obj) throws IllegalArgumentException {
ensureObj(obj);
return isFlattened() ? unsafe.getValue(obj, fieldOffset, field.getType())
: unsafe.getReference(obj, fieldOffset);
: unsafe.getReference(obj, fieldOffset, field.getType());
}

public boolean getBoolean(Object obj) throws IllegalArgumentException {
@@ -37,7 +37,7 @@
public Object get(Object obj) throws IllegalArgumentException {
ensureObj(obj);
return isFlattened() ? unsafe.getValue(obj, fieldOffset, field.getType())
: unsafe.getReferenceVolatile(obj, fieldOffset);
: unsafe.getReferenceVolatile(obj, fieldOffset, field.getType());
}

public boolean getBoolean(Object obj) throws IllegalArgumentException {
@@ -83,7 +83,7 @@ public void set(Object obj, Object value)
if (isFlattened()) {
unsafe.putValue(obj, fieldOffset, field.getType(), value);
} else {
unsafe.putReferenceVolatile(obj, fieldOffset, value);
unsafe.putReferenceVolatile(obj, fieldOffset, value);
}
}

@@ -36,7 +36,7 @@

public Object get(Object obj) throws IllegalArgumentException {
return isFlattened() ? unsafe.getValue(obj, fieldOffset, field.getType())
: unsafe.getReferenceVolatile(base, fieldOffset);
: unsafe.getReferenceVolatile(base, fieldOffset, field.getType());
}

public boolean getBoolean(Object obj) throws IllegalArgumentException {
@@ -81,7 +81,7 @@ public void set(Object obj, Object value)
if (isFlattened()) {
unsafe.putValue(base, fieldOffset, field.getType(), value);
} else {
unsafe.putReferenceVolatile(base, fieldOffset, value);
unsafe.putReferenceVolatile(base, fieldOffset, value);
}
}

@@ -34,7 +34,7 @@ class UnsafeStaticObjectFieldAccessorImpl extends UnsafeStaticFieldAccessorImpl

public Object get(Object obj) throws IllegalArgumentException {
return isFlattened() ? unsafe.getValue(base, fieldOffset, field.getType())
: unsafe.getReference(base, fieldOffset);
: unsafe.getReference(base, fieldOffset, field.getType());
}

public boolean getBoolean(Object obj) throws IllegalArgumentException {
@@ -79,7 +79,7 @@ public void set(Object obj, Object value)
if (isFlattened()) {
unsafe.putValue(obj, fieldOffset, field.getType(), value);
} else {
unsafe.putReference(base, fieldOffset, value);
unsafe.putReference(base, fieldOffset, value);
}
}

@@ -0,0 +1,159 @@
/*
* Copyright (c) 2021, 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
* @compile --enable-preview --source ${jdk.version} UninitializedInlineValueTest.java
* @run testng/othervm --enable-preview -XX:InlineFieldMaxFlatSize=128 UninitializedInlineValueTest
* @run testng/othervm --enable-preview -XX:InlineFieldMaxFlatSize=0 UninitializedInlineValueTest
* @summary Test reflection and method handle on accessing a field of inline type
* that may be flattened or non-flattened
*/

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;

import org.testng.annotations.Test;
import static org.testng.Assert.*;

public class UninitializedInlineValueTest {
static inline class EmptyInline {
public boolean isEmpty() {
return true;
}
}

static inline class InlineValue {
Object o;
EmptyInline empty;
InlineValue() {
this.o = null;
this.empty = new EmptyInline();
}
}

static class MutableValue {
Object o;
EmptyInline empty;
volatile EmptyInline vempty;
}

@Test
public void emptyInlineClass() throws ReflectiveOperationException {
EmptyInline e = new EmptyInline();
Field[] fields = e.getClass().getDeclaredFields();
assertTrue(fields.length == 0);
}

@Test
public void testInlineValue() throws ReflectiveOperationException {
InlineValue v = new InlineValue();
Field f0 = v.getClass().getDeclaredField("o");
Object o = f0.get(v);
assertTrue(o == null);

// field of inline type must be non-null
Field f1 = v.getClass().getDeclaredField("empty");
assertTrue(f1.getType() == EmptyInline.class);
EmptyInline empty = (EmptyInline)f1.get(v);
assertTrue(empty.isEmpty()); // test if empty is non-null with default value
}

@Test
public void testMutableValue() throws ReflectiveOperationException {
MutableValue v = new MutableValue();
Field f0 = v.getClass().getDeclaredField("o");
f0.set(v, null);
assertTrue( f0.get(v) == null);

// field of inline type must be non-null
Field f1 = v.getClass().getDeclaredField("empty");
assertTrue(f1.getType() == EmptyInline.class);
EmptyInline empty = (EmptyInline)f1.get(v);
assertTrue(empty.isEmpty()); // test if empty is non-null with default value

Field f2 = v.getClass().getDeclaredField("vempty");
assertTrue(f2.getType() == EmptyInline.class);
EmptyInline vempty = (EmptyInline)f2.get(v);
assertTrue(vempty.isEmpty()); // test if vempty is non-null with default value

f1.set(v, new EmptyInline());
assertTrue((EmptyInline)f1.get(v) == new EmptyInline());
f2.set(v, new EmptyInline());
assertTrue((EmptyInline)f2.get(v) == new EmptyInline());
}

@Test
public void testMethodHandleInlineValue() throws Throwable {
InlineValue v = new InlineValue();
MethodHandle mh = MethodHandles.lookup().findGetter(InlineValue.class, "empty", EmptyInline.class);
EmptyInline empty = (EmptyInline) mh.invokeExact(v);
assertTrue(empty.isEmpty()); // test if empty is non-null with default value
}

@Test
public void testMethodHandleMutableValue() throws Throwable {
MutableValue v = new MutableValue();
MethodHandle getter = MethodHandles.lookup().findGetter(MutableValue.class, "empty", EmptyInline.class);
EmptyInline empty = (EmptyInline) getter.invokeExact(v);
assertTrue(empty.isEmpty()); // test if empty is non-null with default value

MethodHandle getter1 = MethodHandles.lookup().findGetter(MutableValue.class, "vempty", EmptyInline.class);
EmptyInline vempty = (EmptyInline) getter1.invokeExact(v);
assertTrue(vempty.isEmpty()); // test if vempty is non-null with default value

MethodHandle setter = MethodHandles.lookup().findSetter(MutableValue.class, "empty", EmptyInline.class);
setter.invokeExact(v, new EmptyInline());
empty = (EmptyInline) getter.invokeExact(v);
assertTrue(empty == new EmptyInline());

MethodHandle setter1 = MethodHandles.lookup().findSetter(MutableValue.class, "vempty", EmptyInline.class);
setter1.invokeExact(v, new EmptyInline());
vempty = (EmptyInline) getter1.invokeExact(v);
assertTrue(vempty == new EmptyInline());
}

@Test(expectedExceptions = { IllegalAccessException.class})
public void noWriteAccess() throws ReflectiveOperationException {
InlineValue v = new InlineValue();
Field f = v.getClass().getDeclaredField("empty");
f.set(v, null);
}

@Test(expectedExceptions = { NullPointerException.class})
public void nonNullableField_reflection() throws ReflectiveOperationException {
MutableValue v = new MutableValue();
Field f = v.getClass().getDeclaredField("empty");
f.set(v, null);
}

@Test(expectedExceptions = { NullPointerException.class})
public void nonNullableField_MethodHandle() throws Throwable {
MutableValue v = new MutableValue();
MethodHandle mh = MethodHandles.lookup().findSetter(MutableValue.class, "empty", EmptyInline.class);
EmptyInline.ref e = null;
EmptyInline empty = (EmptyInline) mh.invokeExact(v, (EmptyInline)e);
}
}