Compare commits

...

1 Commits

Author SHA1 Message Date
Jarred Sumner
8c13f5249f Use typed allocator in Sink 2024-07-28 21:28:23 -07:00
4 changed files with 176 additions and 18 deletions

View File

@@ -472,6 +472,25 @@ pub const ArrayBuffer = extern struct {
const log = Output.scoped(.ArrayBuffer, false);
pub export fn Bun__ArrayBuffer__deallocate(bytes: ?[*]u8, byte_length: usize, allocatorPtr: ?*anyopaque, fntable: *const std.mem.Allocator.VTable) void {
const allocator = std.mem.Allocator{
// We use an "undefined" pointer for default_allocator
// So this value can genuinely be anything.
.ptr = allocatorPtr orelse undefined,
.vtable = fntable,
};
if (bytes) |ptr| {
allocator.free(ptr[0..byte_length]);
}
}
extern fn Bun__JSTypedArray__fromAllocator(*JSC.JSGlobalObject, bytes: [*]u8, offset: usize, len: usize, typed_array_type: JSC.JSValue.JSType, allocator_ptr: ?*const anyopaque, fntable: ?*const std.mem.Allocator.VTable) JSC.JSValue;
pub fn toJSWithAllocator(this: ArrayBuffer, allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject) JSC.JSValue {
return Bun__JSTypedArray__fromAllocator(globalThis, this.ptr, this.offset, this.byte_len, this.typed_array_type, allocator.ptr, allocator.vtable);
}
pub fn toJS(this: ArrayBuffer, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.JSValue {
if (!this.value.isEmpty()) {
return this.value;
@@ -479,7 +498,7 @@ pub const ArrayBuffer = extern struct {
// If it's not a mimalloc heap buffer, we're not going to call a deallocator
if (this.len > 0 and !bun.Mimalloc.mi_is_in_heap_region(this.ptr)) {
log("toJS but will never free: {d} bytes", .{this.len});
Output.debugWarn("toJS but will never free: {d} bytes", .{this.len});
if (this.typed_array_type == .ArrayBuffer) {
return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArrayBufferWithBytesNoCopy(

View File

@@ -1,5 +1,8 @@
#include "root.h"
#include "JavaScriptCore/JSCast.h"
#include "JavaScriptCore/TypedArrayType.h"
#include "JavaScriptCore/JSString.h"
#include "JavaScriptCore/Error.h"
#include "JavaScriptCore/JSArrayBufferView.h"
@@ -221,9 +224,121 @@ public:
}
static JSC::JSValue createTypedArrayForType(
JSC::JSGlobalObject* lexicalGlobalObject,
JSC::JSType typedArrayType,
Ref<JSC::ArrayBuffer>&& buffer,
size_t byteOffset,
size_t length)
{
if (typedArrayType == JSC::JSType::ArrayBufferType) {
ASSERT(byteOffset == 0);
return JSC::JSArrayBuffer::create(lexicalGlobalObject->vm(), lexicalGlobalObject->arrayBufferStructureWithSharingMode<ArrayBufferSharingMode::Default>(), WTFMove(buffer));
}
switch (JSC::typedArrayType(typedArrayType)) {
case JSC::TypedArrayType::TypeInt8:
return JSC::JSInt8Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), WTFMove(buffer), byteOffset, length);
break;
case JSC::TypedArrayType::TypeUint8:
return JSC::JSUint8Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), WTFMove(buffer), byteOffset, length);
break;
case JSC::TypedArrayType::TypeUint8Clamped:
return JSC::JSUint8ClampedArray::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), WTFMove(buffer), byteOffset, length);
break;
case JSC::TypedArrayType::TypeInt16:
return JSC::JSInt16Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), WTFMove(buffer), byteOffset, length);
break;
case JSC::TypedArrayType::TypeUint16:
return JSC::JSUint16Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), WTFMove(buffer), byteOffset, length);
break;
case JSC::TypedArrayType::TypeInt32:
return JSC::JSInt32Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), WTFMove(buffer), byteOffset, length);
break;
case JSC::TypedArrayType::TypeUint32:
return JSC::JSUint32Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), WTFMove(buffer), byteOffset, length);
break;
case JSC::TypedArrayType::TypeFloat32:
return JSC::JSFloat32Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), WTFMove(buffer), byteOffset, length);
break;
case JSC::TypedArrayType::TypeFloat64:
return JSC::JSFloat64Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), WTFMove(buffer), byteOffset, length);
break;
case JSC::TypedArrayType::TypeBigInt64:
return JSC::JSBigInt64Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), WTFMove(buffer), byteOffset, length);
break;
case JSC::TypedArrayType::TypeBigUint64:
return JSC::JSBigUint64Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), WTFMove(buffer), byteOffset, length);
break;
default: {
RELEASE_ASSERT_NOT_REACHED();
}
}
}
static JSC::JSValue createEmptyTypedArrayForType(
JSC::JSGlobalObject* lexicalGlobalObject,
JSC::JSType typedArrayType)
{
if (typedArrayType == JSC::JSType::ArrayBufferType) {
return JSC::JSArrayBuffer::create(lexicalGlobalObject->vm(), lexicalGlobalObject->arrayBufferStructureWithSharingMode<ArrayBufferSharingMode::Default>(), nullptr);
}
switch (JSC::typedArrayType(typedArrayType)) {
case JSC::TypedArrayType::TypeInt8:
return JSC::JSInt8Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), 0);
break;
case JSC::TypedArrayType::TypeUint8:
return JSC::JSUint8Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), 0);
break;
case JSC::TypedArrayType::TypeUint8Clamped:
return JSC::JSUint8ClampedArray::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), 0);
break;
case JSC::TypedArrayType::TypeInt16:
return JSC::JSInt16Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), 0);
break;
case JSC::TypedArrayType::TypeUint16:
return JSC::JSUint16Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), 0);
break;
case JSC::TypedArrayType::TypeInt32:
return JSC::JSInt32Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), 0);
break;
case JSC::TypedArrayType::TypeUint32:
return JSC::JSUint32Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), 0);
break;
case JSC::TypedArrayType::TypeFloat32:
return JSC::JSFloat32Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), 0);
break;
case JSC::TypedArrayType::TypeFloat64:
return JSC::JSFloat64Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), 0);
break;
case JSC::TypedArrayType::TypeBigInt64:
return JSC::JSBigInt64Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), 0);
break;
case JSC::TypedArrayType::TypeBigUint64:
return JSC::JSBigUint64Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::typedArrayType(typedArrayType), false), 0);
break;
default: {
RELEASE_ASSERT_NOT_REACHED();
}
}
}
extern "C" void Bun__ArrayBuffer__deallocate(void* bytes, size_t length, void* allocatorPtr, void* fnTable);
extern "C" JSC::EncodedJSValue Bun__JSTypedArray__fromAllocator(JSC::JSGlobalObject* lexicalGlobalObject, char* ptr, size_t byteOffset, size_t length, JSC::JSType typedArrayType, void* ctx, void* fnTable)
{
if (LIKELY(length > 0)) {
auto buffer = ArrayBuffer::createFromBytes({ reinterpret_cast<const uint8_t*>(ptr), length }, createSharedTask<void(void*)>([ctx, fnTable, length](void* p) {
Bun__ArrayBuffer__deallocate(p, length, ctx, fnTable);
}));
return JSC::JSValue::encode(createTypedArrayForType(lexicalGlobalObject, typedArrayType, WTFMove(buffer), byteOffset, length));
} else {
return JSC::JSValue::encode(createEmptyTypedArrayForType(lexicalGlobalObject, typedArrayType));
}
}
JSC::EncodedJSValue JSBuffer__bufferFromPointerAndLengthAndDeinit(JSC::JSGlobalObject* lexicalGlobalObject, char* ptr, size_t length, void* ctx, JSTypedArrayBytesDeallocator bytesDeallocator)
{
JSC::JSUint8Array* uint8Array = nullptr;
auto* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);

