fix(compiler): 方法返回类型三级来源重构(移除 _infer_method_ret_ty 按名推断)
方法返回类型改为:当前模块函数 → text.ll define → vpi stub 返回注解缓存,全部未命中 fail-fast 终止(无白名单、无 hook 编译器)。 1. VpiReader 文本提取缓存 + 按需加载 + 动态扩容 + 无注解默认 i32 2. 类名解析修复(继承括号不入类名、模块级函数清空类名) 3. SetTempDir 提前到 Phase1(json 在 Phase1 翻译,Phase2 太晚) 4. 内置方法 __before_init__/__init__/__new__ 固定返回类型 5. 泛型归一化匹配 + _subst_template_arg 模板参数替换 6. 调试插桩 VPI_DEBUG_ENABLE 开关(默认关闭)
This commit is contained in:
1 parent
a9ebb20790
commit
ea8bb0b3a4
3 files changed
+289
-13
No files matched your search
+180
-11
@@ -2,6 +2,7 @@ import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import sys
|
||||
import memhub
|
||||
@@ -29,6 +30,13 @@ import lib.core.Handles.HandlesTranslator as HT
|
||||
# 按 sha1.类名.方法名 查表并用 _resolve_vpi_ret_annot_str 纯字符串
|
||||
# 解析为 LLVMType,返回类型始终来自方法定义处,无白名单/无硬编码。
|
||||
# ============================================================
|
||||
# ============================================================
|
||||
# VPI_DEBUG_ENABLE - vpi 返回注解缓存调试输出开关
|
||||
# 0=关闭(默认),1=开启(打印全部 [VPI-*] 调试插桩)。
|
||||
# 排查"方法返回类型无法精确获取"问题时临时改为 1,解决后改回 0。
|
||||
# ============================================================
|
||||
VPI_DEBUG_ENABLE: t.CDefine = 0
|
||||
|
||||
VPI_RET_MAX: t.CDefine = 4096
|
||||
VPI_KEY_LEN: t.CDefine = 224
|
||||
VPI_RET_LEN: t.CDefine = 224
|
||||
@@ -50,6 +58,8 @@ _g_vpi_ret_cap: int = 0
|
||||
# ============================================================
|
||||
def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
"""从 vpi_buf 文本提取方法返回注解字符串(stdlib 持久)"""
|
||||
if VPI_DEBUG_ENABLE != 0:
|
||||
stdio.printf("[VPI-CACHE] in sha1=%s\n", src_sha1)
|
||||
global _g_vpi_ret_keys, _g_vpi_ret_strs, _g_vpi_ret_count, _g_vpi_ret_cap
|
||||
if vpi_buf is None or src_sha1 is None:
|
||||
return 0
|
||||
@@ -81,7 +91,9 @@ def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
if line_len >= 6 and string.strncmp(vpi_buf + i, "class ", 6) == 0:
|
||||
cstart: t.CSizeT = i + 6
|
||||
cend: t.CSizeT = cstart
|
||||
while cend < le and vpi_buf[cend] != ':' and vpi_buf[cend] != ' ':
|
||||
# 类名提取:到 ':' / ' ' / '(' 前停止(继承基类括号不入类名,
|
||||
# 如 "class MemBuddy(MemManager):" → "MemBuddy",与调用方短名一致)
|
||||
while cend < le and vpi_buf[cend] != ':' and vpi_buf[cend] != ' ' and vpi_buf[cend] != '(':
|
||||
cend += 1
|
||||
if cend > cstart:
|
||||
if cur_cls is not None:
|
||||
@@ -92,6 +104,11 @@ def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
cur_cls[cend - cstart] = '\0'
|
||||
# def name(...) -> Ret:
|
||||
elif line_len >= 4 and string.strncmp(vpi_buf + i, "def ", 4) == 0:
|
||||
# 模块级函数(行首无缩进):清空类名上下文,避免类结束后残留
|
||||
# (如 json 的 null/int_val 等模块级函数被误存为 JsonValue.null)
|
||||
if i == ls and cur_cls is not None:
|
||||
stdlib.free(cur_cls)
|
||||
cur_cls = None
|
||||
dstart: t.CSizeT = i + 4
|
||||
dend: t.CSizeT = dstart
|
||||
while dend < le and vpi_buf[dend] != '(':
|
||||
@@ -105,18 +122,30 @@ def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
arrow_pos = rpos
|
||||
break
|
||||
rpos += 1
|
||||
if arrow_pos < le and dend > dstart:
|
||||
if dend > dstart:
|
||||
# 返回类型:有 "-> Ret" 提取注解;无注解的非特殊方法默认 "i32"
|
||||
# (与 HandlesType.infer_return_type 无 return 语句时的默认行为一致,
|
||||
# 如 json._append_child / __setitem__ 无注解实际编译为 i32)。
|
||||
ret_src: str = None
|
||||
rtype_len: t.CSizeT = 0
|
||||
if arrow_pos < le:
|
||||
# 返回类型 = arrow_pos+2 跳过空格 到 ':' 前
|
||||
rstart: t.CSizeT = arrow_pos + 2
|
||||
while rstart < le and vpi_buf[rstart] == ' ':
|
||||
rstart += 1
|
||||
rend: t.CSizeT = rstart
|
||||
while rend < le and vpi_buf[rend] != ':':
|
||||
rend += 1
|
||||
if rend > rstart:
|
||||
rstart2: t.CSizeT = arrow_pos + 2
|
||||
while rstart2 < le and vpi_buf[rstart2] == ' ':
|
||||
rstart2 += 1
|
||||
rend2: t.CSizeT = rstart2
|
||||
while rend2 < le and vpi_buf[rend2] != ':':
|
||||
rend2 += 1
|
||||
if rend2 > rstart2:
|
||||
rtype_len = rend2 - rstart2
|
||||
ret_src = vpi_buf + rstart2
|
||||
else:
|
||||
# 无返回注解:默认 i32(特殊方法除外,见下方过滤)
|
||||
rtype_len = 3
|
||||
ret_src = "i32"
|
||||
if ret_src is not None:
|
||||
# 构造 key 和 ret_str,存入缓存
|
||||
mname_len: t.CSizeT = dend - dstart
|
||||
rtype_len: t.CSizeT = rend - rstart
|
||||
cls_len2: t.CSizeT = 0
|
||||
if cur_cls is not None:
|
||||
cls_len2 = string.strlen(cur_cls)
|
||||
@@ -127,6 +156,18 @@ def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
if mname_buf is not None:
|
||||
string.strncpy(mname_buf, vpi_buf + dstart, mname_len)
|
||||
mname_buf[mname_len] = '\0'
|
||||
# 无注解的特殊方法(构造/析构)跳过:它们有专门调用路径
|
||||
skip_def: int = 0
|
||||
if arrow_pos >= le:
|
||||
if string.strcmp(mname_buf, "__init__") == 0 or \
|
||||
string.strcmp(mname_buf, "__new__") == 0 or \
|
||||
string.strcmp(mname_buf, "__before_init__") == 0 or \
|
||||
string.strcmp(mname_buf, "__after_init__") == 0:
|
||||
skip_def = 1
|
||||
else:
|
||||
if VPI_DEBUG_ENABLE != 0:
|
||||
stdio.printf("[VPI-DEF] sha1=%s cls=%s m=%s\n", src_sha1, cur_cls, mname_buf)
|
||||
if skip_def == 0:
|
||||
key_buf: bytes = stdlib.malloc(key_len + 1)
|
||||
if key_buf is not None:
|
||||
if cur_cls is not None:
|
||||
@@ -147,7 +188,7 @@ def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
if grow_ok != 0:
|
||||
string.strcpy(_g_vpi_ret_keys + _g_vpi_ret_count * VPI_KEY_LEN, key_buf)
|
||||
string.strncpy(_g_vpi_ret_strs + _g_vpi_ret_count * VPI_RET_LEN,
|
||||
vpi_buf + rstart, rtype_len)
|
||||
ret_src, rtype_len)
|
||||
(_g_vpi_ret_strs + _g_vpi_ret_count * VPI_RET_LEN)[rtype_len] = '\0'
|
||||
_g_vpi_ret_count += 1
|
||||
stdlib.free(key_buf)
|
||||
@@ -201,6 +242,8 @@ def _grow_vpi_ret_cache() -> int:
|
||||
# ============================================================
|
||||
def _ensure_vpi_ret_annot_loaded(src_sha1: str, temp_dir: str) -> int:
|
||||
"""按需加载模块 vpi stub 的返回注解缓存,返回 1=已就绪 / 0=失败"""
|
||||
if VPI_DEBUG_ENABLE != 0:
|
||||
stdio.printf("[VPI-ENSURE] in sha1=%s temp=%s\n", src_sha1, temp_dir)
|
||||
if src_sha1 is None or temp_dir is None:
|
||||
return 0
|
||||
sha1_len: t.CSizeT = string.strlen(src_sha1)
|
||||
@@ -212,6 +255,8 @@ def _ensure_vpi_ret_annot_loaded(src_sha1: str, temp_dir: str) -> int:
|
||||
for pre_i in range(_g_vpi_ret_count):
|
||||
pre_key: bytes = _g_vpi_ret_keys + pre_i * VPI_KEY_LEN
|
||||
if string.strncmp(pre_key, src_sha1, sha1_len) == 0 and pre_key[sha1_len] == '.':
|
||||
if VPI_DEBUG_ENABLE != 0:
|
||||
stdio.printf("[VPI-ENSURE] prefix-hit key=%s count=%d\n", pre_key, _g_vpi_ret_count)
|
||||
return 1
|
||||
# 构造路径 {temp_dir}/{sha1[0:2]}/{sha1}.vpi(逐字符拼接,避免 %c 格式化问题)
|
||||
td_len: t.CSizeT = string.strlen(temp_dir)
|
||||
@@ -226,8 +271,12 @@ def _ensure_vpi_ret_annot_loaded(src_sha1: str, temp_dir: str) -> int:
|
||||
vpi_path[td_len + 3] = '/'
|
||||
string.strcpy(vpi_path + td_len + 4, src_sha1)
|
||||
string.strcpy(vpi_path + td_len + 4 + sha1_len, ".vpi")
|
||||
if VPI_DEBUG_ENABLE != 0:
|
||||
stdio.printf("[VPI-ENSURE] path=%s\n", vpi_path)
|
||||
f: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R)
|
||||
if f.closed:
|
||||
if VPI_DEBUG_ENABLE != 0:
|
||||
stdio.printf("[VPI-ENSURE] open-fail\n")
|
||||
stdlib.free(vpi_path)
|
||||
return 0
|
||||
vpi_buf: bytes = stdlib.malloc(VPI_READ_BUF_SIZE)
|
||||
@@ -243,17 +292,74 @@ def _ensure_vpi_ret_annot_loaded(src_sha1: str, temp_dir: str) -> int:
|
||||
else:
|
||||
vpi_buf[VPI_READ_BUF_SIZE - 1] = 0
|
||||
_cache_vpi_return_annots_text(vpi_buf, src_sha1)
|
||||
if VPI_DEBUG_ENABLE != 0:
|
||||
stdio.printf("[VPI-ENSURE] read=%d after-count=%d\n", bytes_read, _g_vpi_ret_count)
|
||||
stdlib.free(vpi_buf)
|
||||
stdlib.free(vpi_path)
|
||||
return 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _subst_template_arg - 替换注解字符串中独立的模板参数 token
|
||||
#
|
||||
# 泛型模板返回注解(如 list[T].get -> T)中的类型参数名(T)
|
||||
# 需替换为实际特化实参(AST|t.CPtr)后才能解析。仅替换前后
|
||||
# 非字母数字下划线边界的独立 token(避免误替换 t.CSizeT 等)。
|
||||
# 返回 stdlib 新分配字符串(调用者负责 free);失败返回 None。
|
||||
# ============================================================
|
||||
def _subst_template_arg(annot: str, tparam: str, targ: str) -> str:
|
||||
"""替换 annot 中独立的 tparam token 为 targ"""
|
||||
if annot is None or tparam is None or targ is None:
|
||||
return None
|
||||
alen: t.CSizeT = string.strlen(annot)
|
||||
tplen: t.CSizeT = string.strlen(tparam)
|
||||
tglen: t.CSizeT = string.strlen(targ)
|
||||
if tplen == 0 or tplen > alen:
|
||||
return annot
|
||||
out: bytes = stdlib.malloc(alen + tglen * 8 + 16)
|
||||
if out is None:
|
||||
return None
|
||||
opos: t.CSizeT = 0
|
||||
p: t.CSizeT = 0
|
||||
while p < alen:
|
||||
matched: int = 0
|
||||
if annot[p] == tparam[0] and p + tplen <= alen:
|
||||
if string.strncmp(annot + p, tparam, tplen) == 0:
|
||||
prev_ch: int = 0
|
||||
next_ch: int = 0
|
||||
if p > 0:
|
||||
prev_ch = annot[p - 1]
|
||||
if p + tplen < alen:
|
||||
next_ch = annot[p + tplen]
|
||||
prev_ok: int = 1
|
||||
if (prev_ch >= 'a' and prev_ch <= 'z') or (prev_ch >= 'A' and prev_ch <= 'Z') or \
|
||||
(prev_ch >= '0' and prev_ch <= '9') or prev_ch == '_':
|
||||
prev_ok = 0
|
||||
next_ok: int = 1
|
||||
if (next_ch >= 'a' and next_ch <= 'z') or (next_ch >= 'A' and next_ch <= 'Z') or \
|
||||
(next_ch >= '0' and next_ch <= '9') or next_ch == '_':
|
||||
next_ok = 0
|
||||
if prev_ok != 0 and next_ok != 0:
|
||||
string.strncpy(out + opos, targ, tglen)
|
||||
opos += tglen
|
||||
p += tplen
|
||||
matched = 1
|
||||
if matched == 0:
|
||||
out[opos] = annot[p]
|
||||
opos += 1
|
||||
p += 1
|
||||
out[opos] = '\0'
|
||||
return out
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _lookup_vpi_ret_annot - 查找缓存的方法返回注解字符串
|
||||
# ============================================================
|
||||
def _lookup_vpi_ret_annot(src_sha1: str, cls_name: str, method_name: str) -> str:
|
||||
"""查找缓存的方法返回注解字符串,未找到返回 None"""
|
||||
if _g_vpi_ret_keys is None or _g_vpi_ret_count == 0:
|
||||
if VPI_DEBUG_ENABLE != 0:
|
||||
stdio.printf("[VPI-LOOKUP] empty count=%d\n", _g_vpi_ret_count)
|
||||
return None
|
||||
if src_sha1 is None or method_name is None:
|
||||
return None
|
||||
@@ -270,11 +376,74 @@ def _lookup_vpi_ret_annot(src_sha1: str, cls_name: str, method_name: str) -> str
|
||||
viperlib.snprintf(key_buf, key_len + 1, "%s.%s.%s", src_sha1, cls_name, method_name)
|
||||
else:
|
||||
viperlib.snprintf(key_buf, key_len + 1, "%s.%s", src_sha1, method_name)
|
||||
if VPI_DEBUG_ENABLE != 0:
|
||||
stdio.printf("[VPI-LOOKUP] key=%s count=%d\n", key_buf, _g_vpi_ret_count)
|
||||
i: int
|
||||
for i in range(_g_vpi_ret_count):
|
||||
if string.strcmp(_g_vpi_ret_keys + i * VPI_KEY_LEN, key_buf) == 0:
|
||||
if VPI_DEBUG_ENABLE != 0:
|
||||
stdio.printf("[VPI-LOOKUP] hit\n")
|
||||
stdlib.free(key_buf)
|
||||
return _g_vpi_ret_strs + i * VPI_RET_LEN
|
||||
# 未命中:打印同 sha1 前缀的所有缓存条目(调试定位 key 形式差异)
|
||||
if VPI_DEBUG_ENABLE != 0:
|
||||
stdio.printf("[VPI-MISS] key=%s\n", key_buf)
|
||||
mi: int
|
||||
for mi in range(_g_vpi_ret_count):
|
||||
mk: bytes = _g_vpi_ret_keys + mi * VPI_KEY_LEN
|
||||
if string.strncmp(mk, src_sha1, sha1_len) == 0:
|
||||
if VPI_DEBUG_ENABLE != 0:
|
||||
stdio.printf(" [VPI-ENTRY] %s\n", mk)
|
||||
# 泛型特化归一化匹配:list[AST|t.CPtr].get → list[T].get 模板缓存。
|
||||
# 命中后把模板注解中的类型参数名(如 T)替换为实参(AST|t.CPtr)再返回。
|
||||
# 不依赖模板类已注册/特化已发生(base.vp 可能先于 list 模块翻译)。
|
||||
if cls_name is not None:
|
||||
lbkt_v: str = string.strchr(cls_name, '[')
|
||||
if lbkt_v is not None:
|
||||
rbkt_v: str = string.strrchr(cls_name, ']')
|
||||
if rbkt_v is not None and rbkt_v > lbkt_v:
|
||||
base_len_v: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_v) - t.CUInt64T(cls_name))
|
||||
param_len_v: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_v) - t.CUInt64T(lbkt_v) - 1)
|
||||
if base_len_v > 0 and param_len_v > 0:
|
||||
base_v: str = stdlib.malloc(base_len_v + 1)
|
||||
param_v: str = stdlib.malloc(param_len_v + 1)
|
||||
if base_v is not None and param_v is not None:
|
||||
string.strncpy(base_v, cls_name, base_len_v)
|
||||
base_v[base_len_v] = '\0'
|
||||
string.strncpy(param_v, lbkt_v + 1, param_len_v)
|
||||
param_v[param_len_v] = '\0'
|
||||
# 遍历缓存找 {sha1}.{base}[xxx].{method}
|
||||
gi: int
|
||||
for gi in range(_g_vpi_ret_count):
|
||||
gk: bytes = _g_vpi_ret_keys + gi * VPI_KEY_LEN
|
||||
if string.strncmp(gk, src_sha1, sha1_len) == 0 and \
|
||||
gk[sha1_len] == '.' and \
|
||||
string.strncmp(gk + sha1_len + 1, base_v, base_len_v) == 0 and \
|
||||
gk[sha1_len + 1 + base_len_v] == '[':
|
||||
gklb: str = string.strchr(gk + sha1_len + 1 + base_len_v, ']')
|
||||
if gklb is not None:
|
||||
tparam_len_v: t.CSizeT = t.CSizeT(
|
||||
t.CUInt64T(gklb) - t.CUInt64T(gk + sha1_len + 1 + base_len_v) - 1)
|
||||
if tparam_len_v > 0:
|
||||
meth_start_v: str = gklb + 2 # 跳过 ']' 和 '.'
|
||||
if string.strcmp(meth_start_v, method_name) == 0:
|
||||
tparam_v: str = stdlib.malloc(tparam_len_v + 1)
|
||||
if tparam_v is not None:
|
||||
string.strncpy(tparam_v, gk + sha1_len + 1 + base_len_v + 1, tparam_len_v)
|
||||
tparam_v[tparam_len_v] = '\0'
|
||||
new_annot_v: str = _subst_template_arg(
|
||||
_g_vpi_ret_strs + gi * VPI_RET_LEN, tparam_v, param_v)
|
||||
if VPI_DEBUG_ENABLE != 0:
|
||||
stdio.printf("[VPI-GEN] base=%s tparam=%s arg=%s annot=%s\n",
|
||||
base_v, tparam_v, param_v,
|
||||
_g_vpi_ret_strs + gi * VPI_RET_LEN)
|
||||
stdlib.free(tparam_v)
|
||||
stdlib.free(base_v)
|
||||
stdlib.free(param_v)
|
||||
stdlib.free(key_buf)
|
||||
return new_annot_v
|
||||
stdlib.free(base_v)
|
||||
stdlib.free(param_v)
|
||||
stdlib.free(key_buf)
|
||||
return None
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import sys
|
||||
import viperlib
|
||||
@@ -3082,6 +3083,9 @@ def _lookup_method_ret_ty_via_vpi(pool: memhub.MemBuddy | t.CPtr,
|
||||
cls_name: str,
|
||||
method_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""从 vpi stub 返回注解缓存获取方法返回类型,未命中返回 None"""
|
||||
if VpiReader.VPI_DEBUG_ENABLE != 0:
|
||||
stdio.printf("[VPI-CALL] lookup sha1=%s cls=%s m=%s tdlen=%d\n",
|
||||
cls_sha1, cls_name, method_name, _g_temp_dir_len)
|
||||
if pool is None or cls_sha1 is None or method_name is None:
|
||||
return None
|
||||
# 函数内懒 import:VpiReader imports HandlesExprCall,顶层 import 会成环
|
||||
@@ -3094,10 +3098,43 @@ def _lookup_method_ret_ty_via_vpi(pool: memhub.MemBuddy | t.CPtr,
|
||||
VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, _g_temp_dir)
|
||||
annot: str = VpiReader._lookup_vpi_ret_annot(cls_sha1, cls_name, method_name)
|
||||
if annot is None:
|
||||
if VpiReader.VPI_DEBUG_ENABLE != 0:
|
||||
stdio.printf("[VPI-CALL] annot=NONE\n")
|
||||
return None
|
||||
if VpiReader.VPI_DEBUG_ENABLE != 0:
|
||||
stdio.printf("[VPI-CALL] annot=%s\n", annot)
|
||||
return VpiReader._resolve_vpi_ret_annot_str(pool, annot, i32_ty, i8_ptr_ty)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _special_method_ret_ty - 编译器内置特殊方法的固定返回类型
|
||||
#
|
||||
# __before_init__ / __init__:编译器生成/约定返回 void
|
||||
# __new__:返回 Ptr(StructTy)(存储空间指针)
|
||||
#
|
||||
# 这些方法不存在于源码(vpi stub 无条目),跨模块调用时
|
||||
# found_func/text.ll/vpi 缓存必然未命中,但返回类型是编译器
|
||||
# 确定性语义(与 HandlesClassDef._translate_method 3543-3548 一致),
|
||||
# 在此直接固定,不触发 fail-fast 误报。非特殊方法返回 None。
|
||||
# ============================================================
|
||||
def _special_method_ret_ty(pool: memhub.MemBuddy | t.CPtr,
|
||||
class_name: str,
|
||||
method_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""编译器内置特殊方法的固定返回类型;非特殊返回 None"""
|
||||
if pool is None or method_name is None:
|
||||
return None
|
||||
if string.strcmp(method_name, "__before_init__") == 0 or \
|
||||
string.strcmp(method_name, "__init__") == 0:
|
||||
return llvmlite.Void(pool)
|
||||
if string.strcmp(method_name, "__new__") == 0:
|
||||
if class_name is not None:
|
||||
sp_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name)
|
||||
if sp_struct_ty is not None:
|
||||
return llvmlite.Ptr(pool, sp_struct_ty)
|
||||
return None
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _fail_method_ret_ty - 方法返回类型无法精确获取时 fail-fast
|
||||
#
|
||||
@@ -3440,6 +3477,10 @@ def _translate_property_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
|
||||
if frt is not None:
|
||||
call_ret_ty = frt
|
||||
else:
|
||||
sp_ty1: llvmlite.LLVMType | t.CPtr = _special_method_ret_ty(pool, class_name, method_name)
|
||||
if sp_ty1 is not None:
|
||||
call_ret_ty = sp_ty1
|
||||
else:
|
||||
cls_sha1_rt: str = HandlesStruct.get_struct_sha1(class_name)
|
||||
looked_up_ty: llvmlite.LLVMType | t.CPtr = _LookupMethodRetTyFromTextLL(
|
||||
@@ -3779,7 +3820,65 @@ def _translate_method_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
if frt is not None:
|
||||
call_ret_ty = frt
|
||||
else:
|
||||
# found_func 为 None(stub 未注入):尝试从 text.ll 查找实际返回类型
|
||||
# found_func 为 None(stub 未注入):先处理编译器内置特殊方法
|
||||
sp_ty2: llvmlite.LLVMType | t.CPtr = _special_method_ret_ty(pool, class_name, method_name)
|
||||
if sp_ty2 is not None:
|
||||
call_ret_ty = sp_ty2
|
||||
else:
|
||||
# 泛型特化方法调用:特化函数可能尚未注册(如 ast.base 用
|
||||
# list[AST|t.CPtr].get)。主动触发特化(幂等,MethodsEmitted 防重入),
|
||||
# 特化后重新查找即可命中,返回类型来自特化函数定义(天然精确)。
|
||||
gen_done: int = 0
|
||||
if class_name is not None:
|
||||
lbkt_g: str = string.strchr(class_name, '[')
|
||||
if lbkt_g is not None:
|
||||
rbkt_g: str = string.strrchr(class_name, ']')
|
||||
if rbkt_g is not None and rbkt_g > lbkt_g:
|
||||
base_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_g) - t.CUInt64T(class_name))
|
||||
arg_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_g) - t.CUInt64T(lbkt_g) - 1)
|
||||
if base_len_g > 0 and arg_len_g > 0:
|
||||
base_buf_g: str = pool.alloc(base_len_g + 1)
|
||||
arg_buf_g: str = pool.alloc(arg_len_g + 1)
|
||||
if base_buf_g is not None and arg_buf_g is not None:
|
||||
string.strncpy(base_buf_g, class_name, base_len_g)
|
||||
base_buf_g[base_len_g] = '\0'
|
||||
string.strncpy(arg_buf_g, lbkt_g + 1, arg_len_g)
|
||||
arg_buf_g[arg_len_g] = '\0'
|
||||
ta_list_g: list[str] | t.CPtr = list[str](pool, 4)
|
||||
if ta_list_g is not None:
|
||||
# 逗号分隔多类型实参(list[X] / dict[K, V])
|
||||
cur_arg_g: str = arg_buf_g
|
||||
while cur_arg_g is not None:
|
||||
comma_g: str = string.strchr(cur_arg_g, ',')
|
||||
if comma_g is None:
|
||||
ta_list_g.append(cur_arg_g)
|
||||
break
|
||||
seg_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(comma_g) - t.CUInt64T(cur_arg_g))
|
||||
seg_buf_g: str = pool.alloc(seg_len_g + 1)
|
||||
if seg_buf_g is not None:
|
||||
string.strncpy(seg_buf_g, cur_arg_g, seg_len_g)
|
||||
seg_buf_g[seg_len_g] = '\0'
|
||||
ta_list_g.append(seg_buf_g)
|
||||
cur_arg_g = comma_g + 1
|
||||
spec_name_g: str = HandlesClassDef._specialize_generic_class(
|
||||
trans, base_buf_g, ta_list_g)
|
||||
if spec_name_g is not None:
|
||||
# 特化后重新查找特化函数(特化名 = 调用点类名)
|
||||
spec_lk_g: str = pool.alloc(
|
||||
string.strlen(class_name) + string.strlen(method_name) + 2)
|
||||
if spec_lk_g is not None:
|
||||
viperlib.snprintf(spec_lk_g,
|
||||
string.strlen(class_name) + string.strlen(method_name) + 2,
|
||||
"%s.%s", class_name, method_name)
|
||||
spec_found_g: llvmlite.Function | t.CPtr = find_func_in_module(mod, spec_lk_g)
|
||||
if spec_found_g is not None:
|
||||
frt_g: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(spec_found_g)
|
||||
if frt_g is not None:
|
||||
call_ret_ty = frt_g
|
||||
found_func = spec_found_g
|
||||
gen_done = 1
|
||||
if gen_done == 0:
|
||||
# 尝试从 text.ll 查找实际返回类型
|
||||
# 避免指针返回值被默认 i32 导致 inttoptr 截断
|
||||
looked_up_ty: llvmlite.LLVMType | t.CPtr = _LookupMethodRetTyFromTextLL(
|
||||
pool, cls_sha1_mc, class_name, method_name)
|
||||
@@ -4993,7 +5092,10 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
llvmlite.value_set_next(tail3, arg_val3)
|
||||
tail3 = arg_val3
|
||||
total3: int = 1 + can
|
||||
ret_ty3: llvmlite.LLVMType | t.CPtr = _LookupMethodRetTyFromTextLL(
|
||||
ret_ty3: llvmlite.LLVMType | t.CPtr = _special_method_ret_ty(
|
||||
pool, cls_nm2, func_name)
|
||||
if ret_ty3 is None:
|
||||
ret_ty3 = _LookupMethodRetTyFromTextLL(
|
||||
pool, sha1_fc, cls_nm2, func_name)
|
||||
if ret_ty3 is None:
|
||||
# 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单)
|
||||
|
||||
@@ -500,6 +500,11 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
|
||||
# 设置全局 temp_dir(供跨模块 CDefine 查找使用)
|
||||
HandlesType.set_temp_dir(temp_dir)
|
||||
# 同步设置 HandlesExprCall 的 temp_dir(供 vpi stub 返回注解缓存按需加载)。
|
||||
# 必须在 includes 翻译前设置:Phase1 翻译 json 等 includes 时,"同模块方法
|
||||
# 调用(定义在后)"(如 json.__setitem__ 调 _pool_alloc)需要读
|
||||
# {temp_dir}/{sha1[0:2]}/{sha1}.vpi 兜底,而 Phase2 的 SetTempDir 太晚。
|
||||
HandlesExprCall.SetTempDir(temp_dir)
|
||||
|
||||
# 确保 temp 目录存在(build_dir/temp 可能尚未创建)
|
||||
BuildPipeline.ensure_dir(temp_dir)
|
||||
|
||||
Reference in new issue
Block a user