Skip to content

Commit f4e8bb6

Browse files
committed
Re-introduce postAttach
index_get seems to be ~1000x slower than setting the value directly on the v8.Object. There's a lot of information on "v8 fast properties", and values set directly on objects seem to be heavily optimized. Still, I can't imagine indexed properties are always _that_ slow, so I must be doing something wrong. Still, for now, this brings back the original functionality / behavior / perf. Introduce the ability for Zig functions to take a Env.JsObject parameter. While this isn't currently being used, it aligns with bringing back the postAttach / JSObject functionality in main. Moved function *State to the end of the function list (making it consistent with getters and setters). The optional Env.JsObject parameter comes after the optional state. Removed some uncessary arena deinits from a few webapis.
1 parent e363805 commit f4e8bb6

24 files changed

+200
-156
lines changed

src/browser/dom/comment.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub const Comment = struct {
2828
pub const Self = parser.Comment;
2929
pub const prototype = *CharacterData;
3030

31-
pub fn constructor(state: *const SessionState, data: ?[]const u8) !*parser.Comment {
31+
pub fn constructor(data: ?[]const u8, state: *const SessionState) !*parser.Comment {
3232
return parser.documentCreateComment(
3333
parser.documentHTMLToDocument(state.document.?),
3434
data orelse "",

src/browser/dom/document.zig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,16 @@ pub const Document = struct {
138138
// HTMLCollection in zig here.
139139
pub fn _getElementsByTagName(
140140
self: *parser.Document,
141-
state: *SessionState,
142141
tag_name: []const u8,
142+
state: *SessionState,
143143
) !collection.HTMLCollection {
144144
return try collection.HTMLCollectionByTagName(state.arena, parser.documentToNode(self), tag_name, true);
145145
}
146146

147147
pub fn _getElementsByClassName(
148148
self: *parser.Document,
149-
state: *SessionState,
150149
classNames: []const u8,
150+
state: *SessionState,
151151
) !collection.HTMLCollection {
152152
const allocator = state.arena;
153153
return try collection.HTMLCollectionByClassName(allocator, parser.documentToNode(self), classNames, true);
@@ -212,7 +212,7 @@ pub const Document = struct {
212212
return 1;
213213
}
214214

215-
pub fn _querySelector(self: *parser.Document, state: *SessionState, selector: []const u8) !?ElementUnion {
215+
pub fn _querySelector(self: *parser.Document, selector: []const u8, state: *SessionState) !?ElementUnion {
216216
if (selector.len == 0) return null;
217217

218218
const allocator = state.arena;
@@ -223,7 +223,7 @@ pub const Document = struct {
223223
return try Element.toInterface(parser.nodeToElement(n.?));
224224
}
225225

226-
pub fn _querySelectorAll(self: *parser.Document, state: *SessionState, selector: []const u8) !NodeList {
226+
pub fn _querySelectorAll(self: *parser.Document, selector: []const u8, state: *SessionState) !NodeList {
227227
const allocator = state.arena;
228228
return css.querySelectorAll(allocator, parser.documentToNode(self), selector);
229229
}

src/browser/dom/element.zig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,8 @@ pub const Element = struct {
226226

227227
pub fn _getElementsByTagName(
228228
self: *parser.Element,
229-
state: *SessionState,
230229
tag_name: []const u8,
230+
state: *SessionState,
231231
) !collection.HTMLCollection {
232232
return try collection.HTMLCollectionByTagName(
233233
state.arena,
@@ -239,8 +239,8 @@ pub const Element = struct {
239239

240240
pub fn _getElementsByClassName(
241241
self: *parser.Element,
242-
state: *SessionState,
243242
classNames: []const u8,
243+
state: *SessionState,
244244
) !collection.HTMLCollection {
245245
return try collection.HTMLCollectionByClassName(
246246
state.arena,
@@ -306,7 +306,7 @@ pub const Element = struct {
306306
}
307307
}
308308

309-
pub fn _querySelector(self: *parser.Element, state: *SessionState, selector: []const u8) !?Union {
309+
pub fn _querySelector(self: *parser.Element, selector: []const u8, state: *SessionState) !?Union {
310310
if (selector.len == 0) return null;
311311

312312
const n = try css.querySelector(state.arena, parser.elementToNode(self), selector);
@@ -316,7 +316,7 @@ pub const Element = struct {
316316
return try toInterface(parser.nodeToElement(n.?));
317317
}
318318

319-
pub fn _querySelectorAll(self: *parser.Element, state: *SessionState, selector: []const u8) !NodeList {
319+
pub fn _querySelectorAll(self: *parser.Element, selector: []const u8, state: *SessionState) !NodeList {
320320
return css.querySelectorAll(state.arena, parser.elementToNode(self), selector);
321321
}
322322

src/browser/dom/event_target.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ pub const EventTarget = struct {
4646

4747
pub fn _addEventListener(
4848
self: *parser.EventTarget,
49-
state: *SessionState,
5049
eventType: []const u8,
5150
cbk: Env.Callback,
5251
capture: ?bool,
52+
state: *SessionState,
5353
// TODO: hanle EventListenerOptions
5454
// see #https://github.com/lightpanda-io/jsruntime-lib/issues/114
5555
) !void {
@@ -76,10 +76,10 @@ pub const EventTarget = struct {
7676

7777
pub fn _removeEventListener(
7878
self: *parser.EventTarget,
79-
state: *SessionState,
8079
eventType: []const u8,
8180
cbk: Env.Callback,
8281
capture: ?bool,
82+
state: *SessionState,
8383
// TODO: hanle EventListenerOptions
8484
// see #https://github.com/lightpanda-io/jsruntime-lib/issues/114
8585
) !void {

src/browser/dom/html_collection.zig

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ const utils = @import("utils.z");
2424
const Element = @import("element.zig").Element;
2525
const Union = @import("element.zig").Union;
2626

27+
const JsObject = @import("../env.zig").JsObject;
28+
2729
const Walker = @import("walker.zig").Walker;
2830
const WalkerDepthFirst = @import("walker.zig").WalkerDepthFirst;
2931
const WalkerChildren = @import("walker.zig").WalkerChildren;
@@ -318,10 +320,6 @@ pub const HTMLCollection = struct {
318320
cur_idx: ?u32 = undefined,
319321
cur_node: ?*parser.Node = undefined,
320322

321-
// array_like_keys is used to keep reference to array like interface implementation.
322-
// the collection generates keys string which must be free on deinit.
323-
array_like_keys: std.ArrayListUnmanaged([]u8) = .{},
324-
325323
// start returns the first node to walk on.
326324
fn start(self: HTMLCollection) !?*parser.Node {
327325
if (self.root == null) return null;
@@ -403,13 +401,6 @@ pub const HTMLCollection = struct {
403401
return try Element.toInterface(e);
404402
}
405403

406-
pub fn indexed_get(self: *HTMLCollection, index: u32, has_value: *bool) !?Union {
407-
return (try self._item(index)) orelse {
408-
has_value.* = false;
409-
return null;
410-
};
411-
}
412-
413404
pub fn _namedItem(self: *const HTMLCollection, name: []const u8) !?Union {
414405
if (self.root == null) return null;
415406
if (name.len == 0) return null;
@@ -441,13 +432,6 @@ pub const HTMLCollection = struct {
441432
return null;
442433
}
443434

444-
pub fn named_get(self: *HTMLCollection, name: []const u8, has_value: *bool) !?Union {
445-
return (try self._namedItem(name)) orelse {
446-
has_value.* = false;
447-
return null;
448-
};
449-
}
450-
451435
fn item_name(elt: *parser.Element) !?[]const u8 {
452436
if (try parser.elementGetAttribute(elt, "id")) |v| {
453437
return v;
@@ -459,10 +443,17 @@ pub const HTMLCollection = struct {
459443
return null;
460444
}
461445

462-
pub fn deinit(self: *HTMLCollection, alloc: std.mem.Allocator) void {
463-
for (self.array_like_keys_) |k| alloc.free(k);
464-
self.array_like_keys.deinit(alloc);
465-
self.matcher.deinit(alloc);
446+
pub fn postAttach(self: *HTMLCollection, js_obj: JsObject) !void {
447+
const len = try self.get_length();
448+
for (0..len) |i| {
449+
const node = try self.item(@intCast(i)) orelse unreachable;
450+
const e = @as(*parser.Element, @ptrCast(node));
451+
try js_obj.setIndex(@intCast(i), e);
452+
453+
if (try item_name(e)) |name| {
454+
try js_obj.set(name, e);
455+
}
456+
}
466457
}
467458
};
468459

src/browser/dom/implementation.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ pub const DOMImplementation = struct {
3131

3232
pub fn _createDocumentType(
3333
_: *DOMImplementation,
34-
state: *SessionState,
3534
qname: []const u8,
3635
publicId: []const u8,
3736
systemId: []const u8,
37+
state: *SessionState,
3838
) !*parser.DocumentType {
3939
const allocator = state.arena;
4040
const cqname = try allocator.dupeZ(u8, qname);
@@ -51,10 +51,10 @@ pub const DOMImplementation = struct {
5151

5252
pub fn _createDocument(
5353
_: *DOMImplementation,
54-
state: *SessionState,
5554
namespace: ?[]const u8,
5655
qname: ?[]const u8,
5756
doctype: ?*parser.DocumentType,
57+
state: *SessionState,
5858
) !*parser.Document {
5959
const allocator = state.arena;
6060
var cnamespace: ?[:0]const u8 = null;

src/browser/dom/mutation_observer.zig

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const parser = @import("../netsurf.zig");
2222
const SessionState = @import("../env.zig").SessionState;
2323

2424
const Env = @import("../env.zig").Env;
25+
const JsObject = @import("../env.zig").JsObject;
2526
const NodeList = @import("nodelist.zig").NodeList;
2627

2728
pub const Interfaces = .{
@@ -84,7 +85,7 @@ pub const MutationObserver = struct {
8485
return opt orelse .{};
8586
}
8687

87-
pub fn _observe(self: *MutationObserver, state: *SessionState, node: *parser.Node, options: ?MutationObserverInit) !void {
88+
pub fn _observe(self: *MutationObserver, node: *parser.Node, options: ?MutationObserverInit, state: *SessionState) !void {
8889
const arena = state.arena;
8990
const o = try arena.create(Observer);
9091
o.* = .{
@@ -183,6 +184,11 @@ pub const MutationRecords = struct {
183184
return null;
184185
};
185186
}
187+
pub fn postAttach(self: *const MutationRecords, js_obj: JsObject) !void {
188+
if (self.first) |mr| {
189+
try js_obj.set("0", mr);
190+
}
191+
}
186192
};
187193

188194
pub const MutationRecord = struct {

src/browser/dom/node.zig

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@
1818

1919
const std = @import("std");
2020

21-
const jsruntime = @import("jsruntime");
22-
const Case = jsruntime.test_utils.Case;
23-
const checkCases = jsruntime.test_utils.checkCases;
24-
const runScript = jsruntime.test_utils.runScript;
25-
2621
const parser = @import("../netsurf.zig");
2722
const generate = @import("../../runtime/generate.zig");
2823

src/browser/dom/nodelist.zig

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@ const std = @import("std");
2020

2121
const parser = @import("../netsurf.zig");
2222

23-
const jsruntime = @import("jsruntime");
23+
const JsObject = @import("../env.zig").JsObject;
2424
const Callback = @import("../env.zig").Callback;
25-
const Case = jsruntime.test_utils.Case;
26-
const checkCases = jsruntime.test_utils.checkCases;
25+
const SessionState = @import("../env.zig").SessionState;
2726

2827
const NodeUnion = @import("node.zig").Union;
2928
const Node = @import("node.zig").Node;
@@ -133,13 +132,22 @@ pub const NodeList = struct {
133132
return try Node.toInterface(n);
134133
}
135134

136-
// TODO entries() https://developer.mozilla.org/en-US/docs/Web/API/NodeList/entries
137-
pub fn indexed_get(self: *const NodeList, index: u32, has_value: *bool) !?NodeUnion {
138-
return (try self._item(index)) orelse {
139-
has_value.* = false;
140-
return null;
141-
};
142-
}
135+
// This code works, but it's _MUCH_ slower than using postAttach. The benefit
136+
// of this version, is that it's "live"..but we're talking many orders of
137+
// magnitude slower.
138+
//
139+
// You can test it by commenting out `postAttach`, uncommenting this and
140+
// running:
141+
// zig build wpt -- tests/wpt/dom/nodes/NodeList-static-length-getter-tampered-indexOf-1.html
142+
//
143+
// I think this _is_ the right way to do it, but I must be doing something
144+
// wrong to make it so slow.
145+
// pub fn indexed_get(self: *const NodeList, index: u32, has_value: *bool) !?NodeUnion {
146+
// return (try self._item(index)) orelse {
147+
// has_value.* = false;
148+
// return null;
149+
// };
150+
// }
143151

144152
pub fn _forEach(self: *NodeList, cbk: Callback) !void { // TODO handle thisArg
145153
for (self.nodes.items, 0..) |n, i| {
@@ -167,6 +175,15 @@ pub const NodeList = struct {
167175
pub fn _symbol_iterator(self: *NodeList) NodeListIterator {
168176
return self._values();
169177
}
178+
179+
// TODO entries() https://developer.mozilla.org/en-US/docs/Web/API/NodeList/entries
180+
pub fn postAttach(self: *NodeList, js_obj: JsObject) !void {
181+
const len = self.get_length();
182+
for (0..len) |i| {
183+
const node = try self._item(@intCast(i)) orelse unreachable;
184+
try js_obj.setIndex(i, node);
185+
}
186+
}
170187
};
171188

172189
const testing = @import("../../testing.zig");

src/browser/dom/text.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub const Text = struct {
3333
pub const Self = parser.Text;
3434
pub const prototype = *CharacterData;
3535

36-
pub fn constructor(state: *const SessionState, data: ?[]const u8) !*parser.Text {
36+
pub fn constructor(data: ?[]const u8, state: *const SessionState) !*parser.Text {
3737
return parser.documentCreateTextNode(
3838
parser.documentHTMLToDocument(state.document.?),
3939
data orelse "",

0 commit comments

Comments
 (0)