[gjs: 1/2] function: Remove JSClass macros
- From: Philip Chimento <pchimento src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs: 1/2] function: Remove JSClass macros
- Date: Sun, 31 Jan 2021 05:03:00 +0000 (UTC)
commit 8e51ae02eacf0879fb0168381c37ab6d896ee82b
Author: Philip Chimento <philip chimento gmail com>
Date: Mon Nov 30 21:41:46 2020 -0800
function: Remove JSClass macros
Port Function to use the CWrapper template, instead of the
GJS_DEFINE_PRIV_FROM_JS family of macros.
Includes Marco's work from "function: Make the object more C++ friendly"
(https://gitlab.gnome.org/GNOME/gjs/-/merge_requests/514)
Co-authored-by: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
gi/function.cpp | 469 +++++++++++++++++++++++++++++---------------------------
1 file changed, 239 insertions(+), 230 deletions(-)
---
diff --git a/gi/function.cpp b/gi/function.cpp
index 0a85d4d3..285eddc6 100644
--- a/gi/function.cpp
+++ b/gi/function.cpp
@@ -6,7 +6,6 @@
#include <stdint.h>
#include <stdlib.h> // for exit
-#include <string.h> // for memset
#include <memory> // for unique_ptr
#include <string>
@@ -32,18 +31,20 @@
#include <js/ValueArray.h>
#include <js/Warnings.h>
#include <jsapi.h> // for HandleValueArray, JS_GetElement
+#include <jspubtd.h> // for JSProtoKey
#include "gi/arg-cache.h"
#include "gi/arg-inl.h"
#include "gi/arg.h"
#include "gi/closure.h"
+#include "gi/cwrapper.h"
#include "gi/function.h"
#include "gi/gerror.h"
#include "gi/object.h"
#include "gi/utils-inl.h"
#include "gjs/context-private.h"
#include "gjs/context.h"
-#include "gjs/jsapi-class.h"
+#include "gjs/global.h"
#include "gjs/jsapi-util.h"
#include "gjs/mem-private.h"
#include "util/log.h"
@@ -53,17 +54,116 @@
*/
#define GJS_ARG_INDEX_INVALID G_MAXUINT8
-typedef struct {
- GICallableInfo* info;
+class Function : public CWrapper<Function> {
+ friend CWrapperPointerOps<Function>;
+ friend CWrapper<Function>;
- GjsArgumentCache* arguments;
+ static constexpr auto PROTOTYPE_SLOT = GjsGlobalSlot::PROTOTYPE_function;
+ static constexpr GjsDebugTopic DEBUG_TOPIC = GJS_DEBUG_GFUNCTION;
- uint8_t js_in_argc;
- guint8 js_out_argc;
- GIFunctionInvoker invoker;
-} Function;
+ GjsAutoCallableInfo m_info;
-extern struct JSClass gjs_function_class;
+ GjsArgumentCache* m_arguments;
+
+ uint8_t m_js_in_argc;
+ uint8_t m_js_out_argc;
+ GIFunctionInvoker m_invoker;
+
+ explicit Function(GICallableInfo* info)
+ : m_info(info, GjsAutoTakeOwnership()),
+ m_arguments(nullptr),
+ m_js_in_argc(0),
+ m_js_out_argc(0),
+ m_invoker({}) {
+ GJS_INC_COUNTER(function);
+ }
+ ~Function();
+
+ GJS_JSAPI_RETURN_CONVENTION
+ bool init(JSContext* cx, GType gtype = G_TYPE_NONE);
+
+ /**
+ * Like CWrapperPointerOps::for_js_typecheck(), but additionally checks that
+ * the pointer is not null, which is the case for prototype objects.
+ */
+ GJS_JSAPI_RETURN_CONVENTION
+ static bool for_js_instance(JSContext* cx, JS::HandleObject obj,
+ Function** out, JS::CallArgs* args) {
+ Function* priv;
+ if (!Function::for_js_typecheck(cx, obj, &priv, args))
+ return false;
+ if (!priv) {
+ // This is the prototype
+ gjs_throw(cx, "Impossible on prototype; only on instances");
+ return false;
+ }
+ *out = priv;
+ return true;
+ }
+
+ GJS_JSAPI_RETURN_CONVENTION
+ static bool call(JSContext* cx, unsigned argc, JS::Value* vp);
+
+ static void finalize_impl(JSFreeOp*, Function* priv);
+
+ GJS_JSAPI_RETURN_CONVENTION
+ static bool get_length(JSContext* cx, unsigned argc, JS::Value* vp);
+
+ GJS_JSAPI_RETURN_CONVENTION
+ static bool to_string(JSContext* cx, unsigned argc, JS::Value* vp);
+
+ GJS_JSAPI_RETURN_CONVENTION
+ bool to_string_impl(JSContext* cx, JS::MutableHandleValue rval);
+
+ GJS_JSAPI_RETURN_CONVENTION
+ static JSObject* inherit_builtin_function(JSContext* cx, JSProtoKey) {
+ JS::RootedObject builtin_function_proto(
+ cx, JS::GetRealmFunctionPrototype(cx));
+ return JS_NewObjectWithGivenProto(cx, &Function::klass,
+ builtin_function_proto);
+ }
+
+ static const JSClassOps class_ops;
+ static const JSPropertySpec proto_props[];
+ static const JSFunctionSpec proto_funcs[];
+
+ static constexpr js::ClassSpec class_spec = {
+ nullptr, // createConstructor
+ &Function::inherit_builtin_function,
+ nullptr, // constructorFunctions
+ nullptr, // constructorProperties
+ Function::proto_funcs,
+ Function::proto_props,
+ nullptr, // finishInit
+ js::ClassSpec::DontDefineConstructor};
+
+ static constexpr JSClass klass = {
+ "GIRepositoryFunction",
+ JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE, &Function::class_ops,
+ &Function::class_spec};
+
+ public:
+ GJS_JSAPI_RETURN_CONVENTION
+ static JSObject* create(JSContext* cx, GType gtype, GICallableInfo* info);
+
+ [[nodiscard]] char* format_name();
+
+ GJS_JSAPI_RETURN_CONVENTION
+ bool invoke(JSContext* cx, const JS::CallArgs& args,
+ JS::HandleObject this_obj = nullptr,
+ GIArgument* r_value = nullptr);
+
+ GJS_JSAPI_RETURN_CONVENTION
+ static bool invoke_constructor_uncached(JSContext* cx, GIFunctionInfo* info,
+ JS::HandleObject obj,
+ const JS::CallArgs& args,
+ GIArgument* rvalue) {
+ Function function(info);
+ if (!function.init(cx))
+ return false;
+ return function.invoke(cx, args, obj, rvalue);
+ }
+};
/* Because we can't free the mmap'd data for a callback
* while it's in use, this list keeps track of ones that
@@ -71,8 +171,6 @@ extern struct JSClass gjs_function_class;
*/
static std::vector<GjsAutoCallbackTrampoline> completed_trampolines;
-GJS_DEFINE_PRIV_FROM_JS(Function, gjs_function_class)
-
GjsCallbackTrampoline* gjs_callback_trampoline_ref(
GjsCallbackTrampoline* trampoline) {
g_atomic_ref_count_inc(&trampoline->ref_count);
@@ -639,15 +737,13 @@ bool GjsCallbackTrampoline::initialize(JSContext* cx,
}
/* Intended for error messages. Return value must be freed */
-[[nodiscard]] static char* format_function_name(Function* function) {
- if (g_callable_info_is_method(function->info))
+char* Function::format_name() {
+ if (g_callable_info_is_method(m_info))
return g_strdup_printf(
- "method %s.%s.%s", g_base_info_get_namespace(function->info),
- g_base_info_get_name(g_base_info_get_container(function->info)),
- g_base_info_get_name(function->info));
- return g_strdup_printf("function %s.%s",
- g_base_info_get_namespace(function->info),
- g_base_info_get_name(function->info));
+ "method %s.%s.%s", m_info.ns(),
+ g_base_info_get_name(g_base_info_get_container(m_info)),
+ m_info.name());
+ return g_strdup_printf("function %s.%s", m_info.ns(), m_info.name());
}
void gjs_function_clear_async_closures() { completed_trampolines.clear(); }
@@ -701,55 +797,49 @@ static void* get_return_ffi_pointer_from_giargument(
// create JavaScript objects by calling it without @r_value, or you can decide
// to keep the return values in #GArgument format by providing a @r_value
// argument.
-GJS_JSAPI_RETURN_CONVENTION
-static bool gjs_invoke_c_function(JSContext* context, Function* function,
- const JS::CallArgs& args,
- JS::HandleObject this_obj = nullptr,
- GIArgument* r_value = nullptr) {
+bool Function::invoke(JSContext* context, const JS::CallArgs& args,
+ JS::HandleObject this_obj /* = nullptr */,
+ GIArgument* r_value /* = nullptr */) {
g_assert((args.isConstructing() || !this_obj) &&
"If not a constructor, then pass the 'this' object via CallArgs");
void* return_value_p; // will point inside the return GIArgument union
GIFFIReturnValue return_value;
- int gi_argc, gi_arg_pos;
- bool can_throw_gerror;
+ int gi_arg_pos;
bool did_throw_gerror = false;
GError *local_error = NULL;
bool failed, postinvoke_release_failed;
-
- bool is_method;
JS::RootedValueVector return_values(context);
- is_method = g_callable_info_is_method(function->info);
- can_throw_gerror = g_callable_info_can_throw_gerror(function->info);
+ bool is_method = g_callable_info_is_method(m_info);
+ bool can_throw_gerror = g_callable_info_can_throw_gerror(m_info);
- unsigned ffi_argc = function->invoker.cif.nargs;
- gi_argc = g_callable_info_get_n_args( (GICallableInfo*) function->info);
+ unsigned ffi_argc = m_invoker.cif.nargs;
+ int gi_argc = g_callable_info_get_n_args(m_info);
if (gi_argc > GjsArgumentCache::MAX_ARGS) {
- GjsAutoChar name = format_function_name(function);
+ GjsAutoChar name = format_name();
gjs_throw(context, "Function %s has too many arguments", name.get());
return false;
}
// ffi_argc is the number of arguments that the underlying C function takes.
// gi_argc is the number of arguments the GICallableInfo describes (which
- // does not include "this" or GError**). function->js_in_argc is the number
+ // does not include "this" or GError**). m_js_in_argc is the number
// of arguments we expect the JS function to take (which does not include
// PARAM_SKIPPED args).
// args.length() is the number of arguments that were actually passed.
- if (args.length() > function->js_in_argc) {
- GjsAutoChar name = format_function_name(function);
+ if (args.length() > m_js_in_argc) {
+ GjsAutoChar name = format_name();
if (!JS::WarnUTF8(context,
"Too many arguments to %s: expected %u, got %u",
- name.get(), function->js_in_argc, args.length()))
+ name.get(), m_js_in_argc, args.length()))
return false;
- } else if (args.length() < function->js_in_argc) {
- GjsAutoChar name = format_function_name(function);
+ } else if (args.length() < m_js_in_argc) {
+ GjsAutoChar name = format_name();
- args.reportMoreArgsNeeded(context, name, function->js_in_argc,
- args.length());
+ args.reportMoreArgsNeeded(context, name, m_js_in_argc, args.length());
return false;
}
@@ -776,7 +866,7 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
//
// Use gi_arg_pos to index inside the GIArgument array. Use ffi_arg_pos to
// index inside ffi_arg_pointers.
- GjsFunctionCallState state(context, function->info, gi_argc);
+ GjsFunctionCallState state(context, m_info, gi_argc);
auto ffi_arg_pointers = std::make_unique<void*[]>(ffi_argc);
@@ -789,7 +879,7 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
return false;
if (is_method) {
- GjsArgumentCache* cache = &function->arguments[-2];
+ GjsArgumentCache* cache = &m_arguments[-2];
GIArgument* in_value = &state.in_cvalues[-2];
JS::RootedValue in_js_value(context, JS::ObjectValue(*obj));
@@ -809,7 +899,7 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
unsigned processed_c_args = ffi_arg_pos;
for (gi_arg_pos = 0; gi_arg_pos < gi_argc; gi_arg_pos++, ffi_arg_pos++) {
- GjsArgumentCache* cache = &function->arguments[gi_arg_pos];
+ GjsArgumentCache* cache = &m_arguments[gi_arg_pos];
GIArgument* in_value = &state.in_cvalues[gi_arg_pos];
gjs_debug_marshal(GJS_DEBUG_GFUNCTION,
@@ -826,8 +916,7 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
"to pass to the '%s' argument. It may be that the "
"function is unsupported, or there may be a bug in "
"its annotations.",
- g_base_info_get_namespace(function->info),
- g_base_info_get_name(function->info), cache->arg_name);
+ m_info.ns(), m_info.name(), cache->arg_name);
failed = true;
break;
}
@@ -870,10 +959,10 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
g_assert_cmpuint(ffi_arg_pos, ==, ffi_argc);
g_assert_cmpuint(gi_arg_pos, ==, gi_argc);
- return_value_p = get_return_ffi_pointer_from_giargument(
- &function->arguments[-1], &return_value);
- ffi_call(&(function->invoker.cif), FFI_FN(function->invoker.native_address),
- return_value_p, ffi_arg_pointers.get());
+ return_value_p =
+ get_return_ffi_pointer_from_giargument(&m_arguments[-1], &return_value);
+ ffi_call(&m_invoker.cif, FFI_FN(m_invoker.native_address), return_value_p,
+ ffi_arg_pointers.get());
/* Return value and out arguments are valid only if invocation doesn't
* return error. In arguments need to be released always.
@@ -887,17 +976,16 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
if (!r_value)
args.rval().setUndefined();
- if (!function->arguments[-1].skip_out()) {
+ if (!m_arguments[-1].skip_out()) {
gi_type_info_extract_ffi_return_value(
- &function->arguments[-1].type_info, &return_value,
- &state.out_cvalues[-1]);
+ &m_arguments[-1].type_info, &return_value, &state.out_cvalues[-1]);
}
// Process out arguments and return values. This loop is skipped if we fail
// the type conversion above, or if did_throw_gerror is true.
js_arg_pos = 0;
for (gi_arg_pos = -1; gi_arg_pos < gi_argc; gi_arg_pos++) {
- GjsArgumentCache* cache = &function->arguments[gi_arg_pos];
+ GjsArgumentCache* cache = &m_arguments[gi_arg_pos];
GIArgument* out_value = &state.out_cvalues[gi_arg_pos];
gjs_debug_marshal(GJS_DEBUG_GFUNCTION,
@@ -925,7 +1013,7 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
}
}
- g_assert(failed || did_throw_gerror || js_arg_pos == function->js_out_argc);
+ g_assert(failed || did_throw_gerror || js_arg_pos == m_js_out_argc);
release:
// If we failed before calling the function, or if the function threw an
@@ -946,7 +1034,7 @@ release:
for (gi_arg_pos = is_method ? -2 : -1;
gi_arg_pos < gi_argc && ffi_arg_pos < ffi_arg_max;
gi_arg_pos++, ffi_arg_pos++) {
- GjsArgumentCache* cache = &function->arguments[gi_arg_pos];
+ GjsArgumentCache* cache = &m_arguments[gi_arg_pos];
GIArgument* in_value = &state.in_cvalues[gi_arg_pos];
GIArgument* out_value = &state.out_cvalues[gi_arg_pos];
@@ -978,12 +1066,11 @@ release:
g_assert(ffi_arg_pos == processed_c_args + (is_method ? 2 : 1));
- if (!r_value && function->js_out_argc > 0 &&
- (!failed && !did_throw_gerror)) {
+ if (!r_value && m_js_out_argc > 0 && (!failed && !did_throw_gerror)) {
// If we have one return value or out arg, return that item on its
// own, otherwise return a JavaScript array with [return value,
// out arg 1, out arg 2, ...]
- if (function->js_out_argc == 1) {
+ if (m_js_out_argc == 1) {
args.rval().set(return_values[0]);
} else {
JSObject* array = JS::NewArrayObject(context, return_values);
@@ -1004,98 +1091,68 @@ release:
}
}
-GJS_JSAPI_RETURN_CONVENTION
-static bool
-function_call(JSContext *context,
- unsigned js_argc,
- JS::Value *vp)
-{
+bool Function::call(JSContext* context, unsigned js_argc, JS::Value* vp) {
JS::CallArgs js_argv = JS::CallArgsFromVp(js_argc, vp);
JS::RootedObject callee(context, &js_argv.callee());
Function *priv;
+ if (!Function::for_js_typecheck(context, callee, &priv, &js_argv))
+ return false;
- priv = priv_from_js(context, callee);
gjs_debug_marshal(GJS_DEBUG_GFUNCTION, "Call callee %p priv %p",
callee.get(), priv);
if (priv == NULL)
- return true; /* we are the prototype, or have the wrong class */
+ return true; // we are the prototype
- return gjs_invoke_c_function(context, priv, js_argv);
+ return priv->invoke(context, js_argv);
}
-GJS_NATIVE_CONSTRUCTOR_DEFINE_ABSTRACT(function)
+Function::~Function() {
+ if (m_arguments) {
+ g_assert(m_info && "Don't know how to free cache without GI info");
-/* Does not actually free storage for structure, just
- * reverses init_cached_function_data
- */
-static void
-uninit_cached_function_data (Function *function)
-{
- if (function->arguments) {
- g_assert(function->info &&
- "Don't know how to free cache without GI info");
-
- // Careful! function->arguments is offset by one or two elements inside
+ // Careful! m_arguments is offset by one or two elements inside
// the allocated space, so we have to free index -1 or -2.
- int start_index = g_callable_info_is_method(function->info) ? -2 : -1;
- int gi_argc = MIN(g_callable_info_get_n_args(function->info),
- function->js_in_argc + function->js_out_argc);
+ int start_index = g_callable_info_is_method(m_info) ? -2 : -1;
+ int gi_argc = MIN(g_callable_info_get_n_args(m_info),
+ m_js_in_argc + m_js_out_argc);
for (int i = 0; i < gi_argc; i++) {
int ix = start_index + i;
- if (!function->arguments[ix].marshallers)
+ if (!m_arguments[ix].marshallers)
break;
- if (function->arguments[ix].marshallers->free)
- function->arguments[ix].marshallers->free(
- &function->arguments[ix]);
+ if (m_arguments[ix].marshallers->free)
+ m_arguments[ix].marshallers->free(&m_arguments[ix]);
}
- g_free(&function->arguments[start_index]);
- function->arguments = nullptr;
+ g_free(&m_arguments[start_index]);
+ m_arguments = nullptr;
}
- g_clear_pointer(&function->info, g_base_info_unref);
- g_function_invoker_destroy(&function->invoker);
+ g_function_invoker_destroy(&m_invoker);
+ GJS_DEC_COUNTER(function);
}
-static void function_finalize(JSFreeOp*, JSObject* obj) {
- Function *priv;
-
- priv = (Function *) JS_GetPrivate(obj);
- gjs_debug_lifecycle(GJS_DEBUG_GFUNCTION,
- "finalize, obj %p priv %p", obj, priv);
+void Function::finalize_impl(JSFreeOp*, Function* priv) {
if (priv == NULL)
return; /* we are the prototype, not a real instance, so constructor never called */
-
- uninit_cached_function_data(priv);
-
- GJS_DEC_COUNTER(function);
- g_free(priv);
+ delete priv;
}
-GJS_JSAPI_RETURN_CONVENTION
-static bool
-get_num_arguments (JSContext *context,
- unsigned argc,
- JS::Value *vp)
-{
- GJS_GET_PRIV(context, argc, vp, rec, to, Function, priv);
- rec.rval().setInt32(priv->js_in_argc);
+bool Function::get_length(JSContext* cx, unsigned argc, JS::Value* vp) {
+ GJS_GET_THIS(cx, argc, vp, args, this_obj);
+ Function* priv;
+ if (!Function::for_js_instance(cx, this_obj, &priv, &args))
+ return false;
+ args.rval().setInt32(priv->m_js_in_argc);
return true;
}
-GJS_JSAPI_RETURN_CONVENTION
-static bool
-function_to_string (JSContext *context,
- guint argc,
- JS::Value *vp)
-{
- GJS_GET_PRIV(context, argc, vp, rec, to, Function, priv);
- int i, n_args, n_jsargs;
+bool Function::to_string(JSContext* context, unsigned argc, JS::Value* vp) {
+ GJS_CHECK_WRAPPER_PRIV(context, argc, vp, rec, this_obj, Function, priv);
if (priv == NULL) {
JSString* retval = JS_NewStringCopyZ(context, "function () {\n}");
@@ -1105,92 +1162,74 @@ function_to_string (JSContext *context,
return true;
}
- n_args = g_callable_info_get_n_args(priv->info);
+ return priv->to_string_impl(context, rec.rval());
+}
+
+bool Function::to_string_impl(JSContext* cx, JS::MutableHandleValue rval) {
+ int i, n_jsargs;
+
+ int n_args = g_callable_info_get_n_args(m_info);
n_jsargs = 0;
std::string arg_names;
for (i = 0; i < n_args; i++) {
- if (priv->arguments[i].skip_in())
+ if (m_arguments[i].skip_in())
continue;
if (n_jsargs > 0)
arg_names += ", ";
n_jsargs++;
- arg_names += priv->arguments[i].arg_name;
+ arg_names += m_arguments[i].arg_name;
}
GjsAutoChar descr;
- if (g_base_info_get_type(priv->info) == GI_INFO_TYPE_FUNCTION) {
+ if (g_base_info_get_type(m_info) == GI_INFO_TYPE_FUNCTION) {
descr = g_strdup_printf(
"function %s(%s) {\n\t/* wrapper for native symbol %s(); */\n}",
- g_base_info_get_name(priv->info), arg_names.c_str(),
- g_function_info_get_symbol(priv->info));
+ m_info.name(), arg_names.c_str(),
+ g_function_info_get_symbol(m_info));
} else {
descr = g_strdup_printf(
"function %s(%s) {\n\t/* wrapper for native symbol */\n}",
- g_base_info_get_name(priv->info), arg_names.c_str());
+ m_info.name(), arg_names.c_str());
}
- return gjs_string_from_utf8(context, descr, rec.rval());
+ return gjs_string_from_utf8(cx, descr, rval);
}
-/* The bizarre thing about this vtable is that it applies to both
- * instances of the object, and to the prototype that instances of the
- * class have.
- */
-static const struct JSClassOps gjs_function_class_ops = {
+const JSClassOps Function::class_ops = {
nullptr, // addProperty
nullptr, // deleteProperty
nullptr, // enumerate
nullptr, // newEnumerate
nullptr, // resolve
nullptr, // mayResolve
- function_finalize,
- function_call};
-
-struct JSClass gjs_function_class = {
- "GIRepositoryFunction", /* means "new GIRepositoryFunction()" works */
- JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
- &gjs_function_class_ops
+ &Function::finalize,
+ &Function::call,
};
-static JSPropertySpec gjs_function_proto_props[] = {
- JS_PSG("length", get_num_arguments, JSPROP_PERMANENT),
+const JSPropertySpec Function::proto_props[] = {
+ JS_PSG("length", &Function::get_length, JSPROP_PERMANENT),
JS_STRING_SYM_PS(toStringTag, "GIRepositoryFunction", JSPROP_READONLY),
JS_PS_END};
/* The original Function.prototype.toString complains when
given a GIRepository function as an argument */
-static JSFunctionSpec gjs_function_proto_funcs[] = {
- JS_FN("toString", function_to_string, 0, 0),
- JS_FS_END
-};
-
-static JSFunctionSpec *gjs_function_static_funcs = nullptr;
-
-GJS_JSAPI_RETURN_CONVENTION
-static bool
-init_cached_function_data (JSContext *context,
- Function *function,
- GType gtype,
- GICallableInfo *info)
-{
- guint8 i, n_args;
+// clang-format off
+const JSFunctionSpec Function::proto_funcs[] = {
+ JS_FN("toString", &Function::to_string, 0, 0),
+ JS_FS_END};
+// clang-format on
+
+bool Function::init(JSContext* context, GType gtype /* = G_TYPE_NONE */) {
+ guint8 i;
GError *error = NULL;
- GIInfoType info_type;
-
- info_type = g_base_info_get_type((GIBaseInfo *)info);
- if (info_type == GI_INFO_TYPE_FUNCTION) {
- if (!g_function_info_prep_invoker((GIFunctionInfo *)info,
- &(function->invoker),
- &error)) {
+ if (m_info.type() == GI_INFO_TYPE_FUNCTION) {
+ if (!g_function_info_prep_invoker(m_info, &m_invoker, &error))
return gjs_throw_gerror(context, error);
- }
- } else if (info_type == GI_INFO_TYPE_VFUNC) {
- gpointer addr;
-
- addr = g_vfunc_info_get_address((GIVFuncInfo *)info, gtype, &error);
+ } else if (m_info.type() == GI_INFO_TYPE_VFUNC) {
+ void* addr = g_vfunc_info_get_address(m_info, gtype, &error);
if (error != NULL) {
if (error->code != G_INVOKE_ERROR_SYMBOL_NOT_FOUND)
return gjs_throw_gerror(context, error);
@@ -1201,63 +1240,57 @@ init_cached_function_data (JSContext *context,
return false;
}
- if (!g_function_invoker_new_for_address(addr, info,
- &(function->invoker),
- &error)) {
+ if (!g_function_invoker_new_for_address(addr, m_info, &m_invoker,
+ &error))
return gjs_throw_gerror(context, error);
- }
}
- bool is_method = g_callable_info_is_method(info);
- n_args = g_callable_info_get_n_args((GICallableInfo*) info);
+ bool is_method = g_callable_info_is_method(m_info);
+ uint8_t n_args = g_callable_info_get_n_args(m_info);
// arguments is one or two inside an array of n_args + 2, so
// arguments[-1] is the return value (which can be skipped if void)
// arguments[-2] is the instance parameter
size_t offset = is_method ? 2 : 1;
- GjsArgumentCache* arguments =
- g_new0(GjsArgumentCache, n_args + offset) + offset;
-
- function->arguments = arguments;
- function->info = g_base_info_ref(info);
- function->js_in_argc = 0;
- function->js_out_argc = 0;
+ m_arguments = g_new0(GjsArgumentCache, n_args + offset) + offset;
if (is_method &&
- !gjs_arg_cache_build_instance(context, &arguments[-2], info))
+ !gjs_arg_cache_build_instance(context, &m_arguments[-2], m_info))
return false;
bool inc_counter;
- if (!gjs_arg_cache_build_return(context, &arguments[-1], arguments, info,
- &inc_counter))
+ if (!gjs_arg_cache_build_return(context, &m_arguments[-1], m_arguments,
+ m_info, &inc_counter))
return false;
- function->js_out_argc = inc_counter ? 1 : 0;
+ if (inc_counter)
+ m_js_out_argc++;
for (i = 0; i < n_args; i++) {
GIDirection direction;
GIArgInfo arg_info;
- if (arguments[i].skip_in() || arguments[i].skip_out())
+ if (m_arguments[i].skip_in() || m_arguments[i].skip_out())
continue;
- g_callable_info_load_arg((GICallableInfo*) info, i, &arg_info);
+ g_callable_info_load_arg(m_info, i, &arg_info);
direction = g_arg_info_get_direction(&arg_info);
- if (!gjs_arg_cache_build_arg(context, &arguments[i], arguments, i,
- direction, &arg_info, info, &inc_counter))
+ if (!gjs_arg_cache_build_arg(context, &m_arguments[i], m_arguments, i,
+ direction, &arg_info, m_info,
+ &inc_counter))
return false;
if (inc_counter) {
switch (direction) {
case GI_DIRECTION_INOUT:
- function->js_out_argc++;
+ m_js_out_argc++;
[[fallthrough]];
case GI_DIRECTION_IN:
- function->js_in_argc++;
+ m_js_in_argc++;
break;
case GI_DIRECTION_OUT:
- function->js_out_argc++;
+ m_js_out_argc++;
break;
default:
g_assert_not_reached();
@@ -1268,45 +1301,28 @@ init_cached_function_data (JSContext *context,
return true;
}
-[[nodiscard]] static inline JSObject* gjs_builtin_function_get_proto(
- JSContext* cx) {
- return JS::GetRealmFunctionPrototype(cx);
-}
-
-GJS_DEFINE_PROTO_FUNCS_WITH_PARENT(function, builtin_function)
-
-GJS_JSAPI_RETURN_CONVENTION
-static JSObject*
-function_new(JSContext *context,
- GType gtype,
- GICallableInfo *info)
-{
- Function *priv;
-
- JS::RootedObject proto(context);
- if (!gjs_function_define_proto(context, nullptr, &proto))
+JSObject* Function::create(JSContext* context, GType gtype,
+ GICallableInfo* info) {
+ JS::RootedObject proto(context, Function::create_prototype(context));
+ if (!proto)
return nullptr;
- JS::RootedObject function(context,
- JS_NewObjectWithGivenProto(context, &gjs_function_class, proto));
+ JS::RootedObject function(
+ context, JS_NewObjectWithGivenProto(context, &Function::klass, proto));
if (!function) {
gjs_debug(GJS_DEBUG_GFUNCTION, "Failed to construct function");
return NULL;
}
- priv = g_new0(Function, 1);
-
- GJS_INC_COUNTER(function);
+ auto* priv = new Function(info);
- g_assert(priv_from_js(context, function) == NULL);
+ g_assert(!JS_GetPrivate(function) && "Function should be a fresh object");
JS_SetPrivate(function, priv);
- gjs_debug_lifecycle(GJS_DEBUG_GFUNCTION,
- "function constructor, obj %p priv %p", function.get(),
- priv);
+ debug_lifecycle(function, priv, "Constructor");
- if (!init_cached_function_data(context, priv, gtype, (GICallableInfo *)info))
- return NULL;
+ if (!priv->init(context, gtype))
+ return nullptr;
return function;
}
@@ -1324,7 +1340,7 @@ gjs_define_function(JSContext *context,
info_type = g_base_info_get_type((GIBaseInfo *)info);
- JS::RootedObject function(context, function_new(context, gtype, info));
+ JS::RootedObject function(context, Function::create(context, gtype, info));
if (!function)
return NULL;
@@ -1354,13 +1370,6 @@ bool gjs_invoke_constructor_from_c(JSContext* context, GIFunctionInfo* info,
JS::HandleObject obj,
const JS::CallArgs& args,
GIArgument* rvalue) {
- Function function;
-
- memset(&function, 0, sizeof(Function));
- if (!init_cached_function_data(context, &function, 0, info))
- return false;
-
- bool result = gjs_invoke_c_function(context, &function, args, obj, rvalue);
- uninit_cached_function_data(&function);
- return result;
+ return Function::invoke_constructor_uncached(context, info, obj, args,
+ rvalue);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]