Compare commits

...

6 Commits

Author SHA1 Message Date
Jarred Sumner
9689b5b4be Ignore C++23 error in webkit 2025-04-11 02:41:54 -07:00
Jarred Sumner
03d6dc7532 Bump zig 2025-04-11 02:41:39 -07:00
Jarred Sumner
df8e0dc239 Update 2025-03-01 00:16:53 -08:00
Jarred Sumner
62e3c05c62 Merge branch 'main' into bun-split-3 2025-03-01 00:14:53 -08:00
Jarred-Sumner
7f330141ee bun run zig-format 2025-03-01 07:54:00 +00:00
Jarred Sumner
7e3bf269fd Split up exports.zig into files 2025-02-28 23:52:14 -08:00
22 changed files with 1198 additions and 1068 deletions

View File

@@ -879,6 +879,7 @@ if(NOT WIN32)
-Werror=sometimes-uninitialized
-Werror=unused
-Wno-unused-function
-Wno-c++23-lambda-attributes
-Wno-nullability-completeness
-Werror
)
@@ -895,6 +896,7 @@ if(NOT WIN32)
-Werror=nonnull
-Werror=move
-Werror=sometimes-uninitialized
-Wno-c++23-lambda-attributes
-Wno-nullability-completeness
-Werror
)

View File

@@ -20,7 +20,7 @@ else()
unsupported(CMAKE_SYSTEM_NAME)
endif()
set(ZIG_COMMIT "bb9d6ab2c0bbbf20cc24dad03e88f3b3ffdb7de7")
set(ZIG_COMMIT "deab5c9e7526de0a47b449c5545c3a0f66ebc3c8")
optionx(ZIG_TARGET STRING "The zig target to use" DEFAULT ${DEFAULT_ZIG_TARGET})
if(CMAKE_BUILD_TYPE STREQUAL "Release")

View File

@@ -0,0 +1,25 @@
const std = @import("std");
const ErrorCodeInt = u16;
pub const ErrorCode = enum(ErrorCodeInt) {
_,
pub inline fn from(code: anyerror) ErrorCode {
return @as(ErrorCode, @enumFromInt(@intFromError(code)));
}
pub inline fn toError(self: ErrorCode) anyerror {
return @errorFromInt(@intFromEnum(self));
}
pub const ParserError = @intFromEnum(ErrorCode.from(error.ParserError));
pub const JSErrorObject = @intFromEnum(ErrorCode.from(error.JSErrorObject));
pub const Type = ErrorCodeInt;
};
comptime {
@export(&ErrorCode.ParserError, .{ .name = "Zig_ErrorCodeParserError" });
@export(&ErrorCode.JSErrorObject, .{ .name = "Zig_ErrorCodeJSErrorObject" });
}

View File

@@ -0,0 +1,47 @@
const bun = @import("root").bun;
const std = @import("std");
const ZigErrorType = @import("ZigErrorType.zig").ZigErrorType;
const ErrorCode = @import("ErrorCode.zig").ErrorCode;
const typeBaseName = @import("../../meta.zig").typeBaseName;
pub fn Errorable(comptime Type: type) type {
return extern struct {
result: Result,
success: bool,
pub const name = "Errorable" ++ typeBaseName(@typeName(Type));
pub const Result = extern union {
value: Type,
err: ZigErrorType,
};
pub fn unwrap(errorable: @This()) !Type {
if (errorable.success) {
return errorable.result.value;
} else {
return errorable.result.err.code.toError();
}
}
pub fn value(val: Type) @This() {
return @This(){ .result = .{ .value = val }, .success = true };
}
pub fn ok(val: Type) @This() {
return @This(){ .result = .{ .value = val }, .success = true };
}
threadlocal var err_buf: [4096]u8 = undefined;
pub fn err(code: anyerror, ptr: *anyopaque) @This() {
return @This(){
.result = .{
.err = .{
.code = ErrorCode.from(code),
.ptr = ptr,
},
},
.success = false,
};
}
};
}

View File

@@ -0,0 +1,31 @@
const bun = @import("root").bun;
const string = bun.string;
pub const EventType = enum(u8) {
Event,
MessageEvent,
CloseEvent,
ErrorEvent,
OpenEvent,
unknown = 254,
_,
pub const map = bun.ComptimeStringMap(EventType, .{
.{ EventType.Event.label(), EventType.Event },
.{ EventType.MessageEvent.label(), EventType.MessageEvent },
.{ EventType.CloseEvent.label(), EventType.CloseEvent },
.{ EventType.ErrorEvent.label(), EventType.ErrorEvent },
.{ EventType.OpenEvent.label(), EventType.OpenEvent },
});
pub fn label(this: EventType) string {
return switch (this) {
.Event => "event",
.MessageEvent => "message",
.CloseEvent => "close",
.ErrorEvent => "error",
.OpenEvent => "open",
else => "event",
};
}
};

View File

