[gjs] add JS_BeginRequest/JS_EndRequest calls throughout the codebase.



commit ccc6e7ce6cf9d2f42b2667d1998598f376c86f76
Author: Havoc Pennington <hp pobox com>
Date:   Sat May 1 00:33:01 2010 -0400

    add JS_BeginRequest/JS_EndRequest calls throughout the codebase.
    
    This is one step toward thread safety. Remaining work includes at least:
    * put locks on our own global state
    * JS_SuspendRequest() when blocking in native code
    * JS_SetContextThread() on load and call contexts

 gi/closure.c            |   12 +++++
 gi/function.c           |    6 ++
 gi/keep-alive.c         |   34 ++++++++++++-
 gi/ns.c                 |    6 ++
 gi/repo.c               |   30 +++++++++--
 gi/value.c              |    3 +
 gjs/context.c           |   34 ++++++++++++-
 gjs/importer.c          |   23 +++++++--
 gjs/jsapi-util-array.c  |   13 +++++
 gjs/jsapi-util-error.c  |    9 +++
 gjs/jsapi-util-string.c |   39 +++++++++++++-
 gjs/jsapi-util.c        |  125 ++++++++++++++++++++++++++++++++++++++++++----
 modules/dbus-exports.c  |   14 ++++--
 modules/dbus.c          |   21 ++++++++
 modules/mainloop.c      |    4 +-
 15 files changed, 340 insertions(+), 33 deletions(-)
---
diff --git a/gi/closure.c b/gi/closure.c
index 722279a..7cf084c 100644
--- a/gi/closure.c
+++ b/gi/closure.c
@@ -255,6 +255,8 @@ gjs_closure_invoke(GClosure *closure,
         return;
     }
 
+    JS_BeginRequest(context);
+
     if (JS_IsExceptionPending(context)) {
         gjs_debug_closure("Exception was pending before invoking callback??? "
                           "Not expected");
@@ -279,6 +281,8 @@ gjs_closure_invoke(GClosure *closure,
     if (gjs_log_exception(context, NULL)) {
         gjs_debug_closure("Closure invocation succeeded but an exception was set");
     }
+
+    JS_EndRequest(context);
 }
 
 gboolean
@@ -294,6 +298,8 @@ gjs_closure_invoke_simple(JSContext   *context,
     jsval *argv;
     int i;
 
+    JS_BeginRequest(context);
+
     va_start(ap, format);
     argv = JS_PushArgumentsVA(context, &stack_space, format, ap);
     va_end(ap);
@@ -313,6 +319,8 @@ gjs_closure_invoke_simple(JSContext   *context,
 
     JS_PopArguments(context, stack_space);
 
+    JS_EndRequest(context);
+
     return TRUE;
 }
 
@@ -352,6 +360,8 @@ gjs_closure_new(JSContext  *context,
      * is invoked (as long as the runtime lives)
      */
     c->context = gjs_runtime_get_load_context(c->runtime);
+    JS_BeginRequest(c->context);
+
     c->obj = callable;
     c->unref_on_global_object_finalized = FALSE;
 
@@ -371,6 +381,8 @@ gjs_closure_new(JSContext  *context,
     gjs_debug_closure("Create closure %p which calls object %p '%s'",
                       c, c->obj, description);
 
+    JS_EndRequest(c->context);
+
     return &c->base;
 }
 
diff --git a/gi/function.c b/gi/function.c
index 0bf5744..98343f5 100644
--- a/gi/function.c
+++ b/gi/function.c
@@ -1033,10 +1033,13 @@ gjs_define_function(JSContext      *context,
     JSContext *load_context;
 
     load_context = gjs_runtime_get_load_context(JS_GetRuntime(context));
+    JS_BeginRequest(load_context);
 
     function = function_new(load_context, info);
     if (function == NULL) {
         gjs_move_exception(load_context, context);
+
+        JS_EndRequest(load_context);
         return NULL;
     }
 
@@ -1046,9 +1049,12 @@ gjs_define_function(JSContext      *context,
                            NULL, NULL,
                            GJS_MODULE_PROP_FLAGS)) {
         gjs_debug(GJS_DEBUG_GFUNCTION, "Failed to define function");
+
+        JS_EndRequest(load_context);
         return NULL;
     }
 
+    JS_EndRequest(load_context);
     return function;
 }
 
diff --git a/gi/keep-alive.c b/gi/keep-alive.c
index 160a9ca..8e2c4ab 100644
--- a/gi/keep-alive.c
+++ b/gi/keep-alive.c
@@ -217,6 +217,8 @@ gjs_keep_alive_new(JSContext *context)
 
     g_assert(context != NULL);
 
+    JS_BeginRequest(context);
+
     /* put constructor in the global namespace */
     global = JS_GetGlobalObject(context);
 
@@ -277,6 +279,8 @@ gjs_keep_alive_new(JSContext *context)
         gjs_fatal("Failed to create keep_alive object");
     }
 
+    JS_EndRequest(context);
+
     return keep_alive;
 }
 
@@ -292,7 +296,9 @@ gjs_keep_alive_add_child(JSContext         *context,
 
     g_assert(keep_alive != NULL);
 
+    JS_BeginRequest(context);
     priv = priv_from_js(context, keep_alive);
+    JS_EndRequest(context);
 
     g_assert(priv != NULL);
 
@@ -323,7 +329,9 @@ gjs_keep_alive_remove_child(JSContext         *context,
     KeepAlive *priv;
     Child child;
 
+    JS_BeginRequest(context);
     priv = priv_from_js(context, keep_alive);
+    JS_EndRequest(context);
 
     g_assert(priv != NULL);
 
@@ -345,15 +353,22 @@ gjs_keep_alive_get_global(JSContext *context)
 {
     jsval value;
     JSObject *global;
+    JSObject *result;
+
+    JS_BeginRequest(context);
 
     global = JS_GetGlobalObject(context);
 
     gjs_object_get_property(context, global, GLOBAL_KEEP_ALIVE_NAME, &value);
 
     if (JSVAL_IS_OBJECT(value))
-        return JSVAL_TO_OBJECT(value);
+        result = JSVAL_TO_OBJECT(value);
+    else
+        result = NULL;
 
-    return NULL;
+    JS_EndRequest(context);
+
+    return result;
 }
 
 static JSObject*
@@ -362,6 +377,8 @@ gjs_keep_alive_create_in_global(JSContext *context)
     JSObject *keep_alive;
     JSObject *global;
 
+    JS_BeginRequest(context);
+
     global = JS_GetGlobalObject(context);
 
     keep_alive = gjs_keep_alive_new(context);
@@ -376,6 +393,7 @@ gjs_keep_alive_create_in_global(JSContext *context)
                            JSPROP_READONLY | JSPROP_PERMANENT))
         gjs_fatal("no memory to define keep_alive property");
 
