aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js')
-rw-r--r--src/bun.js/api/server.zig53
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp26
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.h2
-rw-r--r--src/bun.js/bindings/bindings.zig17
-rw-r--r--src/bun.js/bindings/webcore/WebSocket.cpp27
-rw-r--r--src/bun.js/bindings/webcore/WebSocket.h28
6 files changed, 75 insertions, 78 deletions
diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig
index f52c08301..9625ff693 100644
--- a/src/bun.js/api/server.zig
+++ b/src/bun.js/api/server.zig
@@ -3560,11 +3560,6 @@ pub const ServerWebSocket = struct {
if (message_value.asArrayBuffer(globalThis)) |array_buffer| {
const buffer = array_buffer.slice();
- if (buffer.len == 0) {
- globalThis.throw("publish requires a non-empty message", .{});
- return .zero;
- }
-
const result = if (!publish_to_self)
this.websocket.publish(topic_slice.slice(), buffer, .binary, compress)
else
@@ -3580,9 +3575,6 @@ pub const ServerWebSocket = struct {
{
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();
@@ -3634,10 +3626,6 @@ pub const ServerWebSocket = struct {
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();
@@ -3648,9 +3636,6 @@ pub const ServerWebSocket = struct {
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();
@@ -3715,10 +3700,6 @@ pub const ServerWebSocket = struct {
};
const buffer = array_buffer.slice();
- if (buffer.len == 0) {
- return JSC.JSValue.jsNumber(0);
- }
-
const result = if (!publish_to_self)
this.websocket.publish(topic_slice.slice(), buffer, .binary, compress)
else
@@ -3883,10 +3864,6 @@ pub const ServerWebSocket = struct {
}
if (message_value.asArrayBuffer(globalThis)) |buffer| {
- if (buffer.len == 0) {
- return JSValue.jsNumber(0);
- }
-
switch (this.websocket.send(buffer.slice(), .binary, compress, true)) {
.backpressure => {
log("send() backpressure ({d} bytes)", .{buffer.len});
@@ -3906,9 +3883,6 @@ pub const ServerWebSocket = struct {
{
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)) {
@@ -3960,9 +3934,6 @@ pub const ServerWebSocket = struct {
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)) {
@@ -3994,9 +3965,6 @@ pub const ServerWebSocket = struct {
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)) {
@@ -4043,10 +4011,6 @@ pub const ServerWebSocket = struct {
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});
@@ -4076,10 +4040,6 @@ pub const ServerWebSocket = struct {
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});
@@ -4416,17 +4376,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
const compress = (compress_value orelse JSValue.jsBoolean(true)).toBoolean();
- if (message_value.isEmptyOrUndefinedOrNull()) {
- JSC.JSError(this.vm.allocator, "publish requires a non-empty message", .{}, globalThis, exception);
- return .zero;
- }
-
if (message_value.asArrayBuffer(globalThis)) |buffer| {
- if (buffer.len == 0) {
- JSC.JSError(this.vm.allocator, "publish requires a non-empty message", .{}, globalThis, exception);
- return .zero;
- }
-
return JSValue.jsNumber(
// if 0, return 0
// else return number of bytes sent
@@ -4437,9 +4387,6 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
{
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(
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index c00670289..b3236a4a2 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -1021,6 +1021,20 @@ JSC_DEFINE_HOST_FUNCTION(functionBunSleepThenCallback,
return JSC::JSValue::encode(promise);
}
+using MicrotaskCallback = void (*)(void*);
+
+JSC_DEFINE_HOST_FUNCTION(functionNativeMicrotaskTrampoline,
+ (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
+{
+ JSCell* cellPtr = callFrame->uncheckedArgument(0).asCell();
+ JSCell* callbackPtr = callFrame->uncheckedArgument(1).asCell();
+
+ void* cell = reinterpret_cast<void*>(cellPtr);
+ auto* callback = reinterpret_cast<MicrotaskCallback>(callbackPtr);
+ callback(cell);
+ return JSValue::encode(jsUndefined());
+}
+
JSC_DEFINE_HOST_FUNCTION(functionBunSleep,
(JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
@@ -3027,6 +3041,11 @@ void GlobalObject::finishCreation(VM& vm)
init.set(JSFunction::create(init.vm, init.owner, 4, "performMicrotaskVariadic"_s, jsFunctionPerformMicrotaskVariadic, ImplementationVisibility::Public));
});
+ m_nativeMicrotaskTrampoline.initLater(
+ [](const Initializer<JSFunction>& init) {
+ init.set(JSFunction::create(init.vm, init.owner, 2, ""_s, functionNativeMicrotaskTrampoline, ImplementationVisibility::Public));
+ });
+
m_navigatorObject.initLater(
[](const Initializer<JSObject>& init) {
int cpuCount = 0;
@@ -4225,6 +4244,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
thisObject->m_JSFileSinkControllerPrototype.visit(visitor);
thisObject->m_JSHTTPSResponseControllerPrototype.visit(visitor);
thisObject->m_navigatorObject.visit(visitor);
+ thisObject->m_nativeMicrotaskTrampoline.visit(visitor);
thisObject->m_performanceObject.visit(visitor);
thisObject->m_primordialsObject.visit(visitor);
thisObject->m_processEnvObject.visit(visitor);
@@ -4387,6 +4407,12 @@ extern "C" void JSC__JSGlobalObject__reload(JSC__JSGlobalObject* arg0)
globalObject->reload();
}
+extern "C" void JSC__JSGlobalObject__queueMicrotaskCallback(Zig::GlobalObject* globalObject, void* ptr, MicrotaskCallback callback)
+{
+ JSFunction* function = globalObject->nativeMicrotaskTrampoline();
+ globalObject->queueMicrotask(function, JSValue(reinterpret_cast<JSC::JSCell*>(ptr)), JSValue(reinterpret_cast<JSC::JSCell*>(callback)), jsUndefined(), jsUndefined());
+}
+
JSC::Identifier GlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject,
JSModuleLoader* loader, JSValue key,
JSValue referrer, JSValue origin)
diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h
index a5b802ced..da6ba92a0 100644
--- a/src/bun.js/bindings/ZigGlobalObject.h
+++ b/src/bun.js/bindings/ZigGlobalObject.h
@@ -369,6 +369,7 @@ public:
mutable WriteBarrier<JSFunction> m_thenables[promiseFunctionsSize + 1];
JSObject* navigatorObject();
+ JSFunction* nativeMicrotaskTrampoline() { return m_nativeMicrotaskTrampoline.getInitializedOnMainThread(this); }
void trackFFIFunction(JSC::JSFunction* function)
{
@@ -466,6 +467,7 @@ private:
*/
LazyProperty<JSGlobalObject, JSC::Structure> m_pendingVirtualModuleResultStructure;
LazyProperty<JSGlobalObject, JSFunction> m_performMicrotaskFunction;
+ LazyProperty<JSGlobalObject, JSFunction> m_nativeMicrotaskTrampoline;
LazyProperty<JSGlobalObject, JSFunction> m_performMicrotaskVariadicFunction;
LazyProperty<JSGlobalObject, JSFunction> m_emitReadableNextTickFunction;
LazyProperty<JSGlobalObject, JSMap> m_lazyReadableStreamPrototypeMap;
diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig
index 277172b81..07882d857 100644
--- a/src/bun.js/bindings/bindings.zig
+++ b/src/bun.js/bindings/bindings.zig
@@ -2732,6 +2732,23 @@ pub const JSGlobalObject = extern struct {
this.vm().throwError(this, this.createErrorInstance(Output.prettyFmt(fmt, false), args));
}
}
+ extern fn JSC__JSGlobalObject__queueMicrotaskCallback(*JSGlobalObject, *anyopaque, Function: *const (fn (*anyopaque) callconv(.C) void)) void;
+ pub fn queueMicrotaskCallback(
+ this: *JSGlobalObject,
+ ctx_val: anytype,
+ comptime Function: fn (ctx: @TypeOf(ctx_val)) void,
+ ) void {
+ JSC.markBinding(@src());
+ const Fn = Function;
+ const ContextType = @TypeOf(ctx_val);
+ const Wrapper = struct {
+ pub fn call(p: *anyopaque) callconv(.C) void {
+ Fn(bun.cast(ContextType, p));
+ }
+ };
+
+ JSC__JSGlobalObject__queueMicrotaskCallback(this, ctx_val, &Wrapper.call);
+ }
pub fn queueMicrotask(
this: *JSGlobalObject,
diff --git a/src/bun.js/bindings/webcore/WebSocket.cpp b/src/bun.js/bindings/webcore/WebSocket.cpp
index a346175df..1d6392f44 100644
--- a/src/bun.js/bindings/webcore/WebSocket.cpp
+++ b/src/bun.js/bindings/webcore/WebSocket.cpp
@@ -458,8 +458,8 @@ ExceptionOr<void> WebSocket::send(const String& message)
return {};
}
- if (message.length() > 0)
- this->sendWebSocketString(message);
+ // 0-length is allowed
+ this->sendWebSocketString(message);
return {};
}
@@ -477,8 +477,8 @@ ExceptionOr<void> WebSocket::send(ArrayBuffer& binaryData)
}
char* data = static_cast<char*>(binaryData.data());
size_t length = binaryData.byteLength();
- if (length > 0)
- this->sendWebSocketData(data, length);
+ // 0-length is allowed
+ this->sendWebSocketData(data, length);
return {};
}
@@ -498,8 +498,8 @@ ExceptionOr<void> WebSocket::send(ArrayBufferView& arrayBufferView)
auto buffer = arrayBufferView.unsharedBuffer().get();
char* baseAddress = reinterpret_cast<char*>(buffer->data()) + arrayBufferView.byteOffset();
size_t length = arrayBufferView.byteLength();
- if (length > 0)
- this->sendWebSocketData(baseAddress, length);
+ // 0-length is allowed
+ this->sendWebSocketData(baseAddress, length);
return {};
}
@@ -1232,14 +1232,19 @@ extern "C" void WebSocket__didCloseWithErrorCode(WebCore::WebSocket* webSocket,
extern "C" void WebSocket__didReceiveText(WebCore::WebSocket* webSocket, bool clone, const ZigString* str)
{
- WTF::String wtf_str = Zig::toString(*str);
- if (clone) {
- wtf_str = wtf_str.isolatedCopy();
- }
-
+ WTF::String wtf_str = clone ? Zig::toStringCopy(*str) : Zig::toString(*str);
webSocket->didReceiveMessage(WTFMove(wtf_str));
}
extern "C" void WebSocket__didReceiveBytes(WebCore::WebSocket* webSocket, uint8_t* bytes, size_t len)
{
webSocket->didReceiveBinaryData({ bytes, len });
}
+
+extern "C" void WebSocket__incrementPendingActivity(WebCore::WebSocket* webSocket)
+{
+ webSocket->incPendingActivityCount();
+}
+extern "C" void WebSocket__decrementPendingActivity(WebCore::WebSocket* webSocket)
+{
+ webSocket->decPendingActivityCount();
+} \ No newline at end of file
diff --git a/src/bun.js/bindings/webcore/WebSocket.h b/src/bun.js/bindings/webcore/WebSocket.h
index 42261cfc4..846bd186b 100644
--- a/src/bun.js/bindings/webcore/WebSocket.h
+++ b/src/bun.js/bindings/webcore/WebSocket.h
@@ -111,6 +111,20 @@ public:
return m_hasPendingActivity.load();
}
+ void incPendingActivityCount()
+ {
+ m_pendingActivityCount++;
+ ref();
+ updateHasPendingActivity();
+ }
+
+ void decPendingActivityCount()
+ {
+ m_pendingActivityCount--;
+ deref();
+ updateHasPendingActivity();
+ }
+
private:
typedef union AnyWebSocket {
WebSocketClient* client;
@@ -147,20 +161,6 @@ private:
void sendWebSocketString(const String& message);
void sendWebSocketData(const char* data, size_t length);
- void incPendingActivityCount()
- {
- m_pendingActivityCount++;
- ref();
- updateHasPendingActivity();
- }
-
- void decPendingActivityCount()
- {
- m_pendingActivityCount--;
- deref();
- updateHasPendingActivity();
- }
-
void failAsynchronously();
enum class BinaryType { Blob,