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

NPE when compiling ConcurrentLinkedQueue.offer with JITServer and Java11 #8370

Closed
mpirvu opened this issue Jan 22, 2020 · 16 comments · Fixed by #8410
Closed

NPE when compiling ConcurrentLinkedQueue.offer with JITServer and Java11 #8370

mpirvu opened this issue Jan 22, 2020 · 16 comments · Fixed by #8410
Assignees
Labels
comp:jitserver Artifacts related to JIT-as-a-Service project

Comments

@mpirvu
Copy link
Contributor

mpirvu commented Jan 22, 2020

The NPE has the following stack trace and is seen in several Java11 sanity tests:

Exception in thread "main" java.lang.NullPointerException
        at java.base/java.util.concurrent.ConcurrentLinkedQueue.offer(ConcurrentLinkedQueue.java:361)
        at java.base/java.util.concurrent.ConcurrentLinkedQueue.add(ConcurrentLinkedQueue.java:283)
        at org.testng.ClassMethodMap.<init>(ClassMethodMap.java:42)
        at org.testng.TestRunner.initMethods(TestRunner.java:444)
        at org.testng.TestRunner.init(TestRunner.java:271)
        at org.testng.TestRunner.init(TestRunner.java:241)
        at org.testng.TestRunner.<init>(TestRunner.java:167)
        at org.testng.SuiteRunner$DefaultTestRunnerFactory.newTestRunner(SuiteRunner.java:663)
        at org.testng.SuiteRunner.init(SuiteRunner.java:260)
        at org.testng.SuiteRunner.<init>(SuiteRunner.java:198)
        at org.testng.TestNG.createSuiteRunner(TestNG.java:1295)
        at org.testng.TestNG.createSuiteRunners(TestNG.java:1273)
        at org.testng.TestNG.runSuitesLocally(TestNG.java:1128)
        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)

It happens even if we compile with optLevel=noOpt.
A simple command line to reproduce it:
"/home/mpirvu/FullJava11/openj9-openjdk-jdk11/build/linux-x86_64-normal-server-release/images/jdk/bin/java" -Xcompressedrefs -XX:-EnableHCR -Xjit:"count=0,optLevel=noopt,verbose,vlog=vlogutilc.txt,limit={java/util/concurrent/ConcurrentLinkedQueue.offer*},{java/util/concurrent/ConcurrentLinkedQueue.offer*}(traceFull,log=log.txt)" -XX:+UseJITServer -XXjitdirectory=/home/mpirvu/FullJava11/openj9-openjdk-jdk11/.. -cp "/home/mpirvu/FullJava11/openj9-openjdk-jdk11/openj9/test/TKG/../../jvmtest/TestConfig/resources:/home/mpirvu/FullJava11/openj9-openjdk-jdk11/openj9/test/TKG/../TKG/lib/testng.jar:/home/mpirvu/FullJava11/openj9-openjdk-jdk11/openj9/test/TKG/../TKG/lib/jcommander.jar:/home/mpirvu/FullJava11/openj9-openjdk-jdk11/openj9/test/TKG/../../jvmtest/functional/JIT_Test/jitt.jar" org.testng.TestNG -d "/home/mpirvu/FullJava11/openj9-openjdk-jdk11/openj9/test/TKG/../TKG/test_output_15796621567907/StringPeepholeTest_0" "/home/mpirvu/FullJava11/openj9-openjdk-jdk11/openj9/test/TKG/../../jvmtest/functional/JIT_Test/testng.xml" -testnames StringPeepholeTest -groups level.sanity -excludegroups d.*.linux_x86-64_cmprssptrs,d.*.arch.x86,d.*.os.linux,d.*.bits.64,d.*.generic-all

@mpirvu mpirvu added the comp:jitserver Artifacts related to JIT-as-a-Service project label Jan 22, 2020
@mpirvu mpirvu added this to To do in JIT as a Service via automation Jan 22, 2020
@mpirvu
Copy link
Contributor Author

mpirvu commented Jan 22, 2020

