diff options
author | Havoc Pennington <hp@pobox.com> | 2010-05-01 00:33:01 -0400 |
---|---|---|
committer | Havoc Pennington <hp@pobox.com> | 2010-05-01 01:19:21 -0400 |
commit | ccc6e7ce6cf9d2f42b2667d1998598f376c86f76 (patch) | |
tree | 99eed51691ecdde6ac7a80658358fc0e04f1c1dd /gjs | |
parent | 941791d4cbcf4a42ecac63d47ab2333613d847b8 (diff) | |
download | gjs-ccc6e7ce6cf9d2f42b2667d1998598f376c86f76.tar.gz |
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
Diffstat (limited to 'gjs')
-rw-r--r-- | gjs/context.c | 34 | ||||
-rw-r--r-- | gjs/importer.c | 23 | ||||
-rw-r--r-- | gjs/jsapi-util-array.c | 13 | ||||
-rw-r--r-- | gjs/jsapi-util-error.c | 9 | ||||
-rw-r--r-- | gjs/jsapi-util-string.c | 39 | ||||
-rw-r--r-- | gjs/jsapi-util.c | 125 |
6 files changed, 223 insertions, 20 deletions
diff --git a/gjs/context.c b/gjs/context.c index 035c8d3a..743bb1a3 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 8d11e9d5..c7902f61 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 d3ce3f7a..b4c7360e 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 2b867183..50d4449b 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 fc669a02..4a571761 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 25bdf5ce..e2f7f14b 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; } |