Add some crash info to Heap::checkConn() RELEASE_ASSERTs.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Jul 2018 22:44:47 +0000 (22:44 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Jul 2018 22:44:47 +0000 (22:44 +0000)
https://bugs.webkit.org/show_bug.cgi?id=188123
<rdar://problem/42672268>

Reviewed by Keith Miller.

Source/JavaScriptCore:

1. Add VM::m_id and Heap::m_lastPhase fields.  Both of these fit within existing
   padding space in VM and Heap, and should not cost any measurable perf to
   initialize and update.

2. Add some crash info to the RELEASE_ASSERTs in Heap::checkConn():

   worldState tells us the value we failed the assertion on.

   m_lastPhase, m_currentPhase, and m_nextPhase tells us the GC phase transition
   that led us here.

   VM::id(), and VM::numberOfIDs() tells us how many VMs may be in play.

   VM::isEntered() tells us if the current VM is currently executing JS code.

   Some of this data may be redundant, but the redundancy is intentional so that
   we can double check what is really happening at the time of crash.

* heap/Heap.cpp:
(JSC::asInt):
(JSC::Heap::checkConn):
(JSC::Heap::changePhase):
* heap/Heap.h:
* runtime/VM.cpp:
(JSC::VM::nextID):
(JSC::VM::VM):
* runtime/VM.h:
(JSC::VM::numberOfIDs):
(JSC::VM::id const):
(JSC::VM::isEntered const):

Source/WTF:

1. Rename STUFF_FOR_CRASH_REGISTERx to CRASH_GPRx.  These are only used in
   locally in Assertions.cpp.  There is little to no chance of a name collision,
   and the shorter names will be much easier to read and grok in the code.

2. Added an additional 2 registers so that we can pass more info.

3. Change the WTFCrashWithInfo() implementations to issue only a single asm
   statement so that the compiler does not inadvertently move values out of the
   CRASH_GPRs that we want them to be in.

4. Use register targeting for local variables to get the compiler to put our
   desired values in specific registers.  For how this works, see
   https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables

   "The only supported use for this feature is to specify registers for input and
   output operands when calling Extended asm (see Extended Asm).  This may be
   necessary if the constraints for a particular machine don’t provide sufficient
   control to select the desired register."

5. Enhance ASSERT, ASSERT_UNUSED, RELEASE_ASSERT, RELEASE_ASSERT_NOT_REACHED to
   accept crash info arguments.  We no longer need to use an if statement with a
   call to CRASH_WITH_INFO instead of these assertions.  The only case not handled
   yet is one where we might want to dataLog some info before the crash.  I'll
   add that functionality in a subsequent patch.

6. Move UNREACHABLE_FOR_PLATFORM to the bottom of Assertions.h because it depends
   on the definition of RELEASE_ASSERT_NOT_REACHED, which now depends on the
   definiton of CRASH_WITH_INFO.

* wtf/Assertions.cpp:
(WTFCrashWithInfo):
* wtf/Assertions.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@234335 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/heap/Heap.cpp
Source/JavaScriptCore/heap/Heap.h
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/runtime/VM.h
Source/WTF/ChangeLog
Source/WTF/wtf/Assertions.cpp
Source/WTF/wtf/Assertions.h

index c20a868..8ce535c 100644 (file)
@@ -1,3 +1,42 @@
+2018-07-27  Mark Lam  <mark.lam@apple.com>
+
+        Add some crash info to Heap::checkConn() RELEASE_ASSERTs.
+        https://bugs.webkit.org/show_bug.cgi?id=188123
+        <rdar://problem/42672268>
+
+        Reviewed by Keith Miller.
+
+        1. Add VM::m_id and Heap::m_lastPhase fields.  Both of these fit within existing
+           padding space in VM and Heap, and should not cost any measurable perf to
+           initialize and update.
+
+        2. Add some crash info to the RELEASE_ASSERTs in Heap::checkConn():
+
+           worldState tells us the value we failed the assertion on.
+
+           m_lastPhase, m_currentPhase, and m_nextPhase tells us the GC phase transition
+           that led us here.
+
+           VM::id(), and VM::numberOfIDs() tells us how many VMs may be in play.
+
+           VM::isEntered() tells us if the current VM is currently executing JS code.
+
+           Some of this data may be redundant, but the redundancy is intentional so that
+           we can double check what is really happening at the time of crash.
+
+        * heap/Heap.cpp:
+        (JSC::asInt):
+        (JSC::Heap::checkConn):
+        (JSC::Heap::changePhase):
+        * heap/Heap.h:
+        * runtime/VM.cpp:
+        (JSC::VM::nextID):
+        (JSC::VM::VM):
+        * runtime/VM.h:
+        (JSC::VM::numberOfIDs):
+        (JSC::VM::id const):
+        (JSC::VM::isEntered const):
+
 2018-07-25  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         [JSC] Record CoW status in ArrayProfile correctly
index aef44c3..ea3a0fc 100644 (file)
@@ -1121,14 +1121,20 @@ void Heap::collectInCollectorThread()
     }
 }
 