@@ -0,0 +1,18 @@
const JSC = @import("root").bun.JSC;
const JSGlobalObject = JSC.JSGlobalObject;
const ZigStackTrace = @import("ZigStackTrace.zig").ZigStackTrace;
const JSValue = JSC.JSValue;
/// Opaque representation of a JavaScript exception
pub const Exception = opaque {
extern fn JSC__Exception__getStackTrace(this: *Exception, global: *JSGlobalObject, stack: *ZigStackTrace) void;
extern fn JSC__Exception__asJSValue(this: *Exception) JSValue;
pub fn getStackTrace(this: *Exception, global: *JSGlobalObject, stack: *ZigStackTrace) void {
JSC__Exception__getStackTrace(this, global, stack);
}
pub fn value(this: *Exception) JSValue {
return JSC__Exception__asJSValue(this);
}
};

View File

@@ -0,0 +1,18 @@
/// Represents JavaScript error types
pub const JSErrorCode = enum(u8) {
Error = 0,
EvalError = 1,
RangeError = 2,
ReferenceError = 3,
SyntaxError = 4,
TypeError = 5,
URIError = 6,
AggregateError = 7,
// StackOverflow & OutOfMemoryError is not an ErrorType in "JavaScriptCore/ErrorType.h" within JSC, so the number here is just totally made up
OutOfMemoryError = 8,
BundlerError = 252,
StackOverflow = 253,
UserErrorCode = 254,
_,
};

View File

@@ -0,0 +1,16 @@
/// Represents JavaScript runtime value types
pub const JSRuntimeType = enum(u16) {
Nothing = 0x0,
Function = 0x1,
Undefined = 0x2,
Null = 0x4,
Boolean = 0x8,
AnyInt = 0x10,
Number = 0x20,
String = 0x40,
Object = 0x80,
Symbol = 0x100,
BigInt = 0x200,
_,
};

View File

@@ -0,0 +1,29 @@
const bun = @import("root").bun;
const Environment = bun.Environment;
/// Returns null on error. Use windows API to lookup the actual error.
/// The reason this function is in zig is so that we can use our own utf16-conversion functions.
///
/// Using characters16() does not seem to always have the sentinel. or something else
/// broke when I just used it. Not sure. ... but this works!
pub export fn Bun__LoadLibraryBunString(str: *bun.String) ?*anyopaque {
if (comptime !Environment.isWindows) {
unreachable;
}
var buf: bun.WPathBuffer = undefined;
const data = switch (str.encoding()) {
.utf8 => bun.strings.convertUTF8toUTF16InBuffer(&buf, str.utf8()),
.utf16 => brk: {
@memcpy(buf[0..str.length()], str.utf16());
break :brk buf[0..str.length()];
},
.latin1 => brk: {
bun.strings.copyU8IntoU16(&buf, str.latin1());
break :brk buf[0..str.length()];
},
};
buf[data.len] = 0;
const LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008;
return bun.windows.LoadLibraryExW(buf[0..data.len :0].ptr, null, LOAD_WITH_ALTERED_SEARCH_PATH);
}

View File

@@ -0,0 +1,66 @@
const bun = @import("root").bun;
const JSC = bun.JSC;
const std = @import("std");
const JSGlobalObject = JSC.JSGlobalObject;
const JSValue = JSC.JSValue;
const ErrorableString = JSC.ErrorableString;
// https://github.com/nodejs/node/blob/40ef9d541ed79470977f90eb445c291b95ab75a0/lib/internal/modules/cjs/loader.js#L666
pub export fn NodeModuleModule__findPath(
global: *JSGlobalObject,
request_bun_str: bun.String,
paths_maybe: ?*JSC.JSArray,
) JSValue {
var stack_buf = std.heap.stackFallback(8192, bun.default_allocator);
const alloc = stack_buf.get();
const request_slice = request_bun_str.toUTF8(alloc);
defer request_slice.deinit();
const request = request_slice.slice();
const absolute_request = std.fs.path.isAbsolute(request);
if (!absolute_request and paths_maybe == null) {
return .false;
}
// for each path
const found = if (paths_maybe) |paths| found: {
var iter = paths.iterator(global);
while (iter.next()) |path| {
const cur_path = bun.String.tryFromJS(path, global) orelse {
if (global.hasException()) return .zero;
continue;
};
defer cur_path.deref();
if (findPathInner(request_bun_str, cur_path, global)) |found| {
break :found found;
}
}
break :found null;
} else findPathInner(request_bun_str, bun.String.static(""), global);
if (found) |str| {
return str.toJS(global);
}
return .false;
}
fn findPathInner(
request: bun.String,
cur_path: bun.String,
global: *JSGlobalObject,
) ?bun.String {
var errorable: ErrorableString = undefined;
JSC.VirtualMachine.resolve(
&errorable,
global,
request,
cur_path,
null,
false,
);
return errorable.unwrap() catch null;
}

View File

