Changeset 207228 in webkit


Ignore:
Timestamp:
Oct 12, 2016 11:47:48 AM (8 years ago)
Author:
Joseph Pecoraro
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/JavaScriptCore:

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.

Location:
trunk
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r207217 r207228  
     12016-10-12  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Emit DebugHooks uniformly with pause locations instead of having separate pause locations and op_debug emits
     4        https://bugs.webkit.org/show_bug.cgi?id=162809
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        * inspector/debugger/stepping/stepping-control-flow-expected.txt:
     9        * inspector/debugger/stepping/stepping-control-flow.html:
     10        Add new tests for stepping through conditional expressions with constants,
     11        logical operations, binary operations, and unary negations.
     12
     13        * inspector/debugger/stepping/stepping-loops-expected.txt:
     14        * inspector/debugger/stepping/stepping-loops.html:
     15        Update tests for changes in stepping behavior in for loops.
     16
    1172016-10-12  Carlos Alberto Lopez Perez  <clopez@igalia.com>
    218
  • trunk/LayoutTests/inspector/debugger/stepping/stepping-control-flow-expected.txt

    r206652 r207228  
    88PAUSED (debugger-statement)
    99PAUSE AT entryIfSingleStatement:16:5
    10      12    }
     10     12   
    1111     13   
    1212     14    function entryIfSingleStatement() {
    1313 ->  15        |debugger;
    14      16        if (true)
     14     16        if (truthy)
    1515     17            a();
    16      18        if (false)
     16     18        if (falsey)
    1717
    1818ACTION: step-over
     
    2121     14    function entryIfSingleStatement() {
    2222     15        debugger;
    23  ->  16        if (|true)
     23 ->  16        if (|truthy)
    2424     17            a();
    25      18        if (false)
     25     18        if (falsey)
    2626     19            a();
    2727
     
    3030     14    function entryIfSingleStatement() {
    3131     15        debugger;
    32      16        if (true)
     32     16        if (truthy)
    3333 ->  17            |a();
    34      18        if (false)
     34     18        if (falsey)
    3535     19            a();
    3636     20    }
     
    3939PAUSE AT entryIfSingleStatement:19:9
    4040     15        debugger;
    41      16        if (true)
     41     16        if (truthy)
    4242     17            a();
    43  ->  18        if (|false)
     43 ->  18        if (|falsey)
    4444     19            a();
    4545     20    }
     
    4949PAUSE AT entryIfSingleStatement:21:2
    5050     17            a();
    51      18        if (false)
     51     18        if (falsey)
    5252     19            a();
    5353 ->  20    }|
     
    6969     22    function entryIfMultiStatement() {
    7070 ->  23        |debugger;
    71      24        if (true) {
     71     24        if (truthy) {
    7272     25            a();
    7373     26            a();
     
    7878     22    function entryIfMultiStatement() {
    7979     23        debugger;
    80  ->  24        if (|true) {
     80 ->  24        if (|truthy) {
    8181     25            a();
    8282     26            a();
     
    8787     22    function entryIfMultiStatement() {
    8888     23        debugger;
    89      24        if (true) {
     89     24        if (truthy) {
    9090 ->  25            |a();
    9191     26            a();
    9292     27        }
    93      28        if (false) {
     93     28        if (falsey) {
    9494
    9595ACTION: step-over
    9696PAUSE AT entryIfMultiStatement:27:9
    9797     23        debugger;
    98      24        if (true) {
     98     24        if (truthy) {
    9999     25            a();
    100100 ->  26            |a();
    101101     27        }
    102      28        if (false) {
     102     28        if (falsey) {
    103103     29            a();
    104104
     
    108108     26            a();
    109109     27        }
    110  ->  28        if (|false) {
     110 ->  28        if (|falsey) {
    111111     29            a();
    112112     30            a();
     
    136136     34    function entryIfElse() {
    137137 ->  35        |debugger;
    138      36        if (true)
     138     36        if (truthy)
    139139     37            a();
    140140     38        else
     
    145145     34    function entryIfElse() {
    146146     35        debugger;
    147  ->  36        if (|true)
     147 ->  36        if (|truthy)
    148148     37            a();
    149149     38        else
     
    154154     34    function entryIfElse() {
    155155     35        debugger;
    156      36        if (true)
     156     36        if (truthy)
    157157 ->  37            |a();
    158158     38        else
    159159     39            a();
    160      40        if (false)
     160     40        if (falsey)
    161161
    162162ACTION: step-over
     
    165165     38        else
    166166     39            a();
    167  ->  40        if (|false)
     167 ->  40        if (|falsey)
    168168     41            a();
    169169     42        else
     
    172172ACTION: step-over
    173173PAUSE AT entryIfElse:44:9
    174      40        if (false)
     174     40        if (falsey)
    175175     41            a();
    176176     42        else
     
    203203     46    function entryIfElseChain() {
    204204 ->  47        |debugger;
    205      48        if (false)
     205     48        if (falsey)
    206206     49            a();
    207      50        else if (true)
     207     50        else if (truthy)
    208208
    209209ACTION: step-over
     
    212212     46    function entryIfElseChain() {
    213213     47        debugger;
    214  ->  48        if (|false)
     214 ->  48        if (|falsey)
    215215     49            a();
    216      50        else if (true)
     216     50        else if (truthy)
    217217     51            a();
    218218
     
    220220PAUSE AT entryIfElseChain:51:14
    221221     47        debugger;
    222      48        if (false)
     222     48        if (falsey)
    223223     49            a();
    224  ->  50        else if (|true)
     224 ->  50        else if (|truthy)
    225225     51            a();
    226226     52        else
     
    229229ACTION: step-over
    230230PAUSE AT entryIfElseChain:52:9
    231      48        if (false)
     231     48        if (falsey)
    232232     49            a();
    233      50        else if (true)
     233     50        else if (truthy)
    234234 ->  51            |a();
    235235     52        else
     
    242242     53            a();
    243243     54   
    244  ->  55        if (|false)
     244 ->  55        if (|falsey)
    245245     56            a();
    246      57        else if (false)
     246     57        else if (falsey)
    247247     58            a();
    248248
     
    250250PAUSE AT entryIfElseChain:58:14
    251251     54   
    252      55        if (false)
     252     55        if (falsey)
    253253     56            a();
    254  ->  57        else if (|false)
     254 ->  57        else if (|falsey)
    255255     58            a();
    256256     59        else
     
    259259ACTION: step-over
    260260PAUSE AT entryIfElseChain:61:9
    261      57        else if (false)
     261     57        else if (falsey)
    262262     58            a();
    263263     59        else
     
    322322     68   
    323323     69    function entryTernary() {
    324      70        let t = () => true;
     324     70        let t = () => truthy;
    325325
    326326ACTION: resume
     
    352352
    353353ACTION: step-in
    354 PAUSE AT a:8:5
    355       4    <script src="../resources/log-pause-location.js"></script>
    356       5    <script>
    357       6    function a() {
    358  ->   7        |return 1;
    359       8    }
    360       9   
    361      10    function b() {
     354PAUSE AT a:11:16
     355      7    var value = 1;
     356      8    var truthy = true;
     357      9    var falsey = false;
     358 ->  10    function a() { |return value; }
     359     11    function b() { return value; }
     360     12   
     361     13   
    362362
    363363ACTION: step-out
     
    372372
    373373ACTION: step-in
    374 PAUSE AT a:8:5
    375       4    <script src="../resources/log-pause-location.js"></script>
    376       5    <script>
    377       6    function a() {
    378  ->   7        |return 1;
    379       8    }
    380       9   
    381      10    function b() {
     374PAUSE AT a:11:16
     375      7    var value = 1;
     376      8    var truthy = true;
     377      9    var falsey = false;
     378 ->  10    function a() { |return value; }
     379     11    function b() { return value; }
     380     12   
     381     13   
    382382
    383383ACTION: step-out
     
    399399     68   
    400400     69    function entryTernary() {
    401      70        let t = () => true;
     401     70        let t = () => truthy;
    402402
    403403ACTION: resume
     
    411411PAUSE AT entryTernary:73:5
    412412     69    function entryTernary() {
    413      70        let t = () => true;
    414      71        let f = () => false;
     413     70        let t = () => truthy;
     414     71        let f = () => falsey;
    415415 ->  72        |debugger;
    416416     73        let x = t() ? a() : b();
     
    420420ACTION: step-over
    421421PAUSE AT entryTernary:74:5
    422      70        let t = () => true;
    423      71        let f = () => false;
     422     70        let t = () => truthy;
     423     71        let f = () => falsey;
    424424     72        debugger;
    425425 ->  73        |let x = t() ? a() : b();
     
    430430ACTION: step-over
    431431PAUSE AT entryTernary:75:5
    432      71        let f = () => false;
     432     71        let f = () => falsey;
    433433     72        debugger;
    434434     73        let x = t() ? a() : b();
     
    436436     75    }
    437437     76   
    438      77    // ---------
     438     77    function entryIfConstantBranch() {
    439439
    440440ACTION: step-over
     
    445445 ->  75    }|
    446446     76   
    447      77    // ---------
    448      78   
     447     77    function entryIfConstantBranch() {
     448     78        debugger;
    449449
    450450ACTION: resume
     
    458458PAUSE AT entryTernary:73:5
    459459     69    function entryTernary() {
    460      70        let t = () => true;
    461      71        let f = () => false;
     460     70        let t = () => truthy;
     461     71        let f = () => falsey;
    462462 ->  72        |debugger;
    463463     73        let x = t() ? a() : b();
     
    467467ACTION: step-over
    468468PAUSE AT entryTernary:74:5
    469      70        let t = () => true;
    470      71        let f = () => false;
     469     70        let t = () => truthy;
     470     71        let f = () => falsey;
    471471     72        debugger;
    472472 ->  73        |let x = t() ? a() : b();
     
    480480     68   
    481481     69    function entryTernary() {
    482  ->  70        let t = () => |true;
    483      71        let f = () => false;
     482 ->  70        let t = () => |truthy;
     483     71        let f = () => falsey;
    484484     72        debugger;
    485485     73        let x = t() ? a() : b();
     
    487487ACTION: step-out
    488488PAUSE AT entryTernary:74:19
    489      70        let t = () => true;
    490      71        let f = () => false;
     489     70        let t = () => truthy;
     490     71        let f = () => falsey;
    491491     72        debugger;
    492492 ->  73        let x = t() ? |a() : b();
     
    496496
    497497ACTION: step-in
    498 PAUSE AT a:8:5
    499       4    <script src="../resources/log-pause-location.js"></script>
    500       5    <script>
    501       6    function a() {
    502  ->   7        |return 1;
    503       8    }
    504       9   
    505      10    function b() {
     498PAUSE AT a:11:16
     499      7    var value = 1;
     500      8    var truthy = true;
     501      9    var falsey = false;
     502 ->  10    function a() { |return value; }
     503     11    function b() { return value; }
     504     12   
     505     13   
    506506
    507507ACTION: step-out
    508508PAUSE AT entryTernary:75:5
    509      71        let f = () => false;
     509     71        let f = () => falsey;
    510510     72        debugger;
    511511     73        let x = t() ? a() : b();
     
    513513     75    }
    514514     76   
    515      77    // ---------
     515     77    function entryIfConstantBranch() {
    516516
    517517ACTION: step-in
     
    519519     68   
    520520     69    function entryTernary() {
    521      70        let t = () => true;
    522  ->  71        let f = () => |false;
     521     70        let t = () => truthy;
     522 ->  71        let f = () => |falsey;
    523523     72        debugger;
    524524     73        let x = t() ? a() : b();
     
    527527ACTION: step-out
    528528PAUSE AT entryTernary:75:25
    529      71        let f = () => false;
     529     71        let f = () => falsey;
    530530     72        debugger;
    531531     73        let x = t() ? a() : b();
     
    533533     75    }
    534534     76   
    535      77    // ---------
    536 
    537 ACTION: step-in
    538 PAUSE AT b:12:5
    539       8    }
    540       9   
    541      10    function b() {
    542  ->  11        |return 2;
    543      12    }
     535     77    function entryIfConstantBranch() {
     536
     537ACTION: step-in
     538PAUSE AT b:12:16
     539      8    var truthy = true;
     540      9    var falsey = false;
     541     10    function a() { return value; }
     542 ->  11    function b() { |return value; }
     543     12   
    544544     13   
    545545     14    function entryIfSingleStatement() {
     
    552552 ->  75    }|
    553553     76   
    554      77    // ---------
    555      78   
    556 
    557 ACTION: resume
    558 RESUMED
    559 PASS: Should have used all steps.
    560 
     554     77    function entryIfConstantBranch() {
     555     78        debugger;
     556
     557ACTION: resume
     558RESUMED
     559PASS: Should have used all steps.
     560
     561-- Running test case: Debugger.stepping.ConstantBranch
     562EXPRESSION: setTimeout(entryIfConstantBranch)
     563STEPS: over, over, over, over, over, over, resume
     564PAUSED (debugger-statement)
     565PAUSE AT entryIfConstantBranch:79:5
     566     75    }
     567     76   
     568     77    function entryIfConstantBranch() {
     569 ->  78        |debugger;
     570     79        if (true)
     571     80            a();
     572     81        if (false)
     573
     574ACTION: step-over
     575PAUSE AT entryIfConstantBranch:80:9
     576     76   
     577     77    function entryIfConstantBranch() {
     578     78        debugger;
     579 ->  79        if (|true)
     580     80            a();
     581     81        if (false)
     582     82            a();
     583
     584ACTION: step-over
     585PAUSE AT entryIfConstantBranch:81:9
     586     77    function entryIfConstantBranch() {
     587     78        debugger;
     588     79        if (true)
     589 ->  80            |a();
     590     81        if (false)
     591     82            a();
     592     83        if (0)
     593
     594ACTION: step-over
     595PAUSE AT entryIfConstantBranch:82:9
     596     78        debugger;
     597     79        if (true)
     598     80            a();
     599 ->  81        if (|false)
     600     82            a();
     601     83        if (0)
     602     84            a();
     603
     604ACTION: step-over
     605PAUSE AT entryIfConstantBranch:84:9
     606     80            a();
     607     81        if (false)
     608     82            a();
     609 ->  83        if (|0)
     610     84            a();
     611     85        if (null)
     612     86            a();
     613
     614ACTION: step-over
     615PAUSE AT entryIfConstantBranch:86:9
     616     82            a();
     617     83        if (0)
     618     84            a();
     619 ->  85        if (|null)
     620     86            a();
     621     87    }
     622     88   
     623
     624ACTION: step-over
     625PAUSE AT entryIfConstantBranch:88:2
     626     84            a();
     627     85        if (null)
     628     86            a();
     629 ->  87    }|
     630     88   
     631     89    function entryIfWithLogicalOperation() {
     632     90        debugger;
     633
     634ACTION: resume
     635RESUMED
     636PASS: Should have used all steps.
     637
     638-- Running test case: Debugger.stepping.IfWithLogicalOperation
     639EXPRESSION: setTimeout(entryIfWithLogicalOperation)
     640STEPS: over, in, out, in, out, over, resume
     641PAUSED (debugger-statement)
     642PAUSE AT entryIfWithLogicalOperation:91:5
     643     87    }
     644     88   
     645     89    function entryIfWithLogicalOperation() {
     646 ->  90        |debugger;
     647     91        if (true && a() && a())
     648     92            b();
     649     93    }
     650
     651ACTION: step-over
     652PAUSE AT entryIfWithLogicalOperation:92:9
     653     88   
     654     89    function entryIfWithLogicalOperation() {
     655     90        debugger;
     656 ->  91        if (|true && a() && a())
     657     92            b();
     658     93    }
     659     94   
     660
     661ACTION: step-in
     662PAUSE AT a:11:16
     663      7    var value = 1;
     664      8    var truthy = true;
     665      9    var falsey = false;
     666 ->  10    function a() { |return value; }
     667     11    function b() { return value; }
     668     12   
     669     13   
     670
     671ACTION: step-out
     672PAUSE AT entryIfWithLogicalOperation:92:24
     673     88   
     674     89    function entryIfWithLogicalOperation() {
     675     90        debugger;
     676 ->  91        if (true && a() && |a())
     677     92            b();
     678     93    }
     679     94   
     680
     681ACTION: step-in
     682PAUSE AT a:11:16
     683      7    var value = 1;
     684      8    var truthy = true;
     685      9    var falsey = false;
     686 ->  10    function a() { |return value; }
     687     11    function b() { return value; }
     688     12   
     689     13   
     690
     691ACTION: step-out
     692PAUSE AT entryIfWithLogicalOperation:93:9
     693     89    function entryIfWithLogicalOperation() {
     694     90        debugger;
     695     91        if (true && a() && a())
     696 ->  92            |b();
     697     93    }
     698     94   
     699     95    function entryIfWithBinaryOperation() {
     700
     701ACTION: step-over
     702PAUSE AT entryIfWithLogicalOperation:94:2
     703     90        debugger;
     704     91        if (true && a() && a())
     705     92            b();
     706 ->  93    }|
     707     94   
     708     95    function entryIfWithBinaryOperation() {
     709     96        let i = a();
     710
     711ACTION: resume
     712RESUMED
     713PASS: Should have used all steps.
     714
     715-- Running test case: Debugger.stepping.IfWithBinaryOperation
     716EXPRESSION: setTimeout(entryIfWithBinaryOperation)
     717STEPS: over, in, over, resume
     718PAUSED (debugger-statement)
     719PAUSE AT entryIfWithBinaryOperation:98:5
     720     94   
     721     95    function entryIfWithBinaryOperation() {
     722     96        let i = a();
     723 ->  97        |debugger;
     724     98        if (i < 2)
     725     99            b();
     726    100    }
     727
     728ACTION: step-over
     729PAUSE AT entryIfWithBinaryOperation:99:9
     730     95    function entryIfWithBinaryOperation() {
     731     96        let i = a();
     732     97        debugger;
     733 ->  98        if (|i < 2)
     734     99            b();
     735    100    }
     736    101   
     737
     738ACTION: step-in
     739PAUSE AT entryIfWithBinaryOperation:100:9
     740     96        let i = a();
     741     97        debugger;
     742     98        if (i < 2)
     743 ->  99            |b();
     744    100    }
     745    101   
     746    102    function entryIfWithNotOperation() {
     747
     748ACTION: step-over
     749PAUSE AT entryIfWithBinaryOperation:101:2
     750     97        debugger;
     751     98        if (i < 2)
     752     99            b();
     753 -> 100    }|
     754    101   
     755    102    function entryIfWithNotOperation() {
     756    103        debugger;
     757
     758ACTION: resume
     759RESUMED
     760PASS: Should have used all steps.
     761
     762-- Running test case: Debugger.stepping.IfWithNotOperation
     763EXPRESSION: setTimeout(entryIfWithNotOperation)
     764STEPS: over, in, over, in, over, resume
     765PAUSED (debugger-statement)
     766PAUSE AT entryIfWithNotOperation:104:5
     767    100    }
     768    101   
     769    102    function entryIfWithNotOperation() {
     770 -> 103        |debugger;
     771    104        if (!false)
     772    105            a();
     773    106        if (!!true)
     774
     775ACTION: step-over
     776PAUSE AT entryIfWithNotOperation:105:9
     777    101   
     778    102    function entryIfWithNotOperation() {
     779    103        debugger;
     780 -> 104        if (|!false)
     781    105            a();
     782    106        if (!!true)
     783    107            a();
     784
     785ACTION: step-in
     786PAUSE AT entryIfWithNotOperation:106:9
     787    102    function entryIfWithNotOperation() {
     788    103        debugger;
     789    104        if (!false)
     790 -> 105            |a();
     791    106        if (!!true)
     792    107            a();
     793    108    }
     794
     795ACTION: step-over
     796PAUSE AT entryIfWithNotOperation:107:9
     797    103        debugger;
     798    104        if (!false)
     799    105            a();
     800 -> 106        if (|!!true)
     801    107            a();
     802    108    }
     803    109   
     804
     805ACTION: step-in
     806PAUSE AT entryIfWithNotOperation:108:9
     807    104        if (!false)
     808    105            a();
     809    106        if (!!true)
     810 -> 107            |a();
     811    108    }
     812    109   
     813    110    // ---------
     814
     815ACTION: step-over
     816PAUSE AT entryIfWithNotOperation:109:2
     817    105            a();
     818    106        if (!!true)
     819    107            a();
     820 -> 108    }|
     821    109   
     822    110    // ---------
     823    111   
     824
     825ACTION: resume
     826RESUMED
     827PASS: Should have used all steps.
     828
  • trunk/LayoutTests/inspector/debugger/stepping/stepping-control-flow.html

    r206652 r207228  
    55<script src="../resources/log-pause-location.js"></script>
    66<script>
    7 function a() {
    8     return 1;
    9 }
    10 
    11 function b() {
    12     return 2;
    13 }
     7// We may want to allow constants to eliminate branches. Use vars for existing tests and have constant specific tests.
     8var value = 1;
     9var truthy = true;
     10var falsey = false;
     11function a() { return value; }
     12function b() { return value; }
     13
    1414
    1515function entryIfSingleStatement() {
    1616    debugger;
    17     if (true)
    18         a();
    19     if (false)
     17    if (truthy)
     18        a();
     19    if (falsey)
    2020        a();
    2121}
     
    2323function entryIfMultiStatement() {
    2424    debugger;
    25     if (true) {
     25    if (truthy) {
    2626        a();
    2727        a();
    2828    }
    29     if (false) {
     29    if (falsey) {
    3030        a();
    3131        a();
     
    3535function entryIfElse() {
    3636    debugger;
    37     if (true)
    38         a();
    39     else
    40         a();
    41     if (false)
     37    if (truthy)
     38        a();
     39    else
     40        a();
     41    if (falsey)
    4242        a();
    4343    else
     
    4747function entryIfElseChain() {
    4848    debugger;
    49     if (false)
    50         a();
    51     else if (true)
    52         a();
    53     else
    54         a();
    55 
    56     if (false)
    57         a();
    58     else if (false)
     49    if (falsey)
     50        a();
     51    else if (truthy)
     52        a();
     53    else
     54        a();
     55
     56    if (falsey)
     57        a();
     58    else if (falsey)
    5959        a();
    6060    else
     
    6969
    7070function entryTernary() {
    71     let t = () => true;
    72     let f = () => false;
     71    let t = () => truthy;
     72    let f = () => falsey;
    7373    debugger;
    7474    let x = t() ? a() : b();
    7575    let y = f() ? a() : b();
     76}
     77
     78function entryIfConstantBranch() {
     79    debugger;
     80    if (true)
     81        a();
     82    if (false)
     83        a();
     84    if (0)
     85        a();
     86    if (null)
     87        a();
     88}
     89
     90function entryIfWithLogicalOperation() {
     91    debugger;
     92    if (true && a() && a())
     93        b();
     94}
     95
     96function entryIfWithBinaryOperation() {
     97    let i = a();
     98    debugger;
     99    if (i < 2)
     100        b();
     101}
     102
     103function entryIfWithNotOperation() {
     104    debugger;
     105    if (!false)
     106        a();
     107    if (!!true)
     108        a();
    76109}
    77110
     
    198231    });
    199232
     233    addSteppingTestCase({
     234        name: "Debugger.stepping.ConstantBranch",
     235        description: "Should pause for constant branches.",
     236        expression: "setTimeout(entryIfConstantBranch)",
     237        steps: [
     238            "over",
     239                "over", // (true)
     240                "over", // a()
     241                "over", // (false)
     242                "over", // (0)
     243                "over", // (null)
     244            "resume",
     245        ]
     246    });
     247
     248    addSteppingTestCase({
     249        name: "Debugger.stepping.IfWithLogicalOperation",
     250        description: "Should always pause for a condition with logical operations.",
     251        expression: "setTimeout(entryIfWithLogicalOperation)",
     252        steps: [
     253            "over",
     254                "in",   // into a()
     255                "out",  // out of a() - before a()
     256                "in",   // into a()
     257                "out",  // out of a() - before b()
     258                "over", // b() - leaving entry
     259            "resume",
     260        ]
     261    });
     262
     263    addSteppingTestCase({
     264        name: "Debugger.stepping.IfWithBinaryOperation",
     265        description: "Should always pause for a condition with logical operations.",
     266        expression: "setTimeout(entryIfWithBinaryOperation)",
     267        steps: [
     268            "over",
     269                "in",    // i < 2 [true]
     270                "over",  // over b() - leaving entry
     271            "resume",
     272        ]
     273    });
     274
     275    addSteppingTestCase({
     276        name: "Debugger.stepping.IfWithNotOperation",
     277        description: "Should always pause for a condition that is a not operation.",
     278        expression: "setTimeout(entryIfWithNotOperation)",
     279        steps: [
     280            "over",
     281                "in",   // !false
     282                "over", // a()
     283                "in",   // !!truth
     284                "over", // a() - leaving entry
     285            "resume",
     286        ]
     287    });
     288
    200289    loadMainPageContent().then(() => {
    201290        suite.runTestCasesAndFinish();
  • trunk/LayoutTests/inspector/debugger/stepping/stepping-loops-expected.txt

    r206654 r207228  
    149149-- Running test case: Debugger.stepping.TraditionalForStepOver
    150150EXPRESSION: setTimeout(entryTraditionalFor)
    151 STEPS: over, over, over, over, over, over, over, over, resume
     151STEPS: over, over, over, over, over, over, over, over, over, resume
    152152PAUSED (debugger-statement)
    153153PAUSE AT entryTraditionalFor:27:5
     
    166166     26        debugger;
    167167 ->  27        for (|let i = 0; i < 2; ++i)
     168     28            a();
     169     29    }
     170     30   
     171
     172ACTION: step-over
     173PAUSE AT entryTraditionalFor:28:21
     174     24   
     175     25    function entryTraditionalFor() {
     176     26        debugger;
     177 ->  27        for (let i = 0; |i < 2; ++i)
    168178     28            a();
    169179     29    }
     
    450460-- Running test case: Debugger.stepping.ForIn
    451461EXPRESSION: setTimeout(entryForIn)
    452 STEPS: over, over, over, over, over, over, resume
     462STEPS: over, over, over, over, over, over, over, resume
    453463PAUSED (debugger-statement)
    454464PAUSE AT entryForIn:41:5
     
    472482
    473483ACTION: step-over
     484PAUSE AT entryForIn:42:10
     485     38    function entryForIn() {
     486     39        let o = {key1: 1, key2: 2};
     487     40        debugger;
     488 ->  41        for (|let property in o)
     489     42            a();
     490     43    }
     491     44   
     492
     493ACTION: step-over
    474494PAUSE AT entryForIn:43:9
    475495     39        let o = {key1: 1, key2: 2};
     
    482502
    483503ACTION: step-over
    484 PAUSE AT entryForIn:42:26
     504PAUSE AT entryForIn:42:10
    485505     38    function entryForIn() {
    486506     39        let o = {key1: 1, key2: 2};
    487507     40        debugger;
    488  ->  41        for (let property in |o)
     508 ->  41        for (|let property in o)
    489509     42            a();
    490510     43    }
     
    502522
    503523ACTION: step-over
    504 PAUSE AT entryForIn:42:26
     524PAUSE AT entryForIn:42:10
    505525     38    function entryForIn() {
    506526     39        let o = {key1: 1, key2: 2};
    507527     40        debugger;
    508  ->  41        for (let property in |o)
     528 ->  41        for (|let property in o)
    509529     42            a();
    510530     43    }
     
    527547-- Running test case: Debugger.stepping.ForIn
    528548EXPRESSION: setTimeout(entryForOf)
    529 STEPS: over, over, over, over, over, over, resume
     549STEPS: over, over, over, over, over, over, over, resume
    530550PAUSED (debugger-statement)
    531551PAUSE AT entryForOf:48:5
     
    549569
    550570ACTION: step-over
     571PAUSE AT entryForOf:49:10
     572     45    function entryForOf() {
     573     46        let arr = [1, 2];
     574     47        debugger;
     575 ->  48        for (|let value of arr)
     576     49            a();
     577     50    }
     578     51   
     579
     580ACTION: step-over
    551581PAUSE AT entryForOf:50:9
    552582     46        let arr = [1, 2];
     
    559589
    560590ACTION: step-over
    561 PAUSE AT entryForOf:49:23
     591PAUSE AT entryForOf:49:10
    562592     45    function entryForOf() {
    563593     46        let arr = [1, 2];
    564594     47        debugger;
    565  ->  48        for (let value of |arr)
     595 ->  48        for (|let value of arr)
    566596     49            a();
    567597     50    }
     
    579609
    580610ACTION: step-over
    581 PAUSE AT entryForOf:49:23
     611PAUSE AT entryForOf:49:10
    582612     45    function entryForOf() {
    583613     46        let arr = [1, 2];
    584614     47        debugger;
    585  ->  48        for (let value of |arr)
     615 ->  48        for (|let value of arr)
    586616     49            a();
    587617     50    }
     
    611641     53        let i = 0;
    612642 ->  54        |debugger;
    613      55        while (true) {
     643     55        while (truthy) {
    614644     56            ++i;
    615645     57            if (i === 1)
     
    620650     53        let i = 0;
    621651     54        debugger;
    622  ->  55        while (|true) {
     652 ->  55        while (|truthy) {
    623653     56            ++i;
    624654     57            if (i === 1)
     
    629659     53        let i = 0;
    630660     54        debugger;
    631      55        while (true) {
     661     55        while (truthy) {
    632662 ->  56            |++i;
    633663     57            if (i === 1)
     
    638668PAUSE AT entryWhileBreakContinue:58:13
    639669     54        debugger;
    640      55        while (true) {
     670     55        while (truthy) {
    641671     56            ++i;
    642672 ->  57            if (|i === 1)
     
    647677ACTION: step-over
    648678PAUSE AT entryWhileBreakContinue:59:13
    649      55        while (true) {
     679     55        while (truthy) {
    650680     56            ++i;
    651681     57            if (i === 1)
     
    660690     53        let i = 0;
    661691     54        debugger;
    662  ->  55        while (|true) {
     692 ->  55        while (|truthy) {
    663693     56            ++i;
    664694     57            if (i === 1)
     
    669699     53        let i = 0;
    670700     54        debugger;
    671      55        while (true) {
     701     55        while (truthy) {
    672702 ->  56            |++i;
    673703     57            if (i === 1)
     
    678708PAUSE AT entryWhileBreakContinue:58:13
    679709     54        debugger;
    680      55        while (true) {
     710     55        while (truthy) {
    681711     56            ++i;
    682712 ->  57            if (|i === 1)
  • trunk/LayoutTests/inspector/debugger/stepping/stepping-loops.html

    r206652 r207228  
    55<script src="../resources/log-pause-location.js"></script>
    66<script>
    7 function a() {
    8     return 1;
    9 }
     7var truthy = true;
     8function a() { return 1; }
     9
    1010
    1111function entryWhile() {
     
    5454    let i = 0;
    5555    debugger;
    56     while (true) {
     56    while (truthy) {
    5757        ++i;
    5858        if (i === 1)
     
    118118        steps: [
    119119            "over",
    120                 "over", // complete: let i = 0; i < 2
     120                "over", // complete: let i = 0
     121                "over", // complete: i < 2
    121122                "over", // complete: a()
    122123                "over", // complete: ++i
     
    170171        steps: [
    171172            "over",
     173                "over", // complete: (o)
    172174                "over", // complete: let property in o [key1]
    173175                "over", // complete: a()
     
    185187        steps: [
    186188            "over",
     189                "over", // complete (arr)
    187190                "over", // complete: let value of arr [1]
    188191                "over", // complete: a()
  • trunk/Source/JavaScriptCore/ChangeLog

    r207226 r207228  
     12016-10-12  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Emit DebugHooks uniformly with pause locations instead of having separate pause locations and op_debug emits
     4        https://bugs.webkit.org/show_bug.cgi?id=162809
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Change how BytecodeGeneration emits debug hooks to be more consistent.
     9        Previously most nodes individually generated their own debug hook
     10        and we asserted that it matched a breakpoint location identified
     11        by the parser. This could get out of sync, or nodes could forget to
     12        emit debug hooks expected by the parser.
     13       
     14        With this change, we always check and emit a debug hook for any
     15        node. The default behavior is for BytecodeGenerator::emitNode
     16        to emit the debug hook when emitting the node itself. This covers
     17        the majority of cases (statements).
     18
     19        There are a few exceptions where we continue to need to customize
     20        emitting debug hooks:
     21
     22            1. Nodes with emitBytecodeInConditionContext
     23                - non-Expression nodes customize how they emit their children
     24                - constants conditions may emit nothing, but we had recorded a breakpoint location so emit a debug hook
     25                - always emit one debug hook in case we recorded a breakpoint location, but avoid emitting multiple
     26                  in nodes which may call up to the ExpressionNode::emitBytecodeInConditionContext base impl.
     27            2. Specialized Debug Hooks
     28                - such as hooks for Program start/end, debugger statements, etc.
     29            3. Debug Hooks in for..of / for..in that don't correspond to re-emitting nodes
     30                - such as pausing on the assignment expression inside these loops
     31
     32        The majority of nodes no longer have custom emits.
     33
     34        * bytecompiler/BytecodeGenerator.h:
     35        (JSC::BytecodeGenerator::emitNodeInTailPosition):
     36        (JSC::BytecodeGenerator::emitNodeInConditionContext):
     37        * bytecompiler/BytecodeGenerator.cpp:
     38        (JSC::BytecodeGenerator::emitDebugHook):
     39        (JSC::BytecodeGenerator::emitEnumeration):
     40        By default, when emitting a node check if we should also emit an op_debug for it.
     41        This default DebugHook is WillExecuteStatement, which is a normal pause point.
     42
     43        * bytecompiler/NodesCodegen.cpp:
     44        (JSC::ConstantNode::emitBytecodeInConditionContext):
     45        (JSC::LogicalNotNode::emitBytecodeInConditionContext):
     46        (JSC::BinaryOpNode::emitBytecodeInConditionContext):
     47        (JSC::LogicalOpNode::emitBytecodeInConditionContext):
     48        The parser would have generated a pause location for these conditions
     49        no matter what constant folding and re-writing these nodes may perform.
     50        So, when emitting these nodes in condition context check if they need
     51        emit their own debug hook.
     52
     53        (JSC::EmptyStatementNode::emitBytecode):
     54        (JSC::ExprStatementNode::emitBytecode):
     55        (JSC::DeclarationStatement::emitBytecode):
     56        (JSC::IfElseNode::emitBytecode):
     57        (JSC::DoWhileNode::emitBytecode):
     58        (JSC::WhileNode::emitBytecode):
     59        (JSC::ForNode::emitBytecode):
     60        (JSC::ContinueNode::emitBytecode):
     61        (JSC::BreakNode::emitBytecode):
     62        (JSC::ReturnNode::emitBytecode):
     63        (JSC::WithNode::emitBytecode):
     64        (JSC::SwitchNode::emitBytecode):
     65        (JSC::ThrowNode::emitBytecode):
     66        No longer need to custom emit debug hooks. The default emitNode will handle these.
     67
     68        (JSC::ForInNode::emitBytecode):
     69        Include extra debug hooks the user expects to return back to the assignment
     70        expression in the loop header before starting the body again. The same is done
     71        for for..of with emitEnumeration.
     72
     73        * parser/ASTBuilder.h:
     74        (JSC::ASTBuilder::createExportDefaultDeclaration):
     75        (JSC::ASTBuilder::createExportLocalDeclaration):
     76        These are no longer needed to fake-satisfy assertions. We never wanted to
     77        emit debug hooks for these inner statements because the export statement
     78        will already have the debug hooks.
     79
     80        (JSC::ASTBuilder::createForInLoop):
     81        (JSC::ASTBuilder::createForOfLoop):
     82        Include the correct location where the declaration starts.
     83
     84        (JSC::ASTBuilder::breakpointLocation):
     85        Simplify to a general implementation for Node.
     86
     87        * parser/SyntaxChecker.h:
     88        (JSC::SyntaxChecker::createForInLoop):
     89        (JSC::SyntaxChecker::createForOfLoop):
     90        Ignore the new extra parameter.
     91
     92        * parser/Nodes.h:
     93        (JSC::Node::needsDebugHook):
     94        (JSC::Node::setNeedsDebugHook):
     95        (JSC::ExpressionNode::needsDebugHook): Deleted.
     96        (JSC::ExpressionNode::setNeedsDebugHook): Deleted.
     97        (JSC::StatementNode::isEmptyStatement): Deleted.
     98        (JSC::StatementNode::needsDebugHook): Deleted.
     99        (JSC::StatementNode::setNeedsDebugHook): Deleted.
     100        Move debug hook logic into the base Node class.
     101
     102        (JSC::StatementNode::isDebuggerStatement):
     103        Provide a way to distinguish a debugger statement.
     104
     105        * parser/Parser.cpp:
     106        (JSC::Parser<LexerType>::parseForStatement):
     107        Provide the location before the declaration starts.
     108
    11092016-10-12  Mark Lam  <mark.lam@apple.com>
    2110
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r207023 r207228  
    35053505void BytecodeGenerator::emitDebugHook(StatementNode* statement)
    35063506{
    3507     RELEASE_ASSERT(statement->needsDebugHook());
     3507    // DebuggerStatementNode will output its own special debug hook.
     3508    if (statement->isDebuggerStatement())
     3509        return;
     3510
    35083511    emitDebugHook(WillExecuteStatement, statement->position());
    35093512}
    35103513
    3511 void BytecodeGenerator::emitDebugHook(ExpressionNode* expr, DebugHookType debugHookType)
    3512 {
    3513     RELEASE_ASSERT(expr->needsDebugHook());
    3514     emitDebugHook(debugHookType, expr->position());
     3514void BytecodeGenerator::emitDebugHook(ExpressionNode* expr)
     3515{
     3516    emitDebugHook(WillExecuteStatement, expr->position());
    35153517}
    35163518
     
    42034205            RELEASE_ASSERT(forLoopNode->isForOfNode());
    42044206            prepareLexicalScopeForNextForLoopIteration(forLoopNode, forLoopSymbolTable);
    4205             emitDebugHook(forLoopNode->expr(), WillExecuteStatement);
     4207            emitDebugHook(forLoopNode->lexpr());
    42064208        }
    42074209
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r206870 r207228  
    387387                return;
    388388            }
     389            if (UNLIKELY(n->needsDebugHook()))
     390                emitDebugHook(n);
    389391            n->emitBytecode(*this, dst);
    390392        }
     
    412414            if (UNLIKELY(!m_vm->isSafeToRecurse()))
    413415                return emitThrowExpressionTooDeepException();
     416            if (UNLIKELY(n->needsDebugHook()))
     417                emitDebugHook(n);
    414418            return n->emitBytecode(*this, dst);
    415419        }
     
    431435                return;
    432436            }
    433 
    434437            n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMode);
    435438        }
     
    685688        void emitDebugHook(DebugHookType, unsigned line, unsigned charOffset, unsigned lineStart);
    686689        void emitDebugHook(StatementNode*);
    687         void emitDebugHook(ExpressionNode*, DebugHookType);
     690        void emitDebugHook(ExpressionNode*);
    688691        void emitWillLeaveCallFrameDebugHook();
    689692
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r206870 r207228  
    9595{
    9696    TriState value = jsValue(generator).pureToBoolean();
     97
     98    if (UNLIKELY(needsDebugHook())) {
     99        if (value != MixedTriState)
     100            generator.emitDebugHook(this);
     101    }
     102
    97103    if (value == MixedTriState)
    98104        ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode);
     
    16701676void LogicalNotNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode)
    16711677{
    1672     // reverse the true and false targets
     1678    if (UNLIKELY(needsDebugHook()))
     1679        generator.emitDebugHook(this);
     1680
     1681    // Reverse the true and false targets.
    16731682    generator.emitNodeInConditionContext(expr(), falseTarget, trueTarget, invert(fallThroughMode));
    16741683}
     
    18001809    tryFoldToBranch(generator, branchCondition, branchExpression);
    18011810
     1811    if (UNLIKELY(needsDebugHook())) {
     1812        if (branchCondition != MixedTriState)
     1813            generator.emitDebugHook(this);
     1814    }
     1815
    18021816    if (branchCondition == MixedTriState)
    18031817        ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode);
     
    20012015void LogicalOpNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode)
    20022016{
     2017    if (UNLIKELY(needsDebugHook()))
     2018        generator.emitDebugHook(this);
     2019
    20032020    RefPtr<Label> afterExpr1 = generator.newLabel();
    20042021    if (m_operator == OpLogicalAnd)
     
    23772394// ------------------------------ EmptyStatementNode ---------------------------
    23782395
    2379 void EmptyStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
    2380 {
    2381     generator.emitDebugHook(this);
     2396void EmptyStatementNode::emitBytecode(BytecodeGenerator&, RegisterID*)
     2397{
     2398    RELEASE_ASSERT(needsDebugHook());
    23822399}
    23832400
     
    23942411{
    23952412    ASSERT(m_expr);
    2396     generator.emitDebugHook(this);
    23972413    generator.emitNode(dst, m_expr);
    23982414}
     
    24032419{
    24042420    ASSERT(m_expr);
    2405     generator.emitDebugHook(this);
    24062421    generator.emitNode(m_expr);
    24072422}
     
    24912506void IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    24922507{
    2493     generator.emitDebugHook(m_condition, WillExecuteStatement);
    2494    
    24952508    RefPtr<Label> beforeThen = generator.newLabel();
    24962509    RefPtr<Label> beforeElse = generator.newLabel();
     
    25372550
    25382551    generator.emitLabel(scope->continueTarget());
    2539     generator.emitDebugHook(m_expr, WillExecuteStatement);
    25402552    generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse);
    25412553
     
    25502562    RefPtr<Label> topOfLoop = generator.newLabel();
    25512563
    2552     generator.emitDebugHook(m_expr, WillExecuteStatement);
    25532564    generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansTrue);
    25542565
     
    25602571
    25612572    generator.emitLabel(scope->continueTarget());
    2562     generator.emitDebugHook(m_expr, WillExecuteStatement);
    25632573
    25642574    generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse);
     
    25782588    generator.pushLexicalScope(this, BytecodeGenerator::TDZCheckOptimization::Optimize, BytecodeGenerator::NestedScopeType::IsNested, &forLoopSymbolTable);
    25792589
    2580     if (m_expr1 || m_expr2) {
    2581         ExpressionNode* firstExpr = m_expr1 ? m_expr1 : m_expr2;
    2582         generator.emitDebugHook(firstExpr, WillExecuteStatement);
    2583     }
    2584 
    2585     if (m_expr1) {
    2586         generator.emitDebugHook(m_expr1, WillExecuteExpression);
     2590    if (m_expr1)
    25872591        generator.emitNode(generator.ignoredResult(), m_expr1);
    2588     }
    25892592
    25902593    RefPtr<Label> topOfLoop = generator.newLabel();
    2591     if (m_expr2) {
    2592         generator.emitDebugHook(m_expr2, WillExecuteExpression);
     2594    if (m_expr2)
    25932595        generator.emitNodeInConditionContext(m_expr2, topOfLoop.get(), scope->breakTarget(), FallThroughMeansTrue);
    2594     }
    25952596
    25962597    generator.emitLabel(topOfLoop.get());
     
    26022603    generator.emitLabel(scope->continueTarget());
    26032604    generator.prepareLexicalScopeForNextForLoopIteration(this, forLoopSymbolTable);
    2604     if (m_expr3) {
    2605         generator.emitDebugHook(m_expr3, WillExecuteStatement);
     2605    if (m_expr3)
    26062606        generator.emitNode(generator.ignoredResult(), m_expr3);
    2607     }
    2608 
    2609     if (m_expr2) {
    2610         generator.emitDebugHook(m_expr2, WillExecuteStatement);
     2607
     2608    if (m_expr2)
    26112609        generator.emitNodeInConditionContext(m_expr2, topOfLoop.get(), scope->breakTarget(), FallThroughMeansFalse);
    2612     } else
     2610    else
    26132611        generator.emitJump(topOfLoop.get());
    26142612
     
    27392737    generator.pushLexicalScope(this, BytecodeGenerator::TDZCheckOptimization::Optimize, BytecodeGenerator::NestedScopeType::IsNested, &forLoopSymbolTable);
    27402738
    2741     generator.emitDebugHook(m_expr, WillExecuteStatement);
    2742 
    27432739    if (m_lexpr->isAssignResolveNode())
    27442740        generator.emitNode(generator.ignoredResult(), m_lexpr);
     
    27512747    RefPtr<RegisterID> local = this->tryGetBoundLocal(generator);
    27522748    RefPtr<RegisterID> enumeratorIndex;
     2749
     2750    // Pause at the assignment expression for each for..in iteration.
     2751    generator.emitDebugHook(m_lexpr);
    27532752
    27542753    int profilerStartOffset = m_statement->startOffset();
     
    27892788        generator.prepareLexicalScopeForNextForLoopIteration(this, forLoopSymbolTable);
    27902789        generator.emitInc(i.get());
    2791         generator.emitDebugHook(m_expr, WillExecuteStatement);
     2790        generator.emitDebugHook(m_lexpr); // Pause at the assignment expression for each for..in iteration.
    27922791        generator.emitJump(loopStart.get());
    27932792
     
    28292828        generator.emitInc(enumeratorIndex.get());
    28302829        generator.emitEnumeratorStructurePropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get());
    2831         generator.emitDebugHook(m_expr, WillExecuteStatement);
     2830        generator.emitDebugHook(m_lexpr); // Pause at the assignment expression for each for..in iteration.
    28322831        generator.emitJump(loopStart.get());
    28332832       
     
    28662865        generator.emitInc(enumeratorIndex.get());
    28672866        generator.emitEnumeratorGenericPropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get());
    2868         generator.emitDebugHook(m_expr, WillExecuteStatement);
     2867        generator.emitDebugHook(m_lexpr); // Pause at the assignment expression for each for..in iteration.
    28692868        generator.emitJump(loopStart.get());
    28702869
     
    29632962void ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
    29642963{
    2965     generator.emitDebugHook(this);
    2966    
    29672964    LabelScopePtr scope = generator.continueTarget(m_ident);
    29682965    ASSERT(scope);
     
    29922989void BreakNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
    29932990{
    2994     generator.emitDebugHook(this);
    2995    
    29962991    LabelScopePtr scope = generator.breakTarget(m_ident);
    29972992    ASSERT(scope);
     
    30073002void ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    30083003{
    3009     generator.emitDebugHook(this);
    3010 
    30113004    ASSERT(generator.codeType() == FunctionCode);
    30123005
     
    30353028void WithNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    30363029{
    3037     generator.emitDebugHook(m_expr, WillExecuteStatement);
    3038 
    30393030    RefPtr<RegisterID> scope = generator.emitNode(m_expr);
    30403031    generator.emitExpressionInfo(m_divot, m_divot - m_expressionLength, m_divot);
     
    32103201void SwitchNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    32113202{
    3212     generator.emitDebugHook(m_expr, WillExecuteStatement);
    3213    
    32143203    LabelScopePtr scope = generator.newLabelScope(LabelScope::Switch);
    32153204
     
    32403229void ThrowNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    32413230{
    3242     generator.emitDebugHook(this);
    3243 
    32443231    if (dst == generator.ignoredResult())
    32453232        dst = 0;
  • trunk/Source/JavaScriptCore/parser/ASTBuilder.h

    r206671 r207228  
    560560    }
    561561
    562     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)
     562    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)
    563563    {
    564564        ForInNode* result = new (m_parserArena) ForInNode(location, lhs, iter, statements, lexicalVariables);
     
    568568    }
    569569   
    570     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)
    571     {
    572         auto lexpr = new (m_parserArena) DestructuringAssignmentNode(location, pattern, 0);
    573         return createForInLoop(location, lexpr, iter, statements, eStart, eDivot, eEnd, start, end, lexicalVariables);
    574     }
    575    
    576     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)
     570    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)
     571    {
     572        auto lexpr = new (m_parserArena) DestructuringAssignmentNode(declLocation, pattern, nullptr);
     573        return createForInLoop(location, lexpr, iter, statements, declLocation, eStart, eDivot, eEnd, start, end, lexicalVariables);
     574    }
     575   
     576    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)
    577577    {
    578578        ForOfNode* result = new (m_parserArena) ForOfNode(location, lhs, iter, statements, lexicalVariables);
     
    582582    }
    583583   
    584     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)
    585     {
    586         auto lexpr = new (m_parserArena) DestructuringAssignmentNode(location, pattern, 0);
    587         return createForOfLoop(location, lexpr, iter, statements, eStart, eDivot, eEnd, start, end, lexicalVariables);
     584    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)
     585    {
     586        auto lexpr = new (m_parserArena) DestructuringAssignmentNode(declLocation, pattern, nullptr);
     587        return createForOfLoop(location, lexpr, iter, statements, declLocation, eStart, eDivot, eEnd, start, end, lexicalVariables);
    588588    }
    589589
     
    753753    StatementNode* createExportDefaultDeclaration(const JSTokenLocation& location, StatementNode* declaration, const Identifier& localName)
    754754    {
    755         // We need to mark the inner statement as needing a debug hook (so that when the statement is generated we don't
    756         // assert when generating an op_debug for it) without recording a breakpoint location because the export statement
    757         // itself will get the breakpoint location. This will be eliminated by:
    758         // <https://webkit.org/b/162809> Emit DebugHooks uniformly with pause locations instead of having separate pause locations and op_debug emits
    759         declaration->setNeedsDebugHook();
    760755        return new (m_parserArena) ExportDefaultDeclarationNode(location, declaration, localName);
    761756    }
     
    763758    StatementNode* createExportLocalDeclaration(const JSTokenLocation& location, StatementNode* declaration)
    764759    {
    765         // We need to mark the inner statement as needing a debug hook (so that when the statement is generated we don't
    766         // assert when generating an op_debug for it) without recording a breakpoint location because the export statement
    767         // itself will get the breakpoint location. This will be eliminated by:
    768         // <https://webkit.org/b/162809> Emit DebugHooks uniformly with pause locations instead of having separate pause locations and op_debug emits
    769         declaration->setNeedsDebugHook();
    770760        return new (m_parserArena) ExportLocalDeclarationNode(location, declaration);
    771761    }
     
    984974    }
    985975
    986     JSTextPosition breakpointLocation(StatementNode* statement)
    987     {
    988         statement->setNeedsDebugHook();
    989         return statement->position();
    990     }
    991 
    992     JSTextPosition breakpointLocation(ExpressionNode* expr)
    993     {
    994         expr->setNeedsDebugHook();
    995         return expr->position();
     976    JSTextPosition breakpointLocation(Node* node)
     977    {
     978        node->setNeedsDebugHook();
     979        return node->position();
    996980    }
    997981
  • trunk/Source/JavaScriptCore/parser/Nodes.h

    r206653 r207228  
    146146        void setStartOffset(int offset) { m_position.offset = offset; }
    147147
     148        bool needsDebugHook() const { return m_needsDebugHook; }
     149        void setNeedsDebugHook() { m_needsDebugHook = true; }
     150
    148151    protected:
    149152        JSTextPosition m_position;
    150153        int m_endOffset;
     154        bool m_needsDebugHook { false };
    151155    };
    152156
     
    192196        ResultType resultDescriptor() const { return m_resultType; }
    193197
    194         bool needsDebugHook() { return m_needsDebugHook; }
    195         void setNeedsDebugHook() { m_needsDebugHook = true; }
    196 
    197198    private:
    198199        ResultType m_resultType;
    199         bool m_needsDebugHook { false };
    200200    };
    201201
     
    214214
    215215        virtual bool isEmptyStatement() const { return false; }
     216        virtual bool isDebuggerStatement() const { return false; }
    216217        virtual bool isFunctionNode() const { return false; }
    217218        virtual bool isReturnNode() const { return false; }
     
    225226        virtual bool isForOfNode() const { return false; }
    226227
    227         bool needsDebugHook() { return m_needsDebugHook; }
    228         void setNeedsDebugHook() { m_needsDebugHook = true; }
    229 
    230228    protected:
    231229        StatementNode* m_next;
    232230        int m_lastLine;
    233         bool m_needsDebugHook { false };
    234231    };
    235232
     
    13671364    public:
    13681365        DebuggerStatementNode(const JSTokenLocation&);
     1366
     1367        bool isDebuggerStatement() const override { return true; }
    13691368       
    13701369    private:
     
    14741473        EnumerationNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*, VariableEnvironment&);
    14751474
     1475        ExpressionNode* lexpr() const { return m_lexpr; }
    14761476        ExpressionNode* expr() const { return m_expr; }
    14771477
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r206671 r207228  
    11871187    int nonLHSCount = m_parserState.nonLHSCount;
    11881188    int declarations = 0;
     1189    JSTokenLocation declLocation(tokenLocation());
    11891190    JSTextPosition declsStart;
    11901191    JSTextPosition declsEnd;
     
    12811282        TreeStatement result;
    12821283        if (isOfEnumeration)
    1283             result = context.createForOfLoop(location, forInTarget, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine, *lexicalVariables);
     1284            result = context.createForOfLoop(location, forInTarget, expr, statement, declLocation, declsStart, inLocation, exprEnd, startLine, endLine, *lexicalVariables);
    12841285        else {
    12851286            if (isVarDeclaraton && forInInitializer)
    1286                 result = context.createForInLoop(location, decls, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine, *lexicalVariables);
     1287                result = context.createForInLoop(location, decls, expr, statement, declLocation, declsStart, inLocation, exprEnd, startLine, endLine, *lexicalVariables);
    12871288            else
    1288                 result = context.createForInLoop(location, forInTarget, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine, *lexicalVariables);
     1289                result = context.createForInLoop(location, forInTarget, expr, statement, declLocation, declsStart, inLocation, exprEnd, startLine, endLine, *lexicalVariables);
    12891290        }
    12901291        popLexicalScopeIfNecessary();
     
    13731374        ASSERT(!decls);
    13741375        if (isOfEnumeration)
    1375             result = context.createForOfLoop(location, pattern, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
     1376            result = context.createForOfLoop(location, pattern, expr, statement, declLocation, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
    13761377        else
    1377             result = context.createForInLoop(location, pattern, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
     1378            result = context.createForInLoop(location, pattern, expr, statement, declLocation, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
    13781379
    13791380        popLexicalScopeIfNecessary();
     
    13811382    }
    13821383    if (isOfEnumeration)
    1383         result = context.createForOfLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
     1384        result = context.createForOfLoop(location, decls, expr, statement, declLocation, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
    13841385    else
    1385         result = context.createForInLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
     1386        result = context.createForInLoop(location, decls, expr, statement, declLocation, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
    13861387    popLexicalScopeIfNecessary();
    13871388    return result;
  • trunk/Source/JavaScriptCore/parser/SyntaxChecker.h

    r206653 r207228  
    239239    int createIfStatement(const JSTokenLocation&, int, int, int, int, int) { return StatementResult; }
    240240    int createForLoop(const JSTokenLocation&, int, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
    241     int createForInLoop(const JSTokenLocation&, int, int, int, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
    242     int createForOfLoop(const JSTokenLocation&, int, int, int, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
     241    int createForInLoop(const JSTokenLocation&, int, int, int, const JSTokenLocation&, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
     242    int createForOfLoop(const JSTokenLocation&, int, int, int, const JSTokenLocation&, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
    243243    int createEmptyStatement(const JSTokenLocation&) { return StatementResult; }
    244244    int createDeclarationStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }
  • trunk/Source/WebInspectorUI/ChangeLog

    r207227 r207228  
     12016-10-12  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Emit DebugHooks uniformly with pause locations instead of having separate pause locations and op_debug emits
     4        https://bugs.webkit.org/show_bug.cgi?id=162809
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        * UserInterface/Views/SourceCodeTextEditor.js:
     9        (WebInspector.SourceCodeTextEditor.prototype.textEditorExecutionHighlightRange):
     10        When pausing on the variable assignment inside for..of and for..in don't just
     11        highlight "var foo" but include the right hand side "var foo in ..." or
     12        "var foo of ...".
     13
    1142016-10-12  Joseph Pecoraro  <pecoraro@apple.com>
    215
  • trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js

    r207227 r207228  
    12371237            // Find a node starting at this offset.
    12381238            // Avoid highlighting the entire program if this is the start of the first statement.
     1239            // Special case the assignment expression inside of a for..of and for..in to highlight a larger range.
    12391240            for (let node of nodes) {
    12401241                let startOffset = node.range[0];
     
    12421243                    callback(convertRangeOffsetsToSourceCodeOffsets(node.range));
    12431244                    return;
     1245                }
     1246                if (node.type === WebInspector.ScriptSyntaxTree.NodeType.ForInStatement || node.type === WebInspector.ScriptSyntaxTree.NodeType.ForOfStatement) {
     1247                    if (node.left.range[0] === offset) {
     1248                        callback(convertRangeOffsetsToSourceCodeOffsets([node.left.range[0], node.right.range[1]]));
     1249                        return;
     1250                    }
    12441251                }
    12451252                if (startOffset > offset)
Note: See TracChangeset for help on using the changeset viewer.