Fix a couple memory leaks in bun dev

This commit is contained in:
Jarred Sumner
2022-03-14 23:43:20 -07:00
parent 5aae8726ef
commit a168c51395
11 changed files with 301 additions and 144 deletions

View File

@@ -37,11 +37,6 @@ query_string_map: ?QueryStringMap = null,
param_map: ?QueryStringMap = null,
params_list_holder: FilesystemRouter.Param.List = .{},
script_src: ?string = null,
script_src_buf: [1024]u8 = undefined,
script_src_buf_writer: ScriptSrcStream = undefined,
pub fn importRoute(
this: *Router,
ctx: js.JSContextRef,
@@ -70,15 +65,25 @@ pub fn match(
return null;
}
var arg: JSC.JSValue = undefined;
if (FetchEvent.Class.loaded and js.JSValueIsObjectOfClass(ctx, arguments[0], FetchEvent.Class.get().*)) {
return matchFetchEvent(ctx, To.Zig.ptr(FetchEvent, arguments[0]), exception);
var fetch_event = To.Zig.ptr(FetchEvent, arguments[0]);
if (fetch_event.request_context != null) {
return matchFetchEvent(ctx, fetch_event, exception);
}
// When disconencted, we still have a copy of the request data in here
arg = JSC.JSValue.fromRef(fetch_event.getRequest(ctx, null, null, null));
} else {
arg = JSC.JSValue.fromRef(arguments[0]);
}
var router = JavaScript.VirtualMachine.vm.bundler.router orelse {
JSError(getAllocator(ctx), "Bun.match needs a framework configured with routes", .{}, ctx, exception);
return null;
};
var arg = JSC.JSValue.fromRef(arguments[0]);
var path_: ?ZigString.Slice = null;
var pathname: string = "";
defer {
@@ -128,7 +133,6 @@ pub fn match(
instance.params_list_holder = params_list;
instance.route = &instance.route_holder;
instance.route_holder.params = &instance.params_list_holder;
instance.script_src_buf_writer = ScriptSrcStream{ .pos = 0, .buffer = std.mem.span(&instance.script_src_buf) };
return Instance.make(ctx, instance);
}
@@ -150,7 +154,7 @@ fn matchFetchEvent(
fetch_event: *const FetchEvent,
_: js.ExceptionRef,
) js.JSObjectRef {
return createRouteObject(ctx, fetch_event.request_context);
return createRouteObject(ctx, fetch_event.request_context.?);
}
fn createRouteObject(ctx: js.JSContextRef, req: *const http.RequestContext) js.JSValueRef {
@@ -169,7 +173,6 @@ fn createRouteObjectFromMatch(
router.* = Router{
.route = route,
};
router.script_src_buf_writer = ScriptSrcStream{ .pos = 0, .buffer = std.mem.span(&router.script_src_buf) };
return Instance.make(ctx, router);
}
@@ -221,9 +224,7 @@ pub const Instance = NewClass(
},
},
.{
.finalize = .{
.rfn = finalize,
},
.finalize = finalize,
.import = .{
.rfn = importRoute,
.ts = d.ts{
@@ -345,8 +346,9 @@ pub fn finalize(
this.params_list_holder.deinit(bun.default_allocator);
this.params_list_holder = .{};
this.needs_deinit = false;
bun.default_allocator.destroy(this);
}
bun.default_allocator.destroy(this);
}
pub fn getPathname(
@@ -437,13 +439,13 @@ pub fn createQueryObject(ctx: js.JSContextRef, map: *QueryStringMap, _: js.Excep
return value.asRef();
}
threadlocal var entry_point_tempbuf: [bun.MAX_PATH_BYTES]u8 = undefined;
pub fn getScriptSrcString(
comptime Writer: type,
writer: Writer,
file_path: string,
client_framework_enabled: bool,
) void {
var entry_point_tempbuf: [bun.MAX_PATH_BYTES]u8 = undefined;
// We don't store the framework config including the client parts in the server
// instead, we just store a boolean saying whether we should generate this whenever the script is requested
// this is kind of bad. we should consider instead a way to inline the contents of the script.
@@ -454,11 +456,11 @@ pub fn getScriptSrcString(
Fs.PathName.init(file_path),
),
VirtualMachine.vm.origin,
ScriptSrcStream.Writer,
Writer,
writer,
);
} else {
JavaScript.Bun.getPublicPath(file_path, VirtualMachine.vm.origin, ScriptSrcStream.Writer, writer);
JavaScript.Bun.getPublicPath(file_path, VirtualMachine.vm.origin, Writer, writer);
}
}
@@ -469,12 +471,12 @@ pub fn getScriptSrc(
_: js.JSStringRef,
_: js.ExceptionRef,
) js.JSValueRef {
const src = this.script_src orelse brk: {
getScriptSrcString(ScriptSrcStream.Writer, this.script_src_buf_writer.writer(), this.route.file_path, this.route.client_framework_enabled);
break :brk this.script_src_buf[0..this.script_src_buf_writer.pos];
};
var script_src_buffer = std.ArrayList(u8).init(bun.default_allocator);
return ZigString.init(src).toValueGC(ctx.ptr()).asObjectRef();
var writer = script_src_buffer.writer();
getScriptSrcString(@TypeOf(&writer), &writer, this.route.file_path, this.route.client_framework_enabled);
return ZigString.init(script_src_buffer.toOwnedSlice()).toExternalValue(ctx.ptr()).asObjectRef();
}
pub fn getParams(

View File

@@ -22,6 +22,7 @@ const Request = WebCore.Request;
const Router = @import("./api/router.zig");
const FetchEvent = WebCore.FetchEvent;
const Headers = WebCore.Headers.RefCountedHeaders;
const IdentityContext = @import("../../identity_context.zig").IdentityContext;
const Body = WebCore.Body;
const TaggedPointerTypes = @import("../../tagged_pointer.zig");
@@ -1869,13 +1870,78 @@ pub const MarkedArrayBuffer = struct {
pub const toJS = toJSObjectRef;
};
// expensive heap reference-counted string type
// only use this for big strings
// like source code
// not little ones
pub const RefString = struct {
ptr: [*]const u8 = undefined,
len: usize = 0,
hash: Hash = 0,
count: u32 = 0,
allocator: std.mem.Allocator,
ctx: ?*anyopaque = null,
onBeforeDeinit: ?Callback = null,
pub const Hash = u32;
pub const Map = std.HashMap(Hash, *JSC.RefString, IdentityContext(Hash), 80);
pub const Callback = fn (ctx: *anyopaque, str: *RefString) void;
pub fn computeHash(input: []const u8) u32 {
return @truncate(u32, std.hash.Wyhash.hash(0, input));
}
pub fn ref(this: *RefString) void {
this.count += 1;
}
pub fn slice(this: *RefString) []const u8 {
this.ref();
return this.leak();
}
pub fn leak(this: RefString) []const u8 {
@setRuntimeSafety(false);
return this.ptr[0..this.len];
}
pub fn deref(this: *RefString) void {
this.count -|= 1;
if (this.count == 0) {
this.deinit();
}
}
pub export fn RefString__free(this: *RefString, _: [*]const u8, _: usize) void {
this.deref();
}
pub fn deinit(this: *RefString) void {
if (this.onBeforeDeinit) |onBeforeDeinit| {
onBeforeDeinit(this.ctx.?, this);
}
this.allocator.free(this.leak());
this.allocator.destroy(this);
}
};
comptime {
std.testing.refAllDecls(RefString);
}
export fn MarkedArrayBuffer_deallocator(bytes_: *anyopaque, _: *anyopaque) void {
const mimalloc = @import("../../allocators/mimalloc.zig");
// zig's memory allocator interface won't work here
// mimalloc knows the size of things
// but we don't
mimalloc.mi_free(bytes_);
}
pub export fn BlobArrayBuffer_deallocator(_: *anyopaque, blob: *anyopaque) void {
// zig's memory allocator interface won't work here
// mimalloc knows the size of things

View File

@@ -29,6 +29,7 @@
#include <JavaScriptCore/JSMicrotask.h>
// #include <JavaScriptCore/JSContextInternal.h>
#include <JavaScriptCore/CatchScope.h>
#include <JavaScriptCore/DeferredWorkTimer.h>
#include <JavaScriptCore/JSInternalPromise.h>
#include <JavaScriptCore/JSLock.h>
#include <JavaScriptCore/JSMap.h>
@@ -160,15 +161,16 @@ extern "C" bool Zig__GlobalObject__resetModuleRegistryMap(JSC__JSGlobalObject* g
if (JSC::JSMap* oldMap = JSC::jsDynamicCast<JSC::JSMap*>(
globalObject->vm(), obj->getDirect(globalObject->vm(), identifier))) {
oldMap->clear(globalObject);
// vm.finalizeSynchronousJSExecution();
vm.finalizeSynchronousJSExecution();
obj->putDirect(globalObject->vm(), identifier,
map->clone(globalObject, globalObject->vm(), globalObject->mapStructure()));
// vm.deleteAllLinkedCode(JSC::DeleteAllCodeEffort::DeleteAllCodeIfNotCollecting);
// JSC::Heap::PreventCollectionScope(vm.heap);
oldMap->clear(globalObject);
JSC::gcUnprotect(oldMap);
// vm.heap.completeAllJITPlans();
// vm.forEachScriptExecutableSpace([&](auto &spaceAndSet) {
@@ -181,48 +183,13 @@ extern "C" bool Zig__GlobalObject__resetModuleRegistryMap(JSC__JSGlobalObject* g
// }
// });
// });
// globalObject->vm().heap.deleteAllUnlinkedCodeBlocks(
// JSC::DeleteAllCodeEffort::PreventCollectionAndDeleteAllCode);
}
// globalObject->vm().heap.deleteAllUnlinkedCodeBlocks(
// JSC::DeleteAllCodeEffort::PreventCollectionAndDeleteAllCode);
// vm.whenIdle([globalObject, oldMap, map]() {
// auto recordIdentifier = JSC::Identifier::fromString(globalObject->vm(), "module");
// JSC::JSModuleRecord *record;
// JSC::JSValue key;
// JSC::JSValue value;
// JSC::JSObject *mod;
// JSC::JSObject *nextObject;
// JSC::forEachInIterable(
// globalObject, oldMap,
// [&](JSC::VM &vm, JSC::JSGlobalObject *globalObject, JSC::JSValue nextValue) {
// nextObject = JSC::jsDynamicCast<JSC::JSObject *>(vm, nextValue);
// key = nextObject->getIndex(globalObject, static_cast<unsigned>(0));
// if (!map->has(globalObject, key)) {
// value = nextObject->getIndex(globalObject, static_cast<unsigned>(1));
// mod = JSC::jsDynamicCast<JSC::JSObject *>(vm, value);
// if (mod) {
// record = JSC::jsDynamicCast<JSC::JSModuleRecord *>(
// vm, mod->getDirect(vm, recordIdentifier));
// if (record) {
// auto code = &record->sourceCode();
// if (code) {
// Zig::SourceProvider *provider =
// reinterpret_cast<Zig::SourceProvider *>(code->provider());
// // code->~SourceCode();
// if (provider) { provider->freeSourceCode(); }
// }
// }
// }
// }
// });
// oldMap->clear(globalObject);
// }
// }
// map
}
// map
// }
return true;
}
@@ -317,7 +284,11 @@ JSC_DEFINE_CUSTOM_GETTER(property_lazyProcessGetter,
globalObject->m_process = Zig::Process::create(
vm, Zig::Process::createStructure(vm, globalObject, globalObject->objectPrototype()));
// We must either:
// - GC it and re-create it
// - keep it alive forever
// I think it is more correct to keep it alive forever
JSC::gcProtect(globalObject->m_process);
{
auto jsClass = dot_env_class_ref;
@@ -329,6 +300,8 @@ JSC_DEFINE_CUSTOM_GETTER(property_lazyProcessGetter,
globalObject->m_process->putDirect(vm, JSC::Identifier::fromString(vm, "env"),
JSC::JSValue(object),
JSC::PropertyAttribute::DontDelete | 0);
JSC::gcProtect(JSC::JSValue(object));
}
return JSC::JSValue::encode(JSC::JSValue(globalObject->m_process));

View File

@@ -10,6 +10,8 @@
#include <wtf/Scope.h>
#include <wtf/text/StringHash.h>
extern "C" void RefString__free(void*, void*, unsigned);
namespace Zig {
using Base = JSC::SourceProvider;
@@ -25,22 +27,20 @@ using SourceProviderSourceType = JSC::SourceProviderSourceType;
static char* wasmSourceName = "[WebAssembly Source]";
static size_t wasmSourceName_len = 20;
Ref<SourceProvider> SourceProvider::create(ResolvedSource resolvedSource)
{
void* allocator = resolvedSource.allocator;
JSC::SourceProviderSourceType sourceType = JSC::SourceProviderSourceType::Module;
WTF::StringImpl* stringImpl = nullptr;
if (allocator) {
Ref<WTF::ExternalStringImpl> stringImpl_ = WTF::ExternalStringImpl::create(
resolvedSource.source_code.ptr, resolvedSource.source_code.len,
nullptr,
[allocator](void* str, void* ptr, unsigned int len) {
ZigString__free((const unsigned char*)ptr, len, allocator);
});
allocator,
RefString__free);
return adoptRef(*new SourceProvider(
resolvedSource, reinterpret_cast<WTF::StringImpl*>(stringImpl_.ptr()),
resolvedSource, stringImpl_,
JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(toString(resolvedSource.source_url))),
toStringNotConst(resolvedSource.source_url), TextPosition(),
sourceType));
@@ -48,7 +48,7 @@ Ref<SourceProvider> SourceProvider::create(ResolvedSource resolvedSource)
Ref<WTF::ExternalStringImpl> stringImpl_ = WTF::ExternalStringImpl::createStatic(
resolvedSource.source_code.ptr, resolvedSource.source_code.len);
return adoptRef(*new SourceProvider(
resolvedSource, reinterpret_cast<WTF::StringImpl*>(stringImpl_.ptr()),
resolvedSource, stringImpl_,
JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(toString(resolvedSource.source_url))),
toStringNotConst(resolvedSource.source_url), TextPosition(),
sourceType));

View File

@@ -63,11 +63,11 @@ public:
void freeSourceCode();
private:
SourceProvider(ResolvedSource resolvedSource, WTF::StringImpl* sourceImpl,
SourceProvider(ResolvedSource resolvedSource, WTF::StringImpl& sourceImpl,
const SourceOrigin& sourceOrigin, WTF::String&& sourceURL,
const TextPosition& startPosition, JSC::SourceProviderSourceType sourceType)
: Base(sourceOrigin, WTFMove(sourceURL), startPosition, sourceType)
, m_source(*sourceImpl)
, m_source(sourceImpl)
{
m_resolvedSource = resolvedSource;

View File

@@ -246,13 +246,11 @@ export fn ZigString__free(ptr: [*]const u8, len: usize, allocator_: ?*anyopaque)
allocator.free(str);
}
export fn ZigString__free_global(ptr: [*]const u8, len: usize) void {
var str = ptr[0..len];
export fn ZigString__free_global(ptr: [*]const u8, _: usize) void {
if (comptime Environment.allow_assert) {
std.debug.assert(Mimalloc.mi_check_owned(ptr));
}
default_allocator.free(str);
Mimalloc.mi_free(@intToPtr(*anyopaque, @ptrToInt(ptr)));
}
export fn Zig__getAPIGlobals(count: *usize) [*]JSC.C.JSClassRef {

View File

@@ -1,4 +1,4 @@
//-- AUTOGENERATED FILE -- 1647230769
//-- AUTOGENERATED FILE -- 1647318604
// clang-format off
#pragma once

View File

@@ -1,5 +1,5 @@
// clang-format: off
//-- AUTOGENERATED FILE -- 1647230769
//-- AUTOGENERATED FILE -- 1647318604
#pragma once
#include <stddef.h>
@@ -527,6 +527,7 @@ CPP_DECL JSC__VM* JSC__VM__create(unsigned char HeapType0);
CPP_DECL void JSC__VM__deferGC(JSC__VM* arg0, void* arg1, void (* ArgFn2)(void* arg0));
CPP_DECL void JSC__VM__deinit(JSC__VM* arg0, JSC__JSGlobalObject* arg1);
CPP_DECL void JSC__VM__deleteAllCode(JSC__VM* arg0, JSC__JSGlobalObject* arg1);
CPP_DECL void JSC__VM__doWork(JSC__VM* arg0);
CPP_DECL void JSC__VM__drainMicrotasks(JSC__VM* arg0);
CPP_DECL bool JSC__VM__executionForbidden(JSC__VM* arg0);
CPP_DECL void JSC__VM__holdAPILock(JSC__VM* arg0, void* arg1, void (* ArgFn2)(void* arg0));

View File

@@ -365,6 +365,7 @@ pub extern fn JSC__VM__create(HeapType0: u8) [*c]JSC__VM;
pub extern fn JSC__VM__deferGC(arg0: [*c]JSC__VM, arg1: ?*anyopaque, ArgFn2: ?fn (?*anyopaque) callconv(.C) void) void;
pub extern fn JSC__VM__deinit(arg0: [*c]JSC__VM, arg1: [*c]JSC__JSGlobalObject) void;
pub extern fn JSC__VM__deleteAllCode(arg0: [*c]JSC__VM, arg1: [*c]JSC__JSGlobalObject) void;
pub extern fn JSC__VM__doWork(arg0: [*c]JSC__VM) void;
pub extern fn JSC__VM__drainMicrotasks(arg0: [*c]JSC__VM) void;
pub extern fn JSC__VM__executionForbidden(arg0: [*c]JSC__VM) bool;
pub extern fn JSC__VM__holdAPILock(arg0: [*c]JSC__VM, arg1: ?*anyopaque, ArgFn2: ?fn (?*anyopaque) callconv(.C) void) void;

View File

@@ -688,7 +688,10 @@ pub const Bun = struct {
arguments: []const js.JSValueRef,
_: js.ExceptionRef,
) js.JSValueRef {
Global.mimalloc_cleanup(true);
// it should only force cleanup on thread exit
Global.mimalloc_cleanup(false);
return ctx.ptr().vm().runGC(arguments.len > 0 and JSValue.fromRef(arguments[0]).toBoolean()).asRef();
}
@@ -1809,6 +1812,8 @@ pub const VirtualMachine = struct {
regular_event_loop: EventLoop = EventLoop{},
event_loop: *EventLoop = undefined,
ref_strings: JSC.RefString.Map = undefined,
source_mappings: SavedSourceMap = undefined,
pub inline fn eventLoop(this: *VirtualMachine) *EventLoop {
@@ -1889,7 +1894,9 @@ pub const VirtualMachine = struct {
pub fn tick(this: *EventLoop) void {
while (true) {
this.tickConcurrent();
while (this.tickWithCount() > 0) {}
this.tickConcurrent();
if (this.tickWithCount() == 0) break;
@@ -1897,10 +1904,9 @@ pub const VirtualMachine = struct {
}
pub fn waitForPromise(this: *EventLoop, promise: *JSC.JSInternalPromise) void {
var _vm = this.global.vm();
switch (promise.status(_vm)) {
switch (promise.status(this.global.vm())) {
JSC.JSPromise.Status.Pending => {
while (promise.status(_vm) == .Pending) {
while (promise.status(this.global.vm()) == .Pending) {
this.tick();
}
},
@@ -1937,9 +1943,11 @@ pub const VirtualMachine = struct {
}
pub fn tick(this: *VirtualMachine) void {
this.eventLoop().tickConcurrent();
this.eventLoop().tick();
}
while (this.eventLoop().tickWithCount() > 0) {}
pub fn waitForPromise(this: *VirtualMachine, promise: *JSC.JSInternalPromise) void {
this.eventLoop().waitForPromise(promise);
}
pub fn waitForTasks(this: *VirtualMachine) void {
@@ -2027,6 +2035,7 @@ pub const VirtualMachine = struct {
.macros = MacroMap.init(allocator),
.macro_entry_points = @TypeOf(VirtualMachine.vm.macro_entry_points).init(allocator),
.origin_timer = std.time.Timer.start() catch @panic("Please don't mess with timers."),
.ref_strings = JSC.RefString.Map.init(allocator),
};
VirtualMachine.vm.regular_event_loop.tasks = EventLoop.Queue.init(
@@ -2076,6 +2085,47 @@ pub const VirtualMachine = struct {
threadlocal var source_code_printer: ?*js_printer.BufferPrinter = null;
pub fn clearRefString(_: *anyopaque, ref_string: *JSC.RefString) void {
_ = VirtualMachine.vm.ref_strings.remove(ref_string.hash);
}
pub fn refCountedResolvedSource(this: *VirtualMachine, code: []const u8, specifier: []const u8, source_url: []const u8, hash_: ?u32) ResolvedSource {
var source = this.refCountedString(code, hash_, true);
return ResolvedSource{
.source_code = ZigString.init(source.slice()),
.specifier = ZigString.init(specifier),
.source_url = ZigString.init(source_url),
.hash = source.hash,
.allocator = source,
};
}
pub fn refCountedString(this: *VirtualMachine, input_: []const u8, hash_: ?u32, comptime dupe: bool) *JSC.RefString {
const hash = hash_ orelse JSC.RefString.computeHash(input_);
var entry = this.ref_strings.getOrPut(hash) catch unreachable;
if (!entry.found_existing) {
const input = if (comptime dupe)
(this.allocator.dupe(u8, input_) catch unreachable)
else
input_;
var ref = this.allocator.create(JSC.RefString) catch unreachable;
ref.* = JSC.RefString{
.allocator = this.allocator,
.ptr = input.ptr,
.len = input.len,
.hash = hash,
.ctx = this,
.onBeforeDeinit = VirtualMachine.clearRefString,
};
entry.value_ptr.* = ref;
}
return entry.value_ptr.*;
}
pub fn preflush(this: *VirtualMachine) void {
// We flush on the next tick so that if there were any errors you can still see them
this.blobs.?.temporary.reset() catch {};
@@ -2350,8 +2400,12 @@ pub const VirtualMachine = struct {
return error.PrintingErrorWriteFailed;
}
if (jsc_vm.has_loaded) {
return jsc_vm.refCountedResolvedSource(printer.ctx.written, specifier, path.text, null);
}
return ResolvedSource{
.allocator = if (jsc_vm.has_loaded) &jsc_vm.allocator else null,
.allocator = null,
.source_code = ZigString.init(jsc_vm.allocator.dupe(u8, printer.ctx.written) catch unreachable),
.specifier = ZigString.init(specifier),
.source_url = ZigString.init(path.text),
@@ -2590,11 +2644,15 @@ pub const VirtualMachine = struct {
return slice;
}
// This double prints
pub fn promiseRejectionTracker(_: *JSGlobalObject, _: *JSPromise, _: JSPromiseRejectionOperation) callconv(.C) JSValue {
// VirtualMachine.vm.defaultErrorHandler(promise.result(global.vm()), null);
return JSValue.jsUndefined();
}
// // This double prints
// pub fn promiseRejectionTracker(global: *JSGlobalObject, promise: *JSPromise, _: JSPromiseRejectionOperation) callconv(.C) JSValue {
// const result = promise.result(global.vm());
// if (@enumToInt(VirtualMachine.vm.last_error_jsvalue) != @enumToInt(result)) {
// VirtualMachine.vm.defaultErrorHandler(result, null);
// }
// return JSValue.jsUndefined();
// }
const main_file_name: string = "bun:main";
pub threadlocal var errors_stack: [256]*anyopaque = undefined;
@@ -2725,6 +2783,8 @@ pub const VirtualMachine = struct {
}
pub fn defaultErrorHandler(this: *VirtualMachine, result: JSValue, exception_list: ?*ExceptionList) void {
this.last_error_jsvalue = result;
if (result.isException(this.global.vm())) {
var exception = @ptrCast(*Exception, result.asVoid());
@@ -2763,26 +2823,14 @@ pub const VirtualMachine = struct {
this.has_loaded_node_modules = true;
promise = JSModuleLoader.loadAndEvaluateModule(this.global, &ZigString.init(std.mem.span(bun_file_import_path)));
this.tick();
while (promise.status(this.global.vm()) == JSPromise.Status.Pending) {
this.tick();
}
if (promise.status(this.global.vm()) == JSPromise.Status.Rejected) {
this.waitForPromise(promise);
if (promise.status(this.global.vm()) == .Rejected)
return promise;
}
_ = promise.result(this.global.vm());
}
promise = JSModuleLoader.loadAndEvaluateModule(this.global, &ZigString.init(std.mem.span(main_file_name)));
this.tick();
while (promise.status(this.global.vm()) == JSPromise.Status.Pending) {
this.tick();
}
this.waitForPromise(promise);
return promise;
}
@@ -2990,6 +3038,11 @@ pub const VirtualMachine = struct {
}
}
pub fn reportUncaughtExceptio(_: *JSGlobalObject, exception: *JSC.Exception) JSValue {
VirtualMachine.vm.defaultErrorHandler(exception.value(), null);
return JSC.JSValue.jsUndefined();
}
pub fn printStackTrace(comptime Writer: type, writer: Writer, trace: ZigStackTrace, comptime allow_ansi_colors: bool) !void {
const stack = trace.frames();
if (stack.len > 0) {
@@ -3359,9 +3412,7 @@ pub const EventListenerMixin = struct {
comptime onError: fn (ctx: *CtxType, err: anyerror, value: JSValue, request_ctx: *http.RequestContext) anyerror!void,
) !void {
if (comptime JSC.is_bindgen) unreachable;
defer {
if (request_context.has_called_done) request_context.arena.deinit();
}
var listeners = vm.event_listeners.get(EventType.fetch) orelse (return onError(ctx, error.NoListeners, JSValue.jsUndefined(), request_context) catch {});
if (listeners.items.len == 0) return onError(ctx, error.NoListeners, JSValue.jsUndefined(), request_context) catch {};
const FetchEventRejectionHandler = struct {
@@ -3370,7 +3421,7 @@ pub const EventListenerMixin = struct {
@intToPtr(*CtxType, @ptrToInt(_ctx)),
err,
value,
fetch_event.request_context,
fetch_event.request_context.?,
) catch {};
}
};
@@ -3386,9 +3437,11 @@ pub const EventListenerMixin = struct {
};
var fetch_args: [1]js.JSObjectRef = undefined;
for (listeners.items) |listener_ref| {
fetch_args[0] = FetchEvent.Class.make(vm.global.ref(), fetch_event);
fetch_args[0] = FetchEvent.Class.make(vm.global.ref(), fetch_event);
JSC.C.JSValueProtect(vm.global.ref(), fetch_args[0]);
defer JSC.C.JSValueUnprotect(vm.global.ref(), fetch_args[0]);
for (listeners.items) |listener_ref| {
vm.tick();
var result = js.JSObjectCallAsFunctionReturnValue(vm.global.ref(), listener_ref, null, 1, &fetch_args);
vm.tick();
@@ -3399,7 +3452,7 @@ pub const EventListenerMixin = struct {
if (fetch_event.rejected) return;
if (promise.status(vm.global.vm()) == .Rejected) {
onError(ctx, error.JSError, promise.result(vm.global.vm()), fetch_event.request_context) catch {};
onError(ctx, error.JSError, promise.result(vm.global.vm()), request_context) catch {};
return;
} else {
_ = promise.result(vm.global.vm());
@@ -3407,13 +3460,13 @@ pub const EventListenerMixin = struct {
vm.waitForTasks();
if (fetch_event.request_context.has_called_done) {
if (request_context.has_called_done) {
break;
}
}
if (!fetch_event.request_context.has_called_done) {
onError(ctx, error.FetchHandlerRespondWithNeverCalled, JSValue.jsUndefined(), fetch_event.request_context) catch {};
if (!request_context.has_called_done) {
onError(ctx, error.FetchHandlerRespondWithNeverCalled, JSValue.jsUndefined(), request_context) catch {};
return;
}
}