bool CodeGenWorkItem::ShouldSpeculativelyJitBasedOnProfile() const
{
    Js::FunctionBody* functionBody = this->GetFunctionBody();

    uint loopPercentage = (functionBody->GetByteCodeInLoopCount()*100) / (functionBody->GetByteCodeCount() + 1);
    uint straightLineSize = functionBody->GetByteCodeCount() - functionBody->GetByteCodeInLoopCount();

    // This ensures only small and loopy functions are prejitted.
    if(loopPercentage >= 50 || straightLineSize < 300)
    {
        Js::SourceDynamicProfileManager* profileManager = functionBody->GetSourceContextInfo()->sourceDynamicProfileManager;
        if(profileManager != nullptr)
        {
            functionBody->SetIsSpeculativeJitCandidate();

            if(!functionBody->HasDynamicProfileInfo())
            {
                return false;
            }

            Js::ExecutionFlags executionFlags = profileManager->IsFunctionExecuted(functionBody->GetLocalFunctionId());
            if(executionFlags == Js::ExecutionFlags_Executed)
            {
                return true;
            }
        }
    }
    return false;
}
    void SnapshotExtractor::ExtractSlotArrayIfNeeded(Js::ScriptContext* ctx, Js::Var* scope)
    {
        if(this->m_marks.IsMarked(scope))
        {
            NSSnapValues::SlotArrayInfo* slotInfo = this->m_pendingSnap->GetNextAvailableSlotArrayEntry();

            Js::ScopeSlots slots(scope);
            slotInfo->SlotId = TTD_CONVERT_VAR_TO_PTR_ID(scope);
            slotInfo->ScriptContextLogId = ctx->ScriptContextLogTag;

            slotInfo->SlotCount = slots.GetCount();
            slotInfo->Slots = this->m_pendingSnap->GetSnapshotSlabAllocator().SlabAllocateArray<TTDVar>(slotInfo->SlotCount);

            for(uint32 j = 0; j < slotInfo->SlotCount; ++j)
            {
                slotInfo->Slots[j] = slots.Get(j);
            }

            if(slots.IsFunctionScopeSlotArray())
            {
                Js::FunctionBody* fb = slots.GetFunctionBody();

                slotInfo->isFunctionBodyMetaData = true;
                slotInfo->OptFunctionBodyId = TTD_CONVERT_FUNCTIONBODY_TO_PTR_ID(fb);

#if ENABLE_TTD_INTERNAL_DIAGNOSTICS
                Js::PropertyId* propertyIds = fb->GetPropertyIdsForScopeSlotArray();
                slotInfo->DebugPIDArray = this->m_pendingSnap->GetSnapshotSlabAllocator().SlabAllocateArray<Js::PropertyId>(slotInfo->SlotCount);

                for(uint32 j = 0; j < slotInfo->SlotCount; ++j)
                {
                    slotInfo->DebugPIDArray[j] = propertyIds[j];
                }
#endif
            }
            else
            {
                slotInfo->isFunctionBodyMetaData = false;
                slotInfo->OptFunctionBodyId = TTD_INVALID_PTR_ID;

#if ENABLE_TTD_INTERNAL_DIAGNOSTICS
                slotInfo->DebugPIDArray = this->m_pendingSnap->GetSnapshotSlabAllocator().SlabAllocateArray<Js::PropertyId>(slotInfo->SlotCount);

                for(uint32 j = 0; j < slotInfo->SlotCount; ++j)
                {
                    slotInfo->DebugPIDArray[j] = (Js::PropertyId)0;
                }
#endif
            }

            this->m_marks.ClearMark(scope);
        }
    }
    void SnapshotExtractor::MarkFunctionBody(Js::FunctionBody* fb)
    {
        if(this->m_marks.MarkAndTestAddr<MarkTableTag::FunctionBodyTag>(fb))
        {
            Js::FunctionBody* currfb = fb->GetScriptContext()->TTDContextInfo->ResolveParentBody(fb);

            while(currfb != nullptr && this->m_marks.MarkAndTestAddr<MarkTableTag::FunctionBodyTag>(currfb))
            {
                currfb = currfb->GetScriptContext()->TTDContextInfo->ResolveParentBody(currfb);
            }
        }
    }
Example #4
0
void JsrtDebugUtils::AddFileNameOrScriptTypeToObject(Js::DynamicObject* object, Js::Utf8SourceInfo* utf8SourceInfo)
{
    if (utf8SourceInfo->IsDynamic())
    {
        AssertMsg(utf8SourceInfo->GetSourceContextInfo()->url == nullptr, "How come dynamic code have a url?");

        Js::FunctionBody* anyFunctionBody = utf8SourceInfo->GetAnyParsedFunction();

        Assert(anyFunctionBody != nullptr);

        LPCWSTR sourceName = anyFunctionBody->GetSourceName();

        JsrtDebugUtils::AddPropertyToObject(object, JsrtDebugPropertyId::scriptType, sourceName, wcslen(sourceName), utf8SourceInfo->GetScriptContext());
    }
    else
    {
        // url can be nullptr if JsParseScript/JsRunScript didn't passed any
        const char16* url = utf8SourceInfo->GetSourceContextInfo()->url == nullptr ? _u("") : utf8SourceInfo->GetSourceContextInfo()->url;
        JsrtDebugUtils::AddPropertyToObject(object, JsrtDebugPropertyId::fileName, url, wcslen(url), utf8SourceInfo->GetScriptContext());
    }
}
Example #5
0
    Js::FunctionBody* TTDebuggerSourceLocation::ResolveAssociatedSourceInfo(Js::ScriptContext* ctx) const
    {
        Js::FunctionBody* resBody = ctx->TTDContextInfo->FindFunctionBodyByFileName(this->m_sourceFile);

        while(true)
        {
            for(uint32 i = 0; i < resBody->GetNestedCount(); ++i)
            {
                Js::ParseableFunctionInfo* ipfi = resBody->GetNestedFunc(i)->EnsureDeserialized();
                Js::FunctionBody* ifb = JsSupport::ForceAndGetFunctionBody(ipfi);

                if(this->m_functionLine == ifb->GetLineNumber() && this->m_functionColumn == ifb->GetColumnNumber())
                {
                    return ifb;
                }

                //if it starts on a larger line or if same line but larger column then we don't contain the target
                AssertMsg(ifb->GetLineNumber() < this->m_functionLine || (ifb->GetLineNumber() == this->m_functionLine && ifb->GetColumnNumber() < this->m_functionColumn), "We went to far but didn't find our function??");

                uint32 endLine = UINT32_MAX;
                uint32 endColumn = UINT32_MAX;
                if(i + 1 < resBody->GetNestedCount())
                {
                    Js::ParseableFunctionInfo* ipfinext = resBody->GetNestedFunc(i + 1)->EnsureDeserialized();
                    Js::FunctionBody* ifbnext = JsSupport::ForceAndGetFunctionBody(ipfinext);

                    endLine = ifbnext->GetLineNumber();
                    endColumn = ifbnext->GetColumnNumber();
                }

                if(endLine > this->m_functionLine || (endLine == this->m_functionLine && endColumn > this->m_functionColumn))
                {
                    resBody = ifb;
                    break;
                }
            }
        }

        AssertMsg(false, "We should never get here!!!");
        return nullptr;
    }