+    JS_EndRequest(context);
     return keep_alive;
 }
 
@@ -387,6 +405,8 @@ gjs_keep_alive_add_global_child(JSContext         *context,
 {
     JSObject *keep_alive;
 
+    JS_BeginRequest(context);
+
     keep_alive = gjs_keep_alive_get_global(context);
 
     if (!keep_alive)
@@ -398,6 +418,8 @@ gjs_keep_alive_add_global_child(JSContext         *context,
     gjs_keep_alive_add_child(context,
                              keep_alive,
                              notify, child, data);
+
+    JS_EndRequest(context);
 }
 
 void
@@ -408,6 +430,8 @@ gjs_keep_alive_remove_global_child(JSContext         *context,
 {
     JSObject *keep_alive;
 
+    JS_BeginRequest(context);
+
     keep_alive = gjs_keep_alive_get_global(context);
 
     if (!keep_alive)
@@ -417,6 +441,8 @@ gjs_keep_alive_remove_global_child(JSContext         *context,
     gjs_keep_alive_remove_child(context,
                                 gjs_keep_alive_get_global(context),
                                 notify, child, data);
+
+    JS_EndRequest(context);
 }
 
 JSObject*
@@ -429,6 +455,8 @@ gjs_keep_alive_get_for_load_context(JSRuntime *runtime)
 
     g_assert(context != NULL);
 
+    JS_BeginRequest(context);
+
     keep_alive = gjs_keep_alive_get_global(context);
 
     if (!keep_alive)
@@ -437,5 +465,7 @@ gjs_keep_alive_get_for_load_context(JSRuntime *runtime)
     if (!keep_alive)
         gjs_fatal("could not create keep_alive on global object, no memory?");
 
+    JS_EndRequest(context);
+
     return keep_alive;
 }
diff --git a/gi/ns.c b/gi/ns.c
index 7ab93f8..85652dd 100644
--- a/gi/ns.c
+++ b/gi/ns.c
@@ -89,6 +89,7 @@ ns_new_resolve(JSContext *context,
         return JS_TRUE; /* we are the prototype, or have the wrong class */
 
     load_context = gjs_runtime_get_load_context(JS_GetRuntime(context));
+    JS_BeginRequest(load_context);
 
     repo = g_irepository_get_default();
 
@@ -101,15 +102,18 @@ ns_new_resolve(JSContext *context,
                                    obj,
                                    NULL);
             if (gjs_move_exception(load_context, context)) {
+                JS_EndRequest(load_context);
                 return JS_FALSE;
             } else {
                 *objp = obj; /* we defined the property in this object */
+                JS_EndRequest(load_context);
                 return JS_TRUE;
             }
         } else {
             gjs_throw(context,
                       "No symbol '%s' in namespace '%s'",
                       name, priv->namespace);
+            JS_EndRequest(load_context);
             return JS_FALSE;
         }
     }
@@ -123,6 +127,7 @@ ns_new_resolve(JSContext *context,
     if (gjs_define_info(load_context, obj, info)) {
         g_base_info_unref(info);
         *objp = obj; /* we defined the property in this object */
+        JS_EndRequest(load_context);
         return JS_TRUE;
     } else {
         gjs_debug(GJS_DEBUG_GNAMESPACE,
@@ -137,6 +142,7 @@ ns_new_resolve(JSContext *context,
                          "Defining info failed but no exception set");
         }
 
+        JS_EndRequest(load_context);
         return JS_FALSE;
     }
 }
diff --git a/gi/repo.c b/gi/repo.c
index 4f073ba..cff1b24 100644
--- a/gi/repo.c
+++ b/gi/repo.c
@@ -64,11 +64,16 @@ resolve_namespace_object(JSContext  *context,
     JSObject *versions;
     jsval version_val;
     const char *version;
+    JSObject *result;
 
     load_context = gjs_runtime_get_load_context(JS_GetRuntime(context));
+    JS_BeginRequest(load_context);
+
     if (!gjs_object_require_property(load_context, repo_obj, "GI repository object", "versions", &versions_val) ||
         !JSVAL_IS_OBJECT(versions_val)) {
         gjs_throw(context, "No 'versions' property in GI repository object");
+
+        JS_EndRequest(load_context);
         return NULL;
     }
 
@@ -89,6 +94,7 @@ resolve_namespace_object(JSContext  *context,
                   "Requiring %s, version %s: %s",
                   ns_name, version?version:"none", error->message);
         g_error_free(error);
+        JS_EndRequest(load_context);
         return JS_FALSE;
     }
 
@@ -96,7 +102,9 @@ resolve_namespace_object(JSContext  *context,
      * with the given namespace name, pointing to that namespace
      * in the repo.
      */
-    return gjs_define_ns(context, repo_obj, ns_name, repo);
+    result = gjs_define_ns(context, repo_obj, ns_name, repo);
+    JS_EndRequest(load_context);
+    return result;
 }
 
 /*
@@ -140,11 +148,14 @@ repo_new_resolve(JSContext *context,
         return JS_TRUE; /* we are the prototype, or have the wrong class */
 
     load_context = gjs_runtime_get_load_context(JS_GetRuntime(context));
+    JS_BeginRequest(load_context);
     resolve_namespace_object(load_context, obj, name);
     if (gjs_move_exception(load_context, context)) {
+        JS_EndRequest(load_context);
         return JS_FALSE;
     } else {
         *objp = obj; /* store the object we defined the prop in */
+        JS_EndRequest(load_context);
         return JS_TRUE;
     }
 }
@@ -507,6 +518,7 @@ gjs_lookup_namespace_object_by_name(JSContext      *context,
      */
 
     load_context = gjs_runtime_get_load_context(JS_GetRuntime(context));
+    JS_BeginRequest(load_context);
     global = JS_GetGlobalObject(load_context);
 
     importer = JSVAL_VOID;
@@ -514,7 +526,7 @@ gjs_lookup_namespace_object_by_name(JSContext      *context,
         !JSVAL_IS_OBJECT(importer)) {
         gjs_log_exception(load_context, NULL);
         gjs_throw(context, "No imports property in global object");
-        return NULL;
+        goto fail;
     }
 
     girepository = JSVAL_VOID;
@@ -523,20 +535,26 @@ gjs_lookup_namespace_object_by_name(JSContext      *context,
         !JSVAL_IS_OBJECT(girepository)) {
         gjs_log_exception(load_context, NULL);
         gjs_throw(context, "No gi property in importer");
-        return NULL;
+        goto fail;
     }
 
     repo_obj = JSVAL_TO_OBJECT(girepository);
 
-    if (!gjs_object_require_property(context, repo_obj, "GI repository object", ns, &ns_obj))
-        return NULL;
+    if (!gjs_object_require_property(context, repo_obj, "GI repository object", ns, &ns_obj)) {
+        goto fail;
+    }
 
     if (!JSVAL_IS_OBJECT(ns_obj)) {
         gjs_throw(context, "Namespace '%s' is not an object?", ns);
-        return NULL;
+        goto fail;
     }
 
+    JS_EndRequest(load_context);
     return JSVAL_TO_OBJECT(ns_obj);
+
+ fail:
+    JS_EndRequest(load_context);
+    return NULL;
 }
 
 const char*
diff --git a/gi/value.c b/gi/value.c
index ab80ac9..49df3dc 100644
--- a/gi/value.c
+++ b/gi/value.c
@@ -66,6 +66,8 @@ closure_marshal(GClosure        *closure,
         return;
     }
 
+    JS_BeginRequest(context);
+
     argc = n_param_values;
     argv = g_newa(jsval, n_param_values);
     rval = JSVAL_VOID;
@@ -133,6 +135,7 @@ closure_marshal(GClosure        *closure,
  cleanup:
     gjs_unroot_value_locations(context, argv, argc);
     JS_RemoveRoot(context, &rval);
+    JS_EndRequest(context);
 }
 
 GClosure*
diff --git a/gjs/context.c b/gjs/context.c
index 035c8d3..743bb1a 100644
--- a/gjs/context.c
+++ b/gjs/context.c
@@ -107,6 +107,8 @@ gjs_log(JSContext *context,
         return JS_FALSE;
     }
 
+    JS_BeginRequest(context);
+
     /* JS_ValueToString might throw, in which we will only
      *log that the value could be converted to string */
     exc_state = JS_SaveExceptionState(context);
@@ -117,15 +119,19 @@ gjs_log(JSContext *context,
 
     if (jstr == NULL) {
         gjs_debug(GJS_DEBUG_LOG, "<cannot convert value to string>");
+        JS_EndRequest(context);
         return JS_TRUE;
     }
 
-    if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(jstr), &s))
+    if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(jstr), &s)) {
+        JS_EndRequest(context);
         return JS_FALSE;
+    }
 
     gjs_debug(GJS_DEBUG_LOG, "%s", s);
     g_free(s);
 