View File

@@ -238,7 +238,7 @@ JSC_DEFINE_HOST_FUNCTION(functionMemoryUsageStatistics,
#if OS(DARWIN)
{
vm_address_t *zones;
unsigned count;
unsigned count = 0;
// Zero out the structures in case a zone is missing
malloc_statistics_t zone_stats;

View File

@@ -1458,34 +1458,57 @@ pub const ArrayBufferSink = struct {
return value;
}
return this.toJSBytes(globalThis, as_uint8array);
}
fn toJSBytes(this: *ArrayBufferSink, globalThis: *JSGlobalObject, as_uint8array: bool) JSValue {
var list = this.bytes.listManaged(this.allocator);
this.bytes = bun.ByteList.init("");
return ArrayBuffer.fromBytes(
try list.toOwnedSlice(),
const should_shrink_to_fit = brk: {
if (list.capacity == list.items.len) {
break :brk false;
}
if (VirtualMachine.get().smol) {
break :brk true;
}
if (list.capacity - list.items.len > 1024) {
break :brk true;
}
break :brk false;
};
if (should_shrink_to_fit) {
const value: JSValue = switch (as_uint8array) {
true => JSC.ArrayBuffer.create(globalThis, list.items, .Uint8Array),
false => JSC.ArrayBuffer.create(globalThis, list.items, .ArrayBuffer),
};
list.deinit();
return value;
}
return JSC.ArrayBuffer.fromBytes(
list.items,
if (as_uint8array)
.Uint8Array
else
.ArrayBuffer,
).toJS(globalThis, null);
).toJSWithAllocator(this.allocator, globalThis);
}
pub fn endFromJS(this: *ArrayBufferSink, _: *JSGlobalObject) JSC.Maybe(ArrayBuffer) {
pub fn endFromJS(this: *ArrayBufferSink, globalThis: *JSGlobalObject) JSC.Maybe(JSValue) {
if (this.done) {
return .{ .result = ArrayBuffer.fromBytes(&[_]u8{}, .ArrayBuffer) };
return .{ .result = JSC.ArrayBuffer.empty.toJS(globalThis, null) };
}
bun.assert(this.next == null);
var list = this.bytes.listManaged(this.allocator);
this.bytes = bun.ByteList.init("");
this.done = true;
const bytes = this.toJSBytes(globalThis, this.as_uint8array);
this.signal.close(null);
return .{ .result = ArrayBuffer.fromBytes(
list.toOwnedSlice() catch @panic("TODO"),
if (this.as_uint8array)
.Uint8Array
else
.ArrayBuffer,
) };
return .{ .result = bytes };
}
pub fn sink(this: *ArrayBufferSink) Sink {
@@ -1563,6 +1586,7 @@ pub fn NewJSSink(comptime SinkType: type, comptime name_: []const u8) type {
pub const shim = JSC.Shimmer("", name_, @This());
pub const name = std.fmt.comptimePrint("{s}", .{name_});
pub const heap_label = name;
// This attaches it to JS
pub const SinkSignal = extern struct {
@@ -1636,7 +1660,7 @@ pub fn NewJSSink(comptime SinkType: type, comptime name_: []const u8) type {
return .undefined;
}
var allocator = globalThis.bunVM().allocator;
const allocator = bun.typedAllocator(ThisSink);
var this = allocator.create(ThisSink) catch {
globalThis.vm().throwError(globalThis, Syscall.Error.oom.toJSC(
globalThis,