mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-26 06:34:20 +08:00
A typed teardown freed each block onto its free list as it went, and the free lists, which are LIFO, handed a torn-down structure's blocks to the next allocations in the reverse order. A structure that a loop rebuilds the same way each time was therefore laid out mirrored every other generation, and every walk over it, its teardown included, ran through memory backwards, which the hardware prefetchers handle three to four times worse. A program that rebuilds a tree of 2^21 - 1 object literals 12 times, summing each generation before dropping it, took 26 to 28 ns per node to build, 24 to sum and 16 to drop in those generations, against 6.8, 6.3 and 5.3 in the others. With this change, every generation runs at the second set of times, and the program takes 0.50 s instead of 1.18 s (Node: 0.91 s). The teardown of a class or record type with children of its own type now keeps the blocks it frees in a segment, linked through their first words and built in order through a tail pointer. A node releases its own block first, places it ahead of its children's when its address is the lower (object literals allocate before their fields) and behind them otherwise (constructor arguments build the children first), and the chain's first teardown frees the whole segment onto the free list in one step. A teardown past DIRECT_DESTROY_CHAIN appends through scr_rc_destroy_seg, which keeps scr_rc_destroy's depth budget and queue. Blocks outside the calling thread's arena are freed as before, and targets without the inline allocation paths keep the old teardown.