更新,可自举
This commit is contained in:
1 parent
07db560510
commit
ab0f37e1a8
35 files changed
+3759
-1518
No files matched your search
@@ -157,6 +157,9 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
|
||||
# P2-P5: 注入各 Handles 模块级单例(委托函数经本地 _g_gen 访问,
|
||||
# 避免函数体 import 包模块与类/模块名歧义)
|
||||
GenApi._g_gen = gen
|
||||
HandlesTranslator._g_gen = gen
|
||||
HandlesExpr._g_gen = gen
|
||||
HandlesExprCall._g_gen = gen
|
||||
# P6: 注入语句/赋值/变量/导入/翻译驱动模块的单例
|
||||
# 设置当前文件名(供报错使用)
|
||||
GenApi.set_current_file_type(file_path)
|
||||
@@ -836,6 +839,63 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
|
||||
return 0
|
||||
|
||||
|
||||
def asm_to_obj(asm_path: str, sha1_val: str, output_dir: str,
|
||||
triple: str) -> int:
|
||||
"""用 llvm-mc 汇编 .s 源文件为 .obj(切片路径)
|
||||
|
||||
裸机项目(VKernel 等)含 .s 汇编文件(如 Kernel/intr/isr.s 定义
|
||||
isr0/syscall_entry/_per_cpu 等符号)。.s 不经过 TPV 翻译/llc,
|
||||
直接用配套的 llvm-mc 汇编为 .obj,obj 路径与其他模块一致
|
||||
(output_dir/{sha1前缀}/{sha1}.obj),参与 Phase C 链接。
|
||||
|
||||
Args:
|
||||
asm_path: .s 源文件完整路径
|
||||
sha1_val: 文件内容 SHA1 前16字符(切片路径用)
|
||||
output_dir: 输出目录
|
||||
triple: 目标 triple(如 x86_64-none-elf)
|
||||
|
||||
Returns:
|
||||
0 成功,非 0 失败
|
||||
"""
|
||||
if asm_path is None or sha1_val is None or output_dir is None:
|
||||
return 1
|
||||
obj_path: str = build_sliced_path(output_dir, sha1_val, "obj")
|
||||
if obj_path is None:
|
||||
return 1
|
||||
trip: str = triple
|
||||
if trip is None or trip[0] == '\0':
|
||||
trip = "x86_64-none-elf"
|
||||
cmd_len: t.CSizeT = len("llvm-mc -triple=") + len(trip) \
|
||||
+ len(" -filetype=obj -o ") + len(obj_path) + len(asm_path) + 64
|
||||
cmd: bytes = _mbuddy.alloc(cmd_len)
|
||||
if cmd is None:
|
||||
return 1
|
||||
viperlib.snprintf(cmd, cmd_len, "llvm-mc -triple=%s -filetype=obj -o %s %s",
|
||||
trip, obj_path, asm_path)
|
||||
|
||||
# --phase2command 模式:命令写入 bat(与 llc/链接一致)
|
||||
if _phase2_cmd_path is not None:
|
||||
_phase2_write_cmd(cmd)
|
||||
return 0
|
||||
|
||||
result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True)
|
||||
if result is None:
|
||||
VLogger.error("llvm-mc subprocess.run 返回 None", "asm")
|
||||
return 1
|
||||
if result.returncode != 0:
|
||||
if result.stdout is not None:
|
||||
stdio.printf("%s\n", result.stdout)
|
||||
if result.stderr is not None:
|
||||
stdio.printf("%s\n", result.stderr)
|
||||
fb: str = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "llvm-mc 汇编失败,返回码: %d, 命令: %s",
|
||||
result.returncode, cmd)
|
||||
VLogger.error(fb, "asm")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def compile_module_to_obj(ir_buf: bytes, ir_len: t.CSizeT,
|
||||
temp_dir: str, output_dir: str, module_name: str,
|
||||
cc_cmd: str, cc_flags: str) -> int:
|
||||
@@ -899,6 +959,61 @@ def link_objs_to_exe(obj_paths: str, obj_paths_len: t.CSizeT,
|
||||
if obj_paths is None or obj_paths_len == 0 or linker_cmd is None:
|
||||
return 1
|
||||
|
||||
# 去重 .obj 路径:同一模块的 obj 可能被多个收集环节加入(Phase B+
|
||||
# 新编译 obj_paths 与 Phase C reachable 收集指向 includes.binary 中
|
||||
# 同一文件)。App 项目 linker flags 含 --allow-multiple-definition 可
|
||||
# 容忍;VKernel 无此 flag → ld.lld "duplicate symbol"。链接命令中同一
|
||||
# 路径出现两次即重复符号,保留首次出现的路径,后续重复跳过。
|
||||
if obj_paths_len > 0:
|
||||
dedup: bytes = _mbuddy.alloc(obj_paths_len + 1)
|
||||
if dedup is not None:
|
||||
dedup[0] = '\0'
|
||||
dpos: t.CSizeT = 0
|
||||
dsrc_i: t.CSizeT = 0
|
||||
while dsrc_i < obj_paths_len:
|
||||
# 跳过前导空格
|
||||
while dsrc_i < obj_paths_len and obj_paths[dsrc_i] == ' ':
|
||||
dsrc_i += 1
|
||||
if dsrc_i >= obj_paths_len:
|
||||
break
|
||||
dstart: t.CSizeT = dsrc_i
|
||||
while dsrc_i < obj_paths_len and obj_paths[dsrc_i] != ' ':
|
||||
dsrc_i += 1
|
||||
dtlen: t.CSizeT = dsrc_i - dstart
|
||||
# 检查 dedup 中是否已有相同 token
|
||||
ddup: int = 0
|
||||
dj: t.CSizeT = 0
|
||||
while dj < dpos:
|
||||
while dj < dpos and dedup[dj] == ' ':
|
||||
dj += 1
|
||||
if dj >= dpos:
|
||||
break
|
||||
ds2: t.CSizeT = dj
|
||||
while dj < dpos and dedup[dj] != ' ':
|
||||
dj += 1
|
||||
dt2len: t.CSizeT = dj - ds2
|
||||
if dt2len == dtlen:
|
||||
deq: int = 1
|
||||
dk: t.CSizeT = 0
|
||||
while dk < dtlen:
|
||||
if dedup[ds2 + dk] != obj_paths[dstart + dk]:
|
||||
deq = 0
|
||||
break
|
||||
dk += 1
|
||||
if deq != 0:
|
||||
ddup = 1
|
||||
break
|
||||
if ddup == 0:
|
||||
if dpos > 0:
|
||||
dedup[dpos] = ' '
|
||||
dpos += 1
|
||||
string.memcpy(dedup + dpos, obj_paths + dstart, dtlen)
|
||||
dpos += dtlen
|
||||
dedup[dpos] = '\0'
|
||||
if dpos > 0 and dpos != obj_paths_len:
|
||||
obj_paths = dedup
|
||||
obj_paths_len = dpos
|
||||
|
||||
# 收集 includes.binary 的 .obj 文件路径
|
||||
EXTRA_BUF_SIZE: t.CSizeT = 32768
|
||||
extra_objs: bytes = _mbuddy.alloc(EXTRA_BUF_SIZE)
|
||||
|
||||
@@ -74,8 +74,16 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
if log is not None:
|
||||
log.banner("Phase1: 扫描 includes(按需翻译)")
|
||||
|
||||
# 扫描 includes 目录
|
||||
# 扫描 includes 目录(含每文件 SHA1 计算计时)
|
||||
t_scan0: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
result: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, includes_dir)
|
||||
t_scan1: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
fb_scan: str = VLogger.fmt_buf()
|
||||
if fb_scan is not None:
|
||||
viperlib.snprintf(fb_scan, 1024,
|
||||
"扫描 includes 总耗时: %llu ms (%d 文件, 含 SHA1 计算)",
|
||||
t_scan1 - t_scan0, result.Count if result is not None else 0)
|
||||
VLogger.info(fb_scan, "Phase1")
|
||||
if result is None:
|
||||
VLogger.error("扫描失败", "Phase1")
|
||||
return 1
|
||||
@@ -126,6 +134,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
p1a_registered: int = 0
|
||||
p1a_skipped: int = 0
|
||||
p1a_failed: int = 0
|
||||
# 1a-pre 阶段总耗时起点(GetTickCount64,ms;对齐 Phase2 计时插桩)
|
||||
t_pre0: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
|
||||
for i in range(result.Count):
|
||||
# 文件级 mark:import 依赖收集完(deps 写盘 + PopulateIncludesDeps
|
||||
@@ -259,6 +269,14 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
# 回收本文件 AST/lexer/token(deps 已写盘、依赖存储器已深拷贝)
|
||||
mb.reset_to(scan_mark_a)
|
||||
|
||||
# 1a-pre 阶段总耗时(全部 includes 文件读+parse+import 依赖扫描)
|
||||
t_pre1: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
fb_pre: str = VLogger.fmt_buf()
|
||||
if fb_pre is not None:
|
||||
viperlib.snprintf(fb_pre, 1024, "1a-pre 总耗时: %llu ms (%d 文件扫描 import 依赖)",
|
||||
t_pre1 - t_pre0, result.Count)
|
||||
VLogger.info(fb_pre, "Phase1")
|
||||
|
||||
if p1a_failed > 0:
|
||||
fb_p1apre: str = VLogger.fmt_buf()
|
||||
if fb_p1apre is not None:
|
||||
@@ -397,6 +415,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
|
||||
# 遍历文件:优先使用拓扑顺序,回退到字母序
|
||||
iter_count: int = topo_count if topo_count > 0 else result.Count
|
||||
# 1a 阶段总耗时起点(struct/enum/union 注册)
|
||||
t_a0: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
for i in range(iter_count):
|
||||
# 每文件级 mark:翻译完回收该文件 AST(注册数据在 perm_pool)
|
||||
p1a_mark: t.CSizeT = mb.mark()
|
||||
@@ -430,6 +450,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
p1a_skp += 1
|
||||
continue
|
||||
|
||||
# 单文件计时起点(读文件 + parse 段,定位 1a 卡点)
|
||||
t_fa0: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
|
||||
# 读取文件内容
|
||||
file_path_r: str = entry_r.Path
|
||||
f_r: fileio.File | t.CPtr = fileio.File(file_path_r, fileio.MODE.R)
|
||||
@@ -468,6 +491,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
p1a_fl += 1
|
||||
continue
|
||||
|
||||
# 计时点 1:读文件 + parse 完成
|
||||
t_fa1: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
|
||||
# 创建 Translator,设置 _declare_only=1(注册 struct/enum/union)
|
||||
tr_r: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator()
|
||||
if tr_r is None:
|
||||
@@ -484,11 +510,22 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
GenApi.clear_ctypedefs()
|
||||
GenApi.reset_visible_structs(mb, 0)
|
||||
ret_r: int = tr_r.translate(tree_r)
|
||||
# 计时点 2:translate(declare=1) 返回
|
||||
t_fa2: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
if ret_r != 0:
|
||||
p1a_fl += 1
|
||||
else:
|
||||
p1a_reg += 1
|
||||
|
||||
# 逐文件进度日志(parse/translate 两段,定位 1a 卡点)
|
||||
fb_1a: str = VLogger.fmt_buf()
|
||||
if fb_1a is not None:
|
||||
viperlib.snprintf(fb_1a, 1024,
|
||||
"[%d/%d] 1a: %s (parse=%llu ms, translate=%llu ms, total=%llu ms)",
|
||||
i + 1, iter_count, file_path_r,
|
||||
t_fa1 - t_fa0, t_fa2 - t_fa1, t_fa2 - t_fa0)
|
||||
VLogger.info(fb_1a, "Phase1")
|
||||
|
||||
# 释放 Translator 的 C malloc 资源
|
||||
if tr_r._global_names is not None:
|
||||
stdlib.free(tr_r._global_names)
|
||||
@@ -500,6 +537,14 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
# reset 不影响;IncludesScanner result 等在 p1a_mark 前分配同样保留)
|
||||
mb.reset_to(p1a_mark)
|
||||
|
||||
# 1a 阶段总耗时(struct/enum/union 注册,含每文件读+parse+翻译声明)
|
||||
t_a1: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
fb_a: str = VLogger.fmt_buf()
|
||||
if fb_a is not None:
|
||||
viperlib.snprintf(fb_a, 1024, "1a 总耗时: %llu ms (注册 struct/enum, reg=%d skp=%d)",
|
||||
t_a1 - t_a0, p1a_reg, p1a_skp)
|
||||
VLogger.info(fb_a, "Phase1")
|
||||
|
||||
if p1a_fl > 0:
|
||||
fb_p1ar: str = VLogger.fmt_buf()
|
||||
if fb_p1ar is not None:
|
||||
@@ -544,6 +589,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
# ============================================================
|
||||
p1bpre_failed: int = 0
|
||||
dir_len_pv: t.CSizeT = string.strlen(temp_dir)
|
||||
# 1b-pre 阶段总耗时起点(vpi 预生成)
|
||||
t_pv0: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
for i_pv in range(result.Count):
|
||||
entry_addr_pv: t.CUInt64T = t.CUInt64T(result.Entries) + i_pv * entry_size
|
||||
entry_pv: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_pv, t.CPtr))
|
||||
@@ -620,6 +667,14 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
# 回收本文件 AST(vpi 已写盘,AST 不再需要;mark1 后无其他持久数据)
|
||||
mb.reset_to(mark1)
|
||||
|
||||
# 1b-pre 阶段总耗时(vpi 预生成)
|
||||
t_pv1: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
fb_pv: str = VLogger.fmt_buf()
|
||||
if fb_pv is not None:
|
||||
viperlib.snprintf(fb_pv, 1024, "1b-pre 总耗时: %llu ms (vpi 预生成)",
|
||||
t_pv1 - t_pv0)
|
||||
VLogger.info(fb_pv, "Phase1")
|
||||
|
||||
if p1bpre_failed > 0:
|
||||
fb_p1bpre: str = VLogger.fmt_buf()
|
||||
if fb_p1bpre is not None:
|
||||
@@ -632,6 +687,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
translated: int = 0
|
||||
skipped: int = 0
|
||||
failed: int = 0
|
||||
# 1b 阶段总耗时起点(全量翻译)
|
||||
t_b0: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
|
||||
loop_n_b: int = result.Count
|
||||
if topo_count > 0:
|
||||
@@ -705,6 +762,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
|
||||
stdlib.free(stub_path)
|
||||
|
||||
# 单文件计时起点:读文件(parse/translate/dump 三段,对齐 Phase2 插桩)
|
||||
t_f0: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
|
||||
# 读取文件内容
|
||||
file_path: str = entry.Path
|
||||
f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R)
|
||||
@@ -762,6 +822,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
failed += 1
|
||||
continue
|
||||
|
||||
# 计时点 1:读文件 + lexer/tokenize/parse 完成
|
||||
t_f1: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
|
||||
# 文本扫描注册 CTypedef(stdint.vp 崩溃根因修复):AST 字符串字段
|
||||
# (attr/id)token 零拷贝指向 src_buf,跨阶段内容不稳定(悬空),
|
||||
# ScanCTypedefDeclarations 读 attr 会 0xC0000005。改用源码文本逐行
|
||||
@@ -769,18 +832,27 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
GenApi.RegisterCTypedefFromSource(mb, src_buf)
|
||||
|
||||
# 生成 .vpi 存根文件(直接遍历 AST,不依赖 PythonToStubConverter)
|
||||
pyi_buf: bytes = stdlib.malloc(Phase1.PYI_BUF_SIZE)
|
||||
if pyi_buf is not None:
|
||||
pyi_pos: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree, entry.RelPath, pyi_buf, Phase1.PYI_BUF_SIZE)
|
||||
if pyi_pos > 0:
|
||||
pyi_path: str = StubMergerCollect._sliced_path(temp_dir, dir_len, sha1, "vpi")
|
||||
if pyi_path is not None:
|
||||
pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.W)
|
||||
if not pf.closed:
|
||||
pf.write(pyi_buf, pyi_pos)
|
||||
pf.close()
|
||||
stdlib.free(pyi_path)
|
||||
stdlib.free(pyi_buf)
|
||||
# 1b-pre 已为所有待翻译文件生成 vpi,此处仅兜底:vpi 缺失才生成
|
||||
# (消除 1b-pre 与 1b 对同一文件的重复 _GeneratePyiFromAst 工作)
|
||||
vpi_path_1b: str = StubMergerCollect._sliced_path(temp_dir, dir_len, sha1, "vpi")
|
||||
if vpi_path_1b is not None:
|
||||
vf_1b: fileio.File | t.CPtr = fileio.File(vpi_path_1b, fileio.MODE.R)
|
||||
vpi_exists_1b: int = 0
|
||||
if not vf_1b.closed:
|
||||
vf_1b.close()
|
||||
vpi_exists_1b = 1
|
||||
if vpi_exists_1b == 0:
|
||||
pyi_buf: bytes = stdlib.malloc(Phase1.PYI_BUF_SIZE)
|
||||
if pyi_buf is not None:
|
||||
pyi_pos: t.CSizeT = StubConverter._GeneratePyiFromAst(
|
||||
mb, tree, entry.RelPath, pyi_buf, Phase1.PYI_BUF_SIZE)
|
||||
if pyi_pos > 0:
|
||||
pf_1b: fileio.File | t.CPtr = fileio.File(vpi_path_1b, fileio.MODE.W)
|
||||
if not pf_1b.closed:
|
||||
pf_1b.write(pyi_buf, pyi_pos)
|
||||
pf_1b.close()
|
||||
stdlib.free(pyi_buf)
|
||||
stdlib.free(vpi_path_1b)
|
||||
|
||||
# 翻译 AST → LLVM IR
|
||||
tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator()
|
||||
@@ -810,6 +882,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
stdlib.exit(1)
|
||||
|
||||
ret: int = tr.translate(tree)
|
||||
# 计时点 2:translate 返回
|
||||
t_f2: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
# 诊断:translate 正常返回(若挂起在 translate 内部,此行不会打印,
|
||||
# 用于区分"translate 内部挂起"与"后续 dump 挂起")
|
||||
if ret == 0:
|
||||
@@ -891,6 +965,16 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
stdlib.free(text_path_p1)
|
||||
stdlib.free(text_buf)
|
||||
|
||||
# 计时点 3:dump(stub+text)完成;输出单文件三段耗时
|
||||
t_f3: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
fb_t: str = VLogger.fmt_buf()
|
||||
if fb_t is not None:
|
||||
viperlib.snprintf(fb_t, 1024,
|
||||
"[%d/%d] 翻译: %s (parse=%llu ms, translate=%llu ms, dump=%llu ms, total=%llu ms)",
|
||||
i + 1, loop_n_b, file_path,
|
||||
t_f1 - t_f0, t_f2 - t_f1, t_f3 - t_f2, t_f3 - t_f0)
|
||||
VLogger.info(fb_t, "Phase1")
|
||||
|
||||
# save dependencies(_imported_modules) for Phase B
|
||||
deps_path_p1: str = StubMergerCollect._sliced_path(temp_dir, dir_len_p1, sha1, "deps.txt")
|
||||
if deps_path_p1 is not None:
|
||||
@@ -945,6 +1029,14 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
VLogger.error(fb, "Phase1")
|
||||
stdlib.exit(1)
|
||||
|
||||
# 1b 阶段总耗时(全量翻译 + dump)
|
||||
t_b1: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
fb_b: str = VLogger.fmt_buf()
|
||||
if fb_b is not None:
|
||||
viperlib.snprintf(fb_b, 1024, "1b 总耗时: %llu ms (全量翻译, trans=%d skip=%d fail=%d)",
|
||||
t_b1 - t_b0, translated, skipped, failed)
|
||||
VLogger.info(fb_b, "Phase1")
|
||||
|
||||
# 释放 Phase 1b 使用的拓扑排序资源
|
||||
if topo_order is not None:
|
||||
mb.free(topo_order)
|
||||
|
||||
@@ -4,6 +4,7 @@ import string
|
||||
import stdlib
|
||||
import memhub
|
||||
import viperlib
|
||||
import sys
|
||||
import w32.fileio as fileio
|
||||
import w32.win32file
|
||||
import w32.win32base
|
||||
@@ -379,8 +380,17 @@ def _FindClassDefSha1(class_names_buf: bytes, def_sha1s_buf: bytes,
|
||||
# ============================================================
|
||||
def _ScanTreeForContainers(node: ast.AST | t.CPtr,
|
||||
need_list_box: t.CPtr,
|
||||
need_dict_box: t.CPtr):
|
||||
need_dict_box: t.CPtr,
|
||||
depth: int = 0):
|
||||
"""递归扫描 AST(字段 + 语句块),检测 list/dict 容器使用"""
|
||||
# 递归深度守卫:AST 损坏成自引用环(字段/children 回指祖先)时无限
|
||||
# 递归直至栈耗尽(每个 includes 文件 parse 后必执行)。fail-fast 终止。
|
||||
if depth > 128:
|
||||
fb_stc: str = VLogger.fmt_buf()
|
||||
if fb_stc is not None:
|
||||
viperlib.snprintf(fb_stc, 256, "容器扫描递归过深(AST 环或嵌套超过 128 层)")
|
||||
VLogger.error(fb_stc, "Phase1")
|
||||
sys.exit(1)
|
||||
if node is None:
|
||||
return
|
||||
k_s: int = node.kind()
|
||||
@@ -393,21 +403,21 @@ def _ScanTreeForContainers(node: ast.AST | t.CPtr,
|
||||
need_dict_box[0] = 1
|
||||
elif k_s == ast.ASTKind.Subscript:
|
||||
sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||||
_ScanTreeForContainers(sub_s.value, need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(sub_s.slice, need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(sub_s.value, need_list_box, need_dict_box, depth + 1)
|
||||
_ScanTreeForContainers(sub_s.slice, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.BinOp:
|
||||
bop_s: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||||
_ScanTreeForContainers(bop_s.left, need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(bop_s.right, need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(bop_s.left, need_list_box, need_dict_box, depth + 1)
|
||||
_ScanTreeForContainers(bop_s.right, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.Call:
|
||||
cl_s2: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||||
_ScanTreeForContainers(cl_s2.func, need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(cl_s2.func, need_list_box, need_dict_box, depth + 1)
|
||||
cl_args_s: list[ast.AST | t.CPtr] | t.CPtr = cl_s2.args
|
||||
if cl_args_s is not None:
|
||||
na_s: t.CSizeT = len(cl_args_s)
|
||||
i_a2: t.CSizeT
|
||||
for i_a2 in range(na_s):
|
||||
_ScanTreeForContainers(cl_args_s.get(i_a2), need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(cl_args_s.get(i_a2), need_list_box, need_dict_box, depth + 1)
|
||||
cl_kws_s: list[ast.AST | t.CPtr] | t.CPtr = cl_s2.keywords
|
||||
if cl_kws_s is not None:
|
||||
nk_s: t.CSizeT = len(cl_kws_s)
|
||||
@@ -415,23 +425,23 @@ def _ScanTreeForContainers(node: ast.AST | t.CPtr,
|
||||
for i_k2 in range(nk_s):
|
||||
kw_s: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(cl_kws_s.get(i_k2))
|
||||
if kw_s is not None:
|
||||
_ScanTreeForContainers(kw_s.value, need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(kw_s.value, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.Assign:
|
||||
asn_s: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
|
||||
_ScanTreeForContainers(asn_s.value, need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(asn_s.value, need_list_box, need_dict_box, depth + 1)
|
||||
tgts_s: list[ast.AST | t.CPtr] | t.CPtr = asn_s.targets
|
||||
if tgts_s is not None:
|
||||
nt_s: t.CSizeT = len(tgts_s)
|
||||
i_t2: t.CSizeT
|
||||
for i_t2 in range(nt_s):
|
||||
_ScanTreeForContainers(tgts_s.get(i_t2), need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(tgts_s.get(i_t2), need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.AnnAssign:
|
||||
aa_s2: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||||
_ScanTreeForContainers(aa_s2.annotation, need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(aa_s2.value, need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(aa_s2.annotation, need_list_box, need_dict_box, depth + 1)
|
||||
_ScanTreeForContainers(aa_s2.value, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.FunctionDef:
|
||||
fn_s: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
|
||||
_ScanTreeForContainers(fn_s.returns, need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(fn_s.returns, need_list_box, need_dict_box, depth + 1)
|
||||
fn_args_s: ast.Arguments | t.CPtr = fn_s.args
|
||||
if fn_args_s is not None:
|
||||
fa_s: list[ast.AST | t.CPtr] | t.CPtr = fn_args_s.args
|
||||
@@ -441,7 +451,7 @@ def _ScanTreeForContainers(node: ast.AST | t.CPtr,
|
||||
for i_f2 in range(nf_s):
|
||||
arg_s: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(fa_s.get(i_f2))
|
||||
if arg_s is not None:
|
||||
_ScanTreeForContainers(arg_s.annotation, need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(arg_s.annotation, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.ClassDef:
|
||||
cd_s: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(node)
|
||||
bases_s: list[ast.AST | t.CPtr] | t.CPtr = cd_s.bases
|
||||
@@ -449,10 +459,10 @@ def _ScanTreeForContainers(node: ast.AST | t.CPtr,
|
||||
nb_s: t.CSizeT = len(bases_s)
|
||||
i_b2: t.CSizeT
|
||||
for i_b2 in range(nb_s):
|
||||
_ScanTreeForContainers(bases_s.get(i_b2), need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(bases_s.get(i_b2), need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.Attribute:
|
||||
at_s: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||||
_ScanTreeForContainers(at_s.value, need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(at_s.value, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.Tuple:
|
||||
tu_s: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node)
|
||||
elts_s: list[ast.AST | t.CPtr] | t.CPtr = tu_s.elts
|
||||
@@ -460,25 +470,25 @@ def _ScanTreeForContainers(node: ast.AST | t.CPtr,
|
||||
ne_s: t.CSizeT = len(elts_s)
|
||||
i_e2: t.CSizeT
|
||||
for i_e2 in range(ne_s):
|
||||
_ScanTreeForContainers(elts_s.get(i_e2), need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(elts_s.get(i_e2), need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.UnaryOp:
|
||||
uop_s: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
|
||||
_ScanTreeForContainers(uop_s.operand, need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(uop_s.operand, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.Expr:
|
||||
ex_s: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node)
|
||||
_ScanTreeForContainers(ex_s.value, need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(ex_s.value, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.Return:
|
||||
rt_s: ast.Return | t.CPtr = (ast.Return | t.CPtr)(node)
|
||||
_ScanTreeForContainers(rt_s.value, need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(rt_s.value, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.Compare:
|
||||
cp_s: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node)
|
||||
_ScanTreeForContainers(cp_s.left, need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(cp_s.left, need_list_box, need_dict_box, depth + 1)
|
||||
cps_s: list[ast.AST | t.CPtr] | t.CPtr = cp_s.comparators
|
||||
if cps_s is not None:
|
||||
nc_s: t.CSizeT = len(cps_s)
|
||||
i_c2: t.CSizeT
|
||||
for i_c2 in range(nc_s):
|
||||
_ScanTreeForContainers(cps_s.get(i_c2), need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(cps_s.get(i_c2), need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.BoolOp:
|
||||
bo_s: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node)
|
||||
bvs_s: list[ast.AST | t.CPtr] | t.CPtr = bo_s.values
|
||||
@@ -486,7 +496,7 @@ def _ScanTreeForContainers(node: ast.AST | t.CPtr,
|
||||
nv_s: t.CSizeT = len(bvs_s)
|
||||
i_v2: t.CSizeT
|
||||
for i_v2 in range(nv_s):
|
||||
_ScanTreeForContainers(bvs_s.get(i_v2), need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(bvs_s.get(i_v2), need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.List:
|
||||
# [] 字面量
|
||||
need_list_box[0] = 1
|
||||
@@ -499,4 +509,4 @@ def _ScanTreeForContainers(node: ast.AST | t.CPtr,
|
||||
n_s: t.CSizeT = len(ch_s)
|
||||
ci_s: t.CSizeT
|
||||
for ci_s in range(n_s):
|
||||
_ScanTreeForContainers(ch_s.get(ci_s), need_list_box, need_dict_box)
|
||||
_ScanTreeForContainers(ch_s.get(ci_s), need_list_box, need_dict_box, depth + 1)
|
||||
@@ -35,6 +35,7 @@ LinkerFlags: str = None # 链接器参数(空格分隔,从 linker.
|
||||
LinkerOutput: str = None
|
||||
TargetTriple: str = None
|
||||
TargetDataLayout: str = None
|
||||
ProjectDir: str = None # project.vpj 所在目录(resolve_paths 设置)
|
||||
Sha1SliceLevel: int = 0 # SHA1 切片层数(目录分散等级)
|
||||
StrictMode: int = 0
|
||||
IncludesDir: str = None # includes 目录路径(从 includes 数组首元素,兼容单目录场景)
|
||||
@@ -146,7 +147,7 @@ def Load_project_config(path: str) -> int:
|
||||
# 读取 includes 数组(支持多目录:首元素存 IncludesDir,全部拼接存 IncludesDirs)
|
||||
includes_val: JsonValue | t.CPtr = root["includes"]
|
||||
if includes_val is not None and includes_val.is_array():
|
||||
arr_len: t.CSizeT = includes_val.__len__()
|
||||
arr_len: t.CSizeT = len(includes_val)
|
||||
inc_buf: bytes = stdlib.malloc(2048)
|
||||
if inc_buf is not None:
|
||||
inc_buf[0] = '\0'
|
||||
@@ -186,12 +187,10 @@ def _join_flags_array(flags_val: JsonValue | t.CPtr) -> str:
|
||||
Returns:
|
||||
空格分隔的字符串,或 None 如果 flags_val 为 None 或非数组或空数组
|
||||
"""
|
||||
if flags_val is None:
|
||||
return None
|
||||
if not flags_val.is_array():
|
||||
return None
|
||||
if flags_val is None: return None
|
||||
if not flags_val.is_array(): return None
|
||||
|
||||
arr_len: t.CSizeT = flags_val.__len__()
|
||||
arr_len: t.CSizeT = len(flags_val)
|
||||
if arr_len == 0:
|
||||
return None
|
||||
|
||||
@@ -385,11 +384,14 @@ def resolve_paths(project_dir: str) -> int:
|
||||
0 表示成功,非 0 表示失败
|
||||
"""
|
||||
global SourceDir, BuildDir, TempDir, OutputDir, IncludesDir, IncludesDirs
|
||||
global ProjectDir
|
||||
if project_dir is None:
|
||||
return 1
|
||||
if _mbuddy is None:
|
||||
return 1
|
||||
|
||||
ProjectDir = project_dir
|
||||
|
||||
SourceDir = _join_path(SourceDir, project_dir)
|
||||
BuildDir = _join_path(BuildDir, project_dir)
|
||||
|
||||
@@ -441,9 +443,103 @@ def resolve_paths(project_dir: str) -> int:
|
||||
IncludesDirs = id_out
|
||||
if IncludesDir is not None:
|
||||
IncludesDir = _join_path(IncludesDir, project_dir)
|
||||
# linker.flags 中 `-T <脚本>` 的链接脚本路径同样基于 project_dir 解析,
|
||||
# 否则 subprocess 按进程 cwd(TransPyC/)找 linker.ld → ld.lld 报
|
||||
# "cannot find linker script linker.ld"
|
||||
_resolve_linker_t_paths(project_dir)
|
||||
return 0
|
||||
|
||||
|
||||
def _join_path_abs(rel: str, project_dir: str) -> str:
|
||||
"""将相对路径基于 project_dir 拼接为绝对路径(用于 -T 链接脚本等)
|
||||
|
||||
已为绝对路径(/ \\ 开头)或盘符形式(x:)时原样返回。
|
||||
"""
|
||||
if rel is None:
|
||||
return None
|
||||
rel_len: t.CSizeT = string.strlen(rel)
|
||||
if rel_len == 0:
|
||||
return rel
|
||||
if rel[0] == '/' or rel[0] == '\\':
|
||||
return rel
|
||||
if rel_len >= 2 and rel[1] == ':':
|
||||
return rel
|
||||
dir_len: t.CSizeT = string.strlen(project_dir)
|
||||
if dir_len == 0:
|
||||
return rel
|
||||
total_len: t.CSizeT = dir_len + 1 + rel_len + 1
|
||||
buf: str = _mbuddy.alloc(total_len)
|
||||
if buf is None:
|
||||
return rel
|
||||
viperlib.snprintf(buf, total_len, "%s/%s", project_dir, rel)
|
||||
return buf
|
||||
|
||||
|
||||
def _resolve_linker_t_paths(project_dir: str) -> None:
|
||||
"""将 LinkerFlags 中 `-T <相对路径>` 的链接脚本路径解析为绝对路径
|
||||
|
||||
ld.lld 的 -T 参数若是相对路径,将按 subprocess 进程 cwd 解析而找不到
|
||||
脚本。逐 token 扫描 LinkerFlags,遇 -T 其后 token 若非绝对路径则基于
|
||||
project_dir 拼接(与 resolve_paths 对其他相对路径的处理保持一致)。
|
||||
"""
|
||||
global LinkerFlags
|
||||
if LinkerFlags is None or project_dir is None:
|
||||
return
|
||||
fl_total: t.CSizeT = string.strlen(LinkerFlags)
|
||||
if fl_total == 0:
|
||||
return
|
||||
out: str = _mbuddy.alloc(fl_total * 2 + 512)
|
||||
if out is None:
|
||||
return
|
||||
out[0] = '\0'
|
||||
out_pos: t.CSizeT = 0
|
||||
i: t.CSizeT = 0
|
||||
prev_is_t: int = 0 # 前一 token 是否为 -T
|
||||
while i < fl_total:
|
||||
# 跳过前导空格
|
||||
while i < fl_total and LinkerFlags[i] == ' ':
|
||||
i += 1
|
||||
if i >= fl_total:
|
||||
break
|
||||
start: t.CSizeT = i
|
||||
while i < fl_total and LinkerFlags[i] != ' ':
|
||||
i += 1
|
||||
tok_len: t.CSizeT = i - start
|
||||
is_t_flag: int = 0
|
||||
if tok_len == 2 and LinkerFlags[start] == '-' and LinkerFlags[start + 1] == 'T':
|
||||
is_t_flag = 1
|
||||
# 输出分隔符(前一 token 之后)
|
||||
if out_pos > 0:
|
||||
out[out_pos] = ' '
|
||||
out_pos += 1
|
||||
if is_t_flag:
|
||||
string.strcpy(out + out_pos, "-T")
|
||||
out_pos += 2
|
||||
elif prev_is_t != 0:
|
||||
# -T 后的脚本路径:非绝对路径则基于 project_dir 拼接
|
||||
tok_buf: str = _mbuddy.alloc(tok_len + 1)
|
||||
if tok_buf is not None:
|
||||
string.memcpy(tok_buf, LinkerFlags + start, tok_len)
|
||||
tok_buf[tok_len] = '\0'
|
||||
abs_path: str = _join_path_abs(tok_buf, project_dir)
|
||||
if abs_path is not None:
|
||||
p_len: t.CSizeT = string.strlen(abs_path)
|
||||
string.strcpy(out + out_pos, abs_path)
|
||||
out_pos += p_len
|
||||
else:
|
||||
string.memcpy(out + out_pos, LinkerFlags + start, tok_len)
|
||||
out_pos += tok_len
|
||||
else:
|
||||
string.memcpy(out + out_pos, LinkerFlags + start, tok_len)
|
||||
out_pos += tok_len
|
||||
else:
|
||||
string.memcpy(out + out_pos, LinkerFlags + start, tok_len)
|
||||
out_pos += tok_len
|
||||
prev_is_t = is_t_flag
|
||||
out[out_pos] = '\0'
|
||||
LinkerFlags = out
|
||||
|
||||
|
||||
def get_includes_binary_dir() -> str:
|
||||
"""获取 includes.binary 目录路径(includes 目录 + 缓存后缀)
|
||||
|
||||
|
||||
@@ -89,16 +89,18 @@ def compute_sha1(pool: memhub.MemBuddy | t.CPtr, content: str) -> str:
|
||||
|
||||
|
||||
# ============================================================
|
||||
# is_vp_or_py_at - 检查路径段是否以 .vp/.py 后缀结尾
|
||||
# is_vp_at - 检查路径段是否以 .vp 后缀结尾
|
||||
# ============================================================
|
||||
def is_vp_or_py_at(p: str, start: t.CSizeT, plen: t.CSizeT) -> int:
|
||||
"""检查 p[start, start+plen) 是否以 .vp/.py 后缀结尾(1=是,0=否)"""
|
||||
def is_vp_at(p: str, start: t.CSizeT, plen: t.CSizeT) -> int:
|
||||
"""检查 p[start, start+plen) 是否以 .vp 后缀结尾(1=是,0=否)。
|
||||
|
||||
不再识别 .py(移除 vp -> py 后缀识别回退:Viper 源文件仅 .vp)。
|
||||
"""
|
||||
if p is None or plen <= 3:
|
||||
return 0
|
||||
base: t.CSizeT = start + plen - 3
|
||||
if p[base] == '.':
|
||||
if p[base + 1] == 'v' and p[base + 2] == 'p': return 1
|
||||
if p[base + 1] == 'p' and p[base + 2] == 'y': return 1
|
||||
if p[base] == '.' and p[base + 1] == 'v' and p[base + 2] == 'p':
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
@@ -167,8 +169,8 @@ def PathToModuleName(path: str, strip_includes_prefix: int) -> str:
|
||||
if psep_ch == '/' or psep_ch == '\\':
|
||||
path_start = prefix_len
|
||||
plen = plen - prefix_len
|
||||
# 去掉 .vp 或 .py 后缀(.vp 为 Viper 源,.py 向后兼容)
|
||||
if is_vp_or_py_at(path, path_start, plen) != 0:
|
||||
# 去掉 .vp 后缀(Viper 源文件仅 .vp,不再识别 .py)
|
||||
if is_vp_at(path, path_start, plen) != 0:
|
||||
plen -= 3
|
||||
if plen == 0:
|
||||
return None
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import lib.core.Gen.GenApi as GenApi
|
||||
import lib.core.VLogger as VLogger
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
@@ -6,6 +7,7 @@ import string
|
||||
import memhub
|
||||
import viperlib
|
||||
import stdlib
|
||||
import sys
|
||||
|
||||
# ============================================================
|
||||
# StubGen.Converter - vpi 存根文件生成器
|
||||
@@ -184,7 +186,7 @@ def _eval_cdefine_value_cache(node: ast.AST | t.CPtr) -> t.CInt64T:
|
||||
return _eval_binop_int(node)
|
||||
if k == ast.ASTKind.Call:
|
||||
cl_c: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||||
if cl_c.args is not None and cl_c.args.__len__() > 0:
|
||||
if cl_c.args is not None and len(cl_c.args) > 0:
|
||||
return _eval_cdefine_value_cache(cl_c.args.get(0))
|
||||
return 0
|
||||
if k == ast.ASTKind.Name:
|
||||
@@ -244,8 +246,18 @@ def _PyiIndent(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
||||
# 支持: Name, Attribute, Subscript, BinOp(|), Constant(前向引用), Tuple
|
||||
# ============================================================
|
||||
def _PyiTypeStr(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
||||
annot: ast.AST | t.CPtr) -> t.CSizeT:
|
||||
annot: ast.AST | t.CPtr,
|
||||
depth: int = 0) -> t.CSizeT:
|
||||
"""递归生成类型注解字符串,返回新的 pos"""
|
||||
# 递归深度守卫:AST 损坏成自引用环(Attribute.value/Subscript.slice/
|
||||
# BinOp.left 等回指祖先)时无限递归直至栈耗尽(Phase1 vpi 生成最先
|
||||
# 执行,早于翻译阶段)。fail-fast 终止,不静默回退。
|
||||
if depth > 64:
|
||||
fb_pt: str = VLogger.fmt_buf()
|
||||
if fb_pt is not None:
|
||||
viperlib.snprintf(fb_pt, 256, "vpi 类型注解递归过深(AST 环或嵌套超过 64 层)")
|
||||
VLogger.error(fb_pt, "StubGen")
|
||||
sys.exit(1)
|
||||
if annot is None:
|
||||
return _PyiEmit(buf, buf_size, pos, "t.CInt")
|
||||
|
||||
@@ -261,7 +273,7 @@ def _PyiTypeStr(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
||||
# Attribute: 属性引用 (如 t.CInt, memhub.MemBuddy)
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, at.value)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, at.value, depth + 1)
|
||||
pos = _PyiEmit(buf, buf_size, pos, ".")
|
||||
if at.attr is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, at.attr)
|
||||
@@ -270,18 +282,18 @@ def _PyiTypeStr(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
||||
# Subscript: 下标类型 (如 list[int], t.CArray[elem, count])
|
||||
if k == ast.ASTKind.Subscript:
|
||||
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, sub.value)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, sub.value, depth + 1)
|
||||
pos = _PyiEmit(buf, buf_size, pos, "[")
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, sub.slice)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, sub.slice, depth + 1)
|
||||
pos = _PyiEmit(buf, buf_size, pos, "]")
|
||||
return pos
|
||||
|
||||
# BinOp: 联合类型 (如 int | str, File | t.CPtr)
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, bop.left)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, bop.left, depth + 1)
|
||||
pos = _PyiEmit(buf, buf_size, pos, " | ")
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, bop.right)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, bop.right, depth + 1)
|
||||
return pos
|
||||
|
||||
# Constant: 字符串前向引用 (如 'MyClass')、None 或数字常量(CArray count)
|
||||
@@ -313,30 +325,30 @@ def _PyiTypeStr(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
||||
tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(annot)
|
||||
if tup.elts is not None:
|
||||
tup_elts: list[ast.AST | t.CPtr] | t.CPtr = tup.elts
|
||||
tn: t.CSizeT = tup_elts.__len__()
|
||||
tn: t.CSizeT = len(tup_elts)
|
||||
ti: t.CSizeT = 0
|
||||
while ti < tn:
|
||||
if ti > 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
el: ast.AST | t.CPtr = tup_elts.get(ti)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, el)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, el, depth + 1)
|
||||
ti += 1
|
||||
return pos
|
||||
|
||||
# Call: 函数调用表达式 (用于装饰器如 @t.NoVTable())
|
||||
if k == ast.ASTKind.Call:
|
||||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(annot)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, cl.func)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, cl.func, depth + 1)
|
||||
pos = _PyiEmit(buf, buf_size, pos, "(")
|
||||
if cl.args is not None:
|
||||
cl_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||||
can: t.CSizeT = cl_args.__len__()
|
||||
can: t.CSizeT = len(cl_args)
|
||||
cai: t.CSizeT = 0
|
||||
while cai < can:
|
||||
if cai > 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
ca: ast.AST | t.CPtr = cl_args.get(cai)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, ca)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, ca, depth + 1)
|
||||
cai += 1
|
||||
pos = _PyiEmit(buf, buf_size, pos, ")")
|
||||
return pos
|
||||
@@ -345,6 +357,79 @@ def _PyiTypeStr(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
||||
return _PyiEmit(buf, buf_size, pos, "t.CInt")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _PyiDefaultStr - 生成默认值表达式文本
|
||||
#
|
||||
# 用于 vpi 签名 '= <default>' 输出(如 depth: int = 0)。
|
||||
# vpi stub 必须保留默认值:VpiReader 解析后注册默认参数表,
|
||||
# 跨模块缺参调用(如 resolve_annotation_type 的 depth=0)才能
|
||||
# 用默认值填充,否则被调函数读到栈垃圾(假报递归过深/崩溃)。
|
||||
# 支持: Constant(int/str/bool/None), Name(CDefine 常量), UnaryOp。
|
||||
# ============================================================
|
||||
def _PyiDefaultStr(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
||||
node: ast.AST | t.CPtr,
|
||||
depth: int = 0) -> t.CSizeT:
|
||||
"""生成默认值表达式文本到 buf,返回新的 pos"""
|
||||
# 递归深度守卫:AST 损坏成自引用环时 fail-fast 终止(同 _PyiTypeStr)
|
||||
if depth > 64:
|
||||
fb_pd: str = VLogger.fmt_buf()
|
||||
if fb_pd is not None:
|
||||
viperlib.snprintf(fb_pd, 256, "vpi 默认值表达式递归过深(AST 环或嵌套超过 64 层)")
|
||||
VLogger.error(fb_pd, "StubGen")
|
||||
sys.exit(1)
|
||||
if node is None:
|
||||
return pos
|
||||
|
||||
k: int = node.kind()
|
||||
# Constant: 数字/字符串/bool/None 直接输出字面量
|
||||
if k == ast.ASTKind.Constant:
|
||||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
|
||||
if cn.const_kind == ast.CONST_INT or cn.const_kind == ast.CONST_CHAR:
|
||||
num_buf_dv: str = stdlib.malloc(24)
|
||||
if num_buf_dv is not None:
|
||||
viperlib.snprintf(num_buf_dv, 24, "%d", cn.int_val)
|
||||
pos = _PyiEmit(buf, buf_size, pos, num_buf_dv)
|
||||
stdlib.free(num_buf_dv)
|
||||
return pos
|
||||
if cn.const_kind == ast.CONST_STR:
|
||||
pos = _PyiEmit(buf, buf_size, pos, '"')
|
||||
if cn.str_val is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, cn.str_val)
|
||||
return _PyiEmit(buf, buf_size, pos, '"')
|
||||
if cn.const_kind == ast.CONST_BOOL:
|
||||
if cn.int_val != 0:
|
||||
return _PyiEmit(buf, buf_size, pos, "True")
|
||||
return _PyiEmit(buf, buf_size, pos, "False")
|
||||
if cn.const_kind == ast.CONST_NONE:
|
||||
return _PyiEmit(buf, buf_size, pos, "None")
|
||||
return pos
|
||||
|
||||
# Name: CDefine 常量名(如 share: ULONG = SHARE_READ)
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||||
if nm.id is not None:
|
||||
return _PyiEmit(buf, buf_size, pos, nm.id)
|
||||
return pos
|
||||
|
||||
# UnaryOp: 一元运算(如 -1, ~0)
|
||||
if k == ast.ASTKind.UnaryOp:
|
||||
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
|
||||
if uop.op == ast.OpKind.USub:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "-")
|
||||
elif uop.op == ast.OpKind.UAdd:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "+")
|
||||
elif uop.op == ast.OpKind.Invert:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "~")
|
||||
else:
|
||||
return pos
|
||||
if uop.operand is not None:
|
||||
return _PyiDefaultStr(buf, buf_size, pos, uop.operand, depth + 1)
|
||||
return pos
|
||||
|
||||
# 其它(BinOp 等复杂表达式):不输出,保持无默认值(fail-fast 由调用侧兜底)
|
||||
return pos
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _PyiFunction - 生成函数签名
|
||||
#
|
||||
@@ -357,7 +442,7 @@ def _PyiFunction(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
||||
# 装饰器
|
||||
if fn.decorator_list is not None:
|
||||
fn_decorator_list: list[ast.AST | t.CPtr] | t.CPtr = fn.decorator_list
|
||||
dn: t.CSizeT = fn_decorator_list.__len__()
|
||||
dn: t.CSizeT = len(fn_decorator_list)
|
||||
di: t.CSizeT = 0
|
||||
while di < dn:
|
||||
dec: ast.AST | t.CPtr = fn_decorator_list.get(di)
|
||||
@@ -383,7 +468,17 @@ def _PyiFunction(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
||||
# 位置参数
|
||||
if args.args is not None:
|
||||
args_args: list[ast.AST | t.CPtr] | t.CPtr = args.args
|
||||
an: t.CSizeT = args_args.__len__()
|
||||
an: t.CSizeT = len(args_args)
|
||||
# 默认值右对齐到 args 尾部:defaults[i] 对应 args[an - dn + i]。
|
||||
# vpi stub 必须输出 '= <default>',否则 VpiReader 解析后默认参数
|
||||
# 表无条目,跨模块缺参调用(如 depth=0)读到栈垃圾。
|
||||
# 注意:arg_defaults 必须内联声明(list[ast.AST|CPtr] | t.CPtr 联合
|
||||
# 接收者的 .get 会被 TPC/TPV 误分派——预声明 + 重赋值会解析成
|
||||
# list[int].get 返回 i32 截断指针崩溃;内联声明走 list[ast.ASTptr].get)。
|
||||
arg_defaults: list[ast.AST | t.CPtr] | t.CPtr = args.defaults
|
||||
dn: t.CSizeT = 0
|
||||
if arg_defaults is not None:
|
||||
dn = len(arg_defaults)
|
||||
ai: t.CSizeT = 0
|
||||
while ai < an:
|
||||
if first == 0:
|
||||
@@ -395,6 +490,12 @@ def _PyiFunction(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
||||
if ag.annotation is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ": ")
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, ag.annotation)
|
||||
if arg_defaults is not None and an - dn <= ai:
|
||||
di: t.CSizeT = ai - (an - dn)
|
||||
dnode: ast.AST | t.CPtr = arg_defaults.get(di)
|
||||
if dnode is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, " = ")
|
||||
pos = _PyiDefaultStr(buf, buf_size, pos, dnode)
|
||||
ai += 1
|
||||
|
||||
# *args
|
||||
@@ -442,7 +543,7 @@ def _PyiClass(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
||||
# 装饰器
|
||||
if cls.decorator_list is not None:
|
||||
cls_decorator_list: list[ast.AST | t.CPtr] | t.CPtr = cls.decorator_list
|
||||
dcn: t.CSizeT = cls_decorator_list.__len__()
|
||||
dcn: t.CSizeT = len(cls_decorator_list)
|
||||
dci: t.CSizeT = 0
|
||||
while dci < dcn:
|
||||
ddec: ast.AST | t.CPtr = cls_decorator_list.get(dci)
|
||||
@@ -461,7 +562,7 @@ def _PyiClass(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
||||
# PEP 695 类型参数 (class Foo[T]:)
|
||||
if cls.type_params is not None:
|
||||
cls_type_params: list[ast.AST | t.CPtr] | t.CPtr = cls.type_params
|
||||
tpn: t.CSizeT = cls_type_params.__len__()
|
||||
tpn: t.CSizeT = len(cls_type_params)
|
||||
if tpn > 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "[")
|
||||
tpi: t.CSizeT = 0
|
||||
@@ -477,7 +578,7 @@ def _PyiClass(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
||||
# 基类
|
||||
if cls.bases is not None:
|
||||
cls_bases: list[ast.AST | t.CPtr] | t.CPtr = cls.bases
|
||||
bn: t.CSizeT = cls_bases.__len__()
|
||||
bn: t.CSizeT = len(cls_bases)
|
||||
if bn > 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "(")
|
||||
bi: t.CSizeT = 0
|
||||
@@ -496,7 +597,7 @@ def _PyiClass(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
||||
|
||||
if cls.children is not None:
|
||||
cls_children: list[ast.AST | t.CPtr] | t.CPtr = cls.children
|
||||
cn: t.CSizeT = cls_children.__len__()
|
||||
cn: t.CSizeT = len(cls_children)
|
||||
ci: t.CSizeT = 0
|
||||
while ci < cn:
|
||||
stmt: ast.AST | t.CPtr = cls_children.get(ci)
|
||||
@@ -510,7 +611,7 @@ def _PyiClass(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
||||
if mfn.name is not None and string.strcmp(mfn.name, "__init__") == 0:
|
||||
if mfn.children is not None:
|
||||
mfn_children: list[ast.AST | t.CPtr] | t.CPtr = mfn.children
|
||||
icn: t.CSizeT = mfn_children.__len__()
|
||||
icn: t.CSizeT = len(mfn_children)
|
||||
ici: t.CSizeT = 0
|
||||
while ici < icn:
|
||||
ibody: ast.AST | t.CPtr = mfn_children.get(ici)
|
||||
@@ -595,17 +696,13 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
||||
# = 1<<0 = 1、MASK = 0-1 = -1 → 跨模块读回错误常量 → 索引越界崩溃根因)。
|
||||
# 必须 global 声明:TPV 语义下函数内对模块级变量赋值无 global 时创建局部
|
||||
# 变量(_lookup_cdefine_for_pyi 读到的仍是模块级 None → 缓存永不命中,
|
||||
# 追加58 首版失效根因)。
|
||||
global _g_pyi_cdef_names
|
||||
global _g_pyi_cdef_vals
|
||||
global _g_pyi_cdef_count
|
||||
global _g_pyi_cdef_names, _g_pyi_cdef_vals, _g_pyi_cdef_count
|
||||
if tree.children is not None:
|
||||
pre_children: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||
pcn: t.CSizeT = pre_children.__len__()
|
||||
pcn: t.CSizeT = len(pre_children)
|
||||
# 第一遍:数本文件 t.CDefine 声明数(C 数组需先定长分配)
|
||||
_g_pyi_cdef_count = 0
|
||||
pci0: t.CSizeT = 0
|
||||
while pci0 < pcn:
|
||||
for pci0 in range(pcn):
|
||||
stmt_pc0: ast.AST | t.CPtr = pre_children.get(pci0)
|
||||
if stmt_pc0 is not None and stmt_pc0.kind() == ast.ASTKind.AnnAssign:
|
||||
aa_pc0: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt_pc0)
|
||||
@@ -616,14 +713,13 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
||||
ann_pc0: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(aa_pc0.annotation)
|
||||
if ann_pc0.attr is not None and string.strcmp(ann_pc0.attr, "CDefine") == 0:
|
||||
_g_pyi_cdef_count += 1
|
||||
pci0 += 1
|
||||
if _g_pyi_cdef_count > 0:
|
||||
_g_pyi_cdef_names = (str | t.CPtr)(mb.alloc(t.CSizeT(_g_pyi_cdef_count) * 8))
|
||||
_g_pyi_cdef_vals = (t.CInt64T | t.CPtr)(mb.alloc(t.CSizeT(_g_pyi_cdef_count) * 8))
|
||||
# 第二遍:按声明顺序注册(BinOp 内 Name 引用依赖先前注册项)
|
||||
pci: t.CSizeT = 0
|
||||
cdi: t.CInt = 0
|
||||
while pci < pcn:
|
||||
for pci in range(pcn):
|
||||
stmt_pc: ast.AST | t.CPtr = pre_children.get(pci)
|
||||
if stmt_pc is not None and stmt_pc.kind() == ast.ASTKind.AnnAssign:
|
||||
aa_pc: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt_pc)
|
||||
@@ -638,7 +734,6 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
||||
slot_pc[0] = tgt_pc.id
|
||||
_g_pyi_cdef_vals[cdi] = _eval_cdefine_value_cache(aa_pc.value)
|
||||
cdi += 1
|
||||
pci += 1
|
||||
|
||||
# 文件头
|
||||
pos = _PyiEmit(buf, buf_size, pos, "\"\"\"Auto-generated Python stub file\"\"\"\n\n")
|
||||
@@ -649,29 +744,25 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
||||
return pos
|
||||
|
||||
tree_children: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||
n: t.CSizeT = tree_children.__len__()
|
||||
n: t.CSizeT = len(tree_children)
|
||||
|
||||
# 第一遍扫描:检测 import t/c
|
||||
has_import_t: int = 0
|
||||
has_import_c: int = 0
|
||||
i: t.CSizeT = 0
|
||||
while i < n:
|
||||
for i in range(n):
|
||||
stmt: ast.AST | t.CPtr = tree_children.get(i)
|
||||
if stmt is not None and stmt.kind() == ast.ASTKind.Import:
|
||||
imp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(stmt)
|
||||
if imp.names is not None:
|
||||
imp_names: list[ast.AST | t.CPtr] | t.CPtr = imp.names
|
||||
an: t.CSizeT = imp_names.__len__()
|
||||
ai: t.CSizeT = 0
|
||||
while ai < an:
|
||||
an: t.CSizeT = len(imp_names)
|
||||
for ai in range(an):
|
||||
al: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(imp_names.get(ai))
|
||||
if al is not None and al.name is not None:
|
||||
if string.strcmp(al.name, "t") == 0:
|
||||
has_import_t = 1
|
||||
elif string.strcmp(al.name, "c") == 0:
|
||||
has_import_c = 1
|
||||
ai += 1
|
||||
i += 1
|
||||
|
||||
# 补充缺失的 import t/c
|
||||
if has_import_t == 0 and has_import_c == 0:
|
||||
@@ -684,8 +775,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
||||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||||
|
||||
# 第二遍扫描:生成声明
|
||||
i = 0
|
||||
while i < n:
|
||||
for i in range(n):
|
||||
stmt = tree_children.get(i)
|
||||
if stmt is not None:
|
||||
k: int = stmt.kind()
|
||||
@@ -696,7 +786,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
||||
pos = _PyiEmit(buf, buf_size, pos, "import ")
|
||||
if imp2.names is not None:
|
||||
imp2_names: list[ast.AST | t.CPtr] | t.CPtr = imp2.names
|
||||
an2: t.CSizeT = imp2_names.__len__()
|
||||
an2: t.CSizeT = len(imp2_names)
|
||||
ai2: t.CSizeT = 0
|
||||
while ai2 < an2:
|
||||
if ai2 > 0:
|
||||
@@ -723,7 +813,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
||||
pos = _PyiEmit(buf, buf_size, pos, " import ")
|
||||
if ifr.names is not None:
|
||||
ifr_names: list[ast.AST | t.CPtr] | t.CPtr = ifr.names
|
||||
an3: t.CSizeT = ifr_names.__len__()
|
||||
an3: t.CSizeT = len(ifr_names)
|
||||
ai3: t.CSizeT = 0
|
||||
while ai3 < an3:
|
||||
if ai3 > 0:
|
||||
@@ -822,7 +912,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
||||
call_cv: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aa.value)
|
||||
if call_cv.args is not None:
|
||||
call_args_cv: list[ast.AST | t.CPtr] | t.CPtr = call_cv.args
|
||||
if call_args_cv.__len__() > 0:
|
||||
if len(call_args_cv) > 0:
|
||||
first_arg: ast.AST | t.CPtr = call_args_cv.get(0)
|
||||
if first_arg is not None:
|
||||
arg_kind: int = first_arg.kind()
|
||||
@@ -874,7 +964,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
||||
asg: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt)
|
||||
if asg.targets is not None and asg.value is not None:
|
||||
asg_targets: list[ast.AST | t.CPtr] | t.CPtr = asg.targets
|
||||
atn: t.CSizeT = asg_targets.__len__()
|
||||
atn: t.CSizeT = len(asg_targets)
|
||||
if atn == 1:
|
||||
atg: ast.AST | t.CPtr = asg_targets.get(0)
|
||||
if atg is not None and atg.kind() == ast.ASTKind.Name:
|
||||
@@ -909,8 +999,6 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
||||
pos = _PyiEmit(buf, buf_size, pos, "None")
|
||||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||||
|
||||
i += 1
|
||||
|
||||
# NUL 终止
|
||||
if pos < buf_size:
|
||||
buf[pos] = 0
|
||||
|
||||
@@ -25,6 +25,244 @@ import lib.Stub.StubMerger.StubMergerTopo as StubMergerTopo
|
||||
import lib.Stub.StubMerger.StubMergerIR as StubMergerIR
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
|
||||
# ============================================================
|
||||
# 已见符号表(BuildCombinedIR 去重 O(n²)→O(1))
|
||||
#
|
||||
# Phase B 对每个源文件调用 BuildCombinedIR 组合 IR:原实现对每行
|
||||
# declare/global/type 都在不断增长的 out_buf 全量扫描去重
|
||||
# (_IsFuncDeclaredOrDefined 逐字节 strncmp、strstr 等),依赖最多时
|
||||
# (CallGenCall)单文件 merge 达 12s。改用定长槽位开放寻址哈希表
|
||||
# 记录 out_buf 中已活跃的行:去重查找 O(1)、注释行 O(1) 定位。
|
||||
#
|
||||
# slot 布局(步长 _SEEN_SLOT):
|
||||
# {u64 hash} {u64 pos} {u8 flags} {name[_SEEN_NAME_MAX]} {u8 nul}
|
||||
# 空槽判定:hash==0(memset 全零初始化;FNV-1a 保证 >=2)。
|
||||
# flags:类型表 bit0=1 表示活跃行为完整定义(= type { / = type <),
|
||||
# bit0=0 表示仅 opaque 声明;函数/全局表恒为 0。
|
||||
# pos:活跃行在 out_buf 中的起始位置(注释操作直接 out_buf[pos]=';')。
|
||||
# 注释行不从表中删除:注释后必然立即追加新行(更新 pos),表保持
|
||||
# "有活跃行"不变量。超长名(>= _SEEN_NAME_MAX)不登记,防御性回退。
|
||||
# 表满(count >= cap)fail-fast 报错:静默丢弃登记会致去重失效,
|
||||
# 重复行追加 → llc redefinition(88410e59e3e5f98b .str 常量根因,
|
||||
# 该模块合并 IR 实测 4486 个全局行 > 旧容量 4096,故全局表设 16384)。
|
||||
# ============================================================
|
||||
_SEEN_NAME_MAX: t.CDefine = 256
|
||||
_SEEN_SLOT: t.CDefine = 274 # 8(hash)+8(pos)+1(flags)+256(name)+1(nul)
|
||||
_SEEN_FUNC_CAP: t.CDefine = 16384
|
||||
_SEEN_GLOBAL_CAP: t.CDefine = 16384
|
||||
_SEEN_TYPE_CAP: t.CDefine = 4096
|
||||
_SEEN_FNV_OFFSET: t.CUInt64T = 0xcbf29ce484222325
|
||||
_SEEN_FNV_PRIME: t.CUInt64T = 0x100000001b3
|
||||
|
||||
_seen_funcs: bytes # 已见函数签名表(@"sha1.name"( 等)
|
||||
_seen_funcs_count: int
|
||||
_seen_globals: bytes # 已见全局变量名表(@name)
|
||||
_seen_globals_count: int
|
||||
_seen_types: bytes # 已见类型名表(%name)
|
||||
_seen_types_count: int
|
||||
_seen_key_scratch: bytes # 注册键暂存(跨 truncation 窗口复制)
|
||||
|
||||
def _SeenHash(key: str) -> t.CUInt64T:
|
||||
"""FNV-1a 64 位哈希(对齐 includes/hashtable.vp)"""
|
||||
h: t.CUInt64T = _SEEN_FNV_OFFSET
|
||||
p: str = key
|
||||
while p[0] != 0:
|
||||
h = h ^ t.CUInt64T(p[0])
|
||||
h = h * _SEEN_FNV_PRIME
|
||||
p += 1
|
||||
if h < 2:
|
||||
h = 2
|
||||
return h
|
||||
|
||||
def _SeenFind(tbl: bytes, cap: t.CSizeT, key: str, key_hash: t.CUInt64T) -> t.CSizeT:
|
||||
"""已见表槽位查找:命中返回槽位下标;未命中返回 cap(哨兵)"""
|
||||
if tbl is None or key is None:
|
||||
return cap
|
||||
mask: t.CSizeT = cap - 1
|
||||
idx: t.CSizeT = t.CSizeT(key_hash) & mask
|
||||
i: t.CSizeT = 0
|
||||
while i < cap:
|
||||
off: t.CSizeT = idx * _SEEN_SLOT
|
||||
hp: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(tbl) + off)
|
||||
sh: t.CUInt64T = hp[0]
|
||||
if sh == 0:
|
||||
return cap
|
||||
if sh == key_hash:
|
||||
nm: str = tbl + off + 17
|
||||
if string.strcmp(nm, key) == 0:
|
||||
return idx
|
||||
idx = (idx + 1) & mask
|
||||
i += 1
|
||||
return cap
|
||||
|
||||
def _SeenPresent(tbl: bytes, cap: t.CSizeT, key: str, key_hash: t.CUInt64T) -> int:
|
||||
"""已见表查找:返回 0=不存在;>0=存在(返回值 = flags+1)"""
|
||||
si: t.CSizeT = _SeenFind(tbl, cap, key, key_hash)
|
||||
if si >= cap:
|
||||
return 0
|
||||
return t.CInt(tbl[si * _SEEN_SLOT + 16]) + 1
|
||||
|
||||
def _SeenInsert(tbl: bytes, cap: t.CSizeT, count: int, key: str, key_hash: t.CUInt64T,
|
||||
flags: int, pos: t.CSizeT) -> int:
|
||||
"""已见表插入/更新:key 不存在则新登记(返回 count+1);已存在则 OR flags、更新 pos"""
|
||||
if tbl is None or key is None:
|
||||
return count
|
||||
kl: t.CSizeT = string.strlen(key)
|
||||
if kl >= _SEEN_NAME_MAX:
|
||||
return count
|
||||
if count >= cap:
|
||||
fb_full: str = VLogger.fmt_buf()
|
||||
if fb_full is not None:
|
||||
viperlib.snprintf(fb_full, 1024, "已见符号表满(容量 %d),新增符号登记被丢弃——去重失效,必须增大容量", cap)
|
||||
VLogger.error(fb_full, "StubMerger")
|
||||
return count
|
||||
mask: t.CSizeT = cap - 1
|
||||
idx: t.CSizeT = t.CSizeT(key_hash) & mask
|
||||
i: t.CSizeT = 0
|
||||
while i < cap:
|
||||
off: t.CSizeT = idx * _SEEN_SLOT
|
||||
hp: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(tbl) + off)
|
||||
sh: t.CUInt64T = hp[0]
|
||||
if sh == 0:
|
||||
hp[0] = key_hash
|
||||
pp: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(tbl) + off + 8)
|
||||
pp[0] = t.CUInt64T(pos)
|
||||
tbl[off + 16] = t.CChar(flags)
|
||||
string.strcpy(tbl + off + 17, key)
|
||||
return count + 1
|
||||
if sh == key_hash:
|
||||
nm: str = tbl + off + 17
|
||||
if string.strcmp(nm, key) == 0:
|
||||
pp: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(tbl) + off + 8)
|
||||
pp[0] = t.CUInt64T(pos)
|
||||
tbl[off + 16] = t.CChar(t.CInt(tbl[off + 16]) | flags)
|
||||
return count
|
||||
idx = (idx + 1) & mask
|
||||
i += 1
|
||||
return count
|
||||
|
||||
def _SeenCommentOut(tbl: bytes, cap: t.CSizeT, key: str, key_hash: t.CUInt64T,
|
||||
out_buf: bytes) -> int:
|
||||
"""注释 out_buf 中该符号的活跃行(行首改 ';'),返回 1=已注释 0=无"""
|
||||
si: t.CSizeT = _SeenFind(tbl, cap, key, key_hash)
|
||||
if si >= cap:
|
||||
return 0
|
||||
if t.CInt(tbl[si * _SEEN_SLOT + 16]) != 0:
|
||||
return 0 # 类型表 flags=1:活跃行为完整定义,无可注释的 opaque
|
||||
pp: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(tbl) + si * _SEEN_SLOT + 8)
|
||||
p: t.CUInt64T = pp[0]
|
||||
if out_buf is not None:
|
||||
out_buf[t.CSizeT(p)] = ';'
|
||||
return 1
|
||||
|
||||
def _SeenGetPos(tbl: bytes, cap: t.CSizeT, key: str, key_hash: t.CUInt64T) -> t.CSizeT:
|
||||
"""读取已见表条目记录的活跃行位置;不存在返回 cap(哨兵)"""
|
||||
si: t.CSizeT = _SeenFind(tbl, cap, key, key_hash)
|
||||
if si >= cap:
|
||||
return cap
|
||||
pp: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(tbl) + si * _SEEN_SLOT + 8)
|
||||
return t.CSizeT(pp[0])
|
||||
|
||||
def _RegisterStubLines(buf: bytes, buf_len: t.CSizeT, base_pos: t.CSizeT):
|
||||
"""把本地 stub(整体复制进 out_buf)中的 declare/global/type 全部登记到已见表
|
||||
|
||||
本地 stub.ll 在 BuildCombinedIR 第 1 步整体 strcpy 进 out_buf,不做逐行
|
||||
去重处理,若不同步登记,后续依赖的同名行查表未命中会重复追加 →
|
||||
llc "redefinition of type/global"(7871cc1a... ll:758 根因)。
|
||||
行位置 = base_pos + 行内偏移(复制是 1:1 保序),供注释操作定位。
|
||||
同名重复行(如 61d41cf89...stub.ll 的 _g_gen 出现两次)在复制前将
|
||||
行首改为 ';'(注释掉),表只指向首个活跃行(61d41cf89... ll:9853 根因);
|
||||
若先 opaque 后完整定义,则注释旧行、表升级指向完整定义行。
|
||||
"""
|
||||
global _seen_funcs_count, _seen_globals_count, _seen_types_count
|
||||
if buf is None:
|
||||
return
|
||||
pos: t.CSizeT = 0
|
||||
while pos < buf_len:
|
||||
ls: t.CSizeT = pos
|
||||
while pos < buf_len:
|
||||
if buf[pos] == '\n':
|
||||
break
|
||||
pos += 1
|
||||
ll: t.CSizeT = pos - ls
|
||||
if pos < buf_len:
|
||||
pos += 1
|
||||
line_pos: t.CSizeT = base_pos + ls
|
||||
# declare → 函数签名 @"name"(
|
||||
if ll >= 8 and string.strncmp(buf + ls, "declare ", 8) == 0:
|
||||
at: t.CSizeT = ls + 8
|
||||
while at < ls + ll:
|
||||
if buf[at] == '@':
|
||||
break
|
||||
at += 1
|
||||
if at < ls + ll:
|
||||
lp: t.CSizeT = at + 1
|
||||
while lp < ls + ll:
|
||||
if buf[lp] == '(':
|
||||
break
|
||||
lp += 1
|
||||
if lp < ls + ll:
|
||||
sv_f: t.CChar = buf[lp + 1]
|
||||
buf[lp + 1] = '\0'
|
||||
kh_f: t.CUInt64T = _SeenHash(buf + at)
|
||||
if _SeenPresent(_seen_funcs, _SEEN_FUNC_CAP, buf + at, kh_f) == 0:
|
||||
_seen_funcs_count = _SeenInsert(_seen_funcs, _SEEN_FUNC_CAP, _seen_funcs_count, buf + at, kh_f, 0, line_pos)
|
||||
else:
|
||||
buf[ls] = ';'
|
||||
buf[lp + 1] = sv_f
|
||||
continue
|
||||
# 全局 @name =(键 @name,截断于 '=' 前)
|
||||
if ll > 0 and buf[ls] == '@':
|
||||
# 字符串常量 @.str.{sha1}.{N}:本地 stub 的 external 声明是死代码
|
||||
# (本地 text.ll 有 internal constant 定义),注释掉避免与定义重复
|
||||
if ll >= 5 and buf[ls + 1] == '.' and buf[ls + 2] == 's' and buf[ls + 3] == 't' and buf[ls + 4] == 'r':
|
||||
buf[ls] = ';'
|
||||
continue
|
||||
eq: t.CSizeT = ls + 1
|
||||
while eq < ls + ll:
|
||||
if buf[eq] == '=':
|
||||
break
|
||||
eq += 1
|
||||
if eq < ls + ll:
|
||||
sv_g: t.CChar = buf[eq]
|
||||
buf[eq] = '\0'
|
||||
kh_g: t.CUInt64T = _SeenHash(buf + ls)
|
||||
if _SeenPresent(_seen_globals, _SEEN_GLOBAL_CAP, buf + ls, kh_g) == 0:
|
||||
_seen_globals_count = _SeenInsert(_seen_globals, _SEEN_GLOBAL_CAP, _seen_globals_count, buf + ls, kh_g, 0, line_pos)
|
||||
else:
|
||||
buf[ls] = ';'
|
||||
buf[eq] = sv_g
|
||||
continue
|
||||
# 类型 %name = type ...(完整定义 flags=1,opaque flags=0)
|
||||
if ll > 0 and buf[ls] == '%':
|
||||
eq: t.CSizeT = ls + 1
|
||||
while eq < ls + ll:
|
||||
if buf[eq] == '=':
|
||||
break
|
||||
eq += 1
|
||||
if eq < ls + ll:
|
||||
sv_t: t.CChar = buf[eq]
|
||||
buf[eq] = '\0'
|
||||
kh_t: t.CUInt64T = _SeenHash(buf + ls)
|
||||
is_full: int = 0
|
||||
if eq + 8 <= ls + ll:
|
||||
if buf[eq + 2] == 't' and buf[eq + 3] == 'y' and buf[eq + 4] == 'p' and buf[eq + 5] == 'e' and buf[eq + 6] == ' ':
|
||||
if buf[eq + 7] == '{' or buf[eq + 7] == '<':
|
||||
is_full = 1
|
||||
prev_t: int = _SeenPresent(_seen_types, _SEEN_TYPE_CAP, buf + ls, kh_t)
|
||||
if prev_t == 0:
|
||||
_seen_types_count = _SeenInsert(_seen_types, _SEEN_TYPE_CAP, _seen_types_count, buf + ls, kh_t, is_full, line_pos)
|
||||
elif is_full == 1 and prev_t == 1:
|
||||
# 先 opaque 后完整定义:注释旧行,表升级指向新完整定义行
|
||||
old_pos: t.CSizeT = _SeenGetPos(_seen_types, _SEEN_TYPE_CAP, buf + ls, kh_t)
|
||||
if old_pos >= base_pos and old_pos < base_pos + buf_len:
|
||||
buf[old_pos - base_pos] = ';'
|
||||
_seen_types_count = _SeenInsert(_seen_types, _SEEN_TYPE_CAP, _seen_types_count, buf + ls, kh_t, 1, line_pos)
|
||||
else:
|
||||
buf[ls] = ';'
|
||||
buf[eq] = sv_t
|
||||
continue
|
||||
|
||||
# ============================================================
|
||||
# StubMergerBuild - StubMerger 拆分(阶段 E):StubMergerBuild
|
||||
#
|
||||
@@ -43,6 +281,7 @@ def _LoadAndAppendStub(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
|
||||
dep_buf: bytes, out_buf: bytes, out_size: t.CSizeT,
|
||||
out_pos: t.CSizeT) -> t.CSizeT:
|
||||
"""加载依赖 stub 并追加(跳过 header,去重)"""
|
||||
global _seen_funcs_count, _seen_globals_count, _seen_types_count
|
||||
if temp_dir is None or dep_sha1 is None or dep_buf is None or out_buf is None:
|
||||
return out_pos
|
||||
|
||||
@@ -91,7 +330,7 @@ def _LoadAndAppendStub(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
|
||||
dep_buf[ls] = ';'
|
||||
cfs_pos = ext_off2 + 30
|
||||
|
||||
# 跳过 header,追加内容(去重 declare/global)
|
||||
# 跳过 header,追加内容(去重 declare/global/type,已见符号表 O(1) 去重)
|
||||
dep_pos: t.CSizeT = 0
|
||||
skipping: int = 1
|
||||
while dep_pos < dep_br_ls:
|
||||
@@ -116,7 +355,12 @@ def _LoadAndAppendStub(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
|
||||
if string.strncmp(dep_buf + line_start, "source_filename", 15) == 0:
|
||||
continue
|
||||
skipping = 0
|
||||
# 去重:declare(用 _IsFuncDeclaredOrDefined 避免误匹配 call 语句)
|
||||
# 注册暂存(append 成功后才登记;reg_key 指向 scratch,insert 当轮完成)
|
||||
reg_tbl: int = 0
|
||||
reg_key: str = None
|
||||
reg_hash: t.CUInt64T = 0
|
||||
reg_flags: int = 0
|
||||
# 去重:declare(用已见函数表,键 @"name"(,避免误匹配 call 语句)
|
||||
if line_len >= 8 and string.strncmp(dep_buf + line_start, "declare ", 8) == 0:
|
||||
at: t.CSizeT = line_start + 8
|
||||
while at < line_start + line_len:
|
||||
@@ -132,24 +376,39 @@ def _LoadAndAppendStub(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
|
||||
if lp < line_start + line_len:
|
||||
saved: t.CChar = dep_buf[lp + 1]
|
||||
dep_buf[lp + 1] = '\0'
|
||||
if StubMergerIR._IsFuncDeclaredOrDefined(out_buf, dep_buf + at) != 0:
|
||||
reg_hash = _SeenHash(dep_buf + at)
|
||||
if _SeenPresent(_seen_funcs, _SEEN_FUNC_CAP, dep_buf + at, reg_hash) != 0:
|
||||
dep_buf[lp + 1] = saved
|
||||
continue
|
||||
string.strcpy(_seen_key_scratch, dep_buf + at)
|
||||
reg_tbl = 1
|
||||
reg_key = _seen_key_scratch
|
||||
reg_flags = 0
|
||||
dep_buf[lp + 1] = saved
|
||||
# 去重:external global
|
||||
# 去重:external global(键 @name,截断于 '=' 前)
|
||||
if line_len > 0 and dep_buf[line_start] == '@':
|
||||
# 字符串常量 @.str.{sha1}.{N}:依赖 stub 的 external 声明是死代码
|
||||
# (定义在模块自身 text.ll,合并 IR 中依赖方无需声明),跳过
|
||||
if line_len >= 5 and dep_buf[line_start + 1] == '.' and dep_buf[line_start + 2] == 's' \
|
||||
and dep_buf[line_start + 3] == 't' and dep_buf[line_start + 4] == 'r':
|
||||
continue
|
||||
eq: t.CSizeT = line_start + 1
|
||||
while eq < line_start + line_len:
|
||||
if dep_buf[eq] == '=':
|
||||
break
|
||||
eq += 1
|
||||
if eq < line_start + line_len:
|
||||
saved: t.CChar = dep_buf[eq + 1]
|
||||
dep_buf[eq + 1] = '\0'
|
||||
if string.strstr(out_buf, dep_buf + line_start) is not None:
|
||||
dep_buf[eq + 1] = saved
|
||||
saved: t.CChar = dep_buf[eq]
|
||||
dep_buf[eq] = '\0'
|
||||
reg_hash = _SeenHash(dep_buf + line_start)
|
||||
if _SeenPresent(_seen_globals, _SEEN_GLOBAL_CAP, dep_buf + line_start, reg_hash) != 0:
|
||||
dep_buf[eq] = saved
|
||||
continue
|
||||
dep_buf[eq + 1] = saved
|
||||
string.strcpy(_seen_key_scratch, dep_buf + line_start)
|
||||
reg_tbl = 2
|
||||
reg_key = _seen_key_scratch
|
||||
reg_flags = 0
|
||||
dep_buf[eq] = saved
|
||||
# 去重:type 定义(如 %"sha1.Point" = type {i32, i32})
|
||||
# 区分完整定义(= type { ... } / = type < ... >)和 opaque 声明(= type opaque)
|
||||
# 当本地 stub 有 opaque 声明而依赖 stub 有完整定义时,注释掉 opaque 行,
|
||||
@@ -169,34 +428,48 @@ def _LoadAndAppendStub(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
|
||||
if dep_buf[eq2 + 2] == 't' and dep_buf[eq2 + 3] == 'y' and dep_buf[eq2 + 4] == 'p' and dep_buf[eq2 + 5] == 'e' and dep_buf[eq2 + 6] == ' ':
|
||||
if dep_buf[eq2 + 7] == '{' or dep_buf[eq2 + 7] == '<':
|
||||
dep_is_full_def = 1
|
||||
saved_eq: t.CChar = dep_buf[eq2]
|
||||
dep_buf[eq2] = '\0'
|
||||
reg_hash = _SeenHash(dep_buf + line_start)
|
||||
if dep_is_full_def == 1:
|
||||
# 依赖行是完整定义
|
||||
# 临时截断到 '=' 之前(不含 '='),辅助函数期望纯类型名前缀
|
||||
saved_eq: t.CChar = dep_buf[eq2]
|
||||
dep_buf[eq2] = '\0'
|
||||
# 1. 注释掉 out_buf 中的 opaque 声明(如果有)
|
||||
commented: int = StubMergerIR._CommentOutOpaqueTypeInBuf(out_buf, dep_buf + line_start)
|
||||
# 2. 检查 out_buf 中是否已有完整定义(避免重复)
|
||||
has_full: int = StubMergerIR._HasFullTypeDefinition(out_buf, dep_buf + line_start)
|
||||
dep_buf[eq2] = saved_eq
|
||||
if has_full == 1:
|
||||
_SeenCommentOut(_seen_types, _SEEN_TYPE_CAP, dep_buf + line_start, reg_hash, out_buf)
|
||||
# 2. 检查是否已有完整定义(避免重复)
|
||||
if _SeenPresent(_seen_types, _SEEN_TYPE_CAP, dep_buf + line_start, reg_hash) == 2:
|
||||
dep_buf[eq2] = saved_eq
|
||||
dep_buf[eq2 + 1] = saved2
|
||||
continue
|
||||
# 3. 追加完整定义
|
||||
string.strcpy(_seen_key_scratch, dep_buf + line_start)
|
||||
reg_tbl = 3
|
||||
reg_key = _seen_key_scratch
|
||||
reg_flags = 1
|
||||
else:
|
||||
# 依赖行是 opaque 声明,用原有子串匹配去重
|
||||
found_opaque: t.CPtr = string.strstr(out_buf, dep_buf + line_start)
|
||||
if found_opaque is not None:
|
||||
# opaque 声明:已存在同名(任意形态)则跳过
|
||||
if _SeenPresent(_seen_types, _SEEN_TYPE_CAP, dep_buf + line_start, reg_hash) != 0:
|
||||
dep_buf[eq2] = saved_eq
|
||||
dep_buf[eq2 + 1] = saved2
|
||||
continue
|
||||
string.strcpy(_seen_key_scratch, dep_buf + line_start)
|
||||
reg_tbl = 3
|
||||
reg_key = _seen_key_scratch
|
||||
reg_flags = 0
|
||||
dep_buf[eq2] = saved_eq
|
||||
dep_buf[eq2 + 1] = saved2
|
||||
# 追加
|
||||
# 追加(append 成功后才登记已见表)
|
||||
if out_pos + line_len + 2 < out_size:
|
||||
reg_pos: t.CSizeT = out_pos
|
||||
string.strncpy(out_buf + out_pos, dep_buf + line_start, line_len)
|
||||
out_pos += line_len
|
||||
out_buf[out_pos] = '\n'
|
||||
out_pos += 1
|
||||
out_buf[out_pos] = '\0'
|
||||
if reg_tbl == 1:
|
||||
_seen_funcs_count = _SeenInsert(_seen_funcs, _SEEN_FUNC_CAP, _seen_funcs_count, reg_key, reg_hash, reg_flags, reg_pos)
|
||||
elif reg_tbl == 2:
|
||||
_seen_globals_count = _SeenInsert(_seen_globals, _SEEN_GLOBAL_CAP, _seen_globals_count, reg_key, reg_hash, reg_flags, reg_pos)
|
||||
elif reg_tbl == 3:
|
||||
_seen_types_count = _SeenInsert(_seen_types, _SEEN_TYPE_CAP, _seen_types_count, reg_key, reg_hash, reg_flags, reg_pos)
|
||||
return out_pos
|
||||
# ============================================================
|
||||
# _LoadAndAppendTextDeclares - 从依赖 text.ll 提取 declare 追加到 out_buf
|
||||
@@ -208,6 +481,7 @@ def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
|
||||
dep_buf: bytes, out_buf: bytes, out_size: t.CSizeT,
|
||||
out_pos: t.CSizeT) -> t.CSizeT:
|
||||
"""从依赖 text.ll 提取 declare(define 转 declare),追加到 out_buf"""
|
||||
global _seen_funcs_count, _seen_globals_count, _seen_types_count
|
||||
if temp_dir is None or dep_sha1 is None or dep_buf is None or out_buf is None:
|
||||
return out_pos
|
||||
|
||||
@@ -285,13 +559,15 @@ def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
|
||||
if lp_lt >= ls + ll:
|
||||
in_body = 1
|
||||
continue
|
||||
# 去重检查:用 _IsFuncDeclaredOrDefined 避免误匹配 call 语句
|
||||
# 去重检查:用已见函数表(键 @"name"(,避免误匹配 call 语句)
|
||||
saved_lt: t.CChar = dep_buf[lp_lt + 1]
|
||||
dep_buf[lp_lt + 1] = '\0'
|
||||
if StubMergerIR._IsFuncDeclaredOrDefined(out_buf, dep_buf + at_lt) != 0:
|
||||
fh_lt: t.CUInt64T = _SeenHash(dep_buf + at_lt)
|
||||
if _SeenPresent(_seen_funcs, _SEEN_FUNC_CAP, dep_buf + at_lt, fh_lt) != 0:
|
||||
dep_buf[lp_lt + 1] = saved_lt
|
||||
in_body = 1
|
||||
continue
|
||||
string.strcpy(_seen_key_scratch, dep_buf + at_lt)
|
||||
dep_buf[lp_lt + 1] = saved_lt
|
||||
|
||||
# 找行尾的 ' {' 并截断
|
||||
@@ -337,6 +613,7 @@ def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
|
||||
skipped_lt = 1
|
||||
copy_len_lt: t.CSizeT = decl_end - c_start_lt
|
||||
if out_pos + 8 + copy_len_lt + 2 < out_size:
|
||||
decl_pos_lt: t.CSizeT = out_pos
|
||||
string.strncpy(out_buf + out_pos, "declare ", 8)
|
||||
out_pos += 8
|
||||
string.strncpy(out_buf + out_pos, dep_buf + c_start_lt, copy_len_lt)
|
||||
@@ -344,6 +621,7 @@ def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
|
||||
out_buf[out_pos] = '\n'
|
||||
out_pos += 1
|
||||
out_buf[out_pos] = '\0'
|
||||
_seen_funcs_count = _SeenInsert(_seen_funcs, _SEEN_FUNC_CAP, _seen_funcs_count, _seen_key_scratch, fh_lt, 0, decl_pos_lt)
|
||||
in_body = 1
|
||||
continue
|
||||
|
||||
@@ -366,22 +644,27 @@ def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
|
||||
if dep_buf[eq_td + 7] == '{' or dep_buf[eq_td + 7] == '<':
|
||||
dep_is_full_td = 1
|
||||
if dep_is_full_td == 1:
|
||||
# 临时截断到 '=' 之前(不含 '='),辅助函数期望纯类型名前缀
|
||||
# 临时截断到 '=' 之前(不含 '='),键统一为 %name
|
||||
saved_eq_td: t.CChar = dep_buf[eq_td]
|
||||
dep_buf[eq_td] = '\0'
|
||||
th_td: t.CUInt64T = _SeenHash(dep_buf + ls)
|
||||
# 1. 注释掉 out_buf 中的 opaque 声明(如果有)
|
||||
StubMergerIR._CommentOutOpaqueTypeInBuf(out_buf, dep_buf + ls)
|
||||
# 2. 检查 out_buf 中是否已有完整定义(避免重复)
|
||||
has_full_td: int = StubMergerIR._HasFullTypeDefinition(out_buf, dep_buf + ls)
|
||||
_SeenCommentOut(_seen_types, _SEEN_TYPE_CAP, dep_buf + ls, th_td, out_buf)
|
||||
# 2. 检查是否已有完整定义(避免重复)
|
||||
if _SeenPresent(_seen_types, _SEEN_TYPE_CAP, dep_buf + ls, th_td) == 2:
|
||||
dep_buf[eq_td] = saved_eq_td
|
||||
continue
|
||||
string.strcpy(_seen_key_scratch, dep_buf + ls)
|
||||
dep_buf[eq_td] = saved_eq_td
|
||||
if has_full_td == 0:
|
||||
# 追加完整类型定义
|
||||
if out_pos + ll + 2 < out_size:
|
||||
string.strncpy(out_buf + out_pos, dep_buf + ls, ll)
|
||||
out_pos += ll
|
||||
out_buf[out_pos] = '\n'
|
||||
out_pos += 1
|
||||
out_buf[out_pos] = '\0'
|
||||
# 追加完整类型定义
|
||||
if out_pos + ll + 2 < out_size:
|
||||
td_pos: t.CSizeT = out_pos
|
||||
string.strncpy(out_buf + out_pos, dep_buf + ls, ll)
|
||||
out_pos += ll
|
||||
out_buf[out_pos] = '\n'
|
||||
out_pos += 1
|
||||
out_buf[out_pos] = '\0'
|
||||
_seen_types_count = _SeenInsert(_seen_types, _SEEN_TYPE_CAP, _seen_types_count, _seen_key_scratch, th_td, 1, td_pos)
|
||||
continue
|
||||
|
||||
# 提取全局变量定义(@... = ...)
|
||||
@@ -389,31 +672,38 @@ def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
|
||||
# stub.ll 中只有 external 声明,需要从 text.ll 提取完整定义
|
||||
# 注释掉 out_buf 中的同名行(external 声明或旧定义),追加 text.ll 中的完整定义
|
||||
if ll > 0 and dep_buf[ls] == '@':
|
||||
# 字符串常量 @.str.{sha1}.{N}:依赖 text.ll 中的 internal 定义是死代码
|
||||
# (定义模块自身 .obj 已有,合并 IR 中依赖方无需重复),跳过
|
||||
if ll >= 5 and dep_buf[ls + 1] == '.' and dep_buf[ls + 2] == 's' and dep_buf[ls + 3] == 't' \
|
||||
and dep_buf[ls + 4] == 'r':
|
||||
continue
|
||||
eq_gv: t.CSizeT = ls + 1
|
||||
while eq_gv < ls + ll:
|
||||
if dep_buf[eq_gv] == '=':
|
||||
break
|
||||
eq_gv += 1
|
||||
if eq_gv < ls + ll:
|
||||
# 截断到 '=' 之前(不含 '='),得到全局变量名 @name
|
||||
# 截断到 '=' 之前(不含 '='),键统一为 @name
|
||||
saved_gv: t.CChar = dep_buf[eq_gv]
|
||||
dep_buf[eq_gv] = '\0'
|
||||
gh_gv: t.CUInt64T = _SeenHash(dep_buf + ls)
|
||||
# 依赖方已有同名全局(stub 注入的 external 声明或先前依赖的定义)
|
||||
# 时跳过:跨模块全局(如 _op_head、MemBuddy.vtable)只需一份
|
||||
# 强定义(在定义模块的 text.ll 中),复制进每个依赖方会导致
|
||||
# ld.lld duplicate symbol(NewAstTest _op_head/MemBuddy.vtable 根因)。
|
||||
# 仅当依赖方完全没有该全局(既无 external 也无定义)时才需要补充。
|
||||
if StubMergerIR._HasGlobalInBuf(out_buf, dep_buf + ls) == 0:
|
||||
# 注释掉 out_buf 中的同名行(external 声明或旧定义)
|
||||
StubMergerIR._CommentOutGlobalInBuf(out_buf, dep_buf + ls)
|
||||
if _SeenPresent(_seen_globals, _SEEN_GLOBAL_CAP, dep_buf + ls, gh_gv) == 0:
|
||||
# 追加完整定义(无同名行时注释旧行是 no-op)
|
||||
string.strcpy(_seen_key_scratch, dep_buf + ls)
|
||||
dep_buf[eq_gv] = saved_gv
|
||||
# 追加完整定义
|
||||
if out_pos + ll + 2 < out_size:
|
||||
gv_pos: t.CSizeT = out_pos
|
||||
string.strncpy(out_buf + out_pos, dep_buf + ls, ll)
|
||||
out_pos += ll
|
||||
out_buf[out_pos] = '\n'
|
||||
out_pos += 1
|
||||
out_buf[out_pos] = '\0'
|
||||
_seen_globals_count = _SeenInsert(_seen_globals, _SEEN_GLOBAL_CAP, _seen_globals_count, _seen_key_scratch, gh_gv, 0, gv_pos)
|
||||
else:
|
||||
dep_buf[eq_gv] = saved_gv
|
||||
continue
|
||||
@@ -731,19 +1021,12 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
app_mod_path: bytes = stdlib.malloc(sd_len_ff + mb_len_ff + 6)
|
||||
is_app_src: int = 0
|
||||
if app_mod_path is not None:
|
||||
# 优先尝试 .vp,向后兼容 .py
|
||||
# 仅识别 .vp 源文件(不再做 vp -> py 后缀识别回退)
|
||||
viperlib.snprintf(app_mod_path, sd_len_ff + mb_len_ff + 6, "%s/%s.vp", source_dir, mod_buf)
|
||||
af: fileio.File | t.CPtr = fileio.File(app_mod_path, fileio.MODE.R)
|
||||
if not af.closed:
|
||||
is_app_src = 1
|
||||
af.close()
|
||||
else:
|
||||
# .vp 不存在,回退 .py
|
||||
viperlib.snprintf(app_mod_path, sd_len_ff + mb_len_ff + 6, "%s/%s.py", source_dir, mod_buf)
|
||||
af = fileio.File(app_mod_path, fileio.MODE.R)
|
||||
if not af.closed:
|
||||
is_app_src = 1
|
||||
af.close()
|
||||
stdlib.free(app_mod_path)
|
||||
if is_app_src == 0:
|
||||
# fast-fail: includes 文件依赖未在内存中找到,Phase 1a-pre 未正确填充
|
||||
@@ -778,6 +1061,8 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
||||
out_buf: bytes, out_size: t.CSizeT) -> t.CSizeT:
|
||||
"""组合本地 stub + 依赖 stubs + 本地 text → out_buf(按需加载)"""
|
||||
global _seen_funcs, _seen_funcs_count, _seen_globals, _seen_globals_count
|
||||
global _seen_types, _seen_types_count, _seen_key_scratch
|
||||
if temp_dir is None or local_sha1 is None or out_buf is None or out_size == 0:
|
||||
return 0
|
||||
|
||||
@@ -785,6 +1070,34 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
||||
out_buf[0] = '\0'
|
||||
out_pos: t.CSizeT = 0
|
||||
|
||||
# 已见符号表重置(跨构建复用缓冲,仅清零计数 + 全槽位清零)
|
||||
if _seen_funcs is None:
|
||||
_seen_funcs = stdlib.malloc(_SEEN_FUNC_CAP * _SEEN_SLOT)
|
||||
if _seen_funcs is None:
|
||||
VLogger.error("已见函数表分配失败", "StubMerger")
|
||||
return 0
|
||||
if _seen_globals is None:
|
||||
_seen_globals = stdlib.malloc(_SEEN_GLOBAL_CAP * _SEEN_SLOT)
|
||||
if _seen_globals is None:
|
||||
VLogger.error("已见全局表分配失败", "StubMerger")
|
||||
return 0
|
||||
if _seen_types is None:
|
||||
_seen_types = stdlib.malloc(_SEEN_TYPE_CAP * _SEEN_SLOT)
|
||||
if _seen_types is None:
|
||||
VLogger.error("已见类型表分配失败", "StubMerger")
|
||||
return 0
|
||||
if _seen_key_scratch is None:
|
||||
_seen_key_scratch = stdlib.malloc(_SEEN_NAME_MAX + 1)
|
||||
if _seen_key_scratch is None:
|
||||
VLogger.error("已见表键暂存分配失败", "StubMerger")
|
||||
return 0
|
||||
string.memset(_seen_funcs, 0, _SEEN_FUNC_CAP * _SEEN_SLOT)
|
||||
string.memset(_seen_globals, 0, _SEEN_GLOBAL_CAP * _SEEN_SLOT)
|
||||
string.memset(_seen_types, 0, _SEEN_TYPE_CAP * _SEEN_SLOT)
|
||||
_seen_funcs_count = 0
|
||||
_seen_globals_count = 0
|
||||
_seen_types_count = 0
|
||||
|
||||
# 1. 读取并追加本地 stub.ll(含 header)
|
||||
stub_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, local_sha1, "stub.ll")
|
||||
if stub_path is None:
|
||||
@@ -830,8 +1143,10 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
||||
stub_content[ext_off + 6] = ' '
|
||||
stub_content[ext_off + 7] = ' '
|
||||
fix_pos = ext_off + 8
|
||||
# 直接复制修复后的 stub 内容
|
||||
# 直接复制修复后的 stub 内容(复制前先登记其 declare/global/type,
|
||||
# 保持已见表与 out_buf 一致,避免后续依赖重复追加 redefinition)
|
||||
if out_pos + slen + 2 < out_size:
|
||||
_RegisterStubLines(stub_content, slen, out_pos)
|
||||
string.strcpy(out_buf + out_pos, stub_content)
|
||||
out_pos += slen
|
||||
if out_buf[out_pos - 1] != '\n':
|
||||
@@ -944,6 +1259,19 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
||||
# 检查 dep_mod_name 是否是已导入包的子模块
|
||||
# (如 ast.lexer 是 ast 的子模块)
|
||||
should_load = 1
|
||||
else:
|
||||
# 基名匹配:store 键是全路径模块名
|
||||
# (Kernel.drivers.fs.fat32.fat32_types),而 deps.txt
|
||||
# 记录 import 短名(fat32_types)→ 精确/子模块均不命中
|
||||
# → 依赖 stub/text 不加载 → 跨模块类完整定义缺失
|
||||
# (vpi 注入失败的 fat32_types.dirobj 只有 opaque)→
|
||||
# 值类型 alloca 报 llc "Cannot allocate unsized type"
|
||||
# (VKernel example_fs L500 根因)。取最后一个 '.' 之后
|
||||
# 的基名与 deps 词边界匹配(多加载无害,去重表兜底)。
|
||||
last_dot_bm: str = string.strrchr(dep_mod_name, '.')
|
||||
if last_dot_bm is not None and last_dot_bm[1] != '\0':
|
||||
if GenApi.is_module_imported(deps_buf, last_dot_bm + 1) != 0:
|
||||
should_load = 1
|
||||
break
|
||||
if is_include == 0:
|
||||
# 非 includes stub(用户文件),总是加载
|
||||
@@ -1057,7 +1385,12 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
||||
if string.strncmp(text_content + tx_ls, "source_filename", 15) == 0:
|
||||
continue
|
||||
tx_skip = 0
|
||||
# 去重:declare(用 _IsFuncDeclaredOrDefined 避免误匹配 call 语句)
|
||||
# 注册暂存(append 成功后才登记;tx_key 指向 scratch,insert 当轮完成)
|
||||
tx_reg: int = 0
|
||||
tx_key: str = None
|
||||
tx_hash: t.CUInt64T = 0
|
||||
tx_flags: int = 0
|
||||
# 去重:declare(用已见函数表,键 @"name"(,避免误匹配 call 语句)
|
||||
if tx_ll >= 8 and string.strncmp(text_content + tx_ls, "declare ", 8) == 0:
|
||||
tx_at: t.CSizeT = tx_ls + 8
|
||||
while tx_at < tx_ls + tx_ll:
|
||||
@@ -1073,11 +1406,16 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
||||
if tx_lp < tx_ls + tx_ll:
|
||||
tx_sv: t.CChar = text_content[tx_lp + 1]
|
||||
text_content[tx_lp + 1] = '\0'
|
||||
if StubMergerIR._IsFuncDeclaredOrDefined(out_buf, text_content + tx_at) != 0:
|
||||
tx_hash = _SeenHash(text_content + tx_at)
|
||||
if _SeenPresent(_seen_funcs, _SEEN_FUNC_CAP, text_content + tx_at, tx_hash) != 0:
|
||||
text_content[tx_lp + 1] = tx_sv
|
||||
continue
|
||||
string.strcpy(_seen_key_scratch, text_content + tx_at)
|
||||
tx_reg = 1
|
||||
tx_key = _seen_key_scratch
|
||||
tx_flags = 0
|
||||
text_content[tx_lp + 1] = tx_sv
|
||||
# 去重:define(注释掉 out_buf 中已有的 declare,避免 declare/define 冲突)
|
||||
# 去重:define(注释 out_buf 中已有 declare,避免 declare/define 冲突)
|
||||
if tx_ll >= 7 and string.strncmp(text_content + tx_ls, "define ", 7) == 0:
|
||||
tx_at_d: t.CSizeT = tx_ls + 7
|
||||
while tx_at_d < tx_ls + tx_ll:
|
||||
@@ -1093,11 +1431,16 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
||||
if tx_lp_d < tx_ls + tx_ll:
|
||||
tx_sv_d: t.CChar = text_content[tx_lp_d + 1]
|
||||
text_content[tx_lp_d + 1] = '\0'
|
||||
StubMergerIR._CommentOutDeclareInBuf(out_buf, text_content + tx_at_d)
|
||||
tx_hash = _SeenHash(text_content + tx_at_d)
|
||||
_SeenCommentOut(_seen_funcs, _SEEN_FUNC_CAP, text_content + tx_at_d, tx_hash, out_buf)
|
||||
string.strcpy(_seen_key_scratch, text_content + tx_at_d)
|
||||
tx_reg = 1
|
||||
tx_key = _seen_key_scratch
|
||||
tx_flags = 0
|
||||
text_content[tx_lp_d + 1] = tx_sv_d
|
||||
# 处理:@global = ...
|
||||
# stub 中可能是 external 声明或完整定义,以 text 中的定义为准
|
||||
# 找到 stub 中同名全局变量行并注释掉,然后追加 text 中的
|
||||
# 注释 out_buf 中同名全局行,然后追加 text 中的定义(键 @name,截断于 '=' 前)
|
||||
if tx_ll > 0 and text_content[tx_ls] == '@':
|
||||
tx_eq: t.CSizeT = tx_ls + 1
|
||||
while tx_eq < tx_ls + tx_ll:
|
||||
@@ -1105,11 +1448,16 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
||||
break
|
||||
tx_eq += 1
|
||||
if tx_eq < tx_ls + tx_ll:
|
||||
tx_sv2: t.CChar = text_content[tx_eq + 1]
|
||||
text_content[tx_eq + 1] = '\0'
|
||||
StubMergerIR._CommentOutGlobalInBuf(out_buf, text_content + tx_ls)
|
||||
text_content[tx_eq + 1] = tx_sv2
|
||||
# 去重:%type = ...
|
||||
tx_sv2: t.CChar = text_content[tx_eq]
|
||||
text_content[tx_eq] = '\0'
|
||||
tx_hash = _SeenHash(text_content + tx_ls)
|
||||
_SeenCommentOut(_seen_globals, _SEEN_GLOBAL_CAP, text_content + tx_ls, tx_hash, out_buf)
|
||||
string.strcpy(_seen_key_scratch, text_content + tx_ls)
|
||||
tx_reg = 2
|
||||
tx_key = _seen_key_scratch
|
||||
tx_flags = 0
|
||||
text_content[tx_eq] = tx_sv2
|
||||
# 去重:%type = ...(键 %name,截断于 '=' 前)
|
||||
if tx_ll > 0 and text_content[tx_ls] == '%':
|
||||
tx_eq2: t.CSizeT = tx_ls + 1
|
||||
while tx_eq2 < tx_ls + tx_ll:
|
||||
@@ -1117,19 +1465,38 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
||||
break
|
||||
tx_eq2 += 1
|
||||
if tx_eq2 < tx_ls + tx_ll:
|
||||
tx_sv3: t.CChar = text_content[tx_eq2 + 1]
|
||||
text_content[tx_eq2 + 1] = '\0'
|
||||
if string.strstr(out_buf, text_content + tx_ls) is not None:
|
||||
text_content[tx_eq2 + 1] = tx_sv3
|
||||
tx_sv3: t.CChar = text_content[tx_eq2]
|
||||
text_content[tx_eq2] = '\0'
|
||||
tx_is_full: int = 0
|
||||
if tx_eq2 + 8 <= tx_ls + tx_ll:
|
||||
if text_content[tx_eq2 + 2] == 't' and text_content[tx_eq2 + 3] == 'y' \
|
||||
and text_content[tx_eq2 + 4] == 'p' and text_content[tx_eq2 + 5] == 'e' \
|
||||
and text_content[tx_eq2 + 6] == ' ':
|
||||
if text_content[tx_eq2 + 7] == '{' or text_content[tx_eq2 + 7] == '<':
|
||||
tx_is_full = 1
|
||||
tx_hash = _SeenHash(text_content + tx_ls)
|
||||
if _SeenPresent(_seen_types, _SEEN_TYPE_CAP, text_content + tx_ls, tx_hash) != 0:
|
||||
text_content[tx_eq2] = tx_sv3
|
||||
continue
|
||||
text_content[tx_eq2 + 1] = tx_sv3
|
||||
# 追加
|
||||
string.strcpy(_seen_key_scratch, text_content + tx_ls)
|
||||
tx_reg = 3
|
||||
tx_key = _seen_key_scratch
|
||||
tx_flags = tx_is_full
|
||||
text_content[tx_eq2] = tx_sv3
|
||||
# 追加(append 成功后才登记已见表)
|
||||
if out_pos + tx_ll + 2 < out_size:
|
||||
tx_reg_pos: t.CSizeT = out_pos
|
||||
string.strncpy(out_buf + out_pos, text_content + tx_ls, tx_ll)
|
||||
out_pos += tx_ll
|
||||
out_buf[out_pos] = '\n'
|
||||
out_pos += 1
|
||||
out_buf[out_pos] = '\0'
|
||||
if tx_reg == 1:
|
||||
_seen_funcs_count = _SeenInsert(_seen_funcs, _SEEN_FUNC_CAP, _seen_funcs_count, tx_key, tx_hash, tx_flags, tx_reg_pos)
|
||||
elif tx_reg == 2:
|
||||
_seen_globals_count = _SeenInsert(_seen_globals, _SEEN_GLOBAL_CAP, _seen_globals_count, tx_key, tx_hash, tx_flags, tx_reg_pos)
|
||||
elif tx_reg == 3:
|
||||
_seen_types_count = _SeenInsert(_seen_types, _SEEN_TYPE_CAP, _seen_types_count, tx_key, tx_hash, tx_flags, tx_reg_pos)
|
||||
stdlib.free(text_content)
|
||||
|
||||
if deps_buf is not None:
|
||||
|
||||
@@ -19,19 +19,15 @@ import lib.Stub.StubGen.VpiReader as VpiReader
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import lib.Projectrans.Config as Config
|
||||
|
||||
|
||||
import lib.Stub.StubMerger.StubMergerCollect as StubMergerCollect
|
||||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||||
import lib.Stub.StubMerger.StubMergerTopo as StubMergerTopo
|
||||
import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
|
||||
|
||||
# ============================================================
|
||||
# StubMergerIR - StubMerger 拆分(阶段 E):StubMergerIR
|
||||
#
|
||||
# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留
|
||||
# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经
|
||||
# StubMerger._xxx 访问(main.vp 先例)。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
@@ -52,7 +48,7 @@ def IsDeclOnlyModule(temp_dir: str, td_len: t.CSizeT, sha1: str) -> int:
|
||||
tpath: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "text.ll")
|
||||
if tpath is None:
|
||||
return -1
|
||||
tf_d: fileio.File | t.CPtr = fileio.File(tpath, fileio.MODE.R)
|
||||
tf_d: fileio.File = fileio.File(tpath, fileio.MODE.R)
|
||||
stdlib.free(tpath)
|
||||
if tf_d.closed:
|
||||
return -1
|
||||
@@ -110,7 +106,7 @@ def _IsFuncDeclaredOrDefined(out_buf: bytes, func_sig: str) -> int:
|
||||
if sig_len == 0 or out_len == 0 or sig_len > out_len:
|
||||
return 0
|
||||
pos: t.CSizeT = 0
|
||||
while pos + sig_len <= out_len:
|
||||
for pos in range(0, out_len - sig_len + 1):
|
||||
if string.strncmp(out_buf + pos, func_sig, sig_len) == 0:
|
||||
ls: t.CSizeT = pos
|
||||
while ls > 0 and out_buf[ls - 1] != '\n':
|
||||
@@ -119,7 +115,6 @@ def _IsFuncDeclaredOrDefined(out_buf: bytes, func_sig: str) -> int:
|
||||
return 1
|
||||
if string.strncmp(out_buf + ls, "define ", 7) == 0:
|
||||
return 1
|
||||
pos += 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# _CommentOutDeclareInBuf - 将 out_buf 中匹配 func_sig 的 declare 行注释掉
|
||||
|
||||
@@ -72,6 +72,12 @@ def BuildTopoSortedIndices(store_count: int, store_sha1_arr: bytes,
|
||||
if rel_idx is not None:
|
||||
stdlib.free(rel_idx)
|
||||
return 0
|
||||
# 清零 indegree/queue/rel_idx(malloc 返回未初始化内存,Kahn 依赖入度初值 0)
|
||||
zi: int = 0
|
||||
for zi in range(store_count + 1):
|
||||
indegree[zi] = 0
|
||||
queue[zi] = 0
|
||||
rel_idx[zi] = 0
|
||||
# 收集可达 store 索引(reachable_count<=0 时全量,对齐既有全量编译行为)
|
||||
rel_count: int = 0
|
||||
i_t: int
|
||||
@@ -84,6 +90,11 @@ def BuildTopoSortedIndices(store_count: int, store_sha1_arr: bytes,
|
||||
if StubMergerCollect._is_in_sha1_set(store_sha1_arr + t.CSizeT(i_t) * 17, reachable_set, reachable_count) != 0:
|
||||
rel_idx[rel_count] = i_t
|
||||
rel_count += 1
|
||||
# 诊断:可达 store 索引数(rel_count=0 → topo_count=0 → PhaseB+ 循环不执行)
|
||||
fb_rel: str = VLogger.fmt_buf()
|
||||
if fb_rel is not None:
|
||||
viperlib.snprintf(fb_rel, 1024, "诊断 topo rel_count=%d", rel_count)
|
||||
VLogger.debug(fb_rel, "StubMergerTopo")
|
||||
# 计算入度:m 在可达集合内的直接依赖数
|
||||
i_r: int
|
||||
for i_r in range(rel_count):
|
||||
@@ -110,7 +121,10 @@ def BuildTopoSortedIndices(store_count: int, store_sha1_arr: bytes,
|
||||
dsha1: str = StubMergerIR._FindSha1ByModName(store_sha1_arr, store_mod_arr, store_count, dname_buf)
|
||||
stdlib.free(dname_buf)
|
||||
if dsha1 is not None and StubMergerCollect._is_in_sha1_set(dsha1, reachable_set, reachable_count) != 0:
|
||||
indegree[si] = indegree[si] + 1
|
||||
# 中间 int 变量累加:绕过联合类型(CSizeT|CPtr)+ 整数的指针算术编译 bug
|
||||
indg: int = indegree[si]
|
||||
indg = indg + 1
|
||||
indegree[si] = indg
|
||||
# Kahn:入度为 0(不依赖任何可达模块)者先出 → 最先编译
|
||||
q_tail: int = 0
|
||||
for i_r in range(rel_count):
|
||||
@@ -119,7 +133,11 @@ def BuildTopoSortedIndices(store_count: int, store_sha1_arr: bytes,
|
||||
queue[q_tail] = si2
|
||||
q_tail += 1
|
||||
out_count: int = 0
|
||||
for q_head in range(q_tail):
|
||||
# Kahn 主循环必须用 while(不能用 for range):循环体内会动态入队
|
||||
# (queue[q_tail]=si3; q_tail+=1),for range 上界只求值一次,
|
||||
# 动态入队的模块永远不会被处理且兜底(indegree>0)也捞不回 → 拓扑漏项
|
||||
q_head: int = 0
|
||||
while q_head < q_tail:
|
||||
m: int = queue[q_head]
|
||||
sorted_idx[out_count] = m
|
||||
out_count += 1
|
||||
@@ -148,10 +166,14 @@ def BuildTopoSortedIndices(store_count: int, store_sha1_arr: bytes,
|
||||
if dlen3 == mod_m_len and string.strncmp(deps_si3 + dstart3, mod_m, mod_m_len) == 0:
|
||||
found_dep = 1
|
||||
if found_dep == 1:
|
||||
indegree[si3] = indegree[si3] - 1
|
||||
# 中间 int 变量递减:绕过联合类型指针算术编译 bug
|
||||
indg3: int = indegree[si3]
|
||||
indg3 = indg3 - 1
|
||||
indegree[si3] = indg3
|
||||
if indegree[si3] == 0:
|
||||
queue[q_tail] = si3
|
||||
q_tail += 1
|
||||
q_head += 1
|
||||
# 有环时剩余条目按 store 顺序补齐(避免漏编译)
|
||||
for i_r in range(rel_count):
|
||||
si4: int = rel_idx[i_r]
|
||||
|
||||
@@ -203,7 +203,7 @@ class AssignGenMixin:
|
||||
cl_cd: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val_node)
|
||||
if cl_cd is not None and cl_cd.args is not None:
|
||||
cl_args_cd: list[ast.AST | t.CPtr] | t.CPtr = cl_cd.args
|
||||
if cl_args_cd.__len__() > 0:
|
||||
if len(cl_args_cd) > 0:
|
||||
first_arg_cd: ast.AST | t.CPtr = cl_args_cd.get(0)
|
||||
if first_arg_cd is not None and first_arg_cd.kind() == ast.ASTKind.Constant:
|
||||
val_node = first_arg_cd
|
||||
@@ -946,8 +946,7 @@ class AssignGenMixin:
|
||||
|
||||
支持两种书写形式:
|
||||
1. 模块限定 t.CArray[...](Attribute value)
|
||||
2. 裸名 CArray[...](from t import * 后使用,如 Termination4K3 core.vp
|
||||
的 `__python_suffix__: CArray[str] = ["py", ...]`)
|
||||
2. 裸名 CArray[...](from t import * 后使用) # 存疑
|
||||
"""
|
||||
if annot is None or annot.kind() != ast.ASTKind.Subscript:
|
||||
return 0
|
||||
@@ -1076,7 +1075,7 @@ class AssignGenMixin:
|
||||
annot: ast.AST | t.CPtr = aa.annotation
|
||||
if annot is not None:
|
||||
resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, annot, trans._imported_modules, trans._from_imports, trans)
|
||||
pool, annot, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
if resolved is None:
|
||||
# 尝试特化泛型类注解(如 list[str])
|
||||
# resolve_annotation_type 返回 None 可能是因为泛型类未特化
|
||||
@@ -1094,7 +1093,7 @@ class AssignGenMixin:
|
||||
trans, sub_nm.id, type_args_ps)
|
||||
if spec_name_ps is not None:
|
||||
resolved = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, annot, trans._imported_modules, trans._from_imports, trans)
|
||||
pool, annot, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
if resolved is not None:
|
||||
var_ty = resolved
|
||||
# 单参 t.CArray[elem_ty] + 列表字面量 → 静态数组(与 Handle 推断一致)。
|
||||
@@ -1189,7 +1188,7 @@ class AssignGenMixin:
|
||||
annot: ast.AST | t.CPtr = aa.annotation
|
||||
if annot is not None:
|
||||
resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, annot, trans._imported_modules, trans._from_imports, trans)
|
||||
pool, annot, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
if resolved is not None:
|
||||
var_ty = resolved
|
||||
else:
|
||||
@@ -1207,7 +1206,7 @@ class AssignGenMixin:
|
||||
|
||||
# t.Callable 函数指针:注册返回类型签名(供函数指针间接调用精确返回类型)
|
||||
callable_ret: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenErr.try_extract_callable_ret(
|
||||
pool, annot, trans._imported_modules, trans._from_imports, trans)
|
||||
pool, annot, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
if callable_ret is not None:
|
||||
self.Gen.CallGenLeafKit.register_func_ptr_sig(nm.id, callable_ret)
|
||||
|
||||
|
||||
@@ -330,17 +330,41 @@ class CallGenBase:
|
||||
|
||||
|
||||
def is_cexport_func(self, sha1: str, func_name: str) -> int:
|
||||
"""检查 (sha1, func_name) 是否是 CExport 函数(统一读 Gen.CallGenBase 真源)"""
|
||||
"""检查 (sha1, func_name) 是否是 CExport 函数(统一读 Gen.CallGenBase 真源)
|
||||
|
||||
注册表未命中时回退查 vpi 返回注解:跨模块编译存在时序差(如 apic.vp
|
||||
先于 mm.vp 翻译时 mm 的 CExport 尚未 register_cexport_func → mm.malloc
|
||||
误用 @1fdad1c76fb116bc.malloc 而非裸名 @malloc → ld.lld undefined
|
||||
symbol: 1fdad1c76fb116bc.malloc)。
|
||||
"""
|
||||
if self.Gen is None or sha1 is None or func_name is None:
|
||||
return 0
|
||||
if self.Gen.CallGenBase.CexportSha1Arr is None:
|
||||
if self.Gen.CallGenBase.CexportSha1Arr is not None:
|
||||
for i in range(self.Gen.CallGenBase.CexportCount):
|
||||
idx: t.CSizeT = t.CSizeT(i) * 17
|
||||
if string.strcmp(self.Gen.CallGenBase.CexportSha1Arr + idx, sha1) == 0:
|
||||
idx2: t.CSizeT = t.CSizeT(i) * 64
|
||||
if string.strcmp(self.Gen.CallGenBase.CexportFuncArr + idx2, func_name) == 0:
|
||||
return 1
|
||||
return self._is_cexport_func_from_vpi(sha1, func_name)
|
||||
|
||||
|
||||
def _is_cexport_func_from_vpi(self, sha1: str, func_name: str) -> int:
|
||||
"""vpi 返回注解含 t.CExport → 定义端用裸名(跨模块调用无 sha1 头)
|
||||
|
||||
对齐 _is_state_func_from_vpi(State 标记)的 vpi 按需解析路径。
|
||||
"""
|
||||
if sha1 is None or func_name is None:
|
||||
return 0
|
||||
for i in range(self.Gen.CallGenBase.CexportCount):
|
||||
idx: t.CSizeT = t.CSizeT(i) * 17
|
||||
if string.strcmp(self.Gen.CallGenBase.CexportSha1Arr + idx, sha1) == 0:
|
||||
idx2: t.CSizeT = t.CSizeT(i) * 64
|
||||
if string.strcmp(self.Gen.CallGenBase.CexportFuncArr + idx2, func_name) == 0:
|
||||
return 1
|
||||
if self.Gen is None or self.Gen.CallGenBase.TempDir is None \
|
||||
or self.Gen.CallGenBase.TempDirLen <= 0:
|
||||
return 0
|
||||
VpiReader._ensure_vpi_ret_annot_loaded(sha1, self.Gen.CallGenBase.TempDir)
|
||||
cexp_annot: str = VpiReader._lookup_vpi_ret_annot(sha1, None, func_name)
|
||||
if cexp_annot is None:
|
||||
return 0
|
||||
if string.strstr(cexp_annot, "CExport") is not None:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
and trans is not None and trans.CurAssignAnnot is not None:
|
||||
dref_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
trans.Pool, trans.CurAssignAnnot,
|
||||
trans._imported_modules, trans._from_imports, trans)
|
||||
trans._imported_modules, trans._from_imports, trans, 0)
|
||||
if dref_ty is not None:
|
||||
dref_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(dref_ty)
|
||||
dref_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(dref_ty)
|
||||
@@ -161,12 +161,21 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
cl: ast.Call | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""c.DerefAs(ptr, val) → store val to ptr(bitcast 后 store)"""
|
||||
"""c.DerefAs(ptr, val) → store val to ptr(bitcast 后 store)
|
||||
单参形式 c.DerefAs(ptr) → 读取 ptr 指向的值(等价 c.Deref(ptr))。
|
||||
"""
|
||||
if cl is None:
|
||||
return None
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||||
if cargs is None or len(cargs) < 2:
|
||||
if cargs is None or len(cargs) < 1:
|
||||
return None
|
||||
# 单参形式:deref 读(paging.vp save_pt_range L263
|
||||
# saved = c.DerefAs(save_count)、restore_pt_range L277-278
|
||||
# c.DerefAs(entry_ptr) 根因——此前 len<2 直接 return None →
|
||||
# 跌落跨模块函数调用生成 call @DerefAs → ld.lld undefined symbol:
|
||||
# DerefAs。复用 translate_c_deref 的类型推断读取逻辑。
|
||||
if len(cargs) < 2:
|
||||
return self.translate_c_deref(pool, builder, mod, cl, trans)
|
||||
|
||||
ptr_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, cargs.get(0), None, 0, trans)
|
||||
@@ -344,7 +353,69 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
pass
|
||||
case _:
|
||||
pass
|
||||
# nonlocal 变量:提升函数内从 env 读对象指针(load_nonlocal_var),
|
||||
# 不能 lookup_var 跨函数命中父函数 alloca(SSA 编号错乱崩溃)。
|
||||
# 与普通局部 c.Addr(obj) 返回对象指针(load 一次)语义一致。
|
||||
if trans is not None:
|
||||
if HT.is_nonlocal_name(trans, nm.id) != 0:
|
||||
nl_addr: llvmlite.Value | t.CPtr = self.Gen.StmtGenDecl.load_nonlocal_var(
|
||||
trans, nm.id)
|
||||
if nl_addr is not None:
|
||||
return nl_addr
|
||||
return_var: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||||
if return_var is None and mod is not None:
|
||||
# 模块全局变量:c.Addr(模块全局) → 返回全局变量指针。
|
||||
# 此前局部符号表查找失败即返回 None → 跌落跨模块函数调用路径
|
||||
# 生成 call @Addr(裸名,无 obj 定义)→ ld.lld undefined symbol:
|
||||
# Addr(VKernel main.vp L87 c.Addr(ncpu_cr) 及 4d/8d/a1/c3/d3
|
||||
# 大量模块全局取地址根因)。必须经 make_global_ref 转成带引号的
|
||||
# Ptr(Ty) 引用——直接返回 GlobalVariable 节点时其 Ty 是 pointee、
|
||||
# Name 无 @ 引号,参与 ptrtoint 会渲染成 "ptrtoint void to i64"
|
||||
# (llc: void type only allowed for function results)。
|
||||
gv_ref_nm: llvmlite.GlobalVariable | t.CPtr = self.Gen.ExprGenAttr.find_global_in_module(mod, nm.id)
|
||||
if gv_ref_nm is not None and gv_ref_nm.Name is not None and gv_ref_nm.Ty is not None:
|
||||
return_var = self.Gen.ExprGenAttr.make_global_ref(pool, gv_ref_nm.Name, gv_ref_nm.Ty)
|
||||
# 模块函数地址:c.Addr(_on_int_complete) → 函数符号本身(@sha1.func)。
|
||||
# 此前 Name 分支只查局部/模块全局变量,函数取地址失败 return None
|
||||
# → 跌落跨模块函数调用生成 call @Addr → ld.lld undefined symbol:
|
||||
# Addr(uhci.vp L130、coroutine.vp L133 c.Addr(_coro_entry)、
|
||||
# sched.vp L209 c.Addr(_thread_entry) 根因)。
|
||||
if return_var is None and mod is not None:
|
||||
f_addr_ref: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module(mod, nm.id)
|
||||
if f_addr_ref is not None:
|
||||
f_addr_name: str = llvmlite.function_get_name(f_addr_ref)
|
||||
if f_addr_name is not None:
|
||||
p_head_ca: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(f_addr_ref)
|
||||
p_cnt_ca: t.CSizeT = 0
|
||||
p_cur_ca: llvmlite.Param | t.CPtr = p_head_ca
|
||||
while p_cur_ca is not None:
|
||||
p_cnt_ca += 1
|
||||
p_cur_ca = llvmlite.param_get_next(p_cur_ca)
|
||||
fn_ty_ca: llvmlite.LLVMType | t.CPtr = llvmlite.Func(
|
||||
pool, f_addr_ref.RetTy, p_head_ca, p_cnt_ca)
|
||||
# 函数引用名需按需加引号(数字开头/含 '.' 的 sha1 前缀名
|
||||
# 必须 @\"...\",否则 llc "expected 'to' after cast value",
|
||||
# uhci.vp c.Addr(_on_int_complete) 根因)。
|
||||
fnlen_ca: t.CSizeT = string.strlen(f_addr_name)
|
||||
needs_q_ca: int = self.Gen.ClassGenVTable._vtable_name_needs_quote(f_addr_name)
|
||||
faddr_buf_ca: str = pool.alloc(fnlen_ca + 4)
|
||||
if faddr_buf_ca is not None and fn_ty_ca is not None:
|
||||
if needs_q_ca != 0:
|
||||
viperlib.snprintf(faddr_buf_ca, fnlen_ca + 4, "@\"%s\"", f_addr_name)
|
||||
else:
|
||||
viperlib.snprintf(faddr_buf_ca, fnlen_ca + 4, "@%s", f_addr_name)
|
||||
return_var = llvmlite.SSAValue(
|
||||
pool, llvmlite.Ptr(pool, fn_ty_ca), faddr_buf_ca)
|
||||
# 闭包变量:c.Addr(闭包名) → 返回闭包对象指针(load 一次)。
|
||||
# 闭包 alloca 是 i8**(存 {fn_ptr, env_ptr} 结构地址);不 load 的话
|
||||
# 会把 &闭包指针变量(i8**)当对象地址传,回调侧按闭包结构读
|
||||
# fn_ptr 会读到指针变量的存储地址而非函数地址(与 Struct 对象
|
||||
# 变量 c.Addr(obj) load 一次的语义一致)。
|
||||
if return_var is not None and return_var.Ty is not None:
|
||||
if self.Gen.CallGenLeafKit.is_closure_name(nm.id) != 0:
|
||||
i8_ty_cb: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_cb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_cb)
|
||||
return llvmlite.build_load(builder, i8_ptr_ty_cb, return_var)
|
||||
if return_var is not None and return_var.Ty is not None:
|
||||
# 对象指针变量(如 lit_tree = zhuff.zhuff_tree(),alloca 是
|
||||
# Ptr(Ptr(Struct)),存对象指针):c.Addr(对象变量) 应返回对象
|
||||
@@ -377,52 +448,151 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
at_addr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg0)
|
||||
if at_addr is None or at_addr.attr is None or at_addr.value is None:
|
||||
return None
|
||||
# 解析 self(Name)→ 查找 alloca
|
||||
if at_addr.value.kind() != ast.ASTKind.Name:
|
||||
return None
|
||||
self_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_addr.value)
|
||||
if self_nm.id is None:
|
||||
return None
|
||||
self_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(
|
||||
trans.SymTab, self_nm.id)
|
||||
if self_alloca is None or self_alloca.Ty is None:
|
||||
return None
|
||||
# 从 self 类型提取结构体类型(Ptr(Struct) 或 Ptr(Ptr(Struct)))
|
||||
# 跨模块函数地址:c.Addr(serial.puts) → 函数符号本身(@sha1.puts)。
|
||||
# 此前 Attribute 分支只支持 self/cls 字段 GEP;serial.puts 的 value 是
|
||||
# 已导入模块名(非局部变量)→ 下方 self_alloca 查找失败 return None →
|
||||
# 回退 ExprGenAttr 当全局变量处理(创建 @sha1.puts external global i8*
|
||||
# + load)→ 与 vpi 注入的 puts 函数 declare 同名冲突 → llc
|
||||
# "redefinition of function '@a6890f1aeecb0aaf.puts'"
|
||||
# (elf.vp L485 c.Addr(serial.puts) 根因)。
|
||||
if at_addr.value.kind() == ast.ASTKind.Name and trans is not None \
|
||||
and trans._imported_modules is not None:
|
||||
mod_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_addr.value)
|
||||
if mod_nm2.id is not None:
|
||||
if self.Gen.ImportsGen.is_module_imported(
|
||||
trans._imported_modules, mod_nm2.id) != 0:
|
||||
f_ref2: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module(
|
||||
mod, at_addr.attr)
|
||||
if f_ref2 is not None:
|
||||
fname2: str = llvmlite.function_get_name(f_ref2)
|
||||
if fname2 is not None:
|
||||
# 构造带 @ 名的 SSAValue(Ptr(FuncTy)):直接返回
|
||||
# Function 节点会被 IRBuilder 格式化成 RetTy(void)
|
||||
# → "bitcast void to i8*"(elf.vp L2874 根因)。
|
||||
# Function 无 Ty 字段(成员仅 Next/Name/RetTy/
|
||||
# Params/Blocks/IsDeclared/IsVarArg/Attrs),
|
||||
# 用 RetTy+Params 重建函数类型。Params 是
|
||||
# GSList(含 Head 字段),必须经
|
||||
# function_get_param_head 取链表头——直接
|
||||
# 把 Params 当 Param 遍历会读 GSList.Head/
|
||||
# Next 当 Name/Ty → 垃圾参数类型
|
||||
# "i32 (i1425633744, i8*)"(elf.vp L2874 根因)。
|
||||
p_head2: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(f_ref2)
|
||||
p_cnt2: t.CSizeT = 0
|
||||
p_cur2: llvmlite.Param | t.CPtr = p_head2
|
||||
while p_cur2 is not None:
|
||||
p_cnt2 += 1
|
||||
p_cur2 = llvmlite.param_get_next(p_cur2)
|
||||
fn_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Func(
|
||||
pool, f_ref2.RetTy, p_head2, p_cnt2)
|
||||
# 函数引用名按需加引号(数字开头/含 '.' 的
|
||||
# sha1 前缀名必须 @\"...\")。
|
||||
fnlen2: t.CSizeT = string.strlen(fname2)
|
||||
needs_q2: int = self.Gen.ClassGenVTable._vtable_name_needs_quote(fname2)
|
||||
faddr_buf2: str = pool.alloc(fnlen2 + 4)
|
||||
if faddr_buf2 is not None and fn_ty2 is not None:
|
||||
if needs_q2 != 0:
|
||||
viperlib.snprintf(faddr_buf2, fnlen2 + 4, "@\"%s\"", fname2)
|
||||
else:
|
||||
viperlib.snprintf(faddr_buf2, fnlen2 + 4, "@%s", fname2)
|
||||
return llvmlite.SSAValue(
|
||||
pool, llvmlite.Ptr(pool, fn_ty2), faddr_buf2)
|
||||
else:
|
||||
# 模块限定全局:c.Addr(gdt.gp) → 全局符号本身(@gp)。
|
||||
# 跨模块全局(含 CExport 裸名 @gp)已注入为 external
|
||||
# global。经 make_global_ref 转成带引号的 Ptr(Ty) 引用
|
||||
# (直接返回 GlobalVariable 节点会渲染 "ptrtoint void")。
|
||||
# 此前未处理 → return None → 跌落跨模块函数调用路径
|
||||
# 生成 call @Addr(裸名,无 obj 定义)→ ld.lld
|
||||
# undefined symbol: Addr(apic.vp L193 c.Addr(gdt.gp)
|
||||
# / L199 c.Addr(idt.idt) 根因)。
|
||||
g_ref2: llvmlite.GlobalVariable | t.CPtr = self.Gen.ExprGenAttr.find_global_in_module(
|
||||
mod, at_addr.attr)
|
||||
if g_ref2 is not None and g_ref2.Name is not None and g_ref2.Ty is not None:
|
||||
return self.Gen.ExprGenAttr.make_global_ref(pool, g_ref2.Name, g_ref2.Ty)
|
||||
# 解析 base(Name 变量 / Subscript 数组元素)→ 对象指针
|
||||
obj_ptr: llvmlite.Value | t.CPtr = None
|
||||
struct_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
self_is_ptr_ptr: int = 0
|
||||
match self_alloca.Ty:
|
||||
case llvmlite.LLVMType.Ptr(inner1):
|
||||
match inner1:
|
||||
case llvmlite.LLVMType.Ptr(inner2):
|
||||
struct_ty = inner2
|
||||
self_is_ptr_ptr = 1
|
||||
case _:
|
||||
struct_ty = inner1
|
||||
case _:
|
||||
if at_addr.value.kind() == ast.ASTKind.Subscript:
|
||||
# c.Addr(s.threads[0].rsp):base 是数组元素(Subscript)→ 先取
|
||||
# 元素指针(GEP 数组),再 GEP 到字段。此前仅支持 Name base,
|
||||
# Subscript 落到下方 return None → 跌落跨模块函数调用生成
|
||||
# call @Addr(sched.vp L90/L182/L188/L196、coroutine.vp
|
||||
# L99/L106/L112/L120 根因)。
|
||||
sub_base: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(at_addr.value)
|
||||
if sub_base.value is None or sub_base.slice is None:
|
||||
return None
|
||||
bval: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, sub_base.value, None, 0, trans)
|
||||
bidx: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, sub_base.slice, None, 0, trans)
|
||||
if bval is None or bidx is None or bval.Ty is None:
|
||||
return None
|
||||
bpointee: llvmlite.LLVMType | t.CPtr = None
|
||||
if self.Gen.ExprGenBase.is_ptr_type(bval.Ty) != 0:
|
||||
bpointee = bval.Ty.Pointee
|
||||
if bpointee is not None:
|
||||
match bpointee:
|
||||
case llvmlite.LLVMType.Array(bet, _):
|
||||
obj_ptr = llvmlite.build_gep_array(
|
||||
builder, bpointee, bet, bval, bidx)
|
||||
struct_ty = bet
|
||||
case _:
|
||||
return None
|
||||
else:
|
||||
return None
|
||||
elif at_addr.value.kind() == ast.ASTKind.Name:
|
||||
self_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_addr.value)
|
||||
if self_nm.id is None:
|
||||
return None
|
||||
self_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(
|
||||
trans.SymTab, self_nm.id)
|
||||
if self_alloca is None or self_alloca.Ty is None:
|
||||
return None
|
||||
# 从 self 类型提取结构体类型(Ptr(Struct) 或 Ptr(Ptr(Struct)))
|
||||
self_is_ptr_ptr: int = 0
|
||||
match self_alloca.Ty:
|
||||
case llvmlite.LLVMType.Ptr(inner1):
|
||||
match inner1:
|
||||
case llvmlite.LLVMType.Ptr(inner2):
|
||||
struct_ty = inner2
|
||||
self_is_ptr_ptr = 1
|
||||
case _:
|
||||
struct_ty = inner1
|
||||
case _:
|
||||
return None
|
||||
# self_alloca 是 Ptr(Ptr(Struct)) 时先 load 成 Ptr(Struct) 对象指针
|
||||
obj_ptr = self_alloca
|
||||
if self_is_ptr_ptr == 1:
|
||||
self_obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
|
||||
obj_ptr = llvmlite.build_load(builder, self_obj_ty, self_alloca)
|
||||
else:
|
||||
return None
|
||||
if obj_ptr is None or struct_ty is None:
|
||||
return None
|
||||
# 查找字段
|
||||
fe_addr: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field(
|
||||
struct_ty, at_addr.attr)
|
||||
if fe_addr is None:
|
||||
return None
|
||||
# self_alloca 是 Ptr(Ptr(Struct)) 时先 load 成 Ptr(Struct) 对象指针
|
||||
obj_ptr: llvmlite.Value | t.CPtr = self_alloca
|
||||
if self_is_ptr_ptr == 1:
|
||||
self_obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
|
||||
obj_ptr = llvmlite.build_load(builder, self_obj_ty, self_alloca)
|
||||
if obj_ptr is None:
|
||||
return None
|
||||
# GEP 到字段地址
|
||||
return llvmlite.build_gep_struct(
|
||||
builder, struct_ty, fe_addr.Ty, obj_ptr, fe_addr.Index)
|
||||
|
||||
# Subscript 形式: c.Addr(arr[i]) → 数组元素地址(GEP 数组,不 load)
|
||||
# 用于 self.root_directory = c.Addr(directories[directory_count]) 等。
|
||||
# 此前只支持 Name/Attribute,Subscript 落到函数末尾返回 None →
|
||||
# 赋值右侧为 None(devfs.vp:159 根因)。
|
||||
# Subscript 形式: c.Addr(arr[i]) / c.Addr(a.b[i][j]) → 元素地址(GEP,不 load)
|
||||
# 统一走 get_subscript_ptr(递归处理嵌套下标、数组/指针/str|t.CPtr 形态)。
|
||||
# 此前仅处理单层数组 GEP:嵌套下标(c.Addr(self.lines[line_idx][0]),
|
||||
# vpui.vp L985)的 value 是内层 Subscript,translate_value 把内层加载成
|
||||
# 数组值([80 x i8])→ 非 Ptr → return None → 跌落跨模块函数调用生成
|
||||
# call @Addr(ld.lld undefined symbol: Addr 根因)。
|
||||
if arg0.kind() == ast.ASTKind.Subscript:
|
||||
if trans is None:
|
||||
return None
|
||||
elem_ptr_ca: llvmlite.Value | t.CPtr = self.Gen.ExprGenName.get_subscript_ptr(
|
||||
builder, pool, mod, arg0, trans)
|
||||
if elem_ptr_ca is not None:
|
||||
return elem_ptr_ca
|
||||
# 兜底:单层数组基址 GEP(get_subscript_ptr 未命中的形态)
|
||||
sub_addr: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(arg0)
|
||||
if sub_addr is None or sub_addr.value is None or sub_addr.slice is None:
|
||||
return None
|
||||
@@ -434,7 +604,6 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
builder, pool, mod, sub_addr.slice, None, 0, trans)
|
||||
if idx_val is None:
|
||||
return None
|
||||
# 数组基址 pointee 是 Array(elem_ty, N) → GEP 得元素指针
|
||||
arr_pointee_ca: llvmlite.LLVMType | t.CPtr = None
|
||||
if self.Gen.ExprGenBase.is_ptr_type(arr_val.Ty) != 0:
|
||||
arr_pointee_ca = arr_val.Ty.Pointee
|
||||
@@ -444,7 +613,12 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
return llvmlite.build_gep_array(
|
||||
builder, arr_pointee_ca, arr_et_ca, arr_val, idx_val)
|
||||
case _:
|
||||
pass
|
||||
# 标量/指针元素(如字符串 a[4])→ 简单 GEP 元素地址。
|
||||
# 此前仅 Array 走 GEP,标量 pointee 落 return None →
|
||||
# 跌落跨模块函数调用生成 call @Addr(main.vp L272
|
||||
# c.Addr(a[4]) 根因)。
|
||||
return llvmlite.build_gep(
|
||||
builder, arr_pointee_ca, arr_val, idx_val)
|
||||
return None
|
||||
|
||||
# Call 形式: c.Addr(expr) → 求值 expr 存临时槽(entry alloca),返回槽地址
|
||||
@@ -462,8 +636,13 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
llvmlite.build_store(builder, call_val, tmp_slot)
|
||||
return tmp_slot
|
||||
|
||||
# 其他 arg0 形式(非 Name/Attribute/Subscript/Call):真实掉出函数末尾,
|
||||
# 补显式 return None(fail-fast 不允许流程掉出末尾)
|
||||
# 其他 arg0 形式(非 Name/Attribute/Subscript/Call):fail-fast。
|
||||
# c.Addr 是编译期指令,绝不跌落成运行时 call @Addr(ld.lld undefined
|
||||
# symbol: Addr 根因——未识别形态 return None 会被 translate_call 当作
|
||||
# 普通函数调用处理)。
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
cl, f"c.Addr 不支持的操作数形式(kind={arg0.kind()}),"
|
||||
f"c.Addr 仅支持 变量/全局/函数/数组元素/字段", "TypeError")
|
||||
return None
|
||||
|
||||
|
||||
@@ -529,6 +708,78 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
dst[dlen + i] = '\0'
|
||||
|
||||
|
||||
def _asm_mangle_global_symbols(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
asm_text: str, asm_size: t.CSizeT,
|
||||
mod: llvmlite.LLVMModule | t.CPtr) -> str:
|
||||
"""asm 模板中裸符号引用模块全局的检查(fail-fast)
|
||||
|
||||
内联汇编 `lea rax, [rip + gdt]` 的 gdt 是汇编器符号,若对应模块全局
|
||||
带 SHA1 混淆头(@"054f5e56cbefcaa4.gdt")则无法在 LLVM MC 中引用:
|
||||
数字开头的符号名会被解析成数字 → llc "Unexpected offset"(VKernel
|
||||
gdt.vp L76/L93、sched.vp `[rip + _switch_old_rsp]` 根因)。因此引用
|
||||
的全局必须标记 t.CExport 使用裸名(@gdt),此处按词边界匹配(前后
|
||||
非标识符字符,避免误伤寄存器名/局部标签/指令助记符)命中即报错。
|
||||
"""
|
||||
if asm_text is None or mod is None:
|
||||
return asm_text
|
||||
src_len: t.CSizeT = string.strlen(asm_text)
|
||||
if src_len == 0:
|
||||
return asm_text
|
||||
out: str = pool.alloc(asm_size * 2)
|
||||
if out is None:
|
||||
return asm_text
|
||||
out[0] = '\0'
|
||||
out_pos: t.CSizeT = 0
|
||||
i: t.CSizeT = 0
|
||||
while i < src_len:
|
||||
matched: int = 0
|
||||
cur: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead
|
||||
while cur is not None:
|
||||
gname: str = cur.Name
|
||||
if gname is not None and string.strchr(gname, 46) is not None:
|
||||
dot_g: str = string.strchr(gname, 46)
|
||||
bare_g: str = dot_g + 1
|
||||
bare_len: t.CSizeT = string.strlen(bare_g)
|
||||
if bare_len > 0 and i + bare_len <= src_len:
|
||||
if string.strncmp(asm_text + i, bare_g, bare_len) == 0:
|
||||
# 词边界:前后非标识符字符(字母/数字/_)
|
||||
prev_ok: int = 1
|
||||
next_ok: int = 1
|
||||
if i > 0:
|
||||
prev_ch: t.CChar = asm_text[i - 1]
|
||||
if (prev_ch >= 'a' and prev_ch <= 'z') \
|
||||
or (prev_ch >= 'A' and prev_ch <= 'Z') \
|
||||
or (prev_ch >= '0' and prev_ch <= '9') \
|
||||
or prev_ch == '_':
|
||||
prev_ok = 0
|
||||
if i + bare_len < src_len:
|
||||
next_ch: t.CChar = asm_text[i + bare_len]
|
||||
if (next_ch >= 'a' and next_ch <= 'z') \
|
||||
or (next_ch >= 'A' and next_ch <= 'Z') \
|
||||
or (next_ch >= '0' and next_ch <= '9') \
|
||||
or next_ch == '_':
|
||||
next_ok = 0
|
||||
if prev_ok != 0 and next_ok != 0:
|
||||
# fail-fast:asm 模板引用的模块全局带 SHA1 混淆头
|
||||
# 不可在 LLVM MC 内联汇编中使用(数字开头的符号名
|
||||
# 会被解析成数字而报 "Unexpected offset"),必须
|
||||
# 标记 t.CExport 使用裸名(如 gdt → @gdt)。
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
None,
|
||||
f"asm 模板引用的全局符号 '{bare_g}' 带 SHA1 混淆头"
|
||||
f"({gname}),内联汇编必须引用裸名符号,请将该"
|
||||
f"全局定义标记为 t.CExport", "TypeError")
|
||||
return asm_text
|
||||
cur = cur.Next
|
||||
if matched == 0:
|
||||
if out_pos + 1 < asm_size * 2:
|
||||
out[out_pos] = asm_text[i]
|
||||
out_pos += 1
|
||||
i += 1
|
||||
out[out_pos] = '\0'
|
||||
return out
|
||||
|
||||
|
||||
def _asm_escape_for_ir(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
src: str) -> str:
|
||||
"""转义汇编文本用于 LLVM IR 字符串字面量"""
|
||||
@@ -730,6 +981,38 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
return at.attr
|
||||
|
||||
|
||||
def _asm_name_is_mangled(self, name: str) -> int:
|
||||
"""判断 LLVM 名称是否带 SHA1 混淆头(16 hex + '.'),返回 1=是
|
||||
|
||||
兼容 make_global_ref 生成的 '@"sha1.name"' 引用名和 GlobalVariable
|
||||
裸名 "sha1.name"。'@name' 裸引用与局部 SSA(%N)都不算混淆。
|
||||
"""
|
||||
if name is None:
|
||||
return 0
|
||||
n: str = name
|
||||
nlen: t.CSizeT = string.strlen(n)
|
||||
# 去掉 '@"..."' 包装(引用名)
|
||||
if nlen >= 3 and n[0] == '@' and n[1] == '"' and n[nlen - 1] == '"':
|
||||
n = n + 2
|
||||
nlen -= 3
|
||||
elif nlen >= 1 and n[0] == '@':
|
||||
n = n + 1
|
||||
nlen -= 1
|
||||
if nlen <= 17:
|
||||
return 0
|
||||
for i in range(16, nlen):
|
||||
if n[i] == '.':
|
||||
ok: int = 1
|
||||
for j in range(16):
|
||||
cc: t.CChar = n[i - 16 + j]
|
||||
if not (('0' <= cc <= '9') or ('a' <= cc <= 'f') or ('A' <= cc <= 'F')):
|
||||
ok = 0
|
||||
break
|
||||
if ok != 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def _asm_add_operand(self, operands: GenTypes.AsmOperand | t.CPtr,
|
||||
count: int,
|
||||
val: llvmlite.Value | t.CPtr,
|
||||
@@ -744,6 +1027,16 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
"""
|
||||
if count >= ASM_MAX_OPERANDS:
|
||||
return count
|
||||
# fail-fast:AsmInp/AsmOut 操作数不允许带 SHA1 混淆头的符号
|
||||
# (模块级全局/函数)。LLVM MC 内联汇编无法解析数字开头的符号名,
|
||||
# 且裸机链接要求裸名 —— 必须将对应定义标记为 t.CExport。
|
||||
if val is not None and val.Name is not None:
|
||||
if self._asm_name_is_mangled(val.Name) != 0:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
None,
|
||||
f"c.Asm 操作数(AsmInp/AsmOut)不允许带 SHA1 混淆头的符号 "
|
||||
f"'{val.Name}',请将对应函数/全局定义标记为 t.CExport(裸名)",
|
||||
"TypeError")
|
||||
if val is not None:
|
||||
for ei in range(count):
|
||||
eop: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, ei)
|
||||
@@ -751,6 +1044,16 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
return count
|
||||
op: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, count)
|
||||
op.Value = val
|
||||
# 缺省约束:AsmInp(reg) 只传 1 参无 descr → 约束空 → llc
|
||||
# "number of input constraints does not match number of parameters"
|
||||
# (mm.vp L730 c.Asm(f"mov al, {AsmInp(reg)}\nout 0x70, al") 根因)。
|
||||
# 输入默认 "r"(通用寄存器)、输出默认 "=r"(寄存器输出),
|
||||
# 与 _resolve_register 的 REG_ANY/OUTPUT_REG 一致。
|
||||
if constraint is None or string.strlen(constraint) == 0:
|
||||
if is_output != 0:
|
||||
constraint = "=r"
|
||||
else:
|
||||
constraint = "r"
|
||||
op.Constraint = constraint
|
||||
op.IsOutput = is_output
|
||||
return count + 1
|
||||
@@ -845,13 +1148,60 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
cons_str = self._resolve_asm_descr(pool, fargs.get(1))
|
||||
|
||||
if is_out != 0:
|
||||
# 输出:获取变量 alloca
|
||||
if val_node is None or val_node.kind() != ast.ASTKind.Name:
|
||||
# 输出:获取变量 alloca(Name 局部/全局 或
|
||||
# Attribute 字段地址)
|
||||
if val_node is None:
|
||||
continue
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node)
|
||||
if nm.id is None:
|
||||
continue
|
||||
alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||||
alloca: llvmlite.Value | t.CPtr = None
|
||||
if val_node.kind() == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node)
|
||||
if nm.id is None:
|
||||
continue
|
||||
alloca = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||||
if alloca is None:
|
||||
# 模块级全局变量(process.vp _saved_cr3 来自
|
||||
# isr.s .comm):lookup_var 只查局部 → 全局
|
||||
# 落空 → 操作数缺失 → asm 模板 "$0" 空 →
|
||||
# "mov , cr3" llc unknown token in expression。
|
||||
# 回退查模块全局(精确+后缀),全局 Value
|
||||
# (@name,类型 i64*)直接当 store 目标。
|
||||
alloca = self.Gen.ExprGenAttr.find_global_in_module(mod, nm.id)
|
||||
elif val_node.kind() == ast.ASTKind.Attribute:
|
||||
# AsmOut(p.pml4_root)(p 为 Process 指针):
|
||||
# GEP 到字段地址(对齐 translate_c_addr Attribute
|
||||
# 分支)。仅 Name 检查时 Attribute 被跳过 →
|
||||
# 空操作数 "mov , cr3"(process.vp L127/L208 根因)。
|
||||
at_a: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(val_node)
|
||||
if at_a.attr is not None and at_a.value is not None \
|
||||
and at_a.value.kind() == ast.ASTKind.Name:
|
||||
base_nm_a: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_a.value)
|
||||
if base_nm_a.id is not None:
|
||||
base_alloca_a: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(
|
||||
trans.SymTab, base_nm_a.id)
|
||||
if base_alloca_a is not None and base_alloca_a.Ty is not None:
|
||||
struct_ty_a: llvmlite.LLVMType | t.CPtr = None
|
||||
self_is_ptr_ptr_a: int = 0
|
||||
match base_alloca_a.Ty:
|
||||
case llvmlite.LLVMType.Ptr(inner1):
|
||||
match inner1:
|
||||
case llvmlite.LLVMType.Ptr(inner2):
|
||||
struct_ty_a = inner2
|
||||
self_is_ptr_ptr_a = 1
|
||||
case _:
|
||||
struct_ty_a = inner1
|
||||
case _:
|
||||
pass
|
||||
if struct_ty_a is not None:
|
||||
fe_a: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field(
|
||||
struct_ty_a, at_a.attr)
|
||||
if fe_a is not None:
|
||||
obj_ptr_a: llvmlite.Value | t.CPtr = base_alloca_a
|
||||
if self_is_ptr_ptr_a == 1:
|
||||
obj_ptr_a = llvmlite.build_load(
|
||||
builder, llvmlite.Ptr(pool, struct_ty_a), base_alloca_a)
|
||||
if obj_ptr_a is not None:
|
||||
alloca = llvmlite.build_gep_struct(
|
||||
builder, struct_ty_a, fe_a.Ty, obj_ptr_a, fe_a.Index)
|
||||
if alloca is None:
|
||||
continue
|
||||
operand_count = self._asm_add_operand(
|
||||
@@ -1192,8 +1542,12 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||||
|
||||
# ============================================================
|
||||
# 7. 转义汇编文本
|
||||
# ============================================================
|
||||
escaped_asm: str = self._asm_escape_for_ir(pool, asm_text)
|
||||
# 7.0 先做裸符号→混淆名替换(lea rax, [rip + gdt] → [rip + 054f5e56cbefcaa4.gdt])
|
||||
mangled_asm: str = self._asm_mangle_global_symbols(
|
||||
pool, asm_text, ASM_TEXT_BUF_SIZE, mod)
|
||||
if mangled_asm is None:
|
||||
mangled_asm = asm_text
|
||||
escaped_asm: str = self._asm_escape_for_ir(pool, mangled_asm)
|
||||
if escaped_asm is None:
|
||||
return None
|
||||
|
||||
|
||||
@@ -710,6 +710,12 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
mc_entry = self.Gen.StructGen.find_struct_by_type(mc_struct_ty)
|
||||
if mc_entry is None:
|
||||
mc_entry = self.Gen.StructGen.find_struct(class_name)
|
||||
# [MMDBG] 诊断:mc_entry 解析(用后移除)
|
||||
if string.strcmp(method_name, "Sub") == 0:
|
||||
if mc_entry is not None:
|
||||
stdio.printf("[MMDBG] mc_entry.Name=%s\n", mc_entry.Name)
|
||||
else:
|
||||
stdio.printf("[MMDBG] mc_entry=None\n")
|
||||
|
||||
# 构造方法查找名: ClassName.method_name
|
||||
lookup_name: str = pool.alloc(128)
|
||||
@@ -719,6 +725,12 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
|
||||
# 查找函数(支持 SHA1 后缀匹配)
|
||||
found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, lookup_name)
|
||||
# [MMDBG] 诊断:found_func 查找(用后移除)
|
||||
if string.strcmp(method_name, "Sub") == 0:
|
||||
if found_func is not None:
|
||||
stdio.printf("[MMDBG] found_func=%s\n", llvmlite.function_get_name(found_func))
|
||||
else:
|
||||
stdio.printf("[MMDBG] found_func=None lookup=%s\n", lookup_name)
|
||||
|
||||
# 泛型模板类方法:特化函数名带类型参数({sha1}.list[int].get),
|
||||
# "ClassName.method" 短名匹配不到。特化由触发方(通常即调用方)模块完成,
|
||||
@@ -1577,9 +1589,20 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
is_variadic_3441: int = self.Gen.CallGenVa._check_and_promote_variadic_call(
|
||||
pool, builder, mod, call_name, head, total_count, cargs, 1, trans)
|
||||
# try-except:方法含 raise(EH 输出参数)时追加输出实参 + 调用后检测
|
||||
return self.Gen.CallGenLeafKit._emit_eh_guarded_call(
|
||||
# [MMDBG] 诊断:调用发射前状态(用后移除)
|
||||
if string.strcmp(method_name, "Sub") == 0:
|
||||
stdio.printf("[MMDBG] pre-call call_name=%s ret_ty_ptr=%llu head=%llu count=%d\n",
|
||||
call_name, t.CUInt64T(call_ret_ty), t.CUInt64T(head), total_count)
|
||||
res_final: llvmlite.Value | t.CPtr = self.Gen.CallGenLeafKit._emit_eh_guarded_call(
|
||||
builder, pool, mod, trans, found_func, call_name, head, total_count,
|
||||
call_ret_ty, is_variadic_3441)
|
||||
# [MMDBG] 诊断:调用发射结果(用后移除)
|
||||
if string.strcmp(method_name, "Sub") == 0:
|
||||
if res_final is not None:
|
||||
stdio.printf("[MMDBG] _emit_eh_guarded_call ok\n")
|
||||
else:
|
||||
stdio.printf("[MMDBG] _emit_eh_guarded_call None\n")
|
||||
return res_final
|
||||
# ============================================================
|
||||
# _translate_super_call — super().method(args) → 静态调用父类方法
|
||||
#
|
||||
|
||||
@@ -715,7 +715,7 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if kw is None or kw.arg is None or kw.value is None:
|
||||
continue
|
||||
fe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field_by_class(
|
||||
class_name, kw.arg, kw_sha1)
|
||||
class_name, kw.arg, kw_sha1, kw, trans._from_imports)
|
||||
if fe is None:
|
||||
# 关键字字段不存在:fail-fast(AttributeError),绝不静默跳过
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
|
||||
@@ -306,6 +306,81 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if tc_at.value is not None and tc_at.value.kind() == ast.ASTKind.Name:
|
||||
tc_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_at.value)
|
||||
if tc_mod_nm.id is not None and string.strcmp(tc_mod_nm.id, "t") == 0:
|
||||
# t.CType 特殊形式:t.CType(value, TypeName, t.CPtr) →
|
||||
# 把 value 转为 TypeName|t.CPtr(TypeName* 指针)。TypeName
|
||||
# 是类型名(Name/Attribute),不是值表达式——此前被当普通
|
||||
# 参数翻译 → NameError: 未定义名称 'memory_block'
|
||||
# (VKernel mm.vp merge_blocks 根因)。CType 不是 map_t_type
|
||||
# 的具名类型,须在此显式处理,否则跌落到跨模块 FATAL。
|
||||
if string.strcmp(func_name, "CType") == 0 and can >= 2:
|
||||
cty_node: ast.AST | t.CPtr = cargs.get(1)
|
||||
ctype_target: llvmlite.LLVMType | t.CPtr = None
|
||||
if cty_node is not None:
|
||||
cti_imp: str = None
|
||||
cti_fi: str = None
|
||||
if trans is not None:
|
||||
cti_imp = trans._imported_modules
|
||||
cti_fi = trans._from_imports
|
||||
ctype_target = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, cty_node, cti_imp, cti_fi, trans, 0)
|
||||
if ctype_target is not None:
|
||||
if can == 3:
|
||||
cty_arg3: ast.AST | t.CPtr = cargs.get(2)
|
||||
cty_is_cptr: int = 0
|
||||
if cty_arg3 is not None:
|
||||
# 形式 1: t.CPtr(Attribute)
|
||||
if cty_arg3.kind() == ast.ASTKind.Attribute:
|
||||
cty_at3: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cty_arg3)
|
||||
if cty_at3.attr is not None and string.strcmp(cty_at3.attr, "CPtr") == 0:
|
||||
if cty_at3.value is not None and cty_at3.value.kind() == ast.ASTKind.Name:
|
||||
cty_nm3: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cty_at3.value)
|
||||
if cty_nm3.id is not None and string.strcmp(cty_nm3.id, "t") == 0:
|
||||
cty_is_cptr = 1
|
||||
# 形式 2: 裸名 CPtr
|
||||
elif cty_arg3.kind() == ast.ASTKind.Name:
|
||||
cty_bn3: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cty_arg3)
|
||||
if cty_bn3.id is not None and string.strcmp(cty_bn3.id, "CPtr") == 0:
|
||||
cty_is_cptr = 1
|
||||
if cty_is_cptr != 0:
|
||||
# CVoid* → i8*(LLVM 中 void* 表示为 i8*)
|
||||
match ctype_target:
|
||||
case llvmlite.LLVMType.Void():
|
||||
ctype_target = llvmlite.Int8(pool)
|
||||
case _:
|
||||
pass
|
||||
ctype_target = llvmlite.Ptr(pool, ctype_target)
|
||||
cty_arg0: ast.AST | t.CPtr = cargs.get(0)
|
||||
if cty_arg0 is not None:
|
||||
cty_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, cty_arg0, funcs_ptr, func_count, trans)
|
||||
if cty_val is not None:
|
||||
return self.Gen.CallGenCtor._translate_t_type_cast(
|
||||
pool, builder, cty_val, ctype_target,
|
||||
func_name, cty_arg0, trans)
|
||||
# t.CType 语法已确认:即使类型解析失败也不跌落到跨模块 FATAL
|
||||
return None
|
||||
# CConst const 标记:CConst(val, t.CPtr) → Ptr(i8)(const void*)。
|
||||
# CConst 不是 map_t_type 具名类型——t.CConst|t.CChar|t.CPtr 注解 =
|
||||
# const char*(i8*),显式调用 t.CConst(addr, t.CPtr) 把整数地址转
|
||||
# const 指针。此前 map_t_type 失败 → 跌落跨模块函数调用 → 生成
|
||||
# call @CConst(裸名,无 obj 定义)→ ld.lld undefined symbol:
|
||||
# CConst(elf.vp L650 t.CConst(t.CUInt64T(strtab_ptr)+sym.st_name,
|
||||
# t.CPtr) 根因)。单参 CConst(x) 仅 const 限定,LLVM 类型不变,
|
||||
# 直接返回原值。
|
||||
if string.strcmp(func_name, "CConst") == 0:
|
||||
if can >= 2:
|
||||
cconst_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
|
||||
pool, llvmlite.Int8(pool))
|
||||
cconst_arg: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
|
||||
if cconst_arg is not None:
|
||||
return self.Gen.CallGenCtor._translate_t_type_cast(
|
||||
pool, builder, cconst_arg, cconst_ptr_ty,
|
||||
func_name, cargs.get(0), trans)
|
||||
elif can == 1:
|
||||
return self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
|
||||
return None
|
||||
target_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.map_t_type(pool, func_name)
|
||||
if target_ty is not None:
|
||||
tc_effective_can: t.CSizeT = can
|
||||
@@ -374,7 +449,7 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
mod_imp_td = trans._imported_modules
|
||||
mod_fi_td = trans._from_imports
|
||||
mod_td_ty = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, mod_td_ast, mod_imp_td, mod_fi_td, trans)
|
||||
pool, mod_td_ast, mod_imp_td, mod_fi_td, trans, 0)
|
||||
if mod_td_ty is not None and can == 1:
|
||||
mt_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
|
||||
@@ -412,7 +487,7 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
imp_gp = trans._imported_modules
|
||||
fi_gp = trans._from_imports
|
||||
bare_ty = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, gp_ast, imp_gp, fi_gp, trans)
|
||||
pool, gp_ast, imp_gp, fi_gp, trans, 0)
|
||||
# 泛型类型参数双参数形式: T(val, t.CPtr) → Ptr(T)
|
||||
# (与 t.CInt(val, t.CPtr) → Ptr(i32) 对齐;vector.vp get() 的
|
||||
# typed_ptr = T(offset, t.CPtr) 依赖此路径,否则双参数不进
|
||||
@@ -944,9 +1019,72 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||||
if method_at is not None and method_at.value is not None:
|
||||
# 链式方法调用: a.b().c() —— value 是内层 Call(如 gfx.vp 的
|
||||
# eye.Sub(target).Norm())。此前未处理 → 外层 .Norm() 的 value
|
||||
# 非 Name 跳过方法分支 → 通用路径把 eye.Sub 当属性解析 →
|
||||
# "属性写入失败: .Sub"。先翻译内层调用得接收者,再方法调用。
|
||||
if method_at.value.kind() == ast.ASTKind.Call and trans is not None:
|
||||
recv_val_c: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, method_at.value, None, 0, trans)
|
||||
if recv_val_c is not None and recv_val_c.Ty is not None:
|
||||
recv_ty_c: llvmlite.LLVMType | t.CPtr = recv_val_c.Ty
|
||||
if self.Gen.ExprGenBase.is_ptr_type(recv_ty_c) != 0:
|
||||
recv_ty_c = recv_ty_c.Pointee
|
||||
# 堆对象(@t.Object)双指针 → 再解一层取 struct
|
||||
if self.Gen.ExprGenBase.is_ptr_type(recv_ty_c) != 0:
|
||||
recv_ty_c = recv_ty_c.Pointee
|
||||
recv_cls_c: str = self.Gen.StructGen.get_class_name_by_type(
|
||||
pool, recv_ty_c)
|
||||
if recv_cls_c is not None:
|
||||
if self.Gen.CallGenProp._is_list_builtin_method(
|
||||
recv_cls_c, method_at.attr) == 0:
|
||||
obj_ptr_c: llvmlite.Value | t.CPtr = recv_val_c
|
||||
if self.Gen.ExprGenBase.is_ptr_type(recv_val_c.Ty) != 0 \
|
||||
and recv_val_c.Ty.Pointee is not None \
|
||||
and self.Gen.ExprGenBase.is_ptr_type(recv_val_c.Ty.Pointee) != 0:
|
||||
obj_ptr_c = llvmlite.build_load(
|
||||
builder, recv_val_c.Ty, recv_val_c)
|
||||
if obj_ptr_c is not None:
|
||||
if hit_box is not None:
|
||||
hit_box[0] = 1
|
||||
return self.Gen.CallGenCall._translate_method_call(
|
||||
pool, builder, mod, recv_cls_c, method_at.attr,
|
||||
obj_ptr_c, cl, trans)
|
||||
if method_at.value.kind() == ast.ASTKind.Name and trans is not None:
|
||||
method_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(method_at.value)
|
||||
if method_obj_nm.id is not None:
|
||||
# nonlocal 对象:提升函数内从 env 读对象指针(load_nonlocal_var),
|
||||
# 不能 lookup_var 跨函数命中父函数 alloca(SSA 编号错乱 →
|
||||
# llc "use of undefined value")。entry.get() 等方法调用的
|
||||
# 基座对象经此路径解析(closure 隐式捕获场景)。
|
||||
# 用 get_struct_type_from_value 递归解 Ptr,兼容
|
||||
# Ptr(Struct)(load_nonlocal_var 已 load)与
|
||||
# Ptr(Ptr(Struct))(联合简化未解引用)两种形态。
|
||||
if HT.is_nonlocal_name(trans, method_obj_nm.id) != 0:
|
||||
nl_obj: llvmlite.Value | t.CPtr = self.Gen.StmtGenDecl.load_nonlocal_var(
|
||||
trans, method_obj_nm.id)
|
||||
if nl_obj is not None and nl_obj.Ty is not None:
|
||||
nl_deref: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase._deref_if_ptr_ptr(
|
||||
builder, nl_obj)
|
||||
if nl_deref is None:
|
||||
nl_deref = nl_obj
|
||||
nl_struct: llvmlite.LLVMType | t.CPtr = \
|
||||
self.Gen.StructGen.get_struct_type_from_value(nl_deref)
|
||||
if nl_struct is not None:
|
||||
nl_cls: str = self.Gen.StructGen.get_class_name_by_type(
|
||||
pool, nl_struct)
|
||||
if nl_cls is not None:
|
||||
if self.Gen.CallGenProp._is_list_builtin_method(
|
||||
nl_cls, func_name) == 0:
|
||||
if hit_box is not None:
|
||||
hit_box[0] = 1
|
||||
return self.Gen.CallGenCall._translate_method_call(
|
||||
pool, builder, mod, nl_cls, func_name,
|
||||
nl_deref, cl, trans)
|
||||
# 非 local 对象但分派未成功:绝不回退 lookup_var
|
||||
# (其 Alloca 是父函数存储,跨函数引用 → SSA 错乱),
|
||||
# 返回 None 让上层 fast-fail 暴露类型解析问题。
|
||||
return None
|
||||
# 查找对象变量
|
||||
obj_var: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(
|
||||
trans.SymTab, method_obj_nm.id)
|
||||
|
||||
@@ -1183,6 +1183,13 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
entry.Defaults = defaults
|
||||
entry.DefaultCount = default_count
|
||||
entry.ParamCount = param_count
|
||||
# 范围防御:default_count 异常(vpi tree 损坏时 len 垃圾大数)时放弃
|
||||
# 提取快照(调用方哨兵已拦截,此为第二道),避免 alloc(垃圾) + 数组
|
||||
# 越界写 perm_pool 覆盖当前模块 AST/表(SlotsBugTest 崩溃根因候选)。
|
||||
if default_count > 128:
|
||||
entry.Defaults = None
|
||||
entry.DefaultCount = 0
|
||||
return 0
|
||||
# 提取常量快照到 stdlib
|
||||
if default_count > 0:
|
||||
kinds: t.CInt | t.CPtr = CompilerFactory.get_perm_pool().alloc(default_count * 4)
|
||||
|
||||
@@ -79,7 +79,7 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
return llvmlite.Int32(pool)
|
||||
# 使用 HandlesType.resolve_annotation_type 解析类型表达式
|
||||
resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, type_node, trans._imported_modules, trans._from_imports, trans)
|
||||
pool, type_node, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
if resolved is not None:
|
||||
return resolved
|
||||
# 类型节点存在但解析失败:fail-fast,绝不回退 i32(会按错宽度读变参槽位)
|
||||
@@ -230,6 +230,50 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
count += 1
|
||||
param = llvmlite.param_get_next(param)
|
||||
return count
|
||||
def _get_known_vararg_cfunc_fixed_count(self, name: str) -> int:
|
||||
"""已知变参 C 库函数固定参数个数(-1=未知)
|
||||
|
||||
跨模块 stub 未注入时 find_func_in_module 返回 None(CallGenMixin
|
||||
注释:stubs 在翻译后才注入,翻译时跨模块函数 found_func 恒 None),
|
||||
无法从函数对象获取 IsVarArg/固定参数个数。这些 t.CExport 变参函数
|
||||
(viperlib 定义)签名固定,按表回退(对齐 TPC _C_LIB_FUNCS 机制)。
|
||||
"""
|
||||
if name is None:
|
||||
return -1
|
||||
if string.strcmp(name, "snprintf") == 0:
|
||||
return 3
|
||||
if string.strcmp(name, "sprintf") == 0:
|
||||
return 2
|
||||
if string.strcmp(name, "vsprintf") == 0:
|
||||
return 2
|
||||
return -1
|
||||
|
||||
def _get_known_vararg_cfunc_param_ty(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str, idx: int) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""已知变参 C 库函数第 idx 个固定参数类型(变参位置/未知返回 None)
|
||||
|
||||
固定参数类型是 C ABI 硬约束(snprintf 的 size 为 i64),stub 未注入
|
||||
时按表 coerce,避免 call(i32 1024) 与 declare(i64 size) 不匹配。
|
||||
"""
|
||||
if pool is None or name is None or idx < 0:
|
||||
return None
|
||||
i8_ptr_kv: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
i64_kv: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
if string.strcmp(name, "snprintf") == 0:
|
||||
if idx == 0:
|
||||
return i8_ptr_kv
|
||||
if idx == 1:
|
||||
return i64_kv
|
||||
if idx == 2:
|
||||
return i8_ptr_kv
|
||||
return None
|
||||
if string.strcmp(name, "sprintf") == 0 or string.strcmp(name, "vsprintf") == 0:
|
||||
if idx == 0:
|
||||
return i8_ptr_kv
|
||||
if idx == 1:
|
||||
return i8_ptr_kv
|
||||
return None
|
||||
return None
|
||||
def _check_and_promote_variadic_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
@@ -252,13 +296,20 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
return 0
|
||||
# 查找函数对象
|
||||
func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name)
|
||||
if func is None:
|
||||
return 0
|
||||
if func.IsVarArg != 1:
|
||||
return 0
|
||||
|
||||
# 获取固定参数数量
|
||||
fixed_count: int = self._get_func_fixed_param_count(func)
|
||||
fixed_count: int = -1
|
||||
if func is not None and func.IsVarArg == 1:
|
||||
fixed_count = self._get_func_fixed_param_count(func)
|
||||
else:
|
||||
# 两种情况回退已知变参 C 库函数签名表(snprintf 等):
|
||||
# 1. func 为 None——跨模块 stub 未注入(CallGenMixin 注释:stubs
|
||||
# 在翻译后才注入,翻译时跨模块函数 found_func 恒 None);
|
||||
# 2. func 存在但 IsVarArg=0——该 declare 由 _ensure_method_declare
|
||||
# 按实参类型临时创建(无 ... 标记),不能代表真实签名。
|
||||
# 否则 i32 变参不提升,Win64 8 字节槽只写 4 字节 →
|
||||
# va_arg(i64) 高 4 字节读残留栈垃圾(clean 日志 0x7ff700000052 根因)。
|
||||
fixed_count = self._get_known_vararg_cfunc_fixed_count(call_name)
|
||||
if fixed_count < 0:
|
||||
return 0
|
||||
|
||||
# 无变长参数(实参数量 <= 固定参数数量),仍需 is_variadic=1
|
||||
if can <= fixed_count:
|
||||
@@ -319,6 +370,32 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
promoted.Next = next_node
|
||||
if prev is not None:
|
||||
prev.Next = promoted
|
||||
# Win64 变参槽位 8 字节:i8/i16/i32 → i64
|
||||
# TPV va_arg 读取端统一按 i64 读(_translate_va_arg_sugar),
|
||||
# 调用方必须写满 8 字节槽,否则高 4 字节残留旧栈数据,%d 读到
|
||||
# 0x7ff700000052 类垃圾(clean 日志根因;对齐 CallGenMixin
|
||||
# L798-811 的 found_func.IsVarArg 提升)。
|
||||
i64_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
pb_va: int = self.Gen.ExprGenBase.get_llvm_type_bits(promoted.Ty)
|
||||
if pb_va != 0 and pb_va < 64:
|
||||
promoted_va2: llvmlite.Value | t.CPtr = None
|
||||
is_u_va2: int = 0
|
||||
if arg_nodes is not None and trans is not None:
|
||||
ast_idx_va2: int = v_idx - self_offset
|
||||
if ast_idx_va2 >= 0 and ast_idx_va2 < len(arg_nodes):
|
||||
an_va2: ast.AST | t.CPtr = arg_nodes.get(ast_idx_va2)
|
||||
if an_va2 is not None:
|
||||
if self.Gen.ExprGenOps._node_type_unsigned(pool, an_va2, trans) != 0:
|
||||
is_u_va2 = 1
|
||||
if is_u_va2 != 0:
|
||||
promoted_va2 = llvmlite.build_zext(builder, promoted, i64_ty_promote)
|
||||
else:
|
||||
promoted_va2 = llvmlite.build_sext(builder, promoted, i64_ty_promote)
|
||||
if promoted_va2 is not None:
|
||||
promoted_va2.Next = next_node
|
||||
if prev is not None:
|
||||
prev.Next = promoted_va2
|
||||
promoted = promoted_va2
|
||||
prev = promoted
|
||||
cur = next_node
|
||||
v_idx += 1
|
||||
|
||||
@@ -137,17 +137,32 @@ class CallGenVt(CallGenBase.CallGenBase):
|
||||
llvmlite.module_add_global(mod, vcopy_gv)
|
||||
vcopy_gv.Linkage = None
|
||||
vcopy_gv.Initializer = "zeroinitializer"
|
||||
# 引用名必须带 @ 前缀:SSAValue 名原样输出,裸名
|
||||
# devfs_file.vtable.copy.71 无 @ → llc "expected value token"
|
||||
# (devfs vtable.copy 根因;全局定义 @name 是 new_global_variable
|
||||
# 输出时加的,引用侧不自动加)
|
||||
vcopy_ref_nm: str = pool.alloc(272)
|
||||
if vcopy_ref_nm is None:
|
||||
vcopy_ref_nm = vcopy_buf
|
||||
else:
|
||||
viperlib.snprintf(vcopy_ref_nm, 272, "@%s", vcopy_buf)
|
||||
vcopy_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
|
||||
pool, llvmlite.Ptr(pool, vtable_ty), vcopy_buf)
|
||||
pool, llvmlite.Ptr(pool, vtable_ty), vcopy_ref_nm)
|
||||
if vcopy_ref is not None:
|
||||
vcopy_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
builder, vcopy_ref, i8_ptr_ty)
|
||||
if vcopy_i8 is not None:
|
||||
vt_size: llvmlite.Value | t.CPtr = llvmlite.ConstInt(
|
||||
pool, llvmlite.Int64(pool), method_count * 8, "vtsz")
|
||||
if vt_size is not None:
|
||||
self.Gen.CallGenLib._emit_llvm_memcpy_intrinsic(
|
||||
pool, builder, mod, vcopy_i8, class_vt, vt_size)
|
||||
# ConstInt 的 name 必须是数字文本(如 "56"),不能是
|
||||
# 标识符 "vtsz"——参数经 Name 原样输出,裸名 vtsz 无 %
|
||||
# → llc "expected value token"(devfs memcpy 根因)
|
||||
vtsz_buf: str = pool.alloc(32)
|
||||
if vtsz_buf is not None:
|
||||
viperlib.snprintf(vtsz_buf, 32, "%lld", method_count * 8)
|
||||
vt_size: llvmlite.Value | t.CPtr = llvmlite.ConstInt(
|
||||
pool, llvmlite.Int64(pool), method_count * 8, vtsz_buf)
|
||||
if vt_size is not None:
|
||||
self.Gen.CallGenLib._emit_llvm_memcpy_intrinsic(
|
||||
pool, builder, mod, vcopy_i8, class_vt, vt_size)
|
||||
llvmlite.build_store(builder, vcopy_i8, vtable_slot)
|
||||
llvmlite.build_br(builder, vt_skip_bb)
|
||||
# skip 块:reload vtable → GEP 槽位 → store 函数指针(i8*)
|
||||
|
||||
@@ -328,7 +328,7 @@ class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
|
||||
# 解析字段类型
|
||||
field_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, aa.annotation, trans._imported_modules, trans._from_imports, trans)
|
||||
pool, aa.annotation, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
# 单参 t.CArray[elem] + 列表字面量 → 静态数组 [N x elem]
|
||||
# (与局部 AnnAssign 路径一致,对齐 TPC ParseListAnnotation 语义):
|
||||
# 否则字段保持 Ptr(elem)(如 t.CArray[str] → i8**),
|
||||
|
||||
@@ -449,7 +449,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
|
||||
# 解析字段类型
|
||||
field_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, aa.annotation, trans._imported_modules, trans._from_imports, trans)
|
||||
pool, aa.annotation, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
if field_ty is None:
|
||||
# Phase A-pre(declare_only=1):依赖的类可能尚未注册,
|
||||
# 静默 return 1 让多遍收敛机制生效(renum 返回 1=跳过该类)
|
||||
@@ -707,7 +707,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
mem_ty_l = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, vaa.annotation,
|
||||
trans._imported_modules,
|
||||
trans._from_imports, trans)
|
||||
trans._from_imports, trans, 0)
|
||||
self._register_renum_field_alias(
|
||||
pool, class_name, vnm.id, field_idx + 1,
|
||||
mem_ty_l, variant_cd.name)
|
||||
|
||||
@@ -167,12 +167,18 @@ class ExprGenBase:
|
||||
level: int = 0
|
||||
cur: llvmlite.LLVMType | t.CPtr = ty
|
||||
while cur is not None:
|
||||
# 同类编译 bug(见 TypeGenResolve L1463 注释):case body 直接
|
||||
# 更新 while 条件变量(cur = pointee)时自举编译出的 match 把赋值
|
||||
# 写到 subject 快照槽,while 条件读旧槽 → 死循环。改法:case
|
||||
# 绑定到局部变量,match 外更新循环变量。
|
||||
nxt_cur: llvmlite.LLVMType | t.CPtr = None
|
||||
match cur:
|
||||
case llvmlite.LLVMType.Ptr(pointee):
|
||||
level += 1
|
||||
cur = pointee
|
||||
nxt_cur = pointee
|
||||
case _:
|
||||
break
|
||||
cur = nxt_cur
|
||||
return level
|
||||
# ============================================================
|
||||
# _is_zero_int_literal - 判断 AST 节点是否为整数字面量 0
|
||||
|
||||
@@ -95,7 +95,8 @@ class ExprGenConst(ExprGenBase.ExprGenBase):
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
trans: HT.Translator | t.CPtr = None,
|
||||
target_ty: llvmlite.LLVMType | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译常量(int/str/bool)"""
|
||||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
|
||||
if cn is None:
|
||||
@@ -112,7 +113,27 @@ class ExprGenConst(ExprGenBase.ExprGenBase):
|
||||
double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
|
||||
return llvmlite.ConstFloat(pool, double_ty, cn.float_val)
|
||||
elif cn.const_kind == ast.CONST_CHAR:
|
||||
# 单引号单字符 → i32 值(字符 ASCII 码),coerce_to_type 会 trunc 为 i8
|
||||
# 单引号单字符字面量:默认按字符值(i32,coerce_to_type 截断为 i8)。
|
||||
# 但当目标类型是指针(str/bytes/t.CPtr 等)时,对齐 TPC 引号推断
|
||||
# (HandlesExpr:"目标是 ptr 但值是 char → 走字符串路径"):物化为
|
||||
# 1 字符字符串。否则 coerce inttoptr 把字符值当指针(如 '"'=0x22),
|
||||
# 运行期 strlen 访问低地址 → ASan 崩溃(二代编 StringTest PyI 生成根因)。
|
||||
# 1a 阶段(declare_only=1)不 LoadDepVpi(vpi 未预生成)→ 依赖函数
|
||||
# found_func=None → translate_call 缺省参数补全不生效 → translate_value
|
||||
# 调用参数数 < define(如 target_ty 缺省)→ x64 ABI 被调方读第 9 参
|
||||
# 栈槽残留垃圾(0x4 等)。declare_only 不产出 IR,target_ty 无用,
|
||||
# 未对齐(8 对齐失败)即视为垃圾跳过,避免 is_ptr_type 解引用崩溃
|
||||
# (SlotsBugTest 1a string.vp 崩溃根因;1b found_func 非 None 正常填充)。
|
||||
if target_ty is not None and (t.CUInt64T(target_ty) & 7) == 0 \
|
||||
and self.is_ptr_type(target_ty) != 0:
|
||||
cbuf: bytes = stdlib.malloc(2)
|
||||
if cbuf is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
cbuf[0] = t.CChar(cn.int_val)
|
||||
cbuf[1] = '\0'
|
||||
r_cs: llvmlite.Value | t.CPtr = self.create_global_string(builder, pool, mod, cbuf, trans)
|
||||
stdlib.free(cbuf)
|
||||
return r_cs
|
||||
cv: t.CInt64T = cn.int_val
|
||||
return llvmlite.const_int32(pool, cv)
|
||||
elif cn.const_kind == ast.CONST_STR:
|
||||
|
||||
@@ -79,13 +79,38 @@ class ExprGenMixin(ExprGenBase.ExprGenBase):
|
||||
node: ast.AST | t.CPtr,
|
||||
funcs_ptr: t.CPtr = None,
|
||||
func_count: int = 0,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
trans: HT.Translator | t.CPtr = None,
|
||||
target_ty: llvmlite.LLVMType | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译值表达式为 LLVM Value(深度守卫包装器,原逻辑见 _translate_value_impl)
|
||||
|
||||
target_ty: 目标类型上下文(如调用形参类型/赋值目标类型),用于单引号
|
||||
单字符字面量(CONST_CHAR)在字符串目标下物化为 1 字符字符串(对齐 TPC)。
|
||||
"""
|
||||
if trans is not None:
|
||||
if trans.TranslateDepth >= HT.TRANSLATE_MAX_DEPTH:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
node, "表达式翻译嵌套过深(疑似 AST 自引用环或翻译 bug)", "RecursionError")
|
||||
trans.TranslateDepth += 1
|
||||
rv: llvmlite.Value | t.CPtr = self._translate_value_impl(
|
||||
builder, pool, mod, node, funcs_ptr, func_count, trans, target_ty)
|
||||
if trans is not None:
|
||||
trans.TranslateDepth -= 1
|
||||
return rv
|
||||
|
||||
def _translate_value_impl(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
funcs_ptr: t.CPtr = None,
|
||||
func_count: int = 0,
|
||||
trans: HT.Translator | t.CPtr = None,
|
||||
target_ty: llvmlite.LLVMType | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译值表达式为 LLVM Value"""
|
||||
if node is None:
|
||||
return None
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Constant:
|
||||
rv: llvmlite.Value | t.CPtr = self.Gen.ExprGenConst.translate_constant(builder, pool, mod, node, trans)
|
||||
rv: llvmlite.Value | t.CPtr = self.Gen.ExprGenConst.translate_constant(builder, pool, mod, node, trans, target_ty)
|
||||
return rv
|
||||
elif k == ast.ASTKind.Name:
|
||||
return self.Gen.ExprGenName.translate_name_value(builder, pool, node, trans)
|
||||
|
||||
+1564
-1173
File diff suppressed because it is too large.
Load diff
@@ -37,6 +37,12 @@ MAX_MATCH_CASES: t.CDefine = 32
|
||||
# 作用域种类常量(与 HandlesVar 的 Scope.Kind 区分,原 HandlesMatch.SCOPE_MATCH)
|
||||
SCOPE_MATCH: t.CDefine = 6
|
||||
|
||||
# match 翻译最大递归深度(match → case body → translate_value → 嵌套 match)。
|
||||
# AST 自引用环/翻译 bug 可致无限递归 → ASan stack-overflow(崩溃点实测为
|
||||
# translate_match 内 subject kind() 虚调用,栈 2MB 耗尽)。入口计数出口递减,
|
||||
# 超限即 fail-fast(对齐 TypeGenResolve 深度守卫,防栈溢出)。
|
||||
MATCH_TRANSLATE_MAX_DEPTH: t.CDefine = 64
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class MatchGenMixin:
|
||||
@@ -86,6 +92,19 @@ class MatchGenMixin:
|
||||
# ============================================================
|
||||
def translate_match(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""match 语句翻译主入口(深度守卫包装器,原逻辑见 _translate_match_impl)"""
|
||||
if trans is not None:
|
||||
if trans.MatchTranslateDepth >= MATCH_TRANSLATE_MAX_DEPTH:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
node, "match 翻译嵌套过深(疑似 AST 自引用环或翻译 bug)", "RecursionError")
|
||||
trans.MatchTranslateDepth += 1
|
||||
mret: int = self._translate_match_impl(trans, node)
|
||||
if trans is not None:
|
||||
trans.MatchTranslateDepth -= 1
|
||||
return mret
|
||||
|
||||
def _translate_match_impl(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
if node is None:
|
||||
return 0
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
@@ -365,17 +384,15 @@ class MatchGenMixin:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError")
|
||||
case_count: t.CSizeT = len(cases_list)
|
||||
|
||||
# [MATCHDBG] 临时诊断:match 元信息(对比崩溃对应文件/语句;用后移除)
|
||||
stdio.printf("[MATCHDBG] renum_match node=%llx renum=%s subject=%llx cases=%llx count=%zu\n",
|
||||
t.CUInt64T(node), renum_name, t.CUInt64T(subject_ptr),
|
||||
t.CUInt64T(cases_list), case_count)
|
||||
|
||||
# BB 指针数组、case 值指针数组、default 标记数组、nobreak 标记数组
|
||||
bb_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
|
||||
cv_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
|
||||
def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
|
||||
nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES)
|
||||
if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None:
|
||||
# pass1 缓存的 mc 指针数组(pass2 复用,避免重索引)
|
||||
mc_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
|
||||
if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None \
|
||||
or mc_arr is None:
|
||||
# fail-fast: match 分派数组分配失败
|
||||
self.Gen.TypeGenErr.fatal_error(node, "match 分派数组分配失败", "TypeError")
|
||||
|
||||
@@ -454,23 +471,14 @@ class MatchGenMixin:
|
||||
body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children
|
||||
nb: int = self._has_no_break(body_list)
|
||||
|
||||
# [MATCHDBG] 临时诊断:第一遍记录 case 快照(对比第二遍,定位列表破坏点;用后移除)
|
||||
dbg_bl_len: t.CInt = -1
|
||||
dbg_first0: t.CSizeT = 0
|
||||
if body_list is not None:
|
||||
dbg_bl_len = t.CInt(len(body_list))
|
||||
if dbg_bl_len > 0:
|
||||
dbg_first0 = t.CUInt64T(body_list.get(0))
|
||||
stdio.printf("[MATCHDBG] pass1 i=%d mc=%llx pat=%llx children=%llx len=%d data0=%llx\n",
|
||||
i, t.CUInt64T(mc), t.CUInt64T(pat),
|
||||
t.CUInt64T(body_list), dbg_bl_len, dbg_first0)
|
||||
|
||||
# 存入数组
|
||||
if collected < MAX_MATCH_CASES:
|
||||
bb_arr[collected] = t.CSizeT(bb)
|
||||
cv_arr[collected] = t.CSizeT(cv)
|
||||
def_arr[collected] = is_def
|
||||
nb_arr[collected] = nb
|
||||
# 缓存 mc 指针(pass2 复用,避免重索引)
|
||||
mc_arr[collected] = t.CSizeT(mc)
|
||||
collected = collected + 1
|
||||
|
||||
# 构建 SwitchCase 链表(非 default case 且有值)
|
||||
@@ -502,11 +510,12 @@ class MatchGenMixin:
|
||||
# 7. 第二遍:翻译每个 case body
|
||||
i = 0
|
||||
while i < collected:
|
||||
case_node: ast.AST | t.CPtr = cases_list.get(i)
|
||||
if case_node is None:
|
||||
# pass2 用 pass1 缓存的 mc(避免重索引错位)
|
||||
mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(
|
||||
t.CVoid(mc_arr[i], t.CPtr))
|
||||
if mc is None:
|
||||
i = i + 1
|
||||
continue
|
||||
mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node)
|
||||
pat: ast.AST | t.CPtr = mc.pattern
|
||||
|
||||
# 取 BB
|
||||
@@ -540,11 +549,11 @@ class MatchGenMixin:
|
||||
bc: t.CSizeT = len(body_list)
|
||||
bi: int = 0
|
||||
while bi < bc:
|
||||
# 用 list.get() 读取元素值(已验证编译为 8 字节加载,与
|
||||
# pass1 的 cases_list.get(i) 同型同码)。切勿改为
|
||||
# `bl_data + bi*8` 裸地址:那会把数组槽地址当节点传入
|
||||
# translate_stmt,虚调用跳进 vtable 表 → DEP 崩溃。
|
||||
stmt: ast.AST | t.CPtr = body_list.get(bi)
|
||||
# [MATCHDBG] 临时诊断:第二遍逐条打印(对比 pass1 快照;用后移除)
|
||||
stdio.printf("[MATCHDBG] pass2 i=%d bi=%d bc=%zu mc=%llx children=%llx stmt=%llx\n",
|
||||
i, bi, bc, t.CUInt64T(mc),
|
||||
t.CUInt64T(body_list), t.CUInt64T(stmt))
|
||||
if stmt is not None:
|
||||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||||
bi = bi + 1
|
||||
@@ -582,13 +591,17 @@ class MatchGenMixin:
|
||||
dmc: ast.MatchCase | t.CPtr = (
|
||||
ast.MatchCase | t.CPtr)(dcase)
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
# dbody 预声明+重赋值会使 .get 误分派成 list[int].get
|
||||
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,
|
||||
# gen1 IR 证据)。用 dbody2 内联声明接收者遍历(对齐
|
||||
# Converter arg_defaults 内联声明规避模式)。
|
||||
dbody2: list[ast.AST | t.CPtr] | t.CPtr = dmc.children
|
||||
dbody = dbody2
|
||||
if dbody is not None:
|
||||
dn: t.CSizeT = len(dbody)
|
||||
if dbody2 is not None:
|
||||
dn: t.CSizeT = len(dbody2)
|
||||
dj: int = 0
|
||||
while dj < dn:
|
||||
stmt: ast.AST | t.CPtr = dbody.get(dj)
|
||||
stmt: ast.AST | t.CPtr = dbody2.get(dj)
|
||||
if stmt is not None:
|
||||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||||
dj = dj + 1
|
||||
@@ -801,7 +814,10 @@ class MatchGenMixin:
|
||||
if subj_vals is None:
|
||||
return 0
|
||||
for ei in range(ecount):
|
||||
elt: ast.AST | t.CPtr = elts.get(ei)
|
||||
# elts 预声明+重赋值会把 .get 误分派成 list[int].get(i32 截断);
|
||||
# 用内联别名接收者规避(对齐 Converter arg_defaults 内联模式)
|
||||
elts_inl: list[ast.AST | t.CPtr] | t.CPtr = elts
|
||||
elt: ast.AST | t.CPtr = elts_inl.get(ei)
|
||||
sv: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, trans.Module, elt,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
@@ -925,7 +941,10 @@ class MatchGenMixin:
|
||||
cond = llvmlite.const_int(pool, 1, 0)
|
||||
else:
|
||||
for pi in range(ecount):
|
||||
pat1: ast.AST | t.CPtr = pats.get(pi)
|
||||
# pats 预声明+重赋值会把 .get 误分派成 list[int].get(i32 截断);
|
||||
# 用内联别名接收者规避(对齐 Converter arg_defaults 内联模式)
|
||||
pats_inl: list[ast.AST | t.CPtr] | t.CPtr = pats
|
||||
pat1: ast.AST | t.CPtr = pats_inl.get(pi)
|
||||
if pat1 is None:
|
||||
continue
|
||||
pk1: int = pat1.kind()
|
||||
@@ -1064,13 +1083,17 @@ class MatchGenMixin:
|
||||
dmc: ast.MatchCase | t.CPtr = (
|
||||
ast.MatchCase | t.CPtr)(dnode)
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
# dbody 预声明+重赋值会使 .get 误分派成 list[int].get
|
||||
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,
|
||||
# gen1 IR 证据)。用 dbody2 内联声明接收者遍历(对齐
|
||||
# Converter arg_defaults 内联声明规避模式)。
|
||||
dbody2: list[ast.AST | t.CPtr] | t.CPtr = dmc.children
|
||||
dbody = dbody2
|
||||
if dbody is not None:
|
||||
dn: t.CSizeT = len(dbody)
|
||||
if dbody2 is not None:
|
||||
dn: t.CSizeT = len(dbody2)
|
||||
dj: int = 0
|
||||
while dj < dn:
|
||||
stmt: ast.AST | t.CPtr = dbody.get(dj)
|
||||
stmt: ast.AST | t.CPtr = dbody2.get(dj)
|
||||
if stmt is not None:
|
||||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||||
dj = dj + 1
|
||||
@@ -1301,13 +1324,17 @@ class MatchGenMixin:
|
||||
dmc: ast.MatchCase | t.CPtr = (
|
||||
ast.MatchCase | t.CPtr)(dcase)
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
# dbody 预声明+重赋值会使 .get 误分派成 list[int].get
|
||||
# (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,
|
||||
# gen1 IR 证据)。用 dbody2 内联声明接收者遍历(对齐
|
||||
# Converter arg_defaults 内联声明规避模式)。
|
||||
dbody2: list[ast.AST | t.CPtr] | t.CPtr = dmc.children
|
||||
dbody = dbody2
|
||||
if dbody is not None:
|
||||
dn: t.CSizeT = len(dbody)
|
||||
if dbody2 is not None:
|
||||
dn: t.CSizeT = len(dbody2)
|
||||
dj: int = 0
|
||||
while dj < dn:
|
||||
stmt: ast.AST | t.CPtr = dbody.get(dj)
|
||||
stmt: ast.AST | t.CPtr = dbody2.get(dj)
|
||||
if stmt is not None:
|
||||
self.Gen.StmtGen.translate_stmt(trans, stmt)
|
||||
dj = dj + 1
|
||||
|
||||
@@ -136,11 +136,98 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""预扫描语句中的 AnnAssign,提前创建 alloca
|
||||
|
||||
返回新增的变量数
|
||||
递归分支/循环/异常体:if/else/for/while/try 分支内的 AnnAssign 局部
|
||||
也必须提前注册到 entry alloca——否则闭包隐式捕获扫描(step 8c)
|
||||
在分支局部未注册时会误判为外层函数捕获(Terminal _build_path 的
|
||||
i/j/cwd_len 被当 nonlocal 捕获 → 循环计数器走 env/父函数存储 →
|
||||
跨函数 SSA 错乱,llc "instruction expected to be numbered")。
|
||||
|
||||
返回新增的变量数(调用方均忽略返回值)。
|
||||
"""
|
||||
if node is None:
|
||||
return 0
|
||||
return self.Gen.AssignGen.translate_annassign_prescan(trans, node)
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.AnnAssign:
|
||||
return self.Gen.AssignGen.translate_annassign_prescan(trans, node)
|
||||
if k == ast.ASTKind.If:
|
||||
ifn: ast.If | t.CPtr = (ast.If | t.CPtr)(node)
|
||||
if ifn.children is not None:
|
||||
bn_pre_i: t.CSizeT = len(ifn.children)
|
||||
for bi_pre_i in range(bn_pre_i):
|
||||
self.pre_scan_allocas(trans, ifn.children.get(bi_pre_i))
|
||||
if ifn.orelse is not None:
|
||||
bn_pre_e: t.CSizeT = len(ifn.orelse)
|
||||
for bi_pre_e in range(bn_pre_e):
|
||||
self.pre_scan_allocas(trans, ifn.orelse.get(bi_pre_e))
|
||||
return 0
|
||||
if k == ast.ASTKind.For:
|
||||
for_n: ast.For | t.CPtr = (ast.For | t.CPtr)(node)
|
||||
if for_n.children is not None:
|
||||
bn_pre_f: t.CSizeT = len(for_n.children)
|
||||
for bi_pre_f in range(bn_pre_f):
|
||||
self.pre_scan_allocas(trans, for_n.children.get(bi_pre_f))
|
||||
if for_n.orelse is not None:
|
||||
bn_pre_fe: t.CSizeT = len(for_n.orelse)
|
||||
for bi_pre_fe in range(bn_pre_fe):
|
||||
self.pre_scan_allocas(trans, for_n.orelse.get(bi_pre_fe))
|
||||
return 0
|
||||
if k == ast.ASTKind.While:
|
||||
wh_n: ast.While | t.CPtr = (ast.While | t.CPtr)(node)
|
||||
if wh_n.children is not None:
|
||||
bn_pre_w: t.CSizeT = len(wh_n.children)
|
||||
for bi_pre_w in range(bn_pre_w):
|
||||
self.pre_scan_allocas(trans, wh_n.children.get(bi_pre_w))
|
||||
if wh_n.orelse is not None:
|
||||
bn_pre_we: t.CSizeT = len(wh_n.orelse)
|
||||
for bi_pre_we in range(bn_pre_we):
|
||||
self.pre_scan_allocas(trans, wh_n.orelse.get(bi_pre_we))
|
||||
return 0
|
||||
if k == ast.ASTKind.Try:
|
||||
tr_n: ast.Try | t.CPtr = (ast.Try | t.CPtr)(node)
|
||||
if tr_n.children is not None:
|
||||
bn_pre_t: t.CSizeT = len(tr_n.children)
|
||||
for bi_pre_t in range(bn_pre_t):
|
||||
self.pre_scan_allocas(trans, tr_n.children.get(bi_pre_t))
|
||||
if tr_n.handlers is not None:
|
||||
bn_pre_th: t.CSizeT = len(tr_n.handlers)
|
||||
for bi_pre_th in range(bn_pre_th):
|
||||
eh_pre: ast.AST | t.CPtr = tr_n.handlers.get(bi_pre_th)
|
||||
if eh_pre is not None and eh_pre.kind() == ast.ASTKind.ExceptHandler:
|
||||
ehc_pre: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)(eh_pre)
|
||||
if ehc_pre.children is not None:
|
||||
bn_pre_ehb: t.CSizeT = len(ehc_pre.children)
|
||||
for bi_pre_ehb in range(bn_pre_ehb):
|
||||
self.pre_scan_allocas(trans, ehc_pre.children.get(bi_pre_ehb))
|
||||
if tr_n.orelse is not None:
|
||||
bn_pre_to: t.CSizeT = len(tr_n.orelse)
|
||||
for bi_pre_to in range(bn_pre_to):
|
||||
self.pre_scan_allocas(trans, tr_n.orelse.get(bi_pre_to))
|
||||
if tr_n.finalbody is not None:
|
||||
bn_pre_tf: t.CSizeT = len(tr_n.finalbody)
|
||||
for bi_pre_tf in range(bn_pre_tf):
|
||||
self.pre_scan_allocas(trans, tr_n.finalbody.get(bi_pre_tf))
|
||||
return 0
|
||||
if k == ast.ASTKind.With:
|
||||
wth: ast.With | t.CPtr = (ast.With | t.CPtr)(node)
|
||||
if wth.children is not None:
|
||||
bn_pre_wb: t.CSizeT = len(wth.children)
|
||||
for bi_pre_wb in range(bn_pre_wb):
|
||||
self.pre_scan_allocas(trans, wth.children.get(bi_pre_wb))
|
||||
return 0
|
||||
if k == ast.ASTKind.Match:
|
||||
mt_n: ast.Match | t.CPtr = (ast.Match | t.CPtr)(node)
|
||||
if mt_n.cases is not None:
|
||||
bn_pre_mc: t.CSizeT = len(mt_n.cases)
|
||||
for bi_pre_mc in range(bn_pre_mc):
|
||||
mc_pre: ast.AST | t.CPtr = mt_n.cases.get(bi_pre_mc)
|
||||
if mc_pre is not None and mc_pre.kind() == ast.ASTKind.MatchCase:
|
||||
mcc_pre: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(mc_pre)
|
||||
if mcc_pre.children is not None:
|
||||
bn_pre_mcb: t.CSizeT = len(mcc_pre.children)
|
||||
for bi_pre_mcb in range(bn_pre_mcb):
|
||||
self.pre_scan_allocas(trans, mcc_pre.children.get(bi_pre_mcb))
|
||||
return 0
|
||||
return 0
|
||||
|
||||
def pre_scan_scope_decls(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
|
||||
@@ -41,6 +41,19 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
|
||||
def translate_stmt(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译单条语句,返回新增的变量数(深度守卫包装器,原逻辑见 _translate_stmt_impl)"""
|
||||
if trans is not None:
|
||||
if trans.TranslateDepth >= HT.TRANSLATE_MAX_DEPTH:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
node, "语句翻译嵌套过深(疑似 AST 自引用环或翻译 bug)", "RecursionError")
|
||||
trans.TranslateDepth += 1
|
||||
mret: int = self._translate_stmt_impl(trans, node)
|
||||
if trans is not None:
|
||||
trans.TranslateDepth -= 1
|
||||
return mret
|
||||
|
||||
def _translate_stmt_impl(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译单条语句,返回新增的变量数"""
|
||||
if node is None:
|
||||
return 0
|
||||
|
||||
@@ -280,16 +280,24 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
def _eval_const_int_expr(self, node: ast.AST | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr = None,
|
||||
from_imports: str = None,
|
||||
imported_modules: str = None) -> int:
|
||||
imported_modules: str = None,
|
||||
depth: int = 0) -> int:
|
||||
"""递归计算常量整数表达式
|
||||
|
||||
pool/from_imports/imported_modules:跨模块 CDefine 查找上下文
|
||||
(t.CArray count 引用依赖模块的 CDefine,如 SHA512_BLOCK_LEN 定义在
|
||||
hashlib/__sha512.vp,本地 CDefine 表每模块清空,需跨模块回退查找)。
|
||||
depth:递归深度守卫(防御 AST 损坏成自引用环导致的无限递归——
|
||||
本函数被 resolve_annotation_type 的 t.CArray count 解析调用,其内部
|
||||
BinOp 自递归不经过 resolve_annotation_type 的 depth 守卫)。
|
||||
"""
|
||||
if node is None:
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
# 递归深度守卫:BinOp 左右子树成环时无限递归直至栈耗尽。
|
||||
# fail-fast 终止(fatal_type_error → sys.exit(1)),不静默回落。
|
||||
if depth > 64:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "常量表达式递归过深(AST 环或嵌套超过 64 层)")
|
||||
k: int = node.kind()
|
||||
|
||||
# Constant: 整数字面量
|
||||
@@ -369,11 +377,11 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||||
# 递归计算左操作数
|
||||
lv: int = self._eval_const_int_expr(bop.left, pool, from_imports, imported_modules)
|
||||
lv: int = self._eval_const_int_expr(bop.left, pool, from_imports, imported_modules, depth + 1)
|
||||
if self.ConstEvalOk == 0:
|
||||
return 0
|
||||
# 递归计算右操作数
|
||||
rv: int = self._eval_const_int_expr(bop.right, pool, from_imports, imported_modules)
|
||||
rv: int = self._eval_const_int_expr(bop.right, pool, from_imports, imported_modules, depth + 1)
|
||||
if self.ConstEvalOk == 0:
|
||||
return 0
|
||||
# 根据运算符执行计算
|
||||
|
||||
@@ -205,12 +205,18 @@ class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
ret_node_cr: ast.AST | t.CPtr = tp_cr.elts.get(1)
|
||||
if ret_node_cr is None:
|
||||
return None
|
||||
return self.Gen.TypeGenResolve.resolve_annotation_type(pool, ret_node_cr, imported_modules, from_imports, trans)
|
||||
return self.Gen.TypeGenResolve.resolve_annotation_type(pool, ret_node_cr, imported_modules, from_imports, trans, 0)
|
||||
def has_decorator_marker(self, node: ast.AST | t.CPtr,
|
||||
marker_name: str) -> int:
|
||||
marker_name: str,
|
||||
depth: int = 0) -> int:
|
||||
"""检测类型注解中是否包含指定的装饰器标记"""
|
||||
if node is None or marker_name is None:
|
||||
return 0
|
||||
# 递归深度守卫:vpi stub 注入时对每个函数 returns 调用本函数,
|
||||
# vpi tree 深层节点可能被覆盖损坏成回指环(VpiReader L810-813),
|
||||
# BinOp 递归无守卫会无限递归直至栈耗尽。fail-fast 终止。
|
||||
if depth > 128:
|
||||
self.fatal_type_error(node, "装饰器标记检测递归过深(AST 环或嵌套超过 128 层)")
|
||||
|
||||
k: int = node.kind()
|
||||
|
||||
@@ -225,9 +231,9 @@ class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
# BinOp 节点: int | t.CExtern(递归检测左右子节点)
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||||
if self.has_decorator_marker(bop.left, marker_name) != 0:
|
||||
if self.has_decorator_marker(bop.left, marker_name, depth + 1) != 0:
|
||||
return 1
|
||||
if self.has_decorator_marker(bop.right, marker_name) != 0:
|
||||
if self.has_decorator_marker(bop.right, marker_name, depth + 1) != 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
|
||||
@@ -70,6 +71,30 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
string.strcat(buf, at_attr_v)
|
||||
return buf
|
||||
return at_attr_v
|
||||
# Subscript: 构造 "value[slice]" 格式(slice 递归,List/Tuple 保留完整下标)
|
||||
# 如 t.Callable[[t.CInt], t.CInt] → "t.Callable[[t.CInt], t.CInt]"。
|
||||
# CTypedef 值提取(_register_ctypedef_from_annassign → lookup → _parse_type_string
|
||||
# 重建)需要完整类型表达式字符串,slice 不能丢(此前不支持 Subscript → 返回
|
||||
# None → 注册失败 → 同 vpi 后续裸类名 lookup_ctypedef 失败 fail-fast,
|
||||
# VKernel idt.vp irq_handler_t 根因)。
|
||||
if k == ast.ASTKind.Subscript:
|
||||
sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||||
val_s: str = self._get_type_name_from_annotation(pool, sub_s.value)
|
||||
if val_s is None:
|
||||
return None
|
||||
slice_s: str = self._subscript_slice_to_str(pool, sub_s.slice)
|
||||
if slice_s is None:
|
||||
return None
|
||||
total_s: t.CSizeT = string.strlen(val_s) + 1 + string.strlen(slice_s) + 2
|
||||
buf_s: str = pool.alloc(total_s)
|
||||
if buf_s is not None:
|
||||
buf_s[0] = '\0'
|
||||
string.strcat(buf_s, val_s)
|
||||
string.strcat(buf_s, "[")
|
||||
string.strcat(buf_s, slice_s)
|
||||
string.strcat(buf_s, "]")
|
||||
return buf_s
|
||||
return None
|
||||
# BinOp (BitOr): 构造 "left|right" 格式
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||||
@@ -87,6 +112,70 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
return buf2
|
||||
return None
|
||||
return None
|
||||
def _subscript_slice_to_str(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> str:
|
||||
"""Subscript slice 节点转类型字符串(递归,支持 Name/Attribute/BinOp/Constant/List/Tuple/Subscript)"""
|
||||
if node is None:
|
||||
return None
|
||||
k2: int = node.kind()
|
||||
# Name / Attribute / BinOp / 嵌套 Subscript:复用类型名提取
|
||||
if k2 == ast.ASTKind.Name or k2 == ast.ASTKind.Attribute \
|
||||
or k2 == ast.ASTKind.BinOp or k2 == ast.ASTKind.Subscript:
|
||||
return self._get_type_name_from_annotation(pool, node)
|
||||
# Constant:数值/字符串字面量(t.CArray[elem, 104] 的 count 等)
|
||||
if k2 == ast.ASTKind.Constant:
|
||||
cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
|
||||
if cn2.const_kind == ast.CONST_INT:
|
||||
buf2: str = pool.alloc(24)
|
||||
if buf2 is not None:
|
||||
viperlib.snprintf(buf2, 24, "%lld", t.CInt64T(cn2.int_val))
|
||||
return buf2
|
||||
if cn2.const_kind == ast.CONST_STR and cn2.str_val is not None:
|
||||
return cn2.str_val
|
||||
return None
|
||||
# List:Callable 参数列表([[A], B]),元素递归,逗号连接
|
||||
if k2 == ast.ASTKind.List:
|
||||
lst: ast.List | t.CPtr = (ast.List | t.CPtr)(node)
|
||||
return self._list_elts_to_type_str(pool, lst.elts, "[", "]")
|
||||
# Tuple:t.CArray[elem, N] 等双参形式。注意 TPV parser 把 Subscript 内
|
||||
# 带逗号的 slice 统一打包为 Tuple("a[x, y]" 语法),故 slice 在 Subscript
|
||||
# 内**不带括号**输出("x, y"),否则 "t.Callable[([t.CInt], t.CInt)]"
|
||||
# 的显式括号 Tuple slice 会让 ast.parse_expression 解析失败。
|
||||
if k2 == ast.ASTKind.Tuple:
|
||||
tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node)
|
||||
return self._list_elts_to_type_str(pool, tup.elts, "", "")
|
||||
return None
|
||||
def _list_elts_to_type_str(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
elts: list[ast.AST | t.CPtr] | t.CPtr,
|
||||
open_ch: str, close_ch: str) -> str:
|
||||
"""元素列表转逗号分隔字符串(List/Tuple 共用),包上 open/close 括号"""
|
||||
if elts is None or pool is None:
|
||||
return None
|
||||
buf3: str = pool.alloc(1024)
|
||||
if buf3 is None:
|
||||
return None
|
||||
buf3[0] = '\0'
|
||||
n3: t.CSizeT = len(elts)
|
||||
for i3 in range(n3):
|
||||
e3: ast.AST | t.CPtr = elts.get(i3)
|
||||
if e3 is None:
|
||||
continue
|
||||
es3: str = self._subscript_slice_to_str(pool, e3)
|
||||
if es3 is None:
|
||||
continue
|
||||
if string.strlen(buf3) > 0 and string.strlen(buf3) + 2 < 1024:
|
||||
string.strcat(buf3, ", ")
|
||||
if string.strlen(buf3) + string.strlen(es3) < 1024:
|
||||
string.strcat(buf3, es3)
|
||||
total3: t.CSizeT = string.strlen(buf3) + 2 + 2
|
||||
buf4: str = pool.alloc(total3)
|
||||
if buf4 is None:
|
||||
return None
|
||||
buf4[0] = '\0'
|
||||
string.strcat(buf4, open_ch)
|
||||
string.strcat(buf4, buf3)
|
||||
string.strcat(buf4, close_ch)
|
||||
return buf4
|
||||
def _is_sha1_prefixed(self, s: str) -> int:
|
||||
"""判断 s 是否已是 "{16位hex}." 前缀(已规范化,防二次前缀)
|
||||
|
||||
@@ -273,6 +362,41 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
return ast.BinOp(pool, left_node, ast.OpKind.BitOr, right_node)
|
||||
return None
|
||||
|
||||
# 检查是否包含 [ (Subscript):t.Callable[[t.CInt], t.CInt] 等。
|
||||
# 必须在 . 检查之前("t.Callable[...]" 含 '.',但本质是 Subscript,
|
||||
# 若先走 Attribute 会把 "Callable[[t.CInt], t.CInt]" 当 attr → resolve
|
||||
# 失败)。用 ast.parse_expression 完整解析(支持 List/Tuple 字面量
|
||||
# slice)。CTypedef 值如 "t.Callable[[t.CInt], t.CInt]"(irq_handler_t)
|
||||
# 与返回注解 "t.CArray[t.CUInt8T, 16]" 依赖此路径。
|
||||
bracket_idx: t.CSizeT = seg_len
|
||||
bi: t.CSizeT = 0
|
||||
while bi < seg_len:
|
||||
if type_str[bi] == '[':
|
||||
bracket_idx = bi
|
||||
break
|
||||
bi += 1
|
||||
if bracket_idx < seg_len:
|
||||
# 优先 ast.parse_expression(单表达式入口)
|
||||
expr_node: ast.AST | t.CPtr = ast.parse_expression(type_str, pool)
|
||||
if expr_node is not None:
|
||||
expr_body: ast.AST | t.CPtr = expr_node.body
|
||||
if expr_body is not None:
|
||||
return expr_body
|
||||
# 备选:ast.parse 文件级(TPV parser 的 _parse_test 单表达式入口对
|
||||
# 复杂 slice 如 "t.Callable[[t.CInt], t.CInt]" 解析失败,但文件级
|
||||
# _parse_expr_stmt 可解析裸表达式语句——vpi 同语法已验证
|
||||
# parse_tokens 成功,故此处用文件级 parse 兜底)
|
||||
tree_s: ast.AST | t.CPtr = ast.parse(type_str, pool)
|
||||
if tree_s is not None:
|
||||
ch_s: list[ast.AST | t.CPtr] | t.CPtr = tree_s.children
|
||||
if ch_s is not None and len(ch_s) > 0:
|
||||
st0: ast.AST | t.CPtr = ch_s.get(0)
|
||||
if st0 is not None and st0.kind() == ast.ASTKind.Expr:
|
||||
ex0: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(st0)
|
||||
if ex0.value is not None:
|
||||
return ex0.value
|
||||
return None
|
||||
|
||||
# 检查是否包含 . (Attribute):只在有效段 [0, seg_len) 内查找
|
||||
dot_idx: t.CSizeT = seg_len
|
||||
di: t.CSizeT = 0
|
||||
@@ -828,14 +952,28 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
val_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||||
if val_nm2.id is not None and string.strcmp(val_nm2.id, "t") == 0:
|
||||
return at.attr
|
||||
# import 别名还原:val_nm2.id 可能是 "import X as Y" 的别名 Y
|
||||
# (如 "import fat32_types as types" → types.fileinfo 实为
|
||||
# fat32_types.fileinfo)。还原为模块真名后,AnnotClassName 存
|
||||
# 真限定名,跨模块同名类查找可经 StubMergerStore 按模块归属解析。
|
||||
real_mod2: str = val_nm2.id
|
||||
alias_mod2: str = None
|
||||
if from_imports is not None:
|
||||
alias_mod2 = StubMergerStore.LookupModNameByAlias(from_imports, val_nm2.id)
|
||||
if alias_mod2 is not None:
|
||||
real_mod2 = alias_mod2
|
||||
# 返回模块限定名 "module.Class"(如 "memhub.MemBuddy")
|
||||
mod_qual_buf: str = stdlib.malloc(
|
||||
string.strlen(val_nm2.id) + string.strlen(at.attr) + 2)
|
||||
string.strlen(real_mod2) + string.strlen(at.attr) + 2)
|
||||
if mod_qual_buf is not None:
|
||||
viperlib.snprintf(mod_qual_buf,
|
||||
string.strlen(val_nm2.id) + string.strlen(at.attr) + 2,
|
||||
"%s.%s", val_nm2.id, at.attr)
|
||||
string.strlen(real_mod2) + string.strlen(at.attr) + 2,
|
||||
"%s.%s", real_mod2, at.attr)
|
||||
if alias_mod2 is not None:
|
||||
stdlib.free(alias_mod2)
|
||||
return mod_qual_buf
|
||||
if alias_mod2 is not None:
|
||||
stdlib.free(alias_mod2)
|
||||
return at.attr
|
||||
|
||||
# BinOp 节点: 联合类型 A | B
|
||||
@@ -928,7 +1066,8 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
gen_cls_name: str,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
imported_modules: str,
|
||||
from_imports: str) -> llvmlite.LLVMType | t.CPtr:
|
||||
from_imports: str,
|
||||
depth: int = 0) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""解析泛型类类型注解(特化或查找已注册结构体),失败返回 None"""
|
||||
if pool is None or sub is None or gen_cls_name is None:
|
||||
return None
|
||||
@@ -960,7 +1099,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if tup_elt is None:
|
||||
continue
|
||||
tup_ety: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, tup_elt, imported_modules, from_imports, trans)
|
||||
pool, tup_elt, imported_modules, from_imports, trans, depth + 1)
|
||||
if tup_ety is None:
|
||||
return None
|
||||
tup_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, tup_ety)
|
||||
@@ -1060,7 +1199,8 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
node: ast.AST | t.CPtr,
|
||||
imported_modules: str,
|
||||
from_imports: str,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.LLVMType | t.CPtr:
|
||||
trans: HT.Translator | t.CPtr = None,
|
||||
depth: int = 0) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""解析类型注解节点为 LLVMType
|
||||
|
||||
Args:
|
||||
@@ -1069,9 +1209,16 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
imported_modules: 已导入模块名字符串(空格分隔)
|
||||
from_imports: from-import 映射字符串("name:module name:module" 格式)
|
||||
trans: 翻译器对象(可选,用于触发泛型特化)
|
||||
depth: 递归深度(防御 AST 损坏成自引用环导致的无限递归)
|
||||
"""
|
||||
if node is None:
|
||||
return None
|
||||
# 递归深度守卫:AST 损坏成自引用环(子节点回指祖先)时,无守卫的
|
||||
# BinOp/Subscript/Constant/Tuple 递归会无限加深直至栈耗尽(自举版
|
||||
# TransPyV.exe 编译 FuncTest 时 ASan stack-overflow 首选嫌疑)。超过
|
||||
# 128 层即 fail-fast 终止(fatal_type_error → sys.exit(1)),不静默兜底。
|
||||
if depth > 128:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "类型注解递归过深(AST 环或嵌套超过 128 层)")
|
||||
|
||||
k: int = node.kind()
|
||||
|
||||
@@ -1083,7 +1230,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if cn.const_kind == ast.CONST_STR and cn.str_val is not None:
|
||||
sub_node: ast.AST | t.CPtr = self._parse_type_string(pool, cn.str_val, ast.ASTCtx.Load)
|
||||
if sub_node is not None:
|
||||
return self.resolve_annotation_type(pool, sub_node, imported_modules, from_imports, trans)
|
||||
return self.resolve_annotation_type(pool, sub_node, imported_modules, from_imports, trans, depth + 1)
|
||||
return None
|
||||
|
||||
# Name 节点: str, int, bytes, from-import 名称, class 名称等
|
||||
@@ -1125,7 +1272,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# 用具体类型名递归解析(支持 BinOp/Attribute 类型实参)
|
||||
gp_sub_node: ast.AST | t.CPtr = self._parse_type_string(pool, gp_ta, nm.ctx)
|
||||
if gp_sub_node is not None:
|
||||
return self.resolve_annotation_type(pool, gp_sub_node, imported_modules, from_imports, trans)
|
||||
return self.resolve_annotation_type(pool, gp_sub_node, imported_modules, from_imports, trans, depth + 1)
|
||||
# str = bytes = str = i8*
|
||||
if string.strcmp(nm.id, "str") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
@@ -1189,7 +1336,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if inner_node is not None:
|
||||
self.Gen.TypeGenCType.CTypedefResolveDepth += 1
|
||||
inner_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, inner_node, imported_modules, from_imports, trans)
|
||||
pool, inner_node, imported_modules, from_imports, trans, depth + 1)
|
||||
self.Gen.TypeGenCType.CTypedefResolveDepth -= 1
|
||||
self.Gen.TypeGenCType._ctypedef_pop_visiting()
|
||||
if inner_ty is not None:
|
||||
@@ -1253,9 +1400,35 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
full_attr_ty = self.Gen.StructGen.get_struct_type(full_q)
|
||||
if full_attr_ty is not None:
|
||||
return full_attr_ty
|
||||
mod_struct_ty: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type(at.attr)
|
||||
if mod_struct_ty is not None:
|
||||
return mod_struct_ty
|
||||
# 跨模块限定名(Module.Class,Module 非 t/c/SHA1):按模块归属解析,
|
||||
# 禁止裸名回退抓跨模块同名类(根因:VKernel sched.Thread 被
|
||||
# includes/vthreading.vp 同名 Thread 顶掉 → 'tid' 字段缺失)。
|
||||
# 模块名经 StubMergerStore sha1 映射表解析为模块 sha1,再精确命中
|
||||
# "{sha1}.{Class}"(定义侧命名)或 name+sha1(vpi stub 注入)。
|
||||
if is_builtin_attr == 0:
|
||||
# 模块名 → sha1(精确/后缀/import 别名还原,统一经
|
||||
# StructGenMixin._resolve_module_sha1 逐级尝试)
|
||||
mod_sha1_v: str = self.Gen.StructGen._resolve_module_sha1(
|
||||
val_name.id, from_imports)
|
||||
if mod_sha1_v is not None:
|
||||
full_q_v: str = self._concat_sha1_class(pool, mod_sha1_v, at.attr)
|
||||
if full_q_v is not None:
|
||||
full_ty_v: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type(full_q_v)
|
||||
if full_ty_v is not None:
|
||||
return full_ty_v
|
||||
mod_entry_v: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module(at.attr, mod_sha1_v)
|
||||
if mod_entry_v is not None and mod_entry_v.Ty is not None:
|
||||
if mod_entry_v.HasNew != 0:
|
||||
return llvmlite.Ptr(pool, mod_entry_v.Ty)
|
||||
return mod_entry_v.Ty
|
||||
# 模块可解析但类未注册:不裸名回退(防跨库抓错),
|
||||
# 落到下方枚举/typedef 尝试;struct 缺失由调用侧暴露
|
||||
# 模块名未登记(未编译/未扫描):同样不裸名回退
|
||||
else:
|
||||
# t/c 内置库限定:裸名回退合法(内置类名无跨模块冲突)
|
||||
mod_struct_ty: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type(at.attr)
|
||||
if mod_struct_ty is not None:
|
||||
return mod_struct_ty
|
||||
# 模块限定枚举类型:Module.EnumClass(如 fat32_types.FRESULT,
|
||||
# t.CEnum 枚举类非结构体,get_struct_type 查不到)
|
||||
if self.Gen.StmtGenDecl.is_enum_class(at.attr) == 1:
|
||||
@@ -1274,7 +1447,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if mod_td_inner is not None:
|
||||
self.Gen.TypeGenCType.CTypedefResolveDepth += 1
|
||||
mod_td_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, mod_td_inner, imported_modules, from_imports, trans)
|
||||
pool, mod_td_inner, imported_modules, from_imports, trans, depth + 1)
|
||||
self.Gen.TypeGenCType.CTypedefResolveDepth -= 1
|
||||
self.Gen.TypeGenCType._ctypedef_pop_visiting()
|
||||
if mod_td_ty is not None:
|
||||
@@ -1305,7 +1478,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if nested_inner is not None:
|
||||
self.Gen.TypeGenCType.CTypedefResolveDepth += 1
|
||||
nested_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, nested_inner, imported_modules, from_imports, trans)
|
||||
pool, nested_inner, imported_modules, from_imports, trans, depth + 1)
|
||||
self.Gen.TypeGenCType.CTypedefResolveDepth -= 1
|
||||
self.Gen.TypeGenCType._ctypedef_pop_visiting()
|
||||
if nested_ty is not None:
|
||||
@@ -1354,7 +1527,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if other_is_cvoid != 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
other_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, other_node, imported_modules, from_imports, trans)
|
||||
pool, other_node, imported_modules, from_imports, trans, depth + 1)
|
||||
# 仅裸名(Name)场景验证解析结果必须是已注册 struct:
|
||||
# 损坏节点可能解析出基础类型垃圾(如 Int8 → Ptr(i8))。
|
||||
# Attribute 场景(Module.Class / t.XXX)resolve 结果直接可用
|
||||
@@ -1444,20 +1617,27 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
cptr_other = bop.left
|
||||
if cptr_sub_side is not None and cptr_other is not None:
|
||||
cptr_sub_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, cptr_sub_side, imported_modules, from_imports, trans)
|
||||
pool, cptr_sub_side, imported_modules, from_imports, trans, depth + 1)
|
||||
cptr_other_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, cptr_other, imported_modules, from_imports, trans)
|
||||
pool, cptr_other, imported_modules, from_imports, trans, depth + 1)
|
||||
if cptr_sub_ty is not None and cptr_other_ty is not None:
|
||||
# 计算 CPtr 侧外层 Ptr 嵌套数(如 t.CPtr[t.CPtr]=i8** → 2 层)
|
||||
cptr_level: int = 0
|
||||
cur_lvl: llvmlite.LLVMType | t.CPtr = cptr_sub_ty
|
||||
while cur_lvl is not None:
|
||||
# 注意:不能在 case body 内直接更新 while 条件变量
|
||||
# (cur_lvl = cur_lvl.Pointee)——自举编译出的 match 会把
|
||||
# 赋值写到 subject 快照槽,while 条件仍读旧槽 → 死循环
|
||||
# (gen2 编 FuncTest 卡死根因,gdb 反汇编 +3770-3819 确认)。
|
||||
# 改法:case 绑定 pointee 到局部变量,match 外更新循环变量。
|
||||
nxt_lvl: llvmlite.LLVMType | t.CPtr = None
|
||||
match cur_lvl:
|
||||
case llvmlite.LLVMType.Ptr(_):
|
||||
case llvmlite.LLVMType.Ptr(pointee):
|
||||
cptr_level += 1
|
||||
cur_lvl = cur_lvl.Pointee
|
||||
nxt_lvl = pointee
|
||||
case _:
|
||||
break
|
||||
cur_lvl = nxt_lvl
|
||||
# 结果 = 另一侧类型外包 N 层 Ptr
|
||||
res_ty: llvmlite.LLVMType | t.CPtr = cptr_other_ty
|
||||
li2: int = 0
|
||||
@@ -1468,11 +1648,11 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
|
||||
# 无 CPtr 标记:返回第一个非 None(装饰器标记如 CExport/CExtern 被忽略)
|
||||
left_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, bop.left, imported_modules, from_imports, trans)
|
||||
pool, bop.left, imported_modules, from_imports, trans, depth + 1)
|
||||
if left_ty is not None:
|
||||
return left_ty
|
||||
right_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, bop.right, imported_modules, from_imports, trans)
|
||||
pool, bop.right, imported_modules, from_imports, trans, depth + 1)
|
||||
if right_ty is not None:
|
||||
return right_ty
|
||||
return None
|
||||
@@ -1491,7 +1671,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
gen_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
|
||||
if gen_nm.id is not None:
|
||||
# 裸名 CArray(from t import * 场景,如 core.vp 的
|
||||
# `__python_suffix__: CArray[str] = ["py", ...]`):与 t.CArray
|
||||
# `__python_suffix__: CArray[str] = [...]):与 t.CArray
|
||||
# 语义等价。否则走泛型模板查找失败(CArray 不是泛型类模板)→
|
||||
# 字段类型退化 Ptr(i8) → __before_init__ 默认值 List 字面量误走
|
||||
# 动态 list 构造(list[str].__new__/append 符号未生成 → 链接
|
||||
@@ -1500,7 +1680,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# 单参数: CArray[elem_ty] → Ptr(elem_ty)(静态推导长度数组)
|
||||
if sub.slice.kind() != ast.ASTKind.Tuple:
|
||||
elem_n: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, sub.slice, imported_modules, from_imports, trans)
|
||||
pool, sub.slice, imported_modules, from_imports, trans, depth + 1)
|
||||
if elem_n is None:
|
||||
return None
|
||||
return llvmlite.Ptr(pool, elem_n)
|
||||
@@ -1513,7 +1693,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if elem_node_n is None or count_node_n is None:
|
||||
return None
|
||||
elem_ty_n: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, elem_node_n, imported_modules, from_imports, trans)
|
||||
pool, elem_node_n, imported_modules, from_imports, trans, depth + 1)
|
||||
if elem_ty_n is None:
|
||||
return None
|
||||
# count=None → Ptr(elem)(等价单参)
|
||||
@@ -1527,7 +1707,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
return None
|
||||
return llvmlite.Array(pool, elem_ty_n, count_n)
|
||||
return self._resolve_generic_subscript_ty(pool, sub, gen_nm.id, trans,
|
||||
imported_modules, from_imports)
|
||||
imported_modules, from_imports, depth + 1)
|
||||
# 检查 value 是否是 Attribute(t.CArray / t.Callable / 模块限定泛型类如 numpy.ndarray[T])
|
||||
if sub.value.kind() != ast.ASTKind.Attribute:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "不支持的 Subscript 类型注解(仅支持 t.CArray / t.Callable)")
|
||||
@@ -1539,7 +1719,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if trans is not None:
|
||||
if self.Gen.ClassGenGeneric._find_generic_template(arr_at.attr) is not None:
|
||||
return self._resolve_generic_subscript_ty(pool, sub, arr_at.attr, trans,
|
||||
imported_modules, from_imports)
|
||||
imported_modules, from_imports, depth + 1)
|
||||
if arr_at.value is None or arr_at.value.kind() != ast.ASTKind.Name:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "t.CArray / t.Callable 必须通过模块名限定")
|
||||
arr_val_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arr_at.value)
|
||||
@@ -1560,7 +1740,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "t.CPtr 模块未导入")
|
||||
inner_cptr_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, sub.slice, imported_modules, from_imports, trans)
|
||||
pool, sub.slice, imported_modules, from_imports, trans, depth + 1)
|
||||
if inner_cptr_ty is None:
|
||||
self.Gen.TypeGenErr.fatal_type_error(sub.slice, "t.CPtr[?] 元素类型解析失败")
|
||||
return llvmlite.Ptr(pool, inner_cptr_ty)
|
||||
@@ -1572,7 +1752,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# 相当于 t.CArray[elem_ty, None],表示静态推导长度数组
|
||||
if sub.slice.kind() != ast.ASTKind.Tuple:
|
||||
elem_ty_single: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, sub.slice, imported_modules, from_imports, trans)
|
||||
pool, sub.slice, imported_modules, from_imports, trans, depth + 1)
|
||||
if elem_ty_single is None:
|
||||
self.Gen.TypeGenErr.fatal_type_error(sub.slice, "t.CArray[?] 元素类型解析失败")
|
||||
return llvmlite.Ptr(pool, elem_ty_single)
|
||||
@@ -1590,7 +1770,7 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "t.CArray Tuple 元素为 None")
|
||||
# 递归解析元素类型
|
||||
elem_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, elem_node, imported_modules, from_imports, trans)
|
||||
pool, elem_node, imported_modules, from_imports, trans, depth + 1)
|
||||
if elem_ty is None:
|
||||
self.Gen.TypeGenErr.fatal_type_error(elem_node, "t.CArray 元素类型解析失败")
|
||||
# 解析 count(支持整数常量、None、CDefine 常量名、常量表达式如 2*MAX)
|
||||
|
||||
@@ -39,6 +39,10 @@ import string
|
||||
SCOPE_MODULE: t.CDefine = 0
|
||||
SCOPE_FUNCTION: t.CDefine = 1
|
||||
SCOPE_BLOCK: t.CDefine = 2
|
||||
# match case 作用域(对齐 MatchGenMixin.SCOPE_MATCH;本地定义避免循环依赖)。
|
||||
# 该作用域仅用于"变体字段绑定隔离",普通赋值语义上属于外层函数作用域,
|
||||
# get_or_create_sym/_lookup_through_match_scope 会"看穿"它写回外层变量。
|
||||
SCOPE_MATCH: t.CDefine = 6
|
||||
|
||||
# 每个作用域最大变量数
|
||||
# 256 太小:NewAstTest main() 有 289 个局部变量(几十个测试用例),
|
||||
@@ -377,6 +381,39 @@ class VarGenMixin:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# _lookup_through_match_scope — 穿越 match case 作用域查找变量
|
||||
#
|
||||
# match case 作用域(SCOPE_MATCH)仅用于"变体字段绑定隔离"(case 绑定的
|
||||
# 模式变量互不泄漏)。case 体内对"外层普通变量"的赋值(如 FuncGenDef
|
||||
# 参数 match 的 param_ty2 = Ptr(...),或 translate_subscript 内层 case 的
|
||||
# list_struct_name = lsn)语义上应写回外层 alloca,而非新建 case 局部槽
|
||||
# ——否则外层变量恒为初始值。自举证据:gen1 编译出的 gen2 其 FuncGenDef
|
||||
# 参数 match 把赋值写进 case 局部槽、build_alloca 读初始 i32_ty,导致
|
||||
# 指针参数 alloca 退化为 i32 → FuncTest main.vp:32 `p[0] = p[0] + val`
|
||||
# 的 translate_subscript 读 i32 非指针返回 None("赋值右侧为 None
|
||||
# [kind=11]" 根因)。
|
||||
# 遍历规则:逐级向上查找;SCOPE_MATCH 边界可穿越(可命中外层 case 声明的
|
||||
# 变量),遇到第一个非 match 作用域(函数/模块)后停止——不跨函数边界
|
||||
# (闭包 nonlocal 语义由 is_nonlocal_name 单独处理)。
|
||||
# ============================================================
|
||||
def _lookup_through_match_scope(self, symtab: GenTypes.SymbolTable | t.CPtr,
|
||||
name: str) -> llvmlite.Value | t.CPtr:
|
||||
"""从当前作用域向上,仅穿越 SCOPE_MATCH 作用域查找变量 alloca"""
|
||||
if symtab is None or name is None:
|
||||
return None
|
||||
scope: GenTypes.Scope | t.CPtr = symtab.Current
|
||||
while scope is not None:
|
||||
result: llvmlite.Value | t.CPtr = self.find_var(
|
||||
scope.Vars, scope.VarCount, name)
|
||||
if result is not None:
|
||||
return result
|
||||
if scope.Kind == SCOPE_MATCH:
|
||||
scope = scope.Parent
|
||||
continue
|
||||
return None
|
||||
return None
|
||||
|
||||
# ============================================================
|
||||
# get_or_create_sym — 查找或创建变量(在当前作用域)
|
||||
# ============================================================
|
||||
@@ -387,6 +424,12 @@ class VarGenMixin:
|
||||
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""查找或创建变量 alloca(在当前作用域)"""
|
||||
existing: llvmlite.Value | t.CPtr = self.lookup_current(symtab, name)
|
||||
if existing is not None:
|
||||
return existing
|
||||
# SCOPE_MATCH 隔离作用域对"赋值"必须透明(详见 _lookup_through_match_scope):
|
||||
# case 体内对外层变量的赋值要写回外层 alloca。仅穿越 match 边界,
|
||||
# 不跨函数/模块作用域(global/nonlocal 在 AssignGenMixin 提前拦截)。
|
||||
existing = self._lookup_through_match_scope(symtab, name)
|
||||
if existing is not None:
|
||||
return existing
|
||||
alloca: llvmlite.Value | t.CPtr = self._alloca_at_entry(builder, ty)
|
||||
|
||||
@@ -49,6 +49,12 @@ MAX_CORO_FUNCS: t.CDefine = 256
|
||||
MAX_CORO_VARS: t.CDefine = 256
|
||||
MAX_CORO_TRY: t.CDefine = 16
|
||||
|
||||
# 翻译主环最大递归深度(translate_stmt/translate_value 嵌套)。AST 自引用环
|
||||
# 或翻译 bug 可致翻译主环(语句/表达式/调用)无限递归 → ASan stack-overflow。
|
||||
# match 守卫(MatchTranslateDepth)只保护 match 递归,本常量保护语句/表达式
|
||||
# 翻译环(fail-fast,对齐 TypeGenResolve 深度守卫模式)。
|
||||
TRANSLATE_MAX_DEPTH: t.CDefine = 256
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
|
||||
@@ -150,6 +156,16 @@ class Translator:
|
||||
# 追加90:控制流 merge 块可达性(1=有 br 进入可达/0=全分支 return 结构性不可达)
|
||||
_ctrl_merge_reachable: t.CInt
|
||||
|
||||
# match 翻译递归深度(match → case body → translate_value → 嵌套 match)。
|
||||
# 守卫:AST 自引用环(子节点回指祖先)或翻译 bug 导致的无限递归在此
|
||||
# fail-fast(对齐 TypeGenResolve 深度守卫,防 ASan stack-overflow)。
|
||||
MatchTranslateDepth: t.CInt
|
||||
|
||||
# 翻译主环递归深度(translate_stmt/translate_value 入口计数)。match 守卫
|
||||
# 只覆盖 match 递归;语句/表达式/调用环(如 translate_value ↔ translate_call)
|
||||
# 由本字段守卫,超 TRANSLATE_MAX_DEPTH 即 fail-fast(防 ASan stack-overflow)。
|
||||
TranslateDepth: t.CInt
|
||||
|
||||
# global 声明的变量名集合(当前函数内)
|
||||
_global_names: str
|
||||
_global_name_count: t.CInt
|
||||
|
||||
@@ -277,9 +277,9 @@ def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
|
||||
if scan_directory_recursive(pool, full_path, rel_path, result, inc_dir) != 0:
|
||||
subdir_failed += 1
|
||||
else:
|
||||
# 检查是否为 .vp 或 .py 文件(.vp 为 Viper 源,.py 向后兼容)
|
||||
# 检查是否为 .vp 源文件(Viper 源仅 .vp,不再识别 .py)
|
||||
is_py: int = 0
|
||||
if Utils.is_vp_or_py_at(fname, 0, fname_len) != 0:
|
||||
if Utils.is_vp_at(fname, 0, fname_len) != 0:
|
||||
is_py = 1
|
||||
|
||||
if is_py != 0:
|
||||
@@ -314,6 +314,7 @@ def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
|
||||
if fb_sdf is not None:
|
||||
viperlib.snprintf(fb_sdf, 1024, "子目录扫描失败 %d 个", subdir_failed)
|
||||
VLogger.error(fb_sdf, "scan")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
+1
-8
@@ -435,18 +435,11 @@ Target: %s
|
||||
# === 单文件模式:--src 指定时使用指定文件;--project 但无 SourceDir 时回退 ===
|
||||
if src_path is None and project is not None:
|
||||
if Config.SourceDir is not None:
|
||||
# 构造入口路径: 优先 SourceDir/main.vp,回退 SourceDir/main.py
|
||||
# 构造入口路径: SourceDir/main.vp(不再做 vp -> py 后缀识别回退)
|
||||
sd_len: t.CSizeT = string.strlen(Config.SourceDir)
|
||||
path_buf: bytes = stdlib.malloc(sd_len + 16)
|
||||
if path_buf is not None:
|
||||
# 优先尝试 main.vp
|
||||
viperlib.snprintf(path_buf, sd_len + 16, "%s/main.vp", Config.SourceDir)
|
||||
ef: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R)
|
||||
if ef.closed:
|
||||
# .vp 不存在,回退 main.py
|
||||
viperlib.snprintf(path_buf, sd_len + 16, "%s/main.py", Config.SourceDir)
|
||||
else:
|
||||
ef.close()
|
||||
src_path = path_buf
|
||||
if log is not None:
|
||||
fb4: str = VLogger.fmt_buf()
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition", "-Wl,--stack,0x1000000"],
|
||||
"flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition", "-Wl,--stack,0x1000000", "-Wl,--no-insert-timestamp"],
|
||||
"output": "TransPyV.exe"
|
||||
},
|
||||
"includes": [
|
||||
|
||||
Reference in new issue
Block a user