diff --git a/runtimec2/include/vmbin.hpp b/runtimec2/include/vmbin.hpp index 3bdc0266..e728cd15 100644 --- a/runtimec2/include/vmbin.hpp +++ b/runtimec2/include/vmbin.hpp @@ -128,6 +128,10 @@ struct FReg { // src_ptr:读参 → 调用方 reg(只读转发);dst_ptr:写参 → 调用方 reg(写转发)。 FReg* src_ptr = nullptr; FReg* dst_ptr = nullptr; + // 成员 base 缓存:base 槽值是否为 Ptr(member_read/write 热路径——binary_trees/ + // hash_table 动态键 `L·*k` 每次免 kvspace read_wire_raw 检查)。写后失效。 + bool base_ptr = false; + bool base_ptr_known = false; // compact 数组布局缓存(xv·at/set 首次 decode 后复用:dims/esz/kind 恒定, // quicksort 1728 次 at + 1492 次 set 免每次 strtoll/substr 解析)。 std::uint32_t arr_esz = 0; diff --git a/runtimec2/src/rwir_gen.cpp b/runtimec2/src/rwir_gen.cpp index b1bce55b..c03797c4 100644 --- a/runtimec2/src/rwir_gen.cpp +++ b/runtimec2/src/rwir_gen.cpp @@ -207,7 +207,7 @@ const Entry myrwircaps[] = { {"string·parseuint", Op::None, Kind::None, 0, Class::Complex, Impl::Native}, {"string·set", Op::None, Kind::None, 0, Class::Complex, Impl::Native}, {"string·slice", Op::None, Kind::None, 0, Class::Complex, Impl::Native}, - {"struct·new", Op::None, Kind::None, 0, Class::Complex, Impl::Handoff}, + {"struct·new", Op::None, Kind::None, 0, Class::Complex, Impl::Native}, {"sub", Op::Sub, Kind::Any, 0, Class::Complex, Impl::Dynamic}, {"time/duration·add", Op::None, Kind::None, 0, Class::Complex, Impl::Native}, {"time/duration·after", Op::None, Kind::None, 0, Class::Complex, Impl::Native}, diff --git a/runtimec2/src/vmkv.cpp b/runtimec2/src/vmkv.cpp index 1ea4b38b..666c7bf1 100644 --- a/runtimec2/src/vmkv.cpp +++ b/runtimec2/src/vmkv.cpp @@ -89,15 +89,20 @@ bool Vmkv::resolve_desc(FrameCtx& f, const std::string& name, std::string* key, const std::uint8_t* ad = nullptr; std::uint32_t an = 0; if (!read_wire_raw(f.h, target, &ad, &an)) { - *err = "operand: arg Ptr missing: " + target; - return false; + // arg 槽缺失 = 空指针(None 在 shm 即无键):key 指回 arg 槽, + // 读取自然返回 None,不是错误(`inorder(None)` 传空指针参数)。 + *key = target; + return true; } + // 读参(`*[0,-k]`)取 arg 槽本体(Ptr→调用方槽,一跳):`head -> cur` + // 复制的是指针;两跳会落到调用方实例。写参(`*[0,k]`)才两跳取地址。 + const bool read_arg = member.size() >= 4 && member[3] == '-'; Wire aw{ad, an}; std::string t2; - if (v_ptr_target(aw, &t2)) { + if (!read_arg && v_ptr_target(aw, &t2)) { *key = t2; // 写参 Ptr 链:arg 槽 Ptr → 调用方槽 } else { - *key = target; // 读参传值:arg 槽即值槽(本帧,view 缓存) + *key = target; // 读参:arg 槽即 Ptr/值槽(本帧,view 缓存) } return true; } @@ -179,6 +184,15 @@ thread_local std::uint32_t g_none_len = 0; // 帧入口解析会过早失败)。读写共用同一入口。 bool Vmkv::ensure_reg_key(FrameCtx& f, FReg& r) { if (r.key.empty()) { + // 内存别名写参(dst_ptr 链):key = 调用方 reg 最终槽(纯内存帧无 arg 槽, + // `p·x = v` 的 p 写参直接落在调用方实例成员上)。 + FReg* ap = &r; + while (ap->dst_ptr) + ap = ap->dst_ptr; + if (ap != &r && !ap->key.empty()) { + r.key = ap->key; + return true; + } // 普通变量(desc_ref):key = frame + "/" + name(一次轻拼接,SSO)。 if (r.desc_ref) { // 绝对路径变量(`/lib/...` 顶层写槽):直接作 key,不拼 f.frame。 @@ -404,16 +418,82 @@ bool Vmkv::write_reg(FrameCtx& f, std::uint8_t idx, const std::uint8_t* data, if (dr.view_ok) { dr.view_ok = false; } + dr.base_ptr_known = false; char err[192] = {}; return kvspaceSetValue(f.h, dr.key.c_str(), data, len, 0, 0, err, sizeof err) == 0; } + // 成员写槽(desc 含 `·`,如 `p·x`):base 是帧变量/参数(可能 dst_ptr 别名 + // 指向调用方实例),key = 最终 base 槽 + `·` + 成员名(`p·x = v` 就地改 + // 调用方对象,见 ptr-param-mutate)。绝对路径 base(`/tmp/x·y`)直接用。 + const std::string& wdsc = !r.desc.empty() ? r.desc + : (r.desc_ref ? r.desc_ref->name : r.desc); + if (wdsc.find("\xC2\xB7") != std::string::npos && wdsc[0] != '/') { + const auto mid = wdsc.find("\xC2\xB7"); + const std::string base_part = wdsc.substr(0, mid); + const std::string mname = wdsc.substr(mid + 2); + // base 对应的 reg:desc 名匹配(`p` 参数/变量)→ 沿 src/dst 别名链到最终槽 + // (`p·x` 的 p 写参 dst_ptr→调用方 a)。 + FReg* bp = &r; + for (FReg& rr : f.regs) { + const std::string rn = !rr.desc.empty() ? rr.desc + : (rr.desc_ref ? rr.desc_ref->name : std::string()); + if (rn == base_part || rr.key == f.frame + "/" + base_part) { + bp = &rr; + break; + } + } + while (bp->src_ptr || bp->dst_ptr) + bp = bp->src_ptr ? bp->src_ptr : bp->dst_ptr; + // base 名未匹配(写槽 `p·x` 的 p 是 `*[0,1]` 写参描述符):取已解析到 + // 调用方实例的写参 reg 链作 base(成员写就地改调用方对象)。 + if (bp == &r || bp->key.empty()) { + for (FReg& rr : f.regs) { + const std::string rn = !rr.desc.empty() ? rr.desc + : (rr.desc_ref ? rr.desc_ref->name + : std::string()); + if (rn.rfind("*[0,", 0) == 0) { + FReg* rp = &rr; + while (rp->src_ptr || rp->dst_ptr) + rp = rp->src_ptr ? rp->src_ptr : rp->dst_ptr; + if (rp->key.empty() && !ensure_reg_key(f, *rp)) + continue; + if (!rp->key.empty()) { + bp = rp; + break; + } + } + } + } + if (bp->key.empty() && !ensure_reg_key(f, *bp)) + return false; + // base 槽是 Ptr(`cur->next = v` 的 cur 存指针):成员写落在 target 上。 + if (!bp->key.empty()) { + const std::uint8_t* bd = nullptr; + std::uint32_t bn = 0; + std::string bt; + if (read_wire_raw(f.h, bp->key, &bd, &bn) && + v_ptr_target(Wire{bd, bn}, &bt) && !bt.empty()) + bp->key = bt; + } + if (!bp->key.empty() && !mname.empty() && mname[0] != '*') { + r.key = bp->key + "\xC2\xB7" + mname; + r.view_ok = false; + r.sc_ok = false; + r.fast_i64 = false; + r.fast_bool = false; + char errb[192] = {}; + return kvspaceSetValue(f.h, r.key.c_str(), data, len, 0, 0, errb, + sizeof errb) == 0; + } + } if (!ensure_reg_key(f, r)) return false; r.view_ok = false; r.sc_ok = false; r.fast_i64 = false; r.fast_bool = false; + r.base_ptr_known = false; // 槽值可能变 Ptr/非 Ptr,成员 base 缓存失效 // 帧局部 int64 变量:内存化写(FReg.fv + 槽直写若已有 view),层内读走 fast // 缓存,免每 op kvspace 往返(fib/binary_search 热点)。参数/绝对路径/系统槽照旧。 const std::string& rk = r.key; @@ -982,6 +1062,8 @@ bool Vmkv::enter_frame(FrameCtx& f, const Segment* seg, std::string* err) { rr.arr_dims[4] = rr.arr_dims[5] = rr.arr_dims[6] = rr.arr_dims[7] = 0; rr.arr_ndim = 0; rr.arr_kind = 0; + rr.base_ptr = false; + rr.base_ptr_known = false; rr.key.clear(); rr.desc.clear(); rr.desc_ref = nullptr; @@ -1016,6 +1098,7 @@ bool Vmkv::enter_frame(FrameCtx& f, const Segment* seg, std::string* err) { // 零 kvspace;未命中(容器/扩展参数)回退 kvspace 原路径。 // 槽号 build 已预解析(d.param_k),帧入口零 substr/atoi // (fib 递归每帧 12+ reg,字符串解析是 setup 大头)。 + f.regs[i].desc_ref = &d; // 成员写 base 匹配(`p·x` 的 p→`*[0,1]`) const int k = d.param_k; FReg* ap = nullptr; if (k < 0 && static_cast(-k) <= @@ -1037,7 +1120,13 @@ bool Vmkv::enter_frame(FrameCtx& f, const Segment* seg, std::string* err) { } else { f.regs[i].dst_ptr = ap; } - f.regs[i].key.clear(); + // 写参别名:key 直接继承调用方实例槽(成员写 `p·x = v` 的 + // base p 经 f.regs 遍历能取到最终 key)。读参别名 key 留空 + // (值转发走 src_ptr,读穿透到目标)。 + if (k > 0 && ap && !ap->key.empty()) + f.regs[i].key = ap->key; + else + f.regs[i].key.clear(); if (std::getenv("RC2_TRACE")) std::fprintf(stderr, "[argmem d=%s k=%d %s]\n", d.name.c_str(), k, @@ -1625,8 +1714,9 @@ RunResult Vmkv::run_frame(FrameCtx& f, int start_s0, bool none0 = false, none1 = false; if (ins.op != ops::Op::Copy) { for (int i = 0; i < ins.nrd; i++) { - if (read_scalar(f, ins.rd[i], &s[i])) + if (read_scalar(f, ins.rd[i], &s[i])) { continue; + } if (!read_reg(f, ins.rd[i], &w[i])) { *err = "operand " + std::to_string(i) + " is missing"; return RunResult::Error; @@ -1640,7 +1730,9 @@ RunResult Vmkv::run_frame(FrameCtx& f, int start_s0, } bool ok = true; // None 参与比较:对齐 C 语义(Eq:双 None=true;Neq:双 None=false;其余 → TypeError)。 - if ((none0 || none1) && is_cmp(ins.op)) { + // Ptr vs None(Ptr 悬空=空指针)交给 non_scalar 的 Ptr 分支,不在此判。 + const bool any_ptr_cmp = (v_ptr(w[0]) || v_ptr(w[1])) && is_cmp(ins.op); + if (!any_ptr_cmp && (none0 || none1) && is_cmp(ins.op)) { if (ins.op == ops::Op::Eq) ok = slot_write_bool(f, ins.wr[0], none0 && none1); else if (ins.op == ops::Op::Neq) @@ -1694,47 +1786,83 @@ RunResult Vmkv::run_frame(FrameCtx& f, int start_s0, // 动态算子按运行时类型分派:`+` 对 char 族即字符串拼接; // `==`/`!=` 对 char 族按文本比较产 bool。 std::string a, b; - if (ins.nrd == 2 && (ins.op == ops::Op::Eq || ins.op == ops::Op::Neq) && - wire_text(w[0].d, w[0].n, &a) && - wire_text(w[1].d, w[1].n, &b)) { - const bool eq = a == b; - ok = slot_write_bool(f, ins.wr[0], ins.op == ops::Op::Eq ? eq : !eq); + if (ins.nrd == 2 && (ins.op == ops::Op::Eq || ins.op == ops::Op::Neq)) { + // Ptr 参与比较:指针本体 vs None(空指针检查)或 Ptr 间按 target 比 + // (链表 `cur != None` / `h·next == &n2`)。读参 w[i] 可能已被 + // resolve 穿透成目标值——按 Ptr target 判空与相等。 + const bool p0 = v_ptr(w[0]), p1 = v_ptr(w[1]); + if (p0 || p1) { + // Ptr 为空 = target 槽缺失/None(`walk(None)` 的 arg 槽 + // Ptr→nil 槽是空指针,`node != None` 须 false)。 + auto ptr_empty = [&](const Wire& pw) -> bool { + std::string t; + if (!v_ptr_target(pw, &t) || t.empty()) + return true; + const std::uint8_t* td = nullptr; + std::uint32_t tn = 0; + return !read_wire(f.h, t, &td, &tn) || + v_is_none(Wire{td, tn}); + }; + const bool e0 = ptr_empty(w[0]); + const bool e1 = ptr_empty(w[1]); + std::string pt0, pt1; + const bool h0 = v_ptr_target(w[0], &pt0); + const bool h1 = v_ptr_target(w[1], &pt1); + const bool eq = p0 && p1 + ? (e0 && e1) || (!e0 && !e1 && pt0 == pt1) + : p0 ? e0 : e1; + ok = slot_write_bool(f, ins.wr[0], + ins.op == ops::Op::Eq ? eq : !eq); + if (bin.prof_on) { + const std::uint64_t d2 = bin.now() - t0; + bin.prof.handler += d2; + bin.prof.steps++; + bin.prof_tick(ins.prof_id, d2, 0); + } + continue; + } + if (wire_text(w[0].d, w[0].n, &a) && + wire_text(w[1].d, w[1].n, &b)) { + const bool eq = a == b; + ok = slot_write_bool(f, ins.wr[0], + ins.op == ops::Op::Eq ? eq : !eq); + if (bin.prof_on) { + const std::uint64_t dh = bin.now() - t0; + bin.prof.handler += dh; + bin.prof.steps++; + bin.prof_tick(ins.prof_id, dh, 0); + } + continue; + } + if (ins.op != ops::Op::Add || ins.nrd != 2 || + !wire_text(w[0].d, w[0].n, &a) || + !wire_text(w[1].d, w[1].n, &b)) { + *err = "non-scalar operand: " + ins.name; + return RunResult::Error; + } + const std::string out_s = a + b; + const std::int32_t dims[1] = {static_cast(out_s.size())}; + std::uint8_t* buf = nullptr; + std::uint32_t len = 0; + ok = kvspaceXvalueEncode( + "char/utf8", + reinterpret_cast(out_s.data()), + static_cast(out_s.size()), dims, 1, + &buf, &len) == 0 && + buf && write_reg(f, ins.wr[0], buf, len); + std::free(buf); if (bin.prof_on) { const std::uint64_t dh = bin.now() - t0; bin.prof.handler += dh; bin.prof.steps++; bin.prof_tick(ins.prof_id, dh, 0); } + if (!ok) { + *err = "value op failed: " + ins.name; + return RunResult::Error; + } continue; } - if (ins.op != ops::Op::Add || ins.nrd != 2 || - !wire_text(w[0].d, w[0].n, &a) || - !wire_text(w[1].d, w[1].n, &b)) { - *err = "non-scalar operand: " + ins.name; - return RunResult::Error; - } - const std::string out_s = a + b; - const std::int32_t dims[1] = {static_cast(out_s.size())}; - std::uint8_t* buf = nullptr; - std::uint32_t len = 0; - ok = kvspaceXvalueEncode( - "char/utf8", - reinterpret_cast(out_s.data()), - static_cast(out_s.size()), dims, 1, &buf, - &len) == 0 && - buf && write_reg(f, ins.wr[0], buf, len); - std::free(buf); - if (bin.prof_on) { - const std::uint64_t dh = bin.now() - t0; - bin.prof.handler += dh; - bin.prof.steps++; - bin.prof_tick(ins.prof_id, dh, 0); - } - if (!ok) { - *err = "value op failed: " + ins.name; - return RunResult::Error; - } - continue; } } // 动态键:Ptr 参数先解引用取 target 槽值(链最多 2 跳);int64/标量 → @@ -1838,6 +1966,8 @@ RunResult Vmkv::run_frame(FrameCtx& f, int start_s0, // 成员读:base(读参0 的值或 Ptr 目标 key)+ key(读参1 的值)。 Wire bw{}; std::string base_key; + FReg& br0 = f.regs[ins.rd[0]]; + FReg& br0f = br0.src_ptr ? *br0.src_ptr : br0; if (read_reg(f, ins.rd[0], &bw)) { std::string bt; if (v_ptr_target(bw, &bt)) { @@ -1846,8 +1976,22 @@ RunResult Vmkv::run_frame(FrameCtx& f, int start_s0, bt[0] == '/') { // 字面量路径 base(`char/utf32:/tmp/up`)→ 直接取文本。 base_key = bt; - } else if (f.regs[ins.rd[0]].key.size() > 5) { - base_key = f.regs[ins.rd[0]].key; + } else { + // 帧局部变量(惰性 key 未解析):ensure 后取实例槽路径 + // (`n3·val` 在 n3 只经 struct·new 写、无明文值时 key 仍空)。 + if (ensure_reg_key(f, br0) && br0.key.size() > 5) + base_key = br0.key; + // Ptr 参数(key=arg 槽):read_reg 已穿透成实例,raw 读回 + // Ptr 本体取 target(`p·x` 的 p 是 *点 读参)。 + if (br0f.key.size() > 5) { + const std::uint8_t* rd2 = nullptr; + std::uint32_t rn2 = 0; + std::string t2; + if (read_wire_raw(f.h, br0f.key, &rd2, &rn2) && + v_ptr_target(Wire{rd2, rn2}, &t2) && + !t2.empty()) + base_key = t2; + } } } Wire kw{}; @@ -1855,10 +1999,12 @@ RunResult Vmkv::run_frame(FrameCtx& f, int start_s0, if (!base_key.empty() && read_reg(f, ins.rd[1], &kw) && key_str(kw, &kstr) && !kstr.empty()) { // 容器成员 key = base·name(· 中点键,对齐 C kvlangKeytreeMember)。 + // 值读用 raw(resolve=0):成员是 Ptr 时须取 Ptr 本体(链表 + // `cur·next -> cur` 拿指针),穿透会得到目标值。 const std::string mkey = base_key + "\xC2\xB7" + kstr; const std::uint8_t* md = nullptr; std::uint32_t mn = 0; - if (read_wire(f.h, mkey, &md, &mn) && md && mn) { + if (read_wire_raw(f.h, mkey, &md, &mn) && md && mn) { ok = write_reg(f, ins.wr[0], md, mn); } else { // 缺失成员 → None(容器成员可能未建)。 @@ -1918,10 +2064,91 @@ RunResult Vmkv::run_frame(FrameCtx& f, int start_s0, } // base 槽 key = 帧局部变量名(arr 是帧变量,key=frame/arr); // `/` 开头 = 绝对路径字面量 base(如 /tmp/two_sum·*x),直接用。 - const std::string base_key = - !base_part.empty() && base_part[0] == '/' - ? base_part - : f.frame + "/" + base_part; + // 参数 Ptr 别名(`*[0,±k]` / `*p`):取调用方 reg 链的最终 key + // (`p·x = v` 的 p 是 src_ptr 别名 → 写调用方实例成员)。 + std::string base_key; + if (!base_part.empty() && base_part[0] == '/') { + base_key = base_part; + } else { + const std::string fbp = f.frame + "/" + base_part; + // 先精确匹配 base 名(`cur·next` 的 cur 局部变量),失败才回退 + // 写参 Ptr(`*[0,±k]`:`r·x` 的 r 是写参)——顺序不可反。 + // 无字符串拷贝:desc_ref 指针/name 直接比较,key 前缀匹配。 + FReg* base_reg = nullptr; + for (FReg& r : f.regs) { + if ((r.desc_ref && r.desc_ref->name == base_part) || + r.key == fbp || + (!r.desc.empty() && r.desc == base_part)) { + base_reg = &r; + break; + } + } + if (base_reg) { + FReg* rk = base_reg; + while (rk->src_ptr || rk->dst_ptr) + rk = rk->src_ptr ? rk->src_ptr : rk->dst_ptr; + if (!rk->key.empty()) { + // base 槽是 Ptr(`cur·next` 的 cur 存指针):成员写落 + // target。首查后缓存(热路径动态键容器免每写 kvspace)。 + if (!rk->base_ptr_known) { + const std::uint8_t* bd = nullptr; + std::uint32_t bn = 0; + std::string bt; + rk->base_ptr = + read_wire_raw(f.h, rk->key, &bd, &bn) && + v_ptr_target(Wire{bd, bn}, &bt) && !bt.empty(); + rk->base_ptr_known = true; + } + if (rk->base_ptr) { + const std::uint8_t* bd = nullptr; + std::uint32_t bn = 0; + std::string bt; + if (read_wire_raw(f.h, rk->key, &bd, &bn) && + v_ptr_target(Wire{bd, bn}, &bt)) + base_key = bt; + else + base_key = rk->key; + } else { + base_key = rk->key; + } + } + } else { + base_key = fbp; + } + if (base_key == f.frame + "/" + base_part) { + for (FReg& r : f.regs) { + const std::string rn = !r.desc.empty() ? r.desc + : (r.desc_ref ? r.desc_ref->name + : std::string()); + if (rn.rfind("*[0,", 0) == 0 && !r.key.empty()) { + FReg* rk = &r; + while (rk->src_ptr || rk->dst_ptr) + rk = rk->src_ptr ? rk->src_ptr : rk->dst_ptr; + if (!rk->key.empty()) { + base_key = rk->key; + break; + } + } + } + } + // 写参 base 无独立 reg(`造点(a,b) -> (r:*点)` 的 r 只出现在 + // `r·x` 写槽,layout 不生成 `*[0,1]` reg):读本帧写参 arg 槽 + // (do_call 绑定 `‥arg[0,k]` 存 Ptr→调用方槽)取 target。 + if (base_key == f.frame + "/" + base_part) { + for (int k2 = 1; k2 <= 4; k2++) { + const std::string ak = f.frame + "/\xE2\x80\xA5" "arg[0," + + std::to_string(k2) + "]"; + const std::uint8_t* ad2 = nullptr; + std::uint32_t an2 = 0; + std::string at; + if (read_wire_raw(f.h, ak, &ad2, &an2) && + v_ptr_target(Wire{ad2, an2}, &at) && !at.empty()) { + base_key = at; + break; + } + } + } + } if (base_key.empty()) { *err = "member write: no base: " + ins.name; return RunResult::Error; @@ -1936,8 +2163,19 @@ RunResult Vmkv::run_frame(FrameCtx& f, int start_s0, ok = kvspaceSetValue(f.h, mkey.c_str(), kw.d, kw.n, 0, 0, e, sizeof e) == 0; } else { + // 普通单参赋值(`a -> b`):复制**槽本体**(Ptr 不穿透——链表 + // `head -> cur` 复制指针,穿透会拿到目标实例)。普通值 raw 同值。 Wire src{}; - if (read_reg(f, ins.rd[0], &src)) { + FReg& sr0 = regs[ins.rd[0]]; + FReg& srf = sr0.src_ptr ? *sr0.src_ptr : sr0; + const std::uint8_t* rawd = nullptr; + std::uint32_t rawn = 0; + if (!srf.key.empty() && + read_wire_raw(f.h, srf.key, &rawd, &rawn) && rawd && rawn) { + src.d = rawd; + src.n = rawn; + ok = write_reg(f, ins.wr[0], src.d, src.n); + } else if (read_reg(f, ins.rd[0], &src)) { ok = write_reg(f, ins.wr[0], src.d, src.n); } else { // 未赋值变量读作 None:整体写 None XValue,不是错误。 @@ -2201,6 +2439,60 @@ bin::RunResult Vmkv::do_call(FrameCtx& f, const Segment* seg, const CInsn& ins, mk_done = true; } if (x < 0 && !container_arg) { + // Ptr 类型读参(`*T`):arg 槽存 Ptr→调用方槽(`求和(a)` 的 a 是 + // 值实例;&n3 已 Ptr 则链 Ptr→target)。slot 恒 Ptr→arg。 + if (typ.size() >= 2 && typ[0] == '*') { + const std::uint8_t* pd = src.d; + std::uint32_t pn = src.n; + std::string pt; + const std::string pkind = typ.substr(1); + std::uint8_t* ap = nullptr; + std::uint32_t an = 0; + // src 已是 Ptr(&n3 传 _3 变量):arg 直接继承 Ptr→target。 + if (v_ptr_target(src, &pt) && !pt.empty()) { + bool bok = kvspaceNewPtr(pkind.c_str(), pt.c_str(), &ap, + &an) == 0; + if (!bok) { + *err = "bind: NewPtr(arg chain) failed"; + return false; + } + } else if (pd && pn) { + // 值实例:arg 槽 = Ptr→调用方槽。 + bool bok = value_key.empty() + ? false + : kvspaceNewPtr(pkind.c_str(), + value_key.c_str(), &ap, + &an) == 0; + if (!bok) { + *err = "bind: NewPtr(value) failed typ=" + typ; + return false; + } + } else { + *err = "bind: read arg value failed: " + value_key; + return false; + } + bool bok2 = kvspaceSetValue(f.h, arg_key.c_str(), ap, an, 0, 0, + be, sizeof be) == 0; + std::free(ap); + if (!bok2) { + *err = std::string("bind: set arg failed: ") + be; + return false; + } + std::uint8_t* sp = nullptr; + std::uint32_t sn = 0; + bool bok3 = kvspaceNewPtr(typ.c_str(), arg_key.c_str(), &sp, + &sn) == 0; + if (!bok3) { + *err = "bind: NewPtr(slot) failed"; + return false; + } + bok3 = kvspaceSetValue(f.h, slot.c_str(), sp, sn, 0, 0, be, + sizeof be) == 0; + std::free(sp); + if (!bok3) + *err = std::string("bind: set slot failed: ") + be; + return bok3; + } const std::uint8_t* vd = src.d; std::uint32_t vn = src.n; if (!vd || !vn) { @@ -2312,9 +2604,14 @@ bin::RunResult Vmkv::do_call(FrameCtx& f, const Segment* seg, const CInsn& ins, if (!jcode) for (int i = 1; i <= ins.nwr; i++) { FReg& wr = f.regs[ins.wr[i - 1]]; - if (!ensure_reg_key(f, wr)) + // 内存别名写参(dst_ptr,key 空)转发给非纯内存 callee:值在调用方 reg, + // 沿 dst_ptr 链取明文 key 作 NewPtr 目标(replace→replacen 转发链)。 + FReg* wrk = ≀ + while (wrk->key.empty() && wrk->dst_ptr) + wrk = wrk->dst_ptr; + if (!ensure_reg_key(f, *wrk)) return RunResult::Error; - const std::string vk = wr.key; + const std::string vk = wrk->key; std::string typ; if (!param_decl_type(i, &typ)) typ = "int64"; @@ -2358,6 +2655,28 @@ bin::RunResult Vmkv::do_call(FrameCtx& f, const Segment* seg, const CInsn& ins, RunResult rr = run_frame(nfc, 1, stop_pc, err); if (rr != RunResult::Ok && rr != RunResult::Returned) return rr; + // 写参回写分流失效:内存别名(mem_dst)标量直写调用方 reg,缓存即值; + // 其余经 kvspace 槽回写 → 调用方写参 fast 缓存陈旧,须逐级失效(重读槽), + // 否则下条指令的 fk 快路径读到旧值(title 每字符 isalpha 后 br 误判)。 + for (int i = 0; i < ins.nwr; i++) { + bool aliased = false; + for (int j = 0; j < mem_dst_n; j++) + if (mem_dst[j] == &f.regs[ins.wr[i]]) { + aliased = true; + break; + } + if (aliased) + continue; + FReg* wr = &f.regs[ins.wr[i]]; + do { + wr->fast_i64 = false; + wr->fast_bool = false; + wr->sc_ok = false; + wr->view_ok = false; + wr->resolved = false; + wr = wr->dst_ptr; + } while (wr); + } if (bin.prof_on) bin.prof.steps++; // 嵌套帧自身已计时,勿重复累计 return RunResult::Ok; diff --git a/runtimec2/src/vmkv_native.cpp b/runtimec2/src/vmkv_native.cpp index 158627a3..dc3ca4ce 100644 --- a/runtimec2/src/vmkv_native.cpp +++ b/runtimec2/src/vmkv_native.cpp @@ -942,6 +942,241 @@ bool h_string_ord(NativeCtx& c, std::string* err) { return c.vm.slot_write_i64(c.f, c.ins.wr[0], cp); } +// ── string 家族共用 ──────────────────────────────────────────────────────── +// UTF-8 文本 → 码点数组(无效序列按 0xFFFD,对齐 C utf8_decode_next)。 +std::vector utf8_to_runes(const std::string& s) { + std::vector r; + r.reserve(s.size()); + std::size_t i = 0; + while (i < s.size()) { + const std::uint32_t c0 = static_cast(s[i]); + std::uint32_t cp = c0, take = 1; + if (c0 < 0x80) cp = c0; + else if ((c0 >> 5) == 0x6) { cp = c0 & 0x1F; take = 2; } + else if ((c0 >> 4) == 0xE) { cp = c0 & 0x0F; take = 3; } + else if ((c0 >> 3) == 0x1E) { cp = c0 & 0x07; take = 4; } + else { cp = 0xFFFD; take = 1; } + if (i + take > s.size()) { cp = 0xFFFD; take = 1; } + for (std::size_t k = 1; k < take && i + k < s.size(); k++) + cp = (cp << 6) | (static_cast(s[i + k]) & 0x3F); + r.push_back(cp); + i += take; + } + return r; +} + +// 码点数组 → char/utf32 XValue → 写槽(字符串 ops 的统一输出)。 +bool write_runes(NativeCtx& c, const std::vector& r) { + const std::uint32_t n = static_cast(r.size()); + std::vector raw(static_cast(n) * 4, 0); + for (std::uint32_t i = 0; i < n; i++) + std::memcpy(raw.data() + static_cast(i) * 4, &r[i], 4); + const std::int32_t dims[1] = {static_cast(n)}; + std::uint8_t* out = nullptr; + std::uint32_t ol = 0; + const bool ok = kvspaceXvalueEncode( + "char/utf32", raw.data(), + static_cast(raw.size()), dims, 1, &out, + &ol) == 0 && + out && c.vm.write_reg(c.f, c.ins.wr[0], out, ol); + std::free(out); + return ok; +} + +// 读参必须是 char 族(剥 dims 前缀后 kind 为 char/*;对齐 C 的 char 判定)。 +bool is_char_wire(const Wire& w) { + std::string lt; + if (!v_langtype(w, <)) + return false; + const std::size_t close = lt.find(']'); + if (!lt.empty() && lt[0] == '[' && close != std::string::npos) + lt = lt.substr(close + 1); + return lt.rfind("char/", 0) == 0; +} + +bool h_string_cmp(NativeCtx& c, std::string* err) { + std::string a, b; + if (c.ins.nrd < 2 || !c.atext(0, &a) || !c.atext(1, &b)) { + *err = "string·cmp: bad input"; + return false; + } + const std::int64_t r = a < b ? -1 : a > b ? 1 : 0; + return c.vm.slot_write_i64(c.f, c.ins.wr[0], r); +} + +bool h_string_slice(NativeCtx& c, std::string* err) { + std::string s; + std::int64_t lo = 0, hi = 0; + if (c.ins.nrd < 3 || !c.atext(0, &s) || + !c.vm.read_i64(c.f, c.ins.rd[1], &lo) || + !c.vm.read_i64(c.f, c.ins.rd[2], &hi)) { + *err = "string·slice: bad input"; + return false; + } + const std::vector r = utf8_to_runes(s); + if (lo < 0 || hi > static_cast(r.size()) || lo > hi) { + *err = "string·slice: index out of bounds"; + return false; + } + return write_runes(c, std::vector(r.begin() + lo, r.begin() + hi)); +} + +bool h_string_find(NativeCtx& c, std::string* err) { + std::string hs, nd; + if (c.ins.nrd < 2 || !c.atext(0, &hs) || !c.atext(1, &nd)) { + *err = "string·find: bad input"; + return false; + } + const std::vector hay = utf8_to_runes(hs); + const std::vector ndl = utf8_to_runes(nd); + std::int64_t r = -1; + if (ndl.empty()) + r = 0; + else + for (std::size_t i = 0; i + ndl.size() <= hay.size(); i++) { + bool m = true; + for (std::size_t j = 0; j < ndl.size(); j++) + if (hay[i + j] != ndl[j]) { m = false; break; } + if (m) { r = static_cast(i); break; } + } + return c.vm.slot_write_i64(c.f, c.ins.wr[0], r); +} + +bool h_string_concat(NativeCtx& c, std::string* err) { + if (c.ins.nrd < 2 || !is_char_wire(c.in[0]) || !is_char_wire(c.in[1])) { + *err = "string·concat: requires strings"; + return false; + } + std::string a, b; + if (!c.atext(0, &a) || !c.atext(1, &b)) { + *err = "string·concat: bad input"; + return false; + } + return write_runes(c, utf8_to_runes(a + b)); +} + +// 对齐 C format_base:base 2..36,非法 base 回退 10;负数带 '-'。 +std::string format_base(std::uint64_t u, int base, bool neg) { + if (base < 2 || base > 36) + base = 10; + char tmp[65]; + int n = 0; + if (u == 0) + tmp[n++] = '0'; + while (u) { + const int d = static_cast(u % static_cast(base)); + tmp[n++] = static_cast(d < 10 ? '0' + d : 'a' + d - 10); + u /= static_cast(base); + } + std::string out; + if (neg) + out.push_back('-'); + for (int i = n - 1; i >= 0; i--) + out.push_back(tmp[i]); + return out; +} + +bool h_string_formatint(NativeCtx& c, std::string* err) { + std::int64_t v = 0, base = 10; + if (c.ins.nrd < 1 || !c.ai64(0, &v)) { + *err = "string·formatint: bad input"; + return false; + } + if (c.ins.nrd >= 2) + (void)c.ai64(1, &base); + const std::uint64_t u = + v < 0 ? static_cast(-(v + 1)) + 1 : static_cast(v); + return write_runes(c, utf8_to_runes(format_base(u, static_cast(base), v < 0))); +} + +bool h_string_formatuint(NativeCtx& c, std::string* err) { + std::int64_t v = 0, base = 10; + if (c.ins.nrd < 1 || !c.ai64(0, &v)) { + *err = "string·formatuint: bad input"; + return false; + } + if (c.ins.nrd >= 2) + (void)c.ai64(1, &base); + return write_runes(c, utf8_to_runes( + format_base(static_cast(v), + static_cast(base), false))); +} + +// 整串消费完(无尾随空白/垃圾),否则 ValueError(对齐 C strtoll 三查)。 +bool parse_consumed(const std::string& s, char* end, const char* start) { + return !s.empty() && end != start && *end == '\0'; +} + +bool h_string_parseint(NativeCtx& c, std::string* err) { + std::string s; + std::int64_t base = 10; + if (c.ins.nrd < 1 || !c.atext(0, &s)) { + *err = "string·parseint: bad input"; + return false; + } + if (c.ins.nrd >= 2) + (void)c.ai64(1, &base); + char* end = nullptr; + long long v = std::strtoll(s.c_str(), &end, static_cast(base)); + if (!parse_consumed(s, end, s.c_str())) { + *err = "ValueError: string·parseint: invalid syntax"; + return false; + } + return c.vm.slot_write_i64(c.f, c.ins.wr[0], static_cast(v)); +} + +bool h_string_parseuint(NativeCtx& c, std::string* err) { + std::string s; + std::int64_t base = 10; + if (c.ins.nrd < 1 || !c.atext(0, &s)) { + *err = "string·parseuint: bad input"; + return false; + } + if (c.ins.nrd >= 2) + (void)c.ai64(1, &base); + char* end = nullptr; + unsigned long long v = std::strtoull(s.c_str(), &end, static_cast(base)); + if (!parse_consumed(s, end, s.c_str())) { + *err = "ValueError: string·parseuint: invalid syntax"; + return false; + } + return c.vm.write_named_i64(c.f.h, c.ins.wr[0], c.f, "uint64", + static_cast(v)); +} + +bool h_string_parsefloat(NativeCtx& c, std::string* err) { + std::string s; + if (c.ins.nrd < 1 || !c.atext(0, &s)) { + *err = "string·parsefloat: bad input"; + return false; + } + char* end = nullptr; + double v = std::strtod(s.c_str(), &end); + if (!parse_consumed(s, end, s.c_str())) { + *err = "ValueError: string·parsefloat: invalid syntax"; + return false; + } + std::uint8_t raw[8]; + std::memcpy(raw, &v, 8); + std::uint8_t* buf = nullptr; + std::uint32_t len = 0; + const bool ok = kvspaceXvalueEncode("float64", raw, 8, nullptr, 0, &buf, + &len) == 0 && + buf && c.vm.write_reg(c.f, c.ins.wr[0], buf, len); + std::free(buf); + return ok; +} + +bool h_string_set(NativeCtx& c, std::string* err) { + // 对齐 C kvlangBuiltinStringSet:读参[0] 的显示文本写为 char/utf32。 + std::string s; + if (c.ins.nrd < 1 || !c.atext(0, &s)) { + *err = "string·set: bad input"; + return false; + } + return write_runes(c, utf8_to_runes(s)); +} + // ── ndarray 元数据(numel/dim/shape)────────────────────────────────────── bool h_array_meta(NativeCtx& c, std::string* err) { Wire aw{}; @@ -1380,6 +1615,131 @@ bool h_array_at_set(NativeCtx& c, std::string* err) { return false; } +// ── struct·new ───────────────────────────────────────────────────────────── +// 克隆 /lib/Name 原型子树到写槽,覆盖给定字段(校验字段存在性+类型)。 +// in[0]=structref("/lib/Name"),其后成对 (字段名, 值)。实例基值 langtype=structref。 +namespace { +// 剥 `[dims]` 前缀得裸 kind(字段类型与值类型比对用)。 +std::string bare_kind(const std::string& lt) { + if (!lt.empty() && lt[0] == '[') { + const std::size_t close = lt.find(']'); + if (close != std::string::npos) + return lt.substr(close + 1); + } + return lt; +} +} // namespace + +bool h_struct_new(NativeCtx& c, std::string* err) { + // ref 形参:绝对路径字面量(`/lib/Point`)的 RegDesc.name 即路径本体—— + // read_reg 会按 key 直达目标值(def struct 标记),不能当文本读;变量则读值。 + const RegDesc& rd0 = c.seg->regs[c.ins.rd[0]]; + std::string ref; + if (rd0.kind == Operand::Kind::Literal && !rd0.name.empty() && + rd0.name[0] == '/') { + ref = rd0.name.substr(0, rd0.name.find(' ')); + } else if (!c.atext(0, &ref) || ref.empty()) { + *err = "TypeError: struct·new requires a type"; + return false; + } + if (ref.empty()) { + *err = "TypeError: struct·new requires a type"; + return false; + } + // 原型必须存在且 kind=def struct。 + const std::uint8_t* pd = nullptr; + std::uint32_t pn = 0; + std::string plt; + if (!read_wire(c.f.h, ref, &pd, &pn) || !v_langtype(Wire{pd, pn}, &plt) || + bare_kind(plt) != "def struct") { + *err = "TypeError: " + ref + " is not a struct type"; + return false; + } + FReg& wr0 = c.f.regs[c.ins.wr[0]]; + if (!c.vm.ensure_reg_key(c.f, wr0)) { + *err = "struct·new: bad write slot"; + return false; + } + const std::string base = wr0.key; + char eb[192] = {}; + // 克隆原型成员(默认值:`Point·x` 等)+ 基值,覆盖给定字段。 + if (kvspaceCpList(c.f.h, ref.c_str(), base.c_str(), eb, sizeof eb) != 0) { + *err = std::string("struct·new: copy failed: ") + eb; + return false; + } + // 基值标 structref 标记(langtype=ref,空 body,ndim 0)。 + std::uint8_t* mark = nullptr; + std::uint32_t ml = 0; + bool ok = kvspaceXvalueEncode(ref.c_str(), nullptr, 0, nullptr, 0, &mark, + &ml) == 0 && + mark; + if (ok) + ok = kvspaceSetValue(c.f.h, base.c_str(), mark, ml, 0, 0, eb, + sizeof eb) == 0; + std::free(mark); + if (!ok) { + *err = std::string("struct·new: marker failed: ") + eb; + return false; + } + // 字段成对:读参[1]=字段名,[2]=值,[3]=名,[4]=值,… + for (int i = 1; i + 1 < c.ins.nrd; i += 2) { + std::string fname; + Wire fw{}; + Wire fv{}; + if (!c.vm.read_reg(c.f, c.ins.rd[i], &fw) || + !wire_text(fw.d, fw.n, &fname) || fname.empty() || + !c.vm.read_reg(c.f, c.ins.rd[i + 1], &fv)) { + *err = "struct·new: bad field pair"; + return false; + } + // 字段类型槽:`ref/` 的 def langtype body。 + std::string ftype; + { + const std::uint8_t* td = nullptr; + std::uint32_t tn = 0; + const std::string tk = ref + "/" + fname; + std::string tlt; + if (!read_wire(c.f.h, tk, &td, &tn) || + !v_langtype(Wire{td, tn}, &tlt) || + bare_kind(tlt) != "def langtype") { + *err = "TypeError: struct " + ref + " has no field " + fname; + return false; + } + kvspaceXh th{}; + if (kvspaceXhDecode(td, tn, &th) != 0 || !th.body) + ftype.clear(); + else + ftype.assign(reinterpret_cast(th.body), + th.content_len); + } + std::string vlt; + (void)v_langtype(fv, &vlt); + const bool none = v_is_none(fv); + // *T 字段:None 合法;非 None 须 Ptr 且目标种类匹配(剥离前导 *)。 + if (!ftype.empty() && ftype[0] == '*') { + if (!none && + (!v_ptr(fv) || + bare_kind(ftype.substr(1)) != bare_kind(vlt))) { + *err = "TypeError: field " + fname + ": expected " + ftype + + ", got " + (vlt.empty() ? "None" : vlt); + return false; + } + } else if (!ftype.empty() && + (none || bare_kind(ftype) != bare_kind(vlt))) { + *err = "TypeError: field " + fname + ": expected " + ftype + + ", got " + (none ? "None" : vlt); + return false; + } + const std::string mk = base + "\xC2\xB7" + fname; + if (kvspaceSetValue(c.f.h, mk.c_str(), fv.d, fv.n, 0, 0, eb, + sizeof eb) != 0) { + *err = std::string("struct·new: set field failed: ") + eb; + return false; + } + } + return true; +} + // ── 容器(obj / map·new)─────────────────────────────────────────────────── bool h_obj_map(NativeCtx& c, std::string* err) { std::string lt = c.write_slot_lt(); @@ -1451,7 +1811,12 @@ bool h_kvlang_abs(NativeCtx& c, std::string* err) { } else if (ad.name[0] == '/') { k0 = ad.name.substr(0, ad.name.find(' ')); // 剥类型后缀 } else { - k0 = c.f.regs[c.ins.rd[0]].key; // 变量已解析的帧 key + // 变量帧 key 惰性:`&x` 前 x 未必写过(链表 `{next=&n3}` 先于 n3 再写), + // 必须 ensure_reg_key 才拿得到路径(&n3 恒指向已建实例的槽 key)。 + FReg& ar = c.f.regs[c.ins.rd[0]]; + if (!c.vm.ensure_reg_key(c.f, ar)) + return false; + k0 = ar.key; } if (!ok || k0.empty()) { *err = "native: bad path operand: " + c.ins.name; @@ -1669,13 +2034,24 @@ constexpr NativeCap kScatterCaps[] = { constexpr NativeCap kStringCaps[] = { NCAP("string/char", h_string_char), + NCAP("string/cmp", h_string_cmp), + NCAP("string/concat", h_string_concat), + NCAP("string/find", h_string_find), + NCAP("string/formatint", h_string_formatint), + NCAP("string/formatuint", h_string_formatuint), NCAP("string/len", h_string_len), NCAP("string/ord", h_string_ord), + NCAP("string/parsefloat", h_string_parsefloat), + NCAP("string/parseint", h_string_parseint), + NCAP("string/parseuint", h_string_parseuint), + NCAP("string/set", h_string_set), + NCAP("string/slice", h_string_slice), }; constexpr NativeCap kContainerCaps[] = { NCAP("obj", h_obj_map), NCAP("map/new", h_obj_map), + NCAP("struct/new", h_struct_new), }; constexpr NativeCap kKvlangCaps[] = { @@ -1711,6 +2087,7 @@ constexpr NativeFamily kFamilies[] = { {"string/", kStringCaps, NCAPS(kStringCaps)}, {"obj", kContainerCaps, NCAPS(kContainerCaps)}, {"map/", kContainerCaps, NCAPS(kContainerCaps)}, + {"struct/", kContainerCaps, NCAPS(kContainerCaps)}, {"kvlang/", kKvlangCaps, NCAPS(kKvlangCaps)}, {"kvspace/", kKvspaceCaps, NCAPS(kKvspaceCaps)}, }; diff --git a/runtimec2/tools/gen_ops.py b/runtimec2/tools/gen_ops.py index 00da05d4..ab8820dd 100755 --- a/runtimec2/tools/gen_ops.py +++ b/runtimec2/tools/gen_ops.py @@ -59,14 +59,13 @@ def impl_of(name): return "Impl::Native" if fam in KIND: return "Impl::Typed" - # 用户裁定:容器/string/ndarray 是 runtimec2 核心职责(Native), - # Handoff 只留 struct·new(待实现)。 - return "Impl::Native" if name != "struct·new" else "Impl::Handoff" + # 用户裁定:容器/string/ndarray 是 runtimec2 核心职责(Native)。 + return "Impl::Native" if name in KIND: return "Impl::Typed" # bare kind = cast if name in GENERIC or name.startswith("char/"): return "Impl::Dynamic" # 泛型数值/比较 + char cast:运行动态分派 - return "Impl::Native" if name != "struct·new" else "Impl::Handoff" + return "Impl::Native" def op_of(name):