diff --git a/src/interpreter/ByteCodeInterpreter.cpp b/src/interpreter/ByteCodeInterpreter.cpp index a43d8e846..998ac3064 100644 --- a/src/interpreter/ByteCodeInterpreter.cpp +++ b/src/interpreter/ByteCodeInterpreter.cpp @@ -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) diff --git a/src/parser/CodeBlock.cpp b/src/parser/CodeBlock.cpp index 594af02a5..6c24e8d79 100644 --- a/src/parser/CodeBlock.cpp +++ b/src/parser/CodeBlock.cpp @@ -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; @@ -466,7 +469,7 @@ std::pair 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); } } diff --git a/src/parser/CodeBlock.h b/src/parser/CodeBlock.h index d8f10f95a..fb0dff35d 100644 --- a/src/parser/CodeBlock.h +++ b/src/parser/CodeBlock.h @@ -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) */ diff --git a/src/parser/Script.cpp b/src/parser/Script.cpp index 5e81aac97..be7c25b64 100644 --- a/src/parser/Script.cpp +++ b/src/parser/Script.cpp @@ -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); } } diff --git a/src/parser/ScriptParser.cpp b/src/parser/ScriptParser.cpp index b7981574a..5a3bea7f4 100644 --- a/src/parser/ScriptParser.cpp +++ b/src/parser/ScriptParser.cpp @@ -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]; @@ -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; @@ -213,6 +213,9 @@ InterpretedCodeBlock* ScriptParser::generateCodeBlockTreeFromASTWalker(Context* ASSERT(p == argumentsObjectHolder); codeBlock->markHeapAllocatedEnvironmentFromHere(blockIndex, argumentsObjectHolder); } + + // arguments captured, so continue to the next + continue; } } diff --git a/src/runtime/ScriptFunctionObject.cpp b/src/runtime/ScriptFunctionObject.cpp index 9f5bb4196..2a18956ff 100644 --- a/src/runtime/ScriptFunctionObject.cpp +++ b/src/runtime/ScriptFunctionObject.cpp @@ -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; } diff --git a/test/vendortest b/test/vendortest index 6226beb94..0e299c5e5 160000 --- a/test/vendortest +++ b/test/vendortest @@ -1 +1 @@ -Subproject commit 6226beb943358ca644b2e8655c2cd6fe8633ff03 +Subproject commit 0e299c5e5aa9b05e195f571ff6752d978d551bd1