optimize frames; remove trampoline

This commit is contained in:
2026-02-18 22:37:48 -06:00
parent 27ca008f18
commit e004b2c472
14 changed files with 318 additions and 91 deletions

View File

@@ -168,6 +168,9 @@ pit bench <suite> # run specific benchmark file
pit bench package <name> # benchmark a named package
pit bench package <name> <suite> # specific benchmark in a package
pit bench package all # benchmark all packages
pit bench --bytecode <suite> # force bytecode-only benchmark run
pit bench --native <suite> # force native-only benchmark run
pit bench --compare <suite> # run bytecode and native side-by-side
```
Output includes median, mean, standard deviation, and percentiles for each benchmark.

View File

@@ -37,7 +37,12 @@ On a cache miss, the C runtime loads `boot/bootstrap.cm.mcode` (a pre-compiled s
### Cache invalidation
All caching is content-addressed by BLAKE2 hash of the source. When any source file changes, its hash changes and the old cache entry is simply never looked up again. No manual invalidation is needed. To force a full rebuild, delete `~/.pit/build/`.
Caching is content-addressed by BLAKE2 over the relevant inputs for each artifact.
- Mach/script cache keys are source-content based.
- Native (`.dylib`) cache keys include source, host target, native mode marker, native cache version, and sanitize flags.
When inputs change, the old cache entry is simply never looked up again. To force a full rebuild, delete `~/.pit/build/` (or run `cell --dev clean shop --build` in a dev workspace).
## Module Resolution
@@ -73,7 +78,7 @@ use('gitea.pockle.world/john/renderer/sprite')
## Compilation and Caching
Every module goes through a content-addressed caching pipeline. The cache key is the BLAKE2 hash of the source content, so changing the source automatically invalidates the cache.
Every module goes through a content-addressed caching pipeline. Cache keys are based on the inputs that affect the output artifact, so changing any relevant input automatically invalidates the cache.
### Cache Hierarchy
@@ -104,7 +109,9 @@ The build cache at `~/.pit/build/` stores ephemeral artifacts named by the BLAKE
└── f3a4b5c6... # compiled dylib (checked before copying to lib/)
```
This scheme provides automatic cache invalidation: when source changes, its hash changes, and the old cache entry is simply never looked up again. When building a dylib, the build cache is checked first — if a matching hash exists, it is copied to `lib/` without recompiling.
This scheme provides automatic cache invalidation: when an input changes, its hash changes, and the old cache entry is simply never looked up again. For native dylibs, inputs include target and native cache version in addition to source.
When native codegen/runtime ABI changes, bump `NATIVE_CACHE_VERSION` in both `build.cm` and `internal/shop.cm` so stale native artifacts are never reused.
### Core Module Caching

View File

@@ -118,6 +118,45 @@ When a mismatch is found:
MISMATCH: test_foo: result mismatch opt=42 noopt=43
```
## ASAN for Native AOT
When debugging native (`shop.use_native`) crashes, there are two useful sanitizer workflows.
### 1) AOT-only sanitizer (fastest loop)
Enable sanitizer flags for generated native modules by creating a marker file:
```bash
touch .cell/asan_aot
cell --dev bench --native fibonacci
```
This adds `-fsanitize=address -fno-omit-frame-pointer` to AOT module compilation.
Disable it with:
```bash
rm -f .cell/asan_aot
```
### 2) Full runtime sanitizer (CLI + runtime + AOT)
Build an ASAN-instrumented `cell` binary:
```bash
meson setup build-asan -Dbuildtype=debug -Db_sanitize=address
CCACHE_DISABLE=1 meson compile -C build-asan
ASAN_OPTIONS=abort_on_error=1:detect_leaks=0 ./build-asan/cell --dev bench --native fibonacci
```
This catches bugs crossing the boundary between generated dylibs and runtime helpers.
If stale native artifacts are suspected after compiler/runtime changes, clear build outputs first:
```bash
cell --dev clean shop --build
```
## Fuzz Testing
The fuzzer generates random self-checking programs, compiles them, and runs them through both optimized and unoptimized paths. Each generated program contains test functions that validate their own expected results, so failures catch both correctness bugs and optimizer mismatches.