diff options
author | 2022-06-22 06:43:57 -0700 | |
---|---|---|
committer | 2022-06-22 06:56:47 -0700 | |
commit | 92aeb0af5594516d6444c9fcc69d56682e34771b (patch) | |
tree | 4ff007b8f345e1ccdf25839858bf104ada1cb5f0 /src | |
parent | 759bfadb933266de99c4bd7cf7c4c92b8dd97576 (diff) | |
download | bun-92aeb0af5594516d6444c9fcc69d56682e34771b.tar.gz bun-92aeb0af5594516d6444c9fcc69d56682e34771b.tar.zst bun-92aeb0af5594516d6444c9fcc69d56682e34771b.zip |
Add a way to schedule microtasks from C++
Diffstat (limited to 'src')
-rw-r--r-- | src/javascript/jsc/bindings/ScriptExecutionContext.h | 75 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/ZigGlobalObject.cpp | 11 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/ZigGlobalObject.h | 5 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/webcore/JSCallbackData.h | 4 | ||||
-rw-r--r-- | src/javascript/jsc/event_loop.zig | 17 |
5 files changed, 77 insertions, 35 deletions
diff --git a/src/javascript/jsc/bindings/ScriptExecutionContext.h b/src/javascript/jsc/bindings/ScriptExecutionContext.h index e5644c2fc..72837368e 100644 --- a/src/javascript/jsc/bindings/ScriptExecutionContext.h +++ b/src/javascript/jsc/bindings/ScriptExecutionContext.h @@ -14,8 +14,12 @@ namespace uWS { template<bool isServer, bool isClient, typename UserData> struct WebSocketContext; - } + +#ifndef ZIG_GLOBAL_OBJECT_DEFINED +#include "ZigGlobalObject.h" +#endif + struct us_socket_t; struct us_socket_context_t; struct us_loop_t; @@ -24,42 +28,48 @@ namespace WebCore { class WebSocket; -class ScriptExecutionContext : public CanMakeWeakPtr<ScriptExecutionContext> { -public: - class Task { - WTF_MAKE_FAST_ALLOCATED; +class ScriptExecutionContext; - public: - enum CleanupTaskTag { CleanupTask }; +class EventLoopTask { + WTF_MAKE_FAST_ALLOCATED; - template<typename T, typename = typename std::enable_if<!std::is_base_of<Task, T>::value && std::is_convertible<T, Function<void(ScriptExecutionContext&)>>::value>::type> - Task(T task) - : m_task(WTFMove(task)) - , m_isCleanupTask(false) - { - } +public: + enum CleanupTaskTag { CleanupTask }; - Task(Function<void()>&& task) - : m_task([task = WTFMove(task)](ScriptExecutionContext&) { task(); }) - , m_isCleanupTask(false) - { - } + template<typename T, typename = typename std::enable_if<!std::is_base_of<EventLoopTask, T>::value && std::is_convertible<T, Function<void(ScriptExecutionContext&)>>::value>::type> + EventLoopTask(T task) + : m_task(WTFMove(task)) + , m_isCleanupTask(false) + { + } - template<typename T, typename = typename std::enable_if<std::is_convertible<T, Function<void(ScriptExecutionContext&)>>::value>::type> - Task(CleanupTaskTag, T task) - : m_task(WTFMove(task)) - , m_isCleanupTask(true) - { - } + EventLoopTask(Function<void()>&& task) + : m_task([task = WTFMove(task)](ScriptExecutionContext&) { task(); }) + , m_isCleanupTask(false) + { + } - void performTask(ScriptExecutionContext& context) { m_task(context); } - bool isCleanupTask() const { return m_isCleanupTask; } + template<typename T, typename = typename std::enable_if<std::is_convertible<T, Function<void(ScriptExecutionContext&)>>::value>::type> + EventLoopTask(CleanupTaskTag, T task) + : m_task(WTFMove(task)) + , m_isCleanupTask(true) + { + } - protected: - Function<void(ScriptExecutionContext&)> m_task; - bool m_isCleanupTask; - }; + void performTask(ScriptExecutionContext& context) + { + m_task(context); + delete this; + } + bool isCleanupTask() const { return m_isCleanupTask; } +protected: + Function<void(ScriptExecutionContext&)> m_task; + bool m_isCleanupTask; +}; + +class ScriptExecutionContext : public CanMakeWeakPtr<ScriptExecutionContext> { +public: public: ScriptExecutionContext(JSC::VM* vm, JSC::JSGlobalObject* globalObject) : m_vm(vm) @@ -96,9 +106,10 @@ public: // { // } - void postTask(Task&& task) + void postTask(Function<void(ScriptExecutionContext&)>&& lambda) { - + auto* task = new EventLoopTask(WTFMove(lambda)); + reinterpret_cast<Zig::GlobalObject*>(m_globalObject)->queueTask(task); } // Executes the task on context's thread asynchronously. template<typename... Arguments> diff --git a/src/javascript/jsc/bindings/ZigGlobalObject.cpp b/src/javascript/jsc/bindings/ZigGlobalObject.cpp index 53872f325..e99f9a1cc 100644 --- a/src/javascript/jsc/bindings/ZigGlobalObject.cpp +++ b/src/javascript/jsc/bindings/ZigGlobalObject.cpp @@ -2107,6 +2107,17 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) visitor.addOpaqueRoot(context); } +extern "C" void Bun__queueMicrotask(JSC__JSGlobalObject*, WebCore::EventLoopTask* task); +extern "C" void Bun__performTask(Zig::GlobalObject* globalObject, WebCore::EventLoopTask* task) +{ + task->performTask(*globalObject->scriptExecutionContext()); +} + +void GlobalObject::queueTask(WebCore::EventLoopTask* task) +{ + Bun__queueMicrotask(this, task); +} + DEFINE_VISIT_CHILDREN(GlobalObject); // void GlobalObject::destroy(JSCell* cell) diff --git a/src/javascript/jsc/bindings/ZigGlobalObject.h b/src/javascript/jsc/bindings/ZigGlobalObject.h index 4f8a7871e..41556e639 100644 --- a/src/javascript/jsc/bindings/ZigGlobalObject.h +++ b/src/javascript/jsc/bindings/ZigGlobalObject.h @@ -13,6 +13,7 @@ class LazyClassStructure; namespace WebCore { class ScriptExecutionContext; class DOMGuardedObject; +class EventLoopTask; } #include "root.h" @@ -37,6 +38,8 @@ namespace Zig { using JSDOMStructureMap = HashMap<const JSC::ClassInfo*, JSC::WriteBarrier<JSC::Structure>>; using DOMGuardedObjectSet = HashSet<WebCore::DOMGuardedObject*>; +#define ZIG_GLOBAL_OBJECT_DEFINED + class GlobalObject : public JSC::JSGlobalObject { using Base = JSC::JSGlobalObject; @@ -111,6 +114,8 @@ public: WebCore::ScriptExecutionContext* scriptExecutionContext(); WebCore::ScriptExecutionContext* scriptExecutionContext() const; + void queueTask(WebCore::EventLoopTask* task); + JSDOMStructureMap& structures() WTF_REQUIRES_LOCK(m_gcLock) { return m_structures; } JSDOMStructureMap& structures(NoLockingNecessaryTag) WTF_IGNORES_THREAD_SAFETY_ANALYSIS { diff --git a/src/javascript/jsc/bindings/webcore/JSCallbackData.h b/src/javascript/jsc/bindings/webcore/JSCallbackData.h index 07114ce41..7ddd70ba7 100644 --- a/src/javascript/jsc/bindings/webcore/JSCallbackData.h +++ b/src/javascript/jsc/bindings/webcore/JSCallbackData.h @@ -109,11 +109,11 @@ private: JSC::Weak<JSC::JSObject> m_callback; }; -class DeleteCallbackDataTask : public ScriptExecutionContext::Task { +class DeleteCallbackDataTask : public EventLoopTask { public: template<typename CallbackDataType> explicit DeleteCallbackDataTask(CallbackDataType* data) - : ScriptExecutionContext::Task(ScriptExecutionContext::Task::CleanupTask, [data = std::unique_ptr<CallbackDataType>(data)](ScriptExecutionContext&) { + : EventLoopTask(EventLoopTask::CleanupTask, [data = std::unique_ptr<CallbackDataType>(data)](ScriptExecutionContext&) { }) { } diff --git a/src/javascript/jsc/event_loop.zig b/src/javascript/jsc/event_loop.zig index f7ba4c49e..2623551f6 100644 --- a/src/javascript/jsc/event_loop.zig +++ b/src/javascript/jsc/event_loop.zig @@ -259,6 +259,14 @@ pub const AnyTask = struct { }; } }; + +pub const CppTask = opaque { + extern fn Bun__performTask(globalObject: *JSGlobalObject, task: *CppTask) void; + pub fn run(this: *CppTask, global: *JSGlobalObject) void { + JSC.markBinding(); + Bun__performTask(global, this); + } +}; const ThreadSafeFunction = JSC.napi.ThreadSafeFunction; const MicrotaskForDefaultGlobalObject = JSC.MicrotaskForDefaultGlobalObject; // const PromiseTask = JSInternalPromise.Completion.PromiseTask; @@ -274,6 +282,7 @@ pub const Task = TaggedPointerUnion(.{ AnyTask, napi_async_work, ThreadSafeFunction, + CppTask, // PromiseTask, // TimeoutTasklet, }); @@ -287,7 +296,7 @@ pub const EventLoop = struct { concurrent_lock: Lock = Lock.init(), global: *JSGlobalObject = undefined, virtual_machine: *VirtualMachine = undefined, - pub const Queue = bun.LinearFifo(Task, .Dynamic); + pub const Queue = std.fifo.LinearFifo(Task, .Dynamic); pub fn tickWithCount(this: *EventLoop) u32 { var finished: u32 = 0; @@ -357,6 +366,12 @@ pub const EventLoop = struct { finished += 1; vm_.active_tasks -|= 1; }, + @field(Task.Tag, @typeName(CppTask)) => { + var any: *CppTask = task.get(CppTask).?; + any.run(global); + finished += 1; + vm_.active_tasks -|= 1; + }, else => if (Environment.allow_assert) { bun.Output.prettyln("\nUnexpected tag: {s}\n", .{@tagName(task.tag())}); } else unreachable, |