string arc: emit ownership in the compiler, o(1) cstring length - #231
Merged
Conversation
correctness proven: the stage-2 compiler runs its own 21k lines under the discipline and compiles itself. the missing piece was the real assignment path (ir_emit_compound_assignment op '='), which stored strings with no ownership handling — the bind/assign work originally landed on a path the parser rarely produces. not ready to merge: self-compile takes ~94s (rc traffic on every string param, bind, and return) and peak rss is unchanged because the compiler's memory is ast/token structures, not cstring garbage. next: param-borrow convention instead of retain/release per call, statement-temp releases (the real garbage), then the full suite.
the compiler now emits the string ownership discipline: retain on binding a borrowed value, release on rebinding, reassignment, and at every return, transfer on returns, and retains at each escape point (struct fields, containers, tuples, closure captures, channel sends). params are borrows — an unmodified string parameter costs no rc traffic. concat and interpolation chains free their intermediates as they fold. two lessons are baked into the shape of this: plain assignments go through the compound-assignment path, not ir_emit_assign_stmt, and sibling scopes can bind the same name with different types, so the pre-pass poisons any name that is ever non-string rather than let a retain fire on an integer handle. the refcount header also stores the length, so cstring len() is one read instead of a strlen. profiling showed the compiler spent 80% of its runtime in strlen — every while-i-less-than-len loop over a big string was quadratic. make self-host drops from ~45s to 1.7s. string microbench: 85.5mb peak rss to 15.2mb, 131ms to 81ms. std_pipeline: 888ms to 804ms. stage2 and stage3 compiler binaries are byte-identical (fixed point), bootstrap seed refreshed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
summary
strings now reclaim in the native path. this is the emitter half of the work started in #230 (refcounted cstring headers):
len()on a heap cstring is one read instead of a strlen.the numbers
make self-hostthe compile-time one deserves a line: profiling showed the compiler spent ~80% of its own runtime in strlen — every
while i < s.len()loop over a large string was quadratic. the header length turns all of those linear at once.design notes
two hard-won facts shaped the implementation. plain
name = valuestatements lower through the compound-assignment path, not the assign path — the first version put the ownership logic on a near-dead code path, and the lexer's token globals ended up holding freed buffers. and sibling scopes can bind the same name with different types over one flat storage slot, so the pre-pass poisons any name that is ever bound non-string; otherwise a retain fires on an integer handle and walks off the map. the runtime gained aPITH_CSTRING_NOFREEdebug mode (over-release reporting plus content scrubbing) that made both bugs findable.what still leaks: container elements in untagged collections, bytes objects, struct fields, and the ast/token structures that dominate the compiler's own peak rss. collections are the next reclamation target.
what was tested