diff options
author | Philip Chimento <philip.chimento@gmail.com> | 2018-11-03 22:09:05 -0400 |
---|---|---|
committer | Philip Chimento <philip.chimento@gmail.com> | 2018-11-03 22:11:08 -0400 |
commit | 7140cac80c8a1df90debfec2305738c830b335f7 (patch) | |
tree | b2550a5d4dd3bb236d35586911c21d068720aad7 | |
parent | 92e20de33d4b882b172db9edf78f4699dd923905 (diff) | |
download | gjs-7140cac80c8a1df90debfec2305738c830b335f7.tar.gz |
closure: Store JSFunction* pointer instead of JSObject*
In practice not much difference, but this should give a small extra
safeguard against accidentally using a non-function object as the
callable of a signal connection.
-rw-r--r-- | gi/arg.cpp | 10 | ||||
-rw-r--r-- | gi/closure.cpp | 81 | ||||
-rw-r--r-- | gi/closure.h | 8 | ||||
-rw-r--r-- | gi/function.cpp | 35 | ||||
-rw-r--r-- | gi/function.h | 9 | ||||
-rw-r--r-- | gi/object.cpp | 11 | ||||
-rw-r--r-- | gi/value.cpp | 20 | ||||
-rw-r--r-- | gi/value.h | 12 | ||||
-rw-r--r-- | gjs/jsapi-util-root.h | 12 |
9 files changed, 91 insertions, 107 deletions
@@ -1776,11 +1776,11 @@ gjs_value_to_g_argument(JSContext *context, } } else if (g_type_is_a(gtype, G_TYPE_BOXED)) { if (g_type_is_a(gtype, G_TYPE_CLOSURE)) { - arg->v_pointer = gjs_closure_new_marshaled(context, - &value.toObject(), - "boxed"); - g_closure_ref((GClosure *) arg->v_pointer); - g_closure_sink((GClosure *) arg->v_pointer); + GClosure* closure = gjs_closure_new_marshaled( + context, JS_GetObjectFunction(obj), "boxed"); + g_closure_ref(closure); + g_closure_sink(closure); + arg->v_pointer = closure; } else { /* Should have been caught above as STRUCT/BOXED/UNION */ gjs_throw(context, diff --git a/gi/closure.cpp b/gi/closure.cpp index e5c38413..5bf082d3 100644 --- a/gi/closure.cpp +++ b/gi/closure.cpp @@ -34,7 +34,7 @@ struct Closure { JSContext *context; - GjsMaybeOwned<JSObject *> obj; + GjsMaybeOwned<JSFunction*> func; }; struct GjsClosure { @@ -86,10 +86,10 @@ invalidate_js_pointers(GjsClosure *gc) c = &gc->priv; - if (c->obj == nullptr) + if (!c->func) return; - c->obj.reset(); + c->func.reset(); c->context = NULL; /* Notify any closure reference holders they @@ -98,19 +98,17 @@ invalidate_js_pointers(GjsClosure *gc) g_closure_invalidate(&gc->base); } -static void -global_context_finalized(JS::HandleObject obj, - void *data) -{ +static void global_context_finalized(JS::HandleFunction func, void* data) { GjsClosure *gc = (GjsClosure*) data; Closure *c = &gc->priv; - gjs_debug_closure("Context global object destroy notifier on closure %p " - "which calls object %p", - c, c->obj.get()); + gjs_debug_closure( + "Context global object destroy notifier on closure %p which calls " + "object %p", + c, c->func.get()); - if (c->obj) { - g_assert(c->obj == obj.get()); + if (c->func) { + g_assert(c->func == func.get()); invalidate_js_pointers(gc); } @@ -136,10 +134,10 @@ closure_invalidated(gpointer data, c = &((GjsClosure*) closure)->priv; GJS_DEC_COUNTER(closure); - gjs_debug_closure("Invalidating closure %p which calls object %p", - closure, c->obj.get()); + gjs_debug_closure("Invalidating closure %p which calls function %p", + closure, c->func.get()); - if (c->obj == nullptr) { + if (!c->func) { gjs_debug_closure(" (closure %p already dead, nothing to do)", closure); return; @@ -156,7 +154,7 @@ closure_invalidated(gpointer data, "removing our destroy notifier on global object)", closure); - c->obj.reset(); + c->func.reset(); c->context = nullptr; } @@ -166,11 +164,11 @@ closure_set_invalid(gpointer data, { Closure *self = &((GjsClosure*) closure)->priv; - gjs_debug_closure("Invalidating signal closure %p which calls object %p", - closure, self->obj.get()); + gjs_debug_closure("Invalidating signal closure %p which calls function %p", + closure, self->func.get()); - self->obj.prevent_collection(); - self->obj.reset(); + self->func.prevent_collection(); + self->func.reset(); self->context = nullptr; GJS_DEC_COUNTER(closure); @@ -197,7 +195,7 @@ gjs_closure_invoke(GClosure *closure, c = &((GjsClosure*) closure)->priv; - if (c->obj == nullptr) { + if (!c->func) { /* We were destroyed; become a no-op */ c->context = NULL; return false; @@ -205,7 +203,7 @@ gjs_closure_invoke(GClosure *closure, context = c->context; JSAutoRequest ar(context); - JSAutoCompartment ac(context, c->obj); + JSAutoCompartment ac(context, JS_GetFunctionObject(c->func)); if (JS_IsExceptionPending(context)) { gjs_debug_closure("Exception was pending before invoking callback??? " @@ -213,12 +211,13 @@ gjs_closure_invoke(GClosure *closure, gjs_log_exception(context); } - JS::RootedValue v_closure(context, JS::ObjectValue(*c->obj)); - if (!gjs_call_function_value(context, this_obj, v_closure, args, retval)) { + JS::RootedFunction func(context, c->func); + if (!JS::Call(context, this_obj, func, args, retval)) { /* Exception thrown... */ - gjs_debug_closure("Closure invocation failed (exception should " - "have been thrown) closure %p callable %p", - closure, c->obj.get()); + gjs_debug_closure( + "Closure invocation failed (exception should have been thrown) " + "closure %p function %p", + closure, c->func.get()); /* 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 @@ -241,7 +240,7 @@ gjs_closure_invoke(GClosure *closure, " - closure %p", closure); } - JS_MaybeGC(context); + gjs_schedule_gc_if_needed(context); return true; } @@ -265,14 +264,12 @@ gjs_closure_get_context(GClosure *closure) return c->context; } -JSObject* -gjs_closure_get_callable(GClosure *closure) -{ +JSFunction* gjs_closure_get_callable(GClosure* closure) { Closure *c; c = &((GjsClosure*) closure)->priv; - return c->obj; + return c->func; } void @@ -283,18 +280,14 @@ gjs_closure_trace(GClosure *closure, c = &((GjsClosure*) closure)->priv; - if (c->obj == nullptr) + if (!c->func) return; - c->obj.trace(tracer, "signal connection"); + c->func.trace(tracer, "signal connection"); } -GClosure* -gjs_closure_new(JSContext *context, - JSObject *callable, - const char *description, - bool root_function) -{ +GClosure* gjs_closure_new(JSContext* context, JSFunction* callable, + const char* description, bool root_function) { GjsClosure *gc; Closure *c; @@ -313,11 +306,11 @@ gjs_closure_new(JSContext *context, if (root_function) { /* Fully manage closure lifetime if so asked */ - c->obj.root(context, callable, global_context_finalized, gc); + c->func.root(context, callable, global_context_finalized, gc); g_closure_add_invalidate_notifier(&gc->base, NULL, closure_invalidated); } else { - c->obj = callable; + c->func = callable; /* Only mark the closure as invalid if memory is managed outside (i.e. by object.c for signals) */ g_closure_add_invalidate_notifier(&gc->base, NULL, closure_set_invalid); @@ -325,8 +318,8 @@ gjs_closure_new(JSContext *context, g_closure_add_finalize_notifier(&gc->base, NULL, closure_finalize); - gjs_debug_closure("Create closure %p which calls object %p '%s'", - gc, c->obj.get(), description); + gjs_debug_closure("Create closure %p which calls function %p '%s'", gc, + c->func.get(), description); JS_EndRequest(context); diff --git a/gi/closure.h b/gi/closure.h index 40f5b0d8..33cc5341 100644 --- a/gi/closure.h +++ b/gi/closure.h @@ -33,10 +33,8 @@ G_BEGIN_DECLS GJS_USE -GClosure* gjs_closure_new (JSContext *context, - JSObject *callable, - const char *description, - bool root_function); +GClosure* gjs_closure_new(JSContext* cx, JSFunction* callable, + const char* description, bool root_function); GJS_USE bool gjs_closure_invoke(GClosure *closure, @@ -50,7 +48,7 @@ JSContext* gjs_closure_get_context (GClosure *closure); GJS_USE bool gjs_closure_is_valid (GClosure *closure); GJS_USE -JSObject* gjs_closure_get_callable (GClosure *closure); +JSFunction* gjs_closure_get_callable(GClosure* closure); void gjs_closure_trace (GClosure *closure, JSTracer *tracer); diff --git a/gi/function.cpp b/gi/function.cpp index 2673eaf5..41586f14 100644 --- a/gi/function.cpp +++ b/gi/function.cpp @@ -226,8 +226,8 @@ gjs_callback_closure(ffi_cif *cif, } JS_BeginRequest(context); - JSAutoCompartment ac(context, - gjs_closure_get_callable(trampoline->js_function)); + JSAutoCompartment ac(context, JS_GetFunctionObject(gjs_closure_get_callable( + trampoline->js_function))); bool can_throw_gerror = g_callable_info_can_throw_gerror(trampoline->info); n_args = g_callable_info_get_n_args(trampoline->info); @@ -490,19 +490,14 @@ gjs_destroy_notify_callback(gpointer data) gjs_callback_trampoline_unref(trampoline); } -GjsCallbackTrampoline* -gjs_callback_trampoline_new(JSContext *context, - JS::HandleValue function, - GICallableInfo *callable_info, - GIScopeType scope, - JS::HandleObject scope_object, - bool is_vfunc) -{ +GjsCallbackTrampoline* gjs_callback_trampoline_new( + JSContext* context, JS::HandleFunction function, + GICallableInfo* callable_info, GIScopeType scope, + JS::HandleObject scope_object, bool is_vfunc) { GjsCallbackTrampoline *trampoline; int n_args, i; - g_assert(function.isObject()); - g_assert(JS_TypeOfValue(context, function) == JSTYPE_FUNCTION); + g_assert(function); trampoline = g_slice_new(GjsCallbackTrampoline); new (trampoline) GjsCallbackTrampoline(); @@ -516,9 +511,8 @@ gjs_callback_trampoline_new(JSContext *context, * (and same for vfuncs, which are associated with a GObject prototype) */ bool should_root = scope != GI_SCOPE_TYPE_NOTIFIED || !scope_object; - trampoline->js_function = gjs_closure_new(context, &function.toObject(), - g_base_info_get_name(callable_info), - should_root); + trampoline->js_function = gjs_closure_new( + context, function, g_base_info_get_name(callable_info), should_root); if (!should_root && scope_object) gjs_object_associate_closure(context, scope_object, trampoline->js_function); @@ -959,13 +953,12 @@ gjs_invoke_c_function(JSContext *context, break; } + JS::RootedFunction func( + context, JS_GetObjectFunction(¤t_arg.toObject())); callable_info = (GICallableInfo*) g_type_info_get_interface(&ainfo); - trampoline = gjs_callback_trampoline_new(context, - current_arg, - callable_info, - scope, - is_object_method ? obj : nullptr, - false); + trampoline = gjs_callback_trampoline_new( + context, func, callable_info, scope, + is_object_method ? obj : nullptr, false); closure = trampoline->closure; g_base_info_unref(callable_info); } diff --git a/gi/function.h b/gi/function.h index 30f473c7..42861d39 100644 --- a/gi/function.h +++ b/gi/function.h @@ -56,12 +56,9 @@ struct GjsCallbackTrampoline { }; GJS_JSAPI_RETURN_CONVENTION -GjsCallbackTrampoline* gjs_callback_trampoline_new(JSContext *context, - JS::HandleValue function, - GICallableInfo *callable_info, - GIScopeType scope, - JS::HandleObject scope_object, - bool is_vfunc); +GjsCallbackTrampoline* gjs_callback_trampoline_new( + JSContext* cx, JS::HandleFunction function, GICallableInfo* callable_info, + GIScopeType scope, JS::HandleObject scope_object, bool is_vfunc); void gjs_callback_trampoline_unref(GjsCallbackTrampoline *trampoline); void gjs_callback_trampoline_ref(GjsCallbackTrampoline *trampoline); diff --git a/gi/object.cpp b/gi/object.cpp index 0edb003e..ee31e1b6 100644 --- a/gi/object.cpp +++ b/gi/object.cpp @@ -1917,7 +1917,8 @@ ObjectInstance::connect_impl(JSContext *context, return false; } - closure = gjs_closure_new_for_signal(context, callback, "signal callback", signal_id); + closure = gjs_closure_new_for_signal( + context, JS_GetObjectFunction(callback), "signal callback", signal_id); if (closure == NULL) return false; associate_closure(context, closure); @@ -2533,9 +2534,13 @@ bool ObjectPrototype::hook_up_vfunc_impl(JSContext* cx, offset = g_field_info_get_offset(field_info); method_ptr = G_STRUCT_MEMBER_P(implementor_vtable, offset); - JS::RootedValue v_function(cx, JS::ObjectValue(*function)); + if (!JS_ObjectIsFunction(cx, function)) { + gjs_throw(cx, "Tried to deal with a vfunc that wasn't a function"); + return false; + } + JS::RootedFunction func(cx, JS_GetObjectFunction(function)); trampoline = gjs_callback_trampoline_new( - cx, v_function, vfunc, GI_SCOPE_TYPE_NOTIFIED, prototype, true); + cx, func, vfunc, GI_SCOPE_TYPE_NOTIFIED, prototype, true); *((ffi_closure **)method_ptr) = trampoline->closure; } diff --git a/gi/value.cpp b/gi/value.cpp index fabecca2..1e51fd96 100644 --- a/gi/value.cpp +++ b/gi/value.cpp @@ -124,7 +124,6 @@ closure_marshal(GClosure *closure, gpointer marshal_data) { JSContext *context; - JSObject *obj; unsigned i; GSignalQuery signal_query = { 0, }; GISignalInfo *signal_info; @@ -163,9 +162,9 @@ closure_marshal(GClosure *closure, return; } - obj = gjs_closure_get_callable(closure); + JSFunction* func = gjs_closure_get_callable(closure); JSAutoRequest ar(context); - JSAutoCompartment ac(context, obj); + JSAutoCompartment ac(context, JS_GetFunctionObject(func)); if (marshal_data) { /* we are used for a signal handler */ @@ -292,12 +291,8 @@ closure_marshal(GClosure *closure, } } -GClosure* -gjs_closure_new_for_signal(JSContext *context, - JSObject *callable, - const char *description, - guint signal_id) -{ +GClosure* gjs_closure_new_for_signal(JSContext* context, JSFunction* callable, + const char* description, guint signal_id) { GClosure *closure; closure = gjs_closure_new(context, callable, description, false); @@ -307,11 +302,8 @@ gjs_closure_new_for_signal(JSContext *context, return closure; } -GClosure* -gjs_closure_new_marshaled (JSContext *context, - JSObject *callable, - const char *description) -{ +GClosure* gjs_closure_new_marshaled(JSContext* context, JSFunction* callable, + const char* description) { GClosure *closure; closure = gjs_closure_new(context, callable, description, true); @@ -47,14 +47,12 @@ bool gjs_value_from_g_value(JSContext *context, const GValue *gvalue); GJS_USE -GClosure* gjs_closure_new_marshaled (JSContext *context, - JSObject *callable, - const char *description); +GClosure* gjs_closure_new_marshaled(JSContext* cx, JSFunction* callable, + const char* description); GJS_USE -GClosure* gjs_closure_new_for_signal (JSContext *context, - JSObject *callable, - const char *description, - guint signal_id); +GClosure* gjs_closure_new_for_signal(JSContext* cx, JSFunction* callable, + const char* description, + unsigned signal_id); G_END_DECLS diff --git a/gjs/jsapi-util-root.h b/gjs/jsapi-util-root.h index 299562bd..c81c4e55 100644 --- a/gjs/jsapi-util-root.h +++ b/gjs/jsapi-util-root.h @@ -87,8 +87,16 @@ struct GjsHeapOperation<JSObject *> { } }; -template<> -struct GjsHeapOperation<JS::Value> {}; +template <> +struct GjsHeapOperation<JSFunction*> { + static void expose_to_js(const JS::Heap<JSFunction*>& thing) { + JSFunction* func = thing.unbarrieredGet(); + if (!func || !js::gc::detail::GetGCThingZone(uintptr_t(func))) + return; + if (!JS::CurrentThreadIsHeapCollecting()) + js::gc::ExposeGCThingToActiveJS(JS::GCCellPtr(func)); + } +}; /* GjsMaybeOwned is intended only for use in heap allocation. Do not allocate it * on the stack, and do not allocate any instances of structures that have it as |