//
    // Do not save the profile:
    //      - If it is a non-cacheable WININET resource
    //      - If there are no or small number of functions executed
    //      - If there is not substantial difference in number of functions executed.
    //
    bool SourceDynamicProfileManager::ShouldSaveToProfileCache(SourceContextInfo* info) const
    {
        if(isNonCachableScript)
        {
            OUTPUT_VERBOSE_TRACE(Js::DynamicProfilePhase, L"Skipping save of profile. Non-cacheable resource. %s\n", info->url);
            return false;
        }

        if(!startupFunctions || startupFunctions->Length() <= DEFAULT_CONFIG_MinProfileCacheSize)
        {
            OUTPUT_VERBOSE_TRACE(Js::DynamicProfilePhase, L"Skipping save of profile. Small number of functions. %s\n", info->url);
            return false;
        }

        if(cachedStartupFunctions)
        {
            AssertMsg(cachedStartupFunctions != startupFunctions, "Ensure they are not shallow copies of each other - Reuse() does this for dynamic sources. We should not be invoked for dynamic sources");
            uint numberOfBitsDifferent = cachedStartupFunctions->DiffCount(startupFunctions);
            uint saveThreshold = (cachedStartupFunctions->Length() * DEFAULT_CONFIG_ProfileDifferencePercent) / 100;
            if(numberOfBitsDifferent <= saveThreshold)
            {
                OUTPUT_VERBOSE_TRACE(Js::DynamicProfilePhase, L"Skipping save of profile. Number of functions different: %d %s\n", numberOfBitsDifferent, info->url);
                return false;
            }
            else
            {
                OUTPUT_VERBOSE_TRACE(Js::DynamicProfilePhase, L"Number of functions different: %d ", numberOfBitsDifferent);
            }
        }
        return true;
    }
Esempio n. 2
0
 bool ProbeContainer::CanDispatchHalt(InterpreterHaltState* pHaltState)
 {
     if (!haltCallbackProbe || haltCallbackProbe->IsInClosedState() || debugManager->IsAtDispatchHalt())
     {
         OUTPUT_VERBOSE_TRACE(Js::DebuggerPhase, _u("ProbeContainer::CanDispatchHalt: Not in break mode. pHaltState = %p\n"), pHaltState);
         return false;
     }
     return true;
 }
    //
    // Loads the profile from the WININET cache
    //
    bool SourceDynamicProfileManager::LoadFromProfileCache(IActiveScriptDataCache* profileDataCache, LPCWSTR url)
    {
    #ifdef ENABLE_WININET_PROFILE_DATA_CACHE
        AssertMsg(CONFIG_FLAG(WininetProfileCache), "Profile caching should be enabled for us to get here");
        Assert(profileDataCache);
        AssertMsg(!IsProfileLoadedFromWinInet(), "Duplicate profile cache loading?");

        // Keep a copy of this and addref it
        profileDataCache->AddRef();
        this->profileDataCache = profileDataCache;

        IStream* readStream;
        HRESULT hr = profileDataCache->GetReadDataStream(&readStream);
        if(SUCCEEDED(hr))
        {
            Assert(readStream != nullptr);
            // stream reader owns the stream and will close it on destruction
            SimpleStreamReader streamReader(readStream);
            DWORD jscriptMajorVersion;
            DWORD jscriptMinorVersion;
            if(FAILED(AutoSystemInfo::GetJscriptFileVersion(&jscriptMajorVersion, &jscriptMinorVersion)))
            {
                return false;
            }

            DWORD majorVersion;
            if(!streamReader.Read(&majorVersion) || majorVersion != jscriptMajorVersion)
            {
                return false;
            }

            DWORD minorVersion;
            if(!streamReader.Read(&minorVersion) || minorVersion != jscriptMinorVersion)
            {
                return false;
            }

            uint numberOfFunctions;
            if(!streamReader.Read(&numberOfFunctions) || numberOfFunctions > MAX_FUNCTION_COUNT)
            {
                return false;
            }
            BVFixed* functions = BVFixed::New(numberOfFunctions, this->recycler);
            if(!streamReader.ReadArray(functions->GetData(), functions->WordCount()))
            {
                return false;
            }
            this->cachedStartupFunctions = functions;
            OUTPUT_TRACE(Js::DynamicProfilePhase, L"Profile load succeeded. Function count: %d  %s\n", numberOfFunctions, url);
#if DBG_DUMP
            if(PHASE_TRACE1(Js::DynamicProfilePhase) && Js::Configuration::Global.flags.Verbose)
            {
                OUTPUT_VERBOSE_TRACE(Js::DynamicProfilePhase, L"Profile loaded:\n");
                functions->Dump();
            }
#endif
            return true;
        }
        else if (hr == HRESULT_FROM_WIN32(ERROR_WRITE_PROTECT))
        {
            this->isNonCachableScript = true;
            OUTPUT_VERBOSE_TRACE(Js::DynamicProfilePhase, L"Profile load failed. Non-cacheable resource. %s\n", url);
        }
        else
        {
            OUTPUT_TRACE(Js::DynamicProfilePhase, L"Profile load failed. No read stream. %s\n", url);
        }
#endif
        return false;
    }
    //
    // Saves the profile to the WININET cache
    //
    uint SourceDynamicProfileManager::SaveToProfileCache()
    {
        AssertMsg(CONFIG_FLAG(WininetProfileCache), "Profile caching should be enabled for us to get here");
        Assert(startupFunctions);

        uint bytesWritten = 0;
#ifdef ENABLE_WININET_PROFILE_DATA_CACHE
        //TODO: Add some diffing logic to not write unless necessary
        IStream* writeStream;
        HRESULT hr = profileDataCache->GetWriteDataStream(&writeStream);
        if(FAILED(hr))
        {
            return 0;
        }
        Assert(writeStream != nullptr);
        // stream writer owns the stream and will close it on destruction
        SimpleStreamWriter streamWriter(writeStream);

        DWORD jscriptMajorVersion;
        DWORD jscriptMinorVersion;
        if(FAILED(AutoSystemInfo::GetJscriptFileVersion(&jscriptMajorVersion, &jscriptMinorVersion)))
        {
            return 0;
        }

        if(!streamWriter.Write(jscriptMajorVersion))
        {
            return 0;
        }

        if(!streamWriter.Write(jscriptMinorVersion))
        {
            return 0;
        }

        if(!streamWriter.Write(startupFunctions->Length()))
        {
            return 0;
        }
        if(streamWriter.WriteArray(startupFunctions->GetData(), startupFunctions->WordCount()))
        {
            STATSTG stats;
            if(SUCCEEDED(writeStream->Stat(&stats, STATFLAG_NONAME)))
            {
                bytesWritten = stats.cbSize.LowPart;
                Assert(stats.cbSize.LowPart > 0);
                AssertMsg(stats.cbSize.HighPart == 0, "We should not be writing such long data that the high part is non-zero");
            }

            hr = profileDataCache->SaveWriteDataStream(writeStream);
            if(FAILED(hr))
            {
                return 0;
            }
#if DBG_DUMP
            if(PHASE_TRACE1(Js::DynamicProfilePhase) && Js::Configuration::Global.flags.Verbose)
            {
                OUTPUT_VERBOSE_TRACE(Js::DynamicProfilePhase, L"Saved profile:\n");
                startupFunctions->Dump();
            }
#endif
        }
#endif
        return bytesWritten;
    }