Bug 1392408 Part 1 - Add interface to help convert SavedFrames to JSON, r=jimb.

--HG--
extra : rebase_source : 994a07e6f5af10d4f1c94e459d9af5b7db22703e
This commit is contained in:
Brian Hackett 2019-04-19 06:57:06 -10:00
parent 1b63eb551b
commit 961e486752
2 changed files with 66 additions and 0 deletions

View File

@ -128,6 +128,17 @@ extern JS_PUBLIC_API SavedFrameResult GetSavedFrameParent(
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 {

View File

@ -1088,6 +1088,61 @@ JS_PUBLIC_API bool IsUnwrappedSavedFrame(JSObject* 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 {