@@ -0,0 +1,80 @@
const bun = @import("root").bun;
const JSC = bun.JSC;
const JSGlobalObject = JSC.JSGlobalObject;
const JSValue = JSC.JSValue;
const ZigString = JSC.ZigString;
const Shimmer = @import("./shimmer.zig").Shimmer;
/// Process information and control APIs
pub const Process = extern struct {
pub const shim = Shimmer("Bun", "Process", @This());
pub const name = "Process";
pub const namespace = shim.namespace;
var title_mutex = bun.Mutex{};
pub fn getTitle(_: *JSGlobalObject, title: *ZigString) callconv(.C) void {
title_mutex.lock();
defer title_mutex.unlock();
const str = bun.CLI.Bun__Node__ProcessTitle;
title.* = ZigString.init(str orelse "bun");
}
// TODO: https://github.com/nodejs/node/blob/master/deps/uv/src/unix/darwin-proctitle.c
pub fn setTitle(globalObject: *JSGlobalObject, newvalue: *ZigString) callconv(.C) JSValue {
title_mutex.lock();
defer title_mutex.unlock();
if (bun.CLI.Bun__Node__ProcessTitle) |_| bun.default_allocator.free(bun.CLI.Bun__Node__ProcessTitle.?);
bun.CLI.Bun__Node__ProcessTitle = newvalue.dupe(bun.default_allocator) catch bun.outOfMemory();
return newvalue.toJS(globalObject);
}
pub const getArgv = JSC.Node.Process.getArgv;
pub const getCwd = JSC.Node.Process.getCwd;
pub const setCwd = JSC.Node.Process.setCwd;
pub const exit = JSC.Node.Process.exit;
pub const getArgv0 = JSC.Node.Process.getArgv0;
pub const getExecPath = JSC.Node.Process.getExecPath;
pub const getExecArgv = JSC.Node.Process.getExecArgv;
pub const Export = shim.exportFunctions(.{
.getTitle = getTitle,
.setTitle = setTitle,
.getArgv = getArgv,
.getCwd = getCwd,
.setCwd = setCwd,
.exit = exit,
.getArgv0 = getArgv0,
.getExecPath = getExecPath,
.getExecArgv = getExecArgv,
});
comptime {
@export(&getTitle, .{
.name = Export[0].symbol_name,
});
@export(&setTitle, .{
.name = Export[1].symbol_name,
});
@export(&getArgv, .{
.name = Export[2].symbol_name,
});
@export(&getCwd, .{
.name = Export[3].symbol_name,
});
@export(&setCwd, .{
.name = Export[4].symbol_name,
});
@export(&exit, .{
.name = Export[5].symbol_name,
});
@export(&getArgv0, .{
.name = Export[6].symbol_name,
});
@export(&getExecPath, .{
.name = Export[7].symbol_name,
});
@export(&getExecArgv, .{
.name = Export[8].symbol_name,
});
}
};

View File

@@ -0,0 +1,36 @@
const bun = @import("root").bun;
const JSC = bun.JSC;
const Shimmer = @import("./shimmer.zig").Shimmer;
const JSValue = JSC.JSValue;
pub const ResolvedSource = extern struct {
pub const shim = Shimmer("Zig", "ResolvedSource", @This());
pub const name = "ResolvedSource";
pub const namespace = shim.namespace;
/// Specifier's lifetime is the caller from C++
/// https://github.com/oven-sh/bun/issues/9521
specifier: bun.String = bun.String.empty,
source_code: bun.String = bun.String.empty,
/// source_url is eventually deref'd on success
source_url: bun.String = bun.String.empty,
is_commonjs_module: bool = false,
hash: u32 = 0,
allocator: ?*anyopaque = null,
jsvalue_for_export: JSValue = .zero,
tag: Tag = Tag.javascript,
/// This is for source_code
source_code_needs_deref: bool = true,
already_bundled: bool = false,
bytecode_cache: ?[*]u8 = null,
bytecode_cache_size: usize = 0,
pub const Tag = @import("ResolvedSourceTag").ResolvedSourceTag;
};

View File

