openj9 icon indicating copy to clipboard operation
openj9 copied to clipboard

Valhalla tests should use migrated value classes

Open theresa-m opened this issue 1 year ago • 1 comments

Jep 401 migrates existing ValueBased classes (such as java/lang/Integer) to be value classes. Right now these classes are compiled into jdk/lib/valueclasses/java.base-valueclasses.jar and can be used by patching them into the java.base module --patch-module java.base=jdk/lib/valueclasses/java.base-valueclasses.jar

To complete this issue:

  • [ ] Update Valhalla tests to use ValueBased classes and address test failures
  • [ ] Add tests to verify that migrated classes are being treated as value classes: a = new Integer(1); b= new Integer(1); a == b should be true. a and b should have the same hashcode. synchronized(a) is not allowed. a.getClass().isValue() should be true.
  • [ ] Verify that the updates would work on a grinder job

theresa-m avatar Oct 18 '24 18:10 theresa-m

Issue Number: 20386 Status: Open Recommended Components: comp:test, comp:vm, comp:build Recommended Assignees: hangshao0, jasonfengj9, theresa-m

github-actions[bot] avatar Oct 18 '24 18:10 github-actions[bot]

This is currently blocked by https://github.com/eclipse-openj9/openj9/issues/20372

theresa-m avatar Nov 04 '24 16:11 theresa-m

There is another MethodHandles error when trying to enable the use of classes in java.base-valueclasses.jar:

Exception in thread "main" java.lang.InternalError: java.lang.NoSuchFieldException: no such field: java.util.concurrent.atomic.Striped64.base/long/getField
	at java.base/jdk.internal.invoke.MhUtil.findVarHandle(MhUtil.java:62)
	at java.base/jdk.internal.invoke.MhUtil.findVarHandle(MhUtil.java:52)
	at java.base/java.util.concurrent.atomic.Striped64.<clinit>(Striped64.java:381)
	at java.base/java.util.concurrent.ConcurrentSkipListMap.addCount(ConcurrentSkipListMap.java:439)
	at java.base/java.util.concurrent.ConcurrentSkipListMap.doPut(ConcurrentSkipListMap.java:683)
	at java.base/java.util.concurrent.ConcurrentSkipListMap.putIfAbsent(ConcurrentSkipListMap.java:1789)
	at java.base/java.util.concurrent.ConcurrentSkipListSet.add(ConcurrentSkipListSet.java:240)
	at java.base/java.net.InetAddress$NameServiceAddresses.get(InetAddress.java:1193)
	at java.base/java.net.InetAddress.getAllByName0(InetAddress.java:1812)
	at java.base/java.net.InetAddress.getLocalHost(InetAddress.java:1925)
	at org.testng.reporters.JUnitXMLReporter.generateReport(JUnitXMLReporter.java:152)
	at org.testng.reporters.JUnitXMLReporter.onFinish(JUnitXMLReporter.java:112)
	at org.testng.TestRunner.fireEvent(TestRunner.java:772)
	at org.testng.TestRunner.afterRun(TestRunner.java:741)
	at org.testng.TestRunner.run(TestRunner.java:509)
	at org.testng.SuiteRunner.runTest(SuiteRunner.java:455)
	at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450)
	at org.testng.SuiteRunner.privateRun(SuiteRunner.java:415)
	at org.testng.SuiteRunner.run(SuiteRunner.java:364)
	at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
	at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84)
	at org.testng.TestNG.runSuitesSequentially(TestNG.java:1208)
	at org.testng.TestNG.runSuitesLocally(TestNG.java:1137)
	at org.testng.TestNG.runSuites(TestNG.java:1049)
	at org.testng.TestNG.run(TestNG.java:1017)
	at org.testng.TestNG.privateMain(TestNG.java:1354)
	at org.testng.TestNG.main(TestNG.java:1323)
