#include "config.h"
#include "Watchpoint.h"
#include "AdaptiveInferredPropertyValueWatchpointBase.h"
#include "CachedSpecialPropertyAdaptiveStructureWatchpoint.h"
#include "CodeBlockJettisoningWatchpoint.h"
#include "DFGAdaptiveStructureWatchpoint.h"
#include "FunctionRareData.h"
#include "HeapInlines.h"
#include "LLIntPrototypeLoadAdaptiveStructureWatchpoint.h"
#include "StructureStubClearingWatchpoint.h"
#include "VM.h"
namespace JSC {
DEFINE_ALLOCATOR_WITH_HEAP_IDENTIFIER(Watchpoint);
DEFINE_ALLOCATOR_WITH_HEAP_IDENTIFIER(WatchpointSet);
void StringFireDetail::dump(PrintStream& out) const
{
out.print(m_string);
}
Watchpoint::~Watchpoint()
{
if (isOnList()) {
remove();
}
}
void Watchpoint::fire(VM& vm, const FireDetail& detail)
{
RELEASE_ASSERT(!isOnList());
switch (m_type) {
#define JSC_DEFINE_WATCHPOINT_DISPATCH(type, cast) \
case Type::type: \
static_cast<cast*>(this)->fireInternal(vm, detail); \
break;
JSC_WATCHPOINT_TYPES(JSC_DEFINE_WATCHPOINT_DISPATCH)
#undef JSC_DEFINE_WATCHPOINT_DISPATCH
}
}
WatchpointSet::WatchpointSet(WatchpointState state)
: m_state(state)
, m_setIsNotEmpty(false)
{
}
WatchpointSet::~WatchpointSet()
{
while (!m_set.isEmpty())
m_set.begin()->remove();
}
void WatchpointSet::add(Watchpoint* watchpoint)
{
ASSERT(!isCompilationThread());
ASSERT(state() != IsInvalidated);
if (!watchpoint)
return;
m_set.push(watchpoint);
m_setIsNotEmpty = true;
m_state = IsWatched;
}
void WatchpointSet::fireAllSlow(VM& vm, const FireDetail& detail)
{
ASSERT(state() == IsWatched);
WTF::storeStoreFence();
m_state = IsInvalidated; fireAllWatchpoints(vm, detail);
WTF::storeStoreFence();
}
void WatchpointSet::fireAllSlow(VM&, DeferredWatchpointFire* deferredWatchpoints)
{
ASSERT(state() == IsWatched);
WTF::storeStoreFence();
deferredWatchpoints->takeWatchpointsToFire(this);
m_state = IsInvalidated; WTF::storeStoreFence();
}
void WatchpointSet::fireAllSlow(VM& vm, const char* reason)
{
fireAllSlow(vm, StringFireDetail(reason));
}
void WatchpointSet::fireAllWatchpoints(VM& vm, const FireDetail& detail)
{
RELEASE_ASSERT(hasBeenInvalidated());
DeferGCForAWhile deferGC(vm.heap);
while (!m_set.isEmpty()) {
Watchpoint* watchpoint = m_set.begin();
ASSERT(watchpoint->isOnList());
watchpoint->remove();
ASSERT(m_set.begin() != watchpoint);
ASSERT(!watchpoint->isOnList());
watchpoint->fire(vm, detail);
}
}
void WatchpointSet::take(WatchpointSet* other)
{
ASSERT(state() == ClearWatchpoint);
m_set.takeFrom(other->m_set);
m_setIsNotEmpty = other->m_setIsNotEmpty;
m_state = other->m_state;
other->m_setIsNotEmpty = false;
}
void InlineWatchpointSet::add(Watchpoint* watchpoint)
{
inflate()->add(watchpoint);
}
void InlineWatchpointSet::fireAll(VM& vm, const char* reason)
{
fireAll(vm, StringFireDetail(reason));
}
WatchpointSet* InlineWatchpointSet::inflateSlow()
{
ASSERT(isThin());
ASSERT(!isCompilationThread());
WatchpointSet* fat = &WatchpointSet::create(decodeState(m_data)).leakRef();
WTF::storeStoreFence();
m_data = bitwise_cast<uintptr_t>(fat);
return fat;
}
void InlineWatchpointSet::freeFat()
{
ASSERT(isFat());
fat()->deref();
}
DeferredWatchpointFire::DeferredWatchpointFire(VM& vm)
: m_vm(vm)
, m_watchpointsToFire(ClearWatchpoint)
{
}
DeferredWatchpointFire::~DeferredWatchpointFire()
{
}
void DeferredWatchpointFire::fireAll()
{
if (m_watchpointsToFire.state() == IsWatched)
m_watchpointsToFire.fireAll(m_vm, *this);
}
void DeferredWatchpointFire::takeWatchpointsToFire(WatchpointSet* watchpointsToFire)
{
ASSERT(m_watchpointsToFire.state() == ClearWatchpoint);
ASSERT(watchpointsToFire->state() == IsWatched);
m_watchpointsToFire.take(watchpointsToFire);
}
}
namespace WTF {
void printInternal(PrintStream& out, JSC::WatchpointState state)
{
switch (state) {
case JSC::ClearWatchpoint:
out.print("ClearWatchpoint");
return;
case JSC::IsWatched:
out.print("IsWatched");
return;
case JSC::IsInvalidated:
out.print("IsInvalidated");
return;
}
RELEASE_ASSERT_NOT_REACHED();
}
}