+ALWAYS_INLINE int asInt(CollectorPhase phase)
+{
+    return static_cast<int>(phase);
+}
+
 void Heap::checkConn(GCConductor conn)
 {
+    unsigned worldState = m_worldState.load();
     switch (conn) {
     case GCConductor::Mutator:
-        RELEASE_ASSERT(m_worldState.load() & mutatorHasConnBit);
+        RELEASE_ASSERT(worldState & mutatorHasConnBit, worldState, asInt(m_lastPhase), asInt(m_currentPhase), asInt(m_nextPhase), vm()->id(), VM::numberOfIDs(), vm()->isEntered());
         return;
     case GCConductor::Collector:
-        RELEASE_ASSERT(!(m_worldState.load() & mutatorHasConnBit));
+        RELEASE_ASSERT(!(worldState & mutatorHasConnBit), worldState, asInt(m_lastPhase), asInt(m_currentPhase), asInt(m_nextPhase), vm()->id(), VM::numberOfIDs(), vm()->isEntered());
         return;
     }
     RELEASE_ASSERT_NOT_REACHED();
@@ -1519,6 +1525,7 @@ bool Heap::changePhase(GCConductor conn, CollectorPhase nextPhase)
 {
     checkConn(conn);
 
+    m_lastPhase = m_currentPhase;
     m_nextPhase = nextPhase;
 
     return finishChangingPhase(conn);
index 020226b..e1395d0 100644 (file)
@@ -693,6 +693,7 @@ private:
     GCRequest m_currentRequest;
     Ticket m_lastServedTicket { 0 };
     Ticket m_lastGrantedTicket { 0 };
+    CollectorPhase m_lastPhase { CollectorPhase::NotRunning };
     CollectorPhase m_currentPhase { CollectorPhase::NotRunning };
     CollectorPhase m_nextPhase { CollectorPhase::NotRunning };
     bool m_threadShouldStop { false };
index 77cbbf0..f10ffdb 100644 (file)
@@ -182,6 +182,8 @@ bool VM::s_canUseJITIsSet = false;
 bool VM::s_canUseJIT = false;
 #endif
 
+Atomic<unsigned> VM::s_numberOfIDs;
+
 // Note: Platform.h will enforce that ENABLE(ASSEMBLER) is true if either
 // ENABLE(JIT) or ENABLE(YARR_JIT) or both are enabled. The code below
 // just checks for ENABLE(JIT) or ENABLE(YARR_JIT) with this premise in mind.
@@ -247,8 +249,20 @@ bool VM::isInMiniMode()
     return !canUseJIT() || Options::forceMiniVMMode();
 }
 
+inline unsigned VM::nextID()
+{
+    for (;;) {
+        unsigned currentNumberOfIDs = s_numberOfIDs.load();
+        unsigned newID = currentNumberOfIDs + 1;
+        if (s_numberOfIDs.compareExchangeWeak(currentNumberOfIDs, newID))
+            return newID;
+    }
+}
+
+
 VM::VM(VMType vmType, HeapType heapType)
-    : m_apiLock(adoptRef(new JSLock(this)))
+    : m_id(nextID())
+    , m_apiLock(adoptRef(new JSLock(this)))
 #if USE(CF)
     , m_runLoop(CFRunLoopGetCurrent())
 #endif // USE(CF)
index f74bb8c..f1b9101 100644 (file)
@@ -289,7 +289,16 @@ public:
     JS_EXPORT_PRIVATE SamplingProfiler& ensureSamplingProfiler(RefPtr<Stopwatch>&&);
 #endif
 
+    static unsigned numberOfIDs() { return s_numberOfIDs.load(); }
+    unsigned id() const { return m_id; }
+    bool isEntered() const { return !!entryScope; }
+
 private:
+    unsigned nextID();
+
+    static Atomic<unsigned> s_numberOfIDs;
+
+    unsigned m_id;
     RefPtr<JSLock> m_apiLock;
 #if USE(CF)
     // These need to be initialized before heap below.
index 6eff453..6837059 100644 (file)
@@ -1,3 +1,44 @@
+2018-07-27  Mark Lam  <mark.lam@apple.com>
+
+        Add some crash info to Heap::checkConn() RELEASE_ASSERTs.
+        https://bugs.webkit.org/show_bug.cgi?id=188123
+        <rdar://problem/42672268>
+
+        Reviewed by Keith Miller.
+
+        1. Rename STUFF_FOR_CRASH_REGISTERx to CRASH_GPRx.  These are only used in
+           locally in Assertions.cpp.  There is little to no chance of a name collision,
+           and the shorter names will be much easier to read and grok in the code.
+
+        2. Added an additional 2 registers so that we can pass more info.
+
+        3. Change the WTFCrashWithInfo() implementations to issue only a single asm
+           statement so that the compiler does not inadvertently move values out of the
+           CRASH_GPRs that we want them to be in.
+
+        4. Use register targeting for local variables to get the compiler to put our
+           desired values in specific registers.  For how this works, see
+           https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables
+
+           "The only supported use for this feature is to specify registers for input and
+           output operands when calling Extended asm (see Extended Asm).  This may be
+           necessary if the constraints for a particular machine don’t provide sufficient
+           control to select the desired register."
+
+        5. Enhance ASSERT, ASSERT_UNUSED, RELEASE_ASSERT, RELEASE_ASSERT_NOT_REACHED to
+           accept crash info arguments.  We no longer need to use an if statement with a
+           call to CRASH_WITH_INFO instead of these assertions.  The only case not handled
+           yet is one where we might want to dataLog some info before the crash.  I'll
+           add that functionality in a subsequent patch.
+
+        6. Move UNREACHABLE_FOR_PLATFORM to the bottom of Assertions.h because it depends
+           on the definition of RELEASE_ASSERT_NOT_REACHED, which now depends on the
+           definiton of CRASH_WITH_INFO.
+
+        * wtf/Assertions.cpp:
+        (WTFCrashWithInfo):
+        * wtf/Assertions.h:
+
 2018-07-27  Alex Christensen  <achristensen@webkit.org>
 
         Make CompletionHandler more const correct
index 9700e05..34a2b72 100644 (file)
@@ -566,76 +566,115 @@ void WTFReleaseLogStackTrace(WTFLogChannel* channel)
 
 #if OS(DARWIN) && (CPU(X86_64) || CPU(ARM64))
 #if CPU(X86_64)
-#define STUFF_REGISTER_FOR_CRASH(reg, info) __asm__ volatile ("movq %0, %%" reg : : "r" (static_cast<uint64_t>(info)) : reg)
+
+#define CRASH_INST "int3"
 
 // This ordering was chosen to be consistent with JSC's JIT asserts. We probably shouldn't change this ordering
 // since it would make tooling crash reports much harder. If, for whatever reason, we decide to change the ordering
 // here we should update the abortWithuint64_t functions.
-#define STUFF_FOR_CRASH_REGISTER1 "r11"
-#define STUFF_FOR_CRASH_REGISTER2 "r10"
-#define STUFF_FOR_CRASH_REGISTER3 "r9"
-#define STUFF_FOR_CRASH_REGISTER4 "r8"
-#define STUFF_FOR_CRASH_REGISTER5 "r15"
+#define CRASH_GPR0 "r11"
+#define CRASH_GPR1 "r10"
+#define CRASH_GPR2 "r9"
+#define CRASH_GPR3 "r8"
+#define CRASH_GPR4 "r15"
+#define CRASH_GPR5 "r14"
+#define CRASH_GPR6 "r13"
 
 #elif CPU(ARM64) // CPU(X86_64)
-#define STUFF_REGISTER_FOR_CRASH(reg, info) __asm__ volatile ("mov " reg ", %0" : : "r" (static_cast<uint64_t>(info)) : reg)
+
+#define CRASH_INST "brk #0"
 
 // See comment above on the ordering.
-#define STUFF_FOR_CRASH_REGISTER1 "x16"
-#define STUFF_FOR_CRASH_REGISTER2 "x17"
-#define STUFF_FOR_CRASH_REGISTER3 "x18"
-#define STUFF_FOR_CRASH_REGISTER4 "x19"
-#define STUFF_FOR_CRASH_REGISTER5 "x20"
+#define CRASH_GPR0 "x16"
+#define CRASH_GPR1 "x17"
+#define CRASH_GPR2 "x18"
+#define CRASH_GPR3 "x19"
+#define CRASH_GPR4 "x20"
+#define CRASH_GPR5 "x21"
+#define CRASH_GPR6 "x22"
 
 #endif // CPU(ARM64)
 
+void WTFCrashWithInfo(int, const char*, const char*, int, uint64_t reason, uint64_t misc1, uint64_t misc2, uint64_t misc3, uint64_t misc4, uint64_t misc5, uint64_t misc6)
+{
+    register uint64_t reasonGPR asm(CRASH_GPR0) = reason;
+    register uint64_t misc1GPR asm(CRASH_GPR1) = misc1;
+    register uint64_t misc2GPR asm(CRASH_GPR2) = misc2;
+    register uint64_t misc3GPR asm(CRASH_GPR3) = misc3;
+    register uint64_t misc4GPR asm(CRASH_GPR4) = misc4;
+    register uint64_t misc5GPR asm(CRASH_GPR5) = misc5;
+    register uint64_t misc6GPR asm(CRASH_GPR6) = misc6;
+    __asm__ volatile (CRASH_INST : : "r"(reasonGPR), "r"(misc1GPR), "r"(misc2GPR), "r"(misc3GPR), "r"(misc4GPR), "r"(misc5GPR), "r"(misc6GPR));
+    __builtin_unreachable();
+}
+
+void WTFCrashWithInfo(int, const char*, const char*, int, uint64_t reason, uint64_t misc1, uint64_t misc2, uint64_t misc3, uint64_t misc4, uint64_t misc5)
+{
+    register uint64_t reasonGPR asm(CRASH_GPR0) = reason;
+    register uint64_t misc1GPR asm(CRASH_GPR1) = misc1;
+    register uint64_t misc2GPR asm(CRASH_GPR2) = misc2;
+    register uint64_t misc3GPR asm(CRASH_GPR3) = misc3;
+    register uint64_t misc4GPR asm(CRASH_GPR4) = misc4;
+    register uint64_t misc5GPR asm(CRASH_GPR5) = misc5;
+    __asm__ volatile (CRASH_INST : : "r"(reasonGPR), "r"(misc1GPR), "r"(misc2GPR), "r"(misc3GPR), "r"(misc4GPR), "r"(misc5GPR));
+    __builtin_unreachable();
+}
+
 void WTFCrashWithInfo(int, const char*, const char*, int, uint64_t reason, uint64_t misc1, uint64_t misc2, uint64_t misc3, uint64_t misc4)
 {
-    STUFF_REGISTER_FOR_CRASH(STUFF_FOR_CRASH_REGISTER1, reason);
-    STUFF_REGISTER_FOR_CRASH(STUFF_FOR_CRASH_REGISTER2, misc1);
-    STUFF_REGISTER_FOR_CRASH(STUFF_FOR_CRASH_REGISTER3, misc2);
-    STUFF_REGISTER_FOR_CRASH(STUFF_FOR_CRASH_REGISTER4, misc3);
-    STUFF_REGISTER_FOR_CRASH(STUFF_FOR_CRASH_REGISTER5, misc4);
-    CRASH();
+    register uint64_t reasonGPR asm(CRASH_GPR0) = reason;
+    register uint64_t misc1GPR asm(CRASH_GPR1) = misc1;
+    register uint64_t misc2GPR asm(CRASH_GPR2) = misc2;
+    register uint64_t misc3GPR asm(CRASH_GPR3) = misc3;
+    register uint64_t misc4GPR asm(CRASH_GPR4) = misc4;
+    __asm__ volatile (CRASH_INST : : "r"(reasonGPR), "r"(misc1GPR), "r"(misc2GPR), "r"(misc3GPR), "r"(misc4GPR));
+    __builtin_unreachable();
 }
 
 void WTFCrashWithInfo(int, const char*, const char*, int, uint64_t reason, uint64_t misc1, uint64_t misc2, uint64_t misc3)
 {
-    STUFF_REGISTER_FOR_CRASH(STUFF_FOR_CRASH_REGISTER1, reason);
-    STUFF_REGISTER_FOR_CRASH(STUFF_FOR_CRASH_REGISTER2, misc1);
-    STUFF_REGISTER_FOR_CRASH(STUFF_FOR_CRASH_REGISTER3, misc2);
-    STUFF_REGISTER_FOR_CRASH(STUFF_FOR_CRASH_REGISTER4, misc3);
-    CRASH();
+    register uint64_t reasonGPR asm(CRASH_GPR0) = reason;
+    register uint64_t misc1GPR asm(CRASH_GPR1) = misc1;
+    register uint64_t misc2GPR asm(CRASH_GPR2) = misc2;
+    register uint64_t misc3GPR asm(CRASH_GPR3) = misc3;
+    __asm__ volatile (CRASH_INST : : "r"(reasonGPR), "r"(misc1GPR), "r"(misc2GPR), "r"(misc3GPR));
+    __builtin_unreachable();
 }
 
 void WTFCrashWithInfo(int, const char*, const char*, int, uint64_t reason, uint64_t misc1, uint64_t misc2)
 {
-    STUFF_REGISTER_FOR_CRASH(STUFF_FOR_CRASH_REGISTER1, reason);
-    STUFF_REGISTER_FOR_CRASH(STUFF_FOR_CRASH_REGISTER2, misc1);
-    STUFF_REGISTER_FOR_CRASH(STUFF_FOR_CRASH_REGISTER3, misc2);
-    CRASH();
+    register uint64_t reasonGPR asm(CRASH_GPR0) = reason;
+    register uint64_t misc1GPR asm(CRASH_GPR1) = misc1;
+    register uint64_t misc2GPR asm(CRASH_GPR2) = misc2;
+    __asm__ volatile (CRASH_INST : : "r"(reasonGPR), "r"(misc1GPR), "r"(misc2GPR));
+    __builtin_unreachable();
 }
 
 void WTFCrashWithInfo(int, const char*, const char*, int, uint64_t reason, uint64_t misc1)
 {
-    STUFF_REGISTER_FOR_CRASH(STUFF_FOR_CRASH_REGISTER1, reason);
-    STUFF_REGISTER_FOR_CRASH(STUFF_FOR_CRASH_REGISTER2, misc1);
-    CRASH();
+    register uint64_t reasonGPR asm(CRASH_GPR0) = reason;
+    register uint64_t misc1GPR asm(CRASH_GPR1) = misc1;
+    __asm__ volatile (CRASH_INST : : "r"(reasonGPR), "r"(misc1GPR));
+    __builtin_unreachable();
 }
 
 void WTFCrashWithInfo(int, const char*, const char*, int, uint64_t reason)
 {
-    STUFF_REGISTER_FOR_CRASH(STUFF_FOR_CRASH_REGISTER1, reason);
-    CRASH();
+    register uint64_t reasonGPR asm(CRASH_GPR0) = reason;
+    __asm__ volatile (CRASH_INST : : "r"(reasonGPR));
+    __builtin_unreachable();
 }
 
 void WTFCrashWithInfo(int, const char*, const char*, int)
 {
-    CRASH();
+    __asm__ volatile (CRASH_INST : : );
+    __builtin_unreachable();
 }
 
 #else
 
+void WTFCrashWithInfo(int, const char*, const char*, int, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t) { CRASH(); }
+void WTFCrashWithInfo(int, const char*, const char*, int, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t) { CRASH(); }
 void WTFCrashWithInfo(int, const char*, const char*, int, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t) { CRASH(); }
 void WTFCrashWithInfo(int, const char*, const char*, int, uint64_t, uint64_t, uint64_t, uint64_t) { CRASH(); }
 void WTFCrashWithInfo(int, const char*, const char*, int, uint64_t, uint64_t, uint64_t) { CRASH(); }
index 60ad4c7..68b342e 100644 (file)
@@ -289,15 +289,15 @@ WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH void WTFCrashWithSecurityImplication(v
 
 #if ASSERT_DISABLED
 
-#define ASSERT(assertion) ((void)0)
+#define ASSERT(assertion, ...) ((void)0)
 #define ASSERT_UNDER_CONSTEXPR_CONTEXT(assertion) ((void)0)
 #define ASSERT_AT(assertion, file, line, function) ((void)0)
-#define ASSERT_NOT_REACHED() ((void)0)
+#define ASSERT_NOT_REACHED(...) ((void)0)
 #define ASSERT_NOT_IMPLEMENTED_YET() ((void)0)
 #define ASSERT_IMPLIES(condition, assertion) ((void)0)
 #define NO_RETURN_DUE_TO_ASSERT
 
-#define ASSERT_UNUSED(variable, assertion) ((void)variable)
+#define ASSERT_UNUSED(variable, assertion, ...) ((void)variable)
 
 #if ENABLE(SECURITY_ASSERTIONS)
 #define ASSERT_WITH_SECURITY_IMPLICATION(assertion) \
@@ -314,10 +314,10 @@ WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH void WTFCrashWithSecurityImplication(v
 
 #else
 
-#define ASSERT(assertion) do { \
+#define ASSERT(assertion, ...) do { \
     if (!(assertion)) { \
         WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion); \
-        CRASH(); \
+        CRASH_WITH_INFO(__VA_ARGS__); \
     } \
 } while (0)
 
@@ -335,9 +335,9 @@ WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH void WTFCrashWithSecurityImplication(v
     } \
 } while (0)
 
