/* Embedding-ABI M3 record round-trip C host (own + borrow via a * compile-time -DBORROW switch). Frozen value layout * (design/contracts/0006-frozen-value-layout.md): * p - 8 .. p uint64_t refcount header (set to 1 by ailang_rc_alloc) * p + 0 int64_t constructor tag (single ctor → 0) * p + 8 IEEE-754 double field 0 = Float acc * p + 16 int64_t field 1 = Int n * Total payload = 8 + 2*8 = 24. * * own : the kernel consumes each `(own (con State))` input (drop at * return); the host must NOT touch/dec it after the call. * borrow: the kernel does NOT consume the `(borrow (con State))` * input; the host retains it and dec's it itself each iter. * In both modes the return is host-owned and host-freed. */ #include #include #include #include typedef struct ailang_ctx ailang_ctx_t; extern ailang_ctx_t *ailang_ctx_new(void); extern void ailang_ctx_free(ailang_ctx_t *); extern void *ailang_rc_alloc(size_t); extern void ailang_rc_dec(void *); extern void *backtest_step(ailang_ctx_t *ctx, void *st, double sample); static void *make_state(double acc, int64_t n) { void *p = ailang_rc_alloc(8 + 2 * 8); /* header=1 set by runtime */ *(int64_t *)((char *)p + 0) = 0; /* single-ctor tag = 0 */ memcpy((char *)p + 8, &acc, 8); /* Float acc @ 8 */ *(int64_t *)((char *)p + 16) = n; /* Int n @ 16 */ return p; } int main(void) { ailang_ctx_t *ctx = ailang_ctx_new(); void *st = make_state(0.0, 0); for (int i = 0; i < 1000000; i++) { void *next = backtest_step(ctx, st, (double)(i & 7)); #ifdef BORROW ailang_rc_dec(st); /* borrow: host retained input, frees it */ #endif /* own: kernel consumed `st`; do NOT touch/dec it here. */ st = next; /* return is host-owned */ } double acc; memcpy(&acc, (char *)st + 8, 8); int64_t n = *(int64_t *)((char *)st + 16); assert(n == 1000000); ailang_rc_dec(st); /* host frees the final return */ ailang_ctx_free(ctx); /* AILANG_RC_STATS readback fires here */ return 0; }