+    JS_EndRequest(context);
     return JS_TRUE;
 }
 
@@ -146,6 +152,8 @@ gjs_log_error(JSContext *context,
         return JS_FALSE;
     }
 
+    JS_BeginRequest(context);
+
     exc = argv[0];
 
     /* JS_ValueToString might throw, in which we will only
@@ -159,16 +167,20 @@ gjs_log_error(JSContext *context,
     if (jstr == NULL) {
         gjs_debug(GJS_DEBUG_ERROR, "<cannot convert value to string>");
         gjs_log_exception_props(context, exc);
+        JS_EndRequest(context);
         return JS_TRUE;
     }
 
-    if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(jstr), &s))
+    if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(jstr), &s)) {
+        JS_EndRequest(context);
         return JS_FALSE;
+    }
 
     gjs_debug(GJS_DEBUG_ERROR, "%s", s);
     gjs_log_exception_props(context, exc);
     g_free(s);
 
+    JS_EndRequest(context);
     return JS_TRUE;
 }
 
@@ -182,6 +194,8 @@ gjs_print_parse_args(JSContext *context,
     gchar *s;
     guint n;
 
+    JS_BeginRequest(context);
+
     str = g_string_new("");
     JS_EnterLocalRootScope(context);
     for (n = 0; n < argc; ++n) {
@@ -201,6 +215,7 @@ gjs_print_parse_args(JSContext *context,
         if (jstr != NULL) {
             if (!gjs_string_to_utf8(context, STRING_TO_JSVAL(jstr), &s)) {
                 JS_LeaveLocalRootScope(context);
+                JS_EndRequest(context);
                 g_string_free(str, TRUE);
                 return JS_FALSE;
             }
@@ -211,6 +226,7 @@ gjs_print_parse_args(JSContext *context,
                 g_string_append_c(str, ' ');
         } else {
             JS_LeaveLocalRootScope(context);
+            JS_EndRequest(context);
             *buffer = g_string_free(str, TRUE);
             if (!*buffer)
                 *buffer = g_strdup("<invalid string>");
@@ -221,6 +237,7 @@ gjs_print_parse_args(JSContext *context,
     JS_LeaveLocalRootScope(context);
     *buffer = g_string_free(str, FALSE);
 
+    JS_EndRequest(context);
     return JS_TRUE;
 }
 
@@ -330,7 +347,9 @@ gjs_context_dispose(GObject *object)
     }
 
     if (js_context->global != NULL) {
+        JS_BeginRequest(js_context->context);
         JS_RemoveRoot(js_context->context, &js_context->global);
+        JS_EndRequest(js_context->context);
         js_context->global = NULL;
     }
 
@@ -537,6 +556,8 @@ gjs_context_constructor (GType                  type,
     if (js_context->context == NULL)
         gjs_fatal("Failed to create javascript context");
 
+    JS_BeginRequest(js_context->context);
+
     /* same as firefox, see discussion at
      * https://bugzilla.mozilla.org/show_bug.cgi?id=420869 */
     JS_SetScriptStackQuota(js_context->context, 100*1024*1024);
@@ -652,6 +673,8 @@ gjs_context_constructor (GType                  type,
         js_context->profiler = gjs_profiler_new(js_context->runtime);
     }
 
+    JS_EndRequest(js_context->context);
+
     g_static_mutex_lock (&contexts_lock);
     all_contexts = g_list_prepend(all_contexts, object);
     g_static_mutex_unlock (&contexts_lock);
@@ -805,6 +828,11 @@ gjs_context_eval(GjsContext *js_context,
                   "Exception was set prior to JS_EvaluateScript()");
     }
 
