use a pool arena with ReadableStream

This commit is contained in:
Pierre Tachoire
2026-03-02 17:51:33 +01:00
parent 4863b3df6e
commit 8e8a1a7541
2 changed files with 19 additions and 7 deletions

View File

@@ -47,6 +47,8 @@ _page: *Page,
_state: State,
_reader: ?*ReadableStreamDefaultReader,
_controller: *ReadableStreamDefaultController,
// The arena is used by the builtin controller.
_arena: std.mem.Allocator,
_stored_error: ?[]const u8,
_pull_fn: ?js.Function.Global = null,
_pulling: bool = false,
@@ -68,9 +70,13 @@ const QueueingStrategy = struct {
pub fn init(src_: ?UnderlyingSource, strategy_: ?QueueingStrategy, page: *Page) !*ReadableStream {
const strategy: QueueingStrategy = strategy_ orelse .{};
const arena = try page.getArena(.{ .debug = "Animation" });
errdefer page.releaseArena(arena);
const self = try page._factory.create(ReadableStream{
._page = page,
._state = .readable,
._arena = arena,
._reader = null,
._controller = undefined,
._stored_error = null,
@@ -108,6 +114,10 @@ pub fn initWithData(data: []const u8, page: *Page) !*ReadableStream {
return stream;
}
pub fn deinit(self: *ReadableStream, _: bool, page: *Page) void {
page.releaseArena(self._arena);
}
pub fn getReader(self: *ReadableStream, page: *Page) !*ReadableStreamDefaultReader {
if (self.getLocked()) {
return error.ReaderLocked;
@@ -367,6 +377,8 @@ pub const JsApi = struct {
pub const name = "ReadableStream";
pub const prototype_chain = bridge.prototypeChain();
pub var class_id: bridge.ClassId = undefined;
pub const weak = true;
pub const finalizer = bridge.finalizer(ReadableStream.deinit);
};
pub const constructor = bridge.constructor(ReadableStream.init, .{});

View File

@@ -27,6 +27,8 @@ const ReadableStreamDefaultReader = @import("ReadableStreamDefaultReader.zig");
const IS_DEBUG = @import("builtin").mode == .Debug;
/// ReadableStreamDefaultController uses ReadableStream's arena to make
/// allocation. Indeed, the controller is owned by its ReadableStream.
const ReadableStreamDefaultController = @This();
pub const Chunk = union(enum) {
@@ -46,7 +48,6 @@ pub const Chunk = union(enum) {
_page: *Page,
_stream: *ReadableStream,
_arena: std.mem.Allocator,
_queue: std.ArrayList(Chunk),
_pending_reads: std.ArrayList(js.PromiseResolver.Global),
_high_water_mark: u32,
@@ -56,7 +57,6 @@ pub fn init(stream: *ReadableStream, high_water_mark: u32, page: *Page) !*Readab
._page = page,
._queue = .empty,
._stream = stream,
._arena = page.arena,
._pending_reads = .empty,
._high_water_mark = high_water_mark,
});
@@ -64,7 +64,7 @@ pub fn init(stream: *ReadableStream, high_water_mark: u32, page: *Page) !*Readab
pub fn addPendingRead(self: *ReadableStreamDefaultController, page: *Page) !js.Promise {
const resolver = page.js.local.?.createPromiseResolver();
try self._pending_reads.append(self._arena, try resolver.persist());
try self._pending_reads.append(self._stream._arena, try resolver.persist());
return resolver.promise();
}
@@ -74,8 +74,8 @@ pub fn enqueue(self: *ReadableStreamDefaultController, chunk: Chunk) !void {
}
if (self._pending_reads.items.len == 0) {
const chunk_copy = try chunk.dupe(self._page.arena);
return self._queue.append(self._arena, chunk_copy);
const chunk_copy = try chunk.dupe(self._stream._arena);
return self._queue.append(self._stream._arena, chunk_copy);
}
// I know, this is ouch! But we expect to have very few (if any)
@@ -109,7 +109,7 @@ pub fn enqueueValue(self: *ReadableStreamDefaultController, value: js.Value) !vo
if (self._pending_reads.items.len == 0) {
const persisted = try value.persist();
try self._queue.append(self._arena, .{ .js_value = persisted });
try self._queue.append(self._stream._arena, .{ .js_value = persisted });
return;
}
@@ -170,7 +170,7 @@ pub fn doError(self: *ReadableStreamDefaultController, err: []const u8) !void {
}
self._stream._state = .errored;
self._stream._stored_error = try self._page.arena.dupe(u8, err);
self._stream._stored_error = try self._stream._arena.dupe(u8, err);
// Reject all pending reads
for (self._pending_reads.items) |resolver| {