[aarch64-port-dev ] Redundant guard conditions caused guarantee failure

chengjingwei (A) chengjingwei1 at huawei.com
Tue Jul 9 08:49:25 UTC 2019


Hotspot would crash when running tomcat with the following parameters:
-XX:+MonitorInUseLists -XX:MonitorBound=16384

The crash message was:
#  Internal Error (synchronizer.cpp:1464), pid=78479, tid=0x00007f965a82b700
#  guarantee(obj->mark() == markOopDesc::encode(mid)) failed: invariant

This bug can be reproduced with a simplified testcase, by running javac command:
$ javac -J-XX:+MonitorInUseLists ByteAdd.java
where ByteAdd.java is as follows:
```
public class ByteAdd {
    public byte add(byte a, byte b) {
                    return (byte) (a + (byte) b);
    }

    public static void main(String args[]) throws Exception {
        byte aa = (byte) 128;
        byte bb = (byte) 127;
        byte result = (byte) 255;
        ByteAdd obj = new ByteAdd();
        if (Math.abs(obj.add(aa, bb) - result) <= 0)
            System.out.println("PASSED");
        else
            throw new Exception("The caculated result is incorrect!");
    }
}
```

My colleague(wangyadong4 at huawei.com) investigated into it and found that it was caused by redundant guard conditions in Thread::oops_do, and made the following patch:
--- a/hotspot/src/share/vm/runtime/thread.cpp
+++ b/hotspot/src/share/vm/runtime/thread.cpp
@@ -871,12 +871,9 @@ void Thread::oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf) {
   // Do oop for ThreadShadow
   f->do_oop((oop*)&_pending_exception);
   handle_area()->oops_do(f);
-#if INCLUDE_ALL_GCS
-  // TODO: Either need better abstractions or have all GCs use this.
-  if (UseShenandoahGC && ShenandoahFastSyncRoots && MonitorInUseLists) {
+  if (MonitorInUseLists) {
     ObjectSynchronizer::thread_local_used_oops_do(this, f);
   }
-#endif
}

The cause of the crash is that MonitorInUseLists would affect the behaviour of monitor list scanning. When this switch is turned on,
the scanning of global used monitor list and thread-local ones are separated. The code of ObjectSynchronizer::oops_do,
listed below, indicates that it only scans global monitors with MonitorInUseLists turned on, so thread-local ones
should be scanned in Thread::oops_do no matter what GC algorithm is used.
```
void ObjectSynchronizer::oops_do(OopClosure* f) {
  if (MonitorInUseLists) {
    // When using thread local monitor lists, we only scan the
    // global used list here (for moribund threads), and
    // the thread-local monitors in Thread::oops_do().
    global_used_oops_do(f);
  } else {
    global_oops_do(f);
  }
}
```

This bug affects only jdk8u-shenandoah port because MonitorInUseLists is deprecated in JDK10.


More information about the aarch64-port-dev mailing list