From 2463c839f9fb79bcec3d3a523c4cfa8fb6377a48 Mon Sep 17 00:00:00 2001 From: Willy Sudiarto Raharjo Date: Wed, 16 Oct 2024 12:37:15 +0700 Subject: [PATCH] Revert "cjs: Port to mozjs 128." Turns out the patch does compile but runtime is broken. This reverts commit b6accfbbb3a9f0e3cdba667789d3abe2cf151c6a. --- cjs/cjs.SlackBuild | 5 +- cjs/mozjs128.patch | 11577 ------------------------------------------- 2 files changed, 1 insertion(+), 11581 deletions(-) delete mode 100644 cjs/mozjs128.patch diff --git a/cjs/cjs.SlackBuild b/cjs/cjs.SlackBuild index 3f1937c..b6e2f9a 100644 --- a/cjs/cjs.SlackBuild +++ b/cjs/cjs.SlackBuild @@ -24,7 +24,7 @@ PRGNAM=cjs VERSION=${VERSION:-6.2.0} -BUILD=${BUILD:-2} +BUILD=${BUILD:-1} TAG=${TAG:-_csb} if [ -z "$ARCH" ]; then @@ -74,9 +74,6 @@ find -L . \ \( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \ -o -perm 440 -o -perm 400 \) -exec chmod 644 {} \; -# Patch for mozjs128 -patch -p1 < $CWD/mozjs128.patch - mkdir -p build cd build CFLAGS="$SLKCFLAGS" \ diff --git a/cjs/mozjs128.patch b/cjs/mozjs128.patch deleted file mode 100644 index 390f552..0000000 --- a/cjs/mozjs128.patch +++ /dev/null @@ -1,11577 +0,0 @@ -diff -ruN cjs-6.2.0-orig/cjs/byteArray.cpp cjs-6.2.0/cjs/byteArray.cpp ---- cjs-6.2.0-orig/cjs/byteArray.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/byteArray.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -6,11 +6,14 @@ - - #include - -+#include // for copy_n -+ - #include - #include - - #include - #include -+#include - #include - #include - #include -@@ -28,15 +31,6 @@ - #include "cjs/jsapi-util.h" - #include "cjs/macros.h" - #include "cjs/text-encoding.h" --#include "util/misc.h" // for _gjs_memdup2 -- --// Callback to use with JS::NewExternalArrayBuffer() -- --static void bytes_unref_arraybuffer(void* contents [[maybe_unused]], -- void* user_data) { -- auto* gbytes = static_cast(user_data); -- g_bytes_unref(gbytes); --} - - GJS_JSAPI_RETURN_CONVENTION - static bool to_string_func(JSContext* cx, unsigned argc, JS::Value* vp) { -@@ -145,15 +139,18 @@ - return true; - } - -- JS::RootedObject array_buffer( -- context, -- JS::NewExternalArrayBuffer( -- context, len, -- const_cast(data), // the ArrayBuffer won't modify the data -- bytes_unref_arraybuffer, gbytes)); -+ JS::RootedObject array_buffer{context, JS::NewArrayBuffer(context, len)}; - if (!array_buffer) - return false; -- g_bytes_ref(gbytes); // now owned by both ArrayBuffer and BoxedBase -+ -+ // Copy the data into the ArrayBuffer so that the copy is aligned, and -+ // because the GBytes data pointer may point into immutable memory. -+ { -+ JS::AutoCheckCannotGC nogc; -+ bool unused; -+ uint8_t* storage = JS::GetArrayBufferData(array_buffer, &unused, nogc); -+ std::copy_n(static_cast(data), len, storage); -+ } - - JS::RootedObject obj( - context, JS_NewUint8ArrayWithBuffer(context, array_buffer, 0, -1)); -@@ -164,14 +161,20 @@ - return true; - } - --JSObject* gjs_byte_array_from_data(JSContext* cx, size_t nbytes, void* data) { -+JSObject* gjs_byte_array_from_data_copy(JSContext* cx, size_t nbytes, -+ void* data) { - JS::RootedObject array_buffer(cx); - // a null data pointer takes precedence over whatever `nbytes` says -- if (data) -- array_buffer = JS::NewArrayBufferWithContents( -- cx, nbytes, _gjs_memdup2(data, nbytes)); -- else -+ if (data) { -+ array_buffer = JS::NewArrayBuffer(cx, nbytes); -+ -+ JS::AutoCheckCannotGC nogc{}; -+ bool unused; -+ uint8_t* storage = JS::GetArrayBufferData(array_buffer, &unused, nogc); -+ std::copy_n(static_cast(data), nbytes, storage); -+ } else { - array_buffer = JS::NewArrayBuffer(cx, 0); -+ } - if (!array_buffer) - return nullptr; - -@@ -186,7 +189,7 @@ - } - - JSObject* gjs_byte_array_from_byte_array(JSContext* cx, GByteArray* array) { -- return gjs_byte_array_from_data(cx, array->len, array->data); -+ return gjs_byte_array_from_data_copy(cx, array->len, array->data); - } - - GBytes* gjs_byte_array_get_bytes(JSObject* obj) { -diff -ruN cjs-6.2.0-orig/cjs/byteArray.h cjs-6.2.0/cjs/byteArray.h ---- cjs-6.2.0-orig/cjs/byteArray.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/byteArray.h 2024-10-14 18:35:57.000000000 +0200 -@@ -20,7 +20,8 @@ - JS::MutableHandleObject module); - - GJS_JSAPI_RETURN_CONVENTION --JSObject* gjs_byte_array_from_data(JSContext* cx, size_t nbytes, void* data); -+JSObject* gjs_byte_array_from_data_copy(JSContext* cx, size_t nbytes, -+ void* data); - - GJS_JSAPI_RETURN_CONVENTION - JSObject * gjs_byte_array_from_byte_array (JSContext *context, -diff -ruN cjs-6.2.0-orig/cjs/context-private.h cjs-6.2.0/cjs/context-private.h ---- cjs-6.2.0-orig/cjs/context-private.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/context-private.h 2024-10-14 18:35:57.000000000 +0200 -@@ -32,12 +32,14 @@ - #include - #include - #include -+#include // for UniqueChars, FreePolicy - #include - #include // for ScriptEnvironmentPreparer - - #include "gi/closure.h" - #include "cjs/context.h" - #include "cjs/jsapi-util.h" -+#include "cjs/jsapi-util-root.h" - #include "cjs/macros.h" - #include "cjs/mainloop.h" - #include "cjs/profiler.h" -@@ -51,11 +53,12 @@ - using ObjectInitList = - JS::GCVector, 0, js::SystemAllocPolicy>; - using FundamentalTable = -- JS::GCHashMap, js::DefaultHasher, -+ JS::GCHashMap, js::DefaultHasher, - js::SystemAllocPolicy>; - using GTypeTable = -- JS::GCHashMap, js::DefaultHasher, -+ JS::GCHashMap, js::DefaultHasher, - js::SystemAllocPolicy>; -+using FunctionVector = JS::GCVector; - - class GjsContextPrivate : public JS::JobQueue { - public: -@@ -87,7 +90,8 @@ - - std::vector> m_destroy_notifications; - std::vector m_async_closures; -- std::unordered_map m_unhandled_rejection_stacks; -+ std::unordered_map m_unhandled_rejection_stacks; -+ FunctionVector m_cleanup_tasks; - - GjsProfiler* m_profiler; - -@@ -117,7 +121,6 @@ - - /* flags */ - std::atomic_bool m_destroying = ATOMIC_VAR_INIT(false); -- bool m_in_gc_sweep : 1; - bool m_should_exit : 1; - bool m_force_gc : 1; - bool m_draining_job_queue : 1; -@@ -126,13 +129,6 @@ - bool m_unhandled_exception : 1; - bool m_should_listen_sigusr2 : 1; - -- // If profiling is enabled, we record the durations and reason for GC mark -- // and sweep -- int64_t m_gc_begin_time; -- int64_t m_sweep_begin_time; -- int64_t m_group_sweep_begin_time; -- const char* m_gc_reason; // statically allocated -- - void schedule_gc_internal(bool force_gc); - static gboolean trigger_gc_if_needed(void* data); - void on_garbage_collection(JSGCStatus, JS::GCReason); -@@ -192,7 +188,6 @@ - [[nodiscard]] GjsProfiler* profiler() const { return m_profiler; } - [[nodiscard]] const GjsAtoms& atoms() const { return *m_atoms; } - [[nodiscard]] bool destroying() const { return m_destroying.load(); } -- [[nodiscard]] bool sweeping() const { return m_in_gc_sweep; } - [[nodiscard]] const char* program_name() const { return m_program_name; } - void set_program_name(char* value) { m_program_name = value; } - GJS_USE const char* program_path(void) const { return m_program_path; } -@@ -256,12 +251,19 @@ - JS::HandleObject incumbent_global) override; - void runJobs(JSContext* cx) override; - [[nodiscard]] bool empty() const override { return m_job_queue.empty(); } -+ [[nodiscard]] bool isDrainingStopped() const override { -+ return !m_draining_job_queue; -+ } - js::UniquePtr saveJobQueue( - JSContext* cx) override; - - GJS_JSAPI_RETURN_CONVENTION bool run_jobs_fallible(); -- void register_unhandled_promise_rejection(uint64_t id, GjsAutoChar&& stack); -+ void register_unhandled_promise_rejection(uint64_t id, -+ JS::UniqueChars&& stack); - void unregister_unhandled_promise_rejection(uint64_t id); -+ GJS_JSAPI_RETURN_CONVENTION bool queue_finalization_registry_cleanup( -+ JSFunction* cleanup_task); -+ GJS_JSAPI_RETURN_CONVENTION bool run_finalization_registry_cleanup(); - - void register_notifier(DestroyNotify notify_func, void* data); - void unregister_notifier(DestroyNotify notify_func, void* data); -@@ -270,9 +272,6 @@ - [[nodiscard]] bool register_module(const char* identifier, - const char* filename, GError** error); - -- void set_gc_status(JSGCStatus status, JS::GCReason reason); -- void set_finalize_status(JSFinalizeStatus status); -- - static void trace(JSTracer* trc, void* data); - - void free_profiler(void); -diff -ruN cjs-6.2.0-orig/cjs/context.cpp cjs-6.2.0/cjs/context.cpp ---- cjs-6.2.0-orig/cjs/context.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/context.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -12,13 +12,13 @@ - - #ifdef HAVE_UNISTD_H - # include // for getpid --#elif defined (_WIN32) --# include - #endif - --#ifdef DEBUG --# include // for find -+#ifdef G_OS_WIN32 -+# include -+# include - #endif -+ - #include - #include // for u16string - #include // for get_id -@@ -31,10 +31,6 @@ - #include - #include - --#ifdef G_OS_WIN32 --#include --#endif -- - #include // for SystemAllocPolicy - #include // for Call, JS_CallFunctionValue - #include // for UndefinedHandleValue -@@ -48,7 +44,7 @@ - #include // for WeakCache - #include // for RootedVector - #include // for CurrentGlobalOrNull --#include // for DefaultHasher via WeakCache -+#include // for ExposeObjectToActiveJS - #include - #include - #include // for JobQueue::SavedJobQueue -@@ -67,6 +63,7 @@ - #include - #include // for JS_GetFunctionObject, JS_Ge... - #include // for ScriptEnvironmentPreparer -+#include // for UniquePtr::get - - #include "gi/closure.h" // for Closure::Ptr, Closure - #include "gi/function.h" -@@ -93,7 +90,10 @@ - #include "cjs/profiler.h" - #include "cjs/promise.h" - #include "cjs/text-encoding.h" --#include "modules/modules.h" -+#include "modules/cairo-module.h" -+#include "modules/console.h" -+#include "modules/print.h" -+#include "modules/system.h" - #include "util/log.h" - - namespace mozilla { -@@ -127,8 +127,6 @@ - - G_DEFINE_TYPE_WITH_PRIVATE(GjsContext, gjs_context, G_TYPE_OBJECT); - --Gjs::NativeModuleRegistry& registry = Gjs::NativeModuleRegistry::get(); -- - GjsContextPrivate* GjsContextPrivate::from_object(GObject* js_context) { - g_return_val_if_fail(GJS_IS_CONTEXT(js_context), nullptr); - return static_cast( -@@ -322,7 +320,7 @@ - g_object_class_install_property(object_class, PROP_EXEC_AS_MODULE, pspec); - g_param_spec_unref(pspec); - -- /* For CjsPrivate */ -+ /* For GjsPrivate */ - if (!g_getenv("GJS_USE_UNINSTALLED_FILES")) { - #ifdef G_OS_WIN32 - extern HMODULE gjs_dll; -@@ -336,13 +334,16 @@ - #endif - g_irepository_prepend_search_path(priv_typelib_dir); - } -+ auto& registry = Gjs::NativeModuleDefineFuncs::get(); - registry.add("_promiseNative", gjs_define_native_promise_stuff); - registry.add("_byteArrayNative", gjs_define_byte_array_stuff); - registry.add("_encodingNative", gjs_define_text_encoding_stuff); - registry.add("_gi", gjs_define_private_gi_stuff); - registry.add("gi", gjs_define_repo); -- -- gjs_register_static_modules(); -+ registry.add("cairoNative", gjs_js_define_cairo_stuff); -+ registry.add("system", gjs_js_define_system_stuff); -+ registry.add("console", gjs_define_console_stuff); -+ registry.add("_print", gjs_define_print_stuff); - } - - void GjsContextPrivate::trace(JSTracer* trc, void* data) { -@@ -353,12 +354,13 @@ - JS::TraceEdge(trc, &gjs->m_main_loop_hook, "GJS main loop hook"); - gjs->m_atoms->trace(trc); - gjs->m_job_queue.trace(trc); -+ gjs->m_cleanup_tasks.trace(trc); - gjs->m_object_init_list.trace(trc); - } - - void GjsContextPrivate::warn_about_unhandled_promise_rejections(void) { - for (auto& kv : m_unhandled_rejection_stacks) { -- const char *stack = kv.second; -+ const char* stack = kv.second.get(); - g_warning("Unhandled promise rejection. To suppress this warning, add " - "an error handler to your promise chain with .catch() or a " - "try-catch block around your await expression. %s%s", -@@ -533,10 +535,8 @@ - JS::Value* vp) { - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - -- JSString* id = -- JS_GetFunctionDisplayId(JS_GetObjectFunction(&args.callee())); - gjs_debug(GJS_DEBUG_IMPORTER, "Module evaluation promise rejected: %s", -- gjs_debug_string(id).c_str()); -+ gjs_debug_callable(&args.callee()).c_str()); - - JS::HandleValue error = args.get(0); - -@@ -555,10 +555,8 @@ - JS::Value* vp) { - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - -- JSString* id = -- JS_GetFunctionDisplayId(JS_GetObjectFunction(&args.callee())); - gjs_debug(GJS_DEBUG_IMPORTER, "Module evaluation promise resolved: %s", -- gjs_debug_string(id).c_str()); -+ gjs_debug_callable(&args.callee()).c_str()); - - args.rval().setUndefined(); - -@@ -619,11 +617,9 @@ - [](JSContext* cx, unsigned argc, JS::Value* vp) { - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - -- JSString* id = -- JS_GetFunctionDisplayId(JS_GetObjectFunction(&args.callee())); - gjs_debug(GJS_DEBUG_IMPORTER, - "Module evaluation promise rejected: %s", -- gjs_debug_string(id).c_str()); -+ gjs_debug_callable(&args.callee()).c_str()); - - JS::HandleValue error = args.get(0); - // Abort because this module is required. -@@ -886,6 +882,11 @@ - m_auto_gc_id = g_timeout_add_seconds_full(G_PRIORITY_LOW, 10, - trigger_gc_if_needed, this, - nullptr); -+ -+ if (force_gc) -+ g_source_set_name_by_id(m_auto_gc_id, "[gjs] Garbage Collection (Big Hammer)"); -+ else -+ g_source_set_name_by_id(m_auto_gc_id, "[gjs] Garbage Collection"); - } - - /* -@@ -903,17 +904,14 @@ - } - - void GjsContextPrivate::on_garbage_collection(JSGCStatus status, JS::GCReason reason) { -- int64_t now = 0; - if (m_profiler) -- now = g_get_monotonic_time() * 1000L; -+ _gjs_profiler_set_gc_status(m_profiler, status, reason); - - switch (status) { - case JSGC_BEGIN: -- m_gc_begin_time = now; -- m_gc_reason = gjs_explain_gc_reason(reason); - gjs_debug_lifecycle(GJS_DEBUG_CONTEXT, - "Begin garbage collection because of %s", -- m_gc_reason); -+ gjs_explain_gc_reason(reason)); - - // We finalize any pending toggle refs before doing any garbage - // collection, so that we can collect the JS wrapper objects, and in -@@ -925,14 +923,6 @@ - m_async_closures.shrink_to_fit(); - break; - case JSGC_END: -- if (m_profiler && m_gc_begin_time != 0) { -- _gjs_profiler_add_mark(m_profiler, m_gc_begin_time, -- now - m_gc_begin_time, "GJS", -- "Garbage collection", m_gc_reason); -- } -- m_gc_begin_time = 0; -- m_gc_reason = nullptr; -- - m_destroy_notifications.shrink_to_fit(); - gjs_debug_lifecycle(GJS_DEBUG_CONTEXT, "End garbage collection"); - break; -@@ -941,73 +931,6 @@ - } - } - --void GjsContextPrivate::set_finalize_status(JSFinalizeStatus status) { -- // Implementation note for mozjs-24: -- // -- // Sweeping happens in two phases, in the first phase all GC things from the -- // allocation arenas are queued for sweeping, then the actual sweeping -- // happens. The first phase is marked by JSFINALIZE_GROUP_START, the second -- // one by JSFINALIZE_GROUP_END, and finally we will see -- // JSFINALIZE_COLLECTION_END at the end of all GC. (see jsgc.cpp, -- // BeginSweepPhase/BeginSweepingZoneGroup and SweepPhase, all called from -- // IncrementalCollectSlice). -- // -- // Incremental GC muddies the waters, because BeginSweepPhase is always run -- // to entirety, but SweepPhase can be run incrementally and mixed with JS -- // code runs or even native code, when MaybeGC/IncrementalGC return. -- // -- // Luckily for us, objects are treated specially, and are not really queued -- // for deferred incremental finalization (unless they are marked for -- // background sweeping). Instead, they are finalized immediately during -- // phase 1, so the following guarantees are true (and we rely on them): -- // - phase 1 of GC will begin and end in the same JSAPI call (i.e., our -- // callback will be called with GROUP_START and the triggering JSAPI call -- // will not return until we see a GROUP_END) -- // - object finalization will begin and end in the same JSAPI call -- // - therefore, if there is a finalizer frame somewhere in the stack, -- // GjsContextPrivate::sweeping() will return true. -- // -- // Comments in mozjs-24 imply that this behavior might change in the future, -- // but it hasn't changed in mozilla-central as of 2014-02-23. In addition to -- // that, the mozilla-central version has a huge comment in a different -- // portion of the file, explaining why finalization of objects can't be -- // mixed with JS code, so we can probably rely on this behavior. -- -- int64_t now = 0; -- -- if (m_profiler) -- now = g_get_monotonic_time() * 1000L; -- -- switch (status) { -- case JSFINALIZE_GROUP_PREPARE: -- m_in_gc_sweep = true; -- m_sweep_begin_time = now; -- break; -- case JSFINALIZE_GROUP_START: -- m_group_sweep_begin_time = now; -- break; -- case JSFINALIZE_GROUP_END: -- if (m_profiler && m_group_sweep_begin_time != 0) { -- _gjs_profiler_add_mark(m_profiler, m_group_sweep_begin_time, -- now - m_group_sweep_begin_time, "GJS", -- "Group sweep", nullptr); -- } -- m_group_sweep_begin_time = 0; -- break; -- case JSFINALIZE_COLLECTION_END: -- m_in_gc_sweep = false; -- if (m_profiler && m_sweep_begin_time != 0) { -- _gjs_profiler_add_mark(m_profiler, m_sweep_begin_time, -- now - m_sweep_begin_time, "GJS", "Sweep", -- nullptr); -- } -- m_sweep_begin_time = 0; -- break; -- default: -- g_assert_not_reached(); -- } --} -- - void GjsContextPrivate::exit(uint8_t exit_code) { - g_assert(!m_should_exit); - m_should_exit = true; -@@ -1096,6 +1019,14 @@ - JS::HandleValueArray args(JS::HandleValueArray::empty()); - JS::RootedValue rval(m_cx); - -+ if (m_job_queue.length() == 0) { -+ // Check FinalizationRegistry cleanup tasks at least once if there are -+ // no microtasks queued. This may enqueue more microtasks, which will be -+ // appended to m_job_queue. -+ if (!run_finalization_registry_cleanup()) -+ retval = false; -+ } -+ - /* Execute jobs in a loop until we've reached the end of the queue. - * Since executing a job can trigger enqueueing of additional jobs, - * it's crucial to recheck the queue length during each iteration. */ -@@ -1139,6 +1070,11 @@ - } - } - gjs_debug(GJS_DEBUG_MAINLOOP, "Completed job %zu", ix); -+ -+ // Run FinalizationRegistry cleanup tasks after each job. Cleanup tasks -+ // may enqueue more microtasks, which will be appended to m_job_queue. -+ if (!run_finalization_registry_cleanup()) -+ retval = false; - } - - m_draining_job_queue = false; -@@ -1148,6 +1084,44 @@ - return retval; - } - -+bool GjsContextPrivate::run_finalization_registry_cleanup() { -+ bool retval = true; -+ -+ JS::Rooted tasks{m_cx}; -+ std::swap(tasks.get(), m_cleanup_tasks); -+ g_assert(m_cleanup_tasks.empty()); -+ -+ JS::RootedFunction task{m_cx}; -+ JS::RootedValue unused_rval{m_cx}; -+ for (JSFunction* func : tasks) { -+ gjs_debug(GJS_DEBUG_MAINLOOP, -+ "Running FinalizationRegistry cleanup callback"); -+ -+ task.set(func); -+ JS::ExposeObjectToActiveJS(JS_GetFunctionObject(func)); -+ -+ JSAutoRealm ar{m_cx, JS_GetFunctionObject(func)}; -+ if (!JS_CallFunction(m_cx, nullptr, task, JS::HandleValueArray::empty(), -+ &unused_rval)) { -+ // Same logic as above -+ if (!JS_IsExceptionPending(m_cx)) { -+ if (!should_exit(nullptr)) -+ g_critical( -+ "FinalizationRegistry callback terminated with " -+ "uncatchable exception"); -+ retval = false; -+ continue; -+ } -+ gjs_log_exception_uncaught(m_cx); -+ } -+ -+ gjs_debug(GJS_DEBUG_MAINLOOP, -+ "Completed FinalizationRegistry cleanup callback"); -+ } -+ -+ return retval; -+} -+ - class GjsContextPrivate::SavedQueue : public JS::JobQueue::SavedJobQueue { - private: - GjsContextPrivate* m_gjs; -@@ -1187,7 +1161,7 @@ - } - - void GjsContextPrivate::register_unhandled_promise_rejection( -- uint64_t id, GjsAutoChar&& stack) { -+ uint64_t id, JS::UniqueChars&& stack) { - m_unhandled_rejection_stacks[id] = std::move(stack); - } - -@@ -1202,6 +1176,11 @@ - } - } - -+bool GjsContextPrivate::queue_finalization_registry_cleanup( -+ JSFunction* cleanup_task) { -+ return m_cleanup_tasks.append(cleanup_task); -+} -+ - void GjsContextPrivate::async_closure_enqueue_for_gc(Gjs::Closure* trampoline) { - // Because we can't free the mmap'd data for a callback - // while it's in use, this list keeps track of ones that -diff -ruN cjs-6.2.0-orig/cjs/context.h cjs-6.2.0/cjs/context.h ---- cjs-6.2.0-orig/cjs/context.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/context.h 2024-10-14 18:38:17.000000000 +0200 -@@ -8,7 +8,7 @@ - #define GJS_CONTEXT_H_ - - #if !defined(INSIDE_GJS_H) && !defined(GJS_COMPILATION) --# error "Only can be included directly." -+# error "Only can be included directly." - #endif - - #include /* IWYU pragma: keep */ -diff -ruN cjs-6.2.0-orig/cjs/coverage.h cjs-6.2.0/cjs/coverage.h ---- cjs-6.2.0-orig/cjs/coverage.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/coverage.h 2024-10-14 18:38:17.000000000 +0200 -@@ -9,7 +9,7 @@ - #define GJS_COVERAGE_H_ - - #if !defined(INSIDE_GJS_H) && !defined(GJS_COMPILATION) --# error "Only can be included directly." -+# error "Only can be included directly." - #endif - - #include -diff -ruN cjs-6.2.0-orig/cjs/deprecation.cpp cjs-6.2.0/cjs/deprecation.cpp ---- cjs-6.2.0-orig/cjs/deprecation.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/deprecation.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -49,8 +49,14 @@ - "to be exported from a module must be defined with 'var'. The property " - "access will work as previously for the time being, but please fix your " - "code anyway.", -+ -+ // PlatformSpecificTypelib: -+ ("{} has been moved to a separate platform-specific library. Please update " -+ "your code to use {} instead."), - }; - -+static_assert(G_N_ELEMENTS(messages) == GjsDeprecationMessageId::LastValue); -+ - struct DeprecationEntry { - GjsDeprecationMessageId id; - std::string loc; -@@ -111,9 +117,9 @@ - warn_deprecated_unsafe_internal(cx, id, messages[id]); - } - --void _gjs_warn_deprecated_once_per_callsite(JSContext* cx, -- GjsDeprecationMessageId id, -- std::vector args) { -+void _gjs_warn_deprecated_once_per_callsite( -+ JSContext* cx, GjsDeprecationMessageId id, -+ const std::vector& args) { - // In C++20, use std::format() for this - std::string_view format_string{messages[id]}; - std::stringstream message; -@@ -126,7 +132,7 @@ - while ((pos = format_string.find("{}", pos)) != std::string::npos) { - if (args_ptr >= nargs_given) { - g_critical("Only %zu format args passed for message ID %u", -- nargs_given, id); -+ nargs_given, unsigned{id}); - return; - } - -@@ -136,11 +142,12 @@ - } - if (args_ptr != nargs_given) { - g_critical("Excess %zu format args passed for message ID %u", -- nargs_given, id); -+ nargs_given, unsigned{id}); - return; - } - - message << format_string.substr(copied, std::string::npos); - -- warn_deprecated_unsafe_internal(cx, id, message.str().c_str()); -+ std::string message_formatted = message.str(); -+ warn_deprecated_unsafe_internal(cx, id, message_formatted.c_str()); - } -diff -ruN cjs-6.2.0-orig/cjs/deprecation.h cjs-6.2.0/cjs/deprecation.h ---- cjs-6.2.0-orig/cjs/deprecation.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/deprecation.h 2024-09-16 22:32:54.000000000 +0200 -@@ -5,22 +5,26 @@ - #ifndef GJS_DEPRECATION_H_ - #define GJS_DEPRECATION_H_ - -+#include -+ - #include - - struct JSContext; - --enum GjsDeprecationMessageId { -+enum GjsDeprecationMessageId : unsigned { - None, - ByteArrayInstanceToString, - DeprecatedGObjectProperty, - ModuleExportedLetOrConst, -+ PlatformSpecificTypelib, -+ LastValue, // insert new elements before this one - }; - - void _gjs_warn_deprecated_once_per_callsite(JSContext* cx, - GjsDeprecationMessageId message); - --void _gjs_warn_deprecated_once_per_callsite(JSContext* cx, -- GjsDeprecationMessageId id, -- std::vector args); -+void _gjs_warn_deprecated_once_per_callsite( -+ JSContext* cx, GjsDeprecationMessageId id, -+ const std::vector& args); - - #endif // GJS_DEPRECATION_H_ -diff -ruN cjs-6.2.0-orig/cjs/engine.cpp cjs-6.2.0/cjs/engine.cpp ---- cjs-6.2.0-orig/cjs/engine.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/engine.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -19,24 +19,32 @@ - #include - #include // for JS_SetGCParameter, JS_AddFin... - #include // for JS_Init, JS_ShutDown -+#include - #include - #include - #include // for JS_SetNativeStackQuota -+#include // for JS_WriteUint32Pair - #include -+#include // for UniqueChars - #include - #include - #include // for JS_SetGlobalJitCompilerOption -+#include // for Atomic in JSPrincipals - #include - - #include "cjs/context-private.h" - #include "cjs/engine.h" - #include "cjs/jsapi-util.h" -+#include "cjs/profiler-private.h" - #include "util/log.h" - -+struct JSStructuredCloneWriter; -+ - static void gjs_finalize_callback(JS::GCContext*, JSFinalizeStatus status, - void* data) { - auto* gjs = static_cast(data); -- gjs->set_finalize_status(status); -+ if (gjs->profiler()) -+ _gjs_profiler_set_finalize_status(gjs->profiler(), status); - } - - static void on_promise_unhandled_rejection( -@@ -52,10 +60,19 @@ - } - - JS::RootedObject allocation_site(cx, JS::GetPromiseAllocationSite(promise)); -- GjsAutoChar stack = gjs_format_stack_trace(cx, allocation_site); -+ JS::UniqueChars stack = format_saved_frame(cx, allocation_site); - gjs->register_unhandled_promise_rejection(id, std::move(stack)); - } - -+static void on_cleanup_finalization_registry(JSFunction* cleanup_task, -+ JSObject* incumbent_global -+ [[maybe_unused]], -+ void* data) { -+ auto* gjs = static_cast(data); -+ if (!gjs->queue_finalization_registry_cleanup(cleanup_task)) -+ g_critical("Out of memory queueing FinalizationRegistry cleanup task"); -+} -+ - bool gjs_load_internal_source(JSContext* cx, const char* filename, char** src, - size_t* length) { - GjsAutoError error; -@@ -82,31 +99,26 @@ - HMODULE gjs_dll; - static bool gjs_is_inited = false; - --BOOL WINAPI --DllMain (HINSTANCE hinstDLL, --DWORD fdwReason, --LPVOID lpvReserved) --{ -- switch (fdwReason) -- { -- case DLL_PROCESS_ATTACH: { -- gjs_dll = hinstDLL; -- const char* reason = JS_InitWithFailureDiagnostic(); -- if (reason) -- g_error("Could not initialize JavaScript: %s", reason); -- gjs_is_inited = true; -- } break; -- -- case DLL_THREAD_DETACH: -- JS_ShutDown (); -- break; -- -- default: -- /* do nothing */ -- ; -+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { -+ switch (fdwReason) { -+ case DLL_PROCESS_ATTACH: { -+ gjs_dll = hinstDLL; -+ const char* reason = JS_InitWithFailureDiagnostic(); -+ if (reason) -+ g_error("Could not initialize JavaScript: %s", reason); -+ gjs_is_inited = true; -+ } break; -+ -+ case DLL_THREAD_DETACH: -+ JS_ShutDown(); -+ break; -+ -+ default: -+ /* do nothing */ -+ ; - } - -- return TRUE; -+ return TRUE; - } - - #else -@@ -128,6 +140,49 @@ - static GjsInit gjs_is_inited; - #endif - -+// JSPrincipals (basically a weird name for security callbacks) which are in -+// effect in the module loader's realm (GjsInternalGlobal). This prevents module -+// loader stack frames from showing up in public stack traces. -+class ModuleLoaderPrincipals final : public JSPrincipals { -+ static constexpr uint32_t STRUCTURED_CLONE_TAG = JS_SCTAG_USER_MIN; -+ -+ bool write(JSContext* cx [[maybe_unused]], -+ JSStructuredCloneWriter* writer) override { -+ g_assert_not_reached(); -+ return JS_WriteUint32Pair(writer, STRUCTURED_CLONE_TAG, 1); -+ } -+ -+ bool isSystemOrAddonPrincipal() override { return true; } -+ -+ public: -+ static bool subsumes(JSPrincipals* first, JSPrincipals* second) { -+ if (first != &the_principals && second == &the_principals) -+ return false; -+ return true; -+ } -+ -+ static void destroy(JSPrincipals* principals [[maybe_unused]]) { -+ g_assert(principals == &the_principals && -+ "Should not create other instances of ModuleLoaderPrinciples"); -+ g_assert(principals->refcount == 0 && -+ "Mismatched JS_HoldPrincipals/JS_DropPrincipals"); -+ } -+ -+ // Singleton -+ static ModuleLoaderPrincipals the_principals; -+}; -+ -+ModuleLoaderPrincipals ModuleLoaderPrincipals::the_principals{}; -+ -+JSPrincipals* get_internal_principals() { -+ return &ModuleLoaderPrincipals::the_principals; -+} -+ -+static const JSSecurityCallbacks security_callbacks = { -+ /* contentSecurityPolicyAllows = */ nullptr, -+ &ModuleLoaderPrincipals::subsumes, -+}; -+ - JSContext* gjs_create_js_context(GjsContextPrivate* uninitialized_gjs) { - g_assert(gjs_is_inited); - JSContext *cx = JS_NewContext(32 * 1024 * 1024 /* max bytes */); -@@ -149,11 +204,15 @@ - /* set ourselves as the private data */ - JS_SetContextPrivate(cx, uninitialized_gjs); - -+ JS_SetSecurityCallbacks(cx, &security_callbacks); -+ JS_InitDestroyPrincipalsCallback(cx, &ModuleLoaderPrincipals::destroy); - JS_AddFinalizeCallback(cx, gjs_finalize_callback, uninitialized_gjs); - JS::SetWarningReporter(cx, gjs_warning_reporter); - JS::SetJobQueue(cx, dynamic_cast(uninitialized_gjs)); - JS::SetPromiseRejectionTrackerCallback(cx, on_promise_unhandled_rejection, - uninitialized_gjs); -+ JS::SetHostCleanupFinalizationRegistryCallback( -+ cx, on_cleanup_finalization_registry, uninitialized_gjs); - - // We use this to handle "lazy sources" that SpiderMonkey doesn't need to - // keep in memory. Most sources should be kept in memory, but we can skip -diff -ruN cjs-6.2.0-orig/cjs/engine.h cjs-6.2.0/cjs/engine.h ---- cjs-6.2.0-orig/cjs/engine.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/engine.h 2024-09-16 22:32:54.000000000 +0200 -@@ -5,14 +5,19 @@ - #ifndef GJS_ENGINE_H_ - #define GJS_ENGINE_H_ - -+#include -+ - #include // for size_t - - class GjsContextPrivate; - struct JSContext; -+struct JSPrincipals; - - JSContext* gjs_create_js_context(GjsContextPrivate* uninitialized_gjs); - - bool gjs_load_internal_source(JSContext* cx, const char* filename, char** src, - size_t* length); - -+JSPrincipals* get_internal_principals(); -+ - #endif // GJS_ENGINE_H_ -diff -ruN cjs-6.2.0-orig/cjs/error-types.cpp cjs-6.2.0/cjs/error-types.cpp ---- cjs-6.2.0-orig/cjs/error-types.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/error-types.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -2,6 +2,8 @@ - // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later - // SPDX-FileCopyrightText: 2008 litl, LLC - -+#include -+ - #include - - #include "cjs/error-types.h" -diff -ruN cjs-6.2.0-orig/cjs/error-types.h cjs-6.2.0/cjs/error-types.h ---- cjs-6.2.0-orig/cjs/error-types.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/error-types.h 2024-10-14 18:38:17.000000000 +0200 -@@ -8,7 +8,7 @@ - #define GJS_ERROR_TYPES_H_ - - #if !defined(INSIDE_GJS_H) && !defined(GJS_COMPILATION) --# error "Only can be included directly." -+# error "Only can be included directly." - #endif - - #include -diff -ruN cjs-6.2.0-orig/cjs/gjs_pch.hh cjs-6.2.0/cjs/gjs_pch.hh ---- cjs-6.2.0-orig/cjs/gjs_pch.hh 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/gjs_pch.hh 2024-10-14 18:38:17.000000000 +0200 -@@ -58,6 +58,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -80,6 +81,8 @@ - #include - #include - #include -+#include -+#include - #include - #include - #include -@@ -95,6 +98,7 @@ - #include - #include - #include -+#include - #include - #include - #include -diff -ruN cjs-6.2.0-orig/cjs/global.cpp cjs-6.2.0/cjs/global.cpp ---- cjs-6.2.0-orig/cjs/global.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/global.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -46,21 +46,16 @@ - } - - class GjsBaseGlobal { -+ GJS_JSAPI_RETURN_CONVENTION - static JSObject* base(JSContext* cx, const JSClass* clasp, -- JS::RealmCreationOptions options) { -- // Enable WeakRef without the cleanupSome specification -- // Re-evaluate if cleanupSome is standardized -- // See: https://github.com/tc39/proposal-cleanup-some -- options.setWeakRefsEnabled( -- JS::WeakRefSpecifier::EnabledWithoutCleanupSome); -- -+ JS::RealmCreationOptions options, -+ JSPrincipals* principals = nullptr) { - JS::RealmBehaviors behaviors; - JS::RealmOptions compartment_options(options, behaviors); - -- JS::RootedObject global( -- cx, JS_NewGlobalObject(cx, clasp, nullptr, JS::FireOnNewGlobalHook, -- compartment_options)); -- -+ JS::RootedObject global{cx, JS_NewGlobalObject(cx, clasp, principals, -+ JS::FireOnNewGlobalHook, -+ compartment_options)}; - if (!global) - return nullptr; - -@@ -74,18 +69,22 @@ - } - - protected: -- [[nodiscard]] static JSObject* create( -+ GJS_JSAPI_RETURN_CONVENTION -+ static JSObject* create( - JSContext* cx, const JSClass* clasp, -- JS::RealmCreationOptions options = JS::RealmCreationOptions()) { -+ JS::RealmCreationOptions options = JS::RealmCreationOptions(), -+ JSPrincipals* principals = nullptr) { - options.setNewCompartmentAndZone(); -- return base(cx, clasp, options); -+ return base(cx, clasp, options, principals); - } - -- [[nodiscard]] static JSObject* create_with_compartment( -+ GJS_JSAPI_RETURN_CONVENTION -+ static JSObject* create_with_compartment( - JSContext* cx, JS::HandleObject existing, const JSClass* clasp, -- JS::RealmCreationOptions options = JS::RealmCreationOptions()) { -+ JS::RealmCreationOptions options = JS::RealmCreationOptions(), -+ JSPrincipals* principals = nullptr) { - options.setExistingCompartment(existing); -- return base(cx, clasp, options); -+ return base(cx, clasp, options, principals); - } - - GJS_JSAPI_RETURN_CONVENTION -@@ -132,8 +131,8 @@ - - JS::RootedObject native_obj(m_cx); - -- if (!Gjs::NativeModuleRegistry::get().load(m_cx, id.get(), -- &native_obj)) { -+ if (!Gjs::NativeModuleDefineFuncs::get().define(m_cx, id.get(), -+ &native_obj)) { - gjs_throw(m_cx, "Failed to load native module: %s", id.get()); - return false; - } -@@ -165,12 +164,14 @@ - JS_FS_END}; - - public: -- [[nodiscard]] static JSObject* create(JSContext* cx) { -+ GJS_JSAPI_RETURN_CONVENTION -+ static JSObject* create(JSContext* cx) { - return GjsBaseGlobal::create(cx, &klass); - } - -- [[nodiscard]] static JSObject* create_with_compartment( -- JSContext* cx, JS::HandleObject cmp_global) { -+ GJS_JSAPI_RETURN_CONVENTION -+ static JSObject* create_with_compartment(JSContext* cx, -+ JS::HandleObject cmp_global) { - return GjsBaseGlobal::create_with_compartment(cx, cmp_global, &klass); - } - -@@ -238,17 +239,20 @@ - JS_FN("loadNative", &load_native_module, 1, 0), JS_FS_END}; - - public: -- [[nodiscard]] static JSObject* create(JSContext* cx) { -+ GJS_JSAPI_RETURN_CONVENTION -+ static JSObject* create(JSContext* cx) { - JS::RealmCreationOptions options; - options.setToSourceEnabled(true); // debugger uses uneval() - return GjsBaseGlobal::create(cx, &klass, options); - } - -- [[nodiscard]] static JSObject* create_with_compartment( -- JSContext* cx, JS::HandleObject cmp_global) { -+ GJS_JSAPI_RETURN_CONVENTION -+ static JSObject* create_with_compartment(JSContext* cx, -+ JS::HandleObject cmp_global) { - return GjsBaseGlobal::create_with_compartment(cx, cmp_global, &klass); - } - -+ GJS_JSAPI_RETURN_CONVENTION - static bool define_properties(JSContext* cx, JS::HandleObject global, - const char* realm_name, - const char* bootstrap_script) { -@@ -298,15 +302,19 @@ - }; - - public: -- [[nodiscard]] static JSObject* create(JSContext* cx) { -- return GjsBaseGlobal::create(cx, &klass); -+ GJS_JSAPI_RETURN_CONVENTION -+ static JSObject* create(JSContext* cx) { -+ return GjsBaseGlobal::create(cx, &klass, {}, get_internal_principals()); - } - -- [[nodiscard]] static JSObject* create_with_compartment( -- JSContext* cx, JS::HandleObject cmp_global) { -- return GjsBaseGlobal::create_with_compartment(cx, cmp_global, &klass); -+ GJS_JSAPI_RETURN_CONVENTION -+ static JSObject* create_with_compartment(JSContext* cx, -+ JS::HandleObject cmp_global) { -+ return GjsBaseGlobal::create_with_compartment( -+ cx, cmp_global, &klass, {}, get_internal_principals()); - } - -+ GJS_JSAPI_RETURN_CONVENTION - static bool define_properties(JSContext* cx, JS::HandleObject global, - const char* realm_name, - const char* bootstrap_script -diff -ruN cjs-6.2.0-orig/cjs/global.h cjs-6.2.0/cjs/global.h ---- cjs-6.2.0-orig/cjs/global.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/global.h 2024-10-14 18:35:57.000000000 +0200 -@@ -8,12 +8,12 @@ - - #include - -+#include -+ - #include // for Handle - #include - #include - --#include -- - #include "cjs/macros.h" - - namespace JS { -diff -ruN cjs-6.2.0-orig/cjs/importer.cpp cjs-6.2.0/cjs/importer.cpp ---- cjs-6.2.0-orig/cjs/importer.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/importer.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -24,9 +24,10 @@ - #include - #include // for JS_ReportOutOfMemory, JSEXN_ERR - #include -+#include // for StackGCVector - #include // for CurrentGlobalOrNull --#include // for PropertyKey --#include // for GetClass -+#include // for PropertyKey -+#include // for GetClass - #include - #include - #include -@@ -265,26 +266,21 @@ - * gjs_import_native_module: - * @cx: the #JSContext - * @importer: the root importer -- * @parse_name: Name under which the module was registered with -- * add(), should be in the format as returned by -- * g_file_get_parse_name() -+ * @id_str: Name under which the module was registered with add() - * - * Imports a builtin native-code module so that it is available to JS code as -- * `imports[parse_name]`. -+ * `imports[id_str]`. - * - * Returns: true on success, false if an exception was thrown. - */ --bool --gjs_import_native_module(JSContext *cx, -- JS::HandleObject importer, -- const char *parse_name) --{ -- gjs_debug(GJS_DEBUG_IMPORTER, "Importing '%s'", parse_name); -+bool gjs_import_native_module(JSContext* cx, JS::HandleObject importer, -+ const char* id_str) { -+ gjs_debug(GJS_DEBUG_IMPORTER, "Importing '%s'", id_str); - - JS::RootedObject native_registry( - cx, gjs_get_native_registry(JS::CurrentGlobalOrNull(cx))); - -- JS::RootedId id(cx, gjs_intern_string_to_id(cx, parse_name)); -+ JS::RootedId id(cx, gjs_intern_string_to_id(cx, id_str)); - if (id.isVoid()) - return false; - -@@ -293,12 +289,12 @@ - return false; - - if (!module && -- (!Gjs::NativeModuleRegistry::get().load(cx, parse_name, &module) || -+ (!Gjs::NativeModuleDefineFuncs::get().define(cx, id_str, &module) || - !gjs_global_registry_set(cx, native_registry, id, module))) - return false; - -- return define_meta_properties(cx, module, nullptr, parse_name, importer) && -- JS_DefineProperty(cx, importer, parse_name, module, -+ return define_meta_properties(cx, module, nullptr, id_str, importer) && -+ JS_DefineProperty(cx, importer, id_str, module, - GJS_MODULE_PROP_FLAGS); - } - -@@ -496,7 +492,7 @@ - - /* First try importing an internal module like gi */ - if (parent.isNull() && -- Gjs::NativeModuleRegistry::get().is_registered(name.get())) { -+ Gjs::NativeModuleDefineFuncs::get().is_registered(name.get())) { - if (!gjs_import_native_module(context, obj, name.get())) - return false; - -@@ -676,7 +672,8 @@ - while (true) { - GFileInfo *info; - GFile *file; -- if (!g_file_enumerator_iterate(direnum, &info, &file, NULL, NULL)) -+ if (!direnum || -+ !g_file_enumerator_iterate(direnum, &info, &file, NULL, NULL)) - break; - if (info == NULL || file == NULL) - break; -@@ -896,7 +893,7 @@ - /* API users can replace this property from JS, is the idea */ - if (!gjs_define_string_array( - context, importer, "searchPath", search_paths, -- /* settable (no READONLY) but not deleteable (PERMANENT) */ -+ // settable (no READONLY) but not deletable (PERMANENT) - JSPROP_PERMANENT | JSPROP_RESOLVING)) - return nullptr; - -diff -ruN cjs-6.2.0-orig/cjs/internal.cpp cjs-6.2.0/cjs/internal.cpp ---- cjs-6.2.0-orig/cjs/internal.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/internal.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -1,8 +1,6 @@ - // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later - // SPDX-FileCopyrightText: 2020 Evan Welsh - --#include "cjs/internal.h" -- - #include - - #include // for size_t -@@ -41,6 +39,7 @@ - #include "cjs/context-private.h" - #include "cjs/engine.h" - #include "cjs/global.h" -+#include "cjs/internal.h" - #include "cjs/jsapi-util-args.h" - #include "cjs/jsapi-util.h" - #include "cjs/macros.h" -@@ -346,7 +345,15 @@ - if (!path) - return false; - -- if (!JS_DefineProperty(cx, return_obj, "uri", string_arg, -+ GjsAutoChar no_query_str = -+ g_uri_to_string_partial(parsed, G_URI_HIDE_QUERY); -+ JS::RootedString uri_no_query{cx, JS_NewStringCopyZ(cx, no_query_str)}; -+ if (!uri_no_query) -+ return false; -+ -+ if (!JS_DefineProperty(cx, return_obj, "uri", uri_no_query, -+ JSPROP_ENUMERATE) || -+ !JS_DefineProperty(cx, return_obj, "uriWithQuery", string_arg, - JSPROP_ENUMERATE) || - !JS_DefineProperty(cx, return_obj, "scheme", scheme, - JSPROP_ENUMERATE) || -@@ -370,12 +377,10 @@ - return handle_wrong_args(cx); - - GjsAutoUnref module_file = g_file_new_for_uri(uri.get()); -- GjsAutoUnref module_parent_file = g_file_get_parent(module_file); - -- if (module_parent_file) { -- GjsAutoUnref output = g_file_resolve_relative_path( -- module_parent_file, relative_path.get()); -- GjsAutoChar output_uri = g_file_get_uri(output); -+ if (module_file) { -+ GjsAutoChar output_uri = g_uri_resolve_relative( -+ uri.get(), relative_path.get(), G_URI_FLAGS_NONE, nullptr); - - JS::ConstUTF8CharsZ uri_chars(output_uri, strlen(output_uri)); - JS::RootedString retval(cx, JS_NewStringCopyUTF8Z(cx, uri_chars)); -@@ -511,7 +516,7 @@ - /* etag_out = */ nullptr, &error)) { - GjsAutoChar uri = g_file_get_uri(G_FILE(file)); - gjs_throw_custom(promise->cx, JSEXN_ERR, "ImportError", -- "Unable to load file from: %s (%s)", uri.get(), -+ "Unable to load file async from: %s (%s)", uri.get(), - error->message); - promise->reject_with_pending_exception(); - return; -diff -ruN cjs-6.2.0-orig/cjs/jsapi-class.h cjs-6.2.0/cjs/jsapi-class.h ---- cjs-6.2.0-orig/cjs/jsapi-class.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/jsapi-class.h 2024-10-14 18:35:57.000000000 +0200 -@@ -10,9 +10,10 @@ - #include - #include - -+#include // for JSNative - #include -+#include - --#include "gi/wrapperutils.h" - #include "cjs/global.h" - #include "cjs/jsapi-util.h" - #include "cjs/macros.h" -@@ -35,14 +36,23 @@ - const JS::HandleValueArray& args); - - GJS_JSAPI_RETURN_CONVENTION --bool gjs_define_property_dynamic(JSContext *cx, -- JS::HandleObject proto, -- const char *prop_name, -- const char *func_namespace, -- JSNative getter, -- JSNative setter, -- JS::HandleValue private_slot, -- unsigned flags); -+bool gjs_define_property_dynamic(JSContext*, JS::HandleObject proto, -+ const char* prop_name, JS::HandleId, -+ const char* func_namespace, JSNative getter, -+ JS::HandleValue getter_slot, JSNative setter, -+ JS::HandleValue setter_slot, unsigned flags); -+ -+GJS_JSAPI_RETURN_CONVENTION -+inline bool gjs_define_property_dynamic(JSContext* cx, JS::HandleObject proto, -+ const char* prop_name, JS::HandleId id, -+ const char* func_namespace, -+ JSNative getter, JSNative setter, -+ JS::HandleValue private_slot, -+ unsigned flags) { -+ return gjs_define_property_dynamic(cx, proto, prop_name, id, func_namespace, -+ getter, private_slot, setter, -+ private_slot, flags); -+} - - [[nodiscard]] JS::Value gjs_dynamic_property_private_slot( - JSObject* accessor_obj); -diff -ruN cjs-6.2.0-orig/cjs/jsapi-dynamic-class.cpp cjs-6.2.0/cjs/jsapi-dynamic-class.cpp ---- cjs-6.2.0-orig/cjs/jsapi-dynamic-class.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/jsapi-dynamic-class.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -194,31 +194,32 @@ - * - * Returns: %true on success, %false if an exception is pending on @cx. - */ --bool --gjs_define_property_dynamic(JSContext *cx, -- JS::HandleObject proto, -- const char *prop_name, -- const char *func_namespace, -- JSNative getter, -- JSNative setter, -- JS::HandleValue private_slot, -- unsigned flags) --{ -+bool gjs_define_property_dynamic(JSContext* cx, JS::HandleObject proto, -+ const char* prop_name, JS::HandleId id, -+ const char* func_namespace, JSNative getter, -+ JS::HandleValue getter_slot, JSNative setter, -+ JS::HandleValue setter_slot, unsigned flags) { - GjsAutoChar getter_name = g_strconcat(func_namespace, "_get::", prop_name, nullptr); - GjsAutoChar setter_name = g_strconcat(func_namespace, "_set::", prop_name, nullptr); - -- JS::RootedObject getter_obj(cx, -- define_native_accessor_wrapper(cx, getter, 0, getter_name, private_slot)); -+ JS::RootedObject getter_obj( -+ cx, define_native_accessor_wrapper(cx, getter, 0, getter_name, -+ getter_slot)); - if (!getter_obj) - return false; - -- JS::RootedObject setter_obj(cx, -- define_native_accessor_wrapper(cx, setter, 1, setter_name, private_slot)); -+ JS::RootedObject setter_obj( -+ cx, define_native_accessor_wrapper(cx, setter, 1, setter_name, -+ setter_slot)); - if (!setter_obj) - return false; - -- return JS_DefineProperty(cx, proto, prop_name, getter_obj, setter_obj, -- flags); -+ if (id.isVoid()) { -+ return JS_DefineProperty(cx, proto, prop_name, getter_obj, setter_obj, -+ flags); -+ } -+ -+ return JS_DefinePropertyById(cx, proto, id, getter_obj, setter_obj, flags); - } - - /** -diff -ruN cjs-6.2.0-orig/cjs/jsapi-util-args.h cjs-6.2.0/cjs/jsapi-util-args.h ---- cjs-6.2.0-orig/cjs/jsapi-util-args.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/jsapi-util-args.h 2024-10-14 18:35:57.000000000 +0200 -@@ -22,6 +22,7 @@ - #include - #include - #include // for UniqueChars -+#include - #include // for GenericErrorResult - #include // IWYU pragma: keep - -diff -ruN cjs-6.2.0-orig/cjs/jsapi-util-error.cpp cjs-6.2.0/cjs/jsapi-util-error.cpp ---- cjs-6.2.0-orig/cjs/jsapi-util-error.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/jsapi-util-error.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -12,6 +12,7 @@ - - #include - #include -+#include - #include - #include - #include // for GCHashSet -@@ -113,8 +114,10 @@ - &source_string); - uint32_t line_num; - JS::GetSavedFrameLine(cx, nullptr, saved_frame, &line_num); -- uint32_t column_num; -- JS::GetSavedFrameColumn(cx, nullptr, saved_frame, &column_num); -+ JS::TaggedColumnNumberOneOrigin tagged_column; -+ JS::GetSavedFrameColumn(cx, nullptr, saved_frame, &tagged_column); -+ JS::ColumnNumberOneOrigin column_num{tagged_column.toLimitedColumnNumber()}; -+ // asserts that this isn't a WASM frame - - JS::RootedValue v_exc{cx}; - if (!JS::CreateError(cx, error_kind, saved_frame, source_string, line_num, -@@ -216,33 +219,30 @@ - } - - /** -- * gjs_format_stack_trace: -+ * format_saved_frame: - * @cx: the #JSContext - * @saved_frame: a SavedFrame #JSObject -+ * @indent: (optional): spaces of indentation - * -- * Formats a stack trace as a string in filename encoding, suitable for -- * printing to stderr. Ignores any errors. -+ * Formats a stack trace as a UTF-8 string. If there are errors, ignores them -+ * and returns null. -+ * If you print this to stderr, you will need to re-encode it in filename -+ * encoding with g_filename_from_utf8(). - * -- * Returns: unique string in filename encoding, or nullptr if no stack trace -+ * Returns (nullable) (transfer full): unique string - */ --GjsAutoChar --gjs_format_stack_trace(JSContext *cx, -- JS::HandleObject saved_frame) --{ -+JS::UniqueChars format_saved_frame(JSContext* cx, JS::HandleObject saved_frame, -+ size_t indent /* = 0 */) { - JS::AutoSaveExceptionState saved_exc(cx); - - JS::RootedString stack_trace(cx); - JS::UniqueChars stack_utf8; -- if (JS::BuildStackString(cx, nullptr, saved_frame, &stack_trace, 2)) -+ if (JS::BuildStackString(cx, nullptr, saved_frame, &stack_trace, indent)) - stack_utf8 = JS_EncodeStringToUTF8(cx, stack_trace); - - saved_exc.restore(); - -- if (!stack_utf8) -- return nullptr; -- -- return g_filename_from_utf8(stack_utf8.get(), -1, nullptr, nullptr, -- nullptr); -+ return stack_utf8; - } - - void gjs_warning_reporter(JSContext*, JSErrorReport* report) { -@@ -254,8 +254,7 @@ - if (gjs_environment_variable_is_set("GJS_ABORT_ON_OOM") && - !report->isWarning() && report->errorNumber == 137) { - /* 137, JSMSG_OUT_OF_MEMORY */ -- g_error("GJS ran out of memory at %s: %i.", -- report->filename, -+ g_error("GJS ran out of memory at %s: %i.", report->filename.c_str(), - report->lineno); - } - -@@ -277,6 +276,6 @@ - level = G_LOG_LEVEL_WARNING; - } - -- g_log(G_LOG_DOMAIN, level, "JS %s: [%s %d]: %s", warning, report->filename, -- report->lineno, report->message().c_str()); -+ g_log(G_LOG_DOMAIN, level, "JS %s: [%s %d]: %s", warning, -+ report->filename.c_str(), report->lineno, report->message().c_str()); - } -diff -ruN cjs-6.2.0-orig/cjs/jsapi-util-root.h cjs-6.2.0/cjs/jsapi-util-root.h ---- cjs-6.2.0-orig/cjs/jsapi-util-root.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/jsapi-util-root.h 2024-09-16 22:32:54.000000000 +0200 -@@ -11,84 +11,57 @@ - #include // for nullptr_t - #include - #include --#include // for enable_if_t, is_pointer - - #include - -+#include - #include -+#include // for ExposeObjectToActiveJS, GetGCThingZone -+#include // for SafelyInitialized - #include - #include - - #include "util/log.h" - -+namespace JS { template struct GCPolicy; } -+ - /* jsapi-util-root.h - Utilities for dealing with the lifetime and ownership of - * JS Objects and other things that can be collected by the garbage collector - * (collectively called "GC things.") - * -- * GjsMaybeOwned is a multi-purpose wrapper for a GC thing of type T. You can -+ * GjsMaybeOwned is a multi-purpose wrapper for a JSObject. You can - * wrap a thing in one of three ways: - * -- * - trace the thing (tie it to the lifetime of another GC thing), -- * - root the thing (keep it alive as long as the wrapper is in existence), -- * - maintain a weak pointer to the thing (not keep it alive at all and have it -+ * - trace the object (tie it to the lifetime of another GC thing), -+ * - root the object (keep it alive as long as the wrapper is in existence), -+ * - maintain a weak pointer to the object (not keep it alive at all and have it - * possibly be finalized out from under you). - * -- * To trace or maintain a weak pointer, simply assign a thing of type T to the -+ * To trace or maintain a weak pointer, simply assign an object to the - * GjsMaybeOwned wrapper. For tracing, you must call the trace() method when - * your other GC thing is traced. - * - * Rooting requires a JSContext so can't just assign a thing of type T. Instead - * you need to call the root() method to set up rooting. - * -- * If the thing is rooted, it will be unrooted either when the GjsMaybeOwned is -- * destroyed, or when the JSContext is destroyed. In the latter case, you can -- * get an optional notification by registering a callback in the PrivateContext. -+ * If the thing is rooted, it will be unrooted when the GjsMaybeOwned is -+ * destroyed. - * - * To switch between one of the three modes, you must first call reset(). This -- * drops all references to any GC thing and leaves the GjsMaybeOwned in the -+ * drops all references to any object and leaves the GjsMaybeOwned in the - * same state as if it had just been constructed. - */ - --/* This struct contains operations that must be implemented differently -- * depending on the type of the GC thing. Add more types as necessary. If an -- * implementation is never used, it's OK to leave it out. The compiler will -- * complain if it's used somewhere but not instantiated here. -- */ --template --struct GjsHeapOperation { -- [[nodiscard]] static bool update_after_gc(JS::Heap* location); -- static void expose_to_js(JS::Heap& thing); --}; -- --template<> --struct GjsHeapOperation { -- [[nodiscard]] static bool update_after_gc(JSTracer* trc, -- JS::Heap* location) { -- JS_UpdateWeakPointerAfterGC(trc, location); -- return (location->unbarrieredGet() == nullptr); -- } -- -- static void expose_to_js(JS::Heap& thing) { -- JSObject *obj = thing.unbarrieredGet(); -- /* If the object has been swept already, then the zone is nullptr */ -- if (!obj || !JS::GetGCThingZone(JS::GCCellPtr(obj))) -- return; -- if (!JS::RuntimeHeapIsCollecting()) -- JS::ExposeObjectToActiveJS(obj); -- } --}; -- - /* GjsMaybeOwned is intended for use as a member of classes that are allocated - * on the heap. Do not allocate GjsMaybeOwned on the stack, and do not allocate - * any instances of classes that have it as a member on the stack either. */ --template - class GjsMaybeOwned { - private: - /* m_root value controls which of these members we can access. When switching - * from one to the other, be careful to call the constructor and destructor - * of JS::Heap, since they use post barriers. */ -- JS::Heap m_heap; -- std::unique_ptr> m_root; -+ JS::Heap m_heap; -+ std::unique_ptr m_root; - - /* No-op unless GJS_VERBOSE_ENABLE_LIFECYCLE is defined to 1. */ - inline void debug(const char* what GJS_USED_VERBOSE_LIFECYCLE) { -@@ -104,7 +77,7 @@ - - m_root.reset(); - -- new (&m_heap) JS::Heap(); -+ new (&m_heap) JS::Heap(); - } - - public: -@@ -116,68 +89,61 @@ - debug("destroyed"); - } - -- /* To access the GC thing, call get(). In many cases you can just use the -- * GjsMaybeOwned wrapper in place of the GC thing itself due to the implicit -- * cast operator. But if you want to call methods on the GC thing, for -- * example if it's a JS::Value, you have to use get(). */ -- [[nodiscard]] constexpr const T get() const { -+ // COMPAT: constexpr in C++23 -+ [[nodiscard]] JSObject* get() const { - return m_root ? m_root->get() : m_heap.get(); - } -- constexpr operator const T() const { return get(); } - -- /* Use debug_addr() only for debug logging, because it is unbarriered. */ -- template -- [[nodiscard]] constexpr const void* debug_addr( -- std::enable_if_t>* = nullptr) const { -+ // Use debug_addr() only for debug logging, because it is unbarriered. -+ // COMPAT: constexpr in C++23 -+ [[nodiscard]] const void* debug_addr() const { - return m_root ? m_root->get() : m_heap.unbarrieredGet(); - } - -- constexpr bool operator==(const T& other) const { -+ // COMPAT: constexpr in C++23 -+ bool operator==(JSObject* other) const { - if (m_root) - return m_root->get() == other; - return m_heap == other; - } -- constexpr bool operator!=(const T& other) const { -- return !(*this == other); -- } -+ bool operator!=(JSObject* other) const { return !(*this == other); } - -- /* We can access the pointer without a read barrier if the only thing we -- * are doing with it is comparing it to nullptr. */ -- constexpr bool operator==(std::nullptr_t) const { -+ // We can access the pointer without a read barrier if the only thing we are -+ // are doing with it is comparing it to nullptr. -+ // COMPAT: constexpr in C++23 -+ bool operator==(std::nullptr_t) const { - if (m_root) - return m_root->get() == nullptr; - return m_heap.unbarrieredGet() == nullptr; - } -- constexpr bool operator!=(std::nullptr_t) const { -- return !(*this == nullptr); -- } -- -- /* Likewise the truth value does not require a read barrier */ -- constexpr explicit operator bool() const { return *this != nullptr; } -+ bool operator!=(std::nullptr_t) const { return !(*this == nullptr); } - -- /* You can get a Handle if the thing is rooted, so that you can use this -- * wrapper with stack rooting. However, you must not do this if the -- * JSContext can be destroyed while the Handle is live. */ -- [[nodiscard]] constexpr JS::Handle handle() { -+ // Likewise the truth value does not require a read barrier -+ // COMPAT: constexpr in C++23 -+ explicit operator bool() const { return *this != nullptr; } -+ -+ // You can get a Handle if the thing is rooted, so that you can use this -+ // wrapper with stack rooting. However, you must not do this if the -+ // JSContext can be destroyed while the Handle is live. */ -+ // COMPAT: constexpr in C++23 -+ [[nodiscard]] JS::HandleObject handle() { - g_assert(m_root); - return *m_root; - } - - /* Roots the GC thing. You must not use this if you're already using the - * wrapper to store a non-rooted GC thing. */ -- void root(JSContext* cx, const T& thing) { -+ void root(JSContext* cx, JSObject* thing) { - debug("root()"); - g_assert(!m_root); -- g_assert(m_heap.get() == JS::SafelyInitialized::create()); -+ g_assert(!m_heap); - m_heap.~Heap(); -- m_root = std::make_unique>(cx, thing); -+ m_root = std::make_unique(cx, thing); - } - - /* You can only assign directly to the GjsMaybeOwned wrapper in the - * non-rooted case. */ -- void -- operator=(const T& thing) -- { -+ void operator=(JSObject* thing) { - g_assert(!m_root); - m_heap = thing; - } -@@ -188,13 +154,18 @@ - void prevent_collection() { - debug("prevent_collection()"); - g_assert(!m_root); -- GjsHeapOperation::expose_to_js(m_heap); -+ JSObject* obj = m_heap.unbarrieredGet(); -+ // If the object has been swept already, then the zone is nullptr -+ if (!obj || !JS::GetGCThingZone(JS::GCCellPtr(obj))) -+ return; -+ if (!JS::RuntimeHeapIsCollecting()) -+ JS::ExposeObjectToActiveJS(obj); - } - - void reset() { - debug("reset()"); - if (!m_root) { -- m_heap = JS::SafelyInitialized::create(); -+ m_heap = nullptr; - return; - } - -@@ -207,7 +178,7 @@ - - /* Prevent the thing from being garbage collected while it is in neither - * m_heap nor m_root */ -- JS::Rooted thing(cx, m_heap); -+ JS::RootedObject thing{cx, m_heap}; - - reset(); - root(cx, thing); -@@ -220,7 +191,7 @@ - - /* Prevent the thing from being garbage collected while it is in neither - * m_heap nor m_root */ -- JS::Rooted thing(cx, *m_root); -+ JS::RootedObject thing{cx, *m_root}; - - reset(); - m_heap = thing; -@@ -235,7 +206,7 @@ - { - debug("trace()"); - g_assert(!m_root); -- JS::TraceEdge(tracer, &m_heap, name); -+ JS::TraceEdge(tracer, &m_heap, name); - } - - /* If not tracing, then you must call this method during GC in order to -@@ -244,10 +215,44 @@ - bool update_after_gc(JSTracer* trc) { - debug("update_after_gc()"); - g_assert(!m_root); -- return GjsHeapOperation::update_after_gc(trc, &m_heap); -+ JS_UpdateWeakPointerAfterGC(trc, &m_heap); -+ return !m_heap; -+ } -+ -+ // COMPAT: constexpr in C++23 -+ [[nodiscard]] bool rooted() const { return m_root != nullptr; } -+}; -+ -+namespace Gjs { -+ -+template -+class WeakPtr : public JS::Heap { -+ public: -+ using JS::Heap::Heap; -+ using JS::Heap::operator=; -+}; -+ -+} // namespace Gjs -+ -+namespace JS { -+ -+template -+struct GCPolicy> { -+ static void trace(JSTracer* trc, Gjs::WeakPtr* thingp, -+ const char* name) { -+ return JS::TraceEdge(trc, thingp, name); - } - -- [[nodiscard]] constexpr bool rooted() const { return m_root != nullptr; } -+ static bool traceWeak(JSTracer* trc, Gjs::WeakPtr* thingp) { -+ return js::gc::TraceWeakEdge(trc, thingp); -+ } -+ -+ static bool needsSweep(JSTracer* trc, const Gjs::WeakPtr* thingp) { -+ Gjs::WeakPtr thing{*thingp}; -+ return !js::gc::TraceWeakEdge(trc, &thing); -+ } - }; - -+} // namespace JS -+ - #endif // GJS_JSAPI_UTIL_ROOT_H_ -diff -ruN cjs-6.2.0-orig/cjs/jsapi-util-string.cpp cjs-6.2.0/cjs/jsapi-util-string.cpp ---- cjs-6.2.0-orig/cjs/jsapi-util-string.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/jsapi-util-string.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -116,7 +116,7 @@ - return false; - - size_t length = JS::GetDeflatedUTF8StringLength(linear); -- char* bytes = js_pod_arena_malloc(js::StringBufferArena, length + 1); -+ char* bytes = js_pod_malloc(length + 1); - if (!bytes) - return false; - -@@ -590,7 +590,7 @@ - - if (js::IsFunctionObject(obj)) { - JSFunction* fun = JS_GetObjectFunction(obj); -- JSString* display_name = JS_GetFunctionDisplayId(fun); -+ JSString* display_name = JS_GetMaybePartialFunctionDisplayId(fun); - if (display_name && JS_GetStringLength(display_name)) - out << " // for GetClass - #include - #include --#include // for BuildStackString - #include - #include - #include -@@ -40,6 +39,7 @@ - #include // for JS_InstanceOf - #include // for ProtoKeyToClass - #include // for JSProto_InternalError, JSProto_SyntaxError -+#include - - #include "cjs/atoms.h" - #include "cjs/context-private.h" -@@ -262,6 +262,44 @@ - return JS::ToString(cx, exc); - } - -+// Helper function: format the error's stack property. -+static std::string format_exception_stack(JSContext* cx, JS::HandleObject exc) { -+ JS::AutoSaveExceptionState saved_exc(cx); -+ auto restore = -+ mozilla::MakeScopeExit([&saved_exc]() { saved_exc.restore(); }); -+ -+ const GjsAtoms& atoms = GjsContextPrivate::atoms(cx); -+ std::ostringstream out; -+ -+ // Check both the internal SavedFrame object and the stack property. -+ // GErrors will not have the former, and internal errors will not -+ // have the latter. -+ JS::RootedObject saved_frame{cx, JS::ExceptionStackOrNull(exc)}; -+ if (saved_frame) { -+ JS::UniqueChars utf8_stack{format_saved_frame(cx, saved_frame)}; -+ if (!utf8_stack) -+ return {}; -+ out << '\n' << utf8_stack.get(); -+ return out.str(); -+ } -+ -+ JS::RootedValue stack{cx}; -+ if (!JS_GetPropertyById(cx, exc, atoms.stack(), &stack) || !stack.isString()) -+ return {}; -+ -+ JS::RootedString str{cx, stack.toString()}; -+ bool is_empty; -+ if (!JS_StringEqualsLiteral(cx, str, "", &is_empty) || is_empty) -+ return {}; -+ -+ JS::UniqueChars utf8_stack{JS_EncodeStringToUTF8(cx, str)}; -+ if (!utf8_stack) -+ return {}; -+ -+ out << '\n' << utf8_stack.get(); -+ return out.str(); -+} -+ - // Helper function: format the file name, line number, and column number where a - // SyntaxError occurred. - static std::string format_syntax_error_location(JSContext* cx, -@@ -311,25 +349,7 @@ - std::ostringstream out; - const GjsAtoms& atoms = GjsContextPrivate::atoms(cx); - -- JS::UniqueChars utf8_stack; -- // Check both the internal SavedFrame object and the stack property. -- // GErrors will not have the former, and internal errors will not -- // have the latter. -- JS::RootedObject saved_frame(cx, JS::ExceptionStackOrNull(exc_obj)); -- JS::RootedString str(cx); -- if (saved_frame) { -- JS::BuildStackString(cx, nullptr, saved_frame, &str, 0); -- } else { -- JS::RootedValue stack(cx); -- if (JS_GetPropertyById(cx, exc_obj, atoms.stack(), &stack) && -- stack.isString()) -- str = stack.toString(); -- } -- if (str) -- utf8_stack = JS_EncodeStringToUTF8(cx, str); -- if (utf8_stack) -- out << '\n' << utf8_stack.get(); -- JS_ClearPendingException(cx); -+ out << format_exception_stack(cx, exc_obj); - - JS::RootedValue v_cause(cx); - if (!JS_GetPropertyById(cx, exc_obj, atoms.cause(), &v_cause)) -@@ -347,7 +367,7 @@ - return out.str(); // out of memory, just stop here - } - -- out << "Caused by: "; -+ out << "\nCaused by: "; - JS::RootedString exc_str(cx, exception_to_string(cx, v_cause)); - if (exc_str) { - JS::UniqueChars utf8_exception = JS_EncodeStringToUTF8(cx, exc_str); -@@ -393,7 +413,8 @@ - // file name, line number, and column number from the exception. - // We assume that syntax errors have no cause property, and are not the - // cause of other exceptions, so no recursion. -- out << format_syntax_error_location(cx, exc_obj); -+ out << format_syntax_error_location(cx, exc_obj) -+ << format_exception_stack(cx, exc_obj); - return out.str(); - } - -diff -ruN cjs-6.2.0-orig/cjs/jsapi-util.h cjs-6.2.0/cjs/jsapi-util.h ---- cjs-6.2.0-orig/cjs/jsapi-util.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/jsapi-util.h 2024-10-14 18:35:57.000000000 +0200 -@@ -549,8 +549,8 @@ - void gjs_gc_if_needed(JSContext *cx); - - GJS_JSAPI_RETURN_CONVENTION --GjsAutoChar gjs_format_stack_trace(JSContext *cx, -- JS::HandleObject saved_frame); -+JS::UniqueChars format_saved_frame(JSContext* cx, JS::HandleObject saved_frame, -+ size_t indent = 0); - - /* Overloaded functions, must be outside G_DECLS. More types are intended to be - * added as the opportunity arises. */ -@@ -600,6 +600,7 @@ - [[nodiscard]] std::string gjs_debug_string(JSString* str); - [[nodiscard]] std::string gjs_debug_symbol(JS::Symbol* const sym); - [[nodiscard]] std::string gjs_debug_object(JSObject* obj); -+[[nodiscard]] std::string gjs_debug_callable(JSObject* callable); - [[nodiscard]] std::string gjs_debug_value(JS::Value v); - [[nodiscard]] std::string gjs_debug_id(jsid id); - -diff -ruN cjs-6.2.0-orig/cjs/mem-private.h cjs-6.2.0/cjs/mem-private.h ---- cjs-6.2.0-orig/cjs/mem-private.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/mem-private.h 2024-09-16 22:32:54.000000000 +0200 -@@ -6,6 +6,8 @@ - #ifndef GJS_MEM_PRIVATE_H_ - #define GJS_MEM_PRIVATE_H_ - -+#include -+ - #include // for size_t - - #include -diff -ruN cjs-6.2.0-orig/cjs/mem.cpp cjs-6.2.0/cjs/mem.cpp ---- cjs-6.2.0-orig/cjs/mem.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/mem.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -2,6 +2,8 @@ - // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later - // SPDX-FileCopyrightText: 2008 litl, LLC - -+#include -+ - #include - - #include -diff -ruN cjs-6.2.0-orig/cjs/mem.h cjs-6.2.0/cjs/mem.h ---- cjs-6.2.0-orig/cjs/mem.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/mem.h 2024-10-14 18:35:57.000000000 +0200 -@@ -8,7 +8,7 @@ - #define GJS_MEM_H_ - - #if !defined(INSIDE_GJS_H) && !defined(GJS_COMPILATION) --# error "Only can be included directly." -+# error "Only can be included directly." - #endif - - #include /* IWYU pragma: keep */ -diff -ruN cjs-6.2.0-orig/cjs/module.cpp cjs-6.2.0/cjs/module.cpp ---- cjs-6.2.0-orig/cjs/module.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/module.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -7,7 +7,10 @@ - #include // for size_t - #include - -+#include // for vector -+ - #include -+#include - #include - - #include -@@ -438,7 +441,8 @@ - } - - JS::RootedObject native_obj(cx); -- if (!Gjs::NativeModuleRegistry::get().load(cx, id.get(), &native_obj)) { -+ if (!Gjs::NativeModuleDefineFuncs::get().define(cx, id.get(), -+ &native_obj)) { - gjs_throw(cx, "Failed to load native module: %s", id.get()); - return false; - } -@@ -471,9 +475,9 @@ - &private_ref.toObject()); - - const GjsAtoms& atoms = GjsContextPrivate::atoms(cx); -- JS::RootedValue v_uri(cx); -- if (!JS_GetPropertyById(cx, module, atoms.uri(), &v_uri) || -- !JS_DefinePropertyById(cx, meta, atoms.url(), v_uri, -+ JS::RootedValue specifier{cx}; -+ if (!JS_GetProperty(cx, module, "id", &specifier) || -+ !JS_DefinePropertyById(cx, meta, atoms.url(), specifier, - GJS_MODULE_PROP_FLAGS)) - return false; - -@@ -492,6 +496,47 @@ - return true; - } - -+// Canonicalize specifier so that differently-spelled specifiers referring to -+// the same module don't result in duplicate entries in the registry -+static bool canonicalize_specifier(JSContext* cx, -+ JS::MutableHandleString specifier) { -+ JS::UniqueChars specifier_utf8 = JS_EncodeStringToUTF8(cx, specifier); -+ if (!specifier_utf8) -+ return false; -+ -+ GjsAutoChar scheme, host, path, query; -+ if (!g_uri_split(specifier_utf8.get(), G_URI_FLAGS_NONE, scheme.out(), -+ nullptr, host.out(), nullptr, path.out(), query.out(), -+ nullptr, nullptr)) -+ return false; -+ -+ if (g_strcmp0(scheme, "gi")) { -+ // canonicalize without the query portion to avoid it being encoded -+ GjsAutoChar for_file_uri = -+ g_uri_join(G_URI_FLAGS_NONE, scheme.get(), nullptr, host.get(), -1, -+ path.get(), nullptr, nullptr); -+ GjsAutoUnref file = g_file_new_for_uri(for_file_uri.get()); -+ for_file_uri = g_file_get_uri(file); -+ host.reset(); -+ path.reset(); -+ if (!g_uri_split(for_file_uri.get(), G_URI_FLAGS_NONE, nullptr, nullptr, -+ host.out(), nullptr, path.out(), nullptr, nullptr, -+ nullptr)) -+ return false; -+ } -+ -+ GjsAutoChar canonical_specifier = -+ g_uri_join(G_URI_FLAGS_NONE, scheme.get(), nullptr, host.get(), -1, -+ path.get(), query.get(), nullptr); -+ JS::ConstUTF8CharsZ chars{canonical_specifier, strlen(canonical_specifier)}; -+ JS::RootedString new_specifier{cx, JS_NewStringCopyUTF8Z(cx, chars)}; -+ if (!new_specifier) -+ return false; -+ -+ specifier.set(new_specifier); -+ return true; -+} -+ - /** - * gjs_module_resolve: - * -@@ -518,6 +563,9 @@ - g_assert(v_loader.isObject()); - JS::RootedObject loader(cx, &v_loader.toObject()); - -+ if (!canonicalize_specifier(cx, &specifier)) -+ return nullptr; -+ - JS::RootedValueArray<2> args(cx); - args[0].set(importingModulePriv); - args[1].setString(specifier); -@@ -535,23 +583,6 @@ - return &result.toObject(); - } - --// Note: exception is never pending after this function finishes, even if it --// returns null. The return value is intended to be passed to --// JS::FinishDynamicModuleImport(). --static JSObject* reject_new_promise_with_pending_exception(JSContext* cx) { -- JS::ExceptionStack stack{cx}; -- if (!JS::StealPendingExceptionStack(cx, &stack)) { -- gjs_log_exception(cx); -- return nullptr; -- } -- JS::RootedObject rejected{cx, JS::NewPromiseObject(cx, nullptr)}; -- if (!rejected || !JS::RejectPromise(cx, rejected, stack.exception())) { -- gjs_log_exception(cx); -- return nullptr; -- } -- return rejected; --} -- - // Call JS::FinishDynamicModuleImport() with the values stashed in the function. - // Can fail in JS::FinishDynamicModuleImport(), but will assert if anything - // fails in fetching the stashed values, since that would be a serious GJS bug. -@@ -593,12 +624,9 @@ - // case we must not call JS::FinishDynamicModuleImport(). - GJS_JSAPI_RETURN_CONVENTION - static bool fail_import(JSContext* cx, const JS::CallArgs& args) { -- if (!JS_IsExceptionPending(cx)) -- return false; -- -- JS::RootedObject rejected_promise{ -- cx, reject_new_promise_with_pending_exception(cx)}; -- return finish_import(cx, rejected_promise, args); -+ if (JS_IsExceptionPending(cx)) -+ return finish_import(cx, nullptr, args); -+ return false; - } - - GJS_JSAPI_RETURN_CONVENTION -@@ -607,16 +635,12 @@ - - gjs_debug(GJS_DEBUG_IMPORTER, "Async import promise rejected"); - -- // Reject a new promise with the rejection value of the async import -- // promise, so that FinishDynamicModuleImport will reject the -- // internal_promise with it. -- JS::RootedObject rejected{cx, JS::NewPromiseObject(cx, nullptr)}; -- if (!rejected || !JS::RejectPromise(cx, rejected, args.get(0))) { -- gjs_log_exception(cx); -- return finish_import(cx, nullptr, args); -- } -+ // Throw the value that the promise is rejected with, so that -+ // FinishDynamicModuleImport will reject the internal_promise with it. -+ JS_SetPendingException(cx, args.get(0), -+ JS::ExceptionStackBehavior::DoNotCapture); - -- return finish_import(cx, rejected, args); -+ return finish_import(cx, nullptr, args); - } - - GJS_JSAPI_RETURN_CONVENTION -@@ -660,6 +684,9 @@ - JS::RootedString specifier( - cx, JS::GetModuleRequestSpecifier(cx, module_request)); - -+ if (!canonicalize_specifier(cx, &specifier)) -+ return false; -+ - JS::RootedObject callback_data(cx, JS_NewPlainObject(cx)); - if (!callback_data || - !JS_DefineProperty(cx, callback_data, "module_request", module_request, -@@ -688,16 +715,9 @@ - args[1].setString(specifier); - - JS::RootedValue result(cx); -- if (!JS::Call(cx, loader, "moduleResolveAsyncHook", args, &result)) { -- if (!JS_IsExceptionPending(cx)) -- return false; -- -- JS::RootedObject rejected_promise{ -- cx, reject_new_promise_with_pending_exception(cx)}; -- return JS::FinishDynamicModuleImport(cx, rejected_promise, -- importing_module_priv, -+ if (!JS::Call(cx, loader, "moduleResolveAsyncHook", args, &result)) -+ return JS::FinishDynamicModuleImport(cx, nullptr, importing_module_priv, - module_request, internal_promise); -- } - - // Release in finish_import - GjsContextPrivate* priv = GjsContextPrivate::from_cx(cx); -diff -ruN cjs-6.2.0-orig/cjs/native.cpp cjs-6.2.0/cjs/native.cpp ---- cjs-6.2.0-orig/cjs/native.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/native.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -18,8 +18,8 @@ - #include "cjs/native.h" - #include "util/log.h" - --void Gjs::NativeModuleRegistry::add(const char* module_id, -- GjsDefineModuleFunc func) { -+void Gjs::NativeModuleDefineFuncs::add(const char* module_id, -+ GjsDefineModuleFunc func) { - bool inserted; - std::tie(std::ignore, inserted) = m_modules.insert({module_id, func}); - if (!inserted) { -@@ -41,32 +41,30 @@ - * been registered. This is used to check to see if a name is a - * builtin module without starting to try and load it. - */ --bool Gjs::NativeModuleRegistry::is_registered(const char* name) const { -+bool Gjs::NativeModuleDefineFuncs::is_registered(const char* name) const { - return m_modules.count(name) > 0; - } - - /** -- * gjs_load: -+ * define: - * @context: the #JSContext -- * @parse_name: Name under which the module was registered with -- * add(), should be in the format as returned by -- * g_file_get_parse_name() -+ * @id: Name under which the module was registered with add() - * @module_out: Return location for a #JSObject - * -- * Loads a builtin native-code module called @name into @module_out. -+ * Loads a builtin native-code module called @name into @module_out by calling -+ * the function to define it. - * - * Returns: true on success, false if an exception was thrown. - */ --bool Gjs::NativeModuleRegistry::load(JSContext* context, const char* parse_name, -- JS::MutableHandleObject module_out) { -- gjs_debug(GJS_DEBUG_NATIVE, "Defining native module '%s'", parse_name); -+bool Gjs::NativeModuleDefineFuncs::define( -+ JSContext* context, const char* id, -+ JS::MutableHandleObject module_out) const { -+ gjs_debug(GJS_DEBUG_NATIVE, "Defining native module '%s'", id); - -- const auto& iter = m_modules.find(parse_name); -+ const auto& iter = m_modules.find(id); - - if (iter == m_modules.end()) { -- gjs_throw(context, -- "No native module '%s' has registered itself", -- parse_name); -+ gjs_throw(context, "No native module '%s' has registered itself", id); - return false; - } - -diff -ruN cjs-6.2.0-orig/cjs/native.h cjs-6.2.0/cjs/native.h ---- cjs-6.2.0-orig/cjs/native.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/native.h 2024-10-14 18:35:57.000000000 +0200 -@@ -9,35 +9,34 @@ - #include - #include - --#include - #include - - #include "cjs/macros.h" - - namespace Gjs { --class NativeModuleRegistry { -- NativeModuleRegistry() {} -+class NativeModuleDefineFuncs { -+ NativeModuleDefineFuncs() {} - typedef bool (*GjsDefineModuleFunc)(JSContext* context, - JS::MutableHandleObject module_out); - - std::unordered_map m_modules; - - public: -- static NativeModuleRegistry& get() { -- static NativeModuleRegistry the_singleton; -+ static NativeModuleDefineFuncs& get() { -+ static NativeModuleDefineFuncs the_singleton; - return the_singleton; - } - - /* called on context init */ - void add(const char* module_id, GjsDefineModuleFunc func); - -- /* called by importer.c to to check for already loaded modules */ -+ // called by importer.cpp to to check for already loaded modules - [[nodiscard]] bool is_registered(const char* name) const; - -- /* called by importer.cpp to load a statically linked native module */ -+ // called by importer.cpp to load a built-in native module - GJS_JSAPI_RETURN_CONVENTION -- bool load(JSContext* cx, const char* name, -- JS::MutableHandleObject module_out); -+ bool define(JSContext* cx, const char* name, -+ JS::MutableHandleObject module_out) const; - }; - }; // namespace Gjs - -diff -ruN cjs-6.2.0-orig/cjs/profiler-private.h cjs-6.2.0/cjs/profiler-private.h ---- cjs-6.2.0-orig/cjs/profiler-private.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/profiler-private.h 2024-10-14 18:35:57.000000000 +0200 -@@ -5,8 +5,11 @@ - #ifndef GJS_PROFILER_PRIVATE_H_ - #define GJS_PROFILER_PRIVATE_H_ - -+#include -+ - #include - -+#include // for JSFinalizeStatus, JSGCStatus, GCReason - #include - #include - #include -@@ -55,4 +58,7 @@ - - void _gjs_profiler_setup_signals(GjsProfiler *self, GjsContext *context); - -+void _gjs_profiler_set_finalize_status(GjsProfiler*, JSFinalizeStatus); -+void _gjs_profiler_set_gc_status(GjsProfiler*, JSGCStatus, JS::GCReason); -+ - #endif // GJS_PROFILER_PRIVATE_H_ -diff -ruN cjs-6.2.0-orig/cjs/profiler.cpp cjs-6.2.0/cjs/profiler.cpp ---- cjs-6.2.0-orig/cjs/profiler.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/profiler.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -7,33 +7,40 @@ - # include // for siginfo_t, sigevent, sigaction, SIGPROF, ... - #endif - --#include --#include -- - #ifdef ENABLE_PROFILER --# include -+// IWYU has a weird loop where if this is present, it asks for it to be removed, -+// and if absent, asks for it to be added -+# include // IWYU pragma: keep - # include - # include --# include // for sscanf --# include // for memcpy, strlen -+# include // for sscanf -+# include // for memcpy, strlen - # include // for __NR_gettid -+# include // for timer_t - # include // for size_t, CLOCK_MONOTONIC, itimerspec, ... - # ifdef HAVE_UNISTD_H - # include // for getpid, syscall - # endif - # include -+#endif -+ -+#include -+#include -+ -+#ifdef ENABLE_PROFILER - # ifdef G_OS_UNIX - # include - # endif - # include - #endif - -+#include // for JSFinalizeStatus, JSGCStatus, GCReason - #include // for EnableContextProfilingStack, ... - #include - #include // for ProfilingStack operators - - #include "cjs/context.h" --#include "cjs/jsapi-util.h" -+#include "cjs/jsapi-util.h" // for gjs_explain_gc_reason - #include "cjs/mem-private.h" - #include "cjs/profiler-private.h" - #include "cjs/profiler.h" -@@ -49,7 +56,7 @@ - * However, we do use a Linux'ism that allows us to deliver the signal - * to only a single thread. Doing this in a generic fashion would - * require thread-registration so that we can mask SIGPROF from all -- * threads execpt the JS thread. The gecko engine uses tgkill() to do -+ * threads except the JS thread. The gecko engine uses tgkill() to do - * this with a secondary thread instead of using POSIX timers. We could - * do this too, but it would still be Linux-only. - * -@@ -89,6 +96,10 @@ - GSource* periodic_flush; - - SysprofCaptureWriter* target_capture; -+ -+ // Cache previous values of counters so that we don't overrun the output -+ // with counters that don't change very often -+ uint64_t last_counter_values[GJS_N_COUNTERS]; - #endif /* ENABLE_PROFILER */ - - /* The filename to write to */ -@@ -104,6 +115,12 @@ - /* Cached copy of our pid */ - GPid pid; - -+ /* Timing information */ -+ int64_t gc_begin_time; -+ int64_t sweep_begin_time; -+ int64_t group_sweep_begin_time; -+ const char* gc_reason; // statically allocated -+ - /* GLib signal handler ID for SIGUSR2 */ - unsigned sigusr2_id; - unsigned counter_base; // index of first GObject memory counter -@@ -435,15 +452,24 @@ - - unsigned ids[GJS_N_COUNTERS]; - SysprofCaptureCounterValue values[GJS_N_COUNTERS]; -+ size_t new_counts = 0; - --# define FETCH_COUNTERS(name, ix) \ -- ids[ix] = self->counter_base + ix; \ -- values[ix].v64 = GJS_GET_COUNTER(name); -+# define FETCH_COUNTERS(name, ix) \ -+ { \ -+ uint64_t count = GJS_GET_COUNTER(name); \ -+ if (count != self->last_counter_values[ix]) { \ -+ ids[new_counts] = self->counter_base + ix; \ -+ values[new_counts].v64 = count; \ -+ new_counts++; \ -+ } \ -+ self->last_counter_values[ix] = count; \ -+ } - GJS_FOR_EACH_COUNTER(FETCH_COUNTERS); - # undef FETCH_COUNTERS - -- if (!sysprof_capture_writer_set_counters(self->capture, now, -1, self->pid, -- ids, values, GJS_N_COUNTERS)) -+ if (new_counts > 0 && -+ !sysprof_capture_writer_set_counters(self->capture, now, -1, self->pid, -+ ids, values, new_counts)) - gjs_profiler_stop(self); - } - -@@ -848,3 +874,87 @@ - (void)fd; // Unused in the no-profiler case - #endif - } -+ -+void _gjs_profiler_set_finalize_status(GjsProfiler* self, -+ JSFinalizeStatus status) { -+#ifdef ENABLE_PROFILER -+ // Implementation note for mozjs-128: -+ // -+ // Sweeping happens in three phases: -+ // 1st phase (JSFINALIZE_GROUP_PREPARE): the collector prepares to sweep a -+ // group of zones. 2nd phase (JSFINALIZE_GROUP_START): weak references to -+ // unmarked things have been removed, but no GC thing has been swept. 3rd -+ // Phase (JSFINALIZE_GROUP_END): all dead GC things for a group of zones -+ // have been swept. The above repeats for each sweep group. -+ // JSFINALIZE_COLLECTION_END occurs at the end of all GC. (see jsgc.cpp, -+ // BeginSweepPhase/BeginSweepingZoneGroup and SweepPhase, all called from -+ // IncrementalCollectSlice). -+ // -+ // Incremental GC muddies the waters, because BeginSweepPhase is always run -+ // to entirety, but SweepPhase can be run incrementally and mixed with JS -+ // code runs or even native code, when MaybeGC/IncrementalGC return. -+ // After GROUP_START, the collector may yield to the mutator meaning JS code -+ // can run between the callback for GROUP_START and GROUP_END. -+ -+ int64_t now = g_get_monotonic_time() * 1000L; -+ -+ switch (status) { -+ case JSFINALIZE_GROUP_PREPARE: -+ self->sweep_begin_time = now; -+ break; -+ case JSFINALIZE_GROUP_START: -+ self->group_sweep_begin_time = now; -+ break; -+ case JSFINALIZE_GROUP_END: -+ if (self->group_sweep_begin_time != 0) { -+ _gjs_profiler_add_mark(self, self->group_sweep_begin_time, -+ now - self->group_sweep_begin_time, -+ "GJS", "Group sweep", nullptr); -+ } -+ self->group_sweep_begin_time = 0; -+ break; -+ case JSFINALIZE_COLLECTION_END: -+ if (self->sweep_begin_time != 0) { -+ _gjs_profiler_add_mark(self, self->sweep_begin_time, -+ now - self->sweep_begin_time, "GJS", -+ "Sweep", nullptr); -+ } -+ self->sweep_begin_time = 0; -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+#else -+ (void)self; -+ (void)status; -+#endif -+} -+ -+void _gjs_profiler_set_gc_status(GjsProfiler* self, JSGCStatus status, -+ JS::GCReason reason) { -+#ifdef ENABLE_PROFILER -+ int64_t now = g_get_monotonic_time() * 1000L; -+ -+ switch (status) { -+ case JSGC_BEGIN: -+ self->gc_begin_time = now; -+ self->gc_reason = gjs_explain_gc_reason(reason); -+ break; -+ case JSGC_END: -+ if (self->gc_begin_time != 0) { -+ _gjs_profiler_add_mark(self, self->gc_begin_time, -+ now - self->gc_begin_time, "GJS", -+ "Garbage collection", self->gc_reason); -+ } -+ self->gc_begin_time = 0; -+ self->gc_reason = nullptr; -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+#else -+ (void)self; -+ (void)status; -+ (void)reason; -+#endif -+} -diff -ruN cjs-6.2.0-orig/cjs/profiler.h cjs-6.2.0/cjs/profiler.h ---- cjs-6.2.0-orig/cjs/profiler.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/profiler.h 2024-10-14 18:38:17.000000000 +0200 -@@ -7,7 +7,7 @@ - #define GJS_PROFILER_H_ - - #if !defined(INSIDE_GJS_H) && !defined(GJS_COMPILATION) --# error "Only can be included directly." -+# error "Only can be included directly." - #endif - - #include -diff -ruN cjs-6.2.0-orig/cjs/promise.cpp cjs-6.2.0/cjs/promise.cpp ---- cjs-6.2.0-orig/cjs/promise.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/promise.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -16,6 +16,7 @@ - #include - #include - #include // for JS_NewPlainObject -+#include // for RunJobs - - #include "cjs/context-private.h" - #include "cjs/jsapi-util-args.h" -@@ -81,7 +82,7 @@ - g_source_set_ready_time(this, -1); - - // Drain the job queue. -- m_gjs->runJobs(m_gjs->context()); -+ js::RunJobs(m_gjs->context()); - - return G_SOURCE_CONTINUE; - } -@@ -193,8 +194,7 @@ - bool drain_microtask_queue(JSContext* cx, unsigned argc, JS::Value* vp) { - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - -- auto* gjs = GjsContextPrivate::from_cx(cx); -- gjs->runJobs(cx); -+ js::RunJobs(cx); - - args.rval().setUndefined(); - return true; -diff -ruN cjs-6.2.0-orig/cjs/stack.cpp cjs-6.2.0/cjs/stack.cpp ---- cjs-6.2.0-orig/cjs/stack.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/stack.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -4,7 +4,7 @@ - - #include - --#include // for stderr, open_memstream -+#include // for stderr - - #include - #include -@@ -12,7 +12,9 @@ - #include - #include - -+#include - #include -+#include // for UniqueChars - #include - - #include "cjs/context-private.h" -@@ -40,48 +42,31 @@ - } - } - --#ifdef HAVE_OPEN_MEMSTREAM --static std::string --stack_trace_string(GjsContext *context) { -- JSContext *cx = static_cast(gjs_context_get_native_context(context)); -- std::ostringstream out; -- FILE *stream; -- GjsAutoChar buf; -- size_t len; -- -- stream = open_memstream(buf.out(), &len); -- if (!stream) { -- out << "No stack trace for context " << context << ": " -- "open_memstream() failed\n\n"; -- return out.str(); -- } -- js::DumpBacktrace(cx, stream); -- fclose(stream); -- out << "== Stack trace for context " << context << " ==\n" -- << buf.get() << "\n"; -- return out.str(); --} --#endif -- - std::string - gjs_dumpstack_string() { - std::string out; - std::ostringstream all_traces; - --#ifdef HAVE_OPEN_MEMSTREAM - GjsSmartPointer contexts = gjs_context_get_all(); -+ js::Sprinter printer; - GList *iter; - - for (iter = contexts; iter; iter = iter->next) { - GjsAutoUnref context(GJS_CONTEXT(iter->data)); -- all_traces << stack_trace_string(context); -+ if (!printer.init()) { -+ all_traces << "No stack trace for context " << context.get() -+ << ": out of memory\n\n"; -+ break; -+ } -+ auto* cx = -+ static_cast(gjs_context_get_native_context(context)); -+ js::DumpBacktrace(cx, printer); -+ JS::UniqueChars trace = printer.release(); -+ all_traces << "== Stack trace for context " << context.get() << " ==\n" -+ << trace.get() << "\n"; - } - out = all_traces.str(); - out.resize(MAX(out.size() - 2, 0)); --#else -- out = "No stack trace: no open_memstream() support. " -- "See https://bugzilla.mozilla.org/show_bug.cgi?id=1826290"; --#endif - - return out; - } -diff -ruN cjs-6.2.0-orig/cjs/text-encoding.cpp cjs-6.2.0/cjs/text-encoding.cpp ---- cjs-6.2.0-orig/cjs/text-encoding.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/cjs/text-encoding.cpp 2024-10-14 18:35:57.000000000 +0200 -@@ -16,6 +16,7 @@ - #include // for unique_ptr - #include // for u16string - #include // for tuple -+#include // for move - - #include - #include -@@ -40,7 +41,7 @@ - #include // for JSProto_InternalError - #include - #include --#include -+#include - - #include "cjs/jsapi-util-args.h" - #include "cjs/jsapi-util.h" -@@ -93,7 +94,7 @@ - // this is typical for ASCII and non-supplementary characters. - // Because we are converting from an unknown encoding - // technically a single byte could be supplementary in -- // Unicode (4 bytes) or even represen multiple Unicode characters. -+ // Unicode (4 bytes) or even represent multiple Unicode characters. - // - // std::u16string does not care about these implementation - // details, its only concern is that is consists of byte pairs. -@@ -165,7 +166,7 @@ - // Append the unicode fallback character to the output - output_str.append(u"\ufffd", 1); - } -- } else if (g_error_matches(error, G_IO_ERROR, -+ } else if (g_error_matches(local_error, G_IO_ERROR, - G_IO_ERROR_NO_SPACE)) { - // If the buffer was full increase the buffer - // size and re-try the conversion. -@@ -180,15 +181,12 @@ - } else { - buffer_size += bytes_len; - } -+ } else { -+ // Stop decoding if an unknown error occurs. -+ return gjs_throw_type_error_from_gerror(cx, local_error); - } - } -- -- // Stop decoding if an unknown error occurs. -- } while (input_len > 0 && !error); -- -- // An unexpected error occurred. -- if (error) -- return gjs_throw_type_error_from_gerror(cx, error); -+ } while (input_len > 0); - - // Copy the accumulator's data into a JSString of Unicode (UTF-16) chars. - return JS_NewUCStringCopyN(cx, output_str.c_str(), output_str.size()); -@@ -401,13 +399,8 @@ - utf8_len = strlen(utf8.get()); - } - -- array_buffer = JS::NewArrayBufferWithContents(cx, utf8_len, utf8.get()); -- -- // array_buffer only assumes ownership if the call succeeded, -- // if array_buffer assumes ownership we must release our ownership -- // without freeing the data. -- if (array_buffer) -- mozilla::Unused << utf8.release(); -+ array_buffer = -+ JS::NewArrayBufferWithContents(cx, utf8_len, std::move(utf8)); - } else { - GjsAutoError error; - GjsAutoChar encoded = nullptr; -@@ -456,9 +449,10 @@ - if (bytes_written == 0) - return JS_NewUint8Array(cx, 0); - -+ mozilla::UniquePtr contents{ -+ encoded.release(), gfree_arraybuffer_contents}; - array_buffer = -- JS::NewExternalArrayBuffer(cx, bytes_written, encoded.release(), -- gfree_arraybuffer_contents, nullptr); -+ JS::NewExternalArrayBuffer(cx, bytes_written, std::move(contents)); - } - - if (!array_buffer) -diff -ruN cjs-6.2.0-orig/gi/arg-cache.cpp cjs-6.2.0/gi/arg-cache.cpp ---- cjs-6.2.0-orig/gi/arg-cache.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/arg-cache.cpp 2024-10-14 18:41:39.000000000 +0200 -@@ -63,9 +63,9 @@ - static_assert(G_N_ELEMENTS(expected_type_names) == ExpectedType::LAST, - "Names must match the values in ExpectedType"); - --static constexpr void gjs_g_argument_set_array_length(GITypeTag tag, -- GIArgument* arg, -- size_t value) { -+static constexpr void gjs_gi_argument_set_array_length(GITypeTag tag, -+ GIArgument* arg, -+ size_t value) { - switch (tag) { - case GI_TYPE_TAG_INT8: - gjs_arg_set(arg, value); -@@ -145,18 +145,13 @@ - GITypeTag m_tag : 5; - }; - --struct String { -- constexpr String() : m_filename(false) {} -- bool m_filename : 1; --}; -- --struct TypeInfo { -+struct HasTypeInfo { - constexpr GITypeInfo* type_info() const { - // Should be const GITypeInfo*, but G-I APIs won't accept that - return const_cast(&m_type_info); - } - -- GITypeInfo m_type_info; -+ GITypeInfo m_type_info{}; - }; - - struct Transferable { -@@ -187,8 +182,21 @@ - - constexpr bool set_out_parameter(GjsFunctionCallState* state, - GIArgument* arg) { -- gjs_arg_unset(&state->out_cvalue(m_arg_pos)); -- gjs_arg_set(arg, &gjs_arg_member(&state->out_cvalue(m_arg_pos))); -+ // Clear all bits of the out C value. No one member is guaranteed to -+ // span the whole union on all architectures, so use memset() instead of -+ // gjs_arg_unset(). -+ memset(&state->out_cvalue(m_arg_pos), 0, sizeof(GIArgument)); -+ // The value passed to the function is actually the address of the out -+ // C value -+ gjs_arg_set(arg, &state->out_cvalue(m_arg_pos)); -+ return true; -+ } -+ -+ constexpr bool set_inout_parameter(GjsFunctionCallState* state, -+ GIArgument* arg) { -+ state->out_cvalue(m_arg_pos) = state->inout_original_cvalue(m_arg_pos) = -+ *arg; -+ gjs_arg_set(arg, &state->out_cvalue(m_arg_pos)); - return true; - } - -@@ -197,20 +205,24 @@ - - struct Array : BasicType { - uint8_t m_length_pos = 0; -+ GIDirection m_length_direction : 2; - -- void set_array_length(int pos, GITypeTag tag) { -+ Array() : BasicType(), m_length_direction(GI_DIRECTION_IN) {} -+ -+ void set_array_length(int pos, GITypeTag tag, GIDirection direction) { - g_assert(pos >= 0 && pos <= Argument::MAX_ARGS && - "No more than 253 arguments allowed"); - m_length_pos = pos; -+ m_length_direction = direction; - m_tag = tag; - } - }; - --struct BaseInfo { -- constexpr explicit BaseInfo(GIBaseInfo* info, -- const GjsAutoTakeOwnership& add_ref) -+struct HasIntrospectionInfo { -+ constexpr explicit HasIntrospectionInfo(GIBaseInfo* info, -+ const GjsAutoTakeOwnership& add_ref) - : m_info(info, add_ref) {} -- constexpr explicit BaseInfo(GIBaseInfo* info) : m_info(info) {} -+ constexpr explicit HasIntrospectionInfo(GIBaseInfo* info) : m_info(info) {} - - GjsAutoBaseInfo m_info; - }; -@@ -227,7 +239,7 @@ - struct RegisteredType : GTypedType { - RegisteredType(GType gtype, GIInfoType info_type) - : GTypedType(gtype), m_info_type(info_type) {} -- explicit RegisteredType(GIBaseInfo* info) -+ explicit RegisteredType(GIRegisteredTypeInfo* info) - : GTypedType(g_registered_type_info_get_g_type(info)), - m_info_type(g_base_info_get_type(info)) { - g_assert(m_gtype != G_TYPE_NONE && -@@ -237,15 +249,15 @@ - GIInfoType m_info_type : 5; - }; - --struct RegisteredInterface : BaseInfo, GTypedType { -- explicit RegisteredInterface(GIBaseInfo* info) -- : BaseInfo(info, GjsAutoTakeOwnership{}), -+struct RegisteredInterface : HasIntrospectionInfo, GTypedType { -+ explicit RegisteredInterface(GIRegisteredTypeInfo* info) -+ : HasIntrospectionInfo(info, GjsAutoTakeOwnership{}), - GTypedType(g_registered_type_info_get_g_type(m_info)) {} - }; - --struct Callback : Nullable, BaseInfo { -- explicit Callback(GIInterfaceInfo* info) -- : BaseInfo(info, GjsAutoTakeOwnership{}), -+struct Callback : Nullable, HasIntrospectionInfo { -+ explicit Callback(GICallbackInfo* info) -+ : HasIntrospectionInfo(info, GjsAutoTakeOwnership{}), - m_scope(GI_SCOPE_TYPE_INVALID) {} - - inline void set_callback_destroy_pos(int pos) { -@@ -319,7 +331,7 @@ - constexpr bool skip() { return true; } - }; - --struct Generic : SkipAll, Transferable, TypeInfo {}; -+struct Generic : SkipAll, Transferable, HasTypeInfo {}; - - struct GenericIn : Generic { - bool in(JSContext*, GjsFunctionCallState*, GIArgument*, -@@ -347,7 +359,10 @@ - bool release(JSContext*, GjsFunctionCallState*, GIArgument*, - GIArgument*) override; - -- const ReturnValue* as_return_value() const override { return this; } -+ GITypeTag return_tag() const override { -+ return g_type_info_get_tag(&const_cast(this)->m_type_info); -+ } -+ const GITypeInfo* return_type() const override { return &m_type_info; } - }; - - struct GenericReturn : ReturnValue { -@@ -358,6 +373,39 @@ - } - }; - -+template -+struct NumericOut : SkipAll, Positioned { -+ static_assert(std::is_arithmetic_v, "Not arithmetic type"); -+ bool in(JSContext*, GjsFunctionCallState* state, GIArgument* arg, -+ JS::HandleValue) override { -+ return set_out_parameter(state, arg); -+ } -+ bool out(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, -+ JS::MutableHandleValue value) override { -+ return Gjs::c_value_to_js_checked(cx, gjs_arg_get(arg), -+ value); -+ } -+}; -+ -+using BooleanOut = NumericOut; -+ -+template -+struct NumericReturn : SkipAll { -+ static_assert(std::is_arithmetic_v, "Not arithmetic type"); -+ bool in(JSContext* cx, GjsFunctionCallState*, GIArgument*, -+ JS::HandleValue) override { -+ return invalid(cx, G_STRFUNC); -+ } -+ bool out(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, -+ JS::MutableHandleValue value) override { -+ return Gjs::c_value_to_js_checked(cx, gjs_arg_get(arg), -+ value); -+ } -+ GITypeTag return_tag() const override { return TAG; } -+}; -+ -+using BooleanReturn = NumericReturn; -+ - struct SimpleOut : SkipAll, Positioned { - bool in(JSContext*, GjsFunctionCallState* state, GIArgument* arg, - JS::HandleValue) override { -@@ -403,6 +451,13 @@ - struct ReturnArray : ExplicitArrayOut { - bool in(JSContext* cx, GjsFunctionCallState* state, GIArgument* arg, - JS::HandleValue value) override { -+ if (m_length_direction != GI_DIRECTION_OUT) { -+ gjs_throw(cx, -+ "Using different length argument direction for array %s" -+ "is not supported for out arrays", -+ m_arg_name); -+ return false; -+ } - return GenericOut::in(cx, state, arg, value); - }; - }; -@@ -506,14 +561,14 @@ - GIArgument*) override; - }; - --struct FallbackInterfaceIn : RegisteredInterfaceIn, TypeInfo { -+struct FallbackInterfaceIn : RegisteredInterfaceIn, HasTypeInfo { - using RegisteredInterfaceIn::RegisteredInterfaceIn; - - bool in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, - JS::HandleValue value) override { -- return gjs_value_to_g_argument(cx, value, &m_type_info, m_arg_name, -- GJS_ARGUMENT_ARGUMENT, m_transfer, -- flags(), arg); -+ return gjs_value_to_gi_argument(cx, value, &m_type_info, m_arg_name, -+ GJS_ARGUMENT_ARGUMENT, m_transfer, -+ flags(), arg); - } - }; - -@@ -536,11 +591,11 @@ - } - }; - --struct UnregisteredBoxedIn : BoxedIn, BaseInfo { -- explicit UnregisteredBoxedIn(GIInterfaceInfo* info) -+struct UnregisteredBoxedIn : BoxedIn, HasIntrospectionInfo { -+ explicit UnregisteredBoxedIn(GIStructInfo* info) - : BoxedIn(g_registered_type_info_get_g_type(info), - g_base_info_get_type(info)), -- BaseInfo(info, GjsAutoTakeOwnership{}) {} -+ HasIntrospectionInfo(info, GjsAutoTakeOwnership{}) {} - // This is a smart argument, no release needed - GIBaseInfo* info() const override { return m_info; } - }; -@@ -625,12 +680,32 @@ - JS::HandleValue) override; - }; - --struct NumericIn : SkipAll, BasicType { -- explicit NumericIn(GITypeTag tag) : BasicType(tag) {} -+template -+struct NumericIn : SkipAll { -+ static_assert(std::is_arithmetic_v, "Not arithmetic type"); - bool in(JSContext*, GjsFunctionCallState*, GIArgument*, - JS::HandleValue) override; - }; - -+template -+struct NumericInOut : NumericIn, Positioned { -+ static_assert(std::is_arithmetic_v, "Not arithmetic type"); -+ bool in(JSContext* cx, GjsFunctionCallState* state, GIArgument* arg, -+ JS::HandleValue value) override { -+ if (!NumericIn::in(cx, state, arg, value)) -+ return false; -+ -+ return set_inout_parameter(state, arg); -+ } -+ bool out(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, -+ JS::MutableHandleValue value) override { -+ return Gjs::c_value_to_js_checked(cx, gjs_arg_get(arg), -+ value); -+ } -+}; -+ -+using BooleanInOut = NumericInOut; -+ - struct UnicharIn : SkipAll { - bool in(JSContext*, GjsFunctionCallState*, GIArgument*, - JS::HandleValue) override; -@@ -641,26 +716,61 @@ - JS::HandleValue) override; - }; - --struct StringInTransferNone : NullableIn, String { -+template -+struct StringInTransferNone : NullableIn { - bool in(JSContext*, GjsFunctionCallState*, GIArgument*, - JS::HandleValue) override; - bool release(JSContext*, GjsFunctionCallState*, GIArgument*, - GIArgument*) override; - }; - --struct StringIn : StringInTransferNone { -+struct StringIn : StringInTransferNone { - bool release(JSContext*, GjsFunctionCallState*, GIArgument*, - GIArgument*) override { - return skip(); - } - }; - --struct FilenameInTransferNone : StringInTransferNone { -- FilenameInTransferNone() { m_filename = true; } -+template -+struct StringOutBase : SkipAll { -+ bool out(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, -+ JS::MutableHandleValue value) override { -+ return Gjs::c_value_to_js(cx, gjs_arg_get(arg), value); -+ } -+ bool release(JSContext* cx, GjsFunctionCallState*, GIArgument*, -+ GIArgument* out_arg [[maybe_unused]]) override { -+ if constexpr (TRANSFER == GI_TRANSFER_NOTHING) { -+ return skip(); -+ } else if constexpr (TRANSFER == GI_TRANSFER_EVERYTHING) { -+ g_clear_pointer(&gjs_arg_member(out_arg), g_free); -+ return true; -+ } else { -+ return invalid(cx, G_STRFUNC); -+ } -+ } -+}; -+ -+template -+struct StringReturn : StringOutBase { -+ bool in(JSContext* cx, GjsFunctionCallState*, GIArgument*, -+ JS::HandleValue) override { -+ return Argument::invalid(cx, G_STRFUNC); -+ } -+ -+ GITypeTag return_tag() const override { return GI_TYPE_TAG_UTF8; } -+}; -+ -+template -+struct StringOut : StringOutBase, Positioned { -+ bool in(JSContext*, GjsFunctionCallState* state, GIArgument* arg, -+ JS::HandleValue) override { -+ return set_out_parameter(state, arg); -+ } - }; - -+using FilenameInTransferNone = StringInTransferNone; -+ - struct FilenameIn : FilenameInTransferNone { -- FilenameIn() { m_filename = true; } - bool release(JSContext*, GjsFunctionCallState*, GIArgument*, - GIArgument*) override { - return skip(); -@@ -722,6 +832,78 @@ - GIArgument*) override; - }; - -+struct ZeroTerminatedArrayInOut : GenericInOut { -+ bool release(JSContext* cx, GjsFunctionCallState* state, GIArgument*, -+ GIArgument* out_arg) override { -+ GITransfer transfer = -+ state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; -+ GIArgument* original_out_arg = &state->inout_original_cvalue(m_arg_pos); -+ if (!gjs_gi_argument_release_in_array(cx, transfer, &m_type_info, -+ original_out_arg)) -+ return false; -+ -+ transfer = -+ state->call_completed() ? m_transfer : GI_TRANSFER_EVERYTHING; -+ return gjs_gi_argument_release_out_array(cx, transfer, &m_type_info, -+ out_arg); -+ } -+}; -+ -+struct ZeroTerminatedArrayIn : GenericIn, Nullable { -+ bool out(JSContext*, GjsFunctionCallState*, GIArgument*, -+ JS::MutableHandleValue) override { -+ return skip(); -+ } -+ -+ bool release(JSContext* cx, GjsFunctionCallState* state, GIArgument* in_arg, -+ GIArgument*) override { -+ GITransfer transfer = -+ state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; -+ -+ return gjs_gi_argument_release_in_array(cx, transfer, &m_type_info, -+ in_arg); -+ } -+ -+ GjsArgumentFlags flags() const override { -+ return Argument::flags() | Nullable::flags(); -+ } -+}; -+ -+struct FixedSizeArrayIn : GenericIn { -+ bool out(JSContext*, GjsFunctionCallState*, GIArgument*, -+ JS::MutableHandleValue) override { -+ return skip(); -+ } -+ -+ bool release(JSContext* cx, GjsFunctionCallState* state, GIArgument* in_arg, -+ GIArgument*) override { -+ GITransfer transfer = -+ state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; -+ -+ int size = g_type_info_get_array_fixed_size(&m_type_info); -+ return gjs_gi_argument_release_in_array(cx, transfer, &m_type_info, -+ size, in_arg); -+ } -+}; -+ -+struct FixedSizeArrayInOut : GenericInOut { -+ bool release(JSContext* cx, GjsFunctionCallState* state, GIArgument*, -+ GIArgument* out_arg) override { -+ GITransfer transfer = -+ state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; -+ GIArgument* original_out_arg = &state->inout_original_cvalue(m_arg_pos); -+ int size = g_type_info_get_array_fixed_size(&m_type_info); -+ if (!gjs_gi_argument_release_in_array(cx, transfer, &m_type_info, size, -+ original_out_arg)) -+ return false; -+ -+ transfer = -+ state->call_completed() ? m_transfer : GI_TRANSFER_EVERYTHING; -+ return gjs_gi_argument_release_out_array(cx, transfer, &m_type_info, -+ size, out_arg); -+ } -+}; -+ - GJS_JSAPI_RETURN_CONVENTION - bool NotIntrospectable::in(JSContext* cx, GjsFunctionCallState* state, - GIArgument*, JS::HandleValue) { -@@ -769,9 +951,9 @@ - GJS_JSAPI_RETURN_CONVENTION - bool GenericIn::in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, - JS::HandleValue value) { -- return gjs_value_to_g_argument(cx, value, &m_type_info, m_arg_name, -- GJS_ARGUMENT_ARGUMENT, m_transfer, flags(), -- arg); -+ return gjs_value_to_gi_argument(cx, value, &m_type_info, m_arg_name, -+ GJS_ARGUMENT_ARGUMENT, m_transfer, flags(), -+ arg); - } - - GJS_JSAPI_RETURN_CONVENTION -@@ -780,25 +962,29 @@ - if (!GenericIn::in(cx, state, arg, value)) - return false; - -- state->out_cvalue(m_arg_pos) = state->inout_original_cvalue(m_arg_pos) = -- *arg; -- gjs_arg_set(arg, &state->out_cvalue(m_arg_pos)); -- return true; -+ return set_inout_parameter(state, arg); - } - - GJS_JSAPI_RETURN_CONVENTION - bool ExplicitArrayIn::in(JSContext* cx, GjsFunctionCallState* state, -- GArgument* arg, JS::HandleValue value) { -+ GIArgument* arg, JS::HandleValue value) { - void* data; - size_t length; - -+ if (m_length_direction != GI_DIRECTION_INOUT && -+ m_length_direction != GI_DIRECTION_IN) { -+ gjs_throw(cx, "Using different length argument direction for array %s" -+ "is not supported for in arrays", m_arg_name); -+ return false; -+ } -+ - if (!gjs_array_to_explicit_array(cx, value, &m_type_info, m_arg_name, - GJS_ARGUMENT_ARGUMENT, m_transfer, flags(), - &data, &length)) - return false; - -- gjs_g_argument_set_array_length(m_tag, &state->in_cvalue(m_length_pos), -- length); -+ gjs_gi_argument_set_array_length(m_tag, &state->in_cvalue(m_length_pos), -+ length); - gjs_arg_set(arg, data); - return true; - } -@@ -822,11 +1008,13 @@ - gjs_arg_unset(&state->out_cvalue(ix)); - gjs_arg_unset(&state->inout_original_cvalue(ix)); - } else { -- state->out_cvalue(length_pos) = -- state->inout_original_cvalue(length_pos) = -- state->in_cvalue(length_pos); -- gjs_arg_set(&state->in_cvalue(length_pos), -- &state->out_cvalue(length_pos)); -+ if G_LIKELY (m_length_direction == GI_DIRECTION_INOUT) { -+ state->out_cvalue(length_pos) = -+ state->inout_original_cvalue(length_pos) = -+ state->in_cvalue(length_pos); -+ gjs_arg_set(&state->in_cvalue(length_pos), -+ &state->out_cvalue(length_pos)); -+ } - - state->out_cvalue(ix) = state->inout_original_cvalue(ix) = *arg; - gjs_arg_set(arg, &state->out_cvalue(ix)); -@@ -938,61 +1126,32 @@ - } - - template --GJS_JSAPI_RETURN_CONVENTION inline static bool gjs_arg_set_from_js_value( -- JSContext* cx, const JS::HandleValue& value, GArgument* arg, -- Argument* gjs_arg) { -+GJS_JSAPI_RETURN_CONVENTION bool NumericIn::in(JSContext* cx, -+ GjsFunctionCallState*, -+ GIArgument* arg, -+ JS::HandleValue value) { - bool out_of_range = false; - - if (!gjs_arg_set_from_js_value(cx, value, arg, &out_of_range)) { - if (out_of_range) { - gjs_throw(cx, "Argument %s: value is out of range for %s", -- gjs_arg->arg_name(), Gjs::static_type_name()); -+ arg_name(), Gjs::static_type_name()); - } - - return false; - } - -- gjs_debug_marshal( -- GJS_DEBUG_GFUNCTION, "%s set to value %s (type %s)", -- GjsAutoChar(gjs_argument_display_name(gjs_arg->arg_name(), -- GJS_ARGUMENT_ARGUMENT)) -- .get(), -- std::to_string(gjs_arg_get(arg)).c_str(), -- Gjs::static_type_name()); -+ gjs_debug_marshal(GJS_DEBUG_GFUNCTION, "%s set to value %s (type %s)", -+ GjsAutoChar{gjs_argument_display_name( -+ arg_name(), GJS_ARGUMENT_ARGUMENT)} -+ .get(), -+ std::to_string(gjs_arg_get(arg)).c_str(), -+ Gjs::static_type_name()); - - return true; - } - - GJS_JSAPI_RETURN_CONVENTION --bool NumericIn::in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, -- JS::HandleValue value) { -- switch (m_tag) { -- case GI_TYPE_TAG_INT8: -- return gjs_arg_set_from_js_value(cx, value, arg, this); -- case GI_TYPE_TAG_UINT8: -- return gjs_arg_set_from_js_value(cx, value, arg, this); -- case GI_TYPE_TAG_INT16: -- return gjs_arg_set_from_js_value(cx, value, arg, this); -- case GI_TYPE_TAG_UINT16: -- return gjs_arg_set_from_js_value(cx, value, arg, this); -- case GI_TYPE_TAG_INT32: -- return gjs_arg_set_from_js_value(cx, value, arg, this); -- case GI_TYPE_TAG_DOUBLE: -- return gjs_arg_set_from_js_value(cx, value, arg, this); -- case GI_TYPE_TAG_FLOAT: -- return gjs_arg_set_from_js_value(cx, value, arg, this); -- case GI_TYPE_TAG_INT64: -- return gjs_arg_set_from_js_value(cx, value, arg, this); -- case GI_TYPE_TAG_UINT64: -- return gjs_arg_set_from_js_value(cx, value, arg, this); -- case GI_TYPE_TAG_UINT32: -- return gjs_arg_set_from_js_value(cx, value, arg, this); -- default: -- g_assert_not_reached(); -- } --} -- --GJS_JSAPI_RETURN_CONVENTION - bool UnicharIn::in(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, - JS::HandleValue value) { - if (!value.isString()) -@@ -1025,9 +1184,10 @@ - return true; - } - --GJS_JSAPI_RETURN_CONVENTION --bool StringInTransferNone::in(JSContext* cx, GjsFunctionCallState* state, -- GIArgument* arg, JS::HandleValue value) { -+template -+GJS_JSAPI_RETURN_CONVENTION bool StringInTransferNone::in( -+ JSContext* cx, GjsFunctionCallState* state, GIArgument* arg, -+ JS::HandleValue value) { - if (value.isNull()) - return NullableIn::in(cx, state, arg, value); - -@@ -1035,19 +1195,21 @@ - return report_typeof_mismatch(cx, m_arg_name, value, - ExpectedType::STRING); - -- if (m_filename) { -+ if constexpr (TAG == GI_TYPE_TAG_FILENAME) { - GjsAutoChar str; - if (!gjs_string_to_filename(cx, value, &str)) - return false; - gjs_arg_set(arg, str.release()); - return true; -+ } else if constexpr (TAG == GI_TYPE_TAG_UTF8) { -+ JS::UniqueChars str = gjs_string_to_utf8(cx, value); -+ if (!str) -+ return false; -+ gjs_arg_set(arg, g_strdup(str.get())); -+ return true; -+ } else { -+ return invalid(cx, G_STRFUNC); - } -- -- JS::UniqueChars str = gjs_string_to_utf8(cx, value); -- if (!str) -- return false; -- gjs_arg_set(arg, g_strdup(str.get())); -- return true; - } - - GJS_JSAPI_RETURN_CONVENTION -@@ -1091,8 +1253,7 @@ - - if ((uint64_t(number) & m_mask) != uint64_t(number)) { - gjs_throw(cx, -- "0x%" G_GINT64_MODIFIER -- "x is not a valid value for flags argument %s", -+ "0x%" PRId64 " is not a valid value for flags argument %s", - number, m_arg_name); - return false; - } -@@ -1107,7 +1268,7 @@ - GJS_JSAPI_RETURN_CONVENTION - bool ForeignStructInstanceIn::in(JSContext* cx, GjsFunctionCallState*, - GIArgument* arg, JS::HandleValue value) { -- return gjs_struct_foreign_convert_to_g_argument( -+ return gjs_struct_foreign_convert_to_gi_argument( - cx, value, m_info, m_arg_name, GJS_ARGUMENT_ARGUMENT, m_transfer, - flags(), arg); - } -@@ -1340,14 +1501,20 @@ - GJS_JSAPI_RETURN_CONVENTION - bool GenericInOut::out(JSContext* cx, GjsFunctionCallState*, GIArgument* arg, - JS::MutableHandleValue value) { -- return gjs_value_from_g_argument(cx, value, &m_type_info, arg, true); -+ return gjs_value_from_gi_argument(cx, value, &m_type_info, arg, true); - } - - GJS_JSAPI_RETURN_CONVENTION - bool ExplicitArrayInOut::out(JSContext* cx, GjsFunctionCallState* state, - GIArgument* arg, JS::MutableHandleValue value) { -- GIArgument* length_arg = &(state->out_cvalue(m_length_pos)); -- size_t length = gjs_g_argument_get_array_length(m_tag, length_arg); -+ GIArgument* length_arg; -+ -+ if (m_length_direction != GI_DIRECTION_IN) -+ length_arg = &(state->out_cvalue(m_length_pos)); -+ else -+ length_arg = &(state->in_cvalue(m_length_pos)); -+ -+ size_t length = gjs_gi_argument_get_array_length(m_tag, length_arg); - - return gjs_value_from_explicit_array(cx, value, &m_type_info, m_transfer, - arg, length); -@@ -1358,14 +1525,14 @@ - GIArgument* in_arg, GIArgument*) { - GITransfer transfer = - state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; -- return gjs_g_argument_release_in_arg(cx, transfer, &m_type_info, in_arg); -+ return gjs_gi_argument_release_in_arg(cx, transfer, &m_type_info, in_arg); - } - - GJS_JSAPI_RETURN_CONVENTION - bool GenericOut::release(JSContext* cx, GjsFunctionCallState*, - GIArgument* in_arg [[maybe_unused]], - GIArgument* out_arg) { -- return gjs_g_argument_release(cx, m_transfer, &m_type_info, out_arg); -+ return gjs_gi_argument_release(cx, m_transfer, &m_type_info, out_arg); - } - - GJS_JSAPI_RETURN_CONVENTION -@@ -1376,11 +1543,11 @@ - // freeing it. - - GIArgument* original_out_arg = &state->inout_original_cvalue(m_arg_pos); -- if (!gjs_g_argument_release_in_arg(cx, GI_TRANSFER_NOTHING, &m_type_info, -- original_out_arg)) -+ if (!gjs_gi_argument_release_in_arg(cx, GI_TRANSFER_NOTHING, &m_type_info, -+ original_out_arg)) - return false; - -- return gjs_g_argument_release(cx, m_transfer, &m_type_info, out_arg); -+ return gjs_gi_argument_release(cx, m_transfer, &m_type_info, out_arg); - } - - GJS_JSAPI_RETURN_CONVENTION -@@ -1388,10 +1555,10 @@ - GIArgument* in_arg [[maybe_unused]], - GIArgument* out_arg) { - GIArgument* length_arg = &state->out_cvalue(m_length_pos); -- size_t length = gjs_g_argument_get_array_length(m_tag, length_arg); -+ size_t length = gjs_gi_argument_get_array_length(m_tag, length_arg); - -- return gjs_g_argument_release_out_array(cx, m_transfer, &m_type_info, -- length, out_arg); -+ return gjs_gi_argument_release_out_array(cx, m_transfer, &m_type_info, -+ length, out_arg); - } - - GJS_JSAPI_RETURN_CONVENTION -@@ -1399,34 +1566,42 @@ - GIArgument* in_arg, - GIArgument* out_arg [[maybe_unused]]) { - GIArgument* length_arg = &state->in_cvalue(m_length_pos); -- size_t length = gjs_g_argument_get_array_length(m_tag, length_arg); -+ size_t length = gjs_gi_argument_get_array_length(m_tag, length_arg); - - GITransfer transfer = - state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; - -- return gjs_g_argument_release_in_array(cx, transfer, &m_type_info, length, -- in_arg); -+ return gjs_gi_argument_release_in_array(cx, transfer, &m_type_info, length, -+ in_arg); - } - - GJS_JSAPI_RETURN_CONVENTION - bool ExplicitArrayInOut::release(JSContext* cx, GjsFunctionCallState* state, - GIArgument* in_arg [[maybe_unused]], - GIArgument* out_arg) { -- GIArgument* length_arg = &state->in_cvalue(m_length_pos); -- size_t length = gjs_g_argument_get_array_length(m_tag, length_arg); -+ GIArgument* length_arg = &state->out_cvalue(m_length_pos); -+ size_t length = gjs_gi_argument_get_array_length(m_tag, length_arg); - - // For inout, transfer refers to what we get back from the function; for - // the temporary C value we allocated, clearly we're responsible for - // freeing it. - - GIArgument* original_out_arg = &state->inout_original_cvalue(m_arg_pos); -- if (gjs_arg_get(original_out_arg) != gjs_arg_get(out_arg) && -- !gjs_g_argument_release_in_array(cx, GI_TRANSFER_NOTHING, &m_type_info, -- length, original_out_arg)) -- return false; -+ // Due to https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/192 -+ // Here we've to guess what to do, but in general is "better" to leak than -+ // crash, so let's assume that in/out transfer is matching. -+ if (gjs_arg_get(original_out_arg) != gjs_arg_get(out_arg)) { -+ GITransfer transfer = -+ state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; -+ if (!gjs_gi_argument_release_in_array(cx, transfer, &m_type_info, -+ length, original_out_arg)) -+ return false; -+ } - -- return gjs_g_argument_release_out_array(cx, m_transfer, &m_type_info, -- length, out_arg); -+ GITransfer transfer = -+ state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; -+ return gjs_gi_argument_release_out_array(cx, transfer, &m_type_info, length, -+ out_arg); - } - - GJS_JSAPI_RETURN_CONVENTION -@@ -1459,10 +1634,10 @@ - return true; - } - --GJS_JSAPI_RETURN_CONVENTION --bool StringInTransferNone::release(JSContext*, GjsFunctionCallState*, -- GIArgument* in_arg, -- GIArgument* out_arg [[maybe_unused]]) { -+template -+GJS_JSAPI_RETURN_CONVENTION bool StringInTransferNone::release( -+ JSContext*, GjsFunctionCallState*, GIArgument* in_arg, -+ GIArgument* out_arg [[maybe_unused]]) { - g_free(gjs_arg_get(in_arg)); - return true; - } -@@ -1475,8 +1650,8 @@ - state->call_completed() ? m_transfer : GI_TRANSFER_NOTHING; - - if (transfer == GI_TRANSFER_NOTHING) -- return gjs_struct_foreign_release_g_argument(cx, m_transfer, m_info, -- in_arg); -+ return gjs_struct_foreign_release_gi_argument(cx, m_transfer, m_info, -+ in_arg); - - return true; - } -@@ -1534,7 +1709,7 @@ - #ifdef GJS_DO_ARGUMENTS_SIZE_CHECK - template - constexpr size_t argument_maximum_size() { -- if constexpr (std::is_same_v) -+ if constexpr (std::is_same_v>) - return 24; - if constexpr (std::is_same_v || - std::is_same_v) -@@ -1582,7 +1757,7 @@ - if constexpr (std::is_base_of_v) - arg->m_transfer = transfer; - -- if constexpr (std::is_base_of_v && -+ if constexpr (std::is_base_of_v && - ArgKind != Arg::Kind::INSTANCE) { - arg->m_type_info = std::move(*type_info); - } -@@ -1680,12 +1855,20 @@ - return instance()->as_instance()->gtype(); - } - -+GITypeTag ArgsCache::return_tag() const { -+ Argument* rval = return_value(); -+ if (!rval) -+ return GI_TYPE_TAG_VOID; -+ -+ return rval->return_tag(); -+} -+ - GITypeInfo* ArgsCache::return_type() const { - Argument* rval = return_value(); - if (!rval) - return nullptr; - -- return const_cast(rval->as_return_value()->type_info()); -+ return const_cast(rval->return_type()); - } - - constexpr void ArgsCache::set_skip_all(uint8_t index, const char* name) { -@@ -1734,7 +1917,8 @@ - static_cast(flags | GjsArgumentFlags::SKIP_ALL)); - } - -- array->set_array_length(length_pos, g_type_info_get_tag(&length_type)); -+ array->set_array_length(length_pos, g_type_info_get_tag(&length_type), -+ g_arg_info_get_direction(&length_arg)); - } - - void ArgsCache::build_return(GICallableInfo* callable, bool* inc_counter_out) { -@@ -1753,14 +1937,89 @@ - *inc_counter_out = true; - GjsArgumentFlags flags = GjsArgumentFlags::SKIP_IN; - -- if (tag == GI_TYPE_TAG_ARRAY) { -- int length_pos = g_type_info_get_array_length(&type_info); -- if (length_pos >= 0) { -- set_array_argument( -- callable, 0, &type_info, GI_DIRECTION_OUT, nullptr, flags, -- length_pos); -+ if (g_callable_info_may_return_null(callable)) -+ flags |= GjsArgumentFlags::MAY_BE_NULL; -+ -+ switch (tag) { -+ case GI_TYPE_TAG_BOOLEAN: -+ set_return(&type_info, transfer, flags); - return; -+ -+ case GI_TYPE_TAG_INT8: -+ set_return>( -+ &type_info, transfer, flags); -+ return; -+ -+ case GI_TYPE_TAG_INT16: -+ set_return>( -+ &type_info, transfer, flags); -+ return; -+ -+ case GI_TYPE_TAG_INT32: -+ set_return>( -+ &type_info, transfer, flags); -+ return; -+ -+ case GI_TYPE_TAG_UINT8: -+ set_return>( -+ &type_info, transfer, flags); -+ return; -+ -+ case GI_TYPE_TAG_UINT16: -+ set_return>( -+ &type_info, transfer, flags); -+ return; -+ -+ case GI_TYPE_TAG_UINT32: -+ set_return>( -+ &type_info, transfer, flags); -+ return; -+ -+ case GI_TYPE_TAG_INT64: -+ set_return>( -+ &type_info, transfer, flags); -+ return; -+ -+ case GI_TYPE_TAG_UINT64: -+ set_return>( -+ &type_info, transfer, flags); -+ return; -+ -+ case GI_TYPE_TAG_FLOAT: -+ set_return>( -+ &type_info, transfer, flags); -+ return; -+ -+ case GI_TYPE_TAG_DOUBLE: -+ set_return>( -+ &type_info, transfer, flags); -+ return; -+ -+ case GI_TYPE_TAG_UTF8: -+ if (transfer == GI_TRANSFER_NOTHING) { -+ set_return>( -+ &type_info, transfer, flags); -+ return; -+ } else { -+ set_return>( -+ &type_info, transfer, flags); -+ return; -+ } -+ -+ case GI_TYPE_TAG_ARRAY: { -+ int length_pos = g_type_info_get_array_length(&type_info); -+ if (length_pos >= 0) { -+ set_array_argument( -+ callable, 0, &type_info, GI_DIRECTION_OUT, nullptr, flags, -+ length_pos); -+ return; -+ } -+ -+ [[fallthrough]]; - } -+ -+ default: -+ break; - } - - // in() is ignored for the return value, but skip_in is not (it is used -@@ -2020,17 +2279,44 @@ - break; - - case GI_TYPE_TAG_INT8: -+ set_argument_auto>(common_args); -+ return; -+ - case GI_TYPE_TAG_INT16: -+ set_argument_auto>(common_args); -+ return; -+ - case GI_TYPE_TAG_INT32: -+ set_argument_auto>(common_args); -+ return; -+ - case GI_TYPE_TAG_UINT8: -+ set_argument_auto>(common_args); -+ return; -+ - case GI_TYPE_TAG_UINT16: -+ set_argument_auto>(common_args); -+ return; -+ - case GI_TYPE_TAG_UINT32: -+ set_argument_auto>(common_args); -+ return; -+ - case GI_TYPE_TAG_INT64: -+ set_argument_auto>(common_args); -+ return; -+ - case GI_TYPE_TAG_UINT64: -+ set_argument_auto>(common_args); -+ return; -+ - case GI_TYPE_TAG_FLOAT: -+ set_argument_auto>(common_args); -+ return; -+ - case GI_TYPE_TAG_DOUBLE: -- set_argument_auto(common_args, tag); -- break; -+ set_argument_auto>(common_args); -+ return; - - case GI_TYPE_TAG_UNICHAR: - set_argument_auto(common_args); -@@ -2049,7 +2335,8 @@ - - case GI_TYPE_TAG_UTF8: - if (transfer == GI_TRANSFER_NOTHING) -- set_argument_auto(common_args); -+ set_argument_auto>( -+ common_args); - else - set_argument_auto(common_args); - break; -@@ -2073,6 +2360,132 @@ - } - } - -+void ArgsCache::build_normal_out_arg(uint8_t gi_index, GITypeInfo* type_info, -+ GIArgInfo* arg, GjsArgumentFlags flags) { -+ const char* name = g_base_info_get_name(arg); -+ GITransfer transfer = g_arg_info_get_ownership_transfer(arg); -+ auto common_args = -+ std::make_tuple(gi_index, name, type_info, transfer, flags); -+ GITypeTag tag = g_type_info_get_tag(type_info); -+ -+ switch (tag) { -+ case GI_TYPE_TAG_BOOLEAN: -+ set_argument_auto(common_args); -+ break; -+ -+ case GI_TYPE_TAG_INT8: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_INT16: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_INT32: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_UINT8: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_UINT16: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_UINT32: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_INT64: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_UINT64: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_FLOAT: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_DOUBLE: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_UTF8: -+ if (transfer == GI_TRANSFER_NOTHING) { -+ set_argument_auto>( -+ common_args); -+ } else { -+ set_argument_auto>( -+ common_args); -+ } -+ return; -+ -+ default: -+ set_argument_auto(common_args); -+ } -+} -+ -+void ArgsCache::build_normal_inout_arg(uint8_t gi_index, GITypeInfo* type_info, -+ GIArgInfo* arg, GjsArgumentFlags flags) { -+ const char* name = g_base_info_get_name(arg); -+ GITransfer transfer = g_arg_info_get_ownership_transfer(arg); -+ auto common_args = -+ std::make_tuple(gi_index, name, type_info, transfer, flags); -+ GITypeTag tag = g_type_info_get_tag(type_info); -+ -+ switch (tag) { -+ case GI_TYPE_TAG_BOOLEAN: -+ set_argument_auto(common_args); -+ break; -+ -+ case GI_TYPE_TAG_INT8: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_INT16: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_INT32: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_UINT8: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_UINT16: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_UINT32: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_INT64: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_UINT64: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_FLOAT: -+ set_argument_auto>(common_args); -+ return; -+ -+ case GI_TYPE_TAG_DOUBLE: -+ set_argument_auto>(common_args); -+ return; -+ -+ default: -+ set_argument_auto(common_args); -+ } -+} -+ - void ArgsCache::build_instance(GICallableInfo* callable) { - if (!m_is_method) - return; -@@ -2107,6 +2520,11 @@ - GjsArgumentFlags::NONE); - } - -+static constexpr bool type_tag_is_scalar(GITypeTag tag) { -+ return GI_TYPE_TAG_IS_NUMERIC(tag) || tag == GI_TYPE_TAG_BOOLEAN || -+ tag == GI_TYPE_TAG_GTYPE; -+} -+ - void ArgsCache::build_arg(uint8_t gi_index, GIDirection direction, - GIArgInfo* arg, GICallableInfo* callable, - bool* inc_counter_out) { -@@ -2159,7 +2577,11 @@ - default: - break; - } -- } else { -+ } else if (!type_tag_is_scalar(type_tag) && -+ !g_type_info_is_pointer(&type_info)) { -+ // Scalar out parameters should not be annotated with -+ // caller-allocates, which is for structured types that need to be -+ // allocated in order for the function to fill them in. - size = gjs_type_get_element_size(type_tag, &type_info); - } - -@@ -2254,15 +2676,31 @@ - } - - return; -+ } else if (g_type_info_is_zero_terminated(&type_info)) { -+ if (direction == GI_DIRECTION_IN) { -+ set_argument_auto(common_args); -+ return; -+ } else if (direction == GI_DIRECTION_INOUT) { -+ set_argument_auto(common_args); -+ return; -+ } -+ } else if (g_type_info_get_array_fixed_size(&type_info) >= 0) { -+ if (direction == GI_DIRECTION_IN) { -+ set_argument_auto(common_args); -+ return; -+ } else if (direction == GI_DIRECTION_INOUT) { -+ set_argument_auto(common_args); -+ return; -+ } - } - } - - if (direction == GI_DIRECTION_IN) - build_normal_in_arg(gi_index, &type_info, arg, flags); - else if (direction == GI_DIRECTION_INOUT) -- set_argument_auto(common_args); -+ build_normal_inout_arg(gi_index, &type_info, arg, flags); - else -- set_argument_auto(common_args); -+ build_normal_out_arg(gi_index, &type_info, arg, flags); - - return; - } -diff -ruN cjs-6.2.0-orig/gi/arg-cache.h cjs-6.2.0/gi/arg-cache.h ---- cjs-6.2.0-orig/gi/arg-cache.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/arg-cache.h 2024-10-14 18:41:39.000000000 +0200 -@@ -94,7 +94,8 @@ - protected: - constexpr Argument() : m_skip_in(false), m_skip_out(false) {} - -- virtual const Arg::ReturnValue* as_return_value() const { return nullptr; } -+ virtual GITypeTag return_tag() const { return GI_TYPE_TAG_VOID; } -+ virtual const GITypeInfo* return_type() const { return nullptr; } - virtual const Arg::Instance* as_instance() const { return nullptr; } - - constexpr void set_instance_parameter() { -@@ -156,11 +157,16 @@ - void build_instance(GICallableInfo* callable); - - GType instance_type() const; -+ GITypeTag return_tag() const; - GITypeInfo* return_type() const; - - private: - void build_normal_in_arg(uint8_t gi_index, GITypeInfo*, GIArgInfo*, - GjsArgumentFlags); -+ void build_normal_out_arg(uint8_t gi_index, GITypeInfo*, GIArgInfo*, -+ GjsArgumentFlags); -+ void build_normal_inout_arg(uint8_t gi_index, GITypeInfo*, GIArgInfo*, -+ GjsArgumentFlags); - - template - void build_interface_in_arg(uint8_t gi_index, GITypeInfo*, GIBaseInfo*, -diff -ruN cjs-6.2.0-orig/gi/arg-inl.h cjs-6.2.0/gi/arg-inl.h ---- cjs-6.2.0-orig/gi/arg-inl.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/arg-inl.h 2024-10-14 18:41:39.000000000 +0200 -@@ -4,6 +4,8 @@ - - #pragma once - -+#include -+ - #include - - #include // for nullptr_t -@@ -114,6 +116,20 @@ - } - } - -+typedef enum { -+ GJS_TYPE_TAG_LONG = 0, -+} ExtraTag; -+ -+template -+[[nodiscard]] constexpr inline decltype(auto) gjs_arg_member(GIArgument* arg) { -+ if constexpr (TAG == GJS_TYPE_TAG_LONG && -+ std::is_same_v) // NOLINT(runtime/int) -+ return gjs_arg_member<&GIArgument::v_long>(arg); -+ else if constexpr (TAG == GJS_TYPE_TAG_LONG && -+ std::is_same_v) // NOLINT(runtime/int) -+ return gjs_arg_member<&GIArgument::v_ulong>(arg); -+} -+ - template - constexpr inline void gjs_arg_set(GIArgument* arg, T v) { - if constexpr (std::is_pointer_v) { -@@ -129,6 +145,11 @@ - } - } - -+template -+constexpr inline void gjs_arg_set(GIArgument* arg, T v) { -+ gjs_arg_member(arg) = v; -+} -+ - // Store function pointers as void*. It is a requirement of GLib that your - // compiler can do this - template -@@ -151,6 +172,11 @@ - return gjs_arg_member(arg); - } - -+template -+[[nodiscard]] constexpr inline T gjs_arg_get(GIArgument* arg) { -+ return gjs_arg_member(arg); -+} -+ - template - [[nodiscard]] constexpr inline void* gjs_arg_get_as_pointer(GIArgument* arg) { - return gjs_int_to_pointer(gjs_arg_get(arg)); -@@ -192,29 +218,29 @@ - return static_cast(val); - } - --template -+template - GJS_JSAPI_RETURN_CONVENTION inline bool gjs_arg_set_from_js_value( -- JSContext* cx, const JS::HandleValue& value, GArgument* arg, -+ JSContext* cx, const JS::HandleValue& value, GIArgument* arg, - bool* out_of_range) { - if constexpr (Gjs::type_has_js_getter()) -- return Gjs::js_value_to_c(cx, value, &gjs_arg_member(arg)); -+ return Gjs::js_value_to_c(cx, value, &gjs_arg_member(arg)); - - Gjs::JsValueHolder::Relaxed val{}; - -- if (!Gjs::js_value_to_c_checked(cx, value, &val, out_of_range)) -+ if (!Gjs::js_value_to_c_checked(cx, value, &val, out_of_range)) - return false; - - if (*out_of_range) - return false; - -- gjs_arg_set(arg, val); -+ gjs_arg_set(arg, val); - - return true; - } - - // A helper function to retrieve array lengths from a GIArgument (letting the - // compiler generate good instructions in case of big endian machines) --[[nodiscard]] constexpr size_t gjs_g_argument_get_array_length( -+[[nodiscard]] constexpr size_t gjs_gi_argument_get_array_length( - GITypeTag tag, GIArgument* arg) { - switch (tag) { - case GI_TYPE_TAG_INT8: -diff -ruN cjs-6.2.0-orig/gi/arg-types-inl.h cjs-6.2.0/gi/arg-types-inl.h ---- cjs-6.2.0-orig/gi/arg-types-inl.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/arg-types-inl.h 2024-09-16 22:32:54.000000000 +0200 -@@ -102,4 +102,14 @@ - return "string"; - } - -+template <> -+inline const char* static_type_name() { -+ return "constant string"; -+} -+ -+template <> -+inline const char* static_type_name() { -+ return "void"; -+} -+ - } // namespace Gjs -diff -ruN cjs-6.2.0-orig/gi/arg.cpp cjs-6.2.0/gi/arg.cpp ---- cjs-6.2.0-orig/gi/arg.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/arg.cpp 2024-10-14 18:41:39.000000000 +0200 -@@ -5,11 +5,11 @@ - - #include - -+#include - #include - #include // for strcmp, strlen, memcpy - - #include --#include - - #include - #include -@@ -32,6 +32,7 @@ - #include - #include - #include // for InformalValueTypeName, IdVector -+#include - - #include "gi/arg-inl.h" - #include "gi/arg-types-inl.h" -@@ -65,7 +66,7 @@ - GITypeInfo* arginfo, const char* arg_name, - GjsArgumentType arg_type); - --bool _gjs_flags_value_is_valid(JSContext* context, GType gtype, int64_t value) { -+bool _gjs_flags_value_is_valid(JSContext* cx, GType gtype, int64_t value) { - /* Do proper value check for flags with GType's */ - if (gtype != G_TYPE_NONE) { - GjsAutoTypeClass gflags_class(gtype); -@@ -73,9 +74,8 @@ - - /* check all bits are valid bits for the flag and is a 32 bit flag*/ - if ((tmpval &= gflags_class->mask) != value) { /* Not a guint32 with invalid mask values*/ -- gjs_throw(context, -- "0x%" G_GINT64_MODIFIER "x is not a valid value for flags %s", -- value, g_type_name(gtype)); -+ gjs_throw(cx, "0x%" PRIx64 " is not a valid value for flags %s", -+ value, g_type_name(gtype)); - return false; - } - } -@@ -84,7 +84,7 @@ - } - - GJS_JSAPI_RETURN_CONVENTION --static bool _gjs_enum_value_is_valid(JSContext* context, GIEnumInfo* enum_info, -+static bool _gjs_enum_value_is_valid(JSContext* cx, GIEnumInfo* enum_info, - int64_t value) { - bool found; - int n_values; -@@ -104,9 +104,8 @@ - } - - if (!found) { -- gjs_throw(context, -- "%" G_GINT64_MODIFIER "d is not a valid value for enumeration %s", -- value, g_base_info_get_name((GIBaseInfo *)enum_info)); -+ gjs_throw(cx, "%" PRId64 " is not a valid value for enumeration %s", -+ value, g_base_info_get_name(enum_info)); - } - - return found; -@@ -163,7 +162,7 @@ - g_type_info_get_interface(type_info); - g_assert(interface_info != nullptr); - -- switch (g_base_info_get_type(interface_info)) { -+ switch (interface_info.type()) { - case GI_INFO_TYPE_STRUCT: - case GI_INFO_TYPE_ENUM: - case GI_INFO_TYPE_FLAGS: -@@ -175,9 +174,6 @@ - // cast is safe - gtype = g_registered_type_info_get_g_type(interface_info); - break; -- case GI_INFO_TYPE_VALUE: -- // Special case for GValues -- return true; - default: - gtype = G_TYPE_NONE; - } -@@ -218,7 +214,7 @@ - GjsAutoBaseInfo interface_info = - g_type_info_get_interface(type_info); - -- switch (g_base_info_get_type(interface_info)) { -+ switch (interface_info.type()) { - case GI_INFO_TYPE_ENUM: - case GI_INFO_TYPE_FLAGS: - return false; -@@ -271,7 +267,7 @@ - if (transfer == GI_TRANSFER_CONTAINER) { - if (type_needs_release (param_info, g_type_info_get_tag(param_info))) { - /* FIXME: to make this work, we'd have to keep a list of temporary -- * GArguments for the function call so we could free them after -+ * GIArguments for the function call so we could free them after - * the surrounding container had been freed by the callee. - */ - gjs_throw(cx, "Container transfer for in parameters not supported"); -@@ -286,8 +282,6 @@ - T* list = nullptr; - - for (size_t i = 0; i < length; ++i) { -- GArgument elem_arg = { 0 }; -- - elem = JS::UndefinedValue(); - if (!JS_GetElement(cx, array, i, &elem)) { - gjs_throw(cx, "Missing array element %zu", i); -@@ -298,9 +292,10 @@ - * gobject-introspection needs to tell us this. - * Always say they can't for now. - */ -- if (!gjs_value_to_g_argument(cx, elem, param_info, -- GJS_ARGUMENT_LIST_ELEMENT, transfer, -- &elem_arg)) { -+ GIArgument elem_arg; -+ if (!gjs_value_to_gi_argument(cx, elem, param_info, -+ GJS_ARGUMENT_LIST_ELEMENT, transfer, -+ &elem_arg)) { - return false; - } - -@@ -327,7 +322,7 @@ - GITypeTag key_type) { - /* Don't use key/value destructor functions here, because we can't - * construct correct ones in general if the value type is complex. -- * Rely on the type-aware g_argument_release functions. */ -+ * Rely on the type-aware gi_argument_release functions. */ - if (is_string_type(key_type)) - return g_hash_table_new(g_str_hash, g_str_equal); - return g_hash_table_new(NULL, NULL); -@@ -492,14 +487,14 @@ - - g_assert(props && "Property bag cannot be null"); - -- GjsAutoBaseInfo key_param_info = g_type_info_get_param_type(type_info, 0); -- GjsAutoBaseInfo val_param_info = g_type_info_get_param_type(type_info, 1); -+ GjsAutoTypeInfo key_param_info = g_type_info_get_param_type(type_info, 0); -+ GjsAutoTypeInfo val_param_info = g_type_info_get_param_type(type_info, 1); - - if (transfer == GI_TRANSFER_CONTAINER) { - if (type_needs_release (key_param_info, g_type_info_get_tag(key_param_info)) || - type_needs_release (val_param_info, g_type_info_get_tag(val_param_info))) { - /* FIXME: to make this work, we'd have to keep a list of temporary -- * GArguments for the function call so we could free them after -+ * GIArguments for the function call so we could free them after - * the surrounding container had been freed by the callee. - */ - gjs_throw(context, -@@ -530,9 +525,9 @@ - !value_to_ghashtable_key(context, key_js, key_tag, &key_ptr) || - !JS_GetPropertyById(context, props, cur_id, &val_js) || - // Type check and convert value to a C type -- !gjs_value_to_g_argument(context, val_js, val_param_info, nullptr, -- GJS_ARGUMENT_HASH_ELEMENT, transfer, -- GjsArgumentFlags::MAY_BE_NULL, &val_arg)) -+ !gjs_value_to_gi_argument(context, val_js, val_param_info, nullptr, -+ GJS_ARGUMENT_HASH_ELEMENT, transfer, -+ GjsArgumentFlags::MAY_BE_NULL, &val_arg)) - return false; - - GITypeTag val_type = g_type_info_get_tag(val_param_info); -@@ -644,7 +639,7 @@ - return false; - } - -- JS::RootedObject obj(context, JS::NewArrayObject(context, elems)); -+ JSObject* obj = JS::NewArrayObject(context, elems); - if (!obj) - return false; - -@@ -731,10 +726,9 @@ - return false; - } - -- if (!gjs_value_to_g_argument( -- context, elem, param_info, -- GJS_ARGUMENT_ARRAY_ELEMENT, transfer, -- &arg)) { -+ if (!gjs_value_to_gi_argument(context, elem, param_info, -+ GJS_ARGUMENT_ARRAY_ELEMENT, transfer, -+ &arg)) { - gjs_throw(context, - "Invalid element in array"); - return false; -@@ -767,9 +761,9 @@ - } - - GIArgument arg; -- if (!gjs_value_to_g_argument(cx, elem, param_info, -- GJS_ARGUMENT_ARRAY_ELEMENT, -- GI_TRANSFER_NOTHING, &arg)) -+ if (!gjs_value_to_gi_argument(cx, elem, param_info, -+ GJS_ARGUMENT_ARRAY_ELEMENT, -+ GI_TRANSFER_NOTHING, &arg)) - return false; - - memcpy(&flat_array[param_size * i], gjs_arg_get(&arg), -@@ -780,11 +774,8 @@ - return true; - } - --[[nodiscard]] static bool is_gvalue(GIBaseInfo* info, GIInfoType info_type) { -- switch (info_type) { -- case GI_INFO_TYPE_VALUE: -- return true; -- -+[[nodiscard]] static bool is_gvalue(GIBaseInfo* info) { -+ switch (g_base_info_get_type(info)) { - case GI_INFO_TYPE_STRUCT: - case GI_INFO_TYPE_OBJECT: - case GI_INFO_TYPE_INTERFACE: -@@ -852,9 +843,7 @@ - if (!g_type_info_is_pointer(param_info)) { - GjsAutoBaseInfo interface_info = - g_type_info_get_interface(param_info); -- GIInfoType info_type = g_base_info_get_type(interface_info); -- -- if (is_gvalue(interface_info, info_type)) { -+ if (is_gvalue(interface_info)) { - // Special case for GValue "flat arrays", this could also - // using the generic case, but if we do so we're leaking atm. - return gjs_array_to_auto_array(context, array_value, -@@ -935,7 +924,7 @@ - case GI_TYPE_TAG_INTERFACE: { - GjsAutoBaseInfo interface_info = g_type_info_get_interface(type_info); - -- switch (g_base_info_get_type(interface_info)) { -+ switch (interface_info.type()) { - case GI_INFO_TYPE_ENUM: - case GI_INFO_TYPE_FLAGS: - return sizeof(unsigned int); -@@ -944,8 +933,6 @@ - return g_struct_info_get_size(interface_info); - case GI_INFO_TYPE_UNION: - return g_union_info_get_size(interface_info); -- case GI_INFO_TYPE_VALUE: -- return sizeof(GValue); - default: - return 0; - } -@@ -960,14 +947,10 @@ - if (length < 0) - return sizeof(void*); - -- GjsAutoBaseInfo param_info = -+ GjsAutoTypeInfo param_info = - g_type_info_get_param_type(type_info, 0); - GITypeTag param_tag = g_type_info_get_tag(param_info); -- size_t param_size = -- gjs_type_get_element_size(param_tag, param_info); -- -- if (param_size) -- return param_size * length; -+ return gjs_type_get_element_size(param_tag, param_info); - } - - return sizeof(void*); -@@ -979,22 +962,27 @@ - g_return_val_if_reached(0); - } - --template --static inline bool gjs_g_argument_release_array_internal( -+enum class ArrayReleaseType { -+ EXPLICIT_LENGTH, -+ ZERO_TERMINATED, -+}; -+ -+template -+static inline bool gjs_gi_argument_release_array_internal( - JSContext* cx, GITransfer element_transfer, GjsArgumentFlags flags, - GITypeInfo* param_type, unsigned length, GIArgument* arg) { - GjsAutoPointer arg_array = - gjs_arg_steal(arg); - -+ if (!arg_array) -+ return true; -+ - if (element_transfer != GI_TRANSFER_EVERYTHING) - return true; - -- if constexpr (!zero_terminated) { -+ if constexpr (release_type == ArrayReleaseType::EXPLICIT_LENGTH) { - if (length == 0) - return true; -- } else { -- if (!arg_array) -- return true; - } - - GITypeTag type_tag = g_type_info_get_tag(param_type); -@@ -1015,16 +1003,21 @@ - for (size_t i = 0;; i++) { - GIArgument elem; - auto* element_start = &arg_array[i * element_size]; -+ auto* pointer = -+ is_pointer ? *reinterpret_cast(element_start) : nullptr; - -- if constexpr (zero_terminated) { -- if (*element_start == 0 && -- memcmp(element_start, element_start + 1, element_size - 1) == 0) -+ if constexpr (release_type == ArrayReleaseType::ZERO_TERMINATED) { -+ if (is_pointer) { -+ if (!pointer) -+ break; -+ } else if (*element_start == 0 && -+ memcmp(element_start, element_start + 1, -+ element_size - 1) == 0) { - break; -+ } - } - -- gjs_arg_set(&elem, is_pointer -- ? *reinterpret_cast(element_start) -- : element_start); -+ gjs_arg_set(&elem, is_pointer ? pointer : element_start); - JS::AutoSaveExceptionState saved_exc(cx); - if (!gjs_g_arg_release_internal(cx, element_transfer, param_type, - type_tag, GJS_ARGUMENT_ARRAY_ELEMENT, -@@ -1032,7 +1025,7 @@ - return false; - } - -- if constexpr (!zero_terminated) { -+ if constexpr (release_type == ArrayReleaseType::EXPLICIT_LENGTH) { - if (i == length - 1) - break; - } -@@ -1076,7 +1069,7 @@ - - if (tag == GI_TYPE_TAG_INTERFACE) { - GjsAutoBaseInfo interface = g_type_info_get_interface(type_info); -- return g_info_type_to_string(g_base_info_get_type(interface)); -+ return g_info_type_to_string(interface.type()); - } else { - return g_type_tag_to_string(tag); - } -@@ -1173,10 +1166,7 @@ - } - } // namespace arg - --static void --intern_gdk_atom(const char *name, -- GArgument *ret) --{ -+static void intern_gdk_atom(const char* name, GIArgument* ret) { - GjsAutoFunctionInfo atom_intern_fun = - g_irepository_find_by_name(nullptr, "Gdk", "atom_intern"); - -@@ -1187,11 +1177,8 @@ - gjs_arg_set(&atom_intern_args[0], name); - gjs_arg_set(&atom_intern_args[1], false); - -- g_function_info_invoke(atom_intern_fun, -- atom_intern_args, 2, -- nullptr, 0, -- ret, -- nullptr); -+ mozilla::Unused << g_function_info_invoke(atom_intern_fun, atom_intern_args, -+ 2, nullptr, 0, ret, nullptr); - } - - static bool value_to_interface_gi_argument( -@@ -1215,11 +1202,6 @@ - gtype = g_registered_type_info_get_g_type(interface_info); - break; - -- case GI_INFO_TYPE_VALUE: -- // Special case for GValues -- gtype = G_TYPE_VALUE; -- break; -- - default: - gtype = G_TYPE_NONE; - } -@@ -1358,11 +1340,18 @@ - - } else if (g_type_is_a(gtype, G_TYPE_BOXED)) { - if (g_type_is_a(gtype, G_TYPE_CLOSURE)) { -+ if (BoxedBase::typecheck(cx, obj, interface_info, gtype, -+ GjsTypecheckNoThrow())) { -+ return BoxedBase::transfer_to_gi_argument( -+ cx, obj, arg, GI_DIRECTION_IN, transfer, gtype, -+ interface_info); -+ } -+ - GClosure* closure = - Gjs::Closure::create_marshaled(cx, obj, "boxed"); - // GI doesn't know about floating GClosure references. We - // guess that if this is a return value going from JS::Value -- // to GArgument, it's intended to be passed to a C API that -+ // to GIArgument, it's intended to be passed to a C API that - // will consume the floating reference. - if (arg_type != GJS_ARGUMENT_RETURN_VALUE) { - g_closure_ref(closure); -@@ -1458,7 +1447,7 @@ - - template - GJS_JSAPI_RETURN_CONVENTION inline static bool gjs_arg_set_from_js_value( -- JSContext* cx, const JS::HandleValue& value, GArgument* arg, -+ JSContext* cx, const JS::HandleValue& value, GIArgument* arg, - const char* arg_name, GjsArgumentType arg_type) { - bool out_of_range = false; - -@@ -1498,10 +1487,10 @@ - return true; - } - --bool gjs_value_to_g_argument(JSContext* context, JS::HandleValue value, -- GITypeInfo* type_info, const char* arg_name, -- GjsArgumentType arg_type, GITransfer transfer, -- GjsArgumentFlags flags, GIArgument* arg) { -+bool gjs_value_to_gi_argument(JSContext* context, JS::HandleValue value, -+ GITypeInfo* type_info, const char* arg_name, -+ GjsArgumentType arg_type, GITransfer transfer, -+ GjsArgumentFlags flags, GIArgument* arg) { - GITypeTag type_tag = g_type_info_get_tag(type_info); - - gjs_debug_marshal( -@@ -1648,7 +1637,7 @@ - GjsAutoBaseInfo interface_info = g_type_info_get_interface(type_info); - g_assert(interface_info); - -- GIInfoType interface_type = g_base_info_get_type(interface_info); -+ GIInfoType interface_type = interface_info.type(); - if (interface_type == GI_INFO_TYPE_ENUM || - interface_type == GI_INFO_TYPE_FLAGS || - arg::is_gdk_atom(interface_info)) -@@ -1656,7 +1645,7 @@ - - if (interface_type == GI_INFO_TYPE_STRUCT && - g_struct_info_is_foreign(interface_info)) { -- return gjs_struct_foreign_convert_to_g_argument( -+ return gjs_struct_foreign_convert_to_gi_argument( - context, value, interface_info, arg_name, arg_type, transfer, - flags, arg); - } -@@ -1765,7 +1754,7 @@ - break; - } - default: -- g_warning("Unhandled type %s for JavaScript to GArgument conversion", -+ g_warning("Unhandled type %s for JavaScript to GIArgument conversion", - g_type_tag_to_string(type_tag)); - throw_invalid_argument(context, value, type_info, arg_name, arg_type); - return false; -@@ -1779,13 +1768,11 @@ - * is. It basically boils down to memset(arg, 0, sizeof(*arg)), but - * gives as a bit more future flexibility and also will work if - * libffi passes us a buffer that only has room for the appropriate -- * branch of GArgument. (Currently it appears that the return buffer -+ * branch of GIArgument. (Currently it appears that the return buffer - * has a fixed size large enough for the union of all types.) - */ - void gjs_gi_argument_init_default(GITypeInfo* type_info, GIArgument* arg) { -- GITypeTag type_tag; -- -- type_tag = g_type_info_get_tag( (GITypeInfo*) type_info); -+ GITypeTag type_tag = g_type_info_get_tag(type_info); - - switch (type_tag) { - case GI_TYPE_TAG_VOID: -@@ -1839,13 +1826,11 @@ - gjs_arg_unset(arg); - break; - case GI_TYPE_TAG_INTERFACE: { -- GIInfoType interface_type; -- - GjsAutoBaseInfo interface_info = - g_type_info_get_interface(type_info); - g_assert(interface_info != nullptr); - -- interface_type = g_base_info_get_type(interface_info); -+ GIInfoType interface_type = interface_info.type(); - - if (interface_type == GI_INFO_TYPE_ENUM || - interface_type == GI_INFO_TYPE_FLAGS) -@@ -1861,7 +1846,7 @@ - gjs_arg_unset(arg); - break; - default: -- g_warning("Unhandled type %s for default GArgument initialization", -+ g_warning("Unhandled type %s for default GIArgument initialization", - g_type_tag_to_string(type_tag)); - break; - } -@@ -1897,7 +1882,7 @@ - if (g_arg_info_is_caller_allocates(arg_info)) - flags |= GjsArgumentFlags::CALLER_ALLOCATES; - -- return gjs_value_to_g_argument( -+ return gjs_value_to_gi_argument( - context, value, &type_info, g_base_info_get_name(arg_info), - (g_arg_info_is_return_value(arg_info) ? GJS_ARGUMENT_RETURN_VALUE - : GJS_ARGUMENT_ARGUMENT), -@@ -1909,12 +1894,12 @@ - JSContext* cx, JS::MutableHandleValue value_p, GITypeInfo* type_info, - GITransfer transfer, T* list) { - static_assert(std::is_same_v || std::is_same_v); -- GArgument arg; - JS::RootedValueVector elems(cx); - GjsAutoTypeInfo param_info = g_type_info_get_param_type(type_info, 0); - - g_assert(param_info); - -+ GIArgument arg; - for (size_t i = 0; list; list = list->next, ++i) { - g_type_info_argument_from_hash_pointer(param_info, list->data, &arg); - -@@ -1923,13 +1908,13 @@ - return false; - } - -- if (!gjs_value_from_g_argument(cx, elems[i], param_info, -- GJS_ARGUMENT_LIST_ELEMENT, transfer, -- &arg)) -+ if (!gjs_value_from_gi_argument(cx, elems[i], param_info, -+ GJS_ARGUMENT_LIST_ELEMENT, transfer, -+ &arg)) - return false; - } - -- JS::RootedObject obj(cx, JS::NewArrayObject(cx, elems)); -+ JSObject* obj = JS::NewArrayObject(cx, elems); - if (!obj) - return false; - -@@ -1974,9 +1959,9 @@ - for (size_t i = 0; i < length; i++) { - gjs_arg_set(arg, *(static_cast(array) + i)); - -- if (!gjs_value_from_g_argument(cx, elems[i], param_info, -- GJS_ARGUMENT_ARRAY_ELEMENT, -- transfer, arg)) -+ if (!gjs_value_from_gi_argument(cx, elems[i], param_info, -+ GJS_ARGUMENT_ARRAY_ELEMENT, transfer, -+ arg)) - return false; - } - -@@ -1987,7 +1972,6 @@ - static bool gjs_array_from_carray_internal( - JSContext* context, JS::MutableHandleValue value_p, GIArrayType array_type, - GITypeInfo* param_info, GITransfer transfer, guint length, void* array) { -- GArgument arg; - GITypeTag element_type; - guint i; - -@@ -1995,7 +1979,7 @@ - - /* Special case array(guint8) */ - if (element_type == GI_TYPE_TAG_UINT8) { -- JSObject* obj = gjs_byte_array_from_data(context, length, array); -+ JSObject* obj = gjs_byte_array_from_data_copy(context, length, array); - if (!obj) - return false; - value_p.setObject(*obj); -@@ -2021,6 +2005,7 @@ - return false; - } - -+ GIArgument arg; - switch (element_type) { - /* Special cases handled above */ - case GI_TYPE_TAG_UINT8: -@@ -2079,12 +2064,11 @@ - case GI_TYPE_TAG_INTERFACE: { - GjsAutoBaseInfo interface_info = - g_type_info_get_interface(param_info); -- GIInfoType info_type = g_base_info_get_type (interface_info); -+ GIInfoType info_type = interface_info.type(); - - if (array_type != GI_ARRAY_TYPE_PTR_ARRAY && - (info_type == GI_INFO_TYPE_STRUCT || -- info_type == GI_INFO_TYPE_UNION || -- info_type == GI_INFO_TYPE_VALUE) && -+ info_type == GI_INFO_TYPE_UNION) && - !g_type_info_is_pointer(param_info)) { - size_t struct_size; - -@@ -2097,7 +2081,7 @@ - gjs_arg_set(&arg, - static_cast(array) + (struct_size * i)); - -- if (!gjs_value_from_g_argument( -+ if (!gjs_value_from_gi_argument( - context, elems[i], param_info, - GJS_ARGUMENT_ARRAY_ELEMENT, transfer, &arg)) - return false; -@@ -2125,7 +2109,7 @@ - return false; - } - -- JS::RootedObject obj(context, JS::NewArrayObject(context, elems)); -+ JSObject* obj = JS::NewArrayObject(context, elems); - if (!obj) - return false; - -@@ -2168,7 +2152,7 @@ - JS::MutableHandleValue value_p, - GIArrayType array_type, - GITypeInfo* param_info, -- GITransfer transfer, GArgument* arg) { -+ GITransfer transfer, GIArgument* arg) { - GArray *array; - GPtrArray *ptr_array; - gpointer data = NULL; -@@ -2192,7 +2176,7 @@ - data = ptr_array->pdata; - length = ptr_array->len; - break; -- case GI_ARRAY_TYPE_C: /* already checked in gjs_value_from_g_argument() */ -+ case GI_ARRAY_TYPE_C: // already checked in gjs_value_from_gi_argument() - default: - g_assert_not_reached(); - } -@@ -2227,6 +2211,8 @@ - length = ptr_array->len; - } else { - g_assert_not_reached(); -+ gjs_throw(cx, "%s is not an array type", g_type_name(value_gtype)); -+ return false; - } - - return gjs_array_from_carray_internal(cx, value_p, array_type, param_info, -@@ -2261,9 +2247,9 @@ - return false; - } - -- if (!gjs_value_from_g_argument(cx, elems[i], param_info, -- GJS_ARGUMENT_ARRAY_ELEMENT, transfer, -- arg)) -+ if (!gjs_value_from_gi_argument(cx, elems[i], param_info, -+ GJS_ARGUMENT_ARRAY_ELEMENT, transfer, -+ arg)) - return false; - } - -@@ -2274,7 +2260,6 @@ - static bool gjs_array_from_zero_terminated_c_array( - JSContext* context, JS::MutableHandleValue value_p, GITypeInfo* param_info, - GITransfer transfer, void* c_array) { -- GArgument arg; - GITypeTag element_type; - - element_type = g_type_info_get_tag(param_info); -@@ -2282,7 +2267,7 @@ - /* Special case array(guint8) */ - if (element_type == GI_TYPE_TAG_UINT8) { - size_t len = strlen(static_cast(c_array)); -- JSObject* obj = gjs_byte_array_from_data(context, len, c_array); -+ JSObject* obj = gjs_byte_array_from_data_copy(context, len, c_array); - if (!obj) - return false; - value_p.setObject(*obj); -@@ -2295,6 +2280,7 @@ - - JS::RootedValueVector elems(context); - -+ GIArgument arg; - switch (element_type) { - /* Special cases handled above. */ - case GI_TYPE_TAG_UINT8: -@@ -2350,14 +2336,21 @@ - g_type_info_get_interface(param_info); - - if (!g_type_info_is_pointer(param_info) && -- is_gvalue(interface_info, -- g_base_info_get_type(interface_info))) { -+ is_gvalue(interface_info)) { - if (!fill_vector_from_zero_terminated_carray( - context, elems, param_info, &arg, c_array)) - return false; - break; - } - -+ if (!g_type_info_is_pointer(param_info)) { -+ gjs_throw(context, -+ "Flat C array of %s.%s not supported (see " -+ "https://gitlab.gnome.org/GNOME/gjs/-/issues/603)", -+ interface_info.ns(), interface_info.name()); -+ return false; -+ } -+ - [[fallthrough]]; - } - case GI_TYPE_TAG_GTYPE: -@@ -2383,7 +2376,7 @@ - return false; - } - -- JS::RootedObject obj(context, JS::NewArrayObject(context, elems)); -+ JSObject* obj = JS::NewArrayObject(context, elems); - if (!obj) - return false; - -@@ -2397,7 +2390,6 @@ - GITypeInfo* val_param_info, GITransfer transfer, - GHashTable* hash) { - GHashTableIter iter; -- GArgument keyarg, valarg; - - // a NULL hash table becomes a null JS value - if (hash==NULL) { -@@ -2417,13 +2409,14 @@ - g_hash_table_iter_init(&iter, hash); - void* key_pointer; - void* val_pointer; -+ GIArgument keyarg, valarg; - while (g_hash_table_iter_next(&iter, &key_pointer, &val_pointer)) { - g_type_info_argument_from_hash_pointer(key_param_info, key_pointer, - &keyarg); -- if (!gjs_value_from_g_argument(context, &keyjs, key_param_info, -- GJS_ARGUMENT_HASH_ELEMENT, -- transfer, &keyarg)) -- return false; -+ if (!gjs_value_from_gi_argument(context, &keyjs, key_param_info, -+ GJS_ARGUMENT_HASH_ELEMENT, transfer, -+ &keyarg)) -+ return false; - - keystr = JS::ToString(context, keyjs); - if (!keystr) -@@ -2435,9 +2428,9 @@ - - g_type_info_argument_from_hash_pointer(val_param_info, val_pointer, - &valarg); -- if (!gjs_value_from_g_argument(context, &valjs, val_param_info, -- GJS_ARGUMENT_HASH_ELEMENT, -- transfer, &valarg)) -+ if (!gjs_value_from_gi_argument(context, &valjs, val_param_info, -+ GJS_ARGUMENT_HASH_ELEMENT, transfer, -+ &valarg)) - return false; - - if (!JS_DefineProperty(context, obj, keyutf8.get(), valjs, -@@ -2448,21 +2441,17 @@ - return true; - } - --bool gjs_value_from_g_argument(JSContext* context, -- JS::MutableHandleValue value_p, -- GITypeInfo* type_info, -- GjsArgumentType argument_type, -- GITransfer transfer, GArgument* arg) { -- GITypeTag type_tag; -- -- type_tag = g_type_info_get_tag( (GITypeInfo*) type_info); -+bool gjs_value_from_gi_argument(JSContext* context, -+ JS::MutableHandleValue value_p, -+ GITypeInfo* type_info, -+ GjsArgumentType argument_type, -+ GITransfer transfer, GIArgument* arg) { -+ GITypeTag type_tag = g_type_info_get_tag(type_info); - - gjs_debug_marshal(GJS_DEBUG_GFUNCTION, -- "Converting GArgument %s to JS::Value", -+ "Converting GIArgument %s to JS::Value", - g_type_tag_to_string(type_tag)); - -- value_p.setNull(); -- - switch (type_tag) { - case GI_TYPE_TAG_VOID: - // If the argument is a pointer, convert to null to match our -@@ -2510,20 +2499,22 @@ - break; - - case GI_TYPE_TAG_FLOAT: -- value_p.setNumber(gjs_arg_get(arg)); -+ value_p.setNumber(JS::CanonicalizeNaN(gjs_arg_get(arg))); - break; - - case GI_TYPE_TAG_DOUBLE: -- value_p.setNumber(gjs_arg_get(arg)); -+ value_p.setNumber(JS::CanonicalizeNaN(gjs_arg_get(arg))); - break; - - case GI_TYPE_TAG_GTYPE: - { - GType gtype = gjs_arg_get(arg); -- if (gtype == 0) -- return true; /* value_p is set to JS null */ -+ if (gtype == 0) { -+ value_p.setNull(); -+ return true; -+ } - -- JS::RootedObject obj(context, gjs_gtype_create_gtype_wrapper(context, gtype)); -+ JSObject* obj = gjs_gtype_create_gtype_wrapper(context, gtype); - if (!obj) - return false; - -@@ -2553,10 +2544,10 @@ - case GI_TYPE_TAG_FILENAME: - case GI_TYPE_TAG_UTF8: { - const char* str = gjs_arg_get(arg); -- // For nullptr we'll return JS::NullValue(), which is already set -- // in *value_p -- if (!str) -+ if (!str) { -+ value_p.setNull(); - return true; -+ } - - if (type_tag == GI_TYPE_TAG_FILENAME) - return gjs_string_from_filename(context, str, -1, value_p); -@@ -2566,8 +2557,10 @@ - - case GI_TYPE_TAG_ERROR: { - GError* ptr = gjs_arg_get(arg); -- if (!ptr) -+ if (!ptr) { -+ value_p.setNull(); - return true; -+ } - - JSObject* obj = ErrorInstance::object_for_c_ptr(context, ptr); - if (!obj) -@@ -2579,14 +2572,11 @@ - - case GI_TYPE_TAG_INTERFACE: - { -- GIInfoType interface_type; -- GType gtype; -- - GjsAutoBaseInfo interface_info = - g_type_info_get_interface(type_info); - g_assert(interface_info); - -- interface_type = g_base_info_get_type(interface_info); -+ GIInfoType interface_type = interface_info.type(); - - if (interface_type == GI_INFO_TYPE_UNRESOLVED) { - gjs_throw(context, -@@ -2614,14 +2604,17 @@ - interface_info, - gjs_arg_get(arg)); - -- gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*)interface_info); -+ GType gtype = g_registered_type_info_get_g_type( -+ interface_info.as()); - - if (gtype != G_TYPE_NONE) { - /* check make sure 32 bit flag */ -- if (static_cast(value_int64) != value_int64) { /* Not a guint32 */ -+ if (static_cast(value_int64) != value_int64) { -+ // Not a 32-bit integer - gjs_throw(context, -- "0x%" G_GINT64_MODIFIER "x is not a valid value for flags %s", -- value_int64, g_type_name(gtype)); -+ "0x%" PRIx64 -+ " is not a valid value for flags %s", -+ value_int64, g_type_name(gtype)); - return false; - } - -@@ -2635,8 +2628,8 @@ - } - - if (interface_type == GI_INFO_TYPE_STRUCT && -- g_struct_info_is_foreign((GIStructInfo*)interface_info)) { -- return gjs_struct_foreign_convert_from_g_argument( -+ g_struct_info_is_foreign(interface_info.as())) { -+ return gjs_struct_foreign_convert_from_gi_argument( - context, value_p, interface_info, arg); - } - -@@ -2647,12 +2640,13 @@ - } - - if (interface_type == GI_INFO_TYPE_STRUCT && -- g_struct_info_is_gtype_struct((GIStructInfo*)interface_info)) { -+ g_struct_info_is_gtype_struct( -+ interface_info.as())) { - /* XXX: here we make the implicit assumption that GTypeClass is the same - as GTypeInterface. This is true for the GType field, which is what we - use, but not for the rest of the structure! - */ -- gtype = G_TYPE_FROM_CLASS(gjs_arg_get(arg)); -+ GType gtype = G_TYPE_FROM_CLASS(gjs_arg_get(arg)); - - if (g_type_is_a(gtype, G_TYPE_INTERFACE)) { - return gjs_lookup_interface_constructor(context, gtype, -@@ -2661,7 +2655,8 @@ - return gjs_lookup_object_constructor(context, gtype, value_p); - } - -- gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*)interface_info); -+ GType gtype = g_registered_type_info_get_g_type( -+ interface_info.as()); - if (G_TYPE_IS_INSTANTIATABLE(gtype) || - G_TYPE_IS_INTERFACE(gtype)) - gtype = G_TYPE_FROM_INSTANCE(gjs_arg_get(arg)); -@@ -2691,11 +2686,14 @@ - g_struct_info_find_method(interface_info, "name"); - GIArgument atom_name_ret; - -- g_function_info_invoke(atom_name_fun, -- arg, 1, -- nullptr, 0, -- &atom_name_ret, -- nullptr); -+ GjsAutoError error = nullptr; -+ if (!g_function_info_invoke(atom_name_fun, arg, 1, nullptr, -+ 0, &atom_name_ret, -+ error.out())) { -+ gjs_throw(context, "Failed to call gdk_atom_name(): %s", -+ error->message); -+ return false; -+ } - - GjsAutoChar name = gjs_arg_get(&atom_name_ret); - if (g_strcmp0("NONE", name) == 0) { -@@ -2738,7 +2736,7 @@ - - if (interface_type == GI_INFO_TYPE_UNION) { - JSObject* obj = UnionInstance::new_for_c_union( -- context, static_cast(interface_info), -+ context, interface_info.as(), - gjs_arg_get(arg)); - if (!obj) - return false; -@@ -2775,7 +2773,9 @@ - } - - if (gtype == G_TYPE_NONE) { -- gjs_throw(context, "Unexpected unregistered type packing GArgument into JS::Value"); -+ gjs_throw(context, -+ "Unexpected unregistered type packing GIArgument " -+ "into JS::Value"); - return false; - } - -@@ -2789,17 +2789,20 @@ - } - - gjs_throw(context, -- "Unhandled GType %s packing GArgument into JS::Value", -+ "Unhandled GType %s packing GIArgument into JS::Value", - g_type_name(gtype)); - return false; - } - - case GI_TYPE_TAG_ARRAY: - if (!gjs_arg_get(arg)) { -- /* OK, but no conversion to do */ -- } else if (g_type_info_get_array_type(type_info) == GI_ARRAY_TYPE_C) { -+ value_p.setNull(); -+ return true; -+ } -+ -+ if (g_type_info_get_array_type(type_info) == GI_ARRAY_TYPE_C) { - if (g_type_info_is_zero_terminated(type_info)) { -- GjsAutoBaseInfo param_info = -+ GjsAutoTypeInfo param_info = - g_type_info_get_param_type(type_info, 0); - g_assert(param_info != nullptr); - -@@ -2861,7 +2864,7 @@ - break; - - default: -- g_warning("Unhandled type %s converting GArgument to JavaScript", -+ g_warning("Unhandled type %s converting GIArgument to JavaScript", - g_type_tag_to_string(type_tag)); - return false; - } -@@ -2880,14 +2883,14 @@ - static gboolean - gjs_ghr_helper(gpointer key, gpointer val, gpointer user_data) { - GHR_closure *c = (GHR_closure *) user_data; -- GArgument key_arg, val_arg; -+ GIArgument key_arg, val_arg; - gjs_arg_set(&key_arg, key); - gjs_arg_set(&val_arg, val); - if (!gjs_g_arg_release_internal(c->context, c->transfer, c->key_param_info, - g_type_info_get_tag(c->key_param_info), - GJS_ARGUMENT_HASH_ELEMENT, c->flags, - &key_arg)) -- c->failed = true; -+ c->failed = true; - - GITypeTag val_type = g_type_info_get_tag(c->val_param_info); - -@@ -2955,19 +2958,16 @@ - - case GI_TYPE_TAG_INTERFACE: - { -- GIInfoType interface_type; -- GType gtype; -- - GjsAutoBaseInfo interface_info = - g_type_info_get_interface(type_info); - g_assert(interface_info); - -- interface_type = g_base_info_get_type(interface_info); -+ GIInfoType interface_type = interface_info.type(); - - if (interface_type == GI_INFO_TYPE_STRUCT && -- g_struct_info_is_foreign((GIStructInfo*)interface_info)) -- return gjs_struct_foreign_release_g_argument(context, -- transfer, interface_info, arg); -+ g_struct_info_is_foreign(interface_info.as())) -+ return gjs_struct_foreign_release_gi_argument( -+ context, transfer, interface_info, arg); - - if (interface_type == GI_INFO_TYPE_ENUM || interface_type == GI_INFO_TYPE_FLAGS) - return true; -@@ -2976,7 +2976,8 @@ - if (!gjs_arg_get(arg)) - return true; - -- gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*)interface_info); -+ GType gtype = g_registered_type_info_get_g_type( -+ interface_info.as()); - if (G_TYPE_IS_INSTANTIATABLE(gtype) || - G_TYPE_IS_INTERFACE(gtype)) - gtype = G_TYPE_FROM_INSTANCE(gjs_arg_get(arg)); -@@ -2984,11 +2985,10 @@ - gjs_debug_marshal(GJS_DEBUG_GFUNCTION, - "gtype of INTERFACE is %s", g_type_name(gtype)); - -- /* In gjs_value_from_g_argument we handle Struct/Union types without a -- * registered GType, but here we are specifically handling a GArgument that -- * *owns* its value, and that is non-sensical for such types, so we -- * don't have to worry about it. -- */ -+ // In gjs_value_from_gi_argument we handle Struct/Union types -+ // without a registered GType, but here we are specifically handling -+ // a GIArgument that *owns* its value, and that is nonsensical for -+ // such types, so we don't have to worry about it. - - if (g_type_is_a(gtype, G_TYPE_OBJECT)) { - if (!is_transfer_in_nothing(transfer, flags)) -@@ -3016,7 +3016,9 @@ - g_variant_unref); - } else if (gtype == G_TYPE_NONE) { - if (!is_transfer_in_nothing(transfer, flags)) { -- gjs_throw(context, "Don't know how to release GArgument: not an object or boxed type"); -+ gjs_throw(context, -+ "Don't know how to release GIArgument: not an " -+ "object or boxed type"); - return false; - } - } else if (G_TYPE_IS_INSTANTIATABLE(gtype)) { -@@ -3026,7 +3028,7 @@ - priv->call_unref_function(gjs_arg_steal(arg)); - } - } else { -- gjs_throw(context, "Unhandled GType %s releasing GArgument", -+ gjs_throw(context, "Unhandled GType %s releasing GIArgument", - g_type_name(gtype)); - return false; - } -@@ -3077,7 +3079,7 @@ - if (!g_type_info_is_pointer(param_info)) { - GjsAutoBaseInfo interface_info = - g_type_info_get_interface(param_info); -- GIInfoType info_type = g_base_info_get_type(interface_info); -+ GIInfoType info_type = interface_info.type(); - if (info_type == GI_INFO_TYPE_STRUCT || - info_type == GI_INFO_TYPE_UNION) { - g_clear_pointer(&gjs_arg_member(arg), g_free); -@@ -3097,11 +3099,13 @@ - element_transfer = GI_TRANSFER_NOTHING; - - if (g_type_info_is_zero_terminated(type_info)) { -- return gjs_g_argument_release_array_internal( -+ return gjs_gi_argument_release_array_internal< -+ ArrayReleaseType::ZERO_TERMINATED>( - context, element_transfer, - flags | GjsArgumentFlags::ARG_OUT, param_info, 0, arg); - } else { -- return gjs_g_argument_release_array_internal( -+ return gjs_gi_argument_release_array_internal< -+ ArrayReleaseType::EXPLICIT_LENGTH>( - context, element_transfer, - flags | GjsArgumentFlags::ARG_OUT, param_info, - g_type_info_get_array_fixed_size(type_info), arg); -@@ -3155,7 +3159,7 @@ - guint i; - - for (i = 0; i < array->len; i++) { -- GArgument arg_iter; -+ GIArgument arg_iter; - - gjs_arg_set(&arg_iter, - g_array_index(array, gpointer, i)); -@@ -3190,11 +3194,11 @@ - guint i; - - for (i = 0; i < array->len; i++) { -- GArgument arg_iter; -+ GIArgument arg_iter; - - gjs_arg_set(&arg_iter, g_ptr_array_index(array, i)); -- if (!gjs_g_argument_release(context, transfer, param_info, -- flags, &arg_iter)) -+ if (!gjs_gi_argument_release(context, transfer, param_info, -+ flags, &arg_iter)) - return false; - } - } -@@ -3236,7 +3240,7 @@ - break; - - default: -- g_warning("Unhandled type %s releasing GArgument", -+ g_warning("Unhandled type %s releasing GIArgument", - g_type_tag_to_string(type_tag)); - return false; - } -@@ -3244,30 +3248,26 @@ - return true; - } - --bool gjs_g_argument_release(JSContext* cx, GITransfer transfer, -- GITypeInfo* type_info, GjsArgumentFlags flags, -- GIArgument* arg) { -- GITypeTag type_tag; -- -+bool gjs_gi_argument_release(JSContext* cx, GITransfer transfer, -+ GITypeInfo* type_info, GjsArgumentFlags flags, -+ GIArgument* arg) { - if (transfer == GI_TRANSFER_NOTHING && - !is_transfer_in_nothing(transfer, flags)) - return true; - -- type_tag = g_type_info_get_tag( (GITypeInfo*) type_info); -+ GITypeTag type_tag = g_type_info_get_tag(type_info); - - gjs_debug_marshal(GJS_DEBUG_GFUNCTION, -- "Releasing GArgument %s out param or return value", -+ "Releasing GIArgument %s out param or return value", - g_type_tag_to_string(type_tag)); - - return gjs_g_arg_release_internal(cx, transfer, type_info, type_tag, - GJS_ARGUMENT_ARGUMENT, flags, arg); - } - --bool gjs_g_argument_release_in_arg(JSContext* cx, GITransfer transfer, -- GITypeInfo* type_info, -- GjsArgumentFlags flags, GIArgument* arg) { -- GITypeTag type_tag; -- -+bool gjs_gi_argument_release_in_arg(JSContext* cx, GITransfer transfer, -+ GITypeInfo* type_info, -+ GjsArgumentFlags flags, GIArgument* arg) { - /* GI_TRANSFER_EVERYTHING: we don't own the argument anymore. - * GI_TRANSFER_CONTAINER: - * - non-containers: treated as GI_TRANSFER_EVERYTHING -@@ -3277,10 +3277,9 @@ - if (transfer != GI_TRANSFER_NOTHING) - return true; - -- type_tag = g_type_info_get_tag( (GITypeInfo*) type_info); -+ GITypeTag type_tag = g_type_info_get_tag(type_info); - -- gjs_debug_marshal(GJS_DEBUG_GFUNCTION, -- "Releasing GArgument %s in param", -+ gjs_debug_marshal(GJS_DEBUG_GFUNCTION, "Releasing GIArgument %s in param", - g_type_tag_to_string(type_tag)); - - if (type_needs_release (type_info, type_tag)) -@@ -3290,36 +3289,72 @@ - return true; - } - --bool gjs_g_argument_release_in_array(JSContext* context, GITransfer transfer, -- GITypeInfo* type_info, unsigned length, -- GIArgument* arg) { -+bool gjs_gi_argument_release_in_array(JSContext* context, GITransfer transfer, -+ GITypeInfo* type_info, unsigned length, -+ GIArgument* arg) { - if (transfer != GI_TRANSFER_NOTHING) - return true; - - gjs_debug_marshal(GJS_DEBUG_GFUNCTION, -- "Releasing GArgument array in param"); -+ "Releasing GIArgument array in param"); - - GjsAutoTypeInfo param_type = g_type_info_get_param_type(type_info, 0); -- return gjs_g_argument_release_array_internal( -- context, GI_TRANSFER_EVERYTHING, GjsArgumentFlags::ARG_IN, param_type, -- length, arg); -+ return gjs_gi_argument_release_array_internal< -+ ArrayReleaseType::EXPLICIT_LENGTH>(context, GI_TRANSFER_EVERYTHING, -+ GjsArgumentFlags::ARG_IN, param_type, -+ length, arg); - } - --bool gjs_g_argument_release_out_array(JSContext* context, GITransfer transfer, -- GITypeInfo* type_info, unsigned length, -- GIArgument* arg) { -+bool gjs_gi_argument_release_in_array(JSContext* context, GITransfer transfer, -+ GITypeInfo* type_info, GIArgument* arg) { -+ if (transfer != GI_TRANSFER_NOTHING) -+ return true; -+ -+ gjs_debug_marshal(GJS_DEBUG_GFUNCTION, -+ "Releasing GIArgument array in param"); -+ -+ GjsAutoTypeInfo param_type = g_type_info_get_param_type(type_info, 0); -+ return gjs_gi_argument_release_array_internal< -+ ArrayReleaseType::ZERO_TERMINATED>(context, GI_TRANSFER_EVERYTHING, -+ GjsArgumentFlags::ARG_IN, param_type, -+ 0, arg); -+} -+ -+bool gjs_gi_argument_release_out_array(JSContext* context, GITransfer transfer, -+ GITypeInfo* type_info, unsigned length, -+ GIArgument* arg) { -+ if (transfer == GI_TRANSFER_NOTHING) -+ return true; -+ -+ gjs_debug_marshal(GJS_DEBUG_GFUNCTION, -+ "Releasing GIArgument array out param"); -+ -+ GITransfer element_transfer = transfer == GI_TRANSFER_CONTAINER -+ ? GI_TRANSFER_NOTHING -+ : GI_TRANSFER_EVERYTHING; -+ -+ GjsAutoTypeInfo param_type = g_type_info_get_param_type(type_info, 0); -+ return gjs_gi_argument_release_array_internal< -+ ArrayReleaseType::EXPLICIT_LENGTH>(context, element_transfer, -+ GjsArgumentFlags::ARG_OUT, -+ param_type, length, arg); -+} -+ -+bool gjs_gi_argument_release_out_array(JSContext* context, GITransfer transfer, -+ GITypeInfo* type_info, GIArgument* arg) { - if (transfer == GI_TRANSFER_NOTHING) - return true; - - gjs_debug_marshal(GJS_DEBUG_GFUNCTION, -- "Releasing GArgument array out param"); -+ "Releasing GIArgument array out param"); - - GITransfer element_transfer = transfer == GI_TRANSFER_CONTAINER - ? GI_TRANSFER_NOTHING - : GI_TRANSFER_EVERYTHING; - - GjsAutoTypeInfo param_type = g_type_info_get_param_type(type_info, 0); -- return gjs_g_argument_release_array_internal(context, element_transfer, -- GjsArgumentFlags::ARG_OUT, -- param_type, length, arg); -+ return gjs_gi_argument_release_array_internal< -+ ArrayReleaseType::ZERO_TERMINATED>(context, element_transfer, -+ GjsArgumentFlags::ARG_OUT, -+ param_type, 0, arg); - } -diff -ruN cjs-6.2.0-orig/gi/arg.h cjs-6.2.0/gi/arg.h ---- cjs-6.2.0-orig/gi/arg.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/arg.h 2024-10-14 18:41:39.000000000 +0200 -@@ -65,34 +65,30 @@ - void gjs_gi_argument_init_default(GITypeInfo* type_info, GIArgument* arg); - - GJS_JSAPI_RETURN_CONVENTION --bool gjs_value_to_g_argument(JSContext* cx, JS::HandleValue value, -- GITypeInfo* type_info, const char* arg_name, -- GjsArgumentType argument_type, GITransfer transfer, -- GjsArgumentFlags flags, GIArgument* arg); -+bool gjs_value_to_gi_argument(JSContext*, JS::HandleValue, GITypeInfo*, -+ const char* arg_name, GjsArgumentType, GITransfer, -+ GjsArgumentFlags, GIArgument*); - - GJS_JSAPI_RETURN_CONVENTION --bool inline gjs_value_to_g_argument(JSContext* cx, JS::HandleValue value, -- GITypeInfo* type_info, -- GjsArgumentType argument_type, -- GITransfer transfer, GIArgument* arg) { -- return gjs_value_to_g_argument(cx, value, type_info, nullptr /* arg_name */, -- argument_type, transfer, -- GjsArgumentFlags::NONE, arg); -+bool inline gjs_value_to_gi_argument(JSContext* cx, JS::HandleValue value, -+ GITypeInfo* type_info, -+ GjsArgumentType argument_type, -+ GITransfer transfer, GIArgument* arg) { -+ return gjs_value_to_gi_argument(cx, value, type_info, -+ nullptr /* arg_name */, argument_type, -+ transfer, GjsArgumentFlags::NONE, arg); - } - - GJS_JSAPI_RETURN_CONVENTION --bool gjs_value_from_g_argument(JSContext* context, -- JS::MutableHandleValue value_p, -- GITypeInfo* type_info, -- GjsArgumentType argument_type, -- GITransfer transfer, GIArgument* arg); -+bool gjs_value_from_gi_argument(JSContext*, JS::MutableHandleValue, GITypeInfo*, -+ GjsArgumentType, GITransfer, GIArgument*); - - GJS_JSAPI_RETURN_CONVENTION --inline bool gjs_value_from_g_argument(JSContext* cx, -- JS::MutableHandleValue value_p, -- GITypeInfo* type_info, GIArgument* arg, -- bool copy_structs) { -- return gjs_value_from_g_argument( -+inline bool gjs_value_from_gi_argument(JSContext* cx, -+ JS::MutableHandleValue value_p, -+ GITypeInfo* type_info, GIArgument* arg, -+ bool copy_structs) { -+ return gjs_value_from_gi_argument( - cx, value_p, type_info, GJS_ARGUMENT_ARGUMENT, - copy_structs ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING, arg); - } -@@ -113,31 +109,35 @@ - } - - GJS_JSAPI_RETURN_CONVENTION --bool gjs_g_argument_release(JSContext*, GITransfer, GITypeInfo*, -- GjsArgumentFlags, GIArgument*); -+bool gjs_gi_argument_release(JSContext*, GITransfer, GITypeInfo*, -+ GjsArgumentFlags, GIArgument*); - GJS_JSAPI_RETURN_CONVENTION --inline bool gjs_g_argument_release(JSContext* cx, GITransfer transfer, -- GITypeInfo* type_info, GIArgument* arg) { -- return gjs_g_argument_release(cx, transfer, type_info, -- GjsArgumentFlags::NONE, arg); -+inline bool gjs_gi_argument_release(JSContext* cx, GITransfer transfer, -+ GITypeInfo* type_info, GIArgument* arg) { -+ return gjs_gi_argument_release(cx, transfer, type_info, -+ GjsArgumentFlags::NONE, arg); - } - GJS_JSAPI_RETURN_CONVENTION --bool gjs_g_argument_release_out_array(JSContext* cx, GITransfer transfer, -- GITypeInfo* type_info, unsigned length, -- GIArgument* arg); --GJS_JSAPI_RETURN_CONVENTION --bool gjs_g_argument_release_in_array(JSContext* cx, GITransfer transfer, -- GITypeInfo* type_info, unsigned length, -- GIArgument* arg); -+bool gjs_gi_argument_release_out_array(JSContext*, GITransfer, GITypeInfo*, -+ unsigned length, GIArgument*); - GJS_JSAPI_RETURN_CONVENTION --bool gjs_g_argument_release_in_arg(JSContext*, GITransfer, GITypeInfo*, -- GjsArgumentFlags, GIArgument*); -+bool gjs_gi_argument_release_out_array(JSContext*, GITransfer, GITypeInfo*, -+ GIArgument*); - GJS_JSAPI_RETURN_CONVENTION --inline bool gjs_g_argument_release_in_arg(JSContext* cx, GITransfer transfer, -- GITypeInfo* type_info, -- GIArgument* arg) { -- return gjs_g_argument_release_in_arg(cx, transfer, type_info, -- GjsArgumentFlags::ARG_IN, arg); -+bool gjs_gi_argument_release_in_array(JSContext*, GITransfer, GITypeInfo*, -+ unsigned length, GIArgument*); -+GJS_JSAPI_RETURN_CONVENTION -+bool gjs_gi_argument_release_in_array(JSContext*, GITransfer, GITypeInfo*, -+ GIArgument*); -+GJS_JSAPI_RETURN_CONVENTION -+bool gjs_gi_argument_release_in_arg(JSContext*, GITransfer, GITypeInfo*, -+ GjsArgumentFlags, GIArgument*); -+GJS_JSAPI_RETURN_CONVENTION -+inline bool gjs_gi_argument_release_in_arg(JSContext* cx, GITransfer transfer, -+ GITypeInfo* type_info, -+ GIArgument* arg) { -+ return gjs_gi_argument_release_in_arg(cx, transfer, type_info, -+ GjsArgumentFlags::ARG_IN, arg); - } - - GJS_JSAPI_RETURN_CONVENTION -diff -ruN cjs-6.2.0-orig/gi/boxed.cpp cjs-6.2.0/gi/boxed.cpp ---- cjs-6.2.0-orig/gi/boxed.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/boxed.cpp 2024-10-14 18:41:39.000000000 +0200 -@@ -214,7 +214,7 @@ - } - - /* Initialize a newly created Boxed from an object that is a "hash" of -- * properties to set as fieds of the object. We don't require that every field -+ * properties to set as fields of the object. We don't require that every field - * of the object be set. - */ - bool BoxedInstance::init_from_props(JSContext* context, JS::Value props_value) { -@@ -480,10 +480,10 @@ - */ - bool BoxedInstance::get_nested_interface_object( - JSContext* context, JSObject* parent_obj, GIFieldInfo* field_info, -- GIBaseInfo* interface_info, JS::MutableHandleValue value) const { -+ GIStructInfo* struct_info, JS::MutableHandleValue value) const { - int offset; - -- if (!struct_is_simple(reinterpret_cast(interface_info))) { -+ if (!struct_is_simple(struct_info)) { - gjs_throw(context, "Reading field %s.%s is not supported", name(), - g_base_info_get_name(field_info)); - -@@ -492,8 +492,8 @@ - - offset = g_field_info_get_offset (field_info); - -- JS::RootedObject obj(context, gjs_new_object_with_generic_prototype( -- context, interface_info)); -+ JS::RootedObject obj{ -+ context, gjs_new_object_with_generic_prototype(context, struct_info)}; - if (!obj) - return false; - -@@ -567,26 +567,26 @@ - get_field_info(cx, length_field_ix); - if (!length_field_info) { - gjs_throw(cx, "Reading field %s.%s is not supported", name(), -- g_base_info_get_name(length_field_info)); -+ g_base_info_get_name(field_info)); - return false; - } - - GIArgument length_arg; - if (!g_field_info_get_field(length_field_info, m_ptr, &length_arg)) { - gjs_throw(cx, "Reading field %s.%s is not supported", name(), -- g_base_info_get_name(length_field_info)); -+ length_field_info.name()); - return false; - } - - GjsAutoTypeInfo length_type_info = - g_field_info_get_type(length_field_info); -- size_t length = gjs_g_argument_get_array_length( -+ size_t length = gjs_gi_argument_get_array_length( - g_type_info_get_tag(length_type_info), &length_arg); - return gjs_value_from_explicit_array(cx, rval, type_info, &arg, length); - } - -- return gjs_value_from_g_argument(cx, rval, type_info, GJS_ARGUMENT_FIELD, -- GI_TRANSFER_EVERYTHING, &arg); -+ return gjs_value_from_gi_argument(cx, rval, type_info, GJS_ARGUMENT_FIELD, -+ GI_TRANSFER_EVERYTHING, &arg); - } - - /* -@@ -603,19 +603,19 @@ - */ - bool BoxedInstance::set_nested_interface_object(JSContext* context, - GIFieldInfo* field_info, -- GIBaseInfo* interface_info, -+ GIStructInfo* struct_info, - JS::HandleValue value) { - int offset; - -- if (!struct_is_simple(reinterpret_cast(interface_info))) { -+ if (!struct_is_simple(struct_info)) { - gjs_throw(context, "Writing field %s.%s is not supported", name(), - g_base_info_get_name(field_info)); - - return false; - } - -- JS::RootedObject proto( -- context, gjs_lookup_generic_prototype(context, interface_info)); -+ JS::RootedObject proto{context, -+ gjs_lookup_generic_prototype(context, struct_info)}; - - if (!proto) - return false; -@@ -647,7 +647,6 @@ - bool BoxedInstance::field_setter_impl(JSContext* context, - GIFieldInfo* field_info, - JS::HandleValue value) { -- GArgument arg; - GjsAutoTypeInfo type_info = g_field_info_get_type(field_info); - - if (!g_type_info_is_pointer (type_info) && -@@ -661,10 +660,11 @@ - } - } - -- if (!gjs_value_to_g_argument(context, value, type_info, -- g_base_info_get_name(field_info), -- GJS_ARGUMENT_FIELD, GI_TRANSFER_NOTHING, -- GjsArgumentFlags::MAY_BE_NULL, &arg)) -+ GIArgument arg; -+ if (!gjs_value_to_gi_argument(context, value, type_info, -+ g_base_info_get_name(field_info), -+ GJS_ARGUMENT_FIELD, GI_TRANSFER_NOTHING, -+ GjsArgumentFlags::MAY_BE_NULL, &arg)) - return false; - - bool success = true; -@@ -675,7 +675,7 @@ - } - - JS::AutoSaveExceptionState saved_exc(context); -- if (!gjs_g_argument_release(context, GI_TRANSFER_NOTHING, type_info, &arg)) -+ if (!gjs_gi_argument_release(context, GI_TRANSFER_NOTHING, type_info, &arg)) - gjs_log_exception(context); - saved_exc.restore(); - -@@ -718,28 +718,41 @@ - int n_fields = g_struct_info_get_n_fields(info()); - int i; - -- /* We define all fields as read/write so that the user gets an -- * error message. If we omitted fields or defined them read-only -- * we'd: -- * -- * - Store a new property for a non-accessible field -- * - Silently do nothing when writing a read-only field -- * -- * Which is pretty confusing if the only reason a field isn't -- * writable is language binding or memory-management restrictions. -- * -- * We just go ahead and define the fields immediately for the -- * class; doing it lazily in boxed_resolve() would be possible -- * as well if doing it ahead of time caused to much start-up -- * memory overhead. -- */ -+ // We define all fields as read/write so that the user gets an error -+ // message. If we omitted fields or defined them read-only we'd: -+ // -+ // - Store a new property for a non-accessible field -+ // - Silently do nothing when writing a read-only field -+ // -+ // Which is pretty confusing if the only reason a field isn't writable is -+ // language binding or memory-management restrictions. -+ // -+ // We just go ahead and define the fields immediately for the class; doing -+ // it lazily in boxed_resolve() would be possible as well if doing it ahead -+ // of time caused too much start-up memory overhead. -+ // -+ // At this point methods have already been defined on the prototype, so we -+ // may get name conflicts which we need to check for. - for (i = 0; i < n_fields; i++) { - GjsAutoFieldInfo field = g_struct_info_get_field(info(), i); - JS::RootedValue private_id(cx, JS::PrivateUint32Value(i)); -- if (!gjs_define_property_dynamic(cx, proto, field.name(), "boxed_field", -- &BoxedBase::field_getter, -- &BoxedBase::field_setter, private_id, -- GJS_MODULE_PROP_FLAGS)) -+ JS::RootedId id{cx, gjs_intern_string_to_id(cx, field.name())}; -+ -+ bool already_defined; -+ if (!JS_HasOwnPropertyById(cx, proto, id, &already_defined)) -+ return false; -+ if (already_defined) { -+ gjs_debug(GJS_DEBUG_GBOXED, -+ "Field %s.%s.%s overlaps with method of the same name; " -+ "skipping", -+ ns(), name(), field.name()); -+ continue; -+ } -+ -+ if (!gjs_define_property_dynamic( -+ cx, proto, field.name(), id, "boxed_field", -+ &BoxedBase::field_getter, &BoxedBase::field_setter, private_id, -+ GJS_MODULE_PROP_FLAGS)) - return false; - } - -@@ -768,7 +781,7 @@ - &BoxedBase::trace - }; - --/* We allocate 1 reserved slot; this is typically unused, but if the -+/* We allocate 1 extra reserved slot; this is typically unused, but if the - * boxed is for a nested structure inside a parent structure, the - * reserved slot is used to hold onto the parent Javascript object and - * make sure it doesn't get freed. -@@ -787,7 +800,7 @@ - if (g_type_info_is_pointer(type_info)) { - if (g_type_info_get_tag(type_info) == GI_TYPE_TAG_ARRAY && - g_type_info_get_array_type(type_info) == GI_ARRAY_TYPE_C) { -- GjsAutoBaseInfo param_info = -+ GjsAutoTypeInfo param_info = - g_type_info_get_param_type(type_info, 0); - return type_can_be_allocated_directly(param_info); - } -@@ -798,7 +811,7 @@ - case GI_TYPE_TAG_INTERFACE: - { - GjsAutoBaseInfo interface = g_type_info_get_interface(type_info); -- switch (g_base_info_get_type(interface)) { -+ switch (interface.type()) { - case GI_INFO_TYPE_BOXED: - case GI_INFO_TYPE_STRUCT: - return struct_is_simple(interface.as()); -@@ -867,7 +880,7 @@ - if (g_type_info_is_pointer(type_info)) { - if (g_type_info_get_tag(type_info) == GI_TYPE_TAG_ARRAY && - g_type_info_get_array_type(type_info) == GI_ARRAY_TYPE_C) { -- GjsAutoBaseInfo param_info = -+ GjsAutoTypeInfo param_info = - g_type_info_get_param_type(type_info, 0); - return direct_allocation_has_pointers(param_info); - } -@@ -900,8 +913,8 @@ - return false; - - for (i = 0; i < n_fields && is_simple; i++) { -- GjsAutoBaseInfo field_info = g_struct_info_get_field(info, i); -- GjsAutoBaseInfo type_info = g_field_info_get_type(field_info); -+ GjsAutoFieldInfo field_info = g_struct_info_get_field(info, i); -+ GjsAutoTypeInfo type_info = g_field_info_get_type(field_info); - - is_simple = type_can_be_allocated_directly(type_info); - } -@@ -917,8 +930,8 @@ - g_assert(n_fields > 0); - - for (int i = 0; i < n_fields; i++) { -- GjsAutoBaseInfo field_info = g_struct_info_get_field(info, i); -- GjsAutoBaseInfo type_info = g_field_info_get_type(field_info); -+ GjsAutoFieldInfo field_info = g_struct_info_get_field(info, i); -+ GjsAutoTypeInfo type_info = g_field_info_get_type(field_info); - if (direct_allocation_has_pointers(type_info)) - return true; - } -diff -ruN cjs-6.2.0-orig/gi/boxed.h cjs-6.2.0/gi/boxed.h ---- cjs-6.2.0-orig/gi/boxed.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/boxed.h 2024-10-14 18:41:39.000000000 +0200 -@@ -198,11 +198,11 @@ - GJS_JSAPI_RETURN_CONVENTION - bool get_nested_interface_object(JSContext* cx, JSObject* parent_obj, - GIFieldInfo* field_info, -- GIBaseInfo* interface_info, -+ GIStructInfo* interface_info, - JS::MutableHandleValue value) const; - GJS_JSAPI_RETURN_CONVENTION - bool set_nested_interface_object(JSContext* cx, GIFieldInfo* field_info, -- GIBaseInfo* interface_info, -+ GIStructInfo* interface_info, - JS::HandleValue value); - - GJS_JSAPI_RETURN_CONVENTION -diff -ruN cjs-6.2.0-orig/gi/closure.cpp cjs-6.2.0/gi/closure.cpp ---- cjs-6.2.0-orig/gi/closure.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/closure.cpp 2024-10-14 18:41:39.000000000 +0200 -@@ -171,7 +171,7 @@ - return false; - } - -- JSAutoRealm ar(m_cx, m_callable); -+ JSAutoRealm ar{m_cx, m_callable.get()}; - - if (gjs_log_exception(m_cx)) { - gjs_debug_closure( -@@ -180,7 +180,7 @@ - this); - } - -- JS::RootedValue v_callable(m_cx, JS::ObjectValue(*m_callable)); -+ JS::RootedValue v_callable{m_cx, JS::ObjectValue(*m_callable.get())}; - bool ok = JS::Call(m_cx, this_obj, v_callable, args, retval); - GjsContextPrivate* gjs = GjsContextPrivate::from_cx(m_cx); - -diff -ruN cjs-6.2.0-orig/gi/closure.h cjs-6.2.0/gi/closure.h ---- cjs-6.2.0-orig/gi/closure.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/closure.h 2024-10-14 18:41:39.000000000 +0200 -@@ -9,9 +9,10 @@ - - #include - --#include - #include - -+#include -+ - #include - - #include "gi/utils-inl.h" -@@ -68,8 +69,9 @@ - - [[nodiscard]] static Closure* create_marshaled(JSContext* cx, - JSObject* callable, -- const char* description) { -- auto* self = new Closure(cx, callable, true /* root */, description); -+ const char* description, -+ bool root = true) { -+ auto* self = new Closure(cx, callable, root, description); - self->add_finalize_notifier(); - g_closure_set_marshal(self, marshal_cb); - return self; -@@ -86,7 +88,8 @@ - return self; - } - -- constexpr JSObject* callable() const { return m_callable; } -+ // COMPAT: constexpr in C++23 -+ JSObject* callable() const { return m_callable.get(); } - [[nodiscard]] constexpr JSContext* context() const { return m_cx; } - [[nodiscard]] constexpr bool is_valid() const { return !!m_cx; } - GJS_JSAPI_RETURN_CONVENTION bool invoke(JS::HandleObject, -@@ -127,7 +130,7 @@ - // The context could be attached to the default context of the runtime - // using if we wanted the closure to survive the context that created it. - JSContext* m_cx; -- GjsMaybeOwned m_callable; -+ GjsMaybeOwned m_callable; - }; - - } // namespace Gjs -diff -ruN cjs-6.2.0-orig/gi/cwrapper.h cjs-6.2.0/gi/cwrapper.h ---- cjs-6.2.0-orig/gi/cwrapper.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/cwrapper.h 2024-10-14 18:41:39.000000000 +0200 -@@ -16,6 +16,7 @@ - #include - #include - #include // for JSEXN_TYPEERR -+#include // for MutableHandleIdVector - #include // for CurrentGlobalOrNull - #include - #include // for GetClass -diff -ruN cjs-6.2.0-orig/gi/enumeration.cpp cjs-6.2.0/gi/enumeration.cpp ---- cjs-6.2.0-orig/gi/enumeration.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/enumeration.cpp 2024-10-14 18:41:39.000000000 +0200 -@@ -4,6 +4,8 @@ - - #include - -+#include -+ - #include - #include - #include -@@ -46,7 +48,7 @@ - } - - gjs_debug(GJS_DEBUG_GENUM, -- "Defining enum value %s (fixed from %s) %" G_GINT64_MODIFIER "d", -+ "Defining enum value %s (fixed from %s) %" PRId64, - fixed_name.get(), value_name, value_val); - - if (!JS_DefineProperty(context, in_object, -diff -ruN cjs-6.2.0-orig/gi/foreign.cpp cjs-6.2.0/gi/foreign.cpp ---- cjs-6.2.0-orig/gi/foreign.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/foreign.cpp 2024-10-14 18:41:39.000000000 +0200 -@@ -4,112 +4,92 @@ - - #include - --#include // for strcmp -+#include // for size_t -+ - #include -+#include -+#include // for pair - - #include - #include - -+#include - #include - - #include "gi/foreign.h" - #include "cjs/context-private.h" - #include "cjs/jsapi-util.h" -+#include "cjs/macros.h" - --static struct { -- const char* gi_namespace; -- bool loaded; --} foreign_modules[] = { -- // clang-format off -- {"cairo", false}, -- {nullptr} -- // clang-format on --}; -- --static GHashTable* foreign_structs_table = NULL; -- --[[nodiscard]] static GHashTable* get_foreign_structs() { -- // FIXME: look into hasing on GITypeInfo instead. -- if (!foreign_structs_table) { -- foreign_structs_table = g_hash_table_new_full(g_str_hash, g_str_equal, -- (GDestroyNotify)g_free, -- NULL); -+enum LoadedStatus { NotLoaded, Loaded }; -+static std::unordered_map foreign_modules{ -+ {"cairo", NotLoaded}}; -+ -+using StructID = std::pair; -+struct StructIDHash { -+ [[nodiscard]] size_t operator()(StructID val) const { -+ std::hash hasher; -+ return hasher(val.first) ^ hasher(val.second); - } -- -- return foreign_structs_table; --} -+}; -+static std::unordered_map -+ foreign_structs_table; - - [[nodiscard]] static bool gjs_foreign_load_foreign_module( -- JSContext* context, const char* gi_namespace) { -- int i; -+ JSContext* cx, const char* gi_namespace) { -+ auto entry = foreign_modules.find(gi_namespace); -+ if (entry == foreign_modules.end()) -+ return false; - -- for (i = 0; foreign_modules[i].gi_namespace; ++i) { -- if (strcmp(gi_namespace, foreign_modules[i].gi_namespace) != 0) -- continue; -- -- if (foreign_modules[i].loaded) -- return true; -- -- // FIXME: Find a way to check if a module is imported -- // and only execute this statement if isn't -- std::string script = "imports." + std::string(gi_namespace) + ';'; -- JS::RootedValue retval(context); -- GjsContextPrivate* gjs = GjsContextPrivate::from_cx(context); -- if (!gjs->eval_with_scope(nullptr, script.c_str(), script.length(), -- "", &retval)) { -- g_critical("ERROR importing foreign module %s\n", gi_namespace); -- return false; -- } -- foreign_modules[i].loaded = true; -+ if (entry->second == Loaded) - return true; -- } - -- return false; -+ // FIXME: Find a way to check if a module is imported and only execute this -+ // statement if it isn't -+ std::string script = "imports." + entry->first + ';'; -+ JS::RootedValue retval{cx}; -+ GjsContextPrivate* gjs = GjsContextPrivate::from_cx(cx); -+ if (!gjs->eval_with_scope(nullptr, script.c_str(), script.length(), -+ "", &retval)) { -+ g_critical("ERROR importing foreign module %s\n", gi_namespace); -+ return false; -+ } -+ entry->second = Loaded; -+ return true; - } - - void gjs_struct_foreign_register(const char* gi_namespace, - const char* type_name, GjsForeignInfo* info) { -- char *canonical_name; -+ foreign_structs_table.insert({{gi_namespace, type_name}, info}); -+} - -- g_return_if_fail(info); -- g_return_if_fail(info->to_func); -- g_return_if_fail(info->from_func); -- -- canonical_name = g_strdup_printf("%s.%s", gi_namespace, type_name); -- g_hash_table_insert(get_foreign_structs(), canonical_name, info); --} -- --[[nodiscard]] static GjsForeignInfo* gjs_struct_foreign_lookup( -- JSContext* context, GIBaseInfo* interface_info) { -- GHashTable* hash_table; -- -- auto key = std::string(g_base_info_get_namespace(interface_info)) + '.' + -- g_base_info_get_name(interface_info); -- hash_table = get_foreign_structs(); -- auto* retval = static_cast( -- g_hash_table_lookup(hash_table, key.c_str())); -- if (!retval) { -- if (gjs_foreign_load_foreign_module(context, g_base_info_get_namespace(interface_info))) { -- retval = static_cast( -- g_hash_table_lookup(hash_table, key.c_str())); -- } -+GJS_JSAPI_RETURN_CONVENTION -+static GjsForeignInfo* gjs_struct_foreign_lookup(JSContext* cx, -+ GIStructInfo* info) { -+ const char* ns = g_base_info_get_namespace(info); -+ StructID key{ns, g_base_info_get_name(info)}; -+ auto entry = foreign_structs_table.find(key); -+ if (entry == foreign_structs_table.end()) { -+ if (gjs_foreign_load_foreign_module(cx, ns)) -+ entry = foreign_structs_table.find(key); - } - -- if (!retval) { -- gjs_throw(context, "Unable to find module implementing foreign type %s", -- key.c_str()); -+ if (entry == foreign_structs_table.end()) { -+ gjs_throw(cx, "Unable to find module implementing foreign type %s.%s", -+ key.first.c_str(), key.second.c_str()); -+ return nullptr; - } - -- return retval; -+ return entry->second; - } - --bool gjs_struct_foreign_convert_to_g_argument( -- JSContext* context, JS::Value value, GIBaseInfo* interface_info, -+bool gjs_struct_foreign_convert_to_gi_argument( -+ JSContext* context, JS::Value value, GIStructInfo* info, - const char* arg_name, GjsArgumentType argument_type, GITransfer transfer, -- GjsArgumentFlags flags, GArgument* arg) { -+ GjsArgumentFlags flags, GIArgument* arg) { - GjsForeignInfo *foreign; - -- foreign = gjs_struct_foreign_lookup(context, interface_info); -+ foreign = gjs_struct_foreign_lookup(context, info); - if (!foreign) - return false; - -@@ -120,15 +100,11 @@ - return true; - } - --bool --gjs_struct_foreign_convert_from_g_argument(JSContext *context, -- JS::MutableHandleValue value_p, -- GIBaseInfo *interface_info, -- GIArgument *arg) --{ -- GjsForeignInfo *foreign; -- -- foreign = gjs_struct_foreign_lookup(context, interface_info); -+bool gjs_struct_foreign_convert_from_gi_argument(JSContext* context, -+ JS::MutableHandleValue value_p, -+ GIStructInfo* info, -+ GIArgument* arg) { -+ GjsForeignInfo* foreign = gjs_struct_foreign_lookup(context, info); - if (!foreign) - return false; - -@@ -138,15 +114,11 @@ - return true; - } - --bool --gjs_struct_foreign_release_g_argument(JSContext *context, -- GITransfer transfer, -- GIBaseInfo *interface_info, -- GArgument *arg) --{ -- GjsForeignInfo *foreign; -- -- foreign = gjs_struct_foreign_lookup(context, interface_info); -+bool gjs_struct_foreign_release_gi_argument(JSContext* context, -+ GITransfer transfer, -+ GIStructInfo* info, -+ GIArgument* arg) { -+ GjsForeignInfo* foreign = gjs_struct_foreign_lookup(context, info); - if (!foreign) - return false; - -@@ -158,4 +130,3 @@ - - return true; - } -- -diff -ruN cjs-6.2.0-orig/gi/foreign.h cjs-6.2.0/gi/foreign.h ---- cjs-6.2.0-orig/gi/foreign.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/foreign.h 2024-10-14 18:41:39.000000000 +0200 -@@ -9,50 +9,46 @@ - - #include - --#include - #include - #include - - #include "gi/arg.h" - #include "cjs/macros.h" - --typedef bool (*GjsArgOverrideToGArgumentFunc)( -- JSContext* context, JS::Value value, const char* arg_name, -- GjsArgumentType argument_type, GITransfer transfer, GjsArgumentFlags flags, -- GArgument* arg); -- --typedef bool (*GjsArgOverrideFromGArgumentFunc) (JSContext *context, -- JS::MutableHandleValue value_p, -- GIArgument *arg); -- --typedef bool (*GjsArgOverrideReleaseGArgumentFunc) (JSContext *context, -- GITransfer transfer, -- GArgument *arg); -+typedef bool (*GjsArgOverrideToGIArgumentFunc)(JSContext*, JS::Value, -+ const char* arg_name, -+ GjsArgumentType, GITransfer, -+ GjsArgumentFlags, GIArgument*); -+ -+typedef bool (*GjsArgOverrideFromGIArgumentFunc)(JSContext*, -+ JS::MutableHandleValue, -+ GIArgument*); -+ -+typedef bool (*GjsArgOverrideReleaseGIArgumentFunc)(JSContext*, GITransfer, -+ GIArgument*); - - typedef struct { -- GjsArgOverrideToGArgumentFunc to_func; -- GjsArgOverrideFromGArgumentFunc from_func; -- GjsArgOverrideReleaseGArgumentFunc release_func; -+ GjsArgOverrideToGIArgumentFunc to_func; -+ GjsArgOverrideFromGIArgumentFunc from_func; -+ GjsArgOverrideReleaseGIArgumentFunc release_func; - } GjsForeignInfo; - - void gjs_struct_foreign_register(const char* gi_namespace, - const char* type_name, GjsForeignInfo* info); - - GJS_JSAPI_RETURN_CONVENTION --bool gjs_struct_foreign_convert_to_g_argument( -- JSContext* context, JS::Value value, GIBaseInfo* interface_info, -- const char* arg_name, GjsArgumentType argument_type, GITransfer transfer, -- GjsArgumentFlags flags, GArgument* arg); -+bool gjs_struct_foreign_convert_to_gi_argument(JSContext*, JS::Value, -+ GIStructInfo*, -+ const char* arg_name, -+ GjsArgumentType, GITransfer, -+ GjsArgumentFlags, GIArgument*); - GJS_JSAPI_RETURN_CONVENTION --bool gjs_struct_foreign_convert_from_g_argument(JSContext *context, -- JS::MutableHandleValue value_p, -- GIBaseInfo *interface_info, -- GIArgument *arg); -+bool gjs_struct_foreign_convert_from_gi_argument(JSContext*, -+ JS::MutableHandleValue, -+ GIStructInfo*, GIArgument*); - - GJS_JSAPI_RETURN_CONVENTION --bool gjs_struct_foreign_release_g_argument (JSContext *context, -- GITransfer transfer, -- GIBaseInfo *interface_info, -- GArgument *arg); -+bool gjs_struct_foreign_release_gi_argument(JSContext*, GITransfer, -+ GIStructInfo*, GIArgument*); - - #endif // GI_FOREIGN_H_ -diff -ruN cjs-6.2.0-orig/gi/function.cpp cjs-6.2.0/gi/function.cpp ---- cjs-6.2.0-orig/gi/function.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/function.cpp 2024-10-14 18:41:39.000000000 +0200 -@@ -25,19 +25,18 @@ - #include - #include // for JS_ReportOutOfMemory - #include -+#include // for RuntimeHeapIsCollecting - #include - #include // for JSPROP_PERMANENT - #include - #include // for GetRealmFunctionPrototype - #include --#include - #include - #include - #include - #include --#include // for HandleValueArray --#include // for JS_GetObjectFunction --#include // for JSProtoKey -+#include // for HandleValueArray -+#include // for JSProtoKey - - #include "gi/arg-cache.h" - #include "gi/arg-inl.h" -@@ -132,8 +131,7 @@ - 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); -+ return JS_NewObjectWithGivenProto(cx, nullptr, builtin_function_proto); - } - - static const JSClassOps class_ops; -@@ -192,12 +190,10 @@ - } - } - --static void --set_return_ffi_arg_from_giargument (GITypeInfo *ret_type, -- void *result, -- GIArgument *return_value) --{ -- // Be consistent with gjs_value_to_g_argument() -+static void set_return_ffi_arg_from_gi_argument(GITypeInfo* ret_type, -+ void* result, -+ GIArgument* return_value) { -+ // Be consistent with gjs_value_to_gi_argument() - switch (g_type_info_get_tag(ret_type)) { - case GI_TYPE_TAG_VOID: - g_assert_not_reached(); -@@ -230,10 +226,8 @@ - break; - case GI_TYPE_TAG_INTERFACE: - { -- GIInfoType interface_type; -- - GjsAutoBaseInfo interface_info(g_type_info_get_interface(ret_type)); -- interface_type = g_base_info_get_type(interface_info); -+ GIInfoType interface_type = interface_info.type(); - - if (interface_type == GI_INFO_TYPE_ENUM || - interface_type == GI_INFO_TYPE_FLAGS) -@@ -303,7 +297,7 @@ - if (g_type_info_get_tag(&ret_type) != GI_TYPE_TAG_VOID) { - GIArgument argument = {}; - gjs_gi_argument_init_default(&ret_type, &argument); -- set_return_ffi_arg_from_giargument(&ret_type, result, &argument); -+ set_return_ffi_arg_from_gi_argument(&ret_type, result, &argument); - } - - if (G_UNLIKELY(!is_valid())) { -@@ -317,7 +311,7 @@ - - JSContext* context = this->context(); - GjsContextPrivate* gjs = GjsContextPrivate::from_cx(context); -- if (G_UNLIKELY(gjs->sweeping())) { -+ if (JS::RuntimeHeapIsCollecting()) { - warn_about_illegal_js_callback( - "during garbage collection", - "destroying a Clutter actor or GTK widget with ::destroy signal " -@@ -396,12 +390,9 @@ - gjs->exit_immediately(code); - - // Some other uncatchable exception, e.g. out of memory -- JSFunction* fn = JS_GetObjectFunction(callable()); -- std::string descr = -- fn ? "function " + gjs_debug_string(JS_GetFunctionDisplayId(fn)) -- : "callable object " + gjs_debug_object(callable()); - g_error("Call to %s (%s.%s) terminated with uncatchable exception", -- descr.c_str(), m_info.ns(), m_info.name()); -+ gjs_debug_callable(callable()).c_str(), m_info.ns(), -+ m_info.name()); - } - - // If the callback has a GError** argument, then make a GError from the -@@ -480,7 +471,7 @@ - g_callable_info_load_arg(m_info, array_length_pos, - &array_length_arg); - g_arg_info_load_type(&array_length_arg, &arg_type_info); -- size_t length = gjs_g_argument_get_array_length( -+ size_t length = gjs_gi_argument_get_array_length( - g_type_info_get_tag(&arg_type_info), - args[array_length_pos + c_args_offset]); - -@@ -503,8 +494,8 @@ - !g_arg_info_is_caller_allocates(&arg_info)) - arg = *reinterpret_cast(arg); - -- if (!gjs_value_from_g_argument(context, jsargs[n_jsargs++], -- &type_info, arg, false)) -+ if (!gjs_value_from_gi_argument(context, jsargs[n_jsargs++], -+ &type_info, arg, false)) - return false; - break; - } -@@ -530,12 +521,12 @@ - transfer = g_callable_info_get_caller_owns(m_info); - /* non-void return value, no out args. Should - * be a single return value. */ -- if (!gjs_value_to_g_argument(context, rval, ret_type, "callback", -- GJS_ARGUMENT_RETURN_VALUE, transfer, -- GjsArgumentFlags::MAY_BE_NULL, &argument)) -+ if (!gjs_value_to_gi_argument(context, rval, ret_type, "callback", -+ GJS_ARGUMENT_RETURN_VALUE, transfer, -+ GjsArgumentFlags::MAY_BE_NULL, &argument)) - return false; - -- set_return_ffi_arg_from_giargument(ret_type, result, &argument); -+ set_return_ffi_arg_from_gi_argument(ret_type, result, &argument); - } else if (n_outargs == 1 && ret_type_is_void) { - /* void return value, one out args. Should - * be a single return value. */ -@@ -559,14 +550,11 @@ - return false; - - if (!is_array) { -- JSFunction* fn = JS_GetObjectFunction(callable()); -- std::string descr = -- fn ? "function " + gjs_debug_string(JS_GetFunctionDisplayId(fn)) -- : "callable object " + gjs_debug_object(callable()); - gjs_throw(context, - "Call to %s (%s.%s) returned unexpected value, expecting " - "an Array", -- descr.c_str(), m_info.ns(), m_info.name()); -+ gjs_debug_callable(callable()).c_str(), m_info.ns(), -+ m_info.name()); - return false; - } - -@@ -583,10 +571,10 @@ - if (!JS_GetElement(context, out_array, elem_idx, &elem)) - return false; - -- if (!gjs_value_to_g_argument(context, elem, ret_type, "callback", -- GJS_ARGUMENT_RETURN_VALUE, transfer, -- GjsArgumentFlags::MAY_BE_NULL, -- &argument)) -+ if (!gjs_value_to_gi_argument(context, elem, ret_type, "callback", -+ GJS_ARGUMENT_RETURN_VALUE, transfer, -+ GjsArgumentFlags::MAY_BE_NULL, -+ &argument)) - return false; - - if ((ret_tag == GI_TYPE_TAG_FILENAME || -@@ -604,7 +592,7 @@ - } - } - -- set_return_ffi_arg_from_giargument(ret_type, result, &argument); -+ set_return_ffi_arg_from_gi_argument(ret_type, result, &argument); - - elem_idx++; - } -@@ -647,7 +635,7 @@ - GITypeInfo type_info; - g_arg_info_load_type(&arg_info, &type_info); - -- if (!gjs_g_argument_release(context, transfer, &type_info, arg)) -+ if (!gjs_gi_argument_release(context, transfer, &type_info, arg)) - return false; - - continue; -@@ -669,8 +657,8 @@ - - GITypeInfo type_info; - g_arg_info_load_type(&data->arg_info, &type_info); -- if (!gjs_g_argument_release(self->context(), transfer, -- &type_info, &data->arg)) { -+ if (!gjs_gi_argument_release(self->context(), transfer, -+ &type_info, &data->arg)) { - gjs_throw(self->context(), - "Impossible to release closure argument '%s'", - g_base_info_get_name(&data->arg_info)); -@@ -782,11 +770,9 @@ - } - - if (type_tag == GI_TYPE_TAG_INTERFACE) { -- GIInfoType interface_type; -- - GjsAutoBaseInfo interface_info = - g_type_info_get_interface(&type_info); -- interface_type = g_base_info_get_type(interface_info); -+ GIInfoType interface_type = interface_info.type(); - if (interface_type == GI_INFO_TYPE_CALLBACK) { - gjs_throw(context(), - "%s %s accepts another callback as a parameter. This " -@@ -843,13 +829,13 @@ - - namespace Gjs { - --static void* get_return_ffi_pointer_from_giargument( -- GITypeInfo* return_type, GIFFIReturnValue* return_value) { -- // This should be the inverse of gi_type_info_extract_ffi_return_value(). -- if (!return_type) -- return nullptr; -- -- switch (g_type_info_get_tag(return_type)) { -+static void* get_return_ffi_pointer_from_gi_argument( -+ GITypeTag tag, GITypeInfo* return_type, GIFFIReturnValue* return_value) { -+ if (return_type && g_type_info_is_pointer(return_type)) -+ return &gjs_arg_member(return_value); -+ switch (tag) { -+ case GI_TYPE_TAG_VOID: -+ return nullptr; - case GI_TYPE_TAG_INT8: - return &gjs_arg_member(return_value); - case GI_TYPE_TAG_INT16: -@@ -875,9 +861,12 @@ - case GI_TYPE_TAG_DOUBLE: - return &gjs_arg_member(return_value); - case GI_TYPE_TAG_INTERFACE: { -+ if (!return_type) -+ return nullptr; -+ - GjsAutoBaseInfo info = g_type_info_get_interface(return_type); - -- switch (g_base_info_get_type(info)) { -+ switch (info.type()) { - case GI_INFO_TYPE_ENUM: - case GI_INFO_TYPE_FLAGS: - return &gjs_arg_member( -@@ -894,7 +883,7 @@ - - // This function can be called in two different ways. You can either use it to - // 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 -+// to keep the return values in GIArgument format by providing a @r_value - // argument. - bool Function::invoke(JSContext* context, const JS::CallArgs& args, - JS::HandleObject this_obj /* = nullptr */, -@@ -1054,9 +1043,10 @@ - g_assert_cmpuint(ffi_arg_pos, ==, ffi_argc); - g_assert_cmpuint(gi_arg_pos, ==, state.gi_argc); - -+ GITypeTag return_tag = m_arguments.return_tag(); - GITypeInfo* return_type = m_arguments.return_type(); -- return_value_p = -- get_return_ffi_pointer_from_giargument(return_type, &return_value); -+ return_value_p = get_return_ffi_pointer_from_gi_argument( -+ return_tag, return_type, &return_value); - ffi_call(&m_invoker.cif, FFI_FN(m_invoker.native_address), return_value_p, - ffi_arg_pointers.get()); - -@@ -1069,6 +1059,11 @@ - if (return_type) { - gi_type_info_extract_ffi_return_value(return_type, &return_value, - state.return_value()); -+ } else if (return_tag != GI_TYPE_TAG_VOID) { -+ g_assert(GI_TYPE_TAG_IS_BASIC(return_tag)); -+ gi_type_tag_extract_ffi_return_value(return_tag, GI_INFO_TYPE_INVALID, -+ &return_value, -+ state.return_value()); - } - - // Process out arguments and return values. This loop is skipped if we fail -@@ -1102,8 +1097,7 @@ - "to pass to the out '%s' argument. It may be that the " - "function is unsupported, or there may be a bug in " - "its annotations.", -- g_base_info_get_namespace(m_info), -- g_base_info_get_name(m_info), -+ m_info.ns(), m_info.name(), - g_base_info_get_name(&arg_info)); - state.failed = true; - break; -@@ -1234,9 +1228,7 @@ - gjs_debug_marshal(GJS_DEBUG_GFUNCTION, "Call callee %p priv %p", - callee.get(), priv); - -- if (priv == NULL) -- return true; // we are the prototype -- -+ g_assert(priv); - return priv->invoke(context, js_argv); - } - -@@ -1246,8 +1238,7 @@ - } - - void Function::finalize_impl(JS::GCContext*, Function* priv) { -- if (priv == NULL) -- return; /* we are the prototype, not a real instance, so constructor never called */ -+ g_assert(priv); - delete priv; - } - -@@ -1262,15 +1253,6 @@ - - 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}"); -- if (!retval) -- return false; -- rec.rval().setString(retval); -- return true; -- } -- - return priv->to_string_impl(context, rec.rval()); - } - -@@ -1293,7 +1275,7 @@ - } - - GjsAutoChar descr; -- if (g_base_info_get_type(m_info) == GI_INFO_TYPE_FUNCTION) { -+ if (m_info.type() == GI_INFO_TYPE_FUNCTION) { - descr = g_strdup_printf( - "%s(%s) {\n\t/* wrapper for native symbol %s() */\n}", - format_name().c_str(), arg_names.c_str(), -diff -ruN cjs-6.2.0-orig/gi/fundamental.cpp cjs-6.2.0/gi/fundamental.cpp ---- cjs-6.2.0-orig/gi/fundamental.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/fundamental.cpp 2024-10-14 18:41:39.000000000 +0200 -@@ -8,11 +8,9 @@ - #include - #include - --#include // for SystemAllocPolicy - #include - #include // for JS_ReportOutOfMemory - #include // for WeakCache --#include // for DefaultHasher via WeakCache - #include // for GetClass - #include - #include -@@ -200,7 +198,7 @@ - bool FundamentalInstance::constructor_impl(JSContext* cx, - JS::HandleObject object, - const JS::CallArgs& argv) { -- GArgument ret_value; -+ GIArgument ret_value; - GITypeInfo return_info; - - if (!invoke_constructor(cx, object, argv, &ret_value) || -@@ -210,7 +208,7 @@ - GICallableInfo* constructor_info = get_prototype()->constructor_info(); - g_callable_info_load_return_type(constructor_info, &return_info); - -- return gjs_g_argument_release( -+ return gjs_gi_argument_release( - cx, g_callable_info_get_caller_owns(constructor_info), &return_info, - &ret_value); - } -diff -ruN cjs-6.2.0-orig/gi/gerror.cpp cjs-6.2.0/gi/gerror.cpp ---- cjs-6.2.0-orig/gi/gerror.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/gerror.cpp 2024-10-14 18:41:39.000000000 +0200 -@@ -12,6 +12,7 @@ - #include - #include - #include -+#include - #include - #include - #include // for JSPROP_ENUMERATE -@@ -263,7 +264,7 @@ - - /* last attempt: load GIRepository (for invoke errors, rarely - needed) */ -- g_irepository_require(nullptr, "GIRepository", "1.0", -+ g_irepository_require(nullptr, "GIRepository", "2.0", - GIRepositoryLoadFlags(0), nullptr); - info = g_irepository_find_by_error_domain(nullptr, domain); - -@@ -278,7 +279,8 @@ - JS::RootedObject frame(cx); - JS::RootedString stack(cx); - JS::RootedString source(cx); -- uint32_t line, column; -+ uint32_t line; -+ JS::TaggedColumnNumberOneOrigin tagged_column; - - if (!JS::CaptureCurrentStack(cx, &frame) || - !JS::BuildStackString(cx, nullptr, frame, &stack)) -@@ -287,7 +289,7 @@ - auto ok = JS::SavedFrameResult::Ok; - if (JS::GetSavedFrameSource(cx, nullptr, frame, &source) != ok || - JS::GetSavedFrameLine(cx, nullptr, frame, &line) != ok || -- JS::GetSavedFrameColumn(cx, nullptr, frame, &column) != ok) { -+ JS::GetSavedFrameColumn(cx, nullptr, frame, &tagged_column) != ok) { - gjs_throw(cx, "Error getting saved frame information"); - return false; - } -@@ -299,7 +301,8 @@ - JSPROP_ENUMERATE) && - JS_DefinePropertyById(cx, obj, atoms.line_number(), line, - JSPROP_ENUMERATE) && -- JS_DefinePropertyById(cx, obj, atoms.column_number(), column, -+ JS_DefinePropertyById(cx, obj, atoms.column_number(), -+ tagged_column.oneOriginValue(), - JSPROP_ENUMERATE); - } - -diff -ruN cjs-6.2.0-orig/gi/gobject.cpp cjs-6.2.0/gi/gobject.cpp ---- cjs-6.2.0-orig/gi/gobject.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/gobject.cpp 2024-10-14 18:41:39.000000000 +0200 -@@ -163,12 +163,10 @@ - */ - Gjs::AutoMainRealm ar{gjs}; - -- JS::RootedObject constructor( -- cx, gjs_lookup_object_constructor_from_info(cx, nullptr, type)); -- if (!constructor) -+ JS::RootedValue constructor{cx}; -+ if (!gjs_lookup_object_constructor(cx, type, &constructor)) - return nullptr; - -- JS::RootedValue v_constructor(cx, JS::ObjectValue(*constructor)); - JS::RootedObject object(cx); - if (n_construct_properties) { - JS::RootedObject props_hash(cx, JS_NewPlainObject(cx)); -@@ -182,9 +180,9 @@ - JS::RootedValueArray<1> args(cx); - args[0].set(JS::ObjectValue(*props_hash)); - -- if (!JS::Construct(cx, v_constructor, args, &object)) -+ if (!JS::Construct(cx, constructor, args, &object)) - return nullptr; -- } else if (!JS::Construct(cx, v_constructor, JS::HandleValueArray::empty(), -+ } else if (!JS::Construct(cx, constructor, JS::HandleValueArray::empty(), - &object)) { - return nullptr; - } -diff -ruN cjs-6.2.0-orig/gi/gobject.h cjs-6.2.0/gi/gobject.h ---- cjs-6.2.0-orig/gi/gobject.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/gobject.h 2024-10-14 18:41:39.000000000 +0200 -@@ -5,6 +5,8 @@ - #ifndef GI_GOBJECT_H_ - #define GI_GOBJECT_H_ - -+#include -+ - #include - - #include -diff -ruN cjs-6.2.0-orig/gi/gtype.cpp cjs-6.2.0/gi/gtype.cpp ---- cjs-6.2.0-orig/gi/gtype.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/gtype.cpp 2024-10-14 18:41:39.000000000 +0200 -@@ -8,11 +8,9 @@ - #include - #include - --#include // for SystemAllocPolicy - #include - #include - #include // for WeakCache --#include // for DefaultHasher via WeakCache - #include - #include // for JSPROP_PERMANENT - #include -diff -ruN cjs-6.2.0-orig/gi/interface.cpp cjs-6.2.0/gi/interface.cpp ---- cjs-6.2.0-orig/gi/interface.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/interface.cpp 2024-10-14 18:41:39.000000000 +0200 -@@ -9,6 +9,7 @@ - - #include - #include // for JS_ReportOutOfMemory -+#include // for MutableHandleIdVector - #include // for PropertyKey, jsid - #include - #include // for UniqueChars -@@ -34,18 +35,20 @@ - GJS_DEC_COUNTER(interface); - } - --static bool append_inferface_properties(JSContext* cx, -- JS::MutableHandleIdVector properties, -- GIInterfaceInfo* iface_info) { -- int n_methods = g_interface_info_get_n_methods(iface_info); -+bool InterfacePrototype::new_enumerate_impl( -+ JSContext* cx, JS::HandleObject, JS::MutableHandleIdVector properties, -+ bool only_enumerable [[maybe_unused]]) { -+ if (!info()) -+ return true; -+ -+ int n_methods = g_interface_info_get_n_methods(info()); - if (!properties.reserve(properties.length() + n_methods)) { - JS_ReportOutOfMemory(cx); - return false; - } - - for (int i = 0; i < n_methods; i++) { -- GjsAutoFunctionInfo meth_info = -- g_interface_info_get_method(iface_info, i); -+ GjsAutoFunctionInfo meth_info = g_interface_info_get_method(info(), i); - GIFunctionInfoFlags flags = g_function_info_get_flags(meth_info); - - if (flags & GI_FUNCTION_IS_METHOD) { -@@ -60,31 +63,6 @@ - return true; - } - --bool InterfacePrototype::new_enumerate_impl( -- JSContext* cx, JS::HandleObject obj [[maybe_unused]], -- JS::MutableHandleIdVector properties, -- bool only_enumerable [[maybe_unused]]) { -- unsigned n_interfaces; -- GjsAutoPointer interfaces = -- g_type_interfaces(gtype(), &n_interfaces); -- -- for (unsigned k = 0; k < n_interfaces; k++) { -- GjsAutoInterfaceInfo iface_info = -- g_irepository_find_by_gtype(nullptr, interfaces[k]); -- -- if (!iface_info) -- continue; -- -- if (!append_inferface_properties(cx, properties, iface_info)) -- return false; -- } -- -- if (!info()) -- return true; -- -- return append_inferface_properties(cx, properties, info()); --} -- - // See GIWrapperBase::resolve(). - bool InterfacePrototype::resolve_impl(JSContext* context, JS::HandleObject obj, - JS::HandleId id, bool* resolved) { -@@ -194,25 +172,18 @@ - JS::MutableHandleValue value_p) - { - JSObject *constructor; -- GIBaseInfo *interface_info; -- -- interface_info = g_irepository_find_by_gtype(nullptr, gtype); - -+ GjsAutoInterfaceInfo interface_info = gjs_lookup_gtype(nullptr, gtype); - if (!interface_info) { - gjs_throw(context, "Cannot expose non introspectable interface %s", - g_type_name(gtype)); - return false; - } - -- g_assert(g_base_info_get_type(interface_info) == -- GI_INFO_TYPE_INTERFACE); -- - constructor = gjs_lookup_generic_constructor(context, interface_info); - if (G_UNLIKELY(!constructor)) - return false; - -- g_base_info_unref(interface_info); -- - value_p.setObject(*constructor); - return true; - } -diff -ruN cjs-6.2.0-orig/gi/js-value-inl.h cjs-6.2.0/gi/js-value-inl.h ---- cjs-6.2.0-orig/gi/js-value-inl.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/js-value-inl.h 2024-10-14 18:41:39.000000000 +0200 -@@ -10,6 +10,7 @@ - - #include // for isnan - #include -+#include - - #include - #include -@@ -20,6 +21,7 @@ - #include - #include - #include // for UniqueChars -+#include // for CanonicalizeNaN - - #include "gi/gtype.h" - #include "gi/value.h" -@@ -229,7 +231,7 @@ - return std::numeric_limits::lowest(); - } - --template -+template - GJS_JSAPI_RETURN_CONVENTION inline bool js_value_to_c_checked( - JSContext* cx, const JS::HandleValue& value, T* out, bool* out_of_range) { - static_assert(std::numeric_limits::max() >= -@@ -266,7 +268,7 @@ - } - - if constexpr (std::is_same_v) -- return js_value_to_c(cx, value, out); -+ return js_value_to_c(cx, value, out); - - // JS::ToIntNN() converts undefined, NaN, infinity to 0 - if constexpr (std::is_integral_v) { -@@ -278,7 +280,7 @@ - } - - if constexpr (std::is_arithmetic_v) { -- bool ret = js_value_to_c(cx, value, out); -+ bool ret = js_value_to_c(cx, value, out); - if (out_of_range) { - // Infinity and NaN preserved between floating point types - if constexpr (std::is_floating_point_v && -@@ -300,18 +302,20 @@ - *out_of_range |= std::isnan(*out); - } - return ret; -+ // https://trac.cppcheck.net/ticket/10731 -+ // cppcheck-suppress missingReturn - } - } - --template -+template - GJS_JSAPI_RETURN_CONVENTION inline bool js_value_to_c_checked( - JSContext* cx, const JS::HandleValue& value, TypeWrapper* out, - bool* out_of_range) { - static_assert(std::is_integral_v); - - WantedType wanted_out; -- if (!js_value_to_c_checked(cx, value, &wanted_out, -- out_of_range)) -+ if (!js_value_to_c_checked(cx, value, &wanted_out, -+ out_of_range)) - return false; - - *out = TypeWrapper{wanted_out}; -@@ -319,4 +323,61 @@ - return true; - } - -+template -+GJS_JSAPI_RETURN_CONVENTION inline bool c_value_to_js( -+ JSContext* cx [[maybe_unused]], T value, -+ JS::MutableHandleValue js_value_p) { -+ if constexpr (std::is_same_v) { -+ js_value_p.setBoolean(value); -+ return true; -+ } else if constexpr (std::is_same_v< // NOLINT(readability/braces) -+ T, gboolean> && -+ TAG == GI_TYPE_TAG_BOOLEAN) { -+ js_value_p.setBoolean(value); -+ return true; -+ } else if constexpr (std::is_arithmetic_v) { -+ if constexpr (std::is_same_v || -+ std::is_same_v) { -+ if (value < Gjs::min_safe_big_number() || -+ value > Gjs::max_safe_big_number()) { -+ js_value_p.setDouble(value); -+ return true; -+ } -+ } -+ if constexpr (std::is_floating_point_v) { -+ js_value_p.setDouble(JS::CanonicalizeNaN(double{value})); -+ return true; -+ } -+ js_value_p.setNumber(value); -+ return true; -+ } else if constexpr (std::is_same_v || -+ std::is_same_v) { -+ if (!value) { -+ js_value_p.setNull(); -+ return true; -+ } -+ return gjs_string_from_utf8(cx, value, js_value_p); -+ } else { -+ static_assert(std::is_arithmetic_v, "Unsupported type"); -+ } -+} -+ -+template -+GJS_JSAPI_RETURN_CONVENTION inline bool c_value_to_js_checked( -+ JSContext* cx [[maybe_unused]], T value, -+ JS::MutableHandleValue js_value_p) { -+ if constexpr (std::is_same_v || std::is_same_v) { -+ if (value < Gjs::min_safe_big_number() || -+ value > Gjs::max_safe_big_number()) { -+ g_warning( -+ "Value %s cannot be safely stored in a JS Number " -+ "and may be rounded", -+ std::to_string(value).c_str()); -+ } -+ } -+ -+ return c_value_to_js(cx, value, js_value_p); -+} -+ - } // namespace Gjs -diff -ruN cjs-6.2.0-orig/gi/ns.cpp cjs-6.2.0/gi/ns.cpp ---- cjs-6.2.0-orig/gi/ns.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/ns.cpp 2024-10-14 18:44:51.000000000 +0200 -@@ -4,6 +4,10 @@ - - #include - -+#include -+ -+#include -+ - #include - #include - -@@ -11,6 +15,7 @@ - #include - #include - #include // for JS_ReportOutOfMemory -+#include // for MutableHandleIdVector - #include - #include // for JSPROP_READONLY - #include -@@ -30,6 +35,10 @@ - #include "cjs/mem-private.h" - #include "util/log.h" - -+#if GLIB_CHECK_VERSION(2, 79, 2) -+# include "cjs/deprecation.h" -+#endif // GLib >= 2.79.2 -+ - [[nodiscard]] static bool type_is_enumerable(GIInfoType info_type) { - switch (info_type) { - case GI_INFO_TYPE_BOXED: -@@ -64,16 +73,51 @@ - friend CWrapperPointerOps; - friend CWrapper; - -+#if GLIB_CHECK_VERSION(2, 79, 2) -+ bool m_is_gio_or_glib : 1; -+#endif // GLib >= 2.79.2 -+ - static constexpr auto PROTOTYPE_SLOT = GjsGlobalSlot::PROTOTYPE_ns; - static constexpr GjsDebugTopic DEBUG_TOPIC = GJS_DEBUG_GNAMESPACE; - - explicit Ns(const char* ns_name) - : GjsAutoChar(const_cast(ns_name), GjsAutoTakeOwnership()) { - GJS_INC_COUNTER(ns); -+#if GLIB_CHECK_VERSION(2, 79, 2) -+ m_is_gio_or_glib = -+ strcmp(ns_name, "Gio") == 0 || strcmp(ns_name, "GLib") == 0; -+#endif // GLib >= 2.79.2 - } - - ~Ns() { GJS_DEC_COUNTER(ns); } - -+#if GLIB_CHECK_VERSION(2, 79, 2) -+ // helper function -+ void platform_specific_warning(JSContext* cx, const char* prefix, -+ const char* platform, -+ const char* resolved_name, -+ const char** exceptions = nullptr) { -+ if (!g_str_has_prefix(resolved_name, prefix)) -+ return; -+ -+ const char* base_name = resolved_name + strlen(prefix); -+ GjsAutoChar old_name = -+ g_strdup_printf("%s.%s", this->get(), resolved_name); -+ if (exceptions) { -+ for (const char** exception = exceptions; *exception; exception++) { -+ if (strcmp(old_name, *exception) == 0) -+ return; -+ } -+ } -+ -+ GjsAutoChar new_name = -+ g_strdup_printf("%s%s.%s", this->get(), platform, base_name); -+ _gjs_warn_deprecated_once_per_callsite( -+ cx, GjsDeprecationMessageId::PlatformSpecificTypelib, -+ {old_name.get(), new_name.get()}); -+ } -+#endif // GLib >= 2.79.2 -+ - // JSClass operations - - // The *resolved out parameter, on success, should be false to indicate that -@@ -112,6 +156,24 @@ - "Found info type %s for '%s' in namespace '%s'", - gjs_info_type_name(info.type()), info.name(), info.ns()); - -+#if GLIB_CHECK_VERSION(2, 79, 2) -+ static const char* unix_types_exceptions[] = { -+ "Gio.UnixConnection", -+ "Gio.UnixCredentialsMessage", -+ "Gio.UnixFDList", -+ "Gio.UnixSocketAddress", -+ "Gio.UnixSocketAddressType", -+ nullptr}; -+ -+ if (m_is_gio_or_glib) { -+ platform_specific_warning(cx, "Unix", "Unix", name.get(), -+ unix_types_exceptions); -+ platform_specific_warning(cx, "unix_", "Unix", name.get()); -+ platform_specific_warning(cx, "Win32", "Win32", name.get()); -+ platform_specific_warning(cx, "win32_", "Win32", name.get()); -+ } -+#endif // GLib >= 2.79.2 -+ - bool defined; - if (!gjs_define_info(cx, obj, info, &defined)) { - gjs_debug(GJS_DEBUG_GNAMESPACE, "Failed to define info '%s'", -diff -ruN cjs-6.2.0-orig/gi/ns.h cjs-6.2.0/gi/ns.h ---- cjs-6.2.0-orig/gi/ns.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/ns.h 2024-10-14 18:41:39.000000000 +0200 -@@ -5,6 +5,8 @@ - #ifndef GI_NS_H_ - #define GI_NS_H_ - -+#include -+ - #include "cjs/macros.h" - - class JSObject; -diff -ruN cjs-6.2.0-orig/gi/object.cpp cjs-6.2.0/gi/object.cpp ---- cjs-6.2.0-orig/gi/object.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/object.cpp 2024-10-14 18:41:39.000000000 +0200 -@@ -92,8 +92,8 @@ - static const auto DISPOSED_OBJECT = std::numeric_limits::max(); - - GJS_JSAPI_RETURN_CONVENTION --static JSObject* gjs_lookup_object_prototype_from_info(JSContext*, -- GIObjectInfo*, GType); -+static JSObject* gjs_lookup_object_prototype_from_info(JSContext*, GIBaseInfo*, -+ GType); - - // clang-format off - G_DEFINE_QUARK(gjs::custom-type, ObjectBase::custom_type) -@@ -114,16 +114,6 @@ - return !!g_type_get_qdata(gtype(), ObjectBase::custom_type_quark()); - } - --// Plain g_type_query fails and leaves @query uninitialized for dynamic types. --// See https://gitlab.gnome.org/GNOME/glib/issues/623 --void ObjectBase::type_query_dynamic_safe(GTypeQuery* query) { -- GType type = gtype(); -- while (g_type_get_qdata(type, ObjectBase::custom_type_quark())) -- type = g_type_parent(type); -- -- g_type_query(type, query); --} -- - void ObjectInstance::link() { - g_assert(std::find(s_wrapped_gobject_list.begin(), - s_wrapped_gobject_list.end(), -@@ -242,32 +232,24 @@ - g_object_steal_qdata(m_ptr, priv_quark); - } - --GParamSpec* ObjectPrototype::find_param_spec_from_id(JSContext* cx, -- JS::HandleString key) { -+GParamSpec* ObjectPrototype::find_param_spec_from_id( -+ JSContext* cx, GjsAutoTypeClass const& object_class, -+ JS::HandleString key) { - /* First check for the ID in the cache */ -- auto entry = m_property_cache.lookupForAdd(key); -- if (entry) -- return entry->value(); - - JS::UniqueChars js_prop_name(JS_EncodeStringToUTF8(cx, key)); - if (!js_prop_name) - return nullptr; - - GjsAutoChar gname = gjs_hyphen_from_camel(js_prop_name.get()); -- GjsAutoTypeClass gobj_class(m_gtype); -- GParamSpec* pspec = g_object_class_find_property(gobj_class, gname); -- GjsAutoParam param_spec(pspec, GjsAutoTakeOwnership()); -+ GParamSpec* pspec = g_object_class_find_property(object_class, gname); - -- if (!param_spec) { -+ if (!pspec) { - gjs_wrapper_throw_nonexistent_field(cx, m_gtype, js_prop_name.get()); - return nullptr; - } - -- if (!m_property_cache.add(entry, key, std::move(param_spec))) { -- JS_ReportOutOfMemory(cx); -- return nullptr; -- } -- return pspec; /* owned by property cache */ -+ return pspec; - } - - /* A hook on adding a property to an object. This is called during a set -@@ -298,52 +280,41 @@ - if (is_custom_js_class()) - return true; - -- if (!ensure_uses_toggle_ref(cx)) { -- gjs_throw(cx, "Impossible to set toggle references on %sobject %p", -- m_gobj_disposed ? "disposed " : "", m_ptr.get()); -- return false; -- } -- -+ ensure_uses_toggle_ref(cx); - return true; - } - - bool ObjectBase::prop_getter(JSContext* cx, unsigned argc, JS::Value* vp) { - GJS_CHECK_WRAPPER_PRIV(cx, argc, vp, args, obj, ObjectBase, priv); - -- JS::RootedString name(cx, -- gjs_dynamic_property_private_slot(&args.callee()).toString()); -+ auto* pspec = static_cast( -+ gjs_dynamic_property_private_slot(&args.callee()).toPrivate()); - -- std::string fullName{priv->format_name() + "[" + gjs_debug_string(name) + -- "]"}; -+ std::string fullName{priv->format_name() + "[\"" + pspec->name + "\"]"}; - AutoProfilerLabel label(cx, "property getter", fullName.c_str()); - -- priv->debug_jsprop("Property getter", name, obj); -+ priv->debug_jsprop("Property getter", pspec->name, obj); - - if (priv->is_prototype()) - return true; - /* Ignore silently; note that this is different from what we do for - * boxed types, for historical reasons */ - -- return priv->to_instance()->prop_getter_impl(cx, name, args.rval()); -+ return priv->to_instance()->prop_getter_impl(cx, pspec, args.rval()); - } - --bool ObjectInstance::prop_getter_impl(JSContext* cx, JS::HandleString name, -+bool ObjectInstance::prop_getter_impl(JSContext* cx, GParamSpec* param, - JS::MutableHandleValue rval) { - if (!check_gobject_finalized("get any property from")) { - rval.setUndefined(); - return true; - } - -- ObjectPrototype* proto_priv = get_prototype(); -- GParamSpec *param = proto_priv->find_param_spec_from_id(cx, name); -- -- /* This is guaranteed because we resolved the property before */ -- g_assert(param); -- -- /* Do not fetch JS overridden properties from GObject, to avoid -- * infinite recursion. */ -- if (g_param_spec_get_qdata(param, ObjectBase::custom_property_quark())) -- return true; -+ if (param->flags & G_PARAM_DEPRECATED) { -+ const std::string& class_name = format_name(); -+ _gjs_warn_deprecated_once_per_callsite( -+ cx, DeprecatedGObjectProperty, {class_name.c_str(), param->name}); -+ } - - if ((param->flags & G_PARAM_READABLE) == 0) { - rval.setUndefined(); -@@ -384,7 +355,8 @@ - JS::RootedString name(cx, - gjs_dynamic_property_private_slot(&args.callee()).toString()); - -- std::string fullName = priv->format_name() + "." + gjs_debug_string(name); -+ std::string fullName{priv->format_name() + "[" + gjs_debug_string(name) + -+ "]"}; - AutoProfilerLabel label(cx, "field getter", fullName.c_str()); - - priv->debug_jsprop("Field getter", name, obj); -@@ -437,8 +409,8 @@ - return false; - } - -- return gjs_value_from_g_argument(cx, rval, type, GJS_ARGUMENT_FIELD, -- GI_TRANSFER_EVERYTHING, &arg); -+ return gjs_value_from_gi_argument(cx, rval, type, GJS_ARGUMENT_FIELD, -+ GI_TRANSFER_EVERYTHING, &arg); - /* transfer is irrelevant because g_field_info_get_field() doesn't - * handle boxed types */ - } -@@ -448,14 +420,13 @@ - bool ObjectBase::prop_setter(JSContext* cx, unsigned argc, JS::Value* vp) { - GJS_CHECK_WRAPPER_PRIV(cx, argc, vp, args, obj, ObjectBase, priv); - -- JS::RootedString name(cx, -- gjs_dynamic_property_private_slot(&args.callee()).toString()); -+ auto* pspec = static_cast( -+ gjs_dynamic_property_private_slot(&args.callee()).toPrivate()); - -- std::string fullName{priv->format_name() + "[" + gjs_debug_string(name) + -- "]"}; -+ std::string fullName{priv->format_name() + "[\"" + pspec->name + "\"]"}; - AutoProfilerLabel label(cx, "property setter", fullName.c_str()); - -- priv->debug_jsprop("Property setter", name, obj); -+ priv->debug_jsprop("Property setter", pspec->name, obj); - - if (priv->is_prototype()) - return true; -@@ -465,24 +436,14 @@ - /* Clear the JS stored value, to avoid keeping additional references */ - args.rval().setUndefined(); - -- return priv->to_instance()->prop_setter_impl(cx, name, args[0]); -+ return priv->to_instance()->prop_setter_impl(cx, pspec, args[0]); - } - --bool ObjectInstance::prop_setter_impl(JSContext* cx, JS::HandleString name, -+bool ObjectInstance::prop_setter_impl(JSContext* cx, GParamSpec* param_spec, - JS::HandleValue value) { - if (!check_gobject_finalized("set any property on")) - return true; - -- ObjectPrototype* proto_priv = get_prototype(); -- GParamSpec *param_spec = proto_priv->find_param_spec_from_id(cx, name); -- if (!param_spec) -- return false; -- -- /* Do not set JS overridden properties through GObject, to avoid -- * infinite recursion (unless constructing) */ -- if (g_param_spec_get_qdata(param_spec, ObjectBase::custom_property_quark())) -- return true; -- - if (!(param_spec->flags & G_PARAM_WRITABLE)) - /* prevent setting the prop even in JS */ - return gjs_wrapper_throw_readonly_field(cx, gtype(), param_spec->name); -@@ -622,11 +583,9 @@ - return !!prop_info; - } - --bool ObjectPrototype::lazy_define_gobject_property(JSContext* cx, -- JS::HandleObject obj, -- JS::HandleId id, -- bool* resolved, -- const char* name) { -+bool ObjectPrototype::lazy_define_gobject_property( -+ JSContext* cx, JS::HandleObject obj, JS::HandleId id, GParamSpec* pspec, -+ bool* resolved, const char* name) { - bool found = false; - if (!JS_AlreadyHasOwnPropertyById(cx, obj, id, &found)) - return false; -@@ -639,10 +598,17 @@ - - debug_jsprop("Defining lazy GObject property", id, obj); - -- JS::RootedValue private_id(cx, JS::StringValue(id.toString())); -+ // Do not fetch JS overridden properties from GObject, to avoid -+ // infinite recursion. -+ if (g_param_spec_get_qdata(pspec, ObjectBase::custom_property_quark())) { -+ *resolved = false; -+ return true; -+ } -+ -+ JS::RootedValue private_value{cx, JS::PrivateValue(pspec)}; - if (!gjs_define_property_dynamic( -- cx, obj, name, "gobject_prop", &ObjectBase::prop_getter, -- &ObjectBase::prop_setter, private_id, -+ cx, obj, name, id, "gobject_prop", &ObjectBase::prop_getter, -+ &ObjectBase::prop_setter, private_value, - // Make property configurable so that interface properties can be - // overridden by GObject.ParamSpec.override in the class that - // implements them -@@ -701,8 +667,11 @@ - g_assert(v_prototype.isObject() && "prototype must be an object"); - - JS::RootedObject prototype(cx, &v_prototype.toObject()); -- JS::RootedId id(cx, JS::PropertyKey::NonIntAtom(JS_GetFunctionId( -- JS_GetObjectFunction(&args.callee())))); -+ JS::RootedFunction fn_obj{cx, JS_GetObjectFunction(&args.callee())}; -+ JS::RootedString fn_name{cx}; -+ if (!JS_GetFunctionId(cx, fn_obj, &fn_name)) -+ return false; -+ JS::RootedId id{cx, JS::PropertyKey::NonIntAtom(fn_name)}; - return JS_GetPropertyById(cx, prototype, id, args.rval()); - } - -@@ -731,7 +700,7 @@ - } - - static bool resolve_on_interface_prototype(JSContext* cx, -- GIObjectInfo* iface_info, -+ GIInterfaceInfo* iface_info, - JS::HandleId identifier, - JS::HandleObject class_prototype, - bool* found) { -@@ -832,8 +801,10 @@ - if (canonical_name && G_TYPE_IS_CLASSED(m_gtype) && !is_custom_js_class()) { - GjsAutoTypeClass oclass(m_gtype); - -- if (g_object_class_find_property(oclass, canonical_name)) -- return lazy_define_gobject_property(cx, obj, id, resolved, name); -+ if (GParamSpec* pspec = -+ g_object_class_find_property(oclass, canonical_name)) -+ return lazy_define_gobject_property(cx, obj, id, pspec, resolved, -+ name); - - for (i = 0; i < n_interfaces; i++) { - GType iface_gtype = -@@ -843,8 +814,10 @@ - - GjsAutoTypeClass iclass(iface_gtype); - -- if (g_object_class_find_property(iclass, canonical_name)) -- return lazy_define_gobject_property(cx, obj, id, resolved, name); -+ if (GParamSpec* pspec = -+ g_object_class_find_property(iclass, canonical_name)) -+ return lazy_define_gobject_property(cx, obj, id, pspec, -+ resolved, name); - } - } - -@@ -880,8 +853,8 @@ - GParamSpec* pspec = g_object_class_find_property( - oclass, canonical_name); // unowned - if (pspec && pspec->owner_type == m_gtype) { -- return lazy_define_gobject_property(cx, obj, id, resolved, -- name); -+ return lazy_define_gobject_property(cx, obj, id, pspec, -+ resolved, name); - } - } - -@@ -893,11 +866,11 @@ - return true; - } - --[[nodiscard]] static bool is_gobject_property_name(GIObjectInfo* info, -- const char* name) { -+[[nodiscard]] static GjsAutoChar get_gobject_property_name(GIObjectInfo* info, -+ const char* name) { - // Optimization: GObject property names must start with a letter - if (!g_ascii_isalpha(name[0])) -- return false; -+ return nullptr; - - int n_props = g_object_info_get_n_properties(info); - int n_ifaces = g_object_info_get_n_interfaces(info); -@@ -909,15 +882,15 @@ - for (ix = 0; ix < n_props; ix++) { - GjsAutoPropertyInfo prop_info = g_object_info_get_property(info, ix); - if (strcmp(canonical_name, prop_info.name()) == 0) -- return true; -+ return canonical_name; - } - - for (ix = 0; ix < n_ifaces; ix++) { - GjsAutoInterfaceInfo iface_info = g_object_info_get_interface(info, ix); - if (is_ginterface_property_name(iface_info, canonical_name)) -- return true; -+ return canonical_name; - } -- return false; -+ return nullptr; - } - - // Override of GIWrapperBase::id_is_never_lazy() -@@ -1005,8 +978,13 @@ - * method resolution. */ - } - -- if (is_gobject_property_name(m_info, name)) -- return lazy_define_gobject_property(context, obj, id, resolved, name); -+ if (auto const& canonical_name = get_gobject_property_name(m_info, name)) { -+ GjsAutoTypeClass gobj_class{m_gtype}; -+ if (GParamSpec* pspec = -+ g_object_class_find_property(gobj_class, canonical_name)) -+ return lazy_define_gobject_property(context, obj, id, pspec, -+ resolved, name); -+ } - - GjsAutoFieldInfo field_info = lookup_field_info(m_info, name); - if (field_info) { -@@ -1032,8 +1010,9 @@ - - JS::RootedValue private_id(context, JS::StringValue(key)); - if (!gjs_define_property_dynamic( -- context, obj, name, "gobject_field", &ObjectBase::field_getter, -- &ObjectBase::field_setter, private_id, flags)) -+ context, obj, name, id, "gobject_field", -+ &ObjectBase::field_getter, &ObjectBase::field_setter, -+ private_id, flags)) - return false; - - *resolved = true; -@@ -1190,10 +1169,10 @@ - - /* Set properties from args to constructor (args[0] is supposed to be - * a hash) */ --bool ObjectPrototype::props_to_g_parameters(JSContext* context, -- JS::HandleObject props, -- std::vector* names, -- AutoGValueVector* values) { -+bool ObjectPrototype::props_to_g_parameters( -+ JSContext* context, GjsAutoTypeClass const& object_class, -+ JS::HandleObject props, std::vector* names, -+ AutoGValueVector* values) { - size_t ix, length; - JS::RootedId prop_id(context); - JS::RootedValue value(context); -@@ -1215,7 +1194,8 @@ - context, m_gtype, gjs_debug_id(prop_id).c_str()); - - JS::RootedString js_prop_name(context, prop_id.toString()); -- GParamSpec *param_spec = find_param_spec_from_id(context, js_prop_name); -+ GParamSpec* param_spec = -+ find_param_spec_from_id(context, object_class, js_prop_name); - if (!param_spec) - return false; - -@@ -1241,7 +1221,7 @@ - if (!gjs_value_to_g_value(context, value, &gvalue)) - return false; - -- names->push_back(param_spec->name); /* owned by GParamSpec in cache */ -+ names->push_back(param_spec->name); // owned by GParamSpec - } - - return true; -@@ -1501,6 +1481,8 @@ - void - ObjectInstance::release_native_object(void) - { -+ static GType gdksurface_type = 0; -+ - discard_wrapper(); - - if (m_gobj_finalized) { -@@ -1519,11 +1501,41 @@ - if (m_gobj_disposed) - ignore_gobject_finalization(); - -- if (m_uses_toggle_ref && !m_gobj_disposed) -+ if (m_uses_toggle_ref && !m_gobj_disposed) { - g_object_remove_toggle_ref(m_ptr.release(), wrapped_gobj_toggle_notify, - this); -- else -- m_ptr = nullptr; -+ return; -+ } -+ -+ // Unref the object. Handle any special cases for destruction here -+ if (m_ptr->ref_count == 1) { -+ // Quickest way to check for GdkSurface if Gdk has been loaded? -+ // surface_type may be 0 if Gdk not loaded. The type may be a private -+ // type and not have introspection info. -+ if (!gdksurface_type) -+ gdksurface_type = g_type_from_name("GdkSurface"); -+ if (gdksurface_type && g_type_is_a(gtype(), gdksurface_type)) { -+ GObject* ptr = m_ptr.release(); -+ -+ // Workaround for https://gitlab.gnome.org/GNOME/gtk/-/issues/6289 -+ GjsAutoObjectInfo surface_info = -+ g_irepository_find_by_gtype(nullptr, gdksurface_type); -+ g_assert(surface_info && "Could not find introspected GdkSurface info"); -+ GjsAutoFunctionInfo destroy_func = -+ g_object_info_find_method(surface_info, "destroy"); -+ GIArgument destroy_args; -+ gjs_arg_set(&destroy_args, ptr); -+ GIArgument unused_return; -+ -+ GjsAutoError err; -+ if (!g_function_info_invoke(destroy_func, &destroy_args, 1, nullptr, -+ 0, &unused_return, err.out())) -+ g_critical("Error destroying GdkSurface %p: %s", ptr, -+ err->message); -+ } -+ } -+ -+ m_ptr = nullptr; - } - - /* At shutdown, we need to ensure we've cleared the context of any -@@ -1565,7 +1577,7 @@ - m_gobj_finalized(false), - m_uses_toggle_ref(false) { - GTypeQuery query; -- type_query_dynamic_safe(&query); -+ g_type_query(gtype(), &query); - if (G_LIKELY(query.type)) - JS::AddAssociatedMemory(object, query.instance_size, - MemoryUse::GObjectInstanceStruct); -@@ -1668,12 +1680,12 @@ - g_object_weak_ref(gobj, wrapped_gobj_dispose_notify, this); - } - --bool ObjectInstance::ensure_uses_toggle_ref(JSContext* cx) { -+void ObjectInstance::ensure_uses_toggle_ref(JSContext* cx) { - if (m_uses_toggle_ref) -- return true; -+ return; - - if (!check_gobject_disposed_or_finalized("add toggle reference on")) -- return true; -+ return; - - debug_lifecycle("Switching object instance to toggle ref"); - -@@ -1698,8 +1710,6 @@ - * This may immediately remove the GC root we just added, since refcount - * may drop to 1. */ - g_object_unref(m_ptr); -- -- return true; - } - - static void invalidate_closure_vector(std::vector* closures, -@@ -1730,8 +1740,8 @@ - { - bool had_toggle_down, had_toggle_up; - -- auto locked_queue = ToggleQueue::get_default(); -- std::tie(had_toggle_down, had_toggle_up) = locked_queue->cancel(this); -+ std::tie(had_toggle_down, had_toggle_up) = -+ ToggleQueue::get_default()->cancel(this); - if (had_toggle_up && !had_toggle_down) { - g_error( - "JS object wrapper for GObject %p (%s) is being released while " -@@ -1766,20 +1776,30 @@ - name(), args.length())) - return false; - -+ GjsAutoTypeClass object_class(gtype()); - std::vector names; - AutoGValueVector values; - - if (args.length() > 0 && !args[0].isUndefined()) { - if (!args[0].isObject()) { - gjs_throw(context, -- "Argument to the constructor of %s should be an object " -- "with properties to set", -+ "Argument to the constructor of %s should be a plain JS " -+ "object with properties to set", - name()); - return false; - } - - JS::RootedObject props(context, &args[0].toObject()); -- if (!m_proto->props_to_g_parameters(context, props, &names, &values)) -+ if (ObjectInstance::typecheck(context, props, nullptr, G_TYPE_NONE, -+ GjsTypecheckNoThrow{})) { -+ gjs_throw(context, -+ "Argument to the constructor of %s should be a plain JS " -+ "object with properties to set", -+ name()); -+ return false; -+ } -+ if (!m_proto->props_to_g_parameters(context, object_class, props, -+ &names, &values)) - return false; - } - -@@ -1822,17 +1842,11 @@ - * */ - bool toggle_ref_added = false; - if (!m_uses_toggle_ref) { -- if (!other_priv->ensure_uses_toggle_ref(context)) { -- gjs_throw(context, -- "Impossible to set toggle references on %sobject %p", -- other_priv->m_gobj_disposed ? "disposed " : "", gobj); -- return false; -- } -- -+ other_priv->ensure_uses_toggle_ref(context); - toggle_ref_added = m_uses_toggle_ref; - } - -- args.rval().setObject(*other_priv->m_wrapper); -+ args.rval().setObject(*other_priv->m_wrapper.get()); - - if (toggle_ref_added) - g_clear_object(&gobj); /* We already own a reference */ -@@ -1897,7 +1911,6 @@ - } - - void ObjectPrototype::trace_impl(JSTracer* tracer) { -- m_property_cache.trace(tracer); - m_field_cache.trace(tracer); - m_unresolvable_cache.trace(tracer); - for (GClosure* closure : m_vfuncs) -@@ -1906,7 +1919,7 @@ - - void ObjectInstance::finalize_impl(JS::GCContext* gcx, JSObject* obj) { - GTypeQuery query; -- type_query_dynamic_safe(&query); -+ g_type_query(gtype(), &query); - if (G_LIKELY(query.type)) - JS::RemoveAssociatedMemory(obj, query.instance_size, - MemoryUse::GObjectInstanceStruct); -@@ -1978,15 +1991,18 @@ - GJS_DEC_COUNTER(object_prototype); - } - --JSObject* gjs_lookup_object_constructor_from_info(JSContext* context, -- GIObjectInfo* info, -- GType gtype) { -+static JSObject* gjs_lookup_object_constructor_from_info(JSContext* context, -+ GIBaseInfo* info, -+ GType gtype) { -+ g_return_val_if_fail( -+ !info || GI_IS_OBJECT_INFO(info) || GI_IS_INTERFACE_INFO(info), NULL); -+ - JS::RootedObject in_object(context); - const char *constructor_name; - - if (info) { -- in_object = gjs_lookup_namespace_object(context, (GIBaseInfo*) info); -- constructor_name = g_base_info_get_name((GIBaseInfo*) info); -+ in_object = gjs_lookup_namespace_object(context, info); -+ constructor_name = g_base_info_get_name(info); - } else { - in_object = gjs_lookup_private_namespace(context); - constructor_name = g_type_name(gtype); -@@ -2025,11 +2041,12 @@ - } - - GJS_JSAPI_RETURN_CONVENTION --static JSObject * --gjs_lookup_object_prototype_from_info(JSContext *context, -- GIObjectInfo *info, -- GType gtype) --{ -+static JSObject* gjs_lookup_object_prototype_from_info(JSContext* context, -+ GIBaseInfo* info, -+ GType gtype) { -+ g_return_val_if_fail( -+ !info || GI_IS_OBJECT_INFO(info) || GI_IS_INTERFACE_INFO(info), NULL); -+ - JS::RootedObject constructor(context, - gjs_lookup_object_constructor_from_info(context, info, gtype)); - -@@ -2050,7 +2067,7 @@ - gjs_lookup_object_prototype(JSContext *context, - GType gtype) - { -- GjsAutoObjectInfo info = g_irepository_find_by_gtype(nullptr, gtype); -+ GjsAutoObjectInfo info = gjs_lookup_gtype(nullptr, gtype); - return gjs_lookup_object_prototype_from_info(context, info, gtype); - } - -@@ -2100,13 +2117,8 @@ - } - - bool ObjectInstance::associate_closure(JSContext* cx, GClosure* closure) { -- if (!is_prototype()) { -- if (!to_instance()->ensure_uses_toggle_ref(cx)) { -- gjs_throw(cx, "Impossible to set toggle references on %sobject %p", -- m_gobj_disposed ? "disposed " : "", to_instance()->ptr()); -- return false; -- } -- } -+ if (!is_prototype()) -+ to_instance()->ensure_uses_toggle_ref(cx); - - g_assert(std::find(m_closures.begin(), m_closures.end(), closure) == - m_closures.end() && -@@ -2148,14 +2160,22 @@ - return priv->to_instance()->connect_impl(cx, args, true); - } - --bool --ObjectInstance::connect_impl(JSContext *context, -- const JS::CallArgs& args, -- bool after) --{ -+bool ObjectBase::connect_object(JSContext* cx, unsigned argc, JS::Value* vp) { -+ GJS_CHECK_WRAPPER_PRIV(cx, argc, vp, args, obj, ObjectBase, priv); -+ if (!priv->check_is_instance(cx, "connect to signals")) -+ return false; -+ -+ return priv->to_instance()->connect_impl(cx, args, false, true); -+} -+ -+bool ObjectInstance::connect_impl(JSContext* context, const JS::CallArgs& args, -+ bool after, bool object) { - gulong id; - guint signal_id; - GQuark signal_detail; -+ const char* func_name = object ? "connect_object" -+ : after ? "connect_after" -+ : "connect"; - - gjs_debug_gsignal("connect obj %p priv %p", m_wrapper.get(), this); - -@@ -2166,14 +2186,29 @@ - - JS::UniqueChars signal_name; - JS::RootedObject callback(context); -- if (!gjs_parse_call_args(context, after ? "connect_after" : "connect", args, "so", -- "signal name", &signal_name, -- "callback", &callback)) -- return false; -+ JS::RootedObject associate_obj(context); -+ GConnectFlags flags; -+ if (object) { -+ if (!gjs_parse_call_args(context, func_name, args, "sooi", -+ "signal name", &signal_name, "callback", -+ &callback, "gobject", &associate_obj, -+ "connect_flags", &flags)) -+ return false; - -- std::string dynamicString = format_name() + '.' + -- (after ? "connect_after" : "connect") + "('" + -- signal_name.get() + "')"; -+ if (flags & G_CONNECT_SWAPPED) { -+ gjs_throw(context, "Unsupported connect flag G_CONNECT_SWAPPED"); -+ return false; -+ } -+ -+ after = flags & G_CONNECT_AFTER; -+ } else { -+ if (!gjs_parse_call_args(context, func_name, args, "so", "signal name", -+ &signal_name, "callback", &callback)) -+ return false; -+ } -+ -+ std::string dynamicString = -+ format_name() + '.' + func_name + "('" + signal_name.get() + "')"; - AutoProfilerLabel label(context, "", dynamicString.c_str()); - - if (!JS::IsCallable(callback)) { -@@ -2192,8 +2227,17 @@ - context, callback, "signal callback", signal_id); - if (closure == NULL) - return false; -- if (!associate_closure(context, closure)) -+ -+ if (associate_obj.get() != nullptr) { -+ ObjectInstance* obj = ObjectInstance::for_js(context, associate_obj); -+ if (!obj) -+ return false; -+ -+ if (!obj->associate_closure(context, closure)) -+ return false; -+ } else if (!associate_closure(context, closure)) { - return false; -+ } - - id = g_signal_connect_closure_by_id(m_ptr, signal_id, signal_detail, - closure, after); -@@ -2255,6 +2299,7 @@ - - AutoGValueVector instance_and_args; - instance_and_args.reserve(signal_query.n_params + 1); -+ std::vector args_to_steal; - Gjs::AutoGValue& instance = instance_and_args.emplace_back(gtype()); - g_value_set_instance(&instance, m_ptr); - -@@ -2268,12 +2313,31 @@ - if (!gjs_value_to_g_value(context, argv[i + 1], &value)) - return false; - } -+ -+ if (!ObjectBase::info()) -+ continue; -+ -+ GjsAutoSignalInfo signal_info = g_object_info_find_signal( -+ ObjectBase::info(), signal_query.signal_name); -+ if (!signal_info) -+ continue; -+ -+ GjsAutoArgInfo arg_info = g_callable_info_get_arg(signal_info, i); -+ if (g_arg_info_get_ownership_transfer(arg_info) != -+ GI_TRANSFER_NOTHING) { -+ // FIXME(3v1n0): As it happens in many places in gjs, we can't track -+ // (yet) containers content, so in case of transfer container we -+ // can only leak. -+ args_to_steal.push_back(&value); -+ } - } - - if (signal_query.return_type == G_TYPE_NONE) { - g_signal_emitv(instance_and_args.data(), signal_id, signal_detail, - nullptr); - argv.rval().setUndefined(); -+ std::for_each(args_to_steal.begin(), args_to_steal.end(), -+ [](Gjs::AutoGValue* value) { value->steal(); }); - return true; - } - -@@ -2281,6 +2345,9 @@ - Gjs::AutoGValue rvalue(gtype); - g_signal_emitv(instance_and_args.data(), signal_id, signal_detail, &rvalue); - -+ std::for_each(args_to_steal.begin(), args_to_steal.end(), -+ [](Gjs::AutoGValue* value) { value->steal(); }); -+ - return gjs_value_from_g_value(context, argv.rval(), &rvalue); - } - -@@ -2555,6 +2622,7 @@ - JS_FN("_init", &ObjectBase::init_gobject, 0, 0), - JS_FN("connect", &ObjectBase::connect, 0, 0), - JS_FN("connect_after", &ObjectBase::connect_after, 0, 0), -+ JS_FN("connect_object", &ObjectBase::connect_object, 0, 0), - JS_FN("emit", &ObjectBase::emit, 0, 0), - JS_FS_END - }; -@@ -2682,7 +2750,8 @@ - - // Custom JS objects will most likely have visible state, so just do this - // from the start. -- if (!ensure_uses_toggle_ref(cx) || !m_uses_toggle_ref) { -+ ensure_uses_toggle_ref(cx); -+ if (!m_uses_toggle_ref) { - gjs_throw(cx, "Impossible to set toggle references on %sobject %p", - m_gobj_disposed ? "disposed " : "", gobj); - return false; -@@ -3058,7 +3127,7 @@ - { - JSObject *constructor; - -- GjsAutoObjectInfo object_info = g_irepository_find_by_gtype(nullptr, gtype); -+ GjsAutoObjectInfo object_info = gjs_lookup_gtype(nullptr, gtype); - - constructor = gjs_lookup_object_constructor_from_info(context, object_info, gtype); - -diff -ruN cjs-6.2.0-orig/gi/object.h cjs-6.2.0/gi/object.h ---- cjs-6.2.0-orig/gi/object.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/object.h 2024-10-14 18:41:39.000000000 +0200 -@@ -104,8 +104,6 @@ - [[nodiscard]] bool is_custom_js_class(); - - public: -- void type_query_dynamic_safe(GTypeQuery* query); -- - GJS_JSAPI_RETURN_CONVENTION - static bool typecheck(JSContext* cx, JS::HandleObject obj, - GIObjectInfo* expected_info, GType expected_gtype); -@@ -141,6 +139,8 @@ - GJS_JSAPI_RETURN_CONVENTION - static bool connect_after(JSContext* cx, unsigned argc, JS::Value* vp); - GJS_JSAPI_RETURN_CONVENTION -+ static bool connect_object(JSContext* cx, unsigned argc, JS::Value* vp); -+ GJS_JSAPI_RETURN_CONVENTION - static bool emit(JSContext* cx, unsigned argc, JS::Value* vp); - GJS_JSAPI_RETURN_CONVENTION - static bool signal_find(JSContext* cx, unsigned argc, JS::Value* vp); -@@ -185,16 +185,12 @@ - ObjectInstance>; - friend class GIWrapperBase; - -- using PropertyCache = -- JS::GCHashMap, GjsAutoParam, -- js::DefaultHasher, js::SystemAllocPolicy>; - using FieldCache = -- JS::GCHashMap, GjsAutoInfo, -+ JS::GCHashMap, GjsAutoFieldInfo, - js::DefaultHasher, js::SystemAllocPolicy>; - using NegativeLookupCache = - JS::GCHashSet, IdHasher, js::SystemAllocPolicy>; - -- PropertyCache m_property_cache; - FieldCache m_field_cache; - NegativeLookupCache m_unresolvable_cache; - // a list of vfunc GClosures installed on this prototype, used when tracing -@@ -224,8 +220,8 @@ - - GJS_JSAPI_RETURN_CONVENTION - bool lazy_define_gobject_property(JSContext* cx, JS::HandleObject obj, -- JS::HandleId id, bool* resolved, -- const char* name); -+ JS::HandleId id, GParamSpec*, -+ bool* resolved, const char* name); - - enum ResolveWhat { ConsiderOnlyMethods, ConsiderMethodsAndProperties }; - GJS_JSAPI_RETURN_CONVENTION -@@ -240,11 +236,15 @@ - void set_interfaces(GType* interface_gtypes, uint32_t n_interface_gtypes); - void set_type_qdata(void); - GJS_JSAPI_RETURN_CONVENTION -- GParamSpec* find_param_spec_from_id(JSContext* cx, JS::HandleString key); -+ GParamSpec* find_param_spec_from_id(JSContext*, -+ GjsAutoTypeClass const&, -+ JS::HandleString key); - GJS_JSAPI_RETURN_CONVENTION - GIFieldInfo* lookup_cached_field_info(JSContext* cx, JS::HandleString key); - GJS_JSAPI_RETURN_CONVENTION -- bool props_to_g_parameters(JSContext* cx, JS::HandleObject props, -+ bool props_to_g_parameters(JSContext*, -+ GjsAutoTypeClass const&, -+ JS::HandleObject props, - std::vector* names, - AutoGValueVector* values); - -@@ -293,7 +293,7 @@ - - // GIWrapperInstance::m_ptr may be null in ObjectInstance. - -- GjsMaybeOwned m_wrapper; -+ GjsMaybeOwned m_wrapper; - // a list of all GClosures installed on this object (from signal connections - // and scope-notify callbacks passed to methods), used when tracing - std::vector m_closures; -@@ -329,7 +329,7 @@ - [[nodiscard]] bool has_wrapper() const { return !!m_wrapper; } - - public: -- [[nodiscard]] JSObject* wrapper() const { return m_wrapper; } -+ [[nodiscard]] JSObject* wrapper() const { return m_wrapper.get(); } - - /* Methods to manipulate the JS object wrapper */ - -@@ -379,7 +379,7 @@ - void track_gobject_finalization(); - void ignore_gobject_finalization(); - void check_js_object_finalized(void); -- GJS_JSAPI_RETURN_CONVENTION bool ensure_uses_toggle_ref(JSContext* cx); -+ void ensure_uses_toggle_ref(JSContext*); - [[nodiscard]] bool check_gobject_disposed_or_finalized( - const char* for_what) const; - [[nodiscard]] bool check_gobject_finalized(const char* for_what) const; -@@ -430,14 +430,13 @@ - - private: - GJS_JSAPI_RETURN_CONVENTION -- bool prop_getter_impl(JSContext* cx, JS::HandleString name, -+ bool prop_getter_impl(JSContext* cx, GParamSpec*, - JS::MutableHandleValue rval); - GJS_JSAPI_RETURN_CONVENTION - bool field_getter_impl(JSContext* cx, JS::HandleString name, - JS::MutableHandleValue rval); - GJS_JSAPI_RETURN_CONVENTION -- bool prop_setter_impl(JSContext* cx, JS::HandleString name, -- JS::HandleValue value); -+ bool prop_setter_impl(JSContext* cx, GParamSpec*, JS::HandleValue value); - GJS_JSAPI_RETURN_CONVENTION - bool field_setter_not_impl(JSContext* cx, JS::HandleString name); - -@@ -451,7 +450,8 @@ - - private: - GJS_JSAPI_RETURN_CONVENTION -- bool connect_impl(JSContext* cx, const JS::CallArgs& args, bool after); -+ bool connect_impl(JSContext* cx, const JS::CallArgs& args, bool after, -+ bool object = false); - GJS_JSAPI_RETURN_CONVENTION - bool emit_impl(JSContext* cx, const JS::CallArgs& args); - GJS_JSAPI_RETURN_CONVENTION -@@ -483,10 +483,6 @@ - bool gjs_lookup_object_constructor(JSContext *context, - GType gtype, - JS::MutableHandleValue value_p); --GJS_JSAPI_RETURN_CONVENTION --JSObject* gjs_lookup_object_constructor_from_info(JSContext* cx, -- GIObjectInfo* info, -- GType gtype); - - void gjs_object_clear_toggles(void); - void gjs_object_shutdown_toggle_queue(void); -diff -ruN cjs-6.2.0-orig/gi/param.cpp cjs-6.2.0/gi/param.cpp ---- cjs-6.2.0-orig/gi/param.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/param.cpp 2024-10-14 18:41:39.000000000 +0200 -@@ -12,8 +12,10 @@ - #include - #include - #include // for JSEXN_TYPEERR --#include // for GetClass -+#include // for GetClass - #include -+#include // for JSPROP_READONLY -+#include // for JSPropertySpec, JS_PS_END, JS_STR... - #include - #include - #include // for UniqueChars -@@ -148,10 +150,24 @@ - nullptr, // mayResolve - param_finalize}; - -+static JSPropertySpec proto_props[] = { -+ JS_STRING_SYM_PS(toStringTag, "GObject_ParamSpec", JSPROP_READONLY), -+ JS_PS_END}; -+ -+static constexpr js::ClassSpec class_spec = { -+ nullptr, // createConstructor -+ nullptr, // createPrototype -+ nullptr, // constructorFunctions -+ nullptr, // constructorProperties -+ nullptr, // prototypeFunctions -+ proto_props, // prototypeProperties -+ nullptr // finishInit -+}; -+ - struct JSClass gjs_param_class = { - "GObject_ParamSpec", - JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE, -- &gjs_param_class_ops}; -+ &gjs_param_class_ops, &class_spec}; - - GJS_JSAPI_RETURN_CONVENTION - static JSObject* -@@ -187,10 +203,10 @@ - if (!gjs_init_class_dynamic( - context, in_object, nullptr, "GObject", "ParamSpec", - &gjs_param_class, gjs_param_constructor, 0, -- nullptr, // props of prototype -- nullptr, // funcs of prototype -- nullptr, // props of constructor, MyConstructor.myprop -- nullptr, // funcs of constructor -+ proto_props, // props of prototype -+ nullptr, // funcs of prototype -+ nullptr, // props of constructor, MyConstructor.myprop -+ nullptr, // funcs of constructor - &prototype, &constructor)) - return false; - -diff -ruN cjs-6.2.0-orig/gi/private.cpp cjs-6.2.0/gi/private.cpp ---- cjs-6.2.0-orig/gi/private.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/private.cpp 2024-10-14 18:41:39.000000000 +0200 -@@ -10,7 +10,8 @@ - #include - #include - --#include // for JS::GetArrayLength, -+#include // for JS::GetArrayLength -+#include // for IsCallable - #include - #include - #include -@@ -21,6 +22,7 @@ - #include - #include // for JS_NewPlainObject - -+#include "gi/closure.h" - #include "gi/gobject.h" - #include "gi/gtype.h" - #include "gi/interface.h" -@@ -28,6 +30,7 @@ - #include "gi/param.h" - #include "gi/private.h" - #include "gi/repo.h" -+#include "gi/value.h" - #include "cjs/atoms.h" - #include "cjs/context-private.h" - #include "cjs/jsapi-util-args.h" -@@ -344,10 +347,11 @@ - g_assert(parent_priv); - - GTypeQuery query; -- parent_priv->type_query_dynamic_safe(&query); -- if (G_UNLIKELY(query.type == 0)) { -- gjs_throw(cx, -- "Cannot inherit from a non-gjs dynamic type [bug 687184]"); -+ g_type_query(parent_priv->gtype(), &query); -+ -+ if (G_UNLIKELY( -+ g_type_test_flags(parent_priv->gtype(), G_TYPE_FLAG_FINAL))) { -+ gjs_throw(cx, "Cannot inherit from a final type"); - return false; - } - -@@ -554,6 +558,37 @@ - return true; - } - -+GJS_JSAPI_RETURN_CONVENTION -+static bool gjs_associate_closure(JSContext* context, unsigned argc, -+ JS::Value* vp) { -+ JS::CallArgs argv = JS::CallArgsFromVp(argc, vp); -+ JS::RootedObject func_obj(context); -+ JS::RootedObject target_obj(context); -+ Gjs::Closure::Ptr closure; -+ Gjs::AutoGValue value(G_TYPE_CLOSURE); -+ ObjectInstance* obj; -+ -+ if (!gjs_parse_call_args(context, "associateClosure", argv, "oo", "object", -+ &target_obj, "func", &func_obj)) -+ return false; -+ -+ g_assert(JS::IsCallable(func_obj) && -+ "associateClosure's function must be callable"); -+ -+ obj = ObjectInstance::for_js(context, target_obj); -+ if (!obj) -+ return false; -+ -+ closure = -+ Gjs::Closure::create_marshaled(context, func_obj, "wrapped", false); -+ -+ if (!obj->associate_closure(context, closure)) -+ return false; -+ -+ g_value_set_boxed(&value, closure); -+ return gjs_value_from_g_value(context, argv.rval(), &value); -+} -+ - static JSFunctionSpec private_module_funcs[] = { - JS_FN("override_property", gjs_override_property, 2, GJS_MODULE_PROP_FLAGS), - JS_FN("register_interface", gjs_register_interface, 3, -@@ -565,6 +600,7 @@ - GJS_MODULE_PROP_FLAGS), - JS_FN("signal_new", gjs_signal_new, 6, GJS_MODULE_PROP_FLAGS), - JS_FN("lookupConstructor", gjs_lookup_constructor, 1, 0), -+ JS_FN("associateClosure", gjs_associate_closure, 2, GJS_MODULE_PROP_FLAGS), - JS_FS_END, - }; - -diff -ruN cjs-6.2.0-orig/gi/repo.cpp cjs-6.2.0/gi/repo.cpp ---- cjs-6.2.0-orig/gi/repo.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/repo.cpp 2024-10-14 18:41:39.000000000 +0200 -@@ -106,6 +106,27 @@ - return false; - - GjsAutoError error; -+ // If resolving Gio, load the platform-specific typelib first, so that -+ // GioUnix/GioWin32 GTypes get looked up in there with higher priority, -+ // instead of in Gio. -+#if GLIB_CHECK_VERSION(2, 79, 2) && (defined(G_OS_UNIX) || defined(G_OS_WIN32)) -+ if (strcmp(ns_name.get(), "Gio") == 0) { -+# ifdef G_OS_UNIX -+ const char* platform = "Unix"; -+# else // G_OS_WIN32 -+ const char* platform = "Win32"; -+# endif // G_OS_UNIX/G_OS_WIN32 -+ GjsAutoChar platform_specific = -+ g_strconcat(ns_name.get(), platform, nullptr); -+ if (!g_irepository_require(nullptr, platform_specific, version.get(), -+ GIRepositoryLoadFlags(0), &error)) { -+ gjs_throw(context, "Failed to require %s %s: %s", -+ platform_specific.get(), version.get(), error->message); -+ return false; -+ } -+ } -+#endif // GLib >= 2.79.2 -+ - g_irepository_require(nullptr, ns_name.get(), version.get(), - GIRepositoryLoadFlags(0), &error); - if (error) { -@@ -122,12 +143,10 @@ - gjs_create_ns(context, ns_name.get())); - - JS::RootedValue override(context); -- if (!lookup_override_function(context, ns_id, &override)) -- return false; -- -- /* Define the property early, to avoid reentrancy issues if -- the override module looks for namespaces that import this */ -- if (!JS_DefinePropertyById(context, repo_obj, ns_id, gi_namespace, -+ if (!lookup_override_function(context, ns_id, &override) || -+ // Define the property early, to avoid reentrancy issues if the override -+ // module looks for namespaces that import this -+ !JS_DefinePropertyById(context, repo_obj, ns_id, gi_namespace, - GJS_MODULE_PROP_FLAGS)) - return false; - -@@ -216,14 +235,28 @@ - */ - JS::RootedString two_point_oh(context, JS_NewStringCopyZ(context, "2.0")); - if (!JS_DefinePropertyById(context, versions, atoms.glib(), two_point_oh, -+ JSPROP_PERMANENT) || -+ !JS_DefinePropertyById(context, versions, atoms.gobject(), two_point_oh, -+ JSPROP_PERMANENT) || -+ !JS_DefinePropertyById(context, versions, atoms.gio(), two_point_oh, - JSPROP_PERMANENT)) - return nullptr; -- if (!JS_DefinePropertyById(context, versions, atoms.gobject(), two_point_oh, -- JSPROP_PERMANENT)) -+ -+#if GLIB_CHECK_VERSION(2, 79, 2) -+# if defined(G_OS_UNIX) -+ if (!JS_DefineProperty(context, versions, "GLibUnix", two_point_oh, -+ JSPROP_PERMANENT) || -+ !JS_DefineProperty(context, versions, "GioUnix", two_point_oh, -+ JSPROP_PERMANENT)) - return nullptr; -- if (!JS_DefinePropertyById(context, versions, atoms.gio(), two_point_oh, -- JSPROP_PERMANENT)) -+# elif defined(G_OS_WIN32) -+ if (!JS_DefineProperty(context, versions, "GLibWin32", two_point_oh, -+ JSPROP_PERMANENT) || -+ !JS_DefineProperty(context, versions, "GioWin32", two_point_oh, -+ JSPROP_PERMANENT)) - return nullptr; -+# endif // G_OS_UNIX/G_OS_WIN32 -+#endif // GLib >= 2.79.2 - - JS::RootedObject private_ns(context, JS_NewPlainObject(context)); - if (!JS_DefinePropertyById(context, repo, atoms.private_ns_marker(), -@@ -249,7 +282,7 @@ - - GjsAutoTypeInfo type_info = g_constant_info_get_type(info); - -- bool ok = gjs_value_from_g_argument(cx, value, type_info, &garg, true); -+ bool ok = gjs_value_from_gi_argument(cx, value, type_info, &garg, true); - - g_constant_info_free_value(info, &garg); - return ok; -@@ -662,11 +695,9 @@ - gjs_lookup_generic_constructor(JSContext *context, - GIBaseInfo *info) - { -- const char *constructor_name; -- -- JS::RootedObject in_object(context, -- gjs_lookup_namespace_object(context, (GIBaseInfo*) info)); -- constructor_name = g_base_info_get_name((GIBaseInfo*) info); -+ JS::RootedObject in_object{context, -+ gjs_lookup_namespace_object(context, info)}; -+ const char* constructor_name = g_base_info_get_name(info); - - if (G_UNLIKELY (!in_object)) - return NULL; -@@ -717,3 +748,39 @@ - - return JS_NewObjectWithGivenProto(cx, JS::GetClass(proto), proto); - } -+ -+// Handle the case where g_irepository_find_by_gtype() returns a type in Gio -+// that should be in GioUnix or GioWin32. This may be an interface, class, or -+// boxed. This function only needs to be called if you are going to do something -+// with the GIBaseInfo that involves handing a JS object to the user. Otherwise, -+// use g_irepository_find_by_gtype() directly. -+GIBaseInfo* gjs_lookup_gtype(GIRepository* repo, GType gtype) { -+ GjsAutoBaseInfo retval = g_irepository_find_by_gtype(repo, gtype); -+ if (!retval) -+ return nullptr; -+ -+#if GLIB_CHECK_VERSION(2, 79, 2) && (defined(G_OS_UNIX) || defined(G_OS_WIN32)) -+# ifdef G_OS_UNIX -+ static const char* c_prefix = "GUnix"; -+ static const char* new_ns = "GioUnix"; -+# else // G_OS_WIN32 -+ static const char* c_prefix = "GWin32"; -+ static const char* new_ns = "GioWin32"; -+# endif -+ -+ const char* ns = g_base_info_get_namespace(retval); -+ if (strcmp(ns, "Gio") != 0) -+ return retval.release(); -+ -+ const char* gtype_name = g_type_name(gtype); -+ if (!g_str_has_prefix(gtype_name, c_prefix)) -+ return retval.release(); -+ -+ const char* new_name = gtype_name + strlen(c_prefix); -+ GIBaseInfo* new_info = g_irepository_find_by_name(repo, new_ns, new_name); -+ if (new_info) -+ return new_info; -+#endif // GLib >= 2.79.2 -+ -+ return retval.release(); -+} -diff -ruN cjs-6.2.0-orig/gi/repo.h cjs-6.2.0/gi/repo.h ---- cjs-6.2.0-orig/gi/repo.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/repo.h 2024-10-14 18:41:39.000000000 +0200 -@@ -8,6 +8,7 @@ - #include - - #include -+#include - - #include - -@@ -47,6 +48,8 @@ - - [[nodiscard]] char* gjs_hyphen_from_camel(const char* camel_name); - -+[[nodiscard]] GIBaseInfo* gjs_lookup_gtype(GIRepository*, GType); -+ - #if GJS_VERBOSE_ENABLE_GI_USAGE - void _gjs_log_info_usage(GIBaseInfo *info); - #endif -diff -ruN cjs-6.2.0-orig/gi/toggle.cpp cjs-6.2.0/gi/toggle.cpp ---- cjs-6.2.0-orig/gi/toggle.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/toggle.cpp 2024-09-16 22:32:54.000000000 +0200 -@@ -6,6 +6,8 @@ - // SPDX-FileContributor: Philip Chimento - // SPDX-FileContributor: Marco Trevisan - -+#include -+ - #include // for find_if - #include - #include -@@ -146,6 +148,8 @@ - } - - void ToggleQueue::enqueue(ObjectInstance* obj, ToggleQueue::Direction direction, -+ // https://trac.cppcheck.net/ticket/10733 -+ // cppcheck-suppress passedByValue - ToggleQueue::Handler handler) { - g_assert(owns_lock() && "Unsafe access to queue"); - -diff -ruN cjs-6.2.0-orig/gi/toggle.h cjs-6.2.0/gi/toggle.h ---- cjs-6.2.0-orig/gi/toggle.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/toggle.h 2024-09-16 22:32:54.000000000 +0200 -@@ -9,13 +9,15 @@ - #ifndef GI_TOGGLE_H_ - #define GI_TOGGLE_H_ - --#include // for gboolean -+#include - - #include - #include - #include - #include // for pair - -+#include // for gboolean -+ - class ObjectInstance; - namespace Gjs { - namespace Test { -diff -ruN cjs-6.2.0-orig/gi/utils-inl.h cjs-6.2.0/gi/utils-inl.h ---- cjs-6.2.0-orig/gi/utils-inl.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/utils-inl.h 2024-09-16 22:32:54.000000000 +0200 -@@ -8,6 +8,7 @@ - - #include - -+#include // IWYU pragma: keep (for find) - #include // IWYU pragma: keep (for swap) - #include - -diff -ruN cjs-6.2.0-orig/gi/value.cpp cjs-6.2.0/gi/value.cpp ---- cjs-6.2.0-orig/gi/value.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/value.cpp 2024-10-14 18:41:39.000000000 +0200 -@@ -20,6 +20,7 @@ - #include - #include - #include // for RootedVector -+#include // for RuntimeHeapIsCollecting - #include - #include - #include -@@ -28,7 +29,6 @@ - #include - #include - #include // for InformalValueTypeName, JS_Get... --#include // for JS_GetObjectFunction - - #include "gi/arg-inl.h" - #include "gi/arg.h" -@@ -41,6 +41,7 @@ - #include "gi/js-value-inl.h" - #include "gi/object.h" - #include "gi/param.h" -+#include "gi/repo.h" - #include "gi/union.h" - #include "gi/value.h" - #include "gi/wrapperutils.h" -@@ -54,10 +55,117 @@ - GJS_JSAPI_RETURN_CONVENTION - static bool gjs_value_from_g_value_internal(JSContext*, JS::MutableHandleValue, - const GValue*, bool no_copy = false, -- GjsAutoSignalInfo const& = nullptr, -- GjsAutoArgInfo const& = nullptr, -+ bool is_introspected_signal = false, -+ GIArgInfo* = nullptr, - GITypeInfo* = nullptr); - -+GJS_JSAPI_RETURN_CONVENTION -+static bool gjs_arg_set_from_gvalue(JSContext* cx, GIArgument* arg, -+ const GValue* value) { -+ switch (G_VALUE_TYPE(value)) { -+ case G_TYPE_CHAR: -+ gjs_arg_set(arg, g_value_get_schar(value)); -+ return true; -+ case G_TYPE_UCHAR: -+ gjs_arg_set(arg, g_value_get_uchar(value)); -+ return true; -+ case G_TYPE_BOOLEAN: -+ gjs_arg_set(arg, g_value_get_boolean(value)); -+ return true; -+ case G_TYPE_INT: -+ gjs_arg_set(arg, g_value_get_int(value)); -+ return true; -+ case G_TYPE_UINT: -+ gjs_arg_set(arg, g_value_get_uint(value)); -+ return true; -+ case G_TYPE_LONG: -+ gjs_arg_set( // NOLINT(runtime/int) -+ arg, g_value_get_long(value)); -+ return true; -+ case G_TYPE_ULONG: -+ gjs_arg_set(arg, g_value_get_ulong(value)); -+ return true; -+ case G_TYPE_INT64: -+ gjs_arg_set(arg, int64_t{g_value_get_int64(value)}); -+ return true; -+ case G_TYPE_UINT64: -+ gjs_arg_set(arg, uint64_t{g_value_get_uint64(value)}); -+ return true; -+ case G_TYPE_FLOAT: -+ gjs_arg_set(arg, g_value_get_float(value)); -+ return true; -+ case G_TYPE_DOUBLE: -+ gjs_arg_set(arg, g_value_get_double(value)); -+ return true; -+ case G_TYPE_STRING: -+ gjs_arg_set(arg, g_value_get_string(value)); -+ return true; -+ case G_TYPE_POINTER: -+ gjs_arg_set(arg, g_value_get_pointer(value)); -+ return true; -+ case G_TYPE_VARIANT: -+ gjs_arg_set(arg, g_value_get_variant(value)); -+ return true; -+ default: { -+ if (g_value_fits_pointer(value)) { -+ gjs_arg_set(arg, g_value_peek_pointer(value)); -+ return true; -+ } -+ -+ GType gtype = G_VALUE_TYPE(value); -+ -+ if (g_type_is_a(gtype, G_TYPE_FLAGS)) { -+ gjs_arg_set(arg, g_value_get_flags(value)); -+ return true; -+ } -+ -+ if (g_type_is_a(gtype, G_TYPE_ENUM)) { -+ gjs_arg_set(arg, g_value_get_enum(value)); -+ return true; -+ } -+ -+ if (g_type_is_a(gtype, G_TYPE_GTYPE)) { -+ gjs_arg_set(arg, -+ g_value_get_gtype(value)); -+ return true; -+ } -+ -+ if (g_type_is_a(gtype, G_TYPE_PARAM)) { -+ gjs_arg_set(arg, g_value_get_param(value)); -+ return true; -+ } -+ } -+ } -+ -+ gjs_throw(cx, "No know GArgument conversion for %s", -+ G_VALUE_TYPE_NAME(value)); -+ return false; -+} -+ -+GJS_JSAPI_RETURN_CONVENTION -+static bool maybe_release_signal_value(JSContext* cx, -+ GjsAutoArgInfo const& arg_info, -+ GITypeInfo* type_info, -+ const GValue* gvalue, -+ GITransfer transfer) { -+ if (transfer == GI_TRANSFER_NOTHING) -+ return true; -+ -+ GIArgument arg; -+ if (!gjs_arg_set_from_gvalue(cx, &arg, gvalue)) -+ return false; -+ -+ if (!gjs_gi_argument_release(cx, transfer, type_info, -+ GjsArgumentFlags::ARG_OUT, &arg)) { -+ gjs_throw(cx, "Cannot release argument %s value, we're gonna leak!", -+ arg_info.name()); -+ return false; -+ } -+ -+ return true; -+} -+ - /* - * Gets signal introspection info about closure, or NULL if not found. Currently - * only works for signals on introspected GObjects, not signals on GJS-defined -@@ -65,8 +173,6 @@ - */ - [[nodiscard]] static GjsAutoSignalInfo get_signal_info_if_available( - GSignalQuery* signal_query) { -- GIInfoType info_type; -- - if (!signal_query->itype) - return nullptr; - -@@ -75,7 +181,7 @@ - if (!obj) - return nullptr; - -- info_type = g_base_info_get_type (obj); -+ GIInfoType info_type = obj.type(); - if (info_type == GI_INFO_TYPE_OBJECT) - return g_object_info_find_signal(obj, signal_query->signal_name); - else if (info_type == GI_INFO_TYPE_INTERFACE) -@@ -90,22 +196,22 @@ - */ - GJS_JSAPI_RETURN_CONVENTION - static bool gjs_value_from_array_and_length_values( -- JSContext* context, GjsAutoSignalInfo const& signal_info, -- JS::MutableHandleValue value_p, GITypeInfo* array_type_info, -- const GValue* array_value, GjsAutoArgInfo const& array_length_arg_info, -- GITypeInfo* array_length_type_info, const GValue* array_length_value, -- bool no_copy) { -+ JSContext* context, JS::MutableHandleValue value_p, -+ GITypeInfo* array_type_info, const GValue* array_value, -+ GIArgInfo* array_length_arg_info, GITypeInfo* array_length_type_info, -+ const GValue* array_length_value, bool no_copy, -+ bool is_introspected_signal) { - JS::RootedValue array_length(context); -- GArgument array_arg; - - g_assert(G_VALUE_HOLDS_POINTER(array_value)); - g_assert(G_VALUE_HOLDS_INT(array_length_value)); - - if (!gjs_value_from_g_value_internal( -- context, &array_length, array_length_value, no_copy, signal_info, -+ context, &array_length, array_length_value, no_copy, is_introspected_signal, - array_length_arg_info, array_length_type_info)) - return false; - -+ GIArgument array_arg; - gjs_arg_set(&array_arg, g_value_get_pointer(array_value)); - - return gjs_value_from_explicit_array( -@@ -131,7 +237,7 @@ - - context = m_cx; - GjsContextPrivate* gjs = GjsContextPrivate::from_cx(context); -- if (G_UNLIKELY(gjs->sweeping())) { -+ if (JS::RuntimeHeapIsCollecting()) { - GSignalInvocationHint *hint = (GSignalInvocationHint*) invocation_hint; - std::ostringstream message; - -@@ -189,6 +295,7 @@ - GjsAutoArgInfo arg_info; - }; - std::vector args_details(n_param_values); -+ bool needs_cleanup = false; - - GjsAutoSignalInfo signal_info = get_signal_info_if_available(&signal_query); - if (signal_info) { -@@ -206,6 +313,11 @@ - args_details[array_len_pos + 1].skip = true; - arg_details.array_len_index_for = array_len_pos + 1; - } -+ -+ if (!needs_cleanup && -+ g_arg_info_get_ownership_transfer(arg_details.arg_info) != -+ GI_TRANSFER_NOTHING) -+ needs_cleanup = true; - } - } - -@@ -214,6 +326,7 @@ - if (!argv.reserve(n_param_values)) - g_error("Unable to reserve space"); - JS::RootedValue argv_to_append(context); -+ bool is_introspected_signal = !!signal_info; - for (i = 0; i < n_param_values; ++i) { - const GValue* gval = ¶m_values[i]; - ArgumentDetails& arg_details = args_details[i]; -@@ -235,12 +348,12 @@ - ArgumentDetails& array_len_details = - args_details[arg_details.array_len_index_for]; - res = gjs_value_from_array_and_length_values( -- context, signal_info, &argv_to_append, &arg_details.type_info, -- gval, array_len_details.arg_info, &array_len_details.type_info, -- array_len_gval, no_copy); -+ context, &argv_to_append, &arg_details.type_info, gval, -+ array_len_details.arg_info, &array_len_details.type_info, -+ array_len_gval, no_copy, is_introspected_signal); - } else { - res = gjs_value_from_g_value_internal( -- context, &argv_to_append, gval, no_copy, signal_info, -+ context, &argv_to_append, gval, no_copy, is_introspected_signal, - arg_details.arg_info, &arg_details.type_info); - } - -@@ -268,12 +381,29 @@ - gjs->exit_immediately(code); - - // Some other uncatchable exception, e.g. out of memory -- JSFunction* fn = JS_GetObjectFunction(callable()); -- std::string descr = -- fn ? "function " + gjs_debug_string(JS_GetFunctionDisplayId(fn)) -- : "callable object " + gjs_debug_object(callable()); - g_error("Call to %s terminated with uncatchable exception", -- descr.c_str()); -+ gjs_debug_callable(callable()).c_str()); -+ } -+ } -+ -+ if (needs_cleanup) { -+ for (i = 0; i < n_param_values; ++i) { -+ ArgumentDetails& arg_details = args_details[i]; -+ if (!arg_details.arg_info) -+ continue; -+ -+ GITransfer transfer = -+ g_arg_info_get_ownership_transfer(arg_details.arg_info); -+ -+ if (transfer == GI_TRANSFER_NOTHING) -+ continue; -+ -+ if (!maybe_release_signal_value(context, arg_details.arg_info, -+ &arg_details.type_info, -+ ¶m_values[i], transfer)) { -+ gjs_log_exception(context); -+ return; -+ } - } - } - -@@ -635,13 +765,14 @@ - /* We don't necessarily have the typelib loaded when - we first see the structure... */ - if (registered) { -- GIInfoType info_type = g_base_info_get_type (registered); -+ GIInfoType info_type = registered.type(); - - if (info_type == GI_INFO_TYPE_STRUCT && -- g_struct_info_is_foreign ((GIStructInfo*)registered)) { -- GArgument arg; -+ g_struct_info_is_foreign( -+ registered.as())) { -+ GIArgument arg; - -- if (!gjs_struct_foreign_convert_to_g_argument( -+ if (!gjs_struct_foreign_convert_to_gi_argument( - context, value, registered, nullptr, - GJS_ARGUMENT_ARGUMENT, GI_TRANSFER_NOTHING, - GjsArgumentFlags::MAY_BE_NULL, &arg)) -@@ -847,10 +978,12 @@ - } - - GJS_JSAPI_RETURN_CONVENTION --static bool gjs_value_from_g_value_internal( -- JSContext* context, JS::MutableHandleValue value_p, const GValue* gvalue, -- bool no_copy, GjsAutoSignalInfo const& signal_info, -- GjsAutoArgInfo const& arg_info, GITypeInfo* type_info) { -+static bool gjs_value_from_g_value_internal(JSContext* context, -+ JS::MutableHandleValue value_p, -+ const GValue* gvalue, bool no_copy, -+ bool is_introspected_signal, -+ GIArgInfo* arg_info, -+ GITypeInfo* type_info) { - GType gtype; - - gtype = G_VALUE_TYPE(gvalue); -@@ -893,11 +1026,11 @@ - } else if (gtype == G_TYPE_DOUBLE) { - double d; - d = g_value_get_double(gvalue); -- value_p.setNumber(d); -+ value_p.setNumber(JS::CanonicalizeNaN(d)); - } else if (gtype == G_TYPE_FLOAT) { - double d; - d = g_value_get_float(gvalue); -- value_p.setNumber(d); -+ value_p.setNumber(JS::CanonicalizeNaN(d)); - } else if (gtype == G_TYPE_BOOLEAN) { - bool v; - v = g_value_get_boolean(gvalue); -@@ -928,15 +1061,15 @@ - return true; - } - -- if (!signal_info || !arg_info) { -+ if (!is_introspected_signal || !arg_info) { - gjs_throw(context, "Unknown signal"); - return false; - } - -+ GITransfer transfer = g_arg_info_get_ownership_transfer(arg_info); - GjsAutoTypeInfo element_info = g_type_info_get_param_type(type_info, 0); -- if (!gjs_array_from_g_value_array( -- context, value_p, element_info, -- g_arg_info_get_ownership_transfer(arg_info), gvalue)) { -+ if (!gjs_array_from_g_value_array(context, value_p, element_info, -+ transfer, gvalue)) { - gjs_throw(context, "Failed to convert array"); - return false; - } -@@ -992,7 +1125,7 @@ - - /* The only way to differentiate unions and structs is from - * their g-i info as both GBoxed */ -- GjsAutoBaseInfo info = g_irepository_find_by_gtype(nullptr, gtype); -+ GjsAutoBaseInfo info = gjs_lookup_gtype(nullptr, gtype); - if (!info) { - gjs_throw(context, - "No introspection information found for %s", -@@ -1004,8 +1137,8 @@ - g_struct_info_is_foreign(info)) { - GIArgument arg; - gjs_arg_set(&arg, gboxed); -- return gjs_struct_foreign_convert_from_g_argument(context, value_p, -- info, &arg); -+ return gjs_struct_foreign_convert_from_gi_argument(context, value_p, -+ info, &arg); - } - - GIInfoType type = info.type(); -@@ -1034,9 +1167,7 @@ - - obj = gjs_param_from_g_param(context, gparam); - value_p.setObjectOrNull(obj); -- } else if (signal_info && g_type_is_a(gtype, G_TYPE_POINTER)) { -- GArgument arg; -- -+ } else if (is_introspected_signal && g_type_is_a(gtype, G_TYPE_POINTER)) { - if (!arg_info) { - gjs_throw(context, "Unknown signal."); - return false; -@@ -1046,10 +1177,11 @@ - " calling gjs_value_from_g_value_internal()", - g_type_info_get_array_length(type_info) == -1)); - -+ GIArgument arg; - gjs_arg_set(&arg, g_value_get_pointer(gvalue)); - -- return gjs_value_from_g_argument(context, value_p, type_info, &arg, -- true); -+ return gjs_value_from_gi_argument(context, value_p, type_info, &arg, -+ true); - } else if (gtype == G_TYPE_GTYPE) { - GType gvalue_gtype = g_value_get_gtype(gvalue); - -diff -ruN cjs-6.2.0-orig/gi/value.h cjs-6.2.0/gi/value.h ---- cjs-6.2.0-orig/gi/value.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/value.h 2024-10-14 18:41:39.000000000 +0200 -@@ -51,11 +51,12 @@ - break; - default: - // We can't safely move in complex cases, so let's just copy -- *static_cast(this) = G_VALUE_INIT; -+ this->steal(); - *this = src; - g_value_unset(&src); - } - } -+ void steal() { *static_cast(this) = G_VALUE_INIT; } - ~AutoGValue() { g_value_unset(this); } - }; - } // namespace Gjs -diff -ruN cjs-6.2.0-orig/gi/wrapperutils.h cjs-6.2.0/gi/wrapperutils.h ---- cjs-6.2.0-orig/gi/wrapperutils.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/gi/wrapperutils.h 2024-10-14 18:41:39.000000000 +0200 -@@ -20,6 +20,7 @@ - #include - #include - #include // for JSEXN_TYPEERR -+#include // for MutableHandleIdVector - #include - #include - #include -@@ -33,7 +34,7 @@ - #include "gi/cwrapper.h" - #include "cjs/atoms.h" - #include "cjs/context-private.h" --#include "cjs/jsapi-class.h" // IWYU pragma: keep -+#include "cjs/jsapi-class.h" - #include "cjs/jsapi-util.h" - #include "cjs/macros.h" - #include "cjs/profiler-private.h" -diff -ruN cjs-6.2.0-orig/libgjs-private/gjs-gdbus-wrapper.c cjs-6.2.0/libgjs-private/gjs-gdbus-wrapper.c ---- cjs-6.2.0-orig/libgjs-private/gjs-gdbus-wrapper.c 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/libgjs-private/gjs-gdbus-wrapper.c 2024-09-16 22:32:54.000000000 +0200 -@@ -4,6 +4,8 @@ - * SPDX-FileCopyrightText: 2011 Giovanni Campagna - */ - -+#include -+ - #include // for strcmp - - #include -diff -ruN cjs-6.2.0-orig/libgjs-private/gjs-match-info.c cjs-6.2.0/libgjs-private/gjs-match-info.c ---- cjs-6.2.0-orig/libgjs-private/gjs-match-info.c 1970-01-01 01:00:00.000000000 +0100 -+++ cjs-6.2.0/libgjs-private/gjs-match-info.c 2024-09-16 22:32:54.000000000 +0200 -@@ -0,0 +1,357 @@ -+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -+/* -+ * SPDX-License-Identifier: MIT OR LGPL-2.0-or-later -+ * SPDX-FileCopyrightText: 2023 Philip Chimento -+ */ -+ -+#include -+ -+#include -+#include /* for NULL */ -+#include -+#include /* for ssize_t */ -+ -+#include -+#include -+ -+#include "libgjs-private/gjs-match-info.h" -+ -+G_DEFINE_BOXED_TYPE(GjsMatchInfo, gjs_match_info, gjs_match_info_ref, -+ gjs_match_info_unref) -+ -+struct _GjsMatchInfo { -+ gatomicrefcount refcount; -+ GMatchInfo* base; /* owned */ -+ char* str; -+}; -+ -+/* Takes ownership of string */ -+static GjsMatchInfo* new_match_info(GMatchInfo* base, char* s) { -+ GjsMatchInfo* retval = g_new0(GjsMatchInfo, 1); -+ g_atomic_ref_count_init(&retval->refcount); -+ retval->base = base; -+ retval->str = s; -+ return retval; -+} -+ -+/** -+ * gjs_match_info_get_regex: -+ * @self: a #GjsMatchInfo -+ * -+ * Wrapper for g_match_info_get_regex(). -+ * -+ * Returns: (transfer none): #GRegex object -+ */ -+GRegex* gjs_match_info_get_regex(const GjsMatchInfo* self) { -+ g_return_val_if_fail(self != NULL, NULL); -+ return g_match_info_get_regex(self->base); -+} -+ -+/** -+ * gjs_match_info_get_string: -+ * @self: a #GjsMatchInfo -+ * -+ * Replacement for g_match_info_get_string(), but the string is owned by @self. -+ * -+ * Returns: (transfer none): the string searched with @match_info -+ */ -+const char* gjs_match_info_get_string(const GjsMatchInfo* self) { -+ g_return_val_if_fail(self != NULL, NULL); -+ return self->str; -+} -+ -+/** -+ * gjs_match_info_ref: -+ * @self: a #GjsMatchInfo -+ * -+ * Replacement for g_match_info_ref(). -+ * -+ * Returns: @self -+ */ -+GjsMatchInfo* gjs_match_info_ref(GjsMatchInfo* self) { -+ g_return_val_if_fail(self != NULL, NULL); -+ g_atomic_ref_count_inc(&self->refcount); -+ return self; -+} -+ -+/** -+ * gjs_match_info_unref: -+ * @self: a #GjsMatchInfo -+ * -+ * Replacement for g_match_info_unref(). -+ */ -+void gjs_match_info_unref(GjsMatchInfo* self) { -+ g_return_if_fail(self != NULL); -+ if (g_atomic_ref_count_dec(&self->refcount)) { -+ g_match_info_unref(self->base); -+ g_free(self->str); -+ g_free(self); -+ } -+} -+ -+/** -+ * gjs_match_info_free: -+ * @self: (nullable): a #GjsMatchInfo, or %NULL -+ * -+ * Replacement for g_match_info_free(). -+ */ -+void gjs_match_info_free(GjsMatchInfo* self) { -+ g_return_if_fail(self != NULL); -+ if (self == NULL) -+ return; -+ -+ gjs_match_info_unref(self); -+} -+ -+/** -+ * gjs_match_info_next: -+ * @self: a #GjsMatchInfo -+ * @error: location to store the error occurring, or %NULL to ignore errors -+ * -+ * Wrapper for g_match_info_next(). -+ * -+ * Returns: %TRUE or %FALSE -+ */ -+gboolean gjs_match_info_next(GjsMatchInfo* self, GError** error) { -+ g_return_val_if_fail(self != NULL, FALSE); -+ return g_match_info_next(self->base, error); -+} -+ -+/** -+ * gjs_match_info_matches: -+ * @self: a #GjsMatchInfo -+ * -+ * Wrapper for g_match_info_matches(). -+ * -+ * Returns: %TRUE or %FALSE -+ */ -+gboolean gjs_match_info_matches(const GjsMatchInfo* self) { -+ g_return_val_if_fail(self != NULL, FALSE); -+ return g_match_info_matches(self->base); -+} -+ -+/** -+ * gjs_match_info_get_match_count: -+ * @self: a #GjsMatchInfo -+ * -+ * Wrapper for g_match_info_get_match_count(). -+ * -+ * Returns: Number of matched substrings, or -1 if an error occurred -+ */ -+int gjs_match_info_get_match_count(const GjsMatchInfo* self) { -+ g_return_val_if_fail(self != NULL, -1); -+ return g_match_info_get_match_count(self->base); -+} -+ -+/** -+ * gjs_match_info_is_partial_match: -+ * @self: a #GjsMatchInfo -+ * -+ * Wrapper for g_match_info_is_partial_match(). -+ * -+ * Returns: %TRUE or %FALSE -+ */ -+gboolean gjs_match_info_is_partial_match(const GjsMatchInfo* self) { -+ g_return_val_if_fail(self != NULL, FALSE); -+ return g_match_info_is_partial_match(self->base); -+} -+ -+/** -+ * gjs_match_info_expand_references: -+ * @self: (nullable): a #GjsMatchInfo or %NULL -+ * @string_to_expand: the string to expand -+ * @error: location to store the error occurring, or %NULL to ignore errors -+ * -+ * Wrapper for g_match_info_expand_references(). -+ * -+ * Returns: (nullable): the expanded string, or %NULL if an error occurred -+ */ -+char* gjs_match_info_expand_references(const GjsMatchInfo* self, -+ const char* string_to_expand, -+ GError** error) { -+ return g_match_info_expand_references(self->base, string_to_expand, error); -+} -+ -+/** -+ * gjs_match_info_fetch: -+ * @self: a #GjsMatchInfo -+ * @match_num: number of the sub expression -+ * -+ * Wrapper for g_match_info_fetch(). -+ * -+ * Returns: (nullable): The matched substring, or %NULL if an error occurred. -+ */ -+char* gjs_match_info_fetch(const GjsMatchInfo* self, int match_num) { -+ g_return_val_if_fail(self != NULL, NULL); -+ return g_match_info_fetch(self->base, match_num); -+} -+ -+/** -+ * gjs_match_info_fetch_pos: -+ * @self: a #GMatchInfo -+ * @match_num: number of the sub expression -+ * @start_pos: (out) (optional): pointer to location for the start position -+ * @end_pos: (out) (optional): pointer to location for the end position -+ * -+ * Wrapper for g_match_info_fetch_pos(). -+ * -+ * Returns: %TRUE or %FALSE -+ */ -+gboolean gjs_match_info_fetch_pos(const GjsMatchInfo* self, int match_num, -+ int* start_pos, int* end_pos) { -+ g_return_val_if_fail(self != NULL, FALSE); -+ return g_match_info_fetch_pos(self->base, match_num, start_pos, end_pos); -+} -+ -+/** -+ * gjs_match_info_fetch_named: -+ * @self: a #GjsMatchInfo -+ * @name: name of the subexpression -+ * -+ * Wrapper for g_match_info_fetch_named(). -+ * -+ * Returns: (nullable): The matched substring, or %NULL if an error occurred. -+ */ -+char* gjs_match_info_fetch_named(const GjsMatchInfo* self, const char* name) { -+ g_return_val_if_fail(self != NULL, NULL); -+ return g_match_info_fetch_named(self->base, name); -+} -+ -+/** -+ * gjs_match_info_fetch_named_pos: -+ * @self: a #GMatchInfo -+ * @name: name of the subexpression -+ * @start_pos: (out) (optional): pointer to location for the start position -+ * @end_pos: (out) (optional): pointer to location for the end position -+ * -+ * Wrapper for g_match_info_fetch_named_pos(). -+ * -+ * Returns: %TRUE or %FALSE -+ */ -+gboolean gjs_match_info_fetch_named_pos(const GjsMatchInfo* self, -+ const char* name, int* start_pos, -+ int* end_pos) { -+ g_return_val_if_fail(self != NULL, FALSE); -+ return g_match_info_fetch_named_pos(self->base, name, start_pos, end_pos); -+} -+ -+/** -+ * gjs_match_info_fetch_all: -+ * @self: a #GMatchInfo -+ * -+ * Wrapper for g_match_info_fetch_all(). -+ * -+ * Returns: (transfer full): a %NULL-terminated array of strings. If the -+ * previous match failed %NULL is returned -+ */ -+char** gjs_match_info_fetch_all(const GjsMatchInfo* self) { -+ g_return_val_if_fail(self != NULL, NULL); -+ return g_match_info_fetch_all(self->base); -+} -+ -+/** -+ * gjs_regex_match: -+ * @regex: a #GRegex -+ * @s: the string to scan for matches -+ * @match_options: match options -+ * @match_info: (out) (optional): pointer to location for the #GjsMatchInfo -+ * -+ * Wrapper for g_regex_match() that doesn't require the string to be kept alive. -+ * -+ * Returns: %TRUE or %FALSE -+ */ -+gboolean gjs_regex_match(const GRegex* regex, const char* s, -+ GRegexMatchFlags match_options, -+ GjsMatchInfo** match_info) { -+ return gjs_regex_match_full(regex, (const uint8_t*)s, -1, 0, match_options, -+ match_info, NULL); -+} -+ -+/** -+ * gjs_regex_match_full: -+ * @regex: a #GRegex -+ * @bytes: (array length=len): the string to scan for matches -+ * @len: the length of @bytes -+ * @start_position: starting index of the string to match, in bytes -+ * @match_options: match options -+ * @match_info: (out) (optional): pointer to location for the #GjsMatchInfo -+ * @error: location to store the error occurring, or %NULL to ignore errors -+ * -+ * Wrapper for g_regex_match_full() that doesn't require the string to be kept -+ * alive. -+ * -+ * Returns: %TRUE or %FALSE -+ */ -+gboolean gjs_regex_match_full(const GRegex* regex, const uint8_t* bytes, -+ ssize_t len, int start_position, -+ GRegexMatchFlags match_options, -+ GjsMatchInfo** match_info, GError** error) { -+ const char* s = (const char*)bytes; -+ if (match_info == NULL) -+ return g_regex_match_full(regex, s, len, start_position, match_options, -+ NULL, error); -+ -+ char* string_copy = len < 0 ? g_strdup(s) : g_strndup(s, len); -+ GMatchInfo* base = NULL; -+ bool retval = g_regex_match_full(regex, string_copy, len, start_position, -+ match_options, &base, error); -+ -+ if (base) -+ *match_info = new_match_info(base, string_copy); -+ -+ return retval; -+} -+ -+/** -+ * gjs_regex_match_all: -+ * @regex: a #GRegex -+ * @s: the string to scan for matches -+ * @match_options: match options -+ * @match_info: (out) (optional): pointer to location for the #GjsMatchInfo -+ * -+ * Wrapper for g_regex_match_all() that doesn't require the string to be kept -+ * alive. -+ * -+ * Returns: %TRUE or %FALSE -+ */ -+gboolean gjs_regex_match_all(const GRegex* regex, const char* s, -+ GRegexMatchFlags match_options, -+ GjsMatchInfo** match_info) { -+ return gjs_regex_match_all_full(regex, (const uint8_t*)s, -1, 0, -+ match_options, match_info, NULL); -+} -+ -+/** -+ * gjs_regex_match_all_full: -+ * @regex: a #GRegex -+ * @bytes: (array length=len): the string to scan for matches -+ * @len: the length of @bytes -+ * @start_position: starting index of the string to match, in bytes -+ * @match_options: match options -+ * @match_info: (out) (optional): pointer to location for the #GMatchInfo -+ * @error: location to store the error occurring, or %NULL to ignore errors -+ * -+ * Wrapper for g_regex_match_all_full() that doesn't require the string to be -+ * kept alive. -+ * -+ * Returns: %TRUE or %FALSE -+ */ -+gboolean gjs_regex_match_all_full(const GRegex* regex, const uint8_t* bytes, -+ ssize_t len, int start_position, -+ GRegexMatchFlags match_options, -+ GjsMatchInfo** match_info, GError** error) { -+ const char* s = (const char*)bytes; -+ if (match_info == NULL) -+ return g_regex_match_all_full(regex, s, len, start_position, -+ match_options, NULL, error); -+ -+ char* string_copy = len < 0 ? g_strdup(s) : g_strndup(s, len); -+ GMatchInfo* base = NULL; -+ bool retval = g_regex_match_all_full( -+ regex, string_copy, len, start_position, match_options, &base, error); -+ -+ if (base) -+ *match_info = new_match_info(base, string_copy); -+ -+ return retval; -+} -diff -ruN cjs-6.2.0-orig/libgjs-private/gjs-match-info.h cjs-6.2.0/libgjs-private/gjs-match-info.h ---- cjs-6.2.0-orig/libgjs-private/gjs-match-info.h 1970-01-01 01:00:00.000000000 +0100 -+++ cjs-6.2.0/libgjs-private/gjs-match-info.h 2024-10-14 19:19:28.806368787 +0200 -@@ -0,0 +1,93 @@ -+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -+/* -+ * SPDX-License-Identifier: MIT OR LGPL-2.0-or-later -+ * SPDX-FileCopyrightText: 2023 Philip Chimento -+ */ -+ -+#pragma once -+ -+#include -+#include /* for ssize_t */ -+ -+#include -+#include -+ -+#include "cjs/macros.h" -+ -+G_BEGIN_DECLS -+ -+/** -+ * GjsMatchInfo: -+ * -+ * A GjsMatchInfo is an opaque struct used to return information about -+ * matches. -+ */ -+typedef struct _GjsMatchInfo GjsMatchInfo; -+ -+/** -+ * GJS_TYPE_MATCH_INFO: -+ * -+ * The #GType for a boxed type holding a #GjsMatchInfo reference. -+ */ -+#define GJS_TYPE_MATCH_INFO (gjs_match_info_get_type()) -+ -+GJS_EXPORT -+GType gjs_match_info_get_type(void) G_GNUC_CONST; -+ -+GJS_EXPORT -+GRegex* gjs_match_info_get_regex(const GjsMatchInfo* self); -+GJS_EXPORT -+const char* gjs_match_info_get_string(const GjsMatchInfo* self); -+ -+GJS_EXPORT -+GjsMatchInfo* gjs_match_info_ref(GjsMatchInfo* self); -+GJS_EXPORT -+void gjs_match_info_unref(GjsMatchInfo* self); -+GJS_EXPORT -+void gjs_match_info_free(GjsMatchInfo* self); -+GJS_EXPORT -+gboolean gjs_match_info_next(GjsMatchInfo* self, GError** error); -+GJS_EXPORT -+gboolean gjs_match_info_matches(const GjsMatchInfo* self); -+GJS_EXPORT -+int gjs_match_info_get_match_count(const GjsMatchInfo* self); -+GJS_EXPORT -+gboolean gjs_match_info_is_partial_match(const GjsMatchInfo* self); -+GJS_EXPORT -+char* gjs_match_info_expand_references(const GjsMatchInfo* self, -+ const char* string_to_expand, -+ GError** error); -+GJS_EXPORT -+char* gjs_match_info_fetch(const GjsMatchInfo* self, int match_num); -+GJS_EXPORT -+gboolean gjs_match_info_fetch_pos(const GjsMatchInfo* self, int match_num, -+ int* start_pos, int* end_pos); -+GJS_EXPORT -+char* gjs_match_info_fetch_named(const GjsMatchInfo* self, const char* name); -+GJS_EXPORT -+gboolean gjs_match_info_fetch_named_pos(const GjsMatchInfo* self, -+ const char* name, int* start_pos, -+ int* end_pos); -+GJS_EXPORT -+char** gjs_match_info_fetch_all(const GjsMatchInfo* self); -+ -+GJS_EXPORT -+gboolean gjs_regex_match(const GRegex* regex, const char* s, -+ GRegexMatchFlags match_options, -+ GjsMatchInfo** match_info); -+GJS_EXPORT -+gboolean gjs_regex_match_full(const GRegex* regex, const uint8_t* bytes, -+ ssize_t len, int start_position, -+ GRegexMatchFlags match_options, -+ GjsMatchInfo** match_info, GError** error); -+GJS_EXPORT -+gboolean gjs_regex_match_all(const GRegex* regex, const char* s, -+ GRegexMatchFlags match_options, -+ GjsMatchInfo** match_info); -+GJS_EXPORT -+gboolean gjs_regex_match_all_full(const GRegex* regex, const uint8_t* bytes, -+ ssize_t len, int start_position, -+ GRegexMatchFlags match_options, -+ GjsMatchInfo** match_info, GError** error); -+ -+G_END_DECLS -diff -ruN cjs-6.2.0-orig/libgjs-private/gjs-util.c cjs-6.2.0/libgjs-private/gjs-util.c ---- cjs-6.2.0-orig/libgjs-private/gjs-util.c 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/libgjs-private/gjs-util.c 2024-09-16 22:32:54.000000000 +0200 -@@ -235,7 +235,7 @@ - * @store: a #GListStore - * @item: the new item - * @compare_func: (scope call): pairwise comparison function for sorting -- * @user_data: (closure): user data for @compare_func -+ * @user_data: user data for @compare_func - * - * Inserts @item into @store at a position to be determined by the - * @compare_func. -@@ -258,7 +258,7 @@ - * gjs_list_store_sort: - * @store: a #GListStore - * @compare_func: (scope call): pairwise comparison function for sorting -- * @user_data: (closure): user data for @compare_func -+ * @user_data: user data for @compare_func - * - * Sort the items in @store according to @compare_func. - */ -@@ -270,7 +270,7 @@ - /** - * gjs_gtk_custom_sorter_new: - * @sort_func: (nullable) (scope call): function to sort items -- * @user_data: (closure): user data for @compare_func -+ * @user_data: user data for @sort_func - * @destroy: destroy notify for @user_data - * - * Creates a new `GtkSorter` that works by calling @sort_func to compare items. -@@ -305,7 +305,7 @@ - * gjs_gtk_custom_sorter_set_sort_func: - * @sorter: a `GtkCustomSorter` - * @sort_func: (nullable) (scope call): function to sort items -- * @user_data: (closure): user data to pass to @sort_func -+ * @user_data: user data to pass to @sort_func - * @destroy: destroy notify for @user_data - * - * Sets (or unsets) the function used for sorting items. -@@ -423,7 +423,7 @@ - /** - * gjs_log_set_writer_func: - * @func: (scope notified): callback with log data -- * @user_data: (closure): user data for @func -+ * @user_data: user data for @func - * @user_data_free: (destroy user_data_free): destroy for @user_data - * - * Sets a given function as the writer function for structured logging, -diff -ruN cjs-6.2.0-orig/libgjs-private/gjs-util.h cjs-6.2.0/libgjs-private/gjs-util.h ---- cjs-6.2.0-orig/libgjs-private/gjs-util.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/libgjs-private/gjs-util.h 2024-10-14 19:19:28.805368787 +0200 -@@ -124,11 +124,11 @@ - * @target: - * @target_property: - * @flags: -- * @to_callback: (scope notified) (nullable): -- * @to_data: (closure to_callback): -+ * @to_callback: (scope notified) (nullable) (closure to_data): -+ * @to_data: - * @to_notify: (destroy to_data): -- * @from_callback: (scope notified) (nullable): -- * @from_data: (closure from_callback): -+ * @from_callback: (scope notified) (nullable) (closure from_data): -+ * @from_data: - * @from_notify: (destroy from_data): - * - * Returns: (transfer none): -@@ -149,11 +149,11 @@ - * @target: - * @target_property: - * @flags: -- * @to_callback: (scope notified) (nullable): -- * @to_data: (closure to_callback): -+ * @to_callback: (scope notified) (nullable) (closure to_data): -+ * @to_data: - * @to_notify: (destroy to_data): -- * @from_callback: (scope notified) (nullable): -- * @from_data: (closure from_callback): -+ * @from_callback: (scope notified) (nullable) (closure from_data): -+ * @from_data: - * @from_notify: (destroy from_data): - */ - GJS_EXPORT -diff -ruN cjs-6.2.0-orig/meson.build cjs-6.2.0/meson.build ---- cjs-6.2.0-orig/meson.build 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/meson.build 2024-10-14 19:04:30.000000000 +0200 -@@ -44,7 +44,7 @@ - add_project_arguments(cxx.get_supported_arguments([ - '-utf-8', # Use UTF-8 mode - '/Zc:externConstexpr', # Required for 'extern constexpr' on MSVC -- '/Zc:preprocessor', # Required to consume the mozjs-115 headers on MSVC -+ '/Zc:preprocessor', # Required to consume the mozjs-128 headers on MSVC - - # Ignore spurious compiler warnings for things that GLib and SpiderMonkey - # header files commonly do -@@ -133,22 +133,11 @@ - ffi = dependency('libffi', fallback: ['libffi', 'ffi_dep']) - gi = dependency('gobject-introspection-1.0', version: '>= 1.66.0', - fallback: ['gobject-introspection', 'girepo_dep']) --spidermonkey = dependency('mozjs-115') -- --# We might need to look for the headers and lib's for Cairo --# manually on MSVC/clang-cl builds... --cairo = dependency('cairo', required: get_option('cairo').enabled() and cxx.get_argument_syntax() != 'msvc') --cairo_gobject = dependency('cairo-gobject', required: cairo.found() and cxx.get_argument_syntax() != 'msvc') -+cairo = dependency('cairo', fallback: ['cairo', 'libcairo_dep']) -+cairo_gobject = dependency('cairo-gobject', -+ fallback: ['cairo', 'libcairogobject_dep']) - cairo_xlib = dependency('cairo-xlib', required: false) -- --if cxx.get_argument_syntax() == 'msvc' -- if not cairo.found() -- cairo = cc.find_library('cairo', has_headers: ['cairo.h'], required: get_option('cairo').enabled()) -- endif -- if not cairo_gobject.found() -- cairo_gobject = cc.find_library('cairo-gobject', has_headers: ['cairo-gobject.h'], required: cairo.found()) -- endif --endif -+spidermonkey = dependency('mozjs-128') - - sysprof_capture = dependency('sysprof-capture-4', - required: get_option('profiler'), include_type: 'system', -@@ -450,7 +439,6 @@ - 'cjs/promise.cpp', 'cjs/promise.h', - 'cjs/stack.cpp', - 'modules/console.cpp', 'modules/console.h', -- 'modules/modules.cpp', 'modules/modules.h', - 'modules/print.cpp', 'modules/print.h', - 'modules/system.cpp', 'modules/system.h', - ] -diff -ruN cjs-6.2.0-orig/modules/cairo-context.cpp cjs-6.2.0/modules/cairo-context.cpp ---- cjs-6.2.0-orig/modules/cairo-context.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/cairo-context.cpp 2024-10-14 18:50:11.000000000 +0200 -@@ -90,10 +90,11 @@ - JS::RootedObject array(context, JS::NewArrayObject(context, 2)); \ - if (!array) \ - return false; \ -- JS::RootedValue r(context, JS::NumberValue(arg1)); \ -+ JS::RootedValue r{context, \ -+ JS::NumberValue(JS::CanonicalizeNaN(arg1))}; \ - if (!JS_SetElement(context, array, 0, r)) \ - return false; \ -- r.setNumber(arg2); \ -+ r.setNumber(JS::CanonicalizeNaN(arg2)); \ - if (!JS_SetElement(context, array, 1, r)) \ - return false; \ - argv.rval().setObject(*array); \ -@@ -109,10 +110,11 @@ - JS::RootedObject array(context, JS::NewArrayObject(context, 2)); \ - if (!array) \ - return false; \ -- JS::RootedValue r(context, JS::NumberValue(arg1)); \ -+ JS::RootedValue r{context, \ -+ JS::NumberValue(JS::CanonicalizeNaN(arg1))}; \ - if (!JS_SetElement(context, array, 0, r)) \ - return false; \ -- r.setNumber(arg2); \ -+ r.setNumber(JS::CanonicalizeNaN(arg2)); \ - if (!JS_SetElement(context, array, 1, r)) \ - return false; \ - argv.rval().setObject(*array); \ -@@ -128,16 +130,17 @@ - JS::RootedObject array(context, JS::NewArrayObject(context, 4)); \ - if (!array) \ - return false; \ -- JS::RootedValue r(context, JS::NumberValue(arg1)); \ -+ JS::RootedValue r{context, \ -+ JS::NumberValue(JS::CanonicalizeNaN(arg1))}; \ - if (!JS_SetElement(context, array, 0, r)) \ - return false; \ -- r.setNumber(arg2); \ -+ r.setNumber(JS::CanonicalizeNaN(arg2)); \ - if (!JS_SetElement(context, array, 1, r)) \ - return false; \ -- r.setNumber(arg3); \ -+ r.setNumber(JS::CanonicalizeNaN(arg3)); \ - if (!JS_SetElement(context, array, 2, r)) \ - return false; \ -- r.setNumber(arg4); \ -+ r.setNumber(JS::CanonicalizeNaN(arg4)); \ - if (!JS_SetElement(context, array, 3, r)) \ - return false; \ - argv.rval().setObject(*array); \ -@@ -149,7 +152,7 @@ - double ret; \ - _GJS_CAIRO_CONTEXT_CHECK_NO_ARGS(method) \ - ret = cfunc(cr); \ -- argv.rval().setNumber(ret); \ -+ argv.rval().setNumber(JS::CanonicalizeNaN(ret)); \ - _GJS_CAIRO_CONTEXT_DEFINE_FUNC_END - - #define _GJS_CAIRO_CONTEXT_DEFINE_FUNC1(method, cfunc, fmt, t1, n1) \ -@@ -919,7 +922,7 @@ - JS_FS_END}; - // clang-format on - --[[nodiscard]] static bool context_to_g_argument( -+[[nodiscard]] static bool context_to_gi_argument( - JSContext* context, JS::Value value, const char* arg_name, - GjsArgumentType argument_type, GITransfer transfer, GjsArgumentFlags flags, - GIArgument* arg) { -@@ -947,11 +950,9 @@ - } - - GJS_JSAPI_RETURN_CONVENTION --static bool --context_from_g_argument(JSContext *context, -- JS::MutableHandleValue value_p, -- GIArgument *arg) --{ -+static bool context_from_gi_argument(JSContext* context, -+ JS::MutableHandleValue value_p, -+ GIArgument* arg) { - JSObject* obj = CairoContext::from_c_ptr( - context, static_cast(arg->v_pointer)); - if (!obj) { -@@ -971,8 +972,8 @@ - } - - void gjs_cairo_context_init(void) { -- static GjsForeignInfo foreign_info = {context_to_g_argument, -- context_from_g_argument, -+ static GjsForeignInfo foreign_info = {context_to_gi_argument, -+ context_from_gi_argument, - context_release_argument}; - - gjs_struct_foreign_register("cairo", "Context", &foreign_info); -diff -ruN cjs-6.2.0-orig/modules/cairo-pdf-surface.cpp cjs-6.2.0/modules/cairo-pdf-surface.cpp ---- cjs-6.2.0-orig/modules/cairo-pdf-surface.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/cairo-pdf-surface.cpp 2024-10-14 19:07:48.000000000 +0200 -@@ -8,19 +8,23 @@ - #include // for CAIRO_HAS_PDF_SURFACE - #include - --#include -- --#include "cjs/jsapi-util.h" -- - #if CAIRO_HAS_PDF_SURFACE - # include -+#endif -+ -+#include - -+#if CAIRO_HAS_PDF_SURFACE - # include // for JSPROP_READONLY - # include - # include --# include // for JS_NewObjectWithGivenProto -+# include // for JS_NewObjectWithGivenProto - # include // for JSProtoKey -+#endif - -+#include "cjs/jsapi-util.h" -+ -+#if CAIRO_HAS_PDF_SURFACE - # include "cjs/jsapi-util-args.h" - # include "modules/cairo-private.h" - -diff -ruN cjs-6.2.0-orig/modules/cairo-ps-surface.cpp cjs-6.2.0/modules/cairo-ps-surface.cpp ---- cjs-6.2.0-orig/modules/cairo-ps-surface.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/cairo-ps-surface.cpp 2024-10-14 19:07:48.000000000 +0200 -@@ -8,19 +8,23 @@ - #include // for CAIRO_HAS_PS_SURFACE - #include - --#include -- --#include "cjs/jsapi-util.h" -- - #if CAIRO_HAS_PS_SURFACE - # include -+#endif -+ -+#include - -+#if CAIRO_HAS_PS_SURFACE - # include // for JSPROP_READONLY - # include - # include --# include // for JS_NewObjectWithGivenProto -+# include // for JS_NewObjectWithGivenProto - # include // for JSProtoKey -+#endif - -+#include "cjs/jsapi-util.h" -+ -+#if CAIRO_HAS_PS_SURFACE - # include "cjs/jsapi-util-args.h" - # include "modules/cairo-private.h" - -diff -ruN cjs-6.2.0-orig/modules/cairo-region.cpp cjs-6.2.0/modules/cairo-region.cpp ---- cjs-6.2.0-orig/modules/cairo-region.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/cairo-region.cpp 2024-10-14 18:50:11.000000000 +0200 -@@ -227,7 +227,7 @@ - cairo_region_destroy(region); - } - --[[nodiscard]] static bool region_to_g_argument( -+[[nodiscard]] static bool region_to_gi_argument( - JSContext* context, JS::Value value, const char* arg_name, - GjsArgumentType argument_type, GITransfer transfer, GjsArgumentFlags flags, - GIArgument* arg) { -@@ -256,11 +256,9 @@ - } - - GJS_JSAPI_RETURN_CONVENTION --static bool --region_from_g_argument(JSContext *context, -- JS::MutableHandleValue value_p, -- GIArgument *arg) --{ -+static bool region_from_gi_argument(JSContext* context, -+ JS::MutableHandleValue value_p, -+ GIArgument* arg) { - JSObject* obj = - CairoRegion::from_c_ptr(context, gjs_arg_get(arg)); - if (!obj) -@@ -279,8 +277,9 @@ - - - void gjs_cairo_region_init(void) { -- static GjsForeignInfo foreign_info = { -- region_to_g_argument, region_from_g_argument, region_release_argument}; -+ static GjsForeignInfo foreign_info = {region_to_gi_argument, -+ region_from_gi_argument, -+ region_release_argument}; - - gjs_struct_foreign_register("cairo", "Region", &foreign_info); - } -diff -ruN cjs-6.2.0-orig/modules/cairo-surface.cpp cjs-6.2.0/modules/cairo-surface.cpp ---- cjs-6.2.0-orig/modules/cairo-surface.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/cairo-surface.cpp 2024-10-14 18:50:11.000000000 +0200 -@@ -173,8 +173,8 @@ - // cannot error - - JS::RootedValueArray<2> elements(cx); -- elements[0].setNumber(x_offset); -- elements[1].setNumber(y_offset); -+ elements[0].setNumber(JS::CanonicalizeNaN(x_offset)); -+ elements[1].setNumber(JS::CanonicalizeNaN(y_offset)); - JS::RootedObject retval(cx, JS::NewArrayObject(cx, elements)); - if (!retval) - return false; -@@ -223,8 +223,8 @@ - // cannot error - - JS::RootedValueArray<2> elements(cx); -- elements[0].setNumber(x_scale); -- elements[1].setNumber(y_scale); -+ elements[0].setNumber(JS::CanonicalizeNaN(x_scale)); -+ elements[1].setNumber(JS::CanonicalizeNaN(y_scale)); - JS::RootedObject retval(cx, JS::NewArrayObject(cx, elements)); - if (!retval) - return false; -@@ -324,7 +324,7 @@ - surface_wrapper, CairoSurface::POINTER); - } - --[[nodiscard]] static bool surface_to_g_argument( -+[[nodiscard]] static bool surface_to_gi_argument( - JSContext* context, JS::Value value, const char* arg_name, - GjsArgumentType argument_type, GITransfer transfer, GjsArgumentFlags flags, - GIArgument* arg) { -@@ -359,9 +359,9 @@ - } - - GJS_JSAPI_RETURN_CONVENTION --static bool surface_from_g_argument(JSContext* cx, -- JS::MutableHandleValue value_p, -- GIArgument* arg) { -+static bool surface_from_gi_argument(JSContext* cx, -+ JS::MutableHandleValue value_p, -+ GIArgument* arg) { - JSObject* obj = - CairoSurface::from_c_ptr(cx, gjs_arg_get(arg)); - if (!obj) -@@ -379,8 +379,8 @@ - } - - void gjs_cairo_surface_init(void) { -- static GjsForeignInfo foreign_info = {surface_to_g_argument, -- surface_from_g_argument, -+ static GjsForeignInfo foreign_info = {surface_to_gi_argument, -+ surface_from_gi_argument, - surface_release_argument}; - gjs_struct_foreign_register("cairo", "Surface", &foreign_info); - } -diff -ruN cjs-6.2.0-orig/modules/cairo-svg-surface.cpp cjs-6.2.0/modules/cairo-svg-surface.cpp ---- cjs-6.2.0-orig/modules/cairo-svg-surface.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/cairo-svg-surface.cpp 2024-10-14 19:07:26.000000000 +0200 -@@ -8,19 +8,23 @@ - #include // for CAIRO_HAS_SVG_SURFACE - #include - --#include -- --#include "cjs/jsapi-util.h" -- - #if CAIRO_HAS_SVG_SURFACE - # include -+#endif -+ -+#include - -+#if CAIRO_HAS_SVG_SURFACE - # include // for JSPROP_READONLY - # include - # include --# include // for JS_NewObjectWithGivenProto -+# include // for JS_NewObjectWithGivenProto - # include // for JSProtoKey -+#endif - -+#include "cjs/jsapi-util.h" -+ -+#if CAIRO_HAS_SVG_SURFACE - # include "cjs/jsapi-util-args.h" - # include "modules/cairo-private.h" - -diff -ruN cjs-6.2.0-orig/modules/cairo.cpp cjs-6.2.0/modules/cairo.cpp ---- cjs-6.2.0-orig/modules/cairo.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/cairo.cpp 2024-10-14 18:50:11.000000000 +0200 -@@ -7,6 +7,13 @@ - #include // for CAIRO_HAS_PDF_SURFACE, CAIRO_HAS_PS_SURFA... - #include - -+#ifdef CAIRO_HAS_XLIB_SURFACE -+# include -+# undef None -+// X11 defines a global None macro. Rude! This conflicts with None used as an -+// enum member in SpiderMonkey headers, e.g. JS::ExceptionStatus::None. -+#endif -+ - #include - #include - #include // for JS_NewPlainObject -@@ -15,8 +22,6 @@ - #include "modules/cairo-private.h" - - #ifdef CAIRO_HAS_XLIB_SURFACE --# include -- - class XLibConstructor { - public: - XLibConstructor() { -diff -ruN cjs-6.2.0-orig/modules/console.cpp cjs-6.2.0/modules/console.cpp ---- cjs-6.2.0-orig/modules/console.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/console.cpp 2024-10-14 18:50:11.000000000 +0200 -@@ -87,12 +87,18 @@ - JS::PrintError(stderr, report, /* reportWarnings = */ false); - - if (exnStack.stack()) { -- GjsAutoChar stack_str = -- gjs_format_stack_trace(m_cx, exnStack.stack()); -- if (!stack_str) -+ JS::UniqueChars stack_str{ -+ format_saved_frame(m_cx, exnStack.stack(), 2)}; -+ if (!stack_str) { - g_printerr("(Unable to print stack trace)\n"); -- else -- g_printerr("%s", stack_str.get()); -+ } else { -+ GjsAutoChar encoded_stack_str{g_filename_from_utf8( -+ stack_str.get(), -1, nullptr, nullptr, nullptr)}; -+ if (!encoded_stack_str) -+ g_printerr("(Unable to print stack trace)\n"); -+ else -+ g_printerr("%s", stack_str.get()); -+ } - } - - JS_ClearPendingException(m_cx); -@@ -194,9 +200,6 @@ - GjsContextPrivate* gjs = GjsContextPrivate::from_cx(cx); - gjs->schedule_gc_if_needed(); - -- if (result.isUndefined()) -- return true; -- - JS::AutoSaveExceptionState exc_state(cx); - JS::RootedValue v_printed_string(cx); - JS::RootedValue v_pretty_print( -@@ -301,7 +304,7 @@ - if (!ok) { - /* If this was an uncatchable exception, throw another uncatchable - * exception on up to the surrounding JS::Evaluate() in main(). This -- * happens when you run cjs-console and type imports.system.exit(0); -+ * happens when you run gjs-console and type imports.system.exit(0); - * at the prompt. If we don't throw another uncatchable exception - * here, then it's swallowed and main() won't exit. */ - return false; -diff -ruN cjs-6.2.0-orig/modules/core/_common.js cjs-6.2.0/modules/core/_common.js ---- cjs-6.2.0-orig/modules/core/_common.js 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/core/_common.js 2024-09-16 22:32:54.000000000 +0200 -@@ -3,7 +3,8 @@ - // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later - // SPDX-FileCopyrightText: 2020 Philip Chimento - --/* exported _checkAccessors, _registerType */ -+/* exported _checkAccessors, _createBuilderConnectFunc, _createClosure, -+_registerType */ - - // This is a helper module in which to put code that is common between the - // legacy GObject.Class system and the new GObject.registerClass system. -@@ -92,3 +93,32 @@ - Object.defineProperty(proto, camelName, propdesc); - } - } -+ -+function _createClosure(builder, thisArg, handlerName, swapped, connectObject) { -+ connectObject ??= thisArg; -+ -+ if (swapped) { -+ throw new Error('Unsupported template signal flag "swapped"'); -+ } else if (typeof thisArg[handlerName] === 'undefined') { -+ throw new Error(`A handler called ${handlerName} was not ` + -+ `defined on ${thisArg}`); -+ } -+ -+ return thisArg[handlerName].bind(connectObject); -+} -+ -+function _createBuilderConnectFunc(klass) { -+ const {GObject} = imports.gi; -+ return function (builder, obj, signalName, handlerName, connectObj, flags) { -+ const objects = builder.get_objects(); -+ const thisObj = objects.find(o => o instanceof klass); -+ const swapped = flags & GObject.ConnectFlags.SWAPPED; -+ const closure = _createClosure(builder, thisObj, handlerName, swapped, -+ connectObj); -+ -+ if (flags & GObject.ConnectFlags.AFTER) -+ obj.connect_after(signalName, closure); -+ else -+ obj.connect(signalName, closure); -+ }; -+} -diff -ruN cjs-6.2.0-orig/modules/core/_format.js cjs-6.2.0/modules/core/_format.js ---- cjs-6.2.0-orig/modules/core/_format.js 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/core/_format.js 2024-09-16 22:32:54.000000000 +0200 -@@ -5,7 +5,7 @@ - - /* exported vprintf */ - --const CjsPrivate = imports.gi.CjsPrivate; -+const GjsPrivate = imports.gi.GjsPrivate; - - function vprintf(string, args) { - let i = 0; -@@ -48,7 +48,7 @@ - case 'd': { - let intV = parseInt(getArg()); - if (hasAlternativeIntFlag) -- s = CjsPrivate.format_int_alternative_output(intV); -+ s = GjsPrivate.format_int_alternative_output(intV); - else - s = intV.toString(); - break; -diff -ruN cjs-6.2.0-orig/modules/core/_gettext.js cjs-6.2.0/modules/core/_gettext.js ---- cjs-6.2.0-orig/modules/core/_gettext.js 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/core/_gettext.js 2024-09-16 22:32:54.000000000 +0200 -@@ -19,19 +19,19 @@ - */ - - const GLib = imports.gi.GLib; --const CjsPrivate = imports.gi.CjsPrivate; -+const GjsPrivate = imports.gi.GjsPrivate; - --var LocaleCategory = CjsPrivate.LocaleCategory; -+var LocaleCategory = GjsPrivate.LocaleCategory; - - function setlocale(category, locale) { -- return CjsPrivate.setlocale(category, locale); -+ return GjsPrivate.setlocale(category, locale); - } - - function textdomain(dom) { -- return CjsPrivate.textdomain(dom); -+ return GjsPrivate.textdomain(dom); - } - function bindtextdomain(dom, location) { -- return CjsPrivate.bindtextdomain(dom, location); -+ return GjsPrivate.bindtextdomain(dom, location); - } - - function gettext(msgid) { -diff -ruN cjs-6.2.0-orig/modules/core/overrides/GLib.js cjs-6.2.0/modules/core/overrides/GLib.js ---- cjs-6.2.0-orig/modules/core/overrides/GLib.js 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/core/overrides/GLib.js 2024-09-16 22:32:54.000000000 +0200 -@@ -1,7 +1,7 @@ - // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later - // SPDX-FileCopyrightText: 2011 Giovanni Campagna -+// SPDX-FileCopyrightText: 2023 Philip Chimento - --const ByteArray = imports._byteArrayNative; - const {setMainLoopHook} = imports._promiseNative; - - let GLib; -@@ -100,11 +100,8 @@ - } - if (arrayType[0] === 'y') { - // special case for array of bytes -- if (typeof value === 'string') { -- value = ByteArray.fromString(value); -- if (value[value.length - 1] !== 0) -- value = Uint8Array.of(...value, 0); -- } -+ if (typeof value === 'string') -+ value = Uint8Array.of(...new TextEncoder().encode(value), 0); - const bytes = new GLib.Bytes(value); - return GLib.Variant.new_from_bytes(new GLib.VariantType('ay'), - bytes, true); -@@ -363,23 +360,23 @@ - GLib.log_variant(logDomain, logLevel, new GLib.Variant('a{sv}', variantFields)); - }; - -- // CjsPrivate depends on GLib so we cannot import it -+ // GjsPrivate depends on GLib so we cannot import it - // before GLib is fully resolved. - - this.log_set_writer_func_variant = function (...args) { -- const {log_set_writer_func} = imports.gi.CjsPrivate; -+ const {log_set_writer_func} = imports.gi.GjsPrivate; - - log_set_writer_func(...args); - }; - - this.log_set_writer_default = function (...args) { -- const {log_set_writer_default} = imports.gi.CjsPrivate; -+ const {log_set_writer_default} = imports.gi.GjsPrivate; - - log_set_writer_default(...args); - }; - - this.log_set_writer_func = function (writer_func) { -- const {log_set_writer_func} = imports.gi.CjsPrivate; -+ const {log_set_writer_func} = imports.gi.GjsPrivate; - - if (typeof writer_func !== 'function') { - log_set_writer_func(writer_func); -@@ -538,4 +535,67 @@ - this.Thread.prototype.unref = function () { - throw new Error('\'GLib.Thread.unref()\' may not be called in GJS'); - }; -+ -+ // Override GLib.MatchInfo with a type that keeps the UTF-8 encoded search -+ // string alive. -+ const oldMatchInfo = this.MatchInfo; -+ let matchInfoPatched = false; -+ function patchMatchInfo(GLibModule) { -+ if (matchInfoPatched) -+ return; -+ -+ const {MatchInfo} = imports.gi.GjsPrivate; -+ -+ const originalMatchInfoMethods = new Set(Object.keys(oldMatchInfo.prototype)); -+ const overriddenMatchInfoMethods = new Set(Object.keys(MatchInfo.prototype)); -+ const symmetricDifference = new Set(originalMatchInfoMethods); -+ for (const method of overriddenMatchInfoMethods) { -+ if (symmetricDifference.has(method)) -+ symmetricDifference.delete(method); -+ else -+ symmetricDifference.add(method); -+ } -+ if (symmetricDifference.size !== 0) -+ throw new Error(`Methods of GMatchInfo and GjsMatchInfo don't match: ${[...symmetricDifference]}`); -+ -+ GLibModule.MatchInfo = MatchInfo; -+ matchInfoPatched = true; -+ } -+ -+ // We can't monkeypatch GLib.MatchInfo directly at override time, because -+ // importing GjsPrivate requires GLib. So this monkeypatches GLib.MatchInfo -+ // with a Proxy that overwrites itself with the real GjsPrivate.MatchInfo -+ // as soon as you try to do anything with it. -+ const allProxyOperations = ['apply', 'construct', 'defineProperty', -+ 'deleteProperty', 'get', 'getOwnPropertyDescriptor', 'getPrototypeOf', -+ 'has', 'isExtensible', 'ownKeys', 'preventExtensions', 'set', -+ 'setPrototypeOf']; -+ function delegateToMatchInfo(op) { -+ return function (target, ...params) { -+ patchMatchInfo(GLib); -+ return Reflect[op](GLib.MatchInfo, ...params); -+ }; -+ } -+ this.MatchInfo = new Proxy(function () {}, -+ Object.fromEntries(allProxyOperations.map(op => [op, delegateToMatchInfo(op)]))); -+ -+ this.Regex.prototype.match = function (...args) { -+ patchMatchInfo(GLib); -+ return imports.gi.GjsPrivate.regex_match(this, ...args); -+ }; -+ -+ this.Regex.prototype.match_full = function (...args) { -+ patchMatchInfo(GLib); -+ return imports.gi.GjsPrivate.regex_match_full(this, ...args); -+ }; -+ -+ this.Regex.prototype.match_all = function (...args) { -+ patchMatchInfo(GLib); -+ return imports.gi.GjsPrivate.regex_match_all(this, ...args); -+ }; -+ -+ this.Regex.prototype.match_all_full = function (...args) { -+ patchMatchInfo(GLib); -+ return imports.gi.GjsPrivate.regex_match_all_full(this, ...args); -+ }; - } -diff -ruN cjs-6.2.0-orig/modules/core/overrides/GObject.js cjs-6.2.0/modules/core/overrides/GObject.js ---- cjs-6.2.0-orig/modules/core/overrides/GObject.js 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/core/overrides/GObject.js 2024-09-16 22:32:54.000000000 +0200 -@@ -4,7 +4,7 @@ - // SPDX-FileCopyrightText: 2017 Philip Chimento , - - const Gi = imports._gi; --const {CjsPrivate, GLib} = imports.gi; -+const {GjsPrivate, GLib} = imports.gi; - const {_checkAccessors, _registerType} = imports._common; - const Legacy = imports._legacy; - -@@ -179,7 +179,7 @@ - function _createGTypeName(klass) { - const sanitizeGType = s => s.replace(/[^a-z0-9+_-]/gi, '_'); - -- if (klass.hasOwnProperty(GTypeName)) { -+ if (Object.hasOwn(klass, GTypeName)) { - let sanitized = sanitizeGType(klass[GTypeName]); - if (sanitized !== klass[GTypeName]) { - logError(new RangeError(`Provided GType name '${klass[GTypeName]}' ` + -@@ -203,7 +203,7 @@ - - function _propertiesAsArray(klass) { - let propertiesArray = []; -- if (klass.hasOwnProperty(properties)) { -+ if (Object.hasOwn(klass, properties)) { - for (let prop in klass[properties]) - propertiesArray.push(klass[properties][prop]); - } -@@ -218,7 +218,7 @@ - // Ignore properties starting with __ - (typeof key !== 'string' || !key.startsWith('__')) && - // Don't override an implementation on the target -- !targetPrototype.hasOwnProperty(key) && -+ !Object.hasOwn(targetPrototype, key) && - descriptor && - // Only copy if the descriptor has a getter, is a function, or is enumerable. - (typeof descriptor.value === 'function' || descriptor.get || descriptor.enumerable)) -@@ -273,8 +273,90 @@ - } - } - -+function _registerGObjectType(klass) { -+ const gtypename = _createGTypeName(klass); -+ const gflags = Object.hasOwn(klass, GTypeFlags) ? klass[GTypeFlags] : 0; -+ const gobjectInterfaces = Object.hasOwn(klass, interfaces) ? klass[interfaces] : []; -+ const propertiesArray = _propertiesAsArray(klass); -+ const parent = Object.getPrototypeOf(klass); -+ const gobjectSignals = Object.hasOwn(klass, signals) ? klass[signals] : []; -+ -+ // Default to the GObject-specific prototype, fallback on the JS prototype -+ // for GI native classes. -+ const parentPrototype = parent.prototype[Gi.gobject_prototype_symbol] ?? parent.prototype; -+ -+ const [giPrototype, registeredType] = Gi.register_type_with_class(klass, -+ parentPrototype, gtypename, gflags, gobjectInterfaces, propertiesArray); -+ -+ _defineGType(klass, giPrototype, registeredType); -+ _createSignals(klass.$gtype, gobjectSignals); -+ -+ // Reverse the interface array to give the last required interface -+ // precedence over the first. -+ const requiredInterfaces = [...gobjectInterfaces].reverse(); -+ requiredInterfaces.forEach(iface => -+ _copyInterfacePrototypeDescriptors(klass, iface)); -+ requiredInterfaces.forEach(iface => -+ _copyInterfacePrototypeDescriptors(klass.prototype, iface.prototype)); -+ -+ Object.getOwnPropertyNames(klass.prototype) -+ .filter(name => name.startsWith('vfunc_') || name.startsWith('on_')) -+ .forEach(name => { -+ let descr = Object.getOwnPropertyDescriptor(klass.prototype, name); -+ if (typeof descr.value !== 'function') -+ return; -+ -+ let func = klass.prototype[name]; -+ -+ if (name.startsWith('vfunc_')) { -+ giPrototype[Gi.hook_up_vfunc_symbol](name.slice(6), func); -+ } else if (name.startsWith('on_')) { -+ let id = GObject.signal_lookup(name.slice(3).replace('_', '-'), -+ klass.$gtype); -+ if (id !== 0) { -+ GObject.signal_override_class_closure(id, klass.$gtype, function (...argArray) { -+ let emitter = argArray.shift(); -+ -+ return func.apply(emitter, argArray); -+ }); -+ } -+ } -+ }); -+ -+ gobjectInterfaces.forEach(iface => _checkInterface(iface, klass.prototype)); -+ -+ // Lang.Class parent classes don't support static inheritance -+ if (!('implements' in klass)) -+ klass.implements = GObject.Object.implements; -+} -+ -+function _interfaceInstanceOf(instance) { -+ if (instance && typeof instance === 'object' && -+ GObject.Interface.prototype.isPrototypeOf(this.prototype)) -+ return GObject.type_is_a(instance, this); -+ -+ return false; -+} -+ -+function _registerInterfaceType(klass) { -+ const gtypename = _createGTypeName(klass); -+ const gobjectInterfaces = Object.hasOwn(klass, requires) ? klass[requires] : []; -+ const props = _propertiesAsArray(klass); -+ const gobjectSignals = Object.hasOwn(klass, signals) ? klass[signals] : []; -+ -+ const [giPrototype, registeredType] = Gi.register_interface_with_class( -+ klass, gtypename, gobjectInterfaces, props); -+ -+ _defineGType(klass, giPrototype, registeredType); -+ _createSignals(klass.$gtype, gobjectSignals); -+ -+ Object.defineProperty(klass, Symbol.hasInstance, { -+ value: _interfaceInstanceOf, -+ }); -+} -+ - function _checkProperties(klass) { -- if (!klass.hasOwnProperty(properties)) -+ if (!Object.hasOwn(klass, properties)) - return; - - for (let pspec of Object.values(klass[properties])) -@@ -457,21 +539,21 @@ - configurable: false, - enumerable: false, - get() { -- return CjsPrivate.param_spec_get_flags(this); -+ return GjsPrivate.param_spec_get_flags(this); - }, - }, - 'value_type': { - configurable: false, - enumerable: false, - get() { -- return CjsPrivate.param_spec_get_value_type(this); -+ return GjsPrivate.param_spec_get_value_type(this); - }, - }, - 'owner_type': { - configurable: false, - enumerable: false, - get() { -- return CjsPrivate.param_spec_get_owner_type(this); -+ return GjsPrivate.param_spec_get_owner_type(this); - }, - }, - }); -@@ -512,9 +594,9 @@ - _checkProperties(klass); - - if (_registerType in klass) -- klass[_registerType](); -+ klass[_registerType](klass); - else -- _resolveLegacyClassFunction(klass, _registerType).call(klass); -+ _resolveLegacyClassFunction(klass, _registerType)(klass); - - return klass; - }; -@@ -526,103 +608,15 @@ - return false; - }; - -- function registerGObjectType() { -- let klass = this; -- -- let gtypename = _createGTypeName(klass); -- let gflags = klass.hasOwnProperty(GTypeFlags) ? klass[GTypeFlags] : 0; -- let gobjectInterfaces = klass.hasOwnProperty(interfaces) ? klass[interfaces] : []; -- let propertiesArray = _propertiesAsArray(klass); -- let parent = Object.getPrototypeOf(klass); -- let gobjectSignals = klass.hasOwnProperty(signals) ? klass[signals] : []; -- -- // Default to the GObject-specific prototype, fallback on the JS prototype for GI native classes. -- const parentPrototype = parent.prototype[Gi.gobject_prototype_symbol] ?? parent.prototype; -- -- const [giPrototype, registeredType] = Gi.register_type_with_class( -- klass, parentPrototype, gtypename, gflags, -- gobjectInterfaces, propertiesArray); -- -- _defineGType(klass, giPrototype, registeredType); -- _createSignals(klass.$gtype, gobjectSignals); -- -- // Reverse the interface array to give the last required interface precedence over the first. -- const requiredInterfaces = [...gobjectInterfaces].reverse(); -- requiredInterfaces.forEach(iface => -- _copyInterfacePrototypeDescriptors(klass, iface)); -- requiredInterfaces.forEach(iface => -- _copyInterfacePrototypeDescriptors(klass.prototype, iface.prototype)); -- -- Object.getOwnPropertyNames(klass.prototype) -- .filter(name => name.startsWith('vfunc_') || name.startsWith('on_')) -- .forEach(name => { -- let descr = Object.getOwnPropertyDescriptor(klass.prototype, name); -- if (typeof descr.value !== 'function') -- return; -- -- let func = klass.prototype[name]; -- -- if (name.startsWith('vfunc_')) { -- giPrototype[Gi.hook_up_vfunc_symbol](name.slice(6), func); -- } else if (name.startsWith('on_')) { -- let id = GObject.signal_lookup(name.slice(3).replace('_', '-'), -- klass.$gtype); -- if (id !== 0) { -- GObject.signal_override_class_closure(id, klass.$gtype, function (...argArray) { -- let emitter = argArray.shift(); -- -- return func.apply(emitter, argArray); -- }); -- } -- } -- }); -- -- gobjectInterfaces.forEach(iface => -- _checkInterface(iface, klass.prototype)); -- -- // Lang.Class parent classes don't support static inheritance -- if (!('implements' in klass)) -- klass.implements = GObject.Object.implements; -- } -- - Object.defineProperty(GObject.Object, _registerType, { -- value: registerGObjectType, -+ value: _registerGObjectType, - writable: false, - configurable: false, - enumerable: false, - }); - -- function interfaceInstanceOf(instance) { -- if (instance && typeof instance === 'object' && -- GObject.Interface.prototype.isPrototypeOf(this.prototype)) -- return GObject.type_is_a(instance, this); -- -- return false; -- } -- -- function registerInterfaceType() { -- let klass = this; -- -- let gtypename = _createGTypeName(klass); -- let gobjectInterfaces = klass.hasOwnProperty(requires) ? klass[requires] : []; -- let props = _propertiesAsArray(klass); -- let gobjectSignals = klass.hasOwnProperty(signals) ? klass[signals] : []; -- -- const [giPrototype, registeredType] = Gi.register_interface_with_class(klass, gtypename, gobjectInterfaces, -- props); -- -- _defineGType(klass, giPrototype, registeredType); -- _createSignals(klass.$gtype, gobjectSignals); -- -- Object.defineProperty(klass, Symbol.hasInstance, { -- value: interfaceInstanceOf, -- }); -- -- return klass; -- } -- - Object.defineProperty(GObject.Interface, _registerType, { -- value: registerInterfaceType, -+ value: _registerInterfaceType, - writable: false, - configurable: false, - enumerable: false, -@@ -630,9 +624,9 @@ - - GObject.Interface._classInit = function (klass) { - if (_registerType in klass) -- klass[_registerType](); -+ klass[_registerType](klass); - else -- _resolveLegacyClassFunction(klass, _registerType).call(klass); -+ _resolveLegacyClassFunction(klass, _registerType)(klass); - - Object.getOwnPropertyNames(klass.prototype) - .filter(key => key !== 'constructor') -@@ -688,12 +682,12 @@ - }; - - GObject.Object.prototype.bind_property_full = function (...args) { -- return CjsPrivate.g_object_bind_property_full(this, ...args); -+ return GjsPrivate.g_object_bind_property_full(this, ...args); - }; - - if (GObject.BindingGroup !== undefined) { - GObject.BindingGroup.prototype.bind_full = function (...args) { -- return CjsPrivate.g_binding_group_bind_full(this, ...args); -+ return GjsPrivate.g_binding_group_bind_full(this, ...args); - }; - } - -@@ -890,4 +884,21 @@ - throw new Error('GObject.signal_handlers_disconnect_by_data() is not \ - introspectable. Use GObject.signal_handlers_disconnect_by_func() instead.'); - }; -+ -+ function unsupportedDataMethod() { -+ throw new Error('Data access methods are unsupported. Use normal JS properties instead.'); -+ } -+ GObject.Object.prototype.get_data = unsupportedDataMethod; -+ GObject.Object.prototype.get_qdata = unsupportedDataMethod; -+ GObject.Object.prototype.set_data = unsupportedDataMethod; -+ GObject.Object.prototype.steal_data = unsupportedDataMethod; -+ GObject.Object.prototype.steal_qdata = unsupportedDataMethod; -+ -+ function unsupportedRefcountingMethod() { -+ throw new Error("Don't modify an object's reference count in JS."); -+ } -+ GObject.Object.prototype.force_floating = unsupportedRefcountingMethod; -+ GObject.Object.prototype.ref = unsupportedRefcountingMethod; -+ GObject.Object.prototype.ref_sink = unsupportedRefcountingMethod; -+ GObject.Object.prototype.unref = unsupportedRefcountingMethod; - } -diff -ruN cjs-6.2.0-orig/modules/core/overrides/Gio.js cjs-6.2.0/modules/core/overrides/Gio.js ---- cjs-6.2.0-orig/modules/core/overrides/Gio.js 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/core/overrides/Gio.js 2024-09-16 22:32:54.000000000 +0200 -@@ -2,7 +2,7 @@ - // SPDX-FileCopyrightText: 2011 Giovanni Campagna - - var GLib = imports.gi.GLib; --var CjsPrivate = imports.gi.CjsPrivate; -+var GjsPrivate = imports.gi.GjsPrivate; - var Signals = imports.signals; - var Gio; - -@@ -403,7 +403,7 @@ - info = Gio.DBusInterfaceInfo.new_for_xml(interfaceInfo); - info.cache_build(); - -- var impl = new CjsPrivate.DBusImplementation({g_interface_info: info}); -+ var impl = new GjsPrivate.DBusImplementation({g_interface_info: info}); - impl.connect('handle-method-call', function (self, methodName, parameters, invocation) { - return _handleMethodCall.call(jsObj, info, self, methodName, parameters, invocation); - }); -@@ -541,16 +541,16 @@ - _wrapFunction(Gio.DBusNodeInfo, 'new_for_xml', _newNodeInfo); - Gio.DBusInterfaceInfo.new_for_xml = _newInterfaceInfo; - -- Gio.DBusExportedObject = CjsPrivate.DBusImplementation; -+ Gio.DBusExportedObject = GjsPrivate.DBusImplementation; - Gio.DBusExportedObject.wrapJSObject = _wrapJSObject; - - // ListStore - Gio.ListStore.prototype[Symbol.iterator] = _listModelIterator; - Gio.ListStore.prototype.insert_sorted = function (item, compareFunc) { -- return CjsPrivate.list_store_insert_sorted(this, item, compareFunc); -+ return GjsPrivate.list_store_insert_sorted(this, item, compareFunc); - }; - Gio.ListStore.prototype.sort = function (compareFunc) { -- return CjsPrivate.list_store_sort(this, compareFunc); -+ return GjsPrivate.list_store_sort(this, compareFunc); - }; - - // Promisify -diff -ruN cjs-6.2.0-orig/modules/core/overrides/Gtk.js cjs-6.2.0/modules/core/overrides/Gtk.js ---- cjs-6.2.0-orig/modules/core/overrides/Gtk.js 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/core/overrides/Gtk.js 2024-09-16 22:32:54.000000000 +0200 -@@ -3,8 +3,9 @@ - // SPDX-FileCopyrightText: 2013 Giovanni Campagna - - const Legacy = imports._legacy; --const {Gio, CjsPrivate, GObject} = imports.gi; --const {_registerType} = imports._common; -+const {Gio, GjsPrivate, GLib, GObject} = imports.gi; -+const {_createBuilderConnectFunc, _createClosure, _registerType} = imports._common; -+const Gi = imports._gi; - - let Gtk; - let BuilderScope; -@@ -22,49 +23,32 @@ - - if (Gtk.Container && Gtk.Container.prototype.child_set_property) { - Gtk.Container.prototype.child_set_property = function (child, property, value) { -- CjsPrivate.gtk_container_child_set_property(this, child, property, value); -+ GjsPrivate.gtk_container_child_set_property(this, child, property, value); - }; - } - - if (Gtk.CustomSorter) { -- Gtk.CustomSorter.new = CjsPrivate.gtk_custom_sorter_new; -+ Gtk.CustomSorter.new = GjsPrivate.gtk_custom_sorter_new; - Gtk.CustomSorter.prototype.set_sort_func = function (sortFunc) { -- CjsPrivate.gtk_custom_sorter_set_sort_func(this, sortFunc); -+ GjsPrivate.gtk_custom_sorter_set_sort_func(this, sortFunc); - }; - } - - Gtk.Widget.prototype._init = function (params) { -- let wrapper = this; -+ const klass = this.constructor; -+ const wrapper = GObject.Object.prototype._init.call(this, params) ?? this; - -- if (wrapper.constructor[Gtk.template]) { -- if (!BuilderScope) { -- Gtk.Widget.set_connect_func.call(wrapper.constructor, -- (builder, obj, signalName, handlerName, connectObj, flags) => { -- const swapped = flags & GObject.ConnectFlags.SWAPPED; -- const closure = _createClosure( -- builder, wrapper, handlerName, swapped, connectObj); -- -- if (flags & GObject.ConnectFlags.AFTER) -- obj.connect_after(signalName, closure); -- else -- obj.connect(signalName, closure); -- }); -- } -- } -- -- wrapper = GObject.Object.prototype._init.call(wrapper, params) ?? wrapper; -- -- if (wrapper.constructor[Gtk.template]) { -- let children = wrapper.constructor[Gtk.children] || []; -+ if (klass[Gtk.template]) { -+ let children = klass[Gtk.children] ?? []; - for (let child of children) { - wrapper[child.replace(/-/g, '_')] = -- wrapper.get_template_child(wrapper.constructor, child); -+ wrapper.get_template_child(klass, child); - } - -- let internalChildren = wrapper.constructor[Gtk.internalChildren] || []; -+ let internalChildren = klass[Gtk.internalChildren] ?? []; - for (let child of internalChildren) { - wrapper[`_${child.replace(/-/g, '_')}`] = -- wrapper.get_template_child(wrapper.constructor, child); -+ wrapper.get_template_child(klass, child); - } - } - -@@ -75,56 +59,8 @@ - return GObject.Object._classInit(klass); - }; - -- function registerWidgetType() { -- let klass = this; -- -- let template = klass[Gtk.template]; -- let cssName = klass[Gtk.cssName]; -- let children = klass[Gtk.children]; -- let internalChildren = klass[Gtk.internalChildren]; -- -- if (template) { -- klass.prototype._instance_init = function () { -- this.init_template(); -- }; -- } -- -- GObject.Object[_registerType].call(klass); -- -- if (cssName) -- Gtk.Widget.set_css_name.call(klass, cssName); -- -- if (template) { -- if (typeof template === 'string') { -- if (template.startsWith('resource:///')) { -- Gtk.Widget.set_template_from_resource.call(klass, -- template.slice(11)); -- } else if (template.startsWith('file:///')) { -- let file = Gio.File.new_for_uri(template); -- let [, contents] = file.load_contents(null); -- Gtk.Widget.set_template.call(klass, contents); -- } -- } else { -- Gtk.Widget.set_template.call(klass, template); -- } -- -- if (BuilderScope) -- Gtk.Widget.set_template_scope.call(klass, new BuilderScope()); -- } -- -- if (children) { -- children.forEach(child => -- Gtk.Widget.bind_template_child_full.call(klass, child, false, 0)); -- } -- -- if (internalChildren) { -- internalChildren.forEach(child => -- Gtk.Widget.bind_template_child_full.call(klass, child, true, 0)); -- } -- } -- - Object.defineProperty(Gtk.Widget, _registerType, { -- value: registerWidgetType, -+ value: _registerWidgetType, - writable: false, - configurable: false, - enumerable: false, -@@ -143,23 +79,72 @@ - }, class extends GObject.Object { - vfunc_create_closure(builder, handlerName, flags, connectObject) { - const swapped = flags & Gtk.BuilderClosureFlags.SWAPPED; -- return _createClosure( -- builder, builder.get_current_object(), -- handlerName, swapped, connectObject); -+ const thisArg = builder.get_current_object(); -+ return Gi.associateClosure( -+ connectObject ?? thisArg, -+ _createClosure(builder, thisArg, handlerName, swapped, connectObject) -+ ); - } - }); - } - } - --function _createClosure(builder, thisArg, handlerName, swapped, connectObject) { -- connectObject = connectObject || thisArg; -+function _registerWidgetType(klass) { -+ const template = klass[Gtk.template]; -+ const cssName = klass[Gtk.cssName]; -+ const children = klass[Gtk.children]; -+ const internalChildren = klass[Gtk.internalChildren]; -+ -+ if (template) { -+ klass.prototype._instance_init = function () { -+ this.init_template(); -+ }; -+ } -+ -+ GObject.Object[_registerType](klass); -+ -+ if (cssName) -+ Gtk.Widget.set_css_name.call(klass, cssName); -+ -+ if (template) { -+ if (typeof template === 'string') { -+ try { -+ const uri = GLib.Uri.parse(template, GLib.UriFlags.NONE); -+ const scheme = uri.get_scheme(); -+ -+ if (scheme === 'resource') { -+ Gtk.Widget.set_template_from_resource.call(klass, uri.get_path()); -+ } else if (scheme === 'file') { -+ const file = Gio.File.new_for_uri(template); -+ const [, contents] = file.load_contents(null); -+ Gtk.Widget.set_template.call(klass, contents); -+ } else { -+ throw new TypeError(`Invalid template URI: ${template}`); -+ } -+ } catch (err) { -+ if (!(err instanceof GLib.UriError)) -+ throw err; -+ -+ const contents = new TextEncoder().encode(template); -+ Gtk.Widget.set_template.call(klass, contents); -+ } -+ } else { -+ Gtk.Widget.set_template.call(klass, template); -+ } -+ -+ if (BuilderScope) -+ Gtk.Widget.set_template_scope.call(klass, new BuilderScope()); -+ else -+ Gtk.Widget.set_connect_func.call(klass, _createBuilderConnectFunc(klass)); -+ } - -- if (swapped) { -- throw new Error('Unsupported template signal flag "swapped"'); -- } else if (typeof thisArg[handlerName] === 'undefined') { -- throw new Error(`A handler called ${handlerName} was not ` + -- `defined on ${thisArg}`); -+ if (children) { -+ children.forEach(child => -+ Gtk.Widget.bind_template_child_full.call(klass, child, false, 0)); - } - -- return thisArg[handlerName].bind(connectObject); -+ if (internalChildren) { -+ internalChildren.forEach(child => -+ Gtk.Widget.bind_template_child_full.call(klass, child, true, 0)); -+ } - } -diff -ruN cjs-6.2.0-orig/modules/esm/_encoding/encoding.js cjs-6.2.0/modules/esm/_encoding/encoding.js ---- cjs-6.2.0-orig/modules/esm/_encoding/encoding.js 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/esm/_encoding/encoding.js 2024-09-16 22:32:54.000000000 +0200 -@@ -106,6 +106,8 @@ - input = new Uint8Array(buffer, byteOffset, byteLength); - } else if (bytes === undefined) { - input = new Uint8Array(0); -+ } else if (bytes instanceof import.meta.importSync('gi').GLib.Bytes) { -+ input = bytes.toArray(); - } else { - throw new Error( - 'Provided input cannot be converted to ArrayBufferView or ArrayBuffer' -diff -ruN cjs-6.2.0-orig/modules/esm/console.js cjs-6.2.0/modules/esm/console.js ---- cjs-6.2.0-orig/modules/esm/console.js 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/esm/console.js 2024-09-16 22:32:54.000000000 +0200 -@@ -40,8 +40,9 @@ - * @returns {string} - */ - function formatOptimally(item) { -+ const GLib = imports.gi.GLib; - // Handle optimal error formatting. -- if (item instanceof Error) { -+ if (item instanceof Error || item instanceof GLib.Error) { - return `${item.toString()}${item.stack ? '\n' : ''}${item.stack - ?.split('\n') - // Pad each stacktrace line. -@@ -52,6 +53,12 @@ - // TODO: Enhance 'optimal' formatting. - // There is a current work on a better object formatter for GJS in - // https://gitlab.gnome.org/GNOME/gjs/-/merge_requests/587 -+ if (typeof item === 'object' && item !== null) { -+ if (item.constructor?.name !== 'Object') -+ return `${item.constructor?.name} ${JSON.stringify(item, null, 4)}`; -+ else if (item[Symbol.toStringTag] === 'GIRepositoryNamespace') -+ return `[${item[Symbol.toStringTag]} ${item.__name__}]`; -+ } - return JSON.stringify(item, null, 4); - } - -@@ -109,7 +116,7 @@ - */ - clear() { - this.#groupIndentation = ''; -- imports.gi.CjsPrivate.clear_terminal(); -+ imports.gi.GjsPrivate.clear_terminal(); - } - - /** -diff -ruN cjs-6.2.0-orig/modules/internal/loader.js cjs-6.2.0/modules/internal/loader.js ---- cjs-6.2.0-orig/modules/internal/loader.js 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/internal/loader.js 2024-09-16 22:32:54.000000000 +0200 -@@ -18,14 +18,7 @@ - * Thrown when there is an error importing a module. - */ - class ImportError extends moduleGlobalThis.Error { -- /** -- * @param {string | undefined} message the import error message -- */ -- constructor(message) { -- super(message); -- -- this.name = 'ImportError'; -- } -+ name = 'ImportError'; - } - - /** -@@ -170,7 +163,7 @@ - // 1) Resolve path and URI-based imports. - const uri = this.resolveSpecifier(specifier, importingModuleURI); - if (uri) { -- module = registry.get(uri.uri); -+ module = registry.get(uri.uriWithQuery); - - // Check if module is already loaded (relative handling) - if (module) -@@ -182,10 +175,10 @@ - - const [text, internal = false] = result; - -- const priv = new ModulePrivate(uri.uri, uri.uri, internal); -+ const priv = new ModulePrivate(uri.uriWithQuery, uri.uri, internal); - const compiled = this.compileModule(priv, text); - -- registry.set(uri.uri, compiled); -+ registry.set(uri.uriWithQuery, compiled); - return compiled; - } - -@@ -365,7 +358,7 @@ - // 1) Resolve path and URI-based imports. - const uri = this.resolveSpecifier(specifier, importingModuleURI); - if (uri) { -- module = registry.get(uri.uri); -+ module = registry.get(uri.uriWithQuery); - - // Check if module is already loaded (relative handling) - if (module) -@@ -376,16 +369,16 @@ - return null; - - // Check if module loaded while awaiting. -- module = registry.get(uri.uri); -+ module = registry.get(uri.uriWithQuery); - if (module) - return module; - - const [text, internal = false] = result; - -- const priv = new ModulePrivate(uri.uri, uri.uri, internal); -+ const priv = new ModulePrivate(uri.uriWithQuery, uri.uri, internal); - const compiled = this.compileModule(priv, text); - -- registry.set(uri.uri, compiled); -+ registry.set(uri.uriWithQuery, compiled); - return compiled; - } - -diff -ruN cjs-6.2.0-orig/modules/modules.cpp cjs-6.2.0/modules/modules.cpp ---- cjs-6.2.0-orig/modules/modules.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/modules.cpp 1970-01-01 01:00:00.000000000 +0100 -@@ -1,25 +0,0 @@ --/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ --// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later --// SPDX-FileCopyrightText: 2013 Red Hat, Inc. -- --#include // for ENABLE_CAIRO -- --#include "cjs/native.h" --#include "modules/console.h" --#include "modules/modules.h" --#include "modules/print.h" --#include "modules/system.h" -- --#ifdef ENABLE_CAIRO --# include "modules/cairo-module.h" --#endif -- --void gjs_register_static_modules(void) { -- Gjs::NativeModuleRegistry& registry = Gjs::NativeModuleRegistry::get(); --#ifdef ENABLE_CAIRO -- registry.add("cairoNative", gjs_js_define_cairo_stuff); --#endif -- registry.add("system", gjs_js_define_system_stuff); -- registry.add("console", gjs_define_console_stuff); -- registry.add("_print", gjs_define_print_stuff); --} -diff -ruN cjs-6.2.0-orig/modules/modules.h cjs-6.2.0/modules/modules.h ---- cjs-6.2.0-orig/modules/modules.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/modules.h 1970-01-01 01:00:00.000000000 +0100 -@@ -1,10 +0,0 @@ --/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ --// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later --// SPDX-FileCopyrightText: 2013 Red Hat, Inc. -- --#ifndef MODULES_MODULES_H_ --#define MODULES_MODULES_H_ -- --void gjs_register_static_modules (void); -- --#endif // MODULES_MODULES_H_ -diff -ruN cjs-6.2.0-orig/modules/script/_bootstrap/debugger.js cjs-6.2.0/modules/script/_bootstrap/debugger.js ---- cjs-6.2.0-orig/modules/script/_bootstrap/debugger.js 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/script/_bootstrap/debugger.js 2024-09-16 22:32:54.000000000 +0200 -@@ -23,6 +23,7 @@ - var lastExc = null; - var options = {pretty: true, colors: true, ignoreCaughtExceptions: true}; - var breakpoints = [undefined]; // Breakpoint numbers start at 1 -+var skipUnwindHandler = false; - - // Cleanup functions to run when we next re-enter the repl. - var replCleanups = []; -@@ -31,9 +32,12 @@ - function dvToString(v) { - if (typeof v === 'undefined') - return 'undefined'; // uneval(undefined) === '(void 0)', confusing -- if (v === null) -- return 'null'; // typeof null === 'object', so avoid that case -- return typeof v !== 'object' || v === null ? uneval(v) : `[object ${v.class}]`; -+ if (typeof v === 'object' && v !== null) -+ return `[object ${v.class}]`; -+ const s = uneval(v); -+ if (s.length > 400) -+ return `${s.substr(0, 400)}...<${s.length - 400} more bytes>...`; -+ return s; - } - - function debuggeeValueToString(dv, style = {pretty: options.pretty}) { -@@ -50,21 +54,20 @@ - } - - const dvrepr = dvToString(dv); -- if (!style.pretty || dv === null || typeof dv !== 'object') -+ if (!style.pretty || (typeof dv !== 'object') || (dv === null)) - return [dvrepr, undefined]; - -+ const exec = debuggeeGlobalWrapper.executeInGlobalWithBindings.bind(debuggeeGlobalWrapper); -+ - if (['TypeError', 'Error', 'GIRespositoryNamespace', 'GObject_Object'].includes(dv.class)) { -- const errval = debuggeeGlobalWrapper.executeInGlobalWithBindings( -- 'v.toString()', {v: dv}); -+ const errval = exec('v.toString()', {v: dv}); - return [dvrepr, errval['return']]; - } - - if (style.brief) - return [dvrepr, dvrepr]; - -- const str = debuggeeGlobalWrapper.executeInGlobalWithBindings( -- 'imports._print.getPrettyPrintFunction(globalThis)(v)', {v: dv}); -- -+ const str = exec('imports._print.getPrettyPrintFunction(globalThis)(v)', {v: dv}); - if ('throw' in str) { - if (style.noerror) - return [dvrepr, undefined]; -@@ -183,6 +186,36 @@ - } - } - -+// Evaluate @expr in the current frame, logging and suppressing any exceptions -+function evalInFrame(expr) { -+ if (!focusedFrame) { -+ print('No stack'); -+ return; -+ } -+ -+ skipUnwindHandler = true; -+ let cv; -+ try { -+ cv = saveExcursion( -+ () => focusedFrame.evalWithBindings(`(${expr})`, debuggeeValues)); -+ } finally { -+ skipUnwindHandler = false; -+ } -+ -+ if (cv === null) { -+ print(`Debuggee died while evaluating ${expr}`); -+ return; -+ } -+ -+ const {throw: exc, return: dv} = cv; -+ if (exc) { -+ print(`Exception caught while evaluating ${expr}: ${dvToString(exc)}`); -+ return; -+ } -+ -+ return {value: dv}; -+} -+ - // Accept debugger commands starting with '#' so that scripting the debugger - // can be annotated - function commentCommand(comment) { -@@ -346,13 +379,32 @@ - expressions, or $$ for the most recently printed expression.`; - - function keysCommand(rest) { -- return doPrint(` -- (o => Object.getOwnPropertyNames(o) -- .concat(Object.getOwnPropertySymbols(o))) -- (${rest}) -- `); -+ if (!rest) { -+ print("Missing argument. See 'help keys'"); -+ return; -+ } -+ -+ const result = evalInFrame(rest); -+ if (!result) -+ return; -+ -+ const dv = result.value; -+ if (!(dv instanceof Debugger.Object)) { -+ print(`${rest} is ${dvToString(dv)}, not an object`); -+ return; -+ } -+ const names = dv.getOwnPropertyNames(); -+ const symbols = dv.getOwnPropertySymbols(); -+ const keys = [ -+ ...names.map(s => `"${s}"`), -+ ...symbols.map(s => `Symbol("${s.description}")`), -+ ]; -+ if (keys.length === 0) -+ print('No own properties'); -+ else -+ print(keys.join(', ')); - } --keysCommand.summary = 'Prints keys of the given object'; -+keysCommand.summary = 'Prints own properties of the given object'; - keysCommand.helpText = `USAGE - keys - -@@ -380,25 +432,15 @@ - - function throwOrReturn(rest, action, defaultCompletion) { - if (focusedFrame !== topFrame) { -- print("To throw, you must select the newest frame (use 'frame 0')."); -- return; -- } -- if (focusedFrame === null) { -- print('No stack.'); -+ print(`To ${action}, you must select the newest frame (use 'frame 0')`); - return; - } - if (rest === '') - return [defaultCompletion]; - -- const cv = saveExcursion(() => focusedFrame.eval(rest)); -- if (cv === null) { -- print(`Debuggee died while determining what to ${action}. Stopped.`); -- return; -- } -- if ('return' in cv) -- return [{[action]: cv['return']}]; -- print(`Exception determining what to ${action}. Stopped.`); -- showDebuggeeValue(cv.throw); -+ const result = evalInFrame(rest); -+ if (result) -+ return [{[action]: result.value}]; - } - - function throwCommand(rest) { -@@ -838,7 +880,7 @@ - return undefined; - - var first = pieces[0], rest = pieces[1]; -- if (!commands.hasOwnProperty(first)) { -+ if (!Object.hasOwn(commands, first)) { - print(`unrecognized command '${first}'`); - return undefined; - } -@@ -927,6 +969,9 @@ - }); - }; - dbg.onExceptionUnwind = function (frame, value) { -+ if (skipUnwindHandler) -+ return undefined; -+ - const willBeCaught = currentFrame => { - while (currentFrame) { - if (currentFrame.script.isInCatchScope(currentFrame.offset)) -diff -ruN cjs-6.2.0-orig/modules/script/_bootstrap/default.js cjs-6.2.0/modules/script/_bootstrap/default.js ---- cjs-6.2.0-orig/modules/script/_bootstrap/default.js 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/script/_bootstrap/default.js 2024-09-16 22:32:54.000000000 +0200 -@@ -23,15 +23,28 @@ - return nativeLogError(e, args.map(arg => typeof arg === 'string' ? arg : prettyPrint(arg)).join(' ')); - } - -+ // compare against the %TypedArray% intrinsic object all typed array constructors inherit from -+ function _isTypedArray(value) { -+ return value instanceof Object.getPrototypeOf(Uint8Array); -+ } -+ -+ function _hasStandardToString(value) { -+ return value.toString === Object.prototype.toString || -+ value.toString === Array.prototype.toString || -+ // although TypedArrays have a standard Array.prototype.toString, we currently enforce an override to warn -+ // for legacy behaviour, making the toString non-standard for -+ // "any Uint8Array instances created in situations where previously a ByteArray would have been created" -+ _isTypedArray(value) || -+ value.toString === Date.prototype.toString; -+ } -+ - function prettyPrint(value) { - switch (typeof value) { - case 'object': - if (value === null) - return 'null'; - -- if (value.toString === Object.prototype.toString || -- value.toString === Array.prototype.toString || -- value.toString === Date.prototype.toString) { -+ if (_hasStandardToString(value)) { - const printedObjects = new WeakSet(); - return formatObject(value, printedObjects); - } -@@ -60,15 +73,12 @@ - - function formatObject(obj, printedObjects) { - printedObjects.add(obj); -- if (Array.isArray(obj)) -+ if (Array.isArray(obj) || _isTypedArray(obj)) - return formatArray(obj, printedObjects).toString(); - - if (obj instanceof Date) - return formatDate(obj); - -- if (obj[Symbol.toStringTag] === 'GIRepositoryNamespace') -- return obj.toString(); -- - const formattedObject = []; - const keys = Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj)); - for (const propertyKey of keys) { -@@ -78,8 +88,12 @@ - case 'object': - if (printedObjects.has(value)) - formattedObject.push(`${key}: [Circular]`); -- else -+ else if (value === null) -+ formattedObject.push(`${key}: null`); -+ else if (_hasStandardToString(value)) - formattedObject.push(`${key}: ${formatObject(value, printedObjects)}`); -+ else -+ formattedObject.push(`${key}: ${value.toString()}`); - break; - case 'function': - formattedObject.push(`${key}: ${formatFunction(value)}`); -diff -ruN cjs-6.2.0-orig/modules/script/_legacy.js cjs-6.2.0/modules/script/_legacy.js ---- cjs-6.2.0-orig/modules/script/_legacy.js 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/script/_legacy.js 2024-09-16 22:32:54.000000000 +0200 -@@ -246,7 +246,7 @@ - return req.__super__; - for (let metaclass = req.prototype.__metaclass__; metaclass; - metaclass = metaclass.__super__) { -- if (metaclass.hasOwnProperty('MetaInterface')) -+ if (Object.hasOwn(metaclass, 'MetaInterface')) - return metaclass.MetaInterface; - } - return null; -@@ -441,7 +441,7 @@ - } - - function _getGObjectInterfaces(interfaces) { -- return interfaces.filter(iface => iface.hasOwnProperty('$gtype')); -+ return interfaces.filter(iface => Object.hasOwn(iface, '$gtype')); - } - - function _propertiesAsArray(params) { -@@ -647,6 +647,8 @@ - } - - function defineGtkLegacyObjects(GObject, Gtk) { -+ const {_createBuilderConnectFunc} = imports._common; -+ - const GtkWidgetClass = new Class({ - Name: 'GtkWidgetClass', - Extends: GObject.Class, -@@ -683,6 +685,8 @@ - Gtk.Widget.set_template.call(this, template); - } - -+ Gtk.Widget.set_connect_func.call(this, _createBuilderConnectFunc(this)); -+ - this[Gtk.template] = template; - this[Gtk.children] = children; - this[Gtk.internalChildren] = internalChildren; -diff -ruN cjs-6.2.0-orig/modules/script/lang.js cjs-6.2.0/modules/script/lang.js ---- cjs-6.2.0-orig/modules/script/lang.js 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/script/lang.js 2024-09-16 22:32:54.000000000 +0200 -@@ -16,7 +16,7 @@ - } - - function getPropertyDescriptor(obj, property) { -- if (obj.hasOwnProperty(property)) -+ if (Object.hasOwn(obj, property)) - return Object.getOwnPropertyDescriptor(obj, property); - return getPropertyDescriptor(Object.getPrototypeOf(obj), property); - } -diff -ruN cjs-6.2.0-orig/modules/script/package.js cjs-6.2.0/modules/script/package.js ---- cjs-6.2.0-orig/modules/script/package.js 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/modules/script/package.js 2024-09-16 22:32:54.000000000 +0200 -@@ -9,6 +9,7 @@ - * This module provides a set of convenience APIs for building packaged - * applications. - */ -+imports.gi.versions.GIRepository = '2.0'; - - const GLib = imports.gi.GLib; - const GIRepository = imports.gi.GIRepository; -diff -ruN cjs-6.2.0-orig/test/check-headers.sh cjs-6.2.0/test/check-headers.sh ---- cjs-6.2.0-orig/test/check-headers.sh 1970-01-01 01:00:00.000000000 +0100 -+++ cjs-6.2.0/test/check-headers.sh 2024-09-16 22:32:54.000000000 +0200 -@@ -0,0 +1,181 @@ -+#!/usr/bin/env bash -+# SPDX-License-Identifier: LGPL-2.0-or-later -+# SPDX-FileCopyrightText: 2024 Philip Chimento -+ -+# Drafted with assistance from ChatGPT. -+# https://chat.openai.com/share/0cd77782-13b5-4775-80d0-c77c7749fb9d -+ -+if [ -n "$SELFTEST" ]; then -+ unset SELFTEST -+ set -x -+ self="$(realpath "$0")" -+ test_paths=() -+ trap 'rm -rf -- "${test_paths[@]}"' EXIT -+ -+ test_env() { -+ local code_path -+ code_path=$(mktemp -d -t "check-pch-XXXXXX") -+ test_paths+=("$code_path") -+ cd "$code_path" || exit -+ mkdir gi gjs libgjs-private modules test util -+ } -+ -+ expect_success() { -+ "$self" || exit 1 -+ } -+ expect_failure() { -+ "$self" && exit 1 || true -+ } -+ -+ # config.h is included -+ test_env -+ echo "#include " > gjs/program.c -+ expect_success -+ -+ # config.h must be in angle brackets -+ test_env -+ echo '#include "config.h"' > gjs/program.c -+ expect_failure -+ -+ # public headers are skipped -+ test_env -+ echo "#include " > gjs/macros.h -+ expect_success -+ -+ # config.h must be included -+ test_env -+ echo "#include " > gjs/program.c -+ expect_failure -+ -+ # config.h is included first -+ test_env -+ echo '#include ' > gjs/program.c -+ echo '#include ' >> gjs/program.c -+ expect_success -+ -+ # config.h must be included first -+ test_env -+ echo '#include ' > gjs/program.c -+ echo '#include ' >> gjs/program.c -+ expect_failure -+ -+ # other non-include things can come before the include -+ test_env -+ cat > gjs/program.h < -+EOF -+ expect_success -+ -+ # spaces are taken into account -+ test_env -+ cat > gjs/program.c < -+#endif -+#include -+EOF -+ expect_failure -+ -+ # header blocks in right order -+ test_env -+ cat > gjs/program.c < -+#include -+#include -+#include -+#include -+#include "program.h" -+EOF -+ expect_success -+ -+ # header blocks in wrong order -+ test_env -+ cat > gjs/program.c < -+#include -+#include -+#include -+#include "program.h" -+#include -+EOF -+ expect_failure -+ -+ exit 0 -+fi -+ -+failed=0 -+ -+function report_out_of_order { -+ file="$1" -+ shift -+ include="$1" -+ shift -+ descr="$1" -+ shift -+ headers=("$@") -+ -+ if [[ ${#headers[@]} -ne 0 ]]; then -+ echo "Error: $file: include $include before $descr header ${headers[0]}" -+ failed=1 -+ return 1 -+ fi -+ return 0 -+} -+ -+function check_config_header { -+ file="$1" -+ included_files=($(sed -nE 's/^#[[:space:]]*include[[:space:]]*([<"][^>"]+[>"]).*/\1/p' "$file")) -+ if [[ "${included_files[0]}" != "" ]]; then -+ echo "Error: $file: include as the first #include directive" -+ failed=1 -+ fi -+ -+ c_headers=() -+ cpp_headers=() -+ gnome_headers=() -+ moz_headers=() -+ gjs_headers=() -+ for include in "${included_files[@]:1}"; do -+ if [[ "$include" =~ \".*\.h\" ]]; then -+ gjs_headers+=("$include") -+ continue -+ fi -+ report_out_of_order "$file" "$include" "GJS" "${gjs_headers[@]}" || continue -+ if [[ "$include" =~ \<(js|mozilla).*\.h\> ]]; then -+ moz_headers+=("$include") -+ continue -+ fi -+ report_out_of_order "$file" "$include" "Mozilla" "${moz_headers[@]}" || continue -+ if [[ "$include" =~ \<(ffi|sysprof.*|cairo.*|g.*)\.h\> ]]; then -+ gnome_headers+=("$include") -+ continue -+ fi -+ report_out_of_order "$file" "$include" "GNOME platform" "${gnome_headers[@]}" || continue -+ if [[ "$include" =~ \<.*\.h\> ]]; then -+ report_out_of_order "$file" "$include" "C++ standard library" "${cpp_headers[@]}" || continue -+ c_headers+=("$include") -+ elif [[ "$include" =~ \<.*\> ]]; then -+ cpp_headers+=("$include") -+ else -+ echo "Error: Need to fix your regex to handle $include." -+ failed=1 -+ fi -+ done -+} -+ -+files=$(find gi gjs libgjs-private modules test util \ -+ -name '*.c' -o -name '*.cpp' -o -name '*.h') -+for file in $files; do -+ if [[ "$file" == "gjs/gjs.h" || "$file" == "gjs/macros.h" ]]; then continue; fi -+ if grep -ql "^GJS_EXPORT" "$file"; then continue; fi -+ check_config_header "$file" -+done -+ -+if [[ $failed -ne 0 ]]; then -+ echo "Errors found." -+ exit 1 -+else -+ echo "OK." -+fi -diff -ruN cjs-6.2.0-orig/test/check-pch.sh cjs-6.2.0/test/check-pch.sh ---- cjs-6.2.0-orig/test/check-pch.sh 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/test/check-pch.sh 2024-09-16 22:32:54.000000000 +0200 -@@ -14,8 +14,8 @@ - local code_path="$(mktemp -t -d "check-pch-XXXXXX")" - test_paths+=("$code_path") - cd "$code_path" -- mkdir cjs gi -- echo "#include " >> cjs/gjs_pch.hh -+ mkdir gjs gi -+ echo "#include " >> gjs/gjs_pch.hh - } - - expect_success() { -@@ -53,12 +53,12 @@ - expect_failure - - test_env -- echo "#include " >> cjs/gjs_pch.hh -+ echo "#include " >> gjs/gjs_pch.hh - echo "#include " >> gi/code.c - expect_failure - - test_env -- echo "#include // check-pch: ignore, yes" >> cjs/gjs_pch.hh -+ echo "#include // check-pch: ignore, yes" >> gjs/gjs_pch.hh - echo "#include " >> gi/code.c - expect_success - -@@ -74,14 +74,14 @@ - - test_env - echo "#include " >> gi/code.c -- echo '#include "local/header.h"' >> cjs/gjs_pch.hh -+ echo '#include "local/header.h"' >> gjs/gjs_pch.hh - expect_failure - - test_env - echo "# include " >> gi/code.c - echo "# include " >> gi/code.c - echo " # include " >> gi/other-file.c -- echo "# include " >> cjs/gjs_pch.hh -+ echo "# include " >> gjs/gjs_pch.hh - expect_success - - test_env -@@ -98,7 +98,7 @@ - echo "#include " >> gi/code.c - echo "//#include " >> gi/invalid-file.c - echo "// #include " >> gi/invalid-file.c -- echo "//#include " >> cjs/gjs_pch.hh -+ echo "//#include " >> gjs/gjs_pch.hh - expect_success - - test_env -@@ -114,10 +114,10 @@ - exit 0 - fi - --PCH_FILES=(cjs/gjs_pch.hh) -+PCH_FILES=(gjs/gjs_pch.hh) - IGNORE_COMMENT="check-pch: ignore" - --CODE_PATHS=(cjs gi) -+CODE_PATHS=(gjs gi) - INCLUDED_FILES=( - \*.c - \*.cpp -diff -ruN cjs-6.2.0-orig/test/extra/Dockerfile cjs-6.2.0/test/extra/Dockerfile ---- cjs-6.2.0-orig/test/extra/Dockerfile 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/test/extra/Dockerfile 2024-09-16 22:32:54.000000000 +0200 -@@ -3,22 +3,25 @@ - - # === Build Spidermonkey stage === - --FROM registry.fedoraproject.org/fedora:38 AS mozjs-build --ARG MOZJS_BRANCH=mozjs102 -+FROM registry.fedoraproject.org/fedora:40 AS mozjs-build -+ARG MOZJS_BRANCH=mozjs115 - ARG MOZJS_BUILDDEPS=${MOZJS_BRANCH} - ARG BUILD_OPTS= - - ENV SHELL=/bin/bash - --# mozjs102 cannot be built with python3.11 and possibly 3.10 -+# mozjs115 cannot be built with python3.11 -+# cbindgen should be included in builddep(mozjs128) - RUN dnf -y install 'dnf-command(builddep)' \ - autoconf213 \ -+ cbindgen \ - clang \ - git \ - llvm \ - llvm-devel \ - make \ -- python3.9 \ -+ python3.10 \ -+ python-packaging \ - rust \ - which \ - xz -@@ -31,7 +34,7 @@ - - WORKDIR /root/mozjs/_build - --ENV PYTHON3=/usr/bin/python3.9 -+ENV PYTHON3=/usr/bin/python3.10 - RUN ../js/src/configure --prefix=/usr --libdir=/usr/lib64 --disable-jemalloc \ - --with-system-zlib --with-intl-api ${BUILD_OPTS} - RUN make -j$(nproc) -@@ -40,7 +43,7 @@ - - # === Actual Docker image === - --FROM registry.fedoraproject.org/fedora:38 -+FROM registry.fedoraproject.org/fedora:40 - - ARG LOCALES=tr_TR - ENV SHELL=/bin/bash -diff -ruN cjs-6.2.0-orig/test/extra/Dockerfile.debug cjs-6.2.0/test/extra/Dockerfile.debug ---- cjs-6.2.0-orig/test/extra/Dockerfile.debug 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/test/extra/Dockerfile.debug 2024-09-16 22:32:54.000000000 +0200 -@@ -3,16 +3,18 @@ - - # === Build stage === - --FROM registry.fedoraproject.org/fedora:38 AS build --ARG MOZJS_BRANCH=mozjs102 -+FROM registry.fedoraproject.org/fedora:40 AS build -+ARG MOZJS_BRANCH=mozjs115 - ARG MOZJS_BUILDDEPS=${MOZJS_BRANCH} - ARG BUILD_OPTS= - - ENV SHELL=/bin/bash - --# mozjs102 cannot be built with python3.11 and possibly 3.10 -+# mozjs115 cannot be built with python3.11 -+# cbindgen should be included in builddep(mozjs128) - RUN dnf -y install 'dnf-command(builddep)' \ - autoconf213 \ -+ cbindgen \ - clang \ - clang-devel \ - cmake \ -@@ -21,7 +23,8 @@ - llvm-devel \ - make \ - ninja-build \ -- python3.9 \ -+ python3.10 \ -+ python3-packaging \ - rust \ - which \ - xz -@@ -30,9 +33,9 @@ - WORKDIR /root - - RUN mkdir -p include-what-you-use/_build --ADD https://include-what-you-use.org/downloads/include-what-you-use-0.20.src.tar.gz /root/include-what-you-use/ -+ADD https://include-what-you-use.org/downloads/include-what-you-use-0.22.src.tar.gz /root/include-what-you-use/ - WORKDIR /root/include-what-you-use --RUN tar xzf include-what-you-use-0.20.src.tar.gz --strip-components=1 -+RUN tar xzf include-what-you-use-0.22.src.tar.gz --strip-components=1 - - WORKDIR /root/include-what-you-use/_build - -@@ -47,7 +50,7 @@ - - WORKDIR /root/mozjs/_build - --ENV PYTHON3=/usr/bin/python3.9 -+ENV PYTHON3=/usr/bin/python3.10 - RUN ../js/src/configure --prefix=/usr --libdir=/usr/lib64 --disable-jemalloc \ - --with-system-zlib --with-intl-api --enable-debug \ - ${BUILD_OPTS} -@@ -55,19 +58,9 @@ - RUN DESTDIR=/root/mozjs-install make install - RUN rm -f /root/mozjs-install/usr/lib64/libjs_static.ajs - --WORKDIR /root -- --# Install gnome-introspection from main, so that we can test against it --RUN dnf -y builddep gobject-introspection --RUN git clone https://gitlab.gnome.org/GNOME/gobject-introspection.git -- --WORKDIR /root/gobject-introspection --RUN meson setup _build . --prefix=/opt/GNOME --buildtype debugoptimized --RUN DESTDIR=/root/g-i-install ninja -C _build install -- - # === Actual Docker image === - --FROM registry.fedoraproject.org/fedora:38 -+FROM registry.fedoraproject.org/fedora:40 - - ARG LOCALES=tr_TR - ENV SHELL=/bin/bash -@@ -126,7 +119,6 @@ - - COPY --from=build /root/mozjs-install/usr /usr - COPY --from=build /root/iwyu-install/usr /usr --COPY --from=build /root/g-i-install/opt /opt - RUN ln -s /usr/bin/iwyu_tool.py /usr/bin/iwyu_tool - - # Enable sudo for wheel users -diff -ruN cjs-6.2.0-orig/test/gjs-test-common.h cjs-6.2.0/test/gjs-test-common.h ---- cjs-6.2.0-orig/test/gjs-test-common.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/test/gjs-test-common.h 2024-09-16 22:32:54.000000000 +0200 -@@ -5,6 +5,8 @@ - #ifndef TEST_GJS_TEST_COMMON_H_ - #define TEST_GJS_TEST_COMMON_H_ - -+#include -+ - struct JSContext; - - char* gjs_test_get_exception_message(JSContext* cx); -diff -ruN cjs-6.2.0-orig/test/gjs-test-coverage.cpp cjs-6.2.0/test/gjs-test-coverage.cpp ---- cjs-6.2.0-orig/test/gjs-test-coverage.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/test/gjs-test-coverage.cpp 2024-10-14 18:33:39.000000000 +0200 -@@ -3,6 +3,8 @@ - // SPDX-FileCopyrightText: 2014 Endless Mobile, Inc. - // SPDX-FileContributor: Authored By: Sam Spilsbury - -+#include -+ - #include // for errno - #include // for sscanf, size_t - #include // for strtol, atoi, mkdtemp -diff -ruN cjs-6.2.0-orig/test/gjs-test-jsapi-utils.cpp cjs-6.2.0/test/gjs-test-jsapi-utils.cpp ---- cjs-6.2.0-orig/test/gjs-test-jsapi-utils.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/test/gjs-test-jsapi-utils.cpp 2024-10-14 18:33:39.000000000 +0200 -@@ -5,11 +5,15 @@ - * Copyright (c) 2020 Marco Trevisan - */ - --#include --#include -+#include -+ - #include // for NULL -+ - #include // for move, swap - -+#include -+#include -+ - #include "cjs/jsapi-util.h" - - struct _GjsTestObject { -diff -ruN cjs-6.2.0-orig/test/gjs-test-no-introspection-object.cpp cjs-6.2.0/test/gjs-test-no-introspection-object.cpp ---- cjs-6.2.0-orig/test/gjs-test-no-introspection-object.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/test/gjs-test-no-introspection-object.cpp 2024-09-16 22:32:54.000000000 +0200 -@@ -2,6 +2,8 @@ - // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later - // SPDX-FileCopyrightText: 2020 Endless Mobile Inc. - -+#include -+ - #include "test/gjs-test-no-introspection-object.h" - - struct _GjsTestNoIntrospectionObject { -diff -ruN cjs-6.2.0-orig/test/gjs-test-no-introspection-object.h cjs-6.2.0/test/gjs-test-no-introspection-object.h ---- cjs-6.2.0-orig/test/gjs-test-no-introspection-object.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/test/gjs-test-no-introspection-object.h 2024-09-16 22:32:54.000000000 +0200 -@@ -5,6 +5,8 @@ - #ifndef TEST_GJS_TEST_NO_INTROSPECTION_OBJECT_H_ - #define TEST_GJS_TEST_NO_INTROSPECTION_OBJECT_H_ - -+#include -+ - #include - - #define GJSTEST_TYPE_NO_INTROSPECTION_OBJECT \ -diff -ruN cjs-6.2.0-orig/test/gjs-test-rooting.cpp cjs-6.2.0/test/gjs-test-rooting.cpp ---- cjs-6.2.0-orig/test/gjs-test-rooting.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/test/gjs-test-rooting.cpp 2024-10-14 18:33:39.000000000 +0200 -@@ -40,7 +40,7 @@ - bool finalized; - bool notify_called; - -- GjsMaybeOwned *obj; /* only used in callback test cases */ -+ GjsMaybeOwned* obj; // only used in callback test cases - }; - - static void test_obj_finalize(JS::GCContext*, JSObject* obj) { -@@ -111,23 +111,23 @@ - - static void test_maybe_owned_rooted_flag_set_when_rooted(GjsRootingFixture* fx, - const void*) { -- auto obj = new GjsMaybeOwned(); -- obj->root(PARENT(fx)->cx, JS::TrueValue()); -+ auto* obj = new GjsMaybeOwned(); -+ obj->root(PARENT(fx)->cx, JS_NewPlainObject(PARENT(fx)->cx)); - g_assert_true(obj->rooted()); - delete obj; - } - - static void test_maybe_owned_rooted_flag_not_set_when_not_rooted( -- GjsRootingFixture*, const void*) { -- auto obj = new GjsMaybeOwned(); -- *obj = JS::TrueValue(); -+ GjsRootingFixture* fx, const void*) { -+ auto* obj = new GjsMaybeOwned(); -+ *obj = JS_NewPlainObject(PARENT(fx)->cx); - g_assert_false(obj->rooted()); - delete obj; - } - - static void test_maybe_owned_rooted_keeps_alive_across_gc(GjsRootingFixture* fx, - const void*) { -- auto obj = new GjsMaybeOwned(); -+ auto* obj = new GjsMaybeOwned(); - obj->root(PARENT(fx)->cx, test_obj_new(fx)); - - wait_for_gc(fx); -@@ -140,7 +140,7 @@ - - static void test_maybe_owned_rooted_is_collected_after_reset( - GjsRootingFixture* fx, const void*) { -- auto obj = new GjsMaybeOwned(); -+ auto* obj = new GjsMaybeOwned(); - obj->root(PARENT(fx)->cx, test_obj_new(fx)); - obj->reset(); - -@@ -150,14 +150,14 @@ - } - - static void update_weak_pointer(JSTracer* trc, JS::Compartment*, void* data) { -- auto* obj = static_cast*>(data); -+ auto* obj = static_cast(data); - if (*obj) - obj->update_after_gc(trc); - } - - static void test_maybe_owned_weak_pointer_is_collected_by_gc( - GjsRootingFixture* fx, const void*) { -- auto obj = new GjsMaybeOwned(); -+ auto* obj = new GjsMaybeOwned(); - *obj = test_obj_new(fx); - - JS_AddWeakPointerCompartmentCallback(PARENT(fx)->cx, &update_weak_pointer, -@@ -171,7 +171,7 @@ - - static void test_maybe_owned_heap_rooted_keeps_alive_across_gc( - GjsRootingFixture* fx, const void*) { -- auto obj = new GjsMaybeOwned(); -+ auto* obj = new GjsMaybeOwned(); - obj->root(PARENT(fx)->cx, test_obj_new(fx)); - - wait_for_gc(fx); -@@ -185,7 +185,7 @@ - static void test_maybe_owned_switching_mode_keeps_same_value( - GjsRootingFixture* fx, const void*) { - JSObject *test_obj = test_obj_new(fx); -- auto obj = new GjsMaybeOwned(); -+ auto* obj = new GjsMaybeOwned(); - - *obj = test_obj; - g_assert_true(*obj == test_obj); -@@ -203,7 +203,7 @@ - - static void test_maybe_owned_switch_to_rooted_prevents_collection( - GjsRootingFixture* fx, const void*) { -- auto obj = new GjsMaybeOwned(); -+ auto* obj = new GjsMaybeOwned(); - *obj = test_obj_new(fx); - - obj->switch_to_rooted(PARENT(fx)->cx); -@@ -215,7 +215,7 @@ - - static void test_maybe_owned_switch_to_unrooted_allows_collection( - GjsRootingFixture* fx, const void*) { -- auto obj = new GjsMaybeOwned(); -+ auto* obj = new GjsMaybeOwned(); - obj->root(PARENT(fx)->cx, test_obj_new(fx)); - - obj->switch_to_unrooted(PARENT(fx)->cx); -@@ -240,7 +240,7 @@ - static void test_maybe_owned_notify_callback_called_on_context_destroy( - GjsRootingFixture* fx, const void*) { - auto* gjs = GjsContextPrivate::from_cx(PARENT(fx)->cx); -- fx->obj = new GjsMaybeOwned(); -+ fx->obj = new GjsMaybeOwned(); - fx->obj->root(PARENT(fx)->cx, test_obj_new(fx)); - gjs->register_notifier(context_destroyed, fx); - -@@ -252,7 +252,7 @@ - static void test_maybe_owned_object_destroyed_after_notify( - GjsRootingFixture* fx, const void*) { - auto* gjs = GjsContextPrivate::from_cx(PARENT(fx)->cx); -- fx->obj = new GjsMaybeOwned(); -+ fx->obj = new GjsMaybeOwned(); - fx->obj->root(PARENT(fx)->cx, test_obj_new(fx)); - gjs->register_notifier(context_destroyed, fx); - -diff -ruN cjs-6.2.0-orig/test/gjs-test-toggle-queue.cpp cjs-6.2.0/test/gjs-test-toggle-queue.cpp ---- cjs-6.2.0-orig/test/gjs-test-toggle-queue.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/test/gjs-test-toggle-queue.cpp 2024-10-14 18:33:39.000000000 +0200 -@@ -5,7 +5,6 @@ - - #include - --#include // for copy - #include - #include - #include -@@ -116,8 +115,7 @@ - GjsAutoUnref gobject( - G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr))); - auto* object = ObjectInstance::new_for_gobject(fx->cx, gobject); -- g_assert_true( -- static_cast(object)->ensure_uses_toggle_ref(fx->cx)); -+ static_cast(object)->ensure_uses_toggle_ref(fx->cx); - return object; - } - -diff -ruN cjs-6.2.0-orig/test/gjs-test-utils.h cjs-6.2.0/test/gjs-test-utils.h ---- cjs-6.2.0-orig/test/gjs-test-utils.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/test/gjs-test-utils.h 2024-10-14 18:33:39.000000000 +0200 -@@ -18,10 +18,10 @@ - - #include // for g_assert_... - --#include "cjs/context.h" -- - #include - -+#include "cjs/context.h" -+ - struct GjsUnitTestFixture { - GjsContext *gjs_context; - JSContext *cx; -diff -ruN cjs-6.2.0-orig/test/gjs-tests.cpp cjs-6.2.0/test/gjs-tests.cpp ---- cjs-6.2.0-orig/test/gjs-tests.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/test/gjs-tests.cpp 2024-10-14 18:33:39.000000000 +0200 -@@ -744,7 +744,7 @@ - const void*) { - g_test_expect_message("Gjs", G_LOG_LEVEL_WARNING, - "JS ERROR: Error: Exception 1\n" -- "Caused by: Error: Exception 2\n"); -+ "Caused by: Error: Exception 2"); - - gjs_throw(fx->cx, "Exception 1"); - gjs_throw(fx->cx, "Exception 2"); -@@ -753,7 +753,7 @@ - g_test_expect_message("Gjs", G_LOG_LEVEL_WARNING, - "JS ERROR: Error: Exception 1\n" - "Caused by: Error: Exception 2\n" -- "Caused by: Error: Exception 3\n"); -+ "Caused by: Error: Exception 3"); - - gjs_throw(fx->cx, "Exception 1"); - gjs_throw(fx->cx, "Exception 2"); -diff -ruN cjs-6.2.0-orig/test/meson.build cjs-6.2.0/test/meson.build ---- cjs-6.2.0-orig/test/meson.build 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/test/meson.build 2024-09-16 22:32:54.000000000 +0200 -@@ -28,7 +28,7 @@ - - test('API tests', gjs_tests, args: ['--tap', '--keep-going', '--verbose'], - depends: gjs_private_typelib, env: tests_environment, protocol: 'tap', -- suite: 'C', timeout: 60) -+ suite: 'C', timeout: 60, priority: 10) - - gjs_tests_internal = executable('gjs-tests-internal', - sources: [ -@@ -47,4 +47,4 @@ - test('Internal API tests', gjs_tests_internal, - args: ['--tap', '--keep-going', '--verbose'], - env: tests_environment, protocol: 'tap', -- suite: 'C') -+ suite: 'C', priority: 10) -diff -ruN cjs-6.2.0-orig/test/test-ci.sh cjs-6.2.0/test/test-ci.sh ---- cjs-6.2.0-orig/test/test-ci.sh 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/test/test-ci.sh 2024-09-16 22:32:54.000000000 +0200 -@@ -19,17 +19,6 @@ - export SHELL=/bin/bash - PATH=$PATH:~/.local/bin - -- if [ "$USE_UNSTABLE_GNOME_PREFIX" = "true" ]; then -- prefix=/opt/GNOME -- libdir=$prefix/lib64 -- export PATH=$prefix/bin:$PATH -- export LD_LIBRARY_PATH=$libdir:$LD_LIBRARY_PATH -- export PKG_CONFIG_PATH=$libdir/pkgconfig:$PKG_CONFIG_PATH -- export GI_TYPELIB_PATH=$libdir/girepository-1.0:$GI_TYPELIB_PATH -- export XDG_DATA_DIRS=$prefix/share:$XDG_DATA_DIRS -- export ACLOCAL_PATH=$prefix/share/aclocal:$ACLOCAL_PATH -- fi -- - export DISPLAY="${DISPLAY:-:0}" - } - -@@ -64,7 +53,7 @@ - - # Work out the newest common ancestor between the detached HEAD that this CI - # job has checked out, and the upstream target branch (which will typically -- # be `upstream/master` or `upstream/gnome-nn`). -+ # be `upstream/main` or `upstream/gnome-nn`). - newest_common_ancestor_sha=$(git merge-base ci-upstream-base-branch HEAD) - if test -z "$newest_common_ancestor_sha"; then - echo "Couldn’t find common ancestor with the upstream main branch. This" -@@ -149,8 +138,8 @@ - elif test "$1" = "BUILD"; then - do_Set_Env - -- DEFAULT_CONFIG_OPTS="-Dcairo=enabled -Dreadline=enabled -Dprofiler=enabled \ -- -Ddtrace=false -Dsystemtap=false -Dverbose_logs=false --werror" -+ DEFAULT_CONFIG_OPTS="-Dreadline=enabled -Dprofiler=enabled -Ddtrace=false \ -+ -Dsystemtap=false -Dverbose_logs=false --werror" - meson setup _build $DEFAULT_CONFIG_OPTS $CONFIG_OPTS - ninja -C _build - -diff -ruN cjs-6.2.0-orig/tools/run_iwyu.sh cjs-6.2.0/tools/run_iwyu.sh ---- cjs-6.2.0-orig/tools/run_iwyu.sh 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/tools/run_iwyu.sh 2024-10-14 15:45:41.000000000 +0200 -@@ -47,7 +47,7 @@ - IWYU_TOOL_ARGS="-I../gjs" - IWYU_ARGS="-Wno-pragma-once-outside-header" - IWYU_RAW="include-what-you-use -xc++ -std=c++17 -Xiwyu --keep=config.h $IWYU_ARGS" --IWYU_RAW_INC="-I. -I.. $(pkg-config --cflags gobject-introspection-1.0 mozjs-115)" -+IWYU_RAW_INC="-I. -I.. $(pkg-config --cflags gobject-introspection-1.0 mozjs-128)" - PRIVATE_MAPPING="-Xiwyu --mapping_file=$SRCDIR/tools/gjs-private-iwyu.imp -Xiwyu --keep=config.h" - PUBLIC_MAPPING="-Xiwyu --mapping_file=$SRCDIR/tools/gjs-public-iwyu.imp" - POSTPROCESS="python3 $SRCDIR/tools/process_iwyu.py" -diff -ruN cjs-6.2.0-orig/util/console.h cjs-6.2.0/util/console.h ---- cjs-6.2.0-orig/util/console.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/util/console.h 2024-10-14 18:10:38.000000000 +0200 -@@ -7,6 +7,8 @@ - #ifndef UTIL_CONSOLE_H_ - #define UTIL_CONSOLE_H_ - -+#include -+ - /* This file has to be valid C, because it's used in libgjs-private */ - - #include /* IWYU pragma: keep */ -diff -ruN cjs-6.2.0-orig/util/log.cpp cjs-6.2.0/util/log.cpp ---- cjs-6.2.0-orig/util/log.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/util/log.cpp 2024-10-14 18:09:37.000000000 +0200 -@@ -2,16 +2,12 @@ - // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later - // SPDX-FileCopyrightText: 2008 litl, LLC - --#include // for atomic_bool --#include // for unique_ptr --#include // for string -+#include - - #include --#include // for SEEK_END - #include - #include // for FILE, fprintf, fflush, fopen, fputs, fseek - #include // for strchr, strcmp --#include "cjs/jsapi-util.h" - - #ifdef _WIN32 - # include -@@ -24,9 +20,13 @@ - #endif - - #include -+#include // for atomic_bool -+#include // for unique_ptr -+#include // for string - - #include - -+#include "cjs/jsapi-util.h" - #include "util/log.h" - #include "util/misc.h" - -diff -ruN cjs-6.2.0-orig/util/log.h cjs-6.2.0/util/log.h ---- cjs-6.2.0-orig/util/log.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/util/log.h 2024-10-14 18:04:47.000000000 +0200 -@@ -5,6 +5,8 @@ - #ifndef UTIL_LOG_H_ - #define UTIL_LOG_H_ - -+#include -+ - /* The idea of this is to be able to have one big log file for the entire - * environment, and grep out what you care about. So each module or app - * should have its own entry in the enum. Be sure to add new enum entries -diff -ruN cjs-6.2.0-orig/util/misc.cpp cjs-6.2.0/util/misc.cpp ---- cjs-6.2.0-orig/util/misc.cpp 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/util/misc.cpp 2024-10-14 18:05:41.000000000 +0200 -@@ -2,6 +2,8 @@ - // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later - // SPDX-FileCopyrightText: 2008 litl, LLC - -+#include -+ - #include - - #include "util/misc.h" -diff -ruN cjs-6.2.0-orig/util/misc.h cjs-6.2.0/util/misc.h ---- cjs-6.2.0-orig/util/misc.h 2024-06-11 16:27:18.000000000 +0200 -+++ cjs-6.2.0/util/misc.h 2024-10-14 18:05:59.000000000 +0200 -@@ -5,6 +5,8 @@ - #ifndef UTIL_MISC_H_ - #define UTIL_MISC_H_ - -+#include -+ - #include - #include // for FILE, stdout - #include // for memcpy