зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1280818 part 1 - Add the ability to capture the stack until the first non-self-hosted frame with the given principals; r=bz,jimb
Before this commit, one could either capture all stack frames (by passing maxFrameCount = 0) or a maximum of N frames (by passing maxFrameCount = N). This commit introduces the ability to capture the first frame (by default ignoring self hosted frames) with some target principals. This new option required replacing the `unsigned maxFrameCount` parameter with the introduction of a new sum type to describe the stack capturing behavior: StackCapture = AllFrames | MaxFrames(unsigned n) | FirstSubsumedFrame(JSPrincipals* p, bool ignoreSelfHosted) This is obviously more wordy in C++ than we'd like, but does make the stack capturing more explicit rather than relying on the sentinal 0 to stand in for infinity.
This commit is contained in:
Родитель
d4b9fb7cfb
Коммит
ea16cfab73
|
@ -673,7 +673,10 @@ CreateStack(JSContext* aCx, int32_t aMaxDepth)
|
|||
}
|
||||
|
||||
JS::Rooted<JSObject*> stack(aCx);
|
||||
if (!JS::CaptureCurrentStack(aCx, &stack, aMaxDepth)) {
|
||||
JS::StackCapture capture = aMaxDepth == 0
|
||||
? JS::StackCapture(JS::AllFrames())
|
||||
: JS::StackCapture(JS::MaxFrames(aMaxDepth));
|
||||
if (!JS::CaptureCurrentStack(aCx, &stack, mozilla::Move(capture))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto /
|
|||
// but oh well.
|
||||
RootedObject stack(cx);
|
||||
if (cx->options().asyncStack() || cx->compartment()->isDebuggee()) {
|
||||
if (!JS::CaptureCurrentStack(cx, &stack, 0))
|
||||
if (!JS::CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::AllFrames())))
|
||||
return nullptr;
|
||||
}
|
||||
promise->setFixedSlot(PROMISE_ALLOCATION_SITE_SLOT, ObjectOrNullValue(stack));
|
||||
|
@ -425,7 +425,7 @@ PromiseObject::onSettled(JSContext* cx)
|
|||
Rooted<PromiseObject*> promise(cx, this);
|
||||
RootedObject stack(cx);
|
||||
if (cx->options().asyncStack() || cx->compartment()->isDebuggee()) {
|
||||
if (!JS::CaptureCurrentStack(cx, &stack, 0)) {
|
||||
if (!JS::CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::AllFrames()))) {
|
||||
cx->clearPendingException();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1103,7 +1103,7 @@ SaveStack(JSContext* cx, unsigned argc, Value* vp)
|
|||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
unsigned maxFrameCount = 0;
|
||||
JS::StackCapture capture((JS::AllFrames()));
|
||||
if (args.length() >= 1) {
|
||||
double d;
|
||||
if (!ToNumber(cx, args[0], &d))
|
||||
|
@ -1114,7 +1114,8 @@ SaveStack(JSContext* cx, unsigned argc, Value* vp)
|
|||
"not a valid maximum frame count", NULL);
|
||||
return false;
|
||||
}
|
||||
maxFrameCount = d;
|
||||
if (d > 0)
|
||||
capture = JS::StackCapture(JS::MaxFrames(d));
|
||||
}
|
||||
|
||||
JSCompartment* targetCompartment = cx->compartment();
|
||||
|
@ -1134,7 +1135,7 @@ SaveStack(JSContext* cx, unsigned argc, Value* vp)
|
|||
RootedObject stack(cx);
|
||||
{
|
||||
AutoCompartment ac(cx, targetCompartment);
|
||||
if (!JS::CaptureCurrentStack(cx, &stack, maxFrameCount))
|
||||
if (!JS::CaptureCurrentStack(cx, &stack, mozilla::Move(capture)))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1145,6 +1146,37 @@ SaveStack(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CaptureFirstSubsumedFrame(JSContext* cx, unsigned argc, JS::Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (!args.requireAtLeast(cx, "captureFirstSubsumedFrame", 1))
|
||||
return false;
|
||||
|
||||
if (!args[0].isObject()) {
|
||||
JS_ReportError(cx, "The argument must be an object");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject obj(cx, &args[0].toObject());
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj) {
|
||||
JS_ReportError(cx, "Denied permission to object.");
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::StackCapture capture(JS::FirstSubsumedFrame(cx, obj->compartment()->principals()));
|
||||
if (args.length() > 1)
|
||||
capture.as<JS::FirstSubsumedFrame>().ignoreSelfHosted = JS::ToBoolean(args[1]);
|
||||
|
||||
JS::RootedObject capturedStack(cx);
|
||||
if (!JS::CaptureCurrentStack(cx, &capturedStack, mozilla::Move(capture)))
|
||||
return false;
|
||||
|
||||
args.rval().setObjectOrNull(capturedStack);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CallFunctionFromNativeFrame(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
@ -3603,6 +3635,12 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
|
|||
" of frames. If 'compartment' is given, allocate the js::SavedFrame instances\n"
|
||||
" with the given object's compartment."),
|
||||
|
||||
JS_FN_HELP("captureFirstSubsumedFrame", CaptureFirstSubsumedFrame, 1, 0,
|
||||
"saveStack(object [, shouldIgnoreSelfHosted = true]])",
|
||||
" Capture a stack back to the first frame whose principals are subsumed by the\n"
|
||||
" object's compartment's principals. If 'shouldIgnoreSelfHosted' is given,\n"
|
||||
" control whether self-hosted frames are considered when checking principals."),
|
||||
|
||||
JS_FN_HELP("callFunctionFromNativeFrame", CallFunctionFromNativeFrame, 1, 0,
|
||||
"callFunctionFromNativeFrame(function)",
|
||||
" Call 'function' with a (C++-)native frame on stack.\n"
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
// Create two different globals whose compartments have two different
|
||||
// principals. Test getting the first frame on the stack with some given
|
||||
// principals in various configurations of JS stack and of wanting self-hosted
|
||||
// frames or not.
|
||||
|
||||
const g1 = newGlobal({
|
||||
principal: 0xffff
|
||||
});
|
||||
|
||||
const g2 = newGlobal({
|
||||
principal: 0xff
|
||||
});
|
||||
|
||||
// Introduce everyone to themselves and each other.
|
||||
g1.g2 = g2.g2 = g2;
|
||||
g1.g1 = g2.g1 = g1;
|
||||
|
||||
g1.g2obj = g2.eval("new Object");
|
||||
|
||||
g1.evaluate(`
|
||||
const global = this;
|
||||
|
||||
// Capture the stack back to the first frame in the g2 global.
|
||||
function capture(shouldIgnoreSelfHosted = true) {
|
||||
return captureFirstSubsumedFrame(global.g2obj, shouldIgnoreSelfHosted);
|
||||
}
|
||||
`, {
|
||||
fileName: "script1.js"
|
||||
});
|
||||
|
||||
g2.evaluate(`
|
||||
const capture = g1.capture;
|
||||
|
||||
// Use our Function.prototype.bind, not capture.bind (which is ===
|
||||
// g1.Function.prototype.bind) so that the generated bound function is in our
|
||||
// compartment and has our principals.
|
||||
const boundTrue = Function.prototype.bind.call(capture, null, true);
|
||||
const boundFalse = Function.prototype.bind.call(capture, null, false);
|
||||
|
||||
function getOldestFrame(stack) {
|
||||
while (stack.parent) {
|
||||
stack = stack.parent;
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
||||
function dumpStack(name, stack) {
|
||||
print("Stack " + name + " =");
|
||||
while (stack) {
|
||||
print(" " + stack.functionDisplayName + " @ " + stack.source);
|
||||
stack = stack.parent;
|
||||
}
|
||||
print();
|
||||
}
|
||||
|
||||
// When the youngest frame is not self-hosted, it doesn't matter whether or not
|
||||
// we specify that we should ignore self hosted frames when capturing the first
|
||||
// frame with the given principals.
|
||||
//
|
||||
// Stack: iife1 (g2) <- capture (g1)
|
||||
|
||||
(function iife1() {
|
||||
const captureTrueStack = capture(true);
|
||||
dumpStack("captureTrueStack", captureTrueStack);
|
||||
assertEq(getOldestFrame(captureTrueStack).functionDisplayName, "iife1");
|
||||
assertEq(getOldestFrame(captureTrueStack).source, "script2.js");
|
||||
|
||||
const captureFalseStack = capture(false);
|
||||
dumpStack("captureFalseStack", captureFalseStack);
|
||||
assertEq(getOldestFrame(captureFalseStack).functionDisplayName, "iife1");
|
||||
assertEq(getOldestFrame(captureFalseStack).source, "script2.js");
|
||||
}());
|
||||
|
||||
// When the youngest frame is a self hosted frame, we get two different
|
||||
// captured stacks depending on whether or not we ignore self-hosted frames.
|
||||
//
|
||||
// Stack: iife2 (g2) <- bound function (g2) <- capture (g1)
|
||||
|
||||
(function iife2() {
|
||||
const boundTrueStack = boundTrue();
|
||||
dumpStack("boundTrueStack", boundTrueStack);
|
||||
assertEq(getOldestFrame(boundTrueStack).functionDisplayName, "iife2");
|
||||
assertEq(getOldestFrame(boundTrueStack).source, "script2.js");
|
||||
|
||||
const boundFalseStack = boundFalse();
|
||||
dumpStack("boundFalseStack", boundFalseStack);
|
||||
assertEq(getOldestFrame(boundFalseStack).functionDisplayName !== "iife2", true);
|
||||
assertEq(getOldestFrame(boundFalseStack).source, "self-hosted");
|
||||
}());
|
||||
`, {
|
||||
fileName: "script2.js"
|
||||
});
|
|
@ -6536,8 +6536,14 @@ JS::SetOutOfMemoryCallback(JSContext* cx, OutOfMemoryCallback cb, void* data)
|
|||
cx->oomCallbackData = data;
|
||||
}
|
||||
|
||||
JS::FirstSubsumedFrame::FirstSubsumedFrame(JSContext* cx,
|
||||
bool ignoreSelfHostedFrames /* = true */)
|
||||
: JS::FirstSubsumedFrame(cx, cx->compartment()->principals(), ignoreSelfHostedFrames)
|
||||
{ }
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::CaptureCurrentStack(JSContext* cx, JS::MutableHandleObject stackp, unsigned maxFrameCount)
|
||||
JS::CaptureCurrentStack(JSContext* cx, JS::MutableHandleObject stackp,
|
||||
JS::StackCapture&& capture /* = JS::StackCapture(JS::AllFrames()) */)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
|
@ -6545,7 +6551,7 @@ JS::CaptureCurrentStack(JSContext* cx, JS::MutableHandleObject stackp, unsigned
|
|||
|
||||
JSCompartment* compartment = cx->compartment();
|
||||
Rooted<SavedFrame*> frame(cx);
|
||||
if (!compartment->savedStacks().saveCurrentStack(cx, &frame, maxFrameCount))
|
||||
if (!compartment->savedStacks().saveCurrentStack(cx, &frame, mozilla::Move(capture)))
|
||||
return false;
|
||||
stackp.set(frame.get());
|
||||
return true;
|
||||
|
|
|
@ -5896,14 +5896,96 @@ typedef void
|
|||
extern JS_PUBLIC_API(void)
|
||||
SetOutOfMemoryCallback(JSContext* cx, OutOfMemoryCallback cb, void* data);
|
||||
|
||||
/**
|
||||
* Capture all frames.
|
||||
*/
|
||||
struct AllFrames { };
|
||||
|
||||
/**
|
||||
* Capture at most this many frames.
|
||||
*/
|
||||
struct MaxFrames
|
||||
{
|
||||
unsigned maxFrames;
|
||||
|
||||
explicit MaxFrames(unsigned max)
|
||||
: maxFrames(max)
|
||||
{
|
||||
MOZ_ASSERT(max > 0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Capture the first frame with the given principals. By default, do not
|
||||
* consider self-hosted frames with the given principals as satisfying the stack
|
||||
* capture.
|
||||
*/
|
||||
struct FirstSubsumedFrame
|
||||
{
|
||||
JSContext* cx;
|
||||
JSPrincipals* principals;
|
||||
bool ignoreSelfHosted;
|
||||
|
||||
/**
|
||||
* Use the cx's current compartment's principals.
|
||||
*/
|
||||
explicit FirstSubsumedFrame(JSContext* cx, bool ignoreSelfHostedFrames = true);
|
||||
|
||||
explicit FirstSubsumedFrame(JSContext* ctx, JSPrincipals* p, bool ignoreSelfHostedFrames = true)
|
||||
: cx(ctx)
|
||||
, principals(p)
|
||||
, ignoreSelfHosted(ignoreSelfHostedFrames)
|
||||
{
|
||||
JS_HoldPrincipals(principals);
|
||||
}
|
||||
|
||||
// No copying because we want to avoid holding and dropping principals
|
||||
// unnecessarily.
|
||||
FirstSubsumedFrame(const FirstSubsumedFrame&) = delete;
|
||||
FirstSubsumedFrame& operator=(const FirstSubsumedFrame&) = delete;
|
||||
|
||||
FirstSubsumedFrame(FirstSubsumedFrame&& rhs)
|
||||
: principals(rhs.principals)
|
||||
, ignoreSelfHosted(rhs.ignoreSelfHosted)
|
||||
{
|
||||
MOZ_ASSERT(this != &rhs, "self move disallowed");
|
||||
rhs.principals = nullptr;
|
||||
}
|
||||
|
||||
FirstSubsumedFrame& operator=(FirstSubsumedFrame&& rhs) {
|
||||
new (this) FirstSubsumedFrame(mozilla::Move(rhs));
|
||||
return *this;
|
||||
}
|
||||
|
||||
~FirstSubsumedFrame() {
|
||||
if (principals)
|
||||
JS_DropPrincipals(cx, principals);
|
||||
}
|
||||
};
|
||||
|
||||
using StackCapture = mozilla::Variant<AllFrames, MaxFrames, FirstSubsumedFrame>;
|
||||
|
||||
/**
|
||||
* Capture the current call stack as a chain of SavedFrame JSObjects, and set
|
||||
* |stackp| to the SavedFrame for the youngest stack frame, or nullptr if there
|
||||
* are no JS frames on the stack. If |maxFrameCount| is non-zero, capture at
|
||||
* most the youngest |maxFrameCount| frames.
|
||||
* are no JS frames on the stack.
|
||||
*
|
||||
* The |capture| parameter describes the portion of the JS stack to capture:
|
||||
*
|
||||
* * |JS::AllFrames|: Capture all frames on the stack.
|
||||
*
|
||||
* * |JS::MaxFrames|: Capture no more than |JS::MaxFrames::maxFrames| from the
|
||||
* stack.
|
||||
*
|
||||
* * |JS::FirstSubsumedFrame|: Capture the first frame whose principals are
|
||||
* subsumed by |JS::FirstSubsumedFrame::principals|. By default, do not
|
||||
* consider self-hosted frames; this can be controlled via the
|
||||
* |JS::FirstSubsumedFrame::ignoreSelfHosted| flag. Do not capture any async
|
||||
* stack.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
CaptureCurrentStack(JSContext* cx, MutableHandleObject stackp, unsigned maxFrameCount = 0);
|
||||
CaptureCurrentStack(JSContext* cx, MutableHandleObject stackp,
|
||||
StackCapture&& capture = StackCapture(AllFrames()));
|
||||
|
||||
/*
|
||||
* This is a utility function for preparing an async stack to be used
|
||||
|
|
|
@ -266,7 +266,8 @@ static const size_t MAX_REPORTED_STACK_DEPTH = 1u << 7;
|
|||
static bool
|
||||
CaptureStack(JSContext* cx, MutableHandleObject stack)
|
||||
{
|
||||
return CaptureCurrentStack(cx, stack, MAX_REPORTED_STACK_DEPTH);
|
||||
return CaptureCurrentStack(cx, stack,
|
||||
JS::StackCapture(JS::MaxFrames(MAX_REPORTED_STACK_DEPTH)));
|
||||
}
|
||||
|
||||
JSString*
|
||||
|
|
|
@ -1068,7 +1068,8 @@ SavedStacks::init()
|
|||
}
|
||||
|
||||
bool
|
||||
SavedStacks::saveCurrentStack(JSContext* cx, MutableHandleSavedFrame frame, unsigned maxFrameCount)
|
||||
SavedStacks::saveCurrentStack(JSContext* cx, MutableHandleSavedFrame frame,
|
||||
JS::StackCapture&& capture /* = JS::StackCapture(JS::AllFrames()) */)
|
||||
{
|
||||
MOZ_ASSERT(initialized());
|
||||
MOZ_RELEASE_ASSERT(cx->compartment());
|
||||
|
@ -1085,7 +1086,7 @@ SavedStacks::saveCurrentStack(JSContext* cx, MutableHandleSavedFrame frame, unsi
|
|||
|
||||
AutoSPSEntry psuedoFrame(cx->runtime(), "js::SavedStacks::saveCurrentStack");
|
||||
FrameIter iter(cx);
|
||||
return insertFrames(cx, iter, frame, maxFrameCount);
|
||||
return insertFrames(cx, iter, frame, mozilla::Move(capture));
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1137,9 +1138,49 @@ SavedStacks::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
|||
pcLocationMap.sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
// Given that we have captured a stqck frame with the given principals and
|
||||
// source, return true if the requested `StackCapture` has been satisfied and
|
||||
// stack walking can halt. Return false otherwise (and stack walking and frame
|
||||
// capturing should continue).
|
||||
static inline bool
|
||||
captureIsSatisfied(JSContext* cx, JSPrincipals* principals, const JSAtom* source,
|
||||
JS::StackCapture& capture)
|
||||
{
|
||||
class Matcher
|
||||
{
|
||||
JSContext* cx_;
|
||||
JSPrincipals* framePrincipals_;
|
||||
const JSAtom* frameSource_;
|
||||
|
||||
public:
|
||||
Matcher(JSContext* cx, JSPrincipals* principals, const JSAtom* source)
|
||||
: cx_(cx)
|
||||
, framePrincipals_(principals)
|
||||
, frameSource_(source)
|
||||
{ }
|
||||
|
||||
bool match(JS::FirstSubsumedFrame& target) {
|
||||
auto subsumes = cx_->runtime()->securityCallbacks->subsumes;
|
||||
return (!subsumes || subsumes(target.principals, framePrincipals_)) &&
|
||||
(!target.ignoreSelfHosted || frameSource_ != cx_->names().selfHosted);
|
||||
}
|
||||
|
||||
bool match(JS::MaxFrames& target) {
|
||||
return target.maxFrames == 1;
|
||||
}
|
||||
|
||||
bool match(JS::AllFrames&) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
Matcher m(cx, principals, source);
|
||||
return capture.match(m);
|
||||
}
|
||||
|
||||
bool
|
||||
SavedStacks::insertFrames(JSContext* cx, FrameIter& iter, MutableHandleSavedFrame frame,
|
||||
unsigned maxFrameCount)
|
||||
JS::StackCapture&& capture)
|
||||
{
|
||||
// In order to lookup a cached SavedFrame object, we need to have its parent
|
||||
// SavedFrame, which means we need to walk the stack from oldest frame to
|
||||
|
@ -1216,9 +1257,10 @@ SavedStacks::insertFrames(JSContext* cx, FrameIter& iter, MutableHandleSavedFram
|
|||
|
||||
// The bit set means that the next older parent (frame, pc) pair *must*
|
||||
// be in the cache.
|
||||
if (maxFrameCount == 0)
|
||||
if (capture.is<JS::AllFrames>())
|
||||
parentIsInCache = iter.hasCachedSavedFrame();
|
||||
|
||||
auto principals = iter.compartment()->principals();
|
||||
auto displayAtom = iter.isFunctionFrame() ? iter.functionDisplayAtom() : nullptr;
|
||||
if (!stackChain->emplaceBack(location.source(),
|
||||
location.line(),
|
||||
|
@ -1226,7 +1268,7 @@ SavedStacks::insertFrames(JSContext* cx, FrameIter& iter, MutableHandleSavedFram
|
|||
displayAtom,
|
||||
nullptr,
|
||||
nullptr,
|
||||
iter.compartment()->principals(),
|
||||
principals,
|
||||
LiveSavedFrameCache::getFramePtr(iter),
|
||||
iter.pc(),
|
||||
&activation))
|
||||
|
@ -1235,15 +1277,15 @@ SavedStacks::insertFrames(JSContext* cx, FrameIter& iter, MutableHandleSavedFram
|
|||
return false;
|
||||
}
|
||||
|
||||
++iter;
|
||||
|
||||
if (maxFrameCount == 1) {
|
||||
if (captureIsSatisfied(cx, principals, location.source(), capture)) {
|
||||
// The frame we just saved was the last one we were asked to save.
|
||||
// If we had an async stack, ensure we don't use any of its frames.
|
||||
asyncStack.set(nullptr);
|
||||
break;
|
||||
}
|
||||
|
||||
++iter;
|
||||
|
||||
if (parentIsInCache &&
|
||||
!iter.done() &&
|
||||
iter.hasCachedSavedFrame())
|
||||
|
@ -1256,19 +1298,21 @@ SavedStacks::insertFrames(JSContext* cx, FrameIter& iter, MutableHandleSavedFram
|
|||
break;
|
||||
}
|
||||
|
||||
// If maxFrameCount is zero there's no limit on the number of frames.
|
||||
if (maxFrameCount == 0)
|
||||
continue;
|
||||
|
||||
maxFrameCount--;
|
||||
if (capture.is<JS::MaxFrames>())
|
||||
capture.as<JS::MaxFrames>().maxFrames--;
|
||||
}
|
||||
|
||||
// Limit the depth of the async stack, if any, and ensure that the
|
||||
// SavedFrame instances we use are stored in the same compartment as the
|
||||
// rest of the synchronous stack chain.
|
||||
RootedSavedFrame parentFrame(cx, cachedFrame);
|
||||
if (asyncStack && !adoptAsyncStack(cx, asyncStack, asyncCause, &parentFrame, maxFrameCount))
|
||||
return false;
|
||||
if (asyncStack && !capture.is<JS::FirstSubsumedFrame>()) {
|
||||
unsigned maxAsyncFrames = capture.is<JS::MaxFrames>()
|
||||
? capture.as<JS::MaxFrames>().maxFrames
|
||||
: ASYNC_STACK_MAX_FRAME_COUNT;
|
||||
if (!adoptAsyncStack(cx, asyncStack, asyncCause, &parentFrame, maxAsyncFrames))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Iterate through |stackChain| in reverse order and get or create the
|
||||
// actual SavedFrame instances.
|
||||
|
@ -1279,7 +1323,7 @@ SavedStacks::insertFrames(JSContext* cx, FrameIter& iter, MutableHandleSavedFram
|
|||
if (!parentFrame)
|
||||
return false;
|
||||
|
||||
if (maxFrameCount == 0 && lookup->framePtr && parentFrame != cachedFrame) {
|
||||
if (capture.is<JS::AllFrames>() && lookup->framePtr && parentFrame != cachedFrame) {
|
||||
auto* cache = lookup->activation->getLiveSavedFrameCache(cx);
|
||||
if (!cache || !cache->insert(cx, *lookup->framePtr, lookup->pc, parentFrame))
|
||||
return false;
|
||||
|
|
|
@ -165,7 +165,7 @@ class SavedStacks {
|
|||
MOZ_MUST_USE bool init();
|
||||
bool initialized() const { return frames.initialized(); }
|
||||
MOZ_MUST_USE bool saveCurrentStack(JSContext* cx, MutableHandleSavedFrame frame,
|
||||
unsigned maxFrameCount = 0);
|
||||
JS::StackCapture&& capture = JS::StackCapture(JS::AllFrames()));
|
||||
MOZ_MUST_USE bool copyAsyncStack(JSContext* cx, HandleObject asyncStack,
|
||||
HandleString asyncCause,
|
||||
MutableHandleSavedFrame adoptedStack,
|
||||
|
@ -221,7 +221,7 @@ class SavedStacks {
|
|||
|
||||
MOZ_MUST_USE bool insertFrames(JSContext* cx, FrameIter& iter,
|
||||
MutableHandleSavedFrame frame,
|
||||
unsigned maxFrameCount = 0);
|
||||
JS::StackCapture&& capture);
|
||||
MOZ_MUST_USE bool adoptAsyncStack(JSContext* cx, HandleSavedFrame asyncStack,
|
||||
HandleString asyncCause,
|
||||
MutableHandleSavedFrame adoptedStack,
|
||||
|
|
Загрузка…
Ссылка в новой задаче