Caused by: java.lang.NoSuchFieldException: no such field: java.util.concurrent.atomic.Striped64.base/long/getField
	at java.base/java.lang.invoke.MemberName.makeAccessException(MemberName.java:936)
	at java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1013)
	at java.base/java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:3744)
	at java.base/java.lang.invoke.MethodHandles$Lookup.findVarHandle(MethodHandles.java:3192)
	at java.base/jdk.internal.invoke.MhUtil.findVarHandle(MhUtil.java:60)
	... 26 more
Caused by: java.lang.NoSuchFieldError
	at java.base/java.lang.invoke.MethodHandleNatives.resolve(Native Method)
	at java.base/java.lang.invoke.MemberName$Factory.resolve(MemberName.java:981)
	at java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1010)
	... 29 more

theresa-m avatar Nov 13 '24 17:11 theresa-m

The native implementation of MethodHandleNatives.resolve() is Java_java_lang_invoke_MethodHandleNatives_resolve(). The NoSuchFieldError is likely from: https://github.com/eclipse-openj9/openj9/blob/2583a83f21350465715f015fb407481112063c94/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp#L1394. You can look at why we entered the exception case. May be declaringClass is NULL.

hangshao0 avatar Nov 13 '24 21:11 hangshao0

I created a small program to reproduce this and its not related to migrated value classes, and only happens when an abstract class inherits from an abstract value class. Also finding classes seems to work but primitives are failing.

I've confirmed that the field is found but the offset is 0 https://github.com/eclipse-openj9/openj9/blob/2583a83f21350465715f015fb407481112063c94/runtime/vm/resolvefield.cpp#L224.

The result never gets set here because the offset (which eventually sets the value of target) is 0. https://github.com/eclipse-openj9/openj9/blob/2583a83f21350465715f015fb407481112063c94/runtime/jcl/common/java_lang_invoke_MethodHandleNatives.cpp#L1383

The offset is 8 when CAbsVal is not a value class.

import java.lang.invoke.MethodHandles;
import jdk.internal.invoke.MhUtil;
class Test {
        public static void main(String[] args) throws Throwable {
                C m = new C();
        }
}


// error happens when this is a value class
abstract value class CAbsVal {}

abstract class CAbs extends CAbsVal {
        Object o;
        long l;
        static {
                MethodHandles.Lookup l1 = MethodHandles.lookup();
                MhUtil.findVarHandle(l1, "o", Object.class); // this is okay
                MhUtil.findVarHandle(l1, "l", long.class); // this fails
        }
}

class C extends CAbs {}

theresa-m avatar Nov 14 '24 21:11 theresa-m

For value classes, there is no lockword between the object header and the first field. So it is possible that the first field starts at offset 0.

MhUtil.findVarHandle(l1, "o", Object.class); // this is okay MhUtil.findVarHandle(l1, "l", long.class); // this fails

Are you running with -Xnocompressedrefs ? OpenJ9 will put field long l before Object o in -Xnocompressedrefs mode. In compressedrefs mode, field Object o will be put before long l, so I expect MhUtil.findVarHandle(l1, "o", Object.class) to fail.

hangshao0 avatar Nov 15 '24 15:11 hangshao0

I see, thanks. Yes I'm running with -Xnocompressedrefs. I tried with a compressed refs build and it does fail on Object o.

theresa-m avatar Nov 15 '24 18:11 theresa-m

I added the option to openjdk test runs and re-enabled passing tests. Some of the passing tests are due to extensions updates and other unrelated changes. https://github.com/ibmruntimes/openj9-openjdk-jdk.valuetypes/pull/14/commits/79671f4f53c5c59333e488ead333656347bef17a

There are no new openjdk test failures that need addressing so I am closing this issue as resolved.

This is related to https://github.com/eclipse-openj9/openj9/issues/13182 and https://github.com/eclipse-openj9/openj9/issues/20404

theresa-m avatar Dec 13 '24 16:12 theresa-m