diff --git a/runtime/src/const.h b/runtime/src/const.h index 057e32fd..419217b0 100644 --- a/runtime/src/const.h +++ b/runtime/src/const.h @@ -37,7 +37,6 @@ /* ── 路径/成员分隔符 ───────────────────────────────────────────────── */ #define PATH_SEP "/" -#define DIR_INDEX_SUF "/" #define MEMBER_SEP "\xC2\xB7" /* · U+00B7 中点号:成员分隔符,释放 '.' 供小数 key */ #define MEMBER_SEP_LEN 2 /* MEMBER_SEP 的 UTF-8 字节数 */ #define INDEX_VALUE_SEP "\n" diff --git a/runtime/src/dispatch.c b/runtime/src/dispatch.c index 094fdde2..445fabfa 100644 --- a/runtime/src/dispatch.c +++ b/runtime/src/dispatch.c @@ -222,6 +222,90 @@ bool kvlangDispatchIsDelegatedOp(kvlangKv_t *kv, const char *opcode) { return ok; } +typedef struct { + char **v; + size_t n, cap, len; +} parts_t; + +static void parts_push(parts_t *p, char *s) { + if (p->n == p->cap) { + p->cap = p->cap ? p->cap * 2 : 8; + p->v = realloc(p->v, sizeof(char *) * p->cap); + if (!p->v) + kvlangDie("out of memory building string parts"); + } + p->v[p->n++] = s; + p->len += strlen(s); +} + +/* 拼接后释放所有片段;sep 仅用于分隔。 */ +static char *parts_join(parts_t *p, const char *sep) { + size_t sl = strlen(sep); + size_t total = p->len + (p->n > 1 ? (p->n - 1) * sl : 0); + char *out = malloc(total + 1); + if (!out) + kvlangDie("out of memory joining string parts"); + size_t off = 0; + for (size_t i = 0; i < p->n; i++) { + if (i && sl) { + memcpy(out + off, sep, sl); + off += sl; + } + size_t n = strlen(p->v[i]); + memcpy(out + off, p->v[i], n); + off += n; + free(p->v[i]); + } + out[off] = 0; + free(p->v); + *p = (parts_t){0}; + return out; +} + +static char *json_esc_dup(const char *s) { + size_t n = 2; /* quotes */ + for (const char *p = s ? s : ""; *p; p++) { + unsigned char c = (unsigned char)*p; + n += (c == '"' || c == '\\' || c == '\n' || c == '\r' || c == '\t') + ? 2 + : c < 0x20 ? 6 : 1; + } + char *o = malloc(n + 1); + if (!o) + kvlangDie("out of memory escaping json"); + static const char hex[] = "0123456789abcdef"; + size_t off = 0; + o[off++] = '"'; + for (const char *p = s ? s : ""; *p; p++) { + unsigned char c = (unsigned char)*p; + if (c == '"' || c == '\\') { + o[off++] = '\\'; + o[off++] = (char)c; + } else if (c == '\n') { + o[off++] = '\\'; + o[off++] = 'n'; + } else if (c == '\r') { + o[off++] = '\\'; + o[off++] = 'r'; + } else if (c == '\t') { + o[off++] = '\\'; + o[off++] = 't'; + } else if (c < 0x20) { + o[off++] = '\\'; + o[off++] = 'u'; + o[off++] = '0'; + o[off++] = '0'; + o[off++] = hex[(c >> 4) & 0xF]; + o[off++] = hex[c & 0xF]; + } else { + o[off++] = (char)c; + } + } + o[off++] = '"'; + o[off] = 0; + return o; +} + static int select_backend(kvlangKv_t *kv, const char *op, char **out, char *err, size_t err_cap) { *out = NULL; strlist_t reg = {0}, duty = {0}; @@ -233,23 +317,19 @@ static int select_backend(kvlangKv_t *kv, const char *op, char **out, char *err, return -1; } if (duty.n == 0) { - kvlangStrbuf_t got; - kvlangStrbufInit(&got); + parts_t got = {0}; for (int i = 0; i < reg.n; i++) { - if (i) - kvlangStrbufPuts(&got, ", "); char *sk = kvlangKeytreeSysRwirBackendStatus(reg.v[i]); char *st = get_char(kv, sk); free(sk); - kvlangStrbufPuts(&got, reg.v[i]); - kvlangStrbufPuts(&got, "="); - kvlangStrbufPuts(&got, st ? st : ""); + parts_push(&got, kvlangAstr("%s=%s", reg.v[i], st ? st : "")); free(st); } + char *got_line = parts_join(&got, ", "); snprintf(err, err_cap, "no on-duty backend for opcode=%s; backend status must be ready|busy, got %s", - op, got.p ? got.p : ""); - kvlangStrbufFree(&got); + op, got_line); + free(got_line); sl_free(®); sl_free(&duty); return -1; @@ -300,26 +380,6 @@ static int set_char(kvlangKv_t *kv, const char *key, const char *s, char *err, u return rc; } -static void json_esc(kvlangStrbuf_t *b, const char *s) { - kvlangStrbufPutc(b, '"'); - for (; s && *s; s++) { - unsigned char c = (unsigned char)*s; - if (c == '"' || c == '\\') { - kvlangStrbufPutc(b, '\\'); - kvlangStrbufPutc(b, (char)c); - } else if (c == '\n') - kvlangStrbufPuts(b, "\\n"); - else if (c == '\r') - kvlangStrbufPuts(b, "\\r"); - else if (c == '\t') - kvlangStrbufPuts(b, "\\t"); - else if (c < 0x20) - kvlangStrbufPrintf(b, "\\u%04x", (unsigned)c); - else - kvlangStrbufPutc(b, (char)c); - } - kvlangStrbufPutc(b, '"'); -} static bool is_var_slot(const kvlangParam_t *p) { if (!p->name || !p->name[0] || strstr(p->name, "/" RUNTIME_MEMBER_SEP "operand[")) @@ -397,18 +457,15 @@ int kvlangDispatchDelegate(kvlangKv_t *kv, const char *vtid, const char *pc, kvl kvlangXvalueFree(&sig); return KVLANG_DELEGATE_LOCAL; } - kvlangStrbuf_t names; - kvlangStrbufInit(&names); - for (int i = 0; i < duty.n; i++) { - if (i) - kvlangStrbufPuts(&names, ","); - kvlangStrbufPuts(&names, duty.v[i]); - } + parts_t names = {0}; + for (int i = 0; i < duty.n; i++) + parts_push(&names, strdup(duty.v[i])); sl_free(&duty); + char *name_list = parts_join(&names, ","); int rc = fail_msg(kv, vtid, pc, "%s: on-duty backend %s and local rwfunc both define it; one opcode, one definition", - op, names.p ? names.p : ""); - kvlangStrbufFree(&names); + op, name_list); + free(name_list); kvlangXvalueFree(&sig); return rc; } @@ -476,54 +533,55 @@ int kvlangDispatchDelegate(kvlangKv_t *kv, const char *vtid, const char *pc, kvl out_keys[i] = key; } - kvlangStrbuf_t json; - kvlangStrbufInit(&json); - kvlangStrbufPuts(&json, "{\"request_id\":"); - json_esc(&json, task_id); - kvlangStrbufPuts(&json, ",\"vtid\":"); - json_esc(&json, vtid); - kvlangStrbufPuts(&json, ",\"pc\":"); - json_esc(&json, pc); - kvlangStrbufPuts(&json, ",\"opcode\":"); - json_esc(&json, op); - kvlangStrbufPuts(&json, ",\"inputs\":["); + char *json = NULL; + parts_t j = {0}; + parts_push(&j, strdup("{\"request_id\":")); + parts_push(&j, json_esc_dup(task_id)); + parts_push(&j, strdup(",\"vtid\":")); + parts_push(&j, json_esc_dup(vtid)); + parts_push(&j, strdup(",\"pc\":")); + parts_push(&j, json_esc_dup(pc)); + parts_push(&j, strdup(",\"opcode\":")); + parts_push(&j, json_esc_dup(op)); + parts_push(&j, strdup(",\"inputs\":[")); for (int i = 0; i < inst->nr; i++) { if (i) - kvlangStrbufPutc(&json, ','); - kvlangStrbufPutc(&json, '{'); + parts_push(&j, strdup(",")); + parts_push(&j, strdup("{")); char *rk = is_var_slot(&inst->reads[i]) ? kvlangBuiltinResolveWriteSlot(kv, fr, inst->reads[i].name) : NULL; if (rk && !keyset_has(out_keys, inst->nw, rk)) { - kvlangStrbufPuts(&json, "\"key\":"); - json_esc(&json, rk); + parts_push(&j, strdup("\"key\":")); + parts_push(&j, json_esc_dup(rk)); } else { kvlangXvalue_t val; kvlangXvalueZero(&val); kvlangBuiltinResolveReadValue(kv, fr, inst->reads[i].name, &inst->reads[i].val, &val); char *disp = NULL; kvlangDisplay(&val, &disp); - kvlangStrbufPuts(&json, "\"value\":"); - json_esc(&json, disp ? disp : ""); + parts_push(&j, strdup("\"value\":")); + parts_push(&j, json_esc_dup(disp ? disp : "")); free(disp); kvlangXvalueFree(&val); } free(rk); - kvlangStrbufPutc(&json, '}'); + parts_push(&j, strdup("}")); } - kvlangStrbufPuts(&json, "],\"outputs\":["); + parts_push(&j, strdup("],\"outputs\":[")); for (int i = 0; i < inst->nw; i++) { if (i) - kvlangStrbufPutc(&json, ','); - kvlangStrbufPuts(&json, "{\"key\":"); - json_esc(&json, out_keys[i]); - kvlangStrbufPutc(&json, '}'); + parts_push(&j, strdup(",")); + parts_push(&j, strdup("{\"key\":")); + parts_push(&j, json_esc_dup(out_keys[i])); + parts_push(&j, strdup("}")); } char *done_key = kvlangKeytreeDoneRwir(task_id); - kvlangStrbufPuts(&json, "],\"done_key\":"); - json_esc(&json, done_key); + parts_push(&j, strdup("],\"done_key\":")); + parts_push(&j, json_esc_dup(done_key)); free(done_key); - kvlangStrbufPutc(&json, '}'); + parts_push(&j, strdup("}")); + json = parts_join(&j, ""); char *status_key = kvlangKeytreeSysTask(task_id, SEG_STATUS); kvlangXvalue_t existing; @@ -548,18 +606,13 @@ int kvlangDispatchDelegate(kvlangKv_t *kv, const char *vtid, const char *pc, kvl } char *cmd = kvlangKeytreeSysRwirBackendCmd(backend); - kvlangStrbuf_t cmdk; - kvlangStrbufInit(&cmdk); - kvlangStrbufPuts(&cmdk, cmd); - kvlangStrbufPutc(&cmdk, '/'); - kvlangStrbufPuts(&cmdk, task_id); + char cmdk[KV_KEY_MAX]; + kvlangKeyFmt(cmdk, sizeof cmdk, "%s/%s", cmd, task_id); free(cmd); - if (set_char(kv, cmdk.p, json.p, err, sizeof err) != 0) { + if (set_char(kv, cmdk, json, err, sizeof err) != 0) { rc = fail_msg(kv, vtid, pc, "push task: %s", err); - kvlangStrbufFree(&cmdk); goto enqueue_done; } - kvlangStrbufFree(&cmdk); kvlangVthreadSet(kv, vtid, pc, "wait"); kvlangLogDebug("[%s] DELEGATE %s task=%s", vtid, inst->opcode, task_id); @@ -595,16 +648,15 @@ int kvlangDispatchDelegate(kvlangKv_t *kv, const char *vtid, const char *pc, kvl } } - kvlangStrbuf_t npc; - kvlangStrbufInit(&npc); - kvlangRwirNextPc(pc, &npc); - kvlangVthreadSet(kv, vtid, npc.p, "running"); - kvlangStrbufFree(&npc); + char npc[KV_KEY_MAX]; + if (kvlangRwirNextPcBuf(pc, npc, sizeof npc) == 0) + kvlangDie("next pc exceeds %zu bytes", sizeof npc); + kvlangVthreadSet(kv, vtid, npc, "running"); kvlangLogDebug("[%s] DONE %s task=%s", vtid, inst->opcode, task_id); enqueue_done: free(status_key); - kvlangStrbufFree(&json); + free(json); done: if (out_keys) { for (int i = 0; i < inst->nw; i++) diff --git a/runtime/src/keytree.c b/runtime/src/keytree.c index 0ee6590d..19f1f48f 100644 --- a/runtime/src/keytree.c +++ b/runtime/src/keytree.c @@ -1,15 +1,20 @@ #include "runtime_internal.h" -const char *kvlangKeytreeVtidFromPc(const char *pc, kvlangStrbuf_t *out) { - kvlangStrbufClear(out); +const char *kvlangKeytreeVtidFromPc(const char *pc, char *out, size_t cap) { const char *pfx = VTHREAD_ROOT PATH_SEP; size_t pl = strlen(pfx); - if (strncmp(pc, pfx, pl) != 0) return ""; + if (strncmp(pc, pfx, pl) != 0) { + if (cap) out[0] = 0; + return ""; + } const char *rest = pc + pl; const char *slash = strchr(rest, '/'); - if (slash) kvlangStrbufPutn(out, rest, (size_t)(slash - rest)); - else kvlangStrbufPuts(out, rest); - return out->p; + size_t n = slash ? (size_t)(slash - rest) : strlen(rest); + if (n + 1 > cap) + kvlangDie("vtid exceeds %zu bytes", cap); + memcpy(out, rest, n); + out[n] = 0; + return out; } char *kvlangKeytreeStack(const char *root) { @@ -66,67 +71,53 @@ static char *trim_right_join(const char *root, const char *suffix) { char *kvlangKeytreeEntryPc(const char *root) { return trim_right_join(root, "/[1,0]"); } -static void keytree_die(const char *fmt, ...) { - fputs("panic: ", stderr); - va_list ap; va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fputc('\n', stderr); - abort(); -} - char *kvlangKeytreeFrameAt(const char *vtid, int depth) { - if (!vtid || !vtid[0]) keytree_die("FrameAt: empty vtid"); - if (depth < 1) keytree_die("FrameAt: depth %d < 1", depth); - kvlangStrbuf_t b; kvlangStrbufInit(&b); - kvlangStrbufPrintf(&b, "%s/%s/[%d]", VTHREAD_ROOT, vtid, depth); - return kvlangStrbufDetach(&b); + if (!vtid || !vtid[0]) kvlangDie("FrameAt: empty vtid"); + if (depth < 1) kvlangDie("FrameAt: depth %d < 1", depth); + return kvlangAstr("%s/%s/[%d]", VTHREAD_ROOT, vtid, depth); } int kvlangKeytreeFrameNum(const char *path) { /* 免分配:/vthread//[d][/...] —— 直接定位 vtid 后的帧坐标,不构造前缀串。 */ const size_t rl = sizeof(VTHREAD_ROOT) - 1; if (strncmp(path, VTHREAD_ROOT PATH_SEP, rl + 1) != 0) - keytree_die("FrameNum: not a vthread path: %s", path); + kvlangDie("FrameNum: not a vthread path: %s", path); const char *vtid = path + rl + 1; const char *slash = strchr(vtid, '/'); if (!slash || slash == vtid) - keytree_die("FrameNum: not a vthread path: %s", path); + kvlangDie("FrameNum: not a vthread path: %s", path); const char *rest = slash + 1; - if (rest[0] != '[') keytree_die("FrameNum: no frame coord in %s", path); + if (rest[0] != '[') kvlangDie("FrameNum: no frame coord in %s", path); const char *end = strchr(rest, ']'); - if (!end) keytree_die("FrameNum: unterminated frame coord in %s", path); + if (!end) kvlangDie("FrameNum: unterminated frame coord in %s", path); size_t clen = (size_t)(end - (rest + 1)); if (clen == 0 || memchr(rest + 1, ',', clen)) { - keytree_die("FrameNum: expected [d] frame coord in %s", path); + kvlangDie("FrameNum: expected [d] frame coord in %s", path); } char buf[32]; - if (clen >= sizeof buf) keytree_die("FrameNum: frame coord too long in %s", path); + if (clen >= sizeof buf) kvlangDie("FrameNum: frame coord too long in %s", path); memcpy(buf, rest + 1, clen); buf[clen] = 0; char *ep = NULL; long n = strtol(buf, &ep, 10); - if (ep == buf || *ep != 0 || n < 1) keytree_die("FrameNum: invalid frame number %s in %s", buf, path); + if (ep == buf || *ep != 0 || n < 1) kvlangDie("FrameNum: invalid frame number %s in %s", buf, path); const char *after = end + 1; if (after[0] == 0 || (after[0] == '/' && after[1] == 0)) { /* frame root */ } else if (after[0] == '/' && after[1] == '[') { const char *tail = after + 1; - if (strchr(tail, '/')) keytree_die("FrameNum: nested path after [d]: %s", path); - if (!strchr(tail, ',')) keytree_die("FrameNum: expected [irseq,j] after [d] in %s", path); + if (strchr(tail, '/')) kvlangDie("FrameNum: nested path after [d]: %s", path); + if (!strchr(tail, ',')) kvlangDie("FrameNum: expected [irseq,j] after [d] in %s", path); } else { - keytree_die("FrameNum: expected /[irseq,j] after [d] in %s", path); + kvlangDie("FrameNum: expected /[irseq,j] after [d]: %s", path); } return (int)n; } char *kvlangKeytreeIrseqPc(const char *frame_root, int irseq) { - if (irseq < 0) keytree_die("IrseqPC: irseq %d < 0", irseq); - kvlangStrbuf_t b; kvlangStrbufInit(&b); + if (irseq < 0) kvlangDie("IrseqPC: irseq %d < 0", irseq); size_t n = strlen(frame_root); while (n > 0 && frame_root[n - 1] == '/') n--; - kvlangStrbufPutn(&b, frame_root, n); - kvlangStrbufPrintf(&b, "/[%d,0]", irseq); - return kvlangStrbufDetach(&b); + return kvlangAstr("%.*s/[%d,0]", (int)n, frame_root, irseq); } char *kvlangKeytreeMember(const char *base, const char *name) { @@ -140,65 +131,66 @@ char *kvlangKeytreeMember(const char *base, const char *name) { } char *kvlangKeytreeLibFunc(const char *pkg, const char *name) { - kvlangStrbuf_t b; kvlangStrbufInit(&b); - kvlangStrbufPuts(&b, LIB_ROOT PATH_SEP); - if (pkg && pkg[0]) { kvlangStrbufPuts(&b, pkg); kvlangStrbufPuts(&b, MEMBER_SEP); } - kvlangStrbufPuts(&b, name); - return kvlangStrbufDetach(&b); + if (pkg && pkg[0]) + return kvlangAstr("%s%s%s%s", LIB_ROOT PATH_SEP, pkg, MEMBER_SEP, name); + return kvlangAstr("%s%s", LIB_ROOT PATH_SEP, name); } char *kvlangKeytreeRwir(const char *opcode) { - kvlangStrbuf_t b; kvlangStrbufInit(&b); - kvlangStrbufPuts(&b, LIB_ROOT PATH_SEP); - kvlangStrbufPuts(&b, opcode); - return kvlangStrbufDetach(&b); + return kvlangAstr("%s%s", LIB_ROOT PATH_SEP, opcode); } -void kvlangKeytreeVthread(const char *vtid, kvlangStrbuf_t *out) { - kvlangStrbufClear(out); - kvlangStrbufPuts(out, VTHREAD_ROOT PATH_SEP); - kvlangStrbufPuts(out, vtid); +void kvlangKeytreeVthread(const char *vtid, char *out, size_t cap) { + kvlangKeyFmt(out, cap, "%s%s", VTHREAD_ROOT PATH_SEP, vtid); } -void kvlangKeytreeVthreadSlot(const char *vtid, const char *frame, int i, int j, kvlangStrbuf_t *out) { - kvlangStrbufClear(out); - kvlangStrbufPuts(out, VTHREAD_ROOT PATH_SEP); - kvlangStrbufPuts(out, vtid); - if (frame && frame[0]) { kvlangStrbufPutc(out, '/'); kvlangStrbufPuts(out, frame); } - kvlangStrbufPrintf(out, "/[%d,%d]", i, j); +void kvlangKeytreeVthreadSlot(const char *vtid, const char *frame, int i, int j, + char *out, size_t cap) { + if (frame && frame[0]) + kvlangKeyFmt(out, cap, "%s%s/%s/[%d,%d]", VTHREAD_ROOT PATH_SEP, vtid, + frame, i, j); + else + kvlangKeyFmt(out, cap, "%s%s/[%d,%d]", VTHREAD_ROOT PATH_SEP, vtid, i, j); } -static void kvlangVthreadMember(const char *vtid, const char *seg, kvlangStrbuf_t *out) { - kvlangStrbufClear(out); - kvlangStrbufPuts(out, VTHREAD_ROOT PATH_SEP); - kvlangStrbufPuts(out, vtid); - kvlangStrbufPutc(out, '/'); - kvlangStrbufPuts(out, RUNTIME_MEMBER_SEP); - kvlangStrbufPuts(out, seg); +static void kvlangVthreadMember(const char *vtid, const char *seg, char *out, + size_t cap) { + kvlangKeyFmt(out, cap, "%s%s%s%s%s", VTHREAD_ROOT PATH_SEP, vtid, "/", + RUNTIME_MEMBER_SEP, seg); } -void kvlangKeytreeVthreadPc(const char *vtid, kvlangStrbuf_t *out) { kvlangVthreadMember(vtid, SEG_PC, out); } -void kvlangKeytreeVthreadStatus(const char *vtid, kvlangStrbuf_t *out) { kvlangVthreadMember(vtid, SEG_STATUS, out); } -void kvlangKeytreeVthreadDebugger(const char *vtid, kvlangStrbuf_t *out) { kvlangVthreadMember(vtid, "debugger", out); } +void kvlangKeytreeVthreadPc(const char *vtid, char *out, size_t cap) { + kvlangVthreadMember(vtid, SEG_PC, out, cap); +} +void kvlangKeytreeVthreadStatus(const char *vtid, char *out, size_t cap) { + kvlangVthreadMember(vtid, SEG_STATUS, out, cap); +} +void kvlangKeytreeVthreadDebugger(const char *vtid, char *out, size_t cap) { + kvlangVthreadMember(vtid, "debugger", out, cap); +} -void kvlangKeytreeVthreadStatusMsg(const char *vtid, const char *status, kvlangStrbuf_t *out) { - kvlangVthreadMember(vtid, status, out); - kvlangStrbufPutc(out, '/'); - kvlangStrbufPuts(out, SEG_MSG); +void kvlangKeytreeVthreadStatusMsg(const char *vtid, const char *status, + char *out, size_t cap) { + kvlangKeyFmt(out, cap, "%s%s%s%s%s%s%s", VTHREAD_ROOT PATH_SEP, vtid, "/", + RUNTIME_MEMBER_SEP, status, "/", SEG_MSG); } -static void frame_member(const char *root, const char *seg, kvlangStrbuf_t *out) { - kvlangStrbufClear(out); - char *s = kvlangKeytreeStack(root); - kvlangStrbufPuts(out, s); - free(s); - kvlangStrbufPuts(out, RUNTIME_MEMBER_SEP); - kvlangStrbufPuts(out, seg); +static void frame_member(const char *root, const char *seg, char *out, + size_t cap) { + size_t n = strlen(root); + while (n > 0 && root[n - 1] == '/') n--; + kvlangKeyFmt(out, cap, "%.*s%s%s", (int)n, root, RUNTIME_MEMBER_SEP, seg); } -void kvlangKeytreeFrameCallpc(const char *root, kvlangStrbuf_t *out) { frame_member(root, SEG_CALLPC, out); } -void kvlangKeytreeFrameReturnpc(const char *root, kvlangStrbuf_t *out) { frame_member(root, SEG_RETURNPC, out); } -void kvlangKeytreeFrameRo(const char *root, kvlangStrbuf_t *out) { frame_member(root, SEG_RO, out); } +void kvlangKeytreeFrameCallpc(const char *root, char *out, size_t cap) { + frame_member(root, SEG_CALLPC, out, cap); +} +void kvlangKeytreeFrameReturnpc(const char *root, char *out, size_t cap) { + frame_member(root, SEG_RETURNPC, out, cap); +} +void kvlangKeytreeFrameRo(const char *root, char *out, size_t cap) { + frame_member(root, SEG_RO, out, cap); +} bool kvlangKeytreeIsEntryPc(const char *pc) { const char *slash = strrchr(pc, '/'); @@ -222,18 +214,13 @@ bool kvlangKeytreeValidSegment(const char *s) { } static char *join3(const char *a, const char *b, const char *c) { - kvlangStrbuf_t s; - kvlangStrbufInit(&s); - kvlangStrbufPuts(&s, a); - if (b && b[0]) { - kvlangStrbufPutc(&s, '/'); - kvlangStrbufPuts(&s, b); - } - if (c && c[0]) { - kvlangStrbufPutc(&s, '/'); - kvlangStrbufPuts(&s, c); - } - return kvlangStrbufDetach(&s); + if (b && b[0] && c && c[0]) + return kvlangAstr("%s/%s/%s", a, b, c); + if (b && b[0]) + return kvlangAstr("%s/%s", a, b); + if (c && c[0]) + return kvlangAstr("%s/%s", a, c); + return strdup(a); } char *kvlangKeytreeSysRwirBackendRoot(void) { @@ -245,13 +232,8 @@ char *kvlangKeytreeSysRwirBackend(const char *name) { } char *kvlangKeytreeSysRwirBackendOp(const char *name, const char *opcode) { - kvlangStrbuf_t s; - kvlangStrbufInit(&s); - kvlangStrbufPuts(&s, SYS_ROOT PATH_SEP SEG_RWIR_BACKEND "/"); - kvlangStrbufPuts(&s, name); - kvlangStrbufPuts(&s, "/" SEG_OP "/"); - kvlangStrbufPuts(&s, opcode); - return kvlangStrbufDetach(&s); + return kvlangAstr("%s/%s/%s/%s", SYS_ROOT PATH_SEP SEG_RWIR_BACKEND, name, + SEG_OP, opcode); } char *kvlangKeytreeSysRwirBackendCmd(const char *name) { @@ -275,14 +257,8 @@ char *kvlangKeytreeSysRwirBackendCategoryRoot(const char *name) { } char *kvlangKeytreeSysTask(const char *task_id, const char *field) { - kvlangStrbuf_t s; - kvlangStrbufInit(&s); - kvlangStrbufPuts(&s, SYS_ROOT PATH_SEP SEG_TASK "/"); - kvlangStrbufPuts(&s, task_id); - kvlangStrbufPutc(&s, '/'); - kvlangStrbufPuts(&s, RUNTIME_MEMBER_SEP); - kvlangStrbufPuts(&s, field); - return kvlangStrbufDetach(&s); + return kvlangAstr("%s/%s/%s%s", SYS_ROOT PATH_SEP SEG_TASK, task_id, + RUNTIME_MEMBER_SEP, field); } char *kvlangKeytreeDoneRwir(const char *task_id) { @@ -290,12 +266,7 @@ char *kvlangKeytreeDoneRwir(const char *task_id) { } char *kvlangKeytreeLibSig(const char *opcode) { - kvlangStrbuf_t s; - kvlangStrbufInit(&s); - kvlangStrbufPuts(&s, LIB_ROOT PATH_SEP); - kvlangStrbufPuts(&s, opcode); - kvlangStrbufPuts(&s, "/[0,0]"); - return kvlangStrbufDetach(&s); + return kvlangAstr("%s%s/[0,0]", LIB_ROOT PATH_SEP, opcode); } static char *write_err(size_t n, const char *fmt, ...) { @@ -345,25 +316,19 @@ char *kvlangKeytreeCheckWriteKey(const char *vtid, const char *key) { } size_t vr = strlen(VTHREAD_ROOT) + 1; if (strncmp(key, VTHREAD_ROOT "/", vr) == 0) { - kvlangStrbuf_t own; - kvlangStrbufInit(&own); - kvlangKeytreeVthread(vtid, &own); - if (strcmp(key, own.p) == 0) { - char *e = write_err(200, - "IsADirectoryError: write slot targets this vthread's frame root: \"%s\"; help: a frame root is a directory and writing it as a leaf destroys the call frame", - key); - kvlangStrbufFree(&own); - return e; + char own[KV_KEY_MAX]; + kvlangKeytreeVthread(vtid, own, sizeof own); + if (strcmp(key, own) == 0) { + return write_err(200, + "IsADirectoryError: write slot targets this vthread's frame root: \"%s\"; help: a frame root is a directory and writing it as a leaf destroys the call frame", + key); } - size_t ol = strlen(own.p); - if (!(strncmp(key, own.p, ol) == 0 && key[ol] == '/')) { - char *e = write_err(240, - "PermissionError: write slot is outside this vthread's subtree (vtid=%s): \"%s\"; help: the whole /vthread domain belongs to the engine, a program may only write keys under %s/", - vtid, key, own.p); - kvlangStrbufFree(&own); - return e; + size_t ol = strlen(own); + if (!(strncmp(key, own, ol) == 0 && key[ol] == '/')) { + return write_err(240, + "PermissionError: write slot is outside this vthread's subtree (vtid=%s): \"%s\"; help: the whole /vthread domain belongs to the engine, a program may only write keys under %s/", + vtid, key, own); } - kvlangStrbufFree(&own); } return NULL; } diff --git a/runtime/src/kvcpu.c b/runtime/src/kvcpu.c index 9229113e..a8cc5b0d 100644 --- a/runtime/src/kvcpu.c +++ b/runtime/src/kvcpu.c @@ -213,13 +213,11 @@ static int check_write_types(kvlangKv_t *kv, const char *vtid, const char *pc, /* 读签名行 [0,x] 槽(def langtype)的 body 为 langtype 串(malloc;无槽返 NULL)。 * dir 带尾 /;x<0 读参、x>0 写参。 */ static char *read_sig_slot(kvlangKv_t *kv, const char *dir, int x) { - kvlangStrbuf_t sk; - kvlangStrbufInit(&sk); - kvlangStrbufPrintf(&sk, "%s[0,%d]", dir, x); + char sk[KV_KEY_MAX]; + kvlangKeyFmt(sk, sizeof sk, "%s[0,%d]", dir, x); kvlangXvalue_t v; kvlangXvalueZero(&v); - kvlangKvGetOne(kv, sk.p, &v); - kvlangStrbufFree(&sk); + kvlangKvGetOne(kv, sk, &v); char *s = NULL; if (!kvlangXvalueNone(&v)) { const uint8_t *b = xh_body_of(&v); @@ -232,32 +230,42 @@ static char *read_sig_slot(kvlangKv_t *kv, const char *dir, int x) { return s; } -/* 拼读参签名(\n 连接 [0,-1..-nr] 各 def langtype 槽)。dir 带尾 /。malloc 返回。 */ -static char *join_read_sig(kvlangKv_t *kv, const char *dir, int nr) { - kvlangStrbuf_t b; - kvlangStrbufInit(&b); - for (int i = 1; i <= nr; i++) { +/* \n 连接 [0,±1..±n] 各 def langtype 槽。dir 带尾 /。malloc 返回。 */ +static char *join_sig(kvlangKv_t *kv, const char *dir, int n, bool neg) { + if (n <= 0) + return strdup(""); + char **parts = malloc(sizeof(char *) * (size_t)n); + if (!parts) + kvlangDie("out of memory joining signature"); + size_t total = 1; + for (int i = 1; i <= n; i++) { + parts[i - 1] = read_sig_slot(kv, dir, neg ? -i : i); + total += strlen(parts[i - 1] ? parts[i - 1] : "") + (i > 1 ? 1 : 0); + } + char *out = malloc(total); + if (!out) + kvlangDie("out of memory joining signature"); + size_t off = 0; + for (int i = 1; i <= n; i++) { if (i > 1) - kvlangStrbufPutc(&b, '\n'); - char *s = read_sig_slot(kv, dir, -i); - kvlangStrbufPuts(&b, s ? s : ""); - free(s); + out[off++] = '\n'; + const char *s = parts[i - 1] ? parts[i - 1] : ""; + size_t sl = strlen(s); + memcpy(out + off, s, sl); + off += sl; + free(parts[i - 1]); } - return kvlangStrbufDetach(&b); + out[off] = 0; + free(parts); + return out; +} + +static char *join_read_sig(kvlangKv_t *kv, const char *dir, int nr) { + return join_sig(kv, dir, nr, true); } -/* 拼写参签名(\n 连接 [0,1..nw] 各 def langtype 槽)。dir 带尾 /。malloc 返回。 */ static char *join_write_sig(kvlangKv_t *kv, const char *dir, int nw) { - kvlangStrbuf_t b; - kvlangStrbufInit(&b); - for (int i = 1; i <= nw; i++) { - if (i > 1) - kvlangStrbufPutc(&b, '\n'); - char *s = read_sig_slot(kv, dir, i); - kvlangStrbufPuts(&b, s ? s : ""); - free(s); - } - return kvlangStrbufDetach(&b); + return join_sig(kv, dir, nw, false); } /* 主槽计数头 [nr:u16 LE][nw:u16 LE][dynamic:u8] → nr/nw/dynamic。无定义返回 -1。 */ @@ -293,12 +301,9 @@ static char *load_def_reads(kvlangKv_t *kv, const char *key, int *out_nr, int nw; if (load_def_counts(kv, key, out_nr, &nw, out_dyn) != 0) return NULL; - kvlangStrbuf_t dir; - kvlangStrbufInit(&dir); - kvlangStrbufPrintf(&dir, "%s/", key); - char *sig = join_read_sig(kv, dir.p, *out_nr); - kvlangStrbufFree(&dir); - return sig; + char dir[KV_KEY_MAX]; + kvlangKeyFmt(dir, sizeof dir, "%s/", key); + return join_read_sig(kv, dir, *out_nr); } /* 读取 rwir 定义的写参签名:写参 langtype 逐条落在签名行 [0,i] 槽(def langtype)。 @@ -307,12 +312,9 @@ static char *load_def_writes(kvlangKv_t *kv, const char *key, int *out_nw) { int nr, dyn; if (load_def_counts(kv, key, &nr, out_nw, &dyn) != 0) return NULL; - kvlangStrbuf_t dir; - kvlangStrbufInit(&dir); - kvlangStrbufPrintf(&dir, "%s/", key); - char *sig = join_write_sig(kv, dir.p, *out_nw); - kvlangStrbufFree(&dir); - return sig; + char dir[KV_KEY_MAX]; + kvlangKeyFmt(dir, sizeof dir, "%s/", key); + return join_write_sig(kv, dir, *out_nw); } static char *frame_slot_key(const char *frame_root, const char *slot) { @@ -322,13 +324,10 @@ static char *frame_slot_key(const char *frame_root, const char *slot) { return strdup(slot); if (strncmp(slot, MEMBER_SEP, MEMBER_SEP_LEN) == 0) return NULL; - kvlangStrbuf_t b; - kvlangStrbufInit(&b); char *stk = kvlangKeytreeStack(frame_root); - kvlangStrbufPuts(&b, stk); + char *r = kvlangAstr("%s%s", stk, slot); free(stk); - kvlangStrbufPuts(&b, slot); - return kvlangStrbufDetach(&b); + return r; } /* Resolve a caller operand to its KVSpace key. */ @@ -348,16 +347,14 @@ static int handle_return(kvlangKv_t *kv, const char *vtid, const char *pc, int d = kvlangKeytreeFrameNum(fr); char *next = NULL; if (d > 1) { - kvlangStrbuf_t rk; - kvlangStrbufInit(&rk); - kvlangKeytreeFrameReturnpc(fr, &rk); + char rk[KV_KEY_MAX]; + kvlangKeytreeFrameReturnpc(fr, rk, sizeof rk); kvlangXvalue_t v; kvlangXvalueZero(&v); - kvlangKvGetOne(kv, rk.p, &v); + kvlangKvGetOne(kv, rk, &v); if (!kvlangXvalueNone(&v)) next = kvlangXvalueValueString(&v); kvlangXvalueFree(&v); - kvlangStrbufFree(&rk); if (!next || !next[0]) { char msg[512]; snprintf(msg, sizeof msg, @@ -389,14 +386,9 @@ static int add_param_binding(kvlangKvPair_t *pairs, int *np, type++; if (!type[0]) return -1; - kvlangStrbuf_t arg; - kvlangStrbufInit(&arg); - kvlangStrbufPrintf(&arg, "%s/%sarg[0,%d]", frame_root, RUNTIME_MEMBER_SEP, x); - char *arg_key = kvlangStrbufDetach(&arg); - kvlangStrbuf_t slot; - kvlangStrbufInit(&slot); - kvlangStrbufPrintf(&slot, "%s/[0,%d]", frame_root, x); - char *slot_key = kvlangStrbufDetach(&slot); + char *arg_key = kvlangAstr("%s/%sarg[0,%d]", frame_root, + RUNTIME_MEMBER_SEP, x); + char *slot_key = kvlangAstr("%s/[0,%d]", frame_root, x); kvlangXvalue_t arg_ptr, frame_ptr; kvlangXvalueNewPtr(&arg_ptr, type, value_key); kvlangXvalueNewPtr(&frame_ptr, type, arg_key); @@ -415,9 +407,8 @@ static int add_param_binding(kvlangKvPair_t *pairs, int *np, /* Create the callee frame and return its entry PC. */ static char *handle_call(kvlangKv_t *kv, const char *pc, kvlangRwirInst_t *inst) { - kvlangStrbuf_t vtid_b; - kvlangStrbufInit(&vtid_b); - const char *vtid = kvlangKeytreeVtidFromPc(pc, &vtid_b); + char vtid_b[KV_KEY_MAX]; + const char *vtid = kvlangKeytreeVtidFromPc(pc, vtid_b, sizeof vtid_b); const char *fn = inst->reads[0].name; char *pkg = strdup(""); char *name = strdup(fn); @@ -447,16 +438,13 @@ static char *handle_call(kvlangKv_t *kv, const char *pc, char *ff = kvlangKeytreeFrameRoot(pc); if (ff) { /* 函数目录在帧的 ‥lib 槽(/lib/aaa/bbb/math·double/):由此取调用者 pkg。 */ - kvlangStrbuf_t lk; - kvlangStrbufInit(&lk); char *stk = kvlangKeytreeStack(ff); - kvlangStrbufPuts(&lk, stk); + char lk[KV_KEY_MAX]; + kvlangKeyFmt(lk, sizeof lk, "%s%s", stk, SEG_LIB); free(stk); - kvlangStrbufPuts(&lk, SEG_LIB); kvlangXvalue_t lv; kvlangXvalueZero(&lv); - kvlangKvGetOne(kv, lk.p, &lv); - kvlangStrbufFree(&lk); + kvlangKvGetOne(kv, lk, &lv); char *funcdir = kvlangXvalueNone(&lv) ? NULL : kvlangXvalueValueString(&lv); kvlangXvalueFree(&lv); @@ -469,16 +457,14 @@ static char *handle_call(kvlangKv_t *kv, const char *pc, if (sep) { char *cand_pkg = strndup(rel, (size_t)(sep - rel)); char *cand = kvlangKeytreeLibFunc(cand_pkg, fn); - kvlangStrbuf_t sk; - kvlangStrbufInit(&sk); - kvlangStrbufPrintf(&sk, "%s/[0,0]", cand); + char sk[KV_KEY_MAX]; + kvlangKeyFmt(sk, sizeof sk, "%s/[0,0]", cand); kvlangXvalue_t sv; kvlangXvalueZero(&sv); - kvlangKvGetOne(kv, sk.p, &sv); + kvlangKvGetOne(kv, sk, &sv); bool ok = !kvlangXvalueNone(&sv) && kvlangXvalueKindIs(&sv, KVSPACE_KIND_RWFUNC); kvlangXvalueFree(&sv); - kvlangStrbufFree(&sk); if (ok) { free(pkg); pkg = cand_pkg; @@ -493,17 +479,14 @@ static char *handle_call(kvlangKv_t *kv, const char *pc, } } char *func_key = kvlangKeytreeLibFunc(pkg, name); - kvlangStrbuf_t func_dir; - kvlangStrbufInit(&func_dir); - kvlangStrbufPuts(&func_dir, func_key); - kvlangStrbufPutc(&func_dir, '/'); - - kvlangStrbuf_t sig_key; - kvlangStrbufInit(&sig_key); - kvlangStrbufPrintf(&sig_key, "%s[0,0]", func_dir.p); + char func_dir[KV_KEY_MAX]; + kvlangKeyFmt(func_dir, sizeof func_dir, "%s/", func_key); + + char sig_key[KV_KEY_MAX]; + kvlangKeyFmt(sig_key, sizeof sig_key, "%s[0,0]", func_dir); kvlangXvalue_t sig; kvlangXvalueZero(&sig); - kvlangKvGetOne(kv, sig_key.p, &sig); + kvlangKvGetOne(kv, sig_key, &sig); if (kvlangXvalueNone(&sig) || !kvlangXvalueKindIs(&sig, KVSPACE_KIND_RWFUNC)) { /* 按 xvalue 的 kind 精确区分缺 rwir 还是缺 rwfunc: @@ -547,7 +530,7 @@ static char *handle_call(kvlangKv_t *kv, const char *pc, kvlangKvDelTree(kv, frame_root, err, sizeof err); char *stack_fr = kvlangKeytreeStack(frame_root); if (kvlangKvMkindex(kv, stack_fr, 0, err, sizeof err) != 0 || - kvlangKvExtIndex(kv, stack_fr, func_dir.p, err, sizeof err) != 0) { + kvlangKvExtIndex(kv, stack_fr, func_dir, err, sizeof err) != 0) { kvlangVthreadSetError(kv, vtid, pc, err); free(caller_fr); free(stack_fr); @@ -556,29 +539,23 @@ static char *handle_call(kvlangKv_t *kv, const char *pc, } /* 系统变量 */ - kvlangStrbuf_t npc; - kvlangStrbufInit(&npc); - kvlangRwirNextPc(pc, &npc); - kvlangStrbuf_t retpc; - kvlangStrbufInit(&retpc); - kvlangKeytreeFrameReturnpc(frame_root, &retpc); - kvlangStrbuf_t callpc; - kvlangStrbufInit(&callpc); - kvlangKeytreeFrameCallpc(frame_root, &callpc); + char npc[KV_KEY_MAX], retpc[KV_KEY_MAX], callpc[KV_KEY_MAX]; + if (kvlangRwirNextPcBuf(pc, npc, sizeof npc) == 0) + kvlangDie("next pc exceeds %zu bytes", sizeof npc); + kvlangKeytreeFrameReturnpc(frame_root, retpc, sizeof retpc); + kvlangKeytreeFrameCallpc(frame_root, callpc, sizeof callpc); char *ep = kvlangKeytreeEntryPc(frame_root); - kvlangStrbuf_t seglib; - kvlangStrbufInit(&seglib); - kvlangStrbufPuts(&seglib, stack_fr); - kvlangStrbufPuts(&seglib, SEG_LIB); + char seglib[KV_KEY_MAX]; + kvlangKeyFmt(seglib, sizeof seglib, "%s%s", stack_fr, SEG_LIB); kvlangXvalue_t v_npc, v_ep, v_fn; kvlangXvalueZero(&v_npc); kvlangXvalueZero(&v_ep); kvlangXvalueZero(&v_fn); - kvlangXvalueNewCharUtf8(&v_npc, npc.p); + kvlangXvalueNewCharUtf8(&v_npc, npc); kvlangXvalueNewCharUtf8(&v_ep, ep); kvlangXvalueNewCharUtf8(&v_fn, func_key); kvlangKvPair_t sys[3] = { - {retpc.p, v_npc}, {callpc.p, v_ep}, {seglib.p, v_fn}}; + {retpc, v_npc}, {callpc, v_ep}, {seglib, v_fn}}; int sys_rc = kvlangXvalueNone(&v_npc) || kvlangXvalueNone(&v_ep) || kvlangXvalueNone(&v_fn) ? -1 : kvlangKvSet(kv, sys, 3, err, sizeof err); @@ -608,10 +585,7 @@ static char *handle_call(kvlangKv_t *kv, const char *pc, bool literal = concrete || is_literal(arg->name); char *rk = literal ? NULL : resolve_read_path(kv, caller_fr, arg->name); if (literal) { - kvlangStrbuf_t lit_path; - kvlangStrbufInit(&lit_path); - kvlangStrbufPrintf(&lit_path, "%s/._lit%d", frame_root, i); - rk = kvlangStrbufDetach(&lit_path); + rk = kvlangAstr("%s/._lit%d", frame_root, i); if (concrete) { if (np >= MAX_BIND_PAIRS) { free(rk); @@ -662,13 +636,6 @@ static char *handle_call(kvlangKv_t *kv, const char *pc, free(caller_fr); free(stack_fr); - kvlangStrbufFree(&npc); - kvlangStrbufFree(&retpc); - kvlangStrbufFree(&callpc); - kvlangStrbufFree(&seglib); - kvlangStrbufFree(&func_dir); - kvlangStrbufFree(&sig_key); - kvlangStrbufFree(&vtid_b); kvlangXvalueFree(&sig); free(func_key); free(pkg); @@ -680,16 +647,9 @@ static char *handle_call(kvlangKv_t *kv, const char *pc, kvlangKvDelTree(kv, frame_root, err, sizeof err); free(caller_fr); free(stack_fr); - kvlangStrbufFree(&npc); - kvlangStrbufFree(&retpc); - kvlangStrbufFree(&callpc); - kvlangStrbufFree(&seglib); free(ep); free(frame_root); fail: - kvlangStrbufFree(&func_dir); - kvlangStrbufFree(&sig_key); - kvlangStrbufFree(&vtid_b); kvlangXvalueFree(&sig); free(func_key); free(pkg); @@ -700,13 +660,11 @@ static char *handle_call(kvlangKv_t *kv, const char *pc, /* Read the declared target type; the argument value may be None. */ static void param_decl_type(kvlangKv_t *kv, const char *func_key, int x, char *lt, size_t cap) { - kvlangStrbuf_t pk; - kvlangStrbufInit(&pk); - kvlangStrbufPrintf(&pk, "%s.[0,%d]", func_key, x); + char pk[KV_KEY_MAX]; + kvlangKeyFmt(pk, sizeof pk, "%s.[0,%d]", func_key, x); kvlangXvalue_t dv; kvlangXvalueZero(&dv); - kvlangKvGetOne(kv, pk.p, &dv); - kvlangStrbufFree(&pk); + kvlangKvGetOne(kv, pk, &dv); if (!kvlangXvalueNone(&dv)) { const uint8_t *ab = xh_body_of(&dv); int32_t al = xh_content_len_of(&dv); @@ -834,17 +792,15 @@ int handoff_external_rwir(kvlangKv_t *kv, const char *vtid, const char *pc, * 第一个 rwir 的 vids 下,Set 经路径穿透落到同一 strkeymap)。外部执行器认领并驱动该 vthread, * 完成后删除该条目。本端 watch 同一 key 直至变 None(== 认领方已完成),单键交接、无 id。 */ char *base = kvlangKeytreeRwir(inst->opcode); - kvlangStrbuf_t vids; - kvlangStrbufInit(&vids); - kvlangStrbufPrintf(&vids, "%s/vids/%s", base, vtid); + char vids[KV_KEY_MAX]; + kvlangKeyFmt(vids, sizeof vids, "%s/vids/%s", base, vtid); kvlangXvalue_t pv; kvlangXvalueNewCharUtf8(&pv, pc); - kvlangKvPair_t p = {vids.p, pv}; + kvlangKvPair_t p = {vids, pv}; char err[256]; int set_rc = kvlangKvSet(kv, &p, 1, err, sizeof err); kvlangXvalueFree(&pv); if (set_rc != 0) { - kvlangStrbufFree(&vids); free(base); return -1; } @@ -853,9 +809,8 @@ int handoff_external_rwir(kvlangKv_t *kv, const char *vtid, const char *pc, kvlangXvalueZero(&none); /* 目标 None:等条目被删除 */ kvlangXvalue_t got; kvlangXvalueZero(&got); - int rc = kvlangKvWatch(kv, vids.p, &none, 30000000000ULL, &got); + int rc = kvlangKvWatch(kv, vids, &none, 30000000000ULL, &got); kvlangXvalueFree(&got); - kvlangStrbufFree(&vids); free(base); if (rc != 0) { char msg[256]; @@ -880,17 +835,14 @@ char *kvlangKvcpuBootstrap(kvlangKv_t *kv, const char *vtid, name = strdup(dot + MEMBER_SEP_LEN); } char *func_key = kvlangKeytreeLibFunc(pkg, name); - kvlangStrbuf_t func_dir; - kvlangStrbufInit(&func_dir); - kvlangStrbufPuts(&func_dir, func_key); - kvlangStrbufPutc(&func_dir, '/'); - - kvlangStrbuf_t sig_key; - kvlangStrbufInit(&sig_key); - kvlangStrbufPrintf(&sig_key, "%s[0,0]", func_dir.p); + char func_dir[KV_KEY_MAX]; + kvlangKeyFmt(func_dir, sizeof func_dir, "%s/", func_key); + + char sig_key[KV_KEY_MAX]; + kvlangKeyFmt(sig_key, sizeof sig_key, "%s[0,0]", func_dir); kvlangXvalue_t sig; kvlangXvalueZero(&sig); - kvlangKvGetOne(kv, sig_key.p, &sig); + kvlangKvGetOne(kv, sig_key, &sig); if (kvlangXvalueNone(&sig) || !kvlangXvalueKindIs(&sig, KVSPACE_KIND_RWFUNC)) { char msg[256]; @@ -898,8 +850,6 @@ char *kvlangKvcpuBootstrap(kvlangKv_t *kv, const char *vtid, funcname); kvlangVthreadSetError(kv, vtid, "", msg); kvlangXvalueFree(&sig); - kvlangStrbufFree(&sig_key); - kvlangStrbufFree(&func_dir); free(func_key); free(pkg); free(name); @@ -912,11 +862,9 @@ char *kvlangKvcpuBootstrap(kvlangKv_t *kv, const char *vtid, char *stack_fr = kvlangKeytreeStack(frame_root); char err[256]; if (kvlangKvMkindex(kv, stack_fr, 0, err, sizeof err) != 0 || - kvlangKvExtIndex(kv, stack_fr, func_dir.p, err, sizeof err) != 0) { + kvlangKvExtIndex(kv, stack_fr, func_dir, err, sizeof err) != 0) { kvlangVthreadSetError(kv, vtid, "", err); kvlangXvalueFree(&sig); - kvlangStrbufFree(&sig_key); - kvlangStrbufFree(&func_dir); free(stack_fr); free(frame_root); free(func_key); @@ -926,19 +874,15 @@ char *kvlangKvcpuBootstrap(kvlangKv_t *kv, const char *vtid, } char *ep = kvlangKeytreeEntryPc(frame_root); - kvlangStrbuf_t callpc; - kvlangStrbufInit(&callpc); - kvlangKeytreeFrameCallpc(frame_root, &callpc); - kvlangStrbuf_t seglib; - kvlangStrbufInit(&seglib); - kvlangStrbufPuts(&seglib, stack_fr); - kvlangStrbufPuts(&seglib, SEG_LIB); + char callpc[KV_KEY_MAX], seglib[KV_KEY_MAX]; + kvlangKeytreeFrameCallpc(frame_root, callpc, sizeof callpc); + kvlangKeyFmt(seglib, sizeof seglib, "%s%s", stack_fr, SEG_LIB); kvlangXvalue_t v_ep, v_fn; kvlangXvalueZero(&v_ep); kvlangXvalueZero(&v_fn); kvlangXvalueNewCharUtf8(&v_ep, ep); kvlangXvalueNewCharUtf8(&v_fn, func_key); - kvlangKvPair_t sys[2] = {{callpc.p, v_ep}, {seglib.p, v_fn}}; + kvlangKvPair_t sys[2] = {{callpc, v_ep}, {seglib, v_fn}}; int sys_rc = kvlangXvalueNone(&v_ep) || kvlangXvalueNone(&v_fn) ? -1 : kvlangKvSet(kv, sys, 2, err, sizeof err); if (sys_rc != 0) @@ -955,10 +899,7 @@ char *kvlangKvcpuBootstrap(kvlangKv_t *kv, const char *vtid, kvlangKvPair_t pairs[MAX_BIND_PAIRS]; int np = 0; for (int i = 0; i < nr && i < nargs; i++) { - kvlangStrbuf_t literal; - kvlangStrbufInit(&literal); - kvlangStrbufPrintf(&literal, "%s/._arglit%d", frame_root, i); - char *value_key = kvlangStrbufDetach(&literal); + char *value_key = kvlangAstr("%s/._arglit%d", frame_root, i); kvlangXvalue_t av; kvlangXvalueZero(&av); kvlangBuiltinResolveReadValue(kv, "", args[i], NULL, &av); @@ -991,10 +932,6 @@ char *kvlangKvcpuBootstrap(kvlangKv_t *kv, const char *vtid, } kvlangXvalueFree(&sig); - kvlangStrbufFree(&sig_key); - kvlangStrbufFree(&func_dir); - kvlangStrbufFree(&callpc); - kvlangStrbufFree(&seglib); free(stack_fr); free(frame_root); free(func_key); @@ -1189,22 +1126,17 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode, char **out_pc) { if (out_pc) *out_pc = NULL; - kvlangStrbuf_t vtid_b; - kvlangStrbufInit(&vtid_b); - const char *vtid = kvlangKeytreeVtidFromPc(pc, &vtid_b); + char vtid_b[KV_KEY_MAX]; + const char *vtid = kvlangKeytreeVtidFromPc(pc, vtid_b, sizeof vtid_b); if (vtid[0] == 0) { - kvlangStrbufFree(&vtid_b); return -1; } /* 每步复用的缓冲:pc/status 键与值、帧根、link base 全部跨步保留,免每步 malloc/free。 */ - kvlangStrbuf_t pc_key, st_key, cur_b, status_b; - kvlangStrbufInit(&pc_key); - kvlangStrbufInit(&st_key); - kvlangStrbufInit(&cur_b); - kvlangStrbufInit(&status_b); - kvlangKeytreeVthreadPc(vtid, &pc_key); - kvlangKeytreeVthreadStatus(vtid, &st_key); + char pc_key[KV_KEY_MAX], st_key[KV_KEY_MAX]; + char cur_b[KV_KEY_MAX], status_b[KV_KEY_MAX]; + kvlangKeytreeVthreadPc(vtid, pc_key, sizeof pc_key); + kvlangKeytreeVthreadStatus(vtid, st_key, sizeof st_key); char fr_stk[512]; char lb_stk[512]; char *cur_frame = NULL; /* fr_stk,或超长帧根的 malloc 回退 */ @@ -1215,15 +1147,16 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode, for (;;) { /* Release borrowed values from the previous instruction. */ kvlangKvReadReset(kv); - if (!kvlangVthreadMemberGetBuf(kv, pc_key.p, &cur_b) || !cur_b.p[0]) { + if (!kvlangVthreadMemberGetBuf(kv, pc_key, cur_b, sizeof cur_b) || + !cur_b[0]) { rc = -1; break; } - const char *cur = cur_b.p; + const char *cur = cur_b; /* Observe external status changes on every step. */ - if (!kvlangVthreadMemberGetBuf(kv, st_key.p, &status_b)) + if (!kvlangVthreadMemberGetBuf(kv, st_key, status_b, sizeof status_b)) break; - const char *status = status_b.p; + const char *status = status_b; if (strcmp(status, "init") != 0 && strcmp(status, "running") != 0 && strcmp(status, "wait") != 0) { break; @@ -1329,7 +1262,6 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode, free(yield); rwir_inst_release(&tmp, from_cache); rwir_cache_free(&cache); - kvlangStrbufFree(&vtid_b); return 1; } } else if (kvlangDispatchIsDelegatedOp(kv, inst->opcode)) { @@ -1359,7 +1291,6 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode, *out_pc = strdup(cur); rwir_inst_release(&tmp, from_cache); rwir_cache_free(&cache); - kvlangStrbufFree(&vtid_b); return 1; } if (exec_err == 0) @@ -1404,11 +1335,6 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode, if (cur_frame != fr_stk) free(cur_frame); rwir_cache_free(&cache); - kvlangStrbufFree(&pc_key); - kvlangStrbufFree(&st_key); - kvlangStrbufFree(&cur_b); - kvlangStrbufFree(&status_b); - kvlangStrbufFree(&vtid_b); return rc; } diff --git a/runtime/src/myrwircaps.c b/runtime/src/myrwircaps.c index 18791d16..bcd6d584 100644 --- a/runtime/src/myrwircaps.c +++ b/runtime/src/myrwircaps.c @@ -24,26 +24,22 @@ static int register_vids(kvlangKv_t *k, const char *opcode) { return rc; } char *base = kvlangKeytreeRwir(opcode); - kvlangStrbuf_t tk; - kvlangStrbufInit(&tk); - kvlangStrbufPuts(&tk, base); - kvlangStrbufPuts(&tk, "/vids"); + char tk[KV_KEY_MAX]; + kvlangKeyFmt(tk, sizeof tk, "%s/vids", base); kvlangXvalue_t cur; kvlangXvalueZero(&cur); - bool exists = - (kvlangKvGetOne(k, tk.p, &cur) == 0 && !kvlangXvalueNone(&cur)); + bool exists = (kvlangKvGetOne(k, tk, &cur) == 0 && !kvlangXvalueNone(&cur)); kvlangXvalueFree(&cur); int rc = 0; if (!exists) { kvlangXvalue_t v; kvlangXvalueZero(&v); kvlangXvalueNewPtr(&v, queue_type, queue); - kvlangKvPair_t p = {tk.p, v}; + kvlangKvPair_t p = {tk, v}; char err[256]; rc = kvlangKvSet(k, &p, 1, err, sizeof err); kvlangXvalueFree(&v); } - kvlangStrbufFree(&tk); free(base); return rc; } @@ -51,18 +47,16 @@ static int register_vids(kvlangKv_t *k, const char *opcode) { /* 写 [0,x] 签名行槽 = def langtype(body 为该参数 langtype 串)。 */ static void write_sig_slot(kvlangKv_t *k, const char *base, int x, const char *lt, size_t lt_len) { - kvlangStrbuf_t sk; - kvlangStrbufInit(&sk); - kvlangStrbufPrintf(&sk, "%s/[0,%d]", base, x); + char sk[KV_KEY_MAX]; + kvlangKeyFmt(sk, sizeof sk, "%s/[0,%d]", base, x); char *clean = strndup(lt, lt_len); kvlangXvalue_t sv; kvlangXvalueNewDefLangtype(&sv, clean); free(clean); - kvlangKvPair_t sp = {sk.p, sv}; + kvlangKvPair_t sp = {sk, sv}; char err[256]; kvlangKvSet(k, &sp, 1, err, sizeof err); kvlangXvalueFree(&sv); - kvlangStrbufFree(&sk); } /* 注册一条 rwir:/lib/ 路由头(仅计数头)+ 各参数落 [0,x] 签名行槽(def langtype)。 diff --git a/runtime/src/runtime.c b/runtime/src/runtime.c index 5ebf5c84..257655c2 100644 --- a/runtime/src/runtime.c +++ b/runtime/src/runtime.c @@ -35,15 +35,13 @@ int kvlangRuntimeExecutePc(kvlangRuntime_t *rt, const char *pc) { void *kvlangRuntimeKvspaceHandle(kvlangRuntime_t *rt) { return rt->kv->h; } static char *read_vthread_pc(kvlangKv_t *kv, const char *vid) { - kvlangStrbuf_t key; - kvlangStrbufInit(&key); - kvlangKeytreeVthreadPc(vid, &key); + char key[KV_KEY_MAX]; + kvlangKeytreeVthreadPc(vid, key, sizeof key); kvlangXvalue_t v; kvlangXvalueZero(&v); - kvlangKvGetOne(kv, key.p, &v); + kvlangKvGetOne(kv, key, &v); char *pc = kvlangXvalueNone(&v) ? strdup("") : kvlangXvalueValueString(&v); kvlangXvalueFree(&v); - kvlangStrbufFree(&key); return pc; } @@ -56,12 +54,10 @@ int kvlangRuntimeExecuteVthread(kvlangRuntime_t *rt, const char *vid, } static char *alloc_vtid(kvlangKv_t *kv) { - kvlangStrbuf_t seq; - kvlangStrbufInit(&seq); - kvlangStrbufPuts(&seq, VTHREAD_ROOT "/" RUNTIME_MEMBER_SEP "seq"); + static const char seq[] = VTHREAD_ROOT "/" RUNTIME_MEMBER_SEP "seq"; kvlangXvalue_t v; kvlangXvalueZero(&v); - kvlangKvGetOne(kv, seq.p, &v); + kvlangKvGetOne(kv, seq, &v); char *s = kvlangXvalueNone(&v) ? strdup("") : kvlangXvalueValueString(&v); kvlangXvalueFree(&v); int64_t n = atoll(s) + 1; @@ -70,12 +66,11 @@ static char *alloc_vtid(kvlangKv_t *kv) { snprintf(buf, sizeof buf, "%lld", (long long)n); kvlangXvalue_t nv; kvlangXvalueNewCharUtf8(&nv, buf); - kvlangKvPair_t p = {seq.p, nv}; + kvlangKvPair_t p = {seq, nv}; char err[256]; int rc = kvlangXvalueNone(&nv) ? -1 : kvlangKvSet(kv, &p, 1, err, sizeof err); kvlangXvalueFree(&nv); - kvlangStrbufFree(&seq); return rc == 0 ? strdup(buf) : NULL; } @@ -87,28 +82,24 @@ char *kvlangVthreadSpawn(kvlangKv_t *kv, const char *funcname, char *vtid = alloc_vtid(kv); if (!vtid) return NULL; - kvlangStrbuf_t vtroot; - kvlangStrbufInit(&vtroot); - kvlangKeytreeVthread(vtid, &vtroot); - char *stack_vt = kvlangKeytreeStack(vtroot.p); + char vtroot[KV_KEY_MAX]; + kvlangKeytreeVthread(vtid, vtroot, sizeof vtroot); + char *stack_vt = kvlangKeytreeStack(vtroot); char e[256]; if (kvlangKvMkindex(kv, stack_vt, 0, e, sizeof e) != 0) { free(stack_vt); free(vtid); - kvlangStrbufFree(&vtroot); return NULL; } char *first_pc = kvlangKvcpuBootstrap(kv, vtid, funcname, args, nargs); if (!first_pc) { free(stack_vt); free(vtid); - kvlangStrbufFree(&vtroot); return NULL; } int persisted = kvlangVthreadSet(kv, vtid, first_pc, "init"); free(first_pc); free(stack_vt); - kvlangStrbufFree(&vtroot); if (persisted != 0) { free(vtid); return NULL; @@ -136,29 +127,25 @@ int kvlangRuntimeRunVid(kvlangKv_t *kv, const char *vid, char **ret, char *err, free(pc); /* 读终态 */ - kvlangStrbuf_t st; - kvlangStrbufInit(&st); - kvlangKeytreeVthreadStatus(vid, &st); + char st[KV_KEY_MAX]; + kvlangKeytreeVthreadStatus(vid, st, sizeof st); kvlangXvalue_t sv; kvlangXvalueZero(&sv); - kvlangKvGetOne(kv, st.p, &sv); + kvlangKvGetOne(kv, st, &sv); char *status = kvlangXvalueNone(&sv) ? strdup("") : kvlangXvalueValueString(&sv); kvlangXvalueFree(&sv); - kvlangStrbufFree(&st); if (ret) { if (strcmp(status, "error") == 0) { - kvlangStrbuf_t mk; - kvlangStrbufInit(&mk); - kvlangKeytreeVthreadStatusMsg(vid, "error", &mk); + char mk[KV_KEY_MAX]; + kvlangKeytreeVthreadStatusMsg(vid, "error", mk, sizeof mk); kvlangXvalue_t mv; kvlangXvalueZero(&mv); - kvlangKvGetOne(kv, mk.p, &mv); + kvlangKvGetOne(kv, mk, &mv); char *msg = kvlangXvalueNone(&mv) ? strdup("error") : kvlangXvalueValueString(&mv); kvlangXvalueFree(&mv); - kvlangStrbufFree(&mk); if (err && err_cap) snprintf(err, err_cap, "%s", msg); *ret = strdup("error"); diff --git a/runtime/src/runtime_internal.h b/runtime/src/runtime_internal.h index 3fcd838d..384ca5d0 100644 --- a/runtime/src/runtime_internal.h +++ b/runtime/src/runtime_internal.h @@ -119,29 +119,18 @@ typedef struct { void *h; } kvlangKv_t; -/* growable string buffer */ -typedef struct { - char *p; - size_t len, cap; -} kvlangStrbuf_t; - -static inline void kvlangStrbufInit(kvlangStrbuf_t *b) { - b->p = NULL; - b->len = 0; - b->cap = 0; -} -void kvlangStrbufPutc(kvlangStrbuf_t *b, char c); -void kvlangStrbufPutn(kvlangStrbuf_t *b, const char *s, size_t n); -static inline void kvlangStrbufPuts(kvlangStrbuf_t *b, const char *s) { - kvlangStrbufPutn(b, s, strlen(s)); -} -void kvlangStrbufPrintf(kvlangStrbuf_t *b, const char *fmt, ...); -char *kvlangStrbufDetach(kvlangStrbuf_t *b); /* malloc,调用方 free */ -static inline void kvlangStrbufFree(kvlangStrbuf_t *b) { - free(b->p); - b->p = NULL; - b->len = b->cap = 0; -} +/* ── 字符串工具 ────────────────────────────────────────────────────── + * 只有一次性操作:有界栈格式化 / 堆分配拷贝。没有可增长缓冲、没有复用语义。 */ + +#define KV_KEY_MAX 1024 /* kvspace 写键上限:key_len < 1024 */ + +void kvlangDie(const char *fmt, ...) __attribute__((noreturn, format(printf, 1, 2))); +/* 有界写入调用方缓冲;超长或格式化错误直接 abort,绝不截断。 */ +size_t kvlangKeyFmt(char *buf, size_t cap, const char *fmt, ...) + __attribute__((format(printf, 3, 4))); +/* 一次性堆字符串(调用方 free);OOM abort。 */ +char *kvlangAstr(const char *fmt, ...) __attribute__((format(printf, 1, 2))); +char *kvlangAstrN(const char *s, size_t n); /* ── xvalue head 零解码访问 ────────────────────────────────────────── * wire: [pow:u8][flags:u8][a:u64le][b:u64le][langtype][padding][body] @@ -442,14 +431,8 @@ int kvlangKvWatch(kvlangKv_t *k, const char *key, const kvlangXvalue_t *target, #define LIB_ROOT "/lib" #define VTHREAD_ROOT "/vthread" -static inline void kvlangStrbufClear(kvlangStrbuf_t *b) { - b->len = 0; - if (b->p) - b->p[0] = 0; -} - -const char *kvlangKeytreeVtidFromPc(const char *pc, - kvlangStrbuf_t *out); /* "" 无效 */ +const char *kvlangKeytreeVtidFromPc(const char *pc, char *out, + size_t cap); /* "" 无效 */ char *kvlangKeytreeStack(const char *root); /* malloc */ size_t kvlangKeytreeStackBuf(const char *root, char *buf, size_t cap); /* 栈缓冲,返长度 */ char *kvlangKeytreeFrameRoot(const char *pc); /* malloc,无效 NULL */ @@ -475,17 +458,17 @@ char *kvlangKeytreeSysRwirBackendCategoryRoot(const char *name); char *kvlangKeytreeSysTask(const char *task_id, const char *field); char *kvlangKeytreeDoneRwir(const char *task_id); char *kvlangKeytreeLibSig(const char *opcode); -void kvlangKeytreeVthread(const char *vtid, kvlangStrbuf_t *out); +void kvlangKeytreeVthread(const char *vtid, char *out, size_t cap); void kvlangKeytreeVthreadSlot(const char *vtid, const char *frame, int i, int j, - kvlangStrbuf_t *out); -void kvlangKeytreeVthreadPc(const char *vtid, kvlangStrbuf_t *out); -void kvlangKeytreeVthreadStatus(const char *vtid, kvlangStrbuf_t *out); + char *out, size_t cap); +void kvlangKeytreeVthreadPc(const char *vtid, char *out, size_t cap); +void kvlangKeytreeVthreadStatus(const char *vtid, char *out, size_t cap); void kvlangKeytreeVthreadStatusMsg(const char *vtid, const char *status, - kvlangStrbuf_t *out); -void kvlangKeytreeVthreadDebugger(const char *vtid, kvlangStrbuf_t *out); -void kvlangKeytreeFrameCallpc(const char *root, kvlangStrbuf_t *out); -void kvlangKeytreeFrameReturnpc(const char *root, kvlangStrbuf_t *out); -void kvlangKeytreeFrameRo(const char *root, kvlangStrbuf_t *out); + char *out, size_t cap); +void kvlangKeytreeVthreadDebugger(const char *vtid, char *out, size_t cap); +void kvlangKeytreeFrameCallpc(const char *root, char *out, size_t cap); +void kvlangKeytreeFrameReturnpc(const char *root, char *out, size_t cap); +void kvlangKeytreeFrameRo(const char *root, char *out, size_t cap); bool kvlangKeytreeIsEntryPc(const char *pc); /* ── rwir ──────────────────────────────────────────────────────────── */ @@ -529,7 +512,6 @@ typedef struct { int nw; } kvlangRwirInst_t; -int kvlangRwirNextPc(const char *pc, kvlangStrbuf_t *out); size_t kvlangRwirNextPcBuf(const char *pc, char *buf, size_t cap); /* 栈缓冲,返长度 */ int kvlangRwirExtractAddr0(const char *coord); int kvlangRwirDecode(kvlangKv_t *kv, const char *link_base, const char *pc, @@ -549,9 +531,9 @@ void kvlangVthreadGet(kvlangKv_t *kv, const char *vtid, char **pc, char **status); void kvlangVthreadPcGet(kvlangKv_t *kv, const char *vtid, char **pc); void kvlangVthreadStatusGet(kvlangKv_t *kv, const char *vtid, char **status); -/* 复用调用方 strbuf 读成员值;false = 键缺失 / None。 */ -bool kvlangVthreadMemberGetBuf(kvlangKv_t *kv, const char *key, - kvlangStrbuf_t *out); +/* 读成员值到调用方缓冲;false = 键缺失 / None,超长直接 abort。 */ +bool kvlangVthreadMemberGetBuf(kvlangKv_t *kv, const char *key, char *out, + size_t cap); int kvlangVthreadSet(kvlangKv_t *kv, const char *vtid, const char *pc, const char *status); int kvlangVthreadSetDone(kvlangKv_t *kv, const char *vtid, const char *ret); diff --git a/runtime/src/rwir_array.c b/runtime/src/rwir_array.c index e09efa5d..ae97056d 100644 --- a/runtime/src/rwir_array.c +++ b/runtime/src/rwir_array.c @@ -21,18 +21,14 @@ static void pack_typed_array(const char *kind, const kvlangXvalue_t *elems, } static int separated_len(kvlangKv_t *kv, const char *base) { + char key[KV_KEY_MAX]; for (int i = 0;; i++) { - kvlangStrbuf_t k; - kvlangStrbufInit(&k); - kvlangStrbufPuts(&k, base); - kvlangStrbufPuts(&k, MEMBER_SEP); - kvlangStrbufPrintf(&k, "[%d]", i); + kvlangKeyFmt(key, sizeof key, "%s%s[%d]", base, MEMBER_SEP, i); kvlangXvalue_t v; kvlangXvalueZero(&v); - kvlangKvGetOne(kv, k.p, &v); + kvlangKvGetOne(kv, key, &v); bool none = kvlangXvalueNone(&v); kvlangXvalueFree(&v); - kvlangStrbufFree(&k); if (none) return i; } @@ -72,13 +68,10 @@ static int clear_members(kvlangFrame_t *f, const char *base) { int rc = 0; for (int i = 0; i < count; i++) { if (rc == 0) { - kvlangStrbuf_t key; - kvlangStrbufInit(&key); - kvlangStrbufPuts(&key, prefix); - kvlangStrbufPuts(&key, names[i]); - if (kvlangKvDelTree(f->kv, key.p, err, sizeof err) != 0) + char key[KV_KEY_MAX]; + kvlangKeyFmt(key, sizeof key, "%s%s", prefix, names[i]); + if (kvlangKvDelTree(f->kv, key, err, sizeof err) != 0) rc = kvlangBuiltinSetErr(f, "%s", err); - kvlangStrbufFree(&key); } free(names[i]); } @@ -90,18 +83,24 @@ static int clear_members(kvlangFrame_t *f, const char *base) { /* 坐标段 key:base·[s0,s1,...]。1 维即 base·[s0]。 */ char *kvlangBuiltinScatterKey(const char *base, const int64_t *coords, int ncoord) { - kvlangStrbuf_t b; - kvlangStrbufInit(&b); - kvlangStrbufPuts(&b, base); - kvlangStrbufPuts(&b, MEMBER_SEP); - kvlangStrbufPutc(&b, '['); + char buf[KV_KEY_MAX]; + size_t cap = sizeof buf; + int n = snprintf(buf, cap, "%s%s[", base, MEMBER_SEP); + if (n < 0 || (size_t)n >= cap) + kvlangDie("scatter key exceeds %zu bytes", cap); + size_t off = (size_t)n; for (int i = 0; i < ncoord; i++) { - if (i) - kvlangStrbufPutc(&b, ','); - kvlangStrbufPrintf(&b, "%lld", (long long)coords[i]); + n = snprintf(buf + off, cap - off, "%s%lld", i ? "," : "", + (long long)coords[i]); + if (n < 0 || (size_t)n >= cap - off) + kvlangDie("scatter key exceeds %zu bytes", cap); + off += (size_t)n; } - kvlangStrbufPutc(&b, ']'); - return kvlangStrbufDetach(&b); + if (off + 2 > cap) + kvlangDie("scatter key exceeds %zu bytes", cap); + buf[off++] = ']'; + buf[off] = 0; + return kvlangAstrN(buf, off); } static int ensure_scattered(kvlangFrame_t *f, const char *base, const char *fallback_kind) { diff --git a/runtime/src/rwir_decode.c b/runtime/src/rwir_decode.c index 1cc3dcac..daec74f8 100644 --- a/runtime/src/rwir_decode.c +++ b/runtime/src/rwir_decode.c @@ -9,18 +9,8 @@ int kvlangRwirExtractAddr0(const char *coord) { return end == p ? 0 : (int)n; } -int kvlangRwirNextPc(const char *pc, kvlangStrbuf_t *out) { - kvlangStrbufClear(out); - const char *slash = strrchr(pc, '/'); - size_t plen = slash ? (size_t)(slash - pc) + 1 : 0; - int num = kvlangRwirExtractAddr0(slash ? slash + 1 : pc); - kvlangStrbufPutn(out, pc, plen); - kvlangStrbufPrintf(out, "[%d,0]", num + 1); - return 0; -} - -/* 免分配版:把 pc 末段 [n,0] 换成 [n+1,0] 写入 buf,返回长度;cap 不足返回 0。 - * 供每指令的 PC 推进热路径复用调用方缓冲,免 strbuf 的 realloc + Printf。 */ +/* 把 pc 末段 [n,0] 换成 [n+1,0] 写入 buf,返回长度;cap 不足返回 0。 + * 供每指令的 PC 推进热路径复用调用方缓冲。 */ size_t kvlangRwirNextPcBuf(const char *pc, char *buf, size_t cap) { const char *slash = strrchr(pc, '/'); size_t plen = slash ? (size_t)(slash - pc) + 1 : 0; @@ -106,11 +96,8 @@ static int materialize_operand(kvlangKv_t *kv, const char *link_base, } } } else { - kvlangStrbuf_t literal; - kvlangStrbufInit(&literal); - kvlangStrbufPrintf(&literal, "%s%soperand%s", link_base, - RUNTIME_MEMBER_SEP, slot); - target = kvlangStrbufDetach(&literal); + target = kvlangAstr("%s%soperand%s", link_base, RUNTIME_MEMBER_SEP, + slot); kvlangKvPair_t pair = {target, *v}; if (kvlangKvSet(kv, &pair, 1, err, err_cap) != 0) { free(target); diff --git a/runtime/src/rwir_func.c b/runtime/src/rwir_func.c index 2c303a58..30b54a9e 100644 --- a/runtime/src/rwir_func.c +++ b/runtime/src/rwir_func.c @@ -88,20 +88,14 @@ char *kvlangBuiltinResolveWriteSlot(kvlangKv_t *kv, const char *frame_root, cons free(stk); return target; } - /* 存 stk+name 到栈缓冲后 strdup(返回值须自持);过长才回落 strbuf。 */ + /* stk+name 精确分配(返回值须自持)。 */ size_t sl = strlen(stk), nl = strlen(name); - char outbuf[640]; - char *r; - if (sl + nl + 1 <= sizeof outbuf) { - memcpy(outbuf, stk, sl); - memcpy(outbuf + sl, name, nl); - outbuf[sl + nl] = 0; - r = strdup(outbuf); - } else { - kvlangStrbuf_t o; kvlangStrbufInit(&o); - kvlangStrbufPuts(&o, stk); kvlangStrbufPuts(&o, name); - r = kvlangStrbufDetach(&o); - } + char *r = malloc(sl + nl + 1); + if (!r) + kvlangDie("out of memory building slot key"); + memcpy(r, stk, sl); + memcpy(r + sl, name, nl); + r[sl + nl] = 0; if (stk != stkbuf) free(stk); return r; @@ -151,16 +145,35 @@ void kvlangDisplay(const kvlangXvalue_t *v, char **out); static void format_array(const kvlangXvalue_t *v, char **out) { int n = kvlangXvalueArrayLen(v); - kvlangStrbuf_t b; kvlangStrbufInit(&b); - kvlangStrbufPutc(&b, '['); + char **parts = malloc(sizeof(char *) * (size_t)(n > 0 ? n : 1)); + if (!parts) + kvlangDie("out of memory formatting array"); + size_t total = 2; /* "[" + "]" */ for (int i = 0; i < n; i++) { - if (i) kvlangStrbufPuts(&b, ", "); kvlangXvalue_t e; kvlangBuiltinXvalueAt(v, i, &e); - char *s; kvlangDisplay(&e, &s); - kvlangStrbufPuts(&b, s); free(s); kvlangXvalueFree(&e); + kvlangDisplay(&e, &parts[i]); + kvlangXvalueFree(&e); + total += strlen(parts[i]) + (i ? 2 : 0); + } + char *s = malloc(total + 1); + if (!s) + kvlangDie("out of memory formatting array"); + size_t off = 0; + s[off++] = '['; + for (int i = 0; i < n; i++) { + if (i) { + s[off++] = ','; + s[off++] = ' '; + } + size_t sl = strlen(parts[i]); + memcpy(s + off, parts[i], sl); + off += sl; + free(parts[i]); } - kvlangStrbufPutc(&b, ']'); - *out = kvlangStrbufDetach(&b); + s[off++] = ']'; + s[off] = 0; + free(parts); + *out = s; } void kvlangDisplay(const kvlangXvalue_t *v, char **out) { @@ -188,15 +201,10 @@ int kvlangBuiltinReadInputs(kvlangFrame_t *f, kvlangXvalue_t *out, int cap) { void kvlangBuiltinFreeInputs(kvlangXvalue_t *in, int n) { for (int i = 0; i < n; i++) kvlangXvalueFree(&in[i]); } void kvlangBuiltinNextPc(kvlangFrame_t *f) { - char buf[512]; - if (kvlangRwirNextPcBuf(f->pc, buf, sizeof buf)) { - kvlangVthreadAdvance(f, buf, "running"); - return; - } - kvlangStrbuf_t npc; kvlangStrbufInit(&npc); - kvlangRwirNextPc(f->pc, &npc); - kvlangVthreadAdvance(f, npc.p, "running"); - kvlangStrbufFree(&npc); + char buf[KV_KEY_MAX]; + if (kvlangRwirNextPcBuf(f->pc, buf, sizeof buf) == 0) + kvlangDie("next pc exceeds %zu bytes", sizeof buf); + kvlangVthreadAdvance(f, buf, "running"); } int kvlangBuiltinWriteResult(kvlangFrame_t *f, const kvlangXvalue_t *result) { diff --git a/runtime/src/rwir_kv.c b/runtime/src/rwir_kv.c index b19fa306..5bd0233e 100644 --- a/runtime/src/rwir_kv.c +++ b/runtime/src/rwir_kv.c @@ -22,26 +22,23 @@ static char *original_absolute_arg(kvlangFrame_t *f, int idx) { char *fr = kvlangKeytreeFrameRoot(f->pc); if (!fr) return NULL; - kvlangStrbuf_t key; - kvlangStrbufInit(&key); - kvlangStrbufPrintf(&key, "%s/%slib", fr, RUNTIME_MEMBER_SEP); + char key[KV_KEY_MAX]; + kvlangKeyFmt(key, sizeof key, "%s/%slib", fr, RUNTIME_MEMBER_SEP); kvlangXvalue_t lib; kvlangXvalueZero(&lib); - kvlangKvGetOne(f->kv, key.p, &lib); + kvlangKvGetOne(f->kv, key, &lib); char *root = kvlangXvalueNone(&lib) ? NULL : kvlangXvalueValueString(&lib); kvlangXvalueFree(&lib); if (!root || root[0] != '/') { free(root); free(fr); - kvlangStrbufFree(&key); return NULL; } int row = kvlangRwirExtractAddr0(strrchr(f->pc, '/') + 1); - kvlangStrbufClear(&key); - kvlangStrbufPrintf(&key, "%s/[%d,-%d]", root, row, idx + 1); + kvlangKeyFmt(key, sizeof key, "%s/[%d,-%d]", root, row, idx + 1); kvlangXvalue_t source; kvlangXvalueZero(&source); - kvlangKvGetOne(f->kv, key.p, &source); + kvlangKvGetOne(f->kv, key, &source); char *name = kvlangXvalueKindIs(&source, KVSPACE_KIND_RWIR) ? kvlangXvalueSlotName(&source) : NULL; if (name && name[0] != '/') { @@ -49,7 +46,6 @@ static char *original_absolute_arg(kvlangFrame_t *f, int idx) { name = NULL; } kvlangXvalueFree(&source); - kvlangStrbufFree(&key); free(root); free(fr); return name; diff --git a/runtime/src/rwir_map.c b/runtime/src/rwir_map.c index c1778138..7cbaca88 100644 --- a/runtime/src/rwir_map.c +++ b/runtime/src/rwir_map.c @@ -123,10 +123,7 @@ int kvlangBuiltinMap(kvlangFrame_t *f) { char **names = malloc(sizeof(char *) * (size_t)(n > 0 ? n : 1)); for (int i = 0; i < n; i++) { - kvlangStrbuf_t s; - kvlangStrbufInit(&s); - kvlangStrbufPrintf(&s, "[%d]", i); - names[i] = kvlangStrbufDetach(&s); + names[i] = kvlangAstr("[%d]", i); } /* 容器值 p:langtype=声明的 map langtype,body 空,dims=[n] 落 head。 */ char *wty = declared_map_langtype(f, w); diff --git a/runtime/src/rwir_string.c b/runtime/src/rwir_string.c index 877a67f8..615749f2 100644 --- a/runtime/src/rwir_string.c +++ b/runtime/src/rwir_string.c @@ -48,14 +48,18 @@ static void new_char32_cp(kvlangXvalue_t *out, uint32_t cp) { static int write_char32(kvlangFrame_t *f, const uint32_t *r, int n) { kvlangXvalue_t e; if (n > 0) { - kvlangStrbuf_t raw; kvlangStrbufInit(&raw); + uint8_t *raw = malloc((size_t)n * 4); + if (!raw) + kvlangDie("out of memory writing char/utf32"); for (int i = 0; i < n; i++) { - uint8_t le[4] = { r[i] & 0xFF, (r[i] >> 8) & 0xFF, (r[i] >> 16) & 0xFF, (r[i] >> 24) & 0xFF }; - kvlangStrbufPutn(&raw, (const char *)le, 4); + raw[i * 4 + 0] = (uint8_t)(r[i] & 0xFF); + raw[i * 4 + 1] = (uint8_t)((r[i] >> 8) & 0xFF); + raw[i * 4 + 2] = (uint8_t)((r[i] >> 16) & 0xFF); + raw[i * 4 + 3] = (uint8_t)((r[i] >> 24) & 0xFF); } uint8_t *out; uint32_t len; int32_t d = n; - kvspaceTlvEncode(KVSPACE_KIND_CHAR, (const uint8_t *)raw.p, (uint32_t)raw.len, &d, 1, &out, &len); - kvlangStrbufFree(&raw); + kvspaceTlvEncode(KVSPACE_KIND_CHAR, raw, (uint32_t)n * 4, &d, 1, &out, &len); + free(raw); e.data = out; e.len = len; } else { uint8_t *out; uint32_t len; int32_t d = 0; diff --git a/runtime/src/rwir_struct.c b/runtime/src/rwir_struct.c index 9b838139..c5c91d9e 100644 --- a/runtime/src/rwir_struct.c +++ b/runtime/src/rwir_struct.c @@ -2,13 +2,11 @@ static char *struct_field_type(kvlangKv_t *kv, const char *base, const char *fname) { - kvlangStrbuf_t key; - kvlangStrbufInit(&key); - kvlangStrbufPrintf(&key, "%s/%s", base, fname); + char key[KV_KEY_MAX]; + kvlangKeyFmt(key, sizeof key, "%s/%s", base, fname); kvlangXvalue_t value; kvlangXvalueZero(&value); - kvlangKvGetOne(kv, key.p, &value); - kvlangStrbufFree(&key); + kvlangKvGetOne(kv, key, &value); if (kvlangXvalueNone(&value) || strcmp(kvlangXvalueKind(&value), KVSPACE_KIND_DEF_LANGTYPE) != 0) { kvlangXvalueFree(&value); diff --git a/runtime/src/rwir_vthread.c b/runtime/src/rwir_vthread.c index 6aa12afb..7d92296e 100644 --- a/runtime/src/rwir_vthread.c +++ b/runtime/src/rwir_vthread.c @@ -89,10 +89,10 @@ int kvlangBuiltinVthreadSleep(kvlangFrame_t *f) { /* 设状态并把 PC 前进到下一指令。execute 循环只在 init/running/wait 下继续, * 其余状态(paused/done/error…)即停。恢复:外部把 /vthread/{vid}/·status 改回 running。 */ static int set_status(kvlangFrame_t *f, const char *status) { - kvlangStrbuf_t npc; kvlangStrbufInit(&npc); - kvlangRwirNextPc(f->pc, &npc); - kvlangVthreadAdvance(f, npc.p, status); - kvlangStrbufFree(&npc); + char npc[KV_KEY_MAX]; + if (kvlangRwirNextPcBuf(f->pc, npc, sizeof npc) == 0) + kvlangDie("next pc exceeds %zu bytes", sizeof npc); + kvlangVthreadAdvance(f, npc, status); return 0; } diff --git a/runtime/src/rwirext.c b/runtime/src/rwirext.c index 1a61c7f0..74c12e6c 100644 --- a/runtime/src/rwirext.c +++ b/runtime/src/rwirext.c @@ -2,10 +2,11 @@ #include "runtime_internal.h" char *kvlangRwirextNextPc(const char *pc) { - kvlangStrbuf_t b; - kvlangStrbufInit(&b); - kvlangRwirNextPc(pc, &b); - return kvlangStrbufDetach(&b); + char buf[KV_KEY_MAX]; + size_t n = kvlangRwirNextPcBuf(pc, buf, sizeof buf); + if (n == 0) + kvlangDie("next pc exceeds %zu bytes", sizeof buf); + return kvlangAstrN(buf, n); } char *kvlangRwirextParams(void *kvspace, const char *pc) { @@ -22,20 +23,35 @@ char *kvlangRwirextParams(void *kvspace, const char *pc) { return strdup(""); } free(lb); - kvlangStrbuf_t b; - kvlangStrbufInit(&b); - kvlangStrbufPuts(&b, inst.opcode ? inst.opcode : ""); + const char *op = inst.opcode ? inst.opcode : ""; + size_t total = strlen(op) + 1; + for (int i = 0; i < inst.nr; i++) + total += 1 + strlen(inst.reads[i].name ? inst.reads[i].name : ""); + for (int i = 0; i < inst.nw; i++) + total += 1 + strlen(inst.writes[i].name ? inst.writes[i].name : ""); + char *out = malloc(total); + if (!out) + kvlangDie("out of memory formatting params"); + size_t off = strlen(op); + memcpy(out, op, off); for (int i = 0; i < inst.nr; i++) { - kvlangStrbufPutc(&b, '\n'); - kvlangStrbufPuts(&b, inst.reads[i].name ? inst.reads[i].name : ""); + const char *s = inst.reads[i].name ? inst.reads[i].name : ""; + size_t n = strlen(s); + out[off++] = '\n'; + memcpy(out + off, s, n); + off += n; } for (int i = 0; i < inst.nw; i++) { - kvlangStrbufPutc(&b, '\n'); - kvlangStrbufPuts(&b, inst.writes[i].name ? inst.writes[i].name : ""); + const char *s = inst.writes[i].name ? inst.writes[i].name : ""; + size_t n = strlen(s); + out[off++] = '\n'; + memcpy(out + off, s, n); + off += n; } + out[off] = 0; free(fr); kvlangRwirInstFree(&inst); - return kvlangStrbufDetach(&b); + return out; } /* stringkeymap 容器值:遍历 p· 成员 → "[e0, e1, ...]"(成员为 map 时递归)。 */ @@ -48,30 +64,45 @@ static char *display_map(kvlangKv_t *k, const char *path) { free(names); return strdup("[]"); } - kvlangStrbuf_t b; - kvlangStrbufInit(&b); - kvlangStrbufPutc(&b, '['); + char **ms = malloc(sizeof(char *) * (size_t)cnt); + if (!ms) + kvlangDie("out of memory formatting map"); + size_t total = 2; /* "[" + "]" */ for (int i = 0; i < cnt; i++) { - if (i) - kvlangStrbufPuts(&b, ", "); char *mk = kvlangKeytreeMember(path, names[i]); kvlangXvalue_t mv; kvlangXvalueZero(&mv); kvlangKvGetOne(k, mk, &mv); - char *ms = kvlangXvalueNone(&mv) ? strdup("") - : kvlangKindIsMap(kvlangXvalueKind(&mv)) - ? display_map(k, mk) - : kvlangXvalueValueString(&mv); - kvlangStrbufPuts(&b, ms); - free(ms); + ms[i] = kvlangXvalueNone(&mv) ? strdup("") + : kvlangKindIsMap(kvlangXvalueKind(&mv)) + ? display_map(k, mk) + : kvlangXvalueValueString(&mv); kvlangXvalueFree(&mv); free(mk); free(names[i]); + total += strlen(ms[i]) + (i ? 2 : 0); } - kvlangStrbufPutc(&b, ']'); free(names); free(dir); - return kvlangStrbufDetach(&b); + char *out = malloc(total + 1); + if (!out) + kvlangDie("out of memory formatting map"); + size_t off = 0; + out[off++] = '['; + for (int i = 0; i < cnt; i++) { + if (i) { + out[off++] = ','; + out[off++] = ' '; + } + size_t n = strlen(ms[i]); + memcpy(out + off, ms[i], n); + off += n; + free(ms[i]); + } + out[off++] = ']'; + out[off] = 0; + free(ms); + return out; } /* 解析读参 idx 为字符串(变量 → 帧槽值;路径 → 该路径下的值)。 */ diff --git a/runtime/src/strbuf.c b/runtime/src/strbuf.c deleted file mode 100644 index 3c69ce6e..00000000 --- a/runtime/src/strbuf.c +++ /dev/null @@ -1,46 +0,0 @@ -#include "runtime_internal.h" - -static void kvlangStrbufReserve(kvlangStrbuf_t *b, size_t need) { - if (b->cap >= need) return; - size_t cap = b->cap ? b->cap * 2 : 32; - while (cap < need) cap *= 2; - b->p = realloc(b->p, cap); - b->cap = cap; -} - -void kvlangStrbufPutc(kvlangStrbuf_t *b, char c) { - kvlangStrbufReserve(b, b->len + 2); - b->p[b->len++] = c; - b->p[b->len] = '\0'; -} - -void kvlangStrbufPutn(kvlangStrbuf_t *b, const char *s, size_t n) { - if (n == 0) { - if (!b->p) { b->p = calloc(1, 1); b->cap = 1; } - return; - } - kvlangStrbufReserve(b, b->len + n + 1); - memcpy(b->p + b->len, s, n); - b->len += n; - b->p[b->len] = '\0'; -} - -void kvlangStrbufPrintf(kvlangStrbuf_t *b, const char *fmt, ...) { - va_list ap, ap2; - va_start(ap, fmt); - va_copy(ap2, ap); - int n = vsnprintf(NULL, 0, fmt, ap); - va_end(ap); - if (n < 0) { va_end(ap2); return; } - kvlangStrbufReserve(b, b->len + (size_t)n + 1); - vsnprintf(b->p + b->len, (size_t)n + 1, fmt, ap2); - va_end(ap2); - b->len += (size_t)n; -} - -char *kvlangStrbufDetach(kvlangStrbuf_t *b) { - if (b->p == NULL) return strdup(""); - char *p = b->p; - b->p = NULL; b->len = b->cap = 0; - return p; -} diff --git a/runtime/src/strutil.c b/runtime/src/strutil.c new file mode 100644 index 00000000..c14adc77 --- /dev/null +++ b/runtime/src/strutil.c @@ -0,0 +1,42 @@ +#include "runtime_internal.h" + +void kvlangDie(const char *fmt, ...) { + fputs("panic: ", stderr); + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fputc('\n', stderr); + abort(); +} + +size_t kvlangKeyFmt(char *buf, size_t cap, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int n = vsnprintf(buf, cap, fmt, ap); + va_end(ap); + if (n < 0 || (size_t)n >= cap) + kvlangDie("key exceeds %zu bytes", cap); + return (size_t)n; +} + +char *kvlangAstr(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + char *s = NULL; + int n = vasprintf(&s, fmt, ap); + va_end(ap); + if (n < 0 || !s) + kvlangDie("out of memory formatting string"); + return s; +} + +char *kvlangAstrN(const char *s, size_t n) { + char *p = malloc(n + 1); + if (!p) + kvlangDie("out of memory copying string"); + if (n) + memcpy(p, s, n); + p[n] = 0; + return p; +} diff --git a/runtime/src/vthread.c b/runtime/src/vthread.c index d785ecc9..2db15243 100644 --- a/runtime/src/vthread.c +++ b/runtime/src/vthread.c @@ -3,24 +3,22 @@ #define VT_MEMBER_GET(fn, want_status) \ void fn(kvlangKv_t *kv, const char *vtid, char **out) { \ *out = NULL; \ - kvlangStrbuf_t k; kvlangStrbufInit(&k); \ - if (want_status) kvlangKeytreeVthreadStatus(vtid, &k); \ - else kvlangKeytreeVthreadPc(vtid, &k); \ + char k[KV_KEY_MAX]; \ + if (want_status) kvlangKeytreeVthreadStatus(vtid, k, sizeof k); \ + else kvlangKeytreeVthreadPc(vtid, k, sizeof k); \ kvlangXvalue_t v; kvlangXvalueZero(&v); \ - kvlangKvGetOne(kv, k.p, &v); \ + kvlangKvGetOne(kv, k, &v); \ if (!kvlangXvalueNone(&v)) *out = kvlangXvalueValueString(&v); \ kvlangXvalueFree(&v); \ - kvlangStrbufFree(&k); \ } /* Read PC and status separately from KVSpace. */ VT_MEMBER_GET(kvlangVthreadPcGet, false) VT_MEMBER_GET(kvlangVthreadStatusGet, true) -/* 复用缓冲版:把 key 的成员值读进调用方 strbuf(容量跨步保留),免每步 strdup + free。 - * 返回 false = 键缺失或 None(out 清空)。供执行循环每步读 pc / status。 */ -bool kvlangVthreadMemberGetBuf(kvlangKv_t *kv, const char *key, kvlangStrbuf_t *out) { - kvlangStrbufClear(out); +/* 读成员值到调用方缓冲;false = 键缺失或 None。 */ +bool kvlangVthreadMemberGetBuf(kvlangKv_t *kv, const char *key, char *out, + size_t cap) { kvlangXvalue_t v; kvlangXvalueZero(&v); if (kvlangKvGetOne(kv, key, &v) != 0) @@ -29,14 +27,22 @@ bool kvlangVthreadMemberGetBuf(kvlangKv_t *kv, const char *key, kvlangStrbuf_t * kvlangXvalueFree(&v); return false; } + char *tmp = NULL; + const char *src; + size_t n; if (kvlangXvalueKindIs(&v, KVSPACE_KIND_CHAR_UTF8)) { - kvlangStrbufPutn(out, (const char *)xh_body(v.data), - (size_t)xh_content_len(v.data)); + src = (const char *)xh_body(v.data); + n = (size_t)xh_content_len(v.data); } else { - char *s = kvlangXvalueValueString(&v); - kvlangStrbufPuts(out, s); - free(s); + tmp = kvlangXvalueValueString(&v); + src = tmp; + n = strlen(tmp); } + if (n + 1 > cap) + kvlangDie("member value exceeds %zu bytes", cap); + memcpy(out, src, n); + out[n] = 0; + free(tmp); kvlangXvalueFree(&v); return true; } @@ -47,72 +53,70 @@ void kvlangVthreadGet(kvlangKv_t *kv, const char *vtid, char **pc, char **status } int kvlangVthreadSet(kvlangKv_t *kv, const char *vtid, const char *pc, const char *status) { - kvlangStrbuf_t k1, k2; - kvlangStrbufInit(&k1); kvlangStrbufInit(&k2); - kvlangKeytreeVthreadPc(vtid, &k1); - kvlangKeytreeVthreadStatus(vtid, &k2); + char k1[KV_KEY_MAX], k2[KV_KEY_MAX]; + kvlangKeytreeVthreadPc(vtid, k1, sizeof k1); + kvlangKeytreeVthreadStatus(vtid, k2, sizeof k2); kvlangXvalue_t v1, v2; kvlangXvalueZero(&v1); kvlangXvalueZero(&v2); kvlangXvalueNewCharUtf8(&v1, pc); kvlangXvalueNewCharUtf8(&v2, status); - kvlangKvPair_t pairs[2] = { { k1.p, v1 }, { k2.p, v2 } }; + kvlangKvPair_t pairs[2] = { { k1, v1 }, { k2, v2 } }; char err[256]; int rc = kvlangKvSet(kv, pairs, 2, err, sizeof err); kvlangXvalueFree(&v1); kvlangXvalueFree(&v2); - kvlangStrbufFree(&k1); kvlangStrbufFree(&k2); return rc; } /* Persist PC and changed status after each instruction. */ void kvlangVthreadAdvance(kvlangFrame_t *f, const char *pc, const char *status) { - kvlangStrbuf_t k1, k2; - kvlangStrbufInit(&k1); kvlangStrbufInit(&k2); - kvlangKeytreeVthreadPc(f->vtid, &k1); - kvlangKeytreeVthreadStatus(f->vtid, &k2); - if (kvlangKvSetChar(f->kv, k1.p, pc) != 0) + char k1[KV_KEY_MAX], k2[KV_KEY_MAX]; + kvlangKeytreeVthreadPc(f->vtid, k1, sizeof k1); + kvlangKeytreeVthreadStatus(f->vtid, k2, sizeof k2); + if (kvlangKvSetChar(f->kv, k1, pc) != 0) f->persist_failed = true; if (!f->persist_failed && (!f->status_known || strcmp(f->status_known, status) != 0) && - kvlangKvSetChar(f->kv, k2.p, status) != 0) + kvlangKvSetChar(f->kv, k2, status) != 0) f->persist_failed = true; - kvlangStrbufFree(&k1); kvlangStrbufFree(&k2); } int kvlangVthreadSetDone(kvlangKv_t *kv, const char *vtid, const char *ret) { if (ret == NULL || ret[0] == 0) ret = "ok"; - kvlangStrbuf_t k; kvlangStrbufInit(&k); - kvlangKeytreeVthreadStatus(vtid, &k); + char k[KV_KEY_MAX]; + kvlangKeytreeVthreadStatus(vtid, k, sizeof k); kvlangXvalue_t v; kvlangXvalueZero(&v); kvlangXvalueNewCharUtf8(&v, ret); - kvlangKvPair_t pair = { k.p, v }; + kvlangKvPair_t pair = { k, v }; char err[256]; int rc = kvlangKvSet(kv, &pair, 1, err, sizeof err); - kvlangXvalueFree(&v); kvlangStrbufFree(&k); + kvlangXvalueFree(&v); return rc; } void kvlangVthreadSetError(kvlangKv_t *kv, const char *vtid, const char *pc, const char *msg) { - kvlangStrbuf_t msg_path, pc_key, st_key; kvlangStrbufInit(&msg_path); kvlangStrbufInit(&pc_key); kvlangStrbufInit(&st_key); - kvlangKeytreeVthreadStatusMsg(vtid, "error", &msg_path); - kvlangKeytreeVthreadPc(vtid, &pc_key); - kvlangKeytreeVthreadStatus(vtid, &st_key); + char msg_path[KV_KEY_MAX], pc_key[KV_KEY_MAX], st_key[KV_KEY_MAX]; + kvlangKeytreeVthreadStatusMsg(vtid, "error", msg_path, sizeof msg_path); + kvlangKeytreeVthreadPc(vtid, pc_key, sizeof pc_key); + kvlangKeytreeVthreadStatus(vtid, st_key, sizeof st_key); /* 确保 .error/ 父目录存在 */ - char *sep = strrchr(msg_path.p, '/'); + char *sep = strrchr(msg_path, '/'); if (sep) { - kvlangStrbuf_t dir; kvlangStrbufInit(&dir); - kvlangStrbufPutn(&dir, msg_path.p, (size_t)(sep - msg_path.p) + 1); + size_t dl = (size_t)(sep - msg_path) + 1; + char dir[KV_KEY_MAX]; + if (dl >= sizeof dir) + kvlangDie("error dir exceeds %zu bytes", sizeof dir); + memcpy(dir, msg_path, dl); + dir[dl] = 0; char err[256]; - kvlangKvMkindex(kv, dir.p, 0, err, sizeof err); - kvlangStrbufFree(&dir); + kvlangKvMkindex(kv, dir, 0, err, sizeof err); } kvlangXvalue_t vpc, vmsg, vst; kvlangXvalueZero(&vpc); kvlangXvalueZero(&vmsg); kvlangXvalueZero(&vst); kvlangXvalueNewCharUtf8(&vpc, pc); kvlangXvalueNewCharUtf8(&vmsg, msg); kvlangXvalueNewCharUtf8(&vst, "error"); - kvlangKvPair_t pairs[3] = { { pc_key.p, vpc }, { msg_path.p, vmsg }, { st_key.p, vst } }; + kvlangKvPair_t pairs[3] = { { pc_key, vpc }, { msg_path, vmsg }, { st_key, vst } }; char err[256]; kvlangKvSet(kv, pairs, 3, err, sizeof err); kvlangXvalueFree(&vpc); kvlangXvalueFree(&vmsg); kvlangXvalueFree(&vst); - kvlangStrbufFree(&msg_path); kvlangStrbufFree(&pc_key); kvlangStrbufFree(&st_key); } diff --git a/runtime/src/xvalue.c b/runtime/src/xvalue.c index e06fbee3..a3eba6dd 100644 --- a/runtime/src/xvalue.c +++ b/runtime/src/xvalue.c @@ -384,22 +384,27 @@ uint32_t kvlangXvalueChar32At(const kvlangXvalue_t *v, int32_t idx) { /* ── UTF-8 ↔ UTF-32 ────────────────────────────────────────────────── */ -static void utf8_putc(kvlangStrbuf_t *b, uint32_t cp) { - if (cp < 0x80) - kvlangStrbufPutc(b, (char)cp); - else if (cp < 0x800) { - kvlangStrbufPutc(b, (char)(0xC0 | (cp >> 6))); - kvlangStrbufPutc(b, (char)(0x80 | (cp & 0x3F))); - } else if (cp < 0x10000) { - kvlangStrbufPutc(b, (char)(0xE0 | (cp >> 12))); - kvlangStrbufPutc(b, (char)(0x80 | ((cp >> 6) & 0x3F))); - kvlangStrbufPutc(b, (char)(0x80 | (cp & 0x3F))); - } else { - kvlangStrbufPutc(b, (char)(0xF0 | (cp >> 18))); - kvlangStrbufPutc(b, (char)(0x80 | ((cp >> 12) & 0x3F))); - kvlangStrbufPutc(b, (char)(0x80 | ((cp >> 6) & 0x3F))); - kvlangStrbufPutc(b, (char)(0x80 | (cp & 0x3F))); +static size_t utf8_putc(char *out, uint32_t cp) { + if (cp < 0x80) { + out[0] = (char)cp; + return 1; + } + if (cp < 0x800) { + out[0] = (char)(0xC0 | (cp >> 6)); + out[1] = (char)(0x80 | (cp & 0x3F)); + return 2; + } + if (cp < 0x10000) { + out[0] = (char)(0xE0 | (cp >> 12)); + out[1] = (char)(0x80 | ((cp >> 6) & 0x3F)); + out[2] = (char)(0x80 | (cp & 0x3F)); + return 3; } + out[0] = (char)(0xF0 | (cp >> 18)); + out[1] = (char)(0x80 | ((cp >> 12) & 0x3F)); + out[2] = (char)(0x80 | ((cp >> 6) & 0x3F)); + out[3] = (char)(0x80 | (cp & 0x3F)); + return 4; } static uint32_t utf8_next(const char *s, size_t *i, size_t len) { @@ -430,11 +435,15 @@ static uint32_t utf8_next(const char *s, size_t *i, size_t len) { } static char *utf32_to_utf8(const uint8_t *body, int32_t blen) { - kvlangStrbuf_t b; - kvlangStrbufInit(&b); + size_t n = (size_t)(blen / 4); + char *s = malloc(n * 4 + 1); + if (!s) + kvlangDie("out of memory formatting char/utf32"); + size_t off = 0; for (int32_t i = 0; i + 4 <= blen; i += 4) - utf8_putc(&b, rd32(body + i)); - return kvlangStrbufDetach(&b); + off += utf8_putc(s + off, rd32(body + i)); + s[off] = 0; + return s; } static char *strndup2(const uint8_t *p, int32_t n) { @@ -454,13 +463,6 @@ char *kvlangXvaluePtrTarget(const kvlangXvalue_t *v) { /* ── value_string(对齐 Go ValueString)────────────────────────────── */ -static void append_num_int(kvlangStrbuf_t *b, int64_t n) { - kvlangStrbufPrintf(b, "%lld", (long long)n); -} -static void append_num_uint(kvlangStrbuf_t *b, uint64_t n) { - kvlangStrbufPrintf(b, "%llu", (unsigned long long)n); -} - char *kvlangXvalueValueString(const kvlangXvalue_t *v) { if (kvlangXvalueNone(v)) return strdup(KVSPACE_KIND_NONE); @@ -469,62 +471,33 @@ char *kvlangXvalueValueString(const kvlangXvalue_t *v) { const char *k = kvlangXvalueKind(v); if (xh_is_ptr(v->data)) { - kvlangStrbuf_t b; - kvlangStrbufInit(&b); - kvlangStrbufPutn(&b, "\xE2\x86\x92", 3); - kvlangStrbufPutn(&b, (const char *)body, (size_t)blen); - return kvlangStrbufDetach(&b); + char *s = malloc((size_t)blen + 4); + if (!s) + kvlangDie("out of memory formatting pointer"); + memcpy(s, "\xE2\x86\x92", 3); + if (blen) + memcpy(s + 3, body, (size_t)blen); + s[blen + 3] = 0; + return s; } if (strcmp(k, KVSPACE_KIND_BOOL) == 0) return strdup(body[0] ? "true" : "false"); - if (strcmp(k, KVSPACE_KIND_INT8) == 0) { - kvlangStrbuf_t b; - kvlangStrbufInit(&b); - append_num_int(&b, (int8_t)body[0]); - return kvlangStrbufDetach(&b); - } - if (strcmp(k, KVSPACE_KIND_INT16) == 0) { - kvlangStrbuf_t b; - kvlangStrbufInit(&b); - append_num_int(&b, (int16_t)rd16(body)); - return kvlangStrbufDetach(&b); - } - if (strcmp(k, KVSPACE_KIND_INT32) == 0) { - kvlangStrbuf_t b; - kvlangStrbufInit(&b); - append_num_int(&b, (int32_t)rd32(body)); - return kvlangStrbufDetach(&b); - } - if (strcmp(k, KVSPACE_KIND_INT64) == 0) { - kvlangStrbuf_t b; - kvlangStrbufInit(&b); - append_num_int(&b, (int64_t)rd64(body)); - return kvlangStrbufDetach(&b); - } - if (strcmp(k, KVSPACE_KIND_UINT8) == 0) { - kvlangStrbuf_t b; - kvlangStrbufInit(&b); - append_num_uint(&b, body[0]); - return kvlangStrbufDetach(&b); - } - if (strcmp(k, KVSPACE_KIND_UINT16) == 0) { - kvlangStrbuf_t b; - kvlangStrbufInit(&b); - append_num_uint(&b, rd16(body)); - return kvlangStrbufDetach(&b); - } - if (strcmp(k, KVSPACE_KIND_UINT32) == 0) { - kvlangStrbuf_t b; - kvlangStrbufInit(&b); - append_num_uint(&b, rd32(body)); - return kvlangStrbufDetach(&b); - } - if (strcmp(k, KVSPACE_KIND_UINT64) == 0) { - kvlangStrbuf_t b; - kvlangStrbufInit(&b); - append_num_uint(&b, rd64(body)); - return kvlangStrbufDetach(&b); - } + if (strcmp(k, KVSPACE_KIND_INT8) == 0) + return kvlangAstr("%d", (int)(int8_t)body[0]); + if (strcmp(k, KVSPACE_KIND_INT16) == 0) + return kvlangAstr("%d", (int)(int16_t)rd16(body)); + if (strcmp(k, KVSPACE_KIND_INT32) == 0) + return kvlangAstr("%d", (int32_t)rd32(body)); + if (strcmp(k, KVSPACE_KIND_INT64) == 0) + return kvlangAstr("%lld", (long long)(int64_t)rd64(body)); + if (strcmp(k, KVSPACE_KIND_UINT8) == 0) + return kvlangAstr("%u", (unsigned)body[0]); + if (strcmp(k, KVSPACE_KIND_UINT16) == 0) + return kvlangAstr("%u", (unsigned)rd16(body)); + if (strcmp(k, KVSPACE_KIND_UINT32) == 0) + return kvlangAstr("%u", rd32(body)); + if (strcmp(k, KVSPACE_KIND_UINT64) == 0) + return kvlangAstr("%llu", (unsigned long long)rd64(body)); if (strcmp(k, KVSPACE_KIND_FLOAT32) == 0 || strcmp(k, KVSPACE_KIND_FLOAT64) == 0) { char tmp[64]; @@ -542,11 +515,8 @@ char *kvlangXvalueValueString(const kvlangXvalue_t *v) { if (strcmp(k, KVSPACE_KIND_RWFUNC) == 0) { if (blen > 5) return strndup2(body + 5, blen - 5); - kvlangStrbuf_t b; - kvlangStrbufInit(&b); - kvlangStrbufPrintf(&b, "r%d/w%d", (blen >= 2 ? rd16(body) : 0), - (blen >= 4 ? rd16(body + 2) : 0)); - return kvlangStrbufDetach(&b); + return kvlangAstr("r%d/w%d", (blen >= 2 ? rd16(body) : 0), + (blen >= 4 ? rd16(body + 2) : 0)); } if (kvlangKindIsMap(k)) return strdup("map"); @@ -618,18 +588,20 @@ void kvlangXvalueNewCharKind(kvlangXvalue_t *v, const char *kind, } void kvlangXvalueNewCharUtf32(kvlangXvalue_t *v, const char *s) { size_t len = strlen(s); - kvlangStrbuf_t raw; - kvlangStrbufInit(&raw); - size_t i = 0; + uint8_t *raw = malloc((len ? len : 1) * 4); + if (!raw) + kvlangDie("out of memory encoding char/utf32"); + size_t i = 0, off = 0; while (i < len) { uint32_t cp = utf8_next(s, &i, len); - uint8_t le[4] = {cp & 0xFF, (cp >> 8) & 0xFF, (cp >> 16) & 0xFF, - (cp >> 24) & 0xFF}; - kvlangStrbufPutn(&raw, (const char *)le, 4); - } - kvlangXvalueNewTlv(v, KVSPACE_KIND_CHAR, (const uint8_t *)raw.p, - (uint32_t)raw.len, (int32_t)(raw.len / 4)); - kvlangStrbufFree(&raw); + raw[off++] = (uint8_t)(cp & 0xFF); + raw[off++] = (uint8_t)((cp >> 8) & 0xFF); + raw[off++] = (uint8_t)((cp >> 16) & 0xFF); + raw[off++] = (uint8_t)((cp >> 24) & 0xFF); + } + kvlangXvalueNewTlv(v, KVSPACE_KIND_CHAR, raw, (uint32_t)off, + (int32_t)(off / 4)); + free(raw); } /* 指针:head langtype = "*" + target_langtype(目标完整 langtype),body = 目标 key。 */ void kvlangXvalueNewPtr(kvlangXvalue_t *v, const char *target_langtype, diff --git a/runtime/tests/delegate_test.c b/runtime/tests/delegate_test.c index 0f3c7e27..61402dc2 100644 --- a/runtime/tests/delegate_test.c +++ b/runtime/tests/delegate_test.c @@ -60,12 +60,9 @@ static char *get_char(kvlangKv_t *kv, const char *key) { } static char *error_msg(kvlangKv_t *kv, const char *vtid) { - kvlangStrbuf_t k; - kvlangStrbufInit(&k); - kvlangKeytreeVthreadStatusMsg(vtid, "error", &k); - char *s = get_char(kv, k.p); - kvlangStrbufFree(&k); - return s; + char k[KV_KEY_MAX]; + kvlangKeytreeVthreadStatusMsg(vtid, "error", k, sizeof k); + return get_char(kv, k); } static char *take_cmd(kvlangKv_t *kv, const char *cmd_dir, uint64_t ns) { diff --git a/runtime/tests/test_crash_resume.c b/runtime/tests/test_crash_resume.c index d127f2fd..12a4a97d 100644 --- a/runtime/tests/test_crash_resume.c +++ b/runtime/tests/test_crash_resume.c @@ -17,11 +17,9 @@ int main(void) { kvlangKv_t *kv = kvlangKvConnect(dsn); if (!kv) _exit(2); - kvlangStrbuf_t key; - kvlangStrbufInit(&key); - kvlangKeytreeVthreadPc("vt0", &key); - int rc = kvlangKvSetChar(kv, key.p, "/lib/f/[2,0]"); - kvlangStrbufFree(&key); + char key[KV_KEY_MAX]; + kvlangKeytreeVthreadPc("vt0", key, sizeof key); + int rc = kvlangKvSetChar(kv, key, "/lib/f/[2,0]"); kvlangXvalue_t value; kvlangXvalueNewInt64(&value, 73); kvlangKvPair_t pair = {"/value", value}; diff --git "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/09-cruntime\344\270\216\345\220\216\347\253\257abi.kv" "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/09-cruntime\344\270\216\345\220\216\347\253\257abi.kv" index d06cf80d..6e9b9500 100644 --- "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/09-cruntime\344\270\216\345\220\216\347\253\257abi.kv" +++ "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/09-cruntime\344\270\216\345\220\216\347\253\257abi.kv" @@ -54,7 +54,8 @@ livebyte)。两组对外 C ABI: 内部模块:`xvalue.c`(XValue 编解码薄封装)、`langtype.c` + `langtypetable.c`(langtype 校验/匹配与我 表格)、`kvspace.c`(kvspace ABI 封装)、`keytree.c`(路径构造)、`rwir_decode.c`(PC 解析 + Decode)、 `vthread.c`、`rwir*.c`(native 算子 + 静态注册表)、`kvcpu.c`(Execute 循环)、`runtime.c`(ABI -层)、`rwirext.c`(扩展宿主 ABI,含 `notinmyrwircaps`)、`logx.c`、`strbuf.c`、`const.h`。 +层)、`rwirext.c`(扩展宿主 ABI,含 `notinmyrwircaps`)、`logx.c`、`strutil.c`(一次性字符串 +工具)、`const.h`。 myrwircaps 为**静态数组 + 线性查找**。 ## 统一 `kvspace*` C ABI(去特化)