feat(gen): 逃逸摘要传递闭包(M2.3 v2)
- walker 认值位置上的调用(Return/Assign/AnnAssign/Expr 的 value 为 Call)。 - 传递规则:g(p,...) 中 g 会逃逸的实参位若绑到本函数形参 p,则 p 也逃逸。 - 注册完再重扫 2 遍(单调 OR-in)。已知:超过 2 层的链仍可能漏,真正收敛需改为扫描到不变为止。
This commit is contained in:
1 parent
52fd89decf
commit
1fb0f4a4ea
1 file changed
+57
@@ -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
|
||||
|
||||
Reference in new issue
Block a user