From 5bc5fc78763face05fe0fd8b6f3272fa5768808d Mon Sep 17 00:00:00 2001 From: HyukWoo Park Date: Tue, 21 Nov 2023 21:19:28 +0900 Subject: [PATCH] Add fine-tuned TCO condition check in parsing phase * check argument count and name of callee Signed-off-by: HyukWoo Park --- src/parser/CodeBlock.h | 16 +++++++++++++++- src/parser/ast/CallExpressionNode.h | 6 ++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/parser/CodeBlock.h b/src/parser/CodeBlock.h index d913112f9..2c4c1598d 100644 --- a/src/parser/CodeBlock.h +++ b/src/parser/CodeBlock.h @@ -616,10 +616,24 @@ class InterpretedCodeBlock : public CodeBlock { } // for TCO - bool isTailRecursionTarget() const + bool isTailRecursionTarget(size_t argc, const AtomicString& calleeName) const { // global scope cannot create a return statement, neither tail recursion ASSERT(!isGlobalScope()); + + // check argc + if (m_parameterCount != argc) { + return false; + } + +#ifndef ESCARGOT_ENABLE_TEST + // check callee name + // this check is disabled in test build to pass test262 tco-related test cases + if (m_functionName.string()->length() && m_functionName != calleeName) { + return false; + } +#endif + return (!m_canAllocateVariablesOnStack || m_isArrowFunctionExpression || m_isClassConstructor || m_isDerivedClassConstructor || m_isClassMethod || m_isClassStaticMethod || m_isGenerator || m_isAsync || m_usesArgumentsObject) != true; } diff --git a/src/parser/ast/CallExpressionNode.h b/src/parser/ast/CallExpressionNode.h index 629d0b14f..356073c03 100644 --- a/src/parser/ast/CallExpressionNode.h +++ b/src/parser/ast/CallExpressionNode.h @@ -417,7 +417,8 @@ class CallExpressionNode : public ExpressionNode { if (dstRegister == context->m_returnRegister) { // Try tail recursion optimization (TCO) isTailCall = true; - bool isTailRecursion = context->m_codeBlock->isTailRecursionTarget(); + const AtomicString& calleeName = m_callee->asMemberExpression()->property()->isIdentifier() ? m_callee->asMemberExpression()->property()->asIdentifier()->name() : AtomicString(); + bool isTailRecursion = context->m_codeBlock->isTailRecursionTarget(m_arguments.size(), calleeName); if (UNLIKELY(context->tryCatchWithBlockStatementCount())) { codeBlock->pushCode(CallWithReceiver(ByteCodeLOC(m_loc.index), receiverIndex, calleeIndex, argumentsStartIndex, dstRegister, m_arguments.size()), context, this->m_loc.index); } else { @@ -434,7 +435,8 @@ class CallExpressionNode : public ExpressionNode { if (dstRegister == context->m_returnRegister) { // Try tail recursion optimization (TCO) isTailCall = true; - bool isTailRecursion = context->m_codeBlock->isTailRecursionTarget(); + const AtomicString& calleeName = m_callee->isIdentifier() ? m_callee->asIdentifier()->name() : AtomicString(); + bool isTailRecursion = context->m_codeBlock->isTailRecursionTarget(m_arguments.size(), calleeName); if (UNLIKELY(context->tryCatchWithBlockStatementCount())) { if (isTailRecursion) { codeBlock->pushCode(TailRecursionInTry(ByteCodeLOC(m_loc.index), calleeIndex, argumentsStartIndex, dstRegister, m_arguments.size()), context, this->m_loc.index);