| 283 | /* ── Allocator functions (installed as tree-sitter callbacks) ───── */ |
| 284 | |
| 285 | static void *slab_malloc(size_t size) { |
| 286 | if (size == 0) { |
| 287 | size = SKIP_ONE; |
| 288 | } |
| 289 | /* Tier 1: ≤64B → slab free list */ |
| 290 | if (size <= SLAB_CHUNK_SIZE) { |
| 291 | slab_state_t *s = &tls_slab; |
| 292 | if (!s->freelist) { |
| 293 | slab_refill(s); |
| 294 | if (!s->freelist) { |
| 295 | return malloc(size); /* grow failed → heap fallback */ |
| 296 | } |
| 297 | } |
| 298 | slab_free_node_t *node = s->freelist; |
| 299 | s->freelist = node->next; |
| 300 | slab_page_t *page = (slab_page_t *)((uintptr_t)node & SLAB_PAGE_MASK); |
| 301 | atomic_fetch_add_explicit(&page->refcount, 1u, memory_order_relaxed); |
| 302 | return node; |
| 303 | } |
| 304 | |
| 305 | /* >64B: straight to malloc (= mimalloc in production) */ |
| 306 | return malloc(size); |
| 307 | } |
| 308 | |
| 309 | static void *slab_calloc(size_t count, size_t size) { |
| 310 | /* Overflow check */ |
no test coverage detected