-#define ASSERT_NOT_REACHED() do { \
+#define ASSERT_NOT_REACHED(...) do { \
     WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, 0); \
-    CRASH(); \
+    CRASH_WITH_INFO(__VA_ARGS__); \
 } while (0)
 
 #define ASSERT_NOT_IMPLEMENTED_YET() do { \
@@ -352,7 +352,7 @@ WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH void WTFCrashWithSecurityImplication(v
     } \
 } while (0)
 
-#define ASSERT_UNUSED(variable, assertion) ASSERT(assertion)
+#define ASSERT_UNUSED(variable, assertion, ...) ASSERT(assertion, __VA_ARGS__)
 
 #define NO_RETURN_DUE_TO_ASSERT NO_RETURN_DUE_TO_CRASH
 
@@ -510,42 +510,26 @@ WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH void WTFCrashWithSecurityImplication(v
 /* RELEASE_ASSERT */
 
 #if ASSERT_DISABLED
-#define RELEASE_ASSERT(assertion) do { \
+#define RELEASE_ASSERT(assertion, ...) do { \
     if (UNLIKELY(!(assertion))) \
-        CRASH(); \
+        CRASH_WITH_INFO(__VA_ARGS__); \
 } while (0)
 #define RELEASE_ASSERT_WITH_MESSAGE(assertion, ...) RELEASE_ASSERT(assertion)
 #define RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(assertion) RELEASE_ASSERT(assertion)
