diff options
author | 2022-10-17 06:53:18 -0700 | |
---|---|---|
committer | 2022-10-17 06:53:18 -0700 | |
commit | cdff2697efff88dd4059c41954f4bdd84bd3063c (patch) | |
tree | 6f0dbb3ec34139ca8fb9bf0d90168e962b71dbfe /src | |
parent | ca02695993a3380a75ff4b19fb45814e184b092a (diff) | |
download | bun-cdff2697efff88dd4059c41954f4bdd84bd3063c.tar.gz bun-cdff2697efff88dd4059c41954f4bdd84bd3063c.tar.zst bun-cdff2697efff88dd4059c41954f4bdd84bd3063c.zip |
Implement `sendText`, `sendBinary`, `publishText`, `publishBinary`
Diffstat (limited to 'src')
-rw-r--r-- | src/bun.js/api/server.classes.ts | 34 | ||||
-rw-r--r-- | src/bun.js/api/server.zig | 371 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses.cpp | 208 | ||||
-rw-r--r-- | src/bun.js/bindings/bindings.cpp | 5 | ||||
-rw-r--r-- | src/bun.js/bindings/bindings.zig | 16 | ||||
-rw-r--r-- | src/bun.js/bindings/generated_classes.zig | 37 | ||||
-rw-r--r-- | src/bun.js/bindings/headers-cpp.h | 2 | ||||
-rw-r--r-- | src/bun.js/bindings/headers.h | 3 | ||||
-rw-r--r-- | src/bun.js/bindings/headers.zig | 1 | ||||
-rw-r--r-- | src/bun.js/scripts/class-definitions.ts | 1 | ||||
-rw-r--r-- | src/bun.js/scripts/generate-classes.ts | 138 |
11 files changed, 805 insertions, 11 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( |