Diff
Modified: trunk/LayoutTests/ChangeLog (162939 => 162940)
--- trunk/LayoutTests/ChangeLog 2014-01-28 17:38:49 UTC (rev 162939)
+++ trunk/LayoutTests/ChangeLog 2014-01-28 17:43:07 UTC (rev 162940)
@@ -1,3 +1,23 @@
+2014-01-28 Mark Lam <mark....@apple.com>
+
+ Jettison DFG code when neither breakpoints or the profiler are active.
+ <https://webkit.org/b/127766>
+
+ Reviewed by Geoffrey Garen.
+
+ Added a test to exercise setting a breakpoint in 2 DFG compiled functions:
+ 1 not inlined, and 1 inlined.
+
+ * inspector-protocol/debugger/resources/breakpoint.js:
+ (notInlineable):
+ (inlineable):
+ (notInliningFoo):
+ (inliningFoo):
+ (dfgWithoutInline):
+ (dfgWithInline):
+ * inspector-protocol/debugger/setBreakpoint-dfg-expected.txt: Added.
+ * inspector-protocol/debugger/setBreakpoint-dfg.html: Added.
+
2014-01-28 Gurpreet Kaur <k.gurpr...@samsung.com>
Add support for menclose element
Modified: trunk/LayoutTests/inspector-protocol/debugger/resources/breakpoint.js (162939 => 162940)
--- trunk/LayoutTests/inspector-protocol/debugger/resources/breakpoint.js 2014-01-28 17:38:49 UTC (rev 162939)
+++ trunk/LayoutTests/inspector-protocol/debugger/resources/breakpoint.js 2014-01-28 17:43:07 UTC (rev 162940)
@@ -17,3 +17,42 @@
{
log("inside breakpointActions a:(" + a + ") b:(" + b + ")");
}
+
+function notInlineable(x)
+{
+ var func = new Function("return x + 100;");
+ return x + 3;
+}
+
+function inlineable(x)
+{
+ return x + 5;
+}
+
+function notInliningFoo(x)
+{
+ return notInlineable(x);
+}
+
+function inliningFoo(x)
+{
+ return inlineable(x);
+}
+
+function dfgWithoutInline()
+{
+ var i;
+ var result = 0;
+ for (i = 0; i < 1000; i++)
+ result += notInliningFoo(i);
+ log("dfgWithoutInline result: " + result);
+}
+
+function dfgWithInline()
+{
+ var i;
+ var result = 0;
+ for (i = 0; i < 1000; i++)
+ result += inliningFoo(i);
+ log("dfgWithInline result: " + result);
+}
Added: trunk/LayoutTests/inspector-protocol/debugger/setBreakpoint-dfg-expected.txt (0 => 162940)
--- trunk/LayoutTests/inspector-protocol/debugger/setBreakpoint-dfg-expected.txt (rev 0)
+++ trunk/LayoutTests/inspector-protocol/debugger/setBreakpoint-dfg-expected.txt 2014-01-28 17:43:07 UTC (rev 162940)
@@ -0,0 +1,18 @@
+Debugger.setBreakpoint in DFG compiled functions.
+
+Found breakpoint.js
+dfgWithoutInline result: 502500
+dfgWithInline result: 504500
+dfg functions warmed up
+
+Breakpoint set in notInlineable()
+Breakpoint set in inlineable()
+
+Hit Breakpoint 1!
+Removed Breakpoint 1!
+dfgWithoutInline result: 502500
+Hit Breakpoint 2!
+Removed Breakpoint 2!
+PASS
+dfgWithInline result: 504500
+
Added: trunk/LayoutTests/inspector-protocol/debugger/setBreakpoint-dfg.html (0 => 162940)
--- trunk/LayoutTests/inspector-protocol/debugger/setBreakpoint-dfg.html (rev 0)
+++ trunk/LayoutTests/inspector-protocol/debugger/setBreakpoint-dfg.html 2014-01-28 17:43:07 UTC (rev 162940)
@@ -0,0 +1,85 @@
+<html>
+<head>
+<script src=""
+<script src=""
+
+<script>
+// Put this here instead of on <body onload> to prevent an extra Debugger.scriptParsed event.
+window._onload_ = runTest;
+
+function test()
+{
+ // This test setting 2 breakpoints in DFG compiled functions: one inlined,
+ // and one not inlined.
+
+ InspectorTest.sendCommand("Debugger.enable", {});
+
+ var dfgNonInlinedBreakpointId = null;
+ var dfgInlinedBreakpointId = null;
+ var scriptIdentifier = 0;
+ var startLine = 0;
+
+ InspectorTest.eventHandler["Debugger.scriptParsed"] = function(messageObject)
+ {
+ if (/resources\/breakpoint\.js$/.test(messageObject.params.url)) {
+ InspectorTest.log("Found breakpoint.js");
+ scriptIdentifier = messageObject.params.scriptId;
+ startLine = messageObject.params.startLine;
+
+ InspectorTest.sendCommand("Runtime.evaluate", {
+ _expression_: "dfgWithoutInline(); dfgWithInline();"
+ }, function(responseObject) {
+ InspectorTest.log("dfg functions warmed up\n");
+
+ var location1 = {scriptId: scriptIdentifier, lineNumber: 22, columnNumber: 0};
+
+ InspectorTest.sendCommand("Debugger.setBreakpoint", {location: location1}, function(responseObject) {
+ InspectorTest.checkForError(responseObject);
+ InspectorTest.log("Breakpoint set in notInlineable()");
+
+ dfgNonInlinedBreakpointId = responseObject.result.breakpointId;
+ var location2 = {scriptId: scriptIdentifier, lineNumber: 28, columnNumber: 0};
+ InspectorTest.sendCommand("Debugger.setBreakpoint", {location: location2}, function(responseObject) {
+ InspectorTest.checkForError(responseObject);
+ InspectorTest.log("Breakpoint set in inlineable()\n");
+
+ dfgInlinedBreakpointId = responseObject.result.breakpointId;
+ InspectorTest.sendCommand("Runtime.evaluate", {
+ _expression_: "dfgWithoutInline(); dfgWithInline();"
+ });
+ });
+ });
+ });
+ }
+ }
+
+ var breakpointsHit = 0;
+ InspectorTest.eventHandler["Debugger.paused"] = function(messageObject)
+ {
+ var breakpointId = null;
+ breakpointsHit++;
+ InspectorTest.log("Hit Breakpoint " + breakpointsHit + "!");
+ if (breakpointsHit == 1)
+ breakpointId = dfgNonInlinedBreakpointId;
+ else if (breakpointsHit == 2)
+ breakpointId = dfgInlinedBreakpointId;
+ else
+ InspectorTest.log("Unexpected breakpoint");
+
+ InspectorTest.sendCommand("Debugger.removeBreakpoint", {"breakpointId": breakpointId}, function(responseObject) {
+ InspectorTest.log("Removed Breakpoint " + breakpointsHit + "!");
+ InspectorTest.sendCommand("Debugger.resume", {}, function(responseObject) {
+ if (breakpointsHit == 2) {
+ InspectorTest.log("PASS");
+ InspectorTest.completeTest();
+ }
+ });
+ });
+ }
+}
+</script>
+</head>
+<body>
+<p>Debugger.setBreakpoint in DFG compiled functions.</p>
+</body>
+</html>
Modified: trunk/Source/_javascript_Core/ChangeLog (162939 => 162940)
--- trunk/Source/_javascript_Core/ChangeLog 2014-01-28 17:38:49 UTC (rev 162939)
+++ trunk/Source/_javascript_Core/ChangeLog 2014-01-28 17:43:07 UTC (rev 162940)
@@ -1,3 +1,58 @@
+2014-01-28 Mark Lam <mark....@apple.com>
+
+ Jettison DFG code when neither breakpoints or the profiler are active.
+ <https://webkit.org/b/127766>
+
+ Reviewed by Geoffrey Garen.
+
+ We need to jettison the DFG CodeBlocks under the following circumstances:
+ 1. When adding breakpoints to a CodeBlock, jettison it if it is a DFG CodeBlock.
+ 2. When enabling stepping mode in a CodeBlock, jettison it if it a DFG CodeBlock.
+ 3. When settign the enabled profiler in the VM, we need to jettison all DFG
+ CodeBlocks.
+
+ Instead of emitting speculation checks, the DFG code will now treat Breakpoint,
+ ProfileWillCall, and ProfileDidCall as no-ops similar to a Phantom node. We
+ still need to track these nodes so that they match the corresponding opcodes
+ in the baseline JIT when we jettison and OSR exit. Without them, we would OSR
+ exit to the wrong location in the baseline JIT code.
+
+ In DFGDriver's compileImpl() and DFGPlan's finalizeWithoutNotifyingCallback()
+ we fail the compilation effort with a CompilationInvalidated result. This allows
+ the DFG compiler to re-attampt the compilation of the function after some time
+ if it is hot. The CompilationInvalidated result is supposed to cause the DFG
+ to exercise an exponential back off before re-attempting compilation again
+ (see runtime/CompilationResult.h).
+
+ This patch improves the Octane score from ~2950 to ~3067.
+
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::addBreakpoint):
+ (JSC::CodeBlock::setSteppingMode):
+ * bytecode/CodeBlock.h:
+ * debugger/Debugger.h:
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGClobberize.h:
+ (JSC::DFG::clobberize):
+ * dfg/DFGDriver.cpp:
+ (JSC::DFG::compileImpl):
+ * dfg/DFGPlan.cpp:
+ (JSC::DFG::Plan::finalizeWithoutNotifyingCallback):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * profiler/LegacyProfiler.cpp:
+ (JSC::LegacyProfiler::startProfiling):
+ (JSC::LegacyProfiler::stopProfiling):
+ * runtime/VM.cpp:
+ (JSC::VM::VM):
+ (JSC::SetEnabledProfilerFunctor::operator()):
+ (JSC::VM::setEnabledProfiler):
+ * runtime/VM.h:
+ (JSC::VM::enabledProfiler):
+
2014-01-27 Joseph Pecoraro <pecor...@apple.com>
-[JSContext evaluteScript:] calls JSEvaluteScript with startingLineNumber 0, later interpreted as a oneBasedInt
Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (162939 => 162940)
--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp 2014-01-28 17:38:49 UTC (rev 162939)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp 2014-01-28 17:43:07 UTC (rev 162940)
@@ -3531,4 +3531,19 @@
RELEASE_ASSERT_NOT_REACHED();
}
+void CodeBlock::addBreakpoint(unsigned numBreakpoints)
+{
+ m_numBreakpoints += numBreakpoints;
+ ASSERT(m_numBreakpoints);
+ if (jitType() == JITCode::DFGJIT)
+ jettison();
+}
+
+void CodeBlock::setSteppingMode(CodeBlock::SteppingMode mode)
+{
+ m_steppingMode = mode;
+ if (mode == SteppingModeEnabled && jitType() == JITCode::DFGJIT)
+ jettison();
+}
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.h (162939 => 162940)
--- trunk/Source/_javascript_Core/bytecode/CodeBlock.h 2014-01-28 17:38:49 UTC (rev 162939)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.h 2014-01-28 17:43:07 UTC (rev 162940)
@@ -872,7 +872,7 @@
int hasDebuggerRequests() const { return !!m_debuggerRequests; }
void* debuggerRequestsAddress() { return &m_debuggerRequests; }
- void addBreakpoint(unsigned numBreakpoints) { m_numBreakpoints += numBreakpoints; }
+ void addBreakpoint(unsigned numBreakpoints);
void removeBreakpoint(unsigned numBreakpoints)
{
ASSERT(m_numBreakpoints >= numBreakpoints);
@@ -883,7 +883,7 @@
SteppingModeDisabled,
SteppingModeEnabled
};
- void setSteppingMode(SteppingMode mode) { m_steppingMode = mode; }
+ void setSteppingMode(SteppingMode);
void clearDebuggerRequests() { m_debuggerRequests = 0; }
Modified: trunk/Source/_javascript_Core/debugger/Debugger.h (162939 => 162940)
--- trunk/Source/_javascript_Core/debugger/Debugger.h 2014-01-28 17:38:49 UTC (rev 162939)
+++ trunk/Source/_javascript_Core/debugger/Debugger.h 2014-01-28 17:43:07 UTC (rev 162940)
@@ -90,6 +90,7 @@
void stepOutOfFunction();
bool isPaused() { return m_isPaused; }
+ bool isStepping() const { return m_steppingMode == SteppingModeEnabled; }
virtual void sourceParsed(ExecState*, SourceProvider*, int errorLineNumber, const WTF::String& errorMessage) = 0;
@@ -170,7 +171,6 @@
SteppingModeEnabled
};
void setSteppingMode(SteppingMode);
- bool isStepping() const { return m_steppingMode == SteppingModeEnabled; }
enum BreakpointState {
BreakpointDisabled,
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (162939 => 162940)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2014-01-28 17:38:49 UTC (rev 162939)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2014-01-28 17:43:07 UTC (rev 162940)
@@ -1754,13 +1754,13 @@
node->setCanExit(true);
break;
- case Breakpoint:
- case ProfileWillCall:
- case ProfileDidCall:
case CheckWatchdogTimer:
node->setCanExit(true);
break;
+ case Breakpoint:
+ case ProfileWillCall:
+ case ProfileDidCall:
case Phantom:
case Check:
case CountExecution:
Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (162939 => 162940)
--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2014-01-28 17:38:49 UTC (rev 162939)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2014-01-28 17:43:07 UTC (rev 162940)
@@ -88,6 +88,9 @@
case WeakJSConstant:
case Identity:
case Phantom:
+ case Breakpoint:
+ case ProfileWillCall:
+ case ProfileDidCall:
case BitAnd:
case BitOr:
case BitXor:
@@ -618,9 +621,6 @@
clobberizeForAllocation(read, write);
return;
- case Breakpoint:
- case ProfileWillCall:
- case ProfileDidCall:
case CountExecution:
case CheckWatchdogTimer:
read(InternalState);
Modified: trunk/Source/_javascript_Core/dfg/DFGDriver.cpp (162939 => 162940)
--- trunk/Source/_javascript_Core/dfg/DFGDriver.cpp 2014-01-28 17:38:49 UTC (rev 162939)
+++ trunk/Source/_javascript_Core/dfg/DFGDriver.cpp 2014-01-28 17:43:07 UTC (rev 162940)
@@ -34,6 +34,7 @@
#include "DFGPlan.h"
#include "DFGThunks.h"
#include "DFGWorklist.h"
+#include "Debugger.h"
#include "JITCode.h"
#include "Operations.h"
#include "Options.h"
@@ -73,6 +74,13 @@
if (!Options::bytecodeRangeToDFGCompile().isInRange(codeBlock->instructionCount()))
return CompilationFailed;
+ if (vm.enabledProfiler())
+ return CompilationInvalidated;
+
+ Debugger* debugger = codeBlock->globalObject()->debugger();
+ if (debugger && (debugger->isStepping() || codeBlock->baselineAlternative()->hasDebuggerRequests()))
+ return CompilationInvalidated;
+
if (logCompilationChanges())
dataLog("DFG(Driver) compiling ", *codeBlock, " with ", mode, ", number of instructions = ", codeBlock->instructionCount(), "\n");
Modified: trunk/Source/_javascript_Core/dfg/DFGPlan.cpp (162939 => 162940)
--- trunk/Source/_javascript_Core/dfg/DFGPlan.cpp 2014-01-28 17:38:49 UTC (rev 162939)
+++ trunk/Source/_javascript_Core/dfg/DFGPlan.cpp 2014-01-28 17:43:07 UTC (rev 162940)
@@ -62,6 +62,7 @@
#include "DFGValidate.h"
#include "DFGVirtualRegisterAllocationPhase.h"
#include "DFGWatchpointCollectionPhase.h"
+#include "Debugger.h"
#include "OperandsInlines.h"
#include "Operations.h"
#include <wtf/CurrentTime.h>
@@ -346,7 +347,14 @@
{
if (!isStillValid())
return CompilationInvalidated;
-
+
+ if (vm.enabledProfiler())
+ return CompilationInvalidated;
+
+ Debugger* debugger = codeBlock->globalObject()->debugger();
+ if (debugger && (debugger->isStepping() || codeBlock->baselineAlternative()->hasDebuggerRequests()))
+ return CompilationInvalidated;
+
bool result;
if (codeBlock->codeType() == FunctionCode)
result = finalizer->finalizeFunction();
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (162939 => 162940)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2014-01-28 17:38:49 UTC (rev 162939)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2014-01-28 17:43:07 UTC (rev 162940)
@@ -4232,26 +4232,6 @@
case Flush:
break;
- case Breakpoint: {
- GPRTemporary temp(this);
- GPRReg debuggerRequestsGPR = temp.gpr();
- m_jit.load32(m_jit.codeBlock()->debuggerRequestsAddress(), debuggerRequestsGPR);
- speculationCheck(
- DebuggerEvent, JSValueRegs(), 0,
- m_jit.branchTest32(JITCompiler::NonZero, debuggerRequestsGPR));
- break;
- }
-
- case ProfileWillCall:
- case ProfileDidCall: {
- GPRTemporary temp(this);
- m_jit.loadPtr(m_jit.vm()->enabledProfilerAddress(), temp.gpr());
- speculationCheck(
- DebuggerEvent, JSValueRegs(), 0,
- m_jit.branchTestPtr(JITCompiler::NonZero, temp.gpr()));
- break;
- }
-
case Call:
case Construct:
emitCall(node);
@@ -4690,6 +4670,9 @@
noResult(node);
break;
+ case Breakpoint:
+ case ProfileWillCall:
+ case ProfileDidCall:
case PhantomLocal:
case LoopHint:
// This is a no-op.
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (162939 => 162940)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2014-01-28 17:38:49 UTC (rev 162939)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2014-01-28 17:43:07 UTC (rev 162940)
@@ -4524,25 +4524,6 @@
case Flush:
break;
- case Breakpoint: {
- GPRTemporary temp(this);
- GPRReg debuggerRequestsGPR = temp.gpr();
- m_jit.load32(m_jit.codeBlock()->debuggerRequestsAddress(), debuggerRequestsGPR);
- speculationCheck(
- DebuggerEvent, JSValueRegs(), 0,
- m_jit.branchTest32(JITCompiler::NonZero, debuggerRequestsGPR));
- break;
- }
-
- case ProfileWillCall:
- case ProfileDidCall:
- speculationCheck(
- DebuggerEvent, JSValueRegs(), 0,
- m_jit.branchTestPtr(
- JITCompiler::NonZero,
- JITCompiler::AbsoluteAddress(m_jit.vm()->enabledProfilerAddress())));
- break;
-
case Call:
case Construct:
emitCall(node);
@@ -4939,6 +4920,9 @@
noResult(node);
break;
+ case Breakpoint:
+ case ProfileWillCall:
+ case ProfileDidCall:
case PhantomLocal:
case LoopHint:
// This is a no-op.
Modified: trunk/Source/_javascript_Core/profiler/LegacyProfiler.cpp (162939 => 162940)
--- trunk/Source/_javascript_Core/profiler/LegacyProfiler.cpp 2014-01-28 17:38:49 UTC (rev 162939)
+++ trunk/Source/_javascript_Core/profiler/LegacyProfiler.cpp 2014-01-28 17:43:07 UTC (rev 162940)
@@ -75,7 +75,7 @@
return;
}
- exec->vm().m_enabledProfiler = this;
+ exec->vm().setEnabledProfiler(this);
RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(exec, title, ++ProfilesUID);
m_currentProfiles.append(profileGenerator);
}
@@ -94,7 +94,7 @@
m_currentProfiles.remove(i);
if (!m_currentProfiles.size())
- exec->vm().m_enabledProfiler = 0;
+ exec->vm().setEnabledProfiler(nullptr);
return returnProfile;
}
@@ -111,7 +111,7 @@
profileGenerator->stopProfiling();
m_currentProfiles.remove(i);
if (!m_currentProfiles.size())
- origin->vm().m_enabledProfiler = 0;
+ origin->vm().setEnabledProfiler(nullptr);
}
}
}
Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (162939 => 162940)
--- trunk/Source/_javascript_Core/runtime/VM.cpp 2014-01-28 17:38:49 UTC (rev 162939)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp 2014-01-28 17:43:07 UTC (rev 162940)
@@ -197,7 +197,6 @@
, jsFinalObjectClassInfo(JSFinalObject::info())
, sizeOfLastScratchBuffer(0)
, entryScope(0)
- , m_enabledProfiler(0)
, m_regExpCache(new RegExpCache(this))
#if ENABLE(REGEXP_TRACING)
, m_rtTraceList(new RTTraceList())
@@ -222,6 +221,7 @@
#endif
, m_inDefineOwnProperty(false)
, m_codeCache(CodeCache::create())
+ , m_enabledProfiler(nullptr)
{
interpreter = new Interpreter(*this);
StackBounds stack = wtfThreadData().stack();
@@ -780,4 +780,23 @@
watchpointSet->fireAll();
}
+class SetEnabledProfilerFunctor {
+public:
+ bool operator()(CodeBlock* codeBlock)
+ {
+ if (codeBlock->jitType() == JITCode::DFGJIT)
+ codeBlock->jettison();
+ return false;
+ }
+};
+
+void VM::setEnabledProfiler(LegacyProfiler* profiler)
+{
+ m_enabledProfiler = profiler;
+ if (m_enabledProfiler) {
+ SetEnabledProfilerFunctor functor;
+ heap.forEachCodeBlock(functor);
+ }
+}
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/VM.h (162939 => 162940)
--- trunk/Source/_javascript_Core/runtime/VM.h 2014-01-28 17:38:49 UTC (rev 162939)
+++ trunk/Source/_javascript_Core/runtime/VM.h 2014-01-28 17:43:07 UTC (rev 162940)
@@ -304,10 +304,9 @@
return m_inDefineOwnProperty;
}
- LegacyProfiler* enabledProfiler()
- {
- return m_enabledProfiler;
- }
+ LegacyProfiler* enabledProfiler() { return m_enabledProfiler; }
+ void setEnabledProfiler(LegacyProfiler*);
+
void* enabledProfilerAddress() { return &m_enabledProfiler; }
#if ENABLE(JIT) && ENABLE(LLINT)
@@ -432,7 +431,6 @@
String cachedDateString;
double cachedDateStringValue;
- LegacyProfiler* m_enabledProfiler;
OwnPtr<Profiler::Database> m_perBytecodeProfiler;
RefPtr<TypedArrayController> m_typedArrayController;
RegExpCache* m_regExpCache;
@@ -524,6 +522,8 @@
OwnPtr<CodeCache> m_codeCache;
RefCountedArray<StackFrame> m_exceptionStack;
+ LegacyProfiler* m_enabledProfiler;
+
HashMap<String, RefPtr<WatchpointSet>> m_impurePropertyWatchpointSets;
};