From 6457a7629bc6f675c87f00db2ce37963ea51f509 Mon Sep 17 00:00:00 2001 From: "peng.li24" <734991033@qq.com> Date: Tue, 8 Sep 2026 11:14:06 +0800 Subject: [PATCH 1/3] =?UTF-8?q?runtime:=20=E7=AE=97=E6=9C=AF=E6=B4=BE?= =?UTF-8?q?=E5=8F=91=E9=87=8D=E6=9E=84=E2=80=94=E2=80=94=E4=BB=85=20C=20?= =?UTF-8?q?=E5=8E=9F=E7=94=9F=E6=95=B0=E5=80=BC=20langtype=20=E8=B5=B0?= =?UTF-8?q?=E9=80=9A=E7=94=A8=20add=EF=BC=8C=E9=87=8F=E5=8C=96=E7=B2=BE?= =?UTF-8?q?=E5=BA=A6=E4=B8=93=E7=B2=BE/handoff?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit int4/fp8/bf16 等 C 表达不了的量化精度不再经通用数值路径;is_num_kind_prefix 精确判定,去 strip_num_kind 简化。rwir 适配。 --- runtime/src/builtin.c | 38 ++++---- runtime/src/kvcpu.c | 156 ++++++++++++++++++++++++--------- runtime/src/runtime_internal.h | 27 ++++++ runtime/src/rwir.c | 1 + 4 files changed, 164 insertions(+), 58 deletions(-) diff --git a/runtime/src/builtin.c b/runtime/src/builtin.c index 137a3d98..9cd877ec 100644 --- a/runtime/src/builtin.c +++ b/runtime/src/builtin.c @@ -595,23 +595,33 @@ static const struct { const char *op; kvlangBuiltinFn fn; } myrwircaps[] = { static const size_t myrwircaps_n = sizeof(myrwircaps) / sizeof(myrwircaps[0]); -/* 剥离 . 前缀(int64.add → add),使融合后的单条 add 覆盖全部数字类型。 - * 非数字前缀(array./string./time/duration. 等)与裸类型 cast(int64)原样保留。 */ +/* C 原生数值 langtype 集:仅这些精度的算术走 kvlangBuiltinAdd 等通用实现。 + * int4/fp8/bf16 等 C 表达不了的量化精度不在此列,其 ·op 走专精 fn 或 handoff。 */ static const char *NUM_KINDS[] = {"int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float32", "float64"}; -static const char *strip_num_kind(const char *op) { - const char *dot = strstr(op, MEMBER_SEP); - if (!dot) return op; - size_t n = (size_t)(dot - op); +static bool is_num_kind_prefix(const char *op, size_t n) { for (size_t i = 0; i < sizeof(NUM_KINDS) / sizeof(NUM_KINDS[0]); i++) - if (strlen(NUM_KINDS[i]) == n && strncmp(op, NUM_KINDS[i], n) == 0) return dot + MEMBER_SEP_LEN; - return op; + if (strlen(NUM_KINDS[i]) == n && strncmp(op, NUM_KINDS[i], n) == 0) return true; + return false; +} + +/* rwirtable 两级查找:先查完整 opcode(命中=专精实现,如 fp8·add,或 time·add 等成员算子), + * 未命中且末段前缀是 C 原生数值 langtype 才拆前缀查裸算子(int64·add → add,通用实现)。 + * 非数值前缀(time/duration·max 等用户 rwfunc)不剥离,两级皆 miss → 非本 runtime native。 */ +int kvlangBuiltinCapIndex(const char *opcode) { + for (size_t i = 0; i < myrwircaps_n; i++) + if (strcmp(myrwircaps[i].op, opcode) == 0) return (int)i; + const char *dot = strstr(opcode, MEMBER_SEP); + if (dot && is_num_kind_prefix(opcode, (size_t)(dot - opcode))) { + const char *bare = dot + MEMBER_SEP_LEN; + for (size_t i = 0; i < myrwircaps_n; i++) + if (strcmp(myrwircaps[i].op, bare) == 0) return (int)i; + } + return -1; } bool kvlangBuiltinIsNative(const char *opcode) { - const char *op = strip_num_kind(opcode); - for (size_t i = 0; i < myrwircaps_n; i++) if (strcmp(myrwircaps[i].op, op) == 0) return true; - return false; + return kvlangBuiltinCapIndex(opcode) >= 0; } bool kvlangBuiltinNumOp(const char *opcode) { @@ -631,10 +641,8 @@ bool kvlangBuiltinNumOp(const char *opcode) { } int kvlangBuiltinNative(kvlangFrame_t *f) { - const char *op = strip_num_kind(f->inst->opcode); - for (size_t i = 0; i < myrwircaps_n; i++) { - if (strcmp(myrwircaps[i].op, op) == 0) return myrwircaps[i].fn(f); - } + int i = f->inst->op_id >= 0 ? f->inst->op_id : kvlangBuiltinCapIndex(f->inst->opcode); + if (i >= 0) return myrwircaps[i].fn(f); return kvlangBuiltinSetErr(f, "unknown builtin op: %s", f->inst->opcode); } diff --git a/runtime/src/kvcpu.c b/runtime/src/kvcpu.c index 026190e3..c416e006 100644 --- a/runtime/src/kvcpu.c +++ b/runtime/src/kvcpu.c @@ -1,5 +1,50 @@ #include "runtime_internal.h" +/* decode-once 进程内缓存(IV-0:进程私有,绝不入 kvspace)。指令 XValue layout 后冻结, + * 一条冻结指令由 (funcdir, addr0) 唯一标识(funcdir=/lib/pkg·fn,不同函数不同 funcdir, + * 递归/多帧同函数共享同一条),故缓存永不失效。命中即跳过 code 槽读 + decode + 分类。 + * runtime C 单线程驱动(全库无锁直改 kvspace),此缓存同样无锁。永不淘汰(≈代码大小上界)。 */ +typedef struct rwir_cache_ent { + char *key; + kvlangRwirInst_t *inst; + struct rwir_cache_ent *next; +} rwir_cache_ent_t; +#define RWIR_CACHE_BUCKETS 4096 +static rwir_cache_ent_t *g_rwir_cache[RWIR_CACHE_BUCKETS]; + +static size_t rwir_hash(const char *s) { + size_t h = 1469598103934665603ULL; + for (; *s; s++) { h ^= (unsigned char)*s; h *= 1099511628211ULL; } + return h & (RWIR_CACHE_BUCKETS - 1); +} +static kvlangRwirInst_t *rwir_cache_get(const char *key) { + for (rwir_cache_ent_t *e = g_rwir_cache[rwir_hash(key)]; e; e = e->next) + if (strcmp(e->key, key) == 0) return e->inst; + return NULL; +} +static void rwir_cache_put(const char *key, kvlangRwirInst_t *inst) { + size_t b = rwir_hash(key); + rwir_cache_ent_t *e = malloc(sizeof *e); + e->key = strdup(key); + e->inst = inst; + e->next = g_rwir_cache[b]; + g_rwir_cache[b] = e; +} + +/* 读帧的 ‥lib 槽 → funcdir(/lib/pkg·fn),供缓存键用;无则 NULL(不缓存该指令)。 */ +static char *read_seglib(kvlangKv_t *kv, const char *fr) { + char *stk = kvlangKeytreeStack(fr); + kvlangStrbuf_t k; kvlangStrbufInit(&k); + kvlangStrbufPuts(&k, stk); kvlangStrbufPuts(&k, SEG_LIB); + free(stk); + kvlangXvalue_t v; kvlangXvalueZero(&v); + kvlangKvGetOne(kv, k.p, &v); + kvlangStrbufFree(&k); + char *r = kvlangXvalueNone(&v) ? NULL : kvlangXvalueValueString(&v); + kvlangXvalueFree(&v); + return r; +} + /* 找末个成员分隔符(·,多字节),对齐 strrchr('.') 的单字节旧语义。 */ static const char *rfind_sep(const char *s) { const char *found = NULL, *p = s; @@ -383,14 +428,14 @@ static char *handle_call(kvlangKv_t *kv, const char *pc, kvlangRwirInst_t *inst) } static int handle_control(kvlangKv_t *kv, const char *vtid, const char *pc, kvlangRwirInst_t *inst) { - if (strcmp(inst->opcode, OP_CALL) == 0) { + if (inst->op_id == OPID_CALL) { char *sub = handle_call(kv, pc, inst); if (!sub) return -1; kvlangVthreadSet(kv, vtid, sub, "running"); free(sub); return 0; } - if (strcmp(inst->opcode, OP_RETURN) == 0) { + if (inst->op_id == OPID_RETURN) { char *parent = NULL; if (handle_return(kv, vtid, pc, &parent) != 0) return -1; if (!parent) { kvlangVthreadSetDone(kv, vtid, "ok"); return 0; } @@ -398,7 +443,7 @@ static int handle_control(kvlangKv_t *kv, const char *vtid, const char *pc, kvla free(parent); return 0; } - if (strcmp(inst->opcode, OP_GOTO) == 0) { + if (inst->op_id == OPID_GOTO) { if (inst->nr != 1) { char msg[128]; snprintf(msg, sizeof msg, "RuntimeError: goto expects 1 irseq, got %d", inst->nr); kvlangVthreadSetError(kv, vtid, pc, msg); @@ -406,7 +451,7 @@ static int handle_control(kvlangKv_t *kv, const char *vtid, const char *pc, kvla } return jump_to(kv, vtid, pc, &inst->reads[0], OP_GOTO); } - if (strcmp(inst->opcode, OP_BR) == 0) { + if (inst->op_id == OPID_BR) { if (inst->nr != 3) { char msg[128]; snprintf(msg, sizeof msg, "RuntimeError: br expects cond trueIrseq falseIrseq, got %d", inst->nr); kvlangVthreadSetError(kv, vtid, pc, msg); @@ -439,6 +484,7 @@ static int handle_control(kvlangKv_t *kv, const char *vtid, const char *pc, kvla int kvlangKvcpuDynCall(kvlangKv_t *kv, const char *vtid, const char *pc, const char *funckey) { kvlangRwirInst_t ci; ci.opcode = strdup(OP_CALL); + ci.op_id = OPID_CALL; ci.reads = malloc(sizeof(kvlangParam_t)); ci.reads[0].name = strdup(funckey); kvlangXvalueZero(&ci.reads[0].val); @@ -450,10 +496,6 @@ int kvlangKvcpuDynCall(kvlangKv_t *kv, const char *vtid, const char *pc, const c return rc; } -static bool is_copy_op(const char *opcode) { - return strcmp(opcode, "=") == 0; -} - int handoff_external_rwir(kvlangKv_t *kv, const char *vtid, const char *pc, kvlangRwirInst_t *inst) { /* handoff:把 pc 挂到共享队列 /lib//vids/(各 rwir 的 vids 已 Ptr 统一到 * 第一个 rwir 的 vids 下,Set 经路径穿透落到同一 strkeymap)。外部执行器认领并驱动该 vthread, @@ -549,6 +591,7 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode, char * if (vtid[0] == 0) { kvlangStrbufFree(&vtid_b); return -1; } char *cur = strdup(pc); + char *cur_frame = NULL, *cur_funcdir = NULL; /* 帧不变时 funcdir 只读一次,供缓存键 */ int rc = 0; for (;;) { char *pcv = NULL, *status = NULL; @@ -569,92 +612,119 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode, char * } char *fr = kvlangKeytreeFrameRoot(cur); - char *link_base = kvlangKeytreeStack(fr); - kvlangRwirInst_t inst; - char err[256]; - if (kvlangRwirDecode(kv, link_base, cur, &inst, err, sizeof err) != 0) { - char msg[256]; snprintf(msg, sizeof msg, "decode: %s", err); - kvlangVthreadSetError(kv, vtid, cur, msg); - free(fr); free(link_base); - rc = -1; - break; + if (!cur_frame || strcmp(cur_frame, fr) != 0) { + free(cur_frame); cur_frame = strdup(fr); + free(cur_funcdir); cur_funcdir = read_seglib(kv, fr); + } + const char *lastc = NULL; + for (const char *p = cur; (p = strstr(p, "/[")) != NULL; p += 2) lastc = p; + int addr0 = lastc ? kvlangRwirExtractAddr0(lastc + 1) : 0; + + kvlangRwirInst_t tmp; + kvlangRwirInst_t *inst = NULL; + bool tmp_owned = false; + kvlangStrbuf_t ck; kvlangStrbufInit(&ck); + if (cur_funcdir) { kvlangStrbufPrintf(&ck, "%s#%d", cur_funcdir, addr0); inst = rwir_cache_get(ck.p); } + + if (!inst) { + char *link_base = kvlangKeytreeStack(fr); + char err[256]; + if (kvlangRwirDecode(kv, link_base, cur, &tmp, err, sizeof err) != 0) { + char msg[256]; snprintf(msg, sizeof msg, "decode: %s", err); + kvlangVthreadSetError(kv, vtid, cur, msg); + free(link_base); kvlangStrbufFree(&ck); free(fr); + rc = -1; + break; + } + free(link_base); + if (cur_funcdir && tmp.opcode && tmp.opcode[0]) { + /* 转移所有权入缓存:冻结指令永不失效、永不 free */ + kvlangRwirInst_t *persist = malloc(sizeof *persist); + *persist = tmp; + rwir_cache_put(ck.p, persist); + inst = persist; + } else { + inst = &tmp; tmp_owned = true; + } } - free(link_base); + kvlangStrbufFree(&ck); - kvlangLogDebug("[%s] PC=%s OP=%s R=%d W=%d", vtid, cur, inst.opcode ? inst.opcode : "(empty)", inst.nr, inst.nw); + kvlangLogDebug("[%s] PC=%s OP=%s R=%d W=%d", vtid, cur, inst->opcode ? inst->opcode : "(empty)", inst->nr, inst->nw); - if (!inst.opcode || !inst.opcode[0]) { + if (!inst->opcode || !inst->opcode[0]) { /* layout 对每条路径都补了 return(lower::terminate),走到空槽只能是 /lib 损坏 * 或 goto/br 越界;报 RuntimeError 让该 vthread 停下,不拖垮整个进程。 */ char msg[512]; snprintf(msg, sizeof msg, "RuntimeError: no instruction at %s", cur); kvlangVthreadSetError(kv, vtid, cur, msg); - free(fr); kvlangRwirInstFree(&inst); + free(fr); if (tmp_owned) kvlangRwirInstFree(&tmp); rc = -1; break; } int exec_err = 0; - if (op_is_control(inst.opcode)) { - exec_err = handle_control(kv, vtid, cur, &inst); - } else if (kvlangBuiltinIsNative(inst.opcode)) { + if (inst->op_id >= 0) { char *yield = NULL; - kvlangFrame_t f = { kv, vtid, cur, &inst, &yield }; + kvlangFrame_t f = { kv, vtid, cur, inst, &yield }; exec_err = kvlangBuiltinNative(&f); if (exec_err == 0 && yield) { /* native(vthread·run return 模式)冒泡一个子 vthread 的 rwir pc 给上层驱动。 * 本 vthread(主)pc 未推进,驱动派发子 rwir 并推进子 pc 后重入即续跑。 */ if (out_pc) *out_pc = yield; else free(yield); - free(fr); kvlangRwirInstFree(&inst); - free(cur); kvlangStrbufFree(&vtid_b); + free(fr); if (tmp_owned) kvlangRwirInstFree(&tmp); + free(cur); free(cur_frame); free(cur_funcdir); kvlangStrbufFree(&vtid_b); return 1; } - } else if (is_copy_op(inst.opcode)) { - exec_err = kvlangBuiltinExecuteCopy(kv, vtid, cur, &inst); - } else if (isothersrwir(kv, inst.opcode)) { - char *rk = kvlangKeytreeRwir(inst.opcode); + } else if (inst->op_id == OPID_CALL || inst->op_id == OPID_RETURN || + inst->op_id == OPID_GOTO || inst->op_id == OPID_BR) { + exec_err = handle_control(kv, vtid, cur, inst); + } else if (inst->op_id == OPID_COPY) { + exec_err = kvlangBuiltinExecuteCopy(kv, vtid, cur, inst); + } else if (isothersrwir(kv, inst->opcode)) { + char *rk = kvlangKeytreeRwir(inst->opcode); int def_nr = 0; char *def_sig = load_def_reads(kv, rk, &def_nr); free(rk); if (def_sig) { - exec_err = check_read_types(kv, vtid, cur, inst.opcode, def_sig, def_nr, inst.reads, inst.nr); + exec_err = check_read_types(kv, vtid, cur, inst->opcode, def_sig, def_nr, inst->reads, inst->nr); free(def_sig); } if (exec_err == 0 && mode == KVMODE_RETURN) { if (out_pc) *out_pc = strdup(cur); - free(fr); kvlangRwirInstFree(&inst); - free(cur); kvlangStrbufFree(&vtid_b); + free(fr); if (tmp_owned) kvlangRwirInstFree(&tmp); + free(cur); free(cur_frame); free(cur_funcdir); kvlangStrbufFree(&vtid_b); return 1; } - if (exec_err == 0) exec_err = handoff_external_rwir(kv, vtid, cur, &inst); + if (exec_err == 0) exec_err = handoff_external_rwir(kv, vtid, cur, inst); } else { /* 用户函数 → call */ kvlangRwirInst_t ci; ci.opcode = strdup(OP_CALL); - ci.nr = inst.nr + 1; - ci.nw = inst.nw; + ci.op_id = OPID_CALL; + ci.nr = inst->nr + 1; + ci.nw = inst->nw; ci.reads = malloc(sizeof(kvlangParam_t) * (size_t)ci.nr); - ci.reads[0].name = strdup(inst.opcode); + ci.reads[0].name = strdup(inst->opcode); ci.reads[0].val.data = NULL; ci.reads[0].val.len = 0; - for (int i = 0; i < inst.nr; i++) { ci.reads[i + 1] = inst.reads[i]; } - ci.writes = inst.writes; + for (int i = 0; i < inst->nr; i++) { ci.reads[i + 1] = inst->reads[i]; } + ci.writes = inst->writes; exec_err = handle_control(kv, vtid, cur, &ci); free(ci.opcode); free(ci.reads[0].name); free(ci.reads); } - if (exec_err != 0) { free(fr); kvlangRwirInstFree(&inst); rc = -1; break; } + if (exec_err != 0) { free(fr); if (tmp_owned) kvlangRwirInstFree(&tmp); rc = -1; break; } char *newpc = NULL, *st = NULL; kvlangVthreadGet(kv, vtid, &newpc, &st); free(st); free(fr); - kvlangRwirInstFree(&inst); + if (tmp_owned) kvlangRwirInstFree(&tmp); if (!newpc || !newpc[0]) { free(newpc); break; } free(cur); cur = newpc; } - free(cur); + free(cur); free(cur_frame); free(cur_funcdir); kvlangStrbufFree(&vtid_b); return rc; } diff --git a/runtime/src/runtime_internal.h b/runtime/src/runtime_internal.h index b847b4d2..1515e8d1 100644 --- a/runtime/src/runtime_internal.h +++ b/runtime/src/runtime_internal.h @@ -212,16 +212,43 @@ bool kvlangKeytreeIsEntryPc(const char *pc); #define OP_BR "br" #define OP_GOTO "goto" #define OP_ASSIGN "assign" +#define OP_COPY "=" + +/* op_id:decode 期一次固化的统一派发码(quickening),主循环据此纯整数跳表、热路径零 strcmp。 + * ≥0 = native,直查 myrwircaps[op_id] + * 负值 = 保留派发类(control / copy / 待定),语义见下 */ +enum { + OPID_OTHER = -1, /* 未定:他人 rwir 或用户函数,执行期经 kvspace 查 /lib 才能区分 */ + OPID_CALL = -2, + OPID_RETURN = -3, + OPID_GOTO = -4, + OPID_BR = -5, + OPID_COPY = -6, +}; static inline bool op_is_control(const char *op) { return strcmp(op, OP_CALL) == 0 || strcmp(op, OP_RETURN) == 0 || strcmp(op, OP_BR) == 0 || strcmp(op, OP_GOTO) == 0; } +int kvlangBuiltinCapIndex(const char *opcode); + +/* decode 期分类:control/copy 先于 native,miss 落 OPID_OTHER(执行期再查 /lib)。 */ +static inline int kvlangOpClassify(const char *op) { + if (strcmp(op, OP_CALL) == 0) return OPID_CALL; + if (strcmp(op, OP_RETURN) == 0) return OPID_RETURN; + if (strcmp(op, OP_GOTO) == 0) return OPID_GOTO; + if (strcmp(op, OP_BR) == 0) return OPID_BR; + if (strcmp(op, OP_COPY) == 0) return OPID_COPY; + int n = kvlangBuiltinCapIndex(op); + return n >= 0 ? n : OPID_OTHER; +} + typedef struct { char *name; kvlangXvalue_t val; } kvlangParam_t; typedef struct { char *opcode; + int op_id; /* 统一派发码,见上 enum;decode 期固化,永不随帧变化 */ kvlangParam_t *reads; int nr; kvlangParam_t *writes; int nw; } kvlangRwirInst_t; diff --git a/runtime/src/rwir.c b/runtime/src/rwir.c index b34dd79f..894a0370 100644 --- a/runtime/src/rwir.c +++ b/runtime/src/rwir.c @@ -54,6 +54,7 @@ int kvlangRwirDecode(kvlangKv_t *kv, const char *link_base, const char *pc, kvla free(nm); if (!kvlangXvalueNone(&v)) out->opcode = kvlangXvalueValueString(&v); kvlangXvalueFree(&v); + out->op_id = out->opcode ? kvlangOpClassify(out->opcode) : OPID_OTHER; for (int i = 1; i <= MAX_PARAMS; i++) { kvlangStrbufPrintf(&key, "[%d,-%d]", addr0, i); From 2eaf3bba5b7a4dd054ba5f77e788adf51257c6fd Mon Sep 17 00:00:00 2001 From: "peng.li24" <734991033@qq.com> Date: Tue, 8 Sep 2026 11:14:06 +0800 Subject: [PATCH 2/3] =?UTF-8?q?tutorial:=20=E5=88=A0=20fibonacci/prime=5Fs?= =?UTF-8?q?ieve=20=E6=95=99=E7=A8=8B=EF=BC=88=E5=B7=B2=E8=BF=81=20benchmar?= =?UTF-8?q?k/cases=EF=BC=89+=20=E5=BC=95=E7=94=A8=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 06-algo/08-leetcode/09-debugger 的 fib/prime_sieve 重复实现移除(benchmark/ 已有); issue116.rs/README 引用同步;benchmark.csv 空产物 gitignore。 --- .gitignore | 3 ++ README.md | 4 +-- README_CN.md | 4 +-- layout/tests/issue116.rs | 1 - tutorial/06-algo/fibonacci.kv | 31 ----------------- tutorial/06-algo/prime_sieve.c | 26 -------------- tutorial/06-algo/prime_sieve.kv | 44 ------------------------ tutorial/06-algo/prime_sieve.py | 20 ----------- tutorial/08-leetcode/204_count_primes.kv | 35 ------------------- tutorial/08-leetcode/509_fib.kv | 28 --------------- tutorial/09-debugger/fib.kv | 17 --------- tutorial/README.md | 4 +-- 12 files changed, 8 insertions(+), 209 deletions(-) delete mode 100644 tutorial/06-algo/fibonacci.kv delete mode 100644 tutorial/06-algo/prime_sieve.c delete mode 100644 tutorial/06-algo/prime_sieve.kv delete mode 100644 tutorial/06-algo/prime_sieve.py delete mode 100644 tutorial/08-leetcode/204_count_primes.kv delete mode 100644 tutorial/08-leetcode/509_fib.kv delete mode 100644 tutorial/09-debugger/fib.kv diff --git a/.gitignore b/.gitignore index b3abe0cb..61105ad8 100644 --- a/.gitignore +++ b/.gitignore @@ -78,3 +78,6 @@ stdlib/kvlang/reference/ # tutorial shm 测试产物(相对路径 DSN) kvtut* + +# tutorial bench 空产物 +/tutorial/benchmark.csv diff --git a/README.md b/README.md index ebba9857..1eb3a078 100644 --- a/README.md +++ b/README.md @@ -252,7 +252,7 @@ Strings support indexing and concatenation with `+`; `at(s, i)` reads the i-th c 02-func/ rwfunc, call, accumulator (2 files) 03-control/ if, while, for, guess (5 files) 03-debugger/ chain_array, debugger builtin (4 files) -04-algo/ fibonacci, gcd, collatz, … (13 files) +06-algo/ gcd, collatz, power, factorial, … (8 files) 06-lib/ lib block, nested, cross-lib, anon (11 files) 07-leetcode/ LeetCode solutions (90 files) error_cases/ type_error, index_error, zero_division, … (36 files) @@ -260,7 +260,7 @@ error_cases/ type_error, index_error, zero_division, … (36 files) ```bash ./kvlang tutorial/01-basics/hello.kv # hello kvlang -./kvlang tutorial/04-algo/fibonacci.kv # fib = 55 +./kvlang tutorial/06-algo/gcd.kv # gcd = 6 ./kvlang tutorial/07-leetcode/001_two_sum.kv # LeetCode python3 tutorial/test.py # all positive examples — CI verification diff --git a/README_CN.md b/README_CN.md index 328fe53a..54a7ca50 100644 --- a/README_CN.md +++ b/README_CN.md @@ -249,7 +249,7 @@ string.slice(s, 0, 2) -> p # "he" 02-func/ rwfunc, call, accumulator (2 files) 03-control/ if, while, for, guess (5 files) 03-debugger/ chain_array, debugger builtin (4 files) -04-algo/ fibonacci, gcd, collatz, … (13 files) +06-algo/ gcd, collatz, power, factorial, … (8 files) 06-lib/ lib block, nested, cross-lib, anon (11 files) 07-leetcode/ LeetCode solutions (90 files) error_cases/ type_error, index_error, zero_division, … (36 files) @@ -257,7 +257,7 @@ error_cases/ type_error, index_error, zero_division, … (36 files) ```bash ./kvlang tutorial/01-basics/hello.kv # hello kvlang -./kvlang tutorial/04-algo/fibonacci.kv # fib = 55 +./kvlang tutorial/06-algo/gcd.kv # gcd = 6 ./kvlang tutorial/07-leetcode/001_two_sum.kv # LeetCode python3 tutorial/test.py # 全部正例 — CI 验证 diff --git a/layout/tests/issue116.rs b/layout/tests/issue116.rs index d4fa2bcb..c5418c1c 100644 --- a/layout/tests/issue116.rs +++ b/layout/tests/issue116.rs @@ -559,7 +559,6 @@ fn tutorial_control_files_single_plane() { ("../tutorial/03-control/guess.kv", &["guess_number"][..]), ("../tutorial/03-control/classify.kv", &["classify"][..]), ("../tutorial/03-control/for.kv", &["test"][..]), - ("../tutorial/06-algo/prime_sieve.kv", &["prime_sieve"][..]), ] { let mut kv = fresh_kv(); let src = std::fs::read_to_string(file).unwrap(); diff --git a/tutorial/06-algo/fibonacci.kv b/tutorial/06-algo/fibonacci.kv deleted file mode 100644 index 08d64edd..00000000 --- a/tutorial/06-algo/fibonacci.kv +++ /dev/null @@ -1,31 +0,0 @@ -// fibonacci: 迭代斐波那契数列 -// 算法: while 循环 + 临时交换,计算 fib(10) = 55 -// 期望输出: -// fib = 55 -rwfunc fibonacci(n:int64) -> (result:int64) { - if (n <= 1) { - n -> result - } else { - a = 0 - b = 1 - 2 -> i - while (i <= n) { - c = a + b - a = b - c -> b - i = i + 1 - } - result = b - } -} - -rwfunc test() -> () { - - t0 = time·now() - fibonacci(10) -> ans - t1 = time·now() - println("fib =", ans) - delta = time·sub(t1, t0) - ns = time/duration·as_nanos(delta) - println("__bench_ns:", ns) -} diff --git a/tutorial/06-algo/prime_sieve.c b/tutorial/06-algo/prime_sieve.c deleted file mode 100644 index b955ac3d..00000000 --- a/tutorial/06-algo/prime_sieve.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include - -static void prime_sieve(int limit) { - printf("primes up to %d\n", limit); - int count = 0; - for (int n = 2; n <= limit; ++n) { - bool is_prime = true; - for (int divisor = 2; divisor < n; ++divisor) - if (n % divisor == 0) { is_prime = false; break; } - if (is_prime) { printf(" prime: %d\n", n); ++count; } - } - printf("total primes up to %d = %d\n", limit, count); -} - -int main(void) { - struct timespec t0, t1; - volatile int limit = 200; - clock_gettime(CLOCK_MONOTONIC, &t0); - prime_sieve(limit); - clock_gettime(CLOCK_MONOTONIC, &t1); - long us = (t1.tv_sec-t0.tv_sec)*1000000L + (t1.tv_nsec-t0.tv_nsec)/1000L; - printf("__bench_us: %ld\n", us); - return 0; -} diff --git a/tutorial/06-algo/prime_sieve.kv b/tutorial/06-algo/prime_sieve.kv deleted file mode 100644 index 6652733a..00000000 --- a/tutorial/06-algo/prime_sieve.kv +++ /dev/null @@ -1,44 +0,0 @@ -// prime_sieve: 试除法求质数(Rust The Book §3.5) -// 算法: 嵌套 while,找出 <=200 的质数 -// 期望输出: -// prime: 2 -// prime: 199 -// total primes up to 200 = 46 -rwfunc prime_sieve(limit:int64) -> () { - println("primes up to", limit) - count = 0 - 2 -> n - while (n <= limit) { - is_prime = true - d = 2 - while (d < n) { - n % d -> rem - divisible = rem == 0 - - if (divisible) { - is_prime = false - break - } else { - d = d + 1 - } - } - - if (is_prime) { - println(" prime:", n) - count = count + 1 - } - - n + 1 -> n - } - println("total primes up to", limit, "=", count) -} - -rwfunc test() -> () { - - t0 = time·now() - prime_sieve(200) - t1 = time·now() - delta = time·sub(t1, t0) - ns = time/duration·as_nanos(delta) - println("__bench_ns:", ns) -} diff --git a/tutorial/06-algo/prime_sieve.py b/tutorial/06-algo/prime_sieve.py deleted file mode 100644 index 042e95a2..00000000 --- a/tutorial/06-algo/prime_sieve.py +++ /dev/null @@ -1,20 +0,0 @@ -import time - -def prime_sieve(limit: int) -> None: - print("primes up to", limit) - count = 0 - for n in range(2, limit + 1): - is_prime = True - for divisor in range(2, n): - if n % divisor == 0: - is_prime = False - break - if is_prime: - print(" prime:", n) - count += 1 - print("total primes up to", limit, "=", count) - -t0 = time.perf_counter() -prime_sieve(200) -t1 = time.perf_counter() -print(f"__bench_us: {int((t1 - t0) * 1_000_000)}") diff --git a/tutorial/08-leetcode/204_count_primes.kv b/tutorial/08-leetcode/204_count_primes.kv deleted file mode 100644 index 96f4559f..00000000 --- a/tutorial/08-leetcode/204_count_primes.kv +++ /dev/null @@ -1,35 +0,0 @@ -// 204: Count Primes — 埃氏筛计数 n 以内质数 -// 来源: LeetCode #204 -// 期望输出: -// 4 -rwfunc count_primes(n:int64) -> () { - count = 0 - 2 -> i - while (i < n) { - is_p = true - d = 2 - while (d < i) { - i % d -> rem - div = rem == 0 - - if (div) { - is_p = false - i -> d - } else { - d = d + 1 - } - } - - if (is_p) { - count = count + 1 - } - - i + 1 -> i - } - println(count) -} - -rwfunc test() -> () { - - count_primes(10) -} diff --git a/tutorial/08-leetcode/509_fib.kv b/tutorial/08-leetcode/509_fib.kv deleted file mode 100644 index 44261525..00000000 --- a/tutorial/08-leetcode/509_fib.kv +++ /dev/null @@ -1,28 +0,0 @@ -// 509: Fibonacci Number — 迭代斐波那契 -// 来源: LeetCode #509 -// 期望输出: -// 55 -rwfunc fib(n:int64) -> () { - base = n <= 1 - base_m = n ≤ 1 - - if (base) { - println(n) - } else { - a = 0 - 1 -> b - i = 2 - while (i <= n) { - c = a + b - b -> a - b = c - i = i + 1 - } - println(c) - } -} - -rwfunc test() -> () { - - fib(10) -} diff --git a/tutorial/09-debugger/fib.kv b/tutorial/09-debugger/fib.kv deleted file mode 100644 index 1b8cd369..00000000 --- a/tutorial/09-debugger/fib.kv +++ /dev/null @@ -1,17 +0,0 @@ -rwfunc fib(n: int64) -> (r: int64) { - if (n <= 1) { 1 -> r; return } - if (n ≤ 1) { 1 -> r_m; return } - n - 1 -> a - n - 2 -> b - if(n>10){ - debugger() - } - fib(a) -> ra - fib(b) -> rb - ra + rb -> r -} - -rwfunc test() -> () { - fib(21) -> r - println(r) -} diff --git a/tutorial/README.md b/tutorial/README.md index 702b5026..d8a50613 100644 --- a/tutorial/README.md +++ b/tutorial/README.md @@ -15,7 +15,7 @@ Each numbered directory contains a standalone `main.kv` you can run immediately. | [05-if](05-if/) | Conditionals | `if/else`, boolean operators `&& \|\| !` | | [06-while](06-while/) | While Loops | `while`, `break`, `continue` | | [07-recursion](07-recursion/) | Recursion | multi-write params, tail-call optimization | -| [08-algo/](08-algo/) | Algorithms | fibonacci, fizzbuzz, gcd, collatz, … | +| [08-algo/](08-algo/) | Algorithms | fizzbuzz, gcd, collatz, power, … | ## Running @@ -26,7 +26,6 @@ kvlang tutorial/06-while/main.kv # ... # algo showcase — any file is self-contained -kvlang tutorial/08-algo/fibonacci.kv # fib = 55 kvlang tutorial/08-algo/fizzbuzz.kv # FizzBuzz 1-15 kvlang tutorial/08-algo/gcd.kv # gcd = 6 kvlang tutorial/08-algo/collatz.kv # steps = 111 @@ -36,7 +35,6 @@ kvlang tutorial/08-algo/collatz.kv # steps = 111 | File | Algorithm | Key concepts | |------|-----------|--------------| -| `fibonacci.kv` | Iterative Fibonacci | while, variable swap | | `factorial.kv` | Iterative Factorial | while accumulator | | `fizzbuzz.kv` | FizzBuzz 1–15 | modulo, nested if | | `gcd.kv` | GCD (Euclidean) | tail recursion | From a17dbcf4edf403e473b0eabe5b9e6cae3b321661 Mon Sep 17 00:00:00 2001 From: "peng.li24" <734991033@qq.com> Date: Tue, 8 Sep 2026 12:44:30 +0800 Subject: [PATCH 3/3] =?UTF-8?q?runtime:=20rwir=20=E6=B4=BE=E5=8F=91=20id?= =?UTF-8?q?=20=E5=8C=96=E6=8E=A8=E8=BF=9B=E2=80=94=E2=80=94notinmyrwircaps?= =?UTF-8?q?=20=E8=B7=AF=E7=94=B1=20+=20=E6=95=B0=E5=AD=97=20kind=20?= =?UTF-8?q?=E7=B2=BE=E7=A1=AE=E5=BD=92=E7=BA=A6=EF=BC=88#255=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 热路径去字符串匹配:未命中 myrwircaps 且前缀为 C native 数字 kind 时剥前缀归裸 op, 否则 notinmyrwircaps 路由到 def rwir / handoff。 - runtime-rs rwir/mod、main 适配;spec 05-runtime(07 拆 notinmyrwircaps,08/09 同步)。 Ref #255 --- runtime-rs/src/main.rs | 4 +- runtime-rs/src/rwir/mod.rs | 4 +- runtime/src/builtin.c | 10 ++- runtime/src/kvcpu.c | 80 +++++++++++++------ runtime/src/runtime_internal.h | 19 ++--- runtime/src/rwir.c | 2 +- runtime/src/rwirext.c | 8 +- ...47\350\241\214\346\250\241\345\236\213.kv" | 14 ++-- ...50\344\270\216\345\206\205\345\273\272.kv" | 2 +- ...6\345\206\205\345\273\272-\347\273\255.kv" | 8 +- .../06-rwirext\346\211\251\345\261\225.kv" | 8 +- .../07-notinmyrwircaps.kv" | 6 +- .../08-rwirext\346\211\251\345\261\225-c.kv" | 2 +- ...344\270\216\345\220\216\347\253\257abi.kv" | 4 +- 14 files changed, 103 insertions(+), 68 deletions(-) rename "stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/07-rwirext\346\211\251\345\261\225-b.kv" => "stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/07-notinmyrwircaps.kv" (92%) diff --git a/runtime-rs/src/main.rs b/runtime-rs/src/main.rs index 176a0fef..98a75e09 100644 --- a/runtime-rs/src/main.rs +++ b/runtime-rs/src/main.rs @@ -319,8 +319,8 @@ fn drive_vid(eng: &Engine, vid: &str) { // pc 可能属子 vthread(native vthread·run 冒泡上来):目标 vid 一律由 pc 导出,非固定主 vid。 let sub = c.split('/').nth(2).unwrap_or(vid); - // 外部扩展 rwir(如 numpy):handoff;native/控制帧/帧结束:写回 pc 让 runtime 继续。 - if !stop_op.is_empty() && rwir::is_others_rwir(&stop_op) { + // 停在本 myrwircaps 内的 op:handoff;native/控制帧/帧结束:写回 pc 让 runtime 继续。 + if !stop_op.is_empty() && rwir::in_myrwircaps(&stop_op) { if unsafe { kvlang_rwirextHandoff(kv, cs(sub).as_ptr(), cs(&c).as_ptr()) } != 0 { kvlang_rs::elog!("handoff {stop_op} 失败 @ {c}"); std::process::exit(1); diff --git a/runtime-rs/src/rwir/mod.rs b/runtime-rs/src/rwir/mod.rs index 87c971b6..7768bc06 100644 --- a/runtime-rs/src/rwir/mod.rs +++ b/runtime-rs/src/rwir/mod.rs @@ -226,8 +226,8 @@ pub fn is_inproc(op: &str) -> bool { ) } -/// 判「别人的 rwir」:opcode 是否已注册(进程内 map)。 -pub fn is_others_rwir(op: &str) -> bool { +/// op ∈ 本 runtime myrwircaps(已登记进程内 map);其取反即 notinmycaps。 +pub fn in_myrwircaps(op: &str) -> bool { rwirmap().contains_key(op) } diff --git a/runtime/src/builtin.c b/runtime/src/builtin.c index 9cd877ec..c804c7f5 100644 --- a/runtime/src/builtin.c +++ b/runtime/src/builtin.c @@ -521,8 +521,8 @@ static int kvlangBuiltinCastCharAscii(kvlangFrame_t *f) { return kvlangBuiltinCa /* ── 注册表 ───────────────────────────────────────────────────────── */ -/* 数字多类型运算融合为单条:派发前 strip_num_kind 剥掉 . 前缀, - * int64.add / float32.add … 全部归到同一条 add(union 语义),kvlangBuiltin* 按操作数 kind 归约。 */ +/* 精度前缀(int64·add / float32·add …)保留:CapIndex 两级查表——先按完整 opcode 命中特化, + * 未命中且前缀是 C native 数字 kind 时才剥前缀归到裸 op(如 add),kvlangBuiltin* 按操作数 kind 归约。 */ static const struct { const char *op; kvlangBuiltinFn fn; } myrwircaps[] = { {"add", kvlangBuiltinAdd}, {"+", kvlangBuiltinAdd}, {"sub", kvlangBuiltinSub}, {"-", kvlangBuiltinSub}, @@ -620,8 +620,10 @@ int kvlangBuiltinCapIndex(const char *opcode) { return -1; } -bool kvlangBuiltinIsNative(const char *opcode) { - return kvlangBuiltinCapIndex(opcode) >= 0; +/* notinmycaps:查 myrwircaps table。opcode 不在本 runtime 能力表内 → true + * (即须经 /lib/ 的 def rwir 路由给能兑现它的其它 runtime,或为用户 rwfunc)。 */ +bool notinmycaps(const char *opcode) { + return kvlangBuiltinCapIndex(opcode) < 0; } bool kvlangBuiltinNumOp(const char *opcode) { diff --git a/runtime/src/kvcpu.c b/runtime/src/kvcpu.c index c416e006..7b17aa5b 100644 --- a/runtime/src/kvcpu.c +++ b/runtime/src/kvcpu.c @@ -5,32 +5,71 @@ * 递归/多帧同函数共享同一条),故缓存永不失效。命中即跳过 code 槽读 + decode + 分类。 * runtime C 单线程驱动(全库无锁直改 kvspace),此缓存同样无锁。永不淘汰(≈代码大小上界)。 */ typedef struct rwir_cache_ent { - char *key; + char *funcdir; + int addr0; kvlangRwirInst_t *inst; struct rwir_cache_ent *next; } rwir_cache_ent_t; #define RWIR_CACHE_BUCKETS 4096 static rwir_cache_ent_t *g_rwir_cache[RWIR_CACHE_BUCKETS]; -static size_t rwir_hash(const char *s) { +/* 直接对 (funcdir, addr0) 做 FNV——不拼 "funcdir#addr0" 串(那要每步 malloc+格式化+free, + * 在 shm 后端 decode 本已近乎免费的深递归热路径上纯属净开销)。 */ +static size_t rwir_hash(const char *funcdir, int addr0) { size_t h = 1469598103934665603ULL; - for (; *s; s++) { h ^= (unsigned char)*s; h *= 1099511628211ULL; } + for (const char *s = funcdir; *s; s++) { h ^= (unsigned char)*s; h *= 1099511628211ULL; } + h ^= (size_t)(unsigned)addr0; h *= 1099511628211ULL; return h & (RWIR_CACHE_BUCKETS - 1); } -static kvlangRwirInst_t *rwir_cache_get(const char *key) { - for (rwir_cache_ent_t *e = g_rwir_cache[rwir_hash(key)]; e; e = e->next) - if (strcmp(e->key, key) == 0) return e->inst; +static kvlangRwirInst_t *rwir_cache_get(const char *funcdir, int addr0) { + for (rwir_cache_ent_t *e = g_rwir_cache[rwir_hash(funcdir, addr0)]; e; e = e->next) + if (e->addr0 == addr0 && strcmp(e->funcdir, funcdir) == 0) return e->inst; return NULL; } -static void rwir_cache_put(const char *key, kvlangRwirInst_t *inst) { - size_t b = rwir_hash(key); +static void rwir_cache_put(const char *funcdir, int addr0, kvlangRwirInst_t *inst) { + size_t b = rwir_hash(funcdir, addr0); rwir_cache_ent_t *e = malloc(sizeof *e); - e->key = strdup(key); + e->funcdir = strdup(funcdir); + e->addr0 = addr0; e->inst = inst; e->next = g_rwir_cache[b]; g_rwir_cache[b] = e; } +/* /lib 元信息 intern(P2-c):opcode → {是否 notinmyrwircaps(须经 def rwir 路由到其它 + * runtime)、读参 kindexpr 签名}。/lib 布局后冻结,同 decode 缓存同理永不失效。命中即免去 + * OPID_notinmyrwircaps 分支每步两次元信息往返(notinmyrwircaps + load_def_reads)与签名 kindexpr 重解析。 + * langtype 签名串在此按 opcode 驻留一次(IV-0:进程私有,绝不入 kvspace)。 */ +typedef struct opmeta_ent { + char *opcode; + int notinmyrwircaps; /* 1 = 不在本 runtime myrwircaps、须经 def rwir 路由;0 = 用户 rwfunc */ + char *def_sig; /* notinmyrwircaps 时的读参 kindexpr 签名(owned,可 NULL) */ + int def_nr; + struct opmeta_ent *next; +} opmeta_ent_t; +static opmeta_ent_t *g_opmeta_cache[RWIR_CACHE_BUCKETS]; + +static char *load_def_reads(kvlangKv_t *kv, const char *key, int *out_nr); + +static opmeta_ent_t *opmeta_get(kvlangKv_t *kv, const char *opcode) { + size_t b = rwir_hash(opcode, 0); + for (opmeta_ent_t *e = g_opmeta_cache[b]; e; e = e->next) + if (strcmp(e->opcode, opcode) == 0) return e; + opmeta_ent_t *e = malloc(sizeof *e); + e->opcode = strdup(opcode); + e->notinmyrwircaps = notinmyrwircaps(kv, opcode) ? 1 : 0; + e->def_sig = NULL; + e->def_nr = 0; + if (e->notinmyrwircaps) { + char *rk = kvlangKeytreeRwir(opcode); + e->def_sig = load_def_reads(kv, rk, &e->def_nr); + free(rk); + } + e->next = g_opmeta_cache[b]; + g_opmeta_cache[b] = e; + return e; +} + /* 读帧的 ‥lib 槽 → funcdir(/lib/pkg·fn),供缓存键用;无则 NULL(不缓存该指令)。 */ static char *read_seglib(kvlangKv_t *kv, const char *fr) { char *stk = kvlangKeytreeStack(fr); @@ -308,7 +347,7 @@ static char *handle_call(kvlangKv_t *kv, const char *pc, kvlangRwirInst_t *inst) kvlangKvGetOne(kv, sig_key.p, &sig); if (kvlangXvalueNone(&sig) || !kvlangXvalueKindIs(&sig, KVSPACE_KIND_RWFUNC)) { /* 按 xvalue 的 kind 精确区分缺 rwir 还是缺 rwfunc: - * 到这里说明 opcode 已被 isothersrwir 判否(/lib/ 非 rwir)。 */ + * 到这里说明 opcode 已被 notinmyrwircaps 判否(/lib/ 非 def rwir 路由头)。 */ char *rk = kvlangKeytreeRwir(fn); kvlangXvalue_t rv; kvlangXvalueZero(&rv); kvlangKvGetOne(kv, rk, &rv); @@ -623,8 +662,7 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode, char * kvlangRwirInst_t tmp; kvlangRwirInst_t *inst = NULL; bool tmp_owned = false; - kvlangStrbuf_t ck; kvlangStrbufInit(&ck); - if (cur_funcdir) { kvlangStrbufPrintf(&ck, "%s#%d", cur_funcdir, addr0); inst = rwir_cache_get(ck.p); } + if (cur_funcdir) inst = rwir_cache_get(cur_funcdir, addr0); if (!inst) { char *link_base = kvlangKeytreeStack(fr); @@ -632,7 +670,7 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode, char * if (kvlangRwirDecode(kv, link_base, cur, &tmp, err, sizeof err) != 0) { char msg[256]; snprintf(msg, sizeof msg, "decode: %s", err); kvlangVthreadSetError(kv, vtid, cur, msg); - free(link_base); kvlangStrbufFree(&ck); free(fr); + free(link_base); free(fr); rc = -1; break; } @@ -641,13 +679,12 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode, char * /* 转移所有权入缓存:冻结指令永不失效、永不 free */ kvlangRwirInst_t *persist = malloc(sizeof *persist); *persist = tmp; - rwir_cache_put(ck.p, persist); + rwir_cache_put(cur_funcdir, addr0, persist); inst = persist; } else { inst = &tmp; tmp_owned = true; } } - kvlangStrbufFree(&ck); kvlangLogDebug("[%s] PC=%s OP=%s R=%d W=%d", vtid, cur, inst->opcode ? inst->opcode : "(empty)", inst->nr, inst->nw); @@ -680,15 +717,10 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode, char * exec_err = handle_control(kv, vtid, cur, inst); } else if (inst->op_id == OPID_COPY) { exec_err = kvlangBuiltinExecuteCopy(kv, vtid, cur, inst); - } else if (isothersrwir(kv, inst->opcode)) { - char *rk = kvlangKeytreeRwir(inst->opcode); - int def_nr = 0; - char *def_sig = load_def_reads(kv, rk, &def_nr); - free(rk); - if (def_sig) { - exec_err = check_read_types(kv, vtid, cur, inst->opcode, def_sig, def_nr, inst->reads, inst->nr); - free(def_sig); - } + } else if (opmeta_get(kv, inst->opcode)->notinmyrwircaps) { + opmeta_ent_t *m = opmeta_get(kv, inst->opcode); + if (m->def_sig) + exec_err = check_read_types(kv, vtid, cur, inst->opcode, m->def_sig, m->def_nr, inst->reads, inst->nr); if (exec_err == 0 && mode == KVMODE_RETURN) { if (out_pc) *out_pc = strdup(cur); free(fr); if (tmp_owned) kvlangRwirInstFree(&tmp); diff --git a/runtime/src/runtime_internal.h b/runtime/src/runtime_internal.h index 1515e8d1..2f5850a4 100644 --- a/runtime/src/runtime_internal.h +++ b/runtime/src/runtime_internal.h @@ -218,7 +218,7 @@ bool kvlangKeytreeIsEntryPc(const char *pc); * ≥0 = native,直查 myrwircaps[op_id] * 负值 = 保留派发类(control / copy / 待定),语义见下 */ enum { - OPID_OTHER = -1, /* 未定:他人 rwir 或用户函数,执行期经 kvspace 查 /lib 才能区分 */ + OPID_notinmyrwircaps = -1, /* 不在本 runtime myrwircaps;执行期查 /lib:def rwir 路由头→路由,否则用户 rwfunc→调用 */ OPID_CALL = -2, OPID_RETURN = -3, OPID_GOTO = -4, @@ -226,14 +226,9 @@ enum { OPID_COPY = -6, }; -static inline bool op_is_control(const char *op) { - return strcmp(op, OP_CALL) == 0 || strcmp(op, OP_RETURN) == 0 || - strcmp(op, OP_BR) == 0 || strcmp(op, OP_GOTO) == 0; -} - int kvlangBuiltinCapIndex(const char *opcode); -/* decode 期分类:control/copy 先于 native,miss 落 OPID_OTHER(执行期再查 /lib)。 */ +/* decode 期分类:control/copy 先于 native,miss 落 OPID_notinmyrwircaps(执行期再查 /lib)。 */ static inline int kvlangOpClassify(const char *op) { if (strcmp(op, OP_CALL) == 0) return OPID_CALL; if (strcmp(op, OP_RETURN) == 0) return OPID_RETURN; @@ -241,7 +236,7 @@ static inline int kvlangOpClassify(const char *op) { if (strcmp(op, OP_BR) == 0) return OPID_BR; if (strcmp(op, OP_COPY) == 0) return OPID_COPY; int n = kvlangBuiltinCapIndex(op); - return n >= 0 ? n : OPID_OTHER; + return n >= 0 ? n : OPID_notinmyrwircaps; } typedef struct { char *name; kvlangXvalue_t val; } kvlangParam_t; @@ -260,8 +255,9 @@ void kvlangRwirInstFree(kvlangRwirInst_t *inst); /* 外部扩展 handoff:写共享队列 /lib//vids/=pc,阻塞 watch 该 key 直至变 None * (外部执行器认领、驱动、置 nextpc 后删除该条目 → 本端解除阻塞)。 */ int handoff_external_rwir(kvlangKv_t *kv, const char *vtid, const char *pc, kvlangRwirInst_t *inst); -/* opcode 是否他人 rwir:读 kvspace /lib/,kind=defrwir 即是(能力唯一事实源)。 */ -bool isothersrwir(kvlangKv_t *kv, const char *opcode); +/* notinmyrwircaps:opcode 是不在本 runtime myrwircaps 内、须经 def rwir 路由给能兑现它的 + * 其它 runtime 的 rwir。判据=读 kvspace /lib/ 存在 def rwir 路由头(能力唯一事实源)。 */ +bool notinmyrwircaps(kvlangKv_t *kv, const char *opcode); /* ── vthread ───────────────────────────────────────────────────────── */ @@ -276,7 +272,8 @@ void kvlangVthreadSetError(kvlangKv_t *kv, const char *vtid, const char *pc, con * 唯 vthread·run 的 return 模式用:驱动一个子 vthread 遇非本执行器 rwir 时,把其 pc 冒泡给驱动。 */ typedef struct { kvlangKv_t *kv; const char *vtid; const char *pc; kvlangRwirInst_t *inst; char **yield_pc; } kvlangFrame_t; -bool kvlangBuiltinIsNative(const char *opcode); +/* notinmycaps:查 myrwircaps table,opcode 不在本 runtime 能力表内 → true。 */ +bool notinmycaps(const char *opcode); bool kvlangBuiltinNumOp(const char *opcode); int kvlangBuiltinNative(kvlangFrame_t *f); /* dispatch + call,0 成功 */ int kvlangBuiltinExecuteCopy(kvlangKv_t *kv, const char *vtid, const char *pc, kvlangRwirInst_t *inst); diff --git a/runtime/src/rwir.c b/runtime/src/rwir.c index 894a0370..4f8beef7 100644 --- a/runtime/src/rwir.c +++ b/runtime/src/rwir.c @@ -54,7 +54,7 @@ int kvlangRwirDecode(kvlangKv_t *kv, const char *link_base, const char *pc, kvla free(nm); if (!kvlangXvalueNone(&v)) out->opcode = kvlangXvalueValueString(&v); kvlangXvalueFree(&v); - out->op_id = out->opcode ? kvlangOpClassify(out->opcode) : OPID_OTHER; + out->op_id = out->opcode ? kvlangOpClassify(out->opcode) : OPID_notinmyrwircaps; for (int i = 1; i <= MAX_PARAMS; i++) { kvlangStrbufPrintf(&key, "[%d,-%d]", addr0, i); diff --git a/runtime/src/rwirext.c b/runtime/src/rwirext.c index 8daa3d5c..32502f4e 100644 --- a/runtime/src/rwirext.c +++ b/runtime/src/rwirext.c @@ -4,9 +4,11 @@ /* 共享队列根:第一个 rwir 的 /lib//vids 绝对路径。 */ static char *g_first_vids = NULL; -/* kvspace 是能力的唯一事实源:/lib/ 存在且 kind=defrwir 即他人 rwir。 - * 派发在独立 kvlang 进程内发生,进程内注册表恒空,只有 kvspace 可信。 */ -bool isothersrwir(kvlangKv_t *k, const char *opcode) { +/* notinmyrwircaps:opcode 是一条不在本 runtime myrwircaps 内、须经 def rwir 路由给 + * 能兑现它的其它 runtime 的 rwir。判据是 /lib/ 存在 def rwir 路由头 + * (langtype=def rwir,storetype=index)。kvspace 是能力唯一事实源;本判定在独立 + * kvlang 进程内发生,进程内 myrwircaps 恒不含它,故只有 /lib 路由头可信。 */ +bool notinmyrwircaps(kvlangKv_t *k, const char *opcode) { if (opcode[0] == '/') return false; char *key = kvlangKeytreeRwir(opcode); diff --git "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/01-\346\211\247\350\241\214\346\250\241\345\236\213.kv" "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/01-\346\211\247\350\241\214\346\250\241\345\236\213.kv" index b2e4dbbb..c0aad673 100644 --- "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/01-\346\211\247\350\241\214\346\250\241\345\236\213.kv" +++ "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/01-\346\211\247\350\241\214\346\250\241\345\236\213.kv" @@ -29,15 +29,15 @@ runtime 对一个 vthread 的执行是如下循环(C 实现 `runtime/src/kvcpu ## 派发链 -每条指令按**固定优先级**派发,命中即止: +每条指令的归属互斥,decode 期一次固化为统一派发码 `op_id`(quickening),执行期据此纯整数跳表: -1. **控制指令**(`op_is_control`)——`call` / `return` / `br` / `goto`。 -2. **native builtin**(`kvlangBuiltinIsNative`)——静态注册表内的核心算子(枚举见 [[函数调用与内建]])。 -3. **`=` 拷贝**(`is_copy_op`)——值拷贝语义。 -4. **须经 def rwir 路由的 rwir**(`isothersrwir`)——`/lib/` 存在且 kind=`def rwir`(见 [[rwirext扩展]])。 -5. **否则视为用户函数调用**——opcode 移入 `reads[0]`,改写为 `call` 指令。 +1. **myrwircaps 内的核心算子**(`op_id ≥ 0`,直查静态能力表,枚举见 [[函数调用与内建]])——本 runtime 就地兑现。 +2. **控制指令**(`op_id ∈ {OPID_CALL/RETURN/BR/GOTO}`)——`call` / `return` / `br` / `goto`。 +3. **`=` 拷贝**(`op_id == OPID_COPY`)——值拷贝语义。 +4. 以上皆否(`op_id == OPID_notinmyrwircaps`,即 `notinmycaps`)时查 `/lib`:**`notinmyrwircaps`**——`/lib/` 存在 def rwir 路由头(kind=`def rwir`)→ 路由到能兑现它的其它 runtime(见 [[rwirext扩展]])。 +5. **否则视为用户 rwfunc 调用**——opcode 移入 `reads[0]`,改写为 `call` 指令。 -实现**必须**遵循此优先级:native 注册表先于 `/lib` 查表,故与 native 同名的 `/lib/` 不改变派发。 +`op_id` 由 decode 期分类固化,控制/拷贝/myrwircaps 成员全折入同一整数字段,热路径无 opcode 字符串匹配。myrwircaps 判定先于 `/lib` 查表,故与核心算子同名的 `/lib/` 不改变派发。 ## 调用即无返回值——输出走写参映射 diff --git "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/04-\345\207\275\346\225\260\350\260\203\347\224\250\344\270\216\345\206\205\345\273\272.kv" "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/04-\345\207\275\346\225\260\350\260\203\347\224\250\344\270\216\345\206\205\345\273\272.kv" index 1e7add33..907ab59e 100644 --- "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/04-\345\207\275\346\225\260\350\260\203\347\224\250\344\270\216\345\206\205\345\273\272.kv" +++ "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/04-\345\207\275\346\225\260\350\260\203\347\224\250\344\270\216\345\206\205\345\273\272.kv" @@ -26,7 +26,7 @@ lib kvlang/spec/runtime语义/函数调用与内建 { ## native builtin 判定 -`kvlangBuiltinIsNative(opcode)`(`runtime/src/builtin.c`)先剥数字类型前缀(`int64·add` / `float32·add` … 经 `strip_num_kind` 归并到同一 `add`,按操作数 kind 归约),再在**静态注册表**线性查表。命中即为 native。native 判定**先于** `/lib` 查表,故 native opcode 不会被当须经 def rwir 路由的 rwir 或用户函数。此静态注册表即**核心 runtime-c 的 myrwircaps**(见 [[rwirext扩展]])——核心能就地跑的 opcode 全在这张表里。 +查表函数 `kvlangBuiltinCapIndex(opcode)`(`runtime/src/builtin.c`)**两级查找**:先按完整 opcode 查(命中即专精实现,如 `fp8·add`、`time·add` 等成员算子),未命中且末段前缀是 **C 原生数值 langtype**(`int8..int64`/`uint8..uint64`/`float32`/`float64`)才剥前缀查裸算子(`int64·add → add`,通用实现,按操作数 kind 归约)。命中返回索引即在 myrwircaps 内;否则 `notinmycaps`。**保留精度前缀专精**:`int4`/`fp8`/`bf16` 等 C 表达不了的量化精度不剥离前缀,各走专精 fn 或路由。判定**先于** `/lib` 查表,故 myrwircaps 内 opcode 不会被当须经 def rwir 路由的 rwir 或用户函数。此静态注册表即**核心 runtime-c 的 myrwircaps**(见 [[rwirext扩展]])——核心能就地跑的 opcode 全在这张表里;`notinmycaps(opcode)` 是其否定谓词。 ## native builtin 全集(权威) diff --git "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/05-\345\207\275\346\225\260\350\260\203\347\224\250\344\270\216\345\206\205\345\273\272-\347\273\255.kv" "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/05-\345\207\275\346\225\260\350\260\203\347\224\250\344\270\216\345\206\205\345\273\272-\347\273\255.kv" index c1f96504..1c843535 100644 --- "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/05-\345\207\275\346\225\260\350\260\203\347\224\250\344\270\216\345\206\205\345\273\272-\347\273\255.kv" +++ "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/05-\345\207\275\346\225\260\350\260\203\347\224\250\344\270\216\345\206\205\345\273\272-\347\273\255.kv" @@ -20,14 +20,14 @@ lib kvlang/spec/runtime语义/函数调用与内建_续 { ## `print` / `println` / `cerr` / `input` 不是 native -**规范要点**:`print`、`println`、`cerr`、`input` **不在** native 注册表——它们是 **term runtime 的 rwir(经 def rwir 路由,`/lib/` kind=`def rwir`)**,经派发链第 4 级 `isothersrwir` 命中(见 [[rwirext扩展]])。term 扩展与中央 runtime 同进程,就地 `ResolveRead` + display 直写宿主 stdout/stderr。实现**不得**把这四个 opcode 当 native 处理。 +**规范要点**:`print`、`println`、`cerr`、`input` **不在** myrwircaps——它们是 **term runtime 的 rwir(经 def rwir 路由,`/lib/` kind=`def rwir`)**,经派发链第 4 级 `notinmyrwircaps` 命中(见 [[rwirext扩展]])。term 扩展与中央 runtime 同进程,就地 `ResolveRead` + display 直写宿主 stdout/stderr。实现**不得**把这四个 opcode 当 myrwircaps 内处理。 -## native vs 须经 def rwir 路由的 rwir 的判定边界 +## myrwircaps vs 须经 def rwir 路由的 rwir 的判定边界 一条非控制、非 `=` 的指令,其归属由两步判定: -1. `kvlangBuiltinIsNative(op)` → true:native(见 [[函数调用与内建]]、[[函数调用与内建]]、[[函数调用与内建_续]])。 -2. 否则 `isothersrwir(op)`:`op[0]=='/'` → false;否则读 `/lib/`,kind==`def rwir` → 须经 def rwir 路由的 rwir(`is_ext_rwir`)。 +1. `opcode ∈ myrwircaps`(`!notinmycaps(op)`,查静态能力表)→ 本 runtime 就地兑现(见 [[函数调用与内建]]、[[函数调用与内建_续]])。 +2. 否则 `notinmyrwircaps(op)`:`op[0]=='/'` → false;否则读 `/lib/`,kind==`def rwir` → 不在本 runtime myrwircaps、须经 def rwir 路由到能兑现它的其它 runtime。 3. 二者皆否 → 用户 rwfunc(改写为 `call`)。 layout **不预先**把 opcode 归为 native / user,归属判定全留给 runtime;同包内裸名调用须显式 `pkg·f()`(见 layout 语义卷)。数字类型的多态运算融合为单条 rwir(`int64·add` 与 `float32·add` 同归 `add`),由 native 实现按操作数 kind 在运行期归约(`kvlangBuiltinNumOp`)。 diff --git "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/06-rwirext\346\211\251\345\261\225.kv" "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/06-rwirext\346\211\251\345\261\225.kv" index d8910d0d..524a00da 100644 --- "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/06-rwirext\346\211\251\345\261\225.kv" +++ "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/06-rwirext\346\211\251\345\261\225.kv" @@ -13,8 +13,8 @@ kvlang 是**小核心 + 扩展主导**语言。中央 runtime 只实现执行核 **myrwircaps 是每个 runtime 都必须定义的一张 map/table**——登记本 runtime **能就地解释的全部 opcode**,映射 `opcode → 就地处理器`。它是 kvlang runtime 分层与派发的核心术语:一个 runtime「能跑什么」由且仅由它的 myrwircaps 界定。 - **每个 runtime 必须声明自己的 myrwircaps**。核心 runtime-c 的 myrwircaps 就是其 **native 静态注册表**(数组 + 线性查找,见 [[cruntime与后端abi]]),登记 native builtin(+ 控制流 `call`/`return`/`br`/`goto` + `=` 拷贝,见 [[函数调用与内建]])。 -- **每个扩展运行时各自定义一张 myrwircaps**,登记其自带的 rwir opcode。例:runtime-rs 为 `term`/`json`/`http`/`kvlanglayout`/`networld` 等(见 [[rwirext扩展_b]] 就地集合);未来 deepx-gpu-compute 为 tensor 融合算子。 -- **派发判据**:`opcode ∈ 本 runtime.myrwircaps` → 查表取处理器**就地执行**;否则该 rwir 须经 def rwir 路由,**移交**给以它为 myrwircaps 的另一扩展(跨进程 handoff/watch,或嵌入式交回宿主,见 [[rwirext扩展_b]]、[[cruntime与后端abi_续]])。实现里 `rwir::is_inproc(op)` 即「`op ∈ myrwircaps`」的查表判定。 +- **每个扩展运行时各自定义一张 myrwircaps**,登记其自带的 rwir opcode。例:runtime-rs 为 `term`/`json`/`http`/`kvlanglayout`/`networld` 等(见 [[notinmyrwircaps]] 就地集合);未来 deepx-gpu-compute 为 tensor 融合算子。 +- **派发判据**:`opcode ∈ 本 runtime.myrwircaps` → 查表取处理器**就地执行**;否则该 rwir 须经 def rwir 路由,**移交**给以它为 myrwircaps 的另一扩展(跨进程 handoff/watch,或嵌入式交回宿主,见 [[notinmyrwircaps]]、[[cruntime与后端abi_续]])。实现里 `rwir::is_inproc(op)` 即「`op ∈ myrwircaps`」的查表判定。 myrwircaps **只关乎执行位置**(哪张表登记了它、由谁就地跑),不改变 rwir 的动态语义——同一 rwir 无论落进哪个 runtime 的 myrwircaps,行为必须一致。 @@ -36,8 +36,8 @@ myrwircaps **只关乎执行位置**(哪张表登记了它、由谁就地跑 例:`/lib/json·to`(nr=1, nw=1)→ 主槽 body=[1,1,0],`[0,-1]=def kindexpr("char/utf8")`,`[0,1]=def kindexpr("[]char/utf8")`。 -- native builtin 的签名**不落入 kvspace**——在 C 注册表直接查表(见 [[函数调用与内建]])。 -- 扩展签名**落 `/lib/`**,中央 runtime 经 `isothersrwir` 识别:`opcode[0]=='/'` → false;否则读 `/lib/` 的 kind,等于 `def rwir` 即须经 def rwir 路由的 rwir。 +- 本 runtime myrwircaps 内 opcode 的签名**不落入 kvspace**——在 C 注册表直接查表(见 [[函数调用与内建]])。 +- 其它 runtime 的 rwir 签名**落 `/lib/`**,中央 runtime 经 `notinmyrwircaps` 识别:`opcode[0]=='/'` → false;否则读 `/lib/` 的 kind,等于 `def rwir` 即不在本 runtime myrwircaps、须经 def rwir 路由。 ### 全局标记与幂等 diff --git "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/07-rwirext\346\211\251\345\261\225-b.kv" "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/07-notinmyrwircaps.kv" similarity index 92% rename from "stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/07-rwirext\346\211\251\345\261\225-b.kv" rename to "stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/07-notinmyrwircaps.kv" index c41a1d1c..1f59b350 100644 --- "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/07-rwirext\346\211\251\345\261\225-b.kv" +++ "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/07-notinmyrwircaps.kv" @@ -1,5 +1,5 @@ // 欢迎加入kvspace世界 -lib kvlang/spec/runtime语义/rwirext扩展_b { +lib kvlang/spec/runtime语义/notinmyrwircaps { r####"# rwirext 扩展运行时(handoff 与就地) ## handoff 协议(跨进程扩展) @@ -12,7 +12,7 @@ lib kvlang/spec/runtime语义/rwirext扩展_b { 第一个 rwir 的 `vids` 是真实 strkeymap;后续同 opcode 的 `vids` 是 `Ptr` 指向第一个(共享同一队列)。时序: -1. 中央 runtime `isothersrwir` 命中 → `handoff_external_rwir`:`Set /lib//vids/=pc`。 +1. 中央 runtime `notinmyrwircaps` 命中 → `handoff_external_rwir`:`Set /lib//vids/=pc`。 2. 扩展发现队列中的 vtid,`RunSeq(pc)`:从 PC 起逐条解码,只要 `opcode ∈ 本扩展.myrwircaps` 就执行,遇第一条不在 myrwircaps 内的指令即停(**顺序执行,非并行 batch**);写回最终 PC,删 `vids` 项。 3. 中央 runtime `Watch` 直到 vtid 从队列消失(30s 超时),继续。 @@ -44,5 +44,5 @@ networld networld/proc·exec - `NextPc(pc)`:纯函数,求后继 PC。 **规范要点**:需要整块字节(如 `[]uint8`)时**必须**走 `ResolveReadPath` + TLV body,**不得**用 `ResolveRead`(后者对数组只返首元素)。 - "#### -> /lib/kvlang/spec/runtime语义/rwirext扩展_b + "#### -> /lib/kvlang/spec/runtime语义/notinmyrwircaps } diff --git "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/08-rwirext\346\211\251\345\261\225-c.kv" "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/08-rwirext\346\211\251\345\261\225-c.kv" index 65d93091..b11d3ab9 100644 --- "a/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/08-rwirext\346\211\251\345\261\225-c.kv" +++ "b/stdlib/kvlang/spec/05-runtime\350\257\255\344\271\211/08-rwirext\346\211\251\345\261\225-c.kv" @@ -11,7 +11,7 @@ lib kvlang/spec/runtime语义/rwirext扩展_c { 扩展回答的唯一问题是「**算什么、怎么算**」;它**不回答**「值长什么样、指令怎么解码、类型怎么校验」——这些是 runtime-c 的值语义(见 [[cruntime与后端abi]])。扩展只有三个合法动作: 1. **拿 PC**:经 handoff / 驱动循环取当前 PC,跑己方 rwir,`NextPc` 求后继。 -2. **解析参数**:**只经** `kvlang_rwirext*`(见 [[rwirext扩展_b]])。 +2. **解析参数**:**只经** `kvlang_rwirext*`(见 [[notinmyrwircaps]])。 3. **读写 kvspace**:**只经** `kvspace*` 正典 ABI(`Get` 借用读、`WriteInPlace`/`WriteNewPlace` 写、`TlvEncode`/`DecodeHead` 编解码)。**绝不自造 kindexpr 构造器、绝不手写 TLV/head。** 唯一保留的例外是 json 反序列化里的 kindexpr **串解析器**:kvspace 只导出编码器、不导出串解析器,而「把外部文本按类型/形状分发写回子树」是扩展**自身的反序列化职责**,故留在扩展侧,且只读 head、不造 head。这条例外恰印证边界:**能调用 kvspace 的一律调用;kvspace 未提供且属扩展自身语义的才自理。** 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 393b56ec..d9d54f14 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" @@ -26,7 +26,7 @@ lib kvlang/spec/runtime语义/cruntime与后端abi { - `kvlang_runtime.h`:核心执行器(`kvlangRuntimeConnect`/`Disconnect`/`Bootstrap`/`ExecuteVthread`/`KvspaceHandle` …)。 - `kvlang_rwirext.h`:扩展 runtime 语义,**只暴露 kvspace 不提供的部分**。现有 9 个符号:`Register`、`Handoff`、`NextPc`、`Params`、`ResolveRead`、`ResolveReadPath`、`ResolveWrite`、`KindexprValid`、`KindexprMatch`。KV 存取(connect/get/write/del/list/tlv)**不在此**——扩展宿主自连 kvspace ABI,把句柄(`void *`)传进带句柄的 rwirext 函数。 -内部模块:`xvalue.c`(TLV 编解码薄封装)、`kindexpr.c`、`kv.c`(kvspace ABI 封装)、`keytree.c`(路径构造)、`rwir.c`(PC 解析 + Decode)、`vthread.c`、`builtin*.c`(native 算子 + 静态注册表)、`kvcpu.c`(Execute 循环)、`runtime.c`(ABI 层)、`rwirext.c`(扩展 ABI,含 `isothersrwir`)。native 注册表为**静态数组 + 线性查找**。 +内部模块:`xvalue.c`(TLV 编解码薄封装)、`kindexpr.c`、`kv.c`(kvspace ABI 封装)、`keytree.c`(路径构造)、`rwir.c`(PC 解析 + Decode)、`vthread.c`、`builtin*.c`(native 算子 + 静态注册表)、`kvcpu.c`(Execute 循环)、`runtime.c`(ABI 层)、`rwirext.c`(扩展 ABI,含 `notinmyrwircaps`)。myrwircaps 为**静态数组 + 线性查找**。 ## 统一 `kvspace*` C ABI(去特化) @@ -49,6 +49,8 @@ kvspaceNewPtr / NewChar / NewBool / NewInt64 / NewFloat64 - **写**不经「先 encode 整条 TLV 再交后端」:向后端要一个可写 body 偏移指针再直接写字节——`kvspaceWriteInPlace`(key 已存在且 body 尺寸不变,原 box 就地改)与 `kvspaceWriteNewPlace`(新建 / 换 kind / 换尺寸,分配新 box 并写 head)两条原语,各自唯一、无中转 buffer。 - **前缀枚举**不一次性返回整段名单缓冲:`kvspaceListLen` 只返子项计数,`kvspaceListAt(idx)` 借用回收缓冲逐项取名——遍历即「先 ListLen 定计数、再逐 idx ListAt」。 +**native 读参:标量按值、整块借用**(normative,P2-d)——runtime-c native 算子(标量数值/逻辑/cast + `xv·*`/`array·*`/`string·*`)经 `ResolveReadValue` 取参,两条路径互斥:内联字面量(冻结于 code 槽)按值拷入(标量,纳秒级,无 KV 往返);变量/KV 常驻值经 `GetMember` 一次取出后**移交所有权**(`*out = pv`,非二次拷贝,后端物化只发生在 `Get` 内部)。**整块字节零拷贝不在 native 侧另设机制**——它就是 [[notinmyrwircaps]] 的 `ResolveReadPath` + `kvspaceGet` body 指针那一条路径,由持有大 tensor 的扩展(numpy/op-gpu)承担;native 算子处理的是标量与中等 value,其拷贝相对每步 KV 往返可忽略(fib n=10:redis 1.5s / fs 320ms vs C 586ns,墙钟由 KV I/O 主导约六个数量级),故不为其增设借用管线。 + **后端由链接决定**:构建期经环境变量选择链接哪个 kvspace 库(`kvspace-c` 或 `kvspace_durable`),两者导出同一 ABI;runtime 的句柄结构只保留 `void *h`,代码零后端分支。 "#### -> /lib/kvlang/spec/runtime语义/cruntime与后端abi }