Title: [207228] trunk
Revision
207228
Author
joep...@webkit.org
Date
2016-10-12 11:47:48 -0700 (Wed, 12 Oct 2016)

Log Message

Emit DebugHooks uniformly with pause locations instead of having separate pause locations and op_debug emits
https://bugs.webkit.org/show_bug.cgi?id=162809

Reviewed by Geoffrey Garen.

Source/_javascript_Core:

Change how BytecodeGeneration emits debug hooks to be more consistent.
Previously most nodes individually generated their own debug hook
and we asserted that it matched a breakpoint location identified
by the parser. This could get out of sync, or nodes could forget to
emit debug hooks expected by the parser.

With this change, we always check and emit a debug hook for any
node. The default behavior is for BytecodeGenerator::emitNode
to emit the debug hook when emitting the node itself. This covers
the majority of cases (statements).

There are a few exceptions where we continue to need to customize
emitting debug hooks:

    1. Nodes with emitBytecodeInConditionContext
        - non-_expression_ nodes customize how they emit their children
        - constants conditions may emit nothing, but we had recorded a breakpoint location so emit a debug hook
        - always emit one debug hook in case we recorded a breakpoint location, but avoid emitting multiple
          in nodes which may call up to the ExpressionNode::emitBytecodeInConditionContext base impl.
    2. Specialized Debug Hooks
        - such as hooks for Program start/end, debugger statements, etc.
    3. Debug Hooks in for..of / for..in that don't correspond to re-emitting nodes
        - such as pausing on the assignment _expression_ inside these loops

The majority of nodes no longer have custom emits.

* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::emitNodeInTailPosition):
(JSC::BytecodeGenerator::emitNodeInConditionContext):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitDebugHook):
(JSC::BytecodeGenerator::emitEnumeration):
By default, when emitting a node check if we should also emit an op_debug for it.
This default DebugHook is WillExecuteStatement, which is a normal pause point.

* bytecompiler/NodesCodegen.cpp:
(JSC::ConstantNode::emitBytecodeInConditionContext):
(JSC::LogicalNotNode::emitBytecodeInConditionContext):
(JSC::BinaryOpNode::emitBytecodeInConditionContext):
(JSC::LogicalOpNode::emitBytecodeInConditionContext):
The parser would have generated a pause location for these conditions
no matter what constant folding and re-writing these nodes may perform.
So, when emitting these nodes in condition context check if they need
emit their own debug hook.

(JSC::EmptyStatementNode::emitBytecode):
(JSC::ExprStatementNode::emitBytecode):
(JSC::DeclarationStatement::emitBytecode):
(JSC::IfElseNode::emitBytecode):
(JSC::DoWhileNode::emitBytecode):
(JSC::WhileNode::emitBytecode):
(JSC::ForNode::emitBytecode):
(JSC::ContinueNode::emitBytecode):
(JSC::BreakNode::emitBytecode):
(JSC::ReturnNode::emitBytecode):
(JSC::WithNode::emitBytecode):
(JSC::SwitchNode::emitBytecode):
(JSC::ThrowNode::emitBytecode):
No longer need to custom emit debug hooks. The default emitNode will handle these.

(JSC::ForInNode::emitBytecode):
Include extra debug hooks the user expects to return back to the assignment
_expression_ in the loop header before starting the body again. The same is done
for for..of with emitEnumeration.

* parser/ASTBuilder.h:
(JSC::ASTBuilder::createExportDefaultDeclaration):
(JSC::ASTBuilder::createExportLocalDeclaration):
These are no longer needed to fake-satisfy assertions. We never wanted to
emit debug hooks for these inner statements because the export statement
will already have the debug hooks.

(JSC::ASTBuilder::createForInLoop):
(JSC::ASTBuilder::createForOfLoop):
Include the correct location where the declaration starts.

(JSC::ASTBuilder::breakpointLocation):
Simplify to a general implementation for Node.

* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createForInLoop):
(JSC::SyntaxChecker::createForOfLoop):
Ignore the new extra parameter.

* parser/Nodes.h:
(JSC::Node::needsDebugHook):
(JSC::Node::setNeedsDebugHook):
(JSC::ExpressionNode::needsDebugHook): Deleted.
(JSC::ExpressionNode::setNeedsDebugHook): Deleted.
(JSC::StatementNode::isEmptyStatement): Deleted.
(JSC::StatementNode::needsDebugHook): Deleted.
(JSC::StatementNode::setNeedsDebugHook): Deleted.
Move debug hook logic into the base Node class.

(JSC::StatementNode::isDebuggerStatement):
Provide a way to distinguish a debugger statement.

* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseForStatement):
Provide the location before the declaration starts.

Source/WebInspectorUI:

* UserInterface/Views/SourceCodeTextEditor.js:
(WebInspector.SourceCodeTextEditor.prototype.textEditorExecutionHighlightRange):
When pausing on the variable assignment inside for..of and for..in don't just
highlight "var foo" but include the right hand side "var foo in ..." or
"var foo of ...".

LayoutTests:

* inspector/debugger/stepping/stepping-control-flow-expected.txt:
* inspector/debugger/stepping/stepping-control-flow.html:
Add new tests for stepping through conditional expressions with constants,
logical operations, binary operations, and unary negations.

* inspector/debugger/stepping/stepping-loops-expected.txt:
* inspector/debugger/stepping/stepping-loops.html:
Update tests for changes in stepping behavior in for loops.

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (207227 => 207228)


--- trunk/LayoutTests/ChangeLog	2016-10-12 18:43:19 UTC (rev 207227)
+++ trunk/LayoutTests/ChangeLog	2016-10-12 18:47:48 UTC (rev 207228)
@@ -1,3 +1,19 @@
+2016-10-12  Joseph Pecoraro  <pecor...@apple.com>
+
+        Emit DebugHooks uniformly with pause locations instead of having separate pause locations and op_debug emits
+        https://bugs.webkit.org/show_bug.cgi?id=162809
+
+        Reviewed by Geoffrey Garen.
+
+        * inspector/debugger/stepping/stepping-control-flow-expected.txt:
+        * inspector/debugger/stepping/stepping-control-flow.html:
+        Add new tests for stepping through conditional expressions with constants,
+        logical operations, binary operations, and unary negations.
+
+        * inspector/debugger/stepping/stepping-loops-expected.txt:
+        * inspector/debugger/stepping/stepping-loops.html:
+        Update tests for changes in stepping behavior in for loops.
+
 2016-10-12  Carlos Alberto Lopez Perez  <clo...@igalia.com>
 
         [GTK] Tests that fail since the new URLParser has been enabled on r207162.

Modified: trunk/LayoutTests/inspector/debugger/stepping/stepping-control-flow-expected.txt (207227 => 207228)


--- trunk/LayoutTests/inspector/debugger/stepping/stepping-control-flow-expected.txt	2016-10-12 18:43:19 UTC (rev 207227)
+++ trunk/LayoutTests/inspector/debugger/stepping/stepping-control-flow-expected.txt	2016-10-12 18:47:48 UTC (rev 207228)
@@ -7,13 +7,13 @@
 STEPS: over, over, over, over, resume
 PAUSED (debugger-statement)
 PAUSE AT entryIfSingleStatement:16:5
-     12    }
+     12    
      13    
      14    function entryIfSingleStatement() {
  ->  15        |debugger;
-     16        if (true)
+     16        if (truthy)
      17            a();
-     18        if (false)
+     18        if (falsey)
 
 ACTION: step-over
 PAUSE AT entryIfSingleStatement:17:9
@@ -20,9 +20,9 @@
      13    
      14    function entryIfSingleStatement() {
      15        debugger;
- ->  16        if (|true)
+ ->  16        if (|truthy)
      17            a();
-     18        if (false)
+     18        if (falsey)
      19            a();
 
 ACTION: step-over
@@ -29,9 +29,9 @@
 PAUSE AT entryIfSingleStatement:18:9
      14    function entryIfSingleStatement() {
      15        debugger;
-     16        if (true)
+     16        if (truthy)
  ->  17            |a();
-     18        if (false)
+     18        if (falsey)
      19            a();
      20    }
 
@@ -38,9 +38,9 @@
 ACTION: step-over
 PAUSE AT entryIfSingleStatement:19:9
      15        debugger;
-     16        if (true)
+     16        if (truthy)
      17            a();
- ->  18        if (|false)
+ ->  18        if (|falsey)
      19            a();
      20    }
      21    
@@ -48,7 +48,7 @@
 ACTION: step-over
 PAUSE AT entryIfSingleStatement:21:2
      17            a();
-     18        if (false)
+     18        if (falsey)
      19            a();
  ->  20    }|
      21    