@@ -0,0 +1,74 @@
const bun = @import("root").bun;
const JSC = bun.JSC;
const NodePath = JSC.Node.Path;
const WebSocketHTTPClient = JSC.WebSocketHTTPClient;
const WebSocketHTTPSClient = JSC.WebSocketHTTPSClient;
const WebSocketClient = JSC.WebSocketClient;
const WebSocketClientTLS = JSC.WebSocketClientTLS;
const JSArrayBufferSink = JSC.JSArrayBufferSink;
const JSHTTPResponseSink = JSC.JSHTTPResponseSink;
const JSHTTPSResponseSink = JSC.JSHTTPSResponseSink;
const JSNetworkSink = JSC.JSNetworkSink;
const JSFileSink = JSC.JSFileSink;
const HTTPServerRequestContext = JSC.HTTPServerRequestContext;
const HTTPSSLServerRequestContext = JSC.HTTPSSLServerRequestContext;
const HTTPDebugServerRequestContext = JSC.HTTPDebugServerRequestContext;
const HTTPDebugSSLServerRequestContext = JSC.HTTPDebugSSLServerRequestContext;
const BodyValueBuffererContext = JSC.BodyValueBuffererContext;
const TestScope = JSC.TestScope;
const Process = JSC.Process;
const Environment = bun.Environment;
const Mimalloc = bun.Mimalloc;
const ZigString = JSC.ZigString;
const std = @import("std");
export fn ZigString__free(raw: [*]const u8, len: usize, allocator_: ?*anyopaque) void {
var allocator: std.mem.Allocator = @as(*std.mem.Allocator, @ptrCast(@alignCast(allocator_ orelse return))).*;
var ptr = ZigString.init(raw[0..len]).slice().ptr;
if (comptime Environment.allow_assert) {
bun.assert(Mimalloc.mi_is_in_heap_region(ptr));
}
const str = ptr[0..len];
allocator.free(str);
}
export fn ZigString__free_global(ptr: [*]const u8, len: usize) void {
const untagged = @as(*anyopaque, @ptrFromInt(@intFromPtr(ZigString.init(ptr[0..len]).slice().ptr)));
if (comptime Environment.allow_assert) {
bun.assert(Mimalloc.mi_is_in_heap_region(ptr));
}
// we must untag the string pointer
Mimalloc.mi_free(untagged);
}
pub fn addShimReferences() void {
WebSocketHTTPClient.shim.ref();
WebSocketHTTPSClient.shim.ref();
WebSocketClient.shim.ref();
WebSocketClientTLS.shim.ref();
HTTPServerRequestContext.shim.ref();
HTTPSSLServerRequestContext.shim.ref();
HTTPDebugServerRequestContext.shim.ref();
HTTPDebugSSLServerRequestContext.shim.ref();
_ = Process.getTitle;
_ = Process.setTitle;
NodePath.shim.ref();
JSArrayBufferSink.shim.ref();
JSHTTPResponseSink.shim.ref();
JSHTTPSResponseSink.shim.ref();
JSNetworkSink.shim.ref();
JSFileSink.shim.ref();
JSFileSink.shim.ref();
_ = &ZigString__free;
_ = &ZigString__free_global;
TestScope.shim.ref();
BodyValueBuffererContext.shim.ref();
_ = @import("LoadLibrary.zig").Bun__LoadLibraryBunString;
_ = &JSC.NodeModuleModule__findPath;
}

View File

@@ -0,0 +1,8 @@
/// Opaque representation of a JavaScript source provider
pub const SourceProvider = opaque {
extern fn JSC__SourceProvider__deref(*SourceProvider) void;
pub fn deref(provider: *SourceProvider) void {
JSC__SourceProvider__deref(provider);
}
};

View File

@@ -0,0 +1,11 @@
const Shimmer = @import("./shimmer.zig").Shimmer;
const ErrorCode = @import("ErrorCode.zig").ErrorCode;
pub const ZigErrorType = extern struct {
pub const shim = Shimmer("Zig", "ErrorType", @This());
pub const name = "ErrorType";
pub const namespace = shim.namespace;
code: ErrorCode,
ptr: ?*anyopaque,
};

View File

