// // Save scope info for an outer func which has deferred child. // void ScopeInfo::SaveScopeInfo(ByteCodeGenerator* byteCodeGenerator, FuncInfo* parentFunc, FuncInfo* func) { ParseableFunctionInfo* funcBody = func->byteCodeFunction; Assert((!func->IsGlobalFunction() || byteCodeGenerator->GetFlags() & fscrEvalCode) && (func->HasDeferredChild() || (funcBody->IsReparsed()))); // If we are reparsing a deferred function, we already have correct "parent" info in // funcBody->scopeInfo. parentFunc is the knopProg shell and should not be used in this // case. We should use existing parent if available. FunctionBody * parent = funcBody->GetScopeInfo() ? funcBody->GetScopeInfo()->GetParent() : parentFunc ? parentFunc->byteCodeFunction->GetFunctionBody() : nullptr; ScopeInfo* funcExprScopeInfo = nullptr; Scope* funcExprScope = func->GetFuncExprScope(); if (funcExprScope && funcExprScope->GetMustInstantiate()) { funcExprScopeInfo = FromScope(byteCodeGenerator, parent, funcExprScope, funcBody->GetScriptContext()); } Scope* bodyScope = func->IsGlobalFunction() ? func->GetGlobalEvalBlockScope() : func->GetBodyScope(); ScopeInfo* paramScopeInfo = nullptr; Scope* paramScope = func->GetParamScope(); if (paramScope && bodyScope->GetMustInstantiate()) { paramScopeInfo = FromScope(byteCodeGenerator, parent, paramScope, funcBody->GetScriptContext()); } ScopeInfo* scopeInfo = FromScope(byteCodeGenerator, parent, bodyScope, funcBody->GetScriptContext()); scopeInfo->SetFuncExprScopeInfo(funcExprScopeInfo); scopeInfo->SetParamScopeInfo(paramScopeInfo); funcBody->SetScopeInfo(scopeInfo); }
void Scope::MergeParamAndBodyScopes(ParseNode *pnodeScope, ByteCodeGenerator *byteCodeGenerator) { Assert(pnodeScope->sxFnc.funcInfo); Scope *paramScope = pnodeScope->sxFnc.pnodeScopes->sxBlock.scope; Scope *bodyScope = pnodeScope->sxFnc.pnodeBodyScope->sxBlock.scope; Assert(paramScope->m_symList == nullptr || paramScope->symbolTable == nullptr); Assert(bodyScope->m_symList == nullptr || bodyScope->symbolTable == nullptr); if (paramScope->Count() == 0) { // Once the scopes are merged, there's no reason to instantiate the param scope. paramScope->SetMustInstantiate(false); // Scopes are already merged or we don't have an arguments object. Go ahead and // remove the param scope from the scope chain. bodyScope->SetEnclosingScope(paramScope->GetEnclosingScope()); return; } bodyScope->ForEachSymbol([&](Symbol * sym) { // Duplicate 'arguments' - param scope arguments wins. if (byteCodeGenerator->UseParserBindings() && sym->GetDecl()->sxVar.pid == byteCodeGenerator->GetParser()->names()->arguments) { return; } Assert(paramScope->m_symList == nullptr || paramScope->FindLocalSymbol(sym->GetName()) == nullptr); paramScope->AddNewSymbol(sym); }); // Reassign non-formal slot positions. Formals need to keep their slot positions to ensure // the argument object works properly. Other symbols need to be reassigned slot positions. paramScope->ForEachSymbol([&](Symbol * sym) { if (sym->GetSymbolType() != STFormal && sym->GetScopeSlot() != Js::Constants::NoProperty) { sym->SetScopeSlot(Js::Constants::NoProperty); sym->EnsureScopeSlot(pnodeScope->sxFnc.funcInfo); } sym->SetScope(bodyScope); }); bodyScope->m_count = paramScope->m_count; bodyScope->m_symList = paramScope->m_symList; bodyScope->scopeSlotCount = paramScope->scopeSlotCount; if (bodyScope->symbolTable != nullptr) { Adelete(byteCodeGenerator->GetAllocator(), bodyScope->symbolTable); bodyScope->symbolTable = nullptr; } bodyScope->symbolTable = paramScope->symbolTable; if (paramScope->GetIsObject()) { bodyScope->SetIsObject(); } if (paramScope->GetMustInstantiate()) { bodyScope->SetMustInstantiate(true); } // Once the scopes are merged, there's no reason to instantiate the param scope. paramScope->SetMustInstantiate(false); paramScope->m_count = 0; paramScope->scopeSlotCount = 0; paramScope->m_symList = nullptr; paramScope->symbolTable = nullptr; // Remove the parameter scope from the scope chain. bodyScope->SetEnclosingScope(paramScope->GetEnclosingScope()); }