Attn: @harryyu1994

@harryyu1994
Copy link
Contributor

@mpirvu Could you try assigning this issue to me?

@harryyu1994
Copy link
Contributor

harryyu1994 commented Jan 22, 2020

Some more information that may be useful:
The NPE was exposed by this commit 9771d87a

Digged up the original PR (#6483) that implemented MessageType::ResolvedMethod_varHandleMethodTypeTableEntryAddress and MessageType::ResolvedMethod_isUnresolvedVarHandleMethodTypeTableEntry

@mpirvu
Copy link
Contributor Author

mpirvu commented Jan 22, 2020

I examined the code and I am pretty sure that those two missing break statements need to be there.
The missing break statements caused the code to fail the compilation because of a mismatch in terms of arguments when the server was sending the next query. This becomes apparent with a debug build.
So, the old code used to pass for the wrong reasons (it would still fail with a debug build though)

@ashu-mehra
Copy link
Contributor

Got a simple recreate for the NPE in case it helps in further analysis:

import java.util.Collection;
import java.util.concurrent.ConcurrentLinkedQueue;

public class TestCase {
        public static void main(String args[]) {
                ClassMethodMap map1 = new ClassMethodMap(new ITestNGMethod());
        }
}

class ClassMethodMap {
        public ClassMethodMap(ITestNGMethod method) {
                Collection<ITestNGMethod> l = new ConcurrentLinkedQueue<>();
                l.add(method);
        }
}

class ITestNGMethod {
        Object getInstance() {
                return new Object();
        }
}

Start the jitserver and then run the command:
java -XX:+UseJITServer -Xcompressedrefs -Xshareclasses:none "-Xjit:count=0,disableAsyncCompilation,verbose={compilePerformance},vlog=jit.log,limit={*ConcurrentLinkedQueue.*}" TestCase

Without -XX:+UseJITServer there is no output. With the above command it throws the NPE:

Exception in thread "main" java.lang.NullPointerException
        at java.base/java.util.concurrent.ConcurrentLinkedQueue.offer(ConcurrentLinkedQueue.java:361)
        at java.base/java.util.concurrent.ConcurrentLinkedQueue.add(ConcurrentLinkedQueue.java:283)
        at ClassMethodMap.<init>(TestCase.java:13)
        at TestCase.main(TestCase.java:6)

@harryyu1994
Copy link
Contributor

harryyu1994 commented Jan 22, 2020

    /**
     * Inserts the specified element at the tail of this queue.
     * As the queue is unbounded, this method will never return {@code false}.
     *
     * @return {@code true} (as specified by {@link Queue#offer})
     * @throws NullPointerException if the specified element is null
     */
    public boolean offer(E e) {
        final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));

        for (Node<E> t = tail, p = t;;) {
            Node<E> q = p.next;
            if (q == null) {
                // p is last node
                if (NEXT.compareAndSet(p, null, newNode)) {
                    // Successful CAS is the linearization point
                    // for e to become an element of this queue,
                    // and for newNode to become "live".
                    if (p != t) // hop two nodes at a time; failure is OK
                        TAIL.weakCompareAndSet(this, t, newNode);
                    return true;
                }
                // Lost CAS race to another thread; re-read next
            }
            else if (p == q)
                // We have fallen off list.  If tail is unchanged, it
                // will also be off-list, in which case we need to
                // jump to head, from which all live nodes are always
                // reachable.  Else the new tail is a better bet.
                p = (t != (t = tail)) ? t : head;
            else
                // Check for tail updates after two hops.
                p = (p != t && t != (t = tail)) ? t : q;
        }
    }

    /**
     * Inserts the specified element at the tail of this queue.
     * As the queue is unbounded, this method will never throw
     * {@link IllegalStateException} or return {@code false}.
     *
     * @return {@code true} (as specified by {@link Collection#add})
     * @throws NullPointerException if the specified element is null
     */
    public boolean add(E e) {
        return offer(e);
    }

@harryyu1994
Copy link
Contributor

