diff options
-rw-r--r-- | gi/closure.cpp | 24 | ||||
-rw-r--r-- | gi/closure.h | 11 | ||||
-rw-r--r-- | gi/function.cpp | 33 | ||||
-rw-r--r-- | gi/value.cpp | 23 |
4 files changed, 44 insertions, 47 deletions
diff --git a/gi/closure.cpp b/gi/closure.cpp index bd98390b..ec34b4b9 100644 --- a/gi/closure.cpp +++ b/gi/closure.cpp @@ -163,13 +163,9 @@ static void closure_finalize(void*, GClosure* closure) { self->~Closure(); } -bool -gjs_closure_invoke(GClosure *closure, - JS::HandleObject this_obj, - const JS::HandleValueArray& args, - JS::MutableHandleValue retval, - bool return_exception) -{ +bool gjs_closure_invoke(GClosure* closure, JS::HandleObject this_obj, + const JS::HandleValueArray& args, + JS::MutableHandleValue retval) { Closure *c; JSContext *context; @@ -196,20 +192,6 @@ gjs_closure_invoke(GClosure *closure, "Closure invocation failed (exception should have been thrown) " "closure %p function %p", closure, c->func.debug_addr()); - /* If an exception has been thrown, log it, unless the caller - * explicitly wants to handle it manually (for example to turn it - * into a GError), in which case it replaces the return value - * (which is not valid anyway) */ - if (JS_IsExceptionPending(context)) { - if (return_exception) - JS_GetPendingException(context, retval); - else - gjs_log_exception_uncaught(context); - } else { - retval.setUndefined(); - gjs_debug_closure("Closure invocation failed but no exception was set?" - "closure %p", closure); - } return false; } diff --git a/gi/closure.h b/gi/closure.h index e6b2e091..87299f73 100644 --- a/gi/closure.h +++ b/gi/closure.h @@ -11,6 +11,8 @@ #include <js/TypeDecls.h> +#include "gjs/macros.h" + class JSTracer; namespace JS { class HandleValueArray; @@ -20,11 +22,10 @@ class HandleValueArray; const char* description, bool root_function); -[[nodiscard]] bool gjs_closure_invoke(GClosure* closure, - JS::HandleObject this_obj, - const JS::HandleValueArray& args, - JS::MutableHandleValue retval, - bool return_exception); +GJS_JSAPI_RETURN_CONVENTION +bool gjs_closure_invoke(GClosure* closure, JS::HandleObject this_obj, + const JS::HandleValueArray& args, + JS::MutableHandleValue retval); [[nodiscard]] JSContext* gjs_closure_get_context(GClosure* closure); [[nodiscard]] bool gjs_closure_is_valid(GClosure* closure); diff --git a/gi/function.cpp b/gi/function.cpp index 687eee96..5810adea 100644 --- a/gi/function.cpp +++ b/gi/function.cpp @@ -409,20 +409,23 @@ void GjsCallbackTrampoline::callback_closure(GIArgument** args, void* result) { set_return_ffi_arg_from_giargument(&ret_type, result, &argument); } - // If the callback has a GError** argument and invoking the closure - // returned an error, try to make a GError from it - if (error_argument && rval.isObject()) { - JS::RootedObject exc_object(context, &rval.toObject()); - GError* local_error = - gjs_gerror_make_from_error(context, exc_object); - - // the GError ** pointer is the last argument, and is not - // included in the n_args - auto* gerror = gjs_arg_get<GError**>(error_argument); - g_propagate_error(gerror, local_error); - JS_ClearPendingException(context); // don't log - } else if (!rval.isUndefined()) { - JS_SetPendingException(context, rval); + // If an exception has been thrown, log it. Unless the callback has a + // GError** argument, then try to make a GError from it if it's an + // object (and otherwise fall back to logging) + if (error_argument) { + JS::RootedValue v_exception(context); + JS_GetPendingException(context, &v_exception); + if (v_exception.isObject()) { + JS_ClearPendingException(context); // don't log + JS::RootedObject exc_object(context, &v_exception.toObject()); + GError* local_error = + gjs_gerror_make_from_error(context, exc_object); + + // the GError ** pointer is the last argument, and is not + // included in the n_args + auto* gerror = gjs_arg_get<GError**>(error_argument); + g_propagate_error(gerror, local_error); + } } gjs_log_exception_uncaught(context); } @@ -518,7 +521,7 @@ bool GjsCallbackTrampoline::callback_closure_inner( } } - if (!gjs_closure_invoke(m_js_function, this_object, jsargs, rval, true)) + if (!gjs_closure_invoke(m_js_function, this_object, jsargs, rval)) return false; if (n_outargs == 0 && ret_type_is_void) { diff --git a/gi/value.cpp b/gi/value.cpp index c17c6933..2b82d64d 100644 --- a/gi/value.cpp +++ b/gi/value.cpp @@ -7,6 +7,8 @@ #include <stdint.h> #include <stdlib.h> // for exit +#include <string> + #include <girepository.h> #include <glib-object.h> #include <glib.h> @@ -259,12 +261,21 @@ closure_marshal(GClosure *closure, JS::RootedValue rval(context); - if (!gjs_closure_invoke(closure, nullptr, argv, &rval, false)) { - // "Uncatchable" exception thrown, we have to exit. This - // matches the closure exit handling in function.cpp - uint8_t code; - if (gjs->should_exit(&code)) - exit(code); + if (!gjs_closure_invoke(closure, nullptr, argv, &rval)) { + if (JS_IsExceptionPending(context)) { + gjs_log_exception_uncaught(context); + } else { + // "Uncatchable" exception thrown, we have to exit. This + // matches the closure exit handling in function.cpp + uint8_t code; + if (gjs->should_exit(&code)) + exit(code); + + // Some other uncatchable exception, e.g. out of memory + JSFunction* fn = gjs_closure_get_callable(closure); + g_error("Function %s terminated with uncatchable exception", + gjs_debug_string(JS_GetFunctionDisplayId(fn)).c_str()); + } } // null return_value means the closure wasn't expected to return a value. |