Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (159394 => 159395)
--- trunk/Source/_javascript_Core/ChangeLog 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/ChangeLog 2013-11-18 02:10:42 UTC (rev 159395)
@@ -1,5 +1,64 @@
2013-11-16 Filip Pizlo <[email protected]>
+ Simplify WatchpointSet state tracking
+ https://bugs.webkit.org/show_bug.cgi?id=124465
+
+ Reviewed by Sam Weinig.
+
+ We previously represented the state of watchpoint sets using two booleans. But that
+ makes it awkward to case over the state.
+
+ We also previously supported a watchpoint set being both watched and invalidated. We
+ never used that capability, and its presence was just purely confusing.
+
+ This turns the whole thing into an enum.
+
+ * assembler/MacroAssemblerARM64.h:
+ (JSC::MacroAssemblerARM64::branch8):
+ * assembler/MacroAssemblerARMv7.h:
+ (JSC::MacroAssemblerARMv7::branch8):
+ * assembler/MacroAssemblerX86.h:
+ (JSC::MacroAssemblerX86::branch8):
+ * assembler/MacroAssemblerX86_64.h:
+ (JSC::MacroAssemblerX86_64::branch8):
+ * bytecode/Watchpoint.cpp:
+ (JSC::WatchpointSet::WatchpointSet):
+ (JSC::WatchpointSet::add):
+ (JSC::WatchpointSet::notifyWriteSlow):
+ (JSC::InlineWatchpointSet::inflateSlow):
+ * bytecode/Watchpoint.h:
+ (JSC::WatchpointSet::state):
+ (JSC::WatchpointSet::isStillValid):
+ (JSC::WatchpointSet::startWatching):
+ (JSC::WatchpointSet::notifyWrite):
+ (JSC::WatchpointSet::addressOfState):
+ (JSC::InlineWatchpointSet::InlineWatchpointSet):
+ (JSC::InlineWatchpointSet::hasBeenInvalidated):
+ (JSC::InlineWatchpointSet::startWatching):
+ (JSC::InlineWatchpointSet::notifyWrite):
+ (JSC::InlineWatchpointSet::decodeState):
+ (JSC::InlineWatchpointSet::encodeState):
+ * jit/JITPropertyAccess.cpp:
+ (JSC::JIT::emitVarInjectionCheck):
+ * jit/JITPropertyAccess32_64.cpp:
+ (JSC::JIT::emitVarInjectionCheck):
+ * llint/LowLevelInterpreter.asm:
+ * llint/LowLevelInterpreter32_64.asm:
+ * llint/LowLevelInterpreter64.asm:
+ * runtime/JSFunction.cpp:
+ (JSC::JSFunction::JSFunction):
+ * runtime/JSFunctionInlines.h:
+ (JSC::JSFunction::JSFunction):
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::JSGlobalObject):
+ * runtime/Structure.cpp:
+ (JSC::Structure::Structure):
+ * runtime/SymbolTable.cpp:
+ (JSC::SymbolTableEntry::attemptToWatch):
+ * runtime/SymbolTable.h:
+
+2013-11-16 Filip Pizlo <[email protected]>
+
FTL should have an explicit notion of bytecode liveness
https://bugs.webkit.org/show_bug.cgi?id=124181
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h (159394 => 159395)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2013-11-18 02:10:42 UTC (rev 159395)
@@ -1638,6 +1638,13 @@
return branch32(cond, memoryTempRegister, right);
}
+ Jump branch8(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
+ {
+ ASSERT(!(0xffffff00 & right.m_value));
+ load8(left, getCachedMemoryTempRegisterIDAndInvalidate());
+ return branch32(cond, memoryTempRegister, right);
+ }
+
Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
{
m_assembler.tst<32>(reg, mask);
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h (159394 => 159395)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h 2013-11-18 02:10:42 UTC (rev 159395)
@@ -1377,6 +1377,12 @@
return branch32(cond, addressTempRegister, right);
}
+ Jump branch8(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
+ {
+ load8(left, addressTempRegister);
+ return branch32(cond, addressTempRegister, right);
+ }
+
Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
{
m_assembler.tst(reg, mask);
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86.h (159394 => 159395)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86.h 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86.h 2013-11-18 02:10:42 UTC (rev 159395)
@@ -56,6 +56,7 @@
using MacroAssemblerX86Common::loadDouble;
using MacroAssemblerX86Common::storeDouble;
using MacroAssemblerX86Common::convertInt32ToDouble;
+ using MacroAssemblerX86Common::branch8;
using MacroAssemblerX86Common::branchTest8;
void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
@@ -213,6 +214,12 @@
return DataLabelPtr(this);
}
+ Jump branch8(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
+ {
+ m_assembler.cmpb_im(right.m_value, left.m_ptr);
+ return Jump(m_assembler.jCC(x86Condition(cond)));
+ }
+
Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
{
ASSERT(mask.m_value >= -128 && mask.m_value <= 255);
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h (159394 => 159395)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h 2013-11-18 02:10:42 UTC (rev 159395)
@@ -611,6 +611,13 @@
return label;
}
+ using MacroAssemblerX86Common::branch8;
+ Jump branch8(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
+ {
+ MacroAssemblerX86Common::move(TrustedImmPtr(left.m_ptr), scratchRegister);
+ return MacroAssemblerX86Common::branch8(cond, Address(scratchRegister), right);
+ }
+
using MacroAssemblerX86Common::branchTest8;
Jump branchTest8(ResultCondition cond, ExtendedAddress address, TrustedImm32 mask = TrustedImm32(-1))
{
Modified: trunk/Source/_javascript_Core/bytecode/Watchpoint.cpp (159394 => 159395)
--- trunk/Source/_javascript_Core/bytecode/Watchpoint.cpp 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/bytecode/Watchpoint.cpp 2013-11-18 02:10:42 UTC (rev 159395)
@@ -38,9 +38,8 @@
remove();
}
-WatchpointSet::WatchpointSet(InitialWatchpointSetMode mode)
- : m_isWatched(mode == InitializedWatching)
- , m_isInvalidated(false)
+WatchpointSet::WatchpointSet(WatchpointState state)
+ : m_state(state)
{
}
@@ -57,19 +56,19 @@
void WatchpointSet::add(Watchpoint* watchpoint)
{
ASSERT(!isCompilationThread());
+ ASSERT(state() != IsInvalidated);
if (!watchpoint)
return;
m_set.push(watchpoint);
- m_isWatched = true;
+ m_state = IsWatched;
}
void WatchpointSet::notifyWriteSlow()
{
- ASSERT(m_isWatched);
+ ASSERT(state() == IsWatched);
fireAllWatchpoints();
- m_isWatched = false;
- m_isInvalidated = true;
+ m_state = IsInvalidated;
WTF::storeStoreFence();
}
@@ -88,11 +87,7 @@
{
ASSERT(isThin());
ASSERT(!isCompilationThread());
- WatchpointSet* fat = adoptRef(new WatchpointSet(InitializedBlind)).leakRef();
- if (m_data & IsInvalidatedFlag)
- fat->m_isInvalidated = true;
- if (m_data & IsWatchedFlag)
- fat->m_isWatched = true;
+ WatchpointSet* fat = adoptRef(new WatchpointSet(decodeState(m_data))).leakRef();
WTF::storeStoreFence();
m_data = bitwise_cast<uintptr_t>(fat);
return fat;
Modified: trunk/Source/_javascript_Core/bytecode/Watchpoint.h (159394 => 159395)
--- trunk/Source/_javascript_Core/bytecode/Watchpoint.h 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/bytecode/Watchpoint.h 2013-11-18 02:10:42 UTC (rev 159395)
@@ -45,16 +45,22 @@
virtual void fireInternal() = 0;
};
-enum InitialWatchpointSetMode { InitializedWatching, InitializedBlind };
+enum WatchpointState {
+ ClearWatchpoint,
+ IsWatched,
+ IsInvalidated
+};
class InlineWatchpointSet;
class WatchpointSet : public ThreadSafeRefCounted<WatchpointSet> {
friend class LLIntOffsetsExtractor;
public:
- WatchpointSet(InitialWatchpointSetMode);
+ WatchpointSet(WatchpointState);
~WatchpointSet(); // Note that this will not fire any of the watchpoints; if you need to know when a WatchpointSet dies then you need a separate mechanism for this.
+ WatchpointState state() const { return static_cast<WatchpointState>(m_state); }
+
// It is safe to call this from another thread. It may return true
// even if the set actually had been invalidated, but that ought to happen
// only in the case of races, and should be rare. Guarantees that if you
@@ -64,7 +70,7 @@
bool isStillValid() const
{
WTF::loadLoadFence();
- return !m_isInvalidated;
+ return state() != IsInvalidated;
}
// Like isStillValid(), may be called from another thread.
bool hasBeenInvalidated() const { return !isStillValid(); }
@@ -79,18 +85,21 @@
// watchpoint would have fired. That's a pretty good indication that you
// probably don't want to set watchpoints, since we typically don't want to
// set watchpoints that we believe will actually be fired.
- void startWatching() { m_isWatched = true; }
+ void startWatching()
+ {
+ ASSERT(state() != IsInvalidated);
+ m_state = IsWatched;
+ }
void notifyWrite()
{
- if (!m_isWatched)
+ if (state() != IsWatched)
return;
notifyWriteSlow();
}
+
+ int8_t* addressOfState() { return &m_state; }
- bool* addressOfIsWatched() { return &m_isWatched; }
- bool* addressOfIsInvalidated() { return &m_isInvalidated; }
-
JS_EXPORT_PRIVATE void notifyWriteSlow(); // Call only if you've checked isWatched.
private:
@@ -99,8 +108,7 @@
friend class InlineWatchpointSet;
SentinelLinkedList<Watchpoint, BasicRawSentinelNode<Watchpoint>> m_set;
- bool m_isWatched;
- bool m_isInvalidated;
+ int8_t m_state;
};
// InlineWatchpointSet is a low-overhead, non-copyable watchpoint set in which
@@ -125,8 +133,8 @@
class InlineWatchpointSet {
WTF_MAKE_NONCOPYABLE(InlineWatchpointSet);
public:
- InlineWatchpointSet(InitialWatchpointSetMode mode)
- : m_data((mode == InitializedWatching ? IsWatchedFlag : 0) | IsThinFlag)
+ InlineWatchpointSet(WatchpointState state)
+ : m_data(encodeState(state))
{
}
@@ -148,7 +156,7 @@
WTF::loadLoadFence();
return fat(data)->hasBeenInvalidated();
}
- return data & IsInvalidatedFlag;
+ return decodeState(data) == IsInvalidated;
}
// Like hasBeenInvalidated(), may be called from another thread.
@@ -165,7 +173,8 @@
fat()->startWatching();
return;
}
- m_data |= IsWatchedFlag;
+ ASSERT(decodeState(m_data) != IsInvalidated);
+ m_data = encodeState(IsWatched);
}
void notifyWrite()
@@ -174,20 +183,31 @@
fat()->notifyWrite();
return;
}
- if (!(m_data & IsWatchedFlag))
+ if (decodeState(m_data) == ClearWatchpoint)
return;
- m_data |= IsInvalidatedFlag;
+ m_data = encodeState(IsInvalidated);
WTF::storeStoreFence();
}
private:
static const uintptr_t IsThinFlag = 1;
- static const uintptr_t IsInvalidatedFlag = 2;
- static const uintptr_t IsWatchedFlag = 4;
+ static const uintptr_t StateMask = 6;
+ static const uintptr_t StateShift = 1;
static bool isThin(uintptr_t data) { return data & IsThinFlag; }
static bool isFat(uintptr_t data) { return !isThin(data); }
+ static WatchpointState decodeState(uintptr_t data)
+ {
+ ASSERT(isThin(data));
+ return static_cast<WatchpointState>((data & StateMask) >> StateShift);
+ }
+
+ static uintptr_t encodeState(WatchpointState state)
+ {
+ return (state << StateShift) | IsThinFlag;
+ }
+
bool isThin() const { return isThin(m_data); }
bool isFat() const { return isFat(m_data); };
Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp (159394 => 159395)
--- trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp 2013-11-18 02:10:42 UTC (rev 159395)
@@ -637,7 +637,7 @@
{
if (!needsVarInjectionChecks)
return;
- addSlowCase(branchTest8(NonZero, AbsoluteAddress(m_codeBlock->globalObject()->varInjectionWatchpoint()->addressOfIsInvalidated())));
+ addSlowCase(branch8(Equal, AbsoluteAddress(m_codeBlock->globalObject()->varInjectionWatchpoint()->addressOfState()), TrustedImm32(IsInvalidated)));
}
void JIT::emitResolveClosure(int dst, bool needsVarInjectionChecks, unsigned depth)
Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp (159394 => 159395)
--- trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp 2013-11-18 02:10:42 UTC (rev 159395)
@@ -667,7 +667,7 @@
{
if (!needsVarInjectionChecks)
return;
- addSlowCase(branchTest8(NonZero, AbsoluteAddress(m_codeBlock->globalObject()->varInjectionWatchpoint()->addressOfIsInvalidated())));
+ addSlowCase(branch8(Equal, AbsoluteAddress(m_codeBlock->globalObject()->varInjectionWatchpoint()->addressOfState()), TrustedImm32(IsInvalidated)));
}
void JIT::emitResolveClosure(int dst, bool needsVarInjectionChecks, unsigned depth)
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm (159394 => 159395)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm 2013-11-18 02:10:42 UTC (rev 159395)
@@ -71,6 +71,11 @@
const LowestTag = DeletedValueTag
end
+# Watchpoint states
+const ClearWatchpoint = 0
+const IsWatched = 1
+const IsInvalidated = 2
+
# Some register conventions.
if JSVALUE64
# - Use a pair of registers to represent the PC: one register for the
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm (159394 => 159395)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm 2013-11-18 02:10:42 UTC (rev 159395)
@@ -1987,7 +1987,7 @@
loadp CodeBlock[cfr], t0
loadp CodeBlock::m_globalObject[t0], t0
loadp JSGlobalObject::m_varInjectionWatchpoint[t0], t0
- btbnz WatchpointSet::m_isInvalidated[t0], slowPath
+ bbeq WatchpointSet::m_state[t0], IsInvalidated, slowPath
end
macro resolveScope()
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (159394 => 159395)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2013-11-18 02:10:42 UTC (rev 159395)
@@ -1800,7 +1800,7 @@
loadp CodeBlock[cfr], t0
loadp CodeBlock::m_globalObject[t0], t0
loadp JSGlobalObject::m_varInjectionWatchpoint[t0], t0
- btbnz WatchpointSet::m_isInvalidated[t0], slowPath
+ bbeq WatchpointSet::m_state[t0], IsInvalidated, slowPath
end
macro resolveScope()
Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (159394 => 159395)
--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp 2013-11-18 02:10:42 UTC (rev 159395)
@@ -96,7 +96,7 @@
// was clobbered exactly once, but that seems like overkill. In almost all cases it will be
// clobbered once, and if it's clobbered more than once, that will probably only occur
// before we started optimizing, anyway.
- , m_allocationProfileWatchpoint(InitializedBlind)
+ , m_allocationProfileWatchpoint(ClearWatchpoint)
{
}
Modified: trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h (159394 => 159395)
--- trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h 2013-11-18 02:10:42 UTC (rev 159395)
@@ -35,7 +35,7 @@
: Base(vm, scope->globalObject()->functionStructure())
, m_executable(vm, this, executable)
, m_scope(vm, this, scope)
- , m_allocationProfileWatchpoint(InitializedBlind) // See comment in JSFunction.cpp concerning the reason for using InitializedBlind as opposed to InitializedWatching.
+ , m_allocationProfileWatchpoint(ClearWatchpoint) // See comment in JSFunction.cpp concerning the reason for using ClearWatchpoint as opposed to IsWatched.
{
}
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (159394 => 159395)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2013-11-18 02:10:42 UTC (rev 159395)
@@ -150,9 +150,9 @@
JSGlobalObject::JSGlobalObject(VM& vm, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable)
: Base(vm, structure, 0)
- , m_masqueradesAsUndefinedWatchpoint(adoptRef(new WatchpointSet(InitializedWatching)))
- , m_havingABadTimeWatchpoint(adoptRef(new WatchpointSet(InitializedWatching)))
- , m_varInjectionWatchpoint(adoptRef(new WatchpointSet(InitializedWatching)))
+ , m_masqueradesAsUndefinedWatchpoint(adoptRef(new WatchpointSet(IsWatched)))
+ , m_havingABadTimeWatchpoint(adoptRef(new WatchpointSet(IsWatched)))
+ , m_varInjectionWatchpoint(adoptRef(new WatchpointSet(IsWatched)))
, m_weakRandom(Options::forceWeakRandomSeed() ? Options::forcedWeakRandomSeed() : static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
, m_evalEnabled(true)
, m_globalObjectMethodTable(globalObjectMethodTable ? globalObjectMethodTable : &s_globalObjectMethodTable)
Modified: trunk/Source/_javascript_Core/runtime/Structure.cpp (159394 => 159395)
--- trunk/Source/_javascript_Core/runtime/Structure.cpp 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/runtime/Structure.cpp 2013-11-18 02:10:42 UTC (rev 159395)
@@ -158,7 +158,7 @@
, m_globalObject(vm, this, globalObject, WriteBarrier<JSGlobalObject>::MayBeNull)
, m_prototype(vm, this, prototype)
, m_classInfo(classInfo)
- , m_transitionWatchpointSet(InitializedWatching)
+ , m_transitionWatchpointSet(IsWatched)
, m_offset(invalidOffset)
, m_typeInfo(typeInfo)
, m_indexingType(indexingType)
@@ -185,7 +185,7 @@
: JSCell(CreatingEarlyCell)
, m_prototype(vm, this, jsNull())
, m_classInfo(info())
- , m_transitionWatchpointSet(InitializedWatching)
+ , m_transitionWatchpointSet(IsWatched)
, m_offset(invalidOffset)
, m_typeInfo(CompoundType, OverridesVisitChildren)
, m_indexingType(0)
@@ -207,7 +207,7 @@
: JSCell(vm, vm.structureStructure.get())
, m_prototype(vm, this, previous->storedPrototype())
, m_classInfo(previous->m_classInfo)
- , m_transitionWatchpointSet(InitializedWatching)
+ , m_transitionWatchpointSet(IsWatched)
, m_offset(invalidOffset)
, m_typeInfo(previous->typeInfo().type(), previous->typeInfo().flags() & ~StructureHasRareData)
, m_indexingType(previous->indexingTypeIncludingHistory())
Modified: trunk/Source/_javascript_Core/runtime/SymbolTable.cpp (159394 => 159395)
--- trunk/Source/_javascript_Core/runtime/SymbolTable.cpp 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/runtime/SymbolTable.cpp 2013-11-18 02:10:42 UTC (rev 159395)
@@ -72,15 +72,9 @@
{
FatEntry* entry = inflate();
if (!entry->m_watchpoints)
- entry->m_watchpoints = adoptRef(new WatchpointSet(InitializedWatching));
+ entry->m_watchpoints = adoptRef(new WatchpointSet(IsWatched));
}
-bool* SymbolTableEntry::addressOfIsWatched()
-{
- ASSERT(couldBeWatched());
- return fatEntry()->m_watchpoints->addressOfIsWatched();
-}
-
void SymbolTableEntry::addWatchpoint(Watchpoint* watchpoint)
{
ASSERT(couldBeWatched());
Modified: trunk/Source/_javascript_Core/runtime/SymbolTable.h (159394 => 159395)
--- trunk/Source/_javascript_Core/runtime/SymbolTable.h 2013-11-18 01:46:48 UTC (rev 159394)
+++ trunk/Source/_javascript_Core/runtime/SymbolTable.h 2013-11-18 02:10:42 UTC (rev 159395)
@@ -230,8 +230,6 @@
// immediately after a call to attemptToWatch().
void attemptToWatch();
- bool* addressOfIsWatched();
-
void addWatchpoint(Watchpoint*);
WatchpointSet* watchpointSet()