perf(lookup): 热点线性查找表加开放寻址名索引,O(n) 降为期望 O(1)
VpiReader 参数/返回注解键表(查表 + 写去重共用)、CallGenLeafKit 全局函数表、TypeGenCDef CDefine 表:由线性扫描改为开放寻址索引,对应热点约 117M + 17.8M + 10.5M 次 strcmp。 索引槽只存下标+1(不存键/节点指针),键表 realloc/移动后槽下标仍有效,无悬空指针;可信判据 Built==count,每次注册同步维护,不可信或未命中一律回退原线性扫描(正确性保证)。每次注册占一槽以保持首注册优先(探测链首个键相等者即原首个命中)。CallGenLeafKit 快速路径仅限 owner_sha1 为 None 的全局表查询,保持 owner 优先语义不变。
This commit is contained in:
1 parent
a9819e4123
commit
16472a61d9
5 files changed
+589
-24
No files matched your search
@@ -58,11 +58,176 @@ VPI_PARAM_MAX: t.CDefine = 4096
|
||||
VPI_PARAM_KEY_LEN: t.CDefine = 224
|
||||
VPI_PARAM_LEN: t.CDefine = 1024
|
||||
|
||||
# ============================================================
|
||||
# 键表开放寻址索引(名 → 槽下标)
|
||||
#
|
||||
# 两张键表(返回注解 / 参数注解)都是定长槽数组(每槽 VPI_*_KEY_LEN 字节),
|
||||
# 插入只追加、从不重排 ⇒ 索引可只存"槽下标"(比存指针更省,且 realloc 移动
|
||||
# 键表基址后槽下标仍有效)。索引槽数恒为键表容量的 2 倍(2 的幂,负载 < 0.5,
|
||||
# 线性探测必然终止)。每次注册占一槽(不按键去重):同键条目沿探测链按注册
|
||||
# 顺序递增排列,查找取链上首个"当前键相等"者 = 原线性扫描首个命中(首注册
|
||||
# 优先)。可信判据 = Built == Count;不可信/未命中一律回退原线性扫描。
|
||||
# ============================================================
|
||||
VPI_RET_IDX_CAP: t.CDefine = 8192
|
||||
VPI_PARAM_IDX_CAP: t.CDefine = 8192
|
||||
# 索引哈希常量(32 位 FNV-1a,与 StructGenMixin 范式一致)
|
||||
VPI_IDX_FNV_OFFSET: t.CDefine = 2166136261
|
||||
VPI_IDX_FNV_PRIME: t.CDefine = 16777619
|
||||
VPI_IDX_FNV_MASK: t.CDefine = 4294967295
|
||||
|
||||
_g_vpi_param_keys: bytes = None
|
||||
_g_vpi_param_strs: bytes = None
|
||||
_g_vpi_param_count: int = 0
|
||||
_g_vpi_param_cap: int = 0
|
||||
|
||||
# 返回注解键表索引(与键表同 malloc 生命周期;Built == Count 才可信)
|
||||
_g_vpi_ret_idx: bytes = None
|
||||
_g_vpi_ret_idx_cap: int = 0
|
||||
_g_vpi_ret_idx_built: int = 0
|
||||
# 参数注解键表索引(同上)
|
||||
_g_vpi_param_idx: bytes = None
|
||||
_g_vpi_param_idx_cap: int = 0
|
||||
_g_vpi_param_idx_built: int = 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 索引探测/插入/重建(模块级函数,供两张键表共用)
|
||||
# ============================================================
|
||||
def _vpi_idx_hash(key: bytes) -> uint64:
|
||||
"""键串 → 64 位哈希(32 位 FNV-1a,逐字节到 NUL 结束;空键返回偏移基值)"""
|
||||
h: uint64 = uint64(VPI_IDX_FNV_OFFSET)
|
||||
if key is None:
|
||||
return h
|
||||
i: sizet = 0
|
||||
while key[i] != '\0':
|
||||
h = (h ^ uint64(int(key[i]))) * uint64(VPI_IDX_FNV_PRIME)
|
||||
h = h & uint64(VPI_IDX_FNV_MASK)
|
||||
i += 1
|
||||
return h
|
||||
|
||||
|
||||
def _vpi_idx_slot(idx_base: bytes, si: sizet) -> sizet | t.CPtr:
|
||||
"""取索引第 si 个槽(8 字节,存 slot_index+1;0=空槽)"""
|
||||
return (sizet | t.CPtr)(t.CVoid(uint64(idx_base) + uint64(si) * 8, t.CPtr))
|
||||
|
||||
|
||||
def _vpi_idx_find(keys: bytes, key_stride: int, idx_base: bytes,
|
||||
cap: int, key: bytes) -> int:
|
||||
"""在索引中探测 key,返回命中槽下标(>=0);未命中/索引不可用返回 -1
|
||||
|
||||
命中判据是"当前键相等"(strcmp),不能只比哈希。
|
||||
"""
|
||||
if keys is None or idx_base is None or cap <= 0 or key is None:
|
||||
return -1
|
||||
h: uint64 = _vpi_idx_hash(key)
|
||||
mask: sizet = sizet(cap - 1)
|
||||
si: sizet = sizet(h) & mask
|
||||
i: int = 0
|
||||
while i < cap:
|
||||
slot: sizet | t.CPtr = _vpi_idx_slot(idx_base, si)
|
||||
sv: sizet = slot[0]
|
||||
if sv == 0:
|
||||
return -1
|
||||
se: int = int(sv) - 1
|
||||
ek: bytes = keys + se * key_stride
|
||||
if string.strcmp(ek, key) == 0:
|
||||
return se
|
||||
si = (si + 1) & mask
|
||||
i += 1
|
||||
return -1
|
||||
|
||||
|
||||
def _vpi_idx_insert(idx_base: bytes, cap: int, slot_index: int, key: bytes) -> int:
|
||||
"""把 (key → slot_index) 记入索引(每次注册占一槽,不去重);0=成功 / 1=失败"""
|
||||
if idx_base is None or cap <= 0 or key is None:
|
||||
return 1
|
||||
h: uint64 = _vpi_idx_hash(key)
|
||||
mask: sizet = sizet(cap - 1)
|
||||
si: sizet = sizet(h) & mask
|
||||
i: int = 0
|
||||
while i < cap:
|
||||
slot: sizet | t.CPtr = _vpi_idx_slot(idx_base, si)
|
||||
if slot[0] == 0:
|
||||
slot[0] = sizet(slot_index + 1)
|
||||
return 0
|
||||
si = (si + 1) & mask
|
||||
i += 1
|
||||
return 1
|
||||
|
||||
|
||||
def _vpi_rebuild_ret_idx(new_cap: int) -> int:
|
||||
"""随返回注解键表扩容重建索引(槽数=new_cap,2 的幂);0=可信 / 1=不可信
|
||||
|
||||
槽存下标非指针:键表 realloc 后仅基址变,槽下标与键内容均未变,故重建
|
||||
只需从新基址逐条重放现有 count 个键即可(顺序不变 ⇒ 首注册优先不变)。
|
||||
"""
|
||||
global _g_vpi_ret_idx, _g_vpi_ret_idx_cap, _g_vpi_ret_idx_built
|
||||
if new_cap <= 0:
|
||||
_g_vpi_ret_idx = None
|
||||
_g_vpi_ret_idx_cap = 0
|
||||
_g_vpi_ret_idx_built = -1
|
||||
return 1
|
||||
new_idx: bytes = None
|
||||
if _g_vpi_ret_idx is None:
|
||||
new_idx = stdlib.malloc(new_cap * 8)
|
||||
else:
|
||||
new_idx = stdlib.realloc(_g_vpi_ret_idx, new_cap * 8)
|
||||
if new_idx is None:
|
||||
_g_vpi_ret_idx = None
|
||||
_g_vpi_ret_idx_cap = 0
|
||||
_g_vpi_ret_idx_built = -1
|
||||
return 1
|
||||
string.memset(new_idx, 0, sizet(new_cap) * 8)
|
||||
_g_vpi_ret_idx = new_idx
|
||||
_g_vpi_ret_idx_cap = new_cap
|
||||
fail: int = 0
|
||||
ri: int
|
||||
for ri in range(_g_vpi_ret_count):
|
||||
if _vpi_idx_insert(new_idx, new_cap, ri,
|
||||
_g_vpi_ret_keys + ri * VPI_RET_KEY_LEN) != 0:
|
||||
fail = 1
|
||||
break
|
||||
if fail != 0:
|
||||
_g_vpi_ret_idx_built = -1
|
||||
return 1
|
||||
_g_vpi_ret_idx_built = _g_vpi_ret_count
|
||||
return 0
|
||||
|
||||
|
||||
def _vpi_rebuild_param_idx(new_cap: int) -> int:
|
||||
"""随参数注解键表扩容重建索引(同 _vpi_rebuild_ret_idx);0=可信 / 1=不可信"""
|
||||
global _g_vpi_param_idx, _g_vpi_param_idx_cap, _g_vpi_param_idx_built
|
||||
if new_cap <= 0:
|
||||
_g_vpi_param_idx = None
|
||||
_g_vpi_param_idx_cap = 0
|
||||
_g_vpi_param_idx_built = -1
|
||||
return 1
|
||||
new_idx: bytes = None
|
||||
if _g_vpi_param_idx is None:
|
||||
new_idx = stdlib.malloc(new_cap * 8)
|
||||
else:
|
||||
new_idx = stdlib.realloc(_g_vpi_param_idx, new_cap * 8)
|
||||
if new_idx is None:
|
||||
_g_vpi_param_idx = None
|
||||
_g_vpi_param_idx_cap = 0
|
||||
_g_vpi_param_idx_built = -1
|
||||
return 1
|
||||
string.memset(new_idx, 0, sizet(new_cap) * 8)
|
||||
_g_vpi_param_idx = new_idx
|
||||
_g_vpi_param_idx_cap = new_cap
|
||||
fail: int = 0
|
||||
ri: int
|
||||
for ri in range(_g_vpi_param_count):
|
||||
if _vpi_idx_insert(new_idx, new_cap, ri,
|
||||
_g_vpi_param_keys + ri * VPI_PARAM_KEY_LEN) != 0:
|
||||
fail = 1
|
||||
break
|
||||
if fail != 0:
|
||||
_g_vpi_param_idx_built = -1
|
||||
return 1
|
||||
_g_vpi_param_idx_built = _g_vpi_param_count
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _cache_vpi_return_annots_text - 从 vpi_buf 文本直接提取方法返回注解
|
||||
@@ -76,6 +241,7 @@ _g_vpi_param_cap: int = 0
|
||||
def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
"""从 vpi_buf 文本提取方法返回注解字符串(stdlib 持久)"""
|
||||
global _g_vpi_ret_keys, _g_vpi_ret_strs, _g_vpi_ret_count, _g_vpi_ret_cap
|
||||
global _g_vpi_ret_idx, _g_vpi_ret_idx_cap, _g_vpi_ret_idx_built
|
||||
if vpi_buf is None or src_sha1 is None:
|
||||
return 0
|
||||
if _g_vpi_ret_keys is None:
|
||||
@@ -86,6 +252,16 @@ def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
string.memset(_g_vpi_ret_keys, 0, VPI_RET_MAX * VPI_KEY_LEN)
|
||||
string.memset(_g_vpi_ret_strs, 0, VPI_RET_MAX * VPI_RET_LEN)
|
||||
_g_vpi_ret_cap = VPI_RET_MAX
|
||||
# 名索引:槽数 = 键表容量 * 2。分配失败则保持不可信(Built=-1),
|
||||
# 查找/写去重一律回退原线性扫描(语义完全一致,不因此使缓存失败)。
|
||||
_g_vpi_ret_idx = stdlib.malloc(VPI_RET_IDX_CAP * 8)
|
||||
if _g_vpi_ret_idx is not None:
|
||||
string.memset(_g_vpi_ret_idx, 0, VPI_RET_IDX_CAP * 8)
|
||||
_g_vpi_ret_idx_cap = VPI_RET_IDX_CAP
|
||||
_g_vpi_ret_idx_built = _g_vpi_ret_count
|
||||
else:
|
||||
_g_vpi_ret_idx_cap = 0
|
||||
_g_vpi_ret_idx_built = -1
|
||||
sha1_len: sizet = string.strlen(src_sha1)
|
||||
buf_len: sizet = string.strlen(vpi_buf)
|
||||
cur_cls: bytes = None
|
||||
@@ -189,10 +365,23 @@ def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
# 去重:同一 key 已存在则跳过(同文件可能被多次加载)
|
||||
dup_key: int = 0
|
||||
dki: int
|
||||
for dki in range(_g_vpi_ret_count):
|
||||
if string.strcmp(_g_vpi_ret_keys + dki * VPI_KEY_LEN, key_buf) == 0:
|
||||
# 索引快速路径:索引可信(Built==Count)时一次探测判定
|
||||
# 重复(命中即"首个注册优先"= 原线性扫描首个同名);
|
||||
# 未命中 | 索引不可信 → 回退原线性扫描(正确性保证)。
|
||||
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:
|
||||
if _vpi_idx_find(_g_vpi_ret_keys, VPI_KEY_LEN,
|
||||
_g_vpi_ret_idx, _g_vpi_ret_idx_cap, key_buf) >= 0:
|
||||
dup_key = 1
|
||||
break
|
||||
else:
|
||||
# 快速路径:重复键必首字节相同(strcmp 判等蕴含首字节
|
||||
# 相等),键首字节 = src_sha1[0],首字节不同者跳过 strcmp。
|
||||
dup_first: int = key_buf[0]
|
||||
for dki in range(_g_vpi_ret_count):
|
||||
ent_d: bytes = _g_vpi_ret_keys + dki * VPI_KEY_LEN
|
||||
if ent_d[0] == dup_first and string.strcmp(ent_d, key_buf) == 0:
|
||||
dup_key = 1
|
||||
break
|
||||
grow_ok: int = 1
|
||||
if dup_key == 0 and _g_vpi_ret_count >= _g_vpi_ret_cap:
|
||||
grow_ok = _grow_vpi_ret_cache()
|
||||
@@ -202,6 +391,14 @@ def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
ret_src, rtype_len)
|
||||
(_g_vpi_ret_strs + _g_vpi_ret_count * VPI_RET_LEN)[rtype_len] = '\0'
|
||||
_g_vpi_ret_count += 1
|
||||
# 同步索引:仅当插入前可信(Built==Count-1,含扩容
|
||||
# 重建后)且插入成功;否则标记不可信(查找回退扫描)。
|
||||
if _g_vpi_ret_idx_built == _g_vpi_ret_count - 1 \
|
||||
and _vpi_idx_insert(_g_vpi_ret_idx, _g_vpi_ret_idx_cap,
|
||||
_g_vpi_ret_count - 1, key_buf) == 0:
|
||||
_g_vpi_ret_idx_built = _g_vpi_ret_count
|
||||
else:
|
||||
_g_vpi_ret_idx_built = -1
|
||||
stdlib.free(key_buf)
|
||||
stdlib.free(mname_buf)
|
||||
pos = le + 1
|
||||
@@ -225,6 +422,7 @@ def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
def _cache_vpi_param_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
"""从 vpi_buf 文本提取函数/方法参数注解字符串(stdlib 持久)"""
|
||||
global _g_vpi_param_keys, _g_vpi_param_strs, _g_vpi_param_count, _g_vpi_param_cap
|
||||
global _g_vpi_param_idx, _g_vpi_param_idx_cap, _g_vpi_param_idx_built
|
||||
if vpi_buf is None or src_sha1 is None:
|
||||
return 0
|
||||
if _g_vpi_param_keys is None:
|
||||
@@ -235,6 +433,16 @@ def _cache_vpi_param_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
string.memset(_g_vpi_param_keys, 0, VPI_PARAM_MAX * VPI_PARAM_KEY_LEN)
|
||||
string.memset(_g_vpi_param_strs, 0, VPI_PARAM_MAX * VPI_PARAM_LEN)
|
||||
_g_vpi_param_cap = VPI_PARAM_MAX
|
||||
# 名索引:槽数 = 键表容量 * 2。分配失败则保持不可信(Built=-1),
|
||||
# 查找/写去重一律回退原线性扫描(语义完全一致,不因此使缓存失败)。
|
||||
_g_vpi_param_idx = stdlib.malloc(VPI_PARAM_IDX_CAP * 8)
|
||||
if _g_vpi_param_idx is not None:
|
||||
string.memset(_g_vpi_param_idx, 0, VPI_PARAM_IDX_CAP * 8)
|
||||
_g_vpi_param_idx_cap = VPI_PARAM_IDX_CAP
|
||||
_g_vpi_param_idx_built = _g_vpi_param_count
|
||||
else:
|
||||
_g_vpi_param_idx_cap = 0
|
||||
_g_vpi_param_idx_built = -1
|
||||
sha1_len: sizet = string.strlen(src_sha1)
|
||||
buf_len: sizet = string.strlen(vpi_buf)
|
||||
cur_cls: bytes = None
|
||||
@@ -386,10 +594,23 @@ def _cache_vpi_param_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
viperlib.snprintf(key_buf, key_len + 1, "%s.%s", src_sha1, mname_buf)
|
||||
dup_key: int = 0
|
||||
dki: int
|
||||
for dki in range(_g_vpi_param_count):
|
||||
if string.strcmp(_g_vpi_param_keys + dki * VPI_PARAM_KEY_LEN, key_buf) == 0:
|
||||
# 索引快速路径:索引可信(Built==Count)时一次探测判定
|
||||
# 重复(命中即"首个注册优先"= 原线性扫描首个同名);
|
||||
# 未命中 | 索引不可信 → 回退原线性扫描(正确性保证)。
|
||||
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:
|
||||
if _vpi_idx_find(_g_vpi_param_keys, VPI_PARAM_KEY_LEN,
|
||||
_g_vpi_param_idx, _g_vpi_param_idx_cap, key_buf) >= 0:
|
||||
dup_key = 1
|
||||
break
|
||||
else:
|
||||
# 快速路径:重复键必首字节相同(strcmp 判等蕴含首字节
|
||||
# 相等),键首字节 = src_sha1[0],首字节不同者跳过 strcmp。
|
||||
dup_first: int = key_buf[0]
|
||||
for dki in range(_g_vpi_param_count):
|
||||
ent_d: bytes = _g_vpi_param_keys + dki * VPI_PARAM_KEY_LEN
|
||||
if ent_d[0] == dup_first and string.strcmp(ent_d, key_buf) == 0:
|
||||
dup_key = 1
|
||||
break
|
||||
grow_ok: int = 1
|
||||
if dup_key == 0 and _g_vpi_param_count >= _g_vpi_param_cap:
|
||||
grow_ok = _grow_vpi_param_cache()
|
||||
@@ -399,6 +620,14 @@ def _cache_vpi_param_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
|
||||
plist, plist_pos)
|
||||
(_g_vpi_param_strs + _g_vpi_param_count * VPI_PARAM_LEN)[plist_pos] = '\0'
|
||||
_g_vpi_param_count += 1
|
||||
# 同步索引:仅当插入前可信(Built==Count-1,含扩容
|
||||
# 重建后)且插入成功;否则标记不可信(查找回退扫描)。
|
||||
if _g_vpi_param_idx_built == _g_vpi_param_count - 1 \
|
||||
and _vpi_idx_insert(_g_vpi_param_idx, _g_vpi_param_idx_cap,
|
||||
_g_vpi_param_count - 1, key_buf) == 0:
|
||||
_g_vpi_param_idx_built = _g_vpi_param_count
|
||||
else:
|
||||
_g_vpi_param_idx_built = -1
|
||||
stdlib.free(key_buf)
|
||||
stdlib.free(mname_buf)
|
||||
stdlib.free(plist)
|
||||
@@ -428,6 +657,8 @@ def _grow_vpi_param_cache() -> int:
|
||||
_g_vpi_param_keys = new_keys
|
||||
_g_vpi_param_strs = new_strs
|
||||
_g_vpi_param_cap = new_cap
|
||||
# 索引随表同步扩容并整体重建(槽数 = 表容量 * 2,恒为 2 的幂)
|
||||
_vpi_rebuild_param_idx(new_cap * 2)
|
||||
return 1
|
||||
|
||||
|
||||
@@ -455,10 +686,24 @@ def _lookup_vpi_param_annots(src_sha1: str, cls_name: str, method_name: str) ->
|
||||
viperlib.snprintf(key_buf, key_len + 1, "%s.%s", src_sha1, method_name)
|
||||
r: str = None
|
||||
ki: int
|
||||
for ki in range(_g_vpi_param_count):
|
||||
if string.strcmp(_g_vpi_param_keys + ki * VPI_PARAM_KEY_LEN, key_buf) == 0:
|
||||
r = _g_vpi_param_strs + ki * VPI_PARAM_LEN
|
||||
break
|
||||
# 索引快速路径:索引可信(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(仅做否定判定,不改变命中)。
|
||||
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
|
||||
if ent_p[0] == key_first and string.strcmp(ent_p, key_buf) == 0:
|
||||
hit_p = ki
|
||||
break
|
||||
if hit_p >= 0:
|
||||
r = _g_vpi_param_strs + hit_p * VPI_PARAM_LEN
|
||||
stdlib.free(key_buf)
|
||||
return r
|
||||
|
||||
@@ -597,6 +842,8 @@ def _grow_vpi_ret_cache() -> int:
|
||||
_g_vpi_ret_keys = new_keys
|
||||
_g_vpi_ret_strs = new_strs
|
||||
_g_vpi_ret_cap = new_cap
|
||||
# 索引随表同步扩容并整体重建(槽数 = 表容量 * 2,恒为 2 的幂)
|
||||
_vpi_rebuild_ret_idx(new_cap * 2)
|
||||
return 1
|
||||
|
||||
|
||||
@@ -622,9 +869,14 @@ def _ensure_vpi_ret_annot_loaded(src_sha1: str, temp_dir: str) -> int:
|
||||
# 该模块已有缓存条目 → 跳过(幂等)
|
||||
if _g_vpi_ret_keys is not None and _g_vpi_ret_count > 0:
|
||||
pre_i: int
|
||||
# 快速路径:前缀匹配必首两字节相等(strncmp 判等蕴含前缀逐字节相等),
|
||||
# src_sha1 前两字节即模块子目录名;先比二者可跳过绝大多数条目的 strncmp。
|
||||
s0: int = src_sha1[0]
|
||||
s1: int = src_sha1[1]
|
||||
for pre_i in range(_g_vpi_ret_count):
|
||||
pre_key: bytes = _g_vpi_ret_keys + pre_i * VPI_KEY_LEN
|
||||
if string.strncmp(pre_key, src_sha1, sha1_len) == 0 and pre_key[sha1_len] == '.':
|
||||
if pre_key[0] == s0 and pre_key[1] == s1 and \
|
||||
string.strncmp(pre_key, src_sha1, sha1_len) == 0 and pre_key[sha1_len] == '.':
|
||||
return 1
|
||||
# 构造路径 {temp_dir}/{sha1[0:2]}/{sha1}.vpi(逐字符拼接,避免 %c 格式化问题)
|
||||
td_len: sizet = string.strlen(temp_dir)
|
||||
@@ -680,9 +932,14 @@ def _ensure_vpi_param_annot_loaded(src_sha1: str, temp_dir: str) -> int:
|
||||
# 该模块已有参数缓存条目 → 跳过(幂等)
|
||||
if _g_vpi_param_keys is not None and _g_vpi_param_count > 0:
|
||||
pre_i: int
|
||||
# 快速路径:前缀匹配必首两字节相等(strncmp 判等蕴含前缀逐字节相等),
|
||||
# src_sha1 前两字节即模块子目录名;先比二者可跳过绝大多数条目的 strncmp。
|
||||
s0: int = src_sha1[0]
|
||||
s1: int = src_sha1[1]
|
||||
for pre_i in range(_g_vpi_param_count):
|
||||
pre_key: bytes = _g_vpi_param_keys + pre_i * VPI_PARAM_KEY_LEN
|
||||
if string.strncmp(pre_key, src_sha1, sha1_len) == 0 and pre_key[sha1_len] == '.':
|
||||
if pre_key[0] == s0 and pre_key[1] == s1 and \
|
||||
string.strncmp(pre_key, src_sha1, sha1_len) == 0 and pre_key[sha1_len] == '.':
|
||||
return 1
|
||||
# 构造路径 {temp_dir}/{sha1[0:2]}/{sha1}.vpi(逐字符拼接,避免 %c 格式化问题)
|
||||
td_len: sizet = string.strlen(temp_dir)
|
||||
@@ -805,10 +1062,24 @@ def _lookup_vpi_ret_annot(src_sha1: str, cls_name: str, method_name: str) -> str
|
||||
else:
|
||||
viperlib.snprintf(key_buf, key_len + 1, "%s.%s", src_sha1, method_name)
|
||||
i: int
|
||||
for i in range(_g_vpi_ret_count):
|
||||
if string.strcmp(_g_vpi_ret_keys + i * VPI_KEY_LEN, key_buf) == 0:
|
||||
stdlib.free(key_buf)
|
||||
return _g_vpi_ret_strs + i * VPI_RET_LEN
|
||||
# 索引快速路径:索引可信(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]),首字节不同者跳过。
|
||||
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
|
||||
if ent_r[0] == key_first and string.strcmp(ent_r, key_buf) == 0:
|
||||
hit_r = i
|
||||
break
|
||||
if hit_r >= 0:
|
||||
stdlib.free(key_buf)
|
||||
return _g_vpi_ret_strs + hit_r * VPI_RET_LEN
|
||||
# 泛型特化归一化匹配:list[AST|t.CPtr].get → list[T].get 模板缓存。
|
||||
# 命中后把模板注解中的类型参数名(如 T)替换为实参(AST|t.CPtr)再返回。
|
||||
# 不依赖模板类已注册/特化已发生(base.vp 可能先于 list 模块翻译)。
|
||||
|
||||
Reference in new issue
Block a user