382 lines
19 KiB
Plaintext
382 lines
19 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import string
|
||
import stdlib
|
||
import memhub
|
||
import viperlib
|
||
import w32.fileio as fileio
|
||
import w32.win32file
|
||
import w32.win32base
|
||
import ast
|
||
import llvmlite
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Gen.Translator as HandlesTranslator
|
||
import lib.core.IncludesScanner as IncludesScanner
|
||
import lib.Stub.StubMerger as StubMerger
|
||
import lib.core.Gen.Generator as GenGenerator
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
import lib.Phase.BuildPipeline as BuildPipeline
|
||
import lib.Projectrans.Config as Config
|
||
import lib.Stub.StubGen.Converter as StubConverter
|
||
import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild
|
||
import lib.Stub.StubMerger.StubMergerCollect as StubMergerCollect
|
||
import lib.Stub.StubMerger.StubMergerIR as StubMergerIR
|
||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||
|
||
import lib.Phase.Phase1.Phase1Scan as Phase1Scan
|
||
import lib.Phase.Phase1.Phase1Topo as Phase1Topo
|
||
import lib.Phase.Phase1 as Phase1
|
||
|
||
# ============================================================
|
||
# Phase1Topo - 按类继承与 import 依赖对源文件做拓扑排序
|
||
#
|
||
# 函数实现直接位于本模块,调用方经本模块前缀访问;全局符号经 Phase1._xxx 跨模块访问。
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# _TopoSortFiles - 根据类继承关系对文件进行拓扑排序(Kahn)
|
||
#
|
||
# 步骤:1) 从扁平类信息数组构建「文件 SHA1 → 依赖文件 SHA1 集合」映射;2) 计算每个文件入度(DepCount,初始化 InDegree = DepCount);
|
||
# 3) 入度为 0 的先处理,处理后减少依赖它的文件入度;4) 重复直到全部处理完成。
|
||
# 依赖方向是「父类所在文件 → 子类所在文件」,即父类文件必须先处理。
|
||
#
|
||
# Args: mb 内存池;result IncludesScanner 扫描结果;reachable_set 可达 SHA1 集合;reachable_count 可达 SHA1 数量;use_reachable 是否用可达集合过滤;
|
||
# sha1_set SHA1 集合;set_count SHA1 集合数量;class_names_buf 类名扁平数组;parent_names_buf 父类名扁平数组;def_sha1s_buf 定义 SHA1 扁平数组;
|
||
# class_count 类数量;out_order 输出拓扑顺序的文件索引数组(调用者分配,int 数组);out_count 输出文件数量
|
||
# Returns: 0 成功,-1 失败
|
||
# ============================================================
|
||
def _TopoSortFiles(mb: memhub.MemBuddy*,
|
||
result: rawptr[IncludesScanner.ScanResult],
|
||
reachable_set: str, reachable_count: int,
|
||
use_reachable: int,
|
||
sha1_set: str, set_count: int,
|
||
class_names_buf: bytes, parent_names_buf: bytes,
|
||
def_sha1s_buf: bytes, class_count: int,
|
||
out_order: t.CPtr, out_count: t.CPtr,
|
||
temp_dir: str, td_len_ts: sizet) -> int:
|
||
"""根据类继承关系对文件进行拓扑排序"""
|
||
if result is None or out_order is None or out_count is None:
|
||
return -1
|
||
|
||
entry_size: sizet = IncludesScanner.FileEntry.__sizeof__()
|
||
|
||
# 1. 分配扁平数组:文件 SHA1、依赖 SHA1 列表、依赖数量、入度、处理状态
|
||
# 用扁平数组代替 FileDepEntry 结构体,避免 str 指针字段 NULL 崩溃
|
||
file_sha1s_buf: bytes = mb.alloc(Phase1.MAX_FILE_DEPS * Phase1.SHA1_LEN)
|
||
file_deps_buf: bytes = mb.alloc(Phase1.MAX_FILE_DEPS * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN)
|
||
file_dep_counts: t.CPtr = mb.alloc(Phase1.MAX_FILE_DEPS * 4)
|
||
file_indegrees: t.CPtr = mb.alloc(Phase1.MAX_FILE_DEPS * 4)
|
||
file_processed: t.CPtr = mb.alloc(Phase1.MAX_FILE_DEPS * 4)
|
||
|
||
if file_sha1s_buf is None or file_deps_buf is None or file_dep_counts is None or file_indegrees is None or file_processed is None:
|
||
if file_sha1s_buf is not None:
|
||
mb.free(file_sha1s_buf)
|
||
if file_deps_buf is not None:
|
||
mb.free(file_deps_buf)
|
||
if file_dep_counts is not None:
|
||
mb.free(file_dep_counts)
|
||
if file_indegrees is not None:
|
||
mb.free(file_indegrees)
|
||
if file_processed is not None:
|
||
mb.free(file_processed)
|
||
return -1
|
||
|
||
string.memset(file_sha1s_buf, 0, Phase1.MAX_FILE_DEPS * Phase1.SHA1_LEN)
|
||
string.memset(file_deps_buf, 0, Phase1.MAX_FILE_DEPS * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN)
|
||
string.memset(file_dep_counts, 0, Phase1.MAX_FILE_DEPS * 4)
|
||
string.memset(file_indegrees, 0, Phase1.MAX_FILE_DEPS * 4)
|
||
string.memset(file_processed, 0, Phase1.MAX_FILE_DEPS * 4)
|
||
|
||
file_count: int = 0
|
||
# sha1→file_index 映射(简单线性查找,文件数不多)
|
||
for i in range(result.Count):
|
||
entry_addr: uint64 = uint64(result.Entries) + i * entry_size
|
||
entry: rawptr[IncludesScanner.FileEntry] = rawptr[IncludesScanner.FileEntry](entry_addr)
|
||
if entry is None or entry.Sha1 is None:
|
||
continue
|
||
|
||
sha1_e: str = entry.Sha1
|
||
in_set: int = 0
|
||
if use_reachable != 0:
|
||
in_set = StubMergerCollect._is_in_sha1_set(sha1_e, reachable_set, reachable_count)
|
||
else:
|
||
in_set = StubMergerCollect._is_in_sha1_set(sha1_e, sha1_set, set_count)
|
||
if in_set == 0:
|
||
continue
|
||
|
||
if file_count >= Phase1.MAX_FILE_DEPS:
|
||
break
|
||
|
||
# 初始化扁平数组:文件 SHA1(偏移 = file_count * Phase1.SHA1_LEN)
|
||
# DepCount/InDegree/Processed 已由 memset 清零
|
||
sha1_dst: str = file_sha1s_buf + file_count * Phase1.SHA1_LEN
|
||
string.strcpy(sha1_dst, sha1_e)
|
||
|
||
file_count += 1
|
||
|
||
# 2. 构建依赖边:对每个类,找到父类定义所在文件,建立 子文件→父文件 依赖
|
||
for ci in range(class_count):
|
||
# 读取父类名(偏移 = ci * Phase1.CLASS_NAME_LEN)
|
||
parent_ptr: str = parent_names_buf + ci * Phase1.CLASS_NAME_LEN
|
||
if parent_ptr[0] == '\0':
|
||
continue
|
||
|
||
# 读取子类定义 SHA1(偏移 = ci * Phase1.SHA1_LEN)
|
||
child_def_sha1: str = def_sha1s_buf + ci * Phase1.SHA1_LEN
|
||
|
||
# 查找父类定义所在文件的 SHA1
|
||
parent_sha1: str = Phase1Scan._FindClassDefSha1(class_names_buf, def_sha1s_buf, class_count, parent_ptr)
|
||
if parent_sha1 is None:
|
||
continue # 父类不在 includes 中(如 Object、CEnum 等标记基类)
|
||
|
||
# 父类文件 SHA1 不能等于子类文件 SHA1(同文件内继承不需要依赖)
|
||
if string.strcmp(parent_sha1, child_def_sha1) == 0:
|
||
continue
|
||
|
||
# 找到子类文件对应的索引,添加父文件 SHA1 到依赖列表
|
||
for fi in range(file_count):
|
||
fsha1: str = file_sha1s_buf + fi * Phase1.SHA1_LEN
|
||
if string.strcmp(fsha1, child_def_sha1) != 0:
|
||
continue
|
||
|
||
# 读取当前依赖数量
|
||
cnt_addr: uint64 = uint64(file_dep_counts) + fi * 4
|
||
cnt_ptr: t.CPtr = (int | t.CPtr)(cnt_addr)
|
||
if cnt_ptr is None:
|
||
break
|
||
cur_cnt: int = cnt_ptr[0]
|
||
|
||
# 检查依赖是否已添加(去重)
|
||
already: int = 0
|
||
for di in range(cur_cnt):
|
||
dep_slot: str = file_deps_buf + fi * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + di * Phase1.SHA1_LEN
|
||
if string.strcmp(dep_slot, parent_sha1) == 0:
|
||
already = 1
|
||
break
|
||
if already != 0:
|
||
break
|
||
|
||
if cur_cnt < Phase1.MAX_DEP_EDGES:
|
||
dep_dst: str = file_deps_buf + fi * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + cur_cnt * Phase1.SHA1_LEN
|
||
string.strcpy(dep_dst, parent_sha1)
|
||
cnt_ptr[0] = cur_cnt + 1
|
||
break
|
||
|
||
# 2.5 补充 import 依赖边:被 import 的模块先完整翻译。
|
||
#
|
||
# 仅按类继承建边不够:跨模块全局变量 stub、跨模块 vtable TypeStr、泛型模板都要求依赖模块先翻译,而它们之间可能无类继承关系。
|
||
# deps(_includes_deps_*)由 Phase 1a-pre 填充(含容器按需注入的 _list/_dict);用 _BuildIncludesSha1Map 复制局部 sha1→模块名 数组
|
||
# (与 _BuildReachableSha1Set 的 BFS 一致),避免直接跨函数传全局 store 返回值导致地址异常。
|
||
sha1_arr_ts: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 17)
|
||
mod_arr_ts: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 64)
|
||
map_count_ts: int = 0
|
||
if sha1_arr_ts is not None and mod_arr_ts is not None:
|
||
map_count_ts = StubMergerIR._BuildIncludesSha1Map(
|
||
temp_dir, td_len_ts, sha1_arr_ts, mod_arr_ts)
|
||
for fi_imp in range(file_count):
|
||
if map_count_ts <= 0:
|
||
break
|
||
fsha1_imp: str = file_sha1s_buf + fi_imp * Phase1.SHA1_LEN
|
||
deps_imp: str = StubMergerStore.LookupIncludesDeps(fsha1_imp)
|
||
if deps_imp is None:
|
||
continue
|
||
dl_imp: sizet = string.strlen(deps_imp)
|
||
dpos_imp: sizet = 0
|
||
while dpos_imp < dl_imp:
|
||
dstart_imp: sizet = dpos_imp
|
||
while dpos_imp < dl_imp and deps_imp[dpos_imp] != ' ':
|
||
dpos_imp += 1
|
||
dlen_imp: sizet = dpos_imp - dstart_imp
|
||
if dpos_imp < dl_imp:
|
||
dpos_imp += 1
|
||
if dlen_imp == 0:
|
||
continue
|
||
dname_imp: bytes = stdlib.malloc(dlen_imp + 1)
|
||
if dname_imp is None:
|
||
continue
|
||
string.strncpy(dname_imp, deps_imp + dstart_imp, dlen_imp)
|
||
dname_imp[dlen_imp] = '\0'
|
||
dsha1_imp: str = StubMergerIR._FindSha1ByModName(
|
||
sha1_arr_ts, mod_arr_ts, map_count_ts, dname_imp)
|
||
stdlib.free(dname_imp)
|
||
if dsha1_imp is None:
|
||
continue
|
||
# 找依赖文件在列表中的索引(跳过自身)
|
||
for fj_imp in range(file_count):
|
||
if string.strcmp(file_sha1s_buf + fj_imp * Phase1.SHA1_LEN, dsha1_imp) != 0:
|
||
continue
|
||
if fj_imp == fi_imp:
|
||
break
|
||
# 去重 + 加边:fi_imp 依赖 fj_imp(InDegree[fi_imp]++)
|
||
cnt_addr_imp: uint64 = uint64(file_dep_counts) + fi_imp * 4
|
||
cnt_ptr_imp: t.CPtr = (int | t.CPtr)(cnt_addr_imp)
|
||
if cnt_ptr_imp is None:
|
||
break
|
||
cur_cnt_imp: int = cnt_ptr_imp[0]
|
||
already_imp: int = 0
|
||
for di_imp in range(cur_cnt_imp):
|
||
dep_slot_imp: str = file_deps_buf + fi_imp * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + di_imp * Phase1.SHA1_LEN
|
||
if string.strcmp(dep_slot_imp, dsha1_imp) == 0:
|
||
already_imp = 1
|
||
break
|
||
if already_imp == 0 and cur_cnt_imp < Phase1.MAX_DEP_EDGES:
|
||
dep_dst_imp: str = file_deps_buf + fi_imp * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + cur_cnt_imp * Phase1.SHA1_LEN
|
||
string.strcpy(dep_dst_imp, dsha1_imp)
|
||
cnt_ptr_imp[0] = cur_cnt_imp + 1
|
||
break
|
||
|
||
# 释放 import 边用的局部映射数组
|
||
if sha1_arr_ts is not None:
|
||
stdlib.free(sha1_arr_ts)
|
||
if mod_arr_ts is not None:
|
||
stdlib.free(mod_arr_ts)
|
||
|
||
# 3. Kahn 算法:InDegree = DepCount(依赖多少个父文件)
|
||
# 依赖为 0 的先处理,处理后减少依赖它的文件入度
|
||
for fi in range(file_count):
|
||
cnt_addr3: uint64 = uint64(file_dep_counts) + fi * 4
|
||
cnt_ptr3: t.CPtr = (int | t.CPtr)(cnt_addr3)
|
||
ind_addr3: uint64 = uint64(file_indegrees) + fi * 4
|
||
ind_ptr3: t.CPtr = (int | t.CPtr)(ind_addr3)
|
||
if cnt_ptr3 is not None and ind_ptr3 is not None:
|
||
ind_ptr3[0] = cnt_ptr3[0]
|
||
|
||
# 4. 拓扑排序输出
|
||
out_idx: int = 0
|
||
changed: int = 1
|
||
while changed != 0:
|
||
changed = 0
|
||
for fi in range(file_count):
|
||
# 检查处理状态
|
||
proc_addr4: uint64 = uint64(file_processed) + fi * 4
|
||
proc_ptr4: t.CPtr = (int | t.CPtr)(proc_addr4)
|
||
if proc_ptr4 is None or proc_ptr4[0] != 0:
|
||
continue
|
||
# 检查入度
|
||
ind_addr4: uint64 = uint64(file_indegrees) + fi * 4
|
||
ind_ptr4: t.CPtr = (int | t.CPtr)(ind_addr4)
|
||
if ind_ptr4 is None or ind_ptr4[0] > 0:
|
||
continue
|
||
|
||
# 入度为 0,可以处理
|
||
# 找到对应的 result.Entries 索引
|
||
target_sha1: str = file_sha1s_buf + fi * Phase1.SHA1_LEN
|
||
for ri in range(result.Count):
|
||
ea_r: uint64 = uint64(result.Entries) + ri * entry_size
|
||
ent_r: rawptr[IncludesScanner.FileEntry] = rawptr[IncludesScanner.FileEntry](ea_r)
|
||
if ent_r is not None and ent_r.Sha1 is not None:
|
||
if string.strcmp(ent_r.Sha1, target_sha1) == 0:
|
||
# 写入输出索引数组
|
||
out_idx_addr: uint64 = uint64(out_order) + out_idx * 4
|
||
out_int_ptr: t.CPtr = (int | t.CPtr)(out_idx_addr)
|
||
if out_int_ptr is not None:
|
||
out_int_ptr[0] = ri
|
||
out_idx += 1
|
||
break
|
||
|
||
# 标记已处理
|
||
proc_ptr4[0] = 1
|
||
changed = 1
|
||
|
||
# 减少依赖该文件的其他文件的入度
|
||
for fj in range(file_count):
|
||
proc_addr5: uint64 = uint64(file_processed) + fj * 4
|
||
proc_ptr5: t.CPtr = (int | t.CPtr)(proc_addr5)
|
||
if proc_ptr5 is None or proc_ptr5[0] != 0:
|
||
continue
|
||
# 读取 fj 的依赖数量
|
||
cnt_addr5: uint64 = uint64(file_dep_counts) + fj * 4
|
||
cnt_ptr5: t.CPtr = (int | t.CPtr)(cnt_addr5)
|
||
if cnt_ptr5 is None:
|
||
continue
|
||
fj_dep_cnt: int = cnt_ptr5[0]
|
||
for di in range(fj_dep_cnt):
|
||
dep_slot5: str = file_deps_buf + fj * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + di * Phase1.SHA1_LEN
|
||
if string.strcmp(dep_slot5, target_sha1) == 0:
|
||
ind_addr5: uint64 = uint64(file_indegrees) + fj * 4
|
||
ind_ptr5: t.CPtr = (int | t.CPtr)(ind_addr5)
|
||
if ind_ptr5 is not None:
|
||
ind_ptr5[0] = ind_ptr5[0] - 1
|
||
break
|
||
|
||
# 处理循环依赖:环内优先输出被依赖者(被其余剩余文件依赖数量多者先)。
|
||
#
|
||
# 容器按需注入(string 用 list 泛型 → 依赖 _list)与真实 import 会形成伪环,Kahn 无法完全归零;若按扫描顺序追加,
|
||
# 依赖者会先于被依赖者翻译 → 跨模块 vtable TypeStr 未注册 → 误杀。
|
||
if out_idx < file_count:
|
||
rem_idx: t.CPtr = stdlib.malloc(4 * file_count)
|
||
rem_depcnt: t.CPtr = stdlib.malloc(4 * file_count)
|
||
rem_count: int = 0
|
||
if rem_idx is not None and rem_depcnt is not None:
|
||
for fi in range(file_count):
|
||
proc_addr7: uint64 = uint64(file_processed) + fi * 4
|
||
proc_ptr7: t.CPtr = (int | t.CPtr)(proc_addr7)
|
||
if proc_ptr7 is not None and proc_ptr7[0] == 0:
|
||
rem_idx[rem_count] = fi
|
||
rem_depcnt[rem_count] = 0
|
||
rem_count += 1
|
||
# 计算每个剩余文件的被依赖数(被其余剩余文件依赖)
|
||
for i_a in range(rem_count):
|
||
fi_a: int = rem_idx[i_a]
|
||
target_sha1_a: str = file_sha1s_buf + fi_a * Phase1.SHA1_LEN
|
||
for i_b in range(rem_count):
|
||
fi_b: int = rem_idx[i_b]
|
||
if fi_b == fi_a:
|
||
continue
|
||
cnt_addr_b: uint64 = uint64(file_dep_counts) + fi_b * 4
|
||
cnt_ptr_b: t.CPtr = (int | t.CPtr)(cnt_addr_b)
|
||
if cnt_ptr_b is None:
|
||
continue
|
||
cnt_b: int = cnt_ptr_b[0]
|
||
for di_b in range(cnt_b):
|
||
dep_slot_b: str = file_deps_buf + fi_b * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + di_b * Phase1.SHA1_LEN
|
||
if string.strcmp(dep_slot_b, target_sha1_a) == 0:
|
||
rem_depcnt[i_a] = rem_depcnt[i_a] + 1
|
||
break
|
||
# 冒泡降序(被依赖数多者在前)
|
||
for i_a in range(rem_count):
|
||
for j_a in range(rem_count - 1):
|
||
if rem_depcnt[j_a] < rem_depcnt[j_a + 1]:
|
||
tmp_i: int = rem_idx[j_a]
|
||
rem_idx[j_a] = rem_idx[j_a + 1]
|
||
rem_idx[j_a + 1] = tmp_i
|
||
tmp_d: int = rem_depcnt[j_a]
|
||
rem_depcnt[j_a] = rem_depcnt[j_a + 1]
|
||
rem_depcnt[j_a + 1] = tmp_d
|
||
# 按序输出剩余文件
|
||
for i_a in range(rem_count):
|
||
fi_a2: int = rem_idx[i_a]
|
||
proc_addr8: uint64 = uint64(file_processed) + fi_a2 * 4
|
||
proc_ptr8: t.CPtr = (int | t.CPtr)(proc_addr8)
|
||
if proc_ptr8 is None or proc_ptr8[0] != 0:
|
||
continue
|
||
target_sha1_2: str = file_sha1s_buf + fi_a2 * Phase1.SHA1_LEN
|
||
for ri in range(result.Count):
|
||
ea_r2: uint64 = uint64(result.Entries) + ri * entry_size
|
||
ent_r2: rawptr[IncludesScanner.FileEntry] = rawptr[IncludesScanner.FileEntry](ea_r2)
|
||
if ent_r2 is not None and ent_r2.Sha1 is not None:
|
||
if string.strcmp(ent_r2.Sha1, target_sha1_2) == 0:
|
||
out_idx_addr2: uint64 = uint64(out_order) + out_idx * 4
|
||
out_int_ptr2: t.CPtr = (int | t.CPtr)(out_idx_addr2)
|
||
if out_int_ptr2 is not None:
|
||
out_int_ptr2[0] = ri
|
||
out_idx += 1
|
||
break
|
||
proc_ptr8[0] = 1
|
||
stdlib.free(rem_idx)
|
||
stdlib.free(rem_depcnt)
|
||
|
||
# 写入输出数量
|
||
out_count_ptr: t.CPtr = (int | t.CPtr)(out_count)
|
||
if out_count_ptr is not None:
|
||
out_count_ptr[0] = out_idx
|
||
|
||
# 释放扁平数组
|
||
mb.free(file_sha1s_buf)
|
||
mb.free(file_deps_buf)
|
||
mb.free(file_dep_counts)
|
||
mb.free(file_indegrees)
|
||
mb.free(file_processed)
|
||
|
||
return 0
|