Example #6
0
void
Sym::Dump(IRDumpFlags flags, const ValueType valueType)
{
    bool const AsmDumpMode = flags & IRDumpFlags_AsmDumpMode;
    bool const SimpleForm = !!(flags & IRDumpFlags_SimpleForm);

    if (AsmDumpMode)
    {
        if (this->IsStackSym() && this->AsStackSym()->IsArgSlotSym())
        {
            Output::Print(L"arg ");
        }
        else if (this->IsStackSym() && this->AsStackSym()->IsParamSlotSym())
        {
            Output::Print(L"param ");
        }
    }
    else
    {
        if (this->IsStackSym() && this->AsStackSym()->IsArgSlotSym())
        {
            if (this->AsStackSym()->m_isInlinedArgSlot)
            {
                Output::Print(L"iarg%d", this->AsStackSym()->GetArgSlotNum());
            }
            else
            {
                Output::Print(L"arg%d", this->AsStackSym()->GetArgSlotNum());
            }
            Output::Print(L"(s%d)", m_id);
        }
        else if (this->IsStackSym() && this->AsStackSym()->IsParamSlotSym())
        {
            Output::Print(L"prm%d", this->AsStackSym()->GetParamSlotNum());
        }
        else
        {
            if (!this->IsPropertySym() || !SimpleForm)
            {
                Output::Print(L"s%d", m_id);
            }
            if (this->IsStackSym())
            {
                if(Js::Configuration::Global.flags.Debug && this->AsStackSym()->HasByteCodeRegSlot())
                {
                    StackSym* sym =  this->AsStackSym();
                    Js::FunctionBody* functionBody = sym->GetByteCodeFunc()->GetJnFunction();
                    if(functionBody->GetPropertyIdOnRegSlotsContainer())
                    {
                        if(functionBody->IsNonTempLocalVar(sym->GetByteCodeRegSlot()))
                        {
                            uint index = sym->GetByteCodeRegSlot() - functionBody->GetConstantCount();
                            Js::PropertyId propertyId = functionBody->GetPropertyIdOnRegSlotsContainer()->propertyIdsForRegSlots[index];
                            Output::Print(L"(%s)", functionBody->GetScriptContext()->GetPropertyNameLocked(propertyId)->GetBuffer());
                        }
                    }
                }
                if (this->AsStackSym()->IsVar())
                {
                    if (this->AsStackSym()->HasObjectTypeSym() && !SimpleForm)
                    {
                        Output::Print(L"<s%d>", this->AsStackSym()->GetObjectTypeSym()->m_id);
                    }
                }
                else
                {
                    StackSym *varSym = this->AsStackSym()->GetVarEquivSym(nullptr);
                    if (varSym)
                    {
                        Output::Print(L"(s%d)", varSym->m_id);
                    }
                }
                if (!SimpleForm)
                {
                    if (this->AsStackSym()->m_builtInIndex != Js::BuiltinFunction::None)
                    {
                        Output::Print(L"[ffunc]");
                    }
                }
            }
        }
        if(IsStackSym())
        {
            IR::Opnd::DumpValueType(valueType);
        }
    }

    if (this->IsPropertySym())
    {
        PropertySym *propertySym = this->AsPropertySym();

        if (!SimpleForm)
        {
            Output::Print(L"(");
        }

        Js::ScriptContext* scriptContext;
        switch (propertySym->m_fieldKind)
        {
        case PropertyKindData:
        {
            propertySym->m_stackSym->Dump(flags, valueType);
            scriptContext = propertySym->m_func->GetScriptContext();
            Js::PropertyRecord const* fieldName = scriptContext->GetPropertyNameLocked(propertySym->m_propertyId);
            Output::Print(L"->%s", fieldName->GetBuffer());
            break;
        }
        case PropertyKindSlots:
        case PropertyKindSlotArray:
            propertySym->m_stackSym->Dump(flags, valueType);
            Output::Print(L"[%d]", propertySym->m_propertyId);
            break;
        case PropertyKindLocalSlots:
            propertySym->m_stackSym->Dump(flags, valueType);
            Output::Print(L"l[%d]", propertySym->m_propertyId);
            break;
        default:
            AssertMsg(0, "Unknown field kind");
            break;
        }

        if (!SimpleForm)
        {
            Output::Print(L")");
        }
    }
}
Example #7
0
    bool StepController::IsStepComplete(InterpreterHaltState* haltState, HaltCallback * haltCallback, OpCode originalOpcode)
    {
        int currentFrameCount = haltState->framePointers->Count();
        AssertMsg(currentFrameCount > 0, "In IsStepComplete we must have at least one frame.");

        FunctionBody* body = haltState->framePointers->Peek()->GetJavascriptFunction()->GetFunctionBody();
        bool canPossiblyHalt = haltCallback->CanHalt(haltState);

        OUTPUT_TRACE(Js::DebuggerPhase, _u("StepController::IsStepComplete(): stepType = %d "), stepType);

        uint scriptId = GetScriptId(body);
        AssertMsg(scriptId != InvalidScriptId, "scriptId cannot be 'invalid-reserved'");

        int byteOffset = haltState->GetCurrentOffset();
        bool fCanHalt = false;

        if (this->frameCountWhenSet > currentFrameCount && STEP_DOCUMENT != stepType)
        {
            // all steps match once the frame they started on has popped.
            fCanHalt = canPossiblyHalt;
        }
        else if (STEP_DOCUMENT == stepType)
        {
            OUTPUT_TRACE(Js::DebuggerPhase, _u("StepController::IsStepComplete(): docId when set=%d, currentDocId = %d, can Halt = %d, will halt = %d "), this->scriptIdWhenSet, scriptId, canPossiblyHalt, fCanHalt);
            fCanHalt = (scriptId != this->scriptIdWhenSet) && canPossiblyHalt;
        }
        else if (STEP_IN != stepType && this->frameCountWhenSet < currentFrameCount)
        {
            // Only step into allows the stack to be deeper
            OUTPUT_TRACE(Js::DebuggerPhase, _u("StepController::IsStepComplete(stepType = %d) returning false "), stepType);
            return false;
        }
        else if (STEP_OUT == stepType)
        {
            fCanHalt = this->frameCountWhenSet > currentFrameCount && canPossiblyHalt;
        }
        else if (nullptr != this->statementMap && this->statementMap->isSubexpression && STEP_IN != stepType)
        {
            // Only step into started from subexpression is allowed to stop on another subexpression
            Js::FunctionBody* pCurrentFuncBody = haltState->GetFunction();
            Js::FunctionBody::StatementMap* map = pCurrentFuncBody->GetMatchingStatementMapFromByteCode(byteOffset, false);
            if (nullptr != map && map->isSubexpression)    // Execute remaining Subexpressions
            {
                fCanHalt = false;
            }
            else
            {
                Js::FunctionBody::StatementMap* outerMap = pCurrentFuncBody->GetMatchingStatementMapFromByteCode(this->statementMap->byteCodeSpan.begin, true);
                if (nullptr != outerMap && map == outerMap) // Execute the rest of current regular statement
                {
                    fCanHalt = false;
                }
                else
                {
                    fCanHalt = canPossiblyHalt;
                }
            }
        }
        else
        {
            // Match if we are no longer on the original statement.  Stepping means move off current statement.
            if (body != this->body || NULL == this->statementMap ||
                !this->statementMap->byteCodeSpan.Includes(byteOffset))
            {
                fCanHalt = canPossiblyHalt;
            }
        }
        // At this point we are verifying of global return opcode.
        // The global returns are alway added as a zero range begin with zero.

        if (fCanHalt && originalOpcode == OpCode::Ret)
        {
            Js::FunctionBody* pCurrentFuncBody = haltState->GetFunction();
            Js::FunctionBody::StatementMap* map = pCurrentFuncBody->GetMatchingStatementMapFromByteCode(byteOffset, true);

            fCanHalt = !FunctionBody::IsDummyGlobalRetStatement(&map->sourceSpan);
            if (fCanHalt)
            {
                // We are breaking at last line of function, imagine '}'
                AddReturnToReturnedValueContainer();
            }
        }

        OUTPUT_TRACE(Js::DebuggerPhase, _u("StepController::IsStepComplete(stepType = %d) returning %d "), stepType, fCanHalt);
        return fCanHalt;
    }