1086 lines
50 KiB
Plaintext
1086 lines
50 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import stdlib
|
||
import sys
|
||
import viperlib
|
||
import w32.fileio as fileio
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Handles.HandlesBase as HandlesBase
|
||
import lib.core.Handles.HandlesTranslator as HT
|
||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||
import lib.core.Handles.HandlesVar as HandlesVar
|
||
import lib.core.Handles.HandlesType as HandlesType
|
||
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
|
||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||
import lib.core.Handles.HandlesImports as HandlesImports
|
||
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||
import lib.core.Handles.HandlesFunctions as HandlesFunctions
|
||
import lib.core.StubMerger as StubMerger
|
||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
|
||
|
||
|
||
# ============================================================
|
||
# CallGenBase - CallGenMixin 拆分 1/9(最底层父类):模块符号查找 +
|
||
# 返回类型解析基础设施
|
||
#
|
||
# 按功能域从 CallGenMixin.vp 拆出(500~1500 行/文件架构重构):
|
||
# 字段(15 个)+ InitCallGen + 模块符号查找(sha1/cexport/vpi/reexport/find_func_in_module)
|
||
# + 返回类型解析链(_ensure_method_declare/_LookupMethodRetTyFromTextLL/_dep_text_ll_exists 等)
|
||
#
|
||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug)
|
||
# ============================================================
|
||
GLOBAL_FUNC_MAX: t.CDefine = 8192
|
||
GLOBAL_DEFAULTS_MAX: t.CDefine = 4096
|
||
_CEXPORT_MAX: t.CDefine = 256
|
||
ASM_MAX_OPERANDS: t.CDefine = 16
|
||
ASM_TEXT_BUF_SIZE: t.CDefine = 2048
|
||
ASM_CONST_BUF_SIZE: t.CDefine = 512
|
||
ASM_ARGS_BUF_SIZE: t.CDefine = 512
|
||
ASM_LINE_BUF_SIZE: t.CDefine = 4096
|
||
LLVMIR_MAX_OPS: t.CDefine = 16
|
||
LLVMIR_TEMPLATE_BUF: t.CDefine = 512
|
||
# 闭包名表大小(原 HandlesExprCall 模块级常量)
|
||
MAX_CLOSURE_NAMES: t.CDefine = 128
|
||
# 函数指针签名表大小(原 HandlesExprCall 模块级常量)
|
||
MAX_FUNC_PTR_SIGS: t.CDefine = 64
|
||
# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32)
|
||
ISINSTANCE_CLASS_MAX: t.CDefine = 64
|
||
|
||
|
||
# ============================================================
|
||
# CallGenBase - 最底层父类(字段 + 模块查找 + 返回类型解析)
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class CallGenBase:
|
||
"""调用分派最底层父类(字段 + 模块符号查找 + 返回类型解析基础设施)"""
|
||
|
||
# --- c.cexport 注册表(原 _g_cexport_sha1_arr/_g_cexport_func_arr/_g_cexport_count) ---
|
||
CexportSha1Arr: bytes
|
||
CexportFuncArr: bytes
|
||
CexportCount: int
|
||
|
||
# --- LLVMIR 寄存器序号(原 _g_llvmir_reg_seq) ---
|
||
LLVMIRRegSeq: int
|
||
|
||
# --- temp 目录(原 _g_temp_dir/_g_temp_dir_len) ---
|
||
TempDir: str
|
||
TempDirLen: t.CSizeT
|
||
|
||
# --- 闭包名表(原 _g_closure_names/_g_closure_count) ---
|
||
ClosureNames: str
|
||
ClosureCount: int
|
||
|
||
# --- 函数指针签名表(原 _g_funcptr_names/_g_funcptr_rets/_g_funcptr_count) ---
|
||
FuncptrNames: str
|
||
FuncptrRets: t.CUInt64T | t.CPtr
|
||
FuncptrCount: int
|
||
|
||
# --- 全局函数注册表(原 _global_funcs/_global_func_count) ---
|
||
GlobalFuncs: HandlesExprCall.FuncEntry | t.CPtr
|
||
GlobalFuncCount: int
|
||
|
||
# --- 全局默认参数表(原 _global_defaults/_global_defaults_count) ---
|
||
GlobalDefaults: HandlesExprCall.FuncDefaultsEntry | t.CPtr
|
||
GlobalDefaultsCount: int
|
||
|
||
def InitCallGen(self) -> int:
|
||
"""初始化调用 Mixin 字段(子类构造时内联调用,规避 NoVTable 继承符号不转发)"""
|
||
if self is None:
|
||
return 1
|
||
self.CexportSha1Arr = None
|
||
self.CexportFuncArr = None
|
||
self.CexportCount = 0
|
||
self.LLVMIRRegSeq = 0
|
||
self.TempDir = None
|
||
self.TempDirLen = 0
|
||
self.ClosureNames = None
|
||
self.ClosureCount = 0
|
||
self.FuncptrNames = None
|
||
self.FuncptrRets = None
|
||
self.FuncptrCount = 0
|
||
self.GlobalFuncs = None
|
||
self.GlobalFuncCount = 0
|
||
self.GlobalDefaults = None
|
||
self.GlobalDefaultsCount = 0
|
||
return 0
|
||
|
||
# ============================================================
|
||
# P4 簇 1+2 迁移方法(函数体来自 HandlesExprCall.vp:
|
||
# 模块 SHA1 查询/CExport 注册表/c.* 系列/内联汇编/LLVMIR)
|
||
# 本模块函数调用改 self.,外部模块调用保留模块前缀
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# P4 簇 1+2 迁移方法(函数体来自 HandlesExprCall.vp:
|
||
# 模块 SHA1 查询/CExport 注册表/c.* 系列/内联汇编/LLVMIR)
|
||
# 本模块函数调用改 self.,外部模块调用保留模块前缀
|
||
# ============================================================
|
||
|
||
def _lookup_module_sha1(self, mod_name: str) -> str:
|
||
"""查找模块名对应的 SHA1,找不到返回 None
|
||
|
||
委托给 StubMerger.LookupSha1ByModName(精确匹配 + 包名回退)。
|
||
"""
|
||
return StubMerger.LookupSha1ByModName(mod_name)
|
||
|
||
|
||
def _lookup_module_sha1_suffix(self, mod_suffix: str) -> str:
|
||
"""后缀匹配查找模块 SHA1,如 mod_suffix="__types" 匹配 "llvmlite.__types"
|
||
|
||
用于 from .X import Y 的相对导入:impf.module 是 ".X"(带前导点),
|
||
去掉前导点后为 "X",SHA1 映射表中键是 "pkg.X",需要后缀匹配。
|
||
委托给 StubMerger.LookupSha1ByModNameSuffix(精确 + 后缀 + 反向后缀)。
|
||
"""
|
||
return StubMerger.LookupSha1ByModNameSuffix(mod_suffix)
|
||
|
||
|
||
def _module_package_from_sha1(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod_sha1: str) -> str:
|
||
"""从 SHA1 存储器的 rel_path 计算模块所属包名(目录部分,'/' → '.')"""
|
||
if pool is None or mod_sha1 is None:
|
||
return None
|
||
rel_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr()
|
||
sha1_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr()
|
||
count: int = StubMerger.GetSha1StoreCount()
|
||
if rel_arr_ptr is None or sha1_arr_ptr is None or count <= 0:
|
||
return None
|
||
for i in range(count):
|
||
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||
if string.strcmp(sha1_arr_ptr + sidx, mod_sha1) != 0:
|
||
continue
|
||
ridx: t.CSizeT = t.CSizeT(i) * StubMerger.MAX_REL_PATH_LEN
|
||
rel: str = rel_arr_ptr + ridx
|
||
last_slash: str = string.strrchr(rel, 47) # 47 = ord('/')
|
||
if last_slash is None:
|
||
return None
|
||
pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(last_slash) - t.CUInt64T(rel))
|
||
if pkg_len == 0:
|
||
return None
|
||
pkg_buf: str = pool.alloc(pkg_len + 1)
|
||
if pkg_buf is None:
|
||
return None
|
||
for pi in range(pkg_len):
|
||
if rel[pi] == '/':
|
||
pkg_buf[pi] = '.'
|
||
else:
|
||
pkg_buf[pi] = rel[pi]
|
||
pkg_buf[pkg_len] = '\0'
|
||
return pkg_buf
|
||
return None
|
||
|
||
|
||
def _lookup_reexport_from_vpi(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod_sha1: str, func_name: str) -> str:
|
||
"""re-export 表未命中时,从模块 .vpi 按需解析 from-import 定位定义模块
|
||
|
||
includes 模块(如 llvmlite/__init__)的 stub/text 已存在时不会被按需
|
||
全量翻译(Phase2 3.5 仅在 stub/text 缺失时翻译),而 re-export 表只在
|
||
declare_only=0 的全量翻译中注册(HandleImportFromNames),因此表可能为空。
|
||
本函数解析该模块 .vpi 的 "from .X import ... func_name ..." 语句,
|
||
返回定义模块名(如 llvmlite/__init__ 的 .__builder → "llvmlite.__builder")。
|
||
"""
|
||
if pool is None or mod_sha1 is None or func_name is None:
|
||
return None
|
||
temp_dir: str = HandlesType.get_temp_dir()
|
||
if temp_dir is None:
|
||
return None
|
||
td_len: t.CSizeT = string.strlen(temp_dir)
|
||
vpi_path: str = StubMerger._sliced_path(temp_dir, td_len, mod_sha1, "vpi")
|
||
if vpi_path is None:
|
||
return None
|
||
READ_SZ: t.CSizeT = 1048576
|
||
buf: bytes = stdlib.malloc(READ_SZ)
|
||
if buf is None:
|
||
stdlib.free(vpi_path)
|
||
return None
|
||
vf: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R)
|
||
stdlib.free(vpi_path)
|
||
if vf.closed:
|
||
stdlib.free(buf)
|
||
return None
|
||
nrd: LONG = vf.read_all(buf, READ_SZ)
|
||
vf.close()
|
||
if nrd <= 0:
|
||
stdlib.free(buf)
|
||
return None
|
||
if nrd < READ_SZ:
|
||
buf[nrd] = 0
|
||
else:
|
||
buf[READ_SZ - 1] = 0
|
||
name_len: t.CSizeT = string.strlen(func_name)
|
||
total: t.CSizeT = string.strlen(buf)
|
||
pos: t.CSizeT = 0
|
||
while pos < total:
|
||
ls: t.CSizeT = pos
|
||
while pos < total and buf[pos] != '\n':
|
||
pos += 1
|
||
ll: t.CSizeT = pos - ls
|
||
if pos < total:
|
||
pos += 1
|
||
# 行必须以 "from " 开头
|
||
if ll < 6:
|
||
continue
|
||
if buf[ls] != 'f' or buf[ls + 1] != 'r' or buf[ls + 2] != 'o' or buf[ls + 3] != 'm' or buf[ls + 4] != ' ':
|
||
continue
|
||
# 找 " import " 分隔符
|
||
imp_pos: t.CSizeT = ls + 5
|
||
while imp_pos + 7 <= ls + ll:
|
||
if buf[imp_pos] == ' ' and buf[imp_pos + 1] == 'i' and buf[imp_pos + 2] == 'm' and \
|
||
buf[imp_pos + 3] == 'p' and buf[imp_pos + 4] == 'o' and buf[imp_pos + 5] == 'r' and \
|
||
buf[imp_pos + 6] == 't' and buf[imp_pos + 7] == ' ':
|
||
break
|
||
imp_pos += 1
|
||
if imp_pos + 7 > ls + ll:
|
||
continue
|
||
mod_start: t.CSizeT = ls + 5
|
||
mod_end: t.CSizeT = imp_pos
|
||
# 名称列表从 "import " 之后(逗号分隔,含 "A as B" 取原名 A)
|
||
nm_start: t.CSizeT = imp_pos + 8
|
||
scan: t.CSizeT = nm_start
|
||
while scan < ls + ll:
|
||
while scan < ls + ll and (buf[scan] == ' ' or buf[scan] == ','):
|
||
scan += 1
|
||
if scan >= ls + ll:
|
||
break
|
||
n_end: t.CSizeT = scan
|
||
while n_end < ls + ll and buf[n_end] != ',' and buf[n_end] != ' ':
|
||
n_end += 1
|
||
cand_start: t.CSizeT = scan
|
||
cand_len: t.CSizeT = n_end - scan
|
||
as_pos: t.CSizeT = scan
|
||
while as_pos + 4 <= n_end:
|
||
if buf[as_pos] == ' ' and buf[as_pos + 1] == 'a' and buf[as_pos + 2] == 's' and buf[as_pos + 3] == ' ':
|
||
cand_start = as_pos + 4
|
||
cand_len = n_end - cand_start
|
||
break
|
||
as_pos += 1
|
||
if cand_len == name_len:
|
||
m_ok: int = 1
|
||
for ki in range(name_len):
|
||
if buf[cand_start + ki] != func_name[ki]:
|
||
m_ok = 0
|
||
break
|
||
if m_ok == 1:
|
||
# 命中:解析模块名(前导点 → 相对导入,补包前缀)
|
||
has_dot: int = 0
|
||
if buf[mod_start] == '.':
|
||
has_dot = 1
|
||
mod_buf: str = pool.alloc(mod_end - mod_start + 1)
|
||
if mod_buf is None:
|
||
stdlib.free(buf)
|
||
return None
|
||
mi: t.CSizeT = 0
|
||
while mod_start + mi < mod_end:
|
||
mod_buf[mi] = buf[mod_start + mi]
|
||
mi += 1
|
||
mod_buf[mi] = '\0'
|
||
while mod_buf[0] == '.':
|
||
mod_buf = mod_buf + 1
|
||
if string.strlen(mod_buf) == 0:
|
||
stdlib.free(buf)
|
||
return None
|
||
if has_dot != 0:
|
||
pkg: str = self._module_package_from_sha1(pool, mod_sha1)
|
||
if pkg is None:
|
||
stdlib.free(buf)
|
||
return None
|
||
rl: t.CSizeT = string.strlen(pkg) + string.strlen(mod_buf) + 2
|
||
res: str = pool.alloc(rl)
|
||
if res is None:
|
||
stdlib.free(buf)
|
||
return None
|
||
viperlib.snprintf(res, rl, "%s.%s", pkg, mod_buf)
|
||
stdlib.free(buf)
|
||
return res
|
||
stdlib.free(buf)
|
||
return mod_buf
|
||
scan = n_end
|
||
stdlib.free(buf)
|
||
return None
|
||
|
||
|
||
def register_cexport_func(self, sha1: str, func_name: str) -> int:
|
||
"""注册 CExport 函数到全局表(sha1+func_name 二元组)"""
|
||
if sha1 is None or func_name is None:
|
||
return 0
|
||
if self.CexportSha1Arr is None:
|
||
self.CexportSha1Arr = CompilerFactory.get_perm_pool().alloc(_CEXPORT_MAX * 17)
|
||
self.CexportFuncArr = CompilerFactory.get_perm_pool().alloc(_CEXPORT_MAX * 64)
|
||
if self.CexportSha1Arr is None or self.CexportFuncArr is None:
|
||
return 0
|
||
string.memset(self.CexportSha1Arr, 0, _CEXPORT_MAX * 17)
|
||
string.memset(self.CexportFuncArr, 0, _CEXPORT_MAX * 64)
|
||
if self.CexportCount < _CEXPORT_MAX:
|
||
idx: t.CSizeT = t.CSizeT(self.CexportCount) * 17
|
||
# 槽位定长 17/64 字节,strcpy 无界会越界写相邻槽(stdlib 堆区)
|
||
string.strncpy(self.CexportSha1Arr + idx, sha1, 16)
|
||
self.CexportSha1Arr[idx + 16] = '\0'
|
||
idx2: t.CSizeT = t.CSizeT(self.CexportCount) * 64
|
||
string.strncpy(self.CexportFuncArr + idx2, func_name, 63)
|
||
self.CexportFuncArr[idx2 + 63] = '\0'
|
||
self.CexportCount += 1
|
||
return 1
|
||
return 0
|
||
|
||
|
||
def is_cexport_func(self, sha1: str, func_name: str) -> int:
|
||
"""检查 (sha1, func_name) 是否是 CExport 函数"""
|
||
if sha1 is None or func_name is None:
|
||
return 0
|
||
if self.CexportSha1Arr is None:
|
||
return 0
|
||
for i in range(self.CexportCount):
|
||
idx: t.CSizeT = t.CSizeT(i) * 17
|
||
if string.strcmp(self.CexportSha1Arr + idx, sha1) == 0:
|
||
idx2: t.CSizeT = t.CSizeT(i) * 64
|
||
if string.strcmp(self.CexportFuncArr + idx2, func_name) == 0:
|
||
return 1
|
||
return 0
|
||
|
||
|
||
def _is_state_func_from_vpi(self, pool: memhub.MemBuddy | t.CPtr,
|
||
sha1: str, func_name: str) -> int:
|
||
"""vpi 返回注解含 t.State → 外部 C 函数(定义端用裸名,跨模块调用无 sha1 头)
|
||
|
||
t.State(同 t.CExtern/t.CExport)是外部函数标记:定义端生成裸名
|
||
@PyList_Size(链接外部库 libpython),跨模块调用若生成 @{sha1}.PyList_Size
|
||
→ ld.lld undefined symbol(CPythonTest PyList_Size 根因)。CExport 走
|
||
is_cexport_func 注册表,State 函数未注册 → 按需解析 vpi 返回注解判断。
|
||
"""
|
||
if pool is None or sha1 is None or func_name is None:
|
||
return 0
|
||
import lib.StubGen.VpiReader as VpiReader
|
||
if self.TempDir is not None and self.TempDirLen > 0:
|
||
VpiReader._ensure_vpi_ret_annot_loaded(sha1, self.TempDir)
|
||
state_annot: str = VpiReader._lookup_vpi_ret_annot(sha1, None, func_name)
|
||
if state_annot is None:
|
||
return 0
|
||
# 返回注解含 "State"(如 "t.CSizeT | t.State")→ 外部 C 函数
|
||
if string.strstr(state_annot, "State") is not None:
|
||
return 1
|
||
return 0
|
||
|
||
|
||
def _lookup_mod_sha1(self, pool: memhub.MemBuddy | t.CPtr,
|
||
from_imports: str, class_name: str,
|
||
allow_star_fallback: int = 1) -> str:
|
||
"""从 from_imports 查找类所属模块的 SHA1,返回 None=未找到
|
||
|
||
allow_star_fallback: 传 0 禁用 star import 回退(用于明确模块名/函数名查找)
|
||
"""
|
||
mod_name_raw: str = HandlesImports.lookup_from_import(
|
||
from_imports, class_name, allow_star_fallback)
|
||
if mod_name_raw is None:
|
||
return None
|
||
return self._lookup_sha1_from_modname_raw(pool, mod_name_raw)
|
||
|
||
|
||
def _lookup_sha1_from_modname_raw(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod_name_raw: str) -> str:
|
||
"""从原始模块名查找 SHA1,返回 None=未找到"""
|
||
# 手动找到模块名结束位置(空格、null、或 ':' 别名分隔符),复制到新缓冲区
|
||
mod_len: t.CSizeT = 0
|
||
while mod_name_raw[mod_len] != ' ' and mod_name_raw[mod_len] != '\0' and mod_name_raw[mod_len] != ':':
|
||
mod_len += 1
|
||
mod_name_buf: str = pool.alloc(mod_len + 1)
|
||
if mod_name_buf is None:
|
||
return None
|
||
for mi in range(mod_len):
|
||
mod_name_buf[mi] = mod_name_raw[mi]
|
||
mod_name_buf[mod_len] = '\0'
|
||
# 去掉相对导入的前导点
|
||
base_mod: str = mod_name_buf
|
||
while base_mod[0] == '.':
|
||
base_mod = base_mod + 1
|
||
sha1: str = self._lookup_module_sha1(base_mod)
|
||
if sha1 is None:
|
||
sha1 = self._lookup_module_sha1_suffix(base_mod)
|
||
return sha1
|
||
|
||
|
||
def find_func_in_module(self, mod: llvmlite.LLVMModule | t.CPtr,
|
||
name: str) -> llvmlite.Function | t.CPtr:
|
||
"""在模块的函数链表中按名称查找函数
|
||
|
||
查找策略:
|
||
1. 精确匹配(如 "strlen" 匹配 @strlen,有 t.CExport 的函数)
|
||
2. 后缀匹配(如 "atoi" 匹配 @"83210a72e829a086.atoi",无 t.CExport 的函数)
|
||
|
||
使用 llvmlite.function_get_name/next 访问器绕过 stub 类型限制
|
||
(stub 类型字段不足且字段类型可能错误,直接字段访问会被静默跳过)。
|
||
"""
|
||
if mod is None or name is None:
|
||
return None
|
||
name_len: t.CSizeT = string.strlen(name)
|
||
cur: llvmlite.Function | t.CPtr = mod.FuncHead
|
||
# 第一遍:精确匹配
|
||
while cur is not None:
|
||
cur_name: str = llvmlite.function_get_name(cur)
|
||
if cur_name is not None:
|
||
if string.strcmp(cur_name, name) == 0:
|
||
return cur
|
||
cur = llvmlite.function_get_next(cur)
|
||
# 第二遍:后缀匹配(.name)
|
||
# 不跳过 declare:方法 stub 也是 declare,需要通过后缀匹配找到
|
||
# 调用处(translate_call 等)负责判断 IsDeclared 并决定使用裸名还是 sha1 前缀名
|
||
#
|
||
# 修复:本模块 define 优先于跨模块 stub declare。
|
||
# 根因:跨模块同名函数(如 lexer.vp 的 _advance 与 parser.vp 的 _advance)
|
||
# 的 stub declare 在 stub 注入时排在 FuncHead 前面,裸名调用 _advance 后缀
|
||
# 匹配按链表顺序先命中跨模块 declare → 参数按 Lexer* coerce → Parser* 被
|
||
# bitcast 成 Lexer* → lexer 版 _advance 按 Lexer 布局操作 Parser 指针,
|
||
# cur 永不推进 → parse 无限循环。本模块同名 define 必须优先。
|
||
cur = mod.FuncHead
|
||
while cur is not None:
|
||
cur_name2: str = llvmlite.function_get_name(cur)
|
||
if cur_name2 is not None:
|
||
cur_len: t.CSizeT = string.strlen(cur_name2)
|
||
if cur_len > name_len + 1:
|
||
suffix_start: t.CSizeT = cur_len - name_len
|
||
if cur_name2[suffix_start - 1] == '.':
|
||
match: int = 1
|
||
for i in range(name_len):
|
||
if cur_name2[suffix_start + i] != name[i]:
|
||
match = 0
|
||
break
|
||
if match == 1:
|
||
if cur.IsDeclared == 0:
|
||
return cur
|
||
cur = llvmlite.function_get_next(cur)
|
||
# 本模块无同名 define:回退到 stub declare(跨模块方法/函数调用)
|
||
cur = mod.FuncHead
|
||
while cur is not None:
|
||
cur_name3: str = llvmlite.function_get_name(cur)
|
||
if cur_name3 is not None:
|
||
cur_len3: t.CSizeT = string.strlen(cur_name3)
|
||
if cur_len3 > name_len + 1:
|
||
suffix_start3: t.CSizeT = cur_len3 - name_len
|
||
if cur_name3[suffix_start3 - 1] == '.':
|
||
match3: int = 1
|
||
for i in range(name_len):
|
||
if cur_name3[suffix_start3 + i] != name[i]:
|
||
match3 = 0
|
||
break
|
||
if match3 == 1:
|
||
return cur
|
||
cur = llvmlite.function_get_next(cur)
|
||
return None
|
||
|
||
|
||
# ============================================================
|
||
# _ensure_method_declare - 为跨模块方法调用创建 declare 声明
|
||
#
|
||
# 当 found_func 为 None(stub 未注入或跨模块调用)时,
|
||
# 在当前模块中创建函数声明,避免 llc 报 undefined value。
|
||
# ============================================================
|
||
def _ensure_method_declare(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
call_name: str,
|
||
ret_ty: llvmlite.LLVMType | t.CPtr,
|
||
param_head: llvmlite.ParamNode | t.CPtr,
|
||
param_count: int):
|
||
"""为跨模块方法调用创建 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)
|
||
existing: llvmlite.Function | t.CPtr = mod.FuncHead
|
||
while existing is not None:
|
||
if existing.Name is not None:
|
||
if string.strcmp(existing.Name, call_name) == 0:
|
||
# 已存在:仅当是 declare 且参数数量不足时追加缺失参数
|
||
if existing.IsDeclared == 1:
|
||
# 变长函数(*args,IsVarArg=1)不追加参数:多余实参由
|
||
# 变参机制(...)承接,追加有类型参数会导致调用侧把变参
|
||
# 强转为追加的类型(如 i8 → i64),%d/%x 等格式读错。
|
||
if existing.IsVarArg == 1:
|
||
return
|
||
# 遍历现有参数链表计数(避免依赖 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)
|
||
if func is None:
|
||
return
|
||
func.IsDeclared = 1
|
||
# 添加参数(declare 中参数名无意义,设为 None 只输出类型)
|
||
pnode: llvmlite.ParamNode | t.CPtr = param_head
|
||
pi: int = 0
|
||
while pnode is not None and pi < param_count:
|
||
if pnode.Ty is not None:
|
||
param: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode.Ty, None)
|
||
if param is not None:
|
||
llvmlite.function_add_param(func, param)
|
||
pnode = pnode.Next
|
||
pi += 1
|
||
llvmlite.module_add_function(mod, func)
|
||
|
||
# ============================================================
|
||
# _lookup_method_ret_ty_via_vpi - 从 vpi stub 返回注解缓存精确获取方法返回类型
|
||
#
|
||
# 方法定义处(.vpi stub)的返回注解(如 json.JsonValue._pool_alloc →
|
||
# "str")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。
|
||
# 此函数按 模块SHA1 + 类名 + 方法名 查缓存并纯字符串解析为 LLVMType。
|
||
# 无需硬编码白名单——返回类型始终来自方法定义处。
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# _lookup_method_ret_ty_via_vpi - 从 vpi stub 返回注解缓存精确获取方法返回类型
|
||
#
|
||
# 方法定义处(.vpi stub)的返回注解(如 json.JsonValue._pool_alloc →
|
||
# "str")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。
|
||
# 此函数按 模块SHA1 + 类名 + 方法名 查缓存并纯字符串解析为 LLVMType。
|
||
# 无需硬编码白名单——返回类型始终来自方法定义处。
|
||
# ============================================================
|
||
def _lookup_method_ret_ty_via_vpi(self, pool: memhub.MemBuddy | t.CPtr,
|
||
cls_sha1: str,
|
||
cls_name: str,
|
||
method_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||
"""从 vpi stub 返回注解缓存获取方法返回类型,未命中返回 None"""
|
||
if pool is None or cls_sha1 is None or method_name is None:
|
||
return None
|
||
# 函数内懒 import:VpiReader imports HandlesExprCall,顶层 import 会成环
|
||
import lib.StubGen.VpiReader as VpiReader
|
||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
# 按需加载:缓存未命中时直接读 {temp_dir}/{sha1[0:2]}/{sha1}.vpi
|
||
# 覆盖"模块自身翻译时 stub 尚未注入"(同模块方法调用,定义在后)的场景
|
||
if self.TempDir is not None and self.TempDirLen > 0:
|
||
VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, self.TempDir)
|
||
annot: str = VpiReader._lookup_vpi_ret_annot(cls_sha1, cls_name, method_name)
|
||
if annot is None:
|
||
return None
|
||
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。
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# _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(self, 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
|
||
#
|
||
# 返回类型来源(按序):当前模块函数 → text.ll define → vpi stub 返回注解缓存。
|
||
# 全部未命中时立即 ERROR + 错误堆栈终止,绝不按名推断白名单/静默默认 i32。
|
||
#
|
||
# node: 调用点 AST 节点(可选,用于 ERROR 堆栈定位)
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# _fail_method_ret_ty - 方法返回类型无法精确获取时 fail-fast
|
||
#
|
||
# 返回类型来源(按序):当前模块函数 → text.ll define → vpi stub 返回注解缓存。
|
||
# 全部未命中时立即 ERROR + 错误堆栈终止,绝不按名推断白名单/静默默认 i32。
|
||
#
|
||
# node: 调用点 AST 节点(可选,用于 ERROR 堆栈定位)
|
||
# ============================================================
|
||
def _fail_method_ret_ty(self, method_name: str,
|
||
node: ast.AST | t.CPtr = None) -> llvmlite.LLVMType | t.CPtr:
|
||
"""方法返回类型无法精确获取时 fail-fast(ERROR + 错误堆栈)
|
||
|
||
返回类型来源(按序):当前模块函数 → text.ll define → vpi stub 返回注解缓存。
|
||
全部未命中说明方法定义缺失或 stub 损坏,立即终止暴露,绝不静默默认 i32。
|
||
"""
|
||
VLogger.error(
|
||
f"方法返回类型无法精确获取(函数/text.ll/vpi stub 均未命中): {method_name}",
|
||
"HandlesExprCall")
|
||
HandlesType.fatal_error(
|
||
node,
|
||
f"方法返回类型无法精确获取,默认 i32 会截断指针/i64: {method_name}",
|
||
"TypeError")
|
||
return None
|
||
|
||
# ============================================================
|
||
# SetTempDir - 设置 temp 目录路径
|
||
#
|
||
# 在 Phase2.py 的 Phase A 翻译前调用,使 CallGenMixin
|
||
# 能够读取依赖模块的 text.ll 文件。
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# SetTempDir - 设置 temp 目录路径
|
||
#
|
||
# 在 Phase2.py 的 Phase A 翻译前调用,使 CallGenMixin
|
||
# 能够读取依赖模块的 text.ll 文件。
|
||
# ============================================================
|
||
def SetTempDir(self, temp_dir: str):
|
||
"""设置 temp 目录路径(供跨模块方法返回类型查找使用)"""
|
||
self.TempDir = temp_dir
|
||
if temp_dir is not None:
|
||
self.TempDirLen = string.strlen(temp_dir)
|
||
else:
|
||
self.TempDirLen = 0
|
||
|
||
# ============================================================
|
||
# _ParseLLVMRetTyStr - 将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType
|
||
#
|
||
# 从 define 行中提取的返回类型字符串(define 与 @ 之间的内容),
|
||
# 转换为 llvmlite.LLVMType 对象。
|
||
#
|
||
# 支持的类型:
|
||
# void → Void
|
||
# i8/i16/i32/i64 → Int8/Int16/Int32/Int64
|
||
# double → Double, float → Float
|
||
# 任何含 * 的类型 → Ptr(Int8)(通用指针,保留 64 位地址)
|
||
#
|
||
# Args:
|
||
# pool: 内存池
|
||
# buf: 包含类型字符串的缓冲区
|
||
# start: 类型字符串起始位置
|
||
# end: 类型字符串结束位置(不含)
|
||
#
|
||
# Returns:
|
||
# LLVM 类型对象,或 None(无法解析)
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# _ParseLLVMRetTyStr - 将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType
|
||
#
|
||
# 从 define 行中提取的返回类型字符串(define 与 @ 之间的内容),
|
||
# 转换为 llvmlite.LLVMType 对象。
|
||
#
|
||
# 支持的类型:
|
||
# void → Void
|
||
# i8/i16/i32/i64 → Int8/Int16/Int32/Int64
|
||
# double → Double, float → Float
|
||
# 任何含 * 的类型 → Ptr(Int8)(通用指针,保留 64 位地址)
|
||
#
|
||
# Args:
|
||
# pool: 内存池
|
||
# buf: 包含类型字符串的缓冲区
|
||
# start: 类型字符串起始位置
|
||
# end: 类型字符串结束位置(不含)
|
||
#
|
||
# Returns:
|
||
# LLVM 类型对象,或 None(无法解析)
|
||
# ============================================================
|
||
def _ParseLLVMRetTyStr(self, pool: memhub.MemBuddy | t.CPtr,
|
||
buf: bytes,
|
||
start: t.CSizeT,
|
||
end: t.CSizeT) -> llvmlite.LLVMType | t.CPtr:
|
||
"""将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType"""
|
||
if pool is None or buf is None or start >= end:
|
||
return None
|
||
|
||
# 去除前导空白
|
||
s: t.CSizeT = start
|
||
while s < end:
|
||
c: int = buf[s]
|
||
if c != ' ' and c != '\t':
|
||
break
|
||
s += 1
|
||
# 去除尾部空白
|
||
e: t.CSizeT = end
|
||
while e > s:
|
||
c2: int = buf[e - 1]
|
||
if c2 != ' ' and c2 != '\t':
|
||
break
|
||
e -= 1
|
||
|
||
ty_len: t.CSizeT = e - s
|
||
if ty_len == 0:
|
||
return None
|
||
|
||
# struct 字面量 {T1, T2, ...}(tuple 打包返回类型,如 b2a_hqx ->
|
||
# tuple[str, t.CUnsignedShort] 编译为 {i8*, i16})。必须在 * 检查
|
||
# 之前——否则 "{i8*, i16}" 内含 * 会被误判为 i8*(b2a_hqx 调用侧
|
||
# 返回类型退化 i8* → HandlesAssign tuple 解包静默跳过 → free 未初始化
|
||
# 指针崩溃,HashLibTest hqx 段)。
|
||
if s < e and buf[s] == '{':
|
||
th_st: llvmlite.ParamNode | t.CPtr = None
|
||
tt_st: llvmlite.ParamNode | t.CPtr = None
|
||
tc_st: int = 0
|
||
ps_st: t.CSizeT = s + 1
|
||
while ps_st < e and buf[ps_st] != '}':
|
||
while ps_st < e and (buf[ps_st] == ' ' or buf[ps_st] == ','):
|
||
ps_st += 1
|
||
if ps_st >= e or buf[ps_st] == '}':
|
||
break
|
||
es_st: t.CSizeT = ps_st
|
||
while ps_st < e and buf[ps_st] != ',' and buf[ps_st] != '}':
|
||
ps_st += 1
|
||
ee_st: t.CSizeT = ps_st
|
||
if ee_st > es_st:
|
||
et_st: llvmlite.LLVMType | t.CPtr = self._ParseLLVMRetTyStr(
|
||
pool, buf, es_st, ee_st)
|
||
if et_st is None:
|
||
return None
|
||
en_st: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(
|
||
pool, et_st)
|
||
if en_st is None:
|
||
return None
|
||
if th_st is None:
|
||
th_st = en_st
|
||
else:
|
||
llvmlite.paramnode_set_next(tt_st, en_st)
|
||
tt_st = en_st
|
||
tc_st += 1
|
||
if th_st is None or tc_st == 0:
|
||
return None
|
||
st_ty_st: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, th_st, tc_st, None)
|
||
# 指针到 struct({i32, i8}*):返回 Ptr(Struct);纯 tuple 打包
|
||
# ({i8*, i16})无尾部 *,返回 Struct 本身。
|
||
if ps_st < e and buf[ps_st] == '*':
|
||
return llvmlite.Ptr(pool, st_ty_st)
|
||
return st_ty_st
|
||
|
||
# 检查是否含 * (指针类型) → 返回 i8* (通用指针)
|
||
# 包括 i8*, i32*, %"name"*, { i32, i8 }* 等
|
||
ci: t.CSizeT = s
|
||
while ci < e:
|
||
if buf[ci] == '*':
|
||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
ci += 1
|
||
|
||
# void
|
||
if ty_len == 4 and string.strncmp(buf + s, "void", 4) == 0:
|
||
return llvmlite.Void(pool)
|
||
|
||
# double
|
||
if ty_len == 6 and string.strncmp(buf + s, "double", 6) == 0:
|
||
return llvmlite.Double(pool)
|
||
|
||
# float
|
||
if ty_len == 5 and string.strncmp(buf + s, "float", 5) == 0:
|
||
return llvmlite.Float(pool)
|
||
|
||
# iN (i8, i16, i32, i64)
|
||
if ty_len >= 2 and buf[s] == 'i':
|
||
bits: int = 0
|
||
di: t.CSizeT = s + 1
|
||
valid: int = 1
|
||
while di < e:
|
||
d: int = buf[di]
|
||
if d >= '0' and d <= '9':
|
||
bits = bits * 10 + (d - '0')
|
||
else:
|
||
valid = 0
|
||
break
|
||
di += 1
|
||
if valid != 0 and bits > 0:
|
||
if bits == 8:
|
||
return llvmlite.Int8(pool)
|
||
if bits == 16:
|
||
return llvmlite.Int16(pool)
|
||
if bits == 32:
|
||
return llvmlite.Int32(pool)
|
||
if bits == 64:
|
||
return llvmlite.Int64(pool)
|
||
|
||
# 无法解析
|
||
return None
|
||
|
||
# ============================================================
|
||
# _LookupMethodRetTyFromTextLL - 从依赖模块的 text.ll 查找方法返回类型
|
||
#
|
||
# 读取 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll (level=1),搜索
|
||
# define 行中包含 "{sha1}.{class_name}.{method_name}" 的函数,
|
||
# 提取返回类型并转换为 llvmlite.LLVMType。
|
||
#
|
||
# 解决问题: 旧实现 _infer_method_ret_ty(已移除)默认返回 i32,导致指针返回值
|
||
# 被 inttoptr 截断为 32 位(coerce_to_type line 238-239)。
|
||
# 本函数从 text.ll 获取实际返回类型,避免截断。
|
||
#
|
||
# Args:
|
||
# pool: 内存池
|
||
# class_sha1: 类所属模块的 SHA1
|
||
# class_name: 类名
|
||
# method_name: 方法名
|
||
#
|
||
# Returns:
|
||
# LLVM 类型对象,或 None(未找到/text.ll 不存在)
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# _LookupMethodRetTyFromTextLL - 从依赖模块的 text.ll 查找方法返回类型
|
||
#
|
||
# 读取 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll (level=1),搜索
|
||
# define 行中包含 "{sha1}.{class_name}.{method_name}" 的函数,
|
||
# 提取返回类型并转换为 llvmlite.LLVMType。
|
||
#
|
||
# 解决问题: 旧实现 _infer_method_ret_ty(已移除)默认返回 i32,导致指针返回值
|
||
# 被 inttoptr 截断为 32 位(coerce_to_type line 238-239)。
|
||
# 本函数从 text.ll 获取实际返回类型,避免截断。
|
||
#
|
||
# Args:
|
||
# pool: 内存池
|
||
# class_sha1: 类所属模块的 SHA1
|
||
# class_name: 类名
|
||
# method_name: 方法名
|
||
#
|
||
# Returns:
|
||
# LLVM 类型对象,或 None(未找到/text.ll 不存在)
|
||
# ============================================================
|
||
def _LookupMethodRetTyFromTextLL(self, pool: memhub.MemBuddy | t.CPtr,
|
||
class_sha1: str,
|
||
class_name: str,
|
||
method_name: str,
|
||
use_bare: int = 0) -> llvmlite.LLVMType | t.CPtr:
|
||
"""从依赖模块的 text.ll 中查找方法返回类型
|
||
|
||
use_bare: 1=按模块级函数查找(搜索 "{sha1}.{method_name}" define,
|
||
用于 new_lexer/tokenize 等模块函数;class_name 忽略)。
|
||
"""
|
||
if pool is None or class_sha1 is None or method_name is None:
|
||
return None
|
||
if self.TempDir is None or self.TempDirLen == 0:
|
||
return None
|
||
|
||
sha1_len: t.CSizeT = string.strlen(class_sha1)
|
||
if sha1_len < 2:
|
||
return None
|
||
|
||
# 构造 text.ll 路径 (level=1): {temp_dir}/{sha1[0:2]}/{sha1}.text.ll
|
||
# 使用 subdir 缓冲区避免 %c 格式化问题(与 StubMerger._sliced_path 一致)
|
||
path_len: t.CSizeT = self.TempDirLen + sha1_len + 14
|
||
path_buf: bytes = stdlib.malloc(path_len)
|
||
if path_buf is None:
|
||
return None
|
||
subdir_buf: bytes = stdlib.malloc(3)
|
||
if subdir_buf is None:
|
||
stdlib.free(path_buf)
|
||
return None
|
||
subdir_buf[0] = class_sha1[0]
|
||
subdir_buf[1] = class_sha1[1]
|
||
subdir_buf[2] = '\0'
|
||
viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll",
|
||
self.TempDir, subdir_buf, class_sha1)
|
||
stdlib.free(subdir_buf)
|
||
|
||
# 读取 text.ll(按文件实际大小分配:固定 _TEXT_LL_READ_BUF_SIZE(256KB)
|
||
# 会截断大模块的 text.ll,末尾方法定义查不到 → 误报"方法返回类型无法
|
||
# 精确获取"(追加80b 根因,同追加74 _read_source_line 截断)。64MB 上限
|
||
# 防御异常超大文件整体读取。)
|
||
tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R)
|
||
if tf.closed:
|
||
stdlib.free(path_buf)
|
||
return None
|
||
tfsize: LONGLONG = tf.size()
|
||
if tfsize <= 0 or tfsize > 67108864:
|
||
tf.close()
|
||
stdlib.free(path_buf)
|
||
return None
|
||
read_size: t.CSizeT = t.CSizeT(tfsize)
|
||
read_buf: bytes = stdlib.malloc(read_size + 1)
|
||
if read_buf is None:
|
||
tf.close()
|
||
stdlib.free(path_buf)
|
||
return None
|
||
text_len: t.CInt64T = tf.read_all(read_buf, ULONG(read_size + 1))
|
||
tf.close()
|
||
stdlib.free(path_buf)
|
||
|
||
if text_len <= 0:
|
||
stdlib.free(read_buf)
|
||
return None
|
||
read_buf[text_len] = '\0'
|
||
|
||
# 构造搜索模式: "{sha1}.{class_name}.{method_name}" 或 bare 模式 "{sha1}.{method_name}"
|
||
cls_len: t.CSizeT = 0
|
||
if class_name is not None:
|
||
cls_len = string.strlen(class_name)
|
||
meth_len: t.CSizeT = string.strlen(method_name)
|
||
search_len: t.CSizeT = sha1_len + meth_len + 2
|
||
if use_bare == 0:
|
||
search_len = sha1_len + cls_len + meth_len + 4
|
||
search_buf: bytes = stdlib.malloc(search_len)
|
||
if search_buf is None:
|
||
stdlib.free(read_buf)
|
||
return None
|
||
if use_bare != 0:
|
||
viperlib.snprintf(search_buf, search_len, "%s.%s",
|
||
class_sha1, method_name)
|
||
else:
|
||
viperlib.snprintf(search_buf, search_len, "%s.%s.%s",
|
||
class_sha1, class_name, method_name)
|
||
search_str_len: t.CSizeT = string.strlen(search_buf)
|
||
|
||
# 在 text.ll 中搜索 define 行包含 search_buf
|
||
buf_len: t.CSizeT = string.strlen(read_buf)
|
||
pos: t.CSizeT = 0
|
||
result_ty: llvmlite.LLVMType | t.CPtr = None
|
||
|
||
while pos < buf_len and result_ty is None:
|
||
ls: t.CSizeT = pos
|
||
le: t.CSizeT = pos
|
||
while le < buf_len:
|
||
if read_buf[le] == '\n':
|
||
break
|
||
le += 1
|
||
ll: t.CSizeT = le - ls
|
||
|
||
# 检查是否是 define 行
|
||
if ll >= 7 and string.strncmp(read_buf + ls, "define ", 7) == 0:
|
||
# 找 @ 符号
|
||
at_pos: t.CSizeT = ls + 7
|
||
while at_pos < ls + ll:
|
||
if read_buf[at_pos] == '@':
|
||
break
|
||
at_pos += 1
|
||
if at_pos < ls + ll:
|
||
# 跳过可选引号
|
||
name_start: t.CSizeT = at_pos + 1
|
||
if name_start < ls + ll and read_buf[name_start] == '"':
|
||
name_start += 1
|
||
# 检查是否匹配 search_buf
|
||
if name_start + search_str_len <= ls + ll:
|
||
if string.strncmp(read_buf + name_start, search_buf, search_str_len) == 0:
|
||
# 函数名边界检查:search 后必须是 '"'(带引号名)、'('(参数表)或行尾,
|
||
# 否则 "sha1.func" 会误匹配 "sha1.func_helper" 等前缀同名函数
|
||
name_end: t.CSizeT = name_start + search_str_len
|
||
end_ch: int = 0
|
||
if name_end < ls + ll:
|
||
end_ch = read_buf[name_end]
|
||
if end_ch == 34 or end_ch == 40 or end_ch == 0:
|
||
# 匹配!提取返回类型: [ls+7, at_pos)
|
||
result_ty = self._ParseLLVMRetTyStr(pool, read_buf, ls + 7, at_pos)
|
||
|
||
pos = le + 1
|
||
|
||
stdlib.free(search_buf)
|
||
stdlib.free(read_buf)
|
||
return result_ty
|
||
|
||
# ============================================================
|
||
# _dep_text_ll_exists - 探测依赖模块 text.ll 是否已生成
|
||
#
|
||
# 用于区分跨模块返回类型精确解析失败的两种场景:
|
||
# 1. text.ll 存在但函数未命中 → 真错误(依赖已编译,函数缺失)
|
||
# 2. text.ll 不存在 → 依赖模块尚未翻译(Phase A 按文件顺序翻译,
|
||
# main.vp 先于其 import 的 mbuddytest.vp),标记重试待下遍
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# _dep_text_ll_exists - 探测依赖模块 text.ll 是否已生成
|
||
#
|
||
# 用于区分跨模块返回类型精确解析失败的两种场景:
|
||
# 1. text.ll 存在但函数未命中 → 真错误(依赖已编译,函数缺失)
|
||
# 2. text.ll 不存在 → 依赖模块尚未翻译(Phase A 按文件顺序翻译,
|
||
# main.vp 先于其 import 的 mbuddytest.vp),标记重试待下遍
|
||
# ============================================================
|
||
def _dep_text_ll_exists(self, pool: memhub.MemBuddy | t.CPtr,
|
||
sha1: str) -> int:
|
||
"""探测 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll 是否存在,1=存在"""
|
||
if self.TempDir is None or self.TempDirLen == 0 or sha1 is None:
|
||
return 0
|
||
sha1_len: t.CSizeT = string.strlen(sha1)
|
||
if sha1_len < 2:
|
||
return 0
|
||
path_len: t.CSizeT = self.TempDirLen + sha1_len + 14
|
||
path_buf: bytes = stdlib.malloc(path_len)
|
||
subdir_buf: bytes = stdlib.malloc(3)
|
||
if path_buf is None or subdir_buf is None:
|
||
if path_buf is not None:
|
||
stdlib.free(path_buf)
|
||
if subdir_buf is not None:
|
||
stdlib.free(subdir_buf)
|
||
return 0
|
||
subdir_buf[0] = sha1[0]
|
||
subdir_buf[1] = sha1[1]
|
||
subdir_buf[2] = '\0'
|
||
viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll",
|
||
self.TempDir, subdir_buf, sha1)
|
||
stdlib.free(subdir_buf)
|
||
tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R)
|
||
exists: int = 0
|
||
if not tf.closed:
|
||
tf.close()
|
||
exists = 1
|
||
stdlib.free(path_buf)
|
||
return exists
|
||
|
||
# ============================================================
|
||
# 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助
|
||
#
|
||
# 元数据表由 HandlesClassDef 在类翻译/预注册阶段填充,
|
||
# 这里负责把 obj.prop / obj.prop=v / del obj.prop / Class.method()
|
||
# 翻译为对应的 {sha1}.ClassName.prop 系列函数调用。
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# _translate_property_call — 翻译属性方法调用
|
||
#
|
||
# 与 _translate_method_call 的调用名/返回类型解析逻辑一致:
|
||
# 1. 优先用模块中已有的函数(精确/后缀匹配,来自 stub 注入)
|
||
# 2. 否则用类所属模块的 SHA1 构造 "{sha1}.ClassName.method" 调用名
|
||
# 3. 返回类型:函数实类型 → text.ll 查找 → 按方法名推断(默认 i32)
|
||
#
|
||
# call_head/call_count: 已构建好的参数链表(如 getter 只有 obj 一个参数)
|
||
# ============================================================
|