Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
5a265ff
abortsignal util custom inspect
pfgithub May 6, 2025
87d26e5
abortsignal correct event prototype
pfgithub May 6, 2025
60f9f14
use gc(true)
pfgithub May 6, 2025
75d5254
jest tests
pfgithub May 6, 2025
380d995
.
pfgithub May 6, 2025
ddf2062
update event.test.ts
pfgithub May 6, 2025
c0d93b1
Merge branch 'main' into pfg/abort-signal
pfgithub May 7, 2025
2f2e4be
Merge branch 'main' into pfg/abort-signal
pfgithub May 17, 2025
ce793c0
fix expect toThrow crashing with a non-cell value
pfgithub May 17, 2025
20ca7be
just visit the signal reason
pfgithub May 20, 2025
bc0461d
test for abort signal reason gc problem
pfgithub May 20, 2025
37a21c5
Merge branch 'main' into pfg/abort-signal
pfgithub Jun 7, 2025
596c8cb
fix
pfgithub Jun 7, 2025
fe8690a
`bun run prettier`
pfgithub Jun 7, 2025
56aad4c
increase timeouts
pfgithub Jun 7, 2025
f70f9be
test-eventtarget
pfgithub Jun 7, 2025
403b8d4
Merge branch 'main' into pfg/abort-signal
pfgithub Jun 17, 2025
1472ac0
Merge branch 'main' into pfg/abort-signal
pfgithub Jun 21, 2025
f6a4555
Merge branch 'main' into pfg/abort-signal
pfgithub Jun 23, 2025
2deb1e0
Merge branch 'main' into pfg/abort-signal
pfgithub Jun 24, 2025
8624c24
getClassName can throw
pfgithub Jun 24, 2025
3eaa941
return the error from getClassName
pfgithub Jun 24, 2025
d51be77
unskip
pfgithub Jun 24, 2025
defbb4f
use catch scope
pfgithub Jun 24, 2025
6985f63
fromJSHostCallVoid
pfgithub Jun 30, 2025
c7efa2e
Merge branch 'main' into pfg/abort-signal
pfgithub Jun 30, 2025
999d1e9
fromJSHostCallGeneric
pfgithub Jun 30, 2025
93aa6c0
try
pfgithub Jun 30, 2025
2161bab
.
pfgithub Jun 30, 2025
5113308
`bun run prettier`
pfgithub Jun 30, 2025
615f0de
exception check pass. this is in WebCore bindings (JSDOMConvertNumber…
pfgithub Jul 1, 2025
2b40119
remove tryTakeException
pfgithub Jul 1, 2025
a700f55
`bun scripts/glob-sources.mjs`
pfgithub Jul 1, 2025
42596f2
`bun run zig-format`
pfgithub Jul 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmake/sources/ZigSources.txt
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ src/codegen/process_windows_translate_c.zig
src/compile_target.zig
src/comptime_string_map.zig
src/copy_file.zig
src/cpp.zig
src/crash_handler.zig
src/create/SourceFileProjectGenerator.zig
src/csrf.zig
Expand Down
21 changes: 12 additions & 9 deletions src/bun.js/ConsoleObject.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1879,7 +1879,10 @@ pub const Formatter = struct {
.estimated_line_length = &this.formatter.estimated_line_length,
};

if (getObjectName(globalThis, value)) |name_str| {
if (getObjectName(globalThis, value) catch blk: {
globalThis.clearException();
break :blk null;
}) |name_str| {
writer.print("{} ", .{name_str});
}
}
Expand Down Expand Up @@ -2023,9 +2026,9 @@ pub const Formatter = struct {
};
}

