fix some rough edges around stack traces
hide irrelevant CallFrames fix span info for the implicit stack frame
This commit is contained in:
parent
e49885c83a
commit
7a52dbebd0
4 changed files with 34 additions and 11 deletions
|
@ -196,27 +196,32 @@ export fn haku2_vm_stackframe_count(vm: *const Vm) usize {
|
|||
return vm.stackFrameCount();
|
||||
}
|
||||
|
||||
export fn haku2_vm_stackframe_is_return_marker(vm: *const Vm, index: usize) bool {
|
||||
const stack_frame = vm.stackFrame(index);
|
||||
return stack_frame.closure == null;
|
||||
}
|
||||
|
||||
export fn haku2_vm_stackframe_is_system(vm: *const Vm, index: usize) bool {
|
||||
const stack_frame = vm.stackFrame(index);
|
||||
return stack_frame.closure.impl == .system;
|
||||
return stack_frame.closure.?.impl == .system;
|
||||
}
|
||||
|
||||
export fn haku2_vm_stackframe_pc(vm: *const Vm, index: usize) i32 {
|
||||
const stack_frame = vm.stackFrame(index);
|
||||
if (stack_frame.closure.impl == .bytecode)
|
||||
if (stack_frame.closure.?.impl == .bytecode)
|
||||
if (stack_frame.ip) |ip|
|
||||
return stack_frame.closure.programCounter(ip);
|
||||
return stack_frame.closure.?.programCounter(ip);
|
||||
return -1; // no return address
|
||||
}
|
||||
|
||||
export fn haku2_vm_stackframe_function_name_len(vm: *const Vm, index: usize) usize {
|
||||
const stack_frame = vm.stackFrame(index);
|
||||
return stack_frame.closure.name.len;
|
||||
return stack_frame.closure.?.name.len;
|
||||
}
|
||||
|
||||
export fn haku2_vm_stackframe_function_name(vm: *const Vm, index: usize) [*]const u8 {
|
||||
const stack_frame = vm.stackFrame(index);
|
||||
return stack_frame.closure.name.ptr;
|
||||
return stack_frame.closure.?.name.ptr;
|
||||
}
|
||||
|
||||
// Renderer
|
||||
|
|
|
@ -30,7 +30,7 @@ pub const Limits = struct {
|
|||
};
|
||||
|
||||
pub const CallFrame = struct {
|
||||
closure: *const value.Closure,
|
||||
closure: ?*const value.Closure,
|
||||
return_addr: ?[*]const u8,
|
||||
bottom: u32,
|
||||
};
|
||||
|
@ -100,7 +100,7 @@ pub fn outOfMemory(vm: *Vm) Error {
|
|||
|
||||
// NOTE: Different from CallFrame, this is a helper type for obtaining stack traces.
|
||||
pub const StackFrame = struct {
|
||||
closure: *const value.Closure,
|
||||
closure: ?*const value.Closure,
|
||||
ip: ?[*]const u8,
|
||||
};
|
||||
|
||||
|
@ -117,7 +117,17 @@ pub fn stackFrame(vm: *const Vm, index: usize) StackFrame {
|
|||
if (index == 0) {
|
||||
return .{
|
||||
.closure = closure,
|
||||
.ip = vm.ip,
|
||||
// Span info hairiness:
|
||||
// Because call frames place the instruction pointer past the call instruction,
|
||||
// the frontend subtracts 1 from it to get a position within the chunk that
|
||||
// has the correct line info.
|
||||
// This subtracting by one doesn't work for the implicit stack frame though, because
|
||||
// its ip gets updated at the _start_ of the instruction---meaning that if you
|
||||
// subtract one from it, it'll point to the _previous_ instruction, while the actual
|
||||
// error occurred in the current one.
|
||||
// To alleviate this, add one here to point to either the middle or the end of the
|
||||
// current instruction.
|
||||
.ip = if (vm.ip) |ip| ip + 1 else null,
|
||||
};
|
||||
} else {
|
||||
// NOTE: Minus two, because remember index == 0 is occupied by the current stack frame.
|
||||
|
@ -269,7 +279,7 @@ pub fn run(
|
|||
}
|
||||
|
||||
try vm.pushCall(.{
|
||||
.closure = closure,
|
||||
.closure = null,
|
||||
.return_addr = null, // nowhere to return to
|
||||
.bottom = bottom,
|
||||
});
|
||||
|
@ -591,7 +601,7 @@ pub fn run(
|
|||
try vm.push(result);
|
||||
|
||||
if (call_frame.return_addr) |addr| {
|
||||
closure = call_frame.closure;
|
||||
closure = call_frame.closure.?;
|
||||
ip = addr;
|
||||
bottom = call_frame.bottom;
|
||||
|
||||
|
|
|
@ -280,7 +280,9 @@ class ErrorException extends HTMLElement {
|
|||
}
|
||||
};
|
||||
|
||||
for (let i = 0; i < this.result.stackTrace.length; ++i) {
|
||||
// Iterate in reverse to let uppermost stack frames "win" and overwrite bottommost stack
|
||||
// frames' colouring.
|
||||
for (let i = this.result.stackTrace.length - 1; i >= 0; i--) {
|
||||
let frame = this.result.stackTrace[i];
|
||||
if (frame.span != null) {
|
||||
diagnostics.push({
|
||||
|
|
|
@ -336,6 +336,12 @@ export class Haku {
|
|||
let count = w2.haku2_vm_stackframe_count(this.#pVm2);
|
||||
let trace = [];
|
||||
for (let i = 0; i < count; ++i) {
|
||||
// Don't collect information about return marker stack frames.
|
||||
// They don't actually represent function calls, they're only used to signal the .ret
|
||||
// instruction at which the VM ought to halt.
|
||||
let isReturnMarker = w2.haku2_vm_stackframe_is_return_marker(this.#pVm2, i) != 0;
|
||||
if (isReturnMarker) continue;
|
||||
|
||||
let isSystem = w2.haku2_vm_stackframe_is_system(this.#pVm2, i) != 0;
|
||||
let pc = w2.haku2_vm_stackframe_pc(this.#pVm2, i);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue