Files
hakorune/lang/src/runtime/memory/arc_box.hako

63 lines
2.3 KiB
Plaintext

// arc_box.hako — ArcBox (policy plane)
// Responsibility: simple reference counting semantics in Hakorune space.
// Storage: uses env.local.get/set with key prefix "arc:" to keep per-pointer counts.
// Data plane: when available, host-side env.arc.* can replace these, but this MVP
// remains pure to avoid native coupling. Optional free-on-zero via env.mem.free/1
// guarded by HAKO_ARC_FREE_ON_ZERO=1 (NYASH_ alias honored via runner env mirroring).
using "lang/src/shared/common/string_helpers.hako" as StringHelpers
static box ArcBox {
_key(ptr) { return "ARC_" + ("" + ptr) }
_debug_on() {
local d = call("env.local.get/1", "HAKO_DEBUG_ARC")
if d == null || d == "" { d = call("env.local.get/1", "NYASH_DEBUG_ARC") }
return d == "1"
}
_log(msg) { if me._debug_on() { call("env.console.log/1", "[ArcBox] " + msg) } }
// Read current count (>=0) or -1 if unset/unknown)
_get_count(ptr) { return call("env.arc.count/1", ptr) }
// Create a new ARC handle with count=1. Fail if already exists.
arc_birth(ptr) {
local c = me._get_count(ptr)
if c >= 0 { call("env.console.error/1", "[arc/already_exists]") return -1 }
call("env.arc.birth/1", ptr)
me._log("birth ptr=" + ("" + ptr) + " -> 1")
return 1
}
// Increment; Fail if unknown.
arc_retain(ptr) {
local c = call("env.arc.retain/1", ptr)
if c < 0 { call("env.console.error/1", "[arc/unknown]") return -1 }
me._log("retain ptr=" + ("" + ptr) + " -> " + StringHelpers.int_to_str(c))
return c
}
// Decrement; Fail on unknown or underflow. When reaches 0, optionally free via env.mem.free/1
arc_release(ptr) {
local n = call("env.arc.release/1", ptr)
if n < 0 { return -1 }
me._log("release ptr=" + ("" + ptr) + " -> " + StringHelpers.int_to_str(n))
if n == 0 {
local fz = call("env.local.get/1", "HAKO_ARC_FREE_ON_ZERO")
if fz == null || fz == "" { fz = call("env.local.get/1", "NYASH_ARC_FREE_ON_ZERO") }
if fz == "1" {
// Best-effort free; ignore missing handler
call("env.mem.free/1", ptr)
}
}
return n
}
// Return current count or -1 if unknown
arc_count(ptr) { return me._get_count(ptr) }
// Sugar: clone = retain + return ptr (for chaining)
arc_clone(ptr) { local r = me.arc_retain(ptr) if r < 0 { return -1 } return ptr }
}