Ignore:
Timestamp:
Sep 5, 2017, 10:43:51 AM (8 years ago)
Author:
[email protected]
Message:

test262: Completion values for control flow do not match the spec
https://bugs.webkit.org/show_bug.cgi?id=171265

Patch by Joseph Pecoraro <Joseph Pecoraro> on 2017-09-05
Reviewed by Saam Barati.

JSTests:

  • stress/completion-value.js:

Condensed test for completion values in top level statements.

  • stress/super-get-by-id.js:

ClassDeclaration when evaled no longer produce values. Convert
these to ClassExpressions so they produce the class value.

  • ChakraCore/test/GlobalFunctions/evalreturns3.baseline-jsc:

This is a progression for currect spec behavior.

  • mozilla/mozilla-tests.yaml:

This test is now outdated, so mark it as failing for that reason.

  • test262.yaml:

Passing all "cptn" completion value tests.

Source/JavaScriptCore:

  • bytecompiler/BytecodeGenerator.h:

(JSC::BytecodeGenerator::shouldBeConcernedWithCompletionValue):
When we care about having proper completion values (global code
in programs, modules, and eval) insert undefined results for
control flow statements.

  • bytecompiler/NodesCodegen.cpp:

(JSC::SourceElements::emitBytecode):
Reduce writing a default undefined value to the completion result to
only once before the last statement we know will produce a value.

(JSC::IfElseNode::emitBytecode):
(JSC::WithNode::emitBytecode):
(JSC::WhileNode::emitBytecode):
(JSC::ForNode::emitBytecode):
(JSC::ForInNode::emitBytecode):
(JSC::ForOfNode::emitBytecode):
(JSC::SwitchNode::emitBytecode):
Insert an undefined to handle cases where code may break out of an
if/else or with statement (break/continue).

(JSC::TryNode::emitBytecode):
Same handling for break cases. Also, finally block statement completion
values are always ignored for the try statement result.

(JSC::ClassDeclNode::emitBytecode):
Class declarations, like function declarations, produce an empty result.

  • parser/Nodes.cpp:

(JSC::SourceElements::lastStatement):
(JSC::SourceElements::hasCompletionValue):
(JSC::SourceElements::hasEarlyBreakOrContinue):
(JSC::BlockNode::lastStatement):
(JSC::BlockNode::singleStatement):
(JSC::BlockNode::hasCompletionValue):
(JSC::BlockNode::hasEarlyBreakOrContinue):
(JSC::ScopeNode::singleStatement):
(JSC::ScopeNode::hasCompletionValue):
(JSC::ScopeNode::hasEarlyBreakOrContinue):
The only non-trivial cases need to loop through their list of statements
to determine if this has a completion value or not. Likewise for
determining if there is an early break / continue, meaning a break or
continue statement with no preceding statement that has a completion value.

  • parser/Nodes.h:

(JSC::StatementNode::next):
(JSC::StatementNode::hasCompletionValue):
Helper to check if a statement nodes produces a completion value or not.

Tools:

  • Scripts/run-jsc-stress-tests:

Include a :failDueToOutdatedOrBadTest to mark failures with justification.

LayoutTests:

  • js/eval-throw-return-expected.txt:
  • js/kde/completion-expected.txt:
  • js/kde/script-tests/completion.js:
  • js/script-tests/eval-throw-return.js:
  • sputnik/Conformance/12_Statement/12.6_Iteration_Statements/12.6.3_The_for_Statement/S12.6.3_A9-expected.txt:
  • sputnik/Conformance/12_Statement/12.6_Iteration_Statements/12.6.3_The_for_Statement/S12.6.3_A9.1-expected.txt:

Rebaseline expectations. These are all outdated. In fact the sputnik
tests were imported into test262 and modified for ES2015.

  • js/script-tests/function-toString-vs-name.js:

ClassDeclarations on their own don't produce a value. So output
the class value so the test behaves as expected.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/parser/Nodes.cpp

    r218957 r221622  
    6565{
    6666    return m_head == m_tail ? m_head : nullptr;
     67}
     68
     69StatementNode* SourceElements::lastStatement() const
     70{
     71    return m_tail;
     72}
     73
     74bool SourceElements::hasCompletionValue() const
     75{
     76    for (StatementNode* statement = m_head; statement; statement = statement->next()) {
     77        if (statement->hasCompletionValue())
     78            return true;
     79    }
     80
     81    return false;
     82}
     83
     84bool SourceElements::hasEarlyBreakOrContinue() const
     85{
     86    for (StatementNode* statement = m_head; statement; statement = statement->next()) {
     87        if (statement->isBreak() || statement->isContinue())
     88            return true;
     89        if (statement->hasCompletionValue())
     90            return false;
     91    }
     92
     93    return false;
     94}
     95
     96// ------------------------------ BlockNode ------------------------------------
     97
     98StatementNode* BlockNode::lastStatement() const
     99{
     100    return m_statements ? m_statements->lastStatement() : nullptr;
     101}
     102
     103StatementNode* BlockNode::singleStatement() const
     104{
     105    return m_statements ? m_statements->singleStatement() : nullptr;
     106}
     107
     108bool BlockNode::hasCompletionValue() const
     109{
     110    return m_statements ? m_statements->hasCompletionValue() : false;
     111}
     112
     113bool BlockNode::hasEarlyBreakOrContinue() const
     114{
     115    return m_statements ? m_statements->hasEarlyBreakOrContinue() : false;
    67116}
    68117
     
    101150StatementNode* ScopeNode::singleStatement() const
    102151{
    103     return m_statements ? m_statements->singleStatement() : 0;
     152    return m_statements ? m_statements->singleStatement() : nullptr;
     153}
     154
     155bool ScopeNode::hasCompletionValue() const
     156{
     157    return m_statements ? m_statements->hasCompletionValue() : false;
     158}
     159
     160bool ScopeNode::hasEarlyBreakOrContinue() const
     161{
     162    return m_statements ? m_statements->hasEarlyBreakOrContinue() : false;
    104163}
    105164
Note: See TracChangeset for help on using the changeset viewer.