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
37 changes: 28 additions & 9 deletions runtime/src/keytree.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ char *kvlangKeytreeStack(const char *root) {
return r;
}

/* 栈缓冲版:把 root(去尾 /)拷进 buf 并补 '/',返回写入长度(含尾 /);cap 不足返回 0。
* 读参热路径复用调用方缓冲,免每操作一次 malloc。 */
size_t kvlangKeytreeStackBuf(const char *root, char *buf, size_t cap) {
size_t n = strlen(root);
while (n > 0 && root[n - 1] == '/') n--;
if (n + 2 > cap) return 0;
memcpy(buf, root, n);
buf[n] = '/';
buf[n + 1] = 0;
return n + 1;
}

char *kvlangKeytreeFrameRoot(const char *pc) {
const char *last = NULL;
for (const char *p = pc; (p = strstr(p, "/[")) != NULL; p += 2) last = p;
Expand All @@ -30,6 +42,13 @@ char *kvlangKeytreeFrameRoot(const char *pc) {
return r;
}

/* 帧根长度(末个 "/[" 之前),无分配:循环每步据之判断帧是否变化,免一次 malloc。 */
size_t kvlangKeytreeFrameRootLen(const char *pc) {
const char *last = NULL;
for (const char *p = pc; (p = strstr(p, "/[")) != NULL; p += 2) last = p;
return last ? (size_t)(last - pc) : 0;
}

static char *trim_right_join(const char *root, const char *suffix) {
size_t n = strlen(root);
while (n > 0 && root[n - 1] == '/') n--;
Expand Down Expand Up @@ -59,14 +78,15 @@ char *kvlangKeytreeFrameAt(const char *vtid, int depth) {
}

int kvlangKeytreeFrameNum(const char *path) {
kvlangStrbuf_t vtid_b; kvlangStrbufInit(&vtid_b);
const char *vtid = kvlangKeytreeVtidFromPc(path, &vtid_b);
if (!vtid[0]) keytree_die("FrameNum: not a vthread path: %s", path);
kvlangStrbuf_t pfx; kvlangStrbufInit(&pfx);
kvlangKeytreeVthread(vtid, &pfx);
kvlangStrbufPutc(&pfx, '/');
if (strncmp(path, pfx.p, pfx.len) != 0) keytree_die("FrameNum: not a vthread path: %s", path);
const char *rest = path + pfx.len;
/* 免分配:/vthread/<vtid>/[d][/...] —— 直接定位 vtid 后的帧坐标,不构造前缀串。 */
const size_t rl = sizeof(VTHREAD_ROOT) - 1;
if (strncmp(path, VTHREAD_ROOT PATH_SEP, rl + 1) != 0)
keytree_die("FrameNum: not a vthread path: %s", path);
const char *vtid = path + rl + 1;
const char *slash = strchr(vtid, '/');
if (!slash || slash == vtid)
keytree_die("FrameNum: not a vthread path: %s", path);
const char *rest = slash + 1;
if (rest[0] != '[') keytree_die("FrameNum: no frame coord in %s", path);
const char *end = strchr(rest, ']');
if (!end) keytree_die("FrameNum: unterminated frame coord in %s", path);
Expand All @@ -90,7 +110,6 @@ int kvlangKeytreeFrameNum(const char *path) {
} else {
keytree_die("FrameNum: expected /[irseq,j] after [d] in %s", path);
}
kvlangStrbufFree(&vtid_b); kvlangStrbufFree(&pfx);
return (int)n;
}

Expand Down
90 changes: 53 additions & 37 deletions runtime/src/kvcpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,23 +121,25 @@ static int irseq_of(const kvlangParam_t *p) {
}

/* 函数内跳转:只改 PC 的 [irseq],帧不变。目标非法 → RuntimeError,返回 -1。 */
static int jump_to(kvlangKv_t *kv, const char *vtid, const char *pc,
const kvlangParam_t *target, const char *op) {
static int jump_to(kvlangFrame_t *f, const kvlangParam_t *target, const char *op) {
int irseq = irseq_of(target);
if (irseq < 0) {
char msg[256];
snprintf(msg, sizeof msg,
"RuntimeError: %s target is not an int64 irseq: %s (kind=%s)",
op, target->name ? target->name : "",
kvlangXvalueKind(&target->val));
kvlangVthreadSetError(kv, vtid, pc, msg);
kvlangVthreadSetError(f->kv, f->vtid, f->pc, msg);
return -1;
}
char *fr = kvlangKeytreeFrameRoot(pc);
/* 帧根优先用主循环缓存的(br/goto 帧不变,借它免每次 malloc)。 */
char *owned = NULL;
const char *fr = f->frame_root;
if (!fr) { owned = kvlangKeytreeFrameRoot(f->pc); fr = owned; }
char *np = kvlangKeytreeIrseqPc(fr, irseq);
free(fr);
kvlangVthreadSet(kv, vtid, np, "running");
kvlangLogDebug("[%s] %s → %s", vtid, op, np);
free(owned);
kvlangVthreadAdvance(f, np, "running");
kvlangLogDebug("[%s] %s → %s", f->vtid, op, np);
free(np);
return 0;
}
Expand Down Expand Up @@ -789,7 +791,7 @@ 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");
kvlangVthreadAdvance(f, sub, "running");
free(sub);
return 0;
}
Expand All @@ -802,7 +804,7 @@ int kvlangCtlReturn(kvlangFrame_t *f) {
kvlangVthreadSetDone(f->kv, f->vtid, "ok");
return 0;
}
kvlangVthreadSet(f->kv, f->vtid, parent, "running");
kvlangVthreadAdvance(f, parent, "running");
free(parent);
return 0;
}
Expand All @@ -816,7 +818,7 @@ int kvlangCtlGoto(kvlangFrame_t *f) {
kvlangVthreadSetError(f->kv, f->vtid, f->pc, msg);
return -1;
}
return jump_to(f->kv, f->vtid, f->pc, &inst->reads[0], OP_GOTO);
return jump_to(f, &inst->reads[0], OP_GOTO);
}

