refactor(gen): CallGenMixin 阶段 B 拆出 6 组(Ctor/Call/Prop/Fd/Vt/Va),顶层剩 translate_call 中枢
This commit is contained in:
1 parent
8d9ff96f61
commit
1718738a19
9 files changed
+4123
-3818
No files matched your search
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,437 @@
|
||||
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
|
||||
|
||||
|
||||
import lib.core.Gen.CallGenBase as CallGenBase
|
||||
|
||||
# ============================================================
|
||||
# CallGenFd - CallGenMixin 拆分(阶段 B):FakeDuck / requires 字段注入 / provider 栈
|
||||
#
|
||||
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class CallGenFd(CallGenBase.CallGenBase):
|
||||
"""FakeDuck / requires 字段注入 / provider 栈"""
|
||||
|
||||
# ============================================================
|
||||
# _translate_fakeduck_call - FakeDuck: str 变量方法调用 → 扩展类 _Type/_str
|
||||
#
|
||||
# 对齐 TPC HandlesExprCall.py L2841-2880:
|
||||
# ClassName 常规解析失败且对象是 char*(i8*)时,遍历扩展类查找
|
||||
# {CN}.{method} 函数。对象是 Name 变量且有影子({var}__meta__,fd2
|
||||
# 创建)时 self=影子;否则(字符串字面量/匿名 str)在入口创建临时
|
||||
# 影子,写 __data__=obj 值、__mbuddy__=NULL 后作 self,避免
|
||||
# bitcast i8* → _str* 读取垃圾指针导致 ACCESS_VIOLATION。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# _translate_fakeduck_call - FakeDuck: str 变量方法调用 → 扩展类 _Type/_str
|
||||
#
|
||||
# 对齐 TPC HandlesExprCall.py L2841-2880:
|
||||
# ClassName 常规解析失败且对象是 char*(i8*)时,遍历扩展类查找
|
||||
# {CN}.{method} 函数。对象是 Name 变量且有影子({var}__meta__,fd2
|
||||
# 创建)时 self=影子;否则(字符串字面量/匿名 str)在入口创建临时
|
||||
# 影子,写 __data__=obj 值、__mbuddy__=NULL 后作 self,避免
|
||||
# bitcast i8* → _str* 读取垃圾指针导致 ACCESS_VIOLATION。
|
||||
# ============================================================
|
||||
def _translate_fakeduck_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
cls_name: str,
|
||||
method_name: str,
|
||||
cl: ast.Call | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""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 | t.CPtr = (ast.Attribute | t.CPtr)(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 | t.CPtr = 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 | t.CPtr = HandlesStruct.get_struct_type(fd_cls)
|
||||
if fd_sty is None:
|
||||
return None
|
||||
# 扩展类字段数:有字段(_str)时 self 用影子结构体指针;
|
||||
# 无字段(_Type)时 self 用对象值 bitcast 到扩展类指针(对齐 TPC L2856-2876)
|
||||
fd_entry_fd: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.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 | t.CPtr = None
|
||||
if fd_at.value.kind() == ast.ASTKind.Name:
|
||||
fd_onm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(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 | t.CPtr = HandlesVar.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)
|
||||
HandlesStruct.ensure_struct_def_in_module(pool, mod, fd_sty)
|
||||
fd_self = HandlesVar._alloca_at_entry(builder, fd_sty)
|
||||
if fd_self is None:
|
||||
return None
|
||||
fd_obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, fd_at.value, None, 0, trans)
|
||||
if fd_obj_val is not None:
|
||||
fd_dfe: HandlesStruct.FieldEntry | t.CPtr = \
|
||||
HandlesStruct.lookup_field(fd_sty, "__data__")
|
||||
if fd_dfe is not None and fd_dfe.Ty is not None:
|
||||
fd_dp: llvmlite.Value | t.CPtr = 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: HandlesStruct.FieldEntry | t.CPtr = \
|
||||
HandlesStruct.lookup_field(fd_sty, "__mbuddy__")
|
||||
if fd_bfe is not None and fd_bfe.Ty is not None:
|
||||
fd_bp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||||
builder, fd_sty, fd_bfe.Ty, fd_self, fd_bfe.Index)
|
||||
fd_null: llvmlite.Value | t.CPtr = 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 | t.CPtr = HandlesExpr.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 | t.CPtr = fd_self
|
||||
fd_tail: llvmlite.Value | t.CPtr = fd_self
|
||||
fd_args: list[ast.AST | t.CPtr] | t.CPtr = 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 | t.CPtr = fd_args.get(fd_ai)
|
||||
if fd_arg is not None:
|
||||
fd_av: llvmlite.Value | t.CPtr = HandlesExpr.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 | t.CPtr = (ast.Constant | t.CPtr)(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] = t.CChar(fd_ac.int_val)
|
||||
ch_buf[1] = '\0'
|
||||
fd_av = HandlesExpr.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 | t.CPtr = 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 读取精确返回类型(对齐普通方法调用 _translate_method_call)。
|
||||
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 | t.CPtr = 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 场景。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# _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 | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
meta_ptr: llvmlite.Value | t.CPtr,
|
||||
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 | t.CPtr = 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 = HandlesType.class_meta_count(
|
||||
HandlesType.CLASS_META_REQUIRES, class_name)
|
||||
if cnt <= 0:
|
||||
return 0
|
||||
sty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name)
|
||||
if sty is None:
|
||||
return 0
|
||||
i8_ty_j: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
if i8_ty_j is None:
|
||||
return 0
|
||||
i8_ptr_ty_j: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_j)
|
||||
if i8_ptr_ty_j is None:
|
||||
return 0
|
||||
cur_func: llvmlite.Function | t.CPtr = trans._cur_func
|
||||
if cur_func is None:
|
||||
return 0
|
||||
injected: int = 0
|
||||
for ji in range(cnt):
|
||||
fname: str = HandlesType.class_meta_field_at(
|
||||
HandlesType.CLASS_META_REQUIRES, class_name, ji)
|
||||
if fname is None:
|
||||
continue
|
||||
fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
|
||||
sty, fname)
|
||||
if fe is None or fe.Ty is None:
|
||||
continue
|
||||
# 参数:字段名字符串(i8*)
|
||||
fd_fstr: llvmlite.Value | t.CPtr = HandlesExpr.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 | t.CPtr = 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 | t.CPtr = llvmlite.ConstNull(
|
||||
pool, i8_ptr_ty_j, "null")
|
||||
if fd_null is None:
|
||||
continue
|
||||
fd_cmp: llvmlite.Value | t.CPtr = 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: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||||
pool, cur_func, fd_bb_buf2)
|
||||
viperlib.snprintf(fd_bb_buf2, 64, "fd.inject.%d", vtc2)
|
||||
fd_inject_bb: llvmlite.BasicBlock | t.CPtr = 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 | t.CPtr = llvmlite.build_bitcast(
|
||||
builder, fd_ptr, fe.Ty)
|
||||
if fd_cast is not None:
|
||||
fd_fp: llvmlite.Value | t.CPtr = 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 查找。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# _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 | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
cls_name: str,
|
||||
ctx_val: llvmlite.Value | t.CPtr) -> 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 = HandlesType.class_meta_count(
|
||||
HandlesType.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 | t.CPtr = 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 | t.CPtr = llvmlite.Int8(pool)
|
||||
if i8_ty_p is None:
|
||||
return 0
|
||||
i8_ptr_ty_p: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_p)
|
||||
if i8_ptr_ty_p is None:
|
||||
return 0
|
||||
ret_i32_p: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
if ret_i32_p is None:
|
||||
return 0
|
||||
# ctx 值 bitcast 到 i8*(provider 栈存 void*)
|
||||
fd_ctx_i8: llvmlite.Value | t.CPtr = 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 = HandlesType.class_meta_field_at(
|
||||
HandlesType.CLASS_META_PROVIDES, cls_name, pi)
|
||||
if fname is None:
|
||||
continue
|
||||
fd_fstr: llvmlite.Value | t.CPtr = HandlesExpr.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 | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
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 = HandlesType.class_meta_count(
|
||||
HandlesType.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 | t.CPtr = 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 | t.CPtr = 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
|
||||
+38
-3818
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,455 @@
|
||||
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
|
||||
|
||||
|
||||
import lib.core.Gen.CallGenBase as CallGenBase
|
||||
|
||||
# ============================================================
|
||||
# CallGenProp - CallGenMixin 拆分(阶段 B):属性访问(getter/setter/deleter / 静态类调用 / list 内置方法)
|
||||
#
|
||||
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class CallGenProp(CallGenBase.CallGenBase):
|
||||
"""属性访问(getter/setter/deleter / 静态类调用 / list 内置方法)"""
|
||||
|
||||
# ============================================================
|
||||
# _ensure_method_declare - 为跨模块方法调用创建 declare 声明
|
||||
#
|
||||
# 当 found_func 为 None(stub 未注入或跨模块调用)时,
|
||||
# 在当前模块中创建函数声明,避免 llc 报 undefined value。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# 属性方法(@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 一个参数)
|
||||
# ============================================================
|
||||
def _translate_property_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
class_name: str,
|
||||
method_name: str,
|
||||
call_head: llvmlite.Value | t.CPtr,
|
||||
call_count: int,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译属性/静态方法调用,返回 call 结果 Value"""
|
||||
if pool is None or builder is None or class_name is None or method_name is None:
|
||||
return None
|
||||
|
||||
# 构造查找名: ClassName.method_name
|
||||
lookup_name: str = pool.alloc(128)
|
||||
if lookup_name is None:
|
||||
return None
|
||||
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name)
|
||||
|
||||
# 查找函数(精确/后缀匹配)
|
||||
found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, lookup_name)
|
||||
|
||||
# 确定调用名
|
||||
call_name: str = lookup_name
|
||||
if found_func is not None:
|
||||
found_name: str = llvmlite.function_get_name(found_func)
|
||||
if found_name is not None:
|
||||
call_name = found_name
|
||||
else:
|
||||
# 未找到:用类所属模块的 SHA1 构造调用名
|
||||
cls_sha1_pc: str = HandlesStruct.get_struct_sha1(class_name)
|
||||
if cls_sha1_pc is not None:
|
||||
mlen_pc: t.CSizeT = string.strlen(cls_sha1_pc) + string.strlen(lookup_name) + 2
|
||||
mangled_pc: str = pool.alloc(mlen_pc)
|
||||
if mangled_pc is not None:
|
||||
viperlib.snprintf(mangled_pc, mlen_pc, "%s.%s", cls_sha1_pc, lookup_name)
|
||||
call_name = mangled_pc
|
||||
|
||||
# 确定返回类型
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
||||
if found_func is not None:
|
||||
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 = self._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 = self._LookupMethodRetTyFromTextLL(
|
||||
pool, cls_sha1_rt, class_name, method_name)
|
||||
if looked_up_ty is not None:
|
||||
call_ret_ty = looked_up_ty
|
||||
else:
|
||||
# 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单)
|
||||
vpi_ret_ty: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi(
|
||||
pool, cls_sha1_rt, class_name, method_name)
|
||||
if vpi_ret_ty is not None:
|
||||
call_ret_ty = vpi_ret_ty
|
||||
else:
|
||||
# Phase A 依赖未就绪(cls_sha1_rt None / 定义模块 text.ll 未生成):
|
||||
# 标记 pending 下遍重译(对齐 _translate_method_call L4783-4790),
|
||||
# 绝不 fail-fast 中断多遍收敛;真实错误由收敛检查兜底。
|
||||
if cls_sha1_rt is None \
|
||||
or self._dep_text_ll_exists(pool, cls_sha1_rt) == 0:
|
||||
if trans is not None:
|
||||
trans._deps_pending = 1
|
||||
call_ret_ty = llvmlite.Void(pool)
|
||||
else:
|
||||
call_ret_ty = self._fail_method_ret_ty(method_name)
|
||||
|
||||
# 参数类型对齐:按目标函数声明的参数类型转换实参(与 _translate_method_call
|
||||
# 一致)。例如 from_long(10) 的 i32 字面量 → i64 形参(v: t.CLong),
|
||||
# 不转换则 call(i32) 与 declare(i64) 不匹配,llc 报参数类型错误。
|
||||
# 目标函数优先用已找到的 found_func,否则按 mangled 调用名查模块 declare。
|
||||
tgt_func_pc: llvmlite.Function | t.CPtr = found_func
|
||||
if tgt_func_pc is None:
|
||||
tgt_func_pc = self.find_func_in_module(mod, call_name)
|
||||
if tgt_func_pc is not None:
|
||||
prev_pc: llvmlite.Value | t.CPtr = None
|
||||
cur_arg_pc: llvmlite.Value | t.CPtr = call_head
|
||||
cur_param_pc: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(tgt_func_pc)
|
||||
while cur_arg_pc is not None and cur_param_pc is not None:
|
||||
param_ty_pc: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_pc)
|
||||
if param_ty_pc is not None and cur_arg_pc.Ty is not None:
|
||||
coerced_pc: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
|
||||
builder, cur_arg_pc, param_ty_pc)
|
||||
if coerced_pc is not None and coerced_pc != cur_arg_pc:
|
||||
# 保持链表完整性:新 Value 继承原节点的 Next,前驱指向新节点
|
||||
llvmlite.value_set_next(coerced_pc, cur_arg_pc.Next)
|
||||
if prev_pc is None:
|
||||
call_head = coerced_pc
|
||||
else:
|
||||
llvmlite.value_set_next(prev_pc, coerced_pc)
|
||||
cur_arg_pc = coerced_pc
|
||||
prev_pc = cur_arg_pc
|
||||
cur_arg_pc = cur_arg_pc.Next
|
||||
cur_param_pc = llvmlite.param_get_next(cur_param_pc)
|
||||
|
||||
# 确保 declare 存在,然后调用
|
||||
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, call_head, call_count)
|
||||
return llvmlite.build_call(builder, call_name, call_head, call_count, call_ret_ty, 0)
|
||||
# ============================================================
|
||||
# _resolve_obj_class_name — 解析对象表达式的类名(短名)
|
||||
#
|
||||
# 优先从变量注解(AnnotClassName)解析(如 "memhub.MemBuddy" → "MemBuddy"),
|
||||
# 失败时从 LLVM 类型解析(Ptr(Struct) → 类名)。
|
||||
# 供属性访问/赋值/删除识别 property 时使用。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# _resolve_obj_class_name — 解析对象表达式的类名(短名)
|
||||
#
|
||||
# 优先从变量注解(AnnotClassName)解析(如 "memhub.MemBuddy" → "MemBuddy"),
|
||||
# 失败时从 LLVM 类型解析(Ptr(Struct) → 类名)。
|
||||
# 供属性访问/赋值/删除识别 property 时使用。
|
||||
# ============================================================
|
||||
def _resolve_obj_class_name(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
obj_node: ast.AST | t.CPtr) -> str:
|
||||
"""解析对象表达式的类名(短名),失败返回 None"""
|
||||
if pool is None or trans is None or obj_node is None:
|
||||
return None
|
||||
if obj_node.kind() == ast.ASTKind.Name:
|
||||
obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(obj_node)
|
||||
if obj_nm.id is not None:
|
||||
var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||||
trans.SymTab, obj_nm.id)
|
||||
if var_entry is not None and var_entry.AnnotClassName is not None:
|
||||
annot_val: str = var_entry.AnnotClassName
|
||||
dot_ptr: str = string.strrchr(annot_val, '.')
|
||||
if dot_ptr is not None:
|
||||
return dot_ptr + 1
|
||||
return annot_val
|
||||
return None
|
||||
# ============================================================
|
||||
# _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用
|
||||
#
|
||||
# 检查 obj 的类是否有 @property/@x.getter 的 attr 方法;
|
||||
# 若有则生成 call Class.attr(obj) 并返回调用结果 Value;否则返回 None。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用
|
||||
#
|
||||
# 检查 obj 的类是否有 @property/@x.getter 的 attr 方法;
|
||||
# 若有则生成 call Class.attr(obj) 并返回调用结果 Value;否则返回 None。
|
||||
# ============================================================
|
||||
def _try_property_getter_attr(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
at_node: ast.Attribute | t.CPtr,
|
||||
obj_ptr: llvmlite.Value | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
fallback_class_name: str = None) -> llvmlite.Value | t.CPtr:
|
||||
"""尝试 property getter 属性访问,返回调用结果 Value;非 getter 返回 None
|
||||
|
||||
fallback_class_name: 对象表达式非 Name 时从 LLVM 类型解析出的类名兜底。
|
||||
"""
|
||||
if at_node is None or at_node.attr is None or obj_ptr is None or trans is None:
|
||||
return None
|
||||
class_name: str = self._resolve_obj_class_name(pool, trans, at_node.value)
|
||||
if class_name is None:
|
||||
class_name = fallback_class_name
|
||||
if class_name is None:
|
||||
return None
|
||||
meta: int = HandlesClassDef.lookup_method_meta(class_name, at_node.attr)
|
||||
if meta & HandlesClassDef.META_PROP_GETTER == 0:
|
||||
return None
|
||||
# 单参数调用: obj → getter
|
||||
llvmlite.value_set_next(obj_ptr, None)
|
||||
return self._translate_property_call(
|
||||
pool, builder, mod, class_name, at_node.attr, obj_ptr, 1, trans)
|
||||
# ============================================================
|
||||
# _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用
|
||||
#
|
||||
# 检查 obj 的类是否有 @x.setter 的 attr 方法;
|
||||
# 若有则生成 call Class.attr$set(obj, v),返回 1;否则返回 0。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用
|
||||
#
|
||||
# 检查 obj 的类是否有 @x.setter 的 attr 方法;
|
||||
# 若有则生成 call Class.attr$set(obj, v),返回 1;否则返回 0。
|
||||
# ============================================================
|
||||
def _try_property_setter(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
target_attr: ast.Attribute | t.CPtr,
|
||||
rhs_val: llvmlite.Value | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> int:
|
||||
"""尝试 property setter 赋值,返回 1=已处理(生成调用)"""
|
||||
if pool is None or builder is None or mod is None or trans is None:
|
||||
return 0
|
||||
if target_attr is None or target_attr.attr is None or rhs_val is None:
|
||||
return 0
|
||||
class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value)
|
||||
if class_name is None:
|
||||
return 0
|
||||
meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr)
|
||||
if meta & HandlesClassDef.META_PROP_SETTER == 0:
|
||||
return 0
|
||||
# 翻译对象值(self 参数)
|
||||
obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, target_attr.value, None, 0, trans)
|
||||
if obj_val is None:
|
||||
return 0
|
||||
# 构建参数链表: obj → rhs
|
||||
llvmlite.value_set_next(obj_val, None)
|
||||
llvmlite.value_set_next(rhs_val, None)
|
||||
llvmlite.value_set_next(obj_val, rhs_val)
|
||||
# setter 函数名带 $set 后缀
|
||||
setter_name_buf: str = pool.alloc(128)
|
||||
if setter_name_buf is None:
|
||||
return 0
|
||||
viperlib.snprintf(setter_name_buf, 128, "%s$set", target_attr.attr)
|
||||
self._translate_property_call(pool, builder, mod, class_name,
|
||||
setter_name_buf, obj_val, 2, trans)
|
||||
return 1
|
||||
# ============================================================
|
||||
# _try_property_deleter — 尝试将 del obj.attr 翻译为 property deleter 调用
|
||||
#
|
||||
# 检查 obj 的类是否有 @x.deleter 的 attr 方法;
|
||||
# 若有则生成 call Class.attr$del(obj),返回 1;否则返回 0。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# _try_property_deleter — 尝试将 del obj.attr 翻译为 property deleter 调用
|
||||
#
|
||||
# 检查 obj 的类是否有 @x.deleter 的 attr 方法;
|
||||
# 若有则生成 call Class.attr$del(obj),返回 1;否则返回 0。
|
||||
# ============================================================
|
||||
def _try_property_deleter(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
target_attr: ast.Attribute | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> int:
|
||||
"""尝试 property deleter 删除,返回 1=已处理(生成调用)"""
|
||||
if pool is None or builder is None or mod is None or trans is None:
|
||||
return 0
|
||||
if target_attr is None or target_attr.attr is None:
|
||||
return 0
|
||||
class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value)
|
||||
if class_name is None:
|
||||
return 0
|
||||
meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr)
|
||||
if meta & HandlesClassDef.META_PROP_DELETER == 0:
|
||||
return 0
|
||||
# 翻译对象值(self 参数)
|
||||
obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, target_attr.value, None, 0, trans)
|
||||
if obj_val is None:
|
||||
return 0
|
||||
llvmlite.value_set_next(obj_val, None)
|
||||
# deleter 函数名带 $del 后缀
|
||||
del_name_buf: str = pool.alloc(128)
|
||||
if del_name_buf is None:
|
||||
return 0
|
||||
viperlib.snprintf(del_name_buf, 128, "%s$del", target_attr.attr)
|
||||
self._translate_property_call(pool, builder, mod, class_name,
|
||||
del_name_buf, obj_val, 1, trans)
|
||||
return 1
|
||||
# ============================================================
|
||||
# _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用
|
||||
#
|
||||
# @staticmethod: 直接 call Class.method(args...),无 self
|
||||
# @classmethod: 在参数前插入栈上分配的类实例指针(与 TPC 一致)
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用
|
||||
#
|
||||
# @staticmethod: 直接 call Class.method(args...),无 self
|
||||
# @classmethod: 在参数前插入栈上分配的类实例指针(与 TPC 一致)
|
||||
# ============================================================
|
||||
def _translate_static_class_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
class_name: str,
|
||||
method_name: str,
|
||||
cl: ast.Call | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译类名静态/类方法调用,返回 call 结果 Value;非静态/类方法返回 None"""
|
||||
if pool is None or builder is None or mod is None or trans is None:
|
||||
return None
|
||||
if class_name is None or method_name is None or cl is None:
|
||||
return None
|
||||
meta: int = HandlesClassDef.lookup_method_meta(class_name, method_name)
|
||||
is_static: int = 0
|
||||
is_class: int = 0
|
||||
if meta & HandlesClassDef.META_STATIC != 0:
|
||||
is_static = 1
|
||||
if meta & HandlesClassDef.META_CLASS != 0:
|
||||
is_class = 1
|
||||
if is_static == 0 and is_class == 0:
|
||||
return None
|
||||
|
||||
# 构建参数链表
|
||||
head: llvmlite.Value | t.CPtr = None
|
||||
total_count: int = 0
|
||||
|
||||
# @classmethod: 插入栈上分配的类实例指针作为 cls 参数
|
||||
if is_class != 0:
|
||||
struct_ty_cc: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name)
|
||||
if struct_ty_cc is None:
|
||||
return None
|
||||
cls_ptr: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty_cc)
|
||||
if cls_ptr is None:
|
||||
return None
|
||||
llvmlite.value_set_next(cls_ptr, None)
|
||||
head = cls_ptr
|
||||
total_count = 1
|
||||
|
||||
# 翻译调用参数
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||||
can: t.CSizeT = 0
|
||||
if cargs is not None:
|
||||
can = len(cargs)
|
||||
tail: llvmlite.Value | t.CPtr = head
|
||||
for ai in range(can):
|
||||
arg_node: ast.AST | t.CPtr = cargs.get(ai)
|
||||
if arg_node is None:
|
||||
continue
|
||||
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, arg_node, None, 0, trans)
|
||||
if arg_val is None:
|
||||
continue
|
||||
llvmlite.value_set_next(arg_val, None)
|
||||
if head is None:
|
||||
head = arg_val
|
||||
tail = arg_val
|
||||
else:
|
||||
llvmlite.value_set_next(tail, arg_val)
|
||||
tail = arg_val
|
||||
total_count += 1
|
||||
|
||||
# 零参 @staticmethod(如 PyListObj.new()):head 保持 None 是合法的
|
||||
# 无参调用,照常走 _translate_property_call(SHA1 前缀名 + 精确返回类型)。
|
||||
# 若此处 return None,调用方回退通用路径把方法名当裸函数解析,生成
|
||||
# call i32 @new() → 链接 undefined reference(CPythonTest 根因)。
|
||||
# @classmethod 恒有 cls_ptr(head 非 None),不受影响。
|
||||
return self._translate_property_call(pool, builder, mod, class_name,
|
||||
method_name, head, total_count, trans)
|
||||
# ============================================================
|
||||
# _is_list_builtin_method - 判断是否是 list 泛型内置容器方法
|
||||
#
|
||||
# list[T] 是内置泛型容器(_list.vp),其方法(append/get/set/pop/clear/
|
||||
# __iter__/__len__/__getitem__/__setitem__)由 translate_call 的 list
|
||||
# 内置分支内联 GEP 处理,不注册为方法函数。若 obj.method() 检测把
|
||||
# list 特化 struct(如 list[AST | CPtr])误当普通结构体走
|
||||
# _translate_method_call,会查不到 append 返回类型 → fail-fast
|
||||
# (NewAstTest body.append 根因)。此判断用于跳过 method_call 路径。
|
||||
#
|
||||
# 返回: 1=list 内置方法(应落到 list 内置分支),0=普通方法
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# _is_list_builtin_method - 判断是否是 list 泛型内置容器方法
|
||||
#
|
||||
# list[T] 是内置泛型容器(_list.vp),其方法(append/get/set/pop/clear/
|
||||
# __iter__/__len__/__getitem__/__setitem__)由 translate_call 的 list
|
||||
# 内置分支内联 GEP 处理,不注册为方法函数。若 obj.method() 检测把
|
||||
# list 特化 struct(如 list[AST | CPtr])误当普通结构体走
|
||||
# _translate_method_call,会查不到 append 返回类型 → fail-fast
|
||||
# (NewAstTest body.append 根因)。此判断用于跳过 method_call 路径。
|
||||
#
|
||||
# 返回: 1=list 内置方法(应落到 list 内置分支),0=普通方法
|
||||
# ============================================================
|
||||
def _is_list_builtin_method(self, class_name: str,
|
||||
method_name: str) -> int:
|
||||
"""判断 (class_name, method_name) 是否是 list 泛型内置方法"""
|
||||
if class_name is None or method_name is None:
|
||||
return 0
|
||||
# 类名必须以 "list" 开头(list / list[AST | CPtr] 特化名)
|
||||
if string.strncmp(class_name, "list", 4) != 0:
|
||||
return 0
|
||||
# 方法名必须是 list 内置方法集合
|
||||
if string.strcmp(method_name, "append") == 0: return 1
|
||||
if string.strcmp(method_name, "get") == 0: return 1
|
||||
if string.strcmp(method_name, "set") == 0: return 1
|
||||
if string.strcmp(method_name, "pop") == 0: return 1
|
||||
if string.strcmp(method_name, "clear") == 0: return 1
|
||||
if string.strcmp(method_name, "__iter__") == 0: return 1
|
||||
if string.strcmp(method_name, "__len__") == 0: return 1
|
||||
if string.strcmp(method_name, "__getitem__") == 0: return 1
|
||||
if string.strcmp(method_name, "__setitem__") == 0: return 1
|
||||
return 0
|
||||
@@ -0,0 +1,334 @@
|
||||
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
|
||||
|
||||
|
||||
import lib.core.Gen.CallGenBase as CallGenBase
|
||||
|
||||
# ============================================================
|
||||
# CallGenVa - CallGenMixin 拆分(阶段 B):va_arg 变长参数(start/arg/end / 变长调用提升)
|
||||
#
|
||||
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class CallGenVa(CallGenBase.CallGenBase):
|
||||
"""va_arg 变长参数(start/arg/end / 变长调用提升)"""
|
||||
|
||||
# ============================================================
|
||||
# _func_has_eh_params - 被调函数签名是否含 try-except EH 输出参数
|
||||
#
|
||||
# EH 参数(%__eh_msg_out__/__eh_code_out__)由 translate_function_def/
|
||||
# _translate_method 在含 raise 的函数签名末尾注入(main 除外)。
|
||||
# ============================================================
|
||||
|
||||
def _va_arg_get_alloca_ptr(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
arg_node: ast.AST | t.CPtr,
|
||||
funcs_ptr: t.CPtr,
|
||||
func_count: int,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""获取 va_list 变量的 alloca 指针(不 load)
|
||||
|
||||
va_arg/va_start/va_end 需要的是 va_list 对象的地址(alloca 指针),
|
||||
而非 va_list 的值。若 arg_node 是 Name,查符号表获取 alloca;
|
||||
否则用 translate_value 翻译(调用者负责确保传入的是指针)。
|
||||
"""
|
||||
if arg_node is None:
|
||||
return None
|
||||
# Name 节点:直接查符号表获取 alloca 指针(不 load)
|
||||
if arg_node.kind() == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg_node)
|
||||
if nm.id is not None:
|
||||
alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id)
|
||||
if alloca is not None:
|
||||
return alloca
|
||||
# 回退:translate_value(可能返回 load 后的值,仅适用于已是指针的情况)
|
||||
return HandlesExpr.translate_value(builder, pool, mod, arg_node, funcs_ptr, func_count, trans)
|
||||
def _resolve_va_arg_type(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
type_node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""解析 va_arg/arg 的类型参数为 LLVMType
|
||||
|
||||
支持的类型表达式:
|
||||
t.CInt / t.CInt32T → i32
|
||||
t.CInt64T → i64
|
||||
t.CDouble → double
|
||||
t.CPtr / str → i8*
|
||||
str / bytes → i8*
|
||||
无类型参数时默认 i32(vsnprintf 中 va_arg(ap) 常用于读取 i32)
|
||||
"""
|
||||
if type_node is None:
|
||||
return llvmlite.Int32(pool)
|
||||
# 使用 HandlesType.resolve_annotation_type 解析类型表达式
|
||||
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||
pool, type_node, trans._imported_modules, trans._from_imports, trans)
|
||||
if resolved is not None:
|
||||
return resolved
|
||||
# 类型节点存在但解析失败:fail-fast,绝不回退 i32(会按错宽度读变参槽位)
|
||||
HandlesType.fatal_error(type_node, "va_arg 类型解析失败", "TypeError")
|
||||
return llvmlite.Int32(pool)
|
||||
def _translate_va_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
cl: ast.Call | t.CPtr,
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||||
can: t.CSizeT,
|
||||
funcs_ptr: t.CPtr,
|
||||
func_count: int,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""va_arg(ap, type) / va_arg(ap) → %N = va_arg <ap_ty> <ap>, <type>
|
||||
|
||||
生成 LLVM va_arg 指令,从 va_list 读取下一个变长参数。
|
||||
"""
|
||||
if can == 0 or cargs is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
|
||||
# 第一个参数:va_list(求值为 i8* 地址值,对齐 TPC _HandleVaArgLlvm)
|
||||
# 当前函数 *args:translate_value 经 vararg 名映射直接返回 va_list 缓冲区地址;
|
||||
# 转发场景(sprintf → vsnprintf 的 ap 参数):translate_value load 参数得到地址值。
|
||||
ap_node: ast.AST | t.CPtr = cargs.get(0)
|
||||
ap_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, ap_node, None, 0, trans)
|
||||
if ap_val is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
ap_ptr: llvmlite.Value | t.CPtr = ap_val
|
||||
|
||||
# 第二个参数:目标类型(可选,默认 i32)
|
||||
arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
if can >= 2:
|
||||
type_node: ast.AST | t.CPtr = cargs.get(1)
|
||||
arg_ty = self._resolve_va_arg_type(pool, type_node, trans)
|
||||
|
||||
# Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(对齐 TPC emit_va_arg L72-73)
|
||||
read_ty: llvmlite.LLVMType | t.CPtr = arg_ty
|
||||
abits_va: int = HandlesExpr.get_llvm_type_bits(arg_ty)
|
||||
if abits_va != 0 and abits_va < 64:
|
||||
read_ty = llvmlite.Int64(pool)
|
||||
|
||||
# 生成 va_arg 指令
|
||||
return llvmlite.build_va_arg(builder, ap_ptr, read_ty)
|
||||
def _translate_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
cl: ast.Call | t.CPtr,
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||||
can: t.CSizeT,
|
||||
funcs_ptr: t.CPtr,
|
||||
func_count: int,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""arg(type) → %N = va_arg <va_list_ty> <trans._va_list_ptr>, <type>
|
||||
|
||||
使用当前函数的隐式 va_list(trans._va_list_ptr),
|
||||
简化 *args 函数体内的 va_arg 调用。
|
||||
"""
|
||||
if trans._va_list_ptr is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
|
||||
# 第一个参数:目标类型(可选,默认 i32)
|
||||
arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
if can >= 1 and cargs is not None:
|
||||
type_node: ast.AST | t.CPtr = cargs.get(0)
|
||||
arg_ty = self._resolve_va_arg_type(pool, type_node, trans)
|
||||
|
||||
# Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(与 _translate_va_arg_sugar 一致)
|
||||
read_ty: llvmlite.LLVMType | t.CPtr = arg_ty
|
||||
abits_arg: int = HandlesExpr.get_llvm_type_bits(arg_ty)
|
||||
if abits_arg != 0 and abits_arg < 64:
|
||||
read_ty = llvmlite.Int64(pool)
|
||||
|
||||
# 生成 va_arg 指令(使用 trans._va_list_ptr 作为 va_list 地址)
|
||||
return llvmlite.build_va_arg(builder, trans._va_list_ptr, read_ty)
|
||||
def _translate_va_start_sugar(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||||
can: t.CSizeT,
|
||||
funcs_ptr: t.CPtr,
|
||||
func_count: int,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""va_start(ap, last_arg) → call void @llvm.va_start(i8* %ap)
|
||||
|
||||
初始化 va_list。第二个参数 last_arg 在 LLVM intrinsic 中不使用(C 宏兼容)。
|
||||
"""
|
||||
if can == 0 or cargs is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
|
||||
# 第一个参数:va_list 指针(获取 alloca,不 load)
|
||||
ap_node: ast.AST | t.CPtr = cargs.get(0)
|
||||
ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr(
|
||||
pool, builder, mod, ap_node, funcs_ptr, func_count, trans)
|
||||
if ap_ptr is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
|
||||
# bitcast 到 i8*(@llvm.va_start 接受 i8*)
|
||||
i8_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_vs)
|
||||
ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_vs)
|
||||
if ap_i8 is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
|
||||
void_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
|
||||
llvmlite.build_call(builder, "llvm.va_start", ap_i8, 1, void_ty_vs, 0)
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
def _translate_va_end_sugar(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||||
can: t.CSizeT,
|
||||
funcs_ptr: t.CPtr,
|
||||
func_count: int,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""va_end(ap) → call void @llvm.va_end(i8* %ap)
|
||||
|
||||
清理 va_list。在大多数平台上是 no-op,但调用它是良好的 C ABI 习惯。
|
||||
"""
|
||||
if can == 0 or cargs is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
|
||||
# 第一个参数:va_list 指针(获取 alloca,不 load)
|
||||
ap_node: ast.AST | t.CPtr = cargs.get(0)
|
||||
ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr(
|
||||
pool, builder, mod, ap_node, funcs_ptr, func_count, trans)
|
||||
if ap_ptr is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
|
||||
# bitcast 到 i8*(@llvm.va_end 接受 i8*)
|
||||
i8_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_ve)
|
||||
ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_ve)
|
||||
if ap_i8 is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
|
||||
void_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
|
||||
llvmlite.build_call(builder, "llvm.va_end", ap_i8, 1, void_ty_ve, 0)
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
def _get_func_fixed_param_count(self, func: llvmlite.Function | t.CPtr) -> int:
|
||||
"""获取函数的固定参数数量(遍历 Params 链表)"""
|
||||
if func is None:
|
||||
return 0
|
||||
count: int = 0
|
||||
param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func)
|
||||
while param is not None:
|
||||
count += 1
|
||||
param = llvmlite.param_get_next(param)
|
||||
return count
|
||||
def _check_and_promote_variadic_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
call_name: str,
|
||||
head: llvmlite.Value | t.CPtr,
|
||||
can: t.CSizeT,
|
||||
arg_nodes: list[ast.AST | t.CPtr] | t.CPtr = None,
|
||||
self_offset: int = 0,
|
||||
trans: HT.Translator | t.CPtr = None) -> int:
|
||||
"""检查被调用函数是否为变长函数,若是则对变长参数进行 C ABI 提升
|
||||
|
||||
返回: is_variadic (1=变长调用, 0=普通调用)
|
||||
副作用: 修改 head 链表中超过固定参数数量的节点(C ABI 提升)
|
||||
|
||||
arg_nodes: 实参 AST 链表(不含 self),用于 i8/i16 提升的无符号性判断
|
||||
self_offset: Value 链中 self 占用的偏移(方法调用=1,普通函数=0)
|
||||
trans: 供 _node_type_unsigned 查询变量注解
|
||||
"""
|
||||
if mod is None or call_name is None or head is None:
|
||||
return 0
|
||||
# 查找函数对象
|
||||
func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name)
|
||||
if func is None:
|
||||
return 0
|
||||
if func.IsVarArg != 1:
|
||||
return 0
|
||||
|
||||
# 获取固定参数数量
|
||||
fixed_count: int = self._get_func_fixed_param_count(func)
|
||||
|
||||
# 无变长参数(实参数量 <= 固定参数数量),仍需 is_variadic=1
|
||||
if can <= fixed_count:
|
||||
return 1
|
||||
|
||||
# 遍历到第 fixed_count 个节点(固定参数的最后一个)
|
||||
cur: llvmlite.Value | t.CPtr = head
|
||||
prev: llvmlite.Value | t.CPtr = None
|
||||
idx: int = 0
|
||||
while cur is not None and idx < fixed_count:
|
||||
prev = cur
|
||||
cur = cur.Next
|
||||
idx += 1
|
||||
|
||||
# cur 指向第 fixed_count+1 个节点(第一个变长参数)
|
||||
# 对变长参数进行 C ABI 提升
|
||||
i32_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
double_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
|
||||
v_idx: int = fixed_count
|
||||
while cur is not None:
|
||||
next_node: llvmlite.Value | t.CPtr = cur.Next
|
||||
promoted: llvmlite.Value | t.CPtr = cur
|
||||
# C ABI integer promotion: i8/i16 → i32
|
||||
arg_bits: int = HandlesExpr.get_llvm_type_bits(cur.Ty)
|
||||
if arg_bits != 0 and arg_bits < 32:
|
||||
# 无符号整型(t.CUInt8T/CUInt16T 等)→ zext;有符号/未知 → sext。
|
||||
# 修复: printf("%02x", buf[i]) 中 buf[i] 是 CUInt8T,sext 得
|
||||
# 0xFFFFFFF3 打印 fffffff3(哈希摘要输出垃圾),应 zext 得 0xF3。
|
||||
is_u_va: int = 0
|
||||
if arg_nodes is not None and trans is not None:
|
||||
ast_idx_va: int = v_idx - self_offset
|
||||
if ast_idx_va >= 0 and ast_idx_va < len(arg_nodes):
|
||||
an_va: ast.AST | t.CPtr = arg_nodes.get(ast_idx_va)
|
||||
if an_va is not None:
|
||||
if HandlesExpr._node_type_unsigned(pool, an_va, trans) != 0:
|
||||
is_u_va = 1
|
||||
if is_u_va != 0:
|
||||
promoted = llvmlite.build_zext(builder, cur, i32_ty_promote)
|
||||
else:
|
||||
# is_u_va 判断失败(arg_nodes/trans 缺失或变量注解查不到)时,
|
||||
# i8 按系统编程惯例默认 zext(对齐 should_zext_widen 的
|
||||
# "i8 → zext(系统编程中 i8 几乎总是无符号字节)"策略),
|
||||
# 否则 printf("%02x", buf[i]) 中 uint8 字节被 sext 成
|
||||
# 0xFFFFFFF3,哈希摘要输出 ffffffXX 垃圾。
|
||||
if HandlesExpr.get_llvm_type_bits(cur.Ty) == 8:
|
||||
promoted = llvmlite.build_zext(builder, cur, i32_ty_promote)
|
||||
else:
|
||||
promoted = HandlesExpr.coerce_to_type(builder, cur, i32_ty_promote, None)
|
||||
if promoted is not None:
|
||||
promoted.Next = next_node
|
||||
if prev is not None:
|
||||
prev.Next = promoted
|
||||
# C ABI float promotion: float → double
|
||||
arg_fbits: int = HandlesExpr.get_llvm_float_bits(promoted.Ty)
|
||||
if arg_fbits != 0 and arg_fbits < 64:
|
||||
promoted = HandlesExpr.coerce_to_type(builder, promoted, double_ty_promote, None)
|
||||
if promoted is not None:
|
||||
promoted.Next = next_node
|
||||
if prev is not None:
|
||||
prev.Next = promoted
|
||||
prev = promoted
|
||||
cur = next_node
|
||||
v_idx += 1
|
||||
|
||||
return 1
|
||||
@@ -0,0 +1,251 @@
|
||||
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
|
||||
|
||||
|
||||
import lib.core.Gen.CallGenBase as CallGenBase
|
||||
|
||||
# ============================================================
|
||||
# CallGenVt - CallGenMixin 拆分(阶段 B):vtable 槽位写入
|
||||
#
|
||||
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class CallGenVt(CallGenBase.CallGenBase):
|
||||
"""vtable 槽位写入"""
|
||||
|
||||
# ============================================================
|
||||
# _write_vtable_slot / _write_vtable_attr — vtable 方法槽位直接写入
|
||||
#
|
||||
# serial0_file.open = serial0_open(devfs 驱动注册模式):把模块级函数
|
||||
# 指针写入对象 vtable 的方法槽位。vtable 方法不是数据字段(FieldEntry),
|
||||
# get_attribute_ptr 查不到 → 此前 fatal_error "属性写入失败"。
|
||||
# 对齐 TPC HandlesAssign.py L905-949 的写时复制:
|
||||
# 对象 vtable 仍指向类默认 vtable 时,先复制一份(internal 全局 +
|
||||
# llvm.memcpy)并让对象指向副本,再 GEP method_index 槽位 store
|
||||
# 函数指针(i8*)。多次写入互不覆盖(第二次起 vtable 已非默认,
|
||||
# 跳过复制直接写槽位)。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# _write_vtable_slot / _write_vtable_attr — vtable 方法槽位直接写入
|
||||
#
|
||||
# serial0_file.open = serial0_open(devfs 驱动注册模式):把模块级函数
|
||||
# 指针写入对象 vtable 的方法槽位。vtable 方法不是数据字段(FieldEntry),
|
||||
# get_attribute_ptr 查不到 → 此前 fatal_error "属性写入失败"。
|
||||
# 对齐 TPC HandlesAssign.py L905-949 的写时复制:
|
||||
# 对象 vtable 仍指向类默认 vtable 时,先复制一份(internal 全局 +
|
||||
# llvm.memcpy)并让对象指向副本,再 GEP method_index 槽位 store
|
||||
# 函数指针(i8*)。多次写入互不覆盖(第二次起 vtable 已非默认,
|
||||
# 跳过复制直接写槽位)。
|
||||
# ============================================================
|
||||
def _write_vtable_slot(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
obj_ptr: llvmlite.Value | t.CPtr,
|
||||
class_name: str,
|
||||
method_index: int,
|
||||
func_val: llvmlite.Value | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> int:
|
||||
"""生成 vtable 槽位写入(写时复制),成功返回 1"""
|
||||
if pool is None or builder is None or mod is None or trans is None:
|
||||
return 0
|
||||
if obj_ptr is None or class_name is None or func_val is None:
|
||||
return 0
|
||||
if method_index < 0 or trans._cur_func is None:
|
||||
return 0
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
if i8_ty is None:
|
||||
return 0
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||||
if i8_ptr_ty is None:
|
||||
return 0
|
||||
i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty)
|
||||
if i8_ptr_ptr_ty is None:
|
||||
return 0
|
||||
method_count: int = HandlesStruct.get_vtable_method_count(class_name)
|
||||
if method_count <= 0:
|
||||
return 0
|
||||
# 构造 vtable 类型 { i8*, i8*, ... }
|
||||
vt_first: llvmlite.ParamNode | t.CPtr = None
|
||||
vt_prev: llvmlite.ParamNode | t.CPtr = None
|
||||
for vi in range(method_count):
|
||||
pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty)
|
||||
if pn is None:
|
||||
continue
|
||||
if vt_first is None:
|
||||
vt_first = pn
|
||||
if vt_prev is not None:
|
||||
llvmlite.paramnode_set_next(vt_prev, pn)
|
||||
vt_prev = pn
|
||||
vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first, method_count, None)
|
||||
if vtable_ty is None:
|
||||
return 0
|
||||
# 对象 vtable 槽位(对象头 → i8**,vtable 指针总是第一个字段)
|
||||
vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
builder, obj_ptr, i8_ptr_ptr_ty)
|
||||
if vtable_slot is None:
|
||||
return 0
|
||||
vtable_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, i8_ptr_ty, vtable_slot)
|
||||
if vtable_ptr is None:
|
||||
return 0
|
||||
# 类默认 vtable 地址(比较用)
|
||||
class_vt: llvmlite.Value | t.CPtr = HandlesExprCall._make_vtable_ref_i8(
|
||||
pool, builder, mod, class_name, trans)
|
||||
if class_vt is None:
|
||||
return 0
|
||||
cmp_vt: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
|
||||
builder, llvmlite.ICMP_EQ, vtable_ptr, class_vt)
|
||||
if cmp_vt is None:
|
||||
return 0
|
||||
# 块名唯一化(create_block 不自动编号;同函数多次 vtable 写入(如
|
||||
# devfs open/close/read/write 连续赋值)同名 label 冲突)
|
||||
vtc3: int = trans._label_counter
|
||||
trans._label_counter = vtc3 + 1
|
||||
vt_bb_buf3: str = pool.alloc(64)
|
||||
if vt_bb_buf3 is None:
|
||||
return 0
|
||||
viperlib.snprintf(vt_bb_buf3, 64, "vt.copy.%d", vtc3)
|
||||
vt_copy_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||||
pool, trans._cur_func, vt_bb_buf3)
|
||||
viperlib.snprintf(vt_bb_buf3, 64, "vt.skip.%d", vtc3)
|
||||
vt_skip_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||||
pool, trans._cur_func, vt_bb_buf3)
|
||||
if vt_copy_bb is None or vt_skip_bb is None:
|
||||
return 0
|
||||
llvmlite.build_cond_br(builder, cmp_vt, vt_copy_bb, vt_skip_bb)
|
||||
# copy 块:创建 internal 副本全局(zeroinit)+ memcpy + 对象指向副本
|
||||
llvmlite.position_at_end(builder, vt_copy_bb)
|
||||
vtc: int = trans._label_counter
|
||||
trans._label_counter = vtc + 1
|
||||
vcopy_buf: str = pool.alloc(256)
|
||||
if vcopy_buf is not None:
|
||||
viperlib.snprintf(vcopy_buf, 256, "%s.vtable.copy.%d", class_name, vtc)
|
||||
vcopy_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(
|
||||
pool, vcopy_buf, vtable_ty)
|
||||
if vcopy_gv is not None:
|
||||
llvmlite.module_add_global(mod, vcopy_gv)
|
||||
vcopy_gv.Linkage = None
|
||||
vcopy_gv.Initializer = "zeroinitializer"
|
||||
vcopy_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
|
||||
pool, llvmlite.Ptr(pool, vtable_ty), vcopy_buf)
|
||||
if vcopy_ref is not None:
|
||||
vcopy_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
builder, vcopy_ref, i8_ptr_ty)
|
||||
if vcopy_i8 is not None:
|
||||
vt_size: llvmlite.Value | t.CPtr = llvmlite.ConstInt(
|
||||
pool, llvmlite.Int64(pool), method_count * 8, "vtsz")
|
||||
if vt_size is not None:
|
||||
HandlesExprCall._emit_llvm_memcpy_intrinsic(
|
||||
pool, builder, mod, vcopy_i8, class_vt, vt_size)
|
||||
llvmlite.build_store(builder, vcopy_i8, vtable_slot)
|
||||
llvmlite.build_br(builder, vt_skip_bb)
|
||||
# skip 块:reload vtable → GEP 槽位 → store 函数指针(i8*)
|
||||
llvmlite.position_at_end(builder, vt_skip_bb)
|
||||
vt_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, i8_ptr_ty, vtable_slot)
|
||||
if vt_ptr2 is None:
|
||||
return 0
|
||||
vt_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
builder, vt_ptr2, llvmlite.Ptr(pool, vtable_ty))
|
||||
if vt_typed is None:
|
||||
return 0
|
||||
vt_slotp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||||
builder, vtable_ty, i8_ptr_ty, vt_typed, method_index)
|
||||
if vt_slotp is None:
|
||||
return 0
|
||||
fptr_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
builder, func_val, i8_ptr_ty)
|
||||
if fptr_i8 is not None:
|
||||
llvmlite.build_store(builder, fptr_i8, vt_slotp)
|
||||
return 1
|
||||
def _write_vtable_attr(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
rhs_val: llvmlite.Value | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> int:
|
||||
"""属性写入 obj.method = func:检测 vtable 方法并生成槽位写入(成功返回 1)"""
|
||||
if node is None or builder is None or pool is None or mod is None:
|
||||
return 0
|
||||
if rhs_val is None or trans is None:
|
||||
return 0
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||||
if at is None or at.value is None or at.attr is None:
|
||||
return 0
|
||||
# 解析类名(AnnotClassName;去模块前缀)
|
||||
class_nm_v: str = None
|
||||
if at.value.kind() == ast.ASTKind.Name:
|
||||
nm_v: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||||
if nm_v.id is not None:
|
||||
ve_v: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||||
trans.SymTab, nm_v.id)
|
||||
if ve_v is not None:
|
||||
class_nm_v = ve_v.AnnotClassName
|
||||
elif at.value.kind() == ast.ASTKind.Attribute:
|
||||
# 跨 Mixin:_resolve_attr_field_class 定义在 ExprGenMixin,经 gen 单例调用
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g_vta: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(
|
||||
t.CVoid(HandlesExpr._g_gen, t.CPtr))
|
||||
if g_vta is not None:
|
||||
class_nm_v = g_vta._resolve_attr_field_class(pool, trans, at.value)
|
||||
if class_nm_v is None:
|
||||
return 0
|
||||
fd_dot_v: str = string.strrchr(class_nm_v, '.')
|
||||
if fd_dot_v is not None:
|
||||
class_nm_v = fd_dot_v + 1
|
||||
if HandlesStruct.get_struct_type(class_nm_v) is None:
|
||||
return 0
|
||||
vm_idx_v: int = HandlesStruct.get_vtable_method_index(class_nm_v, at.attr)
|
||||
if vm_idx_v < 0:
|
||||
return 0
|
||||
# 解析 obj_ptr(对齐 get_attribute_ptr 前半段:Name 直接查 alloca)
|
||||
obj_ptr_v: llvmlite.Value | t.CPtr = None
|
||||
if at.value.kind() == ast.ASTKind.Name:
|
||||
obj_ptr_v = HandlesVar.lookup_var(
|
||||
trans.SymTab, ((ast.Name | t.CPtr)(at.value)).id)
|
||||
else:
|
||||
obj_ptr_v = HandlesExpr.translate_value(
|
||||
builder, pool, mod, at.value, None, 0, trans)
|
||||
if obj_ptr_v is None or obj_ptr_v.Ty is None:
|
||||
return 0
|
||||
# X|t.CPtr 变量(Ptr(Ptr))load 解引用取对象指针
|
||||
match obj_ptr_v.Ty:
|
||||
case llvmlite.LLVMType.Ptr(inner_v):
|
||||
match inner_v:
|
||||
case llvmlite.LLVMType.Ptr(_):
|
||||
obj_ptr_v = llvmlite.build_load(builder, inner_v, obj_ptr_v)
|
||||
case _:
|
||||
pass
|
||||
case _:
|
||||
pass
|
||||
if obj_ptr_v is None:
|
||||
return 0
|
||||
return self._write_vtable_slot(
|
||||
pool, builder, mod, obj_ptr_v, class_nm_v, vm_idx_v, rhs_val, trans)
|
||||
@@ -10,6 +10,12 @@ import lib.core.Gen.CallGenMixin as CallGenMixin
|
||||
import lib.core.Gen.CallGenBase as CallGenBase
|
||||
import lib.core.Gen.CallGenLeafKit as CallGenLeafKit
|
||||
import lib.core.Gen.CallGenCBuiltin as CallGenCBuiltin
|
||||
import lib.core.Gen.CallGenCtor as CallGenCtor
|
||||
import lib.core.Gen.CallGenCall as CallGenCall
|
||||
import lib.core.Gen.CallGenProp as CallGenProp
|
||||
import lib.core.Gen.CallGenFd as CallGenFd
|
||||
import lib.core.Gen.CallGenVt as CallGenVt
|
||||
import lib.core.Gen.CallGenVa as CallGenVa
|
||||
import lib.core.Gen.FuncGenMixin as FuncGenMixin
|
||||
import lib.core.Gen.ClassGenMixin as ClassGenMixin
|
||||
import lib.core.Gen.ImportsGenMixin as ImportsGenMixin
|
||||
@@ -38,6 +44,9 @@ class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin,
|
||||
StructGenMixin.StructGenMixin, ExprGenMixin.ExprGenMixin,
|
||||
CallGenMixin.CallGenMixin, CallGenBase.CallGenBase,
|
||||
CallGenLeafKit.CallGenLeafKit, CallGenCBuiltin.CallGenCBuiltin,
|
||||
CallGenCtor.CallGenCtor, CallGenCall.CallGenCall,
|
||||
CallGenProp.CallGenProp, CallGenFd.CallGenFd,
|
||||
CallGenVt.CallGenVt, CallGenVa.CallGenVa,
|
||||
FuncGenMixin.FuncGenMixin,
|
||||
ClassGenMixin.ClassGenMixin, ImportsGenMixin.ImportsGenMixin,
|
||||
StmtGenMixin.StmtGenMixin, AssignGenMixin.AssignGenMixin,
|
||||
|
||||
@@ -1816,3 +1816,54 @@ def _translate_isinstance(pool: memhub.MemBuddy | t.CPtr,
|
||||
if g is not None:
|
||||
return g._translate_isinstance(pool, builder, mod, obj_node, cls_node, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _is_sha1_mangled_call / _is_list_builtin_method / _translate_fakeduck_call /
|
||||
# _translate_super_call(阶段 B:CallGenMixin 拆分后顶层经委托调用这些方法)
|
||||
# ============================================================
|
||||
def _is_sha1_mangled_call(call_name: str) -> int:
|
||||
"""判断 call_name 是否为跨模块 Viper 函数(委托到 gen._is_sha1_mangled_call)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g._is_sha1_mangled_call(call_name)
|
||||
return 0
|
||||
|
||||
|
||||
def _is_list_builtin_method(class_name: str, method_name: str) -> int:
|
||||
"""判断 (class_name, method_name) 是否是 list 泛型内置方法(委托到 gen._is_list_builtin_method)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g._is_list_builtin_method(class_name, method_name)
|
||||
return 0
|
||||
|
||||
|
||||
def _translate_fakeduck_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
cls_name: str,
|
||||
method_name: str,
|
||||
cl: ast.Call | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""FakeDuck: str 变量方法调用(委托到 gen._translate_fakeduck_call)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g._translate_fakeduck_call(pool, builder, mod, cls_name, method_name, cl, trans)
|
||||
return None
|
||||
|
||||
|
||||
def _translate_super_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
cl: ast.Call | t.CPtr,
|
||||
method_name: str,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""super().method(args) → 父类方法静态调用(委托到 gen._translate_super_call)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g._translate_super_call(pool, builder, mod, cl, method_name, trans)
|
||||
return None
|
||||
Reference in new issue
Block a user