diff --git a/benchmark/results/results-v0.2.9-20260908T093654Z.csv b/benchmark/results/results-v0.2.9-20260908T093654Z.csv new file mode 100644 index 00000000..56bab11f --- /dev/null +++ b/benchmark/results/results-v0.2.9-20260908T093654Z.csv @@ -0,0 +1,31 @@ +timestamp,version,commit,cpu,case,input,samples,kvlang_shm_ns,kvlang_fs_ns,kvlang_redis_ns,python_ns,rust_ns,c_ns,python_ver,rust_ver,c_ver,native_opt,valid +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,binary_search,N=16,3,32527855,194479758,820083899,14404,731,462,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,binary_search,N=32,3,67842842,448628414,1904594452,24220,1330,1055,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,binary_search,N=64,3,141902140,1038834649,4355142015,46095,2954,2168,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,binary_trees,depth=4,3,9565444,206757546,834398238,14380,2546,5535,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,binary_trees,depth=5,3,18134413,408716568,1667449155,22793,3216,6038,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,binary_trees,depth=6,3,36247967,810710530,3358673221,40443,4441,8622,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,fib,n=8,3,59489023,122767933,582864913,10374,306,348,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,fib,n=9,3,96253452,197403346,949500665,12220,416,453,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,fib,n=10,3,157592829,320023066,1553405050,15468,537,554,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,hash_table,N=50,3,8425547,189732598,775578044,33985,5357,267,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,hash_table,N=100,3,16604274,373096888,1532670634,60463,8405,463,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,hash_table,N=200,3,34041596,723107692,3029700511,112914,15199,843,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,iops,N=500,3,18675374,458421668,1851640667,23963,475,267,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,iops,N=1000,3,36749731,918106238,3693571868,45746,806,450,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,iops,N=2000,3,71687983,1837705910,7387173219,88119,1454,777,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,k_nucleotide,rep=3,3,19641302,439098994,1774948762,38901,3208,202,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,k_nucleotide,rep=5,3,35414984,731873732,2961697444,63602,4971,300,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,k_nucleotide,rep=8,3,64129390,1165288854,4770162760,98413,7445,401,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,matmul,N=4,3,7156845,182375906,756890850,21138,325,236,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,matmul,N=6,3,21637412,563741306,2365392919,52433,552,354,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,matmul,N=8,3,49384775,1289307606,5382615085,114755,803,574,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,nqueens,N=4,3,34671461,100765217,427896048,13221,312,273,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,nqueens,N=5,3,111935732,303578241,1327765224,22830,592,510,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,nqueens,N=6,3,320738560,890298991,3846554944,50634,1503,1540,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,prime_sieve,N=50,3,24824540,585206026,2423604293,41173,14932,17203,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,prime_sieve,N=75,3,47502938,1177008392,4907926621,62875,19005,23702,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,prime_sieve,N=100,3,69377076,1741897861,7322019745,81926,21732,24523,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,quicksort,"N=32,seed=1",3,16416814,408360181,1683833904,18659,1113,1058,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,quicksort,"N=64,seed=1",3,36706055,951249540,3881924687,33686,2327,2218,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True +2026-09-08T09:36:54Z,v0.2.9-10-g932dae3,932dae3,Intel(R) Xeon(R) Platinum 8336C CPU @ 2.30GHz,quicksort,"N=128,seed=1",3,79435342,2057189243,8473508708,65678,5080,4638,3.12.7,1.97.1,13.3.0,gcc -O1 / rustc opt-level=1 / cpython,True diff --git a/runtime/src/builtin.c b/runtime/src/builtin.c index c804c7f5..b42df005 100644 --- a/runtime/src/builtin.c +++ b/runtime/src/builtin.c @@ -6,66 +6,57 @@ typedef int (*kvlangBuiltinFn)(kvlangFrame_t *f); -/* ── 类型 helper(对齐 Go isIntKind 含 uint)────────────────────── */ - -static bool is_int_kind(const char *k) { return kvlangXvalueIsIntKind(k) || kvlangXvalueIsUintKind(k); } -static bool is_float_kind(const char *k) { return kvlangXvalueIsFloatKind(k); } -static bool is_unsigned_kind(const char *k) { return kvlangXvalueIsUintKind(k); } -static bool is_numeric(const kvlangXvalue_t *v) { return kvlangXvalueIsNumKind(kvlangXvalueKind(v)); } - -static int int_width(const char *k) { - if (strcmp(k, KVSPACE_KIND_INT8) == 0 || strcmp(k, KVSPACE_KIND_UINT8) == 0) return 8; - if (strcmp(k, KVSPACE_KIND_INT16) == 0 || strcmp(k, KVSPACE_KIND_UINT16) == 0) return 16; - if (strcmp(k, KVSPACE_KIND_INT32) == 0 || strcmp(k, KVSPACE_KIND_UINT32) == 0) return 32; - if (strcmp(k, KVSPACE_KIND_INT64) == 0 || strcmp(k, KVSPACE_KIND_UINT64) == 0) return 64; - return 0; -} - -static const char *wider_int_kind(const char *a, const char *b) { - int aw = int_width(a), bw = int_width(b); - bool au = is_unsigned_kind(a), bu = is_unsigned_kind(b); - if (au && bu) return aw >= bw ? a : b; - if (!au && !bu) return aw >= bw ? a : b; +/* ── 类型 helper:全经 langtype id + 标量 0copy 视图,热路径零 strcmp、每值只 decode 一次 ── */ + +static const kvlangScalar_t SCALAR_NONE = { KVLANG_LT_NONE, NULL, 0 }; + +/* 两操作数结果整型 id(对齐旧 wider_int_kind:同号取宽者,异号升一档有符号)。 */ +static int wider_int_id(int a, int b) { + int aw = kvlangLtIntWidth(a), bw = kvlangLtIntWidth(b); + bool au = kvlangLtIsUint(a), bu = kvlangLtIsUint(b); + if (au == bu) { + int w = aw >= bw ? aw : bw; + int off = w == 8 ? 0 : w == 16 ? 1 : w == 32 ? 2 : 3; + return (au ? KVLANG_LT_UINT8 : KVLANG_LT_INT8) + off; + } int w = aw > bw ? aw : bw; - switch (w) { - case 8: return KVSPACE_KIND_INT16; - case 16: return KVSPACE_KIND_INT32; - case 32: return KVSPACE_KIND_INT64; - default: return KVSPACE_KIND_INT64; + return w <= 8 ? KVLANG_LT_INT16 : w == 16 ? KVLANG_LT_INT32 : KVLANG_LT_INT64; +} + +static int wider_float_id(int a, int b) { + if (a == KVLANG_LT_FLOAT64 || b == KVLANG_LT_FLOAT64) return KVLANG_LT_FLOAT64; + if (a == KVLANG_LT_FLOAT32 || b == KVLANG_LT_FLOAT32) return KVLANG_LT_FLOAT32; + return KVLANG_LT_FLOAT64; +} + +static void narrow_int(int a, int b, int64_t v, kvlangXvalue_t *out) { + int k = wider_int_id(a, b); + const char *kind = kvlangLangTypeKind(k); + switch (k) { + case KVLANG_LT_INT8: { int8_t x = (int8_t)v; kvlangXvalueNewTlv(out, kind, (uint8_t *)&x, 1, 1); return; } + case KVLANG_LT_INT16: { int16_t x = (int16_t)v; uint8_t r[2] = { x & 0xFF, (x >> 8) & 0xFF }; kvlangXvalueNewTlv(out, kind, r, 2, 1); return; } + case KVLANG_LT_INT32: { int32_t x = (int32_t)v; uint8_t r[4]; memcpy(r, &x, 4); kvlangXvalueNewTlv(out, kind, r, 4, 1); return; } + case KVLANG_LT_UINT8: { uint8_t x = (uint8_t)v; kvlangXvalueNewTlv(out, kind, &x, 1, 1); return; } + case KVLANG_LT_UINT16: { uint16_t x = (uint16_t)v; uint8_t r[2] = { x & 0xFF, (x >> 8) & 0xFF }; kvlangXvalueNewTlv(out, kind, r, 2, 1); return; } + case KVLANG_LT_UINT32: { uint32_t x = (uint32_t)v; uint8_t r[4]; memcpy(r, &x, 4); kvlangXvalueNewTlv(out, kind, r, 4, 1); return; } + case KVLANG_LT_UINT64: { uint64_t x = (uint64_t)v; uint8_t r[8]; memcpy(r, &x, 8); kvlangXvalueNewTlv(out, kind, r, 8, 1); return; } + default: kvlangXvalueNewInt64(out, v); return; /* INT64 */ } } -static const char *wider_float_kind(const char *a, const char *b) { - if (strcmp(a, KVSPACE_KIND_FLOAT64) == 0 || strcmp(b, KVSPACE_KIND_FLOAT64) == 0) return KVSPACE_KIND_FLOAT64; - if (strcmp(a, KVSPACE_KIND_FLOAT32) == 0 || strcmp(b, KVSPACE_KIND_FLOAT32) == 0) return KVSPACE_KIND_FLOAT32; - return KVSPACE_KIND_FLOAT64; -} - -static void narrow_int(const char *a, const char *b, int64_t v, kvlangXvalue_t *out) { - const char *k = wider_int_kind(a, b); - if (strcmp(k, KVSPACE_KIND_INT8) == 0) { int8_t x = (int8_t)v; kvlangXvalueNewTlv(out, KVSPACE_KIND_INT8, (uint8_t *)&x, 1, 1); return; } - if (strcmp(k, KVSPACE_KIND_INT16) == 0) { int16_t x = (int16_t)v; uint8_t r[2] = { x & 0xFF, (x >> 8) & 0xFF }; kvlangXvalueNewTlv(out, KVSPACE_KIND_INT16, r, 2, 1); return; } - if (strcmp(k, KVSPACE_KIND_INT32) == 0) { int32_t x = (int32_t)v; uint8_t r[4]; memcpy(r, &x, 4); kvlangXvalueNewTlv(out, KVSPACE_KIND_INT32, r, 4, 1); return; } - if (strcmp(k, KVSPACE_KIND_UINT8) == 0) { uint8_t x = (uint8_t)v; kvlangXvalueNewTlv(out, KVSPACE_KIND_UINT8, &x, 1, 1); return; } - if (strcmp(k, KVSPACE_KIND_UINT16) == 0) { uint16_t x = (uint16_t)v; uint8_t r[2] = { x & 0xFF, (x >> 8) & 0xFF }; kvlangXvalueNewTlv(out, KVSPACE_KIND_UINT16, r, 2, 1); return; } - if (strcmp(k, KVSPACE_KIND_UINT32) == 0) { uint32_t x = (uint32_t)v; uint8_t r[4]; memcpy(r, &x, 4); kvlangXvalueNewTlv(out, KVSPACE_KIND_UINT32, r, 4, 1); return; } - if (strcmp(k, KVSPACE_KIND_UINT64) == 0) { uint64_t x = (uint64_t)v; uint8_t r[8]; memcpy(r, &x, 8); kvlangXvalueNewTlv(out, KVSPACE_KIND_UINT64, r, 8, 1); return; } - kvlangXvalueNewInt64(out, v); -} - -static void narrow_float(const char *a, const char *b, double v, kvlangXvalue_t *out) { - if (strcmp(wider_float_kind(a, b), KVSPACE_KIND_FLOAT32) == 0) { +static void narrow_float(int a, int b, double v, kvlangXvalue_t *out) { + if (wider_float_id(a, b) == KVLANG_LT_FLOAT32) { float f = (float)v; uint8_t r[4]; memcpy(r, &f, 4); kvlangXvalueNewTlv(out, KVSPACE_KIND_FLOAT32, r, 4, 1); } else kvlangXvalueNewFloat64(out, v); } -static int cmp_int(const kvlangXvalue_t *a, const kvlangXvalue_t *b) { - bool au = is_unsigned_kind(kvlangXvalueKind(a)), bu = is_unsigned_kind(kvlangXvalueKind(b)); - if (!au && !bu) { int64_t ai = kvlangXvalueAsInt64(a), bi = kvlangXvalueAsInt64(b); return ai < bi ? -1 : ai > bi ? 1 : 0; } - if (au && bu) { uint64_t x = kvlangXvalueAsUint64(a), y = kvlangXvalueAsUint64(b); return x < y ? -1 : x > y ? 1 : 0; } - if (au && !bu) { int64_t bi = kvlangXvalueAsInt64(b); if (bi < 0) return 1; uint64_t x = kvlangXvalueAsUint64(a); return x < (uint64_t)bi ? -1 : x > (uint64_t)bi ? 1 : 0; } - int64_t ai = kvlangXvalueAsInt64(a); if (ai < 0) return -1; uint64_t y = kvlangXvalueAsUint64(b); +static int cmp_int(kvlangScalar_t a, kvlangScalar_t b) { + bool au = kvlangLtIsUint(a.id), bu = kvlangLtIsUint(b.id); + if (!au && !bu) { int64_t ai = kvlangScalarI64(a), bi = kvlangScalarI64(b); return ai < bi ? -1 : ai > bi ? 1 : 0; } + if (au && bu) { uint64_t x = kvlangScalarU64(a), y = kvlangScalarU64(b); return x < y ? -1 : x > y ? 1 : 0; } + if (au && !bu) { int64_t bi = kvlangScalarI64(b); if (bi < 0) return 1; uint64_t x = kvlangScalarU64(a); return x < (uint64_t)bi ? -1 : x > (uint64_t)bi ? 1 : 0; } + int64_t ai = kvlangScalarI64(a); if (ai < 0) return -1; uint64_t y = kvlangScalarU64(b); return (uint64_t)ai < y ? -1 : (uint64_t)ai > y ? 1 : 0; } @@ -76,9 +67,9 @@ void kvlangBuiltinResolveReadValue(kvlangKv_t *kv, const char *frame_root, const const kvlangXvalue_t *val, kvlangXvalue_t *out) { kvlangXvalueZero(out); if (val && !kvlangXvalueNone(val) && !kvlangXvalueKindIs(val, KVSPACE_KIND_RWIR) && !kvlangXvalueKindIs(val, KVSPACE_KIND_RWFUNC)) { - out->data = malloc(val->len); - memcpy(out->data, val->data, val->len); + out->data = val->data; /* 借指令内冻结字面量(生命周期同 decode 缓存,永不 flush/free) */ out->len = val->len; + out->borrowed = 1; return; } if (!name || !name[0]) return; @@ -103,6 +94,17 @@ void kvlangBuiltinResolveReadValue(kvlangKv_t *kv, const char *frame_root, const kvlangXvalueFree(&pv); free(stk); } +/* 读参 → 其最终存储键(malloc):字面量(指令内冻结的具体值,无后端槽)返 NULL; + * 变量则复用 ResolveWriteSlot——读侧最终槽键与写侧同一路径(普通成员=stk+name, + * ptr 追链到最终目标),供 xv 系列对 key 直发 GetHead/GetPart/SetPart 做分片读写。 */ +char *kvlangBuiltinResolveReadKey(kvlangKv_t *kv, const char *frame_root, const char *name, + const kvlangXvalue_t *val) { + if (val && !kvlangXvalueNone(val) && !kvlangXvalueKindIs(val, KVSPACE_KIND_RWIR) && !kvlangXvalueKindIs(val, KVSPACE_KIND_RWFUNC)) + return NULL; + if (!name || !name[0]) return NULL; + return kvlangBuiltinResolveWriteSlot(kv, frame_root, name); +} + char *kvlangBuiltinResolveWriteSlot(kvlangKv_t *kv, const char *frame_root, const char *name) { if (name[0] == '/') return strdup(name); char *stk = kvlangKeytreeStack(frame_root); @@ -252,20 +254,18 @@ int kvlangBuiltinSetErr(kvlangFrame_t *f, const char *fmt, ...) { static int kvlangBuiltinAdd(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; int rc; - if (n == 2 && kvlangXvalueIsCharKind(kvlangXvalueKind(&in[0])) && kvlangXvalueIsCharKind(kvlangXvalueKind(&in[1]))) { + if (n == 2 && kvlangLtIsChar(a.id) && kvlangLtIsChar(b.id)) { kvlangXvalue_t r; if (kvlangBuiltinCharConcat(&in[0], &in[1], &r)) { rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); } else rc = kvlangBuiltinSetErr(f, "TypeError: cannot concat %s with %s; convert encoding explicitly (char/utf8|char/utf32|char/ascii)", kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1])); - } else if (n >= 2 && is_numeric(&in[0]) && is_numeric(&in[1])) { - if (is_int_kind(kvlangXvalueKind(&in[0])) && is_int_kind(kvlangXvalueKind(&in[1]))) { - kvlangXvalue_t r; narrow_int(kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1]), kvlangXvalueAsInt64(&in[0]) + kvlangXvalueAsInt64(&in[1]), &r); - rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); - } else { - kvlangXvalue_t r; narrow_float(kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1]), kvlangXvalueAsFloat64(&in[0]) + kvlangXvalueAsFloat64(&in[1]), &r); - rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); - } + } else if (n >= 2 && kvlangLtIsNum(a.id) && kvlangLtIsNum(b.id)) { + kvlangXvalue_t r; + if (kvlangLtIsInt(a.id) && kvlangLtIsInt(b.id)) narrow_int(a.id, b.id, kvlangScalarI64(a) + kvlangScalarI64(b), &r); + else narrow_float(a.id, b.id, kvlangScalarF64(a) + kvlangScalarF64(b), &r); + rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); } else rc = kvlangBuiltinSetErr(f, "TypeError: expected numeric, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); kvlangBuiltinFreeInputs(in, n); return rc; @@ -273,15 +273,16 @@ static int kvlangBuiltinAdd(kvlangFrame_t *f) { static int kvlangBuiltinSub(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; int rc; if (n == 1) { - kvlangXvalue_t r; kvlangXvalueNewInt64(&r, -kvlangXvalueAsInt64(&in[0])); + kvlangXvalue_t r; kvlangXvalueNewInt64(&r, -kvlangScalarI64(a)); rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); - } else if (n >= 2 && is_int_kind(kvlangXvalueKind(&in[0])) && is_int_kind(kvlangXvalueKind(&in[1]))) { - kvlangXvalue_t r; narrow_int(kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1]), kvlangXvalueAsInt64(&in[0]) - kvlangXvalueAsInt64(&in[1]), &r); + } else if (n >= 2 && kvlangLtIsInt(a.id) && kvlangLtIsInt(b.id)) { + kvlangXvalue_t r; narrow_int(a.id, b.id, kvlangScalarI64(a) - kvlangScalarI64(b), &r); rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); - } else if (n >= 2 && is_numeric(&in[0]) && is_numeric(&in[1])) { - kvlangXvalue_t r; narrow_float(kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1]), kvlangXvalueAsFloat64(&in[0]) - kvlangXvalueAsFloat64(&in[1]), &r); + } else if (n >= 2 && kvlangLtIsNum(a.id) && kvlangLtIsNum(b.id)) { + kvlangXvalue_t r; narrow_float(a.id, b.id, kvlangScalarF64(a) - kvlangScalarF64(b), &r); rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); } else rc = kvlangBuiltinSetErr(f, "TypeError: expected numeric, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); kvlangBuiltinFreeInputs(in, n); @@ -290,12 +291,13 @@ static int kvlangBuiltinSub(kvlangFrame_t *f) { static int kvlangBuiltinMul(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; int rc; - if (n >= 2 && is_int_kind(kvlangXvalueKind(&in[0])) && is_int_kind(kvlangXvalueKind(&in[1]))) { - kvlangXvalue_t r; narrow_int(kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1]), kvlangXvalueAsInt64(&in[0]) * kvlangXvalueAsInt64(&in[1]), &r); + if (n >= 2 && kvlangLtIsInt(a.id) && kvlangLtIsInt(b.id)) { + kvlangXvalue_t r; narrow_int(a.id, b.id, kvlangScalarI64(a) * kvlangScalarI64(b), &r); rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); - } else if (n >= 2 && is_numeric(&in[0]) && is_numeric(&in[1])) { - kvlangXvalue_t r; narrow_float(kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1]), kvlangXvalueAsFloat64(&in[0]) * kvlangXvalueAsFloat64(&in[1]), &r); + } else if (n >= 2 && kvlangLtIsNum(a.id) && kvlangLtIsNum(b.id)) { + kvlangXvalue_t r; narrow_float(a.id, b.id, kvlangScalarF64(a) * kvlangScalarF64(b), &r); rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); } else rc = kvlangBuiltinSetErr(f, "TypeError: expected numeric, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); kvlangBuiltinFreeInputs(in, n); @@ -304,14 +306,15 @@ static int kvlangBuiltinMul(kvlangFrame_t *f) { static int kvlangBuiltinDiv(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; int rc; if (n < 2) { rc = kvlangBuiltinSetErr(f, "TypeError: binary op requires 2 inputs, got %d", n); kvlangBuiltinFreeInputs(in, n); return rc; } - if (kvlangXvalueAsFloat64(&in[1]) == 0) { rc = kvlangBuiltinSetErr(f, "ZeroDivisionError: division by zero"); kvlangBuiltinFreeInputs(in, n); return rc; } - if (is_int_kind(kvlangXvalueKind(&in[0])) && is_int_kind(kvlangXvalueKind(&in[1]))) { - kvlangXvalue_t r; narrow_int(kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1]), kvlangXvalueAsInt64(&in[0]) / kvlangXvalueAsInt64(&in[1]), &r); + if (kvlangScalarF64(b) == 0) { rc = kvlangBuiltinSetErr(f, "ZeroDivisionError: division by zero"); kvlangBuiltinFreeInputs(in, n); return rc; } + if (kvlangLtIsInt(a.id) && kvlangLtIsInt(b.id)) { + kvlangXvalue_t r; narrow_int(a.id, b.id, kvlangScalarI64(a) / kvlangScalarI64(b), &r); rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); } else { - kvlangXvalue_t r; narrow_float(kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1]), kvlangXvalueAsFloat64(&in[0]) / kvlangXvalueAsFloat64(&in[1]), &r); + kvlangXvalue_t r; narrow_float(a.id, b.id, kvlangScalarF64(a) / kvlangScalarF64(b), &r); rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); } kvlangBuiltinFreeInputs(in, n); @@ -320,14 +323,15 @@ static int kvlangBuiltinDiv(kvlangFrame_t *f) { static int kvlangBuiltinMod(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); + kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; int rc; - if (n < 2 || !is_int_kind(kvlangXvalueKind(&in[0])) || !is_int_kind(kvlangXvalueKind(&in[1]))) { + if (n < 2 || !kvlangLtIsInt(a.id) || !kvlangLtIsInt(b.id)) { rc = kvlangBuiltinSetErr(f, "TypeError: expected integer, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); kvlangBuiltinFreeInputs(in, n); return rc; } - int64_t b = kvlangXvalueAsInt64(&in[1]); - if (b == 0) { rc = kvlangBuiltinSetErr(f, "ZeroDivisionError: modulo by zero"); kvlangBuiltinFreeInputs(in, n); return rc; } - kvlangXvalue_t r; narrow_int(kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1]), kvlangXvalueAsInt64(&in[0]) % b, &r); + int64_t bv = kvlangScalarI64(b); + if (bv == 0) { rc = kvlangBuiltinSetErr(f, "ZeroDivisionError: modulo by zero"); kvlangBuiltinFreeInputs(in, n); return rc; } + kvlangXvalue_t r; narrow_int(a.id, b.id, kvlangScalarI64(a) % bv, &r); rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); return rc; @@ -347,23 +351,23 @@ static int kvlangBuiltinCmp(kvlangFrame_t *f, cmp_op op) { int rc = kvlangBuiltinWriteResult(f, &rv); kvlangXvalueFree(&rv); kvlangBuiltinFreeInputs(in, n); return rc; } bool r; - const char *ka = kvlangXvalueKind(&in[0]), *kb = kvlangXvalueKind(&in[1]); - if (is_int_kind(ka) && is_int_kind(kb)) { - int c = cmp_int(&in[0], &in[1]); + kvlangScalar_t a = kvlangXvalueScalar(&in[0]), b = kvlangXvalueScalar(&in[1]); + if (kvlangLtIsInt(a.id) && kvlangLtIsInt(b.id)) { + int c = cmp_int(a, b); r = op == CMP_EQ ? c == 0 : op == CMP_NEQ ? c != 0 : op == CMP_LT ? c < 0 : op == CMP_GT ? c > 0 : op == CMP_LE ? c <= 0 : c >= 0; - } else if (is_numeric(&in[0]) && is_numeric(&in[1])) { - double a = kvlangXvalueAsFloat64(&in[0]), b = kvlangXvalueAsFloat64(&in[1]); - r = op == CMP_EQ ? a == b : op == CMP_NEQ ? a != b : op == CMP_LT ? a < b : op == CMP_GT ? a > b : op == CMP_LE ? a <= b : a >= b; - } else if (kvlangXvalueIsCharKind(ka) && kvlangXvalueIsCharKind(kb)) { - char *a = kvlangXvalueValueString(&in[0]), *b = kvlangXvalueValueString(&in[1]); - int c = strcmp(a, b); + } else if (kvlangLtIsNum(a.id) && kvlangLtIsNum(b.id)) { + double av = kvlangScalarF64(a), bv = kvlangScalarF64(b); + r = op == CMP_EQ ? av == bv : op == CMP_NEQ ? av != bv : op == CMP_LT ? av < bv : op == CMP_GT ? av > bv : op == CMP_LE ? av <= bv : av >= bv; + } else if (kvlangLtIsChar(a.id) && kvlangLtIsChar(b.id)) { + char *as = kvlangXvalueValueString(&in[0]), *bs = kvlangXvalueValueString(&in[1]); + int c = strcmp(as, bs); r = op == CMP_EQ ? c == 0 : op == CMP_NEQ ? c != 0 : op == CMP_LT ? c < 0 : op == CMP_GT ? c > 0 : op == CMP_LE ? c <= 0 : c >= 0; - free(a); free(b); - } else if (strcmp(ka, KVSPACE_KIND_BOOL) == 0 && strcmp(kb, KVSPACE_KIND_BOOL) == 0) { - bool a = kvlangXvalueAsInt64(&in[0]) != 0, b = kvlangXvalueAsInt64(&in[1]) != 0; - r = op == CMP_EQ ? a == b : op == CMP_NEQ ? a != b : op == CMP_LT ? a < b : op == CMP_GT ? a > b : op == CMP_LE ? a <= b : a >= b; + free(as); free(bs); + } else if (a.id == KVLANG_LT_BOOL && b.id == KVLANG_LT_BOOL) { + bool av = kvlangScalarI64(a) != 0, bv = kvlangScalarI64(b) != 0; + r = op == CMP_EQ ? av == bv : op == CMP_NEQ ? av != bv : op == CMP_LT ? av < bv : op == CMP_GT ? av > bv : op == CMP_LE ? av <= bv : av >= bv; } else { - kvlangBuiltinSetErr(f, "TypeError: cannot compare %s with %s", ka, kb); kvlangBuiltinFreeInputs(in, n); return -1; + kvlangBuiltinSetErr(f, "TypeError: cannot compare %s with %s", kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1])); kvlangBuiltinFreeInputs(in, n); return -1; } kvlangXvalue_t rv; kvlangXvalueNewBool(&rv, r); int rc = kvlangBuiltinWriteResult(f, &rv); kvlangXvalueFree(&rv); kvlangBuiltinFreeInputs(in, n); @@ -390,34 +394,35 @@ static bool require_bool(kvlangFrame_t *f, const char *op, kvlangXvalue_t *in, i static int kvlangBuiltinAnd(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); if (!require_bool(f, "&&", in, n, 2)) { kvlangBuiltinFreeInputs(in, n); return -1; } - kvlangXvalue_t r; kvlangXvalueNewBool(&r, kvlangXvalueAsInt64(&in[0]) != 0 && kvlangXvalueAsInt64(&in[1]) != 0); + kvlangXvalue_t r; kvlangXvalueNewBool(&r, kvlangScalarI64(kvlangXvalueScalar(&in[0])) != 0 && kvlangScalarI64(kvlangXvalueScalar(&in[1])) != 0); int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); return rc; } static int kvlangBuiltinOr(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); if (!require_bool(f, "||", in, n, 2)) { kvlangBuiltinFreeInputs(in, n); return -1; } - kvlangXvalue_t r; kvlangXvalueNewBool(&r, kvlangXvalueAsInt64(&in[0]) != 0 || kvlangXvalueAsInt64(&in[1]) != 0); + kvlangXvalue_t r; kvlangXvalueNewBool(&r, kvlangScalarI64(kvlangXvalueScalar(&in[0])) != 0 || kvlangScalarI64(kvlangXvalueScalar(&in[1])) != 0); int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); return rc; } static int kvlangBuiltinNot(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); if (!require_bool(f, "!", in, n, 1)) { kvlangBuiltinFreeInputs(in, n); return -1; } - kvlangXvalue_t r; kvlangXvalueNewBool(&r, kvlangXvalueAsInt64(&in[0]) == 0); + kvlangXvalue_t r; kvlangXvalueNewBool(&r, kvlangScalarI64(kvlangXvalueScalar(&in[0])) == 0); int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); return rc; } static int kvlangBuiltinBit(kvlangFrame_t *f, int op) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - if (n < 2 || !is_int_kind(kvlangXvalueKind(&in[0])) || !is_int_kind(kvlangXvalueKind(&in[1]))) { + kvlangScalar_t sa = kvlangXvalueScalar(&in[0]), sb = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; + if (n < 2 || !kvlangLtIsInt(sa.id) || !kvlangLtIsInt(sb.id)) { kvlangBuiltinSetErr(f, "TypeError: expected integer, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); kvlangBuiltinFreeInputs(in, n); return -1; } - int64_t a = kvlangXvalueAsInt64(&in[0]), b = kvlangXvalueAsInt64(&in[1]); + int64_t a = kvlangScalarI64(sa), b = kvlangScalarI64(sb); int64_t v = op == 0 ? a & b : op == 1 ? a | b : op == 2 ? a ^ b : op == 3 ? (a << (uint64_t)b) : (a >> (uint64_t)b); - kvlangXvalue_t r; narrow_int(kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1]), v, &r); + kvlangXvalue_t r; narrow_int(sa.id, sb.id, v, &r); int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); return rc; } @@ -430,15 +435,16 @@ static int kvlangBuiltinShr(kvlangFrame_t *f) { return kvlangBuiltinBit(f, 4); } /* math */ static int kvlangBuiltinMathUnary(kvlangFrame_t *f, int op) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - if (n < 1 || !is_numeric(&in[0])) { kvlangBuiltinSetErr(f, "TypeError: expected numeric, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); kvlangBuiltinFreeInputs(in, n); return -1; } + kvlangScalar_t sa = kvlangXvalueScalar(&in[0]); + if (n < 1 || !kvlangLtIsNum(sa.id)) { kvlangBuiltinSetErr(f, "TypeError: expected numeric, got %s", n ? kvlangXvalueKind(&in[0]) : "none"); kvlangBuiltinFreeInputs(in, n); return -1; } kvlangXvalue_t r; - double x = kvlangXvalueAsFloat64(&in[0]); + double x = kvlangScalarF64(sa); switch (op) { case 0: kvlangXvalueNewFloat64(&r, sqrt(x)); break; case 1: kvlangXvalueNewFloat64(&r, exp(x)); break; case 2: kvlangXvalueNewFloat64(&r, log(x)); break; - case 3: /* neg */ if (is_float_kind(kvlangXvalueKind(&in[0]))) { narrow_float(kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[0]), -x, &r); } else { narrow_int(kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[0]), -kvlangXvalueAsInt64(&in[0]), &r); } break; - case 4: /* abs */ if (is_float_kind(kvlangXvalueKind(&in[0]))) { narrow_float(kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[0]), fabs(x), &r); } else { narrow_int(kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[0]), kvlangXvalueAsInt64(&in[0]) < 0 ? -kvlangXvalueAsInt64(&in[0]) : kvlangXvalueAsInt64(&in[0]), &r); } break; + case 3: /* neg */ if (kvlangLtIsFloat(sa.id)) { narrow_float(sa.id, sa.id, -x, &r); } else { narrow_int(sa.id, sa.id, -kvlangScalarI64(sa), &r); } break; + case 4: /* abs */ if (kvlangLtIsFloat(sa.id)) { narrow_float(sa.id, sa.id, fabs(x), &r); } else { int64_t iv = kvlangScalarI64(sa); narrow_int(sa.id, sa.id, iv < 0 ? -iv : iv, &r); } break; case 5: kvlangXvalueNewInt64(&r, x < 0 ? -1 : x > 0 ? 1 : 0); break; } int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); @@ -453,8 +459,9 @@ static int kvlangBuiltinSign(kvlangFrame_t *f) { return kvlangBuiltinMathUnary(f static int kvlangBuiltinPow(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - if (n < 2 || !is_numeric(&in[0]) || !is_numeric(&in[1])) { kvlangBuiltinSetErr(f, "TypeError: expected numeric"); kvlangBuiltinFreeInputs(in, n); return -1; } - kvlangXvalue_t r; kvlangXvalueNewFloat64(&r, pow(kvlangXvalueAsFloat64(&in[0]), kvlangXvalueAsFloat64(&in[1]))); + kvlangScalar_t sa = kvlangXvalueScalar(&in[0]), sb = n >= 2 ? kvlangXvalueScalar(&in[1]) : SCALAR_NONE; + if (n < 2 || !kvlangLtIsNum(sa.id) || !kvlangLtIsNum(sb.id)) { kvlangBuiltinSetErr(f, "TypeError: expected numeric"); kvlangBuiltinFreeInputs(in, n); return -1; } + kvlangXvalue_t r; kvlangXvalueNewFloat64(&r, pow(kvlangScalarF64(sa), kvlangScalarF64(sb))); int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); return rc; } @@ -463,14 +470,15 @@ static int kvlangBuiltinMaxmin(kvlangFrame_t *f, bool is_max) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); if (n < 2) { kvlangBuiltinSetErr(f, "TypeError: binary op requires 2 inputs, got %d", n); kvlangBuiltinFreeInputs(in, n); return -1; } kvlangXvalue_t r; - if (is_int_kind(kvlangXvalueKind(&in[0])) && is_int_kind(kvlangXvalueKind(&in[1]))) { - int c = cmp_int(&in[0], &in[1]); + kvlangScalar_t sa = kvlangXvalueScalar(&in[0]), sb = kvlangXvalueScalar(&in[1]); + if (kvlangLtIsInt(sa.id) && kvlangLtIsInt(sb.id)) { + int c = cmp_int(sa, sb); bool take_a = (is_max && c >= 0) || (!is_max && c <= 0); - narrow_int(kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1]), take_a ? kvlangXvalueAsInt64(&in[0]) : kvlangXvalueAsInt64(&in[1]), &r); - } else if (is_numeric(&in[0]) && is_numeric(&in[1])) { - double a = kvlangXvalueAsFloat64(&in[0]), b = kvlangXvalueAsFloat64(&in[1]); + narrow_int(sa.id, sb.id, take_a ? kvlangScalarI64(sa) : kvlangScalarI64(sb), &r); + } else if (kvlangLtIsNum(sa.id) && kvlangLtIsNum(sb.id)) { + double a = kvlangScalarF64(sa), b = kvlangScalarF64(sb); bool take_a = (is_max && a >= b) || (!is_max && a <= b); - narrow_float(kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1]), take_a ? a : b, &r); + narrow_float(sa.id, sb.id, take_a ? a : b, &r); } else { kvlangBuiltinSetErr(f, "TypeError: max/min requires numeric, got %s and %s", kvlangXvalueKind(&in[0]), kvlangXvalueKind(&in[1])); kvlangBuiltinFreeInputs(in, n); return -1; } int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); return rc; @@ -483,13 +491,15 @@ static int kvlangBuiltinCastNum(kvlangFrame_t *f, const char *kind) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); if (n < 1 || kvlangXvalueNone(&in[0])) { kvlangBuiltinSetErr(f, "TypeError: cannot cast None"); kvlangBuiltinFreeInputs(in, n); return -1; } kvlangXvalue_t r; - if (strcmp(kind, KVSPACE_KIND_BOOL) == 0) { + kvlangScalar_t sa = kvlangXvalueScalar(&in[0]); + int tid = kvlangLangTypeId(kind, strlen(kind)); + if (tid == KVLANG_LT_BOOL) { if (!kvlangXvalueKindIs(&in[0], KVSPACE_KIND_BOOL)) { kvlangBuiltinSetErr(f, "TypeError: cannot cast %s to bool — use != 0", kvlangXvalueKind(&in[0])); kvlangBuiltinFreeInputs(in, n); return -1; } - kvlangXvalueNewBool(&r, kvlangXvalueAsInt64(&in[0]) != 0); + kvlangXvalueNewBool(&r, kvlangScalarI64(sa) != 0); } - else if (strcmp(kind, KVSPACE_KIND_FLOAT32) == 0) { float fv = (float)kvlangXvalueAsFloat64(&in[0]); uint8_t b[4]; memcpy(b, &fv, 4); kvlangXvalueNewTlv(&r, KVSPACE_KIND_FLOAT32, b, 4, 1); } - else if (strcmp(kind, KVSPACE_KIND_FLOAT64) == 0) kvlangXvalueNewFloat64(&r, kvlangXvalueAsFloat64(&in[0])); - else { int64_t v = kvlangXvalueAsInt64(&in[0]); narrow_int(kind, kind, v, &r); } + else if (tid == KVLANG_LT_FLOAT32) { float fv = (float)kvlangScalarF64(sa); uint8_t b[4]; memcpy(b, &fv, 4); kvlangXvalueNewTlv(&r, KVSPACE_KIND_FLOAT32, b, 4, 1); } + else if (tid == KVLANG_LT_FLOAT64) kvlangXvalueNewFloat64(&r, kvlangScalarF64(sa)); + else { int64_t v = kvlangScalarI64(sa); narrow_int(tid, tid, v, &r); } int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); return rc; } @@ -523,7 +533,12 @@ static int kvlangBuiltinCastCharAscii(kvlangFrame_t *f) { return kvlangBuiltinCa /* 精度前缀(int64·add / float32·add …)保留:CapIndex 两级查表——先按完整 opcode 命中特化, * 未命中且前缀是 C native 数字 kind 时才剥前缀归到裸 op(如 add),kvlangBuiltin* 按操作数 kind 归约。 */ +static int kvlangCtlCopy(kvlangFrame_t *f) { return kvlangBuiltinExecuteCopy(f->kv, f->vtid, f->pc, f->inst); } + static const struct { const char *op; kvlangBuiltinFn fn; } myrwircaps[] = { + /* control / copy:与 native 算子同表,op_id 单跳派发 */ + {OP_CALL, kvlangCtlCall}, {OP_RETURN, kvlangCtlReturn}, {OP_GOTO, kvlangCtlGoto}, + {OP_BR, kvlangCtlBr}, {OP_COPY, kvlangCtlCopy}, {"add", kvlangBuiltinAdd}, {"+", kvlangBuiltinAdd}, {"sub", kvlangBuiltinSub}, {"-", kvlangBuiltinSub}, {"mul", kvlangBuiltinMul}, {"×", kvlangBuiltinMul}, diff --git a/runtime/src/builtin_collection.c b/runtime/src/builtin_collection.c index 1e5816ad..87efd81e 100644 --- a/runtime/src/builtin_collection.c +++ b/runtime/src/builtin_collection.c @@ -95,33 +95,28 @@ int kvlangBuiltinArray(kvlangFrame_t *f) { return 0; } +static int xv_head1(kvlangFrame_t *f, kvspaceHead_t *h); /* GetHead-only 单读参 head,定义见下 */ + int kvlangBuiltinNdarrayNumel(kvlangFrame_t *f) { - kvlangXvalue_t in[1]; int n = kvlangBuiltinReadInputs(f, in, 1); - int64_t n_el = 0; - if (n > 0) n_el = kvlangXvalueArrayLen(&in[0]); + kvspaceHead_t h; int64_t n_el = 0; + if (xv_head1(f, &h) == 0) { kvlang_kindexpr_t kx; kvlang_kindexpr_parse(h.kindexpr, &kx); n_el = kx.array_len; } kvlangXvalue_t r; kvlangXvalueNewInt64(&r, n_el); - int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); + int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); return rc; } int kvlangBuiltinNdarrayDim(kvlangFrame_t *f) { - kvlangXvalue_t in[1]; int n = kvlangBuiltinReadInputs(f, in, 1); - int64_t ndim = 0; - if (n > 0) { - kvspaceHead_t h; kvlangXvalueHead(&in[0], &h); - kvlang_kindexpr_t kx; kvlang_kindexpr_parse(h.kindexpr, &kx); - ndim = kx.ndim; - } + kvspaceHead_t h; int64_t ndim = 0; + if (xv_head1(f, &h) == 0) { kvlang_kindexpr_t kx; kvlang_kindexpr_parse(h.kindexpr, &kx); ndim = kx.ndim; } kvlangXvalue_t r; kvlangXvalueNewInt64(&r, ndim); - int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); + int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); return rc; } int kvlangBuiltinNdarrayShape(kvlangFrame_t *f) { - kvlangXvalue_t in[1]; int n = kvlangBuiltinReadInputs(f, in, 1); int32_t dims[8]; int32_t ndim = 0; - if (n > 0 && !kvlangXvalueNone(&in[0])) { - kvspaceHead_t h; kvlangXvalueHead(&in[0], &h); + kvspaceHead_t h; + if (xv_head1(f, &h) == 0) { kvlang_kindexpr_t kx; kvlang_kindexpr_parse(h.kindexpr, &kx); ndim = kx.ndim; for (int i = 0; i < ndim && i < 8; i++) dims[i] = kx.dims[i]; @@ -134,62 +129,145 @@ int kvlangBuiltinNdarrayShape(kvlangFrame_t *f) { } int32_t sd[1] = { ndim }; kvlangXvalue_t r; kvlangXvalueNewTlvDims(&r, KVSPACE_KIND_INT64, raw, raw_len, sd, 1); - int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); + int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); return rc; } -/* 计算多维下标 (i0..i_{n-1}) 的 row-major 扁平索引,越界返回 -1。 */ -static int64_t flat_index(const kvlang_kindexpr_t *kx, const kvlangXvalue_t *in, int nidx) { +/* 计算多维下标的 row-major 扁平索引,越界返回 -1。 */ +static int64_t flat_index(const kvlang_kindexpr_t *kx, const int64_t *idx, int nidx) { int64_t flat = 0; for (int i = 0; i < nidx; i++) { - int64_t idx = kvlangXvalueAsInt64(&in[i + 1]); - if (idx < 0 || idx >= kx->dims[i]) return -1; - flat = flat * kx->dims[i] + idx; + if (idx[i] < 0 || idx[i] >= kx->dims[i]) return -1; + flat = flat * kx->dims[i] + idx[i]; } return flat; } +/* base kind(kx.kind 为非 NUL 终止子串)拷成 NUL 终止串,取元素字节大小;空 kind → 0。 */ +static int xv_elem_size(const kvlang_kindexpr_t *kx) { + if (!kx->kind || kx->kind_len <= 0) return 0; + char kb[64]; int kl = kx->kind_len < 63 ? kx->kind_len : 63; + memcpy(kb, kx->kind, (size_t)kl); kb[kl] = 0; + return kvlangXvalueElemSize(kb); +} + +/* 读参 ri 的 head:变量走 GetHead 只读前缀(不借 body,*key=malloc'd 键),字面量数组借整块 + * 解 head(*key=NULL,*borrow 持整块,调用方 kvlangXvalueFree)。返回 0 成功、非 0 空/不存在。 */ +static int xv_read_head(kvlangFrame_t *f, const char *fr, int ri, kvspaceHead_t *h, + char **key, kvlangXvalue_t *borrow) { + kvlangXvalueZero(borrow); *key = NULL; + char *k = kvlangBuiltinResolveReadKey(f->kv, fr, f->inst->reads[ri].name, &f->inst->reads[ri].val); + if (k) { + if (kvlangKvGetHead(f->kv, k, h) != 0) { free(k); return -1; } + *key = k; return 0; + } + kvlangBuiltinResolveReadValue(f->kv, fr, f->inst->reads[ri].name, &f->inst->reads[ri].val, borrow); + if (kvlangXvalueNone(borrow)) return -1; + return kvspaceDecodeHead(borrow->data, borrow->len, h) == 0 ? 0 : -1; +} + +/* 单读参 head:GetHead-only(变量)或借块解码(字面量),完毕即释放借块与键。 + * 返回 0 并填 *h;空/不存在返回 -1(调用方给默认值)。 */ +static int xv_head1(kvlangFrame_t *f, kvspaceHead_t *h) { + char *fr = kvlangKeytreeFrameRoot(f->pc); + char *key; kvlangXvalue_t borrow; + int rc = xv_read_head(f, fr, 0, h, &key, &borrow); + free(key); kvlangXvalueFree(&borrow); free(fr); + return rc; +} + +/* 读 first..first+nidx-1 的标量下标到 idx[]。 */ +static void xv_read_indices(kvlangFrame_t *f, const char *fr, int first, int nidx, int64_t *idx) { + for (int i = 0; i < nidx && i < X_MAX_NDIM; i++) { + kvlangXvalue_t iv; + kvlangBuiltinResolveReadValue(f->kv, fr, f->inst->reads[first + i].name, &f->inst->reads[first + i].val, &iv); + idx[i] = kvlangScalarI64(kvlangXvalueScalar(&iv)); + kvlangXvalueFree(&iv); + } +} + +/* 分片读单元素:GetHead 定位 + GetPart 只借该元素的 [off, off+sz) 字节,不借整块。 */ int kvlangBuiltinXvAt(kvlangFrame_t *f) { int nidx = f->inst->nr - 1; if (nidx < 1) return kvlangBuiltinSetErr(f, "TypeError: xv.at requires array and indices"); - kvlangXvalue_t in[MAX_PARAMS]; int n = kvlangBuiltinReadInputs(f, in, MAX_PARAMS); - const char *k = kvlangXvalueKind(&in[0]); - int sz = kvlangXvalueElemSize(k); - kvspaceHead_t h; kvspaceDecodeHead(in[0].data, in[0].len, &h); + char *fr = kvlangKeytreeFrameRoot(f->pc); + kvspaceHead_t h; char *key; kvlangXvalue_t arr; + if (xv_read_head(f, fr, 0, &h, &key, &arr) != 0) { free(fr); return kvlangBuiltinSetErr(f, "TypeError: xv.at requires a compact array"); } kvlang_kindexpr_t kx; kvlang_kindexpr_parse(h.kindexpr, &kx); - if (sz <= 0 || kx.ndim == 0) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "TypeError: xv.at requires a compact array, got %s", k); } - if (nidx != kx.ndim) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "IndexError: xv.at: %d-dim array needs %d indices, got %d", kx.ndim, kx.ndim, nidx); } - int64_t flat = flat_index(&kx, in, nidx); - if (flat < 0) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "IndexError: xv.at: index out of bounds"); } - const uint8_t *body = in[0].data + h.body_offset; - kvlangXvalue_t e; kvlangXvalueNewTlv(&e, k, body + flat * sz, (uint32_t)sz, 1); - int rc = kvlangBuiltinWriteResult(f, &e); kvlangXvalueFree(&e); kvlangBuiltinFreeInputs(in, n); + int sz = xv_elem_size(&kx); + if (sz <= 0 || kx.ndim == 0) { free(key); kvlangXvalueFree(&arr); free(fr); return kvlangBuiltinSetErr(f, "TypeError: xv.at requires a compact array, got %s", h.kindexpr); } + if (nidx != kx.ndim) { free(key); kvlangXvalueFree(&arr); free(fr); return kvlangBuiltinSetErr(f, "IndexError: xv.at: %d-dim array needs %d indices, got %d", kx.ndim, kx.ndim, nidx); } + int64_t idx[X_MAX_NDIM]; xv_read_indices(f, fr, 1, nidx, idx); + free(fr); + int64_t flat = flat_index(&kx, idx, nidx); + if (flat < 0) { free(key); kvlangXvalueFree(&arr); return kvlangBuiltinSetErr(f, "IndexError: xv.at: index out of bounds"); } + char kb[64]; int kl = kx.kind_len < 63 ? kx.kind_len : 63; memcpy(kb, kx.kind, (size_t)kl); kb[kl] = 0; + kvlangXvalue_t e; + if (key) { + kvlangXvalue_t part; kvlangKvGetPart(f->kv, key, (uint32_t)(h.body_offset + flat * sz), (uint32_t)sz, &part); + kvlangXvalueNewTlv(&e, kb, part.data, part.len, 1); + kvlangXvalueFree(&part); free(key); + } else { + const uint8_t *body = arr.data + h.body_offset; + kvlangXvalueNewTlv(&e, kb, body + flat * sz, (uint32_t)sz, 1); + } + kvlangXvalueFree(&arr); + int rc = kvlangBuiltinWriteResult(f, &e); kvlangXvalueFree(&e); return rc; } +/* 分片写单元素:写目标==源变量且已存在 → GetHead 定位 + SetPart 就地写该元素字节(O(1), + * 不重建整块);源≠目标 / 字面量 / 缺失 → 回退借整块、拷贝、改元素、整体重建。 */ int kvlangBuiltinXvSet(kvlangFrame_t *f) { int nidx = f->inst->nr - 2; if (nidx < 1) return kvlangBuiltinSetErr(f, "TypeError: xv.set requires array, indices, value"); if (f->inst->nw == 0) return kvlangBuiltinSetErr(f, "TypeError: xv.set requires a write param (-> a)"); - kvlangXvalue_t in[MAX_PARAMS]; int n = kvlangBuiltinReadInputs(f, in, MAX_PARAMS); - const char *k = kvlangXvalueKind(&in[0]); + char *fr = kvlangKeytreeFrameRoot(f->pc); + char *rk = kvlangBuiltinResolveReadKey(f->kv, fr, f->inst->reads[0].name, &f->inst->reads[0].val); + char *wk = kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); + int64_t idx[X_MAX_NDIM]; xv_read_indices(f, fr, 1, nidx, idx); + kvlangXvalue_t vv; kvlangBuiltinResolveReadValue(f->kv, fr, f->inst->reads[nidx + 1].name, &f->inst->reads[nidx + 1].val, &vv); + kvspaceHead_t vh; kvspaceDecodeHead(vv.data, vv.len, &vh); + const uint8_t *vb = vv.data + vh.body_offset; + + kvspaceHead_t h; + if (rk && wk && strcmp(rk, wk) == 0 && kvlangKvGetHead(f->kv, wk, &h) == 0) { + kvlang_kindexpr_t kx; kvlang_kindexpr_parse(h.kindexpr, &kx); + int sz = xv_elem_size(&kx); + int64_t flat = (sz > 0 && kx.ndim && nidx == kx.ndim) ? flat_index(&kx, idx, nidx) : -1; + const char *emsg = sz <= 0 || kx.ndim == 0 ? "TypeError: xv.set requires a compact array" + : nidx != kx.ndim ? "IndexError: xv.set: dim/index count mismatch" + : flat < 0 ? "IndexError: xv.set: index out of bounds" : NULL; + int rc = 0; + if (emsg) rc = kvlangBuiltinSetErr(f, "%s", emsg); + else { + int c = vh.body_len < sz ? vh.body_len : sz; + char err[256]; kvlangKvSetPart(f->kv, wk, (uint32_t)(h.body_offset + flat * sz), vb, (uint32_t)c, err, sizeof err); + kvlangBuiltinNextPc(f); + } + free(rk); free(wk); free(fr); kvlangXvalueFree(&vv); + return rc; + } + free(rk); free(wk); + + kvlangXvalue_t arr; kvlangBuiltinResolveReadValue(f->kv, fr, f->inst->reads[0].name, &f->inst->reads[0].val, &arr); + free(fr); + const char *k = kvlangXvalueKind(&arr); int sz = kvlangXvalueElemSize(k); - kvspaceHead_t h; kvspaceDecodeHead(in[0].data, in[0].len, &h); - kvlang_kindexpr_t kx; kvlang_kindexpr_parse(h.kindexpr, &kx); - if (sz <= 0 || kx.ndim == 0) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "TypeError: xv.set requires a compact array, got %s", k); } - if (nidx != kx.ndim) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "IndexError: xv.set: %d-dim array needs %d indices, got %d", kx.ndim, kx.ndim, nidx); } - int64_t flat = flat_index(&kx, in, nidx); - if (flat < 0) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "IndexError: xv.set: index out of bounds"); } - const uint8_t *body = in[0].data + h.body_offset; - uint8_t *nb = malloc((size_t)h.body_len); - memcpy(nb, body, (size_t)h.body_len); - kvspaceHead_t vh; kvspaceDecodeHead(in[nidx + 1].data, in[nidx + 1].len, &vh); - const uint8_t *vb = in[nidx + 1].data + vh.body_offset; + kvspaceHead_t ah; kvspaceDecodeHead(arr.data, arr.len, &ah); + kvlang_kindexpr_t kx; kvlang_kindexpr_parse(ah.kindexpr, &kx); + const char *emsg = sz <= 0 || kx.ndim == 0 ? "TypeError: xv.set requires a compact array" + : nidx != kx.ndim ? "IndexError: xv.set: dim/index count mismatch" : NULL; + int64_t flat = emsg ? -1 : flat_index(&kx, idx, nidx); + if (!emsg && flat < 0) emsg = "IndexError: xv.set: index out of bounds"; + if (emsg) { kvlangXvalueFree(&arr); kvlangXvalueFree(&vv); return kvlangBuiltinSetErr(f, "%s", emsg); } + uint8_t *nb = malloc((size_t)ah.body_len); + memcpy(nb, arr.data + ah.body_offset, (size_t)ah.body_len); int c = vh.body_len < sz ? vh.body_len : sz; memcpy(nb + flat * sz, vb, (size_t)c); - kvlangXvalue_t nv; kvlangXvalueNewTlvDims(&nv, k, nb, (uint32_t)h.body_len, kx.dims, kx.ndim); + kvlangXvalue_t nv; kvlangXvalueNewTlvDims(&nv, k, nb, (uint32_t)ah.body_len, kx.dims, kx.ndim); int rc = kvlangBuiltinWriteResult(f, &nv); - kvlangXvalueFree(&nv); free(nb); kvlangBuiltinFreeInputs(in, n); + kvlangXvalueFree(&nv); free(nb); kvlangXvalueFree(&arr); kvlangXvalueFree(&vv); return rc; } @@ -206,7 +284,7 @@ int kvlangBuiltinXvReshape(kvlangFrame_t *f) { if (ndims > X_MAX_NDIM) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "IndexError: xv.reshape: at most %d dims, got %d", X_MAX_NDIM, ndims); } int32_t dims[X_MAX_NDIM]; int64_t numel = 1; for (int i = 0; i < ndims; i++) { - dims[i] = (int32_t)kvlangXvalueAsInt64(&in[i + 1]); + dims[i] = (int32_t)kvlangScalarI64(kvlangXvalueScalar(&in[i + 1])); if (dims[i] < 0) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "IndexError: xv.reshape: negative dim %d", dims[i]); } numel *= dims[i]; } @@ -244,20 +322,20 @@ int kvlangBuiltinXvReinterpret(kvlangFrame_t *f) { /* xv·kindexpr(v) -> s:返回 v 的 head kindexpr 串(含 ref 前缀与 [dims]),作为字符串。 */ int kvlangBuiltinXvKindexpr(kvlangFrame_t *f) { if (f->inst->nw == 0) return kvlangBuiltinSetErr(f, "TypeError: xv.kindexpr requires a write param (-> s)"); - kvlangXvalue_t in[1]; int n = kvlangBuiltinReadInputs(f, in, 1); - kvspaceHead_t h; kvlangXvalueHead(&in[0], &h); - kvlangXvalue_t r; kvlangXvalueNewCharUtf8(&r, (const char *)h.kindexpr); - int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); + kvspaceHead_t h; const char *ke = ""; + if (xv_head1(f, &h) == 0) ke = (const char *)h.kindexpr; + kvlangXvalue_t r; kvlangXvalueNewCharUtf8(&r, ke); + int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); return rc; } /* xv·bodylen(v) -> n:返回 v 的 body 字节数(int64)。 */ int kvlangBuiltinXvBodylen(kvlangFrame_t *f) { if (f->inst->nw == 0) return kvlangBuiltinSetErr(f, "TypeError: xv.bodylen requires a write param (-> n)"); - kvlangXvalue_t in[1]; int n = kvlangBuiltinReadInputs(f, in, 1); - kvspaceHead_t h; kvlangXvalueHead(&in[0], &h); - kvlangXvalue_t r; kvlangXvalueNewInt64(&r, h.body_len); - int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); kvlangBuiltinFreeInputs(in, n); + kvspaceHead_t h; int64_t bl = 0; + if (xv_head1(f, &h) == 0) bl = h.body_len; + kvlangXvalue_t r; kvlangXvalueNewInt64(&r, bl); + int rc = kvlangBuiltinWriteResult(f, &r); kvlangXvalueFree(&r); return rc; } @@ -334,7 +412,7 @@ int kvlangBuiltinSlice(kvlangFrame_t *f) { char *base = kvlangBuiltinResolveWriteSlot(f->kv, fr, f->inst->writes[0].name); ensure_scattered(f, base); int al = separated_len(f->kv, base); - int lo = (int)kvlangXvalueAsInt64(&in[1]), hi = (int)kvlangXvalueAsInt64(&in[2]); + int lo = (int)kvlangScalarI64(kvlangXvalueScalar(&in[1])), hi = (int)kvlangScalarI64(kvlangXvalueScalar(&in[2])); if (lo < 0 || hi < lo || hi > al) { free(base); free(fr); kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "IndexError: array.slice: bounds [%d:%d] out of range (len=%d)", lo, hi, al); } for (int i = lo; i < hi; i++) { int64_t sc[1] = { i }, dc[1] = { i - lo }; diff --git a/runtime/src/builtin_kv.c b/runtime/src/builtin_kv.c index d3d06dff..eb056df7 100644 --- a/runtime/src/builtin_kv.c +++ b/runtime/src/builtin_kv.c @@ -6,7 +6,7 @@ static bool is_int_kind(const char *k) { return kvlangXvalueIsIntKind(k) || kvla static char *kvlangKvKey(const kvlangXvalue_t *v) { if (kvlangXvalueIsCharKind(kvlangXvalueKind(v))) return kvlangXvalueValueString(v); - if (is_int_kind(kvlangXvalueKind(v))) { char buf[32]; snprintf(buf, sizeof buf, "%lld", (long long)kvlangXvalueAsInt64(v)); return strdup(buf); } + if (is_int_kind(kvlangXvalueKind(v))) { char buf[32]; snprintf(buf, sizeof buf, "%lld", (long long)kvlangScalarI64(kvlangXvalueScalar(v))); return strdup(buf); } return strdup(""); } @@ -214,7 +214,7 @@ int kvlangBuiltinKvListLen(kvlangFrame_t *f) { int kvlangBuiltinKvListN(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); char *key = kv_list_dir(f, in, n); - int idx = n >= 2 ? (int)kvlangXvalueAsInt64(&in[1]) : -1; + int idx = n >= 2 ? (int)kvlangScalarI64(kvlangXvalueScalar(&in[1])) : -1; kvlangXvalue_t r; kvlangXvalueZero(&r); if (key && idx >= 0) { char **names = NULL; int cnt = 0; @@ -234,7 +234,7 @@ int kvlangBuiltinKvMkindex(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); char *key = n >= 1 ? path_arg(f, 0, in) : NULL; if (!key) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "TypeError: kv.mkindex requires a path"); } - uint32_t capacity = n >= 2 ? (uint32_t)kvlangXvalueAsInt64(&in[1]) : 0; + uint32_t capacity = n >= 2 ? (uint32_t)kvlangScalarI64(kvlangXvalueScalar(&in[1])) : 0; char err[256]; int rc = kvlangKvMkindex(f->kv, key, capacity, err, sizeof err); free(key); kvlangBuiltinFreeInputs(in, n); if (rc != 0) return kvlangBuiltinSetErr(f, "%s", err); diff --git a/runtime/src/builtin_random.c b/runtime/src/builtin_random.c index 1194808d..8d2853ab 100644 --- a/runtime/src/builtin_random.c +++ b/runtime/src/builtin_random.c @@ -27,7 +27,7 @@ int kvlangBuiltinRandInt63(kvlangFrame_t *f) { int kvlangBuiltinRandIntn(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); if (n < 1 || kvlangXvalueNone(&in[0])) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "TypeError: random.intn requires 1 int64 arg"); } - uint64_t m = (uint64_t)kvlangXvalueAsInt64(&in[0]); + uint64_t m = (uint64_t)kvlangScalarI64(kvlangXvalueScalar(&in[0])); uint64_t v = m == 0 ? 0 : crypto_rand_u64() % m; uint8_t r[8]; memcpy(r, &v, 8); kvlangXvalue_t e; kvlangXvalueNewTlv(&e, KVSPACE_KIND_UINT64, r, 8, 1); diff --git a/runtime/src/builtin_string.c b/runtime/src/builtin_string.c index c9df0d4e..32aaeeac 100644 --- a/runtime/src/builtin_string.c +++ b/runtime/src/builtin_string.c @@ -92,7 +92,7 @@ int kvlangBuiltinStringChar(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); if (n < 2) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "TypeError: string.char requires string and index"); } if (var_len_char_err(kvlangXvalueKind(&in[0]))) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "%s", var_len_char_err(kvlangXvalueKind(&in[0]))); } - int idx = (int)kvlangXvalueAsInt64(&in[1]); + int idx = (int)kvlangScalarI64(kvlangXvalueScalar(&in[1])); int rn; uint32_t *r = string_runes(&in[0], &rn); int rc; if (idx < 0 || idx >= rn) rc = kvlangBuiltinSetErr(f, "IndexError: at: index %d out of bounds (char count=%d)", idx, rn); @@ -152,7 +152,7 @@ int kvlangBuiltinStringSlice(kvlangFrame_t *f) { kvlangXvalue_t in[3]; int n = kvlangBuiltinReadInputs(f, in, 3); if (n < 3) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "TypeError: string.slice requires string, start, end"); } if (var_len_char_err(kvlangXvalueKind(&in[0]))) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "%s", var_len_char_err(kvlangXvalueKind(&in[0]))); } - int lo = (int)kvlangXvalueAsInt64(&in[1]), hi = (int)kvlangXvalueAsInt64(&in[2]); + int lo = (int)kvlangScalarI64(kvlangXvalueScalar(&in[1])), hi = (int)kvlangScalarI64(kvlangXvalueScalar(&in[2])); int rn; uint32_t *r = string_runes(&in[0], &rn); if (lo < 0 || hi > rn || lo > hi) { free(r); kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "IndexError: at: slice index out of bounds (lo=%d hi=%d char count=%d)", lo, hi, rn); } write_char32(f, r + lo, hi - lo); @@ -217,8 +217,8 @@ static int write_ascii(kvlangFrame_t *f, const char *buf, int len) { int kvlangBuiltinStringFormatInt(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - int64_t v = kvlangXvalueAsInt64(&in[0]); - int base = n >= 2 ? (int)kvlangXvalueAsInt64(&in[1]) : 10; + int64_t v = kvlangScalarI64(kvlangXvalueScalar(&in[0])); + int base = n >= 2 ? (int)kvlangScalarI64(kvlangXvalueScalar(&in[1])) : 10; uint64_t u = v < 0 ? (uint64_t)(-(v + 1)) + 1 : (uint64_t)v; char buf[66]; int len = fmt_base(u, base, v < 0, buf); int rc = write_ascii(f, buf, len); kvlangBuiltinFreeInputs(in, n); @@ -227,8 +227,8 @@ int kvlangBuiltinStringFormatInt(kvlangFrame_t *f) { int kvlangBuiltinStringFormatUint(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); - uint64_t u = kvlangXvalueAsUint64(&in[0]); - int base = n >= 2 ? (int)kvlangXvalueAsInt64(&in[1]) : 10; + uint64_t u = kvlangScalarU64(kvlangXvalueScalar(&in[0])); + int base = n >= 2 ? (int)kvlangScalarI64(kvlangXvalueScalar(&in[1])) : 10; char buf[66]; int len = fmt_base(u, base, 0, buf); int rc = write_ascii(f, buf, len); kvlangBuiltinFreeInputs(in, n); return rc; @@ -237,7 +237,7 @@ int kvlangBuiltinStringFormatUint(kvlangFrame_t *f) { int kvlangBuiltinStringParseInt(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); char *s = kvlangXvalueValueString(&in[0]); - int base = n >= 2 ? (int)kvlangXvalueAsInt64(&in[1]) : 10; + int base = n >= 2 ? (int)kvlangScalarI64(kvlangXvalueScalar(&in[1])) : 10; char *end = NULL; long long v = strtoll(s, &end, base); int bad = s[0] == '\0' || end == s || *end != '\0'; free(s); @@ -250,7 +250,7 @@ int kvlangBuiltinStringParseInt(kvlangFrame_t *f) { int kvlangBuiltinStringParseUint(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); char *s = kvlangXvalueValueString(&in[0]); - int base = n >= 2 ? (int)kvlangXvalueAsInt64(&in[1]) : 10; + int base = n >= 2 ? (int)kvlangScalarI64(kvlangXvalueScalar(&in[1])) : 10; char *end = NULL; unsigned long long v = strtoull(s, &end, base); int bad = s[0] == '\0' || end == s || *end != '\0'; free(s); diff --git a/runtime/src/builtin_time.c b/runtime/src/builtin_time.c index 26f96368..9d7ffbff 100644 --- a/runtime/src/builtin_time.c +++ b/runtime/src/builtin_time.c @@ -28,7 +28,7 @@ int kvlangBuiltinTimeNow(kvlangFrame_t *f) { int kvlangBuiltinTimeSub(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); if (n < 2) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "TypeError: time.sub requires 2 time args"); } - kvlangXvalue_t e; new_duration(&e, kvlangXvalueAsInt64(&in[0]) - kvlangXvalueAsInt64(&in[1])); + kvlangXvalue_t e; new_duration(&e, kvlangScalarI64(kvlangXvalueScalar(&in[0])) - kvlangScalarI64(kvlangXvalueScalar(&in[1]))); int rc = kvlangBuiltinWriteResult(f, &e); kvlangXvalueFree(&e); kvlangBuiltinFreeInputs(in, n); return rc; } @@ -36,7 +36,7 @@ int kvlangBuiltinTimeSub(kvlangFrame_t *f) { int kvlangBuiltinTimeAdd(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); if (n < 2) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "TypeError: time.add requires time and duration"); } - kvlangXvalue_t e; new_time(&e, kvlangXvalueAsInt64(&in[0]) + kvlangXvalueAsInt64(&in[1])); + kvlangXvalue_t e; new_time(&e, kvlangScalarI64(kvlangXvalueScalar(&in[0])) + kvlangScalarI64(kvlangXvalueScalar(&in[1]))); int rc = kvlangBuiltinWriteResult(f, &e); kvlangXvalueFree(&e); kvlangBuiltinFreeInputs(in, n); return rc; } @@ -53,7 +53,7 @@ static int64_t dur_scale(const char *op) { int kvlangBuiltinDurFrom(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); if (n < 1) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "TypeError: time/duration.from requires 1 int64 arg"); } - kvlangXvalue_t e; new_duration(&e, kvlangXvalueAsInt64(&in[0]) * dur_scale(f->inst->opcode)); + kvlangXvalue_t e; new_duration(&e, kvlangScalarI64(kvlangXvalueScalar(&in[0])) * dur_scale(f->inst->opcode)); int rc = kvlangBuiltinWriteResult(f, &e); kvlangXvalueFree(&e); kvlangBuiltinFreeInputs(in, n); return rc; } @@ -61,7 +61,7 @@ int kvlangBuiltinDurFrom(kvlangFrame_t *f) { int kvlangBuiltinDurTo(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); if (n < 1) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "TypeError: time/duration.as requires 1 duration arg"); } - kvlangXvalue_t e; kvlangXvalueNewInt64(&e, kvlangXvalueAsInt64(&in[0]) / dur_scale(f->inst->opcode)); + kvlangXvalue_t e; kvlangXvalueNewInt64(&e, kvlangScalarI64(kvlangXvalueScalar(&in[0])) / dur_scale(f->inst->opcode)); int rc = kvlangBuiltinWriteResult(f, &e); kvlangXvalueFree(&e); kvlangBuiltinFreeInputs(in, n); return rc; } @@ -69,7 +69,7 @@ int kvlangBuiltinDurTo(kvlangFrame_t *f) { int kvlangBuiltinDurArith(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); if (n < 2) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "TypeError: time/duration arith requires 2 duration args"); } - int64_t a = kvlangXvalueAsInt64(&in[0]), b = kvlangXvalueAsInt64(&in[1]); + int64_t a = kvlangScalarI64(kvlangXvalueScalar(&in[0])), b = kvlangScalarI64(kvlangXvalueScalar(&in[1])); bool sub = strstr(f->inst->opcode, ".sub") != NULL; kvlangXvalue_t e; new_duration(&e, sub ? a - b : a + b); int rc = kvlangBuiltinWriteResult(f, &e); kvlangXvalueFree(&e); kvlangBuiltinFreeInputs(in, n); @@ -80,7 +80,7 @@ int kvlangBuiltinDurCmp(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); if (n < 2) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "TypeError: time/duration cmp requires 2 duration args"); } bool before = strstr(f->inst->opcode, "before") != NULL; - int64_t a = kvlangXvalueAsInt64(&in[0]), b = kvlangXvalueAsInt64(&in[1]); + int64_t a = kvlangScalarI64(kvlangXvalueScalar(&in[0])), b = kvlangScalarI64(kvlangXvalueScalar(&in[1])); kvlangXvalue_t e; kvlangXvalueNewBool(&e, before ? a < b : a > b); int rc = kvlangBuiltinWriteResult(f, &e); kvlangXvalueFree(&e); kvlangBuiltinFreeInputs(in, n); return rc; @@ -90,7 +90,7 @@ int kvlangBuiltinTimeCmp(kvlangFrame_t *f) { kvlangXvalue_t in[2]; int n = kvlangBuiltinReadInputs(f, in, 2); if (n < 2) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "TypeError: time cmp requires 2 args"); } bool before = strstr(f->inst->opcode, "before") != NULL; - int64_t a = kvlangXvalueAsInt64(&in[0]), b = kvlangXvalueAsInt64(&in[1]); + int64_t a = kvlangScalarI64(kvlangXvalueScalar(&in[0])), b = kvlangScalarI64(kvlangXvalueScalar(&in[1])); kvlangXvalue_t e; kvlangXvalueNewBool(&e, before ? a < b : a > b); int rc = kvlangBuiltinWriteResult(f, &e); kvlangXvalueFree(&e); kvlangBuiltinFreeInputs(in, n); return rc; diff --git a/runtime/src/builtin_vthread.c b/runtime/src/builtin_vthread.c index 380b2315..81ae418b 100644 --- a/runtime/src/builtin_vthread.c +++ b/runtime/src/builtin_vthread.c @@ -65,7 +65,7 @@ int kvlangBuiltinVthreadCall(kvlangFrame_t *f) { int kvlangBuiltinVthreadSleep(kvlangFrame_t *f) { kvlangXvalue_t in[1]; int n = kvlangBuiltinReadInputs(f, in, 1); if (n < 1) { kvlangBuiltinFreeInputs(in, n); return kvlangBuiltinSetErr(f, "TypeError: vthread.sleep requires 1 duration arg"); } - int64_t ns = kvlangXvalueAsInt64(&in[0]); + int64_t ns = kvlangScalarI64(kvlangXvalueScalar(&in[0])); kvlangBuiltinFreeInputs(in, n); if (ns > 0) { struct timespec ts = { .tv_sec = ns / 1000000000LL, .tv_nsec = ns % 1000000000LL }; diff --git a/runtime/src/kv.c b/runtime/src/kv.c index ed28305a..7b07687e 100644 --- a/runtime/src/kv.c +++ b/runtime/src/kv.c @@ -3,14 +3,6 @@ /* kv 访问统一走 kvspace-durable 兼容 C ABI(kvspace*)。 * 后端由链接的 kvspace 库决定(kvspace-durable / kvspace-c 均导出同一 ABI)。 */ -static void kvlangXvalueCopyMalloc(kvlangXvalue_t *out, const uint8_t *d, uint32_t len) { - if (len > 0) { - out->data = malloc(len); - memcpy(out->data, d, len); - out->len = len; - } -} - kvlangKv_t *kvlangKvConnect(const char *dsn) { kvlangKv_t *k = calloc(1, sizeof(*k)); k->h = kvspaceConnect(dsn); @@ -29,19 +21,24 @@ void kvlangKvDisconnect(kvlangKv_t *k) { free(k); } -/* 借用读(resolve=0,raw)→ 拷贝为 runtime 自持。空值 → out len=0。 */ +/* 借用读(resolve=0,raw):out 直接借 kvspace 常驻/借用池指针(borrowed=1,不 free、不入 + * kvlangKvSet 前不跨写)。空值 → out len=0。 */ int kvlangKvGetOne(kvlangKv_t *k, const char *key, kvlangXvalue_t *out) { kvlangXvalueZero(out); uint8_t *d; uint32_t len; if (kvspaceGet(k->h, key, 0, &d, &len) != 0) return -1; - kvlangXvalueCopyMalloc(out, d, len); + if (d && len > 0) { + out->data = d; + out->len = len; + out->borrowed = 1; + } return 0; } /* Frame member: dir 直连 name 组键,借用读(resolve=1 穿透 link,全路径 Get(resolve=0) 不穿透 [d] 帧) - * → 拷贝自持。空值 → out len=0。 */ + * → out 借 kvspace 指针(borrowed=1)。空值 → out len=0。 */ int kvlangKvGetMember(kvlangKv_t *k, const char *dir, const char *name, kvlangXvalue_t *out) { kvlangXvalueZero(out); if (!name || !name[0]) @@ -53,15 +50,50 @@ int kvlangKvGetMember(kvlangKv_t *k, const char *dir, const char *name, kvlangXv key[dl + nl] = 0; uint8_t *d; uint32_t len; - if (kvspaceGet(k->h, key, 1, &d, &len) == 0 && d && len > 0) - kvlangXvalueCopyMalloc(out, d, len); + if (kvspaceGet(k->h, key, 1, &d, &len) == 0 && d && len > 0) { + out->data = d; + out->len = len; + out->borrowed = 1; + } free(key); return 0; } +/* 指令边界回收读借用池:VM 每条指令末调一次。 */ +void kvlangKvReadReset(kvlangKv_t *k) { kvspaceReadReset(k->h); } + +/* 定位读:借用读 key 值的 [off, off+len) 字节 → out(borrowed=1)。空/越界 → out len=0。 */ +int kvlangKvGetPart(kvlangKv_t *k, const char *key, uint32_t off, uint32_t len, kvlangXvalue_t *out) { + kvlangXvalueZero(out); + uint8_t *d; + uint32_t got; + if (kvspaceGetPart(k->h, key, off, len, &d, &got) != 0) + return -1; + if (d && got > 0) { + out->data = d; + out->len = got; + out->borrowed = 1; + } + return 0; +} + +/* 定位写:就地写 buf 到 key 值的 [off, off+buf_len)(key 须已存在、不改结构)。 */ +int kvlangKvSetPart(kvlangKv_t *k, const char *key, uint32_t off, const uint8_t *buf, uint32_t buf_len, + char *err, uint32_t err_cap) { + return kvspaceSetPart(k->h, key, off, buf, buf_len, err, err_cap); +} + +/* 读 head:只读值前缀解码三正交轴 head(不取 body)。空/不存在 → 非 0。 */ +int kvlangKvGetHead(kvlangKv_t *k, const char *key, kvspaceHead_t *out) { + return kvspaceGetHead(k->h, key, out); +} + /* 写即构造:逐条解 head 取 (kindexpr, body)——同 body_len 就地(WriteInPlace),否则新位置 * (WriteNewPlace)——向 kvspace 要 body 偏移指针后直接写字节,无预合并缓冲。 */ int kvlangKvSet(kvlangKv_t *k, const kvlangKvPair_t *pairs, int n, char *err, uint32_t err_cap) { + /* 借用值全程有效:durable 惰性写不再清读池,读借用池由 VM 在指令边界统一 ReadReset 回收, + * 故写期直接用 v->data,不再需要防御性快照。 */ + int rc = 0; for (int i = 0; i < n; i++) { const kvlangXvalue_t *v = &pairs[i].val; if (!v->data || v->len == 0) { /* None → 删键,令该槽读回 None(不可静默跳过留旧值) */ @@ -76,13 +108,15 @@ int kvlangKvSet(kvlangKv_t *k, const kvlangKvPair_t *pairs, int n, char *err, ui const uint8_t *body = v->data + h.body_offset; uint8_t *dst = NULL; if (kvspaceWriteInPlace(k->h, pairs[i].key, 1, body_len, &dst, err, err_cap) != 0) { - if (kvspaceWriteNewPlace(k->h, pairs[i].key, h.ref, h.storetype, h.ro, h.vid, (const char *)h.kindexpr, body_len, &dst, err, err_cap) != 0) - return -1; + if (kvspaceWriteNewPlace(k->h, pairs[i].key, h.ref, h.storetype, h.ro, h.vid, (const char *)h.kindexpr, body_len, &dst, err, err_cap) != 0) { + rc = -1; + break; + } } if (body_len > 0 && dst) memcpy(dst, body, body_len); } - return 0; + return rc; } int kvlangKvDel(kvlangKv_t *k, const char *key, char *err, uint32_t err_cap) { diff --git a/runtime/src/kvcpu.c b/runtime/src/kvcpu.c index 7b17aa5b..d6a42074 100644 --- a/runtime/src/kvcpu.c +++ b/runtime/src/kvcpu.c @@ -97,7 +97,7 @@ static const char *rfind_sep(const char *s) { /* goto/br 目标:layout 已把 label 解析为 int64 irseq(≥1)。非 int64 / 越界返回 -1。 */ static int irseq_of(const kvlangParam_t *p) { if (kvlangXvalueNone(&p->val) || !kvlangXvalueKindIs(&p->val, KVSPACE_KIND_INT64)) return -1; - int64_t n = kvlangXvalueAsInt64(&p->val); + int64_t n = kvlangScalarI64(kvlangXvalueScalar(&p->val)); if (n < 1 || n > 0x7fffffff) return -1; return (int)n; } @@ -466,56 +466,58 @@ static char *handle_call(kvlangKv_t *kv, const char *pc, kvlangRwirInst_t *inst) return NULL; } -static int handle_control(kvlangKv_t *kv, const char *vtid, const char *pc, kvlangRwirInst_t *inst) { - 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; +int kvlangCtlCall(kvlangFrame_t *f) { + char *sub = handle_call(f->kv, f->pc, f->inst); + if (!sub) return -1; + kvlangVthreadSet(f->kv, f->vtid, sub, "running"); + free(sub); + return 0; +} + +int kvlangCtlReturn(kvlangFrame_t *f) { + char *parent = NULL; + if (handle_return(f->kv, f->vtid, f->pc, &parent) != 0) return -1; + if (!parent) { kvlangVthreadSetDone(f->kv, f->vtid, "ok"); return 0; } + kvlangVthreadSet(f->kv, f->vtid, parent, "running"); + free(parent); + return 0; +} + +int kvlangCtlGoto(kvlangFrame_t *f) { + kvlangRwirInst_t *inst = f->inst; + if (inst->nr != 1) { + char msg[128]; snprintf(msg, sizeof msg, "RuntimeError: goto expects 1 irseq, got %d", inst->nr); + kvlangVthreadSetError(f->kv, f->vtid, f->pc, msg); + return -1; } - 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; } - kvlangVthreadSet(kv, vtid, parent, "running"); - free(parent); - return 0; + return jump_to(f->kv, f->vtid, f->pc, &inst->reads[0], OP_GOTO); +} + +int kvlangCtlBr(kvlangFrame_t *f) { + kvlangRwirInst_t *inst = f->inst; + if (inst->nr != 3) { + char msg[128]; snprintf(msg, sizeof msg, "RuntimeError: br expects cond trueIrseq falseIrseq, got %d", inst->nr); + kvlangVthreadSetError(f->kv, f->vtid, f->pc, msg); + return -1; } - 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); - return -1; - } - return jump_to(kv, vtid, pc, &inst->reads[0], OP_GOTO); + char *fr = kvlangKeytreeFrameRoot(f->pc); + kvlangXvalue_t cond; kvlangXvalueZero(&cond); + kvlangBuiltinResolveReadValue(f->kv, fr, inst->reads[0].name, &inst->reads[0].val, &cond); + free(fr); + if (kvlangXvalueNone(&cond)) { + kvlangVthreadSetError(f->kv, f->vtid, f->pc, "TypeError: None in branch condition"); + kvlangXvalueFree(&cond); + return -1; } - 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); - return -1; - } - char *fr = kvlangKeytreeFrameRoot(pc); - kvlangXvalue_t cond; kvlangXvalueZero(&cond); - kvlangBuiltinResolveReadValue(kv, fr, inst->reads[0].name, &inst->reads[0].val, &cond); - free(fr); - if (kvlangXvalueNone(&cond)) { - kvlangVthreadSetError(kv, vtid, pc, "TypeError: None in branch condition"); - kvlangXvalueFree(&cond); - return -1; - } - if (!kvlangXvalueKindIs(&cond, KVSPACE_KIND_BOOL)) { - char msg[128]; snprintf(msg, sizeof msg, "TypeError: branch condition must be bool, got %s", kvlangXvalueKind(&cond)); - kvlangVthreadSetError(kv, vtid, pc, msg); - kvlangXvalueFree(&cond); - return -1; - } - bool taken = kvlangXvalueAsInt64(&cond) != 0; + if (!kvlangXvalueKindIs(&cond, KVSPACE_KIND_BOOL)) { + char msg[128]; snprintf(msg, sizeof msg, "TypeError: branch condition must be bool, got %s", kvlangXvalueKind(&cond)); + kvlangVthreadSetError(f->kv, f->vtid, f->pc, msg); kvlangXvalueFree(&cond); - return jump_to(kv, vtid, pc, &inst->reads[taken ? 1 : 2], OP_BR); + return -1; } - return -1; + bool taken = kvlangScalarI64(kvlangXvalueScalar(&cond)) != 0; + kvlangXvalueFree(&cond); + return jump_to(f->kv, f->vtid, f->pc, &inst->reads[taken ? 1 : 2], OP_BR); } /* 动态调用:以运行时得到的 funckey 在当前 vthread 造一次 OP_CALL(不新开 vid), @@ -523,14 +525,15 @@ 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.op_id = 0; ci.reads = malloc(sizeof(kvlangParam_t)); ci.reads[0].name = strdup(funckey); kvlangXvalueZero(&ci.reads[0].val); ci.nr = 1; ci.writes = NULL; ci.nw = 0; - int rc = handle_control(kv, vtid, pc, &ci); + kvlangFrame_t f = { kv, vtid, pc, &ci, NULL }; + int rc = kvlangCtlCall(&f); free(ci.opcode); free(ci.reads[0].name); free(ci.reads); return rc; } @@ -633,6 +636,9 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode, char * char *cur_frame = NULL, *cur_funcdir = NULL; /* 帧不变时 funcdir 只读一次,供缓存键 */ int rc = 0; for (;;) { + /* 指令边界:回收上条指令执行期借出的读池(cache 指令的读参已 Materialize 自持,不受影响)。 + * durable 惰性写不再清池,全靠此处回收;shm 常驻映射侧为 no-op。 */ + kvlangKvReadReset(kv); char *pcv = NULL, *status = NULL; kvlangVthreadGet(kv, vtid, &pcv, &status); if (!status || (strcmp(status, "init") != 0 && strcmp(status, "running") != 0 && strcmp(status, "wait") != 0)) { @@ -700,8 +706,9 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode, char * } int exec_err = 0; + char *yield = NULL; if (inst->op_id >= 0) { - char *yield = NULL; + /* 单表派发:native 算子与 control/copy 同居 myrwircaps,op_id 直查一跳到底。 */ kvlangFrame_t f = { kv, vtid, cur, inst, &yield }; exec_err = kvlangBuiltinNative(&f); if (exec_err == 0 && yield) { @@ -712,11 +719,6 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode, char * free(cur); free(cur_frame); free(cur_funcdir); kvlangStrbufFree(&vtid_b); return 1; } - } 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 (opmeta_get(kv, inst->opcode)->notinmyrwircaps) { opmeta_ent_t *m = opmeta_get(kv, inst->opcode); if (m->def_sig) @@ -732,7 +734,7 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode, char * /* 用户函数 → call */ kvlangRwirInst_t ci; ci.opcode = strdup(OP_CALL); - ci.op_id = OPID_CALL; + ci.op_id = 0; ci.nr = inst->nr + 1; ci.nw = inst->nw; ci.reads = malloc(sizeof(kvlangParam_t) * (size_t)ci.nr); @@ -740,7 +742,8 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode, char * 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; - exec_err = handle_control(kv, vtid, cur, &ci); + kvlangFrame_t cf = { kv, vtid, cur, &ci, NULL }; + exec_err = kvlangCtlCall(&cf); free(ci.opcode); free(ci.reads[0].name); free(ci.reads); } diff --git a/runtime/src/langtypetable.c b/runtime/src/langtypetable.c new file mode 100644 index 00000000..df2f424a --- /dev/null +++ b/runtime/src/langtypetable.c @@ -0,0 +1,68 @@ +#include "runtime_internal.h" + +/* langtypetable:base kind 串 ↔ int id 双向映射(runtime 本地,IV-0,不入 + * kvspace)。 decode 期把 head.kindexpr 的 base kind intern 成 + * id,此后热路径纯整数比较。 */ + +typedef struct { + const char *s; + size_t len; + int id; +} lt_ent_t; + +#define LT(k, i) { k, sizeof(k) - 1, i } +static const lt_ent_t LANGTYPETABLE[] = { + LT(KVSPACE_KIND_BOOL, KVLANG_LT_BOOL), + LT(KVSPACE_KIND_INT8, KVLANG_LT_INT8), + LT(KVSPACE_KIND_INT16, KVLANG_LT_INT16), + LT(KVSPACE_KIND_INT32, KVLANG_LT_INT32), + LT(KVSPACE_KIND_INT64, KVLANG_LT_INT64), + LT(KVSPACE_KIND_UINT8, KVLANG_LT_UINT8), + LT(KVSPACE_KIND_UINT16, KVLANG_LT_UINT16), + LT(KVSPACE_KIND_UINT32, KVLANG_LT_UINT32), + LT(KVSPACE_KIND_UINT64, KVLANG_LT_UINT64), + LT(KVSPACE_KIND_FLOAT32, KVLANG_LT_FLOAT32), + LT(KVSPACE_KIND_FLOAT64, KVLANG_LT_FLOAT64), + LT(KVSPACE_KIND_CHAR, KVLANG_LT_CHAR_UTF32), + LT(KVSPACE_KIND_CHAR_UTF8, KVLANG_LT_CHAR_UTF8), + LT(KVSPACE_KIND_CHAR_ASCII, KVLANG_LT_CHAR_ASCII), + LT(KVSPACE_KIND_OBJ, KVLANG_LT_OBJECT), + LT(KVSPACE_KIND_MAP, KVLANG_LT_MAP), + LT(KVSPACE_KIND_INDEX, KVLANG_LT_INDEX), + LT(KVSPACE_KIND_EXT_INDEX, KVLANG_LT_EXTINDEX), + LT(KVSPACE_KIND_RWIR, KVLANG_LT_RWIR), + LT(KVSPACE_KIND_RWFUNC, KVLANG_LT_RWFUNC), + LT(KVSPACE_KIND_SCOPE, KVLANG_LT_SCOPE), + LT(KVSPACE_KIND_STRUCT, KVLANG_LT_STRUCT), + LT(KVSPACE_KIND_TIME, KVLANG_LT_TIME), + LT(KVSPACE_KIND_DURATION, KVLANG_LT_DURATION), + LT(KVSPACE_KIND_NONE, KVLANG_LT_NONE), +}; +#undef LT + +int kvlangLangTypeId(const char *s, size_t len) { + if (!s) + return KVLANG_LT_UNKNOWN; + for (size_t i = 0; i < sizeof(LANGTYPETABLE) / sizeof(LANGTYPETABLE[0]); i++) + if (LANGTYPETABLE[i].len == len && memcmp(LANGTYPETABLE[i].s, s, len) == 0) + return LANGTYPETABLE[i].id; + return KVLANG_LT_UNKNOWN; +} + +const char *kvlangLangTypeKind(int id) { + for (size_t i = 0; i < sizeof(LANGTYPETABLE) / sizeof(LANGTYPETABLE[0]); i++) + if (LANGTYPETABLE[i].id == id) + return LANGTYPETABLE[i].s; + return ""; +} + +int kvlangXvalueLangTypeId(const kvlangXvalue_t *v) { + if (kvlangXvalueNone(v)) + return KVLANG_LT_NONE; + kvspaceHead_t h; + if (kvlangXvalueHead(v, &h) < 0) + return KVLANG_LT_NONE; + kvlang_kindexpr_t kx; + kvlang_kindexpr_parse(h.kindexpr, &kx); + return kvlangLangTypeId(kx.kind, (size_t)kx.kind_len); +} diff --git a/runtime/src/runtime_internal.h b/runtime/src/runtime_internal.h index 2f5850a4..243a12b8 100644 --- a/runtime/src/runtime_internal.h +++ b/runtime/src/runtime_internal.h @@ -40,6 +40,11 @@ extern void *kvspaceConnect(const char *dsn); extern void kvspaceClose(void *h); /* 借用读:*out 指向后端常驻/回收空间,调用方不得 free。resolve=1 穿透 link。 */ extern int kvspaceGet(void *h, const char *key, int resolve, uint8_t **out, uint32_t *out_len); +/* 指令边界回收读借用池;定位读/写(分片);只读 head 前缀。见 kvspace.h 契约。 */ +extern void kvspaceReadReset(void *h); +extern int kvspaceGetPart(void *h, const char *key, uint32_t offset, uint32_t len, uint8_t **out, uint32_t *out_len); +extern int kvspaceSetPart(void *h, const char *key, uint32_t offset, const uint8_t *buf, uint32_t buf_len, char *err, uint32_t err_cap); +extern int kvspaceGetHead(void *h, const char *key, kvspaceHead_t *out); /* 就地写:key 已存在、body_len==原 body_len → 返回原 box body 偏移指针;否则非 0 + err。 */ extern int kvspaceWriteInPlace(void *h, const char *key, int resolve, uint32_t body_len, uint8_t **body, char *err, uint32_t err_cap); @@ -91,7 +96,7 @@ void kvlang_kindexpr_parse(const uint8_t *kindexpr, kvlang_kindexpr_t *out); /* ── 基础类型 ──────────────────────────────────────────────────────── */ -typedef struct { uint8_t *data; uint32_t len; } kvlangXvalue_t; +typedef struct { uint8_t *data; uint32_t len; uint8_t borrowed; } kvlangXvalue_t; typedef struct { char *key; kvlangXvalue_t val; } kvlangKvPair_t; @@ -111,9 +116,10 @@ static inline void kvlangStrbufFree(kvlangStrbuf_t *b) { free(b->p); b->p = NULL /* ── XValue 操作 ───────────────────────────────────────────────────── */ static inline bool kvlangXvalueNone(const kvlangXvalue_t *v) { return v->data == NULL || v->len == 0; } -static inline void kvlangXvalueZero(kvlangXvalue_t *v) { v->data = NULL; v->len = 0; } +static inline void kvlangXvalueZero(kvlangXvalue_t *v) { v->data = NULL; v->len = 0; v->borrowed = 0; } void kvlangXvalueFree(kvlangXvalue_t *v); /* free 自持 data(借用读已拷贝为自持) */ void kvlangXvalueSetBytes(kvlangXvalue_t *v, uint8_t *data, uint32_t len); /* 接管内存 */ +void kvlangXvalueMaterialize(kvlangXvalue_t *v); /* 借用值落地为自持(存入跨指令结构前必调) */ int kvlangXvalueHead(const kvlangXvalue_t *v, kvspaceHead_t *h); /* decode head */ const char *kvlangXvalueKind(const kvlangXvalue_t *v); /* 返回 kind,None="" */ bool kvlangXvalueKindIs(const kvlangXvalue_t *v, const char *kind); @@ -127,13 +133,65 @@ bool kvlangXvalueIsIntKind(const char *kind); bool kvlangXvalueIsUintKind(const char *kind); bool kvlangXvalueIsFloatKind(const char *kind); bool kvlangXvalueIsNumKind(const char *kind); + +/* langtypetable:base kind 串 ↔ int id(runtime 本地,IV-0,不入 kvspace)。 + * 枚举有序:数值家族连续 → 谓词即区间判定,int_width 由序号位移求得。 */ +enum { + KVLANG_LT_UNKNOWN = 0, + KVLANG_LT_NONE, + KVLANG_LT_BOOL, + KVLANG_LT_INT8, KVLANG_LT_INT16, KVLANG_LT_INT32, KVLANG_LT_INT64, + KVLANG_LT_UINT8, KVLANG_LT_UINT16, KVLANG_LT_UINT32, KVLANG_LT_UINT64, + KVLANG_LT_FLOAT32, KVLANG_LT_FLOAT64, + KVLANG_LT_CHAR_UTF32, KVLANG_LT_CHAR_UTF8, KVLANG_LT_CHAR_ASCII, + KVLANG_LT_OBJECT, KVLANG_LT_MAP, KVLANG_LT_INDEX, KVLANG_LT_EXTINDEX, + KVLANG_LT_RWIR, KVLANG_LT_RWFUNC, KVLANG_LT_SCOPE, KVLANG_LT_STRUCT, + KVLANG_LT_TIME, KVLANG_LT_DURATION, + KVLANG_LT_COUNT +}; +int kvlangLangTypeId(const char *s, size_t len); +const char *kvlangLangTypeKind(int id); +int kvlangXvalueLangTypeId(const kvlangXvalue_t *v); +static inline bool kvlangLtIsSint(int id) { return id >= KVLANG_LT_INT8 && id <= KVLANG_LT_INT64; } +static inline bool kvlangLtIsUint(int id) { return id >= KVLANG_LT_UINT8 && id <= KVLANG_LT_UINT64; } +static inline bool kvlangLtIsInt(int id) { return id >= KVLANG_LT_INT8 && id <= KVLANG_LT_UINT64; } +static inline bool kvlangLtIsFloat(int id) { return id == KVLANG_LT_FLOAT32 || id == KVLANG_LT_FLOAT64; } +static inline bool kvlangLtIsNum(int id) { return id >= KVLANG_LT_INT8 && id <= KVLANG_LT_FLOAT64; } +static inline bool kvlangLtIsChar(int id) { return id >= KVLANG_LT_CHAR_UTF32 && id <= KVLANG_LT_CHAR_ASCII; } +static inline int kvlangLtIntWidth(int id) { + if (id >= KVLANG_LT_INT8 && id <= KVLANG_LT_INT64) return 8 << (id - KVLANG_LT_INT8); + if (id >= KVLANG_LT_UINT8 && id <= KVLANG_LT_UINT64) return 8 << (id - KVLANG_LT_UINT8); + return 0; +} +static inline int kvlangLtElemSize(int id) { + if (kvlangLtIsInt(id)) return kvlangLtIntWidth(id) / 8; + if (id == KVLANG_LT_FLOAT32) return 4; + if (id == KVLANG_LT_FLOAT64) return 8; + if (id == KVLANG_LT_BOOL) return 1; + if (id == KVLANG_LT_CHAR_UTF32) return 4; + if (id == KVLANG_LT_CHAR_UTF8 || id == KVLANG_LT_CHAR_ASCII) return 1; + if (id == KVLANG_LT_TIME || id == KVLANG_LT_DURATION) return 8; + return 0; +} + /* 签名 kindexpr(runtime篇-07)校验/匹配 */ bool kvlang_rwirextKindexprValid(const char *expr); bool kvlang_rwirextKindexprMatch(const char *expr, const char *kind, int32_t ndim, const int32_t *dims); bool kvlang_rwirextKindexprVariadic(const char *expr); -int64_t kvlangXvalueAsInt64(const kvlangXvalue_t *v); -double kvlangXvalueAsFloat64(const kvlangXvalue_t *v); -uint64_t kvlangXvalueAsUint64(const kvlangXvalue_t *v); +/* 标量 0copy 视图(取代 kvlangXvalueAsInt64 等按值转换):decode head 一次, + * 持 langtype id + 指向 body 首字节的借用指针,热路径按 id 直读 body。 */ +typedef struct { + int id; + const uint8_t *body; + int32_t len; +} kvlangScalar_t; +kvlangScalar_t kvlangXvalueScalar(const kvlangXvalue_t *v); +int64_t kvlangScalarReadI64(int id, const uint8_t *body); +double kvlangScalarReadF64(int id, const uint8_t *body); +uint64_t kvlangScalarReadU64(int id, const uint8_t *body); +static inline int64_t kvlangScalarI64(kvlangScalar_t s) { return kvlangScalarReadI64(s.id, s.body); } +static inline double kvlangScalarF64(kvlangScalar_t s) { return kvlangScalarReadF64(s.id, s.body); } +static inline uint64_t kvlangScalarU64(kvlangScalar_t s) { return kvlangScalarReadU64(s.id, s.body); } uint32_t kvlangXvalueChar32At(const kvlangXvalue_t *v, int32_t idx); int32_t kvlangXvalueElemSize(const char *kind); @@ -157,6 +215,10 @@ kvlangKv_t *kvlangKvConnect(const char *dsn); void kvlangKvDisconnect(kvlangKv_t *k); int kvlangKvGetOne(kvlangKv_t *k, const char *key, kvlangXvalue_t *out); /* None → out len=0 */ int kvlangKvGetMember(kvlangKv_t *k, const char *dir, const char *name, kvlangXvalue_t *out); +void kvlangKvReadReset(kvlangKv_t *k); /* 指令边界回收读借用池 */ +int kvlangKvGetPart(kvlangKv_t *k, const char *key, uint32_t off, uint32_t len, kvlangXvalue_t *out); /* 借用读分片 body 字节 */ +int kvlangKvSetPart(kvlangKv_t *k, const char *key, uint32_t off, const uint8_t *buf, uint32_t buf_len, char *err, uint32_t err_cap); /* 就地写分片 */ +int kvlangKvGetHead(kvlangKv_t *k, const char *key, kvspaceHead_t *out); /* 只读 head,不取 body */ int kvlangKvSet(kvlangKv_t *k, const kvlangKvPair_t *pairs, int n, char *err, uint32_t err_cap); int kvlangKvDel(kvlangKv_t *k, const char *key, char *err, uint32_t err_cap); int kvlangKvDelTree(kvlangKv_t *k, const char *prefix, char *err, uint32_t err_cap); @@ -215,26 +277,17 @@ bool kvlangKeytreeIsEntryPc(const char *pc); #define OP_COPY "=" /* op_id:decode 期一次固化的统一派发码(quickening),主循环据此纯整数跳表、热路径零 strcmp。 - * ≥0 = native,直查 myrwircaps[op_id] - * 负值 = 保留派发类(control / copy / 待定),语义见下 */ + * ≥0 = 在本 runtime myrwircaps(native 算子 + control/copy 均为其中一行),直查 myrwircaps[op_id].fn + * -1 = 不在表内(执行期查 /lib:def rwir 路由头→路由,否则用户 rwfunc→调用) */ enum { - OPID_notinmyrwircaps = -1, /* 不在本 runtime myrwircaps;执行期查 /lib:def rwir 路由头→路由,否则用户 rwfunc→调用 */ - OPID_CALL = -2, - OPID_RETURN = -3, - OPID_GOTO = -4, - OPID_BR = -5, - OPID_COPY = -6, + OPID_notinmyrwircaps = -1, }; int kvlangBuiltinCapIndex(const char *opcode); -/* decode 期分类:control/copy 先于 native,miss 落 OPID_notinmyrwircaps(执行期再查 /lib)。 */ +/* decode 期分类:control/copy 与 native 同在 myrwircaps 一张表,全走 CapIndex; + * 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; - 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_notinmyrwircaps; } @@ -277,9 +330,15 @@ 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); +/* control 算子:与 native 同居 myrwircaps 一张表,frame 签名统一派发(call/return/goto/br)。 */ +int kvlangCtlCall(kvlangFrame_t *f); +int kvlangCtlReturn(kvlangFrame_t *f); +int kvlangCtlGoto(kvlangFrame_t *f); +int kvlangCtlBr(kvlangFrame_t *f); void kvlangBuiltinResolveReadValue(kvlangKv_t *kv, const char *frame_root, const char *name, const kvlangXvalue_t *val, kvlangXvalue_t *out); char *kvlangBuiltinResolveWriteSlot(kvlangKv_t *kv, const char *frame_root, const char *name); +char *kvlangBuiltinResolveReadKey(kvlangKv_t *kv, const char *frame_root, const char *name, const kvlangXvalue_t *val); bool kvlangBuiltinTryParseNumber(const char *s, kvlangXvalue_t *out); /* 成功 out 接管 */ void kvlangDisplay(const kvlangXvalue_t *v, char **out); /* malloc,对齐 Go Display */ diff --git a/runtime/src/rwir.c b/runtime/src/rwir.c index 4f8beef7..f27fe120 100644 --- a/runtime/src/rwir.c +++ b/runtime/src/rwir.c @@ -63,6 +63,7 @@ int kvlangRwirDecode(kvlangKv_t *kv, const char *link_base, const char *pc, kvla free(nm); if (kvlangXvalueNone(&v)) { kvlangXvalueFree(&v); break; } out->reads[out->nr].name = kvlangXvalueValueString(&v); + kvlangXvalueMaterialize(&v); /* 指令进 rwir_cache 长存,字面量须自持 */ out->reads[out->nr].val = v; out->nr++; } @@ -73,6 +74,7 @@ int kvlangRwirDecode(kvlangKv_t *kv, const char *link_base, const char *pc, kvla free(nm); if (kvlangXvalueNone(&v)) { kvlangXvalueFree(&v); break; } out->writes[out->nw].name = kvlangXvalueValueString(&v); + kvlangXvalueMaterialize(&v); /* 指令进 rwir_cache 长存,字面量须自持 */ out->writes[out->nw].val = v; out->nw++; } diff --git a/runtime/src/xvalue.c b/runtime/src/xvalue.c index 3a54d9cf..a78a0c26 100644 --- a/runtime/src/xvalue.c +++ b/runtime/src/xvalue.c @@ -8,14 +8,28 @@ static uint16_t rd16(const uint8_t *p) { return (uint16_t)(p[0] | (p[1] << 8)); static uint64_t rd64(const uint8_t *p) { return (uint64_t)rd32(p) | ((uint64_t)rd32(p + 4) << 32); } void kvlangXvalueFree(kvlangXvalue_t *v) { - free(v->data); + if (!v->borrowed) + free(v->data); v->data = NULL; v->len = 0; + v->borrowed = 0; } void kvlangXvalueSetBytes(kvlangXvalue_t *v, uint8_t *data, uint32_t len) { v->data = data; v->len = len; + v->borrowed = 0; +} + +/* 借用值 → 自持:凡要把读回的 XValue 存入生命周期超出本指令的结构(如 decode 缓存的指令 + * 字面量),必须先落地,否则 kvspace 借用池回收后指针悬空。 */ +void kvlangXvalueMaterialize(kvlangXvalue_t *v) { + if (v->borrowed && v->data && v->len > 0) { + uint8_t *o = malloc(v->len); + memcpy(o, v->data, v->len); + v->data = o; + } + v->borrowed = 0; } /* 解析 kindexpr 内容 → (dims, base kind)。kindexpr 为 NUL 终止串、无前缀(ref 归 head.ref)。 */ @@ -168,38 +182,14 @@ const uint8_t *kvlangXvalueBody(const kvlangXvalue_t *v, const kvspaceHead_t *h, return v->data + off; } -bool kvlangXvalueIsCharKind(const char *kind) { return strncmp(kind, "char/", 5) == 0; } -bool kvlangXvalueIsIntKind(const char *kind) { - return strcmp(kind, KVSPACE_KIND_INT8) == 0 || strcmp(kind, KVSPACE_KIND_INT16) == 0 || - strcmp(kind, KVSPACE_KIND_INT32) == 0 || strcmp(kind, KVSPACE_KIND_INT64) == 0; -} -bool kvlangXvalueIsUintKind(const char *kind) { - return strcmp(kind, KVSPACE_KIND_UINT8) == 0 || strcmp(kind, KVSPACE_KIND_UINT16) == 0 || - strcmp(kind, KVSPACE_KIND_UINT32) == 0 || strcmp(kind, KVSPACE_KIND_UINT64) == 0; -} -bool kvlangXvalueIsFloatKind(const char *kind) { - return strcmp(kind, KVSPACE_KIND_FLOAT32) == 0 || strcmp(kind, KVSPACE_KIND_FLOAT64) == 0; -} -bool kvlangXvalueIsNumKind(const char *kind) { - return kvlangXvalueIsIntKind(kind) || kvlangXvalueIsUintKind(kind) || kvlangXvalueIsFloatKind(kind); -} +/* kind 分类:经 langtypetable intern 成 id 后整数区间判定(替代旧 strcmp 链)。 */ +bool kvlangXvalueIsCharKind(const char *kind) { return kvlangLtIsChar(kvlangLangTypeId(kind, strlen(kind))); } +bool kvlangXvalueIsIntKind(const char *kind) { return kvlangLtIsSint(kvlangLangTypeId(kind, strlen(kind))); } +bool kvlangXvalueIsUintKind(const char *kind) { return kvlangLtIsUint(kvlangLangTypeId(kind, strlen(kind))); } +bool kvlangXvalueIsFloatKind(const char *kind) { return kvlangLtIsFloat(kvlangLangTypeId(kind, strlen(kind))); } +bool kvlangXvalueIsNumKind(const char *kind) { return kvlangLtIsNum(kvlangLangTypeId(kind, strlen(kind))); } -int32_t kvlangXvalueElemSize(const char *kind) { - if (strcmp(kind, KVSPACE_KIND_INT8) == 0 || strcmp(kind, KVSPACE_KIND_UINT8) == 0 || - strcmp(kind, KVSPACE_KIND_CHAR_UTF8) == 0 || strcmp(kind, KVSPACE_KIND_CHAR_ASCII) == 0 || - strcmp(kind, KVSPACE_KIND_BOOL) == 0) - return 1; - if (strcmp(kind, KVSPACE_KIND_INT16) == 0 || strcmp(kind, KVSPACE_KIND_UINT16) == 0) - return 2; - if (strcmp(kind, KVSPACE_KIND_INT32) == 0 || strcmp(kind, KVSPACE_KIND_UINT32) == 0 || - strcmp(kind, KVSPACE_KIND_FLOAT32) == 0 || strcmp(kind, KVSPACE_KIND_CHAR) == 0) - return 4; - if (strcmp(kind, KVSPACE_KIND_INT64) == 0 || strcmp(kind, KVSPACE_KIND_UINT64) == 0 || - strcmp(kind, KVSPACE_KIND_FLOAT64) == 0 || strcmp(kind, KVSPACE_KIND_TIME) == 0 || - strcmp(kind, KVSPACE_KIND_DURATION) == 0) - return 8; - return 0; -} +int32_t kvlangXvalueElemSize(const char *kind) { return kvlangLtElemSize(kvlangLangTypeId(kind, strlen(kind))); } static const uint8_t *v_body(const kvlangXvalue_t *v, kvspaceHead_t *h) { if (kvlangXvalueDecodeHeadRaw(v->data, v->len, h) < 0) @@ -207,89 +197,83 @@ static const uint8_t *v_body(const kvlangXvalue_t *v, kvspaceHead_t *h) { return v->data + h->body_offset; } -int64_t kvlangXvalueAsInt64(const kvlangXvalue_t *v) { +/* 0copy 标量视图:decode head 一次,返回 langtype id + 指向 body 首字节的借用指针。 */ +kvlangScalar_t kvlangXvalueScalar(const kvlangXvalue_t *v) { + kvlangScalar_t s = {KVLANG_LT_NONE, NULL, 0}; if (kvlangXvalueNone(v)) - return 0; + return s; kvspaceHead_t h; const uint8_t *b = v_body(v, &h); + if (!b) + return s; + kvlang_kindexpr_t kx; + kvlang_kindexpr_parse(h.kindexpr, &kx); + s.id = kvlangLangTypeId(kx.kind, (size_t)kx.kind_len); + s.body = b; + s.len = h.body_len; + return s; +} + +/* 按 langtype id 直接从 body 指针读标量(0copy)。body==NULL → 0。 */ +int64_t kvlangScalarReadI64(int id, const uint8_t *b) { if (!b) return 0; - const char *k = kvlangXvalueKind(v); - if (strcmp(k, KVSPACE_KIND_BOOL) == 0) - return b[0] != 0; - if (strcmp(k, KVSPACE_KIND_INT8) == 0) - return (int8_t)b[0]; - if (strcmp(k, KVSPACE_KIND_INT16) == 0) - return (int16_t)rd16(b); - if (strcmp(k, KVSPACE_KIND_INT32) == 0) - return (int32_t)rd32(b); - if (strcmp(k, KVSPACE_KIND_INT64) == 0) - return (int64_t)rd64(b); - if (strcmp(k, KVSPACE_KIND_UINT8) == 0) - return b[0]; - if (strcmp(k, KVSPACE_KIND_UINT16) == 0) - return rd16(b); - if (strcmp(k, KVSPACE_KIND_UINT32) == 0) - return rd32(b); - if (strcmp(k, KVSPACE_KIND_UINT64) == 0) - return (int64_t)rd64(b); - if (strcmp(k, KVSPACE_KIND_FLOAT32) == 0) { + switch (id) { + case KVLANG_LT_BOOL: return b[0] != 0; + case KVLANG_LT_INT8: return (int8_t)b[0]; + case KVLANG_LT_INT16: return (int16_t)rd16(b); + case KVLANG_LT_INT32: return (int32_t)rd32(b); + case KVLANG_LT_INT64: return (int64_t)rd64(b); + case KVLANG_LT_UINT8: return b[0]; + case KVLANG_LT_UINT16: return rd16(b); + case KVLANG_LT_UINT32: return rd32(b); + case KVLANG_LT_UINT64: return (int64_t)rd64(b); + case KVLANG_LT_FLOAT32: { float f; uint32_t u = rd32(b); memcpy(&f, &u, 4); return (int64_t)f; } - if (strcmp(k, KVSPACE_KIND_FLOAT64) == 0) { + case KVLANG_LT_FLOAT64: { double d; uint64_t u = rd64(b); memcpy(&d, &u, 8); return (int64_t)d; } - if (strcmp(k, KVSPACE_KIND_TIME) == 0 || strcmp(k, KVSPACE_KIND_DURATION) == 0) - return (int64_t)rd64(b); - return 0; + case KVLANG_LT_TIME: + case KVLANG_LT_DURATION: return (int64_t)rd64(b); + default: return 0; + } } -double kvlangXvalueAsFloat64(const kvlangXvalue_t *v) { - if (kvlangXvalueNone(v)) - return 0; - kvspaceHead_t h; - const uint8_t *b = v_body(v, &h); +double kvlangScalarReadF64(int id, const uint8_t *b) { if (!b) return 0; - const char *k = kvlangXvalueKind(v); - if (strcmp(k, KVSPACE_KIND_FLOAT32) == 0) { + if (id == KVLANG_LT_FLOAT32) { float f; uint32_t u = rd32(b); memcpy(&f, &u, 4); return f; } - if (strcmp(k, KVSPACE_KIND_FLOAT64) == 0) { + if (id == KVLANG_LT_FLOAT64) { double d; uint64_t u = rd64(b); memcpy(&d, &u, 8); return d; } - return (double)kvlangXvalueAsInt64(v); + return (double)kvlangScalarReadI64(id, b); } -uint64_t kvlangXvalueAsUint64(const kvlangXvalue_t *v) { - if (kvlangXvalueNone(v)) - return 0; - kvspaceHead_t h; - const uint8_t *b = v_body(v, &h); +uint64_t kvlangScalarReadU64(int id, const uint8_t *b) { if (!b) return 0; - const char *k = kvlangXvalueKind(v); - if (strcmp(k, KVSPACE_KIND_UINT8) == 0) - return b[0]; - if (strcmp(k, KVSPACE_KIND_UINT16) == 0) - return rd16(b); - if (strcmp(k, KVSPACE_KIND_UINT32) == 0) - return rd32(b); - if (strcmp(k, KVSPACE_KIND_UINT64) == 0) - return rd64(b); - return (uint64_t)kvlangXvalueAsInt64(v); + switch (id) { + case KVLANG_LT_UINT8: return b[0]; + case KVLANG_LT_UINT16: return rd16(b); + case KVLANG_LT_UINT32: return rd32(b); + case KVLANG_LT_UINT64: return rd64(b); + default: return (uint64_t)kvlangScalarReadI64(id, b); + } } uint32_t kvlangXvalueChar32At(const kvlangXvalue_t *v, int32_t idx) { @@ -450,7 +434,7 @@ char *kvlangXvalueValueString(const kvlangXvalue_t *v) { } if (strcmp(k, KVSPACE_KIND_FLOAT32) == 0 || strcmp(k, KVSPACE_KIND_FLOAT64) == 0) { char tmp[64]; - kvlangFormatFloat(tmp, sizeof tmp, kvlangXvalueAsFloat64(v)); + kvlangFormatFloat(tmp, sizeof tmp, kvlangScalarF64(kvlangXvalueScalar(v))); return strdup(tmp); } if (strcmp(k, KVSPACE_KIND_CHAR_UTF8) == 0 || strcmp(k, KVSPACE_KIND_CHAR_ASCII) == 0) @@ -495,6 +479,7 @@ void kvlangXvalueNewTlv(kvlangXvalue_t *v, const char *kind, const uint8_t *raw, uint32_t len; v->data = kvlangXvalueEncodeTlv(kind, raw, raw_len, al, &len); v->len = len; + v->borrowed = 0; } /* 显式 ndim/dims 构造(保留多维 shape,供 xv.shape/xv.set 用)。 */ @@ -503,8 +488,7 @@ void kvlangXvalueNewTlvDims(kvlangXvalue_t *v, const char *kind, const uint8_t * uint8_t *tmp = NULL; uint32_t tl = 0; if (kvspaceTlvEncode(kind, raw, raw_len, dims, ndim, &tmp, &tl) != 0 || !tmp) { - v->data = NULL; - v->len = 0; + kvlangXvalueZero(v); return; } uint8_t *buf = malloc(tl); @@ -512,6 +496,7 @@ void kvlangXvalueNewTlvDims(kvlangXvalue_t *v, const char *kind, const uint8_t * free(tmp); v->data = buf; v->len = tl; + v->borrowed = 0; } void kvlangXvalueNewInt64(kvlangXvalue_t *v, int64_t n) { @@ -564,12 +549,12 @@ void kvlangXvalueNewPtr(kvlangXvalue_t *v, const char *target_kindexpr, const ch uint8_t *tmp = NULL; uint32_t tl = 0, len = 0; if (kvspaceNewPtr(target_kindexpr, target, &tmp, &tl) != 0) { - v->data = NULL; - v->len = 0; + kvlangXvalueZero(v); return; } v->data = kvlangXvalueOwn(tmp, tl, &len); v->len = len; + v->borrowed = 0; } void kvlangXvalueNewRwir(kvlangXvalue_t *v, int32_t nr, int32_t nw, const char *sig) { size_t sl = strlen(sig);