Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Source/JavaScriptCore/heap/HandleSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "HandleBlock.h"
#include "HandleBlockInlines.h"
#include "JSCJSValueInlines.h"
#include "VM.h"

namespace JSC {

Expand Down Expand Up @@ -93,4 +94,17 @@ bool HandleSet::isLiveNode(Node* node)
}
#endif // ENABLE(GC_VALIDATION) || ASSERT_ENABLED

#if ASSERT_ENABLED
void HandleSet::assertMayMutate()
{
// Allocating, deallocating, or re-targeting a Strong handle mutates
// m_strongList, which the GC's strong-handles marking constraint scans.
// The VM's API lock is what orders those mutations with the scan, so a
// mutation from a thread that does not hold the lock is a data race. The
// classic way to get here is a Strong captured by value in a lambda that
// another thread destroys.
ASSERT_WITH_MESSAGE(m_vm.currentThreadIsHoldingAPILock(), "Strong handles may only be created, written, or destroyed while holding their VM's API lock");
}
#endif // ASSERT_ENABLED

} // namespace JSC
9 changes: 9 additions & 0 deletions Source/JavaScriptCore/heap/HandleSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ class HandleSet {
JS_EXPORT_PRIVATE bool isLiveNode(Node*);
#endif

#if ASSERT_ENABLED
JS_EXPORT_PRIVATE void assertMayMutate();
#else
void assertMayMutate() { }
#endif

VM& m_vm;
DoublyLinkedList<HandleBlock> m_blockList;

Expand All @@ -106,6 +112,7 @@ inline VM& HandleSet::vm()

inline HandleSlot HandleSet::allocate()
{
assertMayMutate();
if (m_freeList.isEmpty())
grow();

Expand All @@ -116,6 +123,7 @@ inline HandleSlot HandleSet::allocate()

inline void HandleSet::deallocate(HandleSlot handle)
{
assertMayMutate();
HandleSet::Node* node = HandleNode::toHandleNode(handle);
if (node->isOnList())
NodeList::remove(node);
Expand Down Expand Up @@ -147,6 +155,7 @@ template<typename Functor> void HandleSet::forEachStrongHandle(const Functor& fu
template<bool isCellOnly>
inline void HandleSet::writeBarrier(HandleSlot slot, JSValue value)
{
assertMayMutate();
bool valueIsNonEmptyCell = value && (isCellOnly || value.isCell());
bool slotIsNonEmptyCell = *slot && (isCellOnly || slot->isCell());
if (valueIsNonEmptyCell == slotIsNonEmptyCell)
Expand Down
Loading