From 81370537561363f05dfc953871dfb8a69deb4882 Mon Sep 17 00:00:00 2001 From: "peng.li24" <734991033@qq.com> Date: Fri, 11 Sep 2026 15:33:27 +0800 Subject: [PATCH] =?UTF-8?q?wip(layout):=20=E5=89=A5=E7=A6=BB=E5=86=99?= =?UTF-8?q?=E4=BE=A7/vthread/=E5=B8=A7=E8=B7=AF=E5=BE=84=E4=B8=8E=20Ptr=20?= =?UTF-8?q?=E6=9E=84=E9=80=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit layout 归位为只读定位+检查(#202):移除 kvspace 写侧 FFI (WriteInPlace/Del/Mkindex/Rmindex/Clear/Disconnect/NewPtr)、 ext_index/del_ext_index、new_ptr、vthread/帧路径 helper(stack/ frame_*/call_pc/v_thread_*)及 bool_lit/none_lit 字面量构造, 写/执行职责交 runtime。进行中快照,未验证编译。 Co-Authored-By: Claude Opus 4.8 --- layout/build.rs | 5 +- layout/src/ast.rs | 20 ---- layout/src/code.rs | 12 ++- layout/src/ffi.rs | 65 ----------- layout/src/keytree.rs | 101 +----------------- layout/src/kvkind.rs | 8 -- layout/src/parser.rs | 13 ++- layout/tests/pipeline_test.rs | 15 ++- runtime-rs/build.rs | 2 + runtime-rs/src/ffi.rs | 3 - runtime/CMakeLists.txt | 4 +- .../04-CABI.kv" | 3 +- 12 files changed, 39 insertions(+), 212 deletions(-) diff --git a/layout/build.rs b/layout/build.rs index 6c64dcb8..1c92863c 100644 --- a/layout/build.rs +++ b/layout/build.rs @@ -1,5 +1,8 @@ -// 链接 kvspace dispatch 前端(已安装 /usr/lib)。布局侧只通过 extern "C" ABI 调用, +// 链接 kvspace dispatch 前端(与后端同装 /usr/lib/kvspace)。布局侧只通过 extern "C" ABI 调用, // 运行期由前端按 DSN 选后端(shm://→kvspace-c,其余→kvspace-durable)。 fn main() { + println!("cargo:rustc-link-search=native=/usr/lib/kvspace"); println!("cargo:rustc-link-lib=dylib=kvspace"); + println!("cargo:rustc-link-arg=-Wl,--disable-new-dtags"); // rpath 转 DT_RPATH,传递解析子依赖 + println!("cargo:rustc-link-arg=-Wl,-rpath,/usr/lib/kvspace"); } diff --git a/layout/src/ast.rs b/layout/src/ast.rs index 85b1c9f2..51c767f9 100644 --- a/layout/src/ast.rs +++ b/layout/src/ast.rs @@ -316,26 +316,6 @@ pub fn float_lit(v: &str) -> Expr { } } -pub fn bool_lit(v: &str) -> Expr { - Expr { - op: String::new(), - args: Vec::new(), - val: v.to_string(), - quote: 0, - lit: LitKind::LitBool, - } -} - -pub fn none_lit() -> Expr { - Expr { - op: String::new(), - args: Vec::new(), - val: "None".to_string(), - quote: 0, - lit: LitKind::LitNil, - } -} - pub fn call(op: &str, args: Vec) -> Expr { Expr { op: op.to_string(), diff --git a/layout/src/code.rs b/layout/src/code.rs index b4c2820d..b71523a5 100644 --- a/layout/src/code.rs +++ b/layout/src/code.rs @@ -630,11 +630,19 @@ pub fn write_func(kv: &mut Kv, pkg: &str, fn_: &mut Func) { // 不带 `*` 的按**值传递**(槽存值本体,体内裸坐标 `[0,-k]` 直读)。见 spec [[函数]]。 let mut param_coord: HashMap = HashMap::new(); for (i, p) in fn_.sig.params.iter().enumerate() { - let d = if langtype::is_addr_param(&p.ty) { "*" } else { "" }; + let d = if langtype::is_addr_param(&p.ty) { + "*" + } else { + "" + }; param_coord.insert(p.name.clone(), format!("{d}[0,-{}]", i + 1)); } for (i, r) in fn_.sig.returns.iter().enumerate() { - let d = if langtype::is_addr_param(&r.ty) { "*" } else { "" }; + let d = if langtype::is_addr_param(&r.ty) { + "*" + } else { + "" + }; param_coord.insert(r.name.clone(), format!("{d}[0,{}]", i + 1)); } diff --git a/layout/src/ffi.rs b/layout/src/ffi.rs index 45dd9363..40e4b211 100644 --- a/layout/src/ffi.rs +++ b/layout/src/ffi.rs @@ -13,7 +13,6 @@ pub type Handle = *mut c_void; // ── extern "C" 声明 ───────────────────────────────────────────────────── -#[allow(dead_code)] extern "C" { fn kvspaceConnect(dsn: *const c_char) -> Handle; fn kvspaceClose(h: Handle); @@ -28,16 +27,6 @@ extern "C" { out: *mut *mut u8, out_len: *mut u32, ) -> c_int; - /// 就地写:key 已存在、body_len==原 body_len → 返回原 box body 偏移指针;否则非 0。 - fn kvspaceWriteInPlace( - h: Handle, - key: *const c_char, - resolve: c_int, - body_len: u32, - body: *mut *mut u8, - err: *mut c_char, - err_cap: u32, - ) -> c_int; /// 新位置写:按 (ref, storetype, ro, vid, langtype, body_len) 分配新 box、写 head,返回 body 偏移指针。 fn kvspaceWriteNewPlace( h: Handle, @@ -70,13 +59,6 @@ extern "C" { buf_cap: u32, out_len: *mut u32, ) -> c_int; - fn kvspaceDel( - h: Handle, - keys: *const *const c_char, - nkeys: u32, - err: *mut c_char, - err_cap: u32, - ) -> c_int; fn kvspaceDelTree(h: Handle, prefix: *const c_char, err: *mut c_char, err_cap: u32) -> c_int; fn kvspaceMkindex( h: Handle, @@ -85,17 +67,6 @@ extern "C" { err: *mut c_char, err_cap: u32, ) -> c_int; - fn kvspaceMkindexExt( - h: Handle, - path: *const c_char, - ext_path: *const c_char, - err: *mut c_char, - err_cap: u32, - ) -> c_int; - fn kvspaceRmindexExt(h: Handle, path: *const c_char, err: *mut c_char, err_cap: u32) -> c_int; - fn kvspaceClear(h: Handle, err: *mut c_char, err_cap: u32) -> c_int; - fn kvspaceDisconnect(h: Handle, err: *mut c_char, err_cap: u32) -> c_int; - fn kvspaceTlvEncode( kind: *const c_char, raw: *const u8, @@ -107,12 +78,6 @@ extern "C" { ) -> c_int; fn kvspaceDecodeHead(data: *const u8, data_len: u32, out: *mut kvspaceHead_t) -> c_int; - fn kvspaceNewPtr( - target_langtype: *const c_char, - target: *const c_char, - out: *mut *mut u8, - out_len: *mut u32, - ) -> c_int; fn kvspaceNewChar(bytes: *const u8, len: u32, out: *mut *mut u8, out_len: *mut u32) -> c_int; fn kvspaceNewBool(v: u8, out: *mut *mut u8, out_len: *mut u32) -> c_int; fn kvspaceNewInt64(v: i64, out: *mut *mut u8, out_len: *mut u32) -> c_int; @@ -294,30 +259,6 @@ impl Kv { unsafe { kvspaceMkindex(self.h, c.as_ptr(), 0, err.as_mut_ptr(), err.len() as u32) }; err_ret(&mut err, ret) } - - pub fn ext_index(&mut self, path: &str, ext_path: &str) -> Result<(), String> { - let cp = CString::new(path).expect("no NUL"); - let ce = CString::new(ext_path).expect("no NUL"); - let mut err: [c_char; 256] = [0; 256]; - let ret = unsafe { - kvspaceMkindexExt( - self.h, - cp.as_ptr(), - ce.as_ptr(), - err.as_mut_ptr(), - err.len() as u32, - ) - }; - err_ret(&mut err, ret) - } - - pub fn del_ext_index(&mut self, path: &str) -> Result<(), String> { - let c = CString::new(path).expect("no NUL"); - let mut err: [c_char; 256] = [0; 256]; - let ret = - unsafe { kvspaceRmindexExt(self.h, c.as_ptr(), err.as_mut_ptr(), err.len() as u32) }; - err_ret(&mut err, ret) - } } impl Drop for Kv { @@ -379,12 +320,6 @@ pub fn decode_head(data: &[u8]) -> kvspaceHead_t { // ── 标准标量构造器 ─────────────────────────────────────────────────── -pub fn new_ptr(target_langtype: &str, target: &str) -> Vec { - let ck = CString::new(target_langtype).expect("no NUL"); - let ct = CString::new(target).expect("no NUL"); - call_codec(|out, out_len| unsafe { kvspaceNewPtr(ck.as_ptr(), ct.as_ptr(), out, out_len) }) -} - pub fn new_char(kind: &str, s: &str) -> Vec { let bytes = s.as_bytes(); if kind == "char/utf8" { diff --git a/layout/src/keytree.rs b/layout/src/keytree.rs index 463a103b..6224580b 100644 --- a/layout/src/keytree.rs +++ b/layout/src/keytree.rs @@ -1,31 +1,14 @@ -//! KV 路径与成员分隔符统一管理(对齐 keytree/const.go、entry.go、frame.go、 -//! member.go、vthread.go、sys.go)。所有构造 KV 路径的地方均须使用本模块常量。 +//! KV 路径与成员分隔符统一管理。所有构造 KV 路径的地方均须使用本模块常量。 // ── 常量 ───────────────────────────────────────────────────────────── pub const MEMBER_SEP: &str = "·"; // 成员访问分隔符(U+00B7 中点号):释放 '.' 供小数 key 使用 pub const RUNTIME_MEMBER_SEP: &str = "\u{2025}"; // U+2025,运行时保留字段前缀 -pub const PATH_SEG_SEP: &str = "/"; // 路径分隔符 -pub const PATH_SEG_LIB: &str = "lib"; // /lib -pub const PATH_SEG_VTHREAD: &str = "vthread"; // /vthread - -pub const SEG_RO: &str = "ro"; -pub const SEG_RPARAM: &str = "rparam"; -pub const SEG_WPARAM: &str = "wparam"; -pub const SEG_PC: &str = "pc"; -pub const SEG_CALLPC: &str = "callpc"; -pub const SEG_RETURNPC: &str = "returnpc"; -pub const SEG_STATUS: &str = "status"; -pub const SEG_CTIME: &str = "ctime"; -pub const SEG_DEBUGGER: &str = "debugger"; - -pub const SEG_LIB: &str = "\u{2025}lib"; // 帧 extindex 标记 pub const SEG_LABELS: &str = "labels"; // /lib//‥labels/ → irseq pub const SRC_EXT: &str = ".src"; // 函数源码文件后缀 pub const LIB_ROOT: &str = "/lib"; pub const RWIR_ROOT: &str = "/lib"; -pub const VTHREAD_ROOT: &str = "/vthread"; // ── /lib ───────────────────────────────────────────────────────────── @@ -59,90 +42,8 @@ pub fn rwir(opcode: &str) -> String { format!("{RWIR_ROOT}/{opcode}") } -// ── 帧路径 ─────────────────────────────────────────────────────────── - -fn frame_member(root: &str, seg: &str) -> String { - format!("{}{}{}", stack(root), RUNTIME_MEMBER_SEP, seg) -} - -pub fn stack(root: &str) -> String { - format!("{}/", root.trim_end_matches(PATH_SEG_SEP)) -} - -pub fn frame_ro(root: &str) -> String { - frame_member(root, SEG_RO) -} - -pub fn call_pc(root: &str) -> String { - frame_member(root, SEG_CALLPC) -} - -pub fn return_pc(root: &str) -> String { - frame_member(root, SEG_RETURNPC) -} - -/// Frame root of a PC (`/vthread/42/[3]/[5,0]` → `/vthread/42/[3]`). -pub fn frame_root(pc: &str) -> &str { - if let Some(idx) = pc.rfind("/[") { - &pc[..idx] - } else { - panic!("frame_root: pc has no /[coord] segment: {pc:?}") - } -} - -pub fn entry_pc(root: &str) -> String { - format!("{}/[1,0]", root.trim_end_matches(PATH_SEG_SEP)) -} - -pub fn is_entry_pc(pc: &str) -> bool { - pc.ends_with("/[1,0]") -} - // ── 成员 ───────────────────────────────────────────────────────────── pub fn member(base: &str, name: &str) -> String { format!("{base}{MEMBER_SEP}{name}") } - -// ── /vthread ───────────────────────────────────────────────────────── - -pub fn v_thread(vtid: &str) -> String { - format!("{VTHREAD_ROOT}/{vtid}") -} - -fn vt_member(vtid: &str, seg: &str) -> String { - format!("{}/{}{}", v_thread(vtid), RUNTIME_MEMBER_SEP, seg) -} - -pub fn v_thread_pc(vtid: &str) -> String { - vt_member(vtid, SEG_PC) -} - -pub fn v_thread_status(vtid: &str) -> String { - vt_member(vtid, SEG_STATUS) -} - -pub fn v_thread_ctime(vtid: &str) -> String { - vt_member(vtid, SEG_CTIME) -} - -pub fn v_thread_debugger(vtid: &str) -> String { - vt_member(vtid, SEG_DEBUGGER) -} - -pub fn v_thread_at(vtid: &str, key: &str) -> String { - format!("{}/{key}", v_thread(vtid)) -} - -/// 从 pc(/vthread//...)提取 vtid。 -pub fn vtid_from_pc(pc: &str) -> String { - let prefix = format!("{VTHREAD_ROOT}/"); - if !pc.starts_with(&prefix) { - return String::new(); - } - let rest = &pc[prefix.len()..]; - match rest.find(PATH_SEG_SEP) { - Some(i) => rest[..i].to_string(), - None => rest.to_string(), - } -} diff --git a/layout/src/kvkind.rs b/layout/src/kvkind.rs index 2bef422b..c8aff94e 100644 --- a/layout/src/kvkind.rs +++ b/layout/src/kvkind.rs @@ -9,14 +9,7 @@ use super::ffi; // ── kind 常量 ───────────────────────────────────────────────────────── pub const KIND_CHAR: &str = "char/utf32"; -pub const KIND_CHAR_UTF8: &str = "char/utf8"; -pub const KIND_CHAR_ASCII: &str = "char/ascii"; -pub const KIND_BOOL: &str = "bool"; -pub const KIND_INT64: &str = "int64"; -pub const KIND_FLOAT64: &str = "float64"; -pub const KIND_MAP: &str = "stringkeymap"; pub const KIND_INDEX: &str = "index"; -pub const KIND_EXT_INDEX: &str = "extindex"; pub const KIND_STRUCT: &str = "struct"; // kvlang 自有 kind @@ -25,7 +18,6 @@ pub const KIND_RWFUNC: &str = "rwfunc"; pub const KIND_DEF_RWIR: &str = "def rwir"; pub const KIND_DEF_LANGTYPE: &str = "def langtype"; pub const KIND_RWIR_OR_RWFUNC: &str = "rwir|rwfunc"; -pub const KIND_SCOPE: &str = "scope"; // ── 通用 XValue 字节访问器 ─────────────────────────────────────────── diff --git a/layout/src/parser.rs b/layout/src/parser.rs index da4f55dd..e5da0afd 100644 --- a/layout/src/parser.rs +++ b/layout/src/parser.rs @@ -567,10 +567,12 @@ impl Parser { ret.name, ret.ty .split('|') - .map(|a| if !a.starts_with('*') && (a.starts_with('/') || a.contains('·')) { - format!("*{a}") - } else { - a.to_string() + .map(|a| { + if !a.starts_with('*') && (a.starts_with('/') || a.contains('·')) { + format!("*{a}") + } else { + a.to_string() + } }) .collect::>() .join("|") @@ -737,7 +739,8 @@ impl Parser { // 于是经 q 写成员就是在写读参的对象。只读性沿别名传播,否则 `q = p; q·x = v` // 一句话就把「签名诚实原则」洗白了。 // 别名 → 源头读参(`q = p` 记 q→p;再 `r = q` 追到 p),供诊断点名真凶。 - let mut tainted: std::collections::HashMap = std::collections::HashMap::new(); + let mut tainted: std::collections::HashMap = + std::collections::HashMap::new(); let mut all: Vec<&Instruction> = Vec::new(); collect_body_insts(&func.body, &mut all); loop { diff --git a/layout/tests/pipeline_test.rs b/layout/tests/pipeline_test.rs index 0076191b..87502f22 100644 --- a/layout/tests/pipeline_test.rs +++ b/layout/tests/pipeline_test.rs @@ -30,11 +30,16 @@ fn compile_simple_func() { let b = body(&sig_val); assert_eq!(kvkind::rwfunc_num_reads(b), 2); assert_eq!(kvkind::rwfunc_num_writes(b), 1); - // langtype 列表:读参在前(nr=2)、写参在后(nw=1) - assert_eq!( - kvkind::rwfunc_param_types(b), - vec!["int64", "int64", "int64"] - ); + // langtype 列表:读参在前(nr=2)、写参在后(nw=1),落参数定义键 .[0,±k] + let types: Vec = ["[0,-1]", "[0,-2]", "[0,1]"] + .iter() + .map(|k| { + kvkind::def_param_parts(&kv.get_one(&format!("/lib/sum.{k}"))) + .unwrap() + .1 + }) + .collect(); + assert_eq!(types, vec!["int64", "int64", "int64"]); // 参数 Ptr let a = kv.get_one("/lib/sum/A"); diff --git a/runtime-rs/build.rs b/runtime-rs/build.rs index c43721a9..bdee0cc2 100644 --- a/runtime-rs/build.rs +++ b/runtime-rs/build.rs @@ -24,6 +24,7 @@ fn main() { let bin = format!("{manifest}/../bin"); // kvlang/bin(新构建的 libkvlang_runtime.so) println!("cargo:rustc-link-search=native={bin}"); + println!("cargo:rustc-link-search=native=/usr/lib/kvspace"); println!("cargo:rustc-link-search=native=/usr/lib"); println!("cargo:rustc-link-lib=dylib=kvlang_runtime"); println!("cargo:rustc-link-lib=dylib=kvspace"); @@ -32,6 +33,7 @@ fn main() { println!("cargo:rustc-link-arg=-Wl,--disable-new-dtags"); // rpath 转 DT_RPATH,传递解析子依赖 println!("cargo:rustc-link-arg=-Wl,-rpath,$ORIGIN"); println!("cargo:rustc-link-arg=-Wl,-rpath,$ORIGIN/../lib"); + println!("cargo:rustc-link-arg=-Wl,-rpath,/usr/lib/kvspace"); println!("cargo:rustc-link-arg=-Wl,-rpath,/usr/lib"); // 内嵌顶层 stdlib/**/*.kv → EMBEDDED_KV。 diff --git a/runtime-rs/src/ffi.rs b/runtime-rs/src/ffi.rs index a2c89b79..1a32981e 100644 --- a/runtime-rs/src/ffi.rs +++ b/runtime-rs/src/ffi.rs @@ -67,11 +67,9 @@ pub fn tlv_encode(kind: &str, raw: &[u8], dims: &[i32]) -> Vec { } } -#[allow(dead_code)] unsafe extern "C" { // ── kvspace:KV 存取 + TLV ──────────────────────────────────────── pub fn kvspaceConnect(dsn: *const c_char) -> *mut c_void; - pub fn kvspaceClose(h: *mut c_void); pub fn kvspaceClear(h: *mut c_void, err: *mut c_char, err_cap: u32) -> c_int; pub fn kvspaceDelTree( h: *mut c_void, @@ -149,7 +147,6 @@ unsafe extern "C" { // ── kvlang runtime:模式2 执行 ─────────────────────────────────── pub fn kvlangRuntimeConnect(dsn: *const c_char) -> *mut c_void; - pub fn kvlangRuntimeDisconnect(rt: *mut c_void); /// runtime 内部 kvspace 句柄——复用它而非另开连接(durable 惰性 flush 仅同句柄内相干)。 pub fn kvlangRuntimeKvspaceHandle(rt: *mut c_void) -> *mut c_void; pub fn kvlangRuntimeBootstrap( diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 24d8f29c..40125248 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -16,7 +16,9 @@ target_include_directories(kvlang_runtime PUBLIC include src) target_compile_definitions(kvlang_runtime PRIVATE _GNU_SOURCE) # 链接 kvspace dispatch 前端(已安装 /usr/lib),运行期按 DSN 选后端,编译期不再选后端。 +# 链接 kvspace dispatch 前端(与后端同装 /usr/lib/kvspace),运行期按 DSN 选后端,编译期不再选后端。 +target_link_directories(kvlang_runtime PRIVATE /usr/lib/kvspace) target_link_libraries(kvlang_runtime PRIVATE kvspace m pthread) # --export-dynamic 供 kvlang(term 扩展)找符号;--disable-new-dtags 使 rpath 转 DT_RPATH(传递)。 -set_target_properties(kvlang_runtime PROPERTIES LINK_FLAGS "-Wl,--export-dynamic -Wl,--disable-new-dtags") +set_target_properties(kvlang_runtime PROPERTIES LINK_FLAGS "-Wl,--export-dynamic -Wl,--disable-new-dtags -Wl,-rpath,/usr/lib/kvspace") diff --git "a/stdlib/kvlang/spec/02-kvspace\346\250\241\345\236\213/04-CABI.kv" "b/stdlib/kvlang/spec/02-kvspace\346\250\241\345\236\213/04-CABI.kv" index 948e5b68..b63129a4 100644 --- "a/stdlib/kvlang/spec/02-kvspace\346\250\241\345\236\213/04-CABI.kv" +++ "b/stdlib/kvlang/spec/02-kvspace\346\250\241\345\236\213/04-CABI.kv" @@ -38,7 +38,7 @@ camelCase)——kvspace 层前缀 `kvspace`(`kvspaceGet` / `kvspaceWriteInPl `kvspaceDelTree` 对**最终组件**不解析 link——写/删 Ptr 键只作用该键本体,不重定向到 target (`Del`/`DelTree` 为 POSIX rm 式:删指针本身,不删被指向者)。解引用由 runtime 显式 `*` 掌控(见 [[ptr]])。否则「写实参地址 Ptr 到帧槽」会被重定向到 target,导致丢参 / 写坏被指向的值。 -## kvspace C ABI 导出符号全集(nm -D 实测,31) +## kvspace C ABI 导出符号全集(nm -D 实测,30) ``` kvspaceClear @@ -51,7 +51,6 @@ camelCase)——kvspace 层前缀 `kvspace`(`kvspaceGet` / `kvspaceWriteInPl kvspaceDecodeHead kvspaceDel kvspaceDelTree - kvspaceDisconnect kvspaceGet kvspaceGetHead kvspaceGetPart