Beispiel #1
0
void FuncInfo::OnStartVisitScope(Scope *scope, bool *pisMergedScope)
{
    *pisMergedScope = false;

    if (scope == nullptr)
    {
        return;
    }

    Scope* childScope = this->GetCurrentChildScope();
    if (childScope)
    {
        if (scope->GetScopeType() == ScopeType_Parameter)
        {
            Assert(childScope->GetEnclosingScope() == scope);
        }
        else if (childScope->GetScopeType() == ScopeType_Parameter
                 && childScope->GetCanMergeWithBodyScope()
                 && scope->GetScopeType() == ScopeType_Block)
        {
            // If param and body are merged then the class declaration in param scope will have body as the parent
            *pisMergedScope = true;
            Assert(childScope == scope->GetEnclosingScope()->GetEnclosingScope());
        }
        else
        {
            Assert(childScope == scope->GetEnclosingScope());
        }
    }

    this->SetCurrentChildScope(scope);
    return;
}
Beispiel #2
0
Scope * FuncInfo::GetGlobalEvalBlockScope() const
{
    Scope * globalEvalBlockScope = this->GetGlobalBlockScope();
    Assert(globalEvalBlockScope->GetEnclosingScope() == this->GetBodyScope());
    Assert(globalEvalBlockScope->GetScopeType() == ScopeType_GlobalEvalBlock);
    return globalEvalBlockScope;
}
Beispiel #3
0
Scope *
FuncInfo::GetGlobalBlockScope() const
{
    Assert(this->IsGlobalFunction());
    Scope * scope = this->root->sxFnc.pnodeScopes->sxBlock.scope;
    Assert(scope == nullptr || scope == this->GetBodyScope() || scope->GetEnclosingScope() == this->GetBodyScope());
    return scope;
}
Beispiel #4
0
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;
}
Beispiel #5
0
    void ScopeInfo::SaveScopeInfoForDeferParse(ByteCodeGenerator* byteCodeGenerator, FuncInfo* parentFunc, FuncInfo* funcInfo)
    {
        // TODO: Not technically necessary, as we always do scope look up on eval if it is
        // not found in the scope chain, and block scopes are always objects in eval.
        // But if we save the global eval block scope for deferred child so that we can look up
        // let/const in that scope with slot index instead of doing a scope lookup.
        // We will have to implement encoding block scope info to enable, which will also
        // enable defer parsing function that are in block scopes.

        Scope* currentScope = byteCodeGenerator->GetCurrentScope();
        Assert(currentScope == funcInfo->GetBodyScope());
        if (funcInfo->IsDeferred())
        {
            // Don't need to remember the parent function if we have a global function
            if (!parentFunc->IsGlobalFunction() ||
                ((byteCodeGenerator->GetFlags() & fscrEvalCode) && parentFunc->HasDeferredChild()))
            {
                // TODO: currently we only support defer nested function that is in function scope (no block scope, no with scope, etc.)
#if DBG
                if (funcInfo->GetFuncExprScope() && funcInfo->GetFuncExprScope()->GetIsObject())
                {
                    if (funcInfo->paramScope && !funcInfo->paramScope->GetCanMergeWithBodyScope())
                    {
                        Assert(currentScope->GetEnclosingScope()->GetEnclosingScope() == funcInfo->GetFuncExprScope());
                    }
                    else
                    {
                        Assert(currentScope->GetEnclosingScope() == funcInfo->GetFuncExprScope() &&
                            currentScope->GetEnclosingScope()->GetEnclosingScope() ==
                            (parentFunc->IsGlobalFunction() ? parentFunc->GetGlobalEvalBlockScope() : parentFunc->GetBodyScope()));
                    }
                }
                else
                {
                    if (currentScope->GetEnclosingScope() == parentFunc->GetParamScope())
                    {
                        Assert(!parentFunc->GetParamScope()->GetCanMergeWithBodyScope());
                        Assert(funcInfo->GetParamScope()->GetCanMergeWithBodyScope());
                    }
                    else if (currentScope->GetEnclosingScope() == funcInfo->GetParamScope())
                    {
                        Assert(!funcInfo->GetParamScope()->GetCanMergeWithBodyScope());
                    }
                    else
                    { 
                        Assert(currentScope->GetEnclosingScope() ==
                            (parentFunc->IsGlobalFunction() ? parentFunc->GetGlobalEvalBlockScope() : parentFunc->GetBodyScope()));
                    }
                }
#endif
                Js::ScopeInfo::SaveParentScopeInfo(parentFunc, funcInfo);
            }
        }
        else if (funcInfo->HasDeferredChild() ||
            (!funcInfo->IsGlobalFunction() &&
                funcInfo->byteCodeFunction &&
                funcInfo->byteCodeFunction->IsReparsed() &&
                funcInfo->byteCodeFunction->GetFunctionBody()->HasAllNonLocalReferenced()))
        {
            // When we reparse due to attach, we would need to capture all of them, since they were captured before going to debug mode.

            Js::ScopeInfo::SaveScopeInfo(byteCodeGenerator, parentFunc, funcInfo);
        }
    }
Beispiel #6
0
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());
}