diff options
author | 2023-10-17 14:10:25 -0700 | |
---|---|---|
committer | 2023-10-17 14:10:25 -0700 | |
commit | 7458b969c5d9971e89d187b687e1924e78da427e (patch) | |
tree | ee3dbf95c728cf407bf49a27826b541e9264a8bd /src/bun.js | |
parent | d4a2c29131ec154f5e4db897d4deedab2002cbc4 (diff) | |
parent | e91436e5248d947b50f90b4a7402690be8a41f39 (diff) | |
download | bun-7458b969c5d9971e89d187b687e1924e78da427e.tar.gz bun-7458b969c5d9971e89d187b687e1924e78da427e.tar.zst bun-7458b969c5d9971e89d187b687e1924e78da427e.zip |
Merge branch 'main' into postinstall_3
Diffstat (limited to 'src/bun.js')
159 files changed, 10910 insertions, 4767 deletions
diff --git a/src/bun.js/WebKit b/src/bun.js/WebKit -Subproject a780bdf0255ae1a7ed15e4b3f31c14af705faca +Subproject 1a49a1f94bf42ab4f8c6b11d7bbbb21e491d2d6 diff --git a/src/bun.js/api/JSTranspiler.zig b/src/bun.js/api/JSTranspiler.zig index 8cec025eb..d41458acb 100644 --- a/src/bun.js/api/JSTranspiler.zig +++ b/src/bun.js/api/JSTranspiler.zig @@ -72,6 +72,7 @@ const TranspilerOptions = struct { trim_unused_imports: ?bool = null, inlining: bool = false, + dead_code_elimination: bool = true, minify_whitespace: bool = false, minify_identifiers: bool = false, minify_syntax: bool = false, @@ -541,6 +542,10 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std transpiler.minify_whitespace = flag.toBoolean(); } + if (object.get(globalThis, "deadCodeElimination")) |flag| { + transpiler.dead_code_elimination = flag.toBoolean(); + } + if (object.getTruthy(globalThis, "minify")) |hot| { if (hot.isBoolean()) { transpiler.minify_whitespace = hot.coerce(bool, globalThis); @@ -800,6 +805,7 @@ pub fn constructor( bundler.options.macro_remap = transpiler_options.macro_map; } + bundler.options.dead_code_elimination = transpiler_options.dead_code_elimination; bundler.options.minify_whitespace = transpiler_options.minify_whitespace; // Keep defaults for these diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig index 966c82d38..21c2ecd0e 100644 --- a/src/bun.js/api/bun.zig +++ b/src/bun.js/api/bun.zig @@ -782,11 +782,17 @@ fn doResolveWithArgs( var errorable: ErrorableString = undefined; var query_string = ZigString.Empty; + const specifier_decoded = if (specifier.hasPrefixComptime("file://")) + bun.JSC.URL.pathFromFileURL(specifier) + else + specifier.dupeRef(); + defer specifier_decoded.deref(); + if (comptime is_file_path) { VirtualMachine.resolveFilePathForAPI( &errorable, ctx.ptr(), - specifier, + specifier_decoded, from, &query_string, is_esm, @@ -795,7 +801,7 @@ fn doResolveWithArgs( VirtualMachine.resolveForAPI( &errorable, ctx.ptr(), - specifier, + specifier_decoded, from, &query_string, is_esm, @@ -1098,10 +1104,12 @@ pub const Crypto = struct { } pub fn reset(this: *EVP, engine: *BoringSSL.ENGINE) void { + BoringSSL.ERR_clear_error(); _ = BoringSSL.EVP_DigestInit_ex(&this.ctx, this.md, engine); } pub fn hash(this: *EVP, engine: *BoringSSL.ENGINE, input: []const u8, output: []u8) ?u32 { + BoringSSL.ERR_clear_error(); var outsize: c_uint = @min(@as(u16, @truncate(output.len)), this.size()); if (BoringSSL.EVP_Digest(input.ptr, input.len, output.ptr, &outsize, this.md, engine) != 1) { return null; @@ -1111,6 +1119,7 @@ pub const Crypto = struct { } pub fn final(this: *EVP, engine: *BoringSSL.ENGINE, output: []u8) []const u8 { + BoringSSL.ERR_clear_error(); var outsize: u32 = @min(@as(u16, @truncate(output.len)), this.size()); if (BoringSSL.EVP_DigestFinal_ex( &this.ctx, @@ -1126,6 +1135,7 @@ pub const Crypto = struct { } pub fn update(this: *EVP, input: []const u8) void { + BoringSSL.ERR_clear_error(); _ = BoringSSL.EVP_DigestUpdate(&this.ctx, input.ptr, input.len); } @@ -1134,6 +1144,7 @@ pub const Crypto = struct { } pub fn copy(this: *const EVP, engine: *BoringSSL.ENGINE) error{OutOfMemory}!EVP { + BoringSSL.ERR_clear_error(); var new = init(this.algorithm, this.md, engine); if (BoringSSL.EVP_MD_CTX_copy_ex(&new.ctx, &this.ctx) == 0) { return error.OutOfMemory; @@ -2004,7 +2015,6 @@ pub const Crypto = struct { pub const digest = JSC.wrapInstanceMethod(CryptoHasher, "digest_", false); pub const hash = JSC.wrapStaticMethod(CryptoHasher, "hash_", false); - pub fn getByteLength( this: *CryptoHasher, _: *JSC.JSGlobalObject, @@ -3594,7 +3604,7 @@ pub const Timer = struct { this.poll_ref.unref(vm); - this.timer.deinit(); + this.timer.deinit(false); // balance double unreffing in doUnref vm.event_loop_handle.?.num_polls += @as(i32, @intFromBool(this.did_unref_timer)); diff --git a/src/bun.js/api/bun/dns_resolver.zig b/src/bun.js/api/bun/dns_resolver.zig index 8232318a2..3c20f4df7 100644 --- a/src/bun.js/api/bun/dns_resolver.zig +++ b/src/bun.js/api/bun/dns_resolver.zig @@ -102,11 +102,12 @@ const LibInfo = struct { ) catch unreachable; const promise_value = request.head.promise.value(); + const hints = query.options.toLibC(); const errno = getaddrinfo_async_start_( &request.backend.libinfo.machport, name_z.ptr, null, - null, + if (hints != null) &hints.? else null, GetAddrInfoRequest.getAddrInfoAsyncCallback, request, ); @@ -812,6 +813,170 @@ pub const GetHostByAddrInfoRequest = struct { } }; +pub const CAresNameInfo = struct { + const log = Output.scoped(@This(), true); + + globalThis: *JSC.JSGlobalObject = undefined, + promise: JSC.JSPromise.Strong, + poll_ref: JSC.PollRef, + allocated: bool = false, + next: ?*@This() = null, + name: []const u8, + + pub fn init(globalThis: *JSC.JSGlobalObject, allocator: std.mem.Allocator, name: []const u8) !*@This() { + var this = try allocator.create(@This()); + var poll_ref = JSC.PollRef.init(); + poll_ref.ref(globalThis.bunVM()); + this.* = .{ .globalThis = globalThis, .promise = JSC.JSPromise.Strong.init(globalThis), .poll_ref = poll_ref, .allocated = true, .name = name }; + return this; + } + + pub fn processResolve(this: *@This(), err_: ?c_ares.Error, _: i32, result: ?c_ares.struct_nameinfo) void { + if (err_) |err| { + var promise = this.promise; + var globalThis = this.globalThis; + const error_value = globalThis.createErrorInstance("lookupService failed: {s}", .{err.label()}); + error_value.put( + globalThis, + JSC.ZigString.static("code"), + JSC.ZigString.init(err.code()).toValueGC(globalThis), + ); + + promise.reject(globalThis, error_value); + this.deinit(); + return; + } + if (result == null) { + var promise = this.promise; + var globalThis = this.globalThis; + const error_value = globalThis.createErrorInstance("lookupService failed: No results", .{}); + error_value.put( + globalThis, + JSC.ZigString.static("code"), + JSC.ZigString.init("EUNREACHABLE").toValueGC(globalThis), + ); + + promise.reject(globalThis, error_value); + this.deinit(); + return; + } + var name_info = result.?; + const array = name_info.toJSResponse(this.globalThis.allocator(), this.globalThis); + this.onComplete(array); + return; + } + + pub fn onComplete(this: *@This(), result: JSC.JSValue) void { + var promise = this.promise; + var globalThis = this.globalThis; + this.promise = .{}; + promise.resolve(globalThis, result); + this.deinit(); + } + + pub fn deinit(this: *@This()) void { + this.poll_ref.unrefOnNextTick(this.globalThis.bunVM()); + // freed + bun.default_allocator.free(this.name); + + if (this.allocated) + this.globalThis.allocator().destroy(this); + } +}; + +pub const GetNameInfoRequest = struct { + const request_type = @This(); + + const log = Output.scoped(@This(), false); + + resolver_for_caching: ?*DNSResolver = null, + hash: u64 = 0, + cache: @This().CacheConfig = @This().CacheConfig{}, + head: CAresNameInfo, + tail: *CAresNameInfo = undefined, + + pub fn init( + cache: DNSResolver.LookupCacheHit(@This()), + resolver: ?*DNSResolver, + name: []const u8, + globalThis: *JSC.JSGlobalObject, + comptime cache_field: []const u8, + ) !*@This() { + var request = try globalThis.allocator().create(@This()); + var hasher = std.hash.Wyhash.init(0); + hasher.update(name); + const hash = hasher.final(); + var poll_ref = JSC.PollRef.init(); + poll_ref.ref(globalThis.bunVM()); + request.* = .{ + .resolver_for_caching = resolver, + .hash = hash, + .head = .{ .poll_ref = poll_ref, .globalThis = globalThis, .promise = JSC.JSPromise.Strong.init(globalThis), .allocated = false, .name = name }, + }; + request.tail = &request.head; + if (cache == .new) { + request.resolver_for_caching = resolver; + request.cache = @This().CacheConfig{ + .pending_cache = true, + .entry_cache = false, + .pos_in_pending = @as(u5, @truncate(@field(resolver.?, cache_field).indexOf(cache.new).?)), + .name_len = @as(u9, @truncate(name.len)), + }; + cache.new.lookup = request; + } + return request; + } + + pub const CacheConfig = packed struct(u16) { + pending_cache: bool = false, + entry_cache: bool = false, + pos_in_pending: u5 = 0, + name_len: u9 = 0, + }; + + pub const PendingCacheKey = struct { + hash: u64, + len: u16, + lookup: *request_type = undefined, + + pub fn append(this: *PendingCacheKey, cares_lookup: *CAresNameInfo) void { + var tail = this.lookup.tail; + tail.next = cares_lookup; + this.lookup.tail = cares_lookup; + } + + pub fn init(name: []const u8) PendingCacheKey { + var hasher = std.hash.Wyhash.init(0); + hasher.update(name); + const hash = hasher.final(); + return PendingCacheKey{ + .hash = hash, + .len = @as(u16, @truncate(name.len)), + .lookup = undefined, + }; + } + }; + + pub fn onCaresComplete(this: *@This(), err_: ?c_ares.Error, timeout: i32, result: ?c_ares.struct_nameinfo) void { + if (this.resolver_for_caching) |resolver| { + if (this.cache.pending_cache) { + resolver.drainPendingNameInfoCares( + this.cache.pos_in_pending, + err_, + timeout, + result, + ); + return; + } + } + + var head = this.head; + bun.default_allocator.destroy(this); + + head.processResolve(err_, timeout, result); + } +}; + pub const GetAddrInfoRequest = struct { const log = Output.scoped(.GetAddrInfoRequest, false); @@ -1086,7 +1251,7 @@ pub const CAresReverse = struct { return; } var node = result.?; - const array = node.toJSReponse(this.globalThis.allocator(), this.globalThis, ""); + const array = node.toJSResponse(this.globalThis.allocator(), this.globalThis, ""); this.onComplete(array); return; } @@ -1157,7 +1322,7 @@ pub fn CAresLookup(comptime cares_type: type, comptime type_name: []const u8) ty return; } var node = result.?; - const array = node.toJSReponse(this.globalThis.allocator(), this.globalThis, type_name); + const array = node.toJSResponse(this.globalThis.allocator(), this.globalThis, type_name); this.onComplete(array); return; } @@ -1325,6 +1490,7 @@ pub const DNSResolver = struct { pending_ptr_cache_cares: PtrPendingCache = PtrPendingCache.init(), pending_cname_cache_cares: CnamePendingCache = CnamePendingCache.init(), pending_addr_cache_crares: AddrPendingCache = AddrPendingCache.init(), + pending_nameinfo_cache_cares: NameInfoPendingCache = NameInfoPendingCache.init(), const PendingCache = bun.HiveArray(GetAddrInfoRequest.PendingCacheKey, 32); const SrvPendingCache = bun.HiveArray(ResolveInfoRequest(c_ares.struct_ares_srv_reply, "srv").PendingCacheKey, 32); @@ -1337,6 +1503,7 @@ pub const DNSResolver = struct { const PtrPendingCache = bun.HiveArray(ResolveInfoRequest(c_ares.struct_hostent, "ptr").PendingCacheKey, 32); const CnamePendingCache = bun.HiveArray(ResolveInfoRequest(c_ares.struct_hostent, "cname").PendingCacheKey, 32); const AddrPendingCache = bun.HiveArray(GetHostByAddrInfoRequest.PendingCacheKey, 32); + const NameInfoPendingCache = bun.HiveArray(GetNameInfoRequest.PendingCacheKey, 32); fn getKey(this: *DNSResolver, index: u8, comptime cache_name: []const u8, comptime request_type: type) request_type.PendingCacheKey { var cache = &@field(this, cache_name); @@ -1370,7 +1537,7 @@ pub const DNSResolver = struct { var pending: ?*CAresLookup(cares_type, lookup_name) = key.lookup.head.next; var prev_global = key.lookup.head.globalThis; - var array = addr.toJSReponse(this.vm.allocator, prev_global, lookup_name); + var array = addr.toJSResponse(this.vm.allocator, prev_global, lookup_name); defer addr.deinit(); array.ensureStillAlive(); key.lookup.head.onComplete(array); @@ -1381,7 +1548,7 @@ pub const DNSResolver = struct { while (pending) |value| { var new_global = value.globalThis; if (prev_global != new_global) { - array = addr.toJSReponse(this.vm.allocator, new_global, lookup_name); + array = addr.toJSResponse(this.vm.allocator, new_global, lookup_name); prev_global = new_global; } pending = value.next; @@ -1500,7 +1667,48 @@ pub const DNSResolver = struct { // The callback need not and should not attempt to free the memory // pointed to by hostent; the ares library will free it when the // callback returns. - var array = addr.toJSReponse(this.vm.allocator, prev_global, ""); + var array = addr.toJSResponse(this.vm.allocator, prev_global, ""); + array.ensureStillAlive(); + key.lookup.head.onComplete(array); + bun.default_allocator.destroy(key.lookup); + + array.ensureStillAlive(); + + while (pending) |value| { + var new_global = value.globalThis; + if (prev_global != new_global) { + array = addr.toJSResponse(this.vm.allocator, new_global, ""); + prev_global = new_global; + } + pending = value.next; + + { + array.ensureStillAlive(); + value.onComplete(array); + array.ensureStillAlive(); + } + } + } + + pub fn drainPendingNameInfoCares(this: *DNSResolver, index: u8, err: ?c_ares.Error, timeout: i32, result: ?c_ares.struct_nameinfo) void { + const key = this.getKey(index, "pending_nameinfo_cache_cares", GetNameInfoRequest); + + var name_info = result orelse { + var pending: ?*CAresNameInfo = key.lookup.head.next; + key.lookup.head.processResolve(err, timeout, null); + bun.default_allocator.destroy(key.lookup); + + while (pending) |value| { + pending = value.next; + value.processResolve(err, timeout, null); + } + return; + }; + + var pending: ?*CAresNameInfo = key.lookup.head.next; + var prev_global = key.lookup.head.globalThis; + + var array = name_info.toJSResponse(this.vm.allocator, prev_global); array.ensureStillAlive(); key.lookup.head.onComplete(array); bun.default_allocator.destroy(key.lookup); @@ -1510,7 +1718,7 @@ pub const DNSResolver = struct { while (pending) |value| { var new_global = value.globalThis; if (prev_global != new_global) { - array = addr.toJSReponse(this.vm.allocator, new_global, ""); + array = name_info.toJSResponse(this.vm.allocator, new_global); prev_global = new_global; } pending = value.next; @@ -1977,11 +2185,6 @@ pub const DNSResolver = struct { return .zero; }; - if (name_str.length() == 0) { - globalThis.throwInvalidArgumentType("resolveSoa", "hostname", "non-empty string"); - return .zero; - } - const name = name_str.toSliceClone(globalThis, bun.default_allocator); var vm = globalThis.bunVM(); @@ -2039,11 +2242,6 @@ pub const DNSResolver = struct { return .zero; }; - if (name_str.length() == 0) { - globalThis.throwInvalidArgumentType("resolveNs", "hostname", "non-empty string"); - return .zero; - } - const name = name_str.toSliceClone(globalThis, bun.default_allocator); var vm = globalThis.bunVM(); @@ -2278,7 +2476,7 @@ pub const DNSResolver = struct { return dns_lookup.promise.value(); } - // var hints_buf = &[_]c_ares.AddrInfo_hints{query.toCAres()}; + var hints_buf = &[_]c_ares.AddrInfo_hints{query.toCAres()}; var request = GetAddrInfoRequest.init( cache, .{ @@ -2294,7 +2492,7 @@ pub const DNSResolver = struct { channel.getAddrInfo( query.name, query.port, - &.{}, + hints_buf, GetAddrInfoRequest, request, GetAddrInfoRequest.onCaresComplete, @@ -2386,6 +2584,95 @@ pub const DNSResolver = struct { return values; } + // Resolves the given address and port into a host name and service using the operating system's underlying getnameinfo implementation. + // If address is not a valid IP address, a TypeError will be thrown. The port will be coerced to a number. + // If it is not a legal port, a TypeError will be thrown. + pub fn lookupService(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { + const arguments = callframe.arguments(3); + if (arguments.len < 2) { + globalThis.throwNotEnoughArguments("lookupService", 3, arguments.len); + return .zero; + } + + const addr_value = arguments.ptr[0]; + const port_value = arguments.ptr[1]; + if (addr_value.isEmptyOrUndefinedOrNull() or !addr_value.isString()) { + globalThis.throwInvalidArgumentType("lookupService", "address", "string"); + return .zero; + } + const addr_str = addr_value.toStringOrNull(globalThis) orelse { + return .zero; + }; + if (addr_str.length() == 0) { + globalThis.throwInvalidArgumentType("lookupService", "address", "non-empty string"); + return .zero; + } + + const addr_s = addr_str.getZigString(globalThis).slice(); + const port: u16 = if (port_value.isNumber()) blk: { + break :blk port_value.to(u16); + } else { + globalThis.throwInvalidArgumentType("lookupService", "port", "invalid port"); + return .zero; + }; + + var sa: std.os.sockaddr.storage = std.mem.zeroes(std.os.sockaddr.storage); + if (c_ares.getSockaddr(addr_s, port, @as(*std.os.sockaddr, @ptrCast(&sa))) != 0) { + globalThis.throwInvalidArgumentType("lookupService", "address", "invalid address"); + return .zero; + } + + var vm = globalThis.bunVM(); + var resolver = vm.rareData().globalDNSResolver(vm); + var channel: *c_ares.Channel = switch (resolver.getChannel()) { + .result => |res| res, + .err => |err| { + const system_error = JSC.SystemError{ + .errno = -1, + .code = bun.String.static(err.code()), + .message = bun.String.static(err.label()), + }; + + globalThis.throwValue(system_error.toErrorInstance(globalThis)); + return .zero; + }, + }; + + // This string will be freed in `CAresNameInfo.deinit` + const cache_name = std.fmt.allocPrint(bun.default_allocator, "{s}|{d}", .{ addr_s, port }) catch unreachable; + + const key = GetNameInfoRequest.PendingCacheKey.init(cache_name); + var cache = resolver.getOrPutIntoResolvePendingCache( + GetNameInfoRequest, + key, + "pending_nameinfo_cache_cares", + ); + + if (cache == .inflight) { + var info = CAresNameInfo.init(globalThis, globalThis.allocator(), cache_name) catch unreachable; + cache.inflight.append(info); + return info.promise.value(); + } + + var request = GetNameInfoRequest.init( + cache, + resolver, + cache_name, // transfer ownership here + globalThis, + "pending_nameinfo_cache_cares", + ) catch unreachable; + + const promise = request.tail.promise.value(); + channel.getNameInfo( + @as(*std.os.sockaddr, @ptrCast(&sa)), + GetNameInfoRequest, + request, + GetNameInfoRequest.onCaresComplete, + ); + + return promise; + } + comptime { @export( resolve, @@ -2465,11 +2752,13 @@ pub const DNSResolver = struct { .name = "Bun__DNSResolver__reverse", }, ); + @export( + lookupService, + .{ + .name = "Bun__DNSResolver__lookupService", + }, + ); } - // pub fn lookupService(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { - // const arguments = callframe.arguments(3); - - // } // pub fn cancel(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue { // const arguments = callframe.arguments(3); diff --git a/src/bun.js/api/bun/socket.zig b/src/bun.js/api/bun/socket.zig index 2ad44ffb0..e89ee5aa1 100644 --- a/src/bun.js/api/bun/socket.zig +++ b/src/bun.js/api/bun/socket.zig @@ -771,7 +771,7 @@ pub const Listener = struct { Socket.dataSetCached(this_socket.getThisValue(globalObject), globalObject, default_data); } socket.ext(**anyopaque).?.* = bun.cast(**anyopaque, this_socket); - socket.timeout(120000); + socket.setTimeout(120000); } // pub fn addServerName(this: *Listener, _: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSValue { @@ -996,7 +996,12 @@ pub const Listener = struct { handlers.vm.allocator.destroy(handlers_ptr); handlers.promise.deinit(); bun.default_allocator.destroy(tls); - exception.* = ZigString.static("Failed to connect").toErrorInstance(globalObject).asObjectRef(); + const err = JSC.SystemError{ + .message = bun.String.static("Failed to connect"), + .syscall = bun.String.static("connect"), + .code = if (port == null) bun.String.static("ENOENT") else bun.String.static("ECONNREFUSED"), + }; + exception.* = err.toErrorInstance(globalObject).asObjectRef(); return .zero; }; tls.poll_ref.ref(handlers.vm); @@ -1022,7 +1027,12 @@ pub const Listener = struct { handlers.vm.allocator.destroy(handlers_ptr); handlers.promise.deinit(); bun.default_allocator.destroy(tcp); - exception.* = ZigString.static("Failed to connect").toErrorInstance(globalObject).asObjectRef(); + const err = JSC.SystemError{ + .message = bun.String.static("Failed to connect"), + .syscall = bun.String.static("connect"), + .code = if (port == null) bun.String.static("ENOENT") else bun.String.static("ECONNREFUSED"), + }; + exception.* = err.toErrorInstance(globalObject).asObjectRef(); return .zero; }; tcp.poll_ref.ref(handlers.vm); @@ -1205,6 +1215,12 @@ fn NewSocket(comptime ssl: bool) type { .errno = errno, .message = bun.String.static("Failed to connect"), .syscall = bun.String.static("connect"), + + // For some reason errno is 0 which causes this to be success. + // Unix socket case wont hit this callback because it instantly errors. + .code = bun.String.static("ECONNREFUSED"), + // .code = bun.String.static(@tagName(bun.sys.getErrno(errno))), + // .code = bun.String.static(@tagName(@as(bun.C.E, @enumFromInt(errno)))), }; if (callback == .zero) { @@ -1583,7 +1599,7 @@ fn NewSocket(comptime ssl: bool) type { return .zero; } - this.socket.timeout(@as(c_uint, @intCast(t))); + this.socket.setTimeout(@as(c_uint, @intCast(t))); return JSValue.jsUndefined(); } @@ -1913,7 +1929,7 @@ fn NewSocket(comptime ssl: bool) type { } pub fn finalize(this: *This) callconv(.C) void { - log("finalize()", .{}); + log("finalize() {d}", .{@intFromPtr(this)}); if (!this.detached) { this.detached = true; if (!this.socket.isClosed()) { @@ -2946,6 +2962,17 @@ pub fn NewWrappedHandler(comptime tls: bool) type { } } + pub fn onLongTimeout( + this: WrappedSocket, + socket: Socket, + ) void { + if (comptime tls) { + TLSSocket.onTimeout(this.tls, socket); + } else { + TLSSocket.onTimeout(this.tcp, socket); + } + } + pub fn onConnectError( this: WrappedSocket, socket: Socket, diff --git a/src/bun.js/api/bun/subprocess.zig b/src/bun.js/api/bun/subprocess.zig index 5695c15ad..f6d86d91a 100644 --- a/src/bun.js/api/bun/subprocess.zig +++ b/src/bun.js/api/bun/subprocess.zig @@ -62,12 +62,11 @@ pub const Subprocess = struct { is_sync: bool = false, this_jsvalue: JSC.JSValue = .zero, - ipc: IPCMode, - // this is only ever accessed when `ipc` is not `none` - ipc_socket: IPC.Socket = undefined, + ipc_mode: IPCMode, ipc_callback: JSC.Strong = .{}, - ipc_buffer: bun.ByteList, + ipc: IPC.IPCData, + has_pending_unref: bool = false, pub const SignalCode = bun.SignalCode; pub const IPCMode = enum { @@ -82,7 +81,7 @@ pub const Subprocess = struct { pub fn updateHasPendingActivityFlag(this: *Subprocess) void { @fence(.SeqCst); - this.has_pending_activity.store(this.waitpid_err == null and this.exit_code == null and this.ipc == .none, .SeqCst); + this.has_pending_activity.store(this.waitpid_err == null and this.exit_code == null and this.ipc_mode == .none and this.has_pending_unref, .SeqCst); } pub fn hasPendingActivity(this: *Subprocess) callconv(.C) bool { @@ -92,7 +91,7 @@ pub const Subprocess = struct { pub fn updateHasPendingActivity(this: *Subprocess) void { @fence(.Release); - this.has_pending_activity.store(this.waitpid_err == null and this.exit_code == null and this.ipc == .none, .Release); + this.has_pending_activity.store(this.waitpid_err == null and this.exit_code == null and this.ipc_mode == .none and this.has_pending_unref, .Release); } pub fn ref(this: *Subprocess) void { @@ -111,8 +110,10 @@ pub const Subprocess = struct { } } + /// This disables the keeping process alive flag on the poll and also in the stdin, stdout, and stderr pub fn unref(this: *Subprocess) void { var vm = this.globalThis.bunVM(); + if (this.poll_ref) |poll| poll.disableKeepingProcessAlive(vm); if (!this.hasCalledGetter(.stdin)) { this.stdin.unref(); @@ -425,7 +426,7 @@ pub const Subprocess = struct { } pub fn doSend(this: *Subprocess, global: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSValue { - if (this.ipc == .none) { + if (this.ipc_mode == .none) { global.throw("Subprocess.send() can only be used if an IPC channel is open.", .{}); return .zero; } @@ -437,20 +438,16 @@ pub const Subprocess = struct { const value = callFrame.argument(0); - const success = IPC.serializeJSValueForSubprocess( - global, - value, - this.ipc_socket.fd(), - ); + const success = this.ipc.serializeAndSend(global, value); if (!success) return .zero; return JSC.JSValue.jsUndefined(); } pub fn disconnect(this: *Subprocess) void { - if (this.ipc == .none) return; - this.ipc_socket.close(0, null); - this.ipc = .none; + if (this.ipc_mode == .none) return; + this.ipc.socket.close(0, null); + this.ipc_mode = .none; } pub fn getPid( @@ -1538,15 +1535,15 @@ pub const Subprocess = struct { .stderr = Readable.init(stdio[bun.STDERR_FD], stderr_pipe[0], jsc_vm.allocator, default_max_buffer_size), .on_exit_callback = if (on_exit_callback != .zero) JSC.Strong.create(on_exit_callback, globalThis) else .{}, .is_sync = is_sync, - .ipc = ipc_mode, + .ipc_mode = ipc_mode, // will be assigned in the block below - .ipc_socket = socket, - .ipc_buffer = bun.ByteList{}, + .ipc = .{ .socket = socket }, .ipc_callback = if (ipc_callback != .zero) JSC.Strong.create(ipc_callback, globalThis) else undefined, }; if (ipc_mode != .none) { var ptr = socket.ext(*Subprocess); ptr.?.* = subprocess; + subprocess.ipc.writeVersionPacket(); } if (subprocess.stdin == .pipe) { @@ -1805,8 +1802,29 @@ pub const Subprocess = struct { } } - if (this.hasExited()) - this.unref(); + if (this.hasExited()) { + const Holder = struct { + process: *Subprocess, + task: JSC.AnyTask, + + pub fn unref(self: *@This()) void { + // this calls disableKeepingProcessAlive on pool_ref and stdin, stdout, stderr + self.process.unref(); + self.process.has_pending_unref = false; + self.process.updateHasPendingActivity(); + bun.default_allocator.destroy(self); + } + }; + + var holder = bun.default_allocator.create(Holder) catch @panic("OOM"); + this.has_pending_unref = true; + holder.* = .{ + .process = this, + .task = JSC.AnyTask.New(Holder, Holder.unref).init(holder), + }; + + this.globalThis.bunVM().enqueueTask(JSC.Task.init(&holder.task)); + } } const os = std.os; @@ -2036,7 +2054,7 @@ pub const Subprocess = struct { const result = cb.callWithThis( this.globalThis, this.this_jsvalue, - &[_]JSValue{data}, + &[_]JSValue{ data, this.this_jsvalue }, ); data.ensureStillAlive(); if (result.isAnyError()) { @@ -2049,7 +2067,7 @@ pub const Subprocess = struct { pub fn handleIPCClose(this: *Subprocess, _: IPC.Socket) void { // uSocket is already freed so calling .close() on the socket can segfault - this.ipc = .none; + this.ipc_mode = .none; this.updateHasPendingActivity(); } diff --git a/src/bun.js/api/bun/x509.zig b/src/bun.js/api/bun/x509.zig index 9c902b39c..a94d47c45 100644 --- a/src/bun.js/api/bun/x509.zig +++ b/src/bun.js/api/bun/x509.zig @@ -273,7 +273,8 @@ fn x509PrintGeneralName(out: *BoringSSL.BIO, name: *BoringSSL.GENERAL_NAME) bool // instead always print its numeric representation. var oline: [256]u8 = undefined; _ = BoringSSL.OBJ_obj2txt(&oline, @sizeOf(@TypeOf(oline)), name.d.rid, 1); - _ = BoringSSL.BIO_printf(out, "Registered ID:%s", &oline); + // Workaround for https://github.com/ziglang/zig/issues/16197 + _ = BoringSSL.BIO_printf(out, "Registered ID:%s", @as([*]const u8, &oline)); } else if (name.name_type == .GEN_X400) { _ = BoringSSL.BIO_printf(out, "X400Name:<unsupported>"); } else if (name.name_type == .GEN_EDIPARTY) { @@ -301,7 +302,8 @@ fn x509InfoAccessPrint(out: *BoringSSL.BIO, ext: *BoringSSL.X509_EXTENSION) bool } var tmp: [80]u8 = undefined; _ = BoringSSL.i2t_ASN1_OBJECT(&tmp, @sizeOf(@TypeOf(tmp)), desc.method); - _ = BoringSSL.BIO_printf(out, "%s - ", &tmp); + // Workaround for https://github.com/ziglang/zig/issues/16197 + _ = BoringSSL.BIO_printf(out, "%s - ", @as([*]const u8, &tmp)); if (!x509PrintGeneralName(out, desc.location)) { return false; diff --git a/src/bun.js/api/ffi.zig b/src/bun.js/api/ffi.zig index 097b66d35..a7a03e784 100644 --- a/src/bun.js/api/ffi.zig +++ b/src/bun.js/api/ffi.zig @@ -318,7 +318,11 @@ pub const FFI = struct { }; }; - var obj = JSC.JSValue.createEmptyObject(global, symbols.values().len); + var size = symbols.values().len; + if (size >= 63) { + size = 0; + } + var obj = JSC.JSValue.createEmptyObject(global, size); obj.protect(); defer obj.unprotect(); for (symbols.values()) |*function| { diff --git a/src/bun.js/api/html_rewriter.zig b/src/bun.js/api/html_rewriter.zig index 1bda47512..1f2366ad9 100644 --- a/src/bun.js/api/html_rewriter.zig +++ b/src/bun.js/api/html_rewriter.zig @@ -384,10 +384,10 @@ pub const HTMLRewriter = struct { result.* = Response{ .allocator = bun.default_allocator, + .init = .{ + .status_code = 200, + }, .body = .{ - .init = .{ - .status_code = 200, - }, .value = .{ .Locked = .{ .global = global, @@ -397,16 +397,16 @@ pub const HTMLRewriter = struct { }, }; - result.body.init.method = original.body.init.method; - result.body.init.status_code = original.body.init.status_code; + result.init.method = original.init.method; + result.init.status_code = original.init.status_code; + result.init.status_text = original.init.status_text.clone(); // https://github.com/oven-sh/bun/issues/3334 - if (original.body.init.headers) |headers| { - result.body.init.headers = headers.cloneThis(global); + if (original.init.headers) |headers| { + result.init.headers = headers.cloneThis(global); } result.url = original.url.clone(); - result.status_text = original.status_text.clone(); var value = original.getBodyValue(); sink.bodyValueBufferer = JSC.WebCore.BodyValueBufferer.init(sink, onFinishedBuffering, sink.global, bun.default_allocator); sink.bodyValueBufferer.?.run(value) catch |buffering_error| { @@ -606,10 +606,10 @@ pub const HTMLRewriter = struct { // result.* = Response{ // .allocator = bun.default_allocator, + // .init = .{ + // .status_code = 200, + // }, // .body = .{ - // .init = .{ - // .status_code = 200, - // }, // .value = .{ // .Locked = .{ // .global = global, @@ -619,9 +619,9 @@ pub const HTMLRewriter = struct { // }, // }; - // result.body.init.headers = original.body.init.headers; - // result.body.init.method = original.body.init.method; - // result.body.init.status_code = original.body.init.status_code; + // result.init.headers = original.init.headers; + // result.init.method = original.init.method; + // result.init.status_code = original.init.status_code; // result.url = bun.default_allocator.dupe(u8, original.url) catch unreachable; // result.status_text = bun.default_allocator.dupe(u8, original.status_text) catch unreachable; diff --git a/src/bun.js/api/server.classes.ts b/src/bun.js/api/server.classes.ts index 544f37ce6..81ec30988 100644 --- a/src/bun.js/api/server.classes.ts +++ b/src/bun.js/api/server.classes.ts @@ -24,6 +24,10 @@ function generate(name) { fn: "doStop", length: 1, }, + requestIP: { + fn: "doRequestIP", + length: 1, + }, port: { getter: "getPort", }, @@ -41,6 +45,10 @@ function generate(name) { getter: "getHostname", cache: true, }, + address: { + getter: "getAddress", + cache: true, + }, protocol: { getter: "getProtocol", }, diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig index 85d4dadb5..edf1d6d69 100644 --- a/src/bun.js/api/server.zig +++ b/src/bun.js/api/server.zig @@ -1125,6 +1125,92 @@ fn NewFlags(comptime debug_mode: bool) type { }; } +/// A generic wrapper for the HTTP(s) Server`RequestContext`s. +/// Only really exists because of `NewServer()` and `NewRequestContext()` generics. +pub const AnyRequestContext = struct { + pub const Pointer = bun.TaggedPointerUnion(.{ + HTTPServer.RequestContext, + HTTPSServer.RequestContext, + DebugHTTPServer.RequestContext, + DebugHTTPSServer.RequestContext, + }); + + tagged_pointer: Pointer, + + pub const Null = .{ .tagged_pointer = Pointer.Null }; + + pub fn init(request_ctx: anytype) AnyRequestContext { + return .{ .tagged_pointer = Pointer.init(request_ctx) }; + } + + pub fn getRemoteSocketInfo(self: AnyRequestContext) ?uws.SocketAddress { + if (self.tagged_pointer.isNull()) { + return null; + } + + switch (self.tagged_pointer.tag()) { + @field(Pointer.Tag, bun.meta.typeBaseName(@typeName(HTTPServer.RequestContext))) => { + return self.tagged_pointer.as(HTTPServer.RequestContext).getRemoteSocketInfo(); + }, + @field(Pointer.Tag, bun.meta.typeBaseName(@typeName(HTTPSServer.RequestContext))) => { + return self.tagged_pointer.as(HTTPSServer.RequestContext).getRemoteSocketInfo(); + }, + @field(Pointer.Tag, bun.meta.typeBaseName(@typeName(DebugHTTPServer.RequestContext))) => { + return self.tagged_pointer.as(DebugHTTPServer.RequestContext).getRemoteSocketInfo(); + }, + @field(Pointer.Tag, bun.meta.typeBaseName(@typeName(DebugHTTPSServer.RequestContext))) => { + return self.tagged_pointer.as(DebugHTTPSServer.RequestContext).getRemoteSocketInfo(); + }, + else => @panic("Unexpected AnyRequestContext tag"), + } + } + + /// Wont actually set anything if `self` is `.none` + pub fn setRequest(self: AnyRequestContext, req: *uws.Request) void { + if (self.tagged_pointer.isNull()) { + return; + } + + switch (self.tagged_pointer.tag()) { + @field(Pointer.Tag, bun.meta.typeBaseName(@typeName(HTTPServer.RequestContext))) => { + self.tagged_pointer.as(HTTPServer.RequestContext).req = req; + }, + @field(Pointer.Tag, bun.meta.typeBaseName(@typeName(HTTPSServer.RequestContext))) => { + self.tagged_pointer.as(HTTPSServer.RequestContext).req = req; + }, + @field(Pointer.Tag, bun.meta.typeBaseName(@typeName(DebugHTTPServer.RequestContext))) => { + self.tagged_pointer.as(DebugHTTPServer.RequestContext).req = req; + }, + @field(Pointer.Tag, bun.meta.typeBaseName(@typeName(DebugHTTPSServer.RequestContext))) => { + self.tagged_pointer.as(DebugHTTPSServer.RequestContext).req = req; + }, + else => @panic("Unexpected AnyRequestContext tag"), + } + } + + pub fn getRequest(self: AnyRequestContext) ?*uws.Request { + if (self.tagged_pointer.isNull()) { + return null; + } + + switch (self.tagged_pointer.tag()) { + @field(Pointer.Tag, bun.meta.typeBaseName(@typeName(HTTPServer.RequestContext))) => { + return self.tagged_pointer.as(HTTPServer.RequestContext).req; + }, + @field(Pointer.Tag, bun.meta.typeBaseName(@typeName(HTTPSServer.RequestContext))) => { + return self.tagged_pointer.as(HTTPSServer.RequestContext).req; + }, + @field(Pointer.Tag, bun.meta.typeBaseName(@typeName(DebugHTTPServer.RequestContext))) => { + return self.tagged_pointer.as(DebugHTTPServer.RequestContext).req; + }, + @field(Pointer.Tag, bun.meta.typeBaseName(@typeName(DebugHTTPSServer.RequestContext))) => { + return self.tagged_pointer.as(DebugHTTPSServer.RequestContext).req; + }, + else => @panic("Unexpected AnyRequestContext tag"), + } + } +}; + // This is defined separately partially to work-around an LLVM debugger bug. fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comptime ThisServer: type) type { return struct { @@ -1443,6 +1529,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp } pub fn endStream(this: *RequestContext, closeConnection: bool) void { + ctxLog("endStream", .{}); if (this.resp) |resp| { if (this.flags.is_waiting_for_request_body) { this.flags.is_waiting_for_request_body = false; @@ -1537,8 +1624,17 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp pub fn onAbort(this: *RequestContext, resp: *App.Response) void { std.debug.assert(this.resp == resp); std.debug.assert(!this.flags.aborted); - //mark request as aborted + // mark request as aborted this.flags.aborted = true; + var any_js_calls = false; + var vm = this.server.vm; + defer { + // This is a task in the event loop. + // If we called into JavaScript, we must drain the microtask queue + if (any_js_calls) { + vm.drainMicrotasks(); + } + } // if signal is not aborted, abort the signal if (this.signal) |signal| { @@ -1547,6 +1643,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp const reason = JSC.WebCore.AbortSignal.createAbortError(JSC.ZigString.static("The user aborted a request"), &JSC.ZigString.Empty, this.server.globalThis); reason.ensureStillAlive(); _ = signal.signal(reason); + any_js_calls = true; } _ = signal.unref(); } @@ -1578,6 +1675,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp } else if (body.value.Locked.readable != null) { body.value.Locked.readable.?.abort(this.server.globalThis); body.value.Locked.readable = null; + any_js_calls = true; } body.value.toErrorInstance(JSC.toTypeError(.ABORT_ERR, "Request aborted", .{}, this.server.globalThis), this.server.globalThis); } @@ -1588,6 +1686,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp if (response.body.value.Locked.readable) |*readable| { response.body.value.Locked.readable = null; readable.abort(this.server.globalThis); + any_js_calls = true; } } } @@ -1597,10 +1696,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp this.pending_promises_for_abort += 1; this.promise = null; promise.asAnyPromise().?.reject(this.server.globalThis, JSC.toTypeError(.ABORT_ERR, "Request aborted", .{}, this.server.globalThis)); - } - - if (this.pending_promises_for_abort > 0) { - this.server.vm.tick(); + any_js_calls = true; } } } @@ -1720,6 +1816,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp this: *RequestContext, headers: *JSC.FetchHeaders, ) void { + ctxLog("writeHeaders", .{}); headers.fastRemove(.ContentLength); headers.fastRemove(.TransferEncoding); if (!ssl_enabled) headers.fastRemove(.StrictTransportSecurity); @@ -2091,6 +2188,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp } fn doRenderStream(pair: *StreamPair) void { + ctxLog("doRenderStream", .{}); var this = pair.this; var stream = pair.stream; if (this.resp == null or this.flags.aborted) { @@ -2214,6 +2312,14 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp }, } return; + } else { + // if is not a promise we treat it as Error + streamLog("returned an error", .{}); + if (!this.flags.aborted) resp.clearAborted(); + response_stream.detach(); + this.sink = null; + response_stream.sink.destroy(); + return this.handleReject(assignment_result); } } @@ -2223,6 +2329,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp defer stream.value.unprotect(); response_stream.sink.markDone(); this.finalizeForAbort(); + response_stream.sink.onFirstWrite = null; response_stream.sink.finalize(); return; @@ -2246,7 +2353,12 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp this.setAbortHandler(); streamLog("is in progress, but did not return a Promise. Finalizing request context", .{}); - this.finalize(); + response_stream.sink.onFirstWrite = null; + response_stream.sink.ctx = null; + response_stream.detach(); + stream.cancel(globalThis); + response_stream.sink.markDone(); + this.renderMissing(); } const streamLog = Output.scoped(.ReadableStream, false); @@ -2256,7 +2368,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp } fn toAsyncWithoutAbortHandler(ctx: *RequestContext, req: *uws.Request, request_object: *Request) void { - request_object.uws_request = req; + request_object.request_context.setRequest(req); request_object.ensureURL() catch { request_object.url = bun.String.empty; @@ -2269,7 +2381,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp // This object dies after the stack frame is popped // so we have to clear it in here too - request_object.uws_request = null; + request_object.request_context = JSC.API.AnyRequestContext.Null; } fn toAsync( @@ -2446,7 +2558,6 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp } streamLog("onResolve({any})", .{wrote_anything}); - //aborted so call finalizeForAbort if (req.flags.aborted or req.resp == null) { req.finalizeForAbort(); @@ -2723,7 +2834,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp } pub fn doRender(this: *RequestContext) void { - ctxLog("render", .{}); + ctxLog("doRender", .{}); if (this.flags.aborted) { this.finalizeForAbort(); @@ -2877,7 +2988,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp var needs_content_type = true; const content_type: MimeType = brk: { - if (response.body.init.headers) |headers_| { + if (response.init.headers) |headers_| { if (headers_.fastGet(.ContentType)) |content| { needs_content_type = false; break :brk MimeType.byName(content.slice()); @@ -2897,7 +3008,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp }; var has_content_disposition = false; - if (response.body.init.headers) |headers_| { + if (response.init.headers) |headers_| { has_content_disposition = headers_.fastHas(.ContentDisposition); needs_content_range = needs_content_range and headers_.fastHas(.ContentRange); if (needs_content_range) { @@ -2907,7 +3018,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp this.writeStatus(status); this.writeHeaders(headers_); - response.body.init.headers = null; + response.init.headers = null; headers_.deref(); } else if (needs_content_range) { status = 206; @@ -3039,7 +3150,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp if (last) { var bytes = this.request_body_buf; - defer this.request_body_buf = .{}; + var old = body.value; const total = bytes.items.len + chunk.len; @@ -3070,6 +3181,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp }; // } } + this.request_body_buf = .{}; if (old == .Locked) { var vm = this.server.vm; @@ -3142,6 +3254,10 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp return onStartStreamingRequestBody(bun.cast(*RequestContext, this)); } + pub fn getRemoteSocketInfo(this: *RequestContext) ?uws.SocketAddress { + return (this.resp orelse return null).getRemoteSocketInfo(); + } + pub const Export = shim.exportFunctions(.{ .onResolve = onResolve, .onReject = onReject, @@ -4667,17 +4783,6 @@ pub const ServerWebSocket = struct { return JSValue.jsBoolean(this.websocket.isSubscribed(topic.slice())); } - // pub fn getTopics( - // this: *ServerWebSocket, - // globalThis: *JSC.JSGlobalObject, - // ) callconv(.C) JSValue { - // if (this.closed) { - // return JSValue.createStringArray(globalThis, bun.default_allocator, null, 0, false); - // } - - // this - // } - pub fn getRemoteAddress( this: *ServerWebSocket, globalThis: *JSC.JSGlobalObject, @@ -4704,7 +4809,7 @@ pub const ServerWebSocket = struct { pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comptime debug_mode_: bool) type { return struct { pub const ssl_enabled = ssl_enabled_; - const debug_mode = debug_mode_; + pub const debug_mode = debug_mode_; const ThisServer = @This(); pub const RequestContext = NewRequestContext(ssl_enabled, debug_mode, @This()); @@ -4742,6 +4847,7 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp pub const doPublish = JSC.wrapInstanceMethod(ThisServer, "publish", false); pub const doReload = onReload; pub const doFetch = onFetch; + pub const doRequestIP = JSC.wrapInstanceMethod(ThisServer, "requestIP", false); pub usingnamespace NamespaceType; @@ -4749,6 +4855,24 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp globalThis.throw("Server() is not a constructor", .{}); return null; } + + extern fn JSSocketAddress__create(global: *JSC.JSGlobalObject, ip: JSValue, port: i32, is_ipv6: bool) JSValue; + + pub fn requestIP(this: *ThisServer, request: *JSC.WebCore.Request) JSC.JSValue { + if (this.config.address == .unix) { + return JSValue.jsNull(); + } + return if (request.request_context.getRemoteSocketInfo()) |info| + JSSocketAddress__create( + this.globalThis, + bun.String.static(info.ip).toJSConst(this.globalThis), + info.port, + info.is_ipv6, + ) + else + JSValue.jsNull(); + } + pub fn publish(this: *ThisServer, globalThis: *JSC.JSGlobalObject, topic: ZigString, message_value: JSValue, compress_value: ?JSValue, exception: JSC.C.ExceptionRef) JSValue { if (this.config.websocket == null) return JSValue.jsNumber(0); @@ -5092,7 +5216,7 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp return JSPromise.rejectedPromiseValue(ctx, err); } - var request = ctx.bunVM().allocator.create(Request) catch unreachable; + var request = bun.default_allocator.create(Request) catch unreachable; request.* = existing_request; const response_value = this.config.onRequest.callWithThis( @@ -5173,6 +5297,37 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp return JSC.JSValue.jsNumber(@as(i32, @intCast(@as(u31, @truncate(this.activeSocketsCount()))))); } + pub fn getAddress(this: *ThisServer, globalThis: *JSGlobalObject) callconv(.C) JSC.JSValue { + switch (this.config.address) { + .unix => |unix| { + var value = bun.String.create(bun.sliceTo(@constCast(unix), 0)); + defer value.deref(); + return value.toJS(globalThis); + }, + .tcp => { + var port: u16 = this.config.address.tcp.port; + + if (this.listener) |listener| { + port = @intCast(listener.getLocalPort()); + + var buf: [64]u8 = [_]u8{0} ** 64; + var is_ipv6: bool = false; + + if (listener.socket().localAddressText(&buf, &is_ipv6)) |slice| { + var ip = bun.String.create(slice); + return JSSocketAddress__create( + this.globalThis, + ip.toJS(this.globalThis), + port, + is_ipv6, + ); + } + } + return JSValue.jsNull(); + }, + } + } + pub fn getHostname(this: *ThisServer, globalThis: *JSGlobalObject) callconv(.C) JSC.JSValue { if (this.cached_hostname.isEmpty()) { if (this.listener) |listener| { @@ -5254,6 +5409,10 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp var listener = this.listener orelse return; this.listener = null; this.unref(); + + if (!ssl_enabled_) + this.vm.removeListeningSocketForWatchMode(@intCast(listener.socket().fd())); + if (!abrupt) { listener.close(); } else if (!this.flags.terminated) { @@ -5388,24 +5547,18 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp if (error_instance == .zero) { switch (this.config.address) { .tcp => |tcp| { - error_instance = ZigString.init( - std.fmt.bufPrint(&output_buf, "Failed to start server. Is port {d} in use?", .{tcp.port}) catch "Failed to start server", - ).toErrorInstance( - this.globalThis, - ); + error_instance = (JSC.SystemError{ + .message = bun.String.init(std.fmt.bufPrint(&output_buf, "Failed to start server. Is port {d} in use?", .{tcp.port}) catch "Failed to start server"), + .code = bun.String.static("EADDRINUSE"), + .syscall = bun.String.static("listen"), + }).toErrorInstance(this.globalThis); }, .unix => |unix| { - error_instance = ZigString.init( - std.fmt.bufPrint( - &output_buf, - "Failed to listen on unix socket {}", - .{ - strings.QuotedFormatter{ .text = bun.sliceTo(unix, 0) }, - }, - ) catch "Failed to start server", - ).toErrorInstance( - this.globalThis, - ); + error_instance = (JSC.SystemError{ + .message = bun.String.init(std.fmt.bufPrint(&output_buf, "Failed to listen on unix socket {}", .{strings.QuotedFormatter{ .text = bun.sliceTo(unix, 0) }}) catch "Failed to start server"), + .code = bun.String.static("EADDRINUSE"), + .syscall = bun.String.static("listen"), + }).toErrorInstance(this.globalThis); }, } } @@ -5428,6 +5581,8 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp this.listener = socket; this.vm.event_loop_handle = uws.Loop.get(); + if (!ssl_enabled_) + this.vm.addListeningSocketForWatchMode(@intCast(socket.?.socket().fd())); } pub fn ref(this: *ThisServer) void { @@ -5512,21 +5667,19 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp req.setYield(false); var ctx = this.request_pool_allocator.tryGet() catch @panic("ran out of memory"); ctx.create(this, req, resp); + this.vm.jsc.reportExtraMemory(@sizeOf(RequestContext)); var request_object = this.allocator.create(JSC.WebCore.Request) catch unreachable; var body = JSC.WebCore.InitRequestBodyValue(.{ .Null = {} }) catch unreachable; ctx.request_body = body; - const js_signal = JSC.WebCore.AbortSignal.create(this.globalThis); - js_signal.ensureStillAlive(); - if (JSC.WebCore.AbortSignal.fromJS(js_signal)) |signal| { - ctx.signal = signal.ref().ref(); // +2 refs 1 for the request and 1 for the request context - } + var signal = JSC.WebCore.AbortSignal.new(this.globalThis); + ctx.signal = signal; request_object.* = .{ .method = ctx.method, - .uws_request = req, + .request_context = AnyRequestContext.init(ctx), .https = ssl_enabled, - .signal = ctx.signal, + .signal = signal.ref(), .body = body.ref(), }; @@ -5593,7 +5746,7 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp const response_value = this.config.onRequest.callWithThis(this.globalThis, this.thisObject, &args); defer { // uWS request will not live longer than this function - request_object.uws_request = null; + request_object.request_context = JSC.API.AnyRequestContext.Null; } var should_deinit_context = false; @@ -5608,7 +5761,7 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp ctx.defer_deinit_until_callback_completes = null; if (should_deinit_context) { - request_object.uws_request = null; + request_object.request_context = JSC.API.AnyRequestContext.Null; ctx.deinit(); return; } @@ -5637,18 +5790,15 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp var body = JSC.WebCore.InitRequestBodyValue(.{ .Null = {} }) catch unreachable; ctx.request_body = body; - const js_signal = JSC.WebCore.AbortSignal.create(this.globalThis); - js_signal.ensureStillAlive(); - if (JSC.WebCore.AbortSignal.fromJS(js_signal)) |signal| { - ctx.signal = signal.ref().ref(); // +2 refs 1 for the request and 1 for the request context - } + var signal = JSC.WebCore.AbortSignal.new(this.globalThis); + ctx.signal = signal; request_object.* = .{ .method = ctx.method, - .uws_request = req, + .request_context = AnyRequestContext.init(ctx), .upgrader = ctx, .https = ssl_enabled, - .signal = ctx.signal, + .signal = signal.ref(), .body = body.ref(), }; ctx.upgrade_context = upgrade_ctx; @@ -5663,7 +5813,7 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp const response_value = this.config.onRequest.callWithThis(this.globalThis, this.thisObject, &args); defer { // uWS request will not live longer than this function - request_object.uws_request = null; + request_object.request_context = JSC.API.AnyRequestContext.Null; } var should_deinit_context = false; @@ -5678,7 +5828,7 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp ctx.defer_deinit_until_callback_completes = null; if (should_deinit_context) { - request_object.uws_request = null; + request_object.request_context = JSC.API.AnyRequestContext.Null; ctx.deinit(); return; } diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig index d050804e3..70e5351cc 100644 --- a/src/bun.js/base.zig +++ b/src/bun.js/base.zig @@ -1179,8 +1179,7 @@ pub fn DOMCall( \\ thisObject->putDirect( \\ globalObject->vm(), \\ Identifier::fromString(globalObject->vm(), "{[name]s}"_s), - \\ function, - \\ JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction | 0 + \\ function \\ ); \\}} ; @@ -1794,12 +1793,19 @@ pub const FilePoll = struct { pub fn deinit(this: *FilePoll) void { var vm = JSC.VirtualMachine.get(); - this.deinitWithVM(vm); + var loop = vm.event_loop_handle.?; + this.deinitPossiblyDefer(vm, loop, vm.rareData().filePolls(vm), false); + } + + pub fn deinitForceUnregister(this: *FilePoll) void { + var vm = JSC.VirtualMachine.get(); + var loop = vm.event_loop_handle.?; + this.deinitPossiblyDefer(vm, loop, vm.rareData().filePolls(vm), true); } - fn deinitPossiblyDefer(this: *FilePoll, vm: *JSC.VirtualMachine, loop: *uws.Loop, polls: *JSC.FilePoll.Store) void { + fn deinitPossiblyDefer(this: *FilePoll, vm: *JSC.VirtualMachine, loop: *uws.Loop, polls: *JSC.FilePoll.Store, force_unregister: bool) void { if (this.isRegistered()) { - _ = this.unregister(loop); + _ = this.unregister(loop, force_unregister); } this.owner = Deactivated.owner; @@ -1811,7 +1817,7 @@ pub const FilePoll = struct { pub fn deinitWithVM(this: *FilePoll, vm: *JSC.VirtualMachine) void { var loop = vm.event_loop_handle.?; - this.deinitPossiblyDefer(vm, loop, vm.rareData().filePolls(vm)); + this.deinitPossiblyDefer(vm, loop, vm.rareData().filePolls(vm), false); } pub fn isRegistered(this: *const FilePoll) bool { @@ -2204,10 +2210,12 @@ pub const FilePoll = struct { var event = linux.epoll_event{ .events = flags, .data = .{ .u64 = @intFromPtr(Pollable.init(this).ptr()) } }; + var op: u32 = if (this.isRegistered() or this.flags.contains(.needs_rearm)) linux.EPOLL.CTL_MOD else linux.EPOLL.CTL_ADD; + const ctl = linux.epoll_ctl( watcher_fd, - if (this.isRegistered() or this.flags.contains(.needs_rearm)) linux.EPOLL.CTL_MOD else linux.EPOLL.CTL_ADD, - @as(std.os.fd_t, @intCast(fd)), + op, + @intCast(fd), &event, ); this.flags.insert(.was_ever_registered); @@ -2321,11 +2329,11 @@ pub const FilePoll = struct { const invalid_fd = bun.invalid_fd; - pub fn unregister(this: *FilePoll, loop: *uws.Loop) JSC.Maybe(void) { - return this.unregisterWithFd(loop, this.fd); + pub fn unregister(this: *FilePoll, loop: *uws.Loop, force_unregister: bool) JSC.Maybe(void) { + return this.unregisterWithFd(loop, this.fd, force_unregister); } - pub fn unregisterWithFd(this: *FilePoll, loop: *uws.Loop, fd: bun.UFileDescriptor) JSC.Maybe(void) { + pub fn unregisterWithFd(this: *FilePoll, loop: *uws.Loop, fd: bun.UFileDescriptor, force_unregister: bool) JSC.Maybe(void) { if (!(this.flags.contains(.poll_readable) or this.flags.contains(.poll_writable) or this.flags.contains(.poll_process) or this.flags.contains(.poll_machport))) { // no-op return JSC.Maybe(void).success; @@ -2346,7 +2354,7 @@ pub const FilePoll = struct { return JSC.Maybe(void).success; }; - if (this.flags.contains(.needs_rearm)) { + if (this.flags.contains(.needs_rearm) and !force_unregister) { log("unregister: {s} ({d}) skipped due to needs_rearm", .{ @tagName(flag), fd }); this.flags.remove(.poll_process); this.flags.remove(.poll_readable); @@ -2361,7 +2369,7 @@ pub const FilePoll = struct { const ctl = linux.epoll_ctl( watcher_fd, linux.EPOLL.CTL_DEL, - @as(std.os.fd_t, @intCast(fd)), + @intCast(fd), null, ); diff --git a/src/bun.js/bindings/AsyncContextFrame.cpp b/src/bun.js/bindings/AsyncContextFrame.cpp index 1c541b2a8..7b715d3d7 100644 --- a/src/bun.js/bindings/AsyncContextFrame.cpp +++ b/src/bun.js/bindings/AsyncContextFrame.cpp @@ -22,7 +22,7 @@ AsyncContextFrame* AsyncContextFrame::create(VM& vm, JSC::Structure* structure, AsyncContextFrame* AsyncContextFrame::create(JSGlobalObject* global, JSValue callback, JSValue context) { auto& vm = global->vm(); - AsyncContextFrame* asyncContextData = new (NotNull, allocateCell<AsyncContextFrame>(vm)) AsyncContextFrame(vm, static_cast<Zig::GlobalObject*>(global)->AsyncContextFrameStructure()); + AsyncContextFrame* asyncContextData = new (NotNull, allocateCell<AsyncContextFrame>(vm)) AsyncContextFrame(vm, jsCast<Zig::GlobalObject*>(global)->AsyncContextFrameStructure()); asyncContextData->finishCreation(vm); asyncContextData->callback.set(vm, asyncContextData, callback); asyncContextData->context.set(vm, asyncContextData, context); @@ -47,7 +47,7 @@ JSValue AsyncContextFrame::withAsyncContextIfNeeded(JSGlobalObject* globalObject auto& vm = globalObject->vm(); return AsyncContextFrame::create( vm, - static_cast<Zig::GlobalObject*>(globalObject)->AsyncContextFrameStructure(), + jsCast<Zig::GlobalObject*>(globalObject)->AsyncContextFrameStructure(), callback, context); } diff --git a/src/bun.js/bindings/BunDebugger.cpp b/src/bun.js/bindings/BunDebugger.cpp index 046739923..55942d2f6 100644 --- a/src/bun.js/bindings/BunDebugger.cpp +++ b/src/bun.js/bindings/BunDebugger.cpp @@ -452,12 +452,13 @@ extern "C" void Bun__ensureDebugger(ScriptExecutionContextIdentifier scriptId, b } } -extern "C" void BunDebugger__willHotReload() { +extern "C" void BunDebugger__willHotReload() +{ if (debuggerScriptExecutionContext == nullptr) { return; } - debuggerScriptExecutionContext->postTaskConcurrently([](ScriptExecutionContext &context){ + debuggerScriptExecutionContext->postTaskConcurrently([](ScriptExecutionContext& context) { WTF::LockHolder locker(inspectorConnectionsLock); for (auto& connections : *inspectorConnections) { for (auto* connection : connections.value) { diff --git a/src/bun.js/bindings/BunObject.cpp b/src/bun.js/bindings/BunObject.cpp index 0b78d1367..498b83b45 100644 --- a/src/bun.js/bindings/BunObject.cpp +++ b/src/bun.js/bindings/BunObject.cpp @@ -190,7 +190,7 @@ static JSValue constructPluginObject(VM& vm, JSObject* bunObject) auto* globalObject = bunObject->globalObject(); JSFunction* pluginFunction = JSFunction::create(vm, globalObject, 1, String("plugin"_s), jsFunctionBunPlugin, ImplementationVisibility::Public, NoIntrinsic); pluginFunction->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "clearAll"_s), 1, jsFunctionBunPluginClear, ImplementationVisibility::Public, NoIntrinsic, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + JSC::PropertyAttribute::DontDelete | 0); return pluginFunction; } @@ -215,37 +215,40 @@ extern "C" EncodedJSValue Bun__DNSResolver__resolvePtr(JSGlobalObject*, JSC::Cal extern "C" EncodedJSValue Bun__DNSResolver__resolveCname(JSGlobalObject*, JSC::CallFrame*); extern "C" EncodedJSValue Bun__DNSResolver__getServers(JSGlobalObject*, JSC::CallFrame*); extern "C" EncodedJSValue Bun__DNSResolver__reverse(JSGlobalObject*, JSC::CallFrame*); +extern "C" EncodedJSValue Bun__DNSResolver__lookupService(JSGlobalObject*, JSC::CallFrame*); static JSValue constructDNSObject(VM& vm, JSObject* bunObject) { JSGlobalObject* globalObject = bunObject->globalObject(); JSC::JSObject* dnsObject = JSC::constructEmptyObject(globalObject); dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "lookup"_s), 2, Bun__DNSResolver__lookup, ImplementationVisibility::Public, NoIntrinsic, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + JSC::PropertyAttribute::DontDelete | 0); dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolve"_s), 2, Bun__DNSResolver__resolve, ImplementationVisibility::Public, NoIntrinsic, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + JSC::PropertyAttribute::DontDelete | 0); dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveSrv"_s), 2, Bun__DNSResolver__resolveSrv, ImplementationVisibility::Public, NoIntrinsic, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + JSC::PropertyAttribute::DontDelete | 0); dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveTxt"_s), 2, Bun__DNSResolver__resolveTxt, ImplementationVisibility::Public, NoIntrinsic, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + JSC::PropertyAttribute::DontDelete | 0); dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveSoa"_s), 2, Bun__DNSResolver__resolveSoa, ImplementationVisibility::Public, NoIntrinsic, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + JSC::PropertyAttribute::DontDelete | 0); dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveNaptr"_s), 2, Bun__DNSResolver__resolveNaptr, ImplementationVisibility::Public, NoIntrinsic, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + JSC::PropertyAttribute::DontDelete | 0); dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveMx"_s), 2, Bun__DNSResolver__resolveMx, ImplementationVisibility::Public, NoIntrinsic, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + JSC::PropertyAttribute::DontDelete | 0); dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveCaa"_s), 2, Bun__DNSResolver__resolveCaa, ImplementationVisibility::Public, NoIntrinsic, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + JSC::PropertyAttribute::DontDelete | 0); dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveNs"_s), 2, Bun__DNSResolver__resolveNs, ImplementationVisibility::Public, NoIntrinsic, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + JSC::PropertyAttribute::DontDelete | 0); dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolvePtr"_s), 2, Bun__DNSResolver__resolvePtr, ImplementationVisibility::Public, NoIntrinsic, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + JSC::PropertyAttribute::DontDelete | 0); dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveCname"_s), 2, Bun__DNSResolver__resolveCname, ImplementationVisibility::Public, NoIntrinsic, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + JSC::PropertyAttribute::DontDelete | 0); dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "getServers"_s), 2, Bun__DNSResolver__getServers, ImplementationVisibility::Public, NoIntrinsic, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + JSC::PropertyAttribute::DontDelete | 0); dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "reverse"_s), 2, Bun__DNSResolver__reverse, ImplementationVisibility::Public, NoIntrinsic, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + JSC::PropertyAttribute::DontDelete | 0); + dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "lookupService"_s), 2, Bun__DNSResolver__lookupService, ImplementationVisibility::Public, NoIntrinsic, + JSC::PropertyAttribute::DontDelete | 0); return dnsObject; } @@ -255,7 +258,7 @@ static JSValue constructBunPeekObject(VM& vm, JSObject* bunObject) JSC::Identifier identifier = JSC::Identifier::fromString(vm, "peek"_s); JSFunction* peekFunction = JSFunction::create(vm, globalObject, 2, WTF::String("peek"_s), functionBunPeek, ImplementationVisibility::Public, NoIntrinsic); JSFunction* peekStatus = JSFunction::create(vm, globalObject, 1, WTF::String("status"_s), functionBunPeekStatus, ImplementationVisibility::Public, NoIntrinsic); - peekFunction->putDirect(vm, PropertyName(JSC::Identifier::fromString(vm, "status"_s)), peekStatus, JSC::PropertyAttribute::Function | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | 0); + peekFunction->putDirect(vm, PropertyName(JSC::Identifier::fromString(vm, "status"_s)), peekStatus, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | 0); return peekFunction; } @@ -602,7 +605,7 @@ JSC_DEFINE_HOST_FUNCTION(functionHashCode, hash BunObject_getter_wrap_hash DontDelete|PropertyCallback indexOfLine BunObject_callback_indexOfLine DontDelete|Function 1 inflateSync BunObject_callback_inflateSync DontDelete|Function 1 - inspect BunObject_getter_wrap_inspect DontDelete|PropertyCallback + inspect BunObject_getter_wrap_inspect DontDelete|PropertyCallback isMainThread constructIsMainThread ReadOnly|DontDelete|PropertyCallback jest BunObject_callback_jest DontEnum|DontDelete|Function 1 listen BunObject_callback_listen DontDelete|Function 1 @@ -660,6 +663,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSBunObject, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -670,15 +674,14 @@ public: void finishCreation(JSC::VM& vm) { Base::finishCreation(vm); - JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); } static JSBunObject* create(JSC::VM& vm, JSGlobalObject* globalObject) { - auto* object = new (NotNull, JSC::allocateCell<JSBunObject>(vm)) JSBunObject(vm, createStructure(vm, globalObject, globalObject->objectPrototype())); + auto structure = createStructure(vm, globalObject, globalObject->objectPrototype()); + auto* object = new (NotNull, JSC::allocateCell<JSBunObject>(vm)) JSBunObject(vm, structure); object->finishCreation(vm); - return object; } }; @@ -699,11 +702,11 @@ public: #undef bunObjectReadableStreamToJSONCodeGenerator #undef bunObjectReadableStreamToTextCodeGenerator -const JSC::ClassInfo JSBunObject::s_info = { "Bun"_s, &JSNonFinalObject::s_info, &bunObjectTable, nullptr, CREATE_METHOD_TABLE(JSBunObject) }; +const JSC::ClassInfo JSBunObject::s_info = { "Bun"_s, &Base::s_info, &bunObjectTable, nullptr, CREATE_METHOD_TABLE(JSBunObject) }; -JSValue createBunObject(Zig::GlobalObject* globalObject) +JSC::JSObject* createBunObject(VM& vm, JSObject* globalObject) { - return JSBunObject::create(globalObject->vm(), globalObject); + return JSBunObject::create(vm, jsCast<Zig::GlobalObject*>(globalObject)); } } diff --git a/src/bun.js/bindings/BunObject.h b/src/bun.js/bindings/BunObject.h index c2abfe06f..f527f5729 100644 --- a/src/bun.js/bindings/BunObject.h +++ b/src/bun.js/bindings/BunObject.h @@ -13,5 +13,5 @@ JSC_DECLARE_HOST_FUNCTION(functionBunNanoseconds); JSC_DECLARE_HOST_FUNCTION(functionPathToFileURL); JSC_DECLARE_HOST_FUNCTION(functionFileURLToPath); -JSC::JSValue createBunObject(Zig::GlobalObject* globalObject); +JSC::JSObject* createBunObject(VM& vm, JSObject* globalObject); } diff --git a/src/bun.js/bindings/BunObject.lut.h b/src/bun.js/bindings/BunObject.lut.h index 1971cb8da..a2aa95fda 100644 --- a/src/bun.js/bindings/BunObject.lut.h +++ b/src/bun.js/bindings/BunObject.lut.h @@ -1,4 +1,4 @@ -// File generated via `make generate-builtins` +// File generated via `make static-hash-table` / `make cpp` static const struct CompactHashIndex bunObjectTableIndex[269] = { { 75, -1 }, { -1, -1 }, diff --git a/src/bun.js/bindings/BunPlugin.cpp b/src/bun.js/bindings/BunPlugin.cpp index 129d7816b..e0527c724 100644 --- a/src/bun.js/bindings/BunPlugin.cpp +++ b/src/bun.js/bindings/BunPlugin.cpp @@ -11,14 +11,17 @@ #include "JavaScriptCore/JSObjectInlines.h" #include "wtf/text/WTFString.h" #include "JavaScriptCore/JSCInlines.h" +#include "JavaScriptCore/StrongInlines.h" #include "JavaScriptCore/ObjectConstructor.h" #include "JavaScriptCore/SubspaceInlines.h" #include "JavaScriptCore/RegExpObject.h" #include "JavaScriptCore/JSPromise.h" #include "BunClientData.h" - +#include "isBuiltinModule.h" #include "JavaScriptCore/RegularExpression.h" +#include "JavaScriptCore/JSMap.h" +#include "JavaScriptCore/JSMapInlines.h" namespace Zig { @@ -86,6 +89,76 @@ static EncodedJSValue jsFunctionAppendOnLoadPluginBody(JSC::JSGlobalObject* glob return JSValue::encode(jsUndefined()); } +static EncodedJSValue jsFunctionAppendVirtualModulePluginBody(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callframe) +{ + JSC::VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (callframe->argumentCount() < 2) { + throwException(globalObject, scope, createError(globalObject, "module() needs 2 arguments: a module ID and a function to call"_s)); + return JSValue::encode(jsUndefined()); + } + + JSValue moduleIdValue = callframe->uncheckedArgument(0); + JSValue functionValue = callframe->uncheckedArgument(1); + + if (!moduleIdValue.isString()) { + throwException(globalObject, scope, createError(globalObject, "module() expects first argument to be a string for the module ID"_s)); + return JSValue::encode(jsUndefined()); + } + + if (!functionValue.isCallable()) { + throwException(globalObject, scope, createError(globalObject, "module() expects second argument to be a function"_s)); + return JSValue::encode(jsUndefined()); + } + + String moduleId = moduleIdValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + if (moduleId.isEmpty()) { + throwException(globalObject, scope, createError(globalObject, "virtual module cannot be blank"_s)); + return JSValue::encode(jsUndefined()); + } + + if (Bun::isBuiltinModule(moduleId)) { + throwException(globalObject, scope, createError(globalObject, makeString("module() cannot be used to override builtin module \""_s, moduleId, "\""_s))); + return JSValue::encode(jsUndefined()); + } + + if (moduleId.startsWith("."_s)) { + throwException(globalObject, scope, createError(globalObject, "virtual module cannot start with \".\""_s)); + return JSValue::encode(jsUndefined()); + } + + Zig::GlobalObject* global = Zig::jsCast<Zig::GlobalObject*>(globalObject); + if (global->onLoadPlugins.virtualModules == nullptr) { + global->onLoadPlugins.virtualModules = new BunPlugin::VirtualModuleMap; + } + auto* virtualModules = global->onLoadPlugins.virtualModules; + + virtualModules->set(moduleId, JSC::Strong<JSC::JSObject> { vm, jsCast<JSC::JSObject*>(functionValue) }); + + JSMap* esmRegistry; + + if (auto loaderValue = global->getIfPropertyExists(global, JSC::Identifier::fromString(vm, "Loader"_s))) { + if (auto registryValue = loaderValue.getObject()->getIfPropertyExists(global, JSC::Identifier::fromString(vm, "registry"_s))) { + esmRegistry = jsCast<JSC::JSMap*>(registryValue); + } + } + + global->requireMap()->remove(globalObject, moduleIdValue); + esmRegistry && esmRegistry->remove(globalObject, moduleIdValue); + + // bool hasBeenRequired = global->requireMap()->has(globalObject, moduleIdValue); + // bool hasBeenImported = esmRegistry && esmRegistry->has(globalObject, moduleIdValue); + // if (hasBeenRequired || hasBeenImported) { + // // callAndReplaceModule(global, moduleIdValue, functionValue, global->requireMap(), esmRegistry, hasBeenRequired, hasBeenImported); + // // RETURN_IF_EXCEPTION(scope, encodedJSValue()); + // } + + return JSValue::encode(jsUndefined()); +} + static EncodedJSValue jsFunctionAppendOnResolvePluginBody(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callframe, BunPluginTarget target, BunPlugin::Base& plugin, void* ctx, OnAppendPluginCallback callback) { JSC::VM& vm = globalObject->vm(); @@ -143,7 +216,7 @@ static EncodedJSValue jsFunctionAppendOnResolvePluginGlobal(JSC::JSGlobalObject* { Zig::GlobalObject* global = Zig::jsCast<Zig::GlobalObject*>(globalObject); - auto& plugins = global->onResolvePlugins[target]; + auto& plugins = global->onResolvePlugins; auto callback = Bun__onDidAppendPlugin; return jsFunctionAppendOnResolvePluginBody(globalObject, callframe, target, plugins, global->bunVM(), callback); } @@ -152,7 +225,7 @@ static EncodedJSValue jsFunctionAppendOnLoadPluginGlobal(JSC::JSGlobalObject* gl { Zig::GlobalObject* global = Zig::jsCast<Zig::GlobalObject*>(globalObject); - auto& plugins = global->onLoadPlugins[target]; + auto& plugins = global->onLoadPlugins; auto callback = Bun__onDidAppendPlugin; return jsFunctionAppendOnLoadPluginBody(globalObject, callframe, target, plugins, global->bunVM(), callback); } @@ -182,6 +255,11 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionAppendOnResolvePluginBun, (JSC::JSGlobalObjec return jsFunctionAppendOnResolvePluginGlobal(globalObject, callframe, BunPluginTargetBun); } +JSC_DEFINE_HOST_FUNCTION(jsFunctionAppendVirtualModule, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe)) +{ + return jsFunctionAppendVirtualModulePluginBody(globalObject, callframe); +} + JSC_DEFINE_HOST_FUNCTION(jsFunctionAppendOnResolvePluginBrowser, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe)) { return jsFunctionAppendOnResolvePluginGlobal(globalObject, callframe, BunPluginTargetBrowser); @@ -190,12 +268,12 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionAppendOnResolvePluginBrowser, (JSC::JSGlobalO extern "C" EncodedJSValue jsFunctionBunPluginClear(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callframe) { Zig::GlobalObject* global = reinterpret_cast<Zig::GlobalObject*>(globalObject); - for (uint8_t i = 0; i < BunPluginTargetMax + 1; i++) { - global->onLoadPlugins[i].fileNamespace.clear(); - global->onResolvePlugins[i].fileNamespace.clear(); - global->onLoadPlugins[i].groups.clear(); - global->onResolvePlugins[i].namespaces.clear(); - } + global->onLoadPlugins.fileNamespace.clear(); + global->onResolvePlugins.fileNamespace.clear(); + global->onLoadPlugins.groups.clear(); + global->onResolvePlugins.namespaces.clear(); + + delete global->onLoadPlugins.virtualModules; return JSValue::encode(jsUndefined()); } @@ -239,76 +317,37 @@ extern "C" EncodedJSValue setupBunPlugin(JSC::JSGlobalObject* globalObject, JSC: } JSFunction* setupFunction = jsCast<JSFunction*>(setupFunctionValue); - JSObject* builderObject = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 3); - - switch (target) { - case BunPluginTargetNode: { - builderObject->putDirect(vm, Identifier::fromString(vm, "target"_s), jsString(vm, String("node"_s)), 0); - builderObject->putDirectNativeFunction( - vm, - globalObject, - JSC::Identifier::fromString(vm, "onLoad"_s), - 1, - jsFunctionAppendOnLoadPluginNode, - ImplementationVisibility::Public, - NoIntrinsic, - JSC::PropertyAttribute::DontDelete | 0); - builderObject->putDirectNativeFunction( - vm, - globalObject, - JSC::Identifier::fromString(vm, "onResolve"_s), - 1, - jsFunctionAppendOnResolvePluginNode, - ImplementationVisibility::Public, - NoIntrinsic, - JSC::PropertyAttribute::DontDelete | 0); - break; - } - case BunPluginTargetBun: { - builderObject->putDirect(vm, Identifier::fromString(vm, "target"_s), jsString(vm, String("bun"_s)), 0); - builderObject->putDirectNativeFunction( - vm, - globalObject, - JSC::Identifier::fromString(vm, "onLoad"_s), - 1, - jsFunctionAppendOnLoadPluginBun, - ImplementationVisibility::Public, - NoIntrinsic, - JSC::PropertyAttribute::DontDelete | 0); - builderObject->putDirectNativeFunction( - vm, - globalObject, - JSC::Identifier::fromString(vm, "onResolve"_s), - 1, - jsFunctionAppendOnResolvePluginBun, - ImplementationVisibility::Public, - NoIntrinsic, - JSC::PropertyAttribute::DontDelete | 0); - break; - } - case BunPluginTargetBrowser: { - builderObject->putDirect(vm, Identifier::fromString(vm, "target"_s), jsString(vm, String("browser"_s)), 0); - builderObject->putDirectNativeFunction( - vm, - globalObject, - JSC::Identifier::fromString(vm, "onLoad"_s), - 1, - jsFunctionAppendOnLoadPluginBrowser, - ImplementationVisibility::Public, - NoIntrinsic, - JSC::PropertyAttribute::DontDelete | 0); - builderObject->putDirectNativeFunction( - vm, - globalObject, - JSC::Identifier::fromString(vm, "onResolve"_s), - 1, - jsFunctionAppendOnResolvePluginBrowser, - ImplementationVisibility::Public, - NoIntrinsic, - JSC::PropertyAttribute::DontDelete | 0); - break; - } - } + JSObject* builderObject = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 4); + + builderObject->putDirect(vm, Identifier::fromString(vm, "target"_s), jsString(vm, String("bun"_s)), 0); + builderObject->putDirectNativeFunction( + vm, + globalObject, + JSC::Identifier::fromString(vm, "onLoad"_s), + 1, + jsFunctionAppendOnLoadPluginBun, + ImplementationVisibility::Public, + NoIntrinsic, + JSC::PropertyAttribute::DontDelete | 0); + builderObject->putDirectNativeFunction( + vm, + globalObject, + JSC::Identifier::fromString(vm, "onResolve"_s), + 1, + jsFunctionAppendOnResolvePluginBun, + ImplementationVisibility::Public, + NoIntrinsic, + JSC::PropertyAttribute::DontDelete | 0); + + builderObject->putDirectNativeFunction( + vm, + globalObject, + JSC::Identifier::fromString(vm, "module"_s), + 1, + jsFunctionAppendVirtualModule, + ImplementationVisibility::Public, + NoIntrinsic, + JSC::PropertyAttribute::DontDelete | 0); JSC::MarkedArgumentBuffer args; args.append(builderObject); @@ -329,9 +368,7 @@ extern "C" EncodedJSValue setupBunPlugin(JSC::JSGlobalObject* globalObject, JSC: extern "C" EncodedJSValue jsFunctionBunPlugin(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callframe) { Zig::GlobalObject* global = reinterpret_cast<Zig::GlobalObject*>(globalObject); - BunPluginTarget target = global->defaultBunPluginTarget; - - return setupBunPlugin(globalObject, callframe, target); + return setupBunPlugin(globalObject, callframe, BunPluginTargetBun); } void BunPlugin::Group::append(JSC::VM& vm, JSC::RegExp* filter, JSC::JSFunction* func) @@ -513,10 +550,60 @@ EncodedJSValue BunPlugin::OnResolve::run(JSC::JSGlobalObject* globalObject, BunS extern "C" JSC::EncodedJSValue Bun__runOnResolvePlugins(Zig::GlobalObject* globalObject, BunString* namespaceString, BunString* path, BunString* from, BunPluginTarget target) { - return globalObject->onResolvePlugins[target].run(globalObject, namespaceString, path, from); + return globalObject->onResolvePlugins.run(globalObject, namespaceString, path, from); } extern "C" JSC::EncodedJSValue Bun__runOnLoadPlugins(Zig::GlobalObject* globalObject, BunString* namespaceString, BunString* path, BunPluginTarget target) { - return globalObject->onLoadPlugins[target].run(globalObject, namespaceString, path); + return globalObject->onLoadPlugins.run(globalObject, namespaceString, path); +} + +namespace Bun { +JSC::JSValue runVirtualModule(Zig::GlobalObject* globalObject, BunString* specifier) +{ + auto fallback = [&]() -> JSC::JSValue { + return JSValue::decode(Bun__runVirtualModule(globalObject, specifier)); + }; + + if (!globalObject->onLoadPlugins.virtualModules) { + return fallback(); + } + auto& virtualModules = *globalObject->onLoadPlugins.virtualModules; + WTF::String specifierString = Bun::toWTFString(*specifier); + if (auto virtualModuleFn = virtualModules.get(specifierString)) { + auto& vm = globalObject->vm(); + JSC::JSObject* function = virtualModuleFn.get(); + auto throwScope = DECLARE_THROW_SCOPE(vm); + + JSC::MarkedArgumentBuffer arguments; + JSC::CallData callData = JSC::getCallData(function); + RELEASE_ASSERT(callData.type != JSC::CallData::Type::None); + + auto result = call(globalObject, function, callData, JSC::jsUndefined(), arguments); + RETURN_IF_EXCEPTION(throwScope, JSC::jsUndefined()); + + if (auto* promise = JSC::jsDynamicCast<JSPromise*>(result)) { + switch (promise->status(vm)) { + case JSPromise::Status::Rejected: + case JSPromise::Status::Pending: { + return promise; + } + case JSPromise::Status::Fulfilled: { + result = promise->result(vm); + break; + } + } + } + + if (!result.isObject()) { + JSC::throwTypeError(globalObject, throwScope, "virtual module expects an object returned"_s); + return JSC::jsUndefined(); + } + + return result; + } + + return fallback(); } + +}
\ No newline at end of file diff --git a/src/bun.js/bindings/BunPlugin.h b/src/bun.js/bindings/BunPlugin.h index cf37b739b..f4d09883d 100644 --- a/src/bun.js/bindings/BunPlugin.h +++ b/src/bun.js/bindings/BunPlugin.h @@ -15,6 +15,8 @@ using namespace JSC; class BunPlugin { public: + using VirtualModuleMap = WTF::HashMap<String, JSC::Strong<JSC::JSObject>>; + // This is a list of pairs of regexps and functions to match against class Group { @@ -67,7 +69,15 @@ public: { } - EncodedJSValue run(JSC::JSGlobalObject* globalObject, BunString* namespaceString, BunString* path); + VirtualModuleMap* virtualModules = nullptr; + JSC::EncodedJSValue run(JSC::JSGlobalObject* globalObject, BunString* namespaceString, BunString* path); + + ~OnLoad() + { + if (virtualModules) { + delete virtualModules; + } + } }; class OnResolve final : public Base { @@ -78,8 +88,14 @@ public: { } - EncodedJSValue run(JSC::JSGlobalObject* globalObject, BunString* namespaceString, BunString* path, BunString* importer); + JSC::EncodedJSValue run(JSC::JSGlobalObject* globalObject, BunString* namespaceString, BunString* path, BunString* importer); }; }; -} // namespace Zig
\ No newline at end of file +class GlobalObject; + +} // namespace Zig + +namespace Bun { +JSC::JSValue runVirtualModule(Zig::GlobalObject*, BunString* specifier); +}
\ No newline at end of file diff --git a/src/bun.js/bindings/BunString.cpp b/src/bun.js/bindings/BunString.cpp index 416d5d334..99fd02175 100644 --- a/src/bun.js/bindings/BunString.cpp +++ b/src/bun.js/bindings/BunString.cpp @@ -3,12 +3,13 @@ #include "JavaScriptCore/JSCJSValueInlines.h" #include "helpers.h" #include "simdutf.h" -#include "wtf/text/ExternalStringImpl.h" +#include "wtf/Seconds.h" #include "GCDefferalContext.h" #include <JavaScriptCore/JSONObject.h> #include <wtf/text/AtomString.h> using namespace JSC; +extern "C" BunString BunString__fromBytes(const char* bytes, size_t length); extern "C" bool Bun__WTFStringImpl__hasPrefix(const WTF::StringImpl* impl, const char* bytes, size_t length) { @@ -74,7 +75,10 @@ JSC::JSValue toJS(JSC::JSGlobalObject* globalObject, BunString bunString, size_t #endif return jsSubstring(globalObject, jsUndefined(), Bun::toWTFString(bunString), 0, length); } - +BunString toString(const char* bytes, size_t length) +{ + return BunString__fromBytes(bytes, length); +} WTF::String toWTFString(const BunString& bunString) { if (bunString.tag == BunStringTag::ZigString) { @@ -190,22 +194,6 @@ BunString toStringRef(WTF::StringImpl* wtfString) return { BunStringTag::WTFStringImpl, { .wtf = wtfString } }; } -BunString fromString(WTF::String& wtfString) -{ - if (wtfString.isEmpty()) - return { BunStringTag::Empty }; - - return { BunStringTag::WTFStringImpl, { .wtf = wtfString.impl() } }; -} - -BunString fromString(WTF::StringImpl* wtfString) -{ - if (wtfString->isEmpty()) - return { BunStringTag::Empty }; - - return { BunStringTag::WTFStringImpl, { .wtf = wtfString } }; -} - } extern "C" JSC::EncodedJSValue BunString__toJS(JSC::JSGlobalObject* globalObject, BunString* bunString) @@ -252,7 +240,7 @@ extern "C" BunString BunString__fromUTF8(const char* bytes, size_t length) auto str = WTF::String::fromUTF8ReplacingInvalidSequences(reinterpret_cast<const LChar*>(bytes), length); str.impl()->ref(); - return Bun::fromString(str); + return Bun::toString(str); } extern "C" BunString BunString__fromLatin1(const char* bytes, size_t length) @@ -381,7 +369,17 @@ extern "C" BunString URL__getHref(BunString* input) return Bun::toStringRef(url.string()); } -extern "C" BunString URL__getHrefJoin(BunString* baseStr, BunString *relativeStr) +extern "C" BunString URL__pathFromFileURL(BunString* input) +{ + auto&& str = Bun::toWTFString(*input); + auto url = WTF::URL(str); + if (!url.isValid() || url.isEmpty()) + return { BunStringTag::Dead }; + + return Bun::toStringRef(url.fileSystemPath()); +} + +extern "C" BunString URL__getHrefJoin(BunString* baseStr, BunString* relativeStr) { auto base = Bun::toWTFString(*baseStr); auto relative = Bun::toWTFString(*relativeStr); @@ -455,4 +453,4 @@ extern "C" uint32_t URL__port(WTF::URL* url) extern "C" BunString URL__pathname(WTF::URL* url) { return Bun::toStringRef(url->path().toStringWithoutCopying()); -}
\ No newline at end of file +} diff --git a/src/bun.js/bindings/CallSite.cpp b/src/bun.js/bindings/CallSite.cpp index 48fe82275..7667d9606 100644 --- a/src/bun.js/bindings/CallSite.cpp +++ b/src/bun.js/bindings/CallSite.cpp @@ -45,7 +45,7 @@ void CallSite::finishCreation(VM& vm, JSC::JSGlobalObject* globalObject, JSCStac m_function.set(vm, this, JSC::jsUndefined()); m_flags |= static_cast<unsigned int>(Flags::IsStrict); } else { - if (callFrame) { + if (callFrame && callFrame->thisValue()) { // We know that we're not in strict mode m_thisValue.set(vm, this, callFrame->thisValue().toThis(globalObject, JSC::ECMAMode::sloppy())); } else { diff --git a/src/bun.js/bindings/CallSitePrototype.h b/src/bun.js/bindings/CallSitePrototype.h index 000bce2de..8aa543fd3 100644 --- a/src/bun.js/bindings/CallSitePrototype.h +++ b/src/bun.js/bindings/CallSitePrototype.h @@ -26,6 +26,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(CallSitePrototype, Base); return &vm.plainObjectSpace(); } diff --git a/src/bun.js/bindings/CommonJSModuleRecord.cpp b/src/bun.js/bindings/CommonJSModuleRecord.cpp index b94386ab3..f47c57559 100644 --- a/src/bun.js/bindings/CommonJSModuleRecord.cpp +++ b/src/bun.js/bindings/CommonJSModuleRecord.cpp @@ -8,7 +8,7 @@ * Then, at runtime, we create a JSCommonJSModule object. * * On this special object, we override the setter for the "exports" property in - * a non-observable way (`static bool put ...`) + * a non-observable way using a CustomGetterSetter. * * When the setter is called, we set the internal "exports" property to the * value passed in and we also update the requireMap with the new value. @@ -20,17 +20,13 @@ * * If an exception occurs, we remove the entry from the requireMap. * - * We tried using a CustomGetterSetter instead of overriding `put`, but it led - * to returning the getter itself - * - * How cyclical dependencies are handled + * How cyclical dependencies are handled: * * Before executing the CommonJS module, we set the exports object in the * requireMap to an empty object. When the CommonJS module is required again, we * return the exports object from the requireMap. The values should be in sync * while the module is being executed, unless module.exports is re-assigned to a * different value. In that case, it will have a stale value. - * */ #include "root.h" @@ -71,6 +67,8 @@ #include <JavaScriptCore/JSSourceCode.h> #include <JavaScriptCore/LazyPropertyInlines.h> +extern "C" bool Bun__isBunMain(JSC::JSGlobalObject* global, const char* input_ptr, uint64_t input_len); + namespace Bun { using namespace JSC; @@ -96,28 +94,36 @@ static bool canPerformFastEnumeration(Structure* s) static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObject, JSCommonJSModule* moduleObject, JSString* dirname, JSValue filename, WTF::NakedPtr<Exception>& exception) { JSC::Structure* thisObjectStructure = globalObject->commonJSFunctionArgumentsStructure(); - JSC::JSObject* thisObject = JSC::constructEmptyObject( - vm, - thisObjectStructure); - thisObject->putDirectOffset( - vm, - 0, - moduleObject); - thisObject->putDirectOffset( - vm, - 1, - dirname); + JSFunction* resolveFunction = JSC::JSBoundFunction::create(vm, + globalObject, + globalObject->requireResolveFunctionUnbound(), + moduleObject->id(), + ArgList(), 1, jsString(vm, String("resolve"_s))); + JSFunction* requireFunction = JSC::JSBoundFunction::create(vm, + globalObject, + globalObject->requireFunctionUnbound(), + moduleObject, + ArgList(), 1, jsString(vm, String("require"_s))); + requireFunction->putDirect(vm, vm.propertyNames->resolve, resolveFunction, 0); + moduleObject->putDirect(vm, WebCore::clientData(vm)->builtinNames().requirePublicName(), requireFunction, 0); - thisObject->putDirectOffset( - vm, - 2, - filename); + JSC::JSObject* thisObject = JSC::constructEmptyObject(vm, thisObjectStructure); + thisObject->putDirectOffset(vm, 0, moduleObject); + thisObject->putDirectOffset(vm, 1, requireFunction); + thisObject->putDirectOffset(vm, 2, resolveFunction); + thisObject->putDirectOffset(vm, 3, dirname); + thisObject->putDirectOffset(vm, 4, filename); moduleObject->hasEvaluated = true; + // TODO: try to not use this write barrier. it needs some extensive testing. + // there is some possible GC issue where `thisObject` is gc'd before it should be globalObject->m_BunCommonJSModuleValue.set(vm, globalObject, thisObject); JSValue empty = JSC::evaluate(globalObject, moduleObject->sourceCode.get()->sourceCode(), thisObject, exception); + + ensureStillAliveHere(thisObject); + globalObject->m_BunCommonJSModuleValue.clear(); moduleObject->sourceCode.clear(); return exception.get() == nullptr; @@ -190,11 +196,25 @@ static const HashTableValue RequireFunctionPrototypeValues[] = { { "cache"_s, static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsRequireCacheGetter, jsRequireCacheSetter } }, }; +Structure* RequireFunctionPrototype::createStructure( + JSC::VM& vm, + JSC::JSGlobalObject* globalObject) +{ + return Structure::create(vm, globalObject, globalObject->functionPrototype(), TypeInfo(JSFunctionType, StructureFlags), info()); +} + +Structure* RequireResolveFunctionPrototype::createStructure( + JSC::VM& vm, + JSC::JSGlobalObject* globalObject) +{ + return Structure::create(vm, globalObject, globalObject->functionPrototype(), TypeInfo(JSFunctionType, StructureFlags), info()); +} + RequireResolveFunctionPrototype* RequireResolveFunctionPrototype::create(JSC::JSGlobalObject* globalObject) { auto& vm = globalObject->vm(); - auto* structure = RequireResolveFunctionPrototype::createStructure(vm, globalObject, globalObject->functionPrototype()); + auto* structure = RequireResolveFunctionPrototype::createStructure(vm, globalObject); RequireResolveFunctionPrototype* prototype = new (NotNull, JSC::allocateCell<RequireResolveFunctionPrototype>(vm)) RequireResolveFunctionPrototype(vm, structure); prototype->finishCreation(vm); return prototype; @@ -205,11 +225,11 @@ RequireFunctionPrototype* RequireFunctionPrototype::create( { auto& vm = globalObject->vm(); - auto* structure = RequireFunctionPrototype::createStructure(vm, globalObject, globalObject->functionPrototype()); + auto* structure = RequireFunctionPrototype::createStructure(vm, globalObject); RequireFunctionPrototype* prototype = new (NotNull, JSC::allocateCell<RequireFunctionPrototype>(vm)) RequireFunctionPrototype(vm, structure); prototype->finishCreation(vm); - prototype->putDirect(vm, JSC::Identifier::fromString(vm, "resolve"_s), static_cast<Zig::GlobalObject*>(globalObject)->requireResolveFunctionUnbound(), PropertyAttribute::Function | 0); + prototype->putDirect(vm, JSC::Identifier::fromString(vm, "resolve"_s), jsCast<Zig::GlobalObject*>(globalObject)->requireResolveFunctionUnbound(), 0); return prototype; } @@ -217,7 +237,7 @@ RequireFunctionPrototype* RequireFunctionPrototype::create( void RequireFunctionPrototype::finishCreation(JSC::VM& vm) { Base::finishCreation(vm); - ASSERT(inherits(vm, info())); + ASSERT(inherits(info())); reifyStaticProperties(vm, info(), RequireFunctionPrototypeValues, *this); JSC::JSFunction* requireDotMainFunction = JSFunction::create( @@ -225,11 +245,11 @@ void RequireFunctionPrototype::finishCreation(JSC::VM& vm) moduleMainCodeGenerator(vm), globalObject()->globalScope()); - this->putDirect( - vm, + this->putDirectAccessor( + globalObject(), JSC::Identifier::fromString(vm, "main"_s), - JSC::GetterSetter::create(vm, globalObject(), requireDotMainFunction, JSValue()), - PropertyAttribute::Builtin | PropertyAttribute::Accessor | PropertyAttribute::ReadOnly | 0); + JSC::GetterSetter::create(vm, globalObject(), requireDotMainFunction, requireDotMainFunction), + PropertyAttribute::Accessor | PropertyAttribute::ReadOnly | 0); auto extensions = constructEmptyObject(globalObject()); extensions->putDirect(vm, JSC::Identifier::fromString(vm, ".js"_s), jsBoolean(true), 0); @@ -265,6 +285,31 @@ JSC_DEFINE_CUSTOM_GETTER(getterPath, (JSC::JSGlobalObject * globalObject, JSC::E return JSValue::encode(thisObject->m_id.get()); } +JSC_DEFINE_CUSTOM_GETTER(getterParent, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue)); + if (UNLIKELY(!thisObject)) { + return JSValue::encode(jsUndefined()); + } + auto v = thisObject->m_parent.get(); + if (v) + return JSValue::encode(thisObject->m_parent.get()); + + // initialize parent by checking if it is the main module. we do this lazily because most people + // dont need `module.parent` and creating commonjs module records is done a ton. + auto idValue = thisObject->m_id.get(); + if (idValue) { + auto id = idValue->value(globalObject).utf8(); + if (Bun__isBunMain(globalObject, id.data(), id.length())) { + thisObject->m_parent.set(globalObject->vm(), thisObject, jsNull()); + return JSValue::encode(jsNull()); + } + } + + thisObject->m_parent.set(globalObject->vm(), thisObject, jsUndefined()); + return JSValue::encode(jsUndefined()); +} + JSC_DEFINE_CUSTOM_SETTER(setterPath, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue value, JSC::PropertyName propertyName)) @@ -294,6 +339,16 @@ JSC_DEFINE_CUSTOM_GETTER(getterPaths, (JSC::JSGlobalObject * globalObject, JSC:: return JSValue::encode(thisObject->m_paths.get()); } +JSC_DEFINE_CUSTOM_GETTER(getterLoaded, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue)); + if (UNLIKELY(!thisObject)) { + return JSValue::encode(jsUndefined()); + } + + return JSValue::encode(jsBoolean(thisObject->hasEvaluated)); +} + JSC_DEFINE_CUSTOM_SETTER(setterPaths, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue value, JSC::PropertyName propertyName)) @@ -329,27 +384,100 @@ JSC_DEFINE_CUSTOM_SETTER(setterId, thisObject->m_id.set(globalObject->vm(), thisObject, JSValue::decode(value).toString(globalObject)); return true; } - -static JSValue createLoaded(VM& vm, JSObject* object) +JSC_DEFINE_CUSTOM_SETTER(setterParent, + (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, + JSC::EncodedJSValue value, JSC::PropertyName propertyName)) { - JSCommonJSModule* cjs = jsCast<JSCommonJSModule*>(object); - return jsBoolean(cjs->hasEvaluated); + JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue)); + if (!thisObject) + return false; + + thisObject->m_parent.set(globalObject->vm(), thisObject, JSValue::decode(value)); + + return true; } -static JSValue createParent(VM& vm, JSObject* object) +JSC_DEFINE_CUSTOM_SETTER(setterLoaded, + (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, + JSC::EncodedJSValue value, JSC::PropertyName propertyName)) { - return jsUndefined(); + JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue)); + if (!thisObject) + return false; + + thisObject->hasEvaluated = JSValue::decode(value).toBoolean(globalObject); + + return true; } + static JSValue createChildren(VM& vm, JSObject* object) { return constructEmptyArray(object->globalObject(), nullptr, 0); } +JSC_DEFINE_HOST_FUNCTION(functionCommonJSModuleRecord_compile, (JSGlobalObject * globalObject, CallFrame* callframe)) +{ + auto* moduleObject = jsDynamicCast<JSCommonJSModule*>(callframe->thisValue()); + if (!moduleObject) { + return JSValue::encode(jsUndefined()); + } + + auto& vm = globalObject->vm(); + auto throwScope = DECLARE_THROW_SCOPE(vm); + + String sourceString = callframe->argument(0).toWTFString(globalObject); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode({})); + + String filenameString = callframe->argument(1).toWTFString(globalObject); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode({})); + + String wrappedString = makeString( + "(function(exports,require,module,__filename,__dirname){"_s, + sourceString, + "\n}).call(this.module.exports,this.module.exports,this.require,this.module,this.__filename,this.__dirname)"_s); + + SourceCode sourceCode = makeSource( + WTFMove(wrappedString), + SourceOrigin(URL::fileURLWithFileSystemPath(filenameString)), + JSC::SourceTaintedOrigin::Untainted, + filenameString, + WTF::TextPosition(), + JSC::SourceProviderSourceType::Program); + JSSourceCode* jsSourceCode = JSSourceCode::create(vm, WTFMove(sourceCode)); + moduleObject->sourceCode.set(vm, moduleObject, jsSourceCode); + + auto index = filenameString.reverseFind('/', filenameString.length()); + String dirnameString; + if (index != WTF::notFound) { + dirnameString = filenameString.substring(0, index); + } else { + dirnameString = "/"_s; + } + + WTF::NakedPtr<JSC::Exception> exception; + evaluateCommonJSModuleOnce( + vm, + jsCast<Zig::GlobalObject*>(globalObject), + moduleObject, + jsString(vm, dirnameString), + jsString(vm, filenameString), + exception); + + if (exception) { + throwException(globalObject, throwScope, exception.get()); + exception.clear(); + return JSValue::encode({}); + } + + return JSValue::encode(jsUndefined()); +} + static const struct HashTableValue JSCommonJSModulePrototypeTableValues[] = { - { "children"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback | PropertyAttribute::DontEnum | 0), NoIntrinsic, { HashTableValue::LazyPropertyType, createChildren } }, + { "_compile"_s, static_cast<unsigned>(PropertyAttribute::Function | PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::NativeFunctionType, functionCommonJSModuleRecord_compile, 2 } }, + { "children"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, createChildren } }, { "filename"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterFilename, setterFilename } }, { "id"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterId, setterId } }, - { "loaded"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback | PropertyAttribute::DontEnum | 0), NoIntrinsic, { HashTableValue::LazyPropertyType, createLoaded } }, - { "parent"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback | PropertyAttribute::DontEnum | 0), NoIntrinsic, { HashTableValue::LazyPropertyType, createParent } }, + { "loaded"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterLoaded, setterLoaded } }, + { "parent"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor | PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, getterParent, setterParent } }, { "path"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterPath, setterPath } }, { "paths"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterPaths, setterPaths } }, }; @@ -367,6 +495,14 @@ public: return prototype; } + static JSC::Structure* createStructure( + JSC::VM& vm, + JSC::JSGlobalObject* globalObject, + JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, TypeInfo(JSC::ObjectType, StructureFlags), info()); + } + DECLARE_INFO; JSCommonJSModulePrototype( @@ -379,36 +515,36 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSCommonJSModulePrototype, Base); return &vm.plainObjectSpace(); } void finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject) { Base::finishCreation(vm); - ASSERT(inherits(vm, info())); - reifyStaticProperties(vm, JSCommonJSModule::info(), JSCommonJSModulePrototypeTableValues, *this); - - this->putDirect(vm, clientData(vm)->builtinNames().requirePublicName(), (static_cast<Zig::GlobalObject*>(globalObject))->requireFunctionUnbound(), PropertyAttribute::Builtin | PropertyAttribute::Function | 0); + ASSERT(inherits(info())); + reifyStaticProperties(vm, info(), JSCommonJSModulePrototypeTableValues, *this); this->putDirectNativeFunction( vm, globalObject, clientData(vm)->builtinNames().requirePrivateName(), 2, - jsFunctionRequireCommonJS, ImplementationVisibility::Public, NoIntrinsic, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | 0); + jsFunctionRequireCommonJS, ImplementationVisibility::Public, NoIntrinsic, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete); } }; -const JSC::ClassInfo JSCommonJSModulePrototype::s_info = { "Module"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSCommonJSModulePrototype) }; +const JSC::ClassInfo JSCommonJSModulePrototype::s_info = { "ModulePrototype"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSCommonJSModulePrototype) }; void JSCommonJSModule::finishCreation(JSC::VM& vm, JSC::JSString* id, JSValue filename, JSC::JSString* dirname, JSC::JSSourceCode* sourceCode) { Base::finishCreation(vm); - ASSERT(inherits(vm, info())); + ASSERT(inherits(info())); m_id.set(vm, this, id); m_filename.set(vm, this, filename); m_dirname.set(vm, this, dirname); - this->sourceCode.set(vm, this, sourceCode); + if (sourceCode) + this->sourceCode.set(vm, this, sourceCode); } JSC::Structure* JSCommonJSModule::createStructure( @@ -439,23 +575,23 @@ JSCommonJSModule* JSCommonJSModule::create( JSC_DEFINE_HOST_FUNCTION(jsFunctionCreateCommonJSModule, (JSGlobalObject * globalObject, CallFrame* callframe)) { auto& vm = globalObject->vm(); + RELEASE_ASSERT(callframe->argumentCount() == 4); - auto id = callframe->argument(0).toWTFString(globalObject); + auto id = callframe->uncheckedArgument(0).toWTFString(globalObject); + JSValue object = callframe->uncheckedArgument(1); + JSValue hasEvaluated = callframe->uncheckedArgument(2); + ASSERT(hasEvaluated.isBoolean()); + JSValue parent = callframe->uncheckedArgument(3); - JSValue object = callframe->argument(1); - - return JSValue::encode( - JSCommonJSModule::create( - jsCast<Zig::GlobalObject*>(globalObject), - id, - object, callframe->argument(2).isBoolean() && callframe->argument(2).asBoolean())); + return JSValue::encode(JSCommonJSModule::create(jsCast<Zig::GlobalObject*>(globalObject), id, object, hasEvaluated.isTrue(), parent)); } JSCommonJSModule* JSCommonJSModule::create( Zig::GlobalObject* globalObject, const WTF::String& key, JSValue exportsObject, - bool hasEvaluated) + bool hasEvaluated, + JSValue parent) { auto& vm = globalObject->vm(); JSString* requireMapKey = JSC::jsStringWithCache(vm, key); @@ -470,8 +606,14 @@ JSCommonJSModule* JSCommonJSModule::create( globalObject->CommonJSModuleObjectStructure(), requireMapKey, requireMapKey, dirname, nullptr); - out->putDirect(vm, WebCore::clientData(vm)->builtinNames().exportsPublicName(), exportsObject, exportsObject.isCell() && exportsObject.isCallable() ? JSC::PropertyAttribute::Function | 0 : 0); + out->putDirect( + vm, + WebCore::clientData(vm)->builtinNames().exportsPublicName(), + exportsObject, + 0); out->hasEvaluated = hasEvaluated; + out->m_parent.set(vm, out, parent); + return out; } @@ -543,7 +685,7 @@ void JSCommonJSModule::toSyntheticSource(JSC::JSGlobalObject* globalObject, bool needsToAssignDefault = true; if (result.isObject()) { - auto* exports = asObject(result); + auto* exports = result.getObject(); auto* structure = exports->structure(); uint32_t size = structure->inlineSize() + structure->outOfLineSize(); @@ -673,33 +815,6 @@ JSValue JSCommonJSModule::id() return m_id.get(); } -bool JSCommonJSModule::put( - JSC::JSCell* cell, - JSC::JSGlobalObject* globalObject, - JSC::PropertyName propertyName, - JSC::JSValue value, - JSC::PutPropertySlot& slot) -{ - - auto& vm = globalObject->vm(); - auto* clientData = WebCore::clientData(vm); - auto throwScope = DECLARE_THROW_SCOPE(vm); - - RELEASE_AND_RETURN(throwScope, Base::put(cell, globalObject, propertyName, value, slot)); -} - -template<typename, SubspaceAccess mode> JSC::GCClient::IsoSubspace* JSCommonJSModule::subspaceFor(JSC::VM& vm) -{ - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return WebCore::subspaceForImpl<JSCommonJSModule, WebCore::UseCustomHeapCellType::No>( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForCommonJSModuleRecord.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForCommonJSModuleRecord = std::forward<decltype(space)>(space); }, - [](auto& spaces) { return spaces.m_subspaceForCommonJSModuleRecord.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForCommonJSModuleRecord = std::forward<decltype(space)>(space); }); -} - Structure* createCommonJSModuleStructure( Zig::GlobalObject* globalObject) { @@ -740,7 +855,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireCommonJS, (JSGlobalObject * lexicalGlo // Special-case for "process" to just return the process object directly. if (UNLIKELY(specifier == "process"_s || specifier == "node:process"_s)) { - jsDynamicCast<JSCommonJSModule*>(callframe->argument(1))->putDirect(vm, builtinNames(vm).exportsPublicName(), globalObject->processObject(), 0); + jsCast<JSCommonJSModule*>(callframe->argument(1))->putDirect(vm, builtinNames(vm).exportsPublicName(), globalObject->processObject(), 0); return JSValue::encode(globalObject->processObject()); } @@ -752,7 +867,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireCommonJS, (JSGlobalObject * lexicalGlo JSValue fetchResult = Bun::fetchCommonJSModule( globalObject, - jsDynamicCast<JSCommonJSModule*>(callframe->argument(1)), + jsCast<JSCommonJSModule*>(callframe->argument(1)), specifierValue, &specifierStr, &referrerStr); @@ -763,9 +878,9 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireCommonJS, (JSGlobalObject * lexicalGlo void RequireResolveFunctionPrototype::finishCreation(JSC::VM& vm) { Base::finishCreation(vm); - ASSERT(inherits(vm, info())); + ASSERT(inherits(info())); - reifyStaticProperties(vm, RequireResolveFunctionPrototype::info(), RequireResolveFunctionPrototypeValues, *this); + reifyStaticProperties(vm, info(), RequireResolveFunctionPrototypeValues, *this); JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); } @@ -909,8 +1024,6 @@ JSObject* JSCommonJSModule::createBoundRequireFunction(VM& vm, JSGlobalObject* l globalObject->CommonJSModuleObjectStructure(), filename, filename, dirname, nullptr); - auto& builtinNames = WebCore::builtinNames(vm); - JSFunction* requireFunction = JSC::JSBoundFunction::create(vm, globalObject, globalObject->requireFunctionUnbound(), @@ -921,9 +1034,9 @@ JSObject* JSCommonJSModule::createBoundRequireFunction(VM& vm, JSGlobalObject* l globalObject, globalObject->requireResolveFunctionUnbound(), moduleObject, - ArgList(), 1, jsString(vm, String("require"_s))); + ArgList(), 1, jsString(vm, String("resolve"_s))); - requireFunction->putDirect(vm, builtinNames.resolvePublicName(), resolveFunction, PropertyAttribute::Function | 0); + requireFunction->putDirect(vm, vm.propertyNames->resolve, resolveFunction, 0); return requireFunction; } diff --git a/src/bun.js/bindings/CommonJSModuleRecord.h b/src/bun.js/bindings/CommonJSModuleRecord.h index e38d2e083..37353978e 100644 --- a/src/bun.js/bindings/CommonJSModuleRecord.h +++ b/src/bun.js/bindings/CommonJSModuleRecord.h @@ -20,13 +20,14 @@ JSC_DECLARE_HOST_FUNCTION(jsFunctionLoadModule); class JSCommonJSModule final : public JSC::JSDestructibleObject { public: using Base = JSC::JSDestructibleObject; - static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::OverridesPut; + static constexpr unsigned StructureFlags = Base::StructureFlags; - mutable JSC::WriteBarrier<JSC::JSString> m_id; - mutable JSC::WriteBarrier<JSC::Unknown> m_filename; - mutable JSC::WriteBarrier<JSC::JSString> m_dirname; + mutable JSC::WriteBarrier<JSString> m_id; + mutable JSC::WriteBarrier<Unknown> m_filename; + mutable JSC::WriteBarrier<JSString> m_dirname; mutable JSC::WriteBarrier<Unknown> m_paths; - mutable JSC::WriteBarrier<JSC::JSSourceCode> sourceCode; + mutable JSC::WriteBarrier<Unknown> m_parent; + mutable JSC::WriteBarrier<JSSourceCode> sourceCode; bool ignoreESModuleAnnotation { false }; static void destroy(JSC::JSCell*); @@ -54,8 +55,7 @@ public: static JSCommonJSModule* create( Zig::GlobalObject* globalObject, const WTF::String& key, - JSValue exportsObject, - bool hasEvaluated = false); + JSValue exportsObject, bool hasEvaluated, JSValue parent); static JSCommonJSModule* create( Zig::GlobalObject* globalObject, @@ -72,15 +72,21 @@ public: JSValue exportsObject(); JSValue id(); + DECLARE_INFO; DECLARE_VISIT_CHILDREN; - static bool put(JSC::JSCell* cell, JSC::JSGlobalObject* globalObject, - JSC::PropertyName propertyName, JSC::JSValue value, - JSC::PutPropertySlot& slot); - - DECLARE_INFO; template<typename, SubspaceAccess mode> - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm); + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + return WebCore::subspaceForImpl<JSCommonJSModule, WebCore::UseCustomHeapCellType::No>( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForCommonJSModuleRecord.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForCommonJSModuleRecord = std::forward<decltype(space)>(space); }, + [](auto& spaces) { return spaces.m_subspaceForCommonJSModuleRecord.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForCommonJSModuleRecord = std::forward<decltype(space)>(space); }); + } bool hasEvaluated = false; @@ -114,7 +120,9 @@ inline std::optional<JSC::SourceCode> createCommonJSModule( class RequireResolveFunctionPrototype final : public JSC::JSNonFinalObject { public: using Base = JSC::JSNonFinalObject; + static RequireResolveFunctionPrototype* create(JSC::JSGlobalObject* globalObject); + static Structure* createStructure(VM& vm, JSC::JSGlobalObject* globalObject); DECLARE_INFO; @@ -128,6 +136,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(RequireResolveFunctionPrototype, Base); return &vm.plainObjectSpace(); } @@ -137,7 +146,11 @@ public: class RequireFunctionPrototype final : public JSC::JSNonFinalObject { public: using Base = JSC::JSNonFinalObject; + static RequireFunctionPrototype* create(JSC::JSGlobalObject* globalObject); + static Structure* createStructure(VM& vm, JSC::JSGlobalObject* globalObject); + + DECLARE_INFO; RequireFunctionPrototype( JSC::VM& vm, @@ -149,12 +162,11 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(RequireFunctionPrototype, Base); return &vm.plainObjectSpace(); } - DECLARE_INFO; - - void finishCreation(JSC::VM& vm); + void finishCreation(JSC::VM&); }; } // namespace Bun diff --git a/src/bun.js/bindings/DOMURL.cpp b/src/bun.js/bindings/DOMURL.cpp index 31381b867..b88161a4d 100644 --- a/src/bun.js/bindings/DOMURL.cpp +++ b/src/bun.js/bindings/DOMURL.cpp @@ -36,26 +36,45 @@ namespace WebCore { +static inline String redact(const String& input) +{ + if (input.contains("@"_s)) + return "<redacted>"_s; + + return makeString('"', input, '"'); +} + inline DOMURL::DOMURL(URL&& completeURL, const URL& baseURL) : m_baseURL(baseURL) , m_url(WTFMove(completeURL)) { } +DOMURL::~DOMURL() = default; + +bool DOMURL::canParse(const String& url, const String& base) +{ + URL baseURL { base }; + if (!base.isNull() && !baseURL.isValid()) + return false; + URL completeURL { baseURL, url }; + return completeURL.isValid(); +} + ExceptionOr<Ref<DOMURL>> DOMURL::create(const String& url, const URL& base) { ASSERT(base.isValid() || base.isNull()); URL completeURL { base, url }; if (!completeURL.isValid()) - return Exception { TypeError }; + return Exception { TypeError, makeString(redact(url), " cannot be parsed as a URL.") }; return adoptRef(*new DOMURL(WTFMove(completeURL), base)); } ExceptionOr<Ref<DOMURL>> DOMURL::create(const String& url, const String& base) { - URL baseURL { URL {}, base }; + URL baseURL { base }; if (!base.isNull() && !baseURL.isValid()) - return Exception { TypeError }; + return Exception { TypeError, makeString(redact(url), " cannot be parsed as a URL against "_s, redact(base)) }; return create(url, baseURL); } @@ -64,13 +83,13 @@ ExceptionOr<Ref<DOMURL>> DOMURL::create(const String& url, const DOMURL& base) return create(url, base.href()); } -DOMURL::~DOMURL() = default; - ExceptionOr<void> DOMURL::setHref(const String& url) { URL completeURL { URL {}, url }; - if (!completeURL.isValid()) - return Exception { TypeError }; + if (!completeURL.isValid()) { + + return Exception { TypeError, makeString(redact(url), " cannot be parsed as a URL.") }; + } m_url = WTFMove(completeURL); if (m_searchParams) m_searchParams->updateFromAssociatedURL(); diff --git a/src/bun.js/bindings/DOMURL.h b/src/bun.js/bindings/DOMURL.h index 0a6210690..0f19510b6 100644 --- a/src/bun.js/bindings/DOMURL.h +++ b/src/bun.js/bindings/DOMURL.h @@ -43,6 +43,7 @@ public: static ExceptionOr<Ref<DOMURL>> create(const String& url, const DOMURL& base); ~DOMURL(); + static bool canParse(const String& url, const String& base); const URL& href() const { return m_url; } ExceptionOr<void> setHref(const String&); void setQuery(const String&); diff --git a/src/bun.js/bindings/ErrorStackTrace.cpp b/src/bun.js/bindings/ErrorStackTrace.cpp index a8c5b65d8..f7013c9c4 100644 --- a/src/bun.js/bindings/ErrorStackTrace.cpp +++ b/src/bun.js/bindings/ErrorStackTrace.cpp @@ -12,6 +12,7 @@ #include <JavaScriptCore/JSCInlines.h> #include <JavaScriptCore/ErrorInstance.h> #include <JavaScriptCore/StackVisitor.h> +#include <JavaScriptCore/NativeCallee.h> #include <wtf/IterationStatus.h> using namespace JSC; @@ -130,8 +131,8 @@ JSCStackFrame::JSCStackFrame(JSC::VM& vm, JSC::StackVisitor& visitor) : m_vm(vm) , m_codeBlock(nullptr) , m_bytecodeIndex(JSC::BytecodeIndex()) - , m_sourceURL(nullptr) - , m_functionName(nullptr) + , m_sourceURL() + , m_functionName() , m_isWasmFrame(false) , m_sourcePositionsState(SourcePositionsState::NotCalculated) { @@ -139,9 +140,18 @@ JSCStackFrame::JSCStackFrame(JSC::VM& vm, JSC::StackVisitor& visitor) m_callFrame = visitor->callFrame(); // Based on JSC's GetStackTraceFunctor (Interpreter.cpp) - if (visitor->isWasmFrame()) { - m_wasmFunctionIndexOrName = visitor->wasmFunctionIndexOrName(); - m_isWasmFrame = true; + if (visitor->isNativeCalleeFrame()) { + auto* nativeCallee = visitor->callee().asNativeCallee(); + switch (nativeCallee->category()) { + case NativeCallee::Category::Wasm: { + m_wasmFunctionIndexOrName = visitor->wasmFunctionIndexOrName(); + m_isWasmFrame = true; + break; + } + case NativeCallee::Category::InlineCache: { + break; + } + } } else if (!!visitor->codeBlock() && !visitor->codeBlock()->unlinkedCodeBlock()->isBuiltinFunction()) { m_codeBlock = visitor->codeBlock(); m_bytecodeIndex = visitor->bytecodeIndex(); @@ -153,8 +163,8 @@ JSCStackFrame::JSCStackFrame(JSC::VM& vm, const JSC::StackFrame& frame) , m_callFrame(nullptr) , m_codeBlock(nullptr) , m_bytecodeIndex(JSC::BytecodeIndex()) - , m_sourceURL(nullptr) - , m_functionName(nullptr) + , m_sourceURL() + , m_functionName() , m_isWasmFrame(false) , m_sourcePositionsState(SourcePositionsState::NotCalculated) { @@ -183,7 +193,7 @@ JSC::JSString* JSCStackFrame::sourceURL() m_sourceURL = retrieveSourceURL(); } - return m_sourceURL; + return jsString(this->m_vm, m_sourceURL); } JSC::JSString* JSCStackFrame::functionName() @@ -192,7 +202,7 @@ JSC::JSString* JSCStackFrame::functionName() m_functionName = retrieveFunctionName(); } - return m_functionName; + return jsString(this->m_vm, m_functionName); } JSC::JSString* JSCStackFrame::typeName() @@ -201,7 +211,7 @@ JSC::JSString* JSCStackFrame::typeName() m_typeName = retrieveTypeName(); } - return m_typeName; + return jsString(this->m_vm, m_typeName); } JSCStackFrame::SourcePositions* JSCStackFrame::getSourcePositions() @@ -213,91 +223,61 @@ JSCStackFrame::SourcePositions* JSCStackFrame::getSourcePositions() return (SourcePositionsState::Calculated == m_sourcePositionsState) ? &m_sourcePositions : nullptr; } -ALWAYS_INLINE JSC::JSString* JSCStackFrame::retrieveSourceURL() +ALWAYS_INLINE String JSCStackFrame::retrieveSourceURL() { static auto sourceURLWasmString = MAKE_STATIC_STRING_IMPL("[wasm code]"); static auto sourceURLNativeString = MAKE_STATIC_STRING_IMPL("[native code]"); if (m_isWasmFrame) { - return jsOwnedString(m_vm, sourceURLWasmString); + return String(sourceURLWasmString); } if (!m_codeBlock) { - return jsOwnedString(m_vm, sourceURLNativeString); + return String(sourceURLNativeString); } - String sourceURL = m_codeBlock->ownerExecutable()->sourceURL(); - return sourceURL.isNull() ? m_vm.smallStrings.emptyString() : JSC::jsString(m_vm, sourceURL); + return m_codeBlock->ownerExecutable()->sourceURL(); } -ALWAYS_INLINE JSC::JSString* JSCStackFrame::retrieveFunctionName() +ALWAYS_INLINE String JSCStackFrame::retrieveFunctionName() { static auto functionNameEvalCodeString = MAKE_STATIC_STRING_IMPL("eval code"); static auto functionNameModuleCodeString = MAKE_STATIC_STRING_IMPL("module code"); static auto functionNameGlobalCodeString = MAKE_STATIC_STRING_IMPL("global code"); if (m_isWasmFrame) { - return jsString(m_vm, JSC::Wasm::makeString(m_wasmFunctionIndexOrName)); + return JSC::Wasm::makeString(m_wasmFunctionIndexOrName); } if (m_codeBlock) { switch (m_codeBlock->codeType()) { case JSC::EvalCode: - return JSC::jsOwnedString(m_vm, functionNameEvalCodeString); + return String(functionNameEvalCodeString); case JSC::ModuleCode: - return JSC::jsOwnedString(m_vm, functionNameModuleCodeString); + return String(functionNameModuleCodeString); case JSC::FunctionCode: break; case JSC::GlobalCode: - return JSC::jsOwnedString(m_vm, functionNameGlobalCodeString); + return String(functionNameGlobalCodeString); default: ASSERT_NOT_REACHED(); } } - if (!m_callee || !m_callee->isObject()) { - return m_vm.smallStrings.emptyString(); - } - - JSC::JSObject* calleeAsObject = JSC::jsCast<JSC::JSObject*>(m_callee); - - // First, try the "displayName" property - JSC::JSValue displayName = calleeAsObject->getDirect(m_vm, m_vm.propertyNames->displayName); - if (displayName && isJSString(displayName)) { - return JSC::asString(displayName); - } - - // Our addition - if there's no "dispalyName" property, try the "name" property - JSC::JSValue name = calleeAsObject->getDirect(m_vm, m_vm.propertyNames->name); - if (name && isJSString(name)) { - return JSC::asString(name); - } - - /* For functions (either JSFunction or InternalFunction), fallback to their "native" name property. - * Based on JSC::getCalculatedDisplayName, "inlining" the - * JSFunction::calculatedDisplayName\InternalFunction::calculatedDisplayName calls */ - if (JSC::JSFunction* function = JSC::jsDynamicCast<JSC::JSFunction*>(calleeAsObject)) { - // Based on JSC::JSFunction::calculatedDisplayName, skipping the "displayName" property check - WTF::String actualName = function->name(m_vm); - if (!actualName.isEmpty() || function->isHostOrBuiltinFunction()) { - return JSC::jsString(m_vm, actualName); - } - - return JSC::jsString(m_vm, function->jsExecutable()->name().string()); - } - if (JSC::InternalFunction* function = JSC::jsDynamicCast<JSC::InternalFunction*>(calleeAsObject)) { - // Based on JSC::InternalFunction::calculatedDisplayName, skipping the "displayName" property check - return JSC::jsString(m_vm, function->name()); + String name; + if (m_callee) { + if (m_callee->isObject()) + name = getCalculatedDisplayName(m_vm, jsCast<JSObject*>(m_callee)).impl(); } - return m_vm.smallStrings.emptyString(); + return name.isNull() ? emptyString() : name; } -ALWAYS_INLINE JSC::JSString* JSCStackFrame::retrieveTypeName() +ALWAYS_INLINE String JSCStackFrame::retrieveTypeName() { JSC::JSObject* calleeObject = JSC::jsCast<JSC::JSObject*>(m_callee); // return JSC::jsTypeStringForValue(m_globalObjectcalleeObject->toThis() - return jsString(m_vm, makeString(calleeObject->className())); + return calleeObject->className(); } // General flow here is based on JSC's appendSourceToError (ErrorInstance.cpp) diff --git a/src/bun.js/bindings/ErrorStackTrace.h b/src/bun.js/bindings/ErrorStackTrace.h index 1284376a4..ac40eaf4b 100644 --- a/src/bun.js/bindings/ErrorStackTrace.h +++ b/src/bun.js/bindings/ErrorStackTrace.h @@ -61,9 +61,9 @@ private: JSC::BytecodeIndex m_bytecodeIndex; // Lazy-initialized - JSC::JSString* m_sourceURL; - JSC::JSString* m_functionName; - JSC::JSString* m_typeName; + WTF::String m_sourceURL; + WTF::String m_functionName; + WTF::String m_typeName; // m_wasmFunctionIndexOrName has meaning only when m_isWasmFrame is set JSC::Wasm::IndexOrName m_wasmFunctionIndexOrName; @@ -105,7 +105,7 @@ public: bool isConstructor() const { return m_codeBlock && (JSC::CodeForConstruct == m_codeBlock->specializationKind()); } private: - ALWAYS_INLINE JSC::JSString* retrieveSourceURL(); + ALWAYS_INLINE String retrieveSourceURL(); /* Regarding real functions (not eval\module\global code), both v8 and JSC seem to follow * the same logic, which is to first try the function's "display name", and if it's not defined, @@ -119,9 +119,9 @@ private: * and just try to use the "name" property when needed, so our lookup will be: * "display name" property -> "name" property -> JSFunction\InternalFunction "name" methods. */ - ALWAYS_INLINE JSC::JSString* retrieveFunctionName(); + ALWAYS_INLINE String retrieveFunctionName(); - ALWAYS_INLINE JSC::JSString* retrieveTypeName(); + ALWAYS_INLINE String retrieveTypeName(); bool calculateSourcePositions(); }; diff --git a/src/bun.js/bindings/FFI.zig b/src/bun.js/bindings/FFI.zig index 9d16bd78e..da98438ba 100644 --- a/src/bun.js/bindings/FFI.zig +++ b/src/bun.js/bindings/FFI.zig @@ -20,8 +20,9 @@ pub const EncodedJSValue = union_EncodedJSValue; pub export var ValueUndefined: EncodedJSValue = EncodedJSValue{ .asInt64 = @as(i64, @bitCast(@as(c_longlong, @as(c_int, 2) | @as(c_int, 8)))), }; +pub const TrueI64 = @as(i64, @bitCast(@as(c_longlong, (@as(c_int, 2) | @as(c_int, 4)) | @as(c_int, 1)))); pub export var ValueTrue: EncodedJSValue = EncodedJSValue{ - .asInt64 = @as(i64, @bitCast(@as(c_longlong, (@as(c_int, 2) | @as(c_int, 4)) | @as(c_int, 1)))), + .asInt64 = TrueI64, }; pub const JSContext = ?*anyopaque; pub inline fn JSVALUE_IS_CELL(arg_val: EncodedJSValue) bool { diff --git a/src/bun.js/bindings/ImportMetaObject.cpp b/src/bun.js/bindings/ImportMetaObject.cpp index 4160102a5..199a13392 100644 --- a/src/bun.js/bindings/ImportMetaObject.cpp +++ b/src/bun.js/bindings/ImportMetaObject.cpp @@ -64,6 +64,12 @@ static EncodedJSValue functionRequireResolve(JSC::JSGlobalObject* globalObject, JSC::JSValue moduleName = callFrame->argument(0); auto doIt = [&](const WTF::String& fromStr) -> JSC::EncodedJSValue { + if (auto* virtualModules = jsCast<Zig::GlobalObject*>(globalObject)->onLoadPlugins.virtualModules) { + if (virtualModules->contains(fromStr)) { + return JSC::JSValue::encode(jsString(vm, fromStr)); + } + } + BunString from = Bun::toString(fromStr); auto result = Bun__resolveSyncWithSource(globalObject, JSC::JSValue::encode(moduleName), &from, false); @@ -160,6 +166,14 @@ extern "C" EncodedJSValue functionImportMeta__resolveSync(JSC::JSGlobalObject* g JSC__JSValue from; bool isESM = true; + if (auto* virtualModules = jsCast<Zig::GlobalObject*>(globalObject)->onLoadPlugins.virtualModules) { + if (moduleName.isString()) { + if (virtualModules->contains(moduleName.toWTFString(globalObject))) { + return JSC::JSValue::encode(moduleName); + } + } + } + if (callFrame->argumentCount() > 1) { if (callFrame->argumentCount() > 2) { @@ -226,6 +240,7 @@ extern "C" EncodedJSValue functionImportMeta__resolveSyncPrivate(JSC::JSGlobalOb { JSC::VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + auto* global = jsDynamicCast<Zig::GlobalObject*>(globalObject); JSC::JSValue moduleName = callFrame->argument(0); JSValue from = callFrame->argument(1); @@ -239,12 +254,19 @@ extern "C" EncodedJSValue functionImportMeta__resolveSyncPrivate(JSC::JSGlobalOb RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {})); + if (auto* virtualModules = global->onLoadPlugins.virtualModules) { + if (moduleName.isString()) { + if (virtualModules->contains(moduleName.toWTFString(globalObject))) { + return JSC::JSValue::encode(moduleName); + } + } + } + if (!isESM) { - auto* global = jsDynamicCast<Zig::GlobalObject*>(globalObject); if (LIKELY(global)) { auto overrideHandler = global->m_nodeModuleOverriddenResolveFilename.get(); if (UNLIKELY(overrideHandler)) { - ASSERT(overrideHandler.isCallable(globalObject)); + ASSERT(overrideHandler->isCallable()); MarkedArgumentBuffer args; args.append(moduleName); args.append(from); @@ -289,6 +311,14 @@ JSC_DEFINE_HOST_FUNCTION(functionImportMeta__resolve, JSC__JSValue from; + if (auto* virtualModules = jsCast<Zig::GlobalObject*>(globalObject)->onLoadPlugins.virtualModules) { + if (moduleName.isString()) { + if (virtualModules->contains(moduleName.toWTFString(globalObject))) { + return JSC::JSValue::encode(moduleName); + } + } + } + if (callFrame->argumentCount() > 1 && callFrame->argument(1).isString()) { from = JSC::JSValue::encode(callFrame->argument(1)); } else { @@ -404,6 +434,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(ImportMetaObjectPrototype, Base); return &vm.plainObjectSpace(); } @@ -417,11 +448,13 @@ public: reifyStaticProperties(vm, ImportMetaObject::info(), ImportMetaObjectPrototypeValues, *this); JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); - this->putDirect( - vm, + auto mainGetter = JSFunction::create(vm, importMetaObjectMainCodeGenerator(vm), globalObject); + + this->putDirectAccessor( + this->globalObject(), builtinNames.mainPublicName(), - GetterSetter::create(vm, globalObject, JSFunction::create(vm, importMetaObjectMainCodeGenerator(vm), globalObject), nullptr), - JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin | 0); + GetterSetter::create(vm, globalObject, mainGetter, mainGetter), + JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | 0); } ImportMetaObjectPrototype(JSC::VM& vm, JSC::Structure* structure) @@ -433,7 +466,7 @@ public: const ClassInfo ImportMetaObjectPrototype::s_info = { "ImportMeta"_s, - Base::info(), nullptr, nullptr, CREATE_METHOD_TABLE(ImportMetaObjectPrototype) + &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(ImportMetaObjectPrototype) }; JSC::Structure* ImportMetaObject::createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject) diff --git a/src/bun.js/bindings/InternalModuleRegistry.cpp b/src/bun.js/bindings/InternalModuleRegistry.cpp index 8dbf42a02..03f946192 100644 --- a/src/bun.js/bindings/InternalModuleRegistry.cpp +++ b/src/bun.js/bindings/InternalModuleRegistry.cpp @@ -33,7 +33,9 @@ static void maybeAddCodeCoverage(JSC::VM& vm, const JSC::SourceCode& code) #define INTERNAL_MODULE_REGISTRY_GENERATE_(globalObject, vm, SOURCE, moduleName, urlString) \ auto throwScope = DECLARE_THROW_SCOPE(vm); \ auto&& origin = SourceOrigin(WTF::URL(urlString)); \ - SourceCode source = JSC::makeSource(SOURCE, origin, moduleName); \ + SourceCode source = JSC::makeSource(SOURCE, origin, \ + JSC::SourceTaintedOrigin::Untainted, \ + moduleName); \ maybeAddCodeCoverage(vm, source); \ JSFunction* func \ = JSFunction::create( \ @@ -118,16 +120,23 @@ DEFINE_VISIT_CHILDREN_WITH_MODIFIER(JS_EXPORT_PRIVATE, InternalModuleRegistry); InternalModuleRegistry* InternalModuleRegistry::create(VM& vm, Structure* structure) { InternalModuleRegistry* registry = new (NotNull, allocateCell<InternalModuleRegistry>(vm)) InternalModuleRegistry(vm, structure); + registry->finishCreation(vm); + return registry; +} + +void InternalModuleRegistry::finishCreation(VM& vm) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); + for (uint8_t i = 0; i < BUN_INTERNAL_MODULE_COUNT; i++) { - registry->internalField(static_cast<Field>(i)) - .set(vm, registry, jsUndefined()); + this->internalField(static_cast<Field>(i)).set(vm, this, jsUndefined()); } - return registry; } Structure* InternalModuleRegistry::createStructure(VM& vm, JSGlobalObject* globalObject) { - return Structure::create(vm, globalObject, jsNull(), TypeInfo(InternalFieldTupleType, StructureFlags), info(), 0, 48); + return Structure::create(vm, globalObject, jsNull(), TypeInfo(InternalFieldTupleType, StructureFlags), info(), 0, 0); } JSValue InternalModuleRegistry::requireId(JSGlobalObject* globalObject, VM& vm, Field id) @@ -150,7 +159,7 @@ JSC_DEFINE_HOST_FUNCTION(InternalModuleRegistry::jsCreateInternalModuleById, (JS auto throwScope = DECLARE_THROW_SCOPE(vm); auto id = callframe->argument(0).toUInt32(lexicalGlobalObject); - auto registry = static_cast<Zig::GlobalObject*>(lexicalGlobalObject)->internalModuleRegistry(); + auto registry = jsCast<Zig::GlobalObject*>(lexicalGlobalObject)->internalModuleRegistry(); auto mod = registry->createInternalModuleById(lexicalGlobalObject, vm, static_cast<Field>(id)); RETURN_IF_EXCEPTION(throwScope, {}); registry->internalField(static_cast<Field>(id)).set(vm, registry, mod); diff --git a/src/bun.js/bindings/InternalModuleRegistry.h b/src/bun.js/bindings/InternalModuleRegistry.h index d14625e00..0944a382a 100644 --- a/src/bun.js/bindings/InternalModuleRegistry.h +++ b/src/bun.js/bindings/InternalModuleRegistry.h @@ -16,19 +16,21 @@ using namespace JSC; // - some are written in JS (src/js, there is a readme file that explain those files more. // - others are native code (src/bun.js/modules), see _NativeModule.h in there. class InternalModuleRegistry : public JSInternalFieldObjectImpl<BUN_INTERNAL_MODULE_COUNT> { -protected: - JS_EXPORT_PRIVATE InternalModuleRegistry(VM&, Structure*); - DECLARE_DEFAULT_FINISH_CREATION; - DECLARE_VISIT_CHILDREN_WITH_MODIFIER(JS_EXPORT_PRIVATE); - public: using Base = JSInternalFieldObjectImpl<BUN_INTERNAL_MODULE_COUNT>; DECLARE_EXPORT_INFO; + static size_t allocationSize(Checked<size_t> inlineCapacity) + { + ASSERT_UNUSED(inlineCapacity, inlineCapacity == 0U); + return sizeof(InternalModuleRegistry); + } + enum Field : uint8_t { #include "../../../src/js/out/InternalModuleRegistry+enum.h" }; + const WriteBarrier<Unknown>& internalField(Field field) const { return Base::internalField(static_cast<uint32_t>(field)); } WriteBarrier<Unknown>& internalField(Field field) { return Base::internalField(static_cast<uint32_t>(field)); } @@ -52,8 +54,11 @@ public: static JSC_DECLARE_HOST_FUNCTION(jsCreateInternalModuleById); -protected: +private: + JS_EXPORT_PRIVATE InternalModuleRegistry(VM&, Structure*); + DECLARE_VISIT_CHILDREN_WITH_MODIFIER(JS_EXPORT_PRIVATE); JSValue createInternalModuleById(JSGlobalObject* globalObject, VM& vm, Field id); + void finishCreation(VM&); }; } // namespace Bun diff --git a/src/bun.js/bindings/JSBuffer.cpp b/src/bun.js/bindings/JSBuffer.cpp index 9227e47b3..524007f86 100644 --- a/src/bun.js/bindings/JSBuffer.cpp +++ b/src/bun.js/bindings/JSBuffer.cpp @@ -819,6 +819,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSBufferPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -865,28 +866,49 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_compareBody(JSC::JSG size_t sourceEndInit = castedThis->byteLength(); size_t sourceEnd = sourceEndInit; + JSValue targetStartValue = jsUndefined(); + JSValue targetEndValue = jsUndefined(); + JSValue sourceStartValue = jsUndefined(); + JSValue sourceEndValue = jsUndefined(); + switch (callFrame->argumentCount()) { default: - sourceEnd = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(4)); - RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + sourceEndValue = callFrame->uncheckedArgument(4); FALLTHROUGH; case 4: - sourceStart = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(3)); - RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + sourceStartValue = callFrame->uncheckedArgument(3); FALLTHROUGH; case 3: - targetEnd = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(2)); - RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + targetEndValue = callFrame->uncheckedArgument(2); FALLTHROUGH; case 2: - targetStart = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(1)); - RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + targetStartValue = callFrame->uncheckedArgument(1); break; case 1: case 0: break; } + if (!targetStartValue.isUndefined()) { + targetStart = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(1)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + } + + if (!targetEndValue.isUndefined()) { + targetEnd = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(2)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + } + + if (!sourceStartValue.isUndefined()) { + sourceStart = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(3)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + } + + if (!sourceEndValue.isUndefined()) { + sourceEnd = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(4)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + } + targetStart = std::min(targetStart, std::min(targetEnd, targetEndInit)); sourceStart = std::min(sourceStart, std::min(sourceEnd, sourceEndInit)); @@ -931,24 +953,40 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_copyBody(JSC::JSGlob size_t sourceEndInit = castedThis->byteLength(); size_t sourceEnd = sourceEndInit; + JSValue targetStartValue = jsUndefined(); + JSValue sourceStartValue = jsUndefined(); + JSValue sourceEndValue = jsUndefined(); + switch (callFrame->argumentCount()) { default: - sourceEnd = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(3)); - RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + sourceEndValue = callFrame->uncheckedArgument(3); FALLTHROUGH; case 3: - sourceStart = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(2)); - RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + sourceStartValue = callFrame->uncheckedArgument(2); FALLTHROUGH; case 2: - targetStart = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(1)); - RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + targetStartValue = callFrame->uncheckedArgument(1); break; case 1: case 0: break; } + if (!targetStartValue.isUndefined()) { + targetStart = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(1)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + } + + if (!sourceStartValue.isUndefined()) { + sourceStart = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(2)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + } + + if (!sourceEndValue.isUndefined()) { + sourceEnd = parseIndex(lexicalGlobalObject, throwScope, callFrame->uncheckedArgument(3)); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); + } + targetStart = std::min(targetStart, targetEnd); sourceEnd = std::min(sourceEnd, sourceEndInit); sourceStart = std::min(sourceStart, sourceEnd); @@ -1614,7 +1652,7 @@ JSC_DEFINE_HOST_FUNCTION(jsBufferConstructorFunction_toBuffer, (JSGlobalObject * class JSBufferConstructor final : public JSC::InternalFunction { public: using Base = JSC::InternalFunction; - static constexpr unsigned StructureFlags = Base::StructureFlags; + static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable; ~JSBufferConstructor() = default; @@ -1700,8 +1738,6 @@ JSC_DEFINE_JIT_OPERATION(jsBufferConstructorAllocUnsafeSlowWithoutTypeChecks, JS JSC_ANNOTATE_HOST_FUNCTION(JSBufferConstructorConstruct, JSBufferConstructor::construct); -const ClassInfo JSBufferConstructor::s_info = { "Buffer"_s, nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(JSBufferConstructor) }; - class JSBuffer : public JSC::JSNonFinalObject { DECLARE_INFO; @@ -1790,8 +1826,8 @@ static const HashTableValue JSBufferPrototypeTableValues[] { "lastIndexOf"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferPrototypeFunction_lastIndexOf, 3 } }, { "latin1Slice"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeLatin1SliceCodeGenerator, 2 } }, { "latin1Write"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeLatin1WriteCodeGenerator, 1 } }, - { "offset"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeOffsetCodeGenerator, 0 } }, - { "parent"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeParentCodeGenerator, 0 } }, + { "offset"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, jsBufferPrototypeOffsetCodeGenerator, 0 } }, + { "parent"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, jsBufferPrototypeParentCodeGenerator, 0 } }, { "readBigInt64"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadBigInt64LECodeGenerator, 1 } }, { "readBigInt64BE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadBigInt64BECodeGenerator, 1 } }, { "readBigInt64LE"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeReadBigInt64LECodeGenerator, 1 } }, @@ -1899,8 +1935,7 @@ const ClassInfo JSBufferPrototype::s_info = { // We must use the same naming convention to match Node // Some packages (like MongoDB's official Node.js client) rely on this behavior. "Uint8Array"_s, - - nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(JSBufferPrototype) + &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSBufferPrototype) }; static const JSC::DOMJIT::Signature DOMJITSignaturejsBufferConstructorAlloc(jsBufferConstructorAllocWithoutTypeChecks, @@ -1917,27 +1952,27 @@ static const JSC::DOMJIT::Signature DOMJITSignaturejsBufferConstructorAllocUnsaf JSC::DOMJIT::Effect::forWriteKinds(JSC::DFG::AbstractHeapKind::Heap), JSC::SpecUint8Array, JSC::SpecInt32Only); -/* Hash table for constructor */ -static const HashTableValue JSBufferConstructorTableValues[] = { - // { "alloc"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction), NoIntrinsic, { HashTableValue::DOMJITFunctionType, jsBufferConstructorFunction_alloc, &DOMJITSignaturejsBufferConstructorAlloc } }, - { "alloc"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_alloc, 1 } }, - // { "allocUnsafe"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction), NoIntrinsic, { HashTableValue::DOMJITFunctionType, jsBufferConstructorFunction_allocUnsafe, &DOMJITSignaturejsBufferConstructorAllocUnsafe } }, - { "allocUnsafe"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_allocUnsafe, 1 } }, - // { "allocUnsafeSlow"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction), NoIntrinsic, { HashTableValue::DOMJITFunctionType, jsBufferConstructorFunction_allocUnsafeSlow, &DOMJITSignaturejsBufferConstructorAllocUnsafeSlow } }, - { "allocUnsafeSlow"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_allocUnsafeSlow, 1 } }, - { "byteLength"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_byteLength, 2 } }, - { "compare"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_compare, 2 } }, - { "concat"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_concat, 2 } }, - { "from"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferConstructorFromCodeGenerator, 1 } }, - { "isBuffer"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferConstructorIsBufferCodeGenerator, 1 } }, - { "toBuffer"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_toBuffer, 1 } }, - { "isEncoding"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_isEncoding, 1 } }, -}; +/* Source for JSBuffer.lut.h +@begin jsBufferConstructorTable + alloc jsBufferConstructorFunction_alloc Constructable|Function 1 + allocUnsafe jsBufferConstructorFunction_allocUnsafe Constructable|Function 1 + allocUnsafeSlow jsBufferConstructorFunction_allocUnsafeSlow Constructable|Function 1 + byteLength jsBufferConstructorFunction_byteLength Function 2 + compare jsBufferConstructorFunction_compare Function 2 + concat jsBufferConstructorFunction_concat Function 2 + from JSBuiltin Builtin|Function 1 + isBuffer JSBuiltin Builtin|Function 1 + toBuffer jsBufferConstructorFunction_toBuffer Function 1 + isEncoding jsBufferConstructorFunction_isEncoding Function 1 +@end +*/ +#include "JSBuffer.lut.h" + +const ClassInfo JSBufferConstructor::s_info = { "Buffer"_s, &Base::s_info, &jsBufferConstructorTable, nullptr, CREATE_METHOD_TABLE(JSBufferConstructor) }; void JSBufferConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, JSC::JSObject* prototype) { Base::finishCreation(vm, 3, "Buffer"_s, PropertyAdditionMode::WithoutStructureTransition); - reifyStaticProperties(vm, JSBufferConstructor::info(), JSBufferConstructorTableValues, *this); putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); prototype->putDirect(vm, vm.propertyNames->speciesSymbol, this, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); } diff --git a/src/bun.js/bindings/JSBuffer.lut.h b/src/bun.js/bindings/JSBuffer.lut.h new file mode 100644 index 000000000..35a3acea9 --- /dev/null +++ b/src/bun.js/bindings/JSBuffer.lut.h @@ -0,0 +1,52 @@ +// File generated via `make static-hash-table` / `make cpp` +static const struct CompactHashIndex jsBufferConstructorTableIndex[33] = { + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 1, 32 }, + { 0, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 8, -1 }, + { 3, -1 }, + { -1, -1 }, + { 5, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 9, -1 }, + { -1, -1 }, + { 4, -1 }, + { -1, -1 }, + { 6, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 2, -1 }, + { -1, -1 }, + { 7, -1 }, +}; + +static const struct HashTableValue jsBufferConstructorTableValues[10] = { + { "alloc"_s, static_cast<unsigned>(PropertyAttribute::Constructable|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_alloc, 1 } }, + { "allocUnsafe"_s, static_cast<unsigned>(PropertyAttribute::Constructable|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_allocUnsafe, 1 } }, + { "allocUnsafeSlow"_s, static_cast<unsigned>(PropertyAttribute::Constructable|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_allocUnsafeSlow, 1 } }, + { "byteLength"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_byteLength, 2 } }, + { "compare"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_compare, 2 } }, + { "concat"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_concat, 2 } }, + { "from"_s, ((static_cast<unsigned>(PropertyAttribute::Builtin|PropertyAttribute::Function)) & ~PropertyAttribute::Function) | PropertyAttribute::Builtin, NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferConstructorFromCodeGenerator, 1 } }, + { "isBuffer"_s, ((static_cast<unsigned>(PropertyAttribute::Builtin|PropertyAttribute::Function)) & ~PropertyAttribute::Function) | PropertyAttribute::Builtin, NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferConstructorIsBufferCodeGenerator, 1 } }, + { "toBuffer"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_toBuffer, 1 } }, + { "isEncoding"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_isEncoding, 1 } }, +}; + +static const struct HashTable jsBufferConstructorTable = + { 10, 31, false, nullptr, jsBufferConstructorTableValues, jsBufferConstructorTableIndex }; diff --git a/src/bun.js/bindings/JSBufferList.cpp b/src/bun.js/bindings/JSBufferList.cpp index a8cefa710..0db5527d7 100644 --- a/src/bun.js/bindings/JSBufferList.cpp +++ b/src/bun.js/bindings/JSBufferList.cpp @@ -118,8 +118,7 @@ JSC::JSValue JSBufferList::_getString(JSC::VM& vm, JSC::JSGlobalObject* lexicalG RELEASE_AND_RETURN(throwScope, JSC::jsEmptyString(vm)); } - auto iter = m_deque.begin(); - JSC::JSString* str = JSC::jsDynamicCast<JSC::JSString*>(iter->get()); + JSC::JSString* str = JSC::jsDynamicCast<JSC::JSString*>(m_deque.first().get()); if (UNLIKELY(!str)) { return throwTypeError(lexicalGlobalObject, throwScope, "_getString can only be called when all buffers are string"_s); } @@ -132,13 +131,14 @@ JSC::JSValue JSBufferList::_getString(JSC::VM& vm, JSC::JSGlobalObject* lexicalG } if (n < len) { JSString* firstHalf = JSC::jsSubstring(lexicalGlobalObject, str, 0, n); - iter->set(vm, this, JSC::jsSubstring(lexicalGlobalObject, str, n, len - n)); + m_deque.first().set(vm, this, JSC::jsSubstring(lexicalGlobalObject, str, n, len - n)); RELEASE_AND_RETURN(throwScope, firstHalf); } JSRopeString::RopeBuilder<RecordOverflow> ropeBuilder(vm); - for (const auto end = m_deque.end(); iter != end; ++iter) { - JSC::JSString* str = JSC::jsDynamicCast<JSC::JSString*>(iter->get()); + while (m_deque.size() > 0) { + auto& element = m_deque.first(); + JSC::JSString* str = JSC::jsDynamicCast<JSC::JSString*>(element.get()); if (UNLIKELY(!str)) { return throwTypeError(lexicalGlobalObject, throwScope, "_getString can only be called when all buffers are string"_s); } @@ -147,7 +147,7 @@ JSC::JSValue JSBufferList::_getString(JSC::VM& vm, JSC::JSGlobalObject* lexicalG JSString* firstHalf = JSC::jsSubstring(lexicalGlobalObject, str, 0, n); if (!ropeBuilder.append(firstHalf)) return throwOutOfMemoryError(lexicalGlobalObject, throwScope); - iter->set(vm, this, JSC::jsSubstring(lexicalGlobalObject, str, n, len - n)); + element.set(vm, this, JSC::jsSubstring(lexicalGlobalObject, str, n, len - n)); break; } if (!ropeBuilder.append(str)) @@ -169,8 +169,7 @@ JSC::JSValue JSBufferList::_getBuffer(JSC::VM& vm, JSC::JSGlobalObject* lexicalG RELEASE_AND_RETURN(throwScope, JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, 0)); } - auto iter = m_deque.begin(); - JSC::JSUint8Array* array = JSC::jsDynamicCast<JSC::JSUint8Array*>(iter->get()); + JSC::JSUint8Array* array = JSC::jsDynamicCast<JSC::JSUint8Array*>(m_deque.first().get()); if (UNLIKELY(!array)) { return throwTypeError(lexicalGlobalObject, throwScope, "_getBuffer can only be called when all buffers are Uint8Array"_s); } @@ -185,7 +184,7 @@ JSC::JSValue JSBufferList::_getBuffer(JSC::VM& vm, JSC::JSGlobalObject* lexicalG auto buffer = array->possiblySharedBuffer(); JSC::JSUint8Array* retArray = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, buffer, 0, n); JSC::JSUint8Array* newArray = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, buffer, n, len - n); - iter->set(vm, this, newArray); + m_deque.first().set(vm, this, newArray); RELEASE_AND_RETURN(throwScope, retArray); } @@ -196,8 +195,9 @@ JSC::JSValue JSBufferList::_getBuffer(JSC::VM& vm, JSC::JSGlobalObject* lexicalG } JSC::JSUint8Array* uint8Array = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, WTFMove(arrayBuffer), 0, n); size_t offset = 0; - for (const auto end = m_deque.end(); iter != end; ++iter) { - JSC::JSUint8Array* array = JSC::jsDynamicCast<JSC::JSUint8Array*>(iter->get()); + while (m_deque.size() > 0) { + auto& element = m_deque.first(); + JSC::JSUint8Array* array = JSC::jsDynamicCast<JSC::JSUint8Array*>(element.get()); if (UNLIKELY(!array)) { return throwTypeError(lexicalGlobalObject, throwScope, "_getBuffer can only be called when all buffers are Uint8Array"_s); } @@ -208,7 +208,7 @@ JSC::JSValue JSBufferList::_getBuffer(JSC::VM& vm, JSC::JSGlobalObject* lexicalG } auto buffer = array->possiblySharedBuffer(); JSC::JSUint8Array* newArray = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, buffer, n, len - n); - iter->set(vm, this, newArray); + element.set(vm, this, newArray); offset += n; break; } @@ -411,11 +411,11 @@ static const HashTableValue JSBufferListPrototypeTableValues[] void JSBufferListPrototype::finishCreation(VM& vm, JSC::JSGlobalObject* globalThis) { Base::finishCreation(vm); - this->setPrototypeDirect(vm, globalThis->objectPrototype()); reifyStaticProperties(vm, JSBufferList::info(), JSBufferListPrototypeTableValues, *this); + ASSERT(inherits(info())); } -const ClassInfo JSBufferListPrototype::s_info = { "BufferList"_s, nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(JSBufferListPrototype) }; +const ClassInfo JSBufferListPrototype::s_info = { "BufferList"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSBufferListPrototype) }; void JSBufferListConstructor::finishCreation(VM& vm, JSC::JSGlobalObject* globalObject, JSBufferListPrototype* prototype) { diff --git a/src/bun.js/bindings/JSBufferList.h b/src/bun.js/bindings/JSBufferList.h index 94a69c8d1..ebbc1781e 100644 --- a/src/bun.js/bindings/JSBufferList.h +++ b/src/bun.js/bindings/JSBufferList.h @@ -46,7 +46,7 @@ public: void finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject); static void destroy(JSCell*) {} - size_t length() { return m_deque.size(); } + inline size_t length() { return m_deque.size(); } void push(JSC::VM& vm, JSC::JSValue v) { m_deque.append(WriteBarrier<Unknown>()); @@ -100,6 +100,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSBufferListPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) diff --git a/src/bun.js/bindings/JSBundlerPlugin.cpp b/src/bun.js/bindings/JSBundlerPlugin.cpp index 6ae266df7..d896d5b3d 100644 --- a/src/bun.js/bindings/JSBundlerPlugin.cpp +++ b/src/bun.js/bindings/JSBundlerPlugin.cpp @@ -31,6 +31,7 @@ namespace Bun { extern "C" void JSBundlerPlugin__addError(void*, void*, JSC::EncodedJSValue, JSC::EncodedJSValue); extern "C" void JSBundlerPlugin__onLoadAsync(void*, void*, JSC::EncodedJSValue, JSC::EncodedJSValue); extern "C" void JSBundlerPlugin__onResolveAsync(void*, void*, JSC::EncodedJSValue, JSC::EncodedJSValue, JSC::EncodedJSValue); +extern "C" void JSBundlerPlugin__onVirtualModulePlugin(void*, void*, JSC::EncodedJSValue, JSC::EncodedJSValue, JSC::EncodedJSValue); JSC_DECLARE_HOST_FUNCTION(jsBundlerPluginFunction_addFilter); JSC_DECLARE_HOST_FUNCTION(jsBundlerPluginFunction_addError); @@ -154,6 +155,7 @@ public: Bun::BundlerPlugin plugin; JSC::LazyProperty<JSBundlerPlugin, JSC::JSFunction> onLoadFunction; JSC::LazyProperty<JSBundlerPlugin, JSC::JSFunction> onResolveFunction; + JSC::LazyProperty<JSBundlerPlugin, JSC::JSFunction> moduleFunction; JSC::LazyProperty<JSBundlerPlugin, JSC::JSFunction> setupFunction; private: diff --git a/src/bun.js/bindings/JSCUSocketsLoopIntegration.cpp b/src/bun.js/bindings/JSCUSocketsLoopIntegration.cpp new file mode 100644 index 000000000..0e3fcf47d --- /dev/null +++ b/src/bun.js/bindings/JSCUSocketsLoopIntegration.cpp @@ -0,0 +1,30 @@ +#include "root.h" +#include "JavaScriptCore/VM.h" + +// On Linux, signals are used to suspend/resume threads in JavaScriptCore +// When `.acquireAccess` is called, the signal might be raised. +// This causes issues with LLDB which might catch the signal. +// So we want to avoid that, we really only want this code to be executed when the debugger is attached +// But it's pretty hard to tell if LLDB is attached or not, so we just disable this code on Linux when in debug mode +#ifndef ACQUIRE_RELEASE_HEAP_ACCESS +#if OS(DARWIN) +#define ACQUIRE_RELEASE_HEAP_ACCESS 1 +#else +#ifndef BUN_DEBUG +#define ACQUIRE_RELEASE_HEAP_ACCESS 1 +#endif +#endif +#endif + +extern "C" void bun_on_tick_before(JSC::VM* vm) +{ +#if ACQUIRE_RELEASE_HEAP_ACCESS + // vm->heap.releaseAccess(); +#endif +} +extern "C" void bun_on_tick_after(JSC::VM* vm) +{ +#if ACQUIRE_RELEASE_HEAP_ACCESS + // vm->heap.acquireAccess(); +#endif +}
\ No newline at end of file diff --git a/src/bun.js/bindings/JSDOMFile.cpp b/src/bun.js/bindings/JSDOMFile.cpp index 1d7770ac1..1e1f9f2bc 100644 --- a/src/bun.js/bindings/JSDOMFile.cpp +++ b/src/bun.js/bindings/JSDOMFile.cpp @@ -17,7 +17,7 @@ class JSDOMFile : public JSC::InternalFunction { public: JSDOMFile(JSC::VM& vm, JSC::Structure* structure) - : Base(vm, structure, nullptr, construct) + : Base(vm, structure, call, construct) { } @@ -43,7 +43,8 @@ public: static JSDOMFile* create(JSC::VM& vm, JSGlobalObject* globalObject) { auto* zigGlobal = reinterpret_cast<Zig::GlobalObject*>(globalObject); - auto* object = new (NotNull, JSC::allocateCell<JSDOMFile>(vm)) JSDOMFile(vm, createStructure(vm, globalObject, zigGlobal->functionPrototype())); + auto structure = createStructure(vm, globalObject, zigGlobal->functionPrototype()); + auto* object = new (NotNull, JSC::allocateCell<JSDOMFile>(vm)) JSDOMFile(vm, structure); object->finishCreation(vm); // This is not quite right. But we'll fix it if someone files an issue about it. @@ -91,6 +92,12 @@ public: return JSValue::encode( WebCore::JSBlob::create(vm, globalObject, structure, ptr)); } + + static EncodedJSValue call(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame) + { + auto scope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm()); + throwTypeError(lexicalGlobalObject, scope, "Class constructor File cannot be invoked without 'new"_s); + } }; const JSC::ClassInfo JSDOMFile::s_info = { "File"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDOMFile) }; diff --git a/src/bun.js/bindings/JSDOMWrapperCache.h b/src/bun.js/bindings/JSDOMWrapperCache.h index 7656c7c17..e06f2607d 100644 --- a/src/bun.js/bindings/JSDOMWrapperCache.h +++ b/src/bun.js/bindings/JSDOMWrapperCache.h @@ -215,6 +215,10 @@ template<typename DOMClass> inline void setSubclassStructureIfNeeded(JSC::JSGlob JSC::VM& vm = lexicalGlobalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); + // If the new target isn't actually callable + if (UNLIKELY(!newTarget->isCallable())) + newTarget = constructor; + auto* functionGlobalObject = JSC::getFunctionRealm(lexicalGlobalObject, newTarget); RETURN_IF_EXCEPTION(scope, void()); auto* newTargetGlobalObject = JSC::jsCast<JSDOMGlobalObject*>(functionGlobalObject); diff --git a/src/bun.js/bindings/JSMockFunction.cpp b/src/bun.js/bindings/JSMockFunction.cpp index a8bac7c56..498864dfc 100644 --- a/src/bun.js/bindings/JSMockFunction.cpp +++ b/src/bun.js/bindings/JSMockFunction.cpp @@ -486,6 +486,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSMockFunctionPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -623,7 +624,6 @@ extern "C" EncodedJSValue JSMock__jsSpyOn(JSC::JSGlobalObject* lexicalGlobalObje mock->copyNameAndLength(vm, globalObject, value); - attributes |= PropertyAttribute::Function; object->putDirect(vm, propertyKey, mock, attributes); RETURN_IF_EXCEPTION(scope, {}); @@ -1320,7 +1320,7 @@ MockWithImplementationCleanupData* MockWithImplementationCleanupData::create(VM& } Structure* MockWithImplementationCleanupData::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } MockWithImplementationCleanupData::MockWithImplementationCleanupData(VM& vm, Structure* structure) diff --git a/src/bun.js/bindings/JSNextTickQueue.cpp b/src/bun.js/bindings/JSNextTickQueue.cpp index 8916ef6c8..18963645c 100644 --- a/src/bun.js/bindings/JSNextTickQueue.cpp +++ b/src/bun.js/bindings/JSNextTickQueue.cpp @@ -18,7 +18,7 @@ namespace Bun { using namespace JSC; -const JSC::ClassInfo JSNextTickQueue::s_info = { "JSNextTickQueue"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSNextTickQueue) }; +const JSC::ClassInfo JSNextTickQueue::s_info = { "NextTickQueue"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSNextTickQueue) }; template<typename, JSC::SubspaceAccess mode> JSC::GCClient::IsoSubspace* JSNextTickQueue::subspaceFor(JSC::VM& vm) @@ -34,11 +34,12 @@ JSC::GCClient::IsoSubspace* JSNextTickQueue::subspaceFor(JSC::VM& vm) JSNextTickQueue* JSNextTickQueue::create(VM& vm, Structure* structure) { JSNextTickQueue* mod = new (NotNull, allocateCell<JSNextTickQueue>(vm)) JSNextTickQueue(vm, structure); + mod->finishCreation(vm); return mod; } Structure* JSNextTickQueue::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } JSNextTickQueue::JSNextTickQueue(VM& vm, Structure* structure) @@ -65,7 +66,6 @@ JSNextTickQueue* JSNextTickQueue::create(JSC::JSGlobalObject* globalObject) { auto& vm = globalObject->vm(); auto* obj = create(vm, createStructure(vm, globalObject, jsNull())); - obj->finishCreation(vm); return obj; } diff --git a/src/bun.js/bindings/JSNextTickQueue.h b/src/bun.js/bindings/JSNextTickQueue.h index c3bd228cc..3a499345d 100644 --- a/src/bun.js/bindings/JSNextTickQueue.h +++ b/src/bun.js/bindings/JSNextTickQueue.h @@ -10,7 +10,6 @@ using namespace JSC; class JSNextTickQueue : public JSC::JSInternalFieldObjectImpl<3> { public: - static constexpr unsigned numberOfInternalFields = 3; using Base = JSC::JSInternalFieldObjectImpl<3>; template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm); diff --git a/src/bun.js/bindings/JSReadableState.cpp b/src/bun.js/bindings/JSReadableState.cpp index 1f3a36def..22b1ec357 100644 --- a/src/bun.js/bindings/JSReadableState.cpp +++ b/src/bun.js/bindings/JSReadableState.cpp @@ -314,12 +314,12 @@ JSReadableState_NULLABLE_BOOLEAN_GETTER_SETTER(paused) #undef JSReadableState_JSVALUE_GETTER_SETTER -#define JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(NAME) \ - { \ -#NAME ""_s, static_cast < unsigned>(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, \ - { \ - HashTableValue::GetterSetterType, jsReadableState_##NAME, setJSReadableState_##NAME \ - } \ +#define JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(NAME) \ + { \ + #NAME ""_s, static_cast<unsigned>(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, \ + { \ + HashTableValue::GetterSetterType, jsReadableState_##NAME, setJSReadableState_##NAME \ + } \ } /* Hash table for prototype */ diff --git a/src/bun.js/bindings/JSReadableState.h b/src/bun.js/bindings/JSReadableState.h index c67baebad..78a716910 100644 --- a/src/bun.js/bindings/JSReadableState.h +++ b/src/bun.js/bindings/JSReadableState.h @@ -107,6 +107,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStatePrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) diff --git a/src/bun.js/bindings/JSSink.cpp b/src/bun.js/bindings/JSSink.cpp index d986ae590..ef6343849 100644 --- a/src/bun.js/bindings/JSSink.cpp +++ b/src/bun.js/bindings/JSSink.cpp @@ -711,6 +711,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSArrayBufferSinkPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -743,6 +744,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableArrayBufferSinkControllerPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -798,17 +800,19 @@ void JSReadableArrayBufferSinkController::detach() auto readableStream = m_weakReadableStream.get(); auto onClose = m_onClose.get(); - m_onClose.clear(); if (readableStream && onClose) { - JSC::JSGlobalObject* globalObject = this->globalObject(); auto callData = JSC::getCallData(onClose); - JSC::MarkedArgumentBuffer arguments; - arguments.append(readableStream); - arguments.append(jsUndefined()); - call(globalObject, onClose, callData, JSC::jsUndefined(), arguments); + if (callData.type != JSC::CallData::Type::None) { + JSC::JSGlobalObject* globalObject = this->globalObject(); + JSC::MarkedArgumentBuffer arguments; + arguments.append(readableStream); + arguments.append(jsUndefined()); + call(globalObject, onClose, callData, JSC::jsUndefined(), arguments); + } } + m_onClose.clear(); m_weakReadableStream.clear(); } @@ -965,6 +969,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSFileSinkPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -997,6 +1002,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableFileSinkControllerPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -1052,17 +1058,19 @@ void JSReadableFileSinkController::detach() auto readableStream = m_weakReadableStream.get(); auto onClose = m_onClose.get(); - m_onClose.clear(); if (readableStream && onClose) { - JSC::JSGlobalObject* globalObject = this->globalObject(); auto callData = JSC::getCallData(onClose); - JSC::MarkedArgumentBuffer arguments; - arguments.append(readableStream); - arguments.append(jsUndefined()); - call(globalObject, onClose, callData, JSC::jsUndefined(), arguments); + if (callData.type != JSC::CallData::Type::None) { + JSC::JSGlobalObject* globalObject = this->globalObject(); + JSC::MarkedArgumentBuffer arguments; + arguments.append(readableStream); + arguments.append(jsUndefined()); + call(globalObject, onClose, callData, JSC::jsUndefined(), arguments); + } } + m_onClose.clear(); m_weakReadableStream.clear(); } @@ -1219,6 +1227,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSHTTPResponseSinkPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -1251,6 +1260,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableHTTPResponseSinkControllerPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -1306,17 +1316,19 @@ void JSReadableHTTPResponseSinkController::detach() auto readableStream = m_weakReadableStream.get(); auto onClose = m_onClose.get(); - m_onClose.clear(); if (readableStream && onClose) { - JSC::JSGlobalObject* globalObject = this->globalObject(); auto callData = JSC::getCallData(onClose); - JSC::MarkedArgumentBuffer arguments; - arguments.append(readableStream); - arguments.append(jsUndefined()); - call(globalObject, onClose, callData, JSC::jsUndefined(), arguments); + if (callData.type != JSC::CallData::Type::None) { + JSC::JSGlobalObject* globalObject = this->globalObject(); + JSC::MarkedArgumentBuffer arguments; + arguments.append(readableStream); + arguments.append(jsUndefined()); + call(globalObject, onClose, callData, JSC::jsUndefined(), arguments); + } } + m_onClose.clear(); m_weakReadableStream.clear(); } @@ -1473,6 +1485,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSHTTPSResponseSinkPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -1505,6 +1518,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableHTTPSResponseSinkControllerPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -1560,17 +1574,19 @@ void JSReadableHTTPSResponseSinkController::detach() auto readableStream = m_weakReadableStream.get(); auto onClose = m_onClose.get(); - m_onClose.clear(); if (readableStream && onClose) { - JSC::JSGlobalObject* globalObject = this->globalObject(); auto callData = JSC::getCallData(onClose); - JSC::MarkedArgumentBuffer arguments; - arguments.append(readableStream); - arguments.append(jsUndefined()); - call(globalObject, onClose, callData, JSC::jsUndefined(), arguments); + if (callData.type != JSC::CallData::Type::None) { + JSC::JSGlobalObject* globalObject = this->globalObject(); + JSC::MarkedArgumentBuffer arguments; + arguments.append(readableStream); + arguments.append(jsUndefined()); + call(globalObject, onClose, callData, JSC::jsUndefined(), arguments); + } } + m_onClose.clear(); m_weakReadableStream.clear(); } diff --git a/src/bun.js/bindings/JSSocketAddress.cpp b/src/bun.js/bindings/JSSocketAddress.cpp new file mode 100644 index 000000000..181507339 --- /dev/null +++ b/src/bun.js/bindings/JSSocketAddress.cpp @@ -0,0 +1,63 @@ +#include "JSSocketAddress.h" +#include "ZigGlobalObject.h" +#include "JavaScriptCore/JSObjectInlines.h" +#include "JavaScriptCore/ObjectConstructor.h" +#include "JavaScriptCore/JSCast.h" + +using namespace JSC; + +namespace Bun { +namespace JSSocketAddress { + +// Using a structure with inlined offsets should be more lightweight than a class. +Structure* createStructure(VM& vm, JSGlobalObject* globalObject) +{ + JSC::Structure* structure = globalObject->structureCache().emptyObjectStructureForPrototype( + globalObject, + globalObject->objectPrototype(), + 3); + + JSC::PropertyOffset offset; + structure = structure->addPropertyTransition( + vm, + structure, + JSC::Identifier::fromString(vm, "address"_s), + 0, + offset); + + structure = structure->addPropertyTransition( + vm, + structure, + JSC::Identifier::fromString(vm, "family"_s), + 0, + offset); + + structure = structure->addPropertyTransition( + vm, + structure, + JSC::Identifier::fromString(vm, "port"_s), + 0, + offset); + + return structure; +} + +} // namespace JSSocketAddress +} // namespace Bun + +extern "C" JSObject* JSSocketAddress__create(JSGlobalObject* globalObject, JSString* value, int32_t port, bool isIPv6) +{ + static const NeverDestroyed<String> IPv4 = MAKE_STATIC_STRING_IMPL("IPv4"); + static const NeverDestroyed<String> IPv6 = MAKE_STATIC_STRING_IMPL("IPv6"); + + VM& vm = globalObject->vm(); + + auto* global = jsCast<Zig::GlobalObject*>(globalObject); + + JSObject* thisObject = constructEmptyObject(vm, global->JSSocketAddressStructure()); + thisObject->putDirectOffset(vm, 0, value); + thisObject->putDirectOffset(vm, 1, isIPv6 ? jsString(vm, IPv6) : jsString(vm, IPv4)); + thisObject->putDirectOffset(vm, 2, jsNumber(port)); + + return thisObject; +} diff --git a/src/bun.js/bindings/JSSocketAddress.h b/src/bun.js/bindings/JSSocketAddress.h new file mode 100644 index 000000000..77bdca5d4 --- /dev/null +++ b/src/bun.js/bindings/JSSocketAddress.h @@ -0,0 +1,16 @@ +// The object returned by Bun.serve's .requestIP() +#pragma once +#include "root.h" +#include "JavaScriptCore/JSObjectInlines.h" + +using namespace JSC; + +namespace Bun { +namespace JSSocketAddress { + +Structure* createStructure(VM& vm, JSGlobalObject* globalObject); + +} // namespace JSSocketAddress +} // namespace Bun + +extern "C" JSObject* JSSocketAddress__create(JSGlobalObject* globalObject, JSString* value, int port, bool isIPv6); diff --git a/src/bun.js/bindings/JSStringDecoder.h b/src/bun.js/bindings/JSStringDecoder.h index bce1ae05d..cd2e017d6 100644 --- a/src/bun.js/bindings/JSStringDecoder.h +++ b/src/bun.js/bindings/JSStringDecoder.h @@ -77,6 +77,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSStringDecoderPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) diff --git a/src/bun.js/bindings/KeyObject.cpp b/src/bun.js/bindings/KeyObject.cpp new file mode 100644 index 000000000..d5782779d --- /dev/null +++ b/src/bun.js/bindings/KeyObject.cpp @@ -0,0 +1,2389 @@ +// Attribution: Some parts of of this module are derived from code originating from the Node.js +// crypto module which is licensed under an MIT license: +// +// Copyright Node.js contributors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "KeyObject.h" +#include "webcrypto/JSCryptoKey.h" +#include "webcrypto/JSSubtleCrypto.h" +#include "webcrypto/CryptoKeyOKP.h" +#include "webcrypto/CryptoKeyEC.h" +#include "webcrypto/CryptoKeyRSA.h" +#include "webcrypto/CryptoKeyAES.h" +#include "webcrypto/CryptoKeyHMAC.h" +#include "webcrypto/CryptoKeyRaw.h" +#include "webcrypto/CryptoKeyUsage.h" +#include "webcrypto/JsonWebKey.h" +#include "webcrypto/JSJsonWebKey.h" +#include "JavaScriptCore/JSObject.h" +#include "JavaScriptCore/ObjectConstructor.h" +#include "headers-handwritten.h" +#include <openssl/evp.h> +#include <openssl/mem.h> +#include <openssl/x509.h> +#include <openssl/pem.h> +#include <openssl/curve25519.h> +#include "JSBuffer.h" + +using namespace JSC; +using namespace Bun; +using JSGlobalObject + = JSC::JSGlobalObject; +using Exception = JSC::Exception; +using JSValue = JSC::JSValue; +using JSString = JSC::JSString; +using JSModuleLoader = JSC::JSModuleLoader; +using JSModuleRecord = JSC::JSModuleRecord; +using Identifier = JSC::Identifier; +using SourceOrigin = JSC::SourceOrigin; +using JSObject = JSC::JSObject; +using JSNonFinalObject = JSC::JSNonFinalObject; + +namespace WebCore { + +static bool KeyObject__IsASN1Sequence(const unsigned char* data, size_t size, + size_t* data_offset, size_t* data_size) +{ + if (size < 2 || data[0] != 0x30) + return false; + + if (data[1] & 0x80) { + // Long form. + size_t n_bytes = data[1] & ~0x80; + if (n_bytes + 2 > size || n_bytes > sizeof(size_t)) + return false; + size_t length = 0; + for (size_t i = 0; i < n_bytes; i++) + length = (length << 8) | data[i + 2]; + *data_offset = 2 + n_bytes; + *data_size = std::min(size - 2 - n_bytes, length); + } else { + // Short form. + *data_offset = 2; + *data_size = std::min<size_t>(size - 2, data[1]); + } + + return true; +} +static bool KeyObject__IsRSAPrivateKey(const unsigned char* data, size_t size) +{ + // Both RSAPrivateKey and RSAPublicKey structures start with a SEQUENCE. + size_t offset, len; + if (!KeyObject__IsASN1Sequence(data, size, &offset, &len)) + return false; + + // An RSAPrivateKey sequence always starts with a single-byte integer whose + // value is either 0 or 1, whereas an RSAPublicKey starts with the modulus + // (which is the product of two primes and therefore at least 4), so we can + // decide the type of the structure based on the first three bytes of the + // sequence. + return len >= 3 && data[offset] == 2 && data[offset + 1] == 1 && !(data[offset + 2] & 0xfe); +} + +static bool KeyObject__IsEncryptedPrivateKeyInfo(const unsigned char* data, size_t size) +{ + // Both PrivateKeyInfo and EncryptedPrivateKeyInfo start with a SEQUENCE. + size_t offset, len; + if (!KeyObject__IsASN1Sequence(data, size, &offset, &len)) + return false; + + // A PrivateKeyInfo sequence always starts with an integer whereas an + // EncryptedPrivateKeyInfo starts with an AlgorithmIdentifier. + return len >= 1 && data[offset] != 2; +} + +struct AsymmetricKeyValue { + EVP_PKEY* key; + bool owned; +}; + +struct AsymmetricKeyValueWithDER { + EVP_PKEY* key; + unsigned char* der_data; + long der_len; +}; + +struct PrivateKeyPassphrase { + char* passphrase; + size_t passphrase_len; +}; + +int PasswordCallback(char* buf, int size, int rwflag, void* u) +{ + auto result = static_cast<PrivateKeyPassphrase*>(u); + if (result != nullptr && size > 0 && result->passphrase != nullptr) { + size_t buflen = static_cast<size_t>(size); + size_t len = result->passphrase_len; + if (buflen < len) + return -1; + memcpy(buf, result->passphrase, buflen); + return len; + } + + return -1; +} + +AsymmetricKeyValueWithDER KeyObject__ParsePublicKeyPEM(const char* key_pem, + size_t key_pem_len) +{ + auto bp = BIOPtr(BIO_new_mem_buf(const_cast<char*>(key_pem), key_pem_len)); + auto result = (AsymmetricKeyValueWithDER) { .key = nullptr, .der_data = nullptr, .der_len = 0 }; + + if (!bp) { + ERR_clear_error(); + return result; + } + + // Try parsing as a SubjectPublicKeyInfo first. + if (PEM_bytes_read_bio(&result.der_data, &result.der_len, nullptr, "PUBLIC KEY", bp.get(), nullptr, nullptr) == 1) { + // OpenSSL might modify the pointer, so we need to make a copy before parsing. + const unsigned char* p = result.der_data; + result.key = d2i_PUBKEY(nullptr, &p, result.der_len); + if (result.key) { + return result; + } + } + + ERR_clear_error(); + BIO_reset(bp.get()); + + // Maybe it is PKCS#1. + if (PEM_bytes_read_bio(&result.der_data, &result.der_len, nullptr, "RSA PUBLIC KEY", bp.get(), nullptr, nullptr) == 1) { + const unsigned char* p = result.der_data; + result.key = d2i_PublicKey(EVP_PKEY_RSA, nullptr, &p, result.der_len); + if (result.key) { + return result; + } + } + ERR_clear_error(); + BIO_reset(bp.get()); + + // X.509 fallback. + if (PEM_bytes_read_bio(&result.der_data, &result.der_len, nullptr, "CERTIFICATE", bp.get(), nullptr, nullptr) == 1) { + const unsigned char* p = result.der_data; + X509Ptr x509(d2i_X509(nullptr, &p, result.der_len)); + result.key = x509 ? X509_get_pubkey(x509.get()) : nullptr; + if (result.key) { + return result; + } + OPENSSL_clear_free(result.der_data, result.der_len); + ERR_clear_error(); + result.der_data = nullptr; + result.der_len = 0; + } else { + OPENSSL_clear_free(result.der_data, result.der_len); + ERR_clear_error(); + result.der_data = nullptr; + result.der_len = 0; + } + return result; +} + +JSC::EncodedJSValue KeyObject__createPrivateKey(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) +{ + + auto count = callFrame->argumentCount(); + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (count < 1) { + JSC::throwTypeError(globalObject, scope, "createPrivateKey requires 1 arguments"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + auto* options = jsDynamicCast<JSC::JSObject*>(callFrame->argument(0)); + if (!options) { + JSC::throwTypeError(globalObject, scope, "expected options to be a object"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + JSValue keyJSValue = options->getIfPropertyExists(globalObject, PropertyName(Identifier::fromString(vm, "key"_s))); + if (keyJSValue.isUndefinedOrNull() || keyJSValue.isEmpty()) { + JSC::throwTypeError(globalObject, scope, "key is required"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + if (!keyJSValue.isCell()) { + JSC::throwTypeError(globalObject, scope, "key must be a Buffer, Array-like or object"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + JSValue formatJSValue = options->getIfPropertyExists(globalObject, PropertyName(Identifier::fromString(vm, "format"_s))); + if (formatJSValue.isUndefinedOrNull() || formatJSValue.isEmpty()) { + JSC::throwTypeError(globalObject, scope, "format is required"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + if (!formatJSValue.isString()) { + JSC::throwTypeError(globalObject, scope, "format must be a string"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto format = formatJSValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + Zig::GlobalObject* zigGlobalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject); + auto* structure = zigGlobalObject->JSCryptoKeyStructure(); + + void* data; + size_t byteLength; + + auto keyJSValueCell = keyJSValue.asCell(); + auto type = keyJSValueCell->type(); + + switch (type) { + + case DataViewType: + case Uint8ArrayType: + case Uint8ClampedArrayType: + case Uint16ArrayType: + case Uint32ArrayType: + case Int8ArrayType: + case Int16ArrayType: + case Int32ArrayType: + case Float32ArrayType: + case Float64ArrayType: + case BigInt64ArrayType: + case BigUint64ArrayType: { + JSC::JSArrayBufferView* view = jsCast<JSC::JSArrayBufferView*>(keyJSValueCell); + + data = view->vector(); + byteLength = view->length(); + break; + } + case ArrayBufferType: { + auto* jsBuffer = jsDynamicCast<JSC::JSArrayBuffer*>(keyJSValueCell); + if (UNLIKELY(!jsBuffer)) { + throwException(globalObject, scope, createTypeError(globalObject, "ERR_INVALID_ARG_TYPE: expected key to be Buffer or array-like object"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto* buffer = jsBuffer->impl(); + data = buffer->data(); + byteLength = buffer->byteLength(); + break; + } + default: { + if (auto* keyObj = jsDynamicCast<JSC::JSObject*>(keyJSValue)) { + if (format != "jwk"_s) { + JSC::throwTypeError(globalObject, scope, "format should be 'jwk' when key type is 'object'"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto jwk = WebCore::convertDictionary<JsonWebKey>(*globalObject, keyJSValue); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (jwk.kty == "OKP"_s) { + if (jwk.crv == "Ed25519"_s) { + auto result = CryptoKeyOKP::importJwk(CryptoAlgorithmIdentifier::Ed25519, CryptoKeyOKP::NamedCurve::Ed25519, WTFMove(jwk), true, CryptoKeyUsageSign); + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid Ed25519 private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + if (impl->type() != CryptoKeyType::Private) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else if (jwk.crv == "X25519"_s) { + auto result = CryptoKeyOKP::importJwk(CryptoAlgorithmIdentifier::Ed25519, CryptoKeyOKP::NamedCurve::X25519, WTFMove(jwk), true, CryptoKeyUsageSign); + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid X25519 private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + if (impl->type() != CryptoKeyType::Private) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else { + throwException(globalObject, scope, createTypeError(globalObject, "Unsupported OKP curve"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + } else if (jwk.kty == "EC"_s) { + auto result = CryptoKeyEC::importJwk(CryptoAlgorithmIdentifier::ECDSA, jwk.crv, WTFMove(jwk), true, jwk.usages); + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid EC private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + if (impl->type() != CryptoKeyType::Private) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else if (jwk.kty == "RSA"_s) { + auto result = CryptoKeyRSA::importJwk(CryptoAlgorithmIdentifier::RSA_OAEP, std::nullopt, WTFMove(jwk), true, jwk.usages); + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid RSA private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + if (impl->type() != CryptoKeyType::Private) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else { + throwException(globalObject, scope, createTypeError(globalObject, "Unsupported private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + } + JSC::throwTypeError(globalObject, scope, "The \"key\" property must be of type object"_s); + return JSValue::encode(JSC::jsUndefined()); + } + } + + if (format == "jwk"_s) { + JSC::throwTypeError(globalObject, scope, "The \"key\" property must be of type object"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + if (UNLIKELY(!data) || UNLIKELY(!byteLength)) { + throwException(globalObject, scope, createTypeError(globalObject, "ERR_INVALID_ARG_TYPE: expected key to be Buffer or array-like object"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + + JSValue passphraseJSValue = options->getIfPropertyExists(globalObject, PropertyName(Identifier::fromString(vm, "passphrase"_s))); + PrivateKeyPassphrase passphrase = { nullptr, 0 }; + + auto hasPassphrase = !passphraseJSValue.isUndefinedOrNull() && !passphraseJSValue.isEmpty(); + + if (hasPassphrase) { + if (passphraseJSValue.isString()) { + auto passphrase_wtfstr = passphraseJSValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (!passphrase_wtfstr.isNull()) { + if (auto pass = passphrase_wtfstr.tryGetUTF8()) { + if (pass.has_value()) { + auto value = pass.value(); + passphrase.passphrase = const_cast<char*>(value.data()); + passphrase.passphrase_len = value.length(); + } + } + } + } else if (auto* passphraseBuffer = jsDynamicCast<JSUint8Array*>(passphraseJSValue)) { + passphrase.passphrase = (char*)passphraseBuffer->vector(); + passphrase.passphrase_len = passphraseBuffer->byteLength(); + } else { + JSC::throwTypeError(globalObject, scope, "passphrase must be a Buffer or String"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } + + if (format == "pem"_s) { + auto bio = BIOPtr(BIO_new_mem_buf(const_cast<char*>((char*)data), byteLength)); + auto pkey = EvpPKeyPtr(PEM_read_bio_PrivateKey(bio.get(), nullptr, PasswordCallback, &passphrase)); + + if (!pkey) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid private key pem file"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto pKeyID = EVP_PKEY_id(pkey.get()); + + if (pKeyID == EVP_PKEY_RSA || pKeyID == EVP_PKEY_RSA_PSS) { + auto impl = CryptoKeyRSA::create(pKeyID == EVP_PKEY_RSA_PSS ? CryptoAlgorithmIdentifier::RSA_PSS : CryptoAlgorithmIdentifier::RSA_OAEP, CryptoAlgorithmIdentifier::SHA_1, false, CryptoKeyType::Private, WTFMove(pkey), true, CryptoKeyUsageDecrypt); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else if (pKeyID == EVP_PKEY_ED25519 || pKeyID == EVP_PKEY_X25519) { + size_t out_len = 0; + if (!EVP_PKEY_get_raw_private_key(pkey.get(), nullptr, &out_len)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + Vector<uint8_t> out(out_len); + if (!EVP_PKEY_get_raw_private_key(pkey.get(), out.data(), &out_len) || out_len != out.size()) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto result = CryptoKeyOKP::create(CryptoAlgorithmIdentifier::Ed25519, pKeyID == EVP_PKEY_ED25519 ? CryptoKeyOKP::NamedCurve::Ed25519 : CryptoKeyOKP::NamedCurve::X25519, CryptoKeyType::Private, WTFMove(out), true, CryptoKeyUsageSign); + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else if (pKeyID == EVP_PKEY_EC) { + EC_KEY* ec_key = EVP_PKEY_get1_EC_KEY(pkey.get()); + if (UNLIKELY(ec_key == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid EC private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key); + // Get the curve name + int curve_name = EC_GROUP_get_curve_name(ec_group); + if (curve_name == NID_undef) { + EC_KEY_free(ec_key); + throwException(globalObject, scope, createTypeError(globalObject, "Unable to identify EC curve"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + CryptoKeyEC::NamedCurve curve; + if (curve_name == NID_X9_62_prime256v1) + curve = CryptoKeyEC::NamedCurve::P256; + else if (curve_name == NID_secp384r1) + curve = CryptoKeyEC::NamedCurve::P384; + else if (curve_name == NID_secp521r1) + curve = CryptoKeyEC::NamedCurve::P521; + else { + EC_KEY_free(ec_key); + throwException(globalObject, scope, createTypeError(globalObject, "Unsupported EC curve"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + EC_KEY_free(ec_key); + auto impl = CryptoKeyEC::create(CryptoAlgorithmIdentifier::ECDH, curve, CryptoKeyType::Private, WTFMove(pkey), true, CryptoKeyUsageSign); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else { + throwException(globalObject, scope, createTypeError(globalObject, "Unsupported private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + } + if (format == "der"_s) { + JSValue typeJSValue = options->getIfPropertyExists(globalObject, PropertyName(Identifier::fromString(vm, "type"_s))); + WTF::String type = "pkcs8"_s; + if (!typeJSValue.isUndefinedOrNull() && !typeJSValue.isEmpty()) { + if (!typeJSValue.isString()) { + JSC::throwTypeError(globalObject, scope, "type must be a string"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + type = typeJSValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + } + + if (type == "pkcs1"_s) { + // must be RSA + const unsigned char* p = reinterpret_cast<const unsigned char*>(data); + auto pkey = EvpPKeyPtr(d2i_PrivateKey(EVP_PKEY_RSA, nullptr, &p, byteLength)); + if (!pkey) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid use of PKCS#1 as private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto pKeyID = EVP_PKEY_id(pkey.get()); + auto impl = CryptoKeyRSA::create(pKeyID == EVP_PKEY_RSA_PSS ? CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5 : CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5, CryptoAlgorithmIdentifier::SHA_1, false, CryptoKeyType::Private, WTFMove(pkey), true, CryptoKeyUsageDecrypt); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else if (type == "pkcs8"_s) { + + auto bio = BIOPtr(BIO_new_mem_buf(const_cast<char*>((char*)data), byteLength)); + WebCore::EvpPKeyPtr pkey; + if (KeyObject__IsEncryptedPrivateKeyInfo(const_cast<unsigned char*>((unsigned char*)data), byteLength)) { + pkey = EvpPKeyPtr(d2i_PKCS8PrivateKey_bio(bio.get(), + nullptr, + PasswordCallback, + &passphrase)); + } else { + auto* p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), nullptr); + if (!p8inf) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid PKCS8 data"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + pkey = EvpPKeyPtr(EVP_PKCS82PKEY(p8inf)); + } + if (!pkey) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto pKeyID = EVP_PKEY_id(pkey.get()); + + if (pKeyID == EVP_PKEY_RSA || pKeyID == EVP_PKEY_RSA_PSS) { + auto impl = CryptoKeyRSA::create(pKeyID == EVP_PKEY_RSA_PSS ? CryptoAlgorithmIdentifier::RSA_PSS : CryptoAlgorithmIdentifier::RSA_OAEP, CryptoAlgorithmIdentifier::SHA_1, false, CryptoKeyType::Private, WTFMove(pkey), true, CryptoKeyUsageDecrypt); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else if (pKeyID == EVP_PKEY_ED25519) { + auto result = CryptoKeyOKP::importPkcs8(CryptoAlgorithmIdentifier::Ed25519, CryptoKeyOKP::NamedCurve::Ed25519, Vector<uint8_t>((uint8_t*)data, byteLength), true, CryptoKeyUsageSign); + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid Ed25519 private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else if (pKeyID == EVP_PKEY_X25519) { + auto result = CryptoKeyOKP::importPkcs8(CryptoAlgorithmIdentifier::Ed25519, CryptoKeyOKP::NamedCurve::X25519, Vector<uint8_t>((uint8_t*)data, byteLength), true, CryptoKeyUsageSign); + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid Ed25519 private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else if (pKeyID == EVP_PKEY_EC) { + EC_KEY* ec_key = EVP_PKEY_get1_EC_KEY(pkey.get()); + if (UNLIKELY(ec_key == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid EC private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key); + // Get the curve name + int curve_name = EC_GROUP_get_curve_name(ec_group); + if (curve_name == NID_undef) { + EC_KEY_free(ec_key); + throwException(globalObject, scope, createTypeError(globalObject, "Unable to identify EC curve"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + CryptoKeyEC::NamedCurve curve; + if (curve_name == NID_X9_62_prime256v1) + curve = CryptoKeyEC::NamedCurve::P256; + else if (curve_name == NID_secp384r1) + curve = CryptoKeyEC::NamedCurve::P384; + else if (curve_name == NID_secp521r1) + curve = CryptoKeyEC::NamedCurve::P521; + else { + EC_KEY_free(ec_key); + throwException(globalObject, scope, createTypeError(globalObject, "Unsupported EC curve"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto result = CryptoKeyEC::platformImportPkcs8(CryptoAlgorithmIdentifier::ECDH, curve, Vector<uint8_t>((uint8_t*)data, byteLength), true, CryptoKeyUsageSign); + if (UNLIKELY(result == nullptr)) { + result = CryptoKeyEC::platformImportPkcs8(CryptoAlgorithmIdentifier::ECDSA, curve, Vector<uint8_t>((uint8_t*)data, byteLength), true, CryptoKeyUsageSign); + } + EC_KEY_free(ec_key); + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid EC private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else { + throwException(globalObject, scope, createTypeError(globalObject, "Unsupported private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + } else if (type == "sec1"_s) { + const unsigned char* p = reinterpret_cast<const unsigned char*>(data); + auto pkey = EvpPKeyPtr(d2i_PrivateKey(EVP_PKEY_EC, nullptr, &p, byteLength)); + auto pKeyID = EVP_PKEY_id(pkey.get()); + + if (pKeyID == EVP_PKEY_EC) { + EC_KEY* ec_key = EVP_PKEY_get1_EC_KEY(pkey.get()); + if (UNLIKELY(ec_key == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid EC private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key); + // Get the curve name + int curve_name = EC_GROUP_get_curve_name(ec_group); + if (curve_name == NID_undef) { + EC_KEY_free(ec_key); + throwException(globalObject, scope, createTypeError(globalObject, "Unable to identify EC curve"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + CryptoKeyEC::NamedCurve curve; + if (curve_name == NID_X9_62_prime256v1) + curve = CryptoKeyEC::NamedCurve::P256; + else if (curve_name == NID_secp384r1) + curve = CryptoKeyEC::NamedCurve::P384; + else if (curve_name == NID_secp521r1) + curve = CryptoKeyEC::NamedCurve::P521; + else { + EC_KEY_free(ec_key); + throwException(globalObject, scope, createTypeError(globalObject, "Unsupported EC curve"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + EC_KEY_free(ec_key); + auto impl = CryptoKeyEC::create(CryptoAlgorithmIdentifier::ECDH, curve, CryptoKeyType::Private, WTFMove(pkey), true, CryptoKeyUsageSign); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid EC private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + } + + JSC::throwTypeError(globalObject, scope, "type should be 'pkcs1', 'pkcs8' or 'sec1'"_s); + return JSValue::encode(JSC::jsUndefined()); + } + + JSC::throwTypeError(globalObject, scope, "format should be 'pem' or 'der'"_s); + return JSValue::encode(JSC::jsUndefined()); +} + +static JSC::EncodedJSValue KeyObject__createRSAFromPrivate(JSC::JSGlobalObject* globalObject, EVP_PKEY* pkey, WebCore::CryptoAlgorithmIdentifier alg) +{ + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + const RSA* rsa_key = EVP_PKEY_get0_RSA(pkey); + + auto publicRSA = RSAPtr(RSAPublicKey_dup(rsa_key)); + if (!publicRSA) { + JSC::throwTypeError(globalObject, scope, "ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE: Failed to create a public key from private"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto publicPKey = EvpPKeyPtr(EVP_PKEY_new()); + if (EVP_PKEY_set1_RSA(publicPKey.get(), publicRSA.get()) <= 0) { + JSC::throwTypeError(globalObject, scope, "ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE: Failed to create a public key from private"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto impl = CryptoKeyRSA::create(alg, CryptoAlgorithmIdentifier::SHA_1, false, CryptoKeyType::Public, WTFMove(publicPKey), true, CryptoKeyUsageVerify); + Zig::GlobalObject* zigGlobalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject); + auto* structure = zigGlobalObject->JSCryptoKeyStructure(); + + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); +} + +static JSC::EncodedJSValue KeyObject__createECFromPrivate(JSC::JSGlobalObject* globalObject, EVP_PKEY* pkey, CryptoKeyEC::NamedCurve namedCurve, WebCore::CryptoAlgorithmIdentifier alg) +{ + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey); + auto point = ECPointPtr(EC_POINT_dup(EC_KEY_get0_public_key(ec_key), EC_KEY_get0_group(ec_key))); + if (!point) { + JSC::throwTypeError(globalObject, scope, "ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE: Failed to create a public key from private 1"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto curve = NID_undef; + + switch (namedCurve) { + case CryptoKeyEC::NamedCurve::P256: + curve = NID_X9_62_prime256v1; + break; + case CryptoKeyEC::NamedCurve::P384: + curve = NID_secp384r1; + break; + case CryptoKeyEC::NamedCurve::P521: + curve = NID_secp521r1; + break; + } + auto publicECKey = ECKeyPtr(EC_KEY_new_by_curve_name(curve)); + if (!publicECKey) { + JSC::throwTypeError(globalObject, scope, "ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE: Failed to create a public key from private 2"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + // OPENSSL_EC_NAMED_CURVE needs to be set to export the key with the curve name, not with the curve parameters. + EC_KEY_set_asn1_flag(publicECKey.get(), OPENSSL_EC_NAMED_CURVE); + if (EC_KEY_set_public_key(publicECKey.get(), point.get()) <= 0) { + JSC::throwTypeError(globalObject, scope, "ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE: Failed to create a public key from private 3"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto publicPKey = EvpPKeyPtr(EVP_PKEY_new()); + if (EVP_PKEY_set1_EC_KEY(publicPKey.get(), publicECKey.get()) <= 0) { + JSC::throwTypeError(globalObject, scope, "ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE: Failed to create a public key from private 4"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto impl = CryptoKeyEC::create(alg, namedCurve, CryptoKeyType::Public, WTFMove(publicPKey), true, CryptoKeyUsageVerify); + + Zig::GlobalObject* zigGlobalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject); + auto* structure = zigGlobalObject->JSCryptoKeyStructure(); + + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); +} + +static JSC::EncodedJSValue KeyObject__createOKPFromPrivate(JSC::JSGlobalObject* globalObject, const WebCore::CryptoKeyOKP::KeyMaterial keyData, CryptoKeyOKP::NamedCurve namedCurve, WebCore::CryptoAlgorithmIdentifier alg) +{ + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + uint8_t public_key[ED25519_PUBLIC_KEY_LEN]; + + if (namedCurve == CryptoKeyOKP::NamedCurve::Ed25519) { + memcpy(public_key, keyData.data() + ED25519_PRIVATE_KEY_LEN, ED25519_PUBLIC_KEY_LEN); + } else { + X25519_public_from_private(public_key, keyData.data()); + } + auto result = CryptoKeyOKP::create(alg, namedCurve, CryptoKeyType::Public, Vector<uint8_t>(public_key), true, CryptoKeyUsageVerify); + if (UNLIKELY(result == nullptr)) { + JSC::throwTypeError(globalObject, scope, "ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE: Failed to create a public key from private"_s); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + + Zig::GlobalObject* zigGlobalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject); + auto* structure = zigGlobalObject->JSCryptoKeyStructure(); + + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); +} + +static JSC::EncodedJSValue KeyObject__createPublicFromPrivate(JSC::JSGlobalObject* globalObject, EVP_PKEY* pkey) +{ + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto pKeyID = EVP_PKEY_id(pkey); + if (pKeyID == EVP_PKEY_RSA || pKeyID == EVP_PKEY_RSA_PSS) { + return KeyObject__createRSAFromPrivate(globalObject, pkey, pKeyID == EVP_PKEY_RSA_PSS ? CryptoAlgorithmIdentifier::RSA_PSS : CryptoAlgorithmIdentifier::RSA_OAEP); + } else if (pKeyID == EVP_PKEY_EC) { + + EC_KEY* ec_key = EVP_PKEY_get1_EC_KEY(pkey); + if (UNLIKELY(ec_key == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid EC key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key); + // Get the curve name + int curve_name = EC_GROUP_get_curve_name(ec_group); + if (curve_name == NID_undef) { + EC_KEY_free(ec_key); + throwException(globalObject, scope, createTypeError(globalObject, "Unable to identify EC curve"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + CryptoKeyEC::NamedCurve curve; + if (curve_name == NID_X9_62_prime256v1) + curve = CryptoKeyEC::NamedCurve::P256; + else if (curve_name == NID_secp384r1) + curve = CryptoKeyEC::NamedCurve::P384; + else if (curve_name == NID_secp521r1) + curve = CryptoKeyEC::NamedCurve::P521; + else { + EC_KEY_free(ec_key); + throwException(globalObject, scope, createTypeError(globalObject, "Unsupported EC curve"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + EC_KEY_free(ec_key); + return KeyObject__createECFromPrivate(globalObject, pkey, curve, CryptoAlgorithmIdentifier::ECDSA); + } else if (pKeyID == EVP_PKEY_ED25519 || pKeyID == EVP_PKEY_X25519) { + size_t out_len = 0; + auto& vm = globalObject->vm(); + if (!EVP_PKEY_get_raw_private_key(pkey, nullptr, &out_len)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + Vector<uint8_t> out(out_len); + if (!EVP_PKEY_get_raw_private_key(pkey, out.data(), &out_len) || out_len != out.size()) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid private key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + return KeyObject__createOKPFromPrivate(globalObject, out, pKeyID == EVP_PKEY_ED25519 ? CryptoKeyOKP::NamedCurve::Ed25519 : CryptoKeyOKP::NamedCurve::X25519, CryptoAlgorithmIdentifier::Ed25519); + } else { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid private key type"_s)); + return JSValue::encode(JSC::jsUndefined()); + } +} + +JSC::EncodedJSValue KeyObject__createPublicKey(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) +{ + + auto count = callFrame->argumentCount(); + auto& vm = globalObject->vm(); + + auto scope = DECLARE_THROW_SCOPE(vm); + + if (count < 1) { + auto scope = DECLARE_THROW_SCOPE(vm); + JSC::throwTypeError(globalObject, scope, "createPublicKey requires 1 arguments"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto* options = jsDynamicCast<JSC::JSObject*>(callFrame->argument(0)); + if (!options) { + JSC::throwTypeError(globalObject, scope, "expected options to be a object"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + JSValue keyJSValue = options->getIfPropertyExists(globalObject, PropertyName(Identifier::fromString(vm, "key"_s))); + if (keyJSValue.isUndefinedOrNull() || keyJSValue.isEmpty()) { + JSC::throwTypeError(globalObject, scope, "key is required"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + Zig::GlobalObject* zigGlobalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject); + auto* structure = zigGlobalObject->JSCryptoKeyStructure(); + + void* data; + size_t byteLength; + if (auto* key = jsDynamicCast<JSCryptoKey*>(keyJSValue)) { + auto& wrapped = key->wrapped(); + auto key_type = wrapped.type(); + if (key_type != CryptoKeyType::Private) { + JSC::throwTypeError(globalObject, scope, "ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE: Invalid key object type, expected private"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto id = wrapped.keyClass(); + + switch (id) { + case CryptoKeyClass::RSA: { + return KeyObject__createRSAFromPrivate(globalObject, downcast<WebCore::CryptoKeyRSA>(wrapped).platformKey(), wrapped.algorithmIdentifier()); + } + case CryptoKeyClass::EC: { + auto& impl = downcast<WebCore::CryptoKeyEC>(wrapped); + return KeyObject__createECFromPrivate(globalObject, impl.platformKey(), impl.namedCurve(), wrapped.algorithmIdentifier()); + } + case CryptoKeyClass::OKP: { + auto& impl = downcast<WebCore::CryptoKeyOKP>(wrapped); + return KeyObject__createOKPFromPrivate(globalObject, impl.exportKey(), impl.namedCurve(), wrapped.algorithmIdentifier()); + } + default: { + JSC::throwTypeError(globalObject, scope, "ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE: Invalid key object type, expected private"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } + } + if (!keyJSValue.isCell()) { + JSC::throwTypeError(globalObject, scope, "expected options to be a object"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + JSValue formatJSValue = options->getIfPropertyExists(globalObject, PropertyName(Identifier::fromString(vm, "format"_s))); + if (formatJSValue.isUndefinedOrNull() || formatJSValue.isEmpty()) { + JSC::throwTypeError(globalObject, scope, "format is required"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + if (!formatJSValue.isString()) { + JSC::throwTypeError(globalObject, scope, "format must be a string"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto format = formatJSValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + auto keyJSValueCell = keyJSValue.asCell(); + auto type = keyJSValueCell->type(); + + switch (type) { + + case DataViewType: + case Uint8ArrayType: + case Uint8ClampedArrayType: + case Uint16ArrayType: + case Uint32ArrayType: + case Int8ArrayType: + case Int16ArrayType: + case Int32ArrayType: + case Float32ArrayType: + case Float64ArrayType: + case BigInt64ArrayType: + case BigUint64ArrayType: { + JSC::JSArrayBufferView* view = jsCast<JSC::JSArrayBufferView*>(keyJSValueCell); + + data = view->vector(); + byteLength = view->length(); + break; + } + case ArrayBufferType: { + auto* jsBuffer = jsDynamicCast<JSC::JSArrayBuffer*>(keyJSValueCell); + if (UNLIKELY(!jsBuffer)) { + auto scope = DECLARE_THROW_SCOPE(vm); + throwException(globalObject, scope, createTypeError(globalObject, "ERR_INVALID_ARG_TYPE: expected key to be Buffer or array-like object"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto* buffer = jsBuffer->impl(); + data = buffer->data(); + byteLength = buffer->byteLength(); + break; + } + default: { + if (auto* keyObj = jsDynamicCast<JSC::JSObject*>(keyJSValue)) { + if (format != "jwk"_s) { + JSC::throwTypeError(globalObject, scope, "format should be 'jwk' when key type is 'object'"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto jwk = WebCore::convertDictionary<JsonWebKey>(*globalObject, keyJSValue); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (jwk.kty == "OKP"_s) { + if (jwk.crv == "Ed25519"_s) { + auto result = CryptoKeyOKP::importPublicJwk(CryptoAlgorithmIdentifier::Ed25519, CryptoKeyOKP::NamedCurve::Ed25519, WTFMove(jwk), true, CryptoKeyUsageVerify); + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid Ed25519 public key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + if (impl->type() == CryptoKeyType::Private) { + return KeyObject__createOKPFromPrivate(globalObject, impl.get().exportKey(), CryptoKeyOKP::NamedCurve::Ed25519, CryptoAlgorithmIdentifier::Ed25519); + } + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else if (jwk.crv == "X25519"_s) { + auto result = CryptoKeyOKP::importPublicJwk(CryptoAlgorithmIdentifier::Ed25519, CryptoKeyOKP::NamedCurve::X25519, WTFMove(jwk), true, CryptoKeyUsageVerify); + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid X25519 public key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + if (impl->type() == CryptoKeyType::Private) { + return KeyObject__createOKPFromPrivate(globalObject, impl.get().exportKey(), CryptoKeyOKP::NamedCurve::X25519, CryptoAlgorithmIdentifier::Ed25519); + } + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else { + throwException(globalObject, scope, createTypeError(globalObject, "Unsupported OKP curve"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + } else if (jwk.kty == "EC"_s) { + auto result = CryptoKeyEC::importJwk(CryptoAlgorithmIdentifier::ECDSA, jwk.crv, WTFMove(jwk), true, jwk.usages); + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid EC public key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + if (impl->type() == CryptoKeyType::Private) { + return KeyObject__createECFromPrivate(globalObject, impl.get().platformKey(), impl.get().namedCurve(), CryptoAlgorithmIdentifier::ECDSA); + } + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else if (jwk.kty == "RSA"_s) { + auto result = CryptoKeyRSA::importJwk(CryptoAlgorithmIdentifier::RSA_OAEP, std::nullopt, WTFMove(jwk), true, jwk.usages); + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid RSA public key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + if (impl->type() == CryptoKeyType::Private) { + return KeyObject__createRSAFromPrivate(globalObject, impl.get().platformKey(), CryptoAlgorithmIdentifier::RSA_OAEP); + } + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else { + throwException(globalObject, scope, createTypeError(globalObject, "Unsupported public key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + } + } + } + + if (format == "jwk"_s) { + JSC::throwTypeError(globalObject, scope, "The \"key\" property must be of type object"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + if (UNLIKELY(!data) || UNLIKELY(!byteLength)) { + throwException(globalObject, scope, createTypeError(globalObject, "ERR_INVALID_ARG_TYPE: expected key to be Buffer or array-like object"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + + if (format == "pem"_s) { + auto pem = KeyObject__ParsePublicKeyPEM((const char*)data, byteLength); + if (!pem.key) { + // maybe is a private pem + auto bio = BIOPtr(BIO_new_mem_buf(const_cast<char*>((char*)data), byteLength)); + JSValue passphraseJSValue = options->getIfPropertyExists(globalObject, PropertyName(Identifier::fromString(vm, "passphrase"_s))); + PrivateKeyPassphrase passphrase = { nullptr, 0 }; + + auto hasPassphrase = !passphraseJSValue.isUndefinedOrNull() && !passphraseJSValue.isEmpty(); + + if (hasPassphrase) { + if (passphraseJSValue.isString()) { + auto passphrase_wtfstr = passphraseJSValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (!passphrase_wtfstr.isNull()) { + if (auto pass = passphrase_wtfstr.tryGetUTF8()) { + if (pass.has_value()) { + auto value = pass.value(); + passphrase.passphrase = const_cast<char*>(value.data()); + passphrase.passphrase_len = value.length(); + } + } + } + } else if (auto* passphraseBuffer = jsDynamicCast<JSUint8Array*>(passphraseJSValue)) { + passphrase.passphrase = (char*)passphraseBuffer->vector(); + passphrase.passphrase_len = passphraseBuffer->byteLength(); + } else { + JSC::throwTypeError(globalObject, scope, "passphrase must be a Buffer or String"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } + + auto pkey = EvpPKeyPtr(PEM_read_bio_PrivateKey(bio.get(), nullptr, PasswordCallback, &passphrase)); + if (!pkey) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid PEM data"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + return KeyObject__createPublicFromPrivate(globalObject, pkey.get()); + } + auto pkey = EvpPKeyPtr(pem.key); + auto pKeyID = EVP_PKEY_id(pem.key); + if (pKeyID == EVP_PKEY_RSA || pKeyID == EVP_PKEY_RSA_PSS) { + if (pem.der_data) { + OPENSSL_clear_free(pem.der_data, pem.der_len); + } + auto impl = CryptoKeyRSA::create(pKeyID == EVP_PKEY_RSA_PSS ? CryptoAlgorithmIdentifier::RSA_PSS : CryptoAlgorithmIdentifier::RSA_OAEP, CryptoAlgorithmIdentifier::SHA_1, false, CryptoKeyType::Public, WTFMove(pkey), true, CryptoKeyUsageEncrypt); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else if (pKeyID == EVP_PKEY_ED25519) { + auto result = CryptoKeyOKP::importSpki(CryptoAlgorithmIdentifier::Ed25519, CryptoKeyOKP::NamedCurve::Ed25519, Vector<uint8_t>((uint8_t*)pem.der_data, (size_t)pem.der_len), true, CryptoKeyUsageVerify); + if (pem.der_data) { + OPENSSL_clear_free(pem.der_data, pem.der_len); + } + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid Ed25519 public key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else if (pKeyID == EVP_PKEY_X25519) { + auto result = CryptoKeyOKP::importSpki(CryptoAlgorithmIdentifier::Ed25519, CryptoKeyOKP::NamedCurve::X25519, Vector<uint8_t>((uint8_t*)pem.der_data, (size_t)pem.der_len), true, CryptoKeyUsageVerify); + if (pem.der_data) { + OPENSSL_clear_free(pem.der_data, pem.der_len); + } + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid Ed25519 public key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else if (pKeyID == EVP_PKEY_EC) { + EC_KEY* ec_key = EVP_PKEY_get1_EC_KEY(pkey.get()); + if (UNLIKELY(ec_key == nullptr)) { + if (pem.der_data) { + OPENSSL_clear_free(pem.der_data, pem.der_len); + } + throwException(globalObject, scope, createTypeError(globalObject, "Invalid EC public key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key); + // Get the curve name + int curve_name = EC_GROUP_get_curve_name(ec_group); + if (curve_name == NID_undef) { + if (pem.der_data) { + OPENSSL_clear_free(pem.der_data, pem.der_len); + } + EC_KEY_free(ec_key); + throwException(globalObject, scope, createTypeError(globalObject, "Unable to identify EC curve"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + CryptoKeyEC::NamedCurve curve; + if (curve_name == NID_X9_62_prime256v1) + curve = CryptoKeyEC::NamedCurve::P256; + else if (curve_name == NID_secp384r1) + curve = CryptoKeyEC::NamedCurve::P384; + else if (curve_name == NID_secp521r1) + curve = CryptoKeyEC::NamedCurve::P521; + else { + if (pem.der_data) { + OPENSSL_clear_free(pem.der_data, pem.der_len); + } + EC_KEY_free(ec_key); + throwException(globalObject, scope, createTypeError(globalObject, "Unsupported EC curve"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto result = CryptoKeyEC::platformImportSpki(CryptoAlgorithmIdentifier::ECDH, curve, Vector<uint8_t>((uint8_t*)pem.der_data, (size_t)pem.der_len), true, CryptoKeyUsageVerify); + if (UNLIKELY(result == nullptr)) { + result = CryptoKeyEC::platformImportSpki(CryptoAlgorithmIdentifier::ECDSA, curve, Vector<uint8_t>((uint8_t*)pem.der_data, (size_t)pem.der_len), true, CryptoKeyUsageVerify); + } + if (pem.der_data) { + OPENSSL_clear_free(pem.der_data, pem.der_len); + } + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid EC public key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else { + if (pem.der_data) { + OPENSSL_clear_free(pem.der_data, pem.der_len); + } + throwException(globalObject, scope, createTypeError(globalObject, "Unsupported public key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + } + if (format == "der"_s) { + JSValue typeJSValue = options->getIfPropertyExists(globalObject, PropertyName(Identifier::fromString(vm, "type"_s))); + WTF::String type = "spki"_s; + if (!typeJSValue.isUndefinedOrNull() && !typeJSValue.isEmpty()) { + if (!typeJSValue.isString()) { + JSC::throwTypeError(globalObject, scope, "type must be a string"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + type = typeJSValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + } + + if (type == "pkcs1"_s) { + // must be RSA + const unsigned char* p = reinterpret_cast<const unsigned char*>(data); + auto pkey = EvpPKeyPtr(d2i_PublicKey(EVP_PKEY_RSA, nullptr, &p, byteLength)); + if (!pkey) { + // maybe is a private RSA key + const unsigned char* p = reinterpret_cast<const unsigned char*>(data); + pkey = EvpPKeyPtr(d2i_PrivateKey(EVP_PKEY_RSA, nullptr, &p, byteLength)); + if (!pkey) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid PKCS#1"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + + auto pKeyID = EVP_PKEY_id(pkey.get()); + return KeyObject__createRSAFromPrivate(globalObject, pkey.get(), pKeyID == EVP_PKEY_RSA_PSS ? CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5 : CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5); + } + + auto pKeyID = EVP_PKEY_id(pkey.get()); + auto impl = CryptoKeyRSA::create(pKeyID == EVP_PKEY_RSA_PSS ? CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5 : CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5, CryptoAlgorithmIdentifier::SHA_1, false, CryptoKeyType::Public, WTFMove(pkey), true, CryptoKeyUsageEncrypt); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else if (type == "spki"_s) { + // We use d2i_PUBKEY() to import a public key. + const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data); + auto pkey = EvpPKeyPtr(d2i_PUBKEY(nullptr, &ptr, byteLength)); + if (!pkey) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid public key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto pKeyID = EVP_PKEY_id(pkey.get()); + + if (pKeyID == EVP_PKEY_RSA || pKeyID == EVP_PKEY_RSA_PSS) { + auto impl = CryptoKeyRSA::create(pKeyID == EVP_PKEY_RSA_PSS ? CryptoAlgorithmIdentifier::RSA_PSS : CryptoAlgorithmIdentifier::RSA_OAEP, CryptoAlgorithmIdentifier::SHA_1, false, CryptoKeyType::Public, WTFMove(pkey), true, CryptoKeyUsageEncrypt); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else if (pKeyID == EVP_PKEY_ED25519) { + auto result = CryptoKeyOKP::importSpki(CryptoAlgorithmIdentifier::Ed25519, CryptoKeyOKP::NamedCurve::Ed25519, Vector<uint8_t>((uint8_t*)data, byteLength), true, CryptoKeyUsageVerify); + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid Ed25519 public key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else if (pKeyID == EVP_PKEY_X25519) { + auto result = CryptoKeyOKP::importSpki(CryptoAlgorithmIdentifier::Ed25519, CryptoKeyOKP::NamedCurve::X25519, Vector<uint8_t>((uint8_t*)data, byteLength), true, CryptoKeyUsageVerify); + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid Ed25519 public key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else if (pKeyID == EVP_PKEY_EC) { + EC_KEY* ec_key = EVP_PKEY_get1_EC_KEY(pkey.get()); + if (UNLIKELY(ec_key == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid EC public key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key); + // Get the curve name + int curve_name = EC_GROUP_get_curve_name(ec_group); + if (curve_name == NID_undef) { + EC_KEY_free(ec_key); + throwException(globalObject, scope, createTypeError(globalObject, "Unable to identify EC curve"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + CryptoKeyEC::NamedCurve curve; + if (curve_name == NID_X9_62_prime256v1) + curve = CryptoKeyEC::NamedCurve::P256; + else if (curve_name == NID_secp384r1) + curve = CryptoKeyEC::NamedCurve::P384; + else if (curve_name == NID_secp521r1) + curve = CryptoKeyEC::NamedCurve::P521; + else { + EC_KEY_free(ec_key); + throwException(globalObject, scope, createTypeError(globalObject, "Unsupported EC curve"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto alg = CryptoAlgorithmIdentifier::ECDH; + auto result = CryptoKeyEC::platformImportSpki(alg, curve, Vector<uint8_t>((uint8_t*)data, byteLength), true, CryptoKeyUsageVerify); + if (UNLIKELY(result == nullptr)) { + alg = CryptoAlgorithmIdentifier::ECDSA; + result = CryptoKeyEC::platformImportSpki(CryptoAlgorithmIdentifier::ECDSA, curve, Vector<uint8_t>((uint8_t*)data, byteLength), true, CryptoKeyUsageVerify); + } + if (UNLIKELY(result == nullptr)) { + throwException(globalObject, scope, createTypeError(globalObject, "Invalid EC public key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto impl = result.releaseNonNull(); + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(impl))); + } else { + throwException(globalObject, scope, createTypeError(globalObject, "Unsupported public key"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + } + + JSC::throwTypeError(globalObject, scope, "type should be 'pkcs1' or 'spki'"_s); + return JSValue::encode(JSC::jsUndefined()); + } + JSC::throwTypeError(globalObject, scope, "format should be 'pem' or 'der'"_s); + return JSValue::encode(JSC::jsUndefined()); +} + +JSC::EncodedJSValue KeyObject__createSecretKey(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame) +{ + + JSValue bufferArg = callFrame->uncheckedArgument(0); + auto& vm = lexicalGlobalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto* structure = globalObject->JSCryptoKeyStructure(); + + if (!bufferArg.isCell()) { + throwException(lexicalGlobalObject, scope, createTypeError(lexicalGlobalObject, "ERR_INVALID_ARG_TYPE: expected Buffer or array-like object"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + + auto bufferArgCell = bufferArg.asCell(); + auto type = bufferArgCell->type(); + + switch (type) { + + case DataViewType: + case Uint8ArrayType: + case Uint8ClampedArrayType: + case Uint16ArrayType: + case Uint32ArrayType: + case Int8ArrayType: + case Int16ArrayType: + case Int32ArrayType: + case Float32ArrayType: + case Float64ArrayType: + case BigInt64ArrayType: + case BigUint64ArrayType: { + JSC::JSArrayBufferView* view = jsCast<JSC::JSArrayBufferView*>(bufferArgCell); + + void* data = view->vector(); + size_t byteLength = view->length(); + if (UNLIKELY(!data)) { + break; + } + auto impl = CryptoKeyHMAC::generateFromBytes(data, byteLength, CryptoAlgorithmIdentifier::HMAC, true, CryptoKeyUsageSign | CryptoKeyUsageVerify).releaseNonNull(); + return JSC::JSValue::encode(JSCryptoKey::create(structure, globalObject, WTFMove(impl))); + } + case ArrayBufferType: { + auto* jsBuffer = jsDynamicCast<JSC::JSArrayBuffer*>(bufferArgCell); + if (UNLIKELY(!jsBuffer)) { + break; + } + auto* buffer = jsBuffer->impl(); + void* data = buffer->data(); + size_t byteLength = buffer->byteLength(); + if (UNLIKELY(!data)) { + break; + } + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto impl = CryptoKeyHMAC::generateFromBytes(data, byteLength, CryptoAlgorithmIdentifier::HMAC, true, CryptoKeyUsageSign | CryptoKeyUsageVerify).releaseNonNull(); + return JSC::JSValue::encode(JSCryptoKey::create(structure, globalObject, WTFMove(impl))); + } + default: + throwException(lexicalGlobalObject, scope, createTypeError(lexicalGlobalObject, "ERR_INVALID_ARG_TYPE: expected Buffer or array-like object"_s)); + return JSValue::encode(JSC::jsUndefined()); + } +} + +JSC::EncodedJSValue KeyObject__Exports(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) +{ + + auto count = callFrame->argumentCount(); + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (count < 2) { + JSC::throwTypeError(globalObject, scope, "exports requires 2 arguments"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + auto* key = jsDynamicCast<JSCryptoKey*>(callFrame->argument(0)); + if (!key) { + // No JSCryptoKey instance + JSC::throwTypeError(globalObject, scope, "expected CryptoKey as first argument"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + auto& wrapped = key->wrapped(); + auto key_type = wrapped.type(); + auto id = wrapped.keyClass(); + if (auto* options = jsDynamicCast<JSC::JSObject*>(callFrame->argument(1))) { + JSValue formatJSValue = options->getIfPropertyExists(globalObject, PropertyName(Identifier::fromString(vm, "format"_s))); + JSValue typeJSValue = options->getIfPropertyExists(globalObject, PropertyName(Identifier::fromString(vm, "type"_s))); + JSValue passphraseJSValue = options->getIfPropertyExists(globalObject, PropertyName(Identifier::fromString(vm, "passphrase"_s))); + auto hasPassphrase = !passphraseJSValue.isUndefinedOrNull() && !passphraseJSValue.isEmpty(); + if (formatJSValue.isUndefinedOrNull() || formatJSValue.isEmpty()) { + JSC::throwTypeError(globalObject, scope, "format is expected to be a string"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + auto string = formatJSValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (string == "jwk"_s && hasPassphrase) { + JSC::throwTypeError(globalObject, scope, "encryption is not supported for jwk format"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + switch (id) { + case CryptoKeyClass::HMAC: { + const auto& hmac = downcast<WebCore::CryptoKeyHMAC>(wrapped); + if (string == "buffer"_s) { + auto keyData = hmac.key(); + auto size = keyData.size(); + auto* buffer = jsCast<JSUint8Array*>(JSValue::decode(JSBuffer__bufferFromLength(globalObject, size))); + if (size > 0) + memcpy(buffer->vector(), keyData.data(), size); + + return JSC::JSValue::encode(buffer); + } else if (string == "jwk"_s) { + const JsonWebKey& jwkValue = hmac.exportJwk(); + Zig::GlobalObject* domGlobalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject); + return JSC::JSValue::encode(WebCore::convertDictionaryToJS(*globalObject, *domGlobalObject, jwkValue, true)); + } + break; + } + case CryptoKeyClass::AES: { + const auto& aes = downcast<WebCore::CryptoKeyAES>(wrapped); + if (string == "buffer"_s) { + auto keyData = aes.key(); + auto size = keyData.size(); + auto* buffer = jsCast<JSUint8Array*>(JSValue::decode(JSBuffer__bufferFromLength(globalObject, size))); + if (size > 0) + memcpy(buffer->vector(), keyData.data(), size); + + return JSC::JSValue::encode(buffer); + } else if (string == "jwk"_s) { + const JsonWebKey& jwkValue = aes.exportJwk(); + Zig::GlobalObject* domGlobalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject); + return JSC::JSValue::encode(WebCore::convertDictionaryToJS(*globalObject, *domGlobalObject, jwkValue, true)); + } + break; + } + case CryptoKeyClass::RSA: { + const auto& rsa = downcast<WebCore::CryptoKeyRSA>(wrapped); + if (string == "jwk"_s) { + const JsonWebKey& jwkValue = rsa.exportJwk(); + Zig::GlobalObject* domGlobalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject); + return JSC::JSValue::encode(WebCore::convertDictionaryToJS(*globalObject, *domGlobalObject, jwkValue, true)); + } else { + WTF::String type = "pkcs1"_s; + if (!typeJSValue.isUndefinedOrNull() && !typeJSValue.isEmpty()) { + if (!typeJSValue.isString()) { + JSC::throwTypeError(globalObject, scope, "type must be a string"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + type = typeJSValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + } + + auto* bio = BIO_new(BIO_s_mem()); + auto* rsaKey = rsa.platformKey(); + auto* rsa_ptr = EVP_PKEY_get0_RSA(rsaKey); + + if (key_type == CryptoKeyType::Public) { + if (string == "pem"_s) { + if (type == "pkcs1"_s) { + if (PEM_write_bio_RSAPublicKey(bio, rsa_ptr) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write public key"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else if (type == "spki"_s) { + if (PEM_write_bio_PUBKEY(bio, rsaKey) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write public key"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "type should be 'pkcs1' or 'spki'"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + } else if (string == "der"_s) { + if (type == "pkcs1"_s) { + if (i2d_RSAPublicKey_bio(bio, rsa_ptr) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write public key"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else if (type == "spki"_s) { + if (i2d_PUBKEY_bio(bio, rsaKey) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write public key"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "type should be 'pkcs1' or 'spki'"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "format expected to be 'der', 'pem' or 'jwk'"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSValue cipherJSValue = options->getIfPropertyExists(globalObject, PropertyName(Identifier::fromString(vm, "cipher"_s))); + + const EVP_CIPHER* cipher = nullptr; + if (!cipherJSValue.isUndefinedOrNull() && !cipherJSValue.isEmpty() && cipherJSValue.isString()) { + auto cipher_wtfstr = cipherJSValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (!cipher_wtfstr.isNull()) { + auto cipherOrError = cipher_wtfstr.tryGetUTF8(); + if (!cipherOrError.has_value()) { + JSC::throwTypeError(globalObject, scope, "invalid cipher name"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } else { + auto value = cipherOrError.value(); + auto cipher_str = value.data(); + if (cipher_str != nullptr) { + cipher = EVP_get_cipherbyname(cipher_str); + } + } + } + } + void* passphrase = nullptr; + size_t passphrase_len = 0; + if (hasPassphrase) { + if (!cipher) { + JSC::throwTypeError(globalObject, scope, "cipher is required when passphrase is specified"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + if (passphraseJSValue.isString()) { + auto passphrase_wtfstr = passphraseJSValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (!passphrase_wtfstr.isNull()) { + if (auto pass = passphrase_wtfstr.tryGetUTF8()) { + if (pass.has_value()) { + auto value = pass.value(); + passphrase = const_cast<char*>(value.data()); + passphrase_len = value.length(); + } + } + } + } else if (auto* passphraseBuffer = jsDynamicCast<JSUint8Array*>(passphraseJSValue)) { + passphrase = passphraseBuffer->vector(); + passphrase_len = passphraseBuffer->byteLength(); + } else { + JSC::throwTypeError(globalObject, scope, "passphrase must be a Buffer or String"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } + + if (string == "pem"_s) { + if (type == "pkcs1"_s) { + if (PEM_write_bio_RSAPrivateKey(bio, rsa_ptr, cipher, (unsigned char*)passphrase, passphrase_len, nullptr, nullptr) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write private key"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else if (type == "pkcs8"_s) { + if (PEM_write_bio_PKCS8PrivateKey(bio, rsaKey, cipher, (char*)passphrase, passphrase_len, nullptr, nullptr) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write private key"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "type should be 'pkcs1' or 'pkcs8'"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else if (string == "der"_s) { + if (type == "pkcs1"_s) { + if (i2d_RSAPrivateKey_bio(bio, rsa_ptr) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write private key"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else if (type == "pkcs8"_s) { + if (i2d_PKCS8PrivateKey_bio(bio, rsaKey, cipher, (char*)passphrase, passphrase_len, nullptr, nullptr) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write private key"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "type should be 'pkcs1' or 'pkcs8'"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "format expected to be 'der', 'pem' or 'jwk'"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } + + BUF_MEM* bptr; + BIO_get_mem_ptr(bio, &bptr); + auto length = bptr->length; + if (string == "pem"_s) { + auto str = WTF::String::fromUTF8(bptr->data, length); + return JSValue::encode(JSC::jsString(vm, str)); + } + + auto* buffer = jsCast<JSUint8Array*>(JSValue::decode(JSBuffer__bufferFromLength(globalObject, length))); + if (length > 0) + memcpy(buffer->vector(), bptr->data, length); + + BIO_free(bio); + return JSC::JSValue::encode(buffer); + } + } + case CryptoKeyClass::EC: { + const auto& ec = downcast<WebCore::CryptoKeyEC>(wrapped); + if (string == "jwk"_s) { + auto result = ec.exportJwk(); + if (result.hasException()) { + WebCore::propagateException(*globalObject, scope, result.releaseException()); + return JSC::JSValue::encode(JSC::JSValue {}); + } + const JsonWebKey& jwkValue = result.releaseReturnValue(); + Zig::GlobalObject* domGlobalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject); + return JSC::JSValue::encode(WebCore::convertDictionaryToJS(*globalObject, *domGlobalObject, jwkValue, true)); + } else { + WTF::String type = "spki"_s; + if (!typeJSValue.isUndefinedOrNull() && !typeJSValue.isEmpty()) { + if (!typeJSValue.isString()) { + JSC::throwTypeError(globalObject, scope, "type must be a string"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + type = typeJSValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + } + + auto* bio = BIO_new(BIO_s_mem()); + auto* ecKey = ec.platformKey(); + auto* ec_ptr = EVP_PKEY_get1_EC_KEY(ecKey); + + if (key_type == CryptoKeyType::Public) { + if (string == "pem"_s) { + if (type == "spki"_s) { + if (PEM_write_bio_PUBKEY(bio, ecKey) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write public key"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "type should be 'spki'"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + } else if (string == "der"_s) { + if (type == "spki"_s) { + if (i2d_PUBKEY_bio(bio, ecKey) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write public key"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "type should be 'spki'"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "format expected to be 'der', 'pem' or 'jwk'"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSValue passphraseJSValue = options->getIfPropertyExists(globalObject, PropertyName(Identifier::fromString(vm, "passphrase"_s))); + JSValue cipherJSValue = options->getIfPropertyExists(globalObject, PropertyName(Identifier::fromString(vm, "cipher"_s))); + + const EVP_CIPHER* cipher = nullptr; + if (!cipherJSValue.isUndefinedOrNull() && !cipherJSValue.isEmpty()) { + auto cipher_wtfstr = cipherJSValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (!cipher_wtfstr.isNull()) { + auto cipherOrError = cipher_wtfstr.tryGetUTF8(); + if (!cipherOrError.has_value()) { + JSC::throwTypeError(globalObject, scope, "invalid cipher name"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } else { + auto value = cipherOrError.value(); + auto cipher_str = value.data(); + if (cipher_str != nullptr) { + cipher = EVP_get_cipherbyname(cipher_str); + } + } + } + } + void* passphrase = nullptr; + size_t passphrase_len = 0; + auto hasPassphrase = !passphraseJSValue.isUndefinedOrNull() && !passphraseJSValue.isEmpty(); + + if (hasPassphrase) { + if (!cipher) { + JSC::throwTypeError(globalObject, scope, "cipher is required when passphrase is specified"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + if (passphraseJSValue.isString()) { + auto passphrase_wtfstr = passphraseJSValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (!passphrase_wtfstr.isNull()) { + if (auto pass = passphrase_wtfstr.tryGetUTF8()) { + if (pass.has_value()) { + auto value = pass.value(); + passphrase = const_cast<char*>(value.data()); + passphrase_len = value.length(); + } + } + } + } else if (auto* passphraseBuffer = jsDynamicCast<JSUint8Array*>(passphraseJSValue)) { + passphrase = passphraseBuffer->vector(); + passphrase_len = passphraseBuffer->byteLength(); + } else { + JSC::throwTypeError(globalObject, scope, "passphrase must be a Buffer or String"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } + + if (string == "pem"_s) { + if (type == "sec1"_s) { + if (PEM_write_bio_ECPrivateKey(bio, ec_ptr, cipher, (unsigned char*)passphrase, passphrase_len, nullptr, nullptr) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write private key"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else if (type == "pkcs8"_s) { + if (PEM_write_bio_PKCS8PrivateKey(bio, ecKey, cipher, (char*)passphrase, passphrase_len, nullptr, nullptr) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write private key"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "type should be 'sec1' or 'pkcs8'"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else if (string == "der"_s) { + if (type == "sec1"_s) { + if (i2d_ECPrivateKey_bio(bio, ec_ptr) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write private key"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else if (type == "pkcs8"_s) { + if (i2d_PKCS8PrivateKey_bio(bio, ecKey, cipher, (char*)passphrase, passphrase_len, nullptr, nullptr) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write private key"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "type should be 'sec1' or 'pkcs8'"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "format expected to be 'der', 'pem' or 'jwk'"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } + + BUF_MEM* bptr; + BIO_get_mem_ptr(bio, &bptr); + auto length = bptr->length; + if (string == "pem"_s) { + auto str = WTF::String::fromUTF8(bptr->data, length); + return JSValue::encode(JSC::jsString(vm, str)); + } + + auto* buffer = jsCast<JSUint8Array*>(JSValue::decode(JSBuffer__bufferFromLength(globalObject, length))); + if (length > 0) + memcpy(buffer->vector(), bptr->data, length); + + BIO_free(bio); + return JSC::JSValue::encode(buffer); + } + } + case CryptoKeyClass::OKP: { + const auto& okpKey = downcast<WebCore::CryptoKeyOKP>(wrapped); + if (string == "jwk"_s) { + auto result = okpKey.exportJwk(); + if (result.hasException()) { + WebCore::propagateException(*globalObject, scope, result.releaseException()); + return JSC::JSValue::encode(JSC::JSValue {}); + } + const JsonWebKey& jwkValue = result.releaseReturnValue(); + Zig::GlobalObject* domGlobalObject = reinterpret_cast<Zig::GlobalObject*>(globalObject); + return JSC::JSValue::encode(WebCore::convertDictionaryToJS(*globalObject, *domGlobalObject, jwkValue, true)); + } else { + WTF::String type = "pkcs8"_s; + if (!typeJSValue.isUndefinedOrNull() && !typeJSValue.isEmpty()) { + if (!typeJSValue.isString()) { + JSC::throwTypeError(globalObject, scope, "type must be a string"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + type = typeJSValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + } + + auto keyData = okpKey.exportKey(); + auto* bio = BIO_new(BIO_s_mem()); + + EVP_PKEY* evpKey; + // TODO: CHECK THIS WHEN X488 AND ED448 ARE ADDED + if (okpKey.type() == CryptoKeyType::Private) { + evpKey = EVP_PKEY_new_raw_private_key(okpKey.namedCurve() == CryptoKeyOKP::NamedCurve::X25519 ? EVP_PKEY_X25519 : EVP_PKEY_ED25519, nullptr, keyData.data(), keyData.size()); + JSValue passphraseJSValue = options->getIfPropertyExists(globalObject, PropertyName(Identifier::fromString(vm, "passphrase"_s))); + JSValue cipherJSValue = options->getIfPropertyExists(globalObject, PropertyName(Identifier::fromString(vm, "cipher"_s))); + + const EVP_CIPHER* cipher = nullptr; + if (!cipherJSValue.isUndefinedOrNull() && !cipherJSValue.isEmpty() && cipherJSValue.isString()) { + auto cipher_wtfstr = cipherJSValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (!cipher_wtfstr.isNull()) { + auto cipherOrError = cipher_wtfstr.tryGetUTF8(); + if (!cipherOrError.has_value()) { + JSC::throwTypeError(globalObject, scope, "invalid cipher name"_s); + BIO_free(bio); + EVP_PKEY_free(evpKey); + return JSC::JSValue::encode(JSC::JSValue {}); + } else { + auto value = cipherOrError.value(); + auto cipher_str = value.data(); + if (cipher_str != nullptr) { + cipher = EVP_get_cipherbyname(cipher_str); + } + } + } + } + void* passphrase = nullptr; + size_t passphrase_len = 0; + auto hasPassphrase = !passphraseJSValue.isUndefinedOrNull() && !passphraseJSValue.isEmpty(); + + if (hasPassphrase) { + if (!cipher) { + JSC::throwTypeError(globalObject, scope, "cipher is required when passphrase is specified"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + if (passphraseJSValue.isString()) { + auto passphrase_wtfstr = passphraseJSValue.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (!passphrase_wtfstr.isNull()) { + if (auto pass = passphrase_wtfstr.tryGetUTF8()) { + if (pass.has_value()) { + auto value = pass.value(); + passphrase = const_cast<char*>(value.data()); + passphrase_len = value.length(); + } + } + } + } else if (auto* passphraseBuffer = jsDynamicCast<JSUint8Array*>(passphraseJSValue)) { + passphrase = passphraseBuffer->vector(); + passphrase_len = passphraseBuffer->byteLength(); + } else { + JSC::throwTypeError(globalObject, scope, "passphrase must be a Buffer or String"_s); + BIO_free(bio); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } + + if (string == "pem"_s) { + if (type == "pkcs8"_s) { + if (PEM_write_bio_PKCS8PrivateKey(bio, evpKey, cipher, (char*)passphrase, passphrase_len, nullptr, nullptr) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write private key"_s); + BIO_free(bio); + EVP_PKEY_free(evpKey); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "type should be 'pkcs8'"_s); + BIO_free(bio); + EVP_PKEY_free(evpKey); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else if (string == "der"_s) { + if (type == "pkcs8"_s) { + if (i2d_PKCS8PrivateKey_bio(bio, evpKey, cipher, (char*)passphrase, passphrase_len, nullptr, nullptr) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write private key"_s); + BIO_free(bio); + EVP_PKEY_free(evpKey); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "type should be 'pkcs8'"_s); + BIO_free(bio); + EVP_PKEY_free(evpKey); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "format expected to be 'der', 'pem' or 'jwk'"_s); + BIO_free(bio); + EVP_PKEY_free(evpKey); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + evpKey = EVP_PKEY_new_raw_public_key(okpKey.namedCurve() == CryptoKeyOKP::NamedCurve::X25519 ? EVP_PKEY_X25519 : EVP_PKEY_ED25519, nullptr, keyData.data(), keyData.size()); + if (string == "pem"_s) { + if (type == "spki"_s) { + if (PEM_write_bio_PUBKEY(bio, evpKey) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write public key"_s); + BIO_free(bio); + EVP_PKEY_free(evpKey); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "type should be 'spki'"_s); + BIO_free(bio); + EVP_PKEY_free(evpKey); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + } else if (string == "der"_s) { + if (type == "spki"_s) { + if (i2d_PUBKEY_bio(bio, evpKey) != 1) { + JSC::throwTypeError(globalObject, scope, "Failed to write public key"_s); + BIO_free(bio); + EVP_PKEY_free(evpKey); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "type should be 'spki'"_s); + BIO_free(bio); + EVP_PKEY_free(evpKey); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } else { + JSC::throwTypeError(globalObject, scope, "format expected to be 'der', 'pem' or 'jwk'"_s); + BIO_free(bio); + EVP_PKEY_free(evpKey); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } + + BUF_MEM* bptr; + BIO_get_mem_ptr(bio, &bptr); + auto length = bptr->length; + if (string == "pem"_s) { + auto str = WTF::String::fromUTF8(bptr->data, length); + EVP_PKEY_free(evpKey); + return JSValue::encode(JSC::jsString(vm, str)); + } + + auto* buffer = jsCast<JSUint8Array*>(JSValue::decode(JSBuffer__bufferFromLength(globalObject, length))); + if (length > 0) + memcpy(buffer->vector(), bptr->data, length); + + BIO_free(bio); + EVP_PKEY_free(evpKey); + return JSC::JSValue::encode(buffer); + } + } + case CryptoKeyClass::Raw: { + const auto& raw = downcast<WebCore::CryptoKeyRaw>(wrapped); + if (string == "buffer"_s) { + auto keyData = raw.key(); + auto size = keyData.size(); + auto* buffer = jsCast<JSUint8Array*>(JSValue::decode(JSBuffer__bufferFromLength(globalObject, size))); + if (size > 0) + memcpy(buffer->vector(), keyData.data(), size); + + return JSC::JSValue::encode(buffer); + } + + JSC::throwTypeError(globalObject, scope, "format is expected to be 'buffer'"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + default: { + JSC::throwTypeError(globalObject, scope, "Invalid Operation"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + } + JSC::throwTypeError(globalObject, scope, "format is expected to be 'buffer' or 'jwk'"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } else { + JSC::throwTypeError(globalObject, scope, "expected options to be a object"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } +} + +static char* bignum_to_string(const BIGNUM* bn) +{ + char *tmp, *ret; + size_t len; + + // Display large numbers in hex and small numbers in decimal. Converting to + // decimal takes quadratic time and is no more useful than hex for large + // numbers. + if (BN_num_bits(bn) < 32) { + return BN_bn2dec(bn); + } + + tmp = BN_bn2hex(bn); + if (tmp == NULL) { + return NULL; + } + + len = strlen(tmp) + 3; + ret = (char*)OPENSSL_malloc(len); + if (ret == NULL) { + OPENSSL_free(tmp); + return NULL; + } + + // Prepend "0x", but place it after the "-" if negative. + if (tmp[0] == '-') { + OPENSSL_strlcpy(ret, "-0x", len); + OPENSSL_strlcat(ret, tmp + 1, len); + } else { + OPENSSL_strlcpy(ret, "0x", len); + OPENSSL_strlcat(ret, tmp, len); + } + OPENSSL_free(tmp); + return ret; +} + +JSC::EncodedJSValue KeyObject_AsymmetricKeyDetails(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame) +{ + + if (auto* key = jsDynamicCast<JSCryptoKey*>(callFrame->argument(0))) { + auto id = key->wrapped().algorithmIdentifier(); + auto& vm = lexicalGlobalObject->vm(); + switch (id) { + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSA_OAEP: + case CryptoAlgorithmIdentifier::RSA_PSS: { + auto* obj = JSC::constructEmptyObject(lexicalGlobalObject); + + auto& wrapped = key->wrapped(); + const auto& rsa = downcast<WebCore::CryptoKeyRSA>(wrapped); + auto* platformKey = rsa.platformKey(); + const BIGNUM* e; // Public Exponent + const BIGNUM* n; // Modulus + const RSA* rsa_key = EVP_PKEY_get0_RSA(platformKey); + if (rsa_key == nullptr) { + return JSValue::encode(JSC::jsUndefined()); + } + + RSA_get0_key(rsa_key, &n, &e, nullptr); + + auto modulus_length = BN_num_bits(n); + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "modulusLength"_s)), jsNumber(modulus_length), 0); + + auto str = bignum_to_string(e); + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "publicExponent"_s)), JSC::JSBigInt::stringToBigInt(lexicalGlobalObject, StringView::fromLatin1(str)), 0); + OPENSSL_free(str); + + if (id == CryptoAlgorithmIdentifier::RSA_PSS) { + // Due to the way ASN.1 encoding works, default values are omitted when + // encoding the data structure. However, there are also RSA-PSS keys for + // which no parameters are set. In that case, the ASN.1 RSASSA-PSS-params + // sequence will be missing entirely and RSA_get0_pss_params will return + // nullptr. If parameters are present but all parameters are set to their + // default values, an empty sequence will be stored in the ASN.1 structure. + // In that case, RSA_get0_pss_params does not return nullptr but all fields + // of the returned RSA_PSS_PARAMS will be set to nullptr. + + auto* params = RSA_get0_pss_params(rsa_key); + if (params != nullptr) { + int hash_nid = NID_sha1; + int mgf_nid = NID_mgf1; + int mgf1_hash_nid = NID_sha1; + int64_t salt_length = 20; + + if (params->hashAlgorithm != nullptr) { + hash_nid = OBJ_obj2nid(params->hashAlgorithm->algorithm); + } + auto* hash_srt = OBJ_nid2ln(hash_nid); + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "hashAlgorithm"_s)), Bun::toJS(lexicalGlobalObject, Bun::toString(hash_srt, strlen(hash_srt))), 0); + if (params->maskGenAlgorithm != nullptr) { + mgf_nid = OBJ_obj2nid(params->maskGenAlgorithm->algorithm); + if (mgf_nid == NID_mgf1) { + mgf1_hash_nid = OBJ_obj2nid(params->maskHash->algorithm); + } + } + + // If, for some reason, the MGF is not MGF1, then the MGF1 hash function + // is intentionally not added to the object. + if (mgf_nid == NID_mgf1) { + auto* mgf1_hash_srt = OBJ_nid2ln(mgf1_hash_nid); + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "mgf1HashAlgorithm"_s)), Bun::toJS(lexicalGlobalObject, Bun::toString(mgf1_hash_srt, strlen(mgf1_hash_srt))), 0); + } + + if (params->saltLength != nullptr) { + if (ASN1_INTEGER_get_int64(&salt_length, params->saltLength) != 1) { + auto scope = DECLARE_THROW_SCOPE(vm); + throwException(lexicalGlobalObject, scope, createTypeError(lexicalGlobalObject, "Failed to get saltLenght"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + } + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "saltLength"_s)), jsNumber(salt_length), 0); + } + } + return JSC::JSValue::encode(obj); + } + case CryptoAlgorithmIdentifier::ECDSA: + case CryptoAlgorithmIdentifier::ECDH: { + auto* obj = JSC::constructEmptyObject(lexicalGlobalObject, lexicalGlobalObject->objectPrototype(), 1); + + auto& wrapped = key->wrapped(); + const auto& ec = downcast<WebCore::CryptoKeyEC>(wrapped); + static const NeverDestroyed<String> values[] = { + MAKE_STATIC_STRING_IMPL("prime256v1"), + MAKE_STATIC_STRING_IMPL("secp384r1"), + MAKE_STATIC_STRING_IMPL("secp521r1"), + }; + + WTF::String named_curve; + switch (ec.namedCurve()) { + case CryptoKeyEC::NamedCurve::P256: + named_curve = values[0]; + break; + case CryptoKeyEC::NamedCurve::P384: + named_curve = values[1]; + break; + case CryptoKeyEC::NamedCurve::P521: + named_curve = values[2]; + break; + default: + ASSERT_NOT_REACHED(); + named_curve = WTF::emptyString(); + } + + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "namedCurve"_s)), JSC::jsString(vm, named_curve), 0); + return JSC::JSValue::encode(obj); + } + case CryptoAlgorithmIdentifier::Ed25519: { + auto* obj = JSC::constructEmptyObject(lexicalGlobalObject, lexicalGlobalObject->objectPrototype(), 1); + auto& wrapped = key->wrapped(); + const auto& okp = downcast<WebCore::CryptoKeyOKP>(wrapped); + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "namedCurve"_s)), JSC::jsString(vm, okp.namedCurveString()), 0); + return JSC::JSValue::encode(obj); + } + default: + return JSC::JSValue::encode(JSC::jsUndefined()); + } + } + return JSC::JSValue::encode(JSC::jsUndefined()); +} + +JSC::EncodedJSValue KeyObject__generateKeyPairSync(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame) +{ + auto count = callFrame->argumentCount(); + auto& vm = lexicalGlobalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (count < 1) { + JSC::throwTypeError(lexicalGlobalObject, scope, "generateKeyPairSync requires 1 arguments"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + auto type = callFrame->argument(0); + if (type.isUndefinedOrNull() || type.isEmpty() || !type.isString()) { + JSC::throwTypeError(lexicalGlobalObject, scope, "type is expected to be a string"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto type_str = type.toWTFString(lexicalGlobalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + Zig::GlobalObject* zigGlobalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto* structure = zigGlobalObject->JSCryptoKeyStructure(); + // TODO: rsa-pss + if (type_str == "rsa"_s) { + if (count == 1) { + JSC::throwTypeError(lexicalGlobalObject, scope, "options.modulusLength are required for rsa"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto* options = jsDynamicCast<JSC::JSObject*>(callFrame->argument(1)); + if (options == nullptr) { + JSC::throwTypeError(lexicalGlobalObject, scope, "options is expected to be a object"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto modulusLengthJS = options->getIfPropertyExists(lexicalGlobalObject, PropertyName(Identifier::fromString(vm, "modulusLength"_s))); + if (!modulusLengthJS.isNumber()) { + JSC::throwTypeError(lexicalGlobalObject, scope, "options.modulusLength is expected to be a number"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto publicExponentJS = options->getIfPropertyExists(lexicalGlobalObject, PropertyName(Identifier::fromString(vm, "publicExponent"_s))); + uint32_t publicExponent = 0x10001; + if (publicExponentJS.isNumber()) { + publicExponent = publicExponentJS.toUInt32(lexicalGlobalObject); + } else if (!publicExponentJS.isUndefinedOrNull() && !publicExponentJS.isEmpty()) { + JSC::throwTypeError(lexicalGlobalObject, scope, "options.publicExponent is expected to be a number"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + uint8_t publicExponentArray[4]; + publicExponentArray[0] = (uint8_t)(publicExponent >> 24); + publicExponentArray[1] = (uint8_t)(publicExponent >> 16); + publicExponentArray[2] = (uint8_t)(publicExponent >> 8); + publicExponentArray[3] = (uint8_t)publicExponent; + + int modulusLength = modulusLengthJS.toUInt32(lexicalGlobalObject); + auto returnValue = JSC::JSValue {}; + auto keyPairCallback = [&](CryptoKeyPair&& pair) { + pair.publicKey->setUsagesBitmap(pair.publicKey->usagesBitmap() & CryptoKeyUsageVerify); + pair.privateKey->setUsagesBitmap(pair.privateKey->usagesBitmap() & CryptoKeyUsageSign); + + auto obj = JSC::constructEmptyObject(lexicalGlobalObject, lexicalGlobalObject->objectPrototype(), 2); + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "publicKey"_s)), JSCryptoKey::create(structure, zigGlobalObject, pair.publicKey.releaseNonNull()), 0); + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "privateKey"_s)), JSCryptoKey::create(structure, zigGlobalObject, pair.privateKey.releaseNonNull()), 0); + returnValue = obj; + }; + auto failureCallback = [&]() { + throwException(lexicalGlobalObject, scope, createTypeError(lexicalGlobalObject, "Failed to generate key pair"_s)); + }; + // this is actually sync + CryptoKeyRSA::generatePair(CryptoAlgorithmIdentifier::RSA_OAEP, CryptoAlgorithmIdentifier::SHA_1, false, modulusLength, Vector<uint8_t>((uint8_t*)&publicExponentArray, 4), true, CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt, WTFMove(keyPairCallback), WTFMove(failureCallback), zigGlobalObject->scriptExecutionContext()); + return JSValue::encode(returnValue); + } else if (type_str == "ec"_s) { + if (count == 1) { + JSC::throwTypeError(lexicalGlobalObject, scope, "options.namedCurve is required for ec"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto* options = jsDynamicCast<JSC::JSObject*>(callFrame->argument(1)); + if (options == nullptr) { + JSC::throwTypeError(lexicalGlobalObject, scope, "options is expected to be a object"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto namedCurveJS = options->getIfPropertyExists(lexicalGlobalObject, PropertyName(Identifier::fromString(vm, "namedCurve"_s))); + if (namedCurveJS.isUndefinedOrNull() || namedCurveJS.isEmpty() || !namedCurveJS.isString()) { + JSC::throwTypeError(lexicalGlobalObject, scope, "namedCurve is expected to be a string"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto namedCurve = namedCurveJS.toWTFString(lexicalGlobalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if(namedCurve == "P-384"_s || namedCurve == "p384"_s || namedCurve == "secp384r1"_s) { + namedCurve = "P-384"_s; + } else if(namedCurve == "P-256"_s || namedCurve == "p256"_s || namedCurve == "prime256v1"_s) { + namedCurve = "P-256"_s; + } else if(namedCurve == "P-521"_s || namedCurve == "p521"_s || namedCurve == "secp521r1"_s) { + namedCurve = "P-521"_s; + }else { + throwException(lexicalGlobalObject, scope, createTypeError(lexicalGlobalObject, "curve not supported"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + + auto result = CryptoKeyEC::generatePair(CryptoAlgorithmIdentifier::ECDSA, namedCurve, true, CryptoKeyUsageSign | CryptoKeyUsageVerify); + if (result.hasException()) { + WebCore::propagateException(*lexicalGlobalObject, scope, result.releaseException()); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto pair = result.releaseReturnValue(); + auto obj = JSC::constructEmptyObject(lexicalGlobalObject, lexicalGlobalObject->objectPrototype(), 2); + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "publicKey"_s)), JSCryptoKey::create(structure, zigGlobalObject, pair.publicKey.releaseNonNull()), 0); + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "privateKey"_s)), JSCryptoKey::create(structure, zigGlobalObject, pair.privateKey.releaseNonNull()), 0); + return JSValue::encode(obj); + } else if (type_str == "ed25519"_s) { + auto result = CryptoKeyOKP::generatePair(CryptoAlgorithmIdentifier::Ed25519, CryptoKeyOKP::NamedCurve::Ed25519, true, CryptoKeyUsageSign | CryptoKeyUsageVerify); + if (result.hasException()) { + WebCore::propagateException(*lexicalGlobalObject, scope, result.releaseException()); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto pair = result.releaseReturnValue(); + auto obj = JSC::constructEmptyObject(lexicalGlobalObject, lexicalGlobalObject->objectPrototype(), 2); + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "publicKey"_s)), JSCryptoKey::create(structure, zigGlobalObject, pair.publicKey.releaseNonNull()), 0); + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "privateKey"_s)), JSCryptoKey::create(structure, zigGlobalObject, pair.privateKey.releaseNonNull()), 0); + return JSValue::encode(obj); + } else if (type_str == "x25519"_s) { + auto result = CryptoKeyOKP::generatePair(CryptoAlgorithmIdentifier::Ed25519, CryptoKeyOKP::NamedCurve::X25519, true, CryptoKeyUsageSign | CryptoKeyUsageVerify); + if (result.hasException()) { + WebCore::propagateException(*lexicalGlobalObject, scope, result.releaseException()); + return JSC::JSValue::encode(JSC::JSValue {}); + } + auto pair = result.releaseReturnValue(); + auto obj = JSC::constructEmptyObject(lexicalGlobalObject, lexicalGlobalObject->objectPrototype(), 2); + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "publicKey"_s)), JSCryptoKey::create(structure, zigGlobalObject, pair.publicKey.releaseNonNull()), 0); + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "privateKey"_s)), JSCryptoKey::create(structure, zigGlobalObject, pair.privateKey.releaseNonNull()), 0); + return JSValue::encode(obj); + } else { + throwException(lexicalGlobalObject, scope, createTypeError(lexicalGlobalObject, "algorithm should be 'rsa', 'ec', 'x25519' or 'ed25519'"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + return JSValue::encode(JSC::jsUndefined()); +} +JSC::EncodedJSValue KeyObject__generateKeySync(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame) +{ + auto count = callFrame->argumentCount(); + auto& vm = lexicalGlobalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + if (count < 2) { + JSC::throwTypeError(lexicalGlobalObject, scope, "generateKeySync requires 2 arguments"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + auto type = callFrame->argument(0); + if (type.isUndefinedOrNull() || type.isEmpty() || !type.isString()) { + JSC::throwTypeError(lexicalGlobalObject, scope, "type is expected to be a string"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + auto type_str = type.toWTFString(lexicalGlobalObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + if (type_str == "hmac"_s) { + Zig::GlobalObject* zigGlobalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto* structure = zigGlobalObject->JSCryptoKeyStructure(); + size_t lengthBits = 0; + auto length = callFrame->argument(1); + if (!length.isNumber()) { + JSC::throwTypeError(lexicalGlobalObject, scope, "length is expected to be a number"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + lengthBits = length.toUInt32(lexicalGlobalObject); + auto result = CryptoKeyHMAC::generate(lengthBits, WebCore::CryptoAlgorithmIdentifier::HMAC, true, CryptoKeyUsageSign | CryptoKeyUsageVerify); + if (UNLIKELY(result == nullptr)) { + throwException(lexicalGlobalObject, scope, createTypeError(lexicalGlobalObject, "Invalid length"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(result.releaseNonNull()))); + } else if (type_str == "aes"_s) { + Zig::GlobalObject* zigGlobalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto* structure = zigGlobalObject->JSCryptoKeyStructure(); + size_t lengthBits = 0; + if (count > 1) { + auto length = callFrame->argument(1); + if (!length.isNumber()) { + JSC::throwTypeError(lexicalGlobalObject, scope, "length is expected to be a number"_s); + return JSC::JSValue::encode(JSC::JSValue {}); + } + lengthBits = length.toUInt32(lexicalGlobalObject); + } + + auto result = CryptoKeyAES::generate(WebCore::CryptoAlgorithmIdentifier::AES_CBC, lengthBits, true, CryptoKeyUsageSign | CryptoKeyUsageVerify); + if (UNLIKELY(result == nullptr)) { + throwException(lexicalGlobalObject, scope, createTypeError(lexicalGlobalObject, "Invalid length"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + return JSC::JSValue::encode(JSCryptoKey::create(structure, zigGlobalObject, WTFMove(result.releaseNonNull()))); + } else { + throwException(lexicalGlobalObject, scope, createTypeError(lexicalGlobalObject, "algorithm should be 'aes' or 'hmac'"_s)); + return JSValue::encode(JSC::jsUndefined()); + } +} + +JSC::EncodedJSValue KeyObject__AsymmetricKeyType(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame) +{ + static const NeverDestroyed<String> values[] = { + MAKE_STATIC_STRING_IMPL("rsa"), + MAKE_STATIC_STRING_IMPL("rsa-pss"), + MAKE_STATIC_STRING_IMPL("ec"), + MAKE_STATIC_STRING_IMPL("x25519"), + MAKE_STATIC_STRING_IMPL("ed25519"), + }; + + // TODO: Look into DSA and DH + if (auto* key = jsDynamicCast<JSCryptoKey*>(callFrame->argument(0))) { + auto id = key->wrapped().algorithmIdentifier(); + switch (id) { + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSA_OAEP: + return JSC::JSValue::encode(JSC::jsStringWithCache(lexicalGlobalObject->vm(), values[0])); + case CryptoAlgorithmIdentifier::RSA_PSS: + return JSC::JSValue::encode(JSC::jsStringWithCache(lexicalGlobalObject->vm(), values[1])); + case CryptoAlgorithmIdentifier::ECDSA: + case CryptoAlgorithmIdentifier::ECDH: + return JSC::JSValue::encode(JSC::jsStringWithCache(lexicalGlobalObject->vm(), values[2])); + case CryptoAlgorithmIdentifier::Ed25519: { + const auto& okpKey = downcast<WebCore::CryptoKeyOKP>(key->wrapped()); + // TODO: CHECK THIS WHEN X488 AND ED448 ARE ADDED + return JSC::JSValue::encode(JSC::jsStringWithCache(lexicalGlobalObject->vm(), String(okpKey.namedCurve() == CryptoKeyOKP::NamedCurve::X25519 ? values[3] : values[4]))); + } + default: + return JSC::JSValue::encode(JSC::jsUndefined()); + } + } + return JSC::JSValue::encode(JSC::jsUndefined()); +} + +static Vector<uint8_t> GetRawKeyFromSecret(WebCore::CryptoKey& key) +{ + auto id = key.keyClass(); + switch (id) { + case CryptoKeyClass::HMAC: { + const auto& hmac = downcast<WebCore::CryptoKeyHMAC>(key); + return hmac.key(); + } + case CryptoKeyClass::AES: { + const auto& aes = downcast<WebCore::CryptoKeyAES>(key); + return aes.key(); + } + case CryptoKeyClass::Raw: { + const auto& raw = downcast<WebCore::CryptoKeyRaw>(key); + return raw.key(); + } + default: { + Vector<uint8_t> empty; + return empty; + } + } +} +static AsymmetricKeyValue GetInternalAsymmetricKey(WebCore::CryptoKey& key) +{ + auto id = key.algorithmIdentifier(); + switch (id) { + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSA_OAEP: + case CryptoAlgorithmIdentifier::RSA_PSS: + return (AsymmetricKeyValue) { .key = downcast<WebCore::CryptoKeyRSA>(key).platformKey(), .owned = false }; + case CryptoAlgorithmIdentifier::ECDSA: + case CryptoAlgorithmIdentifier::ECDH: + return (AsymmetricKeyValue) { .key = downcast<WebCore::CryptoKeyEC>(key).platformKey(), .owned = false }; + case CryptoAlgorithmIdentifier::Ed25519: { + const auto& okpKey = downcast<WebCore::CryptoKeyOKP>(key); + auto keyData = okpKey.exportKey(); + if (okpKey.type() == CryptoKeyType::Private) { + auto* evp_key = EVP_PKEY_new_raw_private_key(okpKey.namedCurve() == CryptoKeyOKP::NamedCurve::X25519 ? EVP_PKEY_X25519 : EVP_PKEY_ED25519, nullptr, keyData.data(), keyData.size()); + return (AsymmetricKeyValue) { .key = evp_key, .owned = true }; + } else { + auto* evp_key = EVP_PKEY_new_raw_public_key(okpKey.namedCurve() == CryptoKeyOKP::NamedCurve::X25519 ? EVP_PKEY_X25519 : EVP_PKEY_ED25519, nullptr, keyData.data(), keyData.size()); + return (AsymmetricKeyValue) { .key = evp_key, .owned = true }; + } + } + default: + return (AsymmetricKeyValue) { .key = NULL, .owned = false }; + } +} + +JSC::EncodedJSValue KeyObject__Equals(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame) +{ + if (auto* key = jsDynamicCast<JSCryptoKey*>(callFrame->argument(0))) { + if (auto* key2 = jsDynamicCast<JSCryptoKey*>(callFrame->argument(1))) { + auto& wrapped = key->wrapped(); + auto& wrapped2 = key2->wrapped(); + auto key_type = wrapped.type(); + auto key_class = wrapped.keyClass(); + if (key_type != wrapped2.type()) { + return JSC::JSValue::encode(jsBoolean(false)); + } + + if (key_type == CryptoKeyType::Secret) { + auto keyData = GetRawKeyFromSecret(wrapped); + auto keyData2 = GetRawKeyFromSecret(wrapped2); + auto size = keyData.size(); + + if (size != keyData2.size()) { + return JSC::JSValue::encode(jsBoolean(false)); + } + return JSC::JSValue::encode(jsBoolean(CRYPTO_memcmp(keyData.data(), keyData2.data(), size) == 0)); + } + auto evp_key = GetInternalAsymmetricKey(wrapped); + auto evp_key2 = GetInternalAsymmetricKey(wrapped2); + + int ok = !evp_key.key || !evp_key2.key ? -2 : EVP_PKEY_cmp(evp_key.key, evp_key2.key); + + if (evp_key.key && evp_key.owned) { + EVP_PKEY_free(evp_key.key); + } + if (evp_key2.key && evp_key2.owned) { + EVP_PKEY_free(evp_key2.key); + } + if (ok == -2) { + auto& vm = lexicalGlobalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + throwException(lexicalGlobalObject, scope, createTypeError(lexicalGlobalObject, "ERR_CRYPTO_UNSUPPORTED_OPERATION"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + return JSC::JSValue::encode(jsBoolean(ok == 1)); + } + } + return JSC::JSValue::encode(jsBoolean(false)); +} + +JSC::EncodedJSValue KeyObject__SymmetricKeySize(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) +{ + if (auto* key = jsDynamicCast<JSCryptoKey*>(callFrame->argument(0))) { + auto& wrapped = key->wrapped(); + auto id = wrapped.keyClass(); + size_t size = 0; + switch (id) { + case CryptoKeyClass::HMAC: { + const auto& hmac = downcast<WebCore::CryptoKeyHMAC>(wrapped); + auto keyData = hmac.key(); + size = keyData.size(); + break; + } + case CryptoKeyClass::AES: { + const auto& aes = downcast<WebCore::CryptoKeyAES>(wrapped); + auto keyData = aes.key(); + size = keyData.size(); + break; + } + case CryptoKeyClass::Raw: { + const auto& raw = downcast<WebCore::CryptoKeyRaw>(wrapped); + auto keyData = raw.key(); + size = keyData.size(); + break; + } + default: { + return JSC::JSValue::encode(JSC::jsUndefined()); + } + } + + if (!size) { + return JSC::JSValue::encode(JSC::jsUndefined()); + } + + return JSC::JSValue::encode(JSC::jsNumber(size)); + } + + return JSC::JSValue::encode(JSC::jsUndefined()); +} + +}
\ No newline at end of file diff --git a/src/bun.js/bindings/KeyObject.h b/src/bun.js/bindings/KeyObject.h new file mode 100644 index 000000000..c9b172e3b --- /dev/null +++ b/src/bun.js/bindings/KeyObject.h @@ -0,0 +1,18 @@ + +#pragma once + +#include "root.h" +#include "helpers.h" +namespace WebCore { + +JSC::EncodedJSValue KeyObject__AsymmetricKeyType(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC::EncodedJSValue KeyObject_AsymmetricKeyDetails(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC::EncodedJSValue KeyObject__SymmetricKeySize(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame); +JSC::EncodedJSValue KeyObject__Equals(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC::EncodedJSValue KeyObject__Exports(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame); +JSC::EncodedJSValue KeyObject__createSecretKey(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC::EncodedJSValue KeyObject__createPublicKey(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC::EncodedJSValue KeyObject__createPrivateKey(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC::EncodedJSValue KeyObject__generateKeySync(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC::EncodedJSValue KeyObject__generateKeyPairSync(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +}
\ No newline at end of file diff --git a/src/bun.js/bindings/ModuleLoader.cpp b/src/bun.js/bindings/ModuleLoader.cpp index 252c446b1..ac980d062 100644 --- a/src/bun.js/bindings/ModuleLoader.cpp +++ b/src/bun.js/bindings/ModuleLoader.cpp @@ -27,7 +27,6 @@ #include "EventEmitter.h" #include "JSEventEmitter.h" -#include "CommonJSModuleRecord.h" #include <JavaScriptCore/JSModuleLoader.h> #include <JavaScriptCore/Completion.h> #include <JavaScriptCore/JSModuleNamespaceObject.h> @@ -93,13 +92,20 @@ generateInternalModuleSourceCode(JSC::JSGlobalObject* globalObject, InternalModu exportNames.reserveCapacity(len); exportValues.ensureCapacity(len); - exportNames.append(vm.propertyNames->defaultKeyword); - exportValues.append(object); + bool hasDefault = false; for (auto& entry : properties) { + if (UNLIKELY(entry == vm.propertyNames->defaultKeyword)) { + hasDefault = true; + } exportNames.append(entry); exportValues.append(object->get(globalObject, entry)); } + + if (!hasDefault) { + exportNames.append(vm.propertyNames->defaultKeyword); + exportValues.append(object); + } }; } @@ -139,7 +145,7 @@ PendingVirtualModuleResult* PendingVirtualModuleResult::create(VM& vm, Structure } Structure* PendingVirtualModuleResult::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); } PendingVirtualModuleResult::PendingVirtualModuleResult(VM& vm, Structure* structure) @@ -459,7 +465,7 @@ JSValue fetchCommonJSModule( } } - if (JSC::JSValue virtualModuleResult = JSValue::decode(Bun__runVirtualModule(globalObject, specifier))) { + if (JSC::JSValue virtualModuleResult = Bun::runVirtualModule(globalObject, specifier)) { JSPromise* promise = jsCast<JSPromise*>(handleVirtualModuleResult<true>(globalObject, virtualModuleResult, res, specifier, referrer)); switch (promise->status(vm)) { case JSPromise::Status::Rejected: { @@ -534,7 +540,7 @@ JSValue fetchCommonJSModule( RELEASE_AND_RETURN(scope, {}); } - target->putDirect(vm, WebCore::clientData(vm)->builtinNames().exportsPublicName(), value, value.isCell() && value.isCallable() ? JSC::PropertyAttribute::Function | 0 : 0); + target->putDirect(vm, WebCore::clientData(vm)->builtinNames().exportsPublicName(), value, 0); target->hasEvaluated = true; RELEASE_AND_RETURN(scope, target); } @@ -634,7 +640,7 @@ static JSValue fetchESMSourceCode( } } - if (JSC::JSValue virtualModuleResult = JSValue::decode(Bun__runVirtualModule(globalObject, specifier))) { + if (JSC::JSValue virtualModuleResult = Bun::runVirtualModule(globalObject, specifier)) { return handleVirtualModuleResult<allowPromise>(globalObject, virtualModuleResult, res, specifier, referrer); } diff --git a/src/bun.js/bindings/ModuleLoader.h b/src/bun.js/bindings/ModuleLoader.h index ee726ebcf..72dd8b49a 100644 --- a/src/bun.js/bindings/ModuleLoader.h +++ b/src/bun.js/bindings/ModuleLoader.h @@ -4,6 +4,9 @@ #include "JavaScriptCore/JSCInlines.h" #include "BunClientData.h" +extern "C" JSC::EncodedJSValue jsFunctionOnLoadObjectResultResolve(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame); +extern "C" JSC::EncodedJSValue jsFunctionOnLoadObjectResultReject(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame); + namespace Zig { class GlobalObject; } diff --git a/src/bun.js/bindings/NodeVMScript.cpp b/src/bun.js/bindings/NodeVMScript.cpp index 05921dd8d..e0e0dc93a 100644 --- a/src/bun.js/bindings/NodeVMScript.cpp +++ b/src/bun.js/bindings/NodeVMScript.cpp @@ -19,6 +19,7 @@ #include "JavaScriptCore/JSWeakMap.h" #include "JavaScriptCore/JSWeakMapInlines.h" #include "JavaScriptCore/JSWithScope.h" +#include "JavaScriptCore/JSGlobalProxyInlines.h" #include "Buffer.h" #include "GCDefferalContext.h" #include "Buffer.h" @@ -120,7 +121,7 @@ constructScript(JSGlobalObject* globalObject, CallFrame* callFrame, JSValue newT auto scope = DECLARE_THROW_SCOPE(vm); SourceCode source( - JSC::StringSourceProvider::create(sourceString, JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(options.filename)), options.filename, TextPosition(options.lineOffset, options.columnOffset)), + JSC::StringSourceProvider::create(sourceString, JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(options.filename)), options.filename, JSC::SourceTaintedOrigin::Untainted, TextPosition(options.lineOffset, options.columnOffset)), options.lineOffset.zeroBasedInt(), options.columnOffset.zeroBasedInt()); RETURN_IF_EXCEPTION(scope, {}); NodeVMScript* script = NodeVMScript::create(vm, globalObject, structure, source); @@ -263,7 +264,7 @@ JSC_DEFINE_HOST_FUNCTION(vmModuleRunInNewContext, (JSGlobalObject * globalObject } } SourceCode source( - JSC::StringSourceProvider::create(sourceString, JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(options.filename)), options.filename, TextPosition(options.lineOffset, options.columnOffset)), + JSC::StringSourceProvider::create(sourceString, JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(options.filename)), options.filename, JSC::SourceTaintedOrigin::Untainted, TextPosition(options.lineOffset, options.columnOffset)), options.lineOffset.zeroBasedInt(), options.columnOffset.zeroBasedInt()); auto* zigGlobal = reinterpret_cast<Zig::GlobalObject*>(globalObject); @@ -332,7 +333,7 @@ JSC_DEFINE_HOST_FUNCTION(vmModuleRunInThisContext, (JSGlobalObject * globalObjec } } SourceCode source( - JSC::StringSourceProvider::create(sourceString, JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(options.filename)), options.filename, TextPosition(options.lineOffset, options.columnOffset)), + JSC::StringSourceProvider::create(sourceString, JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(options.filename)), options.filename, JSC::SourceTaintedOrigin::Untainted, TextPosition(options.lineOffset, options.columnOffset)), options.lineOffset.zeroBasedInt(), options.columnOffset.zeroBasedInt()); auto* zigGlobal = reinterpret_cast<Zig::GlobalObject*>(globalObject); JSObject* context = asObject(contextObjectValue); @@ -501,6 +502,7 @@ public: template<typename CellType, SubspaceAccess> static GCClient::IsoSubspace* subspaceFor(VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(NodeVMScriptPrototype, Base); return &vm.plainObjectSpace(); } static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) diff --git a/src/bun.js/bindings/Path.cpp b/src/bun.js/bindings/Path.cpp index 808613b0c..6507b7122 100644 --- a/src/bun.js/bindings/Path.cpp +++ b/src/bun.js/bindings/Path.cpp @@ -173,7 +173,7 @@ static JSC::JSObject* createPath(JSGlobalObject* globalThis, bool isWindows) JSC::JSFunction::create(vm, JSC::jsCast<JSC::JSGlobalObject*>(globalThis), 0, "relative"_s, Path_functionRelative, ImplementationVisibility::Public), 0); - path->putDirect(vm, clientData->builtinNames().resolvePublicName(), + path->putDirect(vm, vm.propertyNames->resolve, JSC::JSFunction::create(vm, JSC::jsCast<JSC::JSGlobalObject*>(globalThis), 0, "resolve"_s, Path_functionResolve, ImplementationVisibility::Public), 0); diff --git a/src/bun.js/bindings/Process.cpp b/src/bun.js/bindings/Process.cpp index 282cf6460..6fbc797cd 100644 --- a/src/bun.js/bindings/Process.cpp +++ b/src/bun.js/bindings/Process.cpp @@ -20,6 +20,8 @@ #include <errno.h> #include <sys/ioctl.h> #include "JSNextTickQueue.h" +#include "ProcessBindingUV.h" +#include "ProcessBindingNatives.h" #pragma mark - Node.js Process @@ -39,11 +41,11 @@ #include <unistd.h> // setuid, getuid #endif -namespace Zig { +namespace Bun { using namespace JSC; -#define REPORTED_NODE_VERSION "18.15.0" +#define REPORTED_NODE_VERSION "20.8.0" #define processObjectBindingCodeGenerator processObjectInternalsBindingCodeGenerator #define processObjectMainModuleCodeGenerator moduleMainCodeGenerator @@ -226,7 +228,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionDlopen, } } - JSC::EncodedJSValue (*napi_register_module_v1)(JSC::JSGlobalObject * globalObject, + JSC::EncodedJSValue (*napi_register_module_v1)(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue exports); napi_register_module_v1 = reinterpret_cast<JSC::EncodedJSValue (*)(JSC::JSGlobalObject*, @@ -618,7 +620,7 @@ static void onDidChangeListeners(EventEmitter& eventEmitter, const Identifier& e continue; JSGlobalObject* lexicalGlobalObject = context->jsGlobalObject(); - Zig::GlobalObject* globalObject = static_cast<Zig::GlobalObject*>(lexicalGlobalObject); + Zig::GlobalObject* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject); Process* process = jsCast<Process*>(globalObject->processObject()); @@ -677,7 +679,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionAbort, (JSGlobalObject * globalObject, JSC_DEFINE_HOST_FUNCTION(Process_emitWarning, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) { - Zig::GlobalObject* globalObject = static_cast<Zig::GlobalObject*>(lexicalGlobalObject); + Zig::GlobalObject* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject); VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); @@ -747,8 +749,8 @@ JSC_DEFINE_CUSTOM_SETTER(setProcessExitCode, (JSC::JSGlobalObject * lexicalGloba int exitCodeInt = exitCode.toInt32(lexicalGlobalObject); RETURN_IF_EXCEPTION(throwScope, false); - if (exitCodeInt < 0 || exitCodeInt > 127) { - throwRangeError(lexicalGlobalObject, throwScope, "exitCode must be between 0 and 127"_s); + if (exitCodeInt < 0 || exitCodeInt > 255) { + throwRangeError(lexicalGlobalObject, throwScope, "exitCode must be between 0 and 255"_s); return false; } @@ -808,12 +810,12 @@ static JSValue constructVersions(VM& vm, JSObject* processObject) object->putDirect(vm, JSC::Identifier::fromString(vm, "usockets"_s), JSC::JSValue(JSC::jsString(vm, makeString(Bun__versions_usockets))), 0); - object->putDirect(vm, JSC::Identifier::fromString(vm, "v8"_s), JSValue(JSC::jsString(vm, makeString("10.8.168.20-node.8"_s))), 0); - object->putDirect(vm, JSC::Identifier::fromString(vm, "uv"_s), JSValue(JSC::jsString(vm, makeString("1.44.2"_s))), 0); - object->putDirect(vm, JSC::Identifier::fromString(vm, "napi"_s), JSValue(JSC::jsString(vm, makeString("8"_s))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "v8"_s), JSValue(JSC::jsString(vm, makeString("11.3.244.8-node.15"_s))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "uv"_s), JSValue(JSC::jsString(vm, makeString("1.46.0"_s))), 0); + object->putDirect(vm, JSC::Identifier::fromString(vm, "napi"_s), JSValue(JSC::jsString(vm, makeString("9"_s))), 0); object->putDirect(vm, JSC::Identifier::fromString(vm, "modules"_s), - JSC::JSValue(JSC::jsString(vm, makeAtomString("108")))); + JSC::JSValue(JSC::jsString(vm, makeAtomString("115")))); return object; } @@ -950,7 +952,7 @@ static JSValue constructProcessSend(VM& vm, JSObject* processObject) if (Bun__GlobalObject__hasIPC(globalObject)) { return JSC::JSFunction::create(vm, globalObject, 1, String("send"_s), Bun__Process__send, ImplementationVisibility::Public); } else { - return jsNumber(4); + return jsUndefined(); } } @@ -1121,6 +1123,91 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionAssert, (JSGlobalObject * globalObject, return JSValue::encode(jsUndefined()); } +#define PROCESS_BINDING_NOT_IMPLEMENTED_ISSUE(str, issue) \ + { \ + throwScope.throwException(globalObject, createError(globalObject, String("process.binding(\"" str "\") is not implemented in Bun. Track the status & thumbs up the issue: https://github.com/oven-sh/bun/issues/" issue ""_s))); \ + return JSValue::encode(JSValue {}); \ + } + +#define PROCESS_BINDING_NOT_IMPLEMENTED(str) \ + { \ + throwScope.throwException(globalObject, createError(globalObject, String("process.binding(\"" str "\") is not implemented in Bun. If that breaks something, please file an issue and include a reproducible code sample."_s))); \ + return JSValue::encode(JSValue {}); \ + } + +inline JSValue processBindingUtil(Zig::GlobalObject* globalObject, JSC::VM& vm) +{ + auto& builtinNames = WebCore::builtinNames(vm); + auto fn = globalObject->getDirect(vm, builtinNames.requireNativeModulePrivateName()); + auto callData = JSC::getCallData(fn); + JSC::MarkedArgumentBuffer args; + args.append(jsString(vm, String("util/types"_s))); + return JSC::call(globalObject, fn, callData, globalObject, args); +} + +inline JSValue processBindingConfig(Zig::GlobalObject* globalObject, JSC::VM& vm) +{ + auto config = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 9); +#ifdef BUN_DEBUG + config->putDirect(vm, Identifier::fromString(vm, "isDebugBuild"_s), jsBoolean(true), 0); +#else + config->putDirect(vm, Identifier::fromString(vm, "isDebugBuild"_s), jsBoolean(false), 0); +#endif + config->putDirect(vm, Identifier::fromString(vm, "hasOpenSSL"_s), jsBoolean(true), 0); + config->putDirect(vm, Identifier::fromString(vm, "fipsMode"_s), jsBoolean(true), 0); + config->putDirect(vm, Identifier::fromString(vm, "hasIntl"_s), jsBoolean(true), 0); + config->putDirect(vm, Identifier::fromString(vm, "hasTracing"_s), jsBoolean(true), 0); + config->putDirect(vm, Identifier::fromString(vm, "hasNodeOptions"_s), jsBoolean(true), 0); + config->putDirect(vm, Identifier::fromString(vm, "hasInspector"_s), jsBoolean(true), 0); + config->putDirect(vm, Identifier::fromString(vm, "noBrowserGlobals"_s), jsBoolean(false), 0); + config->putDirect(vm, Identifier::fromString(vm, "bits"_s), jsNumber(64), 0); + return config; +} + +JSC_DEFINE_HOST_FUNCTION(Process_functionBinding, (JSGlobalObject * jsGlobalObject, CallFrame* callFrame)) +{ + auto& vm = jsGlobalObject->vm(); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto globalObject = jsCast<Zig::GlobalObject*>(jsGlobalObject); + auto process = jsCast<Process*>(globalObject->processObject()); + auto moduleName = callFrame->argument(0).toWTFString(globalObject); + + // clang-format off + if (moduleName == "async_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("async_wrap"); + if (moduleName == "buffer"_s) PROCESS_BINDING_NOT_IMPLEMENTED_ISSUE("buffer", "2020"); + if (moduleName == "cares_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("cares_wrap"); + if (moduleName == "config"_s) return JSValue::encode(processBindingConfig(globalObject, vm)); + if (moduleName == "constants"_s) return JSValue::encode(globalObject->processBindingConstants()); + if (moduleName == "contextify"_s) PROCESS_BINDING_NOT_IMPLEMENTED("contextify"); + if (moduleName == "crypto"_s) PROCESS_BINDING_NOT_IMPLEMENTED("crypto"); + if (moduleName == "fs"_s) PROCESS_BINDING_NOT_IMPLEMENTED_ISSUE("fs", "3546"); + if (moduleName == "fs_event_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("fs_event_wrap"); + if (moduleName == "http_parser"_s) PROCESS_BINDING_NOT_IMPLEMENTED("http_parser"); + if (moduleName == "icu"_s) PROCESS_BINDING_NOT_IMPLEMENTED("icu"); + if (moduleName == "inspector"_s) PROCESS_BINDING_NOT_IMPLEMENTED("inspector"); + if (moduleName == "js_stream"_s) PROCESS_BINDING_NOT_IMPLEMENTED("js_stream"); + if (moduleName == "natives"_s) return JSValue::encode(process->bindingNatives()); + if (moduleName == "os"_s) PROCESS_BINDING_NOT_IMPLEMENTED("os"); + if (moduleName == "pipe_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("pipe_wrap"); + if (moduleName == "process_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("process_wrap"); + if (moduleName == "signal_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("signal_wrap"); + if (moduleName == "spawn_sync"_s) PROCESS_BINDING_NOT_IMPLEMENTED("spawn_sync"); + if (moduleName == "stream_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED_ISSUE("stream_wrap", "4957"); + if (moduleName == "tcp_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("tcp_wrap"); + if (moduleName == "tls_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("tls_wrap"); + if (moduleName == "tty_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED_ISSUE("tty_wrap", "4694"); + if (moduleName == "udp_wrap"_s) PROCESS_BINDING_NOT_IMPLEMENTED("udp_wrap"); + if (moduleName == "url"_s) PROCESS_BINDING_NOT_IMPLEMENTED("url"); + if (moduleName == "util"_s) return JSValue::encode(processBindingUtil(globalObject, vm)); + if (moduleName == "uv"_s) return JSValue::encode(process->bindingUV()); + if (moduleName == "v8"_s) PROCESS_BINDING_NOT_IMPLEMENTED("v8"); + if (moduleName == "zlib"_s) PROCESS_BINDING_NOT_IMPLEMENTED("zlib"); + // clang-format on + + throwScope.throwException(globalObject, createError(globalObject, makeString("No such module: "_s, moduleName))); + return JSValue::encode(jsUndefined()); +} + JSC_DEFINE_HOST_FUNCTION(Process_functionReallyExit, (JSGlobalObject * globalObject, CallFrame* callFrame)) { auto& vm = globalObject->vm(); @@ -1158,8 +1245,10 @@ void Process::visitChildrenImpl(JSCell* cell, Visitor& visitor) Process* thisObject = jsCast<Process*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); Base::visitChildren(thisObject, visitor); - thisObject->cpuUsageStructure.visit(visitor); - thisObject->memoryUsageStructure.visit(visitor); + thisObject->m_cpuUsageStructure.visit(visitor); + thisObject->m_memoryUsageStructure.visit(visitor); + thisObject->m_bindingUV.visit(visitor); + thisObject->m_bindingNatives.visit(visitor); } DEFINE_VISIT_CHILDREN(Process); @@ -1239,6 +1328,16 @@ static Process* getProcessObject(JSC::JSGlobalObject* lexicalGlobalObject, JSVal return process; } +JSC_DEFINE_HOST_FUNCTION(Process_functionConstrainedMemory, + (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ +#if OS(LINUX) || OS(FREEBSD) + return JSValue::encode(jsDoubleNumber(static_cast<double>(WTF::ramSize()))); +#else + return JSValue::encode(jsUndefined()); +#endif +} + JSC_DEFINE_HOST_FUNCTION(Process_functionCpuUsage, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { @@ -1252,7 +1351,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionCpuUsage, auto* process = getProcessObject(globalObject, callFrame->thisValue()); - Structure* cpuUsageStructure = process->cpuUsageStructure.getInitializedOnMainThread(process); + Structure* cpuUsageStructure = process->cpuUsageStructure(); constexpr double MICROS_PER_SEC = 1000000.0; @@ -1405,7 +1504,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionMemoryUsage, return JSC::JSValue::encode(JSC::JSValue {}); } - JSC::JSObject* result = JSC::constructEmptyObject(vm, process->memoryUsageStructure.getInitializedOnMainThread(process)); + JSC::JSObject* result = JSC::constructEmptyObject(vm, process->memoryUsageStructure()); if (UNLIKELY(throwScope.exception())) { return JSC::JSValue::encode(JSC::JSValue {}); } @@ -1525,7 +1624,7 @@ static JSValue constructMemoryUsage(VM& vm, JSObject* processObject) JSC::JSFunction* rss = JSC::JSFunction::create(vm, globalObject, 0, String("rss"_s), Process_functionMemoryUsageRSS, ImplementationVisibility::Public); - memoryUsage->putDirect(vm, JSC::Identifier::fromString(vm, "rss"_s), rss, JSC::PropertyAttribute::Function | 0); + memoryUsage->putDirect(vm, JSC::Identifier::fromString(vm, "rss"_s), rss, 0); return memoryUsage; } @@ -1548,14 +1647,14 @@ static JSValue constructProcessNextTickFn(VM& vm, JSObject* processObject) Zig::GlobalObject* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject); JSValue nextTickQueueObject; if (!globalObject->m_nextTickQueue) { - Bun::JSNextTickQueue* queue = Bun::JSNextTickQueue::create(globalObject); - globalObject->m_nextTickQueue.set(vm, globalObject, queue); - nextTickQueueObject = queue; + nextTickQueueObject = Bun::JSNextTickQueue::create(globalObject); + globalObject->m_nextTickQueue.set(vm, globalObject, nextTickQueueObject); } else { nextTickQueueObject = jsCast<Bun::JSNextTickQueue*>(globalObject->m_nextTickQueue.get()); } JSC::JSFunction* initializer = JSC::JSFunction::create(vm, processObjectInternalsInitializeNextTickQueueCodeGenerator(vm), lexicalGlobalObject); + JSC::MarkedArgumentBuffer args; args.append(processObject); args.append(nextTickQueueObject); @@ -1736,7 +1835,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionKill, return JSValue::encode(jsUndefined()); } - return JSValue::encode(jsUndefined()); + return JSValue::encode(jsBoolean(true)); } extern "C" void Process__emitMessageEvent(Zig::GlobalObject* global, EncodedJSValue value) @@ -1770,11 +1869,12 @@ extern "C" void Process__emitDisconnectEvent(Zig::GlobalObject* global) argv constructArgv PropertyCallback argv0 constructArgv0 PropertyCallback assert Process_functionAssert Function 1 - binding JSBuiltin Function 1 + binding Process_functionBinding Function 1 browser constructBrowser PropertyCallback chdir Process_functionChdir Function 1 config constructProcessConfigObject PropertyCallback connected processConnected CustomAccessor + constrainedMemory Process_functionConstrainedMemory Function 0 cpuUsage Process_functionCpuUsage Function 1 cwd Process_functionCwd Function 1 debugPort processDebugPort CustomAccessor @@ -1831,7 +1931,6 @@ extern "C" void Process__emitDisconnectEvent(Zig::GlobalObject* global) _kill Process_functionReallyKill Function 2 @end */ - #include "Process.lut.h" const JSC::ClassInfo Process::s_info = { "Process"_s, &Base::s_info, &processObjectTable, nullptr, CREATE_METHOD_TABLE(Process) }; @@ -1840,17 +1939,24 @@ void Process::finishCreation(JSC::VM& vm) { Base::finishCreation(vm); - this->wrapped().onDidChangeListener = &onDidChangeListeners; + wrapped().onDidChangeListener = &onDidChangeListeners; - this->cpuUsageStructure.initLater([](const JSC::LazyProperty<JSC::JSObject, JSC::Structure>::Initializer& init) { + m_cpuUsageStructure.initLater([](const JSC::LazyProperty<Process, JSC::Structure>::Initializer& init) { init.set(constructCPUUsageStructure(init.vm, init.owner->globalObject())); }); - this->memoryUsageStructure.initLater([](const JSC::LazyProperty<JSC::JSObject, JSC::Structure>::Initializer& init) { + m_memoryUsageStructure.initLater([](const JSC::LazyProperty<Process, JSC::Structure>::Initializer& init) { init.set(constructMemoryUsageStructure(init.vm, init.owner->globalObject())); }); - this->putDirect(vm, vm.propertyNames->toStringTagSymbol, jsString(vm, String("process"_s)), 0); + m_bindingUV.initLater([](const JSC::LazyProperty<Process, JSC::JSObject>::Initializer& init) { + init.set(Bun::ProcessBindingUV::create(init.vm, init.owner->globalObject())); + }); + m_bindingNatives.initLater([](const JSC::LazyProperty<Process, JSC::JSObject>::Initializer& init) { + init.set(Bun::ProcessBindingNatives::create(init.vm, ProcessBindingNatives::createStructure(init.vm, init.owner->globalObject()))); + }); + + putDirect(vm, vm.propertyNames->toStringTagSymbol, jsString(vm, String("process"_s)), 0); } -} // namespace Zig +} // namespace Bun diff --git a/src/bun.js/bindings/Process.h b/src/bun.js/bindings/Process.h index ab344c7fe..1615aabdd 100644 --- a/src/bun.js/bindings/Process.h +++ b/src/bun.js/bindings/Process.h @@ -6,7 +6,7 @@ #include "BunClientData.h" #include "JSEventEmitter.h" -namespace Zig { +namespace Bun { // TODO: find a better place for this int getRSS(size_t* rss); @@ -16,6 +16,11 @@ using namespace JSC; class Process : public WebCore::JSEventEmitter { using Base = WebCore::JSEventEmitter; + LazyProperty<Process, Structure> m_cpuUsageStructure; + LazyProperty<Process, Structure> m_memoryUsageStructure; + LazyProperty<Process, JSObject> m_bindingUV; + LazyProperty<Process, JSObject> m_bindingNatives; + public: Process(JSC::Structure* structure, WebCore::JSDOMGlobalObject& globalObject, Ref<WebCore::EventEmitter>&& impl) : Base(structure, globalObject, WTFMove(impl)) @@ -50,9 +55,6 @@ public: return accessor; } - LazyProperty<JSObject, Structure> cpuUsageStructure; - LazyProperty<JSObject, Structure> memoryUsageStructure; - DECLARE_VISIT_CHILDREN; template<typename, SubspaceAccess mode> @@ -69,6 +71,11 @@ public: } void finishCreation(JSC::VM& vm); + + inline Structure* cpuUsageStructure() { return m_cpuUsageStructure.getInitializedOnMainThread(this); } + inline Structure* memoryUsageStructure() { return m_memoryUsageStructure.getInitializedOnMainThread(this); } + inline JSObject* bindingUV() { return m_bindingUV.getInitializedOnMainThread(this); } + inline JSObject* bindingNatives() { return m_bindingNatives.getInitializedOnMainThread(this); } }; -} // namespace Zig
\ No newline at end of file +} // namespace Bun
\ No newline at end of file diff --git a/src/bun.js/bindings/Process.lut.h b/src/bun.js/bindings/Process.lut.h index dda54ff01..6016466c2 100644 --- a/src/bun.js/bindings/Process.lut.h +++ b/src/bun.js/bindings/Process.lut.h @@ -1,6 +1,6 @@ -// File generated via `make generate-builtins` -static const struct CompactHashIndex processObjectTableIndex[267] = { - { 47, -1 }, +// File generated via `make static-hash-table` / `make cpp` +static const struct CompactHashIndex processObjectTableIndex[268] = { + { 48, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -14,9 +14,9 @@ static const struct CompactHashIndex processObjectTableIndex[267] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 20, -1 }, + { 21, -1 }, { -1, -1 }, - { 49, -1 }, + { 50, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -41,14 +41,14 @@ static const struct CompactHashIndex processObjectTableIndex[267] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 34, -1 }, + { 35, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 29, -1 }, - { 13, -1 }, + { 30, -1 }, + { 14, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -57,11 +57,11 @@ static const struct CompactHashIndex processObjectTableIndex[267] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 59, -1 }, + { 60, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 55, -1 }, + { 56, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -75,36 +75,36 @@ static const struct CompactHashIndex processObjectTableIndex[267] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 43, -1 }, + { 44, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { 0, -1 }, - { 28, -1 }, - { 37, -1 }, - { 42, -1 }, + { 29, -1 }, + { 38, -1 }, + { 43, -1 }, { -1, -1 }, - { 25, -1 }, - { 12, -1 }, + { 26, -1 }, + { 13, -1 }, { -1, -1 }, { -1, -1 }, - { 62, -1 }, + { 63, -1 }, { -1, -1 }, { -1, -1 }, - { 33, -1 }, - { 44, -1 }, + { 34, -1 }, + { 45, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 26, -1 }, + { 27, -1 }, { -1, -1 }, { -1, -1 }, - { 22, -1 }, + { 23, -1 }, { -1, -1 }, { 5, -1 }, { -1, -1 }, - { 64, -1 }, + { 65, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -115,19 +115,19 @@ static const struct CompactHashIndex processObjectTableIndex[267] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 27, 261 }, + { 28, 262 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 23, 262 }, + { 24, 263 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 50, 265 }, + { 51, 266 }, { -1, -1 }, - { 19, -1 }, + { 20, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -139,10 +139,10 @@ static const struct CompactHashIndex processObjectTableIndex[267] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 17, 257 }, + { 18, 257 }, { -1, -1 }, - { 14, -1 }, - { 57, -1 }, + { 15, -1 }, + { 58, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -161,12 +161,12 @@ static const struct CompactHashIndex processObjectTableIndex[267] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 3, 266 }, + { 3, 267 }, { 1, -1 }, { -1, -1 }, - { 63, -1 }, + { 64, -1 }, { -1, -1 }, - { 11, -1 }, + { 12, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -174,24 +174,24 @@ static const struct CompactHashIndex processObjectTableIndex[267] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 56, -1 }, + { 57, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { 10, 256 }, { -1, -1 }, - { 16, 263 }, + { 17, 264 }, { -1, -1 }, - { 39, -1 }, + { 40, -1 }, { -1, -1 }, - { 41, -1 }, + { 42, -1 }, { -1, -1 }, - { 38, -1 }, - { 6, 264 }, + { 11, 260 }, + { 6, 265 }, { -1, -1 }, { -1, -1 }, { 4, -1 }, - { 51, -1 }, + { 52, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -205,11 +205,11 @@ static const struct CompactHashIndex processObjectTableIndex[267] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 31, 260 }, + { 32, 261 }, { -1, -1 }, { -1, -1 }, - { 48, -1 }, - { 18, 258 }, + { 49, -1 }, + { 19, 258 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -219,10 +219,10 @@ static const struct CompactHashIndex processObjectTableIndex[267] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 53, -1 }, + { 54, -1 }, { -1, -1 }, - { 32, -1 }, - { 24, -1 }, + { 33, -1 }, + { 25, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -233,12 +233,12 @@ static const struct CompactHashIndex processObjectTableIndex[267] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 52, -1 }, + { 53, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 15, 259 }, + { 16, 259 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -256,31 +256,33 @@ static const struct CompactHashIndex processObjectTableIndex[267] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 21, -1 }, - { 30, -1 }, - { 35, -1 }, + { 22, -1 }, + { 31, -1 }, { 36, -1 }, - { 40, -1 }, - { 45, -1 }, + { 37, -1 }, + { 39, -1 }, + { 41, -1 }, { 46, -1 }, - { 54, -1 }, - { 58, -1 }, - { 60, -1 }, + { 47, -1 }, + { 55, -1 }, + { 59, -1 }, { 61, -1 }, + { 62, -1 }, }; -static const struct HashTableValue processObjectTableValues[65] = { +static const struct HashTableValue processObjectTableValues[66] = { { "abort"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionAbort, 1 } }, { "allowedNodeEnvironmentFlags"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, Process_stubEmptySet } }, { "arch"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructArch } }, { "argv"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructArgv } }, { "argv0"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructArgv0 } }, { "assert"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionAssert, 1 } }, - { "binding"_s, ((static_cast<unsigned>(PropertyAttribute::Function)) & ~PropertyAttribute::Function) | PropertyAttribute::Builtin, NoIntrinsic, { HashTableValue::BuiltinGeneratorType, processObjectBindingCodeGenerator, 1 } }, + { "binding"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionBinding, 1 } }, { "browser"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructBrowser } }, { "chdir"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionChdir, 1 } }, { "config"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructProcessConfigObject } }, { "connected"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, processConnected, setProcessConnected } }, + { "constrainedMemory"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionConstrainedMemory, 0 } }, { "cpuUsage"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionCpuUsage, 1 } }, { "cwd"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionCwd, 1 } }, { "debugPort"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, processDebugPort, setProcessDebugPort } }, @@ -338,4 +340,4 @@ static const struct HashTableValue processObjectTableValues[65] = { }; static const struct HashTable processObjectTable = - { 65, 255, true, nullptr, processObjectTableValues, processObjectTableIndex }; + { 66, 255, true, nullptr, processObjectTableValues, processObjectTableIndex }; diff --git a/src/bun.js/bindings/ProcessBindingConstants.cpp b/src/bun.js/bindings/ProcessBindingConstants.cpp index 36a4a7f96..8544b2f20 100644 --- a/src/bun.js/bindings/ProcessBindingConstants.cpp +++ b/src/bun.js/bindings/ProcessBindingConstants.cpp @@ -685,9 +685,6 @@ static JSValue processBindingConstantsGetFs(VM& vm, JSObject* bindingObject) #ifdef O_DIRECTORY object->putDirect(vm, PropertyName(Identifier::fromString(vm, "O_DIRECTORY"_s)), jsNumber(O_DIRECTORY)); #endif -#ifdef O_EXCL - object->putDirect(vm, PropertyName(Identifier::fromString(vm, "O_EXCL"_s)), jsNumber(O_EXCL)); -#endif #ifdef O_NOATIME object->putDirect(vm, PropertyName(Identifier::fromString(vm, "O_NOATIME"_s)), jsNumber(O_NOATIME)); #endif @@ -1082,15 +1079,18 @@ static JSValue processBindingConstantsGetZlib(VM& vm, JSObject* bindingObject) return object; } -static const HashTableValue ProcessBindingConstantsValues[] = { - { "os"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingConstantsGetOs } }, - { "fs"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingConstantsGetFs } }, - { "crypto"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingConstantsGetCrypto } }, - { "zlib"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingConstantsGetZlib } }, - { "trace"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingConstantsGetTrace } }, -}; +/* Source for ProcessBindingConstants.lut.h +@begin processBindingConstantsTable + os processBindingConstantsGetOs PropertyCallback + fs processBindingConstantsGetFs PropertyCallback + crypto processBindingConstantsGetCrypto PropertyCallback + zlib processBindingConstantsGetZlib PropertyCallback + trace processBindingConstantsGetTrace PropertyCallback +@end +*/ +#include "ProcessBindingConstants.lut.h" -const ClassInfo ProcessBindingConstants::s_info = { "ProcessBindingConstants"_s, Base::info(), nullptr, nullptr, CREATE_METHOD_TABLE(ProcessBindingConstants) }; +const ClassInfo ProcessBindingConstants::s_info = { "ProcessBindingConstants"_s, &Base::s_info, &processBindingConstantsTable, nullptr, CREATE_METHOD_TABLE(ProcessBindingConstants) }; ProcessBindingConstants* ProcessBindingConstants::create(VM& vm, Structure* structure) { @@ -1107,8 +1107,7 @@ Structure* ProcessBindingConstants::createStructure(VM& vm, JSGlobalObject* glob void ProcessBindingConstants::finishCreation(JSC::VM& vm) { Base::finishCreation(vm); - reifyStaticProperties(vm, ProcessBindingConstants::info(), ProcessBindingConstantsValues, *this); - ASSERT(inherits(vm, info())); + ASSERT(inherits(info())); } template<typename Visitor> diff --git a/src/bun.js/bindings/ProcessBindingConstants.h b/src/bun.js/bindings/ProcessBindingConstants.h index 5a9be7ce7..6115534a0 100644 --- a/src/bun.js/bindings/ProcessBindingConstants.h +++ b/src/bun.js/bindings/ProcessBindingConstants.h @@ -1,3 +1,4 @@ +#pragma once #include "root.h" namespace Bun { @@ -11,12 +12,15 @@ public: using Base = JSC::JSNonFinalObject; + static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable; + static ProcessBindingConstants* create(JSC::VM& vm, JSC::Structure* structure); static Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject); template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(ProcessBindingConstants, Base); return &vm.plainObjectSpace(); } diff --git a/src/bun.js/bindings/ProcessBindingConstants.lut.h b/src/bun.js/bindings/ProcessBindingConstants.lut.h new file mode 100644 index 000000000..4ad86860d --- /dev/null +++ b/src/bun.js/bindings/ProcessBindingConstants.lut.h @@ -0,0 +1,31 @@ +// File generated via `make static-hash-table` / `make cpp` +static const struct CompactHashIndex processBindingConstantsTableIndex[17] = { + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 2, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 0, 16 }, + { -1, -1 }, + { -1, -1 }, + { 4, -1 }, + { 3, -1 }, +}; + +static const struct HashTableValue processBindingConstantsTableValues[5] = { + { "os"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingConstantsGetOs } }, + { "fs"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingConstantsGetFs } }, + { "crypto"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingConstantsGetCrypto } }, + { "zlib"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingConstantsGetZlib } }, + { "trace"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingConstantsGetTrace } }, +}; + +static const struct HashTable processBindingConstantsTable = + { 5, 15, false, nullptr, processBindingConstantsTableValues, processBindingConstantsTableIndex }; diff --git a/src/bun.js/bindings/ProcessBindingNatives.cpp b/src/bun.js/bindings/ProcessBindingNatives.cpp new file mode 100644 index 000000000..2a2685524 --- /dev/null +++ b/src/bun.js/bindings/ProcessBindingNatives.cpp @@ -0,0 +1,131 @@ +// Modelled off of https://github.com/nodejs/node/blob/main/src/node_constants.cc +// Note that if you change any of this code, you probably also have to change NodeConstantsModule.h +#include "ProcessBindingNatives.h" +#include "JavaScriptCore/ObjectConstructor.h" + +namespace Bun { +using namespace JSC; + +static JSValue processBindingNativesGetter(VM& vm, JSObject* bindingObject) +{ + // Instead of actually returning our source code, we just return a dummy string. + // Most people just use `process.binding('natives')` to get a list of builtin modules + // We also don't report internal modules. + // If any of this breaks your package, please open an issue. + return jsString(vm, String("/* [native code] */"_s)); +} + +static JSValue processBindingNativesReturnUndefined(VM& vm, JSObject* bindingObject) +{ + // process.binding('natives').config === undefined + return jsUndefined(); +} + +/* Source for ProcessBindingNatives.lut.h +@begin processBindingNativesTable + _http_agent processBindingNativesGetter PropertyCallback + _http_client processBindingNativesGetter PropertyCallback + _http_common processBindingNativesGetter PropertyCallback + _http_incoming processBindingNativesGetter PropertyCallback + _http_outgoing processBindingNativesGetter PropertyCallback + _http_server processBindingNativesGetter PropertyCallback + _stream_duplex processBindingNativesGetter PropertyCallback + _stream_passthrough processBindingNativesGetter PropertyCallback + _stream_readable processBindingNativesGetter PropertyCallback + _stream_transform processBindingNativesGetter PropertyCallback + _stream_wrap processBindingNativesGetter PropertyCallback + _stream_writable processBindingNativesGetter PropertyCallback + _tls_common processBindingNativesGetter PropertyCallback + _tls_wrap processBindingNativesGetter PropertyCallback + assert processBindingNativesGetter PropertyCallback + assert/strict processBindingNativesGetter PropertyCallback + async_hooks processBindingNativesGetter PropertyCallback + buffer processBindingNativesGetter PropertyCallback + child_process processBindingNativesGetter PropertyCallback + cluster processBindingNativesGetter PropertyCallback + console processBindingNativesGetter PropertyCallback + constants processBindingNativesGetter PropertyCallback + crypto processBindingNativesGetter PropertyCallback + dgram processBindingNativesGetter PropertyCallback + diagnostics_channel processBindingNativesGetter PropertyCallback + dns processBindingNativesGetter PropertyCallback + dns/promises processBindingNativesGetter PropertyCallback + domain processBindingNativesGetter PropertyCallback + events processBindingNativesGetter PropertyCallback + fs processBindingNativesGetter PropertyCallback + fs/promises processBindingNativesGetter PropertyCallback + http processBindingNativesGetter PropertyCallback + http2 processBindingNativesGetter PropertyCallback + https processBindingNativesGetter PropertyCallback + inspector processBindingNativesGetter PropertyCallback + inspector/promises processBindingNativesGetter PropertyCallback + module processBindingNativesGetter PropertyCallback + net processBindingNativesGetter PropertyCallback + os processBindingNativesGetter PropertyCallback + path processBindingNativesGetter PropertyCallback + path/posix processBindingNativesGetter PropertyCallback + path/win32 processBindingNativesGetter PropertyCallback + perf_hooks processBindingNativesGetter PropertyCallback + process processBindingNativesGetter PropertyCallback + punycode processBindingNativesGetter PropertyCallback + querystring processBindingNativesGetter PropertyCallback + readline processBindingNativesGetter PropertyCallback + readline/promises processBindingNativesGetter PropertyCallback + repl processBindingNativesGetter PropertyCallback + stream processBindingNativesGetter PropertyCallback + stream/consumers processBindingNativesGetter PropertyCallback + stream/promises processBindingNativesGetter PropertyCallback + stream/web processBindingNativesGetter PropertyCallback + string_decoder processBindingNativesGetter PropertyCallback + sys processBindingNativesGetter PropertyCallback + test processBindingNativesGetter PropertyCallback + test/reporters processBindingNativesGetter PropertyCallback + timers processBindingNativesGetter PropertyCallback + timers/promises processBindingNativesGetter PropertyCallback + tls processBindingNativesGetter PropertyCallback + trace_events processBindingNativesGetter PropertyCallback + tty processBindingNativesGetter PropertyCallback + url processBindingNativesGetter PropertyCallback + util processBindingNativesGetter PropertyCallback + util/types processBindingNativesGetter PropertyCallback + v8 processBindingNativesGetter PropertyCallback + vm processBindingNativesGetter PropertyCallback + wasi processBindingNativesGetter PropertyCallback + worker_threads processBindingNativesGetter PropertyCallback + zlib processBindingNativesGetter PropertyCallback + configs processBindingNativesReturnUndefined PropertyCallback +@end +*/ +#include "ProcessBindingNatives.lut.h" + +const ClassInfo ProcessBindingNatives::s_info = { "ProcessBindingNatives"_s, &Base::s_info, &processBindingNativesTable, nullptr, CREATE_METHOD_TABLE(ProcessBindingNatives) }; + +ProcessBindingNatives* ProcessBindingNatives::create(VM& vm, Structure* structure) +{ + ProcessBindingNatives* obj = new (NotNull, allocateCell<ProcessBindingNatives>(vm)) ProcessBindingNatives(vm, structure); + obj->finishCreation(vm); + return obj; +} + +Structure* ProcessBindingNatives::createStructure(VM& vm, JSGlobalObject* globalObject) +{ + return Structure::create(vm, globalObject, jsNull(), TypeInfo(ObjectType, StructureFlags), ProcessBindingNatives::info()); +} + +void ProcessBindingNatives::finishCreation(JSC::VM& vm) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); +} + +template<typename Visitor> +void ProcessBindingNatives::visitChildrenImpl(JSCell* cell, Visitor& visitor) +{ + ProcessBindingNatives* thisObject = jsCast<ProcessBindingNatives*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + Base::visitChildren(thisObject, visitor); +} + +DEFINE_VISIT_CHILDREN(ProcessBindingNatives); + +} // namespace Bun diff --git a/src/bun.js/bindings/ProcessBindingNatives.h b/src/bun.js/bindings/ProcessBindingNatives.h new file mode 100644 index 000000000..bbeaaa524 --- /dev/null +++ b/src/bun.js/bindings/ProcessBindingNatives.h @@ -0,0 +1,36 @@ +#pragma once +#include "root.h" + +namespace Bun { +using namespace JSC; + +// The object returned from process.binding('natives') +class ProcessBindingNatives final : public JSC::JSNonFinalObject { +public: + DECLARE_INFO; + DECLARE_VISIT_CHILDREN; + + using Base = JSC::JSNonFinalObject; + + static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable; + + static ProcessBindingNatives* create(JSC::VM& vm, JSC::Structure* structure); + static Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject); + + template<typename CellType, JSC::SubspaceAccess> + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(ProcessBindingNatives, Base); + return &vm.plainObjectSpace(); + } + +private: + void finishCreation(JSC::VM& vm); + + ProcessBindingNatives(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure) + { + } +}; + +} // namespace Bun diff --git a/src/bun.js/bindings/ProcessBindingNatives.lut.h b/src/bun.js/bindings/ProcessBindingNatives.lut.h new file mode 100644 index 000000000..2bc7e34f5 --- /dev/null +++ b/src/bun.js/bindings/ProcessBindingNatives.lut.h @@ -0,0 +1,339 @@ +// File generated via `make static-hash-table` / `make cpp` +static const struct CompactHashIndex processBindingNativesTableIndex[259] = { + { 11, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 16, -1 }, + { 40, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 17, -1 }, + { -1, -1 }, + { -1, -1 }, + { 18, -1 }, + { -1, -1 }, + { 59, -1 }, + { -1, -1 }, + { 58, -1 }, + { 29, -1 }, + { -1, -1 }, + { 12, -1 }, + { 56, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 64, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 63, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 61, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 50, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 35, -1 }, + { 42, -1 }, + { 55, -1 }, + { -1, -1 }, + { -1, -1 }, + { 66, -1 }, + { -1, -1 }, + { 52, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 60, -1 }, + { -1, -1 }, + { 41, -1 }, + { 21, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 47, -1 }, + { 30, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 15, -1 }, + { 70, -1 }, + { 26, -1 }, + { -1, -1 }, + { -1, -1 }, + { 54, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 51, -1 }, + { -1, -1 }, + { 2, -1 }, + { 28, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 14, -1 }, + { -1, -1 }, + { -1, -1 }, + { 27, -1 }, + { -1, -1 }, + { 37, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 36, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 1, -1 }, + { -1, -1 }, + { 3, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 19, -1 }, + { -1, -1 }, + { 10, -1 }, + { -1, -1 }, + { -1, -1 }, + { 8, 257 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 43, -1 }, + { -1, -1 }, + { -1, -1 }, + { 5, -1 }, + { -1, -1 }, + { 62, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 57, -1 }, + { 38, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 6, 256 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 22, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 0, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 48, -1 }, + { -1, -1 }, + { -1, -1 }, + { 4, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 32, -1 }, + { -1, -1 }, + { 31, -1 }, + { 49, -1 }, + { 34, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 68, -1 }, + { -1, -1 }, + { -1, -1 }, + { 69, -1 }, + { 33, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 9, -1 }, + { 44, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 23, -1 }, + { -1, -1 }, + { 7, -1 }, + { 67, -1 }, + { -1, -1 }, + { 24, -1 }, + { 25, -1 }, + { -1, -1 }, + { -1, -1 }, + { 20, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 65, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 46, -1 }, + { -1, -1 }, + { 45, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 13, -1 }, + { 39, 258 }, + { 53, -1 }, +}; + +static const struct HashTableValue processBindingNativesTableValues[71] = { + { "_http_agent"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "_http_client"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "_http_common"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "_http_incoming"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "_http_outgoing"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "_http_server"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "_stream_duplex"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "_stream_passthrough"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "_stream_readable"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "_stream_transform"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "_stream_wrap"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "_stream_writable"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "_tls_common"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "_tls_wrap"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "assert"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "assert/strict"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "async_hooks"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "buffer"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "child_process"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "cluster"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "console"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "constants"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "crypto"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "dgram"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "diagnostics_channel"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "dns"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "dns/promises"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "domain"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "events"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "fs"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "fs/promises"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "http"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "http2"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "https"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "inspector"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "inspector/promises"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "module"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "net"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "os"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "path"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "path/posix"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "path/win32"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "perf_hooks"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "process"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "punycode"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "querystring"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "readline"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "readline/promises"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "repl"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "stream"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "stream/consumers"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "stream/promises"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "stream/web"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "string_decoder"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "sys"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "test"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "test/reporters"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "timers"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "timers/promises"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "tls"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "trace_events"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "tty"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "url"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "util"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "util/types"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "v8"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "vm"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "wasi"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "worker_threads"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "zlib"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesGetter } }, + { "configs"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, processBindingNativesReturnUndefined } }, +}; + +static const struct HashTable processBindingNativesTable = + { 71, 255, false, nullptr, processBindingNativesTableValues, processBindingNativesTableIndex }; diff --git a/src/bun.js/bindings/ProcessBindingUV.cpp b/src/bun.js/bindings/ProcessBindingUV.cpp new file mode 100644 index 000000000..8173072a9 --- /dev/null +++ b/src/bun.js/bindings/ProcessBindingUV.cpp @@ -0,0 +1,158 @@ +#include "ProcessBindingUV.h" +#include "ZigGlobalObject.h" +#include "JavaScriptCore/ObjectConstructor.h" +#include "JavaScriptCore/JSMap.h" +#include "JavaScriptCore/JSMapInlines.h" + +// clang-format off + +#define UV_ERRNO_MAP(macro) \ + macro(E2BIG, -7, "argument list too long") \ + macro(EACCES, -13, "permission denied") \ + macro(EADDRINUSE, -48, "address already in use") \ + macro(EADDRNOTAVAIL, -49, "address not available") \ + macro(EAFNOSUPPORT, -47, "address family not supported") \ + macro(EAGAIN, -35, "resource temporarily unavailable") \ + macro(EAI_ADDRFAMILY, -3000, "address family not supported") \ + macro(EAI_AGAIN, -3001, "temporary failure") \ + macro(EAI_BADFLAGS, -3002, "bad ai_flags value") \ + macro(EAI_BADHINTS, -3013, "invalid value for hints") \ + macro(EAI_CANCELED, -3003, "request canceled") \ + macro(EAI_FAIL, -3004, "permanent failure") \ + macro(EAI_FAMILY, -3005, "ai_family not supported") \ + macro(EAI_MEMORY, -3006, "out of memory") \ + macro(EAI_NODATA, -3007, "no address") \ + macro(EAI_NONAME, -3008, "unknown node or service") \ + macro(EAI_OVERFLOW, -3009, "argument buffer overflow") \ + macro(EAI_PROTOCOL, -3014, "resolved protocol is unknown") \ + macro(EAI_SERVICE, -3010, "service not available for socket type") \ + macro(EAI_SOCKTYPE, -3011, "socket type not supported") \ + macro(EALREADY, -37, "connection already in progress") \ + macro(EBADF, -9, "bad file descriptor") \ + macro(EBUSY, -16, "resource busy or locked") \ + macro(ECANCELED, -89, "operation canceled") \ + macro(ECHARSET, -4080, "invalid Unicode character") \ + macro(ECONNABORTED, -53, "software caused connection abort") \ + macro(ECONNREFUSED, -61, "connection refused") \ + macro(ECONNRESET, -54, "connection reset by peer") \ + macro(EDESTADDRREQ, -39, "destination address required") \ + macro(EEXIST, -17, "file already exists") \ + macro(EFAULT, -14, "bad address in system call argument") \ + macro(EFBIG, -27, "file too large") \ + macro(EHOSTUNREACH, -65, "host is unreachable") \ + macro(EINTR, -4, "interrupted system call") \ + macro(EINVAL, -22, "invalid argument") \ + macro(EIO, -5, "i/o error") \ + macro(EISCONN, -56, "socket is already connected") \ + macro(EISDIR, -21, "illegal operation on a directory") \ + macro(ELOOP, -62, "too many symbolic links encountered") \ + macro(EMFILE, -24, "too many open files") \ + macro(EMSGSIZE, -40, "message too long") \ + macro(ENAMETOOLONG, -63, "name too long") \ + macro(ENETDOWN, -50, "network is down") \ + macro(ENETUNREACH, -51, "network is unreachable") \ + macro(ENFILE, -23, "file table overflow") \ + macro(ENOBUFS, -55, "no buffer space available") \ + macro(ENODEV, -19, "no such device") \ + macro(ENOENT, -2, "no such file or directory") \ + macro(ENOMEM, -12, "not enough memory") \ + macro(ENONET, -4056, "machine is not on the network") \ + macro(ENOPROTOOPT, -42, "protocol not available") \ + macro(ENOSPC, -28, "no space left on device") \ + macro(ENOSYS, -78, "function not implemented") \ + macro(ENOTCONN, -57, "socket is not connected") \ + macro(ENOTDIR, -20, "not a directory") \ + macro(ENOTEMPTY, -66, "directory not empty") \ + macro(ENOTSOCK, -38, "socket operation on non-socket") \ + macro(ENOTSUP, -45, "operation not supported on socket") \ + macro(EOVERFLOW, -84, "value too large for defined data type") \ + macro(EPERM, -1, "operation not permitted") \ + macro(EPIPE, -32, "broken pipe") \ + macro(EPROTO, -100, "protocol error") \ + macro(EPROTONOSUPPORT, -43, "protocol not supported") \ + macro(EPROTOTYPE, -41, "protocol wrong type for socket") \ + macro(ERANGE, -34, "result too large") \ + macro(EROFS, -30, "read-only file system") \ + macro(ESHUTDOWN, -58, "cannot send after transport endpoint shutdown") \ + macro(ESPIPE, -29, "invalid seek") \ + macro(ESRCH, -3, "no such process") \ + macro(ETIMEDOUT, -60, "connection timed out") \ + macro(ETXTBSY, -26, "text file is busy") \ + macro(EXDEV, -18, "cross-device link not permitted") \ + macro(UNKNOWN, -4094, "unknown error") \ + macro(EOF, -4095, "end of file") \ + macro(ENXIO, -6, "no such device or address") \ + macro(EMLINK, -31, "too many links") \ + macro(EHOSTDOWN, -64, "host is down") \ + macro(EREMOTEIO, -4030, "remote I/O error") \ + macro(ENOTTY, -25, "inappropriate ioctl for device") \ + macro(EFTYPE, -79, "inappropriate file type or format") \ + macro(EILSEQ, -92, "illegal byte sequence") \ + macro(ESOCKTNOSUPPORT, -44, "socket type not supported") \ + macro(ENODATA, -96, "no data available") \ + macro(EUNATCH, -4023, "protocol driver not attache") + +// clang-format on +namespace Bun { +namespace ProcessBindingUV { + +JSC_DEFINE_HOST_FUNCTION(jsErrname, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ + auto arg0 = callFrame->argument(0); + auto& vm = globalObject->vm(); + + // Node.js will actualy crash here, lol. + if (!arg0.isInt32()) + return JSValue::encode(jsString(vm, makeString("Unknown system error "_s, arg0.toWTFString(globalObject)))); + + auto err = arg0.asInt32(); + switch (err) { +#define CASE(name, value, desc) \ + case value: \ + return JSValue::encode(JSC::jsString(vm, String(#name##_s))); + + UV_ERRNO_MAP(CASE) +#undef CASE + } + + return JSValue::encode(jsString(vm, makeString("Unknown system error "_s, String::number(err)))); +} + +JSC_DEFINE_HOST_FUNCTION(jsGetErrorMap, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ + auto& vm = globalObject->vm(); + auto map = JSC::JSMap::create(vm, globalObject->mapStructure()); + +#define PUT_PROPERTY(name, value, desc) \ + { \ + auto arr = JSC::constructEmptyArray(globalObject, nullptr, 2); \ + arr->putDirectIndex(globalObject, 0, JSC::jsString(vm, String(#name##_s))); \ + arr->putDirectIndex(globalObject, 1, JSC::jsString(vm, String(desc##_s))); \ + map->set(globalObject, JSC::jsNumber(value), arr); \ + } + + UV_ERRNO_MAP(PUT_PROPERTY) +#undef PUT_PROPERTY + + return JSValue::encode(map); +} + +JSObject* create(VM& vm, JSGlobalObject* globalObject) +{ + auto bindingObject = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 0); + + bindingObject->putDirect(vm, JSC::Identifier::fromString(vm, "errname"_s), JSC::JSFunction::create(vm, globalObject, 1, "errname"_s, jsErrname, ImplementationVisibility::Public)); + +#define PUT_PROPERTY(name, value, desc) \ + bindingObject->putDirect(vm, JSC::Identifier::fromString(vm, "UV_" #name##_s), JSC::jsNumber(value)); + + UV_ERRNO_MAP(PUT_PROPERTY) +#undef PUT_PROPERTY + + bindingObject->putDirect(vm, JSC::Identifier::fromString(vm, "getErrorMap"_s), JSC::JSFunction::create(vm, globalObject, 0, "getErrorMap"_s, jsGetErrorMap, ImplementationVisibility::Public)); + + return bindingObject; +} + +} // namespace ProcessBindingUV +} // namespace Bun
\ No newline at end of file diff --git a/src/bun.js/bindings/ProcessBindingUV.h b/src/bun.js/bindings/ProcessBindingUV.h new file mode 100644 index 000000000..4306e21f8 --- /dev/null +++ b/src/bun.js/bindings/ProcessBindingUV.h @@ -0,0 +1,13 @@ +#include "root.h" + +namespace Bun { +namespace ProcessBindingUV { + +JSC_DECLARE_HOST_FUNCTION(jsErrname); + +JSC_DECLARE_HOST_FUNCTION(jsGetErrorMap); + +JSC::JSObject* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject); + +} // namespace ProcessBindingUV +} // namespace Bun
\ No newline at end of file diff --git a/src/bun.js/bindings/RegularExpression.cpp b/src/bun.js/bindings/RegularExpression.cpp index 1c8df1bc0..c59e6fa4c 100644 --- a/src/bun.js/bindings/RegularExpression.cpp +++ b/src/bun.js/bindings/RegularExpression.cpp @@ -1,12 +1,16 @@ #include "root.h" #include "headers-handwritten.h" #include "JavaScriptCore/RegularExpression.h" +#include "JavaScriptCore/Options.h" using namespace JSC; using namespace JSC::Yarr; extern "C" RegularExpression* Yarr__RegularExpression__init(BunString pattern, uint16_t flags) { + // TODO: Remove this, we technically are accessing options before we finalize them. + // This means you cannot use BUN_JSC_dumpCompiledRegExpPatterns on the flag passed to `bun test -t` + Options::AllowUnfinalizedAccessScope scope; return new RegularExpression(Bun::toWTFString(pattern), OptionSet<Flags>(static_cast<Flags>(flags))); } extern "C" void Yarr__RegularExpression__deinit(RegularExpression* re) diff --git a/src/bun.js/bindings/ScriptExecutionContext.cpp b/src/bun.js/bindings/ScriptExecutionContext.cpp index 2113c9f64..9f824dde5 100644 --- a/src/bun.js/bindings/ScriptExecutionContext.cpp +++ b/src/bun.js/bindings/ScriptExecutionContext.cpp @@ -105,7 +105,7 @@ bool ScriptExecutionContext::postTaskTo(ScriptExecutionContextIdentifier identif void ScriptExecutionContext::didCreateDestructionObserver(ContextDestructionObserver& observer) { - ASSERT(!m_inScriptExecutionContextDestructor); + // ASSERT(!m_inScriptExecutionContextDestructor); m_destructionObservers.add(&observer); } @@ -181,7 +181,7 @@ void ScriptExecutionContext::dispatchMessagePortEvents() ASSERT(isContextThread()); checkConsistency(); - ASSERT(m_willprocessMessageWithMessagePortsSoon); + ASSERT(m_willProcessMessageWithMessagePortsSoon); m_willProcessMessageWithMessagePortsSoon = false; auto completionHandlers = std::exchange(m_processMessageWithMessagePortsSoonHandlers, Vector<CompletionHandler<void()>> {}); diff --git a/src/bun.js/bindings/Serialization.cpp b/src/bun.js/bindings/Serialization.cpp index 89937ebbb..fdaf2ab75 100644 --- a/src/bun.js/bindings/Serialization.cpp +++ b/src/bun.js/bindings/Serialization.cpp @@ -8,9 +8,15 @@ using namespace JSC; using namespace WebCore; -/// This is used for Bun.spawn() IPC because otherwise we would have to copy the data once to get it to zig, then write it. -/// Returns `true` on success, `false` on failure + throws a JS error. -extern "C" bool Bun__serializeJSValueForSubprocess(JSGlobalObject* globalObject, EncodedJSValue encodedValue, int fd) +// Must be synced with bindings.zig's JSValue.SerializedScriptValue.External +struct SerializedValueSlice { + uint8_t* bytes; + size_t size; + WebCore::SerializedScriptValue* value; +}; + +/// Returns a "slice" that also contains a pointer to the SerializedScriptValue. Must be freed by the caller +extern "C" SerializedValueSlice Bun__serializeJSValue(JSGlobalObject* globalObject, EncodedJSValue encodedValue) { JSValue value = JSValue::decode(encodedValue); @@ -25,19 +31,23 @@ extern "C" bool Bun__serializeJSValueForSubprocess(JSGlobalObject* globalObject, if (serialized.hasException()) { WebCore::propagateException(*globalObject, scope, serialized.releaseException()); - RELEASE_AND_RETURN(scope, false); + RELEASE_AND_RETURN(scope, { 0 }); } auto serializedValue = serialized.releaseReturnValue(); - auto bytes = serializedValue.ptr()->wireBytes(); - uint8_t id = 2; // IPCMessageType.SerializedMessage - write(fd, &id, sizeof(uint8_t)); - uint32_t size = bytes.size(); - write(fd, &size, sizeof(uint32_t)); - write(fd, bytes.data(), size); + auto bytes = serializedValue->wireBytes(); - RELEASE_AND_RETURN(scope, true); + return { + bytes.data(), + bytes.size(), + &serializedValue.leakRef(), + }; +} + +extern "C" void Bun__SerializedScriptSlice__free(SerializedScriptValue* value) +{ + delete value; } extern "C" EncodedJSValue Bun__JSValue__deserialize(JSGlobalObject* globalObject, const uint8_t* bytes, size_t size) diff --git a/src/bun.js/bindings/URLDecomposition.cpp b/src/bun.js/bindings/URLDecomposition.cpp index d3f11b27f..21168f70f 100644 --- a/src/bun.js/bindings/URLDecomposition.cpp +++ b/src/bun.js/bindings/URLDecomposition.cpp @@ -35,7 +35,14 @@ String URLDecomposition::origin() const if (fullURL.protocolIsInHTTPFamily() or fullURL.protocolIsInFTPFamily() or fullURL.protocolIs("ws"_s) or fullURL.protocolIs("wss"_s)) return fullURL.protocolHostAndPort(); - + if (fullURL.protocolIsBlob()) { + const String& path = fullURL.path().toString(); + const URL subUrl { URL {}, path }; + if (subUrl.isValid()) { + if (subUrl.protocolIsInHTTPFamily() or subUrl.protocolIsInFTPFamily() or subUrl.protocolIs("ws"_s) or subUrl.protocolIs("wss"_s) or subUrl.protocolIsFile()) + return subUrl.protocolHostAndPort(); + } + } return "null"_s; } diff --git a/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h b/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h index a364c0a48..cef5c512a 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h +++ b/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h @@ -16,6 +16,7 @@ std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForEndTag; std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForExpect; std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForExpectConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForExpectAny; std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForExpectAnything; +std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForExpectArrayContaining; std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForExpectStringContaining; std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForExpectStringMatching; std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForFFI; diff --git a/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h b/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h index e98ea16c3..d06451eda 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h +++ b/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h @@ -16,6 +16,7 @@ std::unique_ptr<IsoSubspace> m_subspaceForEndTag; std::unique_ptr<IsoSubspace> m_subspaceForExpect; std::unique_ptr<IsoSubspace> m_subspaceForExpectConstructor;std::unique_ptr<IsoSubspace> m_subspaceForExpectAny; std::unique_ptr<IsoSubspace> m_subspaceForExpectAnything; +std::unique_ptr<IsoSubspace> m_subspaceForExpectArrayContaining; std::unique_ptr<IsoSubspace> m_subspaceForExpectStringContaining; std::unique_ptr<IsoSubspace> m_subspaceForExpectStringMatching; std::unique_ptr<IsoSubspace> m_subspaceForFFI; diff --git a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h index 2c075a508..381378262 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h +++ b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h @@ -1,300 +1,204 @@ JSC::Structure* JSAttributeIteratorStructure() { return m_JSAttributeIterator.getInitializedOnMainThread(this); } - JSC::JSObject* JSAttributeIteratorConstructor() { return m_JSAttributeIterator.constructorInitializedOnMainThread(this); } - JSC::JSValue JSAttributeIteratorPrototype() { return m_JSAttributeIterator.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSAttributeIteratorConstructor() { return m_JSAttributeIterator.constructorInitializedOnMainThread(this); } + JSC::JSValue JSAttributeIteratorPrototype() { return m_JSAttributeIterator.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSAttributeIterator; - bool hasJSAttributeIteratorSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSAttributeIteratorSetterValue; JSC::Structure* JSBigIntStatsStructure() { return m_JSBigIntStats.getInitializedOnMainThread(this); } - JSC::JSObject* JSBigIntStatsConstructor() { return m_JSBigIntStats.constructorInitializedOnMainThread(this); } - JSC::JSValue JSBigIntStatsPrototype() { return m_JSBigIntStats.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSBigIntStatsConstructor() { return m_JSBigIntStats.constructorInitializedOnMainThread(this); } + JSC::JSValue JSBigIntStatsPrototype() { return m_JSBigIntStats.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSBigIntStats; - bool hasJSBigIntStatsSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSBigIntStatsSetterValue; JSC::Structure* JSBlobStructure() { return m_JSBlob.getInitializedOnMainThread(this); } - JSC::JSObject* JSBlobConstructor() { return m_JSBlob.constructorInitializedOnMainThread(this); } - JSC::JSValue JSBlobPrototype() { return m_JSBlob.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSBlobConstructor() { return m_JSBlob.constructorInitializedOnMainThread(this); } + JSC::JSValue JSBlobPrototype() { return m_JSBlob.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSBlob; - bool hasJSBlobSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSBlobSetterValue; JSC::Structure* JSBuildArtifactStructure() { return m_JSBuildArtifact.getInitializedOnMainThread(this); } - JSC::JSObject* JSBuildArtifactConstructor() { return m_JSBuildArtifact.constructorInitializedOnMainThread(this); } - JSC::JSValue JSBuildArtifactPrototype() { return m_JSBuildArtifact.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSBuildArtifactConstructor() { return m_JSBuildArtifact.constructorInitializedOnMainThread(this); } + JSC::JSValue JSBuildArtifactPrototype() { return m_JSBuildArtifact.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSBuildArtifact; - bool hasJSBuildArtifactSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSBuildArtifactSetterValue; JSC::Structure* JSBuildMessageStructure() { return m_JSBuildMessage.getInitializedOnMainThread(this); } - JSC::JSObject* JSBuildMessageConstructor() { return m_JSBuildMessage.constructorInitializedOnMainThread(this); } - JSC::JSValue JSBuildMessagePrototype() { return m_JSBuildMessage.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSBuildMessageConstructor() { return m_JSBuildMessage.constructorInitializedOnMainThread(this); } + JSC::JSValue JSBuildMessagePrototype() { return m_JSBuildMessage.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSBuildMessage; - bool hasJSBuildMessageSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSBuildMessageSetterValue; JSC::Structure* JSCommentStructure() { return m_JSComment.getInitializedOnMainThread(this); } - JSC::JSObject* JSCommentConstructor() { return m_JSComment.constructorInitializedOnMainThread(this); } - JSC::JSValue JSCommentPrototype() { return m_JSComment.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSCommentConstructor() { return m_JSComment.constructorInitializedOnMainThread(this); } + JSC::JSValue JSCommentPrototype() { return m_JSComment.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSComment; - bool hasJSCommentSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSCommentSetterValue; JSC::Structure* JSCryptoStructure() { return m_JSCrypto.getInitializedOnMainThread(this); } - JSC::JSObject* JSCryptoConstructor() { return m_JSCrypto.constructorInitializedOnMainThread(this); } - JSC::JSValue JSCryptoPrototype() { return m_JSCrypto.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSCryptoConstructor() { return m_JSCrypto.constructorInitializedOnMainThread(this); } + JSC::JSValue JSCryptoPrototype() { return m_JSCrypto.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSCrypto; - bool hasJSCryptoSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSCryptoSetterValue; JSC::Structure* JSCryptoHasherStructure() { return m_JSCryptoHasher.getInitializedOnMainThread(this); } - JSC::JSObject* JSCryptoHasherConstructor() { return m_JSCryptoHasher.constructorInitializedOnMainThread(this); } - JSC::JSValue JSCryptoHasherPrototype() { return m_JSCryptoHasher.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSCryptoHasherConstructor() { return m_JSCryptoHasher.constructorInitializedOnMainThread(this); } + JSC::JSValue JSCryptoHasherPrototype() { return m_JSCryptoHasher.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSCryptoHasher; - bool hasJSCryptoHasherSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSCryptoHasherSetterValue; JSC::Structure* JSDebugHTTPSServerStructure() { return m_JSDebugHTTPSServer.getInitializedOnMainThread(this); } - JSC::JSObject* JSDebugHTTPSServerConstructor() { return m_JSDebugHTTPSServer.constructorInitializedOnMainThread(this); } - JSC::JSValue JSDebugHTTPSServerPrototype() { return m_JSDebugHTTPSServer.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSDebugHTTPSServerConstructor() { return m_JSDebugHTTPSServer.constructorInitializedOnMainThread(this); } + JSC::JSValue JSDebugHTTPSServerPrototype() { return m_JSDebugHTTPSServer.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSDebugHTTPSServer; - bool hasJSDebugHTTPSServerSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSDebugHTTPSServerSetterValue; JSC::Structure* JSDebugHTTPServerStructure() { return m_JSDebugHTTPServer.getInitializedOnMainThread(this); } - JSC::JSObject* JSDebugHTTPServerConstructor() { return m_JSDebugHTTPServer.constructorInitializedOnMainThread(this); } - JSC::JSValue JSDebugHTTPServerPrototype() { return m_JSDebugHTTPServer.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSDebugHTTPServerConstructor() { return m_JSDebugHTTPServer.constructorInitializedOnMainThread(this); } + JSC::JSValue JSDebugHTTPServerPrototype() { return m_JSDebugHTTPServer.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSDebugHTTPServer; - bool hasJSDebugHTTPServerSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSDebugHTTPServerSetterValue; JSC::Structure* JSDirentStructure() { return m_JSDirent.getInitializedOnMainThread(this); } - JSC::JSObject* JSDirentConstructor() { return m_JSDirent.constructorInitializedOnMainThread(this); } - JSC::JSValue JSDirentPrototype() { return m_JSDirent.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSDirentConstructor() { return m_JSDirent.constructorInitializedOnMainThread(this); } + JSC::JSValue JSDirentPrototype() { return m_JSDirent.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSDirent; - bool hasJSDirentSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSDirentSetterValue; JSC::Structure* JSDocEndStructure() { return m_JSDocEnd.getInitializedOnMainThread(this); } - JSC::JSObject* JSDocEndConstructor() { return m_JSDocEnd.constructorInitializedOnMainThread(this); } - JSC::JSValue JSDocEndPrototype() { return m_JSDocEnd.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSDocEndConstructor() { return m_JSDocEnd.constructorInitializedOnMainThread(this); } + JSC::JSValue JSDocEndPrototype() { return m_JSDocEnd.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSDocEnd; - bool hasJSDocEndSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSDocEndSetterValue; JSC::Structure* JSDocTypeStructure() { return m_JSDocType.getInitializedOnMainThread(this); } - JSC::JSObject* JSDocTypeConstructor() { return m_JSDocType.constructorInitializedOnMainThread(this); } - JSC::JSValue JSDocTypePrototype() { return m_JSDocType.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSDocTypeConstructor() { return m_JSDocType.constructorInitializedOnMainThread(this); } + JSC::JSValue JSDocTypePrototype() { return m_JSDocType.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSDocType; - bool hasJSDocTypeSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSDocTypeSetterValue; JSC::Structure* JSElementStructure() { return m_JSElement.getInitializedOnMainThread(this); } - JSC::JSObject* JSElementConstructor() { return m_JSElement.constructorInitializedOnMainThread(this); } - JSC::JSValue JSElementPrototype() { return m_JSElement.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSElementConstructor() { return m_JSElement.constructorInitializedOnMainThread(this); } + JSC::JSValue JSElementPrototype() { return m_JSElement.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSElement; - bool hasJSElementSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSElementSetterValue; JSC::Structure* JSEndTagStructure() { return m_JSEndTag.getInitializedOnMainThread(this); } - JSC::JSObject* JSEndTagConstructor() { return m_JSEndTag.constructorInitializedOnMainThread(this); } - JSC::JSValue JSEndTagPrototype() { return m_JSEndTag.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSEndTagConstructor() { return m_JSEndTag.constructorInitializedOnMainThread(this); } + JSC::JSValue JSEndTagPrototype() { return m_JSEndTag.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSEndTag; - bool hasJSEndTagSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSEndTagSetterValue; JSC::Structure* JSExpectStructure() { return m_JSExpect.getInitializedOnMainThread(this); } - JSC::JSObject* JSExpectConstructor() { return m_JSExpect.constructorInitializedOnMainThread(this); } - JSC::JSValue JSExpectPrototype() { return m_JSExpect.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSExpectConstructor() { return m_JSExpect.constructorInitializedOnMainThread(this); } + JSC::JSValue JSExpectPrototype() { return m_JSExpect.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSExpect; - bool hasJSExpectSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSExpectSetterValue; JSC::Structure* JSExpectAnyStructure() { return m_JSExpectAny.getInitializedOnMainThread(this); } - JSC::JSObject* JSExpectAnyConstructor() { return m_JSExpectAny.constructorInitializedOnMainThread(this); } - JSC::JSValue JSExpectAnyPrototype() { return m_JSExpectAny.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSExpectAnyConstructor() { return m_JSExpectAny.constructorInitializedOnMainThread(this); } + JSC::JSValue JSExpectAnyPrototype() { return m_JSExpectAny.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSExpectAny; - bool hasJSExpectAnySetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSExpectAnySetterValue; JSC::Structure* JSExpectAnythingStructure() { return m_JSExpectAnything.getInitializedOnMainThread(this); } - JSC::JSObject* JSExpectAnythingConstructor() { return m_JSExpectAnything.constructorInitializedOnMainThread(this); } - JSC::JSValue JSExpectAnythingPrototype() { return m_JSExpectAnything.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSExpectAnythingConstructor() { return m_JSExpectAnything.constructorInitializedOnMainThread(this); } + JSC::JSValue JSExpectAnythingPrototype() { return m_JSExpectAnything.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSExpectAnything; - bool hasJSExpectAnythingSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSExpectAnythingSetterValue; +JSC::Structure* JSExpectArrayContainingStructure() { return m_JSExpectArrayContaining.getInitializedOnMainThread(this); } + JSC::JSObject* JSExpectArrayContainingConstructor() { return m_JSExpectArrayContaining.constructorInitializedOnMainThread(this); } + JSC::JSValue JSExpectArrayContainingPrototype() { return m_JSExpectArrayContaining.prototypeInitializedOnMainThread(this); } + JSC::LazyClassStructure m_JSExpectArrayContaining; JSC::Structure* JSExpectStringContainingStructure() { return m_JSExpectStringContaining.getInitializedOnMainThread(this); } - JSC::JSObject* JSExpectStringContainingConstructor() { return m_JSExpectStringContaining.constructorInitializedOnMainThread(this); } - JSC::JSValue JSExpectStringContainingPrototype() { return m_JSExpectStringContaining.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSExpectStringContainingConstructor() { return m_JSExpectStringContaining.constructorInitializedOnMainThread(this); } + JSC::JSValue JSExpectStringContainingPrototype() { return m_JSExpectStringContaining.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSExpectStringContaining; - bool hasJSExpectStringContainingSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSExpectStringContainingSetterValue; JSC::Structure* JSExpectStringMatchingStructure() { return m_JSExpectStringMatching.getInitializedOnMainThread(this); } - JSC::JSObject* JSExpectStringMatchingConstructor() { return m_JSExpectStringMatching.constructorInitializedOnMainThread(this); } - JSC::JSValue JSExpectStringMatchingPrototype() { return m_JSExpectStringMatching.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSExpectStringMatchingConstructor() { return m_JSExpectStringMatching.constructorInitializedOnMainThread(this); } + JSC::JSValue JSExpectStringMatchingPrototype() { return m_JSExpectStringMatching.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSExpectStringMatching; - bool hasJSExpectStringMatchingSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSExpectStringMatchingSetterValue; JSC::Structure* JSFFIStructure() { return m_JSFFI.getInitializedOnMainThread(this); } - JSC::JSObject* JSFFIConstructor() { return m_JSFFI.constructorInitializedOnMainThread(this); } - JSC::JSValue JSFFIPrototype() { return m_JSFFI.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSFFIConstructor() { return m_JSFFI.constructorInitializedOnMainThread(this); } + JSC::JSValue JSFFIPrototype() { return m_JSFFI.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSFFI; - bool hasJSFFISetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSFFISetterValue; JSC::Structure* JSFSWatcherStructure() { return m_JSFSWatcher.getInitializedOnMainThread(this); } - JSC::JSObject* JSFSWatcherConstructor() { return m_JSFSWatcher.constructorInitializedOnMainThread(this); } - JSC::JSValue JSFSWatcherPrototype() { return m_JSFSWatcher.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSFSWatcherConstructor() { return m_JSFSWatcher.constructorInitializedOnMainThread(this); } + JSC::JSValue JSFSWatcherPrototype() { return m_JSFSWatcher.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSFSWatcher; - bool hasJSFSWatcherSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSFSWatcherSetterValue; JSC::Structure* JSFileSystemRouterStructure() { return m_JSFileSystemRouter.getInitializedOnMainThread(this); } - JSC::JSObject* JSFileSystemRouterConstructor() { return m_JSFileSystemRouter.constructorInitializedOnMainThread(this); } - JSC::JSValue JSFileSystemRouterPrototype() { return m_JSFileSystemRouter.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSFileSystemRouterConstructor() { return m_JSFileSystemRouter.constructorInitializedOnMainThread(this); } + JSC::JSValue JSFileSystemRouterPrototype() { return m_JSFileSystemRouter.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSFileSystemRouter; - bool hasJSFileSystemRouterSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSFileSystemRouterSetterValue; JSC::Structure* JSHTMLRewriterStructure() { return m_JSHTMLRewriter.getInitializedOnMainThread(this); } - JSC::JSObject* JSHTMLRewriterConstructor() { return m_JSHTMLRewriter.constructorInitializedOnMainThread(this); } - JSC::JSValue JSHTMLRewriterPrototype() { return m_JSHTMLRewriter.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSHTMLRewriterConstructor() { return m_JSHTMLRewriter.constructorInitializedOnMainThread(this); } + JSC::JSValue JSHTMLRewriterPrototype() { return m_JSHTMLRewriter.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSHTMLRewriter; - bool hasJSHTMLRewriterSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSHTMLRewriterSetterValue; JSC::Structure* JSHTTPSServerStructure() { return m_JSHTTPSServer.getInitializedOnMainThread(this); } - JSC::JSObject* JSHTTPSServerConstructor() { return m_JSHTTPSServer.constructorInitializedOnMainThread(this); } - JSC::JSValue JSHTTPSServerPrototype() { return m_JSHTTPSServer.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSHTTPSServerConstructor() { return m_JSHTTPSServer.constructorInitializedOnMainThread(this); } + JSC::JSValue JSHTTPSServerPrototype() { return m_JSHTTPSServer.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSHTTPSServer; - bool hasJSHTTPSServerSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSHTTPSServerSetterValue; JSC::Structure* JSHTTPServerStructure() { return m_JSHTTPServer.getInitializedOnMainThread(this); } - JSC::JSObject* JSHTTPServerConstructor() { return m_JSHTTPServer.constructorInitializedOnMainThread(this); } - JSC::JSValue JSHTTPServerPrototype() { return m_JSHTTPServer.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSHTTPServerConstructor() { return m_JSHTTPServer.constructorInitializedOnMainThread(this); } + JSC::JSValue JSHTTPServerPrototype() { return m_JSHTTPServer.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSHTTPServer; - bool hasJSHTTPServerSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSHTTPServerSetterValue; JSC::Structure* JSListenerStructure() { return m_JSListener.getInitializedOnMainThread(this); } - JSC::JSObject* JSListenerConstructor() { return m_JSListener.constructorInitializedOnMainThread(this); } - JSC::JSValue JSListenerPrototype() { return m_JSListener.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSListenerConstructor() { return m_JSListener.constructorInitializedOnMainThread(this); } + JSC::JSValue JSListenerPrototype() { return m_JSListener.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSListener; - bool hasJSListenerSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSListenerSetterValue; JSC::Structure* JSMD4Structure() { return m_JSMD4.getInitializedOnMainThread(this); } - JSC::JSObject* JSMD4Constructor() { return m_JSMD4.constructorInitializedOnMainThread(this); } - JSC::JSValue JSMD4Prototype() { return m_JSMD4.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSMD4Constructor() { return m_JSMD4.constructorInitializedOnMainThread(this); } + JSC::JSValue JSMD4Prototype() { return m_JSMD4.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSMD4; - bool hasJSMD4SetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSMD4SetterValue; JSC::Structure* JSMD5Structure() { return m_JSMD5.getInitializedOnMainThread(this); } - JSC::JSObject* JSMD5Constructor() { return m_JSMD5.constructorInitializedOnMainThread(this); } - JSC::JSValue JSMD5Prototype() { return m_JSMD5.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSMD5Constructor() { return m_JSMD5.constructorInitializedOnMainThread(this); } + JSC::JSValue JSMD5Prototype() { return m_JSMD5.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSMD5; - bool hasJSMD5SetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSMD5SetterValue; JSC::Structure* JSMatchedRouteStructure() { return m_JSMatchedRoute.getInitializedOnMainThread(this); } - JSC::JSObject* JSMatchedRouteConstructor() { return m_JSMatchedRoute.constructorInitializedOnMainThread(this); } - JSC::JSValue JSMatchedRoutePrototype() { return m_JSMatchedRoute.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSMatchedRouteConstructor() { return m_JSMatchedRoute.constructorInitializedOnMainThread(this); } + JSC::JSValue JSMatchedRoutePrototype() { return m_JSMatchedRoute.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSMatchedRoute; - bool hasJSMatchedRouteSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSMatchedRouteSetterValue; JSC::Structure* JSNodeJSFSStructure() { return m_JSNodeJSFS.getInitializedOnMainThread(this); } - JSC::JSObject* JSNodeJSFSConstructor() { return m_JSNodeJSFS.constructorInitializedOnMainThread(this); } - JSC::JSValue JSNodeJSFSPrototype() { return m_JSNodeJSFS.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSNodeJSFSConstructor() { return m_JSNodeJSFS.constructorInitializedOnMainThread(this); } + JSC::JSValue JSNodeJSFSPrototype() { return m_JSNodeJSFS.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSNodeJSFS; - bool hasJSNodeJSFSSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSNodeJSFSSetterValue; JSC::Structure* JSRequestStructure() { return m_JSRequest.getInitializedOnMainThread(this); } - JSC::JSObject* JSRequestConstructor() { return m_JSRequest.constructorInitializedOnMainThread(this); } - JSC::JSValue JSRequestPrototype() { return m_JSRequest.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSRequestConstructor() { return m_JSRequest.constructorInitializedOnMainThread(this); } + JSC::JSValue JSRequestPrototype() { return m_JSRequest.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSRequest; - bool hasJSRequestSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSRequestSetterValue; JSC::Structure* JSResolveMessageStructure() { return m_JSResolveMessage.getInitializedOnMainThread(this); } - JSC::JSObject* JSResolveMessageConstructor() { return m_JSResolveMessage.constructorInitializedOnMainThread(this); } - JSC::JSValue JSResolveMessagePrototype() { return m_JSResolveMessage.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSResolveMessageConstructor() { return m_JSResolveMessage.constructorInitializedOnMainThread(this); } + JSC::JSValue JSResolveMessagePrototype() { return m_JSResolveMessage.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSResolveMessage; - bool hasJSResolveMessageSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSResolveMessageSetterValue; JSC::Structure* JSResponseStructure() { return m_JSResponse.getInitializedOnMainThread(this); } - JSC::JSObject* JSResponseConstructor() { return m_JSResponse.constructorInitializedOnMainThread(this); } - JSC::JSValue JSResponsePrototype() { return m_JSResponse.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSResponseConstructor() { return m_JSResponse.constructorInitializedOnMainThread(this); } + JSC::JSValue JSResponsePrototype() { return m_JSResponse.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSResponse; - bool hasJSResponseSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSResponseSetterValue; JSC::Structure* JSSHA1Structure() { return m_JSSHA1.getInitializedOnMainThread(this); } - JSC::JSObject* JSSHA1Constructor() { return m_JSSHA1.constructorInitializedOnMainThread(this); } - JSC::JSValue JSSHA1Prototype() { return m_JSSHA1.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSSHA1Constructor() { return m_JSSHA1.constructorInitializedOnMainThread(this); } + JSC::JSValue JSSHA1Prototype() { return m_JSSHA1.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSSHA1; - bool hasJSSHA1SetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSSHA1SetterValue; JSC::Structure* JSSHA224Structure() { return m_JSSHA224.getInitializedOnMainThread(this); } - JSC::JSObject* JSSHA224Constructor() { return m_JSSHA224.constructorInitializedOnMainThread(this); } - JSC::JSValue JSSHA224Prototype() { return m_JSSHA224.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSSHA224Constructor() { return m_JSSHA224.constructorInitializedOnMainThread(this); } + JSC::JSValue JSSHA224Prototype() { return m_JSSHA224.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSSHA224; - bool hasJSSHA224SetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSSHA224SetterValue; JSC::Structure* JSSHA256Structure() { return m_JSSHA256.getInitializedOnMainThread(this); } - JSC::JSObject* JSSHA256Constructor() { return m_JSSHA256.constructorInitializedOnMainThread(this); } - JSC::JSValue JSSHA256Prototype() { return m_JSSHA256.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSSHA256Constructor() { return m_JSSHA256.constructorInitializedOnMainThread(this); } + JSC::JSValue JSSHA256Prototype() { return m_JSSHA256.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSSHA256; - bool hasJSSHA256SetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSSHA256SetterValue; JSC::Structure* JSSHA384Structure() { return m_JSSHA384.getInitializedOnMainThread(this); } - JSC::JSObject* JSSHA384Constructor() { return m_JSSHA384.constructorInitializedOnMainThread(this); } - JSC::JSValue JSSHA384Prototype() { return m_JSSHA384.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSSHA384Constructor() { return m_JSSHA384.constructorInitializedOnMainThread(this); } + JSC::JSValue JSSHA384Prototype() { return m_JSSHA384.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSSHA384; - bool hasJSSHA384SetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSSHA384SetterValue; JSC::Structure* JSSHA512Structure() { return m_JSSHA512.getInitializedOnMainThread(this); } - JSC::JSObject* JSSHA512Constructor() { return m_JSSHA512.constructorInitializedOnMainThread(this); } - JSC::JSValue JSSHA512Prototype() { return m_JSSHA512.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSSHA512Constructor() { return m_JSSHA512.constructorInitializedOnMainThread(this); } + JSC::JSValue JSSHA512Prototype() { return m_JSSHA512.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSSHA512; - bool hasJSSHA512SetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSSHA512SetterValue; JSC::Structure* JSSHA512_256Structure() { return m_JSSHA512_256.getInitializedOnMainThread(this); } - JSC::JSObject* JSSHA512_256Constructor() { return m_JSSHA512_256.constructorInitializedOnMainThread(this); } - JSC::JSValue JSSHA512_256Prototype() { return m_JSSHA512_256.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSSHA512_256Constructor() { return m_JSSHA512_256.constructorInitializedOnMainThread(this); } + JSC::JSValue JSSHA512_256Prototype() { return m_JSSHA512_256.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSSHA512_256; - bool hasJSSHA512_256SetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSSHA512_256SetterValue; JSC::Structure* JSServerWebSocketStructure() { return m_JSServerWebSocket.getInitializedOnMainThread(this); } - JSC::JSObject* JSServerWebSocketConstructor() { return m_JSServerWebSocket.constructorInitializedOnMainThread(this); } - JSC::JSValue JSServerWebSocketPrototype() { return m_JSServerWebSocket.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSServerWebSocketConstructor() { return m_JSServerWebSocket.constructorInitializedOnMainThread(this); } + JSC::JSValue JSServerWebSocketPrototype() { return m_JSServerWebSocket.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSServerWebSocket; - bool hasJSServerWebSocketSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSServerWebSocketSetterValue; JSC::Structure* JSStatWatcherStructure() { return m_JSStatWatcher.getInitializedOnMainThread(this); } - JSC::JSObject* JSStatWatcherConstructor() { return m_JSStatWatcher.constructorInitializedOnMainThread(this); } - JSC::JSValue JSStatWatcherPrototype() { return m_JSStatWatcher.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSStatWatcherConstructor() { return m_JSStatWatcher.constructorInitializedOnMainThread(this); } + JSC::JSValue JSStatWatcherPrototype() { return m_JSStatWatcher.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSStatWatcher; - bool hasJSStatWatcherSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSStatWatcherSetterValue; JSC::Structure* JSStatsStructure() { return m_JSStats.getInitializedOnMainThread(this); } - JSC::JSObject* JSStatsConstructor() { return m_JSStats.constructorInitializedOnMainThread(this); } - JSC::JSValue JSStatsPrototype() { return m_JSStats.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSStatsConstructor() { return m_JSStats.constructorInitializedOnMainThread(this); } + JSC::JSValue JSStatsPrototype() { return m_JSStats.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSStats; - bool hasJSStatsSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSStatsSetterValue; JSC::Structure* JSSubprocessStructure() { return m_JSSubprocess.getInitializedOnMainThread(this); } - JSC::JSObject* JSSubprocessConstructor() { return m_JSSubprocess.constructorInitializedOnMainThread(this); } - JSC::JSValue JSSubprocessPrototype() { return m_JSSubprocess.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSSubprocessConstructor() { return m_JSSubprocess.constructorInitializedOnMainThread(this); } + JSC::JSValue JSSubprocessPrototype() { return m_JSSubprocess.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSSubprocess; - bool hasJSSubprocessSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSSubprocessSetterValue; JSC::Structure* JSTCPSocketStructure() { return m_JSTCPSocket.getInitializedOnMainThread(this); } - JSC::JSObject* JSTCPSocketConstructor() { return m_JSTCPSocket.constructorInitializedOnMainThread(this); } - JSC::JSValue JSTCPSocketPrototype() { return m_JSTCPSocket.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSTCPSocketConstructor() { return m_JSTCPSocket.constructorInitializedOnMainThread(this); } + JSC::JSValue JSTCPSocketPrototype() { return m_JSTCPSocket.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSTCPSocket; - bool hasJSTCPSocketSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSTCPSocketSetterValue; JSC::Structure* JSTLSSocketStructure() { return m_JSTLSSocket.getInitializedOnMainThread(this); } - JSC::JSObject* JSTLSSocketConstructor() { return m_JSTLSSocket.constructorInitializedOnMainThread(this); } - JSC::JSValue JSTLSSocketPrototype() { return m_JSTLSSocket.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSTLSSocketConstructor() { return m_JSTLSSocket.constructorInitializedOnMainThread(this); } + JSC::JSValue JSTLSSocketPrototype() { return m_JSTLSSocket.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSTLSSocket; - bool hasJSTLSSocketSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSTLSSocketSetterValue; JSC::Structure* JSTextChunkStructure() { return m_JSTextChunk.getInitializedOnMainThread(this); } - JSC::JSObject* JSTextChunkConstructor() { return m_JSTextChunk.constructorInitializedOnMainThread(this); } - JSC::JSValue JSTextChunkPrototype() { return m_JSTextChunk.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSTextChunkConstructor() { return m_JSTextChunk.constructorInitializedOnMainThread(this); } + JSC::JSValue JSTextChunkPrototype() { return m_JSTextChunk.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSTextChunk; - bool hasJSTextChunkSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSTextChunkSetterValue; JSC::Structure* JSTextDecoderStructure() { return m_JSTextDecoder.getInitializedOnMainThread(this); } - JSC::JSObject* JSTextDecoderConstructor() { return m_JSTextDecoder.constructorInitializedOnMainThread(this); } - JSC::JSValue JSTextDecoderPrototype() { return m_JSTextDecoder.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSTextDecoderConstructor() { return m_JSTextDecoder.constructorInitializedOnMainThread(this); } + JSC::JSValue JSTextDecoderPrototype() { return m_JSTextDecoder.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSTextDecoder; - bool hasJSTextDecoderSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSTextDecoderSetterValue; JSC::Structure* JSTimeoutStructure() { return m_JSTimeout.getInitializedOnMainThread(this); } - JSC::JSObject* JSTimeoutConstructor() { return m_JSTimeout.constructorInitializedOnMainThread(this); } - JSC::JSValue JSTimeoutPrototype() { return m_JSTimeout.prototypeInitializedOnMainThread(this); } + JSC::JSObject* JSTimeoutConstructor() { return m_JSTimeout.constructorInitializedOnMainThread(this); } + JSC::JSValue JSTimeoutPrototype() { return m_JSTimeout.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_JSTimeout; - bool hasJSTimeoutSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSTimeoutSetterValue; JSC::Structure* JSTranspilerStructure() { return m_JSTranspiler.getInitializedOnMainThread(this); } - JSC::JSObject* JSTranspilerConstructor() { return m_JSTranspiler.constructorInitializedOnMainThread(this); } - JSC::JSValue JSTranspilerPrototype() { return m_JSTranspiler.prototypeInitializedOnMainThread(this); } - JSC::LazyClassStructure m_JSTranspiler; - bool hasJSTranspilerSetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_JSTranspilerSetterValue;
\ No newline at end of file + JSC::JSObject* JSTranspilerConstructor() { return m_JSTranspiler.constructorInitializedOnMainThread(this); } + JSC::JSValue JSTranspilerPrototype() { return m_JSTranspiler.prototypeInitializedOnMainThread(this); } + JSC::LazyClassStructure m_JSTranspiler;
\ No newline at end of file diff --git a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h index cb4c47ccb..84d3df7a0 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h +++ b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h @@ -1,4 +1,4 @@ -void GlobalObject::initGeneratedLazyClasses() { +ALWAYS_INLINE void GlobalObject::initGeneratedLazyClasses() { m_JSAttributeIterator.initLater( [](LazyClassStructure::Initializer& init) { init.setPrototype(WebCore::JSAttributeIterator::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.global))); @@ -107,6 +107,12 @@ void GlobalObject::initGeneratedLazyClasses() { init.setStructure(WebCore::JSExpectAnything::createStructure(init.vm, init.global, init.prototype)); }); + m_JSExpectArrayContaining.initLater( + [](LazyClassStructure::Initializer& init) { + init.setPrototype(WebCore::JSExpectArrayContaining::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.global))); + init.setStructure(WebCore::JSExpectArrayContaining::createStructure(init.vm, init.global, init.prototype)); + + }); m_JSExpectStringContaining.initLater( [](LazyClassStructure::Initializer& init) { init.setPrototype(WebCore::JSExpectStringContaining::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.global))); @@ -303,54 +309,55 @@ void GlobalObject::initGeneratedLazyClasses() { template<typename Visitor> void GlobalObject::visitGeneratedLazyClasses(GlobalObject *thisObject, Visitor& visitor) { - thisObject->m_JSAttributeIterator.visit(visitor); visitor.append(thisObject->m_JSAttributeIteratorSetterValue); - thisObject->m_JSBigIntStats.visit(visitor); visitor.append(thisObject->m_JSBigIntStatsSetterValue); - thisObject->m_JSBlob.visit(visitor); visitor.append(thisObject->m_JSBlobSetterValue); - thisObject->m_JSBuildArtifact.visit(visitor); visitor.append(thisObject->m_JSBuildArtifactSetterValue); - thisObject->m_JSBuildMessage.visit(visitor); visitor.append(thisObject->m_JSBuildMessageSetterValue); - thisObject->m_JSComment.visit(visitor); visitor.append(thisObject->m_JSCommentSetterValue); - thisObject->m_JSCrypto.visit(visitor); visitor.append(thisObject->m_JSCryptoSetterValue); - thisObject->m_JSCryptoHasher.visit(visitor); visitor.append(thisObject->m_JSCryptoHasherSetterValue); - thisObject->m_JSDebugHTTPSServer.visit(visitor); visitor.append(thisObject->m_JSDebugHTTPSServerSetterValue); - thisObject->m_JSDebugHTTPServer.visit(visitor); visitor.append(thisObject->m_JSDebugHTTPServerSetterValue); - thisObject->m_JSDirent.visit(visitor); visitor.append(thisObject->m_JSDirentSetterValue); - thisObject->m_JSDocEnd.visit(visitor); visitor.append(thisObject->m_JSDocEndSetterValue); - thisObject->m_JSDocType.visit(visitor); visitor.append(thisObject->m_JSDocTypeSetterValue); - thisObject->m_JSElement.visit(visitor); visitor.append(thisObject->m_JSElementSetterValue); - thisObject->m_JSEndTag.visit(visitor); visitor.append(thisObject->m_JSEndTagSetterValue); - thisObject->m_JSExpect.visit(visitor); visitor.append(thisObject->m_JSExpectSetterValue); - thisObject->m_JSExpectAny.visit(visitor); visitor.append(thisObject->m_JSExpectAnySetterValue); - thisObject->m_JSExpectAnything.visit(visitor); visitor.append(thisObject->m_JSExpectAnythingSetterValue); - thisObject->m_JSExpectStringContaining.visit(visitor); visitor.append(thisObject->m_JSExpectStringContainingSetterValue); - thisObject->m_JSExpectStringMatching.visit(visitor); visitor.append(thisObject->m_JSExpectStringMatchingSetterValue); - thisObject->m_JSFFI.visit(visitor); visitor.append(thisObject->m_JSFFISetterValue); - thisObject->m_JSFSWatcher.visit(visitor); visitor.append(thisObject->m_JSFSWatcherSetterValue); - thisObject->m_JSFileSystemRouter.visit(visitor); visitor.append(thisObject->m_JSFileSystemRouterSetterValue); - thisObject->m_JSHTMLRewriter.visit(visitor); visitor.append(thisObject->m_JSHTMLRewriterSetterValue); - thisObject->m_JSHTTPSServer.visit(visitor); visitor.append(thisObject->m_JSHTTPSServerSetterValue); - thisObject->m_JSHTTPServer.visit(visitor); visitor.append(thisObject->m_JSHTTPServerSetterValue); - thisObject->m_JSListener.visit(visitor); visitor.append(thisObject->m_JSListenerSetterValue); - thisObject->m_JSMD4.visit(visitor); visitor.append(thisObject->m_JSMD4SetterValue); - thisObject->m_JSMD5.visit(visitor); visitor.append(thisObject->m_JSMD5SetterValue); - thisObject->m_JSMatchedRoute.visit(visitor); visitor.append(thisObject->m_JSMatchedRouteSetterValue); - thisObject->m_JSNodeJSFS.visit(visitor); visitor.append(thisObject->m_JSNodeJSFSSetterValue); - thisObject->m_JSRequest.visit(visitor); visitor.append(thisObject->m_JSRequestSetterValue); - thisObject->m_JSResolveMessage.visit(visitor); visitor.append(thisObject->m_JSResolveMessageSetterValue); - thisObject->m_JSResponse.visit(visitor); visitor.append(thisObject->m_JSResponseSetterValue); - thisObject->m_JSSHA1.visit(visitor); visitor.append(thisObject->m_JSSHA1SetterValue); - thisObject->m_JSSHA224.visit(visitor); visitor.append(thisObject->m_JSSHA224SetterValue); - thisObject->m_JSSHA256.visit(visitor); visitor.append(thisObject->m_JSSHA256SetterValue); - thisObject->m_JSSHA384.visit(visitor); visitor.append(thisObject->m_JSSHA384SetterValue); - thisObject->m_JSSHA512.visit(visitor); visitor.append(thisObject->m_JSSHA512SetterValue); - thisObject->m_JSSHA512_256.visit(visitor); visitor.append(thisObject->m_JSSHA512_256SetterValue); - thisObject->m_JSServerWebSocket.visit(visitor); visitor.append(thisObject->m_JSServerWebSocketSetterValue); - thisObject->m_JSStatWatcher.visit(visitor); visitor.append(thisObject->m_JSStatWatcherSetterValue); - thisObject->m_JSStats.visit(visitor); visitor.append(thisObject->m_JSStatsSetterValue); - thisObject->m_JSSubprocess.visit(visitor); visitor.append(thisObject->m_JSSubprocessSetterValue); - thisObject->m_JSTCPSocket.visit(visitor); visitor.append(thisObject->m_JSTCPSocketSetterValue); - thisObject->m_JSTLSSocket.visit(visitor); visitor.append(thisObject->m_JSTLSSocketSetterValue); - thisObject->m_JSTextChunk.visit(visitor); visitor.append(thisObject->m_JSTextChunkSetterValue); - thisObject->m_JSTextDecoder.visit(visitor); visitor.append(thisObject->m_JSTextDecoderSetterValue); - thisObject->m_JSTimeout.visit(visitor); visitor.append(thisObject->m_JSTimeoutSetterValue); - thisObject->m_JSTranspiler.visit(visitor); visitor.append(thisObject->m_JSTranspilerSetterValue); + thisObject->m_JSAttributeIterator.visit(visitor); + thisObject->m_JSBigIntStats.visit(visitor); + thisObject->m_JSBlob.visit(visitor); + thisObject->m_JSBuildArtifact.visit(visitor); + thisObject->m_JSBuildMessage.visit(visitor); + thisObject->m_JSComment.visit(visitor); + thisObject->m_JSCrypto.visit(visitor); + thisObject->m_JSCryptoHasher.visit(visitor); + thisObject->m_JSDebugHTTPSServer.visit(visitor); + thisObject->m_JSDebugHTTPServer.visit(visitor); + thisObject->m_JSDirent.visit(visitor); + thisObject->m_JSDocEnd.visit(visitor); + thisObject->m_JSDocType.visit(visitor); + thisObject->m_JSElement.visit(visitor); + thisObject->m_JSEndTag.visit(visitor); + thisObject->m_JSExpect.visit(visitor); + thisObject->m_JSExpectAny.visit(visitor); + thisObject->m_JSExpectAnything.visit(visitor); + thisObject->m_JSExpectArrayContaining.visit(visitor); + thisObject->m_JSExpectStringContaining.visit(visitor); + thisObject->m_JSExpectStringMatching.visit(visitor); + thisObject->m_JSFFI.visit(visitor); + thisObject->m_JSFSWatcher.visit(visitor); + thisObject->m_JSFileSystemRouter.visit(visitor); + thisObject->m_JSHTMLRewriter.visit(visitor); + thisObject->m_JSHTTPSServer.visit(visitor); + thisObject->m_JSHTTPServer.visit(visitor); + thisObject->m_JSListener.visit(visitor); + thisObject->m_JSMD4.visit(visitor); + thisObject->m_JSMD5.visit(visitor); + thisObject->m_JSMatchedRoute.visit(visitor); + thisObject->m_JSNodeJSFS.visit(visitor); + thisObject->m_JSRequest.visit(visitor); + thisObject->m_JSResolveMessage.visit(visitor); + thisObject->m_JSResponse.visit(visitor); + thisObject->m_JSSHA1.visit(visitor); + thisObject->m_JSSHA224.visit(visitor); + thisObject->m_JSSHA256.visit(visitor); + thisObject->m_JSSHA384.visit(visitor); + thisObject->m_JSSHA512.visit(visitor); + thisObject->m_JSSHA512_256.visit(visitor); + thisObject->m_JSServerWebSocket.visit(visitor); + thisObject->m_JSStatWatcher.visit(visitor); + thisObject->m_JSStats.visit(visitor); + thisObject->m_JSSubprocess.visit(visitor); + thisObject->m_JSTCPSocket.visit(visitor); + thisObject->m_JSTLSSocket.visit(visitor); + thisObject->m_JSTextChunk.visit(visitor); + thisObject->m_JSTextDecoder.visit(visitor); + thisObject->m_JSTimeout.visit(visitor); + thisObject->m_JSTranspiler.visit(visitor); }
\ No newline at end of file diff --git a/src/bun.js/bindings/ZigGeneratedClasses.cpp b/src/bun.js/bindings/ZigGeneratedClasses.cpp index ec2add296..8d8c98154 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses.cpp +++ b/src/bun.js/bindings/ZigGeneratedClasses.cpp @@ -43,6 +43,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSAttributeIteratorPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -150,7 +151,7 @@ void JSAttributeIteratorPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObje { Base::finishCreation(vm); reifyStaticProperties(vm, JSAttributeIterator::info(), JSAttributeIteratorPrototypeTableValues, *this); - this->putDirect(vm, vm.propertyNames->iteratorSymbol, JSFunction::create(vm, globalObject, 1, String("iterator"_s), AttributeIteratorPrototype__iteratorCallback, ImplementationVisibility::Public), PropertyAttribute::Function | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | 0); + this->putDirect(vm, vm.propertyNames->iteratorSymbol, JSFunction::create(vm, globalObject, 1, String("iterator"_s), AttributeIteratorPrototype__iteratorCallback, ImplementationVisibility::Public), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | 0); JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); } @@ -245,6 +246,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSBigIntStatsPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -1301,6 +1303,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSBlobPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -1777,7 +1780,7 @@ JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSBlobConstructor::construct(JSC::J } JSBlob* instance = JSBlob::create(vm, globalObject, structure, ptr); - vm.heap.reportExtraMemoryAllocated(Blob__estimatedSize(instance->wrapped())); + vm.heap.reportExtraMemoryAllocated(instance, Blob__estimatedSize(instance->wrapped())); return JSValue::encode(instance); } @@ -1871,7 +1874,7 @@ extern "C" EncodedJSValue Blob__create(Zig::GlobalObject* globalObject, void* pt auto& vm = globalObject->vm(); JSC::Structure* structure = globalObject->JSBlobStructure(); JSBlob* instance = JSBlob::create(vm, globalObject, structure, ptr); - vm.heap.reportExtraMemoryAllocated(Blob__estimatedSize(ptr)); + vm.heap.reportExtraMemoryAllocated(instance, Blob__estimatedSize(ptr)); return JSValue::encode(instance); } @@ -1924,6 +1927,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSBuildArtifactPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -2471,6 +2475,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSBuildMessagePrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -2752,7 +2757,7 @@ void JSBuildMessagePrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* g { Base::finishCreation(vm); reifyStaticProperties(vm, JSBuildMessage::info(), JSBuildMessagePrototypeTableValues, *this); - this->putDirect(vm, vm.propertyNames->toPrimitiveSymbol, JSFunction::create(vm, globalObject, 1, String("toPrimitive"_s), BuildMessagePrototype__toPrimitiveCallback, ImplementationVisibility::Public), PropertyAttribute::Function | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | 0); + this->putDirect(vm, vm.propertyNames->toPrimitiveSymbol, JSFunction::create(vm, globalObject, 1, String("toPrimitive"_s), BuildMessagePrototype__toPrimitiveCallback, ImplementationVisibility::Public), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | 0); this->putDirect(vm, vm.propertyNames->name, jsString(vm, String("BuildMessage"_s)), PropertyAttribute::ReadOnly | 0); JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); } @@ -2950,6 +2955,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSCommentPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -3262,6 +3268,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSCryptoPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -3715,6 +3722,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSCryptoHasherPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -4146,6 +4154,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSDebugHTTPSServerPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -4167,6 +4176,9 @@ JSC_DECLARE_CUSTOM_GETTER(jsDebugHTTPSServerConstructor); extern "C" void DebugHTTPSServerClass__finalize(void*); +extern "C" JSC::EncodedJSValue DebugHTTPSServerPrototype__getAddress(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); +JSC_DECLARE_CUSTOM_GETTER(DebugHTTPSServerPrototype__addressGetterWrap); + extern "C" JSC::EncodedJSValue DebugHTTPSServerPrototype__getDevelopment(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); JSC_DECLARE_CUSTOM_GETTER(DebugHTTPSServerPrototype__developmentGetterWrap); @@ -4197,6 +4209,9 @@ JSC_DECLARE_HOST_FUNCTION(DebugHTTPSServerPrototype__publishCallback); extern "C" EncodedJSValue DebugHTTPSServerPrototype__doReload(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); JSC_DECLARE_HOST_FUNCTION(DebugHTTPSServerPrototype__reloadCallback); +extern "C" EncodedJSValue DebugHTTPSServerPrototype__doRequestIP(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(DebugHTTPSServerPrototype__requestIPCallback); + extern "C" EncodedJSValue DebugHTTPSServerPrototype__doStop(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); JSC_DECLARE_HOST_FUNCTION(DebugHTTPSServerPrototype__stopCallback); @@ -4206,6 +4221,7 @@ JSC_DECLARE_HOST_FUNCTION(DebugHTTPSServerPrototype__upgradeCallback); STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSDebugHTTPSServerPrototype, JSDebugHTTPSServerPrototype::Base); static const HashTableValue JSDebugHTTPSServerPrototypeTableValues[] = { + { "address"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPSServerPrototype__addressGetterWrap, 0 } }, { "development"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPSServerPrototype__developmentGetterWrap, 0 } }, { "fetch"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, DebugHTTPSServerPrototype__fetchCallback, 1 } }, { "hostname"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPSServerPrototype__hostnameGetterWrap, 0 } }, @@ -4216,6 +4232,7 @@ static const HashTableValue JSDebugHTTPSServerPrototypeTableValues[] = { { "protocol"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPSServerPrototype__protocolGetterWrap, 0 } }, { "publish"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, DebugHTTPSServerPrototype__publishCallback, 3 } }, { "reload"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, DebugHTTPSServerPrototype__reloadCallback, 2 } }, + { "requestIP"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, DebugHTTPSServerPrototype__requestIPCallback, 1 } }, { "stop"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, DebugHTTPSServerPrototype__stopCallback, 1 } }, { "upgrade"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, DebugHTTPSServerPrototype__upgradeCallback, 1 } } }; @@ -4234,6 +4251,37 @@ JSC_DEFINE_CUSTOM_GETTER(jsDebugHTTPSServerConstructor, (JSGlobalObject * lexica return JSValue::encode(globalObject->JSDebugHTTPSServerConstructor()); } +JSC_DEFINE_CUSTOM_GETTER(DebugHTTPSServerPrototype__addressGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) +{ + auto& vm = lexicalGlobalObject->vm(); + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + JSDebugHTTPSServer* thisObject = jsCast<JSDebugHTTPSServer*>(JSValue::decode(thisValue)); + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + if (JSValue cachedValue = thisObject->m_address.get()) + return JSValue::encode(cachedValue); + + JSC::JSValue result = JSC::JSValue::decode( + DebugHTTPSServerPrototype__getAddress(thisObject->wrapped(), globalObject)); + RETURN_IF_EXCEPTION(throwScope, {}); + thisObject->m_address.set(vm, thisObject, result); + RELEASE_AND_RETURN(throwScope, JSValue::encode(result)); +} + +extern "C" void DebugHTTPSServerPrototype__addressSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value) +{ + auto& vm = globalObject->vm(); + auto* thisObject = jsCast<JSDebugHTTPSServer*>(JSValue::decode(thisValue)); + thisObject->m_address.set(vm, thisObject, JSValue::decode(value)); +} + +extern "C" EncodedJSValue DebugHTTPSServerPrototype__addressGetCachedValue(JSC::EncodedJSValue thisValue) +{ + auto* thisObject = jsCast<JSDebugHTTPSServer*>(JSValue::decode(thisValue)); + return JSValue::encode(thisObject->m_address.get()); +} + JSC_DEFINE_CUSTOM_GETTER(DebugHTTPSServerPrototype__developmentGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) { auto& vm = lexicalGlobalObject->vm(); @@ -4440,6 +4488,34 @@ JSC_DEFINE_HOST_FUNCTION(DebugHTTPSServerPrototype__reloadCallback, (JSGlobalObj return DebugHTTPSServerPrototype__doReload(thisObject->wrapped(), lexicalGlobalObject, callFrame); } +JSC_DEFINE_HOST_FUNCTION(DebugHTTPSServerPrototype__requestIPCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSDebugHTTPSServer* thisObject = jsDynamicCast<JSDebugHTTPSServer*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + throwVMTypeError(lexicalGlobalObject, throwScope, "Expected 'this' to be instanceof DebugHTTPSServer"_s); + return JSValue::encode({}); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + +#ifdef BUN_DEBUG + /** View the file name of the JS file that called this function + * from a debugger */ + SourceOrigin sourceOrigin = callFrame->callerSourceOrigin(vm); + const char* fileName = sourceOrigin.string().utf8().data(); + static const char* lastFileName = nullptr; + if (lastFileName != fileName) { + lastFileName = fileName; + } +#endif + + return DebugHTTPSServerPrototype__doRequestIP(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + JSC_DEFINE_HOST_FUNCTION(DebugHTTPSServerPrototype__stopCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) { auto& vm = lexicalGlobalObject->vm(); @@ -4598,6 +4674,7 @@ void JSDebugHTTPSServer::visitAdditionalChildren(Visitor& visitor) JSDebugHTTPSServer* thisObject = this; ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + visitor.append(thisObject->m_address); visitor.append(thisObject->m_hostname); visitor.append(thisObject->m_id); } @@ -4628,6 +4705,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSDebugHTTPServerPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -4649,6 +4727,9 @@ JSC_DECLARE_CUSTOM_GETTER(jsDebugHTTPServerConstructor); extern "C" void DebugHTTPServerClass__finalize(void*); +extern "C" JSC::EncodedJSValue DebugHTTPServerPrototype__getAddress(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); +JSC_DECLARE_CUSTOM_GETTER(DebugHTTPServerPrototype__addressGetterWrap); + extern "C" JSC::EncodedJSValue DebugHTTPServerPrototype__getDevelopment(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); JSC_DECLARE_CUSTOM_GETTER(DebugHTTPServerPrototype__developmentGetterWrap); @@ -4679,6 +4760,9 @@ JSC_DECLARE_HOST_FUNCTION(DebugHTTPServerPrototype__publishCallback); extern "C" EncodedJSValue DebugHTTPServerPrototype__doReload(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); JSC_DECLARE_HOST_FUNCTION(DebugHTTPServerPrototype__reloadCallback); +extern "C" EncodedJSValue DebugHTTPServerPrototype__doRequestIP(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(DebugHTTPServerPrototype__requestIPCallback); + extern "C" EncodedJSValue DebugHTTPServerPrototype__doStop(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); JSC_DECLARE_HOST_FUNCTION(DebugHTTPServerPrototype__stopCallback); @@ -4688,6 +4772,7 @@ JSC_DECLARE_HOST_FUNCTION(DebugHTTPServerPrototype__upgradeCallback); STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSDebugHTTPServerPrototype, JSDebugHTTPServerPrototype::Base); static const HashTableValue JSDebugHTTPServerPrototypeTableValues[] = { + { "address"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPServerPrototype__addressGetterWrap, 0 } }, { "development"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPServerPrototype__developmentGetterWrap, 0 } }, { "fetch"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, DebugHTTPServerPrototype__fetchCallback, 1 } }, { "hostname"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPServerPrototype__hostnameGetterWrap, 0 } }, @@ -4698,6 +4783,7 @@ static const HashTableValue JSDebugHTTPServerPrototypeTableValues[] = { { "protocol"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPServerPrototype__protocolGetterWrap, 0 } }, { "publish"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, DebugHTTPServerPrototype__publishCallback, 3 } }, { "reload"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, DebugHTTPServerPrototype__reloadCallback, 2 } }, + { "requestIP"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, DebugHTTPServerPrototype__requestIPCallback, 1 } }, { "stop"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, DebugHTTPServerPrototype__stopCallback, 1 } }, { "upgrade"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, DebugHTTPServerPrototype__upgradeCallback, 1 } } }; @@ -4716,6 +4802,37 @@ JSC_DEFINE_CUSTOM_GETTER(jsDebugHTTPServerConstructor, (JSGlobalObject * lexical return JSValue::encode(globalObject->JSDebugHTTPServerConstructor()); } +JSC_DEFINE_CUSTOM_GETTER(DebugHTTPServerPrototype__addressGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) +{ + auto& vm = lexicalGlobalObject->vm(); + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + JSDebugHTTPServer* thisObject = jsCast<JSDebugHTTPServer*>(JSValue::decode(thisValue)); + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + if (JSValue cachedValue = thisObject->m_address.get()) + return JSValue::encode(cachedValue); + + JSC::JSValue result = JSC::JSValue::decode( + DebugHTTPServerPrototype__getAddress(thisObject->wrapped(), globalObject)); + RETURN_IF_EXCEPTION(throwScope, {}); + thisObject->m_address.set(vm, thisObject, result); + RELEASE_AND_RETURN(throwScope, JSValue::encode(result)); +} + +extern "C" void DebugHTTPServerPrototype__addressSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value) +{ + auto& vm = globalObject->vm(); + auto* thisObject = jsCast<JSDebugHTTPServer*>(JSValue::decode(thisValue)); + thisObject->m_address.set(vm, thisObject, JSValue::decode(value)); +} + +extern "C" EncodedJSValue DebugHTTPServerPrototype__addressGetCachedValue(JSC::EncodedJSValue thisValue) +{ + auto* thisObject = jsCast<JSDebugHTTPServer*>(JSValue::decode(thisValue)); + return JSValue::encode(thisObject->m_address.get()); +} + JSC_DEFINE_CUSTOM_GETTER(DebugHTTPServerPrototype__developmentGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) { auto& vm = lexicalGlobalObject->vm(); @@ -4922,6 +5039,34 @@ JSC_DEFINE_HOST_FUNCTION(DebugHTTPServerPrototype__reloadCallback, (JSGlobalObje return DebugHTTPServerPrototype__doReload(thisObject->wrapped(), lexicalGlobalObject, callFrame); } +JSC_DEFINE_HOST_FUNCTION(DebugHTTPServerPrototype__requestIPCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSDebugHTTPServer* thisObject = jsDynamicCast<JSDebugHTTPServer*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + throwVMTypeError(lexicalGlobalObject, throwScope, "Expected 'this' to be instanceof DebugHTTPServer"_s); + return JSValue::encode({}); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + +#ifdef BUN_DEBUG + /** View the file name of the JS file that called this function + * from a debugger */ + SourceOrigin sourceOrigin = callFrame->callerSourceOrigin(vm); + const char* fileName = sourceOrigin.string().utf8().data(); + static const char* lastFileName = nullptr; + if (lastFileName != fileName) { + lastFileName = fileName; + } +#endif + + return DebugHTTPServerPrototype__doRequestIP(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + JSC_DEFINE_HOST_FUNCTION(DebugHTTPServerPrototype__stopCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) { auto& vm = lexicalGlobalObject->vm(); @@ -5080,6 +5225,7 @@ void JSDebugHTTPServer::visitAdditionalChildren(Visitor& visitor) JSDebugHTTPServer* thisObject = this; ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + visitor.append(thisObject->m_address); visitor.append(thisObject->m_hostname); visitor.append(thisObject->m_id); } @@ -5110,6 +5256,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSDirentPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -5644,6 +5791,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSDocEndPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -5814,6 +5962,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSDocTypePrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -6092,6 +6241,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSElementPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -6808,6 +6958,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSEndTagPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -7072,6 +7223,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSExpectPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -7257,6 +7409,9 @@ JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__toEndWithCallback); extern "C" EncodedJSValue ExpectPrototype__toEqual(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__toEqualCallback); +extern "C" EncodedJSValue ExpectPrototype__toEqualIgnoringWhitespace(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__toEqualIgnoringWhitespaceCallback); + extern "C" EncodedJSValue ExpectPrototype__toHaveBeenCalled(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); JSC_DECLARE_HOST_FUNCTION(ExpectPrototype__toHaveBeenCalledCallback); @@ -7371,6 +7526,7 @@ static const HashTableValue JSExpectPrototypeTableValues[] = { { "toContainEqual"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toContainEqualCallback, 1 } }, { "toEndWith"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toEndWithCallback, 1 } }, { "toEqual"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toEqualCallback, 1 } }, + { "toEqualIgnoringWhitespace"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toEqualIgnoringWhitespaceCallback, 1 } }, { "toHaveBeenCalled"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toHaveBeenCalledCallback, 0 } }, { "toHaveBeenCalledTimes"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toHaveBeenCalledTimesCallback, 1 } }, { "toHaveBeenCalledWith"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, ExpectPrototype__toHaveBeenCalledWithCallback, 1 } }, @@ -8538,6 +8694,34 @@ JSC_DEFINE_HOST_FUNCTION(ExpectPrototype__toEqualCallback, (JSGlobalObject * lex return ExpectPrototype__toEqual(thisObject->wrapped(), lexicalGlobalObject, callFrame); } +JSC_DEFINE_HOST_FUNCTION(ExpectPrototype__toEqualIgnoringWhitespaceCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSExpect* thisObject = jsDynamicCast<JSExpect*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + throwVMTypeError(lexicalGlobalObject, throwScope, "Expected 'this' to be instanceof Expect"_s); + return JSValue::encode({}); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + +#ifdef BUN_DEBUG + /** View the file name of the JS file that called this function + * from a debugger */ + SourceOrigin sourceOrigin = callFrame->callerSourceOrigin(vm); + const char* fileName = sourceOrigin.string().utf8().data(); + static const char* lastFileName = nullptr; + if (lastFileName != fileName) { + lastFileName = fileName; + } +#endif + + return ExpectPrototype__toEqualIgnoringWhitespace(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + JSC_DEFINE_HOST_FUNCTION(ExpectPrototype__toHaveBeenCalledCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) { auto& vm = lexicalGlobalObject->vm(); @@ -9436,6 +9620,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSExpectAnyPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -9604,6 +9789,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSExpectAnythingPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -9712,6 +9898,175 @@ extern "C" EncodedJSValue ExpectAnything__create(Zig::GlobalObject* globalObject return JSValue::encode(instance); } +class JSExpectArrayContainingPrototype final : public JSC::JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + + static JSExpectArrayContainingPrototype* create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure) + { + JSExpectArrayContainingPrototype* ptr = new (NotNull, JSC::allocateCell<JSExpectArrayContainingPrototype>(vm)) JSExpectArrayContainingPrototype(vm, globalObject, structure); + ptr->finishCreation(vm, globalObject); + return ptr; + } + + DECLARE_INFO; + template<typename CellType, JSC::SubspaceAccess> + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSExpectArrayContainingPrototype, Base); + return &vm.plainObjectSpace(); + } + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); + } + +private: + JSExpectArrayContainingPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) + : Base(vm, structure) + { + } + + void finishCreation(JSC::VM&, JSC::JSGlobalObject*); +}; + +extern "C" void ExpectArrayContainingClass__finalize(void*); +extern "C" JSC_DECLARE_HOST_FUNCTION(ExpectArrayContainingClass__call); + +STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSExpectArrayContainingPrototype, JSExpectArrayContainingPrototype::Base); + +static const HashTableValue JSExpectArrayContainingPrototypeTableValues[] = {}; + +const ClassInfo JSExpectArrayContainingPrototype::s_info = { "ExpectArrayContaining"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSExpectArrayContainingPrototype) }; + +extern "C" void ExpectArrayContainingPrototype__arrayValueSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value) +{ + auto& vm = globalObject->vm(); + auto* thisObject = jsCast<JSExpectArrayContaining*>(JSValue::decode(thisValue)); + thisObject->m_arrayValue.set(vm, thisObject, JSValue::decode(value)); +} + +extern "C" EncodedJSValue ExpectArrayContainingPrototype__arrayValueGetCachedValue(JSC::EncodedJSValue thisValue) +{ + auto* thisObject = jsCast<JSExpectArrayContaining*>(JSValue::decode(thisValue)); + return JSValue::encode(thisObject->m_arrayValue.get()); +} + +void JSExpectArrayContainingPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +{ + Base::finishCreation(vm); + + JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); +} + +JSExpectArrayContaining::~JSExpectArrayContaining() +{ + if (m_ctx) { + ExpectArrayContainingClass__finalize(m_ctx); + } +} +void JSExpectArrayContaining::destroy(JSCell* cell) +{ + static_cast<JSExpectArrayContaining*>(cell)->JSExpectArrayContaining::~JSExpectArrayContaining(); +} + +const ClassInfo JSExpectArrayContaining::s_info = { "ExpectArrayContaining"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSExpectArrayContaining) }; + +void JSExpectArrayContaining::finishCreation(VM& vm) +{ + Base::finishCreation(vm); + ASSERT(inherits(info())); +} + +JSExpectArrayContaining* JSExpectArrayContaining::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx) +{ + JSExpectArrayContaining* ptr = new (NotNull, JSC::allocateCell<JSExpectArrayContaining>(vm)) JSExpectArrayContaining(vm, structure, ctx); + ptr->finishCreation(vm); + return ptr; +} + +extern "C" void* ExpectArrayContaining__fromJS(JSC::EncodedJSValue value) +{ + JSC::JSValue decodedValue = JSC::JSValue::decode(value); + if (decodedValue.isEmpty() || !decodedValue.isCell()) + return nullptr; + + JSC::JSCell* cell = decodedValue.asCell(); + JSExpectArrayContaining* object = JSC::jsDynamicCast<JSExpectArrayContaining*>(cell); + + if (!object) + return nullptr; + + return object->wrapped(); +} + +extern "C" bool ExpectArrayContaining__dangerouslySetPtr(JSC::EncodedJSValue value, void* ptr) +{ + JSExpectArrayContaining* object = JSC::jsDynamicCast<JSExpectArrayContaining*>(JSValue::decode(value)); + if (!object) + return false; + + object->m_ctx = ptr; + return true; +} + +extern "C" const size_t ExpectArrayContaining__ptrOffset = JSExpectArrayContaining::offsetOfWrapped(); + +void JSExpectArrayContaining::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer) +{ + auto* thisObject = jsCast<JSExpectArrayContaining*>(cell); + if (void* wrapped = thisObject->wrapped()) { + // if (thisObject->scriptExecutionContext()) + // analyzer.setLabelForCell(cell, "url " + thisObject->scriptExecutionContext()->url().string()); + } + Base::analyzeHeap(cell, analyzer); +} + +JSObject* JSExpectArrayContaining::createPrototype(VM& vm, JSDOMGlobalObject* globalObject) +{ + return JSExpectArrayContainingPrototype::create(vm, globalObject, JSExpectArrayContainingPrototype::createStructure(vm, globalObject, globalObject->objectPrototype())); +} + +extern "C" EncodedJSValue ExpectArrayContaining__create(Zig::GlobalObject* globalObject, void* ptr) +{ + auto& vm = globalObject->vm(); + JSC::Structure* structure = globalObject->JSExpectArrayContainingStructure(); + JSExpectArrayContaining* instance = JSExpectArrayContaining::create(vm, globalObject, structure, ptr); + + return JSValue::encode(instance); +} + +template<typename Visitor> +void JSExpectArrayContaining::visitChildrenImpl(JSCell* cell, Visitor& visitor) +{ + JSExpectArrayContaining* thisObject = jsCast<JSExpectArrayContaining*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + Base::visitChildren(thisObject, visitor); + + thisObject->visitAdditionalChildren<Visitor>(visitor); +} + +DEFINE_VISIT_CHILDREN(JSExpectArrayContaining); + +template<typename Visitor> +void JSExpectArrayContaining::visitAdditionalChildren(Visitor& visitor) +{ + JSExpectArrayContaining* thisObject = this; + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + visitor.append(thisObject->m_arrayValue); +} + +DEFINE_VISIT_ADDITIONAL_CHILDREN(JSExpectArrayContaining); + +template<typename Visitor> +void JSExpectArrayContaining::visitOutputConstraintsImpl(JSCell* cell, Visitor& visitor) +{ + JSExpectArrayContaining* thisObject = jsCast<JSExpectArrayContaining*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + thisObject->visitAdditionalChildren<Visitor>(visitor); +} + +DEFINE_VISIT_OUTPUT_CONSTRAINTS(JSExpectArrayContaining); class JSExpectStringContainingPrototype final : public JSC::JSNonFinalObject { public: using Base = JSC::JSNonFinalObject; @@ -9727,6 +10082,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSExpectStringContainingPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -9895,6 +10251,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSExpectStringMatchingPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -10063,6 +10420,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSFFIPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -10313,6 +10671,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSFSWatcherPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -10617,6 +10976,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSFileSystemRouterPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -11063,6 +11423,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSHTMLRewriterPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -11401,6 +11762,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSHTTPSServerPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -11422,6 +11784,9 @@ JSC_DECLARE_CUSTOM_GETTER(jsHTTPSServerConstructor); extern "C" void HTTPSServerClass__finalize(void*); +extern "C" JSC::EncodedJSValue HTTPSServerPrototype__getAddress(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); +JSC_DECLARE_CUSTOM_GETTER(HTTPSServerPrototype__addressGetterWrap); + extern "C" JSC::EncodedJSValue HTTPSServerPrototype__getDevelopment(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); JSC_DECLARE_CUSTOM_GETTER(HTTPSServerPrototype__developmentGetterWrap); @@ -11452,6 +11817,9 @@ JSC_DECLARE_HOST_FUNCTION(HTTPSServerPrototype__publishCallback); extern "C" EncodedJSValue HTTPSServerPrototype__doReload(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); JSC_DECLARE_HOST_FUNCTION(HTTPSServerPrototype__reloadCallback); +extern "C" EncodedJSValue HTTPSServerPrototype__doRequestIP(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(HTTPSServerPrototype__requestIPCallback); + extern "C" EncodedJSValue HTTPSServerPrototype__doStop(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); JSC_DECLARE_HOST_FUNCTION(HTTPSServerPrototype__stopCallback); @@ -11461,6 +11829,7 @@ JSC_DECLARE_HOST_FUNCTION(HTTPSServerPrototype__upgradeCallback); STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSHTTPSServerPrototype, JSHTTPSServerPrototype::Base); static const HashTableValue JSHTTPSServerPrototypeTableValues[] = { + { "address"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPSServerPrototype__addressGetterWrap, 0 } }, { "development"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPSServerPrototype__developmentGetterWrap, 0 } }, { "fetch"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, HTTPSServerPrototype__fetchCallback, 1 } }, { "hostname"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPSServerPrototype__hostnameGetterWrap, 0 } }, @@ -11471,6 +11840,7 @@ static const HashTableValue JSHTTPSServerPrototypeTableValues[] = { { "protocol"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPSServerPrototype__protocolGetterWrap, 0 } }, { "publish"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, HTTPSServerPrototype__publishCallback, 3 } }, { "reload"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, HTTPSServerPrototype__reloadCallback, 2 } }, + { "requestIP"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, HTTPSServerPrototype__requestIPCallback, 1 } }, { "stop"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, HTTPSServerPrototype__stopCallback, 1 } }, { "upgrade"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, HTTPSServerPrototype__upgradeCallback, 1 } } }; @@ -11489,6 +11859,37 @@ JSC_DEFINE_CUSTOM_GETTER(jsHTTPSServerConstructor, (JSGlobalObject * lexicalGlob return JSValue::encode(globalObject->JSHTTPSServerConstructor()); } +JSC_DEFINE_CUSTOM_GETTER(HTTPSServerPrototype__addressGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) +{ + auto& vm = lexicalGlobalObject->vm(); + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + JSHTTPSServer* thisObject = jsCast<JSHTTPSServer*>(JSValue::decode(thisValue)); + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + if (JSValue cachedValue = thisObject->m_address.get()) + return JSValue::encode(cachedValue); + + JSC::JSValue result = JSC::JSValue::decode( + HTTPSServerPrototype__getAddress(thisObject->wrapped(), globalObject)); + RETURN_IF_EXCEPTION(throwScope, {}); + thisObject->m_address.set(vm, thisObject, result); + RELEASE_AND_RETURN(throwScope, JSValue::encode(result)); +} + +extern "C" void HTTPSServerPrototype__addressSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value) +{ + auto& vm = globalObject->vm(); + auto* thisObject = jsCast<JSHTTPSServer*>(JSValue::decode(thisValue)); + thisObject->m_address.set(vm, thisObject, JSValue::decode(value)); +} + +extern "C" EncodedJSValue HTTPSServerPrototype__addressGetCachedValue(JSC::EncodedJSValue thisValue) +{ + auto* thisObject = jsCast<JSHTTPSServer*>(JSValue::decode(thisValue)); + return JSValue::encode(thisObject->m_address.get()); +} + JSC_DEFINE_CUSTOM_GETTER(HTTPSServerPrototype__developmentGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) { auto& vm = lexicalGlobalObject->vm(); @@ -11695,6 +12096,34 @@ JSC_DEFINE_HOST_FUNCTION(HTTPSServerPrototype__reloadCallback, (JSGlobalObject * return HTTPSServerPrototype__doReload(thisObject->wrapped(), lexicalGlobalObject, callFrame); } +JSC_DEFINE_HOST_FUNCTION(HTTPSServerPrototype__requestIPCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSHTTPSServer* thisObject = jsDynamicCast<JSHTTPSServer*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + throwVMTypeError(lexicalGlobalObject, throwScope, "Expected 'this' to be instanceof HTTPSServer"_s); + return JSValue::encode({}); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + +#ifdef BUN_DEBUG + /** View the file name of the JS file that called this function + * from a debugger */ + SourceOrigin sourceOrigin = callFrame->callerSourceOrigin(vm); + const char* fileName = sourceOrigin.string().utf8().data(); + static const char* lastFileName = nullptr; + if (lastFileName != fileName) { + lastFileName = fileName; + } +#endif + + return HTTPSServerPrototype__doRequestIP(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + JSC_DEFINE_HOST_FUNCTION(HTTPSServerPrototype__stopCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) { auto& vm = lexicalGlobalObject->vm(); @@ -11853,6 +12282,7 @@ void JSHTTPSServer::visitAdditionalChildren(Visitor& visitor) JSHTTPSServer* thisObject = this; ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + visitor.append(thisObject->m_address); visitor.append(thisObject->m_hostname); visitor.append(thisObject->m_id); } @@ -11883,6 +12313,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSHTTPServerPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -11904,6 +12335,9 @@ JSC_DECLARE_CUSTOM_GETTER(jsHTTPServerConstructor); extern "C" void HTTPServerClass__finalize(void*); +extern "C" JSC::EncodedJSValue HTTPServerPrototype__getAddress(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); +JSC_DECLARE_CUSTOM_GETTER(HTTPServerPrototype__addressGetterWrap); + extern "C" JSC::EncodedJSValue HTTPServerPrototype__getDevelopment(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); JSC_DECLARE_CUSTOM_GETTER(HTTPServerPrototype__developmentGetterWrap); @@ -11934,6 +12368,9 @@ JSC_DECLARE_HOST_FUNCTION(HTTPServerPrototype__publishCallback); extern "C" EncodedJSValue HTTPServerPrototype__doReload(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); JSC_DECLARE_HOST_FUNCTION(HTTPServerPrototype__reloadCallback); +extern "C" EncodedJSValue HTTPServerPrototype__doRequestIP(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); +JSC_DECLARE_HOST_FUNCTION(HTTPServerPrototype__requestIPCallback); + extern "C" EncodedJSValue HTTPServerPrototype__doStop(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame); JSC_DECLARE_HOST_FUNCTION(HTTPServerPrototype__stopCallback); @@ -11943,6 +12380,7 @@ JSC_DECLARE_HOST_FUNCTION(HTTPServerPrototype__upgradeCallback); STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSHTTPServerPrototype, JSHTTPServerPrototype::Base); static const HashTableValue JSHTTPServerPrototypeTableValues[] = { + { "address"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPServerPrototype__addressGetterWrap, 0 } }, { "development"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPServerPrototype__developmentGetterWrap, 0 } }, { "fetch"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, HTTPServerPrototype__fetchCallback, 1 } }, { "hostname"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPServerPrototype__hostnameGetterWrap, 0 } }, @@ -11953,6 +12391,7 @@ static const HashTableValue JSHTTPServerPrototypeTableValues[] = { { "protocol"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPServerPrototype__protocolGetterWrap, 0 } }, { "publish"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, HTTPServerPrototype__publishCallback, 3 } }, { "reload"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, HTTPServerPrototype__reloadCallback, 2 } }, + { "requestIP"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, HTTPServerPrototype__requestIPCallback, 1 } }, { "stop"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, HTTPServerPrototype__stopCallback, 1 } }, { "upgrade"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, HTTPServerPrototype__upgradeCallback, 1 } } }; @@ -11971,6 +12410,37 @@ JSC_DEFINE_CUSTOM_GETTER(jsHTTPServerConstructor, (JSGlobalObject * lexicalGloba return JSValue::encode(globalObject->JSHTTPServerConstructor()); } +JSC_DEFINE_CUSTOM_GETTER(HTTPServerPrototype__addressGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) +{ + auto& vm = lexicalGlobalObject->vm(); + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + JSHTTPServer* thisObject = jsCast<JSHTTPServer*>(JSValue::decode(thisValue)); + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + if (JSValue cachedValue = thisObject->m_address.get()) + return JSValue::encode(cachedValue); + + JSC::JSValue result = JSC::JSValue::decode( + HTTPServerPrototype__getAddress(thisObject->wrapped(), globalObject)); + RETURN_IF_EXCEPTION(throwScope, {}); + thisObject->m_address.set(vm, thisObject, result); + RELEASE_AND_RETURN(throwScope, JSValue::encode(result)); +} + +extern "C" void HTTPServerPrototype__addressSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value) +{ + auto& vm = globalObject->vm(); + auto* thisObject = jsCast<JSHTTPServer*>(JSValue::decode(thisValue)); + thisObject->m_address.set(vm, thisObject, JSValue::decode(value)); +} + +extern "C" EncodedJSValue HTTPServerPrototype__addressGetCachedValue(JSC::EncodedJSValue thisValue) +{ + auto* thisObject = jsCast<JSHTTPServer*>(JSValue::decode(thisValue)); + return JSValue::encode(thisObject->m_address.get()); +} + JSC_DEFINE_CUSTOM_GETTER(HTTPServerPrototype__developmentGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) { auto& vm = lexicalGlobalObject->vm(); @@ -12177,6 +12647,34 @@ JSC_DEFINE_HOST_FUNCTION(HTTPServerPrototype__reloadCallback, (JSGlobalObject * return HTTPServerPrototype__doReload(thisObject->wrapped(), lexicalGlobalObject, callFrame); } +JSC_DEFINE_HOST_FUNCTION(HTTPServerPrototype__requestIPCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = lexicalGlobalObject->vm(); + + JSHTTPServer* thisObject = jsDynamicCast<JSHTTPServer*>(callFrame->thisValue()); + + if (UNLIKELY(!thisObject)) { + auto throwScope = DECLARE_THROW_SCOPE(vm); + throwVMTypeError(lexicalGlobalObject, throwScope, "Expected 'this' to be instanceof HTTPServer"_s); + return JSValue::encode({}); + } + + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + +#ifdef BUN_DEBUG + /** View the file name of the JS file that called this function + * from a debugger */ + SourceOrigin sourceOrigin = callFrame->callerSourceOrigin(vm); + const char* fileName = sourceOrigin.string().utf8().data(); + static const char* lastFileName = nullptr; + if (lastFileName != fileName) { + lastFileName = fileName; + } +#endif + + return HTTPServerPrototype__doRequestIP(thisObject->wrapped(), lexicalGlobalObject, callFrame); +} + JSC_DEFINE_HOST_FUNCTION(HTTPServerPrototype__stopCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) { auto& vm = lexicalGlobalObject->vm(); @@ -12335,6 +12833,7 @@ void JSHTTPServer::visitAdditionalChildren(Visitor& visitor) JSHTTPServer* thisObject = this; ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + visitor.append(thisObject->m_address); visitor.append(thisObject->m_hostname); visitor.append(thisObject->m_id); } @@ -12365,6 +12864,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSListenerPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -12781,6 +13281,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSMD4Prototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -13111,6 +13612,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSMD5Prototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -13441,6 +13943,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSMatchedRoutePrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -13898,6 +14401,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSNodeJSFSPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -16889,6 +17393,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSRequestPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -17514,7 +18019,7 @@ JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSRequestConstructor::construct(JSC } JSRequest* instance = JSRequest::create(vm, globalObject, structure, ptr); - vm.heap.reportExtraMemoryAllocated(Request__estimatedSize(instance->wrapped())); + vm.heap.reportExtraMemoryAllocated(instance, Request__estimatedSize(instance->wrapped())); return JSValue::encode(instance); } @@ -17608,7 +18113,7 @@ extern "C" EncodedJSValue Request__create(Zig::GlobalObject* globalObject, void* auto& vm = globalObject->vm(); JSC::Structure* structure = globalObject->JSRequestStructure(); JSRequest* instance = JSRequest::create(vm, globalObject, structure, ptr); - vm.heap.reportExtraMemoryAllocated(Request__estimatedSize(ptr)); + vm.heap.reportExtraMemoryAllocated(instance, Request__estimatedSize(ptr)); return JSValue::encode(instance); } @@ -17664,6 +18169,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSResolveMessagePrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -18085,7 +18591,7 @@ void JSResolveMessagePrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* { Base::finishCreation(vm); reifyStaticProperties(vm, JSResolveMessage::info(), JSResolveMessagePrototypeTableValues, *this); - this->putDirect(vm, vm.propertyNames->toPrimitiveSymbol, JSFunction::create(vm, globalObject, 1, String("toPrimitive"_s), ResolveMessagePrototype__toPrimitiveCallback, ImplementationVisibility::Public), PropertyAttribute::Function | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | 0); + this->putDirect(vm, vm.propertyNames->toPrimitiveSymbol, JSFunction::create(vm, globalObject, 1, String("toPrimitive"_s), ResolveMessagePrototype__toPrimitiveCallback, ImplementationVisibility::Public), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | 0); this->putDirect(vm, vm.propertyNames->name, jsString(vm, String("ResolveMessage"_s)), PropertyAttribute::ReadOnly | 0); JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); } @@ -18287,6 +18793,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSResponsePrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -18841,7 +19348,7 @@ JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSResponseConstructor::construct(JS } JSResponse* instance = JSResponse::create(vm, globalObject, structure, ptr); - vm.heap.reportExtraMemoryAllocated(Response__estimatedSize(instance->wrapped())); + vm.heap.reportExtraMemoryAllocated(instance, Response__estimatedSize(instance->wrapped())); return JSValue::encode(instance); } @@ -18935,7 +19442,7 @@ extern "C" EncodedJSValue Response__create(Zig::GlobalObject* globalObject, void auto& vm = globalObject->vm(); JSC::Structure* structure = globalObject->JSResponseStructure(); JSResponse* instance = JSResponse::create(vm, globalObject, structure, ptr); - vm.heap.reportExtraMemoryAllocated(Response__estimatedSize(ptr)); + vm.heap.reportExtraMemoryAllocated(instance, Response__estimatedSize(ptr)); return JSValue::encode(instance); } @@ -18991,6 +19498,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSSHA1Prototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -19321,6 +19829,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSSHA224Prototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -19651,6 +20160,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSSHA256Prototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -19981,6 +20491,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSSHA384Prototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -20311,6 +20822,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSSHA512Prototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -20641,6 +21153,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSSHA512_256Prototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -20971,6 +21484,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSServerWebSocketPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -21929,6 +22443,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSStatWatcherPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -22201,6 +22716,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSStatsPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -23173,6 +23689,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSSubprocessPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -23736,6 +24253,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSTCPSocketPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -24723,8 +25241,10 @@ bool JSTCPSocket::hasPendingActivity(void* ctx) JSTCPSocket::~JSTCPSocket() { + printf("~JSTCPSocket\n"); if (m_ctx) { TCPSocketClass__finalize(m_ctx); + m_ctx = nullptr; } } void JSTCPSocket::destroy(JSCell* cell) @@ -24847,6 +25367,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSTLSSocketPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -25958,6 +26479,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSTextChunkPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -26324,6 +26846,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSTextDecoderPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -26409,12 +26932,16 @@ JSC_DECLARE_CUSTOM_GETTER(TextDecoderPrototype__encodingGetterWrap); extern "C" JSC::EncodedJSValue TextDecoderPrototype__getFatal(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); JSC_DECLARE_CUSTOM_GETTER(TextDecoderPrototype__fatalGetterWrap); +extern "C" JSC::EncodedJSValue TextDecoderPrototype__getIgnoreBOM(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); +JSC_DECLARE_CUSTOM_GETTER(TextDecoderPrototype__ignoreBOMGetterWrap); + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSTextDecoderPrototype, JSTextDecoderPrototype::Base); static const HashTableValue JSTextDecoderPrototypeTableValues[] = { { "decode"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::DOMJITFunctionType, TextDecoderPrototype__decodeCallback, &DOMJITSignatureForTextDecoderPrototype__decode } }, { "encoding"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, TextDecoderPrototype__encodingGetterWrap, 0 } }, - { "fatal"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, TextDecoderPrototype__fatalGetterWrap, 0 } } + { "fatal"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, TextDecoderPrototype__fatalGetterWrap, 0 } }, + { "ignoreBOM"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, TextDecoderPrototype__ignoreBOMGetterWrap, 0 } } }; const ClassInfo JSTextDecoderPrototype::s_info = { "TextDecoder"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTextDecoderPrototype) }; @@ -26502,6 +27029,18 @@ JSC_DEFINE_CUSTOM_GETTER(TextDecoderPrototype__fatalGetterWrap, (JSGlobalObject RELEASE_AND_RETURN(throwScope, result); } +JSC_DEFINE_CUSTOM_GETTER(TextDecoderPrototype__ignoreBOMGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) +{ + auto& vm = lexicalGlobalObject->vm(); + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + JSTextDecoder* thisObject = jsCast<JSTextDecoder*>(JSValue::decode(thisValue)); + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + JSC::EncodedJSValue result = TextDecoderPrototype__getIgnoreBOM(thisObject->wrapped(), globalObject); + RETURN_IF_EXCEPTION(throwScope, {}); + RELEASE_AND_RETURN(throwScope, result); +} + void JSTextDecoderPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject) { Base::finishCreation(vm); @@ -26700,6 +27239,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSTimeoutPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -26914,7 +27454,7 @@ void JSTimeoutPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* global { Base::finishCreation(vm); reifyStaticProperties(vm, JSTimeout::info(), JSTimeoutPrototypeTableValues, *this); - this->putDirect(vm, vm.propertyNames->toPrimitiveSymbol, JSFunction::create(vm, globalObject, 1, String("toPrimitive"_s), TimeoutPrototype__toPrimitiveCallback, ImplementationVisibility::Public), PropertyAttribute::Function | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | 0); + this->putDirect(vm, vm.propertyNames->toPrimitiveSymbol, JSFunction::create(vm, globalObject, 1, String("toPrimitive"_s), TimeoutPrototype__toPrimitiveCallback, ImplementationVisibility::Public), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | 0); JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); } @@ -27042,6 +27582,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSTranspilerPrototype, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) diff --git a/src/bun.js/bindings/ZigGeneratedClasses.h b/src/bun.js/bindings/ZigGeneratedClasses.h index 142a96746..c1d7ca99e 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses.h +++ b/src/bun.js/bindings/ZigGeneratedClasses.h @@ -510,6 +510,7 @@ public: template<typename Visitor> void visitAdditionalChildren(Visitor&); DECLARE_VISIT_OUTPUT_CONSTRAINTS; + mutable JSC::WriteBarrier<JSC::Unknown> m_address; mutable JSC::WriteBarrier<JSC::Unknown> m_hostname; mutable JSC::WriteBarrier<JSC::Unknown> m_id; }; @@ -567,6 +568,7 @@ public: template<typename Visitor> void visitAdditionalChildren(Visitor&); DECLARE_VISIT_OUTPUT_CONSTRAINTS; + mutable JSC::WriteBarrier<JSC::Unknown> m_address; mutable JSC::WriteBarrier<JSC::Unknown> m_hostname; mutable JSC::WriteBarrier<JSC::Unknown> m_id; }; @@ -1004,6 +1006,62 @@ public: void finishCreation(JSC::VM&); }; +class JSExpectArrayContaining final : public JSC::JSDestructibleObject { +public: + using Base = JSC::JSDestructibleObject; + static JSExpectArrayContaining* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx); + + DECLARE_EXPORT_INFO; + template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if constexpr (mode == JSC::SubspaceAccess::Concurrently) + return nullptr; + return WebCore::subspaceForImpl<JSExpectArrayContaining, WebCore::UseCustomHeapCellType::No>( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForExpectArrayContaining.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForExpectArrayContaining = std::forward<decltype(space)>(space); }, + [](auto& spaces) { return spaces.m_subspaceForExpectArrayContaining.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForExpectArrayContaining = std::forward<decltype(space)>(space); }); + } + + static void destroy(JSC::JSCell*); + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(static_cast<JSC::JSType>(0b11101110), StructureFlags), info()); + } + + static JSObject* createPrototype(VM& vm, JSDOMGlobalObject* globalObject); + ; + + ~JSExpectArrayContaining(); + + void* wrapped() const { return m_ctx; } + + void detach() + { + m_ctx = nullptr; + } + + static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); + static ptrdiff_t offsetOfWrapped() { return OBJECT_OFFSETOF(JSExpectArrayContaining, m_ctx); } + + void* m_ctx { nullptr }; + + JSExpectArrayContaining(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr) + : Base(vm, structure) + { + m_ctx = sinkPtr; + } + + void finishCreation(JSC::VM&); + + DECLARE_VISIT_CHILDREN; + template<typename Visitor> void visitAdditionalChildren(Visitor&); + DECLARE_VISIT_OUTPUT_CONSTRAINTS; + + mutable JSC::WriteBarrier<JSC::Unknown> m_arrayValue; +}; + class JSExpectStringContaining final : public JSC::JSDestructibleObject { public: using Base = JSC::JSDestructibleObject; @@ -1416,6 +1474,7 @@ public: template<typename Visitor> void visitAdditionalChildren(Visitor&); DECLARE_VISIT_OUTPUT_CONSTRAINTS; + mutable JSC::WriteBarrier<JSC::Unknown> m_address; mutable JSC::WriteBarrier<JSC::Unknown> m_hostname; mutable JSC::WriteBarrier<JSC::Unknown> m_id; }; @@ -1473,6 +1532,7 @@ public: template<typename Visitor> void visitAdditionalChildren(Visitor&); DECLARE_VISIT_OUTPUT_CONSTRAINTS; + mutable JSC::WriteBarrier<JSC::Unknown> m_address; mutable JSC::WriteBarrier<JSC::Unknown> m_hostname; mutable JSC::WriteBarrier<JSC::Unknown> m_id; }; diff --git a/src/bun.js/bindings/ZigGeneratedCode.cpp b/src/bun.js/bindings/ZigGeneratedCode.cpp index 057eaf28e..777c6455e 100644 --- a/src/bun.js/bindings/ZigGeneratedCode.cpp +++ b/src/bun.js/bindings/ZigGeneratedCode.cpp @@ -51,8 +51,7 @@ extern "C" void FFI__ptr__put(JSC::JSGlobalObject* globalObject, JSC::EncodedJSV thisObject->putDirect( globalObject->vm(), Identifier::fromString(globalObject->vm(), "ptr"_s), - function, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction | 0); + function); } extern "C" JSC_DECLARE_HOST_FUNCTION(Reader__u8__slowpathWrapper); @@ -92,8 +91,7 @@ extern "C" void Reader__u8__put(JSC::JSGlobalObject* globalObject, JSC::EncodedJ thisObject->putDirect( globalObject->vm(), Identifier::fromString(globalObject->vm(), "u8"_s), - function, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction | 0); + function); } extern "C" JSC_DECLARE_HOST_FUNCTION(Reader__u16__slowpathWrapper); @@ -133,8 +131,7 @@ extern "C" void Reader__u16__put(JSC::JSGlobalObject* globalObject, JSC::Encoded thisObject->putDirect( globalObject->vm(), Identifier::fromString(globalObject->vm(), "u16"_s), - function, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction | 0); + function); } extern "C" JSC_DECLARE_HOST_FUNCTION(Reader__u32__slowpathWrapper); @@ -174,8 +171,7 @@ extern "C" void Reader__u32__put(JSC::JSGlobalObject* globalObject, JSC::Encoded thisObject->putDirect( globalObject->vm(), Identifier::fromString(globalObject->vm(), "u32"_s), - function, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction | 0); + function); } extern "C" JSC_DECLARE_HOST_FUNCTION(Reader__ptr__slowpathWrapper); @@ -215,8 +211,7 @@ extern "C" void Reader__ptr__put(JSC::JSGlobalObject* globalObject, JSC::Encoded thisObject->putDirect( globalObject->vm(), Identifier::fromString(globalObject->vm(), "ptr"_s), - function, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction | 0); + function); } extern "C" JSC_DECLARE_HOST_FUNCTION(Reader__i8__slowpathWrapper); @@ -256,8 +251,7 @@ extern "C" void Reader__i8__put(JSC::JSGlobalObject* globalObject, JSC::EncodedJ thisObject->putDirect( globalObject->vm(), Identifier::fromString(globalObject->vm(), "i8"_s), - function, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction | 0); + function); } extern "C" JSC_DECLARE_HOST_FUNCTION(Reader__i16__slowpathWrapper); @@ -297,8 +291,7 @@ extern "C" void Reader__i16__put(JSC::JSGlobalObject* globalObject, JSC::Encoded thisObject->putDirect( globalObject->vm(), Identifier::fromString(globalObject->vm(), "i16"_s), - function, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction | 0); + function); } extern "C" JSC_DECLARE_HOST_FUNCTION(Reader__i32__slowpathWrapper); @@ -338,8 +331,7 @@ extern "C" void Reader__i32__put(JSC::JSGlobalObject* globalObject, JSC::Encoded thisObject->putDirect( globalObject->vm(), Identifier::fromString(globalObject->vm(), "i32"_s), - function, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction | 0); + function); } extern "C" JSC_DECLARE_HOST_FUNCTION(Reader__i64__slowpathWrapper); @@ -379,8 +371,7 @@ extern "C" void Reader__i64__put(JSC::JSGlobalObject* globalObject, JSC::Encoded thisObject->putDirect( globalObject->vm(), Identifier::fromString(globalObject->vm(), "i64"_s), - function, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction | 0); + function); } extern "C" JSC_DECLARE_HOST_FUNCTION(Reader__u64__slowpathWrapper); @@ -420,8 +411,7 @@ extern "C" void Reader__u64__put(JSC::JSGlobalObject* globalObject, JSC::Encoded thisObject->putDirect( globalObject->vm(), Identifier::fromString(globalObject->vm(), "u64"_s), - function, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction | 0); + function); } extern "C" JSC_DECLARE_HOST_FUNCTION(Reader__intptr__slowpathWrapper); @@ -461,8 +451,7 @@ extern "C" void Reader__intptr__put(JSC::JSGlobalObject* globalObject, JSC::Enco thisObject->putDirect( globalObject->vm(), Identifier::fromString(globalObject->vm(), "intptr"_s), - function, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction | 0); + function); } extern "C" JSC_DECLARE_HOST_FUNCTION(Reader__f32__slowpathWrapper); @@ -502,8 +491,7 @@ extern "C" void Reader__f32__put(JSC::JSGlobalObject* globalObject, JSC::Encoded thisObject->putDirect( globalObject->vm(), Identifier::fromString(globalObject->vm(), "f32"_s), - function, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction | 0); + function); } extern "C" JSC_DECLARE_HOST_FUNCTION(Reader__f64__slowpathWrapper); @@ -543,8 +531,7 @@ extern "C" void Reader__f64__put(JSC::JSGlobalObject* globalObject, JSC::Encoded thisObject->putDirect( globalObject->vm(), Identifier::fromString(globalObject->vm(), "f64"_s), - function, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction | 0); + function); } /* -- END DOMCall DEFINITIONS-- */ diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index cdc4adb1b..93f9a0fa2 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -23,6 +23,7 @@ #include "JavaScriptCore/InitializeThreading.h" #include "JavaScriptCore/IteratorOperations.h" #include "JavaScriptCore/JSArray.h" +#include "JavaScriptCore/JSGlobalProxyInlines.h" #include "JavaScriptCore/JSCallbackConstructor.h" #include "JavaScriptCore/JSCallbackObject.h" @@ -38,6 +39,7 @@ #include "JavaScriptCore/JSMap.h" #include "JavaScriptCore/JSModuleLoader.h" #include "JavaScriptCore/JSModuleNamespaceObject.h" +#include "JavaScriptCore/JSModuleNamespaceObjectInlines.h" #include "JavaScriptCore/JSModuleRecord.h" #include "JavaScriptCore/JSNativeStdFunction.h" #include "JavaScriptCore/JSObject.h" @@ -103,6 +105,7 @@ #include "JavaScriptCore/LazyClassStructure.h" #include "JavaScriptCore/LazyClassStructureInlines.h" #include "JavaScriptCore/FunctionPrototype.h" +#include "JavaScriptCore/GetterSetter.h" #include "napi.h" #include "JSSQLStatement.h" #include "ModuleLoader.h" @@ -125,6 +128,8 @@ #include "JSDOMFile.h" +#include "ProcessBindingConstants.h" + #if ENABLE(REMOTE_INSPECTOR) #include "JavaScriptCore/RemoteInspectorServer.h" #endif @@ -186,9 +191,6 @@ namespace JSCastingHelpers = JSC::JSCastingHelpers; #include "DOMJITHelpers.h" #include <JavaScriptCore/DFGAbstractHeap.h> -#include "webcrypto/JSCryptoKey.h" -#include "webcrypto/JSSubtleCrypto.h" - #include "JSDOMFormData.h" #include "JSDOMBinding.h" #include "JSDOMConstructor.h" @@ -201,6 +203,7 @@ namespace JSCastingHelpers = JSC::JSCastingHelpers; #include "JSDOMConvertStrings.h" #include "JSDOMConvertUnion.h" #include "AddEventListenerOptions.h" +#include "JSSocketAddress.h" #include "ErrorStackTrace.h" #include "CallSite.h" @@ -211,6 +214,9 @@ namespace JSCastingHelpers = JSC::JSCastingHelpers; #include <wtf/text/Base64.h> #include "simdutf.h" #include "libusockets.h" +#include "KeyObject.h" +#include "webcrypto/JSCryptoKey.h" +#include "webcrypto/JSSubtleCrypto.h" constexpr size_t DEFAULT_ERROR_STACK_TRACE_LIMIT = 10; @@ -226,6 +232,10 @@ static bool has_loaded_jsc = false; Structure* createMemoryFootprintStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject); +namespace Bun { +extern JSC::EncodedJSValue Process_functionInternalGetWindowSize(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame); +} + namespace WebCore { class Base64Utilities { public: @@ -270,6 +280,7 @@ extern "C" void JSCInitialize(const char* envp[], size_t envc, void (*onCrash)(c JSC::Options::useShadowRealm() = true; JSC::Options::useResizableArrayBuffer() = true; JSC::Options::usePromiseWithResolversMethod() = true; + JSC::Options::useV8DateParser() = true; #ifdef BUN_DEBUG JSC::Options::showPrivateScriptsInStackTraces() = true; @@ -305,29 +316,16 @@ static bool skipNextComputeErrorInfo = false; // error.stack calls this function static String computeErrorInfoWithoutPrepareStackTrace(JSC::VM& vm, Vector<StackFrame>& stackTrace, unsigned& line, unsigned& column, String& sourceURL, JSObject* errorInstance) { - if (!errorInstance) { - return String(); - } - - if (skipNextComputeErrorInfo) { - return String(); - } - - Zig::GlobalObject* globalObject = jsDynamicCast<Zig::GlobalObject*>(errorInstance->globalObject()); - if (!globalObject) { - // Happens in node:vm - globalObject = jsDynamicCast<Zig::GlobalObject*>(Bun__getDefaultGlobal()); - } + auto* lexicalGlobalObject = errorInstance->globalObject(); + Zig::GlobalObject* globalObject = jsDynamicCast<Zig::GlobalObject*>(lexicalGlobalObject); WTF::String name = "Error"_s; WTF::String message; - if (errorInstance) { - // Note that we are not allowed to allocate memory in here. It's called inside a finalizer. - if (auto* instance = jsDynamicCast<ErrorInstance*>(errorInstance)) { - name = instance->sanitizedNameString(globalObject); - message = instance->sanitizedMessageString(globalObject); - } + // Note that we are not allowed to allocate memory in here. It's called inside a finalizer. + if (auto* instance = jsDynamicCast<ErrorInstance*>(errorInstance)) { + name = instance->sanitizedNameString(lexicalGlobalObject); + message = instance->sanitizedMessageString(lexicalGlobalObject); } WTF::StringBuilder sb; @@ -381,20 +379,23 @@ static String computeErrorInfoWithoutPrepareStackTrace(JSC::VM& vm, Vector<Stack unsigned int thisColumn = 0; frame.computeLineAndColumn(thisLine, thisColumn); memset(remappedFrames + i, 0, sizeof(ZigStackFrame)); - remappedFrames[i].position.line = thisLine; remappedFrames[i].position.column_start = thisColumn; + String sourceURLForFrame = frame.sourceURL(vm); - if (!sourceURLForFrame.isEmpty()) { - remappedFrames[i].source_url = Bun::toString(sourceURLForFrame); - } else { - // https://github.com/oven-sh/bun/issues/3595 - remappedFrames[i].source_url = BunStringEmpty; - } + // If it's not a Zig::GlobalObject, don't bother source-mapping it. + if (globalObject) { + if (!sourceURLForFrame.isEmpty()) { + remappedFrames[i].source_url = Bun::toString(sourceURLForFrame); + } else { + // https://github.com/oven-sh/bun/issues/3595 + remappedFrames[i].source_url = BunStringEmpty; + } - // This ensures the lifetime of the sourceURL is accounted for correctly - Bun__remapStackFramePositions(globalObject, remappedFrames + i, 1); + // This ensures the lifetime of the sourceURL is accounted for correctly + Bun__remapStackFramePositions(globalObject, remappedFrames + i, 1); + } if (!hasSet) { hasSet = true; @@ -402,11 +403,9 @@ static String computeErrorInfoWithoutPrepareStackTrace(JSC::VM& vm, Vector<Stack column = thisColumn; sourceURL = frame.sourceURL(vm); - if (errorInstance) { - if (remappedFrames[i].remapped) { - errorInstance->putDirect(vm, Identifier::fromString(vm, "originalLine"_s), jsNumber(thisLine), 0); - errorInstance->putDirect(vm, Identifier::fromString(vm, "originalColumn"_s), jsNumber(thisColumn), 0); - } + if (remappedFrames[i].remapped) { + errorInstance->putDirect(vm, Identifier::fromString(vm, "originalLine"_s), jsNumber(thisLine), 0); + errorInstance->putDirect(vm, Identifier::fromString(vm, "originalColumn"_s), jsNumber(thisColumn), 0); } } @@ -428,8 +427,95 @@ static String computeErrorInfoWithoutPrepareStackTrace(JSC::VM& vm, Vector<Stack return sb.toString(); } +static String computeErrorInfoWithPrepareStackTrace(JSC::VM& vm, Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, Vector<StackFrame>& stackFrames, unsigned& line, unsigned& column, String& sourceURL, JSObject* errorObject, JSObject* prepareStackTrace) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + size_t stackTraceLimit = globalObject->stackTraceLimit().value(); + if (stackTraceLimit == 0) { + stackTraceLimit = DEFAULT_ERROR_STACK_TRACE_LIMIT; + } + + JSCStackTrace stackTrace = JSCStackTrace::fromExisting(vm, stackFrames); + + // Note: we cannot use tryCreateUninitializedRestricted here because we cannot allocate memory inside initializeIndex() + JSC::JSArray* callSites = JSC::JSArray::create(vm, + globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous), + stackTrace.size()); + + // Create the call sites (one per frame) + GlobalObject::createCallSitesFromFrames(globalObject, lexicalGlobalObject, stackTrace, callSites); + + // We need to sourcemap it if it's a GlobalObject. + if (globalObject == lexicalGlobalObject) { + size_t framesCount = stackTrace.size(); + ZigStackFrame remappedFrames[framesCount]; + for (int i = 0; i < framesCount; i++) { + memset(remappedFrames + i, 0, sizeof(ZigStackFrame)); + remappedFrames[i].source_url = Bun::toString(lexicalGlobalObject, stackTrace.at(i).sourceURL()); + if (JSCStackFrame::SourcePositions* sourcePositions = stackTrace.at(i).getSourcePositions()) { + remappedFrames[i].position.line = sourcePositions->line.zeroBasedInt(); + remappedFrames[i].position.column_start = sourcePositions->startColumn.zeroBasedInt() + 1; + } else { + remappedFrames[i].position.line = -1; + remappedFrames[i].position.column_start = -1; + } + } + + Bun__remapStackFramePositions(globalObject, remappedFrames, framesCount); + + for (size_t i = 0; i < framesCount; i++) { + JSC::JSValue callSiteValue = callSites->getIndex(lexicalGlobalObject, i); + CallSite* callSite = JSC::jsDynamicCast<CallSite*>(callSiteValue); + if (remappedFrames[i].remapped) { + int32_t remappedColumnStart = remappedFrames[i].position.column_start; + JSC::JSValue columnNumber = JSC::jsNumber(remappedColumnStart); + callSite->setColumnNumber(columnNumber); + + int32_t remappedLine = remappedFrames[i].position.line; + JSC::JSValue lineNumber = JSC::jsNumber(remappedLine); + callSite->setLineNumber(lineNumber); + } + } + } + + globalObject->formatStackTrace(vm, lexicalGlobalObject, errorObject, callSites, prepareStackTrace); + + RETURN_IF_EXCEPTION(scope, String()); + return String(); +} + static String computeErrorInfo(JSC::VM& vm, Vector<StackFrame>& stackTrace, unsigned& line, unsigned& column, String& sourceURL, JSObject* errorInstance) { + if (skipNextComputeErrorInfo) { + return String(); + } + + if (!errorInstance) { + return String(); + } + + auto* lexicalGlobalObject = errorInstance->globalObject(); + Zig::GlobalObject* globalObject = jsDynamicCast<Zig::GlobalObject*>(lexicalGlobalObject); + + // Error.prepareStackTrace - https://v8.dev/docs/stack-trace-api#customizing-stack-traces + if (!globalObject) { + // node:vm will use a different JSGlobalObject + globalObject = Bun__getDefaultGlobal(); + + auto* errorConstructor = lexicalGlobalObject->m_errorStructure.constructor(lexicalGlobalObject); + if (JSValue prepareStackTrace = errorConstructor->getIfPropertyExists(lexicalGlobalObject, Identifier::fromString(vm, "prepareStackTrace"_s))) { + if (prepareStackTrace.isCell() && prepareStackTrace.isObject() && prepareStackTrace.isCallable()) { + return computeErrorInfoWithPrepareStackTrace(vm, globalObject, lexicalGlobalObject, stackTrace, line, column, sourceURL, errorInstance, prepareStackTrace.getObject()); + } + } + } else { + if (JSValue prepareStackTrace = globalObject->m_errorConstructorPrepareStackTraceValue.get()) { + if (prepareStackTrace.isCell() && prepareStackTrace.isObject() && prepareStackTrace.isCallable()) { + return computeErrorInfoWithPrepareStackTrace(vm, globalObject, lexicalGlobalObject, stackTrace, line, column, sourceURL, errorInstance, prepareStackTrace.getObject()); + } + } + } + return computeErrorInfoWithoutPrepareStackTrace(vm, stackTrace, line, column, sourceURL, errorInstance); } @@ -627,69 +713,17 @@ extern "C" bool Zig__GlobalObject__resetModuleRegistryMap(JSC__JSGlobalObject* g return true; } -#define BUN_LAZY_GETTER_FN_NAME(GetterName) BunLazyGetter##GetterName##_getter - -#define DEFINE_BUN_LAZY_GETTER(GetterName, __propertyName) \ - JSC_DEFINE_CUSTOM_GETTER(GetterName, \ - (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, \ - JSC::PropertyName)) \ - { \ - Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject); \ - return JSC::JSValue::encode(thisObject->__propertyName()); \ - } - -#define GENERATED_CONSTRUCTOR_GETTER(ConstructorName) \ - JSC_DECLARE_CUSTOM_GETTER(ConstructorName##_getter); \ - JSC_DEFINE_CUSTOM_GETTER(ConstructorName##_getter, \ - (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, \ - JSC::PropertyName)) \ - { \ - Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject); \ - if (JSValue override = thisObject->m_##ConstructorName##SetterValue.get()) { \ - return JSC::JSValue::encode(override); \ - } \ - return JSC::JSValue::encode( \ - thisObject->ConstructorName##Constructor()); \ - } - -#define GENERATED_CONSTRUCTOR_SETTER(ConstructorName) \ - JSC_DECLARE_CUSTOM_SETTER(ConstructorName##_setter); \ - JSC_DEFINE_CUSTOM_SETTER(ConstructorName##_setter, \ - (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, \ - EncodedJSValue value, JSC::PropertyName)) \ - { \ - Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject); \ - thisObject->m_##ConstructorName##SetterValue.set(thisObject->vm(), thisObject, JSValue::decode(value)); \ - return true; \ - } - -#define WEBCORE_GENERATED_CONSTRUCTOR_GETTER(ConstructorName) \ - JSC_DECLARE_CUSTOM_GETTER(ConstructorName##_getter); \ - JSC_DEFINE_CUSTOM_GETTER(ConstructorName##_getter, \ - (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, \ - JSC::PropertyName)) \ - { \ - Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject); \ - if (JSValue override = thisObject->m_##ConstructorName##SetterValue.get()) { \ - return JSC::JSValue::encode(override); \ - } \ - return JSC::JSValue::encode( \ - WebCore::ConstructorName::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject)); \ - } - -#define WEBCORE_GENERATED_CONSTRUCTOR_SETTER(ConstructorName) \ - JSC_DECLARE_CUSTOM_SETTER(ConstructorName##_setter); \ - JSC_DEFINE_CUSTOM_SETTER(ConstructorName##_setter, \ - (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, \ - EncodedJSValue value, JSC::PropertyName)) \ - { \ - Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject); \ - thisObject->m_##ConstructorName##SetterValue.set(thisObject->vm(), thisObject, JSValue::decode(value)); \ - return true; \ - } - -#define PUT_WEBCORE_GENERATED_CONSTRUCTOR(name, ConstructorName) \ - putDirectCustomAccessor(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, name)), JSC::CustomGetterSetter::create(vm, ConstructorName##_getter, ConstructorName##_setter), 0) +#define WEBCORE_GENERATED_CONSTRUCTOR_GETTER(ConstructorName) \ + JSValue ConstructorName##ConstructorCallback(VM& vm, JSObject* lexicalGlobalObject) \ + { \ + return WebCore::JS##ConstructorName::getConstructor(vm, JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject)); \ + } \ + JSC_DEFINE_CUSTOM_GETTER(ConstructorName##_getter, \ + (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, \ + JSC::PropertyName)) \ + { \ + return JSC::JSValue::encode(WebCore::JS##ConstructorName::getConstructor(lexicalGlobalObject->vm(), JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject))); \ + } String GlobalObject::defaultAgentClusterID() { @@ -708,9 +742,6 @@ namespace Zig { using namespace WebCore; -const JSC::ClassInfo GlobalObject::s_info = { "GlobalObject"_s, &Base::s_info, nullptr, nullptr, - CREATE_METHOD_TABLE(GlobalObject) }; - static JSGlobalObject* deriveShadowRealmGlobalObject(JSGlobalObject* globalObject) { auto& vm = globalObject->vm(); @@ -734,9 +765,9 @@ extern "C" JSC__JSValue JSC__JSValue__makeWithNameAndPrototype(JSC__JSGlobalObje JSC::JSObject* wrapped = JSC::JSValue::decode(reinterpret_cast<JSC__JSValue>(wrappedRef)).getObject(); object->setPrototypeDirect(vm, wrapped); JSString* nameString = JSC::jsNontrivialString(vm, Zig::toString(*visibleInterfaceName)); - object->putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum); + object->putDirect(vm, vm.propertyNames->name, nameString, PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum); object->putDirect(vm, vm.propertyNames->toStringTagSymbol, - nameString, JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly); + nameString, PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly); return JSC::JSValue::encode(JSC::JSValue(object)); } @@ -801,7 +832,7 @@ GlobalObject::~GlobalObject() finalizer(toNapi(this), napiInstanceData, napiInstanceDataFinalizerHint); } - delete crypto; + delete m_subtleCrypto; scriptExecutionContext()->removeFromContextsMap(); } @@ -851,9 +882,31 @@ void GlobalObject::setConsole(void* console) this->setConsoleClient(new Zig::ConsoleClient(console)); } +JSC_DEFINE_CUSTOM_GETTER(errorConstructorPrepareStackTraceGetter, + (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, + JSC::PropertyName)) +{ + Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject); + JSValue value = jsUndefined(); + if (thisObject->m_errorConstructorPrepareStackTraceValue) { + value = thisObject->m_errorConstructorPrepareStackTraceValue.get(); + } + return JSValue::encode(value); +} + +JSC_DEFINE_CUSTOM_SETTER(errorConstructorPrepareStackTraceSetter, + (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, + JSC::EncodedJSValue encodedValue, JSC::PropertyName property)) +{ + auto& vm = JSC::getVM(lexicalGlobalObject); + Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject); + thisObject->m_errorConstructorPrepareStackTraceValue.set(vm, thisObject, JSValue::decode(encodedValue)); + return true; +} + #pragma mark - Globals -JSC_DEFINE_CUSTOM_GETTER(globalGetterOnMessage, +JSC_DEFINE_CUSTOM_GETTER(globalOnMessage, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) { @@ -861,7 +914,7 @@ JSC_DEFINE_CUSTOM_GETTER(globalGetterOnMessage, return JSValue::encode(eventHandlerAttribute(thisObject->eventTarget(), eventNames().messageEvent, thisObject->world())); } -JSC_DEFINE_CUSTOM_GETTER(globalGetterOnError, +JSC_DEFINE_CUSTOM_GETTER(globalOnError, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) { @@ -869,7 +922,7 @@ JSC_DEFINE_CUSTOM_GETTER(globalGetterOnError, return JSValue::encode(eventHandlerAttribute(thisObject->eventTarget(), eventNames().errorEvent, thisObject->world())); } -JSC_DEFINE_CUSTOM_SETTER(globalSetterOnMessage, +JSC_DEFINE_CUSTOM_SETTER(setGlobalOnMessage, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue encodedValue, JSC::PropertyName property)) { @@ -882,7 +935,7 @@ JSC_DEFINE_CUSTOM_SETTER(globalSetterOnMessage, return true; } -JSC_DEFINE_CUSTOM_SETTER(globalSetterOnError, +JSC_DEFINE_CUSTOM_SETTER(setGlobalOnError, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue encodedValue, JSC::PropertyName property)) { @@ -900,8 +953,6 @@ WebCore::EventTarget& GlobalObject::eventTarget() return globalEventScope; } -JSC_DECLARE_CUSTOM_GETTER(functionLazyLoadStreamPrototypeMap_getter); - JSC_DEFINE_CUSTOM_GETTER(functionLazyLoadStreamPrototypeMap_getter, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) @@ -911,165 +962,61 @@ JSC_DEFINE_CUSTOM_GETTER(functionLazyLoadStreamPrototypeMap_getter, thisObject->readableStreamNativeMap()); } -JSC_DECLARE_CUSTOM_GETTER(JSDOMURL_getter); - -JSC_DEFINE_CUSTOM_GETTER(JSDOMURL_getter, - (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, - JSC::PropertyName)) -{ - Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject); - return JSC::JSValue::encode( - WebCore::JSDOMURL::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject)); -} - -JSC_DEFINE_CUSTOM_GETTER(JSBuffer_privateGetter, - (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, - JSC::PropertyName)) -{ - Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject); - return JSC::JSValue::encode( - thisObject->JSBufferConstructor()); -} - -GENERATED_CONSTRUCTOR_GETTER(JSBuffer); -GENERATED_CONSTRUCTOR_SETTER(JSBuffer); - -GENERATED_CONSTRUCTOR_GETTER(JSTextDecoder); -GENERATED_CONSTRUCTOR_SETTER(JSTextDecoder); - -GENERATED_CONSTRUCTOR_GETTER(JSResponse); -GENERATED_CONSTRUCTOR_SETTER(JSResponse); - -GENERATED_CONSTRUCTOR_GETTER(JSRequest); -GENERATED_CONSTRUCTOR_SETTER(JSRequest); - -GENERATED_CONSTRUCTOR_GETTER(JSBlob); -GENERATED_CONSTRUCTOR_SETTER(JSBlob); - -GENERATED_CONSTRUCTOR_GETTER(JSHTMLRewriter); -GENERATED_CONSTRUCTOR_SETTER(JSHTMLRewriter); - -GENERATED_CONSTRUCTOR_GETTER(JSCrypto); -GENERATED_CONSTRUCTOR_SETTER(JSCrypto); - -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSMessageEvent); -WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSMessageEvent); - -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSWebSocket); -WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSWebSocket); - -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSFetchHeaders); -WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSFetchHeaders); - -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSTextEncoder); -WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSTextEncoder); - -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSURLSearchParams); -WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSURLSearchParams); - -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSDOMFormData); -WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSDOMFormData); - -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSWorker); -WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSWorker); - -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSMessageChannel); -WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSMessageChannel); - -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSMessagePort); -WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSMessagePort); - -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSBroadcastChannel); -WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSBroadcastChannel); - -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSEvent); -WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSEvent); - -JSC_DECLARE_CUSTOM_GETTER(JSEvent_getter); - -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSDOMException); -WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSDOMException); - -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSEventTarget); -WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSEventTarget); - -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSCustomEvent); -WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSCustomEvent); - -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSErrorEvent); -WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSErrorEvent); - -WEBCORE_GENERATED_CONSTRUCTOR_GETTER(JSCloseEvent); -WEBCORE_GENERATED_CONSTRUCTOR_SETTER(JSCloseEvent); - -JSC_DECLARE_CUSTOM_GETTER(JSDOMAbortController_getter); - -JSC_DEFINE_CUSTOM_GETTER(JSDOMAbortController_getter, +JSC_DEFINE_CUSTOM_GETTER(JSBuffer_getter, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) { - Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject); - return JSC::JSValue::encode( - WebCore::JSAbortController::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject)); -} - -JSC_DECLARE_CUSTOM_GETTER(JSDOMAbortSignal_getter); - -JSC_DEFINE_CUSTOM_GETTER(JSDOMAbortSignal_getter, - (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, - JSC::PropertyName)) -{ - Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject); - return JSC::JSValue::encode( - WebCore::JSAbortSignal::getConstructor(JSC::getVM(lexicalGlobalObject), thisObject)); -} - -static JSC_DECLARE_CUSTOM_SETTER(property_lazyProcessSetter); -static JSC_DECLARE_CUSTOM_GETTER(property_lazyProcessGetter); - -JSC_DEFINE_CUSTOM_SETTER(property_lazyProcessSetter, - (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, - JSC::EncodedJSValue value, JSC::PropertyName)) -{ - return false; -} - -JSC_DEFINE_CUSTOM_GETTER(property_lazyProcessGetter, - (JSC::JSGlobalObject * _globalObject, JSC::EncodedJSValue thisValue, - JSC::PropertyName)) -{ - Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(_globalObject); - - JSC::VM& vm = globalObject->vm(); - auto clientData = WebCore::clientData(vm); - return JSC::JSValue::encode( - globalObject->processObject()); -} - -JSC_DEFINE_CUSTOM_GETTER(property_lazyCryptoGetter, - (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, - JSC::PropertyName property)) + return JSC::JSValue::encode(JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject)->JSBufferConstructor()); +} + +// This macro defines the getter needed for ZigGlobalObject.lut.h +// "<ClassName>ConstructorCallback" is a PropertyCallback +// it also defines "<ClassName>_getter" which is the getter for a JSC::CustomGetterSetter +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(AbortController); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(AbortSignal); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(BroadcastChannel); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(ByteLengthQueuingStrategy) +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(CloseEvent); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(CountQueuingStrategy) +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(CryptoKey); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(CustomEvent); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(DOMException); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(DOMFormData); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(DOMURL); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(ErrorEvent); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(Event); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(EventTarget); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(FetchHeaders); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(MessageChannel); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(MessageEvent); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(MessagePort); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(ReadableByteStreamController) +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(ReadableStream) +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(ReadableStreamBYOBReader) +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(ReadableStreamBYOBRequest) +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(ReadableStreamDefaultController) +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(ReadableStreamDefaultReader) +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(SubtleCrypto); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(TextEncoder); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(TransformStream) +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(TransformStreamDefaultController) +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(URLSearchParams); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(WebSocket); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(Worker); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(WritableStream); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(WritableStreamDefaultController); +WEBCORE_GENERATED_CONSTRUCTOR_GETTER(WritableStreamDefaultWriter); + +JSC_DEFINE_HOST_FUNCTION(functionGetSelf, + (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { - Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(JSValue::decode(thisValue)); - JSValue cryptoObject = thisObject->cryptoObject(); - thisObject->putDirect(thisObject->vm(), property, cryptoObject, JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - return JSValue::encode(cryptoObject); + return JSC::JSValue::encode(callFrame->thisValue()); } -JSC_DEFINE_CUSTOM_SETTER(lazyProcessEnvSetter, - (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, - JSC::EncodedJSValue value, JSC::PropertyName)) -{ - return false; -} - -JSC_DEFINE_CUSTOM_GETTER(lazyProcessEnvGetter, - (JSC::JSGlobalObject * _globalObject, JSC::EncodedJSValue thisValue, - JSC::PropertyName)) +JSC_DEFINE_HOST_FUNCTION(functionSetSelf, + (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { - Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(_globalObject); - return JSC::JSValue::encode( - globalObject->processEnvObject()); + return JSC::JSValue::encode(jsUndefined()); } JSC_DEFINE_HOST_FUNCTION(functionQueueMicrotask, @@ -1385,7 +1332,7 @@ JSC_DEFINE_HOST_FUNCTION(functionBTOA, static_cast<uint8_t>(WebCore::BufferEncodingType::base64))); } -static JSC_DEFINE_HOST_FUNCTION(functionATOB, +JSC_DEFINE_HOST_FUNCTION(functionATOB, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { JSC::VM& vm = globalObject->vm(); @@ -1408,7 +1355,7 @@ static JSC_DEFINE_HOST_FUNCTION(functionATOB, RELEASE_AND_RETURN(throwScope, JSValue::encode(jsString(vm, result.releaseReturnValue()))); } -static JSC_DEFINE_HOST_FUNCTION(functionReportError, +JSC_DEFINE_HOST_FUNCTION(functionReportError, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { switch (callFrame->argumentCount()) { @@ -1538,6 +1485,89 @@ JSC_DEFINE_HOST_FUNCTION(jsTTYSetMode, (JSC::JSGlobalObject * globalObject, Call return JSValue::encode(jsNumber(err)); } +JSC_DEFINE_HOST_FUNCTION(jsHTTPGetHeader, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSValue headersValue = callFrame->argument(0); + + if (auto* headers = jsDynamicCast<WebCore::JSFetchHeaders*>(headersValue)) { + JSValue nameValue = callFrame->argument(1); + if (nameValue.isString()) { + FetchHeaders* impl = &headers->wrapped(); + String name = nameValue.toWTFString(globalObject); + if (WTF::equalIgnoringASCIICase(name, "set-cookie"_s)) { + return fetchHeadersGetSetCookie(globalObject, vm, impl); + } + + WebCore::ExceptionOr<String> res = impl->get(name); + if (res.hasException()) { + WebCore::propagateException(globalObject, scope, res.releaseException()); + return JSValue::encode(jsUndefined()); + } + + String value = res.returnValue(); + if (value.isEmpty()) { + return JSValue::encode(jsUndefined()); + } + + return JSC::JSValue::encode(jsString(vm, value)); + } + } + + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsHTTPSetHeader, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + auto& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSValue headersValue = callFrame->argument(0); + + if (auto* headers = jsDynamicCast<WebCore::JSFetchHeaders*>(headersValue)) { + JSValue nameValue = callFrame->argument(1); + if (nameValue.isString()) { + String name = nameValue.toWTFString(globalObject); + FetchHeaders* impl = &headers->wrapped(); + + JSValue valueValue = callFrame->argument(2); + if (valueValue.isUndefined()) + return JSValue::encode(jsUndefined()); + + if (isArray(globalObject, valueValue)) { + auto* array = jsCast<JSArray*>(valueValue); + unsigned length = array->length(); + if (length > 0) { + JSValue item = array->getIndex(globalObject, 0); + if (UNLIKELY(scope.exception())) + return JSValue::encode(jsUndefined()); + impl->set(name, item.getString(globalObject)); + RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); + } + for (unsigned i = 1; i < length; ++i) { + JSValue value = array->getIndex(globalObject, i); + if (UNLIKELY(scope.exception())) + return JSValue::encode(jsUndefined()); + if (!value.isString()) + continue; + impl->append(name, value.getString(globalObject)); + RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); + } + RELEASE_AND_RETURN(scope, JSValue::encode(jsUndefined())); + return JSValue::encode(jsUndefined()); + } + + impl->set(name, valueValue.getString(globalObject)); + RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); + return JSValue::encode(jsUndefined()); + } + } + + return JSValue::encode(jsUndefined()); +} + JSC_DEFINE_CUSTOM_GETTER(noop_getter, (JSGlobalObject*, EncodedJSValue, PropertyName)) { return JSC::JSValue::encode(JSC::jsUndefined()); @@ -1577,15 +1607,6 @@ enum ReadableStreamTag : int32_t { Bytes = 4, }; -JSC_DEFINE_HOST_FUNCTION(functionCallNotImplemented, - (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) -{ - auto& vm = globalObject->vm(); - auto scope = DECLARE_THROW_SCOPE(vm); - throwTypeError(globalObject, scope, "Not implemented yet in Bun :("_s); - return JSC::JSValue::encode(JSC::JSValue {}); -} - JSC_DEFINE_HOST_FUNCTION(jsReceiveMessageOnPort, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) { auto& vm = lexicalGlobalObject->vm(); @@ -1614,11 +1635,9 @@ JSC_DEFINE_HOST_FUNCTION(jsReceiveMessageOnPort, (JSGlobalObject * lexicalGlobal return JSC::JSValue::encode(jsUndefined()); } -extern JSC::EncodedJSValue Process_functionInternalGetWindowSize(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame); - // we're trying out a new way to do this lazy loading // this is $lazy() in js code -static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad, +JSC_DEFINE_HOST_FUNCTION(functionLazyLoad, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame)) { @@ -1628,7 +1647,7 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad, switch (callFrame->argumentCount()) { case 0: { - JSC::throwTypeError(globalObject, scope, "lazyLoad needs 1 argument (a string)"_s); + JSC::throwTypeError(globalObject, scope, "$lazy needs 1 argument (a string)"_s); scope.release(); return JSC::JSValue::encode(JSC::JSValue {}); } @@ -1637,7 +1656,7 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad, if (moduleName.isNumber()) { switch (moduleName.toInt32(globalObject)) { case 0: { - JSC::throwTypeError(globalObject, scope, "lazyLoad expects a string"_s); + JSC::throwTypeError(globalObject, scope, "$lazy expects a string"_s); scope.release(); return JSC::JSValue::encode(JSC::JSValue {}); } @@ -1654,7 +1673,7 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad, default: { auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); - JSC::throwTypeError(globalObject, scope, "lazyLoad expects a string"_s); + JSC::throwTypeError(globalObject, scope, "$lazy expects a string"_s); scope.release(); return JSC::JSValue::encode(JSC::JSValue {}); } @@ -1663,7 +1682,7 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad, auto string = moduleName.toWTFString(globalObject); if (string.isNull()) { - JSC::throwTypeError(globalObject, scope, "lazyLoad expects a string"_s); + JSC::throwTypeError(globalObject, scope, "$lazy expects a string"_s); scope.release(); return JSC::JSValue::encode(JSC::JSValue {}); } @@ -1672,6 +1691,17 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad, return JSC::JSValue::encode(JSSQLStatementConstructor::create(vm, globalObject, JSSQLStatementConstructor::createStructure(vm, globalObject, globalObject->m_functionPrototype.get()))); } + if (string == "http"_s) { + auto* obj = constructEmptyObject(globalObject); + obj->putDirect( + vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "setHeader"_s)), + JSC::JSFunction::create(vm, globalObject, 3, "setHeader"_s, jsHTTPSetHeader, ImplementationVisibility::Public), NoIntrinsic); + obj->putDirect( + vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "getHeader"_s)), + JSC::JSFunction::create(vm, globalObject, 2, "getHeader"_s, jsHTTPGetHeader, ImplementationVisibility::Public), NoIntrinsic); + return JSC::JSValue::encode(obj); + } + if (string == "worker_threads"_s) { JSValue workerData = jsUndefined(); @@ -1729,6 +1759,41 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad, if (string == "events"_s) { return JSValue::encode(WebCore::JSEventEmitter::getConstructor(vm, globalObject)); } + + if (string == "internal/crypto"_s) { + // auto sourceOrigin = callFrame->callerSourceOrigin(vm).url(); + // bool isBuiltin = sourceOrigin.protocolIs("builtin"_s); + // if (!isBuiltin) { + // return JSC::JSValue::encode(JSC::jsUndefined()); + // } + auto* obj = constructEmptyObject(globalObject); + obj->putDirect( + vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "symmetricKeySize"_s)), JSC::JSFunction::create(vm, globalObject, 1, "symmetricKeySize"_s, KeyObject__SymmetricKeySize, ImplementationVisibility::Public, NoIntrinsic), 0); + obj->putDirect( + vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "asymmetricKeyType"_s)), JSC::JSFunction::create(vm, globalObject, 1, "asymmetricKeyType"_s, KeyObject__AsymmetricKeyType, ImplementationVisibility::Public, NoIntrinsic), 0); + obj->putDirect( + vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "asymmetricKeyDetails"_s)), JSC::JSFunction::create(vm, globalObject, 1, "asymmetricKeyDetails"_s, KeyObject_AsymmetricKeyDetails, ImplementationVisibility::Public, NoIntrinsic), 0); + obj->putDirect( + vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "equals"_s)), JSC::JSFunction::create(vm, globalObject, 2, "equals"_s, KeyObject__Equals, ImplementationVisibility::Public, NoIntrinsic), 0); + obj->putDirect( + vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "exports"_s)), JSC::JSFunction::create(vm, globalObject, 2, "exports"_s, KeyObject__Exports, ImplementationVisibility::Public, NoIntrinsic), 0); + + obj->putDirect( + vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "createSecretKey"_s)), JSC::JSFunction::create(vm, globalObject, 1, "createSecretKey"_s, KeyObject__createSecretKey, ImplementationVisibility::Public, NoIntrinsic), 0); + + obj->putDirect( + vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "createPublicKey"_s)), JSC::JSFunction::create(vm, globalObject, 1, "createPublicKey"_s, KeyObject__createPublicKey, ImplementationVisibility::Public, NoIntrinsic), 0); + + obj->putDirect( + vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "createPrivateKey"_s)), JSC::JSFunction::create(vm, globalObject, 1, "createPrivateKey"_s, KeyObject__createPrivateKey, ImplementationVisibility::Public, NoIntrinsic), 0); + + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "generateKeySync"_s)), JSC::JSFunction::create(vm, globalObject, 2, "generateKeySync"_s, KeyObject__generateKeySync, ImplementationVisibility::Public, NoIntrinsic), 0); + + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "generateKeyPairSync"_s)), JSC::JSFunction::create(vm, globalObject, 2, "generateKeyPairSync"_s, KeyObject__generateKeyPairSync, ImplementationVisibility::Public, NoIntrinsic), 0); + + return JSValue::encode(obj); + } + if (string == "internal/tls"_s) { auto* obj = constructEmptyObject(globalObject); @@ -1759,10 +1824,6 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad, return JSValue::encode(obj); } - if (string == "masqueradesAsUndefined"_s) { - return JSValue::encode(InternalFunction::createFunctionThatMasqueradesAsUndefined(vm, globalObject, 0, String(), functionCallNotImplemented)); - } - if (string == "vm"_s) { auto* obj = constructEmptyObject(globalObject); obj->putDirect( @@ -1803,7 +1864,7 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad, obj->putDirect(vm, PropertyName(Identifier::fromString(vm, "isatty"_s)), JSFunction::create(vm, globalObject, 0, "isatty"_s, jsFunctionTty_isatty, ImplementationVisibility::Public), 1); - obj->putDirect(vm, PropertyName(Identifier::fromString(vm, "getWindowSize"_s)), JSFunction::create(vm, globalObject, 0, "getWindowSize"_s, Process_functionInternalGetWindowSize, ImplementationVisibility::Public), 2); + obj->putDirect(vm, PropertyName(Identifier::fromString(vm, "getWindowSize"_s)), JSFunction::create(vm, globalObject, 0, "getWindowSize"_s, Bun::Process_functionInternalGetWindowSize, ImplementationVisibility::Public), 2); return JSValue::encode(obj); } @@ -1812,9 +1873,9 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad, auto* obj = constructEmptyObject(globalObject); obj->putDirectCustomAccessor(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "getterSetter"_s)), JSC::CustomGetterSetter::create(vm, noop_getter, noop_setter), 0); Zig::JSFFIFunction* function = Zig::JSFFIFunction::create(vm, reinterpret_cast<Zig::GlobalObject*>(globalObject), 0, String(), functionNoop, JSC::NoIntrinsic); - obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "function"_s)), function, JSC::PropertyAttribute::Function | 0); - obj->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "functionRegular"_s), 1, functionNoop, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::Function); - obj->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "callback"_s), 1, functionCallback, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::Function); + obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "function"_s)), function, 0); + obj->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "functionRegular"_s), 1, functionNoop, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); + obj->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "callback"_s), 1, functionCallback, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); return JSC::JSValue::encode(obj); } @@ -1903,173 +1964,9 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionDispatchEvent, (JSGlobalObject * lexicalGloba return jsFunctionDispatchEventBody(lexicalGlobalObject, callFrame, jsDynamicCast<Zig::GlobalObject*>(lexicalGlobalObject)); } -static inline JSValue jsServiceWorkerGlobalScope_ByteLengthQueuingStrategyConstructorGetter(JSGlobalObject& lexicalGlobalObject, Zig::GlobalObject& thisObject) -{ - UNUSED_PARAM(lexicalGlobalObject); - return JSByteLengthQueuingStrategy::getConstructor(JSC::getVM(&lexicalGlobalObject), &thisObject); -} - -JSC_DEFINE_CUSTOM_GETTER(jsServiceWorkerGlobalScope_ByteLengthQueuingStrategyConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) -{ - return IDLAttribute<Zig::GlobalObject>::get<jsServiceWorkerGlobalScope_ByteLengthQueuingStrategyConstructorGetter>(*lexicalGlobalObject, thisValue, attributeName); -} - -static inline JSValue jsServiceWorkerGlobalScope_CountQueuingStrategyConstructorGetter(JSGlobalObject& lexicalGlobalObject, Zig::GlobalObject& thisObject) -{ - UNUSED_PARAM(lexicalGlobalObject); - return JSCountQueuingStrategy::getConstructor(JSC::getVM(&lexicalGlobalObject), &thisObject); -} - -JSC_DEFINE_CUSTOM_GETTER(jsServiceWorkerGlobalScope_CountQueuingStrategyConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) -{ - return IDLAttribute<Zig::GlobalObject>::get<jsServiceWorkerGlobalScope_CountQueuingStrategyConstructorGetter>(*lexicalGlobalObject, thisValue, attributeName); -} - -static inline JSValue jsServiceWorkerGlobalScope_ReadableByteStreamControllerConstructorGetter(JSGlobalObject& lexicalGlobalObject, Zig::GlobalObject& thisObject) -{ - UNUSED_PARAM(lexicalGlobalObject); - return JSReadableByteStreamController::getConstructor(JSC::getVM(&lexicalGlobalObject), &thisObject); -} - -JSC_DEFINE_CUSTOM_GETTER(jsServiceWorkerGlobalScope_ReadableByteStreamControllerConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) -{ - return IDLAttribute<Zig::GlobalObject>::get<jsServiceWorkerGlobalScope_ReadableByteStreamControllerConstructorGetter>(*lexicalGlobalObject, thisValue, attributeName); -} - -static inline JSValue jsServiceWorkerGlobalScope_ReadableStreamConstructorGetter(JSGlobalObject& lexicalGlobalObject, Zig::GlobalObject& thisObject) -{ - UNUSED_PARAM(lexicalGlobalObject); - return JSReadableStream::getConstructor(JSC::getVM(&lexicalGlobalObject), &thisObject); -} - -JSC_DEFINE_CUSTOM_GETTER(jsServiceWorkerGlobalScope_ReadableStreamConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) -{ - return IDLAttribute<Zig::GlobalObject>::get<jsServiceWorkerGlobalScope_ReadableStreamConstructorGetter>(*lexicalGlobalObject, thisValue, attributeName); -} - -static inline JSValue jsServiceWorkerGlobalScope_ReadableStreamBYOBReaderConstructorGetter(JSGlobalObject& lexicalGlobalObject, Zig::GlobalObject& thisObject) -{ - UNUSED_PARAM(lexicalGlobalObject); - return JSReadableStreamBYOBReader::getConstructor(JSC::getVM(&lexicalGlobalObject), &thisObject); -} - -JSC_DEFINE_CUSTOM_GETTER(jsServiceWorkerGlobalScope_ReadableStreamBYOBReaderConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) -{ - return IDLAttribute<Zig::GlobalObject>::get<jsServiceWorkerGlobalScope_ReadableStreamBYOBReaderConstructorGetter>(*lexicalGlobalObject, thisValue, attributeName); -} - -static inline JSValue jsServiceWorkerGlobalScope_ReadableStreamBYOBRequestConstructorGetter(JSGlobalObject& lexicalGlobalObject, Zig::GlobalObject& thisObject) -{ - UNUSED_PARAM(lexicalGlobalObject); - return JSReadableStreamBYOBRequest::getConstructor(JSC::getVM(&lexicalGlobalObject), &thisObject); -} - -JSC_DEFINE_CUSTOM_GETTER(jsServiceWorkerGlobalScope_ReadableStreamBYOBRequestConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) -{ - return IDLAttribute<Zig::GlobalObject>::get<jsServiceWorkerGlobalScope_ReadableStreamBYOBRequestConstructorGetter>(*lexicalGlobalObject, thisValue, attributeName); -} - -static inline JSValue jsServiceWorkerGlobalScope_ReadableStreamDefaultControllerConstructorGetter(JSGlobalObject& lexicalGlobalObject, Zig::GlobalObject& thisObject) -{ - UNUSED_PARAM(lexicalGlobalObject); - return JSReadableStreamDefaultController::getConstructor(JSC::getVM(&lexicalGlobalObject), &thisObject); -} - -JSC_DEFINE_CUSTOM_GETTER(jsServiceWorkerGlobalScope_ReadableStreamDefaultControllerConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) -{ - return IDLAttribute<Zig::GlobalObject>::get<jsServiceWorkerGlobalScope_ReadableStreamDefaultControllerConstructorGetter>(*lexicalGlobalObject, thisValue, attributeName); -} - -static inline JSValue jsServiceWorkerGlobalScope_ReadableStreamDefaultReaderConstructorGetter(JSGlobalObject& lexicalGlobalObject, Zig::GlobalObject& thisObject) -{ - UNUSED_PARAM(lexicalGlobalObject); - return JSReadableStreamDefaultReader::getConstructor(JSC::getVM(&lexicalGlobalObject), &thisObject); -} - -JSC_DEFINE_CUSTOM_GETTER(jsServiceWorkerGlobalScope_ReadableStreamDefaultReaderConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) -{ - return IDLAttribute<Zig::GlobalObject>::get<jsServiceWorkerGlobalScope_ReadableStreamDefaultReaderConstructorGetter>(*lexicalGlobalObject, thisValue, attributeName); -} - -static inline JSValue jsServiceWorkerGlobalScope_TransformStreamConstructorGetter(JSGlobalObject& lexicalGlobalObject, Zig::GlobalObject& thisObject) -{ - UNUSED_PARAM(lexicalGlobalObject); - return JSTransformStream::getConstructor(JSC::getVM(&lexicalGlobalObject), &thisObject); -} - -JSC_DEFINE_CUSTOM_GETTER(jsServiceWorkerGlobalScope_TransformStreamConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) -{ - return IDLAttribute<Zig::GlobalObject>::get<jsServiceWorkerGlobalScope_TransformStreamConstructorGetter>(*lexicalGlobalObject, thisValue, attributeName); -} - -static inline JSValue jsServiceWorkerGlobalScope_TransformStreamDefaultControllerConstructorGetter(JSGlobalObject& lexicalGlobalObject, Zig::GlobalObject& thisObject) -{ - UNUSED_PARAM(lexicalGlobalObject); - return JSTransformStreamDefaultController::getConstructor(JSC::getVM(&lexicalGlobalObject), &thisObject); -} - -JSC_DEFINE_CUSTOM_GETTER(jsServiceWorkerGlobalScope_TransformStreamDefaultControllerConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) -{ - return IDLAttribute<Zig::GlobalObject>::get<jsServiceWorkerGlobalScope_TransformStreamDefaultControllerConstructorGetter>(*lexicalGlobalObject, thisValue, attributeName); -} - -static inline JSValue jsServiceWorkerGlobalScope_WritableStreamConstructorGetter(JSGlobalObject& lexicalGlobalObject, Zig::GlobalObject& thisObject) -{ - UNUSED_PARAM(lexicalGlobalObject); - return JSWritableStream::getConstructor(JSC::getVM(&lexicalGlobalObject), &thisObject); -} - -JSC_DEFINE_CUSTOM_GETTER(jsServiceWorkerGlobalScope_WritableStreamConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) -{ - return IDLAttribute<Zig::GlobalObject>::get<jsServiceWorkerGlobalScope_WritableStreamConstructorGetter>(*lexicalGlobalObject, thisValue, attributeName); -} - -static inline JSValue jsServiceWorkerGlobalScope_WritableStreamDefaultControllerConstructorGetter(JSGlobalObject& lexicalGlobalObject, Zig::GlobalObject& thisObject) -{ - UNUSED_PARAM(lexicalGlobalObject); - return JSWritableStreamDefaultController::getConstructor(JSC::getVM(&lexicalGlobalObject), &thisObject); -} - -JSC_DEFINE_CUSTOM_GETTER(jsServiceWorkerGlobalScope_WritableStreamDefaultControllerConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) -{ - return IDLAttribute<Zig::GlobalObject>::get<jsServiceWorkerGlobalScope_WritableStreamDefaultControllerConstructorGetter>(*lexicalGlobalObject, thisValue, attributeName); -} - -static inline JSValue jsServiceWorkerGlobalScope_WritableStreamDefaultWriterConstructorGetter(JSGlobalObject& lexicalGlobalObject, Zig::GlobalObject& thisObject) -{ - UNUSED_PARAM(lexicalGlobalObject); - return JSWritableStreamDefaultWriter::getConstructor(JSC::getVM(&lexicalGlobalObject), &thisObject); -} - -JSC_DEFINE_CUSTOM_GETTER(jsServiceWorkerGlobalScope_WritableStreamDefaultWriterConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) -{ - return IDLAttribute<Zig::GlobalObject>::get<jsServiceWorkerGlobalScope_WritableStreamDefaultWriterConstructorGetter>(*lexicalGlobalObject, thisValue, attributeName); -} - -JSC_DEFINE_CUSTOM_GETTER(getterSubtleCryptoConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) -{ - Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject); - return JSValue::encode( - JSSubtleCrypto::getConstructor(thisObject->vm(), thisObject)); -} - -JSC_DEFINE_CUSTOM_GETTER(getterCryptoKeyConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) -{ - Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(lexicalGlobalObject); - return JSValue::encode( - JSCryptoKey::getConstructor(thisObject->vm(), thisObject)); -} - -static inline JSValue getterSubtleCryptoBody(JSGlobalObject& lexicalGlobalObject, Zig::GlobalObject& thisObject) -{ - UNUSED_PARAM(lexicalGlobalObject); - return thisObject.subtleCrypto(); -} - JSC_DEFINE_CUSTOM_GETTER(getterSubtleCrypto, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) { - return JSValue::encode( - getterSubtleCryptoBody(*lexicalGlobalObject, *reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject))); + return JSValue::encode(reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject)->subtleCrypto()); } JSC_DECLARE_HOST_FUNCTION(makeThisTypeErrorForBuiltins); @@ -2079,6 +1976,12 @@ JSC_DECLARE_HOST_FUNCTION(createWritableStreamFromInternal); JSC_DECLARE_HOST_FUNCTION(getInternalWritableStream); JSC_DECLARE_HOST_FUNCTION(whenSignalAborted); JSC_DECLARE_HOST_FUNCTION(isAbortSignal); + +JSC_DEFINE_HOST_FUNCTION(jsCreateCJSImportMeta, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + return JSValue::encode(Zig::ImportMetaObject::create(globalObject, callFrame->argument(0).toString(globalObject))); +} + JSC_DEFINE_HOST_FUNCTION(makeThisTypeErrorForBuiltins, (JSGlobalObject * globalObject, CallFrame* callFrame)) { ASSERT(callFrame); @@ -2296,9 +2199,11 @@ static inline EncodedJSValue functionPerformanceNowBody(JSGlobalObject* globalOb { auto* global = reinterpret_cast<GlobalObject*>(globalObject); // nanoseconds to seconds - uint64_t time = Bun__readOriginTimer(global->bunVM()); + double time = static_cast<double>(Bun__readOriginTimer(global->bunVM())); double result = time / 1000000.0; - return JSValue::encode(jsNumber(result)); + + // https://github.com/oven-sh/bun/issues/5604 + return JSValue::encode(jsDoubleNumber(result)); } extern "C" { @@ -2337,11 +2242,12 @@ private: void finishCreation(JSC::VM& vm) { + Base::finishCreation(vm); static const JSC::DOMJIT::Signature DOMJITSignatureForPerformanceNow( functionPerformanceNowWithoutTypeCheck, JSPerformanceObject::info(), JSC::DOMJIT::Effect::forWriteKinds(DFG::AbstractHeapKind::SideState), - SpecBytecodeDouble); + SpecDoubleReal); JSFunction* now = JSFunction::create( vm, @@ -2350,7 +2256,7 @@ private: String("now"_s), functionPerformanceNow, ImplementationVisibility::Public, NoIntrinsic, functionPerformanceNow, &DOMJITSignatureForPerformanceNow); - this->putDirect(vm, JSC::Identifier::fromString(vm, "now"_s), now, JSC::PropertyAttribute::DOMJITFunction | JSC::PropertyAttribute::Function); + this->putDirect(vm, JSC::Identifier::fromString(vm, "now"_s), now, 0); JSFunction* noopNotImplemented = JSFunction::create( vm, @@ -2358,16 +2264,17 @@ private: 0, String("noopNotImplemented"_s), functionNoop, ImplementationVisibility::Public, NoIntrinsic, functionNoop, - &DOMJITSignatureForPerformanceNow); - this->putDirect(vm, JSC::Identifier::fromString(vm, "mark"_s), noopNotImplemented, JSC::PropertyAttribute::DOMJITFunction | JSC::PropertyAttribute::Function); - this->putDirect(vm, JSC::Identifier::fromString(vm, "markResourceTiming"_s), noopNotImplemented, JSC::PropertyAttribute::DOMJITFunction | JSC::PropertyAttribute::Function); - this->putDirect(vm, JSC::Identifier::fromString(vm, "measure"_s), noopNotImplemented, JSC::PropertyAttribute::DOMJITFunction | JSC::PropertyAttribute::Function); + nullptr); + + this->putDirect(vm, JSC::Identifier::fromString(vm, "mark"_s), noopNotImplemented, 0); + this->putDirect(vm, JSC::Identifier::fromString(vm, "markResourceTiming"_s), noopNotImplemented, 0); + this->putDirect(vm, JSC::Identifier::fromString(vm, "measure"_s), noopNotImplemented, 0); this->putDirect( vm, JSC::Identifier::fromString(vm, "timeOrigin"_s), jsNumber(Bun__readOriginTimerStart(reinterpret_cast<Zig::GlobalObject*>(this->globalObject())->bunVM())), - JSC::PropertyAttribute::ReadOnly | 0); + PropertyAttribute::ReadOnly | 0); } }; const ClassInfo JSPerformanceObject::s_info = { "Performance"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSPerformanceObject) }; @@ -2665,7 +2572,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionPerformMicrotaskVariadic, (JSGlobalObject * g return JSValue::encode(jsUndefined()); } -void GlobalObject::createCallSitesFromFrames(JSC::JSGlobalObject* lexicalGlobalObject, JSCStackTrace& stackTrace, JSC::JSArray* callSites) +void GlobalObject::createCallSitesFromFrames(Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSCStackTrace& stackTrace, JSC::JSArray* callSites) { /* From v8's "Stack Trace API" (https://github.com/v8/v8/wiki/Stack-Trace-API): * "To maintain restrictions imposed on strict mode functions, frames that have a @@ -2673,10 +2580,11 @@ void GlobalObject::createCallSitesFromFrames(JSC::JSGlobalObject* lexicalGlobalO * their receiver and function objects. For those frames, getFunction() and getThis() * will return undefined."." */ bool encounteredStrictFrame = false; - GlobalObject* globalObject = reinterpret_cast<GlobalObject*>(lexicalGlobalObject); + // TODO: is it safe to use CallSite structure from a different JSGlobalObject? This case would happen within a node:vm JSC::Structure* callSiteStructure = globalObject->callSiteStructure(); size_t framesCount = stackTrace.size(); + for (size_t i = 0; i < framesCount; i++) { CallSite* callSite = CallSite::create(lexicalGlobalObject, callSiteStructure, stackTrace.at(i), encounteredStrictFrame); callSites->putDirectIndex(lexicalGlobalObject, i, callSite); @@ -2687,40 +2595,19 @@ void GlobalObject::createCallSitesFromFrames(JSC::JSGlobalObject* lexicalGlobalO } } -JSC::JSValue GlobalObject::formatStackTrace(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSObject* errorObject, JSC::JSArray* callSites) +void GlobalObject::formatStackTrace(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSObject* errorObject, JSC::JSArray* callSites, JSValue prepareStackTrace) { auto scope = DECLARE_THROW_SCOPE(vm); - JSValue errorValue = this->get(this, JSC::Identifier::fromString(vm, "Error"_s)); - if (UNLIKELY(scope.exception())) { - return JSValue(); - } - if (!errorValue || errorValue.isUndefined() || !errorValue.isObject()) { - return JSValue(jsEmptyString(vm)); - } + auto* errorConstructor = lexicalGlobalObject->m_errorStructure.constructor(this); - auto* errorConstructor = jsDynamicCast<JSC::JSObject*>(errorValue); - - /* If the user has set a callable Error.prepareStackTrace - use it to format the stack trace. */ - JSC::JSValue prepareStackTrace = errorConstructor->getIfPropertyExists(lexicalGlobalObject, JSC::Identifier::fromString(vm, "prepareStackTrace"_s)); - if (prepareStackTrace && prepareStackTrace.isCallable()) { - JSC::CallData prepareStackTraceCallData = JSC::getCallData(prepareStackTrace); - - if (prepareStackTraceCallData.type != JSC::CallData::Type::None) { - JSC::MarkedArgumentBuffer arguments; - arguments.append(errorObject); - arguments.append(callSites); - ASSERT(!arguments.hasOverflowed()); - - JSC::JSValue result = profiledCall( - lexicalGlobalObject, - JSC::ProfilingReason::Other, - prepareStackTrace, - prepareStackTraceCallData, - errorConstructor, - arguments); - RETURN_IF_EXCEPTION(scope, JSC::jsUndefined()); - return result; + if (!prepareStackTrace) { + if (lexicalGlobalObject->inherits<Zig::GlobalObject>()) { + if (auto prepare = this->m_errorConstructorPrepareStackTraceValue.get()) { + prepareStackTrace = prepare; + } + } else { + prepareStackTrace = errorConstructor->getIfPropertyExists(lexicalGlobalObject, JSC::Identifier::fromString(vm, "prepareStackTrace"_s)); } } @@ -2749,7 +2636,43 @@ JSC::JSValue GlobalObject::formatStackTrace(JSC::VM& vm, JSC::JSGlobalObject* le } } - return JSC::JSValue(jsString(vm, sb.toString())); + bool orignialSkipNextComputeErrorInfo = skipNextComputeErrorInfo; + skipNextComputeErrorInfo = true; + if (errorObject->hasProperty(lexicalGlobalObject, vm.propertyNames->stack)) { + skipNextComputeErrorInfo = true; + errorObject->deleteProperty(lexicalGlobalObject, vm.propertyNames->stack); + } + skipNextComputeErrorInfo = orignialSkipNextComputeErrorInfo; + + // In Node, if you console.log(error.stack) inside Error.prepareStackTrace + // it will display the stack as a formatted string, so we have to do the same. + errorObject->putDirect(vm, vm.propertyNames->stack, JSC::JSValue(jsString(vm, sb.toString())), 0); + + if (prepareStackTrace && prepareStackTrace.isCallable()) { + JSC::CallData prepareStackTraceCallData = JSC::getCallData(prepareStackTrace); + + if (prepareStackTraceCallData.type != JSC::CallData::Type::None) { + JSC::MarkedArgumentBuffer arguments; + arguments.append(errorObject); + arguments.append(callSites); + + JSC::JSValue result = profiledCall( + lexicalGlobalObject, + JSC::ProfilingReason::Other, + prepareStackTrace, + prepareStackTraceCallData, + errorConstructor, + arguments); + + RETURN_IF_EXCEPTION(scope, void()); + + if (result.isUndefinedOrNull()) { + result = jsUndefined(); + } + + errorObject->putDirect(vm, vm.propertyNames->stack, result, 0); + } + } } JSC_DEFINE_HOST_FUNCTION(errorConstructorFuncAppendStackTrace, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame)) @@ -2805,9 +2728,9 @@ JSC_DEFINE_HOST_FUNCTION(errorConstructorFuncCaptureStackTrace, (JSC::JSGlobalOb stackTrace.size()); // Create the call sites (one per frame) - GlobalObject::createCallSitesFromFrames(lexicalGlobalObject, stackTrace, callSites); + GlobalObject::createCallSitesFromFrames(globalObject, lexicalGlobalObject, stackTrace, callSites); - /* Foramt the stack trace. + /* Format the stack trace. * Note that v8 won't actually format the stack trace here, but will create a "stack" accessor * on the error object, which will format the stack trace on the first access. For now, since * we're not being used internally by JSC, we can assume callers of Error.captureStackTrace in @@ -2847,23 +2770,9 @@ JSC_DEFINE_HOST_FUNCTION(errorConstructorFuncCaptureStackTrace, (JSC::JSGlobalOb } } - JSC::JSValue formattedStackTrace = globalObject->formatStackTrace(vm, lexicalGlobalObject, errorObject, callSites); + globalObject->formatStackTrace(vm, lexicalGlobalObject, errorObject, callSites, JSC::JSValue()); RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode({})); - bool orignialSkipNextComputeErrorInfo = skipNextComputeErrorInfo; - skipNextComputeErrorInfo = true; - if (errorObject->hasProperty(lexicalGlobalObject, vm.propertyNames->stack)) { - skipNextComputeErrorInfo = true; - errorObject->deleteProperty(lexicalGlobalObject, vm.propertyNames->stack); - } - skipNextComputeErrorInfo = orignialSkipNextComputeErrorInfo; - - if (formattedStackTrace.isUndefinedOrNull()) { - formattedStackTrace = JSC::jsUndefined(); - } - - errorObject->putDirect(vm, vm.propertyNames->stack, formattedStackTrace, 0); - if (auto* instance = jsDynamicCast<JSC::ErrorInstance*>(errorObject)) { // we make a separate copy of the StackTrace unfortunately so that we // can later console.log it without losing the info @@ -2900,7 +2809,7 @@ void GlobalObject::finishCreation(VM& vm) init.vm, Identifier::fromString(init.vm, "subtle"_s), JSC::CustomGetterSetter::create(init.vm, getterSubtleCrypto, nullptr), - JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | 0); + PropertyAttribute::ReadOnly | PropertyAttribute::DontDelete | 0); init.set(crypto); }); @@ -2950,11 +2859,20 @@ void GlobalObject::finishCreation(VM& vm) m_commonJSFunctionArgumentsStructure.initLater( [](const Initializer<Structure>& init) { auto* globalObject = reinterpret_cast<Zig::GlobalObject*>(init.owner); + + auto prototype = JSC::constructEmptyObject(init.owner, globalObject->objectPrototype(), 1); + prototype->putDirect( + init.vm, + Identifier::fromString(init.vm, "createImportMeta"_s), + JSFunction::create(init.vm, init.owner, 2, ""_s, jsCreateCJSImportMeta, ImplementationVisibility::Public), + PropertyAttribute::DontDelete | PropertyAttribute::DontEnum | 0); + JSC::Structure* structure = globalObject->structureCache().emptyObjectStructureForPrototype( globalObject, - globalObject->objectPrototype(), - 3); + prototype, + 5); JSC::PropertyOffset offset; + auto& vm = globalObject->vm(); structure = structure->addPropertyTransition( @@ -2967,6 +2885,20 @@ void GlobalObject::finishCreation(VM& vm) structure = structure->addPropertyTransition( vm, structure, + JSC::Identifier::fromString(vm, "require"_s), + 0, + offset); + + structure = structure->addPropertyTransition( + vm, + structure, + JSC::Identifier::fromString(vm, "resolve"_s), + 0, + offset); + + structure = structure->addPropertyTransition( + vm, + structure, JSC::Identifier::fromString(vm, "__dirname"_s), 0, offset); @@ -2981,6 +2913,11 @@ void GlobalObject::finishCreation(VM& vm) init.set(structure); }); + m_JSSocketAddressStructure.initLater( + [](const Initializer<Structure>& init) { + init.set(JSSocketAddress::createStructure(init.vm, init.owner)); + }); + // Change prototype from null to object for synthetic modules. m_moduleNamespaceObjectStructure.initLater( [](const Initializer<Structure>& init) { @@ -3022,7 +2959,7 @@ void GlobalObject::finishCreation(VM& vm) m_utilInspectFunction.initLater( [](const Initializer<JSFunction>& init) { - JSValue nodeUtilValue = static_cast<Zig::GlobalObject*>(init.owner)->internalModuleRegistry()->requireId(init.owner, init.vm, Bun::InternalModuleRegistry::Field::NodeUtil); + JSValue nodeUtilValue = jsCast<Zig::GlobalObject*>(init.owner)->internalModuleRegistry()->requireId(init.owner, init.vm, Bun::InternalModuleRegistry::Field::NodeUtil); RELEASE_ASSERT(nodeUtilValue.isObject()); init.set(jsCast<JSFunction*>(nodeUtilValue.getObject()->getIfPropertyExists(init.owner, Identifier::fromString(init.vm, "inspect"_s)))); }); @@ -3034,7 +2971,7 @@ void GlobalObject::finishCreation(VM& vm) // RETURN_IF_EXCEPTION(scope, {}); JSC::MarkedArgumentBuffer args; - args.append(static_cast<Zig::GlobalObject*>(init.owner)->utilInspectFunction()); + args.append(jsCast<Zig::GlobalObject*>(init.owner)->utilInspectFunction()); auto clientData = WebCore::clientData(init.vm); JSC::CallData callData = JSC::getCallData(getStylize); @@ -3078,7 +3015,7 @@ void GlobalObject::finishCreation(VM& vm) JSC::JSObject* obj = JSC::constructEmptyObject(init.owner, init.owner->objectPrototype(), 4); obj->putDirect(init.vm, userAgentIdentifier, JSC::jsString(init.vm, str)); obj->putDirect(init.vm, init.vm.propertyNames->toStringTagSymbol, - jsNontrivialString(init.vm, "Navigator"_s), JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly); + jsNontrivialString(init.vm, "Navigator"_s), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly); // https://developer.mozilla.org/en-US/docs/Web/API/Navigator/platform // https://github.com/oven-sh/bun/issues/4588 @@ -3091,8 +3028,7 @@ void GlobalObject::finishCreation(VM& vm) #endif obj->putDirect(init.vm, hardwareConcurrencyIdentifier, JSC::jsNumber(cpuCount)); - init.set( - obj); + init.set(obj); }); this->m_pendingVirtualModuleResultStructure.initLater( @@ -3100,6 +3036,11 @@ void GlobalObject::finishCreation(VM& vm) init.set(Bun::PendingVirtualModuleResult::createStructure(init.vm, init.owner, init.owner->objectPrototype())); }); + m_bunObject.initLater( + [](const JSC::LazyProperty<JSC::JSGlobalObject, JSObject>::Initializer& init) { + init.set(Bun::createBunObject(init.vm, init.owner)); + }); + this->initGeneratedLazyClasses(); m_cachedGlobalObjectStructure.initLater( @@ -3119,13 +3060,12 @@ void GlobalObject::finishCreation(VM& vm) m_subtleCryptoObject.initLater( [](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSObject>::Initializer& init) { auto& global = *reinterpret_cast<Zig::GlobalObject*>(init.owner); - if (global.crypto == nullptr) { - global.crypto = WebCore::SubtleCrypto::createPtr(global.scriptExecutionContext()); - global.crypto->ref(); + + if (!global.m_subtleCrypto) { + global.m_subtleCrypto = &WebCore::SubtleCrypto::create(global.scriptExecutionContext()).leakRef(); } - init.set( - toJS<IDLInterface<SubtleCrypto>>(*init.owner, global, global.crypto).getObject()); + init.set(toJS<IDLInterface<SubtleCrypto>>(*init.owner, global, global.m_subtleCrypto).getObject()); }); m_NapiClassStructure.initLater( @@ -3173,8 +3113,8 @@ void GlobalObject::finishCreation(VM& vm) m_processObject.initLater( [](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSObject>::Initializer& init) { Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(init.owner); - auto* process = Zig::Process::create( - *globalObject, Zig::Process::createStructure(init.vm, init.owner, WebCore::JSEventEmitter::prototype(init.vm, *globalObject))); + auto* process = Bun::Process::create( + *globalObject, Bun::Process::createStructure(init.vm, init.owner, WebCore::JSEventEmitter::prototype(init.vm, *globalObject))); init.set(process); }); @@ -3234,7 +3174,7 @@ void GlobalObject::finishCreation(VM& vm) }); m_processBindingConstants.initLater( - [](const JSC::LazyProperty<JSC::JSGlobalObject, Bun::ProcessBindingConstants>::Initializer& init) { + [](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSObject>::Initializer& init) { init.set( ProcessBindingConstants::create( init.vm, @@ -3291,6 +3231,14 @@ void GlobalObject::finishCreation(VM& vm) init.setConstructor(constructor); }); + m_JSCryptoKey.initLater( + [](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::Structure>::Initializer& init) { + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(init.owner); + auto* prototype = JSCryptoKey::createPrototype(init.vm, *globalObject); + auto* structure = JSCryptoKey::createStructure(init.vm, init.owner, JSValue(prototype)); + init.set(structure); + }); + m_JSHTTPSResponseSinkClassStructure.initLater( [](LazyClassStructure::Initializer& init) { auto* prototype = createJSSinkPrototype(init.vm, init.global, WebCore::SinkID::HTTPSResponseSink); @@ -3363,22 +3311,13 @@ void GlobalObject::finishCreation(VM& vm) init.setConstructor(constructor); }); - addBuiltinGlobals(vm); - #if ENABLE(REMOTE_INSPECTOR) setInspectable(false); #endif - RELEASE_ASSERT(classInfo()); + addBuiltinGlobals(vm); - JSC::JSObject* errorConstructor = this->errorConstructor(); - errorConstructor->putDirectNativeFunction(vm, this, JSC::Identifier::fromString(vm, "captureStackTrace"_s), 2, errorConstructorFuncCaptureStackTrace, ImplementationVisibility::Public, JSC::NoIntrinsic, PropertyAttribute::DontEnum | 0); - errorConstructor->putDirectNativeFunction(vm, this, JSC::Identifier::fromString(vm, "appendStackTrace"_s), 2, errorConstructorFuncAppendStackTrace, ImplementationVisibility::Private, JSC::NoIntrinsic, PropertyAttribute::DontEnum | 0); - JSC::JSValue console = this->get(this, JSC::Identifier::fromString(vm, "console"_s)); - JSC::JSObject* consoleObject = console.getObject(); - consoleObject->putDirectBuiltinFunction(vm, this, vm.propertyNames->asyncIteratorSymbol, consoleObjectAsyncIteratorCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete); - auto clientData = WebCore::clientData(vm); - consoleObject->putDirectBuiltinFunction(vm, this, clientData->builtinNames().writePublicName(), consoleObjectWriteCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::ReadOnly | PropertyAttribute::DontDelete); + ASSERT(classInfo()); } JSC_DEFINE_HOST_FUNCTION(jsFunctionPostMessage, @@ -3483,7 +3422,7 @@ JSC_DEFINE_CUSTOM_GETTER(BunCommonJSModule_getter, (JSGlobalObject * globalObjec // This implementation works the same as setTimeout(myFunction, 0) // TODO: make it more efficient // https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate -static JSC_DEFINE_HOST_FUNCTION(functionSetImmediate, +JSC_DEFINE_HOST_FUNCTION(functionSetImmediate, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { JSC::VM& vm = globalObject->vm(); @@ -3525,31 +3464,11 @@ static JSC_DEFINE_HOST_FUNCTION(functionSetImmediate, return Bun__Timer__setTimeout(globalObject, JSC::JSValue::encode(job), JSC::JSValue::encode(jsNumber(0)), JSValue::encode(arguments)); } -JSC_DEFINE_CUSTOM_GETTER(JSModuleLoader_getter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) -{ - return JSValue::encode(globalObject->moduleLoader()); -} - -JSC_DEFINE_CUSTOM_GETTER(functionResolveMessageGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) +JSValue getEventSourceConstructor(VM& vm, JSObject* thisObject) { - return JSValue::encode(reinterpret_cast<Zig::GlobalObject*>(globalObject)->JSResolveMessageConstructor()); -} -JSC_DEFINE_CUSTOM_GETTER(functionBuildMessageGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) -{ - return JSValue::encode(reinterpret_cast<Zig::GlobalObject*>(globalObject)->JSBuildMessageConstructor()); -} - -JSC_DEFINE_CUSTOM_GETTER( - EventSource_getter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName property)) -{ - auto& vm = globalObject->vm(); + auto globalObject = jsCast<Zig::GlobalObject*>(thisObject); auto scope = DECLARE_THROW_SCOPE(vm); - // If "this" is not the Global object, just return undefined - // you should not be able to reset the global object's EventSource if you muck around with prototypes - if (JSValue::decode(thisValue) != globalObject) - return JSValue::encode(JSC::jsUndefined()); - JSC::JSFunction* getSourceEvent = JSC::JSFunction::create(vm, eventSourceGetEventSourceCodeGenerator(vm), globalObject); RETURN_IF_EXCEPTION(scope, {}); @@ -3564,15 +3483,61 @@ JSC_DEFINE_CUSTOM_GETTER( if (returnedException) { throwException(globalObject, scope, returnedException.get()); + return jsUndefined(); } - RETURN_IF_EXCEPTION(scope, {}); + RELEASE_AND_RETURN(scope, result); +} - if (LIKELY(result)) { - globalObject->putDirect(vm, property, result, 0); +// `console.Console` or `import { Console } from 'console';` +JSC_DEFINE_CUSTOM_GETTER(getConsoleConstructor, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName property)) +{ + auto& vm = globalObject->vm(); + auto console = JSValue::decode(thisValue).getObject(); + JSC::JSFunction* createConsoleConstructor = JSC::JSFunction::create(vm, consoleObjectCreateConsoleConstructorCodeGenerator(vm), globalObject); + JSC::MarkedArgumentBuffer args; + args.append(console); + JSC::CallData callData = JSC::getCallData(createConsoleConstructor); + NakedPtr<JSC::Exception> returnedException = nullptr; + auto result = JSC::call(globalObject, createConsoleConstructor, callData, console, args, returnedException); + if (returnedException) { + auto scope = DECLARE_THROW_SCOPE(vm); + throwException(globalObject, scope, returnedException.get()); } + console->putDirect(vm, property, result, 0); + return JSValue::encode(result); +} + +// `console._stdout` is equal to `process.stdout` +JSC_DEFINE_CUSTOM_GETTER(getConsoleStdout, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName property)) +{ + auto& vm = globalObject->vm(); + auto console = JSValue::decode(thisValue).getObject(); + auto global = jsCast<Zig::GlobalObject*>(globalObject); - RELEASE_AND_RETURN(scope, JSValue::encode(result)); + // instead of calling the constructor builtin, go through the process.stdout getter to ensure it's only created once. + auto stdout = global->processObject()->get(globalObject, Identifier::fromString(vm, "stdout"_s)); + if (!stdout) + return JSValue::encode({}); + + console->putDirect(vm, property, stdout, PropertyAttribute::DontEnum | 0); + return JSValue::encode(stdout); +} + +// `console._stderr` is equal to `process.stderr` +JSC_DEFINE_CUSTOM_GETTER(getConsoleStderr, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName property)) +{ + auto& vm = globalObject->vm(); + auto console = JSValue::decode(thisValue).getObject(); + auto global = jsCast<Zig::GlobalObject*>(globalObject); + + // instead of calling the constructor builtin, go through the process.stdout getter to ensure it's only created once. + auto stdout = global->processObject()->get(globalObject, Identifier::fromString(vm, "stderr"_s)); + if (!stdout) + return JSValue::encode({}); + + console->putDirect(vm, property, stdout, PropertyAttribute::DontEnum | 0); + return JSValue::encode(stdout); } JSC_DEFINE_CUSTOM_SETTER(EventSource_setter, @@ -3680,6 +3645,19 @@ extern "C" EncodedJSValue WebCore__alert(JSC::JSGlobalObject*, JSC::CallFrame*); extern "C" EncodedJSValue WebCore__prompt(JSC::JSGlobalObject*, JSC::CallFrame*); extern "C" EncodedJSValue WebCore__confirm(JSC::JSGlobalObject*, JSC::CallFrame*); +JSValue GlobalObject_getPerformanceObject(VM& vm, JSObject* globalObject) +{ + return jsCast<Zig::GlobalObject*>(globalObject)->performanceObject(); +} + +JSValue GlobalObject_getGlobalThis(VM& vm, JSObject* globalObject) +{ + return jsCast<Zig::GlobalObject*>(globalObject)->globalThis(); +} + +// This is like `putDirectBuiltinFunction` but for the global static list. +#define globalBuiltinFunction(vm, globalObject, identifier, function, attributes) JSC::JSGlobalObject::GlobalPropertyInfo(identifier, JSFunction::create(vm, function, globalObject), attributes) + void GlobalObject::addBuiltinGlobals(JSC::VM& vm) { m_builtinInternalFunctions.initialize(*this); @@ -3687,318 +3665,63 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) auto clientData = WebCore::clientData(vm); auto& builtinNames = WebCore::builtinNames(vm); - WTF::Vector<GlobalPropertyInfo> extraStaticGlobals; - extraStaticGlobals.reserveCapacity(51); - - JSC::Identifier queueMicrotaskIdentifier = JSC::Identifier::fromString(vm, "queueMicrotask"_s); - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { JSC::Identifier::fromString(vm, "fetch"_s), - JSC::JSFunction::create(vm, this, 2, - "fetch"_s, Bun__fetch, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { queueMicrotaskIdentifier, - JSC::JSFunction::create(vm, this, 2, - "queueMicrotask"_s, functionQueueMicrotask, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { JSC::Identifier::fromString(vm, "setImmediate"_s), - JSC::JSFunction::create(vm, this, 1, - "setImmediate"_s, functionSetImmediate, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { JSC::Identifier::fromString(vm, "clearImmediate"_s), - JSC::JSFunction::create(vm, this, 1, - "clearImmediate"_s, functionClearTimeout, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { JSC::Identifier::fromString(vm, "structuredClone"_s), - JSC::JSFunction::create(vm, this, 2, - "structuredClone"_s, functionStructuredClone, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - - JSC::Identifier setTimeoutIdentifier = JSC::Identifier::fromString(vm, "setTimeout"_s); - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { setTimeoutIdentifier, - JSC::JSFunction::create(vm, this, 1, - "setTimeout"_s, functionSetTimeout, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); + // ----- Private/Static Properties ----- - JSC::Identifier clearTimeoutIdentifier = JSC::Identifier::fromString(vm, "clearTimeout"_s); - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { clearTimeoutIdentifier, - JSC::JSFunction::create(vm, this, 1, - "clearTimeout"_s, functionClearTimeout, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); + auto $lazy = JSC::JSFunction::create(vm, this, 0, "$lazy"_s, functionLazyLoad, ImplementationVisibility::Public); - JSC::Identifier setIntervalIdentifier = JSC::Identifier::fromString(vm, "setInterval"_s); - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { setIntervalIdentifier, - JSC::JSFunction::create(vm, this, 1, - "setInterval"_s, functionSetInterval, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - - JSC::Identifier clearIntervalIdentifier = JSC::Identifier::fromString(vm, "clearInterval"_s); - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { clearIntervalIdentifier, - JSC::JSFunction::create(vm, this, 1, - "clearInterval"_s, functionClearInterval, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - - JSC::Identifier atobIdentifier = JSC::Identifier::fromString(vm, "atob"_s); - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { atobIdentifier, - JSC::JSFunction::create(vm, this, 1, - "atob"_s, functionATOB, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - - JSC::Identifier btoaIdentifier = JSC::Identifier::fromString(vm, "btoa"_s); - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { btoaIdentifier, - JSC::JSFunction::create(vm, this, 1, - "btoa"_s, functionBTOA, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - JSC::Identifier reportErrorIdentifier = JSC::Identifier::fromString(vm, "reportError"_s); - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { reportErrorIdentifier, - JSC::JSFunction::create(vm, this, 1, - "reportError"_s, functionReportError, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - - { - JSC::Identifier postMessageIdentifier = JSC::Identifier::fromString(vm, "postMessage"_s); - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { postMessageIdentifier, - JSC::JSFunction::create(vm, this, 1, - "postMessage"_s, jsFunctionPostMessage, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - } - - { - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { JSC::Identifier::fromString(vm, "alert"_s), - JSC::JSFunction::create(vm, this, 1, - "alert"_s, WebCore__alert, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - } - - { - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { JSC::Identifier::fromString(vm, "confirm"_s), - JSC::JSFunction::create(vm, this, 1, - "confirm"_s, WebCore__confirm, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - } - - { - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { JSC::Identifier::fromString(vm, "prompt"_s), - JSC::JSFunction::create(vm, this, 1, - "prompt"_s, WebCore__prompt, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - } - - JSValue bunObject = Bun::createBunObject(this); - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { builtinNames.BunPrivateName(), - bunObject, - JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | 0 }); - - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { builtinNames.BunPublicName(), - bunObject, - JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | 0 }); - - extraStaticGlobals.uncheckedAppend( + GlobalPropertyInfo staticGlobals[] = { GlobalPropertyInfo { builtinNames.startDirectStreamPrivateName(), JSC::JSFunction::create(vm, this, 1, String(), functionStartDirectStream, ImplementationVisibility::Public), - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0 }); - - static NeverDestroyed<const String> BunLazyString(MAKE_STATIC_STRING_IMPL("Bun.lazy")); - JSC::Identifier BunLazyIdentifier = JSC::Identifier::fromUid(vm.symbolRegistry().symbolForKey(BunLazyString)); - JSC::JSFunction* lazyLoadFunction = JSC::JSFunction::create(vm, this, 0, - BunLazyString, functionLazyLoad, ImplementationVisibility::Public); - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { BunLazyIdentifier, - lazyLoadFunction, - JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::Function | 0 }); - - extraStaticGlobals.uncheckedAppend( - GlobalPropertyInfo { builtinNames.lazyLoadPrivateName(), - lazyLoadFunction, - JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::Function | 0 }); - - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.makeThisTypeErrorPrivateName(), JSFunction::create(vm, this, 2, String(), makeThisTypeErrorForBuiltins, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly)); - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.makeGetterTypeErrorPrivateName(), JSFunction::create(vm, this, 2, String(), makeGetterTypeErrorForBuiltins, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly)); - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.makeDOMExceptionPrivateName(), JSFunction::create(vm, this, 2, String(), makeDOMExceptionForBuiltins, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly)); - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.whenSignalAbortedPrivateName(), JSFunction::create(vm, this, 2, String(), whenSignalAborted, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly)); - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.cloneArrayBufferPrivateName(), JSFunction::create(vm, this, 3, String(), cloneArrayBuffer, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly)); - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.structuredCloneForStreamPrivateName(), JSFunction::create(vm, this, 1, String(), structuredCloneForStream, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly)); - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.streamClosedPrivateName(), jsNumber(1), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::ConstantInteger)); - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.streamClosingPrivateName(), jsNumber(2), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::ConstantInteger)); - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.streamErroredPrivateName(), jsNumber(3), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::ConstantInteger)); - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.streamReadablePrivateName(), jsNumber(4), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::ConstantInteger)); - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.streamWaitingPrivateName(), jsNumber(5), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::ConstantInteger)); - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.streamWritablePrivateName(), jsNumber(6), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::ConstantInteger)); - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.isAbortSignalPrivateName(), JSFunction::create(vm, this, 1, String(), isAbortSignal, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly)); - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.getInternalWritableStreamPrivateName(), JSFunction::create(vm, this, 1, String(), getInternalWritableStream, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly)); - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.createWritableStreamFromInternalPrivateName(), JSFunction::create(vm, this, 1, String(), createWritableStreamFromInternal, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly)); - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.fulfillModuleSyncPrivateName(), JSFunction::create(vm, this, 1, String(), functionFulfillModuleSync, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::Function)); - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(builtinNames.directPrivateName(), JSFunction::create(vm, this, 1, String(), functionGetDirectStreamDetails, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::Function)); - extraStaticGlobals.uncheckedAppend(GlobalPropertyInfo(vm.propertyNames->builtinNames().ArrayBufferPrivateName(), arrayBufferConstructor(), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly)); - - this->addStaticGlobals(extraStaticGlobals.data(), extraStaticGlobals.size()); - - extraStaticGlobals.releaseBuffer(); + PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | 0 }, + + // TODO: Remove the "Bun.lazy" symbol + // The reason we cant do this easily is our tests rely on this being public to test the internals. + GlobalPropertyInfo { JSC::Identifier::fromUid(vm.symbolRegistry().symbolForKey(MAKE_STATIC_STRING_IMPL("Bun.lazy"))), + $lazy, + PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | 0 }, + + GlobalPropertyInfo { builtinNames.lazyPrivateName(), + $lazy, + PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | 0 }, + + GlobalPropertyInfo(builtinNames.makeThisTypeErrorPrivateName(), JSFunction::create(vm, this, 2, String(), makeThisTypeErrorForBuiltins, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + GlobalPropertyInfo(builtinNames.makeGetterTypeErrorPrivateName(), JSFunction::create(vm, this, 2, String(), makeGetterTypeErrorForBuiltins, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + GlobalPropertyInfo(builtinNames.makeDOMExceptionPrivateName(), JSFunction::create(vm, this, 2, String(), makeDOMExceptionForBuiltins, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + GlobalPropertyInfo(builtinNames.whenSignalAbortedPrivateName(), JSFunction::create(vm, this, 2, String(), whenSignalAborted, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + GlobalPropertyInfo(builtinNames.cloneArrayBufferPrivateName(), JSFunction::create(vm, this, 3, String(), cloneArrayBuffer, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + GlobalPropertyInfo(builtinNames.structuredCloneForStreamPrivateName(), JSFunction::create(vm, this, 1, String(), structuredCloneForStream, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + GlobalPropertyInfo(builtinNames.isAbortSignalPrivateName(), JSFunction::create(vm, this, 1, String(), isAbortSignal, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + GlobalPropertyInfo(builtinNames.getInternalWritableStreamPrivateName(), JSFunction::create(vm, this, 1, String(), getInternalWritableStream, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + GlobalPropertyInfo(builtinNames.createWritableStreamFromInternalPrivateName(), JSFunction::create(vm, this, 1, String(), createWritableStreamFromInternal, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + GlobalPropertyInfo(builtinNames.fulfillModuleSyncPrivateName(), JSFunction::create(vm, this, 1, String(), functionFulfillModuleSync, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + GlobalPropertyInfo(builtinNames.directPrivateName(), JSFunction::create(vm, this, 1, String(), functionGetDirectStreamDetails, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + GlobalPropertyInfo(vm.propertyNames->builtinNames().ArrayBufferPrivateName(), arrayBufferConstructor(), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + GlobalPropertyInfo(builtinNames.LoaderPrivateName(), this->moduleLoader(), PropertyAttribute::DontDelete | 0), + GlobalPropertyInfo(builtinNames.internalModuleRegistryPrivateName(), this->internalModuleRegistry(), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + GlobalPropertyInfo(builtinNames.processBindingConstantsPrivateName(), this->processBindingConstants(), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), + GlobalPropertyInfo(builtinNames.requireMapPrivateName(), this->requireMap(), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | 0), + }; + addStaticGlobals(staticGlobals, std::size(staticGlobals)); + + // TODO: most/all of these private properties can be made as static globals. + // i've noticed doing it as is will work somewhat but getDirect() wont be able to find them putDirectBuiltinFunction(vm, this, builtinNames.createFIFOPrivateName(), streamInternalsCreateFIFOCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); putDirectBuiltinFunction(vm, this, builtinNames.createEmptyReadableStreamPrivateName(), readableStreamCreateEmptyReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); + putDirectBuiltinFunction(vm, this, builtinNames.createUsedReadableStreamPrivateName(), readableStreamCreateUsedReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); putDirectBuiltinFunction(vm, this, builtinNames.consumeReadableStreamPrivateName(), readableStreamConsumeReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); - - putDirect(vm, builtinNames.LoaderPrivateName(), this->moduleLoader(), 0); putDirectBuiltinFunction(vm, this, builtinNames.createNativeReadableStreamPrivateName(), readableStreamCreateNativeReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); - putDirectBuiltinFunction(vm, this, builtinNames.requireESMPrivateName(), importMetaObjectRequireESMCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); putDirectBuiltinFunction(vm, this, builtinNames.loadCJS2ESMPrivateName(), importMetaObjectLoadCJS2ESMCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); putDirectBuiltinFunction(vm, this, builtinNames.internalRequirePrivateName(), importMetaObjectInternalRequireCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); putDirectBuiltinFunction(vm, this, builtinNames.requireNativeModulePrivateName(), moduleRequireNativeModuleCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); - putDirectNativeFunction(vm, this, builtinNames.createUninitializedArrayBufferPrivateName(), 1, functionCreateUninitializedArrayBuffer, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::Function); - putDirectNativeFunction(vm, this, builtinNames.resolveSyncPrivateName(), 1, functionImportMeta__resolveSyncPrivate, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::Function); - putDirectNativeFunction(vm, this, builtinNames.createInternalModuleByIdPrivateName(), 1, InternalModuleRegistry::jsCreateInternalModuleById, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::Function); - putDirect(vm, builtinNames.internalModuleRegistryPrivateName(), this->internalModuleRegistry(), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); - putDirect(vm, builtinNames.processBindingConstantsPrivateName(), this->processBindingConstants(), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "process"_s), JSC::CustomGetterSetter::create(vm, property_lazyProcessGetter, property_lazyProcessSetter), - JSC::PropertyAttribute::CustomAccessor | 0); - putDirect(vm, JSC::Identifier::fromString(vm, "performance"_s), this->performanceObject(), - 0); + putDirectBuiltinFunction(vm, this, builtinNames.overridableRequirePrivateName(), moduleOverridableRequireCodeGenerator(vm), 0); - putDirect(vm, JSC::Identifier::fromString(vm, "self"_s), this->globalThis(), JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete | 0); - putDirect(vm, JSC::Identifier::fromString(vm, "global"_s), this->globalThis(), JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete | 0); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "URL"_s), JSC::CustomGetterSetter::create(vm, JSDOMURL_getter, nullptr), - JSC::PropertyAttribute::DontDelete | 0); - - putDirectCustomAccessor(vm, builtinNames.lazyStreamPrototypeMapPrivateName(), JSC::CustomGetterSetter::create(vm, functionLazyLoadStreamPrototypeMap_getter, nullptr), - JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly | 0); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "navigator"_s), JSC::CustomGetterSetter::create(vm, functionLazyNavigatorGetter, nullptr), - JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly | 0); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "ResolveError"_s), JSC::CustomGetterSetter::create(vm, functionResolveMessageGetter, nullptr), - JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly | 0); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "ResolveMessage"_s), JSC::CustomGetterSetter::create(vm, functionResolveMessageGetter, nullptr), - JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly | 0); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "BuildError"_s), JSC::CustomGetterSetter::create(vm, functionBuildMessageGetter, nullptr), - JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly | 0); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "BuildMessage"_s), JSC::CustomGetterSetter::create(vm, functionBuildMessageGetter, nullptr), - JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly | 0); - - putDirect(vm, builtinNames.requireMapPrivateName(), this->requireMap(), - JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly | 0); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "Request"_s), JSC::CustomGetterSetter::create(vm, JSRequest_getter, JSRequest_setter), - JSC::PropertyAttribute::DontDelete | 0); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "Response"_s), JSC::CustomGetterSetter::create(vm, JSResponse_getter, JSResponse_setter), - JSC::PropertyAttribute::DontDelete | 0); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "TextDecoder"_s), JSC::CustomGetterSetter::create(vm, JSTextDecoder_getter, JSTextDecoder_setter), - JSC::PropertyAttribute::DontDelete | 0); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "Blob"_s), JSC::CustomGetterSetter::create(vm, JSBlob_getter, JSBlob_setter), - JSC::PropertyAttribute::DontDelete | 0); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "HTMLRewriter"_s), JSC::CustomGetterSetter::create(vm, JSHTMLRewriter_getter, JSHTMLRewriter_setter), - JSC::PropertyAttribute::DontDelete | 0); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "Crypto"_s), JSC::CustomGetterSetter::create(vm, JSCrypto_getter, JSCrypto_setter), - JSC::PropertyAttribute::DontDelete | 0); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "File"_s), JSC::CustomGetterSetter::create(vm, JSDOMFileConstructor_getter, JSDOMFileConstructor_setter), - JSC::PropertyAttribute::DontDelete | 0); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "DOMException"_s), JSC::CustomGetterSetter::create(vm, JSDOMException_getter, nullptr), - JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "Event"_s), JSC::CustomGetterSetter::create(vm, JSEvent_getter, nullptr), - JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "EventTarget"_s), JSC::CustomGetterSetter::create(vm, JSEventTarget_getter, nullptr), - JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "AbortController"_s), JSC::CustomGetterSetter::create(vm, JSDOMAbortController_getter, nullptr), - JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "AbortSignal"_s), JSC::CustomGetterSetter::create(vm, JSDOMAbortSignal_getter, nullptr), - JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "$_BunCommonJSModule_$"_s), JSC::CustomGetterSetter::create(vm, BunCommonJSModule_getter, nullptr), - JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "EventSource"_s), JSC::CustomGetterSetter::create(vm, EventSource_getter, EventSource_setter), 0); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "onmessage"_s), JSC::CustomGetterSetter::create(vm, globalGetterOnMessage, globalSetterOnMessage), 0); - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "onerror"_s), JSC::CustomGetterSetter::create(vm, globalGetterOnError, globalSetterOnError), 0); - - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "crypto"_s), JSC::CustomGetterSetter::create(vm, property_lazyCryptoGetter, nullptr), - JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | 0); - - auto bufferAccessor = JSC::CustomGetterSetter::create(vm, JSBuffer_getter, JSBuffer_setter); - auto realBufferAccessor = JSC::CustomGetterSetter::create(vm, JSBuffer_privateGetter, nullptr); - - // - putDirectCustomAccessor(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames().BufferPublicName(), bufferAccessor, - JSC::PropertyAttribute::DontDelete | 0); - putDirectCustomAccessor(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames().BufferPrivateName(), realBufferAccessor, - JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - - PUT_WEBCORE_GENERATED_CONSTRUCTOR("BroadcastChannel"_s, JSBroadcastChannel); - PUT_WEBCORE_GENERATED_CONSTRUCTOR("CloseEvent"_s, JSCloseEvent); - PUT_WEBCORE_GENERATED_CONSTRUCTOR("CustomEvent"_s, JSCustomEvent); - PUT_WEBCORE_GENERATED_CONSTRUCTOR("DOMException"_s, JSDOMException); - PUT_WEBCORE_GENERATED_CONSTRUCTOR("ErrorEvent"_s, JSErrorEvent); - PUT_WEBCORE_GENERATED_CONSTRUCTOR("Event"_s, JSEvent); - PUT_WEBCORE_GENERATED_CONSTRUCTOR("EventTarget"_s, JSEventTarget); - PUT_WEBCORE_GENERATED_CONSTRUCTOR("FormData"_s, JSDOMFormData); - PUT_WEBCORE_GENERATED_CONSTRUCTOR("Headers"_s, JSFetchHeaders); - PUT_WEBCORE_GENERATED_CONSTRUCTOR("MessageChannel"_s, JSMessageChannel); - PUT_WEBCORE_GENERATED_CONSTRUCTOR("MessageEvent"_s, JSMessageEvent); - PUT_WEBCORE_GENERATED_CONSTRUCTOR("MessagePort"_s, JSMessagePort); - PUT_WEBCORE_GENERATED_CONSTRUCTOR("TextEncoder"_s, JSTextEncoder); - PUT_WEBCORE_GENERATED_CONSTRUCTOR("URLSearchParams"_s, JSURLSearchParams); - PUT_WEBCORE_GENERATED_CONSTRUCTOR("WebSocket"_s, JSWebSocket); - PUT_WEBCORE_GENERATED_CONSTRUCTOR("Worker"_s, JSWorker); - - putDirectCustomAccessor(vm, builtinNames.TransformStreamPublicName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_TransformStreamConstructor, nullptr), attributesForStructure(static_cast<unsigned>(JSC::PropertyAttribute::DontEnum))); - putDirectCustomAccessor(vm, builtinNames.TransformStreamPrivateName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_TransformStreamConstructor, nullptr), attributesForStructure(static_cast<unsigned>(JSC::PropertyAttribute::DontEnum))); - putDirectCustomAccessor(vm, builtinNames.TransformStreamDefaultControllerPublicName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_TransformStreamDefaultControllerConstructor, nullptr), attributesForStructure(static_cast<unsigned>(JSC::PropertyAttribute::DontEnum))); - putDirectCustomAccessor(vm, builtinNames.TransformStreamDefaultControllerPrivateName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_TransformStreamDefaultControllerConstructor, nullptr), attributesForStructure(static_cast<unsigned>(JSC::PropertyAttribute::DontEnum))); - putDirectCustomAccessor(vm, builtinNames.ReadableByteStreamControllerPrivateName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_ReadableByteStreamControllerConstructor, nullptr), attributesForStructure(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly)); - putDirectCustomAccessor(vm, builtinNames.ReadableStreamPrivateName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_ReadableStreamConstructor, nullptr), attributesForStructure(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly)); - putDirectCustomAccessor(vm, builtinNames.ReadableStreamBYOBReaderPrivateName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_ReadableStreamBYOBReaderConstructor, nullptr), attributesForStructure(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly)); - putDirectCustomAccessor(vm, builtinNames.ReadableStreamBYOBRequestPrivateName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_ReadableStreamBYOBRequestConstructor, nullptr), attributesForStructure(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly)); - putDirectCustomAccessor(vm, builtinNames.ReadableStreamDefaultControllerPrivateName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_ReadableStreamDefaultControllerConstructor, nullptr), attributesForStructure(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly)); - putDirectCustomAccessor(vm, builtinNames.ReadableStreamDefaultReaderPrivateName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_ReadableStreamDefaultReaderConstructor, nullptr), attributesForStructure(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly)); - putDirectCustomAccessor(vm, builtinNames.WritableStreamPrivateName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_WritableStreamConstructor, nullptr), attributesForStructure(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly)); - putDirectCustomAccessor(vm, builtinNames.WritableStreamDefaultControllerPrivateName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_WritableStreamDefaultControllerConstructor, nullptr), attributesForStructure(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly)); - putDirectCustomAccessor(vm, builtinNames.WritableStreamDefaultWriterPrivateName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_WritableStreamDefaultWriterConstructor, nullptr), attributesForStructure(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly)); - putDirectCustomAccessor(vm, builtinNames.AbortSignalPrivateName(), CustomGetterSetter::create(vm, JSDOMAbortSignal_getter, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - putDirectCustomAccessor(vm, builtinNames.ReadableByteStreamControllerPublicName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_ReadableByteStreamControllerConstructor, nullptr), JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - putDirectCustomAccessor(vm, builtinNames.ReadableStreamPublicName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_ReadableStreamConstructor, nullptr), JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - putDirectCustomAccessor(vm, builtinNames.ReadableStreamBYOBReaderPublicName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_ReadableStreamBYOBReaderConstructor, nullptr), JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - putDirectCustomAccessor(vm, builtinNames.ReadableStreamBYOBRequestPublicName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_ReadableStreamBYOBRequestConstructor, nullptr), JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - putDirectCustomAccessor(vm, builtinNames.ReadableStreamDefaultControllerPublicName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_ReadableStreamDefaultControllerConstructor, nullptr), JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - putDirectCustomAccessor(vm, builtinNames.ReadableStreamDefaultReaderPublicName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_ReadableStreamDefaultReaderConstructor, nullptr), JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - putDirectCustomAccessor(vm, builtinNames.WritableStreamPublicName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_WritableStreamConstructor, nullptr), JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - putDirectCustomAccessor(vm, builtinNames.WritableStreamDefaultControllerPublicName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_WritableStreamDefaultControllerConstructor, nullptr), JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - putDirectCustomAccessor(vm, builtinNames.WritableStreamDefaultWriterPublicName(), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_WritableStreamDefaultWriterConstructor, nullptr), JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); + putDirectNativeFunction(vm, this, builtinNames.createUninitializedArrayBufferPrivateName(), 1, functionCreateUninitializedArrayBuffer, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); + putDirectNativeFunction(vm, this, builtinNames.resolveSyncPrivateName(), 1, functionImportMeta__resolveSyncPrivate, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); + putDirectNativeFunction(vm, this, builtinNames.createInternalModuleByIdPrivateName(), 1, InternalModuleRegistry::jsCreateInternalModuleById, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); putDirectNativeFunction(vm, this, builtinNames.createCommonJSModulePrivateName(), @@ -4006,42 +3729,60 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) Bun::jsFunctionCreateCommonJSModule, ImplementationVisibility::Public, NoIntrinsic, - JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + PropertyAttribute::ReadOnly | PropertyAttribute::DontDelete | 0); putDirectNativeFunction(vm, this, builtinNames.evaluateCommonJSModulePrivateName(), 2, Bun::jsFunctionLoadModule, ImplementationVisibility::Public, NoIntrinsic, - JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "ByteLengthQueuingStrategy"_s), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_ByteLengthQueuingStrategyConstructor, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "CountQueuingStrategy"_s), CustomGetterSetter::create(vm, jsServiceWorkerGlobalScope_CountQueuingStrategyConstructor, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "SubtleCrypto"_s), JSC::CustomGetterSetter::create(vm, getterSubtleCryptoConstructor, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); - putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "CryptoKey"_s), JSC::CustomGetterSetter::create(vm, getterCryptoKeyConstructor, nullptr), JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); + PropertyAttribute::ReadOnly | PropertyAttribute::DontDelete | 0); + + putDirectCustomAccessor(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames().BufferPrivateName(), JSC::CustomGetterSetter::create(vm, JSBuffer_getter, nullptr), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessorOrValue); + putDirectCustomAccessor(vm, builtinNames.lazyStreamPrototypeMapPrivateName(), JSC::CustomGetterSetter::create(vm, functionLazyLoadStreamPrototypeMap_getter, nullptr), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessorOrValue); + putDirectCustomAccessor(vm, builtinNames.TransformStreamPrivateName(), CustomGetterSetter::create(vm, TransformStream_getter, nullptr), attributesForStructure(static_cast<unsigned>(PropertyAttribute::DontEnum)) | PropertyAttribute::CustomAccessorOrValue); + putDirectCustomAccessor(vm, builtinNames.TransformStreamDefaultControllerPrivateName(), CustomGetterSetter::create(vm, TransformStreamDefaultController_getter, nullptr), attributesForStructure(static_cast<unsigned>(PropertyAttribute::DontEnum)) | PropertyAttribute::CustomAccessorOrValue); + putDirectCustomAccessor(vm, builtinNames.ReadableByteStreamControllerPrivateName(), CustomGetterSetter::create(vm, ReadableByteStreamController_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomAccessorOrValue); + putDirectCustomAccessor(vm, builtinNames.ReadableStreamPrivateName(), CustomGetterSetter::create(vm, ReadableStream_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomAccessorOrValue); + putDirectCustomAccessor(vm, builtinNames.ReadableStreamBYOBReaderPrivateName(), CustomGetterSetter::create(vm, ReadableStreamBYOBReader_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomAccessorOrValue); + putDirectCustomAccessor(vm, builtinNames.ReadableStreamBYOBRequestPrivateName(), CustomGetterSetter::create(vm, ReadableStreamBYOBRequest_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomAccessorOrValue); + putDirectCustomAccessor(vm, builtinNames.ReadableStreamDefaultControllerPrivateName(), CustomGetterSetter::create(vm, ReadableStreamDefaultController_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomAccessorOrValue); + putDirectCustomAccessor(vm, builtinNames.ReadableStreamDefaultReaderPrivateName(), CustomGetterSetter::create(vm, ReadableStreamDefaultReader_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomAccessorOrValue); + putDirectCustomAccessor(vm, builtinNames.WritableStreamPrivateName(), CustomGetterSetter::create(vm, WritableStream_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomAccessorOrValue); + putDirectCustomAccessor(vm, builtinNames.WritableStreamDefaultControllerPrivateName(), CustomGetterSetter::create(vm, WritableStreamDefaultController_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomAccessorOrValue); + putDirectCustomAccessor(vm, builtinNames.WritableStreamDefaultWriterPrivateName(), CustomGetterSetter::create(vm, WritableStreamDefaultWriter_getter, nullptr), attributesForStructure(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly) | PropertyAttribute::CustomAccessorOrValue); + putDirectCustomAccessor(vm, builtinNames.AbortSignalPrivateName(), CustomGetterSetter::create(vm, AbortSignal_getter, nullptr), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessorOrValue); + + // ----- Public Properties ----- + + // a direct accessor (uses js functions for get and set) cannot be on the lookup table. i think. + putDirectAccessor( + this, + builtinNames.selfPublicName(), + JSC::GetterSetter::create( + vm, + this, + JSFunction::create(vm, this, 0, "get"_s, functionGetSelf, ImplementationVisibility::Public), + JSFunction::create(vm, this, 0, "set"_s, functionSetSelf, ImplementationVisibility::Public)), + PropertyAttribute::Accessor | 0); - putDirectNativeFunction(vm, this, - Identifier::fromString(vm, "addEventListener"_s), - 2, - jsFunctionAddEventListener, - ImplementationVisibility::Public, - NoIntrinsic, - JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + // TODO: this should be usable on the lookup table. it crashed las time i tried it + putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "onmessage"_s), JSC::CustomGetterSetter::create(vm, globalOnMessage, setGlobalOnMessage), 0); + putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "onerror"_s), JSC::CustomGetterSetter::create(vm, globalOnError, setGlobalOnError), 0); - putDirectNativeFunction(vm, this, - Identifier::fromString(vm, "dispatchEvent"_s), - 1, - jsFunctionDispatchEvent, - ImplementationVisibility::Public, - NoIntrinsic, - JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + // ----- Extensions to Built-in objects ----- - putDirectNativeFunction(vm, this, - Identifier::fromString(vm, "removeEventListener"_s), - 2, - jsFunctionRemoveEventListener, - ImplementationVisibility::Public, - NoIntrinsic, - JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + JSC::JSObject* errorConstructor = this->errorConstructor(); + errorConstructor->putDirectNativeFunction(vm, this, JSC::Identifier::fromString(vm, "captureStackTrace"_s), 2, errorConstructorFuncCaptureStackTrace, ImplementationVisibility::Public, JSC::NoIntrinsic, PropertyAttribute::DontEnum | 0); + errorConstructor->putDirectNativeFunction(vm, this, JSC::Identifier::fromString(vm, "appendStackTrace"_s), 2, errorConstructorFuncAppendStackTrace, ImplementationVisibility::Private, JSC::NoIntrinsic, PropertyAttribute::DontEnum | 0); + errorConstructor->putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "prepareStackTrace"_s), JSC::CustomGetterSetter::create(vm, errorConstructorPrepareStackTraceGetter, errorConstructorPrepareStackTraceSetter), PropertyAttribute::DontEnum | PropertyAttribute::CustomValue); + + JSC::JSObject* consoleObject = this->get(this, JSC::Identifier::fromString(vm, "console"_s)).getObject(); + consoleObject->putDirectBuiltinFunction(vm, this, vm.propertyNames->asyncIteratorSymbol, consoleObjectAsyncIteratorCodeGenerator(vm), PropertyAttribute::Builtin | 0); + consoleObject->putDirectBuiltinFunction(vm, this, clientData->builtinNames().writePublicName(), consoleObjectWriteCodeGenerator(vm), PropertyAttribute::Builtin | 0); + consoleObject->putDirectCustomAccessor(vm, Identifier::fromString(vm, "Console"_s), CustomGetterSetter::create(vm, getConsoleConstructor, nullptr), PropertyAttribute::CustomValue | 0); + consoleObject->putDirectCustomAccessor(vm, Identifier::fromString(vm, "_stdout"_s), CustomGetterSetter::create(vm, getConsoleStdout, nullptr), PropertyAttribute::DontEnum | PropertyAttribute::CustomValue | 0); + consoleObject->putDirectCustomAccessor(vm, Identifier::fromString(vm, "_stderr"_s), CustomGetterSetter::create(vm, getConsoleStderr, nullptr), PropertyAttribute::DontEnum | PropertyAttribute::CustomValue | 0); } extern "C" bool JSC__JSGlobalObject__startRemoteInspector(JSC__JSGlobalObject* globalObject, unsigned char* host, uint16_t arg1) @@ -4104,29 +3845,8 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) visitor.append(thisObject->m_readableStreamToFormData); visitor.append(thisObject->m_nodeModuleOverriddenResolveFilename); - visitor.append(thisObject->m_JSBlobSetterValue); - visitor.append(thisObject->m_JSBroadcastChannelSetterValue); - visitor.append(thisObject->m_JSBufferSetterValue); - visitor.append(thisObject->m_JSCloseEventSetterValue); - visitor.append(thisObject->m_JSCustomEventSetterValue); - visitor.append(thisObject->m_JSDOMExceptionSetterValue); - visitor.append(thisObject->m_JSDOMFormDataSetterValue); - visitor.append(thisObject->m_JSErrorEventSetterValue); - visitor.append(thisObject->m_JSEventSetterValue); - visitor.append(thisObject->m_JSEventTargetSetterValue); - visitor.append(thisObject->m_JSFetchHeadersSetterValue); - visitor.append(thisObject->m_JSMessageChannelSetterValue); - visitor.append(thisObject->m_JSMessageEventSetterValue); - visitor.append(thisObject->m_JSMessagePortSetterValue); - visitor.append(thisObject->m_JSRequestSetterValue); - visitor.append(thisObject->m_JSResponseSetterValue); - visitor.append(thisObject->m_JSTextDecoderSetterValue); - visitor.append(thisObject->m_JSTextEncoderSetterValue); - visitor.append(thisObject->m_JSURLSearchParamsSetterValue); - visitor.append(thisObject->m_JSWebSocketSetterValue); - visitor.append(thisObject->m_JSWorkerSetterValue); - visitor.append(thisObject->m_nextTickQueue); + visitor.append(thisObject->m_errorConstructorPrepareStackTraceValue); thisObject->m_JSArrayBufferSinkClassStructure.visit(visitor); thisObject->m_JSBufferListClassStructure.visit(visitor); @@ -4157,17 +3877,19 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) thisObject->m_performanceObject.visit(visitor); thisObject->m_processEnvObject.visit(visitor); thisObject->m_processObject.visit(visitor); + thisObject->m_bunObject.visit(visitor); thisObject->m_subtleCryptoObject.visit(visitor); thisObject->m_JSHTTPResponseController.visit(visitor); thisObject->m_callSiteStructure.visit(visitor); thisObject->m_emitReadableNextTickFunction.visit(visitor); thisObject->m_JSBufferSubclassStructure.visit(visitor); + thisObject->m_JSCryptoKey.visit(visitor); + thisObject->m_cryptoObject.visit(visitor); thisObject->m_JSDOMFileConstructor.visit(visitor); thisObject->m_requireFunctionUnbound.visit(visitor); thisObject->m_requireResolveFunctionUnbound.visit(visitor); - thisObject->m_processBindingConstants.visit(visitor); thisObject->m_importMetaObjectStructure.visit(visitor); thisObject->m_asyncBoundFunctionStructure.visit(visitor); thisObject->m_internalModuleRegistry.visit(visitor); @@ -4180,6 +3902,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) thisObject->m_commonJSModuleObjectStructure.visit(visitor); thisObject->m_memoryFootprintStructure.visit(visitor); thisObject->m_commonJSFunctionArgumentsStructure.visit(visitor); + thisObject->m_JSSocketAddressStructure.visit(visitor); thisObject->m_cachedGlobalObjectStructure.visit(visitor); thisObject->m_cachedGlobalProxyStructure.visit(visitor); @@ -4291,7 +4014,7 @@ template void GlobalObject::visitOutputConstraints(JSCell*, SlotVisitor&); // void GlobalObject::destroy(JSCell* cell) // { -// static_cast<Zig::GlobalObject*>(cell)->Zig::GlobalObject::~Zig::GlobalObject(); +// jsCast<Zig::GlobalObject*>(cell)->Zig::GlobalObject::~Zig::GlobalObject(); // } // template<typename Visitor> @@ -4351,16 +4074,45 @@ extern "C" void JSC__JSGlobalObject__queueMicrotaskCallback(Zig::GlobalObject* g globalObject->queueMicrotask(function, JSValue(bitwise_cast<double>(reinterpret_cast<uintptr_t>(ptr))), JSValue(bitwise_cast<double>(reinterpret_cast<uintptr_t>(callback))), jsUndefined(), jsUndefined()); } -JSC::Identifier GlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject, +JSC::Identifier GlobalObject::moduleLoaderResolve(JSGlobalObject* jsGlobalObject, JSModuleLoader* loader, JSValue key, JSValue referrer, JSValue origin) { + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(jsGlobalObject); + ErrorableString res; res.success = false; - BunString keyZ = Bun::toString(globalObject, key); - BunString referrerZ = referrer && !referrer.isUndefinedOrNull() && referrer.isString() ? Bun::toString(globalObject, referrer) : BunStringEmpty; + + if (key.isString()) { + if (auto* virtualModules = globalObject->onLoadPlugins.virtualModules) { + auto keyString = key.toWTFString(globalObject); + if (virtualModules->contains(keyString)) { + return JSC::Identifier::fromString(globalObject->vm(), keyString); + } + } + } + + BunString keyZ; + if (key.isString()) { + auto moduleName = jsCast<JSString*>(key)->value(globalObject); + if (moduleName.startsWith("file://"_s)) { + auto url = WTF::URL(moduleName); + if (url.isValid() && !url.isEmpty()) { + keyZ = Bun::toStringRef(url.fileSystemPath()); + } else { + keyZ = Bun::toStringRef(moduleName); + } + } else { + keyZ = Bun::toStringRef(moduleName); + } + } else { + keyZ = Bun::toStringRef(globalObject, key); + } + BunString referrerZ = referrer && !referrer.isUndefinedOrNull() && referrer.isString() ? Bun::toStringRef(globalObject, referrer) : BunStringEmpty; ZigString queryString = { 0, 0 }; Zig__GlobalObject__resolve(&res, globalObject, &keyZ, &referrerZ, &queryString); + keyZ.deref(); + referrerZ.deref(); if (res.success) { if (queryString.len > 0) { @@ -4375,25 +4127,60 @@ JSC::Identifier GlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject, } } -JSC::JSInternalPromise* GlobalObject::moduleLoaderImportModule(JSGlobalObject* globalObject, +JSC::JSInternalPromise* GlobalObject::moduleLoaderImportModule(JSGlobalObject* jsGlobalObject, JSModuleLoader*, JSString* moduleNameValue, JSValue parameters, const SourceOrigin& sourceOrigin) { + auto* globalObject = reinterpret_cast<Zig::GlobalObject*>(jsGlobalObject); JSC::VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); auto* promise = JSC::JSInternalPromise::create(vm, globalObject->internalPromiseStructure()); RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope)); + if (auto* virtualModules = globalObject->onLoadPlugins.virtualModules) { + auto keyString = moduleNameValue->value(globalObject); + if (virtualModules->contains(keyString)) { + auto resolvedIdentifier = JSC::Identifier::fromString(vm, keyString); + + auto result = JSC::importModule(globalObject, resolvedIdentifier, + JSC::jsUndefined(), parameters, JSC::jsUndefined()); + + RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope)); + return result; + } + } + auto sourceURL = sourceOrigin.url(); ErrorableString resolved; - auto moduleNameZ = Bun::toString(globalObject, moduleNameValue); - auto sourceOriginZ = sourceURL.isEmpty() ? BunStringCwd : Bun::toString(sourceURL.fileSystemPath()); + BunString moduleNameZ; + + auto moduleName = moduleNameValue->value(globalObject); +#if BUN_DEBUG + auto startRefCount = moduleName.impl()->refCount(); +#endif + if (moduleName.startsWith("file://"_s)) { + auto url = WTF::URL(moduleName); + if (url.isValid() && !url.isEmpty()) { + moduleNameZ = Bun::toStringRef(url.fileSystemPath()); + } else { + moduleNameZ = Bun::toStringRef(moduleName); + } + } else { + moduleNameZ = Bun::toStringRef(moduleName); + } + auto sourceOriginZ = sourceURL.isEmpty() ? BunStringCwd : Bun::toStringRef(sourceURL.fileSystemPath()); ZigString queryString = { 0, 0 }; resolved.success = false; Zig__GlobalObject__resolve(&resolved, globalObject, &moduleNameZ, &sourceOriginZ, &queryString); + moduleNameZ.deref(); + sourceOriginZ.deref(); +#if BUN_DEBUG + // TODO: ASSERT doesnt work right now + RELEASE_ASSERT(startRefCount == moduleName.impl()->refCount()); +#endif if (!resolved.success) { throwException(scope, resolved.result.err, globalObject); return promise->rejectWithCaughtException(globalObject, scope); @@ -4549,5 +4336,9 @@ GlobalObject::PromiseFunctions GlobalObject::promiseHandlerID(EncodedJSValue (*h } #include "ZigGeneratedClasses+lazyStructureImpl.h" +#include "ZigGlobalObject.lut.h" + +const JSC::ClassInfo GlobalObject::s_info = { "GlobalObject"_s, &Base::s_info, &bunGlobalObjectTable, nullptr, + CREATE_METHOD_TABLE(GlobalObject) }; } // namespace Zig diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index 29c1cd09c..19630d4b7 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -13,21 +13,22 @@ namespace JSC { class Structure; class Identifier; class LazyClassStructure; - -} // namespace JSC - -namespace JSC { - enum class JSPromiseRejectionOperation : unsigned; - -} +} // namespace JSC namespace WebCore { class ScriptExecutionContext; class DOMGuardedObject; class EventLoopTask; class DOMWrapperWorld; -} +class GlobalScope; +class SubtleCrypto; +class EventTarget; +} // namespace WebCore + +namespace Bun { +class InternalModuleRegistry; +} // namespace Bun #include "root.h" @@ -43,37 +44,9 @@ class DOMWrapperWorld; #include "BunPlugin.h" #include "JSMockFunction.h" #include "InternalModuleRegistry.h" -#include "ProcessBindingConstants.h" - -namespace WebCore { -class GlobalScope; -class SubtleCrypto; -class EventTarget; -} extern "C" void Bun__reportError(JSC__JSGlobalObject*, JSC__JSValue); extern "C" void Bun__reportUnhandledError(JSC__JSGlobalObject*, JSC::EncodedJSValue); -// defined in ModuleLoader.cpp -extern "C" JSC::EncodedJSValue jsFunctionOnLoadObjectResultResolve(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame); -extern "C" JSC::EncodedJSValue jsFunctionOnLoadObjectResultReject(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame); - -// #include "EventTarget.h" - -// namespace WebCore { -// class GlobalEventTarget : public EventTargetWithInlineData, public ContextDestructionObserver { -// WTF_MAKE_ISO_ALLOCATED(GlobalEventTarget); - -// public: -// static Ref<GlobalEventTarget> create(ScriptExecutionContext&); - -// EventTargetInterface eventTargetInterface() const final { return DOMWindowEventTargetInterfaceType; } -// ScriptExecutionContext* scriptExecutionContext() const final { return ContextDestructionObserver::scriptExecutionContext(); } -// void refEventTarget() final {} -// void derefEventTarget() final {} -// void eventListenersDidChange() final; -// }; - -// } namespace Zig { @@ -179,27 +152,17 @@ public: void clearDOMGuardedObjects(); - static void createCallSitesFromFrames(JSC::JSGlobalObject* lexicalGlobalObject, JSCStackTrace& stackTrace, JSC::JSArray* callSites); - JSC::JSValue formatStackTrace(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSObject* errorObject, JSC::JSArray* callSites); + static void createCallSitesFromFrames(Zig::GlobalObject* globalObject, JSC::JSGlobalObject* lexicalGlobalObject, JSCStackTrace& stackTrace, JSC::JSArray* callSites); + void formatStackTrace(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSObject* errorObject, JSC::JSArray* callSites, JSValue prepareStack = JSC::jsUndefined()); static void reportUncaughtExceptionAtEventLoop(JSGlobalObject*, JSC::Exception*); static JSGlobalObject* deriveShadowRealmGlobalObject(JSGlobalObject* globalObject); - static JSC::JSInternalPromise* moduleLoaderImportModule(JSGlobalObject*, JSC::JSModuleLoader*, - JSC::JSString* moduleNameValue, - JSC::JSValue parameters, - const JSC::SourceOrigin&); - static JSC::Identifier moduleLoaderResolve(JSGlobalObject*, JSC::JSModuleLoader*, - JSC::JSValue keyValue, JSC::JSValue referrerValue, - JSC::JSValue); - static JSC::JSInternalPromise* moduleLoaderFetch(JSGlobalObject*, JSC::JSModuleLoader*, - JSC::JSValue, JSC::JSValue, JSC::JSValue); - static JSC::JSObject* moduleLoaderCreateImportMetaProperties(JSGlobalObject*, - JSC::JSModuleLoader*, JSC::JSValue, - JSC::JSModuleRecord*, JSC::JSValue); - static JSC::JSValue moduleLoaderEvaluate(JSGlobalObject*, JSC::JSModuleLoader*, JSC::JSValue, - JSC::JSValue, JSC::JSValue, JSC::JSValue, JSC::JSValue); - static void promiseRejectionTracker(JSGlobalObject*, JSC::JSPromise*, - JSC::JSPromiseRejectionOperation); + static JSC::JSInternalPromise* moduleLoaderImportModule(JSGlobalObject*, JSC::JSModuleLoader*, JSC::JSString* moduleNameValue, JSC::JSValue parameters, const JSC::SourceOrigin&); + static JSC::Identifier moduleLoaderResolve(JSGlobalObject*, JSC::JSModuleLoader*, JSC::JSValue keyValue, JSC::JSValue referrerValue, JSC::JSValue); + static JSC::JSInternalPromise* moduleLoaderFetch(JSGlobalObject*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSValue, JSC::JSValue); + static JSC::JSObject* moduleLoaderCreateImportMetaProperties(JSGlobalObject*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSModuleRecord*, JSC::JSValue); + static JSC::JSValue moduleLoaderEvaluate(JSGlobalObject*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSValue, JSC::JSValue, JSC::JSValue, JSC::JSValue); + static void promiseRejectionTracker(JSGlobalObject*, JSC::JSPromise*, JSC::JSPromiseRejectionOperation); void setConsole(void* console); WebCore::JSBuiltinInternalFunctions& builtinInternalFunctions() { return m_builtinInternalFunctions; } JSC::Structure* FFIFunctionStructure() { return m_JSFFIFunctionStructure.getInitializedOnMainThread(this); } @@ -215,6 +178,8 @@ public: JSC::JSValue JSBufferPrototype() { return m_JSBufferClassStructure.prototypeInitializedOnMainThread(this); } JSC::Structure* JSBufferSubclassStructure() { return m_JSBufferSubclassStructure.getInitializedOnMainThread(this); } + JSC::Structure* JSCryptoKeyStructure() { return m_JSCryptoKey.getInitializedOnMainThread(this); } + JSC::Structure* ArrayBufferSinkStructure() { return m_JSArrayBufferSinkClassStructure.getInitializedOnMainThread(this); } JSC::JSObject* ArrayBufferSink() { return m_JSArrayBufferSinkClassStructure.constructorInitializedOnMainThread(this); } JSC::JSValue ArrayBufferSinkPrototype() { return m_JSArrayBufferSinkClassStructure.prototypeInitializedOnMainThread(this); } @@ -266,7 +231,8 @@ public: JSObject* requireFunctionUnbound() { return m_requireFunctionUnbound.getInitializedOnMainThread(this); } JSObject* requireResolveFunctionUnbound() { return m_requireResolveFunctionUnbound.getInitializedOnMainThread(this); } Bun::InternalModuleRegistry* internalModuleRegistry() { return m_internalModuleRegistry.getInitializedOnMainThread(this); } - Bun::ProcessBindingConstants* processBindingConstants() { return m_processBindingConstants.getInitializedOnMainThread(this); } + + JSObject* processBindingConstants() { return m_processBindingConstants.getInitializedOnMainThread(this); } JSObject* lazyRequireCacheObject() { return m_lazyRequireCacheObject.getInitializedOnMainThread(this); } @@ -281,36 +247,28 @@ public: Structure* AsyncContextFrameStructure() { return m_asyncBoundFunctionStructure.getInitializedOnMainThread(this); } Structure* commonJSFunctionArgumentsStructure() { return m_commonJSFunctionArgumentsStructure.getInitializedOnMainThread(this); } + Structure* JSSocketAddressStructure() { return m_JSSocketAddressStructure.getInitializedOnMainThread(this); } JSWeakMap* vmModuleContextMap() { return m_vmModuleContextMap.getInitializedOnMainThread(this); } bool hasProcessObject() const { return m_processObject.isInitialized(); } - JSC::JSObject* processObject() - { - return m_processObject.getInitializedOnMainThread(this); - } - - JSC::JSObject* processEnvObject() - { - return m_processEnvObject.getInitializedOnMainThread(this); - } + JSC::JSObject* processObject() { return m_processObject.getInitializedOnMainThread(this); } + JSC::JSObject* processEnvObject() { return m_processEnvObject.getInitializedOnMainThread(this); } + JSC::JSObject* bunObject() { return m_bunObject.getInitializedOnMainThread(this); } void drainMicrotasks(); void handleRejectedPromises(); - void initGeneratedLazyClasses(); + ALWAYS_INLINE void initGeneratedLazyClasses(); template<typename Visitor> void visitGeneratedLazyClasses(GlobalObject*, Visitor&); - void* bunVM() { return m_bunVM; } + ALWAYS_INLINE void* bunVM() { return m_bunVM; } bool isThreadLocalDefaultGlobalObject = false; - JSObject* subtleCrypto() - { - return m_subtleCryptoObject.getInitializedOnMainThread(this); - } + JSObject* subtleCrypto() { return m_subtleCryptoObject.getInitializedOnMainThread(this); } EncodedJSValue assignToStream(JSValue stream, JSValue controller); @@ -377,6 +335,7 @@ public: * For example, if you don't add the queueMicrotask functions to visitChildrenImpl(), * those callbacks will eventually never be called anymore. But it'll work the first time! */ + // TODO: these should use LazyProperty mutable WriteBarrier<JSFunction> m_assignToStream; mutable WriteBarrier<JSFunction> m_readableStreamToArrayBuffer; mutable WriteBarrier<JSFunction> m_readableStreamToArrayBufferResolve; @@ -390,28 +349,14 @@ public: mutable WriteBarrier<JSFunction> m_nodeModuleOverriddenResolveFilename; mutable WriteBarrier<Unknown> m_nextTickQueue; + // Value of $_BunCommonJSModule_$ mutable WriteBarrier<Unknown> m_BunCommonJSModuleValue; - mutable WriteBarrier<Unknown> m_JSBroadcastChannelSetterValue; - mutable WriteBarrier<Unknown> m_JSBufferSetterValue; - mutable WriteBarrier<Unknown> m_JSCloseEventSetterValue; - mutable WriteBarrier<Unknown> m_JSCustomEventSetterValue; - mutable WriteBarrier<Unknown> m_JSDOMExceptionSetterValue; - mutable WriteBarrier<Unknown> m_JSDOMFormDataSetterValue; - mutable WriteBarrier<Unknown> m_JSErrorEventSetterValue; - mutable WriteBarrier<Unknown> m_JSEventSetterValue; - mutable WriteBarrier<Unknown> m_JSEventTargetSetterValue; - mutable WriteBarrier<Unknown> m_JSFetchHeadersSetterValue; - mutable WriteBarrier<Unknown> m_JSMessageChannelSetterValue; - mutable WriteBarrier<Unknown> m_JSMessageEventSetterValue; - mutable WriteBarrier<Unknown> m_JSMessagePortSetterValue; - mutable WriteBarrier<Unknown> m_JSTextEncoderSetterValue; - mutable WriteBarrier<Unknown> m_JSURLSearchParamsSetterValue; - mutable WriteBarrier<Unknown> m_JSWebSocketSetterValue; - mutable WriteBarrier<Unknown> m_JSWorkerSetterValue; - - mutable WriteBarrier<Unknown> m_JSBunDebuggerValue; + + // mutable WriteBarrier<Unknown> m_JSBunDebuggerValue; mutable WriteBarrier<JSFunction> m_thenables[promiseFunctionsSize + 1]; + mutable WriteBarrier<JSC::Unknown> m_errorConstructorPrepareStackTraceValue; + Structure* memoryFootprintStructure() { return m_memoryFootprintStructure.getInitializedOnMainThread(this); @@ -439,9 +384,8 @@ public: return false; } - BunPlugin::OnLoad onLoadPlugins[BunPluginTargetMax + 1] {}; - BunPlugin::OnResolve onResolvePlugins[BunPluginTargetMax + 1] {}; - BunPluginTarget defaultBunPluginTarget = BunPluginTargetBun; + BunPlugin::OnLoad onLoadPlugins {}; + BunPlugin::OnResolve onResolvePlugins {}; // This increases the cache hit rate for JSC::VM's SourceProvider cache // It also avoids an extra allocation for the SourceProvider @@ -478,6 +422,7 @@ public: private: void addBuiltinGlobals(JSC::VM&); + void finishCreation(JSC::VM&); friend void WebCore::JSBuiltinInternalFunctions::initialize(Zig::GlobalObject&); WebCore::JSBuiltinInternalFunctions m_builtinInternalFunctions; @@ -490,6 +435,9 @@ private: WebCore::ScriptExecutionContext* m_scriptExecutionContext; Ref<WebCore::DOMWrapperWorld> m_world; + // JSC's hashtable code-generator tries to access these properties, so we make them public. + // However, we'd like it better if they could be protected. +public: /** * WARNING: You must update visitChildrenImpl() if you add a new field. * @@ -523,7 +471,7 @@ private: * For example, if you don't add the queueMicrotask functions to visitChildrenImpl(), * those callbacks will eventually never be called anymore. But it'll work the first time! */ - LazyProperty<JSGlobalObject, JSC::Structure> m_pendingVirtualModuleResultStructure; + LazyProperty<JSGlobalObject, Structure> m_pendingVirtualModuleResultStructure; LazyProperty<JSGlobalObject, JSFunction> m_performMicrotaskFunction; LazyProperty<JSGlobalObject, JSFunction> m_nativeMicrotaskTrampoline; LazyProperty<JSGlobalObject, JSFunction> m_performMicrotaskVariadicFunction; @@ -537,38 +485,40 @@ private: LazyProperty<JSGlobalObject, JSObject> m_JSArrayBufferControllerPrototype; LazyProperty<JSGlobalObject, JSObject> m_JSFileSinkControllerPrototype; LazyProperty<JSGlobalObject, JSObject> m_JSHTTPSResponseControllerPrototype; - LazyProperty<JSGlobalObject, JSObject> m_navigatorObject; - LazyProperty<JSGlobalObject, JSObject> m_performanceObject; - LazyProperty<JSGlobalObject, JSObject> m_processObject; LazyProperty<JSGlobalObject, JSObject> m_subtleCryptoObject; LazyProperty<JSGlobalObject, Structure> m_JSHTTPResponseController; - LazyProperty<JSGlobalObject, JSC::Structure> m_JSBufferSubclassStructure; + LazyProperty<JSGlobalObject, Structure> m_JSBufferSubclassStructure; LazyProperty<JSGlobalObject, JSWeakMap> m_vmModuleContextMap; LazyProperty<JSGlobalObject, JSObject> m_lazyRequireCacheObject; LazyProperty<JSGlobalObject, JSObject> m_lazyTestModuleObject; LazyProperty<JSGlobalObject, JSObject> m_lazyPreloadTestModuleObject; - LazyProperty<JSGlobalObject, JSFunction> m_bunSleepThenCallback; LazyProperty<JSGlobalObject, Structure> m_cachedGlobalObjectStructure; LazyProperty<JSGlobalObject, Structure> m_cachedGlobalProxyStructure; LazyProperty<JSGlobalObject, Structure> m_commonJSModuleObjectStructure; LazyProperty<JSGlobalObject, Structure> m_commonJSFunctionArgumentsStructure; + LazyProperty<JSGlobalObject, Structure> m_JSSocketAddressStructure; LazyProperty<JSGlobalObject, Structure> m_memoryFootprintStructure; - LazyProperty<JSGlobalObject, JSObject> m_cryptoObject; - - LazyProperty<JSGlobalObject, JSC::JSObject> m_requireFunctionUnbound; - LazyProperty<JSGlobalObject, JSC::JSObject> m_requireResolveFunctionUnbound; + LazyProperty<JSGlobalObject, JSObject> m_requireFunctionUnbound; + LazyProperty<JSGlobalObject, JSObject> m_requireResolveFunctionUnbound; LazyProperty<JSGlobalObject, Bun::InternalModuleRegistry> m_internalModuleRegistry; - LazyProperty<JSGlobalObject, Bun::ProcessBindingConstants> m_processBindingConstants; - LazyProperty<JSGlobalObject, JSC::Structure> m_importMetaObjectStructure; - LazyProperty<JSGlobalObject, JSC::Structure> m_asyncBoundFunctionStructure; - + LazyProperty<JSGlobalObject, JSObject> m_processBindingConstants; + LazyProperty<JSGlobalObject, Structure> m_importMetaObjectStructure; + LazyProperty<JSGlobalObject, Structure> m_asyncBoundFunctionStructure; LazyProperty<JSGlobalObject, JSC::JSObject> m_JSDOMFileConstructor; + LazyProperty<JSGlobalObject, Structure> m_JSCryptoKey; + LazyProperty<JSGlobalObject, JSObject> m_bunObject; + LazyProperty<JSGlobalObject, JSObject> m_cryptoObject; + LazyProperty<JSGlobalObject, JSObject> m_navigatorObject; + LazyProperty<JSGlobalObject, JSObject> m_performanceObject; + LazyProperty<JSGlobalObject, JSObject> m_processObject; + +private: DOMGuardedObjectSet m_guardedObjects WTF_GUARDED_BY_LOCK(m_gcLock); void* m_bunVM; - WebCore::SubtleCrypto* crypto = nullptr; + WebCore::SubtleCrypto* m_subtleCrypto = nullptr; WTF::Vector<JSC::Strong<JSC::JSPromise>> m_aboutToBeNotifiedRejectedPromises; WTF::Vector<JSC::Strong<JSC::JSFunction>> m_ffiFunctions; diff --git a/src/bun.js/bindings/ZigGlobalObject.lut.h b/src/bun.js/bindings/ZigGlobalObject.lut.h new file mode 100644 index 000000000..6516648e8 --- /dev/null +++ b/src/bun.js/bindings/ZigGlobalObject.lut.h @@ -0,0 +1,341 @@ +// File generated via `make static-hash-table` / `make cpp` +static const struct CompactHashIndex bunGlobalObjectTableIndex[260] = { + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 42, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 6, -1 }, + { 3, -1 }, + { -1, -1 }, + { 34, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 29, 258 }, + { -1, -1 }, + { -1, -1 }, + { 54, 257 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 51, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 2, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 18, -1 }, + { 56, -1 }, + { -1, -1 }, + { -1, -1 }, + { 14, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 41, -1 }, + { 47, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 69, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 39, -1 }, + { -1, -1 }, + { -1, -1 }, + { 38, -1 }, + { 63, -1 }, + { -1, -1 }, + { 57, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 49, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 58, -1 }, + { 11, -1 }, + { -1, -1 }, + { -1, -1 }, + { 0, -1 }, + { -1, -1 }, + { 37, -1 }, + { 21, -1 }, + { 66, -1 }, + { -1, -1 }, + { -1, -1 }, + { 70, -1 }, + { -1, -1 }, + { 45, -1 }, + { -1, -1 }, + { 48, -1 }, + { -1, -1 }, + { -1, -1 }, + { 24, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 33, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 50, -1 }, + { 46, -1 }, + { -1, -1 }, + { 13, -1 }, + { -1, -1 }, + { -1, -1 }, + { 43, -1 }, + { -1, -1 }, + { 1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 32, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 28, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 26, -1 }, + { -1, -1 }, + { -1, -1 }, + { 17, -1 }, + { -1, -1 }, + { 31, -1 }, + { -1, -1 }, + { -1, -1 }, + { 35, -1 }, + { 71, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 22, -1 }, + { -1, -1 }, + { -1, -1 }, + { 4, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 23, -1 }, + { -1, -1 }, + { -1, -1 }, + { 55, -1 }, + { -1, -1 }, + { 53, -1 }, + { -1, -1 }, + { 12, -1 }, + { 25, -1 }, + { 7, -1 }, + { -1, -1 }, + { 9, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 61, -1 }, + { 60, -1 }, + { -1, -1 }, + { 5, 256 }, + { -1, -1 }, + { 64, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 36, -1 }, + { -1, -1 }, + { 15, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 40, 259 }, + { -1, -1 }, + { -1, -1 }, + { 68, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 52, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 30, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 27, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 44, -1 }, + { -1, -1 }, + { -1, -1 }, + { 65, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 20, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 10, -1 }, + { 16, -1 }, + { -1, -1 }, + { -1, -1 }, + { -1, -1 }, + { 19, -1 }, + { -1, -1 }, + { 8, -1 }, + { 59, -1 }, + { 62, -1 }, + { 67, -1 }, +}; + +static const struct HashTableValue bunGlobalObjectTableValues[72] = { + { "addEventListener"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFunctionAddEventListener, 2 } }, + { "alert"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, WebCore__alert, 1 } }, + { "atob"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, functionATOB, 1 } }, + { "btoa"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, functionBTOA, 1 } }, + { "clearImmediate"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, functionClearTimeout, 1 } }, + { "clearInterval"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, functionClearInterval, 1 } }, + { "clearTimeout"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, functionClearTimeout, 1 } }, + { "confirm"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, WebCore__confirm, 1 } }, + { "dispatchEvent"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFunctionDispatchEvent, 1 } }, + { "fetch"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Bun__fetch, 2 } }, + { "postMessage"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFunctionPostMessage, 1 } }, + { "prompt"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, WebCore__prompt, 1 } }, + { "queueMicrotask"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, functionQueueMicrotask, 2 } }, + { "removeEventListener"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFunctionRemoveEventListener, 2 } }, + { "reportError"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, functionReportError, 1 } }, + { "setImmediate"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, functionSetImmediate, 1 } }, + { "setInterval"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, functionSetInterval, 1 } }, + { "setTimeout"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, functionSetTimeout, 1 } }, + { "structuredClone"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, functionStructuredClone, 2 } }, + { "global"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, GlobalObject_getGlobalThis } }, + { "EventSource"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, getEventSourceConstructor } }, + { "Bun"_s, static_cast<unsigned>(PropertyAttribute::CellProperty|PropertyAttribute::DontDelete|PropertyAttribute::ReadOnly), NoIntrinsic, { HashTableValue::LazyCellPropertyType, OBJECT_OFFSETOF(GlobalObject, m_bunObject) } }, + { "File"_s, static_cast<unsigned>(PropertyAttribute::CellProperty), NoIntrinsic, { HashTableValue::LazyCellPropertyType, OBJECT_OFFSETOF(GlobalObject, m_JSDOMFileConstructor) } }, + { "crypto"_s, static_cast<unsigned>(PropertyAttribute::CellProperty), NoIntrinsic, { HashTableValue::LazyCellPropertyType, OBJECT_OFFSETOF(GlobalObject, m_cryptoObject) } }, + { "navigator"_s, static_cast<unsigned>(PropertyAttribute::CellProperty), NoIntrinsic, { HashTableValue::LazyCellPropertyType, OBJECT_OFFSETOF(GlobalObject, m_navigatorObject) } }, + { "performance"_s, static_cast<unsigned>(PropertyAttribute::CellProperty), NoIntrinsic, { HashTableValue::LazyCellPropertyType, OBJECT_OFFSETOF(GlobalObject, m_performanceObject) } }, + { "process"_s, static_cast<unsigned>(PropertyAttribute::CellProperty), NoIntrinsic, { HashTableValue::LazyCellPropertyType, OBJECT_OFFSETOF(GlobalObject, m_processObject) } }, + { "Blob"_s, static_cast<unsigned>(PropertyAttribute::ClassStructure), NoIntrinsic, { HashTableValue::LazyClassStructureType, OBJECT_OFFSETOF(GlobalObject, m_JSBlob) } }, + { "Buffer"_s, static_cast<unsigned>(PropertyAttribute::ClassStructure), NoIntrinsic, { HashTableValue::LazyClassStructureType, OBJECT_OFFSETOF(GlobalObject, m_JSBufferClassStructure) } }, + { "BuildError"_s, static_cast<unsigned>(PropertyAttribute::ClassStructure), NoIntrinsic, { HashTableValue::LazyClassStructureType, OBJECT_OFFSETOF(GlobalObject, m_JSBuildMessage) } }, + { "BuildMessage"_s, static_cast<unsigned>(PropertyAttribute::ClassStructure), NoIntrinsic, { HashTableValue::LazyClassStructureType, OBJECT_OFFSETOF(GlobalObject, m_JSBuildMessage) } }, + { "Crypto"_s, static_cast<unsigned>(PropertyAttribute::ClassStructure), NoIntrinsic, { HashTableValue::LazyClassStructureType, OBJECT_OFFSETOF(GlobalObject, m_JSCrypto) } }, + { "HTMLRewriter"_s, static_cast<unsigned>(PropertyAttribute::ClassStructure), NoIntrinsic, { HashTableValue::LazyClassStructureType, OBJECT_OFFSETOF(GlobalObject, m_JSHTMLRewriter) } }, + { "Request"_s, static_cast<unsigned>(PropertyAttribute::ClassStructure), NoIntrinsic, { HashTableValue::LazyClassStructureType, OBJECT_OFFSETOF(GlobalObject, m_JSRequest) } }, + { "ResolveError"_s, static_cast<unsigned>(PropertyAttribute::ClassStructure), NoIntrinsic, { HashTableValue::LazyClassStructureType, OBJECT_OFFSETOF(GlobalObject, m_JSResolveMessage) } }, + { "ResolveMessage"_s, static_cast<unsigned>(PropertyAttribute::ClassStructure), NoIntrinsic, { HashTableValue::LazyClassStructureType, OBJECT_OFFSETOF(GlobalObject, m_JSResolveMessage) } }, + { "Response"_s, static_cast<unsigned>(PropertyAttribute::ClassStructure), NoIntrinsic, { HashTableValue::LazyClassStructureType, OBJECT_OFFSETOF(GlobalObject, m_JSResponse) } }, + { "TextDecoder"_s, static_cast<unsigned>(PropertyAttribute::ClassStructure), NoIntrinsic, { HashTableValue::LazyClassStructureType, OBJECT_OFFSETOF(GlobalObject, m_JSTextDecoder) } }, + { "AbortController"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, AbortControllerConstructorCallback } }, + { "AbortSignal"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, AbortSignalConstructorCallback } }, + { "BroadcastChannel"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, BroadcastChannelConstructorCallback } }, + { "ByteLengthQueuingStrategy"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, ByteLengthQueuingStrategyConstructorCallback } }, + { "CloseEvent"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, CloseEventConstructorCallback } }, + { "CountQueuingStrategy"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, CountQueuingStrategyConstructorCallback } }, + { "CryptoKey"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, CryptoKeyConstructorCallback } }, + { "CustomEvent"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, CustomEventConstructorCallback } }, + { "DOMException"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, DOMExceptionConstructorCallback } }, + { "ErrorEvent"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, ErrorEventConstructorCallback } }, + { "Event"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, EventConstructorCallback } }, + { "EventTarget"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, EventTargetConstructorCallback } }, + { "FormData"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, DOMFormDataConstructorCallback } }, + { "Headers"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, FetchHeadersConstructorCallback } }, + { "MessageChannel"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, MessageChannelConstructorCallback } }, + { "MessageEvent"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, MessageEventConstructorCallback } }, + { "MessagePort"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, MessagePortConstructorCallback } }, + { "ReadableByteStreamController"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, ReadableByteStreamControllerConstructorCallback } }, + { "ReadableStream"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, ReadableStreamConstructorCallback } }, + { "ReadableStreamBYOBReader"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, ReadableStreamBYOBReaderConstructorCallback } }, + { "ReadableStreamBYOBRequest"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, ReadableStreamBYOBRequestConstructorCallback } }, + { "ReadableStreamDefaultController"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, ReadableStreamDefaultControllerConstructorCallback } }, + { "ReadableStreamDefaultReader"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, ReadableStreamDefaultReaderConstructorCallback } }, + { "SubtleCrypto"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, SubtleCryptoConstructorCallback } }, + { "TextEncoder"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, TextEncoderConstructorCallback } }, + { "TransformStream"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, TransformStreamConstructorCallback } }, + { "URL"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, DOMURLConstructorCallback } }, + { "URLSearchParams"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, URLSearchParamsConstructorCallback } }, + { "WebSocket"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, WebSocketConstructorCallback } }, + { "Worker"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, WorkerConstructorCallback } }, + { "WritableStream"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, WritableStreamConstructorCallback } }, + { "WritableStreamDefaultController"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, WritableStreamDefaultControllerConstructorCallback } }, + { "WritableStreamDefaultWriter"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, WritableStreamDefaultWriterConstructorCallback } }, + { "TransformStreamDefaultController"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, TransformStreamDefaultControllerConstructorCallback } }, +}; + +static const struct HashTable bunGlobalObjectTable = + { 72, 255, false, nullptr, bunGlobalObjectTableValues, bunGlobalObjectTableIndex }; diff --git a/src/bun.js/bindings/ZigGlobalObject.lut.txt b/src/bun.js/bindings/ZigGlobalObject.lut.txt new file mode 100644 index 000000000..aadaee92a --- /dev/null +++ b/src/bun.js/bindings/ZigGlobalObject.lut.txt @@ -0,0 +1,82 @@ +// In a separate file because processing ZigGlobalObject.cpp takes 15+ seconds + +/* Source for ZigGlobalObject.lut.h +@begin bunGlobalObjectTable + addEventListener jsFunctionAddEventListener Function 2 + alert WebCore__alert Function 1 + atob functionATOB Function 1 + btoa functionBTOA Function 1 + clearImmediate functionClearTimeout Function 1 + clearInterval functionClearInterval Function 1 + clearTimeout functionClearTimeout Function 1 + confirm WebCore__confirm Function 1 + dispatchEvent jsFunctionDispatchEvent Function 1 + fetch Bun__fetch Function 2 + postMessage jsFunctionPostMessage Function 1 + prompt WebCore__prompt Function 1 + queueMicrotask functionQueueMicrotask Function 2 + removeEventListener jsFunctionRemoveEventListener Function 2 + reportError functionReportError Function 1 + setImmediate functionSetImmediate Function 1 + setInterval functionSetInterval Function 1 + setTimeout functionSetTimeout Function 1 + structuredClone functionStructuredClone Function 2 + + global GlobalObject_getGlobalThis PropertyCallback + EventSource getEventSourceConstructor PropertyCallback + + Bun GlobalObject::m_bunObject CellProperty|DontDelete|ReadOnly + File GlobalObject::m_JSDOMFileConstructor CellProperty + crypto GlobalObject::m_cryptoObject CellProperty + navigator GlobalObject::m_navigatorObject CellProperty + performance GlobalObject::m_performanceObject CellProperty + process GlobalObject::m_processObject CellProperty + + Blob GlobalObject::m_JSBlob ClassStructure + Buffer GlobalObject::m_JSBufferClassStructure ClassStructure + BuildError GlobalObject::m_JSBuildMessage ClassStructure + BuildMessage GlobalObject::m_JSBuildMessage ClassStructure + Crypto GlobalObject::m_JSCrypto ClassStructure + HTMLRewriter GlobalObject::m_JSHTMLRewriter ClassStructure + Request GlobalObject::m_JSRequest ClassStructure + ResolveError GlobalObject::m_JSResolveMessage ClassStructure + ResolveMessage GlobalObject::m_JSResolveMessage ClassStructure + Response GlobalObject::m_JSResponse ClassStructure + TextDecoder GlobalObject::m_JSTextDecoder ClassStructure + + AbortController AbortControllerConstructorCallback PropertyCallback + AbortSignal AbortSignalConstructorCallback PropertyCallback + BroadcastChannel BroadcastChannelConstructorCallback PropertyCallback + ByteLengthQueuingStrategy ByteLengthQueuingStrategyConstructorCallback PropertyCallback + CloseEvent CloseEventConstructorCallback PropertyCallback + CountQueuingStrategy CountQueuingStrategyConstructorCallback PropertyCallback + CryptoKey CryptoKeyConstructorCallback PropertyCallback + CustomEvent CustomEventConstructorCallback PropertyCallback + DOMException DOMExceptionConstructorCallback PropertyCallback + ErrorEvent ErrorEventConstructorCallback PropertyCallback + Event EventConstructorCallback PropertyCallback + EventTarget EventTargetConstructorCallback PropertyCallback + FormData DOMFormDataConstructorCallback PropertyCallback + Headers FetchHeadersConstructorCallback PropertyCallback + MessageChannel MessageChannelConstructorCallback PropertyCallback + MessageEvent MessageEventConstructorCallback PropertyCallback + MessagePort MessagePortConstructorCallback PropertyCallback + ReadableByteStreamController ReadableByteStreamControllerConstructorCallback PropertyCallback + ReadableStream ReadableStreamConstructorCallback PropertyCallback + ReadableStreamBYOBReader ReadableStreamBYOBReaderConstructorCallback PropertyCallback + ReadableStreamBYOBRequest ReadableStreamBYOBRequestConstructorCallback PropertyCallback + ReadableStreamDefaultController ReadableStreamDefaultControllerConstructorCallback PropertyCallback + ReadableStreamDefaultReader ReadableStreamDefaultReaderConstructorCallback PropertyCallback + SubtleCrypto SubtleCryptoConstructorCallback PropertyCallback + TextEncoder TextEncoderConstructorCallback PropertyCallback + TransformStream TransformStreamConstructorCallback PropertyCallback + URL DOMURLConstructorCallback PropertyCallback + URLSearchParams URLSearchParamsConstructorCallback PropertyCallback + WebSocket WebSocketConstructorCallback PropertyCallback + Worker WorkerConstructorCallback PropertyCallback + WritableStream WritableStreamConstructorCallback PropertyCallback + WritableStreamDefaultController WritableStreamDefaultControllerConstructorCallback PropertyCallback + WritableStreamDefaultWriter WritableStreamDefaultWriterConstructorCallback PropertyCallback + TransformStreamDefaultController TransformStreamDefaultControllerConstructorCallback PropertyCallback +@end +*/ diff --git a/src/bun.js/bindings/ZigLazyStaticFunctions-inlines.h b/src/bun.js/bindings/ZigLazyStaticFunctions-inlines.h index c97393723..0c13ecd58 100644 --- a/src/bun.js/bindings/ZigLazyStaticFunctions-inlines.h +++ b/src/bun.js/bindings/ZigLazyStaticFunctions-inlines.h @@ -25,7 +25,7 @@ static void DOMCall__FFI__ptr__put(JSC::JSGlobalObject* globalObject, JSC::Encod globalObject->vm(), Identifier::fromString(globalObject->vm(), "ptr"_s), function, - JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction | 0); + 0); } /* -- END DOMCall DEFINITIONS-- */ diff --git a/src/bun.js/bindings/ZigSourceProvider.cpp b/src/bun.js/bindings/ZigSourceProvider.cpp index d11c748da..960e577b9 100644 --- a/src/bun.js/bindings/ZigSourceProvider.cpp +++ b/src/bun.js/bindings/ZigSourceProvider.cpp @@ -104,6 +104,7 @@ Ref<SourceProvider> SourceProvider::create(Zig::GlobalObject* globalObject, Reso auto provider = adoptRef(*new SourceProvider( globalObject->isThreadLocalDefaultGlobalObject ? globalObject : nullptr, resolvedSource, stringImpl.releaseImpl().releaseNonNull(), + JSC::SourceTaintedOrigin::Untainted, toSourceOrigin(sourceURLString, isBuiltin), sourceURLString.impl(), TextPosition(), sourceType)); diff --git a/src/bun.js/bindings/ZigSourceProvider.h b/src/bun.js/bindings/ZigSourceProvider.h index 364e6ee23..b7574c7a4 100644 --- a/src/bun.js/bindings/ZigSourceProvider.h +++ b/src/bun.js/bindings/ZigSourceProvider.h @@ -69,9 +69,10 @@ public: private: SourceProvider(Zig::GlobalObject* globalObject, ResolvedSource resolvedSource, Ref<WTF::StringImpl>&& sourceImpl, + JSC::SourceTaintedOrigin taintedness, const SourceOrigin& sourceOrigin, WTF::String&& sourceURL, const TextPosition& startPosition, JSC::SourceProviderSourceType sourceType) - : Base(sourceOrigin, WTFMove(sourceURL), String(), startPosition, sourceType) + : Base(sourceOrigin, WTFMove(sourceURL), String(), taintedness, startPosition, sourceType) , m_source(sourceImpl) { diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index e46982aad..117b848ef 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -19,6 +19,7 @@ #include "JavaScriptCore/JSArray.h" #include "JavaScriptCore/JSArrayBuffer.h" #include "JavaScriptCore/JSArrayInlines.h" +#include "JavaScriptCore/ErrorInstanceInlines.h" #include "JavaScriptCore/JSCallbackObject.h" #include "JavaScriptCore/JSClassRef.h" @@ -229,6 +230,47 @@ AsymmetricMatcherResult matchAsymmetricMatcher(JSGlobalObject* globalObject, JSC } return AsymmetricMatcherResult::FAIL; + } else if (auto* expectArrayContaining = jsDynamicCast<JSExpectArrayContaining*>(matcherPropCell)) { + JSValue expectedArrayValue = expectArrayContaining->m_arrayValue.get(); + + if (JSC::isArray(globalObject, otherProp)) { + if (JSC::isArray(globalObject, expectedArrayValue)) { + JSArray* expectedArray = jsDynamicCast<JSArray*>(expectedArrayValue); + JSArray* otherArray = jsDynamicCast<JSArray*>(otherProp); + + unsigned expectedLength = expectedArray->length(); + unsigned otherLength = otherArray->length(); + + // A empty array is all array's subset + if (expectedLength == 0) { + return AsymmetricMatcherResult::PASS; + } + + // O(m*n) but works for now + for (unsigned m = 0; m < expectedLength; m++) { + JSValue expectedValue = expectedArray->getIndex(globalObject, m); + bool found = false; + + for (unsigned n = 0; n < otherLength; n++) { + JSValue otherValue = otherArray->getIndex(globalObject, n); + ThrowScope scope = DECLARE_THROW_SCOPE(globalObject->vm()); + Vector<std::pair<JSValue, JSValue>, 16> stack; + if (Bun__deepEquals<false, true>(globalObject, expectedValue, otherValue, stack, &scope, true)) { + found = true; + break; + } + } + + if (!found) { + return AsymmetricMatcherResult::FAIL; + } + } + + return AsymmetricMatcherResult::PASS; + } + } + + return AsymmetricMatcherResult::FAIL; } return AsymmetricMatcherResult::NOT_MATCHER; @@ -306,10 +348,8 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2, // need to check this before primitives, asymmetric matchers // can match against any type of value. if constexpr (enableAsymmetricMatchers) { - JSCell* c1 = v1.asCell(); - JSCell* c2 = v2.asCell(); - if (v2.isCell() && !v2.isEmpty() && c2->type() == JSC::JSType(JSDOMWrapperType)) { - switch (matchAsymmetricMatcher(globalObject, c2, v1, scope)) { + if (v2.isCell() && !v2.isEmpty() && v2.asCell()->type() == JSC::JSType(JSDOMWrapperType)) { + switch (matchAsymmetricMatcher(globalObject, v2.asCell(), v1, scope)) { case AsymmetricMatcherResult::FAIL: return false; case AsymmetricMatcherResult::PASS: @@ -318,8 +358,8 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2, // continue comparison break; } - } else if (v1.isCell() && !v1.isEmpty() && c1->type() == JSC::JSType(JSDOMWrapperType)) { - switch (matchAsymmetricMatcher(globalObject, c1, v2, scope)) { + } else if (v1.isCell() && !v1.isEmpty() && v1.asCell()->type() == JSC::JSType(JSDOMWrapperType)) { + switch (matchAsymmetricMatcher(globalObject, v1.asCell(), v2, scope)) { case AsymmetricMatcherResult::FAIL: return false; case AsymmetricMatcherResult::PASS: @@ -576,7 +616,7 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2, case Float64ArrayType: case BigInt64ArrayType: case BigUint64ArrayType: { - if (!isTypedArrayType(static_cast<JSC::JSType>(c2Type))) { + if (!isTypedArrayType(static_cast<JSC::JSType>(c2Type)) || c1Type != c2Type) { return false; } @@ -627,6 +667,7 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2, case JSDOMWrapperType: { if (c2Type == JSDOMWrapperType) { // https://github.com/oven-sh/bun/issues/4089 + // https://github.com/oven-sh/bun/issues/6492 auto* url2 = jsDynamicCast<JSDOMURL*>(v2); auto* url1 = jsDynamicCast<JSDOMURL*>(v1); @@ -635,19 +676,15 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2, if ((url2 == nullptr) != (url1 == nullptr)) { return false; } - - if (url2 && url1) { - return url1->wrapped().href() != url2->wrapped().href(); - } - } else { - if (url2 && url1) { - // toEqual should return false when the URLs' href is not equal - // But you could have added additional properties onto the - // url object itself, so we must check those as well - // But it's definitely not equal if the href() is not the same - if (url1->wrapped().href() != url2->wrapped().href()) { - return false; - } + } + + if (url2 && url1) { + // toEqual or toStrictEqual should return false when the URLs' href is not equal + // But you could have added additional properties onto the + // url object itself, so we must check those as well + // But it's definitely not equal if the href() is not the same + if (url1->wrapped().href() != url2->wrapped().href()) { + return false; } } } @@ -1045,7 +1082,9 @@ void WebCore__FetchHeaders__toUWSResponse(WebCore__FetchHeaders* arg0, bool is_s WebCore__FetchHeaders* WebCore__FetchHeaders__createEmpty() { - return new WebCore::FetchHeaders({ WebCore::FetchHeaders::Guard::None, {} }); + auto* headers = new WebCore::FetchHeaders({ WebCore::FetchHeaders::Guard::None, {} }); + headers->relaxAdoptionRequirement(); + return headers; } void WebCore__FetchHeaders__append(WebCore__FetchHeaders* headers, const ZigString* arg1, const ZigString* arg2, JSC__JSGlobalObject* lexicalGlobalObject) @@ -1074,6 +1113,7 @@ WebCore__FetchHeaders* WebCore__FetchHeaders__createFromJS(JSC__JSGlobalObject* RETURN_IF_EXCEPTION(throwScope, nullptr); auto* headers = new WebCore::FetchHeaders({ WebCore::FetchHeaders::Guard::None, {} }); + headers->relaxAdoptionRequirement(); if (init) { // `fill` doesn't set an exception on the VM if it fails, it returns an // ExceptionOr<void>. So we need to check for the exception and, if set, @@ -1112,6 +1152,7 @@ WebCore__FetchHeaders* WebCore__FetchHeaders__cloneThis(WebCore__FetchHeaders* h { auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm()); auto* clone = new WebCore::FetchHeaders({ WebCore::FetchHeaders::Guard::None, {} }); + clone->relaxAdoptionRequirement(); WebCore::propagateException(*lexicalGlobalObject, throwScope, clone->fill(*headers)); return clone; @@ -1181,6 +1222,7 @@ WebCore::FetchHeaders* WebCore__FetchHeaders__createFromPicoHeaders_(const void* { PicoHTTPHeaders pico_headers = *reinterpret_cast<const PicoHTTPHeaders*>(arg1); auto* headers = new WebCore::FetchHeaders({ WebCore::FetchHeaders::Guard::None, {} }); + headers->relaxAdoptionRequirement(); // This prevents an assertion later, but may not be the proper approach. if (pico_headers.len > 0) { HTTPHeaderMap map = HTTPHeaderMap(); @@ -1223,6 +1265,8 @@ WebCore::FetchHeaders* WebCore__FetchHeaders__createFromUWS(JSC__JSGlobalObject* size_t i = 0; auto* headers = new WebCore::FetchHeaders({ WebCore::FetchHeaders::Guard::None, {} }); + headers->relaxAdoptionRequirement(); // This prevents an assertion later, but may not be the proper approach. + HTTPHeaderMap map = HTTPHeaderMap(); for (const auto& header : req) { @@ -1246,7 +1290,6 @@ WebCore::FetchHeaders* WebCore__FetchHeaders__createFromUWS(JSC__JSGlobalObject* if (i > 56) __builtin_unreachable(); } - headers->setInternalHeaders(WTFMove(map)); return headers; } @@ -1354,15 +1397,22 @@ BunString WebCore__DOMURL__fileSystemPath(WebCore__DOMURL* arg0) extern "C" JSC__JSValue ZigString__toJSONObject(const ZigString* strPtr, JSC::JSGlobalObject* globalObject) { auto str = Zig::toString(*strPtr); - auto throwScope = DECLARE_THROW_SCOPE(globalObject->vm()); - auto scope = DECLARE_CATCH_SCOPE(globalObject->vm()); - JSValue result = JSONParseWithException(globalObject, str); - if (auto* exception = scope.exception()) { + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + + // JSONParseWithException does not propagate exceptions as expected. See #5859 + JSValue result = JSONParse(globalObject, str); + + if (!result && !scope.exception()) { + scope.throwException(globalObject, createSyntaxError(globalObject, "Failed to parse JSON"_s)); + } + + if (scope.exception()) { + auto* exception = scope.exception(); scope.clearException(); - RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(exception->value())); + return JSC::JSValue::encode(exception); } - RELEASE_AND_RETURN(throwScope, JSValue::encode(result)); + return JSValue::encode(result); } JSC__JSValue SystemError__toErrorInstance(const SystemError* arg0, @@ -2063,7 +2113,7 @@ JSC__JSValue JSC__JSModuleLoader__evaluate(JSC__JSGlobalObject* globalObject, co JSC::VM& vm = globalObject->vm(); JSC::SourceCode sourceCode = JSC::makeSource( - src, JSC::SourceOrigin { origin }, origin.fileSystemPath(), + src, JSC::SourceOrigin { origin }, JSC::SourceTaintedOrigin::Untainted, origin.fileSystemPath(), WTF::TextPosition(), JSC::SourceProviderSourceType::Module); globalObject->moduleLoader()->provideFetch(globalObject, jsString(vm, origin.fileSystemPath()), WTFMove(sourceCode)); auto* promise = JSC::importModule(globalObject, JSC::Identifier::fromString(vm, origin.fileSystemPath()), JSValue(jsString(vm, referrer.fileSystemPath())), JSValue(), JSValue()); @@ -2116,6 +2166,14 @@ JSC__JSValue ReadableStream__empty(Zig::GlobalObject* globalObject) return JSValue::encode(JSC::call(globalObject, function, JSC::ArgList(), "ReadableStream.create"_s)); } +JSC__JSValue ReadableStream__used(Zig::GlobalObject* globalObject) +{ + auto& vm = globalObject->vm(); + auto clientData = WebCore::clientData(vm); + auto* function = globalObject->getDirect(vm, clientData->builtinNames().createUsedReadableStreamPrivateName()).getObject(); + return JSValue::encode(JSC::call(globalObject, function, JSC::ArgList(), "ReadableStream.create"_s)); +} + JSC__JSValue JSC__JSValue__createRangeError(const ZigString* message, const ZigString* arg1, JSC__JSGlobalObject* globalObject) { @@ -2303,29 +2361,31 @@ JSC__JSValue JSC__JSValue__createStringArray(JSC__JSGlobalObject* globalObject, JSC::JSArray* array = nullptr; { + JSC::GCDeferralContext deferralContext(vm); JSC::ObjectInitializationScope initializationScope(vm); if ((array = JSC::JSArray::tryCreateUninitializedRestricted( - initializationScope, nullptr, + initializationScope, &deferralContext, globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous), arg2))) { if (!clone) { for (size_t i = 0; i < arg2; ++i) { - array->putDirectIndex(globalObject, i, JSC::jsString(vm, Zig::toString(arg1[i]))); + array->putDirectIndex(globalObject, i, JSC::jsString(vm, Zig::toString(arg1[i]), &deferralContext)); } } else { for (size_t i = 0; i < arg2; ++i) { - array->putDirectIndex(globalObject, i, JSC::jsString(vm, Zig::toStringCopy(arg1[i]))); + array->putDirectIndex(globalObject, i, JSC::jsString(vm, Zig::toStringCopy(arg1[i]), &deferralContext)); } } } - } - if (!array) { - JSC::throwOutOfMemoryError(globalObject, scope); - return JSC::JSValue::encode(JSC::JSValue()); - } - RELEASE_AND_RETURN(scope, JSC::JSValue::encode(JSC::JSValue(array))); + if (!array) { + JSC::throwOutOfMemoryError(globalObject, scope); + return JSC::JSValue::encode(JSC::JSValue()); + } + + RELEASE_AND_RETURN(scope, JSC::JSValue::encode(JSC::JSValue(array))); + } } JSC__JSValue JSC__JSGlobalObject__createAggregateError(JSC__JSGlobalObject* globalObject, @@ -2803,7 +2863,7 @@ JSC__VM* JSC__JSGlobalObject__vm(JSC__JSGlobalObject* arg0) { return &arg0->vm() void JSC__JSGlobalObject__handleRejectedPromises(JSC__JSGlobalObject* arg0) { - return static_cast<Zig::GlobalObject*>(arg0)->handleRejectedPromises(); + return jsCast<Zig::GlobalObject*>(arg0)->handleRejectedPromises(); } #pragma mark - JSC::JSValue @@ -3012,20 +3072,16 @@ JSC__JSValue JSC__JSValue__jsNumberFromUint64(uint64_t arg0) int64_t JSC__JSValue__toInt64(JSC__JSValue val) { - JSC::JSValue _val = JSC::JSValue::decode(val); - - int64_t result = JSC::tryConvertToInt52(_val.asDouble()); - if (result != JSC::JSValue::notInt52) { - return result; - } - - if (_val.isHeapBigInt()) { - - if (auto* heapBigInt = _val.asHeapBigInt()) { + JSC::JSValue value = JSC::JSValue::decode(val); + ASSERT(value.isHeapBigInt() || value.isNumber()); + if (value.isHeapBigInt()) { + if (auto* heapBigInt = value.asHeapBigInt()) { return heapBigInt->toBigInt64(heapBigInt); } } - return _val.asAnyInt(); + if (value.isInt32()) + return value.asInt32(); + return static_cast<int64_t>(value.asDouble()); } uint8_t JSC__JSValue__asBigIntCompare(JSC__JSValue JSValue0, JSC__JSGlobalObject* globalObject, JSC__JSValue JSValue1) @@ -3086,28 +3142,28 @@ JSC__JSValue JSC__JSValue__fromUInt64NoTruncate(JSC__JSGlobalObject* globalObjec uint64_t JSC__JSValue__toUInt64NoTruncate(JSC__JSValue val) { - JSC::JSValue _val = JSC::JSValue::decode(val); - - int64_t result = JSC::tryConvertToInt52(_val.asDouble()); - if (result != JSC::JSValue::notInt52) { - if (result < 0) - return 0; + JSC::JSValue value = JSC::JSValue::decode(val); + ASSERT(value.isHeapBigInt() || value.isNumber()); - return static_cast<uint64_t>(result); - } - - if (_val.isHeapBigInt()) { - - if (auto* heapBigInt = _val.asHeapBigInt()) { + if (value.isHeapBigInt()) { + if (auto* heapBigInt = value.asHeapBigInt()) { return heapBigInt->toBigUInt64(heapBigInt); } } - if (!_val.isNumber()) { - return 0; + if (value.isInt32()) { + return static_cast<uint64_t>(value.asInt32()); } + ASSERT(value.isDouble()); - return static_cast<uint64_t>(_val.asAnyInt()); + int64_t result = JSC::tryConvertToInt52(value.asDouble()); + if (result != JSC::JSValue::notInt52) { + if (result < 0) + return 0; + + return static_cast<uint64_t>(result); + } + return 0; } JSC__JSValue JSC__JSValue__createObject2(JSC__JSGlobalObject* globalObject, const ZigString* arg1, @@ -4046,6 +4102,7 @@ enum class BuiltinNamesMap : uint8_t { method, headers, status, + statusText, url, body, data, @@ -4065,6 +4122,9 @@ static JSC::Identifier builtinNameMap(JSC::JSGlobalObject* globalObject, unsigne case BuiltinNamesMap::headers: { return clientData->builtinNames().headersPublicName(); } + case BuiltinNamesMap::statusText: { + return clientData->builtinNames().statusTextPublicName(); + } case BuiltinNamesMap::status: { return clientData->builtinNames().statusPublicName(); } @@ -4485,6 +4545,14 @@ extern "C" void JSC__JSGlobalObject__queueMicrotaskJob(JSC__JSGlobalObject* arg0 JSC::JSValue::decode(JSValue4)); } +extern "C" WebCore::AbortSignal* WebCore__AbortSignal__new(JSC__JSGlobalObject* globalObject) +{ + Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(globalObject); + auto* context = thisObject->scriptExecutionContext(); + RefPtr<WebCore::AbortSignal> abortSignal = WebCore::AbortSignal::create(context); + return abortSignal.leakRef(); +} + extern "C" JSC__JSValue WebCore__AbortSignal__create(JSC__JSGlobalObject* globalObject) { Zig::GlobalObject* thisObject = JSC::jsCast<Zig::GlobalObject*>(globalObject); @@ -4701,4 +4769,4 @@ CPP_DECL void JSC__VM__setControlFlowProfiler(JSC__VM* vm, bool isEnabled) } else { vm->disableControlFlowProfiler(); } -}
\ No newline at end of file +} diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 1a82fc5e6..98e91c1ca 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -1969,6 +1969,12 @@ pub const AbortSignal = extern opaque { return cppFn("create", .{global}); } + extern fn WebCore__AbortSignal__new(*JSGlobalObject) *AbortSignal; + pub fn new(global: *JSGlobalObject) *AbortSignal { + JSC.markBinding(@src()); + return WebCore__AbortSignal__new(global); + } + pub fn createAbortError(message: *const ZigString, code: *const ZigString, global: *JSGlobalObject) JSValue { return cppFn("createAbortError", .{ message, code, global }); } @@ -3034,7 +3040,7 @@ pub const JSValue = enum(JSValueReprInt) { zero = 0, undefined = @as(JSValueReprInt, @bitCast(@as(i64, 0xa))), null = @as(JSValueReprInt, @bitCast(@as(i64, 0x2))), - true = @as(JSValueReprInt, @bitCast(@as(i64, 0x4))), + true = FFI.TrueI64, false = @as(JSValueReprInt, @bitCast(@as(i64, 0x6))), _, @@ -3224,7 +3230,7 @@ pub const JSValue = enum(JSValueReprInt) { }; } - pub fn isObject(this: JSType) bool { + pub inline fn isObject(this: JSType) bool { // inline constexpr bool isObjectType(JSType type) { return type >= ObjectType; } return @intFromEnum(this) >= @intFromEnum(JSType.Object); } @@ -3527,7 +3533,7 @@ pub const JSValue = enum(JSValueReprInt) { } pub fn createEmptyObject(global: *JSGlobalObject, len: usize) JSValue { - std.debug.assert(len <= 64); // max inline capacity JSC allows is 64. If you run into this, just set it to 0. + std.debug.assert(len <= 63); // max inline capacity JSC allows is 63. If you run into this, just set it to 0. return cppFn("createEmptyObject", .{ global, len }); } @@ -3903,6 +3909,10 @@ pub const JSValue = enum(JSValueReprInt) { return jsNumberFromInt32(@as(i32, @intCast(i))); } + return jsNumberFromPtrSize(i); + } + + pub fn jsNumberFromPtrSize(i: usize) JSValue { return jsNumberFromDouble(@as(f64, @floatFromInt(@as(i52, @intCast(@as(u51, @truncate(i))))))); } @@ -4255,6 +4265,7 @@ pub const JSValue = enum(JSValueReprInt) { method, headers, status, + statusText, url, body, data, @@ -4924,6 +4935,34 @@ pub const JSValue = enum(JSValueReprInt) { pub inline fn deserialize(bytes: []const u8, global: *JSGlobalObject) JSValue { return Bun__JSValue__deserialize(global, bytes.ptr, @intCast(bytes.len)); } + + extern fn Bun__serializeJSValue(global: *JSC.JSGlobalObject, value: JSValue) SerializedScriptValue.External; + extern fn Bun__SerializedScriptSlice__free(*anyopaque) void; + + pub const SerializedScriptValue = struct { + data: []const u8, + handle: *anyopaque, + + const External = extern struct { + bytes: ?[*]const u8, + size: isize, + handle: ?*anyopaque, + }; + + pub inline fn deinit(self: @This()) void { + Bun__SerializedScriptSlice__free(self.handle); + } + }; + + /// Throws a JS exception and returns null if the serialization fails, otherwise returns a SerializedScriptValue. + /// Must be freed when you are done with the bytes. + pub inline fn serialize(this: JSValue, global: *JSGlobalObject) ?SerializedScriptValue { + const value = Bun__serializeJSValue(global, this); + return if (value.bytes) |bytes| + .{ .data = bytes[0..@intCast(value.size)], .handle = value.handle.? } + else + null; + } }; extern "c" fn AsyncContextFrame__withAsyncContextIfNeeded(global: *JSGlobalObject, callback: JSValue) JSValue; @@ -5492,6 +5531,7 @@ pub const URL = opaque { extern fn URL__getHref(*String) String; extern fn URL__getFileURLString(*String) String; extern fn URL__getHrefJoin(*String, *String) String; + extern fn URL__pathFromFileURL(*String) String; pub fn hrefFromString(str: bun.String) String { JSC.markBinding(@src()); @@ -5512,6 +5552,12 @@ pub const URL = opaque { return URL__getFileURLString(&input); } + pub fn pathFromFileURL(str: bun.String) String { + JSC.markBinding(@src()); + var input = str; + return URL__pathFromFileURL(&input); + } + /// This percent-encodes the URL, punycode-encodes the hostname, and returns the result /// If it fails, the tag is marked Dead pub fn hrefFromJS(value: JSValue, globalObject: *JSC.JSGlobalObject) String { @@ -5816,7 +5862,7 @@ pub fn initialize() void { \\ \\ https://github.com/oven-sh/webkit/blob/main/Source/JavaScriptCore/runtime/OptionsList.h \\ - \\Environment variables must be prefixed with "BUN_JSC_". This code runs before .env files are loaded, so those won't work here. + \\Environment variables must be prefixed with "BUN_JSC_". This code runs before .env files are loaded, so those won't work here. \\ \\Warning: options change between releases of Bun and WebKit without notice. This is not a stable API, you should not rely on it beyond debugging something, and it may be removed entirely in a future version of Bun. , diff --git a/src/bun.js/bindings/c-bindings.cpp b/src/bun.js/bindings/c-bindings.cpp index ff4c8c4e7..f53ff52cc 100644 --- a/src/bun.js/bindings/c-bindings.cpp +++ b/src/bun.js/bindings/c-bindings.cpp @@ -1,4 +1,5 @@ // when we don't want to use @cInclude, we can just stick wrapper functions here +#include "root.h" #include <sys/resource.h> #include <cstdint> #include <unistd.h> @@ -6,6 +7,32 @@ #include <sys/stat.h> #include <sys/signal.h> +#if CPU(X86_64) +#include <cstring> +#include <cpuid.h> + +extern "C" void bun_warn_avx_missing(const char* url) +{ + __builtin_cpu_init(); + if (__builtin_cpu_supports("avx")) { + return; + } + + static constexpr const char* str = "warn: CPU lacks AVX support, strange crashes may occur. Reinstall Bun or use *-baseline build:\n "; + const size_t len = strlen(str); + + char buf[512]; + strcpy(buf, str); + strcpy(buf + len, url); + strcpy(buf + len + strlen(url), "\n\0"); + write(STDERR_FILENO, buf, strlen(buf)); +} +#else +extern "C" void bun_warn_avx_missing(char* url) +{ +} +#endif + extern "C" int32_t get_process_priority(uint32_t pid) { return getpriority(PRIO_PROCESS, pid); @@ -48,4 +75,4 @@ extern "C" ssize_t bun_sysconf__SC_CLK_TCK() #else return 0; #endif -}
\ No newline at end of file +} diff --git a/src/bun.js/bindings/exports.zig b/src/bun.js/bindings/exports.zig index 18b7c8bce..617530ec6 100644 --- a/src/bun.js/bindings/exports.zig +++ b/src/bun.js/bindings/exports.zig @@ -969,7 +969,7 @@ pub const ZigConsoleClient = struct { Output.prettyFmt("<r><red>Assertion failed<r>\n", true) else "Assertion failed\n"; - console.error_writer.unbuffered_writer.writeAll(text) catch unreachable; + console.error_writer.unbuffered_writer.writeAll(text) catch {}; return; } @@ -983,28 +983,48 @@ pub const ZigConsoleClient = struct { else console.writer; var writer = buffered_writer.writer(); - const Writer = @TypeOf(writer); - if (len > 0) + + var print_length = len; + var print_options: FormatOptions = .{ + .enable_colors = enable_colors, + .add_newline = true, + .flush = true, + }; + + if (message_type == .Dir and len >= 2) { + print_length = 1; + var opts = vals[1]; + if (opts.isObject()) { + if (opts.get(global, "depth")) |depth_prop| { + if (depth_prop.isNumber()) + print_options.max_depth = depth_prop.toU16(); + if (depth_prop.isNull() or depth_prop.toInt64() == std.math.maxInt(i64)) + print_options.max_depth = std.math.maxInt(u16); + } + if (opts.get(global, "colors")) |colors_prop| { + if (colors_prop.isBoolean()) + print_options.enable_colors = colors_prop.toBoolean(); + } + } + } + + if (print_length > 0) format( level, global, vals, - len, + print_length, @TypeOf(buffered_writer.unbuffered_writer.context), Writer, writer, - .{ - .enable_colors = enable_colors, - .add_newline = true, - .flush = true, - }, + print_options, ) else if (message_type == .Log) { _ = console.writer.write("\n") catch 0; console.writer.flush() catch {}; } else if (message_type != .Trace) - writer.writeAll("undefined\n") catch unreachable; + writer.writeAll("undefined\n") catch {}; if (message_type == .Trace) { writeTrace(Writer, writer, global); @@ -1026,14 +1046,14 @@ pub const ZigConsoleClient = struct { writer, exception.stack, true, - ) catch unreachable + ) catch {} else JS.VirtualMachine.printStackTrace( Writer, writer, exception.stack, false, - ) catch unreachable; + ) catch {}; } pub const FormatOptions = struct { @@ -1042,7 +1062,7 @@ pub const ZigConsoleClient = struct { flush: bool, ordered_properties: bool = false, quote_strings: bool = false, - max_depth: u16 = 8, + max_depth: u16 = 2, }; pub fn format( @@ -1082,7 +1102,7 @@ pub const ZigConsoleClient = struct { if (tag.tag == .String) { if (options.enable_colors) { if (level == .Error) { - unbuffered_writer.writeAll(comptime Output.prettyFmt("<r><red>", true)) catch unreachable; + unbuffered_writer.writeAll(comptime Output.prettyFmt("<r><red>", true)) catch {}; } fmt.format( tag, @@ -1093,7 +1113,7 @@ pub const ZigConsoleClient = struct { true, ); if (level == .Error) { - unbuffered_writer.writeAll(comptime Output.prettyFmt("<r>", true)) catch unreachable; + unbuffered_writer.writeAll(comptime Output.prettyFmt("<r>", true)) catch {}; } } else { fmt.format( @@ -1155,7 +1175,7 @@ pub const ZigConsoleClient = struct { var any = false; if (options.enable_colors) { if (level == .Error) { - writer.writeAll(comptime Output.prettyFmt("<r><red>", true)) catch unreachable; + writer.writeAll(comptime Output.prettyFmt("<r><red>", true)) catch {}; } while (true) { if (any) { @@ -1177,7 +1197,7 @@ pub const ZigConsoleClient = struct { fmt.remaining_values = fmt.remaining_values[1..]; } if (level == .Error) { - writer.writeAll(comptime Output.prettyFmt("<r>", true)) catch unreachable; + writer.writeAll(comptime Output.prettyFmt("<r>", true)) catch {}; } } else { while (true) { @@ -2119,7 +2139,7 @@ pub const ZigConsoleClient = struct { this.globalThis, this.custom_formatted_object.function, this.custom_formatted_object.this, - this.max_depth - this.depth, + this.max_depth -| this.depth, this.max_depth, enable_ansi_colors, ); @@ -2158,7 +2178,7 @@ pub const ZigConsoleClient = struct { this.addForNewLine(printable.len); if (printable.len == 0) { - writer.print(comptime Output.prettyFmt("<cyan>[class]<r>", enable_ansi_colors), .{}); + writer.print(comptime Output.prettyFmt("<cyan>[class (anonymous)]<r>", enable_ansi_colors), .{}); } else { writer.print(comptime Output.prettyFmt("<cyan>[class {}]<r>", enable_ansi_colors), .{printable}); } diff --git a/src/bun.js/bindings/generated_classes.zig b/src/bun.js/bindings/generated_classes.zig index 329506718..c4f63084b 100644 --- a/src/bun.js/bindings/generated_classes.zig +++ b/src/bun.js/bindings/generated_classes.zig @@ -1220,6 +1220,28 @@ pub const JSDebugHTTPSServer = struct { return DebugHTTPSServer__fromJS(value); } + extern fn DebugHTTPSServerPrototype__addressSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void; + + extern fn DebugHTTPSServerPrototype__addressGetCachedValue(JSC.JSValue) JSC.JSValue; + + /// `DebugHTTPSServer.address` setter + /// This value will be visited by the garbage collector. + pub fn addressSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void { + JSC.markBinding(@src()); + DebugHTTPSServerPrototype__addressSetCachedValue(thisValue, globalObject, value); + } + + /// `DebugHTTPSServer.address` getter + /// This value will be visited by the garbage collector. + pub fn addressGetCached(thisValue: JSC.JSValue) ?JSC.JSValue { + JSC.markBinding(@src()); + const result = DebugHTTPSServerPrototype__addressGetCachedValue(thisValue); + if (result == .zero) + return null; + + return result; + } + extern fn DebugHTTPSServerPrototype__hostnameSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void; extern fn DebugHTTPSServerPrototype__hostnameGetCachedValue(JSC.JSValue) JSC.JSValue; @@ -1300,6 +1322,9 @@ pub const JSDebugHTTPSServer = struct { @compileLog("DebugHTTPSServer.finalize is not a finalizer"); } + if (@TypeOf(DebugHTTPSServer.getAddress) != GetterType) + @compileLog("Expected DebugHTTPSServer.getAddress to be a getter"); + if (@TypeOf(DebugHTTPSServer.getDevelopment) != GetterType) @compileLog("Expected DebugHTTPSServer.getDevelopment to be a getter"); @@ -1327,6 +1352,8 @@ pub const JSDebugHTTPSServer = struct { @compileLog("Expected DebugHTTPSServer.doPublish to be a callback but received " ++ @typeName(@TypeOf(DebugHTTPSServer.doPublish))); if (@TypeOf(DebugHTTPSServer.doReload) != CallbackType) @compileLog("Expected DebugHTTPSServer.doReload to be a callback but received " ++ @typeName(@TypeOf(DebugHTTPSServer.doReload))); + if (@TypeOf(DebugHTTPSServer.doRequestIP) != CallbackType) + @compileLog("Expected DebugHTTPSServer.doRequestIP to be a callback but received " ++ @typeName(@TypeOf(DebugHTTPSServer.doRequestIP))); if (@TypeOf(DebugHTTPSServer.doStop) != CallbackType) @compileLog("Expected DebugHTTPSServer.doStop to be a callback but received " ++ @typeName(@TypeOf(DebugHTTPSServer.doStop))); if (@TypeOf(DebugHTTPSServer.doUpgrade) != CallbackType) @@ -1335,9 +1362,11 @@ pub const JSDebugHTTPSServer = struct { @export(DebugHTTPSServer.doFetch, .{ .name = "DebugHTTPSServerPrototype__doFetch" }); @export(DebugHTTPSServer.doPublish, .{ .name = "DebugHTTPSServerPrototype__doPublish" }); @export(DebugHTTPSServer.doReload, .{ .name = "DebugHTTPSServerPrototype__doReload" }); + @export(DebugHTTPSServer.doRequestIP, .{ .name = "DebugHTTPSServerPrototype__doRequestIP" }); @export(DebugHTTPSServer.doStop, .{ .name = "DebugHTTPSServerPrototype__doStop" }); @export(DebugHTTPSServer.doUpgrade, .{ .name = "DebugHTTPSServerPrototype__doUpgrade" }); @export(DebugHTTPSServer.finalize, .{ .name = "DebugHTTPSServerClass__finalize" }); + @export(DebugHTTPSServer.getAddress, .{ .name = "DebugHTTPSServerPrototype__getAddress" }); @export(DebugHTTPSServer.getDevelopment, .{ .name = "DebugHTTPSServerPrototype__getDevelopment" }); @export(DebugHTTPSServer.getHostname, .{ .name = "DebugHTTPSServerPrototype__getHostname" }); @export(DebugHTTPSServer.getId, .{ .name = "DebugHTTPSServerPrototype__getId" }); @@ -1363,6 +1392,28 @@ pub const JSDebugHTTPServer = struct { return DebugHTTPServer__fromJS(value); } + extern fn DebugHTTPServerPrototype__addressSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void; + + extern fn DebugHTTPServerPrototype__addressGetCachedValue(JSC.JSValue) JSC.JSValue; + + /// `DebugHTTPServer.address` setter + /// This value will be visited by the garbage collector. + pub fn addressSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void { + JSC.markBinding(@src()); + DebugHTTPServerPrototype__addressSetCachedValue(thisValue, globalObject, value); + } + + /// `DebugHTTPServer.address` getter + /// This value will be visited by the garbage collector. + pub fn addressGetCached(thisValue: JSC.JSValue) ?JSC.JSValue { + JSC.markBinding(@src()); + const result = DebugHTTPServerPrototype__addressGetCachedValue(thisValue); + if (result == .zero) + return null; + + return result; + } + extern fn DebugHTTPServerPrototype__hostnameSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void; extern fn DebugHTTPServerPrototype__hostnameGetCachedValue(JSC.JSValue) JSC.JSValue; @@ -1443,6 +1494,9 @@ pub const JSDebugHTTPServer = struct { @compileLog("DebugHTTPServer.finalize is not a finalizer"); } + if (@TypeOf(DebugHTTPServer.getAddress) != GetterType) + @compileLog("Expected DebugHTTPServer.getAddress to be a getter"); + if (@TypeOf(DebugHTTPServer.getDevelopment) != GetterType) @compileLog("Expected DebugHTTPServer.getDevelopment to be a getter"); @@ -1470,6 +1524,8 @@ pub const JSDebugHTTPServer = struct { @compileLog("Expected DebugHTTPServer.doPublish to be a callback but received " ++ @typeName(@TypeOf(DebugHTTPServer.doPublish))); if (@TypeOf(DebugHTTPServer.doReload) != CallbackType) @compileLog("Expected DebugHTTPServer.doReload to be a callback but received " ++ @typeName(@TypeOf(DebugHTTPServer.doReload))); + if (@TypeOf(DebugHTTPServer.doRequestIP) != CallbackType) + @compileLog("Expected DebugHTTPServer.doRequestIP to be a callback but received " ++ @typeName(@TypeOf(DebugHTTPServer.doRequestIP))); if (@TypeOf(DebugHTTPServer.doStop) != CallbackType) @compileLog("Expected DebugHTTPServer.doStop to be a callback but received " ++ @typeName(@TypeOf(DebugHTTPServer.doStop))); if (@TypeOf(DebugHTTPServer.doUpgrade) != CallbackType) @@ -1478,9 +1534,11 @@ pub const JSDebugHTTPServer = struct { @export(DebugHTTPServer.doFetch, .{ .name = "DebugHTTPServerPrototype__doFetch" }); @export(DebugHTTPServer.doPublish, .{ .name = "DebugHTTPServerPrototype__doPublish" }); @export(DebugHTTPServer.doReload, .{ .name = "DebugHTTPServerPrototype__doReload" }); + @export(DebugHTTPServer.doRequestIP, .{ .name = "DebugHTTPServerPrototype__doRequestIP" }); @export(DebugHTTPServer.doStop, .{ .name = "DebugHTTPServerPrototype__doStop" }); @export(DebugHTTPServer.doUpgrade, .{ .name = "DebugHTTPServerPrototype__doUpgrade" }); @export(DebugHTTPServer.finalize, .{ .name = "DebugHTTPServerClass__finalize" }); + @export(DebugHTTPServer.getAddress, .{ .name = "DebugHTTPServerPrototype__getAddress" }); @export(DebugHTTPServer.getDevelopment, .{ .name = "DebugHTTPServerPrototype__getDevelopment" }); @export(DebugHTTPServer.getHostname, .{ .name = "DebugHTTPServerPrototype__getHostname" }); @export(DebugHTTPServer.getId, .{ .name = "DebugHTTPServerPrototype__getId" }); @@ -2205,6 +2263,8 @@ pub const JSExpect = struct { @compileLog("Expected Expect.toEndWith to be a callback but received " ++ @typeName(@TypeOf(Expect.toEndWith))); if (@TypeOf(Expect.toEqual) != CallbackType) @compileLog("Expected Expect.toEqual to be a callback but received " ++ @typeName(@TypeOf(Expect.toEqual))); + if (@TypeOf(Expect.toEqualIgnoringWhitespace) != CallbackType) + @compileLog("Expected Expect.toEqualIgnoringWhitespace to be a callback but received " ++ @typeName(@TypeOf(Expect.toEqualIgnoringWhitespace))); if (@TypeOf(Expect.toHaveBeenCalled) != CallbackType) @compileLog("Expected Expect.toHaveBeenCalled to be a callback but received " ++ @typeName(@TypeOf(Expect.toHaveBeenCalled))); if (@TypeOf(Expect.toHaveBeenCalledTimes) != CallbackType) @@ -2341,6 +2401,7 @@ pub const JSExpect = struct { @export(Expect.toContainEqual, .{ .name = "ExpectPrototype__toContainEqual" }); @export(Expect.toEndWith, .{ .name = "ExpectPrototype__toEndWith" }); @export(Expect.toEqual, .{ .name = "ExpectPrototype__toEqual" }); + @export(Expect.toEqualIgnoringWhitespace, .{ .name = "ExpectPrototype__toEqualIgnoringWhitespace" }); @export(Expect.toHaveBeenCalled, .{ .name = "ExpectPrototype__toHaveBeenCalled" }); @export(Expect.toHaveBeenCalledTimes, .{ .name = "ExpectPrototype__toHaveBeenCalledTimes" }); @export(Expect.toHaveBeenCalledWith, .{ .name = "ExpectPrototype__toHaveBeenCalledWith" }); @@ -2507,6 +2568,87 @@ pub const JSExpectAnything = struct { } } }; +pub const JSExpectArrayContaining = struct { + const ExpectArrayContaining = Classes.ExpectArrayContaining; + const GetterType = fn (*ExpectArrayContaining, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue; + const GetterTypeWithThisValue = fn (*ExpectArrayContaining, JSC.JSValue, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue; + const SetterType = fn (*ExpectArrayContaining, *JSC.JSGlobalObject, JSC.JSValue) callconv(.C) bool; + const SetterTypeWithThisValue = fn (*ExpectArrayContaining, JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) callconv(.C) bool; + const CallbackType = fn (*ExpectArrayContaining, *JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) JSC.JSValue; + + /// Return the pointer to the wrapped object. + /// If the object does not match the type, return null. + pub fn fromJS(value: JSC.JSValue) ?*ExpectArrayContaining { + JSC.markBinding(@src()); + return ExpectArrayContaining__fromJS(value); + } + + extern fn ExpectArrayContainingPrototype__arrayValueSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void; + + extern fn ExpectArrayContainingPrototype__arrayValueGetCachedValue(JSC.JSValue) JSC.JSValue; + + /// `ExpectArrayContaining.arrayValue` setter + /// This value will be visited by the garbage collector. + pub fn arrayValueSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void { + JSC.markBinding(@src()); + ExpectArrayContainingPrototype__arrayValueSetCachedValue(thisValue, globalObject, value); + } + + /// `ExpectArrayContaining.arrayValue` getter + /// This value will be visited by the garbage collector. + pub fn arrayValueGetCached(thisValue: JSC.JSValue) ?JSC.JSValue { + JSC.markBinding(@src()); + const result = ExpectArrayContainingPrototype__arrayValueGetCachedValue(thisValue); + if (result == .zero) + return null; + + return result; + } + + /// Create a new instance of ExpectArrayContaining + pub fn toJS(this: *ExpectArrayContaining, globalObject: *JSC.JSGlobalObject) JSC.JSValue { + JSC.markBinding(@src()); + if (comptime Environment.allow_assert) { + const value__ = ExpectArrayContaining__create(globalObject, this); + std.debug.assert(value__.as(ExpectArrayContaining).? == this); // If this fails, likely a C ABI issue. + return value__; + } else { + return ExpectArrayContaining__create(globalObject, this); + } + } + + /// Modify the internal ptr to point to a new instance of ExpectArrayContaining. + pub fn dangerouslySetPtr(value: JSC.JSValue, ptr: ?*ExpectArrayContaining) bool { + JSC.markBinding(@src()); + return ExpectArrayContaining__dangerouslySetPtr(value, ptr); + } + + /// Detach the ptr from the thisValue + pub fn detachPtr(_: *ExpectArrayContaining, value: JSC.JSValue) void { + JSC.markBinding(@src()); + std.debug.assert(ExpectArrayContaining__dangerouslySetPtr(value, null)); + } + + extern fn ExpectArrayContaining__fromJS(JSC.JSValue) ?*ExpectArrayContaining; + extern fn ExpectArrayContaining__getConstructor(*JSC.JSGlobalObject) JSC.JSValue; + + extern fn ExpectArrayContaining__create(globalObject: *JSC.JSGlobalObject, ptr: ?*ExpectArrayContaining) JSC.JSValue; + + extern fn ExpectArrayContaining__dangerouslySetPtr(JSC.JSValue, ?*ExpectArrayContaining) bool; + + comptime { + if (@TypeOf(ExpectArrayContaining.finalize) != (fn (*ExpectArrayContaining) callconv(.C) void)) { + @compileLog("ExpectArrayContaining.finalize is not a finalizer"); + } + + if (@TypeOf(ExpectArrayContaining.call) != StaticCallbackType) + @compileLog("Expected ExpectArrayContaining.call to be a static callback"); + if (!JSC.is_bindgen) { + @export(ExpectArrayContaining.call, .{ .name = "ExpectArrayContainingClass__call" }); + @export(ExpectArrayContaining.finalize, .{ .name = "ExpectArrayContainingClass__finalize" }); + } + } +}; pub const JSExpectStringContaining = struct { const ExpectStringContaining = Classes.ExpectStringContaining; const GetterType = fn (*ExpectStringContaining, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue; @@ -3089,6 +3231,28 @@ pub const JSHTTPSServer = struct { return HTTPSServer__fromJS(value); } + extern fn HTTPSServerPrototype__addressSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void; + + extern fn HTTPSServerPrototype__addressGetCachedValue(JSC.JSValue) JSC.JSValue; + + /// `HTTPSServer.address` setter + /// This value will be visited by the garbage collector. + pub fn addressSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void { + JSC.markBinding(@src()); + HTTPSServerPrototype__addressSetCachedValue(thisValue, globalObject, value); + } + + /// `HTTPSServer.address` getter + /// This value will be visited by the garbage collector. + pub fn addressGetCached(thisValue: JSC.JSValue) ?JSC.JSValue { + JSC.markBinding(@src()); + const result = HTTPSServerPrototype__addressGetCachedValue(thisValue); + if (result == .zero) + return null; + + return result; + } + extern fn HTTPSServerPrototype__hostnameSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void; extern fn HTTPSServerPrototype__hostnameGetCachedValue(JSC.JSValue) JSC.JSValue; @@ -3169,6 +3333,9 @@ pub const JSHTTPSServer = struct { @compileLog("HTTPSServer.finalize is not a finalizer"); } + if (@TypeOf(HTTPSServer.getAddress) != GetterType) + @compileLog("Expected HTTPSServer.getAddress to be a getter"); + if (@TypeOf(HTTPSServer.getDevelopment) != GetterType) @compileLog("Expected HTTPSServer.getDevelopment to be a getter"); @@ -3196,6 +3363,8 @@ pub const JSHTTPSServer = struct { @compileLog("Expected HTTPSServer.doPublish to be a callback but received " ++ @typeName(@TypeOf(HTTPSServer.doPublish))); if (@TypeOf(HTTPSServer.doReload) != CallbackType) @compileLog("Expected HTTPSServer.doReload to be a callback but received " ++ @typeName(@TypeOf(HTTPSServer.doReload))); + if (@TypeOf(HTTPSServer.doRequestIP) != CallbackType) + @compileLog("Expected HTTPSServer.doRequestIP to be a callback but received " ++ @typeName(@TypeOf(HTTPSServer.doRequestIP))); if (@TypeOf(HTTPSServer.doStop) != CallbackType) @compileLog("Expected HTTPSServer.doStop to be a callback but received " ++ @typeName(@TypeOf(HTTPSServer.doStop))); if (@TypeOf(HTTPSServer.doUpgrade) != CallbackType) @@ -3204,9 +3373,11 @@ pub const JSHTTPSServer = struct { @export(HTTPSServer.doFetch, .{ .name = "HTTPSServerPrototype__doFetch" }); @export(HTTPSServer.doPublish, .{ .name = "HTTPSServerPrototype__doPublish" }); @export(HTTPSServer.doReload, .{ .name = "HTTPSServerPrototype__doReload" }); + @export(HTTPSServer.doRequestIP, .{ .name = "HTTPSServerPrototype__doRequestIP" }); @export(HTTPSServer.doStop, .{ .name = "HTTPSServerPrototype__doStop" }); @export(HTTPSServer.doUpgrade, .{ .name = "HTTPSServerPrototype__doUpgrade" }); @export(HTTPSServer.finalize, .{ .name = "HTTPSServerClass__finalize" }); + @export(HTTPSServer.getAddress, .{ .name = "HTTPSServerPrototype__getAddress" }); @export(HTTPSServer.getDevelopment, .{ .name = "HTTPSServerPrototype__getDevelopment" }); @export(HTTPSServer.getHostname, .{ .name = "HTTPSServerPrototype__getHostname" }); @export(HTTPSServer.getId, .{ .name = "HTTPSServerPrototype__getId" }); @@ -3232,6 +3403,28 @@ pub const JSHTTPServer = struct { return HTTPServer__fromJS(value); } + extern fn HTTPServerPrototype__addressSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void; + + extern fn HTTPServerPrototype__addressGetCachedValue(JSC.JSValue) JSC.JSValue; + + /// `HTTPServer.address` setter + /// This value will be visited by the garbage collector. + pub fn addressSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void { + JSC.markBinding(@src()); + HTTPServerPrototype__addressSetCachedValue(thisValue, globalObject, value); + } + + /// `HTTPServer.address` getter + /// This value will be visited by the garbage collector. + pub fn addressGetCached(thisValue: JSC.JSValue) ?JSC.JSValue { + JSC.markBinding(@src()); + const result = HTTPServerPrototype__addressGetCachedValue(thisValue); + if (result == .zero) + return null; + + return result; + } + extern fn HTTPServerPrototype__hostnameSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void; extern fn HTTPServerPrototype__hostnameGetCachedValue(JSC.JSValue) JSC.JSValue; @@ -3312,6 +3505,9 @@ pub const JSHTTPServer = struct { @compileLog("HTTPServer.finalize is not a finalizer"); } + if (@TypeOf(HTTPServer.getAddress) != GetterType) + @compileLog("Expected HTTPServer.getAddress to be a getter"); + if (@TypeOf(HTTPServer.getDevelopment) != GetterType) @compileLog("Expected HTTPServer.getDevelopment to be a getter"); @@ -3339,6 +3535,8 @@ pub const JSHTTPServer = struct { @compileLog("Expected HTTPServer.doPublish to be a callback but received " ++ @typeName(@TypeOf(HTTPServer.doPublish))); if (@TypeOf(HTTPServer.doReload) != CallbackType) @compileLog("Expected HTTPServer.doReload to be a callback but received " ++ @typeName(@TypeOf(HTTPServer.doReload))); + if (@TypeOf(HTTPServer.doRequestIP) != CallbackType) + @compileLog("Expected HTTPServer.doRequestIP to be a callback but received " ++ @typeName(@TypeOf(HTTPServer.doRequestIP))); if (@TypeOf(HTTPServer.doStop) != CallbackType) @compileLog("Expected HTTPServer.doStop to be a callback but received " ++ @typeName(@TypeOf(HTTPServer.doStop))); if (@TypeOf(HTTPServer.doUpgrade) != CallbackType) @@ -3347,9 +3545,11 @@ pub const JSHTTPServer = struct { @export(HTTPServer.doFetch, .{ .name = "HTTPServerPrototype__doFetch" }); @export(HTTPServer.doPublish, .{ .name = "HTTPServerPrototype__doPublish" }); @export(HTTPServer.doReload, .{ .name = "HTTPServerPrototype__doReload" }); + @export(HTTPServer.doRequestIP, .{ .name = "HTTPServerPrototype__doRequestIP" }); @export(HTTPServer.doStop, .{ .name = "HTTPServerPrototype__doStop" }); @export(HTTPServer.doUpgrade, .{ .name = "HTTPServerPrototype__doUpgrade" }); @export(HTTPServer.finalize, .{ .name = "HTTPServerClass__finalize" }); + @export(HTTPServer.getAddress, .{ .name = "HTTPServerPrototype__getAddress" }); @export(HTTPServer.getDevelopment, .{ .name = "HTTPServerPrototype__getDevelopment" }); @export(HTTPServer.getHostname, .{ .name = "HTTPServerPrototype__getHostname" }); @export(HTTPServer.getId, .{ .name = "HTTPServerPrototype__getId" }); @@ -6781,6 +6981,9 @@ pub const JSTextDecoder = struct { if (@TypeOf(TextDecoder.getFatal) != GetterType) @compileLog("Expected TextDecoder.getFatal to be a getter"); + if (@TypeOf(TextDecoder.getIgnoreBOM) != GetterType) + @compileLog("Expected TextDecoder.getIgnoreBOM to be a getter"); + if (!JSC.is_bindgen) { @export(TextDecoder.constructor, .{ .name = "TextDecoderClass__construct" }); @export(TextDecoder.decode, .{ .name = "TextDecoderPrototype__decode" }); @@ -6788,6 +6991,7 @@ pub const JSTextDecoder = struct { @export(TextDecoder.finalize, .{ .name = "TextDecoderClass__finalize" }); @export(TextDecoder.getEncoding, .{ .name = "TextDecoderPrototype__getEncoding" }); @export(TextDecoder.getFatal, .{ .name = "TextDecoderPrototype__getFatal" }); + @export(TextDecoder.getIgnoreBOM, .{ .name = "TextDecoderPrototype__getIgnoreBOM" }); } } }; @@ -7006,6 +7210,7 @@ comptime { _ = JSExpect; _ = JSExpectAny; _ = JSExpectAnything; + _ = JSExpectArrayContaining; _ = JSExpectStringContaining; _ = JSExpectStringMatching; _ = JSFFI; diff --git a/src/bun.js/bindings/generated_classes_list.zig b/src/bun.js/bindings/generated_classes_list.zig index a86f74dd3..3b45f33b8 100644 --- a/src/bun.js/bindings/generated_classes_list.zig +++ b/src/bun.js/bindings/generated_classes_list.zig @@ -17,6 +17,7 @@ pub const Classes = struct { pub const ExpectAnything = JSC.Expect.ExpectAnything; pub const ExpectStringContaining = JSC.Expect.ExpectStringContaining; pub const ExpectStringMatching = JSC.Expect.ExpectStringMatching; + pub const ExpectArrayContaining = JSC.Expect.ExpectArrayContaining; pub const FileSystemRouter = JSC.API.FileSystemRouter; pub const Bundler = JSC.API.JSBundler; pub const JSBundler = Bundler; diff --git a/src/bun.js/bindings/headers-handwritten.h b/src/bun.js/bindings/headers-handwritten.h index e19be7abe..d8cfa58ef 100644 --- a/src/bun.js/bindings/headers-handwritten.h +++ b/src/bun.js/bindings/headers-handwritten.h @@ -17,10 +17,6 @@ typedef union BunStringImpl { void* wtf; } BunStringImpl; -typedef struct BunString { - BunStringTag tag; - BunStringImpl impl; -} BunString; #else typedef union BunStringImpl { ZigString zig; @@ -34,13 +30,15 @@ enum class BunStringTag : uint8_t { StaticZigString = 3, Empty = 4, }; +#endif typedef struct BunString { BunStringTag tag; BunStringImpl impl; -} BunString; -#endif + inline void ref(); + inline void deref(); +} BunString; typedef struct ZigErrorType { ZigErrorCode code; @@ -241,6 +239,7 @@ extern "C" void BunString__toWTFString(BunString*); namespace Bun { JSC::JSValue toJS(JSC::JSGlobalObject*, BunString); BunString toString(JSC::JSGlobalObject* globalObject, JSC::JSValue value); +BunString toString(const char* bytes, size_t length); WTF::String toWTFString(const BunString& bunString); BunString toString(WTF::String& wtfString); BunString toString(const WTF::String& wtfString); @@ -348,3 +347,16 @@ class ScriptArguments; using ScriptArguments = Inspector::ScriptArguments; #endif + +ALWAYS_INLINE void BunString::ref() +{ + if (this->tag == BunStringTag::WTFStringImpl) { + this->impl.wtf->ref(); + } +} +ALWAYS_INLINE void BunString::deref() +{ + if (this->tag == BunStringTag::WTFStringImpl) { + this->impl.wtf->deref(); + } +}
\ No newline at end of file diff --git a/src/bun.js/bindings/isBuiltinModule.cpp b/src/bun.js/bindings/isBuiltinModule.cpp new file mode 100644 index 000000000..b8e69f479 --- /dev/null +++ b/src/bun.js/bindings/isBuiltinModule.cpp @@ -0,0 +1,98 @@ +#include "root.h" + +static constexpr ASCIILiteral builtinModuleNamesSortedLength[] = { + "fs"_s, + "os"_s, + "v8"_s, + "vm"_s, + "ws"_s, + "bun"_s, + "dns"_s, + "net"_s, + "sys"_s, + "tls"_s, + "tty"_s, + "url"_s, + "http"_s, + "path"_s, + "repl"_s, + "util"_s, + "wasi"_s, + "zlib"_s, + "dgram"_s, + "http2"_s, + "https"_s, + "assert"_s, + "buffer"_s, + "crypto"_s, + "domain"_s, + "events"_s, + "module"_s, + "stream"_s, + "timers"_s, + "undici"_s, + "bun:ffi"_s, + "bun:jsc"_s, + "cluster"_s, + "console"_s, + "process"_s, + "bun:wrap"_s, + "punycode"_s, + "bun:test"_s, + "bun:main"_s, + "readline"_s, + "_tls_wrap"_s, + "constants"_s, + "inspector"_s, + "bun:sqlite"_s, + "path/posix"_s, + "path/win32"_s, + "perf_hooks"_s, + "stream/web"_s, + "util/types"_s, + "_http_agent"_s, + "_tls_common"_s, + "async_hooks"_s, + "detect-libc"_s, + "fs/promises"_s, + "querystring"_s, + "_http_client"_s, + "_http_common"_s, + "_http_server"_s, + "_stream_wrap"_s, + "dns/promises"_s, + "trace_events"_s, + "assert/strict"_s, + "child_process"_s, + "_http_incoming"_s, + "_http_outgoing"_s, + "_stream_duplex"_s, + "string_decoder"_s, + "worker_threads"_s, + "stream/promises"_s, + "timers/promises"_s, + "_stream_readable"_s, + "_stream_writable"_s, + "stream/consumers"_s, + "_stream_transform"_s, + "readline/promises"_s, + "inspector/promises"_s, + "_stream_passthrough"_s, + "diagnostics_channel"_s, +}; + +namespace Bun { + +bool isBuiltinModule(const String &namePossiblyWithNodePrefix) { + String name = namePossiblyWithNodePrefix; + if (name.startsWith("node:"_s)) + name = name.substringSharingImpl(5); + + for (auto &builtinModule : builtinModuleNamesSortedLength) { + if (name == builtinModule) + return true; + } + return false; +} + +} // namespace Bun
\ No newline at end of file diff --git a/src/bun.js/bindings/isBuiltinModule.h b/src/bun.js/bindings/isBuiltinModule.h new file mode 100644 index 000000000..d66f025d1 --- /dev/null +++ b/src/bun.js/bindings/isBuiltinModule.h @@ -0,0 +1,5 @@ +#pragma once + +namespace Bun { +bool isBuiltinModule(const String &namePossiblyWithNodePrefix); +} // namespace Bun
\ No newline at end of file diff --git a/src/bun.js/bindings/napi.cpp b/src/bun.js/bindings/napi.cpp index 72ca50dcb..005a753d0 100644 --- a/src/bun.js/bindings/napi.cpp +++ b/src/bun.js/bindings/napi.cpp @@ -83,7 +83,7 @@ JSC::SourceCode generateSourceCode(WTF::String keyString, JSC::VM& vm, JSC::JSOb sourceCodeBuilder.append(";\n"_s); } globalObject->putDirect(vm, ident, object, JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::DontEnum); - return JSC::makeSource(sourceCodeBuilder.toString(), JSC::SourceOrigin(), keyString, WTF::TextPosition(), JSC::SourceProviderSourceType::Module); + return JSC::makeSource(sourceCodeBuilder.toString(), JSC::SourceOrigin(), JSC::SourceTaintedOrigin::Untainted, keyString, WTF::TextPosition(), JSC::SourceProviderSourceType::Module); } } @@ -200,10 +200,6 @@ static uint32_t getPropertyAttributes(napi_property_descriptor prop) // result |= JSC::PropertyAttribute::ReadOnly; // } - if (prop.method) { - result |= JSC::PropertyAttribute::Function; - } - return result; } @@ -257,7 +253,7 @@ static void defineNapiProperty(Zig::GlobalObject* globalObject, JSC::JSObject* t value = JSC::JSValue(function); // } - to->putDirect(vm, propertyName, value, getPropertyAttributes(property) | JSC::PropertyAttribute::Function); + to->putDirect(vm, propertyName, value, getPropertyAttributes(property)); return; } @@ -317,6 +313,10 @@ static void defineNapiProperty(Zig::GlobalObject* globalObject, JSC::JSObject* t extern "C" napi_status napi_set_property(napi_env env, napi_value target, napi_value key, napi_value value) { + if (UNLIKELY(!env || !target || !key)) { + return napi_invalid_arg; + } + auto globalObject = toJS(env); auto& vm = globalObject->vm(); auto* object = toJS(target).getObject(); @@ -327,7 +327,8 @@ extern "C" napi_status napi_set_property(napi_env env, napi_value target, auto keyProp = toJS(key); auto scope = DECLARE_CATCH_SCOPE(vm); - object->putDirect(globalObject->vm(), keyProp.toPropertyKey(globalObject), toJS(value)); + PutPropertySlot slot(object, true); + object->put(object, globalObject, keyProp.toPropertyKey(globalObject), toJS(value), slot); RETURN_IF_EXCEPTION(scope, napi_generic_failure); scope.clearException(); @@ -336,6 +337,10 @@ extern "C" napi_status napi_set_property(napi_env env, napi_value target, extern "C" napi_status napi_has_property(napi_env env, napi_value object, napi_value key, bool* result) { + if (UNLIKELY(!object || !env)) { + return napi_invalid_arg; + } + auto globalObject = toJS(env); auto& vm = globalObject->vm(); auto* target = toJS(object).getObject(); @@ -345,8 +350,7 @@ extern "C" napi_status napi_has_property(napi_env env, napi_value object, auto keyProp = toJS(key); auto scope = DECLARE_CATCH_SCOPE(vm); - // TODO: use the slot directly? - *result = !!target->getIfPropertyExists(globalObject, keyProp.toPropertyKey(globalObject)); + *result = target->hasProperty(globalObject, keyProp.toPropertyKey(globalObject)); RETURN_IF_EXCEPTION(scope, napi_generic_failure); scope.clearException(); @@ -495,6 +499,81 @@ extern "C" napi_status napi_get_named_property(napi_env env, napi_value object, return napi_ok; } +#if !COMPILER(MSVC) +__attribute__((visibility("default"))) +#endif +extern "C" napi_status +node_api_create_external_string_latin1(napi_env env, + char* str, + size_t length, + napi_finalize finalize_callback, + void* finalize_hint, + napi_value* result, + bool* copied) +{ + // https://nodejs.org/api/n-api.html#node_api_create_external_string_latin1 + if (UNLIKELY(!str || !result)) { + return napi_invalid_arg; + } + + length = length == NAPI_AUTO_LENGTH ? strlen(str) : length; + WTF::ExternalStringImpl& impl = WTF::ExternalStringImpl::create(reinterpret_cast<LChar*>(str), static_cast<unsigned int>(length), finalize_hint, [finalize_callback](void* hint, void* str, unsigned length) { + if (finalize_callback) { + finalize_callback(reinterpret_cast<napi_env>(Bun__getDefaultGlobal()), nullptr, hint); + } + }); + JSGlobalObject* globalObject = toJS(env); + // globalObject is allowed to be null here + if (UNLIKELY(!globalObject)) { + globalObject = Bun__getDefaultGlobal(); + } + + JSString* out = JSC::jsString(globalObject->vm(), WTF::String(impl)); + ensureStillAliveHere(out); + *result = toNapi(out); + ensureStillAliveHere(out); + + return napi_ok; +} + +#if !COMPILER(MSVC) +__attribute__((visibility("default"))) +#endif + +extern "C" napi_status +node_api_create_external_string_utf16(napi_env env, + char16_t* str, + size_t length, + napi_finalize finalize_callback, + void* finalize_hint, + napi_value* result, + bool* copied) +{ + // https://nodejs.org/api/n-api.html#node_api_create_external_string_utf16 + if (UNLIKELY(!str || !result)) { + return napi_invalid_arg; + } + + length = length == NAPI_AUTO_LENGTH ? std::char_traits<char16_t>::length(str) : length; + WTF::ExternalStringImpl& impl = WTF::ExternalStringImpl::create(reinterpret_cast<UChar*>(str), static_cast<unsigned int>(length), finalize_hint, [finalize_callback](void* hint, void* str, unsigned length) { + if (finalize_callback) { + finalize_callback(reinterpret_cast<napi_env>(Bun__getDefaultGlobal()), nullptr, hint); + } + }); + JSGlobalObject* globalObject = toJS(env); + // globalObject is allowed to be null here + if (UNLIKELY(!globalObject)) { + globalObject = Bun__getDefaultGlobal(); + } + + JSString* out = JSC::jsString(globalObject->vm(), WTF::String(impl)); + ensureStillAliveHere(out); + *result = toNapi(out); + ensureStillAliveHere(out); + + return napi_ok; +} + extern "C" void napi_module_register(napi_module* mod) { auto* globalObject = Bun__getDefaultGlobal(); @@ -1028,7 +1107,7 @@ extern "C" napi_status napi_fatal_exception(napi_env env, napi_value err) { auto globalObject = toJS(env); - JSC::JSValue value = JSC::JSValue::decode(reinterpret_cast<JSC::EncodedJSValue>(err)); + JSC::JSValue value = toJS(err); JSC::JSObject* obj = value.getObject(); if (UNLIKELY(obj == nullptr || !obj->isErrorInstance())) { return napi_invalid_arg; @@ -1045,7 +1124,7 @@ extern "C" napi_status napi_throw(napi_env env, napi_value error) JSC::VM& vm = globalObject->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); - JSC::JSValue value = JSC::JSValue::decode(reinterpret_cast<JSC::EncodedJSValue>(error)); + JSC::JSValue value = toJS(error); if (value) { JSC::throwException(globalObject, throwScope, value); } else { @@ -1131,8 +1210,8 @@ extern "C" napi_status napi_create_type_error(napi_env env, napi_value code, Zig::GlobalObject* globalObject = toJS(env); JSC::VM& vm = globalObject->vm(); - JSC::JSValue codeValue = JSC::JSValue::decode(reinterpret_cast<JSC::EncodedJSValue>(code)); - JSC::JSValue messageValue = JSC::JSValue::decode(reinterpret_cast<JSC::EncodedJSValue>(msg)); + JSC::JSValue codeValue = toJS(code); + JSC::JSValue messageValue = toJS(msg); auto error = JSC::createTypeError(globalObject, messageValue.toWTFString(globalObject)); if (codeValue) { @@ -1150,10 +1229,11 @@ extern "C" napi_status napi_create_error(napi_env env, napi_value code, Zig::GlobalObject* globalObject = toJS(env); JSC::VM& vm = globalObject->vm(); - JSC::JSValue codeValue = JSC::JSValue::decode(reinterpret_cast<JSC::EncodedJSValue>(code)); - JSC::JSValue messageValue = JSC::JSValue::decode(reinterpret_cast<JSC::EncodedJSValue>(msg)); + JSC::JSValue codeValue = toJS(code); + JSC::JSValue messageValue = toJS(msg); - auto error = JSC::createError(globalObject, messageValue.toWTFString(globalObject)); + WTF::String message = messageValue.toWTFString(globalObject); + auto* error = JSC::createError(globalObject, message); if (codeValue) { error->putDirect(vm, WebCore::builtinNames(vm).codePublicName(), codeValue, 0); } @@ -1557,15 +1637,15 @@ extern "C" napi_status napi_define_class(napi_env env, extern "C" napi_status napi_coerce_to_string(napi_env env, napi_value value, napi_value* result) { - if (UNLIKELY(result == nullptr)) { + if (UNLIKELY(result == nullptr || value == nullptr || env == nullptr)) { return napi_invalid_arg; } Zig::GlobalObject* globalObject = toJS(env); JSC::VM& vm = globalObject->vm(); - auto scope = DECLARE_CATCH_SCOPE(vm); - JSC::JSValue jsValue = JSC::JSValue::decode(reinterpret_cast<JSC::EncodedJSValue>(value)); + auto scope = DECLARE_THROW_SCOPE(vm); + JSC::JSValue jsValue = toJS(value); JSC::EnsureStillAliveScope ensureStillAlive(jsValue); // .toString() can throw @@ -1588,7 +1668,7 @@ extern "C" napi_status napi_get_property_names(napi_env env, napi_value object, Zig::GlobalObject* globalObject = toJS(env); JSC::VM& vm = globalObject->vm(); - JSC::JSValue jsValue = JSC::JSValue::decode(reinterpret_cast<JSC::EncodedJSValue>(object)); + JSC::JSValue jsValue = toJS(object); if (!jsValue || !jsValue.isObject()) { return napi_invalid_arg; } @@ -1717,7 +1797,7 @@ extern "C" napi_status napi_get_element(napi_env env, napi_value objectValue, uint32_t index, napi_value* result) { JSValue jsValue = toJS(objectValue); - if (!jsValue || !jsValue.isObject()) { + if (UNLIKELY(!env || !jsValue || !jsValue.isObject())) { return napi_invalid_arg; } @@ -1737,7 +1817,7 @@ extern "C" napi_status napi_get_element(napi_env env, napi_value objectValue, extern "C" napi_status napi_create_object(napi_env env, napi_value* result) { - if (UNLIKELY(result == nullptr)) { + if (UNLIKELY(result == nullptr || env == nullptr)) { return napi_invalid_arg; } diff --git a/src/bun.js/bindings/process.d.ts b/src/bun.js/bindings/process.d.ts deleted file mode 100644 index 194ea2b6a..000000000 --- a/src/bun.js/bindings/process.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * The process object provides information about, and control over, the - * current Bun.js process. While it is available as a global, it is - * recommended to explicitly access it via require or import - */ -export interface Process { - // -} diff --git a/src/bun.js/bindings/sqlite/JSSQLStatement.cpp b/src/bun.js/bindings/sqlite/JSSQLStatement.cpp index 8519cb2e2..2ce4cc9a6 100644 --- a/src/bun.js/bindings/sqlite/JSSQLStatement.cpp +++ b/src/bun.js/bindings/sqlite/JSSQLStatement.cpp @@ -83,6 +83,11 @@ static JSC_DECLARE_CUSTOM_GETTER(jsSqlStatementGetColumnCount); static JSC_DECLARE_HOST_FUNCTION(jsSQLStatementSerialize); static JSC_DECLARE_HOST_FUNCTION(jsSQLStatementDeserialize); +static inline JSC::JSValue jsNumberFromSQLite(sqlite3_stmt* stmt, unsigned int i) +{ + int64_t num = sqlite3_column_int64(stmt, i); + return num > INT_MAX || num < INT_MIN ? JSC::jsDoubleNumber(static_cast<double>(num)) : JSC::jsNumber(static_cast<int>(num)); +} #define CHECK_THIS \ if (UNLIKELY(!castedThis)) { \ @@ -183,7 +188,7 @@ public: JSC::JSValue rebind(JSGlobalObject* globalObject, JSC::JSValue values, bool clone); static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) { - return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::JSFunctionType, StructureFlags), info()); } bool need_update() { return version_db->version.load() != version; } @@ -336,10 +341,6 @@ void JSSQLStatement::destroy(JSC::JSCell* cell) thisObject->stmt = nullptr; } -void JSSQLStatementConstructor::destroy(JSC::JSCell* cell) -{ -} - static inline bool rebindValue(JSC::JSGlobalObject* lexicalGlobalObject, sqlite3_stmt* stmt, int i, JSC::JSValue value, JSC::ThrowScope& scope, bool clone) { #define CHECK_BIND(param) \ @@ -690,6 +691,11 @@ JSC_DEFINE_HOST_FUNCTION(jsSQLStatementLoadExtensionFunction, (JSC::JSGlobalObje return JSValue::encode(JSC::jsUndefined()); } + if (sqlite3_compileoption_used("SQLITE_OMIT_LOAD_EXTENSION")) { + throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, "This build of sqlite3 does not support dynamic extension loading"_s)); + return JSValue::encode(JSC::jsUndefined()); + } + auto entryPointStr = callFrame->argumentCount() > 2 && callFrame->argument(2).isString() ? callFrame->argument(2).toWTFString(lexicalGlobalObject) : String(); const char* entryPoint = entryPointStr.length() == 0 ? NULL : entryPointStr.utf8().data(); char* error; @@ -1054,7 +1060,7 @@ static const HashTableValue JSSQLStatementConstructorTableValues[] = { { "deserialize"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsSQLStatementDeserialize, 2 } }, }; -const ClassInfo JSSQLStatementConstructor::s_info = { "SQLStatement"_s, nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(JSSQLStatementConstructor) }; +const ClassInfo JSSQLStatementConstructor::s_info = { "SQLStatement"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSQLStatementConstructor) }; void JSSQLStatementConstructor::finishCreation(VM& vm) { @@ -1090,7 +1096,7 @@ static inline JSC::JSValue constructResultObject(JSC::JSGlobalObject* lexicalGlo switch (sqlite3_column_type(stmt, i)) { case SQLITE_INTEGER: { // https://github.com/oven-sh/bun/issues/1536 - value = jsNumber(sqlite3_column_int64(stmt, i)); + value = jsNumberFromSQLite(stmt, i); break; } case SQLITE_FLOAT: { @@ -1146,11 +1152,11 @@ static inline JSC::JSValue constructResultObject(JSC::JSGlobalObject* lexicalGlo switch (sqlite3_column_type(stmt, i)) { case SQLITE_INTEGER: { // https://github.com/oven-sh/bun/issues/1536 - result->putDirect(vm, name, jsNumber(sqlite3_column_int64(stmt, i)), 0); + result->putDirect(vm, name, jsNumberFromSQLite(stmt, i), 0); break; } case SQLITE_FLOAT: { - result->putDirect(vm, name, jsNumber(sqlite3_column_double(stmt, i)), 0); + result->putDirect(vm, name, jsDoubleNumber(sqlite3_column_double(stmt, i)), 0); break; } // > Note that the SQLITE_TEXT constant was also used in SQLite version @@ -1205,11 +1211,11 @@ static inline JSC::JSArray* constructResultRow(JSC::JSGlobalObject* lexicalGloba switch (sqlite3_column_type(stmt, i)) { case SQLITE_INTEGER: { // https://github.com/oven-sh/bun/issues/1536 - result->putDirectIndex(lexicalGlobalObject, i, jsNumber(sqlite3_column_int64(stmt, i))); + result->putDirectIndex(lexicalGlobalObject, i, jsNumberFromSQLite(stmt, i)); break; } case SQLITE_FLOAT: { - result->putDirectIndex(lexicalGlobalObject, i, jsNumber(sqlite3_column_double(stmt, i))); + result->putDirectIndex(lexicalGlobalObject, i, jsDoubleNumber(sqlite3_column_double(stmt, i))); break; } // > Note that the SQLITE_TEXT constant was also used in SQLite version @@ -1251,7 +1257,6 @@ static inline JSC::JSArray* constructResultRow(JSC::JSGlobalObject* lexicalGloba JSC_DEFINE_HOST_FUNCTION(jsSQLStatementExecuteStatementFunctionAll, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame)) { - JSC::VM& vm = lexicalGlobalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); auto castedThis = jsDynamicCast<JSSQLStatement*>(callFrame->thisValue()); @@ -1283,7 +1288,6 @@ JSC_DEFINE_HOST_FUNCTION(jsSQLStatementExecuteStatementFunctionAll, (JSC::JSGlob size_t columnCount = castedThis->columnNames->size(); JSValue result = jsUndefined(); - if (status == SQLITE_ROW) { // this is a count from UPDATE or another query like that if (columnCount == 0) { @@ -1305,11 +1309,7 @@ JSC_DEFINE_HOST_FUNCTION(jsSQLStatementExecuteStatementFunctionAll, (JSC::JSGlob result = resultArray; } } else if (status == SQLITE_DONE) { - if (columnCount == 0) { - result = jsNumber(sqlite3_changes(castedThis->version_db->db)); - } else { - result = JSC::constructEmptyArray(lexicalGlobalObject, nullptr, 0); - } + result = JSC::constructEmptyArray(lexicalGlobalObject, nullptr, 0); } if (UNLIKELY(status != SQLITE_DONE && status != SQLITE_OK)) { @@ -1632,7 +1632,7 @@ JSC_DEFINE_HOST_FUNCTION(jsSQLStatementFunctionFinalize, (JSC::JSGlobalObject * RELEASE_AND_RETURN(scope, JSValue::encode(jsUndefined())); } -const ClassInfo JSSQLStatement::s_info = { "SQLStatement"_s, nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(JSSQLStatement) }; +const ClassInfo JSSQLStatement::s_info = { "SQLStatement"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSQLStatement) }; /* Hash table for prototype */ static const HashTableValue JSSQLStatementTableValues[] = { diff --git a/src/bun.js/bindings/sqlite/JSSQLStatement.h b/src/bun.js/bindings/sqlite/JSSQLStatement.h index 8566fcdd9..b628f2a38 100644 --- a/src/bun.js/bindings/sqlite/JSSQLStatement.h +++ b/src/bun.js/bindings/sqlite/JSSQLStatement.h @@ -50,25 +50,15 @@ namespace WebCore { class JSSQLStatementConstructor final : public JSC::JSFunction { public: using Base = JSC::JSFunction; + static constexpr unsigned StructureFlags = Base::StructureFlags; + static JSSQLStatementConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure); DECLARE_INFO; - template<typename, SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return WebCore::subspaceForImpl<JSSQLStatementConstructor, WebCore::UseCustomHeapCellType::No>( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForJSSQLStatementConstructor.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForJSSQLStatementConstructor = std::forward<decltype(space)>(space); }, - [](auto& spaces) { return spaces.m_subspaceForJSSQLStatementConstructor.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForJSSQLStatementConstructor = std::forward<decltype(space)>(space); }); - } - static void destroy(JSC::JSCell*); static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) { - return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSFunctionType, StructureFlags), info()); } private: @@ -79,5 +69,6 @@ private: void finishCreation(JSC::VM&); }; +static_assert(sizeof(JSSQLStatementConstructor) == sizeof(JSFunction), "Allocate JSSQLStatementConstructor in JSFunction IsoSubspace"); }
\ No newline at end of file diff --git a/src/bun.js/bindings/sqlite/lazy_sqlite3.h b/src/bun.js/bindings/sqlite/lazy_sqlite3.h index 8b23a7e03..a012f6ab6 100644 --- a/src/bun.js/bindings/sqlite/lazy_sqlite3.h +++ b/src/bun.js/bindings/sqlite/lazy_sqlite3.h @@ -71,6 +71,7 @@ typedef int (*lazy_sqlite3_deserialize_type)( ); typedef int (*lazy_sqlite3_stmt_readonly_type)(sqlite3_stmt* pStmt); +typedef int (*lazy_sqlite3_compileoption_used_type)(const char *zOptName); static lazy_sqlite3_bind_blob_type lazy_sqlite3_bind_blob; static lazy_sqlite3_bind_double_type lazy_sqlite3_bind_double; @@ -112,6 +113,7 @@ static lazy_sqlite3_malloc64_type lazy_sqlite3_malloc64; static lazy_sqlite3_serialize_type lazy_sqlite3_serialize; static lazy_sqlite3_deserialize_type lazy_sqlite3_deserialize; static lazy_sqlite3_stmt_readonly_type lazy_sqlite3_stmt_readonly; +static lazy_sqlite3_compileoption_used_type lazy_sqlite3_compileoption_used; #define sqlite3_bind_blob lazy_sqlite3_bind_blob #define sqlite3_bind_double lazy_sqlite3_bind_double @@ -152,6 +154,7 @@ static lazy_sqlite3_stmt_readonly_type lazy_sqlite3_stmt_readonly; #define sqlite3_deserialize lazy_sqlite3_deserialize #define sqlite3_stmt_readonly lazy_sqlite3_stmt_readonly #define sqlite3_column_int64 lazy_sqlite3_column_int64 +#define sqlite3_compileoption_used lazy_sqlite3_compileoption_used; static void* sqlite3_handle = nullptr; static const char* sqlite3_lib_path = "libsqlite3.dylib"; @@ -204,6 +207,7 @@ static int lazyLoadSQLite() lazy_sqlite3_deserialize = (lazy_sqlite3_deserialize_type)dlsym(sqlite3_handle, "sqlite3_deserialize"); lazy_sqlite3_malloc64 = (lazy_sqlite3_malloc64_type)dlsym(sqlite3_handle, "sqlite3_malloc64"); lazy_sqlite3_stmt_readonly = (lazy_sqlite3_stmt_readonly_type)dlsym(sqlite3_handle, "sqlite3_stmt_readonly"); + lazy_sqlite3_compileoption_used = (lazy_sqlite3_compileoption_used_type)dlsym(sqlite3_handle, "sqlite3_compileoption_used"); return 0; } diff --git a/src/bun.js/bindings/webcore/AbortSignal.h b/src/bun.js/bindings/webcore/AbortSignal.h index 6f4abf5ba..b60d2a6bf 100644 --- a/src/bun.js/bindings/webcore/AbortSignal.h +++ b/src/bun.js/bindings/webcore/AbortSignal.h @@ -45,6 +45,7 @@ class AbortSignal final : public RefCounted<AbortSignal>, public EventTargetWith public: static Ref<AbortSignal> create(ScriptExecutionContext*); WEBCORE_EXPORT ~AbortSignal(); + using NativeCallbackTuple = std::tuple<void*, void (*)(void*, JSC::EncodedJSValue)>; static Ref<AbortSignal> abort(JSDOMGlobalObject&, ScriptExecutionContext&, JSC::JSValue reason); static Ref<AbortSignal> timeout(ScriptExecutionContext&, uint64_t milliseconds); @@ -66,7 +67,7 @@ public: using Algorithm = Function<void(JSValue)>; void addAlgorithm(Algorithm&& algorithm) { m_algorithms.append(WTFMove(algorithm)); } void cleanNativeBindings(void* ref); - void addNativeCallback(std::tuple<void*, void (*)(void*, JSC::EncodedJSValue)> callback) { m_native_callbacks.append(callback); } + void addNativeCallback(NativeCallbackTuple callback) { m_native_callbacks.append(callback); } bool isFollowingSignal() const { return !!m_followingSignal; } @@ -87,8 +88,8 @@ private: void eventListenersDidChange() final; bool m_aborted { false }; - Vector<Algorithm> m_algorithms; - Vector<std::tuple<void*, void (*)(void*, JSC::EncodedJSValue)>> m_native_callbacks; + Vector<Algorithm, 2> m_algorithms; + Vector<NativeCallbackTuple, 2> m_native_callbacks; WeakPtr<AbortSignal> m_followingSignal; JSC::Strong<JSC::Unknown> m_reason; bool m_hasActiveTimeoutTimer { false }; diff --git a/src/bun.js/bindings/webcore/JSDOMURL.cpp b/src/bun.js/bindings/webcore/JSDOMURL.cpp index 747154bed..3f99fc2b7 100644 --- a/src/bun.js/bindings/webcore/JSDOMURL.cpp +++ b/src/bun.js/bindings/webcore/JSDOMURL.cpp @@ -64,6 +64,7 @@ using namespace JSC; static JSC_DECLARE_HOST_FUNCTION(jsDOMURLPrototypeFunction_toJSON); static JSC_DECLARE_HOST_FUNCTION(jsDOMURLConstructorFunction_createObjectURL); static JSC_DECLARE_HOST_FUNCTION(jsDOMURLConstructorFunction_revokeObjectURL); +static JSC_DECLARE_HOST_FUNCTION(jsDOMURLConstructorFunction_canParse); static JSC_DECLARE_HOST_FUNCTION(jsDOMURLPrototypeFunction_toString); // Attributes @@ -131,6 +132,7 @@ using JSDOMURLDOMConstructor = JSDOMConstructor<JSDOMURL>; static const HashTableValue JSDOMURLConstructorTableValues[] = { { "createObjectURL"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsDOMURLConstructorFunction_createObjectURL, 1 } }, { "revokeObjectURL"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsDOMURLConstructorFunction_revokeObjectURL, 1 } }, + { "canParse"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsDOMURLConstructorFunction_canParse, 2 } }, }; static inline EncodedJSValue constructJSDOMURL1(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame) @@ -688,6 +690,33 @@ JSC_DEFINE_HOST_FUNCTION(jsDOMURLConstructorFunction_revokeObjectURL, (JSGlobalO return IDLOperation<JSDOMURL>::callStatic<jsDOMURLConstructorFunction_revokeObjectURLBody>(*lexicalGlobalObject, *callFrame, "revokeObjectURL"); } +static inline JSC::EncodedJSValue jsDOMURLConstructorFunction_canParseBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame) +{ + auto& vm = JSC::getVM(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(callFrame->argumentCount() < 1)) + return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject)); + + EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0); + auto url = convert<IDLUSVString>(*lexicalGlobalObject, argument0.value()); + RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); + + EnsureStillAliveScope argument1 = callFrame->argument(1); + String base; + if (!argument1.value().isUndefinedOrNull()) { + base = convert<IDLUSVString>(*lexicalGlobalObject, argument1.value()); + RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); + } + + return JSValue::encode(jsBoolean(DOMURL::canParse(url, base))); +} + +JSC_DEFINE_HOST_FUNCTION(jsDOMURLConstructorFunction_canParse, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + return IDLOperation<JSDOMURL>::callStatic<jsDOMURLConstructorFunction_canParseBody>(*lexicalGlobalObject, *callFrame, "canParse"); +} + #if ENABLE(MEDIA_SOURCE) static inline JSC::EncodedJSValue jsDOMURLConstructorFunction_createObjectURL2Body(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame) { diff --git a/src/bun.js/bindings/webcore/JSEventEmitter.cpp b/src/bun.js/bindings/webcore/JSEventEmitter.cpp index 959cbd8d7..e81af9549 100644 --- a/src/bun.js/bindings/webcore/JSEventEmitter.cpp +++ b/src/bun.js/bindings/webcore/JSEventEmitter.cpp @@ -109,9 +109,10 @@ template<> EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSEventEmitterDOMConstructor: if constexpr (IsExceptionOr<decltype(object)>) RETURN_IF_EXCEPTION(throwScope, {}); - if (JSValue maxListeners = castedThis->getIfPropertyExists(lexicalGlobalObject, JSC::Identifier::fromString(vm, "defaultMaxListeners"_s))) { - if (maxListeners.isUInt32()) - object->setMaxListeners(maxListeners.toUInt32(lexicalGlobalObject)); + JSValue maxListeners = castedThis->getIfPropertyExists(lexicalGlobalObject, JSC::Identifier::fromString(vm, "defaultMaxListeners"_s)); + RETURN_IF_EXCEPTION(throwScope, {}); + if (maxListeners && maxListeners.isUInt32()) { + object->setMaxListeners(maxListeners.toUInt32(lexicalGlobalObject)); } static_assert(TypeOrExceptionOrUnderlyingType<decltype(object)>::isRef); auto jsValue = toJSNewlyCreated<IDLInterface<EventEmitter>>(*lexicalGlobalObject, *castedThis->globalObject(), throwScope, WTFMove(object)); diff --git a/src/bun.js/bindings/webcore/JSFetchHeaders.cpp b/src/bun.js/bindings/webcore/JSFetchHeaders.cpp index 2ae8dd547..421a042e5 100644 --- a/src/bun.js/bindings/webcore/JSFetchHeaders.cpp +++ b/src/bun.js/bindings/webcore/JSFetchHeaders.cpp @@ -245,17 +245,11 @@ JSC_DEFINE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_getAll, (JSGlobalObject return JSValue::encode(array); } -JSC_DEFINE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_getSetCookie, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +JSC_DEFINE_HOST_FUNCTION(fetchHeadersGetSetCookie, (JSC::JSGlobalObject * lexicalGlobalObject, VM& vm, WebCore::FetchHeaders* impl)) { - auto& vm = JSC::getVM(lexicalGlobalObject); auto scope = DECLARE_THROW_SCOPE(vm); - JSFetchHeaders* castedThis = jsDynamicCast<JSFetchHeaders*>(callFrame->thisValue()); - if (UNLIKELY(!castedThis)) { - return JSValue::encode(jsUndefined()); - } - auto& impl = castedThis->wrapped(); - auto values = impl.getSetCookieHeaders(); + auto values = impl->getSetCookieHeaders(); unsigned count = values.size(); if (!count) { @@ -263,20 +257,31 @@ JSC_DEFINE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_getSetCookie, (JSGlobal } JSC::JSArray* array = constructEmptyArray(lexicalGlobalObject, nullptr, count); - RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); if (UNLIKELY(!array)) { throwOutOfMemoryError(lexicalGlobalObject, scope); - return JSValue::encode(jsUndefined()); + return encodedJSValue(); } for (unsigned i = 0; i < count; ++i) { array->putDirectIndex(lexicalGlobalObject, i, jsString(vm, values[i])); - RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); } return JSValue::encode(array); } +JSC_DEFINE_HOST_FUNCTION(jsFetchHeadersPrototypeFunction_getSetCookie, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame)) +{ + auto& vm = JSC::getVM(lexicalGlobalObject); + JSFetchHeaders* castedThis = jsDynamicCast<JSFetchHeaders*>(callFrame->thisValue()); + if (UNLIKELY(!castedThis)) { + return JSValue::encode(jsUndefined()); + } + auto& impl = castedThis->wrapped(); + return fetchHeadersGetSetCookie(lexicalGlobalObject, vm, &impl); +} + /* Hash table for prototype */ static const HashTableValue JSFetchHeadersPrototypeTableValues[] = { @@ -324,7 +329,7 @@ void JSFetchHeaders::finishCreation(VM& vm) void JSFetchHeaders::computeMemoryCost() { m_memoryCost = wrapped().memoryCost(); - globalObject()->vm().heap.reportExtraMemoryAllocated(m_memoryCost); + globalObject()->vm().heap.reportExtraMemoryAllocated(this, m_memoryCost); } JSObject* JSFetchHeaders::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) @@ -688,7 +693,6 @@ extern void* _ZTVN7WebCore12FetchHeadersE[]; JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject* globalObject, Ref<FetchHeaders>&& impl) { - if constexpr (std::is_polymorphic_v<FetchHeaders>) { #if ENABLE(BINDING_INTEGRITY) const void* actualVTablePointer = getVTablePointer(impl.ptr()); diff --git a/src/bun.js/bindings/webcore/JSFetchHeaders.h b/src/bun.js/bindings/webcore/JSFetchHeaders.h index 4efcc5f5f..58b61bbbb 100644 --- a/src/bun.js/bindings/webcore/JSFetchHeaders.h +++ b/src/bun.js/bindings/webcore/JSFetchHeaders.h @@ -97,4 +97,6 @@ template<> struct JSDOMWrapperConverterTraits<FetchHeaders> { using ToWrappedReturnType = FetchHeaders*; }; +JSC::EncodedJSValue fetchHeadersGetSetCookie(JSC::JSGlobalObject* lexicalGlobalObject, VM& vm, WebCore::FetchHeaders* impl); + } // namespace WebCore diff --git a/src/bun.js/bindings/webcore/JSMessageEvent.cpp b/src/bun.js/bindings/webcore/JSMessageEvent.cpp index 68414fe46..0a7ca6a5f 100644 --- a/src/bun.js/bindings/webcore/JSMessageEvent.cpp +++ b/src/bun.js/bindings/webcore/JSMessageEvent.cpp @@ -295,7 +295,7 @@ void JSMessageEvent::finishCreation(VM& vm) // static_assert(!std::is_base_of<ActiveDOMObject, MessageEvent>::value, "Interface is not marked as [ActiveDOMObject] even though implementation class subclasses ActiveDOMObject."); - vm.heap.reportExtraMemoryAllocated(wrapped().memoryCost()); + vm.heap.reportExtraMemoryAllocated(this, wrapped().memoryCost()); } JSObject* JSMessageEvent::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) diff --git a/src/bun.js/bindings/webcore/JSReadableStream.cpp b/src/bun.js/bindings/webcore/JSReadableStream.cpp index 3fea3d44f..0a0ef3b23 100644 --- a/src/bun.js/bindings/webcore/JSReadableStream.cpp +++ b/src/bun.js/bindings/webcore/JSReadableStream.cpp @@ -108,7 +108,7 @@ template<> FunctionExecutable* JSReadableStreamDOMConstructor::initializeExecuta static const HashTableValue JSReadableStreamPrototypeTableValues[] = { { "constructor"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableStreamConstructor, 0 } }, - { "locked"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamLockedCodeGenerator, 0 } }, + { "locked"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, readableStreamLockedCodeGenerator, 0 } }, { "cancel"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamCancelCodeGenerator, 0 } }, { "getReader"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamGetReaderCodeGenerator, 0 } }, { "pipeTo"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamPipeToCodeGenerator, 1 } }, diff --git a/src/bun.js/bindings/webcore/JSReadableStreamDefaultController.cpp b/src/bun.js/bindings/webcore/JSReadableStreamDefaultController.cpp index fea3ffc8c..b15084041 100644 --- a/src/bun.js/bindings/webcore/JSReadableStreamDefaultController.cpp +++ b/src/bun.js/bindings/webcore/JSReadableStreamDefaultController.cpp @@ -108,7 +108,7 @@ template<> FunctionExecutable* JSReadableStreamDefaultControllerDOMConstructor:: static const HashTableValue JSReadableStreamDefaultControllerPrototypeTableValues[] = { { "constructor"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableStreamDefaultControllerConstructor, 0 } }, - { "desiredSize"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamDefaultControllerDesiredSizeCodeGenerator, 0 } }, + { "desiredSize"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, readableStreamDefaultControllerDesiredSizeCodeGenerator, 0 } }, { "enqueue"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamDefaultControllerEnqueueCodeGenerator, 0 } }, { "close"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamDefaultControllerCloseCodeGenerator, 0 } }, { "error"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamDefaultControllerErrorCodeGenerator, 0 } }, diff --git a/src/bun.js/bindings/webcore/JSReadableStreamDefaultReader.cpp b/src/bun.js/bindings/webcore/JSReadableStreamDefaultReader.cpp index 55b89ad46..68b587a92 100644 --- a/src/bun.js/bindings/webcore/JSReadableStreamDefaultReader.cpp +++ b/src/bun.js/bindings/webcore/JSReadableStreamDefaultReader.cpp @@ -108,7 +108,7 @@ template<> FunctionExecutable* JSReadableStreamDefaultReaderDOMConstructor::init static const HashTableValue JSReadableStreamDefaultReaderPrototypeTableValues[] = { { "constructor"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableStreamDefaultReaderConstructor, 0 } }, - { "closed"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamDefaultReaderClosedCodeGenerator, 0 } }, + { "closed"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinAccessorType, readableStreamDefaultReaderClosedCodeGenerator, 0 } }, { "read"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamDefaultReaderReadCodeGenerator, 0 } }, { "readMany"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamDefaultReaderReadManyCodeGenerator, 0 } }, { "cancel"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, readableStreamDefaultReaderCancelCodeGenerator, 0 } }, diff --git a/src/bun.js/bindings/webcore/JSURLSearchParams.cpp b/src/bun.js/bindings/webcore/JSURLSearchParams.cpp index 0d401fa00..4c0f0e912 100644 --- a/src/bun.js/bindings/webcore/JSURLSearchParams.cpp +++ b/src/bun.js/bindings/webcore/JSURLSearchParams.cpp @@ -182,6 +182,7 @@ static const HashTableValue JSURLSearchParamsPrototypeTableValues[] = { { "toString"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsURLSearchParamsPrototypeFunction_toString, 0 } }, { "toJSON"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsURLSearchParamsPrototypeFunction_toJSON, 0 } }, { "length"_s, static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsURLSearchParamsPrototype_getLength, 0 } }, + { "size"_s, static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsURLSearchParamsPrototype_getLength, 0 } }, }; const ClassInfo JSURLSearchParamsPrototype::s_info = { "URLSearchParams"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSURLSearchParamsPrototype) }; diff --git a/src/bun.js/bindings/webcore/MessagePort.cpp b/src/bun.js/bindings/webcore/MessagePort.cpp index da2bd32e8..b463791df 100644 --- a/src/bun.js/bindings/webcore/MessagePort.cpp +++ b/src/bun.js/bindings/webcore/MessagePort.cpp @@ -141,7 +141,7 @@ MessagePort::MessagePort(ScriptExecutionContext& scriptExecutionContext, const M , m_identifier(local) , m_remoteIdentifier(remote) { - LOG(MessagePorts, "Created MessagePort %s (%p) in process %" PRIu64, m_identifier.logString().utf8().data(), this, ProcessIdent::identifier().toUInt64()); + // LOG(MessagePorts, "Created MessagePort %s (%p) in process %" PRIu64, m_identifier.logString().utf8().data(), this, ProcessIdent::identifier().toUInt64()); Locker locker { allMessagePortsLock }; allMessagePorts().set(m_identifier, this); @@ -157,7 +157,7 @@ MessagePort::MessagePort(ScriptExecutionContext& scriptExecutionContext, const M MessagePort::~MessagePort() { - LOG(MessagePorts, "Destroyed MessagePort %s (%p) in process %" PRIu64, m_identifier.logString().utf8().data(), this, ProcessIdent::identifier().toUInt64()); + // LOG(MessagePorts, "Destroyed MessagePort %s (%p) in process %" PRIu64, m_identifier.logString().utf8().data(), this, ProcessIdent::identifier().toUInt64()); ASSERT(allMessagePortsLock.isLocked()); @@ -175,7 +175,7 @@ void MessagePort::entangle() ExceptionOr<void> MessagePort::postMessage(JSC::JSGlobalObject& state, JSC::JSValue messageValue, StructuredSerializeOptions&& options) { - LOG(MessagePorts, "Attempting to post message to port %s (to be received by port %s)", m_identifier.logString().utf8().data(), m_remoteIdentifier.logString().utf8().data()); + // LOG(MessagePorts, "Attempting to post message to port %s (to be received by port %s)", m_identifier.logString().utf8().data(), m_remoteIdentifier.logString().utf8().data()); Vector<RefPtr<MessagePort>> ports; auto messageData = SerializedScriptValue::create(state, messageValue, WTFMove(options.transfer), ports, SerializationForStorage::No, SerializationContext::WorkerPostMessage); @@ -202,7 +202,7 @@ ExceptionOr<void> MessagePort::postMessage(JSC::JSGlobalObject& state, JSC::JSVa MessageWithMessagePorts message { messageData.releaseReturnValue(), WTFMove(transferredPorts) }; - LOG(MessagePorts, "Actually posting message to port %s (to be received by port %s)", m_identifier.logString().utf8().data(), m_remoteIdentifier.logString().utf8().data()); + // LOG(MessagePorts, "Actually posting message to port %s (to be received by port %s)", m_identifier.logString().utf8().data(), m_remoteIdentifier.logString().utf8().data()); ScriptExecutionContextIdentifier contextId = contextIdForMessagePortId(m_remoteIdentifier); @@ -280,7 +280,7 @@ void MessagePort::dispatchMessages() auto messagesTakenHandler = [this, protectedThis = Ref { *this }](Vector<MessageWithMessagePorts>&& messages, CompletionHandler<void()>&& completionCallback) mutable { auto scopeExit = makeScopeExit(WTFMove(completionCallback)); - LOG(MessagePorts, "MessagePort %s (%p) dispatching %zu messages", m_identifier.logString().utf8().data(), this, messages.size()); + // LOG(MessagePorts, "MessagePort %s (%p) dispatching %zu messages", m_identifier.logString().utf8().data(), this, messages.size()); auto* context = scriptExecutionContext(); if (!context || !context->jsGlobalObject()) @@ -382,7 +382,7 @@ ExceptionOr<Vector<TransferredMessagePort>> MessagePort::disentanglePorts(Vector Vector<RefPtr<MessagePort>> MessagePort::entanglePorts(ScriptExecutionContext& context, Vector<TransferredMessagePort>&& transferredPorts) { - LOG(MessagePorts, "Entangling %zu transferred ports to ScriptExecutionContext %s (%p)", transferredPorts.size(), context.url().string().utf8().data(), &context); + // LOG(MessagePorts, "Entangling %zu transferred ports to ScriptExecutionContext %s (%p)", transferredPorts.size(), context.url().string().utf8().data(), &context); if (transferredPorts.isEmpty()) return {}; diff --git a/src/bun.js/bindings/webcore/MessagePortChannel.cpp b/src/bun.js/bindings/webcore/MessagePortChannel.cpp index 031679204..425fb8c11 100644 --- a/src/bun.js/bindings/webcore/MessagePortChannel.cpp +++ b/src/bun.js/bindings/webcore/MessagePortChannel.cpp @@ -75,7 +75,7 @@ void MessagePortChannel::entanglePortWithProcess(const MessagePortIdentifier& po ASSERT(port == m_ports[0] || port == m_ports[1]); size_t i = port == m_ports[0] ? 0 : 1; - LOG(MessagePorts, "MessagePortChannel %s (%p) entangling port %s (that port has %zu messages available)", logString().utf8().data(), this, port.logString().utf8().data(), m_pendingMessages[i].size()); + // LOG(MessagePorts, "MessagePortChannel %s (%p) entangling port %s (that port has %zu messages available)", logString().utf8().data(), this, port.logString().utf8().data(), m_pendingMessages[i].size()); ASSERT(!m_processes[i] || *m_processes[i] == process); m_processes[i] = process; @@ -85,7 +85,7 @@ void MessagePortChannel::entanglePortWithProcess(const MessagePortIdentifier& po void MessagePortChannel::disentanglePort(const MessagePortIdentifier& port) { - LOG(MessagePorts, "MessagePortChannel %s (%p) disentangling port %s", logString().utf8().data(), this, port.logString().utf8().data()); + // LOG(MessagePorts, "MessagePortChannel %s (%p) disentangling port %s", logString().utf8().data(), this, port.logString().utf8().data()); ASSERT(port == m_ports[0] || port == m_ports[1]); size_t i = port == m_ports[0] ? 0 : 1; @@ -123,7 +123,7 @@ bool MessagePortChannel::postMessageToRemote(MessageWithMessagePorts&& message, size_t i = remoteTarget == m_ports[0] ? 0 : 1; m_pendingMessages[i].append(WTFMove(message)); - LOG(MessagePorts, "MessagePortChannel %s (%p) now has %zu messages pending on port %s", logString().utf8().data(), this, m_pendingMessages[i].size(), remoteTarget.logString().utf8().data()); + // LOG(MessagePorts, "MessagePortChannel %s (%p) now has %zu messages pending on port %s", logString().utf8().data(), this, m_pendingMessages[i].size(), remoteTarget.logString().utf8().data()); if (m_pendingMessages[i].size() == 1) { m_pendingMessageProtectors[i] = this; @@ -136,7 +136,7 @@ bool MessagePortChannel::postMessageToRemote(MessageWithMessagePorts&& message, void MessagePortChannel::takeAllMessagesForPort(const MessagePortIdentifier& port, CompletionHandler<void(Vector<MessageWithMessagePorts>&&, CompletionHandler<void()>&&)>&& callback) { - LOG(MessagePorts, "MessagePortChannel %p taking all messages for port %s", this, port.logString().utf8().data()); + // LOG(MessagePorts, "MessagePortChannel %p taking all messages for port %s", this, port.logString().utf8().data()); ASSERT(port == m_ports[0] || port == m_ports[1]); size_t i = port == m_ports[0] ? 0 : 1; @@ -153,7 +153,7 @@ void MessagePortChannel::takeAllMessagesForPort(const MessagePortIdentifier& por ++m_messageBatchesInFlight; - LOG(MessagePorts, "There are %zu messages to take for port %s. Taking them now, messages in flight is now %" PRIu64, result.size(), port.logString().utf8().data(), m_messageBatchesInFlight); + // LOG(MessagePorts, "There are %zu messages to take for port %s. Taking them now, messages in flight is now %" PRIu64, result.size(), port.logString().utf8().data(), m_messageBatchesInFlight); auto size = result.size(); callback(WTFMove(result), [size, this, port, protectedThis = WTFMove(m_pendingMessageProtectors[i])] { @@ -162,7 +162,7 @@ void MessagePortChannel::takeAllMessagesForPort(const MessagePortIdentifier& por UNUSED_PARAM(size); #endif --m_messageBatchesInFlight; - LOG(MessagePorts, "Message port channel %s was notified that a batch of %zu message port messages targeted for port %s just completed dispatch, in flight is now %" PRIu64, logString().utf8().data(), size, port.logString().utf8().data(), m_messageBatchesInFlight); + // LOG(MessagePorts, "Message port channel %s was notified that a batch of %zu message port messages targeted for port %s just completed dispatch, in flight is now %" PRIu64, logString().utf8().data(), size, port.logString().utf8().data(), m_messageBatchesInFlight); }); } diff --git a/src/bun.js/bindings/webcore/MessagePortChannelProvider.cpp b/src/bun.js/bindings/webcore/MessagePortChannelProvider.cpp index 7675a2e75..cde0d0dd4 100644 --- a/src/bun.js/bindings/webcore/MessagePortChannelProvider.cpp +++ b/src/bun.js/bindings/webcore/MessagePortChannelProvider.cpp @@ -38,7 +38,8 @@ static MessagePortChannelProviderImpl* globalProvider; MessagePortChannelProvider& MessagePortChannelProvider::singleton() { - ASSERT(isMainThread()); + // TODO: I think this assertion is relevant. Bun will call this on the Worker's thread + // ASSERT(isMainThread()); static std::once_flag onceFlag; std::call_once(onceFlag, [] { if (!globalProvider) diff --git a/src/bun.js/bindings/webcore/MessagePortChannelRegistry.cpp b/src/bun.js/bindings/webcore/MessagePortChannelRegistry.cpp index 5096357f2..a92262f63 100644 --- a/src/bun.js/bindings/webcore/MessagePortChannelRegistry.cpp +++ b/src/bun.js/bindings/webcore/MessagePortChannelRegistry.cpp @@ -30,6 +30,9 @@ #include <wtf/CompletionHandler.h> #include <wtf/MainThread.h> +// ASSERT(isMainThread()) is used alot here, and I think it may be required, but i'm not 100% sure. +// we totally are calling these off the main thread in many cases in Bun, so ........ + namespace WebCore { MessagePortChannelRegistry::MessagePortChannelRegistry() = default; @@ -41,15 +44,15 @@ MessagePortChannelRegistry::~MessagePortChannelRegistry() void MessagePortChannelRegistry::didCreateMessagePortChannel(const MessagePortIdentifier& port1, const MessagePortIdentifier& port2) { - LOG(MessagePorts, "Registry: Creating MessagePortChannel %p linking %s and %s", this, port1.logString().utf8().data(), port2.logString().utf8().data()); - ASSERT(isMainThread()); + // LOG(MessagePorts, "Registry: Creating MessagePortChannel %p linking %s and %s", this, port1.logString().utf8().data(), port2.logString().utf8().data()); + // ASSERT(isMainThread()); MessagePortChannel::create(*this, port1, port2); } void MessagePortChannelRegistry::messagePortChannelCreated(MessagePortChannel& channel) { - ASSERT(isMainThread()); + // ASSERT(isMainThread()); auto result = m_openChannels.ensure(channel.port1(), [channel = &channel] { return channel; @@ -64,7 +67,7 @@ void MessagePortChannelRegistry::messagePortChannelCreated(MessagePortChannel& c void MessagePortChannelRegistry::messagePortChannelDestroyed(MessagePortChannel& channel) { - ASSERT(isMainThread()); + // ASSERT(isMainThread()); ASSERT(m_openChannels.get(channel.port1()) == &channel); ASSERT(m_openChannels.get(channel.port2()) == &channel); @@ -72,12 +75,12 @@ void MessagePortChannelRegistry::messagePortChannelDestroyed(MessagePortChannel& m_openChannels.remove(channel.port1()); m_openChannels.remove(channel.port2()); - LOG(MessagePorts, "Registry: After removing channel %s there are %u channels left in the registry:", channel.logString().utf8().data(), m_openChannels.size()); + // LOG(MessagePorts, "Registry: After removing channel %s there are %u channels left in the registry:", channel.logString().utf8().data(), m_openChannels.size()); } void MessagePortChannelRegistry::didEntangleLocalToRemote(const MessagePortIdentifier& local, const MessagePortIdentifier& remote, ProcessIdentifier process) { - ASSERT(isMainThread()); + // ASSERT(isMainThread()); // The channel might be gone if the remote side was closed. auto* channel = m_openChannels.get(local); @@ -91,7 +94,7 @@ void MessagePortChannelRegistry::didEntangleLocalToRemote(const MessagePortIdent void MessagePortChannelRegistry::didDisentangleMessagePort(const MessagePortIdentifier& port) { - ASSERT(isMainThread()); + // ASSERT(isMainThread()); // The channel might be gone if the remote side was closed. auto* channel = m_openChannels.get(port); @@ -103,17 +106,17 @@ void MessagePortChannelRegistry::didDisentangleMessagePort(const MessagePortIden void MessagePortChannelRegistry::didCloseMessagePort(const MessagePortIdentifier& port) { - ASSERT(isMainThread()); + // ASSERT(isMainThread()); - LOG(MessagePorts, "Registry: MessagePort %s closed in registry", port.logString().utf8().data()); + // LOG(MessagePorts, "Registry: MessagePort %s closed in registry", port.logString().utf8().data()); auto* channel = m_openChannels.get(port); if (!channel) return; #ifndef NDEBUG - if (channel && channel->hasAnyMessagesPendingOrInFlight()) - LOG(MessagePorts, "Registry: (Note) The channel closed for port %s had messages pending or in flight", port.logString().utf8().data()); + // if (channel && channel->hasAnyMessagesPendingOrInFlight()) + // LOG(MessagePorts, "Registry: (Note) The channel closed for port %s had messages pending or in flight", port.logString().utf8().data()); #endif channel->closePort(port); @@ -124,14 +127,14 @@ void MessagePortChannelRegistry::didCloseMessagePort(const MessagePortIdentifier bool MessagePortChannelRegistry::didPostMessageToRemote(MessageWithMessagePorts&& message, const MessagePortIdentifier& remoteTarget) { - ASSERT(isMainThread()); + // ASSERT(isMainThread()); - LOG(MessagePorts, "Registry: Posting message to MessagePort %s in registry", remoteTarget.logString().utf8().data()); + // LOG(MessagePorts, "Registry: Posting message to MessagePort %s in registry", remoteTarget.logString().utf8().data()); // The channel might be gone if the remote side was closed. auto* channel = m_openChannels.get(remoteTarget); if (!channel) { - LOG(MessagePorts, "Registry: Could not find MessagePortChannel for port %s; It was probably closed. Message will be dropped.", remoteTarget.logString().utf8().data()); + // LOG(MessagePorts, "Registry: Could not find MessagePortChannel for port %s; It was probably closed. Message will be dropped.", remoteTarget.logString().utf8().data()); return false; } @@ -140,9 +143,9 @@ bool MessagePortChannelRegistry::didPostMessageToRemote(MessageWithMessagePorts& void MessagePortChannelRegistry::takeAllMessagesForPort(const MessagePortIdentifier& port, CompletionHandler<void(Vector<MessageWithMessagePorts>&&, CompletionHandler<void()>&&)>&& callback) { - ASSERT(isMainThread()); + // ASSERT(isMainThread()); - LOG(MessagePorts, "Registry: Taking all messages for MessagePort %s", port.logString().utf8().data()); + // LOG(MessagePorts, "Registry: Taking all messages for MessagePort %s", port.logString().utf8().data()); // The channel might be gone if the remote side was closed. auto* channel = m_openChannels.get(port); @@ -156,9 +159,9 @@ void MessagePortChannelRegistry::takeAllMessagesForPort(const MessagePortIdentif std::optional<MessageWithMessagePorts> MessagePortChannelRegistry::tryTakeMessageForPort(const MessagePortIdentifier& port) { - ASSERT(isMainThread()); + // ASSERT(isMainThread()); - LOG(MessagePorts, "Registry: Trying to take a message for MessagePort %s", port.logString().utf8().data()); + // LOG(MessagePorts, "Registry: Trying to take a message for MessagePort %s", port.logString().utf8().data()); // The channel might be gone if the remote side was closed. auto* channel = m_openChannels.get(port); @@ -170,7 +173,7 @@ std::optional<MessageWithMessagePorts> MessagePortChannelRegistry::tryTakeMessag MessagePortChannel* MessagePortChannelRegistry::existingChannelContainingPort(const MessagePortIdentifier& port) { - ASSERT(isMainThread()); + // ASSERT(isMainThread()); return m_openChannels.get(port); } diff --git a/src/bun.js/bindings/webcore/WebCoreTypedArrayController.cpp b/src/bun.js/bindings/webcore/WebCoreTypedArrayController.cpp index ca8c79aef..5c8f4fbea 100644 --- a/src/bun.js/bindings/webcore/WebCoreTypedArrayController.cpp +++ b/src/bun.js/bindings/webcore/WebCoreTypedArrayController.cpp @@ -35,6 +35,16 @@ #include "JavaScriptCore/JSArrayBuffer.h" +extern "C" Zig::GlobalObject* Bun__getDefaultGlobal(); +static inline WebCore::JSDOMGlobalObject* getDefaultGlobal(JSC::JSGlobalObject* lexicalGlobalObject) +{ + if (auto* global = jsDynamicCast<WebCore::JSDOMGlobalObject*>(lexicalGlobalObject)) { + return global; + } + + return Bun__getDefaultGlobal(); +} + namespace WebCore { WebCoreTypedArrayController::WebCoreTypedArrayController(bool allowAtomicsWait) @@ -46,7 +56,7 @@ WebCoreTypedArrayController::~WebCoreTypedArrayController() = default; JSC::JSArrayBuffer* WebCoreTypedArrayController::toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSC::JSGlobalObject* globalObject, JSC::ArrayBuffer* buffer) { - return JSC::jsCast<JSC::JSArrayBuffer*>(WebCore::toJS(lexicalGlobalObject, JSC::jsCast<JSDOMGlobalObject*>(globalObject), buffer)); + return JSC::jsCast<JSC::JSArrayBuffer*>(WebCore::toJS(lexicalGlobalObject, getDefaultGlobal(globalObject), buffer)); } void WebCoreTypedArrayController::registerWrapper(JSC::JSGlobalObject* globalObject, JSC::ArrayBuffer* native, JSC::JSArrayBuffer* wrapper) diff --git a/src/bun.js/bindings/webcore/WebSocket.cpp b/src/bun.js/bindings/webcore/WebSocket.cpp index c1a4054f5..4f7f933c5 100644 --- a/src/bun.js/bindings/webcore/WebSocket.cpp +++ b/src/bun.js/bindings/webcore/WebSocket.cpp @@ -161,7 +161,6 @@ WebSocket::WebSocket(ScriptExecutionContext& context) { m_state = CONNECTING; m_hasPendingActivity.store(true); - ref(); } WebSocket::~WebSocket() @@ -650,7 +649,7 @@ ExceptionOr<void> WebSocket::close(std::optional<unsigned short> optionalCode, c ExceptionOr<void> WebSocket::terminate() { - LOG(Network, "WebSocket %p terminate()", this); + // LOG(Network, "WebSocket %p terminate()", this); if (m_state == CLOSING || m_state == CLOSED) return {}; @@ -692,7 +691,7 @@ ExceptionOr<void> WebSocket::terminate() ExceptionOr<void> WebSocket::ping() { auto message = WTF::String::number(WTF::jsCurrentTime()); - LOG(Network, "WebSocket %p ping() Sending Timestamp '%s'", this, message.data()); + // LOG(Network, "WebSocket %p ping() Sending Timestamp '%s'", this, message.data()); if (m_state == CONNECTING) return Exception { InvalidStateError }; @@ -711,7 +710,7 @@ ExceptionOr<void> WebSocket::ping() ExceptionOr<void> WebSocket::ping(const String& message) { - LOG(Network, "WebSocket %p ping() Sending String '%s'", this, message.utf8().data()); + // LOG(Network, "WebSocket %p ping() Sending String '%s'", this, message.utf8().data()); if (m_state == CONNECTING) return Exception { InvalidStateError }; @@ -731,7 +730,7 @@ ExceptionOr<void> WebSocket::ping(const String& message) ExceptionOr<void> WebSocket::ping(ArrayBuffer& binaryData) { - LOG(Network, "WebSocket %p ping() Sending ArrayBuffer %p", this, &binaryData); + // LOG(Network, "WebSocket %p ping() Sending ArrayBuffer %p", this, &binaryData); if (m_state == CONNECTING) return Exception { InvalidStateError }; @@ -751,7 +750,7 @@ ExceptionOr<void> WebSocket::ping(ArrayBuffer& binaryData) ExceptionOr<void> WebSocket::ping(ArrayBufferView& arrayBufferView) { - LOG(Network, "WebSocket %p ping() Sending ArrayBufferView %p", this, &arrayBufferView); + // LOG(Network, "WebSocket %p ping() Sending ArrayBufferView %p", this, &arrayBufferView); if (m_state == CONNECTING) return Exception { InvalidStateError }; @@ -774,7 +773,7 @@ ExceptionOr<void> WebSocket::ping(ArrayBufferView& arrayBufferView) ExceptionOr<void> WebSocket::pong() { auto message = WTF::String::number(WTF::jsCurrentTime()); - LOG(Network, "WebSocket %p pong() Sending Timestamp '%s'", this, message.data()); + // LOG(Network, "WebSocket %p pong() Sending Timestamp '%s'", this, message.data()); if (m_state == CONNECTING) return Exception { InvalidStateError }; @@ -793,7 +792,7 @@ ExceptionOr<void> WebSocket::pong() ExceptionOr<void> WebSocket::pong(const String& message) { - LOG(Network, "WebSocket %p pong() Sending String '%s'", this, message.utf8().data()); + // LOG(Network, "WebSocket %p pong() Sending String '%s'", this, message.utf8().data()); if (m_state == CONNECTING) return Exception { InvalidStateError }; @@ -813,7 +812,7 @@ ExceptionOr<void> WebSocket::pong(const String& message) ExceptionOr<void> WebSocket::pong(ArrayBuffer& binaryData) { - LOG(Network, "WebSocket %p pong() Sending ArrayBuffer %p", this, &binaryData); + // LOG(Network, "WebSocket %p pong() Sending ArrayBuffer %p", this, &binaryData); if (m_state == CONNECTING) return Exception { InvalidStateError }; @@ -833,7 +832,7 @@ ExceptionOr<void> WebSocket::pong(ArrayBuffer& binaryData) ExceptionOr<void> WebSocket::pong(ArrayBufferView& arrayBufferView) { - LOG(Network, "WebSocket %p pong() Sending ArrayBufferView %p", this, &arrayBufferView); + // LOG(Network, "WebSocket %p pong() Sending ArrayBufferView %p", this, &arrayBufferView); if (m_state == CONNECTING) return Exception { InvalidStateError }; @@ -1431,7 +1430,7 @@ extern "C" void WebSocket__didAbruptClose(WebCore::WebSocket* webSocket, int32_t { webSocket->didFailWithErrorCode(errorCode); } -extern "C" void WebSocket__didClose(WebCore::WebSocket* webSocket, uint16_t errorCode, const BunString *reason) +extern "C" void WebSocket__didClose(WebCore::WebSocket* webSocket, uint16_t errorCode, const BunString* reason) { WTF::String wtf_reason = Bun::toWTFString(*reason); webSocket->didClose(0, errorCode, WTFMove(wtf_reason)); diff --git a/src/bun.js/bindings/webcrypto/CryptoKeyAES.cpp b/src/bun.js/bindings/webcrypto/CryptoKeyAES.cpp index 17cbf48d9..ce23ce5dd 100644 --- a/src/bun.js/bindings/webcrypto/CryptoKeyAES.cpp +++ b/src/bun.js/bindings/webcrypto/CryptoKeyAES.cpp @@ -25,7 +25,7 @@ #include "config.h" #include "CryptoKeyAES.h" - +#include "../wtf-bindings.h" #if ENABLE(WEB_CRYPTO) #include "CryptoAesKeyAlgorithm.h" @@ -107,7 +107,7 @@ JsonWebKey CryptoKeyAES::exportJwk() const { JsonWebKey result; result.kty = "oct"_s; - result.k = base64URLEncodeToString(m_key); + result.k = Bun::base64URLEncodeToString(m_key); result.key_ops = usages(); result.ext = extractable(); return result; diff --git a/src/bun.js/bindings/webcrypto/CryptoKeyEC.h b/src/bun.js/bindings/webcrypto/CryptoKeyEC.h index f2cf7383f..8e8f5eb35 100644 --- a/src/bun.js/bindings/webcrypto/CryptoKeyEC.h +++ b/src/bun.js/bindings/webcrypto/CryptoKeyEC.h @@ -91,6 +91,8 @@ public: String namedCurveString() const; PlatformECKey platformKey() const { return m_platformKey.get(); } static bool isValidECAlgorithm(CryptoAlgorithmIdentifier); + static RefPtr<CryptoKeyEC> platformImportSpki(CryptoAlgorithmIdentifier, NamedCurve, Vector<uint8_t>&& keyData, bool extractable, CryptoKeyUsageBitmap); + static RefPtr<CryptoKeyEC> platformImportPkcs8(CryptoAlgorithmIdentifier, NamedCurve, Vector<uint8_t>&& keyData, bool extractable, CryptoKeyUsageBitmap); private: CryptoKeyEC(CryptoAlgorithmIdentifier, NamedCurve, CryptoKeyType, PlatformECKeyContainer&&, bool extractable, CryptoKeyUsageBitmap); @@ -104,8 +106,6 @@ private: static RefPtr<CryptoKeyEC> platformImportRaw(CryptoAlgorithmIdentifier, NamedCurve, Vector<uint8_t>&& keyData, bool extractable, CryptoKeyUsageBitmap); static RefPtr<CryptoKeyEC> platformImportJWKPublic(CryptoAlgorithmIdentifier, NamedCurve, Vector<uint8_t>&& x, Vector<uint8_t>&& y, bool extractable, CryptoKeyUsageBitmap); static RefPtr<CryptoKeyEC> platformImportJWKPrivate(CryptoAlgorithmIdentifier, NamedCurve, Vector<uint8_t>&& x, Vector<uint8_t>&& y, Vector<uint8_t>&& d, bool extractable, CryptoKeyUsageBitmap); - static RefPtr<CryptoKeyEC> platformImportSpki(CryptoAlgorithmIdentifier, NamedCurve, Vector<uint8_t>&& keyData, bool extractable, CryptoKeyUsageBitmap); - static RefPtr<CryptoKeyEC> platformImportPkcs8(CryptoAlgorithmIdentifier, NamedCurve, Vector<uint8_t>&& keyData, bool extractable, CryptoKeyUsageBitmap); Vector<uint8_t> platformExportRaw() const; bool platformAddFieldElements(JsonWebKey&) const; Vector<uint8_t> platformExportSpki() const; diff --git a/src/bun.js/bindings/webcrypto/CryptoKeyECOpenSSL.cpp b/src/bun.js/bindings/webcrypto/CryptoKeyECOpenSSL.cpp index bb5dc5e62..c2b363b32 100644 --- a/src/bun.js/bindings/webcrypto/CryptoKeyECOpenSSL.cpp +++ b/src/bun.js/bindings/webcrypto/CryptoKeyECOpenSSL.cpp @@ -25,6 +25,7 @@ #include "config.h" #include "CryptoKeyEC.h" +#include "../wtf-bindings.h" #if ENABLE(WEB_CRYPTO) @@ -408,15 +409,15 @@ bool CryptoKeyEC::platformAddFieldElements(JsonWebKey& jwk) const auto x = BIGNUMPtr(BN_new()); auto y = BIGNUMPtr(BN_new()); if (1 == EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(key), publicKey, x.get(), y.get(), ctx.get())) { - jwk.x = base64URLEncodeToString(convertToBytesExpand(x.get(), keySizeInBytes)); - jwk.y = base64URLEncodeToString(convertToBytesExpand(y.get(), keySizeInBytes)); + jwk.x = Bun::base64URLEncodeToString(convertToBytesExpand(x.get(), keySizeInBytes)); + jwk.y = Bun::base64URLEncodeToString(convertToBytesExpand(y.get(), keySizeInBytes)); } } if (type() == Type::Private) { const BIGNUM* privateKey = EC_KEY_get0_private_key(key); if (privateKey) - jwk.d = base64URLEncodeToString(convertToBytes(privateKey)); + jwk.d = Bun::base64URLEncodeToString(convertToBytes(privateKey)); } return true; } diff --git a/src/bun.js/bindings/webcrypto/CryptoKeyHMAC.cpp b/src/bun.js/bindings/webcrypto/CryptoKeyHMAC.cpp index aafb3b2fe..9428998cb 100644 --- a/src/bun.js/bindings/webcrypto/CryptoKeyHMAC.cpp +++ b/src/bun.js/bindings/webcrypto/CryptoKeyHMAC.cpp @@ -25,6 +25,7 @@ #include "config.h" #include "CryptoKeyHMAC.h" +#include "../wtf-bindings.h" #if ENABLE(WEB_CRYPTO) @@ -69,6 +70,13 @@ CryptoKeyHMAC::CryptoKeyHMAC(Vector<uint8_t>&& key, CryptoAlgorithmIdentifier ha CryptoKeyHMAC::~CryptoKeyHMAC() = default; + +RefPtr<CryptoKeyHMAC> CryptoKeyHMAC::generateFromBytes(void* data, size_t byteLength, CryptoAlgorithmIdentifier hash, bool extractable, CryptoKeyUsageBitmap usages) { + + Vector<uint8_t> vec_data((uint8_t*)data, byteLength); + return adoptRef(new CryptoKeyHMAC(vec_data, hash, extractable, usages)); +} + RefPtr<CryptoKeyHMAC> CryptoKeyHMAC::generate(size_t lengthBits, CryptoAlgorithmIdentifier hash, bool extractable, CryptoKeyUsageBitmap usages) { if (!lengthBits) { @@ -118,11 +126,13 @@ RefPtr<CryptoKeyHMAC> CryptoKeyHMAC::importJwk(size_t lengthBits, CryptoAlgorith return CryptoKeyHMAC::importRaw(lengthBits, hash, WTFMove(*octetSequence), extractable, usages); } + JsonWebKey CryptoKeyHMAC::exportJwk() const -{ +{ + JsonWebKey result; result.kty = "oct"_s; - result.k = base64URLEncodeToString(m_key); + result.k = Bun::base64URLEncodeToString(m_key); result.key_ops = usages(); result.ext = extractable(); return result; diff --git a/src/bun.js/bindings/webcrypto/CryptoKeyHMAC.h b/src/bun.js/bindings/webcrypto/CryptoKeyHMAC.h index 0c7ba38cb..714888019 100644 --- a/src/bun.js/bindings/webcrypto/CryptoKeyHMAC.h +++ b/src/bun.js/bindings/webcrypto/CryptoKeyHMAC.h @@ -43,9 +43,11 @@ public: { return adoptRef(*new CryptoKeyHMAC(key, hash, extractable, usage)); } + virtual ~CryptoKeyHMAC(); static RefPtr<CryptoKeyHMAC> generate(size_t lengthBits, CryptoAlgorithmIdentifier hash, bool extractable, CryptoKeyUsageBitmap); + static RefPtr<CryptoKeyHMAC> generateFromBytes(void* data, size_t byteLength, CryptoAlgorithmIdentifier hash, bool extractable, CryptoKeyUsageBitmap); static RefPtr<CryptoKeyHMAC> importRaw(size_t lengthBits, CryptoAlgorithmIdentifier hash, Vector<uint8_t>&& keyData, bool extractable, CryptoKeyUsageBitmap); using CheckAlgCallback = Function<bool(CryptoAlgorithmIdentifier, const String&)>; static RefPtr<CryptoKeyHMAC> importJwk(size_t lengthBits, CryptoAlgorithmIdentifier hash, JsonWebKey&&, bool extractable, CryptoKeyUsageBitmap, CheckAlgCallback&&); diff --git a/src/bun.js/bindings/webcrypto/CryptoKeyOKP.cpp b/src/bun.js/bindings/webcrypto/CryptoKeyOKP.cpp index b7dc55018..4b5d8d588 100644 --- a/src/bun.js/bindings/webcrypto/CryptoKeyOKP.cpp +++ b/src/bun.js/bindings/webcrypto/CryptoKeyOKP.cpp @@ -119,14 +119,13 @@ RefPtr<CryptoKeyOKP> CryptoKeyOKP::importRaw(CryptoAlgorithmIdentifier identifie return create(identifier, namedCurve, usages & CryptoKeyUsageSign ? CryptoKeyType::Private : CryptoKeyType::Public, WTFMove(keyData), extractable, usages); } -RefPtr<CryptoKeyOKP> CryptoKeyOKP::importJwk(CryptoAlgorithmIdentifier identifier, NamedCurve namedCurve, JsonWebKey&& keyData, bool extractable, CryptoKeyUsageBitmap usages) -{ +RefPtr<CryptoKeyOKP> CryptoKeyOKP::importJwkInternal(CryptoAlgorithmIdentifier identifier, NamedCurve namedCurve, JsonWebKey&& keyData, bool extractable, CryptoKeyUsageBitmap usages, bool onlyPublic) { if (!isPlatformSupportedCurve(namedCurve)) return nullptr; switch (namedCurve) { case NamedCurve::Ed25519: - if (!keyData.d.isEmpty()) { + if (!keyData.d.isEmpty() && !onlyPublic) { if (usages & (CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt | CryptoKeyUsageVerify | CryptoKeyUsageDeriveKey | CryptoKeyUsageDeriveBits | CryptoKeyUsageWrapKey | CryptoKeyUsageUnwrapKey)) return nullptr; } else { @@ -137,8 +136,6 @@ RefPtr<CryptoKeyOKP> CryptoKeyOKP::importJwk(CryptoAlgorithmIdentifier identifie return nullptr; if (keyData.crv != "Ed25519"_s) return nullptr; - if (!keyData.alg.isEmpty() && keyData.alg != "EdDSA"_s) - return nullptr; if (usages && !keyData.use.isEmpty() && keyData.use != "sig"_s) return nullptr; if (keyData.key_ops && ((keyData.usages & usages) != usages)) @@ -153,12 +150,14 @@ RefPtr<CryptoKeyOKP> CryptoKeyOKP::importJwk(CryptoAlgorithmIdentifier identifie break; } - if (!keyData.d.isNull()) { - // FIXME: Validate keyData.x is paired with keyData.d - auto d = base64URLDecode(keyData.d); - if (!d) - return nullptr; - return create(identifier, namedCurve, CryptoKeyType::Private, WTFMove(*d), extractable, usages); + if(!onlyPublic){ + if (!keyData.d.isNull()) { + // FIXME: Validate keyData.x is paired with keyData.d + auto d = base64URLDecode(keyData.d); + if (!d) + return nullptr; + return create(identifier, namedCurve, CryptoKeyType::Private, WTFMove(*d), extractable, usages); + } } if (keyData.x.isNull()) @@ -168,6 +167,14 @@ RefPtr<CryptoKeyOKP> CryptoKeyOKP::importJwk(CryptoAlgorithmIdentifier identifie if (!x) return nullptr; return create(identifier, namedCurve, CryptoKeyType::Public, WTFMove(*x), extractable, usages); +} + +RefPtr<CryptoKeyOKP> CryptoKeyOKP::importPublicJwk(CryptoAlgorithmIdentifier identifier, NamedCurve namedCurve, JsonWebKey&& keyData, bool extractable, CryptoKeyUsageBitmap usages) { + return importJwkInternal(identifier, namedCurve, WTFMove(keyData), extractable, usages, true); +} +RefPtr<CryptoKeyOKP> CryptoKeyOKP::importJwk(CryptoAlgorithmIdentifier identifier, NamedCurve namedCurve, JsonWebKey&& keyData, bool extractable, CryptoKeyUsageBitmap usages) +{ + return importJwkInternal(identifier, namedCurve, WTFMove(keyData), extractable, usages, false); } ExceptionOr<Vector<uint8_t>> CryptoKeyOKP::exportRaw() const diff --git a/src/bun.js/bindings/webcrypto/CryptoKeyOKP.h b/src/bun.js/bindings/webcrypto/CryptoKeyOKP.h index cc1fe2c73..4d521227f 100644 --- a/src/bun.js/bindings/webcrypto/CryptoKeyOKP.h +++ b/src/bun.js/bindings/webcrypto/CryptoKeyOKP.h @@ -48,6 +48,7 @@ public: WEBCORE_EXPORT static ExceptionOr<CryptoKeyPair> generatePair(CryptoAlgorithmIdentifier, NamedCurve, bool extractable, CryptoKeyUsageBitmap); WEBCORE_EXPORT static RefPtr<CryptoKeyOKP> importRaw(CryptoAlgorithmIdentifier, NamedCurve, Vector<uint8_t>&& keyData, bool extractable, CryptoKeyUsageBitmap); + static RefPtr<CryptoKeyOKP> importPublicJwk(CryptoAlgorithmIdentifier, NamedCurve, JsonWebKey&&, bool extractable, CryptoKeyUsageBitmap); static RefPtr<CryptoKeyOKP> importJwk(CryptoAlgorithmIdentifier, NamedCurve, JsonWebKey&&, bool extractable, CryptoKeyUsageBitmap); static RefPtr<CryptoKeyOKP> importSpki(CryptoAlgorithmIdentifier, NamedCurve, Vector<uint8_t>&& keyData, bool extractable, CryptoKeyUsageBitmap); static RefPtr<CryptoKeyOKP> importPkcs8(CryptoAlgorithmIdentifier, NamedCurve, Vector<uint8_t>&& keyData, bool extractable, CryptoKeyUsageBitmap); @@ -88,6 +89,7 @@ private: Vector<uint8_t> platformExportRaw() const; Vector<uint8_t> platformExportSpki() const; Vector<uint8_t> platformExportPkcs8() const; + static RefPtr<CryptoKeyOKP> importJwkInternal(CryptoAlgorithmIdentifier identifier, NamedCurve namedCurve, JsonWebKey&& keyData, bool extractable, CryptoKeyUsageBitmap usages, bool onlyPublic); NamedCurve m_curve; KeyMaterial m_data; diff --git a/src/bun.js/bindings/webcrypto/CryptoKeyOKPOpenSSL.cpp b/src/bun.js/bindings/webcrypto/CryptoKeyOKPOpenSSL.cpp index ea3a4d498..82e352d0a 100644 --- a/src/bun.js/bindings/webcrypto/CryptoKeyOKPOpenSSL.cpp +++ b/src/bun.js/bindings/webcrypto/CryptoKeyOKPOpenSSL.cpp @@ -25,7 +25,7 @@ #include "config.h" #include "CryptoKeyOKP.h" - +#include "../wtf-bindings.h" #if ENABLE(WEB_CRYPTO) #include "JsonWebKey.h" @@ -296,9 +296,9 @@ String CryptoKeyOKP::generateJwkD() const ASSERT(type() == CryptoKeyType::Private); if (namedCurve() == NamedCurve::Ed25519) { ASSERT(m_exportKey); - return base64URLEncodeToString(*m_exportKey); + return Bun::base64URLEncodeToString(*m_exportKey); } - return base64URLEncodeToString(m_data); + return Bun::base64URLEncodeToString(m_data); } CryptoKeyOKP::KeyMaterial CryptoKeyOKP::ed25519PublicFromPrivate(const KeyMaterial& seed) @@ -333,15 +333,15 @@ CryptoKeyOKP::KeyMaterial CryptoKeyOKP::ed25519PrivateFromSeed(KeyMaterial&& see String CryptoKeyOKP::generateJwkX() const { if (type() == CryptoKeyType::Public) - return base64URLEncodeToString(m_data); + return Bun::base64URLEncodeToString(m_data); ASSERT(type() == CryptoKeyType::Private); if (namedCurve() == NamedCurve::Ed25519) - return base64URLEncodeToString(WTFMove(ed25519PublicFromPrivate(const_cast<KeyMaterial&>(m_data)))); + return Bun::base64URLEncodeToString(WTFMove(ed25519PublicFromPrivate(const_cast<KeyMaterial&>(m_data)))); ASSERT(namedCurve() == NamedCurve::X25519); - return base64URLEncodeToString(WTFMove(x25519PublicFromPrivate(const_cast<KeyMaterial&>(m_data)))); + return Bun::base64URLEncodeToString(WTFMove(x25519PublicFromPrivate(const_cast<KeyMaterial&>(m_data)))); } CryptoKeyOKP::KeyMaterial CryptoKeyOKP::platformExportRaw() const diff --git a/src/bun.js/bindings/webcrypto/CryptoKeyRSA.cpp b/src/bun.js/bindings/webcrypto/CryptoKeyRSA.cpp index 273218721..859767107 100644 --- a/src/bun.js/bindings/webcrypto/CryptoKeyRSA.cpp +++ b/src/bun.js/bindings/webcrypto/CryptoKeyRSA.cpp @@ -28,6 +28,7 @@ #include "CryptoKeyRSAComponents.h" #include "JsonWebKey.h" +#include "../wtf-bindings.h" #include <wtf/text/Base64.h> #if ENABLE(WEB_CRYPTO) @@ -143,30 +144,30 @@ JsonWebKey CryptoKeyRSA::exportJwk() const return result; // public key - result.n = base64URLEncodeToString(rsaComponents->modulus()); - result.e = base64URLEncodeToString(rsaComponents->exponent()); + result.n = Bun::base64URLEncodeToString(rsaComponents->modulus()); + result.e = Bun::base64URLEncodeToString(rsaComponents->exponent()); if (rsaComponents->type() == CryptoKeyRSAComponents::Type::Public) return result; // private key - result.d = base64URLEncodeToString(rsaComponents->privateExponent()); + result.d = Bun::base64URLEncodeToString(rsaComponents->privateExponent()); if (!rsaComponents->hasAdditionalPrivateKeyParameters()) return result; - result.p = base64URLEncodeToString(rsaComponents->firstPrimeInfo().primeFactor); - result.q = base64URLEncodeToString(rsaComponents->secondPrimeInfo().primeFactor); - result.dp = base64URLEncodeToString(rsaComponents->firstPrimeInfo().factorCRTExponent); - result.dq = base64URLEncodeToString(rsaComponents->secondPrimeInfo().factorCRTExponent); - result.qi = base64URLEncodeToString(rsaComponents->secondPrimeInfo().factorCRTCoefficient); + result.p = Bun::base64URLEncodeToString(rsaComponents->firstPrimeInfo().primeFactor); + result.q = Bun::base64URLEncodeToString(rsaComponents->secondPrimeInfo().primeFactor); + result.dp = Bun::base64URLEncodeToString(rsaComponents->firstPrimeInfo().factorCRTExponent); + result.dq = Bun::base64URLEncodeToString(rsaComponents->secondPrimeInfo().factorCRTExponent); + result.qi = Bun::base64URLEncodeToString(rsaComponents->secondPrimeInfo().factorCRTCoefficient); if (rsaComponents->otherPrimeInfos().isEmpty()) return result; Vector<RsaOtherPrimesInfo> oth; for (const auto& info : rsaComponents->otherPrimeInfos()) { RsaOtherPrimesInfo otherInfo; - otherInfo.r = base64URLEncodeToString(info.primeFactor); - otherInfo.d = base64URLEncodeToString(info.factorCRTExponent); - otherInfo.t = base64URLEncodeToString(info.factorCRTCoefficient); + otherInfo.r = Bun::base64URLEncodeToString(info.primeFactor); + otherInfo.d = Bun::base64URLEncodeToString(info.factorCRTExponent); + otherInfo.t = Bun::base64URLEncodeToString(info.factorCRTCoefficient); oth.append(WTFMove(otherInfo)); } result.oth = WTFMove(oth); diff --git a/src/bun.js/bindings/webcrypto/JSCryptoKey.cpp b/src/bun.js/bindings/webcrypto/JSCryptoKey.cpp index d2ec84afb..5b38d78c9 100644 --- a/src/bun.js/bindings/webcrypto/JSCryptoKey.cpp +++ b/src/bun.js/bindings/webcrypto/JSCryptoKey.cpp @@ -196,6 +196,8 @@ void JSCryptoKey::finishCreation(VM& vm) // static_assert(!std::is_base_of<ActiveDOMObject, CryptoKey>::value, "Interface is not marked as [ActiveDOMObject] even though implementation class subclasses ActiveDOMObject."); } + + JSObject* JSCryptoKey::createPrototype(VM& vm, JSDOMGlobalObject& globalObject) { return JSCryptoKeyPrototype::create(vm, &globalObject, JSCryptoKeyPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype())); diff --git a/src/bun.js/bindings/webcrypto/JSJsonWebKey.cpp b/src/bun.js/bindings/webcrypto/JSJsonWebKey.cpp index 39ed1ff31..067421303 100644 --- a/src/bun.js/bindings/webcrypto/JSJsonWebKey.cpp +++ b/src/bun.js/bindings/webcrypto/JSJsonWebKey.cpp @@ -256,7 +256,7 @@ template<> JsonWebKey convertDictionary<JsonWebKey>(JSGlobalObject& lexicalGloba return result; } -JSC::JSObject* convertDictionaryToJS(JSC::JSGlobalObject& lexicalGlobalObject, JSDOMGlobalObject& globalObject, const JsonWebKey& dictionary) +JSC::JSObject* convertDictionaryToJS(JSC::JSGlobalObject& lexicalGlobalObject, JSDOMGlobalObject& globalObject, const JsonWebKey& dictionary, bool ignoreExtAndKeyOps) { auto& vm = JSC::getVM(&lexicalGlobalObject); auto throwScope = DECLARE_THROW_SCOPE(vm); @@ -293,7 +293,7 @@ JSC::JSObject* convertDictionaryToJS(JSC::JSGlobalObject& lexicalGlobalObject, J RETURN_IF_EXCEPTION(throwScope, { }); result->putDirect(vm, JSC::Identifier::fromString(vm, "e"_s), eValue); } - if (!IDLBoolean::isNullValue(dictionary.ext)) { + if (!ignoreExtAndKeyOps && !IDLBoolean::isNullValue(dictionary.ext)) { auto extValue = toJS<IDLBoolean>(lexicalGlobalObject, throwScope, IDLBoolean::extractValueFromNullable(dictionary.ext)); RETURN_IF_EXCEPTION(throwScope, { }); result->putDirect(vm, JSC::Identifier::fromString(vm, "ext"_s), extValue); @@ -303,7 +303,7 @@ JSC::JSObject* convertDictionaryToJS(JSC::JSGlobalObject& lexicalGlobalObject, J RETURN_IF_EXCEPTION(throwScope, { }); result->putDirect(vm, JSC::Identifier::fromString(vm, "k"_s), kValue); } - if (!IDLSequence<IDLEnumeration<CryptoKeyUsage>>::isNullValue(dictionary.key_ops)) { + if (!ignoreExtAndKeyOps && !IDLSequence<IDLEnumeration<CryptoKeyUsage>>::isNullValue(dictionary.key_ops)) { auto key_opsValue = toJS<IDLSequence<IDLEnumeration<CryptoKeyUsage>>>(lexicalGlobalObject, globalObject, throwScope, IDLSequence<IDLEnumeration<CryptoKeyUsage>>::extractValueFromNullable(dictionary.key_ops)); RETURN_IF_EXCEPTION(throwScope, { }); result->putDirect(vm, JSC::Identifier::fromString(vm, "key_ops"_s), key_opsValue); diff --git a/src/bun.js/bindings/webcrypto/JSJsonWebKey.h b/src/bun.js/bindings/webcrypto/JSJsonWebKey.h index 07e7960be..c1b287c4d 100644 --- a/src/bun.js/bindings/webcrypto/JSJsonWebKey.h +++ b/src/bun.js/bindings/webcrypto/JSJsonWebKey.h @@ -29,7 +29,7 @@ namespace WebCore { template<> JsonWebKey convertDictionary<JsonWebKey>(JSC::JSGlobalObject&, JSC::JSValue); -JSC::JSObject* convertDictionaryToJS(JSC::JSGlobalObject&, JSDOMGlobalObject&, const JsonWebKey&); +JSC::JSObject* convertDictionaryToJS(JSC::JSGlobalObject&, JSDOMGlobalObject&, const JsonWebKey&, bool ignoreExtAndKeyOps = false); } // namespace WebCore diff --git a/src/bun.js/bindings/wtf-bindings.cpp b/src/bun.js/bindings/wtf-bindings.cpp index d05fb255b..2ec3d7ee8 100644 --- a/src/bun.js/bindings/wtf-bindings.cpp +++ b/src/bun.js/bindings/wtf-bindings.cpp @@ -237,4 +237,24 @@ extern "C" size_t WTF__base64URLEncode(const unsigned char* __restrict inputData destinationDataBuffer[didx++] = '='; return destinationDataBufferSize; -}
\ No newline at end of file +} + +namespace Bun { +String base64URLEncodeToString(Vector<uint8_t> data) +{ + auto size = data.size(); + size_t encodedLength = ((size * 4) + 2) / 3; + if (!encodedLength) + return String(); + + LChar* ptr; + auto result = String::createUninitialized(encodedLength, ptr); + if (UNLIKELY(!ptr)) { + RELEASE_ASSERT_NOT_REACHED(); + return String(); + } + encodedLength = WTF__base64URLEncode(data.data(), data.size(), ptr, encodedLength); + RELEASE_ASSERT(result.length() == encodedLength); + return result; +} +} diff --git a/src/bun.js/bindings/wtf-bindings.h b/src/bun.js/bindings/wtf-bindings.h index 1721b0e1c..3df543934 100644 --- a/src/bun.js/bindings/wtf-bindings.h +++ b/src/bun.js/bindings/wtf-bindings.h @@ -4,3 +4,7 @@ #include "wtf/text/ASCIIFastPath.h" extern "C" void WTF__copyLCharsFromUCharSource(LChar* destination, const UChar* source, size_t length); + +namespace Bun { +String base64URLEncodeToString(Vector<uint8_t> data); +}
\ No newline at end of file diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index f22d8793a..bdee2cefb 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -118,6 +118,7 @@ pub fn WorkTask(comptime Context: type, comptime async_io: bool) type { } pub fn runFromThreadPool(task: *TaskType) void { + JSC.markBinding(@src()); var this = @fieldParentPtr(This, "task", task); Context.run(this.ctx, this); } @@ -303,6 +304,48 @@ const PollPendingModulesTask = JSC.ModuleLoader.AsyncModule.Queue; // const PromiseTask = JSInternalPromise.Completion.PromiseTask; const GetAddrInfoRequestTask = JSC.DNS.GetAddrInfoRequest.Task; const JSCDeferredWorkTask = JSCScheduler.JSCDeferredWorkTask; + +const Stat = JSC.Node.Async.stat; +const Lstat = JSC.Node.Async.lstat; +const Fstat = JSC.Node.Async.fstat; +const Open = JSC.Node.Async.open; +const ReadFile = JSC.Node.Async.readFile; +const WriteFile = JSC.Node.Async.writeFile; +const CopyFile = JSC.Node.Async.copyFile; +const Read = JSC.Node.Async.read; +const Write = JSC.Node.Async.write; +const Truncate = JSC.Node.Async.truncate; +const FTruncate = JSC.Node.Async.ftruncate; +const Readdir = JSC.Node.Async.readdir; +const Readv = JSC.Node.Async.readv; +const Writev = JSC.Node.Async.writev; +const Close = JSC.Node.Async.close; +const Rm = JSC.Node.Async.rm; +const Rmdir = JSC.Node.Async.rmdir; +const Chown = JSC.Node.Async.chown; +const FChown = JSC.Node.Async.fchown; +const Utimes = JSC.Node.Async.utimes; +const Lutimes = JSC.Node.Async.lutimes; +const Chmod = JSC.Node.Async.chmod; +const Fchmod = JSC.Node.Async.fchmod; +const Link = JSC.Node.Async.link; +const Symlink = JSC.Node.Async.symlink; +const Readlink = JSC.Node.Async.readlink; +const Realpath = JSC.Node.Async.realpath; +const Mkdir = JSC.Node.Async.mkdir; +const Fsync = JSC.Node.Async.fsync; +const Rename = JSC.Node.Async.rename; +const Fdatasync = JSC.Node.Async.fdatasync; +const Access = JSC.Node.Async.access; +const AppendFile = JSC.Node.Async.appendFile; +const Mkdtemp = JSC.Node.Async.mkdtemp; +const Exists = JSC.Node.Async.exists; +const Futimes = JSC.Node.Async.futimes; +const Lchmod = JSC.Node.Async.lchmod; +const Lchown = JSC.Node.Async.lchown; +const Unlink = JSC.Node.Async.unlink; + +// Task.get(ReadFileTask) -> ?ReadFileTask pub const Task = TaggedPointerUnion(.{ FetchTasklet, Microtask, @@ -321,13 +364,49 @@ pub const Task = TaggedPointerUnion(.{ GetAddrInfoRequestTask, FSWatchTask, JSCDeferredWorkTask, - - // PromiseTask, - // TimeoutTasklet, + Stat, + Lstat, + Fstat, + Open, + ReadFile, + WriteFile, + CopyFile, + Read, + Write, + Truncate, + FTruncate, + Readdir, + Close, + Rm, + Rmdir, + Chown, + FChown, + Utimes, + Lutimes, + Chmod, + Fchmod, + Link, + Symlink, + Readlink, + Realpath, + Mkdir, + Fsync, + Fdatasync, + Writev, + Readv, + Rename, + Access, + AppendFile, + Mkdtemp, + Exists, + Futimes, + Lchmod, + Lchown, + Unlink, }); const UnboundedQueue = @import("./unbounded_queue.zig").UnboundedQueue; pub const ConcurrentTask = struct { - task: Task = undefined, + task: if (JSC.is_bindgen) void else Task = undefined, next: ?*ConcurrentTask = null, auto_delete: bool = false, @@ -348,14 +427,19 @@ pub const ConcurrentTask = struct { } pub fn createFrom(task: anytype) *ConcurrentTask { + JSC.markBinding(@src()); return create(Task.init(task)); } pub fn fromCallback(ptr: anytype, comptime callback: anytype) *ConcurrentTask { + JSC.markBinding(@src()); + return create(ManagedTask.New(std.meta.Child(@TypeOf(ptr)), callback).init(ptr)); } pub fn from(this: *ConcurrentTask, of: anytype, auto_deinit: AutoDeinit) *ConcurrentTask { + JSC.markBinding(@src()); + this.* = .{ .task = Task.init(of), .next = null, @@ -377,6 +461,7 @@ pub const GarbageCollectionController = struct { gc_repeating_timer: *uws.Timer = undefined, gc_timer_interval: i32 = 0, gc_repeating_timer_fast: bool = true, + disabled: bool = false, pub fn init(this: *GarbageCollectionController, vm: *VirtualMachine) void { var actual = vm.event_loop_handle.?; @@ -391,8 +476,12 @@ pub const GarbageCollectionController = struct { } } else |_| {} } - this.gc_repeating_timer.set(this, onGCRepeatingTimer, gc_timer_interval, gc_timer_interval); this.gc_timer_interval = gc_timer_interval; + + this.disabled = vm.bundler.env.has("BUN_GC_TIMER_DISABLE"); + + if (!this.disabled) + this.gc_repeating_timer.set(this, onGCRepeatingTimer, gc_timer_interval, gc_timer_interval); } pub fn scheduleGCTimer(this: *GarbageCollectionController) void { @@ -406,6 +495,7 @@ pub const GarbageCollectionController = struct { pub fn onGCTimer(timer: *uws.Timer) callconv(.C) void { var this = timer.as(*GarbageCollectionController); + if (this.disabled) return; this.gc_timer_state = .run_on_next_tick; } @@ -450,11 +540,12 @@ pub const GarbageCollectionController = struct { } pub fn processGCTimer(this: *GarbageCollectionController) void { - var vm = this.bunVM().global.vm(); + if (this.disabled) return; + var vm = this.bunVM().jsc; this.processGCTimerWithHeapSize(vm, vm.blockBytesAllocated()); } - pub fn processGCTimerWithHeapSize(this: *GarbageCollectionController, vm: *JSC.VM, this_heap_size: usize) void { + fn processGCTimerWithHeapSize(this: *GarbageCollectionController, vm: *JSC.VM, this_heap_size: usize) void { const prev = this.gc_last_heap_size; switch (this.gc_timer_state) { @@ -490,7 +581,8 @@ pub const GarbageCollectionController = struct { } pub fn performGC(this: *GarbageCollectionController) void { - var vm = this.bunVM().global.vm(); + if (this.disabled) return; + var vm = this.bunVM().jsc; vm.collectAsync(); this.gc_last_heap_size = vm.blockBytesAllocated(); } @@ -515,7 +607,7 @@ comptime { pub const DeferredRepeatingTask = *const (fn (*anyopaque) bool); pub const EventLoop = struct { - tasks: Queue = undefined, + tasks: if (JSC.is_bindgen) void else Queue = undefined, concurrent_tasks: ConcurrentTask.Queue = ConcurrentTask.Queue{}, global: *JSGlobalObject = undefined, virtual_machine: *JSC.VirtualMachine = undefined, @@ -530,7 +622,7 @@ pub const EventLoop = struct { pub fn tickWhilePaused(this: *EventLoop, done: *bool) void { while (!done.*) { - this.virtual_machine.event_loop_handle.?.tick(); + this.virtual_machine.event_loop_handle.?.tick(this.virtual_machine.jsc); } } extern fn JSC__JSGlobalObject__drainMicrotasks(*JSC.JSGlobalObject) void; @@ -662,6 +754,162 @@ pub const EventLoop = struct { any.runFromJS(); any.deinit(); }, + @field(Task.Tag, typeBaseName(@typeName(Stat))) => { + var any: *Stat = task.get(Stat).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Lstat))) => { + var any: *Lstat = task.get(Lstat).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Fstat))) => { + var any: *Fstat = task.get(Fstat).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Open))) => { + var any: *Open = task.get(Open).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(ReadFile))) => { + var any: *ReadFile = task.get(ReadFile).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(WriteFile))) => { + var any: *WriteFile = task.get(WriteFile).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(CopyFile))) => { + var any: *CopyFile = task.get(CopyFile).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Read))) => { + var any: *Read = task.get(Read).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Write))) => { + var any: *Write = task.get(Write).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Truncate))) => { + var any: *Truncate = task.get(Truncate).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Writev))) => { + var any: *Writev = task.get(Writev).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Readv))) => { + var any: *Readv = task.get(Readv).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Rename))) => { + var any: *Rename = task.get(Rename).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(FTruncate))) => { + var any: *FTruncate = task.get(FTruncate).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Readdir))) => { + var any: *Readdir = task.get(Readdir).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Close))) => { + var any: *Close = task.get(Close).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Rm))) => { + var any: *Rm = task.get(Rm).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Rmdir))) => { + var any: *Rmdir = task.get(Rmdir).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Chown))) => { + var any: *Chown = task.get(Chown).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(FChown))) => { + var any: *FChown = task.get(FChown).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Utimes))) => { + var any: *Utimes = task.get(Utimes).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Lutimes))) => { + var any: *Lutimes = task.get(Lutimes).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Chmod))) => { + var any: *Chmod = task.get(Chmod).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Fchmod))) => { + var any: *Fchmod = task.get(Fchmod).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Link))) => { + var any: *Link = task.get(Link).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Symlink))) => { + var any: *Symlink = task.get(Symlink).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Readlink))) => { + var any: *Readlink = task.get(Readlink).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Realpath))) => { + var any: *Realpath = task.get(Realpath).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Mkdir))) => { + var any: *Mkdir = task.get(Mkdir).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Fsync))) => { + var any: *Fsync = task.get(Fsync).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Fdatasync))) => { + var any: *Fdatasync = task.get(Fdatasync).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Access))) => { + var any: *Access = task.get(Access).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(AppendFile))) => { + var any: *AppendFile = task.get(AppendFile).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Mkdtemp))) => { + var any: *Mkdtemp = task.get(Mkdtemp).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Exists))) => { + var any: *Exists = task.get(Exists).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Futimes))) => { + var any: *Futimes = task.get(Futimes).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Lchmod))) => { + var any: *Lchmod = task.get(Lchmod).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Lchown))) => { + var any: *Lchown = task.get(Lchown).?; + any.runFromJSThread(); + }, + @field(Task.Tag, typeBaseName(@typeName(Unlink))) => { + var any: *Unlink = task.get(Unlink).?; + any.runFromJSThread(); + }, else => if (Environment.allow_assert) { bun.Output.prettyln("\nUnexpected tag: {s}\n", .{@tagName(task.tag())}); } else { @@ -683,6 +931,7 @@ pub const EventLoop = struct { } pub fn tickConcurrentWithCount(this: *EventLoop) usize { + JSC.markBinding(@src()); var concurrent = this.concurrent_tasks.popBatch(); const count = concurrent.count; if (count == 0) @@ -740,8 +989,9 @@ pub const EventLoop = struct { } if (loop.num_polls > 0 or loop.active > 0) { - loop.tick(); this.processGCTimer(); + loop.tick(ctx.jsc); + ctx.onAfterEventLoop(); // this.afterUSocketsTick(); } @@ -764,8 +1014,8 @@ pub const EventLoop = struct { } if (loop.num_polls > 0 or loop.active > 0) { - loop.tickWithTimeout(timeoutMs); this.processGCTimer(); + loop.tickWithTimeout(timeoutMs, ctx.jsc); ctx.onAfterEventLoop(); // this.afterUSocketsTick(); } @@ -789,8 +1039,8 @@ pub const EventLoop = struct { } } - loop.tick(); this.processGCTimer(); + loop.tick(ctx.jsc); ctx.onAfterEventLoop(); this.tickConcurrent(); this.tick(); @@ -812,8 +1062,8 @@ pub const EventLoop = struct { } if (loop.active > 0) { - loop.tick(); this.processGCTimer(); + loop.tick(ctx.jsc); ctx.onAfterEventLoop(); // this.afterUSocketsTick(); } @@ -824,13 +1074,15 @@ pub const EventLoop = struct { } pub fn tick(this: *EventLoop) void { + JSC.markBinding(@src()); + var ctx = this.virtual_machine; this.tickConcurrent(); this.processGCTimer(); var global = ctx.global; - var global_vm = global.vm(); + var global_vm = ctx.jsc; while (true) { while (this.tickWithCount() > 0) : (this.global.handleRejectedPromises()) { this.tickConcurrent(); @@ -851,12 +1103,12 @@ pub const EventLoop = struct { } pub fn waitForPromise(this: *EventLoop, promise: JSC.AnyPromise) void { - switch (promise.status(this.global.vm())) { + switch (promise.status(this.virtual_machine.jsc)) { JSC.JSPromise.Status.Pending => { - while (promise.status(this.global.vm()) == .Pending) { + while (promise.status(this.virtual_machine.jsc) == .Pending) { this.tick(); - if (promise.status(this.global.vm()) == .Pending) { + if (promise.status(this.virtual_machine.jsc) == .Pending) { this.autoTick(); } } @@ -868,16 +1120,16 @@ pub const EventLoop = struct { // TODO: this implementation is terrible // we should not be checking the millitimestamp every time pub fn waitForPromiseWithTimeout(this: *EventLoop, promise: JSC.AnyPromise, timeout: u32) bool { - return switch (promise.status(this.global.vm())) { + return switch (promise.status(this.virtual_machine.jsc)) { JSC.JSPromise.Status.Pending => { if (timeout == 0) { return false; } var start_time = std.time.milliTimestamp(); - while (promise.status(this.global.vm()) == .Pending) { + while (promise.status(this.virtual_machine.jsc) == .Pending) { this.tick(); - if (promise.status(this.global.vm()) == .Pending) { + if (promise.status(this.virtual_machine.jsc) == .Pending) { const remaining = std.time.milliTimestamp() - start_time; if (remaining >= timeout) { return false; @@ -893,6 +1145,7 @@ pub const EventLoop = struct { } pub fn enqueueTask(this: *EventLoop, task: Task) void { + JSC.markBinding(@src()); this.tasks.writeItem(task) catch unreachable; } @@ -905,7 +1158,7 @@ pub const EventLoop = struct { pub fn callTask(timer: *uws.Timer) callconv(.C) void { var task = Task.from(timer.as(*anyopaque)); - timer.deinit(); + defer timer.deinit(true); JSC.VirtualMachine.get().enqueueTask(task); } @@ -916,7 +1169,7 @@ pub const EventLoop = struct { this.virtual_machine.event_loop_handle = uws.Loop.get(); this.virtual_machine.gc_controller.init(this.virtual_machine); // _ = actual.addPostHandler(*JSC.EventLoop, this, JSC.EventLoop.afterUSocketsTick); - // _ = actual.addPreHandler(*JSC.VM, this.virtual_machine.global.vm(), JSC.VM.drainMicrotasks); + // _ = actual.addPreHandler(*JSC.VM, this.virtual_machine.jsc, JSC.VM.drainMicrotasks); } } @@ -995,7 +1248,7 @@ pub const MiniEventLoop = struct { while (!isDone(context)) { if (this.tickConcurrentWithCount() == 0 and this.tasks.count == 0) { this.loop.num_polls += 1; - this.loop.tick(); + this.loop.tick(null); this.loop.num_polls -= 1; } @@ -1086,7 +1339,7 @@ pub const AnyEventLoop = union(enum) { // var concurrent = bun.default_allocator.create(ConcurrentTask) catch unreachable; // _ = concurrent.from(JSC.Task.init(&@field(ctx, field))); // concurrent.auto_delete = true; - // this.jsc.enqueueTaskConcurrent(concurrent); + // this.virtual_machine.jsc.enqueueTaskConcurrent(concurrent); }, .mini => { this.mini.enqueueTaskConcurrent(Context, ParentContext, ctx, Callback, field); diff --git a/src/bun.js/ipc.zig b/src/bun.js/ipc.zig index 57fcef75f..a0742a0c4 100644 --- a/src/bun.js/ipc.zig +++ b/src/bun.js/ipc.zig @@ -35,6 +35,11 @@ pub const IPCMessageType = enum(u8) { _, }; +pub const IPCBuffer = struct { + list: bun.ByteList = .{}, + cursor: u32 = 0, +}; + /// Given potentially unfinished buffer `data`, attempt to decode and process a message from it. /// Returns `NotEnoughBytes` if there werent enough bytes /// Returns `InvalidFormat` if the message was invalid, probably close the socket in this case @@ -89,12 +94,74 @@ pub fn decodeIPCMessage( pub const Socket = uws.NewSocketHandler(false); +pub const IPCData = struct { + socket: Socket, + incoming: bun.ByteList = .{}, // Maybe we should use IPCBuffer here as well + outgoing: IPCBuffer = .{}, + + has_written_version: if (Environment.allow_assert) u1 else u0 = 0, + + pub fn writeVersionPacket(this: *IPCData) void { + if (Environment.allow_assert) { + std.debug.assert(this.has_written_version == 0); + } + const VersionPacket = extern struct { + type: IPCMessageType align(1) = .Version, + version: u32 align(1) = ipcVersion, + }; + const bytes = comptime std.mem.asBytes(&VersionPacket{}); + const n = this.socket.write(bytes, false); + if (n != bytes.len) { + var list = this.outgoing.list.listManaged(bun.default_allocator); + list.appendSlice(bytes) catch @panic("OOM"); + } + if (Environment.allow_assert) { + this.has_written_version = 1; + } + } + + pub fn serializeAndSend(ipc_data: *IPCData, globalThis: *JSGlobalObject, value: JSValue) bool { + if (Environment.allow_assert) { + std.debug.assert(ipc_data.has_written_version == 1); + } + + const serialized = value.serialize(globalThis) orelse return false; + defer serialized.deinit(); + + const size: u32 = @intCast(serialized.data.len); + + const payload_length: usize = @sizeOf(IPCMessageType) + @sizeOf(u32) + size; + + ipc_data.outgoing.list.ensureUnusedCapacity(bun.default_allocator, payload_length) catch @panic("OOM"); + const start_offset = ipc_data.outgoing.list.len; + + ipc_data.outgoing.list.writeTypeAsBytesAssumeCapacity(u8, @intFromEnum(IPCMessageType.SerializedMessage)); + ipc_data.outgoing.list.writeTypeAsBytesAssumeCapacity(u32, size); + ipc_data.outgoing.list.appendSliceAssumeCapacity(serialized.data); + + std.debug.assert(ipc_data.outgoing.list.len == start_offset + payload_length); + + if (start_offset == 0) { + std.debug.assert(ipc_data.outgoing.cursor == 0); + + const n = ipc_data.socket.write(ipc_data.outgoing.list.ptr[start_offset..payload_length], false); + if (n == payload_length) { + ipc_data.outgoing.list.len = 0; + } else if (n > 0) { + ipc_data.outgoing.cursor = @intCast(n); + } + } + + return true; + } +}; + /// This type is shared between VirtualMachine and Subprocess for their respective IPC handlers /// /// `Context` must be a struct that implements this interface: /// struct { /// globalThis: ?*JSGlobalObject, -/// ipc_buffer: bun.ByteList, +/// ipc: IPCData, /// /// fn handleIPCMessage(*Context, DecodedIPCMessage) void /// fn handleIPCClose(*Context, Socket) void @@ -102,18 +169,18 @@ pub const Socket = uws.NewSocketHandler(false); pub fn NewIPCHandler(comptime Context: type) type { return struct { pub fn onOpen( - _: *Context, - socket: Socket, + _: *anyopaque, + _: Socket, ) void { - // Write the version message - const Data = extern struct { - type: IPCMessageType align(1) = .Version, - version: u32 align(1) = ipcVersion, - }; - const data: []const u8 = comptime @as([@sizeOf(Data)]u8, @bitCast(Data{}))[0..]; - _ = socket.write(data, false); - socket.flush(); + // it is NOT safe to use the first argument here because it has not been initialized yet. + // ideally we would call .ipc.writeVersionPacket() here, and we need that to handle the + // theoretical write failure, but since the .ipc.outgoing buffer isn't available, that + // data has nowhere to go. + // + // therefore, initializers of IPC handlers need to call .ipc.writeVersionPacket() themselves + // this is covered by an assertion. } + pub fn onClose( this: *Context, socket: Socket, @@ -124,7 +191,7 @@ pub fn NewIPCHandler(comptime Context: type) type { log("onClose\n", .{}); this.handleIPCClose(socket); } - // extern fn getpid() i32; + pub fn onData( this: *Context, socket: Socket, @@ -133,10 +200,6 @@ pub fn NewIPCHandler(comptime Context: type) type { var data = data_; log("onData {}", .{std.fmt.fmtSliceHexLower(data)}); - // if (comptime Context == bun.JSC.VirtualMachine.IPCInstance) { - // logDataOnly("{d} -> '{}'", .{ getpid(), std.fmt.fmtSliceHexLower(data) }); - // } - // In the VirtualMachine case, `globalThis` is an optional, in case // the vm is freed before the socket closes. var globalThis = switch (@typeInfo(@TypeOf(this.globalThis))) { @@ -154,11 +217,11 @@ pub fn NewIPCHandler(comptime Context: type) type { // Decode the message with just the temporary buffer, and if that // fails (not enough bytes) then we allocate to .ipc_buffer - if (this.ipc_buffer.len == 0) { + if (this.ipc.incoming.len == 0) { while (true) { const result = decodeIPCMessage(data, globalThis) catch |e| switch (e) { error.NotEnoughBytes => { - _ = this.ipc_buffer.write(bun.default_allocator, data) catch @panic("OOM"); + _ = this.ipc.incoming.write(bun.default_allocator, data) catch @panic("OOM"); log("hit NotEnoughBytes", .{}); return; }, @@ -180,15 +243,15 @@ pub fn NewIPCHandler(comptime Context: type) type { } } - _ = this.ipc_buffer.write(bun.default_allocator, data) catch @panic("OOM"); + _ = this.ipc.incoming.write(bun.default_allocator, data) catch @panic("OOM"); - var slice = this.ipc_buffer.slice(); + var slice = this.ipc.incoming.slice(); while (true) { const result = decodeIPCMessage(slice, globalThis) catch |e| switch (e) { error.NotEnoughBytes => { // copy the remaining bytes to the start of the buffer - bun.copy(u8, this.ipc_buffer.ptr[0..slice.len], slice); - this.ipc_buffer.len = @truncate(slice.len); + bun.copy(u8, this.ipc.incoming.ptr[0..slice.len], slice); + this.ipc.incoming.len = @truncate(slice.len); log("hit NotEnoughBytes2", .{}); return; }, @@ -206,34 +269,47 @@ pub fn NewIPCHandler(comptime Context: type) type { slice = slice[result.bytes_consumed..]; } else { // clear the buffer - this.ipc_buffer.len = 0; + this.ipc.incoming.len = 0; return; } } } pub fn onWritable( - _: *Context, - _: Socket, - ) void {} + context: *Context, + socket: Socket, + ) void { + const to_write = context.ipc.outgoing.list.ptr[context.ipc.outgoing.cursor..context.ipc.outgoing.list.len]; + if (to_write.len == 0) { + context.ipc.outgoing.cursor = 0; + context.ipc.outgoing.list.len = 0; + return; + } + const n = socket.write(to_write, false); + if (n == to_write.len) { + context.ipc.outgoing.cursor = 0; + context.ipc.outgoing.list.len = 0; + } else if (n > 0) { + context.ipc.outgoing.cursor += @intCast(n); + } + } + pub fn onTimeout( _: *Context, _: Socket, ) void {} + pub fn onConnectError( - _: *Context, + _: *anyopaque, _: Socket, _: c_int, - ) void {} + ) void { + // context has not been initialized + } + pub fn onEnd( _: *Context, _: Socket, ) void {} }; } - -/// This is used for Bun.spawn() IPC because otherwise we would have to copy the data once to get it to zig, then write it. -/// Returns `true` on success, `false` on failure + throws a JS error. -extern fn Bun__serializeJSValueForSubprocess(global: *JSC.JSGlobalObject, value: JSValue, fd: bun.FileDescriptor) bool; - -pub const serializeJSValueForSubprocess = Bun__serializeJSValueForSubprocess; diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index e2e44e63a..1c996039d 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -294,13 +294,8 @@ pub export fn Bun__Process__send( return .zero; } var vm = globalObject.bunVM(); - if (vm.ipc) |ipc| { - const fd = ipc.socket.fd(); - const success = IPC.serializeJSValueForSubprocess( - globalObject, - callFrame.argument(0), - fd, - ); + if (vm.ipc) |ipc_instance| { + const success = ipc_instance.ipc.serializeAndSend(globalObject, callFrame.argument(0)); return if (success) .undefined else .zero; } else { globalObject.throw("IPC Socket is no longer open.", .{}); @@ -308,10 +303,15 @@ pub export fn Bun__Process__send( } } +pub export fn Bun__isBunMain(globalObject: *JSGlobalObject, input_ptr: [*]const u8, input_len: usize) bool { + return strings.eql(globalObject.bunVM().main, input_ptr[0..input_len]); +} + pub export fn Bun__Process__disconnect( globalObject: *JSGlobalObject, callFrame: *JSC.CallFrame, ) JSValue { + JSC.markBinding(@src()); _ = callFrame; _ = globalObject; return .undefined; @@ -320,14 +320,20 @@ pub export fn Bun__Process__disconnect( /// This function is called on the main thread /// The bunVM() call will assert this pub export fn Bun__queueTask(global: *JSGlobalObject, task: *JSC.CppTask) void { + JSC.markBinding(@src()); + global.bunVM().eventLoop().enqueueTask(Task.init(task)); } pub export fn Bun__queueTaskWithTimeout(global: *JSGlobalObject, task: *JSC.CppTask, milliseconds: i32) void { + JSC.markBinding(@src()); + global.bunVM().eventLoop().enqueueTaskWithTimeout(Task.init(task), milliseconds); } pub export fn Bun__reportUnhandledError(globalObject: *JSGlobalObject, value: JSValue) callconv(.C) JSValue { + JSC.markBinding(@src()); + var jsc_vm = globalObject.bunVM(); jsc_vm.onUnhandledError(globalObject, value); return JSC.JSValue.jsUndefined(); @@ -337,6 +343,8 @@ pub export fn Bun__reportUnhandledError(globalObject: *JSGlobalObject, value: JS /// The main difference: we need to allocate the task & wakeup the thread /// We can avoid that if we run it from the main thread. pub export fn Bun__queueTaskConcurrently(global: *JSGlobalObject, task: *JSC.CppTask) void { + JSC.markBinding(@src()); + var concurrent = bun.default_allocator.create(JSC.ConcurrentTask) catch unreachable; concurrent.* = JSC.ConcurrentTask{ .task = Task.init(task), @@ -346,6 +354,8 @@ pub export fn Bun__queueTaskConcurrently(global: *JSGlobalObject, task: *JSC.Cpp } pub export fn Bun__handleRejectedPromise(global: *JSGlobalObject, promise: *JSC.JSPromise) void { + JSC.markBinding(@src()); + const result = promise.result(global.vm()); var jsc_vm = global.bunVM(); @@ -369,6 +379,14 @@ pub export fn Bun__onDidAppendPlugin(jsc_vm: *VirtualMachine, globalObject: *JSG jsc_vm.bundler.linker.plugin_runner = &jsc_vm.plugin_runner.?; } +// pub fn getGlobalExitCodeForPipeFailure() u8 { +// if (VirtualMachine.is_main_thread_vm) { +// return VirtualMachine.get().exit_handler.exit_code; +// } + +// return 0; +// } + pub const ExitHandler = struct { exit_code: u8 = 0, @@ -401,6 +419,50 @@ pub const ExitHandler = struct { pub const WebWorker = @import("./web_worker.zig").WebWorker; +pub const ImportWatcher = union(enum) { + none: void, + hot: *HotReloader.Watcher, + watch: *WatchReloader.Watcher, + + pub fn start(this: ImportWatcher) !void { + switch (this) { + inline .hot => |watcher| try watcher.start(), + inline .watch => |watcher| try watcher.start(), + else => {}, + } + } + + pub inline fn watchlist(this: ImportWatcher) Watcher.WatchListArray { + return switch (this) { + inline .hot, .watch => |wacher| wacher.watchlist, + else => .{}, + }; + } + + pub inline fn indexOf(this: ImportWatcher, hash: Watcher.HashType) ?u32 { + return switch (this) { + inline .hot, .watch => |wacher| wacher.indexOf(hash), + else => null, + }; + } + + pub inline fn addFile( + this: ImportWatcher, + fd: StoredFileDescriptorType, + file_path: string, + hash: Watcher.HashType, + loader: options.Loader, + dir_fd: StoredFileDescriptorType, + package_json: ?*PackageJSON, + comptime copy_file_path: bool, + ) !void { + switch (this) { + inline .hot, .watch => |wacher| try wacher.addFile(fd, file_path, hash, loader, dir_fd, package_json, copy_file_path), + else => {}, + } + } +}; + /// TODO: rename this to ScriptExecutionContext /// This is the shared global state for a single JS instance execution /// Today, Bun is one VM per thread, so the name "VirtualMachine" sort of makes sense @@ -410,8 +472,7 @@ pub const VirtualMachine = struct { allocator: std.mem.Allocator, has_loaded_constructors: bool = false, bundler: Bundler, - bun_dev_watcher: ?*http.Watcher = null, - bun_watcher: ?*JSC.Watcher = null, + bun_watcher: ImportWatcher = .{ .none = {} }, console: *ZigConsoleClient, log: *logger.Log, main: string = "", @@ -980,6 +1041,8 @@ pub const VirtualMachine = struct { pub const MacroMap = std.AutoArrayHashMap(i32, js.JSObjectRef); pub fn enableMacroMode(this: *VirtualMachine) void { + JSC.markBinding(@src()); + if (!this.has_enabled_macro_mode) { this.has_enabled_macro_mode = true; this.macro_event_loop.tasks = EventLoop.Queue.init(default_allocator); @@ -1006,7 +1069,7 @@ pub const VirtualMachine = struct { } pub fn isWatcherEnabled(this: *VirtualMachine) bool { - return this.bun_dev_watcher != null or this.bun_watcher != null; + return this.bun_watcher != .none; } /// Instead of storing timestamp as a i128, we store it as a u64. @@ -1033,6 +1096,7 @@ pub const VirtualMachine = struct { pub fn initWithModuleGraph( opts: Options, ) !*VirtualMachine { + JSC.markBinding(@src()); const allocator = opts.allocator; VMHolder.vm = try allocator.create(VirtualMachine); var console = try allocator.create(ZigConsoleClient); @@ -1129,6 +1193,7 @@ pub const VirtualMachine = struct { }; pub fn init(opts: Options) !*VirtualMachine { + JSC.markBinding(@src()); const allocator = opts.allocator; var log: *logger.Log = undefined; if (opts.log) |__log| { @@ -1258,6 +1323,7 @@ pub const VirtualMachine = struct { worker: *WebWorker, opts: Options, ) anyerror!*VirtualMachine { + JSC.markBinding(@src()); var log: *logger.Log = undefined; const allocator = opts.allocator; if (opts.log) |__log| { @@ -1372,6 +1438,7 @@ pub const VirtualMachine = struct { pub fn refCountedStringWithWasNew(this: *VirtualMachine, new: *bool, input_: []const u8, hash_: ?u32, comptime dupe: bool) *JSC.RefString { JSC.markBinding(@src()); + std.debug.assert(input_.len > 0); const hash = hash_ orelse JSC.RefString.computeHash(input_); this.ref_strings_mutex.lock(); defer this.ref_strings_mutex.unlock(); @@ -1400,6 +1467,7 @@ pub const VirtualMachine = struct { } pub fn refCountedString(this: *VirtualMachine, input_: []const u8, hash_: ?u32, comptime dupe: bool) *JSC.RefString { + std.debug.assert(input_.len > 0); var _was_new = false; return this.refCountedStringWithWasNew(&_was_new, input_, hash_, comptime dupe); } @@ -1476,7 +1544,6 @@ pub const VirtualMachine = struct { fn normalizeSpecifierForResolution(specifier_: []const u8, query_string: *[]const u8) []const u8 { var specifier = specifier_; - if (strings.hasPrefixComptime(specifier, "file://")) specifier = specifier["file://".len..]; if (strings.indexOfChar(specifier, '?')) |i| { query_string.* = specifier[i..]; @@ -1673,7 +1740,7 @@ pub const VirtualMachine = struct { printed, ), }; - res.* = ErrorableString.err(error.NameTooLong, ResolveMessage.create(global, VirtualMachine.get().allocator, msg, source.utf8()).asVoid()); + res.* = ErrorableString.err(error.NameTooLong, ResolveMessage.create(global, VirtualMachine.get().allocator, msg, source_utf8.slice()).asVoid()); return; } @@ -1987,7 +2054,7 @@ pub const VirtualMachine = struct { try this.entry_point.generate( this.allocator, - this.bun_watcher != null, + this.bun_watcher != .none, Fs.PathName.init(entry_path), main_file_name, ); @@ -2044,7 +2111,7 @@ pub const VirtualMachine = struct { defer JSValue.fromCell(promise).unprotect(); // pending_internal_promise can change if hot module reloading is enabled - if (this.bun_watcher != null) { + if (this.isWatcherEnabled()) { this.eventLoop().performGC(); switch (this.pending_internal_promise.status(this.global.vm())) { JSC.JSPromise.Status.Pending => { @@ -2099,7 +2166,7 @@ pub const VirtualMachine = struct { var promise = try this.reloadEntryPoint(entry_path); // pending_internal_promise can change if hot module reloading is enabled - if (this.bun_watcher != null) { + if (this.isWatcherEnabled()) { this.eventLoop().performGC(); switch (this.pending_internal_promise.status(this.global.vm())) { JSC.JSPromise.Status.Pending => { @@ -2125,6 +2192,21 @@ pub const VirtualMachine = struct { return this.pending_internal_promise; } + pub fn addListeningSocketForWatchMode(this: *VirtualMachine, socket: bun.FileDescriptor) void { + if (this.hot_reload != .watch) { + return; + } + + this.rareData().addListeningSocketForWatchMode(socket); + } + pub fn removeListeningSocketForWatchMode(this: *VirtualMachine, socket: bun.FileDescriptor) void { + if (this.hot_reload != .watch) { + return; + } + + this.rareData().removeListeningSocketForWatchMode(socket); + } + pub fn loadMacroEntryPoint(this: *VirtualMachine, entry_path: string, function_name: string, specifier: string, hash: i32) !*JSInternalPromise { var entry_point_entry = try this.macro_entry_points.getOrPut(hash); @@ -2742,9 +2824,8 @@ pub const VirtualMachine = struct { pub const IPCInstance = struct { globalThis: ?*JSGlobalObject, - socket: IPC.Socket, uws_context: *uws.SocketContext, - ipc_buffer: bun.ByteList, + ipc: IPC.IPCData, pub fn handleIPCMessage( this: *IPCInstance, @@ -2794,13 +2875,13 @@ pub const VirtualMachine = struct { var instance = bun.default_allocator.create(IPCInstance) catch @panic("OOM"); instance.* = .{ .globalThis = this.global, - .socket = socket, .uws_context = context, - .ipc_buffer = bun.ByteList{}, + .ipc = .{ .socket = socket }, }; var ptr = socket.ext(*IPCInstance); ptr.?.* = instance; this.ipc = instance; + instance.ipc.writeVersionPacket(); } comptime { if (!JSC.is_bindgen) @@ -2809,6 +2890,7 @@ pub const VirtualMachine = struct { }; pub const HotReloader = NewHotReloader(VirtualMachine, JSC.EventLoop, false); +pub const WatchReloader = NewHotReloader(VirtualMachine, JSC.EventLoop, true); pub const Watcher = HotReloader.Watcher; extern fn BunDebugger__willHotReload() void; @@ -2835,6 +2917,8 @@ pub fn NewHotReloader(comptime Ctx: type, comptime EventLoopType: type, comptime this.eventLoop().enqueueTaskConcurrent(task); } + pub var clear_screen = false; + pub const HotReloadTask = struct { reloader: *Reloader, count: u8 = 0, @@ -2860,11 +2944,16 @@ pub fn NewHotReloader(comptime Ctx: type, comptime EventLoopType: type, comptime } pub fn enqueue(this: *HotReloadTask) void { + JSC.markBinding(@src()); if (this.count == 0) return; if (comptime reload_immediately) { - bun.reloadProcess(bun.default_allocator, Output.enable_ansi_colors); + Output.flush(); + if (comptime Ctx == ImportWatcher) { + this.reloader.ctx.rareData().closeAllListenSocketsForWatchMode(); + } + bun.reloadProcess(bun.default_allocator, clear_screen); unreachable; } @@ -2898,23 +2987,51 @@ pub fn NewHotReloader(comptime Ctx: type, comptime EventLoopType: type, comptime ) void); pub fn enableHotModuleReloading(this: *Ctx) void { - if (this.bun_watcher != null) - return; + if (comptime @TypeOf(this.bun_watcher) == ImportWatcher) { + if (this.bun_watcher != .none) + return; + } else { + if (this.bun_watcher != null) + return; + } var reloader = bun.default_allocator.create(Reloader) catch @panic("OOM"); reloader.* = .{ .ctx = this, .verbose = if (@hasField(Ctx, "log")) this.log.level.atLeast(.info) else false, }; - this.bun_watcher = @This().Watcher.init( - reloader, - this.bundler.fs, - bun.default_allocator, - ) catch @panic("Failed to enable File Watcher"); - this.bundler.resolver.watcher = Resolver.ResolveWatcher(*@This().Watcher, onMaybeWatchDirectory).init(this.bun_watcher.?); + if (comptime @TypeOf(this.bun_watcher) == ImportWatcher) { + this.bun_watcher = if (reload_immediately) + .{ .watch = @This().Watcher.init( + reloader, + this.bundler.fs, + bun.default_allocator, + ) catch @panic("Failed to enable File Watcher") } + else + .{ .hot = @This().Watcher.init( + reloader, + this.bundler.fs, + bun.default_allocator, + ) catch @panic("Failed to enable File Watcher") }; + + if (reload_immediately) { + this.bundler.resolver.watcher = Resolver.ResolveWatcher(*@This().Watcher, onMaybeWatchDirectory).init(this.bun_watcher.watch); + } else { + this.bundler.resolver.watcher = Resolver.ResolveWatcher(*@This().Watcher, onMaybeWatchDirectory).init(this.bun_watcher.hot); + } + } else { + this.bun_watcher = @This().Watcher.init( + reloader, + this.bundler.fs, + bun.default_allocator, + ) catch @panic("Failed to enable File Watcher"); + this.bundler.resolver.watcher = Resolver.ResolveWatcher(*@This().Watcher, onMaybeWatchDirectory).init(this.bun_watcher.?); + } + + clear_screen = Output.enable_ansi_colors and !strings.eqlComptime(this.bundler.env.map.get("BUN_CONFIG_NO_CLEAR_TERMINAL_ON_RELOAD") orelse "0", "true"); - this.bun_watcher.?.start() catch @panic("Failed to start File Watcher"); + reloader.getContext().start() catch @panic("Failed to start File Watcher"); } pub fn onMaybeWatchDirectory(watch: *@This().Watcher, file_path: string, dir_fd: StoredFileDescriptorType) void { @@ -2941,6 +3058,18 @@ pub fn NewHotReloader(comptime Ctx: type, comptime EventLoopType: type, comptime Output.prettyErrorln("<r>Watcher crashed: <red><b>{s}<r>", .{@errorName(err)}); } + pub fn getContext(this: *@This()) *@This().Watcher { + if (comptime @TypeOf(this.ctx.bun_watcher) == ImportWatcher) { + if (reload_immediately) { + return this.ctx.bun_watcher.watch; + } else { + return this.ctx.bun_watcher.hot; + } + } else { + return this.ctx.bun_watcher.?; + } + } + pub fn onFileUpdate( this: *@This(), events: []watcher.WatchEvent, @@ -2954,7 +3083,7 @@ pub fn NewHotReloader(comptime Ctx: type, comptime EventLoopType: type, comptime const hashes = slice.items(.hash); const parents = slice.items(.parent_hash); var file_descriptors = slice.items(.fd); - var ctx = this.ctx.bun_watcher.?; + var ctx = this.getContext(); defer ctx.flushEvictions(); defer Output.flush(); diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index cf86cb460..9a46d403b 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -154,21 +154,26 @@ const BunDebugHolder = struct { pub var lock: bun.Lock = undefined; }; -fn dumpSource(specifier: string, printer: anytype) !void { +/// Dumps the module source to a file in /tmp/bun-debug-src/{filepath} +/// +/// This can technically fail if concurrent access across processes happens, or permission issues. +/// Errors here should always be ignored. +fn dumpSource(specifier: string, printer: anytype) void { if (BunDebugHolder.dir == null) { - BunDebugHolder.dir = try std.fs.cwd().makeOpenPathIterable("/tmp/bun-debug-src/", .{}); + BunDebugHolder.dir = std.fs.cwd().makeOpenPathIterable("/tmp/bun-debug-src/", .{}) catch return; BunDebugHolder.lock = bun.Lock.init(); } BunDebugHolder.lock.lock(); defer BunDebugHolder.lock.unlock(); + const dir = BunDebugHolder.dir orelse return; if (std.fs.path.dirname(specifier)) |dir_path| { - var parent = try BunDebugHolder.dir.?.dir.makeOpenPathIterable(dir_path[1..], .{}); + var parent = dir.dir.makeOpenPathIterable(dir_path[1..], .{}) catch return; defer parent.close(); - try parent.dir.writeFile(std.fs.path.basename(specifier), printer.ctx.getWritten()); + parent.dir.writeFile(std.fs.path.basename(specifier), printer.ctx.getWritten()) catch return; } else { - try BunDebugHolder.dir.?.dir.writeFile(std.fs.path.basename(specifier), printer.ctx.getWritten()); + dir.dir.writeFile(std.fs.path.basename(specifier), printer.ctx.getWritten()) catch return; } } @@ -363,18 +368,15 @@ pub const RuntimeTranspilerStore = struct { var package_json: ?*PackageJSON = null; const hash = JSC.Watcher.getHash(path.text); - if (vm.bun_dev_watcher) |watcher| { - if (watcher.indexOf(hash)) |index| { - const _fd = watcher.watchlist.items(.fd)[index]; - fd = if (_fd > 0) _fd else null; - package_json = watcher.watchlist.items(.package_json)[index]; - } - } else if (vm.bun_watcher) |watcher| { - if (watcher.indexOf(hash)) |index| { - const _fd = watcher.watchlist.items(.fd)[index]; - fd = if (_fd > 0) _fd else null; - package_json = watcher.watchlist.items(.package_json)[index]; - } + switch (vm.bun_watcher) { + .hot, .watch => { + if (vm.bun_watcher.indexOf(hash)) |index| { + const _fd = vm.bun_watcher.watchlist().items(.fd)[index]; + fd = if (_fd > 0) _fd else null; + package_json = vm.bun_watcher.watchlist().items(.package_json)[index]; + } + }, + else => {}, } // this should be a cheap lookup because 24 bytes == 8 * 3 so it's read 3 machine words @@ -405,6 +407,7 @@ pub const RuntimeTranspilerStore = struct { .file_hash = hash, .macro_remappings = macro_remappings, .jsx = bundler.options.jsx, + .emit_decorator_metadata = bundler.options.emit_decorator_metadata, .virtual_source = null, .dont_bundle_twice = true, .allow_commonjs = true, @@ -438,9 +441,9 @@ pub const RuntimeTranspilerStore = struct { ) orelse { if (vm.isWatcherEnabled()) { if (input_file_fd != 0) { - if (vm.bun_watcher != null and !is_node_override and std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { + if (!is_node_override and std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { should_close_input_file_fd = false; - vm.bun_watcher.?.addFile( + vm.bun_watcher.addFile( input_file_fd, path.text, hash, @@ -459,11 +462,11 @@ pub const RuntimeTranspilerStore = struct { if (vm.isWatcherEnabled()) { if (input_file_fd != 0) { - if (vm.bun_watcher != null and !is_node_override and + if (!is_node_override and std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { should_close_input_file_fd = false; - vm.bun_watcher.?.addFile( + vm.bun_watcher.addFile( input_file_fd, path.text, hash, @@ -547,7 +550,7 @@ pub const RuntimeTranspilerStore = struct { } if (comptime Environment.dump_source) { - dumpSource(specifier, &printer) catch {}; + dumpSource(specifier, &printer); } this.resolved_source = ResolvedSource{ @@ -689,6 +692,7 @@ pub const ModuleLoader = struct { .onPackageDownloadError = onPackageDownloadError, .progress_bar = true, }, + true, PackageManager.Options.LogLevel.default, ) catch unreachable; } else { @@ -701,6 +705,7 @@ pub const ModuleLoader = struct { .onPackageManifestError = onPackageManifestError, .onPackageDownloadError = onPackageDownloadError, }, + true, PackageManager.Options.LogLevel.default_no_progress, ) catch unreachable; } @@ -1232,7 +1237,7 @@ pub const ModuleLoader = struct { } if (comptime Environment.dump_source) { - try dumpSource(specifier, &printer); + dumpSource(specifier, &printer); } var commonjs_exports = try bun.default_allocator.alloc(ZigString, parse_result.ast.commonjs_export_names.len); @@ -1244,8 +1249,8 @@ pub const ModuleLoader = struct { var resolved_source = jsc_vm.refCountedResolvedSource(printer.ctx.written, bun.String.init(specifier), path.text, null, false); if (parse_result.input_fd) |fd_| { - if (jsc_vm.bun_watcher != null and std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { - jsc_vm.bun_watcher.?.addFile( + if (std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { + jsc_vm.bun_watcher.addFile( fd_, path.text, this.hash, @@ -1379,18 +1384,10 @@ pub const ModuleLoader = struct { var fd: ?StoredFileDescriptorType = null; var package_json: ?*PackageJSON = null; - if (jsc_vm.bun_dev_watcher) |watcher| { - if (watcher.indexOf(hash)) |index| { - const _fd = watcher.watchlist.items(.fd)[index]; - fd = if (_fd > 0) _fd else null; - package_json = watcher.watchlist.items(.package_json)[index]; - } - } else if (jsc_vm.bun_watcher) |watcher| { - if (watcher.indexOf(hash)) |index| { - const _fd = watcher.watchlist.items(.fd)[index]; - fd = if (_fd > 0) _fd else null; - package_json = watcher.watchlist.items(.package_json)[index]; - } + if (jsc_vm.bun_watcher.indexOf(hash)) |index| { + const _fd = jsc_vm.bun_watcher.watchlist().items(.fd)[index]; + fd = if (_fd > 0) _fd else null; + package_json = jsc_vm.bun_watcher.watchlist().items(.package_json)[index]; } var old = jsc_vm.bundler.log; @@ -1438,6 +1435,7 @@ pub const ModuleLoader = struct { .file_hash = hash, .macro_remappings = macro_remappings, .jsx = jsc_vm.bundler.options.jsx, + .emit_decorator_metadata = jsc_vm.bundler.options.emit_decorator_metadata, .virtual_source = virtual_source, .dont_bundle_twice = true, .allow_commonjs = true, @@ -1470,9 +1468,9 @@ pub const ModuleLoader = struct { if (comptime !disable_transpilying) { if (jsc_vm.isWatcherEnabled()) { if (input_file_fd != 0) { - if (jsc_vm.bun_watcher != null and !is_node_override and std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { + if (!is_node_override and std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { should_close_input_file_fd = false; - jsc_vm.bun_watcher.?.addFile( + jsc_vm.bun_watcher.addFile( input_file_fd, path.text, hash, @@ -1513,9 +1511,9 @@ pub const ModuleLoader = struct { if (comptime !disable_transpilying) { if (jsc_vm.isWatcherEnabled()) { if (input_file_fd != 0) { - if (jsc_vm.bun_watcher != null and !is_node_override and std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { + if (!is_node_override and std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { should_close_input_file_fd = false; - jsc_vm.bun_watcher.?.addFile( + jsc_vm.bun_watcher.addFile( input_file_fd, path.text, hash, @@ -1635,7 +1633,7 @@ pub const ModuleLoader = struct { }; if (comptime Environment.dump_source) { - try dumpSource(specifier, &printer); + dumpSource(specifier, &printer); } var commonjs_exports = try bun.default_allocator.alloc(ZigString, parse_result.ast.commonjs_export_names.len); @@ -1715,7 +1713,7 @@ pub const ModuleLoader = struct { // const hash = http.Watcher.getHash(path.text); // if (jsc_vm.watcher) |watcher| { // if (watcher.indexOf(hash)) |index| { - // const _fd = watcher.watchlist.items(.fd)[index]; + // const _fd = watcher.watchlist().items(.fd)[index]; // fd = if (_fd > 0) _fd else null; // } // } @@ -1946,14 +1944,21 @@ pub const ModuleLoader = struct { } } - const synchronous_loader = loader orelse - // Unknown extensions are to be treated as file loader - if (jsc_vm.has_loaded or jsc_vm.is_in_preload) - options.Loader.file - else - // Unless it's potentially the main module - // This is important so that "bun run ./foo-i-have-no-extension" works - options.Loader.js; + const synchronous_loader = loader orelse loader: { + if (jsc_vm.has_loaded or jsc_vm.is_in_preload) { + // Extensionless files in this context are treated as the JS loader + if (path.name.ext.len == 0) { + break :loader options.Loader.tsx; + } + + // Unknown extensions are to be treated as file loader + break :loader options.Loader.file; + } else { + // Unless it's potentially the main module + // This is important so that "bun run ./foo-i-have-no-extension" works + break :loader options.Loader.tsx; + } + }; var promise: ?*JSC.JSInternalPromise = null; ret.* = ErrorableResolvedSource.ok( @@ -1981,6 +1986,7 @@ pub const ModuleLoader = struct { if (err == error.PluginError) { return null; } + VirtualMachine.processFetchLog(globalObject, specifier_ptr.*, referrer.*, &log, ret, err); return null; }, @@ -2152,7 +2158,7 @@ pub const ModuleLoader = struct { const path = Fs.Path.init(specifier); const loader = if (loader_ != ._none) - options.Loader.fromString(@tagName(loader_)).? + options.Loader.fromAPI(loader_) else jsc_vm.bundler.options.loaders.get(path.name.ext) orelse brk: { if (strings.eqlLong(specifier, jsc_vm.main, true)) { @@ -2171,7 +2177,7 @@ pub const ModuleLoader = struct { referrer_slice.slice(), specifier_ptr.*, path, - options.Loader.fromString(@tagName(loader)).?, + loader, &log, &virtual_source, ret, diff --git a/src/bun.js/modules/BunJSCModule.h b/src/bun.js/modules/BunJSCModule.h index 73823e16e..74e745bad 100644 --- a/src/bun.js/modules/BunJSCModule.h +++ b/src/bun.js/modules/BunJSCModule.h @@ -238,7 +238,7 @@ JSC_DEFINE_HOST_FUNCTION(functionCreateMemoryFootprint, &peak_rss, ¤t_commit, &peak_commit, &page_faults); // mi_process_info produces incorrect rss size on linux. - Zig::getRSS(¤t_rss); + Bun::getRSS(¤t_rss); VM &vm = globalObject->vm(); JSC::JSObject *object = JSC::constructEmptyObject( @@ -746,7 +746,7 @@ JSC_DEFINE_HOST_FUNCTION(functionCodeCoverageForFile, namespace Zig { DEFINE_NATIVE_MODULE(BunJSC) { - INIT_NATIVE_MODULE(33); + INIT_NATIVE_MODULE(34); putNativeFn(Identifier::fromString(vm, "callerSourceOrigin"_s), functionCallerSourceOrigin); putNativeFn(Identifier::fromString(vm, "jscDescribe"_s), functionDescribe); diff --git a/src/bun.js/modules/NodeConstantsModule.h b/src/bun.js/modules/NodeConstantsModule.h index c1e324b0a..ce701f5e3 100644 --- a/src/bun.js/modules/NodeConstantsModule.h +++ b/src/bun.js/modules/NodeConstantsModule.h @@ -1,6 +1,8 @@ #include "_NativeModule.h" -// Modelled off of https://github.com/nodejs/node/blob/main/src/node_constants.cc -// Note that if you change any of this code, you probably also have to change ProcessBindingConstants.cpp +// Modelled off of +// https://github.com/nodejs/node/blob/main/src/node_constants.cc Note that if +// you change any of this code, you probably also have to change +// ProcessBindingConstants.cpp // require('constants') is implemented in node as a spread of: // - constants.os.dlopen @@ -12,16 +14,17 @@ // Instead of loading $processBindingConstants, we just inline it // These headers may not all be needed, but they are the ones node references. -// Most of the constants are defined with #if checks on existing #defines, instead of platform-checks -#include <openssl/ec.h> -#include <openssl/ssl.h> -#include <zlib.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> +// Most of the constants are defined with #if checks on existing #defines, +// instead of platform-checks #include <cerrno> #include <csignal> +#include <fcntl.h> #include <limits> +#include <openssl/ec.h> +#include <openssl/ssl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <zlib.h> #ifndef OPENSSL_NO_ENGINE #include <openssl/engine.h> @@ -47,870 +50,940 @@ namespace Zig { using namespace WebCore; DEFINE_NATIVE_MODULE(NodeConstants) { - INIT_NATIVE_MODULE(63); + INIT_NATIVE_MODULE(0); #ifdef RTLD_LAZY - put(Identifier::fromString(vm, "RTLD_LAZY"_s), jsNumber(RTLD_LAZY)); + put(Identifier::fromString(vm, "RTLD_LAZY"_s), jsNumber(RTLD_LAZY)); #endif #ifdef RTLD_NOW - put(Identifier::fromString(vm, "RTLD_NOW"_s), jsNumber(RTLD_NOW)); + put(Identifier::fromString(vm, "RTLD_NOW"_s), jsNumber(RTLD_NOW)); #endif #ifdef RTLD_GLOBAL - put(Identifier::fromString(vm, "RTLD_GLOBAL"_s), jsNumber(RTLD_GLOBAL)); + put(Identifier::fromString(vm, "RTLD_GLOBAL"_s), jsNumber(RTLD_GLOBAL)); #endif #ifdef RTLD_LOCAL - put(Identifier::fromString(vm, "RTLD_LOCAL"_s), jsNumber(RTLD_LOCAL)); + put(Identifier::fromString(vm, "RTLD_LOCAL"_s), jsNumber(RTLD_LOCAL)); #endif #ifdef RTLD_DEEPBIND - put(Identifier::fromString(vm, "RTLD_DEEPBIND"_s), jsNumber(RTLD_DEEPBIND)); + put(Identifier::fromString(vm, "RTLD_DEEPBIND"_s), jsNumber(RTLD_DEEPBIND)); #endif #ifdef E2BIG - put(Identifier::fromString(vm, "E2BIG"_s), jsNumber(E2BIG)); + put(Identifier::fromString(vm, "E2BIG"_s), jsNumber(E2BIG)); #endif #ifdef EACCES - put(Identifier::fromString(vm, "EACCES"_s), jsNumber(EACCES)); + put(Identifier::fromString(vm, "EACCES"_s), jsNumber(EACCES)); #endif #ifdef EADDRINUSE - put(Identifier::fromString(vm, "EADDRINUSE"_s), jsNumber(EADDRINUSE)); + put(Identifier::fromString(vm, "EADDRINUSE"_s), jsNumber(EADDRINUSE)); #endif #ifdef EADDRNOTAVAIL - put(Identifier::fromString(vm, "EADDRNOTAVAIL"_s), jsNumber(EADDRNOTAVAIL)); + put(Identifier::fromString(vm, "EADDRNOTAVAIL"_s), jsNumber(EADDRNOTAVAIL)); #endif #ifdef EAFNOSUPPORT - put(Identifier::fromString(vm, "EAFNOSUPPORT"_s), jsNumber(EAFNOSUPPORT)); + put(Identifier::fromString(vm, "EAFNOSUPPORT"_s), jsNumber(EAFNOSUPPORT)); #endif #ifdef EAGAIN - put(Identifier::fromString(vm, "EAGAIN"_s), jsNumber(EAGAIN)); + put(Identifier::fromString(vm, "EAGAIN"_s), jsNumber(EAGAIN)); #endif #ifdef EALREADY - put(Identifier::fromString(vm, "EALREADY"_s), jsNumber(EALREADY)); + put(Identifier::fromString(vm, "EALREADY"_s), jsNumber(EALREADY)); #endif #ifdef EBADF - put(Identifier::fromString(vm, "EBADF"_s), jsNumber(EBADF)); + put(Identifier::fromString(vm, "EBADF"_s), jsNumber(EBADF)); #endif #ifdef EBADMSG - put(Identifier::fromString(vm, "EBADMSG"_s), jsNumber(EBADMSG)); + put(Identifier::fromString(vm, "EBADMSG"_s), jsNumber(EBADMSG)); #endif #ifdef EBUSY - put(Identifier::fromString(vm, "EBUSY"_s), jsNumber(EBUSY)); + put(Identifier::fromString(vm, "EBUSY"_s), jsNumber(EBUSY)); #endif #ifdef ECANCELED - put(Identifier::fromString(vm, "ECANCELED"_s), jsNumber(ECANCELED)); + put(Identifier::fromString(vm, "ECANCELED"_s), jsNumber(ECANCELED)); #endif #ifdef ECHILD - put(Identifier::fromString(vm, "ECHILD"_s), jsNumber(ECHILD)); + put(Identifier::fromString(vm, "ECHILD"_s), jsNumber(ECHILD)); #endif #ifdef ECONNABORTED - put(Identifier::fromString(vm, "ECONNABORTED"_s), jsNumber(ECONNABORTED)); + put(Identifier::fromString(vm, "ECONNABORTED"_s), jsNumber(ECONNABORTED)); #endif #ifdef ECONNREFUSED - put(Identifier::fromString(vm, "ECONNREFUSED"_s), jsNumber(ECONNREFUSED)); + put(Identifier::fromString(vm, "ECONNREFUSED"_s), jsNumber(ECONNREFUSED)); #endif #ifdef ECONNRESET - put(Identifier::fromString(vm, "ECONNRESET"_s), jsNumber(ECONNRESET)); + put(Identifier::fromString(vm, "ECONNRESET"_s), jsNumber(ECONNRESET)); #endif #ifdef EDEADLK - put(Identifier::fromString(vm, "EDEADLK"_s), jsNumber(EDEADLK)); + put(Identifier::fromString(vm, "EDEADLK"_s), jsNumber(EDEADLK)); #endif #ifdef EDESTADDRREQ - put(Identifier::fromString(vm, "EDESTADDRREQ"_s), jsNumber(EDESTADDRREQ)); + put(Identifier::fromString(vm, "EDESTADDRREQ"_s), jsNumber(EDESTADDRREQ)); #endif #ifdef EDOM - put(Identifier::fromString(vm, "EDOM"_s), jsNumber(EDOM)); + put(Identifier::fromString(vm, "EDOM"_s), jsNumber(EDOM)); #endif #ifdef EDQUOT - put(Identifier::fromString(vm, "EDQUOT"_s), jsNumber(EDQUOT)); + put(Identifier::fromString(vm, "EDQUOT"_s), jsNumber(EDQUOT)); #endif #ifdef EEXIST - put(Identifier::fromString(vm, "EEXIST"_s), jsNumber(EEXIST)); + put(Identifier::fromString(vm, "EEXIST"_s), jsNumber(EEXIST)); #endif #ifdef EFAULT - put(Identifier::fromString(vm, "EFAULT"_s), jsNumber(EFAULT)); + put(Identifier::fromString(vm, "EFAULT"_s), jsNumber(EFAULT)); #endif #ifdef EFBIG - put(Identifier::fromString(vm, "EFBIG"_s), jsNumber(EFBIG)); + put(Identifier::fromString(vm, "EFBIG"_s), jsNumber(EFBIG)); #endif #ifdef EHOSTUNREACH - put(Identifier::fromString(vm, "EHOSTUNREACH"_s), jsNumber(EHOSTUNREACH)); + put(Identifier::fromString(vm, "EHOSTUNREACH"_s), jsNumber(EHOSTUNREACH)); #endif #ifdef EIDRM - put(Identifier::fromString(vm, "EIDRM"_s), jsNumber(EIDRM)); + put(Identifier::fromString(vm, "EIDRM"_s), jsNumber(EIDRM)); #endif #ifdef EILSEQ - put(Identifier::fromString(vm, "EILSEQ"_s), jsNumber(EILSEQ)); + put(Identifier::fromString(vm, "EILSEQ"_s), jsNumber(EILSEQ)); #endif #ifdef EINPROGRESS - put(Identifier::fromString(vm, "EINPROGRESS"_s), jsNumber(EINPROGRESS)); + put(Identifier::fromString(vm, "EINPROGRESS"_s), jsNumber(EINPROGRESS)); #endif #ifdef EINTR - put(Identifier::fromString(vm, "EINTR"_s), jsNumber(EINTR)); + put(Identifier::fromString(vm, "EINTR"_s), jsNumber(EINTR)); #endif #ifdef EINVAL - put(Identifier::fromString(vm, "EINVAL"_s), jsNumber(EINVAL)); + put(Identifier::fromString(vm, "EINVAL"_s), jsNumber(EINVAL)); #endif #ifdef EIO - put(Identifier::fromString(vm, "EIO"_s), jsNumber(EIO)); + put(Identifier::fromString(vm, "EIO"_s), jsNumber(EIO)); #endif #ifdef EISCONN - put(Identifier::fromString(vm, "EISCONN"_s), jsNumber(EISCONN)); + put(Identifier::fromString(vm, "EISCONN"_s), jsNumber(EISCONN)); #endif #ifdef EISDIR - put(Identifier::fromString(vm, "EISDIR"_s), jsNumber(EISDIR)); + put(Identifier::fromString(vm, "EISDIR"_s), jsNumber(EISDIR)); #endif #ifdef ELOOP - put(Identifier::fromString(vm, "ELOOP"_s), jsNumber(ELOOP)); + put(Identifier::fromString(vm, "ELOOP"_s), jsNumber(ELOOP)); #endif #ifdef EMFILE - put(Identifier::fromString(vm, "EMFILE"_s), jsNumber(EMFILE)); + put(Identifier::fromString(vm, "EMFILE"_s), jsNumber(EMFILE)); #endif #ifdef EMLINK - put(Identifier::fromString(vm, "EMLINK"_s), jsNumber(EMLINK)); + put(Identifier::fromString(vm, "EMLINK"_s), jsNumber(EMLINK)); #endif #ifdef EMSGSIZE - put(Identifier::fromString(vm, "EMSGSIZE"_s), jsNumber(EMSGSIZE)); + put(Identifier::fromString(vm, "EMSGSIZE"_s), jsNumber(EMSGSIZE)); #endif #ifdef EMULTIHOP - put(Identifier::fromString(vm, "EMULTIHOP"_s), jsNumber(EMULTIHOP)); + put(Identifier::fromString(vm, "EMULTIHOP"_s), jsNumber(EMULTIHOP)); #endif #ifdef ENAMETOOLONG - put(Identifier::fromString(vm, "ENAMETOOLONG"_s), jsNumber(ENAMETOOLONG)); + put(Identifier::fromString(vm, "ENAMETOOLONG"_s), jsNumber(ENAMETOOLONG)); #endif #ifdef ENETDOWN - put(Identifier::fromString(vm, "ENETDOWN"_s), jsNumber(ENETDOWN)); + put(Identifier::fromString(vm, "ENETDOWN"_s), jsNumber(ENETDOWN)); #endif #ifdef ENETRESET - put(Identifier::fromString(vm, "ENETRESET"_s), jsNumber(ENETRESET)); + put(Identifier::fromString(vm, "ENETRESET"_s), jsNumber(ENETRESET)); #endif #ifdef ENETUNREACH - put(Identifier::fromString(vm, "ENETUNREACH"_s), jsNumber(ENETUNREACH)); + put(Identifier::fromString(vm, "ENETUNREACH"_s), jsNumber(ENETUNREACH)); #endif #ifdef ENFILE - put(Identifier::fromString(vm, "ENFILE"_s), jsNumber(ENFILE)); + put(Identifier::fromString(vm, "ENFILE"_s), jsNumber(ENFILE)); #endif #ifdef ENOBUFS - put(Identifier::fromString(vm, "ENOBUFS"_s), jsNumber(ENOBUFS)); + put(Identifier::fromString(vm, "ENOBUFS"_s), jsNumber(ENOBUFS)); #endif #ifdef ENODATA - put(Identifier::fromString(vm, "ENODATA"_s), jsNumber(ENODATA)); + put(Identifier::fromString(vm, "ENODATA"_s), jsNumber(ENODATA)); #endif #ifdef ENODEV - put(Identifier::fromString(vm, "ENODEV"_s), jsNumber(ENODEV)); + put(Identifier::fromString(vm, "ENODEV"_s), jsNumber(ENODEV)); #endif #ifdef ENOENT - put(Identifier::fromString(vm, "ENOENT"_s), jsNumber(ENOENT)); + put(Identifier::fromString(vm, "ENOENT"_s), jsNumber(ENOENT)); #endif #ifdef ENOEXEC - put(Identifier::fromString(vm, "ENOEXEC"_s), jsNumber(ENOEXEC)); + put(Identifier::fromString(vm, "ENOEXEC"_s), jsNumber(ENOEXEC)); #endif #ifdef ENOLCK - put(Identifier::fromString(vm, "ENOLCK"_s), jsNumber(ENOLCK)); + put(Identifier::fromString(vm, "ENOLCK"_s), jsNumber(ENOLCK)); #endif #ifdef ENOLINK - put(Identifier::fromString(vm, "ENOLINK"_s), jsNumber(ENOLINK)); + put(Identifier::fromString(vm, "ENOLINK"_s), jsNumber(ENOLINK)); #endif #ifdef ENOMEM - put(Identifier::fromString(vm, "ENOMEM"_s), jsNumber(ENOMEM)); + put(Identifier::fromString(vm, "ENOMEM"_s), jsNumber(ENOMEM)); #endif #ifdef ENOMSG - put(Identifier::fromString(vm, "ENOMSG"_s), jsNumber(ENOMSG)); + put(Identifier::fromString(vm, "ENOMSG"_s), jsNumber(ENOMSG)); #endif #ifdef ENOPROTOOPT - put(Identifier::fromString(vm, "ENOPROTOOPT"_s), jsNumber(ENOPROTOOPT)); + put(Identifier::fromString(vm, "ENOPROTOOPT"_s), jsNumber(ENOPROTOOPT)); #endif #ifdef ENOSPC - put(Identifier::fromString(vm, "ENOSPC"_s), jsNumber(ENOSPC)); + put(Identifier::fromString(vm, "ENOSPC"_s), jsNumber(ENOSPC)); #endif #ifdef ENOSR - put(Identifier::fromString(vm, "ENOSR"_s), jsNumber(ENOSR)); + put(Identifier::fromString(vm, "ENOSR"_s), jsNumber(ENOSR)); #endif #ifdef ENOSTR - put(Identifier::fromString(vm, "ENOSTR"_s), jsNumber(ENOSTR)); + put(Identifier::fromString(vm, "ENOSTR"_s), jsNumber(ENOSTR)); #endif #ifdef ENOSYS - put(Identifier::fromString(vm, "ENOSYS"_s), jsNumber(ENOSYS)); + put(Identifier::fromString(vm, "ENOSYS"_s), jsNumber(ENOSYS)); #endif #ifdef ENOTCONN - put(Identifier::fromString(vm, "ENOTCONN"_s), jsNumber(ENOTCONN)); + put(Identifier::fromString(vm, "ENOTCONN"_s), jsNumber(ENOTCONN)); #endif #ifdef ENOTDIR - put(Identifier::fromString(vm, "ENOTDIR"_s), jsNumber(ENOTDIR)); + put(Identifier::fromString(vm, "ENOTDIR"_s), jsNumber(ENOTDIR)); #endif #ifdef ENOTEMPTY - put(Identifier::fromString(vm, "ENOTEMPTY"_s), jsNumber(ENOTEMPTY)); + put(Identifier::fromString(vm, "ENOTEMPTY"_s), jsNumber(ENOTEMPTY)); #endif #ifdef ENOTSOCK - put(Identifier::fromString(vm, "ENOTSOCK"_s), jsNumber(ENOTSOCK)); + put(Identifier::fromString(vm, "ENOTSOCK"_s), jsNumber(ENOTSOCK)); #endif #ifdef ENOTSUP - put(Identifier::fromString(vm, "ENOTSUP"_s), jsNumber(ENOTSUP)); + put(Identifier::fromString(vm, "ENOTSUP"_s), jsNumber(ENOTSUP)); #endif #ifdef ENOTTY - put(Identifier::fromString(vm, "ENOTTY"_s), jsNumber(ENOTTY)); + put(Identifier::fromString(vm, "ENOTTY"_s), jsNumber(ENOTTY)); #endif #ifdef ENXIO - put(Identifier::fromString(vm, "ENXIO"_s), jsNumber(ENXIO)); + put(Identifier::fromString(vm, "ENXIO"_s), jsNumber(ENXIO)); #endif #ifdef EOPNOTSUPP - put(Identifier::fromString(vm, "EOPNOTSUPP"_s), jsNumber(EOPNOTSUPP)); + put(Identifier::fromString(vm, "EOPNOTSUPP"_s), jsNumber(EOPNOTSUPP)); #endif #ifdef EOVERFLOW - put(Identifier::fromString(vm, "EOVERFLOW"_s), jsNumber(EOVERFLOW)); + put(Identifier::fromString(vm, "EOVERFLOW"_s), jsNumber(EOVERFLOW)); #endif #ifdef EPERM - put(Identifier::fromString(vm, "EPERM"_s), jsNumber(EPERM)); + put(Identifier::fromString(vm, "EPERM"_s), jsNumber(EPERM)); #endif #ifdef EPIPE - put(Identifier::fromString(vm, "EPIPE"_s), jsNumber(EPIPE)); + put(Identifier::fromString(vm, "EPIPE"_s), jsNumber(EPIPE)); #endif #ifdef EPROTO - put(Identifier::fromString(vm, "EPROTO"_s), jsNumber(EPROTO)); + put(Identifier::fromString(vm, "EPROTO"_s), jsNumber(EPROTO)); #endif #ifdef EPROTONOSUPPORT - put(Identifier::fromString(vm, "EPROTONOSUPPORT"_s), jsNumber(EPROTONOSUPPORT)); + put(Identifier::fromString(vm, "EPROTONOSUPPORT"_s), + jsNumber(EPROTONOSUPPORT)); #endif #ifdef EPROTOTYPE - put(Identifier::fromString(vm, "EPROTOTYPE"_s), jsNumber(EPROTOTYPE)); + put(Identifier::fromString(vm, "EPROTOTYPE"_s), jsNumber(EPROTOTYPE)); #endif #ifdef ERANGE - put(Identifier::fromString(vm, "ERANGE"_s), jsNumber(ERANGE)); + put(Identifier::fromString(vm, "ERANGE"_s), jsNumber(ERANGE)); #endif #ifdef EROFS - put(Identifier::fromString(vm, "EROFS"_s), jsNumber(EROFS)); + put(Identifier::fromString(vm, "EROFS"_s), jsNumber(EROFS)); #endif #ifdef ESPIPE - put(Identifier::fromString(vm, "ESPIPE"_s), jsNumber(ESPIPE)); + put(Identifier::fromString(vm, "ESPIPE"_s), jsNumber(ESPIPE)); #endif #ifdef ESRCH - put(Identifier::fromString(vm, "ESRCH"_s), jsNumber(ESRCH)); + put(Identifier::fromString(vm, "ESRCH"_s), jsNumber(ESRCH)); #endif #ifdef ESTALE - put(Identifier::fromString(vm, "ESTALE"_s), jsNumber(ESTALE)); + put(Identifier::fromString(vm, "ESTALE"_s), jsNumber(ESTALE)); #endif #ifdef ETIME - put(Identifier::fromString(vm, "ETIME"_s), jsNumber(ETIME)); + put(Identifier::fromString(vm, "ETIME"_s), jsNumber(ETIME)); #endif #ifdef ETIMEDOUT - put(Identifier::fromString(vm, "ETIMEDOUT"_s), jsNumber(ETIMEDOUT)); + put(Identifier::fromString(vm, "ETIMEDOUT"_s), jsNumber(ETIMEDOUT)); #endif #ifdef ETXTBSY - put(Identifier::fromString(vm, "ETXTBSY"_s), jsNumber(ETXTBSY)); + put(Identifier::fromString(vm, "ETXTBSY"_s), jsNumber(ETXTBSY)); #endif #ifdef EWOULDBLOCK - put(Identifier::fromString(vm, "EWOULDBLOCK"_s), jsNumber(EWOULDBLOCK)); + put(Identifier::fromString(vm, "EWOULDBLOCK"_s), jsNumber(EWOULDBLOCK)); #endif #ifdef EXDEV - put(Identifier::fromString(vm, "EXDEV"_s), jsNumber(EXDEV)); + put(Identifier::fromString(vm, "EXDEV"_s), jsNumber(EXDEV)); #endif #ifdef WSAEINTR - put(Identifier::fromString(vm, "WSAEINTR"_s), jsNumber(WSAEINTR)); + put(Identifier::fromString(vm, "WSAEINTR"_s), jsNumber(WSAEINTR)); #endif #ifdef WSAEBADF - put(Identifier::fromString(vm, "WSAEBADF"_s), jsNumber(WSAEBADF)); + put(Identifier::fromString(vm, "WSAEBADF"_s), jsNumber(WSAEBADF)); #endif #ifdef WSAEACCES - put(Identifier::fromString(vm, "WSAEACCES"_s), jsNumber(WSAEACCES)); + put(Identifier::fromString(vm, "WSAEACCES"_s), jsNumber(WSAEACCES)); #endif #ifdef WSAEFAULT - put(Identifier::fromString(vm, "WSAEFAULT"_s), jsNumber(WSAEFAULT)); + put(Identifier::fromString(vm, "WSAEFAULT"_s), jsNumber(WSAEFAULT)); #endif #ifdef WSAEINVAL - put(Identifier::fromString(vm, "WSAEINVAL"_s), jsNumber(WSAEINVAL)); + put(Identifier::fromString(vm, "WSAEINVAL"_s), jsNumber(WSAEINVAL)); #endif #ifdef WSAEMFILE - put(Identifier::fromString(vm, "WSAEMFILE"_s), jsNumber(WSAEMFILE)); + put(Identifier::fromString(vm, "WSAEMFILE"_s), jsNumber(WSAEMFILE)); #endif #ifdef WSAEWOULDBLOCK - put(Identifier::fromString(vm, "WSAEWOULDBLOCK"_s), jsNumber(WSAEWOULDBLOCK)); + put(Identifier::fromString(vm, "WSAEWOULDBLOCK"_s), jsNumber(WSAEWOULDBLOCK)); #endif #ifdef WSAEINPROGRESS - put(Identifier::fromString(vm, "WSAEINPROGRESS"_s), jsNumber(WSAEINPROGRESS)); + put(Identifier::fromString(vm, "WSAEINPROGRESS"_s), jsNumber(WSAEINPROGRESS)); #endif #ifdef WSAEALREADY - put(Identifier::fromString(vm, "WSAEALREADY"_s), jsNumber(WSAEALREADY)); + put(Identifier::fromString(vm, "WSAEALREADY"_s), jsNumber(WSAEALREADY)); #endif #ifdef WSAENOTSOCK - put(Identifier::fromString(vm, "WSAENOTSOCK"_s), jsNumber(WSAENOTSOCK)); + put(Identifier::fromString(vm, "WSAENOTSOCK"_s), jsNumber(WSAENOTSOCK)); #endif #ifdef WSAEDESTADDRREQ - put(Identifier::fromString(vm, "WSAEDESTADDRREQ"_s), jsNumber(WSAEDESTADDRREQ)); + put(Identifier::fromString(vm, "WSAEDESTADDRREQ"_s), + jsNumber(WSAEDESTADDRREQ)); #endif #ifdef WSAEMSGSIZE - put(Identifier::fromString(vm, "WSAEMSGSIZE"_s), jsNumber(WSAEMSGSIZE)); + put(Identifier::fromString(vm, "WSAEMSGSIZE"_s), jsNumber(WSAEMSGSIZE)); #endif #ifdef WSAEPROTOTYPE - put(Identifier::fromString(vm, "WSAEPROTOTYPE"_s), jsNumber(WSAEPROTOTYPE)); + put(Identifier::fromString(vm, "WSAEPROTOTYPE"_s), jsNumber(WSAEPROTOTYPE)); #endif #ifdef WSAENOPROTOOPT - put(Identifier::fromString(vm, "WSAENOPROTOOPT"_s), jsNumber(WSAENOPROTOOPT)); + put(Identifier::fromString(vm, "WSAENOPROTOOPT"_s), jsNumber(WSAENOPROTOOPT)); #endif #ifdef WSAEPROTONOSUPPORT - put(Identifier::fromString(vm, "WSAEPROTONOSUPPORT"_s), jsNumber(WSAEPROTONOSUPPORT)); + put(Identifier::fromString(vm, "WSAEPROTONOSUPPORT"_s), + jsNumber(WSAEPROTONOSUPPORT)); #endif #ifdef WSAESOCKTNOSUPPORT - put(Identifier::fromString(vm, "WSAESOCKTNOSUPPORT"_s), jsNumber(WSAESOCKTNOSUPPORT)); + put(Identifier::fromString(vm, "WSAESOCKTNOSUPPORT"_s), + jsNumber(WSAESOCKTNOSUPPORT)); #endif #ifdef WSAEOPNOTSUPP - put(Identifier::fromString(vm, "WSAEOPNOTSUPP"_s), jsNumber(WSAEOPNOTSUPP)); + put(Identifier::fromString(vm, "WSAEOPNOTSUPP"_s), jsNumber(WSAEOPNOTSUPP)); #endif #ifdef WSAEPFNOSUPPORT - put(Identifier::fromString(vm, "WSAEPFNOSUPPORT"_s), jsNumber(WSAEPFNOSUPPORT)); + put(Identifier::fromString(vm, "WSAEPFNOSUPPORT"_s), + jsNumber(WSAEPFNOSUPPORT)); #endif #ifdef WSAEAFNOSUPPORT - put(Identifier::fromString(vm, "WSAEAFNOSUPPORT"_s), jsNumber(WSAEAFNOSUPPORT)); + put(Identifier::fromString(vm, "WSAEAFNOSUPPORT"_s), + jsNumber(WSAEAFNOSUPPORT)); #endif #ifdef WSAEADDRINUSE - put(Identifier::fromString(vm, "WSAEADDRINUSE"_s), jsNumber(WSAEADDRINUSE)); + put(Identifier::fromString(vm, "WSAEADDRINUSE"_s), jsNumber(WSAEADDRINUSE)); #endif #ifdef WSAEADDRNOTAVAIL - put(Identifier::fromString(vm, "WSAEADDRNOTAVAIL"_s), jsNumber(WSAEADDRNOTAVAIL)); + put(Identifier::fromString(vm, "WSAEADDRNOTAVAIL"_s), + jsNumber(WSAEADDRNOTAVAIL)); #endif #ifdef WSAENETDOWN - put(Identifier::fromString(vm, "WSAENETDOWN"_s), jsNumber(WSAENETDOWN)); + put(Identifier::fromString(vm, "WSAENETDOWN"_s), jsNumber(WSAENETDOWN)); #endif #ifdef WSAENETUNREACH - put(Identifier::fromString(vm, "WSAENETUNREACH"_s), jsNumber(WSAENETUNREACH)); + put(Identifier::fromString(vm, "WSAENETUNREACH"_s), jsNumber(WSAENETUNREACH)); #endif #ifdef WSAENETRESET - put(Identifier::fromString(vm, "WSAENETRESET"_s), jsNumber(WSAENETRESET)); + put(Identifier::fromString(vm, "WSAENETRESET"_s), jsNumber(WSAENETRESET)); #endif #ifdef WSAECONNABORTED - put(Identifier::fromString(vm, "WSAECONNABORTED"_s), jsNumber(WSAECONNABORTED)); + put(Identifier::fromString(vm, "WSAECONNABORTED"_s), + jsNumber(WSAECONNABORTED)); #endif #ifdef WSAECONNRESET - put(Identifier::fromString(vm, "WSAECONNRESET"_s), jsNumber(WSAECONNRESET)); + put(Identifier::fromString(vm, "WSAECONNRESET"_s), jsNumber(WSAECONNRESET)); #endif #ifdef WSAENOBUFS - put(Identifier::fromString(vm, "WSAENOBUFS"_s), jsNumber(WSAENOBUFS)); + put(Identifier::fromString(vm, "WSAENOBUFS"_s), jsNumber(WSAENOBUFS)); #endif #ifdef WSAEISCONN - put(Identifier::fromString(vm, "WSAEISCONN"_s), jsNumber(WSAEISCONN)); + put(Identifier::fromString(vm, "WSAEISCONN"_s), jsNumber(WSAEISCONN)); #endif #ifdef WSAENOTCONN - put(Identifier::fromString(vm, "WSAENOTCONN"_s), jsNumber(WSAENOTCONN)); + put(Identifier::fromString(vm, "WSAENOTCONN"_s), jsNumber(WSAENOTCONN)); #endif #ifdef WSAESHUTDOWN - put(Identifier::fromString(vm, "WSAESHUTDOWN"_s), jsNumber(WSAESHUTDOWN)); + put(Identifier::fromString(vm, "WSAESHUTDOWN"_s), jsNumber(WSAESHUTDOWN)); #endif #ifdef WSAETOOMANYREFS - put(Identifier::fromString(vm, "WSAETOOMANYREFS"_s), jsNumber(WSAETOOMANYREFS)); + put(Identifier::fromString(vm, "WSAETOOMANYREFS"_s), + jsNumber(WSAETOOMANYREFS)); #endif #ifdef WSAETIMEDOUT - put(Identifier::fromString(vm, "WSAETIMEDOUT"_s), jsNumber(WSAETIMEDOUT)); + put(Identifier::fromString(vm, "WSAETIMEDOUT"_s), jsNumber(WSAETIMEDOUT)); #endif #ifdef WSAECONNREFUSED - put(Identifier::fromString(vm, "WSAECONNREFUSED"_s), jsNumber(WSAECONNREFUSED)); + put(Identifier::fromString(vm, "WSAECONNREFUSED"_s), + jsNumber(WSAECONNREFUSED)); #endif #ifdef WSAELOOP - put(Identifier::fromString(vm, "WSAELOOP"_s), jsNumber(WSAELOOP)); + put(Identifier::fromString(vm, "WSAELOOP"_s), jsNumber(WSAELOOP)); #endif #ifdef WSAENAMETOOLONG - put(Identifier::fromString(vm, "WSAENAMETOOLONG"_s), jsNumber(WSAENAMETOOLONG)); + put(Identifier::fromString(vm, "WSAENAMETOOLONG"_s), + jsNumber(WSAENAMETOOLONG)); #endif #ifdef WSAEHOSTDOWN - put(Identifier::fromString(vm, "WSAEHOSTDOWN"_s), jsNumber(WSAEHOSTDOWN)); + put(Identifier::fromString(vm, "WSAEHOSTDOWN"_s), jsNumber(WSAEHOSTDOWN)); #endif #ifdef WSAEHOSTUNREACH - put(Identifier::fromString(vm, "WSAEHOSTUNREACH"_s), jsNumber(WSAEHOSTUNREACH)); + put(Identifier::fromString(vm, "WSAEHOSTUNREACH"_s), + jsNumber(WSAEHOSTUNREACH)); #endif #ifdef WSAENOTEMPTY - put(Identifier::fromString(vm, "WSAENOTEMPTY"_s), jsNumber(WSAENOTEMPTY)); + put(Identifier::fromString(vm, "WSAENOTEMPTY"_s), jsNumber(WSAENOTEMPTY)); #endif #ifdef WSAEPROCLIM - put(Identifier::fromString(vm, "WSAEPROCLIM"_s), jsNumber(WSAEPROCLIM)); + put(Identifier::fromString(vm, "WSAEPROCLIM"_s), jsNumber(WSAEPROCLIM)); #endif #ifdef WSAEUSERS - put(Identifier::fromString(vm, "WSAEUSERS"_s), jsNumber(WSAEUSERS)); + put(Identifier::fromString(vm, "WSAEUSERS"_s), jsNumber(WSAEUSERS)); #endif #ifdef WSAEDQUOT - put(Identifier::fromString(vm, "WSAEDQUOT"_s), jsNumber(WSAEDQUOT)); + put(Identifier::fromString(vm, "WSAEDQUOT"_s), jsNumber(WSAEDQUOT)); #endif #ifdef WSAESTALE - put(Identifier::fromString(vm, "WSAESTALE"_s), jsNumber(WSAESTALE)); + put(Identifier::fromString(vm, "WSAESTALE"_s), jsNumber(WSAESTALE)); #endif #ifdef WSAEREMOTE - put(Identifier::fromString(vm, "WSAEREMOTE"_s), jsNumber(WSAEREMOTE)); + put(Identifier::fromString(vm, "WSAEREMOTE"_s), jsNumber(WSAEREMOTE)); #endif #ifdef WSASYSNOTREADY - put(Identifier::fromString(vm, "WSASYSNOTREADY"_s), jsNumber(WSASYSNOTREADY)); + put(Identifier::fromString(vm, "WSASYSNOTREADY"_s), jsNumber(WSASYSNOTREADY)); #endif #ifdef WSAVERNOTSUPPORTED - put(Identifier::fromString(vm, "WSAVERNOTSUPPORTED"_s), jsNumber(WSAVERNOTSUPPORTED)); + put(Identifier::fromString(vm, "WSAVERNOTSUPPORTED"_s), + jsNumber(WSAVERNOTSUPPORTED)); #endif #ifdef WSANOTINITIALISED - put(Identifier::fromString(vm, "WSANOTINITIALISED"_s), jsNumber(WSANOTINITIALISED)); + put(Identifier::fromString(vm, "WSANOTINITIALISED"_s), + jsNumber(WSANOTINITIALISED)); #endif #ifdef WSAEDISCON - put(Identifier::fromString(vm, "WSAEDISCON"_s), jsNumber(WSAEDISCON)); + put(Identifier::fromString(vm, "WSAEDISCON"_s), jsNumber(WSAEDISCON)); #endif #ifdef WSAENOMORE - put(Identifier::fromString(vm, "WSAENOMORE"_s), jsNumber(WSAENOMORE)); + put(Identifier::fromString(vm, "WSAENOMORE"_s), jsNumber(WSAENOMORE)); #endif #ifdef WSAECANCELLED - put(Identifier::fromString(vm, "WSAECANCELLED"_s), jsNumber(WSAECANCELLED)); + put(Identifier::fromString(vm, "WSAECANCELLED"_s), jsNumber(WSAECANCELLED)); #endif #ifdef WSAEINVALIDPROCTABLE - put(Identifier::fromString(vm, "WSAEINVALIDPROCTABLE"_s), jsNumber(WSAEINVALIDPROCTABLE)); + put(Identifier::fromString(vm, "WSAEINVALIDPROCTABLE"_s), + jsNumber(WSAEINVALIDPROCTABLE)); #endif #ifdef WSAEINVALIDPROVIDER - put(Identifier::fromString(vm, "WSAEINVALIDPROVIDER"_s), jsNumber(WSAEINVALIDPROVIDER)); + put(Identifier::fromString(vm, "WSAEINVALIDPROVIDER"_s), + jsNumber(WSAEINVALIDPROVIDER)); #endif #ifdef WSAEPROVIDERFAILEDINIT - put(Identifier::fromString(vm, "WSAEPROVIDERFAILEDINIT"_s), jsNumber(WSAEPROVIDERFAILEDINIT)); + put(Identifier::fromString(vm, "WSAEPROVIDERFAILEDINIT"_s), + jsNumber(WSAEPROVIDERFAILEDINIT)); #endif #ifdef WSASYSCALLFAILURE - put(Identifier::fromString(vm, "WSASYSCALLFAILURE"_s), jsNumber(WSASYSCALLFAILURE)); + put(Identifier::fromString(vm, "WSASYSCALLFAILURE"_s), + jsNumber(WSASYSCALLFAILURE)); #endif #ifdef WSASERVICE_NOT_FOUND - put(Identifier::fromString(vm, "WSASERVICE_NOT_FOUND"_s), jsNumber(WSASERVICE_NOT_FOUND)); + put(Identifier::fromString(vm, "WSASERVICE_NOT_FOUND"_s), + jsNumber(WSASERVICE_NOT_FOUND)); #endif #ifdef WSATYPE_NOT_FOUND - put(Identifier::fromString(vm, "WSATYPE_NOT_FOUND"_s), jsNumber(WSATYPE_NOT_FOUND)); + put(Identifier::fromString(vm, "WSATYPE_NOT_FOUND"_s), + jsNumber(WSATYPE_NOT_FOUND)); #endif #ifdef WSA_E_NO_MORE - put(Identifier::fromString(vm, "WSA_E_NO_MORE"_s), jsNumber(WSA_E_NO_MORE)); + put(Identifier::fromString(vm, "WSA_E_NO_MORE"_s), jsNumber(WSA_E_NO_MORE)); #endif #ifdef WSA_E_CANCELLED - put(Identifier::fromString(vm, "WSA_E_CANCELLED"_s), jsNumber(WSA_E_CANCELLED)); + put(Identifier::fromString(vm, "WSA_E_CANCELLED"_s), + jsNumber(WSA_E_CANCELLED)); #endif #ifdef WSAEREFUSED - put(Identifier::fromString(vm, "WSAEREFUSED"_s), jsNumber(WSAEREFUSED)); -#endif - put(Identifier::fromString(vm, "PRIORITY_LOW"_s), jsNumber(19)); - put(Identifier::fromString(vm, "PRIORITY_BELOW_NORMAL"_s), jsNumber(10)); - put(Identifier::fromString(vm, "PRIORITY_NORMAL"_s), jsNumber(0)); - put(Identifier::fromString(vm, "PRIORITY_ABOVE_NORMAL"_s), jsNumber(-7)); - put(Identifier::fromString(vm, "PRIORITY_HIGH"_s), jsNumber(-14)); - put(Identifier::fromString(vm, "PRIORITY_HIGHEST"_s), jsNumber(-20)); + put(Identifier::fromString(vm, "WSAEREFUSED"_s), jsNumber(WSAEREFUSED)); +#endif + put(Identifier::fromString(vm, "PRIORITY_LOW"_s), jsNumber(19)); + put(Identifier::fromString(vm, "PRIORITY_BELOW_NORMAL"_s), jsNumber(10)); + put(Identifier::fromString(vm, "PRIORITY_NORMAL"_s), jsNumber(0)); + put(Identifier::fromString(vm, "PRIORITY_ABOVE_NORMAL"_s), jsNumber(-7)); + put(Identifier::fromString(vm, "PRIORITY_HIGH"_s), jsNumber(-14)); + put(Identifier::fromString(vm, "PRIORITY_HIGHEST"_s), jsNumber(-20)); #ifdef SIGHUP - put(Identifier::fromString(vm, "SIGHUP"_s), jsNumber(SIGHUP)); + put(Identifier::fromString(vm, "SIGHUP"_s), jsNumber(SIGHUP)); #endif #ifdef SIGINT - put(Identifier::fromString(vm, "SIGINT"_s), jsNumber(SIGINT)); + put(Identifier::fromString(vm, "SIGINT"_s), jsNumber(SIGINT)); #endif #ifdef SIGQUIT - put(Identifier::fromString(vm, "SIGQUIT"_s), jsNumber(SIGQUIT)); + put(Identifier::fromString(vm, "SIGQUIT"_s), jsNumber(SIGQUIT)); #endif #ifdef SIGILL - put(Identifier::fromString(vm, "SIGILL"_s), jsNumber(SIGILL)); + put(Identifier::fromString(vm, "SIGILL"_s), jsNumber(SIGILL)); #endif #ifdef SIGTRAP - put(Identifier::fromString(vm, "SIGTRAP"_s), jsNumber(SIGTRAP)); + put(Identifier::fromString(vm, "SIGTRAP"_s), jsNumber(SIGTRAP)); #endif #ifdef SIGABRT - put(Identifier::fromString(vm, "SIGABRT"_s), jsNumber(SIGABRT)); + put(Identifier::fromString(vm, "SIGABRT"_s), jsNumber(SIGABRT)); #endif #ifdef SIGIOT - put(Identifier::fromString(vm, "SIGIOT"_s), jsNumber(SIGIOT)); + put(Identifier::fromString(vm, "SIGIOT"_s), jsNumber(SIGIOT)); #endif #ifdef SIGBUS - put(Identifier::fromString(vm, "SIGBUS"_s), jsNumber(SIGBUS)); + put(Identifier::fromString(vm, "SIGBUS"_s), jsNumber(SIGBUS)); #endif #ifdef SIGFPE - put(Identifier::fromString(vm, "SIGFPE"_s), jsNumber(SIGFPE)); + put(Identifier::fromString(vm, "SIGFPE"_s), jsNumber(SIGFPE)); #endif #ifdef SIGKILL - put(Identifier::fromString(vm, "SIGKILL"_s), jsNumber(SIGKILL)); + put(Identifier::fromString(vm, "SIGKILL"_s), jsNumber(SIGKILL)); #endif #ifdef SIGUSR1 - put(Identifier::fromString(vm, "SIGUSR1"_s), jsNumber(SIGUSR1)); + put(Identifier::fromString(vm, "SIGUSR1"_s), jsNumber(SIGUSR1)); #endif #ifdef SIGSEGV - put(Identifier::fromString(vm, "SIGSEGV"_s), jsNumber(SIGSEGV)); + put(Identifier::fromString(vm, "SIGSEGV"_s), jsNumber(SIGSEGV)); #endif #ifdef SIGUSR2 - put(Identifier::fromString(vm, "SIGUSR2"_s), jsNumber(SIGUSR2)); + put(Identifier::fromString(vm, "SIGUSR2"_s), jsNumber(SIGUSR2)); #endif #ifdef SIGPIPE - put(Identifier::fromString(vm, "SIGPIPE"_s), jsNumber(SIGPIPE)); + put(Identifier::fromString(vm, "SIGPIPE"_s), jsNumber(SIGPIPE)); #endif #ifdef SIGALRM - put(Identifier::fromString(vm, "SIGALRM"_s), jsNumber(SIGALRM)); + put(Identifier::fromString(vm, "SIGALRM"_s), jsNumber(SIGALRM)); #endif #ifdef SIGTERM - put(Identifier::fromString(vm, "SIGTERM"_s), jsNumber(SIGTERM)); + put(Identifier::fromString(vm, "SIGTERM"_s), jsNumber(SIGTERM)); #endif #ifdef SIGCHLD - put(Identifier::fromString(vm, "SIGCHLD"_s), jsNumber(SIGCHLD)); + put(Identifier::fromString(vm, "SIGCHLD"_s), jsNumber(SIGCHLD)); #endif #ifdef SIGSTKFLT - put(Identifier::fromString(vm, "SIGSTKFLT"_s), jsNumber(SIGSTKFLT)); + put(Identifier::fromString(vm, "SIGSTKFLT"_s), jsNumber(SIGSTKFLT)); #endif #ifdef SIGCONT - put(Identifier::fromString(vm, "SIGCONT"_s), jsNumber(SIGCONT)); + put(Identifier::fromString(vm, "SIGCONT"_s), jsNumber(SIGCONT)); #endif #ifdef SIGSTOP - put(Identifier::fromString(vm, "SIGSTOP"_s), jsNumber(SIGSTOP)); + put(Identifier::fromString(vm, "SIGSTOP"_s), jsNumber(SIGSTOP)); #endif #ifdef SIGTSTP - put(Identifier::fromString(vm, "SIGTSTP"_s), jsNumber(SIGTSTP)); + put(Identifier::fromString(vm, "SIGTSTP"_s), jsNumber(SIGTSTP)); #endif #ifdef SIGBREAK - put(Identifier::fromString(vm, "SIGBREAK"_s), jsNumber(SIGBREAK)); + put(Identifier::fromString(vm, "SIGBREAK"_s), jsNumber(SIGBREAK)); #endif #ifdef SIGTTIN - put(Identifier::fromString(vm, "SIGTTIN"_s), jsNumber(SIGTTIN)); + put(Identifier::fromString(vm, "SIGTTIN"_s), jsNumber(SIGTTIN)); #endif #ifdef SIGTTOU - put(Identifier::fromString(vm, "SIGTTOU"_s), jsNumber(SIGTTOU)); + put(Identifier::fromString(vm, "SIGTTOU"_s), jsNumber(SIGTTOU)); #endif #ifdef SIGURG - put(Identifier::fromString(vm, "SIGURG"_s), jsNumber(SIGURG)); + put(Identifier::fromString(vm, "SIGURG"_s), jsNumber(SIGURG)); #endif #ifdef SIGXCPU - put(Identifier::fromString(vm, "SIGXCPU"_s), jsNumber(SIGXCPU)); + put(Identifier::fromString(vm, "SIGXCPU"_s), jsNumber(SIGXCPU)); #endif #ifdef SIGXFSZ - put(Identifier::fromString(vm, "SIGXFSZ"_s), jsNumber(SIGXFSZ)); + put(Identifier::fromString(vm, "SIGXFSZ"_s), jsNumber(SIGXFSZ)); #endif #ifdef SIGVTALRM - put(Identifier::fromString(vm, "SIGVTALRM"_s), jsNumber(SIGVTALRM)); + put(Identifier::fromString(vm, "SIGVTALRM"_s), jsNumber(SIGVTALRM)); #endif #ifdef SIGPROF - put(Identifier::fromString(vm, "SIGPROF"_s), jsNumber(SIGPROF)); + put(Identifier::fromString(vm, "SIGPROF"_s), jsNumber(SIGPROF)); #endif #ifdef SIGWINCH - put(Identifier::fromString(vm, "SIGWINCH"_s), jsNumber(SIGWINCH)); + put(Identifier::fromString(vm, "SIGWINCH"_s), jsNumber(SIGWINCH)); #endif #ifdef SIGIO - put(Identifier::fromString(vm, "SIGIO"_s), jsNumber(SIGIO)); + put(Identifier::fromString(vm, "SIGIO"_s), jsNumber(SIGIO)); #endif #ifdef SIGPOLL - put(Identifier::fromString(vm, "SIGPOLL"_s), jsNumber(SIGPOLL)); + put(Identifier::fromString(vm, "SIGPOLL"_s), jsNumber(SIGPOLL)); #endif #ifdef SIGLOST - put(Identifier::fromString(vm, "SIGLOST"_s), jsNumber(SIGLOST)); + put(Identifier::fromString(vm, "SIGLOST"_s), jsNumber(SIGLOST)); #endif #ifdef SIGPWR - put(Identifier::fromString(vm, "SIGPWR"_s), jsNumber(SIGPWR)); + put(Identifier::fromString(vm, "SIGPWR"_s), jsNumber(SIGPWR)); #endif #ifdef SIGINFO - put(Identifier::fromString(vm, "SIGINFO"_s), jsNumber(SIGINFO)); + put(Identifier::fromString(vm, "SIGINFO"_s), jsNumber(SIGINFO)); #endif #ifdef SIGSYS - put(Identifier::fromString(vm, "SIGSYS"_s), jsNumber(SIGSYS)); + put(Identifier::fromString(vm, "SIGSYS"_s), jsNumber(SIGSYS)); #endif #ifdef SIGUNUSED - put(Identifier::fromString(vm, "SIGUNUSED"_s), jsNumber(SIGUNUSED)); + put(Identifier::fromString(vm, "SIGUNUSED"_s), jsNumber(SIGUNUSED)); #endif - put(Identifier::fromString(vm, "UV_FS_SYMLINK_DIR"_s), jsNumber(1)); - put(Identifier::fromString(vm, "UV_FS_SYMLINK_JUNCTION"_s), jsNumber(2)); - put(Identifier::fromString(vm, "O_RDONLY"_s), jsNumber(O_RDONLY)); - put(Identifier::fromString(vm, "O_WRONLY"_s), jsNumber(O_WRONLY)); - put(Identifier::fromString(vm, "O_RDWR"_s), jsNumber(O_RDWR)); + put(Identifier::fromString(vm, "UV_FS_SYMLINK_DIR"_s), jsNumber(1)); + put(Identifier::fromString(vm, "UV_FS_SYMLINK_JUNCTION"_s), jsNumber(2)); + put(Identifier::fromString(vm, "O_RDONLY"_s), jsNumber(O_RDONLY)); + put(Identifier::fromString(vm, "O_WRONLY"_s), jsNumber(O_WRONLY)); + put(Identifier::fromString(vm, "O_RDWR"_s), jsNumber(O_RDWR)); - put(Identifier::fromString(vm, "UV_DIRENT_UNKNOWN"_s), jsNumber(0)); - put(Identifier::fromString(vm, "UV_DIRENT_FILE"_s), jsNumber(1)); - put(Identifier::fromString(vm, "UV_DIRENT_DIR"_s), jsNumber(2)); - put(Identifier::fromString(vm, "UV_DIRENT_LINK"_s), jsNumber(3)); - put(Identifier::fromString(vm, "UV_DIRENT_FIFO"_s), jsNumber(4)); - put(Identifier::fromString(vm, "UV_DIRENT_SOCKET"_s), jsNumber(5)); - put(Identifier::fromString(vm, "UV_DIRENT_CHAR"_s), jsNumber(6)); - put(Identifier::fromString(vm, "UV_DIRENT_BLOCK"_s), jsNumber(7)); + put(Identifier::fromString(vm, "UV_DIRENT_UNKNOWN"_s), jsNumber(0)); + put(Identifier::fromString(vm, "UV_DIRENT_FILE"_s), jsNumber(1)); + put(Identifier::fromString(vm, "UV_DIRENT_DIR"_s), jsNumber(2)); + put(Identifier::fromString(vm, "UV_DIRENT_LINK"_s), jsNumber(3)); + put(Identifier::fromString(vm, "UV_DIRENT_FIFO"_s), jsNumber(4)); + put(Identifier::fromString(vm, "UV_DIRENT_SOCKET"_s), jsNumber(5)); + put(Identifier::fromString(vm, "UV_DIRENT_CHAR"_s), jsNumber(6)); + put(Identifier::fromString(vm, "UV_DIRENT_BLOCK"_s), jsNumber(7)); - put(Identifier::fromString(vm, "S_IFMT"_s), jsNumber(S_IFMT)); - put(Identifier::fromString(vm, "S_IFREG"_s), jsNumber(S_IFREG)); - put(Identifier::fromString(vm, "S_IFDIR"_s), jsNumber(S_IFDIR)); - put(Identifier::fromString(vm, "S_IFCHR"_s), jsNumber(S_IFCHR)); + put(Identifier::fromString(vm, "S_IFMT"_s), jsNumber(S_IFMT)); + put(Identifier::fromString(vm, "S_IFREG"_s), jsNumber(S_IFREG)); + put(Identifier::fromString(vm, "S_IFDIR"_s), jsNumber(S_IFDIR)); + put(Identifier::fromString(vm, "S_IFCHR"_s), jsNumber(S_IFCHR)); #ifdef S_IFBLK - put(Identifier::fromString(vm, "S_IFBLK"_s), jsNumber(S_IFBLK)); + put(Identifier::fromString(vm, "S_IFBLK"_s), jsNumber(S_IFBLK)); #endif #ifdef S_IFIFO - put(Identifier::fromString(vm, "S_IFIFO"_s), jsNumber(S_IFIFO)); + put(Identifier::fromString(vm, "S_IFIFO"_s), jsNumber(S_IFIFO)); #endif #ifdef S_IFLNK - put(Identifier::fromString(vm, "S_IFLNK"_s), jsNumber(S_IFLNK)); + put(Identifier::fromString(vm, "S_IFLNK"_s), jsNumber(S_IFLNK)); #endif #ifdef S_IFSOCK - put(Identifier::fromString(vm, "S_IFSOCK"_s), jsNumber(S_IFSOCK)); + put(Identifier::fromString(vm, "S_IFSOCK"_s), jsNumber(S_IFSOCK)); #endif #ifdef O_CREAT - put(Identifier::fromString(vm, "O_CREAT"_s), jsNumber(O_CREAT)); + put(Identifier::fromString(vm, "O_CREAT"_s), jsNumber(O_CREAT)); #endif #ifdef O_EXCL - put(Identifier::fromString(vm, "O_EXCL"_s), jsNumber(O_EXCL)); + put(Identifier::fromString(vm, "O_EXCL"_s), jsNumber(O_EXCL)); #endif - put(Identifier::fromString(vm, "UV_FS_O_FILEMAP"_s), jsNumber(0)); + put(Identifier::fromString(vm, "UV_FS_O_FILEMAP"_s), jsNumber(0)); #ifdef O_NOCTTY - put(Identifier::fromString(vm, "O_NOCTTY"_s), jsNumber(O_NOCTTY)); + put(Identifier::fromString(vm, "O_NOCTTY"_s), jsNumber(O_NOCTTY)); #endif #ifdef O_TRUNC - put(Identifier::fromString(vm, "O_TRUNC"_s), jsNumber(O_TRUNC)); + put(Identifier::fromString(vm, "O_TRUNC"_s), jsNumber(O_TRUNC)); #endif #ifdef O_APPEND - put(Identifier::fromString(vm, "O_APPEND"_s), jsNumber(O_APPEND)); + put(Identifier::fromString(vm, "O_APPEND"_s), jsNumber(O_APPEND)); #endif #ifdef O_DIRECTORY - put(Identifier::fromString(vm, "O_DIRECTORY"_s), jsNumber(O_DIRECTORY)); -#endif -#ifdef O_EXCL - put(Identifier::fromString(vm, "O_EXCL"_s), jsNumber(O_EXCL)); + put(Identifier::fromString(vm, "O_DIRECTORY"_s), jsNumber(O_DIRECTORY)); #endif #ifdef O_NOATIME - put(Identifier::fromString(vm, "O_NOATIME"_s), jsNumber(O_NOATIME)); + put(Identifier::fromString(vm, "O_NOATIME"_s), jsNumber(O_NOATIME)); #endif #ifdef O_NOFOLLOW - put(Identifier::fromString(vm, "O_NOFOLLOW"_s), jsNumber(O_NOFOLLOW)); + put(Identifier::fromString(vm, "O_NOFOLLOW"_s), jsNumber(O_NOFOLLOW)); #endif #ifdef O_SYNC - put(Identifier::fromString(vm, "O_SYNC"_s), jsNumber(O_SYNC)); + put(Identifier::fromString(vm, "O_SYNC"_s), jsNumber(O_SYNC)); #endif #ifdef O_DSYNC - put(Identifier::fromString(vm, "O_DSYNC"_s), jsNumber(O_DSYNC)); + put(Identifier::fromString(vm, "O_DSYNC"_s), jsNumber(O_DSYNC)); #endif #ifdef O_SYMLINK - put(Identifier::fromString(vm, "O_SYMLINK"_s), jsNumber(O_SYMLINK)); + put(Identifier::fromString(vm, "O_SYMLINK"_s), jsNumber(O_SYMLINK)); #endif #ifdef O_DIRECT - put(Identifier::fromString(vm, "O_DIRECT"_s), jsNumber(O_DIRECT)); + put(Identifier::fromString(vm, "O_DIRECT"_s), jsNumber(O_DIRECT)); #endif #ifdef O_NONBLOCK - put(Identifier::fromString(vm, "O_NONBLOCK"_s), jsNumber(O_NONBLOCK)); + put(Identifier::fromString(vm, "O_NONBLOCK"_s), jsNumber(O_NONBLOCK)); #endif #ifdef S_IRWXU - put(Identifier::fromString(vm, "S_IRWXU"_s), jsNumber(S_IRWXU)); + put(Identifier::fromString(vm, "S_IRWXU"_s), jsNumber(S_IRWXU)); #endif #ifdef S_IRUSR - put(Identifier::fromString(vm, "S_IRUSR"_s), jsNumber(S_IRUSR)); + put(Identifier::fromString(vm, "S_IRUSR"_s), jsNumber(S_IRUSR)); #endif #ifdef S_IWUSR - put(Identifier::fromString(vm, "S_IWUSR"_s), jsNumber(S_IWUSR)); + put(Identifier::fromString(vm, "S_IWUSR"_s), jsNumber(S_IWUSR)); #endif #ifdef S_IXUSR - put(Identifier::fromString(vm, "S_IXUSR"_s), jsNumber(S_IXUSR)); + put(Identifier::fromString(vm, "S_IXUSR"_s), jsNumber(S_IXUSR)); #endif #ifdef S_IRWXG - put(Identifier::fromString(vm, "S_IRWXG"_s), jsNumber(S_IRWXG)); + put(Identifier::fromString(vm, "S_IRWXG"_s), jsNumber(S_IRWXG)); #endif #ifdef S_IRGRP - put(Identifier::fromString(vm, "S_IRGRP"_s), jsNumber(S_IRGRP)); + put(Identifier::fromString(vm, "S_IRGRP"_s), jsNumber(S_IRGRP)); #endif #ifdef S_IWGRP - put(Identifier::fromString(vm, "S_IWGRP"_s), jsNumber(S_IWGRP)); + put(Identifier::fromString(vm, "S_IWGRP"_s), jsNumber(S_IWGRP)); #endif #ifdef S_IXGRP - put(Identifier::fromString(vm, "S_IXGRP"_s), jsNumber(S_IXGRP)); + put(Identifier::fromString(vm, "S_IXGRP"_s), jsNumber(S_IXGRP)); #endif #ifdef S_IRWXO - put(Identifier::fromString(vm, "S_IRWXO"_s), jsNumber(S_IRWXO)); + put(Identifier::fromString(vm, "S_IRWXO"_s), jsNumber(S_IRWXO)); #endif #ifdef S_IROTH - put(Identifier::fromString(vm, "S_IROTH"_s), jsNumber(S_IROTH)); + put(Identifier::fromString(vm, "S_IROTH"_s), jsNumber(S_IROTH)); #endif #ifdef S_IWOTH - put(Identifier::fromString(vm, "S_IWOTH"_s), jsNumber(S_IWOTH)); + put(Identifier::fromString(vm, "S_IWOTH"_s), jsNumber(S_IWOTH)); #endif #ifdef S_IXOTH - put(Identifier::fromString(vm, "S_IXOTH"_s), jsNumber(S_IXOTH)); + put(Identifier::fromString(vm, "S_IXOTH"_s), jsNumber(S_IXOTH)); #endif #ifdef F_OK - put(Identifier::fromString(vm, "F_OK"_s), jsNumber(F_OK)); + put(Identifier::fromString(vm, "F_OK"_s), jsNumber(F_OK)); #endif #ifdef R_OK - put(Identifier::fromString(vm, "R_OK"_s), jsNumber(R_OK)); + put(Identifier::fromString(vm, "R_OK"_s), jsNumber(R_OK)); #endif #ifdef W_OK - put(Identifier::fromString(vm, "W_OK"_s), jsNumber(W_OK)); + put(Identifier::fromString(vm, "W_OK"_s), jsNumber(W_OK)); #endif #ifdef X_OK - put(Identifier::fromString(vm, "X_OK"_s), jsNumber(X_OK)); -#endif - put(Identifier::fromString(vm, "UV_FS_COPYFILE_EXCL"_s), jsNumber(1)); - put(Identifier::fromString(vm, "COPYFILE_EXCL"_s), jsNumber(1)); - put(Identifier::fromString(vm, "UV_FS_COPYFILE_FICLONE"_s), jsNumber(2)); - put(Identifier::fromString(vm, "COPYFILE_FICLONE"_s), jsNumber(2)); - put(Identifier::fromString(vm, "UV_FS_COPYFILE_FICLONE_FORCE"_s), jsNumber(4)); - put(Identifier::fromString(vm, "COPYFILE_FICLONE_FORCE"_s), jsNumber(4)); + put(Identifier::fromString(vm, "X_OK"_s), jsNumber(X_OK)); +#endif + put(Identifier::fromString(vm, "UV_FS_COPYFILE_EXCL"_s), jsNumber(1)); + put(Identifier::fromString(vm, "COPYFILE_EXCL"_s), jsNumber(1)); + put(Identifier::fromString(vm, "UV_FS_COPYFILE_FICLONE"_s), jsNumber(2)); + put(Identifier::fromString(vm, "COPYFILE_FICLONE"_s), jsNumber(2)); + put(Identifier::fromString(vm, "UV_FS_COPYFILE_FICLONE_FORCE"_s), + jsNumber(4)); + put(Identifier::fromString(vm, "COPYFILE_FICLONE_FORCE"_s), jsNumber(4)); #ifdef OPENSSL_VERSION_NUMBER - put(Identifier::fromString(vm, "OPENSSL_VERSION_NUMBER"_s), jsNumber(OPENSSL_VERSION_NUMBER)); + put(Identifier::fromString(vm, "OPENSSL_VERSION_NUMBER"_s), + jsNumber(OPENSSL_VERSION_NUMBER)); #endif #ifdef SSL_OP_ALL - put(Identifier::fromString(vm, "SSL_OP_ALL"_s), jsNumber(SSL_OP_ALL)); + put(Identifier::fromString(vm, "SSL_OP_ALL"_s), jsNumber(SSL_OP_ALL)); #endif #ifdef SSL_OP_ALLOW_NO_DHE_KEX - put(Identifier::fromString(vm, "SSL_OP_ALLOW_NO_DHE_KEX"_s), jsNumber(SSL_OP_ALLOW_NO_DHE_KEX)); + put(Identifier::fromString(vm, "SSL_OP_ALLOW_NO_DHE_KEX"_s), + jsNumber(SSL_OP_ALLOW_NO_DHE_KEX)); #endif #ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION - put(Identifier::fromString(vm, "SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION"_s), jsNumber(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)); + put(Identifier::fromString(vm, "SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION"_s), + jsNumber(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)); #endif #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE - put(Identifier::fromString(vm, "SSL_OP_CIPHER_SERVER_PREFERENCE"_s), jsNumber(SSL_OP_CIPHER_SERVER_PREFERENCE)); + put(Identifier::fromString(vm, "SSL_OP_CIPHER_SERVER_PREFERENCE"_s), + jsNumber(SSL_OP_CIPHER_SERVER_PREFERENCE)); #endif #ifdef SSL_OP_CISCO_ANYCONNECT - put(Identifier::fromString(vm, "SSL_OP_CISCO_ANYCONNECT"_s), jsNumber(SSL_OP_CISCO_ANYCONNECT)); + put(Identifier::fromString(vm, "SSL_OP_CISCO_ANYCONNECT"_s), + jsNumber(SSL_OP_CISCO_ANYCONNECT)); #endif #ifdef SSL_OP_COOKIE_EXCHANGE - put(Identifier::fromString(vm, "SSL_OP_COOKIE_EXCHANGE"_s), jsNumber(SSL_OP_COOKIE_EXCHANGE)); + put(Identifier::fromString(vm, "SSL_OP_COOKIE_EXCHANGE"_s), + jsNumber(SSL_OP_COOKIE_EXCHANGE)); #endif #ifdef SSL_OP_CRYPTOPRO_TLSEXT_BUG - put(Identifier::fromString(vm, "SSL_OP_CRYPTOPRO_TLSEXT_BUG"_s), jsNumber(SSL_OP_CRYPTOPRO_TLSEXT_BUG)); + put(Identifier::fromString(vm, "SSL_OP_CRYPTOPRO_TLSEXT_BUG"_s), + jsNumber(SSL_OP_CRYPTOPRO_TLSEXT_BUG)); #endif #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS - put(Identifier::fromString(vm, "SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS"_s), jsNumber(SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)); + put(Identifier::fromString(vm, "SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS"_s), + jsNumber(SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)); #endif #ifdef SSL_OP_LEGACY_SERVER_CONNECT - put(Identifier::fromString(vm, "SSL_OP_LEGACY_SERVER_CONNECT"_s), jsNumber(SSL_OP_LEGACY_SERVER_CONNECT)); + put(Identifier::fromString(vm, "SSL_OP_LEGACY_SERVER_CONNECT"_s), + jsNumber(SSL_OP_LEGACY_SERVER_CONNECT)); #endif #ifdef SSL_OP_NO_COMPRESSION - put(Identifier::fromString(vm, "SSL_OP_NO_COMPRESSION"_s), jsNumber(SSL_OP_NO_COMPRESSION)); + put(Identifier::fromString(vm, "SSL_OP_NO_COMPRESSION"_s), + jsNumber(SSL_OP_NO_COMPRESSION)); #endif #ifdef SSL_OP_NO_ENCRYPT_THEN_MAC - put(Identifier::fromString(vm, "SSL_OP_NO_ENCRYPT_THEN_MAC"_s), jsNumber(SSL_OP_NO_ENCRYPT_THEN_MAC)); + put(Identifier::fromString(vm, "SSL_OP_NO_ENCRYPT_THEN_MAC"_s), + jsNumber(SSL_OP_NO_ENCRYPT_THEN_MAC)); #endif #ifdef SSL_OP_NO_QUERY_MTU - put(Identifier::fromString(vm, "SSL_OP_NO_QUERY_MTU"_s), jsNumber(SSL_OP_NO_QUERY_MTU)); + put(Identifier::fromString(vm, "SSL_OP_NO_QUERY_MTU"_s), + jsNumber(SSL_OP_NO_QUERY_MTU)); #endif #ifdef SSL_OP_NO_RENEGOTIATION - put(Identifier::fromString(vm, "SSL_OP_NO_RENEGOTIATION"_s), jsNumber(SSL_OP_NO_RENEGOTIATION)); + put(Identifier::fromString(vm, "SSL_OP_NO_RENEGOTIATION"_s), + jsNumber(SSL_OP_NO_RENEGOTIATION)); #endif #ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION - put(Identifier::fromString(vm, "SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION"_s), jsNumber(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)); + put(Identifier::fromString(vm, + "SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION"_s), + jsNumber(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)); #endif #ifdef SSL_OP_NO_SSLv2 - put(Identifier::fromString(vm, "SSL_OP_NO_SSLv2"_s), jsNumber(SSL_OP_NO_SSLv2)); + put(Identifier::fromString(vm, "SSL_OP_NO_SSLv2"_s), + jsNumber(SSL_OP_NO_SSLv2)); #endif #ifdef SSL_OP_NO_SSLv3 - put(Identifier::fromString(vm, "SSL_OP_NO_SSLv3"_s), jsNumber(SSL_OP_NO_SSLv3)); + put(Identifier::fromString(vm, "SSL_OP_NO_SSLv3"_s), + jsNumber(SSL_OP_NO_SSLv3)); #endif #ifdef SSL_OP_NO_TICKET - put(Identifier::fromString(vm, "SSL_OP_NO_TICKET"_s), jsNumber(SSL_OP_NO_TICKET)); + put(Identifier::fromString(vm, "SSL_OP_NO_TICKET"_s), + jsNumber(SSL_OP_NO_TICKET)); #endif #ifdef SSL_OP_NO_TLSv1 - put(Identifier::fromString(vm, "SSL_OP_NO_TLSv1"_s), jsNumber(SSL_OP_NO_TLSv1)); + put(Identifier::fromString(vm, "SSL_OP_NO_TLSv1"_s), + jsNumber(SSL_OP_NO_TLSv1)); #endif #ifdef SSL_OP_NO_TLSv1_1 - put(Identifier::fromString(vm, "SSL_OP_NO_TLSv1_1"_s), jsNumber(SSL_OP_NO_TLSv1_1)); + put(Identifier::fromString(vm, "SSL_OP_NO_TLSv1_1"_s), + jsNumber(SSL_OP_NO_TLSv1_1)); #endif #ifdef SSL_OP_NO_TLSv1_2 - put(Identifier::fromString(vm, "SSL_OP_NO_TLSv1_2"_s), jsNumber(SSL_OP_NO_TLSv1_2)); + put(Identifier::fromString(vm, "SSL_OP_NO_TLSv1_2"_s), + jsNumber(SSL_OP_NO_TLSv1_2)); #endif #ifdef SSL_OP_NO_TLSv1_3 - put(Identifier::fromString(vm, "SSL_OP_NO_TLSv1_3"_s), jsNumber(SSL_OP_NO_TLSv1_3)); + put(Identifier::fromString(vm, "SSL_OP_NO_TLSv1_3"_s), + jsNumber(SSL_OP_NO_TLSv1_3)); #endif #ifdef SSL_OP_PRIORITIZE_CHACHA - put(Identifier::fromString(vm, "SSL_OP_PRIORITIZE_CHACHA"_s), jsNumber(SSL_OP_PRIORITIZE_CHACHA)); + put(Identifier::fromString(vm, "SSL_OP_PRIORITIZE_CHACHA"_s), + jsNumber(SSL_OP_PRIORITIZE_CHACHA)); #endif #ifdef SSL_OP_TLS_ROLLBACK_BUG - put(Identifier::fromString(vm, "SSL_OP_TLS_ROLLBACK_BUG"_s), jsNumber(SSL_OP_TLS_ROLLBACK_BUG)); + put(Identifier::fromString(vm, "SSL_OP_TLS_ROLLBACK_BUG"_s), + jsNumber(SSL_OP_TLS_ROLLBACK_BUG)); #endif #ifndef OPENSSL_NO_ENGINE #ifdef ENGINE_METHOD_RSA - put(Identifier::fromString(vm, "ENGINE_METHOD_RSA"_s), jsNumber(ENGINE_METHOD_RSA)); + put(Identifier::fromString(vm, "ENGINE_METHOD_RSA"_s), + jsNumber(ENGINE_METHOD_RSA)); #endif #ifdef ENGINE_METHOD_DSA - put(Identifier::fromString(vm, "ENGINE_METHOD_DSA"_s), jsNumber(ENGINE_METHOD_DSA)); + put(Identifier::fromString(vm, "ENGINE_METHOD_DSA"_s), + jsNumber(ENGINE_METHOD_DSA)); #endif #ifdef ENGINE_METHOD_DH - put(Identifier::fromString(vm, "ENGINE_METHOD_DH"_s), jsNumber(ENGINE_METHOD_DH)); + put(Identifier::fromString(vm, "ENGINE_METHOD_DH"_s), + jsNumber(ENGINE_METHOD_DH)); #endif #ifdef ENGINE_METHOD_RAND - put(Identifier::fromString(vm, "ENGINE_METHOD_RAND"_s), jsNumber(ENGINE_METHOD_RAND)); + put(Identifier::fromString(vm, "ENGINE_METHOD_RAND"_s), + jsNumber(ENGINE_METHOD_RAND)); #endif #ifdef ENGINE_METHOD_EC - put(Identifier::fromString(vm, "ENGINE_METHOD_EC"_s), jsNumber(ENGINE_METHOD_EC)); + put(Identifier::fromString(vm, "ENGINE_METHOD_EC"_s), + jsNumber(ENGINE_METHOD_EC)); #endif #ifdef ENGINE_METHOD_CIPHERS - put(Identifier::fromString(vm, "ENGINE_METHOD_CIPHERS"_s), jsNumber(ENGINE_METHOD_CIPHERS)); + put(Identifier::fromString(vm, "ENGINE_METHOD_CIPHERS"_s), + jsNumber(ENGINE_METHOD_CIPHERS)); #endif #ifdef ENGINE_METHOD_DIGESTS - put(Identifier::fromString(vm, "ENGINE_METHOD_DIGESTS"_s), jsNumber(ENGINE_METHOD_DIGESTS)); + put(Identifier::fromString(vm, "ENGINE_METHOD_DIGESTS"_s), + jsNumber(ENGINE_METHOD_DIGESTS)); #endif #ifdef ENGINE_METHOD_PKEY_METHS - put(Identifier::fromString(vm, "ENGINE_METHOD_PKEY_METHS"_s), jsNumber(ENGINE_METHOD_PKEY_METHS)); + put(Identifier::fromString(vm, "ENGINE_METHOD_PKEY_METHS"_s), + jsNumber(ENGINE_METHOD_PKEY_METHS)); #endif #ifdef ENGINE_METHOD_PKEY_ASN1_METHS - put(Identifier::fromString(vm, "ENGINE_METHOD_PKEY_ASN1_METHS"_s), jsNumber(ENGINE_METHOD_PKEY_ASN1_METHS)); + put(Identifier::fromString(vm, "ENGINE_METHOD_PKEY_ASN1_METHS"_s), + jsNumber(ENGINE_METHOD_PKEY_ASN1_METHS)); #endif #ifdef ENGINE_METHOD_ALL - put(Identifier::fromString(vm, "ENGINE_METHOD_ALL"_s), jsNumber(ENGINE_METHOD_ALL)); + put(Identifier::fromString(vm, "ENGINE_METHOD_ALL"_s), + jsNumber(ENGINE_METHOD_ALL)); #endif #ifdef ENGINE_METHOD_NONE - put(Identifier::fromString(vm, "ENGINE_METHOD_NONE"_s), jsNumber(ENGINE_METHOD_NONE)); + put(Identifier::fromString(vm, "ENGINE_METHOD_NONE"_s), + jsNumber(ENGINE_METHOD_NONE)); #endif #endif // !OPENSSL_NO_ENGINE #ifdef DH_CHECK_P_NOT_SAFE_PRIME - put(Identifier::fromString(vm, "DH_CHECK_P_NOT_SAFE_PRIME"_s), jsNumber(DH_CHECK_P_NOT_SAFE_PRIME)); + put(Identifier::fromString(vm, "DH_CHECK_P_NOT_SAFE_PRIME"_s), + jsNumber(DH_CHECK_P_NOT_SAFE_PRIME)); #endif #ifdef DH_CHECK_P_NOT_PRIME - put(Identifier::fromString(vm, "DH_CHECK_P_NOT_PRIME"_s), jsNumber(DH_CHECK_P_NOT_PRIME)); + put(Identifier::fromString(vm, "DH_CHECK_P_NOT_PRIME"_s), + jsNumber(DH_CHECK_P_NOT_PRIME)); #endif #ifdef DH_UNABLE_TO_CHECK_GENERATOR - put(Identifier::fromString(vm, "DH_UNABLE_TO_CHECK_GENERATOR"_s), jsNumber(DH_UNABLE_TO_CHECK_GENERATOR)); + put(Identifier::fromString(vm, "DH_UNABLE_TO_CHECK_GENERATOR"_s), + jsNumber(DH_UNABLE_TO_CHECK_GENERATOR)); #endif #ifdef DH_NOT_SUITABLE_GENERATOR - put(Identifier::fromString(vm, "DH_NOT_SUITABLE_GENERATOR"_s), jsNumber(DH_NOT_SUITABLE_GENERATOR)); + put(Identifier::fromString(vm, "DH_NOT_SUITABLE_GENERATOR"_s), + jsNumber(DH_NOT_SUITABLE_GENERATOR)); #endif #ifdef RSA_PKCS1_PADDING - put(Identifier::fromString(vm, "RSA_PKCS1_PADDING"_s), jsNumber(RSA_PKCS1_PADDING)); + put(Identifier::fromString(vm, "RSA_PKCS1_PADDING"_s), + jsNumber(RSA_PKCS1_PADDING)); #endif #ifdef RSA_SSLV23_PADDING - put(Identifier::fromString(vm, "RSA_SSLV23_PADDING"_s), jsNumber(RSA_SSLV23_PADDING)); + put(Identifier::fromString(vm, "RSA_SSLV23_PADDING"_s), + jsNumber(RSA_SSLV23_PADDING)); #endif #ifdef RSA_NO_PADDING - put(Identifier::fromString(vm, "RSA_NO_PADDING"_s), jsNumber(RSA_NO_PADDING)); + put(Identifier::fromString(vm, "RSA_NO_PADDING"_s), jsNumber(RSA_NO_PADDING)); #endif #ifdef RSA_PKCS1_OAEP_PADDING - put(Identifier::fromString(vm, "RSA_PKCS1_OAEP_PADDING"_s), jsNumber(RSA_PKCS1_OAEP_PADDING)); + put(Identifier::fromString(vm, "RSA_PKCS1_OAEP_PADDING"_s), + jsNumber(RSA_PKCS1_OAEP_PADDING)); #endif #ifdef RSA_X931_PADDING - put(Identifier::fromString(vm, "RSA_X931_PADDING"_s), jsNumber(RSA_X931_PADDING)); + put(Identifier::fromString(vm, "RSA_X931_PADDING"_s), + jsNumber(RSA_X931_PADDING)); #endif #ifdef RSA_PKCS1_PSS_PADDING - put(Identifier::fromString(vm, "RSA_PKCS1_PSS_PADDING"_s), jsNumber(RSA_PKCS1_PSS_PADDING)); + put(Identifier::fromString(vm, "RSA_PKCS1_PSS_PADDING"_s), + jsNumber(RSA_PKCS1_PSS_PADDING)); #endif #ifdef RSA_PSS_SALTLEN_DIGEST - put(Identifier::fromString(vm, "RSA_PSS_SALTLEN_DIGEST"_s), jsNumber(RSA_PSS_SALTLEN_DIGEST)); + put(Identifier::fromString(vm, "RSA_PSS_SALTLEN_DIGEST"_s), + jsNumber(RSA_PSS_SALTLEN_DIGEST)); #endif #ifdef RSA_PSS_SALTLEN_MAX_SIGN - put(Identifier::fromString(vm, "RSA_PSS_SALTLEN_MAX_SIGN"_s), jsNumber(RSA_PSS_SALTLEN_MAX_SIGN)); + put(Identifier::fromString(vm, "RSA_PSS_SALTLEN_MAX_SIGN"_s), + jsNumber(RSA_PSS_SALTLEN_MAX_SIGN)); #endif #ifdef RSA_PSS_SALTLEN_AUTO - put(Identifier::fromString(vm, "RSA_PSS_SALTLEN_AUTO"_s), jsNumber(RSA_PSS_SALTLEN_AUTO)); -#endif - auto cipherList = String("TLS_AES_256_GCM_SHA384:" - "TLS_CHACHA20_POLY1305_SHA256:" - "TLS_AES_128_GCM_SHA256:" - "ECDHE-RSA-AES128-GCM-SHA256:" - "ECDHE-ECDSA-AES128-GCM-SHA256:" - "ECDHE-RSA-AES256-GCM-SHA384:" - "ECDHE-ECDSA-AES256-GCM-SHA384:" - "DHE-RSA-AES128-GCM-SHA256:" - "ECDHE-RSA-AES128-SHA256:" - "DHE-RSA-AES128-SHA256:" - "ECDHE-RSA-AES256-SHA384:" - "DHE-RSA-AES256-SHA384:" - "ECDHE-RSA-AES256-SHA256:" - "DHE-RSA-AES256-SHA256:" - "HIGH:" - "!aNULL:" - "!eNULL:" - "!EXPORT:" - "!DES:" - "!RC4:" - "!MD5:" - "!PSK:" - "!SRP:" - "!CAMELLIA"_s); - put(Identifier::fromString(vm, "defaultCoreCipherList"_s), - jsString(vm, cipherList)); - put(Identifier::fromString(vm, "defaultCipherList"_s), - jsString(vm, cipherList)); + put(Identifier::fromString(vm, "RSA_PSS_SALTLEN_AUTO"_s), + jsNumber(RSA_PSS_SALTLEN_AUTO)); +#endif + auto cipherList = String("TLS_AES_256_GCM_SHA384:" + "TLS_CHACHA20_POLY1305_SHA256:" + "TLS_AES_128_GCM_SHA256:" + "ECDHE-RSA-AES128-GCM-SHA256:" + "ECDHE-ECDSA-AES128-GCM-SHA256:" + "ECDHE-RSA-AES256-GCM-SHA384:" + "ECDHE-ECDSA-AES256-GCM-SHA384:" + "DHE-RSA-AES128-GCM-SHA256:" + "ECDHE-RSA-AES128-SHA256:" + "DHE-RSA-AES128-SHA256:" + "ECDHE-RSA-AES256-SHA384:" + "DHE-RSA-AES256-SHA384:" + "ECDHE-RSA-AES256-SHA256:" + "DHE-RSA-AES256-SHA256:" + "HIGH:" + "!aNULL:" + "!eNULL:" + "!EXPORT:" + "!DES:" + "!RC4:" + "!MD5:" + "!PSK:" + "!SRP:" + "!CAMELLIA"_s); + put(Identifier::fromString(vm, "defaultCoreCipherList"_s), + jsString(vm, cipherList)); + put(Identifier::fromString(vm, "defaultCipherList"_s), + jsString(vm, cipherList)); #ifdef TLS1_VERSION - put(Identifier::fromString(vm, "TLS1_VERSION"_s), jsNumber(TLS1_VERSION)); + put(Identifier::fromString(vm, "TLS1_VERSION"_s), jsNumber(TLS1_VERSION)); #endif #ifdef TLS1_1_VERSION - put(Identifier::fromString(vm, "TLS1_1_VERSION"_s), jsNumber(TLS1_1_VERSION)); + put(Identifier::fromString(vm, "TLS1_1_VERSION"_s), jsNumber(TLS1_1_VERSION)); #endif #ifdef TLS1_2_VERSION - put(Identifier::fromString(vm, "TLS1_2_VERSION"_s), jsNumber(TLS1_2_VERSION)); + put(Identifier::fromString(vm, "TLS1_2_VERSION"_s), jsNumber(TLS1_2_VERSION)); #endif #ifdef TLS1_3_VERSION - put(Identifier::fromString(vm, "TLS1_3_VERSION"_s), jsNumber(TLS1_3_VERSION)); -#endif - put(Identifier::fromString(vm, "POINT_CONVERSION_COMPRESSED"_s), jsNumber(POINT_CONVERSION_COMPRESSED)); - put(Identifier::fromString(vm, "POINT_CONVERSION_UNCOMPRESSED"_s), jsNumber(POINT_CONVERSION_UNCOMPRESSED)); - put(Identifier::fromString(vm, "POINT_CONVERSION_HYBRID"_s), jsNumber(POINT_CONVERSION_HYBRID)); - RETURN_NATIVE_MODULE(); + put(Identifier::fromString(vm, "TLS1_3_VERSION"_s), jsNumber(TLS1_3_VERSION)); +#endif + put(Identifier::fromString(vm, "POINT_CONVERSION_COMPRESSED"_s), + jsNumber(POINT_CONVERSION_COMPRESSED)); + put(Identifier::fromString(vm, "POINT_CONVERSION_UNCOMPRESSED"_s), + jsNumber(POINT_CONVERSION_UNCOMPRESSED)); + put(Identifier::fromString(vm, "POINT_CONVERSION_HYBRID"_s), + jsNumber(POINT_CONVERSION_HYBRID)); + + // RETURN_NATIVE_MODULE(); } } // namespace Zig diff --git a/src/bun.js/modules/NodeModuleModule.h b/src/bun.js/modules/NodeModuleModule.h index b3c34eb5e..804d1dd9d 100644 --- a/src/bun.js/modules/NodeModuleModule.h +++ b/src/bun.js/modules/NodeModuleModule.h @@ -1,8 +1,11 @@ +#pragma once + #include "CommonJSModuleRecord.h" #include "ImportMetaObject.h" #include "JavaScriptCore/JSBoundFunction.h" #include "JavaScriptCore/ObjectConstructor.h" #include "_NativeModule.h" +#include "isBuiltinModule.h" using namespace Zig; using namespace JSC; @@ -88,18 +91,6 @@ static constexpr ASCIILiteral builtinModuleNames[] = { "zlib"_s, }; -static bool isBuiltinModule(const String &namePossiblyWithNodePrefix) { - String name = namePossiblyWithNodePrefix; - if (name.startsWith("node:"_s)) - name = name.substringSharingImpl(5); - - for (auto &builtinModule : builtinModuleNames) { - if (name == builtinModule) - return true; - } - return false; -} - JSC_DEFINE_HOST_FUNCTION(jsFunctionNodeModuleModuleConstructor, (JSC::JSGlobalObject * globalObject, JSC::CallFrame *callFrame)) { @@ -158,7 +149,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionIsBuiltinModule, auto moduleStr = moduleName.toWTFString(globalObject); RETURN_IF_EXCEPTION(scope, JSValue::encode(jsBoolean(false))); - return JSValue::encode(jsBoolean(isBuiltinModule(moduleStr))); + return JSValue::encode(jsBoolean(Bun::isBuiltinModule(moduleStr))); } JSC_DEFINE_HOST_FUNCTION(jsFunctionWrap, (JSC::JSGlobalObject * globalObject, @@ -304,6 +295,39 @@ JSC_DEFINE_CUSTOM_SETTER(set_resolveFilename, return false; } +// These two setters are only used if you directly hit +// `Module.prototype.require` or `module.require`. When accessing the cjs +// require argument, this is a bound version of `require`, which calls into the +// overridden one. +// +// This require function also intentionally does not have .resolve on it, nor +// does it have any of the other properties. +// +// Note: allowing require to be overridable at all is only needed for Next.js to +// work (they do Module.prototype.require = ...) + +JSC_DEFINE_CUSTOM_GETTER(getterRequireFunction, + (JSC::JSGlobalObject * globalObject, + JSC::EncodedJSValue thisValue, JSC::PropertyName)) { + return JSValue::encode(globalObject->getDirect( + globalObject->vm(), WebCore::clientData(globalObject->vm()) + ->builtinNames() + .overridableRequirePrivateName())); +} + +JSC_DEFINE_CUSTOM_SETTER(setterRequireFunction, + (JSC::JSGlobalObject * globalObject, + JSC::EncodedJSValue thisValue, + JSC::EncodedJSValue value, + JSC::PropertyName propertyName)) { + globalObject->putDirect(globalObject->vm(), + WebCore::clientData(globalObject->vm()) + ->builtinNames() + .overridableRequirePrivateName(), + JSValue::decode(value), 0); + return true; +} + namespace Zig { DEFINE_NATIVE_MODULE(NodeModule) { @@ -330,13 +354,18 @@ DEFINE_NATIVE_MODULE(NodeModule) { exportNames.append(name); exportValues.append(value); }; - exportNames.reserveCapacity(15); - exportValues.ensureCapacity(15); + exportNames.reserveCapacity(16); + exportValues.ensureCapacity(16); exportNames.append(vm.propertyNames->defaultKeyword); exportValues.append(defaultObject); put(Identifier::fromString(vm, "Module"_s), defaultObject); + // Module._extensions === require.extensions + put(Identifier::fromString(vm, "_extensions"_s), + globalObject->requireFunctionUnbound()->get( + globalObject, Identifier::fromString(vm, "extensions"_s))); + defaultObject->putDirectCustomAccessor( vm, JSC::Identifier::fromString(vm, "_resolveFilename"_s), JSC::CustomGetterSetter::create(vm, get_resolveFilename, @@ -366,8 +395,15 @@ DEFINE_NATIVE_MODULE(NodeModule) { put(Identifier::fromString(vm, "globalPaths"_s), constructEmptyArray(globalObject, nullptr, 0)); - put(Identifier::fromString(vm, "prototype"_s), - constructEmptyObject(globalObject)); + auto prototype = + constructEmptyObject(globalObject, globalObject->objectPrototype(), 1); + prototype->putDirectCustomAccessor( + vm, JSC::Identifier::fromString(vm, "require"_s), + JSC::CustomGetterSetter::create(vm, getterRequireFunction, + setterRequireFunction), + 0); + + defaultObject->putDirect(vm, vm.propertyNames->prototype, prototype); JSC::JSArray *builtinModules = JSC::JSArray::create( vm, @@ -381,8 +417,6 @@ DEFINE_NATIVE_MODULE(NodeModule) { } put(JSC::Identifier::fromString(vm, "builtinModules"_s), builtinModules); - - RETURN_NATIVE_MODULE(); } } // namespace Zig diff --git a/src/bun.js/modules/NodeUtilTypesModule.h b/src/bun.js/modules/NodeUtilTypesModule.h index de9b147a4..e0b990603 100644 --- a/src/bun.js/modules/NodeUtilTypesModule.h +++ b/src/bun.js/modules/NodeUtilTypesModule.h @@ -203,7 +203,10 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionIsWeakSet, (JSC::JSGlobalObject * globalObjec JSC_DEFINE_HOST_FUNCTION(jsFunctionIsArrayBuffer, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe)) { GET_FIRST_CELL - return JSValue::encode(jsBoolean(jsDynamicCast<JSArrayBuffer*>(cell) != nullptr)); + auto* arrayBuffer = jsDynamicCast<JSArrayBuffer*>(cell); + if (!arrayBuffer) + return JSValue::encode(jsBoolean(false)); + return JSValue::encode(jsBoolean(!arrayBuffer->isShared())); } JSC_DEFINE_HOST_FUNCTION(jsFunctionIsDataView, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe)) { diff --git a/src/bun.js/modules/_NativeModule.h b/src/bun.js/modules/_NativeModule.h index b23906ad0..6d3d76176 100644 --- a/src/bun.js/modules/_NativeModule.h +++ b/src/bun.js/modules/_NativeModule.h @@ -40,18 +40,19 @@ // that what you passed to INIT_NATIVE_MODULE is indeed correct. #define RETURN_NATIVE_MODULE() \ ASSERT_WITH_MESSAGE(numberOfActualExportNames == passedNumberOfExportNames, \ - "NATIVE_MODULE_START() was given the incorrect value."); + "NATIVE_MODULE_START() was should be given %d", numberOfActualExportNames); -#define __NATIVE_MODULE_ASSERT_DECL \ +#define __NATIVE_MODULE_ASSERT_DECL(numberOfExportNames) \ int numberOfActualExportNames = 0; \ int passedNumberOfExportNames = numberOfExportNames; \ + #define __NATIVE_MODULE_ASSERT_INCR numberOfActualExportNames++; #else #define RETURN_NATIVE_MODULE() ; #define __NATIVE_MODULE_ASSERT_INCR ; -#define __NATIVE_MODULE_ASSERT_DECL ; +#define __NATIVE_MODULE_ASSERT_DECL(numberOfExportNames) ; #endif @@ -67,7 +68,7 @@ JSC::VM &vm = globalObject->vm(); \ JSC::JSObject *defaultObject = JSC::constructEmptyObject( \ globalObject, globalObject->objectPrototype(), numberOfExportNames); \ - __NATIVE_MODULE_ASSERT_DECL \ + __NATIVE_MODULE_ASSERT_DECL(numberOfExportNames); \ auto put = [&](JSC::Identifier name, JSC::JSValue value) { \ defaultObject->putDirect(vm, name, value); \ exportNames.append(name); \ diff --git a/src/bun.js/node/node_fs.zig b/src/bun.js/node/node_fs.zig index d9e3ed119..173f750a5 100644 --- a/src/bun.js/node/node_fs.zig +++ b/src/bun.js/node/node_fs.zig @@ -55,468 +55,151 @@ else // TODO: 0; +const SliceWithUnderlyingStringOrBuffer = JSC.Node.SliceWithUnderlyingStringOrBuffer; const ArrayBuffer = JSC.MarkedArrayBuffer; const Buffer = JSC.Buffer; const FileSystemFlags = JSC.Node.FileSystemFlags; +pub const Async = struct { + pub const access = NewAsyncFSTask(Return.Access, Arguments.Access, NodeFS.access); + pub const appendFile = NewAsyncFSTask(Return.AppendFile, Arguments.AppendFile, NodeFS.appendFile); + pub const chmod = NewAsyncFSTask(Return.Chmod, Arguments.Chmod, NodeFS.chmod); + pub const chown = NewAsyncFSTask(Return.Chown, Arguments.Chown, NodeFS.chown); + pub const close = NewAsyncFSTask(Return.Close, Arguments.Close, NodeFS.close); + pub const copyFile = NewAsyncFSTask(Return.CopyFile, Arguments.CopyFile, NodeFS.copyFile); + pub const exists = NewAsyncFSTask(Return.Exists, Arguments.Exists, NodeFS.exists); + pub const fchmod = NewAsyncFSTask(Return.Fchmod, Arguments.FChmod, NodeFS.fchmod); + pub const fchown = NewAsyncFSTask(Return.Fchown, Arguments.Fchown, NodeFS.fchown); + pub const fdatasync = NewAsyncFSTask(Return.Fdatasync, Arguments.FdataSync, NodeFS.fdatasync); + pub const fstat = NewAsyncFSTask(Return.Fstat, Arguments.Fstat, NodeFS.fstat); + pub const fsync = NewAsyncFSTask(Return.Fsync, Arguments.Fsync, NodeFS.fsync); + pub const ftruncate = NewAsyncFSTask(Return.Ftruncate, Arguments.FTruncate, NodeFS.ftruncate); + pub const futimes = NewAsyncFSTask(Return.Futimes, Arguments.Futimes, NodeFS.futimes); + pub const lchmod = NewAsyncFSTask(Return.Lchmod, Arguments.LCHmod, NodeFS.lchmod); + pub const lchown = NewAsyncFSTask(Return.Lchown, Arguments.LChown, NodeFS.lchown); + pub const link = NewAsyncFSTask(Return.Link, Arguments.Link, NodeFS.link); + pub const lstat = NewAsyncFSTask(Return.Stat, Arguments.Stat, NodeFS.lstat); + pub const lutimes = NewAsyncFSTask(Return.Lutimes, Arguments.Lutimes, NodeFS.lutimes); + pub const mkdir = NewAsyncFSTask(Return.Mkdir, Arguments.Mkdir, NodeFS.mkdir); + pub const mkdtemp = NewAsyncFSTask(Return.Mkdtemp, Arguments.MkdirTemp, NodeFS.mkdtemp); + pub const open = NewAsyncFSTask(Return.Open, Arguments.Open, NodeFS.open); + pub const read = NewAsyncFSTask(Return.Read, Arguments.Read, NodeFS.read); + pub const readdir = NewAsyncFSTask(Return.Readdir, Arguments.Readdir, NodeFS.readdir); + pub const readFile = NewAsyncFSTask(Return.ReadFile, Arguments.ReadFile, NodeFS.readFile); + pub const readlink = NewAsyncFSTask(Return.Readlink, Arguments.Readlink, NodeFS.readlink); + pub const readv = NewAsyncFSTask(Return.Readv, Arguments.Readv, NodeFS.readv); + pub const realpath = NewAsyncFSTask(Return.Realpath, Arguments.Realpath, NodeFS.realpath); + pub const rename = NewAsyncFSTask(Return.Rename, Arguments.Rename, NodeFS.rename); + pub const rm = NewAsyncFSTask(Return.Rm, Arguments.Rm, NodeFS.rm); + pub const rmdir = NewAsyncFSTask(Return.Rmdir, Arguments.RmDir, NodeFS.rmdir); + pub const stat = NewAsyncFSTask(Return.Stat, Arguments.Stat, NodeFS.stat); + pub const symlink = NewAsyncFSTask(Return.Symlink, Arguments.Symlink, NodeFS.symlink); + pub const truncate = NewAsyncFSTask(Return.Truncate, Arguments.Truncate, NodeFS.truncate); + pub const unlink = NewAsyncFSTask(Return.Unlink, Arguments.Unlink, NodeFS.unlink); + pub const utimes = NewAsyncFSTask(Return.Utimes, Arguments.Utimes, NodeFS.utimes); + pub const write = NewAsyncFSTask(Return.Write, Arguments.Write, NodeFS.write); + pub const writeFile = NewAsyncFSTask(Return.WriteFile, Arguments.WriteFile, NodeFS.writeFile); + pub const writev = NewAsyncFSTask(Return.Writev, Arguments.Writev, NodeFS.writev); + + pub const cp = AsyncCpTask; + + fn NewAsyncFSTask(comptime ReturnType: type, comptime ArgumentType: type, comptime Function: anytype) type { + return struct { + promise: JSC.JSPromise.Strong, + args: ArgumentType, + globalObject: *JSC.JSGlobalObject, + task: JSC.WorkPoolTask = .{ .callback = &workPoolCallback }, + result: JSC.Maybe(ReturnType), + ref: JSC.PollRef = .{}, + tracker: JSC.AsyncTaskTracker, + + pub const Task = @This(); + + pub fn create( + globalObject: *JSC.JSGlobalObject, + args: ArgumentType, + vm: *JSC.VirtualMachine, + ) JSC.JSValue { + var task = bun.default_allocator.create(Task) catch @panic("out of memory"); + task.* = Task{ + .promise = JSC.JSPromise.Strong.init(globalObject), + .args = args, + .result = undefined, + .globalObject = globalObject, + .tracker = JSC.AsyncTaskTracker.init(vm), + }; + task.ref.ref(vm); + task.args.toThreadSafe(); + task.tracker.didSchedule(globalObject); + JSC.WorkPool.schedule(&task.task); -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 = .{}, - arena: bun.ArenaAllocator, - tracker: JSC.AsyncTaskTracker, - - pub fn create(globalObject: *JSC.JSGlobalObject, readdir_args: Arguments.Readdir, vm: *JSC.VirtualMachine, arena: bun.ArenaAllocator) 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, - .arena = arena, - .tracker = JSC.AsyncTaskTracker.init(vm), - }; - task.ref.ref(vm); - task.args.path.toThreadSafe(); - task.tracker.didSchedule(globalObject); - 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); - - if (this.result == .err) { - this.result.err.path = bun.default_allocator.dupe(u8, this.result.err.path) catch ""; - } - - 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(); - - const tracker = this.tracker; - this.deinit(); - - tracker.willDispatch(globalObject); - defer tracker.didDispatch(globalObject); - 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.deinitAndUnprotect(); - this.promise.strong.deinit(); - this.arena.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, - arena: bun.ArenaAllocator, - tracker: JSC.AsyncTaskTracker, - - pub fn create( - globalObject: *JSC.JSGlobalObject, - readdir_args: Arguments.Stat, - vm: *JSC.VirtualMachine, - is_lstat: bool, - arena: bun.ArenaAllocator, - ) 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, - .tracker = JSC.AsyncTaskTracker.init(vm), - .arena = arena, - }; - task.ref.ref(vm); - task.args.path.toThreadSafe(); - task.tracker.didSchedule(globalObject); - - JSC.WorkPool.schedule(&task.task); - - return task.promise.value(); - } + return task.promise.value(); + } - fn workPoolCallback(task: *JSC.WorkPoolTask) void { - var this: *AsyncStatTask = @fieldParentPtr(AsyncStatTask, "task", task); + fn workPoolCallback(task: *JSC.WorkPoolTask) void { + var this: *Task = @fieldParentPtr(Task, "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); + var node_fs = NodeFS{}; + this.result = Function(&node_fs, 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; + if (this.result == .err) { + this.result.err.path = bun.default_allocator.dupe(u8, this.result.err.path) catch ""; + std.mem.doNotOptimizeAway(&node_fs); } - break :brk out; - }, - }; - var promise_value = this.promise.value(); - var promise = this.promise.get(); - promise_value.ensureStillAlive(); - - const tracker = this.tracker; - tracker.willDispatch(globalObject); - defer tracker.didDispatch(globalObject); - - 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.deinitAndUnprotect(); - this.promise.strong.deinit(); - this.arena.deinit(); - bun.default_allocator.destroy(this); - } -}; - -pub const AsyncRealpathTask = struct { - promise: JSC.JSPromise.Strong, - args: Arguments.Realpath, - globalObject: *JSC.JSGlobalObject, - task: JSC.WorkPoolTask = .{ .callback = &workPoolCallback }, - result: JSC.Maybe(Return.Realpath), - ref: JSC.PollRef = .{}, - arena: bun.ArenaAllocator, - tracker: JSC.AsyncTaskTracker, - - pub fn create( - globalObject: *JSC.JSGlobalObject, - args: Arguments.Realpath, - vm: *JSC.VirtualMachine, - arena: bun.ArenaAllocator, - ) JSC.JSValue { - var task = bun.default_allocator.create(AsyncRealpathTask) catch @panic("out of memory"); - task.* = AsyncRealpathTask{ - .promise = JSC.JSPromise.Strong.init(globalObject), - .args = args, - .result = undefined, - .globalObject = globalObject, - .arena = arena, - .tracker = JSC.AsyncTaskTracker.init(vm), - }; - task.ref.ref(vm); - task.args.path.toThreadSafe(); - task.tracker.didSchedule(globalObject); - JSC.WorkPool.schedule(&task.task); - - return task.promise.value(); - } - - fn workPoolCallback(task: *JSC.WorkPoolTask) void { - var this: *AsyncRealpathTask = @fieldParentPtr(AsyncRealpathTask, "task", task); - - var node_fs = NodeFS{}; - this.result = node_fs.realpath(this.args, .promise); - - if (this.result == .err) { - this.result.err.path = bun.default_allocator.dupe(u8, this.result.err.path) catch ""; - } + this.globalObject.bunVMConcurrently().eventLoop().enqueueTaskConcurrent(JSC.ConcurrentTask.create(JSC.Task.init(this))); + } - this.globalObject.bunVMConcurrently().eventLoop().enqueueTaskConcurrent(JSC.ConcurrentTask.fromCallback(this, runFromJSThread)); - } + pub fn runFromJSThread(this: *Task) void { + var globalObject = this.globalObject; + var success = @as(JSC.Maybe(ReturnType).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(ReturnType, res, globalObject, &exceptionref)); + const exception = JSC.JSValue.c(exceptionref); + if (exception != .zero) { + success = false; + break :brk exception; + } - fn runFromJSThread(this: *AsyncRealpathTask) void { - var globalObject = this.globalObject; - var success = @as(JSC.Maybe(Return.Realpath).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.Realpath, 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(); + + const tracker = this.tracker; + tracker.willDispatch(globalObject); + defer tracker.didDispatch(globalObject); + + this.deinit(); + switch (success) { + false => { + promise.reject(globalObject, result); + }, + true => { + promise.resolve(globalObject, result); + }, } + } - break :brk out; - }, - }; - var promise_value = this.promise.value(); - var promise = this.promise.get(); - promise_value.ensureStillAlive(); - - const tracker = this.tracker; - tracker.willDispatch(globalObject); - defer tracker.didDispatch(globalObject); - - this.deinit(); - switch (success) { - false => { - promise.reject(globalObject, result); - }, - true => { - promise.resolve(globalObject, result); - }, - } - } - - pub fn deinit(this: *AsyncRealpathTask) void { - if (this.result == .err) { - bun.default_allocator.free(this.result.err.path); - } - - this.ref.unref(this.globalObject.bunVM()); - this.args.deinitAndUnprotect(); - this.promise.strong.deinit(); - this.arena.deinit(); - bun.default_allocator.destroy(this); - } -}; - -pub const AsyncReadFileTask = struct { - promise: JSC.JSPromise.Strong, - args: Arguments.ReadFile, - globalObject: *JSC.JSGlobalObject, - task: JSC.WorkPoolTask = .{ .callback = &workPoolCallback }, - result: JSC.Maybe(Return.ReadFile), - ref: JSC.PollRef = .{}, - arena: bun.ArenaAllocator, - tracker: JSC.AsyncTaskTracker, - - pub fn create( - globalObject: *JSC.JSGlobalObject, - args: Arguments.ReadFile, - vm: *JSC.VirtualMachine, - arena: bun.ArenaAllocator, - ) JSC.JSValue { - var task = bun.default_allocator.create(AsyncReadFileTask) catch @panic("out of memory"); - task.* = AsyncReadFileTask{ - .promise = JSC.JSPromise.Strong.init(globalObject), - .args = args, - .result = undefined, - .globalObject = globalObject, - .arena = arena, - .tracker = JSC.AsyncTaskTracker.init(vm), - }; - task.ref.ref(vm); - task.args.path.toThreadSafe(); - task.tracker.didSchedule(globalObject); - JSC.WorkPool.schedule(&task.task); - - return task.promise.value(); - } - - fn workPoolCallback(task: *JSC.WorkPoolTask) void { - var this: *AsyncReadFileTask = @fieldParentPtr(AsyncReadFileTask, "task", task); - - var node_fs = NodeFS{}; - this.result = node_fs.readFile(this.args, .promise); - - if (this.result == .err) { - this.result.err.path = bun.default_allocator.dupe(u8, this.result.err.path) catch ""; - } - - this.globalObject.bunVMConcurrently().eventLoop().enqueueTaskConcurrent(JSC.ConcurrentTask.fromCallback(this, runFromJSThread)); - } - - fn runFromJSThread(this: *AsyncReadFileTask) void { - var globalObject = this.globalObject; - - var success = @as(JSC.Maybe(Return.ReadFile).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.ReadFile, res, globalObject, &exceptionref)); - const exception = JSC.JSValue.c(exceptionref); - if (exception != .zero) { - success = false; - break :brk exception; + pub fn deinit(this: *Task) void { + if (this.result == .err) { + bun.default_allocator.free(this.result.err.path); } - break :brk out; - }, - }; - var promise_value = this.promise.value(); - var promise = this.promise.get(); - promise_value.ensureStillAlive(); - - const tracker = this.tracker; - tracker.willDispatch(globalObject); - defer tracker.didDispatch(globalObject); - - this.deinit(); - switch (success) { - false => { - promise.reject(globalObject, result); - }, - true => { - promise.resolve(globalObject, result); - }, - } - } - - pub fn deinit(this: *AsyncReadFileTask) void { - this.ref.unref(this.globalObject.bunVM()); - this.args.deinitAndUnprotect(); - this.promise.strong.deinit(); - this.arena.deinit(); - bun.default_allocator.destroy(this); - } -}; - -pub const AsyncCopyFileTask = struct { - promise: JSC.JSPromise.Strong, - args: Arguments.CopyFile, - globalObject: *JSC.JSGlobalObject, - task: JSC.WorkPoolTask = .{ .callback = &workPoolCallback }, - result: JSC.Maybe(Return.CopyFile), - ref: JSC.PollRef = .{}, - arena: bun.ArenaAllocator, - tracker: JSC.AsyncTaskTracker, - - pub fn create( - globalObject: *JSC.JSGlobalObject, - copyfile_args: Arguments.CopyFile, - vm: *JSC.VirtualMachine, - arena: bun.ArenaAllocator, - ) JSC.JSValue { - var task = bun.default_allocator.create(AsyncCopyFileTask) catch @panic("out of memory"); - task.* = AsyncCopyFileTask{ - .promise = JSC.JSPromise.Strong.init(globalObject), - .args = copyfile_args, - .result = undefined, - .globalObject = globalObject, - .tracker = JSC.AsyncTaskTracker.init(vm), - .arena = arena, - }; - task.ref.ref(vm); - task.args.src.toThreadSafe(); - task.args.dest.toThreadSafe(); - task.tracker.didSchedule(globalObject); - - JSC.WorkPool.schedule(&task.task); - - return task.promise.value(); - } - - fn workPoolCallback(task: *JSC.WorkPoolTask) void { - var this: *AsyncCopyFileTask = @fieldParentPtr(AsyncCopyFileTask, "task", task); - - var node_fs = NodeFS{}; - this.result = node_fs.copyFile(this.args, .promise); - - if (this.result == .err) { - this.result.err.path = bun.default_allocator.dupe(u8, this.result.err.path) catch ""; - } - - this.globalObject.bunVMConcurrently().eventLoop().enqueueTaskConcurrent(JSC.ConcurrentTask.fromCallback(this, runFromJSThread)); - } - - fn runFromJSThread(this: *AsyncCopyFileTask) void { - var globalObject = this.globalObject; - var success = @as(JSC.Maybe(Return.CopyFile).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.CopyFile, res, globalObject, &exceptionref)); - const exception = JSC.JSValue.c(exceptionref); - if (exception != .zero) { - success = false; - break :brk exception; + this.ref.unref(this.globalObject.bunVM()); + if (@hasDecl(ArgumentType, "deinitAndUnprotect")) { + this.args.deinitAndUnprotect(); + } else { + this.args.deinit(); } - - break :brk out; - }, + this.promise.strong.deinit(); + bun.default_allocator.destroy(this); + } }; - var promise_value = this.promise.value(); - var promise = this.promise.get(); - promise_value.ensureStillAlive(); - - const tracker = this.tracker; - tracker.willDispatch(globalObject); - defer tracker.didDispatch(globalObject); - - this.deinit(); - switch (success) { - false => { - promise.reject(globalObject, result); - }, - true => { - promise.resolve(globalObject, result); - }, - } - } - - pub fn deinit(this: *AsyncCopyFileTask) void { - this.ref.unref(this.globalObject.bunVM()); - this.args.deinit(); - this.promise.strong.deinit(); - this.arena.deinit(); - bun.default_allocator.destroy(this); } }; @@ -710,6 +393,16 @@ pub const Arguments = struct { this.new_path.deinit(); } + pub fn deinitAndUnprotect(this: @This()) void { + this.old_path.deinitAndUnprotect(); + this.new_path.deinitAndUnprotect(); + } + + pub fn toThreadSafe(this: *@This()) void { + this.old_path.toThreadSafe(); + this.new_path.toThreadSafe(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Rename { const old_path = PathLike.fromJS(ctx, arguments, exception) orelse { if (exception.* == null) { @@ -748,8 +441,16 @@ pub const Arguments = struct { this.path.deinit(); } + pub fn deinitAndUnprotect(this: *@This()) void { + this.path.deinitAndUnprotect(); + } + + pub fn toThreadSafe(this: *@This()) void { + this.path.toThreadSafe(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Truncate { - const path = PathOrFileDescriptor.fromJS(ctx, arguments, arguments.arena.allocator(), exception) orelse { + const path = PathOrFileDescriptor.fromJS(ctx, arguments, bun.default_allocator, exception) orelse { if (exception.* == null) { JSC.throwInvalidArguments( "path must be a string or TypedArray", @@ -783,6 +484,21 @@ pub const Arguments = struct { pub fn deinit(_: *const @This()) void {} + pub fn deinitAndUnprotect(this: *const @This()) void { + this.buffers.value.unprotect(); + this.buffers.buffers.deinit(); + } + + pub fn toThreadSafe(this: *@This()) void { + this.buffers.value.protect(); + + var clone = bun.default_allocator.dupe(std.os.iovec, this.buffers.buffers.items) catch @panic("out of memory"); + this.buffers.buffers.deinit(); + this.buffers.buffers.items = clone; + this.buffers.buffers.capacity = clone.len; + this.buffers.buffers.allocator = bun.default_allocator; + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Writev { const fd_value = arguments.nextEat() orelse { if (exception.* == null) { @@ -855,7 +571,23 @@ pub const Arguments = struct { buffers: JSC.Node.VectorArrayBuffer, position: ?u52 = 0, - pub fn deinit(_: *const @This()) void {} + pub fn deinit(this: *const @This()) void { + _ = this; + } + + pub fn deinitAndUnprotect(this: *const @This()) void { + this.buffers.value.unprotect(); + this.buffers.buffers.deinit(); + } + + pub fn toThreadSafe(this: *@This()) void { + this.buffers.value.protect(); + var clone = bun.default_allocator.dupe(std.os.iovec, this.buffers.buffers.items) catch @panic("out of memory"); + this.buffers.buffers.deinit(); + this.buffers.buffers.items = clone; + this.buffers.buffers.capacity = clone.len; + this.buffers.buffers.allocator = bun.default_allocator; + } pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Readv { const fd_value = arguments.nextEat() orelse { @@ -932,6 +664,14 @@ pub const Arguments = struct { _ = this; } + pub fn deinitAndUnprotect(this: *@This()) void { + _ = this; + } + + pub fn toThreadSafe(this: *const @This()) void { + _ = this; + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?FTruncate { const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { if (exception.* == null) { @@ -982,6 +722,14 @@ pub const Arguments = struct { this.path.deinit(); } + pub fn deinitAndUnprotect(this: *@This()) void { + this.path.deinitAndUnprotect(); + } + + pub fn toThreadSafe(this: *@This()) void { + this.path.toThreadSafe(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Chown { const path = PathLike.fromJS(ctx, arguments, exception) orelse { if (exception.* == null) { @@ -1040,6 +788,8 @@ pub const Arguments = struct { pub fn deinit(_: @This()) void {} + pub fn toThreadSafe(_: *const @This()) void {} + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Fchown { const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { if (exception.* == null) { @@ -1114,6 +864,14 @@ pub const Arguments = struct { this.path.deinit(); } + pub fn deinitAndUnprotect(this: *@This()) void { + this.path.deinitAndUnprotect(); + } + + pub fn toThreadSafe(this: *@This()) void { + this.path.toThreadSafe(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Lutimes { const path = PathLike.fromJS(ctx, arguments, exception) orelse { if (exception.* == null) { @@ -1189,6 +947,14 @@ pub const Arguments = struct { this.path.deinit(); } + pub fn toThreadSafe(this: *@This()) void { + this.path.toThreadSafe(); + } + + pub fn deinitAndUnprotect(this: *@This()) void { + this.path.deinitAndUnprotect(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Chmod { const path = PathLike.fromJS(ctx, arguments, exception) orelse { if (exception.* == null) { @@ -1234,6 +1000,10 @@ pub const Arguments = struct { fd: FileDescriptor, mode: Mode = 0x777, + pub fn deinit(_: *const @This()) void {} + + pub fn toThreadSafe(_: *const @This()) void {} + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?FChmod { const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { if (exception.* == null) { @@ -1303,8 +1073,12 @@ pub const Arguments = struct { this.path.deinitAndUnprotect(); } + pub fn toThreadSafe(this: *Stat) void { + this.path.toThreadSafe(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Stat { - const path = PathLike.fromJSWithAllocator(ctx, arguments, bun.default_allocator, exception) orelse { + const path = PathLike.fromJS(ctx, arguments, exception) orelse { if (exception.* == null) { JSC.throwInvalidArguments( "path must be a string or TypedArray", @@ -1356,6 +1130,8 @@ pub const Arguments = struct { pub fn deinit(_: @This()) void {} + pub fn toThreadSafe(_: *@This()) void {} + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Fstat { const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { if (exception.* == null) { @@ -1412,6 +1188,16 @@ pub const Arguments = struct { this.new_path.deinit(); } + pub fn deinitAndUnprotect(this: *Link) void { + this.old_path.deinitAndUnprotect(); + this.new_path.deinitAndUnprotect(); + } + + pub fn toThreadSafe(this: *Link) void { + this.old_path.toThreadSafe(); + this.new_path.toThreadSafe(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Link { const old_path = PathLike.fromJS(ctx, arguments, exception) orelse { if (exception.* == null) { @@ -1454,6 +1240,16 @@ pub const Arguments = struct { this.new_path.deinit(); } + pub fn deinitAndUnprotect(this: Symlink) void { + this.old_path.deinitAndUnprotect(); + this.new_path.deinitAndUnprotect(); + } + + pub fn toThreadSafe(this: *@This()) void { + this.old_path.toThreadSafe(); + this.new_path.toThreadSafe(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Symlink { const old_path = PathLike.fromJS(ctx, arguments, exception) orelse { if (exception.* == null) { @@ -1512,6 +1308,14 @@ pub const Arguments = struct { this.path.deinit(); } + pub fn deinitAndUnprotect(this: *Readlink) void { + this.path.deinitAndUnprotect(); + } + + pub fn toThreadSafe(this: *Readlink) void { + this.path.toThreadSafe(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Readlink { const path = PathLike.fromJS(ctx, arguments, exception) orelse { if (exception.* == null) { @@ -1560,6 +1364,10 @@ pub const Arguments = struct { this.path.deinitAndUnprotect(); } + pub fn toThreadSafe(this: *Realpath) void { + this.path.toThreadSafe(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Realpath { const path = PathLike.fromJS(ctx, arguments, exception) orelse { if (exception.* == null) { @@ -1599,6 +1407,18 @@ pub const Arguments = struct { pub const Unlink = struct { path: PathLike, + pub fn deinit(this: Unlink) void { + this.path.deinit(); + } + + pub fn deinitAndUnprotect(this: *Unlink) void { + this.path.deinitAndUnprotect(); + } + + pub fn toThreadSafe(this: *Unlink) void { + this.path.toThreadSafe(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Unlink { const path = PathLike.fromJS(ctx, arguments, exception) orelse { if (exception.* == null) { @@ -1620,13 +1440,7 @@ pub const Arguments = struct { } }; - pub const Rm = struct { - path: PathLike, - force: bool = false, - max_retries: u32 = 0, - recursive: bool = false, - retry_delay: c_uint = 100, - }; + pub const Rm = RmDir; pub const RmDir = struct { path: PathLike, @@ -1637,6 +1451,14 @@ pub const Arguments = struct { recursive: bool = false, retry_delay: c_uint = 100, + pub fn deinitAndUnprotect(this: *RmDir) void { + this.path.deinitAndUnprotect(); + } + + pub fn toThreadSafe(this: *RmDir) void { + this.path.toThreadSafe(); + } + pub fn deinit(this: RmDir) void { this.path.deinit(); } @@ -1701,6 +1523,14 @@ pub const Arguments = struct { this.path.deinit(); } + pub fn deinitAndUnprotect(this: *Mkdir) void { + this.path.deinitAndUnprotect(); + } + + pub fn toThreadSafe(this: *Mkdir) void { + this.path.toThreadSafe(); + } + pub fn fromJS(ctx: *JSC.JSGlobalObject, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Mkdir { const path = PathLike.fromJS(ctx, arguments, exception) orelse { if (exception.* == null) { @@ -1752,10 +1582,18 @@ pub const Arguments = struct { this.prefix.deinit(); } + pub fn deinitAndUnprotect(this: *MkdirTemp) void { + this.prefix.deinit(); + } + + pub fn toThreadSafe(this: *MkdirTemp) void { + this.prefix.toThreadSafe(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?MkdirTemp { const prefix_value = arguments.next() orelse return MkdirTemp{}; - var prefix = JSC.Node.SliceOrBuffer.fromJS(ctx, arguments.arena.allocator(), prefix_value) orelse { + var prefix = JSC.Node.SliceOrBuffer.fromJS(ctx, bun.default_allocator, prefix_value) orelse { if (exception.* == null) { JSC.throwInvalidArguments( "prefix must be a string or TypedArray", @@ -1810,8 +1648,12 @@ pub const Arguments = struct { this.path.deinitAndUnprotect(); } + pub fn toThreadSafe(this: *Readdir) void { + this.path.toThreadSafe(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Readdir { - const path = PathLike.fromJSWithAllocator(ctx, arguments, bun.default_allocator, exception) orelse { + const path = PathLike.fromJS(ctx, arguments, exception) orelse { if (exception.* == null) { JSC.throwInvalidArguments( "path must be a string or TypedArray", @@ -1864,6 +1706,7 @@ pub const Arguments = struct { fd: FileDescriptor, pub fn deinit(_: Close) void {} + pub fn toThreadSafe(_: Close) void {} pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Close { const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { @@ -1905,6 +1748,14 @@ pub const Arguments = struct { this.path.deinit(); } + pub fn deinitAndUnprotect(this: Open) void { + this.path.deinitAndUnprotect(); + } + + pub fn toThreadSafe(this: *Open) void { + this.path.toThreadSafe(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Open { const path = PathLike.fromJS(ctx, arguments, exception) orelse { if (exception.* == null) { @@ -1971,6 +1822,10 @@ pub const Arguments = struct { pub fn deinit(_: Futimes) void {} + pub fn toThreadSafe(self: *const @This()) void { + _ = self; + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Futimes { const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { if (exception.* == null) { @@ -2052,42 +1907,6 @@ pub const Arguments = struct { } }; - pub const FSync = struct { - fd: FileDescriptor, - - pub fn deinit(_: FSync) void {} - - pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?FSync { - const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "File descriptor is required", - .{}, - ctx, - exception, - ); - } - return null; - }, exception) orelse { - if (exception.* == null) { - JSC.throwInvalidArguments( - "fd must be a number", - .{}, - ctx, - exception, - ); - } - return null; - }; - - if (exception.* != null) return null; - - return FSync{ - .fd = fd, - }; - } - }; - /// Write `buffer` to the file specified by `fd`. If `buffer` is a normal object, it /// must have an own `toString` function property. /// @@ -2114,14 +1933,24 @@ pub const Arguments = struct { /// pub const Write = struct { fd: FileDescriptor, - buffer: StringOrBuffer, + buffer: JSC.Node.SliceWithUnderlyingStringOrBuffer, // buffer_val: JSC.JSValue = JSC.JSValue.zero, offset: u64 = 0, length: u64 = std.math.maxInt(u64), position: ?ReadPosition = null, encoding: Encoding = Encoding.buffer, - pub fn deinit(_: Write) void {} + pub fn deinit(this: *const @This()) void { + this.buffer.deinit(); + } + + pub fn deinitAndUnprotect(this: *@This()) void { + this.buffer.deinitAndUnprotect(); + } + + pub fn toThreadSafe(self: *@This()) void { + self.buffer.toThreadSafe(); + } pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Write { const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { @@ -2150,7 +1979,7 @@ pub const Arguments = struct { if (exception.* != null) return null; - const buffer = StringOrBuffer.fromJS(ctx.ptr(), arguments.arena.allocator(), arguments.next() orelse { + const buffer = SliceWithUnderlyingStringOrBuffer.fromJS(ctx.ptr(), bun.default_allocator, arguments.next() orelse { if (exception.* == null) { JSC.throwInvalidArguments( "data is required", @@ -2177,7 +2006,7 @@ pub const Arguments = struct { .fd = fd, .buffer = buffer, .encoding = switch (buffer) { - .string => Encoding.utf8, + .SliceWithUnderlyingString => Encoding.utf8, .buffer => Encoding.buffer, }, }; @@ -2190,7 +2019,7 @@ pub const Arguments = struct { var current = current_; switch (buffer) { // fs.write(fd, string[, position[, encoding]], callback) - .string => { + .SliceWithUnderlyingString => { if (current.isNumber()) { args.position = current.to(i52); arguments.eat(); @@ -2239,6 +2068,14 @@ pub const Arguments = struct { pub fn deinit(_: Read) void {} + pub fn toThreadSafe(this: Read) void { + this.buffer.buffer.value.protect(); + } + + pub fn deinitAndUnprotect(this: *Read) void { + this.buffer.buffer.value.unprotect(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Read { const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { if (exception.* == null) { @@ -2377,6 +2214,10 @@ pub const Arguments = struct { self.path.deinitAndUnprotect(); } + pub fn toThreadSafe(self: *ReadFile) void { + self.path.toThreadSafe(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?ReadFile { const path = PathOrFileDescriptor.fromJS(ctx, arguments, bun.default_allocator, exception) orelse { if (exception.* == null) { @@ -2463,8 +2304,16 @@ pub const Arguments = struct { self.file.deinit(); } + pub fn toThreadSafe(self: *WriteFile) void { + self.file.toThreadSafe(); + } + + pub fn deinitAndUnprotect(self: *WriteFile) void { + self.file.deinitAndUnprotect(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?WriteFile { - const file = PathOrFileDescriptor.fromJS(ctx, arguments, arguments.arena.allocator(), exception) orelse { + const file = PathOrFileDescriptor.fromJS(ctx, arguments, bun.default_allocator, exception) orelse { if (exception.* == null) { JSC.throwInvalidArguments( "path must be a string or a file descriptor", @@ -2478,7 +2327,7 @@ pub const Arguments = struct { if (exception.* != null) return null; - const data = StringOrBuffer.fromJS(ctx.ptr(), arguments.arena.allocator(), arguments.next() orelse { + const data = StringOrBuffer.fromJS(ctx.ptr(), bun.default_allocator, arguments.next() orelse { if (exception.* == null) { JSC.throwInvalidArguments( "data is required", @@ -2673,6 +2522,18 @@ pub const Arguments = struct { } } + pub fn toThreadSafe(this: *Exists) void { + if (this.path) |*path| { + path.toThreadSafe(); + } + } + + pub fn deinitAndUnprotect(this: *Exists) void { + if (this.path) |*path| { + path.deinitAndUnprotect(); + } + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Exists { return Exists{ .path = PathLike.fromJS(ctx, arguments, exception), @@ -2688,6 +2549,14 @@ pub const Arguments = struct { this.path.deinit(); } + pub fn toThreadSafe(this: *Access) void { + this.path.toThreadSafe(); + } + + pub fn deinitAndUnprotect(this: *Access) void { + this.path.deinitAndUnprotect(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Access { const path = PathLike.fromJS(ctx, arguments, exception) orelse { if (exception.* == null) { @@ -3002,6 +2871,9 @@ pub const Arguments = struct { fd: FileDescriptor, pub fn deinit(_: FdataSync) void {} + pub fn toThreadSafe(self: *const @This()) void { + _ = self; + } pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?FdataSync { const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { @@ -3039,13 +2911,23 @@ pub const Arguments = struct { dest: PathLike, mode: Constants.Copyfile, - fn deinit(this: CopyFile) void { + pub fn deinit(this: CopyFile) void { this.src.deinit(); this.dest.deinit(); } + pub fn toThreadSafe(this: *CopyFile) void { + this.src.toThreadSafe(); + this.dest.toThreadSafe(); + } + + pub fn deinitAndUnprotect(this: *CopyFile) void { + this.src.deinitAndUnprotect(); + this.dest.deinitAndUnprotect(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?CopyFile { - const src = PathLike.fromJSWithAllocator(ctx, arguments, bun.default_allocator, exception) orelse { + const src = PathLike.fromJS(ctx, arguments, exception) orelse { if (exception.* == null) { JSC.throwInvalidArguments( "src must be a string or buffer", @@ -3059,7 +2941,7 @@ pub const Arguments = struct { if (exception.* != null) return null; - const dest = PathLike.fromJSWithAllocator(ctx, arguments, bun.default_allocator, exception) orelse { + const dest = PathLike.fromJS(ctx, arguments, exception) orelse { src.deinit(); if (exception.* == null) { @@ -3109,7 +2991,7 @@ pub const Arguments = struct { } pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Cp { - const src = PathLike.fromJSWithAllocator(ctx, arguments, bun.default_allocator, exception) orelse { + const src = PathLike.fromJS(ctx, arguments, exception) orelse { if (exception.* == null) { JSC.throwInvalidArguments( "src must be a string or buffer", @@ -3123,7 +3005,7 @@ pub const Arguments = struct { if (exception.* != null) return null; - const dest = PathLike.fromJSWithAllocator(ctx, arguments, bun.default_allocator, exception) orelse { + const dest = PathLike.fromJS(ctx, arguments, exception) orelse { defer src.deinit(); if (exception.* == null) { JSC.throwInvalidArguments( @@ -3196,6 +3078,9 @@ pub const Arguments = struct { pub const Fsync = struct { fd: FileDescriptor, + pub fn deinit(_: Fsync) void {} + pub fn toThreadSafe(_: *const @This()) void {} + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Fsync { const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse { if (exception.* == null) { @@ -3411,69 +3296,49 @@ pub const NodeFS = struct { } pub fn appendFile(this: *NodeFS, args: Arguments.AppendFile, comptime flavor: Flavor) Maybe(Return.AppendFile) { + _ = flavor; var data = args.data.slice(); switch (args.file) { .fd => |fd| { - switch (comptime flavor) { - .sync => { - while (data.len > 0) { - const written = switch (Syscall.write(fd, data)) { - .result => |result| result, - .err => |err| return .{ .err = err }, - }; - data = data[written..]; - } - - return Maybe(Return.AppendFile).success; - }, - else => { - @compileError("Not implemented yet"); - }, + while (data.len > 0) { + const written = switch (Syscall.write(fd, data)) { + .result => |result| result, + .err => |err| return .{ .err = err }, + }; + data = data[written..]; } + + return Maybe(Return.AppendFile).success; }, .path => |path_| { const path = path_.sliceZ(&this.sync_error_buf); - switch (comptime flavor) { - .sync => { - const fd = switch (Syscall.open(path, @intFromEnum(FileSystemFlags.a), 0o000666)) { - .result => |result| result, - .err => |err| return .{ .err = err }, - }; - defer { - _ = Syscall.close(fd); - } + const fd = switch (Syscall.open(path, @intFromEnum(FileSystemFlags.a), 0o000666)) { + .result => |result| result, + .err => |err| return .{ .err = err }, + }; - while (data.len > 0) { - const written = switch (Syscall.write(fd, data)) { - .result => |result| result, - .err => |err| return .{ .err = err }, - }; - data = data[written..]; - } + defer { + _ = Syscall.close(fd); + } - return Maybe(Return.AppendFile).success; - }, - else => { - @compileError("Not implemented yet"); - }, + while (data.len > 0) { + const written = switch (Syscall.write(fd, data)) { + .result => |result| result, + .err => |err| return .{ .err = err }, + }; + data = data[written..]; } + + return Maybe(Return.AppendFile).success; }, } - - return Maybe(Return.AppendFile).todo; } pub fn close(_: *NodeFS, args: Arguments.Close, comptime flavor: Flavor) Maybe(Return.Close) { - switch (comptime flavor) { - .sync => { - return if (Syscall.close(args.fd)) |err| .{ .err = err } else Maybe(Return.Close).success; - }, - else => {}, - } - - return .{ .err = Syscall.Error.todo }; + _ = flavor; + return if (Syscall.close(args.fd)) |err| .{ .err = err } else Maybe(Return.Close).success; } // since we use a 64 KB stack buffer, we should not let this function get inlined @@ -3714,132 +3579,92 @@ pub const NodeFS = struct { } pub fn exists(this: *NodeFS, args: Arguments.Exists, comptime flavor: Flavor) Maybe(Return.Exists) { + _ = flavor; const Ret = Maybe(Return.Exists); - switch (comptime flavor) { - .sync => { - const path = args.path orelse return Ret{ .result = false }; - const slice = path.sliceZ(&this.sync_error_buf); - // access() may not work correctly on NFS file systems with UID - // mapping enabled, because UID mapping is done on the server and - // hidden from the client, which checks permissions. Similar - // problems can occur to FUSE mounts. - const rc = (system.access(slice, std.os.F_OK)); - return Ret{ .result = rc == 0 }; - }, - else => {}, - } - - return Ret.todo; + const path = args.path orelse return Ret{ .result = false }; + const slice = path.sliceZ(&this.sync_error_buf); + // access() may not work correctly on NFS file systems with UID + // mapping enabled, because UID mapping is done on the server and + // hidden from the client, which checks permissions. Similar + // problems can occur to FUSE mounts. + const rc = (system.access(slice, std.os.F_OK)); + return Ret{ .result = rc == 0 }; } pub fn chown(this: *NodeFS, args: Arguments.Chown, comptime flavor: Flavor) Maybe(Return.Chown) { + _ = flavor; if (comptime Environment.isWindows) { return Maybe(Return.Fchmod).todo; } const path = args.path.sliceZ(&this.sync_error_buf); - switch (comptime flavor) { - .sync => return Syscall.chown(path, args.uid, args.gid), - else => {}, - } - - return Maybe(Return.Chown).todo; + return Syscall.chown(path, args.uid, args.gid); } /// This should almost never be async pub fn chmod(this: *NodeFS, args: Arguments.Chmod, comptime flavor: Flavor) Maybe(Return.Chmod) { + _ = flavor; if (comptime Environment.isWindows) { return Maybe(Return.Fchmod).todo; } const path = args.path.sliceZ(&this.sync_error_buf); - switch (comptime flavor) { - .sync => { - return Maybe(Return.Chmod).errnoSysP(C.chmod(path, args.mode), .chmod, path) orelse - Maybe(Return.Chmod).success; - }, - else => {}, - } - - return Maybe(Return.Chmod).todo; + return Maybe(Return.Chmod).errnoSysP(C.chmod(path, args.mode), .chmod, path) orelse + Maybe(Return.Chmod).success; } /// This should almost never be async pub fn fchmod(_: *NodeFS, args: Arguments.FChmod, comptime flavor: Flavor) Maybe(Return.Fchmod) { + _ = flavor; if (comptime Environment.isWindows) { return Maybe(Return.Fchmod).todo; } - switch (comptime flavor) { - .sync => { - return Syscall.fchmod(args.fd, args.mode); - }, - else => {}, - } - - return Maybe(Return.Fchmod).todo; + return Syscall.fchmod(args.fd, args.mode); } pub fn fchown(_: *NodeFS, args: Arguments.Fchown, comptime flavor: Flavor) Maybe(Return.Fchown) { + _ = flavor; if (comptime Environment.isWindows) { return Maybe(Return.Fchown).todo; } - switch (comptime flavor) { - .sync => { - return Maybe(Return.Fchown).errnoSys(C.fchown(args.fd, args.uid, args.gid), .fchown) orelse - Maybe(Return.Fchown).success; - }, - else => {}, - } - - return Maybe(Return.Fchown).todo; + return Maybe(Return.Fchown).errnoSys(C.fchown(args.fd, args.uid, args.gid), .fchown) orelse + Maybe(Return.Fchown).success; } pub fn fdatasync(_: *NodeFS, args: Arguments.FdataSync, comptime flavor: Flavor) Maybe(Return.Fdatasync) { + _ = flavor; if (comptime Environment.isWindows) { return Maybe(Return.Fdatasync).todo; } - switch (comptime flavor) { - .sync => return Maybe(Return.Fdatasync).errnoSys(system.fdatasync(args.fd), .fdatasync) orelse - Maybe(Return.Fdatasync).success, - else => {}, - } - - return Maybe(Return.Fdatasync).todo; + return Maybe(Return.Fdatasync).errnoSys(system.fdatasync(args.fd), .fdatasync) orelse + Maybe(Return.Fdatasync).success; } pub fn fstat(_: *NodeFS, args: Arguments.Fstat, comptime flavor: Flavor) Maybe(Return.Fstat) { + _ = flavor; if (comptime Environment.isWindows) { return Maybe(Return.Fstat).todo; } - switch (comptime flavor) { - .sync => { - if (comptime Environment.isPosix) { - return switch (Syscall.fstat(args.fd)) { - .result => |result| Maybe(Return.Fstat){ .result = Stats.init(result, false) }, - .err => |err| Maybe(Return.Fstat){ .err = err }, - }; - } - }, - else => {}, + if (comptime Environment.isPosix) { + return switch (Syscall.fstat(args.fd)) { + .result => |result| Maybe(Return.Fstat){ .result = Stats.init(result, false) }, + .err => |err| Maybe(Return.Fstat){ .err = err }, + }; } return Maybe(Return.Fstat).todo; } pub fn fsync(_: *NodeFS, args: Arguments.Fsync, comptime flavor: Flavor) Maybe(Return.Fsync) { + _ = flavor; if (comptime Environment.isWindows) { return Maybe(Return.Fsync).todo; } - switch (comptime flavor) { - .sync => return Maybe(Return.Fsync).errnoSys(system.fsync(args.fd), .fsync) orelse - Maybe(Return.Fsync).success, - else => {}, - } - - return Maybe(Return.Fsync).todo; + return Maybe(Return.Fsync).errnoSys(system.fsync(args.fd), .fsync) orelse + Maybe(Return.Fsync).success; } pub fn ftruncateSync(args: Arguments.FTruncate) Maybe(Return.Ftruncate) { @@ -3847,14 +3672,11 @@ pub const NodeFS = struct { } pub fn ftruncate(_: *NodeFS, args: Arguments.FTruncate, comptime flavor: Flavor) Maybe(Return.Ftruncate) { - switch (comptime flavor) { - .sync => return ftruncateSync(args), - else => {}, - } - - return Maybe(Return.Ftruncate).todo; + _ = flavor; + return ftruncateSync(args); } pub fn futimes(_: *NodeFS, args: Arguments.Futimes, comptime flavor: Flavor) Maybe(Return.Futimes) { + _ = flavor; if (comptime Environment.isWindows) { return Maybe(Return.Futimes).todo; } @@ -3870,66 +3692,43 @@ pub const NodeFS = struct { }, }; - switch (comptime flavor) { - .sync => return if (Maybe(Return.Futimes).errnoSys(system.futimens(args.fd, ×), .futimens)) |err| - err - else - Maybe(Return.Futimes).success, - else => {}, - } - - return Maybe(Return.Futimes).todo; + return if (Maybe(Return.Futimes).errnoSys(system.futimens(args.fd, ×), .futimens)) |err| + err + else + Maybe(Return.Futimes).success; } pub fn lchmod(this: *NodeFS, args: Arguments.LCHmod, comptime flavor: Flavor) Maybe(Return.Lchmod) { + _ = flavor; if (comptime Environment.isWindows) { return Maybe(Return.Lchmod).todo; } const path = args.path.sliceZ(&this.sync_error_buf); - switch (comptime flavor) { - .sync => { - return Maybe(Return.Lchmod).errnoSysP(C.lchmod(path, args.mode), .lchmod, path) orelse - Maybe(Return.Lchmod).success; - }, - else => {}, - } - - return Maybe(Return.Lchmod).todo; + return Maybe(Return.Lchmod).errnoSysP(C.lchmod(path, args.mode), .lchmod, path) orelse + Maybe(Return.Lchmod).success; } pub fn lchown(this: *NodeFS, args: Arguments.LChown, comptime flavor: Flavor) Maybe(Return.Lchown) { + _ = flavor; if (comptime Environment.isWindows) { return Maybe(Return.Lchown).todo; } const path = args.path.sliceZ(&this.sync_error_buf); - switch (comptime flavor) { - .sync => { - return Maybe(Return.Lchown).errnoSysP(C.lchown(path, args.uid, args.gid), .lchown, path) orelse - Maybe(Return.Lchown).success; - }, - else => {}, - } - - return Maybe(Return.Lchown).todo; + return Maybe(Return.Lchown).errnoSysP(C.lchown(path, args.uid, args.gid), .lchown, path) orelse + Maybe(Return.Lchown).success; } pub fn link(this: *NodeFS, args: Arguments.Link, comptime flavor: Flavor) Maybe(Return.Link) { + _ = flavor; var new_path_buf: [bun.MAX_PATH_BYTES]u8 = undefined; const from = args.old_path.sliceZ(&this.sync_error_buf); const to = args.new_path.sliceZ(&new_path_buf); - switch (comptime flavor) { - .sync => { - return Maybe(Return.Link).errnoSysP(system.link(from, to, 0), .link, from) orelse - Maybe(Return.Link).success; - }, - else => {}, - } - - return Maybe(Return.Link).todo; + return Maybe(Return.Link).errnoSysP(system.link(from, to, 0), .link, from) orelse + Maybe(Return.Link).success; } pub fn lstat(this: *NodeFS, args: Arguments.Lstat, comptime flavor: Flavor) Maybe(Return.Lstat) { if (comptime Environment.isWindows) { @@ -3957,158 +3756,146 @@ pub const NodeFS = struct { } // Node doesn't absolute the path so we don't have to either fn mkdirNonRecursive(this: *NodeFS, args: Arguments.Mkdir, comptime flavor: Flavor) Maybe(Return.Mkdir) { - switch (comptime flavor) { - .sync => { - const path = args.path.sliceZ(&this.sync_error_buf); - return switch (Syscall.mkdir(path, args.mode)) { - .result => Maybe(Return.Mkdir){ .result = bun.String.empty }, - .err => |err| Maybe(Return.Mkdir){ .err = err }, - }; - }, - else => {}, - } + _ = flavor; - return Maybe(Return.Mkdir).todo; + const path = args.path.sliceZ(&this.sync_error_buf); + return switch (Syscall.mkdir(path, args.mode)) { + .result => Maybe(Return.Mkdir){ .result = bun.String.empty }, + .err => |err| Maybe(Return.Mkdir){ .err = err }, + }; } // TODO: windows // TODO: verify this works correctly with unicode codepoints pub fn mkdirRecursive(this: *NodeFS, args: Arguments.Mkdir, comptime flavor: Flavor) Maybe(Return.Mkdir) { + _ = flavor; const Option = Maybe(Return.Mkdir); if (comptime Environment.isWindows) return Option.todo; - switch (comptime flavor) { - // The sync version does no allocation except when returning the path - .sync => { - var buf: [bun.MAX_PATH_BYTES]u8 = undefined; - const path = args.path.sliceZWithForceCopy(&buf, true); - const len = @as(u16, @truncate(path.len)); + var buf: [bun.MAX_PATH_BYTES]u8 = undefined; + const path = args.path.sliceZWithForceCopy(&buf, true); + const len = @as(u16, @truncate(path.len)); - // First, attempt to create the desired directory - // If that fails, then walk back up the path until we have a match - switch (Syscall.mkdir(path, args.mode)) { - .err => |err| { - switch (err.getErrno()) { - else => { - @memcpy(this.sync_error_buf[0..len], path[0..len]); - return .{ .err = err.withPath(this.sync_error_buf[0..len]) }; - }, - - .EXIST => { - return Option{ .result = bun.String.empty }; - }, - // continue - .NOENT => {}, - } + // First, attempt to create the desired directory + // If that fails, then walk back up the path until we have a match + switch (Syscall.mkdir(path, args.mode)) { + .err => |err| { + switch (err.getErrno()) { + else => { + @memcpy(this.sync_error_buf[0..len], path[0..len]); + return .{ .err = err.withPath(this.sync_error_buf[0..len]) }; }, - .result => { - return Option{ - .result = if (args.path == .slice_with_underlying_string) - args.path.slice_with_underlying_string.underlying - else - bun.String.create(args.path.slice()), - }; + + .EXIST => { + return Option{ .result = bun.String.empty }; }, + // continue + .NOENT => {}, } + }, + .result => { + return Option{ + .result = if (args.path == .slice_with_underlying_string) + args.path.slice_with_underlying_string.underlying + else + bun.String.create(args.path.slice()), + }; + }, + } - var working_mem = &this.sync_error_buf; - @memcpy(working_mem[0..len], path[0..len]); + var working_mem = &this.sync_error_buf; + @memcpy(working_mem[0..len], path[0..len]); - var i: u16 = len - 1; + var i: u16 = len - 1; - // iterate backwards until creating the directory works successfully - while (i > 0) : (i -= 1) { - if (path[i] == std.fs.path.sep) { - working_mem[i] = 0; - var parent: [:0]u8 = working_mem[0..i :0]; + // iterate backwards until creating the directory works successfully + while (i > 0) : (i -= 1) { + if (path[i] == std.fs.path.sep) { + working_mem[i] = 0; + var parent: [:0]u8 = working_mem[0..i :0]; - switch (Syscall.mkdir(parent, args.mode)) { - .err => |err| { - working_mem[i] = std.fs.path.sep; - switch (err.getErrno()) { - .EXIST => { - // Handle race condition - break; - }, - .NOENT => { - continue; - }, - else => return .{ .err = err.withPath(parent) }, - } - }, - .result => { - // We found a parent that worked - working_mem[i] = std.fs.path.sep; + switch (Syscall.mkdir(parent, args.mode)) { + .err => |err| { + working_mem[i] = std.fs.path.sep; + switch (err.getErrno()) { + .EXIST => { + // Handle race condition break; }, - } - } - } - var first_match: u16 = i; - i += 1; - // after we find one that works, we go forward _after_ the first working directory - while (i < len) : (i += 1) { - if (path[i] == std.fs.path.sep) { - working_mem[i] = 0; - var parent: [:0]u8 = working_mem[0..i :0]; - - switch (Syscall.mkdir(parent, args.mode)) { - .err => |err| { - working_mem[i] = std.fs.path.sep; - switch (err.getErrno()) { - .EXIST => { - if (Environment.allow_assert) std.debug.assert(false); - continue; - }, - else => return .{ .err = err }, - } - }, - - .result => { - working_mem[i] = std.fs.path.sep; + .NOENT => { + continue; }, + else => return .{ .err = err.withPath(parent) }, } - } + }, + .result => { + // We found a parent that worked + working_mem[i] = std.fs.path.sep; + break; + }, } + } + } + var first_match: u16 = i; + i += 1; + // after we find one that works, we go forward _after_ the first working directory + while (i < len) : (i += 1) { + if (path[i] == std.fs.path.sep) { + working_mem[i] = 0; + var parent: [:0]u8 = working_mem[0..i :0]; - working_mem[len] = 0; - - // Our final directory will not have a trailing separator - // so we have to create it once again - switch (Syscall.mkdir(working_mem[0..len :0], args.mode)) { + switch (Syscall.mkdir(parent, args.mode)) { .err => |err| { + working_mem[i] = std.fs.path.sep; switch (err.getErrno()) { - // handle the race condition .EXIST => { - var display_path = bun.String.empty; - if (first_match != std.math.maxInt(u16)) { - display_path = bun.String.create(working_mem[0..first_match]); - } - return Option{ .result = display_path }; - }, - - // NOENT shouldn't happen here - else => return .{ - .err = err.withPath(path), + if (Environment.allow_assert) std.debug.assert(false); + continue; }, + else => return .{ .err = err }, } }, + .result => { - return Option{ - .result = if (first_match != std.math.maxInt(u16)) - bun.String.create(working_mem[0..first_match]) - else if (args.path == .slice_with_underlying_string) - args.path.slice_with_underlying_string.underlying - else - bun.String.create(args.path.slice()), - }; + working_mem[i] = std.fs.path.sep; }, } - }, - else => {}, + } } - return Maybe(Return.Mkdir).todo; + working_mem[len] = 0; + + // Our final directory will not have a trailing separator + // so we have to create it once again + switch (Syscall.mkdir(working_mem[0..len :0], args.mode)) { + .err => |err| { + switch (err.getErrno()) { + // handle the race condition + .EXIST => { + var display_path = bun.String.empty; + if (first_match != std.math.maxInt(u16)) { + display_path = bun.String.create(working_mem[0..first_match]); + } + return Option{ .result = display_path }; + }, + + // NOENT shouldn't happen here + else => return .{ + .err = err.withPath(path), + }, + } + }, + .result => { + return Option{ + .result = if (first_match != std.math.maxInt(u16)) + bun.String.create(working_mem[0..first_match]) + else if (args.path == .slice_with_underlying_string) + args.path.slice_with_underlying_string.underlying + else + bun.String.create(args.path.slice()), + }; + }, + } } pub fn mkdtemp(this: *NodeFS, args: Arguments.MkdirTemp, comptime _: Flavor) Maybe(Return.Mkdtemp) { @@ -4136,75 +3923,54 @@ pub const NodeFS = struct { return .{ .err = Syscall.Error{ .errno = @as(Syscall.Error.Int, @truncate(@intFromEnum(errno))), .syscall = .mkdtemp } }; } pub fn open(this: *NodeFS, args: Arguments.Open, comptime flavor: Flavor) Maybe(Return.Open) { - switch (comptime flavor) { - // The sync version does no allocation except when returning the path - .sync => { - const path = args.path.sliceZ(&this.sync_error_buf); - return switch (Syscall.open(path, @intFromEnum(args.flags), args.mode)) { - .err => |err| .{ - .err = err.withPath(args.path.slice()), - }, - .result => |fd| .{ .result = fd }, - }; + _ = flavor; + const path = args.path.sliceZ(&this.sync_error_buf); + return switch (Syscall.open(path, @intFromEnum(args.flags), args.mode)) { + .err => |err| .{ + .err = err.withPath(args.path.slice()), }, - else => {}, - } - - return Maybe(Return.Open).todo; + .result => |fd| .{ .result = fd }, + }; } pub fn openDir(_: *NodeFS, _: Arguments.OpenDir, comptime _: Flavor) Maybe(Return.OpenDir) { return Maybe(Return.OpenDir).todo; } fn _read(_: *NodeFS, args: Arguments.Read, comptime flavor: Flavor) Maybe(Return.Read) { + _ = flavor; if (Environment.allow_assert) std.debug.assert(args.position == null); + var buf = args.buffer.slice(); + buf = buf[@min(args.offset, buf.len)..]; + buf = buf[0..@min(buf.len, args.length)]; - switch (comptime flavor) { - // The sync version does no allocation except when returning the path - .sync => { - var buf = args.buffer.slice(); - buf = buf[@min(args.offset, buf.len)..]; - buf = buf[0..@min(buf.len, args.length)]; - - return switch (Syscall.read(args.fd, buf)) { - .err => |err| .{ - .err = err, - }, - .result => |amt| .{ - .result = .{ - .bytes_read = @as(u52, @truncate(amt)), - }, - }, - }; + return switch (Syscall.read(args.fd, buf)) { + .err => |err| .{ + .err = err, }, - else => {}, - } - - return Maybe(Return.Read).todo; + .result => |amt| .{ + .result = .{ + .bytes_read = @as(u52, @truncate(amt)), + }, + }, + }; } fn _pread(_: *NodeFS, args: Arguments.Read, comptime flavor: Flavor) Maybe(Return.Read) { - switch (comptime flavor) { - .sync => { - var buf = args.buffer.slice(); - buf = buf[@min(args.offset, buf.len)..]; - buf = buf[0..@min(buf.len, args.length)]; - - return switch (Syscall.pread(args.fd, buf, args.position.?)) { - .err => |err| .{ - .err = err, - }, - .result => |amt| .{ - .result = .{ - .bytes_read = @as(u52, @truncate(amt)), - }, - }, - }; - }, - else => {}, - } + _ = flavor; + var buf = args.buffer.slice(); + buf = buf[@min(args.offset, buf.len)..]; + buf = buf[0..@min(buf.len, args.length)]; - return Maybe(Return.Read).todo; + return switch (Syscall.pread(args.fd, buf, args.position.?)) { + .err => |err| .{ + .err = err, + }, + .result => |amt| .{ + .result = .{ + .bytes_read = @as(u52, @truncate(amt)), + }, + }, + }; } pub fn read(this: *NodeFS, args: Arguments.Read, comptime flavor: Flavor) Maybe(Return.Read) { @@ -4236,127 +4002,91 @@ pub const NodeFS = struct { return if (args.position != null) _pwrite(this, args, flavor) else _write(this, args, flavor); } fn _write(_: *NodeFS, args: Arguments.Write, comptime flavor: Flavor) Maybe(Return.Write) { - switch (comptime flavor) { - .sync => { - var buf = args.buffer.slice(); - buf = buf[@min(args.offset, buf.len)..]; - buf = buf[0..@min(buf.len, args.length)]; - - return switch (Syscall.write(args.fd, buf)) { - .err => |err| .{ - .err = err, - }, - .result => |amt| .{ - .result = .{ - .bytes_written = @as(u52, @truncate(amt)), - }, - }, - }; - }, - else => {}, - } + _ = flavor; - return Maybe(Return.Write).todo; + var buf = args.buffer.slice(); + buf = buf[@min(args.offset, buf.len)..]; + buf = buf[0..@min(buf.len, args.length)]; + + return switch (Syscall.write(args.fd, buf)) { + .err => |err| .{ + .err = err, + }, + .result => |amt| .{ + .result = .{ + .bytes_written = @as(u52, @truncate(amt)), + }, + }, + }; } fn _pwrite(_: *NodeFS, args: Arguments.Write, comptime flavor: Flavor) Maybe(Return.Write) { + _ = flavor; const position = args.position.?; - switch (comptime flavor) { - .sync => { - var buf = args.buffer.slice(); - buf = buf[@min(args.offset, buf.len)..]; - buf = buf[0..@min(args.length, buf.len)]; + var buf = args.buffer.slice(); + buf = buf[@min(args.offset, buf.len)..]; + buf = buf[0..@min(args.length, buf.len)]; - return switch (Syscall.pwrite(args.fd, buf, position)) { - .err => |err| .{ - .err = err, - }, - .result => |amt| .{ .result = .{ - .bytes_written = @as(u52, @truncate(amt)), - } }, - }; + return switch (Syscall.pwrite(args.fd, buf, position)) { + .err => |err| .{ + .err = err, }, - else => {}, - } - - return Maybe(Return.Write).todo; + .result => |amt| .{ .result = .{ + .bytes_written = @as(u52, @truncate(amt)), + } }, + }; } fn _preadv(_: *NodeFS, args: Arguments.Readv, comptime flavor: Flavor) Maybe(Return.Readv) { + _ = flavor; const position = args.position.?; - switch (comptime flavor) { - .sync => { - return switch (Syscall.preadv(args.fd, args.buffers.buffers.items, position)) { - .err => |err| .{ - .err = err, - }, - .result => |amt| .{ .result = .{ - .bytes_read = @as(u52, @truncate(amt)), - } }, - }; + return switch (Syscall.preadv(args.fd, args.buffers.buffers.items, position)) { + .err => |err| .{ + .err = err, }, - else => {}, - } - - return Maybe(Return.Write).todo; + .result => |amt| .{ .result = .{ + .bytes_read = @as(u52, @truncate(amt)), + } }, + }; } fn _readv(_: *NodeFS, args: Arguments.Readv, comptime flavor: Flavor) Maybe(Return.Readv) { - switch (comptime flavor) { - .sync => { - return switch (Syscall.readv(args.fd, args.buffers.buffers.items)) { - .err => |err| .{ - .err = err, - }, - .result => |amt| .{ .result = .{ - .bytes_read = @as(u52, @truncate(amt)), - } }, - }; + _ = flavor; + return switch (Syscall.readv(args.fd, args.buffers.buffers.items)) { + .err => |err| .{ + .err = err, }, - else => {}, - } - - return Maybe(Return.Write).todo; + .result => |amt| .{ .result = .{ + .bytes_read = @as(u52, @truncate(amt)), + } }, + }; } fn _pwritev(_: *NodeFS, args: Arguments.Writev, comptime flavor: Flavor) Maybe(Return.Write) { + _ = flavor; const position = args.position.?; - - switch (comptime flavor) { - .sync => { - return switch (Syscall.pwritev(args.fd, args.buffers.buffers.items, position)) { - .err => |err| .{ - .err = err, - }, - .result => |amt| .{ .result = .{ - .bytes_written = @as(u52, @truncate(amt)), - } }, - }; + return switch (Syscall.pwritev(args.fd, args.buffers.buffers.items, position)) { + .err => |err| .{ + .err = err, }, - else => {}, - } - - return Maybe(Return.Write).todo; + .result => |amt| .{ .result = .{ + .bytes_written = @as(u52, @truncate(amt)), + } }, + }; } fn _writev(_: *NodeFS, args: Arguments.Writev, comptime flavor: Flavor) Maybe(Return.Write) { - switch (comptime flavor) { - .sync => { - return switch (Syscall.writev(args.fd, args.buffers.buffers.items)) { - .err => |err| .{ - .err = err, - }, - .result => |amt| .{ .result = .{ - .bytes_written = @as(u52, @truncate(amt)), - } }, - }; + _ = flavor; + return switch (Syscall.writev(args.fd, args.buffers.buffers.items)) { + .err => |err| .{ + .err = err, }, - else => {}, - } - - return Maybe(Return.Write).todo; + .result => |amt| .{ .result = .{ + .bytes_written = @as(u52, @truncate(amt)), + } }, + }; } pub fn readdir(this: *NodeFS, args: Arguments.Readdir, comptime flavor: Flavor) Maybe(Return.Readdir) { @@ -4751,50 +4481,39 @@ pub const NodeFS = struct { return Maybe(Return.WriteFile).success; } - pub fn writeFile(this: *NodeFS, args: Arguments.WriteFile, comptime flavor: Flavor) Maybe(Return.WriteFile) { - switch (comptime flavor) { - .sync => return writeFileWithPathBuffer(&this.sync_error_buf, args), - else => {}, - } - - return Maybe(Return.WriteFile).todo; + pub fn writeFile(this: *NodeFS, args: Arguments.WriteFile, comptime _: Flavor) Maybe(Return.WriteFile) { + return writeFileWithPathBuffer(&this.sync_error_buf, args); } - pub fn readlink(this: *NodeFS, args: Arguments.Readlink, comptime flavor: Flavor) Maybe(Return.Readlink) { + pub fn readlink(this: *NodeFS, args: Arguments.Readlink, comptime _: Flavor) Maybe(Return.Readlink) { var outbuf: [bun.MAX_PATH_BYTES]u8 = undefined; var inbuf = &this.sync_error_buf; - switch (comptime flavor) { - .sync => { - const path = args.path.sliceZ(inbuf); - const len = switch (Syscall.readlink(path, &outbuf)) { - .err => |err| return .{ - .err = err.withPath(args.path.slice()), - }, - .result => |buf_| buf_, - }; + const path = args.path.sliceZ(inbuf); - return .{ - .result = switch (args.encoding) { - .buffer => .{ - .buffer = Buffer.fromString(outbuf[0..len], bun.default_allocator) catch unreachable, - }, - else => if (args.path == .slice_with_underlying_string and - strings.eqlLong(args.path.slice_with_underlying_string.slice(), outbuf[0..len], true)) - .{ - .BunString = args.path.slice_with_underlying_string.underlying.dupeRef(), - } - else - .{ - .BunString = bun.String.create(outbuf[0..len]), - }, - }, - }; + const len = switch (Syscall.readlink(path, &outbuf)) { + .err => |err| return .{ + .err = err.withPath(args.path.slice()), }, - else => {}, - } + .result => |buf_| buf_, + }; - return Maybe(Return.Readlink).todo; + return .{ + .result = switch (args.encoding) { + .buffer => .{ + .buffer = Buffer.fromString(outbuf[0..len], bun.default_allocator) catch unreachable, + }, + else => if (args.path == .slice_with_underlying_string and + strings.eqlLong(args.path.slice_with_underlying_string.slice(), outbuf[0..len], true)) + .{ + .BunString = args.path.slice_with_underlying_string.underlying.dupeRef(), + } + else + .{ + .BunString = bun.String.create(outbuf[0..len]), + }, + }, + }; } pub fn realpath(this: *NodeFS, args: Arguments.Realpath, comptime _: Flavor) Maybe(Return.Realpath) { var outbuf: [bun.MAX_PATH_BYTES]u8 = undefined; @@ -4857,325 +4576,227 @@ pub const NodeFS = struct { // return error.NotImplementedYet; // } pub fn rename(this: *NodeFS, args: Arguments.Rename, comptime flavor: Flavor) Maybe(Return.Rename) { + _ = flavor; var from_buf = &this.sync_error_buf; var to_buf: [bun.MAX_PATH_BYTES]u8 = undefined; - switch (comptime flavor) { - .sync => { - var from = args.old_path.sliceZ(from_buf); - var to = args.new_path.sliceZ(&to_buf); - return Syscall.rename(from, to); - }, - else => {}, - } - - return Maybe(Return.Rename).todo; + var from = args.old_path.sliceZ(from_buf); + var to = args.new_path.sliceZ(&to_buf); + return Syscall.rename(from, to); } - pub fn rmdir(this: *NodeFS, args: Arguments.RmDir, comptime flavor: Flavor) Maybe(Return.Rmdir) { - switch (comptime flavor) { - .sync => { - if (comptime Environment.isMac) { - if (args.recursive) { - var dest = args.path.sliceZ(&this.sync_error_buf); - - var flags: u32 = bun.C.darwin.RemoveFileFlags.cross_mount | - bun.C.darwin.RemoveFileFlags.allow_long_paths | - bun.C.darwin.RemoveFileFlags.recursive; - - while (true) { - if (Maybe(Return.Rmdir).errnoSys(bun.C.darwin.removefileat(std.os.AT.FDCWD, dest, null, flags), .rmdir)) |errno| { - switch (@as(os.E, @enumFromInt(errno.err.errno))) { - .AGAIN, .INTR => continue, - .NOENT => return Maybe(Return.Rmdir).success, - .MLINK => { - var copy: [bun.MAX_PATH_BYTES]u8 = undefined; - @memcpy(copy[0..dest.len], dest); - copy[dest.len] = 0; - var dest_copy = copy[0..dest.len :0]; - switch (Syscall.unlink(dest_copy).getErrno()) { - .AGAIN, .INTR => continue, - .NOENT => return errno, - .SUCCESS => continue, - else => return errno, - } - }, - .SUCCESS => unreachable, - else => return errno, - } - } - - return Maybe(Return.Rmdir).success; - } - } - - return Maybe(Return.Rmdir).errnoSysP(system.rmdir(args.path.sliceZ(&this.sync_error_buf)), .rmdir, args.path.slice()) orelse - Maybe(Return.Rmdir).success; - } else if (comptime Environment.isLinux) { - if (args.recursive) { - std.fs.cwd().deleteTree(args.path.slice()) catch |err| { - const errno: std.os.E = switch (err) { - error.InvalidHandle => .BADF, - error.AccessDenied => .PERM, - error.FileTooBig => .FBIG, - error.SymLinkLoop => .LOOP, - error.ProcessFdQuotaExceeded => .NFILE, - error.NameTooLong => .NAMETOOLONG, - error.SystemFdQuotaExceeded => .MFILE, - error.SystemResources => .NOMEM, - error.ReadOnlyFileSystem => .ROFS, - error.FileSystem => .IO, - error.FileBusy => .BUSY, - error.DeviceBusy => .BUSY, - - // One of the path components was not a directory. - // This error is unreachable if `sub_path` does not contain a path separator. - error.NotDir => .NOTDIR, - // On Windows, file paths must be valid Unicode. - error.InvalidUtf8 => .INVAL, - - // On Windows, file paths cannot contain these characters: - // '/', '*', '?', '"', '<', '>', '|' - error.BadPathName => .INVAL, - - else => .FAULT, - }; - return Maybe(Return.Rm){ - .err = bun.sys.Error.fromCode(errno, .rmdir), - }; - }; + pub fn rmdir(this: *NodeFS, args: Arguments.RmDir, comptime _: Flavor) Maybe(Return.Rmdir) { + if (comptime Environment.isPosix) { + if (args.recursive) { + std.fs.cwd().deleteTree(args.path.slice()) catch |err| { + const errno: std.os.E = switch (err) { + error.InvalidHandle => .BADF, + error.AccessDenied => .PERM, + error.FileTooBig => .FBIG, + error.SymLinkLoop => .LOOP, + error.ProcessFdQuotaExceeded => .NFILE, + error.NameTooLong => .NAMETOOLONG, + error.SystemFdQuotaExceeded => .MFILE, + error.SystemResources => .NOMEM, + error.ReadOnlyFileSystem => .ROFS, + error.FileSystem => .IO, + error.FileBusy => .BUSY, + error.DeviceBusy => .BUSY, + + // One of the path components was not a directory. + // This error is unreachable if `sub_path` does not contain a path separator. + error.NotDir => .NOTDIR, + // On Windows, file paths must be valid Unicode. + error.InvalidUtf8 => .INVAL, + + // On Windows, file paths cannot contain these characters: + // '/', '*', '?', '"', '<', '>', '|' + error.BadPathName => .INVAL, + + else => .FAULT, + }; + return Maybe(Return.Rm){ + .err = bun.sys.Error.fromCode(errno, .rmdir), + }; + }; - return Maybe(Return.Rmdir).success; - } + return Maybe(Return.Rmdir).success; + } - return Maybe(Return.Rmdir).errnoSysP(system.rmdir(args.path.sliceZ(&this.sync_error_buf)), .rmdir, args.path.slice()) orelse - Maybe(Return.Rmdir).success; - } - }, - else => {}, + return Maybe(Return.Rmdir).errnoSysP(system.rmdir(args.path.sliceZ(&this.sync_error_buf)), .rmdir, args.path.slice()) orelse + Maybe(Return.Rmdir).success; } return Maybe(Return.Rmdir).todo; } pub fn rm(this: *NodeFS, args: Arguments.RmDir, comptime flavor: Flavor) Maybe(Return.Rm) { - switch (comptime flavor) { - .sync => { - if (comptime Environment.isMac) { - var dest = args.path.sliceZ(&this.sync_error_buf); - - while (true) { - var flags: u32 = 0; - if (args.recursive) { - flags |= bun.C.darwin.RemoveFileFlags.cross_mount; - flags |= bun.C.darwin.RemoveFileFlags.allow_long_paths; - flags |= bun.C.darwin.RemoveFileFlags.recursive; - } - - if (Maybe(Return.Rm).errnoSys(bun.C.darwin.removefileat(std.os.AT.FDCWD, dest, null, flags), .unlink)) |errno| { - switch (@as(os.E, @enumFromInt(errno.err.errno))) { - .AGAIN, .INTR => continue, - .NOENT => { - if (args.force) { - return Maybe(Return.Rm).success; - } - - return errno; - }, - - .MLINK => { - var copy: [bun.MAX_PATH_BYTES]u8 = undefined; - @memcpy(copy[0..dest.len], dest); - copy[dest.len] = 0; - var dest_copy = copy[0..dest.len :0]; - switch (Syscall.unlink(dest_copy).getErrno()) { - .AGAIN, .INTR => continue, - .NOENT => { - if (args.force) { - continue; - } - - return errno; - }, - .SUCCESS => continue, - else => return errno, - } - }, - .SUCCESS => unreachable, - else => return errno, - } - } + _ = flavor; + if (comptime Environment.isPosix) { + // We cannot use removefileat() on macOS because it does not handle write-protected files as expected. + if (args.recursive) { + // TODO: switch to an implementation which does not use any "unreachable" + std.fs.cwd().deleteTree(args.path.slice()) catch |err| { + const errno: E = switch (err) { + error.InvalidHandle => .BADF, + error.AccessDenied => .PERM, + error.FileTooBig => .FBIG, + error.SymLinkLoop => .LOOP, + error.ProcessFdQuotaExceeded => .NFILE, + error.NameTooLong => .NAMETOOLONG, + error.SystemFdQuotaExceeded => .MFILE, + error.SystemResources => .NOMEM, + error.ReadOnlyFileSystem => .ROFS, + error.FileSystem => .IO, + error.FileBusy => .BUSY, + error.DeviceBusy => .BUSY, + + // One of the path components was not a directory. + // This error is unreachable if `sub_path` does not contain a path separator. + error.NotDir => .NOTDIR, + // On Windows, file paths must be valid Unicode. + error.InvalidUtf8 => .INVAL, + + // On Windows, file paths cannot contain these characters: + // '/', '*', '?', '"', '<', '>', '|' + error.BadPathName => .INVAL, + + else => .FAULT, + }; + if (args.force) { return Maybe(Return.Rm).success; } - } else if (comptime Environment.isLinux or Environment.isWindows) { - if (args.recursive) { - std.fs.cwd().deleteTree(args.path.slice()) catch |err| { - const errno: E = switch (err) { - error.InvalidHandle => .BADF, - error.AccessDenied => .PERM, - error.FileTooBig => .FBIG, - error.SymLinkLoop => .LOOP, - error.ProcessFdQuotaExceeded => .NFILE, - error.NameTooLong => .NAMETOOLONG, - error.SystemFdQuotaExceeded => .MFILE, - error.SystemResources => .NOMEM, - error.ReadOnlyFileSystem => .ROFS, - error.FileSystem => .IO, - error.FileBusy => .BUSY, - error.DeviceBusy => .BUSY, - - // One of the path components was not a directory. - // This error is unreachable if `sub_path` does not contain a path separator. - error.NotDir => .NOTDIR, - // On Windows, file paths must be valid Unicode. - error.InvalidUtf8 => .INVAL, - - // On Windows, file paths cannot contain these characters: - // '/', '*', '?', '"', '<', '>', '|' - error.BadPathName => .INVAL, - - else => .FAULT, - }; - if (args.force) { - return Maybe(Return.Rm).success; - } - return Maybe(Return.Rm){ - .err = bun.sys.Error.fromCode(errno, .unlink), - }; - }; - return Maybe(Return.Rm).success; - } - } - - if (comptime Environment.isPosix) { - var dest = args.path.osPath(&this.sync_error_buf); - std.os.unlinkZ(dest) catch |er| { - // empircally, it seems to return AccessDenied when the - // file is actually a directory on macOS. - if (args.recursive and - (er == error.IsDir or er == error.NotDir or er == error.AccessDenied)) - { - std.os.rmdirZ(dest) catch |err| { - if (args.force) { - return Maybe(Return.Rm).success; - } - - const code: E = switch (err) { - error.AccessDenied => .PERM, - error.SymLinkLoop => .LOOP, - error.NameTooLong => .NAMETOOLONG, - error.SystemResources => .NOMEM, - error.ReadOnlyFileSystem => .ROFS, - error.FileBusy => .BUSY, - error.FileNotFound => .NOENT, - error.InvalidUtf8 => .INVAL, - error.BadPathName => .INVAL, - else => .FAULT, - }; + return Maybe(Return.Rm){ + .err = bun.sys.Error.fromCode(errno, .unlink), + }; + }; + return Maybe(Return.Rm).success; + } - return .{ - .err = bun.sys.Error.fromCode( - code, - .rmdir, - ), - }; - }; - - return Maybe(Return.Rm).success; - } + var dest = args.path.sliceZ(&this.sync_error_buf); + std.os.unlinkZ(dest) catch |er| { + // empircally, it seems to return AccessDenied when the + // file is actually a directory on macOS. + if (args.recursive and + (er == error.IsDir or er == error.NotDir or er == error.AccessDenied)) + { + std.os.rmdirZ(dest) catch |err| { if (args.force) { return Maybe(Return.Rm).success; } - { - const code: E = switch (er) { - error.AccessDenied => .PERM, - error.SymLinkLoop => .LOOP, - error.NameTooLong => .NAMETOOLONG, - error.SystemResources => .NOMEM, - error.ReadOnlyFileSystem => .ROFS, - error.FileBusy => .BUSY, - error.InvalidUtf8 => .INVAL, - error.BadPathName => .INVAL, - error.FileNotFound => .NOENT, - else => .FAULT, - }; + const code: E = switch (err) { + error.AccessDenied => .PERM, + error.SymLinkLoop => .LOOP, + error.NameTooLong => .NAMETOOLONG, + error.SystemResources => .NOMEM, + error.ReadOnlyFileSystem => .ROFS, + error.FileBusy => .BUSY, + error.FileNotFound => .NOENT, + error.InvalidUtf8 => .INVAL, + error.BadPathName => .INVAL, + else => .FAULT, + }; - return .{ - .err = bun.sys.Error.fromCode( - code, - .unlink, - ), - }; - } + return .{ + .err = bun.sys.Error.fromCode( + code, + .rmdir, + ), + }; }; return Maybe(Return.Rm).success; } - if (comptime Environment.isWindows) { - var dest = args.path.osPath(&this.sync_error_buf); - std.os.windows.DeleteFile(dest, .{ - .dir = null, - .remove_dir = brk: { - const file_attrs = std.os.windows.GetFileAttributesW(dest.ptr) catch |err| { - if (args.force) { - return Maybe(Return.Rm).success; - } + if (args.force) { + return Maybe(Return.Rm).success; + } - const code: E = switch (err) { - error.FileNotFound => .NOENT, - error.PermissionDenied => .PERM, - else => .INVAL, - }; + { + const code: E = switch (er) { + error.AccessDenied => .PERM, + error.SymLinkLoop => .LOOP, + error.NameTooLong => .NAMETOOLONG, + error.SystemResources => .NOMEM, + error.ReadOnlyFileSystem => .ROFS, + error.FileBusy => .BUSY, + error.InvalidUtf8 => .INVAL, + error.BadPathName => .INVAL, + error.FileNotFound => .NOENT, + else => .FAULT, + }; - return .{ - .err = bun.sys.Error.fromCode( - code, - .unlink, - ), - }; - }; - // TODO: check FILE_ATTRIBUTE_INVALID - break :brk (file_attrs & std.os.windows.FILE_ATTRIBUTE_DIRECTORY) != 0; - }, - }) catch |er| { - // empircally, it seems to return AccessDenied when the - // file is actually a directory on macOS. + return .{ + .err = bun.sys.Error.fromCode( + code, + .unlink, + ), + }; + } + }; + return Maybe(Return.Rm).success; + } + + if (comptime Environment.isWindows) { + var dest = args.path.osPath(&this.sync_error_buf); + std.os.windows.DeleteFile(dest, .{ + .dir = null, + .remove_dir = brk: { + const file_attrs = std.os.windows.GetFileAttributesW(dest.ptr) catch |err| { if (args.force) { return Maybe(Return.Rm).success; } - { - const code: E = switch (er) { - error.FileNotFound => .NOENT, - error.AccessDenied => .PERM, - error.NameTooLong => .INVAL, - error.FileBusy => .BUSY, - error.NotDir => .NOTDIR, - error.IsDir => .ISDIR, - error.DirNotEmpty => .INVAL, - error.NetworkNotFound => .NOENT, - else => .UNKNOWN, - }; + const code: E = switch (err) { + error.FileNotFound => .NOENT, + error.PermissionDenied => .PERM, + else => .INVAL, + }; - return .{ - .err = bun.sys.Error.fromCode( - code, - .unlink, - ), - }; - } + return .{ + .err = bun.sys.Error.fromCode( + code, + .unlink, + ), + }; }; + // TODO: check FILE_ATTRIBUTE_INVALID + break :brk (file_attrs & std.os.windows.FILE_ATTRIBUTE_DIRECTORY) != 0; + }, + }) catch |er| { + // empircally, it seems to return AccessDenied when the + // file is actually a directory on macOS. + if (args.force) { return Maybe(Return.Rm).success; } - }, - else => {}, - } - return Maybe(Return.Rm).todo; + { + const code: E = switch (er) { + error.FileNotFound => .NOENT, + error.AccessDenied => .PERM, + error.NameTooLong => .INVAL, + error.FileBusy => .BUSY, + error.NotDir => .NOTDIR, + error.IsDir => .ISDIR, + error.DirNotEmpty => .INVAL, + error.NetworkNotFound => .NOENT, + else => .UNKNOWN, + }; + + return .{ + .err = bun.sys.Error.fromCode( + code, + .unlink, + ), + }; + } + }; + + return Maybe(Return.Rm).success; + } } pub fn stat(this: *NodeFS, args: Arguments.Stat, comptime flavor: Flavor) Maybe(Return.Stat) { if (comptime Environment.isWindows) { @@ -5199,38 +4820,26 @@ pub const NodeFS = struct { } pub fn symlink(this: *NodeFS, args: Arguments.Symlink, comptime flavor: Flavor) Maybe(Return.Symlink) { + _ = flavor; if (comptime Environment.isWindows) { return Maybe(Return.Symlink).todo; } var to_buf: [bun.MAX_PATH_BYTES]u8 = undefined; - switch (comptime flavor) { - .sync => { - return Syscall.symlink( - args.old_path.sliceZ(&this.sync_error_buf), - args.new_path.sliceZ(&to_buf), - ); - }, - else => {}, - } - - return Maybe(Return.Symlink).todo; + return Syscall.symlink( + args.old_path.sliceZ(&this.sync_error_buf), + args.new_path.sliceZ(&to_buf), + ); } fn _truncate(this: *NodeFS, path: PathLike, len: JSC.WebCore.Blob.SizeType, comptime flavor: Flavor) Maybe(Return.Truncate) { + _ = flavor; if (comptime Environment.isWindows) { return Maybe(Return.Truncate).todo; } - switch (comptime flavor) { - .sync => { - return Maybe(Return.Truncate).errno(C.truncate(path.sliceZ(&this.sync_error_buf), len)) orelse - Maybe(Return.Truncate).success; - }, - else => {}, - } - - return Maybe(Return.Truncate).todo; + return Maybe(Return.Truncate).errno(C.truncate(path.sliceZ(&this.sync_error_buf), len)) orelse + Maybe(Return.Truncate).success; } pub fn truncate(this: *NodeFS, args: Arguments.Truncate, comptime flavor: Flavor) Maybe(Return.Truncate) { return switch (args.path) { @@ -5246,19 +4855,13 @@ pub const NodeFS = struct { }; } pub fn unlink(this: *NodeFS, args: Arguments.Unlink, comptime flavor: Flavor) Maybe(Return.Unlink) { + _ = flavor; if (comptime Environment.isWindows) { return Maybe(Return.Unlink).todo; } - switch (comptime flavor) { - .sync => { - return Maybe(Return.Unlink).errnoSysP(system.unlink(args.path.sliceZ(&this.sync_error_buf)), .unlink, args.path.slice()) orelse - Maybe(Return.Unlink).success; - }, - else => {}, - } - - return Maybe(Return.Unlink).todo; + return Maybe(Return.Unlink).errnoSysP(system.unlink(args.path.sliceZ(&this.sync_error_buf)), .unlink, args.path.slice()) orelse + Maybe(Return.Unlink).success; } pub fn watchFile(_: *NodeFS, args: Arguments.WatchFile, comptime flavor: Flavor) Maybe(Return.WatchFile) { std.debug.assert(flavor == .sync); @@ -5283,6 +4886,7 @@ pub const NodeFS = struct { return Maybe(Return.UnwatchFile).todo; } pub fn utimes(this: *NodeFS, args: Arguments.Utimes, comptime flavor: Flavor) Maybe(Return.Utimes) { + _ = flavor; if (comptime Environment.isWindows) { return Maybe(Return.Utimes).todo; } @@ -5300,21 +4904,13 @@ pub const NodeFS = struct { }, }; - switch (comptime flavor) { - // futimes uses the syscall version - // we use libc because here, not for a good reason - // just missing from the linux syscall interface in zig and I don't want to modify that right now - .sync => return if (Maybe(Return.Utimes).errnoSysP(std.c.utimes(args.path.sliceZ(&this.sync_error_buf), ×), .utimes, args.path.slice())) |err| - err - else - Maybe(Return.Utimes).success, - else => {}, - } - - return Maybe(Return.Utimes).todo; + return if (Maybe(Return.Utimes).errnoSysP(std.c.utimes(args.path.sliceZ(&this.sync_error_buf), ×), .utimes, args.path.slice())) |err| + err + else + Maybe(Return.Utimes).success; } - pub fn lutimes(this: *NodeFS, args: Arguments.Lutimes, comptime flavor: Flavor) Maybe(Return.Lutimes) { + pub fn lutimes(this: *NodeFS, args: Arguments.Lutimes, comptime _: Flavor) Maybe(Return.Lutimes) { if (comptime Environment.isWindows) { return Maybe(Return.Lutimes).todo; } @@ -5332,18 +4928,10 @@ pub const NodeFS = struct { }, }; - switch (comptime flavor) { - // futimes uses the syscall version - // we use libc because here, not for a good reason - // just missing from the linux syscall interface in zig and I don't want to modify that right now - .sync => return if (Maybe(Return.Lutimes).errnoSysP(C.lutimes(args.path.sliceZ(&this.sync_error_buf), ×), .lutimes, args.path.slice())) |err| - err - else - Maybe(Return.Lutimes).success, - else => {}, - } - - return Maybe(Return.Lutimes).todo; + return if (Maybe(Return.Lutimes).errnoSysP(C.lutimes(args.path.sliceZ(&this.sync_error_buf), ×), .lutimes, args.path.slice())) |err| + err + else + Maybe(Return.Lutimes).success; } pub fn watch(_: *NodeFS, args: Arguments.Watch, comptime _: Flavor) Maybe(Return.Watch) { if (comptime Environment.isWindows) { diff --git a/src/bun.js/node/node_fs_binding.zig b/src/bun.js/node/node_fs_binding.zig index b3866b557..967acbe53 100644 --- a/src/bun.js/node/node_fs_binding.zig +++ b/src/bun.js/node/node_fs_binding.zig @@ -67,6 +67,7 @@ fn callSync(comptime FunctionEnum: NodeFSFunctionEnum) NodeFSFunction { args, comptime Flavor.sync, ); + switch (result) { .err => |err| { globalObject.throwValue(JSC.JSValue.c(err.toJS(globalObject))); @@ -108,14 +109,6 @@ fn call(comptime FunctionEnum: NodeFSFunctionEnum) NodeFSFunction { globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame, ) callconv(.C) JSC.JSValue { - switch (comptime FunctionEnum) { - .readdir, .lstat, .stat, .readFile, .realpath, .copyFile, .cp => {}, - else => { - globalObject.throw("Not implemented yet", .{}); - return .zero; - }, - } - var arguments = callframe.arguments(8); var slice = ArgumentsSlice.init(globalObject.bunVM(), arguments.ptr[0..arguments.len]); @@ -142,57 +135,12 @@ fn call(comptime FunctionEnum: NodeFSFunctionEnum) NodeFSFunction { // TODO: handle globalObject.throwValue - if (comptime FunctionEnum == .readdir) { - return JSC.Node.AsyncReaddirTask.create(globalObject, args, slice.vm, slice.arena); - } - - if (comptime FunctionEnum == .readFile) { - return JSC.Node.AsyncReadFileTask.create(globalObject, args, slice.vm, slice.arena); - } - - if (comptime FunctionEnum == .realpath) { - return JSC.Node.AsyncRealpathTask.create(globalObject, args, slice.vm, slice.arena); - } - - if (comptime FunctionEnum == .stat or FunctionEnum == .lstat) { - return JSC.Node.AsyncStatTask.create(globalObject, args, slice.vm, FunctionEnum == .lstat, slice.arena); - } - - if (comptime FunctionEnum == .copyFile) { - return JSC.Node.AsyncCopyFileTask.create(globalObject, args, slice.vm, slice.arena); - } - + const Task = @field(JSC.Node.Async, @tagName(FunctionEnum)); if (comptime FunctionEnum == .cp) { - return JSC.Node.AsyncCpTask.create(globalObject, args, slice.vm, slice.arena); + return Task.create(globalObject, args, globalObject.bunVM(), slice.arena); + } else { + return Task.create(globalObject, args, globalObject.bunVM()); } - - // defer { - // for (arguments.len) |arg| { - // JSC.C.JSValueUnprotect(ctx, arg); - // } - // slice.arena.deinit(); - // } - - // const args = if (comptime Arguments != void) - // Arguments.fromJS(ctx, &slice, exception) - // else - // Arguments{}; - // if (exception.* != null) return null; - - // const result: Maybe(Result) = Function(this, comptime Flavor.sync, args); - // switch (result) { - // .err => |err| { - // exception.* = err.toJS(ctx); - // return null; - // }, - // .result => |res| { - // return switch (comptime Result) { - // void => JSC.JSValue.jsUndefined().asRef(), - // else => res.toJS(ctx), - // }; - // }, - // } - // unreachable; } }; return NodeBindingClosure.bind; diff --git a/src/bun.js/node/node_fs_constant.zig b/src/bun.js/node/node_fs_constant.zig index 0d8ec66c5..75211723d 100644 --- a/src/bun.js/node/node_fs_constant.zig +++ b/src/bun.js/node/node_fs_constant.zig @@ -6,8 +6,9 @@ fn get(comptime name: []const u8) comptime_int { return if (@hasDecl(std.os.O, name)) return @field(std.os.O, name) else - return 0; + @compileError("Unknown Constant: " ++ name); } + pub const Constants = struct { // File Access Constants /// Constant for fs.access(). File is visible to the calling process. @@ -41,16 +42,15 @@ pub const Constants = struct { }; /// Constant for fs.copyFile. Flag indicating the destination file should not be overwritten if it already exists. - pub const COPYFILE_EXCL: i32 = 1 << Copyfile.exclusive; - + pub const COPYFILE_EXCL: i32 = Copyfile.exclusive; /// /// Constant for fs.copyFile. copy operation will attempt to create a copy-on-write reflink. /// If the underlying platform does not support copy-on-write, then a fallback copy mechanism is used. - pub const COPYFILE_FICLONE: i32 = 1 << Copyfile.clone; + pub const COPYFILE_FICLONE: i32 = Copyfile.clone; /// /// Constant for fs.copyFile. Copy operation will attempt to create a copy-on-write reflink. /// If the underlying platform does not support copy-on-write, then the operation will fail with an error. - pub const COPYFILE_FICLONE_FORCE: i32 = 1 << Copyfile.force; + pub const COPYFILE_FICLONE_FORCE: i32 = Copyfile.force; // File Open Constants /// Constant for fs.open(). Flag indicating to open a file for read-only access. pub const O_RDONLY = std.os.O.RDONLY; @@ -142,64 +142,3 @@ pub const Constants = struct { /// this flag is ignored. pub const UV_FS_O_FILEMAP = 49152; }; - -// Due to zig's format support max 32 arguments, we need to split -// here. -const constants_string_format1 = - \\var constants = {{ - \\ F_OK: {d}, - \\ R_OK: {d}, - \\ W_OK: {d}, - \\ X_OK: {d}, - \\ COPYFILE_EXCL: {d}, - \\ COPYFILE_FICLONE: {d}, - \\ COPYFILE_FICLONE_FORCE: {d}, - \\ O_RDONLY: {d}, - \\ O_WRONLY: {d}, - \\ O_RDWR: {d}, - \\ O_CREAT: {d}, - \\ O_EXCL: {d}, - \\ O_NOCTTY: {d}, - \\ O_TRUNC: {d}, - \\ O_APPEND: {d}, - \\ O_DIRECTORY: {d}, - \\ O_NOATIME: {d}, - \\ O_NOFOLLOW: {d}, - \\ O_SYNC: {d}, - \\ O_DSYNC: {d}, -; -const constants_string_format2 = - \\ O_SYMLINK: {s}, - \\ O_DIRECT: {d}, - \\ O_NONBLOCK: {d}, - \\ S_IFMT: {d}, - \\ S_IFREG: {d}, - \\ S_IFDIR: {d}, - \\ S_IFCHR: {d}, - \\ S_IFBLK: {d}, - \\ S_IFIFO: {d}, - \\ S_IFLNK: {d}, - \\ S_IFSOCK: {d}, - \\ S_IRWXU: {d}, - \\ S_IRUSR: {d}, - \\ S_IWUSR: {d}, - \\ S_IXUSR: {d}, - \\ S_IRWXG: {d}, - \\ S_IRGRP: {d}, - \\ S_IWGRP: {d}, - \\ S_IXGRP: {d}, - \\ S_IRWXO: {d}, - \\ S_IROTH: {d}, - \\ S_IWOTH: {d}, - \\ S_IXOTH: {d}, - \\ UV_FS_O_FILEMAP: {d} - \\}}; - \\ -; - -const constants_string1 = std.fmt.comptimePrint(constants_string_format1, .{ Constants.F_OK, Constants.R_OK, Constants.W_OK, Constants.X_OK, Constants.COPYFILE_EXCL, Constants.COPYFILE_FICLONE, Constants.COPYFILE_FICLONE_FORCE, Constants.O_RDONLY, Constants.O_WRONLY, Constants.O_RDWR, Constants.O_CREAT, Constants.O_EXCL, Constants.O_NOCTTY, Constants.O_TRUNC, Constants.O_APPEND, Constants.O_DIRECTORY, Constants.O_NOATIME, Constants.O_NOFOLLOW, Constants.O_SYNC, Constants.O_DSYNC }); - -const constants_string2 = - std.fmt.comptimePrint(constants_string_format2, .{ if (@TypeOf(Constants.O_SYMLINK) == void) "undefined" else std.fmt.comptimePrint("{}", .{Constants.O_SYMLINK}), Constants.O_DIRECT, Constants.O_NONBLOCK, Constants.S_IFMT, Constants.S_IFREG, Constants.S_IFDIR, Constants.S_IFCHR, Constants.S_IFBLK, Constants.S_IFIFO, Constants.S_IFLNK, Constants.S_IFSOCK, Constants.S_IRWXU, Constants.S_IRUSR, Constants.S_IWUSR, Constants.S_IXUSR, Constants.S_IRWXG, Constants.S_IRGRP, Constants.S_IWGRP, Constants.S_IXGRP, Constants.S_IRWXO, Constants.S_IROTH, Constants.S_IWOTH, Constants.S_IXOTH, Constants.UV_FS_O_FILEMAP }); - -pub const constants_string = constants_string1 ++ constants_string2; diff --git a/src/bun.js/node/node_fs_stat_watcher.zig b/src/bun.js/node/node_fs_stat_watcher.zig index c2690c200..158a08ff7 100644 --- a/src/bun.js/node/node_fs_stat_watcher.zig +++ b/src/bun.js/node/node_fs_stat_watcher.zig @@ -97,7 +97,7 @@ pub const StatWatcherScheduler = struct { prev = next; } else { if (this.head.load(.Monotonic) == null) { - this.timer.?.deinit(); + this.timer.?.deinit(false); this.timer = null; // The scheduler is not deinit here, but it will get reused. } @@ -198,7 +198,7 @@ pub const StatWatcher = struct { pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Arguments { const vm = ctx.vm(); - const path = PathLike.fromJS(ctx, arguments, exception) orelse { + const path = PathLike.fromJSWithAllocator(ctx, arguments, bun.default_allocator, exception) orelse { if (exception.* == null) { JSC.throwInvalidArguments( "filename must be a string or TypedArray", diff --git a/src/bun.js/node/node_os.zig b/src/bun.js/node/node_os.zig index 07dec1c7d..ae8f527ce 100644 --- a/src/bun.js/node/node_os.zig +++ b/src/bun.js/node/node_os.zig @@ -531,6 +531,9 @@ pub const Os = struct { addr_data[3], addr_data[4], addr_data[5], }) catch unreachable; interface.put(globalThis, JSC.ZigString.static("mac"), JSC.ZigString.init(mac).withEncoding().toValueGC(globalThis)); + } else { + const mac = "00:00:00:00:00:00"; + interface.put(globalThis, JSC.ZigString.static("mac"), JSC.ZigString.init(mac).withEncoding().toValueGC(globalThis)); } } diff --git a/src/bun.js/node/path_watcher.zig b/src/bun.js/node/path_watcher.zig index 4f44a68ff..e00451a38 100644 --- a/src/bun.js/node/path_watcher.zig +++ b/src/bun.js/node/path_watcher.zig @@ -286,17 +286,8 @@ pub const PathWatcherManager = struct { if (!(path.len == 1 and entry_point[0] == '/')) { path = path[entry_point.len..]; - if (path.len == 0) { - while (path.len > 0) { - if (bun.strings.startsWithChar(path, '/')) { - path = path[1..]; - break; - } else { - path = path[1..]; - } - } - } else { - // Skip forward slash + // Skip leading slash + if (bun.strings.startsWithChar(path, '/')) { path = path[1..]; } } diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig index 35daea52c..96d1a00ef 100644 --- a/src/bun.js/node/types.zig +++ b/src/bun.js/node/types.zig @@ -315,6 +315,89 @@ pub const StringOrBunStringOrBuffer = union(enum) { } }; +pub const SliceWithUnderlyingStringOrBuffer = union(enum) { + SliceWithUnderlyingString: bun.SliceWithUnderlyingString, + buffer: Buffer, + + pub fn toThreadSafe(this: *@This()) void { + switch (this.*) { + .SliceWithUnderlyingString => this.SliceWithUnderlyingString.toThreadSafe(), + else => {}, + } + } + + pub fn toJS(this: *SliceWithUnderlyingStringOrBuffer, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.C.JSValueRef { + return switch (this) { + .SliceWithUnderlyingStringOrBuffer => { + defer { + this.SliceWithUnderlyingString.deinit(); + this.SliceWithUnderlyingString.underlying = bun.String.empty; + this.SliceWithUnderlyingString.utf8 = .{}; + } + + return this.SliceWithUnderlyingString.underlying.toJS(ctx); + }, + .buffer => this.buffer.toJSObjectRef(ctx, exception), + }; + } + + pub fn slice(this: *const SliceWithUnderlyingStringOrBuffer) []const u8 { + return switch (this.*) { + .SliceWithUnderlyingString => this.SliceWithUnderlyingString.slice(), + .buffer => this.buffer.slice(), + }; + } + + pub fn deinit(this: *const SliceWithUnderlyingStringOrBuffer) void { + switch (this.*) { + .SliceWithUnderlyingString => |*str| { + str.deinit(); + }, + else => {}, + } + } + + pub fn deinitAndUnprotect(this: *const SliceWithUnderlyingStringOrBuffer) void { + switch (this.*) { + .SliceWithUnderlyingString => |*str| { + str.deinit(); + }, + .buffer => |buffer| { + buffer.buffer.value.unprotect(); + }, + } + } + + pub fn fromJS(global: *JSC.JSGlobalObject, allocator: std.mem.Allocator, value: JSC.JSValue, exception: JSC.C.ExceptionRef) ?SliceWithUnderlyingStringOrBuffer { + _ = exception; + return switch (value.jsType()) { + JSC.JSValue.JSType.String, JSC.JSValue.JSType.StringObject, JSC.JSValue.JSType.DerivedStringObject, JSC.JSValue.JSType.Object => { + var str = bun.String.tryFromJS(value, global) orelse return null; + str.ref(); + return SliceWithUnderlyingStringOrBuffer{ .SliceWithUnderlyingString = str.toSlice(allocator) }; + }, + + .ArrayBuffer, + .Int8Array, + .Uint8Array, + .Uint8ClampedArray, + .Int16Array, + .Uint16Array, + .Int32Array, + .Uint32Array, + .Float32Array, + .Float64Array, + .BigInt64Array, + .BigUint64Array, + .DataView, + => SliceWithUnderlyingStringOrBuffer{ + .buffer = Buffer.fromArrayBuffer(global, value), + }, + else => null, + }; + } +}; + /// Like StringOrBuffer but actually returns a Node.js Buffer pub const StringOrNodeBuffer = union(Tag) { string: string, @@ -401,6 +484,20 @@ pub const SliceOrBuffer = union(Tag) { } } + pub fn toThreadSafe(this: *SliceOrBuffer) void { + var buffer: ?Buffer = null; + if (this.* == .buffer) { + buffer = this.buffer; + this.buffer.buffer.value.ensureStillAlive(); + } + defer { + if (buffer) |buf| { + buf.buffer.value.unprotect(); + } + } + this.ensureCloned(bun.default_allocator) catch unreachable; + } + pub const Tag = enum { string, buffer }; pub fn slice(this: SliceOrBuffer) []const u8 { @@ -650,6 +747,10 @@ pub const PathLike = union(Tag) { if (this.* == .slice_with_underlying_string) { this.slice_with_underlying_string.toThreadSafe(); } + + if (this.* == .buffer) { + this.buffer.buffer.value.protect(); + } } pub fn deinitAndUnprotect(this: *const PathLike) void { @@ -722,7 +823,7 @@ pub const PathLike = union(Tag) { } pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?PathLike { - return fromJSWithAllocator(ctx, arguments, arguments.arena.allocator(), exception); + return fromJSWithAllocator(ctx, arguments, bun.default_allocator, exception); } pub fn fromJSWithAllocator(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, allocator: std.mem.Allocator, exception: JSC.C.ExceptionRef) ?PathLike { const arg = arguments.next() orelse return null; @@ -801,11 +902,7 @@ pub const Valid = struct { pub fn pathSlice(zig_str: JSC.ZigString.Slice, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) bool { switch (zig_str.len) { - 0 => { - JSC.throwInvalidArguments("Invalid path string: can't be empty", .{}, ctx, exception); - return false; - }, - 1...bun.MAX_PATH_BYTES => return true, + 0...bun.MAX_PATH_BYTES => return true, else => { // TODO: should this be an EINVAL? JSC.throwInvalidArguments( @@ -823,11 +920,7 @@ pub const Valid = struct { pub fn pathStringLength(len: usize, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) bool { switch (len) { - 0 => { - JSC.throwInvalidArguments("Invalid path string: can't be empty", .{}, ctx, exception); - return false; - }, - 1...bun.MAX_PATH_BYTES => return true, + 0...bun.MAX_PATH_BYTES => return true, else => { // TODO: should this be an EINVAL? JSC.throwInvalidArguments( @@ -2120,6 +2213,8 @@ pub const Path = struct { 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); + defer arena.deinit(); + var arena_allocator = arena.allocator(); var stack_fallback_allocator = std.heap.stackFallback( ((32 * @sizeOf(string)) + 1024), @@ -2127,18 +2222,27 @@ pub const Path = struct { ); var allocator = stack_fallback_allocator.get(); - defer arena.deinit(); var buf: [bun.MAX_PATH_BYTES]u8 = undefined; + var count: usize = 0; var to_join = allocator.alloc(string, args_len) catch unreachable; for (args_ptr[0..args_len], 0..) |arg, i| { const zig_str: JSC.ZigString = arg.getZigString(globalThis); to_join[i] = zig_str.toSlice(allocator).slice(); + count += to_join[i].len; + } + + var buf_to_use: []u8 = &buf; + if (count * 2 >= buf.len) { + buf_to_use = allocator.alloc(u8, count * 2) catch { + globalThis.throwOutOfMemory(); + return .zero; + }; } const out = if (!isWindows) - PathHandler.joinStringBuf(&buf, to_join, .posix) + PathHandler.joinStringBuf(buf_to_use, to_join, .posix) else - PathHandler.joinStringBuf(&buf, to_join, .windows); + PathHandler.joinStringBuf(buf_to_use, to_join, .windows); var str = bun.String.create(out); defer str.deref(); diff --git a/src/bun.js/rare_data.zig b/src/bun.js/rare_data.zig index 44e482049..c9d742d96 100644 --- a/src/bun.js/rare_data.zig +++ b/src/bun.js/rare_data.zig @@ -39,6 +39,32 @@ mime_types: ?bun.HTTP.MimeType.Map = null, node_fs_stat_watcher_scheduler: ?*StatWatcherScheduler = null, +listening_sockets_for_watch_mode: std.ArrayListUnmanaged(bun.FileDescriptor) = .{}, +listening_sockets_for_watch_mode_lock: bun.Lock = bun.Lock.init(), + +pub fn addListeningSocketForWatchMode(this: *RareData, socket: bun.FileDescriptor) void { + this.listening_sockets_for_watch_mode_lock.lock(); + defer this.listening_sockets_for_watch_mode_lock.unlock(); + this.listening_sockets_for_watch_mode.append(bun.default_allocator, socket) catch {}; +} + +pub fn removeListeningSocketForWatchMode(this: *RareData, socket: bun.FileDescriptor) void { + this.listening_sockets_for_watch_mode_lock.lock(); + defer this.listening_sockets_for_watch_mode_lock.unlock(); + if (std.mem.indexOfScalar(bun.FileDescriptor, this.listening_sockets_for_watch_mode.items, socket)) |i| { + _ = this.listening_sockets_for_watch_mode.swapRemove(i); + } +} + +pub fn closeAllListenSocketsForWatchMode(this: *RareData) void { + this.listening_sockets_for_watch_mode_lock.lock(); + defer this.listening_sockets_for_watch_mode_lock.unlock(); + for (this.listening_sockets_for_watch_mode.items) |socket| { + _ = Syscall.close(socket); + } + this.listening_sockets_for_watch_mode = .{}; +} + pub fn hotMap(this: *RareData, allocator: std.mem.Allocator) *HotMap { if (this.hot_map == null) { this.hot_map = HotMap.init(allocator); diff --git a/src/bun.js/scripts/create_hash_table b/src/bun.js/scripts/create_hash_table index e2645b429..bd604ceaa 100755 --- a/src/bun.js/scripts/create_hash_table +++ b/src/bun.js/scripts/create_hash_table @@ -5,7 +5,7 @@ # (c) 2000-2002 by Harri Porten <porten@kde.org> and # David Faure <faure@kde.org> # Modified (c) 2004 by Nikolas Zimmermann <wildfox@kde.org> -# Copyright (C) 2007-2022 Apple Inc. All rights reserved. +# Copyright (C) 2007-2023 Apple Inc. All rights reserved. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -24,6 +24,7 @@ use strict; use warnings; +use Math::BigInt; use Getopt::Long qw(:config pass_through); my $file = shift @ARGV or die("Must provide source file as final argument."); @@ -33,7 +34,6 @@ open(IN, $file) or die "No such file $file"; my @keys = (); my @attrs = (); my @values = (); -my @hashes = (); my @table = (); my @links = (); @@ -46,11 +46,13 @@ my $pefectHashSize; my $compactSize; my $compactHashSizeMask; my $banner = 0; -sub calcPerfectHashSize(); -sub calcCompactHashSize(); +my $mask64 = 2**64 - 1; +my $mask32 = 2**32 - 1; +sub calcPerfectHashSize($); +sub calcCompactHashSize($); sub output(); sub jsc_ucfirst($); -sub hashValue($); +sub hashValue($$); while (<IN>) { chomp; @@ -64,16 +66,11 @@ while (<IN>) { print STDERR "WARNING: \@begin without table name, skipping $_\n"; } } elsif (/^\@end\s*$/ && $inside) { - calcPerfectHashSize(); - calcCompactHashSize(); output(); @keys = (); @attrs = (); @values = (); - @hashes = (); - @table = (); - @links = (); $includeBuiltin = 0; $inside = 0; @@ -114,7 +111,6 @@ while (<IN>) { } else { push(@values, { "type" => "Lexer", "value" => $val }); } - push(@hashes, hashValue($key)); } elsif ($inside) { die "invalid data {" . $_ . "}"; } @@ -147,13 +143,14 @@ sub ceilingToPowerOf2 return $powerOf2; } -sub calcPerfectHashSize() +sub calcPerfectHashSize($) { + my ($isMac) = @_; tableSizeLoop: for ($pefectHashSize = ceilingToPowerOf2(scalar @keys); ; $pefectHashSize += $pefectHashSize) { my @table = (); foreach my $key (@keys) { - my $h = hashValue($key) % $pefectHashSize; + my $h = hashValue($key, $isMac) % $pefectHashSize; next tableSizeLoop if $table[$h]; $table[$h] = 1; } @@ -166,8 +163,9 @@ sub leftShift($$) { return (($value << $distance) & 0xFFFFFFFF); } -sub calcCompactHashSize() +sub calcCompactHashSize($) { + my ($isMac) = @_; my $compactHashSize = ceilingToPowerOf2(2 * @keys); $compactHashSizeMask = $compactHashSize - 1; $compactSize = $compactHashSize; @@ -176,7 +174,7 @@ sub calcCompactHashSize() my $i = 0; foreach my $key (@keys) { my $depth = 0; - my $h = hashValue($key) % $compactHashSize; + my $h = hashValue($key, $isMac) % $compactHashSize; while (defined($table[$h])) { if (defined($links[$h])) { $h = $links[$h]; @@ -194,60 +192,222 @@ sub calcCompactHashSize() } } +sub avalancheBits($) { + my ($value) = @_; + + $value &= $mask32; + + # Force "avalanching" of lower 32 bits + $value ^= leftShift($value, 3); + $value += ($value >> 5); + $value = ($value & $mask32); + $value ^= (leftShift($value, 2) & $mask32); + $value += ($value >> 15); + $value = $value & $mask32; + $value ^= (leftShift($value, 10) & $mask32); + + return $value; +} + +sub maskTop8BitsAndAvoidZero($) { + my ($value) = @_; + + $value &= $mask32; + + # Save 8 bits for StringImpl to use as flags. + $value &= 0xffffff; + + # This avoids ever returning a hash code of 0, since that is used to + # signal "hash not computed yet". Setting the high bit maintains + # reasonable fidelity to a hash code of 0 because it is likely to yield + # exactly 0 when hash lookup masks out the high bits. + $value = (0x80000000 >> 8) if ($value == 0); + + return $value; +} + # Paul Hsieh's SuperFastHash # http://www.azillionmonkeys.com/qed/hash.html -sub hashValue($) { - my @chars = split(/ */, $_[0]); - - # This hash is designed to work on 16-bit chunks at a time. But since the normal case - # (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they - # were 16-bit chunks, which should give matching results - - my $EXP2_32 = 4294967296; - - my $hash = 0x9e3779b9; - my $l = scalar @chars; #I wish this was in Ruby --- Maks - my $rem = $l & 1; - $l = $l >> 1; - - my $s = 0; - - # Main loop - for (; $l > 0; $l--) { - $hash += ord($chars[$s]); - my $tmp = leftShift(ord($chars[$s+1]), 11) ^ $hash; - $hash = (leftShift($hash, 16)% $EXP2_32) ^ $tmp; - $s += 2; - $hash += $hash >> 11; - $hash %= $EXP2_32; - } - - # Handle end case - if ($rem != 0) { - $hash += ord($chars[$s]); - $hash ^= (leftShift($hash, 11)% $EXP2_32); - $hash += $hash >> 17; - } - - # Force "avalanching" of final 127 bits - $hash ^= leftShift($hash, 3); - $hash += ($hash >> 5); - $hash = ($hash% $EXP2_32); - $hash ^= (leftShift($hash, 2)% $EXP2_32); - $hash += ($hash >> 15); - $hash = $hash% $EXP2_32; - $hash ^= (leftShift($hash, 10)% $EXP2_32); - - # Save 8 bits for StringImpl to use as flags. - $hash &= 0xffffff; - - # This avoids ever returning a hash code of 0, since that is used to - # signal "hash not computed yet". Setting the high bit maintains - # reasonable fidelity to a hash code of 0 because it is likely to yield - # exactly 0 when hash lookup masks out the high bits. - $hash = (0x80000000 >> 8) if ($hash == 0); - - return $hash; +sub superFastHash { + my @chars = @_; + + # This hash is designed to work on 16-bit chunks at a time. But since the normal case + # (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they + # were 16-bit chunks, which should give matching results + + my $hash = 0x9e3779b9; + my $l = scalar @chars; #I wish this was in Ruby --- Maks + my $rem = $l & 1; + $l = $l >> 1; + + my $s = 0; + + # Main loop + for (; $l > 0; $l--) { + $hash += ord($chars[$s]); + my $tmp = leftShift(ord($chars[$s+1]), 11) ^ $hash; + $hash = (leftShift($hash, 16) & $mask32) ^ $tmp; + $s += 2; + $hash += $hash >> 11; + $hash &= $mask32; + } + + # Handle end case + if ($rem != 0) { + $hash += ord($chars[$s]); + $hash ^= (leftShift($hash, 11) & $mask32); + $hash += $hash >> 17; + } + + $hash = avalancheBits($hash); + return maskTop8BitsAndAvoidZero($hash); +} + +sub uint64_add($$) { + my ($a, $b) = @_; + my $sum = $a + $b; + return $sum & $mask64; +} + +sub uint64_multi($$) { + my ($a, $b) = @_; + my $product = $a * $b; + return $product & $mask64; +} + +sub wymum($$) { + my ($A, $B) = @_; + + my $ha = $A >> 32; + my $hb = $B >> 32; + my $la = $A & $mask32; + my $lb = $B & $mask32; + my $hi; + my $lo; + my $rh = uint64_multi($ha, $hb); + my $rm0 = uint64_multi($ha, $lb); + my $rm1 = uint64_multi($hb, $la); + my $rl = uint64_multi($la, $lb); + my $t = uint64_add($rl, ($rm0 << 32)); + my $c = int($t < $rl); + + $lo = uint64_add($t, ($rm1 << 32)); + $c += int($lo < $t); + $hi = uint64_add($rh, uint64_add(($rm0 >> 32), uint64_add(($rm1 >> 32), $c))); + + return ($lo, $hi); +}; + +sub wymix($$) { + my ($A, $B) = @_; + ($A, $B) = wymum($A, $B); + return $A ^ $B; +} + +sub convert32BitTo64Bit($) { + my ($v) = @_; + my ($mask1) = 281470681808895; # 0x0000_ffff_0000_ffff + $v = ($v | ($v << 16)) & $mask1; + my ($mask2) = 71777214294589695; # 0x00ff_00ff_00ff_00ff + return ($v | ($v << 8)) & $mask2; +} + +sub convert16BitTo32Bit($) { + my ($v) = @_; + return ($v | ($v << 8)) & 0x00ff_00ff; +} + +sub wyhash { + # https://github.com/wangyi-fudan/wyhash + my @chars = @_; + my $charCount = scalar @chars; + my $byteCount = $charCount << 1; + my $charIndex = 0; + my $seed = 0; + my @secret = ( 11562461410679940143, 16646288086500911323, 10285213230658275043, 6384245875588680899 ); + my $move1 = (($byteCount >> 3) << 2) >> 1; + + $seed ^= wymix($seed ^ $secret[0], $secret[1]); + my $a = 0; + my $b = 0; + + local *c2i = sub { + my ($i) = @_; + return ord($chars[$i]); + }; + + local *wyr8 = sub { + my ($i) = @_; + my $v = c2i($i) | (c2i($i + 1) << 8) | (c2i($i + 2) << 16) | (c2i($i + 3) << 24); + return convert32BitTo64Bit($v); + }; + + local *wyr4 = sub { + my ($i) = @_; + my $v = c2i($i) | (c2i($i + 1) << 8); + return convert16BitTo32Bit($v); + }; + + local *wyr2 = sub { + my ($i) = @_; + return c2i($i) << 16; + }; + + if ($byteCount <= 16) { + if ($byteCount >= 4) { + $a = (wyr4($charIndex) << 32) | wyr4($charIndex + $move1); + $charIndex = $charIndex + $charCount - 2; + $b = (wyr4($charIndex) << 32) | wyr4($charIndex - $move1); + } elsif ($byteCount > 0) { + $a = wyr2($charIndex); + $b = 0; + } else { + $a = $b = 0; + } + } else { + my $i = $byteCount; + if ($i > 48) { + my $see1 = $seed; + my $see2 = $seed; + do { + $seed = wymix(wyr8($charIndex) ^ $secret[1], wyr8($charIndex + 4) ^ $seed); + $see1 = wymix(wyr8($charIndex + 8) ^ $secret[2], wyr8($charIndex + 12) ^ $see1); + $see2 = wymix(wyr8($charIndex + 16) ^ $secret[3], wyr8($charIndex + 20) ^ $see2); + $charIndex += 24; + $i -= 48; + } while ($i > 48); + $seed ^= $see1 ^ $see2; + } + while ($i > 16) { + $seed = wymix(wyr8($charIndex) ^ $secret[1], wyr8($charIndex + 4) ^ $seed); + $i -= 16; + $charIndex += 8; + } + my $move2 = $i >> 1; + $a = wyr8($charIndex + $move2 - 8); + $b = wyr8($charIndex + $move2 - 4); + } + $a ^= $secret[1]; + $b ^= $seed; + + ($a, $b) = wymum($a, $b); + my $hash = wymix($a ^ $secret[0] ^ $byteCount, $b ^ $secret[1]) & $mask32; + + return maskTop8BitsAndAvoidZero($hash); +} + +sub hashValue($$) { + my ($string, $isMac) = @_; + my @chars = split(/ */, $string); + my $charCount = scalar @chars; + if ($isMac) { + if ($charCount <= 48) { + return superFastHash(@chars); + } + return wyhash(@chars); + } else { + return superFastHash(@chars); + } } sub output() { @@ -267,81 +427,110 @@ sub output() { print "\n"; print "namespace JSC {\n"; print "\n"; - if ($compactSize != 0) { - print "static const struct CompactHashIndex ${nameIndex}\[$compactSize\] = {\n"; - for (my $i = 0; $i < $compactSize; $i++) { - my $T = -1; - if (defined($table[$i])) { $T = $table[$i]; } - my $L = -1; - if (defined($links[$i])) { $L = $links[$i]; } - print " { $T, $L },\n"; + + local *generateHashTableHelper = sub { + my ($isMac, $setToOldValues) = @_; + my $oldCompactSize = $compactSize; + my $oldCompactHashSizeMask = $compactHashSizeMask; + calcPerfectHashSize($isMac); + calcCompactHashSize($isMac); + + my $hashTableString = ""; + + if ($compactSize != 0) { + $hashTableString .= "static const struct CompactHashIndex ${nameIndex}\[$compactSize\] = {\n"; + for (my $i = 0; $i < $compactSize; $i++) { + my $T = -1; + if (defined($table[$i])) { $T = $table[$i]; } + my $L = -1; + if (defined($links[$i])) { $L = $links[$i]; } + $hashTableString .= " { $T, $L },\n"; + } + } else { + # MSVC dislikes empty arrays. + $hashTableString .= "static const struct CompactHashIndex ${nameIndex}\[1\] = {\n"; + $hashTableString .= " { 0, 0 }\n"; } - } else { - # MSVC dislikes empty arrays. - print "static const struct CompactHashIndex ${nameIndex}\[1\] = {\n"; - print " { 0, 0 }\n"; - } - print "};\n"; - print "\n"; + $hashTableString .= "};\n"; + $hashTableString .= "\n"; - my $packedSize = scalar @keys; - if ($packedSize != 0) { - print "static const struct HashTableValue ${nameEntries}\[$packedSize\] = {\n"; - } else { - # MSVC dislikes empty arrays. - print "static const struct HashTableValue ${nameEntries}\[1\] = {\n"; - print " { { }, 0, NoIntrinsic, { HashTableValue::End } }\n"; - } - my $i = 0; - foreach my $key (@keys) { - my $typeTag = ""; - my $firstValue = ""; - my $secondValue = ""; - my $hasSecondValue = 1; - my $intrinsic = "NoIntrinsic"; - - if ($values[$i]{"type"} eq "PropertyAttribute::Function") { - $typeTag = "NativeFunction"; - $firstValue = $values[$i]{"function"}; - $secondValue = $values[$i]{"params"}; - $intrinsic = $values[$i]{"intrinsic"}; - } elsif ($values[$i]{"type"} eq "PropertyAttribute::Property") { - $typeTag = "GetterSetter"; - $firstValue = $values[$i]{"get"}; - $secondValue = $values[$i]{"put"}; - } elsif ($values[$i]{"type"} eq "Lexer") { - $typeTag = "Lexer"; - $firstValue = $values[$i]{"value"}; - $hasSecondValue = 0; - } elsif ($values[$i]{"type"} eq "PropertyAttribute::CellProperty" || $values[$i]{"type"} eq "PropertyAttribute::ClassStructure") { - $typeTag = ($values[$i]{"type"} eq "PropertyAttribute::CellProperty") ? "LazyCellProperty" : "LazyClassStructure"; - $values[$i]{"property"} =~ /\A([a-zA-Z0-9_]+)::(.*)\Z/ or die; - $firstValue = "OBJECT_OFFSETOF($1, $2)"; - $hasSecondValue = 0; - } elsif ($values[$i]{"type"} eq "PropertyAttribute::PropertyCallback") { - $typeTag = "LazyProperty"; - $firstValue = $values[$i]{"cback"}; - $hasSecondValue = 0; + my $packedSize = scalar @keys; + if ($packedSize != 0) { + $hashTableString .= "static const struct HashTableValue ${nameEntries}\[$packedSize\] = {\n"; + } else { + # MSVC dislikes empty arrays. + $hashTableString .= "static const struct HashTableValue ${nameEntries}\[1\] = {\n"; + $hashTableString .= " { { }, 0, NoIntrinsic, { HashTableValue::End } }\n"; } - my $attributes = "PropertyAttribute::" . $attrs[$i]; - $attributes =~ s/\|/\|PropertyAttribute::/g; - $attributes = "static_cast<unsigned>(" . $attributes . ")"; - if ($values[$i]{"type"} eq "PropertyAttribute::Function" && $firstValue eq "JSBuiltin") { - $typeTag = "BuiltinGenerator"; - my $tableHead = $name; - $tableHead =~ s/Table$//; - print " { \"$key\"_s, (($attributes) & ~PropertyAttribute::Function) | PropertyAttribute::Builtin, $intrinsic, { HashTableValue::" . $typeTag . "Type, " . $tableHead . ucfirst($key) . "CodeGenerator, $secondValue } },\n"; + my $i = 0; + foreach my $key (@keys) { + my $typeTag = ""; + my $firstValue = ""; + my $secondValue = ""; + my $hasSecondValue = 1; + my $intrinsic = "NoIntrinsic"; + + if ($values[$i]{"type"} eq "PropertyAttribute::Function") { + $typeTag = "NativeFunction"; + $firstValue = $values[$i]{"function"}; + $secondValue = $values[$i]{"params"}; + $intrinsic = $values[$i]{"intrinsic"}; + } elsif ($values[$i]{"type"} eq "PropertyAttribute::Property") { + $typeTag = "GetterSetter"; + $firstValue = $values[$i]{"get"}; + $secondValue = $values[$i]{"put"}; + } elsif ($values[$i]{"type"} eq "Lexer") { + $typeTag = "Lexer"; + $firstValue = $values[$i]{"value"}; + $hasSecondValue = 0; + } elsif ($values[$i]{"type"} eq "PropertyAttribute::CellProperty" || $values[$i]{"type"} eq "PropertyAttribute::ClassStructure") { + $typeTag = ($values[$i]{"type"} eq "PropertyAttribute::CellProperty") ? "LazyCellProperty" : "LazyClassStructure"; + $values[$i]{"property"} =~ /\A([a-zA-Z0-9_]+)::(.*)\Z/ or die; + $firstValue = "OBJECT_OFFSETOF($1, $2)"; + $hasSecondValue = 0; + } elsif ($values[$i]{"type"} eq "PropertyAttribute::PropertyCallback") { + $typeTag = "LazyProperty"; + $firstValue = $values[$i]{"cback"}; + $hasSecondValue = 0; + } + + my $attributes = "PropertyAttribute::" . $attrs[$i]; + $attributes =~ s/\|/\|PropertyAttribute::/g; + $attributes = "static_cast<unsigned>(" . $attributes . ")"; + if ($values[$i]{"type"} eq "PropertyAttribute::Function" && $firstValue eq "JSBuiltin") { + $typeTag = "BuiltinGenerator"; + my $tableHead = $name; + $tableHead =~ s/Table$//; + $hashTableString .= " { \"$key\"_s, (($attributes) & ~PropertyAttribute::Function) | PropertyAttribute::Builtin, $intrinsic, { HashTableValue::" . $typeTag . "Type, " . $tableHead . ucfirst($key) . "CodeGenerator, $secondValue } },\n"; + } + else { + $hashTableString .= " { \"$key\"_s, $attributes, $intrinsic, { HashTableValue::" . $typeTag . "Type, $firstValue" . ($hasSecondValue ? ", " . $secondValue : "") . " } },\n"; + } + $i++; } - else { - print " { \"$key\"_s, $attributes, $intrinsic, { HashTableValue::" . $typeTag . "Type, $firstValue" . ($hasSecondValue ? ", " . $secondValue : "") . " } },\n"; + $hashTableString .= "};\n"; + $hashTableString .= "\n"; + $hashTableString .= "static const struct HashTable $name =\n"; + $hashTableString .= " \{ $packedSize, $compactHashSizeMask, $hasSetter, nullptr, $nameEntries, $nameIndex \};\n"; + $hashTableString .= "\n"; + + @table = (); + @links = (); + if ($setToOldValues) { + $compactSize = $oldCompactSize; + $compactHashSizeMask = $oldCompactHashSizeMask; } - $i++; + return $hashTableString; + }; + + my $hashTableForMacOS = generateHashTableHelper(1, 1); + my $hashTableForIOS = generateHashTableHelper(0, 0); + my $hashTableToWrite = $hashTableForMacOS; + if ($hashTableForMacOS ne $hashTableForIOS) { + $hashTableToWrite = "#if PLATFORM(MAC)\n" . $hashTableForMacOS . "#else\n" . $hashTableForIOS . "#endif\n"; } - print "};\n"; - print "\n"; - print "static const struct HashTable $name =\n"; - print " \{ $packedSize, $compactHashSizeMask, $hasSetter, nullptr, $nameEntries, $nameIndex \};\n"; - print "\n"; + print $hashTableToWrite; + print "} // namespace JSC\n"; } diff --git a/src/bun.js/scripts/generate-classes.ts b/src/bun.js/scripts/generate-classes.ts index b6fbe0915..ae28f4fe5 100644 --- a/src/bun.js/scripts/generate-classes.ts +++ b/src/bun.js/scripts/generate-classes.ts @@ -335,7 +335,7 @@ function generatePrototype(typeName, obj) { this->putDirect(vm, vm.propertyNames->${symbol}Symbol, JSFunction::create(vm, globalObject, 1, String("${symbol}"_s), ${protoSymbolName( typeName, symbol, - )}Callback, ImplementationVisibility::Public), PropertyAttribute::Function | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | 0);`; + )}Callback, ImplementationVisibility::Public), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | 0);`; } return ` @@ -420,6 +420,7 @@ function generatePrototypeHeader(typename) { template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(${proto}, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -555,7 +556,7 @@ JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES ${name}::construct(JSC::JSGlobalObj ${className(typeName)}* instance = ${className(typeName)}::create(vm, globalObject, structure, ptr); ${ obj.estimatedSize - ? `vm.heap.reportExtraMemoryAllocated(${symbolName(obj.name, "estimatedSize")}(instance->wrapped()));` + ? `vm.heap.reportExtraMemoryAllocated(instance, ${symbolName(obj.name, "estimatedSize")}(instance->wrapped()));` : "" } @@ -1208,7 +1209,11 @@ extern "C" EncodedJSValue ${typeName}__create(Zig::GlobalObject* globalObject, v auto &vm = globalObject->vm(); JSC::Structure* structure = globalObject->${className(typeName)}Structure(); ${className(typeName)}* instance = ${className(typeName)}::create(vm, globalObject, structure, ptr); - ${obj.estimatedSize ? `vm.heap.reportExtraMemoryAllocated(${symbolName(obj.name, "estimatedSize")}(ptr));` : ""} + ${ + obj.estimatedSize + ? `vm.heap.reportExtraMemoryAllocated(instance, ${symbolName(obj.name, "estimatedSize")}(ptr));` + : "" + } return JSValue::encode(instance); } @@ -1556,43 +1561,19 @@ ${[...exports] function generateLazyClassStructureHeader(typeName, { klass = {}, proto = {} }) { return ` - JSC::Structure* ${className(typeName)}Structure() { return m_${className( + JSC::Structure* ${className(typeName)}Structure() { return m_${className( typeName, )}.getInitializedOnMainThread(this); } - JSC::JSObject* ${className(typeName)}Constructor() { return m_${className( + JSC::JSObject* ${className(typeName)}Constructor() { return m_${className( typeName, )}.constructorInitializedOnMainThread(this); } - JSC::JSValue ${className(typeName)}Prototype() { return m_${className( + JSC::JSValue ${className(typeName)}Prototype() { return m_${className( typeName, )}.prototypeInitializedOnMainThread(this); } JSC::LazyClassStructure m_${className(typeName)}; - bool has${className(typeName)}SetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_${className(typeName)}SetterValue; - `.trim(); -} - -function generateLazyStructureHeader(typeName, { klass = {}, proto = {} }) { - return ` - JSC::Structure* ${className(typeName)}Structure() { return m_${className(typeName)}.get(this); } - JSC::LazyProperty<Zig::GlobalObject, Structure> m_${className(typeName)}; - bool has${className(typeName)}SetterValue { false }; - mutable JSC::WriteBarrier<JSC::Unknown> m_${className(typeName)}SetterValue; `.trim(); } -function generateLazyStructureImpl(typeName, { klass = {}, proto = {} }) { - return ` - m_${className(typeName)}.initLater( - [](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSObject>::Initializer& init) { - auto *prototype = WebCore::${className( - typeName, - )}::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.owner)); - init.set(WebCore::${className(typeName)}::createStructure(init.vm, init.owner, prototype)); - }); - - `.trim(); -} - function generateLazyClassStructureImpl(typeName, { klass = {}, proto = {}, noConstructor = false }) { return ` m_${className(typeName)}.initLater( @@ -1685,7 +1666,7 @@ const GENERATED_CLASSES_IMPL_FOOTER = ` function initLazyClasses(initLaterFunctions) { return ` -void GlobalObject::initGeneratedLazyClasses() { +ALWAYS_INLINE void GlobalObject::initGeneratedLazyClasses() { ${initLaterFunctions.map(a => a.trim()).join("\n ")} } @@ -1698,14 +1679,7 @@ function visitLazyClasses(classes) { template<typename Visitor> void GlobalObject::visitGeneratedLazyClasses(GlobalObject *thisObject, Visitor& visitor) { - ${classes - .map( - a => - `thisObject->m_${className(a.name)}.visit(visitor); visitor.append(thisObject->m_${className( - a.name, - )}SetterValue);`, - ) - .join("\n ")} + ${classes.map(a => `thisObject->m_${className(a.name)}.visit(visitor);`).join("\n ")} } `.trim(); diff --git a/src/bun.js/scripts/generate-jssink.js b/src/bun.js/scripts/generate-jssink.js index ef60efbba..758b1863b 100644 --- a/src/bun.js/scripts/generate-jssink.js +++ b/src/bun.js/scripts/generate-jssink.js @@ -548,6 +548,7 @@ public: template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(${prototypeName}, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -580,6 +581,7 @@ class ${controllerPrototypeName} final : public JSC::JSNonFinalObject { template<typename CellType, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(${controllerPrototypeName}, Base); return &vm.plainObjectSpace(); } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -636,17 +638,19 @@ void JS${controllerName}::detach() { auto readableStream = m_weakReadableStream.get(); auto onClose = m_onClose.get(); - m_onClose.clear(); if (readableStream && onClose) { - JSC::JSGlobalObject *globalObject = this->globalObject(); auto callData = JSC::getCallData(onClose); - JSC::MarkedArgumentBuffer arguments; - arguments.append(readableStream); - arguments.append(jsUndefined()); - call(globalObject, onClose, callData, JSC::jsUndefined(), arguments); + if(callData.type != JSC::CallData::Type::None) { + JSC::JSGlobalObject *globalObject = this->globalObject(); + JSC::MarkedArgumentBuffer arguments; + arguments.append(readableStream); + arguments.append(jsUndefined()); + call(globalObject, onClose, callData, JSC::jsUndefined(), arguments); + } } - + + m_onClose.clear(); m_weakReadableStream.clear(); } `; diff --git a/src/bun.js/test/expect.zig b/src/bun.js/test/expect.zig index 0d3ff663e..f83a9b194 100644 --- a/src/bun.js/test/expect.zig +++ b/src/bun.js/test/expect.zig @@ -1518,7 +1518,7 @@ pub const Expect = struct { } const expected_diff = std.math.pow(f64, 10, -precision) / 2; - const actual_diff = std.math.fabs(received - expected); + const actual_diff = @abs(received - expected); var pass = actual_diff < expected_diff; const not = this.flags.not; @@ -1697,7 +1697,7 @@ pub const Expect = struct { const result: JSValue = result_.?; var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject, .quote_strings = true }; - if (expected_value.isEmpty()) { + if (expected_value.isEmpty() or expected_value.isUndefined()) { const signature_no_args = comptime getSignature("toThrow", "", true); if (result.toError()) |err| { const name = err.get(globalObject, "name") orelse JSValue.undefined; @@ -1780,7 +1780,7 @@ pub const Expect = struct { const signature = comptime getSignature("toThrow", "<green>expected<r>", false); if (did_throw) { - if (expected_value.isEmpty()) return thisValue; + if (expected_value.isEmpty() or expected_value.isUndefined()) return thisValue; const result: JSValue = if (result_.?.toError()) |r| r @@ -1915,7 +1915,7 @@ pub const Expect = struct { var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalObject, .quote_strings = true }; const received_line = "Received function did not throw\n"; - if (expected_value.isEmpty()) { + if (expected_value.isEmpty() or expected_value.isUndefined()) { const fmt = comptime getSignature("toThrow", "", false) ++ "\n\n" ++ received_line; if (Output.enable_ansi_colors) { globalObject.throw(Output.prettyFmt(fmt, true), .{}); @@ -2649,6 +2649,83 @@ pub const Expect = struct { return .zero; } + pub fn toEqualIgnoringWhitespace(this: *Expect, globalThis: *JSGlobalObject, callFrame: *CallFrame) callconv(.C) JSValue { + defer this.postMatch(globalThis); + + const thisValue = callFrame.this(); + const _arguments = callFrame.arguments(1); + const arguments: []const JSValue = _arguments.ptr[0.._arguments.len]; + + if (arguments.len < 1) { + globalThis.throwInvalidArguments("toEqualIgnoringWhitespace() requires 1 argument", .{}); + return .zero; + } + + active_test_expectation_counter.actual += 1; + + const expected = arguments[0]; + const value: JSValue = this.getValue(globalThis, thisValue, "toEqualIgnoringWhitespace", "<green>expected<r>") orelse return .zero; + + if (!expected.isString()) { + globalThis.throw("toEqualIgnoringWhitespace() requires argument to be a string", .{}); + return .zero; + } + + const not = this.flags.not; + var pass = value.isString() and expected.isString(); + + if (pass) { + var valueStr = value.toString(globalThis).toSlice(globalThis, default_allocator).slice(); + var expectedStr = expected.toString(globalThis).toSlice(globalThis, default_allocator).slice(); + + var left: usize = 0; + var right: usize = 0; + + // Skip leading whitespaces + while (left < valueStr.len and std.ascii.isWhitespace(valueStr[left])) left += 1; + while (right < expectedStr.len and std.ascii.isWhitespace(expectedStr[right])) right += 1; + + while (left < valueStr.len and right < expectedStr.len) { + const left_char = valueStr[left]; + const right_char = expectedStr[right]; + + if (left_char != right_char) { + pass = false; + break; + } + + left += 1; + right += 1; + + // Skip trailing whitespaces + while (left < valueStr.len and std.ascii.isWhitespace(valueStr[left])) left += 1; + while (right < expectedStr.len and std.ascii.isWhitespace(expectedStr[right])) right += 1; + } + + if (left < valueStr.len or right < expectedStr.len) { + pass = false; + } + } + + if (not) pass = !pass; + if (pass) return thisValue; + + // handle failure + var formatter = JSC.ZigConsoleClient.Formatter{ .globalThis = globalThis, .quote_strings = true }; + const expected_fmt = expected.toFmt(globalThis, &formatter); + const value_fmt = value.toFmt(globalThis, &formatter); + + if (not) { + const fmt = comptime getSignature("toEqualIgnoringWhitespace", "<green>expected<r>", true) ++ "\n\n" ++ "Expected: not <green>{any}<r>\n" ++ "Received: <red>{any}<r>\n"; + globalThis.throwPretty(fmt, .{ expected_fmt, value_fmt }); + return .zero; + } + + const fmt = comptime getSignature("toEqualIgnoringWhitespace", "<green>expected<r>", false) ++ "\n\n" ++ "Expected: <green>{any}<r>\n" ++ "Received: <red>{any}<r>\n"; + globalThis.throwPretty(fmt, .{ expected_fmt, value_fmt }); + return .zero; + } + pub fn toBeSymbol(this: *Expect, globalThis: *JSGlobalObject, callFrame: *CallFrame) callconv(.C) JSValue { defer this.postMatch(globalThis); @@ -3271,7 +3348,7 @@ pub const Expect = struct { globalObject.throw(Output.prettyFmt(fmt, false), .{calls.toFmt(globalObject, &formatter)}); return .zero; } else { - const signature = comptime getSignature("toHaveBeenCalled", "", true); + const signature = comptime getSignature("toHaveBeenCalled", "", false); const fmt = signature ++ "\n\nExpected <green>{any}<r>\n"; if (Output.enable_ansi_colors) { globalObject.throw(Output.prettyFmt(fmt, true), .{calls.toFmt(globalObject, &formatter)}); @@ -3326,7 +3403,7 @@ pub const Expect = struct { globalObject.throw(Output.prettyFmt(fmt, false), .{calls.toFmt(globalObject, &formatter)}); return .zero; } else { - const signature = comptime getSignature("toHaveBeenCalledTimes", "<green>expected<r>", true); + const signature = comptime getSignature("toHaveBeenCalledTimes", "<green>expected<r>", false); const fmt = signature ++ "\n\nExpected <green>{any}<r>\n"; if (Output.enable_ansi_colors) { globalObject.throw(Output.prettyFmt(fmt, true), .{calls.toFmt(globalObject, &formatter)}); @@ -3437,8 +3514,11 @@ pub const Expect = struct { return ExpectStringMatching.call(globalObject, callFrame); } + pub fn arrayContaining(globalObject: *JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSValue { + return ExpectArrayContaining.call(globalObject, callFrame); + } + pub const extend = notImplementedStaticFn; - pub const arrayContaining = notImplementedStaticFn; pub const assertions = notImplementedStaticFn; pub const hasAssertions = notImplementedStaticFn; pub const objectContaining = notImplementedStaticFn; @@ -3621,6 +3701,43 @@ pub const ExpectAny = struct { } }; +pub const ExpectArrayContaining = struct { + pub usingnamespace JSC.Codegen.JSExpectArrayContaining; + + pub fn finalize( + this: *ExpectArrayContaining, + ) callconv(.C) void { + VirtualMachine.get().allocator.destroy(this); + } + + pub fn call(globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSValue { + const args = callFrame.arguments(1).slice(); + + if (args.len == 0 or !args[0].jsType().isArray()) { + const fmt = "<d>expect.<r>arrayContaining<d>(<r>array<d>)<r>\n\nExpected a array\n"; + globalObject.throwPretty(fmt, .{}); + return .zero; + } + + const array_value = args[0]; + const array_containing = globalObject.bunVM().allocator.create(ExpectArrayContaining) catch unreachable; + + if (Jest.runner.?.pending_test == null) { + const err = globalObject.createErrorInstance("expect.arrayContaining() must be called in a test", .{}); + err.put(globalObject, ZigString.static("name"), ZigString.init("TestNotRunningError").toValueGC(globalObject)); + globalObject.throwValue(err); + return .zero; + } + + const array_containing_js_value = array_containing.toJS(globalObject); + ExpectArrayContaining.arrayValueSetCached(array_containing_js_value, globalObject, array_value); + + var vm = globalObject.bunVM(); + vm.autoGarbageCollect(); + return array_containing_js_value; + } +}; + /// JSValue.zero is used to indicate it was not a JSMockFunction /// If there were no calls, it returns an empty JSArray* extern fn JSMockFunction__getCalls(JSValue) JSValue; diff --git a/src/bun.js/test/jest.classes.ts b/src/bun.js/test/jest.classes.ts index d40acbf07..f10d9fb37 100644 --- a/src/bun.js/test/jest.classes.ts +++ b/src/bun.js/test/jest.classes.ts @@ -49,6 +49,18 @@ export default [ proto: {}, }), define({ + name: "ExpectArrayContaining", + construct: false, + noConstructor: true, + call: true, + finalize: true, + JSType: "0b11101110", + values: ["arrayValue"], + configurable: false, + klass: {}, + proto: {}, + }), + define({ name: "Expect", construct: true, call: true, @@ -333,6 +345,10 @@ export default [ fn: "toBeWithin", length: 2, }, + toEqualIgnoringWhitespace: { + fn: "toEqualIgnoringWhitespace", + length: 1, + }, toBeSymbol: { fn: "toBeSymbol", length: 0, diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig index f3c9ffa26..a95897414 100644 --- a/src/bun.js/test/jest.zig +++ b/src/bun.js/test/jest.zig @@ -793,14 +793,33 @@ pub const DescribeScope = struct { current_test_id: TestRunner.Test.ID = 0, value: JSValue = .zero, done: bool = false, - is_skip: bool = false, skip_count: u32 = 0, tag: Tag = .pass, - pub fn isAllSkipped(this: *const DescribeScope) bool { - if (this.is_skip) return true; - const total = this.tests.items.len; - return total > 0 and @as(usize, this.skip_count) >= total; + fn isWithinOnlyScope(this: *const DescribeScope) bool { + if (this.tag == .only) return true; + if (this.parent != null) return this.parent.?.isWithinOnlyScope(); + return false; + } + + fn isWithinSkipScope(this: *const DescribeScope) bool { + if (this.tag == .skip) return true; + if (this.parent != null) return this.parent.?.isWithinSkipScope(); + return false; + } + + fn isWithinTodoScope(this: *const DescribeScope) bool { + if (this.tag == .todo) return true; + if (this.parent != null) return this.parent.?.isWithinTodoScope(); + return false; + } + + pub fn shouldEvaluateScope(this: *const DescribeScope) bool { + if (this.tag == .skip or + this.tag == .todo) return false; + if (Jest.runner.?.only and this.tag == .only) return true; + if (this.parent != null) return this.parent.?.shouldEvaluateScope(); + return true; } pub fn push(new: *DescribeScope) void { @@ -1114,7 +1133,7 @@ pub const DescribeScope = struct { var i: TestRunner.Test.ID = 0; - if (!this.isAllSkipped()) { + if (this.shouldEvaluateScope()) { if (this.runCallback(globalObject, .beforeAll)) |_| { while (i < end) { Jest.runner.?.reportFailure(i + this.test_id_start, source.path.text, tests[i].label, 0, 0, this); @@ -1168,7 +1187,7 @@ pub const DescribeScope = struct { return; } - if (!this.isAllSkipped()) { + if (this.shouldEvaluateScope()) { // Run the afterAll callbacks, in reverse order // unless there were no tests for this scope if (this.execCallback(globalThis, .afterAll)) |err| { @@ -1267,8 +1286,8 @@ pub const TestRunnerTask = struct { var test_: TestScope = this.describe.tests.items[test_id]; describe.current_test_id = test_id; - if (test_.func == .zero or (describe.is_skip and test_.tag != .only)) { - var tag = if (describe.is_skip) describe.tag else test_.tag; + if (test_.func == .zero or !describe.shouldEvaluateScope()) { + var tag = if (!describe.shouldEvaluateScope()) describe.tag else test_.tag; switch (tag) { .todo => { this.processTestResult(globalThis, .{ .todo = {} }, test_, test_id, describe); @@ -1609,8 +1628,7 @@ inline fn createScope( .label = label, .parent = parent, .file_id = parent.file_id, - .tag = if (parent.is_skip) parent.tag else tag, - .is_skip = is_skip or parent.is_skip, + .tag = tag, }; return scope.run(globalThis, function, &.{}); @@ -1983,8 +2001,7 @@ fn eachBind( .label = formattedLabel, .parent = parent, .file_id = parent.file_id, - .tag = if (parent.is_skip) parent.tag else .pass, - .is_skip = parent.is_skip, + .tag = .pass, }; const ret = scope.run(globalThis, function, function_args); diff --git a/src/bun.js/webcore.zig b/src/bun.js/webcore.zig index 168c4339b..411d3ed2e 100644 --- a/src/bun.js/webcore.zig +++ b/src/bun.js/webcore.zig @@ -107,9 +107,11 @@ fn confirm(globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callcon // 6. Pause until the user responds either positively or negatively. var stdin = std.io.getStdIn(); - var reader = stdin.reader(); + var unbuffered_reader = stdin.reader(); + var buffered = std.io.bufferedReader(unbuffered_reader); + var reader = buffered.reader(); - const first_byte = reader.readByte() catch { + var first_byte = reader.readByte() catch { return .false; }; @@ -122,13 +124,14 @@ fn confirm(globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callcon 'y', 'Y' => { const next_byte = reader.readByte() catch { // They may have said yes, but the stdin is invalid. + return .false; }; if (next_byte == '\n') { // 8. If the user responded positively, return true; // otherwise, the user responded negatively: return false. - return .false; + return .true; } }, else => {}, diff --git a/src/bun.js/webcore/blob.zig b/src/bun.js/webcore/blob.zig index 54c37e679..f9699cffc 100644 --- a/src/bun.js/webcore/blob.zig +++ b/src/bun.js/webcore/blob.zig @@ -1040,7 +1040,10 @@ pub const Blob = struct { break :brk result; }, .err => |err| { - return JSC.JSPromise.rejectedPromiseValue(globalThis, err.toJSC(globalThis)); + return JSC.JSPromise.rejectedPromiseValue( + globalThis, + err.withPath(pathlike.path.slice()).toJSC(globalThis), + ); }, } unreachable; @@ -1080,8 +1083,13 @@ pub const Blob = struct { needs_async.* = true; return .zero; } - - return JSC.JSPromise.rejectedPromiseValue(globalThis, err.toJSC(globalThis)); + if (comptime !needs_open) { + return JSC.JSPromise.rejectedPromiseValue(globalThis, err.toJSC(globalThis)); + } + return JSC.JSPromise.rejectedPromiseValue( + globalThis, + err.withPath(pathlike.path.slice()).toJSC(globalThis), + ); }, } } @@ -1110,7 +1118,10 @@ pub const Blob = struct { break :brk result; }, .err => |err| { - return JSC.JSPromise.rejectedPromiseValue(globalThis, err.toJSC(globalThis)); + return JSC.JSPromise.rejectedPromiseValue( + globalThis, + err.withPath(pathlike.path.slice()).toJSC(globalThis), + ); }, } unreachable; @@ -1145,7 +1156,13 @@ pub const Blob = struct { needs_async.* = true; return .zero; } - return JSC.JSPromise.rejectedPromiseValue(globalThis, err.toJSC(globalThis)); + if (comptime !needs_open) { + return JSC.JSPromise.rejectedPromiseValue(globalThis, err.toJSC(globalThis)); + } + return JSC.JSPromise.rejectedPromiseValue( + globalThis, + err.withPath(pathlike.path.slice()).toJSC(globalThis), + ); }, } } @@ -1680,6 +1697,7 @@ pub const Blob = struct { read_completion: HTTPClient.NetworkThread.Completion = undefined, read_len: SizeType = 0, read_off: SizeType = 0, + read_eof: bool = false, size: SizeType = 0, buffer: []u8 = undefined, task: HTTPClient.NetworkThread.Task = undefined, @@ -1797,8 +1815,7 @@ pub const Blob = struct { pub fn onRead(this: *ReadFile, completion: *HTTPClient.NetworkThread.Completion, result: AsyncIO.ReadError!usize) void { defer this.doReadLoop(); - - this.read_len = @as(SizeType, @truncate(result catch |err| { + const read_len = @as(SizeType, @truncate(result catch |err| { if (@hasField(HTTPClient.NetworkThread.Completion, "result")) { this.errno = AsyncIO.asError(-completion.result); this.system_error = (bun.sys.Error{ @@ -1821,6 +1838,8 @@ pub const Blob = struct { this.read_len = 0; return; })); + this.read_eof = read_len == 0; + this.read_len = read_len; } fn runAsync(this: *ReadFile, task: *ReadFileTask) void { @@ -1930,7 +1949,7 @@ pub const Blob = struct { this.read_off += this.read_len; var remain = this.buffer[@min(this.read_off, @as(Blob.SizeType, @truncate(this.buffer.len)))..]; - if (remain.len > 0 and this.errno == null) { + if (remain.len > 0 and this.errno == null and !this.read_eof) { this.doRead(); return; } @@ -2287,7 +2306,7 @@ pub const Blob = struct { this.source_fd = 0; } - this.system_error = errno.toSystemError(); + this.system_error = errno.withPath(this.destination_file_store.pathlike.path.slice()).toSystemError(); return AsyncIO.asError(errno.errno); }, }; @@ -2737,17 +2756,7 @@ pub const Blob = struct { value: JSC.JSValue, global: *JSGlobalObject, ) JSC.JSValue { - if (value.isError()) { - return JSC.JSPromise.rejectedPromiseValue(global, value); - } - - if (value.jsType() == .JSPromise) - return value; - - return JSPromise.resolvedPromiseValue( - global, - value, - ); + return JSC.JSPromise.wrap(global, value); } pub fn getText( @@ -3011,12 +3020,13 @@ pub const Blob = struct { } } + const offset = this.offset +| @as(SizeType, @intCast(relativeStart)); const len = @as(SizeType, @intCast(@max(relativeEnd -| relativeStart, 0))); // This copies over the is_all_ascii flag // which is okay because this will only be a <= slice var blob = this.dupe(); - blob.offset = @as(SizeType, @intCast(relativeStart)); + blob.offset = offset; blob.size = len; // infer the content type if it was not specified @@ -3671,11 +3681,7 @@ pub const Blob = struct { if (comptime lifetime != .temporary) this.setIsASCIIFlag(true); } - if (comptime lifetime == .temporary) { - return ZigString.init(buf).toJSONObject(global); - } else { - return ZigString.init(buf).toJSONObject(global); - } + return ZigString.init(buf).toJSONObject(global); } pub fn toFormDataWithBytes(this: *Blob, global: *JSGlobalObject, buf: []u8, comptime _: Lifetime) JSValue { diff --git a/src/bun.js/webcore/body.zig b/src/bun.js/webcore/body.zig index 621acc0b3..e38f03c08 100644 --- a/src/bun.js/webcore/body.zig +++ b/src/bun.js/webcore/body.zig @@ -51,7 +51,6 @@ const Request = JSC.WebCore.Request; // https://developer.mozilla.org/en-US/docs/Web/API/Body pub const Body = struct { - init: Init = Init{ .headers = null, .status_code = 200 }, value: Value, // = Value.empty, pub inline fn len(this: *const Body) Blob.SizeType { @@ -68,7 +67,6 @@ pub const Body = struct { pub fn clone(this: *Body, globalThis: *JSGlobalObject) Body { return Body{ - .init = this.init.clone(globalThis), .value = this.value.clone(globalThis), }; } @@ -79,19 +77,7 @@ pub const Body = struct { try formatter.writeIndent(Writer, writer); try writer.writeAll(comptime Output.prettyFmt("<r>bodyUsed<d>:<r> ", enable_ansi_colors)); formatter.printAs(.Boolean, Writer, writer, JSC.JSValue.jsBoolean(this.value == .Used), .BooleanObject, enable_ansi_colors); - formatter.printComma(Writer, writer, enable_ansi_colors) catch unreachable; - try writer.writeAll("\n"); - // if (this.init.headers) |headers| { - // try formatter.writeIndent(Writer, writer); - // try writer.writeAll("headers: "); - // try headers.leak().writeFormat(formatter, writer, comptime enable_ansi_colors); - // try writer.writeAll("\n"); - // } - - try formatter.writeIndent(Writer, writer); - try writer.writeAll(comptime Output.prettyFmt("<r>status<d>:<r> ", enable_ansi_colors)); - formatter.printAs(.Double, Writer, writer, JSC.JSValue.jsNumber(this.init.status_code), .NumberObject, enable_ansi_colors); if (this.value == .Blob) { try formatter.printComma(Writer, writer, enable_ansi_colors); try writer.writeAll("\n"); @@ -113,87 +99,9 @@ pub const Body = struct { } pub fn deinit(this: *Body, _: std.mem.Allocator) void { - if (this.init.headers) |headers| { - this.init.headers = null; - - headers.deref(); - } this.value.deinit(); } - pub const Init = struct { - headers: ?*FetchHeaders = null, - status_code: u16, - method: Method = Method.GET, - - pub fn clone(this: Init, ctx: *JSGlobalObject) Init { - var that = this; - var headers = this.headers; - if (headers) |head| { - that.headers = head.cloneThis(ctx); - } - - return that; - } - - pub fn init(allocator: std.mem.Allocator, ctx: *JSGlobalObject, response_init: JSC.JSValue) !?Init { - var result = Init{ .status_code = 200 }; - - if (!response_init.isCell()) - return null; - - if (response_init.jsType() == .DOMWrapper) { - // fast path: it's a Request object or a Response object - // we can skip calling JS getters - if (response_init.as(Request)) |req| { - if (req.headers) |headers| { - if (!headers.isEmpty()) { - result.headers = headers.cloneThis(ctx); - } - } - - result.method = req.method; - return result; - } - - if (response_init.as(Response)) |req| { - return req.body.init.clone(ctx); - } - } - - if (response_init.fastGet(ctx, .headers)) |headers| { - if (headers.as(FetchHeaders)) |orig| { - if (!orig.isEmpty()) { - result.headers = orig.cloneThis(ctx); - } - } else { - result.headers = FetchHeaders.createFromJS(ctx.ptr(), headers); - } - } - - if (response_init.fastGet(ctx, .status)) |status_value| { - const number = status_value.coerceToInt64(ctx); - if ((200 <= number and number < 600) or number == 101) { - result.status_code = @as(u16, @truncate(@as(u32, @intCast(number)))); - } else { - const err = ctx.createRangeErrorInstance("The status provided ({d}) must be 101 or in the range of [200, 599]", .{number}); - ctx.throwValue(err); - return null; - } - } - - if (response_init.fastGet(ctx, .method)) |method_value| { - var method_str = method_value.toSlice(ctx, allocator); - defer method_str.deinit(); - if (method_str.len > 0) { - result.method = Method.which(method_str.slice()) orelse .GET; - } - } - - return result; - } - }; - pub const PendingValue = struct { promise: ?JSValue = null, readable: ?JSC.WebCore.ReadableStream = null, @@ -466,7 +374,10 @@ pub const Body = struct { JSC.markBinding(@src()); switch (this.*) { - .Used, .Empty => { + .Used => { + return JSC.WebCore.ReadableStream.used(globalThis); + }, + .Empty => { return JSC.WebCore.ReadableStream.empty(globalThis); }, .Null => { @@ -493,6 +404,9 @@ pub const Body = struct { if (locked.readable) |readable| { return readable.value; } + if (locked.promise != null) { + return JSC.WebCore.ReadableStream.used(globalThis); + } var drain_result: JSC.WebCore.DrainResult = .{ .estimated_size = 0, }; @@ -998,72 +912,12 @@ pub const Body = struct { } }; - pub fn @"404"(_: js.JSContextRef) Body { - return Body{ - .init = Init{ - .headers = null, - .status_code = 404, - }, - .value = Value{ .Null = {} }, - }; - } - - pub fn @"200"(_: js.JSContextRef) Body { - return Body{ - .init = Init{ - .status_code = 200, - }, - .value = Value{ .Null = {} }, - }; - } - - pub fn extract( - globalThis: *JSGlobalObject, - value: JSValue, - ) ?Body { - return extractBody( - globalThis, - value, - false, - JSValue.zero, - ); - } - - pub fn extractWithInit( - globalThis: *JSGlobalObject, - value: JSValue, - init: JSValue, - ) ?Body { - return extractBody( - globalThis, - value, - true, - init, - ); - } - // https://github.com/WebKit/webkit/blob/main/Source/WebCore/Modules/fetch/FetchBody.cpp#L45 - inline fn extractBody( + pub fn extract( globalThis: *JSGlobalObject, value: JSValue, - comptime has_init: bool, - init: JSValue, ) ?Body { - var body = Body{ - .value = Value{ .Null = {} }, - .init = Init{ .headers = null, .status_code = 200 }, - }; - var allocator = getAllocator(globalThis); - - if (comptime has_init) { - if (Init.init(allocator, globalThis, init)) |maybeInit| { - if (maybeInit) |init_| { - body.init = init_; - } - } else |_| { - return null; - } - } + var body = Body{ .value = Value{ .Null = {} } }; body.value = Value.fromJS(globalThis, value) orelse return null; if (body.value == .Blob) @@ -1104,8 +958,7 @@ pub fn BodyMixin(comptime Type: type) type { var body: *Body.Value = this.getBodyValue(); if (body.* == .Used) { - // TODO: make this closed - return JSC.WebCore.ReadableStream.empty(globalThis); + return JSC.WebCore.ReadableStream.used(globalThis); } return body.toReadableStream(globalThis); @@ -1136,7 +989,9 @@ pub fn BodyMixin(comptime Type: type) type { } var blob = value.useAsAnyBlobAllowNonUTF8String(); - return JSC.JSPromise.wrap(globalObject, blob.toJSON(globalObject, .share)); + const result = blob.toJSON(globalObject, .share); + + return JSC.JSPromise.wrap(globalObject, result); } fn handleBodyAlreadyUsed(globalObject: *JSC.JSGlobalObject) JSValue { diff --git a/src/bun.js/webcore/encoding.classes.ts b/src/bun.js/webcore/encoding.classes.ts index 118dfd09e..7114f210e 100644 --- a/src/bun.js/webcore/encoding.classes.ts +++ b/src/bun.js/webcore/encoding.classes.ts @@ -16,6 +16,9 @@ export default [ fatal: { getter: "getFatal", }, + ignoreBOM: { + getter: "getIgnoreBOM", + }, decode: { fn: "decode", diff --git a/src/bun.js/webcore/encoding.zig b/src/bun.js/webcore/encoding.zig index 53933fdb7..18e70b261 100644 --- a/src/bun.js/webcore/encoding.zig +++ b/src/bun.js/webcore/encoding.zig @@ -559,6 +559,13 @@ pub const TextDecoder = struct { remainder = remainder[1..]; continue; }, + // BOM handling + 0xFEFF => { + buffer.ensureTotalCapacity(allocator, 1) catch unreachable; + buffer.items.ptr[buffer.items.len] = remainder[0]; + buffer.items.len += 1; + remainder = remainder[1..]; + }, // Is this an unpaired low surrogate or four-digit hex escape? else => { @@ -629,8 +636,13 @@ pub const TextDecoder = struct { }, EncodingLabel.@"UTF-8" => { const toUTF16 = if (stream) strings.toUTF16Alloc else strings.toUTF16AllocNoTrim; + const moved_buffer_slice_8 = if (!this.ignore_bom and buffer_slice.len > 3 and std.mem.eql(u8, &[_]u8{ '\xEF', '\xBB', '\xBF' }, buffer_slice[0..3])) + buffer_slice[3..] + else + buffer_slice; + if (this.fatal) { - if (toUTF16(default_allocator, buffer_slice, true)) |result_| { + if (toUTF16(default_allocator, moved_buffer_slice_8, true)) |result_| { if (result_) |result| { return ZigString.toExternalU16(result.ptr, result.len, globalThis); } @@ -649,7 +661,7 @@ pub const TextDecoder = struct { } } } else { - if (toUTF16(default_allocator, buffer_slice, false)) |result_| { + if (toUTF16(default_allocator, moved_buffer_slice_8, false)) |result_| { if (result_) |result| { return ZigString.toExternalU16(result.ptr, result.len, globalThis); } @@ -664,15 +676,20 @@ pub const TextDecoder = struct { } // Experiment: using mimalloc directly is slightly slower - return ZigString.init(buffer_slice).toValueGC(globalThis); + return ZigString.init(moved_buffer_slice_8).toValueGC(globalThis); }, EncodingLabel.@"UTF-16LE" => { - if (std.mem.isAligned(@intFromPtr(buffer_slice.ptr), @alignOf([*]const u16))) { - return this.decodeUTF16WithAlignment([]align(2) const u16, @as([]align(2) const u16, @alignCast(std.mem.bytesAsSlice(u16, buffer_slice))), globalThis); + const moved_buffer_slice_16 = if (!this.ignore_bom and buffer_slice.len > 2 and std.mem.eql(u8, &[_]u8{ '\xFF', '\xFE' }, buffer_slice[0..2])) + buffer_slice[2..] + else + buffer_slice; + + if (std.mem.isAligned(@intFromPtr(moved_buffer_slice_16.ptr), @alignOf([*]const u16))) { + return this.decodeUTF16WithAlignment([]align(2) const u16, @as([]align(2) const u16, @alignCast(std.mem.bytesAsSlice(u16, moved_buffer_slice_16))), globalThis); } - return this.decodeUTF16WithAlignment([]align(1) const u16, std.mem.bytesAsSlice(u16, buffer_slice), globalThis); + return this.decodeUTF16WithAlignment([]align(1) const u16, std.mem.bytesAsSlice(u16, moved_buffer_slice_16), globalThis); }, else => { globalThis.throwInvalidArguments("TextDecoder.decode set to unsupported encoding", .{}); @@ -702,6 +719,9 @@ pub const TextDecoder = struct { globalThis.throwInvalidArguments("Unsupported encoding label \"{s}\"", .{str.slice()}); return null; } + } else if (arguments[0].isUndefined()) { + // default to utf-8 + decoder.encoding = EncodingLabel.@"UTF-8"; } else { globalThis.throwInvalidArguments("TextDecoder(encoding) label is invalid", .{}); return null; @@ -745,7 +765,7 @@ pub const Encoder = struct { export fn Bun__encoding__writeLatin1(input: [*]const u8, len: usize, to: [*]u8, to_len: usize, encoding: u8) usize { return switch (@as(JSC.Node.Encoding, @enumFromInt(encoding))) { .utf8 => writeU8(input, len, to, to_len, .utf8), - .latin1 => writeU8(input, len, to, to_len, .ascii), + .latin1 => writeU8(input, len, to, to_len, .latin1), .ascii => writeU8(input, len, to, to_len, .ascii), .ucs2 => writeU8(input, len, to, to_len, .utf16le), .utf16le => writeU8(input, len, to, to_len, .utf16le), @@ -947,13 +967,13 @@ pub const Encoder = struct { // if (comptime encoding.isBinaryToText()) {} switch (comptime encoding) { - .buffer => { + .buffer, .latin1 => { const written = @min(len, to_len); @memcpy(to_ptr[0..written], input[0..written]); return written; }, - .latin1, .ascii => { + .ascii => { const written = @min(len, to_len); var to = to_ptr[0..written]; diff --git a/src/bun.js/webcore/request.zig b/src/bun.js/webcore/request.zig index fc38e1825..95f92145b 100644 --- a/src/bun.js/webcore/request.zig +++ b/src/bun.js/webcore/request.zig @@ -50,6 +50,7 @@ const InternalBlob = JSC.WebCore.InternalBlob; const BodyMixin = JSC.WebCore.BodyMixin; const Body = JSC.WebCore.Body; const Blob = JSC.WebCore.Blob; +const Response = JSC.WebCore.Response; const body_value_pool_size: u16 = 256; pub const BodyValueRef = bun.HiveRef(Body.Value, body_value_pool_size); @@ -68,7 +69,7 @@ pub const Request = struct { signal: ?*AbortSignal = null, body: *BodyValueRef, method: Method = Method.GET, - uws_request: ?*uws.Request = null, + request_context: JSC.API.AnyRequestContext = JSC.API.AnyRequestContext.Null, https: bool = false, upgrader: ?*anyopaque = null, @@ -89,7 +90,7 @@ pub const Request = struct { pub fn getContentType( this: *Request, ) ?ZigString.Slice { - if (this.uws_request) |req| { + if (this.request_context.getRequest()) |req| { if (req.header("content-type")) |value| { return ZigString.Slice.fromUTF8NeverFree(value); } @@ -324,7 +325,7 @@ pub const Request = struct { if (this.url.length() > 0) return this.url.byteSlice().len; - if (this.uws_request) |req| { + if (this.request_context.getRequest()) |req| { const req_url = req.url(); if (req_url.len > 0 and req_url[0] == '/') { if (req.header("host")) |host| { @@ -351,7 +352,7 @@ pub const Request = struct { pub fn ensureURL(this: *Request) !void { if (!this.url.isEmpty()) return; - if (this.uws_request) |req| { + if (this.request_context.getRequest()) |req| { const req_url = req.url(); if (req_url.len > 0 and req_url[0] == '/') { if (req.header("host")) |host| { @@ -507,10 +508,9 @@ pub const Request = struct { }; const values_to_try = values_to_try_[0 .. @as(usize, @intFromBool(!is_first_argument_a_url)) + @as(usize, @intFromBool(arguments.len > 1 and arguments[1].isObject()))]; - for (values_to_try) |value| { const value_type = value.jsType(); - + const explicit_check = values_to_try.len == 2 and value_type == .FinalObject and values_to_try[1].jsType() == .DOMWrapper; if (value_type == .DOMWrapper) { if (value.as(Request)) |request| { if (values_to_try.len == 1) { @@ -543,12 +543,12 @@ pub const Request = struct { if (value.as(JSC.WebCore.Response)) |response| { if (!fields.contains(.method)) { - req.method = response.body.init.method; + req.method = response.init.method; fields.insert(.method); } if (!fields.contains(.headers)) { - if (response.body.init.headers) |headers| { + if (response.init.headers) |headers| { req.headers = headers.cloneThis(globalThis); fields.insert(.headers); } @@ -608,9 +608,8 @@ pub const Request = struct { } if (!fields.contains(.signal)) { - if (value.get(globalThis, "signal")) |signal_| { + if (value.getTruthy(globalThis, "signal")) |signal_| { fields.insert(.signal); - if (AbortSignal.fromJS(signal_)) |signal| { //Keep it alive signal_.ensureStillAlive(); @@ -625,24 +624,26 @@ pub const Request = struct { } if (!fields.contains(.method) or !fields.contains(.headers)) { - if (Body.Init.init(globalThis.allocator(), globalThis, value) catch null) |init| { - if (!fields.contains(.method)) { - req.method = init.method; - fields.insert(.method); + if (Response.Init.init(globalThis.allocator(), globalThis, value) catch null) |init| { + if (!explicit_check or (explicit_check and value.fastGet(globalThis, .method) != null)) { + if (!fields.contains(.method)) { + req.method = init.method; + fields.insert(.method); + } } - - if (init.headers) |headers| { - if (!fields.contains(.headers)) { - req.headers = headers; - fields.insert(.headers); - } else { - headers.deref(); + if (!explicit_check or (explicit_check and value.fastGet(globalThis, .headers) != null)) { + if (init.headers) |headers| { + if (!fields.contains(.headers)) { + req.headers = headers; + fields.insert(.headers); + } else { + headers.deref(); + } } } } } } - if (req.url.isEmpty()) { globalThis.throw("Failed to construct 'Request': url is required.", .{}); req.finalizeWithoutDeinit(); @@ -724,7 +725,7 @@ pub const Request = struct { globalThis: *JSC.JSGlobalObject, ) callconv(.C) JSC.JSValue { if (this.headers == null) { - if (this.uws_request) |req| { + if (this.request_context.getRequest()) |req| { this.headers = FetchHeaders.createFromUWS(globalThis, req); } else { this.headers = FetchHeaders.createEmpty(); @@ -743,7 +744,7 @@ pub const Request = struct { pub fn cloneHeaders(this: *Request, globalThis: *JSGlobalObject) ?*FetchHeaders { if (this.headers == null) { - if (this.uws_request) |uws_req| { + if (this.request_context.getRequest()) |uws_req| { this.headers = FetchHeaders.createFromUWS(globalThis, uws_req); } } diff --git a/src/bun.js/webcore/response.zig b/src/bun.js/webcore/response.zig index 0e80adfc4..f7ada2862 100644 --- a/src/bun.js/webcore/response.zig +++ b/src/bun.js/webcore/response.zig @@ -63,8 +63,8 @@ pub const Response = struct { allocator: std.mem.Allocator, body: Body, + init: Init, url: bun.String = bun.String.empty, - status_text: bun.String = bun.String.empty, redirected: bool = false, // We must report a consistent value for this @@ -89,7 +89,7 @@ pub const Response = struct { return this.reported_estimated_size orelse brk: { this.reported_estimated_size = @as( u63, - @intCast(this.body.value.estimatedSize() + this.url.byteSlice().len + this.status_text.byteSlice().len + @sizeOf(Response)), + @intCast(this.body.value.estimatedSize() + this.url.byteSlice().len + this.init.status_text.byteSlice().len + @sizeOf(Response)), ); break :brk this.reported_estimated_size.?; }; @@ -104,11 +104,11 @@ pub const Response = struct { pub fn getFetchHeaders( this: *Response, ) ?*FetchHeaders { - return this.body.init.headers; + return this.init.headers; } pub inline fn statusCode(this: *const Response) u16 { - return this.body.init.status_code; + return this.init.status_code; } pub fn redirectLocation(this: *const Response) ?[]const u8 { @@ -116,7 +116,7 @@ pub const Response = struct { } pub fn header(this: *const Response, name: JSC.FetchHeaders.HTTPHeaderName) ?[]const u8 { - return if ((this.body.init.headers orelse return null).fastGet(name)) |str| + return if ((this.init.headers orelse return null).fastGet(name)) |str| str.slice() else null; @@ -146,14 +146,20 @@ pub const Response = struct { try writer.writeAll("\n"); try formatter.writeIndent(Writer, writer); - try writer.writeAll(comptime Output.prettyFmt("<r>headers<d>:<r> ", enable_ansi_colors)); - formatter.printAs(.Private, Writer, writer, this.getHeaders(formatter.globalThis), .DOMWrapper, enable_ansi_colors); + try writer.writeAll(comptime Output.prettyFmt("<r>status<d>:<r> ", enable_ansi_colors)); + formatter.printAs(.Double, Writer, writer, JSC.JSValue.jsNumber(this.init.status_code), .NumberObject, enable_ansi_colors); formatter.printComma(Writer, writer, enable_ansi_colors) catch unreachable; try writer.writeAll("\n"); try formatter.writeIndent(Writer, writer); try writer.writeAll(comptime Output.prettyFmt("<r>statusText<d>:<r> ", enable_ansi_colors)); - try writer.print(comptime Output.prettyFmt("<r>\"<b>{}<r>\"", enable_ansi_colors), .{this.status_text}); + try writer.print(comptime Output.prettyFmt("<r>\"<b>{}<r>\"", enable_ansi_colors), .{this.init.status_text}); + formatter.printComma(Writer, writer, enable_ansi_colors) catch unreachable; + try writer.writeAll("\n"); + + try formatter.writeIndent(Writer, writer); + try writer.writeAll(comptime Output.prettyFmt("<r>headers<d>:<r> ", enable_ansi_colors)); + formatter.printAs(.Private, Writer, writer, this.getHeaders(formatter.globalThis), .DOMWrapper, enable_ansi_colors); formatter.printComma(Writer, writer, enable_ansi_colors) catch unreachable; try writer.writeAll("\n"); @@ -162,6 +168,7 @@ pub const Response = struct { formatter.printAs(.Boolean, Writer, writer, JSC.JSValue.jsBoolean(this.redirected), .BooleanObject, enable_ansi_colors); formatter.printComma(Writer, writer, enable_ansi_colors) catch unreachable; try writer.writeAll("\n"); + formatter.resetLine(); try this.body.writeFormat(Formatter, formatter, writer, enable_ansi_colors); } @@ -172,7 +179,7 @@ pub const Response = struct { } pub fn isOK(this: *const Response) bool { - return this.body.init.status_code == 304 or (this.body.init.status_code >= 200 and this.body.init.status_code <= 299); + return this.init.status_code >= 200 and this.init.status_code <= 299; } pub fn getURL( @@ -187,7 +194,7 @@ pub const Response = struct { this: *Response, globalThis: *JSC.JSGlobalObject, ) callconv(.C) JSC.JSValue { - if (this.body.init.status_code < 200) { + if (this.init.status_code < 200) { return ZigString.init("error").toValue(globalThis); } @@ -199,7 +206,7 @@ pub const Response = struct { globalThis: *JSC.JSGlobalObject, ) callconv(.C) JSC.JSValue { // https://developer.mozilla.org/en-US/docs/Web/API/Response/statusText - return this.status_text.toJS(globalThis); + return this.init.status_text.toJS(globalThis); } pub fn getRedirected( @@ -219,18 +226,18 @@ pub const Response = struct { } fn getOrCreateHeaders(this: *Response, globalThis: *JSC.JSGlobalObject) *FetchHeaders { - if (this.body.init.headers == null) { - this.body.init.headers = FetchHeaders.createEmpty(); + if (this.init.headers == null) { + this.init.headers = FetchHeaders.createEmpty(); if (this.body.value == .Blob) { const content_type = this.body.value.Blob.content_type; if (content_type.len > 0) { - this.body.init.headers.?.put("content-type", content_type, globalThis); + this.init.headers.?.put("content-type", content_type, globalThis); } } } - return this.body.init.headers.?; + return this.init.headers.?; } pub fn getHeaders( @@ -262,8 +269,8 @@ pub const Response = struct { new_response.* = Response{ .allocator = allocator, .body = this.body.clone(globalThis), + .init = this.init.clone(globalThis), .url = this.url.clone(), - .status_text = this.status_text.clone(), .redirected = this.redirected, }; } @@ -279,17 +286,16 @@ pub const Response = struct { _: *JSC.JSGlobalObject, ) callconv(.C) JSC.JSValue { // https://developer.mozilla.org/en-US/docs/Web/API/Response/status - return JSValue.jsNumber(this.body.init.status_code); + return JSValue.jsNumber(this.init.status_code); } pub fn finalize( this: *Response, ) callconv(.C) void { - this.body.deinit(this.allocator); - var allocator = this.allocator; - this.status_text.deref(); + this.init.deinit(allocator); + this.body.deinit(allocator); this.url.deref(); allocator.destroy(this); @@ -348,7 +354,7 @@ pub const Response = struct { pub fn getContentType( this: *Response, ) ?ZigString.Slice { - if (this.body.init.headers) |headers| { + if (this.init.headers) |headers| { if (headers.fastGet(.ContentType)) |value| { return value.toSlice(bun.default_allocator); } @@ -373,11 +379,11 @@ pub const Response = struct { var response = Response{ .body = Body{ - .init = Body.Init{ - .status_code = 200, - }, .value = .{ .Empty = {} }, }, + .init = Response.Init{ + .status_code = 200, + }, .allocator = getAllocator(globalThis), .url = bun.String.empty, }; @@ -409,10 +415,10 @@ pub const Response = struct { if (args.nextEat()) |init| { if (init.isUndefinedOrNull()) {} else if (init.isNumber()) { - response.body.init.status_code = @as(u16, @intCast(@min(@max(0, init.toInt32()), std.math.maxInt(u16)))); + response.init.status_code = @as(u16, @intCast(@min(@max(0, init.toInt32()), std.math.maxInt(u16)))); } else { - if (Body.Init.init(getAllocator(globalThis), globalThis, init) catch null) |_init| { - response.body.init = _init; + if (Response.Init.init(getAllocator(globalThis), globalThis, init) catch null) |_init| { + response.init = _init; } } } @@ -434,10 +440,10 @@ pub const Response = struct { // var response = getAllocator(globalThis).create(Response) catch unreachable; var response = Response{ + .init = Response.Init{ + .status_code = 302, + }, .body = Body{ - .init = Body.Init{ - .status_code = 302, - }, .value = .{ .Empty = {} }, }, .allocator = getAllocator(globalThis), @@ -455,17 +461,17 @@ pub const Response = struct { if (args.nextEat()) |init| { if (init.isUndefinedOrNull()) {} else if (init.isNumber()) { - response.body.init.status_code = @as(u16, @intCast(@min(@max(0, init.toInt32()), std.math.maxInt(u16)))); + response.init.status_code = @as(u16, @intCast(@min(@max(0, init.toInt32()), std.math.maxInt(u16)))); } else { - if (Body.Init.init(getAllocator(globalThis), globalThis, init) catch null) |_init| { - response.body.init = _init; - response.body.init.status_code = 302; + if (Response.Init.init(getAllocator(globalThis), globalThis, init) catch null) |_init| { + response.init = _init; + response.init.status_code = 302; } } } - response.body.init.headers = response.getOrCreateHeaders(globalThis); - var headers_ref = response.body.init.headers.?; + response.init.headers = response.getOrCreateHeaders(globalThis); + var headers_ref = response.init.headers.?; headers_ref.put("location", url_string_slice.slice(), globalThis); var ptr = response.allocator.create(Response) catch unreachable; ptr.* = response; @@ -478,10 +484,10 @@ pub const Response = struct { ) callconv(.C) JSValue { var response = getAllocator(globalThis).create(Response) catch unreachable; response.* = Response{ + .init = Response.Init{ + .status_code = 0, + }, .body = Body{ - .init = Body.Init{ - .status_code = 0, - }, .value = .{ .Empty = {} }, }, .allocator = getAllocator(globalThis), @@ -494,6 +500,8 @@ pub const Response = struct { globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame, ) callconv(.C) ?*Response { + var allocator = getAllocator(globalThis); + const args_list = brk: { var args = callframe.arguments(2); if (args.len > 1 and args.ptr[1].isEmptyOrUndefinedOrNull()) { @@ -503,17 +511,24 @@ pub const Response = struct { }; const arguments = args_list.ptr[0..args_list.len]; - const body: Body = @as(?Body, brk: { + + const init: Init = @as(?Init, brk: { switch (arguments.len) { 0 => { - break :brk Body.@"200"(globalThis); + break :brk Init{ + .status_code = 200, + .headers = null, + }; }, 1 => { - break :brk Body.extract(globalThis, arguments[0]); + break :brk Init{ + .status_code = 200, + .headers = null, + }; }, else => { if (arguments[1].isObject()) { - break :brk Body.extractWithInit(globalThis, arguments[0], arguments[1]); + break :brk Init.init(allocator, globalThis, arguments[1]) catch null; } std.debug.assert(!arguments[1].isEmptyOrUndefinedOrNull()); @@ -526,23 +541,152 @@ pub const Response = struct { unreachable; }) orelse return null; - var response = getAllocator(globalThis).create(Response) catch unreachable; + const body: Body = brk: { + switch (arguments.len) { + 0 => { + break :brk Body{ + .value = Body.Value{ .Null = {} }, + }; + }, + else => { + break :brk Body.extract(globalThis, arguments[0]); + }, + } + unreachable; + } orelse return null; + + var response = allocator.create(Response) catch unreachable; response.* = Response{ .body = body, + .init = init, .allocator = getAllocator(globalThis), }; if (response.body.value == .Blob and - response.body.init.headers != null and + response.init.headers != null and response.body.value.Blob.content_type.len > 0 and - !response.body.init.headers.?.fastHas(.ContentType)) + !response.init.headers.?.fastHas(.ContentType)) { - response.body.init.headers.?.put("content-type", response.body.value.Blob.content_type, globalThis); + response.init.headers.?.put("content-type", response.body.value.Blob.content_type, globalThis); } return response; } + + pub const Init = struct { + headers: ?*FetchHeaders = null, + status_code: u16, + status_text: bun.String = bun.String.empty, + method: Method = Method.GET, + + pub fn clone(this: Init, ctx: *JSGlobalObject) Init { + var that = this; + var headers = this.headers; + if (headers) |head| { + that.headers = head.cloneThis(ctx); + } + that.status_text = this.status_text.clone(); + + return that; + } + + pub fn init(allocator: std.mem.Allocator, ctx: *JSGlobalObject, response_init: JSC.JSValue) !?Init { + var result = Init{ .status_code = 200 }; + + if (!response_init.isCell()) + return null; + + if (response_init.jsType() == .DOMWrapper) { + // fast path: it's a Request object or a Response object + // we can skip calling JS getters + if (response_init.as(Request)) |req| { + if (req.headers) |headers| { + if (!headers.isEmpty()) { + result.headers = headers.cloneThis(ctx); + } + } + + result.method = req.method; + return result; + } + + if (response_init.as(Response)) |resp| { + return resp.init.clone(ctx); + } + } + + if (response_init.fastGet(ctx, .headers)) |headers| { + if (headers.as(FetchHeaders)) |orig| { + if (!orig.isEmpty()) { + result.headers = orig.cloneThis(ctx); + } + } else { + result.headers = FetchHeaders.createFromJS(ctx.ptr(), headers); + } + } + + if (response_init.fastGet(ctx, .status)) |status_value| { + const number = status_value.coerceToInt64(ctx); + if ((200 <= number and number < 600) or number == 101) { + result.status_code = @as(u16, @truncate(@as(u32, @intCast(number)))); + } else { + const err = ctx.createRangeErrorInstance("The status provided ({d}) must be 101 or in the range of [200, 599]", .{number}); + ctx.throwValue(err); + return null; + } + } + + if (response_init.fastGet(ctx, .statusText)) |status_text| { + result.status_text = bun.String.fromJS(status_text, ctx).dupeRef(); + } + + if (response_init.fastGet(ctx, .method)) |method_value| { + var method_str = method_value.toSlice(ctx, allocator); + defer method_str.deinit(); + if (method_str.len > 0) { + result.method = Method.which(method_str.slice()) orelse .GET; + } + } + + return result; + } + + pub fn deinit(this: *Init, _: std.mem.Allocator) void { + if (this.headers) |headers| { + this.headers = null; + + headers.deref(); + } + + this.status_text.deref(); + } + }; + + pub fn @"404"(globalThis: *JSC.JSGlobalObject) Response { + return emptyWithStatus(globalThis, 404); + } + + pub fn @"200"(globalThis: *JSC.JSGlobalObject) Response { + return emptyWithStatus(globalThis, 200); + } + + inline fn emptyWithStatus(globalThis: *JSC.JSGlobalObject, status: u16) Response { + var allocator = getAllocator(globalThis); + var response = allocator.create(Response) catch unreachable; + + response.* = Response{ + .body = Body{ + .value = Body.Value{ .Null = {} }, + }, + .init = Init{ + .status_code = status, + }, + .allocator = getAllocator(globalThis), + }; + + return response; + } }; const null_fd = bun.invalid_fd; @@ -778,27 +922,27 @@ pub const Fetch = struct { if (!success) { const err = this.onReject(); err.ensureStillAlive(); + // if we are streaming update with error + if (this.readable_stream_ref.get()) |readable| { + readable.ptr.Bytes.onData( + .{ + .err = .{ .JSValue = err }, + }, + bun.default_allocator, + ); + } + // if we are buffering resolve the promise if (this.response.get()) |response_js| { if (response_js.as(Response)) |response| { const body = response.body; - if (body.value == .Locked) { - if (body.value.Locked.readable) |readable| { - readable.ptr.Bytes.onData( - .{ - .err = .{ .JSValue = err }, - }, - bun.default_allocator, - ); - return; - } + if (body.value.Locked.promise) |promise_| { + const promise = promise_.asAnyPromise().?; + promise.reject(globalThis, err); } response.body.value.toErrorInstance(err, globalThis); - return; } } - - globalThis.throwValue(err); return; } @@ -1238,13 +1382,13 @@ pub const Fetch = struct { return Response{ .allocator = allocator, .url = bun.String.createAtomIfPossible(metadata.url), - .status_text = bun.String.createAtomIfPossible(http_response.status), .redirected = this.result.redirected, + .init = .{ + .headers = FetchHeaders.createFromPicoHeaders(http_response.headers), + .status_code = @as(u16, @truncate(http_response.status_code)), + .status_text = bun.String.createAtomIfPossible(http_response.status), + }, .body = .{ - .init = .{ - .headers = FetchHeaders.createFromPicoHeaders(http_response.headers), - .status_code = @as(u16, @truncate(http_response.status_code)), - }, .value = this.toBodyValue(), }, }; @@ -1488,15 +1632,15 @@ pub const Fetch = struct { response.* = Response{ .body = Body{ - .init = Body.Init{ - .status_code = 200, - }, .value = .{ .Blob = blob, }, }, + .init = Response.Init{ + .status_code = 200, + .status_text = bun.String.createAtom("OK"), + }, .allocator = allocator, - .status_text = bun.String.createAtom("OK"), .url = data_url.url.dupeRef(), }; @@ -1708,7 +1852,7 @@ pub const Fetch = struct { if (decompress.isBoolean()) { disable_decompression = !decompress.asBoolean(); } else if (decompress.isNumber()) { - disable_keepalive = decompress.to(i32) == 0; + disable_decompression = decompress.to(i32) == 0; } } @@ -1901,7 +2045,7 @@ pub const Fetch = struct { if (decompress.isBoolean()) { disable_decompression = !decompress.asBoolean(); } else if (decompress.isNumber()) { - disable_keepalive = decompress.to(i32) == 0; + disable_decompression = decompress.to(i32) == 0; } } @@ -2009,11 +2153,11 @@ pub const Fetch = struct { response.* = Response{ .body = Body{ - .init = Body.Init{ - .status_code = 200, - }, .value = .{ .Blob = bun_file }, }, + .init = Response.Init{ + .status_code = 200, + }, .allocator = bun.default_allocator, .url = file_url_string.clone(), }; diff --git a/src/bun.js/webcore/streams.zig b/src/bun.js/webcore/streams.zig index a578313d7..6c51daf94 100644 --- a/src/bun.js/webcore/streams.zig +++ b/src/bun.js/webcore/streams.zig @@ -225,6 +225,7 @@ pub const ReadableStream = struct { extern fn ReadableStream__isDisturbed(possibleReadableStream: JSValue, globalObject: *JSGlobalObject) bool; extern fn ReadableStream__isLocked(possibleReadableStream: JSValue, globalObject: *JSGlobalObject) bool; extern fn ReadableStream__empty(*JSGlobalObject) JSC.JSValue; + extern fn ReadableStream__used(*JSGlobalObject) JSC.JSValue; extern fn ReadableStream__cancel(stream: JSValue, *JSGlobalObject) void; extern fn ReadableStream__abort(stream: JSValue, *JSGlobalObject) void; extern fn ReadableStream__detach(stream: JSValue, *JSGlobalObject) void; @@ -367,6 +368,12 @@ pub const ReadableStream = struct { return ReadableStream__empty(globalThis); } + pub fn used(globalThis: *JSGlobalObject) JSC.JSValue { + JSC.markBinding(@src()); + + return ReadableStream__used(globalThis); + } + const Base = @import("../../ast/base.zig"); pub const StreamTag = enum(usize) { invalid = 0, @@ -2634,6 +2641,7 @@ pub fn HTTPServerWritable(comptime ssl: bool) type { } fn flushFromJSNoWait(this: *@This()) JSC.Node.Maybe(JSValue) { + log("flushFromJSNoWait", .{}); if (this.hasBackpressure() or this.done) { return .{ .result = JSValue.jsNumberFromInt32(0) }; } @@ -3595,6 +3603,9 @@ pub const ByteStream = struct { this.buffer = try std.ArrayList(u8).initCapacity(bun.default_allocator, chunk.len); this.buffer.appendSliceAssumeCapacity(chunk); }, + .err => { + this.pending.result = .{ .err = stream.err }; + }, else => unreachable, } return; @@ -3604,6 +3615,9 @@ pub const ByteStream = struct { .temporary_and_done, .temporary => { try this.buffer.appendSlice(chunk); }, + .err => { + this.pending.result = .{ .err = stream.err }; + }, // We don't support the rest of these yet else => unreachable, } @@ -3788,7 +3802,6 @@ pub const FIFO = struct { }, signal: JSC.WebCore.Signal = .{}, is_first_read: bool = true, - auto_close: bool = true, has_adjusted_pipe_size_on_linux: bool = false, drained: bool = true, @@ -3807,7 +3820,12 @@ pub const FIFO = struct { pub fn close(this: *FIFO) void { if (this.poll_ref) |poll| { this.poll_ref = null; - poll.deinit(); + if (comptime Environment.isLinux) { + // force target fd to be removed from epoll + poll.deinitForceUnregister(); + } else { + poll.deinit(); + } } const fd = this.fd; @@ -3815,8 +3833,7 @@ pub const FIFO = struct { defer if (signal_close) this.signal.close(null); if (signal_close) { this.fd = bun.invalid_fd; - if (this.auto_close) - _ = bun.sys.close(fd); + _ = bun.sys.close(fd); } this.to_read = null; @@ -3831,7 +3848,7 @@ pub const FIFO = struct { pub fn getAvailableToReadOnLinux(this: *FIFO) u32 { var len: c_int = 0; - const rc: c_int = std.c.ioctl(this.fd, std.os.linux.T.FIONREAD, &len); + const rc: c_int = std.c.ioctl(this.fd, std.os.linux.T.FIONREAD, @as(*c_int, &len)); if (rc != 0) { len = 0; } @@ -4198,10 +4215,15 @@ pub const File = struct { file: *Blob.FileStore, ) StreamStart { var file_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; - var auto_close = file.pathlike == .path; - var fd = if (!auto_close) - file.pathlike.fd + var fd = if (file.pathlike != .path) + // We will always need to close the file descriptor. + switch (Syscall.dup(@intCast(file.pathlike.fd))) { + .result => |_fd| _fd, + .err => |err| { + return .{ .err = err.withPath(file.pathlike.path.slice()) }; + }, + } else switch (Syscall.open(file.pathlike.path.sliceZ(&file_buf), std.os.O.RDONLY | std.os.O.NONBLOCK | std.os.O.CLOEXEC, 0)) { .result => |_fd| _fd, .err => |err| { @@ -4218,7 +4240,7 @@ pub const File = struct { } } - if (!auto_close and !(file.is_atty orelse false)) { + if (file.pathlike != .path and !(file.is_atty orelse false)) { if (comptime Environment.isWindows) { bun.todo(@src(), {}); } else { @@ -4229,7 +4251,6 @@ pub const File = struct { // if we do not, clone the descriptor and set non-blocking // it is important for us to clone it so we don't cause Weird Things to happen if ((flags & std.os.O.NONBLOCK) == 0) { - auto_close = true; fd = switch (Syscall.fcntl(fd, std.os.F.DUPFD, 0)) { .result => |_fd| @as(@TypeOf(fd), @intCast(_fd)), .err => |err| return .{ .err = err }, @@ -4249,24 +4270,18 @@ pub const File = struct { const stat: bun.Stat = switch (Syscall.fstat(fd)) { .result => |result| result, .err => |err| { - if (auto_close) { - _ = Syscall.close(fd); - } + _ = Syscall.close(fd); return .{ .err = err }; }, }; if (std.os.S.ISDIR(stat.mode)) { - if (auto_close) { - _ = Syscall.close(fd); - } + _ = Syscall.close(fd); return .{ .err = Syscall.Error.fromCode(.ISDIR, .fstat) }; } if (std.os.S.ISSOCK(stat.mode)) { - if (auto_close) { - _ = Syscall.close(fd); - } + _ = Syscall.close(fd); return .{ .err = Syscall.Error.fromCode(.INVAL, .fstat) }; } @@ -4292,9 +4307,7 @@ pub const File = struct { file.max_size = this.remaining_bytes; if (this.remaining_bytes == 0) { - if (auto_close) { - _ = Syscall.close(fd); - } + _ = Syscall.close(fd); return .{ .empty = {} }; } @@ -4303,7 +4316,6 @@ pub const File = struct { } this.fd = fd; - this.auto_close = auto_close; return StreamStart{ .ready = {} }; } @@ -4725,7 +4737,6 @@ pub const FileReader = struct { .readable = .{ .FIFO = .{ .fd = readable_file.fd, - .auto_close = readable_file.auto_close, .drained = this.buffered_data.len == 0, }, }, @@ -4885,7 +4896,7 @@ pub fn NewReadyWatcher( const fd = @as(c_int, @intCast(fd_)); std.debug.assert(@as(c_int, @intCast(this.poll_ref.?.fd)) == fd); std.debug.assert( - this.poll_ref.?.unregister(JSC.VirtualMachine.get().event_loop_handle.?) == .result, + this.poll_ref.?.unregister(JSC.VirtualMachine.get().event_loop_handle.?, false) == .result, ); } |