- @t.NoVTable class X → novirtual class X
- t.CDefine = N → define N
- rawptr[X]、X | t.CPtr → X*
- t.CPtr → rawptr(裸指针标记)
- t.Callable[...] → callable[...]
- 去掉 if/elif 条件的行续反斜杠(改单行写法)
- w32.win32file.X → win32file.X(已 import as)
- core/__init__.vp 去掉未使用的 import t, c / from stdint import *
涉及:CompilerFactory、IncludesScanner、Repl、core/__init__、
Gen/Call/{CallGenBase,CallGenCBuiltin,CallGenCall,CallGenDispatch,CallGenLeafKit}、
Gen/Class/ClassGenGeneric。
770 lines
40 KiB
Plaintext
770 lines
40 KiB
Plaintext
import lib.core.Gen.GenTypes as GenTypes
|
||
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import memhub
|
||
import string
|
||
import viperlib
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Gen.Translator as HT
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
|
||
from . import ClassGenBase
|
||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||
|
||
|
||
# 泛型特化递归深度上限(泛型循环套用防护)
|
||
# 正常嵌套特化深度 ≤ 3(如 list[list[str]]);64 远超合理值,命中即循环。
|
||
define GENERIC_SPEC_MAX_DEPTH = 64
|
||
# 泛型模板表容量上限(与 GenericClassNames 等 pool 表可容纳的模板数对齐;
|
||
define GENERIC_TEMPLATE_MAX = 512
|
||
# 泛型特化缓存表容量
|
||
define SPEC_CACHE_MAX = 512
|
||
|
||
# ============================================================
|
||
# ClassGenGeneric - 泛型模板注册/特化/克隆
|
||
# ============================================================
|
||
novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||
"""泛型模板注册/特化/克隆"""
|
||
|
||
# ============================================================
|
||
# 簇 C:泛型模板注册/特化(P5-2 第三阶段迁移,函数体来自
|
||
# HandlesClassDef.vp,逻辑零改动)
|
||
#
|
||
# 说明:
|
||
# - _generic_class_* 全局表已迁入 self.GenericClassNames/
|
||
# GenericClassNodes/GenericClassSha1s(P5-2 收尾)
|
||
# - _spec_* 全局缓存迁移为 self.SpecKeys/SpecNames/SpecCount
|
||
# ============================================================
|
||
|
||
def _is_generic_class(self, tp: list[str]*) -> int:
|
||
"""检查 ClassDef 是否有类型参数(泛型类),返回 1=是 / 0=否
|
||
|
||
接收 type_params 而非 cd,避免 cd.type_params 属性访问
|
||
因跨模块类型推断失败返回 None。
|
||
"""
|
||
if tp is None: return 0
|
||
return 1
|
||
def _dup_perm_str(self, s: str) -> str:
|
||
"""深拷贝字符串到永久池(无永久池/分配失败时原样返回入参)"""
|
||
if s is None: return None
|
||
perm: memhub.MemBuddy* = CompilerFactory.factory.PermPool
|
||
if perm is None: return s
|
||
n: sizet = string.strlen(s)
|
||
b: str = perm.alloc(n + 1)
|
||
if b is None: return s
|
||
string.strcpy(b, s)
|
||
return b
|
||
def _register_generic_template(self, pool: memhub.MemBuddy*,
|
||
cd: ast.ClassDef*,
|
||
module_sha1: str) -> None:
|
||
"""注册泛型类模板(类名 + ClassDef 节点 + 来源模块 SHA1)
|
||
|
||
[池归属修复] 这四张表 + GenericClassTpParams 的语义都是**永久表**:
|
||
批量编译下要在 Phase1 的 reset_to(mark1) 与 Phase2 的 reset_to(mark2) 之后
|
||
继续可读(读点见 _find_generic_template/_find_generic_template_sha1/
|
||
_find_generic_template_file/_find_generic_template_tp_params,均有"遍历
|
||
悬空内存 strcmp 即崩溃"的记录),REPL 下还要跨片段存活。但注册点有三个:
|
||
- Phase1Scan.vp:322 → perm(永久池);
|
||
- Phase2/__init__.vp:321 → perm(永久池);
|
||
- ClassGenDef.vp:78 → trans.Pool(**会被 reset_to 回收的池**)。
|
||
于是"表在哪个池"取决于哪条路径先注册到表:批量编译里两遍预注册
|
||
(_PreRegisterAllGenericTemplates / _PreRegisterAppGenericTemplates)在前,
|
||
表被建在永久池 ⇒ 第三条路径只是追加;而两遍预注册都没建成表时(例如
|
||
includes 的泛型 marker 文本预筛未命中),第三条路径把表建在 trans.Pool 上,
|
||
随 mark 回收 ⇒ 后续 _find_generic_template 遍历悬空表(UAF)。REPL 从不跑
|
||
Phase1/Phase2,第三条路径是**唯一**注册点 ⇒ 表必然落在会被每片段 reset 的
|
||
池上,M4 一旦在片段里定义泛型类就是必现 UAF。
|
||
故此处统一:表体一律用永久池(无永久池时退回入参池,即旧行为),并把
|
||
调用方池里的三个串(类名/SHA1/来源文件)深拷贝进永久池——它们同样会随
|
||
调用方池回收而悬空(挂名 strcmp 即读悬空内存)。
|
||
批量编译不变量:变更只影响"表与串分配在哪个池",写入的**内容**逐字不变
|
||
(同样的类名/节点/ SHA1/文件路径,同样的插入顺序与查重),发射的 IR 与
|
||
符号名不受池选择影响 ⇒ 逐字不变。
|
||
"""
|
||
if cd is None or cd.name is None: return
|
||
perm: memhub.MemBuddy* = CompilerFactory.factory.PermPool
|
||
table_pool: memhub.MemBuddy* = perm
|
||
if table_pool is None:
|
||
table_pool = pool
|
||
if self.GenericClassNames is None:
|
||
self.GenericClassNames = list[str](table_pool, 8)
|
||
self.GenericClassNodes = list[ast.ClassDef*](table_pool, 8)
|
||
self.GenericClassSha1s = list[str](table_pool, 8)
|
||
self.GenericClassFiles = list[str](table_pool, 8)
|
||
if self.GenericClassTpParams is None:
|
||
if perm is None: return
|
||
self.GenericClassTpParams = perm.alloc(GENERIC_TEMPLATE_MAX * 8)
|
||
if self.GenericClassTpParams is None: return
|
||
string.memset(self.GenericClassTpParams, 0, GENERIC_TEMPLATE_MAX * 8)
|
||
# 用局部变量接收 list,触发类型推断(避免字段 __len__ 失败)
|
||
names_local: list[str]* = self.GenericClassNames
|
||
cn: sizet = len(names_local)
|
||
for i in range(cn):
|
||
nm: str = names_local.get(i)
|
||
if nm is not None and string.strcmp(nm, cd.name) == 0: return
|
||
# type_params stdlib 深拷贝:模板节点的 type_params 是 pool 分配的
|
||
tp_names_buf: str = self._copy_type_params_stdlib(cd.type_params)
|
||
self.GenericClassNames.append(self._dup_perm_str(cd.name))
|
||
self.GenericClassNodes.append(cd)
|
||
self.GenericClassSha1s.append(self._dup_perm_str(module_sha1))
|
||
# 同时保存模板来源文件路径(错误定位用,见字段注释)
|
||
self.GenericClassFiles.append(self._dup_perm_str(self.Gen.TypeGenResolve.get_current_file()))
|
||
if tp_names_buf is not None and cn < GENERIC_TEMPLATE_MAX:
|
||
self.GenericClassTpParams[cn] = sizet(tp_names_buf)
|
||
def _copy_type_params_stdlib(self, tp: list[str]*) -> str:
|
||
"""将模板 type_params 深拷贝为空格分隔、NUL 结尾的 stdlib 缓冲区
|
||
|
||
TPC Python 参考实现:type_params = [tp.name for tp in Node.type_params]
|
||
(Python 字符串不可变天然跨阶段存活);Viper 的 type_params 是 pool
|
||
分配 list,跨 Phase 内容可能被复用污染,必须注册时拷贝到 stdlib。
|
||
返回缓冲区指针;tp 为 None(非泛型)或分配失败返回 None。
|
||
"""
|
||
if tp is None:
|
||
return None
|
||
tp_n: sizet = len(tp)
|
||
if tp_n == 0:
|
||
return None
|
||
# 计算总长:各名字长度 + (n-1) 个空格 + NUL
|
||
total: sizet = 1
|
||
ti: sizet
|
||
for ti in range(tp_n):
|
||
tp_name: str = tp.get(ti)
|
||
if tp_name is not None:
|
||
total += string.strlen(tp_name) + 1
|
||
buf: str = CompilerFactory.factory.PermPool.alloc(total)
|
||
if buf is None:
|
||
return None
|
||
buf[0] = '\0'
|
||
for ti in range(tp_n):
|
||
tp_name = tp.get(ti)
|
||
if tp_name is None:
|
||
continue
|
||
if ti > 0 and buf[0] != '\0':
|
||
string.strcat(buf, " ")
|
||
string.strcat(buf, tp_name)
|
||
return buf
|
||
def _find_generic_template_tp_params(self, pool: memhub.MemBuddy*,
|
||
class_name: str) -> list[str]*:
|
||
"""查找泛型类模板的类型参数名列表,未找到返回 None
|
||
|
||
从注册时深拷贝的 stdlib 缓冲区重建当前 pool 的 list[str]
|
||
(特化期间 pool 有效,方法与体翻译共用)。与 GenericClassNames 同序。
|
||
"""
|
||
if self.GenericClassNames is None or class_name is None \
|
||
or self.GenericClassTpParams is None:
|
||
return None
|
||
names_local: list[str]* = self.GenericClassNames
|
||
cn: sizet = len(names_local)
|
||
i: sizet
|
||
for i in range(cn):
|
||
nm: str = names_local.get(i)
|
||
if nm is not None and string.strcmp(nm, class_name) == 0:
|
||
if i >= GENERIC_TEMPLATE_MAX:
|
||
return None
|
||
buf_addr: sizet = self.GenericClassTpParams[i]
|
||
if buf_addr == 0:
|
||
return None
|
||
buf_tp: str = rawptr(buf_addr)
|
||
# 空格分隔 → list[str]
|
||
# 注意:list[str](pool, 8) 第二个参数是 elem_size(指针 8 字节),
|
||
# 不是容量!传 4 会导致 get(i) 偏移算错、append 相互覆盖
|
||
# (Pair[T1,T2] 的 seg1 写 data+4 覆盖 seg0 高 4 字节 → strcmp
|
||
# 收到 0x15B78D5015B78CB0 混合垃圾崩溃,GenericTest 回归根因)
|
||
tp_list: list[str]* = list[str](pool, 8)
|
||
if tp_list is None:
|
||
return None
|
||
seg_start: sizet = 0
|
||
pos: sizet = 0
|
||
blen: sizet = string.strlen(buf_tp)
|
||
while pos <= blen:
|
||
if buf_tp[pos] == ' ' or buf_tp[pos] == '\0':
|
||
seg_len: sizet = pos - seg_start
|
||
if seg_len > 0:
|
||
seg: str = pool.alloc(seg_len + 1)
|
||
if seg is not None:
|
||
string.strncpy(seg, buf_tp + seg_start, seg_len)
|
||
seg[seg_len] = '\0'
|
||
tp_list.append(seg)
|
||
seg_start = pos + 1
|
||
pos += 1
|
||
return tp_list
|
||
return None
|
||
def _find_generic_template(self, class_name: str) -> ast.ClassDef*:
|
||
"""查找泛型类模板,返回 ClassDef 节点或 None"""
|
||
if self.GenericClassNames is None or class_name is None:
|
||
return None
|
||
# 用局部变量接收 list,触发类型推断(避免字段 __len__ 失败)
|
||
names_local: list[str]* = self.GenericClassNames
|
||
nodes_local: list[ast.ClassDef*] | t.CPtr = self.GenericClassNodes
|
||
cn: sizet = len(names_local)
|
||
i: sizet
|
||
for i in range(cn):
|
||
nm: str = names_local.get(i)
|
||
if nm is not None and string.strcmp(nm, class_name) == 0:
|
||
node: ast.ClassDef* = nodes_local.get(i)
|
||
return node
|
||
return None
|
||
def _find_generic_template_sha1(self, class_name: str) -> str:
|
||
"""查找泛型类模板的来源模块 SHA1,未找到返回 None"""
|
||
if self.GenericClassNames is None or class_name is None:
|
||
return None
|
||
# 用局部变量接收 list,触发类型推断
|
||
names_local: list[str]* = self.GenericClassNames
|
||
sha1s_local: list[str]* = self.GenericClassSha1s
|
||
cn: sizet = len(names_local)
|
||
i: sizet
|
||
for i in range(cn):
|
||
nm: str = names_local.get(i)
|
||
if nm is not None and string.strcmp(nm, class_name) == 0:
|
||
sha1_val: str = sha1s_local.get(i)
|
||
return sha1_val
|
||
return None
|
||
def _find_generic_template_file(self, class_name: str) -> str:
|
||
"""查找泛型类模板的来源文件路径,未找到返回 None
|
||
|
||
与 _find_generic_template_sha1 同表同序;供特化翻译模板方法体时
|
||
临时切换 CurrentFile(错误定位:模板 node.lineno 需配模板文件路径)。
|
||
"""
|
||
if self.GenericClassNames is None or class_name is None:
|
||
return None
|
||
names_local: list[str]* = self.GenericClassNames
|
||
files_local: list[str]* = self.GenericClassFiles
|
||
cn: sizet = len(names_local)
|
||
i: sizet
|
||
for i in range(cn):
|
||
nm: str = names_local.get(i)
|
||
if nm is not None and string.strcmp(nm, class_name) == 0:
|
||
f_val: str = files_local.get(i)
|
||
return f_val
|
||
return None
|
||
def _mangle_generic_class_name(self, pool: memhub.MemBuddy*,
|
||
class_name: str,
|
||
type_args: list[str]*,
|
||
from_imports: str = None) -> str:
|
||
"""生成特化类名: list + [int] -> list[int]
|
||
|
||
**唯一生成器 + 唯一规范化点**:所有特化名(结构体注册名、方法符号里的
|
||
后缀段、查找键)都由这里产出,故类型实参的 SHA1 规范化只在这里做一次 ——
|
||
每个实参经 `TypeGenResolve._norm_type_arg_name` 归一到
|
||
`{定义模块SHA1}.{Class}`(该函数对已规范化的串**幂等**:规则 2/3/6 原样
|
||
返回,嵌套 `rawptr[X]` 也递归同形)⇒ 无论调用方(注解侧 / 构造侧 /
|
||
基类侧 / 字面量推断侧)传进来的实参是裸名还是已带前缀,注册名与查找名
|
||
**必然同形**。此前裸露名与已带前缀的两侧会分裂成两个特化结构体,已出现
|
||
三种现场:形参侧/实参侧(stmts.vp:60)、字段侧/构造侧(base.vp:357)、
|
||
基类侧/注解侧(ClassGenBase._get_base_name 的裸 Name.id)。
|
||
|
||
分配新缓冲区拼接,避免原地 strcat 导致缓冲区溢出
|
||
"""
|
||
if class_name is None or type_args is None or pool is None:
|
||
return class_name
|
||
n: sizet = len(type_args)
|
||
if n == 0:
|
||
return class_name
|
||
# 逐实参规范化(幂等):先归一成新列表,长度计算与拼接都用归一后的串
|
||
norm_args: list[str]* = list[str](pool, 8)
|
||
if norm_args is None:
|
||
return class_name
|
||
i: sizet
|
||
for i in range(n):
|
||
ta_raw: str = type_args.get(i)
|
||
if ta_raw is None:
|
||
continue
|
||
ta_norm: str = self.Gen.TypeGenResolve._norm_type_arg_name(pool, ta_raw, from_imports)
|
||
if ta_norm is None:
|
||
ta_norm = ta_raw
|
||
norm_args.append(ta_norm)
|
||
n = len(norm_args)
|
||
if n == 0:
|
||
return class_name
|
||
# 计算总长度: class_name + "[" + arg0 + "," + arg1 + ... + "]" + NUL
|
||
total_len: sizet = string.strlen(class_name) + 2 # "[" 和 "]"
|
||
for i in range(n):
|
||
if i > 0:
|
||
total_len += 1 # ","
|
||
ta: str = norm_args.get(i)
|
||
if ta is not None:
|
||
total_len += string.strlen(ta)
|
||
total_len += 1 # NUL
|
||
# 分配新缓冲区
|
||
mangled: str = pool.alloc(total_len)
|
||
if mangled is None:
|
||
return class_name
|
||
mangled[0] = '\0'
|
||
string.strcat(mangled, class_name)
|
||
string.strcat(mangled, "[")
|
||
for i in range(n):
|
||
if i > 0:
|
||
string.strcat(mangled, ",")
|
||
ta: str = norm_args.get(i)
|
||
if ta is not None:
|
||
string.strcat(mangled, ta)
|
||
string.strcat(mangled, "]")
|
||
return mangled
|
||
def _clone_annotation(self, pool: memhub.MemBuddy*,
|
||
node: ast.AST*,
|
||
tp_names: list[str]*,
|
||
type_args: list[str]*) -> ast.AST*:
|
||
"""拷贝类型注解表达式,替换类型参数 T 为具体类型名
|
||
|
||
tp_names: 类型参数名列表 ['T']
|
||
type_args: 类型实参名列表 ['int']
|
||
"""
|
||
if node is None:
|
||
return None
|
||
k: int = node.kind()
|
||
|
||
# Name: 可能是类型参数 T
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(node)
|
||
if nm.id is not None:
|
||
n: sizet = len(tp_names) if tp_names is not None else 0
|
||
i: sizet
|
||
for i in range(n):
|
||
tpn: str = tp_names.get(i)
|
||
if tpn is not None and string.strcmp(nm.id, tpn) == 0:
|
||
ta: str = type_args.get(i)
|
||
# 类型实参可能是复合类型(如 "AST|t.CPtr"),用 _parse_type_string 解析
|
||
parsed_node: ast.AST* = self.Gen.TypeGenResolve._parse_type_string(pool, ta, nm.ctx)
|
||
return parsed_node
|
||
return ast.Name(pool, nm.id, nm.ctx)
|
||
return None
|
||
|
||
# Attribute: t.CPtr 等
|
||
if k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute* = ast.Attribute*(node)
|
||
new_value: ast.AST* = self._clone_annotation(pool, at.value, tp_names, type_args)
|
||
return ast.Attribute(pool, new_value, at.attr, at.ctx)
|
||
|
||
# BinOp: T | t.CPtr 等
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp* = ast.BinOp*(node)
|
||
new_left: ast.AST* = self._clone_annotation(pool, bop.left, tp_names, type_args)
|
||
new_right: ast.AST* = self._clone_annotation(pool, bop.right, tp_names, type_args)
|
||
return ast.BinOp(pool, new_left, bop.op, new_right)
|
||
|
||
# Subscript: list[int] 等
|
||
if k == ast.ASTKind.Subscript:
|
||
sub: ast.Subscript* = ast.Subscript*(node)
|
||
new_value2: ast.AST* = self._clone_annotation(pool, sub.value, tp_names, type_args)
|
||
new_slice: ast.AST* = self._clone_annotation(pool, sub.slice, tp_names, type_args)
|
||
return ast.Subscript(pool, new_value2, new_slice, sub.ctx)
|
||
|
||
# Tuple: (T, int) 等
|
||
if k == ast.ASTKind.Tuple:
|
||
tup: ast.Tuple* = ast.Tuple*(node)
|
||
new_elts: list[ast.AST*]* = list[ast.AST*](pool, 8)
|
||
if tup.elts is not None:
|
||
tup_elts: list[ast.AST*]* = tup.elts
|
||
en: sizet = len(tup_elts)
|
||
ei: sizet
|
||
for ei in range(en):
|
||
el: ast.AST* = tup_elts.get(ei)
|
||
new_el: ast.AST* = self._clone_annotation(pool, el, tp_names, type_args)
|
||
if new_el is not None:
|
||
new_elts.append(new_el)
|
||
return ast.Tuple(pool, new_elts, tup.ctx)
|
||
|
||
# Constant: 默认值等
|
||
if k == ast.ASTKind.Constant:
|
||
cnst: ast.Constant* = ast.Constant*(node)
|
||
return ast.Constant(pool, cnst.const_kind, cnst.int_val, cnst.float_val,
|
||
cnst.str_val, cnst.lineno, cnst.col_offset)
|
||
|
||
# 其他: 直接引用(不拷贝)
|
||
return node
|
||
def _clone_arguments(self, pool: memhub.MemBuddy*,
|
||
args: ast.AST*,
|
||
tp_names: list[str]*,
|
||
type_args: list[str]*) -> ast.AST*:
|
||
"""拷贝 Arguments 节点,替换 arg annotation 中的 T"""
|
||
if args is None:
|
||
return None
|
||
if args.kind() != ast.ASTKind.Arguments:
|
||
return args
|
||
old_args: ast.Arguments* = ast.Arguments*(args)
|
||
# 拷贝 args 列表,替换每个 Arg 的 annotation
|
||
new_arg_list: list[ast.AST*]* = list[ast.AST*](pool, 8)
|
||
if old_args.args is not None:
|
||
old_arg_list: list[ast.AST*]* = old_args.args
|
||
an: sizet = len(old_arg_list)
|
||
ai: sizet
|
||
for ai in range(an):
|
||
arg_node: ast.AST* = old_arg_list.get(ai)
|
||
if arg_node is None:
|
||
continue
|
||
if arg_node.kind() == ast.ASTKind.Arg:
|
||
ag: ast.Arg* = ast.Arg*(arg_node)
|
||
new_anno: ast.AST* = self._clone_annotation(pool, ag.annotation, tp_names, type_args)
|
||
new_arg: ast.Arg* = ast.Arg(pool, ag.arg, new_anno)
|
||
new_arg_list.append(new_arg)
|
||
else:
|
||
new_arg_list.append(arg_node)
|
||
return ast.Arguments(pool, new_arg_list, old_args.vararg, old_args.kwarg,
|
||
old_args.defaults, old_args.kw_defaults)
|
||
def _clone_classdef_for_spec(self, pool: memhub.MemBuddy*,
|
||
cd: ast.ClassDef*,
|
||
spec_name: str,
|
||
tp_names: list[str]*,
|
||
type_args: list[str]*) -> ast.ClassDef*:
|
||
"""拷贝 ClassDef 节点用于泛型特化
|
||
|
||
- 替换类名为 spec_name
|
||
- 清除 type_params(特化后不是泛型类)
|
||
- 拷贝 children 中的 AnnAssign 和 FunctionDef,替换类型注解中的 T
|
||
- 方法体直接引用原始节点(通过 type_map 上下文处理 T)
|
||
"""
|
||
# 创建新 ClassDef(type_params=None 表示非泛型)
|
||
new_cd: ast.ClassDef* = ast.ClassDef(pool, spec_name, cd.bases, cd.keywords,
|
||
cd.decorator_list, None)
|
||
# 拷贝 children
|
||
if cd.children is not None:
|
||
cd_children: list[ast.AST*]* = cd.children
|
||
cn: sizet = len(cd_children)
|
||
ci: sizet
|
||
for ci in range(cn):
|
||
child: ast.AST* = cd_children.get(ci)
|
||
if child is None:
|
||
continue
|
||
ck: int = child.kind()
|
||
|
||
if ck == ast.ASTKind.AnnAssign:
|
||
aa: ast.AnnAssign* = ast.AnnAssign*(child)
|
||
new_target: ast.AST* = aa.target
|
||
new_anno2: ast.AST* = self._clone_annotation(pool, aa.annotation, tp_names, type_args)
|
||
new_value3: ast.AST* = aa.value
|
||
new_aa: ast.AnnAssign* = ast.AnnAssign(pool, new_target, new_anno2, new_value3, aa.simple)
|
||
new_cd.append(new_aa)
|
||
|
||
elif ck == ast.ASTKind.FunctionDef:
|
||
fd: ast.FunctionDef* = ast.FunctionDef*(child)
|
||
new_args2: ast.AST* = self._clone_arguments(pool, fd.args, tp_names, type_args)
|
||
new_returns2: ast.AST* = self._clone_annotation(pool, fd.returns, tp_names, type_args)
|
||
new_fd: ast.FunctionDef* = ast.FunctionDef(pool, fd.name, new_args2,
|
||
fd.decorator_list, new_returns2, 0)
|
||
# 方法体直接引用原始节点
|
||
if fd.children is not None:
|
||
fd_children: list[ast.AST*]* = fd.children
|
||
bcn: sizet = len(fd_children)
|
||
bci: sizet
|
||
for bci in range(bcn):
|
||
body_stmt: ast.AST* = fd_children.get(bci)
|
||
if body_stmt is not None:
|
||
new_fd.append(body_stmt)
|
||
new_cd.append(new_fd)
|
||
|
||
else:
|
||
new_cd.append(child)
|
||
|
||
return new_cd
|
||
def _find_cached_spec(self, spec_key: str) -> str:
|
||
"""查找已缓存的特化名,未找到返回 None"""
|
||
if self.SpecKeys is None or spec_key is None:
|
||
return None
|
||
i: int
|
||
for i in range(self.SpecCount):
|
||
key_addr: sizet = self.SpecKeys[i]
|
||
if key_addr != 0:
|
||
k: str = rawptr(key_addr)
|
||
if k is not None and string.strcmp(k, spec_key) == 0:
|
||
name_addr: sizet = self.SpecNames[i]
|
||
if name_addr != 0:
|
||
return rawptr(name_addr)
|
||
return None
|
||
def _cache_spec(self, pool: memhub.MemBuddy*, spec_key: str, spec_name: str):
|
||
"""缓存特化结果(stdlib 深拷贝存储,跨文件安全)"""
|
||
if spec_key is None or spec_name is None:
|
||
return
|
||
if self.SpecKeys is None:
|
||
self.SpecKeys = CompilerFactory.factory.PermPool.alloc(SPEC_CACHE_MAX * 8)
|
||
self.SpecNames = CompilerFactory.factory.PermPool.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)
|
||
string.memset(self.SpecNames, 0, SPEC_CACHE_MAX * 8)
|
||
self.SpecCount = 0
|
||
if self.SpecCount >= SPEC_CACHE_MAX:
|
||
return
|
||
# 深拷贝字符串到 stdlib 区
|
||
key_len: sizet = string.strlen(spec_key)
|
||
name_len: sizet = string.strlen(spec_name)
|
||
key_copy: str = CompilerFactory.factory.PermPool.alloc(key_len + 1)
|
||
name_copy: str = CompilerFactory.factory.PermPool.alloc(name_len + 1)
|
||
if key_copy is None or name_copy is None:
|
||
return
|
||
string.strcpy(key_copy, spec_key)
|
||
string.strcpy(name_copy, spec_name)
|
||
self.SpecKeys[self.SpecCount] = sizet(key_copy)
|
||
self.SpecNames[self.SpecCount] = sizet(name_copy)
|
||
self.SpecCount += 1
|
||
def _merge_template_imports(self, trans: HT.Translator*,
|
||
template_sha1: str) -> None:
|
||
"""将模板模块的 imports 并入 trans._imported_modules(空格分隔)"""
|
||
if trans is None or template_sha1 is None:
|
||
return
|
||
tdeps: str = StubMergerStore.LookupIncludesDeps(template_sha1)
|
||
if tdeps is None or tdeps[0] == '\0':
|
||
return
|
||
cur: str = trans._imported_modules
|
||
if cur is None or cur[0] == '\0':
|
||
trans._imported_modules = tdeps
|
||
return
|
||
cur_len: sizet = string.strlen(cur)
|
||
td_len: sizet = string.strlen(tdeps)
|
||
merged: str = trans.Pool.alloc(cur_len + td_len + 2)
|
||
if merged is None:
|
||
return
|
||
string.strcpy(merged, cur)
|
||
merged[cur_len] = ' '
|
||
string.strcpy(merged + cur_len + 1, tdeps)
|
||
trans._imported_modules = merged
|
||
def _record_spec_trigger(self, pool: memhub.MemBuddy*,
|
||
spec_name: str, trigger_sha1: str) -> int:
|
||
"""记录泛型特化类的触发文件 sha1(StructEntry.SpecTriggerSha1)
|
||
|
||
特化类 ModuleSha1=模板 sha1(方法名带模板前缀),Phase A _deps_pending
|
||
作废重译时 reset_module_methods_emitted 按当前文件 sha1 匹配不到 →
|
||
特化方法体 MethodsEmitted 残留 1 → 下遍不补译 → 链接 undefined symbol。
|
||
记录触发文件 sha1 后按此精确重置(见 StructGenMixin.reset_module_methods_emitted)。
|
||
"""
|
||
if spec_name is None or trigger_sha1 is None:
|
||
return 0
|
||
entry_rt: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(spec_name)
|
||
if entry_rt is None:
|
||
return 0
|
||
if string.strcmp(entry_rt.Name, spec_name) != 0:
|
||
return 0
|
||
ts_len_r: sizet = string.strlen(trigger_sha1)
|
||
ts_buf_r: str = CompilerFactory.factory.PermPool.alloc(ts_len_r + 1)
|
||
if ts_buf_r is None:
|
||
return 0
|
||
string.strcpy(ts_buf_r, trigger_sha1)
|
||
entry_rt.SpecTriggerSha1 = ts_buf_r
|
||
return 1
|
||
def _specialize_generic_class(self, trans: HT.Translator*,
|
||
class_name: str,
|
||
type_args: list[str]*) -> str:
|
||
"""特化泛型类,返回特化类名
|
||
|
||
1. 查找泛型模板
|
||
2. 生成特化名
|
||
3. 检查缓存
|
||
4. 拷贝 ClassDef 节点(替换类型注解中的 T)
|
||
5. 设置 type_map 上下文(用于方法体中的 T 替换)
|
||
6. 调用 translate_class_def 翻译特化类
|
||
7. 返回特化名
|
||
"""
|
||
if trans is None or class_name is None or type_args is None:
|
||
return None
|
||
# 泛型循环套用防护:递归深度 +1,超过上限立即报错终止(防 F-bounded
|
||
# 等循环特化把编译变死循环)。所有返回路径都必须 -1(见各 return 前)。
|
||
self.GenericSpecDepth += 1
|
||
# 特化触发文件 sha1:进入函数时 trans.ModuleSha1 是触发方文件,
|
||
# 翻译特化类时会被切换为模板 sha1(见下方),作废重译时按此重置
|
||
# 特化类 MethodsEmitted(见 _record_spec_trigger / reset_module_methods_emitted)
|
||
spec_trigger_sha1: str = trans.ModuleSha1
|
||
if self.GenericSpecDepth > GENERIC_SPEC_MAX_DEPTH:
|
||
err_spec: str = trans.Pool.alloc(256)
|
||
if err_spec is not None:
|
||
viperlib.snprintf(err_spec, 256,
|
||
"泛型特化递归过深(疑似泛型循环套用),类: %s 深度=%d",
|
||
class_name, self.GenericSpecDepth)
|
||
self.Gen.TypeGenErr.fatal_error(None, err_spec, "InternalCompilerError")
|
||
self.Gen.TypeGenErr.fatal_error(None, "泛型特化递归过深(疑似泛型循环套用)", "InternalCompilerError")
|
||
# 防御:泛型上下文内收集的 type_args 若残留未替换的类型参数名(如 "T"),
|
||
# 统一替换为具体类型名,避免 ndarray[T] 二次递归特化崩溃。
|
||
# 调用方传入的 type_args 均为临时新建列表,就地替换无共享副作用。
|
||
ta_cnt_g: sizet = len(type_args)
|
||
ta_i_g: sizet
|
||
for ta_i_g in range(ta_cnt_g):
|
||
ta_raw_g: str = type_args.get(ta_i_g)
|
||
if ta_raw_g is not None:
|
||
ta_rsv_g: str = self.Gen.TypeGenBase.resolve_generic_type_name(ta_raw_g)
|
||
if ta_rsv_g is not None and string.strcmp(ta_raw_g, ta_rsv_g) != 0:
|
||
type_args.set(ta_i_g, ta_rsv_g)
|
||
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
|
||
# 1. 查找泛型模板
|
||
template_cd: ast.ClassDef* = self._find_generic_template(class_name)
|
||
if template_cd is None:
|
||
self.GenericSpecDepth -= 1
|
||
return None
|
||
|
||
# 2. 生成特化名(唯一生成器内部逐实参规范化:裸名/带前缀在此收敛为同一名)
|
||
_from_imports: str = None
|
||
if trans is not None:
|
||
_from_imports = trans._from_imports
|
||
spec_name: str = self._mangle_generic_class_name(pool, class_name, type_args, _from_imports)
|
||
if spec_name is None:
|
||
self.GenericSpecDepth -= 1
|
||
return None
|
||
|
||
# Phase B 补译泛型特化类方法体(统一入口,在 cache/existing 检查之前):Phase 1a
|
||
# 特化时只注册结构体不译方法体(MethodsEmitted==0),Phase B 重复进入时补译以生成
|
||
# define,避免符号只有 declare 无 define → 链接失败。
|
||
# 首次 Phase B 特化(Phase 1a 未特化)find_struct 返回 None,不补译,走下方正常全量翻译。
|
||
if trans._declare_only == 0:
|
||
pre_existing: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(spec_name)
|
||
if pre_existing is not None and pre_existing.MethodsEmitted == 0:
|
||
# 防重入:先标记 MethodsEmitted=1,避免补译过程中方法体/返回类型注解
|
||
# 再次触发 _specialize_generic_class(如 __iter__ 返回 list[T]|t.CPtr)
|
||
# 导致无限递归补译 → OOM。补译完成后已设置,无需恢复。
|
||
# 注意:此处提前置位后调用 _translate_oop_methods 必须传 reemit=1
|
||
# (补译模式),否则其 MethodsEmitted==1 防重复检查会拦截补译,
|
||
# 方法体永不发射 → 特化方法只有 call 无 define → 链接 undefined symbol。
|
||
pre_existing.MethodsEmitted = 1
|
||
# 从 stdlib 深拷贝表取 type_params(模板节点 pool list 跨 Phase 可能失效)
|
||
tp_names_pre: list[str]* = self._find_generic_template_tp_params(pool, class_name)
|
||
if tp_names_pre is None:
|
||
tp_names_pre = template_cd.type_params
|
||
spec_cd_pre: ast.ClassDef* = self._clone_classdef_for_spec(pool, template_cd, spec_name, tp_names_pre, type_args)
|
||
if spec_cd_pre is not None:
|
||
trans.GenericTypeParamNames = tp_names_pre
|
||
trans.GenericTypeArgs = type_args
|
||
self.Gen.TypeGenBase.set_generic_context(tp_names_pre, type_args)
|
||
saved_ms_pre: str = trans.ModuleSha1
|
||
saved_imp_pre: str = trans._imported_modules
|
||
template_sha1_pre: str = self._find_generic_template_sha1(class_name)
|
||
if template_sha1_pre is not None:
|
||
trans.ModuleSha1 = template_sha1_pre
|
||
self._merge_template_imports(trans, template_sha1_pre)
|
||
# 错误定位上下文:补译的是模板方法体(spec_cd_pre 克隆自模板,
|
||
# node.lineno 是模板文件行号)。切换 CurrentFile 到模板文件并压入
|
||
# trace 帧,使 fatal_error 正确显示模板文件位置(翻译完恢复)。
|
||
saved_cur_pre: str = self.Gen.TypeGenResolve.get_current_file()
|
||
tpl_file_pre: str = self._find_generic_template_file(class_name)
|
||
if tpl_file_pre is not None:
|
||
self.Gen.TypeGenResolve.set_current_file(tpl_file_pre)
|
||
self.Gen.TypeGenBase.push_trace(tpl_file_pre, template_cd.lineno)
|
||
self.Gen.ClassGenVTable._translate_oop_methods(trans, spec_cd_pre, pre_existing.Ty, spec_name, 0, 1)
|
||
if tpl_file_pre is not None:
|
||
self.Gen.TypeGenBase.pop_trace()
|
||
self.Gen.TypeGenResolve.set_current_file(saved_cur_pre)
|
||
trans.ModuleSha1 = saved_ms_pre
|
||
trans._imported_modules = saved_imp_pre
|
||
trans.GenericTypeParamNames = None
|
||
trans.GenericTypeArgs = None
|
||
self.Gen.TypeGenBase.clear_generic_context()
|
||
|
||
# 3. 检查缓存(spec_key 包含所有类型实参,避免多参数泛型缓存冲突)
|
||
# 分配新缓冲区避免原地 strcat 溢出
|
||
sk_n: sizet = len(type_args)
|
||
sk_total: sizet = string.strlen(class_name) + 2 # "<" 和 ">"
|
||
sk_i: sizet
|
||
for sk_i in range(sk_n):
|
||
if sk_i > 0:
|
||
sk_total += 1 # ","
|
||
sk_ta: str = type_args.get(sk_i)
|
||
if sk_ta is not None:
|
||
sk_total += string.strlen(sk_ta)
|
||
sk_total += 1 # NUL
|
||
spec_key: str = pool.alloc(sk_total)
|
||
if spec_key is None:
|
||
self.GenericSpecDepth -= 1
|
||
return None
|
||
spec_key[0] = '\0'
|
||
string.strcat(spec_key, class_name)
|
||
string.strcat(spec_key, "<")
|
||
for sk_i in range(sk_n):
|
||
if sk_i > 0:
|
||
string.strcat(spec_key, ",")
|
||
sk_ta: str = type_args.get(sk_i)
|
||
if sk_ta is not None:
|
||
string.strcat(spec_key, sk_ta)
|
||
string.strcat(spec_key, ">")
|
||
cached: str = self._find_cached_spec(spec_key)
|
||
if cached is not None:
|
||
self._record_spec_trigger(pool, spec_name, spec_trigger_sha1)
|
||
self.GenericSpecDepth -= 1
|
||
return cached
|
||
|
||
# 4. 检查是否已注册(Phase B 重复特化)
|
||
existing: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(spec_name)
|
||
if existing is not None:
|
||
self._cache_spec(pool, spec_key, spec_name)
|
||
self._record_spec_trigger(pool, spec_name, spec_trigger_sha1)
|
||
self.GenericSpecDepth -= 1
|
||
return spec_name
|
||
|
||
# 预注册缓存(防止递归)
|
||
self._cache_spec(pool, spec_key, spec_name)
|
||
|
||
# 5. 拷贝 ClassDef 节点
|
||
# 从 stdlib 深拷贝表取 type_params(模板节点 pool list 跨 Phase 可能失效)
|
||
tp_names: list[str]* = self._find_generic_template_tp_params(pool, class_name)
|
||
if tp_names is None:
|
||
tp_names = template_cd.type_params
|
||
spec_cd: ast.ClassDef* = self._clone_classdef_for_spec(pool, template_cd, spec_name, tp_names, type_args)
|
||
if spec_cd is None:
|
||
self.GenericSpecDepth -= 1
|
||
return None
|
||
|
||
# 6. 设置 type_map 上下文(用于方法体中的 T 替换)
|
||
trans.GenericTypeParamNames = tp_names
|
||
trans.GenericTypeArgs = type_args
|
||
self.Gen.TypeGenBase.set_generic_context(tp_names, type_args)
|
||
|
||
# 7. 翻译特化类
|
||
# 切换 trans.ModuleSha1 为泛型模板定义模块的 SHA1,
|
||
# 使结构体类型名与特化方法函数符号名都用定义模块的 SHA1 前缀
|
||
# (跨模块一致,单态化特化名 = {模板SHA1}.Class[param].method)。
|
||
# 同时并入模板模块的 imports(见 _merge_template_imports 注释),
|
||
# 避免模板方法体内的跨模块调用被误报"模块未导入"。
|
||
saved_module_sha1: str = trans.ModuleSha1
|
||
saved_imported: str = trans._imported_modules
|
||
# 【窗口同进同出】类定义窗口(CurDefModuleSha1/CurDefClassName)必须与
|
||
# ModuleSha1 一起保存/恢复:下方 translate_class_def(:729)内部会按
|
||
# **模板模块 sha1 + 特化类名** 调 mark_module_class(ClassGenDef.vp:50),
|
||
# 覆盖这两个窗口变量。原实现只恢复 trans.ModuleSha1 ⇒ 调用方文件在此之后
|
||
# 解析任何裸类名时,规则 5.5 的归属判据(证据 ② is_module_class /
|
||
# ③ CurDefClassName 逐字相同)全都在对着"模板模块 / 特化类"判 ⇒ 判不到
|
||
# ⇒ 该实参以**裸名**形式被首次注册并永久复用,与同一特化在别处解析出的
|
||
# 带 SHA1 形式分裂成两个名字,最终以"被指类型是非基本类型……不可隐式转换"
|
||
# 报出(现场:includes/ast/base.vp:359 `_append_child(self.children, ...)`
|
||
# 源 list[rawptr[AST]] vs 目标 list[rawptr<定义模块SHA1>.AST])。
|
||
saved_def_mod: str = self.Gen.StructGen.CurDefModuleSha1
|
||
saved_def_cls: str = self.Gen.StructGen.CurDefClassName
|
||
template_sha1: str = self._find_generic_template_sha1(class_name)
|
||
if template_sha1 is not None:
|
||
trans.ModuleSha1 = template_sha1
|
||
self._merge_template_imports(trans, template_sha1)
|
||
# 错误定位上下文:spec_cd 克隆自模板,方法体的 node.lineno 是模板文件
|
||
# 行号,而 CurrentFile 仍是调用方文件 → 错误显示错位。切换 CurrentFile
|
||
# 到模板文件并压入 trace 帧(翻译完恢复),使 fatal_error 正确溯源。
|
||
saved_cur_full: str = self.Gen.TypeGenResolve.get_current_file()
|
||
tpl_file_full: str = self._find_generic_template_file(class_name)
|
||
if tpl_file_full is not None:
|
||
self.Gen.TypeGenResolve.set_current_file(tpl_file_full)
|
||
self.Gen.TypeGenBase.push_trace(tpl_file_full, template_cd.lineno)
|
||
self.Gen.ClassGenDef.translate_class_def(trans, spec_cd)
|
||
if tpl_file_full is not None:
|
||
self.Gen.TypeGenBase.pop_trace()
|
||
self.Gen.TypeGenResolve.set_current_file(saved_cur_full)
|
||
# 恢复原始 ModuleSha1 / imports / **类定义窗口**(窗口不平移,见上方说明)
|
||
trans.ModuleSha1 = saved_module_sha1
|
||
trans._imported_modules = saved_imported
|
||
self.Gen.StructGen.CurDefModuleSha1 = saved_def_mod
|
||
self.Gen.StructGen.CurDefClassName = saved_def_cls
|
||
|
||
# 8. 清除 type_map 上下文
|
||
trans.GenericTypeParamNames = None
|
||
trans.GenericTypeArgs = None
|
||
self.Gen.TypeGenBase.clear_generic_context()
|
||
|
||
# 特化结果字段名完整性检查(fail-fast:字段名缺失 = 字段表损坏,
|
||
# 静默继续会让后续 GEP 按错索引访问)
|
||
if string.strcmp(class_name, "GSListNode") == 0:
|
||
result_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(spec_name)
|
||
if result_entry is not None:
|
||
for ri in range(result_entry.FieldCount):
|
||
rfe: GenTypes.FieldEntry* = self.Gen.StructGen._get_field_entry(result_entry, ri)
|
||
if rfe is not None:
|
||
rfn: str = self.Gen.StructGen.get_field_name_ptr(rfe)
|
||
if rfn is None:
|
||
VLogger.error("SPEC 字段名缺失(字段表损坏)", "SPEC")
|
||
self.Gen.TypeGenErr.fatal_error(None, "SPEC 字段名缺失(字段表损坏)", "TypeError")
|
||
|
||
self._record_spec_trigger(pool, spec_name, spec_trigger_sha1)
|
||
self.GenericSpecDepth -= 1
|
||
return spec_name |