Compare commits

...

1 Commits

Author SHA1 Message Date
Jarred Sumner
75df821715 Free cloned body values sooner 2024-09-05 00:53:13 -07:00
4 changed files with 76 additions and 38 deletions

View File

@@ -5050,7 +5050,9 @@ pub const AnyBlob = union(enum) {
return JSC.ArrayBuffer.create(global, "", TypedArrayView);
}
bun.assertMimalloc(&this.InternalBlob.bytes.allocator, @src());
const bytes = this.InternalBlob.toOwnedSlice();
this.* = .{ .Blob = .{} };
return JSC.ArrayBuffer.fromDefaultAllocator(

View File

@@ -373,11 +373,27 @@ pub const Body = struct {
if (this.* != .Locked)
return;
if (this.Locked.toAnyBlob()) |blob| {
this.* = switch (blob) {
.Blob => .{ .Blob = blob.Blob },
.InternalBlob => .{ .InternalBlob = blob.InternalBlob },
.WTFStringImpl => .{ .WTFStringImpl = blob.WTFStringImpl },
if (this.Locked.toAnyBlob()) |any_blob_value| {
var any_blob = any_blob_value;
this.* = switch (any_blob) {
.Blob => |*blob| brk: {
// We want to free the Response body as soon as possible.
// If there's only one reference to it, let's make it an InternalBlob instead.
if (blob.store) |store| {
if (store.toAnyBlob()) |as_any| {
blob.detach();
break :brk switch (as_any) {
.Blob => |blob_| .{ .Blob = blob_ },
.InternalBlob => |internal_blob| .{ .InternalBlob = internal_blob },
.WTFStringImpl => |wtf_string_impl| .{ .WTFStringImpl = wtf_string_impl },
};
}
}
break :brk .{ .Blob = blob.* };
},
.InternalBlob => |internal_blob| .{ .InternalBlob = internal_blob },
.WTFStringImpl => |wtf_string_impl| .{ .WTFStringImpl = wtf_string_impl },
// .InlineBlob => .{ .InlineBlob = blob.InlineBlob },
};
}
@@ -414,28 +430,6 @@ pub const Body = struct {
};
}
pub fn createBlobValue(data: []u8, allocator: std.mem.Allocator, was_string: bool) Value {
// if (data.len <= InlineBlob.available_bytes) {
// var _blob = InlineBlob{
// .bytes = undefined,
// .was_string = was_string,
// .len = @truncate(InlineBlob.IntSize, data.len),
// };
// @memcpy(&_blob.bytes, data.ptr, data.len);
// allocator.free(data);
// return Value{
// .InlineBlob = _blob,
// };
// }
return Value{
.InternalBlob = InternalBlob{
.bytes = std.ArrayList(u8).fromOwnedSlice(allocator, data),
.was_string = was_string,
},
};
}
pub const Tag = enum {
Blob,
WTFStringImpl,
@@ -844,7 +838,19 @@ pub const Body = struct {
}
const any_blob: AnyBlob = switch (this.*) {
.Blob => AnyBlob{ .Blob = this.Blob },
.Blob => |*blob| brk: {
// We want to free the Response body as soon as possible.
// If there's only one reference to it, let's make it an InternalBlob instead.
if (blob.store) |store| {
if (store.toAnyBlob()) |any_blob| {
blob.detach();
this.* = .{ .Used = {} };
return any_blob;
}
}
break :brk .{ .Blob = blob.* };
},
.InternalBlob => AnyBlob{ .InternalBlob = this.InternalBlob },
// .InlineBlob => AnyBlob{ .InlineBlob = this.InlineBlob },
.Locked => this.Locked.toAnyBlobAllowPromise() orelse return null,
@@ -857,7 +863,19 @@ pub const Body = struct {
pub fn useAsAnyBlob(this: *Value) AnyBlob {
const any_blob: AnyBlob = switch (this.*) {
.Blob => .{ .Blob = this.Blob },
.Blob => |*blob| brk: {
// We want to free the Response body as soon as possible.
// If there's only one reference to it, let's make it an InternalBlob instead.
if (blob.store) |store| {
if (store.toAnyBlob()) |any_blob| {
blob.detach();
this.* = .{ .Used = {} };
return any_blob;
}
}
break :brk .{ .Blob = blob.* };
},
.InternalBlob => .{ .InternalBlob = this.InternalBlob },
.WTFStringImpl => |str| brk: {
if (str.toUTF8IfNeeded(bun.default_allocator)) |utf8| {
@@ -888,7 +906,19 @@ pub const Body = struct {
pub fn useAsAnyBlobAllowNonUTF8String(this: *Value) AnyBlob {
const any_blob: AnyBlob = switch (this.*) {
.Blob => .{ .Blob = this.Blob },
.Blob => |*blob| brk: {
// We want to free the Response body as soon as possible.
// If there's only one reference to it, let's make it an InternalBlob instead.
if (blob.store) |store| {
if (store.toAnyBlob()) |any_blob| {
blob.detach();
this.* = .{ .Used = {} };
return any_blob;
}
}
break :brk .{ .Blob = blob.* };
},
.InternalBlob => .{ .InternalBlob = this.InternalBlob },
.WTFStringImpl => .{ .WTFStringImpl = this.WTFStringImpl },
// .InlineBlob => .{ .InlineBlob = this.InlineBlob },

View File

@@ -3725,3 +3725,9 @@ pub fn WeakPtr(comptime T: type, comptime weakable_field: std.meta.FieldEnum(T))
}
};
}
pub inline fn assertMimalloc(allocator: *const std.mem.Allocator, loc: std.builtin.SourceLocation) void {
if (allocator.vtable != default_allocator.vtable and allocator.vtable != MimallocArena.v_table) {
Output.panic("Internal error: expected default allocator in use at {s}:{s}:{d}", .{ loc.file, loc.fn_name, loc.line });
}
}

View File

@@ -136,9 +136,15 @@ pub const Arena = struct {
/// It uses pthread_getspecific to do that.
/// We can save those extra calls if we just do it once in here
pub fn getThreadlocalDefault() Allocator {
return Allocator{ .ptr = mimalloc.mi_heap_get_default(), .vtable = &c_allocator_vtable };
return Allocator{ .ptr = mimalloc.mi_heap_get_default(), .vtable = v_table };
}
pub const v_table = &Allocator.VTable{
.alloc = &Arena.alloc,
.resize = &Arena.resize,
.free = &Arena.free,
};
pub fn backingAllocator(this: Arena) Allocator {
var arena = Arena{ .heap = this.heap.?.backing() };
return arena.allocator();
@@ -146,7 +152,7 @@ pub const Arena = struct {
pub fn allocator(this: Arena) Allocator {
@setRuntimeSafety(false);
return Allocator{ .ptr = this.heap.?, .vtable = &c_allocator_vtable };
return Allocator{ .ptr = this.heap.?, .vtable = v_table };
}
pub fn deinit(this: *Arena) void {
@@ -277,9 +283,3 @@ pub const Arena = struct {
}
}
};
const c_allocator_vtable = Allocator.VTable{
.alloc = &Arena.alloc,
.resize = &Arena.resize,
.free = &Arena.free,
};