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();
|
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 {
|
export fn haku2_vm_stackframe_is_system(vm: *const Vm, index: usize) bool {
|
||||||
const stack_frame = vm.stackFrame(index);
|
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 {
|
export fn haku2_vm_stackframe_pc(vm: *const Vm, index: usize) i32 {
|
||||||
const stack_frame = vm.stackFrame(index);
|
const stack_frame = vm.stackFrame(index);
|
||||||
if (stack_frame.closure.impl == .bytecode)
|
if (stack_frame.closure.?.impl == .bytecode)
|
||||||
if (stack_frame.ip) |ip|
|
if (stack_frame.ip) |ip|
|
||||||
return stack_frame.closure.programCounter(ip);
|
return stack_frame.closure.?.programCounter(ip);
|
||||||
return -1; // no return address
|
return -1; // no return address
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn haku2_vm_stackframe_function_name_len(vm: *const Vm, index: usize) usize {
|
export fn haku2_vm_stackframe_function_name_len(vm: *const Vm, index: usize) usize {
|
||||||
const stack_frame = vm.stackFrame(index);
|
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 {
|
export fn haku2_vm_stackframe_function_name(vm: *const Vm, index: usize) [*]const u8 {
|
||||||
const stack_frame = vm.stackFrame(index);
|
const stack_frame = vm.stackFrame(index);
|
||||||
return stack_frame.closure.name.ptr;
|
return stack_frame.closure.?.name.ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
|
|
|
@ -30,7 +30,7 @@ pub const Limits = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const CallFrame = struct {
|
pub const CallFrame = struct {
|
||||||
closure: *const value.Closure,
|
closure: ?*const value.Closure,
|
||||||
return_addr: ?[*]const u8,
|
return_addr: ?[*]const u8,
|
||||||
bottom: u32,
|
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.
|
// NOTE: Different from CallFrame, this is a helper type for obtaining stack traces.
|
||||||
pub const StackFrame = struct {
|
pub const StackFrame = struct {
|
||||||
closure: *const value.Closure,
|
closure: ?*const value.Closure,
|
||||||
ip: ?[*]const u8,
|
ip: ?[*]const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -117,7 +117,17 @@ pub fn stackFrame(vm: *const Vm, index: usize) StackFrame {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return .{
|
return .{
|
||||||
.closure = closure,
|
.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 {
|
} else {
|
||||||
// NOTE: Minus two, because remember index == 0 is occupied by the current stack frame.
|
// NOTE: Minus two, because remember index == 0 is occupied by the current stack frame.
|
||||||
|
@ -269,7 +279,7 @@ pub fn run(
|
||||||
}
|
}
|
||||||
|
|
||||||
try vm.pushCall(.{
|
try vm.pushCall(.{
|
||||||
.closure = closure,
|
.closure = null,
|
||||||
.return_addr = null, // nowhere to return to
|
.return_addr = null, // nowhere to return to
|
||||||
.bottom = bottom,
|
.bottom = bottom,
|
||||||
});
|
});
|
||||||
|
@ -591,7 +601,7 @@ pub fn run(
|
||||||
try vm.push(result);
|
try vm.push(result);
|
||||||
|
|
||||||
if (call_frame.return_addr) |addr| {
|
if (call_frame.return_addr) |addr| {
|
||||||
closure = call_frame.closure;
|
closure = call_frame.closure.?;
|
||||||
ip = addr;
|
ip = addr;
|
||||||
bottom = call_frame.bottom;
|
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];
|
let frame = this.result.stackTrace[i];
|
||||||
if (frame.span != null) {
|
if (frame.span != null) {
|
||||||
diagnostics.push({
|
diagnostics.push({
|
||||||
|
|
|
@ -336,6 +336,12 @@ export class Haku {
|
||||||
let count = w2.haku2_vm_stackframe_count(this.#pVm2);
|
let count = w2.haku2_vm_stackframe_count(this.#pVm2);
|
||||||
let trace = [];
|
let trace = [];
|
||||||
for (let i = 0; i < count; ++i) {
|
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 isSystem = w2.haku2_vm_stackframe_is_system(this.#pVm2, i) != 0;
|
||||||
let pc = w2.haku2_vm_stackframe_pc(this.#pVm2, i);
|
let pc = w2.haku2_vm_stackframe_pc(this.#pVm2, i);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue