aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-10-17 06:53:18 -0700
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-10-17 06:53:18 -0700
commitcdff2697efff88dd4059c41954f4bdd84bd3063c (patch)
tree6f0dbb3ec34139ca8fb9bf0d90168e962b71dbfe
parentca02695993a3380a75ff4b19fb45814e184b092a (diff)
downloadbun-cdff2697efff88dd4059c41954f4bdd84bd3063c.tar.gz
bun-cdff2697efff88dd4059c41954f4bdd84bd3063c.tar.zst
bun-cdff2697efff88dd4059c41954f4bdd84bd3063c.zip
Implement `sendText`, `sendBinary`, `publishText`, `publishBinary`
-rw-r--r--src/bun.js/api/server.classes.ts34
-rw-r--r--src/bun.js/api/server.zig371
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses.cpp208
-rw-r--r--src/bun.js/bindings/bindings.cpp5
-rw-r--r--src/bun.js/bindings/bindings.zig16
-rw-r--r--src/bun.js/bindings/generated_classes.zig37
-rw-r--r--src/bun.js/bindings/headers-cpp.h2
-rw-r--r--src/bun.js/bindings/headers.h3
-rw-r--r--src/bun.js/bindings/headers.zig1
-rw-r--r--src/bun.js/scripts/class-definitions.ts1
-rw-r--r--src/bun.js/scripts/generate-classes.ts138
-rw-r--r--test/bun.js/websocket-server.test.ts116
12 files changed, 917 insertions, 15 deletions
diff --git a/src/bun.js/api/server.classes.ts b/src/bun.js/api/server.classes.ts
index 19005c1d4..b3d174957 100644
--- a/src/bun.js/api/server.classes.ts
+++ b/src/bun.js/api/server.classes.ts
@@ -29,6 +29,40 @@ export default [
fn: "send",
length: 2,
},
+ sendText: {
+ fn: "sendText",
+ length: 2,
+ DOMJIT: {
+ returns: "int",
+ args: ["JSString", "bool"],
+ },
+ },
+ sendBinary: {
+ fn: "sendBinary",
+ length: 2,
+ DOMJIT: {
+ returns: "int",
+ args: ["JSUint8Array", "bool"],
+ },
+ },
+
+ publishText: {
+ fn: "publishText",
+ length: 2,
+ DOMJIT: {
+ returns: "int",
+ args: ["JSString", "JSString"],
+ },
+ },
+ publishBinary: {
+ fn: "publishBinary",
+ length: 2,
+ DOMJIT: {
+ returns: "int",
+ args: ["JSString", "JSUint8Array"],
+ },
+ },
+
close: {
fn: "close",
length: 1,
diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig
index b4a351089..30ba4d714 100644
--- a/src/bun.js/api/server.zig
+++ b/src/bun.js/api/server.zig
@@ -2542,6 +2542,7 @@ pub const ServerWebSocket = struct {
websocket: uws.AnyWebSocket = undefined,
closed: bool = false,
binary_type: JSC.JSValue.JSType = .Uint8Array,
+ opened: bool = false,
pub usingnamespace JSC.Codegen.JSServerWebSocket;
@@ -2562,6 +2563,7 @@ pub const ServerWebSocket = struct {
const onOpenHandler = handler.onOpen;
this.this_value = .zero;
+ this.opened = false;
if (value_to_cache != .zero) {
const current_this = this.getThisValue();
ServerWebSocket.dataSetCached(current_this, globalObject, value_to_cache);
@@ -2579,10 +2581,15 @@ pub const ServerWebSocket = struct {
const error_handler = handler.onError;
ws.cork(&corker, Corker.run);
const result = corker.result;
+ this.opened = true;
if (result.isAnyError(globalObject)) {
log("onOpen exception", .{});
- ws.close();
+ if (!this.closed) {
+ this.closed = true;
+ this.websocket.end(1000, "");
+ }
+
_ = ServerWebSocket.dangerouslySetPtr(this_value, null);
handler.active_connections -|= 1;
this_value.unprotect();
@@ -2808,7 +2815,7 @@ pub const ServerWebSocket = struct {
return JSValue.jsNumber(
// if 0, return 0
// else return number of bytes sent
- @as(i32, @boolToInt(this.websocket.publishWithOptions(this.handler.app, topic_slice.slice(), buffer.slice(), .text, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
+ @as(i32, @boolToInt(this.websocket.publishWithOptions(this.handler.app, topic_slice.slice(), buffer.slice(), .binary, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
);
}
@@ -2830,6 +2837,195 @@ pub const ServerWebSocket = struct {
return .zero;
}
+ pub fn publishText(
+ this: *ServerWebSocket,
+ globalThis: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ const args = callframe.arguments(4);
+
+ if (args.len < 1) {
+ log("publish()", .{});
+ globalThis.throw("publish requires at least 1 argument", .{});
+ return .zero;
+ }
+
+ if (this.closed) {
+ log("publish() closed", .{});
+ return JSValue.jsNumber(0);
+ }
+
+ const topic_value = args.ptr[0];
+ const message_value = args.ptr[1];
+ const compress_value = args.ptr[2];
+
+ if (topic_value.isEmptyOrUndefinedOrNull() or !topic_value.isString()) {
+ log("publish() topic invalid", .{});
+ globalThis.throw("publishText requires a topic string", .{});
+ return .zero;
+ }
+
+ var topic_slice = topic_value.toSlice(globalThis, bun.default_allocator);
+ defer topic_slice.deinit();
+ if (topic_slice.len == 0) {
+ globalThis.throw("publishText requires a non-empty topic", .{});
+ return .zero;
+ }
+
+ const compress = args.len > 1 and compress_value.toBoolean();
+
+ if (message_value.isEmptyOrUndefinedOrNull() or !message_value.isString()) {
+ globalThis.throw("publishText requires a non-empty message", .{});
+ return .zero;
+ }
+
+ var string_slice = message_value.toSlice(globalThis, bun.default_allocator);
+ defer string_slice.deinit();
+ if (string_slice.len == 0) {
+ return JSValue.jsNumber(0);
+ }
+
+ const buffer = string_slice.slice();
+ return JSValue.jsNumber(
+ // if 0, return 0
+ // else return number of bytes sent
+ @as(i32, @boolToInt(this.websocket.publishWithOptions(this.handler.app, topic_slice.slice(), buffer, .text, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
+ );
+ }
+
+ pub fn publishBinary(
+ this: *ServerWebSocket,
+ globalThis: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ const args = callframe.arguments(4);
+
+ if (args.len < 1) {
+ log("publishBinary()", .{});
+ globalThis.throw("publishBinary requires at least 1 argument", .{});
+ return .zero;
+ }
+
+ if (this.closed) {
+ log("publishBinary() closed", .{});
+ return JSValue.jsNumber(0);
+ }
+
+ const topic_value = args.ptr[0];
+ const message_value = args.ptr[1];
+ const compress_value = args.ptr[2];
+
+ if (topic_value.isEmptyOrUndefinedOrNull() or !topic_value.isString()) {
+ log("publishBinary() topic invalid", .{});
+ globalThis.throw("publishBinary requires a topic string", .{});
+ return .zero;
+ }
+
+ var topic_slice = topic_value.toSlice(globalThis, bun.default_allocator);
+ defer topic_slice.deinit();
+ if (topic_slice.len == 0) {
+ globalThis.throw("publishBinary requires a non-empty topic", .{});
+ return .zero;
+ }
+
+ const compress = args.len > 1 and compress_value.toBoolean();
+
+ if (message_value.isEmptyOrUndefinedOrNull()) {
+ globalThis.throw("publishBinary requires a non-empty message", .{});
+ return .zero;
+ }
+ const buffer = message_value.asArrayBuffer(globalThis) orelse {
+ globalThis.throw("publishBinary expects an ArrayBufferView", .{});
+ return .zero;
+ };
+
+ if (buffer.len == 0) {
+ return JSC.JSValue.jsNumber(0);
+ }
+
+ return JSValue.jsNumber(
+ // if 0, return 0
+ // else return number of bytes sent
+ @as(i32, @boolToInt(this.websocket.publishWithOptions(this.handler.app, topic_slice.slice(), buffer.slice(), .binary, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
+ );
+ }
+
+ pub fn publishBinaryWithoutTypeChecks(
+ this: *ServerWebSocket,
+ globalThis: *JSC.JSGlobalObject,
+ topic_str: *JSC.JSString,
+ buffer: *JSC.JSUint8Array,
+ ) callconv(.C) JSC.JSValue {
+ if (this.closed) {
+ log("publishBinary() closed", .{});
+ return JSValue.jsNumber(0);
+ }
+
+ var topic_slice = topic_str.toSlice(globalThis, bun.default_allocator);
+ defer topic_slice.deinit();
+ if (topic_slice.len == 0) {
+ globalThis.throw("publishBinary requires a non-empty topic", .{});
+ return .zero;
+ }
+
+ const compress = true;
+
+ const slice = buffer.slice();
+ if (slice.len == 0) {
+ return JSC.JSValue.jsNumber(0);
+ }
+
+ return JSValue.jsNumber(
+ // if 0, return 0
+ // else return number of bytes sent
+ @as(i32, @boolToInt(this.websocket.publishWithOptions(this.handler.app, topic_slice.slice(), slice, .binary, compress))) * @intCast(
+ i32,
+ @truncate(u31, slice.len),
+ ),
+ );
+ }
+
+ pub fn publishTextWithoutTypeChecks(
+ this: *ServerWebSocket,
+ globalThis: *JSC.JSGlobalObject,
+ topic_str: *JSC.JSString,
+ str: *JSC.JSString,
+ ) callconv(.C) JSC.JSValue {
+ if (this.closed) {
+ log("publishBinary() closed", .{});
+ return JSValue.jsNumber(0);
+ }
+
+ var topic_slice = topic_str.toSlice(globalThis, bun.default_allocator);
+ defer topic_slice.deinit();
+ if (topic_slice.len == 0) {
+ globalThis.throw("publishBinary requires a non-empty topic", .{});
+ return .zero;
+ }
+
+ const compress = true;
+
+ const slice = str.toSlice(globalThis, bun.default_allocator);
+ if (slice.len == 0) {
+ return JSC.JSValue.jsNumber(0);
+ }
+
+ return JSValue.jsNumber(
+ // if 0, return 0
+ // else return number of bytes sent
+ @as(i32, @boolToInt(this.websocket.publishWithOptions(
+ this.handler.app,
+ topic_slice.slice(),
+ slice.slice(),
+ .text,
+ compress,
+ ))) * @intCast(
+ i32,
+ @truncate(u31, slice.len),
+ ),
+ );
+ }
+
pub fn cork(
this: *ServerWebSocket,
globalThis: *JSC.JSGlobalObject,
@@ -2901,8 +3097,7 @@ pub const ServerWebSocket = struct {
if (message_value.asArrayBuffer(globalThis)) |buffer| {
if (buffer.len == 0) {
- globalThis.throw("send requires a non-empty message", .{});
- return .zero;
+ return JSValue.jsNumber(0);
}
switch (this.websocket.send(buffer.slice(), .binary, compress, true)) {
@@ -2948,6 +3143,172 @@ pub const ServerWebSocket = struct {
return .zero;
}
+ pub fn sendText(
+ this: *ServerWebSocket,
+ globalThis: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ const args = callframe.arguments(2);
+
+ if (args.len < 1) {
+ log("sendText()", .{});
+ globalThis.throw("sendText requires at least 1 argument", .{});
+ return .zero;
+ }
+
+ if (this.closed) {
+ log("sendText() closed", .{});
+ return JSValue.jsNumber(0);
+ }
+
+ const message_value = args.ptr[0];
+ const compress_value = args.ptr[1];
+
+ const compress = args.len > 1 and compress_value.toBoolean();
+
+ if (message_value.isEmptyOrUndefinedOrNull() or !message_value.isString()) {
+ globalThis.throw("sendText expects a string", .{});
+ return .zero;
+ }
+
+ var string_slice = message_value.toSlice(globalThis, bun.default_allocator);
+ defer string_slice.deinit();
+ if (string_slice.len == 0) {
+ return JSValue.jsNumber(0);
+ }
+
+ const buffer = string_slice.slice();
+ switch (this.websocket.send(buffer, .text, compress, true)) {
+ .backpressure => {
+ log("sendText() backpressure ({d} bytes string)", .{buffer.len});
+ return JSValue.jsNumber(-1);
+ },
+ .success => {
+ log("sendText() success ({d} bytes string)", .{buffer.len});
+ return JSValue.jsNumber(buffer.len);
+ },
+ .dropped => {
+ log("sendText() dropped ({d} bytes string)", .{buffer.len});
+ return JSValue.jsNumber(0);
+ },
+ }
+ }
+
+ pub fn sendTextWithoutTypeChecks(
+ this: *ServerWebSocket,
+ globalThis: *JSC.JSGlobalObject,
+ message_str: *JSC.JSString,
+ compress: bool,
+ ) callconv(.C) JSValue {
+ if (this.closed) {
+ log("sendText() closed", .{});
+ return JSValue.jsNumber(0);
+ }
+
+ var string_slice = message_str.toSlice(globalThis, bun.default_allocator);
+ defer string_slice.deinit();
+ if (string_slice.len == 0) {
+ return JSValue.jsNumber(0);
+ }
+
+ const buffer = string_slice.slice();
+ switch (this.websocket.send(buffer, .text, compress, true)) {
+ .backpressure => {
+ log("sendText() backpressure ({d} bytes string)", .{buffer.len});
+ return JSValue.jsNumber(-1);
+ },
+ .success => {
+ log("sendText() success ({d} bytes string)", .{buffer.len});
+ return JSValue.jsNumber(buffer.len);
+ },
+ .dropped => {
+ log("sendText() dropped ({d} bytes string)", .{buffer.len});
+ return JSValue.jsNumber(0);
+ },
+ }
+ }
+
+ pub fn sendBinary(
+ this: *ServerWebSocket,
+ globalThis: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ const args = callframe.arguments(2);
+
+ if (args.len < 1) {
+ log("sendBinary()", .{});
+ globalThis.throw("sendBinary requires at least 1 argument", .{});
+ return .zero;
+ }
+
+ if (this.closed) {
+ log("sendBinary() closed", .{});
+ return JSValue.jsNumber(0);
+ }
+
+ const message_value = args.ptr[0];
+ const compress_value = args.ptr[1];
+
+ const compress = args.len > 1 and compress_value.toBoolean();
+
+ const buffer = message_value.asArrayBuffer(globalThis) orelse {
+ globalThis.throw("sendBinary requires an ArrayBufferView", .{});
+ return .zero;
+ };
+
+ if (buffer.len == 0) {
+ return JSValue.jsNumber(0);
+ }
+
+ switch (this.websocket.send(buffer.slice(), .binary, compress, true)) {
+ .backpressure => {
+ log("sendBinary() backpressure ({d} bytes)", .{buffer.len});
+ return JSValue.jsNumber(-1);
+ },
+ .success => {
+ log("sendBinary() success ({d} bytes)", .{buffer.len});
+ return JSValue.jsNumber(buffer.slice().len);
+ },
+ .dropped => {
+ log("sendBinary() dropped ({d} bytes)", .{buffer.len});
+ return JSValue.jsNumber(0);
+ },
+ }
+ }
+
+ pub fn sendBinaryWithoutTypeChecks(
+ this: *ServerWebSocket,
+ _: *JSC.JSGlobalObject,
+ array_buffer: *JSC.JSUint8Array,
+ compress: bool,
+ ) callconv(.C) JSValue {
+ if (this.closed) {
+ log("sendBinary() closed", .{});
+ return JSValue.jsNumber(0);
+ }
+
+ const buffer = array_buffer.slice();
+
+ if (buffer.len == 0) {
+ return JSValue.jsNumber(0);
+ }
+
+ switch (this.websocket.send(buffer, .binary, compress, true)) {
+ .backpressure => {
+ log("sendBinary() backpressure ({d} bytes)", .{buffer.len});
+ return JSValue.jsNumber(-1);
+ },
+ .success => {
+ log("sendBinary() success ({d} bytes)", .{buffer.len});
+ return JSValue.jsNumber(buffer.len);
+ },
+ .dropped => {
+ log("sendBinary() dropped ({d} bytes)", .{buffer.len});
+ return JSValue.jsNumber(0);
+ },
+ }
+ }
+
pub fn getData(
_: *ServerWebSocket,
_: *JSC.JSGlobalObject,
@@ -2988,7 +3349,7 @@ pub const ServerWebSocket = struct {
log("close()", .{});
if (this.closed) {
- return .zero;
+ return JSValue.jsUndefined();
}
const code = if (args.len > 0) args.ptr[0].toInt32() else @as(i32, 1000);
diff --git a/src/bun.js/bindings/ZigGeneratedClasses.cpp b/src/bun.js/bindings/ZigGeneratedClasses.cpp
index 62952f004..26fcec7b6 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses.cpp
+++ b/src/bun.js/bindings/ZigGeneratedClasses.cpp
@@ -94,6 +94,7 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSSubprocessPrototype, JSSubprocessPrototype
};
+
const ClassInfo JSSubprocessPrototype::s_info = { "Subprocess"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSubprocessPrototype) };
@@ -524,6 +525,7 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSSHA1Prototype, JSSHA1Prototype::Base);
};
+
const ClassInfo JSSHA1Prototype::s_info = { "SHA1"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSHA1Prototype) };
@@ -762,6 +764,7 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSMD5Prototype, JSMD5Prototype::Base);
};
+
const ClassInfo JSMD5Prototype::s_info = { "MD5"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSMD5Prototype) };
@@ -1000,6 +1003,7 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSMD4Prototype, JSMD4Prototype::Base);
};
+
const ClassInfo JSMD4Prototype::s_info = { "MD4"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSMD4Prototype) };
@@ -1238,6 +1242,7 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSSHA224Prototype, JSSHA224Prototype::Base);
};
+
const ClassInfo JSSHA224Prototype::s_info = { "SHA224"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSHA224Prototype) };
@@ -1476,6 +1481,7 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSSHA512Prototype, JSSHA512Prototype::Base);
};
+
const ClassInfo JSSHA512Prototype::s_info = { "SHA512"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSHA512Prototype) };
@@ -1714,6 +1720,7 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSSHA384Prototype, JSSHA384Prototype::Base);
};
+
const ClassInfo JSSHA384Prototype::s_info = { "SHA384"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSHA384Prototype) };
@@ -1952,6 +1959,7 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSSHA256Prototype, JSSHA256Prototype::Base);
};
+
const ClassInfo JSSHA256Prototype::s_info = { "SHA256"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSHA256Prototype) };
@@ -2190,6 +2198,7 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSSHA512_256Prototype, JSSHA512_256Prototype
};
+
const ClassInfo JSSHA512_256Prototype::s_info = { "SHA512_256"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSHA512_256Prototype) };
@@ -2406,6 +2415,14 @@ JSObject* JSSHA512_256::createPrototype(VM& vm, JSDOMGlobalObject* globalObject)
JSC_DECLARE_CUSTOM_GETTER(jsServerWebSocketConstructor);
extern "C" void ServerWebSocketClass__finalize(void*);
+extern "C" JSC::EncodedJSValue ServerWebSocketPrototype__getBinaryType(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(ServerWebSocketPrototype__binaryTypeGetterWrap);
+
+
+extern "C" bool ServerWebSocketPrototype__setBinaryType(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::EncodedJSValue value);
+JSC_DECLARE_CUSTOM_SETTER(ServerWebSocketPrototype__binaryTypeSetterWrap);
+
+
extern "C" EncodedJSValue ServerWebSocketPrototype__close(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
JSC_DECLARE_HOST_FUNCTION(ServerWebSocketPrototype__closeCallback);
@@ -2434,6 +2451,50 @@ extern "C" EncodedJSValue ServerWebSocketPrototype__publish(void* ptr, JSC::JSGl
JSC_DECLARE_HOST_FUNCTION(ServerWebSocketPrototype__publishCallback);
+extern "C" EncodedJSValue ServerWebSocketPrototype__publishBinary(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(ServerWebSocketPrototype__publishBinaryCallback);
+
+
+extern "C" JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(ServerWebSocketPrototype__publishBinaryWithoutTypeChecksWrapper, EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, void* thisValue, JSC::JSString* arg0, JSC::JSUint8Array* arg1));
+ extern "C" EncodedJSValue ServerWebSocketPrototype__publishBinaryWithoutTypeChecks(void* ptr, JSC::JSGlobalObject * lexicalGlobalObject, JSC::JSString* arg0, JSC::JSUint8Array* arg1);
+
+ static const JSC::DOMJIT::Signature DOMJITSignatureForServerWebSocketPrototype__publishBinary(ServerWebSocketPrototype__publishBinaryWithoutTypeChecksWrapper,
+ JSServerWebSocket::info(),
+ JSC::DOMJIT::Effect::forReadWrite(JSC::DOMJIT::HeapRange::top(), JSC::DOMJIT::HeapRange::top()),
+ JSC::SpecHeapTop, JSC::SpecString, JSC::SpecUint8Array);
+
+JSC_DEFINE_JIT_OPERATION(ServerWebSocketPrototype__publishBinaryWithoutTypeChecksWrapper, EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, void* thisValue, JSC::JSString* arg0, JSC::JSUint8Array* arg1))
+{
+ VM& vm = JSC::getVM(lexicalGlobalObject);
+ IGNORE_WARNINGS_BEGIN("frame-address")
+ CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+ IGNORE_WARNINGS_END
+ JSC::JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+ return ServerWebSocketPrototype__publishBinaryWithoutTypeChecks(reinterpret_cast<JSServerWebSocket*>(thisValue)->wrapped(), lexicalGlobalObject, arg0, arg1);
+}
+
+extern "C" EncodedJSValue ServerWebSocketPrototype__publishText(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(ServerWebSocketPrototype__publishTextCallback);
+
+
+extern "C" JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(ServerWebSocketPrototype__publishTextWithoutTypeChecksWrapper, EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, void* thisValue, JSC::JSString* arg0, JSC::JSString* arg1));
+ extern "C" EncodedJSValue ServerWebSocketPrototype__publishTextWithoutTypeChecks(void* ptr, JSC::JSGlobalObject * lexicalGlobalObject, JSC::JSString* arg0, JSC::JSString* arg1);
+
+ static const JSC::DOMJIT::Signature DOMJITSignatureForServerWebSocketPrototype__publishText(ServerWebSocketPrototype__publishTextWithoutTypeChecksWrapper,
+ JSServerWebSocket::info(),
+ JSC::DOMJIT::Effect::forReadWrite(JSC::DOMJIT::HeapRange::top(), JSC::DOMJIT::HeapRange::top()),
+ JSC::SpecHeapTop, JSC::SpecString, JSC::SpecString);
+
+JSC_DEFINE_JIT_OPERATION(ServerWebSocketPrototype__publishTextWithoutTypeChecksWrapper, EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, void* thisValue, JSC::JSString* arg0, JSC::JSString* arg1))
+{
+ VM& vm = JSC::getVM(lexicalGlobalObject);
+ IGNORE_WARNINGS_BEGIN("frame-address")
+ CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+ IGNORE_WARNINGS_END
+ JSC::JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+ return ServerWebSocketPrototype__publishTextWithoutTypeChecks(reinterpret_cast<JSServerWebSocket*>(thisValue)->wrapped(), lexicalGlobalObject, arg0, arg1);
+}
+
extern "C" JSC::EncodedJSValue ServerWebSocketPrototype__getReadyState(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
JSC_DECLARE_CUSTOM_GETTER(ServerWebSocketPrototype__readyStateGetterWrap);
@@ -2446,6 +2507,50 @@ extern "C" EncodedJSValue ServerWebSocketPrototype__send(void* ptr, JSC::JSGloba
JSC_DECLARE_HOST_FUNCTION(ServerWebSocketPrototype__sendCallback);
+extern "C" EncodedJSValue ServerWebSocketPrototype__sendBinary(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(ServerWebSocketPrototype__sendBinaryCallback);
+
+
+extern "C" JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(ServerWebSocketPrototype__sendBinaryWithoutTypeChecksWrapper, EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, void* thisValue, JSC::JSUint8Array* arg0, bool arg1));
+ extern "C" EncodedJSValue ServerWebSocketPrototype__sendBinaryWithoutTypeChecks(void* ptr, JSC::JSGlobalObject * lexicalGlobalObject, JSC::JSUint8Array* arg0, bool arg1);
+
+ static const JSC::DOMJIT::Signature DOMJITSignatureForServerWebSocketPrototype__sendBinary(ServerWebSocketPrototype__sendBinaryWithoutTypeChecksWrapper,
+ JSServerWebSocket::info(),
+ JSC::DOMJIT::Effect::forReadWrite(JSC::DOMJIT::HeapRange::top(), JSC::DOMJIT::HeapRange::top()),
+ JSC::SpecHeapTop, JSC::SpecUint8Array, JSC::SpecBoolean);
+
+JSC_DEFINE_JIT_OPERATION(ServerWebSocketPrototype__sendBinaryWithoutTypeChecksWrapper, EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, void* thisValue, JSC::JSUint8Array* arg0, bool arg1))
+{
+ VM& vm = JSC::getVM(lexicalGlobalObject);
+ IGNORE_WARNINGS_BEGIN("frame-address")
+ CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+ IGNORE_WARNINGS_END
+ JSC::JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+ return ServerWebSocketPrototype__sendBinaryWithoutTypeChecks(reinterpret_cast<JSServerWebSocket*>(thisValue)->wrapped(), lexicalGlobalObject, arg0, arg1);
+}
+
+extern "C" EncodedJSValue ServerWebSocketPrototype__sendText(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(ServerWebSocketPrototype__sendTextCallback);
+
+
+extern "C" JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(ServerWebSocketPrototype__sendTextWithoutTypeChecksWrapper, EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, void* thisValue, JSC::JSString* arg0, bool arg1));
+ extern "C" EncodedJSValue ServerWebSocketPrototype__sendTextWithoutTypeChecks(void* ptr, JSC::JSGlobalObject * lexicalGlobalObject, JSC::JSString* arg0, bool arg1);
+
+ static const JSC::DOMJIT::Signature DOMJITSignatureForServerWebSocketPrototype__sendText(ServerWebSocketPrototype__sendTextWithoutTypeChecksWrapper,
+ JSServerWebSocket::info(),
+ JSC::DOMJIT::Effect::forReadWrite(JSC::DOMJIT::HeapRange::top(), JSC::DOMJIT::HeapRange::top()),
+ JSC::SpecHeapTop, JSC::SpecString, JSC::SpecBoolean);
+
+JSC_DEFINE_JIT_OPERATION(ServerWebSocketPrototype__sendTextWithoutTypeChecksWrapper, EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, void* thisValue, JSC::JSString* arg0, bool arg1))
+{
+ VM& vm = JSC::getVM(lexicalGlobalObject);
+ IGNORE_WARNINGS_BEGIN("frame-address")
+ CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+ IGNORE_WARNINGS_END
+ JSC::JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+ return ServerWebSocketPrototype__sendTextWithoutTypeChecks(reinterpret_cast<JSServerWebSocket*>(thisValue)->wrapped(), lexicalGlobalObject, arg0, arg1);
+}
+
extern "C" EncodedJSValue ServerWebSocketPrototype__subscribe(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
JSC_DECLARE_HOST_FUNCTION(ServerWebSocketPrototype__subscribeCallback);
@@ -2458,20 +2563,26 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSServerWebSocketPrototype, JSServerWebSocke
static const HashTableValue JSServerWebSocketPrototypeTableValues[] = {
+{ "binaryType"_s, static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, ServerWebSocketPrototype__binaryTypeGetterWrap, ServerWebSocketPrototype__binaryTypeSetterWrap } } ,
{ "close"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ServerWebSocketPrototype__closeCallback, 1 } } ,
{ "cork"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ServerWebSocketPrototype__corkCallback, 1 } } ,
{ "data"_s, static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, ServerWebSocketPrototype__dataGetterWrap, ServerWebSocketPrototype__dataSetterWrap } } ,
{ "getBufferedAmount"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ServerWebSocketPrototype__getBufferedAmountCallback, 0 } } ,
{ "isSubscribed"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ServerWebSocketPrototype__isSubscribedCallback, 1 } } ,
{ "publish"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ServerWebSocketPrototype__publishCallback, 3 } } ,
+{ "publishBinary"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction), NoIntrinsic, { HashTableValue::DOMJITFunctionType, ServerWebSocketPrototype__publishBinaryCallback, &DOMJITSignatureForServerWebSocketPrototype__publishBinary } } ,
+{ "publishText"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction), NoIntrinsic, { HashTableValue::DOMJITFunctionType, ServerWebSocketPrototype__publishTextCallback, &DOMJITSignatureForServerWebSocketPrototype__publishText } } ,
{ "readyState"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, ServerWebSocketPrototype__readyStateGetterWrap, 0 } } ,
{ "remoteAddress"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, ServerWebSocketPrototype__remoteAddressGetterWrap, 0 } } ,
{ "send"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ServerWebSocketPrototype__sendCallback, 2 } } ,
+{ "sendBinary"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction), NoIntrinsic, { HashTableValue::DOMJITFunctionType, ServerWebSocketPrototype__sendBinaryCallback, &DOMJITSignatureForServerWebSocketPrototype__sendBinary } } ,
+{ "sendText"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction), NoIntrinsic, { HashTableValue::DOMJITFunctionType, ServerWebSocketPrototype__sendTextCallback, &DOMJITSignatureForServerWebSocketPrototype__sendText } } ,
{ "subscribe"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ServerWebSocketPrototype__subscribeCallback, 1 } } ,
{ "unsubscribe"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ServerWebSocketPrototype__unsubscribeCallback, 1 } }
};
+
const ClassInfo JSServerWebSocketPrototype::s_info = { "ServerWebSocket"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSServerWebSocketPrototype) };
@@ -2490,6 +2601,31 @@ JSC_DEFINE_CUSTOM_GETTER(jsServerWebSocketConstructor, (JSGlobalObject * lexical
+JSC_DEFINE_CUSTOM_GETTER(ServerWebSocketPrototype__binaryTypeGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSServerWebSocket* thisObject = jsCast<JSServerWebSocket*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+ JSC::EncodedJSValue result = ServerWebSocketPrototype__getBinaryType(thisObject->wrapped(), globalObject);
+ RETURN_IF_EXCEPTION(throwScope, {});
+ RELEASE_AND_RETURN(throwScope, result);
+}
+
+
+JSC_DEFINE_CUSTOM_SETTER(ServerWebSocketPrototype__binaryTypeSetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSServerWebSocket* thisObject = jsCast<JSServerWebSocket*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+ auto result = ServerWebSocketPrototype__setBinaryType(thisObject->wrapped(), lexicalGlobalObject, encodedValue);
+
+ RELEASE_AND_RETURN(throwScope, result);
+}
+
+
JSC_DEFINE_HOST_FUNCTION(ServerWebSocketPrototype__closeCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
{
auto& vm = lexicalGlobalObject->vm();
@@ -2613,6 +2749,40 @@ JSC_DEFINE_HOST_FUNCTION(ServerWebSocketPrototype__publishCallback, (JSGlobalObj
}
+JSC_DEFINE_HOST_FUNCTION(ServerWebSocketPrototype__publishBinaryCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSServerWebSocket* thisObject = jsDynamicCast<JSServerWebSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return ServerWebSocketPrototype__publishBinary(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(ServerWebSocketPrototype__publishTextCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSServerWebSocket* thisObject = jsDynamicCast<JSServerWebSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return ServerWebSocketPrototype__publishText(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
JSC_DEFINE_CUSTOM_GETTER(ServerWebSocketPrototype__readyStateGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
{
auto& vm = lexicalGlobalObject->vm();
@@ -2669,6 +2839,40 @@ JSC_DEFINE_HOST_FUNCTION(ServerWebSocketPrototype__sendCallback, (JSGlobalObject
}
+JSC_DEFINE_HOST_FUNCTION(ServerWebSocketPrototype__sendBinaryCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSServerWebSocket* thisObject = jsDynamicCast<JSServerWebSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return ServerWebSocketPrototype__sendBinary(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(ServerWebSocketPrototype__sendTextCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSServerWebSocket* thisObject = jsDynamicCast<JSServerWebSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return ServerWebSocketPrototype__sendText(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
JSC_DEFINE_HOST_FUNCTION(ServerWebSocketPrototype__subscribeCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
{
auto& vm = lexicalGlobalObject->vm();
@@ -2881,6 +3085,7 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSTextDecoderPrototype, JSTextDecoderPrototy
};
+
const ClassInfo JSTextDecoderPrototype::s_info = { "TextDecoder"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTextDecoderPrototype) };
@@ -3207,6 +3412,7 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSRequestPrototype, JSRequestPrototype::Base
};
+
const ClassInfo JSRequestPrototype::s_info = { "Request"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSRequestPrototype) };
@@ -3758,6 +3964,7 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSResponsePrototype, JSResponsePrototype::Ba
};
+
const ClassInfo JSResponsePrototype::s_info = { "Response"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSResponsePrototype) };
@@ -4253,6 +4460,7 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSBlobPrototype, JSBlobPrototype::Base);
};
+
const ClassInfo JSBlobPrototype::s_info = { "Blob"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSBlobPrototype) };
diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp
index 1341023ef..0cba2185d 100644
--- a/src/bun.js/bindings/bindings.cpp
+++ b/src/bun.js/bindings/bindings.cpp
@@ -836,6 +836,11 @@ unsigned char JSC__JSCell__getType(JSC__JSCell* arg0) { return arg0->type(); }
#pragma mark - JSC::JSString
+void JSC__JSString__toZigString(JSC__JSString* arg0, JSC__JSGlobalObject* arg1, ZigString* arg2)
+{
+ *arg2 = Zig::toZigString(arg0->value(arg1));
+}
+
JSC__JSString* JSC__JSString__createFromOwnedString(JSC__VM* arg0, const WTF__String* arg1)
{
return JSC::jsOwnedString(reinterpret_cast<JSC__VM&>(arg0),
diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig
index 8d119821d..021cd2d84 100644
--- a/src/bun.js/bindings/bindings.zig
+++ b/src/bun.js/bindings/bindings.zig
@@ -1171,6 +1171,20 @@ pub const JSString = extern struct {
return shim.cppFn("toObject", .{ this, global });
}
+ pub fn toZigString(this: *JSString, global: *JSGlobalObject, zig_str: *JSC.ZigString) void {
+ return shim.cppFn("toZigString", .{ this, global, zig_str });
+ }
+
+ pub fn toSlice(
+ this: *JSString,
+ global: *JSGlobalObject,
+ allocator: std.mem.Allocator,
+ ) ZigString.Slice {
+ var str = ZigString.init("");
+ this.toZigString(global, &str);
+ return str.toSlice(allocator);
+ }
+
pub fn eql(this: *const JSString, global: *JSGlobalObject, other: *JSString) bool {
return shim.cppFn("eql", .{ this, global, other });
}
@@ -1220,7 +1234,7 @@ pub const JSString = extern struct {
write16: ?JStringIteratorWrite16Callback,
};
- pub const Extern = [_][]const u8{ "iterator", "toObject", "eql", "value", "length", "is8Bit", "createFromOwnedString", "createFromString" };
+ pub const Extern = [_][]const u8{ "toZigString", "iterator", "toObject", "eql", "value", "length", "is8Bit", "createFromOwnedString", "createFromString" };
};
pub const JSPromiseRejectionOperation = enum(u32) {
diff --git a/src/bun.js/bindings/generated_classes.zig b/src/bun.js/bindings/generated_classes.zig
index 6649881ac..5cb04779a 100644
--- a/src/bun.js/bindings/generated_classes.zig
+++ b/src/bun.js/bindings/generated_classes.zig
@@ -25,6 +25,7 @@ pub const JSSubprocess = struct {
/// Set the cached value for stderr on Subprocess
/// This value will be visited by the garbage collector.
pub fn stderrSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
SubprocessPrototype__stderrSetCachedValue(thisValue, globalObject, value);
}
@@ -33,6 +34,7 @@ pub const JSSubprocess = struct {
/// Set the cached value for stdin on Subprocess
/// This value will be visited by the garbage collector.
pub fn stdinSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
SubprocessPrototype__stdinSetCachedValue(thisValue, globalObject, value);
}
@@ -41,6 +43,7 @@ pub const JSSubprocess = struct {
/// Set the cached value for stdout on Subprocess
/// This value will be visited by the garbage collector.
pub fn stdoutSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
SubprocessPrototype__stdoutSetCachedValue(thisValue, globalObject, value);
}
@@ -768,6 +771,7 @@ pub const JSServerWebSocket = struct {
/// Set the cached value for data on ServerWebSocket
/// This value will be visited by the garbage collector.
pub fn dataSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
ServerWebSocketPrototype__dataSetCachedValue(thisValue, globalObject, value);
}
@@ -776,6 +780,7 @@ pub const JSServerWebSocket = struct {
/// Set the cached value for remoteAddress on ServerWebSocket
/// This value will be visited by the garbage collector.
pub fn remoteAddressSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
ServerWebSocketPrototype__remoteAddressSetCachedValue(thisValue, globalObject, value);
}
@@ -840,6 +845,14 @@ pub const JSServerWebSocket = struct {
@compileLog("Expected ServerWebSocket.isSubscribed to be a callback");
if (@TypeOf(ServerWebSocket.publish) != CallbackType)
@compileLog("Expected ServerWebSocket.publish to be a callback");
+ if (@TypeOf(ServerWebSocket.publishBinaryWithoutTypeChecks) != fn (*ServerWebSocket, *JSC.JSGlobalObject, *JSC.JSString, *JSC.JSUint8Array) callconv(.C) JSC.JSValue)
+ @compileLog("Expected ServerWebSocket.publishBinaryWithoutTypeChecks to be a DOMJIT function");
+ if (@TypeOf(ServerWebSocket.publishBinary) != CallbackType)
+ @compileLog("Expected ServerWebSocket.publishBinary to be a callback");
+ if (@TypeOf(ServerWebSocket.publishTextWithoutTypeChecks) != fn (*ServerWebSocket, *JSC.JSGlobalObject, *JSC.JSString, *JSC.JSString) callconv(.C) JSC.JSValue)
+ @compileLog("Expected ServerWebSocket.publishTextWithoutTypeChecks to be a DOMJIT function");
+ if (@TypeOf(ServerWebSocket.publishText) != CallbackType)
+ @compileLog("Expected ServerWebSocket.publishText to be a callback");
if (@TypeOf(ServerWebSocket.getReadyState) != GetterType)
@compileLog("Expected ServerWebSocket.getReadyState to be a getter");
@@ -848,6 +861,14 @@ pub const JSServerWebSocket = struct {
if (@TypeOf(ServerWebSocket.send) != CallbackType)
@compileLog("Expected ServerWebSocket.send to be a callback");
+ if (@TypeOf(ServerWebSocket.sendBinaryWithoutTypeChecks) != fn (*ServerWebSocket, *JSC.JSGlobalObject, *JSC.JSUint8Array, bool) callconv(.C) JSC.JSValue)
+ @compileLog("Expected ServerWebSocket.sendBinaryWithoutTypeChecks to be a DOMJIT function");
+ if (@TypeOf(ServerWebSocket.sendBinary) != CallbackType)
+ @compileLog("Expected ServerWebSocket.sendBinary to be a callback");
+ if (@TypeOf(ServerWebSocket.sendTextWithoutTypeChecks) != fn (*ServerWebSocket, *JSC.JSGlobalObject, *JSC.JSString, bool) callconv(.C) JSC.JSValue)
+ @compileLog("Expected ServerWebSocket.sendTextWithoutTypeChecks to be a DOMJIT function");
+ if (@TypeOf(ServerWebSocket.sendText) != CallbackType)
+ @compileLog("Expected ServerWebSocket.sendText to be a callback");
if (@TypeOf(ServerWebSocket.subscribe) != CallbackType)
@compileLog("Expected ServerWebSocket.subscribe to be a callback");
if (@TypeOf(ServerWebSocket.unsubscribe) != CallbackType)
@@ -864,7 +885,15 @@ pub const JSServerWebSocket = struct {
@export(ServerWebSocket.getRemoteAddress, .{ .name = "ServerWebSocketPrototype__getRemoteAddress" });
@export(ServerWebSocket.isSubscribed, .{ .name = "ServerWebSocketPrototype__isSubscribed" });
@export(ServerWebSocket.publish, .{ .name = "ServerWebSocketPrototype__publish" });
+ @export(ServerWebSocket.publishBinary, .{ .name = "ServerWebSocketPrototype__publishBinary" });
+ @export(ServerWebSocket.publishBinaryWithoutTypeChecks, .{ .name = "ServerWebSocketPrototype__publishBinaryWithoutTypeChecks" });
+ @export(ServerWebSocket.publishText, .{ .name = "ServerWebSocketPrototype__publishText" });
+ @export(ServerWebSocket.publishTextWithoutTypeChecks, .{ .name = "ServerWebSocketPrototype__publishTextWithoutTypeChecks" });
@export(ServerWebSocket.send, .{ .name = "ServerWebSocketPrototype__send" });
+ @export(ServerWebSocket.sendBinary, .{ .name = "ServerWebSocketPrototype__sendBinary" });
+ @export(ServerWebSocket.sendBinaryWithoutTypeChecks, .{ .name = "ServerWebSocketPrototype__sendBinaryWithoutTypeChecks" });
+ @export(ServerWebSocket.sendText, .{ .name = "ServerWebSocketPrototype__sendText" });
+ @export(ServerWebSocket.sendTextWithoutTypeChecks, .{ .name = "ServerWebSocketPrototype__sendTextWithoutTypeChecks" });
@export(ServerWebSocket.setBinaryType, .{ .name = "ServerWebSocketPrototype__setBinaryType" });
@export(ServerWebSocket.setData, .{ .name = "ServerWebSocketPrototype__setData" });
@export(ServerWebSocket.subscribe, .{ .name = "ServerWebSocketPrototype__subscribe" });
@@ -890,6 +919,7 @@ pub const JSTextDecoder = struct {
/// Set the cached value for encoding on TextDecoder
/// This value will be visited by the garbage collector.
pub fn encodingSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
TextDecoderPrototype__encodingSetCachedValue(thisValue, globalObject, value);
}
@@ -969,6 +999,7 @@ pub const JSRequest = struct {
/// Set the cached value for body on Request
/// This value will be visited by the garbage collector.
pub fn bodySetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
RequestPrototype__bodySetCachedValue(thisValue, globalObject, value);
}
@@ -977,6 +1008,7 @@ pub const JSRequest = struct {
/// Set the cached value for headers on Request
/// This value will be visited by the garbage collector.
pub fn headersSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
RequestPrototype__headersSetCachedValue(thisValue, globalObject, value);
}
@@ -985,6 +1017,7 @@ pub const JSRequest = struct {
/// Set the cached value for url on Request
/// This value will be visited by the garbage collector.
pub fn urlSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
RequestPrototype__urlSetCachedValue(thisValue, globalObject, value);
}
@@ -1125,6 +1158,7 @@ pub const JSResponse = struct {
/// Set the cached value for body on Response
/// This value will be visited by the garbage collector.
pub fn bodySetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
ResponsePrototype__bodySetCachedValue(thisValue, globalObject, value);
}
@@ -1133,6 +1167,7 @@ pub const JSResponse = struct {
/// Set the cached value for headers on Response
/// This value will be visited by the garbage collector.
pub fn headersSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
ResponsePrototype__headersSetCachedValue(thisValue, globalObject, value);
}
@@ -1141,6 +1176,7 @@ pub const JSResponse = struct {
/// Set the cached value for statusText on Response
/// This value will be visited by the garbage collector.
pub fn statusTextSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
ResponsePrototype__statusTextSetCachedValue(thisValue, globalObject, value);
}
@@ -1149,6 +1185,7 @@ pub const JSResponse = struct {
/// Set the cached value for url on Response
/// This value will be visited by the garbage collector.
pub fn urlSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
ResponsePrototype__urlSetCachedValue(thisValue, globalObject, value);
}
diff --git a/src/bun.js/bindings/headers-cpp.h b/src/bun.js/bindings/headers-cpp.h
index b64b6cbd0..0bc56c8d0 100644
--- a/src/bun.js/bindings/headers-cpp.h
+++ b/src/bun.js/bindings/headers-cpp.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1665309067
+//-- AUTOGENERATED FILE -- 1666012803
// clang-format off
#pragma once
diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h
index 85e865618..9ab48f4fb 100644
--- a/src/bun.js/bindings/headers.h
+++ b/src/bun.js/bindings/headers.h
@@ -1,5 +1,5 @@
// clang-format off
-//-- AUTOGENERATED FILE -- 1665309067
+//-- AUTOGENERATED FILE -- 1666012803
#pragma once
#include <stddef.h>
@@ -311,6 +311,7 @@ CPP_DECL bool JSC__JSString__is8Bit(const JSC__JSString* arg0);
CPP_DECL void JSC__JSString__iterator(JSC__JSString* arg0, JSC__JSGlobalObject* arg1, void* arg2);
CPP_DECL size_t JSC__JSString__length(const JSC__JSString* arg0);
CPP_DECL JSC__JSObject* JSC__JSString__toObject(JSC__JSString* arg0, JSC__JSGlobalObject* arg1);
+CPP_DECL void JSC__JSString__toZigString(JSC__JSString* arg0, JSC__JSGlobalObject* arg1, ZigString* arg2);
CPP_DECL bWTF__String JSC__JSString__value(JSC__JSString* arg0, JSC__JSGlobalObject* arg1);
#pragma mark - Inspector::ScriptArguments
diff --git a/src/bun.js/bindings/headers.zig b/src/bun.js/bindings/headers.zig
index 0cfe35cff..2f23e8dac 100644
--- a/src/bun.js/bindings/headers.zig
+++ b/src/bun.js/bindings/headers.zig
@@ -141,6 +141,7 @@ pub extern fn JSC__JSString__is8Bit(arg0: [*c]const JSC__JSString) bool;
pub extern fn JSC__JSString__iterator(arg0: [*c]JSC__JSString, arg1: ?*JSC__JSGlobalObject, arg2: ?*anyopaque) void;
pub extern fn JSC__JSString__length(arg0: [*c]const JSC__JSString) usize;
pub extern fn JSC__JSString__toObject(arg0: [*c]JSC__JSString, arg1: ?*JSC__JSGlobalObject) [*c]JSC__JSObject;
+pub extern fn JSC__JSString__toZigString(arg0: [*c]JSC__JSString, arg1: ?*JSC__JSGlobalObject, arg2: [*c]ZigString) void;
pub extern fn JSC__JSString__value(arg0: [*c]JSC__JSString, arg1: ?*JSC__JSGlobalObject) bWTF__String;
pub extern fn Inspector__ScriptArguments__argumentAt(arg0: [*c]bindings.ScriptArguments, arg1: usize) JSC__JSValue;
pub extern fn Inspector__ScriptArguments__argumentCount(arg0: [*c]bindings.ScriptArguments) usize;
diff --git a/src/bun.js/scripts/class-definitions.ts b/src/bun.js/scripts/class-definitions.ts
index 74f04720e..d9d2fa1d1 100644
--- a/src/bun.js/scripts/class-definitions.ts
+++ b/src/bun.js/scripts/class-definitions.ts
@@ -8,7 +8,6 @@ export type Field =
DOMJIT?: {
return: string;
args?: [string, string] | [string, string, string] | [string];
- symbol: string;
};
};
diff --git a/src/bun.js/scripts/generate-classes.ts b/src/bun.js/scripts/generate-classes.ts
index 7755d59aa..21fba1807 100644
--- a/src/bun.js/scripts/generate-classes.ts
+++ b/src/bun.js/scripts/generate-classes.ts
@@ -35,12 +35,108 @@ function constructorName(typeName) {
return `JS${typeName}Constructor`;
}
+function DOMJITName(fnName) {
+ return `${fnName}WithoutTypeChecks`;
+}
+
+function argTypeName(arg) {
+ return {
+ ["bool"]: "bool",
+ ["int"]: "int32_t",
+ ["JSUint8Array"]: "JSC::JSUint8Array*",
+ ["JSString"]: "JSC::JSString*",
+ ["JSValue"]: "JSC::JSValue",
+ }[arg];
+}
+
+function DOMJITType(type) {
+ return {
+ ["bool"]: "JSC::SpecBoolean",
+ ["int"]: "JSC::SpecInt32Only",
+ ["JSUint8Array"]: "JSC::SpecUint8Array",
+ ["JSString"]: "JSC::SpecString",
+ ["JSValue"]: "JSC::SpecHeapTop",
+ }[type];
+}
+
+function ZigDOMJITArgType(type) {
+ return {
+ ["bool"]: "bool",
+ ["int"]: "i32",
+ ["JSUint8Array"]: "*JSC.JSUint8Array",
+ ["JSString"]: "*JSC.JSString",
+ ["JSValue"]: "JSC.JSValue",
+ }[type];
+}
+
+function ZigDOMJITFunctionType(thisName, { args, returns }) {
+ return `fn (*${thisName}, *JSC.JSGlobalObject, ${args
+ .map(ZigDOMJITArgType)
+ .join(", ")}) callconv(.C) ${ZigDOMJITArgType("JSValue")}`;
+}
+
+function DOMJITReturnType(type) {
+ return {
+ ["bool"]: "bool",
+ ["int"]: "int32_t",
+ ["JSUint8Array"]: "JSC::JSUint8Array*",
+ ["JSString"]: "JSString*",
+ ["JSValue"]: "EncodedJSValue",
+ }[type];
+}
+
+function DOMJITFunctionDeclaration(jsClassName, fnName, { args, returns }) {
+ const argNames = args.map((arg, i) => `${argTypeName(arg)} arg${i}`);
+ return `
+ extern "C" JSC_DECLARE_JIT_OPERATION_WITHOUT_WTF_INTERNAL(${DOMJITName(
+ fnName
+ )}Wrapper, EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, void* thisValue, ${argNames.join(
+ ", "
+ )}));
+ extern "C" EncodedJSValue ${DOMJITName(
+ fnName
+ )}(void* ptr, JSC::JSGlobalObject * lexicalGlobalObject, ${argNames.join(
+ ", "
+ )});
+
+ static const JSC::DOMJIT::Signature DOMJITSignatureFor${fnName}(${DOMJITName(
+ fnName
+ )}Wrapper,
+ ${jsClassName}::info(),
+ JSC::DOMJIT::Effect::forReadWrite(JSC::DOMJIT::HeapRange::top(), JSC::DOMJIT::HeapRange::top()),
+ ${DOMJITType("JSValue")}, ${args.map(DOMJITType).join(", ")});
+`.trim();
+}
+
+function DOMJITFunctionDefinition(jsClassName, fnName, { args }) {
+ const argNames = args.map((arg, i) => `${argTypeName(arg)} arg${i}`);
+ return `
+JSC_DEFINE_JIT_OPERATION(${DOMJITName(
+ fnName
+ )}Wrapper, EncodedJSValue, (JSC::JSGlobalObject * lexicalGlobalObject, void* thisValue, ${argNames.join(
+ ", "
+ )}))
+{
+ VM& vm = JSC::getVM(lexicalGlobalObject);
+ IGNORE_WARNINGS_BEGIN("frame-address")
+ CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+ IGNORE_WARNINGS_END
+ JSC::JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+ return ${DOMJITName(
+ fnName
+ )}(reinterpret_cast<${jsClassName}*>(thisValue)->wrapped(), lexicalGlobalObject, ${args
+ .map((b, i) => "arg" + i)
+ .join(", ")});
+}
+`;
+}
+
function appendSymbols(
to: Map<string, string>,
symbolName: (name: string) => string,
prop
) {
- var { defaultValue, getter, setter, accesosr, fn, cache } = prop;
+ var { defaultValue, getter, setter, accesosr, fn, DOMJIT, cache } = prop;
if (accesosr) {
getter = accesosr.getter;
@@ -56,6 +152,9 @@ function appendSymbols(
}
if (fn && !to.get(fn)) {
+ if (DOMJIT) {
+ to.set(DOMJITName(fn), symbolName(DOMJITName(fn)));
+ }
to.set(fn, symbolName(fn));
}
}
@@ -75,6 +174,7 @@ function propRow(
fn,
length = 0,
cache,
+ DOMJIT,
} = prop;
if (accesosr) {
@@ -107,6 +207,12 @@ function propRow(
}
if (fn !== undefined) {
+ if (DOMJIT) {
+ // { "getElementById"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction), NoIntrinsic, { HashTableValue::DOMJITFunctionType, jsTestDOMJITPrototypeFunction_getElementById, &DOMJITSignatureForTestDOMJITGetElementById } },
+ return `
+ { "${name}"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DOMJITFunction), NoIntrinsic, { HashTableValue::DOMJITFunctionType, ${fn}, &DOMJITSignatureFor${symbol} } }
+ `.trim();
+ }
return `
{ "${name}"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ${fn}, ${
length || 0
@@ -202,6 +308,7 @@ ${generateHashTable(
true
)}
+
const ClassInfo ${proto}::s_info = { "${typeName}"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(${proto}) };
${renderFieldsImpl(protoSymbolName, typeName, obj, protoFields)}
@@ -504,6 +611,21 @@ function renderDecls(symbolName, typeName, proto) {
`.trim(),
"\n"
);
+
+ if (proto[name].DOMJIT) {
+ rows.push(
+ DOMJITFunctionDeclaration(
+ className(typeName),
+ symbolName(typeName, name),
+ proto[name].DOMJIT
+ ),
+ DOMJITFunctionDefinition(
+ className(typeName),
+ symbolName(typeName, name),
+ proto[name].DOMJIT
+ )
+ );
+ }
}
}
@@ -992,6 +1114,7 @@ function generateZig(
/// Set the cached value for ${name} on ${typeName}
/// This value will be visited by the garbage collector.
pub fn ${name}SetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
${protoSymbolName(
typeName,
name
@@ -1029,7 +1152,7 @@ function generateZig(
}
[...Object.values(proto)].forEach(
- ({ getter, setter, accessor, fn, cache }) => {
+ ({ getter, setter, accessor, fn, cache, DOMJIT }) => {
if (accessor) {
getter = accessor.getter;
setter = accessor.setter;
@@ -1053,6 +1176,17 @@ function generateZig(
}
if (fn) {
+ if (DOMJIT) {
+ output += `
+ if (@TypeOf(${typeName}.${DOMJITName(fn)}) != ${ZigDOMJITFunctionType(
+ typeName,
+ DOMJIT
+ )})
+ @compileLog(
+ "Expected ${typeName}.${DOMJITName(fn)} to be a DOMJIT function"
+ );`;
+ }
+
output += `
if (@TypeOf(${typeName}.${fn}) != CallbackType)
@compileLog(
diff --git a/test/bun.js/websocket-server.test.ts b/test/bun.js/websocket-server.test.ts
index 0e41d3186..dc9321f6a 100644
--- a/test/bun.js/websocket-server.test.ts
+++ b/test/bun.js/websocket-server.test.ts
@@ -1,8 +1,6 @@
-import { file, serve } from "bun";
-import { afterEach, describe, it, expect } from "bun:test";
-import { readFileSync, writeSync } from "fs";
+import { serve } from "bun";
+import { describe, expect, it } from "bun:test";
import { gcTick } from "gc";
-import { resolve } from "path";
var port = 4321;
function getPort() {
@@ -220,6 +218,116 @@ describe("websocket server", () => {
});
});
+ it("publishText()", async () => {
+ await new Promise((resolve, reject) => {
+ var server = serve({
+ port: getPort(),
+ websocket: {
+ async open(ws) {
+ // we don't care about the data
+ // we just want to make sure the DOMJIT call doesn't crash
+ for (let i = 0; i < 40_000; i++) ws.publishText("hello", "world");
+ resolve();
+ },
+ message(ws, msg) {},
+ },
+ async fetch(req, server) {
+ await 1;
+ if (server.upgrade(req)) return;
+
+ return new Response("noooooo hello world");
+ },
+ });
+
+ const websocket = new WebSocket(`ws://localhost:${server.port}`);
+ websocket.onmessage = () => {};
+ websocket.onerror = () => {};
+ });
+ });
+
+ it("publishBinary()", async () => {
+ const bytes = Buffer.from("hello");
+ await new Promise((resolve, reject) => {
+ var server = serve({
+ port: getPort(),
+ websocket: {
+ async open(ws) {
+ // we don't care about the data
+ // we just want to make sure the DOMJIT call doesn't crash
+ for (let i = 0; i < 40_000; i++) ws.publishBinary("hello", bytes);
+ resolve();
+ },
+ message(ws, msg) {},
+ },
+ async fetch(req, server) {
+ await 1;
+ if (server.upgrade(req)) return;
+
+ return new Response("noooooo hello world");
+ },
+ });
+
+ const websocket = new WebSocket(`ws://localhost:${server.port}`);
+ websocket.onmessage = () => {};
+ websocket.onerror = () => {};
+ });
+ });
+
+ it("sendText()", async () => {
+ await new Promise((resolve, reject) => {
+ var server = serve({
+ port: getPort(),
+ websocket: {
+ async open(ws) {
+ // we don't care about the data
+ // we just want to make sure the DOMJIT call doesn't crash
+ for (let i = 0; i < 40_000; i++) ws.sendText("hello world", true);
+ resolve();
+ },
+ message(ws, msg) {},
+ },
+ async fetch(req, server) {
+ await 1;
+ if (server.upgrade(req)) return;
+
+ return new Response("noooooo hello world");
+ },
+ });
+
+ const websocket = new WebSocket(`ws://localhost:${server.port}`);
+ websocket.onmessage = () => {};
+ websocket.onerror = () => {};
+ });
+ });
+
+ it("sendBinary()", async () => {
+ const bytes = Buffer.from("hello");
+ await new Promise((resolve, reject) => {
+ var server = serve({
+ port: getPort(),
+ websocket: {
+ async open(ws) {
+ // we don't care about the data
+ // we just want to make sure the DOMJIT call doesn't crash
+ for (let i = 0; i < 40_000; i++) ws.sendBinary(bytes, true);
+ resolve();
+ },
+ message(ws, msg) {},
+ },
+ async fetch(req, server) {
+ await 1;
+ if (server.upgrade(req)) return;
+
+ return new Response("noooooo hello world");
+ },
+ });
+
+ const websocket = new WebSocket(`ws://localhost:${server.port}`);
+ websocket.onmessage = () => {};
+ websocket.onerror = () => {};
+ });
+ });
+
it("can do hello world corked", async () => {
var server = serve({
port: getPort(),