void AutoEntryScript::DocshellEntryMonitor::Entry(JSContext* aCx, JSFunction* aFunction, JSScript* aScript, JS::Handle<JS::Value> aAsyncStack, JS::Handle<JSString*> aAsyncCause) { JS::Rooted<JSFunction*> rootedFunction(aCx); if (aFunction) { rootedFunction = aFunction; } JS::Rooted<JSScript*> rootedScript(aCx); if (aScript) { rootedScript = aScript; } nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx))); if (!window || !window->GetDocShell() || !window->GetDocShell()->GetRecordProfileTimelineMarkers()) { return; } nsCOMPtr<nsIDocShell> docShellForJSRunToCompletion = window->GetDocShell(); nsString filename; uint32_t lineNumber = 0; js::AutoStableStringChars functionName(aCx); if (rootedFunction) { JS::Rooted<JSString*> displayId(aCx, JS_GetFunctionDisplayId(rootedFunction)); if (displayId) { if (!functionName.initTwoByte(aCx, displayId)) { JS_ClearPendingException(aCx); return; } } } if (!rootedScript) { rootedScript = JS_GetFunctionScript(aCx, rootedFunction); } if (rootedScript) { filename = NS_ConvertUTF8toUTF16(JS_GetScriptFilename(rootedScript)); lineNumber = JS_GetScriptBaseLineNumber(aCx, rootedScript); } if (!filename.IsEmpty() || functionName.isTwoByte()) { const char16_t* functionNameChars = functionName.isTwoByte() ? functionName.twoByteChars() : nullptr; JS::Rooted<JS::Value> asyncCauseValue(aCx, aAsyncCause ? StringValue(aAsyncCause) : JS::NullValue()); docShellForJSRunToCompletion->NotifyJSRunToCompletionStart(mReason, functionNameChars, filename.BeginReading(), lineNumber, aAsyncStack, asyncCauseValue); } }
nsresult XPCJSStackFrame::CreateStack(JSContext* cx, XPCJSStackFrame** stack) { static const unsigned MAX_FRAMES = 100; nsRefPtr<XPCJSStackFrame> first = new XPCJSStackFrame(); nsRefPtr<XPCJSStackFrame> self = first; JS::StackDescription* desc = JS::DescribeStack(cx, MAX_FRAMES); if (!desc) return NS_ERROR_FAILURE; for (size_t i = 0; i < desc->nframes && self; i++) { self->mLanguage = nsIProgrammingLanguage::JAVASCRIPT; JSAutoCompartment ac(cx, desc->frames[i].script); const char* filename = JS_GetScriptFilename(cx, desc->frames[i].script); if (filename) { self->mFilename = (char*) nsMemory::Clone(filename, sizeof(char)*(strlen(filename)+1)); } self->mLineno = desc->frames[i].lineno; JSFunction* fun = desc->frames[i].fun; if (fun) { JS::RootedString funid(cx, JS_GetFunctionDisplayId(fun)); if (funid) { size_t length = JS_GetStringEncodingLength(cx, funid); if (length != size_t(-1)) { self->mFunname = static_cast<char *>(nsMemory::Alloc(length + 1)); if (self->mFunname) { JS_EncodeStringToBuffer(cx, funid, self->mFunname, length); self->mFunname[length] = '\0'; } } } } XPCJSStackFrame* frame = new XPCJSStackFrame(); self->mCaller = frame; self = frame; } JS::FreeStackDescription(cx, desc); *stack = first.forget().get(); return NS_OK; }
std::string gjs_debug_value(JS::Value v) { std::ostringstream out; if (v.isNull()) return "null"; if (v.isUndefined()) return "undefined"; if (v.isInt32()) { out << v.toInt32(); return out.str(); } if (v.isDouble()) { out << v.toDouble(); return out.str(); } if (v.isString()) { out << gjs_debug_string(v.toString()); return out.str(); } if (v.isSymbol()) { out << gjs_debug_symbol(v.toSymbol()); return out.str(); } if (v.isObject() && js::IsFunctionObject(&v.toObject())) { JSFunction* fun = JS_GetObjectFunction(&v.toObject()); JSString *display_name = JS_GetFunctionDisplayId(fun); if (display_name) out << "<function " << gjs_debug_string(display_name); else out << "<unnamed function"; out << " at " << fun << '>'; return out.str(); } if (v.isObject()) { out << gjs_debug_object(&v.toObject()); return out.str(); } if (v.isBoolean()) return (v.toBoolean() ? "true" : "false"); if (v.isMagic()) return "<magic>"; return "unexpected value"; }