Symbol * Symbol::GetFuncScopeVarSym() const { if (!this->GetIsBlockVar()) { return nullptr; } FuncInfo * parentFuncInfo = this->GetScope()->GetFunc(); if (parentFuncInfo->GetIsStrictMode()) { return nullptr; } Symbol *fncScopeSym = parentFuncInfo->GetBodyScope()->FindLocalSymbol(this->GetName()); if (fncScopeSym == nullptr && parentFuncInfo->GetParamScope() != nullptr) { // We couldn't find the sym in the body scope, try finding it in the parameter scope. Scope* paramScope = parentFuncInfo->GetParamScope(); fncScopeSym = paramScope->FindLocalSymbol(this->GetName()); if (fncScopeSym == nullptr) { FuncInfo* parentParentFuncInfo = paramScope->GetEnclosingScope()->GetFunc(); if (parentParentFuncInfo->root->sxFnc.IsAsync()) { // In the case of async functions the func-scope var sym might have // come from the parent function parameter scope due to the syntax // desugaring implementation of async functions. fncScopeSym = parentParentFuncInfo->GetBodyScope()->FindLocalSymbol(this->GetName()); if (fncScopeSym == nullptr) { fncScopeSym = parentParentFuncInfo->GetParamScope()->FindLocalSymbol(this->GetName()); } } } } Assert(fncScopeSym); // Parser should have added a fake var decl node for block scoped functions in non-strict mode // IsBlockVar() indicates a user let declared variable at function scope which // shadows the function's var binding, thus only emit the var binding init if // we do not have a block var symbol. if (!fncScopeSym || fncScopeSym->GetIsBlockVar()) { return nullptr; } return fncScopeSym; }
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()); }