diff --git a/App/lib/Stub/StubGen/VpiReader.vp b/App/lib/Stub/StubGen/VpiReader.vp index 2510a88..a3702f7 100644 --- a/App/lib/Stub/StubGen/VpiReader.vp +++ b/App/lib/Stub/StubGen/VpiReader.vp @@ -1,5 +1,6 @@ import lib.core.Gen.GenApi as GenApi import lib.core.Gen.GenTypes as GenTypes +import lib.core.CompilerFactory as CompilerFactory import t, c from stdint import * import ast @@ -911,6 +912,13 @@ def _resolve_single_vpi_type_str(pool: memhub.MemBuddy | t.CPtr, # t.XXX / c.XXX 内置类型映射 if string.strncmp(seg, "t.", 2) == 0 or string.strncmp(seg, "c.", 2) == 0: attr_nm: str = seg + 2 + # t.CExport:导出标记,非真实类型。定义侧 FuncGenDef 已特判 + # CExport → Void(返回空),vpi 返回注解缓存原样缓存 "t.CExport", + # 调用方解析必须同样归一 Void,否则 vpi 缓存 miss → 跨模块函数 + # 返回类型无法精确获取 fail-fast 误报(VKernel mm.free -> t.CExport + # "1fdad1c76fb116bc.free 返回类型无法精确获取" 根因)。 + if string.strcmp(attr_nm, "CExport") == 0: + return llvmlite.Void(pool) mapped_ty: llvmlite.LLVMType | t.CPtr = GenApi.map_t_type(pool, attr_nm) if mapped_ty is not None: return mapped_ty @@ -922,11 +930,23 @@ def _resolve_single_vpi_type_str(pool: memhub.MemBuddy | t.CPtr, mod_struct_ty: llvmlite.LLVMType | t.CPtr = GenApi.get_struct_type(cls_nm2) if mod_struct_ty is not None: return mod_struct_ty + # 枚举兜底:t.CEnum 注册在独立 EnumTable(EnumEntry),不进 StructTable, + # get_struct_type 查不到。如 fat32.close -> types.FRESULT(FRESULT 是枚举), + # struct 落空必须回退枚举表取 BaseTy(通常 i32)。否则 vpi 返回注解解析 + # 失败 → 跨模块函数返回类型无法精确获取 → text.ll 缺失(依赖环)时 + # 永久 pending(VKernel fat32→sched→process→fat32 Phase A 死锁根因)。 + mod_enum_ty: llvmlite.LLVMType | t.CPtr = GenApi.get_enum_base_type(cls_nm2) + if mod_enum_ty is not None: + return mod_enum_ty return None # 裸类名 → 全局 struct 注册表 bare_struct_ty: llvmlite.LLVMType | t.CPtr = GenApi.get_struct_type(seg) if bare_struct_ty is not None: return bare_struct_ty + # 裸枚举名 → EnumTable 兜底(同上:枚举不在 StructTable) + bare_enum_ty: llvmlite.LLVMType | t.CPtr = GenApi.get_enum_base_type(seg) + if bare_enum_ty is not None: + return bare_enum_ty # 裸 typedef 名(如 VOIDPTR) mapped_bare: llvmlite.LLVMType | t.CPtr = GenApi.map_t_type(pool, seg) if mapped_bare is not None: @@ -1333,8 +1353,6 @@ def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy | t.CPtr, sr_len_src: t.CSizeT = string.strlen(stub_rel_src) if sr_len_src > 3 and string.strncmp(stub_rel_src + sr_len_src - 3, ".vp", 3) == 0: sr_len_src -= 3 - elif sr_len_src > 3 and string.strncmp(stub_rel_src + sr_len_src - 3, ".py", 3) == 0: - sr_len_src -= 3 if sr_len_src > 0: src_mod_buf: str = stdlib.malloc(sr_len_src + 1) if src_mod_buf is not None: @@ -1357,6 +1375,47 @@ def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy | t.CPtr, funcs_ptr: GenTypes.FuncEntry | t.CPtr = trans._funcs max_funcs: int = 1024 + # ============================================================ + # 第一遍:先注册所有 ClassDef(含字段 + 方法 declare),再处理 + # FunctionDef/AnnAssign。此前单遍顺序处理,类定义位于全局变量之后时 + # (如 devfs.vp:`directories: t.CArray[devfs_directory, MAX_DIRECTORIES]` + # 在 `class devfs_directory` 之前),AnnAssign 全局变量解析裸类名时类 + # 未注册 → CArray 元素解析失败 fatal(VKernel PhaseA 根因)。 + # ============================================================ + i0: t.CSizeT + for i0 in range(n): + child0: ast.AST | t.CPtr = ch.get(i0) + if child0 is None: + continue + if child0.kind() != ast.ASTKind.ClassDef: + continue + class_cd0: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child0) + if class_cd0 is None or class_cd0.name is None: + continue + cls_name_v0: str = class_cd0.name + # 泛型类(class X[T])跳过:stub 模板签名含类级类型参数 T,注入时 + # T 无法确定;特化方法 define 已在 Phase1 生成,无需 stub 模板 declare。 + tp_stub0: list[str] | t.CPtr = class_cd0.type_params + if tp_stub0 is not None and len(tp_stub0) > 0: + continue + _inject_class_struct_declare(pool, mod, class_cd0, cls_name_v0, trans, + src_sha1, imported_modules, from_imports) + cls_children0: list[ast.AST | t.CPtr] | t.CPtr = class_cd0.children + if cls_children0 is not None: + cn20: t.CSizeT = len(cls_children0) + for ci20 in range(cn20): + m_child0: ast.AST | t.CPtr = cls_children0.get(ci20) + if m_child0 is None: + continue + if m_child0.kind() != ast.ASTKind.FunctionDef: + continue + m_fd0: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(m_child0) + if m_fd0 is None or m_fd0.name is None: + continue + _inject_method_declare(pool, mod, m_fd0, cls_name_v0, trans, + src_sha1, imported_modules, from_imports, + i32_ty, i8_ptr_ty, funcs_ptr, max_funcs) + i: t.CSizeT for i in range(n): child: ast.AST | t.CPtr = ch.get(i) @@ -1381,49 +1440,52 @@ def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy | t.CPtr, aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(child) if aa is None: continue + if aa.target is not None and aa.target.kind() == ast.ASTKind.Name: + dbg_tn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + if dbg_tn.id is not None and dbg_tn.id[0] != '\0': # 存疑 + if string.strcmp(dbg_tn.id, "irq_handler_t") == 0 \ + or string.strcmp(dbg_tn.id, "gdt") == 0 \ + or string.strcmp(dbg_tn.id, "KBD_BUF_SIZE") == 0: + dbg_ct: int = GenApi._is_ctypedef_annotation(aa.annotation) + dbg_cd: int = GenApi.is_cdefine_annotation(aa.annotation) if GenApi._is_ctypedef_annotation(aa.annotation) != 0: _register_ctypedef_from_annassign(pool, aa) + elif GenApi.is_cdefine_annotation(aa.annotation) != 0: + # vpi 里 CDefine 定义(如 keyboard.vp 的 KBD_BUF_SIZE: t.CDefine = 1024) + # 注册到当前文件 CDefine 表,供同 vpi 后续 t.CArray count 引用解析 + # (否则跨模块 count 查找 [CDEF-MISS] fail-fast,VKernel PhaseA 根因) + if aa.target is not None and aa.target.kind() == ast.ASTKind.Name \ + and aa.value is not None: + cdef_tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) + if cdef_tgt.id is not None: + # 字符串 CDefine(版本号等)跳过:extract_cdefine_int_value + # 对字符串常量 fail-fast,且 count 引用只关心整数 CDefine + cdef_is_str: int = 0 + cdef_is_float: int = 0 + cdef_float_val: double = 0.0 + if aa.value.kind() == ast.ASTKind.Constant: + cn_v: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value) + if cn_v.const_kind == ast.CONST_STR: + cdef_is_str = 1 + elif cn_v.const_kind == ast.CONST_FLOAT: + cdef_is_float = 1 + cdef_float_val = cn_v.float_val + if cdef_is_str == 0 and cdef_is_float != 0: + # 浮点 CDefine(如 FRAGMENTATION_THRESHOLD: t.CDefine = 0.7) + # 用 register_cdefine_double 注册(走整数提取会 fail-fast) + GenApi.register_cdefine_double(pool, cdef_tgt.id, cdef_float_val) + elif cdef_is_str == 0: + cdef_val: t.CInt64T = GenApi.extract_cdefine_int_value(aa.value) + GenApi.register_cdefine_constant(pool, cdef_tgt.id, cdef_val) else: _inject_global_variable_declare(pool, mod, aa, trans, stub_imported_modules, stub_from_imports, i32_ty, i8_ptr_ty, src_sha1) continue - # ClassDef → 递归注入类内方法(如 MemBuddy.__init__/alloc) - # 方法 declare 使用 {sha1}.{ClassName}.{method} 混淆名, - # 参数类型从 vpi 注解解析(避免调用时 _ensure_method_declare 用实参类型 - # 创建错误 declare,如 size: t.CSizeT 被写成 i32 而非 i64) - if kd == ast.ASTKind.ClassDef: - class_cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child) - if class_cd is None or class_cd.name is None: - continue - cls_name_v: str = class_cd.name - # 泛型类(class X[T])跳过方法 declare 注入:stub 模板签名含类级 - # 类型参数 T(如 ndarray[T].__add__ 的返回 ndarray[T] | t.CPtr), - # 注入时 T 无法确定具体类型,直接解析会触发 - # _specialize_generic_class("ndarray", ["T"]) 错误特化 - # (Phase2 翻译 App 文件注入 numpy stub 时崩溃)。 - # 具体特化的方法 define 已在 Phase1 生成,跨模块调用按特化类名 - # (ndarray[t.CDouble].__add__)查找命中,无需 stub 模板 declare。 - tp_stub: list[str] | t.CPtr = class_cd.type_params - if tp_stub is not None and len(tp_stub) > 0: - continue - cls_children: list[ast.AST | t.CPtr] | t.CPtr = class_cd.children - if cls_children is not None: - cn2: t.CSizeT = len(cls_children) - for ci2 in range(cn2): - m_child: ast.AST | t.CPtr = cls_children.get(ci2) - if m_child is None: - continue - if m_child.kind() != ast.ASTKind.FunctionDef: - continue - m_fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(m_child) - if m_fd is None or m_fd.name is None: - continue - _inject_method_declare(pool, mod, m_fd, cls_name_v, trans, - src_sha1, imported_modules, from_imports, - i32_ty, i8_ptr_ty, funcs_ptr, max_funcs) - continue + # ClassDef → 已在第一遍统一注册(含字段 + 方法 declare),此处跳过 + # (原单遍顺序处理在类定义位于全局变量之后时,AnnAssign 全局变量 + # 解析裸类名找不到类 → CArray 元素解析失败 fatal,见上方第一遍注释) # Import/ImportFrom → 跳过 # (import 不需要处理) @@ -1436,6 +1498,118 @@ def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy | t.CPtr, return 1 +# ============================================================ +# _inject_class_struct_declare - 从 vpi ClassDef 注册类为 struct 类型 +# +# 背景:vpi stub 注入(ParseVpiIntoModule)此前只注入类内方法 declare, +# 不注册类本身 → 严格模式下(strict_mode:true)同一 vpi 内后续 AnnAssign +# 全局变量的裸类名注解(如 gdt.vp 的 `gdt: t.CArray[gdt_entry, 7]` 元素 +# gdt_entry)is_struct_visible=0 → resolve_annotation_type 返回 None → +# TypeGenResolve CArray 元素解析失败 fatal(ViperOS VKernel apic.vp 编译 +# 根因)。源模块编译时 ClassGenDef.translate_class_def 会 add_visible_struct +# + register_struct(含字段),vpi 注入缺同一注册 → 此处补齐: +# 1. 已注册(find_struct_by_module 按 name+sha1 命中,含源模块编译时注册) +# → 仅 add_visible_struct 标记当前文件可见 +# 2. 未注册 → 解析字段类型 → 创建命名 StructType("sha1.ClassName") → +# register_struct + add_visible_struct +# 字段解析失败不 fatal(不注册该类,留给源模块编译注册;若 vpi 内后续 +# 裸类名引用它则由调用侧 fail-fast 暴露)。 +# ============================================================ +def _inject_class_struct_declare(pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_cd: ast.ClassDef | t.CPtr, + cls_name: str, + trans: HT.Translator | t.CPtr, + src_sha1: str, + imported_modules: str, + from_imports: str) -> int: + """从 vpi ClassDef 注册类为 struct 类型(含字段),使同 vpi 内裸类名注解可解析""" + if pool is None or mod is None or class_cd is None or cls_name is None: + return 0 + # 1. 已注册检查(含源模块编译时注册的 entry):仅标记可见,避免重复注册 + if src_sha1 is not None and src_sha1[0] != '\0': + existing_c: GenTypes.StructEntry | t.CPtr = GenApi.find_struct_by_module(cls_name, src_sha1) + if existing_c is not None and existing_c.Ty is not None: + GenApi.add_visible_struct(pool, cls_name) + return 1 + # 2. 收集字段类型(AnnAssign 子节点,仿 ClassGenDef.translate_class_def) + field_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX) + field_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX) + if field_names_buf is None or field_types_buf is None: + return 0 + string.memset(field_names_buf, 0, 8 * GenTypes.FIELD_MAX) + string.memset(field_types_buf, 0, 8 * GenTypes.FIELD_MAX) + field_count: int = 0 + cls_children_c: list[ast.AST | t.CPtr] | t.CPtr = class_cd.children + if cls_children_c is not None: + cn_c: t.CSizeT = len(cls_children_c) + for ci_c in range(cn_c): + m_child_c: ast.AST | t.CPtr = cls_children_c.get(ci_c) + if m_child_c is None: + continue + if m_child_c.kind() != ast.ASTKind.AnnAssign: + continue + m_aa_c: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(m_child_c) + if m_aa_c is None or m_aa_c.target is None: + continue + if m_aa_c.target.kind() != ast.ASTKind.Name: + continue + m_tgt_c: ast.Name | t.CPtr = (ast.Name | t.CPtr)(m_aa_c.target) + if m_tgt_c.id is None: + continue + field_ty_c: llvmlite.LLVMType | t.CPtr = GenApi.resolve_annotation_type( + pool, m_aa_c.annotation, imported_modules, from_imports, trans, 0) + if field_ty_c is None: + # 字段类型解析失败:不注册该类(留给源模块编译注册),不 fatal + return 0 + if field_count < GenTypes.FIELD_MAX: + field_names_buf[field_count] = t.CSizeT(m_tgt_c.id) + field_types_buf[field_count] = t.CSizeT(field_ty_c) + field_count += 1 + # 3. 构建 ParamNode 链表 + first_node_c: llvmlite.ParamNode | t.CPtr = None + prev_node_c: llvmlite.ParamNode | t.CPtr = None + for fi_c in range(field_count): + fty_c: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)( + t.CVoid(field_types_buf[fi_c], t.CPtr)) + pnode_c: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__()) + if pnode_c is None: + continue + string.memset(pnode_c, 0, llvmlite.ParamNode.__sizeof__()) + pnode_c.Ty = fty_c + if first_node_c is None: + first_node_c = pnode_c + if prev_node_c is not None: + prev_node_c.Next = pnode_c + prev_node_c = pnode_c + # 4. 命名结构体类型名 "sha1.ClassName"(与定义侧 ClassGenDef 一致) + type_name_c: str = cls_name + if src_sha1 is not None and src_sha1[0] != '\0': + name_buf_c: str = pool.alloc(64) + if name_buf_c is not None: + viperlib.snprintf(name_buf_c, 64, "%s.%s", src_sha1, cls_name) + type_name_c = name_buf_c + struct_ty_c: llvmlite.LLVMType | t.CPtr = llvmlite.Struct( + pool, first_node_c, field_count, type_name_c) + if struct_ty_c is None: + return 0 + # 5. StdlibAlloc(Phase B)时深拷贝到 perm_pool,跨文件 reset 存活 + # (对齐 ClassGenDef.translate_class_def L489-494) + if GenApi.get_stdlib_alloc() != 0: + st_copy_c: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( + CompilerFactory.get_perm_pool(), struct_ty_c) + if st_copy_c is not None: + struct_ty_c = st_copy_c + # 6. 注册到当前模块(输出类型定义行)+ 全局 StructTable + 可见性 + llvmlite.module_add_named_type(mod, pool, struct_ty_c) + entry_c: GenTypes.StructEntry | t.CPtr = GenApi.register_struct( + pool, cls_name, struct_ty_c, src_sha1) + if entry_c is None: + return 0 + GenApi.add_visible_struct(pool, cls_name) + return 1 + + # ============================================================ # _inject_global_variable_declare - 从 vpi AnnAssign 创建模块级全局变量 declare # @@ -1470,7 +1644,14 @@ def _inject_global_variable_declare(pool: memhub.MemBuddy | t.CPtr, # 注:a42923c 曾把此处写成未定义变量 gv_name_m(笔误,mangle 未实现), # 导致注入空名 @ = external global → llc "expected top-level entity"。 gv_name_m: str = gname_v - if src_sha1 is not None and src_sha1[0] != '\0': + # CExport 全局:定义端用裸名(@gp),stub 声明必须同步裸名,否则跨模块 + # 引用生成 @sha1.gp → 与定义端 @gp 不匹配 → ld.lld undefined symbol + # (gdt.vp gdt/gp、idt.vp idt、sched.vp _sched_ptr/_switch_*_rsp、 + # coroutine.vp _coro_*、process.vp _saved_cr3 等 CExport 全局根因)。 + is_gv_cexport: int = 0 + if aa.annotation is not None: + is_gv_cexport = GenApi.has_decorator_marker(aa.annotation, "CExport") + if src_sha1 is not None and src_sha1[0] != '\0' and is_gv_cexport == 0: ml_v: t.CSizeT = string.strlen(src_sha1) + 1 + string.strlen(gname_v) + 1 gv_name_m = pool.alloc(ml_v) if gv_name_m is not None: @@ -1491,7 +1672,13 @@ def _inject_global_variable_declare(pool: memhub.MemBuddy | t.CPtr, gv_ty_v: llvmlite.LLVMType | t.CPtr = resolved_v match resolved_v: case llvmlite.LLVMType.Struct(_, _, _): - gv_ty_v = llvmlite.Ptr(pool, resolved_v) + # t.CStruct 值类(如 pci_device):模块级全局变量定义端是值实例 + # (handle_module_level_var 直接 new_global_variable(pool, name, resolved_v)), + # stub 声明必须保持值类型(%struct),否则跨模块字段访问 mod.var.field + # 生成 load %T**, %T** → 把实例前 8 字节当指针解引用 → 垃圾地址 #GP + # (uhci.vp pci._uhci_dev.irq 根因)。@t.Object 类 resolve 已返回 + # Ptr(struct),不会命中本分支,对象即指针语义不受影响。 + gv_ty_v = resolved_v case llvmlite.LLVMType.Array(aelem_v, acount_v): # 定长数组(CArray[T, N]):保留完整数组类型 [N x T],与定义端 # handle_module_level_var 生成的 global [N x T] 一致——此前一律 @@ -1505,6 +1692,12 @@ def _inject_global_variable_declare(pool: memhub.MemBuddy | t.CPtr, gv_ty_v = llvmlite.Ptr(pool, aelem_v) case _: gv_ty_v = resolved_v + # 确保跨模块结构体类型在模块中有 opaque 声明:external global 类型 + # (如 [7 x %gdt_entry])内嵌 struct 无任何定义时,llc 报 "use of + # undefined type named 'sha1.gdt_entry'"(fpu/fat32 合并 IR 根因)。 + # 对齐 TranslatorGenMixin 创建全局前的 module_ensure_opaque_for_type + # (_scan_type_for_cross_module_refs 递归 Array/Struct/Ptr)。 + llvmlite.module_ensure_opaque_for_type(mod, pool, gv_ty_v) gv_v: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gv_name_m, gv_ty_v) if gv_v is None: return