fn getObjectName(globalThis: *JSC.JSGlobalObject, value: JSValue) ?ZigString {
fn getObjectName(globalThis: *JSC.JSGlobalObject, value: JSValue) bun.JSError!?ZigString {
var name_str = ZigString.init("");
value.getClassName(globalThis, &name_str);
try value.getClassName(globalThis, &name_str);
if (!name_str.eqlComptime("Object")) {
return name_str;
} else if (value.getPrototype(globalThis).eqlValue(JSValue.null)) {
Expand Down Expand Up @@ -2198,7 +2201,7 @@ pub const Formatter = struct {
.Double => {
if (value.isCell()) {
var number_name = ZigString.Empty;
value.getClassName(this.globalThis, &number_name);
try value.getClassName(this.globalThis, &number_name);

var number_value = ZigString.Empty;
try value.toZigString(&number_value, this.globalThis);
Expand Down Expand Up @@ -2289,12 +2292,12 @@ pub const Formatter = struct {
},
.Class => {
var printable = ZigString.init(&name_buf);
value.getClassName(this.globalThis, &printable);
try value.getClassName(this.globalThis, &printable);
this.addForNewLine(printable.len);

const proto = value.getPrototype(this.globalThis);
var printable_proto = ZigString.init(&name_buf);
proto.getClassName(this.globalThis, &printable_proto);
try proto.getClassName(this.globalThis, &printable_proto);
this.addForNewLine(printable_proto.len);

if (printable.len == 0) {
Expand Down Expand Up @@ -2622,7 +2625,7 @@ pub const Formatter = struct {
} else if (value.as(bun.api.ResolveMessage)) |resolve_log| {
resolve_log.msg.writeFormat(writer_, enable_ansi_colors) catch {};
return;
} else if (JestPrettyFormat.printAsymmetricMatcher(this, Format, &writer, writer_, name_buf, value, enable_ansi_colors)) {
} else if (try JestPrettyFormat.printAsymmetricMatcher(this, Format, &writer, writer_, name_buf, value, enable_ansi_colors)) {
return;
} else if (jsType != .DOMWrapper) {
if (value.isCallable()) {
Expand Down Expand Up @@ -2663,7 +2666,7 @@ pub const Formatter = struct {
.Boolean => {
if (value.isCell()) {
var bool_name = ZigString.Empty;
value.getClassName(this.globalThis, &bool_name);
try value.getClassName(this.globalThis, &bool_name);
var bool_value = ZigString.Empty;
try value.toZigString(&bool_value, this.globalThis);

Expand Down Expand Up @@ -3305,7 +3308,7 @@ pub const Formatter = struct {
else if (value.isCallable())
try this.printAs(.Function, Writer, writer_, value, jsType, enable_ansi_colors)
else {
if (getObjectName(this.globalThis, value)) |name_str| {
if (try getObjectName(this.globalThis, value)) |name_str| {
writer.print("{} ", .{name_str});
}
writer.writeAll("{}");
Expand Down
8 changes: 8 additions & 0 deletions src/bun.js/bindings/CatchScope.zig
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,13 @@ pub fn assertNoExceptionExceptTermination(self: *CatchScope) bun.JSExecutionTerm
}
}

/// Clear the thrown exception
pub fn clearException(self: *CatchScope) void {
if (Environment.allow_assert) bun.assert(self.location == &self.bytes[0]);
if (!self.enabled) return;
CatchScope__clearException(&self.bytes);
}

pub fn deinit(self: *CatchScope) void {
if (comptime Environment.ci_assert) bun.assert(self.location == &self.bytes[0]);
if (!self.enabled) return;
Expand All @@ -161,6 +168,7 @@ extern fn CatchScope__pureException(ptr: *align(alignment) [size]u8) ?*jsc.Excep
extern fn CatchScope__exceptionIncludingTraps(ptr: *align(alignment) [size]u8) ?*jsc.Exception;
extern fn CatchScope__assertNoException(ptr: *align(alignment) [size]u8) void;
extern fn CatchScope__destruct(ptr: *align(alignment) [size]u8) void;
extern fn CatchScope__clearException(ptr: *align(alignment) [size]u8) void;

const std = @import("std");
const bun = @import("bun");
Expand Down
6 changes: 6 additions & 0 deletions src/bun.js/bindings/CatchScopeBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,9 @@ extern "C" void CatchScope__assertNoException(void* ptr)
ASSERT((uintptr_t)ptr % alignof(CatchScope) == 0);
static_cast<CatchScope*>(ptr)->assertNoException();
}

extern "C" void CatchScope__clearException(void* ptr)
{
ASSERT((uintptr_t)ptr % alignof(CatchScope) == 0);
static_cast<CatchScope*>(ptr)->clearException();
}
8 changes: 4 additions & 4 deletions src/bun.js/bindings/JSValue.zig
Original file line number Diff line number Diff line change
Expand Up @@ -703,9 +703,9 @@ pub const JSValue = enum(i64) {
return JSC__JSValue__jsTDZValue();
}

pub fn className(this: JSValue, globalThis: *JSGlobalObject) ZigString {
pub fn className(this: JSValue, globalThis: *JSGlobalObject) JSError!ZigString {
var str = ZigString.init("");
this.getClassName(globalThis, &str);
try this.getClassName(globalThis, &str);
return str;
}

Expand Down Expand Up @@ -1095,8 +1095,8 @@ pub const JSValue = enum(i64) {
}

extern fn JSC__JSValue__getClassName(this: JSValue, global: *JSGlobalObject, ret: *ZigString) void;
pub fn getClassName(this: JSValue, global: *JSGlobalObject, ret: *ZigString) void {
JSC__JSValue__getClassName(this, global, ret);
pub fn getClassName(this: JSValue, global: *JSGlobalObject, ret: *ZigString) bun.JSError!void {
try JSC.fromJSHostCallGeneric(global, @src(), JSC__JSValue__getClassName, .{ this, global, ret });
}

pub inline fn isCell(this: JSValue) bool {
Expand Down
2 changes: 1 addition & 1 deletion src/bun.js/bindings/ZigGlobalObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3201,7 +3201,7 @@ void GlobalObject::finishCreation(VM& vm)
[](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSMap>::Initializer& init) {
auto* global = init.owner;
auto& vm = init.vm;
auto scope = DECLARE_THROW_SCOPE(vm);
auto scope = DECLARE_CATCH_SCOPE(vm);

// if we get the termination exception, we'd still like to set a non-null Map so that
// we don't segfault
Expand Down
76 changes: 76 additions & 0 deletions src/bun.js/bindings/webcore/JSAbortController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include <JavaScriptCore/SubspaceInlines.h>
#include <wtf/GetPtr.h>
#include <wtf/PointerPreparations.h>
#include "ErrorCode.h"
#include <wtf/URL.h>

namespace WebCore {
Expand All @@ -56,6 +57,7 @@ using namespace JSC;
// Functions

static JSC_DECLARE_HOST_FUNCTION(jsAbortControllerPrototypeFunction_abort);
static JSC_DECLARE_HOST_FUNCTION(jsAbortControllerPrototypeFunction_customInspect);

// Attributes

Expand Down Expand Up @@ -149,6 +151,7 @@ void JSAbortControllerPrototype::finishCreation(VM& vm)
{
Base::finishCreation(vm);
reifyStaticProperties(vm, JSAbortController::info(), JSAbortControllerPrototypeTableValues, *this);
this->putDirectNativeFunction(vm, this->globalObject(), builtinNames(vm).inspectCustomPublicName(), 2, jsAbortControllerPrototypeFunction_customInspect, ImplementationVisibility::Public, NoIntrinsic, JSC::PropertyAttribute::Function | 0);
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
}

Expand Down Expand Up @@ -225,6 +228,78 @@ JSC_DEFINE_HOST_FUNCTION(jsAbortControllerPrototypeFunction_abort, (JSGlobalObje
return IDLOperation<JSAbortController>::call<jsAbortControllerPrototypeFunction_abortBody>(*lexicalGlobalObject, *callFrame, "abort");
}

static inline JSC::EncodedJSValue jsAbortControllerPrototypeFunction_customInspectBody(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame, typename IDLOperation<JSAbortController>::ClassParameter castedThis)
{

auto& vm = lexicalGlobalObject->vm();
auto throwScope = DECLARE_THROW_SCOPE(vm);
auto* globalObject = defaultGlobalObject(lexicalGlobalObject);

JSValue depthValue = callFrame->argument(0);
JSValue optionsValue = callFrame->argument(1);

auto depth = depthValue.toNumber(lexicalGlobalObject);
RETURN_IF_EXCEPTION(throwScope, {});
if (depth < 0) {
return JSValue::encode(jsNontrivialString(vm, "[AbortController]"_s));
}

if (!depthValue.isUndefinedOrNull()) {
depthValue = jsNumber(depth - 1);
}

JSObject* options = optionsValue.toObject(lexicalGlobalObject);
RETURN_IF_EXCEPTION(throwScope, {});
PropertyNameArray optionsArray(vm, PropertyNameMode::StringsAndSymbols, PrivateSymbolMode::Exclude);
options->getPropertyNames(lexicalGlobalObject, optionsArray, DontEnumPropertiesMode::Exclude);
RETURN_IF_EXCEPTION(throwScope, {});

JSObject* newOptions = constructEmptyObject(lexicalGlobalObject);
for (size_t i = 0; i < optionsArray.size(); i++) {
auto name = optionsArray[i];

JSValue value = options->get(lexicalGlobalObject, name);
RETURN_IF_EXCEPTION(throwScope, {});

newOptions->putDirect(vm, name, value, 0);
RETURN_IF_EXCEPTION(throwScope, {});
}

PutPropertySlot slot(newOptions);
newOptions->put(newOptions, lexicalGlobalObject, Identifier::fromString(vm, "depth"_s), depthValue, slot);
RETURN_IF_EXCEPTION(throwScope, {});

auto& impl = castedThis->wrapped();

JSObject* inputObj = constructEmptyObject(lexicalGlobalObject);

inputObj->putDirect(vm, Identifier::fromString(vm, "signal"_s), toJS<IDLInterface<AbortSignal>>(*lexicalGlobalObject, *castedThis->globalObject(), throwScope, impl.signal()), 0);

JSFunction* utilInspect = globalObject->utilInspectFunction();
auto callData = JSC::getCallData(utilInspect);
MarkedArgumentBuffer arguments;
arguments.append(inputObj);
arguments.append(newOptions);

auto inspectResult = JSC::profiledCall(globalObject, ProfilingReason::API, utilInspect, callData, inputObj, arguments);
RETURN_IF_EXCEPTION(throwScope, {});

auto* inspectString = inspectResult.toString(lexicalGlobalObject);
RETURN_IF_EXCEPTION(throwScope, {});

auto inspectStringView = inspectString->view(lexicalGlobalObject);
RETURN_IF_EXCEPTION(throwScope, {});

JSValue result = jsString(vm, makeString("AbortController "_s, inspectStringView.data));

return JSValue::encode(result);
}

JSC_DEFINE_HOST_FUNCTION(jsAbortControllerPrototypeFunction_customInspect, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
{
return IDLOperation<JSAbortController>::call<jsAbortControllerPrototypeFunction_customInspectBody>(*lexicalGlobalObject, *callFrame, "inspect");
}

JSC::GCClient::IsoSubspace* JSAbortController::subspaceForImpl(JSC::VM& vm)
{
return WebCore::subspaceForImpl<JSAbortController, UseCustomHeapCellType::No>(
Expand All @@ -242,6 +317,7 @@ void JSAbortController::visitChildrenImpl(JSCell* cell, Visitor& visitor)
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
Base::visitChildren(thisObject, visitor);
addWebCoreOpaqueRoot(visitor, thisObject->wrapped().opaqueRoot());
thisObject->wrapped().signal().reason().visit(visitor);
}

DEFINE_VISIT_CHILDREN(JSAbortController);
Expand Down
75 changes: 75 additions & 0 deletions src/bun.js/bindings/webcore/JSAbortSignal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
#include <JavaScriptCore/SubspaceInlines.h>
#include <wtf/GetPtr.h>
#include <wtf/PointerPreparations.h>
#include "ErrorCode.h"
#include <wtf/URL.h>
#include "ErrorCode.h"

Expand All @@ -64,6 +65,7 @@ static JSC_DECLARE_HOST_FUNCTION(jsAbortSignalConstructorFunction_abort);
static JSC_DECLARE_HOST_FUNCTION(jsAbortSignalConstructorFunction_timeout);
static JSC_DECLARE_HOST_FUNCTION(jsAbortSignalConstructorFunction_any);
static JSC_DECLARE_HOST_FUNCTION(jsAbortSignalPrototypeFunction_throwIfAborted);
static JSC_DECLARE_HOST_FUNCTION(jsAbortSignalPrototypeFunction_customInspect);

// Attributes

Expand Down Expand Up @@ -160,6 +162,7 @@ void JSAbortSignalPrototype::finishCreation(VM& vm)
{
Base::finishCreation(vm);
reifyStaticProperties(vm, JSAbortSignal::info(), JSAbortSignalPrototypeTableValues, *this);
this->putDirectNativeFunction(vm, this->globalObject(), builtinNames(vm).inspectCustomPublicName(), 2, jsAbortSignalPrototypeFunction_customInspect, ImplementationVisibility::Public, NoIntrinsic, JSC::PropertyAttribute::Function | 0);
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
}

Expand Down Expand Up @@ -354,6 +357,78 @@ JSC_DEFINE_HOST_FUNCTION(jsAbortSignalPrototypeFunction_throwIfAborted, (JSGloba
return IDLOperation<JSAbortSignal>::call<jsAbortSignalPrototypeFunction_throwIfAbortedBody>(*lexicalGlobalObject, *callFrame, "throwIfAborted");
}

static inline JSC::EncodedJSValue jsAbortSignalPrototypeFunction_customInspectBody(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame, typename IDLOperation<JSAbortSignal>::ClassParameter castedThis)
{

auto& vm = lexicalGlobalObject->vm();
auto throwScope = DECLARE_THROW_SCOPE(vm);
auto* globalObject = defaultGlobalObject(lexicalGlobalObject);

JSValue depthValue = callFrame->argument(0);
JSValue optionsValue = callFrame->argument(1);

auto depth = depthValue.toNumber(lexicalGlobalObject);
RETURN_IF_EXCEPTION(throwScope, {});
if (depth < 0) {
return JSValue::encode(jsNontrivialString(vm, "[AbortSignal]"_s));
}

if (!depthValue.isUndefinedOrNull()) {
depthValue = jsNumber(depth - 1);
}

JSObject* options = optionsValue.toObject(lexicalGlobalObject);
RETURN_IF_EXCEPTION(throwScope, {});
PropertyNameArray optionsArray(vm, PropertyNameMode::StringsAndSymbols, PrivateSymbolMode::Exclude);
options->getPropertyNames(lexicalGlobalObject, optionsArray, DontEnumPropertiesMode::Exclude);
RETURN_IF_EXCEPTION(throwScope, {});

JSObject* newOptions = constructEmptyObject(lexicalGlobalObject);
for (size_t i = 0; i < optionsArray.size(); i++) {
auto name = optionsArray[i];

JSValue value = options->get(lexicalGlobalObject, name);
RETURN_IF_EXCEPTION(throwScope, {});

newOptions->putDirect(vm, name, value, 0);
RETURN_IF_EXCEPTION(throwScope, {});
}

PutPropertySlot slot(newOptions);
newOptions->put(newOptions, lexicalGlobalObject, Identifier::fromString(vm, "depth"_s), depthValue, slot);
RETURN_IF_EXCEPTION(throwScope, {});

auto& impl = castedThis->wrapped();

JSObject* inputObj = constructEmptyObject(lexicalGlobalObject);

inputObj->putDirect(vm, Identifier::fromString(vm, "aborted"_s), jsBoolean(impl.aborted()), 0);

JSFunction* utilInspect = globalObject->utilInspectFunction();
auto callData = JSC::getCallData(utilInspect);
MarkedArgumentBuffer arguments;
arguments.append(inputObj);
arguments.append(newOptions);

auto inspectResult = JSC::profiledCall(globalObject, ProfilingReason::API, utilInspect, callData, inputObj, arguments);
RETURN_IF_EXCEPTION(throwScope, {});

auto* inspectString = inspectResult.toString(lexicalGlobalObject);
RETURN_IF_EXCEPTION(throwScope, {});

auto inspectStringView = inspectString->view(lexicalGlobalObject);
RETURN_IF_EXCEPTION(throwScope, {});

JSValue result = jsString(vm, makeString("AbortSignal "_s, inspectStringView.data));

return JSValue::encode(result);
}

JSC_DEFINE_HOST_FUNCTION(jsAbortSignalPrototypeFunction_customInspect, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
{
return IDLOperation<JSAbortSignal>::call<jsAbortSignalPrototypeFunction_customInspectBody>(*lexicalGlobalObject, *callFrame, "inspect");
}

size_t JSAbortSignal::estimatedSize(JSC::JSCell* cell, JSC::VM& vm)
{
auto* thisObject = jsCast<JSAbortSignal*>(cell);
Expand Down
Loading