Skip to content

Commit a65aa9f

Browse files
authored
Merge pull request #1126 from lightpanda-io/add_debug_context
Attempt to add more context to debug logs.
2 parents 5b43c16 + 9cb37dc commit a65aa9f

File tree

6 files changed

+41
-48
lines changed

6 files changed

+41
-48
lines changed

build.zig.zon

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
.fingerprint = 0xda130f3af836cea0,
66
.dependencies = .{
77
.v8 = .{
8-
.url = "https://github.com/lightpanda-io/zig-v8-fork/archive/7a1beb016efcb2bd66c0b46b5fc6bcd04fa72db8.tar.gz",
9-
.hash = "v8-0.0.0-xddH6_PFAwAqwLMWbF7S0rAZzRbN8zmf2GhLH_ThdMSR",
8+
.url = "https://github.com/lightpanda-io/zig-v8-fork/archive/5ce9ade6c6d7f7ab9ab4582a6b1b36fdc8e246e2.tar.gz",
9+
.hash = "v8-0.0.0-xddH6yTGAwA__kfiDozsVXL2_jnycrtDUfR8kIADQFUz",
1010
},
1111
//.v8 = .{ .path = "../zig-v8-fork" }
1212
},

src/browser/ScriptManager.zig

Lines changed: 22 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ fn clearList(_: *const ScriptManager, list: *OrderList) void {
131131
std.debug.assert(list.first == null);
132132
}
133133

