hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit 3dd966977c33a89c9bb85662a4e131f892125d9b
parent ed9142ac20ea3f6bed3bc6d6f78acca6d82f7ec3
Author: Drew DeVault <sir@cmpwn.com>
Date:   Wed,  1 Jan 2025 20:00:58 +0100

rt: add heap management utilities

This allows modules like debug:: to use a dedicated heap, so that they
can have access to alloc/insert/etc and work reliably when providing
debugging tools for misbehaving programs which might have, for example,
trashed the default heap.

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Mdebug/abort.ha | 2++
Mdebug/fault.ha | 2+-
Adebug/malloc+libc.ha | 16++++++++++++++++
Adebug/malloc.ha | 26++++++++++++++++++++++++++
Mdebug/traces.ha | 3+++
Mmakefiles/freebsd.aarch64.mk | 2+-
Mmakefiles/freebsd.riscv64.mk | 2+-
Mmakefiles/freebsd.x86_64.mk | 2+-
Mmakefiles/linux.aarch64.mk | 2+-
Mmakefiles/linux.riscv64.mk | 2+-
Mmakefiles/linux.x86_64.mk | 2+-
Mmakefiles/netbsd.aarch64.mk | 2+-
Mmakefiles/netbsd.riscv64.mk | 2+-
Mmakefiles/netbsd.x86_64.mk | 2+-
Art/heap-libc.ha | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mrt/malloc.ha | 50--------------------------------------------------
16 files changed, 113 insertions(+), 60 deletions(-)

