Diff
Modified: trunk/JSTests/ChangeLog (215452 => 215453)
--- trunk/JSTests/ChangeLog 2017-04-18 06:05:25 UTC (rev 215452)
+++ trunk/JSTests/ChangeLog 2017-04-18 06:43:54 UTC (rev 215453)
@@ -1,3 +1,22 @@
+2017-04-17 Saam Barati <[email protected]>
+
+ BytecodeGenerator ".call" and ".apply" is exponential in nesting depth
+ https://bugs.webkit.org/show_bug.cgi?id=139847
+ <rdar://problem/19321122>
+
+ Reviewed by Oliver Hunt.
+
+ * stress/call-apply-exponential-bytecode-size.js: Added.
+ (assert):
+ (const.inc):
+ (const.inc2):
+ (bar):
+ (randomApplyOrCall):
+ (baz):
+ (jaz):
+ (haz):
+ (foo):
+
2017-04-17 Mark Lam <[email protected]>
JSArray::appendMemcpy() needs to handle copying from Undecided indexing type too.
Added: trunk/JSTests/stress/call-apply-exponential-bytecode-size.js (0 => 215453)
--- trunk/JSTests/stress/call-apply-exponential-bytecode-size.js (rev 0)
+++ trunk/JSTests/stress/call-apply-exponential-bytecode-size.js 2017-04-18 06:43:54 UTC (rev 215453)
@@ -0,0 +1,104 @@
+"use strict";
+
+function assert(b) {
+ if (!b)
+ throw new Error();
+}
+
+const inc = (x, y) => { return x + 1; }
+const inc2 = (x, y) => { return y ? y + 1 : x + 1; }
+function bar() {
+ return inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, 1)))))))))))))))))))));
+}
+assert(bar() === 22);
+
+function randomApplyOrCall(bias, size, dontSpreadBias = 0) {
+ let cur = `1`;
+ for (let i = 0; i < size; ++i) {
+ if (Math.random() >= bias) {
+ if (Math.random() >= dontSpreadBias)
+ cur = `inc.call(null, ${cur})`;
+ else
+ cur = `inc.call(...[null, ${cur}])`;
+ } else {
+ if (Math.random() >= dontSpreadBias)
+ cur = `inc.apply(null, [${cur}])`;
+ else
+ cur = `inc.apply(...[null, [${cur}]])`;
+ }
+ }
+
+ if (bias > 0.85) {
+ cur = `let random = ${Math.random()}; ${cur}`;
+ }
+
+ return eval(cur);
+}
+
+assert(randomApplyOrCall(0, 250) === 251);
+assert(randomApplyOrCall(1, 250) === 251);
+assert(randomApplyOrCall(0, 250, 0) === 251);
+assert(randomApplyOrCall(1, 250, 1) === 251);
+for (let i = 0; i < 1000; ++i) {
+ assert(randomApplyOrCall(Math.random(), 250) === 251);
+ assert(randomApplyOrCall(Math.random(), 252, Math.random()) === 253);
+}
+
+function baz() {
+ return inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, 1)))))))))))))))))))),
+ inc.call(null, inc.call(null, 1)));
+}
+assert(baz() === 22);
+
+function jaz() {
+ return inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.apply(null, [inc.call(null, inc.call(null,
+ inc.call(null, 1)))]))))))))))))))))),
+ inc.call(null, inc.call(null, inc.apply(null, [1]))));
+}
+assert(jaz() === 22);
+
+function haz() {
+ return inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.apply(null, [inc.call(null, inc.call(null,
+ inc.call(null, 1)))]))))))))))))))))),
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.call(null, inc.call(null, inc.call(null,
+ inc.call(null, inc.apply(null, [inc.call(null, inc.call(null,
+ inc.call(null, 1)))])))))))))))))))))));
+}
+assert(haz() === 22);
+
+function foo() {
+ return inc2.call(null, inc2.call(null, inc2.call(null, inc2.call(null,
+ inc2.call(null, inc2.call(null, inc2.call(null, inc2.call(null,
+ inc2.call(null, inc2.call(null, inc2.call(null, inc2.call(null,
+ inc2.call(null, inc2.call(null, inc2.call(null, inc2.call(null,
+ inc2.call(null, inc2.apply(null, [inc2.call(null, inc2.call(null,
+ inc2.call(null, 1)))]))))))))))))))))),
+ inc2.call(null, inc2.call(null, inc2.call(null, inc2.call(null,
+ inc2.call(null, inc2.call(null, inc2.call(null, inc2.call(null,
+ inc2.call(null, inc2.call(null, inc2.call(null, inc2.call(null,
+ inc2.call(null, inc2.call(null, inc2.call(null, inc2.call(null,
+ inc2.call(null, inc2.apply(null, [inc2.call(null, inc2.call(null,
+ inc2.call(null, inc2.call(null, inc.call(null, 1)))))])))))))))))))))))));
+}
+assert(foo() === 25);
Modified: trunk/Source/_javascript_Core/ChangeLog (215452 => 215453)
--- trunk/Source/_javascript_Core/ChangeLog 2017-04-18 06:05:25 UTC (rev 215452)
+++ trunk/Source/_javascript_Core/ChangeLog 2017-04-18 06:43:54 UTC (rev 215453)
@@ -1,3 +1,47 @@
+2017-04-17 Saam Barati <[email protected]>
+
+ BytecodeGenerator ".call" and ".apply" is exponential in nesting depth
+ https://bugs.webkit.org/show_bug.cgi?id=139847
+ <rdar://problem/19321122>
+
+ Reviewed by Oliver Hunt.
+
+ The BytecodeGenerator's .apply(...) and .call(...) code would
+ emit bytecode for the evaluation of its arguments twice. This
+ is exponential, specifically, 2^n, where n is the nesting depth of
+ .call(...) or .apply(...) inside other .call(...) or .apply(...).
+
+ The reason we emit code for the arguments twice is that we try
+ to emit efficient code for when .call or .apply is Function.prototype.call
+ or Function.prototype.apply. Because of this, we compare .call/.apply to
+ Function.prototype.call/.apply, and if they're the same, we emit a specialized
+ function call in bytecode. Otherwise, we emit the generalized version.
+
+ This patch makes it so that each .call(...) and .apply(...) records
+ its max inner nesting depth. Then, we only perform the optimization
+ for the bottom k (where k = 6) layers of the nesting tree. The reason we
+ apply the optimization to the bottom k layers instead of top k layers
+ is that we'll produce less code this way.
+
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::CallFunctionCallDotNode::emitBytecode):
+ (JSC::ApplyFunctionCallDotNode::emitBytecode):
+ * parser/ASTBuilder.h:
+ (JSC::ASTBuilder::makeFunctionCallNode):
+ * parser/NodeConstructors.h:
+ (JSC::CallFunctionCallDotNode::CallFunctionCallDotNode):
+ (JSC::ApplyFunctionCallDotNode::ApplyFunctionCallDotNode):
+ * parser/Nodes.h:
+ * parser/Parser.cpp:
+ (JSC::recordCallOrApplyDepth):
+ (JSC::Parser<LexerType>::parseMemberExpression):
+ * parser/Parser.h:
+ (JSC::Parser::CallOrApplyDepth::CallOrApplyDepth):
+ (JSC::Parser::CallOrApplyDepth::maxChildDepth):
+ (JSC::Parser::CallOrApplyDepth::~CallOrApplyDepth):
+ * parser/SyntaxChecker.h:
+ (JSC::SyntaxChecker::makeFunctionCallNode):
+
2017-04-17 Mark Lam <[email protected]>
JSArray::appendMemcpy() needs to handle copying from Undecided indexing type too.
Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (215452 => 215453)
--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2017-04-18 06:05:25 UTC (rev 215452)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2017-04-18 06:43:54 UTC (rev 215453)
@@ -1189,21 +1189,36 @@
RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
{
- Ref<Label> realCall = generator.newLabel();
- Ref<Label> end = generator.newLabel();
RefPtr<RegisterID> base = generator.emitNode(m_base);
generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
RefPtr<RegisterID> function;
- bool emitCallCheck = !generator.isBuiltinFunction();
- if (emitCallCheck) {
+ RefPtr<RegisterID> returnValue = generator.finalDestination(dst);
+
+ auto makeFunction = [&] {
if (m_base->isSuperNode()) {
RefPtr<RegisterID> thisValue = generator.ensureThis();
function = generator.emitGetById(generator.tempDestination(dst), base.get(), thisValue.get(), generator.propertyNames().builtinNames().callPublicName());
} else
function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().builtinNames().callPublicName());
+ };
+
+ bool emitCallCheck = !generator.isBuiltinFunction();
+ if (m_callOrApplyChildDepth > 4 && emitCallCheck) {
+ makeFunction();
+ CallArguments callArguments(generator, m_args);
+ generator.emitMove(callArguments.thisRegister(), base.get());
+ generator.emitCallInTailPosition(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes);
+ generator.moveToDestinationIfNeeded(dst, returnValue.get());
+ return returnValue.get();
+ }
+
+ Ref<Label> realCall = generator.newLabel();
+ Ref<Label> end = generator.newLabel();
+
+ if (emitCallCheck) {
+ makeFunction();
generator.emitJumpIfNotFunctionCall(function.get(), realCall.get());
}
- RefPtr<RegisterID> returnValue = generator.finalDestination(dst);
{
if (m_args->m_listNode && m_args->m_listNode->m_expr && m_args->m_listNode->m_expr->isSpreadExpression()) {
SpreadExpressionNode* spread = static_cast<SpreadExpressionNode*>(m_args->m_listNode->m_expr);
@@ -1256,19 +1271,32 @@
// function.apply(thisArg, [arg0, arg1, ...]) -> can be trivially coerced into function.call(thisArg, arg0, arg1, ...) and saves object allocation
bool mayBeCall = areTrivialApplyArguments(m_args);
- Ref<Label> realCall = generator.newLabel();
- Ref<Label> end = generator.newLabel();
+ RefPtr<RegisterID> function;
RefPtr<RegisterID> base = generator.emitNode(m_base);
- generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
- RefPtr<RegisterID> function;
- RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get());
- bool emitCallCheck = !generator.isBuiltinFunction();
- if (emitCallCheck) {
+ RefPtr<RegisterID> returnValue = generator.finalDestination(dst);
+ auto makeFunction = [&] {
if (m_base->isSuperNode()) {
RefPtr<RegisterID> thisValue = generator.ensureThis();
function = generator.emitGetById(generator.tempDestination(dst), base.get(), thisValue.get(), generator.propertyNames().builtinNames().applyPublicName());
} else
function = generator.emitGetById(generator.tempDestination(dst), base.get(), generator.propertyNames().builtinNames().applyPublicName());
+ };
+
+ bool emitCallCheck = !generator.isBuiltinFunction();
+ if (m_callOrApplyChildDepth > 4 && emitCallCheck) {
+ makeFunction();
+ CallArguments callArguments(generator, m_args);
+ generator.emitMove(callArguments.thisRegister(), base.get());
+ generator.emitCallInTailPosition(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes);
+ generator.moveToDestinationIfNeeded(dst, returnValue.get());
+ return returnValue.get();
+ }
+
+ Ref<Label> realCall = generator.newLabel();
+ Ref<Label> end = generator.newLabel();
+ generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
+ if (emitCallCheck) {
+ makeFunction();
generator.emitJumpIfNotFunctionApply(function.get(), realCall.get());
}
if (mayBeCall) {
Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (215452 => 215453)
--- trunk/Source/_javascript_Core/parser/ASTBuilder.h 2017-04-18 06:05:25 UTC (rev 215452)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h 2017-04-18 06:43:54 UTC (rev 215453)
@@ -129,7 +129,7 @@
static const int DontBuildStrings = 0;
ExpressionNode* makeBinaryNode(const JSTokenLocation&, int token, std::pair<ExpressionNode*, BinaryOpInfo>, std::pair<ExpressionNode*, BinaryOpInfo>);
- ExpressionNode* makeFunctionCallNode(const JSTokenLocation&, ExpressionNode* func, ArgumentsNode* args, const JSTextPosition& divotStart, const JSTextPosition& divot, const JSTextPosition& divotEnd);
+ ExpressionNode* makeFunctionCallNode(const JSTokenLocation&, ExpressionNode* func, ArgumentsNode* args, const JSTextPosition& divotStart, const JSTextPosition& divot, const JSTextPosition& divotEnd, size_t callOrApplyChildDepth);
JSC::SourceElements* createSourceElements() { return new (m_parserArena) JSC::SourceElements(); }
@@ -1301,7 +1301,7 @@
return new (m_parserArena) BitXOrNode(location, expr1, expr2, rightHasAssignments);
}
-ExpressionNode* ASTBuilder::makeFunctionCallNode(const JSTokenLocation& location, ExpressionNode* func, ArgumentsNode* args, const JSTextPosition& divotStart, const JSTextPosition& divot, const JSTextPosition& divotEnd)
+ExpressionNode* ASTBuilder::makeFunctionCallNode(const JSTokenLocation& location, ExpressionNode* func, ArgumentsNode* args, const JSTextPosition& divotStart, const JSTextPosition& divot, const JSTextPosition& divotEnd, size_t callOrApplyChildDepth)
{
ASSERT(divot.offset >= divot.lineStartOffset);
if (func->isSuperNode())
@@ -1333,9 +1333,9 @@
DotAccessorNode* dot = static_cast<DotAccessorNode*>(func);
FunctionCallDotNode* node;
if (dot->identifier() == m_vm->propertyNames->builtinNames().callPublicName() || dot->identifier() == m_vm->propertyNames->builtinNames().callPrivateName())
- node = new (m_parserArena) CallFunctionCallDotNode(location, dot->base(), dot->identifier(), args, divot, divotStart, divotEnd);
+ node = new (m_parserArena) CallFunctionCallDotNode(location, dot->base(), dot->identifier(), args, divot, divotStart, divotEnd, callOrApplyChildDepth);
else if (dot->identifier() == m_vm->propertyNames->builtinNames().applyPublicName() || dot->identifier() == m_vm->propertyNames->builtinNames().applyPrivateName())
- node = new (m_parserArena) ApplyFunctionCallDotNode(location, dot->base(), dot->identifier(), args, divot, divotStart, divotEnd);
+ node = new (m_parserArena) ApplyFunctionCallDotNode(location, dot->base(), dot->identifier(), args, divot, divotStart, divotEnd, callOrApplyChildDepth);
else
node = new (m_parserArena) FunctionCallDotNode(location, dot->base(), dot->identifier(), args, divot, divotStart, divotEnd);
node->setSubexpressionInfo(dot->divot(), dot->divotEnd().offset);
Modified: trunk/Source/_javascript_Core/parser/NodeConstructors.h (215452 => 215453)
--- trunk/Source/_javascript_Core/parser/NodeConstructors.h 2017-04-18 06:05:25 UTC (rev 215452)
+++ trunk/Source/_javascript_Core/parser/NodeConstructors.h 2017-04-18 06:43:54 UTC (rev 215453)
@@ -403,13 +403,15 @@
{
}
- inline CallFunctionCallDotNode::CallFunctionCallDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ inline CallFunctionCallDotNode::CallFunctionCallDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, size_t callOrApplyChildDepth)
: FunctionCallDotNode(location, base, ident, args, divot, divotStart, divotEnd)
+ , m_callOrApplyChildDepth(callOrApplyChildDepth)
{
}
- inline ApplyFunctionCallDotNode::ApplyFunctionCallDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ inline ApplyFunctionCallDotNode::ApplyFunctionCallDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, size_t callOrApplyChildDepth)
: FunctionCallDotNode(location, base, ident, args, divot, divotStart, divotEnd)
+ , m_callOrApplyChildDepth(callOrApplyChildDepth)
{
}
Modified: trunk/Source/_javascript_Core/parser/Nodes.h (215452 => 215453)
--- trunk/Source/_javascript_Core/parser/Nodes.h 2017-04-18 06:05:25 UTC (rev 215452)
+++ trunk/Source/_javascript_Core/parser/Nodes.h 2017-04-18 06:43:54 UTC (rev 215453)
@@ -884,18 +884,20 @@
class CallFunctionCallDotNode : public FunctionCallDotNode {
public:
- CallFunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+ CallFunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, size_t callOrApplyChildDepth);
private:
RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ size_t m_callOrApplyChildDepth;
};
class ApplyFunctionCallDotNode : public FunctionCallDotNode {
public:
- ApplyFunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+ ApplyFunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, size_t callOrApplyChildDepth);
private:
RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ size_t m_callOrApplyChildDepth;
};
class DeleteResolveNode : public ExpressionNode, public ThrowableExpressionData {
Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (215452 => 215453)
--- trunk/Source/_javascript_Core/parser/Parser.cpp 2017-04-18 06:05:25 UTC (rev 215452)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp 2017-04-18 06:43:54 UTC (rev 215453)
@@ -4384,6 +4384,22 @@
return parseAssignmentExpression(context);
}
+template <typename TreeBuilder, typename ParserType, typename = typename std::enable_if<std::is_same<TreeBuilder, ASTBuilder>::value>::type>
+static inline void recordCallOrApplyDepth(ParserType* parser, VM& vm, std::optional<typename ParserType::CallOrApplyDepth>& callOrApplyDepth, ExpressionNode* _expression_)
+{
+ if (_expression_->isDotAccessorNode()) {
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(_expression_);
+ bool isCallOrApply = dot->identifier() == vm.propertyNames->builtinNames().callPublicName() || dot->identifier() == vm.propertyNames->builtinNames().applyPublicName();
+ if (isCallOrApply)
+ callOrApplyDepth.emplace(parser);
+ }
+}
+
+template <typename TreeBuilder, typename ParserType, typename = typename std::enable_if<std::is_same<TreeBuilder, SyntaxChecker>::value>::type>
+static inline void recordCallOrApplyDepth(ParserType*, VM&, std::optional<typename ParserType::CallOrApplyDepth>&, SyntaxChecker::_expression_)
+{
+}
+
template <typename LexerType>
template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpression(TreeBuilder& context)
{
@@ -4498,6 +4514,9 @@
} else {
size_t usedVariablesSize = currentScope()->currentUsedVariablesSize();
JSTextPosition expressionEnd = lastTokenEndPosition();
+ std::optional<CallOrApplyDepth> callOrApplyDepth;
+ recordCallOrApplyDepth<TreeBuilder>(this, *m_vm, callOrApplyDepth, base);
+
TreeArguments arguments = parseArguments(context);
if (baseIsAsyncKeyword && (!arguments || match(ARROWFUNCTION))) {
@@ -4525,7 +4544,8 @@
if (currentScope()->isArrowFunction())
functionScope->setInnerArrowFunctionUsesSuperCall();
}
- base = context.makeFunctionCallNode(startLocation, base, arguments, expressionStart, expressionEnd, lastTokenEndPosition());
+ base = context.makeFunctionCallNode(startLocation, base, arguments, expressionStart,
+ expressionEnd, lastTokenEndPosition(), callOrApplyDepth ? callOrApplyDepth->maxChildDepth() : 0);
}
m_parserState.nonLHSCount = nonLHSCount;
break;
Modified: trunk/Source/_javascript_Core/parser/Parser.h (215452 => 215453)
--- trunk/Source/_javascript_Core/parser/Parser.h 2017-04-18 06:05:25 UTC (rev 215452)
+++ trunk/Source/_javascript_Core/parser/Parser.h 2017-04-18 06:43:54 UTC (rev 215453)
@@ -887,6 +887,37 @@
JSTextPosition positionBeforeLastNewline() const { return m_lexer->positionBeforeLastNewline(); }
JSTokenLocation locationBeforeLastToken() const { return m_lexer->lastTokenLocation(); }
+ struct CallOrApplyDepth {
+ CallOrApplyDepth(Parser* parser)
+ : m_parser(parser)
+ , m_parent(parser->m_callOrApplyDepth)
+ , m_depth(m_parent ? m_parent->m_depth + 1 : 0)
+ , m_childDepth(m_depth)
+ {
+ parser->m_callOrApplyDepth = this;
+ }
+
+ size_t maxChildDepth() const
+ {
+ ASSERT(m_childDepth >= m_depth);
+ return m_childDepth - m_depth;
+ }
+
+ ~CallOrApplyDepth()
+ {
+ if (m_parent)
+ m_parent->m_childDepth = std::max(m_childDepth, m_parent->m_childDepth);
+ m_parser->m_callOrApplyDepth = m_parent;
+ }
+
+ private:
+
+ Parser* m_parser;
+ CallOrApplyDepth* m_parent;
+ size_t m_depth;
+ size_t m_childDepth;
+ };
+
private:
struct AllowInOverride {
AllowInOverride(Parser* parser)
@@ -1780,6 +1811,7 @@
bool m_immediateParentAllowsFunctionDeclarationInStatement;
RefPtr<ModuleScopeData> m_moduleScopeData;
DebuggerParseData* m_debuggerParseData;
+ CallOrApplyDepth* m_callOrApplyDepth { nullptr };
struct DepthManager {
DepthManager(int* depth)
Modified: trunk/Source/_javascript_Core/parser/SyntaxChecker.h (215452 => 215453)
--- trunk/Source/_javascript_Core/parser/SyntaxChecker.h 2017-04-18 06:05:25 UTC (rev 215452)
+++ trunk/Source/_javascript_Core/parser/SyntaxChecker.h 2017-04-18 06:43:54 UTC (rev 215453)
@@ -143,7 +143,7 @@
static const unsigned DontBuildStrings = LexerFlagsDontBuildStrings;
int createSourceElements() { return SourceElementsResult; }
- ExpressionType makeFunctionCallNode(const JSTokenLocation&, int, int, int, int, int) { return CallExpr; }
+ ExpressionType makeFunctionCallNode(const JSTokenLocation&, int, int, int, int, int, size_t) { return CallExpr; }
ExpressionType createCommaExpr(const JSTokenLocation&, ExpressionType expr) { return expr; }
ExpressionType appendToCommaExpr(const JSTokenLocation&, ExpressionType& head, ExpressionType, ExpressionType next) { head = next; return next; }
ExpressionType makeAssignNode(const JSTokenLocation&, ExpressionType, Operator, ExpressionType, bool, bool, int, int, int) { return AssignmentExpr; }