feat: 引入 CompilerFactory 永久内存池,1a 每文件 reset 解 NewAstTest OOM
main 创建 512MB perm_pool(MemBuddy 第二实例,永不 reset)并注册 CompilerFactory 工厂(对齐 TPC Translator 装配模式,memhub 保持通用)。 各 Gen Mixin 跨 mark 持久表(struct/枚举/Renum/spec/vtable/全局函数/ 闭包/函数指针/Cexport/Reexport/TraceFrames/Doc)全部迁移到 perm_pool, 替代 stdlib.malloc 深拷贝提升速度。 Phase1 1a 主循环(98 includes 全量 parse AST 驻留主 pool → 1GB 耗尽) 改为:StdlibAlloc=1 注册数据进 perm_pool + 每文件翻译完 reset_to(文件级 mark) 回收 AST;1b-pre vpi 预生成循环同样 reset_to(mark1)。同步修 7 处 reset 后悬空隐患:StructTable 表体、add_field DefaultVal、Renum 变体/ 别名表内容、vtable full_names 内容、FuncptrRets 深拷贝。 CompilerFactory 类名与模块名同名(合法场景,TPC 已支持模块别名优先)。
This commit is contained in:
1 parent
c27a1ba347
commit
8d5dbeab89
14 files changed
+981
-115
No files matched your search
@@ -0,0 +1,68 @@
|
||||
import t, c
|
||||
import memhub
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CompilerFactory - 编译器结构体工厂(对齐 TPC Translator 装配模式)
|
||||
#
|
||||
# TPC 的 Translator 在 __init__ 集中创建编译器各子对象(Handler/
|
||||
# SymbolTable/Exportable 等),是编译器的"装配器/工厂";TPV 的 main
|
||||
# 目前手动创建 mb/gen 并逐模块注入(_mbuddy/set_global_gen),装配
|
||||
# 逻辑散落。本工厂集中持有编译器级共享内存对象:
|
||||
#
|
||||
# - Pool :主内存池(MemBuddy,瞬时数据,受 mark/reset_to 回收)
|
||||
# - PermPool :永久内存池(MemBuddy,跨 mark 持久数据专用,从不 reset)
|
||||
#
|
||||
# 各模块经模块级委托 CompilerFactory.get_perm_pool() 获取永久池,
|
||||
# 避免把编译器专属单例塞进通用内存库 memhub(memhub 保持通用)。
|
||||
# includes 层(llvmlite/__types.vp 的 DeepCopyType)不依赖本工厂:
|
||||
# 深拷贝的分配源由调用方以 pool 参数传入(传 PermPool 即持久)。
|
||||
# 类名与模块名同名(均为 CompilerFactory):合法场景,TPC 已支持
|
||||
# 模块别名优先解析——`X.func()` 中 X 是 import 别名(IsModuleAlias)
|
||||
# 时按模块函数处理,`X.X(args)` 的类构造按 FuncAttr==类名 走 struct
|
||||
# 路径,二者互不冲突(勿再改类名规避,见用户明确要求)。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class CompilerFactory:
|
||||
"""编译器结构体工厂(持有主池/永久池等共享对象)"""
|
||||
|
||||
Pool: memhub.MemBuddy | t.CPtr # 主内存池(瞬时数据,mark/reset 回收)
|
||||
PermPool: memhub.MemBuddy | t.CPtr # 永久内存池(持久数据,从不 reset)
|
||||
|
||||
def __init__(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
perm_pool: memhub.MemBuddy | t.CPtr):
|
||||
if self is None:
|
||||
return
|
||||
self.Pool = pool
|
||||
self.PermPool = perm_pool
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 全局工厂单例
|
||||
# ============================================================
|
||||
_g_factory: CompilerFactory | t.CPtr = None
|
||||
|
||||
|
||||
def set_factory(factory: CompilerFactory | t.CPtr) -> None:
|
||||
"""注册全局工厂单例(main 创建后注册)"""
|
||||
global _g_factory
|
||||
_g_factory = factory
|
||||
|
||||
|
||||
def get_factory() -> CompilerFactory | t.CPtr:
|
||||
"""获取全局工厂单例(未注册返回 None)"""
|
||||
return _g_factory
|
||||
|
||||
|
||||
def get_pool() -> memhub.MemBuddy | t.CPtr:
|
||||
"""获取主内存池(瞬时数据分配源)"""
|
||||
if _g_factory is not None:
|
||||
return _g_factory.Pool
|
||||
return None
|
||||
|
||||
|
||||
def get_perm_pool() -> memhub.MemBuddy | t.CPtr:
|
||||
"""获取永久内存池(跨 mark 持久数据分配源)"""
|
||||
if _g_factory is not None:
|
||||
return _g_factory.PermPool
|
||||
return None
|
||||
@@ -23,6 +23,7 @@ import lib.core.Handles.HandlesFunctions as HandlesFunctions
|
||||
import lib.core.StubMerger as StubMerger
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -152,8 +153,8 @@ class CallGenMixin:
|
||||
if sha1 is None or func_name is None:
|
||||
return 0
|
||||
if self.CexportSha1Arr is None:
|
||||
self.CexportSha1Arr = stdlib.malloc(_CEXPORT_MAX * 17)
|
||||
self.CexportFuncArr = stdlib.malloc(_CEXPORT_MAX * 64)
|
||||
self.CexportSha1Arr = CompilerFactory.get_perm_pool().alloc(_CEXPORT_MAX * 17)
|
||||
self.CexportFuncArr = CompilerFactory.get_perm_pool().alloc(_CEXPORT_MAX * 64)
|
||||
if self.CexportSha1Arr is None or self.CexportFuncArr is None:
|
||||
return 0
|
||||
string.memset(self.CexportSha1Arr, 0, _CEXPORT_MAX * 17)
|
||||
@@ -7097,7 +7098,7 @@ class CallGenMixin:
|
||||
"""确保闭包名表已分配,0 失败"""
|
||||
if self.ClosureNames is not None:
|
||||
return 1
|
||||
self.ClosureNames = stdlib.malloc(64 * MAX_CLOSURE_NAMES)
|
||||
self.ClosureNames = CompilerFactory.get_perm_pool().alloc(64 * MAX_CLOSURE_NAMES)
|
||||
if self.ClosureNames is None:
|
||||
return 0
|
||||
string.memset(self.ClosureNames, 0, 64 * MAX_CLOSURE_NAMES)
|
||||
@@ -7130,8 +7131,8 @@ class CallGenMixin:
|
||||
"""确保函数指针签名表已分配(stdlib.malloc,懒初始化)"""
|
||||
if self.FuncptrNames is not None:
|
||||
return 1
|
||||
self.FuncptrNames = stdlib.malloc(64 * MAX_FUNC_PTR_SIGS)
|
||||
self.FuncptrRets = stdlib.malloc(8 * MAX_FUNC_PTR_SIGS)
|
||||
self.FuncptrNames = CompilerFactory.get_perm_pool().alloc(64 * MAX_FUNC_PTR_SIGS)
|
||||
self.FuncptrRets = CompilerFactory.get_perm_pool().alloc(8 * MAX_FUNC_PTR_SIGS)
|
||||
if self.FuncptrNames is None or self.FuncptrRets is None:
|
||||
return 0
|
||||
string.memset(self.FuncptrNames, 0, 64 * MAX_FUNC_PTR_SIGS)
|
||||
@@ -7149,7 +7150,14 @@ class CallGenMixin:
|
||||
idx: t.CSizeT = t.CSizeT(self.FuncptrCount) * 64
|
||||
# 槽位定长 64 字节,与 register_closure_name 一致用 strncpy 钳制防越界
|
||||
string.strncpy(self.FuncptrNames + idx, name, 63)
|
||||
self.FuncptrRets[self.FuncptrCount] = t.CUInt64T(ret_ty)
|
||||
# ret_ty 是调用方 pool 分配的裸 LLVMType,1a 每文件 reset 后悬空;
|
||||
# 深拷贝到 perm_pool(lookup_func_ptr_ret 跨文件读取)
|
||||
ret_copy_fp: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(
|
||||
CompilerFactory.get_perm_pool(), ret_ty)
|
||||
if ret_copy_fp is not None:
|
||||
self.FuncptrRets[self.FuncptrCount] = t.CUInt64T(ret_copy_fp)
|
||||
else:
|
||||
self.FuncptrRets[self.FuncptrCount] = t.CUInt64T(ret_ty)
|
||||
self.FuncptrCount += 1
|
||||
return 0
|
||||
|
||||
@@ -7794,7 +7802,7 @@ class CallGenMixin:
|
||||
if self.GlobalFuncs is not None:
|
||||
return 1
|
||||
size: t.CSizeT = GLOBAL_FUNC_MAX * HandlesExprCall.FuncEntry.__sizeof__()
|
||||
self.GlobalFuncs = stdlib.malloc(size)
|
||||
self.GlobalFuncs = CompilerFactory.get_perm_pool().alloc(size)
|
||||
if self.GlobalFuncs is None:
|
||||
return 0
|
||||
string.memset(self.GlobalFuncs, 0, size)
|
||||
@@ -7840,7 +7848,7 @@ class CallGenMixin:
|
||||
|
||||
# 深拷贝到 stdlib 区(TypeStr 跨文件永久存活)
|
||||
ts_len: t.CSizeT = string.strlen(ty_buf)
|
||||
ts_copy: str = stdlib.malloc(ts_len + 1)
|
||||
ts_copy: str = CompilerFactory.get_perm_pool().alloc(ts_len + 1)
|
||||
if ts_copy is None:
|
||||
return None
|
||||
string.strcpy(ts_copy, ty_buf)
|
||||
@@ -7869,7 +7877,7 @@ class CallGenMixin:
|
||||
# Name 深拷贝到 stdlib 区:全局表跨文件永久存活,pool 内名字会被 1b 每文件
|
||||
# reset_to(mark1) 回收导致悬空(vtable 生成 find_func_global 后 strcmp 崩溃)
|
||||
name_len: t.CSizeT = string.strlen(name)
|
||||
name_copy: str = stdlib.malloc(name_len + 1)
|
||||
name_copy: str = CompilerFactory.get_perm_pool().alloc(name_len + 1)
|
||||
if name_copy is None:
|
||||
return 1
|
||||
string.strcpy(name_copy, name)
|
||||
@@ -7921,7 +7929,7 @@ class CallGenMixin:
|
||||
if self.GlobalDefaults is not None:
|
||||
return 1
|
||||
size: t.CSizeT = GLOBAL_DEFAULTS_MAX * HandlesExprCall.FuncDefaultsEntry.__sizeof__()
|
||||
self.GlobalDefaults = stdlib.malloc(size)
|
||||
self.GlobalDefaults = CompilerFactory.get_perm_pool().alloc(size)
|
||||
if self.GlobalDefaults is None:
|
||||
return 0
|
||||
string.memset(self.GlobalDefaults, 0, size)
|
||||
@@ -7951,7 +7959,7 @@ class CallGenMixin:
|
||||
entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr = (HandlesExprCall.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
# Name 深拷贝到 stdlib(全局表跨文件永久存活)
|
||||
nm_len: t.CSizeT = string.strlen(name)
|
||||
nm_copy: str = stdlib.malloc(nm_len + 1)
|
||||
nm_copy: str = CompilerFactory.get_perm_pool().alloc(nm_len + 1)
|
||||
if nm_copy is None:
|
||||
return 1
|
||||
string.strcpy(nm_copy, name)
|
||||
@@ -7961,9 +7969,9 @@ class CallGenMixin:
|
||||
entry.ParamCount = param_count
|
||||
# 提取常量快照到 stdlib
|
||||
if default_count > 0:
|
||||
kinds: t.CInt | t.CPtr = stdlib.malloc(default_count * 4)
|
||||
ints: t.CInt64T | t.CPtr = stdlib.malloc(default_count * 8)
|
||||
strs: t.CSizeT | t.CPtr = stdlib.malloc(default_count * 8)
|
||||
kinds: t.CInt | t.CPtr = CompilerFactory.get_perm_pool().alloc(default_count * 4)
|
||||
ints: t.CInt64T | t.CPtr = CompilerFactory.get_perm_pool().alloc(default_count * 8)
|
||||
strs: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(default_count * 8)
|
||||
if kinds is not None and ints is not None and strs is not None:
|
||||
string.memset(kinds, 0, default_count * 4)
|
||||
string.memset(ints, 0, default_count * 8)
|
||||
@@ -7978,7 +7986,7 @@ class CallGenMixin:
|
||||
ints[di] = dcn.int_val
|
||||
if dcn.const_kind == ast.CONST_STR and dcn.str_val is not None:
|
||||
slen: t.CSizeT = string.strlen(dcn.str_val)
|
||||
scopy: str = stdlib.malloc(slen + 1)
|
||||
scopy: str = CompilerFactory.get_perm_pool().alloc(slen + 1)
|
||||
if scopy is not None:
|
||||
string.strcpy(scopy, dcn.str_val)
|
||||
strs[di] = t.CSizeT(scopy)
|
||||
|
||||
@@ -16,6 +16,7 @@ import lib.core.Handles.HandlesEnum as HandlesEnum
|
||||
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
|
||||
import lib.core.Handles.HandlesImports as HandlesImports
|
||||
import lib.core.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -381,8 +382,8 @@ class ClassGenMixin:
|
||||
return
|
||||
# 懒初始化
|
||||
if self.MethodMetaKeys is None:
|
||||
self.MethodMetaKeys = stdlib.malloc(META_MAX * META_KEY_LEN)
|
||||
self.MethodMetaFlags = stdlib.malloc(META_MAX * 4)
|
||||
self.MethodMetaKeys = CompilerFactory.get_perm_pool().alloc(META_MAX * META_KEY_LEN)
|
||||
self.MethodMetaFlags = CompilerFactory.get_perm_pool().alloc(META_MAX * 4)
|
||||
if self.MethodMetaKeys is None or self.MethodMetaFlags is None:
|
||||
return
|
||||
string.memset(self.MethodMetaKeys, 0, META_MAX * META_KEY_LEN)
|
||||
@@ -1241,8 +1242,13 @@ class ClassGenMixin:
|
||||
return 0
|
||||
|
||||
# Phase 1b 新注册的 union struct_ty 深拷贝到 stdlib(跨文件 reset 存活)
|
||||
if trans._declare_only == 0:
|
||||
union_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(pool, union_ty)
|
||||
# StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:Phase A-pre-inc 预注册
|
||||
# includes 时 declare_only=1,若仍用 pool struct_ty,reset_to(mark2) 后
|
||||
# entry.Ty 悬空 → 后续文件 opaque 扫描跨模块引用遍历悬空 fields 崩溃
|
||||
# (LoopTest _scan_type_for_cross_module_refs 0xFFFF 根因)。
|
||||
if trans._declare_only == 0 or HandlesStruct.get_stdlib_alloc() != 0:
|
||||
union_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(
|
||||
CompilerFactory.get_perm_pool(), union_ty)
|
||||
if union_copy is not None:
|
||||
union_ty = union_copy
|
||||
|
||||
@@ -1510,8 +1516,10 @@ class ClassGenMixin:
|
||||
|
||||
# Phase 1b 新注册的 REnum struct_ty 深拷贝到 stdlib(跨文件 reset 存活,
|
||||
# 与 entry.Ty 保持同一指针,find_struct_by_type 匹配不失效)
|
||||
if trans._declare_only == 0:
|
||||
renum_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(pool, renum_ty)
|
||||
# StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:同 union 的悬空根因。
|
||||
if trans._declare_only == 0 or HandlesStruct.get_stdlib_alloc() != 0:
|
||||
renum_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(
|
||||
CompilerFactory.get_perm_pool(), renum_ty)
|
||||
if renum_copy is not None:
|
||||
renum_ty = renum_copy
|
||||
|
||||
@@ -1580,10 +1588,10 @@ class ClassGenMixin:
|
||||
# 若用 pool 会被 reset_to(mark1) 回收导致悬空(LLVMType 的 match 在
|
||||
# parser.vp 等后续文件翻译时访问已回收的表 → 崩溃)。
|
||||
if self.RenumClassNames is None:
|
||||
self.RenumClassNames = stdlib.malloc(8 * RENUM_CLASS_MAX)
|
||||
self.RenumClassVariantCounts = stdlib.malloc(8 * RENUM_CLASS_MAX)
|
||||
self.RenumVariantNames = stdlib.malloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
|
||||
self.RenumVariantTags = stdlib.malloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
|
||||
self.RenumClassNames = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX)
|
||||
self.RenumClassVariantCounts = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX)
|
||||
self.RenumVariantNames = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
|
||||
self.RenumVariantTags = CompilerFactory.get_perm_pool().alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
|
||||
if (self.RenumClassNames is None or self.RenumClassVariantCounts is None
|
||||
or self.RenumVariantNames is None or self.RenumVariantTags is None):
|
||||
self.RenumClassNames = None
|
||||
@@ -1604,9 +1612,15 @@ class ClassGenMixin:
|
||||
if self.RenumClassCount >= RENUM_CLASS_MAX:
|
||||
return
|
||||
|
||||
# 注册类名
|
||||
# 注册类名(strcpy 到 perm_pool:1a 每文件 reset 后 AST 裸指针悬空,
|
||||
# _lookup_renum_variant/_is_renum_class_name 的 strcmp 会读毒化内存)
|
||||
idx: int = self.RenumClassCount
|
||||
self.RenumClassNames[idx] = t.CSizeT(class_name)
|
||||
cn_len_rv: t.CSizeT = string.strlen(class_name)
|
||||
cn_buf_rv: str = CompilerFactory.get_perm_pool().alloc(cn_len_rv + 1)
|
||||
if cn_buf_rv is None:
|
||||
return
|
||||
string.strcpy(cn_buf_rv, class_name)
|
||||
self.RenumClassNames[idx] = t.CSizeT(cn_buf_rv)
|
||||
self.RenumClassVariantCounts[idx] = variant_count
|
||||
|
||||
# 遍历 children,提取嵌套变体类名并注册
|
||||
@@ -1632,7 +1646,13 @@ class ClassGenMixin:
|
||||
if vcd is None or vcd.name is None:
|
||||
continue
|
||||
name_offset: t.CSizeT = idx * RENUM_VARIANT_PER_CLASS + tag
|
||||
self.RenumVariantNames[name_offset] = t.CSizeT(vcd.name)
|
||||
# 变体名同样 strcpy 到 perm_pool(1a 每文件 reset 后 vcd.name 悬空)
|
||||
vn_len_rv: t.CSizeT = string.strlen(vcd.name)
|
||||
vn_buf_rv: str = CompilerFactory.get_perm_pool().alloc(vn_len_rv + 1)
|
||||
if vn_buf_rv is None:
|
||||
break
|
||||
string.strcpy(vn_buf_rv, vcd.name)
|
||||
self.RenumVariantNames[name_offset] = t.CSizeT(vn_buf_rv)
|
||||
self.RenumVariantTags[name_offset] = tag
|
||||
tag += 1
|
||||
|
||||
@@ -1693,11 +1713,12 @@ class ClassGenMixin:
|
||||
if payload_idx < 1:
|
||||
return
|
||||
|
||||
# 懒初始化表
|
||||
# 懒初始化表(perm_pool:1a 每文件 reset 后表本体不被回收)
|
||||
if self.RenumAliasClass is None:
|
||||
self.RenumAliasClass = pool.alloc(8 * RENUM_ALIAS_MAX)
|
||||
self.RenumAliasField = pool.alloc(8 * RENUM_ALIAS_MAX)
|
||||
self.RenumAliasIndex = pool.alloc(8 * RENUM_ALIAS_MAX)
|
||||
alias_pool_rfa: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool()
|
||||
self.RenumAliasClass = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
|
||||
self.RenumAliasField = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
|
||||
self.RenumAliasIndex = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
|
||||
if (self.RenumAliasClass is None or self.RenumAliasField is None
|
||||
or self.RenumAliasIndex is None):
|
||||
self.RenumAliasClass = None
|
||||
@@ -1710,18 +1731,29 @@ class ClassGenMixin:
|
||||
if self.RenumAliasCount >= RENUM_ALIAS_MAX:
|
||||
return
|
||||
|
||||
# 检查是否已注册(避免重复)— 用 CSizeT 指针值比较,避免 CSizeT→str 转换问题
|
||||
# 检查是否已注册(避免重复)— class 用 CSizeT 指针值比较(契约不变),
|
||||
# field 槽位是 perm_pool 拷贝、key 是原指针,指针比较恒不相等 → 改 strcmp
|
||||
cls_key: t.CSizeT = t.CSizeT(class_name)
|
||||
fld_key: t.CSizeT = t.CSizeT(field_name)
|
||||
for i in range(self.RenumAliasCount):
|
||||
cls_existing: t.CSizeT = self.RenumAliasClass[i]
|
||||
fld_existing: t.CSizeT = self.RenumAliasField[i]
|
||||
if cls_existing == cls_key and fld_existing == fld_key:
|
||||
return
|
||||
if cls_existing == cls_key:
|
||||
fld_existing_ptr: str = (str | t.CPtr)(
|
||||
t.CVoid(self.RenumAliasField[i], t.CPtr))
|
||||
if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0:
|
||||
return
|
||||
|
||||
idx: int = self.RenumAliasCount
|
||||
self.RenumAliasClass[idx] = cls_key
|
||||
self.RenumAliasField[idx] = fld_key
|
||||
# field_name 存 AST 裸指针,1a 每文件 reset 后悬空;_lookup_renum_field_alias
|
||||
# 用 strcmp 内容比较 → strcpy 到 perm_pool 不影响查找。
|
||||
# class_name 槽位保持原指针:_update_renum_alias_class_ptr 会统一为
|
||||
# entry.Name(perm_pool 拷贝),指针值比较契约不变。
|
||||
fn_len_rfa: t.CSizeT = string.strlen(field_name)
|
||||
fn_buf_rfa: str = CompilerFactory.get_perm_pool().alloc(fn_len_rfa + 1)
|
||||
if fn_buf_rfa is None:
|
||||
return
|
||||
string.strcpy(fn_buf_rfa, field_name)
|
||||
self.RenumAliasField[idx] = t.CSizeT(fn_buf_rfa)
|
||||
self.RenumAliasIndex[idx] = t.CSizeT(payload_idx)
|
||||
self.RenumAliasCount = idx + 1
|
||||
|
||||
@@ -1784,7 +1816,7 @@ class ClassGenMixin:
|
||||
self.GenericClassSha1s = list[str](pool, 8)
|
||||
self.GenericClassFiles = list[str](pool, 8)
|
||||
if self.GenericClassTpParams is None:
|
||||
self.GenericClassTpParams = stdlib.malloc(GENERIC_TEMPLATE_MAX * 8)
|
||||
self.GenericClassTpParams = CompilerFactory.get_perm_pool().alloc(GENERIC_TEMPLATE_MAX * 8)
|
||||
if self.GenericClassTpParams is None:
|
||||
return
|
||||
string.memset(self.GenericClassTpParams, 0, GENERIC_TEMPLATE_MAX * 8)
|
||||
@@ -1826,7 +1858,7 @@ class ClassGenMixin:
|
||||
tp_name: str = tp.get(ti)
|
||||
if tp_name is not None:
|
||||
total += string.strlen(tp_name) + 1
|
||||
buf: str = stdlib.malloc(total)
|
||||
buf: str = CompilerFactory.get_perm_pool().alloc(total)
|
||||
if buf is None:
|
||||
return None
|
||||
buf[0] = '\0'
|
||||
@@ -2154,8 +2186,8 @@ class ClassGenMixin:
|
||||
if spec_key is None or spec_name is None:
|
||||
return
|
||||
if self.SpecKeys is None:
|
||||
self.SpecKeys = stdlib.malloc(SPEC_CACHE_MAX * 8)
|
||||
self.SpecNames = stdlib.malloc(SPEC_CACHE_MAX * 8)
|
||||
self.SpecKeys = CompilerFactory.get_perm_pool().alloc(SPEC_CACHE_MAX * 8)
|
||||
self.SpecNames = CompilerFactory.get_perm_pool().alloc(SPEC_CACHE_MAX * 8)
|
||||
if self.SpecKeys is None or self.SpecNames is None:
|
||||
return
|
||||
string.memset(self.SpecKeys, 0, SPEC_CACHE_MAX * 8)
|
||||
@@ -2166,8 +2198,8 @@ class ClassGenMixin:
|
||||
# 深拷贝字符串到 stdlib 区
|
||||
key_len: t.CSizeT = string.strlen(spec_key)
|
||||
name_len: t.CSizeT = string.strlen(spec_name)
|
||||
key_copy: str = stdlib.malloc(key_len + 1)
|
||||
name_copy: str = stdlib.malloc(name_len + 1)
|
||||
key_copy: str = CompilerFactory.get_perm_pool().alloc(key_len + 1)
|
||||
name_copy: str = CompilerFactory.get_perm_pool().alloc(name_len + 1)
|
||||
if key_copy is None or name_copy is None:
|
||||
return
|
||||
string.strcpy(key_copy, spec_key)
|
||||
@@ -2481,13 +2513,14 @@ class ClassGenMixin:
|
||||
# _ensure_field_types_in_module 遍历悬空字段 ParamNode 链表
|
||||
# 读悬空挂起(G3 LinkedNode.prepend 挂起根因)。DeepCopyType
|
||||
# 递归深拷贝字段链表/子类型/Name 到 stdlib(深度上限+链守卫)。
|
||||
ty_deep: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(pool, existing.Ty)
|
||||
ty_deep: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(
|
||||
CompilerFactory.get_perm_pool(), existing.Ty)
|
||||
if ty_deep is not None:
|
||||
existing.Ty = ty_deep
|
||||
old_name: str = llvmlite.get_struct_name(existing.Ty)
|
||||
if old_name is not None:
|
||||
on_len: t.CSizeT = string.strlen(old_name)
|
||||
on_copy: str = stdlib.malloc(on_len + 1)
|
||||
on_copy: str = CompilerFactory.get_perm_pool().alloc(on_len + 1)
|
||||
if on_copy is not None:
|
||||
string.strcpy(on_copy, old_name)
|
||||
c.DerefAs(existing.Ty, llvmlite.LLVMType.Struct(
|
||||
@@ -2797,7 +2830,7 @@ class ClassGenMixin:
|
||||
type_name = name_buf
|
||||
if trans._declare_only == 0 and type_name is not None:
|
||||
tn_len: t.CSizeT = string.strlen(type_name)
|
||||
tn_copy: str = stdlib.malloc(tn_len + 1)
|
||||
tn_copy: str = CompilerFactory.get_perm_pool().alloc(tn_len + 1)
|
||||
if tn_copy is not None:
|
||||
string.strcpy(tn_copy, type_name)
|
||||
type_name = tn_copy
|
||||
@@ -2816,8 +2849,13 @@ class ClassGenMixin:
|
||||
# 对象和 Fields 链是 pool 分配的,本文件 reset_to(mark1) 后悬空。深拷贝整棵树
|
||||
# 到 stdlib,并替换 struct_ty 指针,保证 entry.Ty 与调用方持有的 struct_ty
|
||||
# 指向同一个 stdlib 拷贝(指针匹配不失效)且跨文件永久存活。
|
||||
if trans._declare_only == 0:
|
||||
st_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(pool, struct_ty)
|
||||
# StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:Phase A-pre-inc(declare_only=1)
|
||||
# 预注册 includes 时若仍用 pool struct_ty,reset_to(mark2) 后 entry.Ty 悬空 →
|
||||
# 后续文件字段类型引用(resolve → Ptr(entry.Ty))→ opaque 扫描遍历悬空 fields
|
||||
# 崩溃(LoopTest _scan_type_for_cross_module_refs 0xFFFF 根因)。
|
||||
if trans._declare_only == 0 or HandlesStruct.get_stdlib_alloc() != 0:
|
||||
st_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(
|
||||
CompilerFactory.get_perm_pool(), struct_ty)
|
||||
if st_copy is not None:
|
||||
struct_ty = st_copy
|
||||
type_name = llvmlite.get_struct_name(struct_ty)
|
||||
@@ -2857,7 +2895,7 @@ class ClassGenMixin:
|
||||
# find_struct(ParentName) strcmp 解引用 → 用 stdlib 拷贝保证跨文件存活
|
||||
if HandlesStruct.get_stdlib_alloc() != 0:
|
||||
pn_len: t.CSizeT = string.strlen(parent_name)
|
||||
pn_buf: str = stdlib.malloc(pn_len + 1)
|
||||
pn_buf: str = CompilerFactory.get_perm_pool().alloc(pn_len + 1)
|
||||
if pn_buf is not None:
|
||||
string.strcpy(pn_buf, parent_name)
|
||||
entry.ParentName = pn_buf
|
||||
@@ -2865,7 +2903,7 @@ class ClassGenMixin:
|
||||
entry.ParentName = parent_name
|
||||
# 多继承:设置父类数组(供 MRO/字段/vtable 查询,stdlib 深拷贝跨文件存活)
|
||||
if parents_count > 0 and parents_buf is not None:
|
||||
HandlesStruct.set_parent_names(class_name, parents_buf, parents_count)
|
||||
HandlesStruct.set_parent_names(pool, class_name, parents_buf, parents_count)
|
||||
|
||||
# 添加字段信息
|
||||
# 如果有虚表,先添加 __vtable__ 字段占位(索引 0),用户字段从索引 1 开始
|
||||
@@ -3016,10 +3054,10 @@ class ClassGenMixin:
|
||||
# 1. 收集虚方法信息
|
||||
# stdlib 分配:method_names_buf 存到 StructEntry.VTableMethods(跨文件永久存活),
|
||||
# 必须迁出 mb 池 reset 区间,否则 1b 每文件 reset_to(mark1) 会回收导致悬空。
|
||||
full_names_buf: t.CSizeT | t.CPtr = stdlib.malloc(8 * VTBL_METHOD_MAX)
|
||||
method_names_buf: t.CSizeT | t.CPtr = stdlib.malloc(8 * VTBL_METHOD_MAX)
|
||||
full_names_buf: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX)
|
||||
method_names_buf: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX)
|
||||
# 记录每个方法的父类 SHA1(非 0=继承方法用父模块 SHA1 mangling,0=当前类方法)
|
||||
method_parent_sha1s: t.CSizeT | t.CPtr = stdlib.malloc(8 * VTBL_METHOD_MAX)
|
||||
method_parent_sha1s: t.CSizeT | t.CPtr = CompilerFactory.get_perm_pool().alloc(8 * VTBL_METHOD_MAX)
|
||||
if full_names_buf is None or method_names_buf is None or method_parent_sha1s is None:
|
||||
return 0
|
||||
string.memset(full_names_buf, 0, 8 * VTBL_METHOD_MAX)
|
||||
@@ -3109,13 +3147,13 @@ class ClassGenMixin:
|
||||
def_class = anc
|
||||
break
|
||||
mro_i += 1
|
||||
pfname_buf: str = pool.alloc(128)
|
||||
pfname_buf: str = CompilerFactory.get_perm_pool().alloc(128)
|
||||
if pfname_buf is not None:
|
||||
viperlib.snprintf(pfname_buf, 128, "%s.%s", def_class, pmethod_name)
|
||||
full_names_buf[method_count] = t.CSizeT(pfname_buf)
|
||||
# 复制方法名(短名)
|
||||
pmname_len: t.CSizeT = string.strlen(pmethod_name)
|
||||
pmname_buf: str = stdlib.malloc(pmname_len + 1)
|
||||
pmname_buf: str = CompilerFactory.get_perm_pool().alloc(pmname_len + 1)
|
||||
if pmname_buf is not None:
|
||||
string.strcpy(pmname_buf, pmethod_name)
|
||||
method_names_buf[method_count] = t.CSizeT(pmname_buf)
|
||||
@@ -3169,14 +3207,16 @@ class ClassGenMixin:
|
||||
if already_in_vt == 1:
|
||||
continue
|
||||
# 构造 full_name = "ClassName.method_name"
|
||||
fname_buf: str = pool.alloc(128)
|
||||
# 内容必须落在 perm_pool:1a(mark_only=1)收集的 VTableMethods 被
|
||||
# Phase 1b 依赖模块翻译跨文件读取,1a 每文件 reset 后 pool 裸字符串悬空
|
||||
fname_buf: str = CompilerFactory.get_perm_pool().alloc(128)
|
||||
if fname_buf is not None:
|
||||
viperlib.snprintf(fname_buf, 128, "%s.%s", class_name, mname)
|
||||
full_names_buf[method_count] = t.CSizeT(fname_buf)
|
||||
|
||||
# 复制方法名
|
||||
mname_len: t.CSizeT = string.strlen(mname)
|
||||
mname_buf: str = stdlib.malloc(mname_len + 1)
|
||||
mname_buf: str = CompilerFactory.get_perm_pool().alloc(mname_len + 1)
|
||||
if mname_buf is not None:
|
||||
string.strcpy(mname_buf, mname)
|
||||
method_names_buf[method_count] = t.CSizeT(mname_buf)
|
||||
|
||||
@@ -8,6 +8,7 @@ import stdlib
|
||||
import stdio
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesVar as HandlesVar
|
||||
@@ -25,7 +26,6 @@ import lib.core.VLogger as VLogger
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.Projectrans.Utils as Utils
|
||||
|
||||
|
||||
# ============================================================
|
||||
# docstring 登记表容量(__doc__ 魔法属性支持)
|
||||
#
|
||||
@@ -3847,8 +3847,8 @@ class ExprGenMixin:
|
||||
if string.strlen(doc) == 0:
|
||||
return
|
||||
if self.DocKeys is None:
|
||||
self.DocKeys = stdlib.malloc(DOC_MAX * DOC_KEY_SZ)
|
||||
self.DocValues = stdlib.malloc(DOC_MAX * DOC_VAL_SZ)
|
||||
self.DocKeys = CompilerFactory.get_perm_pool().alloc(DOC_MAX * DOC_KEY_SZ)
|
||||
self.DocValues = CompilerFactory.get_perm_pool().alloc(DOC_MAX * DOC_VAL_SZ)
|
||||
if self.DocKeys is None or self.DocValues is None:
|
||||
return
|
||||
string.memset(self.DocKeys, 0, DOC_MAX * DOC_KEY_SZ)
|
||||
|
||||
@@ -119,6 +119,7 @@ class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin,
|
||||
self.GenericClassNames = None
|
||||
self.GenericClassNodes = None
|
||||
self.GenericClassSha1s = None
|
||||
self.GenericClassFiles = None
|
||||
self.GenericClassTpParams = None
|
||||
self.VtFullNames = None
|
||||
self.VtMethodNames = None
|
||||
|
||||
@@ -9,6 +9,7 @@ import stdio
|
||||
import sys
|
||||
import w32.fileio as fileio
|
||||
import lib.core.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
|
||||
|
||||
@@ -301,9 +302,9 @@ class ImportsGenMixin:
|
||||
return -1
|
||||
# 懒初始化
|
||||
if self.ReexportSha1s is None:
|
||||
self.ReexportSha1s = stdlib.malloc(MAX_REEXPORT * 17)
|
||||
self.ReexportFuncs = stdlib.malloc(MAX_REEXPORT * 64)
|
||||
self.ReexportSrcs = stdlib.malloc(MAX_REEXPORT * 64)
|
||||
self.ReexportSha1s = CompilerFactory.get_perm_pool().alloc(MAX_REEXPORT * 17)
|
||||
self.ReexportFuncs = CompilerFactory.get_perm_pool().alloc(MAX_REEXPORT * 64)
|
||||
self.ReexportSrcs = CompilerFactory.get_perm_pool().alloc(MAX_REEXPORT * 64)
|
||||
if self.ReexportSha1s is None or self.ReexportFuncs is None or self.ReexportSrcs is None:
|
||||
return -1
|
||||
string.memset(self.ReexportSha1s, 0, MAX_REEXPORT * 17)
|
||||
|
||||
@@ -4,6 +4,7 @@ import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdlib
|
||||
import viperlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
@@ -18,8 +19,10 @@ import lib.core.Handles.HandlesIf as HandlesIf
|
||||
import lib.core.Handles.HandlesWhile as HandlesWhile
|
||||
import lib.core.Handles.HandlesFor as HandlesFor
|
||||
import lib.core.Handles.HandlesReturn as HandlesReturn
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
import lib.core.Handles.HandlesMatch as HandlesMatch
|
||||
import lib.core.Handles.HandlesEnum as HandlesEnum
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.Projectrans.Config as Config
|
||||
|
||||
|
||||
@@ -66,7 +69,10 @@ class StmtGenMixin:
|
||||
"""
|
||||
|
||||
# --- 编译期 CIf 求值状态(原 HandlesIf._g_cif_eval_ok) ---
|
||||
CifEvalOk: int
|
||||
# 用 8 字节类型:Mixin 独立布局与 Generator 组合布局的字段对齐必须一致
|
||||
# (i32 首字段在组合布局中导致 EnumTable 相对偏移 4 vs 独立布局 8 的错位,
|
||||
# this_adjust 无法同时修正,枚举表错位到相邻字段被覆盖——ASTCtx 丢失根因)。
|
||||
CifEvalOk: t.CSizeT
|
||||
|
||||
# --- 枚举注册表(原 HandlesEnum._enum_table/_enum_count) ---
|
||||
EnumTable: HandlesEnum.EnumEntry | t.CPtr
|
||||
@@ -1089,12 +1095,17 @@ class StmtGenMixin:
|
||||
# ============================================================
|
||||
|
||||
def init_enum_table(self, pool: memhub.MemBuddy | t.CPtr) -> int:
|
||||
"""初始化枚举注册表,返回 1 成功"""
|
||||
"""初始化枚举注册表,返回 1 成功
|
||||
|
||||
表用 stdlib 分配(跨 Phase1 1b 的 mark/reset_to 存活——枚举表是
|
||||
跨文件持久表,pool 分配会被 reset 回收导致 Phase B 读垃圾,
|
||||
enum_count 出现 512 等垃圾值 / entry.Name 解引用崩溃)。
|
||||
"""
|
||||
if self.EnumTable is not None:
|
||||
return 1
|
||||
|
||||
entry_size: t.CSizeT = HandlesEnum.EnumEntry.__sizeof__()
|
||||
self.EnumTable = pool.alloc(entry_size * ENUM_MAX)
|
||||
self.EnumTable = CompilerFactory.get_perm_pool().alloc(entry_size * ENUM_MAX)
|
||||
if self.EnumTable is None:
|
||||
return 0
|
||||
string.memset(self.EnumTable, 0, entry_size * ENUM_MAX)
|
||||
@@ -1141,21 +1152,35 @@ class StmtGenMixin:
|
||||
if entry is None:
|
||||
return None
|
||||
|
||||
# 分配成员数组
|
||||
# 分配成员数组(永久池:跨 mark/reset 存活,对齐 EnumTable 永久池化)
|
||||
member_size: t.CSizeT = HandlesEnum.EnumMember.__sizeof__()
|
||||
entry.Members = pool.alloc(member_size * ENUM_MEMBER_MAX)
|
||||
entry.Members = CompilerFactory.get_perm_pool().alloc(member_size * ENUM_MEMBER_MAX)
|
||||
if entry.Members is None:
|
||||
return None
|
||||
string.memset(entry.Members, 0, member_size * ENUM_MEMBER_MAX)
|
||||
|
||||
# 复制类名
|
||||
# 复制类名(永久池深拷贝)
|
||||
name_len: t.CSizeT = string.strlen(name)
|
||||
name_buf: str = pool.alloc(name_len + 1)
|
||||
name_buf: str = CompilerFactory.get_perm_pool().alloc(name_len + 1)
|
||||
if name_buf is not None:
|
||||
string.strcpy(name_buf, name)
|
||||
entry.Name = name_buf
|
||||
|
||||
entry.BaseTy = base_ty
|
||||
# BaseTy 深拷贝:LLVMType 是 pool 分配,StdlibAlloc=1(Phase2 mark2 后)
|
||||
# 时 reset 回收悬空 → Phase B 枚举访问 ConstInt(悬空 BaseTy) 生成 void
|
||||
# 值(DecoratorMarkerTest `store void 2` llc 报错根因)。Phase1 1a
|
||||
# (StdlibAlloc=0,mark1 前)保持 pool 存活,无需拷贝。
|
||||
# 注意:StdlibAlloc 是 StructGenMixin 字段,本 Mixin 方法体不能直接
|
||||
# self.StdlibAlloc(NoVTable 按本 Mixin 字段布局编译),走模块级委托。
|
||||
if HandlesStruct.get_stdlib_alloc() != 0:
|
||||
base_ty_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(
|
||||
CompilerFactory.get_perm_pool(), base_ty)
|
||||
if base_ty_copy is not None:
|
||||
entry.BaseTy = base_ty_copy
|
||||
else:
|
||||
entry.BaseTy = base_ty
|
||||
else:
|
||||
entry.BaseTy = base_ty
|
||||
entry.MemberCount = 0
|
||||
|
||||
self.EnumCount += 1
|
||||
@@ -1182,9 +1207,9 @@ class StmtGenMixin:
|
||||
if me is None:
|
||||
return -1
|
||||
|
||||
# 复制成员名
|
||||
# 复制成员名(永久池深拷贝:成员表跨 mark/reset 存活)
|
||||
name_len: t.CSizeT = string.strlen(member_name)
|
||||
name_buf: str = pool.alloc(name_len + 1)
|
||||
name_buf: str = CompilerFactory.get_perm_pool().alloc(name_len + 1)
|
||||
if name_buf is not None:
|
||||
string.strcpy(name_buf, member_name)
|
||||
me.Name = name_buf
|
||||
|
||||
@@ -8,6 +8,7 @@ import stdio
|
||||
import ast
|
||||
import hashtable
|
||||
import viperlib
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
|
||||
@@ -121,12 +122,22 @@ class StructGenMixin:
|
||||
return self.VisibleStructs.__contains__(name)
|
||||
|
||||
def init_struct_table(self, pool: memhub.MemBuddy | t.CPtr) -> int:
|
||||
"""初始化结构体注册表,返回 1 成功"""
|
||||
"""初始化结构体注册表,返回 1 成功
|
||||
|
||||
StdlibAlloc=1 时表体分配在 perm_pool:1a 每文件 reset 后表本体
|
||||
不被回收(否则首次 register_struct 若发生在文件级 mark 之后,
|
||||
reset 会把 StructTable 连根回收,全局 find_struct 悬空)。
|
||||
"""
|
||||
if self.StructTable is not None:
|
||||
return 1
|
||||
|
||||
entry_size: t.CSizeT = HandlesStruct.StructEntry.__sizeof__()
|
||||
self.StructTable = pool.alloc(entry_size * STRUCT_MAX)
|
||||
table_pool: memhub.MemBuddy | t.CPtr = pool
|
||||
if self.StdlibAlloc != 0:
|
||||
table_pool = CompilerFactory.get_perm_pool()
|
||||
if table_pool is None:
|
||||
table_pool = pool
|
||||
self.StructTable = table_pool.alloc(entry_size * STRUCT_MAX)
|
||||
if self.StructTable is None:
|
||||
return 0
|
||||
string.memset(self.StructTable, 0, entry_size * STRUCT_MAX)
|
||||
@@ -182,22 +193,30 @@ class StructGenMixin:
|
||||
if entry is None:
|
||||
return None
|
||||
|
||||
# 分配字段数组(1b 阶段用 stdlib,避免 reset 回收后 Fields 悬空)
|
||||
# 分配字段数组(1b 阶段用永久池,避免 reset 回收后 Fields 悬空)
|
||||
field_size: t.CSizeT = HandlesStruct.FieldEntry.__sizeof__()
|
||||
if self.StdlibAlloc != 0:
|
||||
entry.Fields = stdlib.malloc(field_size * FIELD_MAX)
|
||||
perm_sg: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool()
|
||||
if perm_sg is None:
|
||||
perm_sg = pool
|
||||
entry.Fields = perm_sg.alloc(field_size * FIELD_MAX)
|
||||
else:
|
||||
entry.Fields = pool.alloc(field_size * FIELD_MAX)
|
||||
if entry.Fields is None:
|
||||
return None
|
||||
string.memset(entry.Fields, 0, field_size * FIELD_MAX)
|
||||
|
||||
# 复制类名(统一 stdlib:1a 阶段注册的 entry 需跨 1b reset 存活。
|
||||
# 此前 1a 用 pool,1b 阶段 find_struct_by_module 的 strcmp 读悬空
|
||||
# Name 越界读 → G3 LinkedNode.prepend 挂起根因。stdlib 分配不随
|
||||
# pool reset 回收,多遍去重(Ty 比较)避免重复分配。)
|
||||
# 复制类名(1b/Phase2(StdlibAlloc=1)用永久池跨 reset 存活;
|
||||
# 1a(StdlibAlloc=0)用主 pool,mark1 前不回收同样存活。
|
||||
# 此前 1a 用 pool、1b 用 stdlib,find_struct_by_module 的 strcmp
|
||||
# 曾读悬空 Name 越界 → G3 LinkedNode.prepend 挂起根因)
|
||||
name_pool: memhub.MemBuddy | t.CPtr = pool
|
||||
if self.StdlibAlloc != 0:
|
||||
name_pool = CompilerFactory.get_perm_pool()
|
||||
if name_pool is None:
|
||||
name_pool = pool
|
||||
name_len: t.CSizeT = string.strlen(name)
|
||||
name_buf: str = stdlib.malloc(name_len + 1)
|
||||
name_buf: str = name_pool.alloc(name_len + 1)
|
||||
if name_buf is not None:
|
||||
string.strcpy(name_buf, name)
|
||||
entry.Name = name_buf
|
||||
@@ -206,10 +225,10 @@ class StructGenMixin:
|
||||
entry.FieldCount = 0
|
||||
|
||||
# 注册时直接设置 SHA1(避免 set_struct_sha1 跨模块同名时找错 entry)
|
||||
# SHA1 同样统一 stdlib(跨 1a/1b 存活,防 strcmp 悬空)
|
||||
# SHA1 同样按 StdlibAlloc 选分配源(跨 1a/1b 存活,防 strcmp 悬空)
|
||||
if sha1 is not None:
|
||||
sha1_len: t.CSizeT = string.strlen(sha1)
|
||||
sha1_buf: str = stdlib.malloc(sha1_len + 1)
|
||||
sha1_buf: str = name_pool.alloc(sha1_len + 1)
|
||||
if sha1_buf is not None:
|
||||
string.strcpy(sha1_buf, sha1)
|
||||
entry.ModuleSha1 = sha1_buf
|
||||
@@ -225,9 +244,14 @@ class StructGenMixin:
|
||||
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(class_name)
|
||||
if entry is None:
|
||||
return 0
|
||||
# 复制 SHA1 字符串(统一 stdlib,跨 1a/1b 存活防 strcmp 悬空)
|
||||
# 复制 SHA1 字符串(StdlibAlloc=1 用永久池,跨 1a/1b 存活防 strcmp 悬空)
|
||||
sha1_len: t.CSizeT = string.strlen(sha1)
|
||||
sha1_buf: str = stdlib.malloc(sha1_len + 1)
|
||||
sha1_pool: memhub.MemBuddy | t.CPtr = pool
|
||||
if self.StdlibAlloc != 0:
|
||||
sha1_pool = CompilerFactory.get_perm_pool()
|
||||
if sha1_pool is None:
|
||||
sha1_pool = pool
|
||||
sha1_buf: str = sha1_pool.alloc(sha1_len + 1)
|
||||
if sha1_buf is None:
|
||||
return 0
|
||||
string.strcpy(sha1_buf, sha1)
|
||||
@@ -269,11 +293,16 @@ class StructGenMixin:
|
||||
if fe is None:
|
||||
return -1
|
||||
|
||||
# 复制字段名(统一 stdlib:1a 注册的字段名跨 1b reset 存活,
|
||||
# 复制字段名(StdlibAlloc=1 用永久池跨 reset 存活,
|
||||
# 否则 lookup_field 的 strcmp(fe.Name, ...) 读悬空越界挂起,
|
||||
# 与 register_struct 的 Name 悬空同根因)
|
||||
fname_pool: memhub.MemBuddy | t.CPtr = pool
|
||||
if self.StdlibAlloc != 0:
|
||||
fname_pool = CompilerFactory.get_perm_pool()
|
||||
if fname_pool is None:
|
||||
fname_pool = pool
|
||||
name_len: t.CSizeT = string.strlen(field_name)
|
||||
name_buf: str = stdlib.malloc(name_len + 1)
|
||||
name_buf: str = fname_pool.alloc(name_len + 1)
|
||||
if name_buf is not None:
|
||||
string.strcpy(name_buf, field_name)
|
||||
fe.Name = name_buf
|
||||
@@ -286,20 +315,24 @@ class StructGenMixin:
|
||||
# AnnotClassName 回退、_apply_struct_defaults 的 build_gep_struct 用 fe.Ty
|
||||
# 作 GEP 结果类型)解引用悬空内存 → 崩溃点漂移(json/string/builtins 之间)。
|
||||
if self.StdlibAlloc != 0:
|
||||
ty_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(pool, field_ty)
|
||||
dp_pool_sg: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool()
|
||||
if dp_pool_sg is None:
|
||||
dp_pool_sg = pool
|
||||
ty_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(dp_pool_sg, field_ty)
|
||||
if ty_copy is not None:
|
||||
fe.Ty = ty_copy
|
||||
else:
|
||||
fe.Ty = field_ty
|
||||
if annot_class_name is not None:
|
||||
annot_len: t.CSizeT = string.strlen(annot_class_name)
|
||||
annot_buf: str = stdlib.malloc(annot_len + 1)
|
||||
annot_buf: str = CompilerFactory.get_perm_pool().alloc(annot_len + 1)
|
||||
if annot_buf is not None:
|
||||
string.strcpy(annot_buf, annot_class_name)
|
||||
fe.AnnotClassName = annot_buf
|
||||
# DefaultVal:跨文件结构体构造(_translate_struct_ctor→_apply_struct_defaults)
|
||||
# 在调用方文件翻译时读取字段默认值,原 pool AST 已 reset 回收 → 常量深拷贝
|
||||
fe.DefaultVal = self._deep_copy_default_ast(default_val)
|
||||
# 到 perm_pool(1a 每文件 reset 后 DefaultVal 同样必须跨文件存活)
|
||||
fe.DefaultVal = self._deep_copy_default_ast(dp_pool_sg, default_val)
|
||||
else:
|
||||
fe.Ty = field_ty
|
||||
fe.AnnotClassName = annot_class_name
|
||||
@@ -308,8 +341,9 @@ class StructGenMixin:
|
||||
struct_entry.FieldCount = idx + 1
|
||||
return idx
|
||||
|
||||
def _deep_copy_default_ast(self, default_val: ast.AST | t.CPtr) -> ast.AST | t.CPtr:
|
||||
"""深拷贝字段默认值 AST 到 stdlib(仅常量节点),跨 1b reset 存活。
|
||||
def _deep_copy_default_ast(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
default_val: ast.AST | t.CPtr) -> ast.AST | t.CPtr:
|
||||
"""深拷贝字段默认值 AST 到永久池(仅常量节点),跨 1b reset 存活。
|
||||
|
||||
字段默认值(fe.DefaultVal)除定义文件内 _generate_before_init 使用外,
|
||||
跨文件结构体构造(_translate_struct_ctor → _apply_struct_defaults)会在
|
||||
@@ -322,12 +356,12 @@ class StructGenMixin:
|
||||
if default_val is None:
|
||||
return None
|
||||
if default_val.kind() == ast.ASTKind.List:
|
||||
return self._deep_copy_list_ast(default_val)
|
||||
return self._deep_copy_list_ast(pool, default_val)
|
||||
if default_val.kind() != ast.ASTKind.Constant:
|
||||
return None
|
||||
src_c: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(default_val)
|
||||
dst_c: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(
|
||||
stdlib.malloc(ast.Constant.__sizeof__()))
|
||||
pool.alloc(ast.Constant.__sizeof__()))
|
||||
if dst_c is None:
|
||||
return None
|
||||
string.memset(dst_c, 0, ast.Constant.__sizeof__())
|
||||
@@ -346,22 +380,23 @@ class StructGenMixin:
|
||||
dst_c.float_val = src_c.float_val
|
||||
if src_c.str_val is not None:
|
||||
s_len: t.CSizeT = string.strlen(src_c.str_val)
|
||||
s_copy: str = stdlib.malloc(s_len + 1)
|
||||
s_copy: str = pool.alloc(s_len + 1)
|
||||
if s_copy is not None:
|
||||
string.strcpy(s_copy, src_c.str_val)
|
||||
dst_c.str_val = s_copy
|
||||
return (ast.AST | t.CPtr)(dst_c)
|
||||
|
||||
def _deep_copy_list_ast(self, default_val: ast.AST | t.CPtr) -> ast.AST | t.CPtr:
|
||||
"""深拷贝 List 节点(列表字面量默认值)到 stdlib,跨 1b reset 存活。
|
||||
def _deep_copy_list_ast(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
default_val: ast.AST | t.CPtr) -> ast.AST | t.CPtr:
|
||||
"""深拷贝 List 节点(列表字面量默认值)到永久池,跨 1b reset 存活。
|
||||
|
||||
elts 容器手动在 stdlib 构造(list 的 __pool__ 置 None:深拷贝的 elts
|
||||
elts 容器手动在永久池构造(list 的 __pool__ 置 None:深拷贝的 elts
|
||||
只被只读访问 get/__len__/迭代,不 append,不会触发 pool 扩容)。
|
||||
元素递归调用 _deep_copy_default_ast(支持 Constant 与嵌套 List)。
|
||||
"""
|
||||
src_l: ast.List | t.CPtr = (ast.List | t.CPtr)(default_val)
|
||||
dst_l: ast.List | t.CPtr = (ast.List | t.CPtr)(
|
||||
stdlib.malloc(ast.List.__sizeof__()))
|
||||
pool.alloc(ast.List.__sizeof__()))
|
||||
if dst_l is None:
|
||||
return None
|
||||
string.memset(dst_l, 0, ast.List.__sizeof__())
|
||||
@@ -380,14 +415,14 @@ class StructGenMixin:
|
||||
if src_elts_l is not None:
|
||||
cnt_l: t.CSizeT = len(src_elts_l)
|
||||
lst_copy_l: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(
|
||||
stdlib.malloc(list[ast.AST | t.CPtr].__sizeof__()))
|
||||
pool.alloc(list[ast.AST | t.CPtr].__sizeof__()))
|
||||
if lst_copy_l is not None:
|
||||
string.memset(lst_copy_l, 0, list[ast.AST | t.CPtr].__sizeof__())
|
||||
lst_copy_l.__count__ = cnt_l
|
||||
lst_copy_l.__capacity__ = cnt_l
|
||||
lst_copy_l.__elem_size__ = 8
|
||||
lst_copy_l.__pool__ = None
|
||||
data_l: t.CVoid | t.CPtr = stdlib.malloc(cnt_l * 8)
|
||||
data_l: t.CVoid | t.CPtr = pool.alloc(cnt_l * 8)
|
||||
if data_l is not None:
|
||||
string.memset(data_l, 0, cnt_l * 8)
|
||||
lst_copy_l.__data__ = data_l
|
||||
@@ -395,7 +430,7 @@ class StructGenMixin:
|
||||
for li_l in range(cnt_l):
|
||||
elem_src_l: ast.AST | t.CPtr = src_elts_l.get(li_l)
|
||||
if elem_src_l is not None:
|
||||
elem_dst_l: ast.AST | t.CPtr = self._deep_copy_default_ast(elem_src_l)
|
||||
elem_dst_l: ast.AST | t.CPtr = self._deep_copy_default_ast(pool, elem_src_l)
|
||||
if elem_dst_l is not None:
|
||||
slot_l: ast.AST | t.CPtr = (ast.AST | t.CPtr)(
|
||||
t.CVoid(t.CUInt64T(data_l) + li_l * 8, t.CPtr))
|
||||
@@ -873,9 +908,10 @@ class StructGenMixin:
|
||||
entry.ParentName = parent_name
|
||||
return 1
|
||||
|
||||
def set_parent_names(self, name: str, names_ptr: t.CSizeT | t.CPtr,
|
||||
def set_parent_names(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str, names_ptr: t.CSizeT | t.CPtr,
|
||||
count: int) -> int:
|
||||
"""设置结构体的父类名数组(stdlib 深拷贝,跨文件永久存活)"""
|
||||
"""设置结构体的父类名数组(永久池深拷贝,跨文件永久存活)"""
|
||||
if name is None:
|
||||
return 0
|
||||
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(name)
|
||||
@@ -887,7 +923,12 @@ class StructGenMixin:
|
||||
return 1
|
||||
if count > PARENT_MAX:
|
||||
count = PARENT_MAX
|
||||
arr: t.CSizeT | t.CPtr = stdlib.malloc(8 * count)
|
||||
pn_pool: memhub.MemBuddy | t.CPtr = pool
|
||||
if self.StdlibAlloc != 0:
|
||||
pn_pool = CompilerFactory.get_perm_pool()
|
||||
if pn_pool is None:
|
||||
pn_pool = pool
|
||||
arr: t.CSizeT | t.CPtr = pn_pool.alloc(8 * count)
|
||||
if arr is None:
|
||||
return 0
|
||||
for i in range(count):
|
||||
@@ -897,7 +938,7 @@ class StructGenMixin:
|
||||
src: str = (str | t.CPtr)(t.CVoid(addr, t.CPtr))
|
||||
if src is not None:
|
||||
slen: t.CSizeT = string.strlen(src)
|
||||
dup: str = stdlib.malloc(slen + 1)
|
||||
dup: str = pn_pool.alloc(slen + 1)
|
||||
if dup is not None:
|
||||
string.strcpy(dup, src)
|
||||
arr[i] = t.CSizeT(dup)
|
||||
|
||||
@@ -9,6 +9,7 @@ import sys
|
||||
import stdlib
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesImports as HandlesImports
|
||||
@@ -127,7 +128,7 @@ class TypeGenMixin:
|
||||
if self.TraceFrames is not None:
|
||||
return 1
|
||||
entry_size: t.CSizeT = HandlesType.TraceFrame.__sizeof__()
|
||||
self.TraceFrames = stdlib.malloc(entry_size * TRACE_MAX)
|
||||
self.TraceFrames = CompilerFactory.get_perm_pool().alloc(entry_size * TRACE_MAX)
|
||||
if self.TraceFrames is None:
|
||||
return 0
|
||||
string.memset(self.TraceFrames, 0, entry_size * TRACE_MAX)
|
||||
|
||||
@@ -86,6 +86,12 @@ class MatchHandle(HandlesBase.Mixin):
|
||||
subject_node: ast.AST | t.CPtr = m_node.subject
|
||||
if subject_node is None:
|
||||
return 0
|
||||
# 序列匹配(match (a, b): case (x, y): ...)走独立路径:
|
||||
# Tuple/List subject 无法用 translate_value 求值(会返回 None),
|
||||
# 提前分派到 _handle_sequence_match,避免 fail-fast 误报。
|
||||
sk_seq: int = subject_node.kind()
|
||||
if sk_seq == ast.ASTKind.Tuple or sk_seq == ast.ASTKind.List:
|
||||
return self._handle_sequence_match(m_node, subject_node)
|
||||
subject_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, trans.Module, subject_node,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
@@ -617,6 +623,361 @@ class MatchHandle(HandlesBase.Mixin):
|
||||
trans.SymTab, bind_name, elem_ptr)
|
||||
j = j + 1
|
||||
|
||||
# ============================================================
|
||||
# _seq_cmp_eq - 序列匹配元素相等比较
|
||||
#
|
||||
# 对齐 lhs/rhs(指针统一 ptrtoint i64,整数位宽统一到较宽者)后
|
||||
# 生成 icmp eq,返回 i1 条件。
|
||||
# ============================================================
|
||||
def _seq_cmp_eq(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
lhs: llvmlite.Value | t.CPtr,
|
||||
rhs: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""对齐 lhs/rhs 后生成 icmp eq(指针统一 ptrtoint i64)"""
|
||||
if lhs is None or rhs is None or builder is None:
|
||||
return None
|
||||
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
|
||||
if HandlesExpr.is_ptr_type(lhs.Ty) != 0 \
|
||||
or HandlesExpr.is_ptr_type(rhs.Ty) != 0:
|
||||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
if HandlesExpr.is_ptr_type(lhs.Ty) != 0:
|
||||
lhs = llvmlite.build_ptrtoint(builder, lhs, i64_ty)
|
||||
if HandlesExpr.is_ptr_type(rhs.Ty) != 0:
|
||||
rhs = llvmlite.build_ptrtoint(builder, rhs, i64_ty)
|
||||
lb: int = HandlesExpr.get_llvm_type_bits(lhs.Ty)
|
||||
rb: int = HandlesExpr.get_llvm_type_bits(rhs.Ty)
|
||||
if lb != rb and lb != 0 and rb != 0:
|
||||
if lb < rb:
|
||||
if lb == 1:
|
||||
lhs = llvmlite.build_zext(builder, lhs, rhs.Ty)
|
||||
else:
|
||||
lhs = llvmlite.build_sext(builder, lhs, rhs.Ty)
|
||||
else:
|
||||
if rb == 1:
|
||||
rhs = llvmlite.build_zext(builder, rhs, lhs.Ty)
|
||||
else:
|
||||
rhs = llvmlite.build_sext(builder, rhs, lhs.Ty)
|
||||
return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, lhs, rhs)
|
||||
|
||||
# ============================================================
|
||||
# _handle_sequence_match - 序列匹配(match (a, b): case (x, y): ...)
|
||||
#
|
||||
# subject 是 Tuple/List、case 是 MatchSequence 时走此路径(对齐 Python
|
||||
# 语义,按声明顺序取首个全部元素匹配且 guard 为真的 case 执行):
|
||||
# 元素 pattern:
|
||||
# MatchValue v → subject[i] == v
|
||||
# MatchAs(pattern=None) → _ 通配(恒真)
|
||||
# MatchStar → 剩余元素通配(恒真)
|
||||
# IR 结构(check/body 链):
|
||||
# entry → check0
|
||||
# check_i: 匹配条件 → body_i(不满足 → check_{i+1})
|
||||
# body_i: <body> → end(c.NoBreak 时 fallthrough 到下一 case body)
|
||||
# 全不匹配 → default → end
|
||||
# ============================================================
|
||||
def _handle_sequence_match(self, node: ast.Match | t.CPtr,
|
||||
subject_node: ast.AST | t.CPtr) -> int:
|
||||
trans: HT.Translator | t.CPtr = self.Trans
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
func: llvmlite.Function | t.CPtr = trans._cur_func
|
||||
if builder is None or func is None:
|
||||
return 0
|
||||
|
||||
# 1. 求值 subject 各元素
|
||||
elts: list[ast.AST | t.CPtr] | t.CPtr = None
|
||||
if subject_node.kind() == ast.ASTKind.Tuple:
|
||||
st: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(subject_node)
|
||||
if st is not None:
|
||||
elts = st.elts
|
||||
elif subject_node.kind() == ast.ASTKind.List:
|
||||
sl2: ast.List | t.CPtr = (ast.List | t.CPtr)(subject_node)
|
||||
if sl2 is not None:
|
||||
elts = sl2.elts
|
||||
if elts is None:
|
||||
return 0
|
||||
ecount: t.CSizeT = len(elts)
|
||||
if ecount == 0:
|
||||
return 0
|
||||
subj_vals: t.CSizeT | t.CPtr = pool.alloc(8 * ecount)
|
||||
if subj_vals is None:
|
||||
return 0
|
||||
for ei in range(ecount):
|
||||
elt: ast.AST | t.CPtr = elts.get(ei)
|
||||
sv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, trans.Module, elt,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
if sv is None:
|
||||
HandlesType.fatal_error(
|
||||
elt, f"match 序列元素 {ei} 翻译失败", "TypeError")
|
||||
subj_vals[ei] = t.CSizeT(sv)
|
||||
|
||||
# 2. 创建 default/end BB
|
||||
cnt: int = trans._label_counter
|
||||
trans._label_counter = cnt + 1
|
||||
name_buf: str = pool.alloc(32)
|
||||
if name_buf is None:
|
||||
return 0
|
||||
viperlib.snprintf(name_buf, 32, "match.seq.default.%d", cnt)
|
||||
default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||||
pool, func, name_buf)
|
||||
viperlib.snprintf(name_buf, 32, "match.seq.end.%d", cnt)
|
||||
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||||
pool, func, name_buf)
|
||||
|
||||
# 3. 第一遍:收集 case 信息(check/body BB、default 标记、nobreak、guard)
|
||||
cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases
|
||||
if cases_list is None:
|
||||
return 0
|
||||
case_count: t.CSizeT = len(cases_list)
|
||||
check_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
|
||||
body_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)
|
||||
guard_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES)
|
||||
if check_arr is None or body_arr is None or def_arr is None \
|
||||
or nb_arr is None or guard_arr is None:
|
||||
return 0
|
||||
collected: int = 0
|
||||
has_default: int = 0
|
||||
first_check: int = -1
|
||||
i: int = 0
|
||||
while i < case_count:
|
||||
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
|
||||
continue
|
||||
mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node)
|
||||
pat: ast.AST | t.CPtr = mc.pattern
|
||||
is_def: int = 0
|
||||
if pat is not None:
|
||||
pk: int = pat.kind()
|
||||
if pk == ast.ASTKind.MatchAs:
|
||||
ma0: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat)
|
||||
if ma0.pattern is None:
|
||||
is_def = 1
|
||||
elif pk != ast.ASTKind.MatchSequence:
|
||||
# fail-fast:序列匹配只接受 MatchSequence / 顶层 _ 通配
|
||||
HandlesType.fatal_error(
|
||||
pat, "序列匹配 case 只支持 (元素) 或 _ 模式", "TypeError")
|
||||
if is_def == 1:
|
||||
has_default = 1
|
||||
check_arr[collected] = 0
|
||||
body_arr[collected] = t.CSizeT(default_bb)
|
||||
else:
|
||||
if collected >= MAX_MATCH_CASES:
|
||||
break
|
||||
viperlib.snprintf(name_buf, 32, "match.seq.check.%d.%d", cnt, i)
|
||||
cbb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||||
pool, func, name_buf)
|
||||
viperlib.snprintf(name_buf, 32, "match.seq.body.%d.%d", cnt, i)
|
||||
bbb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||||
pool, func, name_buf)
|
||||
check_arr[collected] = t.CSizeT(cbb)
|
||||
body_arr[collected] = t.CSizeT(bbb)
|
||||
if first_check < 0:
|
||||
first_check = collected
|
||||
body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children
|
||||
nb: int = self._has_no_break(body_list)
|
||||
def_arr[collected] = is_def
|
||||
nb_arr[collected] = nb
|
||||
guard_arr[collected] = t.CSizeT(mc.guard)
|
||||
collected = collected + 1
|
||||
i = i + 1
|
||||
|
||||
# 4. 入口 → 第一个 check(或 default/end)
|
||||
if first_check >= 0:
|
||||
head_bb: llvmlite.BasicBlock | t.CPtr = (
|
||||
llvmlite.BasicBlock | t.CPtr)(
|
||||
t.CVoid(check_arr[first_check], t.CPtr))
|
||||
llvmlite.build_br(builder, head_bb)
|
||||
elif has_default == 1:
|
||||
llvmlite.build_br(builder, default_bb)
|
||||
else:
|
||||
llvmlite.build_br(builder, end_bb)
|
||||
|
||||
# 5. 发射 check 链
|
||||
ci: int = 0
|
||||
while ci < collected:
|
||||
if def_arr[ci] == 1:
|
||||
ci = ci + 1
|
||||
continue
|
||||
cbb2: llvmlite.BasicBlock | t.CPtr = (
|
||||
llvmlite.BasicBlock | t.CPtr)(
|
||||
t.CVoid(check_arr[ci], t.CPtr))
|
||||
bbb2: llvmlite.BasicBlock | t.CPtr = (
|
||||
llvmlite.BasicBlock | t.CPtr)(
|
||||
t.CVoid(body_arr[ci], t.CPtr))
|
||||
llvmlite.position_at_end(builder, cbb2)
|
||||
|
||||
# 计算匹配条件(元素比较 && guard)
|
||||
cond: llvmlite.Value | t.CPtr = None
|
||||
cnode: ast.AST | t.CPtr = cases_list.get(ci)
|
||||
mc2: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(cnode)
|
||||
ms: ast.MatchSequence | t.CPtr = (
|
||||
ast.MatchSequence | t.CPtr)(mc2.pattern)
|
||||
pats: list[ast.AST | t.CPtr] | t.CPtr = None
|
||||
if ms is not None:
|
||||
pats = ms.patterns
|
||||
pcount: t.CSizeT = 0
|
||||
if pats is not None:
|
||||
pcount = len(pats)
|
||||
if pcount != ecount:
|
||||
# 元素数量不匹配 → 恒假(对齐 Python 语义)
|
||||
cond = llvmlite.const_int(pool, 1, 0)
|
||||
else:
|
||||
for pi in range(ecount):
|
||||
pat1: ast.AST | t.CPtr = pats.get(pi)
|
||||
if pat1 is None:
|
||||
continue
|
||||
pk1: int = pat1.kind()
|
||||
if pk1 == ast.ASTKind.MatchValue:
|
||||
mv: ast.MatchValue | t.CPtr = (
|
||||
ast.MatchValue | t.CPtr)(pat1)
|
||||
pv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, trans.Module, mv.value,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
if pv is None:
|
||||
HandlesType.fatal_error(
|
||||
pat1, f"序列模式元素 {pi} 翻译失败", "TypeError")
|
||||
sv1: llvmlite.Value | t.CPtr = (
|
||||
llvmlite.Value | t.CPtr)(
|
||||
t.CVoid(subj_vals[pi], t.CPtr))
|
||||
c1: llvmlite.Value | t.CPtr = self._seq_cmp_eq(
|
||||
builder, sv1, pv)
|
||||
if c1 is None:
|
||||
HandlesType.fatal_error(
|
||||
pat1, "序列模式元素比较失败", "TypeError")
|
||||
if cond is None:
|
||||
cond = c1
|
||||
else:
|
||||
cond = llvmlite.build_and(builder, cond, c1)
|
||||
elif pk1 == ast.ASTKind.MatchAs:
|
||||
ma2: ast.MatchAs | t.CPtr = (
|
||||
ast.MatchAs | t.CPtr)(pat1)
|
||||
if ma2.pattern is None:
|
||||
continue # _ 通配:恒真
|
||||
if ma2.name is not None:
|
||||
# fail-fast:序列模式变量绑定暂不支持
|
||||
HandlesType.fatal_error(
|
||||
pat1, "序列模式变量绑定暂不支持", "NotImplementedError")
|
||||
elif pk1 == ast.ASTKind.MatchStar:
|
||||
continue # 剩余元素通配:恒真
|
||||
else:
|
||||
HandlesType.fatal_error(
|
||||
pat1, "序列模式不支持的 pattern 类型", "TypeError")
|
||||
# guard(若有):匹配成立且 guard 非零
|
||||
g_addr: t.CSizeT = guard_arr[ci]
|
||||
if g_addr != 0:
|
||||
gnode: ast.AST | t.CPtr = (
|
||||
ast.AST | t.CPtr)(t.CVoid(g_addr, t.CPtr))
|
||||
gv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, trans.Module, gnode,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
if gv is None:
|
||||
HandlesType.fatal_error(
|
||||
gnode, "match guard 翻译失败", "TypeError")
|
||||
gbits: int = HandlesExpr.get_llvm_type_bits(gv.Ty)
|
||||
if gbits == 1:
|
||||
g1: llvmlite.Value | t.CPtr = gv
|
||||
else:
|
||||
gzero: llvmlite.Value | t.CPtr = llvmlite.const_int(
|
||||
pool, gbits if gbits > 0 else 32, 0)
|
||||
g1 = llvmlite.build_icmp(
|
||||
builder, llvmlite.ICMP_NE, gv, gzero)
|
||||
if cond is None:
|
||||
cond = g1
|
||||
else:
|
||||
cond = llvmlite.build_and(builder, cond, g1)
|
||||
if cond is None:
|
||||
cond = llvmlite.const_int(pool, 1, 1)
|
||||
|
||||
# 下一个 check(或 default/end)
|
||||
nxt: llvmlite.BasicBlock | t.CPtr = None
|
||||
nj: int = ci + 1
|
||||
while nj < collected and def_arr[nj] == 1:
|
||||
nj = nj + 1
|
||||
if nj < collected:
|
||||
nxt = (llvmlite.BasicBlock | t.CPtr)(
|
||||
t.CVoid(check_arr[nj], t.CPtr))
|
||||
elif has_default == 1:
|
||||
nxt = default_bb
|
||||
else:
|
||||
nxt = end_bb
|
||||
llvmlite.build_cond_br(builder, cond, bbb2, nxt)
|
||||
ci = ci + 1
|
||||
|
||||
# 6. 翻译 case body
|
||||
ci = 0
|
||||
while ci < collected:
|
||||
if def_arr[ci] == 1:
|
||||
ci = ci + 1
|
||||
continue
|
||||
bbb3: llvmlite.BasicBlock | t.CPtr = (
|
||||
llvmlite.BasicBlock | t.CPtr)(
|
||||
t.CVoid(body_arr[ci], t.CPtr))
|
||||
llvmlite.position_at_end(builder, bbb3)
|
||||
cnode2: ast.AST | t.CPtr = cases_list.get(ci)
|
||||
mc3: ast.MatchCase | t.CPtr = (
|
||||
ast.MatchCase | t.CPtr)(cnode2)
|
||||
HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
body_list2: list[ast.AST | t.CPtr] | t.CPtr = mc3.children
|
||||
if body_list2 is not None:
|
||||
bc: t.CSizeT = len(body_list2)
|
||||
bi: int = 0
|
||||
while bi < bc:
|
||||
stmt: ast.AST | t.CPtr = body_list2.get(bi)
|
||||
if stmt is not None:
|
||||
HandlesBody.translate_stmt(trans, stmt)
|
||||
bi = bi + 1
|
||||
HandlesVar.exit_scope(trans.SymTab)
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||||
if nb_arr[ci] == 0:
|
||||
llvmlite.build_br(builder, end_bb)
|
||||
else:
|
||||
# c.NoBreak:fallthrough 到下一个 case body(跳过模式检查)
|
||||
nj2: int = ci + 1
|
||||
while nj2 < collected and def_arr[nj2] == 1:
|
||||
nj2 = nj2 + 1
|
||||
if nj2 < collected:
|
||||
nbb: llvmlite.BasicBlock | t.CPtr = (
|
||||
llvmlite.BasicBlock | t.CPtr)(
|
||||
t.CVoid(body_arr[nj2], t.CPtr))
|
||||
llvmlite.build_br(builder, nbb)
|
||||
elif has_default == 1:
|
||||
llvmlite.build_br(builder, default_bb)
|
||||
else:
|
||||
llvmlite.build_br(builder, end_bb)
|
||||
ci = ci + 1
|
||||
|
||||
# 7. default 块
|
||||
llvmlite.position_at_end(builder, default_bb)
|
||||
if has_default == 1:
|
||||
di: int = 0
|
||||
while di < collected:
|
||||
if def_arr[di] == 1:
|
||||
dnode: ast.AST | t.CPtr = cases_list.get(di)
|
||||
if dnode is not None:
|
||||
dmc: ast.MatchCase | t.CPtr = (
|
||||
ast.MatchCase | t.CPtr)(dnode)
|
||||
HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
dbody: list[ast.AST | t.CPtr] | t.CPtr = dmc.children
|
||||
if dbody is not None:
|
||||
dn: t.CSizeT = len(dbody)
|
||||
dj: int = 0
|
||||
while dj < dn:
|
||||
stmt: ast.AST | t.CPtr = dbody.get(dj)
|
||||
if stmt is not None:
|
||||
HandlesBody.translate_stmt(trans, stmt)
|
||||
dj = dj + 1
|
||||
HandlesVar.exit_scope(trans.SymTab)
|
||||
break
|
||||
di = di + 1
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||||
llvmlite.build_br(builder, end_bb)
|
||||
|
||||
# 8. 定位到 end
|
||||
llvmlite.position_at_end(builder, end_bb)
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# _handle_simple_match - 非 REnum 路径
|
||||
#
|
||||
|
||||
@@ -449,13 +449,14 @@ def set_parent_name(name: str, parent_name: str) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def set_parent_names(name: str, names_ptr: t.CSizeT | t.CPtr,
|
||||
def set_parent_names(pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str, names_ptr: t.CSizeT | t.CPtr,
|
||||
count: int) -> int:
|
||||
"""设置结构体的父类名数组(stdlib 深拷贝,委托到 gen.set_parent_names)"""
|
||||
"""设置结构体的父类名数组(永久池深拷贝,委托到 gen.set_parent_names)"""
|
||||
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.set_parent_names(name, names_ptr, count)
|
||||
return g.set_parent_names(pool, name, names_ptr, count)
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||||
import lib.core.IncludesScanner as IncludesScanner
|
||||
import lib.core.StubMerger as StubMerger
|
||||
import lib.core.Gen.Generator as GenGenerator
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.BuildPipeline as BuildPipeline
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.StubGen.Converter as StubConverter
|
||||
@@ -202,6 +203,149 @@ def _ScanClassInheritance(mb: memhub.MemBuddy | t.CPtr,
|
||||
return class_count
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _BufHasGenericClassMarker - 文本扫描检测文件是否含泛型类标记
|
||||
#
|
||||
# 泛型类(PEP 695)语法: class Name[T]:(类名后紧跟 '[')。
|
||||
# 逐字节扫描找词边界 'class' 关键字,其后标识符后非空白是 '[' → 命中。
|
||||
# 用于 _PreRegisterAllGenericTemplates 预注册前筛选,避免 parse 全部
|
||||
# 98 个 includes 导致 AST 驻留 mark1 前把 pool 推到 OOM
|
||||
# (NewAstTest [52/68] pool 耗尽根因:1a-pre 已 parse 全部驻留,
|
||||
# 预注册再全量 parse 等于翻倍)。
|
||||
# 误报(字符串/注释里的 "class X[")无害(多 parse 一个文件);
|
||||
# 漏报有害(泛型模板未预注册 → 悬空复发),模式保守匹配行内单行形式
|
||||
# (TPV 源码泛型类均为单行 `class X[T]:`,grep 确认)。
|
||||
# ============================================================
|
||||
def _BufHasGenericClassMarker(buf: bytes, blen: t.CSizeT) -> int:
|
||||
"""文本扫描:buf 中是否有 'class 标识符[' 泛型类标记,返回 1/0"""
|
||||
if buf is None or blen <= 6:
|
||||
return 0
|
||||
pos: t.CSizeT = 0
|
||||
while pos + 5 < blen:
|
||||
if buf[pos] == 'c' and buf[pos + 1] == 'l' and buf[pos + 2] == 'a' \
|
||||
and buf[pos + 3] == 's' and buf[pos + 4] == 's':
|
||||
# class 前是词边界(行首或非标识符字符)
|
||||
prev_ok: int = 1
|
||||
if pos > 0:
|
||||
pc: t.CChar = buf[pos - 1]
|
||||
if (pc >= 'a' and pc <= 'z') or (pc >= 'A' and pc <= 'Z') \
|
||||
or (pc >= '0' and pc <= '9') or pc == '_':
|
||||
prev_ok = 0
|
||||
if prev_ok != 0:
|
||||
p: t.CSizeT = pos + 5
|
||||
# 跳过空白
|
||||
while p < blen and (buf[p] == ' ' or buf[p] == '\t'):
|
||||
p += 1
|
||||
# 读类名标识符
|
||||
if p < blen and ((buf[p] >= 'a' and buf[p] <= 'z')
|
||||
or (buf[p] >= 'A' and buf[p] <= 'Z') or buf[p] == '_'):
|
||||
while p < blen and ((buf[p] >= 'a' and buf[p] <= 'z')
|
||||
or (buf[p] >= 'A' and buf[p] <= 'Z')
|
||||
or (buf[p] >= '0' and buf[p] <= '9')
|
||||
or buf[p] == '_'):
|
||||
p += 1
|
||||
# 类名后非空白是 '[' → 泛型类
|
||||
while p < blen and (buf[p] == ' ' or buf[p] == '\t'):
|
||||
p += 1
|
||||
if p < blen and buf[p] == '[':
|
||||
return 1
|
||||
pos += 1
|
||||
else:
|
||||
pos += 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _PreRegisterAllGenericTemplates - 预注册 includes 泛型类模板(mark1 前)
|
||||
#
|
||||
# 背景:泛型模板表(GenericClassNames/GenericClassNodes/GenericClassSha1s/
|
||||
# GenericClassFiles + 模板节点)是懒分配的跨文件持久表,首次注册必须落在
|
||||
# mark1 之前才能跨 Phase1 1b(reset_to(mark1))与 Phase2(reset_to(mark2),
|
||||
# mark2 > mark1)存活。现有 1a-pre-generic 只注册"可达"泛型文件;FuncTest
|
||||
# 这类可达集合无泛型的项目,模板要等 Phase2 Phase A-pre-inc(mark2 之后)
|
||||
# 翻译全部 includes 时才注册 → reset 回收表与节点 → _find_generic_template
|
||||
# 遍历悬空内存 strcmp 崩溃。
|
||||
# 本函数先文本扫描(_BufHasGenericClassMarker,不 parse、不驻留)筛选出
|
||||
# 含泛型类的文件(全量 parse 会把 98 个 includes 的 AST 驻留 mark1 前 →
|
||||
# NewAstTest [52/68] pool 耗尽 OOM),仅对命中的文件用**永久池(perm_pool)**
|
||||
# 解析 → 模板节点与表直接进 perm_pool,跨 mark 永久存活、不占主 pool。
|
||||
# 重复注册由 _register_generic_template 内部查重跳过。
|
||||
# ============================================================
|
||||
def _PreRegisterAllGenericTemplates(mb: memhub.MemBuddy | t.CPtr,
|
||||
result: IncludesScanner.ScanResult | t.CPtr) -> int:
|
||||
"""预注册全部 includes 文件的泛型类模板,返回处理到的泛型类数量"""
|
||||
if result is None or mb is None:
|
||||
return 0
|
||||
perm: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool()
|
||||
if perm is None:
|
||||
return 0
|
||||
p1e_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
|
||||
handled_count: int = 0
|
||||
for i in range(result.Count):
|
||||
entry_addr_pg: t.CUInt64T = t.CUInt64T(result.Entries) + i * p1e_size
|
||||
entry_pg: IncludesScanner.FileEntry | t.CPtr = (
|
||||
IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_pg, t.CPtr))
|
||||
if entry_pg is None or entry_pg.Sha1 is None:
|
||||
continue
|
||||
# 读取文件
|
||||
file_path_pg: str = entry_pg.Path
|
||||
f_pg: fileio.File | t.CPtr = fileio.File(file_path_pg, fileio.MODE.R)
|
||||
if f_pg.closed:
|
||||
continue
|
||||
src_buf_pg: bytes = stdlib.malloc(SRC_BUF_SIZE)
|
||||
if src_buf_pg is None:
|
||||
f_pg.close()
|
||||
continue
|
||||
bytes_read_pg: LONG = f_pg.read_all(src_buf_pg, SRC_BUF_SIZE)
|
||||
f_pg.close()
|
||||
if bytes_read_pg <= 0:
|
||||
stdlib.free(src_buf_pg)
|
||||
continue
|
||||
if bytes_read_pg < SRC_BUF_SIZE:
|
||||
src_buf_pg[bytes_read_pg] = 0
|
||||
else:
|
||||
src_buf_pg[SRC_BUF_SIZE - 1] = 0
|
||||
# 文本扫描筛选:非泛型文件跳过(不 parse、不驻留,防 OOM)
|
||||
if _BufHasGenericClassMarker(src_buf_pg, bytes_read_pg) == 0:
|
||||
stdlib.free(src_buf_pg)
|
||||
continue
|
||||
# 泛型文件:永久池解析 → 注册模板(节点/表进 perm_pool,跨 reset 存活)
|
||||
lx_pg: ast.Lexer | t.CPtr = ast.new_lexer(perm)
|
||||
if lx_pg is None:
|
||||
stdlib.free(src_buf_pg)
|
||||
continue
|
||||
ast._lexer_init(lx_pg, src_buf_pg, perm)
|
||||
tokens_pg: ast.Token | t.CPtr = ast.tokenize(lx_pg)
|
||||
tree_pg: ast.AST | t.CPtr = ast.parse_tokens(perm, tokens_pg)
|
||||
if tree_pg is None:
|
||||
stdlib.free(src_buf_pg)
|
||||
continue
|
||||
# 遍历顶层 ClassDef,注册泛型模板(type_params 非 None)
|
||||
ch_pg: list[ast.AST | t.CPtr] | t.CPtr = tree_pg.children
|
||||
if ch_pg is not None:
|
||||
cn_pg: t.CSizeT = len(ch_pg)
|
||||
for ci_pg in range(cn_pg):
|
||||
child_pg: ast.AST | t.CPtr = ch_pg.get(ci_pg)
|
||||
if child_pg is None or child_pg.kind() != ast.ASTKind.ClassDef:
|
||||
continue
|
||||
cd_pg: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child_pg)
|
||||
if cd_pg is None or cd_pg.name is None:
|
||||
continue
|
||||
tp_pg: list[str] | t.CPtr = cd_pg.type_params
|
||||
if tp_pg is None:
|
||||
continue
|
||||
HandlesType.set_current_file(file_path_pg)
|
||||
HandlesClassDef._register_generic_template(perm, cd_pg, entry_pg.Sha1)
|
||||
handled_count += 1
|
||||
stdlib.free(src_buf_pg)
|
||||
if handled_count > 0:
|
||||
fb_gpre2: str = VLogger.fmt_buf()
|
||||
if fb_gpre2 is not None:
|
||||
viperlib.snprintf(fb_gpre2, 1024, "mark1 前永久池预注册 %d 个 includes 泛型类模板", handled_count)
|
||||
VLogger.info(fb_gpre2, "Phase1")
|
||||
return handled_count
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _FindClassDefSha1 - 在扁平数组中查找类名对应的定义文件 SHA1
|
||||
#
|
||||
@@ -1146,9 +1290,37 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
stdlib.free(gen_tr._nonlocal_names)
|
||||
stdlib.free(gen_src)
|
||||
|
||||
# ============================================================
|
||||
# Phase 1a-pre-generic-all: mark1 前全量预注册 includes 泛型模板
|
||||
#
|
||||
# 1a-pre-generic 只覆盖"可达"泛型文件;非可达泛型文件(如 FuncTest
|
||||
# 场景的 linkedlist/llvmlite/_list)的模板要等 Phase2 Phase A-pre-inc
|
||||
# (mark2 之后)才注册 → reset 回收表/节点 → _find_generic_template
|
||||
# strcmp 悬空崩溃。此处对全部 includes 轻量预注册,使模板表与节点
|
||||
# 都落在 mark1 之前(mark2 > mark1,reset_to(mark2) 不回收)。
|
||||
# ============================================================
|
||||
_PreRegisterAllGenericTemplates(mb, result)
|
||||
|
||||
# ============================================================
|
||||
# Phase 1a: 注册 struct/enum/union(mark1 前,全量 includes)
|
||||
#
|
||||
# OOM 治理:1a 对全部 includes parse 完整 AST(主 pool 分配),若
|
||||
# 驻留到 mark1(循环后)会累积 98 文件 × 每文件 AST 树 → 1GB 主池
|
||||
# 耗尽(NewAstTest alloc 失败 0xBE 根因)。现改为:
|
||||
# 1) StdlibAlloc=1:1a 注册的跨文件持久数据(StructTable 表、
|
||||
# Fields/Name/ModuleSha1、struct_ty 深拷贝、枚举/Renum/泛型
|
||||
# 模板等)全部落在 perm_pool(永不 reset),不占主 pool;
|
||||
# 2) 每文件翻译完 reset_to(文件级 mark):仅回收该文件的 AST/
|
||||
# lexer/token/IR 等瞬时数据,注册数据不受影响。
|
||||
# mark1 仍在 1a 结束后打,1b 每文件 reset_to(mark1) 语义不变。
|
||||
# ============================================================
|
||||
HandlesStruct.set_stdlib_alloc(1)
|
||||
|
||||
# 遍历文件:优先使用拓扑顺序,回退到字母序
|
||||
iter_count: int = topo_count if topo_count > 0 else result.Count
|
||||
for i in range(iter_count):
|
||||
# 每文件级 mark:翻译完回收该文件 AST(注册数据在 perm_pool)
|
||||
p1a_mark: t.CSizeT = mb.mark()
|
||||
# 获取文件索引:拓扑顺序或字母序
|
||||
file_idx: int = i
|
||||
if topo_count > 0:
|
||||
@@ -1245,6 +1417,10 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
stdlib.free(tr_r._nonlocal_names)
|
||||
stdlib.free(src_buf_r)
|
||||
|
||||
# 回收本文件 AST/lexer/token/IR 等瞬时数据(注册数据已在 perm_pool,
|
||||
# reset 不影响;IncludesScanner result 等在 p1a_mark 前分配同样保留)
|
||||
mb.reset_to(p1a_mark)
|
||||
|
||||
if p1a_fl > 0:
|
||||
fb_p1ar: str = VLogger.fmt_buf()
|
||||
if fb_p1ar is not None:
|
||||
@@ -1362,6 +1538,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
else:
|
||||
p1bpre_failed += 1
|
||||
stdlib.free(src_buf_pv)
|
||||
# 回收本文件 AST(vpi 已写盘,AST 不再需要;mark1 后无其他持久数据)
|
||||
mb.reset_to(mark1)
|
||||
|
||||
if p1bpre_failed > 0:
|
||||
fb_p1bpre: str = VLogger.fmt_buf()
|
||||
|
||||
+120
-2
@@ -16,10 +16,13 @@ import argparse
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||||
import lib.core.Handles.HandlesImports as HandlesImports
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
import lib.core.BuildPipeline as BuildPipeline
|
||||
import lib.core.IncludesScanner as IncludesScanner
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.StubMerger as StubMerger
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import lib.Projectrans.Config as Config
|
||||
@@ -30,8 +33,10 @@ _mbuddy: memhub.MemBuddy | t.CPtr
|
||||
# 源代码缓冲区大小(1MB)
|
||||
SRC_BUF_SIZE: t.CDefine = 1048576
|
||||
|
||||
# 最大源文件数(递归扫描子目录后文件数增多,增大到 64)
|
||||
MAX_SRC_FILES: t.CDefine = 64
|
||||
# 最大源文件数(递归扫描子目录后文件数增多:App 现有 65 个 .vp,
|
||||
# 2026-08-14 CompilerFactory.vp 加入后超出 64 被截断 → 链接 undefined symbol
|
||||
# CompilerFactory.get_perm_pool。增大到 128 留余量)
|
||||
MAX_SRC_FILES: t.CDefine = 128
|
||||
|
||||
# 全局栈金丝雀(避免局部变量改变栈布局)
|
||||
_g_canary: t.CUInt32T
|
||||
@@ -165,6 +170,85 @@ def _ScanDirForPyFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
return file_count
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _PreRegisterAppGenericTemplates - mark2 前预注册 App 源文件泛型类模板
|
||||
#
|
||||
# 与 Phase1 的 includes 全量预注册同理:泛型模板表(GenericClassNames 等
|
||||
# 4 张 + 模板节点)是 pool 懒分配的跨文件持久表,若在 mark2 之后
|
||||
# (Phase A-pre 翻译 App 文件时)才首次注册,reset_to(mark2) 会回收表与
|
||||
# 节点 → 后续查重/特化遍历悬空内存崩溃。App 文件数量少,mark2 前预注册
|
||||
# 产生的 AST 驻留内存可忽略。重复注册由 _register_generic_template 查重跳过。
|
||||
# ============================================================
|
||||
def _PreRegisterAppGenericTemplates(mb: memhub.MemBuddy | t.CPtr,
|
||||
entries: SrcFileEntry | t.CPtr,
|
||||
file_count: int,
|
||||
entry_size: t.CSizeT) -> int:
|
||||
"""mark2 前预注册 App 源文件的泛型类模板,返回处理到的泛型类数量"""
|
||||
if mb is None or entries is None or file_count <= 0:
|
||||
return 0
|
||||
handled: int = 0
|
||||
for i in range(file_count):
|
||||
ea_pa: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
||||
ent_pa: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_pa, t.CPtr))
|
||||
if ent_pa is None or ent_pa.Path is None or ent_pa.Sha1 is None:
|
||||
continue
|
||||
# 读取文件
|
||||
f_pa: fileio.File | t.CPtr = fileio.File(ent_pa.Path, fileio.MODE.R)
|
||||
if f_pa.closed:
|
||||
continue
|
||||
src_buf_pa: bytes = stdlib.malloc(SRC_BUF_SIZE)
|
||||
if src_buf_pa is None:
|
||||
f_pa.close()
|
||||
continue
|
||||
bytes_read_pa: LONG = f_pa.read_all(src_buf_pa, SRC_BUF_SIZE)
|
||||
f_pa.close()
|
||||
if bytes_read_pa <= 0:
|
||||
stdlib.free(src_buf_pa)
|
||||
continue
|
||||
if bytes_read_pa < SRC_BUF_SIZE:
|
||||
src_buf_pa[bytes_read_pa] = 0
|
||||
else:
|
||||
src_buf_pa[SRC_BUF_SIZE - 1] = 0
|
||||
# 解析 AST(只解析,不完整翻译;用永久池使模板节点跨 mark2 reset 存活)
|
||||
perm_pa: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool()
|
||||
if perm_pa is None:
|
||||
perm_pa = mb
|
||||
lx_pa: ast.Lexer | t.CPtr = ast.new_lexer(perm_pa)
|
||||
if lx_pa is None:
|
||||
stdlib.free(src_buf_pa)
|
||||
continue
|
||||
ast._lexer_init(lx_pa, src_buf_pa, perm_pa)
|
||||
tokens_pa: ast.Token | t.CPtr = ast.tokenize(lx_pa)
|
||||
tree_pa: ast.AST | t.CPtr = ast.parse_tokens(perm_pa, tokens_pa)
|
||||
if tree_pa is None:
|
||||
stdlib.free(src_buf_pa)
|
||||
continue
|
||||
# 遍历顶层 ClassDef,注册泛型模板(type_params 非 None)
|
||||
ch_pa: list[ast.AST | t.CPtr] | t.CPtr = tree_pa.children
|
||||
if ch_pa is not None:
|
||||
cn_pa: t.CSizeT = len(ch_pa)
|
||||
for ci_pa in range(cn_pa):
|
||||
child_pa: ast.AST | t.CPtr = ch_pa.get(ci_pa)
|
||||
if child_pa is None or child_pa.kind() != ast.ASTKind.ClassDef:
|
||||
continue
|
||||
cd_pa: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child_pa)
|
||||
if cd_pa is None or cd_pa.name is None:
|
||||
continue
|
||||
tp_pa: list[str] | t.CPtr = cd_pa.type_params
|
||||
if tp_pa is None:
|
||||
continue
|
||||
HandlesType.set_current_file(ent_pa.Path)
|
||||
HandlesClassDef._register_generic_template(perm_pa, cd_pa, ent_pa.Sha1)
|
||||
handled += 1
|
||||
stdlib.free(src_buf_pa)
|
||||
if handled > 0:
|
||||
fb_pg3: str = VLogger.fmt_buf()
|
||||
if fb_pg3 is not None:
|
||||
viperlib.snprintf(fb_pg3, 1024, "mark2 前预注册 %d 个 App 泛型类模板", handled)
|
||||
VLogger.info(fb_pg3, "PhaseA")
|
||||
return handled
|
||||
|
||||
|
||||
def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
source_dir: str, temp_dir: str, output_dir: str,
|
||||
cc_cmd: str, cc_flags: str,
|
||||
@@ -211,6 +295,24 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
# 初始化 AST 表
|
||||
ast._init_tables(mb)
|
||||
|
||||
# mark2 之前预注册 App 源文件的泛型类模板:泛型模板表/节点是 pool 懒分配,
|
||||
# 必须在 mark2 之前注册才能跨 reset_to(mark2) 存活(与 Phase1 的 includes
|
||||
# 全量预注册同理),否则 Phase A-pre 首次注册后 reset 回收 → 后续查重/特化
|
||||
# 遍历悬空内存崩溃(1.log FuncTest ASAN access-violation 同类根因)。
|
||||
_PreRegisterAppGenericTemplates(mb, entries, file_count, entry_size)
|
||||
|
||||
# OOM 清理(对齐 Phase1 1b 的 mark1/reset_to 模式):
|
||||
# Phase2 的 includes 预注册(Phase A-pre-inc)、App 源文件预注册(Phase A-pre)、
|
||||
# App 全量翻译(Phase A)、缺失 includes 翻译(Phase B+)都会产生大量瞬时数据
|
||||
# (AST/tokens/lexer/IR/Handler/dump 临时)。无回收时 98 个 includes 的 AST/IR
|
||||
# 全量累积 pool → 1GB OOM(NewAstTest 依赖 ast 模块场景)。
|
||||
# 此处打 mark2,各处翻译完成后 reset_to(mark2) 回收该文件瞬时数据;
|
||||
# 跨文件持久表(struct/enum/docstring/CDefine/函数注册表等)已 stdlib 化
|
||||
# 或落在 mark2 之前,reset 不受影响(与 Phase1 1b 同翻译路径,已验证安全)。
|
||||
mark2: t.CSizeT = mb.mark()
|
||||
# mark2 之后新注册的 struct/enum 条目改 stdlib 分配(跨 reset 存活,对齐 Phase1)
|
||||
HandlesStruct.set_stdlib_alloc(1)
|
||||
|
||||
# 确保 temp/output 目录存在
|
||||
BuildPipeline.ensure_dir(temp_dir)
|
||||
BuildPipeline.ensure_dir(output_dir)
|
||||
@@ -361,10 +463,14 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
if inc_fail_flags is not None:
|
||||
inc_fail_flags[si_inc] = 0
|
||||
# 依赖填充只在第一遍执行(PopulateIncludesDeps 内部有去重)
|
||||
# 注意:必须在 reset_to(mark2) 之前调用——内部深拷贝到 stdlib
|
||||
if pass_inc_i == 0 and tr_inc_pre._imported_modules is not None \
|
||||
and StubMerger.PopulateIncludesDeps(
|
||||
inc_sha1_pre, tr_inc_pre._imported_modules) == 0:
|
||||
deps_filled_pre = deps_filled_pre + 1
|
||||
# OOM 清理:回收本 includes 文件预注册翻译的瞬时数据
|
||||
# (AST/tokens/lexer/IR/Handler);struct 注册表条目 stdlib 分配不受影响
|
||||
mb.reset_to(mark2)
|
||||
struct_count_after_inc: int = HandlesStruct.get_struct_count()
|
||||
# 收敛检查:本遍没有新结构体注册 → 所有类已注册
|
||||
if struct_count_after_inc == struct_count_before_inc:
|
||||
@@ -412,6 +518,8 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "预注册失败: %s", ent_pre.Path)
|
||||
VLogger.error(fb, "PhaseA")
|
||||
# OOM 清理:回收本 App 文件预注册翻译的瞬时数据
|
||||
mb.reset_to(mark2)
|
||||
struct_count_after: int = HandlesStruct.get_struct_count()
|
||||
# 收敛检查:本遍没有新结构体注册 → 所有类已注册
|
||||
if struct_count_after == struct_count_before:
|
||||
@@ -465,6 +573,8 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
tr_a: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent.Path, ent.Sha1, pkg_pa, 0, temp_dir)
|
||||
if tr_a is None:
|
||||
# 翻译失败(语法/解析错误):记录待下遍重试,收敛检查统一报错
|
||||
# OOM 清理:失败翻译也已产生 AST/tokens 瞬时数据,立即回收
|
||||
mb.reset_to(mark2)
|
||||
continue
|
||||
# 收集 _imported_modules 到 app_deps_buf(供 Phase B+ 按需编译)。
|
||||
# 依赖在翻译早期已填充,即使 _deps_pending 也收集。
|
||||
@@ -484,6 +594,8 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
viperlib.snprintf(fb_dp, 1024,
|
||||
"Phase A 依赖未就绪,下遍重试: %s", ent.Path)
|
||||
VLogger.warning(fb_dp, "PhaseA-DBG")
|
||||
# OOM 清理:本文件翻译已产生瞬时数据(下遍会重新翻译),立即回收
|
||||
mb.reset_to(mark2)
|
||||
continue
|
||||
|
||||
# dump stub IR (declarations only)
|
||||
@@ -533,6 +645,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
done_flags[i] = 1
|
||||
completed_this_pass += 1
|
||||
# OOM 清理:stub/text/deps 已写盘,回收本文件翻译瞬时数据
|
||||
# (AST/tokens/lexer/IR/Handler);app_deps_buf 已深拷贝依赖,不受影响
|
||||
mb.reset_to(mark2)
|
||||
# 收敛检查:所有文件完成则结束
|
||||
all_done: int = 1
|
||||
for i_ck in range(file_count):
|
||||
@@ -877,6 +992,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
stdlib.free(inc_text_buf)
|
||||
# 重试 BuildCombinedIR
|
||||
inc_combined_len_mi = StubMerger.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
|
||||
# OOM 清理:stub/text 已写盘,回收本 includes 文件翻译瞬时数据
|
||||
# (AST/tokens/lexer/IR/Handler);BuildCombinedIR 只读文件,不受影响
|
||||
mb.reset_to(mark2)
|
||||
|
||||
if inc_combined_len_mi == 0:
|
||||
# 诊断:检查 stub.ll/text.ll 是否存在
|
||||
|
||||
+24
-1
@@ -39,6 +39,7 @@ import lib.core.IncludesScanner as IncludesScanner
|
||||
import lib.core.StubMerger as StubMerger
|
||||
import lib.core.Phase1 as Phase1
|
||||
import lib.core.Phase2 as Phase2
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Gen.Generator as GenGenerator
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.Projectrans.Utils as Utils
|
||||
@@ -50,9 +51,17 @@ import hashlib
|
||||
|
||||
# 内存大小: fl_bytes=264 (33*8), POOL_SIZE-fl_bytes 必须是 2 的幂以避免浪费
|
||||
# 1073742088 - 264 = 1073741824 (1024MB usable = 2^30)
|
||||
# 注意: POOL_SIZE 必须是 2^30+264=1073742088,否则 _largest_pow2_le 会取 2^29=512MB
|
||||
# 注意: POOL_SIZE 必须是 2^N+264,否则 _largest_pow2_le 会取低一级 2 的幂
|
||||
# Phase1 翻译 87 个 includes 文件 + Phase2 翻译 30 个测试文件,512MB 不足导致 Phase2 崩溃
|
||||
# 2026-08-13: NewAstTest 依赖 ast 模块(98 includes),Phase2 的 Phase A-pre-inc/Phase A
|
||||
# 无 mark/reset 回收,98 个 includes 的 AST/IR 全量累积 pool 超 1GB → 曾增大到 2GB。
|
||||
# → 已在 Phase2 对齐 Phase1 的 mark1/reset_to 清理机制(每文件翻译后回收瞬时数据),
|
||||
# 峰值回落至单文件水平,恢复 1GB(1073742088 - 264 = 1073741824 = 2^30)
|
||||
POOL_SIZE: t.CDefine = 1073742088
|
||||
# 永久内存池大小:2^29 + 264 = 512MB usable(存跨 mark 持久数据:泛型模板
|
||||
# 表/节点、struct/union/REnum 类型树、枚举 BaseTy、spec 缓存等)。
|
||||
# 与主 pool 独立(MemBuddy 第二实例),永不 reset_to,不占主 pool 配额。
|
||||
PERM_POOL_SIZE: t.CDefine = 536871176
|
||||
# 语言编码页
|
||||
CODE_PAGE: t.CDefine = 65001
|
||||
# 源代码缓冲区大小(1MB)
|
||||
@@ -77,6 +86,20 @@ def main() -> int:
|
||||
stdio.printf("FAIL: MemBuddy init failed\n")
|
||||
return 1
|
||||
|
||||
# 创建全局永久内存池(perm_pool,512MB):存放跨 mark/reset 持久数据
|
||||
# (泛型模板表/节点、struct/union/REnum 类型树、枚举 BaseTy、spec 缓存
|
||||
# 等),替代 stdlib.malloc 深拷贝(buddy 分配更快),永不 reset,不占
|
||||
# 主 pool 配额。经 CompilerFactory 单例分发(不改通用库 memhub)。
|
||||
perm_arena: bytes = stdlib.malloc(PERM_POOL_SIZE)
|
||||
if perm_arena is None:
|
||||
stdio.printf("FAIL: malloc for perm_pool arena failed\n")
|
||||
return 1
|
||||
perm_pool: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(perm_arena, PERM_POOL_SIZE)
|
||||
if perm_pool is None:
|
||||
stdio.printf("FAIL: perm_pool init failed\n")
|
||||
return 1
|
||||
CompilerFactory.set_factory(CompilerFactory.CompilerFactory(mb, perm_pool))
|
||||
|
||||
# 设置全局 mbuddy 指针(sys 和 argparse 都需要)
|
||||
sys._mbuddy = mb
|
||||
argparse._mbuddy = mb
|
||||
|
||||
Reference in new issue
Block a user