@@ -0,0 +1,179 @@
const bun = @import("root").bun;
const std = @import("std");
const JSC = bun.JSC;
const JSValue = JSC.JSValue;
const JSGlobalObject = JSC.JSGlobalObject;
const Exception = JSC.Exception;
const JSErrorCode = JSC.JSErrorCode;
const JSRuntimeType = JSC.JSRuntimeType;
const ZigStackTrace = JSC.ZigStackTrace;
const ZigStackFrame = JSC.ZigStackFrame;
const ZigURL = @import("../../url.zig").URL;
const Api = @import("../../api/schema.zig").Api;
const String = bun.String;
const string = bun.string;
/// Represents a JavaScript exception with additional information
pub const ZigException = extern struct {
type: JSErrorCode,
runtime_type: JSRuntimeType,
/// SystemError only
errno: c_int = 0,
/// SystemError only
syscall: String = String.empty,
/// SystemError only
system_code: String = String.empty,
/// SystemError only
path: String = String.empty,
name: String,
message: String,
stack: ZigStackTrace,
exception: ?*anyopaque,
remapped: bool = false,
fd: i32 = -1,
browser_url: String = .empty,
pub extern fn ZigException__collectSourceLines(jsValue: JSValue, global: *JSGlobalObject, exception: *ZigException) void;
pub fn collectSourceLines(this: *ZigException, value: JSValue, global: *JSGlobalObject) void {
ZigException__collectSourceLines(value, global, this);
}
pub fn deinit(this: *ZigException) void {
this.syscall.deref();
this.system_code.deref();
this.path.deref();
this.name.deref();
this.message.deref();
for (this.stack.source_lines_ptr[0..this.stack.source_lines_len]) |*line| {
line.deref();
}
for (this.stack.frames_ptr[0..this.stack.frames_len]) |*frame| {
frame.deinit();
}
if (this.stack.referenced_source_provider) |source| {
source.deref();
}
}
pub const Holder = extern struct {
const frame_count = 32;
pub const source_lines_count = 6;
source_line_numbers: [source_lines_count]i32,
source_lines: [source_lines_count]String,
frames: [frame_count]ZigStackFrame,
loaded: bool,
zig_exception: ZigException,
need_to_clear_parser_arena_on_deinit: bool = false,
pub const Zero: Holder = Holder{
.frames = brk: {
var _frames: [frame_count]ZigStackFrame = undefined;
@memset(&_frames, ZigStackFrame.Zero);
break :brk _frames;
},
.source_line_numbers = brk: {
var lines: [source_lines_count]i32 = undefined;
@memset(&lines, -1);
break :brk lines;
},
.source_lines = brk: {
var lines: [source_lines_count]String = undefined;
@memset(&lines, String.empty);
break :brk lines;
},
.zig_exception = undefined,
.loaded = false,
};
pub fn init() Holder {
return Holder.Zero;
}
pub fn deinit(this: *Holder, vm: *JSC.VirtualMachine) void {
if (this.loaded) {
this.zig_exception.deinit();
}
if (this.need_to_clear_parser_arena_on_deinit) {
vm.module_loader.resetArena(vm);
}
}
pub fn zigException(this: *Holder) *ZigException {
if (!this.loaded) {
this.zig_exception = ZigException{
.type = @as(JSErrorCode, @enumFromInt(255)),
.runtime_type = JSRuntimeType.Nothing,
.name = String.empty,
.message = String.empty,
.exception = null,
.stack = ZigStackTrace{
.source_lines_ptr = &this.source_lines,
.source_lines_numbers = &this.source_line_numbers,
.source_lines_len = source_lines_count,
.source_lines_to_collect = source_lines_count,
.frames_ptr = &this.frames,
.frames_len = this.frames.len,
},
};
this.loaded = true;
}
return &this.zig_exception;
}
};
extern fn ZigException__fromException(*Exception) ZigException;
pub const fromException = ZigException__fromException;
pub fn addToErrorList(
this: *ZigException,
error_list: *std.ArrayList(Api.JsException),
root_path: string,
origin: ?*const ZigURL,
) !void {
const name_slice = this.name.toUTF8(bun.default_allocator);
const message_slice = this.message.toUTF8(bun.default_allocator);
const _name = name_slice.slice();
defer name_slice.deinit();
const message = message_slice.slice();
defer message_slice.deinit();
var is_empty = true;
var api_exception = Api.JsException{
.runtime_type = @intFromEnum(this.runtime_type),
.code = @intFromEnum(this.type),
};
if (_name.len > 0) {
api_exception.name = try error_list.allocator.dupe(u8, _name);
is_empty = false;
}
if (message.len > 0) {
api_exception.message = try error_list.allocator.dupe(u8, message);
is_empty = false;
}
if (this.stack.frames_len > 0) {
api_exception.stack = try this.stack.toAPI(error_list.allocator, root_path, origin);
is_empty = false;
}
if (!is_empty) {
try error_list.append(api_exception);
}
}
};

View File

