Title: [255440] trunk
Revision
255440
Author
[email protected]
Date
2020-01-30 11:04:13 -0800 (Thu, 30 Jan 2020)

Log Message

Parser needs to restore unary stack state when backtracking
https://bugs.webkit.org/show_bug.cgi?id=206972

Reviewed by Saam Barati.

JSTests:

* stress/parser-save-state-remove-stale-entries.js: Added.
* stress/parser-syntax-checker-assignments-are-not-resolve-expressions.js: Added.
(foo):

Source/_javascript_Core:

Previously we would try to parse possibly stale unary operator
stack entries after backtracking from a parse error.  This would
cause us to think one token was a different token while reparsing
after backtracking. Additionally, this patch fixes an issue where
the syntax checker would think assignment expressions were resolve
expressions. Intrestingly, this was not tested in test262.

Lastly, I tried adding some assertions to improve help diagnose
when our source text locations are incorrect.

* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::emitExpressionInfo):
* bytecompiler/NodesCodegen.cpp:
(JSC::ThisNode::emitBytecode):
(JSC::ResolveNode::emitBytecode):
(JSC::EmptyVarExpression::emitBytecode):
(JSC::EmptyLetExpression::emitBytecode):
(JSC::ForInNode::emitLoopHeader):
(JSC::ForOfNode::emitBytecode):
(JSC::DefineFieldNode::emitBytecode):
* parser/ASTBuilder.h:
(JSC::ASTBuilder::unaryTokenStackDepth const):
(JSC::ASTBuilder::setUnaryTokenStackDepth):
* parser/Lexer.cpp:
(JSC::Lexer<T>::Lexer):
* parser/Lexer.h:
(JSC::Lexer::setLineNumber):
* parser/Nodes.cpp:
(JSC::FunctionMetadataNode::operator== const):
* parser/Nodes.h:
(JSC::ThrowableExpressionData::ThrowableExpressionData):
(JSC::ThrowableExpressionData::setExceptionSourceCode):
(JSC::ThrowableExpressionData::checkConsistency const):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::isArrowFunctionParameters):
(JSC::Parser<LexerType>::parseSourceElements):
(JSC::Parser<LexerType>::parseModuleSourceElements):
(JSC::Parser<LexerType>::parseStatementListItem):
(JSC::Parser<LexerType>::parseAssignmentElement):
(JSC::Parser<LexerType>::parseForStatement):
(JSC::Parser<LexerType>::maybeParseAsyncFunctionDeclarationStatement):
(JSC::Parser<LexerType>::parseFunctionInfo):
(JSC::Parser<LexerType>::parseClass):
(JSC::Parser<LexerType>::parseExportDeclaration):
(JSC::Parser<LexerType>::parseAssignmentExpression):
(JSC::Parser<LexerType>::parseYieldExpression):
(JSC::Parser<LexerType>::parseProperty):
(JSC::Parser<LexerType>::parseMemberExpression):
(JSC::Parser<LexerType>::parseUnaryExpression):
* parser/Parser.h:
(JSC::Parser::lexCurrentTokenAgainUnderCurrentContext):
(JSC::Parser::internalSaveParserState):
(JSC::Parser::restoreParserState):
(JSC::Parser::internalSaveState):
(JSC::Parser::swapSavePointForError):
(JSC::Parser::createSavePoint):
(JSC::Parser::internalRestoreState):
(JSC::Parser::restoreSavePointWithError):
(JSC::Parser::restoreSavePoint):
(JSC::Parser::createSavePointForError): Deleted.
* parser/ParserTokens.h:
(JSC::JSTextPosition::JSTextPosition):
(JSC::JSTextPosition::checkConsistency):
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::operatorStackPop):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (255439 => 255440)


--- trunk/JSTests/ChangeLog	2020-01-30 18:57:43 UTC (rev 255439)
+++ trunk/JSTests/ChangeLog	2020-01-30 19:04:13 UTC (rev 255440)
@@ -1,3 +1,14 @@
+2020-01-30  Keith Miller  <[email protected]>
+
+        Parser needs to restore unary stack state when backtracking
+        https://bugs.webkit.org/show_bug.cgi?id=206972
+
+        Reviewed by Saam Barati.
+
+        * stress/parser-save-state-remove-stale-entries.js: Added.
+        * stress/parser-syntax-checker-assignments-are-not-resolve-expressions.js: Added.
+        (foo):
+
 2020-01-29  Mark Lam  <[email protected]>
 
         Fix bad assertion in InternalFunctionAllocationProfile::createAllocationStructureFromBase().

Added: trunk/JSTests/stress/parser-save-state-remove-stale-entries.js (0 => 255440)


--- trunk/JSTests/stress/parser-save-state-remove-stale-entries.js	                        (rev 0)
+++ trunk/JSTests/stress/parser-save-state-remove-stale-entries.js	2020-01-30 19:04:13 UTC (rev 255440)
@@ -0,0 +1,10 @@
+// This test ensures we properly remove unary _expression_ stack entries when backtracing in the parser.
+
+try {
+    eval("delete((a=++(b=b)) => {})");
+} catch { }
+
+try {
+    eval("!(({a=(++((t)=((e))))})=>{})");
+} catch { }
+

Added: trunk/JSTests/stress/parser-syntax-checker-assignments-are-not-resolve-expressions.js (0 => 255440)


--- trunk/JSTests/stress/parser-syntax-checker-assignments-are-not-resolve-expressions.js	                        (rev 0)
+++ trunk/JSTests/stress/parser-syntax-checker-assignments-are-not-resolve-expressions.js	2020-01-30 19:04:13 UTC (rev 255440)
@@ -0,0 +1,4 @@
+//@ requireOptions("--exception=SyntaxError") && runDefault
+"use strict";
+
+function foo() { (b=b) = b; }

Modified: trunk/LayoutTests/js/function-toString-parentheses-expected.txt (255439 => 255440)


--- trunk/LayoutTests/js/function-toString-parentheses-expected.txt	2020-01-30 18:57:43 UTC (rev 255439)
+++ trunk/LayoutTests/js/function-toString-parentheses-expected.txt	2020-01-30 19:04:13 UTC (rev 255440)
@@ -211,7 +211,7 @@
 PASS compileAndSerialize('(a || b) || c') is '(a || b) || c'
 PASS compileAndSerialize('a || (b || c)') is 'a || (b || c)'
 PASS compileAndSerialize('a = b = c') is 'a = b = c'
