Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion layout/src/capi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use std::fs;
use std::os::raw::c_char;
use std::panic::catch_unwind;

use crate::{compile, format, init_dirs, vet, Kv};
use crate::{compile, format, init_dirs, kvkind, vet, Kv};

/// 复刻 Go runtime / layout_file 的 findEntry:DFS /lib/ 找首个 `.init`,否则 "init"。
fn find_entry(kv: &mut Kv, prefix: &str) -> String {
Expand Down Expand Up @@ -163,3 +163,46 @@ pub extern "C" fn kvlangLayoutFormat(
}
}
}

// ── kindexpr 解析 ABI ──────────────────────────────────────────────────
// kindexpr 语法唯一事实源在 layout(kindexpr.rs);解析能力导出为 C ABI,
// 供 runtime 之外的消费方(扩展宿主 term/numpy/json、byteseek…)读取 XValue head 时
// 复用,杜绝各处手写 head 结构/解析造成的 ABI 漂移(#70 遗留的旧 kind[32] 结构即此类)。

/// kindexpr 解析结果(repr(C),内存布局 = i32,i32,[i32;8],i32,[u8;64])。
#[repr(C)]
pub struct kvlangKindexpr {
pub ref_: i32, // 0=内联 1=软链接(*) 2=扩展句柄(@)
pub ndim: i32, // 维数(0=标量)
pub dims: [i32; 8], // 各维大小(前 ndim 项有效)
pub array_len: i32, // 元素总数(标量=1,多维=各维乘积)
pub kind: [u8; 64], // base kind,NUL 终止(如 "float64"、"char/utf8"、"rwir|rwfunc")
}

/// 解析 XValue head 的 kindexpr 内容(NUL 终止串,含 */@ 前缀与 [dims])。
/// 成功返回 0,失败(空指针/空串)返回 -1。
#[no_mangle]
pub extern "C" fn kvlangKindexprParse(kindexpr: *const c_char, out: *mut kvlangKindexpr) -> i32 {
if kindexpr.is_null() || out.is_null() {
return -1;
}
let s = cstr(kindexpr);
if s.is_empty() {
return -1;
}
let (r, dims, kind) = kvkind::parse_kindexpr(s);
let out = unsafe { &mut *out };
out.ref_ = r;
out.ndim = dims.len() as i32;
for (i, d) in dims.iter().enumerate() {
if i < 8 {
out.dims[i] = *d;
}
}
out.array_len = if dims.is_empty() { 1 } else { dims.iter().product() };
let kb = kind.as_bytes();
let n = kb.len().min(63);
out.kind[..n].copy_from_slice(&kb[..n]);
out.kind[n] = 0;
0
}
72 changes: 26 additions & 46 deletions layout/src/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::collections::HashMap;

use super::ast::{Func, RwirDecl, Stmt};
use super::ffi::Kv;
use super::{builtin, ffi, keytree, kvkind, lower, parser, symbol};
use super::{builtin, ffi, keytree, kvkind, lower, parser};

