Skip to content

Commit

Permalink
Fix generation of arguments object used in nested arrow functions and…
Browse files Browse the repository at this point in the history
… eval codes

Signed-off-by: HyukWoo Park <[email protected]>
  • Loading branch information
clover2123 committed Sep 5, 2024
1 parent 7589396 commit a778455
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 26 deletions.
22 changes: 18 additions & 4 deletions src/interpreter/ByteCodeInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4964,10 +4964,24 @@ NEVER_INLINE void InterpreterSlowPath::setObjectOpcodeSlowCase(ExecutionState& s

NEVER_INLINE void InterpreterSlowPath::ensureArgumentsObjectOperation(ExecutionState& state, ByteCodeBlock* byteCodeBlock, Value* registerFile)
{
auto functionRecord = state.mostNearestFunctionLexicalEnvironment()->record()->asDeclarativeEnvironmentRecord()->asFunctionEnvironmentRecord();
auto functionObject = functionRecord->functionObject()->asScriptFunctionObject();
bool isMapped = functionObject->interpretedCodeBlock()->shouldHaveMappedArguments();
functionObject->generateArgumentsObject(state, state.argc(), state.argv(), functionRecord, registerFile + byteCodeBlock->m_requiredOperandRegisterNumber, isMapped);
FunctionEnvironmentRecord* funcRecord = nullptr;
ScriptFunctionObject* funcObject = nullptr;

// find the most nearest lexical function which is not an arrow function
ExecutionState* es = &state;
while (es) {
EnvironmentRecord* record = es->lexicalEnvironment()->record();
if (record->isDeclarativeEnvironmentRecord() && record->asDeclarativeEnvironmentRecord()->isFunctionEnvironmentRecord() && !record->asDeclarativeEnvironmentRecord()->asFunctionEnvironmentRecord()->functionObject()->isScriptArrowFunctionObject()) {
funcRecord = record->asDeclarativeEnvironmentRecord()->asFunctionEnvironmentRecord();
funcObject = funcRecord->functionObject()->asScriptFunctionObject();
break;
}
es = es->parent();
}

ASSERT(!!funcRecord && !!funcObject && !funcObject->isScriptArrowFunctionObject());
bool isMapped = funcObject->interpretedCodeBlock()->shouldHaveMappedArguments();
funcObject->generateArgumentsObject(state, es->argc(), es->argv(), funcRecord, registerFile + byteCodeBlock->m_requiredOperandRegisterNumber, isMapped);
}

NEVER_INLINE int InterpreterSlowPath::evaluateImportAssertionOperation(ExecutionState& state, const Value& options)
Expand Down
11 changes: 7 additions & 4 deletions src/parser/CodeBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,20 +409,23 @@ void InterpretedCodeBlock::recordFunctionParsingInfo(ASTScopeContext* scopeCtx,
initBlockScopeInformation(scopeCtx);
}

void InterpretedCodeBlock::captureArguments()
void InterpretedCodeBlock::captureArguments(bool needToAllocateOnStack)
{
AtomicString arguments = m_context->staticStrings().arguments;
ASSERT(!hasParameterName(arguments));
ASSERT(!isGlobalCodeBlock() && !isArrowFunctionExpression());
ASSERT(!isGlobalCodeBlock() && !isArrowFunctionExpression() && isKindOfFunction());

if (m_usesArgumentsObject) {
size_t idx = findVarName(arguments);
ASSERT(idx != SIZE_MAX);
m_identifierInfos[idx].m_needToAllocateOnStack &= needToAllocateOnStack;
return;
}

m_usesArgumentsObject = true;
if (findVarName(arguments) == SIZE_MAX) {
IdentifierInfo info;
info.m_needToAllocateOnStack = true;
info.m_needToAllocateOnStack = needToAllocateOnStack;
info.m_isMutable = true;
info.m_isParameterName = false;
info.m_isExplicitlyDeclaredOrParameterName = false;
Expand Down Expand Up @@ -466,7 +469,7 @@ std::pair<bool, size_t> InterpretedCodeBlock::tryCaptureIdentifiersFromChildCode
if (UNLIKELY(blockIndex < m_functionBodyBlockIndex)) {
// case for functions located in parameters
if (!isParameterName(name) && name != m_context->staticStrings().arguments) {
// it's possible to access parameter or arguemnts object of upper function
// it's possible to access parameter or arguments object of upper function
return std::make_pair(false, SIZE_MAX);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/parser/CodeBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ class InterpretedCodeBlock : public CodeBlock {
// You can use this function on ScriptParser only
void computeVariables();
// You can use this function on ScriptParser only
void captureArguments();
void captureArguments(bool needToAllocateOnStack);

// You can use this function on ScriptParser only
/* capture ok, block vector index(if not block variable, returns SIZE_MAX) */
Expand Down
31 changes: 17 additions & 14 deletions src/parser/Script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -602,24 +602,27 @@ Value Script::executeLocal(ExecutionState& state, Value thisValue, InterpretedCo
if (isEvalCodeOnFunction && m_topCodeBlock->usesArgumentsObject()) {
AtomicString arguments = state.context()->staticStrings().arguments;

FunctionEnvironmentRecord* fnRecord = nullptr;
{
LexicalEnvironment* env = state.lexicalEnvironment();
while (env) {
if (env->record()->isDeclarativeEnvironmentRecord() && env->record()->asDeclarativeEnvironmentRecord()->isFunctionEnvironmentRecord()) {
fnRecord = env->record()->asDeclarativeEnvironmentRecord()->asFunctionEnvironmentRecord();
break;
}
env = env->outerEnvironment();
FunctionEnvironmentRecord* funcRecord = nullptr;
ScriptFunctionObject* funcObject = nullptr;

// find the most nearest lexical function which is not an arrow function
ExecutionState* es = &state;
while (es) {
EnvironmentRecord* record = es->lexicalEnvironment()->record();
if (record->isDeclarativeEnvironmentRecord() && record->asDeclarativeEnvironmentRecord()->isFunctionEnvironmentRecord() && !record->asDeclarativeEnvironmentRecord()->asFunctionEnvironmentRecord()->functionObject()->isScriptArrowFunctionObject()) {
funcRecord = record->asDeclarativeEnvironmentRecord()->asFunctionEnvironmentRecord();
funcObject = funcRecord->functionObject()->asScriptFunctionObject();
break;
}
es = es->parent();
}
ASSERT(!!fnRecord);
ASSERT(!!funcRecord && !!funcObject && !funcObject->isScriptArrowFunctionObject());

FunctionObject* callee = state.resolveCallee();
if (fnRecord->hasBinding(newState, arguments).m_index == SIZE_MAX && callee->isScriptFunctionObject()) {
if (funcRecord->hasBinding(newState, arguments).m_index == SIZE_MAX) {
// If eval code uses the arguments object but not yet created in outer function, generate it
// FIXME check if formal parameters does not contain a rest parameter, any binding patterns, or any initializers.
bool isMapped = !callee->codeBlock()->asInterpretedCodeBlock()->hasParameterOtherThanIdentifier() && !inStrict;
callee->asScriptFunctionObject()->generateArgumentsObject(newState, state.argc(), state.argv(), fnRecord, nullptr, isMapped);
bool isMapped = !funcObject->interpretedCodeBlock()->hasParameterOtherThanIdentifier() && !inStrict;
funcObject->generateArgumentsObject(newState, es->argc(), es->argv(), funcRecord, nullptr, isMapped);
}
}

Expand Down
7 changes: 5 additions & 2 deletions src/parser/ScriptParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ InterpretedCodeBlock* ScriptParser::generateCodeBlockTreeFromASTWalker(Context*
}

AtomicString arguments = ctx->staticStrings().arguments;

for (size_t i = 0; i < scopeCtx->m_childBlockScopes.size(); i++) {
ASTBlockContext* childBlockContext = scopeCtx->m_childBlockScopes[i];

Expand All @@ -201,7 +200,8 @@ InterpretedCodeBlock* ScriptParser::generateCodeBlockTreeFromASTWalker(Context*

if (needToCaptureArguments) {
ASSERT(argumentsObjectHolder->isKindOfFunction() && !argumentsObjectHolder->isArrowFunctionExpression());
argumentsObjectHolder->captureArguments();
// if argumentsObjectHolder and codeBlock are not same, arguments should be allocated on the heap
argumentsObjectHolder->captureArguments(argumentsObjectHolder == codeBlock);

if (UNLIKELY(!codeBlock->isKindOfFunction() || codeBlock->isArrowFunctionExpression())) {
InterpretedCodeBlock* p = codeBlock;
Expand All @@ -213,6 +213,9 @@ InterpretedCodeBlock* ScriptParser::generateCodeBlockTreeFromASTWalker(Context*
ASSERT(p == argumentsObjectHolder);
codeBlock->markHeapAllocatedEnvironmentFromHere(blockIndex, argumentsObjectHolder);
}

// arguments captured, so continue to the next
continue;
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/runtime/ScriptFunctionObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ Value ScriptFunctionObject::construct(ExecutionState& state, const size_t argc,

void ScriptFunctionObject::generateArgumentsObject(ExecutionState& state, size_t argc, Value* argv, FunctionEnvironmentRecord* environmentRecordWillArgumentsObjectBeLocatedIn, Value* stackStorage, bool isMapped)
{
// arrow function should not create an ArgumentsObject
ASSERT(!isScriptArrowFunctionObject());

if (environmentRecordWillArgumentsObjectBeLocatedIn->m_argumentsObject->isArgumentsObject()) {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion test/vendortest

0 comments on commit a778455

Please sign in to comment.