#pragma once
#include <wtf/AutomaticThread.h>
#include <wtf/Box.h>
#include <wtf/Expected.h>
#include <wtf/HashSet.h>
#include <wtf/Lock.h>
#include <wtf/Locker.h>
#include <wtf/RefPtr.h>
#include <wtf/StackBounds.h>
namespace JSC {
class ExecState;
class VM;
class VMTraps {
typedef uint8_t BitField;
public:
enum class Error {
None,
LockUnavailable,
NotJITCode
};
enum EventType {
NeedDebuggerBreak,
NeedTermination,
NeedWatchdogCheck,
NumberOfEventTypes, Invalid
};
class Mask {
public:
enum AllEventTypes { AllEventTypesTag };
Mask(AllEventTypes)
: m_mask(std::numeric_limits<BitField>::max())
{ }
static Mask allEventTypes() { return Mask(AllEventTypesTag); }
template<typename... Arguments>
Mask(Arguments... args)
: m_mask(0)
{
init(args...);
}
BitField bits() const { return m_mask; }
private:
template<typename... Arguments>
void init(EventType eventType, Arguments... args)
{
ASSERT(eventType < NumberOfEventTypes);
m_mask |= (1 << eventType);
init(args...);
}
void init() { }
BitField m_mask;
};
~VMTraps();
VMTraps();
void willDestroyVM();
bool needTrapHandling() { return m_needTrapHandling; }
bool needTrapHandling(Mask mask) { return m_needTrapHandling & mask.bits(); }
void* needTrapHandlingAddress() { return &m_needTrapHandling; }
void notifyGrabAllLocks()
{
if (needTrapHandling())
invalidateCodeBlocksOnStack();
}
JS_EXPORT_PRIVATE void fireTrap(EventType);
void handleTraps(ExecState*, VMTraps::Mask);
void tryInstallTrapBreakpoints(struct SignalContext&, StackBounds);
private:
VM& vm() const;
bool hasTrapForEvent(Locker<Lock>&, EventType eventType, Mask mask)
{
ASSERT(eventType < NumberOfEventTypes);
return (m_trapsBitField & mask.bits() & (1 << eventType));
}
void setTrapForEvent(Locker<Lock>&, EventType eventType)
{
ASSERT(eventType < NumberOfEventTypes);
m_trapsBitField |= (1 << eventType);
}
void clearTrapForEvent(Locker<Lock>&, EventType eventType)
{
ASSERT(eventType < NumberOfEventTypes);
m_trapsBitField &= ~(1 << eventType);
}
EventType takeTopPriorityTrap(Mask);
#if ENABLE(SIGNAL_BASED_VM_TRAPS)
class SignalSender;
friend class SignalSender;
void invalidateCodeBlocksOnStack();
void invalidateCodeBlocksOnStack(ExecState* topCallFrame);
void invalidateCodeBlocksOnStack(Locker<Lock>& codeBlockSetLocker, ExecState* topCallFrame);
void addSignalSender(SignalSender*);
void removeSignalSender(SignalSender*);
#else
void invalidateCodeBlocksOnStack() { }
void invalidateCodeBlocksOnStack(ExecState*) { }
#endif
Box<Lock> m_lock;
Ref<AutomaticThreadCondition> m_trapSet;
union {
BitField m_needTrapHandling { 0 };
BitField m_trapsBitField;
};
bool m_needToInvalidatedCodeBlocks { false };
bool m_isShuttingDown { false };
#if ENABLE(SIGNAL_BASED_VM_TRAPS)
RefPtr<SignalSender> m_signalSender;
#endif
friend class LLIntOffsetsExtractor;
friend class SignalSender;
};
}