~sircmpwn/hare

6af48ef20993df64e67902b0e1c3090b4a1ae8c7 — Sebastian 3 months ago f4cc258
rt: simplify frame-walking functions

This simplifies the implementation, changes the interface of nextframe
to return a frame rather than a tagged union (so on aarch64 it fits
within two registers), makes the address in the frame nullable (to
account for what was previously a void result to nextframe), and makes
the docs consistent across all architectures.

Signed-off-by: Sebastian <sebastian@sebsite.pw>
3 files changed, 25 insertions(+), 55 deletions(-)

M rt/+aarch64/backtrace.ha
M rt/+riscv64/backtrace.ha
M rt/+x86_64/backtrace.ha
M rt/+aarch64/backtrace.ha => rt/+aarch64/backtrace.ha +7 -13
@@ 1,24 1,18 @@
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>

fn getfp() **opaque;
fn getfp() *frame;

// Details for a stack frame. Contents are architecture-specific.
// Details for a stack frame. A null address indicates that you've reached the
// top of the stack. Contents are architecture-specific.
export type frame = struct {
	fp: nullable *frame,
	lr: nullable *opaque,
};

// Returns the caller's stack frame. Call [[nextframe]] to walk the stack.
export fn backtrace() frame = *(getfp(): *frame);

// Returns the frame above the current frame, if any.
export fn nextframe(fp: *frame) (frame | void) = {
	return match (fp.fp) {
	case null =>
		yield void;
	case let fp: *frame =>
		yield *fp;
	};
};
export fn backtrace() frame = *getfp();

// Returns the frame above the current frame. The current frame must contain a
// non-nullable address.
export fn nextframe(sframe: frame) frame = *(sframe.fp as *frame);

M rt/+riscv64/backtrace.ha => rt/+riscv64/backtrace.ha +9 -21
@@ 1,29 1,17 @@
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>

fn getfp() **opaque;
fn getfp() *frame;

// Details for a stack frame. Contents are architecture-specific.
// Details for a stack frame. A null address indicates that you've reached the
// top of the stack. Contents are architecture-specific.
export type frame = struct {
	addr: *opaque
	addr: nullable *frame,
};

// Returns the current stack frame. See [[nextframe]] to walk the stack.
export fn backtrace() frame = {
	let fp = frame {
		addr = getfp()
	};
	// Skip the call to backtrace itself
	return nextframe(fp) as frame;
};
// Returns the caller's stack frame. Call [[nextframe]] to walk the stack.
export fn backtrace() frame = *getfp();

// Returns the frame above the current frame, if any.
export fn nextframe(sframe: frame) (frame | void) = {
	let addr = sframe.addr: *nullable *opaque;
	match (*addr) {
	case null =>
		return;
	case let a: *opaque =>
		return frame { addr = a };
	};
};
// Returns the frame above the current frame. The current frame must contain a
// non-nullable address.
export fn nextframe(sframe: frame) frame = *(sframe.addr as *frame);

M rt/+x86_64/backtrace.ha => rt/+x86_64/backtrace.ha +9 -21
@@ 1,29 1,17 @@
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>

fn getfp() **opaque;
fn getfp() *frame;

// Details for a stack frame. Contents are architecture-specific.
// Details for a stack frame. A null address indicates that you've reached the
// top of the stack. Contents are architecture-specific.
export type frame = struct {
	addr: *opaque
	addr: nullable *frame,
};

// Returns the current stack frame. See [[nextframe]] to walk the stack.
export fn backtrace() frame = {
	let fp = frame {
		addr = getfp()
	};
	// Skip the call to backtrace itself
	return nextframe(fp) as frame;
};
// Returns the caller's stack frame. Call [[nextframe]] to walk the stack.
export fn backtrace() frame = *getfp();

// Returns the frame above the current frame, if any.
export fn nextframe(sframe: frame) (frame | void) = {
	let addr = sframe.addr: *nullable *opaque;
	match (*addr) {
	case let a: *opaque =>
		return frame { addr = a };
	case null =>
		return;
	};
};
// Returns the frame above the current frame. The current frame must contain a
// non-nullable address.
export fn nextframe(sframe: frame) frame = *(sframe.addr as *frame);