- CallGenBase:字段声明处直接给默认值,InitCallGen 不再逐字段赋值 - CallGenFd/CallGenDispatch:@t.NoVTable 改 novirtual,清理过时注释 - VLogger:LogLevel 改 enum、t.CDefine 改 define 关键字、Logger|t.CPtr 改 Logger*、longjmp 用 rawptr - Generator:_g_gen 由 Generator|t.CPtr 改为 Generator* - CallGenProp:合并续行
296 lines
18 KiB
Plaintext
296 lines
18 KiB
Plaintext
import lib.core.Gen.GenTypes as GenTypes
|
||
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import viperlib
|
||
import lib.core.Gen.Translator as HT
|
||
import lib.core.Gen.GenApi as GenApi
|
||
|
||
from . import CallGenBase
|
||
|
||
|
||
# ============================================================
|
||
# CallGenFd - CallGenMixin 拆分(阶段 B):FakeDuck / requires 字段注入 / provider 栈
|
||
# ============================================================
|
||
novirtual class CallGenFd(CallGenBase.CallGenBase):
|
||
"""FakeDuck / requires 字段注入 / provider 栈"""
|
||
def _translate_fakeduck_call(self, pool: memhub.MemBuddy*,
|
||
builder: llvmlite.IRBuilder*,
|
||
mod: llvmlite.LLVMModule*,
|
||
cls_name: str,
|
||
method_name: str,
|
||
cl: ast.Call*,
|
||
trans: HT.Translator*) -> llvmlite.Value*:
|
||
"""FakeDuck: str 变量方法调用解析到扩展类 _Type/_str,返回 call 结果或 None"""
|
||
if pool is None or builder is None or cl is None or trans is None: return None
|
||
if method_name is None: return None
|
||
# 仅对 str 类型触发(AnnotClassName == "str",对象是 char*);
|
||
# cls_name 为 None(表达式接收者解析失败)时也尝试
|
||
if cls_name is not None and string.strcmp(cls_name, "str") != 0: return None
|
||
if cl.func is None or cl.func.kind() != ast.ASTKind.Attribute: return None
|
||
fd_at: ast.Attribute* = ast.Attribute*(cl.func)
|
||
if fd_at is None or fd_at.value is None or fd_at.attr is None: return None
|
||
if string.strcmp(fd_at.attr, method_name) != 0: return None
|
||
# 候选扩展类:先 _Type(a.type_id())后 _str(a.upper() 等)
|
||
fd_func: llvmlite.Function* = None
|
||
fd_cls: str = None
|
||
fd_key: str = pool.alloc(160)
|
||
if fd_key is not None:
|
||
for fd_ci in range(2):
|
||
fd_cn: str = "_Type"
|
||
if fd_ci == 1:
|
||
fd_cn = "_str"
|
||
viperlib.snprintf(fd_key, 160, "%s.%s", fd_cn, method_name)
|
||
fd_func = self.find_func_in_module(mod, fd_key)
|
||
if fd_func is not None:
|
||
fd_cls = fd_cn
|
||
break
|
||
if fd_func is None or fd_cls is None: return None
|
||
# 扩展类结构体必须已注册(GEP/临时影子需要类型)
|
||
fd_sty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type(fd_cls)
|
||
if fd_sty is None: return None
|
||
# 扩展类字段数:有字段(_str)时 self 用影子结构体指针;
|
||
# 无字段(_Type)时 self 用对象值 bitcast 到扩展类指针(对齐 TPC L2856-2876)
|
||
fd_entry_fd: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_type(fd_sty)
|
||
fd_has_fields: int = 0
|
||
if fd_entry_fd is not None and fd_entry_fd.FieldCount > 0:
|
||
fd_has_fields = 1
|
||
# self 参数:优先使用已有影子 {var}__meta__(fd2 创建,仅当扩展类有字段时)
|
||
fd_self: llvmlite.Value* = None
|
||
if fd_at.value.kind() == ast.ASTKind.Name:
|
||
fd_onm: ast.Name* = ast.Name*(fd_at.value)
|
||
if fd_onm.id is not None:
|
||
# pool 持久缓冲(f-string 栈缓冲在函数返回后失效)
|
||
fd_mn: str = pool.alloc(256)
|
||
if fd_mn is not None:
|
||
viperlib.snprintf(fd_mn, 256, "%s__meta__", fd_onm.id)
|
||
fd_meta: llvmlite.Value* = self.Gen.VarGen.lookup_current(trans.SymTab, fd_mn)
|
||
if fd_meta is not None and fd_has_fields != 0:
|
||
fd_self = fd_meta
|
||
if fd_self is None:
|
||
if fd_has_fields != 0:
|
||
# 有字段扩展类且无影子(字符串字面量等):入口创建临时影子并初始化
|
||
# 先确保 _str 完整定义(跨模块结构体默认 opaque,alloca 报 unsized)
|
||
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, fd_sty)
|
||
fd_self = self.Gen.VarGen._alloca_at_entry(builder, fd_sty)
|
||
if fd_self is None: return None
|
||
fd_obj_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, fd_at.value, None, 0, trans)
|
||
if fd_obj_val is not None:
|
||
fd_dfe: GenTypes.FieldEntry* = self.Gen.StructGen.lookup_field(fd_sty, "__data__")
|
||
if fd_dfe is not None and fd_dfe.Ty is not None:
|
||
fd_dp: llvmlite.Value* = llvmlite.build_gep_struct(builder, fd_sty, fd_dfe.Ty, fd_self, fd_dfe.Index)
|
||
if fd_dp is not None:
|
||
llvmlite.build_store(builder, fd_obj_val, fd_dp)
|
||
fd_bfe: GenTypes.FieldEntry* = self.Gen.StructGen.lookup_field(fd_sty, "__mbuddy__")
|
||
if fd_bfe is not None and fd_bfe.Ty is not None:
|
||
fd_bp: llvmlite.Value* = llvmlite.build_gep_struct(builder, fd_sty, fd_bfe.Ty, fd_self, fd_bfe.Index)
|
||
fd_null: llvmlite.Value* = llvmlite.ConstNull(pool, fd_bfe.Ty, "null")
|
||
if fd_bp is not None and fd_null is not None:
|
||
llvmlite.build_store(builder, fd_null, fd_bp)
|
||
# FakeDuck: with 上下文自动注入 requires 字段(如 __mbuddy__)
|
||
self._inject_requires_fields(trans, pool, builder, mod, fd_self, fd_cls)
|
||
else:
|
||
# 无字段扩展类(_Type):对象值 bitcast 到扩展类指针
|
||
fd_obj_v: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, fd_at.value, None, 0, trans)
|
||
if fd_obj_v is None: return None
|
||
fd_self = llvmlite.build_bitcast(builder, fd_obj_v, llvmlite.Ptr(pool, fd_sty))
|
||
if fd_self is None: return None
|
||
# 构建参数链表: self → 其余参数
|
||
llvmlite.value_set_next(fd_self, None)
|
||
fd_head: llvmlite.Value* = fd_self
|
||
fd_tail: llvmlite.Value* = fd_self
|
||
fd_args: list[ast.AST*]* = cl.args
|
||
fd_can: int = 0
|
||
if fd_args is not None:
|
||
fd_can = len(fd_args)
|
||
for fd_ai in range(fd_can):
|
||
fd_arg: ast.AST* = fd_args.get(fd_ai)
|
||
if fd_arg is not None:
|
||
fd_av: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, fd_arg, None, 0, trans)
|
||
# char 常量参数 → 单字符字符串(char 隐式转 str,
|
||
# 如 s1.split(','):',' 是 i32 值 44,传给 str 参数须先字符串化,
|
||
# 否则运行时 strlen/strncmp 解引用 44 崩溃)
|
||
if fd_arg.kind() == ast.ASTKind.Constant:
|
||
fd_ac: ast.Constant* = ast.Constant*(fd_arg)
|
||
if fd_ac.const_kind == ast.CONST_CHAR:
|
||
ch_buf: str = pool.alloc(2)
|
||
if ch_buf is not None:
|
||
ch_buf[0] = char(fd_ac.int_val)
|
||
ch_buf[1] = '\0'
|
||
fd_av = self.Gen.ExprGenConst.create_global_string(builder, pool, mod, ch_buf, trans)
|
||
if fd_av is not None:
|
||
llvmlite.value_set_next(fd_av, None)
|
||
llvmlite.value_set_next(fd_tail, fd_av)
|
||
fd_tail = fd_av
|
||
# 返回类型与调用名(来自 find_func_in_module 命中的函数定义)
|
||
fd_ret_ty: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(fd_func)
|
||
if fd_ret_ty is None:
|
||
fd_ret_ty = llvmlite.Int32(pool)
|
||
fd_fname: str = llvmlite.function_get_name(fd_func)
|
||
if fd_fname is None: return None
|
||
# 返回类型精确化:跨模块 declare 的 list[T] 特化返回类型可能被简化为 Ptr(i8),调用方变量 alloca 类型随之退化 → parts[0] 走字符下标路径而非 list 内联 __getitem__(printf %s 崩溃)。从定义模块 text.ll 读取精确返回类型;仅当函数名确为 "{16hex}.{func}"(判定走唯一真源 GenApi.sha1_prefix_len)才提取模块 sha1
|
||
if GenApi.sha1_prefix_len(fd_fname) != 0:
|
||
fd_sha1: str = pool.alloc(17)
|
||
if fd_sha1 is not None:
|
||
string.strncpy(fd_sha1, fd_fname, 16)
|
||
fd_sha1[16] = '\0'
|
||
fd_exact: llvmlite.LLVMType* = self._LookupMethodRetTyFromTextLL(pool, fd_sha1, fd_cls, method_name)
|
||
if fd_exact is not None:
|
||
fd_ret_ty = fd_exact
|
||
fd_total: int = 1 + fd_can
|
||
return llvmlite.build_call(builder, fd_fname, fd_head, fd_total, fd_ret_ty, 0)
|
||
# ============================================================
|
||
# _inject_requires_fields - FakeDuck: with 上下文注入 requires 字段
|
||
#
|
||
# 对齐 TPC HandlesExprCall.py L4021-4079:
|
||
# 对类 __requires__ 元数据(fd1 注册)中的每个字段,运行时调用
|
||
# _find_provider(field) 查找 with 上下文提供的指针;非 NULL 时
|
||
# bitcast 到字段类型写入 meta_ptr 对应槽位(条件注入,避免覆盖
|
||
# 用户已手动设置的值)。_find_provider 未注册(未 import
|
||
# _withcontent)时跳过注入,不影响非 with 场景。
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _inject_requires_fields(self, trans: HT.Translator*,
|
||
pool: memhub.MemBuddy*,
|
||
builder: llvmlite.IRBuilder*,
|
||
mod: llvmlite.LLVMModule*,
|
||
meta_ptr: llvmlite.Value*,
|
||
class_name: str) -> int:
|
||
"""在 with 上下文注入 requires 字段,返回注入字段数"""
|
||
if trans is None or pool is None or builder is None or mod is None:
|
||
return 0
|
||
if meta_ptr is None or class_name is None:
|
||
return 0
|
||
# _withcontent._find_provider(跨模块):仅当本模块可见(_withcontent
|
||
# 被 import,vpi stub declare 已注入)时才注入。对齐 TPC L4048-4050
|
||
# (Gen.functions.get('_find_provider') 不存在则跳过)——否则非 with
|
||
# 项目(如 HashTableTest 未 import _withcontent)也会为每个 _str(...)
|
||
# 构造发射 {sha1}._find_provider 调用 → ld.lld undefined symbol。
|
||
fd_fn_probe: llvmlite.Function* = self.find_func_in_module(mod, "_find_provider")
|
||
if fd_fn_probe is None: return 0
|
||
fd_fname: str = llvmlite.function_get_name(fd_fn_probe)
|
||
if fd_fname is None: return 0
|
||
cnt: int = self.Gen.ClassGenBase.class_meta_count(GenTypes.CLASS_META_REQUIRES, class_name)
|
||
if cnt <= 0: return 0
|
||
sty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type(class_name)
|
||
if sty is None: return 0
|
||
i8_ty_j: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
if i8_ty_j is None: return 0
|
||
i8_ptr_ty_j: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty_j)
|
||
if i8_ptr_ty_j is None: return 0
|
||
cur_func: llvmlite.Function* = trans._cur_func
|
||
if cur_func is None: return 0
|
||
injected: int = 0
|
||
for ji in range(cnt):
|
||
fname: str = self.Gen.ClassGenBase.class_meta_field_at(GenTypes.CLASS_META_REQUIRES, class_name, ji)
|
||
if fname is None: continue
|
||
fe: GenTypes.FieldEntry* = self.Gen.StructGen.lookup_field(sty, fname)
|
||
if fe is None or fe.Ty is None: continue
|
||
# 参数:字段名字符串(i8*)
|
||
fd_fstr: llvmlite.Value* = self.Gen.ExprGenConst.create_global_string(builder, pool, mod, fname, trans)
|
||
if fd_fstr is None: continue
|
||
llvmlite.value_set_next(fd_fstr, None)
|
||
self._ensure_method_declare(pool, mod, fd_fname, i8_ptr_ty_j, fd_fstr, 1)
|
||
fd_ptr: llvmlite.Value* = llvmlite.build_call(builder, fd_fname, fd_fstr, 1, i8_ptr_ty_j, 0)
|
||
if fd_ptr is None: continue
|
||
# 条件注入:ptr != NULL 才写入(保留用户手动设置的值)
|
||
fd_null: llvmlite.Value* = llvmlite.ConstNull(pool, i8_ptr_ty_j, "null")
|
||
if fd_null is None: continue
|
||
fd_cmp: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, fd_ptr, fd_null)
|
||
if fd_cmp is None: continue
|
||
# 块名唯一化(create_block 不自动编号,同名 label 在文本 IR 中
|
||
# 冲突 → llc "Terminator found in the middle of a basic block")
|
||
vtc2: int = trans._label_counter
|
||
trans._label_counter = vtc2 + 1
|
||
fd_bb_buf2: str = pool.alloc(64)
|
||
if fd_bb_buf2 is None: continue
|
||
viperlib.snprintf(fd_bb_buf2, 64, "fd.skip.%d", vtc2)
|
||
fd_skip_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, cur_func, fd_bb_buf2)
|
||
viperlib.snprintf(fd_bb_buf2, 64, "fd.inject.%d", vtc2)
|
||
fd_inject_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, cur_func, fd_bb_buf2)
|
||
if fd_skip_bb is None or fd_inject_bb is None: continue
|
||
llvmlite.build_cond_br(builder, fd_cmp, fd_inject_bb, fd_skip_bb)
|
||
# inject 块:bitcast + GEP + store,跳回 skip
|
||
llvmlite.position_at_end(builder, fd_inject_bb)
|
||
fd_cast: llvmlite.Value* = llvmlite.build_bitcast(builder, fd_ptr, fe.Ty)
|
||
if fd_cast is not None:
|
||
fd_fp: llvmlite.Value* = llvmlite.build_gep_struct(builder, sty, fe.Ty, meta_ptr, fe.Index)
|
||
if fd_fp is not None: llvmlite.build_store(builder, fd_cast, fd_fp)
|
||
llvmlite.build_br(builder, fd_skip_bb)
|
||
# skip 块:恢复 CurBlock,继续后续代码生成
|
||
llvmlite.position_at_end(builder, fd_skip_bb)
|
||
injected += 1
|
||
return injected
|
||
# ============================================================
|
||
# _emit_provider_push / _emit_provider_pop - FakeDuck: with 上下文
|
||
# provider push/pop(__provides__ 元数据,fd1 注册)
|
||
#
|
||
# 对齐 TPC HandlesWith.py L138-174:
|
||
# with 进入时对每个提供字段生成 _push_provider(field_str, ctx_i8);
|
||
# 退出时生成等量 _pop_provider()。运行时 _withcontent 模块负责
|
||
# 维护 TLS provider 栈,供 _inject_requires_fields 查找。
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _emit_provider_push(self, trans: HT.Translator*,
|
||
pool: memhub.MemBuddy*,
|
||
builder: llvmlite.IRBuilder*,
|
||
mod: llvmlite.LLVMModule*,
|
||
cls_name: str,
|
||
ctx_val: llvmlite.Value*) -> int:
|
||
"""生成 _push_provider(field, ctx_i8) 调用(每提供字段一次),返回字段数"""
|
||
if trans is None or pool is None or builder is None or mod is None: return 0
|
||
if cls_name is None or ctx_val is None: return 0
|
||
fd_pc: int = self.Gen.ClassGenBase.class_meta_count(GenTypes.CLASS_META_PROVIDES, cls_name)
|
||
if fd_pc <= 0: return 0
|
||
# _withcontent._push_provider(跨模块,同 _find_provider 的可见性守卫:
|
||
# 本模块未 import _withcontent 时跳过,避免 undefined symbol)
|
||
fd_pfn_probe: llvmlite.Function* = self.find_func_in_module(mod, "_push_provider")
|
||
if fd_pfn_probe is None: return 0
|
||
fd_pfn: str = llvmlite.function_get_name(fd_pfn_probe)
|
||
if fd_pfn is None: return 0
|
||
i8_ty_p: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
if i8_ty_p is None: return 0
|
||
i8_ptr_ty_p: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty_p)
|
||
if i8_ptr_ty_p is None: return 0
|
||
ret_i32_p: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
if ret_i32_p is None: return 0
|
||
# ctx 值 bitcast 到 i8*(provider 栈存 void*)
|
||
fd_ctx_i8: llvmlite.Value* = llvmlite.build_bitcast(builder, ctx_val, i8_ptr_ty_p)
|
||
if fd_ctx_i8 is None: return 0
|
||
for pi in range(fd_pc):
|
||
fname: str = self.Gen.ClassGenBase.class_meta_field_at(GenTypes.CLASS_META_PROVIDES, cls_name, pi)
|
||
if fname is None: continue
|
||
fd_fstr: llvmlite.Value* = self.Gen.ExprGenConst.create_global_string(builder, pool, mod, fname, trans)
|
||
if fd_fstr is None: continue
|
||
llvmlite.value_set_next(fd_fstr, fd_ctx_i8)
|
||
llvmlite.value_set_next(fd_ctx_i8, None)
|
||
self._ensure_method_declare(pool, mod, fd_pfn, ret_i32_p, fd_fstr, 2)
|
||
llvmlite.build_call(builder, fd_pfn, fd_fstr, 2, ret_i32_p, 0)
|
||
return fd_pc
|
||
def _emit_provider_pop(self, trans: HT.Translator*,
|
||
pool: memhub.MemBuddy*,
|
||
builder: llvmlite.IRBuilder*,
|
||
mod: llvmlite.LLVMModule*,
|
||
cls_name: str) -> int:
|
||
"""生成 _pop_provider() 调用(每提供字段一次),返回字段数"""
|
||
if trans is None or pool is None or builder is None or mod is None: return 0
|
||
if cls_name is None: return 0
|
||
fd_pc: int = self.Gen.ClassGenBase.class_meta_count(GenTypes.CLASS_META_PROVIDES, cls_name)
|
||
if fd_pc <= 0: return 0
|
||
# _withcontent._pop_provider(跨模块,同 _find_provider 的可见性守卫:
|
||
# 本模块未 import _withcontent 时跳过,避免 undefined symbol)
|
||
fd_pon_probe: llvmlite.Function* = self.find_func_in_module(mod, "_pop_provider")
|
||
if fd_pon_probe is None: return 0
|
||
fd_pon: str = llvmlite.function_get_name(fd_pon_probe)
|
||
if fd_pon is None: return 0
|
||
ret_i32_q: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||
if ret_i32_q is None: return 0
|
||
self._ensure_method_declare(pool, mod, fd_pon, ret_i32_q, None, 0)
|
||
for _pi in range(fd_pc):
|
||
llvmlite.build_call(builder, fd_pon, None, 0, ret_i32_q, 0)
|
||
return fd_pc |