// // 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; }
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; }