Bug 839088 part 2. Add way to indicate to a CallSetup that it should propagate any exceptions thrown during the call out to the ErrorResult for the call. r=peterv

This commit is contained in:
Boris Zbarsky 2013-02-19 11:54:40 -05:00
parent fb92453c3a
commit c1a79f1556
3 changed files with 48 additions and 6 deletions

View File

@ -33,8 +33,12 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CallbackObject)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCallback)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
CallbackObject::CallSetup::CallSetup(JSObject* const aCallback)
CallbackObject::CallSetup::CallSetup(JSObject* const aCallback,
ErrorResult& aRv,
ExceptionHandling aExceptionHandling)
: mCx(nullptr)
, mErrorResult(aRv)
, mExceptionHandling(aExceptionHandling)
{
xpc_UnmarkGrayObject(aCallback);
@ -123,14 +127,40 @@ CallbackObject::CallSetup::CallSetup(JSObject* const aCallback)
// And now we're ready to go.
mCx = cx;
// Make sure the JS engine doesn't report exceptions we want to re-throw
if (mExceptionHandling == eRethrowExceptions) {
mSavedJSContextOptions = JS_GetOptions(cx);
JS_SetOptions(cx, mSavedJSContextOptions | JSOPTION_DONT_REPORT_UNCAUGHT);
}
}
CallbackObject::CallSetup::~CallSetup()
{
// First things first: if we have a JSContext, report any pending
// errors on it.
// errors on it, unless we were told to re-throw them.
if (mCx) {
nsJSUtils::ReportPendingException(mCx);
bool dealtWithPendingException = false;
if (mExceptionHandling == eRethrowExceptions) {
// Restore the old context options
JS_SetOptions(mCx, mSavedJSContextOptions);
mErrorResult.MightThrowJSException();
if (JS_IsExceptionPending(mCx)) {
JS::Value exn;
if (JS_GetPendingException(mCx, &exn)) {
mErrorResult.ThrowJSException(mCx, exn);
JS_ClearPendingException(mCx);
dealtWithPendingException = true;
}
}
}
if (!dealtWithPendingException) {
// Either we're supposed to report our exceptions, or we're supposed to
// re-throw them but we failed to JS_GetPendingException. Either way,
// just report the pending exception, if any.
nsJSUtils::ReportPendingException(mCx);
}
}
// If we have an mCtx, we need to call ScriptEvaluated() on it. But we have

View File

@ -81,6 +81,11 @@ public:
return mCallback;
}
enum ExceptionHandling {
eReportExceptions,
eRethrowExceptions
};
protected:
explicit CallbackObject(CallbackObject* aCallbackFunction)
: mCallback(aCallbackFunction->mCallback)
@ -112,7 +117,8 @@ protected:
* non-null.
*/
public:
CallSetup(JSObject* const aCallable);
CallSetup(JSObject* const aCallable, ErrorResult& aRv,
ExceptionHandling aExceptionHandling);
~CallSetup();
JSContext* GetContext() const
@ -149,6 +155,12 @@ protected:
// JSContext. Though in practice we'll often manually order those two
// things.
Maybe<JSAutoCompartment> mAc;
// An ErrorResult to possibly re-throw exceptions on and whether
// we should re-throw them.
ErrorResult& mErrorResult;
const ExceptionHandling mExceptionHandling;
uint32_t mSavedJSContextOptions;
};
};

View File

@ -7707,7 +7707,7 @@ class CGCallback(CGClass):
argsWithoutThis = list(args)
args.insert(0, Argument("const T&", "thisObj"))
setupCall = ("CallSetup s(mCallback);\n"
setupCall = ("CallSetup s(mCallback, aRv, eReportExceptions);\n"
"if (!s.GetContext()) {\n"
" aRv.Throw(NS_ERROR_UNEXPECTED);\n"
" return${errorReturn};\n"
@ -7970,7 +7970,7 @@ class CallbackMember(CGNativeMember):
# It's been done for us already
return ""
return string.Template(
"CallSetup s(mCallback);\n"
"CallSetup s(mCallback, aRv, eReportExceptions);\n"
"JSContext* cx = s.GetContext();\n"
"if (!cx) {\n"
" aRv.Throw(NS_ERROR_UNEXPECTED);\n"