Bug 1392408 Part 1 - Add interface to help convert SavedFrames to JSON, r=jimb.
☠☠ backed out by 9dbf4a541fff ☠ ☠
authorBrian Hackett <bhackett1024@gmail.com>
Thu, 02 May 2019 08:25:26 -1000
changeset 531261 337d93c03c2e540b3f1d220f4ccbd1f9deb37435
parent 531260 da538647fa04239bac749064686e8971d22ff355
child 531262 b765eaf69bcb947cedacfefd424a43fa403f0aa4
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimb
bugs1392408
milestone68.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 1392408 Part 1 - Add interface to help convert SavedFrames to JSON, r=jimb.
js/public/SavedFrameAPI.h
js/src/vm/SavedStacks.cpp
--- a/js/public/SavedFrameAPI.h
+++ b/js/public/SavedFrameAPI.h
@@ -123,16 +123,27 @@ extern JS_PUBLIC_API SavedFrameResult Ge
  * it is the oldest frame in the stack. The `parentp` out parameter is _NOT_
  * guaranteed to be in the cx's compartment. Defaults to nullptr.
  */
 extern JS_PUBLIC_API SavedFrameResult GetSavedFrameParent(
     JSContext* cx, JSPrincipals* principals, Handle<JSObject*> savedFrame,
     MutableHandle<JSObject*> parentp,
     SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
 
+/**
+ * Given a SavedFrame object, convert it and its transitive parents to plain
+ * objects. Because SavedFrame objects store their properties on the prototype,
+ * they cannot be usefully stringified to JSON. Assigning their properties to
+ * plain objects allow those objects to be stringified and the saved frame stack
+ * can be encoded as a string.
+ */
+JS_PUBLIC_API JSObject* ConvertSavedFrameToPlainObject(
+    JSContext* cx, JS::HandleObject savedFrame,
+    JS::SavedFrameSelfHosted selfHosted);
+
 }  // namespace JS
 
 namespace js {
 
 /**
  * Get the first SavedFrame object in this SavedFrame stack whose principals are
  * subsumed by the given |principals|. If there is no such frame, return
  * nullptr.
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -1083,16 +1083,71 @@ JS_PUBLIC_API bool IsMaybeWrappedSavedFr
   return obj->canUnwrapAs<js::SavedFrame>();
 }
 
 JS_PUBLIC_API bool IsUnwrappedSavedFrame(JSObject* obj) {
   MOZ_ASSERT(obj);
   return obj->is<js::SavedFrame>();
 }
 
+static bool AssignProperty(JSContext* cx, HandleObject dst, HandleObject src,
+                           const char* property) {
+  RootedValue v(cx);
+  return JS_GetProperty(cx, src, property, &v) &&
+         JS_DefineProperty(cx, dst, property, v, JSPROP_ENUMERATE);
+}
+
+JS_PUBLIC_API JSObject* ConvertSavedFrameToPlainObject
+    (JSContext* cx, HandleObject savedFrameArg, SavedFrameSelfHosted selfHosted) {
+  MOZ_ASSERT(savedFrameArg);
+
+  RootedObject savedFrame(cx, savedFrameArg);
+  RootedObject baseConverted(cx), lastConverted(cx);
+  RootedValue v(cx);
+
+  baseConverted = lastConverted = JS_NewObject(cx, nullptr);
+  if (!baseConverted) {
+    return nullptr;
+  }
+
+  bool foundParent;
+  do {
+    if (!AssignProperty(cx, lastConverted, savedFrame, "source") ||
+        !AssignProperty(cx, lastConverted, savedFrame, "sourceId") ||
+        !AssignProperty(cx, lastConverted, savedFrame, "line") ||
+        !AssignProperty(cx, lastConverted, savedFrame, "column") ||
+        !AssignProperty(cx, lastConverted, savedFrame, "functionDisplayName") ||
+        !AssignProperty(cx, lastConverted, savedFrame, "asyncCause")) {
+      return nullptr;
+    }
+
+    const char* parentProperties[] = { "parent", "asyncParent" };
+    foundParent = false;
+    for (const char* prop : parentProperties) {
+      if (!JS_GetProperty(cx, savedFrame, prop, &v)) {
+        return nullptr;
+      }
+      if (v.isObject()) {
+        RootedObject nextConverted(cx, JS_NewObject(cx, nullptr));
+        if (!nextConverted ||
+            !JS_DefineProperty(cx, lastConverted, prop, nextConverted,
+                               JSPROP_ENUMERATE)) {
+          return nullptr;
+        }
+        lastConverted = nextConverted;
+        savedFrame = &v.toObject();
+        foundParent = true;
+        break;
+      }
+    }
+  } while (foundParent);
+
+  return baseConverted;
+}
+
 } /* namespace JS */
 
 namespace js {
 
 /* static */
 bool SavedFrame::sourceProperty(JSContext* cx, unsigned argc, Value* vp) {
   THIS_SAVEDFRAME(cx, argc, vp, "(get source)", args, frame);
   JSPrincipals* principals = cx->realm()->principals();