mirror of
https://gitlab.com/CinnamonSlackBuilds/csb.git
synced 2024-12-26 21:59:28 +01:00
b6accfbbb3
Signed-off-by: Willy Sudiarto Raharjo <willysr@slackware-id.org>
11577 lines
438 KiB
Diff
11577 lines
438 KiB
Diff
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 <stdint.h>
|
||
|
||
+#include <algorithm> // for copy_n
|
||
+
|
||
#include <glib-object.h>
|
||
#include <glib.h>
|
||
|
||
#include <js/ArrayBuffer.h>
|
||
#include <js/CallArgs.h>
|
||
+#include <js/GCAPI.h>
|
||
#include <js/PropertyAndElement.h>
|
||
#include <js/PropertySpec.h>
|
||
#include <js/RootingAPI.h>
|
||
@@ -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<GBytes*>(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<void*>(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<const uint8_t*>(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<uint8_t*>(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 <js/RootingAPI.h>
|
||
#include <js/TypeDecls.h>
|
||
#include <js/UniquePtr.h>
|
||
+#include <js/Utility.h> // for UniqueChars, FreePolicy
|
||
#include <js/ValueArray.h>
|
||
#include <jsfriendapi.h> // 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<JS::Heap<JSObject*>, 0, js::SystemAllocPolicy>;
|
||
using FundamentalTable =
|
||
- JS::GCHashMap<void*, JS::Heap<JSObject*>, js::DefaultHasher<void*>,
|
||
+ JS::GCHashMap<void*, Gjs::WeakPtr<JSObject*>, js::DefaultHasher<void*>,
|
||
js::SystemAllocPolicy>;
|
||
using GTypeTable =
|
||
- JS::GCHashMap<GType, JS::Heap<JSObject*>, js::DefaultHasher<GType>,
|
||
+ JS::GCHashMap<GType, Gjs::WeakPtr<JSObject*>, js::DefaultHasher<GType>,
|
||
js::SystemAllocPolicy>;
|
||
+using FunctionVector = JS::GCVector<JSFunction*, 0, js::SystemAllocPolicy>;
|
||
|
||
class GjsContextPrivate : public JS::JobQueue {
|
||
public:
|
||
@@ -87,7 +90,8 @@
|
||
|
||
std::vector<std::pair<DestroyNotify, void*>> m_destroy_notifications;
|
||
std::vector<Gjs::Closure::Ptr> m_async_closures;
|
||
- std::unordered_map<uint64_t, GjsAutoChar> m_unhandled_rejection_stacks;
|
||
+ std::unordered_map<uint64_t, JS::UniqueChars> 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<JS::JobQueue::SavedJobQueue> 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 <unistd.h> // for getpid
|
||
-#elif defined (_WIN32)
|
||
-# include <process.h>
|
||
#endif
|
||
|
||
-#ifdef DEBUG
|
||
-# include <algorithm> // for find
|
||
+#ifdef G_OS_WIN32
|
||
+# include <process.h>
|
||
+# include <windows.h>
|
||
#endif
|
||
+
|
||
#include <new>
|
||
#include <string> // for u16string
|
||
#include <thread> // for get_id
|
||
@@ -31,10 +31,6 @@
|
||
#include <glib-object.h>
|
||
#include <glib.h>
|
||
|
||
-#ifdef G_OS_WIN32
|
||
-#include <windows.h>
|
||
-#endif
|
||
-
|
||
#include <js/AllocPolicy.h> // for SystemAllocPolicy
|
||
#include <js/CallAndConstruct.h> // for Call, JS_CallFunctionValue
|
||
#include <js/CallArgs.h> // for UndefinedHandleValue
|
||
@@ -48,7 +44,7 @@
|
||
#include <js/GCHashTable.h> // for WeakCache
|
||
#include <js/GCVector.h> // for RootedVector
|
||
#include <js/GlobalObject.h> // for CurrentGlobalOrNull
|
||
-#include <js/HashTable.h> // for DefaultHasher via WeakCache
|
||
+#include <js/HeapAPI.h> // for ExposeObjectToActiveJS
|
||
#include <js/Id.h>
|
||
#include <js/Modules.h>
|
||
#include <js/Promise.h> // for JobQueue::SavedJobQueue
|
||
@@ -67,6 +63,7 @@
|
||
#include <js/friend/DumpFunctions.h>
|
||
#include <jsapi.h> // for JS_GetFunctionObject, JS_Ge...
|
||
#include <jsfriendapi.h> // for ScriptEnvironmentPreparer
|
||
+#include <mozilla/UniquePtr.h> // 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<GjsContextPrivate*>(
|
||
@@ -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<JSObject*>(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<FunctionVector> 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 <cjs/gjs.h> can be included directly."
|
||
+# error "Only <gjs/gjs.h> can be included directly."
|
||
#endif
|
||
|
||
#include <stdbool.h> /* 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 <cjs/gjs.h> can be included directly."
|
||
+# error "Only <gjs/gjs.h> can be included directly."
|
||
#endif
|
||
|
||
#include <gio/gio.h>
|
||
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<const char*> args) {
|
||
+void _gjs_warn_deprecated_once_per_callsite(
|
||
+ JSContext* cx, GjsDeprecationMessageId id,
|
||
+ const std::vector<const char*>& 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 <config.h>
|
||
+
|
||
#include <vector>
|
||
|
||
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<const char*> args);
|
||
+void _gjs_warn_deprecated_once_per_callsite(
|
||
+ JSContext* cx, GjsDeprecationMessageId id,
|
||
+ const std::vector<const char*>& 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 <js/ContextOptions.h>
|
||
#include <js/GCAPI.h> // for JS_SetGCParameter, JS_AddFin...
|
||
#include <js/Initialization.h> // for JS_Init, JS_ShutDown
|
||
+#include <js/Principals.h>
|
||
#include <js/Promise.h>
|
||
#include <js/RootingAPI.h>
|
||
#include <js/Stack.h> // for JS_SetNativeStackQuota
|
||
+#include <js/StructuredClone.h> // for JS_WriteUint32Pair
|
||
#include <js/TypeDecls.h>
|
||
+#include <js/Utility.h> // for UniqueChars
|
||
#include <js/Warnings.h>
|
||
#include <js/experimental/SourceHook.h>
|
||
#include <jsapi.h> // for JS_SetGlobalJitCompilerOption
|
||
+#include <mozilla/Atomics.h> // for Atomic in JSPrincipals
|
||
#include <mozilla/UniquePtr.h>
|
||
|
||
#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<GjsContextPrivate*>(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<GjsContextPrivate*>(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<JS::JobQueue*>(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 <config.h>
|
||
+
|
||
#include <stddef.h> // 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 <config.h>
|
||
+
|
||
#include <glib-object.h>
|
||
|
||
#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 <cjs/gjs.h> can be included directly."
|
||
+# error "Only <gjs/gjs.h> can be included directly."
|
||
#endif
|
||
|
||
#include <glib-object.h>
|
||
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 <js/CallArgs.h>
|
||
#include <js/CharacterEncoding.h>
|
||
#include <js/Class.h>
|
||
+#include <js/ColumnNumber.h>
|
||
#include <js/ComparisonOperators.h>
|
||
#include <js/CompilationAndEvaluation.h>
|
||
#include <js/CompileOptions.h>
|
||
@@ -80,6 +81,8 @@
|
||
#include <js/MemoryFunctions.h>
|
||
#include <js/Modules.h>
|
||
#include <js/Object.h>
|
||
+#include <js/Principals.h>
|
||
+#include <js/Printer.h>
|
||
#include <js/ProfilingCategory.h>
|
||
#include <js/ProfilingStack.h>
|
||
#include <js/Promise.h>
|
||
@@ -95,6 +98,7 @@
|
||
#include <js/SourceText.h>
|
||
#include <js/Stack.h>
|
||
#include <js/String.h>
|
||
+#include <js/StructuredClone.h>
|
||
#include <js/Symbol.h>
|
||
#include <js/TracingAPI.h>
|
||
#include <js/TypeDecls.h>
|
||
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 <config.h>
|
||
|
||
+#include <stdint.h>
|
||
+
|
||
#include <js/RootingAPI.h> // for Handle
|
||
#include <js/TypeDecls.h>
|
||
#include <js/Value.h>
|
||
|
||
-#include <stdint.h>
|
||
-
|
||
#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 <js/ComparisonOperators.h>
|
||
#include <js/ErrorReport.h> // for JS_ReportOutOfMemory, JSEXN_ERR
|
||
#include <js/Exception.h>
|
||
+#include <js/GCVector.h> // for StackGCVector
|
||
#include <js/GlobalObject.h> // for CurrentGlobalOrNull
|
||
-#include <js/Id.h> // for PropertyKey
|
||
-#include <js/Object.h> // for GetClass
|
||
+#include <js/Id.h> // for PropertyKey
|
||
+#include <js/Object.h> // for GetClass
|
||
#include <js/PropertyAndElement.h>
|
||
#include <js/PropertyDescriptor.h>
|
||
#include <js/PropertySpec.h>
|
||
@@ -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 <contact@evanwelsh.com>
|
||
|
||
-#include "cjs/internal.h"
|
||
-
|
||
#include <config.h>
|
||
|
||
#include <stddef.h> // 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<GFile> module_file = g_file_new_for_uri(uri.get());
|
||
- GjsAutoUnref<GFile> module_parent_file = g_file_get_parent(module_file);
|
||
|
||
- if (module_parent_file) {
|
||
- GjsAutoUnref<GFile> 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 <glib-object.h>
|
||
#include <glib.h>
|
||
|
||
+#include <js/CallArgs.h> // for JSNative
|
||
#include <js/TypeDecls.h>
|
||
+#include <js/ValueArray.h>
|
||
|
||
-#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 <js/RootingAPI.h>
|
||
#include <js/TypeDecls.h>
|
||
#include <js/Utility.h> // for UniqueChars
|
||
+#include <js/Value.h>
|
||
#include <mozilla/Result.h> // for GenericErrorResult
|
||
#include <mozilla/ResultVariant.h> // 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 <js/AllocPolicy.h>
|
||
#include <js/CharacterEncoding.h>
|
||
+#include <js/ColumnNumber.h>
|
||
#include <js/ErrorReport.h>
|
||
#include <js/Exception.h>
|
||
#include <js/GCHashTable.h> // 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 <cstddef> // for nullptr_t
|
||
#include <memory>
|
||
#include <new>
|
||
-#include <type_traits> // for enable_if_t, is_pointer
|
||
|
||
#include <glib.h>
|
||
|
||
+#include <js/ComparisonOperators.h>
|
||
#include <js/GCAPI.h>
|
||
+#include <js/HeapAPI.h> // for ExposeObjectToActiveJS, GetGCThingZone
|
||
+#include <js/RootingAPI.h> // for SafelyInitialized
|
||
#include <js/TracingAPI.h>
|
||
#include <js/TypeDecls.h>
|
||
|
||
#include "util/log.h"
|
||
|
||
+namespace JS { template <typename T> 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<T> 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<typename T>
|
||
-struct GjsHeapOperation {
|
||
- [[nodiscard]] static bool update_after_gc(JS::Heap<T>* location);
|
||
- static void expose_to_js(JS::Heap<T>& thing);
|
||
-};
|
||
-
|
||
-template<>
|
||
-struct GjsHeapOperation<JSObject *> {
|
||
- [[nodiscard]] static bool update_after_gc(JSTracer* trc,
|
||
- JS::Heap<JSObject*>* location) {
|
||
- JS_UpdateWeakPointerAfterGC(trc, location);
|
||
- return (location->unbarrieredGet() == nullptr);
|
||
- }
|
||
-
|
||
- static void expose_to_js(JS::Heap<JSObject *>& 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<typename T>
|
||
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<T> m_heap;
|
||
- std::unique_ptr<JS::PersistentRooted<T>> m_root;
|
||
+ JS::Heap<JSObject*> m_heap;
|
||
+ std::unique_ptr<JS::PersistentRootedObject> 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<T>();
|
||
+ new (&m_heap) JS::Heap<JSObject*>();
|
||
}
|
||
|
||
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 <typename U = T>
|
||
- [[nodiscard]] constexpr const void* debug_addr(
|
||
- std::enable_if_t<std::is_pointer_v<U>>* = 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<T> 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<T> 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<T> 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<T>::create());
|
||
+ g_assert(!m_heap);
|
||
m_heap.~Heap();
|
||
- m_root = std::make_unique<JS::PersistentRooted<T>>(cx, thing);
|
||
+ m_root = std::make_unique<JS::PersistentRootedObject>(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<T>::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<T>::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<T> 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<T> 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<T>(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<T>::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 <typename T>
|
||
+class WeakPtr : public JS::Heap<T> {
|
||
+ public:
|
||
+ using JS::Heap<T>::Heap;
|
||
+ using JS::Heap<T>::operator=;
|
||
+};
|
||
+
|
||
+} // namespace Gjs
|
||
+
|
||
+namespace JS {
|
||
+
|
||
+template <typename T>
|
||
+struct GCPolicy<Gjs::WeakPtr<T>> {
|
||
+ static void trace(JSTracer* trc, Gjs::WeakPtr<T>* 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<T>* thingp) {
|
||
+ return js::gc::TraceWeakEdge(trc, thingp);
|
||
+ }
|
||
+
|
||
+ static bool needsSweep(JSTracer* trc, const Gjs::WeakPtr<T>* thingp) {
|
||
+ Gjs::WeakPtr<T> 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<char>(js::StringBufferArena, length + 1);
|
||
+ char* bytes = js_pod_malloc<char>(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 << "<function " << gjs_debug_string(display_name);
|
||
else
|
||
@@ -622,6 +622,15 @@
|
||
return out.str();
|
||
}
|
||
|
||
+std::string gjs_debug_callable(JSObject* callable) {
|
||
+ if (JSFunction* fn = JS_GetObjectFunction(callable)) {
|
||
+ if (JSString* display_id = JS_GetMaybePartialFunctionDisplayId(fn))
|
||
+ return {"function " + gjs_debug_string(display_id)};
|
||
+ return {"unnamed function"};
|
||
+ }
|
||
+ return {"callable object " + gjs_debug_object(callable)};
|
||
+}
|
||
+
|
||
std::string
|
||
gjs_debug_value(JS::Value v)
|
||
{
|
||
diff -ruN cjs-6.2.0-orig/cjs/jsapi-util.cpp cjs-6.2.0/cjs/jsapi-util.cpp
|
||
--- cjs-6.2.0-orig/cjs/jsapi-util.cpp 2024-06-11 16:27:18.000000000 +0200
|
||
+++ cjs-6.2.0/cjs/jsapi-util.cpp 2024-10-14 18:35:57.000000000 +0200
|
||
@@ -32,7 +32,6 @@
|
||
#include <js/Object.h> // for GetClass
|
||
#include <js/PropertyAndElement.h>
|
||
#include <js/RootingAPI.h>
|
||
-#include <js/Stack.h> // for BuildStackString
|
||
#include <js/String.h>
|
||
#include <js/TypeDecls.h>
|
||
#include <js/Value.h>
|
||
@@ -40,6 +39,7 @@
|
||
#include <jsapi.h> // for JS_InstanceOf
|
||
#include <jsfriendapi.h> // for ProtoKeyToClass
|
||
#include <jspubtd.h> // for JSProto_InternalError, JSProto_SyntaxError
|
||
+#include <mozilla/ScopeExit.h>
|
||
|
||
#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 <config.h>
|
||
+
|
||
#include <stddef.h> // for size_t
|
||
|
||
#include <atomic>
|
||
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 <config.h>
|
||
+
|
||
#include <stdint.h>
|
||
|
||
#include <glib.h>
|
||
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 <cjs/gjs.h> can be included directly."
|
||
+# error "Only <gjs/gjs.h> can be included directly."
|
||
#endif
|
||
|
||
#include <stdbool.h> /* 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 <stddef.h> // for size_t
|
||
#include <string.h>
|
||
|
||
+#include <vector> // for vector
|
||
+
|
||
#include <gio/gio.h>
|
||
+#include <glib-object.h>
|
||
#include <glib.h>
|
||
|
||
#include <js/CallAndConstruct.h>
|
||
@@ -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<GFile> 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 <string>
|
||
#include <unordered_map>
|
||
|
||
-#include <js/RootingAPI.h>
|
||
#include <js/TypeDecls.h>
|
||
|
||
#include "cjs/macros.h"
|
||
|
||
namespace Gjs {
|
||
-class NativeModuleRegistry {
|
||
- NativeModuleRegistry() {}
|
||
+class NativeModuleDefineFuncs {
|
||
+ NativeModuleDefineFuncs() {}
|
||
typedef bool (*GjsDefineModuleFunc)(JSContext* context,
|
||
JS::MutableHandleObject module_out);
|
||
|
||
std::unordered_map<std::string, GjsDefineModuleFunc> 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 <config.h>
|
||
+
|
||
#include <stdint.h>
|
||
|
||
+#include <js/GCAPI.h> // for JSFinalizeStatus, JSGCStatus, GCReason
|
||
#include <js/ProfilingCategory.h>
|
||
#include <js/ProfilingStack.h>
|
||
#include <js/RootingAPI.h>
|
||
@@ -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 <signal.h> // for siginfo_t, sigevent, sigaction, SIGPROF, ...
|
||
#endif
|
||
|
||
-#include <glib-object.h>
|
||
-#include <glib.h>
|
||
-
|
||
#ifdef ENABLE_PROFILER
|
||
-# include <alloca.h>
|
||
+// 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 <alloca.h> // IWYU pragma: keep
|
||
# include <errno.h>
|
||
# include <stdint.h>
|
||
-# include <stdio.h> // for sscanf
|
||
-# include <string.h> // for memcpy, strlen
|
||
+# include <stdio.h> // for sscanf
|
||
+# include <string.h> // for memcpy, strlen
|
||
# include <sys/syscall.h> // for __NR_gettid
|
||
+# include <sys/types.h> // for timer_t
|
||
# include <time.h> // for size_t, CLOCK_MONOTONIC, itimerspec, ...
|
||
# ifdef HAVE_UNISTD_H
|
||
# include <unistd.h> // for getpid, syscall
|
||
# endif
|
||
# include <array>
|
||
+#endif
|
||
+
|
||
+#include <glib-object.h>
|
||
+#include <glib.h>
|
||
+
|
||
+#ifdef ENABLE_PROFILER
|
||
# ifdef G_OS_UNIX
|
||
# include <glib-unix.h>
|
||
# endif
|
||
# include <sysprof-capture.h>
|
||
#endif
|
||
|
||
+#include <js/GCAPI.h> // for JSFinalizeStatus, JSGCStatus, GCReason
|
||
#include <js/ProfilingStack.h> // for EnableContextProfilingStack, ...
|
||
#include <js/TypeDecls.h>
|
||
#include <mozilla/Atomics.h> // 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 <cjs/gjs.h> can be included directly."
|
||
+# error "Only <gjs/gjs.h> can be included directly."
|
||
#endif
|
||
|
||
#include <glib-object.h>
|
||
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 <js/RootingAPI.h>
|
||
#include <js/TypeDecls.h>
|
||
#include <jsapi.h> // for JS_NewPlainObject
|
||
+#include <jsfriendapi.h> // 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 <config.h>
|
||
|
||
-#include <stdio.h> // for stderr, open_memstream
|
||
+#include <stdio.h> // for stderr
|
||
|
||
#include <sstream>
|
||
#include <string>
|
||
@@ -12,7 +12,9 @@
|
||
#include <glib-object.h>
|
||
#include <glib.h>
|
||
|
||
+#include <js/Printer.h>
|
||
#include <js/TypeDecls.h>
|
||
+#include <js/Utility.h> // for UniqueChars
|
||
#include <js/friend/DumpFunctions.h>
|
||
|
||
#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<JSContext *>(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<GList> contexts = gjs_context_get_all();
|
||
+ js::Sprinter printer;
|
||
GList *iter;
|
||
|
||
for (iter = contexts; iter; iter = iter->next) {
|
||
GjsAutoUnref<GjsContext> 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<JSContext*>(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 <memory> // for unique_ptr
|
||
#include <string> // for u16string
|
||
#include <tuple> // for tuple
|
||
+#include <utility> // for move
|
||
|
||
#include <gio/gio.h>
|
||
#include <glib-object.h>
|
||
@@ -40,7 +41,7 @@
|
||
#include <jspubtd.h> // for JSProto_InternalError
|
||
#include <mozilla/Maybe.h>
|
||
#include <mozilla/Span.h>
|
||
-#include <mozilla/Unused.h>
|
||
+#include <mozilla/UniquePtr.h>
|
||
|
||
#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<void, JS::BufferContentsDeleter> 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<int8_t>(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<GITypeInfo*>(&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<void*>(&state->out_cvalue(m_arg_pos));
|
||
- gjs_arg_set(arg, &gjs_arg_member<void*>(&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<T>().
|
||
+ 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<GenericOut*>(this)->m_type_info);
|
||
+ }
|
||
+ const GITypeInfo* return_type() const override { return &m_type_info; }
|
||
};
|
||
|
||
struct GenericReturn : ReturnValue {
|
||
@@ -358,6 +373,39 @@
|
||
}
|
||
};
|
||
|
||
+template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
|
||
+struct NumericOut : SkipAll, Positioned {
|
||
+ static_assert(std::is_arithmetic_v<T>, "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<T, TAG>(cx, gjs_arg_get<T>(arg),
|
||
+ value);
|
||
+ }
|
||
+};
|
||
+
|
||
+using BooleanOut = NumericOut<gboolean, GI_TYPE_TAG_BOOLEAN>;
|
||
+
|
||
+template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
|
||
+struct NumericReturn : SkipAll {
|
||
+ static_assert(std::is_arithmetic_v<T>, "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<T, TAG>(cx, gjs_arg_get<T>(arg),
|
||
+ value);
|
||
+ }
|
||
+ GITypeTag return_tag() const override { return TAG; }
|
||
+};
|
||
+
|
||
+using BooleanReturn = NumericReturn<gboolean, GI_TYPE_TAG_BOOLEAN>;
|
||
+
|
||
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 <typename T>
|
||
+struct NumericIn : SkipAll {
|
||
+ static_assert(std::is_arithmetic_v<T>, "Not arithmetic type");
|
||
bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
|
||
JS::HandleValue) override;
|
||
};
|
||
|
||
+template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
|
||
+struct NumericInOut : NumericIn<T>, Positioned {
|
||
+ static_assert(std::is_arithmetic_v<T>, "Not arithmetic type");
|
||
+ bool in(JSContext* cx, GjsFunctionCallState* state, GIArgument* arg,
|
||
+ JS::HandleValue value) override {
|
||
+ if (!NumericIn<T>::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<T, TAG>(cx, gjs_arg_get<T>(arg),
|
||
+ value);
|
||
+ }
|
||
+};
|
||
+
|
||
+using BooleanInOut = NumericInOut<gboolean, GI_TYPE_TAG_BOOLEAN>;
|
||
+
|
||
struct UnicharIn : SkipAll {
|
||
bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
|
||
JS::HandleValue) override;
|
||
@@ -641,26 +716,61 @@
|
||
JS::HandleValue) override;
|
||
};
|
||
|
||
-struct StringInTransferNone : NullableIn, String {
|
||
+template <GITypeTag TAG = GI_TYPE_TAG_UTF8>
|
||
+struct StringInTransferNone : NullableIn {
|
||
bool in(JSContext*, GjsFunctionCallState*, GIArgument*,
|
||
JS::HandleValue) override;
|
||
bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
|
||
GIArgument*) override;
|
||
};
|
||
|
||
-struct StringIn : StringInTransferNone {
|
||
+struct StringIn : StringInTransferNone<GI_TYPE_TAG_UTF8> {
|
||
bool release(JSContext*, GjsFunctionCallState*, GIArgument*,
|
||
GIArgument*) override {
|
||
return skip();
|
||
}
|
||
};
|
||
|
||
-struct FilenameInTransferNone : StringInTransferNone {
|
||
- FilenameInTransferNone() { m_filename = true; }
|
||
+template <GITransfer TRANSFER = GI_TRANSFER_NOTHING>
|
||
+struct StringOutBase : SkipAll {
|
||
+ bool out(JSContext* cx, GjsFunctionCallState*, GIArgument* arg,
|
||
+ JS::MutableHandleValue value) override {
|
||
+ return Gjs::c_value_to_js(cx, gjs_arg_get<char*>(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<char*>(out_arg), g_free);
|
||
+ return true;
|
||
+ } else {
|
||
+ return invalid(cx, G_STRFUNC);
|
||
+ }
|
||
+ }
|
||
+};
|
||
+
|
||
+template <GITransfer TRANSFER = GI_TRANSFER_NOTHING>
|
||
+struct StringReturn : StringOutBase<TRANSFER> {
|
||
+ 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 <GITransfer TRANSFER = GI_TRANSFER_NOTHING>
|
||
+struct StringOut : StringOutBase<TRANSFER>, Positioned {
|
||
+ bool in(JSContext*, GjsFunctionCallState* state, GIArgument* arg,
|
||
+ JS::HandleValue) override {
|
||
+ return set_out_parameter(state, arg);
|
||
+ }
|
||
};
|
||
|
||
+using FilenameInTransferNone = StringInTransferNone<GI_TYPE_TAG_FILENAME>;
|
||
+
|
||
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<void*>(&state->out_cvalue(ix));
|
||
gjs_arg_unset<void*>(&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 <typename T>
|
||
-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<T>::in(JSContext* cx,
|
||
+ GjsFunctionCallState*,
|
||
+ GIArgument* arg,
|
||
+ JS::HandleValue value) {
|
||
bool out_of_range = false;
|
||
|
||
if (!gjs_arg_set_from_js_value<T>(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<T>());
|
||
+ arg_name(), Gjs::static_type_name<T>());
|
||
}
|
||
|
||
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<T>(arg)).c_str(),
|
||
- Gjs::static_type_name<T>());
|
||
+ 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<T>(arg)).c_str(),
|
||
+ Gjs::static_type_name<T>());
|
||
|
||
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<int8_t>(cx, value, arg, this);
|
||
- case GI_TYPE_TAG_UINT8:
|
||
- return gjs_arg_set_from_js_value<uint8_t>(cx, value, arg, this);
|
||
- case GI_TYPE_TAG_INT16:
|
||
- return gjs_arg_set_from_js_value<int16_t>(cx, value, arg, this);
|
||
- case GI_TYPE_TAG_UINT16:
|
||
- return gjs_arg_set_from_js_value<uint16_t>(cx, value, arg, this);
|
||
- case GI_TYPE_TAG_INT32:
|
||
- return gjs_arg_set_from_js_value<int32_t>(cx, value, arg, this);
|
||
- case GI_TYPE_TAG_DOUBLE:
|
||
- return gjs_arg_set_from_js_value<double>(cx, value, arg, this);
|
||
- case GI_TYPE_TAG_FLOAT:
|
||
- return gjs_arg_set_from_js_value<float>(cx, value, arg, this);
|
||
- case GI_TYPE_TAG_INT64:
|
||
- return gjs_arg_set_from_js_value<int64_t>(cx, value, arg, this);
|
||
- case GI_TYPE_TAG_UINT64:
|
||
- return gjs_arg_set_from_js_value<uint64_t>(cx, value, arg, this);
|
||
- case GI_TYPE_TAG_UINT32:
|
||
- return gjs_arg_set_from_js_value<uint32_t>(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 <GITypeTag TAG>
|
||
+GJS_JSAPI_RETURN_CONVENTION bool StringInTransferNone<TAG>::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<void*>(original_out_arg) != gjs_arg_get<void*>(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<void*>(original_out_arg) != gjs_arg_get<void*>(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 <GITypeTag TAG>
|
||
+GJS_JSAPI_RETURN_CONVENTION bool StringInTransferNone<TAG>::release(
|
||
+ JSContext*, GjsFunctionCallState*, GIArgument* in_arg,
|
||
+ GIArgument* out_arg [[maybe_unused]]) {
|
||
g_free(gjs_arg_get<void*>(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 <typename T>
|
||
constexpr size_t argument_maximum_size() {
|
||
- if constexpr (std::is_same_v<T, Arg::NumericIn>)
|
||
+ if constexpr (std::is_same_v<T, Arg::NumericIn<int>>)
|
||
return 24;
|
||
if constexpr (std::is_same_v<T, Arg::ObjectIn> ||
|
||
std::is_same_v<T, Arg::BoxedIn>)
|
||
@@ -1582,7 +1757,7 @@
|
||
if constexpr (std::is_base_of_v<Arg::Transferable, T>)
|
||
arg->m_transfer = transfer;
|
||
|
||
- if constexpr (std::is_base_of_v<Arg::TypeInfo, T> &&
|
||
+ if constexpr (std::is_base_of_v<Arg::HasTypeInfo, T> &&
|
||
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<GITypeInfo*>(rval->as_return_value()->type_info());
|
||
+ return const_cast<GITypeInfo*>(rval->return_type());
|
||
}
|
||
|
||
constexpr void ArgsCache::set_skip_all(uint8_t index, const char* name) {
|
||
@@ -1734,7 +1917,8 @@
|
||
static_cast<GjsArgumentFlags>(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<Arg::Kind::RETURN_VALUE>(
|
||
- 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<Arg::BooleanReturn>(&type_info, transfer, flags);
|
||
return;
|
||
+
|
||
+ case GI_TYPE_TAG_INT8:
|
||
+ set_return<Arg::NumericReturn<int8_t, GI_TYPE_TAG_INT8>>(
|
||
+ &type_info, transfer, flags);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_INT16:
|
||
+ set_return<Arg::NumericReturn<int16_t, GI_TYPE_TAG_INT16>>(
|
||
+ &type_info, transfer, flags);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_INT32:
|
||
+ set_return<Arg::NumericReturn<int32_t, GI_TYPE_TAG_INT32>>(
|
||
+ &type_info, transfer, flags);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_UINT8:
|
||
+ set_return<Arg::NumericReturn<uint8_t, GI_TYPE_TAG_UINT8>>(
|
||
+ &type_info, transfer, flags);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_UINT16:
|
||
+ set_return<Arg::NumericReturn<uint16_t, GI_TYPE_TAG_UINT16>>(
|
||
+ &type_info, transfer, flags);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_UINT32:
|
||
+ set_return<Arg::NumericReturn<uint32_t, GI_TYPE_TAG_UINT32>>(
|
||
+ &type_info, transfer, flags);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_INT64:
|
||
+ set_return<Arg::NumericReturn<int64_t, GI_TYPE_TAG_INT64>>(
|
||
+ &type_info, transfer, flags);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_UINT64:
|
||
+ set_return<Arg::NumericReturn<uint64_t, GI_TYPE_TAG_UINT64>>(
|
||
+ &type_info, transfer, flags);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_FLOAT:
|
||
+ set_return<Arg::NumericReturn<float, GI_TYPE_TAG_FLOAT>>(
|
||
+ &type_info, transfer, flags);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_DOUBLE:
|
||
+ set_return<Arg::NumericReturn<double, GI_TYPE_TAG_DOUBLE>>(
|
||
+ &type_info, transfer, flags);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_UTF8:
|
||
+ if (transfer == GI_TRANSFER_NOTHING) {
|
||
+ set_return<Arg::StringReturn<GI_TRANSFER_NOTHING>>(
|
||
+ &type_info, transfer, flags);
|
||
+ return;
|
||
+ } else {
|
||
+ set_return<Arg::StringReturn<GI_TRANSFER_EVERYTHING>>(
|
||
+ &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<Arg::Kind::RETURN_VALUE>(
|
||
+ 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<Arg::NumericIn<int8_t>>(common_args);
|
||
+ return;
|
||
+
|
||
case GI_TYPE_TAG_INT16:
|
||
+ set_argument_auto<Arg::NumericIn<int16_t>>(common_args);
|
||
+ return;
|
||
+
|
||
case GI_TYPE_TAG_INT32:
|
||
+ set_argument_auto<Arg::NumericIn<int32_t>>(common_args);
|
||
+ return;
|
||
+
|
||
case GI_TYPE_TAG_UINT8:
|
||
+ set_argument_auto<Arg::NumericIn<uint8_t>>(common_args);
|
||
+ return;
|
||
+
|
||
case GI_TYPE_TAG_UINT16:
|
||
+ set_argument_auto<Arg::NumericIn<uint16_t>>(common_args);
|
||
+ return;
|
||
+
|
||
case GI_TYPE_TAG_UINT32:
|
||
+ set_argument_auto<Arg::NumericIn<uint32_t>>(common_args);
|
||
+ return;
|
||
+
|
||
case GI_TYPE_TAG_INT64:
|
||
+ set_argument_auto<Arg::NumericIn<int64_t>>(common_args);
|
||
+ return;
|
||
+
|
||
case GI_TYPE_TAG_UINT64:
|
||
+ set_argument_auto<Arg::NumericIn<uint64_t>>(common_args);
|
||
+ return;
|
||
+
|
||
case GI_TYPE_TAG_FLOAT:
|
||
+ set_argument_auto<Arg::NumericIn<float>>(common_args);
|
||
+ return;
|
||
+
|
||
case GI_TYPE_TAG_DOUBLE:
|
||
- set_argument_auto<Arg::NumericIn>(common_args, tag);
|
||
- break;
|
||
+ set_argument_auto<Arg::NumericIn<double>>(common_args);
|
||
+ return;
|
||
|
||
case GI_TYPE_TAG_UNICHAR:
|
||
set_argument_auto<Arg::UnicharIn>(common_args);
|
||
@@ -2049,7 +2335,8 @@
|
||
|
||
case GI_TYPE_TAG_UTF8:
|
||
if (transfer == GI_TRANSFER_NOTHING)
|
||
- set_argument_auto<Arg::StringInTransferNone>(common_args);
|
||
+ set_argument_auto<Arg::StringInTransferNone<GI_TYPE_TAG_UTF8>>(
|
||
+ common_args);
|
||
else
|
||
set_argument_auto<Arg::StringIn>(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<Arg::BooleanOut>(common_args);
|
||
+ break;
|
||
+
|
||
+ case GI_TYPE_TAG_INT8:
|
||
+ set_argument_auto<Arg::NumericOut<int8_t>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_INT16:
|
||
+ set_argument_auto<Arg::NumericOut<int16_t>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_INT32:
|
||
+ set_argument_auto<Arg::NumericOut<int32_t>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_UINT8:
|
||
+ set_argument_auto<Arg::NumericOut<uint8_t>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_UINT16:
|
||
+ set_argument_auto<Arg::NumericOut<uint16_t>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_UINT32:
|
||
+ set_argument_auto<Arg::NumericOut<uint32_t>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_INT64:
|
||
+ set_argument_auto<Arg::NumericOut<int64_t>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_UINT64:
|
||
+ set_argument_auto<Arg::NumericOut<uint64_t>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_FLOAT:
|
||
+ set_argument_auto<Arg::NumericOut<float>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_DOUBLE:
|
||
+ set_argument_auto<Arg::NumericOut<double>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_UTF8:
|
||
+ if (transfer == GI_TRANSFER_NOTHING) {
|
||
+ set_argument_auto<Arg::StringOut<GI_TRANSFER_NOTHING>>(
|
||
+ common_args);
|
||
+ } else {
|
||
+ set_argument_auto<Arg::StringOut<GI_TRANSFER_EVERYTHING>>(
|
||
+ common_args);
|
||
+ }
|
||
+ return;
|
||
+
|
||
+ default:
|
||
+ set_argument_auto<Arg::FallbackOut>(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<Arg::BooleanInOut>(common_args);
|
||
+ break;
|
||
+
|
||
+ case GI_TYPE_TAG_INT8:
|
||
+ set_argument_auto<Arg::NumericInOut<int8_t>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_INT16:
|
||
+ set_argument_auto<Arg::NumericInOut<int16_t>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_INT32:
|
||
+ set_argument_auto<Arg::NumericInOut<int32_t>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_UINT8:
|
||
+ set_argument_auto<Arg::NumericInOut<uint8_t>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_UINT16:
|
||
+ set_argument_auto<Arg::NumericInOut<uint16_t>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_UINT32:
|
||
+ set_argument_auto<Arg::NumericInOut<uint32_t>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_INT64:
|
||
+ set_argument_auto<Arg::NumericInOut<int64_t>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_UINT64:
|
||
+ set_argument_auto<Arg::NumericInOut<uint64_t>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_FLOAT:
|
||
+ set_argument_auto<Arg::NumericInOut<float>>(common_args);
|
||
+ return;
|
||
+
|
||
+ case GI_TYPE_TAG_DOUBLE:
|
||
+ set_argument_auto<Arg::NumericInOut<double>>(common_args);
|
||
+ return;
|
||
+
|
||
+ default:
|
||
+ set_argument_auto<Arg::FallbackInOut>(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<Arg::ZeroTerminatedArrayIn>(common_args);
|
||
+ return;
|
||
+ } else if (direction == GI_DIRECTION_INOUT) {
|
||
+ set_argument_auto<Arg::ZeroTerminatedArrayInOut>(common_args);
|
||
+ return;
|
||
+ }
|
||
+ } else if (g_type_info_get_array_fixed_size(&type_info) >= 0) {
|
||
+ if (direction == GI_DIRECTION_IN) {
|
||
+ set_argument_auto<Arg::FixedSizeArrayIn>(common_args);
|
||
+ return;
|
||
+ } else if (direction == GI_DIRECTION_INOUT) {
|
||
+ set_argument_auto<Arg::FixedSizeArrayInOut>(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<Arg::FallbackInOut>(common_args);
|
||
+ build_normal_inout_arg(gi_index, &type_info, arg, flags);
|
||
else
|
||
- set_argument_auto<Arg::FallbackOut>(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 <Arg::Kind ArgKind = Arg::Kind::NORMAL>
|
||
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 <config.h>
|
||
+
|
||
#include <stdint.h>
|
||
|
||
#include <cstddef> // for nullptr_t
|
||
@@ -114,6 +116,20 @@
|
||
}
|
||
}
|
||
|
||
+typedef enum {
|
||
+ GJS_TYPE_TAG_LONG = 0,
|
||
+} ExtraTag;
|
||
+
|
||
+template <typename T, ExtraTag TAG>
|
||
+[[nodiscard]] constexpr inline decltype(auto) gjs_arg_member(GIArgument* arg) {
|
||
+ if constexpr (TAG == GJS_TYPE_TAG_LONG &&
|
||
+ std::is_same_v<T, long>) // NOLINT(runtime/int)
|
||
+ return gjs_arg_member<&GIArgument::v_long>(arg);
|
||
+ else if constexpr (TAG == GJS_TYPE_TAG_LONG &&
|
||
+ std::is_same_v<T, unsigned long>) // NOLINT(runtime/int)
|
||
+ return gjs_arg_member<&GIArgument::v_ulong>(arg);
|
||
+}
|
||
+
|
||
template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
|
||
constexpr inline void gjs_arg_set(GIArgument* arg, T v) {
|
||
if constexpr (std::is_pointer_v<T>) {
|
||
@@ -129,6 +145,11 @@
|
||
}
|
||
}
|
||
|
||
+template <typename T, ExtraTag TAG>
|
||
+constexpr inline void gjs_arg_set(GIArgument* arg, T v) {
|
||
+ gjs_arg_member<T, TAG>(arg) = v;
|
||
+}
|
||
+
|
||
// Store function pointers as void*. It is a requirement of GLib that your
|
||
// compiler can do this
|
||
template <typename ReturnT, typename... Args>
|
||
@@ -151,6 +172,11 @@
|
||
return gjs_arg_member<T, TAG>(arg);
|
||
}
|
||
|
||
+template <typename T, ExtraTag TAG>
|
||
+[[nodiscard]] constexpr inline T gjs_arg_get(GIArgument* arg) {
|
||
+ return gjs_arg_member<T, TAG>(arg);
|
||
+}
|
||
+
|
||
template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
|
||
[[nodiscard]] constexpr inline void* gjs_arg_get_as_pointer(GIArgument* arg) {
|
||
return gjs_int_to_pointer(gjs_arg_get<T, TAG>(arg));
|
||
@@ -192,29 +218,29 @@
|
||
return static_cast<double>(val);
|
||
}
|
||
|
||
-template <typename T>
|
||
+template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
|
||
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<T>())
|
||
- return Gjs::js_value_to_c(cx, value, &gjs_arg_member<T>(arg));
|
||
+ return Gjs::js_value_to_c<TAG>(cx, value, &gjs_arg_member<T, TAG>(arg));
|
||
|
||
Gjs::JsValueHolder::Relaxed<T> val{};
|
||
|
||
- if (!Gjs::js_value_to_c_checked<T>(cx, value, &val, out_of_range))
|
||
+ if (!Gjs::js_value_to_c_checked<T, TAG>(cx, value, &val, out_of_range))
|
||
return false;
|
||
|
||
if (*out_of_range)
|
||
return false;
|
||
|
||
- gjs_arg_set<T>(arg, val);
|
||
+ gjs_arg_set<T, TAG>(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<const char*>() {
|
||
+ return "constant string";
|
||
+}
|
||
+
|
||
+template <>
|
||
+inline const char* static_type_name<void>() {
|
||
+ 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 <config.h>
|
||
|
||
+#include <inttypes.h>
|
||
#include <stdint.h>
|
||
#include <string.h> // for strcmp, strlen, memcpy
|
||
|
||
#include <string>
|
||
-#include <type_traits>
|
||
|
||
#include <girepository.h>
|
||
#include <glib-object.h>
|
||
@@ -32,6 +32,7 @@
|
||
#include <js/ValueArray.h>
|
||
#include <js/experimental/TypedData.h>
|
||
#include <jsapi.h> // for InformalValueTypeName, IdVector
|
||
+#include <mozilla/Unused.h>
|
||
|
||
#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<GFlagsClass> 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<void*>(&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<GValue>(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 <bool zero_terminated = false>
|
||
-static inline bool gjs_g_argument_release_array_internal(
|
||
+enum class ArrayReleaseType {
|
||
+ EXPLICIT_LENGTH,
|
||
+ ZERO_TERMINATED,
|
||
+};
|
||
+
|
||
+template <ArrayReleaseType release_type = ArrayReleaseType::EXPLICIT_LENGTH>
|
||
+static inline bool gjs_gi_argument_release_array_internal(
|
||
JSContext* cx, GITransfer element_transfer, GjsArgumentFlags flags,
|
||
GITypeInfo* param_type, unsigned length, GIArgument* arg) {
|
||
GjsAutoPointer<uint8_t, void, g_free> arg_array =
|
||
gjs_arg_steal<uint8_t*>(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<uint8_t**>(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<uint8_t**>(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 <typename T>
|
||
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<void*>(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<void*>(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<T, GList> || std::is_same_v<T, GSList>);
|
||
- 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<T, TAG>(arg, *(static_cast<T*>(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<char*>(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<char*>(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<GValue>(
|
||
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<float>(arg));
|
||
+ value_p.setNumber(JS::CanonicalizeNaN(gjs_arg_get<float>(arg)));
|
||
break;
|
||
|
||
case GI_TYPE_TAG_DOUBLE:
|
||
- value_p.setNumber(gjs_arg_get<double>(arg));
|
||
+ value_p.setNumber(JS::CanonicalizeNaN(gjs_arg_get<double>(arg)));
|
||
break;
|
||
|
||
case GI_TYPE_TAG_GTYPE:
|
||
{
|
||
GType gtype = gjs_arg_get<GType, GI_TYPE_TAG_GTYPE>(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<const char*>(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<GError*>(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<int, GI_TYPE_TAG_INTERFACE>(arg));
|
||
|
||
- gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*)interface_info);
|
||
+ GType gtype = g_registered_type_info_get_g_type(
|
||
+ interface_info.as<GIRegisteredTypeInfo>());
|
||
|
||
if (gtype != G_TYPE_NONE) {
|
||
/* check make sure 32 bit flag */
|
||
- if (static_cast<uint32_t>(value_int64) != value_int64) { /* Not a guint32 */
|
||
+ if (static_cast<uint32_t>(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<GIStructInfo>())) {
|
||
+ 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<GIStructInfo>())) {
|
||
/* 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<GTypeClass*>(arg));
|
||
+ GType gtype = G_TYPE_FROM_CLASS(gjs_arg_get<GTypeClass*>(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<GIRegisteredTypeInfo>());
|
||
if (G_TYPE_IS_INSTANTIATABLE(gtype) ||
|
||
G_TYPE_IS_INTERFACE(gtype))
|
||
gtype = G_TYPE_FROM_INSTANCE(gjs_arg_get<GTypeInstance*>(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<char*>(&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<GIUnionInfo*>(interface_info),
|
||
+ context, interface_info.as<GIUnionInfo>(),
|
||
gjs_arg_get<void*>(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<void*>(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<GIStructInfo>()))
|
||
+ 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<void*>(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<GIRegisteredTypeInfo>());
|
||
if (G_TYPE_IS_INSTANTIATABLE(gtype) ||
|
||
G_TYPE_IS_INTERFACE(gtype))
|
||
gtype = G_TYPE_FROM_INSTANCE(gjs_arg_get<GTypeInstance*>(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<void*>(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<void*>(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<true>(
|
||
+ 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<false>(
|
||
+ 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<GIStructInfo*>(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<GIStructInfo*>(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<GIStructInfo>());
|
||
@@ -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 <config.h>
|
||
|
||
-#include <glib-object.h>
|
||
#include <stddef.h>
|
||
|
||
+#include <glib-object.h>
|
||
+
|
||
#include <js/TypeDecls.h>
|
||
|
||
#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<Closure>();
|
||
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<JSObject*> 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 <js/CallArgs.h>
|
||
#include <js/Class.h>
|
||
#include <js/ErrorReport.h> // for JSEXN_TYPEERR
|
||
+#include <js/GCVector.h> // for MutableHandleIdVector
|
||
#include <js/GlobalObject.h> // for CurrentGlobalOrNull
|
||
#include <js/Id.h>
|
||
#include <js/Object.h> // 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 <config.h>
|
||
|
||
+#include <inttypes.h>
|
||
+
|
||
#include <girepository.h>
|
||
#include <glib-object.h>
|
||
#include <glib.h>
|
||
@@ -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 <config.h>
|
||
|
||
-#include <string.h> // for strcmp
|
||
+#include <stddef.h> // for size_t
|
||
+
|
||
#include <string>
|
||
+#include <unordered_map>
|
||
+#include <utility> // for pair
|
||
|
||
#include <girepository.h>
|
||
#include <glib.h>
|
||
|
||
+#include <js/RootingAPI.h>
|
||
#include <js/TypeDecls.h>
|
||
|
||
#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<std::string, LoadedStatus> foreign_modules{
|
||
+ {"cairo", NotLoaded}};
|
||
+
|
||
+using StructID = std::pair<std::string, std::string>;
|
||
+struct StructIDHash {
|
||
+ [[nodiscard]] size_t operator()(StructID val) const {
|
||
+ std::hash<std::string> hasher;
|
||
+ return hasher(val.first) ^ hasher(val.second);
|
||
}
|
||
-
|
||
- return foreign_structs_table;
|
||
-}
|
||
+};
|
||
+static std::unordered_map<StructID, GjsForeignInfo*, StructIDHash>
|
||
+ 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(),
|
||
- "<internal>", &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(),
|
||
+ "<internal>", &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<GjsForeignInfo*>(
|
||
- 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<GjsForeignInfo*>(
|
||
- 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 <girepository.h>
|
||
|
||
-#include <js/RootingAPI.h>
|
||
#include <js/TypeDecls.h>
|
||
#include <js/Value.h>
|
||
|
||
#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 <js/Class.h>
|
||
#include <js/ErrorReport.h> // for JS_ReportOutOfMemory
|
||
#include <js/Exception.h>
|
||
+#include <js/HeapAPI.h> // for RuntimeHeapIsCollecting
|
||
#include <js/PropertyAndElement.h>
|
||
#include <js/PropertyDescriptor.h> // for JSPROP_PERMANENT
|
||
#include <js/PropertySpec.h>
|
||
#include <js/Realm.h> // for GetRealmFunctionPrototype
|
||
#include <js/RootingAPI.h>
|
||
-#include <js/String.h>
|
||
#include <js/TypeDecls.h>
|
||
#include <js/Value.h>
|
||
#include <js/ValueArray.h>
|
||
#include <js/Warnings.h>
|
||
-#include <jsapi.h> // for HandleValueArray
|
||
-#include <jsfriendapi.h> // for JS_GetObjectFunction
|
||
-#include <jspubtd.h> // for JSProtoKey
|
||
+#include <jsapi.h> // for HandleValueArray
|
||
+#include <jspubtd.h> // 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<GIArgument**>(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<void*>(return_value);
|
||
+ switch (tag) {
|
||
+ case GI_TYPE_TAG_VOID:
|
||
+ return nullptr;
|
||
case GI_TYPE_TAG_INT8:
|
||
return &gjs_arg_member<int8_t>(return_value);
|
||
case GI_TYPE_TAG_INT16:
|
||
@@ -875,9 +861,12 @@
|
||
case GI_TYPE_TAG_DOUBLE:
|
||
return &gjs_arg_member<double>(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<int, GI_TYPE_TAG_INTERFACE>(
|
||
@@ -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 <girepository.h>
|
||
#include <glib.h>
|
||
|
||
-#include <js/AllocPolicy.h> // for SystemAllocPolicy
|
||
#include <js/Class.h>
|
||
#include <js/ErrorReport.h> // for JS_ReportOutOfMemory
|
||
#include <js/GCHashTable.h> // for WeakCache
|
||
-#include <js/HashTable.h> // for DefaultHasher via WeakCache
|
||
#include <js/Object.h> // for GetClass
|
||
#include <js/PropertyAndElement.h>
|
||
#include <js/RootingAPI.h>
|
||
@@ -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 <js/CallAndConstruct.h>
|
||
#include <js/CallArgs.h>
|
||
#include <js/Class.h>
|
||
+#include <js/ColumnNumber.h>
|
||
#include <js/Exception.h>
|
||
#include <js/PropertyAndElement.h>
|
||
#include <js/PropertyDescriptor.h> // 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 <config.h>
|
||
+
|
||
#include <vector>
|
||
|
||
#include <glib-object.h>
|
||
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 <glib-object.h>
|
||
#include <glib.h>
|
||
|
||
-#include <js/AllocPolicy.h> // for SystemAllocPolicy
|
||
#include <js/CallArgs.h>
|
||
#include <js/Class.h>
|
||
#include <js/GCHashTable.h> // for WeakCache
|
||
-#include <js/HashTable.h> // for DefaultHasher via WeakCache
|
||
#include <js/PropertyAndElement.h>
|
||
#include <js/PropertyDescriptor.h> // for JSPROP_PERMANENT
|
||
#include <js/PropertySpec.h>
|
||
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 <js/Class.h>
|
||
#include <js/ErrorReport.h> // for JS_ReportOutOfMemory
|
||
+#include <js/GCVector.h> // for MutableHandleIdVector
|
||
#include <js/Id.h> // for PropertyKey, jsid
|
||
#include <js/TypeDecls.h>
|
||
#include <js/Utility.h> // 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<GType, void, &g_free> 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 <cmath> // for isnan
|
||
#include <limits>
|
||
+#include <string>
|
||
|
||
#include <girepository.h>
|
||
#include <glib-object.h>
|
||
@@ -20,6 +21,7 @@
|
||
#include <js/RootingAPI.h>
|
||
#include <js/TypeDecls.h>
|
||
#include <js/Utility.h> // for UniqueChars
|
||
+#include <js/Value.h> // for CanonicalizeNaN
|
||
|
||
#include "gi/gtype.h"
|
||
#include "gi/value.h"
|
||
@@ -229,7 +231,7 @@
|
||
return std::numeric_limits<BigT>::lowest();
|
||
}
|
||
|
||
-template <typename WantedType, typename T>
|
||
+template <typename WantedType, GITypeTag TAG = GI_TYPE_TAG_VOID, typename T>
|
||
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<T>::max() >=
|
||
@@ -266,7 +268,7 @@
|
||
}
|
||
|
||
if constexpr (std::is_same_v<WantedType, T>)
|
||
- return js_value_to_c(cx, value, out);
|
||
+ return js_value_to_c<TAG>(cx, value, out);
|
||
|
||
// JS::ToIntNN() converts undefined, NaN, infinity to 0
|
||
if constexpr (std::is_integral_v<WantedType>) {
|
||
@@ -278,7 +280,7 @@
|
||
}
|
||
|
||
if constexpr (std::is_arithmetic_v<T>) {
|
||
- bool ret = js_value_to_c(cx, value, out);
|
||
+ bool ret = js_value_to_c<TAG>(cx, value, out);
|
||
if (out_of_range) {
|
||
// Infinity and NaN preserved between floating point types
|
||
if constexpr (std::is_floating_point_v<WantedType> &&
|
||
@@ -300,18 +302,20 @@
|
||
*out_of_range |= std::isnan(*out);
|
||
}
|
||
return ret;
|
||
+ // https://trac.cppcheck.net/ticket/10731
|
||
+ // cppcheck-suppress missingReturn
|
||
}
|
||
}
|
||
|
||
-template <typename WantedType>
|
||
+template <typename WantedType, GITypeTag TAG = GI_TYPE_TAG_VOID>
|
||
GJS_JSAPI_RETURN_CONVENTION inline bool js_value_to_c_checked(
|
||
JSContext* cx, const JS::HandleValue& value, TypeWrapper<WantedType>* out,
|
||
bool* out_of_range) {
|
||
static_assert(std::is_integral_v<WantedType>);
|
||
|
||
WantedType wanted_out;
|
||
- if (!js_value_to_c_checked<WantedType>(cx, value, &wanted_out,
|
||
- out_of_range))
|
||
+ if (!js_value_to_c_checked<WantedType, TAG>(cx, value, &wanted_out,
|
||
+ out_of_range))
|
||
return false;
|
||
|
||
*out = TypeWrapper<WantedType>{wanted_out};
|
||
@@ -319,4 +323,61 @@
|
||
return true;
|
||
}
|
||
|
||
+template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
|
||
+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<T, bool>) {
|
||
+ 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<T>) {
|
||
+ if constexpr (std::is_same_v<T, int64_t> ||
|
||
+ std::is_same_v<T, uint64_t>) {
|
||
+ if (value < Gjs::min_safe_big_number<T>() ||
|
||
+ value > Gjs::max_safe_big_number<T>()) {
|
||
+ js_value_p.setDouble(value);
|
||
+ return true;
|
||
+ }
|
||
+ }
|
||
+ if constexpr (std::is_floating_point_v<T>) {
|
||
+ js_value_p.setDouble(JS::CanonicalizeNaN(double{value}));
|
||
+ return true;
|
||
+ }
|
||
+ js_value_p.setNumber(value);
|
||
+ return true;
|
||
+ } else if constexpr (std::is_same_v<T, // NOLINT(readability/braces)
|
||
+ char*> ||
|
||
+ std::is_same_v<T, const char*>) {
|
||
+ 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<T>, "Unsupported type");
|
||
+ }
|
||
+}
|
||
+
|
||
+template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
|
||
+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<T, int64_t> || std::is_same_v<T, uint64_t>) {
|
||
+ if (value < Gjs::min_safe_big_number<T>() ||
|
||
+ value > Gjs::max_safe_big_number<T>()) {
|
||
+ 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<T, TAG>(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 <config.h>
|
||
|
||
+#include <string.h>
|
||
+
|
||
+#include <vector>
|
||
+
|
||
#include <girepository.h>
|
||
#include <glib.h>
|
||
|
||
@@ -11,6 +15,7 @@
|
||
#include <js/Class.h>
|
||
#include <js/ComparisonOperators.h>
|
||
#include <js/ErrorReport.h> // for JS_ReportOutOfMemory
|
||
+#include <js/GCVector.h> // for MutableHandleIdVector
|
||
#include <js/Id.h>
|
||
#include <js/PropertyDescriptor.h> // for JSPROP_READONLY
|
||
#include <js/PropertySpec.h>
|
||
@@ -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<Ns>;
|
||
friend CWrapper<Ns>;
|
||
|
||
+#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<char*>(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 <config.h>
|
||
+
|
||
#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<uintptr_t>::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<GObjectClass> 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<GObjectClass> 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<GParamSpec*>(
|
||
+ 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<GParamSpec*>(
|
||
+ 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<GObjectClass> 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<GObjectClass> 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<GObjectClass> 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<const char*>* names,
|
||
- AutoGValueVector* values) {
|
||
+bool ObjectPrototype::props_to_g_parameters(
|
||
+ JSContext* context, GjsAutoTypeClass<GObjectClass> const& object_class,
|
||
+ JS::HandleObject props, std::vector<const char*>* 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<GClosure*>* 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<GObjectClass> object_class(gtype());
|
||
std::vector<const char *> 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<Gjs::AutoGValue*> 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<ObjectBase, ObjectPrototype, ObjectInstance>;
|
||
|
||
- using PropertyCache =
|
||
- JS::GCHashMap<JS::Heap<JSString*>, GjsAutoParam,
|
||
- js::DefaultHasher<JSString*>, js::SystemAllocPolicy>;
|
||
using FieldCache =
|
||
- JS::GCHashMap<JS::Heap<JSString*>, GjsAutoInfo<GI_INFO_TYPE_FIELD>,
|
||
+ JS::GCHashMap<JS::Heap<JSString*>, GjsAutoFieldInfo,
|
||
js::DefaultHasher<JSString*>, js::SystemAllocPolicy>;
|
||
using NegativeLookupCache =
|
||
JS::GCHashSet<JS::Heap<jsid>, 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<GObjectClass> 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<GObjectClass> const&,
|
||
+ JS::HandleObject props,
|
||
std::vector<const char*>* names,
|
||
AutoGValueVector* values);
|
||
|
||
@@ -293,7 +293,7 @@
|
||
|
||
// GIWrapperInstance::m_ptr may be null in ObjectInstance.
|
||
|
||
- GjsMaybeOwned<JSObject*> 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<GClosure*> 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 <js/CallArgs.h>
|
||
#include <js/Class.h>
|
||
#include <js/ErrorReport.h> // for JSEXN_TYPEERR
|
||
-#include <js/Object.h> // for GetClass
|
||
+#include <js/Object.h> // for GetClass
|
||
#include <js/PropertyAndElement.h>
|
||
+#include <js/PropertyDescriptor.h> // for JSPROP_READONLY
|
||
+#include <js/PropertySpec.h> // for JSPropertySpec, JS_PS_END, JS_STR...
|
||
#include <js/RootingAPI.h>
|
||
#include <js/TypeDecls.h>
|
||
#include <js/Utility.h> // 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 <glib-object.h>
|
||
#include <glib.h>
|
||
|
||
-#include <js/Array.h> // for JS::GetArrayLength,
|
||
+#include <js/Array.h> // for JS::GetArrayLength
|
||
+#include <js/CallAndConstruct.h> // for IsCallable
|
||
#include <js/CallArgs.h>
|
||
#include <js/PropertyAndElement.h>
|
||
#include <js/PropertySpec.h>
|
||
@@ -21,6 +22,7 @@
|
||
#include <js/ValueArray.h>
|
||
#include <jsapi.h> // 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 <config.h>
|
||
|
||
#include <girepository.h>
|
||
+#include <glib-object.h>
|
||
|
||
#include <js/TypeDecls.h>
|
||
|
||
@@ -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 <philip.chimento@gmail.com>
|
||
// SPDX-FileContributor: Marco Trevisan <marco.trevisan@canonical.com>
|
||
|
||
+#include <config.h>
|
||
+
|
||
#include <algorithm> // for find_if
|
||
#include <atomic>
|
||
#include <deque>
|
||
@@ -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 <glib.h> // for gboolean
|
||
+#include <config.h>
|
||
|
||
#include <atomic>
|
||
#include <deque>
|
||
#include <thread>
|
||
#include <utility> // for pair
|
||
|
||
+#include <glib.h> // 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 <stdint.h>
|
||
|
||
+#include <algorithm> // IWYU pragma: keep (for find)
|
||
#include <utility> // IWYU pragma: keep (for swap)
|
||
#include <vector>
|
||
|
||
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 <js/Conversions.h>
|
||
#include <js/Exception.h>
|
||
#include <js/GCVector.h> // for RootedVector
|
||
+#include <js/HeapAPI.h> // for RuntimeHeapIsCollecting
|
||
#include <js/Realm.h>
|
||
#include <js/RootingAPI.h>
|
||
#include <js/TypeDecls.h>
|
||
@@ -28,7 +29,6 @@
|
||
#include <js/ValueArray.h>
|
||
#include <js/experimental/TypedData.h>
|
||
#include <jsapi.h> // for InformalValueTypeName, JS_Get...
|
||
-#include <jsfriendapi.h> // 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<long, GJS_TYPE_TAG_LONG>( // NOLINT(runtime/int)
|
||
+ arg, g_value_get_long(value));
|
||
+ return true;
|
||
+ case G_TYPE_ULONG:
|
||
+ gjs_arg_set<unsigned long, // NOLINT(runtime/int)
|
||
+ GJS_TYPE_TAG_LONG>(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<GType, GI_TYPE_TAG_GTYPE>(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<ArgumentDetails> 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<GIStructInfo>())) {
|
||
+ 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<GValue*>(this) = G_VALUE_INIT;
|
||
+ this->steal();
|
||
*this = src;
|
||
g_value_unset(&src);
|
||
}
|
||
}
|
||
+ void steal() { *static_cast<GValue*>(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 <js/CallArgs.h>
|
||
#include <js/ComparisonOperators.h>
|
||
#include <js/ErrorReport.h> // for JSEXN_TYPEERR
|
||
+#include <js/GCVector.h> // for MutableHandleIdVector
|
||
#include <js/Id.h>
|
||
#include <js/MemoryFunctions.h>
|
||
#include <js/Object.h>
|
||
@@ -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 <config.h>
|
||
+
|
||
#include <string.h> // for strcmp
|
||
|
||
#include <gio/gio.h>
|
||
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 <philip.chimento@gmail.com>
|
||
+ */
|
||
+
|
||
+#include <config.h>
|
||
+
|
||
+#include <stdbool.h>
|
||
+#include <stddef.h> /* for NULL */
|
||
+#include <stdint.h>
|
||
+#include <sys/types.h> /* for ssize_t */
|
||
+
|
||
+#include <glib-object.h>
|
||
+#include <glib.h>
|
||
+
|
||
+#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 <philip.chimento@gmail.com>
|
||
+ */
|
||
+
|
||
+#pragma once
|
||
+
|
||
+#include <stdint.h>
|
||
+#include <sys/types.h> /* for ssize_t */
|
||
+
|
||
+#include <glib-object.h>
|
||
+#include <glib.h>
|
||
+
|
||
+#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<cairo_t*>(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 <cairo-features.h> // for CAIRO_HAS_PDF_SURFACE
|
||
#include <cairo.h>
|
||
|
||
-#include <js/TypeDecls.h>
|
||
-
|
||
-#include "cjs/jsapi-util.h"
|
||
-
|
||
#if CAIRO_HAS_PDF_SURFACE
|
||
# include <cairo-pdf.h>
|
||
+#endif
|
||
+
|
||
+#include <js/TypeDecls.h>
|
||
|
||
+#if CAIRO_HAS_PDF_SURFACE
|
||
# include <js/PropertyDescriptor.h> // for JSPROP_READONLY
|
||
# include <js/PropertySpec.h>
|
||
# include <js/RootingAPI.h>
|
||
-# include <jsapi.h> // for JS_NewObjectWithGivenProto
|
||
+# include <jsapi.h> // for JS_NewObjectWithGivenProto
|
||
# include <jspubtd.h> // 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 <cairo-features.h> // for CAIRO_HAS_PS_SURFACE
|
||
#include <cairo.h>
|
||
|
||
-#include <js/TypeDecls.h>
|
||
-
|
||
-#include "cjs/jsapi-util.h"
|
||
-
|
||
#if CAIRO_HAS_PS_SURFACE
|
||
# include <cairo-ps.h>
|
||
+#endif
|
||
+
|
||
+#include <js/TypeDecls.h>
|
||
|
||
+#if CAIRO_HAS_PS_SURFACE
|
||
# include <js/PropertyDescriptor.h> // for JSPROP_READONLY
|
||
# include <js/PropertySpec.h>
|
||
# include <js/RootingAPI.h>
|
||
-# include <jsapi.h> // for JS_NewObjectWithGivenProto
|
||
+# include <jsapi.h> // for JS_NewObjectWithGivenProto
|
||
# include <jspubtd.h> // 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<cairo_region_t*>(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<cairo_surface_t*>(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 <cairo-features.h> // for CAIRO_HAS_SVG_SURFACE
|
||
#include <cairo.h>
|
||
|
||
-#include <js/TypeDecls.h>
|
||
-
|
||
-#include "cjs/jsapi-util.h"
|
||
-
|
||
#if CAIRO_HAS_SVG_SURFACE
|
||
# include <cairo-svg.h>
|
||
+#endif
|
||
+
|
||
+#include <js/TypeDecls.h>
|
||
|
||
+#if CAIRO_HAS_SVG_SURFACE
|
||
# include <js/PropertyDescriptor.h> // for JSPROP_READONLY
|
||
# include <js/PropertySpec.h>
|
||
# include <js/RootingAPI.h>
|
||
-# include <jsapi.h> // for JS_NewObjectWithGivenProto
|
||
+# include <jsapi.h> // for JS_NewObjectWithGivenProto
|
||
# include <jspubtd.h> // 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 <cairo-features.h> // for CAIRO_HAS_PDF_SURFACE, CAIRO_HAS_PS_SURFA...
|
||
#include <cairo.h>
|
||
|
||
+#ifdef CAIRO_HAS_XLIB_SURFACE
|
||
+# include <cairo-xlib.h>
|
||
+# 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 <js/RootingAPI.h>
|
||
#include <js/TypeDecls.h>
|
||
#include <jsapi.h> // for JS_NewPlainObject
|
||
@@ -15,8 +22,6 @@
|
||
#include "modules/cairo-private.h"
|
||
|
||
#ifdef CAIRO_HAS_XLIB_SURFACE
|
||
-# include <cairo-xlib.h>
|
||
-
|
||
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 <philip.chimento@gmail.com>
|
||
|
||
-/* 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 <philip.chimento@gmail.com>
|
||
|
||
-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 <philip.chimento@gmail.com>, <philip@endlessm.com>
|
||
|
||
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 <config.h> // 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 <obj>
|
||
|
||
@@ -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 <philip.chimento@gmail.com>
|
||
+
|
||
+# 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 <config.h>" > 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 <stdlib.h>" > gjs/macros.h
|
||
+ expect_success
|
||
+
|
||
+ # config.h must be included
|
||
+ test_env
|
||
+ echo "#include <stdlib.h>" > gjs/program.c
|
||
+ expect_failure
|
||
+
|
||
+ # config.h is included first
|
||
+ test_env
|
||
+ echo '#include <config.h>' > gjs/program.c
|
||
+ echo '#include <stdlib.h>' >> gjs/program.c
|
||
+ expect_success
|
||
+
|
||
+ # config.h must be included first
|
||
+ test_env
|
||
+ echo '#include <stdlib.h>' > gjs/program.c
|
||
+ echo '#include <config.h>' >> gjs/program.c
|
||
+ expect_failure
|
||
+
|
||
+ # other non-include things can come before the include
|
||
+ test_env
|
||
+ cat > gjs/program.h <<EOF
|
||
+/* a comment */
|
||
+#pragma once
|
||
+#include <config.h>
|
||
+EOF
|
||
+ expect_success
|
||
+
|
||
+ # spaces are taken into account
|
||
+ test_env
|
||
+ cat > gjs/program.c <<EOF
|
||
+#ifdef UNIX
|
||
+# include <unix.h>
|
||
+#endif
|
||
+#include <config.h>
|
||
+EOF
|
||
+ expect_failure
|
||
+
|
||
+ # header blocks in right order
|
||
+ test_env
|
||
+ cat > gjs/program.c <<EOF
|
||
+#include <config.h>
|
||
+#include <stdint.h>
|
||
+#include <memory>
|
||
+#include <glib.h>
|
||
+#include <js/TypeDecls.h>
|
||
+#include "program.h"
|
||
+EOF
|
||
+ expect_success
|
||
+
|
||
+ # header blocks in wrong order
|
||
+ test_env
|
||
+ cat > gjs/program.c <<EOF
|
||
+#include <config.h>
|
||
+#include <memory>
|
||
+#include <glib.h>
|
||
+#include <js/TypeDecls.h>
|
||
+#include "program.h"
|
||
+#include <stdint.h>
|
||
+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]}" != "<config.h>" ]]; then
|
||
+ echo "Error: $file: include <config.h> 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 <stlib.h>" >> cjs/gjs_pch.hh
|
||
+ mkdir gjs gi
|
||
+ echo "#include <stlib.h>" >> gjs/gjs_pch.hh
|
||
}
|
||
|
||
expect_success() {
|
||
@@ -53,12 +53,12 @@
|
||
expect_failure
|
||
|
||
test_env
|
||
- echo "#include <invalid.h>" >> cjs/gjs_pch.hh
|
||
+ echo "#include <invalid.h>" >> gjs/gjs_pch.hh
|
||
echo "#include <stlib.h>" >> gi/code.c
|
||
expect_failure
|
||
|
||
test_env
|
||
- echo "#include <invalid.h> // check-pch: ignore, yes" >> cjs/gjs_pch.hh
|
||
+ echo "#include <invalid.h> // check-pch: ignore, yes" >> gjs/gjs_pch.hh
|
||
echo "#include <stlib.h>" >> gi/code.c
|
||
expect_success
|
||
|
||
@@ -74,14 +74,14 @@
|
||
|
||
test_env
|
||
echo "#include <stlib.h>" >> 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 <stlib.h>" >> gi/code.c
|
||
echo "# include <other/include.h>" >> gi/code.c
|
||
echo " # include <other/include.h>" >> gi/other-file.c
|
||
- echo "# include <other/include.h>" >> cjs/gjs_pch.hh
|
||
+ echo "# include <other/include.h>" >> gjs/gjs_pch.hh
|
||
expect_success
|
||
|
||
test_env
|
||
@@ -98,7 +98,7 @@
|
||
echo "#include <stlib.h>" >> gi/code.c
|
||
echo "//#include <invalid.h>" >> gi/invalid-file.c
|
||
echo "// #include <invalid.h>" >> gi/invalid-file.c
|
||
- echo "//#include <invalid.h>" >> cjs/gjs_pch.hh
|
||
+ echo "//#include <invalid.h>" >> 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 <config.h>
|
||
+
|
||
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 <sam@endlessm.com>
|
||
|
||
+#include <config.h>
|
||
+
|
||
#include <errno.h> // for errno
|
||
#include <stdio.h> // for sscanf, size_t
|
||
#include <stdlib.h> // 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 <marco.trevisan@canonical.com>
|
||
*/
|
||
|
||
-#include <glib-object.h>
|
||
-#include <glib.h>
|
||
+#include <config.h>
|
||
+
|
||
#include <stddef.h> // for NULL
|
||
+
|
||
#include <utility> // for move, swap
|
||
|
||
+#include <glib-object.h>
|
||
+#include <glib.h>
|
||
+
|
||
#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 <config.h>
|
||
+
|
||
#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 <config.h>
|
||
+
|
||
#include <glib-object.h>
|
||
|
||
#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<JSObject *> *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<JS::Value>();
|
||
- 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<JS::Value>();
|
||
- *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<JSObject *>();
|
||
+ 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<JSObject *>();
|
||
+ 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<GjsMaybeOwned<JSObject*>*>(data);
|
||
+ auto* obj = static_cast<GjsMaybeOwned*>(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<JSObject *>();
|
||
+ 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<JSObject *>();
|
||
+ 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<JSObject *>();
|
||
+ 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<JSObject *>();
|
||
+ 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<JSObject *>();
|
||
+ 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<JSObject *>();
|
||
+ 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<JSObject *>();
|
||
+ 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 <config.h>
|
||
|
||
-#include <algorithm> // for copy
|
||
#include <atomic>
|
||
#include <chrono>
|
||
#include <deque>
|
||
@@ -116,8 +115,7 @@
|
||
GjsAutoUnref<GObject> gobject(
|
||
G_OBJECT(g_object_new(G_TYPE_OBJECT, nullptr)));
|
||
auto* object = ObjectInstance::new_for_gobject(fx->cx, gobject);
|
||
- g_assert_true(
|
||
- static_cast<ObjectInstance*>(object)->ensure_uses_toggle_ref(fx->cx));
|
||
+ static_cast<ObjectInstance*>(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 <glib.h> // for g_assert_...
|
||
|
||
-#include "cjs/context.h"
|
||
-
|
||
#include <js/TypeDecls.h>
|
||
|
||
+#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 <config.h>
|
||
+
|
||
/* This file has to be valid C, because it's used in libgjs-private */
|
||
|
||
#include <stdbool.h> /* 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 <atomic> // for atomic_bool
|
||
-#include <memory> // for unique_ptr
|
||
-#include <string> // for string
|
||
+#include <config.h>
|
||
|
||
#include <errno.h>
|
||
-#include <fcntl.h> // for SEEK_END
|
||
#include <stdarg.h>
|
||
#include <stdio.h> // for FILE, fprintf, fflush, fopen, fputs, fseek
|
||
#include <string.h> // for strchr, strcmp
|
||
-#include "cjs/jsapi-util.h"
|
||
|
||
#ifdef _WIN32
|
||
# include <io.h>
|
||
@@ -24,9 +20,13 @@
|
||
#endif
|
||
|
||
#include <array>
|
||
+#include <atomic> // for atomic_bool
|
||
+#include <memory> // for unique_ptr
|
||
+#include <string> // for string
|
||
|
||
#include <glib.h>
|
||
|
||
+#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 <config.h>
|
||
+
|
||
/* 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 <config.h>
|
||
+
|
||
#include <glib.h>
|
||
|
||
#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 <config.h>
|
||
+
|
||
#include <errno.h>
|
||
#include <stdio.h> // for FILE, stdout
|
||
#include <string.h> // for memcpy
|