haku2: VM logging

This commit is contained in:
りき萌 2025-06-11 10:43:22 +02:00
parent 5de4f9d7c6
commit 7658e0d4e8
5 changed files with 105 additions and 2 deletions

View file

@ -8,13 +8,21 @@ const render = @import("render.zig");
const Scratch = @import("scratch.zig");
const value = @import("value.zig");
const Vm = @import("vm.zig");
const log = @import("log.zig");
const allocator =
const vm_trace = true;
pub const allocator =
if (builtin.cpu.arch == .wasm32)
std.heap.wasm_allocator
else
@import("allocator.zig").hostAllocator;
pub const std_options: std.Options = .{
.log_level = if (vm_trace) .debug else .info,
.logFn = log.logFn,
};
// Scratch
export fn haku2_scratch_new(max: usize) ?*Scratch {

View file

@ -5,6 +5,7 @@ use std::{
marker::{PhantomData, PhantomPinned},
mem::forget,
ptr::{self, NonNull},
slice,
};
#[unsafe(no_mangle)]
@ -40,6 +41,54 @@ unsafe extern "C" fn __haku2_dealloc(ptr: *mut u8, size: usize, align: usize) {
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn __haku2_log_err(
scope: *const u8,
scope_len: usize,
msg: *const u8,
len: usize,
) {
let scope = String::from_utf8_lossy(slice::from_raw_parts(scope, scope_len));
let msg = String::from_utf8_lossy(slice::from_raw_parts(msg, len));
log::error!("{scope}: {msg}");
}
#[unsafe(no_mangle)]
unsafe extern "C" fn __haku2_log_warn(
scope: *const u8,
scope_len: usize,
msg: *const u8,
len: usize,
) {
let scope = String::from_utf8_lossy(slice::from_raw_parts(scope, scope_len));
let msg = String::from_utf8_lossy(slice::from_raw_parts(msg, len));
log::warn!("{scope}: {msg}");
}
#[unsafe(no_mangle)]
unsafe extern "C" fn __haku2_log_info(
scope: *const u8,
scope_len: usize,
msg: *const u8,
len: usize,
) {
let scope = String::from_utf8_lossy(slice::from_raw_parts(scope, scope_len));
let msg = String::from_utf8_lossy(slice::from_raw_parts(msg, len));
log::info!("{scope}: {msg}");
}
#[unsafe(no_mangle)]
unsafe extern "C" fn __haku2_log_debug(
scope: *const u8,
scope_len: usize,
msg: *const u8,
len: usize,
) {
let scope = String::from_utf8_lossy(slice::from_raw_parts(scope, scope_len));
let msg = String::from_utf8_lossy(slice::from_raw_parts(msg, len));
log::debug!("{scope}: {msg}");
}
#[repr(C)]
struct ScratchC {
_data: (),

42
crates/haku2/src/log.zig Normal file
View file

@ -0,0 +1,42 @@
const std = @import("std");
const log = std.log;
const root = @import("root");
pub fn logFn(
comptime level: log.Level,
comptime scope: @TypeOf(.enum_literal),
comptime fmt: []const u8,
args: anytype,
) void {
const stack_buf_size = 1024;
var stack_buf: [stack_buf_size]u8 = undefined;
var heap_buf: ?[]u8 = null;
// Tricky code ahead: when the heap allocation fails, we still want to fall back to
// logging _something_.
const len: usize = @truncate(std.fmt.count(fmt, args));
if (len > stack_buf_size) {
heap_buf = root.allocator.alloc(u8, len) catch null;
}
defer if (heap_buf) |buf| {
root.allocator.free(buf);
};
const buf: []u8 = if (heap_buf) |b| b else stack_buf[0..len];
const msg = std.fmt.bufPrint(buf, fmt, args) catch buf[0..len]; // no space? yeah whatever print as much as you can
const scope_name = @tagName(scope);
switch (level) {
.err => __haku2_log_err(scope_name.ptr, scope_name.len, msg.ptr, msg.len),
.warn => __haku2_log_warn(scope_name.ptr, scope_name.len, msg.ptr, msg.len),
.info => __haku2_log_info(scope_name.ptr, scope_name.len, msg.ptr, msg.len),
.debug => __haku2_log_debug(scope_name.ptr, scope_name.len, msg.ptr, msg.len),
}
}
extern fn __haku2_log_err(scope: [*]const u8, scope_len: usize, msg: [*]const u8, len: usize) void;
extern fn __haku2_log_warn(scope: [*]const u8, scope_len: usize, msg: [*]const u8, len: usize) void;
extern fn __haku2_log_info(scope: [*]const u8, scope_len: usize, msg: [*]const u8, len: usize) void;
extern fn __haku2_log_debug(scope: [*]const u8, scope_len: usize, msg: [*]const u8, len: usize) void;

View file

@ -1,6 +1,7 @@
const std = @import("std");
const mem = std.mem;
const debug = std.debug;
const log = std.log;
const testAllocator = std.testing.allocator;
const bytecode = @import("bytecode.zig");
@ -54,6 +55,8 @@ pub fn init(a: mem.Allocator, defs: *const bytecode.Defs, limits: *const Limits)
}
pub fn throw(vm: *Vm, comptime fmt: []const u8, args: anytype) Error {
log.debug("throw: fmt={s}", .{fmt});
const Args = @TypeOf(args);
const max_args_size = @sizeOf(@TypeOf(vm.exception.?.args));
if (@sizeOf(Args) > max_args_size) {
@ -75,6 +78,7 @@ pub fn throw(vm: *Vm, comptime fmt: []const u8, args: anytype) Error {
.args = undefined,
};
@memcpy(exn.args[0..@sizeOf(Args)], mem.asBytes(&args));
vm.exception = exn;
return error.Exception;
}

View file

@ -574,7 +574,7 @@ fn jumpstart_trampoline<'a>(
fn jumpstart_trampoline2(haku: &mut Haku) {
if !haku.has_cont2() {
if let Err(e) = haku.eval_brush2() {
error!("eval_brush2: {e}");
error!("eval_brush2: {e:?}");
}
}
}