CHAKRA_API JsDiagRemoveBreakpoint( _In_ unsigned int breakpointId) { #ifndef ENABLE_SCRIPT_DEBUGGING return JsErrorCategoryUsage; #else return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode { JsrtContext *currentContext = JsrtContext::GetCurrent(); JsrtRuntime* runtime = currentContext->GetRuntime(); ThreadContextScope scope(runtime->GetThreadContext()); if (!scope.IsValid()) { return JsErrorWrongThread; } JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager(); VALIDATE_IS_DEBUGGING(jsrtDebugManager); if (!jsrtDebugManager->RemoveBreakpoint(breakpointId)) { return JsErrorInvalidArgument; } return JsNoError; }); #endif }
CHAKRA_API JsDiagGetSource( _In_ unsigned int scriptId, _Out_ JsValueRef *source) { #ifndef ENABLE_SCRIPT_DEBUGGING return JsErrorCategoryUsage; #else return ContextAPIWrapper_NoRecord<false>([&](Js::ScriptContext *scriptContext) -> JsErrorCode { PARAM_NOT_NULL(source); *source = JS_INVALID_REFERENCE; JsrtContext *currentContext = JsrtContext::GetCurrent(); JsrtDebugManager* jsrtDebugManager = currentContext->GetRuntime()->GetJsrtDebugManager(); VALIDATE_IS_DEBUGGING(jsrtDebugManager); Js::DynamicObject* sourceObject = jsrtDebugManager->GetSource(scriptContext, scriptId); if (sourceObject != nullptr) { *source = sourceObject; return JsNoError; } return JsErrorInvalidArgument; }); #endif }
CHAKRA_API JsDiagGetScripts( _Out_ JsValueRef *scriptsArray) { #ifndef ENABLE_SCRIPT_DEBUGGING return JsErrorCategoryUsage; #else return ContextAPIWrapper_NoRecord<false>([&](Js::ScriptContext *scriptContext) -> JsErrorCode { PARAM_NOT_NULL(scriptsArray); *scriptsArray = JS_INVALID_REFERENCE; JsrtContext *currentContext = JsrtContext::GetCurrent(); JsrtDebugManager* jsrtDebugManager = currentContext->GetRuntime()->GetJsrtDebugManager(); VALIDATE_IS_DEBUGGING(jsrtDebugManager); Js::JavascriptArray* scripts = jsrtDebugManager->GetScripts(scriptContext); if (scripts != nullptr) { *scriptsArray = scripts; return JsNoError; } return JsErrorDiagUnableToPerformAction; }); #endif }
CHAKRA_API JsDiagSetBreakpoint( _In_ unsigned int scriptId, _In_ unsigned int lineNumber, _In_ unsigned int columnNumber, _Out_ JsValueRef *breakpoint) { #ifndef ENABLE_SCRIPT_DEBUGGING return JsErrorCategoryUsage; #else return ContextAPIWrapper_NoRecord<false>([&](Js::ScriptContext* scriptContext) -> JsErrorCode { PARAM_NOT_NULL(breakpoint); *breakpoint = JS_INVALID_REFERENCE; JsrtContext* currentContext = JsrtContext::GetCurrent(); JsrtRuntime* runtime = currentContext->GetRuntime(); ThreadContextScope scope(runtime->GetThreadContext()); if (!scope.IsValid()) { return JsErrorWrongThread; } VALIDATE_IS_DEBUGGING(runtime->GetJsrtDebugManager()); Js::Utf8SourceInfo* utf8SourceInfo = nullptr; for (Js::ScriptContext* currentScriptContext = runtime->GetThreadContext()->GetScriptContextList(); currentScriptContext != nullptr && utf8SourceInfo == nullptr && !currentScriptContext->IsClosed(); currentScriptContext = currentScriptContext->next) { currentScriptContext->MapScript([&](Js::Utf8SourceInfo* sourceInfo) -> bool { if (sourceInfo->GetSourceInfoId() == scriptId) { utf8SourceInfo = sourceInfo; return true; } return false; }); } if (utf8SourceInfo != nullptr && utf8SourceInfo->HasDebugDocument()) { JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager(); Js::DynamicObject* bpObject = jsrtDebugManager->SetBreakPoint(currentContext->GetScriptContext(), utf8SourceInfo, lineNumber, columnNumber); if(bpObject != nullptr) { *breakpoint = bpObject; return JsNoError; } return JsErrorDiagUnableToPerformAction; } return JsErrorDiagObjectNotFound; }); #endif }
CHAKRA_API JsDiagGetBreakpoints( _Out_ JsValueRef *breakpoints) { #ifndef ENABLE_SCRIPT_DEBUGGING return JsErrorCategoryUsage; #else return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode { PARAM_NOT_NULL(breakpoints); *breakpoints = JS_INVALID_REFERENCE; JsrtContext *currentContext = JsrtContext::GetCurrent(); Js::JavascriptArray* bpsArray = currentContext->GetScriptContext()->GetLibrary()->CreateArray(); JsrtRuntime * runtime = currentContext->GetRuntime(); ThreadContextScope scope(runtime->GetThreadContext()); if (!scope.IsValid()) { return JsErrorWrongThread; } JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager(); VALIDATE_IS_DEBUGGING(jsrtDebugManager); for (Js::ScriptContext *scriptContext = runtime->GetThreadContext()->GetScriptContextList(); scriptContext != nullptr && !scriptContext->IsClosed(); scriptContext = scriptContext->next) { jsrtDebugManager->GetBreakpoints(&bpsArray, scriptContext); } *breakpoints = bpsArray; return JsNoError; }); #endif }
/* 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; }
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 }