Diff
Modified: trunk/JSTests/ChangeLog (271264 => 271265)
--- trunk/JSTests/ChangeLog 2021-01-07 23:10:51 UTC (rev 271264)
+++ trunk/JSTests/ChangeLog 2021-01-07 23:17:44 UTC (rev 271265)
@@ -1,5 +1,42 @@
2021-01-07 Yusuke Suzuki <[email protected]>
+ [JSC] New _expression_ and value function call should reserve function register if arguments include assignments
+ https://bugs.webkit.org/show_bug.cgi?id=220429
+ <rdar://problem/70598359>
+
+ Reviewed by Alexey Shvayka.
+
+ * stress/comma-value-func-call-resolve.js: Added.
+ (shouldBe):
+ (fn.x):
+ (fn):
+ * stress/construct-overwritten-variable.js:
+ (shouldThrow):
+ (new.x.x): Deleted.
+ * stress/construct-spread-overwritten-variable-2.js:
+ (shouldThrow):
+ (new.x.x): Deleted.
+ * stress/construct-spread-overwritten-variable.js:
+ (shouldThrow):
+ (new.x.x): Deleted.
+ * stress/destructuring-func-call-resolve.js: Added.
+ (shouldBe):
+ (fn.x):
+ (fn):
+ (fn2.x):
+ (fn2):
+ * stress/resolve-func-call-resolve.js: Added.
+ (shouldBe):
+ (fn.x):
+ (fn):
+ * stress/tagged-template-call-resolve.js: Added.
+ (shouldBe):
+ (fn.x):
+ (fn):
+ * test262/expectations.yaml:
+
+2021-01-07 Yusuke Suzuki <[email protected]>
+
Unreviewed, check ICU header version instead of ICU version
https://bugs.webkit.org/show_bug.cgi?id=220419
Added: trunk/JSTests/stress/comma-value-func-call-resolve.js (0 => 271265)
--- trunk/JSTests/stress/comma-value-func-call-resolve.js (rev 0)
+++ trunk/JSTests/stress/comma-value-func-call-resolve.js 2021-01-07 23:17:44 UTC (rev 271265)
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function fn() {
+ var ok = {};
+ var x = function() {
+ ok.foo = 42;
+ };
+
+ var result = (0, x)(x = 1);
+
+ shouldBe(x, 1);
+ shouldBe(ok.foo, 42);
+}
+
+fn();
Modified: trunk/JSTests/stress/construct-overwritten-variable.js (271264 => 271265)
--- trunk/JSTests/stress/construct-overwritten-variable.js 2021-01-07 23:10:51 UTC (rev 271264)
+++ trunk/JSTests/stress/construct-overwritten-variable.js 2021-01-07 23:17:44 UTC (rev 271265)
@@ -1,6 +1,21 @@
//@ runDefault
-(function(){
+function shouldThrow(func, errorMessage) {
+ var errorThrown = false;
+ var error = null;
+ try {
+ func();
+ } catch (e) {
+ errorThrown = true;
+ error = e;
+ }
+ if (!errorThrown)
+ throw new Error('not thrown');
+ if (String(error) !== errorMessage)
+ throw new Error(`bad error: ${String(error)}`);
+}
+
+shouldThrow(function(){
var x = 42;
new x(x = function(){ });
-})();
+}, `TypeError: 42 is not a constructor (evaluating 'new x(x = function(){ })')`);
Modified: trunk/JSTests/stress/construct-spread-overwritten-variable-2.js (271264 => 271265)
--- trunk/JSTests/stress/construct-spread-overwritten-variable-2.js 2021-01-07 23:10:51 UTC (rev 271264)
+++ trunk/JSTests/stress/construct-spread-overwritten-variable-2.js 2021-01-07 23:17:44 UTC (rev 271265)
@@ -1,6 +1,21 @@
//@ runDefault
-(function(){
+function shouldThrow(func, errorMessage) {
+ var errorThrown = false;
+ var error = null;
+ try {
+ func();
+ } catch (e) {
+ errorThrown = true;
+ error = e;
+ }
+ if (!errorThrown)
+ throw new Error('not thrown');
+ if (String(error) !== errorMessage)
+ throw new Error(`bad error: ${String(error)}`);
+}
+
+shouldThrow(function(){
var x = 42;
new x(...[x = function(){ }]);
-})();
+}, `TypeError: 42 is not a constructor (evaluating 'new x(...[x = function(){ }])')`);
Modified: trunk/JSTests/stress/construct-spread-overwritten-variable.js (271264 => 271265)
--- trunk/JSTests/stress/construct-spread-overwritten-variable.js 2021-01-07 23:10:51 UTC (rev 271264)
+++ trunk/JSTests/stress/construct-spread-overwritten-variable.js 2021-01-07 23:17:44 UTC (rev 271265)
@@ -1,7 +1,22 @@
//@ runDefault
-(function(){
+function shouldThrow(func, errorMessage) {
+ var errorThrown = false;
+ var error = null;
+ try {
+ func();
+ } catch (e) {
+ errorThrown = true;
+ error = e;
+ }
+ if (!errorThrown)
+ throw new Error('not thrown');
+ if (String(error) !== errorMessage)
+ throw new Error(`bad error: ${String(error)}`);
+}
+
+shouldThrow(function(){
var x = 42;
var a = [1, 2, 3];
new x(x = function(){ }, ...a);
-})();
+}, `TypeError: 42 is not a constructor (evaluating 'new x(x = function(){ }, ...a)')`);
Added: trunk/JSTests/stress/destructuring-func-call-resolve.js (0 => 271265)
--- trunk/JSTests/stress/destructuring-func-call-resolve.js (rev 0)
+++ trunk/JSTests/stress/destructuring-func-call-resolve.js 2021-01-07 23:17:44 UTC (rev 271265)
@@ -0,0 +1,31 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function fn() {
+ var ok = {};
+ var x = function() {
+ ok.foo = 42;
+ };
+
+ var result = new x({ x } = { x: 1 });
+
+ shouldBe(x, 1);
+ shouldBe(ok.foo, 42);
+}
+
+function fn2() {
+ var ok = {};
+ var x = function() {
+ ok.foo = 42;
+ };
+
+ var result = new x([ x ] = [ 1 ]);
+
+ shouldBe(x, 1);
+ shouldBe(ok.foo, 42);
+}
+
+fn();
+fn2();
Added: trunk/JSTests/stress/resolve-func-call-resolve.js (0 => 271265)
--- trunk/JSTests/stress/resolve-func-call-resolve.js (rev 0)
+++ trunk/JSTests/stress/resolve-func-call-resolve.js 2021-01-07 23:17:44 UTC (rev 271265)
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function fn() {
+ var ok = {};
+ var x = function() {
+ ok.foo = 42;
+ };
+
+ var result = x(x = 1);
+
+ shouldBe(x, 1);
+ shouldBe(ok.foo, 42);
+}
+
+fn();
Added: trunk/JSTests/stress/tagged-template-call-resolve.js (0 => 271265)
--- trunk/JSTests/stress/tagged-template-call-resolve.js (rev 0)
+++ trunk/JSTests/stress/tagged-template-call-resolve.js 2021-01-07 23:17:44 UTC (rev 271265)
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function fn() {
+ var ok = {};
+ var x = function() {
+ ok.foo = 42;
+ };
+
+ var result = x`_${x = 1}_`
+
+ shouldBe(x, 1);
+ shouldBe(ok.foo, 42);
+}
+
+fn();
Modified: trunk/JSTests/test262/expectations.yaml (271264 => 271265)
--- trunk/JSTests/test262/expectations.yaml 2021-01-07 23:10:51 UTC (rev 271264)
+++ trunk/JSTests/test262/expectations.yaml 2021-01-07 23:17:44 UTC (rev 271265)
@@ -1630,12 +1630,6 @@
default: 'Test262: This statement should not be evaluated.'
test/language/expressions/logical-assignment/lgcl-or-assignment-operator-non-simple-lhs.js:
default: 'Test262: This statement should not be evaluated.'
-test/language/expressions/new/ctorExpr-fn-ref-before-args-eval-fn-wrapup.js:
- default: "TypeError: 1 is not a constructor (evaluating 'new x(x = 1)')"
- strict mode: "TypeError: 1 is not a constructor (evaluating 'new x(x = 1)')"
-test/language/expressions/new/ctorExpr-isCtor-after-args-eval-fn-wrapup.js:
- default: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
- strict mode: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
test/language/expressions/new/non-ctor-err-realm.js:
default: 'Test262Error: production including Arguments Expected a TypeError but got a TypeError'
strict mode: 'Test262Error: production including Arguments Expected a TypeError but got a TypeError'
Modified: trunk/Source/_javascript_Core/ChangeLog (271264 => 271265)
--- trunk/Source/_javascript_Core/ChangeLog 2021-01-07 23:10:51 UTC (rev 271264)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-01-07 23:17:44 UTC (rev 271265)
@@ -1,3 +1,38 @@
+2021-01-07 Yusuke Suzuki <[email protected]>
+
+ [JSC] New _expression_ and value function call should reserve function register if arguments include assignments
+ https://bugs.webkit.org/show_bug.cgi?id=220429
+ <rdar://problem/70598359>
+
+ Reviewed by Alexey Shvayka.
+
+ If the following code is executed, we need to reserve |x| before evaluating arguments since arguments can override
+ local |x| variable before calling it.
+
+ new x(x = 1)
+
+ We found there are two places we are not doing this.
+
+ 1. new _expression_
+ 2. function value call (it is checking `isLocation()`, but we can still use local variables for function if we use comma _expression_)
+
+ We introduced hasAssignment flag to ArgumentsNode, and reserve a function in a new temporary register if arguments include assignments.
+ We also need to increment assignmentCount in destructuring assignment.
+
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::NewExprNode::emitBytecode):
+ (JSC::FunctionCallValueNode::emitBytecode):
+ * parser/ASTBuilder.h:
+ (JSC::ASTBuilder::createArguments):
+ * parser/NodeConstructors.h:
+ (JSC::ArgumentsNode::ArgumentsNode):
+ * parser/Nodes.h:
+ * parser/Parser.cpp:
+ (JSC::Parser<LexerType>::parseDestructuringPattern):
+ (JSC::Parser<LexerType>::parseArguments):
+ * parser/SyntaxChecker.h:
+ (JSC::SyntaxChecker::createArguments):
+
2021-01-07 Mark Lam <[email protected]>
The scratch register should be different from the target register when calling validateUntaggedPtr.
Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (271264 => 271265)
--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2021-01-07 23:10:51 UTC (rev 271264)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2021-01-07 23:17:44 UTC (rev 271265)
@@ -979,7 +979,11 @@
expectedFunction = generator.expectedFunctionForIdentifier(static_cast<ResolveNode*>(m_expr)->identifier());
else
expectedFunction = NoExpectedFunction;
- RefPtr<RegisterID> func = generator.emitNode(m_expr);
+
+ RefPtr<RegisterID> func = nullptr;
+ if (m_args && m_args->hasAssignments())
+ func = generator.newTemporary();
+ func = generator.emitNode(func.get(), m_expr);
RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get());
CallArguments callArguments(generator, m_args);
return generator.emitConstruct(returnValue.get(), func.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd());
@@ -1100,7 +1104,10 @@
return ret;
}
- RefPtr<RegisterID> func = generator.emitNode(m_expr);
+ RefPtr<RegisterID> func = nullptr;
+ if (m_args && m_args->hasAssignments())
+ func = generator.newTemporary();
+ func = generator.emitNode(func.get(), m_expr);
RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get());
if (isOptionalChainBase())
generator.emitOptionalCheck(func.get());
Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (271264 => 271265)
--- trunk/Source/_javascript_Core/parser/ASTBuilder.h 2021-01-07 23:10:51 UTC (rev 271264)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h 2021-01-07 23:17:44 UTC (rev 271265)
@@ -477,7 +477,7 @@
}
ArgumentsNode* createArguments() { return new (m_parserArena) ArgumentsNode(); }
- ArgumentsNode* createArguments(ArgumentListNode* args) { return new (m_parserArena) ArgumentsNode(args); }
+ ArgumentsNode* createArguments(ArgumentListNode* args, bool hasAssignments) { return new (m_parserArena) ArgumentsNode(args, hasAssignments); }
ArgumentListNode* createArgumentsList(const JSTokenLocation& location, ExpressionNode* arg) { return new (m_parserArena) ArgumentListNode(location, arg); }
ArgumentListNode* createArgumentsList(const JSTokenLocation& location, ArgumentListNode* args, ExpressionNode* arg) { return new (m_parserArena) ArgumentListNode(location, args, arg); }
Modified: trunk/Source/_javascript_Core/parser/NodeConstructors.h (271264 => 271265)
--- trunk/Source/_javascript_Core/parser/NodeConstructors.h 2021-01-07 23:10:51 UTC (rev 271264)
+++ trunk/Source/_javascript_Core/parser/NodeConstructors.h 2021-01-07 23:17:44 UTC (rev 271265)
@@ -364,8 +364,9 @@
{
}
- inline ArgumentsNode::ArgumentsNode(ArgumentListNode* listNode)
+ inline ArgumentsNode::ArgumentsNode(ArgumentListNode* listNode, bool hasAssignments)
: m_listNode(listNode)
+ , m_hasAssignments(hasAssignments)
{
}
Modified: trunk/Source/_javascript_Core/parser/Nodes.h (271264 => 271265)
--- trunk/Source/_javascript_Core/parser/Nodes.h 2021-01-07 23:10:51 UTC (rev 271264)
+++ trunk/Source/_javascript_Core/parser/Nodes.h 2021-01-07 23:17:44 UTC (rev 271265)
@@ -914,9 +914,13 @@
class ArgumentsNode final : public ParserArenaFreeable {
public:
ArgumentsNode();
- ArgumentsNode(ArgumentListNode*);
+ ArgumentsNode(ArgumentListNode*, bool hasAssignments);
+ bool hasAssignments() const { return m_hasAssignments; }
+
ArgumentListNode* m_listNode;
+ private:
+ bool m_hasAssignments { false };
};
class NewExprNode final : public ExpressionNode, public ThrowableExpressionData {
Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (271264 => 271265)
--- trunk/Source/_javascript_Core/parser/Parser.cpp 2021-01-07 23:10:51 UTC (rev 271264)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp 2021-01-07 23:17:44 UTC (rev 271265)
@@ -1126,6 +1126,7 @@
template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDestructuringPattern(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth)
{
failIfStackOverflow();
+ m_parserState.assignmentCount++;
int nonLHSCount = m_parserState.nonLHSCount;
TreeDestructuringPattern pattern;
switch (m_token.m_type) {
@@ -4836,6 +4837,7 @@
auto argumentsStart = m_token.m_startPosition;
auto argumentsDivot = m_token.m_endPosition;
+ int initialAssignments = m_parserState.assignmentCount;
ArgumentType argType = ArgumentType::Normal;
TreeExpression firstArg = parseArgument(context, argType);
failIfFalse(firstArg, "Cannot parse function argument");
@@ -4867,10 +4869,10 @@
handleProductionOrFail2(CLOSEPAREN, ")", "end", "argument list");
if (hasSpread) {
TreeExpression spreadArray = context.createSpreadExpression(location, context.createArray(location, context.createElementList(argList)), argumentsStart, argumentsDivot, m_lastTokenEndPosition);
- return context.createArguments(context.createArgumentsList(location, spreadArray));
+ return context.createArguments(context.createArgumentsList(location, spreadArray), initialAssignments != m_parserState.assignmentCount);
}
- return context.createArguments(argList);
+ return context.createArguments(argList, initialAssignments != m_parserState.assignmentCount);
}
template <typename LexerType>
Modified: trunk/Source/_javascript_Core/parser/SyntaxChecker.h (271264 => 271265)
--- trunk/Source/_javascript_Core/parser/SyntaxChecker.h 2021-01-07 23:10:51 UTC (rev 271264)
+++ trunk/Source/_javascript_Core/parser/SyntaxChecker.h 2021-01-07 23:17:44 UTC (rev 271265)
@@ -200,7 +200,7 @@
ExpressionType createMethodDefinition(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
void setFunctionNameStart(int, int) { }
int createArguments() { return ArgumentsResult; }
- int createArguments(int) { return ArgumentsResult; }
+ int createArguments(int, bool) { return ArgumentsResult; }
ExpressionType createSpreadExpression(const JSTokenLocation&, ExpressionType, int, int, int) { return SpreadExpr; }
ExpressionType createObjectSpreadExpression(const JSTokenLocation&, ExpressionType, int, int, int) { return ObjectSpreadExpr; }
TemplateString createTemplateString(const JSTokenLocation&, const Identifier*, const Identifier*) { return TemplateStringResult; }