-#define RELEASE_ASSERT_NOT_REACHED() CRASH()
+#define RELEASE_ASSERT_NOT_REACHED(...) CRASH_WITH_INFO(__VA_ARGS__)
 #else
-#define RELEASE_ASSERT(assertion) ASSERT(assertion)
+#define RELEASE_ASSERT(assertion, ...) ASSERT(assertion, __VA_ARGS__)
 #define RELEASE_ASSERT_WITH_MESSAGE(assertion, ...) ASSERT_WITH_MESSAGE(assertion, __VA_ARGS__)
 #define RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(assertion) ASSERT_WITH_SECURITY_IMPLICATION(assertion)
 #define RELEASE_ASSERT_NOT_REACHED() ASSERT_NOT_REACHED()
 #endif
 
-/* UNREACHABLE_FOR_PLATFORM */
-
-#if COMPILER(CLANG)
-// This would be a macro except that its use of #pragma works best around
-// a function. Hence it uses macro naming convention.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmissing-noreturn"
-static inline void UNREACHABLE_FOR_PLATFORM()
-{
-    // This *MUST* be a release assert. We use it in places where it's better to crash than to keep
-    // going.
-    RELEASE_ASSERT_NOT_REACHED();
-}
-#pragma clang diagnostic pop
-#else
-#define UNREACHABLE_FOR_PLATFORM() RELEASE_ASSERT_NOT_REACHED()
-#endif
-
 #ifdef __cplusplus
 
 // The combination of line, file, function, and counter should be a unique number per call to this crash. This tricks the compiler into not coalescing calls to WTFCrashWithInfo.
 // The easiest way to fill these values per translation unit is to pass __LINE__, __FILE__, WTF_PRETTY_FUNCTION, and __COUNTER__.
+WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH NOT_TAIL_CALLED void WTFCrashWithInfo(int line, const char* file, const char* function, int counter, uint64_t reason, uint64_t misc1, uint64_t misc2, uint64_t misc3, uint64_t misc4, uint64_t misc5, uint64_t misc6);
+WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH NOT_TAIL_CALLED void WTFCrashWithInfo(int line, const char* file, const char* function, int counter, uint64_t reason, uint64_t misc1, uint64_t misc2, uint64_t misc3, uint64_t misc4, uint64_t misc5);
 WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH NOT_TAIL_CALLED void WTFCrashWithInfo(int line, const char* file, const char* function, int counter, uint64_t reason, uint64_t misc1, uint64_t misc2, uint64_t misc3, uint64_t misc4);
 WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH NOT_TAIL_CALLED void WTFCrashWithInfo(int line, const char* file, const char* function, int counter, uint64_t reason, uint64_t misc1, uint64_t misc2, uint64_t misc3);
 WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH NOT_TAIL_CALLED void WTFCrashWithInfo(int line, const char* file, const char* function, int counter, uint64_t reason, uint64_t misc1, uint64_t misc2);
@@ -592,6 +576,30 @@ inline void compilerFenceForCrash()
 #define CRASH_WITH_SECURITY_IMPLICATION_AND_INFO CRASH_WITH_INFO
 #endif // CRASH_WITH_SECURITY_IMPLICATION_AND_INFO
 
-#endif // __cplusplus
+#else /* not __cplusplus */
+
+#ifndef CRASH_WITH_INFO
+#define CRASH_WITH_INFO() CRASH()
+#endif
+
+#endif /* __cplusplus */
+
+/* UNREACHABLE_FOR_PLATFORM */
+
+#if COMPILER(CLANG)
+// This would be a macro except that its use of #pragma works best around
+// a function. Hence it uses macro naming convention.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-noreturn"
+static inline void UNREACHABLE_FOR_PLATFORM()
+{
+    // This *MUST* be a release assert. We use it in places where it's better to crash than to keep
+    // going.
+    RELEASE_ASSERT_NOT_REACHED();
+}
+#pragma clang diagnostic pop
+#else
+#define UNREACHABLE_FOR_PLATFORM() RELEASE_ASSERT_NOT_REACHED()
+#endif
 
 #endif /* WTF_Assertions_h */