diff --git a/bench/crypto/primes.mjs b/bench/crypto/primes.mjs
new file mode 100644
index 0000000000..7398d60bf2
--- /dev/null
+++ b/bench/crypto/primes.mjs
@@ -0,0 +1,43 @@
+import { checkPrime, checkPrimeSync, generatePrime, generatePrimeSync } from "node:crypto";
+import { bench, run } from "../runner.mjs";
+
+const prime512 = generatePrimeSync(512);
+const prime2048 = generatePrimeSync(2048);
+
+bench("checkPrimeSync 512", () => {
+ return checkPrimeSync(prime512);
+});
+
+bench("checkPrimeSync 2048", () => {
+ return checkPrimeSync(prime2048);
+});
+
+bench("checkPrime 512", async () => {
+ const promises = Array.from({ length: 10 }, () => new Promise(resolve => checkPrime(prime512, resolve)));
+ await Promise.all(promises);
+});
+
+bench("checkPrime 2048", async () => {
+ const promises = Array.from({ length: 10 }, () => new Promise(resolve => checkPrime(prime2048, resolve)));
+ await Promise.all(promises);
+});
+
+bench("generatePrimeSync 512", () => {
+ return generatePrimeSync(512);
+});
+
+bench("generatePrimeSync 2048", () => {
+ return generatePrimeSync(2048);
+});
+
+bench("generatePrime 512", async () => {
+ const promises = Array.from({ length: 10 }, () => new Promise(resolve => generatePrime(512, resolve)));
+ await Promise.all(promises);
+});
+
+bench("generatePrime 2048", async () => {
+ const promises = Array.from({ length: 10 }, () => new Promise(resolve => generatePrime(2048, resolve)));
+ await Promise.all(promises);
+});
+
+await run();
diff --git a/src/bake/DevServer.zig b/src/bake/DevServer.zig
index b65c72a9ce..2a6bb81673 100644
--- a/src/bake/DevServer.zig
+++ b/src/bake/DevServer.zig
@@ -945,7 +945,7 @@ fn initServerRuntime(dev: *DevServer) void {
if (!interface.isObject()) @panic("Internal assertion failure: expected interface from HMR runtime to be an object");
const fetch_function = interface.get(dev.vm.global, "handleRequest") catch null orelse
@panic("Internal assertion failure: expected interface from HMR runtime to contain handleRequest");
- bun.assert(fetch_function.isCallable(dev.vm.jsc));
+ bun.assert(fetch_function.isCallable());
dev.server_fetch_function_callback = JSC.Strong.create(fetch_function, dev.vm.global);
const register_update = interface.get(dev.vm.global, "registerUpdate") catch null orelse
@panic("Internal assertion failure: expected interface from HMR runtime to contain registerUpdate");
diff --git a/src/bake/FrameworkRouter.zig b/src/bake/FrameworkRouter.zig
index 9c5954eafb..00ada78cba 100644
--- a/src/bake/FrameworkRouter.zig
+++ b/src/bake/FrameworkRouter.zig
@@ -430,7 +430,7 @@ pub const Style = union(enum) {
if (map.get(utf8.slice())) |style| {
return style;
}
- } else if (value.isCallable(global.vm())) {
+ } else if (value.isCallable()) {
return .{ .javascript_defined = JSC.Strong.create(value, global) };
}
diff --git a/src/bake/production.zig b/src/bake/production.zig
index 9e1fc0d59a..e4441ee5df 100644
--- a/src/bake/production.zig
+++ b/src/bake/production.zig
@@ -375,7 +375,7 @@ pub fn buildWithVm(ctx: bun.CLI.Command.Context, cwd: []const u8, vm: *VirtualMa
const server_render_func = brk: {
const raw = BakeGetOnModuleNamespace(global, server_entry_point, "prerender") orelse
break :brk null;
- if (!raw.isCallable(vm.jsc)) {
+ if (!raw.isCallable()) {
break :brk null;
}
break :brk raw;
@@ -391,7 +391,7 @@ pub fn buildWithVm(ctx: bun.CLI.Command.Context, cwd: []const u8, vm: *VirtualMa
brk: {
const raw = BakeGetOnModuleNamespace(global, server_entry_point, "getParams") orelse
break :brk null;
- if (!raw.isCallable(vm.jsc)) {
+ if (!raw.isCallable()) {
break :brk null;
}
break :brk raw;
diff --git a/src/bun.js/ConsoleObject.zig b/src/bun.js/ConsoleObject.zig
index e7202d4126..4c02d210dd 100644
--- a/src/bun.js/ConsoleObject.zig
+++ b/src/bun.js/ConsoleObject.zig
@@ -1238,7 +1238,7 @@ pub const Formatter = struct {
if (js_type.canGet() and js_type != .ProxyObject and !opts.disable_inspect_custom) {
// Attempt to get custom formatter
if (value.fastGet(globalThis, .inspectCustom)) |callback_value| {
- if (callback_value.isCallable(globalThis.vm())) {
+ if (callback_value.isCallable()) {
return .{
.tag = .{
.CustomFormattedObject = .{
@@ -1262,7 +1262,7 @@ pub const Formatter = struct {
// If we check an Object has a method table and it does not
// it will crash
- if (js_type != .Object and js_type != .ProxyObject and value.isCallable(globalThis.vm())) {
+ if (js_type != .Object and js_type != .ProxyObject and value.isCallable()) {
if (value.isClass(globalThis)) {
return .{
.tag = .{ .Class = {} },
@@ -2638,7 +2638,7 @@ pub const Formatter = struct {
} else if (JestPrettyFormat.printAsymmetricMatcher(this, Format, &writer, writer_, name_buf, value, enable_ansi_colors)) {
return;
} else if (jsType != .DOMWrapper) {
- if (value.isCallable(this.globalThis.vm())) {
+ if (value.isCallable()) {
return try this.printAs(.Function, Writer, writer_, value, jsType, enable_ansi_colors);
}
@@ -3038,7 +3038,7 @@ pub const Formatter = struct {
if (_tag.cell == .Symbol) {} else if (_tag.cell.isStringLike()) {
try type_value.toZigString(&tag_name_str, this.globalThis);
is_tag_kind_primitive = true;
- } else if (_tag.cell.isObject() or type_value.isCallable(this.globalThis.vm())) {
+ } else if (_tag.cell.isObject() or type_value.isCallable()) {
type_value.getNameProperty(this.globalThis, &tag_name_str);
if (tag_name_str.len == 0) {
tag_name_str = ZigString.init("NoName");
@@ -3136,15 +3136,15 @@ pub const Formatter = struct {
}
if (!this.single_line and (
- // count_without_children is necessary to prevent printing an extra newline
- // if there are children and one prop and the child prop is the last prop
+ // count_without_children is necessary to prevent printing an extra newline
+ // if there are children and one prop and the child prop is the last prop
props_iter.i + 1 < count_without_children and
- // 3 is arbitrary but basically
- //
- // ^ should be one line
- //
- // ^ should be multiple lines
- props_iter.i > 3))
+ // 3 is arbitrary but basically
+ //
+ // ^ should be one line
+ //
+ // ^ should be multiple lines
+ props_iter.i > 3))
{
writer.writeAll("\n");
this.writeIndent(Writer, writer_) catch unreachable;
@@ -3316,7 +3316,7 @@ pub const Formatter = struct {
if (iter.i == 0) {
if (value.isClass(this.globalThis))
try this.printAs(.Class, Writer, writer_, value, jsType, enable_ansi_colors)
- else if (value.isCallable(this.globalThis.vm()))
+ else if (value.isCallable())
try this.printAs(.Function, Writer, writer_, value, jsType, enable_ansi_colors)
else {
if (getObjectName(this.globalThis, value)) |name_str| {
diff --git a/src/bun.js/api/BunObject.zig b/src/bun.js/api/BunObject.zig
index bcf9566542..a162566d3a 100644
--- a/src/bun.js/api/BunObject.zig
+++ b/src/bun.js/api/BunObject.zig
@@ -587,7 +587,7 @@ pub fn registerMacro(globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFram
return globalObject.throwInvalidArguments("Internal error registering macros: invalid id", .{});
}
- if (!arguments[1].isCell() or !arguments[1].isCallable(globalObject.vm())) {
+ if (!arguments[1].isCell() or !arguments[1].isCallable()) {
// TODO: add "toTypeOf" helper
return globalObject.throw("Macro must be a function", .{});
}
diff --git a/src/bun.js/api/bun/h2_frame_parser.zig b/src/bun.js/api/bun/h2_frame_parser.zig
index 7a1501aab7..8f4aa64b8a 100644
--- a/src/bun.js/api/bun/h2_frame_parser.zig
+++ b/src/bun.js/api/bun/h2_frame_parser.zig
@@ -550,7 +550,7 @@ const Handlers = struct {
}
pub fn callWriteCallback(this: *Handlers, callback: JSC.JSValue, data: []const JSValue) bool {
- if (!callback.isCallable(this.globalObject.vm())) return false;
+ if (!callback.isCallable()) return false;
this.vm.eventLoop().runCallback(callback, this.globalObject, .undefined, data);
return true;
}
@@ -595,7 +595,7 @@ const Handlers = struct {
inline for (pairs) |pair| {
if (try opts.getTruthy(globalObject, pair.@"1")) |callback_value| {
- if (!callback_value.isCell() or !callback_value.isCallable(globalObject.vm())) {
+ if (!callback_value.isCell() or !callback_value.isCallable()) {
return globalObject.throwInvalidArguments("Expected \"{s}\" callback to be a function", .{pair[1]});
}
@@ -604,7 +604,7 @@ const Handlers = struct {
}
if (opts.fastGet(globalObject, .@"error")) |callback_value| {
- if (!callback_value.isCell() or !callback_value.isCallable(globalObject.vm())) {
+ if (!callback_value.isCell() or !callback_value.isCallable()) {
return globalObject.throwInvalidArguments("Expected \"error\" callback to be a function", .{});
}
@@ -1020,7 +1020,7 @@ pub const H2FrameParser = struct {
.len = @intCast(bytes.len),
// we need to clone this data to send it later
.buffer = if (bytes.len == 0) "" else client.allocator.alloc(u8, MAX_PAYLOAD_SIZE_WITHOUT_FRAME) catch bun.outOfMemory(),
- .callback = if (callback.isCallable(globalThis.vm())) JSC.Strong.create(callback, globalThis) else .empty,
+ .callback = if (callback.isCallable()) JSC.Strong.create(callback, globalThis) else .empty,
};
if (bytes.len > 0) {
@memcpy(frame.buffer[0..bytes.len], bytes);
diff --git a/src/bun.js/api/bun/socket.zig b/src/bun.js/api/bun/socket.zig
index 1d045304e9..ee56fc1d05 100644
--- a/src/bun.js/api/bun/socket.zig
+++ b/src/bun.js/api/bun/socket.zig
@@ -245,7 +245,7 @@ const Handlers = struct {
};
inline for (pairs) |pair| {
if (try opts.getTruthyComptime(globalObject, pair.@"1")) |callback_value| {
- if (!callback_value.isCell() or !callback_value.isCallable(globalObject.vm())) {
+ if (!callback_value.isCell() or !callback_value.isCallable()) {
return globalObject.throwInvalidArguments("Expected \"{s}\" callback to be a function", .{pair[1]});
}
diff --git a/src/bun.js/api/bun/subprocess.zig b/src/bun.js/api/bun/subprocess.zig
index fb19d960f0..93d4c9d10d 100644
--- a/src/bun.js/api/bun/subprocess.zig
+++ b/src/bun.js/api/bun/subprocess.zig
@@ -1599,9 +1599,9 @@ pub fn onProcessExit(this: *Subprocess, process: *Process, status: bun.spawn.Sta
if (this.on_exit_callback.trySwap()) |callback| {
const waitpid_value: JSValue =
if (status == .err)
- status.err.toJSC(globalThis)
- else
- .undefined;
+ status.err.toJSC(globalThis)
+ else
+ .undefined;
const this_value = if (this_jsvalue.isEmptyOrUndefinedOrNull()) .undefined else this_jsvalue;
this_value.ensureStillAlive();
@@ -1955,7 +1955,7 @@ pub fn spawnMaybeSync(
// This must run before the stdio parsing happens
if (!is_sync) {
if (try args.getTruthy(globalThis, "ipc")) |val| {
- if (val.isCell() and val.isCallable(globalThis.vm())) {
+ if (val.isCell() and val.isCallable()) {
maybe_ipc_mode = ipc_mode: {
if (try args.getTruthy(globalThis, "serialization")) |mode_val| {
if (mode_val.isString()) {
@@ -1989,7 +1989,7 @@ pub fn spawnMaybeSync(
}
if (try args.getTruthy(globalThis, "onDisconnect")) |onDisconnect_| {
- if (!onDisconnect_.isCell() or !onDisconnect_.isCallable(globalThis.vm())) {
+ if (!onDisconnect_.isCell() or !onDisconnect_.isCallable()) {
return globalThis.throwInvalidArguments("onDisconnect must be a function or undefined", .{});
}
@@ -2000,7 +2000,7 @@ pub fn spawnMaybeSync(
}
if (try args.getTruthy(globalThis, "onExit")) |onExit_| {
- if (!onExit_.isCell() or !onExit_.isCallable(globalThis.vm())) {
+ if (!onExit_.isCell() or !onExit_.isCallable()) {
return globalThis.throwInvalidArguments("onExit must be a function or undefined", .{});
}
diff --git a/src/bun.js/api/bun/udp_socket.zig b/src/bun.js/api/bun/udp_socket.zig
index 93965c51eb..d9043c6e17 100644
--- a/src/bun.js/api/bun/udp_socket.zig
+++ b/src/bun.js/api/bun/udp_socket.zig
@@ -197,7 +197,7 @@ pub const UDPSocketConfig = struct {
inline for (handlers) |handler| {
if (try socket.getTruthyComptime(globalThis, handler.@"0")) |value| {
- if (!value.isCell() or !value.isCallable(globalThis.vm())) {
+ if (!value.isCell() or !value.isCallable()) {
return globalThis.throwInvalidArguments("Expected \"socket.{s}\" to be a function", .{handler.@"0"});
}
@field(config, handler.@"1") = value;
diff --git a/src/bun.js/api/ffi.zig b/src/bun.js/api/ffi.zig
index ec9d7cafa8..61b878bfda 100644
--- a/src/bun.js/api/ffi.zig
+++ b/src/bun.js/api/ffi.zig
@@ -818,7 +818,7 @@ pub const FFI = struct {
return JSC.toInvalidArguments("Expected object", .{}, globalThis);
}
- if (js_callback.isEmptyOrUndefinedOrNull() or !js_callback.isCallable(globalThis.vm())) {
+ if (js_callback.isEmptyOrUndefinedOrNull() or !js_callback.isCallable()) {
return JSC.toInvalidArguments("Expected callback function", .{}, globalThis);
}
diff --git a/src/bun.js/api/html_rewriter.zig b/src/bun.js/api/html_rewriter.zig
index df253e0fbe..e22072c620 100644
--- a/src/bun.js/api/html_rewriter.zig
+++ b/src/bun.js/api/html_rewriter.zig
@@ -809,7 +809,7 @@ const DocumentHandler = struct {
}
if (try thisObject.get(global, "doctype")) |val| {
- if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
+ if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable()) {
return global.throwInvalidArguments("doctype must be a function", .{});
}
val.protect();
@@ -817,7 +817,7 @@ const DocumentHandler = struct {
}
if (try thisObject.get(global, "comments")) |val| {
- if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
+ if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable()) {
return global.throwInvalidArguments("comments must be a function", .{});
}
val.protect();
@@ -825,7 +825,7 @@ const DocumentHandler = struct {
}
if (try thisObject.get(global, "text")) |val| {
- if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
+ if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable()) {
return global.throwInvalidArguments("text must be a function", .{});
}
val.protect();
@@ -833,7 +833,7 @@ const DocumentHandler = struct {
}
if (try thisObject.get(global, "end")) |val| {
- if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
+ if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable()) {
return global.throwInvalidArguments("end must be a function", .{});
}
val.protect();
@@ -954,7 +954,7 @@ const ElementHandler = struct {
}
if (try thisObject.get(global, "element")) |val| {
- if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
+ if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable()) {
return global.throwInvalidArguments("element must be a function", .{});
}
val.protect();
@@ -962,7 +962,7 @@ const ElementHandler = struct {
}
if (try thisObject.get(global, "comments")) |val| {
- if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
+ if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable()) {
return global.throwInvalidArguments("comments must be a function", .{});
}
val.protect();
@@ -970,7 +970,7 @@ const ElementHandler = struct {
}
if (try thisObject.get(global, "text")) |val| {
- if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
+ if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable()) {
return global.throwInvalidArguments("text must be a function", .{});
}
val.protect();
@@ -1614,7 +1614,7 @@ pub const Element = struct {
) bun.JSError!JSValue {
if (this.element == null)
return JSValue.jsNull();
- if (function.isUndefinedOrNull() or !function.isCallable(globalObject.vm())) {
+ if (function.isUndefinedOrNull() or !function.isCallable()) {
return ZigString.init("Expected a function").withEncoding().toJS(globalObject);
}
diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig
index 3521dab350..f34a7f52ed 100644
--- a/src/bun.js/api/server.zig
+++ b/src/bun.js/api/server.zig
@@ -142,8 +142,8 @@ fn getContentType(headers: ?*JSC.FetchHeaders, blob: *const JSC.WebCore.AnyBlob,
content
else if (blob.wasString())
MimeType.text
- // TODO: should we get the mime type off of the Blob.Store if it exists?
- // A little wary of doing this right now due to causing some breaking change
+ // TODO: should we get the mime type off of the Blob.Store if it exists?
+ // A little wary of doing this right now due to causing some breaking change
else
MimeType.other;
};
@@ -1398,7 +1398,7 @@ pub const ServerConfig = struct {
continue;
}
- if (value.isCallable(global.vm())) {
+ if (value.isCallable()) {
try validateRouteName(global, path);
args.user_routes_to_build.append(.{
.route = .{
@@ -1424,7 +1424,7 @@ pub const ServerConfig = struct {
var found = false;
inline for (methods) |method| {
if (value.getOwn(global, @tagName(method))) |function| {
- if (!function.isCallable(global.vm())) {
+ if (!function.isCallable()) {
return global.throwInvalidArguments("Expected {s} in {} route to be a function", .{ @tagName(method), bun.fmt.quote(path) });
}
if (!found) {
@@ -1654,7 +1654,7 @@ pub const ServerConfig = struct {
if (global.hasException()) return error.JSError;
if (try arg.getTruthyComptime(global, "error")) |onError| {
- if (!onError.isCallable(global.vm())) {
+ if (!onError.isCallable()) {
return global.throwInvalidArguments("Expected error to be a function", .{});
}
const onErrorSnapshot = onError.withAsyncContextIfNeeded(global);
@@ -1664,7 +1664,7 @@ pub const ServerConfig = struct {
if (global.hasException()) return error.JSError;
if (try arg.getTruthy(global, "onNodeHTTPRequest")) |onRequest_| {
- if (!onRequest_.isCallable(global.vm())) {
+ if (!onRequest_.isCallable()) {
return global.throwInvalidArguments("Expected onNodeHTTPRequest to be a function", .{});
}
const onRequest = onRequest_.withAsyncContextIfNeeded(global);
@@ -1673,7 +1673,7 @@ pub const ServerConfig = struct {
}
if (try arg.getTruthy(global, "fetch")) |onRequest_| {
- if (!onRequest_.isCallable(global.vm())) {
+ if (!onRequest_.isCallable()) {
return global.throwInvalidArguments("Expected fetch() to be a function", .{});
}
const onRequest = onRequest_.withAsyncContextIfNeeded(global);
@@ -4608,13 +4608,12 @@ pub const WebSocketServer = struct {
}
pub fn fromJS(globalObject: *JSC.JSGlobalObject, object: JSC.JSValue) bun.JSError!Handler {
- const vm = globalObject.vm();
var handler = Handler{ .globalObject = globalObject, .vm = VirtualMachine.get() };
var valid = false;
if (try object.getTruthyComptime(globalObject, "message")) |message_| {
- if (!message_.isCallable(vm)) {
+ if (!message_.isCallable()) {
return globalObject.throwInvalidArguments("websocket expects a function for the message option", .{});
}
const message = message_.withAsyncContextIfNeeded(globalObject);
@@ -4624,7 +4623,7 @@ pub const WebSocketServer = struct {
}
if (try object.getTruthy(globalObject, "open")) |open_| {
- if (!open_.isCallable(vm)) {
+ if (!open_.isCallable()) {
return globalObject.throwInvalidArguments("websocket expects a function for the open option", .{});
}
const open = open_.withAsyncContextIfNeeded(globalObject);
@@ -4634,7 +4633,7 @@ pub const WebSocketServer = struct {
}
if (try object.getTruthy(globalObject, "close")) |close_| {
- if (!close_.isCallable(vm)) {
+ if (!close_.isCallable()) {
return globalObject.throwInvalidArguments("websocket expects a function for the close option", .{});
}
const close = close_.withAsyncContextIfNeeded(globalObject);
@@ -4644,7 +4643,7 @@ pub const WebSocketServer = struct {
}
if (try object.getTruthy(globalObject, "drain")) |drain_| {
- if (!drain_.isCallable(vm)) {
+ if (!drain_.isCallable()) {
return globalObject.throwInvalidArguments("websocket expects a function for the drain option", .{});
}
const drain = drain_.withAsyncContextIfNeeded(globalObject);
@@ -4654,7 +4653,7 @@ pub const WebSocketServer = struct {
}
if (try object.getTruthy(globalObject, "onError")) |onError_| {
- if (!onError_.isCallable(vm)) {
+ if (!onError_.isCallable()) {
return globalObject.throwInvalidArguments("websocket expects a function for the onError option", .{});
}
const onError = onError_.withAsyncContextIfNeeded(globalObject);
@@ -4663,7 +4662,7 @@ pub const WebSocketServer = struct {
}
if (try object.getTruthy(globalObject, "ping")) |cb| {
- if (!cb.isCallable(vm)) {
+ if (!cb.isCallable()) {
return globalObject.throwInvalidArguments("websocket expects a function for the ping option", .{});
}
handler.onPing = cb;
@@ -4672,7 +4671,7 @@ pub const WebSocketServer = struct {
}
if (try object.getTruthy(globalObject, "pong")) |cb| {
- if (!cb.isCallable(vm)) {
+ if (!cb.isCallable()) {
return globalObject.throwInvalidArguments("websocket expects a function for the pong option", .{});
}
handler.onPong = cb;
@@ -5558,7 +5557,7 @@ pub const ServerWebSocket = struct {
}
const callback = args.ptr[0];
- if (callback.isEmptyOrUndefinedOrNull() or !callback.isCallable(globalThis.vm())) {
+ if (callback.isEmptyOrUndefinedOrNull() or !callback.isCallable()) {
return globalThis.throwInvalidArgumentTypeValue("cork", "callback", callback);
}
@@ -6921,13 +6920,13 @@ pub const NodeHTTPResponse = struct {
const input_value = if (arguments.len > 0) arguments[0] else .undefined;
var encoding_value = if (arguments.len > 1) arguments[1] else .undefined;
const callback_value = brk: {
- if ((encoding_value != .null and encoding_value != .undefined) and encoding_value.isCallable(globalObject.vm())) {
+ if ((encoding_value != .null and encoding_value != .undefined) and encoding_value.isCallable()) {
encoding_value = .undefined;
break :brk arguments[1];
}
if (arguments.len > 2 and arguments[2] != .undefined) {
- if (!arguments[2].isCallable(globalObject.vm())) {
+ if (!arguments[2].isCallable()) {
return globalObject.throwInvalidArgumentTypeValue("callback", "function", arguments[2]);
}
@@ -7129,7 +7128,7 @@ pub const NodeHTTPResponse = struct {
return globalObject.throwNotEnoughArguments("cork", 1, 0);
}
- if (!arguments[0].isCallable(globalObject.vm())) {
+ if (!arguments[0].isCallable()) {
return globalObject.throwInvalidArgumentTypeValue("cork", "function", arguments[0]);
}
diff --git a/src/bun.js/bindings/JSValue.zig b/src/bun.js/bindings/JSValue.zig
index 32a31f80cc..93f20f7306 100644
--- a/src/bun.js/bindings/JSValue.zig
+++ b/src/bun.js/bindings/JSValue.zig
@@ -627,7 +627,7 @@ pub const JSValue = enum(i64) {
pub fn callNextTick(function: JSValue, global: *JSGlobalObject, args: anytype) void {
if (Environment.isDebug) {
- bun.assert(function.isCallable(global.vm()));
+ bun.assert(function.isCallable());
}
const num_args = @typeInfo(@TypeOf(args)).array.len;
switch (num_args) {
@@ -1398,8 +1398,8 @@ pub const JSValue = enum(i64) {
return cppFn("asCell", .{this});
}
- pub fn isCallable(this: JSValue, vm: *VM) bool {
- return cppFn("isCallable", .{ this, vm });
+ pub fn isCallable(this: JSValue) bool {
+ return cppFn("isCallable", .{this});
}
pub fn isException(this: JSValue, vm: *VM) bool {
@@ -1784,7 +1784,7 @@ pub const JSValue = enum(i64) {
return false;
const function = this.fastGet(global, BuiltinName.toString) orelse
return false;
- return function.isCell() and function.isCallable(global.vm());
+ return function.isCell() and function.isCallable();
}
// TODO: replace calls to this function with `getOptional`
@@ -2000,7 +2000,7 @@ pub const JSValue = enum(i64) {
pub fn getFunction(this: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8) JSError!?JSValue {
if (try this.getOptional(globalThis, property_name, JSValue)) |prop| {
- if (!prop.isCell() or !prop.isCallable(globalThis.vm())) {
+ if (!prop.isCell() or !prop.isCallable()) {
return globalThis.throwInvalidArguments(property_name ++ " must be a function", .{});
}
@@ -2012,7 +2012,7 @@ pub const JSValue = enum(i64) {
pub fn getOwnFunction(this: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8) JSError!?JSValue {
if (getOwnTruthy(this, globalThis, property_name)) |prop| {
- if (!prop.isCell() or !prop.isCallable(globalThis.vm())) {
+ if (!prop.isCell() or !prop.isCallable()) {
return globalThis.throwInvalidArguments(property_name ++ " must be a function", .{});
}
diff --git a/src/bun.js/bindings/NodeValidator.cpp b/src/bun.js/bindings/NodeValidator.cpp
index 408914d761..ba41b196b3 100644
--- a/src/bun.js/bindings/NodeValidator.cpp
+++ b/src/bun.js/bindings/NodeValidator.cpp
@@ -215,8 +215,8 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_checkRangesOrGetDefault, (JSC::JSGlobalObjec
JSC::EncodedJSValue V::validateFunction(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, ASCIILiteral name)
{
- if (JSC::getCallData(value).type == JSC::CallData::Type::None) {
- return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, name, "function"_s, value);
+ if (!value.isCallable()) {
+ return ERR::INVALID_ARG_TYPE(scope, globalObject, name, "function"_s, value);
}
return JSValue::encode(jsUndefined());
@@ -230,8 +230,8 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_validateFunction, (JSC::JSGlobalObject * glo
auto value = callFrame->argument(0);
auto name = callFrame->argument(1);
- if (JSC::getCallData(value).type == JSC::CallData::Type::None) {
- return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, name, "function"_s, value);
+ if (!value.isCallable()) {
+ return ERR::INVALID_ARG_TYPE(scope, globalObject, name, "function"_s, value);
}
return JSValue::encode(jsUndefined());
}
@@ -250,6 +250,14 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_validateBoolean, (JSC::JSGlobalObject * glob
return JSValue::encode(jsUndefined());
}
+JSC::EncodedJSValue V::validateBoolean(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, ASCIILiteral name)
+{
+ if (!value.isBoolean()) {
+ return Bun::ERR::INVALID_ARG_TYPE(scope, globalObject, name, "boolean"_s, value);
+ }
+ return JSValue::encode(jsUndefined());
+}
+
JSC_DEFINE_HOST_FUNCTION(jsFunction_validatePort, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
auto& vm = JSC::getVM(globalObject);
diff --git a/src/bun.js/bindings/NodeValidator.h b/src/bun.js/bindings/NodeValidator.h
index 5de8fe915b..3878ce6a88 100644
--- a/src/bun.js/bindings/NodeValidator.h
+++ b/src/bun.js/bindings/NodeValidator.h
@@ -49,6 +49,7 @@ JSC::EncodedJSValue validateInt32(JSC::ThrowScope& scope, JSC::JSGlobalObject* g
JSC::EncodedJSValue validateFunction(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, ASCIILiteral name);
JSC::EncodedJSValue validateOneOf(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, ASCIILiteral name, JSValue value, const WTF::Vector& oneOf);
JSC::EncodedJSValue validateObject(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, ASCIILiteral name);
+JSC::EncodedJSValue validateBoolean(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, ASCIILiteral name);
}
diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h
index 8ff2219f55..d94a173325 100644
--- a/src/bun.js/bindings/ZigGlobalObject.h
+++ b/src/bun.js/bindings/ZigGlobalObject.h
@@ -65,6 +65,8 @@ class EventTarget;
extern "C" void Bun__reportError(JSC__JSGlobalObject*, JSC__JSValue);
extern "C" void Bun__reportUnhandledError(JSC__JSGlobalObject*, JSC::EncodedJSValue);
+extern "C" bool Bun__VirtualMachine__isShuttingDown(void* /* BunVM */);
+
#if OS(WINDOWS)
#include
extern "C" uv_loop_t* Bun__ZigGlobalObject__uvLoop(void* /* BunVM */);
@@ -86,6 +88,11 @@ public:
// Move this to the front for better cache locality.
void* m_bunVM;
+ bool isShuttingDown() const
+ {
+ return Bun__VirtualMachine__isShuttingDown(m_bunVM);
+ }
+
static const JSC::ClassInfo s_info;
static const JSC::GlobalObjectMethodTable s_globalObjectMethodTable;
diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp
index 28361ac008..1009d36849 100644
--- a/src/bun.js/bindings/bindings.cpp
+++ b/src/bun.js/bindings/bindings.cpp
@@ -3655,7 +3655,7 @@ void JSC__JSValue__forEach(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, voi
});
}
-bool JSC__JSValue__isCallable(JSC__JSValue JSValue0, JSC__VM* arg1)
+bool JSC__JSValue__isCallable(JSC__JSValue JSValue0)
{
return JSC::JSValue::decode(JSValue0).isCallable();
}
diff --git a/src/bun.js/bindings/headers-handwritten.h b/src/bun.js/bindings/headers-handwritten.h
index 2f751c4448..37f17850fb 100644
--- a/src/bun.js/bindings/headers-handwritten.h
+++ b/src/bun.js/bindings/headers-handwritten.h
@@ -390,6 +390,9 @@ extern "C" size_t Bun__encoding__byteLengthUTF16AsUTF8(const UChar* ptr, size_t
extern "C" int64_t Bun__encoding__constructFromLatin1(void*, const unsigned char* ptr, size_t len, Encoding encoding);
extern "C" int64_t Bun__encoding__constructFromUTF16(void*, const UChar* ptr, size_t len, Encoding encoding);
+extern "C" void Bun__EventLoop__runCallback1(JSC::JSGlobalObject* global, JSC::EncodedJSValue callback, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue arg1);
+extern "C" void Bun__EventLoop__runCallback2(JSC::JSGlobalObject* global, JSC::EncodedJSValue callback, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue arg1, JSC::EncodedJSValue arg2);
+
/// @note throws a JS exception and returns false if a stack overflow occurs
template
bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSC::JSValue v1, JSC::JSValue v2, JSC::MarkedArgumentBuffer&, Vector, 16>& stack, JSC::ThrowScope* scope, bool addToStack);
diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h
index b7af9c4d9e..23de469423 100644
--- a/src/bun.js/bindings/headers.h
+++ b/src/bun.js/bindings/headers.h
@@ -342,7 +342,7 @@ CPP_DECL bool JSC__JSValue__isAnyError(JSC__JSValue JSValue0);
CPP_DECL bool JSC__JSValue__isAnyInt(JSC__JSValue JSValue0);
CPP_DECL bool JSC__JSValue__isBigInt(JSC__JSValue JSValue0);
CPP_DECL bool JSC__JSValue__isBigInt32(JSC__JSValue JSValue0);
-CPP_DECL bool JSC__JSValue__isCallable(JSC__JSValue JSValue0, JSC__VM* arg1);
+CPP_DECL bool JSC__JSValue__isCallable(JSC__JSValue JSValue0);
CPP_DECL bool JSC__JSValue__isClass(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1);
CPP_DECL bool JSC__JSValue__isConstructor(JSC__JSValue JSValue0);
CPP_DECL bool JSC__JSValue__isCustomGetterSetter(JSC__JSValue JSValue0);
diff --git a/src/bun.js/bindings/headers.zig b/src/bun.js/bindings/headers.zig
index ad07e315c7..54b73959fe 100644
--- a/src/bun.js/bindings/headers.zig
+++ b/src/bun.js/bindings/headers.zig
@@ -166,7 +166,7 @@ pub extern fn JSC__JSValue__isAnyError(JSValue0: JSC__JSValue) bool;
pub extern fn JSC__JSValue__isAnyInt(JSValue0: JSC__JSValue) bool;
pub extern fn JSC__JSValue__isBigInt(JSValue0: JSC__JSValue) bool;
pub extern fn JSC__JSValue__isBigInt32(JSValue0: JSC__JSValue) bool;
-pub extern fn JSC__JSValue__isCallable(JSValue0: JSC__JSValue, arg1: *bindings.VM) bool;
+pub extern fn JSC__JSValue__isCallable(JSValue0: JSC__JSValue) bool;
pub extern fn JSC__JSValue__isClass(JSValue0: JSC__JSValue, arg1: *bindings.JSGlobalObject) bool;
pub extern fn JSC__JSValue__isConstructor(JSValue0: JSC__JSValue) bool;
pub extern fn JSC__JSValue__isCustomGetterSetter(JSValue0: JSC__JSValue) bool;
diff --git a/src/bun.js/bindings/ncrypto.h b/src/bun.js/bindings/ncrypto.h
index 81085497d4..c5d9d3f16b 100644
--- a/src/bun.js/bindings/ncrypto.h
+++ b/src/bun.js/bindings/ncrypto.h
@@ -504,7 +504,7 @@ public:
return static_cast(data_);
}
- inline std::span span() const { return { get(), len_ }; }
+ inline std::span span() const { return { get(), len_ }; }
inline size_t size() const noexcept { return len_; }
void reset(void* data = nullptr, size_t len = 0);
void reset(const Buffer& buffer);
diff --git a/src/bun.js/bindings/node/crypto/CryptoPrimes.cpp b/src/bun.js/bindings/node/crypto/CryptoPrimes.cpp
new file mode 100644
index 0000000000..72fadb6cae
--- /dev/null
+++ b/src/bun.js/bindings/node/crypto/CryptoPrimes.cpp
@@ -0,0 +1,510 @@
+#include "CryptoPrimes.h"
+#include "KeyObject.h"
+#include "ErrorCode.h"
+#include "helpers.h"
+#include "CryptoUtil.h"
+#include "NodeValidator.h"
+
+CheckPrimeJobCtx::CheckPrimeJobCtx(ncrypto::BignumPointer candidate, int32_t checks, JSValue callback)
+ : m_candidate(WTFMove(candidate))
+ , m_checks(checks)
+ , m_callback(callback)
+{
+ gcProtect(m_callback);
+}
+
+CheckPrimeJobCtx::~CheckPrimeJobCtx()
+{
+ gcUnprotect(m_callback);
+}
+
+extern "C" void Bun__CheckPrimeJobCtx__runTask(CheckPrimeJobCtx* ctx, JSGlobalObject* lexicalGlobalObject)
+{
+ ctx->runTask(lexicalGlobalObject);
+}
+void CheckPrimeJobCtx::runTask(JSGlobalObject* lexicalGlobalObject)
+{
+ auto* globalObject = defaultGlobalObject(lexicalGlobalObject);
+
+ auto res = m_candidate.isPrime(m_checks, [globalObject](int32_t a, int32_t b) -> bool {
+ // TODO(dylan-conway): needs to be thread safe!!!!!!!!
+ return !globalObject->isShuttingDown();
+ });
+
+ m_result = res != 0;
+}
+
+extern "C" void Bun__CheckPrimeJobCtx__runFromJS(CheckPrimeJobCtx* ctx, JSGlobalObject* lexicalGlobalObject)
+{
+ ctx->runFromJS(lexicalGlobalObject);
+}
+void CheckPrimeJobCtx::runFromJS(JSGlobalObject* lexicalGlobalObject)
+{
+ Bun__EventLoop__runCallback2(lexicalGlobalObject, JSValue::encode(m_callback), JSValue::encode(jsUndefined()), JSValue::encode(jsUndefined()), JSValue::encode(jsBoolean(m_result)));
+}
+
+extern "C" void Bun__CheckPrimeJobCtx__deinit(CheckPrimeJobCtx* ctx)
+{
+ ctx->deinit();
+}
+void CheckPrimeJobCtx::deinit()
+{
+ delete this;
+}
+
+extern "C" CheckPrimeJob* Bun__CheckPrimeJob__create(JSGlobalObject*, CheckPrimeJobCtx*);
+CheckPrimeJob* CheckPrimeJob::create(JSGlobalObject* globalObject, ncrypto::BignumPointer candidate, int32_t checks, JSValue callback)
+{
+ CheckPrimeJobCtx* ctx = new CheckPrimeJobCtx(WTFMove(candidate), checks, callback);
+ return Bun__CheckPrimeJob__create(globalObject, ctx);
+}
+
+extern "C" void Bun__CheckPrimeJob__schedule(CheckPrimeJob*);
+void CheckPrimeJob::schedule()
+{
+ Bun__CheckPrimeJob__schedule(this);
+}
+
+extern "C" void Bun__CheckPrimeJob__createAndSchedule(JSGlobalObject*, CheckPrimeJobCtx*);
+void CheckPrimeJob::createAndSchedule(JSGlobalObject* globalObject, ncrypto::BignumPointer candidate, int32_t checks, JSValue callback)
+{
+ CheckPrimeJobCtx* ctx = new CheckPrimeJobCtx(WTFMove(candidate), checks, callback);
+ return Bun__CheckPrimeJob__createAndSchedule(globalObject, ctx);
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsCheckPrimeSync, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ JSValue candidateValue = callFrame->argument(0);
+
+ if (candidateValue.isBigInt()) {
+ candidateValue = unsignedBigIntToBuffer(lexicalGlobalObject, scope, candidateValue, "candidate"_s);
+ RETURN_IF_EXCEPTION(scope, {});
+ }
+
+ auto* candidateView = getArrayBufferOrView(lexicalGlobalObject, scope, candidateValue, "candidate"_s, jsUndefined());
+ RETURN_IF_EXCEPTION(scope, {});
+
+ JSValue optionsValue = callFrame->argument(1);
+ if (!optionsValue.isUndefined()) {
+ V::validateObject(scope, lexicalGlobalObject, optionsValue, "options"_s);
+ RETURN_IF_EXCEPTION(scope, {});
+ }
+
+ int32_t checks = 0;
+ if (optionsValue.isObject()) {
+ JSObject* options = optionsValue.getObject();
+ JSValue checksValue = options->get(lexicalGlobalObject, Identifier::fromString(vm, "checks"_s));
+ RETURN_IF_EXCEPTION(scope, {});
+
+ if (!checksValue.isUndefined()) {
+ V::validateInt32(scope, lexicalGlobalObject, checksValue, "options.checks"_s, jsNumber(0), jsUndefined(), &checks);
+ RETURN_IF_EXCEPTION(scope, {});
+ }
+ }
+
+ ncrypto::BignumPointer candidate = ncrypto::BignumPointer(reinterpret_cast(candidateView->vector()), candidateView->byteLength());
+ if (!candidate) {
+ throwCryptoError(lexicalGlobalObject, scope, ERR_get_error(), "BignumPointer"_s);
+ return JSValue::encode({});
+ }
+
+ auto* globalObject = defaultGlobalObject(lexicalGlobalObject);
+
+ auto res = candidate.isPrime(checks, [globalObject](int32_t a, int32_t b) -> bool {
+ return !globalObject->isShuttingDown();
+ });
+
+ return JSValue::encode(jsBoolean(res != 0));
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsCheckPrime, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ JSValue candidateValue = callFrame->argument(0);
+ if (candidateValue.isBigInt()) {
+ candidateValue = unsignedBigIntToBuffer(lexicalGlobalObject, scope, candidateValue, "candidate"_s);
+ RETURN_IF_EXCEPTION(scope, JSValue::encode({}));
+ }
+
+ auto* candidateView = jsDynamicCast(candidateValue);
+ if (!candidateView) {
+ return ERR::INVALID_ARG_TYPE(scope, lexicalGlobalObject, "candidate"_s, "ArrayBuffer, TypedArray, Buffer, DataView, or bigint"_s, candidateValue);
+ }
+
+ JSValue optionsValue = callFrame->argument(1);
+ JSValue callback = callFrame->argument(2);
+ if (optionsValue.isCallable()) {
+ callback = optionsValue;
+ optionsValue = jsUndefined();
+ }
+
+ V::validateFunction(scope, lexicalGlobalObject, callback, "callback"_s);
+ RETURN_IF_EXCEPTION(scope, JSValue::encode({}));
+
+ if (!optionsValue.isUndefined()) {
+ V::validateObject(scope, lexicalGlobalObject, optionsValue, "options"_s);
+ RETURN_IF_EXCEPTION(scope, JSValue::encode({}));
+ }
+
+ int32_t checks = 0;
+ if (optionsValue.isObject()) {
+ JSObject* options = optionsValue.getObject();
+ JSValue checksValue = options->get(lexicalGlobalObject, Identifier::fromString(vm, "checks"_s));
+ RETURN_IF_EXCEPTION(scope, JSValue::encode({}));
+
+ if (!checksValue.isUndefined()) {
+ V::validateInt32(scope, lexicalGlobalObject, checksValue, "options.checks"_s, jsNumber(0), jsUndefined(), &checks);
+ RETURN_IF_EXCEPTION(scope, JSValue::encode({}));
+ }
+ }
+
+ ncrypto::BignumPointer candidate = ncrypto::BignumPointer(reinterpret_cast(candidateView->vector()), candidateView->byteLength());
+ if (!candidate) {
+ throwCryptoError(lexicalGlobalObject, scope, ERR_get_error(), "BignumPointer"_s);
+ return JSValue::encode({});
+ }
+
+ CheckPrimeJob::createAndSchedule(lexicalGlobalObject, WTFMove(candidate), checks, callback);
+
+ return JSValue::encode(jsUndefined());
+}
+
+GeneratePrimeJobCtx::GeneratePrimeJobCtx(int32_t size, bool safe, ncrypto::BignumPointer prime, ncrypto::BignumPointer add, ncrypto::BignumPointer rem, bool bigint, JSValue callback)
+ : m_size(size)
+ , m_safe(safe)
+ , m_bigint(bigint)
+ , m_add(WTFMove(add))
+ , m_rem(WTFMove(rem))
+ , m_prime(WTFMove(prime))
+ , m_callback(callback)
+{
+ gcProtect(m_callback);
+}
+
+GeneratePrimeJobCtx::~GeneratePrimeJobCtx()
+{
+ gcUnprotect(m_callback);
+}
+
+extern "C" void Bun__GeneratePrimeJobCtx__runTask(GeneratePrimeJobCtx* ctx, JSGlobalObject* lexicalGlobalObject)
+{
+ ctx->runTask(lexicalGlobalObject);
+}
+void GeneratePrimeJobCtx::runTask(JSGlobalObject* lexicalGlobalObject)
+{
+ auto* globalObject = defaultGlobalObject(lexicalGlobalObject);
+
+ m_prime.generate({ .bits = m_size, .safe = m_safe, .add = m_add, .rem = m_rem }, [globalObject](int32_t a, int32_t b) -> bool {
+ // TODO(dylan-conway): needs to be thread safe!!!!!!!!
+ return !globalObject->isShuttingDown();
+ });
+}
+
+extern "C" void Bun__GeneratePrimeJobCtx__runFromJS(GeneratePrimeJobCtx* ctx, JSGlobalObject* lexicalGlobalObject)
+{
+ ctx->runFromJS(lexicalGlobalObject);
+}
+void GeneratePrimeJobCtx::runFromJS(JSGlobalObject* lexicalGlobalObject)
+{
+ auto& vm = lexicalGlobalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ if (m_bigint) {
+ ncrypto::DataPointer primeHex = m_prime.toHex();
+ if (!primeHex) {
+ JSObject* err = createOutOfMemoryError(lexicalGlobalObject, "could not generate prime"_s);
+ Bun__EventLoop__runCallback1(lexicalGlobalObject, JSValue::encode(m_callback), JSValue::encode(jsUndefined()), JSValue::encode(err));
+ return;
+ }
+
+ JSValue result = JSBigInt::parseInt(lexicalGlobalObject, vm, primeHex.span(), 16, JSBigInt::ErrorParseMode::IgnoreExceptions, JSBigInt::ParseIntSign::Unsigned);
+ if (result.isEmpty()) {
+ JSObject* err = createError(lexicalGlobalObject, ErrorCode::ERR_CRYPTO_OPERATION_FAILED, "could not generate prime"_s);
+ Bun__EventLoop__runCallback1(lexicalGlobalObject, JSValue::encode(m_callback), JSValue::encode(jsUndefined()), JSValue::encode(err));
+ return;
+ }
+
+ Bun__EventLoop__runCallback2(lexicalGlobalObject, JSValue::encode(m_callback), JSValue::encode(jsUndefined()), JSValue::encode(jsUndefined()), JSValue::encode(result));
+ return;
+ }
+
+ auto* globalObject = defaultGlobalObject(lexicalGlobalObject);
+
+ JSC::JSUint8Array* result = JSC::JSUint8Array::createUninitialized(lexicalGlobalObject, globalObject->JSBufferSubclassStructure(), m_prime.byteLength());
+ if (!result) {
+ JSObject* err = createOutOfMemoryError(lexicalGlobalObject, "could not generate prime"_s);
+ Bun__EventLoop__runCallback1(lexicalGlobalObject, JSValue::encode(m_callback), JSValue::encode(jsUndefined()), JSValue::encode(err));
+ return;
+ }
+
+ ncrypto::BignumPointer::EncodePaddedInto(m_prime.get(), reinterpret_cast(result->vector()), result->byteLength());
+
+ Bun__EventLoop__runCallback2(lexicalGlobalObject, JSValue::encode(m_callback), JSValue::encode(jsUndefined()), JSValue::encode(jsUndefined()), JSValue::encode(result));
+}
+
+extern "C" void Bun__GeneratePrimeJobCtx__deinit(GeneratePrimeJobCtx* ctx)
+{
+ ctx->deinit();
+}
+void GeneratePrimeJobCtx::deinit()
+{
+ delete this;
+}
+
+extern "C" GeneratePrimeJob* Bun__GeneratePrimeJob__create(JSGlobalObject*, GeneratePrimeJobCtx*);
+GeneratePrimeJob* GeneratePrimeJob::create(JSGlobalObject* globalObject, int32_t size, bool safe, ncrypto::BignumPointer prime, ncrypto::BignumPointer add, ncrypto::BignumPointer rem, bool bigint, JSValue callback)
+{
+ GeneratePrimeJobCtx* ctx = new GeneratePrimeJobCtx(size, safe, WTFMove(prime), WTFMove(add), WTFMove(rem), bigint, callback);
+ return Bun__GeneratePrimeJob__create(globalObject, ctx);
+}
+
+extern "C" void Bun__GeneratePrimeJob__schedule(GeneratePrimeJob*);
+void GeneratePrimeJob::schedule()
+{
+ Bun__GeneratePrimeJob__schedule(this);
+}
+
+extern "C" void Bun__GeneratePrimeJob__createAndSchedule(JSGlobalObject*, GeneratePrimeJobCtx*);
+void GeneratePrimeJob::createAndSchedule(JSGlobalObject* globalObject, int32_t size, bool safe, ncrypto::BignumPointer prime, ncrypto::BignumPointer add, ncrypto::BignumPointer rem, bool bigint, JSValue callback)
+{
+ GeneratePrimeJobCtx* ctx = new GeneratePrimeJobCtx(size, safe, WTFMove(prime), WTFMove(add), WTFMove(rem), bigint, callback);
+ Bun__GeneratePrimeJob__createAndSchedule(globalObject, ctx);
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsGeneratePrime, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ JSValue sizeValue = callFrame->argument(0);
+ int32_t size = 0;
+ V::validateInt32(scope, lexicalGlobalObject, sizeValue, "size"_s, jsNumber(1), jsUndefined(), &size);
+ RETURN_IF_EXCEPTION(scope, {});
+
+ JSValue optionsValue = callFrame->argument(1);
+ JSValue callback = callFrame->argument(2);
+ if (optionsValue.isCallable()) {
+ callback = optionsValue;
+ optionsValue = jsUndefined();
+ }
+ V::validateFunction(scope, lexicalGlobalObject, callback, "callback"_s);
+ RETURN_IF_EXCEPTION(scope, {});
+
+ if (!optionsValue.isUndefined()) {
+ V::validateObject(scope, lexicalGlobalObject, optionsValue, "options"_s);
+ RETURN_IF_EXCEPTION(scope, {});
+ }
+
+ bool safe = false;
+ bool bigint = false;
+ JSValue addValue = jsUndefined();
+ JSValue remValue = jsUndefined();
+ if (optionsValue.isObject()) {
+ JSObject* options = optionsValue.getObject();
+
+ JSValue safeValue = options->get(lexicalGlobalObject, Identifier::fromString(vm, "safe"_s));
+ RETURN_IF_EXCEPTION(scope, {});
+ JSValue bigintValue = options->get(lexicalGlobalObject, Identifier::fromString(vm, "bigint"_s));
+ RETURN_IF_EXCEPTION(scope, {});
+ addValue = options->get(lexicalGlobalObject, Identifier::fromString(vm, "add"_s));
+ RETURN_IF_EXCEPTION(scope, {});
+ remValue = options->get(lexicalGlobalObject, Identifier::fromString(vm, "rem"_s));
+ RETURN_IF_EXCEPTION(scope, {});
+
+ if (!safeValue.isUndefined()) {
+ V::validateBoolean(scope, lexicalGlobalObject, safeValue, "options.safe"_s);
+ RETURN_IF_EXCEPTION(scope, {});
+ safe = safeValue.asBoolean();
+ }
+
+ if (!bigintValue.isUndefined()) {
+ V::validateBoolean(scope, lexicalGlobalObject, bigintValue, "options.bigint"_s);
+ RETURN_IF_EXCEPTION(scope, {});
+ bigint = bigintValue.asBoolean();
+ }
+ }
+
+ ncrypto::ClearErrorOnReturn clear;
+
+ ncrypto::BignumPointer add;
+ if (!addValue.isUndefined()) {
+ if (addValue.isBigInt()) {
+ addValue = unsignedBigIntToBuffer(lexicalGlobalObject, scope, addValue, "options.add"_s);
+ RETURN_IF_EXCEPTION(scope, {});
+ }
+ auto* addView = jsDynamicCast(addValue);
+ if (!addView) {
+ return ERR::INVALID_ARG_TYPE(scope, lexicalGlobalObject, "options.add"_s, "ArrayBuffer, Buffer, TypedArray, DataView, or bigint"_s, addValue);
+ }
+ add.reset(reinterpret_cast(addView->vector()), addView->byteLength());
+ if (!add) {
+ return ERR::CRYPTO_OPERATION_FAILED(scope, lexicalGlobalObject, "could not generate prime"_s);
+ }
+ }
+
+ ncrypto::BignumPointer rem;
+ if (!remValue.isUndefined()) {
+ if (remValue.isBigInt()) {
+ remValue = unsignedBigIntToBuffer(lexicalGlobalObject, scope, remValue, "options.rem"_s);
+ RETURN_IF_EXCEPTION(scope, {});
+ }
+ auto* remView = jsDynamicCast(remValue);
+ if (!remView) {
+ return ERR::INVALID_ARG_TYPE(scope, lexicalGlobalObject, "options.rem"_s, "ArrayBuffer, Buffer, TypedArray, DataView, or bigint"_s, remValue);
+ }
+ rem.reset(reinterpret_cast(remView->vector()), remView->byteLength());
+ if (!rem) {
+ return ERR::CRYPTO_OPERATION_FAILED(scope, lexicalGlobalObject, "could not generate prime"_s);
+ }
+ }
+
+ if (add) {
+ if (UNLIKELY(ncrypto::BignumPointer::GetBitCount(add.get()) > size)) {
+ throwError(lexicalGlobalObject, scope, ErrorCode::ERR_OUT_OF_RANGE, "invalid options.add"_s);
+ return JSValue::encode({});
+ }
+
+ if (UNLIKELY(rem && add <= rem)) {
+ throwError(lexicalGlobalObject, scope, ErrorCode::ERR_OUT_OF_RANGE, "invalid options.rem"_s);
+ return JSValue::encode({});
+ }
+ }
+
+ ncrypto::BignumPointer prime = ncrypto::BignumPointer::NewSecure();
+ if (!prime) {
+ return ERR::CRYPTO_OPERATION_FAILED(scope, lexicalGlobalObject, "could not generate prime"_s);
+ }
+
+ GeneratePrimeJob::createAndSchedule(lexicalGlobalObject, size, safe, WTFMove(prime), WTFMove(add), WTFMove(rem), bigint, callback);
+
+ return JSValue::encode(jsUndefined());
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsGeneratePrimeSync, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ JSValue sizeValue = callFrame->argument(0);
+ int32_t size = 0;
+ V::validateInt32(scope, lexicalGlobalObject, sizeValue, "size"_s, jsNumber(1), jsUndefined(), &size);
+ RETURN_IF_EXCEPTION(scope, {});
+
+ JSValue optionsValue = callFrame->argument(1);
+ if (!optionsValue.isUndefined()) {
+ V::validateObject(scope, lexicalGlobalObject, optionsValue, "options"_s);
+ RETURN_IF_EXCEPTION(scope, {});
+ }
+
+ bool safe = false;
+ bool bigint = false;
+ JSValue addValue = jsUndefined();
+ JSValue remValue = jsUndefined();
+ if (optionsValue.isObject()) {
+ JSObject* options = optionsValue.getObject();
+
+ JSValue safeValue = options->get(lexicalGlobalObject, Identifier::fromString(vm, "safe"_s));
+ RETURN_IF_EXCEPTION(scope, {});
+ JSValue bigintValue = options->get(lexicalGlobalObject, Identifier::fromString(vm, "bigint"_s));
+ RETURN_IF_EXCEPTION(scope, {});
+ addValue = options->get(lexicalGlobalObject, Identifier::fromString(vm, "add"_s));
+ RETURN_IF_EXCEPTION(scope, {});
+ remValue = options->get(lexicalGlobalObject, Identifier::fromString(vm, "rem"_s));
+ RETURN_IF_EXCEPTION(scope, {});
+
+ if (!safeValue.isUndefined()) {
+ V::validateBoolean(scope, lexicalGlobalObject, safeValue, "options.safe"_s);
+ RETURN_IF_EXCEPTION(scope, {});
+ safe = safeValue.asBoolean();
+ }
+
+ if (!bigintValue.isUndefined()) {
+ V::validateBoolean(scope, lexicalGlobalObject, bigintValue, "options.bigint"_s);
+ RETURN_IF_EXCEPTION(scope, {});
+ bigint = bigintValue.asBoolean();
+ }
+ }
+
+ ncrypto::ClearErrorOnReturn clear;
+
+ ncrypto::BignumPointer add;
+ if (!addValue.isUndefined()) {
+ if (addValue.isBigInt()) {
+ addValue = unsignedBigIntToBuffer(lexicalGlobalObject, scope, addValue, "options.add"_s);
+ RETURN_IF_EXCEPTION(scope, {});
+ }
+ auto* addView = jsDynamicCast(addValue);
+ if (!addView) {
+ return ERR::INVALID_ARG_TYPE(scope, lexicalGlobalObject, "options.add"_s, "ArrayBuffer, Buffer, TypedArray, DataView, or bigint"_s, addValue);
+ }
+ add.reset(reinterpret_cast(addView->vector()), addView->byteLength());
+ if (!add) {
+ return ERR::CRYPTO_OPERATION_FAILED(scope, lexicalGlobalObject, "could not generate prime"_s);
+ }
+ }
+
+ ncrypto::BignumPointer rem;
+ if (!remValue.isUndefined()) {
+ if (remValue.isBigInt()) {
+ remValue = unsignedBigIntToBuffer(lexicalGlobalObject, scope, remValue, "options.rem"_s);
+ RETURN_IF_EXCEPTION(scope, {});
+ }
+ auto* remView = jsDynamicCast(remValue);
+ if (!remView) {
+ return ERR::INVALID_ARG_TYPE(scope, lexicalGlobalObject, "options.rem"_s, "ArrayBuffer, Buffer, TypedArray, DataView, or bigint"_s, remValue);
+ }
+ rem.reset(reinterpret_cast(remView->vector()), remView->byteLength());
+ if (!rem) {
+ return ERR::CRYPTO_OPERATION_FAILED(scope, lexicalGlobalObject, "could not generate prime"_s);
+ }
+ }
+
+ if (add) {
+ if (UNLIKELY(ncrypto::BignumPointer::GetBitCount(add.get()) > size)) {
+ throwError(lexicalGlobalObject, scope, ErrorCode::ERR_OUT_OF_RANGE, "invalid options.add"_s);
+ return JSValue::encode({});
+ }
+
+ if (UNLIKELY(rem && add <= rem)) {
+ throwError(lexicalGlobalObject, scope, ErrorCode::ERR_OUT_OF_RANGE, "invalid options.rem"_s);
+ return JSValue::encode({});
+ }
+ }
+
+ ncrypto::BignumPointer prime = ncrypto::BignumPointer::NewSecure();
+ if (!prime) {
+ return ERR::CRYPTO_OPERATION_FAILED(scope, lexicalGlobalObject, "could not generate prime"_s);
+ }
+
+ auto* globalObject = defaultGlobalObject(lexicalGlobalObject);
+
+ prime.generate({ .bits = size, .safe = safe, .add = add, .rem = rem }, [globalObject](int32_t a, int32_t b) -> bool {
+ return !globalObject->isShuttingDown();
+ });
+
+ if (bigint) {
+ ncrypto::DataPointer primeHex = prime.toHex();
+ if (!primeHex) {
+ throwOutOfMemoryError(lexicalGlobalObject, scope, "could not generate prime"_s);
+ return JSValue::encode({});
+ }
+
+ return JSValue::encode(JSBigInt::parseInt(lexicalGlobalObject, vm, primeHex.span(), 16, JSBigInt::ErrorParseMode::ThrowExceptions,
+ JSBigInt::ParseIntSign::Unsigned));
+ }
+
+ JSC::JSUint8Array* result = JSC::JSUint8Array::createUninitialized(lexicalGlobalObject, globalObject->JSBufferSubclassStructure(), prime.byteLength());
+ if (!result) {
+ throwOutOfMemoryError(lexicalGlobalObject, scope, "could not generate prime"_s);
+ return JSValue::encode({});
+ }
+
+ ncrypto::BignumPointer::EncodePaddedInto(prime.get(), reinterpret_cast(result->vector()), result->byteLength());
+
+ return JSValue::encode(result);
+}
diff --git a/src/bun.js/bindings/node/crypto/CryptoPrimes.h b/src/bun.js/bindings/node/crypto/CryptoPrimes.h
new file mode 100644
index 0000000000..8f910cfc00
--- /dev/null
+++ b/src/bun.js/bindings/node/crypto/CryptoPrimes.h
@@ -0,0 +1,73 @@
+#pragma once
+
+#include "root.h"
+#include "helpers.h"
+#include "ncrypto.h"
+
+using namespace JSC;
+using namespace Bun;
+
+struct CheckPrimeJobCtx {
+ CheckPrimeJobCtx(ncrypto::BignumPointer candidate, int32_t checks, JSValue callback);
+ ~CheckPrimeJobCtx();
+
+ void runTask(JSGlobalObject* lexicalGlobalObject);
+ void runFromJS(JSGlobalObject* lexicalGlobalObject);
+ void deinit();
+
+ int32_t m_checks;
+ JSValue m_callback;
+ ncrypto::BignumPointer m_candidate;
+
+ bool m_result { false };
+
+ WTF_MAKE_TZONE_ALLOCATED(CheckPrimeJobCtx);
+};
+
+extern "C" void Bun__CheckPrimeJobCtx__runTask(CheckPrimeJobCtx*, JSGlobalObject*);
+extern "C" void Bun__CheckPrimeJobCtx__runFromJS(CheckPrimeJobCtx*, JSGlobalObject*);
+extern "C" void Bun__CheckPrimeJobCtx__deinit(CheckPrimeJobCtx*);
+
+// Opaque struct created zig land
+struct CheckPrimeJob {
+ static CheckPrimeJob* create(JSGlobalObject*, ncrypto::BignumPointer candidate, int32_t checks, JSValue callback);
+ static void createAndSchedule(JSGlobalObject* globalObject, ncrypto::BignumPointer candidate, int32_t checks, JSValue callback);
+
+ void schedule();
+};
+
+struct GeneratePrimeJobCtx {
+ GeneratePrimeJobCtx(int32_t size, bool safe, ncrypto::BignumPointer prime, ncrypto::BignumPointer add, ncrypto::BignumPointer rem, bool bigint, JSValue callback);
+ ~GeneratePrimeJobCtx();
+
+ void runTask(JSGlobalObject* lexicalGlobalObject);
+ void runFromJS(JSGlobalObject* lexicalGlobalObject);
+ void deinit();
+
+ int32_t m_size;
+ bool m_safe;
+ bool m_bigint;
+ JSValue m_callback;
+ ncrypto::BignumPointer m_add;
+ ncrypto::BignumPointer m_rem;
+ ncrypto::BignumPointer m_prime;
+
+ WTF_MAKE_TZONE_ALLOCATED(GeneratePrimeJobCtx);
+};
+
+extern "C" void Bun__GeneratePrimeJobCtx__runTask(GeneratePrimeJobCtx*, JSGlobalObject*);
+extern "C" void Bun__GeneratePrimeJobCtx__runFromJS(GeneratePrimeJobCtx*, JSGlobalObject*);
+extern "C" void Bun__GeneratePrimeJobCtx__deinit(GeneratePrimeJobCtx*);
+
+// Opaque struct created zig land
+struct GeneratePrimeJob {
+ static GeneratePrimeJob* create(JSGlobalObject*, int32_t size, bool safe, ncrypto::BignumPointer prime, ncrypto::BignumPointer add, ncrypto::BignumPointer rem, bool bigint, JSValue callback);
+ static void createAndSchedule(JSGlobalObject*, int32_t size, bool safe, ncrypto::BignumPointer prime, ncrypto::BignumPointer add, ncrypto::BignumPointer rem, bool bigint, JSValue callback);
+
+ void schedule();
+};
+
+JSC_DECLARE_HOST_FUNCTION(jsCheckPrime);
+JSC_DECLARE_HOST_FUNCTION(jsCheckPrimeSync);
+JSC_DECLARE_HOST_FUNCTION(jsGeneratePrime);
+JSC_DECLARE_HOST_FUNCTION(jsGeneratePrimeSync);
diff --git a/src/bun.js/bindings/node/crypto/CryptoUtil.cpp b/src/bun.js/bindings/node/crypto/CryptoUtil.cpp
index 0c50cf8d9d..70e3d04c89 100644
--- a/src/bun.js/bindings/node/crypto/CryptoUtil.cpp
+++ b/src/bun.js/bindings/node/crypto/CryptoUtil.cpp
@@ -92,6 +92,36 @@ EncodedJSValue encode(JSGlobalObject* lexicalGlobalObject, ThrowScope& scope, st
}
+JSValue unsignedBigIntToBuffer(JSGlobalObject* lexicalGlobalObject, ThrowScope& scope, JSValue bigIntValue, ASCIILiteral name)
+{
+ ASSERT(bigIntValue.isBigInt());
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSBigInt* bigInt = bigIntValue.asHeapBigInt();
+
+ if (bigInt->sign()) {
+ ERR::OUT_OF_RANGE(scope, lexicalGlobalObject, name, ">= 0"_s, bigIntValue);
+ return {};
+ }
+
+ WTF::String hex = bigInt->toString(lexicalGlobalObject, 16);
+ RETURN_IF_EXCEPTION(scope, {});
+
+ JSString* paddedHex = hex.length() % 2
+ ? jsString(vm, tryMakeString('0', hex))
+ : jsString(vm, hex);
+ if (UNLIKELY(!paddedHex)) {
+ throwOutOfMemoryError(lexicalGlobalObject, scope);
+ return {};
+ }
+
+ GCOwnedDataScope paddedView = paddedHex->view(lexicalGlobalObject);
+ RETURN_IF_EXCEPTION(scope, {});
+
+ JSValue buffer = JSValue::decode(WebCore::constructFromEncoding(lexicalGlobalObject, paddedView, BufferEncodingType::hex));
+ RELEASE_AND_RETURN(scope, buffer);
+}
+
WebCore::BufferEncodingType getEncodingDefaultBuffer(JSGlobalObject* globalObject, ThrowScope& scope, JSValue encodingValue)
{
BufferEncodingType res = BufferEncodingType::buffer;
@@ -252,8 +282,7 @@ std::optional passphraseFromBufferSource(JSC::JSGlobalObje
return std::nullopt;
}
-// Throws a crypto error with optional OpenSSL error details
-void throwCryptoError(JSC::JSGlobalObject* globalObject, ThrowScope& scope, unsigned long err, const char* message)
+JSValue createCryptoError(JSC::JSGlobalObject* globalObject, ThrowScope& scope, uint32_t err, const char* message)
{
JSC::VM& vm = globalObject->vm();
@@ -265,15 +294,15 @@ void throwCryptoError(JSC::JSGlobalObject* globalObject, ThrowScope& scope, unsi
}
WTF::String errorMessage = WTF::String::fromUTF8(message);
- RETURN_IF_EXCEPTION(scope, void());
+ RETURN_IF_EXCEPTION(scope, {});
// Create error object with the message
JSC::JSObject* errorObject = createError(globalObject, errorMessage);
- RETURN_IF_EXCEPTION(scope, void());
+ RETURN_IF_EXCEPTION(scope, {});
PutPropertySlot messageSlot(errorObject, false);
errorObject->put(errorObject, globalObject, Identifier::fromString(vm, "message"_s), jsString(vm, errorMessage), messageSlot);
- RETURN_IF_EXCEPTION(scope, void());
+ RETURN_IF_EXCEPTION(scope, {});
ncrypto::CryptoErrorList errorStack;
errorStack.capture();
@@ -290,7 +319,7 @@ void throwCryptoError(JSC::JSGlobalObject* globalObject, ThrowScope& scope, unsi
WTF::String libString = WTF::String::fromUTF8(lib);
PutPropertySlot slot(errorObject, false);
errorObject->put(errorObject, globalObject, Identifier::fromString(vm, "library"_s), jsString(vm, libString), slot);
- RETURN_IF_EXCEPTION(scope, void());
+ RETURN_IF_EXCEPTION(scope, {});
}
// Add function info if available
@@ -299,7 +328,7 @@ void throwCryptoError(JSC::JSGlobalObject* globalObject, ThrowScope& scope, unsi
PutPropertySlot slot(errorObject, false);
errorObject->put(errorObject, globalObject, Identifier::fromString(vm, "function"_s), jsString(vm, funcString), slot);
- RETURN_IF_EXCEPTION(scope, void());
+ RETURN_IF_EXCEPTION(scope, {});
}
// Add reason info if available
@@ -308,7 +337,7 @@ void throwCryptoError(JSC::JSGlobalObject* globalObject, ThrowScope& scope, unsi
PutPropertySlot reasonSlot(errorObject, false);
errorObject->put(errorObject, globalObject, Identifier::fromString(vm, "reason"_s), jsString(vm, reasonString), reasonSlot);
- RETURN_IF_EXCEPTION(scope, void());
+ RETURN_IF_EXCEPTION(scope, {});
// Convert reason to error code (e.g. "this error" -> "ERR_OSSL_THIS_ERROR")
String upperReason = reasonString.convertToASCIIUppercase();
@@ -316,7 +345,7 @@ void throwCryptoError(JSC::JSGlobalObject* globalObject, ThrowScope& scope, unsi
PutPropertySlot codeSlot(errorObject, false);
errorObject->put(errorObject, globalObject, Identifier::fromString(vm, "code"_s), jsString(vm, code), codeSlot);
- RETURN_IF_EXCEPTION(scope, void());
+ RETURN_IF_EXCEPTION(scope, {});
}
}
@@ -324,16 +353,28 @@ void throwCryptoError(JSC::JSGlobalObject* globalObject, ThrowScope& scope, unsi
if (errorStack.size() > 0) {
PutPropertySlot stackSlot(errorObject, false);
auto arr = JSC::constructEmptyArray(globalObject, nullptr, errorStack.size());
- RETURN_IF_EXCEPTION(scope, void());
+ RETURN_IF_EXCEPTION(scope, {});
for (int32_t i = 0; i < errorStack.size(); i++) {
WTF::String error = errorStack.pop_back().value();
arr->putDirectIndex(globalObject, i, jsString(vm, error));
}
errorObject->put(errorObject, globalObject, Identifier::fromString(vm, "opensslErrorStack"_s), arr, stackSlot);
- RETURN_IF_EXCEPTION(scope, void());
+ RETURN_IF_EXCEPTION(scope, {});
}
- // Throw the decorated error
+ return errorObject;
+}
+
+extern "C" EncodedJSValue Bun__NodeCrypto__createCryptoError(JSC::JSGlobalObject* globalObject, uint32_t err, const char* message)
+{
+ auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
+ return JSValue::encode(createCryptoError(globalObject, scope, err, message));
+}
+
+void throwCryptoError(JSC::JSGlobalObject* globalObject, ThrowScope& scope, uint32_t err, const char* message)
+{
+ JSValue errorObject = createCryptoError(globalObject, scope, err, message);
+ RETURN_IF_EXCEPTION(scope, void());
throwException(globalObject, scope, errorObject);
}
diff --git a/src/bun.js/bindings/node/crypto/CryptoUtil.h b/src/bun.js/bindings/node/crypto/CryptoUtil.h
index 4ed97eb1a2..b770e2e130 100644
--- a/src/bun.js/bindings/node/crypto/CryptoUtil.h
+++ b/src/bun.js/bindings/node/crypto/CryptoUtil.h
@@ -37,13 +37,14 @@ EncodedJSValue encode(JSGlobalObject* lexicalGlobalObject, ThrowScope& scope, st
};
// void CheckThrow(JSC::JSGlobalObject* globalObject, SignBase::Error error);
+JSC::JSValue unsignedBigIntToBuffer(JSC::JSGlobalObject* lexicalGlobalObject, JSC::ThrowScope& scope, JSValue bigIntValue, ASCIILiteral name);
WebCore::BufferEncodingType getEncodingDefaultBuffer(JSGlobalObject* globalObject, ThrowScope& scope, JSValue encodingValue);
std::optional keyFromString(JSGlobalObject* lexicalGlobalObject, JSC::ThrowScope& scope, const WTF::StringView& keyView, JSValue passphraseValue);
ncrypto::EVPKeyPointer::PKFormatType parseKeyFormat(JSC::JSGlobalObject* globalObject, JSValue formatValue, WTF::ASCIILiteral optionName, std::optional defaultFormat = std::nullopt);
std::optional parseKeyType(JSC::JSGlobalObject* globalObject, JSValue typeValue, bool required, WTF::StringView keyType, std::optional isPublic, WTF::ASCIILiteral optionName);
bool isArrayBufferOrView(JSValue value);
std::optional passphraseFromBufferSource(JSC::JSGlobalObject* globalObject, JSC::ThrowScope& scope, JSValue input);
-void throwCryptoError(JSC::JSGlobalObject* globalObject, JSC::ThrowScope& scope, unsigned long err, const char* message = nullptr);
+void throwCryptoError(JSC::JSGlobalObject* globalObject, JSC::ThrowScope& scope, uint32_t err, const char* message = nullptr);
void throwCryptoOperationFailed(JSC::JSGlobalObject* globalObject, JSC::ThrowScope& scope);
std::optional getIntOption(JSC::JSGlobalObject* globalObject, JSValue options, WTF::ASCIILiteral name);
int32_t getPadding(JSC::JSGlobalObject* globalObject, JSValue options, const ncrypto::EVPKeyPointer& pkey);
diff --git a/src/bun.js/bindings/node/crypto/node_crypto_binding.cpp b/src/bun.js/bindings/node/crypto/node_crypto_binding.cpp
index b5cdd36de0..f97deccfe0 100644
--- a/src/bun.js/bindings/node/crypto/node_crypto_binding.cpp
+++ b/src/bun.js/bindings/node/crypto/node_crypto_binding.cpp
@@ -44,6 +44,7 @@
#include "JSVerify.h"
#include "JSHmac.h"
#include "JSHash.h"
+#include "CryptoPrimes.h"
using namespace JSC;
using namespace Bun;
@@ -414,6 +415,15 @@ JSValue createNodeCryptoBinding(Zig::GlobalObject* globalObject)
obj->putDirect(vm, PropertyName(Identifier::fromString(vm, "DiffieHellmanGroup"_s)),
globalObject->m_JSDiffieHellmanGroupClassStructure.constructor(globalObject));
+ obj->putDirect(vm, PropertyName(Identifier::fromString(vm, "generatePrime"_s)),
+ JSFunction::create(vm, globalObject, 3, "generatePrime"_s, jsGeneratePrime, ImplementationVisibility::Public, NoIntrinsic), 0);
+ obj->putDirect(vm, PropertyName(Identifier::fromString(vm, "generatePrimeSync"_s)),
+ JSFunction::create(vm, globalObject, 2, "generatePrimeSync"_s, jsGeneratePrimeSync, ImplementationVisibility::Public, NoIntrinsic), 0);
+ obj->putDirect(vm, PropertyName(Identifier::fromString(vm, "checkPrime"_s)),
+ JSFunction::create(vm, globalObject, 3, "checkPrime"_s, jsCheckPrime, ImplementationVisibility::Public, NoIntrinsic), 0);
+ obj->putDirect(vm, PropertyName(Identifier::fromString(vm, "checkPrimeSync"_s)),
+ JSFunction::create(vm, globalObject, 2, "checkPrimeSync"_s, jsCheckPrimeSync, ImplementationVisibility::Public, NoIntrinsic), 0);
+
return obj;
}
diff --git a/src/bun.js/bindings/node/crypto/node_crypto_binding.h b/src/bun.js/bindings/node/crypto/node_crypto_binding.h
index 924ba9223f..6aac413975 100644
--- a/src/bun.js/bindings/node/crypto/node_crypto_binding.h
+++ b/src/bun.js/bindings/node/crypto/node_crypto_binding.h
@@ -3,6 +3,10 @@
#include "root.h"
#include "helpers.h"
+#include "ncrypto.h"
+
+using namespace Bun;
+using namespace JSC;
namespace WebCore {
diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig
index f54a763841..b418729795 100644
--- a/src/bun.js/event_loop.zig
+++ b/src/bun.js/event_loop.zig
@@ -963,6 +963,23 @@ pub const EventLoop = struct {
globalObject.reportActiveExceptionAsUnhandled(err);
}
+ fn externRunCallback1(global: *JSC.JSGlobalObject, callback: JSC.JSValue, thisValue: JSC.JSValue, arg0: JSC.JSValue) callconv(.c) void {
+ const vm = global.bunVM();
+ var loop = vm.eventLoop();
+ loop.runCallback(callback, global, thisValue, &.{arg0});
+ }
+
+ fn externRunCallback2(global: *JSC.JSGlobalObject, callback: JSC.JSValue, thisValue: JSC.JSValue, arg0: JSC.JSValue, arg1: JSC.JSValue) callconv(.c) void {
+ const vm = global.bunVM();
+ var loop = vm.eventLoop();
+ loop.runCallback(callback, global, thisValue, &.{ arg0, arg1 });
+ }
+
+ comptime {
+ @export(&externRunCallback1, .{ .name = "Bun__EventLoop__runCallback1" });
+ @export(&externRunCallback2, .{ .name = "Bun__EventLoop__runCallback2" });
+ }
+
pub fn runCallbackWithResult(this: *EventLoop, callback: JSC.JSValue, globalObject: *JSC.JSGlobalObject, thisValue: JSC.JSValue, arguments: []const JSC.JSValue) JSC.JSValue {
this.enter();
defer this.exit();
diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig
index 4b046ee5f0..d704a5a00a 100644
--- a/src/bun.js/javascript.zig
+++ b/src/bun.js/javascript.zig
@@ -946,6 +946,10 @@ pub const VirtualMachine = struct {
return this.debugger != null;
}
+ pub export fn Bun__VirtualMachine__isShuttingDown(this: *const VirtualMachine) callconv(.C) bool {
+ return this.isShuttingDown();
+ }
+
pub fn isShuttingDown(this: *const VirtualMachine) bool {
return this.is_shutting_down;
}
diff --git a/src/bun.js/node/node_crypto_binding.zig b/src/bun.js/node/node_crypto_binding.zig
index 37acb601a9..296edf8d3f 100644
--- a/src/bun.js/node/node_crypto_binding.zig
+++ b/src/bun.js/node/node_crypto_binding.zig
@@ -17,6 +17,101 @@ const JSError = bun.JSError;
const String = bun.String;
const UUID = bun.UUID;
+fn ExternCryptoJob(
+ comptime name: []const u8,
+ comptime externRunTask: fn (*anyopaque, *JSGlobalObject) callconv(.c) void,
+ comptime externRunFromJS: fn (*anyopaque, *JSGlobalObject) callconv(.c) void,
+ comptime externDeinit: fn (*anyopaque) callconv(.c) void,
+) type {
+ return struct {
+ vm: *JSC.VirtualMachine,
+ task: JSC.WorkPoolTask,
+ any_task: JSC.AnyTask,
+
+ ctx: *anyopaque,
+
+ pub fn create(global: *JSGlobalObject, ctx: *anyopaque) callconv(.c) *@This() {
+ const vm = global.bunVM();
+ const job = bun.new(@This(), .{
+ .vm = vm,
+ .task = .{
+ .callback = &runTask,
+ },
+ .any_task = undefined,
+ .ctx = ctx,
+ });
+ job.any_task = JSC.AnyTask.New(@This(), &runFromJS).init(job);
+ return job;
+ }
+
+ pub fn createAndSchedule(global: *JSGlobalObject, ctx: *anyopaque) callconv(.c) void {
+ var job = create(global, ctx);
+ job.schedule();
+ }
+
+ pub fn runTask(task: *JSC.WorkPoolTask) void {
+ const job: *@This() = @fieldParentPtr("task", task);
+ var vm = job.vm;
+ defer vm.enqueueTaskConcurrent(JSC.ConcurrentTask.create(job.any_task.task()));
+
+ externRunTask(job.ctx, vm.global);
+ }
+
+ pub fn runFromJS(this: *@This()) void {
+ defer this.deinit();
+ const vm = this.vm;
+
+ if (vm.isShuttingDown()) {
+ return;
+ }
+
+ externRunFromJS(this.ctx, vm.global);
+ }
+
+ fn deinit(this: *@This()) void {
+ externDeinit(this.ctx);
+ bun.destroy(this);
+ }
+
+ pub fn schedule(this: *@This()) callconv(.c) void {
+ JSC.WorkPool.schedule(&this.task);
+ }
+
+ comptime {
+ @export(&create, .{ .name = "Bun__" ++ name ++ "__create" });
+ @export(&schedule, .{ .name = "Bun__" ++ name ++ "__schedule" });
+ @export(&createAndSchedule, .{ .name = "Bun__" ++ name ++ "__createAndSchedule" });
+ }
+ };
+}
+
+extern fn Bun__CheckPrimeJobCtx__runTask(ctx: *anyopaque, global: *JSGlobalObject) void;
+extern fn Bun__CheckPrimeJobCtx__runFromJS(ctx: *anyopaque, global: *JSGlobalObject) void;
+extern fn Bun__CheckPrimeJobCtx__deinit(ctx: *anyopaque) void;
+
+const CheckPrimeJob = ExternCryptoJob(
+ "CheckPrimeJob",
+ Bun__CheckPrimeJobCtx__runTask,
+ Bun__CheckPrimeJobCtx__runFromJS,
+ Bun__CheckPrimeJobCtx__deinit,
+);
+
+extern fn Bun__GeneratePrimeJobCtx__runTask(ctx: *anyopaque, global: *JSGlobalObject) void;
+extern fn Bun__GeneratePrimeJobCtx__runFromJS(ctx: *anyopaque, global: *JSGlobalObject) void;
+extern fn Bun__GeneratePrimeJobCtx__deinit(ctx: *anyopaque) void;
+
+const GeneratePrimeJob = ExternCryptoJob(
+ "GeneratePrimeJob",
+ Bun__GeneratePrimeJobCtx__runTask,
+ Bun__GeneratePrimeJobCtx__runFromJS,
+ Bun__GeneratePrimeJobCtx__deinit,
+);
+
+comptime {
+ _ = CheckPrimeJob;
+ _ = GeneratePrimeJob;
+}
+
const random = struct {
const max_possible_length = @min(JSC.ArrayBuffer.max_size, std.math.maxInt(i32));
const max_range = 0xffff_ffff_ffff;
@@ -25,7 +120,7 @@ const random = struct {
var min_value, var max_value, var callback = callFrame.argumentsAsArray(3);
var min_specified = true;
- if (max_value.isUndefined() or max_value.isFunction()) {
+ if (max_value.isUndefined() or max_value.isCallable()) {
callback = max_value;
max_value = min_value;
min_value = JSValue.jsNumber(0);
@@ -128,10 +223,8 @@ const random = struct {
task: JSC.WorkPoolTask,
any_task: JSC.AnyTask,
- promise: JSC.JSPromise.Strong,
- poll: bun.Async.KeepAlive = .{},
-
- value: JSC.Strong,
+ callback: JSValue,
+ value: JSValue,
bytes: [*]u8,
offset: u32,
length: usize,
@@ -151,14 +244,12 @@ const random = struct {
return;
}
- const global = this.vm.global;
- const promise = this.promise.swap();
-
- promise.resolve(global, this.value.swap());
+ vm.eventLoop().runCallback(this.callback, vm.global, .undefined, &.{ .null, this.value });
}
- pub fn create(global: *JSGlobalObject, value: JSValue, bytes: [*]u8, offset: u32, length: usize) *Job {
+ pub fn create(global: *JSGlobalObject, value: JSValue, bytes: [*]u8, offset: u32, length: usize, callback: JSValue) *Job {
const vm = global.bunVM();
+
const job = bun.new(Job, .{
.vm = vm,
.task = .{
@@ -166,22 +257,25 @@ const random = struct {
},
.any_task = undefined,
- .promise = JSC.JSPromise.Strong.init(global),
-
- .value = JSC.Strong.create(value, global),
+ .callback = callback,
+ .value = value,
.bytes = bytes,
.offset = offset,
.length = length,
});
-
+ job.callback.protect();
+ job.value.protect();
job.any_task = JSC.AnyTask.New(Job, &Job.runFromJS).init(job);
- job.poll.ref(vm);
- JSC.WorkPool.schedule(&job.task);
return job;
}
+ fn schedule(this: *Job) void {
+ JSC.WorkPool.schedule(&this.task);
+ }
+
fn deinit(this: *Job) void {
- this.poll.unref(this.vm);
+ this.value.unprotect();
+ this.callback.unprotect();
bun.destroy(this);
}
};
@@ -202,9 +296,9 @@ const random = struct {
return result;
}
- const job = Job.create(global, result, bytes.ptr, 0, size);
-
- return job.promise.value();
+ const job = Job.create(global, result, bytes.ptr, 0, size, callback);
+ job.schedule();
+ return .undefined;
}
fn randomFillSync(global: *JSGlobalObject, callFrame: *JSC.CallFrame) JSError!JSValue {
@@ -238,7 +332,7 @@ const random = struct {
}
fn randomFill(global: *JSGlobalObject, callFrame: *JSC.CallFrame) JSError!JSValue {
- const buf_value, const offset_value, const size_value, const callback =
+ const buf_value, var offset_value, var size_value, var callback =
callFrame.argumentsAsArray(4);
const buf = buf_value.asArrayBuffer(global) orelse {
@@ -247,9 +341,19 @@ const random = struct {
const element_size = buf.bytesPerElement() orelse 1;
- _ = try validators.validateFunction(global, "callback", callback);
-
- const offset = try assertOffset(global, offset_value, element_size, buf.byte_len);
+ var offset: u32 = 0;
+ if (offset_value.isCallable()) {
+ callback = offset_value;
+ offset = try assertOffset(global, JSValue.jsNumber(0), element_size, buf.byte_len);
+ size_value = JSValue.jsNumber(buf.len);
+ } else if (size_value.isCallable()) {
+ callback = size_value;
+ offset = try assertOffset(global, offset_value, element_size, buf.byte_len);
+ size_value = JSValue.jsNumber(buf.len - offset);
+ } else {
+ _ = try validators.validateFunction(global, "callback", callback);
+ offset = try assertOffset(global, offset_value, element_size, buf.byte_len);
+ }
const size = if (size_value.isUndefined())
buf.byte_len - offset
@@ -257,12 +361,13 @@ const random = struct {
try assertSize(global, size_value, element_size, offset, buf.byte_len);
if (size == 0) {
- return JSC.JSPromise.resolvedPromiseValue(global, callback);
+ _ = try callback.call(global, .undefined, &.{ .null, JSValue.jsNumber(0) });
+ return .undefined;
}
- const job = Job.create(global, buf_value, buf.slice().ptr, offset, size);
-
- return job.promise.value();
+ const job = Job.create(global, buf_value, buf.slice().ptr, offset, size, callback);
+ job.schedule();
+ return .undefined;
}
};
diff --git a/src/bun.js/node/node_fs.zig b/src/bun.js/node/node_fs.zig
index c3363fc49d..a895f931bd 100644
--- a/src/bun.js/node/node_fs.zig
+++ b/src/bun.js/node/node_fs.zig
@@ -1734,7 +1734,7 @@ pub const Arguments = struct {
const big_int = brk: {
if (arguments.next()) |next_val| {
if (next_val.isObject()) {
- if (next_val.isCallable(ctx.vm())) break :brk false;
+ if (next_val.isCallable()) break :brk false;
arguments.eat();
if (try next_val.getBooleanStrict(ctx, "bigint")) |big_int| {
@@ -1777,7 +1777,7 @@ pub const Arguments = struct {
const big_int = brk: {
if (arguments.next()) |next_val| {
if (next_val.isObject()) {
- if (next_val.isCallable(ctx.vm())) break :brk false;
+ if (next_val.isCallable()) break :brk false;
arguments.eat();
if (try next_val.getBooleanStrict(ctx, "throwIfNoEntry")) |throw_if_no_entry_val| {
@@ -1813,7 +1813,7 @@ pub const Arguments = struct {
const big_int = brk: {
if (arguments.next()) |next_val| {
if (next_val.isObject()) {
- if (next_val.isCallable(ctx.vm())) break :brk false;
+ if (next_val.isCallable()) break :brk false;
arguments.eat();
if (try next_val.getBooleanStrict(ctx, "bigint")) |big_int| {
diff --git a/src/bun.js/node/node_fs_stat_watcher.zig b/src/bun.js/node/node_fs_stat_watcher.zig
index 9d49f0496a..b059898636 100644
--- a/src/bun.js/node/node_fs_stat_watcher.zig
+++ b/src/bun.js/node/node_fs_stat_watcher.zig
@@ -232,10 +232,9 @@ pub const StatWatcher = struct {
global_this: JSC.C.JSContextRef,
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Arguments {
- const vm = ctx.vm();
- const path = try PathLike.fromJSWithAllocator(ctx, arguments, bun.default_allocator) orelse {
- return ctx.throwInvalidArguments("filename must be a string or TypedArray", .{});
+ pub fn fromJS(global: *JSC.JSGlobalObject, arguments: *ArgumentsSlice) bun.JSError!Arguments {
+ const path = try PathLike.fromJSWithAllocator(global, arguments, bun.default_allocator) orelse {
+ return global.throwInvalidArguments("filename must be a string or TypedArray", .{});
};
var listener: JSC.JSValue = .zero;
@@ -247,28 +246,28 @@ pub const StatWatcher = struct {
// options
if (options_or_callable.isObject()) {
// default true
- persistent = (try options_or_callable.getBooleanStrict(ctx, "persistent")) orelse true;
+ persistent = (try options_or_callable.getBooleanStrict(global, "persistent")) orelse true;
// default false
- bigint = (try options_or_callable.getBooleanStrict(ctx, "bigint")) orelse false;
+ bigint = (try options_or_callable.getBooleanStrict(global, "bigint")) orelse false;
- if (try options_or_callable.get(ctx, "interval")) |interval_| {
+ if (try options_or_callable.get(global, "interval")) |interval_| {
if (!interval_.isNumber() and !interval_.isAnyInt()) {
- return ctx.throwInvalidArguments("interval must be a number", .{});
+ return global.throwInvalidArguments("interval must be a number", .{});
}
- interval = interval_.coerce(i32, ctx);
+ interval = interval_.coerce(i32, global);
}
}
}
if (arguments.nextEat()) |listener_| {
- if (listener_.isCallable(vm)) {
- listener = listener_.withAsyncContextIfNeeded(ctx);
+ if (listener_.isCallable()) {
+ listener = listener_.withAsyncContextIfNeeded(global);
}
}
if (listener == .zero) {
- return ctx.throwInvalidArguments("Expected \"listener\" callback", .{});
+ return global.throwInvalidArguments("Expected \"listener\" callback", .{});
}
return Arguments{
@@ -277,7 +276,7 @@ pub const StatWatcher = struct {
.persistent = persistent,
.bigint = bigint,
.interval = interval,
- .global_this = ctx,
+ .global_this = global,
};
}
diff --git a/src/bun.js/node/node_fs_watcher.zig b/src/bun.js/node/node_fs_watcher.zig
index 55c2af8c89..425b932909 100644
--- a/src/bun.js/node/node_fs_watcher.zig
+++ b/src/bun.js/node/node_fs_watcher.zig
@@ -342,7 +342,6 @@ pub const FSWatcher = struct {
verbose: bool,
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice) bun.JSError!Arguments {
- const vm = ctx.vm();
const path = try PathLike.fromJS(ctx, arguments) orelse {
return ctx.throwInvalidArguments("filename must be a string or TypedArray", .{});
};
@@ -397,13 +396,13 @@ pub const FSWatcher = struct {
// listener
if (arguments.nextEat()) |callable| {
- if (!callable.isCell() or !callable.isCallable(vm)) {
+ if (!callable.isCell() or !callable.isCallable()) {
return ctx.throwInvalidArguments("Expected \"listener\" callback to be a function", .{});
}
listener = callable;
}
} else {
- if (!options_or_callable.isCell() or !options_or_callable.isCallable(vm)) {
+ if (!options_or_callable.isCell() or !options_or_callable.isCallable()) {
return ctx.throwInvalidArguments("Expected \"listener\" callback to be a function", .{});
}
listener = options_or_callable;
diff --git a/src/bun.js/node/node_zlib_binding.zig b/src/bun.js/node/node_zlib_binding.zig
index 9163f3cc88..80d348b05c 100644
--- a/src/bun.js/node/node_zlib_binding.zig
+++ b/src/bun.js/node/node_zlib_binding.zig
@@ -134,8 +134,8 @@ pub fn CompressionStream(comptime T: type) type {
};
pub fn runFromJSThread(this: *T) void {
- const globalThis: *JSC.JSGlobalObject = this.globalThis;
- const vm = globalThis.bunVM();
+ const global: *JSC.JSGlobalObject = this.globalThis;
+ const vm = global.bunVM();
this.poll_ref.unref(vm);
defer this.deref();
@@ -149,7 +149,7 @@ pub fn CompressionStream(comptime T: type) type {
this_value.ensureStillAlive();
- if (!(this.checkError(globalThis, this_value) catch return globalThis.reportActiveExceptionAsUnhandled(error.JSError))) {
+ if (!(this.checkError(global, this_value) catch return global.reportActiveExceptionAsUnhandled(error.JSError))) {
return;
}
@@ -157,7 +157,8 @@ pub fn CompressionStream(comptime T: type) type {
this_value.ensureStillAlive();
const write_callback: JSC.JSValue = T.writeCallbackGetCached(this_value).?;
- _ = write_callback.call(globalThis, this_value, &.{}) catch |err| globalThis.reportActiveExceptionAsUnhandled(err);
+
+ vm.eventLoop().runCallback(write_callback, global, this_value, &.{});
if (this.pending_close) _ = this._close();
}
diff --git a/src/bun.js/test/expect.zig b/src/bun.js/test/expect.zig
index 185d83c442..ed88720abf 100644
--- a/src/bun.js/test/expect.zig
+++ b/src/bun.js/test/expect.zig
@@ -3236,7 +3236,7 @@ pub const Expect = struct {
var whatIsTheType: []const u8 = "";
// Checking for function/class should be done before everything else, or it will fail.
- if (value.isCallable(globalThis.vm())) {
+ if (value.isCallable()) {
whatIsTheType = "function";
} else if (value.isObject() or value.jsType().isArray() or value.isNull()) {
whatIsTheType = "object";
@@ -3674,7 +3674,7 @@ pub const Expect = struct {
incrementExpectCallCounter();
const not = this.flags.not;
- const pass = value.isCallable(globalThis.vm()) != not;
+ const pass = value.isCallable() != not;
if (pass) return .undefined;
@@ -3942,7 +3942,7 @@ pub const Expect = struct {
const predicate = arguments[0];
predicate.ensureStillAlive();
- if (!predicate.isCallable(globalThis.vm())) {
+ if (!predicate.isCallable()) {
return globalThis.throw("toSatisfy() argument must be a function", .{});
}
@@ -4825,7 +4825,7 @@ pub const Expect = struct {
pass = pass_value.toBoolean();
if (result.fastGet(globalThis, .message)) |message_value| {
- if (!message_value.isString() and !message_value.isCallable(globalThis.vm())) {
+ if (!message_value.isString() and !message_value.isCallable()) {
break :valid false;
}
message = message_value;
@@ -4854,7 +4854,7 @@ pub const Expect = struct {
message_text = try message.toBunString(globalThis);
} else {
if (comptime Environment.allow_assert)
- assert(message.isCallable(globalThis.vm())); // checked above
+ assert(message.isCallable()); // checked above
const message_result = try message.callWithGlobalThis(globalThis, &.{});
message_text = try bun.String.fromJS2(message_result, globalThis);
diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig
index ced19e4a6c..ba0f1df9c2 100644
--- a/src/bun.js/test/jest.zig
+++ b/src/bun.js/test/jest.zig
@@ -295,7 +295,7 @@ pub const Jest = struct {
}
const function = arguments.ptr[0];
- if (function.isEmptyOrUndefinedOrNull() or !function.isCallable(globalThis.vm())) {
+ if (function.isEmptyOrUndefinedOrNull() or !function.isCallable()) {
return globalThis.throwInvalidArgumentType(name, "callback", "function");
}
@@ -883,7 +883,7 @@ pub const DescribeScope = struct {
}
const cb = arguments.ptr[0];
- if (!cb.isObject() or !cb.isCallable(globalThis.vm())) {
+ if (!cb.isObject() or !cb.isCallable()) {
return globalThis.throwInvalidArgumentType(@tagName(hook), "callback", "function");
}
@@ -933,7 +933,7 @@ pub const DescribeScope = struct {
for (hooks.items) |cb| {
if (comptime Environment.allow_assert) {
assert(cb.isObject());
- assert(cb.isCallable(globalObject.vm()));
+ assert(cb.isCallable());
}
defer {
if (comptime hook == .beforeAll or hook == .afterAll) {
@@ -990,7 +990,7 @@ pub const DescribeScope = struct {
for (hooks.items) |cb| {
if (comptime Environment.allow_assert) {
assert(cb.isObject());
- assert(cb.isCallable(globalThis.vm()));
+ assert(cb.isCallable());
}
defer {
if (comptime hook == .beforeAll or hook == .afterAll) {
@@ -2023,7 +2023,7 @@ fn eachBind(globalThis: *JSGlobalObject, callframe: *CallFrame) bun.JSError!JSVa
var function = args[1];
var options = if (args.len > 2) args[2] else .zero;
- if (function.isEmptyOrUndefinedOrNull() or !function.isCell() or !function.isCallable(globalThis.vm())) {
+ if (function.isEmptyOrUndefinedOrNull() or !function.isCell() or !function.isCallable()) {
return globalThis.throwPretty("{s} expects a function", .{signature});
}
diff --git a/src/bun.js/test/pretty_format.zig b/src/bun.js/test/pretty_format.zig
index 176c54f04c..33e5ebd7df 100644
--- a/src/bun.js/test/pretty_format.zig
+++ b/src/bun.js/test/pretty_format.zig
@@ -414,7 +414,7 @@ pub const JestPrettyFormat = struct {
// If we check an Object has a method table and it does not
// it will crash
- if (js_type != .Object and value.isCallable(globalThis.vm())) {
+ if (js_type != .Object and value.isCallable()) {
if (value.isClass(globalThis)) {
return .{
.tag = .Class,
@@ -1305,7 +1305,7 @@ pub const JestPrettyFormat = struct {
} else if (printAsymmetricMatcher(this, Format, &writer, writer_, name_buf, value, enable_ansi_colors)) {
return;
} else if (jsType != .DOMWrapper) {
- if (value.isCallable(this.globalThis.vm())) {
+ if (value.isCallable()) {
return try this.printAs(.Function, Writer, writer_, value, jsType, enable_ansi_colors);
}
@@ -1529,7 +1529,7 @@ pub const JestPrettyFormat = struct {
if (_tag.cell == .Symbol) {} else if (_tag.cell.isStringLike()) {
try type_value.toZigString(&tag_name_str, this.globalThis);
is_tag_kind_primitive = true;
- } else if (_tag.cell.isObject() or type_value.isCallable(this.globalThis.vm())) {
+ } else if (_tag.cell.isObject() or type_value.isCallable()) {
type_value.getNameProperty(this.globalThis, &tag_name_str);
if (tag_name_str.len == 0) {
tag_name_str = ZigString.init("NoName");
diff --git a/src/bun.js/webcore/response.zig b/src/bun.js/webcore/response.zig
index 5fcb0bf74f..0b27ce768e 100644
--- a/src/bun.js/webcore/response.zig
+++ b/src/bun.js/webcore/response.zig
@@ -2627,7 +2627,7 @@ pub const Fetch = struct {
}
if (try tls.get(ctx, "checkServerIdentity")) |checkServerIdentity| {
- if (checkServerIdentity.isCell() and checkServerIdentity.isCallable(globalThis.vm())) {
+ if (checkServerIdentity.isCell() and checkServerIdentity.isCallable()) {
check_server_identity = checkServerIdentity;
}
}
diff --git a/src/bun.js/webcore/streams.zig b/src/bun.js/webcore/streams.zig
index 533738ed25..08aeac61e9 100644
--- a/src/bun.js/webcore/streams.zig
+++ b/src/bun.js/webcore/streams.zig
@@ -3277,7 +3277,7 @@ pub fn ReadableStreamSource(
return true;
}
- if (!value.isCallable(globalObject.vm())) {
+ if (!value.isCallable()) {
globalObject.throwInvalidArgumentType("ReadableStreamSource", "onclose", "function") catch {};
return false;
}
@@ -3295,7 +3295,7 @@ pub fn ReadableStreamSource(
return true;
}
- if (!value.isCallable(globalObject.vm())) {
+ if (!value.isCallable()) {
globalObject.throwInvalidArgumentType("ReadableStreamSource", "onDrain", "function") catch {};
return false;
}
diff --git a/src/js/node/crypto.ts b/src/js/node/crypto.ts
index 482fd3da6d..521cc8ef1b 100644
--- a/src/js/node/crypto.ts
+++ b/src/js/node/crypto.ts
@@ -42,6 +42,10 @@ const {
ECDH,
DiffieHellman: _DiffieHellman,
DiffieHellmanGroup: _DiffieHellmanGroup,
+ checkPrime,
+ checkPrimeSync,
+ generatePrime,
+ generatePrimeSync,
} = $cpp("node_crypto_binding.cpp", "createNodeCryptoBinding");
const {
@@ -49,13 +53,13 @@ const {
pbkdf2Sync: _pbkdf2Sync,
timingSafeEqual: _timingSafeEqual,
randomInt,
- randomUUID: _randomUUID,
- randomBytes: _randomBytes,
+ randomUUID,
+ randomBytes,
randomFillSync,
- randomFill: _randomFill,
+ randomFill,
} = $zig("node_crypto_binding.zig", "createNodeCryptoBindingZig");
-const { validateObject, validateString, validateInt32 } = require("internal/validators");
+const { validateObject, validateString } = require("internal/validators");
const kHandle = Symbol("kHandle");
@@ -2361,7 +2365,6 @@ crypto_exports.getFips = function getFips() {
return 0;
};
-crypto_exports.randomUUID = _randomUUID;
crypto_exports.getCurves = getCurves;
crypto_exports.getCipherInfo = getCipherInfo;
crypto_exports.scrypt = scrypt;
@@ -2513,18 +2516,16 @@ crypto_exports.createVerify = createVerify;
};
}
-function randomBytes(size, callback) {
- if (callback === undefined) {
- return _randomBytes(size);
- }
-
- // Crypto random promise job is guaranteed to resolve.
- _randomBytes(size, callback).then(buf => {
- callback(null, buf);
- });
-}
-
+crypto_exports.randomInt = randomInt;
+crypto_exports.randomFill = randomFill;
+crypto_exports.randomFillSync = randomFillSync;
crypto_exports.randomBytes = randomBytes;
+crypto_exports.randomUUID = randomUUID;
+
+crypto_exports.checkPrime = checkPrime;
+crypto_exports.checkPrimeSync = checkPrimeSync;
+crypto_exports.generatePrime = generatePrime;
+crypto_exports.generatePrimeSync = generatePrimeSync;
for (const rng of ["pseudoRandomBytes", "prng", "rng"]) {
Object.defineProperty(crypto_exports, rng, {
@@ -2534,31 +2535,6 @@ for (const rng of ["pseudoRandomBytes", "prng", "rng"]) {
});
}
-crypto_exports.randomInt = randomInt;
-
-function randomFill(buf, offset, size, callback) {
- if (!isAnyArrayBuffer(buf) && !isArrayBufferView(buf)) {
- throw $ERR_INVALID_ARG_TYPE("buf", ["ArrayBuffer", "ArrayBufferView"], buf);
- }
-
- if (typeof offset === "function") {
- callback = offset;
- offset = 0;
- size = buf.length;
- } else if (typeof size === "function") {
- callback = size;
- size = buf.length - offset;
- }
-
- // Crypto random promise job is guaranteed to resolve.
- _randomFill(buf, offset, size, callback).then(() => {
- callback(null, buf);
- });
-}
-
-crypto_exports.randomFill = randomFill;
-crypto_exports.randomFillSync = randomFillSync;
-
export default crypto_exports;
/*! safe-buffer. MIT License. Feross Aboukhadijeh */
diff --git a/src/napi/napi.zig b/src/napi/napi.zig
index 681af567d5..b3ec1091a6 100644
--- a/src/napi/napi.zig
+++ b/src/napi/napi.zig
@@ -670,7 +670,7 @@ pub export fn napi_make_callback(env_: napi_env, _: *anyopaque, recv_: napi_valu
return envIsNull();
};
const recv, const func = .{ recv_.get(), func_.get() };
- if (func.isEmptyOrUndefinedOrNull() or !func.isCallable(env.toJS().vm())) {
+ if (func.isEmptyOrUndefinedOrNull() or !func.isCallable()) {
return env.setLastError(.function_expected);
}
@@ -1749,7 +1749,7 @@ pub export fn napi_create_threadsafe_function(
};
const func = func_.get();
- if (call_js_cb == null and (func.isEmptyOrUndefinedOrNull() or !func.isCallable(env.toJS().vm()))) {
+ if (call_js_cb == null and (func.isEmptyOrUndefinedOrNull() or !func.isCallable())) {
return env.setLastError(.function_expected);
}
diff --git a/test/js/node/test/parallel/test-crypto-prime.js b/test/js/node/test/parallel/test-crypto-prime.js
new file mode 100644
index 0000000000..91c2d42e52
--- /dev/null
+++ b/test/js/node/test/parallel/test-crypto-prime.js
@@ -0,0 +1,325 @@
+'use strict';
+
+const common = require('../common');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+
+const {
+ generatePrime,
+ generatePrimeSync,
+ checkPrime,
+ checkPrimeSync,
+} = require('crypto');
+
+const { Worker } = require('worker_threads');
+
+const { promisify } = require('util');
+const pgeneratePrime = promisify(generatePrime);
+const pCheckPrime = promisify(checkPrime);
+
+['hello', false, {}, []].forEach((i) => {
+ assert.throws(() => generatePrime(i), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrimeSync(i), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
+
+['hello', false, 123].forEach((i) => {
+ assert.throws(() => generatePrime(80, i, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrimeSync(80, i), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
+
+['hello', false, 123].forEach((i) => {
+ assert.throws(() => generatePrime(80, {}), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
+
+[-1, 0, 2 ** 31, 2 ** 31 + 1, 2 ** 32 - 1, 2 ** 32].forEach((size) => {
+ assert.throws(() => generatePrime(size, common.mustNotCall()), {
+ code: 'ERR_OUT_OF_RANGE',
+ message: />= 1 and <= 2147483647/
+ });
+ assert.throws(() => generatePrimeSync(size), {
+ code: 'ERR_OUT_OF_RANGE',
+ message: />= 1 and <= 2147483647/
+ });
+});
+
+['test', -1, {}, []].forEach((i) => {
+ assert.throws(() => generatePrime(8, { safe: i }, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrime(8, { rem: i }, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrime(8, { add: i }, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrimeSync(8, { safe: i }), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrimeSync(8, { rem: i }), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+ assert.throws(() => generatePrimeSync(8, { add: i }), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
+
+{
+ // Negative BigInts should not be converted to 0 silently.
+
+ assert.throws(() => generatePrime(20, { add: -1n }, common.mustNotCall()), {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "options.add" is out of range. It must be >= 0. ' +
+ 'Received -1n'
+ });
+
+ assert.throws(() => generatePrime(20, { rem: -1n }, common.mustNotCall()), {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "options.rem" is out of range. It must be >= 0. ' +
+ 'Received -1n'
+ });
+
+ assert.throws(() => checkPrime(-1n, common.mustNotCall()), {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'The value of "candidate" is out of range. It must be >= 0. ' +
+ 'Received -1n'
+ });
+}
+
+generatePrime(80, common.mustSucceed((prime) => {
+ assert(checkPrimeSync(prime));
+ checkPrime(prime, common.mustSucceed((result) => {
+ assert(result);
+ }));
+}));
+
+assert(checkPrimeSync(generatePrimeSync(80)));
+
+generatePrime(80, {}, common.mustSucceed((prime) => {
+ assert(checkPrimeSync(prime));
+}));
+
+assert(checkPrimeSync(generatePrimeSync(80, {})));
+
+generatePrime(32, { safe: true }, common.mustSucceed((prime) => {
+ assert(checkPrimeSync(prime));
+ const buf = Buffer.from(prime);
+ const val = buf.readUInt32BE();
+ const check = (val - 1) / 2;
+ buf.writeUInt32BE(check);
+ assert(checkPrimeSync(buf));
+}));
+
+{
+ const prime = generatePrimeSync(32, { safe: true });
+ assert(checkPrimeSync(prime));
+ const buf = Buffer.from(prime);
+ const val = buf.readUInt32BE();
+ const check = (val - 1) / 2;
+ buf.writeUInt32BE(check);
+ assert(checkPrimeSync(buf));
+}
+
+const add = 12;
+const rem = 11;
+const add_buf = Buffer.from([add]);
+const rem_buf = Buffer.from([rem]);
+generatePrime(
+ 32,
+ { add: add_buf, rem: rem_buf },
+ common.mustSucceed((prime) => {
+ assert(checkPrimeSync(prime));
+ const buf = Buffer.from(prime);
+ const val = buf.readUInt32BE();
+ assert.strictEqual(val % add, rem);
+ }));
+
+{
+ const prime = generatePrimeSync(32, { add: add_buf, rem: rem_buf });
+ assert(checkPrimeSync(prime));
+ const buf = Buffer.from(prime);
+ const val = buf.readUInt32BE();
+ assert.strictEqual(val % add, rem);
+}
+
+{
+ const prime = generatePrimeSync(32, { add: BigInt(add), rem: BigInt(rem) });
+ assert(checkPrimeSync(prime));
+ const buf = Buffer.from(prime);
+ const val = buf.readUInt32BE();
+ assert.strictEqual(val % add, rem);
+}
+
+{
+ // The behavior when specifying only add without rem should depend on the
+ // safe option.
+
+ if (process.versions.openssl >= '1.1.1f') {
+ generatePrime(128, {
+ bigint: true,
+ add: 5n
+ }, common.mustSucceed((prime) => {
+ assert(checkPrimeSync(prime));
+ assert.strictEqual(prime % 5n, 1n);
+ }));
+
+ generatePrime(128, {
+ bigint: true,
+ safe: true,
+ add: 5n
+ }, common.mustSucceed((prime) => {
+ assert(checkPrimeSync(prime));
+ assert.strictEqual(prime % 5n, 3n);
+ }));
+ }
+}
+
+{
+ // This is impossible because it implies (prime % 2**64) == 1 and
+ // prime < 2**64, meaning prime = 1, but 1 is not prime.
+ for (const add of [2n ** 64n, 2n ** 65n]) {
+ assert.throws(() => {
+ generatePrimeSync(64, { add });
+ }, {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'invalid options.add'
+ });
+ }
+
+ // Any parameters with rem >= add lead to an impossible condition.
+ for (const rem of [7n, 8n, 3000n]) {
+ assert.throws(() => {
+ generatePrimeSync(64, { add: 7n, rem });
+ }, {
+ code: 'ERR_OUT_OF_RANGE',
+ message: 'invalid options.rem'
+ });
+ }
+
+ // This is possible, but not allowed. It implies prime == 7, which means that
+ // we did not actually generate a random prime.
+ assert.throws(() => {
+ generatePrimeSync(3, { add: 8n, rem: 7n });
+ }, {
+ code: 'ERR_OUT_OF_RANGE'
+ });
+
+ if (process.versions.openssl >= '1.1.1f') {
+ // This is possible and allowed (but makes little sense).
+ assert.strictEqual(generatePrimeSync(4, {
+ add: 15n,
+ rem: 13n,
+ bigint: true
+ }), 13n);
+ }
+}
+
+[1, 'hello', {}, []].forEach((i) => {
+ assert.throws(() => checkPrime(i), {
+ code: 'ERR_INVALID_ARG_TYPE'
+ });
+});
+
+for (const checks of ['hello', {}, []]) {
+ assert.throws(() => checkPrime(2n, { checks }, common.mustNotCall()), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /checks/
+ });
+ assert.throws(() => checkPrimeSync(2n, { checks }), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ message: /checks/
+ });
+}
+
+for (const checks of [-(2 ** 31), -1, 2 ** 31, 2 ** 32 - 1, 2 ** 32, 2 ** 50]) {
+ assert.throws(() => checkPrime(2n, { checks }, common.mustNotCall()), {
+ code: 'ERR_OUT_OF_RANGE',
+ message: /<= 2147483647/
+ });
+ assert.throws(() => checkPrimeSync(2n, { checks }), {
+ code: 'ERR_OUT_OF_RANGE',
+ message: /<= 2147483647/
+ });
+}
+
+{
+ const bytes = Buffer.alloc(67108864);
+ bytes[0] = 0x1;
+ assert.throws(() => checkPrime(bytes, common.mustNotCall()), {
+ code: /ERR_OSSL_(BN_)?BIGNUM_TOO_LONG/,
+ message: /bignum[_ ]too[_ ]long/i
+ });
+ assert.throws(() => checkPrimeSync(bytes), {
+ code: /ERR_OSSL_(BN_)?BIGNUM_TOO_LONG/,
+ message: /bignum[_ ]too[_ ]long/i
+ });
+}
+
+assert(!checkPrimeSync(Buffer.from([0x1])));
+assert(checkPrimeSync(Buffer.from([0x2])));
+assert(checkPrimeSync(Buffer.from([0x3])));
+assert(!checkPrimeSync(Buffer.from([0x4])));
+
+assert(
+ !checkPrimeSync(
+ Buffer.from([0x1]),
+ {
+ fast: true,
+ trialDivision: true,
+ checks: 10
+ }));
+
+(async function() {
+ const prime = await pgeneratePrime(36);
+ assert(await pCheckPrime(prime));
+})().then(common.mustCall());
+
+assert.throws(() => {
+ generatePrimeSync(32, { bigint: '' });
+}, { code: 'ERR_INVALID_ARG_TYPE' });
+
+assert.throws(() => {
+ generatePrime(32, { bigint: '' }, common.mustNotCall());
+}, { code: 'ERR_INVALID_ARG_TYPE' });
+
+{
+ const prime = generatePrimeSync(3, { bigint: true });
+ assert.strictEqual(typeof prime, 'bigint');
+ assert.strictEqual(prime, 7n);
+ assert(checkPrimeSync(prime));
+ checkPrime(prime, common.mustSucceed(assert));
+}
+
+{
+ generatePrime(3, { bigint: true }, common.mustSucceed((prime) => {
+ assert.strictEqual(typeof prime, 'bigint');
+ assert.strictEqual(prime, 7n);
+ assert(checkPrimeSync(prime));
+ checkPrime(prime, common.mustSucceed(assert));
+ }));
+}
+
+{
+ // Verify that generatePrime can be reasonably interrupted.
+ const worker = new Worker(`
+ const { generatePrime } = require('crypto');
+ generatePrime(2048, () => {
+ throw new Error('should not be called');
+ });
+ process.exit(42);
+ `, { eval: true });
+
+ worker.on('error', common.mustNotCall());
+ worker.on('exit', common.mustCall((exitCode) => assert.strictEqual(exitCode, 42)));
+}