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() { }