187 lines
8.3 KiB
Plaintext
187 lines
8.3 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import memhub
|
||
import string
|
||
import stdlib
|
||
import llvmlite
|
||
import w32.win32file as win32file
|
||
import w32.win32base as win32base
|
||
import w32.fileio as fileio
|
||
import viperlib
|
||
import sys
|
||
import ast
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.IncludesScanner as IncludesScanner
|
||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||
import lib.Phase.BuildPipeline as BuildPipeline
|
||
import lib.Stub.StubGen.VpiReader as VpiReader
|
||
import lib.Projectrans.Utils as Utils
|
||
import lib.Projectrans.Config as Config
|
||
|
||
|
||
import lib.Stub.StubMerger.StubMergerCollect as StubMergerCollect
|
||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||
import lib.Stub.StubMerger.StubMergerIR as StubMergerIR
|
||
import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild
|
||
import lib.Stub.StubMerger as StubMerger
|
||
|
||
# ============================================================
|
||
# StubMergerTopo - StubMerger 拆分(阶段 E):StubMergerTopo
|
||
#
|
||
# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留
|
||
# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经
|
||
# StubMerger._xxx 访问(main.vp 先例)。
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# BuildTopoSortedIndices - 对可达 includes 逆拓扑排序(被依赖者先)
|
||
#
|
||
# 背景:跨模块 vtable 生成要求被依赖模块先完整翻译(如 astaux.vp 继承
|
||
# base.vp 的 AST,vtable 槽位需 AST.accept 的 TypeStr 已注册到全局表)。
|
||
# Phase B+ 原先按 store 扫描顺序编译,依赖顺序不保证 → fail-fast 暴露。
|
||
#
|
||
# 算法:Kahn 逆拓扑。边 m→d 表示 m 依赖 d(d 在 m 的 deps 中)。
|
||
# indegree[m] = m 在可达集合内的直接依赖数;
|
||
# 入度为 0(不依赖任何可达模块)者先输出,输出后对依赖它的模块
|
||
# 减入度,入度归 0 者入队。结果即"被依赖者先编译"。
|
||
# reachable_count <= 0 时对全部 store 排序(与既有全量编译行为一致)。
|
||
#
|
||
# Args:
|
||
# store_count / store_sha1_arr / store_mod_arr: store 元数据
|
||
# reachable_set / reachable_count: 可达集合(_BuildReachableSha1Set 输出)
|
||
# sorted_idx: 输出数组(store_count+1 个 8 字节槽),前 N 个为拓扑序 store 索引
|
||
#
|
||
# Returns:
|
||
# 拓扑序条数;有环时剩余条目按 store 顺序补齐(避免漏编译)
|
||
# ============================================================
|
||
def BuildTopoSortedIndices(store_count: int, store_sha1_arr: bytes,
|
||
store_mod_arr: bytes, reachable_set: bytes,
|
||
reachable_count: int,
|
||
sorted_idx: t.CSizeT | t.CPtr) -> int:
|
||
"""对可达 includes 逆拓扑排序(被依赖者先),store 索引写入 sorted_idx"""
|
||
if store_count <= 0 or store_sha1_arr is None or store_mod_arr is None or sorted_idx is None:
|
||
return 0
|
||
indegree: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(stdlib.malloc(8 * (store_count + 1)))
|
||
queue: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(stdlib.malloc(8 * (store_count + 1)))
|
||
rel_idx: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(stdlib.malloc(8 * (store_count + 1)))
|
||
if indegree is None or queue is None or rel_idx is None:
|
||
if indegree is not None:
|
||
stdlib.free(indegree)
|
||
if queue is not None:
|
||
stdlib.free(queue)
|
||
if rel_idx is not None:
|
||
stdlib.free(rel_idx)
|
||
return 0
|
||
# 清零 indegree/queue/rel_idx(malloc 返回未初始化内存,Kahn 依赖入度初值 0)
|
||
zi: int = 0
|
||
for zi in range(store_count + 1):
|
||
indegree[zi] = 0
|
||
queue[zi] = 0
|
||
rel_idx[zi] = 0
|
||
# 收集可达 store 索引(reachable_count<=0 时全量,对齐既有全量编译行为)
|
||
rel_count: int = 0
|
||
i_t: int
|
||
if reachable_set is None or reachable_count <= 0:
|
||
for i_t in range(store_count):
|
||
rel_idx[rel_count] = i_t
|
||
rel_count += 1
|
||
else:
|
||
for i_t in range(store_count):
|
||
if StubMergerCollect._is_in_sha1_set(store_sha1_arr + t.CSizeT(i_t) * 17, reachable_set, reachable_count) != 0:
|
||
rel_idx[rel_count] = i_t
|
||
rel_count += 1
|
||
# 诊断:可达 store 索引数(rel_count=0 → topo_count=0 → PhaseB+ 循环不执行)
|
||
fb_rel: str = VLogger.fmt_buf()
|
||
if fb_rel is not None:
|
||
viperlib.snprintf(fb_rel, 1024, "诊断 topo rel_count=%d", rel_count)
|
||
VLogger.debug(fb_rel, "StubMergerTopo")
|
||
# 计算入度:m 在可达集合内的直接依赖数
|
||
i_r: int
|
||
for i_r in range(rel_count):
|
||
si: int = rel_idx[i_r]
|
||
deps_si: str = StubMergerStore.LookupIncludesDeps(store_sha1_arr + t.CSizeT(si) * 17)
|
||
if deps_si is None:
|
||
continue
|
||
dl_si: t.CSizeT = string.strlen(deps_si)
|
||
dpos: t.CSizeT = 0
|
||
while dpos < dl_si:
|
||
dstart: t.CSizeT = dpos
|
||
while dpos < dl_si and deps_si[dpos] != ' ':
|
||
dpos += 1
|
||
dlen: t.CSizeT = dpos - dstart
|
||
if dpos < dl_si:
|
||
dpos += 1
|
||
if dlen == 0:
|
||
continue
|
||
dname_buf: bytes = stdlib.malloc(dlen + 1)
|
||
if dname_buf is None:
|
||
continue
|
||
string.strncpy(dname_buf, deps_si + dstart, dlen)
|
||
dname_buf[dlen] = '\0'
|
||
dsha1: str = StubMergerIR._FindSha1ByModName(store_sha1_arr, store_mod_arr, store_count, dname_buf)
|
||
stdlib.free(dname_buf)
|
||
if dsha1 is not None and StubMergerCollect._is_in_sha1_set(dsha1, reachable_set, reachable_count) != 0:
|
||
# 中间 int 变量累加:绕过联合类型(CSizeT|CPtr)+ 整数的指针算术编译 bug
|
||
indg: int = indegree[si]
|
||
indg = indg + 1
|
||
indegree[si] = indg
|
||
# Kahn:入度为 0(不依赖任何可达模块)者先出 → 最先编译
|
||
q_tail: int = 0
|
||
for i_r in range(rel_count):
|
||
si2: int = rel_idx[i_r]
|
||
if indegree[si2] == 0:
|
||
queue[q_tail] = si2
|
||
q_tail += 1
|
||
out_count: int = 0
|
||
# Kahn 主循环必须用 while(不能用 for range):循环体内会动态入队
|
||
# (queue[q_tail]=si3; q_tail+=1),for range 上界只求值一次,
|
||
# 动态入队的模块永远不会被处理且兜底(indegree>0)也捞不回 → 拓扑漏项
|
||
q_head: int = 0
|
||
while q_head < q_tail:
|
||
m: int = queue[q_head]
|
||
sorted_idx[out_count] = m
|
||
out_count += 1
|
||
# 对依赖 m 的可达模块减入度
|
||
mod_m: str = store_mod_arr + t.CSizeT(m) * 64
|
||
mod_m_len: t.CSizeT = string.strlen(mod_m)
|
||
for i_r in range(rel_count):
|
||
si3: int = rel_idx[i_r]
|
||
if indegree[si3] == 0:
|
||
continue
|
||
deps_si3: str = StubMergerStore.LookupIncludesDeps(store_sha1_arr + t.CSizeT(si3) * 17)
|
||
if deps_si3 is None:
|
||
continue
|
||
dl_si3: t.CSizeT = string.strlen(deps_si3)
|
||
dpos3: t.CSizeT = 0
|
||
found_dep: int = 0
|
||
while dpos3 < dl_si3 and found_dep == 0:
|
||
dstart3: t.CSizeT = dpos3
|
||
while dpos3 < dl_si3 and deps_si3[dpos3] != ' ':
|
||
dpos3 += 1
|
||
dlen3: t.CSizeT = dpos3 - dstart3
|
||
if dpos3 < dl_si3:
|
||
dpos3 += 1
|
||
if dlen3 == 0:
|
||
continue
|
||
if dlen3 == mod_m_len and string.strncmp(deps_si3 + dstart3, mod_m, mod_m_len) == 0:
|
||
found_dep = 1
|
||
if found_dep == 1:
|
||
# 中间 int 变量递减:绕过联合类型指针算术编译 bug
|
||
indg3: int = indegree[si3]
|
||
indg3 = indg3 - 1
|
||
indegree[si3] = indg3
|
||
if indegree[si3] == 0:
|
||
queue[q_tail] = si3
|
||
q_tail += 1
|
||
q_head += 1
|
||
# 有环时剩余条目按 store 顺序补齐(避免漏编译)
|
||
for i_r in range(rel_count):
|
||
si4: int = rel_idx[i_r]
|
||
if indegree[si4] > 0:
|
||
sorted_idx[out_count] = si4
|
||
out_count += 1
|
||
stdlib.free(indegree)
|
||
stdlib.free(queue)
|
||
stdlib.free(rel_idx)
|
||
return out_count
|