/// 创建基础目录 /lib/ 与 /vthread/(layout 前必须存在)。
pub fn init_dirs(kv: &mut Kv) -> Result<(), String> {
Expand All @@ -30,23 +30,11 @@ pub fn compile(kv: &mut Kv, src: &str) -> Result<(), String> {
return Err("parse: error-level diagnostics — refusing to load".to_string());
}

// 用户函数名 → 有效包名。layout 只对这些名字加包前缀(正向识别用户函数),
// 其余 opcode(native / 扩展 rwir)原样落盘,由 runtime 查 /lib/<op> 的 XValue kind 判定。
let mut user_pkg: HashMap<String, String> = HashMap::new();
for func in &file.funcs {
let p = if func.pkg.is_empty() { file.package.clone() } else { func.pkg.clone() };
user_pkg.insert(func.sig.name.clone(), p);
}
for decl in &file.rwir_decls {
let p = if decl.pkg.is_empty() { file.package.clone() } else { decl.pkg.clone() };
user_pkg.insert(decl.sig.name.clone(), p);
}

let mut any_code = false;
for func in &file.funcs {
let pkg = if func.pkg.is_empty() { file.package.clone() } else { func.pkg.clone() };
let mut lowered = lower::lower_func(func);
write_func(kv, &pkg, &mut lowered, &user_pkg);
write_func(kv, &pkg, &mut lowered);
any_code = true;
}
for decl in &file.rwir_decls {
Expand All @@ -65,7 +53,7 @@ pub fn compile(kv: &mut Kv, src: &str) -> Result<(), String> {
pkg: String::new(),
};
let mut lowered = lower::lower_func(&init_fn);
write_func(kv, "", &mut lowered, &user_pkg);
write_func(kv, "", &mut lowered);
any_code = true;
}

Expand Down Expand Up @@ -112,7 +100,7 @@ pub fn vet(src: &str) -> Result<(), String> {
}

/// 写函数到 /lib/:签名(rwfunc)、源码、参数 Ptr、指令体。
pub fn write_func(kv: &mut Kv, pkg: &str, fn_: &mut Func, user_pkg: &HashMap<String, String>) {
pub fn write_func(kv: &mut Kv, pkg: &str, fn_: &mut Func) {
let mut type_map = lower::infer_types(fn_);
lower::specialize(fn_, &type_map);
let func_dir = keytree::lib_func(pkg, &fn_.sig.name);
Expand Down Expand Up @@ -145,7 +133,7 @@ pub fn write_func(kv: &mut Kv, pkg: &str, fn_: &mut Func, user_pkg: &HashMap<Str
}
let _ = kv.set(&pairs);

write_body(kv, pkg, &fn_.sig.name, &fn_.body, &mut type_map, 1, user_pkg);
write_body(kv, pkg, &fn_.sig.name, &fn_.body, &mut type_map, 1);
}

/// 写用户声明的 rwir(无体)到 /lib/<opcode>。
Expand All @@ -159,11 +147,11 @@ pub fn write_rwir_decl(kv: &mut Kv, decl: &RwirDecl) {
}

/// 将 body 写入 /lib/<pkg>/<name>/ 下。offset 起始 idx(顶层函数=1)。
fn write_body(kv: &mut Kv, pkg: &str, name: &str, body: &[Stmt], type_map: &mut HashMap<String, String>, offset: i32, user_pkg: &HashMap<String, String>) {
fn write_body(kv: &mut Kv, pkg: &str, name: &str, body: &[Stmt], type_map: &mut HashMap<String, String>, offset: i32) {
let prefix = keytree::lib_func(pkg, name);
let mut idx = offset;
for st in body {
write_stmt(kv, st, &prefix, &mut idx, type_map, pkg, user_pkg);
write_stmt(kv, st, &prefix, &mut idx, type_map, pkg);
}
}

Expand All @@ -174,7 +162,6 @@ fn write_stmt(
idx: &mut i32,
type_map: &mut HashMap<String, String>,
pkg: &str,
user_pkg: &HashMap<String, String>,
) {
match st {
Stmt::Instruction(s) => {
Expand All @@ -184,15 +171,7 @@ fn write_stmt(
type_map.insert(w.clone(), s.write_types[j].clone());
}
}
let (mut opcode, reads) = s.flat();
if !pkg.is_empty()
&& user_pkg.get(&opcode).map_or(false, |p| p == pkg)
&& !opcode.contains(keytree::MEMBER_SEP)
&& !opcode.starts_with("/lib/")
&& symbol::lookup(&opcode).word != "assign"
{
opcode = format!("{pkg}{}{opcode}", keytree::MEMBER_SEP);
}
let (opcode, reads) = s.flat();
let target_char = if s.writes.len() == 1 && !s.write_types.is_empty() && kvkind::is_char_kind(&s.write_types[0]) {
s.write_types[0].as_str()
} else {
Expand All @@ -201,7 +180,7 @@ fn write_stmt(

let mut pairs: Vec<(String, Vec<u8>)> = Vec::with_capacity(1 + reads.len() + s.writes.len());
if !opcode.is_empty() {
pairs.push((format!("{prefix}/[{n},0]"), slot_value(&opcode, "")));
pairs.push((format!("{prefix}/[{n},0]"), opcode_value(&opcode)));
}
for (j, r) in reads.iter().enumerate() {
pairs.push((format!("{prefix}/[{n},-{}]", j + 1), slot_value(r, target_char)));
Expand All @@ -218,7 +197,7 @@ fn write_stmt(
let scope_prefix = format!("{prefix}/{}", s.label);
let mut scope_idx = 0;
for child in &s.body {
write_stmt_scope(kv, child, &scope_prefix, &mut scope_idx, type_map, pkg, prefix, user_pkg);
write_stmt_scope(kv, child, &scope_prefix, &mut scope_idx, type_map, pkg, prefix);
}
}
_ => {}
Expand All @@ -233,7 +212,6 @@ fn write_stmt_scope(
type_map: &mut HashMap<String, String>,
pkg: &str,
func_prefix: &str,
user_pkg: &HashMap<String, String>,
) {
match st {
Stmt::Instruction(s) => {
Expand All @@ -243,15 +221,7 @@ fn write_stmt_scope(
type_map.insert(w.clone(), s.write_types[j].clone());
}
}
let (mut opcode, reads) = s.flat();
if !pkg.is_empty()
&& user_pkg.get(&opcode).map_or(false, |p| p == pkg)
&& !opcode.contains(keytree::MEMBER_SEP)
&& !opcode.starts_with("/lib/")
&& symbol::lookup(&opcode).word != "assign"
{
opcode = format!("{pkg}{}{opcode}", keytree::MEMBER_SEP);
}
let (opcode, reads) = s.flat();
let target_char = if s.writes.len() == 1 && !s.write_types.is_empty() && kvkind::is_char_kind(&s.write_types[0]) {
s.write_types[0].as_str()
} else {
Expand All @@ -260,7 +230,7 @@ fn write_stmt_scope(

let mut pairs: Vec<(String, Vec<u8>)> = Vec::with_capacity(1 + reads.len() + s.writes.len());
if !opcode.is_empty() {
pairs.push((format!("{scope_prefix}[{n},0]"), slot_value(&opcode, "")));
pairs.push((format!("{scope_prefix}[{n},0]"), opcode_value(&opcode)));
}
for (j, r) in reads.iter().enumerate() {
pairs.push((format!("{scope_prefix}[{n},-{}]", j + 1), slot_value(r, target_char)));
Expand All @@ -277,13 +247,23 @@ fn write_stmt_scope(
let child_prefix = format!("{func_prefix}/{}", s.label);
let mut child_idx = 0;
for child in &s.body {
write_stmt_scope(kv, child, &child_prefix, &mut child_idx, type_map, pkg, func_prefix, user_pkg);
write_stmt_scope(kv, child, &child_prefix, &mut child_idx, type_map, pkg, func_prefix);
}
}
_ => {}
}
}

/// 调用目标 opcode 槽值:函数调用/运算符 → `rwir|rwfunc` 并列;
/// 控制/拷贝 opcode(return/goto/br/call/=)原样 `rwir`(非调用目标)。
fn opcode_value(opcode: &str) -> Vec<u8> {
if matches!(opcode, "return" | "goto" | "br" | "call" | "=") {
kvkind::new_rwir(0, 0, opcode)
} else {
kvkind::new_rwir_union(opcode)
}
}

/// 将字面量/引用字符串编码为 XValue TLV(rwir 槽值)。
fn slot_value(val: &str, target_char: &str) -> Vec<u8> {
if !is_literal(val) {
Expand Down Expand Up @@ -350,11 +330,11 @@ mod tests {
init_dirs(&mut kv).unwrap();

compile(&mut kv, "lib a {\nlib b {\nrwfunc f() -> (r:int64) {\n1 -> r\n}\n}\n}\n").unwrap();
assert_eq!(kvkind::kind(&kv.get_one("/lib/a/b.f/[0,0]")), "rwfunc");
assert_eq!(kvkind::kind(&kv.get_one("/lib/a/b.f/[0,0]")), "defrwfunc");

// 同 lib a 下再 layout 另一嵌套 lib c,验证 b.f 未被整库删除(增量合并)
compile(&mut kv, "lib a {\nlib c {\nrwfunc g() -> (r:int64) {\n2 -> r\n}\n}\n}\n").unwrap();
assert_eq!(kvkind::kind(&kv.get_one("/lib/a/b.f/[0,0]")), "rwfunc", "b.f 应保留");
assert_eq!(kvkind::kind(&kv.get_one("/lib/a/c.g/[0,0]")), "rwfunc");
assert_eq!(kvkind::kind(&kv.get_one("/lib/a/b.f/[0,0]")), "defrwfunc", "b.f 应保留");
assert_eq!(kvkind::kind(&kv.get_one("/lib/a/c.g/[0,0]")), "defrwfunc");
}
}
9 changes: 8 additions & 1 deletion layout/src/kvkind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub const KIND_RWIR: &str = "rwir";
pub const KIND_RWFUNC: &str = "rwfunc";
pub const KIND_DEF_RWIR: &str = "defrwir";
pub const KIND_DEF_RWFUNC: &str = "defrwfunc";
pub const KIND_RWIR_OR_RWFUNC: &str = "rwir|rwfunc";
pub const KIND_SCOPE: &str = "scope";

// ── 通用 XValue 字节访问器 ───────────────────────────────────────────
Expand All @@ -38,7 +39,7 @@ pub fn head(data: &[u8]) -> ffi::kvspaceHead_t {
}

/// 解析 head 的 kindexpr 内容 → (ref, dims, base kind)。
fn parse_kindexpr(kx: &str) -> (i32, Vec<i32>, String) {
pub fn parse_kindexpr(kx: &str) -> (i32, Vec<i32>, String) {
let (r, rest) = match kx.as_bytes().first() {
Some(b'*') => (1, &kx[1..]),
Some(b'@') => (2, &kx[1..]),
Expand Down Expand Up @@ -138,6 +139,12 @@ pub fn new_rwir(nr: i32, nw: i32, sig: &str) -> Vec<u8> {
ffi::tlv_encode(KIND_RWIR, &rwir_body(nr, nw, sig), 1)
}

/// 调用目标(看起来像函数调用的 opcode)→ kindexpr `rwir|rwfunc` 并列。
/// 静态无法判定是扩展 rwir 还是用户 rwfunc,交 runtime 查 /lib/<op> 的 XValue kind 分派。
pub fn new_rwir_union(sig: &str) -> Vec<u8> {
ffi::tlv_encode(KIND_RWIR_OR_RWFUNC, &rwir_body(0, 0, sig), 1)
}

pub fn new_defrwir(nr: i32, nw: i32, sig: &str) -> Vec<u8> {
ffi::tlv_encode(KIND_DEF_RWIR, &rwir_body(nr, nw, sig), 1)
}
Expand Down
8 changes: 4 additions & 4 deletions layout/tests/pipeline_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ fn compile_simple_func() {

// 函数签名
let sig_val = kv.get_one("/lib/sum/[0,0]");
assert_eq!(kvkind::kind(&sig_val), "rwfunc");
assert_eq!(kvkind::kind(&sig_val), "defrwfunc");
assert_eq!(kvkind::array_len(&sig_val), 1);
let b = body(&sig_val);
assert_eq!(kvkind::rwfunc_num_reads(b), 2);
Expand All @@ -43,7 +43,7 @@ fn compile_simple_func() {

// 指令(特化后 opcode = int64.add)
let op = kv.get_one("/lib/sum/[1,0]");
assert_eq!(kvkind::kind(&op), "rwir");
assert_eq!(kvkind::kind(&op), "rwir|rwfunc");
assert_eq!(sig(&op), "int64.add");
assert_eq!(sig(&kv.get_one("/lib/sum/[1,-1]")), "A");
assert_eq!(sig(&kv.get_one("/lib/sum/[1,-2]")), "B");
Expand All @@ -62,7 +62,7 @@ fn compile_string_literal_and_lib() {

// 函数在 /lib/p.hi/ 下(lib 块 pkg 前缀)
let sig_val = kv.get_one("/lib/p.hi/[0,0]");
assert_eq!(kvkind::kind(&sig_val), "rwfunc");
assert_eq!(kvkind::kind(&sig_val), "defrwfunc");

// 字符串字面量读槽 → char/utf32(UTF-32 LE 码点)
let r = kv.get_one("/lib/p.hi/[1,-1]");
Expand Down Expand Up @@ -98,7 +98,7 @@ fn compile_control_flow_lowers_to_blocks() {
compile(&mut kv, src).unwrap();

let sig_val = kv.get_one("/lib/f/[0,0]");
assert_eq!(kvkind::kind(&sig_val), "rwfunc");
assert_eq!(kvkind::kind(&sig_val), "defrwfunc");
// 降级后存在 if/then 基本块(label 指令以 _label[coord] 扁平键存在;空 merge 块不落盘)
let children = kv.list("/lib/f/", false, false);
assert!(children.iter().any(|c| c.contains("_if_")));
Expand Down
4 changes: 2 additions & 2 deletions layout/tests/redis_roundtrip_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ fn redis_compile() {
compile(&mut kv, src).unwrap();

let sig_val = kv.get_one("/lib/sum/[0,0]");
assert_eq!(kvkind::kind(&sig_val), "rwfunc");
assert_eq!(kvkind::kind(&sig_val), "defrwfunc");
let b = body(&sig_val);
assert_eq!(kvkind::rwfunc_num_reads(b), 2);
assert_eq!(kvkind::rwfunc_num_writes(b), 1);

let op = kv.get_one("/lib/sum/[1,0]");
assert_eq!(kvkind::kind(&op), "rwir");
assert_eq!(kvkind::kind(&op), "rwir|rwfunc");
assert_eq!(String::from_utf8_lossy(&body(&op)[4..]), "int64.add");
}
36 changes: 24 additions & 12 deletions runtime-rwirext_example/go/json/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ package json
// 后端(kvspace-c=shm / kvspace_durable=redis|fs)由 Makefile 经 CGO_LDFLAGS 注入,
// 对齐 term 的 KVLANG_KVSPACE_LIB;扩展宿主自连 kvspace,不经 runtime。
#cgo CFLAGS: -I${SRCDIR}/../../../runtime/include
#cgo LDFLAGS: -L${SRCDIR}/../../../bin -lkvlang_runtime -Wl,-rpath,${SRCDIR}/../../../bin
#cgo LDFLAGS: -L${SRCDIR}/../../../bin -lkvlang_runtime -L${SRCDIR}/../../../layout/target/release -lkvlang_layout -Wl,-rpath,${SRCDIR}/../../../bin -Wl,-rpath,${SRCDIR}/../../../layout/target/release
#include "kvlang_rwirext.h"
#include <stdint.h>
#include <stdlib.h>
Expand All @@ -24,19 +24,27 @@ extern int kvspaceDel(void *h, const char *const *keys, uint32_t nkeys, char *
extern int kvspaceMkindex(void *h, const char *path, char *err, uint32_t err_cap);
extern int kvspaceNewChar(const char *kind, const char *s, uint8_t **out, uint32_t *out_len);

// XValue 头(repr(C),对齐 kvspace ABI):kind+ndim+dims 即 kindexp,body 段靠 offset/len 定位。
// XValue 头(repr(C),对齐 kvspace ABI):kindexpr 为唯一类型真相,body 段靠 offset/len 定位。
typedef struct {
uint8_t kind[32];
uint8_t is_ptr;
int32_t array_len;
int32_t body_len;
int32_t body_offset;
int32_t ndim;
int32_t dims[8];
uint8_t kindexpr[256];
uint8_t ro;
uint32_t vid;
int32_t body_len;
int32_t body_offset;
} kvspaceHead_t;
extern int kvspaceDecodeHead(const uint8_t *data, uint32_t data_len, kvspaceHead_t *out);
extern int kvspaceTlvEncode(const char *kind, const uint8_t *raw, uint32_t raw_len,
const int32_t *dims, int32_t ndim, uint8_t **out, uint32_t *out_len);

// kindexpr 解析(kvlang/layout 提供 ABI,唯一事实源):ref/ndim/dims/kind。
typedef struct {
int32_t ref;
int32_t ndim;
int32_t dims[8];
int32_t array_len;
uint8_t kind[64];
} kvlangKindexpr;
extern int kvlangKindexprParse(const char *kindexpr, kvlangKindexpr *out);
*/
import "C"

Expand Down Expand Up @@ -184,7 +192,11 @@ func parseTLV(data []byte) (kind string, raw []byte, arrLen int) {
if C.kvspaceDecodeHead((*C.uint8_t)(unsafe.Pointer(&data[0])), C.uint32_t(len(data)), &h) != 0 {
return "", nil, 0
}
kb := C.GoBytes(unsafe.Pointer(&h.kind[0]), 32)
var kx C.kvlangKindexpr
if C.kvlangKindexprParse((*C.char)(unsafe.Pointer(&h.kindexpr[0])), &kx) != 0 {
return "", nil, 0
}
kb := C.GoBytes(unsafe.Pointer(&kx.kind[0]), 64)
if i := bytes.IndexByte(kb, 0); i >= 0 {
kb = kb[:i]
}
Expand All @@ -195,8 +207,8 @@ func parseTLV(data []byte) (kind string, raw []byte, arrLen int) {
}
raw = data[bo : bo+bl]
arrLen = 1
for i := 0; i < int(h.ndim); i++ {
arrLen *= int(h.dims[i])
for i := 0; i < int(kx.ndim); i++ {
arrLen *= int(kx.dims[i])
}
if arrLen < 1 {
arrLen = 1
Expand Down
Loading
Loading