fix(core): 跨模块 CDefine 查找缓存 perm_pool + list 内置方法识别

1. _lookup_cross_module_cdefine:lookup_from_import 返回非 NUL 结尾内部指针,
   base_mod 未截断导致 rc_full_mod 每层累积整个 from_imports + ".base"
   (dump:ast.base.base.base 无限递归根因)。入口截断模块名 + 缓存查询/写入
   key 统一用 base_mod;结果缓存到 perm_pool(XmodCdef 表)跨文件复用,
   CONST_INT 递归查找只做一次。
2. translate_call:obj.method 检测将 list[AST|CPtr] 特化 struct 误当普通结构体,
   查 append 返回类型(函数/text.ll/vpi 均未命中)fail-fast。新增
   _is_list_builtin_method 识别 list 内置方法,在 Ptr(Struct)/Ptr(Ptr)/
   AnnotClassName 三条路径跳过,落到 list 内置分支。
3. HandlesType 新增 register/lookup_xmod_cdefine 模块级委托(Mixin 隔离)。
This commit is contained in:
TermiNexus committed 2026-08-15 00:15:43 +08:00
1 parent f7c2fe4534
commit f9878e5a63
5 files changed
+374 -74

No files matched your search

+120 -62
View File
@@ -2018,9 +2018,14 @@ class CallGenMixin:
OOP 结构体:alloca → call __before_init__(ptr) → call __init__(ptr, args) 或 store 参数 → load
普通结构体:alloca → zero + defaults → store 参数 → load
"""
# OOM 诊断:结构体构造入口 used(定位跨模块类构造语句暴涨段)
stdio.printf("[MEM] struct_ctor %s can=%d used=%zu chk=%zu\n",
class_name, can, pool.used_bytes(), pool.chk_depth)
# 创建临时 alloca
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty)
stdio.printf("[MEM] struct_ctor %s after_ensure used=%zu chk=%zu\n",
class_name, pool.used_bytes(), pool.chk_depth)
tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty)
if tmp is None:
return llvmlite.ConstZero(pool, struct_ty)
@@ -2078,6 +2083,9 @@ class CallGenMixin:
new_arg_node: ast.AST | t.CPtr = cargs.get(nai)
if new_arg_node is None:
continue
# OOM 诊断:__new__ 参数逐个打印 used(定位第几个参数暴涨)
stdio.printf("[MEM] struct_ctor %s newarg %d used=%zu chk=%zu\n",
class_name, nai, pool.used_bytes(), pool.chk_depth)
new_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, new_arg_node, None, 0, trans)
if new_av is not None:
@@ -2541,6 +2549,9 @@ class CallGenMixin:
node: 触发本次调用的 AST 节点(如 Subscript 下标节点),用于 fatal_error
准确报告出错行号(传 None 时行号显示 0,不利于定位)。"""
# OOM 诊断:方法调用入口 used(定位 __init__/__before_init__ 跨模块调用段)
stdio.printf("[MEM] method_on_ptr %s.%s used=%zu chk=%zu\n",
class_name, method_name, pool.used_bytes(), pool.chk_depth)
if pool is None or builder is None or class_name is None or method_name is None:
return None
if self_ptr is None:
@@ -3619,6 +3630,38 @@ class CallGenMixin:
return self._translate_property_call(pool, builder, mod, class_name,
method_name, head, total_count, trans)
# ============================================================
# _is_list_builtin_method - 判断是否是 list 泛型内置容器方法
#
# list[T] 是内置泛型容器(_list.vp),其方法(append/get/set/pop/clear/
# __iter__/__len__/__getitem__/__setitem__)由 translate_call 的 list
# 内置分支内联 GEP 处理,不注册为方法函数。若 obj.method() 检测把
# list 特化 struct(如 list[AST | CPtr])误当普通结构体走
# _translate_method_call,会查不到 append 返回类型 → fail-fast
# (NewAstTest body.append 根因)。此判断用于跳过 method_call 路径。
#
# 返回: 1=list 内置方法(应落到 list 内置分支),0=普通方法
# ============================================================
def _is_list_builtin_method(self, class_name: str,
method_name: str) -> int:
"""判断 (class_name, method_name) 是否是 list 泛型内置方法"""
if class_name is None or method_name is None:
return 0
# 类名必须以 "list" 开头(list / list[AST | CPtr] 特化名)
if string.strncmp(class_name, "list", 4) != 0:
return 0
# 方法名必须是 list 内置方法集合
if string.strcmp(method_name, "append") == 0: return 1
if string.strcmp(method_name, "get") == 0: return 1
if string.strcmp(method_name, "set") == 0: return 1
if string.strcmp(method_name, "pop") == 0: return 1
if string.strcmp(method_name, "clear") == 0: return 1
if string.strcmp(method_name, "__iter__") == 0: return 1
if string.strcmp(method_name, "__len__") == 0: return 1
if string.strcmp(method_name, "__getitem__") == 0: return 1
if string.strcmp(method_name, "__setitem__") == 0: return 1
return 0
# ============================================================
# _translate_method_call - 翻译方法调用 obj.method(args)
#
@@ -5644,9 +5687,16 @@ class CallGenMixin:
class_nm: str = HandlesStruct.get_class_name_by_type(
pool, obj_struct_ty)
if class_nm is not None:
return self._translate_method_call(
pool, builder, mod, class_nm, func_name,
obj_var, cl, trans)
# list 泛型内置容器方法(append/get/set/pop/clear/__iter__/
# __len__/__getitem__/__setitem__)由下方 list 内置分支
# (L5848 起)内联 GEP 处理,不注册方法函数;若走
# _translate_method_call 会查 append 返回类型(函数/text.ll/
# vpi stub 均未命中)→ fail-fast。检测到 list 方法时
# 跳过 method_call,落到内置分支(NewAstTest body.append 根因)。
if self._is_list_builtin_method(class_nm, func_name) == 0:
return self._translate_method_call(
pool, builder, mod, class_nm, func_name,
obj_var, cl, trans)
# 指针变量: alloca 类型是 Ptr(Ptr(Struct))
# load 获取实际指针 Ptr(Struct) 后再查找
match obj_struct_ty:
@@ -5654,12 +5704,14 @@ class CallGenMixin:
inner_nm: str = HandlesStruct.get_class_name_by_type(
pool, inner_struct_ty)
if inner_nm is not None:
obj_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, obj_struct_ty, obj_var)
if obj_ptr is not None:
return self._translate_method_call(
pool, builder, mod, inner_nm, func_name,
obj_ptr, cl, trans)
# list 内置方法同样跳过(同 Ptr(Struct) 分支)
if self._is_list_builtin_method(inner_nm, func_name) == 0:
obj_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, obj_struct_ty, obj_var)
if obj_ptr is not None:
return self._translate_method_call(
pool, builder, mod, inner_nm, func_name,
obj_ptr, cl, trans)
# AnnotClassName 回退:联合类型简化为 Ptr(i8) 时,
# 通过原始类型注解的类名查找结构体
var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
@@ -5681,60 +5733,66 @@ class CallGenMixin:
mod_nm2[mod_len2] = '\0'
# 检查结构体是否已注册
if HandlesStruct.get_struct_type(cls_nm2) is not None:
# 结构体已注册:load obj_ptr 走方法调用
i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
pool, llvmlite.Int8(pool))
obj_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, i8_ptr_ty2, obj_var)
if obj_ptr2 is not None:
return self._translate_method_call(
pool, builder, mod, cls_nm2, func_name,
obj_ptr2, cl, trans)
# list 内置方法跳过 method_call(同 Ptr(Struct) 分支),
# 落到下方 list 内置分支
if self._is_list_builtin_method(cls_nm2, func_name) == 0:
# 结构体已注册:load obj_ptr 走方法调用
i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
pool, llvmlite.Int8(pool))
obj_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, i8_ptr_ty2, obj_var)
if obj_ptr2 is not None:
return self._translate_method_call(
pool, builder, mod, cls_nm2, func_name,
obj_ptr2, cl, trans)
else:
# 结构体未注册(跨模块依赖未翻译):
# 用模块名查 SHA1 构造方法调用名
sha1_fc: str = None
if mod_nm2 is not None:
sha1_fc = self._lookup_module_sha1(mod_nm2)
if sha1_fc is not None:
# 构造 "{sha1}.{cls_nm2}.{func_name}" 调用名
mlen3: t.CSizeT = string.strlen(sha1_fc) + string.strlen(cls_nm2) + string.strlen(func_name) + 3
mangled3: str = pool.alloc(mlen3)
if mangled3 is not None:
viperlib.snprintf(mangled3, mlen3, "%s.%s.%s", sha1_fc, cls_nm2, func_name)
# load obj_ptr (self)
i8_ptr_ty3: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
pool, llvmlite.Int8(pool))
obj_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, i8_ptr_ty3, obj_var)
if obj_ptr3 is not None:
# 构建参数链表: obj_ptr3 (self) → 其他参数
llvmlite.value_set_next(obj_ptr3, None)
head3: llvmlite.Value | t.CPtr = obj_ptr3
tail3: llvmlite.Value | t.CPtr = obj_ptr3
for ai3 in range(can):
arg3: ast.AST | t.CPtr = cargs.get(ai3)
if arg3 is not None:
arg_val3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg3, None, 0, trans)
if arg_val3 is not None:
llvmlite.value_set_next(arg_val3, None)
llvmlite.value_set_next(tail3, arg_val3)
tail3 = arg_val3
total3: int = 1 + can
ret_ty3: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(
pool, cls_nm2, func_name)
if ret_ty3 is None:
ret_ty3 = self._LookupMethodRetTyFromTextLL(
pool, sha1_fc, cls_nm2, func_name)
if ret_ty3 is None:
# 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单)
ret_ty3 = self._lookup_method_ret_ty_via_vpi(
pool, sha1_fc, cls_nm2, func_name)
if ret_ty3 is None:
ret_ty3 = self._fail_method_ret_ty(func_name)
self._ensure_method_declare(pool, mod, mangled3, ret_ty3, head3, total3)
return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0)
# list 内置方法跳过(结构体未注册路径同样不能
# 构造 {sha1}.{cls}.append 调用名——list 方法无此函数)
if self._is_list_builtin_method(cls_nm2, func_name) == 0:
# 结构体未注册(跨模块依赖未翻译):
# 用模块名查 SHA1 构造方法调用名
sha1_fc: str = None
if mod_nm2 is not None:
sha1_fc = self._lookup_module_sha1(mod_nm2)
if sha1_fc is not None:
# 构造 "{sha1}.{cls_nm2}.{func_name}" 调用名
mlen3: t.CSizeT = string.strlen(sha1_fc) + string.strlen(cls_nm2) + string.strlen(func_name) + 3
mangled3: str = pool.alloc(mlen3)
if mangled3 is not None:
viperlib.snprintf(mangled3, mlen3, "%s.%s.%s", sha1_fc, cls_nm2, func_name)
# load obj_ptr (self)
i8_ptr_ty3: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
pool, llvmlite.Int8(pool))
obj_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, i8_ptr_ty3, obj_var)
if obj_ptr3 is not None:
# 构建参数链表: obj_ptr3 (self) → 其他参数
llvmlite.value_set_next(obj_ptr3, None)
head3: llvmlite.Value | t.CPtr = obj_ptr3
tail3: llvmlite.Value | t.CPtr = obj_ptr3
for ai3 in range(can):
arg3: ast.AST | t.CPtr = cargs.get(ai3)
if arg3 is not None:
arg_val3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg3, None, 0, trans)
if arg_val3 is not None:
llvmlite.value_set_next(arg_val3, None)
llvmlite.value_set_next(tail3, arg_val3)
tail3 = arg_val3
total3: int = 1 + can
ret_ty3: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(
pool, cls_nm2, func_name)
if ret_ty3 is None:
ret_ty3 = self._LookupMethodRetTyFromTextLL(
pool, sha1_fc, cls_nm2, func_name)
if ret_ty3 is None:
# 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单)
ret_ty3 = self._lookup_method_ret_ty_via_vpi(
pool, sha1_fc, cls_nm2, func_name)
if ret_ty3 is None:
ret_ty3 = self._fail_method_ret_ty(func_name)
self._ensure_method_declare(pool, mod, mangled3, ret_ty3, head3, total3)
return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0)
# ============================================================
# 检测表达式接收者方法调用: (expr).method(args)
+138 -12
View File
@@ -80,6 +80,13 @@ class ExprGenMixin:
DocValues: bytes
DocCount: int
# --- OOM 诊断:跨模块 CDefine 查找调用计数(CONST_INT 参数翻译疑似循环查找) ---
DiagCDefineCount: int
# --- OOM 诊断:translate_name_value 调用计数(顶层 CDefine 查找 14593 次来源) ---
DiagNameValueCount: int
# --- OOM 诊断:translate_value 调用计数(CONST_INT 循环调用源定位) ---
DiagTranslateValueCount: int
# ============================================================
# P3 迁移方法(函数体来自 HandlesExpr.vp 模块级函数,
# 本模块函数调用改 self.,外部模块调用保留模块前缀)
@@ -919,6 +926,12 @@ class ExprGenMixin:
"""翻译值表达式为 LLVM Value"""
if node is None:
return None
# OOM 诊断:translate_value 调用计数(每 4096 次打印 kind+行号,定位 CONST_INT 循环调用源)
self.DiagTranslateValueCount += 1
if (self.DiagTranslateValueCount % 4096) == 1:
stdio.printf("[MEM] trans_val %d kind=%d line=%d used=%zu chk=%zu\n",
self.DiagTranslateValueCount, node.kind(), node.lineno,
pool.used_bytes(), pool.chk_depth)
k: int = node.kind()
if k == ast.ASTKind.Constant:
rv: llvmlite.Value | t.CPtr = self.translate_constant(builder, pool, mod, node, trans)
@@ -2240,7 +2253,9 @@ class ExprGenMixin:
def _lookup_cross_module_cdefine(self, pool: memhub.MemBuddy | t.CPtr,
name: str,
from_imports: str,
imported_modules: str = None) -> int:
imported_modules: str = None,
depth: int = 0,
node: ast.AST | t.CPtr = None) -> int:
"""跨模块查找 CDefine 常量,返回值或 -1(未找到)
查找顺序:
@@ -2248,7 +2263,27 @@ class ExprGenMixin:
2. from_imports star 回退(from X import *)
3. imported_modules 遍历(import X):当通过 import X 导入模块时,
模块中定义的 CDefine 常量可通过此路径找到(如方法签名默认参数引用)
depth: 递归深度(子模块递归/imported_modules 遍历的内部调用递增)。
node: 触发查找的 AST 节点(递归内传 None,line 0;顶层调用点传实际节点)。
"""
# 递归深度守卫:子模块递归(from .X import NAME re-export 链)与
# imported_modules 遍历组合可能形成循环(模块间互相 from import),
# 无上限时无限递归 → 每次递归 pool.alloc 缓冲(rc_sub_buf/rc_full_mod/
# rc_fi/im_buf/sub_fi)→ O(n²) 累积 → 主池 1.5GB OOM
# (NewAstTest CONST_INT 单次查找 14593 次调用,fi 恒为 CONST_INT:ast)。
# 正常跨模块 CDefine 查找深度 < 8(如 ast → ast.base),32 上限 fail-fast
# 暴露循环 import 链(而非静默 OOM)。报错带 node 行号 + 当前递归模块链。
if depth > 32:
err_buf: str = pool.alloc(256)
if err_buf is not None:
viperlib.snprintf(err_buf, 256,
"跨模块 CDefine 查找递归过深(疑似模块循环 import/re-export): %s (depth=%d fi=%s)",
name, depth,
from_imports if from_imports is not None else "(nil)")
HandlesType.fatal_error(node, err_buf, "InternalCompilerError")
HandlesType.fatal_error(node,
"跨模块 CDefine 查找递归过深(疑似模块循环 import/re-export)", "InternalCompilerError")
# 入口处清零标志,确保所有早退路径(return -1)都返回"未找到"状态
# 避免递归调用时前一次成功的标志残留导致误判
HandlesType.set_cdefine_found(0)
@@ -2257,6 +2292,14 @@ class ExprGenMixin:
if from_imports is None:
from_imports = ""
# OOM 诊断:跨模块 CDefine 查找调用计数(每 256 次打印 used)
self.DiagCDefineCount += 1
if (self.DiagCDefineCount % 256) == 1:
stdio.printf("[MEM] cdefine_lookup %d name=%s fi=%.16s used=%zu chk=%zu\n",
self.DiagCDefineCount, name,
from_imports if from_imports is not None else "(nil)",
pool.used_bytes(), pool.chk_depth)
# 1. 从 from_imports 查找名称对应的模块名
# 先尝试精确匹配(allow_star_fallback=0),避免 CDefine 常量被 star import 误导
mod_name_raw: str = HandlesImports.lookup_from_import(from_imports, name, 0)
@@ -2264,14 +2307,53 @@ class ExprGenMixin:
# 精确匹配失败:尝试 star import 回退
mod_name_raw = HandlesImports.lookup_from_import(from_imports, name, 1)
# 当前模块名(去前导点),用于构建子模块全名 base_mod.X(如 "hashlib" + "." +
# "__md5")。此前 base_mod 未赋值(未初始化变量)→ 子模块递归 strlen(NULL)
# 崩溃(ASan access-violation,Attribute count 新路径触发 _lookup_cross_module_cdefine)。
base_mod: str = mod_name_raw
if base_mod is not None:
while base_mod[0] == '.':
# 截断模块名到 NUL 结尾:lookup_from_import 返回指向 from_imports 内部的
# 指针(非 NUL 结尾,后随空格分隔的其他条目,如 "ast CONST_STR:ast ...")。
# 不截断会污染 base_mod:strlen 读到整个 from_imports 末尾 → rc_full_mod
# 每层累积整个列表 + ".base"(dump:ast.base.base.base 无限递归根因),
# 且缓存 key 错乱("CONST_INT@ast CONST_STR:ast ...")无法命中。
# 与 _lookup_sha1_from_modname_raw 的截断逻辑一致(空格/冒号/NUL 分隔)。
base_mod: str = None
if mod_name_raw is not None:
mbl: t.CSizeT = 0
while mod_name_raw[mbl] != ' ' and mod_name_raw[mbl] != '\0' \
and mod_name_raw[mbl] != ':':
mbl += 1
mb_buf: str = pool.alloc(mbl + 1)
if mb_buf is not None:
mi2: t.CSizeT
for mi2 in range(mbl):
mb_buf[mi2] = mod_name_raw[mi2]
mb_buf[mbl] = '\0'
base_mod = mb_buf
while base_mod is not None and base_mod[0] == '.':
base_mod = base_mod + 1
# 跨模块 CDefine 查找缓存(perm_pool 永久,跨文件复用):
# 首次查找成功后结果缓存,后续文件(含 reset_to(mark2)/模块切换)直接命中,
# 避免 CONST_INT 跨模块递归查找反复触发(NewAstTest OOM 根因——
# 14593 次调用全部重复递归 ast → ast.base → ...)。
# key = "name@源模块"(源模块维度,用去点后的 base_mod 保证一致),
# 保持模块隔离:不同源模块的同名 CDefine 值不同时不串值。
# 仅 ALL_CAPS 全局唯一宏名才进入本函数(_is_cdefine_name_pattern 已过滤)。
xkey_buf: str = None
if base_mod is not None:
xk_len: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2
xkey_buf = pool.alloc(xk_len)
if xkey_buf is not None:
viperlib.snprintf(xkey_buf, xk_len, "%s@%s", name, base_mod)
xval: str = HandlesType.lookup_xmod_cdefine(xkey_buf)
if HandlesType.is_cdefine_found() != 0:
if HandlesType.is_cdefine_str() != 0:
HandlesType.register_cdefine_string(pool, name, xval)
elif HandlesType.is_cdefine_double() != 0:
xd_v: double = string.atof(xval)
HandlesType.register_cdefine_double(pool, name, xd_v)
else:
xv_i: int = string.atoi(xval)
HandlesType.register_cdefine_constant(pool, name, xv_i)
return string.atoi(xval)
# 2. from_imports 查找失败:直接回退到 imported_modules 遍历(步骤 9.6)
# 注意:star fallback 可能返回错误模块(如 stdint),常量实际不在其中,
# 步骤 9.6 会在该模块查找失败后继续遍历 imported_modules
@@ -2313,7 +2395,7 @@ class ExprGenMixin:
sub_fi[2 + mk2] = im_buf[mk2]
mk2 += 1
sub_fi[2 + im_nlen] = '\0'
sub_val: int = self._lookup_cross_module_cdefine(pool, name, sub_fi, None)
sub_val: int = self._lookup_cross_module_cdefine(pool, name, sub_fi, None, depth + 1, node)
if HandlesType.is_cdefine_found() != 0:
return sub_val
return -1
@@ -2721,6 +2803,17 @@ class ExprGenMixin:
continue
viperlib.snprintf(rc_full_mod, rc_full_len, "%s.%s", base_mod, rc_sub_buf)
# 防循环:若 base_mod 已以 "."+rc_sub_buf 结尾(如 ast.base 再拼
# .base → ast.base.base),说明子模块递归在重复追加同一模块段
# (模块间循环 re-export / 后缀匹配容错命中自身),跳过该次递归
# (NewAstTest CONST_INT 查找 dump:ast.base.base.base 无限增长根因)。
rc_blen: t.CSizeT = string.strlen(base_mod)
if rc_blen > rc_sub_len + 1:
rc_tail: str = base_mod + (rc_blen - rc_sub_len)
if rc_tail[0] == '.' and \
string.strncmp(rc_tail + 1, rc_sub_buf, rc_sub_len) == 0:
continue
# 构建临时 from_imports "name:full_mod"
rc_fi_len: t.CSizeT = name_len_rc + 1 + string.strlen(rc_full_mod) + 1
rc_fi: str = pool.alloc(rc_fi_len)
@@ -2729,7 +2822,9 @@ class ExprGenMixin:
viperlib.snprintf(rc_fi, rc_fi_len, "%s:%s", name, rc_full_mod)
# 递归调用查找子模块
rc_sub_val: int = self._lookup_cross_module_cdefine(pool, name, rc_fi)
stdio.printf("[MEM] cdef_rec d=%d name=%s mod=%s\n",
depth, name, rc_full_mod)
rc_sub_val: int = self._lookup_cross_module_cdefine(pool, name, rc_fi, None, depth + 1, node)
if HandlesType.is_cdefine_found() != 0:
result_val = rc_sub_val
result_found = 1
@@ -2770,17 +2865,42 @@ class ExprGenMixin:
sub_fi2[2 + mk4] = im2_buf[mk4]
mk4 += 1
sub_fi2[2 + im2_nlen] = '\0'
sub_val2: int = self._lookup_cross_module_cdefine(pool, name, sub_fi2, None)
sub_val2: int = self._lookup_cross_module_cdefine(pool, name, sub_fi2, None, depth + 1, node)
if HandlesType.is_cdefine_found() != 0:
result_val = sub_val2
result_found = 1
# 10. 缓存到当前模块的 CDefine 表中
# 10. 缓存到当前模块的 CDefine 表中,并写入跨模块 perm_pool 缓存
# 浮点 CDefine 已在匹配循环中 register_cdefine_double 缓存
# (res_is_double=1),此处只缓存整数 CDefine,避免覆盖 double。
if result_found != 0:
if res_is_double == 0:
HandlesType.register_cdefine_constant(pool, name, result_val)
# 跨模块查找缓存(perm_pool 永久,跨文件复用):整数
# key 与入口查询一致:"name@源模块"(用截断后的 base_mod,
# 与 mod_name_raw 一致——两者都是去点后的模块名,保证 key 匹配)
if base_mod is not None:
ck_len: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2
ckey_buf: str = pool.alloc(ck_len)
if ckey_buf is not None:
viperlib.snprintf(ckey_buf, ck_len, "%s@%s", name, base_mod)
cbuf_i: str = pool.alloc(32)
if cbuf_i is not None:
viperlib.snprintf(cbuf_i, 32, "%d", result_val)
HandlesType.register_xmod_cdefine(ckey_buf, cbuf_i, 0, 0)
else:
# 浮点:从本地表取回 %.17g 文本,写入跨模块缓存(保精度)
if base_mod is not None:
ck_len2: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2
ckey2: str = pool.alloc(ck_len2)
if ckey2 is not None:
viperlib.snprintf(ckey2, ck_len2, "%s@%s", name, base_mod)
dval_cc: double = HandlesType.lookup_cdefine_double(name)
if HandlesType.is_cdefine_double() != 0:
cbuf_d: str = pool.alloc(64)
if cbuf_d is not None:
stdio.snprintf(cbuf_d, 64, "%.17g", dval_cc)
HandlesType.register_xmod_cdefine(ckey2, cbuf_d, 1, 0)
HandlesType.set_cdefine_found(1)
else:
HandlesType.set_cdefine_found(0)
@@ -2828,6 +2948,12 @@ class ExprGenMixin:
nm_id: str = nm.id
if nm_id is None:
return None
# OOM 诊断:translate_name_value 调用计数(每 2048 次打印,定位 CONST_INT 循环调用源)
self.DiagNameValueCount += 1
if (self.DiagNameValueCount % 2048) == 1:
stdio.printf("[MEM] name_value %d name=%s used=%zu chk=%zu\n",
self.DiagNameValueCount, nm_id,
pool.used_bytes(), pool.chk_depth)
# CDefine 编译期常量: 返回常量值(浮点 CDefine → double 常量,整数 → i32)
# NAME: t.CDefine = value 形式定义的常量在编译期已注册到本地表
@@ -2853,7 +2979,7 @@ class ExprGenMixin:
if self._is_cdefine_name_pattern(nm_id) != 0:
if trans is not None:
cdef_val = self._lookup_cross_module_cdefine(
pool, nm_id, trans._from_imports, trans._imported_modules)
pool, nm_id, trans._from_imports, trans._imported_modules, 0, node)
if HandlesType.is_cdefine_found() != 0:
if HandlesType.is_cdefine_str() != 0:
cdef_sv2: str = HandlesType.lookup_cdefine_string(nm_id)
+11
View File
@@ -70,6 +70,11 @@ class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin,
self.CDefineIsDouble = 0
self.CDefineIsStr = 0
self.CDefineFound = 0
# 跨模块 CDefine 查找缓存(perm_pool 永久,跨文件复用)
self.XmodCdefNames = None
self.XmodCdefValues = None
self.XmodCdefDoubleFlags = None
self.XmodCdefStrFlags = None
self.CurrentModuleSha1 = None
self.CTypedefNames = None
self.CTypedefTypeStrs = None
@@ -84,6 +89,8 @@ class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin,
self.StdlibAlloc = 0
self.VisibleStructs = None
self.StrictVisibility = 0
# OOM 语句级诊断:translate_stmt 限频打印 used(定位单文件翻译暴涨起点)
self.DiagStmtCount = 0
# ---- CallGenMixin 字段 ----
self.CexportSha1Arr = None
self.CexportFuncArr = None
@@ -140,6 +147,10 @@ class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin,
self.DocKeys = None
self.DocValues = None
self.DocCount = 0
# OOM 诊断计数:跨模块 CDefine 查找调用次数
self.DiagCDefineCount = 0
self.DiagNameValueCount = 0
self.DiagTranslateValueCount = 0
# ============================================================
+87
View File
@@ -74,6 +74,15 @@ class TypeGenMixin:
CDefineIsStr: int
CDefineFound: int
# --- 跨模块 CDefine 查找缓存(perm_pool 永久分配,跨文件复用) ---
# 2026-08-14:跨模块 CDefine 查找(_lookup_cross_module_cdefine)结果缓存到
# perm_pool,reset_to(mark2)/clear_cdefine_constants 不清除 → 跨文件复用,
# CONST_INT 递归查找只做一次(NewAstTest OOM 根因)。
XmodCdefNames: list[str] | t.CPtr
XmodCdefValues: list[str] | t.CPtr
XmodCdefDoubleFlags: list[int] | t.CPtr
XmodCdefStrFlags: list[int] | t.CPtr
# --- 当前模块 SHA1(原 _g_current_module_sha1) ---
CurrentModuleSha1: str
@@ -108,6 +117,10 @@ class TypeGenMixin:
self.CDefineIsDouble = 0
self.CDefineIsStr = 0
self.CDefineFound = 0
self.XmodCdefNames = None
self.XmodCdefValues = None
self.XmodCdefDoubleFlags = None
self.XmodCdefStrFlags = None
self.CurrentModuleSha1 = None
self.CTypedefNames = None
self.CTypedefTypeStrs = None
@@ -283,6 +296,80 @@ class TypeGenMixin:
if self.CDefineStrFlags is not None:
self.CDefineStrFlags.append(1)
# ============================================================
# 跨模块 CDefine 查找缓存(perm_pool 永久分配,跨文件复用)
# ============================================================
def register_xmod_cdefine(self, name: str, value_str: str,
is_double: int, is_str: int) -> None:
"""注册跨模块 CDefine 查找结果到 perm_pool 全局缓存(跨文件复用)
Args:
name: CDefine 常量名(如 CONST_INT)
value_str: 值文本(十进制/浮点/字符串)
is_double: 1=浮点值
is_str: 1=字符串值
"""
if name is None or value_str is None:
return
# 去重:同名已缓存则跳过(首次查找结果为准,CDefine 全局唯一约定)
if self.XmodCdefNames is not None:
x_n: t.CSizeT = len(self.XmodCdefNames)
x_i: t.CSizeT
for x_i in range(x_n):
x_nm: str = self.XmodCdefNames.get(x_i)
if x_nm is not None and string.strcmp(x_nm, name) == 0:
return
perm: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool()
if self.XmodCdefNames is None:
self.XmodCdefNames = list[str](perm, 64)
self.XmodCdefValues = list[str](perm, 64)
self.XmodCdefDoubleFlags = list[int](perm, 64)
self.XmodCdefStrFlags = list[int](perm, 64)
# key/value 深拷贝到 perm_pool:入参(pool.alloc 临时缓冲)在
# reset_to(mark2) 后悬空,append 只存指针 → 必须深拷贝跨 reset 存活
klen: t.CSizeT = string.strlen(name)
kcopy: str = perm.alloc(klen + 1)
if kcopy is None:
return
string.strcpy(kcopy, name)
vlen: t.CSizeT = string.strlen(value_str)
vcopy: str = perm.alloc(vlen + 1)
if vcopy is None:
return
string.strcpy(vcopy, value_str)
self.XmodCdefNames.append(kcopy)
self.XmodCdefValues.append(vcopy)
if self.XmodCdefDoubleFlags is not None:
self.XmodCdefDoubleFlags.append(is_double)
if self.XmodCdefStrFlags is not None:
self.XmodCdefStrFlags.append(is_str)
def lookup_xmod_cdefine(self, name: str) -> str:
"""查找跨模块 CDefine 缓存,命中设置 found/is_double/is_str 标志
Returns:
值文本(命中),未命中返回 None
"""
self.CDefineFound = 0
self.CDefineIsDouble = 0
self.CDefineIsStr = 0
if name is None or self.XmodCdefNames is None:
return None
n: t.CSizeT = len(self.XmodCdefNames)
i: t.CSizeT
for i in range(n):
nm: str = self.XmodCdefNames.get(i)
if nm is not None and string.strcmp(nm, name) == 0:
val_str: str = self.XmodCdefValues.get(i)
if val_str is not None:
self.CDefineFound = 1
if self.XmodCdefStrFlags is not None and self.XmodCdefStrFlags.get(i) == 1:
self.CDefineIsStr = 1
elif self.XmodCdefDoubleFlags is not None and self.XmodCdefDoubleFlags.get(i) == 1:
self.CDefineIsDouble = 1
return val_str
return None
def lookup_cdefine_constant(self, name: str) -> int:
"""查找 CDefine 编译期常量
+18
View File
@@ -249,6 +249,24 @@ def clear_cdefine_constants() -> None:
g.clear_cdefine_constants()
def register_xmod_cdefine(name: str, value_str: str,
is_double: int, is_str: int) -> None:
"""注册跨模块 CDefine 查找结果到 perm_pool 全局缓存(委托到 gen.register_xmod_cdefine)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
g.register_xmod_cdefine(name, value_str, is_double, is_str)
def lookup_xmod_cdefine(name: str) -> str:
"""查找跨模块 CDefine 缓存(委托到 gen.lookup_xmod_cdefine)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.lookup_xmod_cdefine(name)
return None
def register_ctypedef(pool: memhub.MemBuddy | t.CPtr,
name: str, type_str: str) -> None:
"""注册 CTypedef 到本地表(委托到 gen.register_ctypedef)"""