feat(TPC): 实现 isinstance 内建 + 多继承 this_adjust 字节偏移修复
isinstance 沿 class_parents 反向 BFS 收集目标类全部子类 vtable,运行时比较对象头部 vtable 指针,修复"目标是实际类祖先"场景误判;this_adjust 改用字节偏移(字段在子类与父类自身布局的字节差)修正第二父类方法体内二次 GEP 越界读。新增 Test/IsinstanceTest 覆盖 5 大场景 14 断言。
This commit is contained in:
1 parent
d2d319eb21
commit
8783340385
4 files changed
+363
-47
No files matched your search
@@ -0,0 +1,127 @@
|
||||
from stdint import *
|
||||
import t, c
|
||||
import testcheck
|
||||
|
||||
|
||||
# ============================================================
|
||||
# isinstance 内建函数测试(运行时 vtable 继承链比较)
|
||||
#
|
||||
# 场景覆盖:
|
||||
# 1. CVTable 自身/子类→基类
|
||||
# 2. 运行时多态(基类指针指向子类对象)
|
||||
# 3. 元组 (A, B)
|
||||
# 4. 多继承(AB 同时是 A 和 B 的实例)
|
||||
# 5. NoVTable 类(编译时静态判断)
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ========== CVTable 继承 ==========
|
||||
|
||||
@t.CVTable
|
||||
class Animal:
|
||||
Name: str
|
||||
|
||||
def __init__(self, name: str):
|
||||
self.Name = name
|
||||
|
||||
def speak(self) -> str:
|
||||
return "..."
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class Dog(Animal):
|
||||
def __init__(self, name: str):
|
||||
self.Name = name
|
||||
|
||||
def speak(self) -> str:
|
||||
return "Woof"
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class Cat(Animal):
|
||||
def speak(self) -> str:
|
||||
return "Meow"
|
||||
|
||||
|
||||
# ========== 多继承 ==========
|
||||
|
||||
@t.CVTable
|
||||
class A:
|
||||
a: CInt
|
||||
|
||||
def get_a(self) -> CInt:
|
||||
return self.a
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class B:
|
||||
b: CInt
|
||||
|
||||
def get_b(self) -> CInt:
|
||||
return self.b
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class AB(A, B):
|
||||
def __init__(self, a: CInt, b: CInt):
|
||||
self.a = a
|
||||
self.b = b
|
||||
|
||||
|
||||
# ========== NoVTable(编译时判断) ==========
|
||||
|
||||
@t.NoVTable
|
||||
class Plain:
|
||||
v: CInt
|
||||
|
||||
|
||||
def main() -> CInt | CExport:
|
||||
testcheck.begin("IsinstanceTest: isinstance 内建函数测试")
|
||||
|
||||
# --- 1. 自身类型 + 子类→基类 ---
|
||||
d: Dog | CPtr = Dog("dog")
|
||||
testcheck.check(isinstance(d, Dog) == 1, "isinstance(d, Dog) 自身 OK",
|
||||
"isinstance(d, Dog) FAILED")
|
||||
testcheck.check(isinstance(d, Animal) == 1, "isinstance(d, Animal) 子类→基类 OK",
|
||||
"isinstance(d, Animal) FAILED")
|
||||
testcheck.check(isinstance(d, Cat) == 0, "isinstance(d, Cat) 不匹配 OK",
|
||||
"isinstance(d, Cat) FAILED")
|
||||
|
||||
# --- 2. 运行时多态:基类指针指向子类对象 ---
|
||||
a: Animal | CPtr = (Animal | CPtr)(d)
|
||||
testcheck.check(isinstance(a, Dog) == 1,
|
||||
"isinstance(Animal*, Dog 对象) 运行时多态 OK",
|
||||
"isinstance(Animal*, Dog) FAILED")
|
||||
testcheck.check(isinstance(a, Animal) == 1,
|
||||
"isinstance(Animal*, Animal) 基类自身 OK",
|
||||
"isinstance(Animal*, Animal) FAILED")
|
||||
testcheck.check(isinstance(a, Cat) == 0,
|
||||
"isinstance(Animal*, Cat) 运行时 False OK",
|
||||
"isinstance(Animal*, Cat) FAILED")
|
||||
|
||||
# --- 3. 元组 ---
|
||||
testcheck.check(isinstance(d, (Cat, Dog)) == 1, "isinstance 元组命中 OK",
|
||||
"isinstance 元组 FAILED")
|
||||
testcheck.check(isinstance(d, (Cat, A)) == 0, "isinstance 元组未命中 OK",
|
||||
"isinstance 元组未命中 FAILED")
|
||||
|
||||
# --- 4. 多继承 ---
|
||||
ab: AB | CPtr = AB(1, 2)
|
||||
testcheck.check(isinstance(ab, A) == 1, "isinstance(AB, A) 多继承 OK",
|
||||
"isinstance(AB, A) FAILED")
|
||||
testcheck.check(isinstance(ab, B) == 1, "isinstance(AB, B) 多继承 OK",
|
||||
"isinstance(AB, B) FAILED")
|
||||
testcheck.check(isinstance(ab, Animal) == 0, "isinstance(AB, Animal) False OK",
|
||||
"isinstance(AB, Animal) FAILED")
|
||||
testcheck.check(ab.get_a() == 1 and ab.get_b() == 2, "AB 字段/方法正常 OK",
|
||||
"AB 字段/方法 FAILED")
|
||||
|
||||
# --- 5. NoVTable(编译时静态判断) ---
|
||||
p: Plain | CPtr = Plain()
|
||||
p.v = 42
|
||||
testcheck.check(isinstance(p, Plain) == 1, "isinstance NoVTable 编译时 OK",
|
||||
"isinstance NoVTable FAILED")
|
||||
testcheck.check(p.v == 42, "NoVTable 字段正常 OK", "NoVTable 字段 FAILED")
|
||||
|
||||
testcheck.ok("isinstance 全部测试完成")
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "IsinstanceTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"],
|
||||
"output": "IsinstanceTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -166,38 +166,11 @@ class ExprBuiltinHandle(BaseHandle):
|
||||
elif FuncName == 'input':
|
||||
return self._HandleInputLlvm(Node)
|
||||
elif FuncName == 'isinstance':
|
||||
# isinstance(obj, Type) — 静态类型系统下编译时解析
|
||||
# TransPyC 是静态类型系统,运行时无 RTTI。
|
||||
# 对于编译时已知类型,若变量类型是目标类型的子类则生成 true,否则 false。
|
||||
# 若无法确定(如基类指针指向子类),保守生成 false。
|
||||
# 注意:这主要让编译时辅助方法(如 c.py 中的 Asm._parse_asm_descr)能通过编译,
|
||||
# 这些方法不在运行时被调用,行为不正确不影响程序。
|
||||
if len(Node.args) >= 2:
|
||||
ObjVal: ir.Value | None = self.HandleExprLlvm(Node.args[0])
|
||||
TypeNode: ast.expr = Node.args[1]
|
||||
TargetClassName: str = ''
|
||||
if isinstance(TypeNode, ast.Name):
|
||||
TargetClassName = TypeNode.id
|
||||
elif isinstance(TypeNode, ast.Attribute):
|
||||
TargetClassName = TypeNode.attr
|
||||
if ObjVal is not None and TargetClassName:
|
||||
ObjType: ir.Type = ObjVal.type
|
||||
# 解引用指针获取 pointee 类型
|
||||
if isinstance(ObjType, ir.PointerType):
|
||||
ObjType = ObjType.pointee
|
||||
# 检查 pointee 是否是目标结构体类型
|
||||
if isinstance(ObjType, ir.IdentifiedStructType):
|
||||
ObjStructName: str = getattr(ObjType, 'name', '')
|
||||
ShortName: str = ObjStructName.split('.')[-1] if '.' in ObjStructName else ObjStructName
|
||||
if ShortName == TargetClassName:
|
||||
return ir.Constant(ir.IntType(1), 1)
|
||||
# 检查 Gen.var_struct_class
|
||||
if isinstance(Node.args[0], ast.Name):
|
||||
VarClassName: str | None = Gen.var_struct_class.get(Node.args[0].id)
|
||||
if VarClassName == TargetClassName:
|
||||
return ir.Constant(ir.IntType(1), 1)
|
||||
return ir.Constant(ir.IntType(1), 0)
|
||||
return ir.Constant(ir.IntType(1), 0)
|
||||
# isinstance(obj, Type) — 运行时 vtable 继承链比较(2026-08-10)
|
||||
# CVTable 对象头部 vtable 指针唯一标识类;isinstance = 对象 vtable
|
||||
# ∈ 目标类及其 MRO 祖先的 vtable 集合(运行时真多态判断)。
|
||||
# NoVTable/基础类型/无法解析时回退编译时静态判断。
|
||||
return self._HandleIsinstanceLlvm(Node)
|
||||
elif FuncName == 'ord':
|
||||
if Node.args:
|
||||
return self._HandleOrdLlvm(Node.args[0])
|
||||
@@ -228,6 +201,152 @@ class ExprBuiltinHandle(BaseHandle):
|
||||
return self._HandleTypeLlvm(Node)
|
||||
return None
|
||||
|
||||
# ============================================================
|
||||
# isinstance - 运行时 vtable 子类集合比较(2026-08-10)
|
||||
#
|
||||
# CVTable 对象头部 vtable 指针唯一标识对象**实际类**(创建对象时写入
|
||||
# 实际类的 vtable)。isinstance(obj, Cls) 语义 = Cls 是实际类的祖先
|
||||
# (实际类 == Cls 或继承自 Cls)。运行时只能拿到实际类 vtable 地址,
|
||||
# 无法向上推导祖先链,因此在编译期沿 class_parents 反向 BFS 枚举
|
||||
# Cls 的全部已知子类(含自身),比较 obj->vtable ∈ {Cls 子类 vtable}。
|
||||
# class_parents 由 Phase1 声明阶段对全部可达文件填充,子类集合完整。
|
||||
# NoVTable / 基础类型 / 无 vtable 可解析 → 回退编译时静态判断。
|
||||
# ============================================================
|
||||
def _HandleIsinstanceLlvm(self, Node: ast.Call) -> ir.Value:
|
||||
"""isinstance(obj, Cls):运行时 vtable 继承链比较(元组 Cls 支持 or 合并)"""
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
if len(Node.args) < 2:
|
||||
return ir.Constant(ir.IntType(1), 0)
|
||||
ObjVal: ir.Value | None = self.HandleExprLlvm(Node.args[0])
|
||||
if ObjVal is None:
|
||||
return ir.Constant(ir.IntType(1), 0)
|
||||
ClsNames: list[str] = self._ExtractIsinstanceClassNames(Node.args[1])
|
||||
if not ClsNames:
|
||||
return ir.Constant(ir.IntType(1), 0)
|
||||
Res: ir.Value | None = None
|
||||
for CN in ClsNames:
|
||||
R: ir.Value = self._IsinstanceOne(Gen, ObjVal, CN)
|
||||
if Res is None:
|
||||
Res = R
|
||||
else:
|
||||
Res = Gen.builder.or_(Res, R, name="isinstance_or")
|
||||
return Res if Res is not None else ir.Constant(ir.IntType(1), 0)
|
||||
|
||||
def _ExtractIsinstanceClassNames(self, TypeNode: ast.expr) -> list[str]:
|
||||
"""从 isinstance 第二参数提取类名列表(支持单类 / (A, B) 元组 / 泛型特化)"""
|
||||
if isinstance(TypeNode, ast.Tuple):
|
||||
names: list[str] = []
|
||||
for elt in TypeNode.elts:
|
||||
names.extend(self._ExtractIsinstanceClassNames(elt))
|
||||
return names
|
||||
if isinstance(TypeNode, ast.Name):
|
||||
return [TypeNode.id]
|
||||
if isinstance(TypeNode, ast.Attribute):
|
||||
return [TypeNode.attr]
|
||||
if isinstance(TypeNode, ast.Subscript):
|
||||
spec = self.Trans.ExprCallHandle._ResolveGenericSlice(TypeNode)
|
||||
if spec:
|
||||
return [spec]
|
||||
return []
|
||||
|
||||
def _IsinstanceOne(self, Gen, ObjVal: ir.Value, ClassName: str) -> ir.Value:
|
||||
"""单类判断:优先运行时 vtable 比较,失败回退编译时静态判断"""
|
||||
VtableAddrs: list = self._CollectSubclassVtables(Gen, ClassName)
|
||||
if VtableAddrs:
|
||||
try:
|
||||
return self._EmitVtableCompare(Gen, ObjVal, VtableAddrs)
|
||||
except Exception:
|
||||
pass
|
||||
return self._IsinstanceCompileTime(Gen, ObjVal, ClassName)
|
||||
|
||||
def _CollectSubclassVtables(self, Gen, ClassName: str) -> list:
|
||||
"""收集目标类及**所有已知子类**的 vtable 全局地址(沿 class_parents 反向 BFS)。
|
||||
|
||||
isinstance(obj, Cls) 的正确语义:obj 头部 vtable 标识对象实际类 C,
|
||||
判断 Cls 是否 ∈ C 的祖先链。运行时无法从 C_vtable 向上推导祖先,
|
||||
因此在编译期反向枚举 Cls 的子树(含 Cls 自身)的 vtable 地址,
|
||||
运行时比较 obj->vtable ∈ 该集合(C 是 Cls 子类 → 命中)。
|
||||
"""
|
||||
addrs: list = []
|
||||
# 反向子类表:父类名 -> [子类名...](class_parents 由 Phase1 全量填充)
|
||||
children: dict[str, list[str]] = {}
|
||||
for cn, parents in getattr(Gen, 'class_parents', {}).items():
|
||||
for p in parents:
|
||||
children.setdefault(p, []).append(cn)
|
||||
queue: list[str] = [ClassName]
|
||||
seen: set[str] = set()
|
||||
while queue:
|
||||
cn: str = queue.pop(0)
|
||||
if cn in seen:
|
||||
continue
|
||||
seen.add(cn)
|
||||
vt = self._ResolveVtableAddr(Gen, cn)
|
||||
if vt is not None:
|
||||
addrs.append(vt)
|
||||
for ch in children.get(cn, []):
|
||||
if ch not in seen:
|
||||
queue.append(ch)
|
||||
return addrs
|
||||
|
||||
def _ResolveVtableAddr(self, Gen, ClassName: str):
|
||||
"""解析类 ClassName 的 vtable 全局地址(本地 Vtables / 跨模块外部引用),
|
||||
无 vtable(NoVTable / 未注册)返回 None。
|
||||
"""
|
||||
vt = Gen.Vtables.get(ClassName) if hasattr(Gen, 'Vtables') else None
|
||||
if vt is not None:
|
||||
return vt
|
||||
sha1_map: dict = getattr(Gen, 'class_sha1_map', {})
|
||||
sha1 = sha1_map.get(ClassName)
|
||||
if not sha1:
|
||||
return None
|
||||
vname: str = f"{sha1}.{ClassName}_Vtable"
|
||||
if vname in Gen.module.globals:
|
||||
return Gen.module.globals[vname]
|
||||
try:
|
||||
ext = ir.GlobalVariable(Gen.module, ir.ArrayType(ir.PointerType(ir.IntType(8)), 1), name=vname)
|
||||
ext.linkage = 'external'
|
||||
return ext
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def _EmitVtableCompare(self, Gen, ObjVal: ir.Value, VtableAddrs: list) -> ir.Value:
|
||||
"""运行时:读对象头部 vtable 指针,与集合中每个 vtable 地址比较"""
|
||||
ObjPtr: ir.Value = ObjVal
|
||||
if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
|
||||
# 二级指针(变量 alloca / 联合 Class|t.CPtr)→ 先 load 出对象指针
|
||||
ObjPtr = Gen._load(ObjVal, name="isinstance_load")
|
||||
if not isinstance(ObjPtr.type, ir.PointerType):
|
||||
return self._IsinstanceCompileTime(Gen, ObjVal, '')
|
||||
ObjAsVt: ir.Value = Gen.builder.bitcast(ObjPtr, ir.PointerType(ir.PointerType(ir.IntType(8))), name="isinstance_cast")
|
||||
VtPtr: ir.Value = Gen._load(ObjAsVt, name="isinstance_vt")
|
||||
Res: ir.Value | None = None
|
||||
for addr in VtableAddrs:
|
||||
AddrI8: ir.Value = Gen.builder.bitcast(addr, ir.PointerType(ir.IntType(8)), name="vt_addr")
|
||||
Cmp: ir.Value = Gen.builder.icmp_unsigned('==', VtPtr, AddrI8, name="isinstance_cmp")
|
||||
if Res is None:
|
||||
Res = Cmp
|
||||
else:
|
||||
Res = Gen.builder.or_(Res, Cmp, name="isinstance_or")
|
||||
return Res if Res is not None else ir.Constant(ir.IntType(1), 0)
|
||||
|
||||
def _IsinstanceCompileTime(self, Gen, ObjVal: ir.Value, ClassName: str) -> ir.Value:
|
||||
"""编译时静态判断:obj 静态类型 == ClassName 或其 MRO 后代 → 1,否则 0"""
|
||||
if ClassName:
|
||||
ObjType: ir.Type = ObjVal.type
|
||||
if isinstance(ObjType, ir.PointerType):
|
||||
ObjType = ObjType.pointee
|
||||
if isinstance(ObjType, ir.IdentifiedStructType):
|
||||
ShortName: str = Gen._extract_short_name(ObjType.name)
|
||||
mro: list = Gen._get_mro_chain(ClassName) if hasattr(Gen, '_get_mro_chain') else [ClassName]
|
||||
if ShortName == ClassName or ShortName in mro:
|
||||
return ir.Constant(ir.IntType(1), 1)
|
||||
# obj 是 ClassName 的子类(obj 的 MRO 含 ClassName)
|
||||
obj_mro: list = Gen._get_mro_chain(ShortName) if hasattr(Gen, '_get_mro_chain') else []
|
||||
if ClassName in obj_mro:
|
||||
return ir.Constant(ir.IntType(1), 1)
|
||||
# 无法判断 → 保守 false
|
||||
return ir.Constant(ir.IntType(1), 0)
|
||||
|
||||
def _HandlePrintLlvm(self, Node: ast.Call) -> ir.Value | None:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
printf_func: ir.Function = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
|
||||
|
||||
@@ -2369,22 +2369,57 @@ class ExprCallHandle(BaseHandle):
|
||||
# 失败时恢复 declare_only 标记,避免后续调用跳过补发
|
||||
Gen._generic_class_specializations[spec_key] = (cached_name, True)
|
||||
|
||||
def _compute_field_byte_offset(self, Gen: LlvmGeneratorMixin, ClassName: str, field_name: str) -> int | None:
|
||||
"""计算字段在 struct 中的字节偏移(按 LLVM 布局含对齐)。
|
||||
|
||||
遍历 struct elements 带对齐累加(与 _get_struct_size/_get_align 一致)。
|
||||
有 vtable 的类 struct 首元素为 vtable 指针(i8*),class_members 不含它。
|
||||
返回 None 表示无法计算(struct 未定义 / 字段不存在)。
|
||||
"""
|
||||
st = Gen.structs.get(ClassName)
|
||||
if not st or not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
|
||||
return None
|
||||
members: list = Gen.class_members.get(ClassName, [])
|
||||
has_vtable: bool = (ClassName in Gen.class_vtable
|
||||
or ClassName in Gen._cross_module_vtable_classes)
|
||||
base: int = 1 if has_vtable else 0
|
||||
idx: int | None = None
|
||||
for i, (name, _) in enumerate(members):
|
||||
if name == field_name:
|
||||
idx = base + i
|
||||
break
|
||||
if idx is None or idx >= len(st.elements):
|
||||
return None
|
||||
offset: int = 0
|
||||
for i in range(idx):
|
||||
et = st.elements[i]
|
||||
align: int = Gen._get_align(et)
|
||||
size: int = Gen._get_struct_size(et)
|
||||
if align > 1:
|
||||
offset = ((offset + align - 1) // align) * align
|
||||
offset += size
|
||||
align = Gen._get_align(st.elements[idx])
|
||||
if align > 1:
|
||||
offset = ((offset + align - 1) // align) * align
|
||||
return offset
|
||||
|
||||
def _adjust_this_for_inherited_method(self, Gen: LlvmGeneratorMixin, ObjVal: ir.Value,
|
||||
ClassName: str, method_anc: str | None) -> ir.Value:
|
||||
"""多继承 this 调整(与 TPV _translate_method_call 一致):
|
||||
|
||||
继承方法定义在"无 vtable 的父类"且该父类字段区在子类中偏移 > 0 时
|
||||
(如 C(A,B).get_b,B 的字段区从 b 开始),父类方法按自身布局读
|
||||
self.field@0 会读到前面父类的字段。调整:GEP 到父类第一个用户字段
|
||||
在子类中的位置(索引 > 0),bitcast 成父类指针作为 self。
|
||||
有 vtable 的父类布局是子类前缀(vptr 共享),self 无需调整。
|
||||
继承方法体按"定义类自身布局"读 self 字段(如 B.get_b 内
|
||||
GEP(self_B, [0, 1]),字节偏移为 B 布局中 b 的 offset 8)。父类字段区
|
||||
在子类中的**字节偏移**可能不同(如 AB={i8*,a@8,b@12} 中 b 偏移 12),
|
||||
self 需按字节差前移,使父类方法内二次 GEP 恰好落到子类字段。
|
||||
|
||||
修复(2026-08-10):字段索引法在"父类与子类元素大小不同"时错位
|
||||
(GEP 索引按元素个数计,非字节等价)。改用字节偏移:
|
||||
delta = 字段在子类中字节偏移 − 字段在父类自身布局中字节偏移
|
||||
delta==0(第一父类,字段区前缀对齐)无需调整;delta>0 时按字节
|
||||
GEP 到父类字段区在子类中的等效基址,再 bitcast 成父类指针。
|
||||
"""
|
||||
if method_anc is None or method_anc == ClassName:
|
||||
return ObjVal
|
||||
anc_has_vtable: bool = (method_anc in Gen.class_vtable
|
||||
or method_anc in Gen._cross_module_vtable_classes)
|
||||
if anc_has_vtable:
|
||||
return ObjVal
|
||||
anc_members: list = Gen.class_members.get(method_anc, [])
|
||||
if not anc_members:
|
||||
return ObjVal
|
||||
@@ -2396,15 +2431,21 @@ class ExprCallHandle(BaseHandle):
|
||||
break
|
||||
if first_field_name is None:
|
||||
return ObjVal
|
||||
field_idx: int | None = Gen._get_member_offset(first_field_name, ClassName)
|
||||
if field_idx is None or field_idx <= 0:
|
||||
sub_off: int | None = self._compute_field_byte_offset(Gen, ClassName, first_field_name)
|
||||
if sub_off is None:
|
||||
return ObjVal
|
||||
anc_off: int | None = self._compute_field_byte_offset(Gen, method_anc, first_field_name)
|
||||
if anc_off is None:
|
||||
return ObjVal
|
||||
delta: int = sub_off - anc_off
|
||||
if delta <= 0:
|
||||
return ObjVal
|
||||
if method_anc not in Gen.structs:
|
||||
return ObjVal
|
||||
adj: ir.Value = Gen.builder.gep(
|
||||
ObjVal,
|
||||
[ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), field_idx)],
|
||||
name=f"this_adjust_{method_anc}")
|
||||
obj_i8: ir.Value = Gen.builder.bitcast(ObjVal, ir.PointerType(ir.IntType(8)),
|
||||
name=f"this_adjust_i8_{method_anc}")
|
||||
adj: ir.Value = Gen.builder.gep(obj_i8, [ir.Constant(ir.IntType(64), delta)],
|
||||
name=f"this_adjust_{method_anc}")
|
||||
return Gen.builder.bitcast(adj, ir.PointerType(Gen.structs[method_anc]),
|
||||
name=f"this_adjust_cast_{method_anc}")
|
||||
|
||||
|
||||
Reference in new issue
Block a user