Bug 1515214 - Add CallbackObject::GetDescription and TimeoutHandler::GetDescription. r=bzbarsky
authorMarkus Stange <mstange@themasta.com>
Wed, 10 Jul 2019 20:48:14 +0000
changeset 482261 a6ad66ea6ddd7dd14eafc95f5128ee15c40cae18
parent 482260 5d2091f9acb34a4fd0733e01e5ce005e643c13b8
child 482262 835a18c6213d447af34dfa1fa19bcb8ae6dade86
push id36272
push usercsabou@mozilla.com
push dateThu, 11 Jul 2019 04:03:34 +0000
treeherdermozilla-central@925e5936677c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs1515214
milestone70.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1515214 - Add CallbackObject::GetDescription and TimeoutHandler::GetDescription. r=bzbarsky This allows us to create profiler markers whose description contains the name of the function and its file / line number. This allows the profiler UI to match up setTimeout callbacks for multiple instances of the same page load, in order to create meaningful profile comparisons based on markers. Differential Revision: https://phabricator.services.mozilla.com/D19192
dom/bindings/CallbackObject.cpp
dom/bindings/CallbackObject.h
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -126,16 +126,74 @@ JSObject* CallbackObject::Callback(JSCon
   if (!callback) {
     callback = JS_NewDeadWrapper(aCx);
   }
 
   MOZ_DIAGNOSTIC_ASSERT(callback);
   return callback;
 }
 
+void CallbackObject::GetDescription(nsACString& aOutString) {
+  JSObject* wrappedCallback = CallbackOrNull();
+  if (!wrappedCallback) {
+    aOutString.Append("<callback from a nuked compartment>");
+    return;
+  }
+
+  JS::Rooted<JSObject*> unwrappedCallback(
+      RootingCx(), js::CheckedUnwrapStatic(wrappedCallback));
+  if (!unwrappedCallback) {
+    aOutString.Append("<not a function>");
+    return;
+  }
+
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JSContext* cx = jsapi.cx();
+
+  JS::RootedObject rootedCallback(cx, unwrappedCallback);
+  JSAutoRealm ar(cx, rootedCallback);
+
+  JS::Rooted<JSFunction*> rootedFunction(cx,
+                                         JS_GetObjectFunction(rootedCallback));
+  if (!rootedFunction) {
+    aOutString.Append("<not a function>");
+    return;
+  }
+
+  JS::Rooted<JSString*> displayId(cx, JS_GetFunctionDisplayId(rootedFunction));
+  if (displayId) {
+    nsAutoJSString funcNameStr;
+    if (funcNameStr.init(cx, displayId)) {
+      if (funcNameStr.IsEmpty()) {
+        aOutString.Append("<empty name>");
+      } else {
+        AppendUTF16toUTF8(funcNameStr, aOutString);
+      }
+    } else {
+      aOutString.Append("<function name string failed to materialize>");
+      jsapi.ClearException();
+    }
+  } else {
+    aOutString.Append("<anonymous>");
+  }
+
+  JS::Rooted<JSScript*> rootedScript(cx,
+                                     JS_GetFunctionScript(cx, rootedFunction));
+  if (!rootedScript) {
+    return;
+  }
+
+  aOutString.Append(" (");
+  aOutString.Append(JS_GetScriptFilename(rootedScript));
+  aOutString.Append(":");
+  aOutString.AppendInt(JS_GetScriptBaseLineNumber(cx, rootedScript));
+  aOutString.Append(")");
+}
+
 CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
                                      ErrorResult& aRv,
                                      const char* aExecutionReason,
                                      ExceptionHandling aExceptionHandling,
                                      JS::Realm* aRealm,
                                      bool aIsJSImplementedWebIDL)
     : mCx(nullptr),
       mRealm(aRealm),
--- a/dom/bindings/CallbackObject.h
+++ b/dom/bindings/CallbackObject.h
@@ -157,16 +157,23 @@ class CallbackObject : public nsISupport
     // report it.
     eRethrowContentExceptions,
     // Throw exceptions to the caller code, unless the caller realm is
     // provided, the exception is not a DOMException from the caller
     // realm, and the caller realm does not subsume our unwrapped callback.
     eRethrowExceptions
   };
 
+  // Append a UTF-8 string to aOutString that describes the callback function,
+  // for use in logging or profiler markers.
+  // The string contains the function name and its source location, if
+  // available, in the following format:
+  // "<functionName> (<sourceURL>:<lineNumber>)"
+  void GetDescription(nsACString& aOutString);
+
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
     return aMallocSizeOf(this);
   }
 
   // Used for cycle collection optimization.  Should return true only if all our
   // outgoing edges are to known-live objects.  In that case, there's no point
   // traversing our edges to them, because we know they can't be collected
   // anyway.