[gjs/burninate-macros: 7/13] function: Remove JSClass macros
- From: Philip Chimento <pchimento src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs/burninate-macros: 7/13] function: Remove JSClass macros
- Date: Wed, 3 Jun 2020 15:17:19 +0000 (UTC)
commit ccd933ac248d41ab63b8b85f05d861e7232acf40
Author: Philip Chimento <philip chimento gmail com>
Date: Sat May 2 18:32:42 2020 -0700
function: Remove JSClass macros
FIXME: Make this into a real class
FIXME: Don't know if can share with other classes, with the prototype==null stuff!
gi/function.cpp | 470 ++++++++++++++++++++++++-----------------------------
gi/function.h | 86 +++++++++-
gi/fundamental.cpp | 4 +-
gi/union.cpp | 4 +-
4 files changed, 297 insertions(+), 267 deletions(-)
---
diff --git a/gi/function.cpp b/gi/function.cpp
index 25bd62b7..12ac64bf 100644
--- a/gi/function.cpp
+++ b/gi/function.cpp
@@ -62,7 +62,6 @@
#include "gi/union.h"
#include "gjs/context-private.h"
#include "gjs/context.h"
-#include "gjs/jsapi-class.h"
#include "gjs/jsapi-util.h"
#include "gjs/mem-private.h"
#include "util/log.h"
@@ -72,17 +71,40 @@
*/
#define GJS_ARG_INDEX_INVALID G_MAXUINT8
-typedef struct {
- GICallableInfo* info;
-
- GjsParamType *param_types;
+static JSObject* builtin_function_proto(JSContext* cx, JSProtoKey) {
+ return JS::GetRealmFunctionPrototype(cx);
+}
- guint8 expected_js_argc;
- guint8 js_out_argc;
- GIFunctionInvoker invoker;
-} Function;
+const js::ClassSpec Function::class_spec = {
+ nullptr, // createConstructor
+ &builtin_function_proto,
+ nullptr, // constructorFunctions
+ nullptr, // constructorProperties
+ Function::proto_funcs,
+ Function::proto_props,
+ nullptr, // finishInit
+ js::ClassSpec::DontDefineConstructor};
+
+Function::Function(GICallableInfo* info)
+ : m_info(g_base_info_ref(info)),
+ m_param_types(nullptr),
+ m_expected_js_argc(0),
+ m_js_out_argc(0) {
+ GJS_INC_COUNTER(function);
+}
-extern struct JSClass gjs_function_class;
+Function* Function::for_js(JSContext* cx, JS::HandleObject obj,
+ JS::CallArgs& args) {
+ Function* priv;
+ if (!Function::for_js_typecheck(cx, obj, &priv, &args))
+ return nullptr;
+ if (!priv) {
+ // This is the prototype
+ gjs_throw(cx, "Impossible on prototype; only on instances");
+ return nullptr;
+ }
+ return priv;
+}
/* Because we can't free the mmap'd data for a callback
* while it's in use, this list keeps track of ones that
@@ -90,8 +112,6 @@ extern struct JSClass gjs_function_class;
*/
static GSList *completed_trampolines = NULL; /* GjsCallbackTrampoline */
-GJS_DEFINE_PRIV_FROM_JS(Function, gjs_function_class)
-
void
gjs_callback_trampoline_ref(GjsCallbackTrampoline *trampoline)
{
@@ -637,17 +657,13 @@ get_length_from_arg (GArgument *arg, GITypeTag tag)
}
GJS_JSAPI_RETURN_CONVENTION
-static bool
-gjs_fill_method_instance(JSContext *context,
- JS::HandleObject obj,
- Function *function,
- GIArgument *out_arg,
- bool& is_gobject)
-{
- GIBaseInfo *container = g_base_info_get_container((GIBaseInfo *) function->info);
+bool Function::fill_method_instance(JSContext* context, JS::HandleObject obj,
+ GIArgument* out_arg, bool& is_gobject) {
+ GIBaseInfo* container = g_base_info_get_container(m_info);
GIInfoType type = g_base_info_get_type(container);
GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *)container);
- GITransfer transfer = g_callable_info_get_instance_ownership_transfer (function->info);
+ GITransfer transfer =
+ g_callable_info_get_instance_ownership_transfer(m_info);
is_gobject = false;
@@ -741,16 +757,14 @@ gjs_fill_method_instance(JSContext *context,
}
/* Intended for error messages. Return value must be freed */
-GJS_USE
-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", g_base_info_get_namespace(m_info),
+ g_base_info_get_name(g_base_info_get_container(m_info)),
+ g_base_info_get_name(m_info));
+ return g_strdup_printf("function %s.%s", g_base_info_get_namespace(m_info),
+ g_base_info_get_name(m_info));
}
static void
@@ -771,10 +785,8 @@ complete_async_calls(void)
// 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, GIArgument* r_value) {
g_assert((args.isConstructing() || !this_obj) &&
"If not a constructor, then pass the 'this' object via CallArgs");
@@ -798,15 +810,13 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
GArgument return_gargument;
guint8 processed_c_args = 0;
- guint8 gi_argc, gi_arg_pos;
- guint8 c_argc, c_arg_pos;
+ uint8_t gi_arg_pos;
+ uint8_t c_arg_pos;
guint8 js_arg_pos;
- bool can_throw_gerror;
bool did_throw_gerror = false;
GError *local_error = NULL;
bool failed, postinvoke_release_failed;
- bool is_method;
bool is_object_method = false;
GITypeInfo return_info;
GITypeTag return_tag;
@@ -819,11 +829,11 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
*/
complete_async_calls();
- 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);
- c_argc = function->invoker.cif.nargs;
- gi_argc = g_callable_info_get_n_args( (GICallableInfo*) function->info);
+ uint8_t c_argc = m_invoker.cif.nargs;
+ uint8_t gi_argc = g_callable_info_get_n_args(m_info);
/* @c_argc is the number of arguments that the underlying C
* function takes. @gi_argc is the number of arguments the
@@ -834,18 +844,17 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
*
* @args.length() is the number of arguments that were actually passed.
*/
- GjsAutoChar name = format_function_name(function);
- if (args.length() > function->expected_js_argc) {
- if (!JS::WarnUTF8(
- context, "Too many arguments to %s: expected %d, got %u",
- name.get(), function->expected_js_argc, args.length()))
+ GjsAutoChar name = format_name();
+ if (args.length() > m_expected_js_argc) {
+ if (!JS::WarnUTF8(context,
+ "Too many arguments to %s: expected %d, got %u",
+ name.get(), m_expected_js_argc, args.length()))
return false;
- } else if (!args.requireAtLeast(context, name,
- function->expected_js_argc)) {
+ } else if (!args.requireAtLeast(context, name, m_expected_js_argc)) {
return false;
}
- g_callable_info_load_return_type( (GICallableInfo*) function->info, &return_info);
+ g_callable_info_load_return_type(m_info, &return_info);
return_tag = g_type_info_get_tag(&return_info);
in_arg_cvalues = g_newa(GArgument, c_argc);
@@ -862,8 +871,8 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
return false;
if (is_method) {
- if (!gjs_fill_method_instance(context, obj, function,
- &in_arg_cvalues[0], is_object_method))
+ if (!fill_method_instance(context, obj, &in_arg_cvalues[0],
+ is_object_method))
return false;
ffi_arg_pointers[0] = &in_arg_cvalues[0];
++c_arg_pos;
@@ -875,7 +884,7 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
GIArgInfo arg_info;
bool arg_removed = false;
- g_callable_info_load_arg( (GICallableInfo*) function->info, gi_arg_pos, &arg_info);
+ g_callable_info_load_arg(m_info, gi_arg_pos, &arg_info);
direction = g_arg_info_get_direction(&arg_info);
gjs_debug_marshal(
@@ -932,13 +941,12 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
} else {
GArgument *in_value;
GITypeInfo ainfo;
- GjsParamType param_type;
g_arg_info_load_type(&arg_info, &ainfo);
in_value = &in_arg_cvalues[c_arg_pos];
- param_type = function->param_types[gi_arg_pos];
+ GjsParamType param_type = m_param_types[gi_arg_pos];
switch (param_type) {
case PARAM_CALLBACK: {
@@ -953,10 +961,12 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
trampoline = NULL;
} else {
if (!(JS_TypeOfValue(context, current_arg) == JSTYPE_FUNCTION)) {
- gjs_throw(context, "Error invoking %s.%s: Expected function for callback argument
%s, got %s",
- g_base_info_get_namespace( (GIBaseInfo*) function->info),
- g_base_info_get_name( (GIBaseInfo*) function->info),
- g_base_info_get_name( (GIBaseInfo*) &arg_info),
+ gjs_throw(context,
+ "Error invoking %s.%s: Expected function for "
+ "callback argument %s, got %s",
+ g_base_info_get_namespace(m_info),
+ g_base_info_get_name(m_info),
+ g_base_info_get_name((GIBaseInfo*)&arg_info),
JS::InformalValueTypeName(current_arg));
failed = true;
break;
@@ -993,12 +1003,12 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
gint closure_pos = g_arg_info_get_closure(&arg_info);
if (destroy_pos >= 0) {
gint c_pos = is_method ? destroy_pos + 1 : destroy_pos;
- g_assert (function->param_types[destroy_pos] == PARAM_SKIPPED);
+ g_assert(m_param_types[destroy_pos] == PARAM_SKIPPED);
in_arg_cvalues[c_pos].v_pointer = trampoline ? (gpointer) gjs_destroy_notify_callback :
NULL;
}
if (closure_pos >= 0) {
gint c_pos = is_method ? closure_pos + 1 : closure_pos;
- g_assert (function->param_types[closure_pos] == PARAM_SKIPPED);
+ g_assert(m_param_types[closure_pos] == PARAM_SKIPPED);
in_arg_cvalues[c_pos].v_pointer = trampoline;
}
@@ -1025,7 +1035,8 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
break;
}
- g_callable_info_load_arg(function->info, array_length_pos, &array_length_arg);
+ g_callable_info_load_arg(m_info, array_length_pos,
+ &array_length_arg);
array_length_pos += is_method ? 1 : 0;
JS::RootedValue v_length(context, JS::Int32Value(length));
@@ -1067,8 +1078,8 @@ 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),
+ g_base_info_get_namespace(m_info),
+ g_base_info_get_name(m_info),
g_base_info_get_name(&arg_info));
failed = true;
break;
@@ -1126,7 +1137,8 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
return_value_p = &return_value.v_uint64;
else
return_value_p = &return_value.v_long;
- ffi_call(&(function->invoker.cif), FFI_FN(function->invoker.native_address), return_value_p,
ffi_arg_pointers);
+ ffi_call(&(m_invoker.cif), FFI_FN(m_invoker.native_address), return_value_p,
+ ffi_arg_pointers);
/* Return value and out arguments are valid only if invocation doesn't
* return error. In arguments need to be released always.
@@ -1141,16 +1153,16 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
args.rval().setUndefined();
/* Only process return values if the function didn't throw */
- if (function->js_out_argc > 0 && !did_throw_gerror) {
- if (!return_values.growBy(function->js_out_argc))
+ if (m_js_out_argc > 0 && !did_throw_gerror) {
+ if (!return_values.growBy(m_js_out_argc))
g_error("Unable to reserve space for vector");
if (return_tag != GI_TYPE_TAG_VOID) {
- GITransfer transfer = g_callable_info_get_caller_owns((GICallableInfo*) function->info);
+ GITransfer transfer = g_callable_info_get_caller_owns(m_info);
bool arg_failed = false;
gint array_length_pos;
- g_assert_cmpuint(next_rval, <, function->js_out_argc);
+ g_assert(next_rval < m_js_out_argc);
gi_type_info_extract_ffi_return_value(&return_info, &return_value, &return_gargument);
@@ -1160,7 +1172,8 @@ static bool gjs_invoke_c_function(JSContext* context, Function* function,
GITypeInfo arg_type_info;
JS::RootedValue length(context);
- g_callable_info_load_arg(function->info, array_length_pos, &array_length_arg);
+ g_callable_info_load_arg(m_info, array_length_pos,
+ &array_length_arg);
g_arg_info_load_type(&array_length_arg, &arg_type_info);
array_length_pos += is_method ? 1 : 0;
arg_failed = !gjs_value_from_g_argument(context, &length,
@@ -1209,13 +1222,12 @@ release:
GIDirection direction;
GIArgInfo arg_info;
GITypeInfo arg_type_info;
- GjsParamType param_type;
- g_callable_info_load_arg( (GICallableInfo*) function->info, gi_arg_pos, &arg_info);
+ g_callable_info_load_arg(m_info, gi_arg_pos, &arg_info);
direction = g_arg_info_get_direction(&arg_info);
g_arg_info_load_type(&arg_info, &arg_type_info);
- param_type = function->param_types[gi_arg_pos];
+ GjsParamType param_type = m_param_types[gi_arg_pos];
if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
GArgument *arg;
@@ -1266,7 +1278,8 @@ release:
g_assert(array_length_pos >= 0);
- g_callable_info_load_arg(function->info, array_length_pos, &array_length_arg);
+ g_callable_info_load_arg(m_info, array_length_pos,
+ &array_length_arg);
g_arg_info_load_type(&array_length_arg, &array_length_type);
array_length_pos += is_method ? 1 : 0;
@@ -1305,7 +1318,7 @@ release:
JS::RootedValue array_length(context, JS::Int32Value(0));
GITransfer transfer;
- g_assert(next_rval < function->js_out_argc);
+ g_assert(next_rval < m_js_out_argc);
arg = &out_arg_cvalues[c_arg_pos];
@@ -1316,7 +1329,8 @@ release:
GIArgInfo array_length_arg;
GITypeInfo array_length_type_info;
- g_callable_info_load_arg(function->info, array_length_pos, &array_length_arg);
+ g_callable_info_load_arg(m_info, array_length_pos,
+ &array_length_arg);
g_arg_info_load_type(&array_length_arg, &array_length_type_info);
array_length_pos += is_method ? 1 : 0;
arg_failed = !gjs_value_from_g_argument(context, &array_length,
@@ -1395,17 +1409,17 @@ release:
if (postinvoke_release_failed)
failed = true;
- g_assert(failed || did_throw_gerror || next_rval == (guint8)function->js_out_argc);
+ g_assert(failed || did_throw_gerror || next_rval == m_js_out_argc);
g_assert_cmpuint(c_arg_pos, ==, processed_c_args);
- if (function->js_out_argc > 0 && (!failed && !did_throw_gerror)) {
+ if (m_js_out_argc > 0 && (!failed && !did_throw_gerror)) {
if (r_value) {
*r_value = return_gargument;
} else {
// 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;
@@ -1428,79 +1442,57 @@ 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;
- Function *priv;
-
- 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)
-
-/* Does not actually free storage for structure, just
- * reverses init_cached_function_data
- */
-static void
-uninit_cached_function_data (Function *function)
-{
- if (function->info)
- g_base_info_unref( (GIBaseInfo*) function->info);
- if (function->param_types)
- g_free(function->param_types);
-
- g_function_invoker_destroy(&function->invoker);
+Function::~Function() {
+ g_clear_pointer(&m_info, g_base_info_unref);
+ g_clear_pointer(&m_param_types, g_free);
+ 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);
+ priv->~Function();
g_slice_free(Function, 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);
- int n_args, n_jsargs, i;
-
+bool Function::get_length(JSContext* cx, unsigned argc, JS::Value* vp) {
+ GJS_GET_THIS(cx, argc, vp, args, this_obj);
+ Function* priv = Function::for_js(cx, this_obj, args);
if (priv == NULL)
return false;
- n_args = g_callable_info_get_n_args(priv->info);
- n_jsargs = 0;
- for (i = 0; i < n_args; i++) {
+ args.rval().setInt32(priv->get_length_impl());
+ return true;
+}
+
+int32_t Function::get_length_impl() {
+ int n_args = g_callable_info_get_n_args(m_info);
+ int n_jsargs = 0;
+ for (int i = 0; i < n_args; i++) {
GIArgInfo arg_info;
- if (priv->param_types[i] == PARAM_SKIPPED)
+ if (m_param_types[i] == PARAM_SKIPPED)
continue;
- g_callable_info_load_arg(priv->info, i, &arg_info);
+ g_callable_info_load_arg(m_info, i, &arg_info);
if (g_arg_info_get_direction(&arg_info) == GI_DIRECTION_OUT)
continue;
@@ -1508,21 +1500,14 @@ get_num_arguments (JSContext *context,
n_jsargs++;
}
- rec.rval().setInt32(n_jsargs);
- return true;
+ return n_jsargs;
}
-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;
- GString *arg_names_str;
- gchar *arg_names;
-
+bool Function::to_string(JSContext* context, guint argc, JS::Value* vp) {
+ GJS_GET_THIS(context, argc, vp, rec, this_obj);
+ Function* priv;
+ if (!Function::for_js_typecheck(context, this_obj, &priv, &rec))
+ return false;
if (priv == NULL) {
JSString* retval = JS_NewStringCopyZ(context, "function () {\n}");
if (!retval)
@@ -1531,16 +1516,20 @@ function_to_string (JSContext *context,
return true;
}
- n_args = g_callable_info_get_n_args(priv->info);
- n_jsargs = 0;
- arg_names_str = g_string_new("");
- for (i = 0; i < n_args; i++) {
+ return priv->to_string_impl(context, rec);
+}
+
+bool Function::to_string_impl(JSContext* cx, const JS::CallArgs& args) {
+ int n_args = g_callable_info_get_n_args(m_info);
+ int n_jsargs = 0;
+ GString* arg_names_str = g_string_new("");
+ for (int i = 0; i < n_args; i++) {
GIArgInfo arg_info;
- if (priv->param_types[i] == PARAM_SKIPPED)
+ if (m_param_types[i] == PARAM_SKIPPED)
continue;
- g_callable_info_load_arg(priv->info, i, &arg_info);
+ g_callable_info_load_arg(m_info, i, &arg_info);
if (g_arg_info_get_direction(&arg_info) == GI_DIRECTION_OUT)
continue;
@@ -1551,84 +1540,69 @@ function_to_string (JSContext *context,
n_jsargs++;
g_string_append(arg_names_str, g_base_info_get_name(&arg_info));
}
- arg_names = g_string_free(arg_names_str, false);
+ GjsAutoChar arg_names = g_string_free(arg_names_str, false);
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,
- g_function_info_get_symbol(priv->info));
+ g_base_info_get_name(m_info), arg_names.get(),
+ 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);
+ g_base_info_get_name(m_info), arg_names.get());
}
- g_free(arg_names);
-
- return gjs_string_from_utf8(context, descr, rec.rval());
+ return gjs_string_from_utf8(cx, descr, args.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};
+ &Function::finalize,
+ &Function::call,
+};
-struct JSClass gjs_function_class = {
- "GIRepositoryFunction", /* means "new GIRepositoryFunction()" works */
+// clang-format off
+const JSClass Function::klass = {
+ "GIRepositoryFunction",
JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
- &gjs_function_class_ops
+ &Function::class_ops
};
-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_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),
+const JSFunctionSpec Function::proto_funcs[] = {
+ JS_FN("toString", &Function::to_string, 0, 0),
JS_FS_END
};
+// clang-format on
-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)
-{
+bool Function::init(JSContext* context, GType gtype) {
guint8 i, n_args;
int array_length_pos;
GError *error = NULL;
GITypeInfo return_type;
- GIInfoType info_type;
- info_type = g_base_info_get_type((GIBaseInfo *)info);
+ GIInfoType info_type = g_base_info_get_type(m_info);
if (info_type == GI_INFO_TYPE_FUNCTION) {
- if (!g_function_info_prep_invoker((GIFunctionInfo *)info,
- &(function->invoker),
- &error)) {
+ 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);
+ 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);
@@ -1637,23 +1611,21 @@ 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);
- }
}
- g_callable_info_load_return_type((GICallableInfo*)info, &return_type);
+ g_callable_info_load_return_type(m_info, &return_type);
if (g_type_info_get_tag(&return_type) != GI_TYPE_TAG_VOID)
- function->js_out_argc += 1;
+ m_js_out_argc += 1;
- n_args = g_callable_info_get_n_args((GICallableInfo*) info);
- function->param_types = g_new0(GjsParamType, n_args);
+ n_args = g_callable_info_get_n_args(m_info);
+ m_param_types = g_new0(GjsParamType, n_args);
array_length_pos = g_type_info_get_array_length(&return_type);
if (array_length_pos >= 0 && array_length_pos < n_args)
- function->param_types[array_length_pos] = PARAM_SKIPPED;
+ m_param_types[array_length_pos] = PARAM_SKIPPED;
for (i = 0; i < n_args; i++) {
GIDirection direction;
@@ -1663,10 +1635,10 @@ init_cached_function_data (JSContext *context,
int closure = -1;
GITypeTag type_tag;
- if (function->param_types[i] == PARAM_SKIPPED)
+ if (m_param_types[i] == PARAM_SKIPPED)
continue;
- g_callable_info_load_arg((GICallableInfo*) info, i, &arg_info);
+ g_callable_info_load_arg(m_info, i, &arg_info);
g_arg_info_load_type(&arg_info, &type_info);
direction = g_arg_info_get_direction(&arg_info);
@@ -1687,26 +1659,28 @@ init_cached_function_data (JSContext *context,
// overwritten with PARAM_SKIPPED. If no callback follows,
// then this is probably an unsupported function, so the
// value will remain PARAM_UNKNOWN.
- function->param_types[i] = PARAM_UNKNOWN;
+ m_param_types[i] = PARAM_UNKNOWN;
} else {
- function->param_types[i] = PARAM_CALLBACK;
- function->expected_js_argc += 1;
+ m_param_types[i] = PARAM_CALLBACK;
+ m_expected_js_argc += 1;
destroy = g_arg_info_get_destroy(&arg_info);
closure = g_arg_info_get_closure(&arg_info);
if (destroy >= 0 && destroy < n_args)
- function->param_types[destroy] = PARAM_SKIPPED;
+ m_param_types[destroy] = PARAM_SKIPPED;
if (closure >= 0 && closure < n_args)
- function->param_types[closure] = PARAM_SKIPPED;
+ m_param_types[closure] = PARAM_SKIPPED;
if (destroy >= 0 && closure < 0) {
- gjs_throw(context, "Function %s.%s has a GDestroyNotify but no user_data, not
supported",
- g_base_info_get_namespace( (GIBaseInfo*) info),
- g_base_info_get_name( (GIBaseInfo*) info));
+ gjs_throw(context,
+ "Function %s.%s has a GDestroyNotify but no "
+ "user_data, not supported",
+ g_base_info_get_namespace(m_info),
+ g_base_info_get_name(m_info));
g_base_info_unref(interface_info);
- g_free(function->param_types);
+ g_free(m_param_types);
return false;
}
}
@@ -1719,86 +1693,72 @@ init_cached_function_data (JSContext *context,
if (array_length_pos >= 0 && array_length_pos < n_args) {
GIArgInfo length_arg_info;
- g_callable_info_load_arg((GICallableInfo*) info, array_length_pos, &length_arg_info);
+ g_callable_info_load_arg(m_info, array_length_pos,
+ &length_arg_info);
if (g_arg_info_get_direction(&length_arg_info) != direction) {
- gjs_throw(context, "Function %s.%s has an array with different-direction length arg,
not supported",
- g_base_info_get_namespace( (GIBaseInfo*) info),
- g_base_info_get_name( (GIBaseInfo*) info));
- g_free(function->param_types);
+ gjs_throw(
+ context,
+ "Function %s.%s has an array with "
+ "different-direction length arg, not supported",
+ g_base_info_get_namespace(m_info),
+ g_base_info_get_name(m_info));
+ g_free(m_param_types);
return false;
}
- function->param_types[array_length_pos] = PARAM_SKIPPED;
- function->param_types[i] = PARAM_ARRAY;
+ m_param_types[array_length_pos] = PARAM_SKIPPED;
+ m_param_types[i] = PARAM_ARRAY;
if (array_length_pos < i) {
/* we already collected array_length_pos, remove it */
if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
- function->expected_js_argc -= 1;
+ m_expected_js_argc -= 1;
if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
- function->js_out_argc -= 1;
+ m_js_out_argc -= 1;
}
}
}
}
- if (function->param_types[i] == PARAM_NORMAL ||
- function->param_types[i] == PARAM_ARRAY) {
+ if (m_param_types[i] == PARAM_NORMAL ||
+ m_param_types[i] == PARAM_ARRAY) {
if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
- function->expected_js_argc += 1;
+ m_expected_js_argc += 1;
if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
- function->js_out_argc += 1;
+ m_js_out_argc += 1;
}
}
- function->info = info;
-
- g_base_info_ref((GIBaseInfo*) function->info);
-
return true;
}
-GJS_USE
-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)
-{
+JSObject* Function::create(JSContext* context, GType gtype,
+ GICallableInfo* info) {
Function *priv;
- JS::RootedObject proto(context);
- if (!gjs_function_define_proto(context, nullptr, &proto))
+ 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_slice_new0(Function);
+ new (priv) Function(info);
- GJS_INC_COUNTER(function);
-
- 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);
- if (!init_cached_function_data(context, priv, gtype, (GICallableInfo *)info))
- return NULL;
+ if (!priv->init(context, gtype))
+ return nullptr;
return function;
}
@@ -1816,7 +1776,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;
@@ -1842,17 +1802,13 @@ gjs_define_function(JSContext *context,
return function;
}
-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))
+bool Function::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;
- bool result = gjs_invoke_c_function(context, &function, args, obj, rvalue);
- uninit_cached_function_data(&function);
- return result;
+ return function.invoke(cx, args, obj, rvalue);
}
diff --git a/gi/function.h b/gi/function.h
index 8b4b1c95..c97699c6 100644
--- a/gi/function.h
+++ b/gi/function.h
@@ -26,17 +26,28 @@
#include <config.h>
+#include <stdint.h>
+
#include <ffi.h>
#include <girepository.h>
+#include <girffi.h>
#include <glib-object.h>
+#include <js/PropertySpec.h>
+#include <js/RootingAPI.h>
#include <js/TypeDecls.h>
+#include "gjs/jsapi-class.h"
#include "gjs/macros.h"
namespace JS {
class CallArgs;
}
+namespace js {
+struct ClassSpec;
+}
+struct JSClass;
+struct JSClassOps;
typedef enum {
PARAM_NORMAL,
@@ -67,16 +78,79 @@ GjsCallbackTrampoline* gjs_callback_trampoline_new(
void gjs_callback_trampoline_unref(GjsCallbackTrampoline *trampoline);
void gjs_callback_trampoline_ref(GjsCallbackTrampoline *trampoline);
+class Function;
+using FunctionBase =
+ NativeObject<Function, Function, GJS_GLOBAL_SLOT_PROTOTYPE_function>;
+
+class Function : public FunctionBase {
+ friend FunctionBase;
+
+ GICallableInfo* m_info;
+
+ GjsParamType* m_param_types;
+
+ uint8_t m_expected_js_argc;
+ uint8_t m_js_out_argc;
+ GIFunctionInvoker m_invoker;
+
+ explicit Function(GICallableInfo* info);
+ ~Function();
+
+ GJS_JSAPI_RETURN_CONVENTION
+ bool init(JSContext* cx, GType gtype = G_TYPE_NONE);
+
+ GJS_JSAPI_RETURN_CONVENTION
+ static Function* for_js(JSContext* cx, JS::HandleObject obj,
+ JS::CallArgs& args);
+
+ 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_USE int32_t get_length_impl();
+
+ 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, const JS::CallArgs& args);
+
+ static const JSClass klass;
+ static const JSClassOps class_ops;
+ static const JSPropertySpec proto_props[];
+ static const JSFunctionSpec proto_funcs[];
+ static const js::ClassSpec class_spec;
+
+ public:
+ GJS_JSAPI_RETURN_CONVENTION
+ static JSObject* create(JSContext* cx, GType gtype, GICallableInfo* info);
+
+ GJS_JSAPI_RETURN_CONVENTION
+ bool fill_method_instance(JSContext* cx, JS::HandleObject obj,
+ GIArgument* out_arg, bool& is_gobject);
+
+ GJS_USE 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);
+};
+
GJS_JSAPI_RETURN_CONVENTION
JSObject *gjs_define_function(JSContext *context,
JS::HandleObject in_object,
GType gtype,
GICallableInfo *info);
-GJS_JSAPI_RETURN_CONVENTION
-bool gjs_invoke_constructor_from_c(JSContext* cx, GIFunctionInfo* info,
- JS::HandleObject this_obj,
- const JS::CallArgs& args,
- GIArgument* rvalue);
-
#endif // GI_FUNCTION_H_
diff --git a/gi/fundamental.cpp b/gi/fundamental.cpp
index 42b53e78..370a409a 100644
--- a/gi/fundamental.cpp
+++ b/gi/fundamental.cpp
@@ -198,8 +198,8 @@ bool FundamentalInstance::invoke_constructor(JSContext* context,
return false;
}
- return gjs_invoke_constructor_from_c(context, constructor_info, obj, args,
- rvalue);
+ return Function::invoke_constructor_uncached(context, constructor_info, obj,
+ args, rvalue);
}
// See GIWrapperBase::constructor().
diff --git a/gi/union.cpp b/gi/union.cpp
index b2b2d834..2b7fd433 100644
--- a/gi/union.cpp
+++ b/gi/union.cpp
@@ -111,8 +111,8 @@ static void* union_new(JSContext* context, JS::HandleObject this_obj,
if ((flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0 &&
g_callable_info_get_n_args((GICallableInfo*) func_info) == 0) {
GIArgument rval;
- if (!gjs_invoke_constructor_from_c(context, func_info, this_obj,
- args, &rval))
+ if (!Function::invoke_constructor_uncached(context, func_info,
+ this_obj, args, &rval))
return nullptr;
if (!rval.v_pointer) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]