diff --git a/src/browser/Frame.zig b/src/browser/Frame.zig index 3e8fd8b2..61667086 100644 --- a/src/browser/Frame.zig +++ b/src/browser/Frame.zig @@ -4302,8 +4302,8 @@ pub fn submitForm(self: *Frame, submitter_: ?*Element, form_: ?*Element.Html.For // The submitter can be an input box (if enter was entered on the box) // I don't think this is technically correct, but FormData handles it ok const form_data = try FormData.init(form, submitter_, &self.js.execution); - // FormData.init acquires file's references. So we must release them once done. - defer form_data.deinit(self._page); + form_data.acquireRef(); + defer form_data.releaseRef(self._page); const arena = try self._session.getArena(.medium, "submitForm"); errdefer self._session.releaseArena(arena); diff --git a/src/browser/webapi/net/FormData.zig b/src/browser/webapi/net/FormData.zig index cafbff3d..5f8b6986 100644 --- a/src/browser/webapi/net/FormData.zig +++ b/src/browser/webapi/net/FormData.zig @@ -72,14 +72,18 @@ pub const Entry = struct { }; pub fn init(form_: ?*Form, submitter: ?*Element, exec: *const Execution) !*FormData { - const form = form_ orelse { - return try exec._factory.create(FormData{ - ._rc = .{}, - ._arena = exec.arena, - ._entries = .empty, - }); + const arena = try exec.getArena(.small, "FormData"); + errdefer exec.releaseArena(arena); + + const form_data = try arena.create(FormData); + form_data.* = .{ + ._rc = .{}, + ._arena = arena, + ._entries = .empty, }; + const form = form_ orelse return form_data; + const frame = switch (exec.js.global) { .frame => |f| f, .worker => lp.assert(false, "FormData worker form", .{}), @@ -93,12 +97,10 @@ pub fn init(form_: ?*Form, submitter: ?*Element, exec: *const Execution) !*FormD form._constructing_entry_list = true; defer form._constructing_entry_list = false; - const form_data = try exec._factory.create(FormData{ - ._rc = .{}, - ._arena = exec.arena, - ._entries = try collectForm(frame.arena, form, submitter, frame), - }); + form_data._entries = try collectForm(arena, form, submitter, frame); + // Hold a reference on each entry's File for the FormData's lifetime; released + // in deinit. for (form_data._entries.items) |entry| { switch (entry.value) { .file => |file| file.acquireRef(), @@ -123,6 +125,8 @@ pub fn deinit(self: *FormData, page: *Page) void { else => {}, } } + // Frees the entry list and this FormData itself; do not touch self afterwards. + page.releaseArena(self._arena); } pub fn releaseRef(self: *FormData, page: *Page) void {