harryyu1994 commented Jan 22, 2020

  • JITServer
./java -XX:+UseJITServer -Xcompressedrefs -Xshareclasses:none "-Xjit:count=0,disableAsyncCompilation,verbose={compilePerformance},vlog=jit.log,log=compile.log,traceFull,limit={java/util/concurrent/ConcurrentLinkedQueue.offer*},optLevel=noOpt" TestCase
  • NonJITServer
./java -Xcompressedrefs -Xshareclasses:none "-Xjit:count=0,disableAsyncCompilation,verbose={compilePerformance},vlog=jit.log,log=compile.log,traceFull,limit={java/util/concurrent/ConcurrentLinkedQueue.offer*},optLevel=noOpt" TestCase

Reduced it even further

import java.util.concurrent.ConcurrentLinkedQueue;

public class TestCase {
        public static void main(String args[]) {
              ConcurrentLinkedQueue<Method> l = new ConcurrentLinkedQueue<Method>();
              l.offer(new Method());
        }
}

class Method {
}

Code Path
On JITClient

root@HarryVM11:~/Harry_Debug/openj9-openjdk-jdk11/build/linux-x86_64-normal-server-release/images/jdk/bin# ./java -XX:+UseJITServer -Xcompressedrefs -Xshareclasses:none "-Xjit:count=0,disableAsyncCompilation,verbose={compilePerformance},vlog=jit.log,log=compile.log,traceFull,limit={java/util/concurrent/ConcurrentLinkedQueue.offer*}" TestCase
JITServer is currently a technology preview. Its use is not yet supported
case MessageType::ResolvedMethod_varHandleMethodTypeTableEntryAddress
TR_ResolvedJ9Method::varHandleMethodTypeTableEntryAddress(int32_t cpIndex)
case MessageType::ResolvedMethod_isUnresolvedVarHandleMethodTypeTableEntry
TR_ResolvedJ9Method::isUnresolvedVarHandleMethodTypeTableEntry
TR_ResolvedJ9Method::varHandleMethodTypeTableEntryAddress(int32_t cpIndex)
case MessageType::ResolvedMethod_varHandleMethodTypeTableEntryAddress
TR_ResolvedJ9Method::varHandleMethodTypeTableEntryAddress(int32_t cpIndex)
case MessageType::ResolvedMethod_isUnresolvedVarHandleMethodTypeTableEntry
TR_ResolvedJ9Method::isUnresolvedVarHandleMethodTypeTableEntry
TR_ResolvedJ9Method::varHandleMethodTypeTableEntryAddress(int32_t cpIndex)
Exception in thread "main" java.lang.NullPointerException
	at java.base/java.util.concurrent.ConcurrentLinkedQueue.offer(ConcurrentLinkedQueue.java:361)
	at java.base/java.util.concurrent.ConcurrentLinkedQueue.add(ConcurrentLinkedQueue.java:283)
	at TestCase.main(TestCase.java:6)

On JITServer

JITServer is ready to accept incoming requests
TR_VarHandleTransformer::perform
findOrCreateVarHandleMethodTypeTableEntrySymbol
varHandleMethodTypeTableEntryAddress
isUnresolvedVarHandleMethodTypeTableEntry
findOrCreateVarHandleMethodTypeTableEntrySymbol
varHandleMethodTypeTableEntryAddress
isUnresolvedVarHandleMethodTypeTableEntry

@harryyu1994

This comment has been minimized.

@harryyu1994

This comment has been minimized.

@harryyu1994
Copy link
Contributor

harryyu1994 commented Jan 23, 2020

Pre IlGenOpt Trees
NonJITServer

