diff options
-rw-r--r-- | src/cache.zig | 15 | ||||
-rw-r--r-- | src/javascript/jsc/javascript.zig | 114 | ||||
-rw-r--r-- | src/javascript/jsc/webcore/response.zig | 2 | ||||
-rw-r--r-- | src/js_ast.zig | 12 | ||||
-rw-r--r-- | src/js_parser/js_parser.zig | 11 |
5 files changed, 103 insertions, 51 deletions
diff --git a/src/cache.zig b/src/cache.zig index 3a3429105..25acce57a 100644 --- a/src/cache.zig +++ b/src/cache.zig @@ -48,6 +48,7 @@ pub const Set = struct { .js = JavaScript.init(allocator), .fs = Fs{ .shared_buffer = MutableString.init(allocator, 0) catch unreachable, + .macro_shared_buffer = MutableString.init(allocator, 0) catch unreachable, }, .json = Json{}, }; @@ -57,6 +58,18 @@ pub const Fs = struct { const Entry = FsCacheEntry; shared_buffer: MutableString, + macro_shared_buffer: MutableString, + + is_macro_mode: bool = false, + + // When we are in a macro, the shared buffer may be in use by the in-progress macro. + // so we have to dynamically switch it out. + pub inline fn sharedBuffer(this: *Fs) *MutableString { + return if (!this.is_macro_mode) + &this.shared_buffer + else + &this.macro_shared_buffer; + } pub fn deinit(c: *Fs) void { var iter = c.entries.iterator(); @@ -138,7 +151,7 @@ pub const Fs = struct { } } - const file = rfs.readFileWithHandle(path, null, file_handle, use_shared_buffer, &c.shared_buffer) catch |err| { + const file = rfs.readFileWithHandle(path, null, file_handle, use_shared_buffer, c.sharedBuffer()) catch |err| { if (Environment.isDebug) { Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) }); } diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig index 043bc7aea..d571def15 100644 --- a/src/javascript/jsc/javascript.zig +++ b/src/javascript/jsc/javascript.zig @@ -837,57 +837,81 @@ pub const VirtualMachine = struct { origin_timer: std.time.Timer = undefined, - ready_tasks_count: std.atomic.Atomic(u32) = std.atomic.Atomic(u32).init(0), - pending_tasks_count: std.atomic.Atomic(u32) = std.atomic.Atomic(u32).init(0), - microtasks_queue: std.ArrayList(Task) = std.ArrayList(Task).init(default_allocator), - - pub fn enqueueTask(this: *VirtualMachine, task: Task) !void { - _ = this.pending_tasks_count.fetchAdd(1, .Monotonic); - try this.microtasks_queue.append(task); - } - - pub fn tick(this: *VirtualMachine) void { - while (this.eventLoopTick() > 0) {} - } - - pub fn waitForTasks(this: *VirtualMachine) void { - while (this.pending_tasks_count.load(.Monotonic) > 0 or this.ready_tasks_count.load(.Monotonic) > 0) { - while (this.eventLoopTick() > 0) {} - } + macro_event_loop: EventLoop = EventLoop{}, + regular_event_loop: EventLoop = EventLoop{}, + + pub inline fn eventLoop(this: *VirtualMachine) *EventLoop { + return if (this.macro_mode) + return &this.macro_event_loop + else + return &this.regular_event_loop; } - // 👶👶👶 event loop 👶👶👶 - pub fn eventLoopTick(this: *VirtualMachine) u32 { - var finished: u32 = 0; - var i: usize = 0; - while (i < this.microtasks_queue.items.len) { - var task: Task = this.microtasks_queue.items[i]; - switch (task.tag()) { - .Microtask => { - var micro: *Microtask = task.get(Microtask).?; - _ = this.microtasks_queue.swapRemove(i); - _ = this.pending_tasks_count.fetchSub(1, .Monotonic); - micro.run(this.global); - - finished += 1; - continue; - }, - .FetchTasklet => { - var fetch_task: *Fetch.FetchTasklet = task.get(Fetch.FetchTasklet).?; - if (fetch_task.status == .done) { - _ = this.ready_tasks_count.fetchSub(1, .Monotonic); + const EventLoop = struct { + ready_tasks_count: std.atomic.Atomic(u32) = std.atomic.Atomic(u32).init(0), + pending_tasks_count: std.atomic.Atomic(u32) = std.atomic.Atomic(u32).init(0), + tasks: std.ArrayList(Task) = std.ArrayList(Task).init(default_allocator), + + pub fn tickWithCount(this: *EventLoop) u32 { + var finished: u32 = 0; + var i: usize = 0; + var global = VirtualMachine.vm.global; + while (i < this.tasks.items.len) { + var task: Task = this.tasks.items[i]; + switch (task.tag()) { + .Microtask => { + var micro: *Microtask = task.get(Microtask).?; + _ = this.tasks.swapRemove(i); _ = this.pending_tasks_count.fetchSub(1, .Monotonic); - _ = this.microtasks_queue.swapRemove(i); - fetch_task.onDone(); + micro.run(global); + finished += 1; continue; - } - }, - else => unreachable, + }, + .FetchTasklet => { + var fetch_task: *Fetch.FetchTasklet = task.get(Fetch.FetchTasklet).?; + if (fetch_task.status == .done) { + _ = this.ready_tasks_count.fetchSub(1, .Monotonic); + _ = this.pending_tasks_count.fetchSub(1, .Monotonic); + _ = this.tasks.swapRemove(i); + fetch_task.onDone(); + finished += 1; + continue; + } + }, + else => unreachable, + } + i += 1; } - i += 1; + return finished; } - return finished; + + pub fn tick(this: *EventLoop) void { + while (this.tickWithCount() > 0) {} + } + + pub fn waitForTasks(this: *EventLoop) void { + while (this.pending_tasks_count.load(.Monotonic) > 0 or this.ready_tasks_count.load(.Monotonic) > 0) { + while (this.tickWithCount() > 0) {} + } + } + + pub fn enqueueTask(this: *EventLoop, task: Task) !void { + _ = this.pending_tasks_count.fetchAdd(1, .Monotonic); + try this.tasks.append(task); + } + }; + + pub inline fn enqueueTask(this: *VirtualMachine, task: Task) !void { + try this.eventLoop().enqueueTask(task); + } + + pub fn tick(this: *VirtualMachine) void { + while (this.eventLoop().tickWithCount() > 0) {} + } + + pub fn waitForTasks(this: *VirtualMachine) void { + this.eventLoop().waitForTasks(); } pub const MacroMap = std.AutoArrayHashMap(i32, js.JSObjectRef); @@ -897,12 +921,14 @@ pub const VirtualMachine = struct { pub fn enableMacroMode(this: *VirtualMachine) void { this.bundler.options.platform = .bun_macro; + this.bundler.resolver.caches.fs.is_macro_mode = true; this.macro_mode = true; Analytics.Features.macros = true; } pub fn disableMacroMode(this: *VirtualMachine) void { this.bundler.options.platform = .bun; + this.bundler.resolver.caches.fs.is_macro_mode = false; this.macro_mode = false; } diff --git a/src/javascript/jsc/webcore/response.zig b/src/javascript/jsc/webcore/response.zig index cb87f2e98..035b6b9e9 100644 --- a/src/javascript/jsc/webcore/response.zig +++ b/src/javascript/jsc/webcore/response.zig @@ -637,7 +637,7 @@ pub const Fetch = struct { pub fn callback(http_: *HTTPClient.AsyncHTTP, sender: *HTTPClient.AsyncHTTP.HTTPSender) void { var task: *FetchTasklet = @fieldParentPtr(FetchTasklet, "http", http_); @atomicStore(Status, &task.status, Status.done, .Monotonic); - _ = task.javascript_vm.ready_tasks_count.fetchAdd(1, .Monotonic); + _ = task.javascript_vm.eventLoop().ready_tasks_count.fetchAdd(1, .Monotonic); sender.release(); } }; diff --git a/src/js_ast.zig b/src/js_ast.zig index 55e7ff48d..e4d130f8d 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -3898,7 +3898,7 @@ pub const Macro = struct { } macro.vm.enableMacroMode(); defer macro.vm.disableMacroMode(); - return Macro.Runner.run( + return try Macro.Runner.run( macro, log, default_allocator, @@ -6725,6 +6725,8 @@ pub const Macro = struct { threadlocal var args_buf: [2]js.JSObjectRef = undefined; threadlocal var expr_nodes_buf: [1]JSNode = undefined; threadlocal var exception_holder: Zig.ZigException.Holder = undefined; + pub const MacroError = error{MacroFailed}; + pub fn run( macro: Macro, _: *logger.Log, @@ -6736,7 +6738,7 @@ pub const Macro = struct { id: i32, comptime Visitor: type, visitor: Visitor, - ) Expr { + ) MacroError!Expr { if (comptime Environment.isDebug) Output.prettyln("<r><d>[macro]<r> call <d><b>{s}<r>", .{function_name}); exception_holder = Zig.ZigException.Holder.init(); @@ -6755,9 +6757,13 @@ pub const Macro = struct { var promise = JSC.JSPromise.resolvedPromise(macro.vm.global, result); _ = macro.vm.tick(); + while (promise.status(macro.vm.global.vm()) == .Pending) { + macro.vm.tick(); + } + if (promise.status(macro.vm.global.vm()) == .Rejected) { macro.vm.defaultErrorHandler(promise.result(macro.vm.global.vm()), null); - return caller; + return error.MacroFailed; } const value = promise.result(macro.vm.global.vm()); diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig index 55b3f9449..3a64fd79b 100644 --- a/src/js_parser/js_parser.zig +++ b/src/js_parser/js_parser.zig @@ -6154,7 +6154,7 @@ pub fn NewParser( } } - const macro_remap = if (FeatureFlags.is_macro_enabled and !is_macro and jsx_transform_type != .macro) + const macro_remap = if ((comptime FeatureFlags.is_macro_enabled and jsx_transform_type != .macro) and !is_macro) p.options.macro_context.getRemap(path.text) else null; @@ -12195,7 +12195,14 @@ pub fn NewParser( name, MacroVisitor, MacroVisitor{ .p = p, .loc = expr.loc }, - ) catch return expr; + ) catch |err| { + if (err == error.MacroFailed) { + p.log.addError(p.source, expr.loc, "error in macro") catch unreachable; + } else { + p.log.addErrorFmt(p.source, expr.loc, p.allocator, "{s} error in macro", .{@errorName(err)}) catch unreachable; + } + return expr; + }; if (macro_result.data != .e_call) { return p.visitExpr(macro_result); |