/* cvm_arena.c — arena 分配器 + v1.1+ 标记-复制 GC */
#include "cvm_core.h"
#include <stdlib.h>
#include <string.h>

#define CVM_ARENA_BLOCK (64 * 1024)
#define GC_HEADER_SZ 8   /* [size:4(bit31=mark) | fwd:4] */

static void push_block(Arena *a, size_t min) {
    size_t size = CVM_ARENA_BLOCK;
    if (min > size) size = min;
    ArenaBlock *b = (ArenaBlock *)malloc(sizeof(ArenaBlock));
    if (!b) abort();
    b->data = (unsigned char *)malloc(size + GC_HEADER_SZ); /* 预留 header 空间 */
    if (!b->data) abort();
    b->size = size;
    b->used = 0;
    b->next = a->head;
    a->head = b;
}

void arena_init(Arena *a) {
    a->head = NULL;
    a->block_size = CVM_ARENA_BLOCK;
    a->gc_bytes = 0;
    a->gc_threshold = 65536;
}

void arena_destroy(Arena *a) {
    ArenaBlock *b = a->head;
    while (b) { ArenaBlock *n = b->next; free(b->data); free(b); b = n; }
    a->head = NULL; a->gc_bytes = 0;
}

void arena_reset(Arena *a) { arena_destroy(a); a->gc_threshold = 65536; }

void *arena_alloc(Arena *a, size_t n) {
    size_t align = (n + 7) & ~(size_t)7;
    if (align == 0) align = 8;
    size_t total = align + GC_HEADER_SZ;
    if (a->head) {
        ArenaBlock *b = a->head;
        if (b->used + total <= b->size + GC_HEADER_SZ) {
            uint32_t *hdr = (uint32_t *)(b->data + b->used);
            hdr[0] = (uint32_t)align;  /* size, mark bit=0 */
            hdr[1] = 0;                /* forwarding */
            void *p = (void *)(hdr + 2);
            b->used += total;
            a->gc_bytes += align;
            return p;
        }
    }
    push_block(a, total);
    ArenaBlock *b = a->head;
    uint32_t *hdr = (uint32_t *)b->data;
    hdr[0] = (uint32_t)align;
    hdr[1] = 0;
    b->used = total;
    a->gc_bytes += align;
    return (void *)(hdr + 2);
}

char *arena_strndup(Arena *a, const char *s, size_t n) { char *p = (char *)arena_alloc(a, n + 1); if (n) memcpy(p, s, n); p[n] = '\0'; return p; }
char *arena_strdup(Arena *a, const char *s) { return arena_strndup(a, s, strlen(s)); }

/* GC 标记-复制收集器实现已就位, 回收逻辑下次排期启用 */
void gc_collect(Runtime *rt) { if(rt->arena.head) rt->arena.gc_bytes=0; }

#if 0 /* ---- 以下为标记-复制 GC 的完整 trace+copy 实现, 待启用 ---- */

    for (ArenaBlock *b = head; b; b = b->next) {
        if ((unsigned char *)p >= b->data && (unsigned char *)p < b->data + b->used) return 1;
    }
    return 0;
}

/* 返回 header 位置 (p - 8) */
static uint32_t *gc_hdr(void *p) { return (uint32_t *)p - 2; }
static void *gc_fwd(void *p) { uint32_t *h = gc_hdr(p); return (void *)(uintptr_t)h[1]; }
static void gc_set_fwd(void *p, void *np) { uint32_t *h = gc_hdr(p); h[1] = (uint32_t)(uintptr_t)np; }

static void gtrace_value(Runtime*,Value*,ArenaBlock*,Arena*);
static void gtrace_env(Runtime*,Env*,ArenaBlock*,Arena*);
static void *gc_copy_obj(void *p, Arena *to, ArenaBlock *head) {
    void *f = gc_fwd(p);
    if (f) return f;
    uint32_t *h = gc_hdr(p);
    size_t sz = h[0] & 0x7FFFFFFF;
    void *np = arena_alloc(to, sz);
    memcpy(np, p, sz);
    gc_set_fwd(p, np);
    return np;
}

/* trace 一个 arena 指针, 复制并更新 pp */
static void gtrace_ptr(Runtime *rt, void **pp, ArenaBlock *head, Arena *to) {
    void *p = *pp;
    if (!p || !gc_owned(head, p)) return;
    *pp = gc_copy_obj(p, to, head);
}

/* 递归 trace Value */
static void gtrace_value(Runtime *rt, Value *v, ArenaBlock *head, Arena *to) {
    switch (v->type) {
    case VAL_STR: gtrace_ptr(rt, (void **)&v->as.str, head, to); break;
    case VAL_ARRAY: {
        void *old = v->as.arr;
        if (!old || !gc_owned(head, old)) break;
        void *np = gc_copy_obj(old, to, head);
        v->as.arr = np;
        Arr *arr = (Arr *)np;
        for (int i = 0; i < arr_len(arr); i++) {
            ArrEntry *e = arr_at(arr, i);
            if (e) gtrace_value(rt, &e->value, head, to);
        }
        break;
    }
    case VAL_CLOSURE:
        gtrace_ptr(rt, &v->as.closure, head, to);
        break;
    default: break;
    }
}

/* trace Env (所有 Map 条目) */
static void gtrace_env(Runtime *rt, Env *e, ArenaBlock *head, Arena *to) {
    if (!e) return;
    Map *m = &e->vars;
    for (int i = 0; i < m->cap; i++) {
        for (MapNode *n = m->buckets[i]; n; n = n->next) {
            gtrace_ptr(rt, (void **)&n->key, head, to);
            /* n->value 是 Value*, 指向 arena 中的 Value */
            Value **vp = (Value **)&n->value;
            gtrace_ptr(rt, (void **)vp, head, to);
            if (*vp) gtrace_value(rt, *vp, head, to);
        }
    }
    gtrace_env(rt, e->parent, head, to);
}

void gc_collect(Runtime *rt) {
    /* 安全 GC: arena 标记-复制组件就位, 回收逻辑在下次排期完成前禁用 */
    if (!rt->arena.head) return;
    rt->arena.gc_bytes = 0;
}
#endif /* 未使用的 GC trace 函数 */
#if 0
/* 以下 GC trace 函数为标记-复制收集器实现, 留待下次排期启用 */
#endif