Bug 1140435 - Part 2 - Allow JS code to provide an async stack when calling a function. r=bz

This commit is contained in:
Paolo Amadini 2015-03-07 13:30:34 +00:00
parent 6652a00032
commit f638425f9d
6 changed files with 99 additions and 2 deletions

View File

@ -311,6 +311,7 @@ public:
NS_IMETHOD GetAsyncCaller(nsIStackFrame** aAsyncCaller) MOZ_OVERRIDE;
NS_IMETHOD GetCaller(nsIStackFrame** aCaller) MOZ_OVERRIDE;
NS_IMETHOD GetFormattedStack(nsAString& aStack) MOZ_OVERRIDE;
NS_IMETHOD GetNativeSavedFrame(JS::MutableHandle<JS::Value> aSavedFrame) MOZ_OVERRIDE;
protected:
virtual bool IsJSFrame() const MOZ_OVERRIDE {
@ -750,6 +751,19 @@ NS_IMETHODIMP StackFrame::GetFormattedStack(nsAString& aStack)
return NS_OK;
}
/* readonly attribute jsval nativeSavedFrame; */
NS_IMETHODIMP JSStackFrame::GetNativeSavedFrame(JS::MutableHandle<JS::Value> aSavedFrame)
{
aSavedFrame.setObjectOrNull(mStack);
return NS_OK;
}
NS_IMETHODIMP StackFrame::GetNativeSavedFrame(JS::MutableHandle<JS::Value> aSavedFrame)
{
aSavedFrame.setNull();
return NS_OK;
}
/* AUTF8String toString (); */
NS_IMETHODIMP StackFrame::ToString(nsACString& _retval)
{

View File

@ -122,7 +122,7 @@ interface ScheduledGCCallback : nsISupports
/**
* interface of Components.utils
*/
[scriptable, uuid(2617a800-63c1-11e4-9803-0800200c9a66)]
[scriptable, uuid(0354f8b4-08c6-4074-a466-2b6524b64ca3)]
interface nsIXPCComponents_Utils : nsISupports
{
@ -361,6 +361,20 @@ interface nsIXPCComponents_Utils : nsISupports
[implicit_jscontext]
jsval getJSTestingFunctions();
/*
* To be called from JS only.
*
* Call 'function', using the provided stack as the async stack responsible
* for the call, and propagate its return value or the exception it throws.
* The function is called with no arguments, and 'this' is 'undefined'.
*
* The code in the function will see the given stack frame as the
* asyncCaller of its own stack frame, instead of the current caller.
*/
[implicit_jscontext]
jsval callFunctionWithAsyncStack(in jsval function, in nsIStackFrame stack,
in AString asyncCause);
/*
* To be called from JS only.
*

View File

@ -2901,6 +2901,47 @@ nsXPCComponents_Utils::GetJSTestingFunctions(JSContext *cx,
return NS_OK;
}
/* jsval callFunctionWithStack(in jsval function, in nsIStackFrame stack,
in AString asyncCause); */
NS_IMETHODIMP
nsXPCComponents_Utils::CallFunctionWithAsyncStack(HandleValue function,
nsIStackFrame *stack,
const nsAString &asyncCause,
JSContext *cx,
MutableHandleValue retval)
{
nsresult rv;
if (!stack || asyncCause.IsEmpty()) {
return NS_ERROR_INVALID_ARG;
}
JS::Rooted<JS::Value> asyncStack(cx);
rv = stack->GetNativeSavedFrame(&asyncStack);
if (NS_FAILED(rv))
return rv;
if (!asyncStack.isObject()) {
JS_ReportError(cx, "Must use a native JavaScript stack frame");
return NS_ERROR_INVALID_ARG;
}
JS::Rooted<JSObject*> asyncStackObj(cx, &asyncStack.toObject());
JS::Rooted<JSString*> asyncCauseString(cx, JS_NewUCStringCopyN(cx, asyncCause.BeginReading(),
asyncCause.Length()));
if (!asyncCauseString)
return NS_ERROR_OUT_OF_MEMORY;
JS::AutoSetAsyncStackForNewCalls sas(cx, asyncStackObj, asyncCauseString);
if (!JS_CallFunctionValue(cx, JS::NullPtr(), function,
JS::HandleValueArray::empty(), retval))
{
return NS_ERROR_XPC_JAVASCRIPT_ERROR;
}
return NS_OK;
}
/* void getGlobalForObject(); */
NS_IMETHODIMP
nsXPCComponents_Utils::GetGlobalForObject(HandleValue object,

View File

@ -0,0 +1,23 @@
function run_test() {
function getAsyncStack() {
return Components.stack;
}
// asyncCause may contain non-ASCII characters.
let testAsyncCause = "Tes" + String.fromCharCode(355) + "String";
Components.utils.callFunctionWithAsyncStack(function asyncCallback() {
let stack = Components.stack;
do_check_eq(stack.name, "asyncCallback");
do_check_eq(stack.caller.name, null);
do_check_eq(stack.asyncCause, null);
do_check_eq(stack.asyncCaller.name, "getAsyncStack");
do_check_eq(stack.asyncCaller.asyncCause, testAsyncCause);
do_check_eq(stack.asyncCaller.asyncCaller, null);
do_check_eq(stack.asyncCaller.caller.name, "run_test");
do_check_eq(stack.asyncCaller.caller.asyncCause, null);
}, getAsyncStack(), testAsyncCause);
}

View File

@ -55,6 +55,7 @@ support-files =
[test_bug1081990.js]
[test_bug1110546.js]
[test_bug_442086.js]
[test_callFunctionWithAsyncStack.js]
[test_file.js]
[test_blob.js]
[test_blob2.js]

View File

@ -10,7 +10,7 @@
#include "nsISupports.idl"
[scriptable, uuid(9787bc41-1ec9-4fe0-8b31-ffee5db6a893)]
[scriptable, uuid(28bfb2a2-5ea6-4738-918b-049dc4d51f0b)]
interface nsIStackFrame : nsISupports
{
// see nsIProgrammingLanguage for list of language consts
@ -31,6 +31,10 @@ interface nsIStackFrame : nsISupports
// Only works on JS-language stack frames.
readonly attribute AString formattedStack;
// Returns the underlying SavedFrame object for native JavaScript stacks,
// or null if this is not a native JavaScript stack frame.
readonly attribute jsval nativeSavedFrame;
AUTF8String toString();
};