From 1fb0f4a4ea415b78e0449f50b7b92c7f4a2e4406 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 8 Oct 2026 13:47:54 +0800 Subject: [PATCH] =?UTF-8?q?feat(gen):=20=E9=80=83=E9=80=B8=E6=91=98?= =?UTF-8?q?=E8=A6=81=E4=BC=A0=E9=80=92=E9=97=AD=E5=8C=85=EF=BC=88M2.3=20v2?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - walker 认值位置上的调用(Return/Assign/AnnAssign/Expr 的 value 为 Call)。 - 传递规则:g(p,...) 中 g 会逃逸的实参位若绑到本函数形参 p,则 p 也逃逸。 - 注册完再重扫 2 遍(单调 OR-in)。已知:超过 2 层的链仍可能漏,真正收敛需改为扫描到不变为止。 --- App/lib/core/Gen/StructGenMixin.vp | 57 ++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/App/lib/core/Gen/StructGenMixin.vp b/App/lib/core/Gen/StructGenMixin.vp index 8734308..223130a 100644 --- a/App/lib/core/Gen/StructGenMixin.vp +++ b/App/lib/core/Gen/StructGenMixin.vp @@ -283,6 +283,10 @@ novirtual class StructGenMixin: # 从根上消除"槽里是坏指针 → strcmp 崩在 0xffff…"这一整类问题。 self._RegisterFuncEscapeSummary(esc_pool, fd, fd.name) + # v2 传递闭包:再迭代两次,让 `f` 经调用点继承 `g` 的逃逸(单调 OR-in,稳定即收敛) + for pi2 in range(2): + self._RescanEscapes(esc_pool, tree) + def is_file_func(self, name: str) -> int: """Return 1 when the bare name is a top-level function declared in this file.""" if name is None or self.FileFuncNames is None: return 0 @@ -422,6 +426,18 @@ novirtual class StructGenMixin: st: ast.AST* = stmts.get(i) if st is None: continue k: int = st.kind() + # v2 传递闭包:语句的值若是调用 g(...),把 g 的逃逸位经实参传递上来 + vnode: ast.AST* = None + if k == ast.ASTKind.Return: + vnode = ast.Return*(st).value + elif k == ast.ASTKind.Assign: + vnode = ast.Assign*(st).value + elif k == ast.ASTKind.AnnAssign: + vnode = ast.AnnAssign*(st).value + elif k == ast.ASTKind.Expr: + vnode = ast.Expr*(st).value + if vnode is not None and vnode.kind() == ast.ASTKind.Call: + self._PropagateCallEscapes(fd, ast.Call*(vnode), box) if k == ast.ASTKind.Return: rt: ast.Return* = ast.Return*(st) pi: int = self._ParamIndex(fd, rt.value) @@ -451,6 +467,47 @@ novirtual class StructGenMixin: self._ScanEscapes(fd, frn.orelse, gset, box, depth + 1) return 0 + def _PropagateCallEscapes(self, fd: ast.FunctionDef*, cl: ast.Call*, box: sizet*) -> int: + """v2 传递:`g(p, ...)` 里 g 会逃逸的实参位若绑到本函数形参 p → p 也逃逸""" + if fd is None or cl is None or box is None: return 0 + if cl.func is None or cl.func.kind() != ast.ASTKind.Name: return 0 + cnm: ast.Name* = ast.Name*(cl.func) + if cnm.id is None: return 0 + gmask: int = self.get_param_escapes(cnm.id) + if gmask == 0: return 0 + if cl.args is None: return 0 + na: sizet = len(cl.args) + for j in range(na): + if ((gmask >> int(j)) & 1) == 0: continue + pi: int = self._ParamIndex(fd, cl.args.get(j)) + if pi >= 0: box[0] = box[0] | (sizet(1) << pi) + return 0 + + def _RescanEscapes(self, pool: memhub.MemBuddy*, tree: ast.AST*) -> int: + """v2 传递闭包的一次迭代:以既有掩码为起点重扫本文件全部顶层函数(单调 OR-in)""" + if pool is None or tree is None or self.EscTable is None: return 1 + ch: list[ast.AST*]* = tree.children + if ch is None: return 1 + cn: sizet = len(ch) + for ci in range(cn): + child: ast.AST* = ch.get(ci) + if child is None: continue + if child.kind() != ast.ASTKind.FunctionDef: continue + fd: ast.FunctionDef* = ast.FunctionDef*(child) + if fd is None or fd.name is None: continue + idx: int = self._EscLookup(fd.name) + if idx < 0: continue + gset: hashtable.HashTable* = hashtable.HashTable(pool) + if gset is not None: self._CollectGlobalNames(fd.children, gset, 0) + box: sizet* = sizet*(pool.alloc(16)) + if box is None: continue + box[0] = self.EscTable[idx * 3 + 1] + box[1] = self.EscTable[idx * 3 + 2] + self._ScanEscapes(fd, fd.children, gset, box, 0) + self.EscTable[idx * 3 + 1] = box[0] + self.EscTable[idx * 3 + 2] = box[1] + return 0 + def get_file_module_sha1(self) -> str: """Return the module SHA1 of the file being translated (None if unregistered).""" return self.FileModuleSha1