134-
pub fn addFromElement(self: *ScriptManager, element: *parser.Element) !void {
134+
pub fn addFromElement(self: *ScriptManager, element: *parser.Element, comptime ctx: []const u8) !void {
135135
if (try parser.elementGetAttribute(element, "nomodule") != null) {
136136
// these scripts should only be loaded if we don't support modules
137137
// but since we do support modules, we can just skip them.
@@ -219,7 +219,11 @@ pub fn addFromElement(self: *ScriptManager, element: *parser.Element) !void {
219219
self.scripts.append(&pending_script.node);
220220
return;
221221
} else {
222-
log.debug(.http, "script queue", .{ .url = remote_url.? });
222+
log.debug(.http, "script queue", .{
223+
.ctx = ctx,
224+
.url = remote_url.?,
225+
.stack = page.js.stackTrace() catch "???",
226+
});
223227
}
224228

225229
pending_script.getList().append(&pending_script.node);
@@ -244,40 +248,7 @@ pub fn addFromElement(self: *ScriptManager, element: *parser.Element) !void {
244248
});
245249
}
246250

247-
// @TODO: Improving this would have the simplest biggest performance improvement
248-
// for most sites.
249-
//
250-
// For JS imports (both static and dynamic), we currently block to get the
251-
// result (the content of the file).
252-
//
253-
// For static imports, this is necessary, since v8 is expecting the compiled module
254-
// as part of the function return. (we should try to pre-load the JavaScript
255-
// source via module.GetModuleRequests(), but that's for a later time).
256-
//
257-
// For dynamic dynamic imports, this is not strictly necessary since the v8
258-
// call returns a Promise; we could make this a normal get call, associated with
259-
// the promise, and when done, resolve the promise.
260-
//
261-
// In both cases, for now at least, we just issue a "blocking" request. We block
262-
// by ticking the http client until the script is complete.
263-
//
264-
// This uses the client.blockingRequest call which has a dedicated handle for
265-
// these blocking requests. Because they are blocking, we're guaranteed to have
266-
// only 1 at a time, thus the 1 reserved handle.
267-
//
268-
// You almost don't need the http client's blocking handle. In most cases, you
269-
// should always have 1 free handle whenever you get here, because we always
270-
// release the handle before executing the doneCallback. So, if a module does:
271-
// import * as x from 'blah'
272-
// And we need to load 'blah', there should always be 1 free handle - the handle
273-
// of the http GET we just completed before executing the module.
274-
// The exception to this, and the reason we need a special blocking handle, is
275-
// for inline modules within the HTML page itself:
276-
// <script type=module>import ....</script>
277-
// Unlike external modules which can only ever be executed after releasing an
278-
// http handle, these are executed without there necessarily being a free handle.
279-
// Thus, Http/Client.zig maintains a dedicated handle for these calls.
280-
pub fn getModule(self: *ScriptManager, url: [:0]const u8) !void {
251+
pub fn getModule(self: *ScriptManager, url: [:0]const u8, referrer: []const u8) !void {
281252
const gop = try self.sync_modules.getOrPut(self.allocator, url);
282253
if (gop.found_existing) {
283254
// already requested
@@ -294,6 +265,13 @@ pub fn getModule(self: *ScriptManager, url: [:0]const u8) !void {
294265
var headers = try self.client.newHeaders();
295266
try self.page.requestCookie(.{}).headersForRequest(self.page.arena, url, &headers);
296267

268+
log.debug(.http, "script queue", .{
269+
.url = url,
270+
.ctx = "module",
271+
.referrer = referrer,
272+
.stack = self.page.js.stackTrace() catch "???",
273+
});
274+
297275
try self.client.request(.{
298276
.url = url,
299277
.ctx = sync,
@@ -340,7 +318,7 @@ pub fn waitForModule(self: *ScriptManager, url: [:0]const u8) !GetResult {
340318
}
341319
}
342320

343-
pub fn getAsyncModule(self: *ScriptManager, url: [:0]const u8, cb: AsyncModule.Callback, cb_data: *anyopaque) !void {
321+
pub fn getAsyncModule(self: *ScriptManager, url: [:0]const u8, cb: AsyncModule.Callback, cb_data: *anyopaque, referrer: []const u8) !void {
344322
const async = try self.async_module_pool.create();
345323
errdefer self.async_module_pool.destroy(async);
346324

@@ -353,6 +331,13 @@ pub fn getAsyncModule(self: *ScriptManager, url: [:0]const u8, cb: AsyncModule.C
353331
var headers = try self.client.newHeaders();
354332
try self.page.requestCookie(.{}).headersForRequest(self.page.arena, url, &headers);
355333

334+
log.debug(.http, "script queue", .{
335+
.url = url,
336+
.ctx = "dynamic module",
337+
.referrer = referrer,
338+
.stack = self.page.js.stackTrace() catch "???",
339+
});
340+
356341
try self.client.request(.{
357342
.url = url,
358343
.method = .GET,

src/browser/html/elements.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,7 @@ pub const HTMLScriptElement = struct {
887887
// s.src = '...';
888888
// This should load the script.
889889
// addFromElement protects against double execution.
890-
try page.script_manager.addFromElement(@ptrCast(@alignCast(self)));
890+
try page.script_manager.addFromElement(@ptrCast(@alignCast(self)), "dynamic");
891891
}
892892
}
893893

src/browser/js/Context.zig

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ pub fn module(self: *Context, comptime want_result: bool, src: []const u8, url:
262262
const owned_specifier = try self.arena.dupeZ(u8, normalized_specifier);
263263
gop.key_ptr.* = owned_specifier;
264264
gop.value_ptr.* = .{};
265-
try self.script_manager.?.getModule(owned_specifier);
265+
try self.script_manager.?.getModule(owned_specifier, src);
266266
}
267267
}
268268
}
@@ -995,7 +995,10 @@ fn debugValueToString(self: *const Context, js_obj: v8.Object) ![]u8 {
995995
}
996996

997997
pub fn stackTrace(self: *const Context) !?[]const u8 {
998-
std.debug.assert(@import("builtin").mode == .Debug);
998+
if (comptime @import("builtin").mode != .Debug) {
999+
return "not available";
1000+
}
1001+
9991002
const isolate = self.isolate;
10001003
const separator = log.separator();
10011004

@@ -1005,6 +1008,10 @@ pub fn stackTrace(self: *const Context) !?[]const u8 {
10051008
const stack_trace = v8.StackTrace.getCurrentStackTrace(isolate, 30);
10061009
const frame_count = stack_trace.getFrameCount();
10071010

1011+
if (v8.StackTrace.getCurrentScriptNameOrSourceUrl(isolate)) |script| {
1012+
try writer.print("{s}<{s}>", .{ separator, try self.jsStringToZig(script, .{}) });
1013+
}
1014+
10081015
for (0..frame_count) |i| {
10091016
const frame = stack_trace.getFrame(isolate, @intCast(i));
10101017
if (frame.getScriptName()) |name| {
@@ -1130,7 +1137,7 @@ pub fn dynamicModuleCallback(
11301137
return @constCast(self.rejectPromise("Out of memory").handle);
11311138
};
11321139

1133-
const promise = self._dynamicModuleCallback(normalized_specifier) catch |err| blk: {
1140+
const promise = self._dynamicModuleCallback(normalized_specifier, resource) catch |err| blk: {
11341141
log.err(.js, "dynamic module callback", .{
11351142
.err = err,
11361143
});
@@ -1190,7 +1197,7 @@ fn _resolveModuleCallback(self: *Context, referrer: v8.Module, specifier: []cons
11901197
// harm in handling this case.
11911198
@branchHint(.unlikely);
11921199
gop.value_ptr.* = .{};
1193-
try self.script_manager.?.getModule(normalized_specifier);
1200+
try self.script_manager.?.getModule(normalized_specifier, referrer_path);
11941201
}
11951202

11961203
var fetch_result = try self.script_manager.?.waitForModule(normalized_specifier);
@@ -1226,7 +1233,7 @@ const DynamicModuleResolveState = struct {
12261233
resolver: v8.Persistent(v8.PromiseResolver),
12271234
};
12281235

1229-
fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8) !v8.Promise {
1236+
fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []const u8) !v8.Promise {
12301237
const isolate = self.isolate;
12311238
const gop = try self.module_cache.getOrPut(self.arena, specifier);
12321239
if (gop.found_existing and gop.value_ptr.resolver_promise != null) {
@@ -1266,7 +1273,7 @@ fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8) !v8.Promise {
12661273
};
12671274

12681275
// Next, we need to actually load it.
1269-
self.script_manager.?.getAsyncModule(specifier, dynamicModuleSourceCallback, state) catch |err| {
1276+
self.script_manager.?.getAsyncModule(specifier, dynamicModuleSourceCallback, state, referrer) catch |err| {
12701277
const error_msg = v8.String.initUtf8(isolate, @errorName(err));
12711278
_ = resolver.reject(self.v8_context, error_msg.toValue());
12721279
};

src/browser/page.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,7 @@ pub const Page = struct {
785785
// ignore non-js script.
786786
continue;
787787
}
788-
try self.script_manager.addFromElement(@ptrCast(node));
788+
try self.script_manager.addFromElement(@ptrCast(node), "page");
789789
}
790790

791791
self.script_manager.staticScriptsDone();
@@ -1250,7 +1250,7 @@ pub export fn scriptAddedCallback(ctx: ?*anyopaque, element: ?*parser.Element) c
12501250
// here, else the script_manager will flag it as already-processed.
12511251
_ = parser.elementGetAttribute(element.?, "src") catch return orelse return;
12521252

1253-
self.script_manager.addFromElement(element.?) catch |err| {
1253+
self.script_manager.addFromElement(element.?, "dynamic") catch |err| {
12541254
log.warn(.browser, "dynamic script", .{ .err = err });
12551255
};
12561256
}

src/browser/polyfill/polyfill.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ pub const Loader = struct {
6969
if (comptime builtin.mode == .Debug) {
7070
log.debug(.unknown_prop, "unkown global property", .{
7171
.info = "but the property can exist in pure JS",
72+
.stack = js_context.stackTrace() catch "???",
7273
.property = name,
7374
});
7475
}

0 commit comments

Comments
 (0)