int kvlangCtlBr(kvlangFrame_t *f) {
Expand Down Expand Up @@ -852,7 +854,7 @@ int kvlangCtlBr(kvlangFrame_t *f) {
}
bool taken = kvlangScalarI64(kvlangXvalueScalar(&cond)) != 0;
kvlangXvalueFree(&cond);
return jump_to(f->kv, f->vtid, f->pc, &inst->reads[taken ? 1 : 2], OP_BR);
return jump_to(f, &inst->reads[taken ? 1 : 2], OP_BR);
}

/* 动态调用:以运行时得到的 funckey 在当前 vthread 造一次 OP_CALL(不新开 vid),
Expand Down Expand Up @@ -1027,28 +1029,40 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode,
char *cur = strdup(pc);
char *cur_frame = NULL,
*cur_funcdir = NULL; /* 帧不变时 funcdir 只读一次,供缓存键 */
int cur_depth = 0; /* 帧深度,随 cur_frame 一起缓存 */
int rc = 0;
/* status 跨轮携带:尾部 VthreadGet 已连 pc 一并取出,下轮直接复用,省掉背靠背重读
* (vthread 记录在两次 get 之间不被改写;status 串由 ValueString 自持,跨 ReadReset 存活)。 */
/* status:每步从 kvspace 回读的**源值**,不当缓存用(下轮开头即重读)。
* 同时借给本步的 kvlangFrame_t.status_known,供 Advance 判断是否真要写 status。 */
char *status = NULL;
{
char *pcv = NULL;
kvlangVthreadGet(kv, vtid, &pcv, &status);
free(pcv);
}
for (;;) {
/* 指令边界:回收上条指令执行期借出的读池(cache 指令的读参已 Materialize 自持,不受影响)。
* durable 惰性写不再清池,全靠此处回收;shm 常驻映射侧为 no-op。 */
kvlangKvReadReset(kv);
/* 状态门(spec [[执行模型]] 步骤 1):每指令边界从 kvspace 回读 ‥status,只读 1 个 key
* (走 vtid key 缓存)。不得改用进程内副本——那是状态的第二份事实源:外部把 ‥status
* 置 paused/error(暂停、接管、终止)必须在下一步就被看见,且 kvspace 始终等于真实状态。 */
free(status);
status = NULL;
kvlangVthreadStatusGet(kv, vtid, &status);
if (!status ||
(strcmp(status, "init") != 0 && strcmp(status, "running") != 0 &&
strcmp(status, "wait") != 0)) {
break;
}
free(status);
status = NULL;

int depth = kvlangKeytreeFrameNum(cur);
/* 帧变(call/return/goto 跨帧)才重算根/深度/funcdir;帧内每步只比较前缀,免分配。 */
size_t frlen = kvlangKeytreeFrameRootLen(cur);
if (!cur_frame || strlen(cur_frame) != frlen ||
strncmp(cur_frame, cur, frlen) != 0) {
free(cur_frame);
cur_frame = malloc(frlen + 1);
memcpy(cur_frame, cur, frlen);
cur_frame[frlen] = 0;
free(cur_funcdir);
cur_funcdir = read_seglib(kv, cur_frame);
cur_depth = kvlangKeytreeFrameNum(cur);
}
int depth = cur_depth;
if (depth > MAX_STACK_DEPTH) {
char msg[256];
snprintf(msg, sizeof msg,
Expand All @@ -1059,13 +1073,7 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode,
break;
}

char *fr = kvlangKeytreeFrameRoot(cur);
if (!cur_frame || strcmp(cur_frame, fr) != 0) {
free(cur_frame);
cur_frame = strdup(fr);
free(cur_funcdir);
cur_funcdir = read_seglib(kv, fr);
}
const char *fr = cur_frame; /* 借用(随 cur_frame 缓存同步),循环内无需 free */
const char *lastc = NULL;
for (const char *p = cur; (p = strstr(p, "/[")) != NULL; p += 2)
lastc = p;
Expand All @@ -1086,7 +1094,6 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode,
snprintf(msg, sizeof msg, "decode: %s", err);
kvlangVthreadSetError(kv, vtid, cur, msg);
free(link_base);
free(fr);
rc = -1;
break;
}
Expand Down Expand Up @@ -1114,7 +1121,6 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode,
snprintf(msg, sizeof msg, "RuntimeError: no instruction at %s",
cur);
kvlangVthreadSetError(kv, vtid, cur, msg);
free(fr);
if (tmp_owned)
kvlangRwirInstFree(&tmp);
rc = -1;
Expand All @@ -1123,9 +1129,12 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode,

int exec_err = 0;
char *yield = NULL;
char *fb_pc = NULL; /* 本指令的 PC 回传槽(见 kvlangFrame_t),免写后回读 */
if (inst->op_id >= 0) {
/* 单表派发:native 算子与 control/copy 同居 myrwircaps,op_id 直查一跳到底。 */
kvlangFrame_t f = {kv, vtid, cur, inst, &yield};
kvlangFrame_t f = {kv, vtid, cur, inst, &yield, &fb_pc};
f.frame_root = cur_frame; /* 复用循环缓存的帧根,免每步重算 */
f.status_known = status; /* 本步开始前读到的 ‥status(源值,借用) */
exec_err = kvlangBuiltinNative(&f);
if (exec_err == 0 && yield) {
/* native(vthread·run return 模式)冒泡一个子 vthread 的 rwir pc 给上层驱动。
Expand All @@ -1134,9 +1143,9 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode,
*out_pc = yield;
else
free(yield);
free(fr);
if (tmp_owned)
kvlangRwirInstFree(&tmp);
free(fb_pc);
free(cur);
free(cur_frame);
free(cur_funcdir);
Expand All @@ -1153,9 +1162,9 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode,
if (exec_err == 0 && mode == KVMODE_RETURN) {
if (out_pc)
*out_pc = strdup(cur);
free(fr);
if (tmp_owned)
kvlangRwirInstFree(&tmp);
free(fb_pc);
free(cur);
free(cur_frame);
free(cur_funcdir);
Expand All @@ -1181,24 +1190,31 @@ int kvlangKvcpuExecuteMode(kvlangKv_t *kv, const char *pc, kvmode_t mode,
}
ci.writes = inst->writes;
kvlangFrame_t cf = {kv, vtid, cur, &ci, NULL};
cf.status_known = status;
exec_err = kvlangCtlCall(&cf);
free(ci.opcode);
free(ci.reads[0].name);
free(ci.reads);
}

if (exec_err != 0) {
free(fr);
if (tmp_owned)
kvlangRwirInstFree(&tmp);
free(fb_pc);
rc = -1;
break;
}

char *newpc = NULL;
kvlangVthreadGet(kv, vtid, &newpc,
&status); /* status 连 pc 一并取出,供下轮直接复用 */
free(fr);
if (fb_pc) {
/* 本指令经帧回传了新 PC:直接用(它就是本指令刚写进 kvspace 的值)。
* status 不回传——下一轮状态门照旧从 kvspace 回读。 */
newpc = fb_pc;
fb_pc = NULL;
} else {
/* 无回传(ext rwir / 用户 call / done 等):从 kvspace 回读 PC。 */
kvlangVthreadPcGet(kv, vtid, &newpc);
}
if (tmp_owned)
kvlangRwirInstFree(&tmp);
if (!newpc || !newpc[0]) {
Expand Down
27 changes: 25 additions & 2 deletions runtime/src/kvspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ int kvlangKvGetMember(kvlangKv_t *k, const char *dir, const char *name, kvlangXv
if (!name || !name[0])
return 0;
size_t dl = strlen(dir), nl = strlen(name);
char *key = malloc(dl + nl + 1);
/* 短 key 走栈缓冲,免读参热路径每步一次 malloc。 */
char stackbuf[512];
char *key = stackbuf;
if (dl + nl + 1 > sizeof stackbuf)
key = malloc(dl + nl + 1);
memcpy(key, dir, dl);
memcpy(key + dl, name, nl);
key[dl + nl] = 0;
Expand All @@ -56,7 +60,8 @@ int kvlangKvGetMember(kvlangKv_t *k, const char *dir, const char *name, kvlangXv
out->len = len;
out->borrowed = 1;
}
free(key);
if (key != stackbuf)
free(key);
return 0;
}

Expand Down Expand Up @@ -123,6 +128,24 @@ int kvlangKvSet(kvlangKv_t *k, const kvlangKvPair_t *pairs, int n, char *err, ui
return rc;
}

/* 直写 char/utf8 值:跳过「TLV 编码 → KvSet 再解 head」的往返,直接向后端要 body 指针填字节。
* 供 PC 推进热路径(每指令一次)用;语义等价于 NewCharUtf8 + KvSet。 */
int kvlangKvSetChar(kvlangKv_t *k, const char *key, const char *s) {
uint32_t len = (uint32_t)strlen(s);
uint8_t *dst = NULL;
char err[256];
if (kvspaceWriteInPlace(k->h, key, 0, len, &dst, err, sizeof err) != 0) {
if (kvspaceWriteNewPlace(k->h, key, KVSPACE_REF_INLINE,
KVSPACE_STORETYPE_ATOM, 0, 0,
KVSPACE_KIND_CHAR_UTF8, len, &dst, err,
sizeof err) != 0)
return -1;
}
if (len && dst)
memcpy(dst, s, len);
return 0;
}

int kvlangKvDel(kvlangKv_t *k, const char *key, char *err, uint32_t err_cap) {
const char *keys[1] = {key};
return kvspaceDel(k->h, keys, 1, err, err_cap);
Expand Down
2 changes: 1 addition & 1 deletion runtime/src/myrwircaps.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ int kvlangDefRwir(void *kvspace, const char *opcode, const char *const *rp,

/* 精度前缀(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 int kvlangCtlCopy(kvlangFrame_t *f) { return kvlangBuiltinExecuteCopy(f); }

static const struct { const char *op; kvlangBuiltinFn fn; } myrwircaps[] = {
/* control / copy:与 native 算子同表,op_id 单跳派发 */
Expand Down
Loading
Loading