fix(tpv): 修常量折成0致alloc(0)与多处fail-fast,并落地热点优化
TypeGenCDef: CDefine 表名深拷贝(vpi 注入名为零拷贝指针且 vpi_buf 提前释放,悬空名致常量查出错误值 0) VpiReader: 模块级 SHA1_LEN(16) 改名 SHA1_HEX_LEN,消除与 Phase1.SHA1_LEN(17) 的跨模块同名冲突 CallGenCall: 实参翻译失败/漏传必需实参改 fail-fast,禁用零值兜底(堵住 SHA1_LEN 未解析变 alloc 0 的通路) MatchGenMixin: 序列 match 的 case _ 分支补容量守卫(原先会越界写穿 pool 块、破坏空闲链) Phase1Main/Phase1Scan: 预扫描缓冲分配失败改 fail-fast;加临时取证打点 CallGenBase: find_func_in_module 4 趟链表扫描合并为 2 趟 ImportsGenMixin: import 查找加哈希索引(键为 NUL 结尾副本,未命中回退原扫描) TypeGenBase/TypeGenResolve: 库 typedef 按模块一次性门禁与缓存 VpiReader: vpi 注解解析补 rowptr[T] 分支
This commit is contained in:
1 parent
af2c66e7d7
commit
0dd7511a9b
11 files changed
+666
-136
No files matched your search
@@ -437,6 +437,59 @@ def RunPhase1(mb: rowptr[memhub.MemBuddy], includes_dir: str, temp_dir: str,
|
||||
p1a_skp: int = 0
|
||||
p1a_fl: int = 0
|
||||
|
||||
# ============================================================
|
||||
# [临时取证打点] Phase1 早期扁平缓冲分配失败现场快照(定位后清理)。
|
||||
# 现场:class_names_buf/parent_names_buf 均成功,def_sha1s_buf 却返回 NULL;
|
||||
# 此时主池(1GiB)远未耗尽 → 非 OOM。本打点仅只读 mb 状态 + 打印,
|
||||
# 绝不改变任何分配行为与逻辑。三维度判定:
|
||||
# ① OOM:dump_stats 显示 used≈total、free≈0;
|
||||
# ② mb 损坏:usable 基址/大小荒谬、self_check != 0、max_order 异常;
|
||||
# ③ size/order 异常:本次请求 size 算出的 order > max_order。
|
||||
# 用 VLogger.info(非终止;VLogger.error 会 sys.exit(1) 掩盖后续打点)。
|
||||
# ============================================================
|
||||
if mb is not None:
|
||||
# 先做带环检测的 self_check:free list 被写坏成环时 dump_stats 的
|
||||
# free_bytes/free_count 无步数上限会死循环(打点自身卡死),故
|
||||
# self_check 返回 4(成环)时跳过 dump_stats。
|
||||
p1_sc: int = mb.self_check()
|
||||
if p1_sc != 4:
|
||||
mb.dump_stats("phase1-pre")
|
||||
else:
|
||||
VLogger.info("[取证] self_check=4(free list 成环),跳过 dump_stats 防死循环", "Phase1")
|
||||
p1_mo: int = mb.max_order
|
||||
if p1_mo < 0 or p1_mo > 32:
|
||||
p1_mo = 32 # 钳制:max_order 被写坏时防本打点自身越界读 free_lists
|
||||
p1_fl_head: uint64 = uint64(mb.free_lists[p1_mo])
|
||||
p1_mb_addr: uint64 = uint64(mb)
|
||||
p1_base_addr: uint64 = uint64(mb.base)
|
||||
p1_usable_addr: uint64 = uint64(mb.usable)
|
||||
p1_chkbase_addr: uint64 = uint64(mb.chk_base)
|
||||
VLogger.info(
|
||||
f"[取证] mb={p1_mb_addr} base={p1_base_addr} usable={p1_usable_addr} "
|
||||
f"usable_size={mb.usable_size} max_order={mb.max_order} self_check={p1_sc} "
|
||||
f"detection={mb.detection}", "Phase1")
|
||||
VLogger.info(
|
||||
f"[取证] chk_base={p1_chkbase_addr} chk_depth={mb.chk_depth} "
|
||||
f"chk_cap={mb.chk_cap} free_lists[clamp={p1_mo}]={p1_fl_head}",
|
||||
"Phase1")
|
||||
p1_sz_cn: sizet = sizet(Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN)
|
||||
p1_sz_ds: sizet = sizet(Phase1.MAX_CLASSES * Phase1.SHA1_LEN)
|
||||
p1_sz_tp: sizet = sizet(4 * Phase1.MAX_FILE_DEPS)
|
||||
p1_sz_bx: sizet = sizet(4)
|
||||
p1_o_cn: int = mb._order_for_size(p1_sz_cn + 16)
|
||||
p1_o_ds: int = mb._order_for_size(p1_sz_ds + 16)
|
||||
p1_o_tp: int = mb._order_for_size(p1_sz_tp + 16)
|
||||
p1_o_bx: int = mb._order_for_size(p1_sz_bx + 16)
|
||||
p1_fl_cn: uint64 = uint64(mb.free_lists[p1_o_cn])
|
||||
p1_fl_ds: uint64 = uint64(mb.free_lists[p1_o_ds])
|
||||
VLogger.info(
|
||||
f"[取证] order(class_names {p1_sz_cn}B+16)={p1_o_cn} fl={p1_fl_cn} "
|
||||
f"order(def_sha1s {p1_sz_ds}B+16)={p1_o_ds} fl={p1_fl_ds} "
|
||||
f"order(topo {p1_sz_tp}B+16)={p1_o_tp} order(box {p1_sz_bx}B+16)={p1_o_bx} "
|
||||
f"(fl==0 只说明该阶空、仍可由更高阶拆分;若 alloc 失败而 dump_stats 的 free>0 才是元数据损坏铁证,"
|
||||
f"任一 order>max_order={mb.max_order} 则是 size 异常)",
|
||||
"Phase1")
|
||||
|
||||
# 预扫描类继承关系,构建拓扑顺序(用扁平字节数组,避免结构体 str 指针 NULL 崩溃)
|
||||
class_names_buf: bytes = mb.alloc(Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN)
|
||||
parent_names_buf: bytes = mb.alloc(Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN)
|
||||
@@ -451,42 +504,57 @@ def RunPhase1(mb: rowptr[memhub.MemBuddy], includes_dir: str, temp_dir: str,
|
||||
string.memset(generic_file_count_box, 0, 4)
|
||||
topo_count: int = 0
|
||||
|
||||
if class_names_buf is not None and parent_names_buf is not None and def_sha1s_buf is not None and topo_order is not None and topo_count_box is not None:
|
||||
string.memset(class_names_buf, 0, Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN)
|
||||
string.memset(parent_names_buf, 0, Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN)
|
||||
string.memset(def_sha1s_buf, 0, Phase1.MAX_CLASSES * Phase1.SHA1_LEN)
|
||||
string.memset(topo_order, 0, 4 * Phase1.MAX_FILE_DEPS)
|
||||
string.memset(topo_count_box, 0, 4)
|
||||
if generic_file_indices is not None:
|
||||
string.memset(generic_file_indices, 0, 4 * Phase1.MAX_FILE_DEPS)
|
||||
if generic_file_count_box is not None:
|
||||
string.memset(generic_file_count_box, 0, 4)
|
||||
# 三块扁平缓冲是 Phase1Scan._ScanClassInheritance 的契约前置缓冲:函数
|
||||
# 入口已对 NULL 做 fail-fast 检查(本处分配失败若静默跳过整段,将退化为
|
||||
# 字母序并掩盖 OOM 等内存故障)。故分配失败时逐块显式报错终止(VLogger.error
|
||||
# 内部 sys.exit(1)),绝不静默回退。
|
||||
# 注:topo_order/topo_count_box 仅供后续 Phase1Topo._TopoSortFiles 使用,
|
||||
# 不属 _ScanClassInheritance 契约,故不并入此处终止逻辑;其有效性由
|
||||
# _TopoSortFiles 入口自身校验(out_order/out_count 为 NULL 即返回 -1 并终止)。
|
||||
if class_names_buf is None:
|
||||
VLogger.error("类继承预扫描扁平缓冲分配失败:class_names_buf 为 NULL,终止编译", "Phase1")
|
||||
if parent_names_buf is None:
|
||||
VLogger.error("类继承预扫描扁平缓冲分配失败:parent_names_buf 为 NULL,终止编译", "Phase1")
|
||||
if def_sha1s_buf is None:
|
||||
VLogger.error("类继承预扫描扁平缓冲分配失败:def_sha1s_buf 为 NULL,终止编译", "Phase1")
|
||||
|
||||
class_count_scanned: int = Phase1Scan._ScanClassInheritance(
|
||||
string.memset(class_names_buf, 0, Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN)
|
||||
string.memset(parent_names_buf, 0, Phase1.MAX_CLASSES * Phase1.CLASS_NAME_LEN)
|
||||
string.memset(def_sha1s_buf, 0, Phase1.MAX_CLASSES * Phase1.SHA1_LEN)
|
||||
if topo_order is not None:
|
||||
string.memset(topo_order, 0, 4 * Phase1.MAX_FILE_DEPS)
|
||||
if topo_count_box is not None:
|
||||
string.memset(topo_count_box, 0, 4)
|
||||
if generic_file_indices is not None:
|
||||
string.memset(generic_file_indices, 0, 4 * Phase1.MAX_FILE_DEPS)
|
||||
if generic_file_count_box is not None:
|
||||
string.memset(generic_file_count_box, 0, 4)
|
||||
|
||||
class_count_scanned: int = Phase1Scan._ScanClassInheritance(
|
||||
mb, result, reachable_set, reachable_count,
|
||||
use_reachable, sha1_set, set_count,
|
||||
class_names_buf, parent_names_buf, def_sha1s_buf,
|
||||
generic_file_indices, generic_file_count_box)
|
||||
|
||||
if class_count_scanned > 0:
|
||||
td_len_ts_call: sizet = string.strlen(temp_dir)
|
||||
ret_topo: int = Phase1Topo._TopoSortFiles(
|
||||
mb, result, reachable_set, reachable_count,
|
||||
use_reachable, sha1_set, set_count,
|
||||
class_names_buf, parent_names_buf, def_sha1s_buf,
|
||||
generic_file_indices, generic_file_count_box)
|
||||
|
||||
if class_count_scanned > 0:
|
||||
td_len_ts_call: sizet = string.strlen(temp_dir)
|
||||
ret_topo: int = Phase1Topo._TopoSortFiles(
|
||||
mb, result, reachable_set, reachable_count,
|
||||
use_reachable, sha1_set, set_count,
|
||||
class_names_buf, parent_names_buf, def_sha1s_buf, class_count_scanned,
|
||||
topo_order, topo_count_box,
|
||||
temp_dir, td_len_ts_call)
|
||||
if ret_topo == 0:
|
||||
tc_ptr: t.CPtr = (int | t.CPtr)(t.CVoid(topo_count_box, t.CPtr))
|
||||
if tc_ptr is not None:
|
||||
topo_count = tc_ptr[0]
|
||||
VLogger.info(f"拓扑排序: {class_count_scanned} 个类, {topo_count} 个文件按依赖顺序处理", "Phase1")
|
||||
else:
|
||||
VLogger.error("拓扑排序失败(类继承依赖无法解析),终止编译", "Phase1")
|
||||
return 1
|
||||
class_names_buf, parent_names_buf, def_sha1s_buf, class_count_scanned,
|
||||
topo_order, topo_count_box,
|
||||
temp_dir, td_len_ts_call)
|
||||
if ret_topo == 0:
|
||||
tc_ptr: t.CPtr = (int | t.CPtr)(t.CVoid(topo_count_box, t.CPtr))
|
||||
if tc_ptr is not None:
|
||||
topo_count = tc_ptr[0]
|
||||
VLogger.info(f"拓扑排序: {class_count_scanned} 个类, {topo_count} 个文件按依赖顺序处理", "Phase1")
|
||||
else:
|
||||
VLogger.warning("类继承预扫描无结果,回退到字母序", "Phase1")
|
||||
topo_count = 0
|
||||
VLogger.error("拓扑排序失败(类继承依赖无法解析),终止编译", "Phase1")
|
||||
return 1
|
||||
else:
|
||||
VLogger.warning("类继承预扫描无结果,回退到字母序", "Phase1")
|
||||
topo_count = 0
|
||||
|
||||
# ============================================================
|
||||
# Phase 1a-pre-generic-all: mark1 前全量预注册 includes 泛型模板
|
||||
|
||||
@@ -76,8 +76,15 @@ def _ScanClassInheritance(mb: rowptr[memhub.MemBuddy],
|
||||
generic_file_indices: t.CPtr,
|
||||
generic_file_count_box: t.CPtr) -> int:
|
||||
"""预扫描 includes 文件,收集类继承关系"""
|
||||
if result is None or class_names_buf is None or parent_names_buf is None or def_sha1s_buf is None:
|
||||
if result is None:
|
||||
return -1
|
||||
# class_names_buf/parent_names_buf/def_sha1s_buf 由调用方 mb.alloc 分配
|
||||
# (Phase1Main 预扫描前),本函数将其地址直接作为 strcpy 的目的缓冲
|
||||
# (name_dst/parent_dst/sha1_dst)。分配失败返回 NULL 时目的指针为近零地址
|
||||
# → strcpy 写零页(ASan access-violation)。按 fail-fast 规则显式报错终止
|
||||
# (VLogger.error 内部 sys.exit(1)),不静默返回 -1 交由调用方宽容跳过。
|
||||
if class_names_buf is None or parent_names_buf is None or def_sha1s_buf is None:
|
||||
VLogger.error("类继承预扫描扁平缓冲分配失败(class_names_buf/parent_names_buf/def_sha1s_buf 为 NULL)", "Phase1")
|
||||
|
||||
entry_size: sizet = IncludesScanner.FileEntry.__sizeof__()
|
||||
class_count: int = 0
|
||||
|
||||
@@ -904,6 +904,26 @@ def _resolve_single_vpi_type_str(pool: rowptr[memhub.MemBuddy],
|
||||
# None 与 void 同义,归一到 Void。
|
||||
if string.strcmp(seg, "None") == 0:
|
||||
return llvmlite.Void(pool)
|
||||
# rowptr[T] 内建裸指针(等价 t.CPtr[T] → Ptr(T)):vpi 返回/参数注解按源码
|
||||
# 原样保留 Subscript 形态(如 tokens.vp `new_token -> rowptr[Token]`)。
|
||||
# 此前无此分支 → 整个注解解析返回 None → text.ll 尚未生成(合法时序:依赖
|
||||
# 模块尚未翻译,占位 text.ll 为空)时跨模块调用 fail-fast 误报
|
||||
# (includes/ast/lexer.vp new_token 根因)。与定义侧 TypeGenResolve
|
||||
# resolve_annotation_type 的 rowptr 分支同口径:Ptr(resolve(T))。
|
||||
if string.strncmp(seg, "rowptr[", 7) == 0:
|
||||
seg_len_rp: sizet = string.strlen(seg)
|
||||
if seg_len_rp > 8 and seg[seg_len_rp - 1] == ']':
|
||||
inner_len_rp: sizet = seg_len_rp - 8
|
||||
inner_buf_rp: bytes = stdlib.malloc(inner_len_rp + 1)
|
||||
if inner_buf_rp is not None:
|
||||
string.strncpy(inner_buf_rp, seg + 7, inner_len_rp)
|
||||
inner_buf_rp[inner_len_rp] = '\0'
|
||||
inner_ty_rp: llvmlite.LLVMType | t.CPtr = _resolve_single_vpi_type_str(
|
||||
pool, inner_buf_rp)
|
||||
stdlib.free(inner_buf_rp)
|
||||
if inner_ty_rp is not None:
|
||||
return llvmlite.Ptr(pool, inner_ty_rp)
|
||||
return None
|
||||
# t.XXX / c.XXX 内置类型映射
|
||||
if string.strncmp(seg, "t.", 2) == 0 or string.strncmp(seg, "c.", 2) == 0:
|
||||
attr_nm: str = seg + 2
|
||||
@@ -1112,8 +1132,14 @@ def _resolve_vpi_ret_annot_str(pool: rowptr[memhub.MemBuddy],
|
||||
# .vpi 读取缓冲区大小(256KB,与 PYI_BUF_SIZE 一致)
|
||||
VPI_READ_BUF_SIZE: sizet = 262144
|
||||
|
||||
# SHA1 字符串长度(16 hex 字符)
|
||||
SHA1_LEN: sizet = 16
|
||||
# SHA1 hex 字符数(16,仅文件名中的十六进制位,不含结尾 NUL)
|
||||
#
|
||||
# 注意:本常量原名 SHA1_LEN,与 lib.Phase.Phase1 的常量宏
|
||||
# Phase1.SHA1_LEN: t.CDefine = 17(16 字符 + NUL 的存储步长)**同名但语义不同**。
|
||||
# 同名跨模块符号会造成 CDefine 解析被遮蔽/串值(Phase1.MAX_CLASSES * Phase1.SHA1_LEN
|
||||
# 被解析成 0 → mb.alloc(0) → 分配失败)。故改为唯一名 SHA1_HEX_LEN 消除冲突;
|
||||
# 权威定义仍分别是:本处 16(hex 位数)、Phase1.SHA1_LEN 17(存储步长)。
|
||||
SHA1_HEX_LEN: sizet = 16
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -1135,7 +1161,7 @@ def _extract_sha1_from_path(vpi_path: str) -> str:
|
||||
return None
|
||||
# 查找最后一个路径分隔符 / 或 \
|
||||
total_len: sizet = string.strlen(vpi_path)
|
||||
if total_len < SHA1_LEN + 4: # 至少需要 "xxxx.vpi" 的长度
|
||||
if total_len < SHA1_HEX_LEN + 4: # 至少需要 "xxxx.vpi" 的长度
|
||||
return None
|
||||
# 从后向前查找最后一个 / 或 \
|
||||
sep_pos: sizet = total_len
|
||||
@@ -1145,14 +1171,14 @@ def _extract_sha1_from_path(vpi_path: str) -> str:
|
||||
if ch == '/' or ch == '\\':
|
||||
sep_pos += 1
|
||||
break
|
||||
if sep_pos + SHA1_LEN > total_len:
|
||||
if sep_pos + SHA1_HEX_LEN > total_len:
|
||||
return None
|
||||
# 分配缓冲区并复制 SHA1(16 字符 + null 终止符)
|
||||
sha1_buf: str = stdlib.malloc(SHA1_LEN + 1)
|
||||
sha1_buf: str = stdlib.malloc(SHA1_HEX_LEN + 1)
|
||||
if sha1_buf is None:
|
||||
return None
|
||||
string.strncpy(sha1_buf, vpi_path + sep_pos, SHA1_LEN)
|
||||
sha1_buf[SHA1_LEN] = '\0'
|
||||
string.strncpy(sha1_buf, vpi_path + sep_pos, SHA1_HEX_LEN)
|
||||
sha1_buf[SHA1_HEX_LEN] = '\0'
|
||||
return sha1_buf
|
||||
|
||||
|
||||
|
||||
@@ -1791,8 +1791,62 @@ class AssignGenMixin:
|
||||
pass
|
||||
if precise_rhs_ty is not None and alloca.Ty is not None:
|
||||
alloca_pt: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||||
# 禁止「降级重建」:RHS 的 pointee 若为**裸泛型基类**(丢类型
|
||||
# 实参,如 {sha1}.list / {sha1}.GSList),以它重建 alloca 会把后
|
||||
# 注解已解析出的「带类型实参特化」(如 list[ast.ASTptr])覆盖成裸
|
||||
# 基类 → 之后 .get() 按错误元素类型特化(list[int].get 返回 i32)
|
||||
# → inttoptr 把 i32 当指针(截断)→ translate_stmt 读垃圾 AST 节
|
||||
# 点崩溃。本重建本意是「注解退化成裸基类/i8*,RHS 构造出精确特化」
|
||||
# 的**反向升级**(见上方注释),因此仅在 RHS 不是裸泛型基类时才执行。
|
||||
# 现场根因:AST.children 字段注册为裸 list*(其注解
|
||||
# list[rowptr[AST]] | t.CPtr 在字段注册期未解析出带实参特化),
|
||||
# 故 `body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children`
|
||||
# 的 RHS 静态类型退化为裸 list*,触发本降级重建 →
|
||||
# MatchGenMixin._handle_renum_match 崩溃(IR 实证:
|
||||
# %"body_list.1" = alloca %"….list"* 被使用,%body_list 特化 alloca
|
||||
# 成死代码;.get 被分派到 list[int].get 返回 i32 → inttoptr 截断)。
|
||||
# 裸泛型基类不可作为 receiver 静态类型,否则泛型方法分派必错。
|
||||
# 取注解侧泛型基名(Base ∈ list/dict/...,仅 Name 形态的
|
||||
# Subscript 一侧),用于下方**不依赖泛型模板注册表**的方向判定。
|
||||
ann_gen_base: str = None
|
||||
if annot is not None:
|
||||
ag_side: ast.AST | t.CPtr = annot
|
||||
if ag_side.kind() == ast.ASTKind.BinOp:
|
||||
ag_bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(ag_side)
|
||||
if ag_bop.op == ast.OpKind.BitOr:
|
||||
if ag_bop.left is not None and ag_bop.left.kind() == ast.ASTKind.Subscript:
|
||||
ag_side = ag_bop.left
|
||||
elif ag_bop.right is not None and ag_bop.right.kind() == ast.ASTKind.Subscript:
|
||||
ag_side = ag_bop.right
|
||||
if ag_side.kind() == ast.ASTKind.Subscript:
|
||||
ag_sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(ag_side)
|
||||
if ag_sub.value is not None and ag_sub.value.kind() == ast.ASTKind.Name:
|
||||
ag_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ag_sub.value)
|
||||
if ag_nm.id is not None:
|
||||
ann_gen_base = ag_nm.id
|
||||
rb_is_bare_generic: int = 0
|
||||
if alloca_pt is not None \
|
||||
and uint64(alloca_pt) != uint64(precise_rhs_ty):
|
||||
rhs_pt_rb: llvmlite.LLVMType | t.CPtr = precise_rhs_ty.Pointee
|
||||
if rhs_pt_rb is not None:
|
||||
rb_nm: str = llvmlite.get_struct_name(rhs_pt_rb)
|
||||
if rb_nm is not None:
|
||||
rb_pf: int = GenApi.sha1_prefix_len(rb_nm)
|
||||
rb_short: str = rb_nm + rb_pf if rb_pf != 0 else rb_nm
|
||||
if string.strchr(rb_short, '[') is None:
|
||||
# ① 裸名命中泛型模板注册表(list/GSList/...)
|
||||
if self.Gen.ClassGenGeneric._find_generic_template(rb_short) is not None:
|
||||
rb_is_bare_generic = 1
|
||||
# ② 与注解同基名:注解是 `Base[...]`(带类型实参,
|
||||
# 已比 RHS 的裸 Base 精确)⇒ 本次重建方向是**降级**,
|
||||
# 必须禁止。此判定不依赖泛型模板注册表(list/dict 等
|
||||
# 内建容器未登记时①会漏判,②仍能命中)。
|
||||
elif ann_gen_base is not None \
|
||||
and string.strcmp(rb_short, ann_gen_base) == 0:
|
||||
rb_is_bare_generic = 1
|
||||
if alloca_pt is not None and \
|
||||
uint64(alloca_pt) != uint64(precise_rhs_ty):
|
||||
uint64(alloca_pt) != uint64(precise_rhs_ty) \
|
||||
and rb_is_bare_generic == 0:
|
||||
new_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(
|
||||
builder, precise_rhs_ty)
|
||||
if new_alloca is not None:
|
||||
|
||||
@@ -522,37 +522,44 @@ class CallGenBase:
|
||||
if mod is None or name is None:
|
||||
return None
|
||||
name_len: sizet = string.strlen(name)
|
||||
# 热点优化:原实现把「精确匹配」+「本模块同名 mangled」+「后缀匹配
|
||||
# define 优先」+「后缀匹配 declare 兜底」拆成 4 趟完整链表扫描,每趟
|
||||
# 对每个节点调用一次 function_get_name/function_get_next(实测二者各
|
||||
# ~1.046 亿次的热点来源)。合并为 2 趟,链表顺序与优先级语义不变:
|
||||
# 趟 1:精确匹配(命中即返回,优先级最高,与原第一遍一致)+ 收集
|
||||
# 首个本模块同名 mangled 候选(原"第一遍半",仅在无精确匹配
|
||||
# 时使用);
|
||||
# 趟 2:收集首个 IsDeclared==0 后缀命中(原第二遍优先)与首个任意
|
||||
# 后缀命中(原第三遍兜底),扫描结束后按原优先级返回。
|
||||
cur: llvmlite.Function | t.CPtr = mod.FuncHead
|
||||
# 第一遍:精确匹配
|
||||
mangle_hit: llvmlite.Function | t.CPtr = None
|
||||
while cur is not None:
|
||||
cur_name: str = llvmlite.function_get_name(cur)
|
||||
if cur_name is not None:
|
||||
if string.strcmp(cur_name, name) == 0:
|
||||
return cur
|
||||
cur = llvmlite.function_get_next(cur)
|
||||
# 第一遍半(owner_sha1 提供时):本模块同名函数优先。
|
||||
# 仅接受恰为 "{owner_sha1}.{name}" 的形态(mangled 模块级函数名含
|
||||
# 且只含一个 '.'),不匹配 "{sha1}.Class.method" 等方法名。是否
|
||||
# IsDeclared==0 均可返回:前向 declare 与 define 同名同符号。
|
||||
if owner_sha1 is not None:
|
||||
cur = mod.FuncHead
|
||||
while cur is not None:
|
||||
cur_name_o: str = llvmlite.function_get_name(cur)
|
||||
if cur_name_o is not None:
|
||||
cur_len_o: sizet = string.strlen(cur_name_o)
|
||||
# 本模块同名候选:仅接受恰为 "{owner_sha1}.{name}" 的形态
|
||||
# (mangled 模块级函数名含且只含一个 '.'),不匹配
|
||||
# "{sha1}.Class.method" 等方法名。是否 IsDeclared==0 均可返回:
|
||||
# 前向 declare 与 define 同名同符号。只在 owner_sha1 提供且尚未
|
||||
# 命中时计算,避免多做一次 strlen。
|
||||
if owner_sha1 is not None and mangle_hit is None:
|
||||
cur_len_o: sizet = string.strlen(cur_name)
|
||||
if cur_len_o == 17 + name_len:
|
||||
if string.strncmp(cur_name_o, owner_sha1, 16) == 0 and cur_name_o[16] == '.':
|
||||
if string.strncmp(cur_name, owner_sha1, 16) == 0 and cur_name[16] == '.':
|
||||
suffix_start_o: sizet = cur_len_o - name_len
|
||||
if cur_name_o[suffix_start_o - 1] == '.':
|
||||
if cur_name[suffix_start_o - 1] == '.':
|
||||
match_o: int = 1
|
||||
for i in range(name_len):
|
||||
if cur_name_o[suffix_start_o + i] != name[i]:
|
||||
if cur_name[suffix_start_o + i] != name[i]:
|
||||
match_o = 0
|
||||
break
|
||||
if match_o == 1:
|
||||
return cur
|
||||
cur = llvmlite.function_get_next(cur)
|
||||
# 第二遍:后缀匹配(.name)
|
||||
mangle_hit = cur
|
||||
cur = llvmlite.function_get_next(cur)
|
||||
if mangle_hit is not None:
|
||||
return mangle_hit
|
||||
# 后缀匹配(.name)
|
||||
# 不跳过 declare:方法 stub 也是 declare,需要通过后缀匹配找到
|
||||
# 调用处(translate_call 等)负责判断 IsDeclared 并决定使用裸名还是 sha1 前缀名
|
||||
#
|
||||
@@ -562,6 +569,9 @@ class CallGenBase:
|
||||
# 匹配按链表顺序先命中跨模块 declare → 参数按 Lexer* coerce → Parser* 被
|
||||
# bitcast 成 Lexer* → lexer 版 _advance 按 Lexer 布局操作 Parser 指针,
|
||||
# cur 永不推进 → parse 无限循环。本模块同名 define 必须优先。
|
||||
# 无同名 define 时回退到 stub declare(跨模块方法/函数调用)。
|
||||
declare_hit: llvmlite.Function | t.CPtr = None
|
||||
any_hit: llvmlite.Function | t.CPtr = None
|
||||
cur = mod.FuncHead
|
||||
while cur is not None:
|
||||
cur_name2: str = llvmlite.function_get_name(cur)
|
||||
@@ -576,27 +586,16 @@ class CallGenBase:
|
||||
match = 0
|
||||
break
|
||||
if match == 1:
|
||||
if cur.IsDeclared == 0:
|
||||
return cur
|
||||
# 首个任意后缀命中(原第三遍兜底)
|
||||
if any_hit is None:
|
||||
any_hit = cur
|
||||
# 首个 IsDeclared==0 命中(原第二遍优先)
|
||||
if cur.IsDeclared == 0 and declare_hit is None:
|
||||
declare_hit = cur
|
||||
cur = llvmlite.function_get_next(cur)
|
||||
# 本模块无同名 define:回退到 stub declare(跨模块方法/函数调用)
|
||||
cur = mod.FuncHead
|
||||
while cur is not None:
|
||||
cur_name3: str = llvmlite.function_get_name(cur)
|
||||
if cur_name3 is not None:
|
||||
cur_len3: sizet = string.strlen(cur_name3)
|
||||
if cur_len3 > name_len + 1:
|
||||
suffix_start3: sizet = cur_len3 - name_len
|
||||
if cur_name3[suffix_start3 - 1] == '.':
|
||||
match3: int = 1
|
||||
for i in range(name_len):
|
||||
if cur_name3[suffix_start3 + i] != name[i]:
|
||||
match3 = 0
|
||||
break
|
||||
if match3 == 1:
|
||||
return cur
|
||||
cur = llvmlite.function_get_next(cur)
|
||||
return None
|
||||
if declare_hit is not None:
|
||||
return declare_hit
|
||||
return any_hit
|
||||
|
||||
|
||||
# ============================================================
|
||||
|
||||
@@ -1353,8 +1353,9 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
arg_count_eff: int = 0
|
||||
|
||||
if kwc > 0 and found_func is not None:
|
||||
# 关键字参数:遍历函数定义参数(跳过 self),位置参数优先,其余按名匹配
|
||||
# 缺失参数用零值兜底,保持 call 参数数量与 define 一致
|
||||
# 关键字参数:遍历函数定义参数(跳过 self),位置参数优先,其余按名匹配。
|
||||
# 未提供的形参按类型补占位零值以保持参数序列位置(见下方 (b)/(c) 注释);
|
||||
# 实参表达式翻译失败则 fail-fast,绝不静默零值替换。
|
||||
cur_param_k: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||||
if cur_param_k is not None:
|
||||
cur_param_k = llvmlite.param_get_next(cur_param_k) # 跳过 self
|
||||
@@ -1381,9 +1382,19 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
arg_val_k = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg_node_k, None, 0, trans, pty_k0)
|
||||
if arg_val_k is None:
|
||||
# 缺失参数:零值兜底(保持参数数量匹配)。
|
||||
# kw 省略的形参可能有默认值(查不到默认表 ≠ 无默认值),
|
||||
# 零值兜底与原逻辑一致,禁止 fail-fast 误杀。
|
||||
if arg_node_k is not None:
|
||||
# (a) 实参节点存在但表达式翻译失败(返回 None)→ fail-fast。
|
||||
# 禁止静默零值替换:那会把未解析实参(如跨模块同名冲突的
|
||||
# Phase1.SHA1_LEN)伪造成合法实参。
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
arg_node_k,
|
||||
f"方法调用 '{class_name}.{method_name}' 第 {pi_k + 1} 个形参"
|
||||
f"的实参表达式翻译失败(返回 None,禁止按类型零值兜底)",
|
||||
"TypeError")
|
||||
continue
|
||||
# (b)/(c) 关键字/位置都未提供该形参:按形参类型补占位零值以保持
|
||||
# 参数序列位置(避免后续实参左移错位)。此占位不是"表达式翻译
|
||||
# 失败"的兜底(那条通路已在上方 fail-fast)。
|
||||
pty_k: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k)
|
||||
if pty_k is not None:
|
||||
arg_val_k = llvmlite.ConstZero(pool, pty_k)
|
||||
@@ -1403,6 +1414,13 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
for ai in range(can):
|
||||
arg_node: ast.AST | t.CPtr = cargs.get(ai)
|
||||
if arg_node is None:
|
||||
# (a) 实参节点缺失(AST 参数列表空洞)→ fail-fast,禁止静默跳过
|
||||
# (跳过会减少 arg_count_eff,随后被"缺参默认填充"用零值补齐)。
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
cl,
|
||||
f"方法调用 '{class_name}.{method_name}' 第 {ai + 1} 个实参"
|
||||
f"节点缺失(AST 参数列表空洞,无法翻译)",
|
||||
"TypeError")
|
||||
continue
|
||||
# 先取形参类型:单引号单字符字面量(CONST_CHAR)传给 str/指针
|
||||
# 形参时需物化 1 字符字符串(translate_constant 依据 target_ty 判定),
|
||||
@@ -1422,6 +1440,16 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg_node, None, 0, trans, pty)
|
||||
if arg_val is None:
|
||||
# (a) 实参表达式翻译失败(translate_value 返回 None)→ fail-fast。
|
||||
# 禁止 continue 跳过:跳过会减少 arg_count_eff,随后"缺参默认
|
||||
# 填充"用类型零值补齐该形参 —— 正是把未解析实参(如跨模块同名
|
||||
# 冲突的 Phase1.SHA1_LEN)静默变成 alloc(..., 0) 的兜底通路。
|
||||
# 用实参节点带出行号,报出被调用者与实参序号。
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
arg_node,
|
||||
f"方法调用 '{class_name}.{method_name}' 第 {ai + 1} 个实参"
|
||||
f"表达式翻译失败(返回 None,禁止按类型零值兜底)",
|
||||
"TypeError")
|
||||
continue
|
||||
# 按形参类型 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1)
|
||||
# 修复: CDefine/i32 常量传给 i64 形参(如 MemBuddy.__init__ 的 size: sizet)
|
||||
@@ -1552,10 +1580,23 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
total_count += 1
|
||||
mdf_pi += 1
|
||||
continue
|
||||
# 无默认值时用零值兜底(需要 found_func 获取参数类型)。
|
||||
# 默认参数表按裸名注册(如 "__init__"),跨模块 "ClassName.method"
|
||||
# 查找常查不到——查不到 ≠ 无默认值(如 Buf.__init__(data, capacity)
|
||||
# 缺的 length=0/owned=False 恰为零值),零值兜底语义一致。
|
||||
# (c) 已知默认值区间(DefaultCount>0)且该形参序号落在区间之前
|
||||
# ⇒ 该形参确无默认值 ⇒ 调用点漏传必需实参。禁止零值兜底(历史
|
||||
# 兜底会把漏传实参静默变成 0),fail-fast 报出被调用者与形参序号。
|
||||
if mdf_default_count > 0 and mdf_pi < mdf_offset:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
cl,
|
||||
f"方法调用 '{lookup_name}' 漏传必需实参:第 {mdf_pi + 1} 个形参"
|
||||
f"无默认值(调用点仅提供 {arg_count_eff} 个实参,"
|
||||
f"该函数前 {mdf_offset} 个形参为必需)",
|
||||
"TypeError")
|
||||
mdf_pi += 1
|
||||
continue
|
||||
# (b) 其余缺参只能来自"默认值信息缺失"(默认参数表按裸名注册、
|
||||
# 跨模块 "ClassName.method" 查找常查不到,vpi 也可能未登记:查不到
|
||||
# ≠ 无默认值,故无法判定)。此时按声明形参类型补零,仅为对齐
|
||||
# call/declare 的形参数量、填补尾随的声明可选参数;这**不是**
|
||||
# "表达式翻译失败"的兜底 —— 那条通路已在实参装配处 fail-fast。
|
||||
if found_func is not None:
|
||||
param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||||
skip_z: int = 0
|
||||
|
||||
@@ -3,6 +3,7 @@ import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import memhub
|
||||
import hashtable
|
||||
import string
|
||||
import stdlib
|
||||
import viperlib
|
||||
@@ -48,11 +49,132 @@ class ImportsGenMixin:
|
||||
ReexportSrcs: bytes
|
||||
ReexportCount: int
|
||||
|
||||
# --- 导入查找索引(把 O(串长) 的逐字符扫描降为 O(名字长) 哈希查找) ---
|
||||
# imported_modules/_from_imports 是空格拼接的扁平串("a b c" / "n:m[:orig]"),
|
||||
# 长度可达数千字符,而每个 Name 节点都会多次查询。索引与「当前串指针」绑定:
|
||||
# 调用方查询的 trans._imported_modules/_from_imports 总是 add_* 刚生成的当前串,
|
||||
# 故命中索引快路径;其余来源(stub 期 stdlib malloc 缓冲等)指针不匹配 → 回退
|
||||
# 原逐字符扫描,语义完全不变。索引表用 PermPool 分配(跨文件/Phase 存活),由
|
||||
# 对应 add_* 增量维护(非每文件重建);key/value 均是指向该扁平串内部的指针,
|
||||
# 串在文件级 reset 前始终有效。
|
||||
CurImportedModulesPtr: str
|
||||
CurImportedModulesNames: hashtable.HashTable | t.CPtr
|
||||
CurFromImportsPtr: str
|
||||
CurFromImportsMods: hashtable.HashTable | t.CPtr
|
||||
CurFromImportsOrigs: hashtable.HashTable | t.CPtr
|
||||
|
||||
# 注意:不声明 CurrentFile 字段——TypeGenMixin 已声明(Generator 展平块
|
||||
# 只有一份,跨父类不去重规则下重复声明会导致字段错位)。本 Mixin 的
|
||||
# set_current_file 与 CurrentFile 读取统一经 HandlesType 委托(延迟 import
|
||||
# 规避 HandlesType↔HandlesImports 循环依赖)。
|
||||
|
||||
# ============================================================
|
||||
# _index_imported_module - 增量维护 imported_modules 查找索引
|
||||
#
|
||||
# old_ptr 为追加前的串指针(None = 首个模块),new_ptr 为追加后的新串,
|
||||
# name_ptr 指向新串内的新模块名(key 直接引用串内部,无需复制)。
|
||||
# 仅当 old_ptr 恰为当前索引绑定的串时复用其索引(正常路径:add_* 始终以
|
||||
# trans 的当前串为输入);否则放弃索引绑定并回退逐字符扫描(语义不变)。
|
||||
# ============================================================
|
||||
def _index_imported_module(self, old_ptr: str, new_ptr: str,
|
||||
name_ptr: str) -> None:
|
||||
"""增量更新 imported_modules 索引(复用旧索引或新建,失败则解除绑定)"""
|
||||
if new_ptr is None or name_ptr is None:
|
||||
return
|
||||
perm: rowptr[memhub.MemBuddy] = CompilerFactory.factory.PermPool
|
||||
if perm is None:
|
||||
return
|
||||
idx: hashtable.HashTable | t.CPtr = None
|
||||
if old_ptr is None:
|
||||
# 新文件/新链首:建全新索引(旧索引随旧串一起废弃)
|
||||
idx = hashtable.HashTable(perm)
|
||||
elif old_ptr == self.CurImportedModulesPtr and self.CurImportedModulesNames is not None:
|
||||
# 正常路径:复用当前串的索引并追加(不重建,内存 O(导入数))
|
||||
idx = self.CurImportedModulesNames
|
||||
else:
|
||||
# 旧串非当前索引串(异常来源):解除绑定,回退逐字符扫描
|
||||
self.CurImportedModulesPtr = None
|
||||
self.CurImportedModulesNames = None
|
||||
return
|
||||
if idx is None:
|
||||
self.CurImportedModulesPtr = None
|
||||
self.CurImportedModulesNames = None
|
||||
return
|
||||
# 同名已在(重复导入)则跳过;否则写入(key/value 均指向 new_ptr 内部)
|
||||
if idx.__contains__(name_ptr) == 0:
|
||||
idx.set_str(name_ptr, name_ptr)
|
||||
self.CurImportedModulesPtr = new_ptr
|
||||
self.CurImportedModulesNames = idx
|
||||
|
||||
# ============================================================
|
||||
# _index_from_import - 增量维护 from_imports 查找索引
|
||||
#
|
||||
# entry_off 为新增 entry("local:module[:orig]")在新串内相对首字节的偏移。
|
||||
# 模块表 key=local_name → 指向模块名切片;orig 表 key=local_name → 指向原始名
|
||||
# 切片(无别名时写入 None,以"名存在但无原始名"区别于未命中)。
|
||||
# 语义对齐逐字符扫描:精确名首次命中为准(不覆盖),star 模块名以最后一条为准。
|
||||
# ============================================================
|
||||
def _index_from_import(self, old_ptr: str, new_ptr: str, entry_off: sizet,
|
||||
local_name: str, module_name: str,
|
||||
original_name: str) -> None:
|
||||
"""增量更新 from_imports 索引(复用旧索引或新建,失败则解除绑定)"""
|
||||
if new_ptr is None or local_name is None or module_name is None:
|
||||
return
|
||||
perm: rowptr[memhub.MemBuddy] = CompilerFactory.factory.PermPool
|
||||
if perm is None:
|
||||
return
|
||||
idx_m: hashtable.HashTable | t.CPtr = None
|
||||
idx_o: hashtable.HashTable | t.CPtr = None
|
||||
if old_ptr is None:
|
||||
idx_m = hashtable.HashTable(perm)
|
||||
idx_o = hashtable.HashTable(perm)
|
||||
elif old_ptr == self.CurFromImportsPtr \
|
||||
and self.CurFromImportsMods is not None \
|
||||
and self.CurFromImportsOrigs is not None:
|
||||
idx_m = self.CurFromImportsMods
|
||||
idx_o = self.CurFromImportsOrigs
|
||||
else:
|
||||
self.CurFromImportsPtr = None
|
||||
self.CurFromImportsMods = None
|
||||
self.CurFromImportsOrigs = None
|
||||
return
|
||||
if idx_m is None or idx_o is None:
|
||||
self.CurFromImportsPtr = None
|
||||
self.CurFromImportsMods = None
|
||||
self.CurFromImportsOrigs = None
|
||||
return
|
||||
local_len: sizet = string.strlen(local_name)
|
||||
mod_len: sizet = string.strlen(module_name)
|
||||
# 哈希键必须是 NUL 结尾串:扁平串内 local 段以 ':' 结尾(非 NUL),若直接把
|
||||
# 串内 local 段指针当键,FNV 会哈希到 "local:module..." 整段,与查询名
|
||||
# "local" 永不相等 → 索引恒 miss(_op_head NameError 根因)。故用 PermPool
|
||||
# 分配 NUL 结尾的稳定副本作键(与索引表同寿命),值仍指向扁平串内模块名切片。
|
||||
key_ptr: str = perm.alloc(local_len + 1)
|
||||
if key_ptr is None:
|
||||
self.CurFromImportsPtr = None
|
||||
self.CurFromImportsMods = None
|
||||
self.CurFromImportsOrigs = None
|
||||
return
|
||||
string.strncpy(key_ptr, local_name, local_len)
|
||||
key_ptr[local_len] = '\0'
|
||||
mod_ptr: str = new_ptr + entry_off + local_len + 1
|
||||
if local_len == 1 and local_name[0] == '*':
|
||||
# star import:模块名以最后一条为准(覆盖旧值,对齐 star_mod 语义)
|
||||
idx_m.set_str(key_ptr, mod_ptr)
|
||||
else:
|
||||
if idx_m.__contains__(key_ptr) == 0:
|
||||
idx_m.set_str(key_ptr, mod_ptr)
|
||||
if idx_o.__contains__(key_ptr) == 0:
|
||||
if original_name is not None and string.strcmp(original_name, local_name) != 0 \
|
||||
and string.strlen(original_name) > 0:
|
||||
idx_o.set_str(key_ptr, mod_ptr + mod_len + 1)
|
||||
else:
|
||||
# 首次出现即无别名(或别名为空)→ 该名查询返回 None(与逐字符扫描一致)
|
||||
idx_o.set_str(key_ptr, None)
|
||||
self.CurFromImportsPtr = new_ptr
|
||||
self.CurFromImportsMods = idx_m
|
||||
self.CurFromImportsOrigs = idx_o
|
||||
|
||||
# ============================================================
|
||||
# 添加已导入模块名
|
||||
# ============================================================
|
||||
@@ -67,6 +189,8 @@ class ImportsGenMixin:
|
||||
buf: str = pool.alloc(nlen + 1)
|
||||
if buf is not None:
|
||||
string.strcpy(buf, name)
|
||||
# 索引:首个模块名(key 指向 buf 内部)
|
||||
self._index_imported_module(None, buf, buf)
|
||||
return buf
|
||||
return None
|
||||
else:
|
||||
@@ -78,6 +202,8 @@ class ImportsGenMixin:
|
||||
string.strcpy(buf2, imported_modules)
|
||||
buf2[old_len] = ' '
|
||||
string.strcpy(buf2 + old_len + 1, name)
|
||||
# 索引:复用旧串索引并追加新名字(key 指向 buf2 内的 name 段)
|
||||
self._index_imported_module(imported_modules, buf2, buf2 + old_len + 1)
|
||||
return buf2
|
||||
return imported_modules
|
||||
|
||||
@@ -88,6 +214,14 @@ class ImportsGenMixin:
|
||||
"""检查模块是否已导入(词边界精确匹配,避免子串误匹配)"""
|
||||
if name is None or imported_modules is None:
|
||||
return 0
|
||||
# [索引快路径] 传入串即当前索引绑定的串(trans 字段的常态)→ O(名字长) 哈希查;
|
||||
# 指针不匹配(stub 期 malloc 缓冲等)→ 回退下方逐字符扫描,语义不变。
|
||||
if imported_modules == self.CurImportedModulesPtr \
|
||||
and self.CurImportedModulesNames is not None:
|
||||
if self.CurImportedModulesNames.__contains__(name) != 0:
|
||||
return 1
|
||||
# 索引未命中:绝不据此返回 0(索引不完整会误判"未导入"),
|
||||
# 落到下方原逐字符扫描按真实串内容判定(正确性优先 | 性能次之)。
|
||||
name_len: sizet = string.strlen(name)
|
||||
cur: str = imported_modules
|
||||
total_len: sizet = string.strlen(imported_modules)
|
||||
@@ -175,6 +309,8 @@ class ImportsGenMixin:
|
||||
else:
|
||||
viperlib.snprintf(entry, 256, "%s:%s", local_name, module_name)
|
||||
if from_imports is None:
|
||||
# 索引:首条 entry(local 从 entry 首字节开始,entry_off=0)
|
||||
self._index_from_import(None, entry, 0, local_name, module_name, original_name)
|
||||
return entry
|
||||
else:
|
||||
old_len: sizet = string.strlen(from_imports)
|
||||
@@ -185,6 +321,9 @@ class ImportsGenMixin:
|
||||
string.strcpy(buf, from_imports)
|
||||
buf[old_len] = ' '
|
||||
string.strcpy(buf + old_len + 1, entry)
|
||||
# 索引:复用旧串索引并追加(entry 从 buf[old_len+1] 开始)
|
||||
self._index_from_import(from_imports, buf, old_len + 1,
|
||||
local_name, module_name, original_name)
|
||||
return buf
|
||||
return from_imports
|
||||
|
||||
@@ -199,6 +338,15 @@ class ImportsGenMixin:
|
||||
"""查找 from-import 别名对应的原始函数名,返回 None=无别名或未找到"""
|
||||
if local_name is None or from_imports is None:
|
||||
return None
|
||||
# [索引快路径] 传入串即当前索引绑定的串 → O(名字长) 哈希查;否则回退扫描。
|
||||
# orig 表:名存在但存 None = 首次出现即无别名 → 返回 None(与扫描一致)。
|
||||
if from_imports == self.CurFromImportsPtr and self.CurFromImportsOrigs is not None:
|
||||
if self.CurFromImportsOrigs.__contains__(local_name) != 0:
|
||||
v_o: t.CPtr = self.CurFromImportsOrigs.__getitem__(local_name)
|
||||
if v_o is not None:
|
||||
return (str | t.CPtr)(v_o)
|
||||
# 索引未命中 | 值为 None(首个即无别名):绝不据此直接返回 None——
|
||||
# 真实串可能仍含该名,落到下方原逐字符扫描按串内容判定(正确性优先)。
|
||||
name_len: sizet = string.strlen(local_name)
|
||||
cur: str = from_imports
|
||||
ci: sizet = 0
|
||||
@@ -273,6 +421,22 @@ class ImportsGenMixin:
|
||||
"""
|
||||
if name is None or from_imports is None:
|
||||
return None
|
||||
# [索引快路径] 传入串即当前索引绑定的串 → O(名字长) 哈希查;否则回退扫描。
|
||||
# name 恰为 "*" 时与扫描一致:不做精确匹配,直接走 star 回退。
|
||||
if from_imports == self.CurFromImportsPtr and self.CurFromImportsMods is not None:
|
||||
name_is_star: int = 0
|
||||
if string.strlen(name) == 1 and name[0] == '*':
|
||||
name_is_star = 1
|
||||
if name_is_star == 0:
|
||||
v_f: t.CPtr = self.CurFromImportsMods.__getitem__(name)
|
||||
if v_f is not None:
|
||||
return (str | t.CPtr)(v_f)
|
||||
if allow_star_fallback != 0:
|
||||
sv_f: t.CPtr = self.CurFromImportsMods.__getitem__("*")
|
||||
if sv_f is not None:
|
||||
return (str | t.CPtr)(sv_f)
|
||||
# 索引精确名 | star 均未命中:绝不据此直接返回 None(索引不完整会漏报
|
||||
# "名已 import",_op_head NameError 即此类),落到下方原逐字符扫描按串内容判定。
|
||||
name_len: sizet = string.strlen(name)
|
||||
cur: str = from_imports
|
||||
ci: sizet = 0
|
||||
@@ -527,6 +691,14 @@ class ImportsGenMixin:
|
||||
# ============================================================
|
||||
def set_current_file(self, file_path: str) -> None:
|
||||
"""设置当前正在编译的文件名(与 HandlesType.set_current_file 同步调用)"""
|
||||
# 文件级失效:索引绑定的是上一文件 arena 内的串指针,本文件 reset 后该
|
||||
# 地址可能被新分配复用(如 _merge_template_imports 的合并串)→ 必须解绑,
|
||||
# 否则可能命中陈旧索引返回错误结果。本文件的索引由后续 add_* 重新建立。
|
||||
self.CurImportedModulesPtr = None
|
||||
self.CurImportedModulesNames = None
|
||||
self.CurFromImportsPtr = None
|
||||
self.CurFromImportsMods = None
|
||||
self.CurFromImportsOrigs = None
|
||||
self.Gen.TypeGenResolve.set_current_file(file_path)
|
||||
|
||||
# ============================================================
|
||||
@@ -834,4 +1006,10 @@ class ImportsGenMixin:
|
||||
self.ReexportFuncs = None
|
||||
self.ReexportSrcs = None
|
||||
self.ReexportCount = 0
|
||||
# 导入查找索引字段(索引表由 add_* 增量创建,PermPool 分配)
|
||||
self.CurImportedModulesPtr = None
|
||||
self.CurImportedModulesNames = None
|
||||
self.CurFromImportsPtr = None
|
||||
self.CurFromImportsMods = None
|
||||
self.CurFromImportsOrigs = None
|
||||
return 0
|
||||
@@ -845,6 +845,18 @@ class MatchGenMixin:
|
||||
first_check: int = -1
|
||||
i: int = 0
|
||||
while i < case_count:
|
||||
# 容量防线(与 _translate_match_simple / match-list 路径的
|
||||
# `collected < MAX_MATCH_CASES` 守卫对齐):默认 case(case _)
|
||||
# 分支此前**不校验** collected 就写 check_arr/body_arr/def_arr/
|
||||
# nb_arr/guard_arr[collected],case 数超过 MAX_MATCH_CASES 时
|
||||
# 越界写穿 pool 相邻块(可破坏相邻空闲块的 free-list next 指针)。
|
||||
# 不静默丢弃 case(会产出漏 case 的错误代码),直接 fail-fast。
|
||||
if collected >= MAX_MATCH_CASES:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
node,
|
||||
f"match case 数量超过上限 MAX_MATCH_CASES={MAX_MATCH_CASES}",
|
||||
"OverflowError")
|
||||
break
|
||||
case_node: ast.AST | t.CPtr = cases_list.get(i)
|
||||
if case_node is None or case_node.kind() != ast.ASTKind.MatchCase:
|
||||
i = i + 1
|
||||
|
||||
@@ -6,6 +6,7 @@ from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import hashtable
|
||||
import string
|
||||
import viperlib
|
||||
import stdio
|
||||
@@ -93,7 +94,17 @@ class TypeGenBase:
|
||||
# 用 malloc 而非 pool list——pool 每文件 reset_to 后 list 悬空(clear_ctypedefs
|
||||
# 未覆盖的路径读到已释放内存 → strcmp 崩溃,1.log 根因);malloc 跨 pool
|
||||
# 生命周期存活,clear_ctypedefs 释放置空。
|
||||
ImportAliasBuf: bytes
|
||||
ImportAliasBuf: bytes
|
||||
|
||||
# --- 库 typedef 按模块一次性门禁(_lookup_library_typedef 性能优化) ---
|
||||
# 库模块 typedef 缓存(PermPool 永久分配,跨文件/Phase 存活):
|
||||
# LibTypedefScannedMods: key=库模块名 → 已扫描标记(命中=该模块源已读并入缓存);
|
||||
# LibTypedefTypeMap: key="模块名|typedef 名" → 源中原始类型表达式。
|
||||
# 原实现每次查询都读 64KB 库源全文扫描(每个 Name 注解兜底连试 stdint/
|
||||
# w32.win32base 两次)→ 单文件 translate 7–12s 根因。缓存按模块名(内容)
|
||||
# 索引,库源单次编译内不变,故命中结果与逐次读源等价。| 不用全局裸表变量。
|
||||
LibTypedefScannedMods: hashtable.HashTable | t.CPtr
|
||||
LibTypedefTypeMap: hashtable.HashTable | t.CPtr
|
||||
|
||||
# --- 常量整数表达式计算成功标志(原 _g_const_eval_ok) ---
|
||||
ConstEvalOk: int
|
||||
@@ -137,7 +148,10 @@ class TypeGenBase:
|
||||
self.LastBuiltinsTypedefResult = None
|
||||
self.LastBuiltinsTypedefNameBuf = None
|
||||
self.LastBuiltinsTypedefResultBuf = None
|
||||
self.ImportAliasBuf = None
|
||||
self.ImportAliasBuf = None
|
||||
# 库 typedef 持久缓存字段(不随 clear_ctypedefs 复位 → 跨文件/Phase 存活)
|
||||
self.LibTypedefScannedMods = None
|
||||
self.LibTypedefTypeMap = None
|
||||
self.ConstEvalOk = 0
|
||||
self.CurrentFile = None
|
||||
self.Specs = None
|
||||
|
||||
@@ -34,13 +34,27 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
sys.maxsize = 9223372036854775807)必须全精度保存,否则 %d 32 位截断
|
||||
成 -1(0xFFFFFFFF)→ 读回 4294967295(SysLibTest maxsize FAIL 根因)。
|
||||
0xFFFFFFFF 仍存为 "4294967295",常量生成端 const_int32 内部截断回 -1。
|
||||
|
||||
名称深拷贝到 pool(与 register_xmod_cdefine 对 key 深拷贝同一教训):
|
||||
调用方传入的 name 可能指向临时缓冲——VpiReader 注入 .vpi 时 Name.id 是
|
||||
零拷贝指向 vpi_buf(见 ParseVpiIntoModule 的 token 零拷贝注释),而
|
||||
vpi_buf 在注入函数末尾即 stdlib.free。只存指针会让 CDefineNames 持有
|
||||
悬空名:之后 lookup 的 strcmp 若命中被回收/复用内存里恰好出现的同名文本,
|
||||
就会返回别的条目的值(Phase1.SHA1_LEN=17 被读成 0 的根因)。
|
||||
"""
|
||||
if name is None:
|
||||
return
|
||||
if self.CDefineNames is None:
|
||||
self.CDefineNames = list[str](pool, 64)
|
||||
self.CDefineValues = list[str](pool, 64)
|
||||
self.CDefineDoubleFlags = list[int](pool, 64)
|
||||
self.CDefineStrFlags = list[int](pool, 64)
|
||||
self.CDefineNames.append(name)
|
||||
name_copy: str = pool.alloc(string.strlen(name) + 1)
|
||||
if name_copy is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine '{name}' 名称缓冲区分配失败", "MemoryError")
|
||||
return
|
||||
string.strcpy(name_copy, name)
|
||||
self.CDefineNames.append(name_copy)
|
||||
val_buf: str = pool.alloc(32)
|
||||
if val_buf is not None:
|
||||
viperlib.snprintf(val_buf, 32, "%lld", value)
|
||||
@@ -60,13 +74,23 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
"""注册浮点 CDefine 编译期常量(如 U_M_PI: t.CDefine = 3.14159...)
|
||||
|
||||
值以 %f 文本存储并标记浮点,供 translate_value 返回浮点常量。
|
||||
|
||||
名称同样深拷贝到 pool(理由见 register_cdefine_constant:注入 .vpi 时
|
||||
Name.id 指向的 vpi_buf 会被释放,只存指针会留下悬空名)。
|
||||
"""
|
||||
if name is None:
|
||||
return
|
||||
if self.CDefineNames is None:
|
||||
self.CDefineNames = list[str](pool, 64)
|
||||
self.CDefineValues = list[str](pool, 64)
|
||||
self.CDefineDoubleFlags = list[int](pool, 64)
|
||||
self.CDefineStrFlags = list[int](pool, 64)
|
||||
self.CDefineNames.append(name)
|
||||
name_copy_d: str = pool.alloc(string.strlen(name) + 1)
|
||||
if name_copy_d is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine 浮点 '{name}' 名称缓冲区分配失败", "MemoryError")
|
||||
return
|
||||
string.strcpy(name_copy_d, name)
|
||||
self.CDefineNames.append(name_copy_d)
|
||||
val_buf: str = pool.alloc(32)
|
||||
if val_buf is not None:
|
||||
# 用 CRT stdio.snprintf 而非 viperlib.snprintf:viperlib 自实现格式化器的
|
||||
@@ -89,7 +113,8 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
"""注册字符串 CDefine 编译期常量(如 ZLIB_VERSION: t.CDefine = "1.3.2")
|
||||
|
||||
字符串值深拷贝到 pool(AST 节点的 str_val 可能被 pool 操作覆写,
|
||||
与浮点 CDefine 的恢复同理)。
|
||||
与浮点 CDefine 的恢复同理)。名称同样深拷贝(理由见
|
||||
register_cdefine_constant:注入 .vpi 的 Name.id 指向会被释放的 vpi_buf)。
|
||||
"""
|
||||
if pool is None or name is None:
|
||||
return
|
||||
@@ -101,7 +126,12 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
self.CDefineValues = list[str](pool, 64)
|
||||
self.CDefineDoubleFlags = list[int](pool, 64)
|
||||
self.CDefineStrFlags = list[int](pool, 64)
|
||||
self.CDefineNames.append(name)
|
||||
ncopy_s: str = pool.alloc(string.strlen(name) + 1)
|
||||
if ncopy_s is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine 字符串 '{name}' 名称缓冲区分配失败", "MemoryError")
|
||||
return
|
||||
string.strcpy(ncopy_s, name)
|
||||
self.CDefineNames.append(ncopy_s)
|
||||
vlen: sizet = string.strlen(value)
|
||||
vcopy: str = pool.alloc(vlen + 1)
|
||||
if vcopy is None:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import lib.core.Gen.GenApi as GenApi
|
||||
import lib.core.Gen.Generator as Generator
|
||||
import lib.core.Gen.Type.TypeGenCType as TypeGenCType
|
||||
import lib.core.Gen.Type.TypeGenMixin as TypeGenMixin
|
||||
@@ -7,6 +8,7 @@ from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import hashtable
|
||||
import string
|
||||
import viperlib
|
||||
import stdio
|
||||
@@ -1054,6 +1056,83 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if b_final_r is not None:
|
||||
return b_final_r
|
||||
return None
|
||||
def _register_lib_typedef_cache(self, mod: str, name_src: str,
|
||||
name_len: sizet, type_str: str) -> None:
|
||||
"""把库模块源中的一条 typedef 写入持久缓存(PermPool,同名首次为准)
|
||||
|
||||
key = "模块名|typedef 名"(模块名/typedef 名均为标识符,不含 '|')。
|
||||
首次扫描某模块时对该模块全部 typedef 调用一次;结果跨文件/Phase 存活,
|
||||
后续同模块查询只查表,不再读库源。
|
||||
"""
|
||||
if mod is None or name_src is None or type_str is None or name_len == 0:
|
||||
return
|
||||
perm: rowptr[memhub.MemBuddy] = CompilerFactory.factory.PermPool
|
||||
if perm is None:
|
||||
return
|
||||
if self.LibTypedefTypeMap is None:
|
||||
self.LibTypedefTypeMap = hashtable.HashTable(perm)
|
||||
if self.LibTypedefTypeMap is None:
|
||||
return
|
||||
mod_len: sizet = string.strlen(mod)
|
||||
key_len: sizet = mod_len + 1 + name_len
|
||||
key_buf: str = perm.alloc(key_len + 1)
|
||||
if key_buf is None:
|
||||
return
|
||||
string.strncpy(key_buf, mod, mod_len)
|
||||
key_buf[mod_len] = '|'
|
||||
string.strncpy(key_buf + mod_len + 1, name_src, name_len)
|
||||
key_buf[key_len] = '\0'
|
||||
# 同名首次为准(与逐次读源命中第一处声明的语义一致)
|
||||
if self.LibTypedefTypeMap.__contains__(key_buf) != 0:
|
||||
return
|
||||
tlen: sizet = string.strlen(type_str)
|
||||
type_copy: str = perm.alloc(tlen + 1)
|
||||
if type_copy is None:
|
||||
return
|
||||
string.strcpy(type_copy, type_str)
|
||||
self.LibTypedefTypeMap.set_str(key_buf, type_copy)
|
||||
def _mark_lib_module_scanned(self, mod: str) -> None:
|
||||
"""置库模块「已扫描」标记(PermPool 持久):其后同模块查询只查缓存表"""
|
||||
if mod is None:
|
||||
return
|
||||
# 缓存表未建成(PermPool 分配失败)时不得置标记——否则后续查询只查空表
|
||||
# 会误返回 None(改变语义);此时不标记、留待下次重试读源。
|
||||
if self.LibTypedefTypeMap is None:
|
||||
return
|
||||
perm: rowptr[memhub.MemBuddy] = CompilerFactory.factory.PermPool
|
||||
if perm is None:
|
||||
return
|
||||
if self.LibTypedefScannedMods is None:
|
||||
self.LibTypedefScannedMods = hashtable.HashTable(perm)
|
||||
if self.LibTypedefScannedMods is None:
|
||||
return
|
||||
if self.LibTypedefScannedMods.__contains__(mod) != 0:
|
||||
return
|
||||
mlen: sizet = string.strlen(mod)
|
||||
mcopy: str = perm.alloc(mlen + 1)
|
||||
if mcopy is None:
|
||||
return
|
||||
string.strcpy(mcopy, mod)
|
||||
self.LibTypedefScannedMods.set_str(mcopy, mcopy)
|
||||
def _lookup_lib_typedef_cache(self, mod: str, attr: str) -> str:
|
||||
"""查持久缓存表:命中返回该模块源中的原始类型表达式,未命中返回 None"""
|
||||
if self.LibTypedefTypeMap is None or mod is None or attr is None:
|
||||
return None
|
||||
mod_len: sizet = string.strlen(mod)
|
||||
attr_len: sizet = string.strlen(attr)
|
||||
key_len: sizet = mod_len + 1 + attr_len
|
||||
key_buf: bytes = stdlib.malloc(key_len + 1)
|
||||
if key_buf is None:
|
||||
return None
|
||||
string.strncpy(key_buf, mod, mod_len)
|
||||
key_buf[mod_len] = '|'
|
||||
string.strncpy(key_buf + mod_len + 1, attr, attr_len)
|
||||
key_buf[key_len] = '\0'
|
||||
v: t.CPtr = self.LibTypedefTypeMap.__getitem__(key_buf)
|
||||
stdlib.free(key_buf)
|
||||
if v is None:
|
||||
return None
|
||||
return (str | t.CPtr)(v)
|
||||
def _lookup_library_typedef(self, pool: rowptr[memhub.MemBuddy],
|
||||
mod: str, attr: str) -> str:
|
||||
"""查库模块源文件中 "attr: t.CTypedef = TYPE" 并注册,返回 TYPE 或 None
|
||||
@@ -1062,6 +1141,11 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
`size_t: t.CTypedef = stdint.size_t` 的 stdint.size_t 部分):
|
||||
直接读模块源扫描 typedef(权威定义),miss 不查表——表内可能是
|
||||
builtins 的间接引用(stdint.size_t → 自身)会自引用死循环。
|
||||
|
||||
[按模块一次性门禁] 首次遇到某库模块:读一次源、把该模块全部 typedef
|
||||
写入持久缓存(PermPool)并置「已扫描」标记;之后同一模块的查询只查
|
||||
缓存表,不再做文件 I/O 与全文扫描。缓存按模块名(内容)索引,库源在
|
||||
单次编译内不变,故命中值与逐次读源等价。| miss 仍返回 None。
|
||||
"""
|
||||
if mod is None or attr is None:
|
||||
return None
|
||||
@@ -1071,6 +1155,14 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
m_real: str = self._resolve_import_alias(mod)
|
||||
if m_real is None:
|
||||
m_real = mod
|
||||
# [门禁命中] 该库模块源已扫描过 → 只查持久缓存表,不再读文件;
|
||||
# 命中值仍注册进当前文件 CTypedef 表(保持原实现每次读源命中的副作用)。
|
||||
if self.LibTypedefScannedMods is not None:
|
||||
if self.LibTypedefScannedMods.__contains__(m_real) != 0:
|
||||
ts_hit: str = self._lookup_lib_typedef_cache(m_real, attr)
|
||||
if ts_hit is not None:
|
||||
self.Gen.TypeGenCType.register_ctypedef(pool, attr, ts_hit)
|
||||
return ts_hit
|
||||
m_sha1: str = StubMergerStore.LookupSha1ByModName(m_real)
|
||||
m_path: str = self._build_lib_source_path(m_real, m_sha1)
|
||||
if m_path is None:
|
||||
@@ -1097,7 +1189,9 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
m_i: sizet = 0
|
||||
m_ls: sizet = 0
|
||||
m_res: str = None
|
||||
while m_i <= m_total and m_res is None:
|
||||
# 全文件扫描(不再在首次命中处提前退出):既为该模块建立完整持久缓存,
|
||||
# 又用与原实现相同的比较取 attr 的首次命中值(保证首次调用返回值不变)。
|
||||
while m_i <= m_total:
|
||||
if m_i == m_total or m_buf[m_i] == '\n':
|
||||
m_line_len: sizet = m_i - m_ls
|
||||
if m_line_len > 0:
|
||||
@@ -1115,39 +1209,46 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
m_nl: sizet = m_j
|
||||
while m_nl > 0 and m_buf[m_ls + m_nl - 1] == ' ':
|
||||
m_nl -= 1
|
||||
if m_nl == attr_len:
|
||||
m_nm_ok: int = 1
|
||||
m_ki: sizet = 0
|
||||
while m_ki < attr_len:
|
||||
if m_buf[m_ls + m_ki] != attr[m_ki]:
|
||||
m_nm_ok = 0
|
||||
break
|
||||
m_ki += 1
|
||||
if m_nm_ok == 1:
|
||||
m_rest: str = m_buf + m_ls + m_j + 1
|
||||
if string.strstr(m_rest, "t.CTypedef") is not None:
|
||||
m_eq: str = string.strstr(m_rest, "=")
|
||||
if m_eq is not None:
|
||||
# '=' 相对行首偏移;值段严格限定在行尾
|
||||
# (m_line_len)内,防止跨行吞换行+后续内容
|
||||
m_eq_off: sizet = sizet(uint64(m_eq) - uint64(m_buf)) - m_ls
|
||||
m_vs: sizet = m_eq_off + 1
|
||||
while m_vs < m_line_len and m_buf[m_ls + m_vs] == ' ':
|
||||
m_vs += 1
|
||||
m_ve: sizet = m_line_len
|
||||
while m_ve > m_vs and (m_buf[m_ls + m_ve - 1] == ' '
|
||||
or m_buf[m_ls + m_ve - 1] == '\r'):
|
||||
m_ve -= 1
|
||||
if m_ve > m_vs:
|
||||
m_vlen: sizet = m_ve - m_vs
|
||||
m_tb: str = pool.alloc(m_vlen + 1)
|
||||
if m_tb is not None:
|
||||
string.strncpy(m_tb, m_buf + m_ls + m_vs, m_vlen)
|
||||
m_tb[m_vlen] = '\0'
|
||||
self.Gen.TypeGenCType.register_ctypedef(pool, attr, m_tb)
|
||||
m_rest: str = m_buf + m_ls + m_j + 1
|
||||
if string.strstr(m_rest, "t.CTypedef") is not None:
|
||||
m_eq: str = string.strstr(m_rest, "=")
|
||||
if m_eq is not None:
|
||||
# '=' 相对行首偏移;值段严格限定在行尾
|
||||
# (m_line_len)内,防止跨行吞换行+后续内容
|
||||
m_eq_off: sizet = sizet(uint64(m_eq) - uint64(m_buf)) - m_ls
|
||||
m_vs: sizet = m_eq_off + 1
|
||||
while m_vs < m_line_len and m_buf[m_ls + m_vs] == ' ':
|
||||
m_vs += 1
|
||||
m_ve: sizet = m_line_len
|
||||
while m_ve > m_vs and (m_buf[m_ls + m_ve - 1] == ' '
|
||||
or m_buf[m_ls + m_ve - 1] == '\r'):
|
||||
m_ve -= 1
|
||||
if m_ve > m_vs:
|
||||
m_vlen: sizet = m_ve - m_vs
|
||||
m_tb: str = pool.alloc(m_vlen + 1)
|
||||
if m_tb is not None:
|
||||
string.strncpy(m_tb, m_buf + m_ls + m_vs, m_vlen)
|
||||
m_tb[m_vlen] = '\0'
|
||||
# 写入持久缓存(首次遇到的名字为准)
|
||||
self._register_lib_typedef_cache(
|
||||
m_real, m_buf + m_ls, m_nl, m_tb)
|
||||
# 原实现语义:attr 的首次匹配值
|
||||
if m_res is None and m_nl == attr_len:
|
||||
m_nm_ok: int = 1
|
||||
m_ki: sizet = 0
|
||||
while m_ki < attr_len:
|
||||
if m_buf[m_ls + m_ki] != attr[m_ki]:
|
||||
m_nm_ok = 0
|
||||
break
|
||||
m_ki += 1
|
||||
if m_nm_ok == 1:
|
||||
m_res = m_tb
|
||||
m_ls = m_i + 1
|
||||
m_i += 1
|
||||
# 置该模块已扫描标记:同模块后续查询只查持久缓存表,不再重复读源
|
||||
self._mark_lib_module_scanned(m_real)
|
||||
if m_res is not None:
|
||||
self.Gen.TypeGenCType.register_ctypedef(pool, attr, m_res)
|
||||
stdlib.free(m_buf)
|
||||
return m_res
|
||||
def _expand_typedef_ref(self, pool: rowptr[memhub.MemBuddy],
|
||||
@@ -1625,15 +1726,15 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
return self.extract_class_name_from_annotation(
|
||||
sub.slice, imported_modules, pool, from_imports)
|
||||
return None
|
||||
# [D25 根因修复] 递归取 base 时必须把 `from_imports` 一并下传:
|
||||
# 此前这里丢掉了第 4 个参数,导致同一份注解在「派发名(本函数)/
|
||||
# 查表键(_resolve_generic_subscript_ty)/ 注册键(_specialize_generic_class)」
|
||||
# 三处算出的 mangled 名可能不同 —— 例如 `list[ast.AST | t.CPtr]` 的
|
||||
# 元素段在带/不带 from_imports 时规范化结果不一致,进而出现
|
||||
# 「alloca 是裸 list*、pass1 按 list[ast.ASTptr] 解释、pass2 按
|
||||
# list[ast.ClassDefptr] 解释」的分裂(MatchGenMixin._handle_renum_match
|
||||
# 崩溃根因,见 Debugger/_Type.md D25)。其余调用点(1625、1650 等)均已传。
|
||||
base_name: str = self.extract_class_name_from_annotation(
|
||||
# [D25 根因修复] 递归取 base 时必须把 `from_imports` 一并下传:
|
||||
# 此前这里丢掉了第 4 个参数,导致同一份注解在「派发名(本函数)/
|
||||
# 查表键(_resolve_generic_subscript_ty)/ 注册键(_specialize_generic_class)」
|
||||
# 三处算出的 mangled 名可能不同 —— 例如 `list[ast.AST | t.CPtr]` 的
|
||||
# 元素段在带/不带 from_imports 时规范化结果不一致,进而出现
|
||||
# 「alloca 是裸 list*、pass1 按 list[ast.ASTptr] 解释、pass2 按
|
||||
# list[ast.ClassDefptr] 解释」的分裂(MatchGenMixin._handle_renum_match
|
||||
# 崩溃根因,见 Debugger/_Type.md D25)。其余调用点(1625、1650 等)均已传。
|
||||
base_name: str = self.extract_class_name_from_annotation(
|
||||
sub.value, imported_modules, pool, from_imports)
|
||||
if base_name is None:
|
||||
return None
|
||||
@@ -2202,8 +2303,8 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# SHA1 前缀形态优先用完整名 "{sha1}.{Class}" 精确命中定义侧
|
||||
# struct(get_struct_type 类名回退可能命中跨模块同名类)
|
||||
full_attr_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
# val_name.id 是模块名段:恰为 16 位小写 hex 才是 SHA1 别名
|
||||
#(判定走唯一真源 GenApi.is_sha1_hex16,C10 收敛)。
|
||||
# val_name.id 是模块名段:恰为 16 位小写 hex 才是 SHA1 别名
|
||||
#(判定走唯一真源 GenApi.is_sha1_hex16,C10 收敛)。
|
||||
if is_builtin_attr == 0 and GenApi.is_sha1_hex16(val_name.id) != 0:
|
||||
full_q: str = self._concat_sha1_class(pool, val_name.id, at.attr)
|
||||
if full_q is not None:
|
||||
|
||||
Reference in new issue
Block a user