Commit adfb7dc3 authored by Philip Chimento's avatar Philip Chimento 🚮

arg-cache: Save space by not caching GType

The GType is fetchable from the GIRegisteredTypeInfo, and it is the only
member keeping the GjsArgumentCache struct from being smaller. However,
this is a bit of a tradeoff since g_registered_type_info_get_g_type()
involves a call to g_module_symbol().

Hopefully this doesn't have much of an effect on performance, compared
to the net benefit of introducing the argument cache in the first place,
since g_registered_type_info_get_type() is also used in the "old way" of
marshalling values in arg.cpp.
parent 8b2927b0
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <ffi.h> #include <ffi.h>
#include <girepository.h> #include <girepository.h>
#include <glib-object.h>
#include <glib.h> #include <glib.h>
#include <js/Conversions.h> #include <js/Conversions.h>
...@@ -600,7 +601,7 @@ static bool gjs_marshal_boxed_in_in(JSContext* cx, GjsArgumentCache* self, ...@@ -600,7 +601,7 @@ static bool gjs_marshal_boxed_in_in(JSContext* cx, GjsArgumentCache* self,
if (value.isNull()) if (value.isNull())
return self->handle_nullable(cx, arg); return self->handle_nullable(cx, arg);
GType gtype = self->contents.object.gtype; GType gtype = g_registered_type_info_get_g_type(self->contents.info);
if (!value.isObject()) if (!value.isObject())
return report_gtype_mismatch(cx, self->arg_name, value, gtype); return report_gtype_mismatch(cx, self->arg_name, value, gtype);
...@@ -613,7 +614,7 @@ static bool gjs_marshal_boxed_in_in(JSContext* cx, GjsArgumentCache* self, ...@@ -613,7 +614,7 @@ static bool gjs_marshal_boxed_in_in(JSContext* cx, GjsArgumentCache* self,
return BoxedBase::transfer_to_gi_argument(cx, object, arg, GI_DIRECTION_IN, return BoxedBase::transfer_to_gi_argument(cx, object, arg, GI_DIRECTION_IN,
self->transfer, gtype, self->transfer, gtype,
self->contents.object.info); self->contents.info);
} }
// Unions include ClutterEvent and GdkEvent, which occur fairly often in an // Unions include ClutterEvent and GdkEvent, which occur fairly often in an
...@@ -626,7 +627,7 @@ static bool gjs_marshal_union_in_in(JSContext* cx, GjsArgumentCache* self, ...@@ -626,7 +627,7 @@ static bool gjs_marshal_union_in_in(JSContext* cx, GjsArgumentCache* self,
if (value.isNull()) if (value.isNull())
return self->handle_nullable(cx, arg); return self->handle_nullable(cx, arg);
GType gtype = self->contents.object.gtype; GType gtype = g_registered_type_info_get_g_type(self->contents.info);
g_assert(gtype != G_TYPE_NONE); g_assert(gtype != G_TYPE_NONE);
if (!value.isObject()) if (!value.isObject())
...@@ -635,7 +636,7 @@ static bool gjs_marshal_union_in_in(JSContext* cx, GjsArgumentCache* self, ...@@ -635,7 +636,7 @@ static bool gjs_marshal_union_in_in(JSContext* cx, GjsArgumentCache* self,
JS::RootedObject object(cx, &value.toObject()); JS::RootedObject object(cx, &value.toObject());
return UnionBase::transfer_to_gi_argument(cx, object, arg, GI_DIRECTION_IN, return UnionBase::transfer_to_gi_argument(cx, object, arg, GI_DIRECTION_IN,
self->transfer, gtype, self->transfer, gtype,
self->contents.object.info); self->contents.info);
} }
GJS_JSAPI_RETURN_CONVENTION GJS_JSAPI_RETURN_CONVENTION
...@@ -678,7 +679,7 @@ static bool gjs_marshal_gbytes_in_in(JSContext* cx, GjsArgumentCache* self, ...@@ -678,7 +679,7 @@ static bool gjs_marshal_gbytes_in_in(JSContext* cx, GjsArgumentCache* self,
// ownership, so we need to do the same here. // ownership, so we need to do the same here.
return BoxedBase::transfer_to_gi_argument( return BoxedBase::transfer_to_gi_argument(
cx, object, arg, GI_DIRECTION_IN, GI_TRANSFER_EVERYTHING, G_TYPE_BYTES, cx, object, arg, GI_DIRECTION_IN, GI_TRANSFER_EVERYTHING, G_TYPE_BYTES,
self->contents.object.info); self->contents.info);
} }
GJS_JSAPI_RETURN_CONVENTION GJS_JSAPI_RETURN_CONVENTION
...@@ -688,7 +689,7 @@ static bool gjs_marshal_object_in_in(JSContext* cx, GjsArgumentCache* self, ...@@ -688,7 +689,7 @@ static bool gjs_marshal_object_in_in(JSContext* cx, GjsArgumentCache* self,
if (value.isNull()) if (value.isNull())
return self->handle_nullable(cx, arg); return self->handle_nullable(cx, arg);
GType gtype = self->contents.object.gtype; GType gtype = g_registered_type_info_get_g_type(self->contents.info);
g_assert(gtype != G_TYPE_NONE); g_assert(gtype != G_TYPE_NONE);
if (!value.isObject()) if (!value.isObject())
...@@ -945,7 +946,7 @@ static bool gjs_marshal_boxed_in_release(JSContext*, GjsArgumentCache* self, ...@@ -945,7 +946,7 @@ static bool gjs_marshal_boxed_in_release(JSContext*, GjsArgumentCache* self,
GjsFunctionCallState*, GjsFunctionCallState*,
GIArgument* in_arg, GIArgument* in_arg,
GIArgument* out_arg G_GNUC_UNUSED) { GIArgument* out_arg G_GNUC_UNUSED) {
GType gtype = self->contents.object.gtype; GType gtype = g_registered_type_info_get_g_type(self->contents.info);
g_assert(g_type_is_a(gtype, G_TYPE_BOXED)); g_assert(g_type_is_a(gtype, G_TYPE_BOXED));
if (!gjs_arg_get<void*>(in_arg)) if (!gjs_arg_get<void*>(in_arg))
...@@ -956,7 +957,7 @@ static bool gjs_marshal_boxed_in_release(JSContext*, GjsArgumentCache* self, ...@@ -956,7 +957,7 @@ static bool gjs_marshal_boxed_in_release(JSContext*, GjsArgumentCache* self,
} }
static void gjs_arg_cache_interface_free(GjsArgumentCache* self) { static void gjs_arg_cache_interface_free(GjsArgumentCache* self) {
g_clear_pointer(&self->contents.object.info, g_base_info_unref); g_clear_pointer(&self->contents.info, g_base_info_unref);
} }
static inline void gjs_arg_cache_set_skip_all(GjsArgumentCache* self) { static inline void gjs_arg_cache_set_skip_all(GjsArgumentCache* self) {
...@@ -1097,8 +1098,7 @@ static bool gjs_arg_cache_build_interface_in_arg(JSContext* cx, ...@@ -1097,8 +1098,7 @@ static bool gjs_arg_cache_build_interface_in_arg(JSContext* cx,
case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_INTERFACE:
case GI_INFO_TYPE_UNION: { case GI_INFO_TYPE_UNION: {
GType gtype = g_registered_type_info_get_g_type(interface_info); GType gtype = g_registered_type_info_get_g_type(interface_info);
self->contents.object.gtype = gtype; self->contents.info = g_base_info_ref(interface_info);
self->contents.object.info = g_base_info_ref(interface_info);
self->free = gjs_arg_cache_interface_free; self->free = gjs_arg_cache_interface_free;
// Transfer handling is a bit complex here, because some of our _in // Transfer handling is a bit complex here, because some of our _in
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include <stdint.h> #include <stdint.h>
#include <girepository.h> #include <girepository.h>
#include <glib-object.h>
#include <glib.h> // for g_assert #include <glib.h> // for g_assert
#include <js/RootingAPI.h> #include <js/RootingAPI.h>
...@@ -80,10 +79,7 @@ struct GjsArgumentCache { ...@@ -80,10 +79,7 @@ struct GjsArgumentCache {
} number; } number;
// boxed / union / GObject // boxed / union / GObject
struct { GIRegisteredTypeInfo* info;
GType gtype;
GIBaseInfo* info;
} object;
// foreign structures // foreign structures
GIStructInfo* tmp_foreign_info; GIStructInfo* tmp_foreign_info;
...@@ -161,7 +157,7 @@ struct GjsArgumentCache { ...@@ -161,7 +157,7 @@ struct GjsArgumentCache {
#if defined(__x86_64__) && defined(__clang__) #if defined(__x86_64__) && defined(__clang__)
// This isn't meant to be comprehensive, but should trip on at least one CI job // This isn't meant to be comprehensive, but should trip on at least one CI job
// if sizeof(GjsArgumentCache) is increased. */ // if sizeof(GjsArgumentCache) is increased. */
static_assert(sizeof(GjsArgumentCache) <= 136, static_assert(sizeof(GjsArgumentCache) <= 128,
"Think very hard before increasing the size of GjsArgumentCache. " "Think very hard before increasing the size of GjsArgumentCache. "
"One is allocated for every argument to every introspected " "One is allocated for every argument to every introspected "
"function."); "function.");
......
...@@ -792,9 +792,13 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function, ...@@ -792,9 +792,13 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
// Callback lifetimes will be attached to the instance object if it is // Callback lifetimes will be attached to the instance object if it is
// a GObject or GInterface // a GObject or GInterface
if (g_type_is_a(cache->contents.object.gtype, G_TYPE_OBJECT) || if (cache->contents.info) {
g_type_is_a(cache->contents.object.gtype, G_TYPE_INTERFACE)) GType gtype =
state.instance_object = obj; g_registered_type_info_get_g_type(cache->contents.info);
if (g_type_is_a(gtype, G_TYPE_OBJECT) ||
g_type_is_a(gtype, G_TYPE_INTERFACE))
state.instance_object = obj;
}
} }
unsigned processed_c_args = ffi_arg_pos; unsigned processed_c_args = ffi_arg_pos;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment