Some simple information syncing
This commit is contained in:
@@ -362,29 +362,49 @@ def _ensure_c_lib_declare(pool: memhub.MemBuddy | t.CPtr,
|
||||
# ============================================================
|
||||
def _infer_external_func_ret_ty(pool: memhub.MemBuddy | t.CPtr,
|
||||
func_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""根据函数名推断外部 includes 函数的返回类型"""
|
||||
"""根据函数名推断外部 includes 函数的返回类型
|
||||
|
||||
支持三种函数名形式:
|
||||
1. 裸名: "parse", "strlen"
|
||||
2. 别名: "json_parse"(from X import parse as json_parse)
|
||||
3. 带 SHA1 前缀: "240a9a4157959a9f.parse"(跨模块调用 mangled name)
|
||||
"""
|
||||
if pool is None or func_name is None:
|
||||
return llvmlite.Int32(pool)
|
||||
|
||||
# 提取裸函数名:去掉 SHA1 前缀(如 "240a9a4157959a9f.parse" → "parse")
|
||||
# SHA1 前缀是 16 位十六进制 + '.',检查是否有 '.' 分隔
|
||||
bare_name: str = func_name
|
||||
dot_pos: str = string.strrchr(func_name, 46) # 46 = ord('.')
|
||||
if dot_pos is not None:
|
||||
# '.' 后的部分是裸函数名
|
||||
bare_name = dot_pos + 1
|
||||
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
|
||||
# 返回 i8* 的函数(指针返回值,截断会导致错误)
|
||||
if func_name == "strchr":
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if func_name == "strrchr":
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if func_name == "strstr":
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if func_name == "strcpy":
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if func_name == "strncpy":
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if func_name == "memset":
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if func_name == "memset32":
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if func_name == "memcpy":
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if func_name == "memmove":
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if bare_name == "strchr" or func_name == "strchr":
|
||||
return i8_ptr_ty
|
||||
if bare_name == "strrchr" or func_name == "strrchr":
|
||||
return i8_ptr_ty
|
||||
if bare_name == "strstr" or func_name == "strstr":
|
||||
return i8_ptr_ty
|
||||
if bare_name == "strcpy" or func_name == "strcpy":
|
||||
return i8_ptr_ty
|
||||
if bare_name == "strncpy" or func_name == "strncpy":
|
||||
return i8_ptr_ty
|
||||
if bare_name == "memset" or func_name == "memset":
|
||||
return i8_ptr_ty
|
||||
if bare_name == "memset32" or func_name == "memset32":
|
||||
return i8_ptr_ty
|
||||
if bare_name == "memcpy" or func_name == "memcpy":
|
||||
return i8_ptr_ty
|
||||
if bare_name == "memmove" or func_name == "memmove":
|
||||
return i8_ptr_ty
|
||||
# JSON 解析函数返回 JsonValue*(指针)
|
||||
# from json.__parser import parse as json_parse → 别名 json_parse 也需覆盖
|
||||
if bare_name == "parse" or func_name == "parse" or func_name == "json_parse":
|
||||
return i8_ptr_ty
|
||||
# MemBuddy 方法(当类型信息丢失时可能走外部函数路径)
|
||||
if func_name == "alloc":
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
@@ -394,6 +414,14 @@ def _infer_external_func_ret_ty(pool: memhub.MemBuddy | t.CPtr,
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if func_name == "alloc_buf":
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
# VLogger 模块函数(跨模块调用时 stub 未注入,返回指针被截断为 i32 导致崩溃)
|
||||
if func_name == "get_logger":
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if func_name == "fmt_buf":
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
# Config 模块函数(跨模块调用时 stub 未注入,返回 i8* 被 inttoptr i32 截断导致路径损坏)
|
||||
if func_name == "get_includes_binary_dir":
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
|
||||
# 返回 i64 的函数
|
||||
if func_name == "strlen":
|
||||
@@ -442,6 +470,17 @@ def _infer_external_func_ret_ty(pool: memhub.MemBuddy | t.CPtr,
|
||||
return i8_ptr_ty
|
||||
if func_name == "LoadLibraryW":
|
||||
return i8_ptr_ty
|
||||
# Win32 Handle 返回函数(HANDLE = void* = i8*)
|
||||
if func_name == "GetStdHandle":
|
||||
return i8_ptr_ty
|
||||
if func_name == "CreateFileA":
|
||||
return i8_ptr_ty
|
||||
if func_name == "CreateFileW":
|
||||
return i8_ptr_ty
|
||||
if func_name == "FindFirstFileA":
|
||||
return i8_ptr_ty
|
||||
if func_name == "FindFirstFileW":
|
||||
return i8_ptr_ty
|
||||
|
||||
# Win32 API 返回 i64 (SIZE_T) 的函数
|
||||
if func_name == "VirtualQuery":
|
||||
@@ -486,7 +525,11 @@ def _infer_external_func_ret_ty(pool: memhub.MemBuddy | t.CPtr,
|
||||
func_name == "function_get_param_head" or func_name == "param_get_next":
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
|
||||
# 默认 i32
|
||||
# 默认 i32(整数):与本模块函数定义的默认返回类型一致(HandlesFunctions.py line 324)
|
||||
# 已知返回指针的函数在上方显式列出(返回 i8*),已知返回 i64 的函数也显式列出
|
||||
# 避免使用 i64 导致 stub 声明(declare i64)与实际定义(define i32)类型不匹配
|
||||
# x86-64 ABI 中 i32 返回值在 rax 低 32 位,与 define i32 完全一致
|
||||
# 与 _infer_method_ret_ty 的默认策略保持一致
|
||||
return llvmlite.Int32(pool)
|
||||
|
||||
# ============================================================
|
||||
@@ -2154,6 +2197,29 @@ def _translate_struct_ctor(pool: memhub.MemBuddy | t.CPtr,
|
||||
if ctor_entry is not None:
|
||||
is_oop = ctor_entry.IsOOP
|
||||
|
||||
# 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods)
|
||||
# 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入)
|
||||
# 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠)
|
||||
if is_oop == 0 and class_name is not None:
|
||||
init_lookup_name: t.CChar | t.CPtr = pool.alloc(128)
|
||||
if init_lookup_name is not None:
|
||||
viperlib.snprintf(init_lookup_name, 128, "%s.__init__", class_name)
|
||||
# 方案1: 检查当前模块的函数声明
|
||||
init_found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, init_lookup_name)
|
||||
if init_found_func is not None:
|
||||
is_oop = 1
|
||||
if ctor_entry is not None:
|
||||
ctor_entry.IsOOP = 1
|
||||
ctor_entry.HasInit = 1
|
||||
else:
|
||||
# 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入)
|
||||
init_defaults_entry: FuncDefaultsEntry | t.CPtr = find_func_defaults(init_lookup_name)
|
||||
if init_defaults_entry is not None:
|
||||
is_oop = 1
|
||||
if ctor_entry is not None:
|
||||
ctor_entry.IsOOP = 1
|
||||
ctor_entry.HasInit = 1
|
||||
|
||||
if is_oop != 0:
|
||||
# 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针
|
||||
storage_ptr: llvmlite.Value | t.CPtr = tmp
|
||||
@@ -2773,7 +2839,13 @@ def _ensure_method_declare(pool: memhub.MemBuddy | t.CPtr,
|
||||
ret_ty: llvmlite.LLVMType | t.CPtr,
|
||||
param_head: llvmlite.ParamNode | t.CPtr,
|
||||
param_count: int):
|
||||
"""为跨模块方法调用创建 declare 声明"""
|
||||
"""为跨模块方法调用创建 declare 声明
|
||||
|
||||
若模块中已存在同名 declare 且参数数量较少(例如 File.__init__ 的
|
||||
stub 仅 3 个参数,而实际调用传入 4 个),则向现有 declare 追加缺失
|
||||
参数,避免 llc 报 `argument invalid for parameter type` 之类的错误。
|
||||
已存在的 define 不修改(其参数由定义决定)。
|
||||
"""
|
||||
if pool is None or mod is None or call_name is None:
|
||||
return
|
||||
# 检查模块中是否已有同名函数(declare 或 define)
|
||||
@@ -2781,7 +2853,32 @@ def _ensure_method_declare(pool: memhub.MemBuddy | t.CPtr,
|
||||
while existing is not None:
|
||||
if existing.Name is not None:
|
||||
if string.strcmp(existing.Name, call_name) == 0:
|
||||
return # 已存在,无需重复声明
|
||||
# 已存在:仅当是 declare 且参数数量不足时追加缺失参数
|
||||
if existing.IsDeclared == 1:
|
||||
# 遍历现有参数链表计数(避免依赖 GSList.Count 字段的类型推断)
|
||||
cur_count: int = 0
|
||||
cur_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(existing)
|
||||
while cur_p is not None:
|
||||
cur_count += 1
|
||||
cur_p = cur_p.Next
|
||||
# 只追加缺失的参数(cur_count < param_count 时)
|
||||
if cur_count < param_count:
|
||||
# 定位到 param_head 的第 cur_count 个节点开始追加
|
||||
pnode2: llvmlite.ParamNode | t.CPtr = param_head
|
||||
pi2: int = 0
|
||||
# 跳过已有的 cur_count 个参数
|
||||
while pnode2 is not None and pi2 < cur_count:
|
||||
pnode2 = pnode2.Next
|
||||
pi2 += 1
|
||||
# 追加剩余参数
|
||||
while pnode2 is not None and pi2 < param_count:
|
||||
if pnode2.Ty is not None:
|
||||
param2: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode2.Ty, None)
|
||||
if param2 is not None:
|
||||
llvmlite.function_add_param(existing, param2)
|
||||
pnode2 = pnode2.Next
|
||||
pi2 += 1
|
||||
return
|
||||
existing = existing.Next
|
||||
# 创建函数声明
|
||||
func: llvmlite.Function | t.CPtr = llvmlite.new_function(pool, call_name, ret_ty)
|
||||
@@ -2832,18 +2929,35 @@ def _infer_method_ret_ty(pool: memhub.MemBuddy | t.CPtr,
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(method_name, "__enter__") == 0:
|
||||
return i8_ptr_ty
|
||||
# 工厂方法:返回对象指针(截断会导致后续方法调用崩溃)
|
||||
if string.strcmp(method_name, "parse_args") == 0:
|
||||
return i8_ptr_ty
|
||||
# 魔术方法:返回对象指针(如 JsonValue.__getitem__ 返回 JsonValue*)
|
||||
if string.strcmp(method_name, "__getitem__") == 0:
|
||||
return i8_ptr_ty
|
||||
|
||||
# 返回 i8* 的方法(返回字符串/类型名/描述)
|
||||
if string.strcmp(method_name, "type_name") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(method_name, "get_name") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(method_name, "get_str") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(method_name, "get_path") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(method_name, "get_buf") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(method_name, "to_string") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(method_name, "as_string") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(method_name, "__repr__") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(method_name, "__str__") == 0:
|
||||
return i8_ptr_ty
|
||||
# 返回 i8* 的方法(返回对象指针,如 JsonValue.get_item → JsonValue*)
|
||||
if string.strcmp(method_name, "get_item") == 0:
|
||||
return i8_ptr_ty
|
||||
|
||||
# 返回 void 的方法
|
||||
if string.strcmp(method_name, "__before_init__") == 0:
|
||||
@@ -2853,10 +2967,12 @@ def _infer_method_ret_ty(pool: memhub.MemBuddy | t.CPtr,
|
||||
if string.strcmp(method_name, "__exit__") == 0:
|
||||
return llvmlite.Void(pool)
|
||||
|
||||
# 默认 i64(整数):既可安全截断为 i32(trunc),也可转换为指针(inttoptr)
|
||||
# 避免使用指针类型(i8*)导致 coerce_to_type 生成 load(解引用)造成崩溃
|
||||
# x86-64 ABI 中 i32 返回值在 rax 低 32 位,i64 读取后 trunc 取低 32 位是安全的
|
||||
return llvmlite.Int64(pool)
|
||||
# 默认 i32(整数):与本模块函数定义的默认返回类型一致(HandlesFunctions.py line 324)
|
||||
# 已知返回指针的方法在上方显式列出(返回 i8*),已知返回 void 的方法也显式列出
|
||||
# 避免使用 i64 导致 stub 声明(declare i64)与实际定义(define i32)类型不匹配
|
||||
# x86-64 ABI 中 i32 返回值在 rax 低 32 位,与 define i32 完全一致
|
||||
# 与 _infer_external_func_ret_ty 的默认策略保持一致
|
||||
return llvmlite.Int32(pool)
|
||||
|
||||
# ============================================================
|
||||
# _translate_method_call - 翻译方法调用 obj.method(args)
|
||||
@@ -2981,6 +3097,65 @@ def _translate_method_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
total_count: int = 1 + can
|
||||
|
||||
# 默认参数填充:如果调用点参数少于函数定义参数,用默认值填充缺失参数
|
||||
# 查找函数的 defaults 信息
|
||||
mdf_defaults: t.CVoid | t.CPtr = None
|
||||
mdf_default_count: int = 0
|
||||
mdf_param_count: int = 0
|
||||
if trans is not None and trans._funcs is not None:
|
||||
mdf_entry: FuncEntry | t.CPtr = find_func_entry_in_table(
|
||||
trans._funcs, trans._func_count, lookup_name)
|
||||
if mdf_entry is not None:
|
||||
mdf_defaults = mdf_entry.Defaults
|
||||
mdf_default_count = mdf_entry.DefaultCount
|
||||
mdf_param_count = mdf_entry.ParamCount
|
||||
if mdf_defaults is None:
|
||||
mdf_gd: FuncDefaultsEntry | t.CPtr = find_func_defaults(lookup_name)
|
||||
if mdf_gd is not None:
|
||||
mdf_defaults = mdf_gd.Defaults
|
||||
mdf_default_count = mdf_gd.DefaultCount
|
||||
mdf_param_count = mdf_gd.ParamCount
|
||||
|
||||
# 计算需要填充的参数(不含 self)
|
||||
# can = 已提供的非 self 参数数量
|
||||
# mdf_param_count = 函数定义的非 self 参数数量
|
||||
if mdf_param_count > can:
|
||||
mdf_offset: int = mdf_param_count - mdf_default_count
|
||||
mdf_pi: int = can
|
||||
while mdf_pi < mdf_param_count:
|
||||
# 优先用默认值
|
||||
if mdf_defaults is not None and mdf_default_count > 0 and mdf_pi >= mdf_offset:
|
||||
mdf_di: int = mdf_pi - mdf_offset
|
||||
if mdf_di < mdf_default_count:
|
||||
mdf_defaults_list: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(mdf_defaults), t.CPtr))
|
||||
mdf_node: ast.AST | t.CPtr = mdf_defaults_list.get(mdf_di)
|
||||
if mdf_node is not None:
|
||||
mdf_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, mdf_node, None, 0, trans)
|
||||
if mdf_val is not None:
|
||||
llvmlite.value_set_next(mdf_val, None)
|
||||
llvmlite.value_set_next(tail, mdf_val)
|
||||
tail = mdf_val
|
||||
total_count += 1
|
||||
mdf_pi += 1
|
||||
continue
|
||||
# 无默认值时用零值兜底(需要 found_func 获取参数类型)
|
||||
if found_func is not None:
|
||||
param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||||
skip_z: int = 0
|
||||
while skip_z <= mdf_pi and param_node_z is not None:
|
||||
param_node_z = llvmlite.param_get_next(param_node_z)
|
||||
skip_z += 1
|
||||
if param_node_z is not None:
|
||||
zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z)
|
||||
zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty)
|
||||
if zero_val is not None:
|
||||
llvmlite.value_set_next(zero_val, None)
|
||||
llvmlite.value_set_next(tail, zero_val)
|
||||
tail = zero_val
|
||||
total_count += 1
|
||||
mdf_pi += 1
|
||||
|
||||
# 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用
|
||||
# (不依赖 found_func — 继承的虚方法可能没有子类实现)
|
||||
# 复用前面已获取的 mc_entry(find_struct_by_type 规避跨模块同名找错)
|
||||
@@ -3061,6 +3236,30 @@ def _translate_struct_ctor_kw(pool: memhub.MemBuddy | t.CPtr,
|
||||
is_oop: int = 0
|
||||
if kw_entry is not None:
|
||||
is_oop = kw_entry.IsOOP
|
||||
|
||||
# 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods)
|
||||
# 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入)
|
||||
# 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠)
|
||||
if is_oop == 0 and class_name is not None:
|
||||
kw_init_lookup: t.CChar | t.CPtr = pool.alloc(128)
|
||||
if kw_init_lookup is not None:
|
||||
viperlib.snprintf(kw_init_lookup, 128, "%s.__init__", class_name)
|
||||
# 方案1: 检查当前模块的函数声明
|
||||
kw_init_found: llvmlite.Function | t.CPtr = find_func_in_module(mod, kw_init_lookup)
|
||||
if kw_init_found is not None:
|
||||
is_oop = 1
|
||||
if kw_entry is not None:
|
||||
kw_entry.IsOOP = 1
|
||||
kw_entry.HasInit = 1
|
||||
else:
|
||||
# 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入)
|
||||
kw_init_defaults: FuncDefaultsEntry | t.CPtr = find_func_defaults(kw_init_lookup)
|
||||
if kw_init_defaults is not None:
|
||||
is_oop = 1
|
||||
if kw_entry is not None:
|
||||
kw_entry.IsOOP = 1
|
||||
kw_entry.HasInit = 1
|
||||
|
||||
if is_oop != 0:
|
||||
_call_method_on_ptr(pool, builder, mod, class_name,
|
||||
"__before_init__", tmp, None, 0, trans)
|
||||
@@ -3693,13 +3892,27 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
# 检测 obj.__len__() — 返回 list 对象的 __count__ 字段(偏移 8,i64)
|
||||
# __len__ 是 list[T] 的内置方法,list 是泛型类不注册 struct
|
||||
# 注意: 必须用 translate_value 而非 translate_name_value,因为 len_at.value
|
||||
# 可能是 Attribute 节点(如 md_ags.args),translate_name_value 只处理 Name 节点,
|
||||
# 对 Attribute 会错误返回 i32 0,导致 GEP base 不是指针(base of getelementptr must be a pointer)
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
len_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||||
if len_at.attr is not None and string.strcmp(len_at.attr, "__len__") == 0:
|
||||
if len_at.value is not None and can == 0:
|
||||
obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_name_value(
|
||||
builder, pool, len_at.value, trans)
|
||||
if obj_val is not None:
|
||||
obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, len_at.value, funcs_ptr, func_count, trans)
|
||||
if obj_val is not None and obj_val.Ty is not None:
|
||||
# 防御性类型检查: obj_val 必须是指针类型才能做 GEP
|
||||
# 如果 translate_value 返回 i32 (如 CDefine 常量被误解析、
|
||||
# 模块属性前向引用回退为 i32),GEP base 会是 i32 而非指针,
|
||||
# 导致 llc 报错 "base of getelementptr must be a pointer"
|
||||
if HandlesExpr.is_ptr_type(obj_val.Ty) == 0:
|
||||
# 诊断: 输出节点类型信息帮助定位根本原因
|
||||
len_node_kind: int = len_at.value.kind()
|
||||
stdio.printf(
|
||||
"[LEN-DIAG] __len__ on non-ptr (kind=%d), fallback to 0\n",
|
||||
len_node_kind)
|
||||
return llvmlite.const_int64(pool, 0)
|
||||
i64_ty_len: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
# 注意: 必须用 const_int64 而非 ConstInt(...,"0")
|
||||
# ConstInt 的 name 参数 "0" 会被当作 IR 文本值输出 i64 0
|
||||
@@ -3917,6 +4130,20 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
lm_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, lm_at.value, funcs_ptr, func_count, trans)
|
||||
if lm_obj is not None:
|
||||
# 防御性类型检查: lm_obj 必须是指针类型才能做 GEP
|
||||
# translate_value 对某些 Attribute 节点(如 ast.Arguments 的属性)
|
||||
# 可能返回 i32 0 (非指针),直接 GEP 会导致
|
||||
# "base of getelementptr must be a pointer" 错误
|
||||
if lm_obj.Ty is None or HandlesExpr.is_ptr_type(lm_obj.Ty) == 0:
|
||||
lm_node_kind: int = lm_at.value.kind()
|
||||
fb_lm: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_lm is not None:
|
||||
viperlib.snprintf(fb_lm, 1024,
|
||||
"list 方法 '%s' 的目标对象非指针 (node kind=%d),"
|
||||
"translate_value 类型推断失败",
|
||||
lm_name, lm_node_kind)
|
||||
VLogger.critical(fb_lm, "LIST-METHOD")
|
||||
return None
|
||||
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)
|
||||
@@ -4245,6 +4472,9 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
# 旧逻辑(IsDeclared==1 时用 func_name 裸名)是错误的:stub 注入的 declare Name 已带 SHA1 前缀,
|
||||
# 用裸名会导致 call @_PathToModuleName 而 define 是 @"sha1._PathToModuleName",链接报 undefined reference
|
||||
call_name: str = func_name
|
||||
# 原始函数名(别名导入时记录,如 from X import parse as json_parse → orig_func_name="parse")
|
||||
# 用于在别名处理后重新推断返回类型,避免 _infer_external_func_ret_ty 用别名匹配失败
|
||||
orig_func_name: str = None
|
||||
if found_func is not None:
|
||||
found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
|
||||
if found_name is not None:
|
||||
@@ -4357,6 +4587,11 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
bo_buf[bo_i] = bare_orig[bo_i]
|
||||
bo_buf[bo_len] = '\0'
|
||||
bare_func_name = bo_buf
|
||||
# 记录原始函数名,供后续重新推断返回类型
|
||||
# 例如 from json.__parser import parse as json_parse
|
||||
# func_name="json_parse", bare_func_name="parse"
|
||||
# _infer_external_func_ret_ty 用 "parse" 能正确匹配,用 "json_parse" 则返回默认 i32
|
||||
orig_func_name = bare_func_name
|
||||
if is_cexport_func(bare_sha1, bare_func_name) != 0:
|
||||
call_name = bare_func_name
|
||||
else:
|
||||
@@ -4382,6 +4617,14 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
# memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失)
|
||||
if func_name == "memcpy" and can >= 3:
|
||||
return _emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst2, mc_src2, mc_num2)
|
||||
# 别名导入重新推断返回类型:
|
||||
# from X import parse as json_parse → func_name="json_parse" 时 _infer_external_func_ret_ty 返回默认 i32
|
||||
# 用 orig_func_name="parse" 重新推断,能正确匹配返回 i8*(JsonValue*)
|
||||
# 避免指针被截断为 i32 后 inttoptr 丢失高 32 位导致崩溃
|
||||
if orig_func_name is not None and orig_func_name != func_name:
|
||||
re_inferred_ty: llvmlite.LLVMType | t.CPtr = _infer_external_func_ret_ty(pool, orig_func_name)
|
||||
if re_inferred_ty is not None:
|
||||
call_ret_ty = re_inferred_ty
|
||||
# 跨模块调用:创建 declare 声明,避免 llc 报 undefined value
|
||||
_ensure_method_declare(pool, mod, call_name, call_ret_ty, head, can)
|
||||
return llvmlite.build_call(builder, call_name, head, can, call_ret_ty, 0)
|
||||
|
||||
Reference in New Issue
Block a user