@@ -0,0 +1,93 @@
const bun = @import("root").bun;
const JSC = bun.JSC;
const Shimmer = @import("./shimmer.zig").Shimmer;
const JSGlobalObject = JSC.JSGlobalObject;
const ZigString = JSC.ZigString;
const String = bun.String;
const JSValue = JSC.JSValue;
const JSPromise = JSC.JSPromise;
const JSPromiseRejectionOperation = JSC.JSPromiseRejectionOperation;
const Exception = JSC.Exception;
const ErrorableString = JSC.ErrorableString;
const NewGlobalObject = JSC.NewGlobalObject;
/// Global object for Zig JavaScript environment
pub const ZigGlobalObject = extern struct {
pub const shim = Shimmer("Zig", "GlobalObject", @This());
bytes: shim.Bytes,
pub const Type = *anyopaque;
pub const name = "Zig::GlobalObject";
pub const include = "\"ZigGlobalObject.h\"";
pub const namespace = shim.namespace;
pub const Interface: type = NewGlobalObject(JSC.VirtualMachine);
pub fn create(
vm: *JSC.VirtualMachine,
console: *anyopaque,
context_id: i32,
mini_mode: bool,
eval_mode: bool,
worker_ptr: ?*anyopaque,
) *JSGlobalObject {
vm.eventLoop().ensureWaker();
const global = shim.cppFn("create", .{ console, context_id, mini_mode, eval_mode, worker_ptr });
// JSC might mess with the stack size.
bun.StackCheck.configureThread();
return global;
}
pub fn getModuleRegistryMap(global: *JSGlobalObject) *anyopaque {
return shim.cppFn("getModuleRegistryMap", .{global});
}
pub fn resetModuleRegistryMap(global: *JSGlobalObject, map: *anyopaque) bool {
return shim.cppFn("resetModuleRegistryMap", .{ global, map });
}
pub fn import(global: *JSGlobalObject, specifier: *bun.String, source: *bun.String) callconv(.C) ErrorableString {
JSC.markBinding(@src());
return @call(bun.callmod_inline, Interface.import, .{ global, specifier, source });
}
pub fn resolve(res: *ErrorableString, global: *JSGlobalObject, specifier: *bun.String, source: *bun.String, query: *ZigString) callconv(.C) void {
JSC.markBinding(@src());
@call(bun.callmod_inline, Interface.resolve, .{ res, global, specifier, source, query });
}
pub fn promiseRejectionTracker(global: *JSGlobalObject, promise: *JSPromise, rejection: JSPromiseRejectionOperation) callconv(.C) JSValue {
JSC.markBinding(@src());
return @call(bun.callmod_inline, Interface.promiseRejectionTracker, .{ global, promise, rejection });
}
pub fn reportUncaughtException(global: *JSGlobalObject, exception: *Exception) callconv(.C) JSValue {
JSC.markBinding(@src());
return @call(bun.callmod_inline, Interface.reportUncaughtException, .{ global, exception });
}
pub fn onCrash() callconv(.C) void {
JSC.markBinding(@src());
return @call(bun.callmod_inline, Interface.onCrash, .{});
}
pub const Export = shim.exportFunctions(
.{
.import = import,
.resolve = resolve,
.promiseRejectionTracker = promiseRejectionTracker,
.reportUncaughtException = reportUncaughtException,
.onCrash = onCrash,
},
);
pub const Extern = [_][]const u8{ "create", "getModuleRegistryMap", "resetModuleRegistryMap" };
comptime {
@export(&import, .{ .name = Export[0].symbol_name });
@export(&resolve, .{ .name = Export[1].symbol_name });
@export(&promiseRejectionTracker, .{ .name = Export[2].symbol_name });
@export(&reportUncaughtException, .{ .name = Export[3].symbol_name });
@export(&onCrash, .{ .name = Export[4].symbol_name });
}
};

View File

