From 820085101433737a363e11a29e337928d6ea1e77 Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Wed, 15 Jun 2022 13:15:44 -0400 Subject: [PATCH 01/13] emit jdk.JavaMonitorEnter events --- .../src/com/oracle/svm/core/jfr/JfrEvent.java | 4 +- .../jfr/events/JavaMonitorEnterEvent.java | 41 +++++++++++++++++++ .../monitor/MultiThreadedMonitorSupport.java | 36 ++++++++++++---- 3 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrEvent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrEvent.java index 70d047dee930..a3a7cc9ce0c8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrEvent.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrEvent.java @@ -53,7 +53,9 @@ public enum JfrEvent { GCPhasePauseLevel4Event("jdk.GCPhasePauseLevel4"), SafepointBegin("jdk.SafepointBegin"), SafepointEnd("jdk.SafepointEnd"), - ExecuteVMOperation("jdk.ExecuteVMOperation"); + ExecuteVMOperation("jdk.ExecuteVMOperation"), + JavaMonitorEnter("jdk.JavaMonitorEnter"); + private final long id; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java new file mode 100644 index 000000000000..c6daccaba615 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java @@ -0,0 +1,41 @@ +package src.com.oracle.svm.core.src.com.oracle.svm.core.jfr.events; + + +import org.graalvm.nativeimage.StackValue; +import org.graalvm.word.UnsignedWord; + +import com.oracle.svm.core.annotate.Uninterruptible; +import com.oracle.svm.core.jfr.JfrEvent; +import com.oracle.svm.core.jfr.JfrNativeEventWriter; +import com.oracle.svm.core.jfr.JfrNativeEventWriterData; +import com.oracle.svm.core.jfr.JfrNativeEventWriterDataAccess; +import com.oracle.svm.core.jfr.JfrTicks; +import com.oracle.svm.core.jfr.SubstrateJVM; + + +public class JavaMonitorEnterEvent { + + @Uninterruptible(reason = "Accesses a JFR buffer.") + public static void emit(Object obj, org.graalvm.nativeimage.IsolateThread previousOwner, long addr) { + emit(obj, com.oracle.svm.core.jfr.SubstrateJVM.get().getThreadId(previousOwner), addr); + } + @Uninterruptible(reason = "Accesses a JFR buffer.") + public static void emit(Object obj, long previousOwner, long addr) { + if (SubstrateJVM.isRecording() && SubstrateJVM.get().isEnabled(JfrEvent.JavaMonitorEnter)) { + JfrNativeEventWriterData data = StackValue.get(JfrNativeEventWriterData.class); + JfrNativeEventWriterDataAccess.initializeThreadLocalNativeBuffer(data); + + JfrNativeEventWriter.beginSmallEvent(data, JfrEvent.JavaMonitorEnter); + + JfrNativeEventWriter.putClass(data, obj.getClass()); + + //for some reason we need both of these ()which do the same thing + JfrNativeEventWriter.putEventThread(data);// same as put thread, but uses the current thread + JfrNativeEventWriter.putLong(data, previousOwner);//basically just does putlong(threadID, based on thread pointer) + + JfrNativeEventWriter.putLong(data, addr);//this should show up as 0 but it seems random + + JfrNativeEventWriter.endSmallEvent(data); + } + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java index cea15cd41940..86305eddcb05 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java @@ -25,10 +25,7 @@ package com.oracle.svm.core.monitor; import java.lang.ref.ReferenceQueue; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.AbstractOwnableSynchronizer; import java.util.concurrent.locks.AbstractQueuedSynchronizer; @@ -61,6 +58,7 @@ import com.oracle.svm.core.util.VMError; import jdk.internal.misc.Unsafe; +import src.com.oracle.svm.core.src.com.oracle.svm.core.jfr.events.JavaMonitorEnterEvent; /** * Implementation of synchronized-related operations. @@ -137,7 +135,7 @@ public class MultiThreadedMonitorSupport extends MonitorSupport { * java.io.FileInputStream.close() which synchronizes on a 'Object closeLock = new * Object()' object. We cannot modify the type of the monitor since it is in JDK code. * Adding a monitor slot to java.lang.Object doesn't impact any subtypes. - * + * * This should also take care of the synchronization in * ReferenceInternals.processPendingReferences(). */ @@ -193,7 +191,9 @@ public class MultiThreadedMonitorSupport extends MonitorSupport { * modification. */ private final Map additionalMonitors = new WeakIdentityHashMap<>(); + private final Map monitorOwners = new WeakIdentityHashMap<>(); private final ReentrantLock additionalMonitorsLock = new ReentrantLock(); + private final ReentrantLock monitorOwnersLock = new ReentrantLock(); @Override public int maybeAdjustNewParkStatus(int status) { @@ -255,8 +255,28 @@ private static void slowPathMonitorEnter(Object obj) { @RestrictHeapAccess(reason = NO_LONGER_UNINTERRUPTIBLE, access = Access.UNRESTRICTED) @Override public void monitorEnter(Object obj) { + ReentrantLock lockObject = getOrCreateMonitor(obj, true); + lockObject.lock(); + + // Prevent deadlock by locking monitorOwners lock due to synchronized block on ReferenceQueue monitor in WeakIdentityHashMap. + if ( obj.getClass() == Target_java_lang_ref_ReferenceQueue_Lock.class || obj.getClass() == ReferenceQueue.class) return; + + // prevent recursive manipulation of the monitorOwners lock + if (monitorOwnersLock.isHeldByCurrentThread()) return; + monitorOwnersLock.lock(); + try { + Long prevOwner = null; + long currentOwnerId = com.oracle.svm.core.jfr.SubstrateJVM.get().getThreadId(org.graalvm.nativeimage.CurrentIsolate.getCurrentThread()); + prevOwner = monitorOwners.get(obj); + monitorOwners.put(obj, currentOwnerId); + if (prevOwner == null) prevOwner = 0L; //same as in hotspot native code + JavaMonitorEnterEvent.emit(obj,prevOwner,0);//not able to get address because its implemented in native code in Hotspot + return; + } finally { + monitorOwnersLock.unlock(); + } } @SubstrateForeignCallTarget(stubCallingConvention = false) @@ -301,13 +321,13 @@ public Object prepareRelockObject(Object obj) { /* * We ensure that the lock for the object exists, so that the actual re-locking during * deoptimization can be uninterruptible. - * + * * Unfortunately, we cannot do any assertion checking in this method: deoptimization can run * in any thread, i.e., not necessarily in the thread that the lock will be for. And while * the frame that is deoptimized must have had the object locked, the thread could have * given up the lock as part of a wait() - so at this time any thread is allowed to hold the * lock. - * + * * Because any thread can hold the lock at this time, there is no way we can patch any * internal state of the lock immediately here. The actual state patching therefore happens * later in doRelockObject. @@ -452,7 +472,7 @@ protected ReentrantLock getOrCreateMonitorFromObject(Object obj, boolean createI protected ReentrantLock getOrCreateMonitorFromMap(Object obj, boolean createIfNotExisting) { assert obj.getClass() != Target_java_lang_ref_ReferenceQueue_Lock.class : "ReferenceQueue.Lock must have a monitor field or we can deadlock accessing WeakIdentityHashMap below"; VMError.guarantee(!additionalMonitorsLock.isHeldByCurrentThread(), - "Recursive manipulation of the additionalMonitors map can lead to table corruptions and double insertion of a monitor for the same object"); + "Recursive manipulation of the additionalMonitors map can lead to table corruptions and double insertion of a monitor for the same object"); /* * Lock the monitor map and maybe add a monitor for this object. This serialization might be From f16c40193eeb3c108f5e1c69a5a9feb9da3d08c6 Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Wed, 15 Jun 2022 13:30:03 -0400 Subject: [PATCH 02/13] refactor --- .../core/monitor/MultiThreadedMonitorSupport.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java index 86305eddcb05..1be7655fd92b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java @@ -255,28 +255,27 @@ private static void slowPathMonitorEnter(Object obj) { @RestrictHeapAccess(reason = NO_LONGER_UNINTERRUPTIBLE, access = Access.UNRESTRICTED) @Override public void monitorEnter(Object obj) { - ReentrantLock lockObject = getOrCreateMonitor(obj, true); - lockObject.lock(); // Prevent deadlock by locking monitorOwners lock due to synchronized block on ReferenceQueue monitor in WeakIdentityHashMap. - if ( obj.getClass() == Target_java_lang_ref_ReferenceQueue_Lock.class || obj.getClass() == ReferenceQueue.class) return; + if ( obj.getClass() == Target_java_lang_ref_ReferenceQueue_Lock.class ) return; // prevent recursive manipulation of the monitorOwners lock if (monitorOwnersLock.isHeldByCurrentThread()) return; + Long prevOwner; + long currentOwnerId = com.oracle.svm.core.jfr.SubstrateJVM.get().getThreadId(org.graalvm.nativeimage.CurrentIsolate.getCurrentThread()); + monitorOwnersLock.lock(); try { - Long prevOwner = null; - long currentOwnerId = com.oracle.svm.core.jfr.SubstrateJVM.get().getThreadId(org.graalvm.nativeimage.CurrentIsolate.getCurrentThread()); prevOwner = monitorOwners.get(obj); monitorOwners.put(obj, currentOwnerId); - if (prevOwner == null) prevOwner = 0L; //same as in hotspot native code - JavaMonitorEnterEvent.emit(obj,prevOwner,0);//not able to get address because its implemented in native code in Hotspot - return; } finally { monitorOwnersLock.unlock(); } + if ( prevOwner==null ) prevOwner = 0L; + JavaMonitorEnterEvent.emit(obj,prevOwner,0);//not able to get address because its implemented in native code in Hotspot + } @SubstrateForeignCallTarget(stubCallingConvention = false) From 040ca50fd1c12b1643551a910e8c7ee2dbfed507 Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Wed, 15 Jun 2022 15:52:51 -0400 Subject: [PATCH 03/13] add retry mechanism --- .../svm/core/jfr/events/JavaMonitorEnterEvent.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java index c6daccaba615..2893c4114a6e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java @@ -25,7 +25,15 @@ public static void emit(Object obj, long previousOwner, long addr) { JfrNativeEventWriterData data = StackValue.get(JfrNativeEventWriterData.class); JfrNativeEventWriterDataAccess.initializeThreadLocalNativeBuffer(data); - JfrNativeEventWriter.beginSmallEvent(data, JfrEvent.JavaMonitorEnter); + if (emit0(data, obj, previousOwner, addr, SubstrateJVM.get().isLarge(JfrEvent.JavaMonitorEnter)) == com.oracle.svm.core.jfr.JfrEventWriteStatus.RetryLarge) { + SubstrateJVM.get().setLarge(JfrEvent.JavaMonitorEnter, true); + emit0(data, obj, previousOwner, addr, true); + } + } + } + @Uninterruptible(reason = "Accesses a JFR buffer.") + private static com.oracle.svm.core.jfr.JfrEventWriteStatus emit0(JfrNativeEventWriterData data, Object obj, long previousOwner, long addr, boolean isLarge){ + JfrNativeEventWriter.beginEvent(data, JfrEvent.JavaMonitorEnter, isLarge); JfrNativeEventWriter.putClass(data, obj.getClass()); @@ -35,7 +43,6 @@ public static void emit(Object obj, long previousOwner, long addr) { JfrNativeEventWriter.putLong(data, addr);//this should show up as 0 but it seems random - JfrNativeEventWriter.endSmallEvent(data); + return JfrNativeEventWriter.endEvent(data, isLarge); } - } } From 5db0d2b0cb74280c23cd9daddf50bf7e48ef72e0 Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Thu, 16 Jun 2022 14:24:20 -0400 Subject: [PATCH 04/13] format event fields correctly --- .../svm/core/jfr/events/JavaMonitorEnterEvent.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java index 2893c4114a6e..0f8361cd4c82 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java @@ -35,13 +35,13 @@ public static void emit(Object obj, long previousOwner, long addr) { private static com.oracle.svm.core.jfr.JfrEventWriteStatus emit0(JfrNativeEventWriterData data, Object obj, long previousOwner, long addr, boolean isLarge){ JfrNativeEventWriter.beginEvent(data, JfrEvent.JavaMonitorEnter, isLarge); + JfrNativeEventWriter.putLong(data, JfrTicks.elapsedTicks()); + JfrNativeEventWriter.putLong(data, 0); + JfrNativeEventWriter.putEventThread(data); + JfrNativeEventWriter.putLong(data, SubstrateJVM.get().getStackTraceId(JfrEvent.ThreadStart.getId(), 0)); JfrNativeEventWriter.putClass(data, obj.getClass()); - - //for some reason we need both of these ()which do the same thing - JfrNativeEventWriter.putEventThread(data);// same as put thread, but uses the current thread - JfrNativeEventWriter.putLong(data, previousOwner);//basically just does putlong(threadID, based on thread pointer) - - JfrNativeEventWriter.putLong(data, addr);//this should show up as 0 but it seems random + JfrNativeEventWriter.putLong(data, previousOwner); + JfrNativeEventWriter.putLong(data, addr); return JfrNativeEventWriter.endEvent(data, isLarge); } From 804754c4f89db5b2595491cb140399561f42deb7 Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Thu, 16 Jun 2022 14:51:45 -0400 Subject: [PATCH 05/13] add duration and start time --- .../core/jfr/events/JavaMonitorEnterEvent.java | 16 ++++++++-------- .../monitor/MultiThreadedMonitorSupport.java | 3 ++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java index 0f8361cd4c82..fcb2c39c83ab 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java @@ -16,27 +16,27 @@ public class JavaMonitorEnterEvent { @Uninterruptible(reason = "Accesses a JFR buffer.") - public static void emit(Object obj, org.graalvm.nativeimage.IsolateThread previousOwner, long addr) { - emit(obj, com.oracle.svm.core.jfr.SubstrateJVM.get().getThreadId(previousOwner), addr); + public static void emit(Object obj, org.graalvm.nativeimage.IsolateThread previousOwner, long addr, long startTicks) { + emit(obj, com.oracle.svm.core.jfr.SubstrateJVM.get().getThreadId(previousOwner), addr, startTicks); } @Uninterruptible(reason = "Accesses a JFR buffer.") - public static void emit(Object obj, long previousOwner, long addr) { + public static void emit(Object obj, long previousOwner, long addr, long startTicks) { if (SubstrateJVM.isRecording() && SubstrateJVM.get().isEnabled(JfrEvent.JavaMonitorEnter)) { JfrNativeEventWriterData data = StackValue.get(JfrNativeEventWriterData.class); JfrNativeEventWriterDataAccess.initializeThreadLocalNativeBuffer(data); - if (emit0(data, obj, previousOwner, addr, SubstrateJVM.get().isLarge(JfrEvent.JavaMonitorEnter)) == com.oracle.svm.core.jfr.JfrEventWriteStatus.RetryLarge) { + if (emit0(data, obj, previousOwner, addr, startTicks, SubstrateJVM.get().isLarge(JfrEvent.JavaMonitorEnter)) == com.oracle.svm.core.jfr.JfrEventWriteStatus.RetryLarge) { SubstrateJVM.get().setLarge(JfrEvent.JavaMonitorEnter, true); - emit0(data, obj, previousOwner, addr, true); + emit0(data, obj, previousOwner, addr, startTicks, true); } } } @Uninterruptible(reason = "Accesses a JFR buffer.") - private static com.oracle.svm.core.jfr.JfrEventWriteStatus emit0(JfrNativeEventWriterData data, Object obj, long previousOwner, long addr, boolean isLarge){ + private static com.oracle.svm.core.jfr.JfrEventWriteStatus emit0(JfrNativeEventWriterData data, Object obj, long previousOwner, long addr, long startTicks, boolean isLarge){ JfrNativeEventWriter.beginEvent(data, JfrEvent.JavaMonitorEnter, isLarge); - JfrNativeEventWriter.putLong(data, JfrTicks.elapsedTicks()); - JfrNativeEventWriter.putLong(data, 0); + JfrNativeEventWriter.putLong(data, startTicks); + JfrNativeEventWriter.putLong(data, JfrTicks.elapsedTicks() - startTicks); JfrNativeEventWriter.putEventThread(data); JfrNativeEventWriter.putLong(data, SubstrateJVM.get().getStackTraceId(JfrEvent.ThreadStart.getId(), 0)); JfrNativeEventWriter.putClass(data, obj.getClass()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java index 1be7655fd92b..ba4883badb49 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java @@ -255,6 +255,7 @@ private static void slowPathMonitorEnter(Object obj) { @RestrictHeapAccess(reason = NO_LONGER_UNINTERRUPTIBLE, access = Access.UNRESTRICTED) @Override public void monitorEnter(Object obj) { + long startTicks = com.oracle.svm.core.jfr.JfrTicks.elapsedTicks(); ReentrantLock lockObject = getOrCreateMonitor(obj, true); lockObject.lock(); @@ -274,7 +275,7 @@ public void monitorEnter(Object obj) { monitorOwnersLock.unlock(); } if ( prevOwner==null ) prevOwner = 0L; - JavaMonitorEnterEvent.emit(obj,prevOwner,0);//not able to get address because its implemented in native code in Hotspot + JavaMonitorEnterEvent.emit(obj,prevOwner,0, startTicks);//not able to get address because its implemented in native code in Hotspot } From 3ee246dafdfa8ab70a32990f41ae7bdb130bdfe7 Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Fri, 17 Jun 2022 13:09:39 -0400 Subject: [PATCH 06/13] add address --- .../svm/core/jfr/events/JavaMonitorEnterEvent.java | 14 +++++++------- .../core/monitor/MultiThreadedMonitorSupport.java | 7 ++++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java index fcb2c39c83ab..31f77495de0a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java @@ -16,23 +16,23 @@ public class JavaMonitorEnterEvent { @Uninterruptible(reason = "Accesses a JFR buffer.") - public static void emit(Object obj, org.graalvm.nativeimage.IsolateThread previousOwner, long addr, long startTicks) { - emit(obj, com.oracle.svm.core.jfr.SubstrateJVM.get().getThreadId(previousOwner), addr, startTicks); + public static void emit(Object obj, org.graalvm.nativeimage.IsolateThread previousOwner,long startTicks) { + emit(obj, com.oracle.svm.core.jfr.SubstrateJVM.get().getThreadId(previousOwner), startTicks); } @Uninterruptible(reason = "Accesses a JFR buffer.") - public static void emit(Object obj, long previousOwner, long addr, long startTicks) { + public static void emit(Object obj, long previousOwner, long startTicks) { if (SubstrateJVM.isRecording() && SubstrateJVM.get().isEnabled(JfrEvent.JavaMonitorEnter)) { JfrNativeEventWriterData data = StackValue.get(JfrNativeEventWriterData.class); JfrNativeEventWriterDataAccess.initializeThreadLocalNativeBuffer(data); - if (emit0(data, obj, previousOwner, addr, startTicks, SubstrateJVM.get().isLarge(JfrEvent.JavaMonitorEnter)) == com.oracle.svm.core.jfr.JfrEventWriteStatus.RetryLarge) { + if (emit0(data, obj, previousOwner, startTicks, SubstrateJVM.get().isLarge(JfrEvent.JavaMonitorEnter)) == com.oracle.svm.core.jfr.JfrEventWriteStatus.RetryLarge) { SubstrateJVM.get().setLarge(JfrEvent.JavaMonitorEnter, true); - emit0(data, obj, previousOwner, addr, startTicks, true); + emit0(data, obj, previousOwner, startTicks, true); } } } @Uninterruptible(reason = "Accesses a JFR buffer.") - private static com.oracle.svm.core.jfr.JfrEventWriteStatus emit0(JfrNativeEventWriterData data, Object obj, long previousOwner, long addr, long startTicks, boolean isLarge){ + private static com.oracle.svm.core.jfr.JfrEventWriteStatus emit0(JfrNativeEventWriterData data, Object obj, long previousOwner, long startTicks, boolean isLarge){ JfrNativeEventWriter.beginEvent(data, JfrEvent.JavaMonitorEnter, isLarge); JfrNativeEventWriter.putLong(data, startTicks); @@ -41,7 +41,7 @@ private static com.oracle.svm.core.jfr.JfrEventWriteStatus emit0(JfrNativeEventW JfrNativeEventWriter.putLong(data, SubstrateJVM.get().getStackTraceId(JfrEvent.ThreadStart.getId(), 0)); JfrNativeEventWriter.putClass(data, obj.getClass()); JfrNativeEventWriter.putLong(data, previousOwner); - JfrNativeEventWriter.putLong(data, addr); + JfrNativeEventWriter.putLong(data, org.graalvm.compiler.word.Word.objectToUntrackedPointer(obj).rawValue()); return JfrNativeEventWriter.endEvent(data, isLarge); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java index ba4883badb49..dc16d7bc6b4f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java @@ -37,8 +37,10 @@ import org.graalvm.compiler.core.common.SuppressFBWarnings; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.compiler.word.BarrieredAccess; +import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.CurrentIsolate; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.WeakIdentityHashMap; @@ -265,7 +267,7 @@ public void monitorEnter(Object obj) { // prevent recursive manipulation of the monitorOwners lock if (monitorOwnersLock.isHeldByCurrentThread()) return; Long prevOwner; - long currentOwnerId = com.oracle.svm.core.jfr.SubstrateJVM.get().getThreadId(org.graalvm.nativeimage.CurrentIsolate.getCurrentThread()); + long currentOwnerId = com.oracle.svm.core.jfr.SubstrateJVM.get().getThreadId(CurrentIsolate.getCurrentThread()); monitorOwnersLock.lock(); try { @@ -275,8 +277,7 @@ public void monitorEnter(Object obj) { monitorOwnersLock.unlock(); } if ( prevOwner==null ) prevOwner = 0L; - JavaMonitorEnterEvent.emit(obj,prevOwner,0, startTicks);//not able to get address because its implemented in native code in Hotspot - + JavaMonitorEnterEvent.emit(obj,prevOwner, startTicks); } @SubstrateForeignCallTarget(stubCallingConvention = false) From f35b11a12041319556ece9b9d1490b746b2b68f8 Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Mon, 20 Jun 2022 10:13:31 -0400 Subject: [PATCH 07/13] add copyright header and remove retry mechanism --- .../jfr/events/JavaMonitorEnterEvent.java | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java index 31f77495de0a..8eabc9198a43 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2022, Red Hat Inc. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + package src.com.oracle.svm.core.src.com.oracle.svm.core.jfr.events; @@ -25,16 +51,7 @@ public static void emit(Object obj, long previousOwner, long startTicks) { JfrNativeEventWriterData data = StackValue.get(JfrNativeEventWriterData.class); JfrNativeEventWriterDataAccess.initializeThreadLocalNativeBuffer(data); - if (emit0(data, obj, previousOwner, startTicks, SubstrateJVM.get().isLarge(JfrEvent.JavaMonitorEnter)) == com.oracle.svm.core.jfr.JfrEventWriteStatus.RetryLarge) { - SubstrateJVM.get().setLarge(JfrEvent.JavaMonitorEnter, true); - emit0(data, obj, previousOwner, startTicks, true); - } - } - } - @Uninterruptible(reason = "Accesses a JFR buffer.") - private static com.oracle.svm.core.jfr.JfrEventWriteStatus emit0(JfrNativeEventWriterData data, Object obj, long previousOwner, long startTicks, boolean isLarge){ - JfrNativeEventWriter.beginEvent(data, JfrEvent.JavaMonitorEnter, isLarge); - + JfrNativeEventWriter.beginSmallEvent(data, JfrEvent.JavaMonitorEnter); JfrNativeEventWriter.putLong(data, startTicks); JfrNativeEventWriter.putLong(data, JfrTicks.elapsedTicks() - startTicks); JfrNativeEventWriter.putEventThread(data); @@ -42,7 +59,7 @@ private static com.oracle.svm.core.jfr.JfrEventWriteStatus emit0(JfrNativeEventW JfrNativeEventWriter.putClass(data, obj.getClass()); JfrNativeEventWriter.putLong(data, previousOwner); JfrNativeEventWriter.putLong(data, org.graalvm.compiler.word.Word.objectToUntrackedPointer(obj).rawValue()); + JfrNativeEventWriter.endSmallEvent(data); - return JfrNativeEventWriter.endEvent(data, isLarge); } -} + }} From a44e3862f092a8aae399d793d5c101baad2f413e Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Mon, 20 Jun 2022 11:01:13 -0400 Subject: [PATCH 08/13] try non-blocking try lock to see if lock is available first --- .../oracle/svm/core/monitor/MultiThreadedMonitorSupport.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java index dc16d7bc6b4f..10c3ddef5cda 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java @@ -259,9 +259,12 @@ private static void slowPathMonitorEnter(Object obj) { public void monitorEnter(Object obj) { long startTicks = com.oracle.svm.core.jfr.JfrTicks.elapsedTicks(); ReentrantLock lockObject = getOrCreateMonitor(obj, true); + + if (lockObject.tryLock()) return; + lockObject.lock(); - // Prevent deadlock by locking monitorOwners lock due to synchronized block on ReferenceQueue monitor in WeakIdentityHashMap. + // Prevent deadlock from locking monitorOwnersLock in conjunction with the synchronized block on ReferenceQueue monitor in WeakIdentityHashMap if ( obj.getClass() == Target_java_lang_ref_ReferenceQueue_Lock.class ) return; // prevent recursive manipulation of the monitorOwners lock From e928ecd9b5e16a524c9b529cc5daeb0247390bb3 Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Mon, 20 Jun 2022 11:52:09 -0400 Subject: [PATCH 09/13] fix style --- .../jfr/events/JavaMonitorEnterEvent.java | 9 +++--- .../monitor/MultiThreadedMonitorSupport.java | 29 ++++++++++++------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java index 8eabc9198a43..db05fb071609 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java @@ -26,9 +26,7 @@ package src.com.oracle.svm.core.src.com.oracle.svm.core.jfr.events; - import org.graalvm.nativeimage.StackValue; -import org.graalvm.word.UnsignedWord; import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.jfr.JfrEvent; @@ -38,13 +36,13 @@ import com.oracle.svm.core.jfr.JfrTicks; import com.oracle.svm.core.jfr.SubstrateJVM; - public class JavaMonitorEnterEvent { @Uninterruptible(reason = "Accesses a JFR buffer.") - public static void emit(Object obj, org.graalvm.nativeimage.IsolateThread previousOwner,long startTicks) { + public static void emit(Object obj, org.graalvm.nativeimage.IsolateThread previousOwner, long startTicks) { emit(obj, com.oracle.svm.core.jfr.SubstrateJVM.get().getThreadId(previousOwner), startTicks); } + @Uninterruptible(reason = "Accesses a JFR buffer.") public static void emit(Object obj, long previousOwner, long startTicks) { if (SubstrateJVM.isRecording() && SubstrateJVM.get().isEnabled(JfrEvent.JavaMonitorEnter)) { @@ -62,4 +60,5 @@ public static void emit(Object obj, long previousOwner, long startTicks) { JfrNativeEventWriter.endSmallEvent(data); } - }} + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java index 10c3ddef5cda..bf60f2daf22a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java @@ -25,7 +25,10 @@ package com.oracle.svm.core.monitor; import java.lang.ref.ReferenceQueue; -import java.util.*; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.AbstractOwnableSynchronizer; import java.util.concurrent.locks.AbstractQueuedSynchronizer; @@ -37,7 +40,6 @@ import org.graalvm.compiler.core.common.SuppressFBWarnings; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.compiler.word.BarrieredAccess; -import org.graalvm.compiler.word.Word; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.CurrentIsolate; @@ -260,15 +262,20 @@ public void monitorEnter(Object obj) { long startTicks = com.oracle.svm.core.jfr.JfrTicks.elapsedTicks(); ReentrantLock lockObject = getOrCreateMonitor(obj, true); - if (lockObject.tryLock()) return; - + if (lockObject.tryLock()) { + return; + } lockObject.lock(); - // Prevent deadlock from locking monitorOwnersLock in conjunction with the synchronized block on ReferenceQueue monitor in WeakIdentityHashMap - if ( obj.getClass() == Target_java_lang_ref_ReferenceQueue_Lock.class ) return; - + // Prevent deadlock from locking monitorOwnersLock in conjunction with the + // synchronized block on ReferenceQueue monitor in WeakIdentityHashMap + if (obj.getClass() == Target_java_lang_ref_ReferenceQueue_Lock.class) { + return; + } // prevent recursive manipulation of the monitorOwners lock - if (monitorOwnersLock.isHeldByCurrentThread()) return; + if (monitorOwnersLock.isHeldByCurrentThread()) { + return; + } Long prevOwner; long currentOwnerId = com.oracle.svm.core.jfr.SubstrateJVM.get().getThreadId(CurrentIsolate.getCurrentThread()); @@ -279,8 +286,10 @@ public void monitorEnter(Object obj) { } finally { monitorOwnersLock.unlock(); } - if ( prevOwner==null ) prevOwner = 0L; - JavaMonitorEnterEvent.emit(obj,prevOwner, startTicks); + if (prevOwner == null) { + prevOwner = 0L; + } + JavaMonitorEnterEvent.emit(obj, prevOwner, startTicks); } @SubstrateForeignCallTarget(stubCallingConvention = false) From 43f0d161160032d447698121ad08e999a4f99559 Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Mon, 20 Jun 2022 15:42:12 -0400 Subject: [PATCH 10/13] fix package --- .../com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java | 2 +- .../oracle/svm/core/monitor/MultiThreadedMonitorSupport.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java index db05fb071609..de38dbc10990 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java @@ -24,7 +24,7 @@ * questions. */ -package src.com.oracle.svm.core.src.com.oracle.svm.core.jfr.events; +package com.oracle.svm.core.jfr.events; import org.graalvm.nativeimage.StackValue; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java index bf60f2daf22a..61bc13c40357 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java @@ -60,9 +60,9 @@ import com.oracle.svm.core.thread.ThreadStatus; import com.oracle.svm.core.thread.VMOperationControl; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.core.jfr.events.JavaMonitorEnterEvent; import jdk.internal.misc.Unsafe; -import src.com.oracle.svm.core.src.com.oracle.svm.core.jfr.events.JavaMonitorEnterEvent; /** * Implementation of synchronized-related operations. From fe9cd54acd489ace50b19db542c6040ff6a3ec98 Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Tue, 21 Jun 2022 09:08:17 -0400 Subject: [PATCH 11/13] fix event type in get stacktrace --- .../com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java index de38dbc10990..5332f8249040 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorEnterEvent.java @@ -53,7 +53,7 @@ public static void emit(Object obj, long previousOwner, long startTicks) { JfrNativeEventWriter.putLong(data, startTicks); JfrNativeEventWriter.putLong(data, JfrTicks.elapsedTicks() - startTicks); JfrNativeEventWriter.putEventThread(data); - JfrNativeEventWriter.putLong(data, SubstrateJVM.get().getStackTraceId(JfrEvent.ThreadStart.getId(), 0)); + JfrNativeEventWriter.putLong(data, SubstrateJVM.get().getStackTraceId(JfrEvent.JavaMonitorEnter.getId(), 0)); JfrNativeEventWriter.putClass(data, obj.getClass()); JfrNativeEventWriter.putLong(data, previousOwner); JfrNativeEventWriter.putLong(data, org.graalvm.compiler.word.Word.objectToUntrackedPointer(obj).rawValue()); From 29efe65dd1ac7a5f14d8deae7aa914da654f4391 Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Tue, 21 Jun 2022 12:29:47 -0400 Subject: [PATCH 12/13] make derived ReentrantLock class --- .../monitor/MultiThreadedMonitorSupport.java | 55 +++++------------ .../svm/core/monitor/OwnedReentrantLock.java | 60 +++++++++++++++++++ 2 files changed, 75 insertions(+), 40 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/OwnedReentrantLock.java diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java index 61bc13c40357..517afabdb81e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java @@ -42,7 +42,6 @@ import org.graalvm.compiler.word.BarrieredAccess; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.CurrentIsolate; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.WeakIdentityHashMap; @@ -194,7 +193,7 @@ public class MultiThreadedMonitorSupport extends MonitorSupport { * Secondary storage for monitor slots. Synchronized to prevent concurrent access and * modification. */ - private final Map additionalMonitors = new WeakIdentityHashMap<>(); + private final Map additionalMonitors = new WeakIdentityHashMap<>(); private final Map monitorOwners = new WeakIdentityHashMap<>(); private final ReentrantLock additionalMonitorsLock = new ReentrantLock(); private final ReentrantLock monitorOwnersLock = new ReentrantLock(); @@ -260,36 +259,12 @@ private static void slowPathMonitorEnter(Object obj) { @Override public void monitorEnter(Object obj) { long startTicks = com.oracle.svm.core.jfr.JfrTicks.elapsedTicks(); - ReentrantLock lockObject = getOrCreateMonitor(obj, true); - - if (lockObject.tryLock()) { - return; - } - lockObject.lock(); + OwnedReentrantLock lockObject = getOrCreateMonitor(obj, true); - // Prevent deadlock from locking monitorOwnersLock in conjunction with the - // synchronized block on ReferenceQueue monitor in WeakIdentityHashMap - if (obj.getClass() == Target_java_lang_ref_ReferenceQueue_Lock.class) { - return; - } - // prevent recursive manipulation of the monitorOwners lock - if (monitorOwnersLock.isHeldByCurrentThread()) { - return; + if (!lockObject.tryLockOwnedLock()) { + JavaMonitorEnterEvent.emit(obj, lockObject.getPrevOwnerTid(), startTicks); } - Long prevOwner; - long currentOwnerId = com.oracle.svm.core.jfr.SubstrateJVM.get().getThreadId(CurrentIsolate.getCurrentThread()); - monitorOwnersLock.lock(); - try { - prevOwner = monitorOwners.get(obj); - monitorOwners.put(obj, currentOwnerId); - } finally { - monitorOwnersLock.unlock(); - } - if (prevOwner == null) { - prevOwner = 0L; - } - JavaMonitorEnterEvent.emit(obj, prevOwner, startTicks); } @SubstrateForeignCallTarget(stubCallingConvention = false) @@ -454,7 +429,7 @@ protected static Object replaceObject(Object unreplacedObject) { return unreplacedObject; } - protected final ReentrantLock getOrCreateMonitor(Object unreplacedObject, boolean createIfNotExisting) { + protected final OwnedReentrantLock getOrCreateMonitor(Object unreplacedObject, boolean createIfNotExisting) { Object obj = replaceObject(unreplacedObject); assert obj != null; int monitorOffset = getMonitorOffset(obj); @@ -467,22 +442,22 @@ protected final ReentrantLock getOrCreateMonitor(Object unreplacedObject, boolea } } - protected ReentrantLock getOrCreateMonitorFromObject(Object obj, boolean createIfNotExisting, int monitorOffset) { - ReentrantLock existingMonitor = (ReentrantLock) BarrieredAccess.readObject(obj, monitorOffset); + protected OwnedReentrantLock getOrCreateMonitorFromObject(Object obj, boolean createIfNotExisting, int monitorOffset) { + OwnedReentrantLock existingMonitor = (OwnedReentrantLock) BarrieredAccess.readObject(obj, monitorOffset); if (existingMonitor != null || !createIfNotExisting) { assert existingMonitor == null || isMonitorLock(existingMonitor); return existingMonitor; } /* Atomically put a new lock in place of the null at the monitorOffset. */ - ReentrantLock newMonitor = newMonitorLock(); + OwnedReentrantLock newMonitor = newMonitorLock(); if (UNSAFE.compareAndSetObject(obj, monitorOffset, null, newMonitor)) { return newMonitor; } /* We lost the race, use the lock some other thread installed. */ - return (ReentrantLock) BarrieredAccess.readObject(obj, monitorOffset); + return (OwnedReentrantLock) BarrieredAccess.readObject(obj, monitorOffset); } - protected ReentrantLock getOrCreateMonitorFromMap(Object obj, boolean createIfNotExisting) { + protected OwnedReentrantLock getOrCreateMonitorFromMap(Object obj, boolean createIfNotExisting) { assert obj.getClass() != Target_java_lang_ref_ReferenceQueue_Lock.class : "ReferenceQueue.Lock must have a monitor field or we can deadlock accessing WeakIdentityHashMap below"; VMError.guarantee(!additionalMonitorsLock.isHeldByCurrentThread(), "Recursive manipulation of the additionalMonitors map can lead to table corruptions and double insertion of a monitor for the same object"); @@ -493,13 +468,13 @@ protected ReentrantLock getOrCreateMonitorFromMap(Object obj, boolean createIfNo */ additionalMonitorsLock.lock(); try { - ReentrantLock existingMonitor = additionalMonitors.get(obj); + OwnedReentrantLock existingMonitor = additionalMonitors.get(obj); if (existingMonitor != null || !createIfNotExisting) { assert existingMonitor == null || isMonitorLock(existingMonitor); return existingMonitor; } - ReentrantLock newMonitor = newMonitorLock(); - ReentrantLock previousEntry = additionalMonitors.put(obj, newMonitor); + OwnedReentrantLock newMonitor = newMonitorLock(); + OwnedReentrantLock previousEntry = additionalMonitors.put(obj, newMonitor); VMError.guarantee(previousEntry == null, "Replaced monitor in secondary storage map"); return newMonitor; } finally { @@ -507,8 +482,8 @@ protected ReentrantLock getOrCreateMonitorFromMap(Object obj, boolean createIfNo } } - protected static ReentrantLock newMonitorLock() { - ReentrantLock newMonitor = new ReentrantLock(); + protected static OwnedReentrantLock newMonitorLock() { + OwnedReentrantLock newMonitor = new OwnedReentrantLock(); Target_java_util_concurrent_locks_ReentrantLock lock = SubstrateUtil.cast(newMonitor, Target_java_util_concurrent_locks_ReentrantLock.class); Target_java_util_concurrent_locks_ReentrantLock_NonfairSync sync = SubstrateUtil.cast(lock.sync, Target_java_util_concurrent_locks_ReentrantLock_NonfairSync.class); sync.objectMonitorCondition = SubstrateUtil.cast(MONITOR_WITHOUT_CONDITION, Target_java_util_concurrent_locks_AbstractQueuedSynchronizer_ConditionObject.class); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/OwnedReentrantLock.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/OwnedReentrantLock.java new file mode 100644 index 000000000000..d25431f02127 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/OwnedReentrantLock.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2022, Red Hat Inc. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package com.oracle.svm.core.monitor; + +import java.util.concurrent.locks.ReentrantLock; + +import org.graalvm.nativeimage.CurrentIsolate; +import com.oracle.svm.core.jfr.SubstrateJVM; + +public class OwnedReentrantLock extends ReentrantLock { + private long prevOwnerTid; + private long currOwnerTid; + + public long getPrevOwnerTid() { + return prevOwnerTid; + } + + public OwnedReentrantLock() { + super(); + currOwnerTid = SubstrateJVM.get().getThreadId(CurrentIsolate.getCurrentThread()); + } + + public boolean tryLockOwnedLock() { + boolean available = true; + if (!tryLock()) { + available = false; + lock(); + } + prevOwnerTid = currOwnerTid; + currOwnerTid = SubstrateJVM.get().getThreadId(CurrentIsolate.getCurrentThread()); + return available; + + } + + +} From 3e5753cff2385c5178408ee7cc41484ac31e9ddf Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Wed, 22 Jun 2022 09:29:06 -0400 Subject: [PATCH 13/13] rename and refactor --- ...nedReentrantLock.java => JavaMonitor.java} | 26 ++++++------- .../monitor/MultiThreadedMonitorSupport.java | 37 ++++++++----------- 2 files changed, 27 insertions(+), 36 deletions(-) rename substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/{OwnedReentrantLock.java => JavaMonitor.java} (72%) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/OwnedReentrantLock.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitor.java similarity index 72% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/OwnedReentrantLock.java rename to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitor.java index d25431f02127..9a78d25ec899 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/OwnedReentrantLock.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitor.java @@ -30,30 +30,28 @@ import org.graalvm.nativeimage.CurrentIsolate; import com.oracle.svm.core.jfr.SubstrateJVM; +import com.oracle.svm.core.jfr.events.JavaMonitorEnterEvent; +import com.oracle.svm.core.jfr.JfrTicks; -public class OwnedReentrantLock extends ReentrantLock { - private long prevOwnerTid; - private long currOwnerTid; +public class JavaMonitor extends ReentrantLock { + private long ownerTid; - public long getPrevOwnerTid() { - return prevOwnerTid; + public long getOwnerTid() { + return ownerTid; } - public OwnedReentrantLock() { + public JavaMonitor() { super(); - currOwnerTid = SubstrateJVM.get().getThreadId(CurrentIsolate.getCurrentThread()); + ownerTid = SubstrateJVM.get().getThreadId(CurrentIsolate.getCurrentThread()); } - public boolean tryLockOwnedLock() { - boolean available = true; + public void monitorEnter(Object obj) { if (!tryLock()) { - available = false; + long startTicks = JfrTicks.elapsedTicks(); lock(); + JavaMonitorEnterEvent.emit(obj, getOwnerTid(), startTicks); } - prevOwnerTid = currOwnerTid; - currOwnerTid = SubstrateJVM.get().getThreadId(CurrentIsolate.getCurrentThread()); - return available; - + ownerTid = SubstrateJVM.get().getThreadId(CurrentIsolate.getCurrentThread()); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java index 517afabdb81e..03276b954891 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java @@ -59,7 +59,7 @@ import com.oracle.svm.core.thread.ThreadStatus; import com.oracle.svm.core.thread.VMOperationControl; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.core.jfr.events.JavaMonitorEnterEvent; + import jdk.internal.misc.Unsafe; @@ -193,10 +193,8 @@ public class MultiThreadedMonitorSupport extends MonitorSupport { * Secondary storage for monitor slots. Synchronized to prevent concurrent access and * modification. */ - private final Map additionalMonitors = new WeakIdentityHashMap<>(); - private final Map monitorOwners = new WeakIdentityHashMap<>(); + private final Map additionalMonitors = new WeakIdentityHashMap<>(); private final ReentrantLock additionalMonitorsLock = new ReentrantLock(); - private final ReentrantLock monitorOwnersLock = new ReentrantLock(); @Override public int maybeAdjustNewParkStatus(int status) { @@ -258,13 +256,8 @@ private static void slowPathMonitorEnter(Object obj) { @RestrictHeapAccess(reason = NO_LONGER_UNINTERRUPTIBLE, access = Access.UNRESTRICTED) @Override public void monitorEnter(Object obj) { - long startTicks = com.oracle.svm.core.jfr.JfrTicks.elapsedTicks(); - OwnedReentrantLock lockObject = getOrCreateMonitor(obj, true); - - if (!lockObject.tryLockOwnedLock()) { - JavaMonitorEnterEvent.emit(obj, lockObject.getPrevOwnerTid(), startTicks); - } - + JavaMonitor lockObject = getOrCreateMonitor(obj, true); + lockObject.monitorEnter(obj); } @SubstrateForeignCallTarget(stubCallingConvention = false) @@ -429,7 +422,7 @@ protected static Object replaceObject(Object unreplacedObject) { return unreplacedObject; } - protected final OwnedReentrantLock getOrCreateMonitor(Object unreplacedObject, boolean createIfNotExisting) { + protected final JavaMonitor getOrCreateMonitor(Object unreplacedObject, boolean createIfNotExisting) { Object obj = replaceObject(unreplacedObject); assert obj != null; int monitorOffset = getMonitorOffset(obj); @@ -442,22 +435,22 @@ protected final OwnedReentrantLock getOrCreateMonitor(Object unreplacedObject, b } } - protected OwnedReentrantLock getOrCreateMonitorFromObject(Object obj, boolean createIfNotExisting, int monitorOffset) { - OwnedReentrantLock existingMonitor = (OwnedReentrantLock) BarrieredAccess.readObject(obj, monitorOffset); + protected JavaMonitor getOrCreateMonitorFromObject(Object obj, boolean createIfNotExisting, int monitorOffset) { + JavaMonitor existingMonitor = (JavaMonitor) BarrieredAccess.readObject(obj, monitorOffset); if (existingMonitor != null || !createIfNotExisting) { assert existingMonitor == null || isMonitorLock(existingMonitor); return existingMonitor; } /* Atomically put a new lock in place of the null at the monitorOffset. */ - OwnedReentrantLock newMonitor = newMonitorLock(); + JavaMonitor newMonitor = newMonitorLock(); if (UNSAFE.compareAndSetObject(obj, monitorOffset, null, newMonitor)) { return newMonitor; } /* We lost the race, use the lock some other thread installed. */ - return (OwnedReentrantLock) BarrieredAccess.readObject(obj, monitorOffset); + return (JavaMonitor) BarrieredAccess.readObject(obj, monitorOffset); } - protected OwnedReentrantLock getOrCreateMonitorFromMap(Object obj, boolean createIfNotExisting) { + protected JavaMonitor getOrCreateMonitorFromMap(Object obj, boolean createIfNotExisting) { assert obj.getClass() != Target_java_lang_ref_ReferenceQueue_Lock.class : "ReferenceQueue.Lock must have a monitor field or we can deadlock accessing WeakIdentityHashMap below"; VMError.guarantee(!additionalMonitorsLock.isHeldByCurrentThread(), "Recursive manipulation of the additionalMonitors map can lead to table corruptions and double insertion of a monitor for the same object"); @@ -468,13 +461,13 @@ protected OwnedReentrantLock getOrCreateMonitorFromMap(Object obj, boolean creat */ additionalMonitorsLock.lock(); try { - OwnedReentrantLock existingMonitor = additionalMonitors.get(obj); + JavaMonitor existingMonitor = additionalMonitors.get(obj); if (existingMonitor != null || !createIfNotExisting) { assert existingMonitor == null || isMonitorLock(existingMonitor); return existingMonitor; } - OwnedReentrantLock newMonitor = newMonitorLock(); - OwnedReentrantLock previousEntry = additionalMonitors.put(obj, newMonitor); + JavaMonitor newMonitor = newMonitorLock(); + JavaMonitor previousEntry = additionalMonitors.put(obj, newMonitor); VMError.guarantee(previousEntry == null, "Replaced monitor in secondary storage map"); return newMonitor; } finally { @@ -482,8 +475,8 @@ protected OwnedReentrantLock getOrCreateMonitorFromMap(Object obj, boolean creat } } - protected static OwnedReentrantLock newMonitorLock() { - OwnedReentrantLock newMonitor = new OwnedReentrantLock(); + protected static JavaMonitor newMonitorLock() { + JavaMonitor newMonitor = new JavaMonitor(); Target_java_util_concurrent_locks_ReentrantLock lock = SubstrateUtil.cast(newMonitor, Target_java_util_concurrent_locks_ReentrantLock.class); Target_java_util_concurrent_locks_ReentrantLock_NonfairSync sync = SubstrateUtil.cast(lock.sync, Target_java_util_concurrent_locks_ReentrantLock_NonfairSync.class); sync.objectMonitorCondition = SubstrateUtil.cast(MONITOR_WITHOUT_CONDITION, Target_java_util_concurrent_locks_AbstractQueuedSynchronizer_ConditionObject.class);