@@ -68,7 +68,7 @@
      21    
      22    function entryIfMultiStatement() {
  ->  23        |debugger;
-     24        if (true) {
+     24        if (truthy) {
      25            a();
      26            a();
 
@@ -77,7 +77,7 @@
      21    
      22    function entryIfMultiStatement() {
      23        debugger;
- ->  24        if (|true) {
+ ->  24        if (|truthy) {
      25            a();
      26            a();
      27        }
@@ -86,20 +86,20 @@
 PAUSE AT entryIfMultiStatement:26:9
      22    function entryIfMultiStatement() {
      23        debugger;
-     24        if (true) {
+     24        if (truthy) {
  ->  25            |a();
      26            a();
      27        }
-     28        if (false) {
+     28        if (falsey) {
 
 ACTION: step-over
 PAUSE AT entryIfMultiStatement:27:9
      23        debugger;
-     24        if (true) {
+     24        if (truthy) {
      25            a();
  ->  26            |a();
      27        }
-     28        if (false) {
+     28        if (falsey) {
      29            a();
 
 ACTION: step-over
@@ -107,7 +107,7 @@
      25            a();
      26            a();
      27        }
- ->  28        if (|false) {
+ ->  28        if (|falsey) {
      29            a();
      30            a();
      31        }
@@ -135,7 +135,7 @@
      33    
      34    function entryIfElse() {
  ->  35        |debugger;
-     36        if (true)
+     36        if (truthy)
      37            a();
      38        else
 
@@ -144,7 +144,7 @@
      33    
      34    function entryIfElse() {
      35        debugger;
- ->  36        if (|true)
+ ->  36        if (|truthy)
      37            a();
      38        else
      39            a();
@@ -153,11 +153,11 @@
 PAUSE AT entryIfElse:38:9
      34    function entryIfElse() {
      35        debugger;
-     36        if (true)
+     36        if (truthy)
  ->  37            |a();
      38        else
      39            a();
-     40        if (false)
+     40        if (falsey)
 
 ACTION: step-over
 PAUSE AT entryIfElse:41:9
@@ -164,7 +164,7 @@
      37            a();
      38        else
      39            a();
- ->  40        if (|false)
+ ->  40        if (|falsey)
      41            a();
      42        else
      43            a();
@@ -171,7 +171,7 @@
 
 ACTION: step-over
 PAUSE AT entryIfElse:44:9
-     40        if (false)
+     40        if (falsey)
      41            a();
      42        else
  ->  43            |a();
@@ -202,9 +202,9 @@
      45    
      46    function entryIfElseChain() {
  ->  47        |debugger;
-     48        if (false)
+     48        if (falsey)
      49            a();
-     50        else if (true)
+     50        else if (truthy)
 
 ACTION: step-over
 PAUSE AT entryIfElseChain:49:9
@@ -211,17 +211,17 @@
      45    
      46    function entryIfElseChain() {
      47        debugger;
- ->  48        if (|false)
+ ->  48        if (|falsey)
      49            a();
-     50        else if (true)
+     50        else if (truthy)
      51            a();
 
 ACTION: step-over
 PAUSE AT entryIfElseChain:51:14
      47        debugger;
-     48        if (false)
+     48        if (falsey)
      49            a();
- ->  50        else if (|true)
+ ->  50        else if (|truthy)
      51            a();
      52        else
      53            a();
@@ -228,9 +228,9 @@
 
 ACTION: step-over
 PAUSE AT entryIfElseChain:52:9
-     48        if (false)
+     48        if (falsey)
      49            a();
-     50        else if (true)
+     50        else if (truthy)
  ->  51            |a();
      52        else
      53            a();
@@ -241,17 +241,17 @@
      52        else
      53            a();
      54    
- ->  55        if (|false)
+ ->  55        if (|falsey)
      56            a();
-     57        else if (false)
+     57        else if (falsey)
      58            a();
 
 ACTION: step-over
 PAUSE AT entryIfElseChain:58:14
      54    
-     55        if (false)
+     55        if (falsey)
      56            a();
- ->  57        else if (|false)
+ ->  57        else if (|falsey)
      58            a();
      59        else
      60            a();
@@ -258,7 +258,7 @@
 
 ACTION: step-over
 PAUSE AT entryIfElseChain:61:9
-     57        else if (false)
+     57        else if (falsey)
      58            a();
      59        else
  ->  60            |a();
@@ -321,7 +321,7 @@
  ->  67    }|
      68    
      69    function entryTernary() {
-     70        let t = () => true;
+     70        let t = () => truthy;
 
 ACTION: resume
 RESUMED
@@ -351,14 +351,14 @@
      68    
 
 ACTION: step-in
-PAUSE AT a:8:5
-      4    <script src=""
-      5    <script>
-      6    function a() {
- ->   7        |return 1;
-      8    }
-      9    
-     10    function b() {
+PAUSE AT a:11:16
+      7    var value = 1;
+      8    var truthy = true;
+      9    var falsey = false;
+ ->  10    function a() { |return value; }
+     11    function b() { return value; }
+     12    
+     13    
 
 ACTION: step-out
 PAUSE AT entryIfWithCall:66:16
@@ -371,14 +371,14 @@
      68    
 
 ACTION: step-in
-PAUSE AT a:8:5
-      4    <script src=""
-      5    <script>
-      6    function a() {
- ->   7        |return 1;
-      8    }
-      9    
-     10    function b() {
+PAUSE AT a:11:16
+      7    var value = 1;
+      8    var truthy = true;
+      9    var falsey = false;
+ ->  10    function a() { |return value; }
+     11    function b() { return value; }
+     12    
+     13    
 
 ACTION: step-out
 PAUSE AT entryIfWithCall:67:9
@@ -398,7 +398,7 @@
  ->  67    }|
      68    
      69    function entryTernary() {
-     70        let t = () => true;
+     70        let t = () => truthy;
 
 ACTION: resume
 RESUMED
@@ -410,8 +410,8 @@
 PAUSED (debugger-statement)
 PAUSE AT entryTernary:73:5
      69    function entryTernary() {
-     70        let t = () => true;
-     71        let f = () => false;
+     70        let t = () => truthy;
+     71        let f = () => falsey;
  ->  72        |debugger;
      73        let x = t() ? a() : b();
      74        let y = f() ? a() : b();
@@ -419,8 +419,8 @@
 
 ACTION: step-over
 PAUSE AT entryTernary:74:5
-     70        let t = () => true;
-     71        let f = () => false;
+     70        let t = () => truthy;
+     71        let f = () => falsey;
      72        debugger;
  ->  73        |let x = t() ? a() : b();
      74        let y = f() ? a() : b();
@@ -429,13 +429,13 @@
 
 ACTION: step-over
 PAUSE AT entryTernary:75:5
-     71        let f = () => false;
+     71        let f = () => falsey;
      72        debugger;
      73        let x = t() ? a() : b();
  ->  74        |let y = f() ? a() : b();
      75    }
      76    
-     77    // ---------
+     77    function entryIfConstantBranch() {
 
 ACTION: step-over
 PAUSE AT entryTernary:76:2
@@ -444,8 +444,8 @@
      74        let y = f() ? a() : b();
  ->  75    }|
      76    
-     77    // ---------
-     78    
+     77    function entryIfConstantBranch() {
+     78        debugger;
 
 ACTION: resume
 RESUMED
@@ -457,8 +457,8 @@
 PAUSED (debugger-statement)
 PAUSE AT entryTernary:73:5
      69    function entryTernary() {
-     70        let t = () => true;
-     71        let f = () => false;
+     70        let t = () => truthy;
+     71        let f = () => falsey;
  ->  72        |debugger;
      73        let x = t() ? a() : b();
      74        let y = f() ? a() : b();
@@ -466,8 +466,8 @@
 
 ACTION: step-over
 PAUSE AT entryTernary:74:5
-     70        let t = () => true;
-     71        let f = () => false;
+     70        let t = () => truthy;
+     71        let f = () => falsey;
      72        debugger;
  ->  73        |let x = t() ? a() : b();
      74        let y = f() ? a() : b();
@@ -479,15 +479,15 @@
      67    }
      68    
      69    function entryTernary() {
- ->  70        let t = () => |true;
-     71        let f = () => false;
+ ->  70        let t = () => |truthy;
+     71        let f = () => falsey;
      72        debugger;
      73        let x = t() ? a() : b();
 
 ACTION: step-out
 PAUSE AT entryTernary:74:19
-     70        let t = () => true;
-     71        let f = () => false;
+     70        let t = () => truthy;
+     71        let f = () => falsey;
      72        debugger;
  ->  73        let x = t() ? |a() : b();
      74        let y = f() ? a() : b();
@@ -495,31 +495,31 @@
      76    
 
 ACTION: step-in
-PAUSE AT a:8:5
-      4    <script src=""
-      5    <script>
-      6    function a() {
- ->   7        |return 1;
-      8    }
-      9    
-     10    function b() {
+PAUSE AT a:11:16
+      7    var value = 1;
+      8    var truthy = true;
+      9    var falsey = false;
+ ->  10    function a() { |return value; }
+     11    function b() { return value; }
+     12    
+     13    
 
 ACTION: step-out
 PAUSE AT entryTernary:75:5
-     71        let f = () => false;
+     71        let f = () => falsey;
      72        debugger;
      73        let x = t() ? a() : b();
  ->  74        |let y = f() ? a() : b();
      75    }
      76    
-     77    // ---------
+     77    function entryIfConstantBranch() {
 
 ACTION: step-in
 PAUSE AT f:72:19
      68    
      69    function entryTernary() {
-     70        let t = () => true;
- ->  71        let f = () => |false;
+     70        let t = () => truthy;
+ ->  71        let f = () => |falsey;
      72        debugger;
      73        let x = t() ? a() : b();
      74        let y = f() ? a() : b();
@@ -526,21 +526,21 @@
 
 ACTION: step-out
 PAUSE AT entryTernary:75:25
-     71        let f = () => false;
+     71        let f = () => falsey;
      72        debugger;
      73        let x = t() ? a() : b();
  ->  74        let y = f() ? a() : |b();
      75    }
      76    
-     77    // ---------
+     77    function entryIfConstantBranch() {
 
 ACTION: step-in
-PAUSE AT b:12:5
-      8    }
-      9    
-     10    function b() {
- ->  11        |return 2;
-     12    }
+PAUSE AT b:12:16
+      8    var truthy = true;
+      9    var falsey = false;
+     10    function a() { return value; }
+ ->  11    function b() { |return value; }
+     12    
      13    
      14    function entryIfSingleStatement() {
 
@@ -551,10 +551,278 @@
      74        let y = f() ? a() : b();
  ->  75    }|
      76    
-     77    // ---------
-     78    
+     77    function entryIfConstantBranch() {
+     78        debugger;
 
 ACTION: resume
 RESUMED
 PASS: Should have used all steps.
 
+-- Running test case: Debugger.stepping.ConstantBranch
+_expression_: setTimeout(entryIfConstantBranch)
+STEPS: over, over, over, over, over, over, resume
+PAUSED (debugger-statement)
+PAUSE AT entryIfConstantBranch:79:5
+     75    }
+     76    
+     77    function entryIfConstantBranch() {
+ ->  78        |debugger;
+     79        if (true)
+     80            a();
+     81        if (false)
+
+ACTION: step-over
+PAUSE AT entryIfConstantBranch:80:9
+     76    
+     77    function entryIfConstantBranch() {
+     78        debugger;
+ ->  79        if (|true)
+     80            a();
+     81        if (false)
+     82            a();
+
+ACTION: step-over
+PAUSE AT entryIfConstantBranch:81:9
+     77    function entryIfConstantBranch() {
+     78        debugger;
+     79        if (true)
+ ->  80            |a();
+     81        if (false)
+     82            a();
+     83        if (0)
+
+ACTION: step-over
+PAUSE AT entryIfConstantBranch:82:9
+     78        debugger;
+     79        if (true)
+     80            a();
+ ->  81        if (|false)
+     82            a();
+     83        if (0)
+     84            a();
+
+ACTION: step-over
+PAUSE AT entryIfConstantBranch:84:9
+     80            a();
+     81        if (false)
+     82            a();
+ ->  83        if (|0)
+     84            a();
+     85        if (null)
+     86            a();
+
+ACTION: step-over
+PAUSE AT entryIfConstantBranch:86:9
+     82            a();
+     83        if (0)
+     84            a();
+ ->  85        if (|null)
+     86            a();
+     87    }
+     88    
+
+ACTION: step-over
+PAUSE AT entryIfConstantBranch:88:2
+     84            a();
+     85        if (null)
+     86            a();
+ ->  87    }|
+     88    
+     89    function entryIfWithLogicalOperation() {
+     90        debugger;
+
+ACTION: resume
+RESUMED
+PASS: Should have used all steps.
+
+-- Running test case: Debugger.stepping.IfWithLogicalOperation
+_expression_: setTimeout(entryIfWithLogicalOperation)
+STEPS: over, in, out, in, out, over, resume
+PAUSED (debugger-statement)
+PAUSE AT entryIfWithLogicalOperation:91:5
+     87    }
+     88    
+     89    function entryIfWithLogicalOperation() {
+ ->  90        |debugger;
+     91        if (true && a() && a())
+     92            b();
+     93    }
+
+ACTION: step-over
+PAUSE AT entryIfWithLogicalOperation:92:9
+     88    
+     89    function entryIfWithLogicalOperation() {
+     90        debugger;
+ ->  91        if (|true && a() && a())
+     92            b();
+     93    }
+     94    
+
+ACTION: step-in
+PAUSE AT a:11:16
+      7    var value = 1;
+      8    var truthy = true;
+      9    var falsey = false;
+ ->  10    function a() { |return value; }
+     11    function b() { return value; }
+     12    
+     13    
+
+ACTION: step-out
+PAUSE AT entryIfWithLogicalOperation:92:24
+     88    
+     89    function entryIfWithLogicalOperation() {
+     90        debugger;
+ ->  91        if (true && a() && |a())
+     92            b();
+     93    }
+     94    
+
+ACTION: step-in
+PAUSE AT a:11:16
+      7    var value = 1;
+      8    var truthy = true;
+      9    var falsey = false;
+ ->  10    function a() { |return value; }
+     11    function b() { return value; }
+     12    
+     13    
+
+ACTION: step-out
+PAUSE AT entryIfWithLogicalOperation:93:9
+     89    function entryIfWithLogicalOperation() {
+     90        debugger;
+     91        if (true && a() && a())
+ ->  92            |b();
+     93    }
+     94    
+     95    function entryIfWithBinaryOperation() {
+
+ACTION: step-over
+PAUSE AT entryIfWithLogicalOperation:94:2
+     90        debugger;
+     91        if (true && a() && a())
+     92            b();
+ ->  93    }|
+     94    
+     95    function entryIfWithBinaryOperation() {
+     96        let i = a();
+
+ACTION: resume
+RESUMED
+PASS: Should have used all steps.
+
+-- Running test case: Debugger.stepping.IfWithBinaryOperation
+_expression_: setTimeout(entryIfWithBinaryOperation)
+STEPS: over, in, over, resume
+PAUSED (debugger-statement)
+PAUSE AT entryIfWithBinaryOperation:98:5
+     94    
+     95    function entryIfWithBinaryOperation() {
+     96        let i = a();
+ ->  97        |debugger;
+     98        if (i < 2)
+     99            b();
+    100    }
+
+ACTION: step-over
+PAUSE AT entryIfWithBinaryOperation:99:9
+     95    function entryIfWithBinaryOperation() {
+     96        let i = a();
+     97        debugger;
+ ->  98        if (|i < 2)
+     99            b();
+    100    }
+    101    
+
+ACTION: step-in
+PAUSE AT entryIfWithBinaryOperation:100:9
+     96        let i = a();
+     97        debugger;
+     98        if (i < 2)
+ ->  99            |b();
+    100    }
+    101    
+    102    function entryIfWithNotOperation() {
+
+ACTION: step-over
+PAUSE AT entryIfWithBinaryOperation:101:2
+     97        debugger;
+     98        if (i < 2)
+     99            b();
+ -> 100    }|
+    101    
+    102    function entryIfWithNotOperation() {
+    103        debugger;
+
+ACTION: resume
+RESUMED
+PASS: Should have used all steps.
+
+-- Running test case: Debugger.stepping.IfWithNotOperation
+_expression_: setTimeout(entryIfWithNotOperation)
+STEPS: over, in, over, in, over, resume
+PAUSED (debugger-statement)
+PAUSE AT entryIfWithNotOperation:104:5
+    100    }
+    101    
+    102    function entryIfWithNotOperation() {
+ -> 103        |debugger;
+    104        if (!false)
+    105            a();
+    106        if (!!true)
+
+ACTION: step-over
+PAUSE AT entryIfWithNotOperation:105:9
+    101    
+    102    function entryIfWithNotOperation() {
+    103        debugger;
+ -> 104        if (|!false)
+    105            a();
+    106        if (!!true)
+    107            a();
+
+ACTION: step-in
+PAUSE AT entryIfWithNotOperation:106:9
+    102    function entryIfWithNotOperation() {
+    103        debugger;
+    104        if (!false)
+ -> 105            |a();
+    106        if (!!true)
+    107            a();
+    108    }
+
+ACTION: step-over
+PAUSE AT entryIfWithNotOperation:107:9
+    103        debugger;
+    104        if (!false)
+    105            a();
+ -> 106        if (|!!true)
+    107            a();
+    108    }
+    109    
+
+ACTION: step-in
+PAUSE AT entryIfWithNotOperation:108:9
+    104        if (!false)
+    105            a();
+    106        if (!!true)
+ -> 107            |a();
+    108    }
+    109    
+    110    // ---------
+
+ACTION: step-over
+PAUSE AT entryIfWithNotOperation:109:2
+    105            a();
+    106        if (!!true)
+    107            a();
+ -> 108    }|
+    109    
+    110    // ---------
+    111    
+
+ACTION: resume
+RESUMED
+PASS: Should have used all steps.
+

Modified: trunk/LayoutTests/inspector/debugger/stepping/stepping-control-flow.html (207227 => 207228)


--- trunk/LayoutTests/inspector/debugger/stepping/stepping-control-flow.html	2016-10-12 18:43:19 UTC (rev 207227)
+++ trunk/LayoutTests/inspector/debugger/stepping/stepping-control-flow.html	2016-10-12 18:47:48 UTC (rev 207228)
@@ -4,29 +4,29 @@
 <script src=""
 <script src=""
 <script>
-function a() {
-    return 1;
-}
+// We may want to allow constants to eliminate branches. Use vars for existing tests and have constant specific tests.
+var value = 1;
+var truthy = true;
+var falsey = false;
+function a() { return value; }
+function b() { return value; }
 
-function b() {
-    return 2;
-}
 
 function entryIfSingleStatement() {
     debugger;
-    if (true)
+    if (truthy)
         a();
-    if (false)
+    if (falsey)
         a();
 }
 
 function entryIfMultiStatement() {
     debugger;
-    if (true) {
+    if (truthy) {
         a();
         a();
     }
-    if (false) {
+    if (falsey) {
         a();
         a();
     }
@@ -34,11 +34,11 @@
 
 function entryIfElse() {
     debugger;
-    if (true)
+    if (truthy)
         a();
     else
         a();
-    if (false)
+    if (falsey)
         a();
     else
         a();
@@ -46,16 +46,16 @@
 
 function entryIfElseChain() {
     debugger;
-    if (false)
+    if (falsey)
         a();
-    else if (true)
+    else if (truthy)
         a();
     else
         a();
 
-    if (false)
+    if (falsey)
         a();
-    else if (false)
+    else if (falsey)
         a();
     else
         a();
@@ -68,13 +68,46 @@
 }
 
 function entryTernary() {
-    let t = () => true;
-    let f = () => false;
+    let t = () => truthy;
+    let f = () => falsey;
     debugger;
     let x = t() ? a() : b();
     let y = f() ? a() : b();
 }
 
+function entryIfConstantBranch() {
+    debugger;
+    if (true)
+        a();
+    if (false)
+        a();
+    if (0)
+        a();
+    if (null)
+        a();
+}
+
+function entryIfWithLogicalOperation() {
+    debugger;
+    if (true && a() && a())
+        b();
+}
+
+function entryIfWithBinaryOperation() {
+    let i = a();
+    debugger;
+    if (i < 2)
+        b();
+}
+
+function entryIfWithNotOperation() {
+    debugger;
+    if (!false)
+        a();
+    if (!!true)
+        a();
+}
+
 // ---------
 
 function test()
@@ -197,6 +230,62 @@
         ]
     });
 
+    addSteppingTestCase({
+        name: "Debugger.stepping.ConstantBranch",
+        description: "Should pause for constant branches.",
+        _expression_: "setTimeout(entryIfConstantBranch)",
+        steps: [
+            "over",
+                "over", // (true)
+                "over", // a()
+                "over", // (false)
+                "over", // (0)
+                "over", // (null)
+            "resume",
+        ]
+    });
+
+    addSteppingTestCase({
+        name: "Debugger.stepping.IfWithLogicalOperation",
+        description: "Should always pause for a condition with logical operations.",
+        _expression_: "setTimeout(entryIfWithLogicalOperation)",
+        steps: [
+            "over",
+                "in",   // into a()
+                "out",  // out of a() - before a()
+                "in",   // into a()
+                "out",  // out of a() - before b()
+                "over", // b() - leaving entry
+            "resume",
+        ]
+    });
+
+    addSteppingTestCase({
+        name: "Debugger.stepping.IfWithBinaryOperation",
+        description: "Should always pause for a condition with logical operations.",
+        _expression_: "setTimeout(entryIfWithBinaryOperation)",
+        steps: [
+            "over",
+                "in",    // i < 2 [true]
+                "over",  // over b() - leaving entry
+            "resume",
+        ]
+    });
+
+    addSteppingTestCase({
+        name: "Debugger.stepping.IfWithNotOperation",
+        description: "Should always pause for a condition that is a not operation.",
+        _expression_: "setTimeout(entryIfWithNotOperation)",
+        steps: [
+            "over",
+                "in",   // !false
+                "over", // a()
+                "in",   // !!truth
+                "over", // a() - leaving entry
+            "resume",
+        ]
+    });
+
     loadMainPageContent().then(() => {
         suite.runTestCasesAndFinish();
     });

Modified: trunk/LayoutTests/inspector/debugger/stepping/stepping-loops-expected.txt (207227 => 207228)


--- trunk/LayoutTests/inspector/debugger/stepping/stepping-loops-expected.txt	2016-10-12 18:43:19 UTC (rev 207227)
+++ trunk/LayoutTests/inspector/debugger/stepping/stepping-loops-expected.txt	2016-10-12 18:47:48 UTC (rev 207228)
@@ -148,7 +148,7 @@
 
 -- Running test case: Debugger.stepping.TraditionalForStepOver
 _expression_: setTimeout(entryTraditionalFor)
-STEPS: over, over, over, over, over, over, over, over, resume
+STEPS: over, over, over, over, over, over, over, over, over, resume
 PAUSED (debugger-statement)
 PAUSE AT entryTraditionalFor:27:5
      23    }
@@ -170,6 +170,16 @@
      30    
 
 ACTION: step-over
+PAUSE AT entryTraditionalFor:28:21
+     24    
+     25    function entryTraditionalFor() {
+     26        debugger;
+ ->  27        for (let i = 0; |i < 2; ++i)
+     28            a();
+     29    }
+     30    
+
+ACTION: step-over
 PAUSE AT entryTraditionalFor:29:9
      25    function entryTraditionalFor() {
      26        debugger;
@@ -449,7 +459,7 @@
 
 -- Running test case: Debugger.stepping.ForIn
 _expression_: setTimeout(entryForIn)
-STEPS: over, over, over, over, over, over, resume
+STEPS: over, over, over, over, over, over, over, resume
 PAUSED (debugger-statement)
 PAUSE AT entryForIn:41:5
      37    
@@ -471,6 +481,16 @@
      44    
 
 ACTION: step-over
+PAUSE AT entryForIn:42:10
+     38    function entryForIn() {
+     39        let o = {key1: 1, key2: 2};
+     40        debugger;
+ ->  41        for (|let property in o)
+     42            a();
+     43    }
+     44    
+
+ACTION: step-over
 PAUSE AT entryForIn:43:9
      39        let o = {key1: 1, key2: 2};
      40        debugger;
@@ -481,11 +501,11 @@
      45    function entryForOf() {
 
 ACTION: step-over
-PAUSE AT entryForIn:42:26
+PAUSE AT entryForIn:42:10
      38    function entryForIn() {
      39        let o = {key1: 1, key2: 2};
      40        debugger;
- ->  41        for (let property in |o)
+ ->  41        for (|let property in o)
      42            a();
      43    }
      44    
@@ -501,11 +521,11 @@
      45    function entryForOf() {
 
 ACTION: step-over
-PAUSE AT entryForIn:42:26
+PAUSE AT entryForIn:42:10
      38    function entryForIn() {
      39        let o = {key1: 1, key2: 2};
      40        debugger;
- ->  41        for (let property in |o)
+ ->  41        for (|let property in o)
      42            a();
      43    }
      44    
@@ -526,7 +546,7 @@
 
 -- Running test case: Debugger.stepping.ForIn
 _expression_: setTimeout(entryForOf)
-STEPS: over, over, over, over, over, over, resume
+STEPS: over, over, over, over, over, over, over, resume
 PAUSED (debugger-statement)
 PAUSE AT entryForOf:48:5
      44    
@@ -548,6 +568,16 @@
      51    
 
 ACTION: step-over
+PAUSE AT entryForOf:49:10
+     45    function entryForOf() {
+     46        let arr = [1, 2];
+     47        debugger;
+ ->  48        for (|let value of arr)
+     49            a();
+     50    }
+     51    
+
+ACTION: step-over
 PAUSE AT entryForOf:50:9
      46        let arr = [1, 2];
      47        debugger;
@@ -558,11 +588,11 @@
      52    function entryWhileBreakContinue() {
 
 ACTION: step-over
-PAUSE AT entryForOf:49:23
+PAUSE AT entryForOf:49:10
      45    function entryForOf() {
      46        let arr = [1, 2];
      47        debugger;
- ->  48        for (let value of |arr)
+ ->  48        for (|let value of arr)
      49            a();
      50    }
      51    
@@ -578,11 +608,11 @@
      52    function entryWhileBreakContinue() {
 
 ACTION: step-over
-PAUSE AT entryForOf:49:23
+PAUSE AT entryForOf:49:10
      45    function entryForOf() {
      46        let arr = [1, 2];
      47        debugger;
- ->  48        for (let value of |arr)
+ ->  48        for (|let value of arr)
      49            a();
      50    }
      51    
@@ -610,7 +640,7 @@
      52    function entryWhileBreakContinue() {
      53        let i = 0;
  ->  54        |debugger;
-     55        while (true) {
+     55        while (truthy) {
      56            ++i;
      57            if (i === 1)
 
@@ -619,7 +649,7 @@
      52    function entryWhileBreakContinue() {
      53        let i = 0;
      54        debugger;
- ->  55        while (|true) {
+ ->  55        while (|truthy) {
      56            ++i;
      57            if (i === 1)
      58                continue;
@@ -628,7 +658,7 @@
 PAUSE AT entryWhileBreakContinue:57:9
      53        let i = 0;
      54        debugger;
-     55        while (true) {
+     55        while (truthy) {
  ->  56            |++i;
      57            if (i === 1)
      58                continue;
@@ -637,7 +667,7 @@
 ACTION: step-over
 PAUSE AT entryWhileBreakContinue:58:13
      54        debugger;
-     55        while (true) {
+     55        while (truthy) {
      56            ++i;
  ->  57            if (|i === 1)
      58                continue;
@@ -646,7 +676,7 @@
 
 ACTION: step-over
 PAUSE AT entryWhileBreakContinue:59:13
-     55        while (true) {
+     55        while (truthy) {
      56            ++i;
      57            if (i === 1)
  ->  58                |continue;
@@ -659,7 +689,7 @@
      52    function entryWhileBreakContinue() {
      53        let i = 0;
      54        debugger;
- ->  55        while (|true) {
+ ->  55        while (|truthy) {
      56            ++i;
      57            if (i === 1)
      58                continue;
@@ -668,7 +698,7 @@
 PAUSE AT entryWhileBreakContinue:57:9
      53        let i = 0;
      54        debugger;
-     55        while (true) {
+     55        while (truthy) {
  ->  56            |++i;
      57            if (i === 1)
      58                continue;
@@ -677,7 +707,7 @@
 ACTION: step-over
 PAUSE AT entryWhileBreakContinue:58:13
      54        debugger;
-     55        while (true) {
+     55        while (truthy) {
      56            ++i;
  ->  57            if (|i === 1)
      58                continue;

Modified: trunk/LayoutTests/inspector/debugger/stepping/stepping-loops.html (207227 => 207228)


--- trunk/LayoutTests/inspector/debugger/stepping/stepping-loops.html	2016-10-12 18:43:19 UTC (rev 207227)
+++ trunk/LayoutTests/inspector/debugger/stepping/stepping-loops.html	2016-10-12 18:47:48 UTC (rev 207228)
@@ -4,10 +4,10 @@
 <script src=""
 <script src=""
 <script>
-function a() {
-    return 1;
-}
+var truthy = true;
+function a() { return 1; }
 
+
 function entryWhile() {
     let i = 2;
     debugger;
@@ -53,7 +53,7 @@
 function entryWhileBreakContinue() {
     let i = 0;
     debugger;
-    while (true) {
+    while (truthy) {
         ++i;
         if (i === 1)
             continue;
@@ -117,7 +117,8 @@
         _expression_: "setTimeout(entryTraditionalFor)",
         steps: [
             "over",
-                "over", // complete: let i = 0; i < 2
+                "over", // complete: let i = 0
+                "over", // complete: i < 2
                 "over", // complete: a()
                 "over", // complete: ++i
                 "over", // complete: i < 2 [i=1]
@@ -169,6 +170,7 @@
         _expression_: "setTimeout(entryForIn)",
         steps: [
             "over",
+                "over", // complete: (o)
                 "over", // complete: let property in o [key1]
                 "over", // complete: a()
                 "over", // complete: let property in o [key2]
@@ -184,6 +186,7 @@
         _expression_: "setTimeout(entryForOf)",
         steps: [
             "over",
+                "over", // complete (arr)
                 "over", // complete: let value of arr [1]
                 "over", // complete: a()
                 "over", // complete: let value of arr [2]

Modified: trunk/Source/_javascript_Core/ChangeLog (207227 => 207228)


--- trunk/Source/_javascript_Core/ChangeLog	2016-10-12 18:43:19 UTC (rev 207227)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-10-12 18:47:48 UTC (rev 207228)
@@ -1,3 +1,111 @@
+2016-10-12  Joseph Pecoraro  <pecor...@apple.com>
+
+        Emit DebugHooks uniformly with pause locations instead of having separate pause locations and op_debug emits
+        https://bugs.webkit.org/show_bug.cgi?id=162809
+
+        Reviewed by Geoffrey Garen.
+
+        Change how BytecodeGeneration emits debug hooks to be more consistent.
+        Previously most nodes individually generated their own debug hook
+        and we asserted that it matched a breakpoint location identified
+        by the parser. This could get out of sync, or nodes could forget to
+        emit debug hooks expected by the parser.
+        
+        With this change, we always check and emit a debug hook for any
+        node. The default behavior is for BytecodeGenerator::emitNode
+        to emit the debug hook when emitting the node itself. This covers
+        the majority of cases (statements).
+
+        There are a few exceptions where we continue to need to customize
+        emitting debug hooks:
+
+            1. Nodes with emitBytecodeInConditionContext
+                - non-_expression_ nodes customize how they emit their children
+                - constants conditions may emit nothing, but we had recorded a breakpoint location so emit a debug hook
+                - always emit one debug hook in case we recorded a breakpoint location, but avoid emitting multiple
+                  in nodes which may call up to the ExpressionNode::emitBytecodeInConditionContext base impl.
+            2. Specialized Debug Hooks
+                - such as hooks for Program start/end, debugger statements, etc.
+            3. Debug Hooks in for..of / for..in that don't correspond to re-emitting nodes
+                - such as pausing on the assignment _expression_ inside these loops
+
+        The majority of nodes no longer have custom emits.
+
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::BytecodeGenerator::emitNodeInTailPosition):
+        (JSC::BytecodeGenerator::emitNodeInConditionContext):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitDebugHook):
+        (JSC::BytecodeGenerator::emitEnumeration):
+        By default, when emitting a node check if we should also emit an op_debug for it.
+        This default DebugHook is WillExecuteStatement, which is a normal pause point.
+
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ConstantNode::emitBytecodeInConditionContext):
+        (JSC::LogicalNotNode::emitBytecodeInConditionContext):
+        (JSC::BinaryOpNode::emitBytecodeInConditionContext):
+        (JSC::LogicalOpNode::emitBytecodeInConditionContext):
+        The parser would have generated a pause location for these conditions
+        no matter what constant folding and re-writing these nodes may perform.
+        So, when emitting these nodes in condition context check if they need
+        emit their own debug hook.
+
+        (JSC::EmptyStatementNode::emitBytecode):
+        (JSC::ExprStatementNode::emitBytecode):
+        (JSC::DeclarationStatement::emitBytecode):
+        (JSC::IfElseNode::emitBytecode):
+        (JSC::DoWhileNode::emitBytecode):
+        (JSC::WhileNode::emitBytecode):
+        (JSC::ForNode::emitBytecode):
+        (JSC::ContinueNode::emitBytecode):
+        (JSC::BreakNode::emitBytecode):
+        (JSC::ReturnNode::emitBytecode):
+        (JSC::WithNode::emitBytecode):
+        (JSC::SwitchNode::emitBytecode):
+        (JSC::ThrowNode::emitBytecode):
+        No longer need to custom emit debug hooks. The default emitNode will handle these.
+
+        (JSC::ForInNode::emitBytecode):
+        Include extra debug hooks the user expects to return back to the assignment
+        _expression_ in the loop header before starting the body again. The same is done
+        for for..of with emitEnumeration.
+
+        * parser/ASTBuilder.h:
+        (JSC::ASTBuilder::createExportDefaultDeclaration):
+        (JSC::ASTBuilder::createExportLocalDeclaration):
+        These are no longer needed to fake-satisfy assertions. We never wanted to
+        emit debug hooks for these inner statements because the export statement
+        will already have the debug hooks.
+
+        (JSC::ASTBuilder::createForInLoop):
+        (JSC::ASTBuilder::createForOfLoop):
+        Include the correct location where the declaration starts.
+
+        (JSC::ASTBuilder::breakpointLocation):
+        Simplify to a general implementation for Node.
+
+        * parser/SyntaxChecker.h:
+        (JSC::SyntaxChecker::createForInLoop):
+        (JSC::SyntaxChecker::createForOfLoop):
+        Ignore the new extra parameter.
+
+        * parser/Nodes.h:
+        (JSC::Node::needsDebugHook):
+        (JSC::Node::setNeedsDebugHook):
+        (JSC::ExpressionNode::needsDebugHook): Deleted.
+        (JSC::ExpressionNode::setNeedsDebugHook): Deleted.
+        (JSC::StatementNode::isEmptyStatement): Deleted.
+        (JSC::StatementNode::needsDebugHook): Deleted.
+        (JSC::StatementNode::setNeedsDebugHook): Deleted.
+        Move debug hook logic into the base Node class.
+
+        (JSC::StatementNode::isDebuggerStatement):
+        Provide a way to distinguish a debugger statement.
+
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseForStatement):
+        Provide the location before the declaration starts.
+
 2016-10-12  Mark Lam  <mark....@apple.com>
 
         Array.prototype.slice should not modify frozen objects.

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (207227 => 207228)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2016-10-12 18:43:19 UTC (rev 207227)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2016-10-12 18:47:48 UTC (rev 207228)
@@ -3504,14 +3504,16 @@
 
 void BytecodeGenerator::emitDebugHook(StatementNode* statement)
 {
-    RELEASE_ASSERT(statement->needsDebugHook());
+    // DebuggerStatementNode will output its own special debug hook.
+    if (statement->isDebuggerStatement())
+        return;
+
     emitDebugHook(WillExecuteStatement, statement->position());
 }
 
-void BytecodeGenerator::emitDebugHook(ExpressionNode* expr, DebugHookType debugHookType)
+void BytecodeGenerator::emitDebugHook(ExpressionNode* expr)
 {
-    RELEASE_ASSERT(expr->needsDebugHook());
-    emitDebugHook(debugHookType, expr->position());
+    emitDebugHook(WillExecuteStatement, expr->position());
 }
 
 void BytecodeGenerator::emitWillLeaveCallFrameDebugHook()
@@ -4202,7 +4204,7 @@
         if (forLoopNode) {
             RELEASE_ASSERT(forLoopNode->isForOfNode());
             prepareLexicalScopeForNextForLoopIteration(forLoopNode, forLoopSymbolTable);
-            emitDebugHook(forLoopNode->expr(), WillExecuteStatement);
+            emitDebugHook(forLoopNode->lexpr());
         }
 
         {

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (207227 => 207228)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2016-10-12 18:43:19 UTC (rev 207227)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2016-10-12 18:47:48 UTC (rev 207228)
@@ -386,6 +386,8 @@
                 emitThrowExpressionTooDeepException();
                 return;
             }
+            if (UNLIKELY(n->needsDebugHook()))
+                emitDebugHook(n);
             n->emitBytecode(*this, dst);
         }
 
@@ -411,6 +413,8 @@
             ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount());
             if (UNLIKELY(!m_vm->isSafeToRecurse()))
                 return emitThrowExpressionTooDeepException();
+            if (UNLIKELY(n->needsDebugHook()))
+                emitDebugHook(n);
             return n->emitBytecode(*this, dst);
         }
 
@@ -430,7 +434,6 @@
                 emitThrowExpressionTooDeepException();
                 return;
             }
-
             n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMode);
         }
 
@@ -684,7 +687,7 @@
         void emitDebugHook(DebugHookType, const JSTextPosition&);
         void emitDebugHook(DebugHookType, unsigned line, unsigned charOffset, unsigned lineStart);
         void emitDebugHook(StatementNode*);
-        void emitDebugHook(ExpressionNode*, DebugHookType);
+        void emitDebugHook(ExpressionNode*);
         void emitWillLeaveCallFrameDebugHook();
 
         bool isInFinallyBlock() { return m_finallyDepth > 0; }

Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (207227 => 207228)


--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2016-10-12 18:43:19 UTC (rev 207227)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2016-10-12 18:47:48 UTC (rev 207228)
@@ -94,6 +94,12 @@
 void ConstantNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode)
 {
     TriState value = jsValue(generator).pureToBoolean();
+
+    if (UNLIKELY(needsDebugHook())) {
+        if (value != MixedTriState)
+            generator.emitDebugHook(this);
+    }
+
     if (value == MixedTriState)
         ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode);
     else if (value == TrueTriState && fallThroughMode == FallThroughMeansFalse)
@@ -1669,7 +1675,10 @@
 
 void LogicalNotNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode)
 {
-    // reverse the true and false targets
+    if (UNLIKELY(needsDebugHook()))
+        generator.emitDebugHook(this);
+
+    // Reverse the true and false targets.
     generator.emitNodeInConditionContext(expr(), falseTarget, trueTarget, invert(fallThroughMode));
 }
 
@@ -1799,6 +1808,11 @@
     ExpressionNode* branchExpression;
     tryFoldToBranch(generator, branchCondition, branchExpression);
 
+    if (UNLIKELY(needsDebugHook())) {
+        if (branchCondition != MixedTriState)
+            generator.emitDebugHook(this);
+    }
+
     if (branchCondition == MixedTriState)
         ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode);
     else if (branchCondition == TrueTriState)
@@ -2000,6 +2014,9 @@
 
 void LogicalOpNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode)
 {
+    if (UNLIKELY(needsDebugHook()))
+        generator.emitDebugHook(this);
+
     RefPtr<Label> afterExpr1 = generator.newLabel();
     if (m_operator == OpLogicalAnd)
         generator.emitNodeInConditionContext(m_expr1, afterExpr1.get(), falseTarget, FallThroughMeansTrue);
@@ -2376,9 +2393,9 @@
 
 // ------------------------------ EmptyStatementNode ---------------------------
 
-void EmptyStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
+void EmptyStatementNode::emitBytecode(BytecodeGenerator&, RegisterID*)
 {
-    generator.emitDebugHook(this);
+    RELEASE_ASSERT(needsDebugHook());
 }
 
 // ------------------------------ DebuggerStatementNode ---------------------------
@@ -2393,7 +2410,6 @@
 void ExprStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
     ASSERT(m_expr);
-    generator.emitDebugHook(this);
     generator.emitNode(dst, m_expr);
 }
 
@@ -2402,7 +2418,6 @@
 void DeclarationStatement::emitBytecode(BytecodeGenerator& generator, RegisterID*)
 {
     ASSERT(m_expr);
-    generator.emitDebugHook(this);
     generator.emitNode(m_expr);
 }
 
@@ -2490,8 +2505,6 @@
 
 void IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    generator.emitDebugHook(m_condition, WillExecuteStatement);
-    
     RefPtr<Label> beforeThen = generator.newLabel();
     RefPtr<Label> beforeElse = generator.newLabel();
     RefPtr<Label> afterElse = generator.newLabel();
@@ -2536,7 +2549,6 @@
     generator.emitNodeInTailPosition(dst, m_statement);
 
     generator.emitLabel(scope->continueTarget());
-    generator.emitDebugHook(m_expr, WillExecuteStatement);
     generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse);
 
     generator.emitLabel(scope->breakTarget());
@@ -2549,7 +2561,6 @@
     LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop);
     RefPtr<Label> topOfLoop = generator.newLabel();
 
-    generator.emitDebugHook(m_expr, WillExecuteStatement);
     generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansTrue);
 
     generator.emitLabel(topOfLoop.get());
@@ -2559,7 +2570,6 @@
     generator.emitNodeInTailPosition(dst, m_statement);
 
     generator.emitLabel(scope->continueTarget());
-    generator.emitDebugHook(m_expr, WillExecuteStatement);
 
     generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse);
 
@@ -2577,21 +2587,12 @@
     RegisterID* forLoopSymbolTable = nullptr;
     generator.pushLexicalScope(this, BytecodeGenerator::TDZCheckOptimization::Optimize, BytecodeGenerator::NestedScopeType::IsNested, &forLoopSymbolTable);
 
-    if (m_expr1 || m_expr2) {
-        ExpressionNode* firstExpr = m_expr1 ? m_expr1 : m_expr2;
-        generator.emitDebugHook(firstExpr, WillExecuteStatement);
-    }
-
-    if (m_expr1) {
-        generator.emitDebugHook(m_expr1, WillExecuteExpression);
+    if (m_expr1)
         generator.emitNode(generator.ignoredResult(), m_expr1);
-    }
 
     RefPtr<Label> topOfLoop = generator.newLabel();
-    if (m_expr2) {
-        generator.emitDebugHook(m_expr2, WillExecuteExpression);
+    if (m_expr2)
         generator.emitNodeInConditionContext(m_expr2, topOfLoop.get(), scope->breakTarget(), FallThroughMeansTrue);
-    }
 
     generator.emitLabel(topOfLoop.get());
     generator.emitLoopHint();
@@ -2601,15 +2602,12 @@
 
     generator.emitLabel(scope->continueTarget());
     generator.prepareLexicalScopeForNextForLoopIteration(this, forLoopSymbolTable);
-    if (m_expr3) {
-        generator.emitDebugHook(m_expr3, WillExecuteStatement);
+    if (m_expr3)
         generator.emitNode(generator.ignoredResult(), m_expr3);
-    }
 
-    if (m_expr2) {
-        generator.emitDebugHook(m_expr2, WillExecuteStatement);
+    if (m_expr2)
         generator.emitNodeInConditionContext(m_expr2, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse);
-    } else
+    else
         generator.emitJump(topOfLoop.get());
 
     generator.emitLabel(scope->breakTarget());
@@ -2738,8 +2736,6 @@
     RegisterID* forLoopSymbolTable = nullptr;
     generator.pushLexicalScope(this, BytecodeGenerator::TDZCheckOptimization::Optimize, BytecodeGenerator::NestedScopeType::IsNested, &forLoopSymbolTable);
 
-    generator.emitDebugHook(m_expr, WillExecuteStatement);
-
     if (m_lexpr->isAssignResolveNode())
         generator.emitNode(generator.ignoredResult(), m_lexpr);
 
@@ -2751,6 +2747,9 @@
     RefPtr<RegisterID> local = this->tryGetBoundLocal(generator);
     RefPtr<RegisterID> enumeratorIndex;
 
+    // Pause at the assignment _expression_ for each for..in iteration.
+    generator.emitDebugHook(m_lexpr);
+
     int profilerStartOffset = m_statement->startOffset();
     int profilerEndOffset = m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0);
 
@@ -2788,7 +2787,7 @@
         generator.emitLabel(scope->continueTarget());
         generator.prepareLexicalScopeForNextForLoopIteration(this, forLoopSymbolTable);
         generator.emitInc(i.get());
-        generator.emitDebugHook(m_expr, WillExecuteStatement);
+        generator.emitDebugHook(m_lexpr); // Pause at the assignment _expression_ for each for..in iteration.
         generator.emitJump(loopStart.get());
 
         generator.emitLabel(scope->breakTarget());
@@ -2828,7 +2827,7 @@
         generator.prepareLexicalScopeForNextForLoopIteration(this, forLoopSymbolTable);
         generator.emitInc(enumeratorIndex.get());
         generator.emitEnumeratorStructurePropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get());
-        generator.emitDebugHook(m_expr, WillExecuteStatement);
+        generator.emitDebugHook(m_lexpr); // Pause at the assignment _expression_ for each for..in iteration.
         generator.emitJump(loopStart.get());
         
         generator.emitLabel(scope->breakTarget());
@@ -2865,7 +2864,7 @@
         generator.prepareLexicalScopeForNextForLoopIteration(this, forLoopSymbolTable);
         generator.emitInc(enumeratorIndex.get());
         generator.emitEnumeratorGenericPropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get());
-        generator.emitDebugHook(m_expr, WillExecuteStatement);
+        generator.emitDebugHook(m_lexpr); // Pause at the assignment _expression_ for each for..in iteration.
         generator.emitJump(loopStart.get());
 
         generator.emitLabel(scope->breakTarget());
@@ -2962,8 +2961,6 @@
 
 void ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
 {
-    generator.emitDebugHook(this);
-    
     LabelScopePtr scope = generator.continueTarget(m_ident);
     ASSERT(scope);
 
@@ -2991,8 +2988,6 @@
 
 void BreakNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
 {
-    generator.emitDebugHook(this);
-    
     LabelScopePtr scope = generator.breakTarget(m_ident);
     ASSERT(scope);
 
@@ -3006,8 +3001,6 @@
 
 void ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    generator.emitDebugHook(this);
-
     ASSERT(generator.codeType() == FunctionCode);
 
     if (dst == generator.ignoredResult())
@@ -3034,8 +3027,6 @@
 
 void WithNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    generator.emitDebugHook(m_expr, WillExecuteStatement);
-
     RefPtr<RegisterID> scope = generator.emitNode(m_expr);
     generator.emitExpressionInfo(m_divot, m_divot - m_expressionLength, m_divot);
     generator.emitPushWithScope(scope.get());
@@ -3209,8 +3200,6 @@
 
 void SwitchNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    generator.emitDebugHook(m_expr, WillExecuteStatement);
-    
     LabelScopePtr scope = generator.newLabelScope(LabelScope::Switch);
 
     RefPtr<RegisterID> r0 = generator.emitNode(m_expr);
@@ -3239,8 +3228,6 @@
 
 void ThrowNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    generator.emitDebugHook(this);
-
     if (dst == generator.ignoredResult())
         dst = 0;
     RefPtr<RegisterID> expr = generator.emitNode(m_expr);

Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (207227 => 207228)


--- trunk/Source/_javascript_Core/parser/ASTBuilder.h	2016-10-12 18:43:19 UTC (rev 207227)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h	2016-10-12 18:47:48 UTC (rev 207228)
@@ -559,7 +559,7 @@
         return result;
     }
 
-    StatementNode* createForInLoop(const JSTokenLocation& location, ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment& lexicalVariables)
+    StatementNode* createForInLoop(const JSTokenLocation& location, ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, const JSTokenLocation&, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment& lexicalVariables)
     {
         ForInNode* result = new (m_parserArena) ForInNode(location, lhs, iter, statements, lexicalVariables);
         result->setLoc(start, end, location.startOffset, location.lineStartOffset);
@@ -567,13 +567,13 @@
         return result;
     }
     
-    StatementNode* createForInLoop(const JSTokenLocation& location, DestructuringPatternNode* pattern, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment& lexicalVariables)
+    StatementNode* createForInLoop(const JSTokenLocation& location, DestructuringPatternNode* pattern, ExpressionNode* iter, StatementNode* statements, const JSTokenLocation& declLocation, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment& lexicalVariables)
     {
-        auto lexpr = new (m_parserArena) DestructuringAssignmentNode(location, pattern, 0);
-        return createForInLoop(location, lexpr, iter, statements, eStart, eDivot, eEnd, start, end, lexicalVariables);
+        auto lexpr = new (m_parserArena) DestructuringAssignmentNode(declLocation, pattern, nullptr);
+        return createForInLoop(location, lexpr, iter, statements, declLocation, eStart, eDivot, eEnd, start, end, lexicalVariables);
     }
     
-    StatementNode* createForOfLoop(const JSTokenLocation& location, ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment& lexicalVariables)
+    StatementNode* createForOfLoop(const JSTokenLocation& location, ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, const JSTokenLocation&, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment& lexicalVariables)
     {
         ForOfNode* result = new (m_parserArena) ForOfNode(location, lhs, iter, statements, lexicalVariables);
         result->setLoc(start, end, location.startOffset, location.lineStartOffset);
@@ -581,10 +581,10 @@
         return result;
     }
     
-    StatementNode* createForOfLoop(const JSTokenLocation& location, DestructuringPatternNode* pattern, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment& lexicalVariables)
+    StatementNode* createForOfLoop(const JSTokenLocation& location, DestructuringPatternNode* pattern, ExpressionNode* iter, StatementNode* statements, const JSTokenLocation& declLocation, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment& lexicalVariables)
     {
-        auto lexpr = new (m_parserArena) DestructuringAssignmentNode(location, pattern, 0);
-        return createForOfLoop(location, lexpr, iter, statements, eStart, eDivot, eEnd, start, end, lexicalVariables);
+        auto lexpr = new (m_parserArena) DestructuringAssignmentNode(declLocation, pattern, nullptr);
+        return createForOfLoop(location, lexpr, iter, statements, declLocation, eStart, eDivot, eEnd, start, end, lexicalVariables);
     }
 
     bool isBindingNode(const DestructuringPattern& pattern)
@@ -752,21 +752,11 @@
 
     StatementNode* createExportDefaultDeclaration(const JSTokenLocation& location, StatementNode* declaration, const Identifier& localName)
     {
-        // We need to mark the inner statement as needing a debug hook (so that when the statement is generated we don't
-        // assert when generating an op_debug for it) without recording a breakpoint location because the export statement
-        // itself will get the breakpoint location. This will be eliminated by:
-        // <https://webkit.org/b/162809> Emit DebugHooks uniformly with pause locations instead of having separate pause locations and op_debug emits
-        declaration->setNeedsDebugHook();
         return new (m_parserArena) ExportDefaultDeclarationNode(location, declaration, localName);
     }
 
     StatementNode* createExportLocalDeclaration(const JSTokenLocation& location, StatementNode* declaration)
     {
-        // We need to mark the inner statement as needing a debug hook (so that when the statement is generated we don't
-        // assert when generating an op_debug for it) without recording a breakpoint location because the export statement
-        // itself will get the breakpoint location. This will be eliminated by:
-        // <https://webkit.org/b/162809> Emit DebugHooks uniformly with pause locations instead of having separate pause locations and op_debug emits
-        declaration->setNeedsDebugHook();
         return new (m_parserArena) ExportLocalDeclarationNode(location, declaration);
     }
 
@@ -983,18 +973,12 @@
         node->setStartOffset(offset);
     }
 
-    JSTextPosition breakpointLocation(StatementNode* statement)
+    JSTextPosition breakpointLocation(Node* node)
     {
-        statement->setNeedsDebugHook();
-        return statement->position();
+        node->setNeedsDebugHook();
+        return node->position();
     }
 
-    JSTextPosition breakpointLocation(ExpressionNode* expr)
-    {
-        expr->setNeedsDebugHook();
-        return expr->position();
-    }
-
     void propagateArgumentsUse() { usesArguments(); }
     
 private:

Modified: trunk/Source/_javascript_Core/parser/Nodes.h (207227 => 207228)


--- trunk/Source/_javascript_Core/parser/Nodes.h	2016-10-12 18:43:19 UTC (rev 207227)
+++ trunk/Source/_javascript_Core/parser/Nodes.h	2016-10-12 18:47:48 UTC (rev 207228)
@@ -145,9 +145,13 @@
         void setEndOffset(int offset) { m_endOffset = offset; }
         void setStartOffset(int offset) { m_position.offset = offset; }
 
+        bool needsDebugHook() const { return m_needsDebugHook; }
+        void setNeedsDebugHook() { m_needsDebugHook = true; }
+
     protected:
         JSTextPosition m_position;
         int m_endOffset;
+        bool m_needsDebugHook { false };
     };
 
     class ExpressionNode : public Node {
@@ -191,12 +195,8 @@
 
         ResultType resultDescriptor() const { return m_resultType; }
 
-        bool needsDebugHook() { return m_needsDebugHook; }
-        void setNeedsDebugHook() { m_needsDebugHook = true; }
-
     private:
         ResultType m_resultType;
-        bool m_needsDebugHook { false };
     };
 
     class StatementNode : public Node {
@@ -213,6 +213,7 @@
         void setNext(StatementNode* next) { m_next = next; }
 
         virtual bool isEmptyStatement() const { return false; }
+        virtual bool isDebuggerStatement() const { return false; }
         virtual bool isFunctionNode() const { return false; }
         virtual bool isReturnNode() const { return false; }
         virtual bool isExprStatement() const { return false; }
@@ -224,13 +225,9 @@
         virtual bool isModuleDeclarationNode() const { return false; }
         virtual bool isForOfNode() const { return false; }
 
-        bool needsDebugHook() { return m_needsDebugHook; }
-        void setNeedsDebugHook() { m_needsDebugHook = true; }
-
     protected:
         StatementNode* m_next;
         int m_lastLine;
-        bool m_needsDebugHook { false };
     };
 
     class VariableEnvironmentNode : public ParserArenaDeletable {
@@ -1366,6 +1363,8 @@
     class DebuggerStatementNode : public StatementNode {
     public:
         DebuggerStatementNode(const JSTokenLocation&);
+
+        bool isDebuggerStatement() const override { return true; }
         
     private:
         void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
@@ -1473,6 +1472,7 @@
 
         EnumerationNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*, VariableEnvironment&);
 
+        ExpressionNode* lexpr() const { return m_lexpr; }
         ExpressionNode* expr() const { return m_expr; }
 
     protected:

Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (207227 => 207228)


--- trunk/Source/_javascript_Core/parser/Parser.cpp	2016-10-12 18:43:19 UTC (rev 207227)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp	2016-10-12 18:47:48 UTC (rev 207228)
@@ -1186,6 +1186,7 @@
     handleProductionOrFail(OPENPAREN, "(", "start", "for-loop header");
     int nonLHSCount = m_parserState.nonLHSCount;
     int declarations = 0;
+    JSTokenLocation declLocation(tokenLocation());
     JSTextPosition declsStart;
     JSTextPosition declsEnd;
     TreeExpression decls = 0;
@@ -1280,12 +1281,12 @@
         gatherLexicalVariablesIfNecessary();
         TreeStatement result;
         if (isOfEnumeration)
-            result = context.createForOfLoop(location, forInTarget, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine, *lexicalVariables);
+            result = context.createForOfLoop(location, forInTarget, expr, statement, declLocation, declsStart, inLocation, exprEnd, startLine, endLine, *lexicalVariables);
         else {
             if (isVarDeclaraton && forInInitializer)
-                result = context.createForInLoop(location, decls, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine, *lexicalVariables);
+                result = context.createForInLoop(location, decls, expr, statement, declLocation, declsStart, inLocation, exprEnd, startLine, endLine, *lexicalVariables);
             else
-                result = context.createForInLoop(location, forInTarget, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine, *lexicalVariables);
+                result = context.createForInLoop(location, forInTarget, expr, statement, declLocation, declsStart, inLocation, exprEnd, startLine, endLine, *lexicalVariables);
         }
         popLexicalScopeIfNecessary();
         return result;
@@ -1372,17 +1373,17 @@
     if (pattern) {
         ASSERT(!decls);
         if (isOfEnumeration)
-            result = context.createForOfLoop(location, pattern, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
+            result = context.createForOfLoop(location, pattern, expr, statement, declLocation, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
         else 
-            result = context.createForInLoop(location, pattern, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
+            result = context.createForInLoop(location, pattern, expr, statement, declLocation, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
 
         popLexicalScopeIfNecessary();
         return result;
     }
     if (isOfEnumeration)
-        result = context.createForOfLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
+        result = context.createForOfLoop(location, decls, expr, statement, declLocation, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
     else
-        result = context.createForInLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
+        result = context.createForInLoop(location, decls, expr, statement, declLocation, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
     popLexicalScopeIfNecessary();
     return result;
 }

Modified: trunk/Source/_javascript_Core/parser/SyntaxChecker.h (207227 => 207228)


--- trunk/Source/_javascript_Core/parser/SyntaxChecker.h	2016-10-12 18:43:19 UTC (rev 207227)
+++ trunk/Source/_javascript_Core/parser/SyntaxChecker.h	2016-10-12 18:47:48 UTC (rev 207228)
@@ -238,8 +238,8 @@
     int createIfStatement(const JSTokenLocation&, int, int, int, int) { return StatementResult; }
     int createIfStatement(const JSTokenLocation&, int, int, int, int, int) { return StatementResult; }
     int createForLoop(const JSTokenLocation&, int, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
-    int createForInLoop(const JSTokenLocation&, int, int, int, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
-    int createForOfLoop(const JSTokenLocation&, int, int, int, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
+    int createForInLoop(const JSTokenLocation&, int, int, int, const JSTokenLocation&, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
+    int createForOfLoop(const JSTokenLocation&, int, int, int, const JSTokenLocation&, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
     int createEmptyStatement(const JSTokenLocation&) { return StatementResult; }
     int createDeclarationStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }
     int createReturnStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }

Modified: trunk/Source/WebInspectorUI/ChangeLog (207227 => 207228)


--- trunk/Source/WebInspectorUI/ChangeLog	2016-10-12 18:43:19 UTC (rev 207227)
+++ trunk/Source/WebInspectorUI/ChangeLog	2016-10-12 18:47:48 UTC (rev 207228)
@@ -1,5 +1,18 @@
 2016-10-12  Joseph Pecoraro  <pecor...@apple.com>
 
+        Emit DebugHooks uniformly with pause locations instead of having separate pause locations and op_debug emits
+        https://bugs.webkit.org/show_bug.cgi?id=162809
+
+        Reviewed by Geoffrey Garen.
+
+        * UserInterface/Views/SourceCodeTextEditor.js:
+        (WebInspector.SourceCodeTextEditor.prototype.textEditorExecutionHighlightRange):
+        When pausing on the variable assignment inside for..of and for..in don't just
+        highlight "var foo" but include the right hand side "var foo in ..." or
+        "var foo of ...".
+
+2016-10-12  Joseph Pecoraro  <pecor...@apple.com>
+
         Web Inspector: Whole program sometimes highlighted instead of just first statement
         https://bugs.webkit.org/show_bug.cgi?id=163300
         <rdar://problem/28723162>

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js (207227 => 207228)


--- trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js	2016-10-12 18:43:19 UTC (rev 207227)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js	2016-10-12 18:47:48 UTC (rev 207228)
@@ -1236,6 +1236,7 @@
 
             // Find a node starting at this offset.
             // Avoid highlighting the entire program if this is the start of the first statement.
+            // Special case the assignment _expression_ inside of a for..of and for..in to highlight a larger range.
             for (let node of nodes) {
                 let startOffset = node.range[0];
                 if (startOffset === offset && node.type !== WebInspector.ScriptSyntaxTree.NodeType.Program) {
@@ -1242,6 +1243,12 @@
                     callback(convertRangeOffsetsToSourceCodeOffsets(node.range));
                     return;
                 }
+                if (node.type === WebInspector.ScriptSyntaxTree.NodeType.ForInStatement || node.type === WebInspector.ScriptSyntaxTree.NodeType.ForOfStatement) {
+                    if (node.left.range[0] === offset) {
+                        callback(convertRangeOffsetsToSourceCodeOffsets([node.left.range[0], node.right.range[1]]));
+                        return;
+                    }
+                }
                 if (startOffset > offset)
                     break;
             }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to