Bug 1515214 - Add CallbackObject::GetDescription. r=bzbarsky
☠☠ backed out by 2d48960b2816 ☠ ☠
authorMarkus Stange <mstange@themasta.com>
Thu, 07 Mar 2019 18:04:43 +0000
changeset 520895 9aabc3ad2470032f34bf20cafcb5c0bc2c61d64e
parent 520894 9bac094cec23aa298e04e8326cbd8d9b558575f0
child 520896 7c4973b0d0e80a4f6b9172454c8f709b60f9e431
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs1515214
milestone67.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. 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
@@ -121,16 +121,73 @@ 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;
+  }
+
+  JSObject* unwrappedCallback = 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
@@ -153,16 +153,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);
   }
 
  protected:
   virtual ~CallbackObject() { mozilla::DropJSObjects(this); }
 
   explicit CallbackObject(CallbackObject* aCallbackObject) {