// This is called at process detach. // threadcontext created from runtime should not be destroyed in ThreadBoundThreadContext // we should clean them up at process detach only as runtime can be used in other threads // even after the current physical thread was destroyed. // This is called after ThreadBoundThreadContext are cleaned up, so the remaining items // in the globalthreadContext linklist should be for jsrt only. void JsrtRuntime::Uninitialize() { ThreadContext* currentThreadContext = ThreadContext::GetThreadContextList(); ThreadContext* tmpThreadContext; while (currentThreadContext) { Assert(!currentThreadContext->IsScriptActive()); JsrtRuntime* currentRuntime = static_cast<JsrtRuntime*>(currentThreadContext->GetJSRTRuntime()); tmpThreadContext = currentThreadContext; currentThreadContext = currentThreadContext->Next(); currentRuntime->CloseContexts(); RentalThreadContextManager::DestroyThreadContext(tmpThreadContext); HeapDelete(currentRuntime); } }
// This is called at process detach. // threadcontext created from runtime should not be destroyed in ThreadBoundThreadContext // we should clean them up at process detach only as runtime can be used in other threads // even after the current physical thread was destroyed. // This is called after ThreadBoundThreadContext are cleaned up, so the remaining items // in the globalthreadContext linklist should be for jsrt only. void JsrtRuntime::Uninitialize() { ThreadContext* currentThreadContext = ThreadContext::GetThreadContextList(); ThreadContext* tmpThreadContext; while (currentThreadContext) { Assert(!currentThreadContext->IsScriptActive()); JsrtRuntime* currentRuntime = static_cast<JsrtRuntime*>(currentThreadContext->GetJSRTRuntime()); tmpThreadContext = currentThreadContext; currentThreadContext = currentThreadContext->Next(); #ifdef CHAKRA_STATIC_LIBRARY // xplat-todo: Cleanup staticlib shutdown. This only shuts down threads. // Other closing contexts / finalizers having trouble with current // runtime/context. RentalThreadContextManager::DestroyThreadContext(tmpThreadContext); #else currentRuntime->CloseContexts(); RentalThreadContextManager::DestroyThreadContext(tmpThreadContext); HeapDelete(currentRuntime); #endif } }
// // Enumerate through all the script contexts in the process and log events // for each function loaded. Depending on the argument, start or end events are logged. // In particular, a rundown is needed for the 'Attach' scenario of profiling. // void EtwTrace::PerformRundown(bool start) { // Lock threadContext list during etw rundown AutoCriticalSection autoThreadContextCs(ThreadContext::GetCriticalSection()); ThreadContext * threadContext = ThreadContext::GetThreadContextList(); if(start) { JS_ETW(EventWriteDCStartInit()); } else { JS_ETW(EventWriteDCEndInit()); } while(threadContext != nullptr) { // Take etw rundown lock on this thread context AutoCriticalSection autoEtwRundownCs(threadContext->GetEtwRundownCriticalSection()); ScriptContext* scriptContext = threadContext->GetScriptContextList(); while(scriptContext != NULL) { if(scriptContext->IsClosed()) { scriptContext = scriptContext->next; continue; } if(start) { JS_ETW(EventWriteScriptContextDCStart(scriptContext)); if(scriptContext->GetSourceContextInfoMap() != nullptr) { scriptContext->GetSourceContextInfoMap()->Map( [=] (DWORD_PTR sourceContext, SourceContextInfo * sourceContextInfo) { if (sourceContext != Constants::NoHostSourceContext) { JS_ETW(LogSourceEvent(EventWriteSourceDCStart, sourceContext, scriptContext, /* sourceFlags*/ 0, sourceContextInfo->url)); } }); } } else { JS_ETW(EventWriteScriptContextDCEnd(scriptContext)); if(scriptContext->GetSourceContextInfoMap() != nullptr) { scriptContext->GetSourceContextInfoMap()->Map( [=] (DWORD_PTR sourceContext, SourceContextInfo * sourceContextInfo) { if (sourceContext != Constants::NoHostSourceContext) { JS_ETW(LogSourceEvent(EventWriteSourceDCEnd, sourceContext, scriptContext, /* sourceFlags*/ 0, sourceContextInfo->url)); } }); } } scriptContext->MapFunction([&start] (FunctionBody* body) { #if DYNAMIC_INTERPRETER_THUNK if(body->HasInterpreterThunkGenerated()) { if(start) { LogMethodInterpretedThunkEvent(EventWriteMethodDCStart, body); } else { LogMethodInterpretedThunkEvent(EventWriteMethodDCEnd, body); } } #endif #if ENABLE_NATIVE_CODEGEN body->MapEntryPoints([&](int index, FunctionEntryPointInfo * entryPoint) { if(entryPoint->IsCodeGenDone()) { if (start) { LogMethodNativeEvent(EventWriteMethodDCStart, body, entryPoint); } else { LogMethodNativeEvent(EventWriteMethodDCEnd, body, entryPoint); } } }); body->MapLoopHeadersWithLock([&](uint loopNumber, LoopHeader* header) { header->MapEntryPoints([&](int index, LoopEntryPointInfo * entryPoint) { if(entryPoint->IsCodeGenDone()) { if(start) { LogLoopBodyEventBG(EventWriteMethodDCStart, body, header, entryPoint, ((uint16)body->GetLoopNumberWithLock(header))); } else { LogLoopBodyEventBG(EventWriteMethodDCEnd, body, header, entryPoint, ((uint16)body->GetLoopNumberWithLock(header))); } } }); }); #endif }); scriptContext = scriptContext->next; } #ifdef NTBUILD if (EventEnabledJSCRIPT_HOSTING_CEO_START()) { threadContext->EtwLogPropertyIdList(); } #endif threadContext = threadContext->Next(); } if(start) { JS_ETW(EventWriteDCStartComplete()); } else { JS_ETW(EventWriteDCEndComplete()); } }
void PerfTrace::WritePerfMap() { #if ENABLE_NATIVE_CODEGEN // Lock threadContext list during etw rundown AutoCriticalSection autoThreadContextCs(ThreadContext::GetCriticalSection()); ThreadContext * threadContext = ThreadContext::GetThreadContextList(); FILE * perfMapFile; { const size_t PERFMAP_FILENAME_MAX_LENGTH = 30; char perfMapFilename[PERFMAP_FILENAME_MAX_LENGTH]; pid_t processId = getpid(); snprintf(perfMapFilename, PERFMAP_FILENAME_MAX_LENGTH, "/tmp/perf-%d.map", processId); perfMapFile = fopen(perfMapFilename, "w"); if (perfMapFile == NULL) { return; } } while(threadContext != nullptr) { // Take etw rundown lock on this thread context AutoCriticalSection autoEtwRundownCs(threadContext->GetFunctionBodyLock()); ScriptContext* scriptContext = threadContext->GetScriptContextList(); while(scriptContext != NULL) { if(scriptContext->IsClosed()) { scriptContext = scriptContext->next; continue; } scriptContext->MapFunction([=] (FunctionBody* body) { #if DYNAMIC_INTERPRETER_THUNK if(body->HasInterpreterThunkGenerated()) { const char16* functionName = body->GetExternalDisplayName(); fwprintf(perfMapFile, _u("%llX %llX %s(Interpreted)\n"), body->GetDynamicInterpreterEntryPoint(), body->GetDynamicInterpreterThunkSize(), functionName); } #endif #if ENABLE_NATIVE_CODEGEN body->MapEntryPoints([&](int index, FunctionEntryPointInfo * entryPoint) { if(entryPoint->IsCodeGenDone()) { const ExecutionMode jitMode = entryPoint->GetJitMode(); if (jitMode == ExecutionMode::SimpleJit) { fwprintf(perfMapFile, _u("%llX %llX %s(SimpleJIT)\n"), entryPoint->GetNativeAddress(), entryPoint->GetCodeSize(), body->GetExternalDisplayName()); } else { fwprintf(perfMapFile, _u("%llX %llX %s(FullJIT)\n"), entryPoint->GetNativeAddress(), entryPoint->GetCodeSize(), body->GetExternalDisplayName()); } } }); body->MapLoopHeadersWithLock([&](uint loopNumber, LoopHeader* header) { header->MapEntryPoints([&](int index, LoopEntryPointInfo * entryPoint) { if(entryPoint->IsCodeGenDone()) { const uint16 loopNumber = ((uint16)body->GetLoopNumberWithLock(header)); fwprintf(perfMapFile, _u("%llX %llX %s(Loop%u)\n"), entryPoint->GetNativeAddress(), entryPoint->GetCodeSize(), body->GetExternalDisplayName(), loopNumber+1); } }); }); #endif }); scriptContext = scriptContext->next; } threadContext = threadContext->Next(); } fflush(perfMapFile); fclose(perfMapFile); #endif PerfTrace::mapsRequested = 0; }