<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[162598] trunk/Source/JavaScriptCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/162598">162598</a></dd>
<dt>Author</dt> <dd>mark.lam@apple.com</dd>
<dt>Date</dt> <dd>2014-01-22 23:39:58 -0800 (Wed, 22 Jan 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Poor man's fast breakpoints for a 2.3x debugger speedup.
&lt;https://webkit.org/b/122836&gt;

Reviewed by Geoffrey Garen.

Previously we gained back some performance (run at baseline JIT speeds)
when the WebInspector is opened provided no breakpoints are set. This
was achieved by simply skipping all op_debug callbacks to the debugger
if no breakpoints are set. If any breakpoints are set, the debugger will
set a m_needsOpDebugCallbacks flag which causes the callbacks to be
called, and we don't get the baseline JIT speeds anymore.

With this patch, we will now track the number of breakpoints set in the
CodeBlock that they are set in. The LLINT and baseline JIT code will
check CodeBlock::m_numBreakpoints to determine if the op_debug callbacks
need to be called. With this, we will only enable op_debug callbacks for
CodeBlocks that need it i.e. those with breakpoints set in them.

Debugger::m_needsOpDebugCallbacks is now obsoleted. The LLINT and baseline
JIT code still needs to check Debugger::m_shouldPause to determine if the
debugger is in stepping mode and hence, needs op_debug callbacks enabled
for everything until the debugger &quot;continues&quot; the run and exit stepping
mode.

Also in this patch, I fixed a regression in DOM breakpoints which relies
Debugger::breakProgram() to pause the debugger.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
- Missed accounting for op_debug's new hasBreakpointFlag operand here when
  it was added.
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::hasOpDebugForLineAndColumn):
- This is needed in Debugger::toggleBreakpoint() to determine if a
  breakpoint falls within a CodeBlock or not. Simply checking the bounds
  of the CodeBlock is insufficient. For example, let's say we have the
  following JS code:

      // begin global scope
      function f1() {
          function f2() {
             ... // set breakpoint here.
          }
      }
      // end global scope

  Using the CodeBlock bounds alone, the breakpoint above will to appear
  to be in the global program CodeBlock, and the CodeBlocks for function
  f1() and f2(). With CodeBlock::hasOpDebugForLineAndColumn() we can
  rule out the global program CodeBlock and f1(), and only apply the
  breakpoint to f2(0 where it belongs.

  CodeBlock::hasOpDebugForLineAndColumn() works by iterating over all
  the opcodes in the CodeBlock to look for op_debug's. For each op_debug,
  it calls CodeBlock::expressionRangeForBytecodeOffset() to do a binary
  seach to get the line and column info for that op_debug. This is a
  N * log(N) algorithm. However, a quick hands on test using the
  WebInspector (with this patch applied) to exercise setting, breaking
  on, and clearing breakpoints, as well as stepping through some code
  shows no noticeable degradation of the user experience compared to the
  baseline without this patch.

* bytecode/CodeBlock.h:
(JSC::CodeBlock::numBreakpoints):
(JSC::CodeBlock::numBreakpointsOffset):
(JSC::CodeBlock::addBreakpoint):
(JSC::CodeBlock::removeBreakpoint):
(JSC::CodeBlock::clearAllBreakpoints):
* debugger/Breakpoint.h:
- defined Breakpoint::unspecifiedColumn so that we can explicitly indicate
  when the WebInspector was setting a line breakpoint and did not provide
  a column value. CodeBlock::hasOpDebugForLineAndColumn() needs this
  information in order to loosen its matching criteria for op_debug
  bytecodes for the specified breakpoint line and column values provided
  by the debugger.

  Previously, we just hijack a 0 value column as an unspecified column.
  However, the WebInspector operates on 0-based ints for column values.
  Hence, 0 should be a valid column value and should not be hijacked to
  mean an unspecified column.

* debugger/Debugger.cpp:
(JSC::Debugger::Debugger):
- added tracking of the VM that the debugger is used with. This is
  needed by Debugger::breakProgram().

  The VM pointer is attained from the first JSGlobalObject that the debugger
  attaches to. When the debugger detaches from the last JSGlobalObject, it
  will nullify its VM pointer to allow a new one to be set on the next
  attach.

  We were always only using each debugger instance with one VM. This change
  makes it explicit with an assert to ensure that all globalObjects that
  the debugger attaches to beongs to the same VM.

(JSC::Debugger::attach):
(JSC::Debugger::detach):
(JSC::Debugger::setShouldPause):

(JSC::Debugger::registerCodeBlock):
(JSC::Debugger::unregisterCodeBlock):
- registerCodeBlock() is responsible for applying pre-existing breakpoints
  to new CodeBlocks being installed. Similarly, unregisterCodeBlock()
  clears the breakpoints.

(JSC::Debugger::toggleBreakpoint):
- This is the workhorse function that checks if a breakpoint falls within
  a CodeBlock or not. If it does, then it can either enable or disable
  said breakpoint in the CodeBlock. In the current implementation,
  enabling/disabling the breakpoint simply means incrementing/decrementing
  the CodeBlock's m_numBreakpoints.

(JSC::Debugger::applyBreakpoints):

(JSC::Debugger::ToggleBreakpointFunctor::ToggleBreakpointFunctor):
(JSC::Debugger::ToggleBreakpointFunctor::operator()):
(JSC::Debugger::toggleBreakpoint):
- Iterates all relevant CodeBlocks and apply the specified breakpoint
  if appropriate. This is called when a new breakpoint is being defined
  by the WebInspector and needs to be applied to an already installed
  CodeBlock.

(JSC::Debugger::setBreakpoint):
(JSC::Debugger::removeBreakpoint):
(JSC::Debugger::hasBreakpoint):
(JSC::Debugger::ClearBreakpointsFunctor::ClearBreakpointsFunctor):
(JSC::Debugger::ClearBreakpointsFunctor::operator()):
(JSC::Debugger::clearBreakpoints):

(JSC::Debugger::breakProgram):
- Fixed a regression that broke DOM breakpoints. The issue is that with
  the skipping of op_debug callbacks, we don't always have an updated
  m_currentCallFrame. Normally, m_currentCallFrame is provided as arg
  in the op_debug callback. In this case, we can get the CallFrame* from
  m_vm-&gt;topCallFrame.

(JSC::Debugger::updateCallFrameAndPauseIfNeeded):
(JSC::Debugger::pauseIfNeeded):
(JSC::Debugger::willExecuteProgram):
* debugger/Debugger.h:
(JSC::Debugger::Debugger):
(JSC::Debugger::shouldPause):

* heap/CodeBlockSet.h:
(JSC::CodeBlockSet::iterate):
* heap/Heap.h:
(JSC::Heap::forEachCodeBlock):
- Added utility to iterate all CodeBlocks in the heap / VM.

* interpreter/Interpreter.cpp:
(JSC::Interpreter::debug):

* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_debug):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_debug):
* llint/LowLevelInterpreter.asm:
- These now checks CodeBlock::m_numBreakpoints and Debugger::m_shouldPause
  instead of Debugger::m_needsOpDebugCallbacks.

