debug: remove unknown property logging

Commented it out for now, but plan on remove the code at some point in the
future. This was useful when sites would break because of an unimplemented
API, but (a) those are rare now and (b) AI is good at finding issues without
this. As-is, it just makes --log-level debug useless in Debug builds. The
logging could never tell between an site-specific global and a real API, and
sites have _a lot_ of globals, so it's a lot of noise.
This commit is contained in:
Karl Seguin committed 2026-08-29 12:01:00 +08:00
1 parent dd2669ade6
commit eabc865338
2 files changed
+130 -124

No files matched your search

+26 -24
View File
@@ -592,14 +592,15 @@ fn collectExternalReferences() [countExternalReferences()]isize {
}
}
if (comptime lp.IS_DEBUG) {
inline for (JsApis) |JsApi| {
if (!hasNamedIndexedGetter(JsApi)) {
references[idx] = @bitCast(@intFromPtr(bridge.unknownObjectPropertyCallback(JsApi)));
idx += 1;
}
}
}
// @LOG-UNKNOWN-PROPERTY
// if (comptime lp.IS_DEBUG) {
// inline for (JsApis) |JsApi| {
// if (!hasNamedIndexedGetter(JsApi)) {
// references[idx] = @bitCast(@intFromPtr(bridge.unknownObjectPropertyCallback(JsApi)));
// idx += 1;
// }
// }
// }
return references;
}
@@ -907,22 +908,23 @@ fn attachClass(comptime JsApi: type, comptime flatten: bool, isolate: *v8.Isolat
v8.v8__Template__Set(@ptrCast(instance), js_name, js_value, v8.ReadOnly + v8.DontEnum);
}
if (comptime lp.IS_DEBUG) {
if (!has_named_index_getter) {
var configuration: v8.NamedPropertyHandlerConfiguration = .{
.getter = bridge.unknownObjectPropertyCallback(JsApi),
.setter = null,
.query = null,
.deleter = null,
.enumerator = null,
.definer = null,
.descriptor = null,
.data = null,
.flags = v8.kOnlyInterceptStrings | v8.kNonMasking,
};
v8.v8__ObjectTemplate__SetNamedHandler(instance, &configuration);
}
}
// @LOG-UNKNOWN-PROPERTY
// if (comptime lp.IS_DEBUG) {
// if (!has_named_index_getter) {
// var configuration: v8.NamedPropertyHandlerConfiguration = .{
// .getter = bridge.unknownObjectPropertyCallback(JsApi),
// .setter = null,
// .query = null,
// .deleter = null,
// .enumerator = null,
// .definer = null,
// .descriptor = null,
// .data = null,
// .flags = v8.kOnlyInterceptStrings | v8.kNonMasking,
// };
// v8.v8__ObjectTemplate__SetNamedHandler(instance, &configuration);
// }
// }
}
// The chain of interface types reachable from a [Global] interface via WebIDL
+104 -100
View File
@@ -684,128 +684,132 @@ pub fn unknownWindowPropertyCallback(c_name: ?*const v8.Name, handle: ?*const v8
.worker => {}, // no global lookup in a worker
}
if (comptime lp.IS_DEBUG) {
if (std.mem.startsWith(u8, property, "__")) {
// some frameworks will extend built-in types using a __ prefix
// these should always be safe to ignore.
return js.Intercepted.no;
}
// @LOG-UNKNOWN-PROPERTY
// This was really useful when sites often broke because of an unimplemented
// feature. But it hasnt' been useful to me in ~6 months.
// if (comptime lp.IS_DEBUG) {
// if (std.mem.startsWith(u8, property, "__")) {
// // some frameworks will extend built-in types using a __ prefix
// // these should always be safe to ignore.
// return js.Intercepted.no;
// }
const ignored = std.StaticStringMap(void).initComptime(.{
.{ "Deno", {} },
.{ "process", {} },
.{ "ShadyDOM", {} },
.{ "ShadyCSS", {} },
// const ignored = std.StaticStringMap(void).initComptime(.{
// .{ "Deno", {} },
// .{ "process", {} },
// .{ "ShadyDOM", {} },
// .{ "ShadyCSS", {} },
// a lot of sites seem to like having their own window.config.
.{ "config", {} },
// // a lot of sites seem to like having their own window.config.
// .{ "config", {} },
.{ "litNonce", {} },
.{ "litHtmlVersions", {} },
.{ "litElementVersions", {} },
.{ "litHtmlPolyfillSupport", {} },
.{ "litElementHydrateSupport", {} },
.{ "litElementPolyfillSupport", {} },
.{ "reactiveElementVersions", {} },
// .{ "litNonce", {} },
// .{ "litHtmlVersions", {} },
// .{ "litElementVersions", {} },
// .{ "litHtmlPolyfillSupport", {} },
// .{ "litElementHydrateSupport", {} },
// .{ "litElementPolyfillSupport", {} },
// .{ "reactiveElementVersions", {} },
.{ "recaptcha", {} },
.{ "grecaptcha", {} },
.{ "___grecaptcha_cfg", {} },
.{ "__recaptcha_api", {} },
.{ "__google_recaptcha_client", {} },
// .{ "recaptcha", {} },
// .{ "grecaptcha", {} },
// .{ "___grecaptcha_cfg", {} },
// .{ "__recaptcha_api", {} },
// .{ "__google_recaptcha_client", {} },
.{ "CLOSURE_FLAGS", {} },
.{ "__REACT_DEVTOOLS_GLOBAL_HOOK__", {} },
.{ "ApplePaySession", {} },
});
if (!ignored.has(property)) {
var buf: [2048]u8 = undefined;
const key = std.fmt.bufPrint(&buf, "Window:{s}", .{property}) catch return js.Intercepted.no;
logUnknownProperty(local, key) catch return js.Intercepted.no;
}
}
// .{ "CLOSURE_FLAGS", {} },
// .{ "__REACT_DEVTOOLS_GLOBAL_HOOK__", {} },
// .{ "ApplePaySession", {} },
// });
// if (!ignored.has(property)) {
// var buf: [2048]u8 = undefined;
// const key = std.fmt.bufPrint(&buf, "Window:{s}", .{property}) catch return js.Intercepted.no;
// logUnknownProperty(local, key) catch return js.Intercepted.no;
// }
// }
return js.Intercepted.no;
}
// @LOG-UNKNOWN-PROPERTY
// Only used for debugging
pub fn unknownObjectPropertyCallback(comptime JsApi: type) *const fn (?*const v8.Name, ?*const v8.PropertyCallbackInfo) callconv(.c) u32 {
if (comptime !lp.IS_DEBUG) {
@compileError("unknownObjectPropertyCallback should only be used in debug builds");
}
// pub fn unknownObjectPropertyCallback(comptime JsApi: type) *const fn (?*const v8.Name, ?*const v8.PropertyCallbackInfo) callconv(.c) u32 {
// if (comptime !lp.IS_DEBUG) {
// @compileError("unknownObjectPropertyCallback should only be used in debug builds");
// }
return struct {
fn wrap(c_name: ?*const v8.Name, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32 {
const v8_isolate = v8.v8__PropertyCallbackInfo__GetIsolate(handle).?;
// return struct {
// fn wrap(c_name: ?*const v8.Name, handle: ?*const v8.PropertyCallbackInfo) callconv(.c) u32 {
// const v8_isolate = v8.v8__PropertyCallbackInfo__GetIsolate(handle).?;
var caller: Caller = undefined;
if (!caller.init(v8_isolate)) {
return js.Intercepted.no;
}
defer caller.deinit();
// var caller: Caller = undefined;
// if (!caller.init(v8_isolate)) {
// return js.Intercepted.no;
// }
// defer caller.deinit();
const local = &caller.local;
// const local = &caller.local;
var hs: js.HandleScope = undefined;
hs.init(local.isolate);
defer hs.deinit();
// var hs: js.HandleScope = undefined;
// hs.init(local.isolate);
// defer hs.deinit();
const property: []const u8 = js.String.toSlice(.{ .local = local, .handle = @ptrCast(c_name.?) }) catch {
return js.Intercepted.no;
};
// const property: []const u8 = js.String.toSlice(.{ .local = local, .handle = @ptrCast(c_name.?) }) catch {
// return js.Intercepted.no;
// };
if (std.mem.startsWith(u8, property, "__")) {
// some frameworks will extend built-in types using a __ prefix
// these should always be safe to ignore.
return js.Intercepted.no;
}
// if (std.mem.startsWith(u8, property, "__")) {
// // some frameworks will extend built-in types using a __ prefix
// // these should always be safe to ignore.
// return js.Intercepted.no;
// }
if (std.mem.startsWith(u8, property, "jQuery")) {
return js.Intercepted.no;
}
// if (std.mem.startsWith(u8, property, "jQuery")) {
// return js.Intercepted.no;
// }
if (JsApi == @import("../webapi/cdata/Text.zig").JsApi or JsApi == @import("../webapi/cdata/Comment.zig").JsApi) {
if (std.mem.eql(u8, property, "tagName")) {
// knockout does this, a lot.
return js.Intercepted.no;
}
}
// if (JsApi == @import("../webapi/cdata/Text.zig").JsApi or JsApi == @import("../webapi/cdata/Comment.zig").JsApi) {
// if (std.mem.eql(u8, property, "tagName")) {
// // knockout does this, a lot.
// return js.Intercepted.no;
// }
// }
if (JsApi == @import("../webapi/element/Html.zig").JsApi or JsApi == @import("../webapi/Element.zig").JsApi or JsApi == @import("../webapi/element/html/Custom.zig").JsApi) {
// react ?
if (std.mem.eql(u8, property, "props")) return js.Intercepted.no;
if (std.mem.eql(u8, property, "hydrated")) return js.Intercepted.no;
if (std.mem.eql(u8, property, "isHydrated")) return js.Intercepted.no;
}
// if (JsApi == @import("../webapi/element/Html.zig").JsApi or JsApi == @import("../webapi/Element.zig").JsApi or JsApi == @import("../webapi/element/html/Custom.zig").JsApi) {
// // react ?
// if (std.mem.eql(u8, property, "props")) return js.Intercepted.no;
// if (std.mem.eql(u8, property, "hydrated")) return js.Intercepted.no;
// if (std.mem.eql(u8, property, "isHydrated")) return js.Intercepted.no;
// }
if (JsApi == @import("../webapi/Console.zig").JsApi) {
if (std.mem.eql(u8, property, "firebug")) return js.Intercepted.no;
}
// if (JsApi == @import("../webapi/Console.zig").JsApi) {
// if (std.mem.eql(u8, property, "firebug")) return js.Intercepted.no;
// }
const ignored = std.StaticStringMap(void).initComptime(.{});
if (!ignored.has(property)) {
var buf: [2048]u8 = undefined;
const key = std.fmt.bufPrint(&buf, "{s}:{s}", .{ if (@hasDecl(JsApi.Meta, "name")) JsApi.Meta.name else @typeName(JsApi), property }) catch return js.Intercepted.no;
logUnknownProperty(local, key) catch return js.Intercepted.no;
}
return js.Intercepted.no;
}
}.wrap;
}
// const ignored = std.StaticStringMap(void).initComptime(.{});
// if (!ignored.has(property)) {
// var buf: [2048]u8 = undefined;
// const key = std.fmt.bufPrint(&buf, "{s}:{s}", .{ if (@hasDecl(JsApi.Meta, "name")) JsApi.Meta.name else @typeName(JsApi), property }) catch return js.Intercepted.no;
// logUnknownProperty(local, key) catch return js.Intercepted.no;
// }
// return js.Intercepted.no;
// }
// }.wrap;
// }
fn logUnknownProperty(local: *const js.Local, key: []const u8) !void {
const ctx = local.ctx;
const gop = try ctx.unknown_properties.getOrPut(ctx.arena.allocator(), key);
if (gop.found_existing) {
gop.value_ptr.count += 1;
} else {
gop.key_ptr.* = try ctx.arena.dupe(u8, key);
gop.value_ptr.* = .{
.count = 1,
.first_stack = try ctx.arena.dupe(u8, (try local.stackTrace()) orelse "???"),
};
}
}
// fn logUnknownProperty(local: *const js.Local, key: []const u8) !void {
// const ctx = local.ctx;
// const gop = try ctx.unknown_properties.getOrPut(ctx.arena.allocator(), key);
// if (gop.found_existing) {
// gop.value_ptr.count += 1;
// } else {
// gop.key_ptr.* = try ctx.arena.dupe(u8, key);
// gop.value_ptr.* = .{
// .count = 1,
// .first_stack = try ctx.arena.dupe(u8, (try local.stackTrace()) orelse "???"),
// };
// }
// }
// Given a Type, returns the length of the prototype chain, including self
fn prototypeChainLength(comptime T: type) usize {