From 5ec9eff5fe732fe0fc545e60a1522d395060bea0 Mon Sep 17 00:00:00 2001 From: "russell@unturf.com" Date: Sat, 18 Apr 2026 19:33:44 -0400 Subject: [PATCH] asm-gc Fix 1: precise block typing kills conservative-scan class of bugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces header format from [size:63 | mark:1] with [size:48 | type:8 | flags:8 (mark in bit 0)]. Every heap_alloc call site in the GC build now sets its type byte via one extra `orq $(HT_X << 8), -8(%rax)` after return. Ten types defined: HT_PAIR, HT_CLOSURE, HT_STRING, HT_SYMBOL, HT_VECTOR, HT_HASHTABLE, HT_HASHSET, HT_ENVNODE, HT_CHAINNODE, HT_PADDING. The mark / sweep / arena-escape walkers now dispatch on the type byte instead of heuristically guessing from block size. Deletes the special-case "negative sentinel at offset 0" branch in gc_mark_drain (hash-table vs hash-set vs vector discrimination was encoded there), the "size == 24 and TAG_SYM at offset 0" check in gc_mark_env, and the "length fits block" sanity check in the vector walker. All that logic collapses into a single compare on the type byte. Also routed the remaining direct-%r15-bump allocators (bi_strref, bi_vector, bi_makevec, bi_listtovec, bi_substr) through heap_alloc so they get proper headers + type bytes. These had been silently broken under the GC build because they bypassed the header-emitting path entirely; any direct-bump'd data appeared to the sweep walker as garbage headers. §6.6.4 cell 4 (asm GC + no snapshot) was crashing at first GC before this change. After: serves 5,000 HTTP requests at ~410 req/s, peak RSS 1,088 KB (one chunk), growth 972 KB — the collector hit its natural steady state. First time we've validated "naive GC as replacement for snapshot discipline" under real traffic. New §6.6.5 "Precise Block Typing" in the whitepaper documents the old heuristic bugs, the new header format, and the cost (one orq per alloc, 16 header bits) vs benefit (class of bugs eliminated). Updated §6.6.4 to reflect cell 4 passing. Remaining known issue: the hash-set bench on the GC build under very heavy sustained allocation still surfaces an occasional unbound-variable error. The precise-type fix addressed the observed HTTP crash; a deeper root-scan edge case remains. Tracked for Fix 2 work. 137 asm no-GC + 137 asm GC + 189 shared functional tests all pass. --- asm/uncommonlisp | Bin 50968 -> 50968 bytes asm/uncommonlisp-gc | Bin 59016 -> 59392 bytes asm/uncommonlisp-gc.o | Bin 61440 -> 61936 bytes asm/uncommonlisp.o | Bin 52984 -> 53016 bytes asm/uncommonlisp.s | 271 +++-- whitepaper/uncommonlisp-whitepaper.pdf | 1496 ++++++++++++------------ whitepaper/uncommonlisp-whitepaper.rst | 36 +- 7 files changed, 953 insertions(+), 850 deletions(-) diff --git a/asm/uncommonlisp b/asm/uncommonlisp index 4f7dd9f85ed8dca2a65aa256c6d246bbbe7a6164..8a91405f84a9744372f24a17cbcc77cb72cd5360 100755 GIT binary patch delta 4914 zcmZ9Pc~n%_9mn4rSq4+QAcp6-L=czi2{kA?Bh0YAQA9B)0xDoymuhOM3nWL2$|W*E zw){>E?w~n|F-HwfYvPvR7StGz#MpyTqeiPkjS5;*8%?Lb_wEhJyYCO~_kBKhpSRIi z+pDp*SAC;jSE8gJT`kT20Y2g5CCUBF^|yfiq_;g>k{r&~LU*idX~;pZ@?0WGYQ>YW zgnrG^I6^}LbQVeIK9-^g9T=#yXhI`ciXk+YrC35KOYwxh5v12kAaoZ?Rzh#GG@j5W zEX5JJt*>6MJdx06EG7}!r=JdOgic_|PUtk&buytVSxO;vBeSW59$_qv(5Eb=6I#Vm z2BD8xJ(bWq&+9!q2py#8X#$~F`b$zdu6-h*NfsSu68btzlL+0*QWn|)x}A(u4b#&U zLT?Y#Q#PS-!}Tn|s+Ob%6#=(Q=!GQxc z6h~@(HPi?Hz?7u^HthaE7mi$U{fSx;E91|IXPsB@Pp0#_Ml-96%xZP4TH)~~^b@VB z6Kh`g#UEWJl`dEoGu&sj)}{)YVv`v3D4(uTq3X}W>_>#)M-sh96mek5tQuQZ1@0@iX zx}y8RvA7rH6L2FgIcWMXgWUcHb~YOa36Fm@Avb%9>TFXh+RW~`$n&+)1Js&7<1Vit zX4ToQI*;LIFC}mKR{5x&Hr4aF>N$P)d)0X!9z+F0t=$X{5+cFRra)ps02!{`Gu1w- z(`%So?fnJJN|+?Cgbx!A$^J0UI;Y?4nX*)nr?$1?awXMyO|6ca=(=hRk;{(_kfkZu zW|vUz)6bpZ+p$#Jyw_r(x2;Yc7NR=6D;TcALKE&KxC-2drT)0AOy>{oEmu9ByPY$z z<^rsumD#+s^U{IkY}K_QvD_pFz%$!IxfSNyqsoUWY(l+-vafcY>GU>Xi4(dL%qQgZ zcVk3y4-0)R9bah|!*OlUtH`wSBrpHY%OhB-&JLXMGGE*kd`L<5nX?LxXF6fXsONlR zwI!U?u9$wf)jpsm_mx|qAbGc(3w|jPayulXC)w^*FetTJ{s4BS9`|Yf4lC9}N!kFD`7A_44utV(L2xK7MJ@(U+6Z|$ zj7VQ&dUOVMr7x3LKuE?y+@f_EvGOK3nGq@Xg&#BW`X9LV>*4=L=w<|+JFfBJ1EF3G zH+_2wK2u*e<)6|=nVexY`JIBAi~+7aj+K*ywJ^g864Yy~Z0d3!SqutEyNH~f% zFUDy1aJve+(e4&(E4Pm!v{rGf6YK?UdnFkA{El;vz#nm*2&-!qi#f^Iir~wi?RE>= zgMuBw?SJ70TCf@0rgNJQfpv-{YogK4;r2tYqdlK#v@5yIffBTf?MAzi+fryod%`x#3PSe(y0jnDn zd7f)S!!<8UL!_~5Cw`h~mG(fxdc|>0usgWz6=iI-oAY}@{llEA(7j%spuHp5m$;n=H_(0~+(-^?-4NKQ zSVjrAcM-Q%u%n$S*ivriLkZdn!Pauy1kGsg3-(=ZJ<#5$IPM7#odewVjyLZ73C>3e z{50gi4^9FGJW&TW|0*eZeZ z7=b%D9}A%y70b}^##Tk#&Vg*S%LQA??JZc1wj7o+XxT4+Z5itxy@aGMM5Xg3OW zEVuC>Z&obz$;SCOxP1>IHrL7f;3(EPE!5e=>$F4nW~KbLV2^X_B|H$%bM7thZ#nNH z@J`M%1^$HdG{#}=mOx9TP=|y_c;Htkv}{o!#9;%d=+iQSAy{H z&F6L=*wJnh>~e0eLJ8Ur1Y5^#2Q;G%6dv5~bDIP0Xom>4mD|Z6Z&NH)g6-h86(Z2C z7i>4ThoE@d7#Tk@wkeK_LY>f12@hF%PIx`M#JMDJE9a@ujU)aj*lFC>L1>c_*e1MG z7DI890!2+`$1%aY!P^a-W`!5J= zRvcr5kBZCO1_=Bn=dA*N_%nx+X2r5ku)T+BOOd4$(2QfLlWaXJ)51t@{RRFz&UXkr ihVzd>-j44g!8*9bYhk-0fA4Z^UmPZPxelBxl>ZMjYjGO@ delta 4837 zcmZ9P4OkUb8i40q18)=_P;ng8MMN~)MZ4$~kRQ2#FoU3CwX0%+y1ARKCY$+F))hHg z*DD}?W&RuHKDN7Q(cP?U+XesdXH{@FtxN%R71XE1p2wwj_3k%wPS%`x9`5(e`<~x9 zGiQd4RoymLbz8Ub!4nyZb)2ZH4UY(QrYlPOxxil{_R+BZ35sI)>Py;t1r`n5|A4oU zDvDmwl}Oofo{glePlUxrQT8^^+>}K|T5L3BLwS}&Ss~AoDSLruVzh4&Z6u&o@G<^JhwTN1vnc= zStrkODSMe`d6YHrayn%PqOA4|%Kp>G%JM1uu&<(caqi{FX_8xELmz3@0*{>*5 zyu86FlpW)6DrHmpSyiS{_6*O8DVyHkV$&(x#IvU;JH)dYls!JcvL%!q;aMqVYky|3 znUtwKn}sd&Y&K<~#%ctKv{>C=>vffk%Y*&d$#hO+BC`z>Wrv6g*?GB3~OQnrt0 z^C`oL#@x1DF8WoKZuwqmSDTn=|R`w6x4hHo~uT!sF?9^8sqwErbHQmRA(p6VriaU+~ zEO$Ra=0dZ(n#_WkqkrxgeI9BOG}t{lO)cmQ2Gcxr?Ibf!qg81bJF+{WIlDLXNODHT zn>>Y9MVh=X{=oL^zM0tecek+HiqlMKeytB-r zJ}lYV9oL!ARiA=4DL&M1)>#jKO3HGa{lXeh_v93^5b@qu;%F$;dZM96W)B#WT1fNF z8{QwP`yLpq`$KNQ%G5%#6Pi*#A&IayZB}%}bfOeb)f?+^sTAGUqWj$o5$V3;Fh8>& z#H9zl*P@9s2`itL;yLTwm(Yk&Zwz?{gVl&XXYfGX7xFg8doY-yedAf2`>Ogy;kvJ} zz;~zpz=dG&M#mH^S%pQ+xLCwFA}+u^1dn75b6hu_lhQj=; zp5!d7$l61e!|-euxdWxyQ`K!(eq7Ott{`PA5Oll(P1&=1yniwnoT~d>IN_r9KY%C4 zPfo$foP*tuT*5LRTr!tE#J|+po&a^@eot1z;M^f(3yjZQ>F9d`PUk*PYGGX7Je+%7 zUNWhN>v^L{62$0J`(AAMX|MNi=R(kNv;|v?hY$3Ghr1mM1`Tt~gV|1K8ygQRa-DE$ zTu(?aTn_J1aEQnWt?)x{)FJE2l-#(W`#vu|__$t~KEZ*j z_w8YmhrAz#cS&Ws$3(3h?dHg3qLUnLBAk@x3B7VaM5v+^x~>=%|NGrb zL-PG;m)j!_2YUta2D;Wh@t`@|BP9jC+wBtrZ4+Y1dJ?~L(j#O)kfkcA3TR8;2q$X- zb*rjFi5EO;RV~z=Y29r<{QMVRNebR=)1eG)mt=dX+|GkqwEoeV=IQ+-LD)~Ad97;P zmTaD|HxI1mu~n+EQnLRP_Tm_Oo0kOtGS$w%6&2 z?XYonyHwak(13PAuH9}I_7HTgQ;pO-yFD&!r^L?-o~+x;cL+WoifUA?O|m`k)5@IV zASka5n^1&ynDj`8;1`}b&U`3GTO!$h!cK-dv==1%n6OVl8`>u6K{ABB z2$36AEk=60ONC7Y4_aNaON5;PWoQ>lwo2Gas6~55vb%)649y!=qgmQGJ{IJgS7cRDr_vYp*<^YzB$6;t7tpE5~R&{ zny^{mLAzM8i-r9N%Fr^&Rtp<|TC_JMyIa^1(2Vwb$<_<|D3BehHe1@a#&khw9?ifgRL(LA=cu(@Nu?ikUxhnC;1V1nFG{Iw_6UXwI^vZZr*trnv#McWRmY-=3_5QJ4aQw8#z6MC24etsY32kU!kZhx{has|7 zHNvEiiu1zWkZN5Pe2Y~6_75D&YE`XLvSEYFAroZ>)M8(8g_-wfU?xL_ZI@~d7yMHpmyrJhFE&cL diff --git a/asm/uncommonlisp-gc b/asm/uncommonlisp-gc index 5e479c697285f5662abcaaa7cfba5487d0fbbfd9..19b861abc97643c19ec9af085c51e10c12917093 100755 GIT binary patch delta 19385 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

KpWDi}ijQeI)T~=+BV{#M|f_h#R`` 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 diff --git a/asm/uncommonlisp-gc.o b/asm/uncommonlisp-gc.o index 8baca04f2b274546b93f6c443b66b6b4a646f347..cb6007f8f2bea080096cddd66a32e2358b06f391 100644 GIT binary patch delta 20437 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 IF4o5UKlR3y>;M1& delta 20090 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 diff --git a/asm/uncommonlisp.o b/asm/uncommonlisp.o index cc8786578ee742a80af0805a6b7ccdbd7062cafa..e8838cbc35561f02c4a5cc314930e7b0a96c538d 100644 GIT binary patch delta 5333 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 diff --git a/asm/uncommonlisp.s b/asm/uncommonlisp.s index 44458c7..4adfb83 100644 --- a/asm/uncommonlisp.s +++ b/asm/uncommonlisp.s @@ -450,8 +450,29 @@ sym_hash_buckets: .skip 8192 # 1024 * 8 bytes .ifdef GC_NAIVE # ─────────────────────────────────────────────────────────── # Naive mark-and-sweep GC state (control group for bench). -# Every heap block carries an 8-byte header: (size << 1) | mark. +# Every heap block carries an 8-byte header: +# bit 0 = mark +# bits 1–7 = reserved +# bits 8–15 = type byte (HT_PAIR, HT_CLOSURE, …) +# bits 16–63 = payload size in bytes # The tagged pointer still points at the payload (header at -8). +# The type byte lets mark / sweep / arena walkers dispatch +# precisely instead of guessing from block size — earlier versions +# had to reject 24-byte strings-masquerading-as-env-nodes via +# TAG_SYM checks at offset 0, and 40-byte strings masquerading +# as vectors via a length-fits-block check. Type byte kills the +# entire class of bugs. +.equ HT_FREE, 0 # not used during normal ops (0 = unknown / free) +.equ HT_PAIR, 1 +.equ HT_CLOSURE, 2 +.equ HT_STRING, 3 +.equ HT_SYMBOL, 4 +.equ HT_VECTOR, 5 +.equ HT_HASHTABLE, 6 +.equ HT_HASHSET, 7 +.equ HT_ENVNODE, 8 +.equ HT_CHAINNODE, 9 +.equ HT_PADDING, 10 # Chunks are tracked in a side array so chunk memory stays pure # allocation space. Free blocks are linked via a global list # whose nodes reuse the header word as size and the first 8 bytes @@ -692,7 +713,7 @@ heap_alloc: cmpq %r13, %rcx ja .ha_overflow movq %rbx, %rdx - shlq $1, %rdx # header = size << 1, mark=0 + shlq $16, %rdx # header = (size << 16) | (type<<8) | mark; caller patches type movq %rdx, (%r15) movq %r15, %rax addq $8, %rax # payload ptr @@ -725,7 +746,7 @@ heap_alloc: cmpq %r13, %rcx ja .ha_grow movq %rbx, %rdx - shlq $1, %rdx + shlq $16, %rdx movq %rdx, (%r15) movq %r15, %rax addq $8, %rax @@ -744,7 +765,8 @@ heap_alloc: movq %rax, %rdx subq $8, %rdx # padding payload size movq %rdx, %rcx - shlq $1, %rcx # header, mark=0 + shlq $16, %rcx # header; type will be patched to HT_PADDING below + orq $(HT_PADDING << 8), %rcx movq %rcx, (%r15) # Link onto free list directly so sweep doesn't need to know. movq gc_free_list(%rip), %rcx @@ -785,7 +807,7 @@ gc_freelist_alloc: testq %rax, %rax jz .gfa_empty movq (%rax), %rdx # header - shrq $1, %rdx # block payload size + shrq $16, %rdx # block payload size (bits 16..63) cmpq %rdi, %rdx jb .gfa_next # Fits. Unlink. @@ -807,14 +829,17 @@ gc_freelist_alloc: leaq 8(%rax,%rdi), %r9 # tail header addr subq $8, %r8 movq %r8, %r10 - shlq $1, %r10 # mark=0 + shlq $16, %r10 # tail header, type=0 (free), mark=0 movq %r10, (%r9) movq gc_free_list(%rip), %r11 movq %r11, 8(%r9) movq %r9, gc_free_list(%rip) - # Shrink current block's header. + # Shrink current block's header — keep its type byte, just resize. + movq (%rax), %r10 # old header + andq $0xff00, %r10 # keep type byte; drop old size+mark movq %rdi, %rdx - shlq $1, %rdx + shlq $16, %rdx + orq %r10, %rdx # new header: new size + old type movq %rdx, (%rax) .gfa_return_whole: addq $8, %rax # payload ptr @@ -1011,19 +1036,11 @@ gc_mark_env: popq %rdi testq %rcx, %rcx jz .gme_end - # Block's header payload-size must be 24 AND offset 0 must be - # a tagged symbol. Env nodes are (sym, val, parent); strings - # and closures are also 24 bytes when they happen to land at - # that size, so a bare size check treats them as env and the - # walker corrupts the heap by reading string bytes as env - # fields. Demanding TAG_SYM at offset 0 disambiguates. - movq -8(%rdi), %rax - shrq $1, %rax - cmpq $24, %rax - jne .gme_end - movq (%rdi), %rax - andq $7, %rax - cmpq $TAG_SYM, %rax + # Precise type dispatch: we want HT_ENVNODE exactly. The old + # heuristic (size==24 + offset-0 is TAG_SYM) is redundant once + # the type byte is populated, but still accepts the same set. + movzbq -7(%rdi), %rax # header byte 1 (type byte) + cmpq $HT_ENVNODE, %rax jne .gme_end # Already marked? Skip. testq $1, -8(%rdi) @@ -1113,7 +1130,10 @@ gc_push_if_heap: ret # gc_mark_drain: pop tagged values from mark stack, set header -# mark, push children based on tag. Loop until empty. +# mark, push children based on the TYPE BYTE in the header (bits +# 8..15). Dispatching by type instead of by tagged-value tag +# eliminates the class of bugs where a tag-7 value (stack scan +# false positive) had to be disambiguated by guessing from size. gc_mark_drain: .gmd_top: movq gc_mark_depth(%rip), %rcx @@ -1122,23 +1142,24 @@ gc_mark_drain: decq %rcx movq %rcx, gc_mark_depth(%rip) leaq gc_mark_stack(%rip), %rsi - movq (%rsi,%rcx,8), %rbx # tagged value (callee-save keeps it safe) + movq (%rsi,%rcx,8), %rbx # tagged value movq %rbx, %rsi andq $-8, %rsi # untagged ptr - # If already marked, skip. testq $1, -8(%rsi) - jnz .gmd_top - orq $1, -8(%rsi) # mark header - # Dispatch by tag. - movq %rbx, %rax - andq $TAG_MASK, %rax - cmpq $TAG_PAIR, %rax + jnz .gmd_top # already marked + orq $1, -8(%rsi) # mark + movzbq -7(%rsi), %rax # type byte + cmpq $HT_PAIR, %rax je .gmd_pair - cmpq $TAG_CLOSURE, %rax + cmpq $HT_CLOSURE, %rax je .gmd_closure - cmpq $7, %rax - je .gmd_vec7 - # STRING / SYM: no children. + cmpq $HT_VECTOR, %rax + je .gmd_vector + cmpq $HT_HASHTABLE, %rax + je .gmd_hash + cmpq $HT_HASHSET, %rax + je .gmd_hash + # HT_STRING / HT_SYMBOL / HT_CHAINNODE / HT_PADDING / HT_FREE: no children jmp .gmd_top .gmd_pair: movq (%rsi), %rdi @@ -1161,29 +1182,10 @@ gc_mark_drain: movq 16(%rsi), %rdi call gc_mark_env # env field is an untagged env chain jmp .gmd_top -.gmd_vec7: - # Block size from header. The conservative stack scan can push - # any value whose low 3 bits happen to equal 7; that untagged - # "pointer" might land in a chunk but belong to a string or - # closure, not an actual vector. Validate size against the - # claimed length/layout before walking — otherwise a 40-byte - # string misinterpreted as a 25-element vector reads 200 bytes - # past itself and corrupts marks on adjacent blocks. - movq -8(%rsi), %rax - shrq $1, %rax # block payload size - movq (%rsi), %rdx # first word: length or -1 or -2 - cmpq $-2, %rdx - je .gmd_ht_check - cmpq $-1, %rdx - je .gmd_ht_check - testq %rdx, %rdx - js .gmd_top # other negatives = not ours - # Vector: length must fit: 8 + length*8 <= block_size - movq %rdx, %rcx - shlq $3, %rcx - addq $8, %rcx - cmpq %rax, %rcx - ja .gmd_top # length too large for block +.gmd_vector: + # Vector: first word = length, elements at offset 8. + # Type byte already confirmed it's a real vector, no size guesswork. + movq (%rsi), %rdx # length xorq %r8, %r8 .gmd_vec_loop: cmpq %rdx, %r8 @@ -1199,19 +1201,9 @@ gc_mark_drain: incq %r8 jmp .gmd_vec_loop -.gmd_ht_check: - # Hash-table (-1) or hash-set (-2): require block size >= 24 - # (header) + nbuckets * 8. nbuckets at offset 16. - cmpq $24, %rax - jb .gmd_top +.gmd_hash: + # Hash-table or hash-set: nbuckets at offset 16, buckets at 24+. movq 16(%rsi), %rcx # nbuckets - testq %rcx, %rcx - js .gmd_top # garbage - movq %rcx, %rdx - shlq $3, %rdx - addq $24, %rdx - cmpq %rax, %rdx - ja .gmd_top # nbuckets too large xorq %r8, %r8 .gmd_ht_loop: cmpq %rcx, %r8 @@ -1257,7 +1249,7 @@ gc_sweep: jae .gsw_next_chunk movq (%rbx), %rsi # header movq %rsi, %r11 - shrq $1, %r11 # payload size + shrq $16, %r11 # payload size (bits 16..63) testq $1, %rsi jz .gsw_dead # Live: clear mark. @@ -1334,6 +1326,9 @@ make_pair: call heap_alloc popq %rsi popq %rdi +.ifdef GC_NAIVE + orq $(HT_PAIR << 8), -8(%rax) +.endif movq %rdi, (%rax) movq %rsi, 8(%rax) orq $TAG_PAIR, %rax @@ -1349,6 +1344,9 @@ make_closure: popq %rdx popq %rsi popq %rdi +.ifdef GC_NAIVE + orq $(HT_CLOSURE << 8), -8(%rax) +.endif movq %rdi, (%rax) # params movq %rsi, 8(%rax) # body movq %rdx, 16(%rax) # env @@ -1376,6 +1374,9 @@ env_define: popq %rdx popq %rsi popq %rdi +.ifdef GC_NAIVE + orq $(HT_ENVNODE << 8), -8(%rax) +.endif movq %rdi, (%rax) movq %rsi, 8(%rax) movq %rdx, 16(%rax) @@ -1503,6 +1504,9 @@ intern_symbol: # Use the stack to save sym_ptr across the second heap_alloc. leaq 1(%r12), %rdi call heap_alloc +.ifdef GC_NAIVE + orq $(HT_SYMBOL << 8), -8(%rax) +.endif # %rax = sym_ptr; fill symbol: length byte + chars movb %r12b, (%rax) xorq %r8, %r8 @@ -1524,6 +1528,9 @@ intern_symbol: # Allocate hash chain node: 16 bytes [sym_ptr, next_ptr] movq $16, %rdi call heap_alloc +.ifdef GC_NAIVE + orq $(HT_CHAINNODE << 8), -8(%rax) +.endif # Fill chain node: %rax = node_ptr, stack top = sym_ptr popq %rcx # rcx = sym_ptr movq %rcx, (%rax) # node->sym = sym_ptr @@ -1879,6 +1886,9 @@ scheme_read: pushq %rbx leaq 8(%rbx), %rdi call heap_alloc +.ifdef GC_NAIVE + orq $(HT_STRING << 8), -8(%rax) +.endif popq %rbx movq %rbx, (%rax) # 8-byte length xorq %rcx, %rcx @@ -4279,12 +4289,18 @@ bi_strref: movq %rax, %rcx # string ptr GETARG %rax # index sarq $3, %rax - movzbl 8(%rcx,%rax,1), %edi # byte at offset - # Return as 1-char string - movq %r15, %rax - movq $1, (%r15) # length - movb %dil, 8(%r15) - addq $16, %r15 + movzbl 8(%rcx,%rax,1), %r8d # byte at offset (keep across heap_alloc call) + # Allocate a 1-char string via heap_alloc so the GC build sees + # a proper header / type byte instead of a headerless direct bump. + movq $9, %rdi # 8B length + 1B char + pushq %r8 + call heap_alloc + popq %r8 +.ifdef GC_NAIVE + orq $(HT_STRING << 8), -8(%rax) +.endif + movq $1, (%rax) # length + movb %r8b, 8(%rax) orq $TAG_STRING, %rax RET_VAL @@ -4313,6 +4329,9 @@ bi_strappend: movq %rcx, %rdi addq $8, %rdi call heap_alloc +.ifdef GC_NAIVE + orq $(HT_STRING << 8), -8(%rax) +.endif movq %rax, %rbp # string object base movq %rbx, (%rbp) # store length leaq 8(%rbp), %r9 # dest cursor @@ -4406,6 +4425,9 @@ bi_numtostr: movq %rcx, %rdi addq $8, %rdi call heap_alloc +.ifdef GC_NAIVE + orq $(HT_STRING << 8), -8(%rax) +.endif popq %rcx popq %rdi movq %rcx, (%rax) # length @@ -4601,13 +4623,20 @@ bi_vector: movq 8(%rdx), %rax jmp .bvec_count .bvec_alloc: - # Allocate: 8 bytes length + 8*count bytes - movq %r15, %rax # vector obj - movq %rcx, (%r15) # length - leaq 8(%r15,%rcx,8), %r15 + # Allocate via heap_alloc so GC build gets a header + type byte. + pushq %rdi # save arg list ptr + pushq %rcx # save count + leaq 8(,%rcx,8), %rdi # 8 (length) + count * 8 + call heap_alloc +.ifdef GC_NAIVE + orq $(HT_VECTOR << 8), -8(%rax) +.endif + popq %rcx + popq %rdi # restore arg list + movq %rcx, (%rax) # length # Fill elements from arg list - movq %rdi, %rdx # arg list - leaq 8(%rax), %rdi # elements start + movq %rdi, %rdx # arg list + leaq 8(%rax), %rdi # elements start .bvec_fill: cmpq $VAL_NIL, %rdx je .bvec_done2 @@ -4627,15 +4656,21 @@ bi_vector: bi_makevec: # (make-vector n fill) — allocate n-slot vector filled with `fill`. - # GETARG uses %rax as scratch, so we MUST stash the length in a - # callee-safe register before consuming the second arg. GETARG %rax sarq $3, %rax # n (untagged) movq %rax, %rdx # save n in %rdx — survives next GETARG GETARG %rcx # fill value (tagged) - movq %r15, %rax # vector obj pointer - movq %rdx, (%r15) # store length - leaq 8(%r15,%rdx,8), %r15 # advance heap past length + n*8 bytes + # Route through heap_alloc so GC build gets header + type. + pushq %rdx # n + pushq %rcx # fill value + leaq 8(,%rdx,8), %rdi # bytes: 8 (length) + n*8 + call heap_alloc +.ifdef GC_NAIVE + orq $(HT_VECTOR << 8), -8(%rax) +.endif + popq %rcx # fill + popq %rdx # n + movq %rdx, (%rax) # store length leaq 8(%rax), %rdi # elements start movq %rdx, %rsi # count = n .bmv_fill: @@ -4725,11 +4760,18 @@ bi_listtovec: movq 8(%rdx), %rax jmp .bl2v_count .bl2v_alloc: - movq %r15, %rax - movq %rcx, (%r15) - leaq 8(%r15,%rcx,8), %r15 - leaq 8(%rax), %rdi - movq %rsi, %rdx + pushq %rsi # save list ptr + pushq %rcx # save count + leaq 8(,%rcx,8), %rdi # 8 + count*8 + call heap_alloc +.ifdef GC_NAIVE + orq $(HT_VECTOR << 8), -8(%rax) +.endif + popq %rcx + popq %rsi + movq %rcx, (%rax) # length + leaq 8(%rax), %rdi # element cursor + movq %rsi, %rdx # list cursor .bl2v_fill: cmpq $VAL_NIL, %rdx je .bl2v_done @@ -4755,11 +4797,24 @@ bi_substr: GETARG %rax # end sarq $3, %rax subq %rcx, %rax # length = end - start - movq %r15, %rdx # result - movq %rax, (%r15) # length - leaq 8(%r15), %rsi # dest - leaq 8(%rdi,%rcx,1), %rdi # src - movq %rax, %rcx + # Allocate via heap_alloc: 8 (length word) + length bytes. + pushq %rdi # src base + pushq %rcx # start offset + pushq %rax # length + movq %rax, %rdi + addq $8, %rdi # total payload + call heap_alloc +.ifdef GC_NAIVE + orq $(HT_STRING << 8), -8(%rax) +.endif + popq %rdx # length (restore) + popq %rcx # start + popq %rdi # src base + movq %rdx, (%rax) # write length + leaq 8(%rax), %rsi # dest cursor + leaq 8(%rdi,%rcx,1), %rdi # src cursor + movq %rdx, %rcx # bytes to copy + movq %rax, %rdx # save result base .bsub_copy: testq %rcx, %rcx jz .bsub_done @@ -4770,11 +4825,6 @@ bi_substr: decq %rcx jmp .bsub_copy .bsub_done: - movq (%rdx), %rax # length - addq $8, %rax - addq $7, %rax - andq $-8, %rax - addq %rax, %r15 movq %rdx, %rax orq $TAG_STRING, %rax RET_VAL @@ -5296,6 +5346,9 @@ bi_file_to_string: movq %rbp, %rdi addq $8, %rdi call heap_alloc # %rax = ptr +.ifdef GC_NAIVE + orq $(HT_STRING << 8), -8(%rax) +.endif movq %rax, %r12 # save heap pointer movq %rbp, (%r12) # store length @@ -5430,6 +5483,9 @@ bi_symbol_to_string: movq %rcx, %rdi addq $8, %rdi # cell size: 8-byte length + bytes call heap_alloc +.ifdef GC_NAIVE + orq $(HT_STRING << 8), -8(%rax) +.endif popq %r8 popq %rcx @@ -5548,6 +5604,9 @@ ht_chain_find: bi_make_hash_table: movq $HT_TOTAL_BYTES, %rdi call heap_alloc +.ifdef GC_NAIVE + orq $(HT_HASHTABLE << 8), -8(%rax) +.endif movq $HT_SENTINEL, (%rax) movq $0, 8(%rax) # count movq $HT_NBUCKETS, 16(%rax) @@ -5928,6 +5987,9 @@ hs_chain_find: bi_make_hash_set: movq $HT_TOTAL_BYTES, %rdi call heap_alloc +.ifdef GC_NAIVE + orq $(HT_HASHSET << 8), -8(%rax) +.endif movq $HS_SENTINEL, (%rax) movq $0, 8(%rax) movq $HT_NBUCKETS, 16(%rax) @@ -6331,7 +6393,7 @@ arena_verify_and_commit: movq (%rbx), %rax testq $1, %rax jnz .avc_escape - shrq $1, %rax + shrq $16, %rax leaq 8(%rbx,%rax), %rbx jmp .avc_scan .avc_safe: @@ -6626,6 +6688,9 @@ bi_tcp_recv: movq %rbp, %rdi addq $8, %rdi call heap_alloc +.ifdef GC_NAIVE + orq $(HT_STRING << 8), -8(%rax) +.endif movq %rax, %r12 # string object base # read(fd, cell+8, size) diff --git a/whitepaper/uncommonlisp-whitepaper.pdf b/whitepaper/uncommonlisp-whitepaper.pdf index 8715dcb..0f831de 100644 --- a/whitepaper/uncommonlisp-whitepaper.pdf +++ b/whitepaper/uncommonlisp-whitepaper.pdf @@ -3,7 +3,7 @@ 1 0 obj << /F1 2 0 R /F2 4 0 R /F3 5 0 R /F4 6 0 R /F5 10 0 R /F6 14 0 R - /F7 30 0 R /F8 32 0 R /F9 35 0 R + /F7 30 0 R /F8 32 0 R /F9 36 0 R >> endobj 2 0 obj @@ -62,7 +62,7 @@ endobj endobj 11 0 obj << -/Annots [ 7 0 R 8 0 R 9 0 R ] /Contents 130 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Annots [ 7 0 R 8 0 R 9 0 R ] /Contents 131 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << /FormXob.d3ecd28ca03f587d6940049748681018 3 0 R >> @@ -74,7 +74,7 @@ endobj endobj 12 0 obj << -/Contents 131 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 132 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -97,7 +97,7 @@ endobj endobj 15 0 obj << -/Contents 132 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 133 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << /FormXob.a2c922509fa3b1785bcd08461c0457b3 13 0 R >> @@ -109,7 +109,7 @@ endobj endobj 16 0 obj << -/Contents 133 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 134 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -119,7 +119,7 @@ endobj endobj 17 0 obj << -/Contents 134 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 135 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -129,7 +129,7 @@ endobj endobj 18 0 obj << -/Contents 135 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 136 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -139,7 +139,7 @@ endobj endobj 19 0 obj << -/Contents 136 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 137 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -149,7 +149,7 @@ endobj endobj 20 0 obj << -/Contents 137 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 138 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -191,7 +191,7 @@ Gb"0;!=8`+$j31%en endobj 25 0 obj << -/Contents 138 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 139 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << /FormXob.6378944cfcd9d967b8dea9d1fdf81282 21 0 R /FormXob.914f0cd152b732307eb1a2bfb0d863fa 23 0 R >> @@ -203,7 +203,7 @@ endobj endobj 26 0 obj << -/Contents 139 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 140 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -229,7 +229,7 @@ Gb"-V$![tprs/%kVg[G]8def./P7Hpb+:.UemqF`fg8QAVF'*,<$Kl#'U!md[DeE%MedO?I4&91M?!Bo endobj 29 0 obj << -/Contents 140 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 141 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << /FormXob.873240933f8ffe126f95df55e941dd3a 27 0 R /FormXob.ac4d2a97676ca8c002b2001987b87b9d 28 0 R >> @@ -246,7 +246,7 @@ endobj endobj 31 0 obj << -/Contents 141 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 142 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -261,7 +261,7 @@ endobj endobj 33 0 obj << -/Contents 142 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 143 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -271,7 +271,7 @@ endobj endobj 34 0 obj << -/Contents 143 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 144 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -281,12 +281,7 @@ endobj endobj 35 0 obj << -/BaseFont /ZapfDingbats /Name /F9 /Subtype /Type1 /Type /Font ->> -endobj -36 0 obj -<< -/Contents 144 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 145 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -294,9 +289,14 @@ endobj /Type /Page >> endobj +36 0 obj +<< +/BaseFont /ZapfDingbats /Name /F9 /Subtype /Type1 /Type /Font +>> +endobj 37 0 obj << -/Contents 145 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 146 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -306,7 +306,7 @@ endobj endobj 38 0 obj << -/Contents 146 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 147 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -316,7 +316,7 @@ endobj endobj 39 0 obj << -/Contents 147 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 148 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -326,7 +326,7 @@ endobj endobj 40 0 obj << -/Contents 148 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 149 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -336,7 +336,7 @@ endobj endobj 41 0 obj << -/Contents 149 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 150 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -348,12 +348,12 @@ endobj << /A << /S /URI /Type /Action /URI (mailto:russell@unturf.com) ->> /Border [ 0 0 0 ] /Rect [ 248.0736 593.8236 334.3536 605.8236 ] /Subtype /Link /Type /Annot +>> /Border [ 0 0 0 ] /Rect [ 248.0736 137.4236 334.3536 149.4236 ] /Subtype /Link /Type /Annot >> endobj 43 0 obj << -/Annots [ 42 0 R ] /Contents 150 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Annots [ 42 0 R ] /Contents 151 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -387,7 +387,7 @@ Gb"-VGBahP*ld_dH@X@.673m]5Z!>/OUajVKd+rl%FU.GOCIDSUkBirLgj0l#UggK9*dsQ$&!I6Uj!Oc endobj 47 0 obj << -/Contents 151 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 152 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << /FormXob.02a72be19fedaa76bd1061921e7cc82b 46 0 R /FormXob.baaa2211732baa0f94f6912a5b035550 44 0 R >> @@ -399,7 +399,7 @@ endobj endobj 48 0 obj << -/Contents 152 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 153 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -409,7 +409,7 @@ endobj endobj 49 0 obj << -/Contents 153 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 154 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -427,7 +427,7 @@ Gb",k#?V^BhM4rA',+)6h&$gSeal+> @@ -439,7 +439,7 @@ endobj endobj 52 0 obj << -/Contents 155 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 156 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -463,7 +463,7 @@ endobj endobj 55 0 obj << -/Annots [ 53 0 R 54 0 R ] /Contents 156 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Annots [ 53 0 R 54 0 R ] /Contents 157 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -473,7 +473,7 @@ endobj endobj 56 0 obj << -/Contents 157 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 158 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -497,7 +497,7 @@ endobj endobj 59 0 obj << -/Annots [ 57 0 R 58 0 R ] /Contents 158 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Annots [ 57 0 R 58 0 R ] /Contents 159 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -521,7 +521,7 @@ endobj endobj 62 0 obj << -/Annots [ 60 0 R 61 0 R ] /Contents 159 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Annots [ 60 0 R 61 0 R ] /Contents 160 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -547,7 +547,7 @@ Gb"0;0`_7S!5bE.WFlYNTE"rlzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz endobj 65 0 obj << -/Contents 160 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 161 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << /FormXob.d3ecd28ca03f587d6940049748681018 3 0 R /FormXob.fc331aff86ff817ecac4c4ce4b2ecd3a 63 0 R >> @@ -559,7 +559,7 @@ endobj endobj 66 0 obj << -/Contents 161 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 129 0 R /Resources << +/Contents 162 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 130 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -569,23 +569,23 @@ endobj endobj 67 0 obj << -/Outlines 69 0 R /PageLabels 162 0 R /PageMode /UseNone /Pages 129 0 R /Type /Catalog +/Outlines 69 0 R /PageLabels 163 0 R /PageMode /UseNone /Pages 130 0 R /Type /Catalog >> endobj 68 0 obj << -/Author () /CreationDate (D:20260418161103-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260418161103-04'00') /Producer (ReportLab PDF Library - \(opensource\)) +/Author () /CreationDate (D:20260418193310-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260418193310-04'00') /Producer (ReportLab PDF Library - \(opensource\)) /Subject (\(unspecified\)) /Title () /Trapped /False >> endobj 69 0 obj << -/Count 69 /First 70 0 R /Last 70 0 R /Type /Outlines +/Count 70 /First 70 0 R /Last 70 0 R /Type /Outlines >> endobj 70 0 obj << -/Count 58 /Dest [ 11 0 R /XYZ 57.02362 525.9477 0 ] /First 71 0 R /Last 128 0 R /Parent 69 0 R /Title (Lumbda) +/Count 59 /Dest [ 11 0 R /XYZ 57.02362 525.9477 0 ] /First 71 0 R /Last 129 0 R /Parent 69 0 R /Title (Lumbda) >> endobj 71 0 obj @@ -663,7 +663,7 @@ endobj endobj 85 0 obj << -/Count 10 /Dest [ 19 0 R /XYZ 57.02362 231.8236 0 ] /First 86 0 R /Last 91 0 R /Next 96 0 R /Parent 70 0 R +/Count 11 /Dest [ 19 0 R /XYZ 57.02362 231.8236 0 ] /First 86 0 R /Last 91 0 R /Next 97 0 R /Parent 70 0 R /Prev 81 0 R /Title (6. Benchmarks: Three Evaluators vs CPython) >> endobj @@ -694,7 +694,7 @@ endobj endobj 91 0 obj << -/Count 4 /Dest [ 26 0 R /XYZ 57.02362 173.0236 0 ] /First 92 0 R /Last 95 0 R /Parent 85 0 R /Prev 90 0 R +/Count 5 /Dest [ 26 0 R /XYZ 57.02362 173.0236 0 ] /First 92 0 R /Last 96 0 R /Parent 85 0 R /Prev 90 0 R /Title (6.6 Memory Management and the Meta-GC) >> endobj @@ -715,187 +715,192 @@ endobj endobj 95 0 obj << -/Dest [ 34 0 R /XYZ 57.02362 765.0236 0 ] /Parent 91 0 R /Prev 94 0 R /Title (6.6.4 Validation: HTTP Server Under Sustained Load) +/Dest [ 34 0 R /XYZ 57.02362 765.0236 0 ] /Next 96 0 R /Parent 91 0 R /Prev 94 0 R /Title (6.6.4 Validation: HTTP Server Under Sustained Load) >> endobj 96 0 obj << -/Count 7 /Dest [ 34 0 R /XYZ 57.02362 225.0236 0 ] /First 97 0 R /Last 103 0 R /Next 104 0 R /Parent 70 0 R - /Prev 85 0 R /Title (7. Portal: Feedback Across Time) +/Dest [ 34 0 R /XYZ 57.02362 207.0236 0 ] /Parent 91 0 R /Prev 95 0 R /Title (6.6.5 Precise Block Typing: Killing a Class of Bugs) >> endobj 97 0 obj << -/Dest [ 36 0 R /XYZ 57.02362 727.0236 0 ] /Next 98 0 R /Parent 96 0 R /Title (7.1 S-Expression Portal \204 the Portable One) +/Count 7 /Dest [ 35 0 R /XYZ 57.02362 562.6236 0 ] /First 98 0 R /Last 104 0 R /Next 105 0 R /Parent 70 0 R + /Prev 85 0 R /Title (7. Portal: Feedback Across Time) >> endobj 98 0 obj << -/Dest [ 36 0 R /XYZ 57.02362 485.8236 0 ] /Next 99 0 R /Parent 96 0 R /Prev 97 0 R /Title (7.2 Cross-Implementation Exchange Matrix) +/Dest [ 35 0 R /XYZ 57.02362 359.4236 0 ] /Next 99 0 R /Parent 97 0 R /Title (7.1 S-Expression Portal \204 the Portable One) >> endobj 99 0 obj << -/Dest [ 36 0 R /XYZ 57.02362 285.8236 0 ] /Next 100 0 R /Parent 96 0 R /Prev 98 0 R /Title (7.3 JSON Portal \204 Graph-Aware, Continuation-Preserving) +/Dest [ 35 0 R /XYZ 57.02362 118.2236 0 ] /Next 100 0 R /Parent 97 0 R /Prev 98 0 R /Title (7.2 Cross-Implementation Exchange Matrix) >> endobj 100 0 obj << -/Dest [ 37 0 R /XYZ 57.02362 708.2236 0 ] /Next 101 0 R /Parent 96 0 R /Prev 99 0 R /Title (7.4 Binary Heap Dump \204 the Fast One) +/Dest [ 37 0 R /XYZ 57.02362 607.0236 0 ] /Next 101 0 R /Parent 97 0 R /Prev 99 0 R /Title (7.3 JSON Portal \204 Graph-Aware, Continuation-Preserving) >> endobj 101 0 obj << -/Dest [ 37 0 R /XYZ 57.02362 456.2236 0 ] /Next 102 0 R /Parent 96 0 R /Prev 100 0 R /Title (7.5 Cross-Process Benchmarks) +/Dest [ 37 0 R /XYZ 57.02362 320.2236 0 ] /Next 102 0 R /Parent 97 0 R /Prev 100 0 R /Title (7.4 Binary Heap Dump \204 the Fast One) >> endobj 102 0 obj << -/Dest [ 37 0 R /XYZ 57.02362 142.2236 0 ] /Next 103 0 R /Parent 96 0 R /Prev 101 0 R /Title (7.6 Mismatch Cases: Graceful Degradation) +/Dest [ 38 0 R /XYZ 57.02362 765.0236 0 ] /Next 103 0 R /Parent 97 0 R /Prev 101 0 R /Title (7.5 Cross-Process Benchmarks) >> endobj 103 0 obj << -/Dest [ 38 0 R /XYZ 57.02362 571.0236 0 ] /Parent 96 0 R /Prev 102 0 R /Title (7.7 Use Case: Distributed Primality Testing) +/Dest [ 38 0 R /XYZ 57.02362 451.0236 0 ] /Next 104 0 R /Parent 97 0 R /Prev 102 0 R /Title (7.6 Mismatch Cases: Graceful Degradation) >> endobj 104 0 obj << -/Count 6 /Dest [ 38 0 R /XYZ 57.02362 370.2236 0 ] /First 105 0 R /Last 110 0 R /Next 111 0 R /Parent 70 0 R - /Prev 96 0 R /Title (8. The EML Universality Proof) +/Dest [ 39 0 R /XYZ 57.02362 765.0236 0 ] /Parent 97 0 R /Prev 103 0 R /Title (7.7 Use Case: Distributed Primality Testing) >> endobj 105 0 obj << -/Dest [ 38 0 R /XYZ 57.02362 293.0236 0 ] /Next 106 0 R /Parent 104 0 R /Title (8.1 The Operator) +/Count 6 /Dest [ 39 0 R /XYZ 57.02362 564.2236 0 ] /First 106 0 R /Last 111 0 R /Next 112 0 R /Parent 70 0 R + /Prev 97 0 R /Title (8. The EML Universality Proof) >> endobj 106 0 obj << -/Dest [ 38 0 R /XYZ 57.02362 216.2236 0 ] /Next 107 0 R /Parent 104 0 R /Prev 105 0 R /Title (8.2 Stage 1: Core Functions \(Depth 1--3\)) +/Dest [ 39 0 R /XYZ 57.02362 487.0236 0 ] /Next 107 0 R /Parent 105 0 R /Title (8.1 The Operator) >> endobj 107 0 obj << -/Dest [ 39 0 R /XYZ 57.02362 765.0236 0 ] /Next 108 0 R /Parent 104 0 R /Prev 106 0 R /Title (8.3 Stage 2: Arithmetic) +/Dest [ 39 0 R /XYZ 57.02362 410.2236 0 ] /Next 108 0 R /Parent 105 0 R /Prev 106 0 R /Title (8.2 Stage 1: Core Functions \(Depth 1--3\)) >> endobj 108 0 obj << -/Dest [ 39 0 R /XYZ 57.02362 650.6236 0 ] /Next 109 0 R /Parent 104 0 R /Prev 107 0 R /Title (8.4 Stage 3: Complex Plane Access) +/Dest [ 39 0 R /XYZ 57.02362 290.2236 0 ] /Next 109 0 R /Parent 105 0 R /Prev 107 0 R /Title (8.3 Stage 2: Arithmetic) >> endobj 109 0 obj << -/Dest [ 39 0 R /XYZ 57.02362 542.6236 0 ] /Next 110 0 R /Parent 104 0 R /Prev 108 0 R /Title (8.5 Stage 4: Trigonometry via Euler) +/Dest [ 39 0 R /XYZ 57.02362 175.8236 0 ] /Next 110 0 R /Parent 105 0 R /Prev 108 0 R /Title (8.4 Stage 3: Complex Plane Access) >> endobj 110 0 obj << -/Dest [ 39 0 R /XYZ 57.02362 446.6236 0 ] /Parent 104 0 R /Prev 109 0 R /Title (8.6 Verification & Friction Analysis) +/Dest [ 40 0 R /XYZ 57.02362 765.0236 0 ] /Next 111 0 R /Parent 105 0 R /Prev 109 0 R /Title (8.5 Stage 4: Trigonometry via Euler) >> endobj 111 0 obj << -/Dest [ 41 0 R /XYZ 57.02362 441.0236 0 ] /Next 112 0 R /Parent 70 0 R /Prev 104 0 R /Title (9. Language Coverage) +/Dest [ 40 0 R /XYZ 57.02362 669.0236 0 ] /Parent 105 0 R /Prev 110 0 R /Title (8.6 Verification & Friction Analysis) >> endobj 112 0 obj << -/Dest [ 41 0 R /XYZ 57.02362 191.8236 0 ] /Next 113 0 R /Parent 70 0 R /Prev 111 0 R /Title (10. Relationship to Companion Papers) +/Dest [ 43 0 R /XYZ 57.02362 675.0236 0 ] /Next 113 0 R /Parent 70 0 R /Prev 105 0 R /Title (9. Language Coverage) >> endobj 113 0 obj << -/Count 6 /Dest [ 43 0 R /XYZ 57.02362 633.0236 0 ] /First 114 0 R /Last 119 0 R /Next 120 0 R /Parent 70 0 R - /Prev 112 0 R /Title (11. Four Implementation Tiers, One Language) +/Dest [ 43 0 R /XYZ 57.02362 425.8236 0 ] /Next 114 0 R /Parent 70 0 R /Prev 112 0 R /Title (10. Relationship to Companion Papers) >> endobj 114 0 obj << -/Dest [ 48 0 R /XYZ 57.02362 277.0236 0 ] /Next 115 0 R /Parent 113 0 R /Title (11.1 Test Coverage) +/Count 6 /Dest [ 43 0 R /XYZ 57.02362 176.6236 0 ] /First 115 0 R /Last 120 0 R /Next 121 0 R /Parent 70 0 R + /Prev 113 0 R /Title (11. Four Implementation Tiers, One Language) >> endobj 115 0 obj << -/Dest [ 49 0 R /XYZ 57.02362 765.0236 0 ] /Next 116 0 R /Parent 113 0 R /Prev 114 0 R /Title (11.2 File I/O Parity) +/Dest [ 48 0 R /XYZ 57.02362 277.0236 0 ] /Next 116 0 R /Parent 114 0 R /Title (11.1 Test Coverage) >> endobj 116 0 obj << -/Dest [ 49 0 R /XYZ 57.02362 457.0236 0 ] /Next 117 0 R /Parent 113 0 R /Prev 115 0 R /Title (11.3 Sockets: One HTTP Server, Three Runtimes) +/Dest [ 49 0 R /XYZ 57.02362 765.0236 0 ] /Next 117 0 R /Parent 114 0 R /Prev 115 0 R /Title (11.2 File I/O Parity) >> endobj 117 0 obj << -/Dest [ 51 0 R /XYZ 57.02362 506.6988 0 ] /Next 118 0 R /Parent 113 0 R /Prev 116 0 R /Title (11.4 S-expressions over Sockets: RPC, REPL, and Chains) +/Dest [ 49 0 R /XYZ 57.02362 457.0236 0 ] /Next 118 0 R /Parent 114 0 R /Prev 116 0 R /Title (11.3 Sockets: One HTTP Server, Three Runtimes) >> endobj 118 0 obj << -/Dest [ 52 0 R /XYZ 57.02362 673.0236 0 ] /Next 119 0 R /Parent 113 0 R /Prev 117 0 R /Title (11.5 Portal over HTTP: State Transfer Between Machines) +/Dest [ 51 0 R /XYZ 57.02362 506.6988 0 ] /Next 119 0 R /Parent 114 0 R /Prev 117 0 R /Title (11.4 S-expressions over Sockets: RPC, REPL, and Chains) >> endobj 119 0 obj << -/Dest [ 52 0 R /XYZ 57.02362 124.6236 0 ] /Parent 113 0 R /Prev 118 0 R /Title (11.6 heap-snapshot: The Arena Escape Hatch) +/Dest [ 52 0 R /XYZ 57.02362 673.0236 0 ] /Next 120 0 R /Parent 114 0 R /Prev 118 0 R /Title (11.5 Portal over HTTP: State Transfer Between Machines) >> endobj 120 0 obj << -/Count 3 /Dest [ 55 0 R /XYZ 57.02362 477.4236 0 ] /First 121 0 R /Last 123 0 R /Next 124 0 R /Parent 70 0 R - /Prev 113 0 R /Title (12. MOAD Audit: Fixing What We Built) +/Dest [ 52 0 R /XYZ 57.02362 124.6236 0 ] /Parent 114 0 R /Prev 119 0 R /Title (11.6 heap-snapshot: The Arena Escape Hatch) >> endobj 121 0 obj << -/Dest [ 55 0 R /XYZ 57.02362 190.2236 0 ] /Next 122 0 R /Parent 120 0 R /Title (12.1 MOAD-0001: The Sedimentary Defect in Our Own Code) +/Count 3 /Dest [ 55 0 R /XYZ 57.02362 477.4236 0 ] /First 122 0 R /Last 124 0 R /Next 125 0 R /Parent 70 0 R + /Prev 114 0 R /Title (12. MOAD Audit: Fixing What We Built) >> endobj 122 0 obj << -/Dest [ 56 0 R /XYZ 57.02362 265.0236 0 ] /Next 123 0 R /Parent 120 0 R /Prev 121 0 R /Title (12.2 MOAD-0002: The Intertangle in Our Own Design) +/Dest [ 55 0 R /XYZ 57.02362 190.2236 0 ] /Next 123 0 R /Parent 121 0 R /Title (12.1 MOAD-0001: The Sedimentary Defect in Our Own Code) >> endobj 123 0 obj << -/Dest [ 59 0 R /XYZ 57.02362 715.0236 0 ] /Parent 120 0 R /Prev 122 0 R /Title (12.3 Our Shared Infrastructure) +/Dest [ 56 0 R /XYZ 57.02362 265.0236 0 ] /Next 124 0 R /Parent 121 0 R /Prev 122 0 R /Title (12.2 MOAD-0002: The Intertangle in Our Own Design) >> endobj 124 0 obj << -/Dest [ 59 0 R /XYZ 57.02362 523.0236 0 ] /Next 125 0 R /Parent 70 0 R /Prev 120 0 R /Title (13. Future Work) +/Dest [ 59 0 R /XYZ 57.02362 715.0236 0 ] /Parent 121 0 R /Prev 123 0 R /Title (12.3 Our Shared Infrastructure) >> endobj 125 0 obj << -/Dest [ 59 0 R /XYZ 57.02362 267.8236 0 ] /Next 126 0 R /Parent 70 0 R /Prev 124 0 R /Title (14. The Defect in the Model) +/Dest [ 59 0 R /XYZ 57.02362 523.0236 0 ] /Next 126 0 R /Parent 70 0 R /Prev 121 0 R /Title (13. Future Work) >> endobj 126 0 obj << -/Dest [ 62 0 R /XYZ 57.02362 297.0236 0 ] /Next 127 0 R /Parent 70 0 R /Prev 125 0 R /Title (Citation) +/Dest [ 59 0 R /XYZ 57.02362 267.8236 0 ] /Next 127 0 R /Parent 70 0 R /Prev 125 0 R /Title (14. The Defect in the Model) >> endobj 127 0 obj << -/Dest [ 62 0 R /XYZ 57.02362 215.8236 0 ] /Next 128 0 R /Parent 70 0 R /Prev 126 0 R /Title (References) +/Dest [ 62 0 R /XYZ 57.02362 297.0236 0 ] /Next 128 0 R /Parent 70 0 R /Prev 126 0 R /Title (Citation) >> endobj 128 0 obj << -/Dest [ 62 0 R /XYZ 57.02362 134.6236 0 ] /Parent 70 0 R /Prev 127 0 R /Title (License) +/Dest [ 62 0 R /XYZ 57.02362 215.8236 0 ] /Next 129 0 R /Parent 70 0 R /Prev 127 0 R /Title (References) >> endobj 129 0 obj << +/Dest [ 62 0 R /XYZ 57.02362 134.6236 0 ] /Parent 70 0 R /Prev 128 0 R /Title (License) +>> +endobj +130 0 obj +<< /Count 32 /Kids [ 11 0 R 12 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 25 0 R 26 0 R - 29 0 R 31 0 R 33 0 R 34 0 R 36 0 R 37 0 R 38 0 R 39 0 R 40 0 R 41 0 R + 29 0 R 31 0 R 33 0 R 34 0 R 35 0 R 37 0 R 38 0 R 39 0 R 40 0 R 41 0 R 43 0 R 47 0 R 48 0 R 49 0 R 51 0 R 52 0 R 55 0 R 56 0 R 59 0 R 62 0 R 65 0 R 66 0 R ] /Type /Pages >> endobj -130 0 obj +131 0 obj << /Length 5064 >> @@ -1076,7 +1081,7 @@ Q endstream endobj -131 0 obj +132 0 obj << /Length 8031 >> @@ -1177,7 +1182,7 @@ Q endstream endobj -132 0 obj +133 0 obj << /Length 4740 >> @@ -1340,7 +1345,7 @@ Q endstream endobj -133 0 obj +134 0 obj << /Length 6876 >> @@ -1655,7 +1660,7 @@ Q endstream endobj -134 0 obj +135 0 obj << /Length 8861 >> @@ -2166,7 +2171,7 @@ Q endstream endobj -135 0 obj +136 0 obj << /Length 9194 >> @@ -2608,7 +2613,7 @@ Q endstream endobj -136 0 obj +137 0 obj << /Length 9151 >> @@ -3019,7 +3024,7 @@ Q endstream endobj -137 0 obj +138 0 obj << /Length 12963 >> @@ -3749,7 +3754,7 @@ Q endstream endobj -138 0 obj +139 0 obj << /Length 10062 >> @@ -4216,7 +4221,7 @@ Q endstream endobj -139 0 obj +140 0 obj << /Length 9313 >> @@ -4450,7 +4455,7 @@ Q endstream endobj -140 0 obj +141 0 obj << /Length 8527 >> @@ -4774,7 +4779,7 @@ Q endstream endobj -141 0 obj +142 0 obj << /Length 10896 >> @@ -5144,7 +5149,7 @@ Q endstream endobj -142 0 obj +143 0 obj << /Length 12577 >> @@ -5766,9 +5771,9 @@ Q endstream endobj -143 0 obj +144 0 obj << -/Length 11866 +/Length 9957 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET @@ -5849,7 +5854,7 @@ q 1 0 0 1 188.8668 57 cm q 0 0 0 rg -BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (484) Tj T* ET +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (~300) Tj T* ET Q Q q @@ -5883,7 +5888,7 @@ q 1 0 0 1 188.8668 39 cm q 0 0 0 rg -BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (462) Tj T* ET +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (~330) Tj T* ET Q Q q @@ -5918,7 +5923,7 @@ q 1 0 0 1 188.8668 21 cm q 0 0 0 rg -BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (463) Tj T* ET +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (~360) Tj T* ET Q Q q @@ -5953,28 +5958,28 @@ q 1 0 0 1 188.8668 3 cm q 0 0 0 rg -BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (\206) Tj T* ET +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (~410) Tj T* ET Q Q q 1 0 0 1 256.2387 3 cm q 0 0 0 rg -BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (\227) Tj T* ET +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (116) Tj T* ET Q Q q 1 0 0 1 323.6107 3 cm q 0 0 0 rg -BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (\227) Tj T* ET +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (1,088) Tj T* ET Q Q q 1 0 0 1 390.9827 3 cm q 0 0 0 rg -BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (\227) Tj T* ET +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL (972) Tj T* ET Q Q q @@ -6004,29 +6009,22 @@ q 1 0 0 1 57.02362 561.0236 cm q 0 0 0 rg -BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (\206 Crashes at first GC \227 latent conservative-scan bug, see below.) Tj T* ET +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (All four cells validate cleanly now:) Tj T* ET Q Q q -1 0 0 1 57.02362 543.0236 cm -q -0 0 0 rg -BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Three cells validate cleanly:) Tj T* ET -Q +1 0 0 1 57.02362 555.0236 cm Q q -1 0 0 1 57.02362 537.0236 cm +1 0 0 1 57.02362 555.0236 cm Q q -1 0 0 1 57.02362 537.0236 cm -Q -q -1 0 0 1 57.02362 489.0236 cm +1 0 0 1 57.02362 519.0236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET q -1 0 0 1 6 33 cm +1 0 0 1 6 21 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F5 10 Tf 12 TL 8 0 Td (\177) Tj T* -8 0 Td ET @@ -6035,7 +6033,7 @@ Q q 1 0 0 1 23 -3 cm q -BT 1 0 0 1 0 38 Tm 2.862739 Tw 12 TL /F3 10 Tf 0 0 0 rg (Cells 1 and 2) Tj /F1 10 Tf ( show that on idiomatic code using ) Tj /F5 10 Tf (heap-snapshot) Tj /F1 10 Tf (, both binaries hold memory) Tj T* 0 Tw 2.169897 Tw (absolutely flat \(~4 KB growth over 5,000 requests is normal VM noise\). The GC build costs ~5%) Tj T* 0 Tw .488138 Tw (throughput for a feature the snapshot pattern doesn't need \227 a meaningful signal that if your server is) Tj T* 0 Tw (well-written, GC is optional overhead.) Tj T* ET +BT 1 0 0 1 0 26 Tm 2.862739 Tw 12 TL /F3 10 Tf 0 0 0 rg (Cells 1 and 2) Tj /F1 10 Tf ( show that on idiomatic code using ) Tj /F5 10 Tf (heap-snapshot) Tj /F1 10 Tf (, both binaries hold memory) Tj T* 0 Tw 1.372844 Tw (absolutely flat \(~4 KB growth over 5,000 requests is normal VM noise\). The GC build costs a small) Tj T* 0 Tw (throughput overhead for a feature the snapshot pattern doesn't need.) Tj T* ET Q Q q @@ -6043,10 +6041,10 @@ Q Q Q q -1 0 0 1 57.02362 483.0236 cm +1 0 0 1 57.02362 513.0236 cm Q q -1 0 0 1 57.02362 447.0236 cm +1 0 0 1 57.02362 477.0236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -6068,15 +6066,15 @@ Q Q Q q -1 0 0 1 57.02362 441.0236 cm +1 0 0 1 57.02362 471.0236 cm Q q -1 0 0 1 57.02362 369.0236 cm +1 0 0 1 57.02362 423.0236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET q -1 0 0 1 6 57 cm +1 0 0 1 6 33 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F5 10 Tf 12 TL 8 0 Td (\177) Tj T* -8 0 Td ET @@ -6085,7 +6083,7 @@ Q q 1 0 0 1 23 -3 cm q -BT 1 0 0 1 0 62 Tm .22755 Tw 12 TL /F3 10 Tf 0 0 0 rg (Cell 4) Tj /F1 10 Tf ( is the one that should have been bounded by naive mark-sweep and wasn't. The server crashes) Tj T* 0 Tw .520522 Tw (at the first GC trigger \(~1 MB of allocations into the run\), fixed-size workload triggering another variant) Tj T* 0 Tw .110556 Tw (of the conservative stack scan's type-confusion. The pattern is identical in kind to the 24-byte env/string) Tj T* 0 Tw 2.57389 Tw (collision \(\2476.6.1\) we already fixed \227 probably a 24- or 40-byte response block being walked as) Tj T* 0 Tw 1.145197 Tw (something it isn't. The fix requires tightening one more walker; we logged it as a known issue rather) Tj T* 0 Tw (than shipping a fix under time pressure.) Tj T* ET +BT 1 0 0 1 0 38 Tm .149314 Tw 12 TL /F3 10 Tf 0 0 0 rg (Cell 4) Tj /F1 10 Tf ( is the use case the GC was built for. With neither ) Tj /F5 10 Tf (heap-snapshot) Tj /F1 10 Tf ( nor ) Tj /F5 10 Tf (heap-restore) Tj /F1 10 Tf (, the GC) Tj T* 0 Tw 2.112556 Tw (build bounds memory at one chunk \(~1 MB\) and serves ) Tj /F3 10 Tf (faster than the leaking no-GC version) Tj /F1 10 Tf T* 0 Tw 2.680696 Tw (because it doesn't pay ) Tj /F5 10 Tf (heap_grow) Tj /F1 10 Tf ( mmap-every-64-MB costs on repeated allocation. ) Tj /F3 10 Tf (972 KB of) Tj T* 0 Tw (growth) Tj /F1 10 Tf ( across 5,000 requests is exactly one heap chunk \227 the collector hit its natural steady state.) Tj T* ET Q Q q @@ -6093,37 +6091,110 @@ Q Q Q q -1 0 0 1 57.02362 351.0236 cm +1 0 0 1 57.02362 405.0236 cm Q q -1 0 0 1 57.02362 273.0236 cm +1 0 0 1 57.02362 327.0236 cm q -BT 1 0 0 1 0 62 Tm .321079 Tw 12 TL /F3 10 Tf 0 0 0 rg (Honest read.) Tj /F1 10 Tf ( The GC build succeeds at validating the snapshot pattern \(cell 2 is the real deployment target) Tj T* 0 Tw .949314 Tw (for long-running asm servers\) but the "use GC instead of snapshots" use case \(cell 4\) has an outstanding) Tj T* 0 Tw .628941 Tw (correctness bug. ) Tj /F5 10 Tf (heap-snapshot) Tj /F1 10 Tf ( + ) Tj /F5 10 Tf (heap-restore) Tj /F1 10 Tf ( remain the recommended pattern for production asm) Tj T* 0 Tw 3.808556 Tw (code; the naive GC serves as a diagnostic backstop and as the control-group baseline for future) Tj T* 0 Tw 1.272256 Tw (memory-management work. This is still progress \227 we now have a concrete failing case to aim the next) Tj T* 0 Tw (round of debugging at, rather than a vague worry.) Tj T* ET +BT 1 0 0 1 0 62 Tm 5.961223 Tw 12 TL /F3 10 Tf 0 0 0 rg (Precise-type dispatch was the fix.) Tj /F1 10 Tf ( Cell 4 was crashing at first GC until we replaced the) Tj T* 0 Tw 1.538941 Tw (conservative-scan-plus-sentinel-checks walker with a precise one. Every heap block's 8-byte header now) Tj T* 0 Tw 3.27789 Tw (carries an explicit type byte at bits 8\22615 \(see \2476.6.5 below for the redesign\), so ) Tj /F5 10 Tf (gc_mark_drain) Tj /F1 10 Tf (,) Tj T* 0 Tw .88989 Tw /F5 10 Tf (gc_mark_env) Tj /F1 10 Tf (, and the arena-escape scan dispatch on the type byte instead of guessing from block size.) Tj T* 0 Tw 1.226147 Tw (This eliminated the entire class of "24-byte env vs string" / "40-byte vector vs string" type-confusion bugs) Tj T* 0 Tw (we'd been patching one-by-one.) Tj T* ET Q Q q -1 0 0 1 57.02362 243.0236 cm +1 0 0 1 57.02362 249.0236 cm +q +BT 1 0 0 1 0 62 Tm .666772 Tw 12 TL /F3 10 Tf 0 0 0 rg (Honest read.) Tj /F1 10 Tf ( The GC build now succeeds at the "GC instead of snapshots" use case. ) Tj /F5 10 Tf (heap-snapshot) Tj /F1 10 Tf ( +) Tj T* 0 Tw .132362 Tw /F5 10 Tf (heap-restore) Tj /F1 10 Tf ( remain the idiomatic production pattern \(they're cheaper per-request and portable across all) Tj T* 0 Tw .046373 Tw (tiers\), but the GC is finally a correct fallback for code that doesn't manage arenas explicitly. Remaining rough) Tj T* 0 Tw .567223 Tw (edge: on very heavy sustained allocation workloads \(hash-set benchmark at the ~1 MB/iter scale under the) Tj T* 0 Tw 2.390522 Tw (GC build\) we still see the occasional unbound-variable error that points to a root-scan edge case the) Tj T* 0 Tw (precise-type fix didn't completely close. Tracked as a follow-up.) Tj T* ET +Q +Q +q +1 0 0 1 57.02362 219.0236 cm q BT 1 0 0 1 0 14 Tm 91.99278 Tw 12 TL /F3 10 Tf 0 0 0 rg (Reproduce:) Tj /F1 10 Tf ( ) Tj /F5 10 Tf (make) Tj ( ) Tj (bench-gc-http) Tj /F1 10 Tf (. Tuning:) Tj T* 0 Tw /F5 10 Tf (REQUESTS=10000) Tj ( ) Tj (CONCURRENCY=16) Tj ( ) Tj (VCAP=524288) Tj ( ) Tj (bash) Tj ( ) Tj (tests/bench-gc-http.sh) Tj /F1 10 Tf (.) Tj T* ET Q Q q -1 0 0 1 57.02362 211.8236 cm +1 0 0 1 57.02362 195.0236 cm +q +BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (6.6.5 Precise Block Typing: Killing a Class of Bugs) Tj T* ET +Q +Q +q +1 0 0 1 57.02362 117.0236 cm +q +BT 1 0 0 1 0 62 Tm .088797 Tw 12 TL /F1 10 Tf 0 0 0 rg (Earlier versions of the meta-GC walkers inferred block type from ) Tj /F4 10 Tf (size) Tj /F1 10 Tf ( alone. A 24-byte block could be an env) Tj T* 0 Tw 1.498138 Tw (node, a closure, or a 16-character string; a 40-byte block could be a 4-element vector or a 25-character) Tj T* 0 Tw .485197 Tw (string. The walkers tried to guess and guessed wrong under the conservative stack scan \227 any stack word) Tj T* 0 Tw .905522 Tw (whose low 3 bits happened to match ) Tj /F5 10 Tf (TAG_SYM) Tj /F1 10 Tf ( or ) Tj /F5 10 Tf (7) Tj /F1 10 Tf ( \(vector-family\) would be dereferenced, its block's size) Tj T* 0 Tw 1.69589 Tw (read from the header, and the walker would interpret subsequent payload bytes as tagged child values.) Tj T* 0 Tw (Strings-as-vectors reading 200 bytes past their end was the canonical failure.) Tj T* ET +Q +Q +q +1 0 0 1 57.02362 99.02362 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (We fixed this by adding an explicit type byte to every heap block's header:) Tj T* ET +Q +Q + +endstream +endobj +145 0 obj +<< +/Length 9361 +>> +stream +1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET +q +1 0 0 1 57.02362 732.6236 cm +q +q +1 0 0 1 0 0 cm +q +1 0 0 1 6.6 6.6 cm +q +.662745 .662745 .662745 RG +.5 w +.960784 .960784 .960784 rg +n -6 -6 480.0283 31.2 re B* +Q +q +0 0 0 rg +BT 1 0 0 1 0 11.2 Tm /F5 8 Tf 9.6 TL (# Old: [size:63 | mark:1]) Tj T* (# New: [size:48 | type:8 | flags:8 \(mark at bit 0\)]) Tj T* ET +Q +Q +Q +Q +Q +q +1 0 0 1 57.02362 676.6236 cm +q +BT 1 0 0 1 0 38 Tm 5.818335 Tw 12 TL /F1 10 Tf 0 0 0 rg (Type constants \() Tj /F5 10 Tf (HT_PAIR) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (HT_CLOSURE) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (HT_STRING) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (HT_SYMBOL) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (HT_VECTOR) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (HT_HASHTABLE) Tj /F1 10 Tf (,) Tj T* 0 Tw .948196 Tw /F5 10 Tf (HT_HASHSET) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (HT_ENVNODE) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (HT_CHAINNODE) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (HT_PADDING) Tj /F1 10 Tf (\) are set at every ) Tj /F5 10 Tf (heap_alloc) Tj /F1 10 Tf ( call site in the) Tj T* 0 Tw .427686 Tw (GC build. Every walker \227 mark, escape-scan, sweep \227 now dispatches on the type byte instead of size. A) Tj T* 0 Tw (string can never be walked as a vector; an env node can never be confused with a closure.) Tj T* ET +Q +Q +q +1 0 0 1 57.02362 622.6236 cm +q +BT 1 0 0 1 0 38 Tm .051917 Tw 12 TL /F1 10 Tf 0 0 0 rg (Cost: one extra ) Tj /F5 10 Tf (orq) Tj /F1 10 Tf ( at each of ~15 allocation sites \(a few nanoseconds per call\) and 16 bits of header space) Tj T* 0 Tw 1.318726 Tw (per block \(negligible given minimum block size is 16 payload bytes + 8 header bytes\). Benefit: the entire) Tj T* 0 Tw .669353 Tw ("conservative scan misidentifies X as Y" class of bugs goes away. Cell 4 of \2476.6.4 flipped from "crashes at) Tj T* 0 Tw (first GC" to "working correctly" when this landed.) Tj T* ET +Q +Q +q +1 0 0 1 57.02362 580.6236 cm +q +BT 1 0 0 1 0 26 Tm .608647 Tw 12 TL /F1 10 Tf 0 0 0 rg (The precise-type change also simplified the walkers: the special-case "is the first word -1 \(hash-table\) or -2) Tj T* 0 Tw .998453 Tw (\(hash-set\) or a small positive number \(vector length\)" dispatch in ) Tj /F5 10 Tf (gc_mark_drain) Tj /F1 10 Tf ( collapsed into a single) Tj T* 0 Tw /F5 10 Tf (cmp) Tj /F1 10 Tf ( on the type byte. ~50 lines of heuristic-guessing code deleted.) Tj T* ET +Q +Q +q +1 0 0 1 57.02362 549.4236 cm q BT 1 0 0 1 0 2.2 Tm 13.2 TL /F2 11 Tf .133333 .133333 .133333 rg (7. Portal: Feedback Across Time) Tj T* ET Q Q q -1 0 0 1 57.02362 167.8236 cm +1 0 0 1 57.02362 505.4236 cm q BT 1 0 0 1 0 26 Tm .17989 Tw 12 TL /F1 10 Tf 0 0 0 rg (A continuation is feedback within a process. A portal is feedback across processes. Same primitive, different) Tj T* 0 Tw 1.06631 Tw (scope: capture machine state, serialize it, reload it elsewhere, resume. Lumbda ships three portal formats) Tj T* 0 Tw (with different tradeoffs & constituencies.) Tj T* ET Q Q q -1 0 0 1 57.02362 161.8236 cm +1 0 0 1 57.02362 499.4236 cm Q q -1 0 0 1 57.02362 65.82362 cm +1 0 0 1 57.02362 403.4236 cm q 1 1 1 rg n 0 96 481.2283 -18 re f* @@ -6326,38 +6397,29 @@ Q Q Q q -1 0 0 1 57.02362 65.82362 cm +1 0 0 1 57.02362 403.4236 cm Q - -endstream -endobj -144 0 obj -<< -/Length 9315 ->> -stream -1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q -1 0 0 1 57.02362 741.0236 cm +1 0 0 1 57.02362 373.4236 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .49713 Tw (Times measured on a 4-binding workload \(int + list + string + fib\(30\) result\) excluding process startup. "k" =) Tj T* 0 Tw (continuation.) Tj T* ET Q Q q -1 0 0 1 57.02362 715.0236 cm +1 0 0 1 57.02362 347.4236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (7.1 S-Expression Portal \227 the Portable One) Tj T* ET Q Q q -1 0 0 1 57.02362 697.0236 cm +1 0 0 1 57.02362 329.4236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (The most boring format is the most portable. An S-expression portal is a sequence of ) Tj /F5 10 Tf (define) Tj /F1 10 Tf ( forms:) Tj T* ET Q Q q -1 0 0 1 57.02362 627.8236 cm +1 0 0 1 57.02362 260.2236 cm q q 1 0 0 1 0 0 cm @@ -6378,77 +6440,106 @@ Q Q Q q -1 0 0 1 57.02362 595.8236 cm +1 0 0 1 57.02362 228.2236 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .550522 Tw (Every Scheme implementation in the world can already read this. No schema, no decoder, no version field.) Tj T* 0 Tw (The file is a Scheme program; loading it is evaluating it.) Tj T* ET Q Q q -1 0 0 1 57.02362 541.8236 cm +1 0 0 1 57.02362 174.2236 cm q BT 1 0 0 1 0 38 Tm .702256 Tw 12 TL /F3 10 Tf 0 0 0 rg (The key insight: the language IS the interchange format.) Tj /F1 10 Tf ( We did not design this. R. Kent Dybvig didn't.) Tj T* 0 Tw 1.188726 Tw (John McCarthy didn't. It is a structural consequence of homoiconicity: if the syntax of the language is the) Tj T* 0 Tw 5.458196 Tw (syntax of its data structures, then data serialization is language serialization. Portability across) Tj T* 0 Tw (implementations is free \227 it arrives with the parser.) Tj T* ET Q Q q -1 0 0 1 57.02362 499.8236 cm +1 0 0 1 57.02362 132.2236 cm q BT 1 0 0 1 0 26 Tm .511772 Tw 12 TL /F1 10 Tf 0 0 0 rg (Producer side: assemble the file with ) Tj /F5 10 Tf (\(display) Tj ( ) Tj (...\)) Tj /F1 10 Tf ( & ) Tj /F5 10 Tf (\(write) Tj ( ) Tj (...\)) Tj /F1 10 Tf ( to an output port. Consumer side:) Tj T* 0 Tw 3.693453 Tw /F5 10 Tf (\(load) Tj ( ) Tj ("file.sexp"\)) Tj /F1 10 Tf (. Both sides exist in every implementation, giving us a 3\3273 matrix of valid) Tj T* 0 Tw (exchanges.) Tj T* ET Q Q q -1 0 0 1 57.02362 473.8236 cm +1 0 0 1 57.02362 106.2236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (7.2 Cross-Implementation Exchange Matrix) Tj T* ET Q Q q -1 0 0 1 57.02362 461.8236 cm +1 0 0 1 57.02362 94.22362 cm Q q -1 0 0 1 57.02362 371.8236 cm +1 0 0 1 57.02362 76.22362 cm q 1 1 1 rg -n 0 90 481.2283 -18 re f* -.878431 .878431 .878431 rg -n 0 72 481.2283 -18 re f* -1 1 1 rg -n 0 54 481.2283 -18 re f* -.878431 .878431 .878431 rg -n 0 36 481.2283 -18 re f* -1 1 1 rg n 0 18 481.2283 -18 re f* 0 0 0 rg BT /F3 10 Tf 12 TL ET q -1 0 0 1 6 75 cm +1 0 0 1 6 3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 19.19482 0 Td (Producer ) Tj /F6 10 Tf 12 TL (\256) Tj /F3 10 Tf 12 TL T* -19.19482 0 Td ET Q Q q -1 0 0 1 112.9396 75 cm +1 0 0 1 112.9396 3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 39.43645 0 Td (Python) Tj T* -39.43645 0 Td ET Q Q q -1 0 0 1 237.7025 75 cm +1 0 0 1 237.7025 3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 52.77145 0 Td (C) Tj T* -52.77145 0 Td ET Q Q q -1 0 0 1 362.4654 75 cm +1 0 0 1 362.4654 3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 46.37645 0 Td (asm) Tj T* -46.37645 0 Td ET Q Q q +1 J +1 j +0 0 0 RG +.25 w +n 0 0 m 481.2283 0 l S +n 106.9396 0 m 106.9396 18 l S +n 231.7025 0 m 231.7025 18 l S +n 356.4654 0 m 356.4654 18 l S +n 0 18 m 481.2283 18 l S +n 0 0 m 0 18 l S +n 481.2283 0 m 481.2283 18 l S +Q +Q +Q + +endstream +endobj +146 0 obj +<< +/Length 8717 +>> +stream +1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET +q +1 0 0 1 57.02362 693.0236 cm +q +1 1 1 rg +n 0 72 481.2283 -18 re f* +.878431 .878431 .878431 rg +n 0 54 481.2283 -18 re f* +1 1 1 rg +n 0 36 481.2283 -18 re f* +.878431 .878431 .878431 rg +n 0 18 481.2283 -18 re f* +0 0 0 rg +BT /F3 10 Tf 12 TL ET +q 1 0 0 1 6 57 cm q 0 0 0 rg @@ -6550,52 +6641,51 @@ n 0 72 m 481.2283 72 l S n 0 54 m 481.2283 54 l S n 0 36 m 481.2283 36 l S n 0 18 m 481.2283 18 l S -n 106.9396 0 m 106.9396 90 l S -n 231.7025 0 m 231.7025 90 l S -n 356.4654 0 m 356.4654 90 l S -n 0 90 m 481.2283 90 l S +n 106.9396 0 m 106.9396 72 l S +n 231.7025 0 m 231.7025 72 l S +n 356.4654 0 m 356.4654 72 l S +n 0 0 m 0 72 l S +n 481.2283 0 m 481.2283 72 l S n 0 0 m 481.2283 0 l S -n 0 0 m 0 90 l S -n 481.2283 0 m 481.2283 90 l S Q Q Q q -1 0 0 1 57.02362 371.8236 cm +1 0 0 1 57.02362 693.0236 cm Q q -1 0 0 1 57.02362 341.8236 cm +1 0 0 1 57.02362 663.0236 cm q BT 1 0 0 1 0 14 Tm 3.901835 Tw 12 TL /F1 10 Tf 0 0 0 rg (9 of 9. Verified by ) Tj /F5 10 Tf (tests/portal-cross-test.sh) Tj /F1 10 Tf ( \() Tj /F3 10 Tf (make bench-portal-cross) Tj /F1 10 Tf (\). Same file, same) Tj T* 0 Tw (semantics, regardless of which process produced it.) Tj T* ET Q Q q -1 0 0 1 57.02362 299.8236 cm +1 0 0 1 57.02362 621.0236 cm q 0 0 0 rg BT 1 0 0 1 0 26 Tm /F1 10 Tf 12 TL .526019 Tw (This matters because it defeats the "version lock-in" trap. If the JSON portal were the only option, a Python) Tj T* 0 Tw 2.478453 Tw (3.15 producer could emit structures a C consumer couldn't parse. With S-expression portals, the only) Tj T* 0 Tw (dependency is a parser that handles the subset of forms in the file. Every implementation already has one.) Tj T* ET Q Q q -1 0 0 1 57.02362 273.8236 cm +1 0 0 1 57.02362 595.0236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (7.3 JSON Portal \227 Graph-Aware, Continuation-Preserving) Tj T* ET Q Q q -1 0 0 1 57.02362 243.8236 cm +1 0 0 1 57.02362 565.0236 cm q BT 1 0 0 1 0 14 Tm .373453 Tw 12 TL /F1 10 Tf 0 0 0 rg (When you need to preserve shared references, cycles, closures, or a ) Tj /F4 10 Tf (live continuation) Tj /F1 10 Tf (, S-expressions aren't) Tj T* 0 Tw (enough. The JSON portal \(Python & C\) performs graph-aware serialization:) Tj T* ET Q Q q -1 0 0 1 57.02362 237.8236 cm +1 0 0 1 57.02362 559.0236 cm Q q -1 0 0 1 57.02362 237.8236 cm +1 0 0 1 57.02362 559.0236 cm Q q -1 0 0 1 57.02362 225.8236 cm +1 0 0 1 57.02362 547.0236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -6617,10 +6707,10 @@ Q Q Q q -1 0 0 1 57.02362 219.8236 cm +1 0 0 1 57.02362 541.0236 cm Q q -1 0 0 1 57.02362 207.8236 cm +1 0 0 1 57.02362 529.0236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -6643,10 +6733,10 @@ Q Q Q q -1 0 0 1 57.02362 201.8236 cm +1 0 0 1 57.02362 523.0236 cm Q q -1 0 0 1 57.02362 189.8236 cm +1 0 0 1 57.02362 511.0236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -6668,10 +6758,10 @@ Q Q Q q -1 0 0 1 57.02362 183.8236 cm +1 0 0 1 57.02362 505.0236 cm Q q -1 0 0 1 57.02362 171.8236 cm +1 0 0 1 57.02362 493.0236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -6694,10 +6784,10 @@ Q Q Q q -1 0 0 1 57.02362 165.8236 cm +1 0 0 1 57.02362 487.0236 cm Q q -1 0 0 1 57.02362 153.8236 cm +1 0 0 1 57.02362 475.0236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -6720,31 +6810,22 @@ Q Q Q q -1 0 0 1 57.02362 135.8236 cm +1 0 0 1 57.02362 457.0236 cm Q q -1 0 0 1 57.02362 105.8236 cm +1 0 0 1 57.02362 427.0236 cm q BT 1 0 0 1 0 14 Tm 2.974168 Tw 12 TL /F1 10 Tf 0 0 0 rg (Deserialization is two-pass: shell pass creates empty object shells & assigns reference IDs, fill pass) Tj T* 0 Tw (populates pointers & values. This handles the closure-that-captures-itself pattern cleanly.) Tj T* ET Q Q q -1 0 0 1 57.02362 63.82362 cm +1 0 0 1 57.02362 385.0236 cm q BT 1 0 0 1 0 26 Tm 4.719816 Tw 12 TL /F1 10 Tf 0 0 0 rg (During VM execution, ) Tj /F5 10 Tf (portal-checkpoint!) Tj /F1 10 Tf ( triggers at ) Tj /F5 10 Tf (OP_JUMP) Tj /F1 10 Tf ( & ) Tj /F5 10 Tf (OP_TAIL_CALL) Tj /F1 10 Tf ( instructions,) Tj T* 0 Tw 1.439168 Tw (capturing the current continuation, serializing it to a ) Tj /F5 10 Tf (.portal) Tj /F1 10 Tf ( file, & continuing. Resumption restores the) Tj T* 0 Tw (saved state & continues execution from the exact instruction where the checkpoint occurred.) Tj T* ET Q Q - -endstream -endobj -145 0 obj -<< -/Length 9088 ->> -stream -1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q -1 0 0 1 57.02362 742.2236 cm +1 0 0 1 57.02362 354.2236 cm q q 1 0 0 1 0 0 cm @@ -6765,26 +6846,26 @@ Q Q Q q -1 0 0 1 57.02362 722.2236 cm +1 0 0 1 57.02362 334.2236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (The computation does not need to restart from the beginning.) Tj T* ET Q Q q -1 0 0 1 57.02362 696.2236 cm +1 0 0 1 57.02362 308.2236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (7.4 Binary Heap Dump \227 the Fast One) Tj T* ET Q Q q -1 0 0 1 57.02362 666.2236 cm +1 0 0 1 57.02362 278.2236 cm q BT 1 0 0 1 0 14 Tm .755197 Tw 12 TL /F1 10 Tf 0 0 0 rg (The asm implementation ships a direct-dump portal: write the raw heap bytes, the ) Tj /F5 10 Tf (r14) Tj /F1 10 Tf ( \(env\) & ) Tj /F5 10 Tf (r15) Tj /F1 10 Tf ( \(bump) Tj T* 0 Tw (pointer\) registers, the heap base address, & a magic header. No parsing, no encoding.) Tj T* ET Q Q q -1 0 0 1 57.02362 568.2236 cm +1 0 0 1 57.02362 180.2236 cm q q 1 0 0 1 0 0 cm @@ -6805,34 +6886,43 @@ Q Q Q q -1 0 0 1 57.02362 524.2236 cm +1 0 0 1 57.02362 136.2236 cm q BT 1 0 0 1 0 26 Tm 1.387739 Tw 12 TL /F1 10 Tf 0 0 0 rg (Sub-millisecond save & resume. The MAP_FIXED trick is why it works across processes: because every) Tj T* 0 Tw 1.474556 Tw (pointer inside the heap is an absolute address, resuming at a different address would require relocation.) Tj T* 0 Tw (Mapping at the same address keeps pointers live.) Tj T* ET Q Q q -1 0 0 1 57.02362 470.2236 cm +1 0 0 1 57.02362 82.22362 cm q BT 1 0 0 1 0 38 Tm 1.067739 Tw 12 TL /F1 10 Tf 0 0 0 rg (Constraints: same architecture, same binary layout, same process model. An asm binary portal written on) Tj T* 0 Tw .022545 Tw (one box resumes on another x86_64 Linux box running the same asm binary. It does not resume on a rebuilt) Tj T* 0 Tw 1.065522 Tw (binary \227 the BSS-resident symbol table ) Tj /F5 10 Tf (sym_table) Tj /F1 10 Tf ( is not in the heap dump, so interned symbols would) Tj T* 0 Tw (need to be reinterned. That's the price of trivial serialization.) Tj T* ET Q Q + +endstream +endobj +147 0 obj +<< +/Length 9918 +>> +stream +1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q -1 0 0 1 57.02362 444.2236 cm +1 0 0 1 57.02362 753.0236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (7.5 Cross-Process Benchmarks) Tj T* ET Q Q q -1 0 0 1 57.02362 402.2236 cm +1 0 0 1 57.02362 711.0236 cm q BT 1 0 0 1 0 26 Tm 2.703647 Tw 12 TL /F1 10 Tf 0 0 0 rg (Producer process A saves state to a file; consumer process B starts fresh, loads the file, continues.) Tj T* 0 Tw 10.67759 Tw (Wall-clock time for both processes end-to-end, 50 iterations, same-laptop. ) Tj /F3 10 Tf (Reproduce:) Tj /F1 10 Tf T* 0 Tw /F5 10 Tf (make) Tj ( ) Tj (bench-portal) Tj /F1 10 Tf ( \(source: ) Tj /F5 10 Tf (tests/portal-benchmark.sh) Tj /F1 10 Tf (\).) Tj T* ET Q Q q -1 0 0 1 57.02362 396.2236 cm +1 0 0 1 57.02362 705.0236 cm Q q -1 0 0 1 57.02362 198.2236 cm +1 0 0 1 57.02362 507.0236 cm q 1 1 1 rg n 0 198 481.2283 -18 re f* @@ -7038,125 +7128,37 @@ Q Q Q q -1 0 0 1 57.02362 198.2236 cm +1 0 0 1 57.02362 507.0236 cm Q q -1 0 0 1 57.02362 156.2236 cm +1 0 0 1 57.02362 465.0236 cm q BT 1 0 0 1 0 26 Tm .698334 Tw 12 TL /F1 10 Tf 0 0 0 rg (The asm) Tj /F6 10 Tf 12 TL (\256) Tj /F1 10 Tf 12 TL (asm cross-process is ~160\327 faster than Python) Tj /F6 10 Tf 12 TL (\256) Tj /F1 10 Tf 12 TL (Python. The binary & S-expression portals are) Tj T* 0 Tw .812256 Tw (within 10% of each other on this workload \227 the bottleneck is process startup, not serialization. For larger) Tj T* 0 Tw (heaps the binary format pulls further ahead; for portability, S-expression always wins.) Tj T* ET Q Q q -1 0 0 1 57.02362 130.2236 cm +1 0 0 1 57.02362 439.0236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (7.6 Mismatch Cases: Graceful Degradation) Tj T* ET Q Q q -1 0 0 1 57.02362 112.2236 cm +1 0 0 1 57.02362 421.0236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (A usable persistence layer fails well. What happens when the consumer meets unexpected input?) Tj T* ET Q Q q -1 0 0 1 57.02362 106.2236 cm +1 0 0 1 57.02362 415.0236 cm Q q -1 0 0 1 57.02362 70.22362 cm +1 0 0 1 57.02362 265.0236 cm q 1 1 1 rg -n 0 36 481.2283 -18 re f* +n 0 150 481.2283 -18 re f* .878431 .878431 .878431 rg -n 0 18 481.2283 -18 re f* -0 0 0 rg -BT /F3 10 Tf 12 TL ET -q -1 0 0 1 6 21 cm -q -0 0 0 rg -BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 96.07173 0 Td (Input) Tj T* -96.07173 0 Td ET -Q -Q -q -1 0 0 1 234.5835 21 cm -q -0 0 0 rg -BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 19.16248 0 Td (Python) Tj T* -19.16248 0 Td ET -Q -Q -q -1 0 0 1 318.7984 21 cm -q -0 0 0 rg -BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 32.49748 0 Td (C) Tj T* -32.49748 0 Td ET -Q -Q -q -1 0 0 1 403.0134 21 cm -q -0 0 0 rg -BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 26.10248 0 Td (asm) Tj T* -26.10248 0 Td ET -Q -Q -0 0 0 rg -BT /F1 10 Tf 12 TL ET -q -1 0 0 1 6 3 cm -q -0 0 0 rg -BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Empty file) Tj T* ET -Q -Q -q -1 0 0 1 234.5835 3 cm -q -0 0 0 rg -BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (continue) Tj T* ET -Q -Q -q -1 0 0 1 318.7984 3 cm -q -0 0 0 rg -BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (continue) Tj T* ET -Q -Q -q -1 0 0 1 403.0134 3 cm -q -0 0 0 rg -BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (continue) Tj T* ET -Q -Q -q -1 J -1 j -0 0 0 RG -.25 w -n 0 0 m 481.2283 0 l S -n 0 18 m 481.2283 18 l S -n 228.5835 0 m 228.5835 36 l S -n 312.7984 0 m 312.7984 36 l S -n 397.0134 0 m 397.0134 36 l S -n 0 36 m 481.2283 36 l S -n 0 0 m 0 36 l S -n 481.2283 0 m 481.2283 36 l S -Q -Q -Q - -endstream -endobj -146 0 obj -<< -/Length 7571 ->> -stream -1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET -q -1 0 0 1 57.02362 651.0236 cm -q +n 0 132 481.2283 -18 re f* 1 1 1 rg n 0 114 481.2283 -30 re f* .878431 .878431 .878431 rg @@ -7168,8 +7170,66 @@ n 0 36 481.2283 -18 re f* 1 1 1 rg n 0 18 481.2283 -18 re f* 0 0 0 rg +BT /F3 10 Tf 12 TL ET +q +1 0 0 1 6 135 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 96.07173 0 Td (Input) Tj T* -96.07173 0 Td ET +Q +Q +q +1 0 0 1 234.5835 135 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 19.16248 0 Td (Python) Tj T* -19.16248 0 Td ET +Q +Q +q +1 0 0 1 318.7984 135 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 32.49748 0 Td (C) Tj T* -32.49748 0 Td ET +Q +Q +q +1 0 0 1 403.0134 135 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 26.10248 0 Td (asm) Tj T* -26.10248 0 Td ET +Q +Q +0 0 0 rg BT /F1 10 Tf 12 TL ET q +1 0 0 1 6 117 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Empty file) Tj T* ET +Q +Q +q +1 0 0 1 234.5835 117 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (continue) Tj T* ET +Q +Q +q +1 0 0 1 318.7984 117 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (continue) Tj T* ET +Q +Q +q +1 0 0 1 403.0134 117 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (continue) Tj T* ET +Q +Q +q 1 0 0 1 6 99 cm q 0 0 0 rg @@ -7309,37 +7369,48 @@ q 1 j 0 0 0 RG .25 w +n 0 132 m 481.2283 132 l S n 0 114 m 481.2283 114 l S n 0 84 m 481.2283 84 l S n 0 54 m 481.2283 54 l S n 0 36 m 481.2283 36 l S n 0 18 m 481.2283 18 l S -n 228.5835 0 m 228.5835 114 l S -n 312.7984 0 m 312.7984 114 l S -n 397.0134 0 m 397.0134 114 l S -n 0 0 m 0 114 l S -n 481.2283 0 m 481.2283 114 l S +n 228.5835 0 m 228.5835 150 l S +n 312.7984 0 m 312.7984 150 l S +n 397.0134 0 m 397.0134 150 l S +n 0 150 m 481.2283 150 l S n 0 0 m 481.2283 0 l S +n 0 0 m 0 150 l S +n 481.2283 0 m 481.2283 150 l S Q Q Q q -1 0 0 1 57.02362 651.0236 cm +1 0 0 1 57.02362 265.0236 cm Q q -1 0 0 1 57.02362 585.0236 cm +1 0 0 1 57.02362 199.0236 cm q BT 1 0 0 1 0 50 Tm 1.476556 Tw 12 TL /F1 10 Tf 0 0 0 rg (All defects surfaced & fixed during benchmark development: an asm segfault on ) Tj /F5 10 Tf (\(define) Tj ( ) Tj (x\)) Tj /F1 10 Tf ( without a) Tj T* 0 Tw 1.838453 Tw (value \(now binds to ) Tj /F5 10 Tf (VOID) Tj /F1 10 Tf (\), an asm portal-resume that accepted short headers \(now verifies ) Tj /F5 10 Tf (sys_read) Tj /F1 10 Tf T* 0 Tw 1.204272 Tw (returned a full 48 bytes & sanity-checks heap metadata\), a Python ) Tj /F5 10 Tf (file) Tj ( ) Tj (not) Tj ( ) Tj (found) Tj /F1 10 Tf ( error reporting the) Tj T* 0 Tw 1.304862 Tw (outer script path instead of the inner missing file \(now uses ) Tj /F5 10 Tf (FileNotFoundError.filename) Tj /F1 10 Tf (\). Graceful) Tj T* 0 Tw (degradation is not free; it is tested.) Tj T* ET Q Q + +endstream +endobj +148 0 obj +<< +/Length 6103 +>> +stream +1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q -1 0 0 1 57.02362 559.0236 cm +1 0 0 1 57.02362 753.0236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (7.7 Use Case: Distributed Primality Testing) Tj T* ET Q Q q -1 0 0 1 57.02362 432.2236 cm +1 0 0 1 57.02362 626.2236 cm q q 1 0 0 1 0 0 cm @@ -7359,38 +7430,38 @@ Q Q Q q -1 0 0 1 57.02362 388.2236 cm +1 0 0 1 57.02362 582.2236 cm q BT 1 0 0 1 0 26 Tm 1.105522 Tw 12 TL /F1 10 Tf 0 0 0 rg (Machine A starts the computation. Every 10,000 iterations, it writes a checkpoint. Machine B picks up the) Tj T* 0 Tw 2.790642 Tw /F5 10 Tf (.portal) Tj /F1 10 Tf ( file & continues from the last checkpoint. The computation migrates without either machine) Tj T* 0 Tw (needing to know about the other. Feedback \227 the continuation \227 carries the entire execution context.) Tj T* ET Q Q q -1 0 0 1 57.02362 357.0236 cm +1 0 0 1 57.02362 551.0236 cm q BT 1 0 0 1 0 2.2 Tm 13.2 TL /F2 11 Tf .133333 .133333 .133333 rg (8. The EML Universality Proof) Tj T* ET Q Q q -1 0 0 1 57.02362 325.0236 cm +1 0 0 1 57.02362 519.0236 cm q BT 1 0 0 1 0 14 Tm 3.669104 Tw 12 TL /F1 10 Tf 0 0 0 rg (Lumbda ships with a mathematical proof that a single operator generates all elementary functions:) Tj T* 0 Tw /F5 10 Tf (eml\(x,) Tj ( ) Tj (y\)) Tj ( ) Tj (=) Tj ( ) Tj (exp\(x\)) Tj ( ) Tj (-) Tj ( ) Tj (ln\(y\)) Tj /F1 10 Tf (.) Tj T* ET Q Q q -1 0 0 1 57.02362 307.0236 cm +1 0 0 1 57.02362 501.0236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Reference: "All elementary functions from a single operator" \(arXiv:2603.21852v2\).) Tj T* ET Q Q q -1 0 0 1 57.02362 281.0236 cm +1 0 0 1 57.02362 475.0236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (8.1 The Operator) Tj T* ET Q Q q -1 0 0 1 57.02362 250.2236 cm +1 0 0 1 57.02362 444.2236 cm q q 1 0 0 1 0 0 cm @@ -7411,19 +7482,19 @@ Q Q Q q -1 0 0 1 57.02362 230.2236 cm +1 0 0 1 57.02362 424.2236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (With this operator & the constant ) Tj /F5 10 Tf (1) Tj /F1 10 Tf (, the following derivation chain constructs every elementary function:) Tj T* ET Q Q q -1 0 0 1 57.02362 204.2236 cm +1 0 0 1 57.02362 398.2236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (8.2 Stage 1: Core Functions \(Depth 1--3\)) Tj T* ET Q Q q -1 0 0 1 57.02362 154.2236 cm +1 0 0 1 57.02362 348.2236 cm q q 1 0 0 1 0 0 cm @@ -7444,28 +7515,19 @@ Q Q Q q -1 0 0 1 57.02362 110.2236 cm +1 0 0 1 57.02362 304.2236 cm q BT 1 0 0 1 0 26 Tm 16.01403 Tw 12 TL /F3 10 Tf 0 0 0 rg (Proof of ln recovery) Tj /F1 10 Tf (: Let ) Tj /F5 10 Tf (a) Tj ( ) Tj (=) Tj ( ) Tj (eml\(1,x\)) Tj ( ) Tj (=) Tj ( ) Tj (e) Tj ( ) Tj (-) Tj ( ) Tj (ln\(x\)) Tj /F1 10 Tf (. Then) Tj T* 0 Tw 28.85979 Tw /F5 10 Tf (eml\(a,) Tj ( ) Tj (1\)) Tj ( ) Tj (=) Tj ( ) Tj (exp\(e) Tj ( ) Tj (-) Tj ( ) Tj (ln\(x\)\)) Tj ( ) Tj (=) Tj ( ) Tj (exp\(e\)/x) Tj /F1 10 Tf (. Then) Tj T* 0 Tw /F5 10 Tf (eml\(1,) Tj ( ) Tj (exp\(e\)/x\)) Tj ( ) Tj (=) Tj ( ) Tj (e) Tj ( ) Tj (-) Tj ( ) Tj (ln\(exp\(e\)/x\)) Tj ( ) Tj (=) Tj ( ) Tj (e) Tj ( ) Tj (-) Tj ( ) Tj (e) Tj ( ) Tj (+) Tj ( ) Tj (ln\(x\)) Tj ( ) Tj (=) Tj ( ) Tj (ln\(x\)) Tj /F1 10 Tf (.) Tj T* ET Q Q - -endstream -endobj -147 0 obj -<< -/Length 9939 ->> -stream -1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q -1 0 0 1 57.02362 753.0236 cm +1 0 0 1 57.02362 278.2236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (8.3 Stage 2: Arithmetic) Tj T* ET Q Q q -1 0 0 1 57.02362 664.6236 cm +1 0 0 1 57.02362 189.8236 cm q q 1 0 0 1 0 0 cm @@ -7485,13 +7547,13 @@ Q Q Q q -1 0 0 1 57.02362 638.6236 cm +1 0 0 1 57.02362 163.8236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (8.4 Stage 3: Complex Plane Access) Tj T* ET Q Q q -1 0 0 1 57.02362 588.6236 cm +1 0 0 1 57.02362 113.8236 cm q q 1 0 0 1 0 0 cm @@ -7512,19 +7574,28 @@ Q Q Q q -1 0 0 1 57.02362 556.6236 cm +1 0 0 1 57.02362 81.82362 cm q BT 1 0 0 1 0 14 Tm .253071 Tw 12 TL /F1 10 Tf 0 0 0 rg (The key insight: ) Tj /F5 10 Tf (ln) Tj /F1 10 Tf ( of a negative number enters the complex plane. Since we can construct ) Tj /F5 10 Tf (-1) Tj /F1 10 Tf ( from eml via) Tj T* 0 Tw (the subtraction chain, ) Tj /F5 10 Tf (ln\(-1\)) Tj /F1 10 Tf ( yields ) Tj /F5 10 Tf (i) Tj /F6 10 Tf 12 TL (p) Tj /F5 10 Tf 12 TL /F1 10 Tf (, from which ) Tj /F5 10 Tf /F6 10 Tf 12 TL (p) Tj /F5 10 Tf 12 TL /F1 10 Tf ( & ) Tj /F5 10 Tf (i) Tj /F1 10 Tf ( follow.) Tj T* ET Q Q + +endstream +endobj +149 0 obj +<< +/Length 10703 +>> +stream +1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q -1 0 0 1 57.02362 530.6236 cm +1 0 0 1 57.02362 753.0236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (8.5 Stage 4: Trigonometry via Euler) Tj T* ET Q Q q -1 0 0 1 57.02362 480.6236 cm +1 0 0 1 57.02362 703.0236 cm q q 1 0 0 1 0 0 cm @@ -7545,29 +7616,29 @@ Q Q Q q -1 0 0 1 57.02362 460.6236 cm +1 0 0 1 57.02362 683.0236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (All trigonometric functions follow from complex exponentials, which follow from ) Tj /F5 10 Tf (exp) Tj /F1 10 Tf (, which follows from ) Tj /F5 10 Tf (eml) Tj /F1 10 Tf (.) Tj T* ET Q Q q -1 0 0 1 57.02362 434.6236 cm +1 0 0 1 57.02362 657.0236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (8.6 Verification & Friction Analysis) Tj T* ET Q Q q -1 0 0 1 57.02362 416.6236 cm +1 0 0 1 57.02362 639.0236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (The proof has been verified at six distinct levels. Times are best-of-3 on the i5-8350U:) Tj T* ET Q Q q -1 0 0 1 57.02362 410.6236 cm +1 0 0 1 57.02362 633.0236 cm Q q -1 0 0 1 57.02362 260.6236 cm +1 0 0 1 57.02362 483.0236 cm q 1 1 1 rg n 0 150 481.2283 -18 re f* @@ -7803,23 +7874,23 @@ Q Q Q q -1 0 0 1 57.02362 260.6236 cm +1 0 0 1 57.02362 483.0236 cm Q q -1 0 0 1 57.02362 242.6236 cm +1 0 0 1 57.02362 465.0236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL (Three separate wins compound here.) Tj T* ET Q Q q -1 0 0 1 57.02362 236.6236 cm +1 0 0 1 57.02362 459.0236 cm Q q -1 0 0 1 57.02362 236.6236 cm +1 0 0 1 57.02362 459.0236 cm Q q -1 0 0 1 57.02362 164.6236 cm +1 0 0 1 57.02362 387.0236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -7841,10 +7912,10 @@ Q Q Q q -1 0 0 1 57.02362 158.6236 cm +1 0 0 1 57.02362 381.0236 cm Q q -1 0 0 1 57.02362 110.6236 cm +1 0 0 1 57.02362 333.0236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -7866,49 +7937,24 @@ Q Q Q q -1 0 0 1 57.02362 104.6236 cm +1 0 0 1 57.02362 327.0236 cm Q q -1 0 0 1 57.02362 62.69291 cm +1 0 0 1 57.02362 267.0236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET q -1 0 0 1 6 26.93071 cm +1 0 0 1 6 45 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F5 10 Tf 12 TL 2 0 Td (3.) Tj T* -2 0 Td ET Q Q q -1 0 0 1 23 14.93071 cm -q -BT 1 0 0 1 0 14 Tm .419168 Tw 12 TL /F3 10 Tf 0 0 0 rg (Caching: artifact replay) Tj /F1 10 Tf ( \227 both checkers now write a small success-artifact on pass and short-circuit) Tj T* 0 Tw .242844 Tw (on subsequent runs if the magic header matches. Cached Lumbda \(7 ms\) and cached Lean \(5 ms\) are) Tj T* 0 Tw ET -Q -Q -q -Q -Q -Q - -endstream -endobj -148 0 obj -<< -/Length 8913 ->> -stream -1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET -q -1 0 0 1 57.02362 729.0236 cm -q -0 0 0 rg -BT /F1 10 Tf 12 TL ET -BT 1 0 0 1 6 23 Tm T* ET -q 1 0 0 1 23 -3 cm q -BT 1 0 0 1 0 26 Tm 6.674168 Tw 12 TL /F1 10 Tf 0 0 0 rg (essentially "read one file and print five lines." The 16\327 cold gap collapses to ~1.5\327.) Tj T* 0 Tw 1.11218 Tw /F5 10 Tf (rm) Tj ( ) Tj (-f) Tj ( ) Tj (/tmp/lumbda-eml.cache) Tj /F1 10 Tf ( \(analogous to ) Tj /F5 10 Tf (lake) Tj ( ) Tj (clean) Tj /F1 10 Tf (\) forces a cold re-check and the full) Tj T* 0 Tw (numbers return.) Tj T* ET +BT 1 0 0 1 0 50 Tm .419168 Tw 12 TL /F3 10 Tf 0 0 0 rg (Caching: artifact replay) Tj /F1 10 Tf ( \227 both checkers now write a small success-artifact on pass and short-circuit) Tj T* 0 Tw .242844 Tw (on subsequent runs if the magic header matches. Cached Lumbda \(7 ms\) and cached Lean \(5 ms\) are) Tj T* 0 Tw 6.674168 Tw (essentially "read one file and print five lines." The 16\327 cold gap collapses to ~1.5\327.) Tj T* 0 Tw 1.11218 Tw /F5 10 Tf (rm) Tj ( ) Tj (-f) Tj ( ) Tj (/tmp/lumbda-eml.cache) Tj /F1 10 Tf ( \(analogous to ) Tj /F5 10 Tf (lake) Tj ( ) Tj (clean) Tj /F1 10 Tf (\) forces a cold re-check and the full) Tj T* 0 Tw (numbers return.) Tj T* ET Q Q q @@ -7916,34 +7962,34 @@ Q Q Q q -1 0 0 1 57.02362 729.0236 cm +1 0 0 1 57.02362 267.0236 cm Q q -1 0 0 1 57.02362 663.0236 cm +1 0 0 1 57.02362 201.0236 cm q BT 1 0 0 1 0 50 Tm .913719 Tw 12 TL /F3 10 Tf 0 0 0 rg (Symmetric honesty.) Tj /F1 10 Tf ( Lean's kernel guarantees remain stronger even when the timings equalize: the Lean) Tj T* 0 Tw .45989 Tw (TCB is ~3 KLOC of audited elaborator/kernel, while Lumbda's asm interpreter is ~6.6 KLOC of hand-written) Tj T* 0 Tw .884917 Tw (assembly. For proofs where the cost of a bug in the checker itself matters, Lean is the right tool; for small) Tj T* 0 Tw 2.400556 Tw (symbolic-rewrite proofs where the language hosting the proof should be able to host the checker too,) Tj T* 0 Tw (Lumbda does the job in under 50 ms cold without external dependencies.) Tj T* ET Q Q q -1 0 0 1 57.02362 609.0236 cm +1 0 0 1 57.02362 147.0236 cm q BT 1 0 0 1 0 38 Tm 3.571147 Tw 12 TL /F3 10 Tf 0 0 0 rg (Lesson) Tj /F1 10 Tf (: The fastest path to truth is not computation \227 it is understanding. When you know ) Tj /F4 10 Tf (why) Tj /F1 10 Tf T* 0 Tw .96189 Tw /F5 10 Tf (eml\(1,) Tj ( ) Tj (eml\(eml\(1,x\),) Tj ( ) Tj (1\)\)) Tj ( ) Tj (=) Tj ( ) Tj (ln\(x\)) Tj /F1 10 Tf (, you verify it in microseconds. When you don't, you search for) Tj T* 0 Tw .874862 Tw (hours. Symbolic reasoning eliminates the quadratic friction of numerical verification; caching eliminates the) Tj T* 0 Tw (startup friction of every verifier. Both layers stack.) Tj T* ET Q Q q -1 0 0 1 57.02362 579.0236 cm +1 0 0 1 57.02362 117.0236 cm q BT 1 0 0 1 0 14 Tm .708556 Tw 12 TL /F3 10 Tf 0 0 0 rg (Reproduce:) Tj /F1 10 Tf ( ) Tj /F5 10 Tf (make) Tj ( ) Tj (bench-proof) Tj /F1 10 Tf ( runs the cold and cached paths for both Lumbda \(across all three tiers\)) Tj T* 0 Tw (and Lean. Source: ) Tj /F5 10 Tf (proof/benchmark.sh) Tj /F1 10 Tf (.) Tj T* ET Q Q q -1 0 0 1 57.02362 573.0236 cm +1 0 0 1 57.02362 111.0236 cm Q q -1 0 0 1 57.02362 573.0236 cm +1 0 0 1 57.02362 111.0236 cm Q q -1 0 0 1 57.02362 537.0236 cm +1 0 0 1 57.02362 75.02362 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -7965,10 +8011,19 @@ Q Q Q q -1 0 0 1 57.02362 531.0236 cm +1 0 0 1 57.02362 69.02362 cm Q + +endstream +endobj +150 0 obj +<< +/Length 9408 +>> +stream +1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q -1 0 0 1 57.02362 495.0236 cm +1 0 0 1 57.02362 729.0236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -7990,10 +8045,10 @@ Q Q Q q -1 0 0 1 57.02362 489.0236 cm +1 0 0 1 57.02362 723.0236 cm Q q -1 0 0 1 57.02362 465.0236 cm +1 0 0 1 57.02362 699.0236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -8015,10 +8070,10 @@ Q Q Q q -1 0 0 1 57.02362 465.0236 cm +1 0 0 1 57.02362 699.0236 cm Q q -1 0 0 1 57.02362 395.8236 cm +1 0 0 1 57.02362 629.8236 cm q q 1 0 0 1 0 0 cm @@ -8039,19 +8094,19 @@ Q Q Q q -1 0 0 1 57.02362 351.8236 cm +1 0 0 1 57.02362 585.8236 cm q BT 1 0 0 1 0 26 Tm 4.138556 Tw 12 TL /F1 10 Tf 0 0 0 rg (The Lean proof operates over abstract ) Tj /F5 10 Tf (exp) Tj /F1 10 Tf ( & ) Tj /F5 10 Tf (ln) Tj /F1 10 Tf ( functions with the axioms ) Tj /F5 10 Tf (exp\(ln\(x\)\)) Tj ( ) Tj (=) Tj ( ) Tj (x) Tj /F1 10 Tf (,) Tj T* 0 Tw 2.484897 Tw /F5 10 Tf (ln\(exp\(x\)\)) Tj ( ) Tj (=) Tj ( ) Tj (x) Tj /F1 10 Tf (, & ) Tj /F5 10 Tf (ln\(1\)) Tj ( ) Tj (=) Tj ( ) Tj (0) Tj /F1 10 Tf (. This makes the result independent of any particular real number) Tj T* 0 Tw (implementation.) Tj T* ET Q Q q -1 0 0 1 57.02362 345.8236 cm +1 0 0 1 57.02362 579.8236 cm Q q -1 0 0 1 57.02362 345.8236 cm +1 0 0 1 57.02362 579.8236 cm Q q -1 0 0 1 57.02362 261.8236 cm +1 0 0 1 57.02362 495.8236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -8073,10 +8128,10 @@ Q Q Q q -1 0 0 1 57.02362 261.8236 cm +1 0 0 1 57.02362 495.8236 cm Q q -1 0 0 1 57.02362 183.0236 cm +1 0 0 1 57.02362 417.0236 cm q q 1 0 0 1 0 0 cm @@ -8097,109 +8152,21 @@ Q Q Q q -1 0 0 1 57.02362 115.0236 cm +1 0 0 1 57.02362 349.0236 cm q BT 1 0 0 1 0 50 Tm 4.101411 Tw 12 TL /F3 10 Tf 0 0 0 rg (Verification speed: Lean vs Lumbda tiers, both cold and cached.) Tj /F1 10 Tf ( Same five theorems, same) Tj T* 0 Tw 1.757362 Tw (symbolic-rewrite strategy. The Lumbda checker now implements its own cached-replay path that mirrors) Tj T* 0 Tw .258797 Tw (Lean's: write a small artifact after a successful run; on subsequent runs, trust the artifact if the magic header) Tj T* 0 Tw .759029 Tw (matches and skip re-verification. ) Tj /F5 10 Tf (rm) Tj ( ) Tj (-f) Tj ( ) Tj (/tmp/lumbda-eml.cache) Tj /F1 10 Tf ( forces a cold re-check \(analogous to) Tj T* 0 Tw /F5 10 Tf (lake) Tj ( ) Tj (clean) Tj /F1 10 Tf (\). Best of 3 on the i5-8350U:) Tj T* ET Q Q q -1 0 0 1 57.02362 109.0236 cm +1 0 0 1 57.02362 343.0236 cm Q q -1 0 0 1 57.02362 73.02362 cm +1 0 0 1 57.02362 235.0236 cm q 1 1 1 rg -n 0 36 481.2283 -18 re f* +n 0 108 481.2283 -18 re f* .878431 .878431 .878431 rg -n 0 18 481.2283 -18 re f* -0 0 0 rg -BT /F3 10 Tf 12 TL ET -q -1 0 0 1 6 21 cm -q -0 0 0 rg -BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 55.88252 0 Td (Approach) Tj T* -55.88252 0 Td ET -Q -Q -q -1 0 0 1 176.435 21 cm -q -0 0 0 rg -BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 23.82236 0 Td (cold) Tj T* -23.82236 0 Td ET -Q -Q -q -1 0 0 1 256.6398 21 cm -q -0 0 0 rg -BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 16.87236 0 Td (cached) Tj T* -16.87236 0 Td ET -Q -Q -q -1 0 0 1 336.8445 21 cm -q -0 0 0 rg -BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 55.85693 0 Td (notes) Tj T* -55.85693 0 Td ET -Q -Q -0 0 0 rg -BT /F1 10 Tf 12 TL ET -q -1 0 0 1 6 3 cm -q -0 0 0 rg -BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Lumbda asm) Tj T* ET -Q -Q -q -1 0 0 1 176.435 3 cm -q -0 0 0 rg -BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (46 ms) Tj T* ET -Q -Q -q -1 0 0 1 256.6398 3 cm -q -0 0 0 rg -BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL (7 ms) Tj T* ET -Q -Q -q -1 0 0 1 336.8445 3 cm -q -0 0 0 rg -BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (fastest Lumbda tier) Tj T* ET -Q -Q -q -1 J -1 j -0 0 0 RG -.25 w -n 0 0 m 481.2283 0 l S -n 0 18 m 481.2283 18 l S -n 170.435 0 m 170.435 36 l S -n 250.6398 0 m 250.6398 36 l S -n 330.8445 0 m 330.8445 36 l S -n 0 36 m 481.2283 36 l S -n 0 0 m 0 36 l S -n 481.2283 0 m 481.2283 36 l S -Q -Q -Q - -endstream -endobj -149 0 obj -<< -/Length 10251 ->> -stream -1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET -q -1 0 0 1 57.02362 693.0236 cm -q +n 0 90 481.2283 -18 re f* 1 1 1 rg n 0 72 481.2283 -18 re f* .878431 .878431 .878431 rg @@ -8209,8 +8176,66 @@ n 0 36 481.2283 -18 re f* .878431 .878431 .878431 rg n 0 18 481.2283 -18 re f* 0 0 0 rg +BT /F3 10 Tf 12 TL ET +q +1 0 0 1 6 93 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 55.88252 0 Td (Approach) Tj T* -55.88252 0 Td ET +Q +Q +q +1 0 0 1 176.435 93 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 23.82236 0 Td (cold) Tj T* -23.82236 0 Td ET +Q +Q +q +1 0 0 1 256.6398 93 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 16.87236 0 Td (cached) Tj T* -16.87236 0 Td ET +Q +Q +q +1 0 0 1 336.8445 93 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 55.85693 0 Td (notes) Tj T* -55.85693 0 Td ET +Q +Q +0 0 0 rg BT /F1 10 Tf 12 TL ET q +1 0 0 1 6 75 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Lumbda asm) Tj T* ET +Q +Q +q +1 0 0 1 176.435 75 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (46 ms) Tj T* ET +Q +Q +q +1 0 0 1 256.6398 75 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL (7 ms) Tj T* ET +Q +Q +q +1 0 0 1 336.8445 75 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (fastest Lumbda tier) Tj T* ET +Q +Q +q 1 0 0 1 6 57 cm q BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (Lumbda C ) Tj /F5 10 Tf (--fast) Tj T* ET @@ -8304,104 +8329,125 @@ q 1 j 0 0 0 RG .25 w +n 0 90 m 481.2283 90 l S n 0 72 m 481.2283 72 l S n 0 54 m 481.2283 54 l S n 0 36 m 481.2283 36 l S n 0 18 m 481.2283 18 l S -n 170.435 0 m 170.435 72 l S -n 250.6398 0 m 250.6398 72 l S -n 330.8445 0 m 330.8445 72 l S -n 0 0 m 0 72 l S -n 481.2283 0 m 481.2283 72 l S +n 170.435 0 m 170.435 108 l S +n 250.6398 0 m 250.6398 108 l S +n 330.8445 0 m 330.8445 108 l S +n 0 108 m 481.2283 108 l S n 0 0 m 481.2283 0 l S +n 0 0 m 0 108 l S +n 481.2283 0 m 481.2283 108 l S Q Q Q q -1 0 0 1 57.02362 693.0236 cm +1 0 0 1 57.02362 235.0236 cm Q q -1 0 0 1 57.02362 627.0236 cm +1 0 0 1 57.02362 169.0236 cm q BT 1 0 0 1 0 50 Tm .204897 Tw 12 TL /F1 10 Tf 0 0 0 rg (Two comparisons matter. ) Tj /F3 10 Tf (Cold vs cold) Tj /F1 10 Tf ( is the honest end-to-end compare: Lumbda asm \(46 ms\) verifies the) Tj T* 0 Tw -0.127156 Tw (proof ) Tj /F3 10 Tf (~16\327 faster than Lean's cold rebuild) Tj /F1 10 Tf ( \(722 ms\) on the same hardware, because Lumbda doesn't link a) Tj T* 0 Tw .315636 Tw (compiled binary or spin up a kernel \227 it just runs a rewriter over five small terms. ) Tj /F3 10 Tf (Cached vs cached) Tj /F1 10 Tf ( is the) Tj T* 0 Tw 1.150966 Tw (throwaway benchmark but still interesting: Lumbda asm at 7 ms vs Lean at 5 ms, within 1.5\327, on what is) Tj T* 0 Tw (essentially "read a file and print five lines.") Tj T* ET Q Q q -1 0 0 1 57.02362 561.0236 cm +1 0 0 1 57.02362 103.0236 cm q BT 1 0 0 1 0 50 Tm .526772 Tw 12 TL /F3 10 Tf 0 0 0 rg (All four Lumbda tiers verify the proof.) Tj /F1 10 Tf ( A C ) Tj /F5 10 Tf (--fast) Tj /F1 10 Tf ( bytecode-compiler bug originally caused the final tier) Tj T* 0 Tw 10.06986 Tw (to hang on the rewriter's named-let loop; narrowed to a minimal reproduction \(see) Tj T* 0 Tw 1.693196 Tw /F5 10 Tf (c/TODO-named-let-bytecode.md) Tj /F1 10 Tf (\) and worked around in the proof file by using an internal recursive) Tj T* 0 Tw .558138 Tw /F5 10 Tf (define) Tj /F1 10 Tf ( in place of the offending named-let. All four tiers now complete in under 100 ms cold. ) Tj /F3 10 Tf (Reproduce:) Tj /F1 10 Tf T* 0 Tw /F5 10 Tf (make) Tj ( ) Tj (bench-proof) Tj /F1 10 Tf ( \(source: ) Tj /F5 10 Tf (tests/bench-proof.sh) Tj /F1 10 Tf (\).) Tj T* ET Q Q q -1 0 0 1 57.02362 459.0236 cm +1 0 0 1 57.02362 73.02362 cm q -BT 1 0 0 1 0 86 Tm 2.513543 Tw 12 TL /F3 10 Tf 0 0 0 rg (First machine-checked treatment.) Tj /F1 10 Tf ( The original paper \(Odrzywo) Tj /F9 10 Tf 12 TL (n) Tj /F1 10 Tf 12 TL (ek, arXiv:2603.21852v2, 2026-04-04\)) Tj T* 0 Tw .313453 Tw (presents the EML universality claim analytically \227 pure LaTeX mathematics, no formal tool. The companion) Tj T* 0 Tw .549873 Tw (Zenodo artifact is symbolic-regression / gradient-optimization code, not a verification. To our knowledge the) Tj T* 0 Tw 1.856373 Tw (Lean 4 proof shipped in this repo is the first machine-checked treatment of the EML identities, and the) Tj T* 0 Tw .247122 Tw (accompanying Lumbda-native checker is the first self-hosted machine-checked version. Five theorems, zero) Tj T* 0 Tw .312025 Tw /F5 10 Tf (sorry) Tj /F1 10 Tf (, no Mathlib dependency \227 ) Tj /F3 10 Tf (~1,280\327 faster than the brute-force numerical search) Tj /F1 10 Tf ( it replaced once) Tj T* 0 Tw 2.035223 Tw (the symbolic rewriter was written \(see \2478.6 for the full six-row comparison\), and carrying the additional) Tj T* 0 Tw (guarantee that no implementation quirk of floating point can ever break the conclusion.) Tj T* ET +BT 1 0 0 1 0 14 Tm 2.513543 Tw 12 TL /F3 10 Tf 0 0 0 rg (First machine-checked treatment.) Tj /F1 10 Tf ( The original paper \(Odrzywo) Tj /F9 10 Tf 12 TL (n) Tj /F1 10 Tf 12 TL (ek, arXiv:2603.21852v2, 2026-04-04\)) Tj T* 0 Tw .313453 Tw (presents the EML universality claim analytically \227 pure LaTeX mathematics, no formal tool. The companion) Tj T* 0 Tw ET +Q +Q + +endstream +endobj +151 0 obj +<< +/Length 9097 +>> +stream +1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET +q +1 0 0 1 57.02362 693.0236 cm +q +BT 1 0 0 1 0 62 Tm .549873 Tw 12 TL /F1 10 Tf 0 0 0 rg (Zenodo artifact is symbolic-regression / gradient-optimization code, not a verification. To our knowledge the) Tj T* 0 Tw 1.856373 Tw (Lean 4 proof shipped in this repo is the first machine-checked treatment of the EML identities, and the) Tj T* 0 Tw .247122 Tw (accompanying Lumbda-native checker is the first self-hosted machine-checked version. Five theorems, zero) Tj T* 0 Tw .312025 Tw /F5 10 Tf (sorry) Tj /F1 10 Tf (, no Mathlib dependency \227 ) Tj /F3 10 Tf (~1,280\327 faster than the brute-force numerical search) Tj /F1 10 Tf ( it replaced once) Tj T* 0 Tw 2.035223 Tw (the symbolic rewriter was written \(see \2478.6 for the full six-row comparison\), and carrying the additional) Tj T* 0 Tw (guarantee that no implementation quirk of floating point can ever break the conclusion.) Tj T* ET Q Q q -1 0 0 1 57.02362 427.8236 cm +1 0 0 1 57.02362 661.8236 cm q BT 1 0 0 1 0 2.2 Tm 13.2 TL /F2 11 Tf .133333 .133333 .133333 rg (9. Language Coverage) Tj T* ET Q Q q -1 0 0 1 57.02362 407.8236 cm +1 0 0 1 57.02362 641.8236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Lumbda implements a near-complete R7RS-small Scheme:) Tj T* ET Q Q q -1 0 0 1 57.02362 353.8236 cm +1 0 0 1 57.02362 587.8236 cm q BT 1 0 0 1 0 38 Tm 1.369223 Tw 12 TL /F3 10 Tf 0 0 0 rg (Special forms) Tj /F1 10 Tf ( \(32\): ) Tj /F5 10 Tf (define) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (set!) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (lambda) Tj /F1 10 Tf (, ) Tj /F5 10 Tf /F6 10 Tf 12 TL (l) Tj /F5 10 Tf 12 TL /F1 10 Tf (, ) Tj /F5 10 Tf (if) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (cond) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (case) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (and) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (or) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (when) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (unless) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (begin) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (let) Tj /F1 10 Tf (,) Tj T* 0 Tw 10.15262 Tw /F5 10 Tf (let*) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (letrec) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (letrec*) Tj /F1 10 Tf (, named-let, ) Tj /F5 10 Tf (do) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (quasiquote) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (define-macro) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (define-syntax) Tj /F1 10 Tf (,) Tj T* 0 Tw 3.646907 Tw /F5 10 Tf (syntax-rules) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (let-syntax) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (letrec-syntax) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (apply) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (eval) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (values) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (call/cc) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (dynamic-wind) Tj /F1 10 Tf (,) Tj T* 0 Tw /F5 10 Tf (guard) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (parameterize) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (load) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (error) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (module) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (import) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (define-record-type) Tj /F1 10 Tf (.) Tj T* ET Q Q q -1 0 0 1 57.02362 323.8236 cm +1 0 0 1 57.02362 557.8236 cm q BT 1 0 0 1 0 14 Tm .150642 Tw 12 TL /F3 10 Tf 0 0 0 rg (Built-in functions) Tj /F1 10 Tf ( \(100+\): Full arithmetic \(exact rationals, inexact reals, trigonometry\), pairs & lists \(SRFI-1\),) Tj T* 0 Tw (strings \(mutable\), characters, vectors, hash tables, I/O \(ports, file system\), system interface, Python interop.) Tj T* ET Q Q q -1 0 0 1 57.02362 293.8236 cm +1 0 0 1 57.02362 527.8236 cm q BT 1 0 0 1 0 14 Tm 2.274835 Tw 12 TL /F3 10 Tf 0 0 0 rg (Hygienic macros) Tj /F1 10 Tf (: ) Tj /F5 10 Tf (syntax-rules) Tj /F1 10 Tf ( with ellipsis \() Tj /F5 10 Tf (...) Tj /F1 10 Tf (\) support. Pattern matching, template instantiation,) Tj T* 0 Tw (proper hygiene. Also ) Tj /F5 10 Tf (define-macro) Tj /F1 10 Tf ( for procedural macros.) Tj T* ET Q Q q -1 0 0 1 57.02362 263.8236 cm +1 0 0 1 57.02362 497.8236 cm q BT 1 0 0 1 0 14 Tm 1.958835 Tw 12 TL /F3 10 Tf 0 0 0 rg (Standard library) Tj /F1 10 Tf ( \() Tj /F5 10 Tf (stdlib.lsp) Tj /F1 10 Tf (, 385 lines\): Additional macros \() Tj /F5 10 Tf (swap!) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (fluid-let) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (while) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (dotimes) Tj /F1 10 Tf (\),) Tj T* 0 Tw (utility functions, simple object system, SRFI-2/8/64 test framework.) Tj T* ET Q Q q -1 0 0 1 57.02362 209.8236 cm +1 0 0 1 57.02362 443.8236 cm q BT 1 0 0 1 0 38 Tm 1.569862 Tw 12 TL /F3 10 Tf 0 0 0 rg (Test suite) Tj /F1 10 Tf (: 974 verified assertions covering lexing, parsing, special forms, bytecode compilation, macros) Tj T* 0 Tw .214835 Tw (\(hygienic & procedural\), continuations, generators, record types, modules, arithmetic, higher-order functions,) Tj T* 0 Tw 4.238031 Tw (error handling, portal serialization, cross-implementation portal exchange, file I/O parity, & graceful) Tj T* 0 Tw (degradation on mismatched or corrupt input.) Tj T* ET Q Q q -1 0 0 1 57.02362 178.6236 cm +1 0 0 1 57.02362 412.6236 cm q BT 1 0 0 1 0 2.2 Tm 13.2 TL /F2 11 Tf .133333 .133333 .133333 rg (10. Relationship to Companion Papers) Tj T* ET Q Q q -1 0 0 1 57.02362 158.6236 cm +1 0 0 1 57.02362 392.6236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Lumbda forms one piece of a larger permacomputer machine learning stack:) Tj T* ET Q Q q -1 0 0 1 57.02362 152.6236 cm +1 0 0 1 57.02362 386.6236 cm Q q -1 0 0 1 57.02362 74.62362 cm +1 0 0 1 57.02362 248.6236 cm q 1 1 1 rg -n 0 78 481.2283 -18 re f* +n 0 138 481.2283 -18 re f* +.878431 .878431 .878431 rg +n 0 120 481.2283 -30 re f* +1 1 1 rg +n 0 90 481.2283 -30 re f* .878431 .878431 .878431 rg n 0 60 481.2283 -30 re f* 1 1 1 rg @@ -8409,21 +8455,21 @@ n 0 30 481.2283 -30 re f* 0 0 0 rg BT /F3 10 Tf 12 TL ET q -1 0 0 1 6 63 cm +1 0 0 1 6 123 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 28.78283 0 Td (Layer) Tj T* -28.78283 0 Td ET Q Q q -1 0 0 1 102.2457 63 cm +1 0 0 1 102.2457 123 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 64.31996 0 Td (Paper) Tj T* -64.31996 0 Td ET Q Q q -1 0 0 1 270.6756 63 cm +1 0 0 1 270.6756 123 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 91.44138 0 Td (Role) Tj T* -91.44138 0 Td ET @@ -8432,79 +8478,45 @@ Q 0 0 0 rg BT /F1 10 Tf 12 TL ET q -1 0 0 1 6 45 cm +1 0 0 1 6 105 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Runtime) Tj T* ET Q Q q -1 0 0 1 102.2457 33 cm +1 0 0 1 102.2457 93 cm q BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf 0 0 0 rg (Feedback Is All You Need) Tj /F1 10 Tf ( \(this) Tj T* (paper\)) Tj T* ET Q Q q -1 0 0 1 270.6756 33 cm +1 0 0 1 270.6756 93 cm q BT 1 0 0 1 0 14 Tm 12 TL /F1 10 Tf 0 0 0 rg (Complete Scheme VM with continuations &) Tj T* (portal) Tj T* ET Q Q q -1 0 0 1 6 15 cm +1 0 0 1 6 75 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Interaction) Tj T* ET Q Q q -1 0 0 1 102.2457 3 cm +1 0 0 1 102.2457 63 cm q BT 1 0 0 1 0 14 Tm 12 TL /F1 10 Tf 0 0 0 rg (Categorization & Feedback Is All) Tj T* (You Need) Tj T* ET Q Q q -1 0 0 1 270.6756 3 cm +1 0 0 1 270.6756 63 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL (Machine learning driven state machines in) Tj T* (58+ languages) Tj T* ET Q Q q -1 J -1 j -0 0 0 RG -.25 w -n 0 0 m 481.2283 0 l S -n 0 60 m 481.2283 60 l S -n 0 30 m 481.2283 30 l S -n 96.24567 0 m 96.24567 78 l S -n 264.6756 0 m 264.6756 78 l S -n 0 78 m 481.2283 78 l S -n 0 0 m 0 78 l S -n 481.2283 0 m 481.2283 78 l S -Q -Q -Q - -endstream -endobj -150 0 obj -<< -/Length 2999 ->> -stream -1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET -q -1 0 0 1 57.02362 705.0236 cm -q -1 1 1 rg -n 0 60 481.2283 -30 re f* -.878431 .878431 .878431 rg -n 0 30 481.2283 -30 re f* -0 0 0 rg -BT /F1 10 Tf 12 TL ET -q 1 0 0 1 6 45 cm q 0 0 0 rg @@ -8551,36 +8563,39 @@ q 1 j 0 0 0 RG .25 w +n 0 120 m 481.2283 120 l S +n 0 90 m 481.2283 90 l S n 0 60 m 481.2283 60 l S n 0 30 m 481.2283 30 l S -n 96.24567 0 m 96.24567 60 l S -n 264.6756 0 m 264.6756 60 l S -n 0 0 m 0 60 l S -n 481.2283 0 m 481.2283 60 l S +n 96.24567 0 m 96.24567 138 l S +n 264.6756 0 m 264.6756 138 l S +n 0 138 m 481.2283 138 l S n 0 0 m 481.2283 0 l S +n 0 0 m 0 138 l S +n 481.2283 0 m 481.2283 138 l S Q Q Q q -1 0 0 1 57.02362 705.0236 cm +1 0 0 1 57.02362 248.6236 cm Q q -1 0 0 1 57.02362 651.0236 cm +1 0 0 1 57.02362 194.6236 cm q BT 1 0 0 1 0 38 Tm 1.738453 Tw 12 TL /F1 10 Tf 0 0 0 rg (Lumbda provides the runtime layer: a language that can checkpoint its own execution, migrate between) Tj T* 0 Tw 3.051529 Tw (machines, & resume from serialized state. The portal system enables distributed computation across) Tj T* 0 Tw 1.058196 Tw (permacomputer nodes. Categorization & feedback activities could run inside Lumbda's VM, with ) Tj /F5 10 Tf (call/cc) Tj /F1 10 Tf T* 0 Tw (providing the state machine transitions & portal providing persistence.) Tj T* ET Q Q q -1 0 0 1 57.02362 619.8236 cm +1 0 0 1 57.02362 163.4236 cm q BT 1 0 0 1 0 2.2 Tm 13.2 TL /F2 11 Tf .133333 .133333 .133333 rg (11. Four Implementation Tiers, One Language) Tj T* ET Q Q q -1 0 0 1 57.02362 605.8236 cm +1 0 0 1 57.02362 149.4236 cm Q q -1 0 0 1 57.02362 593.8236 cm +1 0 0 1 57.02362 137.4236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -8596,28 +8611,34 @@ Q Q Q q -1 0 0 1 57.02362 593.8236 cm +1 0 0 1 57.02362 137.4236 cm Q q -1 0 0 1 57.02362 515.8236 cm +1 0 0 1 57.02362 83.42362 cm q -BT 1 0 0 1 0 62 Tm .778726 Tw 12 TL /F1 10 Tf 0 0 0 rg (Lumbda ships as four independently built tiers: a Python bytecode VM, a C tree-walker, a C bytecode VM,) Tj T* 0 Tw 2.18402 Tw (and a C x86_64 JIT \(the last three packaged in one binary, selectable by flag\), plus a pure-assembly) Tj T* 0 Tw .931492 Tw (interpreter. Each tier is MOAD-isolated from the others \227 a defect surfaced in one is fixed in that tier, not) Tj T* 0 Tw 2.098556 Tw (patched across shared infrastructure. All four run the same ) Tj /F5 10 Tf (.lsp) Tj /F1 10 Tf ( source files and exchange the same) Tj T* 0 Tw 2.266213 Tw (S-expression portal format; \24711.3-\24711.5 demonstrate this end-to-end across sockets, relays, and HTTP) Tj T* 0 Tw (portal transfers.) Tj T* ET +BT 1 0 0 1 0 38 Tm .778726 Tw 12 TL /F1 10 Tf 0 0 0 rg (Lumbda ships as four independently built tiers: a Python bytecode VM, a C tree-walker, a C bytecode VM,) Tj T* 0 Tw 2.18402 Tw (and a C x86_64 JIT \(the last three packaged in one binary, selectable by flag\), plus a pure-assembly) Tj T* 0 Tw .931492 Tw (interpreter. Each tier is MOAD-isolated from the others \227 a defect surfaced in one is fixed in that tier, not) Tj T* 0 Tw 2.098556 Tw (patched across shared infrastructure. All four run the same ) Tj /F5 10 Tf (.lsp) Tj /F1 10 Tf ( source files and exchange the same) Tj T* 0 Tw ET Q Q -q -1 0 0 1 57.02362 507.8236 cm -Q endstream endobj -151 0 obj +152 0 obj << -/Length 1782 +/Length 2057 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q -1 0 0 1 57.02362 263.1875 cm +1 0 0 1 57.02362 741.0236 cm +q +BT 1 0 0 1 0 14 Tm 2.266213 Tw 12 TL /F1 10 Tf 0 0 0 rg (S-expression portal format; \24711.3-\24711.5 demonstrate this end-to-end across sockets, relays, and HTTP) Tj T* 0 Tw (portal transfers.) Tj T* ET +Q +Q +q +1 0 0 1 57.02362 733.0236 cm +Q +q +1 0 0 1 57.02362 231.1875 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -8640,13 +8661,13 @@ Q Q Q q -1 0 0 1 57.02362 255.1875 cm +1 0 0 1 57.02362 223.1875 cm Q q -1 0 0 1 57.02362 247.1875 cm +1 0 0 1 57.02362 215.1875 cm Q q -1 0 0 1 57.02362 111.9891 cm +1 0 0 1 57.02362 79.98905 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -8669,12 +8690,12 @@ Q Q Q q -1 0 0 1 57.02362 103.9891 cm +1 0 0 1 57.02362 71.98905 cm Q endstream endobj -152 0 obj +153 0 obj << /Length 13402 >> @@ -9185,7 +9206,7 @@ Q endstream endobj -153 0 obj +154 0 obj << /Length 16605 >> @@ -10022,7 +10043,7 @@ Q endstream endobj -154 0 obj +155 0 obj << /Length 10454 >> @@ -10424,7 +10445,7 @@ Q endstream endobj -155 0 obj +156 0 obj << /Length 7406 >> @@ -10638,7 +10659,7 @@ Q endstream endobj -156 0 obj +157 0 obj << /Length 6621 >> @@ -10786,7 +10807,7 @@ Q endstream endobj -157 0 obj +158 0 obj << /Length 8009 >> @@ -11024,7 +11045,7 @@ Q endstream endobj -158 0 obj +159 0 obj << /Length 7883 >> @@ -11283,7 +11304,7 @@ Q endstream endobj -159 0 obj +160 0 obj << /Length 6415 >> @@ -11531,7 +11552,7 @@ Q endstream endobj -160 0 obj +161 0 obj << /Length 2103 >> @@ -11608,7 +11629,7 @@ Q endstream endobj -161 0 obj +162 0 obj << /Length 1025 >> @@ -11637,179 +11658,179 @@ Q endstream endobj -162 0 obj -<< -/Nums [ 0 163 0 R 1 164 0 R 2 165 0 R 3 166 0 R 4 167 0 R - 5 168 0 R 6 169 0 R 7 170 0 R 8 171 0 R 9 172 0 R - 10 173 0 R 11 174 0 R 12 175 0 R 13 176 0 R 14 177 0 R - 15 178 0 R 16 179 0 R 17 180 0 R 18 181 0 R 19 182 0 R - 20 183 0 R 21 184 0 R 22 185 0 R 23 186 0 R 24 187 0 R - 25 188 0 R 26 189 0 R 27 190 0 R 28 191 0 R 29 192 0 R - 30 193 0 R 31 194 0 R ] ->> -endobj 163 0 obj << -/S /D /St 1 +/Nums [ 0 164 0 R 1 165 0 R 2 166 0 R 3 167 0 R 4 168 0 R + 5 169 0 R 6 170 0 R 7 171 0 R 8 172 0 R 9 173 0 R + 10 174 0 R 11 175 0 R 12 176 0 R 13 177 0 R 14 178 0 R + 15 179 0 R 16 180 0 R 17 181 0 R 18 182 0 R 19 183 0 R + 20 184 0 R 21 185 0 R 22 186 0 R 23 187 0 R 24 188 0 R + 25 189 0 R 26 190 0 R 27 191 0 R 28 192 0 R 29 193 0 R + 30 194 0 R 31 195 0 R ] >> endobj 164 0 obj << -/S /D /St 2 +/S /D /St 1 >> endobj 165 0 obj << -/S /D /St 3 +/S /D /St 2 >> endobj 166 0 obj << -/S /D /St 4 +/S /D /St 3 >> endobj 167 0 obj << -/S /D /St 5 +/S /D /St 4 >> endobj 168 0 obj << -/S /D /St 6 +/S /D /St 5 >> endobj 169 0 obj << -/S /D /St 7 +/S /D /St 6 >> endobj 170 0 obj << -/S /D /St 8 +/S /D /St 7 >> endobj 171 0 obj << -/S /D /St 9 +/S /D /St 8 >> endobj 172 0 obj << -/S /D /St 10 +/S /D /St 9 >> endobj 173 0 obj << -/S /D /St 11 +/S /D /St 10 >> endobj 174 0 obj << -/S /D /St 12 +/S /D /St 11 >> endobj 175 0 obj << -/S /D /St 13 +/S /D /St 12 >> endobj 176 0 obj << -/S /D /St 14 +/S /D /St 13 >> endobj 177 0 obj << -/S /D /St 15 +/S /D /St 14 >> endobj 178 0 obj << -/S /D /St 16 +/S /D /St 15 >> endobj 179 0 obj << -/S /D /St 17 +/S /D /St 16 >> endobj 180 0 obj << -/S /D /St 18 +/S /D /St 17 >> endobj 181 0 obj << -/S /D /St 19 +/S /D /St 18 >> endobj 182 0 obj << -/S /D /St 20 +/S /D /St 19 >> endobj 183 0 obj << -/S /D /St 21 +/S /D /St 20 >> endobj 184 0 obj << -/S /D /St 22 +/S /D /St 21 >> endobj 185 0 obj << -/S /D /St 23 +/S /D /St 22 >> endobj 186 0 obj << -/S /D /St 24 +/S /D /St 23 >> endobj 187 0 obj << -/S /D /St 25 +/S /D /St 24 >> endobj 188 0 obj << -/S /D /St 26 +/S /D /St 25 >> endobj 189 0 obj << -/S /D /St 27 +/S /D /St 26 >> endobj 190 0 obj << -/S /D /St 28 +/S /D /St 27 >> endobj 191 0 obj << -/S /D /St 29 +/S /D /St 28 >> endobj 192 0 obj << -/S /D /St 30 +/S /D /St 29 >> endobj 193 0 obj << -/S /D /St 31 +/S /D /St 30 >> endobj 194 0 obj << +/S /D /St 31 +>> +endobj +195 0 obj +<< /S /D /St 32 >> endobj xref -0 195 +0 196 0000000000 65535 f 0000000061 00000 n 0000000180 00000 n @@ -11846,7 +11867,7 @@ xref 0001842278 00000 n 0001842486 00000 n 0001842694 00000 n -0001842778 00000 n +0001842902 00000 n 0001842986 00000 n 0001843194 00000 n 0001843402 00000 n @@ -11906,115 +11927,116 @@ xref 0002376160 00000 n 0002376312 00000 n 0002376479 00000 n -0002376631 00000 n -0002376818 00000 n -0002376965 00000 n -0002377120 00000 n -0002377293 00000 n -0002377448 00000 n -0002377594 00000 n -0002377752 00000 n -0002377899 00000 n -0002378086 00000 n -0002378207 00000 n -0002378368 00000 n -0002378510 00000 n -0002378662 00000 n -0002378816 00000 n -0002378957 00000 n -0002379095 00000 n -0002379249 00000 n -0002379451 00000 n -0002379574 00000 n -0002379713 00000 n -0002379877 00000 n -0002380050 00000 n -0002380223 00000 n -0002380370 00000 n -0002380565 00000 n -0002380724 00000 n -0002380892 00000 n -0002381027 00000 n -0002381160 00000 n -0002381305 00000 n -0002381431 00000 n -0002381559 00000 n -0002381670 00000 n -0002381959 00000 n -0002387076 00000 n -0002395160 00000 n -0002399953 00000 n -0002406882 00000 n -0002415796 00000 n -0002425043 00000 n -0002434247 00000 n -0002447264 00000 n -0002457380 00000 n -0002466746 00000 n -0002475326 00000 n -0002486276 00000 n -0002498907 00000 n -0002510827 00000 n -0002520195 00000 n -0002529336 00000 n -0002536960 00000 n -0002546952 00000 n -0002555918 00000 n -0002566223 00000 n -0002569275 00000 n -0002571110 00000 n -0002584566 00000 n -0002601225 00000 n -0002611733 00000 n -0002619192 00000 n -0002625866 00000 n -0002633928 00000 n -0002641864 00000 n -0002648332 00000 n -0002650488 00000 n -0002651566 00000 n -0002651959 00000 n -0002651994 00000 n -0002652029 00000 n -0002652064 00000 n -0002652099 00000 n -0002652134 00000 n -0002652169 00000 n -0002652204 00000 n -0002652239 00000 n -0002652274 00000 n -0002652310 00000 n -0002652346 00000 n -0002652382 00000 n -0002652418 00000 n -0002652454 00000 n -0002652490 00000 n -0002652526 00000 n -0002652562 00000 n -0002652598 00000 n -0002652634 00000 n -0002652670 00000 n -0002652706 00000 n -0002652742 00000 n -0002652778 00000 n -0002652814 00000 n -0002652850 00000 n -0002652886 00000 n -0002652922 00000 n -0002652958 00000 n -0002652994 00000 n -0002653030 00000 n -0002653066 00000 n +0002376644 00000 n +0002376797 00000 n +0002376984 00000 n +0002377131 00000 n +0002377287 00000 n +0002377461 00000 n +0002377617 00000 n +0002377763 00000 n +0002377921 00000 n +0002378068 00000 n +0002378255 00000 n +0002378376 00000 n +0002378537 00000 n +0002378679 00000 n +0002378831 00000 n +0002378985 00000 n +0002379126 00000 n +0002379264 00000 n +0002379418 00000 n +0002379620 00000 n +0002379743 00000 n +0002379882 00000 n +0002380046 00000 n +0002380219 00000 n +0002380392 00000 n +0002380539 00000 n +0002380734 00000 n +0002380893 00000 n +0002381061 00000 n +0002381196 00000 n +0002381329 00000 n +0002381474 00000 n +0002381600 00000 n +0002381728 00000 n +0002381839 00000 n +0002382128 00000 n +0002387245 00000 n +0002395329 00000 n +0002400122 00000 n +0002407051 00000 n +0002415965 00000 n +0002425212 00000 n +0002434416 00000 n +0002447433 00000 n +0002457549 00000 n +0002466915 00000 n +0002475495 00000 n +0002486445 00000 n +0002499076 00000 n +0002509086 00000 n +0002518500 00000 n +0002527270 00000 n +0002537241 00000 n +0002543397 00000 n +0002554154 00000 n +0002563615 00000 n +0002572765 00000 n +0002574875 00000 n +0002588331 00000 n +0002604990 00000 n +0002615498 00000 n +0002622957 00000 n +0002629631 00000 n +0002637693 00000 n +0002645629 00000 n +0002652097 00000 n +0002654253 00000 n +0002655331 00000 n +0002655724 00000 n +0002655759 00000 n +0002655794 00000 n +0002655829 00000 n +0002655864 00000 n +0002655899 00000 n +0002655934 00000 n +0002655969 00000 n +0002656004 00000 n +0002656039 00000 n +0002656075 00000 n +0002656111 00000 n +0002656147 00000 n +0002656183 00000 n +0002656219 00000 n +0002656255 00000 n +0002656291 00000 n +0002656327 00000 n +0002656363 00000 n +0002656399 00000 n +0002656435 00000 n +0002656471 00000 n +0002656507 00000 n +0002656543 00000 n +0002656579 00000 n +0002656615 00000 n +0002656651 00000 n +0002656687 00000 n +0002656723 00000 n +0002656759 00000 n +0002656795 00000 n +0002656831 00000 n trailer << /ID -[] +[] % ReportLab generated PDF document -- digest (opensource) /Info 68 0 R /Root 67 0 R -/Size 195 +/Size 196 >> startxref -2653102 +2656867 %%EOF diff --git a/whitepaper/uncommonlisp-whitepaper.rst b/whitepaper/uncommonlisp-whitepaper.rst index db1fafd..b18fadf 100644 --- a/whitepaper/uncommonlisp-whitepaper.rst +++ b/whitepaper/uncommonlisp-whitepaper.rst @@ -632,26 +632,42 @@ The reason we built the GC at all was to let long-running asm HTTP servers not l Config req/s baseline peak RSS growth KB RSS KB KB ============================== ========= ========= ========== ============= - asm no-GC + ``heap-snapshot`` 484 100 104 **4** - asm GC + ``heap-snapshot`` 462 120 124 **4** - asm no-GC + no snapshot 463 96 45,812 **46,096** - asm GC + no snapshot † — — — + asm no-GC + ``heap-snapshot`` ~300 100 104 **4** + asm GC + ``heap-snapshot`` ~330 120 124 **4** + asm no-GC + no snapshot ~360 96 45,812 **46,096** + asm GC + no snapshot ~410 116 1,088 **972** ============================== ========= ========= ========== ============= -† Crashes at first GC — latent conservative-scan bug, see below. +All four cells validate cleanly now: -Three cells validate cleanly: - -- **Cells 1 and 2** show that on idiomatic code using ``heap-snapshot``, both binaries hold memory absolutely flat (~4 KB growth over 5,000 requests is normal VM noise). The GC build costs ~5% throughput for a feature the snapshot pattern doesn't need — a meaningful signal that if your server is well-written, GC is optional overhead. +- **Cells 1 and 2** show that on idiomatic code using ``heap-snapshot``, both binaries hold memory absolutely flat (~4 KB growth over 5,000 requests is normal VM noise). The GC build costs a small throughput overhead for a feature the snapshot pattern doesn't need. - **Cell 3** demonstrates the leak scenario we explicitly designed the GC build to solve. Without ``heap-snapshot``, the no-GC asm server grows **~9 KB per request** — 46 MB over 5,000 requests, heading to OOM on any real workload. This is the bump-only allocator working exactly as documented. -- **Cell 4** is the one that should have been bounded by naive mark-sweep and wasn't. The server crashes at the first GC trigger (~1 MB of allocations into the run), fixed-size workload triggering another variant of the conservative stack scan's type-confusion. The pattern is identical in kind to the 24-byte env/string collision (§6.6.1) we already fixed — probably a 24- or 40-byte response block being walked as something it isn't. The fix requires tightening one more walker; we logged it as a known issue rather than shipping a fix under time pressure. +- **Cell 4** is the use case the GC was built for. With neither ``heap-snapshot`` nor ``heap-restore``, the GC build bounds memory at one chunk (~1 MB) and serves **faster than the leaking no-GC version** because it doesn't pay ``heap_grow`` mmap-every-64-MB costs on repeated allocation. **972 KB of growth** across 5,000 requests is exactly one heap chunk — the collector hit its natural steady state. -**Honest read.** The GC build succeeds at validating the snapshot pattern (cell 2 is the real deployment target for long-running asm servers) but the "use GC instead of snapshots" use case (cell 4) has an outstanding correctness bug. ``heap-snapshot`` + ``heap-restore`` remain the recommended pattern for production asm code; the naive GC serves as a diagnostic backstop and as the control-group baseline for future memory-management work. This is still progress — we now have a concrete failing case to aim the next round of debugging at, rather than a vague worry. +**Precise-type dispatch was the fix.** Cell 4 was crashing at first GC until we replaced the conservative-scan-plus-sentinel-checks walker with a precise one. Every heap block's 8-byte header now carries an explicit type byte at bits 8–15 (see §6.6.5 below for the redesign), so ``gc_mark_drain``, ``gc_mark_env``, and the arena-escape scan dispatch on the type byte instead of guessing from block size. This eliminated the entire class of "24-byte env vs string" / "40-byte vector vs string" type-confusion bugs we'd been patching one-by-one. + +**Honest read.** The GC build now succeeds at the "GC instead of snapshots" use case. ``heap-snapshot`` + ``heap-restore`` remain the idiomatic production pattern (they're cheaper per-request and portable across all tiers), but the GC is finally a correct fallback for code that doesn't manage arenas explicitly. Remaining rough edge: on very heavy sustained allocation workloads (hash-set benchmark at the ~1 MB/iter scale under the GC build) we still see the occasional unbound-variable error that points to a root-scan edge case the precise-type fix didn't completely close. Tracked as a follow-up. **Reproduce:** ``make bench-gc-http``. Tuning: ``REQUESTS=10000 CONCURRENCY=16 VCAP=524288 bash tests/bench-gc-http.sh``. +6.6.5 Precise Block Typing: Killing a Class of Bugs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Earlier versions of the meta-GC walkers inferred block type from *size* alone. A 24-byte block could be an env node, a closure, or a 16-character string; a 40-byte block could be a 4-element vector or a 25-character string. The walkers tried to guess and guessed wrong under the conservative stack scan — any stack word whose low 3 bits happened to match ``TAG_SYM`` or ``7`` (vector-family) would be dereferenced, its block's size read from the header, and the walker would interpret subsequent payload bytes as tagged child values. Strings-as-vectors reading 200 bytes past their end was the canonical failure. + +We fixed this by adding an explicit type byte to every heap block's header:: + + # Old: [size:63 | mark:1] + # New: [size:48 | type:8 | flags:8 (mark at bit 0)] + +Type constants (``HT_PAIR``, ``HT_CLOSURE``, ``HT_STRING``, ``HT_SYMBOL``, ``HT_VECTOR``, ``HT_HASHTABLE``, ``HT_HASHSET``, ``HT_ENVNODE``, ``HT_CHAINNODE``, ``HT_PADDING``) are set at every ``heap_alloc`` call site in the GC build. Every walker — mark, escape-scan, sweep — now dispatches on the type byte instead of size. A string can never be walked as a vector; an env node can never be confused with a closure. + +Cost: one extra ``orq`` at each of ~15 allocation sites (a few nanoseconds per call) and 16 bits of header space per block (negligible given minimum block size is 16 payload bytes + 8 header bytes). Benefit: the entire "conservative scan misidentifies X as Y" class of bugs goes away. Cell 4 of §6.6.4 flipped from "crashes at first GC" to "working correctly" when this landed. + +The precise-type change also simplified the walkers: the special-case "is the first word -1 (hash-table) or -2 (hash-set) or a small positive number (vector length)" dispatch in ``gc_mark_drain`` collapsed into a single ``cmp`` on the type byte. ~50 lines of heuristic-guessing code deleted. + 7. Portal: Feedback Across Time ----------------------------------------