* runtime/Executable.cpp:
(JSC::ScriptExecutable::installCode):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockcpp">trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockh">trunk/Source/JavaScriptCore/bytecode/CodeBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredebuggerBreakpointh">trunk/Source/JavaScriptCore/debugger/Breakpoint.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredebuggerDebuggercpp">trunk/Source/JavaScriptCore/debugger/Debugger.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredebuggerDebuggerh">trunk/Source/JavaScriptCore/debugger/Debugger.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCodeBlockSeth">trunk/Source/JavaScriptCore/heap/CodeBlockSet.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeaph">trunk/Source/JavaScriptCore/heap/Heap.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreinterpreterInterpretercpp">trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOpcodescpp">trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOpcodes32_64cpp">trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreterasm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeExecutablecpp">trunk/Source/JavaScriptCore/runtime/Executable.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (162597 => 162598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-01-23 06:32:12 UTC (rev 162597)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-01-23 07:39:58 UTC (rev 162598)
</span><span class="lines">@@ -1,3 +1,168 @@
</span><ins>+2014-01-22  Mark Lam  &lt;mark.lam@apple.com&gt;
+
+        Poor man's fast breakpoints for a 2.3x debugger speedup.
+        &lt;https://webkit.org/b/122836&gt;
+
+        Reviewed by Geoffrey Garen.
+
+        Previously we gained back some performance (run at baseline JIT speeds)
+        when the WebInspector is opened provided no breakpoints are set. This
+        was achieved by simply skipping all op_debug callbacks to the debugger
+        if no breakpoints are set. If any breakpoints are set, the debugger will
+        set a m_needsOpDebugCallbacks flag which causes the callbacks to be
+        called, and we don't get the baseline JIT speeds anymore.
+
+        With this patch, we will now track the number of breakpoints set in the
+        CodeBlock that they are set in. The LLINT and baseline JIT code will
+        check CodeBlock::m_numBreakpoints to determine if the op_debug callbacks
+        need to be called. With this, we will only enable op_debug callbacks for
+        CodeBlocks that need it i.e. those with breakpoints set in them.
+
+        Debugger::m_needsOpDebugCallbacks is now obsoleted. The LLINT and baseline
+        JIT code still needs to check Debugger::m_shouldPause to determine if the
+        debugger is in stepping mode and hence, needs op_debug callbacks enabled
+        for everything until the debugger &quot;continues&quot; the run and exit stepping
+        mode.
+
+        Also in this patch, I fixed a regression in DOM breakpoints which relies
+        Debugger::breakProgram() to pause the debugger.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        - Missed accounting for op_debug's new hasBreakpointFlag operand here when
+          it was added.
+        (JSC::CodeBlock::CodeBlock):
+        (JSC::CodeBlock::hasOpDebugForLineAndColumn):
+        - This is needed in Debugger::toggleBreakpoint() to determine if a
+          breakpoint falls within a CodeBlock or not. Simply checking the bounds
+          of the CodeBlock is insufficient. For example, let's say we have the
+          following JS code:
+
+              // begin global scope
+              function f1() {
+                  function f2() {
+                     ... // set breakpoint here.
+                  }
+              }
+              // end global scope
+
+          Using the CodeBlock bounds alone, the breakpoint above will to appear
+          to be in the global program CodeBlock, and the CodeBlocks for function
+          f1() and f2(). With CodeBlock::hasOpDebugForLineAndColumn() we can
+          rule out the global program CodeBlock and f1(), and only apply the
+          breakpoint to f2(0 where it belongs.
+
+          CodeBlock::hasOpDebugForLineAndColumn() works by iterating over all
+          the opcodes in the CodeBlock to look for op_debug's. For each op_debug,
+          it calls CodeBlock::expressionRangeForBytecodeOffset() to do a binary
+          seach to get the line and column info for that op_debug. This is a
+          N * log(N) algorithm. However, a quick hands on test using the
+          WebInspector (with this patch applied) to exercise setting, breaking
+          on, and clearing breakpoints, as well as stepping through some code
+          shows no noticeable degradation of the user experience compared to the
+          baseline without this patch.
+
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::numBreakpoints):
+        (JSC::CodeBlock::numBreakpointsOffset):
+        (JSC::CodeBlock::addBreakpoint):
+        (JSC::CodeBlock::removeBreakpoint):
+        (JSC::CodeBlock::clearAllBreakpoints):
+        * debugger/Breakpoint.h:
+        - defined Breakpoint::unspecifiedColumn so that we can explicitly indicate
+          when the WebInspector was setting a line breakpoint and did not provide
+          a column value. CodeBlock::hasOpDebugForLineAndColumn() needs this
+          information in order to loosen its matching criteria for op_debug
+          bytecodes for the specified breakpoint line and column values provided
+          by the debugger.
+
+          Previously, we just hijack a 0 value column as an unspecified column.
+          However, the WebInspector operates on 0-based ints for column values.
+          Hence, 0 should be a valid column value and should not be hijacked to
+          mean an unspecified column.
+
+        * debugger/Debugger.cpp:
+        (JSC::Debugger::Debugger):
+        - added tracking of the VM that the debugger is used with. This is
+          needed by Debugger::breakProgram().
+
+          The VM pointer is attained from the first JSGlobalObject that the debugger
+          attaches to. When the debugger detaches from the last JSGlobalObject, it
+          will nullify its VM pointer to allow a new one to be set on the next
+          attach.
+
+          We were always only using each debugger instance with one VM. This change
+          makes it explicit with an assert to ensure that all globalObjects that
+          the debugger attaches to beongs to the same VM.
+
+        (JSC::Debugger::attach):
+        (JSC::Debugger::detach):
+        (JSC::Debugger::setShouldPause):
+
+        (JSC::Debugger::registerCodeBlock):
+        (JSC::Debugger::unregisterCodeBlock):
+        - registerCodeBlock() is responsible for applying pre-existing breakpoints
+          to new CodeBlocks being installed. Similarly, unregisterCodeBlock()
+          clears the breakpoints.
+
+        (JSC::Debugger::toggleBreakpoint):
+        - This is the workhorse function that checks if a breakpoint falls within
+          a CodeBlock or not. If it does, then it can either enable or disable
+          said breakpoint in the CodeBlock. In the current implementation,
+          enabling/disabling the breakpoint simply means incrementing/decrementing
+          the CodeBlock's m_numBreakpoints.
+
+        (JSC::Debugger::applyBreakpoints):
+
+        (JSC::Debugger::ToggleBreakpointFunctor::ToggleBreakpointFunctor):
+        (JSC::Debugger::ToggleBreakpointFunctor::operator()):
+        (JSC::Debugger::toggleBreakpoint):
+        - Iterates all relevant CodeBlocks and apply the specified breakpoint
+          if appropriate. This is called when a new breakpoint is being defined
+          by the WebInspector and needs to be applied to an already installed
+          CodeBlock.
+
+        (JSC::Debugger::setBreakpoint):
+        (JSC::Debugger::removeBreakpoint):
+        (JSC::Debugger::hasBreakpoint):
+        (JSC::Debugger::ClearBreakpointsFunctor::ClearBreakpointsFunctor):
+        (JSC::Debugger::ClearBreakpointsFunctor::operator()):
+        (JSC::Debugger::clearBreakpoints):
+
+        (JSC::Debugger::breakProgram):
+        - Fixed a regression that broke DOM breakpoints. The issue is that with
+          the skipping of op_debug callbacks, we don't always have an updated
+          m_currentCallFrame. Normally, m_currentCallFrame is provided as arg
+          in the op_debug callback. In this case, we can get the CallFrame* from
+          m_vm-&gt;topCallFrame.
+
+        (JSC::Debugger::updateCallFrameAndPauseIfNeeded):
+        (JSC::Debugger::pauseIfNeeded):
+        (JSC::Debugger::willExecuteProgram):
+        * debugger/Debugger.h:
+        (JSC::Debugger::Debugger):
+        (JSC::Debugger::shouldPause):
+
+        * heap/CodeBlockSet.h:
+        (JSC::CodeBlockSet::iterate):
+        * heap/Heap.h:
+        (JSC::Heap::forEachCodeBlock):
+        - Added utility to iterate all CodeBlocks in the heap / VM.
+
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::debug):
+
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_debug):
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emit_op_debug):
+        * llint/LowLevelInterpreter.asm:
+        - These now checks CodeBlock::m_numBreakpoints and Debugger::m_shouldPause
+          instead of Debugger::m_needsOpDebugCallbacks.
+
+        * runtime/Executable.cpp:
+        (JSC::ScriptExecutable::installCode):
+
</ins><span class="cx"> 2014-01-22  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Remove CSS3_TEXT_DECORATION define
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp (162597 => 162598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2014-01-23 06:32:12 UTC (rev 162597)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2014-01-23 07:39:58 UTC (rev 162598)
</span><span class="lines">@@ -1352,8 +1352,9 @@
</span><span class="cx">         }
</span><span class="cx">         case op_debug: {
</span><span class="cx">             int debugHookID = (++it)-&gt;u.operand;
</span><ins>+            int hasBreakpointFlag = (++it)-&gt;u.operand;
</ins><span class="cx">             printLocationAndOp(out, exec, location, it, &quot;debug&quot;);
</span><del>-            out.printf(&quot;%s&quot;, debugHookName(debugHookID));
</del><ins>+            out.printf(&quot;%s %d&quot;, debugHookName(debugHookID), hasBreakpointFlag);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_profile_will_call: {
</span><span class="lines">@@ -1468,6 +1469,7 @@
</span><span class="cx">     , m_shouldAlwaysBeInlined(true)
</span><span class="cx">     , m_didFailFTLCompilation(false)
</span><span class="cx">     , m_unlinkedCode(*other.m_vm, other.m_ownerExecutable.get(), other.m_unlinkedCode.get())
</span><ins>+    , m_numBreakpoints(0)
</ins><span class="cx">     , m_ownerExecutable(*other.m_vm, other.m_ownerExecutable.get(), other.m_ownerExecutable.get())
</span><span class="cx">     , m_vm(other.m_vm)
</span><span class="cx">     , m_instructions(other.m_instructions)
</span><span class="lines">@@ -1522,6 +1524,7 @@
</span><span class="cx">     , m_shouldAlwaysBeInlined(true)
</span><span class="cx">     , m_didFailFTLCompilation(false)
</span><span class="cx">     , m_unlinkedCode(m_globalObject-&gt;vm(), ownerExecutable, unlinkedCodeBlock)
</span><ins>+    , m_numBreakpoints(0)
</ins><span class="cx">     , m_ownerExecutable(m_globalObject-&gt;vm(), ownerExecutable, ownerExecutable)
</span><span class="cx">     , m_vm(unlinkedCodeBlock-&gt;vm())
</span><span class="cx">     , m_thisRegister(unlinkedCodeBlock-&gt;thisRegister())
</span><span class="lines">@@ -2566,6 +2569,27 @@
</span><span class="cx">     line += m_ownerExecutable-&gt;lineNo();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool CodeBlock::hasOpDebugForLineAndColumn(unsigned line, unsigned column)
+{
+    Interpreter* interpreter = vm()-&gt;interpreter;
+    const Instruction* begin = instructions().begin();
+    const Instruction* end = instructions().end();
+    for (const Instruction* it = begin; it != end;) {
+        OpcodeID opcodeID = interpreter-&gt;getOpcodeID(it-&gt;u.opcode);
+        if (opcodeID == op_debug) {
+            unsigned bytecodeOffset = it - begin;
+            int unused;
+            unsigned opDebugLine;
+            unsigned opDebugColumn;
+            expressionRangeForBytecodeOffset(bytecodeOffset, unused, unused, unused, opDebugLine, opDebugColumn);
+            if (line == opDebugLine &amp;&amp; (column == Breakpoint::unspecifiedColumn || column == opDebugColumn))
+                return true;
+        }
+        it += opcodeLengths[opcodeID];
+    }
+    return false;
+}
+
</ins><span class="cx"> void CodeBlock::shrinkToFit(ShrinkMode shrinkMode)
</span><span class="cx"> {
</span><span class="cx">     m_rareCaseProfiles.shrinkToFit();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.h (162597 => 162598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2014-01-23 06:32:12 UTC (rev 162597)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2014-01-23 07:39:58 UTC (rev 162598)
</span><span class="lines">@@ -869,6 +869,19 @@
</span><span class="cx"> 
</span><span class="cx">     unsigned frameRegisterCount();
</span><span class="cx"> 
</span><ins>+    bool hasOpDebugForLineAndColumn(unsigned line, unsigned column);
+
+    int numBreakpoints() const { return m_numBreakpoints; }
+    static ptrdiff_t numBreakpointsOffset() { return OBJECT_OFFSETOF(CodeBlock, m_numBreakpoints); }
+
+    void addBreakpoint(int numBreakpoints) { m_numBreakpoints += numBreakpoints; }
+    void removeBreakpoint(int numBreakpoints)
+    {
+        m_numBreakpoints -= numBreakpoints;
+        ASSERT(m_numBreakpoints &gt;= 0);
+    }
+    void clearAllBreakpoints() { m_numBreakpoints = 0; }
+
</ins><span class="cx">     // FIXME: Make these remaining members private.
</span><span class="cx"> 
</span><span class="cx">     int m_numCalleeRegisters;
</span><span class="lines">@@ -1005,6 +1018,7 @@
</span><span class="cx"> #endif
</span><span class="cx">     WriteBarrier&lt;UnlinkedCodeBlock&gt; m_unlinkedCode;
</span><span class="cx">     int m_numParameters;
</span><ins>+    int m_numBreakpoints;
</ins><span class="cx">     WriteBarrier&lt;ScriptExecutable&gt; m_ownerExecutable;
</span><span class="cx">     VM* m_vm;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredebuggerBreakpointh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/debugger/Breakpoint.h (162597 => 162598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/debugger/Breakpoint.h        2014-01-23 06:32:12 UTC (rev 162597)
+++ trunk/Source/JavaScriptCore/debugger/Breakpoint.h        2014-01-23 07:39:58 UTC (rev 162598)
</span><span class="lines">@@ -59,6 +59,8 @@
</span><span class="cx">     unsigned column;
</span><span class="cx">     String condition;
</span><span class="cx">     bool autoContinue;
</span><ins>+
+    static const unsigned unspecifiedColumn = UINT_MAX;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredebuggerDebuggercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/debugger/Debugger.cpp (162597 => 162598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/debugger/Debugger.cpp        2014-01-23 06:32:12 UTC (rev 162597)
+++ trunk/Source/JavaScriptCore/debugger/Debugger.cpp        2014-01-23 07:39:58 UTC (rev 162598)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- *  Copyright (C) 2008, 2013 Apple Inc. All rights reserved.
</del><ins>+ *  Copyright (C) 2008, 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
</span><span class="cx">  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
</span><span class="cx">  *
</span><span class="lines">@@ -24,8 +24,10 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;Debugger.h&quot;
</span><span class="cx"> 
</span><ins>+#include &quot;CodeBlock.h&quot;
</ins><span class="cx"> #include &quot;DebuggerCallFrame.h&quot;
</span><span class="cx"> #include &quot;Error.h&quot;
</span><ins>+
</ins><span class="cx"> #include &quot;HeapIterationScope.h&quot;
</span><span class="cx"> #include &quot;Interpreter.h&quot;
</span><span class="cx"> #include &quot;JSCJSValueInlines.h&quot;
</span><span class="lines">@@ -139,7 +141,8 @@
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> Debugger::Debugger(bool isInWorkerThread)
</span><del>-    : m_pauseOnExceptionsState(DontPauseOnExceptions)
</del><ins>+    : m_vm(nullptr)
+    , m_pauseOnExceptionsState(DontPauseOnExceptions)
</ins><span class="cx">     , m_pauseOnNextStatement(false)
</span><span class="cx">     , m_isPaused(false)
</span><span class="cx">     , m_breakpointsActivated(true)
</span><span class="lines">@@ -151,7 +154,6 @@
</span><span class="cx">     , m_lastExecutedLine(UINT_MAX)
</span><span class="cx">     , m_lastExecutedSourceID(noSourceID)
</span><span class="cx">     , m_topBreakpointID(noBreakpointID)
</span><del>-    , m_needsOpDebugCallbacks(false)
</del><span class="cx">     , m_shouldPause(false)
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="lines">@@ -166,6 +168,10 @@
</span><span class="cx"> void Debugger::attach(JSGlobalObject* globalObject)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!globalObject-&gt;debugger());
</span><ins>+    if (!m_vm)
+        m_vm = &amp;globalObject-&gt;vm();
+    else
+        ASSERT(m_vm == &amp;globalObject-&gt;vm());
</ins><span class="cx">     globalObject-&gt;setDebugger(this);
</span><span class="cx">     m_globalObjects.add(globalObject);
</span><span class="cx"> }
</span><span class="lines">@@ -184,14 +190,106 @@
</span><span class="cx">     ASSERT(m_globalObjects.contains(globalObject));
</span><span class="cx">     m_globalObjects.remove(globalObject);
</span><span class="cx">     globalObject-&gt;setDebugger(0);
</span><ins>+    if (!m_globalObjects.size())
+        m_vm = nullptr;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Debugger::setShouldPause(bool value)
</span><span class="cx"> {
</span><span class="cx">     m_shouldPause = value;
</span><del>-    updateNeedForOpDebugCallbacks();
</del><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Debugger::registerCodeBlock(CodeBlock* codeBlock)
+{
+    applyBreakpoints(codeBlock);
+}
+
+void Debugger::unregisterCodeBlock(CodeBlock* codeBlock)
+{
+    codeBlock-&gt;clearAllBreakpoints();
+}
+
+void Debugger::toggleBreakpoint(CodeBlock* codeBlock, Breakpoint&amp; breakpoint, BreakpointState enabledOrNot)
+{
+    ASSERT(codeBlock-&gt;jitCode()-&gt;jitType() == JITCode::InterpreterThunk
+        || codeBlock-&gt;jitCode()-&gt;jitType() == JITCode::BaselineJIT);
+
+    ScriptExecutable* executable = codeBlock-&gt;ownerExecutable();
+
+    SourceID sourceID = static_cast&lt;SourceID&gt;(executable-&gt;sourceID());
+    if (breakpoint.sourceID != sourceID)
+        return;
+
+    unsigned line = breakpoint.line;
+    unsigned column = breakpoint.column;
+
+    unsigned startLine = executable-&gt;lineNo();
+    unsigned startColumn = executable-&gt;startColumn();
+    unsigned endLine = executable-&gt;lastLine();
+    unsigned endColumn = executable-&gt;endColumn();
+
+    // Inspector breakpoint line and column values are zero-based but the executable
+    // and CodeBlock line and column values are one-based.
+    line += 1;
+    column = column ? column + 1 : Breakpoint::unspecifiedColumn;
+
+    if (line &lt; startLine || line &gt; endLine)
+        return;
+    if (column != Breakpoint::unspecifiedColumn) {
+        if (line == startLine &amp;&amp; column &lt; startColumn)
+            return;
+        if (line == endLine &amp;&amp; column &gt; endColumn)
+            return;
+    }
+    if (!codeBlock-&gt;hasOpDebugForLineAndColumn(line, column))
+        return;
+
+    if (enabledOrNot == BreakpointEnabled)
+        codeBlock-&gt;addBreakpoint(1);
+    else
+        codeBlock-&gt;removeBreakpoint(1);
+}
+
+void Debugger::applyBreakpoints(CodeBlock* codeBlock)
+{
+    BreakpointIDToBreakpointMap&amp; breakpoints = m_breakpointIDToBreakpoint;
+    for (auto it = breakpoints.begin(); it != breakpoints.end(); ++it) {
+        Breakpoint&amp; breakpoint = *it-&gt;value;
+        toggleBreakpoint(codeBlock, breakpoint, BreakpointEnabled);
+    }
+}
+
+class Debugger::ToggleBreakpointFunctor {
+public:
+    ToggleBreakpointFunctor(Debugger* debugger, Breakpoint&amp; breakpoint, BreakpointState enabledOrNot)
+        : m_debugger(debugger)
+        , m_breakpoint(breakpoint)
+        , m_enabledOrNot(enabledOrNot)
+    {
+    }
+
+    bool operator()(CodeBlock* codeBlock)
+    {
+        if (m_debugger == codeBlock-&gt;globalObject()-&gt;debugger())
+            m_debugger-&gt;toggleBreakpoint(codeBlock, m_breakpoint, m_enabledOrNot);
+        return false;
+    }
+
+private:
+    Debugger* m_debugger;
+    Breakpoint&amp; m_breakpoint;
+    BreakpointState m_enabledOrNot;
+};
+
+void Debugger::toggleBreakpoint(Breakpoint&amp; breakpoint, Debugger::BreakpointState enabledOrNot)
+{
+    if (!m_vm)
+        return;
+    HeapIterationScope iterationScope(m_vm-&gt;heap);
+    ToggleBreakpointFunctor functor(this, breakpoint, enabledOrNot);
+    m_vm-&gt;heap.forEachCodeBlock(functor);
+}
+
</ins><span class="cx"> void Debugger::recompileAllJSFunctions(VM* vm)
</span><span class="cx"> {
</span><span class="cx">     // If JavaScript is running, it's not safe to recompile, since we'll end
</span><span class="lines">@@ -207,12 +305,6 @@
</span><span class="cx">     vm-&gt;heap.objectSpace().forEachLiveCell(iterationScope, recompiler);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Debugger::updateNeedForOpDebugCallbacks()
-{
-    size_t numberOfBreakpoints = m_breakpointIDToBreakpoint.size();
-    m_needsOpDebugCallbacks = m_shouldPause || numberOfBreakpoints;
-}
-
</del><span class="cx"> BreakpointID Debugger::setBreakpoint(Breakpoint breakpoint, unsigned&amp; actualLine, unsigned&amp; actualColumn)
</span><span class="cx"> {
</span><span class="cx">     SourceID sourceID = breakpoint.sourceID;
</span><span class="lines">@@ -247,7 +339,7 @@
</span><span class="cx">     breakpoints.append(breakpoint);
</span><span class="cx">     m_breakpointIDToBreakpoint.set(id, &amp;breakpoints.last());
</span><span class="cx"> 
</span><del>-    updateNeedForOpDebugCallbacks();
</del><ins>+    toggleBreakpoint(breakpoint, BreakpointEnabled);
</ins><span class="cx"> 
</span><span class="cx">     return id;
</span><span class="cx"> }
</span><span class="lines">@@ -267,6 +359,8 @@
</span><span class="cx">     LineToBreakpointsMap::iterator breaksIt = it-&gt;value.find(breakpoint.line);
</span><span class="cx">     ASSERT(breaksIt != it-&gt;value.end());
</span><span class="cx"> 
</span><ins>+    toggleBreakpoint(breakpoint, BreakpointDisabled);
+
</ins><span class="cx">     BreakpointsInLine&amp; breakpoints = breaksIt-&gt;value;
</span><span class="cx">     unsigned breakpointsCount = breakpoints.size();
</span><span class="cx">     for (unsigned i = 0; i &lt; breakpointsCount; i++) {
</span><span class="lines">@@ -282,8 +376,6 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-
-    updateNeedForOpDebugCallbacks();
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool Debugger::hasBreakpoint(SourceID sourceID, const TextPosition&amp; position, Breakpoint *hitBreakpoint)
</span><span class="lines">@@ -310,6 +402,7 @@
</span><span class="cx">         unsigned breakLine = breakpoints[i].line;
</span><span class="cx">         unsigned breakColumn = breakpoints[i].column;
</span><span class="cx">         // Since frontend truncates the indent, the first statement in a line must match the breakpoint (line,0).
</span><ins>+        ASSERT(this == m_currentCallFrame-&gt;codeBlock()-&gt;globalObject()-&gt;debugger());
</ins><span class="cx">         if ((line != m_lastExecutedLine &amp;&amp; line == breakLine &amp;&amp; !breakColumn)
</span><span class="cx">             || (line == breakLine &amp;&amp; column == breakColumn)) {
</span><span class="cx">             hit = true;
</span><span class="lines">@@ -345,13 +438,35 @@
</span><span class="cx">     return result.toBoolean(m_currentCallFrame);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+class Debugger::ClearBreakpointsFunctor {
+public:
+    ClearBreakpointsFunctor(Debugger* debugger)
+        : m_debugger(debugger)
+    {
+    }
+
+    bool operator()(CodeBlock* codeBlock)
+    {
+        if (codeBlock-&gt;numBreakpoints() &amp;&amp; m_debugger == codeBlock-&gt;globalObject()-&gt;debugger())
+            codeBlock-&gt;clearAllBreakpoints();
+        return false;
+    }
+
+private:
+    Debugger* m_debugger;
+};
+
</ins><span class="cx"> void Debugger::clearBreakpoints()
</span><span class="cx"> {
</span><span class="cx">     m_topBreakpointID = noBreakpointID;
</span><span class="cx">     m_breakpointIDToBreakpoint.clear();
</span><span class="cx">     m_sourceIDToBreakpoints.clear();
</span><span class="cx"> 
</span><del>-    updateNeedForOpDebugCallbacks();
</del><ins>+    if (!m_vm)
+        return;
+    HeapIterationScope iterationScope(m_vm-&gt;heap);
+    ClearBreakpointsFunctor functor(this);
+    m_vm-&gt;heap.forEachCodeBlock(functor);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Debugger::setBreakpointsActivated(bool activated)
</span><span class="lines">@@ -373,11 +488,13 @@
</span><span class="cx"> 
</span><span class="cx"> void Debugger::breakProgram()
</span><span class="cx"> {
</span><del>-    if (m_isPaused || !m_currentCallFrame)
</del><ins>+    if (m_isPaused)
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     m_pauseOnNextStatement = true;
</span><span class="cx">     setShouldPause(true);
</span><ins>+    m_currentCallFrame = m_vm-&gt;topCallFrame;
+    ASSERT(m_currentCallFrame);
</ins><span class="cx">     pauseIfNeeded(m_currentCallFrame);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -432,7 +549,7 @@
</span><span class="cx"> {
</span><span class="cx">     updateCallFrame(callFrame);
</span><span class="cx">     pauseIfNeeded(callFrame);
</span><del>-    if (!needsOpDebugCallbacks())
</del><ins>+    if (!shouldPause())
</ins><span class="cx">         m_currentCallFrame = 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -477,8 +594,7 @@
</span><span class="cx"> 
</span><span class="cx">     if (!m_pauseOnNextStatement &amp;&amp; !m_pauseOnCallFrame) {
</span><span class="cx">         setShouldPause(false);
</span><del>-        if (!needsOpDebugCallbacks())
-            m_currentCallFrame = 0;
</del><ins>+        m_currentCallFrame = nullptr;
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -548,7 +664,7 @@
</span><span class="cx">     // the debugger implementation to not require callbacks.
</span><span class="cx">     if (!m_isInWorkerThread)
</span><span class="cx">         updateCallFrameAndPauseIfNeeded(callFrame);
</span><del>-    else if (needsOpDebugCallbacks())
</del><ins>+    else if (shouldPause())
</ins><span class="cx">         updateCallFrame(callFrame);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredebuggerDebuggerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/debugger/Debugger.h (162597 => 162598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/debugger/Debugger.h        2014-01-23 06:32:12 UTC (rev 162597)
+++ trunk/Source/JavaScriptCore/debugger/Debugger.h        2014-01-23 07:39:58 UTC (rev 162598)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><span class="cx"> /*
</span><span class="cx">  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
</span><span class="cx">  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
</span><del>- *  Copyright (C) 2008, 2009, 2013 Apple Inc. All rights reserved.
</del><ins>+ *  Copyright (C) 2008, 2009, 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  *  This library is free software; you can redistribute it and/or
</span><span class="cx">  *  modify it under the terms of the GNU Lesser General Public
</span><span class="lines">@@ -48,8 +48,8 @@
</span><span class="cx">     Debugger(bool isInWorkerThread = false);
</span><span class="cx">     virtual ~Debugger();
</span><span class="cx"> 
</span><del>-    bool needsOpDebugCallbacks() const { return m_needsOpDebugCallbacks; }
-    static ptrdiff_t needsOpDebugCallbacksOffset() { return OBJECT_OFFSETOF(Debugger, m_needsOpDebugCallbacks); }
</del><ins>+    bool shouldPause() const { return m_shouldPause; }
+    static ptrdiff_t shouldPauseOffset() { return OBJECT_OFFSETOF(Debugger, m_shouldPause); }
</ins><span class="cx"> 
</span><span class="cx">     JSC::DebuggerCallFrame* currentDebuggerCallFrame() const;
</span><span class="cx">     bool hasHandlerForExceptionCallback() const
</span><span class="lines">@@ -104,6 +104,9 @@
</span><span class="cx"> 
</span><span class="cx">     void recompileAllJSFunctions(VM*);
</span><span class="cx"> 
</span><ins>+    void registerCodeBlock(CodeBlock*);
+    void unregisterCodeBlock(CodeBlock*);
+
</ins><span class="cx"> protected:
</span><span class="cx">     virtual bool needPauseHandling(JSGlobalObject*) { return false; }
</span><span class="cx">     virtual void handleBreakpointHit(const Breakpoint&amp;) { }
</span><span class="lines">@@ -128,8 +131,11 @@
</span><span class="cx"> 
</span><span class="cx">     typedef Vector&lt;Breakpoint&gt; BreakpointsInLine;
</span><span class="cx">     typedef HashMap&lt;unsigned, BreakpointsInLine, WTF::IntHash&lt;int&gt;, WTF::UnsignedWithZeroKeyHashTraits&lt;int&gt;&gt; LineToBreakpointsMap;
</span><del>-    typedef HashMap&lt;SourceID, LineToBreakpointsMap&gt; SourceIDToBreakpointsMap;
</del><ins>+    typedef HashMap&lt;SourceID, LineToBreakpointsMap, WTF::IntHash&lt;SourceID&gt;, WTF::UnsignedWithZeroKeyHashTraits&lt;SourceID&gt;&gt; SourceIDToBreakpointsMap;
</ins><span class="cx"> 
</span><ins>+    class ToggleBreakpointFunctor;
+    class ClearBreakpointsFunctor;
+
</ins><span class="cx">     class PauseReasonDeclaration {
</span><span class="cx">     public:
</span><span class="cx">         PauseReasonDeclaration(Debugger&amp; debugger, ReasonForPause reason)
</span><span class="lines">@@ -148,7 +154,6 @@
</span><span class="cx"> 
</span><span class="cx">     bool hasBreakpoint(SourceID, const TextPosition&amp;, Breakpoint* hitBreakpoint);
</span><span class="cx"> 
</span><del>-    bool shouldPause() const { return m_shouldPause; }
</del><span class="cx">     void setShouldPause(bool);
</span><span class="cx">     void updateNeedForOpDebugCallbacks();
</span><span class="cx"> 
</span><span class="lines">@@ -161,6 +166,15 @@
</span><span class="cx">     void updateCallFrameAndPauseIfNeeded(JSC::CallFrame*);
</span><span class="cx">     void pauseIfNeeded(JSC::CallFrame*);
</span><span class="cx"> 
</span><ins>+    enum BreakpointState {
+        BreakpointDisabled,
+        BreakpointEnabled
+    };
+    void toggleBreakpoint(CodeBlock*, Breakpoint&amp;, BreakpointState);
+    void applyBreakpoints(CodeBlock*);
+    void toggleBreakpoint(Breakpoint&amp;, BreakpointState);
+
+    VM* m_vm;
</ins><span class="cx">     HashSet&lt;JSGlobalObject*&gt; m_globalObjects;
</span><span class="cx"> 
</span><span class="cx">     PauseOnExceptionsState m_pauseOnExceptionsState;
</span><span class="lines">@@ -181,7 +195,6 @@
</span><span class="cx">     BreakpointIDToBreakpointMap m_breakpointIDToBreakpoint;
</span><span class="cx">     SourceIDToBreakpointsMap m_sourceIDToBreakpoints;
</span><span class="cx"> 
</span><del>-    bool m_needsOpDebugCallbacks;
</del><span class="cx">     bool m_shouldPause;
</span><span class="cx"> 
</span><span class="cx">     RefPtr&lt;JSC::DebuggerCallFrame&gt; m_currentDebuggerCallFrame;
</span><span class="lines">@@ -195,8 +208,11 @@
</span><span class="cx"> 
</span><span class="cx"> class Debugger {
</span><span class="cx"> public:
</span><del>-    Debugger(bool = false) : m_needsOpDebugCallbacks(false) { }
-    bool needsOpDebugCallbacks() const { return false; }
</del><ins>+    Debugger(bool = false)
+        : m_shouldPause(false)
+    {
+    }
+    bool shouldPause() const { return false; }
</ins><span class="cx">     bool needsExceptionCallbacks() const { return false; }
</span><span class="cx">     void detach(JSGlobalObject*) { }
</span><span class="cx">     void sourceParsed(ExecState*, SourceProvider*, int, const WTF::String&amp;) { }
</span><span class="lines">@@ -208,7 +224,8 @@
</span><span class="cx">     void didExecuteProgram(CallFrame*) { }
</span><span class="cx">     void didReachBreakpoint(CallFrame*) { }
</span><span class="cx"> 
</span><del>-    bool m_needsOpDebugCallbacks;
</del><ins>+private:
+    bool m_shouldPause;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(JAVASCRIPT_DEBUGGER)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCodeBlockSeth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CodeBlockSet.h (162597 => 162598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CodeBlockSet.h        2014-01-23 06:32:12 UTC (rev 162597)
+++ trunk/Source/JavaScriptCore/heap/CodeBlockSet.h        2014-01-23 07:39:58 UTC (rev 162598)
</span><span class="lines">@@ -71,6 +71,18 @@
</span><span class="cx">     // re-scanned during the next collection.
</span><span class="cx">     void rememberCurrentlyExecutingCodeBlocks(Heap*);
</span><span class="cx"> 
</span><ins>+    // Visits each CodeBlock in the heap until the visitor function returns true
+    // to indicate that it is done iterating, or until every CodeBlock has been
+    // visited.
+    template&lt;typename Functor&gt; void iterate(Functor&amp; functor)
+    {
+        for (auto &amp;codeBlock : m_set) {
+            bool done = functor(codeBlock);
+            if (done)
+                break;
+        }
+    }
+
</ins><span class="cx"> private:
</span><span class="cx">     // This is not a set of RefPtr&lt;CodeBlock&gt; because we need to be able to find
</span><span class="cx">     // arbitrary bogus pointers. I could have written a thingy that had peek types
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.h (162597 => 162598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.h        2014-01-23 06:32:12 UTC (rev 162597)
+++ trunk/Source/JavaScriptCore/heap/Heap.h        2014-01-23 07:39:58 UTC (rev 162598)
</span><span class="lines">@@ -174,6 +174,7 @@
</span><span class="cx">         
</span><span class="cx">         template&lt;typename Functor&gt; typename Functor::ReturnType forEachProtectedCell(Functor&amp;);
</span><span class="cx">         template&lt;typename Functor&gt; typename Functor::ReturnType forEachProtectedCell();
</span><ins>+        template&lt;typename Functor&gt; inline void forEachCodeBlock(Functor&amp;);
</ins><span class="cx"> 
</span><span class="cx">         HandleSet* handleSet() { return &amp;m_handleSet; }
</span><span class="cx">         HandleStack* handleStack() { return &amp;m_handleStack; }
</span><span class="lines">@@ -432,6 +433,11 @@
</span><span class="cx">         return forEachProtectedCell(functor);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    template&lt;typename Functor&gt; inline void Heap::forEachCodeBlock(Functor&amp; functor)
+    {
+        return m_codeBlocks.iterate&lt;Functor&gt;(functor);
+    }
+
</ins><span class="cx">     inline void* Heap::allocateWithNormalDestructor(size_t bytes)
</span><span class="cx">     {
</span><span class="cx"> #if ENABLE(ALLOCATION_LOGGING)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinterpreterInterpretercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp (162597 => 162598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp        2014-01-23 06:32:12 UTC (rev 162597)
+++ trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp        2014-01-23 07:39:58 UTC (rev 162598)
</span><span class="lines">@@ -1205,8 +1205,9 @@
</span><span class="cx"> NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID)
</span><span class="cx"> {
</span><span class="cx">     Debugger* debugger = callFrame-&gt;vmEntryGlobalObject()-&gt;debugger();
</span><del>-    if (!debugger || !debugger-&gt;needsOpDebugCallbacks())
</del><ins>+    if (!debugger)
</ins><span class="cx">         return;
</span><ins>+    ASSERT(debugger-&gt;shouldPause() || callFrame-&gt;codeBlock()-&gt;numBreakpoints() || callFrame-&gt;hadException());
</ins><span class="cx"> 
</span><span class="cx">     switch (debugHookID) {
</span><span class="cx">         case DidEnterCallFrame:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOpcodescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp (162597 => 162598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp        2014-01-23 06:32:12 UTC (rev 162597)
+++ trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp        2014-01-23 07:39:58 UTC (rev 162598)
</span><span class="lines">@@ -715,13 +715,21 @@
</span><span class="cx">     breakpoint();
</span><span class="cx"> #elif ENABLE(JAVASCRIPT_DEBUGGER)
</span><span class="cx">     JSGlobalObject* globalObject = codeBlock()-&gt;globalObject();
</span><del>-    Debugger* debugger = globalObject-&gt;debugger();
</del><span class="cx">     char* debuggerAddress = reinterpret_cast&lt;char*&gt;(globalObject) + JSGlobalObject::debuggerOffset();
</span><span class="cx">     Jump noDebugger = branchTestPtr(Zero, AbsoluteAddress(debuggerAddress));
</span><del>-    char* flagAddress = reinterpret_cast&lt;char*&gt;(debugger) + Debugger::needsOpDebugCallbacksOffset();
-    Jump skipDebugHook = branchTest8(Zero, AbsoluteAddress(flagAddress));
</del><ins>+
+    Debugger* debugger = globalObject-&gt;debugger();
+    char* shouldPauseAddress = reinterpret_cast&lt;char*&gt;(debugger) + Debugger::shouldPauseOffset();
+    Jump callbackNeeded = branchTest8(NonZero, AbsoluteAddress(shouldPauseAddress));
+
+    char* numBreakpointsAddress = reinterpret_cast&lt;char*&gt;(codeBlock()) + CodeBlock::numBreakpointsOffset();
+    load32(numBreakpointsAddress, regT0);
+    Jump noBreakpointSet = branchTest32(Zero, regT0);
+
+    callbackNeeded.link(this);
</ins><span class="cx">     callOperation(operationDebug, currentInstruction[1].u.operand);
</span><del>-    skipDebugHook.link(this);
</del><ins>+
+    noBreakpointSet.link(this);
</ins><span class="cx">     noDebugger.link(this);
</span><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(currentInstruction);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOpcodes32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp (162597 => 162598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp        2014-01-23 06:32:12 UTC (rev 162597)
+++ trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp        2014-01-23 07:39:58 UTC (rev 162598)
</span><span class="lines">@@ -997,14 +997,22 @@
</span><span class="cx">     breakpoint();
</span><span class="cx"> #elif ENABLE(JAVASCRIPT_DEBUGGER)
</span><span class="cx">     JSGlobalObject* globalObject = codeBlock()-&gt;globalObject();
</span><del>-    Debugger* debugger = globalObject-&gt;debugger();
</del><span class="cx">     char* debuggerAddress = reinterpret_cast&lt;char*&gt;(globalObject) + JSGlobalObject::debuggerOffset();
</span><span class="cx">     loadPtr(debuggerAddress, regT0);
</span><span class="cx">     Jump noDebugger = branchTestPtr(Zero, regT0);
</span><del>-    char* flagAddress = reinterpret_cast&lt;char*&gt;(debugger) + Debugger::needsOpDebugCallbacksOffset();
-    Jump skipDebugHook = branchTest8(Zero, AbsoluteAddress(flagAddress));
</del><ins>+
+    Debugger* debugger = globalObject-&gt;debugger();
+    char* shouldPauseAddress = reinterpret_cast&lt;char*&gt;(debugger) + Debugger::shouldPauseOffset();
+    Jump callbackNeeded = branchTest8(NonZero, AbsoluteAddress(shouldPauseAddress));
+
+    char* numBreakpointsAddress = reinterpret_cast&lt;char*&gt;(codeBlock()) + CodeBlock::numBreakpointsOffset();
+    load32(numBreakpointsAddress, regT0);
+    Jump noBreakpointSet = branchTest32(Zero, regT0);
+
+    callbackNeeded.link(this);
</ins><span class="cx">     callOperation(operationDebug, currentInstruction[1].u.operand);
</span><del>-    skipDebugHook.link(this);
</del><ins>+
+    noBreakpointSet.link(this);
</ins><span class="cx">     noDebugger.link(this);
</span><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(currentInstruction);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreterasm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm (162597 => 162598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm        2014-01-23 06:32:12 UTC (rev 162597)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm        2014-01-23 07:39:58 UTC (rev 162598)
</span><span class="lines">@@ -835,13 +835,18 @@
</span><span class="cx"> 
</span><span class="cx"> _llint_op_debug:
</span><span class="cx">     traceExecution()
</span><del>-    loadp CodeBlock[cfr], t0
-    loadp CodeBlock::m_globalObject[t0], t0
</del><ins>+    loadp CodeBlock[cfr], t1
+    loadp CodeBlock::m_globalObject[t1], t0
</ins><span class="cx">     loadp JSGlobalObject::m_debugger[t0], t0
</span><span class="cx">     btiz t0, .opDebugDone
</span><del>-    loadb Debugger::m_needsOpDebugCallbacks[t0], t0
-    btbz t0, .opDebugDone
</del><span class="cx"> 
</span><ins>+    loadb Debugger::m_shouldPause[t0], t0
+    btbnz t0, .opDebugDoCallback
+
+    loadi CodeBlock::m_numBreakpoints[t1], t0
+    btiz t0, .opDebugDone
+
+.opDebugDoCallback:
</ins><span class="cx">     callSlowPath(_llint_slow_path_debug)
</span><span class="cx"> .opDebugDone:                    
</span><span class="cx">     dispatch(3)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeExecutablecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Executable.cpp (162597 => 162598)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Executable.cpp        2014-01-23 06:32:12 UTC (rev 162597)
+++ trunk/Source/JavaScriptCore/runtime/Executable.cpp        2014-01-23 07:39:58 UTC (rev 162598)
</span><span class="lines">@@ -172,6 +172,10 @@
</span><span class="cx"> 
</span><span class="cx">     if (oldCodeBlock)
</span><span class="cx">         oldCodeBlock-&gt;unlinkIncomingCalls();
</span><ins>+
+    Debugger* debugger = genericCodeBlock-&gt;globalObject()-&gt;debugger();
+    if (debugger)
+        debugger-&gt;registerCodeBlock(genericCodeBlock);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> PassRefPtr&lt;CodeBlock&gt; ScriptExecutable::newCodeBlockFor(
</span></span></pre>
</div>
</div>

</body>
</html>