-
-
Save mgaudet/ae38a457d7d26b07f599e3f13f3b57e0 to your computer and use it in GitHub Desktop.
A rough approximation of the edits I expect to be made to GJS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| commit 124a7eb2820a07b98ec8d109fb57cbeb7f83962a | |
| Author: Matthew Gaudet <mgaudet@mozilla.com> | |
| Date: Tue Jan 13 15:06:36 2026 -0700 | |
| An example of how modifications to use the new microtask queue | |
| diff --git a/gjs/context-private.h b/gjs/context-private.h | |
| index 9e9a96a1..a5e1f3f5 100644 | |
| --- a/gjs/context-private.h | |
| +++ b/gjs/context-private.h | |
| @@ -92,7 +92,6 @@ class GjsContextPrivate : public JS::JobQueue { | |
| std::vector<std::string> m_args; | |
| - JobQueueStorage m_job_queue; | |
| Gjs::PromiseJobDispatcher m_dispatcher; | |
| Gjs::MainLoop m_main_loop; | |
| Gjs::AutoUnref<GMemoryMonitor> m_memory_monitor; | |
| @@ -275,12 +274,9 @@ class GjsContextPrivate : public JS::JobQueue { | |
| GJS_JSAPI_RETURN_CONVENTION | |
| bool getHostDefinedData(JSContext*, JS::MutableHandleObject) const override; | |
| GJS_JSAPI_RETURN_CONVENTION | |
| - bool enqueuePromiseJob(JSContext*, JS::HandleObject promise, | |
| - JS::HandleObject job, | |
| - JS::HandleObject allocation_site, | |
| - JS::HandleObject incumbent_global) override; | |
| + | |
| void runJobs(JSContext*) override; | |
| - [[nodiscard]] bool empty() const override { return m_job_queue.empty(); } | |
| + | |
| [[nodiscard]] | |
| bool isDrainingStopped() const override { | |
| return !m_draining_job_queue; | |
| diff --git a/gjs/context.cpp b/gjs/context.cpp | |
| index fb0eaba7..0f3832cd 100644 | |
| --- a/gjs/context.cpp | |
| +++ b/gjs/context.cpp | |
| @@ -65,6 +65,7 @@ | |
| #include <js/Utility.h> // for DeletePolicy via WeakCache | |
| #include <js/Value.h> | |
| #include <js/ValueArray.h> | |
| +#include <js/friend/MicroTask.h> | |
| #include <js/friend/DumpFunctions.h> | |
| #include <jsapi.h> // for JS_GetFunctionObject, JS_Ge... | |
| #include <jsfriendapi.h> // for ScriptEnvironmentPreparer | |
| @@ -365,7 +366,6 @@ void GjsContextPrivate::trace(JSTracer* trc, void* data) { | |
| "GJS internal global object"); | |
| 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); | |
| } | |
| @@ -482,7 +482,6 @@ void GjsContextPrivate::dispose() { | |
| delete m_gtype_table; | |
| delete m_atoms; | |
| - m_job_queue.clear(); | |
| m_object_init_list.clear(); | |
| // Tear down JS | |
| @@ -979,31 +978,6 @@ bool GjsContextPrivate::getHostDefinedData(JSContext* cx, | |
| return true; | |
| } | |
| -// See engine.cpp and JS::SetJobQueue(). | |
| -bool GjsContextPrivate::enqueuePromiseJob(JSContext* cx [[maybe_unused]], | |
| - JS::HandleObject promise, | |
| - JS::HandleObject job, | |
| - JS::HandleObject allocation_site, | |
| - JS::HandleObject incumbent_global | |
| - [[maybe_unused]]) { | |
| - g_assert(cx == m_cx); | |
| - g_assert(from_cx(cx) == this); | |
| - | |
| - gjs_debug(GJS_DEBUG_MAINLOOP, | |
| - "Enqueue job %s, promise=%s, allocation site=%s", | |
| - gjs_debug_object(job).c_str(), gjs_debug_object(promise).c_str(), | |
| - gjs_debug_object(allocation_site).c_str()); | |
| - | |
| - if (!m_job_queue.append(job)) { | |
| - JS_ReportOutOfMemory(m_cx); | |
| - return false; | |
| - } | |
| - | |
| - JS::JobQueueMayNotBeEmpty(m_cx); | |
| - m_dispatcher.start(); | |
| - return true; | |
| -} | |
| - | |
| // Override of JobQueue::runJobs(). Called by js::RunJobs(), and when execution | |
| // of the job queue was interrupted by the debugger and is resuming. | |
| void GjsContextPrivate::runJobs(JSContext* cx) { | |
| @@ -1036,11 +1010,11 @@ bool GjsContextPrivate::run_jobs_fallible() { | |
| JS::RootedObject job(m_cx); | |
| JS::HandleValueArray args(JS::HandleValueArray::empty()); | |
| JS::RootedValue rval(m_cx); | |
| + JS::RootedObject executionGlobal(m_cx); | |
| - if (m_job_queue.length() == 0) { | |
| + if (!JS::HasAnyMicroTasks(m_cx)) { | |
| // 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. | |
| + // no microtasks queued. This may enqueue more microtasks | |
| if (!run_finalization_registry_cleanup()) | |
| retval = false; | |
| } | |
| @@ -1048,7 +1022,7 @@ bool GjsContextPrivate::run_jobs_fallible() { | |
| /* 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. */ | |
| - for (size_t ix = 0; ix < m_job_queue.length(); ix++) { | |
| + while (JS::HasAnyMicroTasks(m_cx)) { | |
| // A previous job might have set this flag. e.g., System.exit(). | |
| if (m_should_exit || !m_dispatcher.is_running()) { | |
| gjs_debug(GJS_DEBUG_MAINLOOP, "Stopping jobs because of %s", | |
| @@ -1056,7 +1030,7 @@ bool GjsContextPrivate::run_jobs_fallible() { | |
| break; | |
| } | |
| - job = m_job_queue[ix]; | |
| + job = JS::DequeueNextMicroTask(m_cx); | |
| /* It's possible that job draining was interrupted prematurely, leaving | |
| * the queue partly processed. In that case, slots for already-executed | |
| @@ -1064,12 +1038,18 @@ bool GjsContextPrivate::run_jobs_fallible() { | |
| if (!job) | |
| continue; | |
| - m_job_queue[ix] = nullptr; | |
| + if (!JS::IsJSMicroTask(m_cx)) { | |
| + // crash! | |
| + } | |
| + | |
| + executionGlobal = JS::GetExecutionGlobalFromJSMicroTask(job); | |
| + | |
| + | |
| { | |
| - JSAutoRealm ar(m_cx, job); | |
| + JSAutoRealm ar(m_cx, executionGlobal); | |
| gjs_debug(GJS_DEBUG_MAINLOOP, "handling job %zu, %s", ix, | |
| gjs_debug_object(job).c_str()); | |
| - if (!JS::Call(m_cx, JS::UndefinedHandleValue, job, args, &rval)) { | |
| + if (!JS::RunJSMicroTask(m_cx, job)){ | |
| /* Uncatchable exception - return false so that System.exit() | |
| * works in the interactive shell and when exiting the | |
| * interpreter. */ | |
| @@ -1091,13 +1071,12 @@ bool GjsContextPrivate::run_jobs_fallible() { | |
| 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. | |
| + // may enqueue more microtasks | |
| if (!run_finalization_registry_cleanup()) | |
| retval = false; | |
| } | |
| m_draining_job_queue = false; | |
| - m_job_queue.clear(); | |
| warn_about_unhandled_promise_rejections(); | |
| JS::JobQueueIsEmpty(m_cx); | |
| return retval; | |
| @@ -1141,46 +1120,6 @@ bool GjsContextPrivate::run_finalization_registry_cleanup() { | |
| return retval; | |
| } | |
| -class GjsContextPrivate::SavedQueue : public JS::JobQueue::SavedJobQueue { | |
| - private: | |
| - GjsContextPrivate* m_gjs; | |
| - JS::PersistentRooted<JobQueueStorage> m_queue; | |
| - bool m_was_draining : 1; | |
| - | |
| - public: | |
| - explicit SavedQueue(GjsContextPrivate* gjs) | |
| - : m_gjs(gjs), | |
| - m_queue(gjs->m_cx, std::move(gjs->m_job_queue)), | |
| - m_was_draining(gjs->m_draining_job_queue) { | |
| - gjs_debug(GJS_DEBUG_CONTEXT, "Pausing job queue"); | |
| - gjs->stop_draining_job_queue(); | |
| - } | |
| - | |
| - ~SavedQueue() { | |
| - gjs_debug(GJS_DEBUG_CONTEXT, "Unpausing job queue"); | |
| - g_assert(m_gjs->m_job_queue.empty() && | |
| - "Current queue should be empty when restoring saved queue"); | |
| - m_gjs->m_job_queue = std::move(m_queue.get()); | |
| - m_gjs->m_draining_job_queue = m_was_draining; | |
| - m_gjs->start_draining_job_queue(); | |
| - } | |
| -}; | |
| - | |
| -js::UniquePtr<JS::JobQueue::SavedJobQueue> GjsContextPrivate::saveJobQueue( | |
| - JSContext* cx) { | |
| - g_assert(cx == m_cx); | |
| - g_assert(from_cx(cx) == this); | |
| - | |
| - auto saved_queue = js::MakeUnique<SavedQueue>(this); | |
| - if (!saved_queue) { | |
| - JS_ReportOutOfMemory(cx); | |
| - return nullptr; | |
| - } | |
| - | |
| - g_assert(m_job_queue.empty()); | |
| - return saved_queue; | |
| -} | |
| - | |
| void GjsContextPrivate::register_unhandled_promise_rejection( | |
| uint64_t id, JS::UniqueChars&& stack) { | |
| m_unhandled_rejection_stacks[id] = std::move(stack); | |
| diff --git a/subprojects/.wraplock b/subprojects/.wraplock | |
| new file mode 100644 | |
| index 00000000..e69de29b | |
| diff --git a/subprojects/gvdb.wrap b/subprojects/gvdb.wrap | |
| new file mode 100644 | |
| index 00000000..ff8b15fd | |
| --- /dev/null | |
| +++ b/subprojects/gvdb.wrap | |
| @@ -0,0 +1,2 @@ | |
| +[wrap-redirect] | |
| +filename = glib/subprojects/gvdb.wrap |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment