diff options
Diffstat (limited to 'lib/fuzzer')
| -rw-r--r-- | lib/fuzzer/index.html | 8 | ||||
| -rw-r--r-- | lib/fuzzer/main.js | 28 | ||||
| -rw-r--r-- | lib/fuzzer/wasm/main.zig | 61 |
3 files changed, 88 insertions, 9 deletions
diff --git a/lib/fuzzer/index.html b/lib/fuzzer/index.html index 7142bf3437..0f62f58e6d 100644 --- a/lib/fuzzer/index.html +++ b/lib/fuzzer/index.html @@ -52,6 +52,14 @@ cursor: default; } + .l { + display: inline-block; + background: white; + width: 1em; + height: 1em; + border-radius: 1em; + } + .tok-kw { color: #333; font-weight: bold; diff --git a/lib/fuzzer/main.js b/lib/fuzzer/main.js index 040aeeb6c4..42bd72cef5 100644 --- a/lib/fuzzer/main.js +++ b/lib/fuzzer/main.js @@ -33,7 +33,7 @@ throw new Error("panic: " + msg); }, emitSourceIndexChange: onSourceIndexChange, - emitCoverageUpdate: renderStats, + emitCoverageUpdate: onCoverageUpdate, emitEntryPointsUpdate: renderStats, }, }).then(function(obj) { @@ -112,7 +112,7 @@ } function onWebSocketOpen() { - console.log("web socket opened"); + //console.log("web socket opened"); } function onWebSocketMessage(ev) { @@ -141,6 +141,11 @@ if (curNavLocation != null) renderSource(curNavLocation); } + function onCoverageUpdate() { + renderStats(); + renderCoverage(); + } + function render() { domStatus.classList.add("hidden"); } @@ -166,6 +171,15 @@ domSectStats.classList.remove("hidden"); } + function renderCoverage() { + for (let i = 0; i < domSourceText.children.length; i += 1) { + const childDom = domSourceText.children[i]; + if (childDom.id != null && childDom.id[0] == "l") { + childDom.classList.add("l"); + } + } + } + function resizeDomList(listDom, desiredLen, templateHtml) { for (let i = listDom.childElementCount; i < desiredLen; i += 1) { listDom.insertAdjacentHTML('beforeend', templateHtml); @@ -190,12 +204,10 @@ domSectSource.classList.remove("hidden"); const slDom = document.getElementById("l" + sourceLocationIndex); - if (slDom != null) { - slDom.scrollIntoView({ - behavior: "smooth", - block: "center", - }); - } + slDom.scrollIntoView({ + behavior: "smooth", + block: "center", + }); } function decodeString(ptr, len) { diff --git a/lib/fuzzer/wasm/main.zig b/lib/fuzzer/wasm/main.zig index 5859a0ca0e..5d8edf768a 100644 --- a/lib/fuzzer/wasm/main.zig +++ b/lib/fuzzer/wasm/main.zig @@ -280,12 +280,71 @@ const SourceLocationIndex = enum(u32) { ) error{ OutOfMemory, SourceUnavailable }!void { const walk_file_index = sli.toWalkFile() orelse return error.SourceUnavailable; const root_node = walk_file_index.findRootDecl().get().ast_node; - html_render.fileSourceHtml(walk_file_index, out, root_node, .{}) catch |err| { + var annotations: std.ArrayListUnmanaged(html_render.Annotation) = .{}; + defer annotations.deinit(gpa); + try computeSourceAnnotations(sli.ptr().file, walk_file_index, &annotations, coverage_source_locations.items); + html_render.fileSourceHtml(walk_file_index, out, root_node, .{ + .source_location_annotations = annotations.items, + }) catch |err| { fatal("unable to render source: {s}", .{@errorName(err)}); }; } }; +fn computeSourceAnnotations( + cov_file_index: Coverage.File.Index, + walk_file_index: Walk.File.Index, + annotations: *std.ArrayListUnmanaged(html_render.Annotation), + source_locations: []const Coverage.SourceLocation, +) !void { + // Collect all the source locations from only this file into this array + // first, then sort by line, col, so that we can collect annotations with + // O(N) time complexity. + var locs: std.ArrayListUnmanaged(SourceLocationIndex) = .{}; + defer locs.deinit(gpa); + + for (source_locations, 0..) |sl, sli_usize| { + if (sl.file != cov_file_index) continue; + const sli: SourceLocationIndex = @enumFromInt(sli_usize); + try locs.append(gpa, sli); + } + + std.mem.sortUnstable(SourceLocationIndex, locs.items, {}, struct { + pub fn lessThan(context: void, lhs: SourceLocationIndex, rhs: SourceLocationIndex) bool { + _ = context; + const lhs_ptr = lhs.ptr(); + const rhs_ptr = rhs.ptr(); + if (lhs_ptr.line < rhs_ptr.line) return true; + if (lhs_ptr.line > rhs_ptr.line) return false; + return lhs_ptr.column < rhs_ptr.column; + } + }.lessThan); + + const source = walk_file_index.get_ast().source; + var line: usize = 1; + var column: usize = 1; + var next_loc_index: usize = 0; + for (source, 0..) |byte, offset| { + if (byte == '\n') { + line += 1; + column = 1; + } else { + column += 1; + } + while (true) { + if (next_loc_index >= locs.items.len) return; + const next_sli = locs.items[next_loc_index]; + const next_sl = next_sli.ptr(); + if (next_sl.line > line or (next_sl.line == line and next_sl.column > column)) break; + try annotations.append(gpa, .{ + .file_byte_offset = offset, + .dom_id = @intFromEnum(next_sli), + }); + next_loc_index += 1; + } + } +} + var coverage = Coverage.init; /// Index of type `SourceLocationIndex`. var coverage_source_locations: std.ArrayListUnmanaged(Coverage.SourceLocation) = .{}; |
