feat(TPV): CArray 形参衰减/tuple 多返回/dict 迭代/ASan 模式等
- CArray 形参按 C 语义衰减为元素指针(FuncGenMixin/ClassGenMixin/VpiReader 多处)
- 跨模块调用 found_func=None 时数组实参衰减,修复 md5.final 实参 [16 x i8]* 与
定义 i8* 类型不匹配
- VpiReader 返回注解支持 tuple[T1,T2] -> 匿名结构体(b2a_hqx -> {i8*,i16})
- 变参 i8/i16 提升按无符号性 zext/sext(print_hex %02x 不再 ffffff 前缀)
- dict 容器可见性/迭代、c.Deref 赋值注解宽度推断、错误定位日志
- HandlesExprCall._check_and_promote_variadic_call 委托同步 9 参
- BuildPipeline/main 支持 --asan 模式(opt -passes=asan + -fsanitize=address)
This commit is contained in:
1 parent
4fd331dc08
commit
304bece6fa
17 files changed
+1202
-50
No files matched your search
@@ -479,6 +479,26 @@ def _resolve_single_vpi_type_str(pool: memhub.MemBuddy | t.CPtr,
|
||||
return llvmlite.Int32(pool)
|
||||
if string.strcmp(seg, "bool") == 0:
|
||||
return llvmlite.Int1(pool)
|
||||
# LLVM 类型串:vpi 缓存对无返回注解方法默认存 "i32"
|
||||
# (见 _cache_vpi_return_annots_text;push 等无注解方法返回 i32)。
|
||||
# 之前缺分支导致解析返回 None → 泛型模板方法(Vector[int].push)调用
|
||||
# 走 fail-fast"方法返回类型无法精确获取",实际是约定不一致。
|
||||
if string.strcmp(seg, "i32") == 0:
|
||||
return llvmlite.Int32(pool)
|
||||
if string.strcmp(seg, "i64") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
if string.strcmp(seg, "i16") == 0:
|
||||
return llvmlite.Int16(pool)
|
||||
if string.strcmp(seg, "i8") == 0:
|
||||
return i8_ty
|
||||
if string.strcmp(seg, "i1") == 0:
|
||||
return llvmlite.Int1(pool)
|
||||
if string.strcmp(seg, "f32") == 0:
|
||||
return llvmlite.Float(pool)
|
||||
if string.strcmp(seg, "f64") == 0:
|
||||
return llvmlite.Double(pool)
|
||||
if string.strcmp(seg, "void") == 0:
|
||||
return llvmlite.Void(pool)
|
||||
# t.XXX / c.XXX 内置类型映射
|
||||
if string.strncmp(seg, "t.", 2) == 0 or string.strncmp(seg, "c.", 2) == 0:
|
||||
attr_nm: str = seg + 2
|
||||
@@ -525,6 +545,54 @@ def _resolve_vpi_ret_annot_str(pool: memhub.MemBuddy | t.CPtr,
|
||||
if ret_annot is None or pool is None:
|
||||
return None
|
||||
|
||||
# tuple[T1, T2, ...] → 匿名结构体 {T1, T2, ...}(多返回值打包,
|
||||
# 与 TypeGenMixin._resolve_generic_subscript_ty 的 tuple 分支一致)。
|
||||
# b2a_hqx -> tuple[str, t.CUnsignedShort] 之前按普通段解析失败 → 调用侧
|
||||
# 返回类型退化 i8* → tuple 解包失效(hqx 段崩溃根因)。
|
||||
if string.strncmp(ret_annot, "tuple[", 6) == 0:
|
||||
inner_len_t: t.CSizeT = 0
|
||||
while ret_annot[6 + inner_len_t] != ']' and ret_annot[6 + inner_len_t] != '\0':
|
||||
inner_len_t += 1
|
||||
if ret_annot[6 + inner_len_t] != ']' or inner_len_t == 0:
|
||||
return None
|
||||
tup_head_t: llvmlite.ParamNode | t.CPtr = None
|
||||
tup_tail_t: llvmlite.ParamNode | t.CPtr = None
|
||||
tup_count_t: int = 0
|
||||
p_t: t.CSizeT = 0
|
||||
while p_t < inner_len_t:
|
||||
# 跳过前导空格/逗号
|
||||
while p_t < inner_len_t and (ret_annot[6 + p_t] == ' ' or ret_annot[6 + p_t] == ','):
|
||||
p_t += 1
|
||||
seg_s_t: t.CSizeT = p_t
|
||||
while p_t < inner_len_t and ret_annot[6 + p_t] != ',':
|
||||
p_t += 1
|
||||
seg_e_t: t.CSizeT = p_t
|
||||
while seg_e_t > seg_s_t and ret_annot[6 + seg_e_t - 1] == ' ':
|
||||
seg_e_t -= 1
|
||||
if seg_e_t > seg_s_t:
|
||||
seg_len_t: t.CSizeT = seg_e_t - seg_s_t
|
||||
seg_buf_t: bytes = stdlib.malloc(seg_len_t + 1)
|
||||
if seg_buf_t is None:
|
||||
return None
|
||||
string.strncpy(seg_buf_t, ret_annot + 6 + seg_s_t, seg_len_t)
|
||||
seg_buf_t[seg_len_t] = '\0'
|
||||
seg_ty_t: llvmlite.LLVMType | t.CPtr = _resolve_single_vpi_type_str(pool, seg_buf_t)
|
||||
stdlib.free(seg_buf_t)
|
||||
if seg_ty_t is None:
|
||||
return None
|
||||
tup_node_t: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, seg_ty_t)
|
||||
if tup_node_t is None:
|
||||
return None
|
||||
if tup_head_t is None:
|
||||
tup_head_t = tup_node_t
|
||||
else:
|
||||
llvmlite.paramnode_set_next(tup_tail_t, tup_node_t)
|
||||
tup_tail_t = tup_node_t
|
||||
tup_count_t += 1
|
||||
if tup_head_t is None:
|
||||
return None
|
||||
return llvmlite.Struct(pool, tup_head_t, tup_count_t, None)
|
||||
|
||||
has_cptr: int = 0
|
||||
has_cvoid: int = 0
|
||||
first_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
@@ -836,6 +904,34 @@ def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy | t.CPtr,
|
||||
imported_modules = stub_imported_modules
|
||||
if stub_from_imports is not None:
|
||||
from_imports = stub_from_imports
|
||||
# 把源模块自己加入 stub 注解上下文:stub 注解(如 __sha512 的 transform
|
||||
# 参数 t.CArray[t.CUInt8T, SHA512_BLOCK_LEN])引用源模块自身的 CDefine,
|
||||
# 但 stub 的 import 只含被 import 的模块(t/c/string),不含自己。
|
||||
# 不加则 _eval_const_int_expr 跨模块 CDefine 查找遍历不到源模块
|
||||
# (imported_modules 无 __sha512)→ t.CArray count 报"必须是整数常量"。
|
||||
# 示例:RelPath "hashlib/__sha512.vp" → 模块名 "hashlib.__sha512"。
|
||||
if src_sha1 is not None:
|
||||
import lib.core.StubMerger as StubMerger
|
||||
stub_rel_src: str = StubMerger.LookupSha1RelPath(src_sha1)
|
||||
if stub_rel_src is not None:
|
||||
sr_len_src: t.CSizeT = string.strlen(stub_rel_src)
|
||||
if sr_len_src > 3 and string.strncmp(stub_rel_src + sr_len_src - 3, ".vp", 3) == 0:
|
||||
sr_len_src -= 3
|
||||
elif sr_len_src > 3 and string.strncmp(stub_rel_src + sr_len_src - 3, ".py", 3) == 0:
|
||||
sr_len_src -= 3
|
||||
if sr_len_src > 0:
|
||||
src_mod_buf: str = stdlib.malloc(sr_len_src + 1)
|
||||
if src_mod_buf is not None:
|
||||
sri_src: t.CSizeT
|
||||
for sri_src in range(sr_len_src):
|
||||
ch_src: t.CChar = stub_rel_src[sri_src]
|
||||
if ch_src == '/' or ch_src == '\\':
|
||||
src_mod_buf[sri_src] = '.'
|
||||
else:
|
||||
src_mod_buf[sri_src] = ch_src
|
||||
src_mod_buf[sr_len_src] = '\0'
|
||||
imported_modules = _stub_add_imported(pool, imported_modules, src_mod_buf)
|
||||
stdlib.free(src_mod_buf)
|
||||
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
@@ -1019,9 +1115,12 @@ def _inject_function_declare(pool: memhub.MemBuddy | t.CPtr,
|
||||
# (未定义字段),LLVM 不允许 opaque struct 作为函数参数
|
||||
# (llc: invalid type for function argument)。Windows ABI
|
||||
# 小结构体(≤8 字节,如 COORD)按整数寄存器传,映射 i64 兼容。
|
||||
# CArray 参数 → 元素指针 ty*(C 数组衰减,与编译侧一致)。
|
||||
match resolved_ty:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
param_ty = llvmlite.Int64(pool)
|
||||
case llvmlite.LLVMType.Array(aelem_ty, _):
|
||||
param_ty = llvmlite.Ptr(pool, aelem_ty)
|
||||
case _:
|
||||
param_ty = resolved_ty
|
||||
llvmlite.add_param(pool, func, param_ty, pname)
|
||||
@@ -1134,9 +1233,12 @@ def _inject_method_declare(pool: memhub.MemBuddy | t.CPtr,
|
||||
# (未定义字段),LLVM 不允许 opaque struct 作为函数参数
|
||||
# (llc: invalid type for function argument)。Windows ABI
|
||||
# 小结构体(≤8 字节,如 COORD)按整数寄存器传,映射 i64 兼容。
|
||||
# CArray 参数 → 元素指针 ty*(C 数组衰减,与编译侧一致)。
|
||||
match resolved_ty:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
param_ty = llvmlite.Int64(pool)
|
||||
case llvmlite.LLVMType.Array(aelem_ty, _):
|
||||
param_ty = llvmlite.Ptr(pool, aelem_ty)
|
||||
case _:
|
||||
param_ty = resolved_ty
|
||||
llvmlite.add_param(pool, func, param_ty, pname)
|
||||
|
||||
@@ -49,6 +49,15 @@ import lib.core.Gen.Generator as GenGenerator
|
||||
# 全局 mbuddy 指针
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
# ASan 模式(--asan):对 .ll 先 opt -passes=asan 插桩,链接加 -fsanitize=address
|
||||
_asan_mode: t.CInt = 0
|
||||
|
||||
|
||||
def set_asan_mode(flag: int) -> None:
|
||||
"""设置 ASan 模式(1=启用,0=禁用)"""
|
||||
global _asan_mode
|
||||
_asan_mode = flag
|
||||
|
||||
# 源代码缓冲区大小(1MB)
|
||||
SRC_BUF_SIZE: t.CDefine = 1048576 # 2^20 = 1MB
|
||||
|
||||
@@ -367,12 +376,36 @@ def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: s
|
||||
if obj_path is None:
|
||||
return 1
|
||||
|
||||
# ASan 模式(_asan_mode=1):先 opt -passes=asan 插桩再 llc。
|
||||
# -asan-globals=false 关闭全局插桩:TPV 对全局变量(如各模块 _g_gen)
|
||||
# 用直接地址寻址,ASan 全局 redzone 重定位后引用错位会读到垃圾指针。
|
||||
compile_input: str = ir_path
|
||||
if _asan_mode != 0:
|
||||
asan_path: str = build_sliced_path(output_dir, module_name, "asan.ll")
|
||||
if asan_path is None:
|
||||
return 1
|
||||
opt_cmd_len: t.CSizeT = string.strlen(asan_path) + string.strlen(ir_path) + 96
|
||||
opt_cmd: bytes = _mbuddy.alloc(opt_cmd_len)
|
||||
if opt_cmd is None:
|
||||
return 1
|
||||
viperlib.snprintf(opt_cmd, opt_cmd_len,
|
||||
"opt -passes=asan -asan-globals=false -o %s %s",
|
||||
asan_path, ir_path)
|
||||
opt_ret: int = stdlib.system(opt_cmd)
|
||||
if opt_ret != 0:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "opt ASan 插桩失败 (module=%s)", module_name)
|
||||
VLogger.error(fb, "ASAN")
|
||||
return 1
|
||||
compile_input = asan_path
|
||||
|
||||
# 构造命令: llc -filetype=obj -o {obj_path} ir_path
|
||||
cmd_len: t.CSizeT = string.strlen(cc_cmd) + string.strlen(cc_flags) + string.strlen(obj_path) + string.strlen(ir_path) + 64
|
||||
cmd_len: t.CSizeT = string.strlen(cc_cmd) + string.strlen(cc_flags) + string.strlen(obj_path) + string.strlen(compile_input) + 64
|
||||
cmd: bytes = _mbuddy.alloc(cmd_len)
|
||||
if cmd is None:
|
||||
return 1
|
||||
viperlib.snprintf(cmd, cmd_len, "%s %s -o %s %s", cc_cmd, cc_flags, obj_path, ir_path)
|
||||
viperlib.snprintf(cmd, cmd_len, "%s %s -o %s %s", cc_cmd, cc_flags, obj_path, compile_input)
|
||||
|
||||
# 用 stdlib.system() 直接在控制台运行,输出直接显示
|
||||
# 避免 subprocess 管道捕获丢失输出
|
||||
@@ -519,18 +552,26 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
|
||||
|
||||
# 构造命令: clang++ {obj_path} extra_objs -o {output_dir}/{linker_output} linker_flags
|
||||
# 注意: .obj 文件必须在 -l 库标志之前,否则链接器无法解析符号依赖
|
||||
cmd_len: t.CSizeT = string.strlen(linker_cmd) + string.strlen(obj_path) + string.strlen(linker_flags) + string.strlen(output_dir) + string.strlen(linker_output) + extra_len + 128
|
||||
# ASan 模式:追加 -fsanitize=address 链接 libasan(配合 opt 插桩)
|
||||
use_flags: str = linker_flags
|
||||
if _asan_mode != 0:
|
||||
fl_len: t.CSizeT = string.strlen(linker_flags) + 32
|
||||
use_flags = _mbuddy.alloc(fl_len)
|
||||
if use_flags is None:
|
||||
return 1
|
||||
viperlib.snprintf(use_flags, fl_len, "%s -fsanitize=address", linker_flags)
|
||||
cmd_len: t.CSizeT = string.strlen(linker_cmd) + string.strlen(obj_path) + string.strlen(use_flags) + string.strlen(output_dir) + string.strlen(linker_output) + extra_len + 128
|
||||
cmd: bytes = _mbuddy.alloc(cmd_len)
|
||||
if cmd is None:
|
||||
return 1
|
||||
if extra_len > 0:
|
||||
viperlib.snprintf(cmd, cmd_len, "%s %s %s -o %s/%s %s",
|
||||
linker_cmd, obj_path, extra_objs,
|
||||
output_dir, linker_output, linker_flags)
|
||||
output_dir, linker_output, use_flags)
|
||||
else:
|
||||
viperlib.snprintf(cmd, cmd_len, "%s %s -o %s/%s %s",
|
||||
linker_cmd, obj_path, output_dir, linker_output,
|
||||
linker_flags)
|
||||
use_flags)
|
||||
|
||||
result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True)
|
||||
if result is None:
|
||||
@@ -630,17 +671,25 @@ def link_objs_to_exe(obj_paths: str, obj_paths_len: t.CSizeT,
|
||||
extra_len = collect_obj_files(includes_binary_dir, extra_objs, EXTRA_BUF_SIZE)
|
||||
|
||||
# 构造命令: clang++ obj_paths extra_objs -o linker_output linker_flags
|
||||
cmd_len: t.CSizeT = string.strlen(linker_cmd) + obj_paths_len + string.strlen(linker_flags) + string.strlen(linker_output) + extra_len + 128
|
||||
# ASan 模式:追加 -fsanitize=address 链接 libasan(配合 opt 插桩)
|
||||
use_flags: str = linker_flags
|
||||
if _asan_mode != 0:
|
||||
fl_len: t.CSizeT = string.strlen(linker_flags) + 32
|
||||
use_flags = _mbuddy.alloc(fl_len)
|
||||
if use_flags is None:
|
||||
return 1
|
||||
viperlib.snprintf(use_flags, fl_len, "%s -fsanitize=address", linker_flags)
|
||||
cmd_len: t.CSizeT = string.strlen(linker_cmd) + obj_paths_len + string.strlen(use_flags) + string.strlen(linker_output) + extra_len + 128
|
||||
cmd: bytes = _mbuddy.alloc(cmd_len)
|
||||
if cmd is None:
|
||||
return 1
|
||||
if extra_len > 0:
|
||||
viperlib.snprintf(cmd, cmd_len, "%s %s %s -o %s %s",
|
||||
linker_cmd, obj_paths, extra_objs,
|
||||
linker_output, linker_flags)
|
||||
linker_output, use_flags)
|
||||
else:
|
||||
viperlib.snprintf(cmd, cmd_len, "%s %s -o %s %s",
|
||||
linker_cmd, obj_paths, linker_output, linker_flags)
|
||||
linker_cmd, obj_paths, linker_output, use_flags)
|
||||
|
||||
# 用 subprocess.run 捕获 clang++ 的 stdout/stderr 输出
|
||||
# 之前用 stdlib.system() 无法捕获具体错误(undefined reference 等),
|
||||
|
||||
@@ -720,6 +720,30 @@ class CallGenMixin:
|
||||
if HandlesExpr.is_ptr_type(ptr_val.Ty) != 0:
|
||||
pointee: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee
|
||||
if pointee is not None:
|
||||
# i8*(void*)时按赋值目标类型推断读取宽度(对齐 TPC
|
||||
# HandlesSpecialCall._infer_deref_target_type):
|
||||
# v: int = c.Deref(p) → bitcast i32* 后 load 4 字节。
|
||||
# 背景:DictTest d3[key5]=500 读出 -12——固定按 i8 读 1 字节 +
|
||||
# sext 截断(0xF4 → 0xFFFFFFF4);Test 1 的小值(10)恰好正确
|
||||
# 掩盖了缺陷。
|
||||
match pointee:
|
||||
case llvmlite.LLVMType.Int(pointee_width):
|
||||
if pointee_width == 8 and trans is not None and trans.CurAssignAnnot is not None:
|
||||
dref_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||
trans.Pool, trans.CurAssignAnnot,
|
||||
trans._imported_modules, trans._from_imports, trans)
|
||||
if dref_ty is not None:
|
||||
dref_bits: int = HandlesExpr.get_llvm_type_bits(dref_ty)
|
||||
dref_fbits: int = HandlesExpr.get_llvm_float_bits(dref_ty)
|
||||
# 仅整数/浮点目标(struct 值目标不推断,保持 i8 读)
|
||||
if (dref_bits != 0 or dref_fbits != 0) and dref_bits != 8:
|
||||
dref_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, dref_ty)
|
||||
dref_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
builder, ptr_val, dref_ptr_ty)
|
||||
if dref_ptr is not None:
|
||||
return llvmlite.build_load(builder, dref_ty, dref_ptr)
|
||||
case _:
|
||||
pass
|
||||
return llvmlite.build_load(builder, pointee, ptr_val)
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
return llvmlite.build_load(builder, i8_ty, ptr_val)
|
||||
@@ -3706,6 +3730,20 @@ class CallGenMixin:
|
||||
if vpi_ret_ty is not None:
|
||||
call_ret_ty = vpi_ret_ty
|
||||
else:
|
||||
# 定位日志:返回类型解析失败前打印关键状态,
|
||||
# 便于区分是"特化未发生"还是"vpi 键不匹配"。
|
||||
fb_mcret: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_mcret is not None:
|
||||
viperlib.snprintf(
|
||||
fb_mcret, 1024,
|
||||
"[MC-RET-FAIL] class=%s m=%s sha1=%s entry_name=%s lookup=%s gen_done=%d",
|
||||
class_name,
|
||||
method_name if method_name is not None else "(null)",
|
||||
cls_sha1_mc if cls_sha1_mc is not None else "(null)",
|
||||
mc_entry.Name if mc_entry is not None and mc_entry.Name is not None else "(null)",
|
||||
lookup_name if lookup_name is not None else "(null)",
|
||||
gen_done)
|
||||
VLogger.info(fb_mcret, "MCRET")
|
||||
call_ret_ty = self._fail_method_ret_ty(method_name, cl)
|
||||
|
||||
# 翻译调用参数
|
||||
@@ -3843,6 +3881,23 @@ class CallGenMixin:
|
||||
if pty is not None:
|
||||
arg_val = HandlesExpr.coerce_to_type(
|
||||
builder, arg_val, pty, arg_node)
|
||||
else:
|
||||
# found_func=None(跨模块 stub 未注入):数组实参按 C 语义
|
||||
# 衰减为元素指针(对齐 TPC _decay_array_to_ptr)。否则
|
||||
# _ensure_method_declare 用 [N x ty]* 实参类型建 declare,
|
||||
# 与定义侧元素指针(如 md5.final 的 i8*)类型不匹配。
|
||||
if arg_val.Ty is not None and HandlesExpr.is_ptr_type(arg_val.Ty) != 0:
|
||||
arr_pointee_ma: llvmlite.LLVMType | t.CPtr = arg_val.Ty.Pointee
|
||||
if arr_pointee_ma is not None:
|
||||
match arr_pointee_ma:
|
||||
case llvmlite.LLVMType.Array(arr_et_ma, _):
|
||||
decayed_ma: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||||
builder, arr_pointee_ma, arr_et_ma, arg_val,
|
||||
llvmlite.const_int32(pool, 0))
|
||||
if decayed_ma is not None:
|
||||
arg_val = decayed_ma
|
||||
case _:
|
||||
pass
|
||||
llvmlite.value_set_next(arg_val, None)
|
||||
llvmlite.value_set_next(tail, arg_val)
|
||||
tail = arg_val
|
||||
@@ -3945,8 +4000,9 @@ class CallGenMixin:
|
||||
|
||||
# 跨模块调用:创建 declare 声明,避免 llc 报 undefined value
|
||||
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count)
|
||||
# 检查变长函数 + C ABI 提升
|
||||
is_variadic_3441: int = HandlesExprCall._check_and_promote_variadic_call(pool, builder, mod, call_name, head, total_count)
|
||||
# 检查变长函数 + C ABI 提升(cargs 是实参 AST,self_offset=1 跳过 self)
|
||||
is_variadic_3441: int = HandlesExprCall._check_and_promote_variadic_call(
|
||||
pool, builder, mod, call_name, head, total_count, cargs, 1, trans)
|
||||
return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, is_variadic_3441)
|
||||
|
||||
# ============================================================
|
||||
@@ -4116,6 +4172,21 @@ class CallGenMixin:
|
||||
if pty_sp is not None:
|
||||
arg_val_sp = HandlesExpr.coerce_to_type(
|
||||
builder, arg_val_sp, pty_sp, arg_node_sp)
|
||||
else:
|
||||
# found_func=None:数组实参按 C 语义衰减为元素指针
|
||||
# (与 _translate_method_call 一致,避免 declare 类型不匹配)
|
||||
if arg_val_sp.Ty is not None and HandlesExpr.is_ptr_type(arg_val_sp.Ty) != 0:
|
||||
arr_pointee_sp: llvmlite.LLVMType | t.CPtr = arg_val_sp.Ty.Pointee
|
||||
if arr_pointee_sp is not None:
|
||||
match arr_pointee_sp:
|
||||
case llvmlite.LLVMType.Array(arr_et_sp, _):
|
||||
decayed_sp: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||||
builder, arr_pointee_sp, arr_et_sp, arg_val_sp,
|
||||
llvmlite.const_int32(pool, 0))
|
||||
if decayed_sp is not None:
|
||||
arg_val_sp = decayed_sp
|
||||
case _:
|
||||
pass
|
||||
llvmlite.value_set_next(arg_val_sp, None)
|
||||
llvmlite.value_set_next(tail, arg_val_sp)
|
||||
tail = arg_val_sp
|
||||
@@ -4139,7 +4210,7 @@ class CallGenMixin:
|
||||
if found_func is None:
|
||||
self._ensure_method_declare(pool, mod, call_name, ret_ty_sp, head, arg_count_sp)
|
||||
is_variadic_sp: int = HandlesExprCall._check_and_promote_variadic_call(
|
||||
pool, builder, mod, call_name, head, arg_count_sp)
|
||||
pool, builder, mod, call_name, head, arg_count_sp, cargs_sp, 1, trans)
|
||||
return llvmlite.build_call(builder, call_name, head, arg_count_sp, ret_ty_sp, is_variadic_sp)
|
||||
|
||||
# ============================================================
|
||||
@@ -5109,6 +5180,43 @@ class CallGenMixin:
|
||||
fi_gp = trans._from_imports
|
||||
bare_ty = HandlesType.resolve_annotation_type(
|
||||
pool, gp_ast, imp_gp, fi_gp, trans)
|
||||
# 泛型类型参数双参数形式: T(val, t.CPtr) → Ptr(T)
|
||||
# (与 t.CInt(val, t.CPtr) → Ptr(i32) 对齐;vector.vp get() 的
|
||||
# typed_ptr = T(offset, t.CPtr) 依赖此路径,否则双参数不进
|
||||
# can==1 单参数分支 → 跌落到"裸名调用未定义"误报)
|
||||
if bare_ty is not None and can == 2:
|
||||
bare_arg2_node: ast.AST | t.CPtr = cargs.get(1)
|
||||
bare_arg2_is_cptr: int = 0
|
||||
if bare_arg2_node is not None:
|
||||
# 形式 1: t.CPtr(Attribute 形式)
|
||||
if bare_arg2_node.kind() == ast.ASTKind.Attribute:
|
||||
bare_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(bare_arg2_node)
|
||||
if bare_arg2_at.attr is not None and string.strcmp(bare_arg2_at.attr, "CPtr") == 0:
|
||||
if bare_arg2_at.value is not None and bare_arg2_at.value.kind() == ast.ASTKind.Name:
|
||||
bare_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bare_arg2_at.value)
|
||||
if bare_arg2_nm.id is not None and string.strcmp(bare_arg2_nm.id, "t") == 0:
|
||||
bare_arg2_is_cptr = 1
|
||||
# 形式 2: 裸名 CPtr(from t import CPtr 后直接使用)
|
||||
elif bare_arg2_node.kind() == ast.ASTKind.Name:
|
||||
bare_arg2_bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bare_arg2_node)
|
||||
if bare_arg2_bn.id is not None and string.strcmp(bare_arg2_bn.id, "CPtr") == 0:
|
||||
bare_arg2_is_cptr = 1
|
||||
if bare_arg2_is_cptr != 0:
|
||||
# CVoid* → i8*(LLVM 中 void* 表示为 i8*)
|
||||
match bare_ty:
|
||||
case llvmlite.LLVMType.Void():
|
||||
bare_ty = llvmlite.Int8(pool)
|
||||
case _:
|
||||
pass
|
||||
bare_ty = llvmlite.Ptr(pool, bare_ty)
|
||||
bare_arg_node: ast.AST | t.CPtr = cargs.get(0)
|
||||
if bare_arg_node is not None:
|
||||
bare_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, bare_arg_node, None, 0, trans)
|
||||
if bare_arg_val is not None:
|
||||
return self._translate_t_type_cast(
|
||||
pool, builder, bare_arg_val, bare_ty,
|
||||
bare_fn_name, bare_arg_node, trans)
|
||||
if bare_ty is not None and can == 1:
|
||||
bare_arg_node: ast.AST | t.CPtr = cargs.get(0)
|
||||
if bare_arg_node is not None:
|
||||
@@ -5830,8 +5938,21 @@ class CallGenMixin:
|
||||
# (TPC 参考: _HandleGenericClassNewLlvm;GenericTest Test4 Box(42)/Test5
|
||||
# Pair(10,20)/Test10 Counter(0) 依赖此路径。显式类型实参 list[int](mb)
|
||||
# 走 translate_call 上方的 Subscript 分支,此处处理裸名 + 推断。)
|
||||
# 支持模块限定调用(vector.Vector(...)):func_name 是 attr("Vector"),
|
||||
# 需确认模块已导入(模板查找兜底——普通函数如 stdlib.free 的 attr 找
|
||||
# 不到模板 → 回落普通调用)。
|
||||
if struct_ty is None and gen_ctor_entry is None and trans is not None:
|
||||
is_gen_bare: int = 0
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
|
||||
is_gen_bare = 1
|
||||
elif cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
at_gb: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||||
if at_gb.value is not None and at_gb.value.kind() == ast.ASTKind.Name:
|
||||
am_gb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_gb.value)
|
||||
if am_gb.id is not None:
|
||||
if HandlesImports.is_module_imported(trans._imported_modules, am_gb.id) != 0:
|
||||
is_gen_bare = 1
|
||||
if is_gen_bare != 0:
|
||||
template_cd_bare: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(func_name)
|
||||
if template_cd_bare is not None and template_cd_bare.type_params is not None:
|
||||
tp_bare: list[str] | t.CPtr = template_cd_bare.type_params
|
||||
@@ -5839,17 +5960,30 @@ class CallGenMixin:
|
||||
if tp_count_bare > 0:
|
||||
inferred_args_bare: list[str] | t.CPtr = list[str](pool, 8)
|
||||
if inferred_args_bare is not None:
|
||||
tpi_bare: t.CSizeT = 0
|
||||
for tpi_bare in range(tp_count_bare):
|
||||
ta_bare: str = "int"
|
||||
if tpi_bare < can:
|
||||
ta_bare = self._infer_generic_ctor_type_arg(pool, cargs.get(tpi_bare))
|
||||
inferred_args_bare.append(ta_bare)
|
||||
spec_name_bare: str = HandlesClassDef._specialize_generic_class(
|
||||
trans, func_name, inferred_args_bare)
|
||||
if spec_name_bare is not None:
|
||||
return self._translate_generic_ctor_call(
|
||||
pool, builder, mod, spec_name_bare, cl, trans)
|
||||
# 对齐 TPC _HandleGenericClassNewLlvm:先收集全部实参
|
||||
# 推断类型,过滤纯 int(排除 pool 等非 T 参数),
|
||||
# hint_types 优先填充(Vector(pool,8,CFloat64T(0.0))
|
||||
# → Vector[double];Vector(pool,10,CInt(0)) → Vector[int])
|
||||
hint_bare: list[str] | t.CPtr = list[str](pool, 8)
|
||||
if hint_bare is not None:
|
||||
hi_bare: t.CSizeT
|
||||
for hi_bare in range(can):
|
||||
hty_bare: str = self._infer_generic_ctor_type_arg(pool, cargs.get(hi_bare))
|
||||
if string.strcmp(hty_bare, "int") != 0:
|
||||
hint_bare.append(hty_bare)
|
||||
tpi_bare: t.CSizeT = 0
|
||||
for tpi_bare in range(tp_count_bare):
|
||||
ta_bare: str = "int"
|
||||
if tpi_bare < hint_bare.__len__():
|
||||
ta_bare = hint_bare.get(tpi_bare)
|
||||
elif tpi_bare < can:
|
||||
ta_bare = self._infer_generic_ctor_type_arg(pool, cargs.get(tpi_bare))
|
||||
inferred_args_bare.append(ta_bare)
|
||||
spec_name_bare: str = HandlesClassDef._specialize_generic_class(
|
||||
trans, func_name, inferred_args_bare)
|
||||
if spec_name_bare is not None:
|
||||
return self._translate_generic_ctor_call(
|
||||
pool, builder, mod, spec_name_bare, cl, trans)
|
||||
|
||||
# REnum 变体构造检测: ClassName.VariantName(args...)
|
||||
# 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体
|
||||
@@ -6022,6 +6156,20 @@ class CallGenMixin:
|
||||
# 根据外部函数签名推断期望类型,提升字面量(如 i32→i64)
|
||||
# 避免 declare(i64) 与 call(i32) 类型不匹配
|
||||
if found_func is None and arg_val.Ty is not None:
|
||||
# 数组实参按 C 语义衰减为元素指针(对齐 TPC
|
||||
# _decay_array_to_ptr),与 _translate_method_call 一致。
|
||||
if HandlesExpr.is_ptr_type(arg_val.Ty) != 0:
|
||||
arr_pointee_fc: llvmlite.LLVMType | t.CPtr = arg_val.Ty.Pointee
|
||||
if arr_pointee_fc is not None:
|
||||
match arr_pointee_fc:
|
||||
case llvmlite.LLVMType.Array(arr_et_fc, _):
|
||||
decayed_fc: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||||
builder, arr_pointee_fc, arr_et_fc, arg_val,
|
||||
llvmlite.const_int32(pool, 0))
|
||||
if decayed_fc is not None:
|
||||
arg_val = decayed_fc
|
||||
case _:
|
||||
pass
|
||||
ext_param_ty: llvmlite.LLVMType | t.CPtr = self._get_external_func_param_ty(
|
||||
pool, func_name, ai)
|
||||
if ext_param_ty is not None:
|
||||
@@ -6385,7 +6533,9 @@ class CallGenMixin:
|
||||
# 跨模块调用:创建 declare 声明,避免 llc 报 undefined value
|
||||
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, can)
|
||||
# 检查被调用函数是否为变长函数(*args),若是则对变长参数进行 C ABI 提升
|
||||
is_variadic_call: int = HandlesExprCall._check_and_promote_variadic_call(pool, builder, mod, call_name, head, can)
|
||||
# (cargs 为本函数参数 AST 链表,self_offset=0 普通函数调用)
|
||||
is_variadic_call: int = HandlesExprCall._check_and_promote_variadic_call(
|
||||
pool, builder, mod, call_name, head, can, cargs, 0, trans)
|
||||
return llvmlite.build_call(builder, call_name, head, can, call_ret_ty, is_variadic_call)
|
||||
|
||||
# ============================================================
|
||||
@@ -7343,11 +7493,18 @@ class CallGenMixin:
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
call_name: str,
|
||||
head: llvmlite.Value | t.CPtr,
|
||||
can: t.CSizeT) -> int:
|
||||
can: t.CSizeT,
|
||||
arg_nodes: list[ast.AST | t.CPtr] | t.CPtr = None,
|
||||
self_offset: int = 0,
|
||||
trans: HT.Translator | t.CPtr = None) -> int:
|
||||
"""检查被调用函数是否为变长函数,若是则对变长参数进行 C ABI 提升
|
||||
|
||||
返回: is_variadic (1=变长调用, 0=普通调用)
|
||||
副作用: 修改 head 链表中超过固定参数数量的节点(C ABI 提升)
|
||||
|
||||
arg_nodes: 实参 AST 链表(不含 self),用于 i8/i16 提升的无符号性判断
|
||||
self_offset: Value 链中 self 占用的偏移(方法调用=1,普通函数=0)
|
||||
trans: 供 _node_type_unsigned 查询变量注解
|
||||
"""
|
||||
if mod is None or call_name is None or head is None:
|
||||
return 0
|
||||
@@ -7378,13 +7535,28 @@ class CallGenMixin:
|
||||
# 对变长参数进行 C ABI 提升
|
||||
i32_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
double_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
|
||||
v_idx: int = fixed_count
|
||||
while cur is not None:
|
||||
next_node: llvmlite.Value | t.CPtr = cur.Next
|
||||
promoted: llvmlite.Value | t.CPtr = cur
|
||||
# C ABI integer promotion: i8/i16 → i32
|
||||
arg_bits: int = HandlesExpr.get_llvm_type_bits(cur.Ty)
|
||||
if arg_bits != 0 and arg_bits < 32:
|
||||
promoted = HandlesExpr.coerce_to_type(builder, cur, i32_ty_promote, None)
|
||||
# 无符号整型(t.CUInt8T/CUInt16T 等)→ zext;有符号/未知 → sext。
|
||||
# 修复: printf("%02x", buf[i]) 中 buf[i] 是 CUInt8T,sext 得
|
||||
# 0xFFFFFFF3 打印 fffffff3(哈希摘要输出垃圾),应 zext 得 0xF3。
|
||||
is_u_va: int = 0
|
||||
if arg_nodes is not None and trans is not None:
|
||||
ast_idx_va: int = v_idx - self_offset
|
||||
if ast_idx_va >= 0 and ast_idx_va < arg_nodes.__len__():
|
||||
an_va: ast.AST | t.CPtr = arg_nodes.get(ast_idx_va)
|
||||
if an_va is not None:
|
||||
if HandlesExpr._node_type_unsigned(pool, an_va, trans) != 0:
|
||||
is_u_va = 1
|
||||
if is_u_va != 0:
|
||||
promoted = llvmlite.build_zext(builder, cur, i32_ty_promote)
|
||||
else:
|
||||
promoted = HandlesExpr.coerce_to_type(builder, cur, i32_ty_promote, None)
|
||||
if promoted is not None:
|
||||
promoted.Next = next_node
|
||||
if prev is not None:
|
||||
@@ -7399,6 +7571,7 @@ class CallGenMixin:
|
||||
prev.Next = promoted
|
||||
prev = promoted
|
||||
cur = next_node
|
||||
v_idx += 1
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
@@ -107,6 +107,12 @@ class ClassGenMixin:
|
||||
GenericClassNames: list[str] | t.CPtr
|
||||
GenericClassNodes: list[ast.ClassDef | t.CPtr] | t.CPtr
|
||||
GenericClassSha1s: list[str] | t.CPtr
|
||||
# 泛型模板来源文件路径(与上面三表同序)。特化翻译模板方法体时
|
||||
# node.lineno 是模板文件行号,若 CurrentFile 仍是调用方文件,
|
||||
# fatal_error 会把模板行号套到调用方文件上显示错位(如 vector.vp
|
||||
# 的 T(...) 错报成 vectortest.vp 的 return 0)。此表用于特化期间
|
||||
# 临时切换 CurrentFile 到模板文件,翻译完恢复。
|
||||
GenericClassFiles: list[str] | t.CPtr
|
||||
|
||||
# --- vtable 方法收集表(原 _g_vt_full_names/_g_vt_method_names/
|
||||
# _g_vt_parent_sha1s/_g_vt_method_count) ---
|
||||
@@ -1716,6 +1722,7 @@ class ClassGenMixin:
|
||||
self.GenericClassNames = list[str](pool, 8)
|
||||
self.GenericClassNodes = list[ast.ClassDef | t.CPtr](pool, 8)
|
||||
self.GenericClassSha1s = list[str](pool, 8)
|
||||
self.GenericClassFiles = list[str](pool, 8)
|
||||
# 用局部变量接收 list,触发类型推断(避免字段 __len__ 失败)
|
||||
names_local: list[str] | t.CPtr = self.GenericClassNames
|
||||
cn: t.CSizeT = names_local.__len__()
|
||||
@@ -1727,6 +1734,8 @@ class ClassGenMixin:
|
||||
self.GenericClassNames.append(cd.name)
|
||||
self.GenericClassNodes.append(cd)
|
||||
self.GenericClassSha1s.append(module_sha1)
|
||||
# 同时保存模板来源文件路径(错误定位用,见字段注释)
|
||||
self.GenericClassFiles.append(HandlesType.get_current_file())
|
||||
# 诊断日志:确认泛型模板注册
|
||||
fb_rg: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_rg is not None:
|
||||
@@ -1765,6 +1774,25 @@ class ClassGenMixin:
|
||||
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] | t.CPtr = self.GenericClassNames
|
||||
files_local: list[str] | t.CPtr = self.GenericClassFiles
|
||||
cn: t.CSizeT = names_local.__len__()
|
||||
i: t.CSizeT
|
||||
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 | t.CPtr,
|
||||
class_name: str,
|
||||
type_args: list[str] | t.CPtr) -> str:
|
||||
@@ -2124,7 +2152,18 @@ class ClassGenMixin:
|
||||
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 = HandlesType.get_current_file()
|
||||
tpl_file_pre: str = self._find_generic_template_file(class_name)
|
||||
if tpl_file_pre is not None:
|
||||
HandlesType.set_current_file(tpl_file_pre)
|
||||
HandlesType.push_trace(tpl_file_pre, template_cd.lineno)
|
||||
self._translate_oop_methods(trans, spec_cd_pre, pre_existing.Ty, spec_name, 0)
|
||||
if tpl_file_pre is not None:
|
||||
HandlesType.pop_trace()
|
||||
HandlesType.set_current_file(saved_cur_pre)
|
||||
trans.ModuleSha1 = saved_ms_pre
|
||||
trans._imported_modules = saved_imp_pre
|
||||
trans.GenericTypeParamNames = None
|
||||
@@ -2208,7 +2247,18 @@ class ClassGenMixin:
|
||||
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 = HandlesType.get_current_file()
|
||||
tpl_file_full: str = self._find_generic_template_file(class_name)
|
||||
if tpl_file_full is not None:
|
||||
HandlesType.set_current_file(tpl_file_full)
|
||||
HandlesType.push_trace(tpl_file_full, template_cd.lineno)
|
||||
self.translate_class_def(trans, spec_cd)
|
||||
if tpl_file_full is not None:
|
||||
HandlesType.pop_trace()
|
||||
HandlesType.set_current_file(saved_cur_full)
|
||||
# 恢复原始 ModuleSha1 与 imports
|
||||
trans.ModuleSha1 = saved_module_sha1
|
||||
trans._imported_modules = saved_imported
|
||||
@@ -2262,6 +2312,14 @@ class ClassGenMixin:
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
class_name: str = cd.name
|
||||
|
||||
# 诊断:翻译类入口(定位 G3 1b 挂起发生在哪个类)
|
||||
fb_cls: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_cls is not None:
|
||||
viperlib.snprintf(fb_cls, 1024, "[CLASS] 翻译类: %s (declare_only=%d, sha1=%s)",
|
||||
class_name, trans._declare_only,
|
||||
trans.ModuleSha1 if trans.ModuleSha1 is not None else "(null)")
|
||||
VLogger.info(fb_cls, "CLASS")
|
||||
|
||||
# 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前,
|
||||
# 因为 Phase B 时结构体已注册会提前 return,否则永远无法标记本地类)
|
||||
HandlesStruct.add_visible_struct(pool, class_name)
|
||||
@@ -2308,6 +2366,13 @@ class ClassGenMixin:
|
||||
# self 参数类型打印),部分实现下 pool 块被复用导致 Name 悬空崩溃。
|
||||
# 保险起见:深拷贝 Name 到 stdlib,确保跨文件永久存活。
|
||||
if trans._declare_only == 0:
|
||||
# 深拷贝整个 existing.Ty 到 stdlib:1a pool Ty 跨 1b reset 悬空,
|
||||
# _ensure_field_types_in_module 遍历悬空字段 ParamNode 链表
|
||||
# 读悬空挂起(G3 LinkedNode.prepend 挂起根因)。DeepCopyType
|
||||
# 递归深拷贝字段链表/子类型/Name 到 stdlib(深度上限+链守卫)。
|
||||
ty_deep: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(pool, existing.Ty)
|
||||
if ty_deep is not None:
|
||||
existing.Ty = ty_deep
|
||||
old_name: t.CChar | t.CPtr = llvmlite.get_struct_name(existing.Ty)
|
||||
if old_name is not None:
|
||||
on_len: t.CSizeT = string.strlen(old_name)
|
||||
@@ -2325,6 +2390,11 @@ class ClassGenMixin:
|
||||
if trans._declare_only == 1:
|
||||
self._translate_oop_methods(trans, cd, existing.Ty, class_name, 1)
|
||||
else:
|
||||
# 诊断:existing 命中后全量翻译方法(定位 G3 1b 挂起)
|
||||
fb_ex: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_ex is not None:
|
||||
viperlib.snprintf(fb_ex, 1024, "[CLASS] %s existing 命中, 全量翻译方法体", class_name)
|
||||
VLogger.info(fb_ex, "CLASS")
|
||||
self._translate_oop_methods(trans, cd, existing.Ty, class_name)
|
||||
# SHA1 已在 register_struct 时设置,无需再补
|
||||
return 0
|
||||
@@ -3222,6 +3292,12 @@ class ClassGenMixin:
|
||||
if trans is None or cd is None or struct_ty is None or class_name is None:
|
||||
return 0
|
||||
|
||||
# 诊断:OOP 方法翻译入口(定位 G3 1b 挂起)
|
||||
fb_oop: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_oop is not None:
|
||||
viperlib.snprintf(fb_oop, 1024, "[OOP] %s mark_only=%d", class_name, mark_only)
|
||||
VLogger.info(fb_oop, "OOP")
|
||||
|
||||
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
|
||||
if children is None:
|
||||
return 0
|
||||
@@ -3378,6 +3454,13 @@ class ClassGenMixin:
|
||||
|
||||
method_name: str = fd.name
|
||||
|
||||
# 诊断:方法翻译入口(定位 G3 1b 挂起在哪个方法)
|
||||
fb_mtd: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_mtd is not None:
|
||||
viperlib.snprintf(fb_mtd, 1024, "[METHOD] %s.%s", class_name,
|
||||
method_name if method_name is not None else "(null)")
|
||||
VLogger.info(fb_mtd, "OOP")
|
||||
|
||||
# 提取装饰器元数据(@property/@staticmethod/@classmethod/@x.setter/@x.deleter)
|
||||
func_meta: int = self._extract_func_meta(fd.decorator_list)
|
||||
# property setter/deleter 函数名带 $set/$del 后缀,避免与 getter 冲突
|
||||
@@ -3503,9 +3586,12 @@ class ClassGenMixin:
|
||||
# 裸类形参 → Ptr(struct):按"对象即指针"引用传参。
|
||||
# 若按 struct 值传参,self.Head = node 会取局部拷贝地址
|
||||
# (append 返回后悬垂,G5 Test4 head.Value 读到垃圾)。
|
||||
# CArray 形参 → 元素指针 ty*(数组衰减,C 语义,与函数形参一致)。
|
||||
match resolved:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
param_ty = llvmlite.Ptr(pool, resolved)
|
||||
case llvmlite.LLVMType.Array(aelem_ty, _):
|
||||
param_ty = llvmlite.Ptr(pool, aelem_ty)
|
||||
case _:
|
||||
param_ty = resolved
|
||||
pname: t.CChar | t.CPtr = pool.alloc(32)
|
||||
@@ -3573,9 +3659,12 @@ class ClassGenMixin:
|
||||
pool, arg2.annotation, imported_modules, from_imports, trans)
|
||||
if resolved2 is not None:
|
||||
# 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针)
|
||||
# CArray 形参 → 元素指针 ty*(数组衰减,与 add_param 一致)
|
||||
match resolved2:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
param_ty2 = llvmlite.Ptr(pool, resolved2)
|
||||
case llvmlite.LLVMType.Array(aelem_ty2, _):
|
||||
param_ty2 = llvmlite.Ptr(pool, aelem_ty2)
|
||||
case _:
|
||||
param_ty2 = resolved2
|
||||
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2)
|
||||
@@ -3621,6 +3710,12 @@ class ClassGenMixin:
|
||||
for bi2 in range(bn2):
|
||||
stmt2: ast.AST | t.CPtr = body.get(bi2)
|
||||
if stmt2 is not None:
|
||||
# 诊断:语句级日志(定位 G3 1b LinkedNode.prepend 挂起在第几条语句)
|
||||
fb_stmt: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_stmt is not None:
|
||||
viperlib.snprintf(fb_stmt, 1024, "[STMT] %s.%s stmt[%d] kind=%d ln=%d",
|
||||
class_name, method_name, bi2, stmt2.kind(), stmt2.lineno)
|
||||
VLogger.info(fb_stmt, "OOP")
|
||||
HandlesBody.translate_stmt(trans, stmt2)
|
||||
|
||||
# 如果返回类型为 void,添加 ret void;否则添加隐式 ret 0
|
||||
@@ -3688,6 +3783,12 @@ class ClassGenMixin:
|
||||
if trans is None or struct_ty is None or class_name is None:
|
||||
return 0
|
||||
|
||||
# 诊断:__before_init__ 生成入口(定位 G3 1b 挂起)
|
||||
fb_bi: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_bi is not None:
|
||||
viperlib.snprintf(fb_bi, 1024, "[BI] %s", class_name)
|
||||
VLogger.info(fb_bi, "OOP")
|
||||
|
||||
import lib.core.Handles.HandlesFunctions as HandlesFunctions
|
||||
import lib.core.Handles.HandlesVar as HandlesVar
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
|
||||
@@ -1624,6 +1624,19 @@ class ExprGenMixin:
|
||||
if self._node_type_unsigned(pool, uop.operand, trans) != 0:
|
||||
return 1
|
||||
return 0
|
||||
if k == ast.ASTKind.Subscript:
|
||||
# 数组/指针下标: md5_buf[i](t.CArray[t.CUInt8T, N])或 buf[i]
|
||||
# (形参 t.CUInt8T | t.CPtr)元素是无符号整型 → printf("%02x", ...) zext。
|
||||
sub_su: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||||
if sub_su.value is not None and sub_su.value.kind() == ast.ASTKind.Name:
|
||||
snm_su: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_su.value)
|
||||
if snm_su.id is not None and trans is not None:
|
||||
ve_su: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||||
trans.SymTab, snm_su.id)
|
||||
if ve_su is not None and ve_su.AnnotClassName is not None:
|
||||
if self._annot_str_unsigned(ve_su.AnnotClassName) != 0:
|
||||
return 1
|
||||
return 0
|
||||
return 0
|
||||
|
||||
def _type_name_unsigned(self, type_name: str) -> int:
|
||||
@@ -1654,6 +1667,26 @@ class ExprGenMixin:
|
||||
if string.strcmp(type_name, "ULONG") == 0: return 1
|
||||
return 0
|
||||
|
||||
def _annot_str_unsigned(self, annot: str) -> int:
|
||||
"""检查类型注解字符串是否引用无符号整型(子串扫描)
|
||||
|
||||
用于复合注解(t.CArray[t.CUInt8T, 16] / t.CUInt8T | t.CPtr),
|
||||
_type_name_unsigned 的精确匹配对这类串不适用。
|
||||
"""
|
||||
if annot is None:
|
||||
return 0
|
||||
if string.strstr(annot, "CUInt8T") is not None: return 1
|
||||
if string.strstr(annot, "CUInt16T") is not None: return 1
|
||||
if string.strstr(annot, "CUInt32T") is not None: return 1
|
||||
if string.strstr(annot, "CUInt64T") is not None: return 1
|
||||
if string.strstr(annot, "CUnsigned") is not None: return 1
|
||||
if string.strstr(annot, "BYTE") is not None: return 1
|
||||
if string.strstr(annot, "UCHAR") is not None: return 1
|
||||
if string.strstr(annot, "USHORT") is not None: return 1
|
||||
if string.strstr(annot, "UINT") is not None: return 1
|
||||
if string.strstr(annot, "ULONG") is not None: return 1
|
||||
return 0
|
||||
|
||||
def translate_compare(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
@@ -2201,6 +2234,14 @@ class ExprGenMixin:
|
||||
# 精确匹配失败:尝试 star import 回退
|
||||
mod_name_raw = HandlesImports.lookup_from_import(from_imports, name, 1)
|
||||
|
||||
# 当前模块名(去前导点),用于构建子模块全名 base_mod.X(如 "hashlib" + "." +
|
||||
# "__md5")。此前 base_mod 未赋值(未初始化变量)→ 子模块递归 strlen(NULL)
|
||||
# 崩溃(ASan access-violation,Attribute count 新路径触发 _lookup_cross_module_cdefine)。
|
||||
base_mod: str = mod_name_raw
|
||||
if base_mod is not None:
|
||||
while base_mod[0] == '.':
|
||||
base_mod = base_mod + 1
|
||||
|
||||
# 2. from_imports 查找失败:直接回退到 imported_modules 遍历(步骤 9.6)
|
||||
# 注意:star fallback 可能返回错误模块(如 stdint),常量实际不在其中,
|
||||
# 步骤 9.6 会在该模块查找失败后继续遍历 imported_modules
|
||||
@@ -2514,6 +2555,8 @@ class ExprGenMixin:
|
||||
# 例如 ast.__init__.vp 中 from .base import CONST_INT, ...
|
||||
# 需要递归查找 ast.base 子模块中的 CONST_INT: t.CDefine = 1
|
||||
if result_found == 0:
|
||||
# base_mod 已在函数开头计算(mod_name_raw 去前导点),
|
||||
# 供子模块递归构建 "base_mod.X" 全名。
|
||||
name_len_rc: t.CSizeT = string.strlen(name)
|
||||
rc_pos: t.CSizeT = 0
|
||||
while rc_pos < total_len and result_found == 0:
|
||||
@@ -4005,6 +4048,15 @@ class ExprGenMixin:
|
||||
VLogger.error(diag_buf_an, "ATTR")
|
||||
return None
|
||||
|
||||
# 诊断:属性访问入口(定位 G3 LinkedNode.prepend 挂起)
|
||||
fb_tattr: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_tattr is not None:
|
||||
viperlib.snprintf(fb_tattr, 1024, "[TATTR] attr=%s obj_kind=%d ln=%d",
|
||||
at.attr if at.attr is not None else "?",
|
||||
at.value.kind() if at.value is not None else -1,
|
||||
at.lineno if at.lineno is not None else 0)
|
||||
VLogger.info(fb_tattr, "ATTR")
|
||||
|
||||
# 魔法属性 __doc__:查询 docstring 登记表(预注册阶段从 AST 提取),
|
||||
# 命中则当前模块内联生成字符串常量返回;未命中(无 docstring 的
|
||||
# 函数/类/方法)返回 null 指针(i8*)。支持本模块与跨模块符号:
|
||||
@@ -4647,6 +4699,14 @@ class ExprGenMixin:
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(attr_node)
|
||||
if at is None or at.attr is None or at.value is None:
|
||||
return None
|
||||
# 诊断:属性链类名解析入口(定位 G3 prepend 挂起)
|
||||
fb_raf: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_raf is not None:
|
||||
viperlib.snprintf(fb_raf, 1024, "[RAF] attr=%s obj_kind=%d ln=%d",
|
||||
at.attr if at.attr is not None else "?",
|
||||
at.value.kind() if at.value is not None else -1,
|
||||
at.lineno if at.lineno is not None else 0)
|
||||
VLogger.info(fb_raf, "ATTR")
|
||||
# 递归解析基座的注解类名(Name → 变量注解;Attribute → 字段注解)
|
||||
parent_class: str = None
|
||||
if at.value.kind() == ast.ASTKind.Name:
|
||||
@@ -4686,6 +4746,15 @@ class ExprGenMixin:
|
||||
if at is None or at.value is None or at.attr is None:
|
||||
return None
|
||||
|
||||
# 诊断:链式属性指针获取入口(定位 G3 LinkedNode.prepend 挂起)
|
||||
fb_gap: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_gap is not None:
|
||||
viperlib.snprintf(fb_gap, 1024, "[GAP] attr=%s obj_kind=%d ln=%d",
|
||||
at.attr if at.attr is not None else "?",
|
||||
at.value.kind() if at.value is not None else -1,
|
||||
at.lineno if at.lineno is not None else 0)
|
||||
VLogger.info(fb_gap, "ATTR")
|
||||
|
||||
# 对于 Name 类型的 obj,直接查找 alloca(不 load 结构体);
|
||||
# nonlocal 变量(提升函数内)从 env 读共享堆值,避免 lookup_var
|
||||
# 跨函数引用外层 alloca(SSA 编号跨函数错乱崩溃)
|
||||
@@ -4780,6 +4849,13 @@ class ExprGenMixin:
|
||||
HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty)
|
||||
field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
|
||||
struct_ty, at.attr)
|
||||
# 诊断:lookup_field 结果(定位 G3 LinkedNode.prepend 挂起)
|
||||
fb_lf2: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_lf2 is not None:
|
||||
viperlib.snprintf(fb_lf2, 1024, "[GAP-LF] attr=%s -> %s",
|
||||
at.attr if at.attr is not None else "?",
|
||||
"found" if field_info is not None else "None")
|
||||
VLogger.info(fb_lf2, "ATTR")
|
||||
# 按需过滤: struct_ty 为 i8(简化联合类型)时,通过 AnnotClassName 按类名查找
|
||||
# 传递 SHA1 以区分跨模块同名类
|
||||
# base 注解类名提取:Name → 变量注解类名;Attribute → 属性链递归字段注解类名
|
||||
@@ -4794,13 +4870,32 @@ class ExprGenMixin:
|
||||
if var_entry is not None:
|
||||
base_class = var_entry.AnnotClassName
|
||||
elif at.value.kind() == ast.ASTKind.Attribute:
|
||||
# 诊断:回退路径(定位 G3 prepend 挂起)
|
||||
fb_fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_fb is not None:
|
||||
viperlib.snprintf(fb_fb, 1024, "[GAP-FB] attr=%s 走 _resolve_attr_field_class",
|
||||
at.attr if at.attr is not None else "?")
|
||||
VLogger.info(fb_fb, "ATTR")
|
||||
base_class = self._resolve_attr_field_class(pool, trans, at.value)
|
||||
fb_fb2: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_fb2 is not None:
|
||||
viperlib.snprintf(fb_fb2, 1024, "[GAP-FB2] attr=%s -> base_class=%s",
|
||||
at.attr if at.attr is not None else "?",
|
||||
base_class if base_class is not None else "None")
|
||||
VLogger.info(fb_fb2, "ATTR")
|
||||
if base_class is not None:
|
||||
cur_sha1: str = None
|
||||
if trans is not None:
|
||||
cur_sha1 = trans.ModuleSha1
|
||||
field_info = HandlesStruct.lookup_field_by_class(
|
||||
base_class, at.attr, cur_sha1)
|
||||
fb_fb3: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_fb3 is not None:
|
||||
viperlib.snprintf(fb_fb3, 1024, "[GAP-FB3] lookup_by_class(%s.%s) -> %s",
|
||||
base_class if base_class is not None else "?",
|
||||
at.attr if at.attr is not None else "?",
|
||||
"found" if field_info is not None else "None")
|
||||
VLogger.info(fb_fb3, "ATTR")
|
||||
# 按需过滤成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型
|
||||
# 原始 struct_ty 可能是 i8(X|t.CPtr 简化为 Ptr(i8)),
|
||||
# 需用实际结构体类型做 GEP,否则 GEP i8 失败
|
||||
@@ -4820,6 +4915,13 @@ class ExprGenMixin:
|
||||
HandlesStruct.ensure_struct_def_in_module(
|
||||
pool, mod, annot_se.Ty)
|
||||
if field_info is not None:
|
||||
# 诊断:GEP 前(定位 G3 prepend 挂起在 ensure 还是 GEP)
|
||||
fb_gep: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_gep is not None:
|
||||
viperlib.snprintf(fb_gep, 1024, "[GAP-GEP] attr=%s idx=%d",
|
||||
at.attr if at.attr is not None else "?",
|
||||
field_info.Index)
|
||||
VLogger.info(fb_gep, "ATTR")
|
||||
# 联合体:bitcast obj_ptr 到 field_ty*(字段指针用于 store)
|
||||
if HandlesStruct.is_union_by_type(struct_ty) == 1:
|
||||
field_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, field_info.Ty)
|
||||
|
||||
@@ -447,9 +447,12 @@ class FuncGenMixin:
|
||||
pool, arg.annotation, imported_modules, from_imports, trans)
|
||||
if resolved is not None:
|
||||
# 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致)
|
||||
# CArray 形参 → 元素指针 ty*(C 数组衰减,与 add_param 一致)
|
||||
match resolved:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
param_ty = llvmlite.Ptr(pool, resolved)
|
||||
case llvmlite.LLVMType.Array(aelem_ty, _):
|
||||
param_ty = llvmlite.Ptr(pool, aelem_ty)
|
||||
case _:
|
||||
param_ty = resolved
|
||||
pname: t.CChar | t.CPtr = pool.alloc(32)
|
||||
@@ -588,9 +591,12 @@ class FuncGenMixin:
|
||||
pool, arg_e.annotation, imported_modules, from_imports, trans)
|
||||
if resolved_e is not None:
|
||||
# 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致)
|
||||
# CArray 形参 → 元素指针 ty*(C 数组衰减)
|
||||
match resolved_e:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
param_ty_e = llvmlite.Ptr(pool, resolved_e)
|
||||
case llvmlite.LLVMType.Array(aelem_ty_e, _):
|
||||
param_ty_e = llvmlite.Ptr(pool, aelem_ty_e)
|
||||
case _:
|
||||
param_ty_e = resolved_e
|
||||
pname_e: t.CChar | t.CPtr = pool.alloc(32)
|
||||
@@ -675,9 +681,14 @@ class FuncGenMixin:
|
||||
pool, arg.annotation, imported_modules, from_imports, trans)
|
||||
if resolved is not None:
|
||||
# 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致)
|
||||
# CArray 形参 → 元素指针 ty*(C 数组衰减:final(out: t.CArray[..., N])
|
||||
# 的 out 指向调用方数组首元素;传 Ptr(数组) 会使 out[i] 的
|
||||
# GEP 以整个数组为步长错位,摘要垃圾根因)
|
||||
match resolved:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
param_ty = llvmlite.Ptr(pool, resolved)
|
||||
case llvmlite.LLVMType.Array(aelem_ty, _):
|
||||
param_ty = llvmlite.Ptr(pool, aelem_ty)
|
||||
case _:
|
||||
param_ty = resolved
|
||||
pname: t.CChar | t.CPtr = pool.alloc(32)
|
||||
@@ -739,10 +750,14 @@ class FuncGenMixin:
|
||||
resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||
pool, arg2.annotation, imported_modules, from_imports, trans)
|
||||
if resolved2 is not None:
|
||||
# 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针)
|
||||
# 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针);
|
||||
# CArray 形参 → 元素指针 ty*(数组衰减,alloca 类型须与形参一致,
|
||||
# 否则 store ty* 到 [N x ty]* 容器类型不匹配)
|
||||
match resolved2:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
param_ty2 = llvmlite.Ptr(pool, resolved2)
|
||||
case llvmlite.LLVMType.Array(aelem_ty2, _):
|
||||
param_ty2 = llvmlite.Ptr(pool, aelem_ty2)
|
||||
case _:
|
||||
param_ty2 = resolved2
|
||||
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2)
|
||||
@@ -957,6 +972,8 @@ class FuncGenMixin:
|
||||
match resolved_n:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
pty_n = llvmlite.Ptr(pool, resolved_n)
|
||||
case llvmlite.LLVMType.Array(aelem_ty_n, _):
|
||||
pty_n = llvmlite.Ptr(pool, aelem_ty_n)
|
||||
case _:
|
||||
pty_n = resolved_n
|
||||
if param_count < 64 and param_tys is not None:
|
||||
@@ -1597,6 +1614,8 @@ class FuncGenMixin:
|
||||
match resolved:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
p_ty = llvmlite.Ptr(pool, resolved)
|
||||
case llvmlite.LLVMType.Array(aelem_ty_l, _):
|
||||
p_ty = llvmlite.Ptr(pool, aelem_ty_l)
|
||||
case _:
|
||||
p_ty = resolved
|
||||
ty_slot_p: str | t.CPtr = (t.CVoid | t.CPtr)(
|
||||
|
||||
@@ -83,6 +83,12 @@ class StmtGenMixin:
|
||||
return 0
|
||||
k: int = node.kind()
|
||||
|
||||
# 诊断:全局语句级日志(定位 G3 LinkedNode.prepend if 内部挂起)
|
||||
fb_sg: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_sg is not None:
|
||||
viperlib.snprintf(fb_sg, 1024, "[STMT2] kind=%d ln=%d", k, node.lineno)
|
||||
VLogger.info(fb_sg, "OOP")
|
||||
|
||||
if k == ast.ASTKind.Expr:
|
||||
return self.translate_expr_stmt(trans, node)
|
||||
elif k == ast.ASTKind.Assign:
|
||||
|
||||
@@ -192,12 +192,12 @@ class StructGenMixin:
|
||||
return None
|
||||
string.memset(entry.Fields, 0, field_size * FIELD_MAX)
|
||||
|
||||
# 复制类名(1b 阶段用 stdlib)
|
||||
# 复制类名(统一 stdlib:1a 阶段注册的 entry 需跨 1b reset 存活。
|
||||
# 此前 1a 用 pool,1b 阶段 find_struct_by_module 的 strcmp 读悬空
|
||||
# Name 越界读 → G3 LinkedNode.prepend 挂起根因。stdlib 分配不随
|
||||
# pool reset 回收,多遍去重(Ty 比较)避免重复分配。)
|
||||
name_len: t.CSizeT = string.strlen(name)
|
||||
if self.StdlibAlloc != 0:
|
||||
name_buf: t.CChar | t.CPtr = stdlib.malloc(name_len + 1)
|
||||
else:
|
||||
name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1)
|
||||
name_buf: t.CChar | t.CPtr = stdlib.malloc(name_len + 1)
|
||||
if name_buf is not None:
|
||||
string.strcpy(name_buf, name)
|
||||
entry.Name = name_buf
|
||||
@@ -206,12 +206,10 @@ class StructGenMixin:
|
||||
entry.FieldCount = 0
|
||||
|
||||
# 注册时直接设置 SHA1(避免 set_struct_sha1 跨模块同名时找错 entry)
|
||||
# SHA1 同样统一 stdlib(跨 1a/1b 存活,防 strcmp 悬空)
|
||||
if sha1 is not None:
|
||||
sha1_len: t.CSizeT = string.strlen(sha1)
|
||||
if self.StdlibAlloc != 0:
|
||||
sha1_buf: t.CChar | t.CPtr = stdlib.malloc(sha1_len + 1)
|
||||
else:
|
||||
sha1_buf: t.CChar | t.CPtr = pool.alloc(sha1_len + 1)
|
||||
sha1_buf: t.CChar | t.CPtr = stdlib.malloc(sha1_len + 1)
|
||||
if sha1_buf is not None:
|
||||
string.strcpy(sha1_buf, sha1)
|
||||
entry.ModuleSha1 = sha1_buf
|
||||
@@ -227,9 +225,9 @@ class StructGenMixin:
|
||||
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct(class_name)
|
||||
if entry is None:
|
||||
return 0
|
||||
# 复制 SHA1 字符串(避免悬空指针)
|
||||
# 复制 SHA1 字符串(统一 stdlib,跨 1a/1b 存活防 strcmp 悬空)
|
||||
sha1_len: t.CSizeT = string.strlen(sha1)
|
||||
sha1_buf: t.CChar | t.CPtr = pool.alloc(sha1_len + 1)
|
||||
sha1_buf: t.CChar | t.CPtr = stdlib.malloc(sha1_len + 1)
|
||||
if sha1_buf is None:
|
||||
return 0
|
||||
string.strcpy(sha1_buf, sha1)
|
||||
@@ -271,12 +269,11 @@ class StructGenMixin:
|
||||
if fe is None:
|
||||
return -1
|
||||
|
||||
# 复制字段名(1b 阶段用 stdlib,避免 reset 回收后 fe.Name 悬空)
|
||||
# 复制字段名(统一 stdlib:1a 注册的字段名跨 1b reset 存活,
|
||||
# 否则 lookup_field 的 strcmp(fe.Name, ...) 读悬空越界挂起,
|
||||
# 与 register_struct 的 Name 悬空同根因)
|
||||
name_len: t.CSizeT = string.strlen(field_name)
|
||||
if self.StdlibAlloc != 0:
|
||||
name_buf: t.CChar | t.CPtr = stdlib.malloc(name_len + 1)
|
||||
else:
|
||||
name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1)
|
||||
name_buf: t.CChar | t.CPtr = stdlib.malloc(name_len + 1)
|
||||
if name_buf is not None:
|
||||
string.strcpy(name_buf, field_name)
|
||||
fe.Name = name_buf
|
||||
@@ -419,6 +416,10 @@ class StructGenMixin:
|
||||
if name is None or self.StructTable is None:
|
||||
return None
|
||||
# 第一遍:精确匹配
|
||||
# StructCount 合理性守卫(内存损坏导致巨大值 → 索引循环假挂起)
|
||||
if self.StructCount < 0 or self.StructCount > 200000:
|
||||
VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct)", "STRUCT")
|
||||
stdlib.exit(1)
|
||||
for i in range(self.StructCount):
|
||||
entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i)
|
||||
if entry is not None and entry.Name is not None:
|
||||
@@ -444,6 +445,10 @@ class StructGenMixin:
|
||||
"""
|
||||
if name is None or self.StructTable is None:
|
||||
return None
|
||||
# StructCount 合理性守卫(内存损坏导致巨大值 → 索引循环假挂起)
|
||||
if self.StructCount < 0 or self.StructCount > 200000:
|
||||
VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct_by_module)", "STRUCT")
|
||||
stdlib.exit(1)
|
||||
if sha1 is not None:
|
||||
for i in range(self.StructCount):
|
||||
entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i)
|
||||
@@ -468,6 +473,10 @@ class StructGenMixin:
|
||||
"""
|
||||
if struct_ty is None or self.StructTable is None:
|
||||
return None
|
||||
# StructCount 合理性守卫(内存损坏导致巨大值 → 索引循环假挂起)
|
||||
if self.StructCount < 0 or self.StructCount > 200000:
|
||||
VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct_by_type)", "STRUCT")
|
||||
stdlib.exit(1)
|
||||
st_val: t.CUInt64T = t.CUInt64T(struct_ty)
|
||||
for i in range(self.StructCount):
|
||||
entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i)
|
||||
@@ -1055,6 +1064,13 @@ class StructGenMixin:
|
||||
"""
|
||||
if ty is None or mod is None or pool is None:
|
||||
return
|
||||
# 诊断:ensure_struct_def_in_module 入口(定位 G3 prepend 挂起)
|
||||
fb_esd: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_esd is not None:
|
||||
esd_name: str = llvmlite.get_struct_name(ty)
|
||||
viperlib.snprintf(fb_esd, 1024, "[ESD] ty=%s",
|
||||
esd_name if esd_name is not None else "(non-struct)")
|
||||
VLogger.info(fb_esd, "ATTR")
|
||||
# 指针类型:确保 pointee 至少有 opaque 声明
|
||||
match ty:
|
||||
case llvmlite.LLVMType.Ptr(pointee):
|
||||
@@ -1068,11 +1084,32 @@ class StructGenMixin:
|
||||
pass
|
||||
# 获取结构体名称(非 Struct 类型返回 None)
|
||||
sname: t.CChar | t.CPtr = llvmlite.get_struct_name(ty)
|
||||
# 诊断:get_struct_name 结果(限长拷贝防 %s 读悬空挂起)
|
||||
fb_esd2: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_esd2 is not None:
|
||||
if sname is not None:
|
||||
sn_cp2: t.CChar | t.CPtr = pool.alloc(64)
|
||||
if sn_cp2 is not None:
|
||||
string.strncpy(sn_cp2, sname, 63)
|
||||
sn_cp2[63] = '\0'
|
||||
viperlib.snprintf(fb_esd2, 1024, "[ESD2] sname=%s", sn_cp2)
|
||||
else:
|
||||
viperlib.snprintf(fb_esd2, 1024, "[ESD2] sname=(null)")
|
||||
VLogger.info(fb_esd2, "ATTR")
|
||||
if sname is None:
|
||||
return
|
||||
# 检查是否为跨模块引用(名称包含 '.')
|
||||
fb_esd3: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_esd3 is not None:
|
||||
viperlib.snprintf(fb_esd3, 1024, "[ESD3] 开始 strchr(sname, '.')")
|
||||
VLogger.info(fb_esd3, "ATTR")
|
||||
if string.strchr(sname, 46) is None:
|
||||
return # 非跨模块引用,无需处理
|
||||
# 诊断:strchr 完成,后续步骤(定位 G3 prepend 挂起)
|
||||
fb_esd4: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_esd4 is not None:
|
||||
viperlib.snprintf(fb_esd4, 1024, "[ESD4] strchr 完成, StructCount=%d", self.StructCount)
|
||||
VLogger.info(fb_esd4, "ATTR")
|
||||
# 提取类名(第一个 '.' 之后的部分)
|
||||
# 必须用 strchr 而非 strrchr:泛型特化名如 "list[ast.AST|t.CPtr]"
|
||||
# 内部含 '.'(ast.AST),strrchr 会错误地把类名解析为 "AST|t.CPtr]"
|
||||
@@ -1082,6 +1119,11 @@ class StructGenMixin:
|
||||
class_name: str = dot_pos + 1
|
||||
if class_name is None or class_name[0] == '\0':
|
||||
return
|
||||
# 诊断:strchr 后步骤(定位 G3 prepend 挂起)
|
||||
fb_esd5: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_esd5 is not None:
|
||||
viperlib.snprintf(fb_esd5, 1024, "[ESD5] class_name=%s", class_name)
|
||||
VLogger.info(fb_esd5, "ATTR")
|
||||
# 提取 SHA1(sname 到 dot_pos 之间,用 strlen 避免指针减法)
|
||||
total_len: t.CSizeT = string.strlen(sname)
|
||||
class_name_len: t.CSizeT = string.strlen(class_name)
|
||||
@@ -1095,8 +1137,17 @@ class StructGenMixin:
|
||||
sha1_cp = 31
|
||||
string.strncpy(sha1_buf, sname, sha1_cp)
|
||||
sha1_buf[sha1_cp] = '\0'
|
||||
fb_esd6: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_esd6 is not None:
|
||||
viperlib.snprintf(fb_esd6, 1024, "[ESD6] sha1=%s len=%d", sha1_buf, sha1_len)
|
||||
VLogger.info(fb_esd6, "ATTR")
|
||||
# 按类名 + SHA1 查找结构体定义
|
||||
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct_by_module(class_name, sha1_buf)
|
||||
fb_esd7: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_esd7 is not None:
|
||||
viperlib.snprintf(fb_esd7, 1024, "[ESD7] find_struct_by_module -> %s",
|
||||
"found" if entry is not None else "None")
|
||||
VLogger.info(fb_esd7, "ATTR")
|
||||
if entry is None:
|
||||
# 回退到按类名查找(可能找到不同模块的同名类,但总比没有好)
|
||||
entry = self.find_struct(class_name)
|
||||
@@ -1104,11 +1155,28 @@ class StructGenMixin:
|
||||
return
|
||||
if entry.Ty is None:
|
||||
return
|
||||
# 诊断:进入 module_add_named_type / _ensure_field_types(定位 G3 prepend 挂起)
|
||||
fb_esd8: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_esd8 is not None:
|
||||
viperlib.snprintf(fb_esd8, 1024, "[ESD8] 进入 module_add_named_type")
|
||||
VLogger.info(fb_esd8, "ATTR")
|
||||
# 将完整定义添加到当前模块(会替换已存在的 opaque 声明)
|
||||
llvmlite.module_add_named_type(mod, pool, entry.Ty)
|
||||
fb_esd9: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_esd9 is not None:
|
||||
viperlib.snprintf(fb_esd9, 1024, "[ESD9] module_add_named_type 完成")
|
||||
VLogger.info(fb_esd9, "ATTR")
|
||||
# 递归扫描字段类型,确保值类型子结构体(如 WIN32_FIND_DATAA 中的 FILETIME)
|
||||
# 也有完整定义。指针类型字段只需 opaque 声明(已由 module_ensure_opaque_for_type 处理)。
|
||||
fb_esd10: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_esd10 is not None:
|
||||
viperlib.snprintf(fb_esd10, 1024, "[ESD10] 进入 _ensure_field_types_in_module")
|
||||
VLogger.info(fb_esd10, "ATTR")
|
||||
self._ensure_field_types_in_module(pool, mod, entry.Ty)
|
||||
fb_esd11: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_esd11 is not None:
|
||||
viperlib.snprintf(fb_esd11, 1024, "[ESD11] ensure_struct_def_in_module 完成")
|
||||
VLogger.info(fb_esd11, "ATTR")
|
||||
|
||||
def _ensure_field_types_in_module(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
@@ -1122,7 +1190,16 @@ class StructGenMixin:
|
||||
# 遍历字段链表
|
||||
if fields is not None:
|
||||
fld: llvmlite.ParamNode | t.CPtr = fields
|
||||
cnt_ef: t.CInt = 0
|
||||
while fld is not None:
|
||||
# 步数守卫:字段链表成环(内存损坏)导致无限遍历挂起
|
||||
# (G3 LinkedNode.prepend 挂起候选),超限立即报错终止
|
||||
cnt_ef += 1
|
||||
if cnt_ef > 100000:
|
||||
VLogger.error(
|
||||
"字段链表疑似成环(_ensure_field_types_in_module),强制终止",
|
||||
"STRUCT")
|
||||
stdlib.exit(1)
|
||||
if fld.Ty is not None:
|
||||
# 值类型子结构体(如 FILETIME)需要完整定义
|
||||
match fld.Ty:
|
||||
|
||||
@@ -522,11 +522,51 @@ class TypeGenMixin:
|
||||
if HandlesType.is_cdefine_found() != 0:
|
||||
self.ConstEvalOk = 1
|
||||
return x_val
|
||||
# 定位日志:跨模块 CDefine 查找失败(t.CArray count 场景)
|
||||
fb_cdf: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_cdf is not None:
|
||||
viperlib.snprintf(fb_cdf, 1024,
|
||||
"[CDEF-MISS] name=%s fi=%s im=%s",
|
||||
nm.id,
|
||||
from_imports if from_imports is not None else "(null)",
|
||||
imported_modules if imported_modules is not None else "(null)")
|
||||
VLogger.error(fb_cdf, "CDEF")
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
self.ConstEvalOk = 1
|
||||
return val
|
||||
|
||||
# Attribute: 模块限定常量名,如 hashlib.MD5_DIGEST_LEN
|
||||
# (t.CArray[t.CUInt8T, hashlib.MD5_DIGEST_LEN] 的 count 是 Attribute,
|
||||
# 复用跨模块 CDefine 查找:*:模块 → 源文件提取;re-export 常量由
|
||||
# _lookup_cross_module_cdefine 的 from-import 递归子模块兜底)
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||||
if at.attr is None:
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||||
at_mod: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||||
if at_mod.id is not None:
|
||||
if (from_imports is not None or imported_modules is not None) \
|
||||
and pool is not None:
|
||||
mod_len: t.CSizeT = string.strlen(at_mod.id)
|
||||
fi_buf: str = pool.alloc(mod_len + 3)
|
||||
if fi_buf is not None:
|
||||
fi_buf[0] = '*'
|
||||
fi_buf[1] = ':'
|
||||
for mi in range(mod_len):
|
||||
fi_buf[2 + mi] = at_mod.id[mi]
|
||||
fi_buf[2 + mod_len] = '\0'
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
av: int = HandlesExpr._lookup_cross_module_cdefine(
|
||||
pool, at.attr, fi_buf, imported_modules)
|
||||
if HandlesType.is_cdefine_found() != 0:
|
||||
self.ConstEvalOk = 1
|
||||
return av
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
|
||||
# BinOp: 算术/位运算
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||||
@@ -1490,10 +1530,48 @@ class TypeGenMixin:
|
||||
"""解析泛型类类型注解(特化或查找已注册结构体),失败返回 None"""
|
||||
if pool is None or sub is None or gen_cls_name is None:
|
||||
return None
|
||||
# tuple[...] 类型注解:TransPyV 暂不支持 tuple 返回类型,返回 None 让上层默认处理
|
||||
# 避免走到 list[str](pool, 4) 构造路径崩溃(tuple 未定义为泛型类)
|
||||
# tuple[T1, T2, ...] → 匿名结构体 {T1, T2, ...}(多返回值打包,
|
||||
# 对齐 TPC LLVMTypeMapper._resolve_subscript 的 '{ ty1, ty2 }')。
|
||||
# 用于函数 `-> tuple[str, t.CUnsignedShort]`(如 binascii.b2a_hqx)
|
||||
# 与调用端 `a, b = f()` 的打包/解包。
|
||||
if string.strcmp(gen_cls_name, "tuple") == 0:
|
||||
return None
|
||||
tp_elts: list[ast.AST | t.CPtr] | t.CPtr = None
|
||||
tp_count: t.CSizeT = 0
|
||||
if sub.slice.kind() == ast.ASTKind.Tuple:
|
||||
tp_tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice)
|
||||
if tp_tup.elts is not None:
|
||||
tp_elts = tp_tup.elts
|
||||
tp_count = tp_elts.__len__()
|
||||
else:
|
||||
tp_single: list[ast.AST | t.CPtr] | t.CPtr = list[ast.AST | t.CPtr](pool, 1)
|
||||
if tp_single is not None:
|
||||
tp_single.append(sub.slice)
|
||||
tp_elts = tp_single
|
||||
tp_count = 1
|
||||
if tp_count == 0 or tp_elts is None:
|
||||
return None
|
||||
tup_head: llvmlite.ParamNode | t.CPtr = None
|
||||
tup_tail: llvmlite.ParamNode | t.CPtr = None
|
||||
tui: t.CSizeT
|
||||
for tui in range(tp_count):
|
||||
tup_elt: ast.AST | t.CPtr = tp_elts.get(tui)
|
||||
if tup_elt is None:
|
||||
continue
|
||||
tup_ety: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, tup_elt, imported_modules, from_imports, trans)
|
||||
if tup_ety is None:
|
||||
return None
|
||||
tup_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, tup_ety)
|
||||
if tup_node is None:
|
||||
return None
|
||||
if tup_head is None:
|
||||
tup_head = tup_node
|
||||
else:
|
||||
llvmlite.paramnode_set_next(tup_tail, tup_node)
|
||||
tup_tail = tup_node
|
||||
if tup_head is None:
|
||||
return None
|
||||
return llvmlite.Struct(pool, tup_head, tp_count, None)
|
||||
# 先收集类型实参名,再分配缓冲区拼接 mangled name(elem_size=8:str 是指针)
|
||||
gen_arg_names: list[str] | t.CPtr = list[str](pool, 8)
|
||||
if sub.slice.kind() == ast.ASTKind.Tuple:
|
||||
@@ -1608,11 +1686,32 @@ class TypeGenMixin:
|
||||
if gp_tpn is not None and string.strcmp(nm.id, gp_tpn) == 0:
|
||||
gp_ta: str = self.GenericTypeArgs.get(gp_i)
|
||||
if gp_ta is not None:
|
||||
# 自映射防护(泛型循环套用):实参与参数名相同(T→T)
|
||||
# 时 _parse_type_string 会重新解析回同一个 Name → 无条件
|
||||
# 自递归无退出条件 → 编译卡死。直接返回 None 让上层回落。
|
||||
# TSUB-DBG: 打印泛型替换(定位 G3 泛型循环)
|
||||
fb_tsub: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_tsub is not None:
|
||||
viperlib.snprintf(fb_tsub, 1024, "[TSUB] %s -> %s", gp_tpn,
|
||||
gp_ta if gp_ta is not None else "(null)")
|
||||
VLogger.info(fb_tsub, "TSUB")
|
||||
# 自映射/污染实参防护(泛型循环套用):
|
||||
# 1) 实参与参数名完全一致(T→T)
|
||||
# 2) 实参串包含任一类型参数名(如 "T | t.CPtr"、" T "、
|
||||
# "list[T]")——_parse_type_string 解析后仍会产出
|
||||
# Name(参数名) → 递归再次进入本分支 → 无条件自递归
|
||||
# 无退出条件 → 编译卡死。该递归不经 _specialize_generic_class
|
||||
# 的深度守卫(GenericSpecDepth),必须在此拦截。
|
||||
# 直接返回 None 让上层回落(fail-fast:宁可类型退化
|
||||
# 也不静默卡死)。
|
||||
if string.strcmp(gp_ta, gp_tpn) == 0:
|
||||
return None
|
||||
polluted: int = 0
|
||||
gp_j: t.CSizeT
|
||||
for gp_j in range(gp_n):
|
||||
gp_pn: str = self.GenericTpNames.get(gp_j)
|
||||
if gp_pn is not None and string.strstr(gp_ta, gp_pn) is not None:
|
||||
polluted = 1
|
||||
break
|
||||
if polluted != 0:
|
||||
return None
|
||||
# 用具体类型名递归解析(支持 BinOp/Attribute 类型实参)
|
||||
gp_sub_node: ast.AST | t.CPtr = self._parse_type_string(pool, gp_ta, nm.ctx)
|
||||
if gp_sub_node is not None:
|
||||
@@ -1642,10 +1741,24 @@ class TypeGenMixin:
|
||||
if trans is not None and trans.ModuleSha1 is not None:
|
||||
own_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(nm.id, trans.ModuleSha1)
|
||||
if own_entry is not None and own_entry.Ty is not None:
|
||||
# 有 __new__ 的类(堆对象)注解 → Ptr(struct)(引用语义,对齐 TPC)。
|
||||
# 否则无 __new__ 的类(栈对象,如 Point)保持 struct 值语义:
|
||||
# 构造返回栈 alloca 指针,赋给 struct 值变量时 coerce load 拷贝。
|
||||
# 背景:d: dict = dict(bd) 的 dict 是堆对象(__new__ 分配),
|
||||
# 裸名注解按值解析会让 sub: dict = sub_p 把 i8* 当 struct 解引用
|
||||
# 崩溃(DictTest Test 13)。
|
||||
if own_entry.HasNew != 0:
|
||||
return llvmlite.Ptr(pool, own_entry.Ty)
|
||||
return own_entry.Ty
|
||||
if HandlesStruct.is_struct_visible(nm.id) != 0:
|
||||
struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(nm.id)
|
||||
if struct_ty is not None:
|
||||
nm_entry_s: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty)
|
||||
nm_has_new_s: int = 0
|
||||
if nm_entry_s is not None:
|
||||
nm_has_new_s = nm_entry_s.HasNew
|
||||
if nm_has_new_s != 0:
|
||||
return llvmlite.Ptr(pool, struct_ty)
|
||||
return struct_ty
|
||||
# CTypedef 动态查表:查动态 CTypedef 表,递归解析类型表达式
|
||||
# 用户自定义 CTypedef(如 MyHandle: t.CTypedef = VOIDPTR)在此解析
|
||||
@@ -1779,6 +1892,21 @@ class TypeGenMixin:
|
||||
if string.strcmp(gtn_nmx, other_nm_x.id) == 0:
|
||||
keep_other_ty = 1
|
||||
break
|
||||
# 内建标量类型名(int/str/bytes/bool/float/double)是合法
|
||||
# 标量,不是损坏节点解析出的垃圾:int | t.CPtr 应解析为
|
||||
# i32*(int 指针),若按"Name 未注册 struct 即丢弃"踢掉
|
||||
# int → 联合退化为 i8* → int_ptr[0]=val 写 1 字节截断、
|
||||
# 读回符号扩展(DictTest key5=500 读出 -12 根因)。
|
||||
if keep_other_ty == 0 and other_node is not None and other_node.kind() == ast.ASTKind.Name:
|
||||
other_nm_b: ast.Name | t.CPtr = (ast.Name | t.CPtr)(other_node)
|
||||
if other_nm_b.id is not None:
|
||||
if string.strcmp(other_nm_b.id, "int") == 0 or \
|
||||
string.strcmp(other_nm_b.id, "str") == 0 or \
|
||||
string.strcmp(other_nm_b.id, "bytes") == 0 or \
|
||||
string.strcmp(other_nm_b.id, "bool") == 0 or \
|
||||
string.strcmp(other_nm_b.id, "float") == 0 or \
|
||||
string.strcmp(other_nm_b.id, "double") == 0:
|
||||
keep_other_ty = 1
|
||||
if keep_other_ty == 0:
|
||||
other_ty = None
|
||||
if other_ty is None:
|
||||
|
||||
@@ -559,10 +559,45 @@ class AnnAssignHandle(HandlesBase.Mixin):
|
||||
_init_global_array_from_list(
|
||||
builder, pool, mod, alloca, aa.value, self.Trans)
|
||||
else:
|
||||
# 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → 读 i32
|
||||
self.Trans.CurAssignAnnot = aa.annotation
|
||||
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, aa.value,
|
||||
None, 0, self.Trans)
|
||||
if rhs_val is not None:
|
||||
# 注解退化修复(对齐 TPC 从构造结果推断类型):
|
||||
# 无实参泛型模板类注解(如 vi: vector.Vector | CPtr,模板
|
||||
# 未注册 struct → resolve 退化)会让 alloca 类型退化为
|
||||
# Ptr(i8),但 rhs 构造返回精确结构体指针(如 Ptr(Vector[int]
|
||||
# 结构))。此时按退化 alloca store 会丢失特化类型,后续
|
||||
# vi.push 方法调用按 Ptr(i8) 查不到类名 → AnnotClassName
|
||||
# 回退到模板名(无实参)→ vpi 查不到返回类型 fail-fast。
|
||||
# 用 rhs 精确类型重建 alloca 并更新符号表注册,使方法调用
|
||||
# 按精确特化类名解析。旧退化 alloca 行残留为 entry block
|
||||
# 死代码(文本 IR 即时生成,无法删除,无害)。
|
||||
precise_rhs_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
if rhs_val.Ty is not None:
|
||||
match rhs_val.Ty:
|
||||
case llvmlite.LLVMType.Ptr(inner_struct):
|
||||
match inner_struct:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
precise_rhs_ty = rhs_val.Ty
|
||||
case _:
|
||||
pass
|
||||
case _:
|
||||
pass
|
||||
if precise_rhs_ty is not None and alloca.Ty is not None:
|
||||
alloca_pt: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||||
if alloca_pt is not None and \
|
||||
t.CUInt64T(alloca_pt) != t.CUInt64T(precise_rhs_ty):
|
||||
new_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(
|
||||
builder, precise_rhs_ty)
|
||||
if new_alloca is not None:
|
||||
v_entry_rb: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||||
self.Trans.SymTab, nm.id)
|
||||
if v_entry_rb is not None:
|
||||
v_entry_rb.Alloca = new_alloca
|
||||
alloca = new_alloca
|
||||
# 类型转换:将 rhs_val 转换为 alloca 的 pointee 类型
|
||||
# 修复:整数字面量是 i32,但变量可能是 i8/i16/i64,需 trunc/sext
|
||||
target_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
|
||||
@@ -60,6 +60,8 @@ class AssignHandle(HandlesBase.Mixin):
|
||||
mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module
|
||||
|
||||
# 翻译 RHS 值
|
||||
# 无注解赋值无目标类型可推断,清空 CurAssignAnnot(防残留误判 c.Deref 宽度)
|
||||
self.Trans.CurAssignAnnot = None
|
||||
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, asgn.value, None, 0, self.Trans)
|
||||
if rhs_val is None:
|
||||
@@ -138,6 +140,51 @@ class AssignHandle(HandlesBase.Mixin):
|
||||
|
||||
tk: int = target.kind()
|
||||
|
||||
# Tuple 赋值: a, b = f() 多返回值解包
|
||||
# rhs_val 是匿名 struct 值(函数返回 tuple[T1,T2] 打包)→ alloca +
|
||||
# store + GEP 逐字段 load → store 到各 Name 目标。
|
||||
if tk == ast.ASTKind.Tuple:
|
||||
tgt_tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target)
|
||||
tgt_elts: list[ast.AST | t.CPtr] | t.CPtr = tgt_tup.elts
|
||||
if tgt_elts is not None and rhs_val is not None and rhs_val.Ty is not None:
|
||||
match rhs_val.Ty:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
tgt_n: t.CSizeT = tgt_elts.__len__()
|
||||
tmp_s: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, rhs_val.Ty)
|
||||
if tmp_s is not None:
|
||||
llvmlite.build_store(builder, rhs_val, tmp_s)
|
||||
fchain: llvmlite.ParamNode | t.CPtr = llvmlite.get_struct_fields(rhs_val.Ty)
|
||||
fcur: llvmlite.ParamNode | t.CPtr = fchain
|
||||
fti: t.CSizeT
|
||||
for fti in range(tgt_n):
|
||||
tgt_elt: ast.AST | t.CPtr = tgt_elts.get(fti)
|
||||
if tgt_elt is None or fcur is None:
|
||||
break
|
||||
fty: llvmlite.LLVMType | t.CPtr = llvmlite.paramnode_get_ty(fcur)
|
||||
if fty is not None and tgt_elt.kind() == ast.ASTKind.Name:
|
||||
tgt_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tgt_elt)
|
||||
if tgt_nm2.id is not None:
|
||||
fp2: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||||
builder, rhs_val.Ty, fty, tmp_s, fti)
|
||||
if fp2 is not None:
|
||||
fv2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, fty, fp2)
|
||||
tgt_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||||
self.Trans.SymTab, tgt_nm2.id)
|
||||
if tgt_alloca is None:
|
||||
tgt_alloca = HandlesVar.get_or_create_sym(
|
||||
self.Trans.SymTab, pool, builder, tgt_nm2.id, fty)
|
||||
if tgt_alloca is not None:
|
||||
sval: llvmlite.Value | t.CPtr = fv2
|
||||
if tgt_alloca.Ty is not None:
|
||||
sp: llvmlite.LLVMType | t.CPtr = tgt_alloca.Ty.Pointee
|
||||
if sp is not None:
|
||||
sval = HandlesExpr.coerce_to_type(builder, fv2, sp, node)
|
||||
llvmlite.build_store(builder, sval, tgt_alloca)
|
||||
fcur = llvmlite.paramnode_get_next(fcur)
|
||||
case _:
|
||||
pass
|
||||
continue
|
||||
|
||||
# Subscript 赋值: arr[i] = val / ptr[i] = val / list[i] = val
|
||||
if tk == ast.ASTKind.Subscript:
|
||||
# 检查是否是 list[T] 类型的 Subscript(泛型类不注册 struct)
|
||||
|
||||
@@ -1489,12 +1489,16 @@ def _check_and_promote_variadic_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
call_name: str,
|
||||
head: llvmlite.Value | t.CPtr,
|
||||
can: t.CSizeT) -> int:
|
||||
can: t.CSizeT,
|
||||
arg_nodes: list[ast.AST | t.CPtr] | t.CPtr = None,
|
||||
self_offset: int = 0,
|
||||
trans: HT.Translator | t.CPtr = None) -> int:
|
||||
"""检查被调用函数是否为变长函数,若是则对变长参数进行 C ABI 提升(委托到 gen._check_and_promote_variadic_call)"""
|
||||
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._check_and_promote_variadic_call(pool, builder, mod, call_name, head, can)
|
||||
return g._check_and_promote_variadic_call(pool, builder, mod, call_name, head, can,
|
||||
arg_nodes, self_offset, trans)
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -171,6 +171,14 @@ class ForHandle(HandlesBase.Mixin):
|
||||
ve_lst: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||||
trans.SymTab, nm_lst.id)
|
||||
if ve_lst is not None and ve_lst.AnnotClassName is not None:
|
||||
# dict 容器变量:按 __count__/__keys__ 布局迭代(__iter__ 协议内联)
|
||||
if string.strstr(ve_lst.AnnotClassName, "dict") is not None:
|
||||
lst_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, trans.Module, iter_node,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
if lst_val is not None and lst_val.Ty is not None \
|
||||
and HandlesExpr.is_ptr_type(lst_val.Ty) != 0:
|
||||
return self._handle_dict_iter(for_node, var_name, lst_val)
|
||||
if string.strstr(ve_lst.AnnotClassName, "list") is not None:
|
||||
lst_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, trans.Module, iter_node,
|
||||
@@ -818,6 +826,115 @@ class ForHandle(HandlesBase.Mixin):
|
||||
llvmlite.position_at_end(builder, end_bb)
|
||||
return new_vars
|
||||
|
||||
def _handle_dict_iter(self, for_node: ast.For | t.CPtr,
|
||||
var_name: str,
|
||||
dict_val: llvmlite.Value | t.CPtr) -> int:
|
||||
"""dict 容器迭代: for key in d: 按 __count__/__keys__ 布局迭代
|
||||
|
||||
_dict.vp 布局(8 字节槽):__keys__@0, __values__@1, __count__@2,
|
||||
__capacity__@3, __mbuddy__@4, __iter_index__@5。
|
||||
__iter__ 协议(__iter__ 重置 iter_index + __next__ 取 key)内联为
|
||||
循环:iter_idx < __count__ → key = __keys__[iter_idx]。
|
||||
"""
|
||||
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
|
||||
|
||||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||||
|
||||
# 读取 __count__(槽 2,字节偏移 16)
|
||||
cnt_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||||
builder, i64_ty, dict_val, llvmlite.const_int64(pool, 2))
|
||||
if cnt_ptr is None:
|
||||
HandlesType.fatal_error(for_node, "dict 迭代: 无法定位 __count__")
|
||||
count_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, cnt_ptr)
|
||||
|
||||
# 循环变量 alloca(元素类型 i8*,与 dict.__next__ 返回 str 一致)
|
||||
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||||
trans.SymTab, var_name)
|
||||
new_vars: int = 0
|
||||
if var_alloca is None:
|
||||
var_alloca = HandlesVar._alloca_at_entry(builder, i8_ptr_ty)
|
||||
if HandlesVar.define_var(
|
||||
trans.SymTab, var_name, var_alloca) == 0:
|
||||
new_vars = 1
|
||||
|
||||
# 隐式 index 变量 (i64,与 __count__ 类型对齐)
|
||||
idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i64_ty)
|
||||
llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca)
|
||||
|
||||
# 基本块: cond / body / incr / end
|
||||
cnt: int = trans._label_counter
|
||||
trans._label_counter = cnt + 1
|
||||
|
||||
name_buf: t.CChar | t.CPtr = pool.alloc(32)
|
||||
viperlib.snprintf(name_buf, 32, "dict.cond.%d", cnt)
|
||||
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
viperlib.snprintf(name_buf, 32, "dict.body.%d", cnt)
|
||||
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
viperlib.snprintf(name_buf, 32, "dict.incr.%d", cnt)
|
||||
incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
viperlib.snprintf(name_buf, 32, "dict.end.%d", cnt)
|
||||
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
llvmlite.build_br(builder, cond_bb)
|
||||
|
||||
# cond 块: load index, icmp slt idx, count
|
||||
llvmlite.position_at_end(builder, cond_bb)
|
||||
cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca)
|
||||
in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
|
||||
builder, llvmlite.ICMP_SLT, cur_idx, count_val)
|
||||
llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb)
|
||||
|
||||
# body 块: __keys__ + idx*8 → load key (i8*) → store to var
|
||||
llvmlite.position_at_end(builder, body_bb)
|
||||
kpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||||
builder, i64_ty, dict_val, llvmlite.const_int64(pool, 0))
|
||||
keys_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, kpp)
|
||||
eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 8)
|
||||
key_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, eight_val)
|
||||
key_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||||
builder, i8_ty, keys_ptr, key_offset)
|
||||
cur_key: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, key_addr)
|
||||
llvmlite.build_store(builder, cur_key, var_alloca)
|
||||
|
||||
# 保存旧循环上下文,设置 break/continue 目标
|
||||
old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb
|
||||
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
|
||||
trans._break_bb = end_bb
|
||||
trans._continue_bb = incr_bb
|
||||
|
||||
body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children
|
||||
if body is not None:
|
||||
body_count: t.CSizeT = body.__len__()
|
||||
for bi in range(body_count):
|
||||
stmt: ast.AST | t.CPtr = body.get(bi)
|
||||
if stmt is not None:
|
||||
HandlesBody.translate_stmt(trans, stmt)
|
||||
|
||||
trans._break_bb = old_break
|
||||
trans._continue_bb = old_continue
|
||||
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||||
llvmlite.build_br(builder, incr_bb)
|
||||
|
||||
# incr 块: index++
|
||||
llvmlite.position_at_end(builder, incr_bb)
|
||||
one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1)
|
||||
next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val)
|
||||
llvmlite.build_store(builder, next_idx, idx_alloca)
|
||||
llvmlite.build_br(builder, cond_bb)
|
||||
|
||||
# 定位到 end 块
|
||||
llvmlite.position_at_end(builder, end_bb)
|
||||
return new_vars
|
||||
|
||||
# ============================================================
|
||||
# 多变量迭代(enumerate / zip)
|
||||
#
|
||||
|
||||
@@ -59,6 +59,64 @@ class ReturnHandle(HandlesBase.Mixin):
|
||||
|
||||
val: llvmlite.Value | t.CPtr = None
|
||||
if rt.value is not None:
|
||||
# return a, b → 打包匿名 struct 值(多返回值,函数返回类型 tuple[T1,T2])
|
||||
if rt.value.kind() == ast.ASTKind.Tuple:
|
||||
rtp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(rt.value)
|
||||
rtp_elts: list[ast.AST | t.CPtr] | t.CPtr = rtp.elts
|
||||
if rtp_elts is not None:
|
||||
rt_n: t.CSizeT = rtp_elts.__len__()
|
||||
if rt_n > 0 and rt_n <= 16:
|
||||
rt_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 16)
|
||||
if rt_vals is not None:
|
||||
rt_val_ok: int = 1
|
||||
rvi: t.CSizeT
|
||||
for rvi in range(rt_n):
|
||||
ev_i: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, rtp_elts.get(rvi),
|
||||
self.Trans._funcs, self.Trans._func_count, self.Trans)
|
||||
if ev_i is not None:
|
||||
rt_vals[rvi] = t.CSizeT(ev_i)
|
||||
else:
|
||||
rt_val_ok = 0
|
||||
break
|
||||
if rt_val_ok != 0:
|
||||
# 构建匿名 struct 类型(字段类型 = 元素值类型)
|
||||
rt_head: llvmlite.ParamNode | t.CPtr = None
|
||||
rt_tail: llvmlite.ParamNode | t.CPtr = None
|
||||
rvi2: t.CSizeT
|
||||
for rvi2 in range(rt_n):
|
||||
rv_i: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(
|
||||
t.CVoid(rt_vals[rvi2], t.CPtr))
|
||||
if rv_i is None or rv_i.Ty is None:
|
||||
rt_val_ok = 0
|
||||
break
|
||||
rn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, rv_i.Ty)
|
||||
if rn is None:
|
||||
rt_val_ok = 0
|
||||
break
|
||||
if rt_head is None:
|
||||
rt_head = rn
|
||||
else:
|
||||
llvmlite.paramnode_set_next(rt_tail, rn)
|
||||
rt_tail = rn
|
||||
if rt_val_ok != 0 and rt_head is not None:
|
||||
rt_struct_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(
|
||||
pool, rt_head, rt_n, None)
|
||||
if rt_struct_ty is not None:
|
||||
rt_tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, rt_struct_ty)
|
||||
if rt_tmp is not None:
|
||||
rvi3: t.CSizeT
|
||||
for rvi3 in range(rt_n):
|
||||
rv3: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(
|
||||
t.CVoid(rt_vals[rvi3], t.CPtr))
|
||||
rfp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||||
builder, rt_struct_ty, rv3.Ty, rt_tmp, rvi3)
|
||||
if rfp is None:
|
||||
rt_val_ok = 0
|
||||
break
|
||||
llvmlite.build_store(builder, rv3, rfp)
|
||||
if rt_val_ok != 0:
|
||||
val = llvmlite.build_load(builder, rt_struct_ty, rt_tmp)
|
||||
# return self: 返回 self 指针本身(Ptr(StructTy)),而非结构体值
|
||||
# translate_value 会 load 得到结构体值,但 return self 需要指针
|
||||
# 注意: lookup_var 返回的是存储 self 的 alloca (Ptr(Ptr(StructTy)))
|
||||
|
||||
@@ -23,6 +23,7 @@ import lib.core.Handles.HandlesMatch as HandlesMatch
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesFunctions as HandlesFunctions
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
import lib.Projectrans.Config as Config
|
||||
|
||||
# ============================================================
|
||||
@@ -87,6 +88,12 @@ class Translator:
|
||||
_cur_func: llvmlite.Function | t.CPtr
|
||||
_cur_builder: llvmlite.IRBuilder | t.CPtr
|
||||
|
||||
# 当前赋值语句的注解节点(AnnAssign 翻译 rhs 前设置,Assign 翻译前清空)。
|
||||
# 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → bitcast i32* load,
|
||||
# 对齐 TPC HandlesSpecialCall._infer_deref_target_type(DictTest 500→-12 根因:
|
||||
# i8* Deref 固定读 1 字节 + sext 截断)。
|
||||
CurAssignAnnot: ast.AST | t.CPtr
|
||||
|
||||
# 循环控制流目标(break/continue)
|
||||
_break_bb: llvmlite.BasicBlock | t.CPtr
|
||||
_continue_bb: llvmlite.BasicBlock | t.CPtr
|
||||
@@ -392,6 +399,14 @@ class Translator:
|
||||
cur_imp_lineno = child.lineno
|
||||
self.ImportsH.HandleImportFromModule(child)
|
||||
self.ImportsH.HandleImportFromNames(child)
|
||||
# 对齐 TPC _inject_auto_imports:检测源文件对 list/dict 容器的使用
|
||||
# (裸名注解 d: dict / 构造 dict(...) / 下标 list[T]),自动把容器
|
||||
# 类标记为可见结构体。背景:_list.vp/_dict.vp 定义内建容器类且已由
|
||||
# Phase1 注册,但源文件不显式 import 它们(TPC 在翻译前自动注入
|
||||
# import _list/_dict);TPV 用可见性机制等效替代——否则裸名
|
||||
# `d: dict` 注解 resolve_annotation_type 时 is_struct_visible=0
|
||||
# 解析失败(DictTest 的 "变量类型注解解析失败")。
|
||||
self._inject_auto_container_visibility(pool, tree)
|
||||
# 扫描当前模块的 CTypedef 声明(NAME: t.CTypedef = Type),
|
||||
# 注册到动态 CTypedef 表,供 resolve_annotation_type 查询
|
||||
HandlesType.ScanCTypedefDeclarations(pool, tree)
|
||||
@@ -425,6 +440,98 @@ class Translator:
|
||||
HandlesFunctions.forward_declare_functions(self, tree)
|
||||
added: int = HandlesMain.translate_children(self, tree)
|
||||
|
||||
# ============================================================
|
||||
# 容器模块自动可见性注入(对齐 TPC _inject_auto_imports)
|
||||
#
|
||||
# TPC 在翻译前自动注入 `import _list / import _dict (+json)` 到源文件,
|
||||
# 使 list/dict 内建容器类在符号表中可见。TPV 用可见性机制等效替代:
|
||||
# _list.vp/_dict.vp 已由 Phase1 注册(可达集合含它们),这里只需在
|
||||
# 当前文件翻译时把容器类名标记为可见结构体,裸名注解/构造即可解析。
|
||||
#
|
||||
# 检测模式(与 TPC Phase2Translator._inject_auto_imports 一致):
|
||||
# - AnnAssign 注解裸名 Name(list/dict):d: dict
|
||||
# - 构造调用 func 裸名 Name(list/dict):dict(bd)
|
||||
# - Subscript 的 value 裸名 Name(list/dict):list[int]
|
||||
# ============================================================
|
||||
def _inject_auto_container_visibility(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
tree: ast.AST | t.CPtr):
|
||||
"""检测 list/dict 容器使用,注入容器类可见性"""
|
||||
if tree is None or tree.children is None:
|
||||
return
|
||||
# 用栈式缓冲区传递检测结果(跨函数参数用 4 字节 int 指针)
|
||||
need_list_box: t.CPtr = stdlib.malloc(4)
|
||||
need_dict_box: t.CPtr = stdlib.malloc(4)
|
||||
if need_list_box is None or need_dict_box is None:
|
||||
if need_list_box is not None:
|
||||
stdlib.free(need_list_box)
|
||||
if need_dict_box is not None:
|
||||
stdlib.free(need_dict_box)
|
||||
return
|
||||
need_list_box[0] = 0
|
||||
need_dict_box[0] = 0
|
||||
self._scan_container_usage(tree, need_list_box, need_dict_box)
|
||||
if need_dict_box[0] != 0:
|
||||
# dict 类可见 + _dict 模块导入(构造/方法调用的 SHA1 解析)
|
||||
HandlesStruct.add_visible_struct(pool, "dict")
|
||||
if self._imported_modules is None or \
|
||||
HandlesImports.is_module_imported(self._imported_modules, "_dict") == 0:
|
||||
self._imported_modules = HandlesImports.add_imported_module(
|
||||
pool, self._imported_modules, "_dict")
|
||||
if need_list_box[0] != 0:
|
||||
HandlesStruct.add_visible_struct(pool, "list")
|
||||
if self._imported_modules is None or \
|
||||
HandlesImports.is_module_imported(self._imported_modules, "_list") == 0:
|
||||
self._imported_modules = HandlesImports.add_imported_module(
|
||||
pool, self._imported_modules, "_list")
|
||||
stdlib.free(need_list_box)
|
||||
stdlib.free(need_dict_box)
|
||||
|
||||
def _scan_container_usage(self, node: ast.AST | t.CPtr,
|
||||
need_list_box: t.CPtr,
|
||||
need_dict_box: t.CPtr):
|
||||
"""递归扫描 AST 语句结构,检测 list/dict 容器使用"""
|
||||
if node is None:
|
||||
return
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.AnnAssign:
|
||||
aa_s: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||||
if aa_s.annotation is not None:
|
||||
self._check_container_type_node(aa_s.annotation, need_list_box, need_dict_box)
|
||||
elif k == ast.ASTKind.Call:
|
||||
cl_s: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||||
if cl_s.func is not None:
|
||||
self._check_container_type_node(cl_s.func, need_list_box, need_dict_box)
|
||||
elif k == ast.ASTKind.Subscript:
|
||||
sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||||
if sub_s.value is not None:
|
||||
self._check_container_type_node(sub_s.value, need_list_box, need_dict_box)
|
||||
# 递归语句块子节点
|
||||
if node.children is not None:
|
||||
ch_s: list[ast.AST | t.CPtr] | t.CPtr = node.children
|
||||
n_s: t.CSizeT = ch_s.__len__()
|
||||
for ci_s in range(n_s):
|
||||
self._scan_container_usage(ch_s.get(ci_s), need_list_box, need_dict_box)
|
||||
|
||||
def _check_container_type_node(self, node: ast.AST | t.CPtr,
|
||||
need_list_box: t.CPtr,
|
||||
need_dict_box: t.CPtr):
|
||||
"""检测类型位置节点是否为 list/dict(支持 Name 与 Subscript 外层)"""
|
||||
if node is None:
|
||||
return
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Name:
|
||||
nm_s: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||||
if nm_s.id is not None:
|
||||
if string.strcmp(nm_s.id, "dict") == 0:
|
||||
need_dict_box[0] = 1
|
||||
elif string.strcmp(nm_s.id, "list") == 0:
|
||||
need_list_box[0] = 1
|
||||
elif k == ast.ASTKind.Subscript:
|
||||
sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||||
if sub_s.value is not None:
|
||||
self._check_container_type_node(sub_s.value, need_list_box, need_dict_box)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# IR 输出
|
||||
# ============================================================
|
||||
|
||||
@@ -1215,6 +1215,13 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
stdlib.exit(1)
|
||||
|
||||
ret: int = tr.translate(tree)
|
||||
# 诊断:translate 正常返回(若挂起在 translate 内部,此行不会打印,
|
||||
# 用于区分"translate 内部挂起"与"后续 dump 挂起")
|
||||
if ret == 0:
|
||||
fb_done: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_done is not None:
|
||||
viperlib.snprintf(fb_done, 1024, "翻译完成(translate返回): %s", file_path)
|
||||
VLogger.info(fb_done, "Phase1")
|
||||
if ret != 0:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
|
||||
+20
@@ -161,6 +161,8 @@ def main() -> int:
|
||||
argparse.STORE_TRUE, "删除 includes.binary 预编译缓存并重新编译所有 includes")
|
||||
parser.add_argument("--clear-cache", None, argparse.BOOL, 0, None, False,
|
||||
argparse.STORE_TRUE, "清除 .transpyc_cache 全局缓存")
|
||||
parser.add_argument("--asan", None, argparse.BOOL, 0, None, False,
|
||||
argparse.STORE_TRUE, "ASan 模式:.ll 先 opt -passes=asan 插桩,链接加 -fsanitize=address")
|
||||
|
||||
# 解析命令行参数
|
||||
args: argparse.ParsedArgs | t.CPtr = parser.parse_args(sys._argc, sys._argv)
|
||||
@@ -234,6 +236,24 @@ def main() -> int:
|
||||
|
||||
stdio.printf("\n参数解析完成。\n")
|
||||
|
||||
# ASan 模式:设置 BuildPipeline 全局标志(compile_ll_to_obj 先 opt 插桩,链接加 -fsanitize=address)
|
||||
if args.get_bool("asan"):
|
||||
BuildPipeline.set_asan_mode(1)
|
||||
if log is not None:
|
||||
log.info("ASan 模式已启用(opt -passes=asan + -fsanitize=address)", "asan")
|
||||
# ASan 模式强制重建 includes.binary:缓存 obj 未做 asan 插桩,
|
||||
# 与非 asan obj 混链会导致 ASan 运行时崩溃
|
||||
mf_inc_bin_asan: str = Config.get_includes_binary_dir()
|
||||
if mf_inc_bin_asan is not None:
|
||||
n_asan: int = Utils.CleanDir(mf_inc_bin_asan)
|
||||
if log is not None:
|
||||
fb_asan: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_asan is not None:
|
||||
viperlib.snprintf(fb_asan, 1024, "ASan 模式清理 includes.binary: %d 个文件(将重建 asan obj)", n_asan)
|
||||
log.info(fb_asan, "asan")
|
||||
else:
|
||||
BuildPipeline.set_asan_mode(0)
|
||||
|
||||
# 加载 project.vpj 配置
|
||||
proj_loaded: int = 0
|
||||
proj_path: str = project
|
||||
|
||||
Reference in new issue
Block a user