@@ -0,0 +1,209 @@
const bun = @import("root").bun;
const std = @import("std");
const JSC = bun.JSC;
const String = bun.String;
const ZigURL = @import("../../url.zig").URL;
const ZigStackFrameCode = JSC.ZigStackFrameCode;
const ZigStackFramePosition = JSC.ZigStackFramePosition;
const Output = bun.Output;
const strings = bun.strings;
const Api = @import("../../api/schema.zig").Api;
const string = []const u8;
/// Represents a single frame in a stack trace
pub const ZigStackFrame = extern struct {
function_name: String,
source_url: String,
position: ZigStackFramePosition,
code_type: ZigStackFrameCode,
/// This informs formatters whether to display as a blob URL or not
remapped: bool = false,
pub fn deinit(this: *ZigStackFrame) void {
this.function_name.deref();
this.source_url.deref();
}
pub fn toAPI(this: *const ZigStackFrame, root_path: string, origin: ?*const ZigURL, allocator: std.mem.Allocator) !Api.StackFrame {
var frame: Api.StackFrame = comptime std.mem.zeroes(Api.StackFrame);
if (!this.function_name.isEmpty()) {
var slicer = this.function_name.toUTF8(allocator);
defer slicer.deinit();
frame.function_name = (try slicer.clone(allocator)).slice();
}
if (!this.source_url.isEmpty()) {
frame.file = try std.fmt.allocPrint(allocator, "{}", .{this.sourceURLFormatter(root_path, origin, true, false)});
}
frame.position = this.position;
frame.scope = @as(Api.StackFrameScope, @enumFromInt(@intFromEnum(this.code_type)));
return frame;
}
pub const SourceURLFormatter = struct {
source_url: bun.String,
position: ZigStackFramePosition,
enable_color: bool,
origin: ?*const ZigURL,
exclude_line_column: bool = false,
remapped: bool = false,
root_path: string = "",
pub fn format(this: SourceURLFormatter, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
if (this.enable_color) {
try writer.writeAll(Output.prettyFmt("<r><cyan>", true));
}
var source_slice_ = this.source_url.toUTF8(bun.default_allocator);
var source_slice = source_slice_.slice();
defer source_slice_.deinit();
if (!this.remapped) {
if (this.origin) |origin| {
try writer.writeAll(origin.displayProtocol());
try writer.writeAll("://");
try writer.writeAll(origin.displayHostname());
try writer.writeAll(":");
try writer.writeAll(origin.port);
try writer.writeAll("/blob:");
if (strings.startsWith(source_slice, this.root_path)) {
source_slice = source_slice[this.root_path.len..];
}
}
}
try writer.writeAll(source_slice);
if (source_slice.len > 0 and (this.position.line.isValid() or this.position.column.isValid())) {
if (this.enable_color) {
try writer.writeAll(comptime Output.prettyFmt("<r><d>:", true));
} else {
try writer.writeAll(":");
}
}
if (this.enable_color) {
if (this.position.line.isValid() or this.position.column.isValid()) {
try writer.writeAll(comptime Output.prettyFmt("<r>", true));
} else {
try writer.writeAll(comptime Output.prettyFmt("<r>", true));
}
}
if (!this.exclude_line_column) {
if (this.position.line.isValid() and this.position.column.isValid()) {
if (this.enable_color) {
try std.fmt.format(
writer,
comptime Output.prettyFmt("<yellow>{d}<r><d>:<yellow>{d}<r>", true),
.{ this.position.line.oneBased(), this.position.column.oneBased() },
);
} else {
try std.fmt.format(writer, "{d}:{d}", .{
this.position.line.oneBased(),
this.position.column.oneBased(),
});
}
} else if (this.position.line.isValid()) {
if (this.enable_color) {
try std.fmt.format(
writer,
comptime Output.prettyFmt("<yellow>{d}<r>", true),
.{
this.position.line.oneBased(),
},
);
} else {
try std.fmt.format(writer, "{d}", .{
this.position.line.oneBased(),
});
}
}
}
}
};
pub const NameFormatter = struct {
function_name: String,
code_type: ZigStackFrameCode,
enable_color: bool,
pub fn format(this: NameFormatter, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
const name = this.function_name;
switch (this.code_type) {
.Eval => {
if (this.enable_color) {
try std.fmt.format(writer, comptime Output.prettyFmt("<r><d>", true) ++ "eval" ++ Output.prettyFmt("<r>", true), .{});
} else {
try writer.writeAll("eval");
}
if (!name.isEmpty()) {
if (this.enable_color) {
try std.fmt.format(writer, comptime Output.prettyFmt(" <r><b><i>{}<r>", true), .{name});
} else {
try std.fmt.format(writer, " {}", .{name});
}
}
},
.Function => {
if (!name.isEmpty()) {
if (this.enable_color) {
try std.fmt.format(writer, comptime Output.prettyFmt("<r><b><i>{}<r>", true), .{name});
} else {
try std.fmt.format(writer, "{}", .{name});
}
} else {
if (this.enable_color) {
try std.fmt.format(writer, comptime Output.prettyFmt("<r><d>", true) ++ "<anonymous>" ++ Output.prettyFmt("<r>", true), .{});
} else {
try writer.writeAll("<anonymous>");
}
}
},
.Global => {},
.Wasm => {
if (!name.isEmpty()) {
try std.fmt.format(writer, "{}", .{name});
} else {
try writer.writeAll("WASM");
}
},
.Constructor => {
try std.fmt.format(writer, "new {}", .{name});
},
else => {
if (!name.isEmpty()) {
try std.fmt.format(writer, "{}", .{name});
}
},
}
}
};
pub const Zero: ZigStackFrame = .{
.function_name = .empty,
.code_type = .None,
.source_url = .empty,
.position = .invalid,
};
pub fn nameFormatter(this: *const ZigStackFrame, comptime enable_color: bool) NameFormatter {
return NameFormatter{ .function_name = this.function_name, .code_type = this.code_type, .enable_color = enable_color };
}
pub fn sourceURLFormatter(this: *const ZigStackFrame, root_path: string, origin: ?*const ZigURL, exclude_line_column: bool, comptime enable_color: bool) SourceURLFormatter {
return SourceURLFormatter{
.source_url = this.source_url,
.exclude_line_column = exclude_line_column,
.origin = origin,
.root_path = root_path,
.position = this.position,
.enable_color = enable_color,
.remapped = this.remapped,
};
}
};

View File

@@ -0,0 +1,42 @@
const string = @import("root").bun.string;
pub const ZigStackFrameCode = enum(u8) {
None = 0,
/// 🏃
Eval = 1,
/// 📦
Module = 2,
/// λ
Function = 3,
/// 🌎
Global = 4,
/// ⚙️
Wasm = 5,
/// 👷
Constructor = 6,
_,
pub fn emoji(this: ZigStackFrameCode) u21 {
return switch (this) {
.Eval => 0x1F3C3,
.Module => 0x1F4E6,
.Function => 0x03BB,
.Global => 0x1F30E,
.Wasm => 0xFE0F,
.Constructor => 0xF1477,
else => ' ',
};
}
pub fn ansiColor(this: ZigStackFrameCode) string {
return switch (this) {
.Eval => "\x1b[31m",
.Module => "\x1b[36m",
.Function => "\x1b[32m",
.Global => "\x1b[35m",
.Wasm => "\x1b[37m",
.Constructor => "\x1b[33m",
else => "",
};
}
};

View File

