aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/javascript/jsc/api/bun.zig51
-rw-r--r--src/javascript/jsc/node/syscall.zig70
2 files changed, 121 insertions, 0 deletions
diff --git a/src/javascript/jsc/api/bun.zig b/src/javascript/jsc/api/bun.zig
index 0eaab1dbb..b43771f07 100644
--- a/src/javascript/jsc/api/bun.zig
+++ b/src/javascript/jsc/api/bun.zig
@@ -1019,6 +1019,10 @@ pub const Class = NewClass(
.rfn = Bun.allocUnsafe,
.ts = .{},
},
+ .mmap = .{
+ .rfn = Bun.mmapFile,
+ .ts = .{},
+ },
.generateHeapSnapshot = .{
.rfn = Bun.generateHeapSnapshot,
.ts = d.ts{},
@@ -1158,6 +1162,53 @@ pub fn allocUnsafe(
).toJSObjectRef(ctx, null);
}
+pub fn mmapFile(
+ _: void,
+ ctx: js.JSContextRef,
+ _: js.JSObjectRef,
+ _: js.JSObjectRef,
+ arguments: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+) js.JSValueRef {
+ var args = JSC.Node.ArgumentsSlice.from(arguments);
+
+ var buf: [bun.MAX_PATH_BYTES]u8 = undefined;
+ const path = getFilePath(ctx, arguments[0..@minimum(1, arguments.len)], &buf, exception) orelse return null;
+
+ buf[path.len] = 0;
+
+ const buf_z: [:0]const u8 = buf[0..path.len :0];
+
+ const flags = v: {
+ _ = args.nextEat();
+ const opts = args.nextEat() orelse break :v std.os.MAP.SHARED;
+ const sync = opts.get(ctx.ptr(), "sync") orelse JSC.JSValue.jsBoolean(false);
+ const shared = opts.get(ctx.ptr(), "shared") orelse JSC.JSValue.jsBoolean(true);
+ const sync_flags = if (@hasDecl(std.os, "SYNC")) std.os.MAP.SYNC | std.os.MAP.SHARED_VALIDATE else 0;
+
+ var flags: u32 = 0;
+ if (sync.toBoolean()) flags |= sync_flags;
+ if (shared.toBoolean()) flags |= std.os.MAP.SHARED else flags |= std.os.MAP.PRIVATE;
+
+ break :v flags;
+ };
+
+ const map = switch (JSC.Node.Syscall.mmapFile(buf_z, flags)) {
+ .result => |map| map,
+
+ .err => |err| {
+ exception.* = err.toJS(ctx);
+ return null;
+ },
+ };
+
+ return JSC.C.JSObjectMakeTypedArrayWithBytesNoCopy(ctx, JSC.C.JSTypedArrayType.kJSTypedArrayTypeUint8Array, @ptrCast(?*anyopaque, map.ptr), map.len, struct {
+ pub fn x(ptr: ?*anyopaque, size: ?*anyopaque) callconv(.C) void {
+ _ = JSC.Node.Syscall.munmap(@ptrCast([*]align(std.mem.page_size) u8, @alignCast(std.mem.page_size, ptr))[0..@ptrToInt(size)]);
+ }
+ }.x, @intToPtr(?*anyopaque, map.len), exception);
+}
+
pub fn getTranspilerConstructor(
_: void,
ctx: js.JSContextRef,
diff --git a/src/javascript/jsc/node/syscall.zig b/src/javascript/jsc/node/syscall.zig
index 75ea5be89..bf4d6189e 100644
--- a/src/javascript/jsc/node/syscall.zig
+++ b/src/javascript/jsc/node/syscall.zig
@@ -51,6 +51,8 @@ pub const Tag = enum(u8) {
lutimes,
mkdir,
mkdtemp,
+ mmap,
+ munmap,
open,
pread,
pwrite,
@@ -399,6 +401,74 @@ pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) Maybe([]u8) {
}
}
+/// Use of a mapped region can result in these signals:
+/// * SIGSEGV - Attempted write into a region mapped as read-only.
+/// * SIGBUS - Attempted access to a portion of the buffer that does not correspond to the file
+fn sysmmap(
+ ptr: ?[*]align(mem.page_size) u8,
+ length: usize,
+ prot: u32,
+ flags: u32,
+ fd: os.fd_t,
+ offset: u64,
+) Maybe([]align(mem.page_size) u8) {
+ const mmap_sym = if (builtin.os.tag == .linux and builtin.link_libc)
+ system.mmap64
+ else
+ system.mmap;
+
+ const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
+ const rc = mmap_sym(ptr, length, prot, flags, fd, ioffset);
+
+ _ = if (builtin.link_libc) blk: {
+ if (rc != std.c.MAP.FAILED) return .{ .result = @ptrCast([*]align(mem.page_size) u8, @alignCast(mem.page_size, rc))[0..length] };
+ break :blk rc;
+ } else blk: {
+ const err = os.errno(rc);
+ if (err == .SUCCESS) return .{ .result = @intToPtr([*]align(mem.page_size) u8, rc)[0..length] };
+ break :blk rc;
+ };
+
+ return Maybe([]align(mem.page_size) u8).errnoSys(@ptrToInt(rc), .mmap).?;
+}
+
+pub fn mmapFile(path: [:0]const u8, flags: u32) Maybe([]align(mem.page_size) u8) {
+ const fd = switch (open(path, os.O.RDWR, 0)) {
+ .result => |fd| fd,
+ .err => |err| return .{ .err = err },
+ };
+
+ const size = switch (stat(path)) {
+ .result => |stat| stat.size,
+ .err => |err| {
+ _ = close(fd);
+ return .{ .err = err };
+ },
+ };
+
+ const map = switch (sysmmap(null, @intCast(usize, size), os.PROT.READ | os.PROT.WRITE, flags, fd, 0)) {
+ .result => |map| map,
+
+ .err => |err| {
+ _ = close(fd);
+ return .{ .err = err };
+ },
+ };
+
+ if (close(fd)) |err| {
+ _ = munmap(map);
+ return .{ .err = err };
+ }
+
+ return .{ .result = map };
+}
+
+pub fn munmap(memory: []align(mem.page_size) const u8) Maybe(void) {
+ if (Maybe(void).errnoSys(system.munmap(memory.ptr, memory.len), .munmap)) |err| {
+ return err;
+ } else return Maybe(void).success;
+}
+
pub const Error = struct {
const max_errno_value = brk: {
const errno_values = std.enums.values(os.E);