audit-eob: close milestone heap-str-abi via eob.tidy
Architect drift review (range 750f97e..78e8338): drift_found with
three [high — spec acceptance] DESIGN.md items left over from the
heap-str-abi spec's acceptance criteria, plus one [medium] record-
keeping note. All three high items fixed inline as eob.tidy (Boss-
mechanical edits — small scope, content fully known from the just-
closed milestone, no plan / implement dispatch warranted):
1. DESIGN.md (Float-semantics block): replaced the stale 'float_to_str
is type-installed but codegen-deferred' caveat with a one-paragraph
statement that float_to_str and int_to_str are fully wired,
allocate a heap-Str slab, and carry ret_mode: Own.
2. DESIGN.md ('What is supported' inventory): dropped the codegen-
deferred parenthetical from float_to_str; added int_to_str to the
inventory with the same Str-ABI cross-reference.
3. DESIGN.md (new 'Str ABI' subsection after Float-semantics): documents
the dual realisation (static-Str packed-struct globals vs heap-Str
malloc slabs), the shared consumer ABI (Str pointer at len-field
offset 0, bytes at payload+8, inherited strcmp semantics), and the
codegen-level non-RC invariant for static-Str (move-tracking +
non-escape lowering + Type::Con{name:"Str"} carve-outs in
field_drop_call and drop_symbol_for_binder's App arm).
Medium-severity hs.4-journal forward-pointer item skipped: INDEX.md
already chains hs.4 → eob.1 chronologically, and eob.1's journal
explicitly cross-references hs.4's deferred fix.
Bench-regression check:
- compile_check.py: exit 0; 24 metrics all stable
- cross_lang.py: exit 0; 25 metrics all stable
- check.py: exit 1; 2 regressed (bench_list_sum.bump_s +12.6%,
bench_hof_pipeline.bump_s +11.65%, both marginal, the other four
bump_s metrics stable — most parsimonious explanation is per-
fixture system noise on ~50ms benches), 5 improved beyond
tolerance (latency.explicit_at_rc.p99_us / p99_9_us / p99_over_median
cluster — third consecutive audit showing the same shift
uncorrelated with milestone work, plus two gc_over_bump mirrors of
the bump_s regressions).
Baseline left pristine on every script for the third consecutive
audit. Latency cluster has persisted across audit-cma → audit-ms →
audit-eob without an identified cause; ratifying via --update-baseline
would obscure the next attributable signal. bump_s cluster is first-
sighting; first-sighting rule says observe in the next audit, do not
ratify on first sight.
Heap-str-abi milestone fully closed:
- Static-Str layout migrated (hs.1, hs.2 + spec amend).
- Heap-Str runtime wired (hs.3, hs.4).
- Effect-op-borrow rule + RC-discipline (eob.1).
- DESIGN anchors landed across eob.1 (arg-position policy under
Decision 10) and eob.tidy (Str-ABI subsection, signatures-inventory
cleanup).
This commit is contained in:
+48
-8
@@ -2335,11 +2335,49 @@ matches via IEEE-`==`, and bit-exact equality is rarely what an
|
||||
LLM-author wants. Use ordering operators (`<`, `>`, ...) and
|
||||
`is_nan` to discriminate Floats.
|
||||
|
||||
`float_to_str` (Float → Str) is **type-installed but codegen-
|
||||
deferred** to a follow-up milestone: it requires runtime-allocated
|
||||
`Str` (the current Str path uses only static `@.str_*` globals;
|
||||
no malloc-backed dynamic-Str infrastructure). Calling it
|
||||
typechecks but produces a structured `CodegenError::Internal`.
|
||||
`float_to_str` (Float → Str) and `int_to_str` (Int → Str) are
|
||||
fully wired through checker, codegen, and runtime. Both allocate
|
||||
a fresh heap-Str slab at the call site (see "Str ABI" below for
|
||||
the dual realisation) and carry `ret_mode: Own` so the let-binder
|
||||
for the call result is RC-tracked and the slab is freed at scope
|
||||
close.
|
||||
|
||||
**Str ABI.** A `Str` is a pointer to a structure with `i64 len` at
|
||||
offset 0 followed by `len` bytes plus a trailing `NUL` at offset 8.
|
||||
Two realisations share this consumer ABI:
|
||||
|
||||
| Realisation | Origin | rc_header | Memory |
|
||||
|-------------|-------------------------------------------------|-----------|-----------------------------------------|
|
||||
| static-Str | string literals (`@.str_*` LLVM globals) | none | `.rodata`, packed-struct `<{ i64, [N+1 x i8] }>` |
|
||||
| heap-Str | runtime allocations (`int_to_str`, `float_to_str`, ...) | yes, at `payload - 8` | `malloc`'d via `ailang_rc_alloc(8 + len + 1)` |
|
||||
|
||||
Every consumer (`@puts`, `@strcmp`, `@ail_str_eq`,
|
||||
`@ail_str_compare`) GEPs `+8` from the Str pointer to reach the
|
||||
bytes, regardless of realisation. The byte-comparison semantics
|
||||
are inherited from libc `strcmp` — locale-independent, NUL-
|
||||
terminated.
|
||||
|
||||
The heap-Str realisation participates in standard RC: the
|
||||
`rc_header` slot eight bytes before the `len` field is managed
|
||||
by `ailang_rc_alloc` / `ailang_rc_inc` / `ailang_rc_dec` exactly
|
||||
like any other RC-allocated cell. The static-Str realisation has
|
||||
no `rc_header` slot at all; the bytes at `payload - 8` belong to
|
||||
the previous global in `.rodata` and reading them is undefined.
|
||||
|
||||
**The static-Str non-RC invariant is enforced at codegen.** Two
|
||||
mechanisms keep static-Str pointers out of `ailang_rc_dec` along
|
||||
every shipping execution path: (1) the non-escape lowering pass
|
||||
(iter 18b) and the move-tracking partial-drop logic (iter 18d.3)
|
||||
prevent let-binders or pattern-binders for static-Str literals
|
||||
from reaching scope-close drop emission; (2) the `Type::Con { name: "Str" }`
|
||||
carve-outs in `field_drop_call` and in the `Term::App` arm of
|
||||
`drop_symbol_for_binder` (both in `crates/ailang-codegen/src/drop.rs`)
|
||||
route the rare case that *does* reach drop emission through
|
||||
`ailang_rc_dec`, which itself only fires for heap-Str at runtime
|
||||
(static-Str pointers never carry a live rc_header; if codegen ever
|
||||
let one through, the runtime would corrupt `.rodata`-adjacent
|
||||
memory). No runtime guard backs the invariant up; the codegen
|
||||
proof is the protection.
|
||||
|
||||
## What is not (yet) supported
|
||||
|
||||
@@ -2384,9 +2422,11 @@ What **is** supported (and used as the smoke test for the pipeline):
|
||||
`not : (Bool) -> Bool`; conversions
|
||||
`int_to_float : (Int) -> Float`,
|
||||
`float_to_int_truncate : (Float) -> Int` (saturating, NaN → 0),
|
||||
`float_to_str : (Float) -> Str` (codegen lowering deferred —
|
||||
symbol installed but errors at codegen pending runtime Str
|
||||
allocation); inspection `is_nan : (Float) -> Bool` (LLVM
|
||||
`float_to_str : (Float) -> Str`,
|
||||
`int_to_str : (Int) -> Str` (both allocate a heap-Str slab at
|
||||
call time and return it with `ret_mode: Own`; see "Str ABI" for
|
||||
the dual heap-/static-Str realisation); inspection
|
||||
`is_nan : (Float) -> Bool` (LLVM
|
||||
`fcmp uno`); Float bit-pattern constants `nan : Float`,
|
||||
`inf : Float`, `neg_inf : Float` (resolved as bare values, lower
|
||||
to direct hex-float `double` SSA constants at use site); the IO
|
||||
|
||||
Reference in New Issue
Block a user