@@ -0,0 +1,32 @@
const bun = @import("root").bun;
const std = @import("std");
/// Represents a position in source code with line and column information
pub const ZigStackFramePosition = extern struct {
line: bun.Ordinal,
column: bun.Ordinal,
/// -1 if not present
line_start_byte: c_int,
pub const invalid = ZigStackFramePosition{
.line = .invalid,
.column = .invalid,
.line_start_byte = -1,
};
pub fn isInvalid(this: *const ZigStackFramePosition) bool {
return std.mem.eql(u8, std.mem.asBytes(this), std.mem.asBytes(&invalid));
}
pub fn decode(reader: anytype) !@This() {
return .{
.line = bun.Ordinal.fromZeroBased(try reader.readValue(i32)),
.column = bun.Ordinal.fromZeroBased(try reader.readValue(i32)),
};
}
pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
try writer.writeInt(this.line.zeroBased());
try writer.writeInt(this.column.zeroBased());
}
};

View File

@@ -0,0 +1,145 @@
const bun = @import("root").bun;
const std = @import("std");
const ZigStackFrame = JSC.ZigStackFrame;
const ZigURL = @import("../../url.zig").URL;
const Api = @import("../../api/schema.zig").Api;
const SourceProvider = JSC.SourceProvider;
const JSC = bun.JSC;
const ZigString = JSC.ZigString;
const string = []const u8;
/// Represents a JavaScript stack trace
pub const ZigStackTrace = extern struct {
source_lines_ptr: [*]bun.String,
source_lines_numbers: [*]i32,
source_lines_len: u8,
source_lines_to_collect: u8,
frames_ptr: [*]ZigStackFrame,
frames_len: u8,
/// Non-null if `source_lines_*` points into data owned by a JSC::SourceProvider.
/// If so, then .deref must be called on it to release the memory.
referenced_source_provider: ?*SourceProvider = null,
pub fn fromFrames(frames_slice: []ZigStackFrame) ZigStackTrace {
return .{
.source_lines_ptr = &[0]bun.String{},
.source_lines_numbers = &[0]i32{},
.source_lines_len = 0,
.source_lines_to_collect = 0,
.frames_ptr = frames_slice.ptr,
.frames_len = @min(frames_slice.len, std.math.maxInt(u8)),
.referenced_source_provider = null,
};
}
pub fn toAPI(
this: *const ZigStackTrace,
allocator: std.mem.Allocator,
root_path: string,
origin: ?*const ZigURL,
) !Api.StackTrace {
var stack_trace: Api.StackTrace = comptime std.mem.zeroes(Api.StackTrace);
{
var source_lines_iter = this.sourceLineIterator();
const source_line_len = source_lines_iter.getLength();
if (source_line_len > 0) {
var source_lines = try allocator.alloc(Api.SourceLine, @as(usize, @intCast(@max(source_lines_iter.i + 1, 0))));
var source_line_buf = try allocator.alloc(u8, source_line_len);
source_lines_iter = this.sourceLineIterator();
var remain_buf = source_line_buf[0..];
var i: usize = 0;
while (source_lines_iter.next()) |source| {
const text = source.text.slice();
defer source.text.deinit();
bun.copy(
u8,
remain_buf,
text,
);
const copied_line = remain_buf[0..text.len];
remain_buf = remain_buf[text.len..];
source_lines[i] = .{ .text = copied_line, .line = source.line };
i += 1;
}
stack_trace.source_lines = source_lines;
}
}
{
const _frames = this.frames();
if (_frames.len > 0) {
var stack_frames = try allocator.alloc(Api.StackFrame, _frames.len);
stack_trace.frames = stack_frames;
for (_frames, 0..) |frame, i| {
stack_frames[i] = try frame.toAPI(
root_path,
origin,
allocator,
);
}
}
}
return stack_trace;
}
pub fn frames(this: *const ZigStackTrace) []const ZigStackFrame {
return this.frames_ptr[0..this.frames_len];
}
pub fn framesMutable(this: *ZigStackTrace) []ZigStackFrame {
return this.frames_ptr[0..this.frames_len];
}
pub const SourceLineIterator = struct {
trace: *const ZigStackTrace,
i: i32,
pub const SourceLine = struct {
line: i32,
text: ZigString.Slice,
};
pub fn getLength(this: *SourceLineIterator) usize {
var count: usize = 0;
for (this.trace.source_lines_ptr[0..@as(usize, @intCast(this.i + 1))]) |*line| {
count += line.length();
}
return count;
}
pub fn untilLast(this: *SourceLineIterator) ?SourceLine {
if (this.i < 1) return null;
return this.next();
}
pub fn next(this: *SourceLineIterator) ?SourceLine {
if (this.i < 0) return null;
const source_line = this.trace.source_lines_ptr[@as(usize, @intCast(this.i))];
const result = SourceLine{
.line = this.trace.source_lines_numbers[@as(usize, @intCast(this.i))],
.text = source_line.toUTF8(bun.default_allocator),
};
this.i -= 1;
return result;
}
};
pub fn sourceLineIterator(this: *const ZigStackTrace) SourceLineIterator {
var i: i32 = -1;
for (this.source_lines_numbers[0..this.source_lines_len], 0..) |num, j| {
if (num >= 0) {
i = @max(@as(i32, @intCast(j)), i);
}
}
return .{ .trace = this, .i = i };
}
};

File diff suppressed because it is too large Load Diff