Simplify WatchpointSet state tracking
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Nov 2013 02:10:42 +0000 (02:10 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Nov 2013 02:10:42 +0000 (02:10 +0000)
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:

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

18 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/assembler/MacroAssemblerARM64.h
Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h
Source/JavaScriptCore/assembler/MacroAssemblerX86.h
Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h
Source/JavaScriptCore/bytecode/Watchpoint.cpp
Source/JavaScriptCore/bytecode/Watchpoint.h
Source/JavaScriptCore/jit/JITPropertyAccess.cpp
Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/runtime/JSFunction.cpp
Source/JavaScriptCore/runtime/JSFunctionInlines.h
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/Structure.cpp
Source/JavaScriptCore/runtime/SymbolTable.cpp
Source/JavaScriptCore/runtime/SymbolTable.h

index f036306..6fa754f 100644 (file)
@@ -1,5 +1,64 @@
 2013-11-16  Filip Pizlo  <fpizlo@apple.com>
 
+        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  <fpizlo@apple.com>
+
         FTL should have an explicit notion of bytecode liveness
         https://bugs.webkit.org/show_bug.cgi?id=124181
 
index 56a6129..1215276 100644 (file)
@@ -1638,6 +1638,13 @@ public:
         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);
index 5194384..dfe57d0 100644 (file)
@@ -1377,6 +1377,12 @@ public:
         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);
index 53afadf..d80cfd4 100644 (file)
@@ -56,6 +56,7 @@ public:
     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 @@ public:
         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);
index 05138df..bfafe2e 100644 (file)
@@ -611,6 +611,13 @@ public:
         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))
     {
index 1b5b030..0fe335e 100644 (file)
@@ -38,9 +38,8 @@ Watchpoint::~Watchpoint()
         remove();
 }
 
-WatchpointSet::WatchpointSet(InitialWatchpointSetMode mode)
-    : m_isWatched(mode == InitializedWatching)
-    , m_isInvalidated(false)
+WatchpointSet::WatchpointSet(WatchpointState state)
+    : m_state(state)
 {
 }
 
@@ -57,19 +56,19 @@ WatchpointSet::~WatchpointSet()
 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 @@ WatchpointSet* InlineWatchpointSet::inflateSlow()
 {
     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;
index cd0a25e..fce70c7 100644 (file)
@@ -45,16 +45,22 @@ protected:
     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 @@ public:
     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,17 +85,20 @@ public:
     // 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();
     }
-    
-    bool* addressOfIsWatched() { return &m_isWatched; }
-    bool* addressOfIsInvalidated() { return &m_isInvalidated; }
+
+    int8_t* addressOfState() { return &m_state; }
     
     JS_EXPORT_PRIVATE void notifyWriteSlow(); // Call only if you've checked isWatched.
     
@@ -99,8 +108,7 @@ private:
     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 @@ private:
 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 @@ public:
             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 @@ public:
             fat()->startWatching();
             return;
         }
-        m_data |= IsWatchedFlag;
+        ASSERT(decodeState(m_data) != IsInvalidated);
+        m_data = encodeState(IsWatched);
     }
     
     void notifyWrite()
@@ -174,20 +183,31 @@ public:
             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); };
     
index fa5bf9c..b42e2c9 100644 (file)
@@ -637,7 +637,7 @@ void JIT::emitVarInjectionCheck(bool needsVarInjectionChecks)
 {
     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)
index 5f0dbe8..319a644 100644 (file)
@@ -667,7 +667,7 @@ void JIT::emitVarInjectionCheck(bool needsVarInjectionChecks)
 {
     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)
index c6a70df..f356f90 100644 (file)
@@ -71,6 +71,11 @@ const DeletedValueTag = -7
 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
index ffc3729..214f4c3 100644 (file)
@@ -1987,7 +1987,7 @@ macro varInjectionCheck(slowPath)
     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()
index 78b4d10..4dd7bc3 100644 (file)
@@ -1800,7 +1800,7 @@ macro varInjectionCheck(slowPath)
     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()
index 2705957..64ea9fb 100644 (file)
@@ -96,7 +96,7 @@ JSFunction::JSFunction(VM& vm, JSGlobalObject* globalObject, Structure* structur
     // 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)
 {
 }
 
index 4f89acd..fe4e114 100644 (file)
@@ -35,7 +35,7 @@ inline JSFunction::JSFunction(VM& vm, FunctionExecutable* executable, JSScope* s
     : 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.
 {
 }
 
index 9f543bb..83ff61e 100644 (file)
@@ -150,9 +150,9 @@ const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &all
 
 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)
index ba40312..7f383d8 100644 (file)
@@ -158,7 +158,7 @@ Structure::Structure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, co
     , 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 @@ Structure::Structure(VM& vm)
     : 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 @@ Structure::Structure(VM& vm, const Structure* previous)
     : 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())
index cb9b0bf..8926a89 100644 (file)
@@ -72,13 +72,7 @@ void SymbolTableEntry::attemptToWatch()
 {
     FatEntry* entry = inflate();
     if (!entry->m_watchpoints)
-        entry->m_watchpoints = adoptRef(new WatchpointSet(InitializedWatching));
-}
-
-bool* SymbolTableEntry::addressOfIsWatched()
-{
-    ASSERT(couldBeWatched());
-    return fatEntry()->m_watchpoints->addressOfIsWatched();
+        entry->m_watchpoints = adoptRef(new WatchpointSet(IsWatched));
 }
 
 void SymbolTableEntry::addWatchpoint(Watchpoint* watchpoint)
index 27e09a9..b8e9db7 100644 (file)
@@ -230,8 +230,6 @@ struct SymbolTableEntry {
     // immediately after a call to attemptToWatch().
     void attemptToWatch();
     
-    bool* addressOfIsWatched();
-    
     void addWatchpoint(Watchpoint*);
     
     WatchpointSet* watchpointSet()