n46n      BBStart <block_4>                                                                   [0x7f4573005810] bci=[-1,32,361] rc=0 vc=0 vn=- li=- udi=- nc=0
n50n      ResolveCHK [#298]                                                                   [0x7f4573005950] bci=[-1,32,361] rc=0 vc=0 vn=- li=- udi=- nc=1
n49n        aload  java/util/concurrent/ConcurrentLinkedQueue.NEXT Ljava/lang/invoke/VarHandle;[#370  unresolved notAccessed volatile Static] [flags 0x2307 0x0 ]  [0x7f4573005900] bci=[-1,32,361] rc=3 vc=0 vn=- li=- udi=- nc=0
n56n      NULLCHK on n49n [#32]                                                               [0x7f4573080140] bci=[-1,39,361] rc=0 vc=0 vn=- li=- udi=- nc=1
n55n        icalli  java/lang/invoke/VarHandleInternal.compareAndSet_impl(Ljava/util/concurrent/ConcurrentLinkedQueue$Node;Ljava/lang/Void;Ljava/util/concurrent/ConcurrentLinkedQueue$Node;)Z[#375  native virtual Method -128] [flags 0x500 0x0 ] ()  [0x7f45730800f0] bci=[-1,39,361] rc=2 vc=0 vn=- li=- udi=- nc=5 flg=0x20
n54n          aloadi  <vft-symbol>[#293  Shadow] [flags 0x18607 0x0 ]                         [0x7f45730800a0] bci=[-1,39,361] rc=1 vc=0 vn=- li=- udi=- nc=1
n49n            ==>aload
n49n          ==>aload
n51n          aload  p<auto slot 4>[#367  Auto] [flags 0x7 0x0 ]                              [0x7f45730059a0] bci=[-1,35,361] rc=1 vc=0 vn=- li=- udi=- nc=0
n52n          aconst NULL                                                                     [0x7f4573080000] bci=[-1,37,361] rc=1 vc=0 vn=- li=- udi=- nc=0
n53n          aload  newNode<auto slot 2>[#364  Auto] [flags 0x7 0x0 ]                        [0x7f4573080050] bci=[-1,38,361] rc=1 vc=0 vn=- li=- udi=- nc=0
n60n      ificmpeq --> block_18 BBStart at n3n ()                                             [0x7f4573080280] bci=[-1,42,361] rc=0 vc=0 vn=- li=- udi=- nc=2 flg=0x20
n55n        ==>icalli
n57n        iconst 0                                                                          [0x7f4573080190] bci=[-1,42,361] rc=1 vc=0 vn=- li=- udi=- nc=0
n47n      BBEnd </block_4> =====                                                              [0x7f4573005860] bci=[-1,42,361] rc=0 vc=0 vn=- li=- udi=- nc=0

JITServer

n46n      BBStart <block_4>                                                                   [0x7f5392862860] bci=[-1,32,361] rc=0 vc=0 vn=- li=- udi=- nc=0
n50n      ResolveCHK [#298]                                                                   [0x7f53928629a0] bci=[-1,32,361] rc=0 vc=0 vn=- li=- udi=- nc=1
n49n        aload  java/util/concurrent/ConcurrentLinkedQueue.NEXT Ljava/lang/invoke/VarHandle;[#370  unresolved notAccessed volatile Static] [flags 0x82307 0x0 ]  [0x7f5392862950] bci=[-1,32,361] rc=2 vc=0 vn=- li=- udi=- nc=0
n56n      NULLCHK on n52n [#32]                                                               [0x7f53928dd140] bci=[-1,39,361] rc=0 vc=0 vn=- li=- udi=- nc=1
n55n        calli  java/lang/invoke/VarHandleInternal.compareAndSet_impl(Ljava/lang/Object;)V[#373  native virtual Method -128] [flags 0x500 0x0 ] ()  [0x7f53928dd0f0] bci=[-1,39,361] rc=1 vc=0 vn=- li=- udi=- nc=3 flg=0x20
n54n          aloadi  <vft-symbol>[#293  Shadow] [flags 0x18607 0x0 ]                         [0x7f53928dd0a0] bci=[-1,39,361] rc=1 vc=0 vn=- li=- udi=- nc=1
n52n            aconst NULL                                                                   [0x7f53928dd000] bci=[-1,37,361] rc=2 vc=0 vn=- li=- udi=- nc=0
n52n          ==>aconst NULL
n53n          aload  newNode<auto slot 2>[#364  Auto] [flags 0x7 0x0 ]                        [0x7f53928dd050] bci=[-1,38,361] rc=1 vc=0 vn=- li=- udi=- nc=0
n60n      astore  <pending push temp 0>[#374  Auto] [flags 0x7 0x800 ]                        [0x7f53928dd280] bci=[-1,42,361] rc=0 vc=0 vn=- li=- udi=- nc=1
n49n        ==>aload
n63n      ificmpeq --> block_18 BBStart at n3n ()                                             [0x7f53928dd370] bci=[-1,42,361] rc=0 vc=0 vn=- li=- udi=- nc=2 flg=0x20

@harryyu1994
Copy link
Contributor

harryyu1994 commented Jan 23, 2020

JITServer has wrong number of parameters and return type (it returns void instead of bool).

if (NEXT.compareAndSet(p, null, newNode))
n55n        calli  java/lang/invoke/VarHandleInternal.compareAndSet_impl(Ljava/lang/Object;)V[#373  native virtual Method -128] [flags 0x500 0x0 ] ()  [0x7f53928dd0f0] bci=[-1,39,361] rc=1 vc=0 vn=- li=- udi=- nc=3 flg=0x20
n55n        icalli  java/lang/invoke/VarHandleInternal.compareAndSet_impl(Ljava/util/concurrent/ConcurrentLinkedQueue$Node;Ljava/lang/Void;Ljava/util/concurrent/ConcurrentLinkedQueue$Node;)Z[#375  native virtual Method -128] [flags 0x500 0x0 ] ()  [0x7f45730800f0] bci=[-1,39,361] rc=2 vc=0 vn=- li=- udi=- nc=5 flg=0x20

@harryyu1994
Copy link
Contributor

harryyu1994 commented Jan 23, 2020

JITServer should have done this but didn't:

  • in getResolvedPossiblyPrivateVirtualMethod()
      if (((TR_ResolvedJ9Method*)resolvedMethod)->isVarHandleAccessMethod())
         {
         // VarHandle access methods are resolved to *_impl()V, restore their signatures to obtain function correctness in the Walker
         J9ROMMethodRef *romMethodRef = (J9ROMMethodRef *)(cp()->romConstantPool + cpIndex);
         J9ROMNameAndSignature *nameAndSig = J9ROMFIELDREF_NAMEANDSIGNATURE(romMethodRef);
         int32_t signatureLength;
         char   *signature = utf8Data(J9ROMNAMEANDSIGNATURE_SIGNATURE(nameAndSig), signatureLength);
         ((TR_ResolvedJ9Method *)resolvedMethod)->setSignature(signature, signatureLength, comp->trMemory());
         }
  • JITServer's getResolvedPossiblyPrivateVirtualMethod() override
TR_ResolvedMethod *
TR_ResolvedJ9JITServerMethod::getResolvedPossiblyPrivateVirtualMethod(TR::Compilation * comp, I_32 cpIndex, bool ignoreRtResolve, bool * unresolvedInCP)
   {
   TR_ASSERT(cpIndex != -1, "cpIndex shouldn't be -1");
#if TURN_OFF_INLINING
   return 0;
#else
   auto compInfoPT = (TR::CompilationInfoPerThreadRemote *) _fe->_compInfoPT;
   TR_ResolvedMethod *resolvedMethod = NULL;
   if (compInfoPT->getCachedResolvedMethod(compInfoPT->getResolvedMethodKey(TR_ResolvedMethodType::VirtualFromCP, (TR_OpaqueClassBlock *) _ramClass, cpIndex), this,
                                           &resolvedMethod, unresolvedInCP))
      {
      if (resolvedMethod == NULL)
         {
         TR::DebugCounter::incStaticDebugCounter(comp, "resources.resolvedMethods/virtual/null");
         if (unresolvedInCP)
            handleUnresolvedVirtualMethodInCP(cpIndex, unresolvedInCP);
         }
      return resolvedMethod;
      }

   // See if the constant pool entry is already resolved or not
   if (unresolvedInCP)
       *unresolvedInCP = true;

   if (!((_fe->_compInfoPT->getClientData()->getRtResolve()) &&
         !comp->ilGenRequest().details().isMethodHandleThunk() && // cmvc 195373
         performTransformation(comp, "Setting as unresolved virtual call cpIndex=%d\n",cpIndex) ) || ignoreRtResolve)
      {
      _stream->write(JITServer::MessageType::ResolvedMethod_getResolvedPossiblyPrivateVirtualMethodAndMirror, (TR_ResolvedMethod *) _remoteMirror, literals(), cpIndex);
      auto recv = _stream->read<J9Method *, UDATA, bool, TR_ResolvedJ9JITServerMethodInfo>();
      J9Method *ramMethod = std::get<0>(recv);
      UDATA vTableIndex = std::get<1>(recv);
      bool isUnresolvedInCP = std::get<2>(recv);

      if (unresolvedInCP)
         *unresolvedInCP = isUnresolvedInCP;

      bool createResolvedMethod = true;

      if (comp->compileRelocatableCode() && ramMethod && comp->getOption(TR_UseSymbolValidationManager))
         {
         if (!comp->getSymbolValidationManager()->addVirtualMethodFromCPRecord((TR_OpaqueMethodBlock *)ramMethod, cp(), cpIndex))
            createResolvedMethod = false;
         }

      if (vTableIndex)
         {
         TR_AOTInliningStats *aotStats = NULL;
         if (comp->getOption(TR_EnableAOTStats))
            aotStats = & (((TR_JitPrivateConfig *)_fe->_jitConfig->privateConfig)->aotStats->virtualMethods);

         TR_ResolvedJ9JITServerMethodInfo &methodInfo = std::get<3>(recv);
         
         // call constructor without making a new query
         if (createResolvedMethod)
            {
            resolvedMethod = createResolvedMethodFromJ9Method(comp, cpIndex, vTableIndex, ramMethod, unresolvedInCP, aotStats, methodInfo);
            compInfoPT->cacheResolvedMethod(compInfoPT->getResolvedMethodKey(TR_ResolvedMethodType::VirtualFromCP, (TR_OpaqueClassBlock *) _ramClass, cpIndex), (TR_OpaqueMethodBlock *) ramMethod, (uint32_t) vTableIndex, methodInfo);
            }
         }
      }

   if (resolvedMethod == NULL)
      {
      TR::DebugCounter::incStaticDebugCounter(comp, "resources.resolvedMethods/virtual/null");
      if (unresolvedInCP)
         handleUnresolvedVirtualMethodInCP(cpIndex, unresolvedInCP);
      }
   else
      {
      if (((TR_ResolvedJ9Method*)resolvedMethod)->isVarHandleAccessMethod())
         {
         // VarHandle access methods are resolved to *_impl()V, restore their signatures to obtain function correctness in the Walker
         J9ROMConstantPoolItem *cpItem = (J9ROMConstantPoolItem *)romLiterals();
         J9ROMMethodRef *romMethodRef = (J9ROMMethodRef *)(cpItem + cpIndex);
         int32_t signatureLength = 0;
         char *signature = getROMString(signatureLength, romMethodRef,
                              {
                              offsetof(J9ROMMethodRef, nameAndSignature),
                              offsetof(J9ROMNameAndSignature, signature)
                              });

         ((TR_ResolvedJ9Method *)resolvedMethod)->setSignature(signature, signatureLength, comp->trMemory());
         }

      TR::DebugCounter::incStaticDebugCounter(comp, "resources.resolvedMethods/virtual");
      TR::DebugCounter::incStaticDebugCounter(comp, "resources.resolvedMethods/virtual:#bytes", sizeof(TR_ResolvedJ9Method));
      
      }
   
   return resolvedMethod;
#endif
   }

There are 4 calls to getResolvedPossiblyPrivateVirtualMethod(), we didn't get into that part of the code for the second and the fourth call. Maybe there's the something wrong with the caching mechanism.

@harryyu1994
Copy link
Contributor

The issue is confirmed to be resolved method caching related.
export TR_DisableResolvedMethodsCaching=1 will make the problem go away.

@mpirvu
Copy link
Contributor Author

mpirvu commented Jan 23, 2020

I am guessing that we cached a NULL entry meaning the method was unresolved. The assumption was that it's ok to pretend methods are unresolved because this only has a performance implication. This is why the cache only lives for the duration of a compilation.

@harryyu1994
Copy link
Contributor

harryyu1994 commented Jan 24, 2020

Some information I've gathered, still a few things confuse me atm.
The issue is due to the cached entry containing a wrong method signature (the default method signature instead of the actual method signature). I'm not sure if we cached a NULL entry, will check tomorrow.
Unlike other normal methods, VarHandle and MethodHandle's method signature depends on its callsite, different callsite will potentially give you different method signatures.

In this case, the signature is supposed to be:
java/lang/invoke/VarHandleInternal.compareAndSet_impl(Ljava/util/concurrent/ConcurrentLinkedQueue$Node;Ljava/lang/Void;Ljava/util/concurrent/ConcurrentLinkedQueue$Node;)Z
From the comment "// VarHandle access methods are resolved to *_impl()V, restore their signatures to obtain function correctness in the Walker", we can tell that it has a default signature to java/lang/invoke/VarHandleInternal.compareAndSet_impl(Ljava/lang/Object;)V and it's when we get into this part of the code we "restore" to the correct signature.

if (((TR_ResolvedJ9Method*)resolvedMethod)->isVarHandleAccessMethod())
         {
         // VarHandle access methods are resolved to *_impl()V, restore their signatures to obtain function correctness in the Walker
         J9ROMConstantPoolItem *cpItem = (J9ROMConstantPoolItem *)romLiterals();
         J9ROMMethodRef *romMethodRef = (J9ROMMethodRef *)(cpItem + cpIndex);
         int32_t signatureLength = 0;
         char *signature = getROMString(signatureLength, romMethodRef,
                              {
                              offsetof(J9ROMMethodRef, nameAndSignature),
                              offsetof(J9ROMNameAndSignature, signature)
                              });

         ((TR_ResolvedJ9Method *)resolvedMethod)->setSignature(signature, signatureLength, comp->trMemory());
         }

So now I need to figure out if we can actually cache VarHandle type resolvedMethods.

@harryyu1994
Copy link
Contributor

harryyu1994 commented Jan 24, 2020

It turns out we are simply missing an extra step to restore the method signature for VarHandles after we create the resolvedMethod from the cached entry.

if (compInfoPT->getCachedResolvedMethod(compInfoPT->getResolvedMethodKey(TR_ResolvedMethodType::VirtualFromCP, (TR_OpaqueClassBlock *) _ramClass, cpIndex), this,
                                           &resolvedMethod, unresolvedInCP))
      {
      if (resolvedMethod == NULL)
         {
         TR::DebugCounter::incStaticDebugCounter(comp, "resources.resolvedMethods/virtual/null");
         if (unresolvedInCP)
            handleUnresolvedVirtualMethodInCP(cpIndex, unresolvedInCP);
         }
      // needs to restore method signature for VarHandles here !!!
      return resolvedMethod;
      }

harryyu1994 added a commit to harryyu1994/openj9 that referenced this issue Jan 24, 2020
After creating the resolvedMethod in TR_ResolvedJ9JITServerMethod::getResolvedPossiblyPrivateVirtualMethod,
we forgot to restore method signatures for VarHandle access methods.

Fixes: eclipse-openj9#8370

Signed-off-by: Harry Yu <harryyu1994@gmail.com>
JIT as a Service automation moved this from To do to Done Jan 29, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
comp:jitserver Artifacts related to JIT-as-a-Service project
Projects
Development

Successfully merging a pull request may close this issue.

3 participants