+    /* JS_EvaluateScript requires a request even though it sort of seems like
+     * it means we're always in a request?
+     */
+    JS_BeginRequest(js_context->context);
+
     retval = JSVAL_VOID;
     if (!JS_EvaluateScript(js_context->context,
                            js_context->global,
@@ -869,6 +897,8 @@ gjs_context_eval(GjsContext *js_context,
 
     g_object_unref(G_OBJECT(js_context));
 
+    JS_EndRequest(js_context->context);
+
     return success;
 }
 
diff --git a/gjs/importer.c b/gjs/importer.c
index 8d11e9d..c7902f6 100644
--- a/gjs/importer.c
+++ b/gjs/importer.c
@@ -925,8 +925,10 @@ importer_new_resolve(JSContext *context,
 
     /* We always import in the special load context. */
     load_context = gjs_runtime_get_load_context(JS_GetRuntime(context));
+    JS_BeginRequest(load_context);
     if (do_import(load_context, obj, priv, name)) {
         *objp = obj;
+        JS_EndRequest(load_context);
         return JS_TRUE;
     } else {
         /* Move the exception to the calling context from load context.
@@ -935,6 +937,7 @@ importer_new_resolve(JSContext *context,
             /* set an exception since none was set */
             gjs_throw(context, "No exception was set, but import failed somehow");
         }
+        JS_EndRequest(load_context);
         return JS_FALSE;
     }
 }
@@ -1182,19 +1185,25 @@ gjs_create_root_importer(JSRuntime   *runtime,
 
     context = gjs_runtime_get_load_context(runtime);
 
+    JS_BeginRequest(context);
+
     if (!gjs_object_has_property(context,
                                  JS_GetGlobalObject(context),
                                  "imports")) {
         if (gjs_define_importer(context, JS_GetGlobalObject(context),
                                 "imports",
-                                initial_search_path, add_standard_search_path) == NULL)
+                                initial_search_path, add_standard_search_path) == NULL) {
+            JS_EndRequest(context);
             return JS_FALSE;
+        }
     } else {
         gjs_debug(GJS_DEBUG_IMPORTER,
                   "Someone else already created root importer, ignoring second request");
+        JS_EndRequest(context);
         return JS_TRUE;
     }
 
+    JS_EndRequest(context);
     return JS_TRUE;
 }
 