-PASS compileAndSerialize('(a = b) = c') is '(a = b) = c'
+PASS compileAndSerialize("(a = b) = c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a = (b = c)') is 'a = (b = c)'
 PASS compileAndSerialize('a = b + c') is 'a = b + c'
 PASS compileAndSerialize('(a = b) + c') is '(a = b) + c'
@@ -220,10 +220,10 @@
 PASS compileAndSerialize('(a + b) = c') threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a + (b = c)') is 'a + (b = c)'
 PASS compileAndSerialize('a *= b *= c') is 'a *= b *= c'
-PASS compileAndSerialize('(a *= b) *= c') is '(a *= b) *= c'
+PASS compileAndSerialize("(a *= b) *= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a *= (b *= c)') is 'a *= (b *= c)'
 PASS compileAndSerialize('a = b *= c') is 'a = b *= c'
-PASS compileAndSerialize('(a = b) *= c') is '(a = b) *= c'
+PASS compileAndSerialize("(a = b) *= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a = (b *= c)') is 'a = (b *= c)'
 PASS compileAndSerialize('a *= b + c') is 'a *= b + c'
 PASS compileAndSerialize('(a *= b) + c') is '(a *= b) + c'
@@ -232,10 +232,10 @@
 PASS compileAndSerialize('(a + b) *= c') threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a + (b *= c)') is 'a + (b *= c)'
 PASS compileAndSerialize('a /= b /= c') is 'a /= b /= c'
-PASS compileAndSerialize('(a /= b) /= c') is '(a /= b) /= c'
+PASS compileAndSerialize("(a /= b) /= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a /= (b /= c)') is 'a /= (b /= c)'
 PASS compileAndSerialize('a = b /= c') is 'a = b /= c'
-PASS compileAndSerialize('(a = b) /= c') is '(a = b) /= c'
+PASS compileAndSerialize("(a = b) /= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a = (b /= c)') is 'a = (b /= c)'
 PASS compileAndSerialize('a /= b + c') is 'a /= b + c'
 PASS compileAndSerialize('(a /= b) + c') is '(a /= b) + c'
@@ -244,10 +244,10 @@
 PASS compileAndSerialize('(a + b) /= c') threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a + (b /= c)') is 'a + (b /= c)'
 PASS compileAndSerialize('a %= b %= c') is 'a %= b %= c'
-PASS compileAndSerialize('(a %= b) %= c') is '(a %= b) %= c'
+PASS compileAndSerialize("(a %= b) %= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a %= (b %= c)') is 'a %= (b %= c)'
 PASS compileAndSerialize('a = b %= c') is 'a = b %= c'
-PASS compileAndSerialize('(a = b) %= c') is '(a = b) %= c'
+PASS compileAndSerialize("(a = b) %= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a = (b %= c)') is 'a = (b %= c)'
 PASS compileAndSerialize('a %= b + c') is 'a %= b + c'
 PASS compileAndSerialize('(a %= b) + c') is '(a %= b) + c'
@@ -256,10 +256,10 @@
 PASS compileAndSerialize('(a + b) %= c') threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a + (b %= c)') is 'a + (b %= c)'
 PASS compileAndSerialize('a += b += c') is 'a += b += c'
-PASS compileAndSerialize('(a += b) += c') is '(a += b) += c'
+PASS compileAndSerialize("(a += b) += c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a += (b += c)') is 'a += (b += c)'
 PASS compileAndSerialize('a = b += c') is 'a = b += c'
-PASS compileAndSerialize('(a = b) += c') is '(a = b) += c'
+PASS compileAndSerialize("(a = b) += c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a = (b += c)') is 'a = (b += c)'
 PASS compileAndSerialize('a += b + c') is 'a += b + c'
 PASS compileAndSerialize('(a += b) + c') is '(a += b) + c'
@@ -268,10 +268,10 @@
 PASS compileAndSerialize('(a + b) += c') threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a + (b += c)') is 'a + (b += c)'
 PASS compileAndSerialize('a -= b -= c') is 'a -= b -= c'
-PASS compileAndSerialize('(a -= b) -= c') is '(a -= b) -= c'
+PASS compileAndSerialize("(a -= b) -= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a -= (b -= c)') is 'a -= (b -= c)'
 PASS compileAndSerialize('a = b -= c') is 'a = b -= c'
-PASS compileAndSerialize('(a = b) -= c') is '(a = b) -= c'
+PASS compileAndSerialize("(a = b) -= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a = (b -= c)') is 'a = (b -= c)'
 PASS compileAndSerialize('a -= b + c') is 'a -= b + c'
 PASS compileAndSerialize('(a -= b) + c') is '(a -= b) + c'
@@ -280,10 +280,10 @@
 PASS compileAndSerialize('(a + b) -= c') threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a + (b -= c)') is 'a + (b -= c)'
 PASS compileAndSerialize('a <<= b <<= c') is 'a <<= b <<= c'
-PASS compileAndSerialize('(a <<= b) <<= c') is '(a <<= b) <<= c'
+PASS compileAndSerialize("(a <<= b) <<= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a <<= (b <<= c)') is 'a <<= (b <<= c)'
 PASS compileAndSerialize('a = b <<= c') is 'a = b <<= c'
-PASS compileAndSerialize('(a = b) <<= c') is '(a = b) <<= c'
+PASS compileAndSerialize("(a = b) <<= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a = (b <<= c)') is 'a = (b <<= c)'
 PASS compileAndSerialize('a <<= b + c') is 'a <<= b + c'
 PASS compileAndSerialize('(a <<= b) + c') is '(a <<= b) + c'
@@ -292,10 +292,10 @@
 PASS compileAndSerialize('(a + b) <<= c') threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a + (b <<= c)') is 'a + (b <<= c)'
 PASS compileAndSerialize('a >>= b >>= c') is 'a >>= b >>= c'
-PASS compileAndSerialize('(a >>= b) >>= c') is '(a >>= b) >>= c'
+PASS compileAndSerialize("(a >>= b) >>= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a >>= (b >>= c)') is 'a >>= (b >>= c)'
 PASS compileAndSerialize('a = b >>= c') is 'a = b >>= c'
-PASS compileAndSerialize('(a = b) >>= c') is '(a = b) >>= c'
+PASS compileAndSerialize("(a = b) >>= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a = (b >>= c)') is 'a = (b >>= c)'
 PASS compileAndSerialize('a >>= b + c') is 'a >>= b + c'
 PASS compileAndSerialize('(a >>= b) + c') is '(a >>= b) + c'
@@ -304,10 +304,10 @@
 PASS compileAndSerialize('(a + b) >>= c') threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a + (b >>= c)') is 'a + (b >>= c)'
 PASS compileAndSerialize('a >>>= b >>>= c') is 'a >>>= b >>>= c'
-PASS compileAndSerialize('(a >>>= b) >>>= c') is '(a >>>= b) >>>= c'
+PASS compileAndSerialize("(a >>>= b) >>>= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a >>>= (b >>>= c)') is 'a >>>= (b >>>= c)'
 PASS compileAndSerialize('a = b >>>= c') is 'a = b >>>= c'
-PASS compileAndSerialize('(a = b) >>>= c') is '(a = b) >>>= c'
+PASS compileAndSerialize("(a = b) >>>= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a = (b >>>= c)') is 'a = (b >>>= c)'
 PASS compileAndSerialize('a >>>= b + c') is 'a >>>= b + c'
 PASS compileAndSerialize('(a >>>= b) + c') is '(a >>>= b) + c'
@@ -316,10 +316,10 @@
 PASS compileAndSerialize('(a + b) >>>= c') threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a + (b >>>= c)') is 'a + (b >>>= c)'
 PASS compileAndSerialize('a &= b &= c') is 'a &= b &= c'
-PASS compileAndSerialize('(a &= b) &= c') is '(a &= b) &= c'
+PASS compileAndSerialize("(a &= b) &= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a &= (b &= c)') is 'a &= (b &= c)'
 PASS compileAndSerialize('a = b &= c') is 'a = b &= c'
-PASS compileAndSerialize('(a = b) &= c') is '(a = b) &= c'
+PASS compileAndSerialize("(a = b) &= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a = (b &= c)') is 'a = (b &= c)'
 PASS compileAndSerialize('a &= b + c') is 'a &= b + c'
 PASS compileAndSerialize('(a &= b) + c') is '(a &= b) + c'
@@ -328,10 +328,10 @@
 PASS compileAndSerialize('(a + b) &= c') threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a + (b &= c)') is 'a + (b &= c)'
 PASS compileAndSerialize('a ^= b ^= c') is 'a ^= b ^= c'
-PASS compileAndSerialize('(a ^= b) ^= c') is '(a ^= b) ^= c'
+PASS compileAndSerialize("(a ^= b) ^= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a ^= (b ^= c)') is 'a ^= (b ^= c)'
 PASS compileAndSerialize('a = b ^= c') is 'a = b ^= c'
-PASS compileAndSerialize('(a = b) ^= c') is '(a = b) ^= c'
+PASS compileAndSerialize("(a = b) ^= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a = (b ^= c)') is 'a = (b ^= c)'
 PASS compileAndSerialize('a ^= b + c') is 'a ^= b + c'
 PASS compileAndSerialize('(a ^= b) + c') is '(a ^= b) + c'
@@ -340,10 +340,10 @@
 PASS compileAndSerialize('(a + b) ^= c') threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a + (b ^= c)') is 'a + (b ^= c)'
 PASS compileAndSerialize('a |= b |= c') is 'a |= b |= c'
-PASS compileAndSerialize('(a |= b) |= c') is '(a |= b) |= c'
+PASS compileAndSerialize("(a |= b) |= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a |= (b |= c)') is 'a |= (b |= c)'
 PASS compileAndSerialize('a = b |= c') is 'a = b |= c'
-PASS compileAndSerialize('(a = b) |= c') is '(a = b) |= c'
+PASS compileAndSerialize("(a = b) |= c") threw exception SyntaxError: Left side of assignment is not a reference..
 PASS compileAndSerialize('a = (b |= c)') is 'a = (b |= c)'
 PASS compileAndSerialize('a |= b + c') is 'a |= b + c'
 PASS compileAndSerialize('(a |= b) + c') is '(a |= b) + c'

Modified: trunk/LayoutTests/js/script-tests/function-toString-parentheses.js (255439 => 255440)


--- trunk/LayoutTests/js/script-tests/function-toString-parentheses.js	2020-01-30 18:57:43 UTC (rev 255439)
+++ trunk/LayoutTests/js/script-tests/function-toString-parentheses.js	2020-01-30 19:04:13 UTC (rev 255440)
@@ -47,10 +47,13 @@
     testKeepParentheses("a " + opA + " (b " + opB + " c)");
 }
 
-function testRightAssociativeSame(opA, opB)
+function testRightAssociativeSame(opA, opB, leftParensThrows = false)
 {
     testKeepParentheses("a " + opA + " b " + opB + " c");
-    testKeepParentheses("(a " + opA + " b) " + opB + " c");
+    if (leftParensThrows)
+        shouldThrow(`compileAndSerialize("(a ${opA} b) ${opB} c")`);
+    else
+        testKeepParentheses("(a " + opA + " b) " + opB + " c");
     testOptionalParentheses("a " + opA + " (b " + opB + " c)");
 }
 
@@ -99,9 +102,9 @@
 
 for (i = 0; i < assignmentOperators.length; ++i) {
     var op = assignmentOperators[i];
-    testRightAssociativeSame(op, op);
+    testRightAssociativeSame(op, op, true);
     if (i != 0)
-        testRightAssociativeSame("=", op);
+        testRightAssociativeSame("=", op, true);
     testLowerFirst(op, "+");
     shouldThrow("compileAndSerialize('a + b " + op + " c')");
     shouldThrow("compileAndSerialize('(a + b) " + op + " c')");

Modified: trunk/Source/_javascript_Core/ChangeLog (255439 => 255440)


--- trunk/Source/_javascript_Core/ChangeLog	2020-01-30 18:57:43 UTC (rev 255439)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-01-30 19:04:13 UTC (rev 255440)
@@ -1,3 +1,76 @@
+2020-01-30  Keith Miller  <[email protected]>
+
+        Parser needs to restore unary stack state when backtracking
+        https://bugs.webkit.org/show_bug.cgi?id=206972
+
+        Reviewed by Saam Barati.
+
+        Previously we would try to parse possibly stale unary operator
+        stack entries after backtracking from a parse error.  This would
+        cause us to think one token was a different token while reparsing
+        after backtracking. Additionally, this patch fixes an issue where
+        the syntax checker would think assignment expressions were resolve
+        expressions. Intrestingly, this was not tested in test262.
+
+        Lastly, I tried adding some assertions to improve help diagnose
+        when our source text locations are incorrect.
+
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::BytecodeGenerator::emitExpressionInfo):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ThisNode::emitBytecode):
+        (JSC::ResolveNode::emitBytecode):
+        (JSC::EmptyVarExpression::emitBytecode):
+        (JSC::EmptyLetExpression::emitBytecode):
+        (JSC::ForInNode::emitLoopHeader):
+        (JSC::ForOfNode::emitBytecode):
+        (JSC::DefineFieldNode::emitBytecode):
+        * parser/ASTBuilder.h:
+        (JSC::ASTBuilder::unaryTokenStackDepth const):
+        (JSC::ASTBuilder::setUnaryTokenStackDepth):
+        * parser/Lexer.cpp:
+        (JSC::Lexer<T>::Lexer):
+        * parser/Lexer.h:
+        (JSC::Lexer::setLineNumber):
+        * parser/Nodes.cpp:
+        (JSC::FunctionMetadataNode::operator== const):
+        * parser/Nodes.h:
+        (JSC::ThrowableExpressionData::ThrowableExpressionData):
+        (JSC::ThrowableExpressionData::setExceptionSourceCode):
+        (JSC::ThrowableExpressionData::checkConsistency const):
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::isArrowFunctionParameters):
+        (JSC::Parser<LexerType>::parseSourceElements):
+        (JSC::Parser<LexerType>::parseModuleSourceElements):
+        (JSC::Parser<LexerType>::parseStatementListItem):
+        (JSC::Parser<LexerType>::parseAssignmentElement):
+        (JSC::Parser<LexerType>::parseForStatement):
+        (JSC::Parser<LexerType>::maybeParseAsyncFunctionDeclarationStatement):
+        (JSC::Parser<LexerType>::parseFunctionInfo):
+        (JSC::Parser<LexerType>::parseClass):
+        (JSC::Parser<LexerType>::parseExportDeclaration):
+        (JSC::Parser<LexerType>::parseAssignmentExpression):
+        (JSC::Parser<LexerType>::parseYieldExpression):
+        (JSC::Parser<LexerType>::parseProperty):
+        (JSC::Parser<LexerType>::parseMemberExpression):
+        (JSC::Parser<LexerType>::parseUnaryExpression):
+        * parser/Parser.h:
+        (JSC::Parser::lexCurrentTokenAgainUnderCurrentContext):
+        (JSC::Parser::internalSaveParserState):
+        (JSC::Parser::restoreParserState):
+        (JSC::Parser::internalSaveState):
+        (JSC::Parser::swapSavePointForError):
+        (JSC::Parser::createSavePoint):
+        (JSC::Parser::internalRestoreState):
+        (JSC::Parser::restoreSavePointWithError):
+        (JSC::Parser::restoreSavePoint):
+        (JSC::Parser::createSavePointForError): Deleted.
+        * parser/ParserTokens.h:
+        (JSC::JSTextPosition::JSTextPosition):
+        (JSC::JSTextPosition::checkConsistency):
+        * parser/SyntaxChecker.h:
+        (JSC::SyntaxChecker::operatorStackPop):
+
 2020-01-29  Mark Lam  <[email protected]>
 
         Fix bad assertion in InternalFunctionAllocationProfile::createAllocationStructureFromBase().

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (255439 => 255440)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2020-01-30 18:57:43 UTC (rev 255439)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2020-01-30 19:04:13 UTC (rev 255440)
@@ -593,6 +593,9 @@
             ASSERT(divot.offset >= divotStart.offset);
             ASSERT(divotEnd.offset >= divot.offset);
 
+            if (m_isBuiltinFunction)
+                return;
+
             int sourceOffset = m_scopeNode->source().startOffset();
             unsigned firstLine = m_scopeNode->source().firstLine().oneBasedInt();
 
@@ -616,8 +619,7 @@
             unsigned column = divotOffset - lineStart;
 
             unsigned instructionOffset = instructions().size();
-            if (!m_isBuiltinFunction)
-                m_codeBlock->addExpressionInfo(instructionOffset, divotOffset, startOffset, endOffset, line, column);
+            m_codeBlock->addExpressionInfo(instructionOffset, divotOffset, startOffset, endOffset, line, column);
         }
 
 

Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (255439 => 255440)


--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2020-01-30 18:57:43 UTC (rev 255439)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2020-01-30 19:04:13 UTC (rev 255440)
@@ -174,8 +174,8 @@
         return 0;
 
     RegisterID* result = generator.move(dst, generator.thisRegister());
-    static constexpr unsigned thisLength = 4;
-    generator.emitProfileType(generator.thisRegister(), position(), JSTextPosition(-1, position().offset + thisLength, -1));
+    static const unsigned thisLength = strlen("this");
+    generator.emitProfileType(generator.thisRegister(), position(), position() + thisLength);
     return result;
 }
 
@@ -258,7 +258,7 @@
         if (dst == generator.ignoredResult())
             return nullptr;
 
-        generator.emitProfileType(local, var, m_position, JSTextPosition(-1, m_position.offset + m_ident.length(), -1));
+        generator.emitProfileType(local, var, m_position, m_position + m_ident.length());
         return generator.move(dst, local);
     }
     
@@ -270,7 +270,7 @@
     generator.emitGetFromScope(uncheckedResult.get(), scope.get(), var, ThrowIfNotFound);
     generator.emitTDZCheckIfNecessary(var, uncheckedResult.get(), nullptr);
     generator.move(finalDest, uncheckedResult.get());
-    generator.emitProfileType(finalDest, var, m_position, JSTextPosition(-1, m_position.offset + m_ident.length(), -1));
+    generator.emitProfileType(finalDest, var, m_position, m_position + m_ident.length());
     return finalDest;
 }
 
@@ -3088,11 +3088,11 @@
 
     Variable var = generator.variable(m_ident);
     if (RegisterID* local = var.local())
-        generator.emitProfileType(local, var, position(), JSTextPosition(-1, position().offset + m_ident.length(), -1));
+        generator.emitProfileType(local, var, position(), position() + m_ident.length());
     else {
         RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
         RefPtr<RegisterID> value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, DoNotThrowIfNotFound);
-        generator.emitProfileType(value.get(), var, position(), JSTextPosition(-1, position().offset + m_ident.length(), -1));
+        generator.emitProfileType(value.get(), var, position(), position() + m_ident.length());
     }
 
     return nullptr;
@@ -3107,12 +3107,12 @@
     Variable var = generator.variable(m_ident);
     if (RegisterID* local = var.local()) {
         generator.emitLoad(local, jsUndefined());
-        generator.emitProfileType(local, var, position(), JSTextPosition(-1, position().offset + m_ident.length(), -1));
+        generator.emitProfileType(local, var, position(), position() + m_ident.length());
     } else {
         RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
         RefPtr<RegisterID> value = generator.emitLoad(nullptr, jsUndefined());
         generator.emitPutToScope(scope.get(), var, value.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, InitializationMode::Initialization);
-        generator.emitProfileType(value.get(), var, position(), JSTextPosition(-1, position().offset + m_ident.length(), -1)); 
+        generator.emitProfileType(value.get(), var, position(), position() + m_ident.length()); 
     }
 
     generator.liftTDZCheckIfPossible(var);
@@ -3329,7 +3329,7 @@
             generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
             generator.emitPutToScope(scope.get(), var, propertyName, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, InitializationMode::NotInitialization);
         }
-        generator.emitProfileType(propertyName, var, m_lexpr->position(), JSTextPosition(-1, m_lexpr->position().offset + ident.length(), -1));
+        generator.emitProfileType(propertyName, var, m_lexpr->position(), m_lexpr->position() + ident.length());
     };
 
     if (m_lexpr->isResolveNode()) {
@@ -3586,7 +3586,7 @@
                 generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
                 generator.emitPutToScope(scope.get(), var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, InitializationMode::NotInitialization);
             }
-            generator.emitProfileType(value, var, m_lexpr->position(), JSTextPosition(-1, m_lexpr->position().offset + ident.length(), -1));
+            generator.emitProfileType(value, var, m_lexpr->position(), m_lexpr->position() + ident.length());
         } else if (m_lexpr->isDotAccessorNode()) {
             DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr);
             const Identifier& ident = assignNode->identifier();
@@ -4350,7 +4350,7 @@
         RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), var);
         RefPtr<RegisterID> privateName = generator.newTemporary();
         generator.emitGetFromScope(privateName.get(), scope.get(), var, ThrowIfNotFound);
-        generator.emitProfileType(privateName.get(), var, m_position, JSTextPosition(-1, m_position.offset + m_ident->length(), -1));
+        generator.emitProfileType(privateName.get(), var, m_position, m_position + m_ident->length());
         generator.emitCallDefineProperty(generator.thisRegister(), privateName.get(), value.get(), nullptr, nullptr, BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable | BytecodeGenerator::PropertyEnumerable, m_position);
         break;
     }

Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (255439 => 255440)


--- trunk/Source/_javascript_Core/parser/ASTBuilder.h	2020-01-30 18:57:43 UTC (rev 255439)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h	2020-01-30 19:04:13 UTC (rev 255440)
@@ -926,6 +926,16 @@
         tokenStackDepth--;
         m_unaryTokenStack.removeLast();
     }
+
+    int unaryTokenStackDepth() const
+    {
+        return m_unaryTokenStack.size();
+    }
+
+    void setUnaryTokenStackDepth(int oldDepth)
+    {
+        m_unaryTokenStack.shrink(oldDepth);
+    }
     
     void assignmentStackAppend(int& assignmentStackDepth, ExpressionNode* node, const JSTextPosition& start, const JSTextPosition& divot, int assignmentCount, Operator op)
     {

Modified: trunk/Source/_javascript_Core/parser/Lexer.cpp (255439 => 255440)


--- trunk/Source/_javascript_Core/parser/Lexer.cpp	2020-01-30 18:57:43 UTC (rev 255439)
+++ trunk/Source/_javascript_Core/parser/Lexer.cpp	2020-01-30 19:04:13 UTC (rev 255440)
@@ -494,7 +494,8 @@
 
 template <typename T>
 Lexer<T>::Lexer(VM& vm, JSParserBuiltinMode builtinMode, JSParserScriptMode scriptMode)
-    : m_isReparsingFunction(false)
+    : m_positionBeforeLastNewline(0,0,0)
+    , m_isReparsingFunction(false)
     , m_vm(vm)
     , m_parsingBuiltinFunction(builtinMode == JSParserBuiltinMode::Builtin)
     , m_scriptMode(scriptMode)

Modified: trunk/Source/_javascript_Core/parser/Lexer.h (255439 => 255440)


--- trunk/Source/_javascript_Core/parser/Lexer.h	2020-01-30 18:57:43 UTC (rev 255439)
+++ trunk/Source/_javascript_Core/parser/Lexer.h	2020-01-30 19:04:13 UTC (rev 255440)
@@ -109,6 +109,7 @@
     }
     void setLineNumber(int line)
     {
+        ASSERT(line >= 0);
         m_lineNumber = line;
     }
     void setHasLineTerminatorBeforeToken(bool terminator)

Modified: trunk/Source/_javascript_Core/parser/Nodes.cpp (255439 => 255440)


--- trunk/Source/_javascript_Core/parser/Nodes.cpp	2020-01-30 18:57:43 UTC (rev 255439)
+++ trunk/Source/_javascript_Core/parser/Nodes.cpp	2020-01-30 19:04:13 UTC (rev 255440)
@@ -254,7 +254,7 @@
 
 bool FunctionMetadataNode::operator==(const FunctionMetadataNode& other) const
 {
-    return m_parseMode== other.m_parseMode
+    return m_parseMode == other.m_parseMode
         && m_isInStrictContext == other.m_isInStrictContext
         && m_superBinding == other.m_superBinding
         && m_constructorKind == other.m_constructorKind
@@ -261,17 +261,17 @@
         && m_isArrowFunctionBodyExpression == other.m_isArrowFunctionBodyExpression
         && m_ident == other.m_ident
         && m_ecmaName == other.m_ecmaName
-        && m_functionMode== other.m_functionMode
-        && m_startColumn== other.m_startColumn
-        && m_endColumn== other.m_endColumn
-        && m_functionKeywordStart== other.m_functionKeywordStart
-        && m_functionNameStart== other.m_functionNameStart
-        && m_parametersStart== other.m_parametersStart
-        && m_source== other.m_source
-        && m_classSource== other.m_classSource
-        && m_startStartOffset== other.m_startStartOffset
-        && m_parameterCount== other.m_parameterCount
-        && m_lastLine== other.m_lastLine
+        && m_functionMode == other.m_functionMode
+        && m_startColumn == other.m_startColumn
+        && m_endColumn == other.m_endColumn
+        && m_functionKeywordStart == other.m_functionKeywordStart
+        && m_functionNameStart == other.m_functionNameStart
+        && m_parametersStart == other.m_parametersStart
+        && m_source == other.m_source
+        && m_classSource == other.m_classSource
+        && m_startStartOffset == other.m_startStartOffset
+        && m_parameterCount == other.m_parameterCount
+        && m_lastLine == other.m_lastLine
         && m_position == other.m_position;
 }
 

Modified: trunk/Source/_javascript_Core/parser/Nodes.h (255439 => 255440)


--- trunk/Source/_javascript_Core/parser/Nodes.h	2020-01-30 18:57:43 UTC (rev 255439)
+++ trunk/Source/_javascript_Core/parser/Nodes.h	2020-01-30 19:04:13 UTC (rev 255440)
@@ -372,12 +372,7 @@
 
     class ThrowableExpressionData {
     public:
-        ThrowableExpressionData()
-            : m_divot(-1, -1, -1)
-            , m_divotStart(-1, -1, -1)
-            , m_divotEnd(-1, -1, -1)
-        {
-        }
+        ThrowableExpressionData() = default;
         
         ThrowableExpressionData(const JSTextPosition& divot, const JSTextPosition& start, const JSTextPosition& end)
             : m_divot(divot)
@@ -384,19 +379,15 @@
             , m_divotStart(start)
             , m_divotEnd(end)
         {
-            ASSERT(m_divot.offset >= m_divot.lineStartOffset);
-            ASSERT(m_divotStart.offset >= m_divotStart.lineStartOffset);
-            ASSERT(m_divotEnd.offset >= m_divotEnd.lineStartOffset);
+            checkConsistency();
         }
 
         void setExceptionSourceCode(const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
         {
-            ASSERT(divot.offset >= divot.lineStartOffset);
-            ASSERT(divotStart.offset >= divotStart.lineStartOffset);
-            ASSERT(divotEnd.offset >= divotEnd.lineStartOffset);
             m_divot = divot;
             m_divotStart = divotStart;
             m_divotEnd = divotEnd;
+            checkConsistency();
         }
 
         const JSTextPosition& divot() const { return m_divot; }
@@ -403,6 +394,14 @@
         const JSTextPosition& divotStart() const { return m_divotStart; }
         const JSTextPosition& divotEnd() const { return m_divotEnd; }
 
+        void checkConsistency() const
+        {
+            ASSERT(m_divot.offset >= m_divot.lineStartOffset);
+            ASSERT(m_divotStart.offset >= m_divotStart.lineStartOffset);
+            ASSERT(m_divotEnd.offset >= m_divotEnd.lineStartOffset);
+            ASSERT(m_divot.offset >= m_divotStart.offset);
+            ASSERT(m_divotEnd.offset >= m_divot.offset);
+        }
     protected:
         RegisterID* emitThrowReferenceError(BytecodeGenerator&, const String& message);
 
@@ -2133,7 +2132,7 @@
         SourceCode m_classSource;
         int m_startStartOffset;
         unsigned m_parameterCount;
-        int m_lastLine;
+        int m_lastLine { 0 };
     };
 
     class FunctionNode final : public ScopeNode {

Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (255439 => 255440)


--- trunk/Source/_javascript_Core/parser/Parser.cpp	2020-01-30 18:57:43 UTC (rev 255439)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp	2020-01-30 19:04:13 UTC (rev 255440)
@@ -29,6 +29,7 @@
 #include "JSCInlines.h"
 #include "VM.h"
 #include <utility>
+#include <wtf/Scope.h>
 #include <wtf/SetForScope.h>
 #include <wtf/StringPrintStream.h>
 
@@ -306,10 +307,10 @@
 }
 
 template <typename LexerType>
-bool Parser<LexerType>::isArrowFunctionParameters()
+template <class TreeBuilder> bool Parser<LexerType>::isArrowFunctionParameters(TreeBuilder& context)
 {
     if (match(OPENPAREN)) {
-        SavePoint saveArrowFunctionPoint = createSavePoint();
+        SavePoint saveArrowFunctionPoint = createSavePoint(context);
         next();
         bool isArrowFunction = false;
         if (match(CLOSEPAREN)) {
@@ -328,16 +329,16 @@
             propagateError();
             popScope(fakeScope, syntaxChecker.NeedsFreeVariableInfo);
         }
-        restoreSavePoint(saveArrowFunctionPoint);
+        restoreSavePoint(context, saveArrowFunctionPoint);
         return isArrowFunction;
     }
 
     if (matchSpecIdentifier()) {
         semanticFailIfTrue(!m_parserState.allowAwait && match(AWAIT), "Cannot use 'await' as a parameter name in an async function");
-        SavePoint saveArrowFunctionPoint = createSavePoint();
+        SavePoint saveArrowFunctionPoint = createSavePoint(context);
         next();
         bool isArrowFunction = match(ARROWFUNCTION);
-        restoreSavePoint(saveArrowFunctionPoint);
+        restoreSavePoint(context, saveArrowFunctionPoint);
         return isArrowFunction;
     }
 
@@ -357,7 +358,7 @@
     TreeSourceElements sourceElements = context.createSourceElements();
     const Identifier* directive = 0;
     unsigned directiveLiteralLength = 0;
-    auto savePoint = createSavePoint();
+    auto savePoint = createSavePoint(context);
     bool shouldCheckForUseStrict = mode == CheckForStrictMode;
     
     while (TreeStatement statement = parseStatementListItem(context, directive, &directiveLiteralLength)) {
@@ -382,7 +383,7 @@
                         semanticFailIfFalse(isValidStrictMode(), "Invalid parameters or function name in strict mode");
                     }
                     // Since strict mode is changed, restoring lexer state by calling next() may cause errors.
-                    restoreSavePoint(savePoint);
+                    restoreSavePoint(context, savePoint);
                     propagateError();
                     continue;
                 }
@@ -420,10 +421,10 @@
             break;
 
         case IMPORT: {
-            SavePoint savePoint = createSavePoint();
+            SavePoint savePoint = createSavePoint(context);
             next();
             bool isImportDeclaration = !match(OPENPAREN) && !match(DOT);
-            restoreSavePoint(savePoint);
+            restoreSavePoint(context, savePoint);
             if (isImportDeclaration) {
                 statement = parseImportDeclaration(context);
                 if (statement)
@@ -667,7 +668,7 @@
     case LET: {
         bool shouldParseVariableDeclaration = true;
         if (!strictMode()) {
-            SavePoint savePoint = createSavePoint();
+            SavePoint savePoint = createSavePoint(context);
             next();
             // Intentionally use `isIdentifierOrAnyContextualKeyword(m_token)` and don't use `matchSpecIdentifier()`.
             // We would like to fall into parseVariableDeclaration path even if "yield" is not treated as an Identifier.
@@ -676,7 +677,7 @@
             // to raise consistent errors between "var", "const" and "let".
             if (!isIdentifierOrAnyContextualKeyword(m_token) && !match(OPENBRACE) && !match(OPENBRACKET))
                 shouldParseVariableDeclaration = false;
-            restoreSavePoint(savePoint);
+            restoreSavePoint(context, savePoint);
         }
         if (shouldParseVariableDeclaration)
             result = parseVariableDeclaration(context, DeclarationType::LetDeclaration);
@@ -697,13 +698,13 @@
         if (UNLIKELY(*m_token.m_data.ident == m_vm.propertyNames->async && !m_token.m_data.escaped)) {
             // Eagerly parse as AsyncFunctionDeclaration. This is the uncommon case,
             // but could be mistakenly parsed as an AsyncFunctionExpression.
-            SavePoint savePoint = createSavePoint();
+            SavePoint savePoint = createSavePoint(context);
             next();
             if (UNLIKELY(match(FUNCTION) && !m_lexer->hasLineTerminatorBeforeToken())) {
                 result = parseAsyncFunctionDeclaration(context);
                 break;
             }
-            restoreSavePoint(savePoint);
+            restoreSavePoint(context, savePoint);
         }
         FALLTHROUGH;
     case AWAIT:
@@ -1042,11 +1043,11 @@
     TreeDestructuringPattern assignmentTarget = 0;
 
     if (match(OPENBRACE) || match(OPENBRACKET)) {
-        SavePoint savePoint = createSavePoint();
+        SavePoint savePoint = createSavePoint(context);
         assignmentTarget = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth);
         if (assignmentTarget && !match(DOT) && !match(OPENBRACKET) && !match(OPENPAREN) && !match(BACKQUOTE))
             return assignmentTarget;
-        restoreSavePoint(savePoint);
+        restoreSavePoint(context, savePoint);
     }
 
     JSTextPosition startPosition = tokenStartPosition();
@@ -1431,7 +1432,7 @@
     
     if (!match(SEMICOLON)) {
         if (match(OPENBRACE) || match(OPENBRACKET)) {
-            SavePoint savePoint = createSavePoint();
+            SavePoint savePoint = createSavePoint(context);
             declsStart = tokenStartPosition();
             pattern = tryParseDestructuringPatternExpression(context, AssignmentContext::DeclarationStatement);
             declsEnd = lastTokenEndPosition();
@@ -1438,7 +1439,7 @@
             if (pattern && (match(INTOKEN) || matchContextualKeyword(m_vm.propertyNames->of)))
                 goto enumerationLoop;
             pattern = TreeDestructuringPattern(0);
-            restoreSavePoint(savePoint);
+            restoreSavePoint(context, savePoint);
         }
         m_allowsIn = false;
         declsStart = tokenStartPosition();
@@ -2027,7 +2028,7 @@
 template <class TreeBuilder> bool Parser<LexerType>::maybeParseAsyncFunctionDeclarationStatement(TreeBuilder& context, TreeStatement& result, bool parentAllowsFunctionDeclarationAsStatement)
 {
     ASSERT(matchContextualKeyword(m_vm.propertyNames->async));
-    SavePoint savePoint = createSavePoint();
+    SavePoint savePoint = createSavePoint(context);
     next();
     if (match(FUNCTION) && !m_lexer->hasLineTerminatorBeforeToken()) {
         const bool isAsync = true;
@@ -2034,7 +2035,7 @@
         result = parseFunctionDeclarationStatement(context, isAsync, parentAllowsFunctionDeclarationAsStatement);
         return true;
     }
-    restoreSavePoint(savePoint);
+    restoreSavePoint(context, savePoint);
     return false;
 }
 
@@ -2520,7 +2521,7 @@
     functionScope->setExpectedSuperBinding(expectedSuperBinding);
 
     m_parserState.lastFunctionName = lastFunctionName;
-    ParserState oldState = internalSaveParserState();
+    ParserState oldState = internalSaveParserState(context);
 
     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=156962
     // This loop collects the set of capture candidates that aren't
@@ -2573,7 +2574,7 @@
     } else
         functionInfo.body = performParsingFunctionBody();
     
-    restoreParserState(oldState);
+    restoreParserState(context, oldState);
     failIfFalse(functionInfo.body, "Cannot parse the body of this ", stringForFunctionMode(mode));
     context.setEndOffset(functionInfo.body, m_lexer->currentOffset());
     if (functionScope->strictMode() && requirements != FunctionNameRequirements::Unnamed) {
@@ -2634,7 +2635,7 @@
         // So we only check TreeBuilder's type here.
         ASSERT_UNUSED(functionScopeWasStrictMode, functionScopeWasStrictMode == currentScope()->strictMode());
         if (!std::is_same<TreeBuilder, SyntaxChecker>::value)
-            lexCurrentTokenAgainUnderCurrentContext();
+            lexCurrentTokenAgainUnderCurrentContext(context);
     }
 
     if (newInfo)
@@ -2864,11 +2865,11 @@
         ClassElementTag tag = ClassElementTag::Instance;
         auto type = PropertyNode::Constant;
         if (match(RESERVED_IF_STRICT) && *m_token.m_data.ident == m_vm.propertyNames->staticKeyword) {
-            SavePoint savePoint = createSavePoint();
+            SavePoint savePoint = createSavePoint(context);
             next();
             if (match(OPENPAREN)) {
                 // Reparse "static()" as a method named "static".
-                restoreSavePoint(savePoint);
+                restoreSavePoint(context, savePoint);
             } else
                 tag = ClassElementTag::Static;
         }
@@ -3494,7 +3495,7 @@
 
         bool startsWithFunction = match(FUNCTION);
         if (startsWithFunction || match(CLASSTOKEN)) {
-            SavePoint savePoint = createSavePoint();
+            SavePoint savePoint = createSavePoint(context);
             isFunctionOrClassDeclaration = true;
             next();
 
@@ -3503,9 +3504,9 @@
                 next();
             if (match(IDENT))
                 localName = m_token.m_data.ident;
-            restoreSavePoint(savePoint);
+            restoreSavePoint(context, savePoint);
         } else if (matchContextualKeyword(m_vm.propertyNames->async)) {
-            SavePoint savePoint = createSavePoint();
+            SavePoint savePoint = createSavePoint(context);
             next();
             if (match(FUNCTION) && !m_lexer->hasLineTerminatorBeforeToken()) {
                 next();
@@ -3513,7 +3514,7 @@
                     localName = m_token.m_data.ident;
                 isFunctionOrClassDeclaration = true;
             }
-            restoreSavePoint(savePoint);
+            restoreSavePoint(context, savePoint);
         }
 
         if (!localName)
@@ -3759,7 +3760,7 @@
     // Whether spec identifier is will be validated by isArrowFunctionParameters().
     bool wasIdentifierOrKeyword = isIdentifierOrKeyword(m_token);
     bool maybeValidArrowFunctionStart = wasOpenParen || wasIdentifierOrKeyword;
-    SavePoint savePoint = createSavePoint();
+    SavePoint savePoint = createSavePoint(context);
     size_t usedVariablesSize = 0;
 
     if (wasOpenParen) {
@@ -3772,8 +3773,7 @@
     if (maybeValidArrowFunctionStart && !match(EOFTOK)) {
         bool isArrowFunctionToken = match(ARROWFUNCTION);
         if (!lhs || isArrowFunctionToken) {
-            SavePointWithError errorRestorationSavePoint = createSavePointForError();
-            restoreSavePoint(savePoint);
+            SavePointWithError errorRestorationSavePoint = swapSavePointForError(context, savePoint);
             bool isAsyncArrow = false;
             if (UNLIKELY(classifier.indicatesPossibleAsyncArrowFunction())) {
                 if (matchContextualKeyword(m_vm.propertyNames->async)) {
@@ -3781,7 +3781,7 @@
                     isAsyncArrow = !m_lexer->hasLineTerminatorBeforeToken();
                 }
             }
-            if (isArrowFunctionParameters()) {
+            if (isArrowFunctionParameters(context)) {
                 if (wasOpenParen)
                     currentScope()->revertToPreviousUsedVariables(usedVariablesSize);
                 return parseArrowFunctionExpression(context, isAsyncArrow);
@@ -3788,7 +3788,7 @@
             }
             if (isArrowFunctionToken)
                 propagateError();
-            restoreSavePointWithError(errorRestorationSavePoint);
+            restoreSavePointWithError(context, errorRestorationSavePoint);
             if (isArrowFunctionToken)
                 failDueToUnexpectedToken();
         }
@@ -3798,11 +3798,10 @@
         propagateError();
 
     if (maybeAssignmentPattern && (!lhs || (context.isObjectOrArrayLiteral(lhs) && match(EQUAL)))) {
-        SavePointWithError expressionErrorLocation = createSavePointForError();
-        restoreSavePoint(savePoint);
+        SavePointWithError expressionErrorLocation = swapSavePointForError(context, savePoint);
         auto pattern = tryParseDestructuringPatternExpression(context, AssignmentContext::AssignmentExpression);
         if (classifier.indicatesPossiblePattern() && (!pattern || !match(EQUAL))) {
-            restoreSavePointWithError(expressionErrorLocation);
+            restoreSavePointWithError(context, expressionErrorLocation);
             return 0;
         }
         failIfFalse(pattern, "Cannot parse assignment pattern");
@@ -3867,9 +3866,6 @@
     if (hadAssignment)
         m_parserState.nonLHSCount++;
     
-    if (!TreeBuilder::CreatesAST)
-        return lhs;
-    
     while (assignmentStack)
         lhs = context.createAssignment(location, assignmentStack, lhs, initialAssignmentCount, m_parserState.assignmentCount, lastTokenEndPosition());
     
@@ -3893,7 +3889,7 @@
     JSTokenLocation location(tokenLocation());
     JSTextPosition divotStart = tokenStartPosition();
     ASSERT(match(YIELD));
-    SavePoint savePoint = createSavePoint();
+    SavePoint savePoint = createSavePoint(context);
     next();
     if (m_lexer->hasLineTerminatorBeforeToken())
         return context.createYield(location);
@@ -3902,7 +3898,7 @@
     JSTextPosition argumentStart = tokenStartPosition();
     TreeExpression argument = parseAssignmentExpression(context);
     if (!argument) {
-        restoreSavePoint(savePoint);
+        restoreSavePoint(context, savePoint);
         next();
         return context.createYield(location);
     }
@@ -4057,11 +4053,11 @@
     case IDENT:
         if (UNLIKELY(*m_token.m_data.ident == m_vm.propertyNames->async && !m_token.m_data.escaped)) {
             if (parseMode == SourceParseMode::MethodMode) {
-                SavePoint savePoint = createSavePoint();
+                SavePoint savePoint = createSavePoint(context);
                 next();
 
                 if (match(COLON) || match(OPENPAREN) || match(COMMA) || match(CLOSEBRACE)) {
-                    restoreSavePoint(savePoint);
+                    restoreSavePoint(context, savePoint);
                     wasIdent = true;
                     goto namedProperty;
                 }
@@ -4856,13 +4852,13 @@
             optionalChainBase = base;
             optionalChainLocation = tokenLocation();
 
-            SavePoint savePoint = createSavePoint();
+            SavePoint savePoint = createSavePoint(context);
             next();
             if (match(OPENBRACKET) || match(OPENPAREN) || match(BACKQUOTE))
                 type = m_token.m_type;
             else {
                 type = DOT;
-                restoreSavePoint(savePoint);
+                restoreSavePoint(context, savePoint);
             }
         }
 
@@ -5042,19 +5038,15 @@
 
     JSTokenLocation location(tokenLocation());
 
+    int oldTokenStackDepth = context.unaryTokenStackDepth();
+    makeScopeExit([&] {
+        ASSERT_UNUSED(oldTokenStackDepth, oldTokenStackDepth <= context.unaryTokenStackDepth());
+    });
+
     while (isUnaryOp(m_token.m_type)) {
-        switch (m_token.m_type) {
-        case PLUSPLUS:
-        case MINUSMINUS:
-        case AUTOPLUSPLUS:
-        case AUTOMINUSMINUS:
-            semanticFailIfTrue(hasPrefixUpdateOp, "The ", operatorString(true, lastOperator), " operator requires a reference _expression_");
+        semanticFailIfTrue(hasPrefixUpdateOp, "The ", operatorString(true, lastOperator), " operator requires a reference _expression_");
+        if (isUpdateOp(m_token.m_type))
             hasPrefixUpdateOp = true;
-            break;
-        default:
-            semanticFailIfTrue(hasPrefixUpdateOp, "The ", operatorString(true, lastOperator), " operator requires a reference _expression_");
-            break;
-        }
         lastOperator = m_token.m_type;
         m_parserState.nonLHSCount++;
         context.appendUnaryToken(tokenStackDepth, m_token.m_type, tokenStartPosition());
@@ -5069,6 +5061,8 @@
             failWithMessage("Cannot parse subexpression of ", operatorString(true, lastOperator), "operator");
         failWithMessage("Cannot parse member _expression_");
     }
+    if constexpr (std::is_same_v<TreeBuilder, ASTBuilder>)
+        ASSERT(oldTokenStackDepth + tokenStackDepth == context.unaryTokenStackDepth());
     if (isUpdateOp(static_cast<JSTokenType>(lastOperator))) {
         semanticFailIfTrue(context.isMetaProperty(expr), metaPropertyName(context, expr), " can't come after a prefix operator");
         semanticFailIfFalse(isSimpleAssignmentTarget(context, expr), "Prefix ", lastOperator == PLUSPLUS ? "++" : "--", " operator applied to value that is not a reference");
@@ -5108,7 +5102,9 @@
     
     JSTextPosition end = lastTokenEndPosition();
     while (tokenStackDepth) {
-        switch (context.unaryTokenStackLastType(tokenStackDepth)) {
+        subExprStart = context.unaryTokenStackLastStart(tokenStackDepth);
+        auto tokenType = context.unaryTokenStackLastType(tokenStackDepth);
+        switch (tokenType) {
         case EXCLAMATION:
             expr = context.createLogicalNot(location, expr);
             break;
@@ -5123,12 +5119,14 @@
             break;
         case PLUSPLUS:
         case AUTOPLUSPLUS:
-            expr = context.makePrefixNode(location, expr, OpPlusPlus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
+            ASSERT(isSimpleAssignmentTarget(context, expr));
+            expr = context.makePrefixNode(location, expr, OpPlusPlus, subExprStart, subExprStart + 2, end);
             m_parserState.assignmentCount++;
             break;
         case MINUSMINUS:
         case AUTOMINUSMINUS:
-            expr = context.makePrefixNode(location, expr, OpMinusMinus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
+            ASSERT(isSimpleAssignmentTarget(context, expr));
+            expr = context.makePrefixNode(location, expr, OpMinusMinus, subExprStart, subExprStart + 2, end);
             m_parserState.assignmentCount++;
             break;
         case TYPEOF:
@@ -5145,7 +5143,6 @@
             // If we get here something has gone horribly horribly wrong
             CRASH();
         }
-        subExprStart = context.unaryTokenStackLastStart(tokenStackDepth);
         context.unaryTokenStackRemoveLast(tokenStackDepth);
     }
     return expr;

Modified: trunk/Source/_javascript_Core/parser/Parser.h (255439 => 255440)


--- trunk/Source/_javascript_Core/parser/Parser.h	2020-01-30 18:57:43 UTC (rev 255439)
+++ trunk/Source/_javascript_Core/parser/Parser.h	2020-01-30 19:04:13 UTC (rev 255440)
@@ -1417,10 +1417,11 @@
         m_token.m_type = m_lexer->lexExpectIdentifier(&m_token, lexerFlags, strictMode());
     }
 
-    ALWAYS_INLINE void lexCurrentTokenAgainUnderCurrentContext()
+    template <class TreeBuilder>
+    ALWAYS_INLINE void lexCurrentTokenAgainUnderCurrentContext(TreeBuilder& context)
     {
-        auto savePoint = createSavePoint();
-        restoreSavePoint(savePoint);
+        auto savePoint = createSavePoint(context);
+        restoreSavePoint(context, savePoint);
     }
 
     ALWAYS_INLINE bool nextTokenIsColon()
@@ -1685,7 +1686,7 @@
     enum class FunctionDefinitionType { _expression_, Declaration, Method };
     template <class TreeBuilder> NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionNameRequirements, SourceParseMode, bool nameIsInContainingScope, ConstructorKind, SuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>&, FunctionDefinitionType, Optional<int> functionConstructorParametersEndPosition = WTF::nullopt);
     
-    ALWAYS_INLINE bool isArrowFunctionParameters();
+    template <class TreeBuilder> ALWAYS_INLINE bool isArrowFunctionParameters(TreeBuilder&);
     
     template <class TreeBuilder, class FunctionInfoType> NEVER_INLINE typename TreeBuilder::FormalParameterList parseFunctionParameters(TreeBuilder&, SourceParseMode, FunctionInfoType&);
     template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::FormalParameterList createGeneratorParameters(TreeBuilder&, unsigned& parameterCount);
@@ -1791,6 +1792,7 @@
         int assignmentCount { 0 };
         int nonLHSCount { 0 };
         int nonTrivialExpressionCount { 0 };
+        int unaryTokenStackDepth { 0 };
         FunctionParsePhase functionParsePhase { FunctionParsePhase::Body };
         const Identifier* lastIdentifier { nullptr };
         const Identifier* lastFunctionName { nullptr };
@@ -1800,14 +1802,19 @@
 
     // If you're using this directly, you probably should be using
     // createSavePoint() instead.
-    ALWAYS_INLINE ParserState internalSaveParserState()
+    template <class TreeBuilder>
+    ALWAYS_INLINE ParserState internalSaveParserState(TreeBuilder& context)
     {
-        return m_parserState;
+        auto parserState = m_parserState;
+        parserState.unaryTokenStackDepth = context.unaryTokenStackDepth();
+        return parserState;
     }
 
-    ALWAYS_INLINE void restoreParserState(const ParserState& state)
+    template <class TreeBuilder>
+    ALWAYS_INLINE void restoreParserState(TreeBuilder& context, const ParserState& state)
     {
         m_parserState = state;
+        context.setUnaryTokenStackDepth(m_parserState.unaryTokenStackDepth);
     }
 
     struct LexerState {
@@ -1855,47 +1862,56 @@
         String parserErrorMessage;
     };
 
-    ALWAYS_INLINE void internalSaveState(SavePoint& savePoint)
+    template <class TreeBuilder>
+    ALWAYS_INLINE void internalSaveState(TreeBuilder& context, SavePoint& savePoint)
     {
-        savePoint.parserState = internalSaveParserState();
+        savePoint.parserState = internalSaveParserState(context);
         savePoint.lexerState = internalSaveLexerState();
     }
     
-    ALWAYS_INLINE SavePointWithError createSavePointForError()
+    template <class TreeBuilder>
+    ALWAYS_INLINE SavePointWithError swapSavePointForError(TreeBuilder& context, SavePoint& oldSavePoint)
     {
         SavePointWithError savePoint;
-        internalSaveState(savePoint);
+        internalSaveState(context, savePoint);
         savePoint.lexerError = m_lexer->sawError();
         savePoint.lexerErrorMessage = m_lexer->getErrorMessage();
         savePoint.parserErrorMessage = m_errorMessage;
+        // Make sure we set our new savepoints unary stack to what oldSavePoint had as it currently may contain stale info.
+        savePoint.parserState.unaryTokenStackDepth = oldSavePoint.parserState.unaryTokenStackDepth;
+        restoreSavePoint(context, oldSavePoint);
         return savePoint;
     }
     
-    ALWAYS_INLINE SavePoint createSavePoint()
+    template <class TreeBuilder>
+    ALWAYS_INLINE SavePoint createSavePoint(TreeBuilder& context)
     {
         ASSERT(!hasError());
         SavePoint savePoint;
-        internalSaveState(savePoint);
+        internalSaveState(context, savePoint);
         return savePoint;
     }
 
-    ALWAYS_INLINE void internalRestoreState(const SavePoint& savePoint)
+    template <class TreeBuilder>
+    ALWAYS_INLINE void internalRestoreState(TreeBuilder& context, const SavePoint& savePoint)
     {
         restoreLexerState(savePoint.lexerState);
-        restoreParserState(savePoint.parserState);
+        restoreParserState(context, savePoint.parserState);
     }
 
-    ALWAYS_INLINE void restoreSavePointWithError(const SavePointWithError& savePoint)
+    template <class TreeBuilder>
+    ALWAYS_INLINE void restoreSavePointWithError(TreeBuilder& context, const SavePointWithError& savePoint)
     {
-        internalRestoreState(savePoint);
+        internalRestoreState(context, savePoint);
         m_lexer->setSawError(savePoint.lexerError);
         m_lexer->setErrorMessage(savePoint.lexerErrorMessage);
         m_errorMessage = savePoint.parserErrorMessage;
     }
 
-    ALWAYS_INLINE void restoreSavePoint(const SavePoint& savePoint)
+    template <class TreeBuilder>
+    ALWAYS_INLINE void restoreSavePoint(TreeBuilder& context, const SavePoint& savePoint)
     {
-        internalRestoreState(savePoint);
+        internalRestoreState(context, savePoint);
         m_errorMessage = String();
     }
 

Modified: trunk/Source/_javascript_Core/parser/ParserTokens.h (255439 => 255440)


--- trunk/Source/_javascript_Core/parser/ParserTokens.h	2020-01-30 18:57:43 UTC (rev 255439)
+++ trunk/Source/_javascript_Core/parser/ParserTokens.h	2020-01-30 19:04:13 UTC (rev 255440)
@@ -197,7 +197,13 @@
 
 struct JSTextPosition {
     JSTextPosition() = default;
-    JSTextPosition(int _line, int _offset, int _lineStartOffset) : line(_line), offset(_offset), lineStartOffset(_lineStartOffset) { }
+    JSTextPosition(int _line, int _offset, int _lineStartOffset) 
+        : line(_line)
+        , offset(_offset)
+        , lineStartOffset(_lineStartOffset)
+    { 
+        checkConsistency();
+    }
 
     JSTextPosition operator+(int adjustment) const { return JSTextPosition(line, offset + adjustment, lineStartOffset); }
     JSTextPosition operator+(unsigned adjustment) const { return *this + static_cast<int>(adjustment); }
@@ -218,10 +224,18 @@
     }
 
     int column() const { return offset - lineStartOffset; }
+    void checkConsistency()
+    {
+        // FIXME: We should test ASSERT(offset >= lineStartOffset); but that breaks a lot of tests.
+        ASSERT(line >= 0);
+        ASSERT(offset >= 0);
+        ASSERT(lineStartOffset >= 0);
+    }
 
-    int line { 0 };
-    int offset { 0 };
-    int lineStartOffset { 0 };
+    // FIXME: these should be unsigned.
+    int line { -1 };
+    int offset { -1 };
+    int lineStartOffset { -1 };
 };
 
 union JSTokenData {

Modified: trunk/Source/_javascript_Core/parser/SyntaxChecker.h (255439 => 255440)


--- trunk/Source/_javascript_Core/parser/SyntaxChecker.h	2020-01-30 18:57:43 UTC (rev 255439)
+++ trunk/Source/_javascript_Core/parser/SyntaxChecker.h	2020-01-30 19:04:13 UTC (rev 255440)
@@ -334,9 +334,11 @@
     int unaryTokenStackLastType(int&) { return m_topUnaryToken; }
     JSTextPosition unaryTokenStackLastStart(int&) { return JSTextPosition(0, 0, 0); }
     void unaryTokenStackRemoveLast(int& stackDepth) { stackDepth = 0; }
+    int unaryTokenStackDepth() const { return 0; }
+    void setUnaryTokenStackDepth(int) { }
     
-    void assignmentStackAppend(int, int, int, int, int, Operator) { }
-    int createAssignment(const JSTokenLocation&, int, int, int, int, int) { RELEASE_ASSERT_NOT_REACHED(); return AssignmentExpr; }
+    void assignmentStackAppend(int& assignmentStackDepth, int, int, int, int, Operator) { assignmentStackDepth = 1; }
+    int createAssignment(const JSTokenLocation&, int& assignmentStackDepth, int, int, int, int) { assignmentStackDepth = 0; return AssignmentExpr; }
     const Identifier* getName(const Property& property) const { return property.name; }
     PropertyNode::Type getType(const Property& property) const { return property.type; }
     bool isResolve(ExpressionType expr) const { return expr == ResolveExpr || expr == ResolveEvalExpr; }
@@ -435,7 +437,7 @@
     int endOffset(int) { return 0; }
     void setStartOffset(int, int) { }
 
-    JSTextPosition breakpointLocation(int) { return JSTextPosition(-1, 0, 0); }
+    JSTextPosition breakpointLocation(int) { return { }; }
 
     void propagateArgumentsUse() { }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to