Skip to content

Commit

Permalink
[bun.js] Fix GC bug with fetch
Browse files Browse the repository at this point in the history
  • Loading branch information
Jarred-Sumner committed Jul 13, 2022
1 parent 0592b1d commit d3963d6
Showing 1 changed file with 29 additions and 68 deletions.
97 changes: 29 additions & 68 deletions src/bun.js/webcore/response.zig
Original file line number Diff line number Diff line change
Expand Up @@ -671,17 +671,14 @@ pub const Fetch = struct {
);

pub const FetchTasklet = struct {
promise: *JSInternalPromise = undefined,
promise: *JSPromise = undefined,
http: HTTPClient.AsyncHTTP = undefined,
status: Status = Status.pending,
javascript_vm: *VirtualMachine = undefined,
global_this: *JSGlobalObject = undefined,

empty_request_body: MutableString = undefined,
// pooled_body: *BodyPool.Node = undefined,
this_object: js.JSObjectRef = null,
resolve: js.JSObjectRef = null,
reject: js.JSObjectRef = null,

context: FetchTaskletContext = undefined,
response_buffer: MutableString = undefined,

Expand All @@ -706,32 +703,34 @@ pub const Fetch = struct {
pub fn onDone(this: *FetchTasklet) void {
if (comptime JSC.is_bindgen)
unreachable;
var args = [1]js.JSValueRef{undefined};

var callback_object = switch (this.http.state.load(.Monotonic)) {
.success => this.resolve,
.fail => this.reject,
else => unreachable,
};

args[0] = switch (this.http.state.load(.Monotonic)) {
.success => this.onResolve().asObjectRef(),
.fail => this.onReject().asObjectRef(),
const globalThis = this.global_this;
const promise = this.promise;
const state = this.http.state.load(.Monotonic);
const result = switch (state) {
.success => this.onResolve(),
.fail => this.onReject(),
else => unreachable,
};

_ = js.JSObjectCallAsFunction(this.global_this.ref(), callback_object, null, 1, &args, null);

this.release();
const promise_value = promise.asValue(globalThis);
promise_value.unprotect();

switch (state) {
.success => {
promise.resolve(globalThis, result);
},
.fail => {
promise.reject(globalThis, result);
},
else => unreachable,
}
}

pub fn reset(_: *FetchTasklet) void {}

pub fn release(this: *FetchTasklet) void {
js.JSValueUnprotect(this.global_this.ref(), this.resolve);
js.JSValueUnprotect(this.global_this.ref(), this.reject);
js.JSValueUnprotect(this.global_this.ref(), this.this_object);

this.global_this = undefined;
this.javascript_vm = undefined;
this.promise = undefined;
Expand All @@ -740,43 +739,13 @@ pub const Fetch = struct {
// BodyPool.release(pooled);
// this.pooled_body = undefined;
this.http = undefined;
this.this_object = null;
this.resolve = null;
this.reject = null;

Pool.release(@fieldParentPtr(Pool.Node, "data", this));
}

pub const FetchResolver = struct {
pub fn call(
_: js.JSContextRef,
_: js.JSObjectRef,
_: js.JSObjectRef,
_: usize,
arguments: [*c]const js.JSValueRef,
_: js.ExceptionRef,
) callconv(.C) js.JSObjectRef {
return JSPrivateDataPtr.from(js.JSObjectGetPrivate(arguments[0]))
.get(FetchTaskletContext).?.tasklet.onResolve().asObjectRef();
// return js.JSObjectGetPrivate(arguments[0]).? .tasklet.onResolve().asObjectRef();
}
};

pub const FetchRejecter = struct {
pub fn call(
_: js.JSContextRef,
_: js.JSObjectRef,
_: js.JSObjectRef,
_: usize,
arguments: [*c]const js.JSValueRef,
_: js.ExceptionRef,
) callconv(.C) js.JSObjectRef {
return JSPrivateDataPtr.from(js.JSObjectGetPrivate(arguments[0]))
.get(FetchTaskletContext).?.tasklet.onReject().asObjectRef();
}
};

pub fn onReject(this: *FetchTasklet) JSValue {
if (this.blob_store) |store| {
this.blob_store = null;
store.deref();
}
const fetch_error = std.fmt.allocPrint(
Expand All @@ -795,6 +764,7 @@ pub const Fetch = struct {
var http_response = this.http.response.?;
var response = allocator.create(Response) catch unreachable;
if (this.blob_store) |store| {
this.blob_store = null;
store.deref();
}
response.* = Response{
Expand Down Expand Up @@ -859,7 +829,6 @@ pub const Fetch = struct {
request_body_store: ?*Blob.Store,
) !*FetchTasklet.Pool.Node {
var node = try get(allocator, method, url, headers, headers_buf, request_body, timeout, request_body_store);
node.data.promise = JSInternalPromise.create(global);

node.data.global_this = global;
node.data.http.callback = callback;
Expand All @@ -883,7 +852,7 @@ pub const Fetch = struct {
_: js.JSObjectRef,
_: js.JSObjectRef,
arguments: []const js.JSValueRef,
exception: js.ExceptionRef,
_: js.ExceptionRef,
) js.JSObjectRef {
var globalThis = ctx.ptr();

Expand Down Expand Up @@ -983,11 +952,6 @@ pub const Fetch = struct {
header_entries = head.entries;
header_buf = head.buf.items;
}
var resolve = js.JSObjectMakeFunctionWithCallback(ctx, null, Fetch.FetchTasklet.FetchResolver.call);
var reject = js.JSObjectMakeFunctionWithCallback(ctx, null, Fetch.FetchTasklet.FetchRejecter.call);

js.JSValueProtect(ctx, resolve);
js.JSValueProtect(ctx, reject);

var request_body: ?*MutableString = null;
if (body.list.items.len > 0) {
Expand All @@ -1008,15 +972,12 @@ pub const Fetch = struct {
std.time.ns_per_hour,
blob_store,
) catch unreachable;
queued.data.this_object = js.JSObjectMake(ctx, null, JSPrivateDataPtr.from(&queued.data.context).ptr());
js.JSValueProtect(ctx, queued.data.this_object);

var promise = js.JSObjectMakeDeferredPromise(ctx, &resolve, &reject, exception);
queued.data.reject = reject;
queued.data.resolve = resolve;
const promise = JSC.JSPromise.create(ctx);
queued.data.promise = promise;
const promise_value = promise.asValue(ctx);
promise_value.protect();

return promise;
// queued.data.promise.create(globalThis: *JSGlobalObject)
return promise_value.asObjectRef();
}
};

Expand Down

0 comments on commit d3963d6

Please sign in to comment.