static void* attribute_align_arg worker(void *v) { AVCodecContext *avctx = v; ThreadContext *c = avctx->thread_opaque; int our_job = c->job_count; int thread_count = avctx->thread_count; int self_id; pthread_mutex_lock(&c->current_job_lock); self_id = c->current_job++; for (;;){ while (our_job >= c->job_count) { if (c->current_job == thread_count + c->job_count) pthread_cond_signal(&c->last_job_cond); pthread_cond_wait(&c->current_job_cond, &c->current_job_lock); our_job = self_id; if (c->done) { pthread_mutex_unlock(&c->current_job_lock); return NULL; } } pthread_mutex_unlock(&c->current_job_lock); c->rets[our_job%c->rets_count] = c->func ? c->func(avctx, (char*)c->args + our_job*c->job_size): c->func2(avctx, c->args, our_job, self_id); pthread_mutex_lock(&c->current_job_lock); our_job = c->current_job++; } }
BOOL DynamicObject::CallToPrimitiveFunction(Var toPrimitiveFunction, PropertyId propertyId, Var* result, ScriptContext * requestContext) { if (JavascriptConversion::IsCallable(toPrimitiveFunction)) { RecyclableObject* toStringFunction = RecyclableObject::FromVar(toPrimitiveFunction); ThreadContext * threadContext = requestContext->GetThreadContext(); Var aResult = threadContext->ExecuteImplicitCall(toStringFunction, ImplicitCall_ToPrimitive, [=]() -> Js::Var { // Stack object should have a pre-op bail on implicit call. We shouldn't see them here. Assert(!ThreadContext::IsOnStack(this) || threadContext->HasNoSideEffect(toStringFunction)); return toStringFunction->GetEntryPoint()(toStringFunction, CallInfo(CallFlags_Value, 1), this); }); if (!aResult) { // There was an implicit call and implicit calls are disabled. This would typically cause a bailout. Assert(threadContext->IsDisableImplicitCall()); *result = requestContext->GetLibrary()->GetNull(); return true; } if (JavascriptOperators::GetTypeId(aResult) <= TypeIds_LastToPrimitiveType) { *result = aResult; return true; } } return false; }
ThreadContext& DebugThreadManager::StartThread(const Common::StackPreparator& stack, size_t stackSize, const PEF::TransitionVector& entryPoint, bool startNow) { // lldb enforces some alignment constraints on the stack, so align it correctly by allocating some additional memory ThreadContext* context = new ThreadContext(allocator, nextId, stackSize + 0x200); uint32_t stackAddress = allocator.ToIntPtr(*context->stack); stackAddress += 0x200; stackAddress &= ~0x1ff; auto info = stack.WriteStack(allocator.ToPointer<char>(stackAddress), stackAddress, stackSize); context->machineState.r1 = allocator.ToIntPtr(info.sp); context->machineState.r2 = entryPoint.TableOfContents; context->machineState.r3 = context->machineState.r27 = info.argc; context->machineState.r4 = context->machineState.r28 = allocator.ToIntPtr(info.argv); context->machineState.r5 = context->machineState.r29 = allocator.ToIntPtr(info.envp); context->machineState.lr = allocator.ToIntPtr(context->interpreter.GetEndAddress()); context->pc = entryPoint.EntryPoint; context->thread = std::thread(&DebugThreadManager::DebugLoop, this, std::ref(*context), startNow); // this should stay at the end of the method or be scoped std::lock_guard<std::mutex> lock(threadsLock); threads[context->GetThreadId()].reset(context); nextId += 0x10; return *context; }
ThreadContext* PhysicalOperator::CreateOrReuseContext(context_reuse_mode crm) { ThreadContext* target = GetFreeContext(crm); if (target != NULL) { return target; } target = CreateContext(); target->set_locality_(GetCurrentCpuAffinity()); InitContext(target); return target; }
SourceDynamicProfileManager * SourceDynamicProfileManager::Deserialize(T * reader, Recycler* recycler) { uint functionCount; if (!reader->Peek(&functionCount)) { return nullptr; } BVFixed * startupFunctions = BVFixed::New(functionCount, recycler); if (!reader->ReadArray(((char *)startupFunctions), BVFixed::GetAllocSize(functionCount))) { return nullptr; } uint profileCount; if (!reader->Read(&profileCount)) { return nullptr; } ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread(); SourceDynamicProfileManager * sourceDynamicProfileManager = RecyclerNew(threadContext->GetRecycler(), SourceDynamicProfileManager, recycler); sourceDynamicProfileManager->cachedStartupFunctions = startupFunctions; #if DBG_DUMP if(Configuration::Global.flags.Dump.IsEnabled(DynamicProfilePhase)) { Output::Print(L"Loaded: Startup functions bit vector:"); startupFunctions->Dump(); } #endif for (uint i = 0; i < profileCount; i++) { Js::LocalFunctionId functionId; DynamicProfileInfo * dynamicProfileInfo = DynamicProfileInfo::Deserialize(reader, recycler, &functionId); if (dynamicProfileInfo == nullptr || functionId >= functionCount) { return nullptr; } sourceDynamicProfileManager->dynamicProfileInfoMap.Add(functionId, dynamicProfileInfo); } return sourceDynamicProfileManager; }
// 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); } }
void LRWMode::EncryptBlock(ThreadContext& context, uint8 *data, size_t length, uint64 blockIndex) { uint8 i[8]; uint8 t[16]; uint32 b; blockIndex = ((blockIndex - fOffset) << 5) + 1; *(uint64*)i = B_HOST_TO_BENDIAN_INT64(blockIndex); for (b = 0; b < length >> 4; b++) { gf128_mul_by_tab64(i, t, (galois_field_context*)context.BufferFor(fGaloisField)); xor128((uint64*)data, (uint64*)t); fAlgorithm->Encrypt(context, data, 16); xor128((uint64*)data, (uint64*)t); data += 16; if (i[7] != 0xff) i[7]++; else { *(uint64*)i = B_HOST_TO_BENDIAN_INT64( B_BENDIAN_TO_HOST_INT64(*(uint64*)i) + 1); } } memset(t, 0, sizeof (t)); }
void AESAlgorithm::Encrypt(ThreadContext& context, uint8 *data, size_t length) { //dprintf(" aes-encrypt-pre: %x\n", *(int*)data); aes_encrypt(data, data, (const aes_encrypt_ctx*)context.BufferFor(fEncryptScheduler)); //dprintf(" aes-encrypt-post: %x\n", *(int*)data); }
status_t AESAlgorithm::SetKey(ThreadContext& context, const uint8* key, size_t keyLength) { //dprintf("%s-aes key: %x (%lu)\n", fMode == MODE_LRW ? "lrw" : "xts", *(int*)key, keyLength); if (aes_encrypt_key(key, keyLength, (aes_encrypt_ctx*)context.BufferFor(fEncryptScheduler)) != EXIT_SUCCESS) return B_ERROR; if (aes_decrypt_key(key, keyLength, (aes_decrypt_ctx*)context.BufferFor(fDecryptScheduler)) != EXIT_SUCCESS) return B_ERROR; return B_OK; }
status_t LRWMode::SetKey(ThreadContext& context, const uint8* key, size_t keyLength) { //dprintf("lrw key: %x\n", *(int*)key); gf128_tab64_init(key, (struct galois_field_context*)context.BufferFor(fGaloisField)); return B_OK; }
// Recover/Release unused memory and give it back to OS. // The function doesn't throw if the attempt to recover memory fails, in which case it simply does nothing. // Useful when running out of memory e.g. for Arena but there is some recycler memory which has been committed but is unused. void Exception::RecoverUnusedMemory() { ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread(); if (threadContext) { Recycler* threadRecycler = threadContext->GetRecycler(); if (threadRecycler) { try { threadRecycler->CollectNow<CollectOnRecoverFromOutOfMemory>(); } catch (...) { // Technically, exception is a valid scenario: we asked to recover mem, and it couldn't. // Do not let the exception leak out. } } } }
status_t AESAlgorithm::Init(ThreadContext& context) { // Make space for our key schedule buffer fEncryptScheduler = context.AddBuffer(sizeof(aes_encrypt_ctx)); fDecryptScheduler = context.AddBuffer(sizeof(aes_decrypt_ctx)); if (fEncryptScheduler < 0 || fDecryptScheduler < 0) return B_NO_MEMORY; return B_OK; }
void ThreadBoundThreadContextManager::DestroyContextAndEntryForCurrentThread() { AutoCriticalSection lock(ThreadContext::GetCriticalSection()); ThreadContextTLSEntry * entry = ThreadContextTLSEntry::GetEntryForCurrentThread(); if (entry == NULL) { return; } ThreadContext * threadContext = static_cast<ThreadContext *>(entry->GetThreadContext()); entries.Remove(entry); if (threadContext != NULL && threadContext->IsThreadBound()) { ShutdownThreadContext(threadContext); } ThreadContextTLSEntry::CleanupThread(); }
bool Exception::RaiseIfScriptActive(ScriptContext *scriptContext, unsigned kind, PVOID returnAddress) { ThreadContext *threadContext = ThreadContext::GetContextForCurrentThread(); if (threadContext != nullptr && threadContext->IsScriptActive()) { switch (kind) { case ExceptionKind_OutOfMemory: AssertMsg(returnAddress == NULL, "should not have returnAddress passed in"); JavascriptError::ThrowOutOfMemoryError(scriptContext); case ExceptionKind_StackOverflow: JavascriptError::ThrowStackOverflowError(scriptContext, returnAddress); default: AssertMsg(false, "Invalid ExceptionKind"); } } return false; }
void ThreadBoundThreadContextManager::DestroyAllContextsAndEntries() { AutoCriticalSection lock(ThreadContext::GetCriticalSection()); while (!entries.Empty()) { ThreadContextTLSEntry * entry = entries.Head(); ThreadContext * threadContext = static_cast<ThreadContext *>(entry->GetThreadContext()); entries.RemoveHead(); if (threadContext != nullptr) { #if DBG PageAllocator* pageAllocator = threadContext->GetPageAllocator(); if (pageAllocator) { pageAllocator->SetConcurrentThreadId(::GetCurrentThreadId()); } #endif threadContext->ShutdownThreads(); HeapDelete(threadContext); } ThreadContextTLSEntry::Delete(entry); } #if ENABLE_BACKGROUND_JOB_PROCESSOR if (s_sharedJobProcessor != NULL) { s_sharedJobProcessor->Close(); HeapDelete(s_sharedJobProcessor); s_sharedJobProcessor = NULL; } #endif }
void DynamicObjectPropertyEnumerator::Reset() { if (this->object) { enumeratedCount = 0; initialType = object->GetDynamicType(); objectIndex = Constants::NoBigSlot; initialPropertyCount = GetSnapShotSemantics() ? this->object->GetPropertyCount() : Constants::NoBigSlot; // Create the appropriate enumerator object. if (GetSnapShotSemantics() && this->initialType->PrepareForTypeSnapshotEnumeration()) { ScriptContext* scriptContext = this->object->GetScriptContext(); ThreadContext * threadContext = scriptContext->GetThreadContext(); CachedData * data = (CachedData *)threadContext->GetDynamicObjectEnumeratorCache(this->initialType); if (data == nullptr || data->scriptContext != this->requestContext || data->enumNonEnumerable != GetEnumNonEnumerable() || data->enumSymbols != GetEnumSymbols()) { data = RecyclerNewStructPlus(scriptContext->GetRecycler(), this->initialPropertyCount * sizeof(PropertyString *) + this->initialPropertyCount * sizeof(BigPropertyIndex) + this->initialPropertyCount * sizeof(PropertyAttributes), CachedData); data->scriptContext = requestContext; data->cachedCount = 0; data->strings = (PropertyString **)(data + 1); data->indexes = (BigPropertyIndex *)(data->strings + this->initialPropertyCount); data->attributes = (PropertyAttributes*)(data->indexes + this->initialPropertyCount); data->completed = false; data->enumNonEnumerable = GetEnumNonEnumerable(); data->enumSymbols = GetEnumSymbols(); threadContext->AddDynamicObjectEnumeratorCache(this->initialType, data); } this->cachedData = data; this->cachedDataType = this->initialType; } else { this->cachedData = nullptr; this->cachedDataType = nullptr; } } }
/* static */ bool JsrtContext::TrySetCurrent(JsrtContext * context) { Assert(s_tlsSlot != TLS_OUT_OF_INDEXES); ThreadContext * threadContext; //We are not pinning the context after SetCurrentContext, so if the context is not pinned //it might be reclaimed half way during execution. In jsrtshell the runtime was optimized out //at time of JsrtContext::Run by the compiler. //The change is to pin the context at setconcurrentcontext, and unpin the previous one. In //JsDisposeRuntime we'll reject if current context is active, so that will make sure all //contexts are unpinned at time of JsDisposeRuntime. if (context != nullptr) { threadContext = context->GetScriptContext()->GetThreadContext(); if (!ThreadContextTLSEntry::TrySetThreadContext(threadContext)) { return false; } threadContext->GetRecycler()->RootAddRef((LPVOID)context); } else { if (!ThreadContextTLSEntry::ClearThreadContext(true)) { return false; } } JsrtContext* originalContext = (JsrtContext*) TlsGetValue(s_tlsSlot); if (originalContext != nullptr) { originalContext->GetScriptContext()->GetRecycler()->RootRelease((LPVOID) originalContext); } TlsSetValue(s_tlsSlot, context); return true; }
void Utf8SourceInfo::EnsureInitialized(int initialFunctionCount) { ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread(); Recycler* recycler = threadContext->GetRecycler(); if (this->functionBodyDictionary == nullptr) { // This collection is allocated with leaf allocation policy. The references to the function body // here does not keep the function alive. However, the functions remove themselves at finalize // so if a function actually is in this map, it means that it is alive. this->functionBodyDictionary = RecyclerNew(recycler, FunctionBodyDictionary, recycler, initialFunctionCount, threadContext->GetEtwRundownCriticalSection()); } if (CONFIG_FLAG(DeferTopLevelTillFirstCall) && !m_deferredFunctionsInitialized) { Assert(this->m_deferredFunctionsDictionary == nullptr); this->m_deferredFunctionsDictionary = RecyclerNew(recycler, DeferredFunctionsDictionary, recycler, initialFunctionCount, threadContext->GetEtwRundownCriticalSection()); m_deferredFunctionsInitialized = true; } }
// 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 } }
status_t LRWMode::Init(ThreadContext& context, EncryptionAlgorithm* algorithm) { if (algorithm == NULL) return B_BAD_VALUE; fGaloisField = context.AddBuffer(sizeof(struct galois_field_context)); if (fGaloisField < 0) return B_NO_MEMORY; fAlgorithm = algorithm; fAlgorithm->SetMode(this); return B_OK; }
Js::ScriptContext* JsrtContextCore::EnsureScriptContext() { Assert(this->GetJavascriptLibrary() == nullptr); ThreadContext* localThreadContext = this->GetRuntime()->GetThreadContext(); AutoPtr<Js::ScriptContext> newScriptContext(Js::ScriptContext::New(localThreadContext)); newScriptContext->Initialize(); hostContext = HeapNew(ChakraCoreHostScriptContext, newScriptContext); newScriptContext->SetHostScriptContext(hostContext); this->SetJavascriptLibrary(newScriptContext.Detach()->GetLibrary()); Js::JavascriptLibrary *library = this->GetScriptContext()->GetLibrary(); Assert(library != nullptr); localThreadContext->GetRecycler()->RootRelease(library->GetGlobalObject()); library->GetEvalFunctionObject()->SetEntryPoint(&Js::GlobalObject::EntryEval); library->GetFunctionConstructor()->SetEntryPoint(&Js::JavascriptFunction::NewInstance); return this->GetScriptContext(); }
ThreadContext * ThreadBoundThreadContextManager::EnsureContextForCurrentThread() { AutoCriticalSection lock(ThreadContext::GetCriticalSection()); ThreadContextTLSEntry * entry = ThreadContextTLSEntry::GetEntryForCurrentThread(); if (entry == NULL) { ThreadContextTLSEntry::CreateEntryForCurrentThread(); entry = ThreadContextTLSEntry::GetEntryForCurrentThread(); entries.Prepend(entry); } ThreadContext * threadContext = entry->GetThreadContext(); // An existing TLS entry may have a null ThreadContext // DllCanUnload may have cleaned out all the TLS entry when the module lock count is 0, // but the library didn't get unloaded because someone is holding onto ref count via LoadLibrary. // Just reinitialize the thread context. if (threadContext == nullptr) { threadContext = HeapNew(ThreadContext); threadContext->SetIsThreadBound(); if (!ThreadContextTLSEntry::TrySetThreadContext(threadContext)) { HeapDelete(threadContext); return NULL; } } Assert(threadContext != NULL); s_maxNumberActiveThreadContexts = max(s_maxNumberActiveThreadContexts, GetActiveThreadContextCount()); return threadContext; }
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; }
TMMemory::TMMemory() { ThreadContext* tc = ThreadContext::getContext(0); virtOffset = tc->getVirt2RealOffset(); heap = tc->getHeapManager(); }
// // 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 DebugThreadManager::DebugLoop(ThreadContext& context, bool autostart) { context.stopReason = StopReason::InterruptTrap; context.executionState = ThreadState::Stopped; changingContexts.PutOne(ThreadUpdate(context)); if (autostart) { context.Perform(RunCommand::Continue); } Instruction initialInstruction; while (context.executionState != ThreadState::Completed) { RunCommand action = context.GetNextAction(); UInt32* location = allocator.ToPointer<UInt32>(context.pc); try { if (action == RunCommand::Kill) { context.pc = allocator.ToIntPtr(context.interpreter.GetEndAddress()); } else if (action == RunCommand::Continue) { breakpoints->GetRealInstruction(location, initialInstruction); location = context.interpreter.ExecuteOne(location, initialInstruction); context.interpreter.Execute(location); context.pc = allocator.ToIntPtr(context.interpreter.GetEndAddress()); } else if (action == RunCommand::SingleStep) { breakpoints->GetRealInstruction(location, initialInstruction); location = context.interpreter.ExecuteOne(location, initialInstruction); context.pc = allocator.ToIntPtr(location); } else if (action == RunCommand::StepOver) { Instruction instruction(location->Get()); if (instruction.OPCD != 18 || instruction.LK == 0) { // step over is the same as single step, unless we step over a call instruction... location = context.interpreter.ExecuteOne(location); context.pc = allocator.ToIntPtr(location); } else { // ...then we should set a breakpoint on the next instruction, and execute until we reach it, // and make sure the stack is the same size (otherwise we're doing recursion). Breakpoint stopAtNext = breakpoints->CreateBreakpoint(&location[1]); uint32_t stopPC = allocator.ToIntPtr(stopAtNext.GetLocation()); uint32_t sp = context.machineState.r1; do { try { // don't be stuck on the breakpoint if it's the first instruction we execute breakpoints->GetRealInstruction(location, initialInstruction); location = context.interpreter.ExecuteOne(location, stopAtNext.GetInstruction()); context.interpreter.Execute(location); context.pc = allocator.ToIntPtr(context.interpreter.GetEndAddress()); break; } catch (Execution::InterpreterException& ex) { context.pc = ex.GetPC(); auto cause = ex.GetReason().get(); if (dynamic_cast<TrapException*>(cause) == nullptr || context.pc != stopPC) throw; } } while (context.machineState.r1 != sp); } } context.executionState = context.pc == allocator.ToIntPtr(context.interpreter.GetEndAddress()) ? ThreadState::Completed : ThreadState::Stopped; } catch (Execution::InterpreterException& ex) { context.pc = ex.GetPC(); context.executionState = ThreadState::Stopped; auto cause = ex.GetReason().get(); if (dynamic_cast<Execution::InvalidInstructionException*>(cause)) context.stopReason = StopReason::InvalidInstruction; else if (dynamic_cast<Common::AccessViolationException*>(cause)) context.stopReason = StopReason::AccessViolation; else if (dynamic_cast<TrapException*>(cause)) context.stopReason = StopReason::InterruptTrap; } changingContexts.PutOne(ThreadUpdate(context)); } }
void Js::CharClassifier::initClassifier(ScriptContext * scriptContext, CharClassifierModes identifierSupport, CharClassifierModes whiteSpaceSupport, CharClassifierModes generalCharClassificationSupport, bool codePointSupport, bool isES6UnicodeVerboseEnabled, CharClassifierModes es6FallbackMode) { bool es6Supported = true; bool es6ModeNeeded = identifierSupport == CharClassifierModes::ES6 || whiteSpaceSupport == CharClassifierModes::ES6 || generalCharClassificationSupport == CharClassifierModes::ES6; #ifdef ENABLE_ES6_CHAR_CLASSIFIER ThreadContext* threadContext = scriptContext->GetThreadContext(); Js::WindowsGlobalizationAdapter* globalizationAdapter = threadContext->GetWindowsGlobalizationAdapter(); Js::DelayLoadWindowsGlobalization* globLibrary = threadContext->GetWindowsGlobalizationLibrary(); if (es6ModeNeeded) { HRESULT hr = globalizationAdapter->EnsureDataTextObjectsInitialized(globLibrary); // Failed to load windows.globalization.dll or jsintl.dll. No unicodeStatics support // in that case. if (FAILED(hr)) { es6Supported = false; es6FallbackMode = CharClassifierModes::ES5; } else { this->winGlobCharApi = globalizationAdapter->GetUnicodeStatics(); if (this->winGlobCharApi == nullptr) { // No fallback mode, then assert if (es6FallbackMode == CharClassifierModes::ES6) { AssertMsg(false, "Windows::Data::Text::IUnicodeCharactersStatics not initialized"); //Fallback to ES5 just in case for fre builds. es6FallbackMode = CharClassifierModes::ES5; } if (isES6UnicodeVerboseEnabled) { Output::Print(L"Windows::Data::Text::IUnicodeCharactersStatics not initialized\r\n"); } //Default to non-es6 es6Supported = false; } } } #else es6Supported = false; es6FallbackMode = CharClassifierModes::ES5; #endif if (es6ModeNeeded && !es6Supported) { identifierSupport = identifierSupport == CharClassifierModes::ES6 ? es6FallbackMode : identifierSupport; whiteSpaceSupport = whiteSpaceSupport == CharClassifierModes::ES6 ? es6FallbackMode : whiteSpaceSupport; generalCharClassificationSupport = generalCharClassificationSupport == CharClassifierModes::ES6 ? es6FallbackMode : generalCharClassificationSupport; } bigCharIsIdStartFunc = identifierSupport == CharClassifierModes::ES6 ? &CharClassifier::BigCharIsIdStartES6 : &CharClassifier::BigCharIsIdStartDefault; bigCharIsIdContinueFunc = identifierSupport == CharClassifierModes::ES6 ? &CharClassifier::BigCharIsIdContinueES6 : &CharClassifier::BigCharIsIdContinueDefault; bigCharIsWhitespaceFunc = whiteSpaceSupport == CharClassifierModes::ES6 ? &CharClassifier::BigCharIsWhitespaceES6 : &CharClassifier::BigCharIsWhitespaceDefault; skipWhiteSpaceFunc = codePointSupport ? &CharClassifier::SkipWhiteSpaceSurrogate : &CharClassifier::SkipWhiteSpaceNonSurrogate; skipWhiteSpaceStartEndFunc = codePointSupport ? &CharClassifier::SkipWhiteSpaceSurrogateStartEnd : &CharClassifier::SkipWhiteSpaceNonSurrogateStartEnd; skipIdentifierFunc = codePointSupport ? &CharClassifier::SkipIdentifierSurrogate : &CharClassifier::SkipIdentifierNonSurrogate; skipIdentifierStartEndFunc = codePointSupport ? &CharClassifier::SkipIdentifierSurrogateStartEnd : &CharClassifier::SkipIdentifierNonSurrogateStartEnd; if (generalCharClassificationSupport == CharClassifierModes::ES6) { getBigCharTypeFunc = &CharClassifier::GetBigCharTypeES6; getBigCharFlagsFunc = &CharClassifier::GetBigCharFlagsES6; } else if (generalCharClassificationSupport == CharClassifierModes::ES5) { getBigCharTypeFunc = &GetBigCharType; getBigCharFlagsFunc = &GetBigCharFlags5; } else { getBigCharTypeFunc = &GetBigCharType; getBigCharFlagsFunc = &GetBigCharFlags; } }
CHAKRA_API JsDiagSetStepType( _In_ JsDiagStepType stepType) { #ifndef ENABLE_SCRIPT_DEBUGGING return JsErrorCategoryUsage; #else return ContextAPIWrapper_NoRecord<true>([&](Js::ScriptContext * scriptContext) -> JsErrorCode { JsrtContext *currentContext = JsrtContext::GetCurrent(); JsrtRuntime* runtime = currentContext->GetRuntime(); VALIDATE_RUNTIME_IS_AT_BREAK(runtime); JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager(); VALIDATE_IS_DEBUGGING(jsrtDebugManager); if (stepType == JsDiagStepTypeStepIn) { jsrtDebugManager->SetResumeType(BREAKRESUMEACTION_STEP_INTO); } else if (stepType == JsDiagStepTypeStepOut) { jsrtDebugManager->SetResumeType(BREAKRESUMEACTION_STEP_OUT); } else if (stepType == JsDiagStepTypeStepOver) { jsrtDebugManager->SetResumeType(BREAKRESUMEACTION_STEP_OVER); } else if (stepType == JsDiagStepTypeStepBack) { #if ENABLE_TTD ThreadContext* threadContext = runtime->GetThreadContext(); if(!threadContext->IsRuntimeInTTDMode()) { //Don't want to fail hard when user accidentally clicks this so pring message and step forward fprintf(stderr, "Must be in replay mode to use reverse-step - launch with \"--replay-debug\" flag in Node."); jsrtDebugManager->SetResumeType(BREAKRESUMEACTION_STEP_OVER); } else { threadContext->TTDExecutionInfo->SetPendingTTDStepBackMove(); //don't worry about BP suppression because we are just going to throw after we return jsrtDebugManager->SetResumeType(BREAKRESUMEACTION_CONTINUE); } #else return JsErrorInvalidArgument; #endif } else if (stepType == JsDiagStepTypeReverseContinue) { #if ENABLE_TTD ThreadContext* threadContext = runtime->GetThreadContext(); if(!threadContext->IsRuntimeInTTDMode()) { //Don't want to fail hard when user accidentally clicks this so pring message and step forward fprintf(stderr, "Must be in replay mode to use reverse-continue - launch with \"--replay-debug\" flag in Node."); jsrtDebugManager->SetResumeType(BREAKRESUMEACTION_CONTINUE); } else { threadContext->TTDExecutionInfo->SetPendingTTDReverseContinueMove(JsTTDMoveMode::JsTTDMoveScanIntervalForContinue); //don't worry about BP suppression because we are just going to throw after we return jsrtDebugManager->SetResumeType(BREAKRESUMEACTION_CONTINUE); } #else return JsErrorInvalidArgument; #endif } else if (stepType == JsDiagStepTypeContinue) { jsrtDebugManager->SetResumeType(BREAKRESUMEACTION_CONTINUE); } return JsNoError; }); #endif }
CHAKRA_API JsDiagStartDebugging( _In_ JsRuntimeHandle runtimeHandle, _In_ JsDiagDebugEventCallback debugEventCallback, _In_opt_ void* callbackState) { #ifndef ENABLE_SCRIPT_DEBUGGING return JsErrorCategoryUsage; #else return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode { VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle); PARAM_NOT_NULL(debugEventCallback); JsrtRuntime * runtime = JsrtRuntime::FromHandle(runtimeHandle); ThreadContext * threadContext = runtime->GetThreadContext(); VALIDATE_RUNTIME_STATE_FOR_START_STOP_DEBUGGING(threadContext); if (runtime->GetJsrtDebugManager() != nullptr && runtime->GetJsrtDebugManager()->IsDebugEventCallbackSet()) { return JsErrorDiagAlreadyInDebugMode; } // Create the debug object to save callback function and data runtime->EnsureJsrtDebugManager(); JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager(); jsrtDebugManager->SetDebugEventCallback(debugEventCallback, callbackState); if (threadContext->GetDebugManager() != nullptr) { threadContext->GetDebugManager()->SetLocalsDisplayFlags(Js::DebugManager::LocalsDisplayFlags::LocalsDisplayFlags_NoGroupMethods); } for (Js::ScriptContext *scriptContext = runtime->GetThreadContext()->GetScriptContextList(); scriptContext != nullptr && !scriptContext->IsClosed(); scriptContext = scriptContext->next) { Assert(!scriptContext->IsScriptContextInDebugMode()); Js::DebugContext* debugContext = scriptContext->GetDebugContext(); if (debugContext->GetHostDebugContext() == nullptr) { debugContext->SetHostDebugContext(jsrtDebugManager); } HRESULT hr; if (FAILED(hr = scriptContext->OnDebuggerAttached())) { Debugger_AttachDetach_fatal_error(hr); // Inconsistent state, we can't continue from here return JsErrorFatal; } // ScriptContext might get closed in OnDebuggerAttached if (!scriptContext->IsClosed()) { Js::ProbeContainer* probeContainer = debugContext->GetProbeContainer(); probeContainer->InitializeInlineBreakEngine(jsrtDebugManager); probeContainer->InitializeDebuggerScriptOptionCallback(jsrtDebugManager); } } return JsNoError; }); #endif }
void ThreadBoundThreadContextManager::DestroyAllContexts() { #if ENABLE_BACKGROUND_JOB_PROCESSOR JsUtil::BackgroundJobProcessor * jobProcessor = NULL; #endif { AutoCriticalSection lock(ThreadContext::GetCriticalSection()); ThreadContextTLSEntry * currentEntry = ThreadContextTLSEntry::GetEntryForCurrentThread(); if (currentEntry == NULL) { // We need a current thread entry so that we can use it to release any thread contexts // we find below. try { AUTO_NESTED_HANDLED_EXCEPTION_TYPE(ExceptionType_OutOfMemory); currentEntry = ThreadContextTLSEntry::CreateEntryForCurrentThread(); entries.Prepend(currentEntry); } catch (Js::OutOfMemoryException) { return; } } else { // We need to clear out the current thread entry so that we can use it to release any // thread contexts we find below. ThreadContext * threadContext = static_cast<ThreadContext *>(currentEntry->GetThreadContext()); if (threadContext != NULL) { if (threadContext->IsThreadBound()) { ShutdownThreadContext(threadContext); ThreadContextTLSEntry::ClearThreadContext(currentEntry, false); } else { ThreadContextTLSEntry::ClearThreadContext(currentEntry, true); } } } EntryList::Iterator iter(&entries); while (iter.Next()) { ThreadContextTLSEntry * entry = iter.Data(); ThreadContext * threadContext = static_cast<ThreadContext *>(entry->GetThreadContext()); if (threadContext != nullptr) { // Found a thread context. Remove it from the containing entry. ThreadContextTLSEntry::ClearThreadContext(entry, true); // Now set it to our thread's entry. ThreadContextTLSEntry::SetThreadContext(currentEntry, threadContext); // Clear it out. ShutdownThreadContext(threadContext); // Now clear it out of our entry. ThreadContextTLSEntry::ClearThreadContext(currentEntry, false); } } // We can only clean up our own TLS entry, so we're going to go ahead and do that here. entries.Remove(currentEntry); ThreadContextTLSEntry::CleanupThread(); #if ENABLE_BACKGROUND_JOB_PROCESSOR if (s_sharedJobProcessor != NULL) { jobProcessor = s_sharedJobProcessor; s_sharedJobProcessor = NULL; jobProcessor->Close(); } #endif } #if ENABLE_BACKGROUND_JOB_PROCESSOR if (jobProcessor != NULL) { HeapDelete(jobProcessor); } #endif }