@@ -1205,15 +1214,18 @@ gjs_define_root_importer(JSContext   *context,
 {
     JSContext *load_context;
     jsval value;
+    JSBool success;
 
+    success = JS_FALSE;
     load_context = gjs_runtime_get_load_context(JS_GetRuntime(context));
+    JS_BeginRequest(load_context);
 
     if (!gjs_object_require_property(load_context,
                                      JS_GetGlobalObject(load_context), "global object",
                                      "imports", &value) ||
         !JSVAL_IS_OBJECT(value)) {
         gjs_debug(GJS_DEBUG_IMPORTER, "Root importer did not exist, couldn't get from load context; must create it");
-        return JS_FALSE;
+        goto fail;
     }
 
     if (!JS_DefineProperty(context, in_object,
@@ -1222,8 +1234,11 @@ gjs_define_root_importer(JSContext   *context,
                            GJS_MODULE_PROP_FLAGS)) {
         gjs_debug(GJS_DEBUG_IMPORTER, "DefineProperty %s on %p failed",
                   importer_name, in_object);
-        return JS_FALSE;
+        goto fail;
     }
 
-    return JS_TRUE;
+    success = JS_TRUE;
+ fail:
+    JS_EndRequest(load_context);
+    return success;
 }
diff --git a/gjs/jsapi-util-array.c b/gjs/jsapi-util-array.c
index d3ce3f7..b4c7360 100644
--- a/gjs/jsapi-util-array.c
+++ b/gjs/jsapi-util-array.c
@@ -59,7 +59,9 @@ static void
 add_root_jsval(JSContext *context,
                jsval     *value_p)
 {
+    JS_BeginRequest(context);
     JS_AddRoot(context, value_p);
+    JS_EndRequest(context);
 }
 
 /* typesafe wrapper */
@@ -67,7 +69,9 @@ static void
 remove_root_jsval(JSContext *context,
                   jsval     *value_p)
 {
+    JS_BeginRequest(context);
     JS_RemoveRoot(context, value_p);
+    JS_EndRequest(context);
 }
 
 /**
@@ -190,9 +194,11 @@ gjs_root_value_locations(JSContext        *context,
     g_return_if_fail(locations != NULL);
     g_return_if_fail(n_locations >= 0);
 
+    JS_BeginRequest(context);
     for (i = 0; i < n_locations; i++) {
         add_root_jsval(context, ((jsval*)locations) + i);
     }
+    JS_EndRequest(context);
 }
 
 /**
@@ -215,9 +221,11 @@ gjs_unroot_value_locations(JSContext *context,
     g_return_if_fail(locations != NULL);
     g_return_if_fail(n_locations >= 0);
 
+    JS_BeginRequest(context);
     for (i = 0; i < n_locations; i++) {
         remove_root_jsval(context, ((jsval*)locations) + i);
     }
+    JS_EndRequest(context);
 }
 
 /**
@@ -302,6 +310,9 @@ gjstest_test_func_gjs_jsapi_util_array(void)
 
     runtime = JS_NewRuntime(1024*1024 /* max bytes */);
     context = JS_NewContext(runtime, 8192);
+
+    JS_BeginRequest(context);
+
     global = JS_NewObject(context, NULL, NULL, NULL);
     JS_SetGlobalObject(context, global);
     JS_InitStandardClasses(context, global);
@@ -332,6 +343,8 @@ gjstest_test_func_gjs_jsapi_util_array(void)
 
     gjs_rooted_array_free(context, array, TRUE);
 
+    JS_EndRequest(context);
+
     JS_DestroyContext(context);
     JS_DestroyRuntime(runtime);
     JS_ShutDown();
diff --git a/gjs/jsapi-util-error.c b/gjs/jsapi-util-error.c
index 2b86718..50d4449 100644
--- a/gjs/jsapi-util-error.c
+++ b/gjs/jsapi-util-error.c
@@ -55,6 +55,8 @@ gjs_throw_valist(JSContext       *context,
 
     s = g_strdup_vprintf(format, args);
 
+    JS_BeginRequest(context);
+
     if (JS_IsExceptionPending(context)) {
         /* Often it's unclear whether a given jsapi.h function
          * will throw an exception, so we will throw ourselves
@@ -138,6 +140,8 @@ gjs_throw_valist(JSContext       *context,
                        s);
     }
     g_free(s);
+
+    JS_EndRequest(context);
 }
 
 /* Throws an exception, like "throw new Error(message)"
@@ -212,6 +216,9 @@ gjstest_test_func_gjs_jsapi_util_error_throw(void)
      */
     runtime = JS_NewRuntime(1024*1024 /* max bytes */);
     context = JS_NewContext(runtime, 8192);
+
+    JS_BeginRequest(context);
+
     global = JS_NewObject(context, NULL, NULL, NULL);
     JS_SetGlobalObject(context, global);
     JS_InitStandardClasses(context, global);
@@ -266,6 +273,8 @@ gjstest_test_func_gjs_jsapi_util_error_throw(void)
 
     JS_RemoveRoot(context, &previous);
 
+    JS_EndRequest(context);
+
     JS_DestroyContext(context);
     JS_DestroyRuntime(runtime);
     JS_ShutDown();
diff --git a/gjs/jsapi-util-string.c b/gjs/jsapi-util-string.c
index fc669a0..4a57176 100644
--- a/gjs/jsapi-util-string.c
+++ b/gjs/jsapi-util-string.c
@@ -41,9 +41,12 @@ gjs_try_string_to_utf8 (JSContext  *context,
     long utf8_length;
     GError *convert_error = NULL;
 
+    JS_BeginRequest(context);
+
     if (!JSVAL_IS_STRING(string_val)) {
         g_set_error_literal(error, GJS_UTIL_ERROR, GJS_UTIL_ERROR_ARGUMENT_TYPE_MISMATCH,
                             "Object is not a string, cannot convert to UTF-8");
+        JS_EndRequest(context);
         return FALSE;
     }
 
@@ -55,6 +58,9 @@ gjs_try_string_to_utf8 (JSContext  *context,
                                   &read_items, &utf8_length,
                                   &convert_error);
 
+    /* ENDING REQUEST - no JSAPI after this point */
+    JS_EndRequest(context);
+
     if (!utf8_string) {
         g_set_error(error, GJS_UTIL_ERROR, GJS_UTIL_ERROR_ARGUMENT_INVALID,
                     "Failed to convert JS string to UTF-8: %s",
@@ -136,15 +142,20 @@ gjs_string_from_utf8(JSContext  *context,
         return JS_FALSE;
     }
 
+    JS_BeginRequest(context);
+
     s = JS_NewUCStringCopyN(context,
                             (jschar*)u16_string,
                             u16_string_length);
     g_free(u16_string);
 
-    if (!s)
+    if (!s) {
+        JS_EndRequest(context);
         return JS_FALSE;
+    }
 
     *value_p = STRING_TO_JSVAL(s);
+    JS_EndRequest(context);
     return JS_TRUE;
 }
 
@@ -301,14 +312,18 @@ gjs_string_get_binary_data(JSContext       *context,
 {
     char *js_data;
 
+    JS_BeginRequest(context);
+
     if (!JSVAL_IS_STRING(value)) {
         gjs_throw(context,
                   "Value is not a string, can't return binary data from it");
         return JS_FALSE;
     }
 
-    if (throw_if_binary_strings_broken(context))
+    if (throw_if_binary_strings_broken(context)) {
+        JS_EndRequest(context);
         return JS_FALSE;
+    }
 
     js_data = JS_GetStringBytes(JSVAL_TO_STRING(value));
     /* GetStringLength returns number of 16-bit jschar;
@@ -317,6 +332,8 @@ gjs_string_get_binary_data(JSContext       *context,
     *len_p = JS_GetStringLength(JSVAL_TO_STRING(value));
     *data_p = g_memdup(js_data, *len_p);
 
+    JS_EndRequest(context);
+
     return JS_TRUE;
 }
 
@@ -339,8 +356,12 @@ gjs_string_from_binary_data(JSContext       *context,
 {
     JSString *s;
 
-    if (throw_if_binary_strings_broken(context))
+    JS_BeginRequest(context);
+
+    if (throw_if_binary_strings_broken(context)) {
+        JS_EndRequest(context);
         return JS_FALSE;
+    }
 
     /* store each byte in a 16-bit jschar so all high bytes are 0;
      * we can't put two bytes per jschar because then we'd lose
@@ -350,10 +371,12 @@ gjs_string_from_binary_data(JSContext       *context,
     if (s == NULL) {
         /* gjs_throw() does nothing if exception already set */
         gjs_throw(context, "Failed to allocate binary string");
+        JS_EndRequest(context);
         return JS_FALSE;
     }
     *value_p = STRING_TO_JSVAL(s);
 
+    JS_EndRequest(context);
     return JS_TRUE;
 }
 
@@ -378,9 +401,12 @@ gjs_string_get_uint16_data(JSContext       *context,
 {
     jschar *js_data;
 
+    JS_BeginRequest(context);
+
     if (!JSVAL_IS_STRING(value)) {
         gjs_throw(context,
                   "Value is not a string, can't return binary data from it");
+        JS_EndRequest(context);
         return JS_FALSE;
     }
 
@@ -388,6 +414,7 @@ gjs_string_get_uint16_data(JSContext       *context,
     *len_p = JS_GetStringLength(JSVAL_TO_STRING(value));
     *data_p = g_memdup(js_data, sizeof(*js_data)*(*len_p));
 
+    JS_EndRequest(context);
     return JS_TRUE;
 }
 
@@ -439,6 +466,7 @@ gjstest_test_func_gjs_jsapi_util_string_js_string_utf8(void)
 
     runtime = JS_NewRuntime(1024*1024 /* max bytes */);
     context = JS_NewContext(runtime, 8192);
+    JS_BeginRequest(context);
     global = JS_NewObject(context, NULL, NULL, NULL);
     JS_SetGlobalObject(context, global);
     JS_InitStandardClasses(context, global);
@@ -450,6 +478,7 @@ gjstest_test_func_gjs_jsapi_util_string_js_string_utf8(void)
     g_assert(JSVAL_IS_STRING(js_string));
     g_assert(gjs_string_to_utf8(context, js_string, &utf8_result) == JS_TRUE);
 
+    JS_EndRequest(context);
     JS_DestroyContext(context);
     JS_DestroyRuntime(runtime);
 
@@ -470,6 +499,7 @@ gjstest_test_func_gjs_jsapi_util_string_get_ascii(void)
 
     runtime = JS_NewRuntime(1024*1024 /* max bytes */);
     context = JS_NewContext(runtime, 8192);
+    JS_BeginRequest(context);
     global = JS_NewObject(context, NULL, NULL, NULL);
     JS_SetGlobalObject(context, global);
     JS_InitStandardClasses(context, global);
@@ -482,6 +512,7 @@ gjstest_test_func_gjs_jsapi_util_string_get_ascii(void)
     g_assert(gjs_string_get_ascii_checked(context, void_value) == NULL);
     g_assert(JS_IsExceptionPending(context));
 
+    JS_EndRequest(context);
     JS_DestroyContext(context);
     JS_DestroyRuntime(runtime);
 }
@@ -504,6 +535,7 @@ gjstest_test_func_gjs_jsapi_util_string_get_binary(void)
 
     runtime = JS_NewRuntime(1024*1024 /* max bytes */);
     context = JS_NewContext(runtime, 8192);
+    JS_BeginRequest(context);
     global = JS_NewObject(context, NULL, NULL, NULL);
     JS_SetGlobalObject(context, global);
     JS_InitStandardClasses(context, global);
@@ -550,6 +582,7 @@ gjstest_test_func_gjs_jsapi_util_string_get_binary(void)
                                         &data, &len));
     g_assert(JS_IsExceptionPending(context));
 
+    JS_EndRequest(context);
     JS_DestroyContext(context);
     JS_DestroyRuntime(runtime);
 }
diff --git a/gjs/jsapi-util.c b/gjs/jsapi-util.c
index 25bdf5c..e2f7f14 100644
--- a/gjs/jsapi-util.c
+++ b/gjs/jsapi-util.c
@@ -242,6 +242,8 @@ gjs_object_get_property(JSContext  *context,
     jsval value;
     JSExceptionState *state;
 
+    JS_BeginRequest(context);
+
     value = JSVAL_VOID;
     state = JS_SaveExceptionState(context);
     JS_GetProperty(context, obj, property_name, &value);
@@ -250,6 +252,8 @@ gjs_object_get_property(JSContext  *context,
     if (value_p)
         *value_p = value;
 
+    JS_EndRequest(context);
+
     return value != JSVAL_VOID;
 }
 
@@ -269,6 +273,8 @@ gjs_object_require_property(JSContext       *context,
 {
     jsval value;
 
+    JS_BeginRequest(context);
+
     value = JSVAL_VOID;
     JS_GetProperty(context, obj, property_name, &value);
 
@@ -277,6 +283,7 @@ gjs_object_require_property(JSContext       *context,
 
     if (value != JSVAL_VOID) {
         JS_ClearPendingException(context); /* in case JS_GetProperty() was on crack */
+        JS_EndRequest(context);
         return TRUE;
     } else {
         /* remember gjs_throw() is a no-op if JS_GetProperty()
@@ -290,6 +297,8 @@ gjs_object_require_property(JSContext       *context,
             gjs_throw(context,
                       "No property '%s' in object %p (or its value was undefined)",
                       property_name, obj);
+
+        JS_EndRequest(context);
         return FALSE;
     }
 }
@@ -318,6 +327,8 @@ gjs_init_class_dynamic(JSContext      *context,
         return NULL;
     }
 
+    JS_BeginRequest(context);
+
     /* We replace the passed-in context and global object with our
      * runtime-global permanent load context. Otherwise, in a
      * process with multiple contexts, we'd arbitrarily define
@@ -325,6 +336,7 @@ gjs_init_class_dynamic(JSContext      *context,
      * class first, which is not desirable.
      */
     load_context = gjs_runtime_get_load_context(JS_GetRuntime(context));
+    JS_BeginRequest(load_context);
 
     /* JS_InitClass() wants to define the constructor in the global object, so
      * we give it a private and namespaced name... passing in the namespace
@@ -397,6 +409,8 @@ gjs_init_class_dynamic(JSContext      *context,
                            GJS_MODULE_PROP_FLAGS))
         goto error;
 
+    JS_EndRequest(load_context);
+    JS_EndRequest(context);
     return prototype;
 
  error:
@@ -407,18 +421,23 @@ gjs_init_class_dynamic(JSContext      *context,
         gjs_throw(context, "No exception was set, but class initialize failed somehow");
     }
 
+    JS_EndRequest(load_context);
+    JS_EndRequest(context);
     return NULL;
 }
 
 gboolean
 gjs_check_constructing(JSContext *context)
 {
+    JS_BeginRequest(context);
     if (!JS_IsConstructing(context)) {
+        JS_EndRequest(context);
         gjs_throw(context,
                   "Constructor called as normal method. Use 'new SomeObject()' not 'SomeObject()'");
         return FALSE;
     }
 
+    JS_EndRequest(context);
     return TRUE;
 }
 
@@ -430,12 +449,15 @@ gjs_get_instance_private_dynamic(JSContext      *context,
 {
     RuntimeData *rd;
     JSClass *obj_class;
+    void *instance;
 
     if (static_clasp->name != NULL) {
         g_warning("Dynamic class should not have a name in the JSClass struct");
         return NULL;
     }
 
+    JS_BeginRequest(context);
+
     obj_class = JS_GET_CLASS(context, obj);
     g_assert(obj_class != NULL);
 
@@ -447,15 +469,20 @@ gjs_get_instance_private_dynamic(JSContext      *context,
         gjs_throw(context,
                   "Object %p proto %p doesn't have a dynamically-registered class, it has %s",
                   obj, JS_GetPrototype(context, obj), obj_class->name);
+        JS_EndRequest(context);
         return NULL;
     }
 
     if (static_clasp != ((DynamicJSClass*) obj_class)->static_class) {
         gjs_throw(context, "Object is not a dynamically-registered class based on expected static class pointer");
+        JS_EndRequest(context);
         return NULL;
     }
 
-    return JS_GetInstancePrivate(context, obj, obj_class, argv);
+    instance = JS_GetInstancePrivate(context, obj, obj_class, argv);
+    JS_EndRequest(context);
+
+    return instance;
 }
 
 void*
@@ -466,12 +493,15 @@ gjs_get_instance_private_dynamic_with_typecheck(JSContext      *context,
 {
     RuntimeData *rd;
     JSClass *obj_class;
+    void *instance;
 
     if (static_clasp->name != NULL) {
         g_warning("Dynamic class should not have a name in the JSClass struct");
         return NULL;
     }
 
+    JS_BeginRequest(context);
+
     obj_class = JS_GET_CLASS(context, obj);
     g_assert(obj_class != NULL);
 
@@ -480,14 +510,18 @@ gjs_get_instance_private_dynamic_with_typecheck(JSContext      *context,
 
     /* Check that it's safe to cast to DynamicJSClass */
     if (g_hash_table_lookup(rd->dynamic_classes, obj_class) == NULL) {
+        JS_EndRequest(context);
         return NULL;
     }
 
     if (static_clasp != ((DynamicJSClass*) obj_class)->static_class) {
+        JS_EndRequest(context);
         return NULL;
     }
 
-    return JS_GetInstancePrivate(context, obj, obj_class, argv);
+    instance = JS_GetInstancePrivate(context, obj, obj_class, argv);
+    JS_EndRequest(context);
+    return instance;
 }
 
 JSObject*
@@ -501,12 +535,15 @@ gjs_construct_object_dynamic(JSContext      *context,
     JSContext *load_context;
     JSObject *result;
 
+    JS_BeginRequest(context);
+
     /* We replace the passed-in context and global object with our
      * runtime-global permanent load context. Otherwise, JS_ConstructObject
      * can't find the constructor in whatever random global object is set
      * on the passed-in context.
      */
     load_context = gjs_runtime_get_load_context(JS_GetRuntime(context));
+    JS_BeginRequest(load_context);
 
     proto_class = JS_GET_CLASS(load_context, proto);
 
@@ -530,6 +567,8 @@ gjs_construct_object_dynamic(JSContext      *context,
     if (!result)
         goto error;
 
+    JS_EndRequest(load_context);
+    JS_EndRequest(context);
     return result;
 
  error:
@@ -540,6 +579,8 @@ gjs_construct_object_dynamic(JSContext      *context,
         gjs_throw(context, "No exception was set, but object construction failed somehow");
     }
 
+    JS_EndRequest(load_context);
+    JS_EndRequest(context);
     return NULL;
 }
 
@@ -555,6 +596,8 @@ gjs_define_string_array(JSContext   *context,
     JSObject *array;
     int i;
 
+    JS_BeginRequest(context);
+
     if (!JS_EnterLocalRootScope(context))
         return JS_FALSE;
 
@@ -580,6 +623,8 @@ gjs_define_string_array(JSContext   *context,
     }
 
     JS_LeaveLocalRootScope(context);
+
+    JS_EndRequest(context);
     return array;
 }
 
@@ -588,6 +633,9 @@ gjs_value_debug_string(JSContext      *context,
                        jsval           value)
 {
     JSString *str;
+    const char *bytes;
+
+    JS_BeginRequest(context);
 
     str = JS_ValueToString(context, value);
 
@@ -616,7 +664,11 @@ gjs_value_debug_string(JSContext      *context,
 
     g_assert(str != NULL);
 
-    return JS_GetStringBytes(str);
+    bytes = JS_GetStringBytes(str);
+
+    JS_EndRequest(context);
+
+    return bytes;
 }
 
 void
@@ -628,6 +680,8 @@ gjs_log_object_props(JSContext      *context,
     JSObject *props_iter;
     jsid prop_id;
 
+    JS_BeginRequest(context);
+
     /* We potentially create new strings, plus the property iterator,
      * that could get collected as we go through this process. So
      * create a local root scope.
@@ -672,6 +726,7 @@ gjs_log_object_props(JSContext      *context,
 
  done:
     JS_LeaveLocalRootScope(context);
+    JS_EndRequest(context);
 }
 
 void
@@ -691,6 +746,10 @@ gjs_explain_scope(JSContext  *context,
     load_context = gjs_runtime_peek_load_context(JS_GetRuntime(context));
     call_context = gjs_runtime_peek_call_context(JS_GetRuntime(context));
 
+    JS_BeginRequest(context);
+    JS_BeginRequest(load_context);
+    JS_BeginRequest(call_context);
+
     JS_EnterLocalRootScope(context);
 
     gjs_debug(GJS_DEBUG_SCOPE,
@@ -724,12 +783,18 @@ gjs_explain_scope(JSContext  *context,
     g_string_free(chain, TRUE);
 
     JS_LeaveLocalRootScope(context);
+
+    JS_EndRequest(call_context);
+    JS_EndRequest(load_context);
+    JS_EndRequest(context);
 }
 
 void
 gjs_log_exception_props(JSContext *context,
                         jsval      exc)
 {
+    JS_BeginRequest(context);
+
     /* This is useful when the exception was never sent to an error reporter
      * due to JSOPTION_DONT_REPORT_UNCAUGHT, or if the exception was not
      * a normal Error object so jsapi didn't know how to report it sensibly.
@@ -766,6 +831,7 @@ gjs_log_exception_props(JSContext *context,
         gjs_debug(GJS_DEBUG_ERROR,
                   "Exception had some strange type");
     }
+    JS_EndRequest(context);
 }
 
 static JSBool
@@ -778,6 +844,8 @@ log_and_maybe_keep_exception(JSContext  *context,
     char *message;
     JSBool retval = JS_FALSE;
 
+    JS_BeginRequest(context);
+
     if (message_p)
         *message_p = NULL;
 
@@ -824,6 +892,8 @@ log_and_maybe_keep_exception(JSContext  *context,
  out:
     JS_RemoveRoot(context, &exc);
 
+    JS_EndRequest(context);
+
     return retval;
 }
 
@@ -850,39 +920,51 @@ try_to_chain_stack_trace(JSContext *src_context, JSContext *dst_context,
     jsval chained, src_stack, dst_stack, new_stack;
     JSString *new_stack_str;
 
+    JS_BeginRequest(src_context);
+    JS_BeginRequest(dst_context);
+
     if (!JSVAL_IS_OBJECT(src_exc))
-        return; // src_exc doesn't have a stack trace
+        goto out; // src_exc doesn't have a stack trace
 
     /* create a new exception in dst_context to get a stack trace */
     gjs_throw_literal(dst_context, "Chained exception");
     if (!(JS_GetPendingException(dst_context, &chained) &&
           JSVAL_IS_OBJECT(chained)))
-        return; // gjs_throw_literal didn't work?!
+        goto out; // gjs_throw_literal didn't work?!
     JS_ClearPendingException(dst_context);
 
     /* get stack trace for src_exc and chained */
     if (!(gjs_object_get_property(dst_context, JSVAL_TO_OBJECT(chained),
                                   "stack", &dst_stack) &&
           JSVAL_IS_STRING(dst_stack)))
-        return; // couldn't get chained stack
+        goto out; // couldn't get chained stack
     if (!(gjs_object_get_property(src_context, JSVAL_TO_OBJECT(src_exc),
                                   "stack", &src_stack) &&
           JSVAL_IS_STRING(src_stack)))
-        return; // couldn't get source stack
+        goto out; // couldn't get source stack
 
     /* add chained exception's stack trace to src_exc */
     new_stack_str = JS_ConcatStrings
         (dst_context, JSVAL_TO_STRING(src_stack), JSVAL_TO_STRING(dst_stack));
     if (new_stack_str==NULL)
-        return; // couldn't concatenate src and dst stacks?!
+        goto out; // couldn't concatenate src and dst stacks?!
     new_stack = STRING_TO_JSVAL(new_stack_str);
     JS_SetProperty(dst_context, JSVAL_TO_OBJECT(src_exc), "stack", &new_stack);
+
+ out:
+    JS_EndRequest(dst_context);
+    JS_EndRequest(src_context);
 }
 
 JSBool
 gjs_move_exception(JSContext      *src_context,
                    JSContext      *dest_context)
 {
+    JSBool success;
+
+    JS_BeginRequest(src_context);
+    JS_BeginRequest(dest_context);
+
     /* NOTE: src and dest could be the same. */
     jsval exc;
     if (JS_GetPendingException(src_context, &exc)) {
@@ -894,10 +976,15 @@ gjs_move_exception(JSContext      *src_context,
             JS_SetPendingException(dest_context, exc);
             JS_ClearPendingException(src_context);
         }
-        return JS_TRUE;
+        success = JS_TRUE;
     } else {
-        return JS_FALSE;
+        success = JS_FALSE;
     }
+
+    JS_EndRequest(dest_context);
+    JS_EndRequest(src_context);
+
+    return success;
 }
 
 JSBool
@@ -911,12 +998,17 @@ gjs_call_function_value(JSContext      *context,
     JSBool result;
     JSContext *call_context;
 
+    JS_BeginRequest(context);
+
     call_context = gjs_runtime_get_call_context(JS_GetRuntime(context));
+    JS_BeginRequest(call_context);
 
     result = JS_CallFunctionValue(call_context, obj, fval,
                                   argc, argv, rval);
     gjs_move_exception(call_context, context);
 
+    JS_EndRequest(call_context);
+    JS_EndRequest(context);
     return result;
 }
 
@@ -1014,6 +1106,9 @@ gjs_date_from_time_t (JSContext *context, time_t time)
     JSObject *date_constructor;
     jsval date_prototype;
     jsval args[1];
+    jsval result;
+
+    JS_BeginRequest(context);
 
     if (!JS_EnterLocalRootScope(context))
         return JSVAL_VOID;
@@ -1033,8 +1128,11 @@ gjs_date_from_time_t (JSContext *context, time_t time)
     date = JS_ConstructObjectWithArguments(context, date_class,
                                            NULL, NULL, 1, args);
 
+    result = OBJECT_TO_JSVAL(date);
     JS_LeaveLocalRootScope(context);
-    return OBJECT_TO_JSVAL(date);
+    JS_EndRequest(context);
+
+    return result;
 }
 
 /**
@@ -1083,6 +1181,8 @@ gjs_parse_args (JSContext  *context,
     guint n_total;
     guint consumed_args;
 
+    JS_BeginRequest(context);
+
     va_start (args, argv);
 
     /* Check for optional argument specifier */
@@ -1219,6 +1319,8 @@ gjs_parse_args (JSContext  *context,
     }
 
     va_end (args);
+
+    JS_EndRequest(context);
     return JS_TRUE;
 
  error_unwind:
@@ -1227,5 +1329,6 @@ gjs_parse_args (JSContext  *context,
     for (i = 0; i < n_unwind; i++) {
         g_free (unwind_strings[i]);
     }
+    JS_EndRequest(context);
     return JS_FALSE;
 }
diff --git a/modules/dbus-exports.c b/modules/dbus-exports.c
index f407667..bed9b7d 100644
--- a/modules/dbus-exports.c
+++ b/modules/dbus-exports.c
@@ -1852,24 +1852,30 @@ gjs_js_define_dbus_exports(JSContext      *context,
 {
     JSObject *exports;
     JSContext *load_context;
+    JSBool success;
 
+    success = JS_FALSE;
     load_context = gjs_runtime_get_load_context(JS_GetRuntime(context));
+    JS_BeginRequest(load_context);
 
     exports = exports_new(load_context, which_bus);
     if (exports == NULL) {
         gjs_move_exception(load_context, context);
-        return JS_FALSE;
+        goto fail;
     }
 
     if (!add_connect_funcs(context, exports, which_bus))
-        return JS_FALSE;
+        goto fail;
 
     if (!JS_DefineProperty(context, in_object,
                            "exports",
                            OBJECT_TO_JSVAL(exports),
                            NULL, NULL,
                            GJS_MODULE_PROP_FLAGS))
-        return JS_FALSE;
+        goto fail;
 
-    return JS_TRUE;
+    success = JS_TRUE;
+ fail:
+    JS_EndRequest(load_context);
+    return success;
 }
diff --git a/modules/dbus.c b/modules/dbus.c
index f1311b4..c6007c9 100644
--- a/modules/dbus.c
+++ b/modules/dbus.c
@@ -632,9 +632,12 @@ signal_handler_callback(DBusConnection *connection,
         return;
     }
 
+    JS_BeginRequest(context);
+
     dbus_message_iter_init(message, &arg_iter);
     if (!gjs_js_values_from_dbus(context, &arg_iter, &arguments)) {
         gjs_debug(GJS_DEBUG_DBUS, "Failed to marshal dbus signal to JS");
+        JS_EndRequest(context);
         return;
     }
 
@@ -657,6 +660,8 @@ signal_handler_callback(DBusConnection *connection,
     gjs_rooted_array_free(context, arguments, TRUE);
 
     signal_handler_unref(handler); /* for safety */
+
+    JS_EndRequest(context);
 }
 
 /* Args are bus_name, object_path, iface, signal, and callback */
@@ -997,6 +1002,8 @@ on_name_acquired(DBusConnection *connection,
         return;
     }
 
+    JS_BeginRequest(context);
+
     argc = 1;
 
     argv[0] = STRING_TO_JSVAL(JS_NewStringCopyZ(context, name));
@@ -1010,6 +1017,8 @@ on_name_acquired(DBusConnection *connection,
 
     JS_RemoveRoot(context, &argv[0]);
     JS_RemoveRoot(context, &rval);
+
+    JS_EndRequest(context);
 }
 
 static void
@@ -1032,6 +1041,8 @@ on_name_lost(DBusConnection *connection,
         return;
     }
 
+    JS_BeginRequest(context);
+
     argc = 1;
 
     argv[0] = STRING_TO_JSVAL(JS_NewStringCopyZ(context, name));
@@ -1045,6 +1056,8 @@ on_name_lost(DBusConnection *connection,
 
     JS_RemoveRoot(context, &argv[0]);
     JS_RemoveRoot(context, &rval);
+
+    JS_EndRequest(context);
 }
 
 static void
@@ -1209,6 +1222,8 @@ on_name_appeared(DBusConnection *connection,
         return;
     }
 
+    JS_BeginRequest(context);
+
     argc = 2;
 
     gjs_set_values(context, argv, argc, JSVAL_VOID);
@@ -1225,6 +1240,8 @@ on_name_appeared(DBusConnection *connection,
 
     JS_RemoveRoot(context, &rval);
     gjs_unroot_value_locations(context, argv, argc);
+
+    JS_EndRequest(context);
 }
 
 static void
@@ -1248,6 +1265,8 @@ on_name_vanished(DBusConnection *connection,
         return;
     }
 
+    JS_BeginRequest(context);
+
     argc = 2;
 
     gjs_set_values(context, argv, argc, JSVAL_VOID);
@@ -1264,6 +1283,8 @@ on_name_vanished(DBusConnection *connection,
 
     JS_RemoveRoot(context, &rval);
     gjs_unroot_value_locations(context, argv, argc);
+
+    JS_EndRequest(context);
 }
 
 static const GjsDBusWatchNameFuncs watch_name_funcs = {
diff --git a/modules/mainloop.c b/modules/mainloop.c
index 814619d..7208e45 100644
--- a/modules/mainloop.c
+++ b/modules/mainloop.c
@@ -123,6 +123,7 @@ closure_source_func(void *data)
         /* closure is invalid now */
         return FALSE;
     }
+    JS_BeginRequest(context);
 
     retval = JSVAL_VOID;
     JS_AddRoot(context, &retval);
@@ -135,12 +136,13 @@ closure_source_func(void *data)
      * JavaScript always makes some sense of any value in
      * an "if (value) {}" context.
      */
-    if (!JS_ValueToBoolean(gjs_closure_get_context(closure),
+    if (!JS_ValueToBoolean(context,
                            retval, &bool_val))
         bool_val = FALSE;
 
     JS_RemoveRoot(context, &retval);
 
+    JS_EndRequest(context);
     return bool_val;
 }
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]