diff --git a/debug/abort.ha b/debug/abort.ha @@ -16,6 +16,8 @@ fn debug_abort( col: u64, msg: str, ) never = { + begin_fatal(); + fmt::errorfln("Abort: {}:{}:{}: {}", *path, line, col, msg): void; const self = match (image::self()) { diff --git a/debug/fault.ha b/debug/fault.ha @@ -26,7 +26,7 @@ def ALTSTACK_SIZE: size = 16384; }; fn signal_handler(sig: sig, info: *signal::siginfo, uctx: *opaque) void = { - signal::resetall(); + begin_fatal(); const ip = uctx_ip(uctx); const sp = uctx_sp(uctx); diff --git a/debug/malloc+libc.ha b/debug/malloc+libc.ha @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use unix::signal; + +fn begin_fatal() void = { + signal::resetall(); +}; + +fn begin_altheap() nullable *opaque = { + return null; // no-op on +libc +}; + +fn end_altheap(restore: nullable *opaque) void = { + void; // no-op on +libc +}; diff --git a/debug/malloc.ha b/debug/malloc.ha @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use rt; +use unix::signal; + +let heap = rt::EMPTY_HEAP; + +// Reconfigure the process to handle a fatal condition, such as a segfault, as +// safely as possible. Resets all signals (in case of faults in debug::) and +// configures the runtime to use the debug heap (in case of heap overflow or +// similar faults in the user program). +fn begin_fatal() void = { + signal::resetall(); + rt::setheap(&heap); +}; + +// Enables the debug:: heap. +fn begin_altheap() *rt::memory_heap = { + return rt::setheap(&heap); +}; + +// Restores the original heap corresponding to [[begin_altheap]]. +fn end_altheap(restore: *rt::memory_heap) void = { + rt::setheap(restore); +}; diff --git a/debug/traces.ha b/debug/traces.ha @@ -30,6 +30,9 @@ export fn trace_store(frame: stackframe) u64 = { static let pc: []uintptr = []; pc = pc[..0]; + const prev_heap = begin_altheap(); + defer end_altheap(prev_heap); + const hash = fnv::fnv64a(); for (true) { hash::write(&hash, &frame_pc(frame): *[size(uintptr)]u8); diff --git a/makefiles/freebsd.aarch64.mk b/makefiles/freebsd.aarch64.mk @@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA RTSCRIPT = rt/+freebsd/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o -rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+freebsd/+aarch64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha +rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+freebsd/+aarch64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" diff --git a/makefiles/freebsd.riscv64.mk b/makefiles/freebsd.riscv64.mk @@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA RTSCRIPT = rt/+freebsd/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o -rt_ha = rt/+freebsd/+riscv64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha +rt_ha = rt/+freebsd/+riscv64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" diff --git a/makefiles/freebsd.x86_64.mk b/makefiles/freebsd.x86_64.mk @@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA RTSCRIPT = rt/+freebsd/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o -rt_ha = rt/+freebsd/+x86_64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha +rt_ha = rt/+freebsd/+x86_64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" diff --git a/makefiles/linux.aarch64.mk b/makefiles/linux.aarch64.mk @@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA RTSCRIPT = rt/+linux/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/format_elf.o $(HARECACHE)/linux.o $(HARECACHE)/types_c.o $(HARECACHE)/linux_vdso.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o -rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+linux/+aarch64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+aarch64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha +rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+linux/+aarch64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+aarch64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" diff --git a/makefiles/linux.riscv64.mk b/makefiles/linux.riscv64.mk @@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA RTSCRIPT = rt/+linux/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/format_elf.o $(HARECACHE)/linux.o $(HARECACHE)/types_c.o $(HARECACHE)/linux_vdso.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o -rt_ha = rt/+linux/+riscv64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+riscv64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha +rt_ha = rt/+linux/+riscv64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+riscv64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" diff --git a/makefiles/linux.x86_64.mk b/makefiles/linux.x86_64.mk @@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA RTSCRIPT = rt/+linux/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/format_elf.o $(HARECACHE)/linux.o $(HARECACHE)/types_c.o $(HARECACHE)/linux_vdso.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o -rt_ha = rt/+linux/+x86_64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+x86_64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha +rt_ha = rt/+linux/+x86_64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+x86_64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" diff --git a/makefiles/netbsd.aarch64.mk b/makefiles/netbsd.aarch64.mk @@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA RTSCRIPT = rt/+netbsd/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o -rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha +rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" diff --git a/makefiles/netbsd.riscv64.mk b/makefiles/netbsd.riscv64.mk @@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA RTSCRIPT = rt/+netbsd/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o -rt_ha = rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha +rt_ha = rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" diff --git a/makefiles/netbsd.x86_64.mk b/makefiles/netbsd.x86_64.mk @@ -4,7 +4,7 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_types=$(HARECACHE)/types.td HA RTSCRIPT = rt/+netbsd/hare.sc OBJS = $(HARECACHE)/rt.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o -rt_ha = rt/+netbsd/+x86_64.ha rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha +rt_ha = rt/+netbsd/+x86_64.ha rt/+netbsd/env.ha rt/+netbsd/errno.ha rt/+netbsd/initfini.ha rt/+netbsd/platform_abort.ha rt/+netbsd/platformstart-libc.ha rt/+netbsd/segmalloc.ha rt/+netbsd/signal.ha rt/+netbsd/socket.ha rt/+netbsd/start.ha rt/+netbsd/syscallno.ha rt/+netbsd/syscalls.ha rt/+netbsd/sysctl.ha rt/+netbsd/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/heap-libc.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha $(HARECACHE)/rt.ssa: $(rt_ha) @mkdir -p -- "$(HARECACHE)" @printf 'HAREC\t%s\n' "$@" diff --git a/rt/heap-libc.ha b/rt/heap-libc.ha @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +// A group of blocks that were allocated together. +export type chunk = union { + padding: size, // TODO: track number of active allocations here + data: [*]u8, +}; + +// Metadata for a block. +export type meta = struct { + union { + sz: size, + next: uintptr, + }, + user: [*]u8, +}; + +export type memory_heap = struct { + // Number of allocations currently in flight. + cur_allocs: size, + // Freelists for blocks up to 2048 bytes. + bins: [9]nullable *meta, + // The chunk to allocate from if there are no blocks available in the + // right freelist. + cur_chunk: (*chunk, size), +}; + +// An empty memory heap, used to initialize a [[memory_heap]] for use with +// [[setheap]]. +export def EMPTY_HEAP = memory_heap { + cur_allocs = 0, + bins = [null...], + cur_chunk = (null: *chunk, CHUNKSZ), +}; + +let static_heap = EMPTY_HEAP; +let heap = &static_heap; + +// Switches the internal runtime allocator to a new memory heap. The caller +// should provision a [[memory_heap]] initialized to [[EMPTY_HEAP]] somehow +// (statically, or in a second memory_heap, or even on the stack if you're brave +// enough) and pass it to this function to enable it. Returns a pointer to the +// heap which was previously in use, should you wish to restore it later. +// +// The caller is responsible for ensuring that any use of free() or delete() +// makes use of an object which was allocated (via alloc(), insert(), or +// append()) from the same heap. +// +// This function is designed for debugging use, and exists in particular to +// satisfy the needs of [[debug::]]. +export fn setheap(new_heap: *memory_heap) *memory_heap = { + const old = heap; + heap = new_heap; + return old; +}; diff --git a/rt/malloc.ha b/rt/malloc.ha @@ -5,21 +5,6 @@ // Appel, Andrew W., and David A. Naumann. "Verified sequential malloc/free" // but with logarithmic bin sizing and additional safety checks. Not thread-safe -// A group of blocks that were allocated together. -export type chunk = union { - padding: size, // TODO: track number of active allocations here - data: [*]u8, -}; - -// Metadata for a block. -export type meta = struct { - union { - sz: size, - next: uintptr, - }, - user: [*]u8, -}; - // Size of the header/footer for allocations. def META: size = size(size); @@ -37,41 +22,6 @@ def CHUNKSZ: size = 1 << 21; // Byte to fill allocations with while they're not in use. def POISON: u8 = 0x69; -export type memory_heap = struct { - // Number of allocations currently in flight. - cur_allocs: size, - // Freelists for blocks up to 2048 bytes. - bins: [9]nullable *meta, - // The chunk to allocate from if there are no blocks available in the - // right freelist. - cur_chunk: (*chunk, size), -}; - -let static_heap = memory_heap { - cur_allocs = 0, - bins = [null...], - cur_chunk = (null: *chunk, CHUNKSZ), -}; - -let heap = &static_heap; - -export fn newheap() memory_heap = { - // Re-initializes the heap from scratch, abandoning all prior memory - // allocations and returning the previous heap. - // - // This function is designed to be called by debug:: in a scenario where - // the heap has been corrupted. It abandons the corrupt heap and - // prepares a fresh heap which debug:: can use to allocate memory for - // any operations it needs to perform during clean-up. - const old = *heap; - *heap = memory_heap { - cur_allocs = 0, - bins = [null...], - cur_chunk = (null: *chunk, CHUNKSZ), - }; - return old; -}; - // Allocates n bytes of memory and returns a pointer to them, or null if there // is insufficient memory. export fn malloc(n: size) nullable *opaque = {