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 模块翻译)。
|
||||
|
||||
@@ -80,6 +80,14 @@ class CallGenBase:
|
||||
GlobalFuncs: GenTypes.FuncEntry | t.CPtr
|
||||
GlobalFuncCount: int
|
||||
|
||||
# --- 全局函数表"名 → 槽下标"索引(开放寻址 | 线性探测;槽存 index+1,0=空槽) ---
|
||||
# GlobalFuncs 在 PermPool 固定容量分配、只追加不重排、从不 reset ⇒ 存槽下标
|
||||
# 稳定(远优于存会被回收的节点指针);GlobalFuncCount 单调递增,
|
||||
# Built == GlobalFuncCount 才可信,不可信/未命中一律回退线性扫描。
|
||||
GlobalFuncNameIdx: sizet | t.CPtr
|
||||
GlobalFuncNameIdxCap: int
|
||||
GlobalFuncNameIdxBuilt: int
|
||||
|
||||
# --- 全局默认参数表(原 _global_defaults/_global_defaults_count) ---
|
||||
GlobalDefaults: GenTypes.FuncDefaultsEntry | t.CPtr
|
||||
GlobalDefaultsCount: int
|
||||
@@ -101,6 +109,9 @@ class CallGenBase:
|
||||
self.FuncptrCount = 0
|
||||
self.GlobalFuncs = None
|
||||
self.GlobalFuncCount = 0
|
||||
self.GlobalFuncNameIdx = None
|
||||
self.GlobalFuncNameIdxCap = 0
|
||||
self.GlobalFuncNameIdxBuilt = -1
|
||||
self.GlobalDefaults = None
|
||||
self.GlobalDefaultsCount = 0
|
||||
return 0
|
||||
@@ -536,7 +547,10 @@ class CallGenBase:
|
||||
while cur is not None:
|
||||
cur_name: str = llvmlite.function_get_name(cur)
|
||||
if cur_name is not None:
|
||||
if string.strcmp(cur_name, name) == 0:
|
||||
# 快速路径:精确匹配要求首字符相等(strcmp 判等蕴含首字符相等),
|
||||
# 首字符不同者直接跳过 strcmp;mangled 名以 sha1 十六进制字符打头,
|
||||
# 裸名多为字母/下划线,绝大多数节点可被此条件短路。
|
||||
if cur_name[0] == name[0] and string.strcmp(cur_name, name) == 0:
|
||||
return cur
|
||||
# 本模块同名候选:仅接受恰为 "{owner_sha1}.{name}" 的形态
|
||||
# (mangled 模块级函数名含且只含一个 '.'),不匹配
|
||||
@@ -1162,7 +1176,10 @@ class CallGenBase:
|
||||
ll: sizet = le - ls
|
||||
|
||||
# 检查是否是 define 行
|
||||
if ll >= 7 and string.strncmp(read_buf + ls, "define ", 7) == 0:
|
||||
# 快速路径:行首字节不是 'd' 时不可能等于 "define "(strncmp 判等
|
||||
# 蕴含首个字节相等),直接短路省去绝大多数非 define 行的 strncmp 调用;
|
||||
# 仅做否定判定,不改变任何原本会命中的行。
|
||||
if ll >= 7 and read_buf[ls] == 'd' and string.strncmp(read_buf + ls, "define ", 7) == 0:
|
||||
# 找 @ 符号
|
||||
at_pos: sizet = ls + 7
|
||||
while at_pos < ls + ll:
|
||||
|
||||
@@ -47,6 +47,81 @@ MAX_FUNC_PTR_SIGS: t.CDefine = 64
|
||||
# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32)
|
||||
ISINSTANCE_CLASS_MAX: t.CDefine = 64
|
||||
|
||||
# ============================================================
|
||||
# 全局函数表名索引(名 → 槽下标,开放寻址 | 线性探测)
|
||||
#
|
||||
# 槽数 = 2 * GLOBAL_FUNC_MAX(2 的幂,负载 < 0.5,线性探测必然终止)。
|
||||
# 槽存槽下标 + 1(0=空槽)。GlobalFuncs 在 PermPool 定长分配、只追加不重排、
|
||||
# 从不 reset ⇒ 槽下标稳定;Built == GlobalFuncCount 才可信。
|
||||
# ============================================================
|
||||
GLOBAL_FUNC_IDX_CAP: t.CDefine = 16384
|
||||
# 索引哈希常量(32 位 FNV-1a,与 StructGenMixin 范式一致)
|
||||
GFN_FNV_OFFSET: t.CDefine = 2166136261
|
||||
GFN_FNV_PRIME: t.CDefine = 16777619
|
||||
GFN_FNV_MASK: t.CDefine = 4294967295
|
||||
|
||||
|
||||
def _gfn_hash(name: str) -> uint64:
|
||||
"""函数名 → 64 位哈希(32 位 FNV-1a,逐字节到 NUL 结束)"""
|
||||
h: uint64 = uint64(GFN_FNV_OFFSET)
|
||||
if name is None:
|
||||
return h
|
||||
i: sizet = 0
|
||||
while name[i] != '\0':
|
||||
h = (h ^ uint64(int(name[i]))) * uint64(GFN_FNV_PRIME)
|
||||
h = h & uint64(GFN_FNV_MASK)
|
||||
i += 1
|
||||
return h
|
||||
|
||||
|
||||
def _gfn_idx_slot(idx_base: sizet | t.CPtr, si: sizet) -> sizet | t.CPtr:
|
||||
"""取索引第 si 个槽(8 字节,存槽下标+1;0=空槽)"""
|
||||
return (sizet | t.CPtr)(t.CVoid(uint64(idx_base) + uint64(si) * 8, t.CPtr))
|
||||
|
||||
|
||||
def _gfn_idx_find(funcs: GenTypes.FuncEntry | t.CPtr,
|
||||
idx_base: sizet | t.CPtr, cap: int, name: str) -> int:
|
||||
"""在全局函数表名索引中探测 name,返回命中槽下标(>=0);未命中/不可用返回 -1"""
|
||||
if funcs is None or idx_base is None or cap <= 0 or name is None:
|
||||
return -1
|
||||
h: uint64 = _gfn_hash(name)
|
||||
mask: sizet = sizet(cap - 1)
|
||||
si: sizet = sizet(h) & mask
|
||||
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
|
||||
i: int = 0
|
||||
while i < cap:
|
||||
slot: sizet | t.CPtr = _gfn_idx_slot(idx_base, si)
|
||||
sv: sizet = slot[0]
|
||||
if sv == 0:
|
||||
return -1
|
||||
se: int = int(sv) - 1
|
||||
entry_addr: uint64 = uint64(funcs) + se * entry_size
|
||||
entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
if entry is not None and entry.Name is not None:
|
||||
if string.strcmp(entry.Name, name) == 0:
|
||||
return se
|
||||
si = (si + 1) & mask
|
||||
i += 1
|
||||
return -1
|
||||
|
||||
|
||||
def _gfn_idx_insert(idx_base: sizet | t.CPtr, cap: int, slot_index: int, name: str) -> int:
|
||||
"""把 (name → slot_index) 记入索引;0=成功 / 1=失败"""
|
||||
if idx_base is None or cap <= 0 or name is None:
|
||||
return 1
|
||||
h: uint64 = _gfn_hash(name)
|
||||
mask: sizet = sizet(cap - 1)
|
||||
si: sizet = sizet(h) & mask
|
||||
i: int = 0
|
||||
while i < cap:
|
||||
slot: sizet | t.CPtr = _gfn_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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CallGenLeafKit - EH/isinstance/闭包/print/函数表
|
||||
@@ -959,6 +1034,24 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
if name is None or funcs is None:
|
||||
return None
|
||||
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
|
||||
# 全局函数表 + 无 owner(find_func_global / _register_global_func 去重路径):
|
||||
# owner 分支不激活 ⇒ 等价于"首个同名条目的 Func"(含 Func 为 None → None),
|
||||
# 走名索引快速路径。funcs 非全局表(逐文件 _funcs)或带 owner 时保持下方
|
||||
# 线性扫描(owner 优先需按同组顺序遍历,索引不适用)。
|
||||
gfuncs_match: int = 0
|
||||
if owner_sha1 is None and self.GlobalFuncs is not None:
|
||||
if uint64(funcs) == uint64(self.GlobalFuncs) and func_count == self.GlobalFuncCount:
|
||||
gfuncs_match = 1
|
||||
if gfuncs_match != 0 and self.GlobalFuncNameIdxBuilt == self.GlobalFuncCount \
|
||||
and self.GlobalFuncNameIdx is not None and self.GlobalFuncNameIdxCap > 0:
|
||||
fi_t: int = _gfn_idx_find(self.GlobalFuncs, self.GlobalFuncNameIdx,
|
||||
self.GlobalFuncNameIdxCap, name)
|
||||
if fi_t >= 0:
|
||||
fe_t: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(
|
||||
t.CVoid(uint64(self.GlobalFuncs) + fi_t * entry_size, t.CPtr))
|
||||
if fe_t is not None:
|
||||
return fe_t.Func
|
||||
return None
|
||||
# 单遍扫描(合并原 owner 优先遍 + 通用遍,语义完全一致但省一半遍历):
|
||||
# 扫描中同时记录"首个同裸名条目"作通用兜底;一旦发现本模块条目
|
||||
# (mangled 名以 "{owner_sha1}." 开头,16 位前缀 + '.')立即返回。
|
||||
@@ -972,7 +1065,9 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
entry_addr: uint64 = uint64(funcs) + i * entry_size
|
||||
entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
if entry is not None and entry.Name is not None:
|
||||
if string.strcmp(entry.Name, name) == 0:
|
||||
# 快速路径:同名要求首字符相等(strcmp 判等蕴含首字符相等),
|
||||
# 首字符不同者直接跳过 strcmp,避免全表每槽一次函数调用。
|
||||
if entry.Name[0] == name[0] and string.strcmp(entry.Name, name) == 0:
|
||||
if fallback_entry is None:
|
||||
fallback_entry = entry
|
||||
if entry.Func is not None and owner_sha1 is not None:
|
||||
@@ -1035,6 +1130,19 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
return 0
|
||||
string.memset(self.GlobalFuncs, 0, size)
|
||||
self.GlobalFuncCount = 0
|
||||
# 名索引(PermPool,与表同生命周期)。分配失败 → 保持不可信(Built=-1),
|
||||
# 查找/去重一律回退线性扫描(语义完全一致,不因此使初始化失败)。
|
||||
idx_bytes: sizet = sizet(GLOBAL_FUNC_IDX_CAP) * 8
|
||||
idx_buf: sizet | t.CPtr = CompilerFactory.factory.PermPool.alloc(idx_bytes)
|
||||
if idx_buf is None:
|
||||
self.GlobalFuncNameIdx = None
|
||||
self.GlobalFuncNameIdxCap = 0
|
||||
self.GlobalFuncNameIdxBuilt = -1
|
||||
else:
|
||||
string.memset(idx_buf, 0, idx_bytes)
|
||||
self.GlobalFuncNameIdx = idx_buf
|
||||
self.GlobalFuncNameIdxCap = GLOBAL_FUNC_IDX_CAP
|
||||
self.GlobalFuncNameIdxBuilt = 0
|
||||
return 1
|
||||
|
||||
|
||||
@@ -1071,6 +1179,14 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
# Spec 不在此生成:函数参数在 add_func_to_table 之后才添加,
|
||||
# 需由调用方在参数添加完成后调用 update_global_func_spec 补全。
|
||||
self.GlobalFuncCount += 1
|
||||
# 同步名索引(槽下标 = 新条目下标):仅当插入前可信(Built==Count-1)
|
||||
# 且插入成功;否则标记不可信(查找回退线性扫描)。
|
||||
if self.GlobalFuncNameIdxBuilt == self.GlobalFuncCount - 1 \
|
||||
and _gfn_idx_insert(self.GlobalFuncNameIdx, self.GlobalFuncNameIdxCap,
|
||||
self.GlobalFuncCount - 1, name_copy) == 0:
|
||||
self.GlobalFuncNameIdxBuilt = self.GlobalFuncCount
|
||||
else:
|
||||
self.GlobalFuncNameIdxBuilt = -1
|
||||
return 0
|
||||
|
||||
|
||||
@@ -1155,11 +1271,24 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
if name is None or self.GlobalFuncs is None:
|
||||
return None
|
||||
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
|
||||
# 名索引快速路径:可信(Built==Count)时一次探测返回首个同名条目
|
||||
# (= 原线性扫描首个命中);未命中/索引不可信 → 回退原线性扫描(正确性保证)。
|
||||
if self.GlobalFuncNameIdxBuilt == self.GlobalFuncCount \
|
||||
and self.GlobalFuncNameIdx is not None and self.GlobalFuncNameIdxCap > 0:
|
||||
gi: int = _gfn_idx_find(self.GlobalFuncs, self.GlobalFuncNameIdx,
|
||||
self.GlobalFuncNameIdxCap, name)
|
||||
if gi >= 0:
|
||||
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))
|
||||
if entry.Name is not None:
|
||||
if string.strcmp(entry.Name, name) == 0:
|
||||
# 快速路径:同名要求首字符相等(strcmp 判等蕴含首字符相等),
|
||||
# 首字符不同者直接跳过 strcmp。
|
||||
if entry.Name[0] == name[0] and string.strcmp(entry.Name, name) == 0:
|
||||
return entry
|
||||
return None
|
||||
|
||||
|
||||
@@ -55,6 +55,13 @@ class TypeGenBase:
|
||||
CDefineIsDouble: int
|
||||
CDefineIsStr: int
|
||||
CDefineFound: int
|
||||
# --- CDefine 名 → 槽下标 索引(开放寻址 | 线性探测;槽存 index+1,0=空槽) ---
|
||||
# 与 CDefineNames 同池分配、同 clear_cdefine_constants 复位;CDefineNames 只
|
||||
# 追加不重排 ⇒ 存槽下标稳定;Built == len(CDefineNames) 才可信,不可信/未命中
|
||||
# 一律回退线性扫描(正确性保证)。
|
||||
CDefineNameIdx: sizet | t.CPtr
|
||||
CDefineNameIdxCap: int
|
||||
CDefineNameIdxBuilt: int
|
||||
|
||||
# --- 跨模块 CDefine 查找缓存(perm_pool 永久分配,跨文件复用) ---
|
||||
# 2026-08-14:跨模块 CDefine 查找(_lookup_cross_module_cdefine)结果缓存到
|
||||
@@ -133,6 +140,9 @@ class TypeGenBase:
|
||||
self.CDefineIsDouble = 0
|
||||
self.CDefineIsStr = 0
|
||||
self.CDefineFound = 0
|
||||
self.CDefineNameIdx = None
|
||||
self.CDefineNameIdxCap = 0
|
||||
self.CDefineNameIdxBuilt = -1
|
||||
self.XmodCdefNames = None
|
||||
self.XmodCdefValues = None
|
||||
self.XmodCdefDoubleFlags = None
|
||||
|
||||
@@ -15,6 +15,20 @@ import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
import lib.core.Gen.Type.TypeGenBase as TypeGenBase
|
||||
|
||||
# ============================================================
|
||||
# CDefine 名索引(名 → 槽下标,开放寻址 | 线性探测)
|
||||
#
|
||||
# 槽数 = 4096(2 的幂;负载 < 0.5 上限 2048 条,超限标记不可信回退线性扫描)。
|
||||
# 槽存槽下标 + 1(0=空槽)。CDefineNames 只追加不重排 ⇒ 槽下标稳定;
|
||||
# Built == len(CDefineNames) 才可信。
|
||||
# ============================================================
|
||||
CDEFINE_IDX_CAP: t.CDefine = 4096
|
||||
# 索引哈希常量(32 位 FNV-1a,与 StructGenMixin 范式一致)
|
||||
CDEF_IDX_FNV_OFFSET: t.CDefine = 2166136261
|
||||
CDEF_IDX_FNV_PRIME: t.CDefine = 16777619
|
||||
CDEF_IDX_FNV_MASK: t.CDefine = 4294967295
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TypeGenCDef - TypeGenMixin 拆分(阶段 D):CDefine 编译期常量表(register/lookup/is/set/clear)
|
||||
#
|
||||
@@ -26,6 +40,86 @@ import lib.core.Gen.Type.TypeGenBase as TypeGenBase
|
||||
class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
"""CDefine 编译期常量表(register/lookup/is/set/clear)"""
|
||||
|
||||
# ============================================================
|
||||
# CDefine 名索引(开放寻址;槽存 index+1,0=空槽)
|
||||
# ============================================================
|
||||
def _cdef_idx_hash(self, name: str) -> uint64:
|
||||
"""名 → 64 位哈希(32 位 FNV-1a,逐字节到 NUL 结束)"""
|
||||
h: uint64 = uint64(CDEF_IDX_FNV_OFFSET)
|
||||
if name is None:
|
||||
return h
|
||||
i: sizet = 0
|
||||
while name[i] != '\0':
|
||||
h = (h ^ uint64(int(name[i]))) * uint64(CDEF_IDX_FNV_PRIME)
|
||||
h = h & uint64(CDEF_IDX_FNV_MASK)
|
||||
i += 1
|
||||
return h
|
||||
|
||||
def _cdef_idx_slot(self, si: sizet) -> sizet | t.CPtr:
|
||||
"""取索引第 si 个槽(8 字节,存槽下标+1;0=空槽)"""
|
||||
return (sizet | t.CPtr)(t.CVoid(uint64(self.CDefineNameIdx) + uint64(si) * 8, t.CPtr))
|
||||
|
||||
def _cdef_idx_init(self, pool: rowptr[memhub.MemBuddy]) -> None:
|
||||
"""创建/清零名索引(与 CDefineNames 同池);失败则标记不可信"""
|
||||
idx: sizet | t.CPtr = pool.alloc(sizet(CDEFINE_IDX_CAP) * 8)
|
||||
if idx is None:
|
||||
self.CDefineNameIdx = None
|
||||
self.CDefineNameIdxCap = 0
|
||||
self.CDefineNameIdxBuilt = -1
|
||||
return
|
||||
string.memset(idx, 0, sizet(CDEFINE_IDX_CAP) * 8)
|
||||
self.CDefineNameIdx = idx
|
||||
self.CDefineNameIdxCap = CDEFINE_IDX_CAP
|
||||
self.CDefineNameIdxBuilt = 0
|
||||
|
||||
def _cdef_idx_find(self, name: str) -> int:
|
||||
"""在名索引中探测 name,返回命中槽下标(>=0);未命中/不可用返回 -1"""
|
||||
if self.CDefineNameIdx is None or self.CDefineNameIdxCap <= 0 or name is None:
|
||||
return -1
|
||||
if self.CDefineNameIdxBuilt != int(len(self.CDefineNames)):
|
||||
return -1
|
||||
h: uint64 = self._cdef_idx_hash(name)
|
||||
mask: sizet = sizet(self.CDefineNameIdxCap - 1)
|
||||
si: sizet = sizet(h) & mask
|
||||
i: int = 0
|
||||
while i < self.CDefineNameIdxCap:
|
||||
slot: sizet | t.CPtr = self._cdef_idx_slot(si)
|
||||
sv: sizet = slot[0]
|
||||
if sv == 0:
|
||||
return -1
|
||||
se: int = int(sv) - 1
|
||||
nm: str = self.CDefineNames.get(sizet(se))
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
return se
|
||||
si = (si + 1) & mask
|
||||
i += 1
|
||||
return -1
|
||||
|
||||
def _cdef_idx_insert(self, slot_index: int, name: str) -> int:
|
||||
"""把 (name → slot_index) 记入索引;0=成功 / 1=失败"""
|
||||
if self.CDefineNameIdx is None or self.CDefineNameIdxCap <= 0 or name is None:
|
||||
return 1
|
||||
h: uint64 = self._cdef_idx_hash(name)
|
||||
mask: sizet = sizet(self.CDefineNameIdxCap - 1)
|
||||
si: sizet = sizet(h) & mask
|
||||
i: int = 0
|
||||
while i < self.CDefineNameIdxCap:
|
||||
slot: sizet | t.CPtr = self._cdef_idx_slot(si)
|
||||
if slot[0] == 0:
|
||||
slot[0] = sizet(slot_index + 1)
|
||||
return 0
|
||||
si = (si + 1) & mask
|
||||
i += 1
|
||||
return 1
|
||||
|
||||
def _cdef_idx_sync_append(self, name: str) -> None:
|
||||
"""CDefineNames.append 后同步索引(槽下标 = len-1);不可信则保持不可信"""
|
||||
n: int = int(len(self.CDefineNames))
|
||||
if self.CDefineNameIdxBuilt == n - 1 and self._cdef_idx_insert(n - 1, name) == 0:
|
||||
self.CDefineNameIdxBuilt = n
|
||||
else:
|
||||
self.CDefineNameIdxBuilt = -1
|
||||
|
||||
def register_cdefine_constant(self, pool: rowptr[memhub.MemBuddy],
|
||||
name: str, value: int64) -> None:
|
||||
"""注册 CDefine 编译期常量到本地表
|
||||
@@ -49,12 +143,14 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
self.CDefineValues = list[str](pool, 64)
|
||||
self.CDefineDoubleFlags = list[int](pool, 64)
|
||||
self.CDefineStrFlags = list[int](pool, 64)
|
||||
self._cdef_idx_init(pool)
|
||||
name_copy: str = pool.alloc(string.strlen(name) + 1)
|
||||
if name_copy is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine '{name}' 名称缓冲区分配失败", "MemoryError")
|
||||
return
|
||||
string.strcpy(name_copy, name)
|
||||
self.CDefineNames.append(name_copy)
|
||||
self._cdef_idx_sync_append(name_copy)
|
||||
val_buf: str = pool.alloc(32)
|
||||
if val_buf is not None:
|
||||
viperlib.snprintf(val_buf, 32, "%lld", value)
|
||||
@@ -85,12 +181,14 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
self.CDefineValues = list[str](pool, 64)
|
||||
self.CDefineDoubleFlags = list[int](pool, 64)
|
||||
self.CDefineStrFlags = list[int](pool, 64)
|
||||
self._cdef_idx_init(pool)
|
||||
name_copy_d: str = pool.alloc(string.strlen(name) + 1)
|
||||
if name_copy_d is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine 浮点 '{name}' 名称缓冲区分配失败", "MemoryError")
|
||||
return
|
||||
string.strcpy(name_copy_d, name)
|
||||
self.CDefineNames.append(name_copy_d)
|
||||
self._cdef_idx_sync_append(name_copy_d)
|
||||
val_buf: str = pool.alloc(32)
|
||||
if val_buf is not None:
|
||||
# 用 CRT stdio.snprintf 而非 viperlib.snprintf:viperlib 自实现格式化器的
|
||||
@@ -126,12 +224,14 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
self.CDefineValues = list[str](pool, 64)
|
||||
self.CDefineDoubleFlags = list[int](pool, 64)
|
||||
self.CDefineStrFlags = list[int](pool, 64)
|
||||
self._cdef_idx_init(pool)
|
||||
ncopy_s: str = pool.alloc(string.strlen(name) + 1)
|
||||
if ncopy_s is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine 字符串 '{name}' 名称缓冲区分配失败", "MemoryError")
|
||||
return
|
||||
string.strcpy(ncopy_s, name)
|
||||
self.CDefineNames.append(ncopy_s)
|
||||
self._cdef_idx_sync_append(ncopy_s)
|
||||
vlen: sizet = string.strlen(value)
|
||||
vcopy: str = pool.alloc(vlen + 1)
|
||||
if vcopy is None:
|
||||
@@ -239,7 +339,18 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
return 0
|
||||
n: sizet = len(self.CDefineNames)
|
||||
i: sizet
|
||||
for i in range(n):
|
||||
# 名索引快速路径:可信(Built==n)时直接定位唯一候选下标(= 原扫描首个
|
||||
# 命中);未命中 → 确实不存在,直接返回;不可用 → 回退原全表线性扫描。
|
||||
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)
|
||||
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:
|
||||
val_str: str = self.CDefineValues.get(i)
|
||||
@@ -268,9 +379,21 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
return 0.0
|
||||
n: sizet = len(self.CDefineNames)
|
||||
i: sizet
|
||||
for i in range(n):
|
||||
# 名索引快速路径:可信(Built==n)时直接定位唯一候选下标(= 原扫描首个
|
||||
# 命中);未命中 → 确实不存在,直接返回;不可用 → 回退原全表线性扫描。
|
||||
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)
|
||||
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:
|
||||
# 快速路径:strcmp 判等蕴含首字符相等,首字符不同者跳过 strcmp。
|
||||
if nm is not None and nm[0] == name[0] and string.strcmp(nm, name) == 0:
|
||||
val_str: str = self.CDefineValues.get(i)
|
||||
if val_str is not None:
|
||||
self.CDefineFound = 1
|
||||
@@ -297,7 +420,18 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
return None
|
||||
n: sizet = len(self.CDefineNames)
|
||||
i: sizet
|
||||
for i in range(n):
|
||||
# 名索引快速路径:可信(Built==n)时直接定位唯一候选下标(= 原扫描首个
|
||||
# 命中);未命中 → 确实不存在,直接返回;不可用 → 回退原全表线性扫描。
|
||||
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)
|
||||
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:
|
||||
val_str: str = self.CDefineValues.get(i)
|
||||
@@ -326,4 +460,8 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
self.CDefineValues = None
|
||||
self.CDefineDoubleFlags = None
|
||||
self.CDefineStrFlags = None
|
||||
# 名索引随表复位(下次 register 重建);不同步会使 Built 与空表错配
|
||||
self.CDefineNameIdx = None
|
||||
self.CDefineNameIdxCap = 0
|
||||
self.CDefineNameIdxBuilt = -1
|
||||
self.CDefineIsStr = 0
|
||||
Reference in new issue
Block a user