aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2023-06-13 09:15:05 -0700
committerGravatar GitHub <noreply@github.com> 2023-06-13 09:15:05 -0700
commitbdb1b7124aec3ca42a13dd13309df4c8e4e3cc64 (patch)
tree57a7a278699999521f561959204a533ea9906f8e /src
parentb93bdbb124fc7b1b4a09d414158e0107e8d66b92 (diff)
downloadbun-bdb1b7124aec3ca42a13dd13309df4c8e4e3cc64.tar.gz
bun-bdb1b7124aec3ca42a13dd13309df4c8e4e3cc64.tar.zst
bun-bdb1b7124aec3ca42a13dd13309df4c8e4e3cc64.zip
Fix crash in CJS (#3294)bun-v0.6.9
* Fix crash in CJS * Add std.heap.ArenaAllocator * Use our arena allocator * Reduce JS parser memory usage and make HMR faster * Write some comments * fix test failure & clean up this code * Update javascript.zig * make arena usage safer --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Diffstat (limited to 'src')
-rw-r--r--src/ArenaAllocator.zig287
-rw-r--r--src/bun.js/api/JSTranspiler.zig4
-rw-r--r--src/bun.js/api/bun.zig2
-rw-r--r--src/bun.js/api/bun/dns_resolver.zig4
-rw-r--r--src/bun.js/api/bun/subprocess.zig2
-rw-r--r--src/bun.js/api/filesystem_router.zig10
-rw-r--r--src/bun.js/api/server.zig12
-rw-r--r--src/bun.js/base.zig28
-rw-r--r--src/bun.js/bindings/BunString.cpp27
-rw-r--r--src/bun.js/bindings/CommonJSModuleRecord.cpp88
-rw-r--r--src/bun.js/bindings/ModuleLoader.cpp12
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp7
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.h6
-rw-r--r--src/bun.js/bindings/ZigSourceProvider.cpp95
-rw-r--r--src/bun.js/bindings/ZigSourceProvider.h19
-rw-r--r--src/bun.js/bindings/exports.zig2
-rw-r--r--src/bun.js/bindings/headers-handwritten.h2
-rw-r--r--src/bun.js/javascript.zig25
-rw-r--r--src/bun.js/module_loader.zig222
-rw-r--r--src/bun.js/node/types.zig8
-rw-r--r--src/bun.js/webcore/blob.zig2
-rw-r--r--src/bun.zig2
-rw-r--r--src/bundler.zig4
-rw-r--r--src/bundler/bundle_v2.zig8
-rw-r--r--src/deps/c_ares.zig14
-rw-r--r--src/deps/diffz/DiffMatchPatch.zig20
-rw-r--r--src/deps/zig-clap/clap.zig2
-rw-r--r--src/deps/zig-clap/clap/args.zig8
-rw-r--r--src/http.zig2
-rw-r--r--src/install/install.zig2
-rw-r--r--src/install/npm.zig2
-rw-r--r--src/main.zig2
-rw-r--r--src/main_wasm.zig4
-rw-r--r--src/renamer.zig4
-rw-r--r--src/string.zig27
-rw-r--r--src/zlib.zig12
36 files changed, 705 insertions, 272 deletions
diff --git a/src/ArenaAllocator.zig b/src/ArenaAllocator.zig
new file mode 100644
index 000000000..31e0cf5b9
--- /dev/null
+++ b/src/ArenaAllocator.zig
@@ -0,0 +1,287 @@
+/// TODO: delete this once we've upgraded Zig and https://github.com/ziglang/zig/pull/15985 is merged.
+const std = @import("std");
+const assert = std.debug.assert;
+const mem = std.mem;
+const Allocator = std.mem.Allocator;
+
+/// This allocator takes an existing allocator, wraps it, and provides an interface
+/// where you can allocate without freeing, and then free it all together.
+pub const ArenaAllocator = struct {
+ child_allocator: Allocator,
+ state: State,
+
+ /// Inner state of ArenaAllocator. Can be stored rather than the entire ArenaAllocator
+ /// as a memory-saving optimization.
+ pub const State = struct {
+ buffer_list: std.SinglyLinkedList(usize) = .{},
+ end_index: usize = 0,
+
+ pub fn promote(self: State, child_allocator: Allocator) ArenaAllocator {
+ return .{
+ .child_allocator = child_allocator,
+ .state = self,
+ };
+ }
+ };
+
+ pub fn allocator(self: *ArenaAllocator) Allocator {
+ return .{
+ .ptr = self,
+ .vtable = &.{
+ .alloc = alloc,
+ .resize = resize,
+ .free = free,
+ },
+ };
+ }
+
+ const BufNode = std.SinglyLinkedList(usize).Node;
+
+ pub fn init(child_allocator: Allocator) ArenaAllocator {
+ return (State{}).promote(child_allocator);
+ }
+
+ pub fn deinit(self: ArenaAllocator) void {
+ // NOTE: When changing this, make sure `reset()` is adjusted accordingly!
+
+ var it = self.state.buffer_list.first;
+ while (it) |node| {
+ // this has to occur before the free because the free frees node
+ const next_it = node.next;
+ const align_bits = std.math.log2_int(usize, @alignOf(BufNode));
+ const alloc_buf = @ptrCast([*]u8, node)[0..node.data];
+ self.child_allocator.rawFree(alloc_buf, align_bits, @returnAddress());
+ it = next_it;
+ }
+ }
+
+ pub const ResetMode = union(enum) {
+ /// Releases all allocated memory in the arena.
+ free_all,
+ /// This will pre-heat the arena for future allocations by allocating a
+ /// large enough buffer for all previously done allocations.
+ /// Preheating will speed up the allocation process by invoking the backing allocator
+ /// less often than before. If `reset()` is used in a loop, this means that after the
+ /// biggest operation, no memory allocations are performed anymore.
+ retain_capacity,
+ /// This is the same as `retain_capacity`, but the memory will be shrunk to
+ /// this value if it exceeds the limit.
+ retain_with_limit: usize,
+ };
+ /// Queries the current memory use of this arena.
+ /// This will **not** include the storage required for internal keeping.
+ pub fn queryCapacity(self: ArenaAllocator) usize {
+ var size: usize = 0;
+ var it = self.state.buffer_list.first;
+ while (it) |node| : (it = node.next) {
+ // Compute the actually allocated size excluding the
+ // linked list node.
+ size += node.data - @sizeOf(BufNode);
+ }
+ return size;
+ }
+ /// Resets the arena allocator and frees all allocated memory.
+ ///
+ /// `mode` defines how the currently allocated memory is handled.
+ /// See the variant documentation for `ResetMode` for the effects of each mode.
+ ///
+ /// The function will return whether the reset operation was successful or not.
+ /// If the reallocation failed `false` is returned. The arena will still be fully
+ /// functional in that case, all memory is released. Future allocations just might
+ /// be slower.
+ ///
+ /// NOTE: If `mode` is `free_mode`, the function will always return `true`.
+ pub fn reset(self: *ArenaAllocator, mode: ResetMode) bool {
+ // Some words on the implementation:
+ // The reset function can be implemented with two basic approaches:
+ // - Counting how much bytes were allocated since the last reset, and storing that
+ // information in State. This will make reset fast and alloc only a teeny tiny bit
+ // slower.
+ // - Counting how much bytes were allocated by iterating the chunk linked list. This
+ // will make reset slower, but alloc() keeps the same speed when reset() as if reset()
+ // would not exist.
+ //
+ // The second variant was chosen for implementation, as with more and more calls to reset(),
+ // the function will get faster and faster. At one point, the complexity of the function
+ // will drop to amortized O(1), as we're only ever having a single chunk that will not be
+ // reallocated, and we're not even touching the backing allocator anymore.
+ //
+ // Thus, only the first hand full of calls to reset() will actually need to iterate the linked
+ // list, all future calls are just taking the first node, and only resetting the `end_index`
+ // value.
+ const requested_capacity = switch (mode) {
+ .retain_capacity => self.queryCapacity(),
+ .retain_with_limit => |limit| std.math.min(limit, self.queryCapacity()),
+ .free_all => 0,
+ };
+ if (requested_capacity == 0) {
+ // just reset when we don't have anything to reallocate
+ self.deinit();
+ self.state = State{};
+ return true;
+ }
+ const total_size = requested_capacity + @sizeOf(BufNode);
+ const align_bits = std.math.log2_int(usize, @alignOf(BufNode));
+ // Free all nodes except for the last one
+ var it = self.state.buffer_list.first;
+ const maybe_first_node = while (it) |node| {
+ // this has to occur before the free because the free frees node
+ const next_it = node.next;
+ if (next_it == null)
+ break node;
+ const alloc_buf = @ptrCast([*]u8, node)[0..node.data];
+ self.child_allocator.rawFree(alloc_buf, align_bits, @returnAddress());
+ it = next_it;
+ } else null;
+ std.debug.assert(maybe_first_node == null or maybe_first_node.?.next == null);
+ // reset the state before we try resizing the buffers, so we definitely have reset the arena to 0.
+ self.state.end_index = 0;
+ if (maybe_first_node) |first_node| {
+ self.state.buffer_list.first = first_node;
+ // perfect, no need to invoke the child_allocator
+ if (first_node.data == total_size)
+ return true;
+ const first_alloc_buf = @ptrCast([*]u8, first_node)[0..first_node.data];
+ if (self.child_allocator.rawResize(first_alloc_buf, align_bits, total_size, @returnAddress())) {
+ // successful resize
+ first_node.data = total_size;
+ } else {
+ // manual realloc
+ const new_ptr = self.child_allocator.rawAlloc(total_size, align_bits, @returnAddress()) orelse {
+ // we failed to preheat the arena properly, signal this to the user.
+ return false;
+ };
+ self.child_allocator.rawFree(first_alloc_buf, align_bits, @returnAddress());
+ const node = @ptrCast(*BufNode, @alignCast(@alignOf(BufNode), new_ptr));
+ node.* = .{ .data = total_size };
+ self.state.buffer_list.first = node;
+ }
+ }
+ return true;
+ }
+
+ fn createNode(self: *ArenaAllocator, prev_len: usize, minimum_size: usize) ?*BufNode {
+ const actual_min_size = minimum_size + (@sizeOf(BufNode) + 16);
+ const big_enough_len = prev_len + actual_min_size;
+ const len = big_enough_len + big_enough_len / 2;
+ const log2_align = comptime std.math.log2_int(usize, @alignOf(BufNode));
+ const ptr = self.child_allocator.rawAlloc(len, log2_align, @returnAddress()) orelse
+ return null;
+ const buf_node = @ptrCast(*BufNode, @alignCast(@alignOf(BufNode), ptr));
+ buf_node.* = .{ .data = len };
+ self.state.buffer_list.prepend(buf_node);
+ self.state.end_index = 0;
+ return buf_node;
+ }
+
+ fn alloc(ctx: *anyopaque, n: usize, log2_ptr_align: u8, ra: usize) ?[*]u8 {
+ const self = @ptrCast(*ArenaAllocator, @alignCast(@alignOf(ArenaAllocator), ctx));
+ _ = ra;
+
+ const ptr_align = @as(usize, 1) << @intCast(Allocator.Log2Align, log2_ptr_align);
+ var cur_node = if (self.state.buffer_list.first) |first_node|
+ first_node
+ else
+ (self.createNode(0, n + ptr_align) orelse return null);
+ while (true) {
+ const cur_alloc_buf = @ptrCast([*]u8, cur_node)[0..cur_node.data];
+ const cur_buf = cur_alloc_buf[@sizeOf(BufNode)..];
+ const addr = @ptrToInt(cur_buf.ptr) + self.state.end_index;
+ const adjusted_addr = mem.alignForward(addr, ptr_align);
+ const adjusted_index = self.state.end_index + (adjusted_addr - addr);
+ const new_end_index = adjusted_index + n;
+
+ if (new_end_index <= cur_buf.len) {
+ const result = cur_buf[adjusted_index..new_end_index];
+ self.state.end_index = new_end_index;
+ return result.ptr;
+ }
+
+ const bigger_buf_size = @sizeOf(BufNode) + new_end_index;
+ const log2_align = comptime std.math.log2_int(usize, @alignOf(BufNode));
+ if (self.child_allocator.rawResize(cur_alloc_buf, log2_align, bigger_buf_size, @returnAddress())) {
+ cur_node.data = bigger_buf_size;
+ } else {
+ // Allocate a new node if that's not possible
+ cur_node = self.createNode(cur_buf.len, n + ptr_align) orelse return null;
+ }
+ }
+ }
+
+ fn resize(ctx: *anyopaque, buf: []u8, log2_buf_align: u8, new_len: usize, ret_addr: usize) bool {
+ const self = @ptrCast(*ArenaAllocator, @alignCast(@alignOf(ArenaAllocator), ctx));
+ _ = log2_buf_align;
+ _ = ret_addr;
+
+ const cur_node = self.state.buffer_list.first orelse return false;
+ const cur_buf = @ptrCast([*]u8, cur_node)[@sizeOf(BufNode)..cur_node.data];
+ if (@ptrToInt(cur_buf.ptr) + self.state.end_index != @ptrToInt(buf.ptr) + buf.len) {
+ // It's not the most recent allocation, so it cannot be expanded,
+ // but it's fine if they want to make it smaller.
+ return new_len <= buf.len;
+ }
+
+ if (buf.len >= new_len) {
+ self.state.end_index -= buf.len - new_len;
+ return true;
+ } else if (cur_buf.len - self.state.end_index >= new_len - buf.len) {
+ self.state.end_index += new_len - buf.len;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ fn free(ctx: *anyopaque, buf: []u8, log2_buf_align: u8, ret_addr: usize) void {
+ _ = log2_buf_align;
+ _ = ret_addr;
+
+ const self = @ptrCast(*ArenaAllocator, @alignCast(@alignOf(ArenaAllocator), ctx));
+
+ const cur_node = self.state.buffer_list.first orelse return;
+ const cur_buf = @ptrCast([*]u8, cur_node)[@sizeOf(BufNode)..cur_node.data];
+
+ if (@ptrToInt(cur_buf.ptr) + self.state.end_index == @ptrToInt(buf.ptr) + buf.len) {
+ self.state.end_index -= buf.len;
+ }
+ }
+};
+
+test "ArenaAllocator (reset with preheating)" {
+ var arena_allocator = ArenaAllocator.init(std.testing.allocator);
+ defer arena_allocator.deinit();
+ // provides some variance in the allocated data
+ var rng_src = std.rand.DefaultPrng.init(19930913);
+ const random = rng_src.random();
+ var rounds: usize = 25;
+ while (rounds > 0) {
+ rounds -= 1;
+ _ = arena_allocator.reset(.retain_capacity);
+ var alloced_bytes: usize = 0;
+ var total_size: usize = random.intRangeAtMost(usize, 256, 16384);
+ while (alloced_bytes < total_size) {
+ const size = random.intRangeAtMost(usize, 16, 256);
+ const alignment = 32;
+ const slice = try arena_allocator.allocator().alignedAlloc(u8, alignment, size);
+ try std.testing.expect(std.mem.isAligned(@ptrToInt(slice.ptr), alignment));
+ try std.testing.expectEqual(size, slice.len);
+ alloced_bytes += slice.len;
+ }
+ }
+}
+
+test "ArenaAllocator (reset while retaining a buffer)" {
+ var arena_allocator = ArenaAllocator.init(std.testing.allocator);
+ defer arena_allocator.deinit();
+ const a = arena_allocator.allocator();
+
+ // Create two internal buffers
+ _ = try a.alloc(u8, 1);
+ _ = try a.alloc(u8, 1000);
+
+ // Check that we have at least two buffers
+ try std.testing.expect(arena_allocator.state.buffer_list.first.?.next != null);
+
+ // This retains the first allocated buffer
+ try std.testing.expect(arena_allocator.reset(.{ .retain_with_limit = 1 }));
+}
diff --git a/src/bun.js/api/JSTranspiler.zig b/src/bun.js/api/JSTranspiler.zig
index 83e3b741f..4cfc02e94 100644
--- a/src/bun.js/api/JSTranspiler.zig
+++ b/src/bun.js/api/JSTranspiler.zig
@@ -46,7 +46,7 @@ const Expr = JSAst.Expr;
pub usingnamespace JSC.Codegen.JSTranspiler;
bundler: Bundler.Bundler,
-arena: std.heap.ArenaAllocator,
+arena: @import("root").bun.ArenaAllocator,
transpiler_options: TranspilerOptions,
scan_pass_result: ScanPassResult,
buffer_writer: ?JSPrinter.BufferWriter = null,
@@ -726,7 +726,7 @@ pub fn constructor(
globalThis: *JSC.JSGlobalObject,
callframe: *JSC.CallFrame,
) callconv(.C) ?*Transpiler {
- var temp = std.heap.ArenaAllocator.init(getAllocator(globalThis));
+ var temp = @import("root").bun.ArenaAllocator.init(getAllocator(globalThis));
const arguments = callframe.arguments(3);
var args = JSC.Node.ArgumentsSlice.init(
globalThis.bunVM(),
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig
index 380ca9cbf..d3ef6919a 100644
--- a/src/bun.js/api/bun.zig
+++ b/src/bun.js/api/bun.zig
@@ -3602,7 +3602,7 @@ pub const TOML = struct {
arguments: []const js.JSValueRef,
exception: js.ExceptionRef,
) js.JSValueRef {
- var arena = std.heap.ArenaAllocator.init(getAllocator(ctx));
+ var arena = @import("root").bun.ArenaAllocator.init(getAllocator(ctx));
var allocator = arena.allocator();
defer arena.deinit();
var log = logger.Log.init(default_allocator);
diff --git a/src/bun.js/api/bun/dns_resolver.zig b/src/bun.js/api/bun/dns_resolver.zig
index bec7e4d64..82411701d 100644
--- a/src/bun.js/api/bun/dns_resolver.zig
+++ b/src/bun.js/api/bun/dns_resolver.zig
@@ -241,7 +241,7 @@ pub fn addrInfoToJSArray(
globalThis: *JSC.JSGlobalObject,
) JSC.JSValue {
var stack = std.heap.stackFallback(2048, parent_allocator);
- var arena = std.heap.ArenaAllocator.init(stack.get());
+ var arena = @import("root").bun.ArenaAllocator.init(stack.get());
const array = JSC.JSValue.createEmptyArray(
globalThis,
addrInfoCount(addr_info),
@@ -553,7 +553,7 @@ pub const GetAddrInfo = struct {
.addrinfo => |addrinfo| addrInfoToJSArray(globalThis.allocator(), addrinfo orelse return null, globalThis),
.list => |list| brk: {
var stack = std.heap.stackFallback(2048, globalThis.allocator());
- var arena = std.heap.ArenaAllocator.init(stack.get());
+ var arena = @import("root").bun.ArenaAllocator.init(stack.get());
const array = JSC.JSValue.createEmptyArray(globalThis, @truncate(u32, list.items.len));
var i: u32 = 0;
const items: []const Result = list.items;
diff --git a/src/bun.js/api/bun/subprocess.zig b/src/bun.js/api/bun/subprocess.zig
index a996f863b..832afac78 100644
--- a/src/bun.js/api/bun/subprocess.zig
+++ b/src/bun.js/api/bun/subprocess.zig
@@ -1031,7 +1031,7 @@ pub const Subprocess = struct {
secondaryArgsValue: ?JSValue,
comptime is_sync: bool,
) JSValue {
- var arena = std.heap.ArenaAllocator.init(bun.default_allocator);
+ var arena = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
defer arena.deinit();
var allocator = arena.allocator();
diff --git a/src/bun.js/api/filesystem_router.zig b/src/bun.js/api/filesystem_router.zig
index d926ca7b3..216f66b7f 100644
--- a/src/bun.js/api/filesystem_router.zig
+++ b/src/bun.js/api/filesystem_router.zig
@@ -153,7 +153,7 @@ pub const FileSystemRouter = struct {
origin: ?*JSC.RefString = null,
base_dir: ?*JSC.RefString = null,
router: Router,
- arena: *std.heap.ArenaAllocator = undefined,
+ arena: *@import("root").bun.ArenaAllocator = undefined,
allocator: std.mem.Allocator = undefined,
asset_prefix: ?*JSC.RefString = null,
@@ -210,8 +210,8 @@ pub const FileSystemRouter = struct {
globalThis.throwInvalidArguments("Expected dir to be a string", .{});
return null;
}
- var arena = globalThis.allocator().create(std.heap.ArenaAllocator) catch unreachable;
- arena.* = std.heap.ArenaAllocator.init(globalThis.allocator());
+ var arena = globalThis.allocator().create(@import("root").bun.ArenaAllocator) catch unreachable;
+ arena.* = @import("root").bun.ArenaAllocator.init(globalThis.allocator());
var allocator = arena.allocator();
var extensions = std.ArrayList(string).init(allocator);
if (argument.get(globalThis, "fileExtensions")) |file_extensions| {
@@ -324,8 +324,8 @@ pub const FileSystemRouter = struct {
pub fn reload(this: *FileSystemRouter, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
var this_value = callframe.this();
- var arena = globalThis.allocator().create(std.heap.ArenaAllocator) catch unreachable;
- arena.* = std.heap.ArenaAllocator.init(globalThis.allocator());
+ var arena = globalThis.allocator().create(@import("root").bun.ArenaAllocator) catch unreachable;
+ arena.* = @import("root").bun.ArenaAllocator.init(globalThis.allocator());
var allocator = arena.allocator();
var vm = globalThis.bunVM();
diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig
index 0f967785e..8fd9acde7 100644
--- a/src/bun.js/api/server.zig
+++ b/src/bun.js/api/server.zig
@@ -296,7 +296,7 @@ pub const ServerConfig = struct {
var i: u32 = 0;
var valid_count: u32 = 0;
- var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
+ var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
while (i < count) : (i += 1) {
const item = js_obj.getIndex(global, i);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), item, exception)) |sb| {
@@ -351,7 +351,7 @@ pub const ServerConfig = struct {
}
} else {
const native_array = bun.default_allocator.alloc([*c]const u8, 1) catch unreachable;
- var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
+ var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), js_obj, exception)) |sb| {
const sliced = sb.slice();
if (sliced.len > 0) {
@@ -398,7 +398,7 @@ pub const ServerConfig = struct {
var i: u32 = 0;
var valid_count: u32 = 0;
- var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
+ var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
while (i < count) : (i += 1) {
const item = js_obj.getIndex(global, i);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), item, exception)) |sb| {
@@ -453,7 +453,7 @@ pub const ServerConfig = struct {
}
} else {
const native_array = bun.default_allocator.alloc([*c]const u8, 1) catch unreachable;
- var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
+ var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), js_obj, exception)) |sb| {
const sliced = sb.slice();
if (sliced.len > 0) {
@@ -513,7 +513,7 @@ pub const ServerConfig = struct {
var i: u32 = 0;
var valid_count: u32 = 0;
- var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
+ var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
while (i < count) : (i += 1) {
const item = js_obj.getIndex(global, i);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), item, exception)) |sb| {
@@ -568,7 +568,7 @@ pub const ServerConfig = struct {
}
} else {
const native_array = bun.default_allocator.alloc([*c]const u8, 1) catch unreachable;
- var arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator);
+ var arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator);
if (JSC.Node.StringOrBuffer.fromJS(global, arena.allocator(), js_obj, exception)) |sb| {
const sliced = sb.slice();
if (sliced.len > 0) {
diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig
index cd0684398..4e3e83bd7 100644
--- a/src/bun.js/base.zig
+++ b/src/bun.js/base.zig
@@ -2042,8 +2042,8 @@ pub const RefString = struct {
ptr: [*]const u8 = undefined,
len: usize = 0,
hash: Hash = 0,
+ impl: bun.WTF.StringImpl,
- count: u32 = 0,
allocator: std.mem.Allocator,
ctx: ?*anyopaque = null,
@@ -2053,17 +2053,13 @@ pub const RefString = struct {
pub const Map = std.HashMap(Hash, *JSC.RefString, IdentityContext(Hash), 80);
pub fn toJS(this: *RefString, global: *JSC.JSGlobalObject) JSValue {
- return JSC.ZigString.init(this.slice()).external(global, this, RefString__external);
+ return bun.String.init(this.impl).toJS(global);
}
pub const Callback = fn (ctx: *anyopaque, str: *RefString) void;
pub fn computeHash(input: []const u8) u32 {
- return @truncate(u32, std.hash.Wyhash.hash(0, input));
- }
-
- pub fn ref(this: *RefString) void {
- this.count += 1;
+ return std.hash.XxHash32.hash(input);
}
pub fn slice(this: *RefString) []const u8 {
@@ -2072,25 +2068,21 @@ pub const RefString = struct {
return this.leak();
}
+ pub fn ref(this: *RefString) void {
+ this.impl.ref();
+ }
+
pub fn leak(this: RefString) []const u8 {
@setRuntimeSafety(false);
return this.ptr[0..this.len];
}
pub fn deref(this: *RefString) void {
- this.count -|= 1;
-
- if (this.count == 0) {
- this.deinit();
- }
- }
-
- pub export fn RefString__free(this: *RefString, _: [*]const u8, _: usize) void {
- this.deref();
+ this.impl.deref();
}
- pub export fn RefString__external(this: ?*anyopaque, _: ?*anyopaque, _: usize) void {
- bun.cast(*RefString, this.?).deref();
+ pub export fn RefString__free(this: *anyopaque, _: *anyopaque, _: u32) void {
+ bun.cast(*RefString, this).deinit();
}
pub fn deinit(this: *RefString) void {
diff --git a/src/bun.js/bindings/BunString.cpp b/src/bun.js/bindings/BunString.cpp
index 797f66545..249f68435 100644
--- a/src/bun.js/bindings/BunString.cpp
+++ b/src/bun.js/bindings/BunString.cpp
@@ -2,7 +2,8 @@
#include "headers-handwritten.h"
#include "JavaScriptCore/JSCJSValueInlines.h"
#include "helpers.h"
-
+#include "simdutf.h"
+#include "wtf/text/ExternalStringImpl.h"
using namespace JSC;
extern "C" void Bun__WTFStringImpl__deref(WTF::StringImpl* impl)
@@ -124,6 +125,30 @@ extern "C" JSC::EncodedJSValue BunString__toJS(JSC::JSGlobalObject* globalObject
return JSValue::encode(Bun::toJS(globalObject, *bunString));
}
+extern "C" BunString BunString__fromLatin1(const char* bytes, size_t length)
+{
+ return { BunStringTag::WTFStringImpl, { .wtf = &WTF::StringImpl::create(bytes, length).leakRef() } };
+}
+
+extern "C" BunString BunString__fromBytes(const char* bytes, size_t length)
+{
+ if (simdutf::validate_ascii(bytes, length)) {
+ return BunString__fromLatin1(bytes, length);
+ }
+
+ auto str = WTF::String::fromUTF8ReplacingInvalidSequences(reinterpret_cast<const LChar*>(bytes), length);
+ return Bun::fromString(str);
+}
+
+extern "C" BunString BunString__createExternal(const char* bytes, size_t length, bool isLatin1, void* ctx, void (*callback)(void* arg0, void* arg1, size_t arg2))
+{
+ Ref<WTF::ExternalStringImpl> impl = isLatin1 ? WTF::ExternalStringImpl::create(reinterpret_cast<const LChar*>(bytes), length, ctx, callback) :
+
+ WTF::ExternalStringImpl::create(reinterpret_cast<const UChar*>(bytes), length, ctx, callback);
+
+ return { BunStringTag::WTFStringImpl, { .wtf = &impl.leakRef() } };
+}
+
extern "C" void BunString__toWTFString(BunString* bunString)
{
if (bunString->tag == BunStringTag::ZigString) {
diff --git a/src/bun.js/bindings/CommonJSModuleRecord.cpp b/src/bun.js/bindings/CommonJSModuleRecord.cpp
index fcf3dfe8c..31c24bb66 100644
--- a/src/bun.js/bindings/CommonJSModuleRecord.cpp
+++ b/src/bun.js/bindings/CommonJSModuleRecord.cpp
@@ -62,6 +62,8 @@
#include <JavaScriptCore/JSMap.h>
#include <JavaScriptCore/JSMapInlines.h>
+#include <JavaScriptCore/GetterSetter.h>
+#include "ZigSourceProvider.h"
namespace Bun {
using namespace JSC;
@@ -76,13 +78,15 @@ public:
mutable JSC::WriteBarrier<JSC::Unknown> m_exportsObject;
mutable JSC::WriteBarrier<JSC::JSString> m_id;
+ mutable JSC::WriteBarrier<JSC::EvalExecutable> m_executable;
- void finishCreation(JSC::VM& vm, JSC::JSValue exportsObject, JSC::JSString* id)
+ void finishCreation(JSC::VM& vm, JSC::JSValue exportsObject, JSC::JSString* id, JSC::JSString* filename, JSC::JSValue requireFunction, JSC::EvalExecutable* executable)
{
Base::finishCreation(vm);
ASSERT(inherits(vm, info()));
m_exportsObject.set(vm, this, exportsObject);
m_id.set(vm, this, id);
+ m_executable.set(vm, this, executable);
this->putDirectOffset(
vm,
@@ -98,16 +102,27 @@ public:
vm,
2,
id);
+ this->putDirectOffset(
+ vm,
+ 3,
+ filename);
+ this->putDirectOffset(
+ vm,
+ 4,
+ requireFunction);
}
static JSCommonJSModule* create(
JSC::VM& vm,
JSC::Structure* structure,
JSC::JSValue exportsObject,
- JSC::JSString* id)
+ JSC::JSString* id,
+ JSC::JSString* filename,
+ JSC::JSValue requireFunction,
+ JSC::EvalExecutable* executable)
{
JSCommonJSModule* cell = new (NotNull, JSC::allocateCell<JSCommonJSModule>(vm)) JSCommonJSModule(vm, structure);
- cell->finishCreation(vm, exportsObject, id);
+ cell->finishCreation(vm, exportsObject, id, filename, requireFunction, executable);
return cell;
}
@@ -240,6 +255,7 @@ void JSCommonJSModule::visitChildrenImpl(JSCell* cell, Visitor& visitor)
Base::visitChildren(thisObject, visitor);
visitor.append(thisObject->m_exportsObject);
visitor.append(thisObject->m_id);
+ visitor.append(thisObject->m_executable);
}
DEFINE_VISIT_CHILDREN(JSCommonJSModule);
@@ -250,7 +266,9 @@ JSCommonJSModule* createCommonJSModuleObject(
const ResolvedSource& source,
const WTF::String& sourceURL,
JSC::JSValue exportsObjectValue,
- JSC::JSValue requireFunctionValue)
+ JSC::JSValue requireFunctionValue,
+ JSC::EvalExecutable* executable,
+ JSC::JSString* filename)
{
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
@@ -260,12 +278,7 @@ JSCommonJSModule* createCommonJSModuleObject(
vm,
globalObject->CommonJSModuleObjectStructure(),
exportsObjectValue,
- jsSourceURL);
-
- moduleObject->putDirectOffset(
- vm,
- 3,
- requireFunctionValue);
+ jsSourceURL, filename, requireFunctionValue, executable);
return moduleObject;
}
@@ -291,25 +304,24 @@ JSC::SourceCode createCommonJSModule(
Zig::GlobalObject* globalObject,
ResolvedSource source)
{
-
auto sourceURL = Zig::toStringCopy(source.source_url);
+ auto sourceProvider = Zig::SourceProvider::create(globalObject, source, JSC::SourceProviderSourceType::Program);
return JSC::SourceCode(
JSC::SyntheticSourceProvider::create(
- [source, sourceURL](JSC::JSGlobalObject* lexicalGlobalObject,
+ [source, sourceProvider = WTFMove(sourceProvider), sourceURL](JSC::JSGlobalObject* lexicalGlobalObject,
JSC::Identifier moduleKey,
Vector<JSC::Identifier, 4>& exportNames,
JSC::MarkedArgumentBuffer& exportValues) -> void {
- Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
auto& vm = globalObject->vm();
+
auto throwScope = DECLARE_THROW_SCOPE(vm);
- auto sourceCodeString = Zig::toString(source.source_code);
auto* requireMapKey = jsString(vm, sourceURL);
JSC::JSObject* exportsObject = source.commonJSExportsLen < 64
? JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), source.commonJSExportsLen)
: JSC::constructEmptyObject(globalObject, globalObject->objectPrototype());
-
auto index = sourceURL.reverseFind('/', sourceURL.length());
JSString* dirname = jsEmptyString(vm);
JSString* filename = requireMapKey;
@@ -318,11 +330,8 @@ JSC::SourceCode createCommonJSModule(
}
globalObject->requireMap()->set(globalObject, requireMapKey, exportsObject);
-
JSC::SourceCode inputSource(
- JSC::StringSourceProvider::create(sourceCodeString,
- JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(sourceURL)),
- sourceURL, TextPosition()));
+ WTFMove(sourceProvider));
JSC::Structure* scopeExtensionObjectStructure = globalObject->commonJSFunctionArgumentsStructure();
JSC::JSObject* scopeExtensionObject = JSC::constructEmptyObject(
@@ -330,12 +339,27 @@ JSC::SourceCode createCommonJSModule(
scopeExtensionObjectStructure);
auto* requireFunction = Zig::ImportMetaObject::createRequireFunction(vm, globalObject, sourceURL);
+ auto* executable = JSC::DirectEvalExecutable::create(
+ globalObject, inputSource, DerivedContextType::None, NeedsClassFieldInitializer::No, PrivateBrandRequirement::None,
+ false, false, EvalContextType::None, nullptr, nullptr, ECMAMode::sloppy());
+
+ if (UNLIKELY(!executable && !throwScope.exception())) {
+ // I'm not sure if this case happens, but it's better to be safe than sorry.
+ throwSyntaxError(globalObject, throwScope, "Failed to compile CommonJS module."_s);
+ }
+
+ if (UNLIKELY(throwScope.exception())) {
+ globalObject->requireMap()->remove(globalObject, requireMapKey);
+ throwScope.release();
+ return;
+ }
auto* moduleObject = createCommonJSModuleObject(globalObject,
source,
sourceURL,
exportsObject,
- requireFunction);
+ requireFunction, executable, filename);
+
scopeExtensionObject->putDirectOffset(
vm,
0,
@@ -361,15 +385,6 @@ JSC::SourceCode createCommonJSModule(
4,
requireFunction);
- auto* executable = JSC::DirectEvalExecutable::create(
- globalObject, inputSource, DerivedContextType::None, NeedsClassFieldInitializer::No, PrivateBrandRequirement::None,
- false, false, EvalContextType::None, nullptr, nullptr, ECMAMode::sloppy());
-
- if (UNLIKELY(!executable && !throwScope.exception())) {
- // I'm not sure if this case happens, but it's better to be safe than sorry.
- throwSyntaxError(globalObject, throwScope, "Failed to compile CommonJS module."_s);
- }
-
if (UNLIKELY(throwScope.exception())) {
globalObject->requireMap()->remove(globalObject, requireMapKey);
throwScope.release();
@@ -432,7 +447,12 @@ JSC::SourceCode createCommonJSModule(
// - Object.defineProperty(module, 'exports', {get: getter})
// - delete module.exports
//
- result = moduleObject->getIfPropertyExists(globalObject, clientData->builtinNames().exportsPublicName());
+ if (result.isGetterSetter()) {
+ JSC::GetterSetter* getter = jsCast<JSC::GetterSetter*>(result);
+ result = getter->callGetter(globalObject, moduleObject);
+ } else {
+ result = moduleObject->getIfPropertyExists(globalObject, clientData->builtinNames().exportsPublicName());
+ }
if (UNLIKELY(throwScope.exception())) {
// Unlike getters on properties of the exports object
@@ -454,17 +474,15 @@ JSC::SourceCode createCommonJSModule(
exportNames.append(Identifier::fromUid(vm.symbolRegistry().symbolForKey("CommonJS"_s)));
exportValues.append(jsNumber(0));
- // This strong reference exists because otherwise it will crash when the finalizer runs.
- exportNames.append(Identifier::fromUid(vm.symbolRegistry().symbolForKey("module"_s)));
- exportValues.append(moduleObject);
+ moduleObject->m_executable.clear();
if (result.isObject()) {
auto* exports = asObject(result);
auto* structure = exports->structure();
uint32_t size = structure->inlineSize() + structure->outOfLineSize();
- exportNames.reserveCapacity(size + 3);
- exportValues.ensureCapacity(size + 3);
+ exportNames.reserveCapacity(size + 2);
+ exportValues.ensureCapacity(size + 2);
if (canPerformFastEnumeration(structure)) {
exports->structure()->forEachProperty(vm, [&](const PropertyTableEntry& entry) -> bool {
diff --git a/src/bun.js/bindings/ModuleLoader.cpp b/src/bun.js/bindings/ModuleLoader.cpp
index 035cd15c8..ed1e5702b 100644
--- a/src/bun.js/bindings/ModuleLoader.cpp
+++ b/src/bun.js/bindings/ModuleLoader.cpp
@@ -282,7 +282,7 @@ static JSValue handleVirtualModuleResult(
return reject(JSValue::decode(reinterpret_cast<EncodedJSValue>(res->result.err.ptr)));
}
- auto provider = Zig::SourceProvider::create(res->result.value);
+ auto provider = Zig::SourceProvider::create(globalObject, res->result.value);
return resolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)));
}
case OnLoadResultTypeError: {
@@ -346,7 +346,7 @@ extern "C" void Bun__onFulfillAsyncModule(
return promise->reject(promise->globalObject(), exception);
}
- auto provider = Zig::SourceProvider::create(res->result.value);
+ auto provider = Zig::SourceProvider::create(jsDynamicCast<Zig::GlobalObject*>(globalObject), res->result.value);
promise->resolve(promise->globalObject(), JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)));
}
@@ -457,8 +457,8 @@ static JSValue fetchSourceCode(
return rejectOrResolve(JSSourceCode::create(vm, WTFMove(source)));
}
default: {
- auto provider = Zig::SourceProvider::create(res->result.value);
- return rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(WTFMove(provider))));
+ auto&& provider = Zig::SourceProvider::create(globalObject, res->result.value);
+ return rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)));
}
}
}
@@ -488,8 +488,8 @@ static JSValue fetchSourceCode(
return reject(exception);
}
- auto provider = Zig::SourceProvider::create(res->result.value);
- return rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(WTFMove(provider))));
+ auto&& provider = Zig::SourceProvider::create(globalObject, res->result.value);
+ return rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)));
}
extern "C" JSC::EncodedJSValue jsFunctionOnLoadObjectResultResolve(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame)
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index 8926be6bb..f2f5a372b 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -4044,7 +4044,12 @@ void GlobalObject::reload()
registry->clear(this->vm());
this->requireMap()->clear(this->vm());
- this->vm().heap.collectSync();
+
+ // If we run the GC every time, we will never get the SourceProvider cache hit.
+ // So we run the GC every other time.
+ if ((this->reloadCount++ + 1) % 2 == 0) {
+ this->vm().heap.collectSync();
+ }
}
extern "C" void JSC__JSGlobalObject__reload(JSC__JSGlobalObject* arg0)
diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h
index 3cf88bf29..d5f933540 100644
--- a/src/bun.js/bindings/ZigGlobalObject.h
+++ b/src/bun.js/bindings/ZigGlobalObject.h
@@ -388,6 +388,12 @@ public:
BunPlugin::OnResolve onResolvePlugins[BunPluginTargetMax + 1] {};
BunPluginTarget defaultBunPluginTarget = BunPluginTargetBun;
+ // This increases the cache hit rate for JSC::VM's SourceProvider cache
+ // It also avoids an extra allocation for the SourceProvider
+ // The key is a pointer to the source code
+ WTF::HashMap<uintptr_t, Ref<JSC::SourceProvider>> sourceProviderMap;
+ size_t reloadCount = 0;
+
void reload();
JSC::Structure* pendingVirtualModuleResultStructure() { return m_pendingVirtualModuleResultStructure.get(this); }
diff --git a/src/bun.js/bindings/ZigSourceProvider.cpp b/src/bun.js/bindings/ZigSourceProvider.cpp
index 7b3a8ffbc..d42d6b445 100644
--- a/src/bun.js/bindings/ZigSourceProvider.cpp
+++ b/src/bun.js/bindings/ZigSourceProvider.cpp
@@ -5,6 +5,7 @@
#include "ZigSourceProvider.h"
#include "JavaScriptCore/BytecodeCacheError.h"
+#include "ZigGlobalObject.h"
#include "JavaScriptCore/Completion.h"
#include "wtf/Scope.h"
@@ -26,67 +27,73 @@ using SourceOrigin = JSC::SourceOrigin;
using String = WTF::String;
using SourceProviderSourceType = JSC::SourceProviderSourceType;
-Ref<SourceProvider> SourceProvider::create(ResolvedSource resolvedSource)
+static uintptr_t getSourceProviderMapKey(ResolvedSource& resolvedSource)
{
- void* allocator = resolvedSource.allocator;
+ switch (resolvedSource.source_code.tag) {
+ case BunStringTag::WTFStringImpl: {
+ return (uintptr_t)resolvedSource.source_code.impl.wtf->characters8();
+ }
+ case BunStringTag::StaticZigString:
+ case BunStringTag::ZigString: {
+ return (uintptr_t)Zig::untag(resolvedSource.source_code.impl.zig.ptr);
+ }
+ default: {
+ return 0;
+ }
+ }
+}
- JSC::SourceProviderSourceType sourceType = JSC::SourceProviderSourceType::Module;
+Ref<SourceProvider> SourceProvider::create(Zig::GlobalObject* globalObject, ResolvedSource resolvedSource, JSC::SourceProviderSourceType sourceType)
+{
- // // JSC owns the memory
- // if (resolvedSource.hash == 1) {
- // return adoptRef(*new SourceProvider(
- // resolvedSource, WTF::StringImpl::create(resolvedSource.source_code.ptr, resolvedSource.source_code.len),
- // JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(toString(resolvedSource.source_url))),
- // toStringNotConst(resolvedSource.source_url).isolatedCopy(), TextPosition(),
- // sourceType));
- // }
+ uintptr_t providerKey = 0;
+ if (globalObject->isThreadLocalDefaultGlobalObject) {
+ auto& sourceProviderMap = globalObject->sourceProviderMap;
+ providerKey = getSourceProviderMapKey(resolvedSource);
+ if (providerKey) {
+ auto sourceProvider = sourceProviderMap.get(providerKey);
+ if (sourceProvider != nullptr) {
+ sourceProvider->ref();
+ return adoptRef(*reinterpret_cast<Zig::SourceProvider*>(sourceProvider));
+ }
+ }
+ }
+ auto stringImpl = Bun::toWTFString(resolvedSource.source_code);
+
+ if (stringImpl.impl()->refCount() > 1)
+ // Deref because we don't call a destructor for BunString
+ stringImpl.impl()->deref();
- if (allocator) {
- Ref<WTF::ExternalStringImpl> stringImpl_ = WTF::ExternalStringImpl::create(
- resolvedSource.source_code.ptr, resolvedSource.source_code.len,
- allocator,
- RefString__free);
- return adoptRef(*new SourceProvider(
- resolvedSource, stringImpl_,
- JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(toString(resolvedSource.source_url))),
- toStringNotConst(resolvedSource.source_url), TextPosition(),
- sourceType));
- } else {
- Ref<WTF::ExternalStringImpl> stringImpl_ = WTF::ExternalStringImpl::createStatic(
- resolvedSource.source_code.ptr, resolvedSource.source_code.len);
- return adoptRef(*new SourceProvider(
- resolvedSource, stringImpl_,
- JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(toString(resolvedSource.source_url))),
- toStringNotConst(resolvedSource.source_url), TextPosition(),
- sourceType));
+ auto provider = adoptRef(*new SourceProvider(
+ globalObject->isThreadLocalDefaultGlobalObject ? globalObject : nullptr,
+ resolvedSource, stringImpl.releaseImpl().releaseNonNull(),
+ JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(toString(resolvedSource.source_url))),
+ toStringNotConst(resolvedSource.source_url), TextPosition(),
+ sourceType));
+
+ if (providerKey) {
+ globalObject->sourceProviderMap.set(providerKey, provider.copyRef());
}
+
+ return provider;
}
-unsigned SourceProvider::getHash()
+unsigned SourceProvider::hash() const
{
if (m_hash) {
return m_hash;
}
- m_hash = WTF::StringHash::hash(m_source.get());
- return m_hash;
+ return m_source->hash();
}
void SourceProvider::freeSourceCode()
{
- if (did_free_source_code) {
- return;
+ if (m_globalObjectForSourceProviderMap) {
+ m_globalObjectForSourceProviderMap->sourceProviderMap.remove((uintptr_t)m_source.get().characters8());
}
- did_free_source_code = true;
- if (m_resolvedSource.allocator != 0) { // // WTF::ExternalStringImpl::destroy(m_source.ptr());
- this->m_source = WTF::StringImpl::empty()->isolatedCopy();
- this->m_hash = 0;
- m_resolvedSource.allocator = 0;
- }
- // if (m_resolvedSource.allocator != 0) {
- // ZigString__free(m_resolvedSource.source_code.ptr, m_resolvedSource.source_code.len,
- // m_resolvedSource.allocator);
- // }
+
+ m_source = *WTF::StringImpl::empty();
}
void SourceProvider::updateCache(const UnlinkedFunctionExecutable* executable, const SourceCode&,
diff --git a/src/bun.js/bindings/ZigSourceProvider.h b/src/bun.js/bindings/ZigSourceProvider.h
index 5219bd2c1..dd78b20ae 100644
--- a/src/bun.js/bindings/ZigSourceProvider.h
+++ b/src/bun.js/bindings/ZigSourceProvider.h
@@ -20,6 +20,8 @@ class SourceProvider;
namespace Zig {
+class GlobalObject;
+
class SourceProvider final : public JSC::SourceProvider {
WTF_MAKE_FAST_ALLOCATED;
using Base = JSC::SourceProvider;
@@ -32,7 +34,7 @@ class SourceProvider final : public JSC::SourceProvider {
using SourceOrigin = JSC::SourceOrigin;
public:
- static Ref<SourceProvider> create(ResolvedSource resolvedSource);
+ static Ref<SourceProvider> create(Zig::GlobalObject*, ResolvedSource resolvedSource, JSC::SourceProviderSourceType sourceType = JSC::SourceProviderSourceType::Module);
~SourceProvider()
{
freeSourceCode();
@@ -40,8 +42,8 @@ public:
commitCachedBytecode();
}
- unsigned hash() const { return m_hash; };
- StringView source() const { return StringView(m_source.get()); }
+ unsigned hash() const override;
+ StringView source() const override { return StringView(m_source.get()); }
RefPtr<JSC::CachedBytecode> cachedBytecode()
{
// if (m_resolvedSource.bytecodecache_fd == 0) {
@@ -62,7 +64,7 @@ public:
void freeSourceCode();
private:
- SourceProvider(ResolvedSource resolvedSource, WTF::StringImpl& sourceImpl,
+ SourceProvider(Zig::GlobalObject* globalObject, ResolvedSource resolvedSource, Ref<WTF::StringImpl>&& sourceImpl,
const SourceOrigin& sourceOrigin, WTF::String&& sourceURL,
const TextPosition& startPosition, JSC::SourceProviderSourceType sourceType)
: Base(sourceOrigin, WTFMove(sourceURL), String(), startPosition, sourceType)
@@ -70,17 +72,14 @@ private:
{
m_resolvedSource = resolvedSource;
-
- m_hash = resolvedSource.hash;
-
- getHash();
}
- unsigned m_hash;
- unsigned getHash();
RefPtr<JSC::CachedBytecode> m_cachedBytecode;
Ref<WTF::StringImpl> m_source;
bool did_free_source_code = false;
+ Zig::GlobalObject* m_globalObjectForSourceProviderMap;
+ unsigned m_hash;
+
// JSC::SourceCodeKey key;
};
diff --git a/src/bun.js/bindings/exports.zig b/src/bun.js/bindings/exports.zig
index e48acb8c4..6ea1eba60 100644
--- a/src/bun.js/bindings/exports.zig
+++ b/src/bun.js/bindings/exports.zig
@@ -203,7 +203,7 @@ pub const ResolvedSource = extern struct {
pub const namespace = shim.namespace;
specifier: bun.String,
- source_code: ZigString,
+ source_code: bun.String,
source_url: ZigString,
commonjs_exports: ?[*]ZigString = null,
commonjs_exports_len: u32 = 0,
diff --git a/src/bun.js/bindings/headers-handwritten.h b/src/bun.js/bindings/headers-handwritten.h
index 9a8cb1ef3..b845c4e00 100644
--- a/src/bun.js/bindings/headers-handwritten.h
+++ b/src/bun.js/bindings/headers-handwritten.h
@@ -64,7 +64,7 @@ typedef struct ErrorableString {
} ErrorableString;
typedef struct ResolvedSource {
BunString specifier;
- ZigString source_code;
+ BunString source_code;
ZigString source_url;
ZigString* commonJSExports;
uint32_t commonJSExportsLen;
diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig
index 5bd066a9a..63d024ad7 100644
--- a/src/bun.js/javascript.zig
+++ b/src/bun.js/javascript.zig
@@ -449,6 +449,8 @@ pub const VirtualMachine = struct {
modules: ModuleLoader.AsyncModule.Queue = .{},
aggressive_garbage_collection: GCLevel = GCLevel.none,
+ parser_arena: ?@import("root").bun.ArenaAllocator = null,
+
gc_controller: JSC.GarbageCollectionController = .{},
pub const OnUnhandledRejection = fn (*VirtualMachine, globalObject: *JSC.JSGlobalObject, JSC.JSValue) void;
@@ -780,6 +782,7 @@ pub const VirtualMachine = struct {
.ref_strings = JSC.RefString.Map.init(allocator),
.file_blobs = JSC.WebCore.Blob.Store.Map.init(allocator),
.standalone_module_graph = graph,
+ .parser_arena = @import("root").bun.ArenaAllocator.init(allocator),
};
vm.source_mappings = .{ .map = &vm.saved_source_map_table };
vm.regular_event_loop.tasks = EventLoop.Queue.init(
@@ -876,6 +879,7 @@ pub const VirtualMachine = struct {
.origin_timestamp = getOriginTimestamp(),
.ref_strings = JSC.RefString.Map.init(allocator),
.file_blobs = JSC.WebCore.Blob.Store.Map.init(allocator),
+ .parser_arena = @import("root").bun.ArenaAllocator.init(allocator),
};
vm.source_mappings = .{ .map = &vm.saved_source_map_table };
vm.regular_event_loop.tasks = EventLoop.Queue.init(
@@ -936,11 +940,15 @@ pub const VirtualMachine = struct {
_ = VirtualMachine.get().ref_strings.remove(ref_string.hash);
}
- pub fn refCountedResolvedSource(this: *VirtualMachine, code: []const u8, specifier: bun.String, source_url: []const u8, hash_: ?u32) ResolvedSource {
- var source = this.refCountedString(code, hash_, true);
+ pub fn refCountedResolvedSource(this: *VirtualMachine, code: []const u8, specifier: bun.String, source_url: []const u8, hash_: ?u32, comptime add_double_ref: bool) ResolvedSource {
+ var source = this.refCountedString(code, hash_, !add_double_ref);
+ if (add_double_ref) {
+ source.ref();
+ source.ref();
+ }
return ResolvedSource{
- .source_code = ZigString.init(source.slice()),
+ .source_code = bun.String.init(source.impl),
.specifier = specifier,
.source_url = ZigString.init(source_url),
.hash = source.hash,
@@ -963,6 +971,7 @@ pub const VirtualMachine = struct {
.allocator = this.allocator,
.ptr = input.ptr,
.len = input.len,
+ .impl = bun.String.createExternal(input, true, ref, &JSC.RefString.RefString__free).value.WTFStringImpl,
.hash = hash,
.ctx = this,
.onBeforeDeinit = VirtualMachine.clearRefString,
@@ -1432,9 +1441,9 @@ pub const VirtualMachine = struct {
};
if (vm.has_loaded) {
- blobs.temporary.put(specifier_blob, .{ .ptr = result.source_code._unsafe_ptr_do_not_use, .len = result.source_code.len }) catch {};
+ blobs.temporary.put(specifier_blob, .{ .ptr = result.source_code.byteSlice().ptr, .len = result.source_code.length() }) catch {};
} else {
- blobs.persistent.put(specifier_blob, .{ .ptr = result.source_code._unsafe_ptr_do_not_use, .len = result.source_code.len }) catch {};
+ blobs.persistent.put(specifier_blob, .{ .ptr = result.source_code.byteSlice().ptr, .len = result.source_code.length() }) catch {};
}
}
@@ -2033,7 +2042,9 @@ pub const VirtualMachine = struct {
var log = logger.Log.init(default_allocator);
var errorable: ErrorableResolvedSource = undefined;
var original_source = fetchWithoutOnLoadPlugins(this, this.global, bun.String.init(top.source_url), bun.String.empty, &log, &errorable, .print_source) catch return;
- const code = original_source.source_code.slice();
+ const code = original_source.source_code.toUTF8(bun.default_allocator);
+ defer code.deinit();
+
top.position.line = mapping.original.lines;
top.position.line_start = mapping.original.lines;
top.position.line_stop = mapping.original.lines + 1;
@@ -2046,7 +2057,7 @@ pub const VirtualMachine = struct {
top.position.expression_stop = mapping.original.columns + 1;
if (strings.getLinesInText(
- code,
+ code.slice(),
@intCast(u32, top.position.line),
JSC.ZigException.Holder.source_lines_count,
)) |lines| {
diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig
index 4611adea4..d115573be 100644
--- a/src/bun.js/module_loader.zig
+++ b/src/bun.js/module_loader.zig
@@ -142,7 +142,7 @@ fn jsModuleFromFile(from_path: string, comptime input: string) string {
inline fn jsSyntheticModule(comptime name: ResolvedSource.Tag, specifier: String) ResolvedSource {
return ResolvedSource{
.allocator = null,
- .source_code = ZigString.init(""),
+ .source_code = bun.String.empty,
.specifier = specifier,
.source_url = ZigString.init(@tagName(name)),
.hash = 0,
@@ -185,6 +185,7 @@ pub const ModuleLoader = struct {
loader: Api.Loader,
hash: u32 = std.math.maxInt(u32),
globalThis: *JSC.JSGlobalObject = undefined,
+ arena: bun.ArenaAllocator,
// This is the specific state for making it async
poll_ref: JSC.PollRef = .{},
@@ -515,6 +516,7 @@ pub const ModuleLoader = struct {
// .stmt_blocks = stmt_blocks,
// .expr_blocks = expr_blocks,
.globalThis = globalObject,
+ .arena = opts.arena,
};
}
@@ -809,7 +811,7 @@ pub const ModuleLoader = struct {
}
if (jsc_vm.isWatcherEnabled()) {
- var resolved_source = jsc_vm.refCountedResolvedSource(printer.ctx.written, bun.String.init(specifier), path.text, null);
+ var resolved_source = jsc_vm.refCountedResolvedSource(printer.ctx.written, bun.String.init(specifier), path.text, null, false);
if (parse_result.input_fd) |fd_| {
if (jsc_vm.bun_watcher != null and std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) {
@@ -841,7 +843,7 @@ pub const ModuleLoader = struct {
return ResolvedSource{
.allocator = null,
- .source_code = ZigString.init(try default_allocator.dupe(u8, printer.ctx.getWritten())),
+ .source_code = bun.String.createLatin1(printer.ctx.getWritten()),
.specifier = String.init(specifier),
.source_url = ZigString.init(path.text),
.commonjs_exports = if (commonjs_exports.len > 0)
@@ -863,10 +865,12 @@ pub const ModuleLoader = struct {
}
pub fn deinit(this: *AsyncModule) void {
+ this.promise.deinit();
this.parse_result.deinit();
+ this.arena.deinit();
// bun.default_allocator.free(this.stmt_blocks);
// bun.default_allocator.free(this.expr_blocks);
- this.promise.deinit();
+
bun.default_allocator.free(this.string_buf);
}
@@ -914,7 +918,32 @@ pub const ModuleLoader = struct {
jsc_vm.bundler.resetStore();
const hash = http.Watcher.getHash(path.text);
- var allocator = if (jsc_vm.has_loaded) jsc_vm.arena.allocator() else jsc_vm.allocator;
+ var arena: bun.ArenaAllocator = undefined;
+
+ // Attempt to reuse the Arena from the parser when we can
+ // This code is potentially re-entrant, so only one Arena can be reused at a time
+ // That's why we have to check if the Arena is null
+ //
+ // Using an Arena here is a significant memory optimization when loading many files
+ if (jsc_vm.parser_arena) |shared| {
+ arena = shared;
+ jsc_vm.parser_arena = null;
+ _ = arena.reset(.retain_capacity);
+ } else {
+ arena = bun.ArenaAllocator.init(jsc_vm.allocator);
+ }
+ var give_back_arena = true;
+ defer {
+ if (give_back_arena) {
+ if (jsc_vm.parser_arena == null) {
+ jsc_vm.parser_arena = arena;
+ } else {
+ arena.deinit();
+ }
+ }
+ }
+
+ var allocator = arena.allocator();
var fd: ?StoredFileDescriptorType = null;
var package_json: ?*PackageJSON = null;
@@ -1014,7 +1043,7 @@ pub const ModuleLoader = struct {
};
if (parse_result.loader == .wasm) {
- const wasm_result = transpileSourceCode(
+ return transpileSourceCode(
jsc_vm,
specifier,
display_specifier,
@@ -1030,7 +1059,6 @@ pub const ModuleLoader = struct {
globalObject,
flags,
);
- return wasm_result;
}
if (comptime !disable_transpilying) {
@@ -1059,8 +1087,8 @@ pub const ModuleLoader = struct {
return ResolvedSource{
.allocator = null,
.source_code = switch (comptime flags) {
- .print_source_and_clone => ZigString.init(jsc_vm.allocator.dupe(u8, parse_result.source.contents) catch unreachable),
- .print_source => ZigString.init(parse_result.source.contents),
+ .print_source_and_clone => bun.String.init(jsc_vm.allocator.dupe(u8, parse_result.source.contents) catch unreachable),
+ .print_source => bun.String.static(parse_result.source.contents),
else => unreachable,
},
.specifier = input_specifier,
@@ -1072,7 +1100,7 @@ pub const ModuleLoader = struct {
if (parse_result.already_bundled) {
return ResolvedSource{
.allocator = null,
- .source_code = ZigString.init(try default_allocator.dupe(u8, parse_result.source.contents)),
+ .source_code = bun.String.createLatin1(parse_result.source.contents),
.specifier = input_specifier,
.source_url = ZigString.init(path.text),
// // TODO: change hash to a bitfield
@@ -1126,8 +1154,11 @@ pub const ModuleLoader = struct {
.promise_ptr = promise_ptr,
.specifier = specifier,
.referrer = referrer,
+ .arena = arena,
},
);
+ arena = bun.ArenaAllocator.init(bun.default_allocator);
+ give_back_arena = false;
return error.AsyncModule;
}
@@ -1150,12 +1181,13 @@ pub const ModuleLoader = struct {
};
if (written == 0) {
+
// if it's an empty file but there were plugins
// we don't want it to break if you try to import from it
if (has_bun_plugin) {
return ResolvedSource{
.allocator = null,
- .source_code = ZigString.init("// auto-generated plugin stub\nexport default undefined\n"),
+ .source_code = String.static("// auto-generated plugin stub\nexport default undefined\n"),
.specifier = input_specifier,
.source_url = ZigString.init(path.text),
// // TODO: change hash to a bitfield
@@ -1178,7 +1210,7 @@ pub const ModuleLoader = struct {
}
if (jsc_vm.isWatcherEnabled()) {
- var resolved_source = jsc_vm.refCountedResolvedSource(printer.ctx.written, input_specifier, path.text, null);
+ var resolved_source = jsc_vm.refCountedResolvedSource(printer.ctx.written, input_specifier, path.text, null, false);
resolved_source.commonjs_exports = if (commonjs_exports.len > 0)
commonjs_exports.ptr
@@ -1195,7 +1227,7 @@ pub const ModuleLoader = struct {
return .{
.allocator = null,
- .source_code = ZigString.init(try default_allocator.dupe(u8, printer.ctx.getWritten())),
+ .source_code = bun.String.createLatin1(printer.ctx.getWritten()),
.specifier = input_specifier,
.source_url = ZigString.init(path.text),
.commonjs_exports = if (commonjs_exports.len > 0)
@@ -1276,7 +1308,7 @@ pub const ModuleLoader = struct {
}
return ResolvedSource{
.allocator = null,
- .source_code = ZigString.init(
+ .source_code = bun.String.static(
strings.append3(
bun.default_allocator,
JSC.Node.fs.constants_string,
@@ -1326,7 +1358,7 @@ pub const ModuleLoader = struct {
writer.writeAll(";\n") catch unreachable;
}
- const public_url = ZigString.fromUTF8(jsc_vm.allocator.dupe(u8, buf.toOwnedSliceLeaky()) catch @panic("out of memory"));
+ const public_url = bun.String.create(buf.toOwnedSliceLeaky());
return ResolvedSource{
.allocator = &jsc_vm.allocator,
.source_code = public_url,
@@ -1614,7 +1646,7 @@ pub const ModuleLoader = struct {
return ResolvedSource{
.allocator = null,
- .source_code = ZigString.init(code),
+ .source_code = bun.String.init(code),
.specifier = bun.String.init(JSC.bun_file_import_path),
.source_url = ZigString.init(JSC.bun_file_import_path[1..]),
.hash = 0, // TODO
@@ -1622,7 +1654,7 @@ pub const ModuleLoader = struct {
} else if (jsc_vm.node_modules == null and specifier.eqlComptime(Runtime.Runtime.Imports.Name)) {
return ResolvedSource{
.allocator = null,
- .source_code = ZigString.init(Runtime.Runtime.sourceContentBun()),
+ .source_code = bun.String.init(Runtime.Runtime.sourceContentBun()),
.specifier = bun.String.init(Runtime.Runtime.Imports.Name),
.source_url = ZigString.init(Runtime.Runtime.Imports.Name),
.hash = Runtime.Runtime.versionHash(),
@@ -1636,13 +1668,35 @@ pub const ModuleLoader = struct {
if (comptime disable_transpilying) {
return ResolvedSource{
.allocator = null,
- .source_code = ZigString.fromBytes(jsc_vm.entry_point.source.contents),
+ .source_code = bun.String.init(jsc_vm.entry_point.source.contents),
.specifier = bun.String.init(bun.asByteSlice(JSC.VirtualMachine.main_file_name)),
.source_url = ZigString.init(bun.asByteSlice(JSC.VirtualMachine.main_file_name)),
.hash = 0,
};
}
defer jsc_vm.transpiled_count += 1;
+ var arena: bun.ArenaAllocator = undefined;
+
+ // Attempt to reuse the Arena from the parser when we can
+ // This code is potentially re-entrant, so only one Arena can be reused at a time
+ // That's why we have to check if the Arena is null
+ //
+ // Using an Arena here is a significant memory optimization when loading many files
+ if (jsc_vm.parser_arena) |shared| {
+ arena = shared;
+ jsc_vm.parser_arena = null;
+ _ = arena.reset(.retain_capacity);
+ } else {
+ arena = bun.ArenaAllocator.init(jsc_vm.allocator);
+ }
+
+ defer {
+ if (jsc_vm.parser_arena == null) {
+ jsc_vm.parser_arena = arena;
+ } else {
+ arena.deinit();
+ }
+ }
var bundler = &jsc_vm.bundler;
var old = jsc_vm.bundler.log;
@@ -1670,7 +1724,7 @@ pub const ModuleLoader = struct {
opts.filepath_hash_for_hmr = 0;
opts.warn_about_unbundled_modules = false;
opts.macro_context = &jsc_vm.bundler.macro_context.?;
- const main_ast = ((bundler.resolver.caches.js.parse(jsc_vm.allocator, opts, bundler.options.define, bundler.log, &jsc_vm.entry_point.source) catch null) orelse {
+ const main_ast = ((bundler.resolver.caches.js.parse(arena.allocator(), opts, bundler.options.define, bundler.log, &jsc_vm.entry_point.source) catch null) orelse {
return error.ParseError;
}).ast;
var parse_result = ParseResult{ .source = jsc_vm.entry_point.source, .ast = main_ast, .loader = .js, .input_fd = null };
@@ -1708,7 +1762,7 @@ pub const ModuleLoader = struct {
return ResolvedSource{
.allocator = null,
- .source_code = ZigString.init(jsc_vm.allocator.dupe(u8, printer.ctx.written) catch unreachable),
+ .source_code = bun.String.createLatin1(printer.ctx.written),
.specifier = specifier,
.source_url = ZigString.init(bun.asByteSlice(JSC.VirtualMachine.main_file_name)),
.hash = 0,
@@ -1725,7 +1779,7 @@ pub const ModuleLoader = struct {
.@"node:fs/promises" => {
return ResolvedSource{
.allocator = null,
- .source_code = ZigString.init(JSC.Node.fs.constants_string ++ @embedFile("../js/out/modules/node/fs.promises.js")),
+ .source_code = bun.String.static(comptime JSC.Node.fs.constants_string ++ @embedFile("../js/out/modules/node/fs.promises.js")),
.specifier = specifier,
.source_url = ZigString.init("node:fs/promises"),
.hash = 0,
@@ -1735,8 +1789,8 @@ pub const ModuleLoader = struct {
const shared_library_suffix = if (Environment.isMac) "dylib" else if (Environment.isLinux) "so" else if (Environment.isWindows) "dll" else "";
return ResolvedSource{
.allocator = null,
- .source_code = ZigString.init(
- "export const FFIType=" ++
+ .source_code = bun.String.static(
+ comptime "export const FFIType=" ++
JSC.FFI.ABIType.map_to_js_object ++
";export const suffix='" ++ shared_library_suffix ++ "';" ++
@embedFile("../js/out/modules/bun/ffi.js"),
@@ -1747,60 +1801,60 @@ pub const ModuleLoader = struct {
};
},
- .@"bun:jsc" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"bun:jsc", "bun/jsc.js", specifier),
- .@"bun:sqlite" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"bun:sqlite", "bun/sqlite.js", specifier),
-
- .@"node:assert" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:assert", "node/assert.js", specifier),
- .@"node:assert/strict" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:assert/strict", "node/assert.strict.js", specifier),
- .@"node:async_hooks" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:async_hooks", "node/async_hooks.js", specifier),
- .@"node:child_process" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:child_process", "node/child_process.js", specifier),
- .@"node:crypto" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:crypto", "node/crypto.js", specifier),
- .@"node:dns" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:dns", "node/dns.js", specifier),
- .@"node:dns/promises" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:dns/promises", "node/dns.promises.js", specifier),
- .@"node:events" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:child_process", "node/events.js", specifier),
- .@"node:fs" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:fs", "node/fs.js", specifier),
- .@"node:http" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:http", "node/http.js", specifier),
- .@"node:https" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:https", "node/https.js", specifier),
- .@"node:net" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:net", "node/net.js", specifier),
- .@"node:os" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:os", "node/os.js", specifier),
- .@"node:path" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:path", "node/path.js", specifier),
- .@"node:path/posix" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:path/posix", "node/path.posix.js", specifier),
- .@"node:path/win32" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:path/win32", "node/path.win32.js", specifier),
- .@"node:perf_hooks" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:perf_hooks", "node/perf_hooks.js", specifier),
- .@"node:readline" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:readline", "node/readline.js", specifier),
- .@"node:readline/promises" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:readline/promises", "node/readline.promises.js", specifier),
- .@"node:stream" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:stream", "node/stream.js", specifier),
- .@"node:stream/consumers" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:stream/consumers", "node/stream.consumers.js", specifier),
- .@"node:stream/promises" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:stream/promises", "node/stream.promises.js", specifier),
- .@"node:stream/web" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:stream/web", "node/stream.web.js", specifier),
- .@"node:timers" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:timers", "node/timers.js", specifier),
- .@"node:timers/promises" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:timers/promises", "node/timers.promises.js", specifier),
- .@"node:tls" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:tls", "node/tls.js", specifier),
- .@"node:url" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:url", "node/url.js", specifier),
- .@"node:util" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:util", "node/util.js", specifier),
- .@"node:vm" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:vm", "node/vm.js", specifier),
- .@"node:wasi" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:wasi", "node/wasi.js", specifier),
- .@"node:zlib" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:zlib", "node/zlib.js", specifier),
-
- .@"detect-libc" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .depd, if (Environment.isLinux) "thirdparty/detect-libc.linux.js" else "thirdparty/detect-libc.js", specifier),
- .depd => return jsResolvedSource(jsc_vm.load_builtins_from_path, .depd, "thirdparty/depd.js", specifier),
- .undici => return jsResolvedSource(jsc_vm.load_builtins_from_path, .undici, "thirdparty/undici.js", specifier),
- .ws => return jsResolvedSource(jsc_vm.load_builtins_from_path, .ws, "thirdparty/ws.js", specifier),
-
- .@"node:cluster" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:cluster", "node/cluster.js", specifier),
- .@"node:dgram" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:dgram", "node/dgram.js", specifier),
- .@"node:diagnostics_channel" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:diagnostics_channel", "node/diagnostics_channel.js", specifier),
- .@"node:http2" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:http2", "node/http2.js", specifier),
- .@"node:inspector" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:inspector", "node/inspector.js", specifier),
- .@"node:repl" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:repl", "node/repl.js", specifier),
- .@"node:trace_events" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:trace_events", "node/trace_events.js", specifier),
- .@"node:v8" => return jsResolvedSource(jsc_vm.load_builtins_from_path, .@"node:v8", "node/v8.js", specifier),
+ .@"bun:jsc" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"bun:jsc", "bun/jsc.js", specifier),
+ .@"bun:sqlite" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"bun:sqlite", "bun/sqlite.js", specifier),
+
+ .@"node:assert" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:assert", "node/assert.js", specifier),
+ .@"node:assert/strict" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:assert/strict", "node/assert.strict.js", specifier),
+ .@"node:async_hooks" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:async_hooks", "node/async_hooks.js", specifier),
+ .@"node:child_process" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:child_process", "node/child_process.js", specifier),
+ .@"node:crypto" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:crypto", "node/crypto.js", specifier),
+ .@"node:dns" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:dns", "node/dns.js", specifier),
+ .@"node:dns/promises" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:dns/promises", "node/dns.promises.js", specifier),
+ .@"node:events" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:child_process", "node/events.js", specifier),
+ .@"node:fs" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:fs", "node/fs.js", specifier),
+ .@"node:http" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:http", "node/http.js", specifier),
+ .@"node:https" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:https", "node/https.js", specifier),
+ .@"node:net" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:net", "node/net.js", specifier),
+ .@"node:os" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:os", "node/os.js", specifier),
+ .@"node:path" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:path", "node/path.js", specifier),
+ .@"node:path/posix" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:path/posix", "node/path.posix.js", specifier),
+ .@"node:path/win32" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:path/win32", "node/path.win32.js", specifier),
+ .@"node:perf_hooks" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:perf_hooks", "node/perf_hooks.js", specifier),
+ .@"node:readline" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:readline", "node/readline.js", specifier),
+ .@"node:readline/promises" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:readline/promises", "node/readline.promises.js", specifier),
+ .@"node:stream" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:stream", "node/stream.js", specifier),
+ .@"node:stream/consumers" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:stream/consumers", "node/stream.consumers.js", specifier),
+ .@"node:stream/promises" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:stream/promises", "node/stream.promises.js", specifier),
+ .@"node:stream/web" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:stream/web", "node/stream.web.js", specifier),
+ .@"node:timers" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:timers", "node/timers.js", specifier),
+ .@"node:timers/promises" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:timers/promises", "node/timers.promises.js", specifier),
+ .@"node:tls" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:tls", "node/tls.js", specifier),
+ .@"node:url" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:url", "node/url.js", specifier),
+ .@"node:util" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:util", "node/util.js", specifier),
+ .@"node:vm" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:vm", "node/vm.js", specifier),
+ .@"node:wasi" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:wasi", "node/wasi.js", specifier),
+ .@"node:zlib" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:zlib", "node/zlib.js", specifier),
+
+ .@"detect-libc" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .depd, if (Environment.isLinux) "thirdparty/detect-libc.linux.js" else "thirdparty/detect-libc.js", specifier),
+ .depd => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .depd, "thirdparty/depd.js", specifier),
+ .undici => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .undici, "thirdparty/undici.js", specifier),
+ .ws => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .ws, "thirdparty/ws.js", specifier),
+
+ .@"node:cluster" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:cluster", "node/cluster.js", specifier),
+ .@"node:dgram" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:dgram", "node/dgram.js", specifier),
+ .@"node:diagnostics_channel" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:diagnostics_channel", "node/diagnostics_channel.js", specifier),
+ .@"node:http2" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:http2", "node/http2.js", specifier),
+ .@"node:inspector" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:inspector", "node/inspector.js", specifier),
+ .@"node:repl" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:repl", "node/repl.js", specifier),
+ .@"node:trace_events" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:trace_events", "node/trace_events.js", specifier),
+ .@"node:v8" => return jsResolvedSource(jsc_vm, jsc_vm.load_builtins_from_path, .@"node:v8", "node/v8.js", specifier),
}
} else if (specifier.hasPrefixComptime(js_ast.Macro.namespaceWithColon)) {
if (jsc_vm.macro_entry_points.get(MacroEntryPoint.generateIDFromSpecifier(specifier.byteSlice()))) |entry| {
return ResolvedSource{
.allocator = null,
- .source_code = ZigString.init(entry.source.contents),
+ .source_code = bun.String.create(entry.source.contents),
.specifier = specifier,
.source_url = specifier.toZigString(),
.hash = 0,
@@ -1809,7 +1863,7 @@ pub const ModuleLoader = struct {
} else if (DisabledModule.getWithEql(specifier, bun.String.eqlComptime) != null) {
return ResolvedSource{
.allocator = null,
- .source_code = ZigString.init(
+ .source_code = bun.String.static(
\\const symbol = Symbol.for("CommonJS");
\\const lazy = globalThis[Symbol.for("Bun.lazy")];
\\var masqueradesAsUndefined = lazy("masqueradesAsUndefined");
@@ -1827,7 +1881,7 @@ pub const ModuleLoader = struct {
if (graph.files.get(specifier_utf8.slice())) |file| {
return ResolvedSource{
.allocator = null,
- .source_code = ZigString.init(file.contents),
+ .source_code = bun.String.static(file.contents),
.specifier = specifier,
.source_url = specifier.toZigString(),
.hash = 0,
@@ -2199,12 +2253,16 @@ pub const DisabledModule = bun.ComptimeStringMap(
},
);
-inline fn jsResolvedSource(builtins: []const u8, comptime module: HardcodedModule, comptime input: []const u8, specifier: bun.String) ResolvedSource {
- return ResolvedSource{
- .allocator = null,
- .source_code = ZigString.init(jsModuleFromFile(builtins, input)),
- .specifier = specifier,
- .source_url = ZigString.init(@tagName(module)),
- .hash = 0,
- };
+fn jsResolvedSource(vm: *JSC.VirtualMachine, builtins: []const u8, comptime module: HardcodedModule, comptime input: []const u8, specifier: bun.String) ResolvedSource {
+ // We use RefCountedResolvedSource because we want a stable StringImpl*
+ // pointer so that the SourceProviderCache has the maximum hit rate
+ return vm.refCountedResolvedSource(
+ jsModuleFromFile(builtins, input),
+ specifier,
+ @tagName(module),
+ null,
+
+ // we never want to free these
+ true,
+ );
}
diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig
index 23af9cc7c..95a2270a5 100644
--- a/src/bun.js/node/types.zig
+++ b/src/bun.js/node/types.zig
@@ -754,7 +754,7 @@ pub const Valid = struct {
pub const ArgumentsSlice = struct {
remaining: []const JSC.JSValue,
vm: *JSC.VirtualMachine,
- arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator),
+ arena: @import("root").bun.ArenaAllocator = @import("root").bun.ArenaAllocator.init(bun.default_allocator),
all: []const JSC.JSValue,
threw: bool = false,
protected: std.bit_set.IntegerBitSet(32) = std.bit_set.IntegerBitSet(32).initEmpty(),
@@ -794,7 +794,7 @@ pub const ArgumentsSlice = struct {
.remaining = arguments,
.vm = vm,
.all = arguments,
- .arena = std.heap.ArenaAllocator.init(vm.allocator),
+ .arena = @import("root").bun.ArenaAllocator.init(vm.allocator),
};
}
@@ -1733,7 +1733,7 @@ pub const Path = struct {
heap_allocator,
);
var allocator = stack_fallback_allocator.get();
- var arena = std.heap.ArenaAllocator.init(heap_allocator);
+ var arena = @import("root").bun.ArenaAllocator.init(heap_allocator);
var arena_allocator = arena.allocator();
defer arena.deinit();
var buf: [bun.MAX_PATH_BYTES]u8 = undefined;
@@ -1870,7 +1870,7 @@ pub const Path = struct {
var parts = allocator.alloc(string, args_len) catch unreachable;
defer allocator.free(parts);
- var arena = std.heap.ArenaAllocator.init(heap_allocator);
+ var arena = @import("root").bun.ArenaAllocator.init(heap_allocator);
var arena_allocator = arena.allocator();
defer arena.deinit();
diff --git a/src/bun.js/webcore/blob.zig b/src/bun.js/webcore/blob.zig
index 13b086541..9b3ddb8df 100644
--- a/src/bun.js/webcore/blob.zig
+++ b/src/bun.js/webcore/blob.zig
@@ -242,7 +242,7 @@ pub const Blob = struct {
allocator: std.mem.Allocator,
form_data: *JSC.DOMFormData,
) Blob {
- var arena = std.heap.ArenaAllocator.init(allocator);
+ var arena = @import("root").bun.ArenaAllocator.init(allocator);
defer arena.deinit();
var stack_allocator = std.heap.stackFallback(1024, arena.allocator());
var stack_mem_all = stack_allocator.get();
diff --git a/src/bun.zig b/src/bun.zig
index 9ca01f2b8..ab3b3e18c 100644
--- a/src/bun.zig
+++ b/src/bun.zig
@@ -1530,3 +1530,5 @@ pub const WTF = struct {
/// The String type from WebKit's WTF library.
pub const StringImpl = @import("./string.zig").WTFStringImpl;
};
+
+pub const ArenaAllocator = @import("./ArenaAllocator.zig").ArenaAllocator;
diff --git a/src/bundler.zig b/src/bundler.zig
index 9a2ae2355..3c796b576 100644
--- a/src/bundler.zig
+++ b/src/bundler.zig
@@ -192,9 +192,9 @@ pub const PluginRunner = struct {
return null;
}
- var file_path = path_value.getZigString(global);
+ var file_path = path_value.toBunString(global);
- if (file_path.len == 0) {
+ if (file_path.length() == 0) {
log.addError(
null,
loc,
diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig
index c62be6153..a03847079 100644
--- a/src/bundler/bundle_v2.zig
+++ b/src/bundler/bundle_v2.zig
@@ -217,7 +217,7 @@ pub const ThreadPool = struct {
deinit_task: ThreadPoolLib.Task = .{ .callback = deinitCallback },
- temporary_arena: std.heap.ArenaAllocator = undefined,
+ temporary_arena: @import("root").bun.ArenaAllocator = undefined,
stmt_list: LinkerContext.StmtList = undefined,
pub fn deinitCallback(task: *ThreadPoolLib.Task) void {
@@ -301,7 +301,7 @@ pub const ThreadPool = struct {
this.data.bundler.linker.resolver = &this.data.bundler.resolver;
this.data.bundler.macro_context = js_ast.Macro.MacroContext.init(&this.data.bundler);
this.data.macro_context = this.data.bundler.macro_context.?;
- this.temporary_arena = std.heap.ArenaAllocator.init(this.allocator);
+ this.temporary_arena = @import("root").bun.ArenaAllocator.init(this.allocator);
this.stmt_list = LinkerContext.StmtList.init(this.allocator);
const CacheSet = @import("../cache.zig");
@@ -3793,7 +3793,7 @@ const LinkerContext = struct {
var stack_fallback = std.heap.stackFallback(4096, this.allocator);
var stack_all = stack_fallback.get();
- var arena = std.heap.ArenaAllocator.init(stack_all);
+ var arena = @import("root").bun.ArenaAllocator.init(stack_all);
defer arena.deinit();
var temp_allocator = arena.allocator();
@@ -6407,7 +6407,7 @@ const LinkerContext = struct {
defer chunk.renamer.deinit(bun.default_allocator);
- var arena = std.heap.ArenaAllocator.init(worker.allocator);
+ var arena = @import("root").bun.ArenaAllocator.init(worker.allocator);
defer arena.deinit();
// Also generate the cross-chunk binding code
diff --git a/src/deps/c_ares.zig b/src/deps/c_ares.zig
index 06c9dfbf1..4539358d0 100644
--- a/src/deps/c_ares.zig
+++ b/src/deps/c_ares.zig
@@ -309,7 +309,7 @@ pub const AddrInfo = extern struct {
globalThis: *JSC.JSGlobalObject,
) JSC.JSValue {
var stack = std.heap.stackFallback(2048, parent_allocator);
- var arena = std.heap.ArenaAllocator.init(stack.get());
+ var arena = @import("root").bun.ArenaAllocator.init(stack.get());
var node = addr_info.node.?;
const array = JSC.JSValue.createEmptyArray(
globalThis,
@@ -627,7 +627,7 @@ pub const struct_ares_caa_reply = extern struct {
pub fn toJSReponse(this: *struct_ares_caa_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
var stack = std.heap.stackFallback(2048, parent_allocator);
- var arena = std.heap.ArenaAllocator.init(stack.get());
+ var arena = @import("root").bun.ArenaAllocator.init(stack.get());
defer arena.deinit();
var allocator = arena.allocator();
@@ -706,7 +706,7 @@ pub const struct_ares_srv_reply = extern struct {
pub fn toJSReponse(this: *struct_ares_srv_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
var stack = std.heap.stackFallback(2048, parent_allocator);
- var arena = std.heap.ArenaAllocator.init(stack.get());
+ var arena = @import("root").bun.ArenaAllocator.init(stack.get());
defer arena.deinit();
var allocator = arena.allocator();
@@ -791,7 +791,7 @@ pub const struct_ares_mx_reply = extern struct {
pub fn toJSReponse(this: *struct_ares_mx_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
var stack = std.heap.stackFallback(2048, parent_allocator);
- var arena = std.heap.ArenaAllocator.init(stack.get());
+ var arena = @import("root").bun.ArenaAllocator.init(stack.get());
defer arena.deinit();
var allocator = arena.allocator();
@@ -867,7 +867,7 @@ pub const struct_ares_txt_reply = extern struct {
pub fn toJSReponse(this: *struct_ares_txt_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
var stack = std.heap.stackFallback(2048, parent_allocator);
- var arena = std.heap.ArenaAllocator.init(stack.get());
+ var arena = @import("root").bun.ArenaAllocator.init(stack.get());
defer arena.deinit();
var allocator = arena.allocator();
@@ -949,7 +949,7 @@ pub const struct_ares_naptr_reply = extern struct {
pub fn toJSReponse(this: *struct_ares_naptr_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
var stack = std.heap.stackFallback(2048, parent_allocator);
- var arena = std.heap.ArenaAllocator.init(stack.get());
+ var arena = @import("root").bun.ArenaAllocator.init(stack.get());
defer arena.deinit();
var allocator = arena.allocator();
@@ -1043,7 +1043,7 @@ pub const struct_ares_soa_reply = extern struct {
pub fn toJSReponse(this: *struct_ares_soa_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
var stack = std.heap.stackFallback(2048, parent_allocator);
- var arena = std.heap.ArenaAllocator.init(stack.get());
+ var arena = @import("root").bun.ArenaAllocator.init(stack.get());
defer arena.deinit();
var allocator = arena.allocator();
diff --git a/src/deps/diffz/DiffMatchPatch.zig b/src/deps/diffz/DiffMatchPatch.zig
index f46d88cd5..7e545f364 100644
--- a/src/deps/diffz/DiffMatchPatch.zig
+++ b/src/deps/diffz/DiffMatchPatch.zig
@@ -1398,7 +1398,7 @@ fn diffCommonOverlap(text1_in: []const u8, text2_in: []const u8) usize {
}
// pub fn main() void {
-// var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+// var arena = @import("root").bun.ArenaAllocator.init(std.heap.page_allocator);
// defer arena.deinit();
// var bruh = default.diff(arena.allocator(), "Hello World.", "Goodbye World.", true);
@@ -1406,7 +1406,7 @@ fn diffCommonOverlap(text1_in: []const u8, text2_in: []const u8) usize {
// }
// test {
-// var arena = std.heap.ArenaAllocator.init(testing.allocator);
+// var arena = @import("root").bun.ArenaAllocator.init(testing.allocator);
// defer arena.deinit();
// var bruh = try default.diff(arena.allocator(), "Hello World.", "Goodbye World.", true);
@@ -1455,7 +1455,7 @@ test diffCommonOverlap {
}
test diffHalfMatch {
- var arena = std.heap.ArenaAllocator.init(testing.allocator);
+ var arena = @import("root").bun.ArenaAllocator.init(testing.allocator);
defer arena.deinit();
var one_timeout = DiffMatchPatch{};
@@ -1549,7 +1549,7 @@ test diffHalfMatch {
}
test diffLinesToChars {
- var arena = std.heap.ArenaAllocator.init(testing.allocator);
+ var arena = @import("root").bun.ArenaAllocator.init(testing.allocator);
defer arena.deinit();
// Convert lines down to characters.
@@ -1611,7 +1611,7 @@ test diffLinesToChars {
}
test diffCharsToLines {
- var arena = std.heap.ArenaAllocator.init(testing.allocator);
+ var arena = @import("root").bun.ArenaAllocator.init(testing.allocator);
defer arena.deinit();
try testing.expect((Diff.init(.equal, "a")).eql(Diff.init(.equal, "a")));
@@ -1640,7 +1640,7 @@ test diffCharsToLines {
}
test diffCleanupMerge {
- var arena = std.heap.ArenaAllocator.init(testing.allocator);
+ var arena = @import("root").bun.ArenaAllocator.init(testing.allocator);
defer arena.deinit();
// Cleanup a messy diff.
@@ -1828,7 +1828,7 @@ test diffCleanupMerge {
}
test diffCleanupSemanticLossless {
- var arena = std.heap.ArenaAllocator.init(testing.allocator);
+ var arena = @import("root").bun.ArenaAllocator.init(testing.allocator);
defer arena.deinit();
var diffs = DiffList{};
@@ -1953,7 +1953,7 @@ fn rebuildtexts(allocator: std.mem.Allocator, diffs: DiffList) ![2][]const u8 {
}
test diffBisect {
- var arena = std.heap.ArenaAllocator.init(talloc);
+ var arena = @import("root").bun.ArenaAllocator.init(talloc);
defer arena.deinit();
// Normal.
@@ -1987,7 +1987,7 @@ test diffBisect {
const talloc = testing.allocator;
test diff {
- var arena = std.heap.ArenaAllocator.init(talloc);
+ var arena = @import("root").bun.ArenaAllocator.init(talloc);
defer arena.deinit();
// Perform a trivial diff.
@@ -2094,7 +2094,7 @@ test diff {
}
test diffCleanupSemantic {
- var arena = std.heap.ArenaAllocator.init(talloc);
+ var arena = @import("root").bun.ArenaAllocator.init(talloc);
defer arena.deinit();
// Cleanup semantically trivial equalities.
diff --git a/src/deps/zig-clap/clap.zig b/src/deps/zig-clap/clap.zig
index a21a1cb1a..16824e788 100644
--- a/src/deps/zig-clap/clap.zig
+++ b/src/deps/zig-clap/clap.zig
@@ -241,7 +241,7 @@ fn testDiag(diag: Diagnostic, err: anyerror, expected: []const u8) void {
pub fn Args(comptime Id: type, comptime params: []const Param(Id)) type {
return struct {
- arena: std.heap.ArenaAllocator,
+ arena: @import("root").bun.ArenaAllocator,
clap: ComptimeClap(Id, params),
exe_arg: ?[]const u8,
diff --git a/src/deps/zig-clap/clap/args.zig b/src/deps/zig-clap/clap/args.zig
index a1fa3773a..d315582bb 100644
--- a/src/deps/zig-clap/clap/args.zig
+++ b/src/deps/zig-clap/clap/args.zig
@@ -48,7 +48,7 @@ test "SliceIterator" {
pub const OsIterator = struct {
const Error = process.ArgIterator.InitError;
- arena: heap.ArenaAllocator,
+ arena: @import("root").bun.ArenaAllocator,
args: process.ArgIterator,
/// The executable path (this is the first argument passed to the program)
@@ -58,7 +58,7 @@ pub const OsIterator = struct {
pub fn init(allocator: mem.Allocator) OsIterator {
var res = OsIterator{
- .arena = heap.ArenaAllocator.init(allocator),
+ .arena = @import("root").bun.ArenaAllocator.init(allocator),
.args = process.args(),
.exe_arg = undefined,
};
@@ -83,12 +83,12 @@ pub const ShellIterator = struct {
QuoteNotClosed,
} || mem.Allocator.Error;
- arena: heap.ArenaAllocator,
+ arena: @import("root").bun.ArenaAllocator,
str: []const u8,
pub fn init(allocator: mem.Allocator, str: []const u8) ShellIterator {
return .{
- .arena = heap.ArenaAllocator.init(allocator),
+ .arena = @import("root").bun.ArenaAllocator.init(allocator),
.str = str,
};
}
diff --git a/src/http.zig b/src/http.zig
index f26a0e985..d2924b804 100644
--- a/src/http.zig
+++ b/src/http.zig
@@ -34,7 +34,7 @@ const DotEnv = @import("./env_loader.zig");
const mimalloc = @import("./allocators/mimalloc.zig");
const MacroMap = @import("./resolver/package_json.zig").MacroMap;
const Analytics = @import("./analytics/analytics_thread.zig");
-const Arena = std.heap.ArenaAllocator;
+const Arena = @import("root").bun.ArenaAllocator;
const ThreadlocalArena = @import("./mimalloc_arena.zig").Arena;
const JSON = bun.JSON;
const DateTime = bun.DateTime;
diff --git a/src/install/install.zig b/src/install/install.zig
index cfbb0cb7f..f4695cc34 100644
--- a/src/install/install.zig
+++ b/src/install/install.zig
@@ -2293,7 +2293,7 @@ pub const PackageManager = struct {
return null;
}
- var arena = std.heap.ArenaAllocator.init(this.allocator);
+ var arena = @import("root").bun.ArenaAllocator.init(this.allocator);
defer arena.deinit();
var arena_alloc = arena.allocator();
var stack_fallback = std.heap.stackFallback(4096, arena_alloc);
diff --git a/src/install/npm.zig b/src/install/npm.zig
index 283d20b39..c01e6ee1f 100644
--- a/src/install/npm.zig
+++ b/src/install/npm.zig
@@ -781,7 +781,7 @@ pub const PackageManifest = struct {
const source = logger.Source.initPathString(expected_name, json_buffer);
initializeStore();
defer bun.JSAst.Stmt.Data.Store.memory_allocator.?.pop();
- var arena = std.heap.ArenaAllocator.init(allocator);
+ var arena = @import("root").bun.ArenaAllocator.init(allocator);
defer arena.deinit();
const json = json_parser.ParseJSONUTF8(
&source,
diff --git a/src/main.zig b/src/main.zig
index 0c7cf9584..f4df0814e 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -24,7 +24,7 @@ pub fn main() void {
// The memory allocator makes a massive difference.
// std.heap.raw_c_allocator and default_allocator perform similarly.
// std.heap.GeneralPurposeAllocator makes this about 3x _slower_ than esbuild.
- // var root_alloc = std.heap.ArenaAllocator.init(std.heap.raw_c_allocator);
+ // var root_alloc = @import("root").bun.ArenaAllocator.init(std.heap.raw_c_allocator);
// var root_alloc_ = &root_alloc.allocator;
var stdout = std.io.getStdOut();
diff --git a/src/main_wasm.zig b/src/main_wasm.zig
index b1cb14dc5..8958d7cd4 100644
--- a/src/main_wasm.zig
+++ b/src/main_wasm.zig
@@ -202,7 +202,7 @@ const Arena = @import("./mimalloc_arena.zig").Arena;
var log: Logger.Log = undefined;
export fn transform(opts_array: u64) u64 {
- // var arena = std.heap.ArenaAllocator.init(default_allocator);
+ // var arena = @import("root").bun.ArenaAllocator.init(default_allocator);
var arena = Arena.init() catch unreachable;
var allocator = arena.allocator();
defer arena.deinit();
@@ -274,7 +274,7 @@ export fn transform(opts_array: u64) u64 {
}
export fn scan(opts_array: u64) u64 {
- // var arena = std.heap.ArenaAllocator.init(default_allocator);
+ // var arena = @import("root").bun.ArenaAllocator.init(default_allocator);
var arena = Arena.init() catch unreachable;
var allocator = arena.allocator();
defer arena.deinit();
diff --git a/src/renamer.zig b/src/renamer.zig
index 3b32511f6..0177725c6 100644
--- a/src/renamer.zig
+++ b/src/renamer.zig
@@ -470,7 +470,7 @@ pub const NumberRenamer = struct {
allocator: std.mem.Allocator,
temp_allocator: std.mem.Allocator,
number_scope_pool: bun.HiveArray(NumberScope, 128).Fallback,
- arena: std.heap.ArenaAllocator,
+ arena: @import("root").bun.ArenaAllocator,
root: NumberScope = .{},
name_stack_fallback: std.heap.StackFallbackAllocator(512) = undefined,
name_temp_allocator: std.mem.Allocator = undefined,
@@ -538,7 +538,7 @@ pub const NumberRenamer = struct {
.temp_allocator = temp_allocator,
.names = try allocator.alloc(bun.BabyList(string), symbols.symbols_for_source.len),
.number_scope_pool = undefined,
- .arena = std.heap.ArenaAllocator.init(temp_allocator),
+ .arena = @import("root").bun.ArenaAllocator.init(temp_allocator),
};
renamer.name_stack_fallback = .{
.buffer = undefined,
diff --git a/src/string.zig b/src/string.zig
index cfa50f792..62cdc5462 100644
--- a/src/string.zig
+++ b/src/string.zig
@@ -239,6 +239,17 @@ pub const String = extern struct {
pub const dead = String{ .tag = .Dead, .value = .{ .Dead = {} } };
pub const StringImplAllocator = Parent.StringImplAllocator;
+ extern fn BunString__fromLatin1(bytes: [*]const u8, len: usize) String;
+ extern fn BunString__fromBytes(bytes: [*]const u8, len: usize) String;
+
+ pub fn createLatin1(bytes: []const u8) String {
+ return BunString__fromLatin1(bytes.ptr, bytes.len);
+ }
+
+ pub fn create(bytes: []const u8) String {
+ return BunString__fromBytes(bytes.ptr, bytes.len);
+ }
+
pub fn initWithType(comptime Type: type, value: Type) String {
switch (comptime Type) {
ZigString => return String{ .tag = .ZigString, .value = .{ .ZigString = value } },
@@ -273,6 +284,18 @@ pub const String = extern struct {
return initWithType(@TypeOf(value), value);
}
+ extern fn BunString__createExternal(
+ bytes: [*]const u8,
+ len: usize,
+ isLatin1: bool,
+ ptr: ?*anyopaque,
+ callback: ?*const fn (*anyopaque, *anyopaque, u32) callconv(.C) void,
+ ) String;
+
+ pub fn createExternal(bytes: []const u8, isLatin1: bool, ctx: ?*anyopaque, callback: ?*const fn (*anyopaque, *anyopaque, u32) callconv(.C) void) String {
+ return BunString__createExternal(bytes.ptr, bytes.len, isLatin1, ctx, callback);
+ }
+
pub fn fromUTF8(value: []const u8) String {
return String.initWithType(ZigString, ZigString.initUTF8(value));
}
@@ -339,7 +362,7 @@ pub const String = extern struct {
if (self.tag == .Empty)
return &[_]u16{};
std.debug.assert(self.tag == .WTFStringImpl);
- return self.value.WTFStringImpl.utf16();
+ return self.value.WTFStringImpl.utf16Slice();
}
pub inline fn latin1(self: String) []const u8 {
@@ -347,7 +370,7 @@ pub const String = extern struct {
return &[_]u8{};
std.debug.assert(self.tag == .WTFStringImpl);
- return self.value.WTFStringImpl.latin1();
+ return self.value.WTFStringImpl.latin1Slice();
}
pub fn isUTF8(self: String) bool {
diff --git a/src/zlib.zig b/src/zlib.zig
index 4a3901a14..b85ddf431 100644
--- a/src/zlib.zig
+++ b/src/zlib.zig
@@ -238,7 +238,7 @@ pub fn NewZlibReader(comptime Writer: type, comptime buffer_size: usize) type {
buf: [buffer_size]u8,
zlib: zStream_struct,
allocator: std.mem.Allocator,
- arena: std.heap.ArenaAllocator,
+ arena: @import("root").bun.ArenaAllocator,
state: State = State.Uninitialized,
pub fn alloc(ctx: *anyopaque, items: uInt, len: uInt) callconv(.C) *anyopaque {
@@ -272,7 +272,7 @@ pub fn NewZlibReader(comptime Writer: type, comptime buffer_size: usize) type {
.buf = std.mem.zeroes([buffer_size]u8),
.allocator = allocator,
.zlib = undefined,
- .arena = std.heap.ArenaAllocator.init(allocator),
+ .arena = @import("root").bun.ArenaAllocator.init(allocator),
};
zlib_reader.zlib = zStream_struct{
@@ -422,7 +422,7 @@ pub const ZlibReaderArrayList = struct {
list_ptr: *std.ArrayListUnmanaged(u8),
zlib: zStream_struct,
allocator: std.mem.Allocator,
- arena: std.heap.ArenaAllocator,
+ arena: @import("root").bun.ArenaAllocator,
state: State = State.Uninitialized,
pub fn alloc(ctx: *anyopaque, items: uInt, len: uInt) callconv(.C) *anyopaque {
@@ -473,7 +473,7 @@ pub const ZlibReaderArrayList = struct {
.list_ptr = list,
.allocator = allocator,
.zlib = undefined,
- .arena = std.heap.ArenaAllocator.init(allocator),
+ .arena = @import("root").bun.ArenaAllocator.init(allocator),
};
zlib_reader.zlib = zStream_struct{
@@ -829,7 +829,7 @@ pub const ZlibCompressorArrayList = struct {
list_ptr: *std.ArrayListUnmanaged(u8),
zlib: zStream_struct,
allocator: std.mem.Allocator,
- arena: std.heap.ArenaAllocator,
+ arena: @import("root").bun.ArenaAllocator,
state: State = State.Uninitialized,
pub fn alloc(ctx: *anyopaque, items: uInt, len: uInt) callconv(.C) *anyopaque {
@@ -868,7 +868,7 @@ pub const ZlibCompressorArrayList = struct {
.list_allocator = list_allocator,
.allocator = allocator,
.zlib = undefined,
- .arena = std.heap.ArenaAllocator.init(allocator),
+ .arena = @import("root").bun.ArenaAllocator.init(allocator),
};
zlib_reader.zlib = zStream_struct{