/* Bench-only bump allocator stub.
 *
 * Used by `ail build --alloc=bump` (Bench iter) to A/B compare AILang
 * binaries against the default Boehm-GC build. The whole runtime is a
 * 256 MB statically-allocated arena and a single bump pointer; there
 * is no `free`, no scan, no anything. If the workload exceeds 256 MB
 * we abort — this is bench code, the right response to overflow is to
 * notice and pick a smaller workload.
 *
 * The signature mirrors `GC_malloc` from libgc: `void *bump_malloc(size_t)`.
 * The codegen replaces every `call ptr @GC_malloc` with
 * `call ptr @bump_malloc` when `--alloc=bump` is set, so the AILang IR
 * is otherwise byte-identical between the two strategies.
 */

#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#define ARENA_BYTES (256ul * 1024ul * 1024ul)

static uint8_t arena[ARENA_BYTES];
static size_t cursor = 0;

void *bump_malloc(size_t n) {
    /* Align bump pointer up to 8 bytes — AILang's allocations are all
     * 8-byte aligned (tag + 8-byte fields, env pointers, closure pairs
     * of two `ptr`s). Matches the alignment Boehm gives us. */
    size_t aligned = (cursor + 7ul) & ~((size_t)7ul);
    if (aligned + n > ARENA_BYTES) {
        fprintf(stderr,
                "bump_malloc: arena exhausted (cursor=%zu, requested=%zu, arena=%zu)\n",
                aligned, n, (size_t)ARENA_BYTES);
        abort();
    }
    void *p = (void *)(arena + aligned);
    cursor = aligned + n;
    return p;
}
