From 0ac575db85ed99404d460b0a87438356cae15d7c Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Tue, 17 Feb 2026 00:28:10 -0600 Subject: [PATCH] fix package bug, improve stack trace --- CLAUDE.md | 4 +- Makefile | 97 +++++++++---------------------------- cell.toml | 15 ++---- editors/vscode/package.json | 1 + package.cm | 2 +- source/mach.c | 34 +++++++------ 6 files changed, 50 insertions(+), 103 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 7a5adfd2..4bff8a87 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,8 +2,8 @@ ## Building -Recompile after changes: `make` -Bootstrap from scratch (first time): `make bootstrap` +Build (or rebuild after changes): `make` +Install to system: `make install` Run `cell --help` to see all CLI flags. ## Code Style diff --git a/Makefile b/Makefile index f0417fc8..4dc24953 100755 --- a/Makefile +++ b/Makefile @@ -1,83 +1,30 @@ -# Development build: creates libcell_runtime.dylib + thin main wrapper -# This is the default target for working on cell itself -# -# If cell doesn't exist yet, use 'make bootstrap' first (requires meson) -# or manually build with meson once. -# -# The cell shop is at ~/.cell and core scripts are installed to ~/.cell/core +BUILD = build +INSTALL_BIN = /opt/homebrew/bin +INSTALL_LIB = /opt/homebrew/lib +INSTALL_INC = /opt/homebrew/include +CELL_SHOP = $(HOME)/.cell -CELL_SHOP = $(HOME)/.cell -CELL_CORE_PACKAGE = $(CELL_SHOP)/packages/core +all: $(BUILD)/build.ninja + meson compile -C $(BUILD) + cp $(BUILD)/libcell_runtime.dylib . + cp $(BUILD)/cell . -doit: bootstrap +$(BUILD)/build.ninja: + meson setup $(BUILD) -Dbuildtype=debugoptimized -maker: install +install: all $(CELL_SHOP) + cp cell $(INSTALL_BIN)/cell + cp libcell_runtime.dylib $(INSTALL_LIB)/ + cp source/cell.h source/quickjs.h source/wota.h $(INSTALL_INC)/ + rm -rf $(CELL_SHOP)/packages/core + ln -s $(CURDIR) $(CELL_SHOP)/packages/core + @echo "Installed cell to $(INSTALL_BIN) and $(INSTALL_LIB)" -makecell: - cell pack core -o cell - cp cell /opt/homebrew/bin/ - -# Install core: symlink this directory to ~/.cell/core -install: cell $(CELL_SHOP) - @echo "Linking cell core to $(CELL_CORE_PACKAGE)" - rm -rf $(CELL_CORE_PACKAGE) - ln -s $(PWD) $(CELL_CORE_PACKAGE) - cp cell /opt/homebrew/bin/ - cp libcell_runtime.dylib /opt/homebrew/lib/ - @echo "Core installed." - -cell: libcell_runtime.dylib cell_main - cp cell_main cell - chmod +x cell - cp cell /opt/homebrew/bin/cell - cp libcell_runtime.dylib /opt/homebrew/lib/ - -# Build the shared runtime library (everything except main.c) -# Uses existing cell to run build -d -libcell_runtime.dylib: $(CELL_SHOP)/build/dynamic - cell build -d - cp $(CELL_SHOP)/build/dynamic/libcell_runtime.dylib . - -# Build the thin main wrapper that links to libcell_runtime -cell_main: source/main.c libcell_runtime.dylib - cc -o cell_main source/main.c -L. -lcell_runtime -Wl,-rpath,@loader_path -Wl,-rpath,/opt/homebrew/lib - -# Create the cell shop directories $(CELL_SHOP): - mkdir -p $(CELL_SHOP) - mkdir -p $(CELL_SHOP)/packages - mkdir -p $(CELL_SHOP)/cache - mkdir -p $(CELL_SHOP)/build + mkdir -p $(CELL_SHOP)/packages $(CELL_SHOP)/cache $(CELL_SHOP)/build -$(CELL_CORE): - ln -s $(PWD) $(CELL_CORE) - -# Static build: creates a fully static cell binary (for distribution) -static: - cell build - cp $(CELL_SHOP)/build/static/cell . - -# Bootstrap: build cell from scratch using meson (only needed once) -# Also installs core scripts to ~/.cell/core -bootstrap: - meson setup build_bootstrap -Dbuildtype=debugoptimized - meson compile -C build_bootstrap - cp build_bootstrap/cell . - cp build_bootstrap/libcell_runtime.dylib . - @echo "Bootstrap complete. Run cell like ./cell --dev to use a local shop at .cell." - -# Clean build artifacts clean: - rm -rf $(CELL_SHOP)/build build_bootstrap - rm -f cell cell_main libcell_runtime.dylib + rm -rf $(BUILD) + rm -f cell libcell_runtime.dylib -# Ensure dynamic build directory exists -$(CELL_SHOP)/build/dynamic: $(CELL_SHOP) - mkdir -p $(CELL_SHOP)/build/dynamic - -# Legacy meson target -meson: - meson setup build_dbg -Dbuildtype=debugoptimized - meson install -C build_dbg - -.PHONY: cell static bootstrap clean meson install +.PHONY: all install clean diff --git a/cell.toml b/cell.toml index 56273e16..9cf8d5a7 100644 --- a/cell.toml +++ b/cell.toml @@ -1,13 +1,6 @@ +[dependencies] +cell-steam = "/Users/johnalanbrook/work/cell-steam" +cell-sdl3 = "/Users/johnalanbrook/work/cell-sdl3" [compilation] -CFLAGS = "-Isource -Wno-incompatible-pointer-types -Wno-missing-braces -Wno-strict-prototypes -Wno-unused-function -Wno-int-conversion" -LDFLAGS = "-lstdc++ -lm" - -[compilation.macos_arm64] -CFLAGS = "-x objective-c" -LDFLAGS = "-framework CoreFoundation -framework CFNetwork" - [compilation.playdate] -CFLAGS = "-DMINIZ_NO_TIME -DTARGET_EXTENSION -DTARGET_PLAYDATE -I$LOCAL/PlaydateSDK/C_API" - -[compilation.windows] -LDFLAGS = "-lws2_32 -lwinmm -liphlpapi -lbcrypt -lwinhttp -static-libgcc -static-libstdc++" +CFLAGS = "-DMINIZ_NO_TIME -DTARGET_EXTENSION -DTARGET_PLAYDATE -I$LOCAL/PlaydateSDK/C_API" \ No newline at end of file diff --git a/editors/vscode/package.json b/editors/vscode/package.json index 4b3e875b..babbd03d 100644 --- a/editors/vscode/package.json +++ b/editors/vscode/package.json @@ -56,6 +56,7 @@ "vscode-languageserver-protocol": "^3.17.0" }, "devDependencies": { + "@types/node": "^20.19.33", "@types/vscode": "^1.75.0", "typescript": "^5.0.0" } diff --git a/package.cm b/package.cm index 09bb96a0..5e74f7ce 100644 --- a/package.cm +++ b/package.cm @@ -75,7 +75,7 @@ package.load_config = function(name) package.save_config = function(name, config) { var config_path = get_path(name) + '/cell.toml' - fd.slurpwrite(config_path, utf8.encode(toml.encode(config))) + fd.slurpwrite(config_path, stone(blob(toml.encode(config)))) } package.dependencies = function(name) diff --git a/source/mach.c b/source/mach.c index fca17c28..e1c76fb1 100644 --- a/source/mach.c +++ b/source/mach.c @@ -2113,7 +2113,9 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, /* Search frame chain for a disruption handler. Use frame_pc to track each frame's execution point: - For the faulting frame, it's the current pc. - - For unwound caller frames, read from frame->address. */ + - For unwound caller frames, read from frame->address. + Keep frame_ref.val at the faulting frame and preserve caller + links so the trace walk can show the full call chain. */ frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); /* re-chase after GC */ { uint32_t frame_pc = pc; @@ -2125,28 +2127,34 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, env = fn->u.reg.env_record; pc = code->disruption_pc; ctx->disruption_reported = FALSE; + frame_ref.val = JS_MKPTR(frame); /* root handler frame for GC */ break; } if (JS_IsNull(frame->caller)) { if (!ctx->disruption_reported) { - const char *fn_name = code->name_cstr ? code->name_cstr : ""; - const char *file = code->filename_cstr ? code->filename_cstr : ""; + /* Use faulting frame (frame_ref.val) for the header */ + JSFrameRegister *fault = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); + JSFunction *fault_fn = JS_VALUE_GET_FUNCTION(fault->function); + JSCodeRegister *fault_code = fault_fn->u.reg.code; + const char *fn_name = fault_code->name_cstr ? fault_code->name_cstr : ""; + const char *file = fault_code->filename_cstr ? fault_code->filename_cstr : ""; uint16_t line = 0, col = 0; - if (code->line_table && frame_pc > 0 && frame_pc - 1 < code->instr_count) { - line = code->line_table[frame_pc - 1].line; - col = code->line_table[frame_pc - 1].col; + uint32_t fpc = pc > 0 ? pc - 1 : 0; + if (fault_code->line_table && fpc < fault_code->instr_count) { + line = fault_code->line_table[fpc].line; + col = fault_code->line_table[fpc].col; } fprintf(stderr, "unhandled disruption in %s (%s:%u:%u)\n", fn_name, file, line, col); - /* Walk and print the frame chain as a stack trace */ + /* Walk intact caller chain for stack trace */ { - JSFrameRegister *trace_frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); + JSFrameRegister *trace_frame = fault; int first = 1; while (trace_frame) { if (!mist_is_function(trace_frame->function)) break; JSFunction *trace_fn = JS_VALUE_GET_FUNCTION(trace_frame->function); if (trace_fn->kind == JS_FUNC_KIND_REGISTER && trace_fn->u.reg.code) { JSCodeRegister *tc = trace_fn->u.reg.code; - uint32_t tpc = first ? (frame_pc > 0 ? frame_pc - 1 : 0) + uint32_t tpc = first ? fpc : (uint32_t)(JS_VALUE_GET_INT(trace_frame->address) >> 16); uint16_t tl = 0, tcol = 0; if (tc->line_table && tpc < tc->instr_count) { @@ -2164,15 +2172,13 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, } ctx->disruption_reported = TRUE; } + frame_ref.val = JS_MKPTR(frame); /* update root for GC / done */ result = JS_Throw(ctx, JS_NULL); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); goto done; } - /* Unwind one frame — read caller's saved pc from its address field */ - JSFrameRegister *caller = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller); - frame->caller = JS_NULL; - frame = caller; - frame_ref.val = JS_MKPTR(frame); + /* Advance to caller — keep chain intact (no nulling caller links) */ + frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller); frame_pc = (uint32_t)(JS_VALUE_GET_INT(frame->address) >> 16); } }