mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-21 20:24:42 +00:00
Merge pull request #1698 from lightpanda-io/readablestream-pool-arena
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
e2e-test / browser fetch (push) Has been cancelled
zig-test / zig test using v8 in debug mode (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
e2e-test / browser fetch (push) Has been cancelled
zig-test / zig test using v8 in debug mode (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
use a pool arena with ReadableStream
This commit is contained in:
@@ -72,6 +72,14 @@ pub fn init(label_: ?[]const u8, opts_: ?InitOpts, page: *Page) !TextDecoderStre
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn acquireRef(self: *TextDecoderStream) void {
|
||||||
|
self._transform.acquireRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *TextDecoderStream, shutdown: bool, page: *Page) void {
|
||||||
|
self._transform.deinit(shutdown, page);
|
||||||
|
}
|
||||||
|
|
||||||
fn decodeTransform(controller: *TransformStream.DefaultController, chunk: js.Value, ignoreBOM: bool) !void {
|
fn decodeTransform(controller: *TransformStream.DefaultController, chunk: js.Value, ignoreBOM: bool) !void {
|
||||||
// chunk should be a Uint8Array; decode it as UTF-8 string
|
// chunk should be a Uint8Array; decode it as UTF-8 string
|
||||||
const typed_array = try chunk.toZig(js.TypedArray(u8));
|
const typed_array = try chunk.toZig(js.TypedArray(u8));
|
||||||
@@ -111,6 +119,8 @@ pub const JsApi = struct {
|
|||||||
pub const name = "TextDecoderStream";
|
pub const name = "TextDecoderStream";
|
||||||
pub const prototype_chain = bridge.prototypeChain();
|
pub const prototype_chain = bridge.prototypeChain();
|
||||||
pub var class_id: bridge.ClassId = undefined;
|
pub var class_id: bridge.ClassId = undefined;
|
||||||
|
pub const weak = true;
|
||||||
|
pub const finalizer = bridge.finalizer(TextDecoderStream.deinit);
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const constructor = bridge.constructor(TextDecoderStream.init, .{});
|
pub const constructor = bridge.constructor(TextDecoderStream.init, .{});
|
||||||
|
|||||||
@@ -34,6 +34,14 @@ pub fn init(page: *Page) !TextEncoderStream {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn acquireRef(self: *TextEncoderStream) void {
|
||||||
|
self._transform.acquireRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *TextEncoderStream, shutdown: bool, page: *Page) void {
|
||||||
|
self._transform.deinit(shutdown, page);
|
||||||
|
}
|
||||||
|
|
||||||
fn encodeTransform(controller: *TransformStream.DefaultController, chunk: js.Value) !void {
|
fn encodeTransform(controller: *TransformStream.DefaultController, chunk: js.Value) !void {
|
||||||
// chunk should be a JS string; encode it as UTF-8 bytes (Uint8Array)
|
// chunk should be a JS string; encode it as UTF-8 bytes (Uint8Array)
|
||||||
const str = chunk.isString() orelse return error.InvalidChunk;
|
const str = chunk.isString() orelse return error.InvalidChunk;
|
||||||
@@ -56,6 +64,8 @@ pub const JsApi = struct {
|
|||||||
pub const name = "TextEncoderStream";
|
pub const name = "TextEncoderStream";
|
||||||
pub const prototype_chain = bridge.prototypeChain();
|
pub const prototype_chain = bridge.prototypeChain();
|
||||||
pub var class_id: bridge.ClassId = undefined;
|
pub var class_id: bridge.ClassId = undefined;
|
||||||
|
pub const weak = true;
|
||||||
|
pub const finalizer = bridge.finalizer(TextEncoderStream.deinit);
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const constructor = bridge.constructor(TextEncoderStream.init, .{});
|
pub const constructor = bridge.constructor(TextEncoderStream.init, .{});
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ _pull_fn: ?js.Function.Global = null,
|
|||||||
_pulling: bool = false,
|
_pulling: bool = false,
|
||||||
_pull_again: bool = false,
|
_pull_again: bool = false,
|
||||||
_cancel: ?Cancel = null,
|
_cancel: ?Cancel = null,
|
||||||
|
_arena: std.mem.Allocator,
|
||||||
|
_rc: usize = 0,
|
||||||
|
|
||||||
const UnderlyingSource = struct {
|
const UnderlyingSource = struct {
|
||||||
start: ?js.Function = null,
|
start: ?js.Function = null,
|
||||||
@@ -68,13 +70,18 @@ const QueueingStrategy = struct {
|
|||||||
pub fn init(src_: ?UnderlyingSource, strategy_: ?QueueingStrategy, page: *Page) !*ReadableStream {
|
pub fn init(src_: ?UnderlyingSource, strategy_: ?QueueingStrategy, page: *Page) !*ReadableStream {
|
||||||
const strategy: QueueingStrategy = strategy_ orelse .{};
|
const strategy: QueueingStrategy = strategy_ orelse .{};
|
||||||
|
|
||||||
const self = try page._factory.create(ReadableStream{
|
const arena = try page.getArena(.{ .debug = "ReadableStream" });
|
||||||
|
errdefer page.releaseArena(arena);
|
||||||
|
|
||||||
|
const self = try arena.create(ReadableStream);
|
||||||
|
self.* = .{
|
||||||
._page = page,
|
._page = page,
|
||||||
._state = .readable,
|
._state = .readable,
|
||||||
|
._arena = arena,
|
||||||
._reader = null,
|
._reader = null,
|
||||||
._controller = undefined,
|
._controller = undefined,
|
||||||
._stored_error = null,
|
._stored_error = null,
|
||||||
});
|
};
|
||||||
|
|
||||||
self._controller = try ReadableStreamDefaultController.init(self, strategy.highWaterMark, page);
|
self._controller = try ReadableStreamDefaultController.init(self, strategy.highWaterMark, page);
|
||||||
|
|
||||||
@@ -108,6 +115,23 @@ pub fn initWithData(data: []const u8, page: *Page) !*ReadableStream {
|
|||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *ReadableStream, _: bool, page: *Page) void {
|
||||||
|
const rc = self._rc;
|
||||||
|
if (comptime IS_DEBUG) {
|
||||||
|
std.debug.assert(rc != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc == 1) {
|
||||||
|
page.releaseArena(self._arena);
|
||||||
|
} else {
|
||||||
|
self._rc = rc - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn acquireRef(self: *ReadableStream) void {
|
||||||
|
self._rc += 1;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn getReader(self: *ReadableStream, page: *Page) !*ReadableStreamDefaultReader {
|
pub fn getReader(self: *ReadableStream, page: *Page) !*ReadableStreamDefaultReader {
|
||||||
if (self.getLocked()) {
|
if (self.getLocked()) {
|
||||||
return error.ReaderLocked;
|
return error.ReaderLocked;
|
||||||
@@ -120,6 +144,12 @@ pub fn getReader(self: *ReadableStream, page: *Page) !*ReadableStreamDefaultRead
|
|||||||
|
|
||||||
pub fn releaseReader(self: *ReadableStream) void {
|
pub fn releaseReader(self: *ReadableStream) void {
|
||||||
self._reader = null;
|
self._reader = null;
|
||||||
|
|
||||||
|
const rc = self._rc;
|
||||||
|
if (comptime IS_DEBUG) {
|
||||||
|
std.debug.assert(rc != 0);
|
||||||
|
}
|
||||||
|
self._rc = rc - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getAsyncIterator(self: *ReadableStream, page: *Page) !*AsyncIterator {
|
pub fn getAsyncIterator(self: *ReadableStream, page: *Page) !*AsyncIterator {
|
||||||
@@ -367,6 +397,8 @@ pub const JsApi = struct {
|
|||||||
pub const name = "ReadableStream";
|
pub const name = "ReadableStream";
|
||||||
pub const prototype_chain = bridge.prototypeChain();
|
pub const prototype_chain = bridge.prototypeChain();
|
||||||
pub var class_id: bridge.ClassId = undefined;
|
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, .{});
|
pub const constructor = bridge.constructor(ReadableStream.init, .{});
|
||||||
@@ -390,6 +422,14 @@ pub const AsyncIterator = struct {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn acquireRef(self: *AsyncIterator) void {
|
||||||
|
self._stream.acquireRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *AsyncIterator, shutdown: bool, page: *Page) void {
|
||||||
|
self._stream.deinit(shutdown, page);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn next(self: *AsyncIterator, page: *Page) !js.Promise {
|
pub fn next(self: *AsyncIterator, page: *Page) !js.Promise {
|
||||||
return self._reader.read(page);
|
return self._reader.read(page);
|
||||||
}
|
}
|
||||||
@@ -406,6 +446,8 @@ pub const AsyncIterator = struct {
|
|||||||
pub const name = "ReadableStreamAsyncIterator";
|
pub const name = "ReadableStreamAsyncIterator";
|
||||||
pub const prototype_chain = bridge.prototypeChain();
|
pub const prototype_chain = bridge.prototypeChain();
|
||||||
pub var class_id: bridge.ClassId = undefined;
|
pub var class_id: bridge.ClassId = undefined;
|
||||||
|
pub const weak = true;
|
||||||
|
pub const finalizer = bridge.finalizer(AsyncIterator.deinit);
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const next = bridge.function(ReadableStream.AsyncIterator.next, .{});
|
pub const next = bridge.function(ReadableStream.AsyncIterator.next, .{});
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ const ReadableStreamDefaultReader = @import("ReadableStreamDefaultReader.zig");
|
|||||||
|
|
||||||
const IS_DEBUG = @import("builtin").mode == .Debug;
|
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();
|
const ReadableStreamDefaultController = @This();
|
||||||
|
|
||||||
pub const Chunk = union(enum) {
|
pub const Chunk = union(enum) {
|
||||||
@@ -46,7 +48,6 @@ pub const Chunk = union(enum) {
|
|||||||
|
|
||||||
_page: *Page,
|
_page: *Page,
|
||||||
_stream: *ReadableStream,
|
_stream: *ReadableStream,
|
||||||
_arena: std.mem.Allocator,
|
|
||||||
_queue: std.ArrayList(Chunk),
|
_queue: std.ArrayList(Chunk),
|
||||||
_pending_reads: std.ArrayList(js.PromiseResolver.Global),
|
_pending_reads: std.ArrayList(js.PromiseResolver.Global),
|
||||||
_high_water_mark: u32,
|
_high_water_mark: u32,
|
||||||
@@ -56,15 +57,22 @@ pub fn init(stream: *ReadableStream, high_water_mark: u32, page: *Page) !*Readab
|
|||||||
._page = page,
|
._page = page,
|
||||||
._queue = .empty,
|
._queue = .empty,
|
||||||
._stream = stream,
|
._stream = stream,
|
||||||
._arena = page.arena,
|
|
||||||
._pending_reads = .empty,
|
._pending_reads = .empty,
|
||||||
._high_water_mark = high_water_mark,
|
._high_water_mark = high_water_mark,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn acquireRef(self: *ReadableStreamDefaultController) void {
|
||||||
|
self._stream.acquireRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *ReadableStreamDefaultController, shutdown: bool, page: *Page) void {
|
||||||
|
self._stream.deinit(shutdown, page);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn addPendingRead(self: *ReadableStreamDefaultController, page: *Page) !js.Promise {
|
pub fn addPendingRead(self: *ReadableStreamDefaultController, page: *Page) !js.Promise {
|
||||||
const resolver = page.js.local.?.createPromiseResolver();
|
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();
|
return resolver.promise();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,8 +82,8 @@ pub fn enqueue(self: *ReadableStreamDefaultController, chunk: Chunk) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (self._pending_reads.items.len == 0) {
|
if (self._pending_reads.items.len == 0) {
|
||||||
const chunk_copy = try chunk.dupe(self._page.arena);
|
const chunk_copy = try chunk.dupe(self._stream._arena);
|
||||||
return self._queue.append(self._arena, chunk_copy);
|
return self._queue.append(self._stream._arena, chunk_copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
// I know, this is ouch! But we expect to have very few (if any)
|
// I know, this is ouch! But we expect to have very few (if any)
|
||||||
@@ -109,7 +117,7 @@ pub fn enqueueValue(self: *ReadableStreamDefaultController, value: js.Value) !vo
|
|||||||
|
|
||||||
if (self._pending_reads.items.len == 0) {
|
if (self._pending_reads.items.len == 0) {
|
||||||
const persisted = try value.persist();
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +178,7 @@ pub fn doError(self: *ReadableStreamDefaultController, err: []const u8) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self._stream._state = .errored;
|
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
|
// Reject all pending reads
|
||||||
for (self._pending_reads.items) |resolver| {
|
for (self._pending_reads.items) |resolver| {
|
||||||
@@ -210,6 +218,8 @@ pub const JsApi = struct {
|
|||||||
pub const name = "ReadableStreamDefaultController";
|
pub const name = "ReadableStreamDefaultController";
|
||||||
pub const prototype_chain = bridge.prototypeChain();
|
pub const prototype_chain = bridge.prototypeChain();
|
||||||
pub var class_id: bridge.ClassId = undefined;
|
pub var class_id: bridge.ClassId = undefined;
|
||||||
|
pub const weak = true;
|
||||||
|
pub const finalizer = bridge.finalizer(ReadableStreamDefaultController.deinit);
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const enqueue = bridge.function(ReadableStreamDefaultController.enqueueValue, .{});
|
pub const enqueue = bridge.function(ReadableStreamDefaultController.enqueueValue, .{});
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const js = @import("../../js/js.zig");
|
const js = @import("../../js/js.zig");
|
||||||
|
|
||||||
|
const IS_DEBUG = @import("builtin").mode == .Debug;
|
||||||
|
|
||||||
const Page = @import("../../Page.zig");
|
const Page = @import("../../Page.zig");
|
||||||
const ReadableStream = @import("ReadableStream.zig");
|
const ReadableStream = @import("ReadableStream.zig");
|
||||||
const ReadableStreamDefaultController = @import("ReadableStreamDefaultController.zig");
|
const ReadableStreamDefaultController = @import("ReadableStreamDefaultController.zig");
|
||||||
@@ -35,6 +37,21 @@ pub fn init(stream: *ReadableStream, page: *Page) !*ReadableStreamDefaultReader
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn acquireRef(self: *ReadableStreamDefaultReader) void {
|
||||||
|
const stream = self._stream orelse {
|
||||||
|
if (comptime IS_DEBUG) {
|
||||||
|
std.debug.assert(false);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
stream.acquireRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *ReadableStreamDefaultReader, shutdown: bool, page: *Page) void {
|
||||||
|
const stream = self._stream orelse return;
|
||||||
|
stream.deinit(shutdown, page);
|
||||||
|
}
|
||||||
|
|
||||||
pub const ReadResult = struct {
|
pub const ReadResult = struct {
|
||||||
done: bool,
|
done: bool,
|
||||||
value: Chunk,
|
value: Chunk,
|
||||||
@@ -110,6 +127,8 @@ pub const JsApi = struct {
|
|||||||
pub const name = "ReadableStreamDefaultReader";
|
pub const name = "ReadableStreamDefaultReader";
|
||||||
pub const prototype_chain = bridge.prototypeChain();
|
pub const prototype_chain = bridge.prototypeChain();
|
||||||
pub var class_id: bridge.ClassId = undefined;
|
pub var class_id: bridge.ClassId = undefined;
|
||||||
|
pub const weak = true;
|
||||||
|
pub const finalizer = bridge.finalizer(ReadableStreamDefaultReader.deinit);
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const read = bridge.function(ReadableStreamDefaultReader.read, .{});
|
pub const read = bridge.function(ReadableStreamDefaultReader.read, .{});
|
||||||
|
|||||||
@@ -85,6 +85,14 @@ pub fn initWithZigTransform(zig_transform: ZigTransformFn, page: *Page) !*Transf
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn acquireRef(self: *TransformStream) void {
|
||||||
|
self._readable.acquireRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *TransformStream, shutdown: bool, page: *Page) void {
|
||||||
|
self._readable.deinit(shutdown, page);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn transformWrite(self: *TransformStream, chunk: js.Value, page: *Page) !void {
|
pub fn transformWrite(self: *TransformStream, chunk: js.Value, page: *Page) !void {
|
||||||
if (self._controller._zig_transform_fn) |zig_fn| {
|
if (self._controller._zig_transform_fn) |zig_fn| {
|
||||||
// Zig-level transform (used by TextEncoderStream etc.)
|
// Zig-level transform (used by TextEncoderStream etc.)
|
||||||
@@ -130,6 +138,8 @@ pub const JsApi = struct {
|
|||||||
pub const name = "TransformStream";
|
pub const name = "TransformStream";
|
||||||
pub const prototype_chain = bridge.prototypeChain();
|
pub const prototype_chain = bridge.prototypeChain();
|
||||||
pub var class_id: bridge.ClassId = undefined;
|
pub var class_id: bridge.ClassId = undefined;
|
||||||
|
pub const weak = true;
|
||||||
|
pub const finalizer = bridge.finalizer(TransformStream.deinit);
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const constructor = bridge.constructor(TransformStream.init, .{});
|
pub const constructor = bridge.constructor(TransformStream.init, .{});
|
||||||
@@ -165,6 +175,14 @@ pub const TransformStreamDefaultController = struct {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn acquireRef(self: *TransformStreamDefaultController) void {
|
||||||
|
self._stream.acquireRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *TransformStreamDefaultController, shutdown: bool, page: *Page) void {
|
||||||
|
self._stream.deinit(shutdown, page);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn enqueue(self: *TransformStreamDefaultController, chunk: ReadableStreamDefaultController.Chunk) !void {
|
pub fn enqueue(self: *TransformStreamDefaultController, chunk: ReadableStreamDefaultController.Chunk) !void {
|
||||||
try self._stream._readable._controller.enqueue(chunk);
|
try self._stream._readable._controller.enqueue(chunk);
|
||||||
}
|
}
|
||||||
@@ -189,6 +207,8 @@ pub const TransformStreamDefaultController = struct {
|
|||||||
pub const name = "TransformStreamDefaultController";
|
pub const name = "TransformStreamDefaultController";
|
||||||
pub const prototype_chain = bridge.prototypeChain();
|
pub const prototype_chain = bridge.prototypeChain();
|
||||||
pub var class_id: bridge.ClassId = undefined;
|
pub var class_id: bridge.ClassId = undefined;
|
||||||
|
pub const weak = true;
|
||||||
|
pub const finalizer = bridge.finalizer(TransformStreamDefaultController.deinit);
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const enqueue = bridge.function(TransformStreamDefaultController.enqueueValue, .{});
|
pub const enqueue = bridge.function(TransformStreamDefaultController.enqueueValue, .{});
|
||||||
|
|||||||
Reference in New Issue
Block a user