diff --git a/App/lib/Stub/StubGen/VpiReader.vp b/App/lib/Stub/StubGen/VpiReader.vp index 54b47ce..8eddd11 100644 --- a/App/lib/Stub/StubGen/VpiReader.vp +++ b/App/lib/Stub/StubGen/VpiReader.vp @@ -687,15 +687,16 @@ def _lookup_vpi_param_annots(src_sha1: str, cls_name: str, method_name: str) -> r: str = None ki: int # 索引快速路径:索引可信(Built==Count)时一次探测返回命中槽下标(= 原线性 - # 扫描首个同名,首注册优先);未命中 | 索引不可信 → 回退原线性扫描(正确性保证)。 + # 扫描首个同名,首注册优先);未命中一律回退下方原线性扫描(索引只加速命中, + # 未命中行为与未加索引前逐字节一致);此前"可信未命中即确无"的语义已回退。 hit_p: int = -1 if _g_vpi_param_idx_built == _g_vpi_param_count \ and _g_vpi_param_idx is not None and _g_vpi_param_idx_cap > 0: hit_p = _vpi_idx_find(_g_vpi_param_keys, VPI_PARAM_KEY_LEN, _g_vpi_param_idx, _g_vpi_param_idx_cap, key_buf) - else: - # 快速路径:strcmp 判等蕴含首字节相等;键首字节 = src_sha1[0],缓存含多模块 - # 条目,首字节不同者必不相等,直接跳过其 strcmp(仅做否定判定,不改变命中)。 + if hit_p < 0: + # 回退原线性扫描:strcmp 判等蕴含首字节相等;键首字节 = src_sha1[0],缓存含 + # 多模块条目,首字节不同者必不相等,直接跳过其 strcmp(仅做否定判定,不改命中)。 key_first: int = key_buf[0] for ki in range(_g_vpi_param_count): ent_p: bytes = _g_vpi_param_keys + ki * VPI_PARAM_KEY_LEN @@ -1063,14 +1064,15 @@ def _lookup_vpi_ret_annot(src_sha1: str, cls_name: str, method_name: str) -> str viperlib.snprintf(key_buf, key_len + 1, "%s.%s", src_sha1, method_name) i: int # 索引快速路径:索引可信(Built==Count)时一次探测返回命中槽下标(= 原线性 - # 扫描首个同名,首注册优先);未命中 | 索引不可信 → 回退原线性扫描(正确性保证)。 + # 扫描首个同名,首注册优先);未命中一律回退下方原线性扫描(索引只加速命中, + # 未命中行为与未加索引前逐字节一致);此前"可信未命中即确无"的语义已回退。 hit_r: int = -1 if _g_vpi_ret_idx_built == _g_vpi_ret_count \ and _g_vpi_ret_idx is not None and _g_vpi_ret_idx_cap > 0: hit_r = _vpi_idx_find(_g_vpi_ret_keys, VPI_KEY_LEN, _g_vpi_ret_idx, _g_vpi_ret_idx_cap, key_buf) - else: - # 快速路径:strcmp 判等蕴含首字节相等(键首字节 = src_sha1[0]),首字节不同者跳过。 + if hit_r < 0: + # 回退原线性扫描:strcmp 判等蕴含首字节相等(键首字节 = src_sha1[0]),跳过首字节不同者。 key_first: int = key_buf[0] for i in range(_g_vpi_ret_count): ent_r: bytes = _g_vpi_ret_keys + i * VPI_KEY_LEN diff --git a/App/lib/core/Gen/Call/CallGenLeafKit.vp b/App/lib/core/Gen/Call/CallGenLeafKit.vp index 8e729ca..c375735 100644 --- a/App/lib/core/Gen/Call/CallGenLeafKit.vp +++ b/App/lib/core/Gen/Call/CallGenLeafKit.vp @@ -1051,7 +1051,8 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin): t.CVoid(uint64(self.GlobalFuncs) + fi_t * entry_size, t.CPtr)) if fe_t is not None: return fe_t.Func - return None + # 索引未命中一律回退下方原线性扫描(索引只加速命中,未命中行为与未加 + # 索引前逐字节一致);此前"可信未命中即 return None"的语义已回退。 # 单遍扫描(合并原 owner 优先遍 + 通用遍,语义完全一致但省一半遍历): # 扫描中同时记录"首个同裸名条目"作通用兜底;一旦发现本模块条目 # (mangled 名以 "{owner_sha1}." 开头,16 位前缀 + '.')立即返回。 @@ -1272,7 +1273,8 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin): return None entry_size: sizet = GenTypes.FuncEntry.__sizeof__() # 名索引快速路径:可信(Built==Count)时一次探测返回首个同名条目 - # (= 原线性扫描首个命中);未命中/索引不可信 → 回退原线性扫描(正确性保证)。 + # (= 原线性扫描首个命中);未命中一律回退下方原线性扫描(索引只加速命中, + # 未命中行为与未加索引前逐字节一致);此前"可信未命中即 return None"已回退。 if self.GlobalFuncNameIdxBuilt == self.GlobalFuncCount \ and self.GlobalFuncNameIdx is not None and self.GlobalFuncNameIdxCap > 0: gi: int = _gfn_idx_find(self.GlobalFuncs, self.GlobalFuncNameIdx, @@ -1281,7 +1283,6 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin): entry_g: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)( t.CVoid(uint64(self.GlobalFuncs) + gi * entry_size, t.CPtr)) return entry_g - return None for i in range(self.GlobalFuncCount): entry_addr: uint64 = uint64(self.GlobalFuncs) + i * entry_size entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) diff --git a/App/lib/core/Gen/StructGenMixin.vp b/App/lib/core/Gen/StructGenMixin.vp index e8c9880..dbc193d 100644 --- a/App/lib/core/Gen/StructGenMixin.vp +++ b/App/lib/core/Gen/StructGenMixin.vp @@ -393,10 +393,8 @@ class StructGenMixin: # 用类型指针去重(同一类型不重复注册,支持跨模块同名类) # 用 uint64 指针值比较(is 比较会触发类型安全检查解引用悬空 Ty) - # 类型索引快速路径:find_struct_by_type 的 Ty 指针身份语义 = 原去重扫描 - # "首个 Ty 指针相等条目"(首注册优先),且其索引未命中 | 不可信时会回退 - # 原线性扫描(正确性保证,非兜底)⇒ 与原扫描结果逐字节一致。 - # 注册途中索引恒与 StructCount 同步(每次注册后 _struct_idx_add 同步)。 + # 走 find_struct_by_type(其 Ty 索引判定已整体停用、恢复原线性扫描), + # 去重语义 = 原去重扫描"首个 Ty 指针相等条目"(首注册优先),逐字节一致。 existing: GenTypes.StructEntry | t.CPtr = self.find_struct_by_type(struct_ty) if existing is not None: return existing @@ -786,27 +784,18 @@ class StructGenMixin: VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct)", "STRUCT") stdlib.exit(1) # 名索引快速路径:命中即首注册下标(语义 = 原精确匹配扫描首个命中)。 - # 未命中/索引不可信 → 回退下方原精确匹配扫描(保证正确性); - # 精确匹配确无时继续走模块限定名/裸名回退逻辑(不提前 return None)。 + # 未命中一律回退下方原精确匹配扫描(索引只加速命中,未命中行为与未加索引 + # 前逐字节一致);精确匹配确无时继续走模块限定名/裸名回退逻辑(不提前 + # return None)。此前"索引可信且查询名非空 ⇒ 未命中即确无、跳过 O(n) 扫描" + # 的语义已回退(一旦判据有未覆盖情形就会把"找得到"变成"找不到")。 fi: int = self._struct_name_idx_find(name) if fi >= 0: return self._get_struct_entry(fi) - # 名索引可信(Built==Count | 索引存在 | 查询名非空)时,索引未命中即 - # "确无同名条目":条目在注册时即命名并同步入索引,之后名至多被中和为 "" - # (ClassGenDef/ClassGenEnum 置 Name[0]=0),故任何非空查询名的命中项必在 - # 索引探测链上 ⇒ 可跳过下方 O(n) 精确扫描(热点:本扫描占 find_struct 的 - # 全部 strcmp)。索引不可信 / 无索引 / 空名查询时仍回退原线性扫描 - # (正确性保证,非兜底)。 - name_idx_trusted: int = 0 - if self.StructNameIdx is not None and self.StructIdxCap > 0 \ - and self.StructIdxBuilt == self.StructCount: - name_idx_trusted = 1 - if name_idx_trusted == 0 or name[0] == '\0': - for i in range(self.StructCount): - entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i) - if entry is not None and entry.Name is not None: - if string.strcmp(entry.Name, name) == 0: - return entry + for i in range(self.StructCount): + entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i) + if entry is not None and entry.Name is not None: + if string.strcmp(entry.Name, name) == 0: + return entry # 模块限定名(module.Class):模块可解析时按模块归属精确匹配, # 防止裸名回退抓跨模块同名类。模块未命中时若裸名类唯一(无冲突) # 仍回退,避免误杀未登记模块的既有解析。 @@ -969,12 +958,11 @@ class StructGenMixin: VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct_by_type)", "STRUCT") stdlib.exit(1) st_val: uint64 = uint64(struct_ty) - # 类型索引快速路径:命中即首注册下标(语义 = 原扫描首个 Ty 指针相等条目)。 - # 未命中/索引不可信 → 回退原线性扫描(Ty 可能被深拷贝改写,索引未覆盖全部 - # Ty 值,故此处未命中不能断言"确无",必须回退)。 - ti: int = self._struct_type_idx_find(st_val) - if ti >= 0: - return self._get_struct_entry(ti) + # Ty 索引整体停用判定(索引结构仍由 _struct_idx_add 维护,但不用于此处): + # 条目 Ty 可能被深拷贝改写为新指针(ClassGenDef),索引槽按"注册时的 Ty 值" + # 落位,改写后该条目的 live 键与槽位脱钩 ⇒ 索引命中返回的未必是"原线性扫描 + # 首个 Ty 相等条目",命中路径与原语义不等价、且无法低成本保证等价。故此处 + # 恢复原线性精确扫描(未命中/命中行为均与未加索引前逐字节一致)。 for i in range(self.StructCount): entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i) if entry is not None and entry.Ty is not None: @@ -1026,10 +1014,9 @@ class StructGenMixin: # ============================================================ # 第一遍: is 身份比较(用 uint64 指针值比较,避免 is 编译路径解引用悬空 Ty) - # 类型索引快速路径:find_struct_by_type 的语义 = 原扫描"首个 Ty 指针相等 - # 条目"(首注册优先);索引未命中 | 不可信时其内部回退原线性扫描 - # (正确性保证,非兜底)⇒ 选中的 entry 与原 is 身份扫描完全一致。 - # 类型唯一确定 entry:命中后查字段,字段未找到直接返回 None(不继续遍历)。 + # find_struct_by_type 的语义 = 原扫描"首个 Ty 指针相等条目"(首注册优先); + # 其 Ty 索引判定已整体停用、恢复原线性扫描 ⇒ 选中的 entry 与原 is 身份扫描 + # 完全一致。类型唯一确定 entry:命中后查字段,字段未找到直接返回 None。 lk_entry: GenTypes.StructEntry | t.CPtr = self.find_struct_by_type(struct_ty) if lk_entry is not None: for fi in range(lk_entry.FieldCount): @@ -1513,9 +1500,8 @@ class StructGenMixin: """按类型指针查找类名,返回类名字符串或 None""" if struct_ty is None or self.StructTable is None: return None - # 类型索引快速路径:find_struct_by_type 的 Ty 指针身份语义 = 原扫描 - # "首个 Ty 指针相等条目"(首注册优先),返回其 Name;索引未命中 | - # 不可信时其内部回退原线性扫描(正确性保证,非兜底)⇒ 逐字节一致。 + # find_struct_by_type 的语义 = 原扫描"首个 Ty 指针相等条目"(首注册优先), + # 返回其 Name;其 Ty 索引判定已整体停用、恢复原线性扫描 ⇒ 逐字节一致。 fast_cn: GenTypes.StructEntry | t.CPtr = self.find_struct_by_type(struct_ty) if fast_cn is not None: return fast_cn.Name diff --git a/App/lib/core/Gen/Type/TypeGenCDef.vp b/App/lib/core/Gen/Type/TypeGenCDef.vp index 861100b..23e63cf 100644 --- a/App/lib/core/Gen/Type/TypeGenCDef.vp +++ b/App/lib/core/Gen/Type/TypeGenCDef.vp @@ -340,16 +340,16 @@ class TypeGenCDef(TypeGenBase.TypeGenBase): n: sizet = len(self.CDefineNames) i: sizet # 名索引快速路径:可信(Built==n)时直接定位唯一候选下标(= 原扫描首个 - # 命中);未命中 → 确实不存在,直接返回;不可用 → 回退原全表线性扫描。 + # 命中);未命中一律保持全表范围、回退下方原全表线性扫描(索引只加速命中, + # 未命中行为与未加索引前逐字节一致);此前"未命中即确无、直接 return"已回退。 cd_start: sizet = 0 cd_end: sizet = n if name is not None and self.CDefineNameIdxBuilt == int(n) \ and self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0: cd_hit: int = self._cdef_idx_find(name) - if cd_hit < 0: - return 0 - cd_start = sizet(cd_hit) - cd_end = sizet(cd_hit + 1) + if cd_hit >= 0: + cd_start = sizet(cd_hit) + cd_end = sizet(cd_hit + 1) for i in range(cd_start, cd_end): nm: str = self.CDefineNames.get(i) if nm is not None and string.strcmp(nm, name) == 0: @@ -380,16 +380,16 @@ class TypeGenCDef(TypeGenBase.TypeGenBase): n: sizet = len(self.CDefineNames) i: sizet # 名索引快速路径:可信(Built==n)时直接定位唯一候选下标(= 原扫描首个 - # 命中);未命中 → 确实不存在,直接返回;不可用 → 回退原全表线性扫描。 + # 命中);未命中一律保持全表范围、回退下方原全表线性扫描(索引只加速命中, + # 未命中行为与未加索引前逐字节一致);此前"未命中即确无、直接 return"已回退。 cd_start: sizet = 0 cd_end: sizet = n if name is not None and self.CDefineNameIdxBuilt == int(n) \ and self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0: cd_hit: int = self._cdef_idx_find(name) - if cd_hit < 0: - return 0.0 - cd_start = sizet(cd_hit) - cd_end = sizet(cd_hit + 1) + if cd_hit >= 0: + cd_start = sizet(cd_hit) + cd_end = sizet(cd_hit + 1) for i in range(cd_start, cd_end): nm: str = self.CDefineNames.get(i) # 快速路径:strcmp 判等蕴含首字符相等,首字符不同者跳过 strcmp。 @@ -421,16 +421,16 @@ class TypeGenCDef(TypeGenBase.TypeGenBase): n: sizet = len(self.CDefineNames) i: sizet # 名索引快速路径:可信(Built==n)时直接定位唯一候选下标(= 原扫描首个 - # 命中);未命中 → 确实不存在,直接返回;不可用 → 回退原全表线性扫描。 + # 命中);未命中一律保持全表范围、回退下方原全表线性扫描(索引只加速命中, + # 未命中行为与未加索引前逐字节一致);此前"未命中即确无、直接 return"已回退。 cd_start: sizet = 0 cd_end: sizet = n if name is not None and self.CDefineNameIdxBuilt == int(n) \ and self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0: cd_hit: int = self._cdef_idx_find(name) - if cd_hit < 0: - return None - cd_start = sizet(cd_hit) - cd_end = sizet(cd_hit + 1) + if cd_hit >= 0: + cd_start = sizet(cd_hit) + cd_end = sizet(cd_hit + 1) for i in range(cd_start, cd_end): nm: str = self.CDefineNames.get(i) if nm is not None and string.strcmp(nm, name) == 0: diff --git a/App/lib/core/Gen/Type/TypeGenCType.vp b/App/lib/core/Gen/Type/TypeGenCType.vp index c079c91..75e64db 100644 --- a/App/lib/core/Gen/Type/TypeGenCType.vp +++ b/App/lib/core/Gen/Type/TypeGenCType.vp @@ -219,17 +219,17 @@ class TypeGenCType(TypeGenBase.TypeGenBase): return None n: sizet = len(self.CTypedefNames) i: sizet - # 名索引快速路径:可信(Built==n)时直接定位唯一候选槽下标。CTypedef 表 - # 注册时按名去重(register_ctypedef 已存在则原地更新类型串)⇒ 名唯一, - # 索引未命中 ⇒ 确实不存在,直接返回;索引不可用/不可信 → 回退原全表扫描。 + # 名索引快速路径:可信(Built==n)时直接定位唯一候选槽下标(CTypedef 表 + # 注册时按名去重 ⇒ 名唯一,命中即原全表扫描首个命中)。未命中一律回退下方 + # 原全表线性扫描(索引只加速命中,未命中行为与未加索引前逐字节一致); + # 此前"可信未命中即确无、直接 return None"的语义已回退。 if self.CTypedefNameIdxBuilt == int(n) \ and self.CTypedefNameIdx is not None and self.CTypedefNameIdxCap > 0: ti: int = self._ctypedef_idx_find(name) - if ti < 0: - return None - ts_hit: str = self.CTypedefTypeStrs.get(sizet(ti)) - self.CTypedefFound = 1 - return ts_hit + if ti >= 0: + ts_hit: str = self.CTypedefTypeStrs.get(sizet(ti)) + self.CTypedefFound = 1 + return ts_hit for i in range(n): nm: str = self.CTypedefNames.get(i) if nm is not None and string.strcmp(nm, name) == 0: