aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js')
-rw-r--r--src/bun.js/base.zig55
-rw-r--r--src/bun.js/bindings/BunString.cpp50
-rw-r--r--src/bun.js/node/node_fs.zig344
-rw-r--r--src/bun.js/node/node_fs_binding.zig57
-rw-r--r--src/bun.js/node/types.zig28
5 files changed, 338 insertions, 196 deletions
diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig
index f7b2eb343..579a0975a 100644
--- a/src/bun.js/base.zig
+++ b/src/bun.js/base.zig
@@ -266,58 +266,21 @@ pub const To = struct {
// Recursion can stack overflow here
if (comptime std.meta.trait.isSlice(Type)) {
- const Child = std.meta.Child(Type);
-
- const prefill = 32;
- if (value.len <= prefill) {
- var array: [prefill]JSC.C.JSValueRef = undefined;
- var i: u8 = 0;
- const len = @min(@as(u8, @intCast(value.len)), prefill);
- while (i < len and exception.* == null) : (i += 1) {
- array[i] = if (comptime Child == JSC.C.JSValueRef)
- value[i]
- else
- To.JS.withType(Child, value[i], context, exception);
- }
-
- if (exception.* != null) {
- return null;
- }
-
- // TODO: this function copies to a MarkedArgumentsBuffer
- // That copy is unnecessary.
- const obj = JSC.C.JSObjectMakeArray(context, len, &array, exception);
-
- if (exception.* != null) {
- return null;
- }
- return obj;
- }
-
- {
- var array = bun.default_allocator.alloc(JSC.C.JSValueRef, value.len) catch unreachable;
- defer bun.default_allocator.free(array);
- var i: usize = 0;
- while (i < value.len and exception.* == null) : (i += 1) {
- array[i] = if (comptime Child == JSC.C.JSValueRef)
- value[i]
- else
- To.JS.withType(Child, value[i], context, exception);
- }
+ const Child = comptime std.meta.Child(Type);
- if (exception.* != null) {
- return null;
- }
+ var array = JSC.JSValue.createEmptyArray(context, value.len);
+ for (value, 0..) |item, i| {
+ array.putIndex(
+ context,
+ @truncate(i),
+ JSC.JSValue.c(To.JS.withType(Child, item, context, exception)),
+ );
- // TODO: this function copies to a MarkedArgumentsBuffer
- // That copy is unnecessary.
- const obj = JSC.C.JSObjectMakeArray(context, value.len, array.ptr, exception);
if (exception.* != null) {
return null;
}
-
- return obj;
}
+ return array.asObjectRef();
}
if (comptime std.meta.trait.isZigString(Type)) {
diff --git a/src/bun.js/bindings/BunString.cpp b/src/bun.js/bindings/BunString.cpp
index 714f10080..e044730c4 100644
--- a/src/bun.js/bindings/BunString.cpp
+++ b/src/bun.js/bindings/BunString.cpp
@@ -256,31 +256,47 @@ extern "C" EncodedJSValue BunString__createArray(
auto& vm = globalObject->vm();
auto throwScope = DECLARE_THROW_SCOPE(vm);
- // We must do this or Bun.gc(true) in a loop creating large arrays of strings will crash due to GC'ing.
- MarkedArgumentBuffer arguments;
- JSC::ObjectInitializationScope scope(vm);
- GCDeferralContext context(vm);
-
- arguments.fill(length, [&](JSC::JSValue* value) {
- const BunString* end = ptr + length;
- while (ptr != end) {
- *value++ = Bun::toJS(globalObject, *ptr++);
- }
- });
+ if (length < 64) {
+ // We must do this or Bun.gc(true) in a loop creating large arrays of strings will crash due to GC'ing.
+ MarkedArgumentBuffer arguments;
+
+ arguments.fill(length, [&](JSC::JSValue* value) {
+ const BunString* end = ptr + length;
+ while (ptr != end) {
+ *value++ = Bun::toJS(globalObject, *ptr++);
+ }
+ });
+
+ JSC::ObjectInitializationScope scope(vm);
+ GCDeferralContext context(vm);
- if (JSC::JSArray* array = JSC::JSArray::tryCreateUninitializedRestricted(
+ JSC::JSArray* array = JSC::JSArray::tryCreateUninitializedRestricted(
scope,
globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
- length)) {
+ length);
+
+ if (array) {
+ for (size_t i = 0; i < length; ++i) {
+ array->initializeIndex(scope, i, arguments.at(i));
+ }
+ return JSValue::encode(array);
+ }
+
+ JSC::throwOutOfMemoryError(globalObject, throwScope);
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(JSC::JSValue()));
+ } else {
+ JSC::JSArray* array = constructEmptyArray(globalObject, nullptr, length);
+ if (!array) {
+ JSC::throwOutOfMemoryError(globalObject, throwScope);
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(JSC::JSValue()));
+ }
for (size_t i = 0; i < length; ++i) {
- array->initializeIndex(scope, i, arguments.at(i));
+ array->putDirectIndex(globalObject, i, Bun::toJS(globalObject, *ptr++));
}
+
return JSValue::encode(array);
}
-
- JSC::throwOutOfMemoryError(globalObject, throwScope);
- RELEASE_AND_RETURN(throwScope, JSValue::encode(JSC::JSValue()));
}
extern "C" void BunString__toWTFString(BunString* bunString)
diff --git a/src/bun.js/node/node_fs.zig b/src/bun.js/node/node_fs.zig
index 314cd44bd..6d2ec4120 100644
--- a/src/bun.js/node/node_fs.zig
+++ b/src/bun.js/node/node_fs.zig
@@ -55,6 +55,160 @@ const ArrayBuffer = JSC.MarkedArrayBuffer;
const Buffer = JSC.Buffer;
const FileSystemFlags = JSC.Node.FileSystemFlags;
+pub const AsyncReaddirTask = struct {
+ promise: JSC.JSPromise.Strong,
+ args: Arguments.Readdir,
+ globalObject: *JSC.JSGlobalObject,
+ task: JSC.WorkPoolTask = .{ .callback = &workPoolCallback },
+ result: JSC.Maybe(Return.Readdir),
+ ref: JSC.PollRef = .{},
+
+ pub fn create(globalObject: *JSC.JSGlobalObject, readdir_args: Arguments.Readdir, vm: *JSC.VirtualMachine) JSC.JSValue {
+ var task = bun.default_allocator.create(AsyncReaddirTask) catch @panic("out of memory");
+ task.* = AsyncReaddirTask{
+ .promise = JSC.JSPromise.Strong.init(globalObject),
+ .args = readdir_args,
+ .result = undefined,
+ .globalObject = globalObject,
+ };
+ task.ref.ref(vm);
+
+ JSC.WorkPool.schedule(&task.task);
+
+ return task.promise.value();
+ }
+
+ fn workPoolCallback(task: *JSC.WorkPoolTask) void {
+ var this: *AsyncReaddirTask = @fieldParentPtr(AsyncReaddirTask, "task", task);
+
+ var node_fs = NodeFS{};
+ this.result = node_fs.readdir(this.args, .promise);
+
+ this.globalObject.bunVMConcurrently().eventLoop().enqueueTaskConcurrent(JSC.ConcurrentTask.fromCallback(this, runFromJSThread));
+ }
+
+ fn runFromJSThread(this: *AsyncReaddirTask) void {
+ var globalObject = this.globalObject;
+ var success = @as(JSC.Maybe(Return.Readdir).Tag, this.result) == .result;
+ const result = switch (this.result) {
+ .err => |err| err.toJSC(globalObject),
+ .result => |res| brk: {
+ var exceptionref: JSC.C.JSValueRef = null;
+ const out = JSC.JSValue.c(JSC.To.JS.withType(Return.Readdir, res, globalObject, &exceptionref));
+ const exception = JSC.JSValue.c(exceptionref);
+ if (exception != .zero) {
+ success = false;
+ break :brk exception;
+ }
+
+ break :brk out;
+ },
+ };
+ var promise_value = this.promise.value();
+ var promise = this.promise.get();
+ promise_value.ensureStillAlive();
+
+ this.deinit();
+ switch (success) {
+ false => {
+ promise.reject(globalObject, result);
+ },
+ true => {
+ promise.resolve(globalObject, result);
+ },
+ }
+ }
+
+ pub fn deinit(this: *AsyncReaddirTask) void {
+ this.ref.unref(this.globalObject.bunVM());
+ this.args.deinit();
+ this.promise.strong.deinit();
+ bun.default_allocator.destroy(this);
+ }
+};
+
+pub const AsyncStatTask = struct {
+ promise: JSC.JSPromise.Strong,
+ args: Arguments.Stat,
+ globalObject: *JSC.JSGlobalObject,
+ task: JSC.WorkPoolTask = .{ .callback = &workPoolCallback },
+ result: JSC.Maybe(Return.Stat),
+ ref: JSC.PollRef = .{},
+ is_lstat: bool = false,
+
+ pub fn create(
+ globalObject: *JSC.JSGlobalObject,
+ readdir_args: Arguments.Stat,
+ vm: *JSC.VirtualMachine,
+ is_lstat: bool,
+ ) JSC.JSValue {
+ var task = bun.default_allocator.create(AsyncStatTask) catch @panic("out of memory");
+ task.* = AsyncStatTask{
+ .promise = JSC.JSPromise.Strong.init(globalObject),
+ .args = readdir_args,
+ .result = undefined,
+ .globalObject = globalObject,
+ .is_lstat = is_lstat,
+ };
+ task.ref.ref(vm);
+
+ JSC.WorkPool.schedule(&task.task);
+
+ return task.promise.value();
+ }
+
+ fn workPoolCallback(task: *JSC.WorkPoolTask) void {
+ var this: *AsyncStatTask = @fieldParentPtr(AsyncStatTask, "task", task);
+
+ var node_fs = NodeFS{};
+ this.result = if (this.is_lstat)
+ node_fs.lstat(this.args, .promise)
+ else
+ node_fs.stat(this.args, .promise);
+
+ this.globalObject.bunVMConcurrently().eventLoop().enqueueTaskConcurrent(JSC.ConcurrentTask.fromCallback(this, runFromJSThread));
+ }
+
+ fn runFromJSThread(this: *AsyncStatTask) void {
+ var globalObject = this.globalObject;
+ var success = @as(JSC.Maybe(Return.Lstat).Tag, this.result) == .result;
+ const result = switch (this.result) {
+ .err => |err| err.toJSC(globalObject),
+ .result => |res| brk: {
+ var exceptionref: JSC.C.JSValueRef = null;
+ const out = JSC.JSValue.c(JSC.To.JS.withType(Return.Lstat, res, globalObject, &exceptionref));
+ const exception = JSC.JSValue.c(exceptionref);
+ if (exception != .zero) {
+ success = false;
+ break :brk exception;
+ }
+
+ break :brk out;
+ },
+ };
+ var promise_value = this.promise.value();
+ var promise = this.promise.get();
+ promise_value.ensureStillAlive();
+
+ this.deinit();
+ switch (success) {
+ false => {
+ promise.reject(globalObject, result);
+ },
+ true => {
+ promise.resolve(globalObject, result);
+ },
+ }
+ }
+
+ pub fn deinit(this: *AsyncStatTask) void {
+ this.ref.unref(this.globalObject.bunVM());
+ this.args.deinit();
+ this.promise.strong.deinit();
+ bun.default_allocator.destroy(this);
+ }
+};
+
// TODO: to improve performance for all of these
// The tagged unions for each type should become regular unions
// and the tags should be passed in as comptime arguments to the functions performing the syscalls
@@ -2624,11 +2778,20 @@ const Return = struct {
};
pub fn toJS(this: Readdir, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.C.JSValueRef {
- return switch (this) {
- .with_file_types => JSC.To.JS.withType([]const Dirent, this.with_file_types, ctx, exception),
- .buffers => JSC.To.JS.withType([]const Buffer, this.buffers, ctx, exception),
- .files => JSC.To.JS.withType([]const bun.String, this.files, ctx, exception),
- };
+ switch (this) {
+ .with_file_types => {
+ defer bun.default_allocator.free(this.with_file_types);
+ return JSC.To.JS.withType([]const Dirent, this.with_file_types, ctx, exception);
+ },
+ .buffers => {
+ defer bun.default_allocator.free(this.buffers);
+ return JSC.To.JS.withType([]const Buffer, this.buffers, ctx, exception);
+ },
+ .files => {
+ // automatically freed
+ return JSC.To.JS.withType([]const bun.String, this.files, ctx, exception);
+ },
+ }
}
};
pub const ReadFile = JSC.Node.StringOrNodeBuffer;
@@ -3145,28 +3308,22 @@ pub const NodeFS = struct {
return Maybe(Return.Link).todo;
}
pub fn lstat(this: *NodeFS, args: Arguments.Lstat, comptime flavor: Flavor) Maybe(Return.Lstat) {
+ _ = flavor;
if (args.big_int) return Maybe(Return.Lstat).todo;
- switch (comptime flavor) {
- .sync => {
- return switch (Syscall.lstat(
- args.path.sliceZ(
- &this.sync_error_buf,
- ),
- )) {
- .result => |result| Maybe(Return.Lstat){ .result = .{ .stats = Stats.init(result, args.big_int) } },
- .err => |err| brk: {
- if (!args.throw_if_no_entry and err.getErrno() == .NOENT) {
- return Maybe(Return.Lstat){ .result = .{ .not_found = {} } };
- }
- break :brk Maybe(Return.Lstat){ .err = err };
- },
- };
+ return switch (Syscall.lstat(
+ args.path.sliceZ(
+ &this.sync_error_buf,
+ ),
+ )) {
+ .result => |result| Maybe(Return.Lstat){ .result = .{ .stats = Stats.init(result, args.big_int) } },
+ .err => |err| brk: {
+ if (!args.throw_if_no_entry and err.getErrno() == .NOENT) {
+ return Maybe(Return.Lstat){ .result = .{ .not_found = {} } };
+ }
+ break :brk Maybe(Return.Lstat){ .err = err };
},
- else => {},
- }
-
- return Maybe(Return.Lstat).todo;
+ };
}
pub fn mkdir(this: *NodeFS, args: Arguments.Mkdir, comptime flavor: Flavor) Maybe(Return.Mkdir) {
@@ -3575,7 +3732,7 @@ pub const NodeFS = struct {
pub fn readdir(this: *NodeFS, args: Arguments.Readdir, comptime flavor: Flavor) Maybe(Return.Readdir) {
return switch (args.encoding) {
.buffer => _readdir(
- this,
+ &this.sync_error_buf,
args,
Buffer,
flavor,
@@ -3583,7 +3740,7 @@ pub const NodeFS = struct {
else => {
if (!args.with_file_types) {
return _readdir(
- this,
+ &this.sync_error_buf,
args,
bun.String,
flavor,
@@ -3591,7 +3748,7 @@ pub const NodeFS = struct {
}
return _readdir(
- this,
+ &this.sync_error_buf,
args,
Dirent,
flavor,
@@ -3601,10 +3758,10 @@ pub const NodeFS = struct {
}
pub fn _readdir(
- this: *NodeFS,
+ buf: *[bun.MAX_PATH_BYTES]u8,
args: Arguments.Readdir,
comptime ExpectedType: type,
- comptime flavor: Flavor,
+ comptime _: Flavor,
) Maybe(Return.Readdir) {
const file_type = comptime switch (ExpectedType) {
Dirent => "with_file_types",
@@ -3613,73 +3770,66 @@ pub const NodeFS = struct {
else => unreachable,
};
- switch (comptime flavor) {
- .sync => {
- var path = args.path.sliceZ(&this.sync_error_buf);
- const flags = os.O.DIRECTORY | os.O.RDONLY;
- const fd = switch (Syscall.open(path, flags, 0)) {
- .err => |err| return .{
- .err = err.withPath(args.path.slice()),
- },
- .result => |fd_| fd_,
- };
- defer {
- _ = Syscall.close(fd);
- }
-
- var entries = std.ArrayList(ExpectedType).init(bun.default_allocator);
- var dir = std.fs.Dir{ .fd = fd };
- var iterator = DirIterator.iterate(dir);
- var entry = iterator.next();
- while (switch (entry) {
- .err => |err| {
- for (entries.items) |*item| {
- switch (comptime ExpectedType) {
- Dirent => {
- item.name.deref();
- },
- Buffer => {
- item.destroy();
- },
- bun.String => {
- item.deref();
- },
- else => unreachable,
- }
- }
-
- entries.deinit();
+ var path = args.path.sliceZ(buf);
+ const flags = os.O.DIRECTORY | os.O.RDONLY;
+ const fd = switch (Syscall.open(path, flags, 0)) {
+ .err => |err| return .{
+ .err = err.withPath(args.path.slice()),
+ },
+ .result => |fd_| fd_,
+ };
+ defer {
+ _ = Syscall.close(fd);
+ }
- return .{
- .err = err.withPath(args.path.slice()),
- };
- },
- .result => |ent| ent,
- }) |current| : (entry = iterator.next()) {
- const utf8_name = current.name.slice();
+ var entries = std.ArrayList(ExpectedType).init(bun.default_allocator);
+ var dir = std.fs.Dir{ .fd = fd };
+ var iterator = DirIterator.iterate(dir);
+ var entry = iterator.next();
+ while (switch (entry) {
+ .err => |err| {
+ for (entries.items) |*item| {
switch (comptime ExpectedType) {
Dirent => {
- entries.append(.{
- .name = bun.String.create(utf8_name),
- .kind = current.kind,
- }) catch unreachable;
+ item.name.deref();
},
Buffer => {
- entries.append(Buffer.fromString(utf8_name, bun.default_allocator) catch unreachable) catch unreachable;
+ item.destroy();
},
bun.String => {
- entries.append(bun.String.create(utf8_name)) catch unreachable;
+ item.deref();
},
else => unreachable,
}
}
- return .{ .result = @unionInit(Return.Readdir, file_type, entries.items) };
+ entries.deinit();
+
+ return .{
+ .err = err.withPath(args.path.slice()),
+ };
},
- else => {},
+ .result => |ent| ent,
+ }) |current| : (entry = iterator.next()) {
+ const utf8_name = current.name.slice();
+ switch (comptime ExpectedType) {
+ Dirent => {
+ entries.append(.{
+ .name = bun.String.create(utf8_name),
+ .kind = current.kind,
+ }) catch unreachable;
+ },
+ Buffer => {
+ entries.append(Buffer.fromString(utf8_name, bun.default_allocator) catch unreachable) catch unreachable;
+ },
+ bun.String => {
+ entries.append(bun.String.create(utf8_name)) catch unreachable;
+ },
+ else => unreachable,
+ }
}
- return Maybe(Return.Readdir).todo;
+ return .{ .result = @unionInit(Return.Readdir, file_type, entries.items) };
}
pub const StringType = enum {
@@ -4354,28 +4504,22 @@ pub const NodeFS = struct {
return Maybe(Return.Rm).todo;
}
pub fn stat(this: *NodeFS, args: Arguments.Stat, comptime flavor: Flavor) Maybe(Return.Stat) {
+ _ = flavor;
if (args.big_int) return Maybe(Return.Stat).todo;
- switch (comptime flavor) {
- .sync => {
- return @as(Maybe(Return.Stat), switch (Syscall.stat(
- args.path.sliceZ(
- &this.sync_error_buf,
- ),
- )) {
- .result => |result| Maybe(Return.Stat){ .result = .{ .stats = Stats.init(result, args.big_int) } },
- .err => |err| brk: {
- if (!args.throw_if_no_entry and err.getErrno() == .NOENT) {
- return Maybe(Return.Stat){ .result = .{ .not_found = {} } };
- }
- break :brk Maybe(Return.Stat){ .err = err };
- },
- });
+ return @as(Maybe(Return.Stat), switch (Syscall.stat(
+ args.path.sliceZ(
+ &this.sync_error_buf,
+ ),
+ )) {
+ .result => |result| Maybe(Return.Stat){ .result = .{ .stats = Stats.init(result, args.big_int) } },
+ .err => |err| brk: {
+ if (!args.throw_if_no_entry and err.getErrno() == .NOENT) {
+ return Maybe(Return.Stat){ .result = .{ .not_found = {} } };
+ }
+ break :brk Maybe(Return.Stat){ .err = err };
},
- else => {},
- }
-
- return Maybe(Return.Stat).todo;
+ });
}
pub fn symlink(this: *NodeFS, args: Arguments.Symlink, comptime flavor: Flavor) Maybe(Return.Symlink) {
diff --git a/src/bun.js/node/node_fs_binding.zig b/src/bun.js/node/node_fs_binding.zig
index a4cc62cd3..88e0b30e2 100644
--- a/src/bun.js/node/node_fs_binding.zig
+++ b/src/bun.js/node/node_fs_binding.zig
@@ -95,25 +95,54 @@ fn callSync(comptime FunctionEnum: NodeFSFunctionEnum) NodeFSFunction {
return NodeBindingClosure.bind;
}
-fn call(comptime Function: NodeFSFunctionEnum) NodeFSFunction {
- // const FunctionType = @TypeOf(Function);
- _ = Function;
-
- // const function: std.builtin.Type.Fn = comptime @typeInfo(FunctionType).Fn;
- // comptime if (function.args.len != 3) @compileError("Expected 3 arguments");
- // const Arguments = comptime function.args[2].type orelse @compileError(std.fmt.comptimePrint("Function {s} expected to have an arg type at [2]", .{@typeName(FunctionType)}));
- // const Result = comptime function.return_type.?;
- // comptime if (Arguments != void and !fromJSTrait(Arguments)) @compileError(std.fmt.comptimePrint("{s} is missing fromJS()", .{@typeName(Arguments)}));
- // comptime if (Result != void and !toJSTrait(Result)) @compileError(std.fmt.comptimePrint("{s} is missing toJS()", .{@typeName(Result)}));
+fn call(comptime FunctionEnum: NodeFSFunctionEnum) NodeFSFunction {
+ const Function = @field(JSC.Node.NodeFS, @tagName(FunctionEnum));
+ const FunctionType = @TypeOf(Function);
+
+ const function: std.builtin.Type.Fn = comptime @typeInfo(FunctionType).Fn;
+ comptime if (function.params.len != 3) @compileError("Expected 3 arguments");
+ const Arguments = comptime function.params[1].type.?;
const NodeBindingClosure = struct {
pub fn bind(
_: *JSC.Node.NodeJSFS,
globalObject: *JSC.JSGlobalObject,
- _: *JSC.CallFrame,
+ callframe: *JSC.CallFrame,
) callconv(.C) JSC.JSValue {
- globalObject.throw("Not implemented yet", .{});
- return .zero;
- // var slice = ArgumentsSlice.init(arguments);
+ if (comptime FunctionEnum != .readdir and FunctionEnum != .lstat and FunctionEnum != .stat) {
+ globalObject.throw("Not implemented yet", .{});
+ return .zero;
+ }
+
+ var arguments = callframe.arguments(8);
+
+ var slice = ArgumentsSlice.init(globalObject.bunVM(), arguments.ptr[0..arguments.len]);
+ var exceptionref: JSC.C.JSValueRef = null;
+ const args = if (comptime Arguments != void)
+ (Arguments.fromJS(globalObject, &slice, &exceptionref) orelse {
+ // we might've already thrown
+ if (exceptionref != null)
+ globalObject.throwValue(JSC.JSValue.c(exceptionref));
+ return .zero;
+ })
+ else
+ Arguments{};
+
+ const exception1 = JSC.JSValue.c(exceptionref);
+
+ if (exception1 != .zero) {
+ globalObject.throwValue(exception1);
+ return .zero;
+ }
+
+ // TODO: handle globalObject.throwValue
+
+ if (comptime FunctionEnum == .readdir) {
+ return JSC.Node.AsyncReaddirTask.create(globalObject, args, slice.vm);
+ }
+
+ if (comptime FunctionEnum == .stat or FunctionEnum == .lstat) {
+ return JSC.Node.AsyncStatTask.create(globalObject, args, slice.vm, FunctionEnum == .lstat);
+ }
// defer {
// for (arguments.len) |arg| {
diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig
index 23d693d69..dadf28629 100644
--- a/src/bun.js/node/types.zig
+++ b/src/bun.js/node/types.zig
@@ -1937,27 +1937,20 @@ pub const Path = struct {
) callconv(.C) JSC.JSValue {
if (comptime is_bindgen) return JSC.JSValue.jsUndefined();
if (args_len == 0) return JSC.ZigString.init("").toValue(globalThis);
-
+ var arena = @import("root").bun.ArenaAllocator.init(heap_allocator);
+ var arena_allocator = arena.allocator();
var stack_fallback_allocator = std.heap.stackFallback(
- (32 * @sizeOf(string)),
- heap_allocator,
+ ((32 * @sizeOf(string)) + 1024),
+ arena_allocator,
);
var allocator = stack_fallback_allocator.get();
- 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;
var to_join = allocator.alloc(string, args_len) catch unreachable;
- var possibly_utf16 = false;
for (args_ptr[0..args_len], 0..) |arg, i| {
const zig_str: JSC.ZigString = arg.getZigString(globalThis);
- if (zig_str.is16Bit()) {
- // TODO: remove this string conversion
- to_join[i] = zig_str.toSlice(arena_allocator).slice();
- possibly_utf16 = true;
- } else {
- to_join[i] = zig_str.slice();
- }
+ to_join[i] = zig_str.toSlice(allocator).slice();
}
const out = if (!isWindows)
@@ -1965,12 +1958,9 @@ pub const Path = struct {
else
PathHandler.joinStringBuf(&buf, to_join, .windows);
- var out_str = JSC.ZigString.init(out);
- if (possibly_utf16) {
- out_str.setOutputEncoding();
- }
-
- return out_str.toValueGC(globalThis);
+ var str = bun.String.create(out);
+ defer str.deref();
+ return str.toJS(globalThis);
}
pub fn normalize(globalThis: *JSC.JSGlobalObject, isWindows: bool, args_ptr: [*]JSC.JSValue, args_len: u16) callconv(.C) JSC.JSValue {
if (comptime is_bindgen) return JSC.JSValue.jsUndefined();