411 lines
18 KiB
Plaintext
411 lines
18 KiB
Plaintext
import lib.core.Gen.GenApi as GenApi
|
||
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.StubMergerTopo as StubMergerTopo
|
||
import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild
|
||
import lib.Stub.StubMerger as StubMerger
|
||
|
||
|
||
# ============================================================
|
||
# StubMergerIR - StubMerger 拆分(阶段 E):StubMergerIR
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# IsDeclOnlyModule - 判断模块是否为纯声明文件
|
||
#
|
||
# 读取 {temp_dir}/{sha1}.text.ll,扫描是否含 "define " 行:
|
||
# 返回 1 = 纯声明(无函数体,如 stdio.vp 全 pass),无需 .obj
|
||
# 返回 0 = 实现文件(含 define 函数体)
|
||
# 返回 -1 = text.ll 不存在/无法判断
|
||
#
|
||
# 与 Phase B+(Phase2.vp 编译缺失 includes 时)的内联判断逻辑一致,
|
||
# 供 Phase C 链接时区分"声明文件无需 .obj"与"实现文件缺失"。
|
||
# ============================================================
|
||
def IsDeclOnlyModule(temp_dir: str, td_len: t.CSizeT, sha1: str) -> int:
|
||
"""判断模块是否为纯声明文件(text.ll 无 define 行)"""
|
||
if temp_dir is None or sha1 is None:
|
||
return -1
|
||
tpath: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "text.ll")
|
||
if tpath is None:
|
||
return -1
|
||
tf_d: fileio.File = fileio.File(tpath, fileio.MODE.R)
|
||
stdlib.free(tpath)
|
||
if tf_d.closed:
|
||
return -1
|
||
tbuf_d: bytes = stdlib.malloc(StubMerger.STUB_READ_BUF_SIZE)
|
||
tbr_d: t.CInt64T = 0
|
||
if tbuf_d is not None:
|
||
tbr_d = tf_d.read_all(tbuf_d, StubMerger.STUB_READ_BUF_SIZE)
|
||
tf_d.close()
|
||
if tbuf_d is None:
|
||
return -1
|
||
if tbr_d <= 0:
|
||
# 空 text.ll:无函数体,纯声明
|
||
stdlib.free(tbuf_d)
|
||
return 1
|
||
if tbr_d < StubMerger.STUB_READ_BUF_SIZE:
|
||
tbuf_d[tbr_d] = '\0'
|
||
else:
|
||
tbuf_d[StubMerger.STUB_READ_BUF_SIZE - 1] = '\0'
|
||
# 逐行扫描:找 "define " 行即为实现文件
|
||
tpos_d: t.CSizeT = 0
|
||
while tpos_d < tbr_d:
|
||
tls_d: t.CSizeT = tpos_d
|
||
while tpos_d < tbr_d:
|
||
if tbuf_d[tpos_d] == '\n':
|
||
break
|
||
tpos_d += 1
|
||
tll_d: t.CSizeT = tpos_d - tls_d
|
||
if tpos_d < tbr_d:
|
||
tpos_d += 1
|
||
if tll_d >= 7 and string.strncmp(tbuf_d + tls_d, "define ", 7) == 0:
|
||
stdlib.free(tbuf_d)
|
||
return 0
|
||
stdlib.free(tbuf_d)
|
||
return 1
|
||
# ============================================================
|
||
# _IsFuncDeclaredOrDefined - 检查 out_buf 中是否已有函数的 declare/define
|
||
#
|
||
# 逐字节strncmp搜索 func_sig(如 @"sha1.func"(/ @printf( ),每次
|
||
# 找到匹配后检查行首是否以 "declare " 或 "define " 开头,跳过 call 语句。
|
||
# 避免 strstr 子串匹配误匹配 call ... @"func"(...) 中的 @"func"( 子串。
|
||
#
|
||
# Args:
|
||
# out_buf: 已有的 IR 文本缓冲区
|
||
# func_sig: 函数签名片段,如 @"sha1.func"(/ @printf(
|
||
#
|
||
# Returns:
|
||
# 1=已存在 declare/define, 0=不存在
|
||
# ============================================================
|
||
def _IsFuncDeclaredOrDefined(out_buf: bytes, func_sig: str) -> int:
|
||
"""检查 out_buf 中是否已有函数的 declare 或 define 行"""
|
||
if out_buf is None or func_sig is None:
|
||
return 0
|
||
sig_len: t.CSizeT = string.strlen(func_sig)
|
||
out_len: t.CSizeT = string.strlen(out_buf)
|
||
if sig_len == 0 or out_len == 0 or sig_len > out_len:
|
||
return 0
|
||
pos: t.CSizeT = 0
|
||
for pos in range(0, out_len - sig_len + 1):
|
||
if string.strncmp(out_buf + pos, func_sig, sig_len) == 0:
|
||
ls: t.CSizeT = pos
|
||
while ls > 0 and out_buf[ls - 1] != '\n':
|
||
ls -= 1
|
||
if string.strncmp(out_buf + ls, "declare ", 8) == 0:
|
||
return 1
|
||
if string.strncmp(out_buf + ls, "define ", 7) == 0:
|
||
return 1
|
||
return 0
|
||
# ============================================================
|
||
# _CommentOutDeclareInBuf - 将 out_buf 中匹配 func_sig 的 declare 行注释掉
|
||
#
|
||
# 用于解决 declare/define 冲突:当本地 text.ll 包含 define 而依赖
|
||
# text.ll 已生成了同函数的 declare 时,将 declare 行首字符改为 ';'
|
||
# 使其成为注释,然后追加 define 行。
|
||
# ============================================================
|
||
def _CommentOutDeclareInBuf(out_buf: bytes, func_sig: str) -> int:
|
||
"""在 out_buf 中搜索 declare 行(包含 func_sig),将其注释掉"""
|
||
if out_buf is None or func_sig is None:
|
||
return 0
|
||
sig_len: t.CSizeT = string.strlen(func_sig)
|
||
out_len: t.CSizeT = string.strlen(out_buf)
|
||
if sig_len == 0 or out_len == 0 or sig_len > out_len:
|
||
return 0
|
||
pos: t.CSizeT = 0
|
||
while pos + sig_len <= out_len:
|
||
if string.strncmp(out_buf + pos, func_sig, sig_len) == 0:
|
||
ls: t.CSizeT = pos
|
||
while ls > 0 and out_buf[ls - 1] != '\n':
|
||
ls -= 1
|
||
if string.strncmp(out_buf + ls, "declare ", 8) == 0:
|
||
out_buf[ls] = ';'
|
||
return 1
|
||
pos += 1
|
||
return 0
|
||
# ============================================================
|
||
# _CommentOutGlobalInBuf - 将 out_buf 中匹配全局变量名的行注释掉
|
||
#
|
||
# 解决 stub/text 全局变量重复定义问题:stub 中可能是 external 声明
|
||
# 或完整定义,以 text 中的定义为准,将 stub 中的同名行注释掉。
|
||
# ============================================================
|
||
def _CommentOutGlobalInBuf(out_buf: bytes, global_name: str) -> int:
|
||
"""在 out_buf 中搜索全局变量定义行(以 global_name 开头),将行首改为 ';'
|
||
|
||
注释掉**所有**匹配行(而非仅第一个):跨模块同名裸全局(如 main.vp 与
|
||
argparse.vp 都声明 StubMerger._mbuddy)时,本地 stub external + 依赖 stub external +
|
||
依赖 text 定义会同时存在。只注释第一个会导致依赖 text 的定义残留 →
|
||
合成 IR 重复定义 → llc "redefinition of global '@StubMerger._mbuddy'"(ArgparseTest
|
||
回归根因)。"以 text 中定义为准"的语义:后追加者注释掉全部旧行,最终
|
||
只保留最后一个定义。
|
||
"""
|
||
if out_buf is None or global_name is None:
|
||
return 0
|
||
name_len: t.CSizeT = string.strlen(global_name)
|
||
out_len: t.CSizeT = string.strlen(out_buf)
|
||
if name_len == 0 or out_len == 0 or name_len > out_len:
|
||
return 0
|
||
pos: t.CSizeT = 0
|
||
commented: int = 0
|
||
while pos + name_len <= out_len:
|
||
if string.strncmp(out_buf + pos, global_name, name_len) == 0:
|
||
# 确认是行首(前一个是换行或 pos==0)
|
||
if pos == 0 or out_buf[pos - 1] == '\n':
|
||
out_buf[pos] = ';'
|
||
commented = 1
|
||
pos += 1
|
||
return commented
|
||
def _HasGlobalInBuf(out_buf: bytes, global_name: str) -> int:
|
||
"""检测 out_buf 中是否已有同名全局变量行(行首匹配,未注释)
|
||
|
||
用于跳过重复追加依赖全局强定义:stub 注入已提供 external 声明,
|
||
依赖 text.ll 的强定义只需在定义模块存在一份,复制进每个依赖方
|
||
会导致 ld.lld duplicate symbol(如 _op_head、MemBuddy.vtable)。
|
||
"""
|
||
if out_buf is None or global_name is None:
|
||
return 0
|
||
name_len: t.CSizeT = string.strlen(global_name)
|
||
out_len: t.CSizeT = string.strlen(out_buf)
|
||
if name_len == 0 or out_len == 0 or name_len > out_len:
|
||
return 0
|
||
pos: t.CSizeT = 0
|
||
while pos + name_len <= out_len:
|
||
if string.strncmp(out_buf + pos, global_name, name_len) == 0:
|
||
# 确认是行首(前一个是换行或 pos==0)
|
||
if pos == 0 or out_buf[pos - 1] == '\n':
|
||
return 1
|
||
pos += 1
|
||
return 0
|
||
# ============================================================
|
||
# _CommentOutOpaqueTypeInBuf - 将 out_buf 中匹配类型名的 opaque 声明行注释掉
|
||
#
|
||
# 解决跨模块类型定义冲突:本地 stub 可能包含自动生成的 opaque 声明
|
||
#(如 %"sha1.Widget" = type opaque),而依赖 stub 包含完整定义
|
||
#(如 %"sha1.Widget" = type { i8*, i32 })。去重时需要将 opaque 声明
|
||
# 注释掉,让完整定义被追加,否则 LLC 报错 "Cannot allocate unsized type"。
|
||
# ============================================================
|
||
def _CommentOutOpaqueTypeInBuf(out_buf: bytes, type_name_prefix: str) -> int:
|
||
"""在 out_buf 中搜索 type_name_prefix 对应的 opaque 声明行,将行首改为 ';'
|
||
|
||
type_name_prefix 格式: '%"sha1.ClassName"'(不含 '=' 和后续内容)
|
||
返回 1=已注释, 0=未找到
|
||
"""
|
||
if out_buf is None or type_name_prefix is None:
|
||
return 0
|
||
prefix_len: t.CSizeT = string.strlen(type_name_prefix)
|
||
out_len: t.CSizeT = string.strlen(out_buf)
|
||
if prefix_len == 0 or out_len == 0 or prefix_len > out_len:
|
||
return 0
|
||
pos: t.CSizeT = 0
|
||
while pos + prefix_len <= out_len:
|
||
if string.strncmp(out_buf + pos, type_name_prefix, prefix_len) == 0:
|
||
# 确认是行首(前一个是换行或 pos==0)
|
||
if pos == 0 or out_buf[pos - 1] == '\n':
|
||
# 检查后面是否是 " = type opaque"
|
||
p: t.CSizeT = pos + prefix_len
|
||
# 跳过空格
|
||
while p < out_len and out_buf[p] == ' ':
|
||
p += 1
|
||
if p < out_len and out_buf[p] == '=':
|
||
p += 1
|
||
while p < out_len and out_buf[p] == ' ':
|
||
p += 1
|
||
if p + 11 <= out_len:
|
||
if string.strncmp(out_buf + p, "type opaque", 11) == 0:
|
||
# 找到 opaque 声明,将行首改为 ';'
|
||
out_buf[pos] = ';'
|
||
return 1
|
||
pos += 1
|
||
return 0
|
||
# ============================================================
|
||
# _is_submodule_of_imported - 检查模块名是否是已导入包的子模块
|
||
#
|
||
# deps.txt 只记录直接导入的模块名(如 "ast"),但包的 __init__.vp
|
||
# 内部 from .lexer import Lexer 会让 IR 引用 ast.lexer 子模块类型。
|
||
# 当模块名包含 '.' 时,检查其顶层包名是否在 deps_buf 中。
|
||
#
|
||
# 例如:
|
||
# deps_buf = "ast stdio string"
|
||
# mod_name = "ast.lexer" → 顶层包 "ast" 在 deps_buf 中 → 返回 1
|
||
# mod_name = "ast.token" → 顶层包 "ast" 在 deps_buf 中 → 返回 1
|
||
# mod_name = "foo.bar" → 顶层包 "foo" 不在 deps_buf 中 → 返回 0
|
||
# ============================================================
|
||
def _is_submodule_of_imported(deps_buf: str, mod_name: str) -> int:
|
||
"""检查 mod_name 是否是 deps_buf 中已导入包的子模块"""
|
||
if deps_buf is None or mod_name is None:
|
||
return 0
|
||
# 查找第一个 '.',提取顶层包名
|
||
dot_pos: str = string.strchr(mod_name, 46) # '.' = 46
|
||
if dot_pos is None:
|
||
return 0
|
||
pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(dot_pos) - t.CUInt64T(mod_name))
|
||
if pkg_len == 0 or pkg_len >= 256:
|
||
return 0
|
||
# 构造顶层包名(截断到 '.' 之前)
|
||
# 直接在 mod_name 上临时截断检查,避免分配
|
||
saved_ch: t.CChar = mod_name[pkg_len]
|
||
mod_name[pkg_len] = '\0'
|
||
result: int = GenApi.is_module_imported(deps_buf, mod_name)
|
||
mod_name[pkg_len] = saved_ch
|
||
return result
|
||
# ============================================================
|
||
# _HasFullTypeDefinition - 检查 out_buf 中是否已有完整类型定义(非 opaque)
|
||
#
|
||
# type_name_prefix 格式: '%"sha1.ClassName"'(不含 '=')
|
||
# 完整定义: %"name" = type { ... } 或 %"name" = type < { ... } >
|
||
# 返回 1=已有完整定义, 0=无完整定义
|
||
# ============================================================
|
||
def _HasFullTypeDefinition(out_buf: bytes, type_name_prefix: str) -> int:
|
||
"""检查 out_buf 中是否已有 type_name_prefix 的完整定义"""
|
||
if out_buf is None or type_name_prefix is None:
|
||
return 0
|
||
prefix_len: t.CSizeT = string.strlen(type_name_prefix)
|
||
out_len: t.CSizeT = string.strlen(out_buf)
|
||
if prefix_len == 0 or out_len == 0 or prefix_len > out_len:
|
||
return 0
|
||
pos: t.CSizeT = 0
|
||
while pos + prefix_len <= out_len:
|
||
if string.strncmp(out_buf + pos, type_name_prefix, prefix_len) == 0:
|
||
# 确认是行首(前一个是换行或 pos==0),且未被注释(行首不是 ';')
|
||
is_line_start: int = 0
|
||
if pos == 0:
|
||
is_line_start = 1
|
||
elif out_buf[pos - 1] == '\n':
|
||
is_line_start = 1
|
||
if is_line_start == 1:
|
||
# 检查后面是否是 " = type {" 或 " = type <"
|
||
p: t.CSizeT = pos + prefix_len
|
||
while p < out_len and out_buf[p] == ' ':
|
||
p += 1
|
||
if p < out_len and out_buf[p] == '=':
|
||
p += 1
|
||
while p < out_len and out_buf[p] == ' ':
|
||
p += 1
|
||
if p + 5 < out_len:
|
||
if string.strncmp(out_buf + p, "type ", 5) == 0:
|
||
p += 5
|
||
if p < out_len:
|
||
if out_buf[p] == '{' or out_buf[p] == '<':
|
||
return 1
|
||
pos += 1
|
||
return 0
|
||
# ============================================================
|
||
# _BuildIncludesSha1Map - 从全局内存存储器构建 sha1 → module_name 映射
|
||
#
|
||
# 数据来源是 PopulateSha1MapStore 填充的全局存储器(不读取 _sha1_map.txt)。
|
||
# 返回两个数组(sha1_list 和 mod_list),长度存储在 count 中。
|
||
# 所有内存由 stdlib.malloc 分配,调用者负责释放。
|
||
# ============================================================
|
||
def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT,
|
||
sha1_list: str,
|
||
mod_list: str) -> int:
|
||
"""从全局内存存储器复制 sha1→module_name 映射到调用者数组
|
||
|
||
temp_dir/td_len 参数保留以兼容现有调用者,但不再使用。
|
||
数据来源是 PopulateSha1MapStore 填充的全局存储器。
|
||
"""
|
||
if sha1_list is None or mod_list is None:
|
||
return 0
|
||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None:
|
||
return 0
|
||
count: int = 0
|
||
for i in range(StubMerger._sha1_store_count):
|
||
if count >= StubMerger.MAX_INCLUDES:
|
||
break
|
||
idx: t.CSizeT = t.CSizeT(i) * 17
|
||
idx2: t.CSizeT = t.CSizeT(i) * 64
|
||
string.strcpy(sha1_list + t.CSizeT(count) * 17, StubMerger._sha1_store_arr + idx)
|
||
string.strcpy(mod_list + t.CSizeT(count) * 64, StubMerger._sha1_store_mod + idx2)
|
||
count += 1
|
||
return count
|
||
# ============================================================
|
||
# _FindSha1ByModName - 从模块名查找 SHA1(精确匹配)
|
||
#
|
||
# 在 sha1_arr/mod_arr 映射中查找模块名对应的 SHA1。
|
||
# 用于依赖图分析:模块名 → SHA1。
|
||
#
|
||
# Args:
|
||
# sha1_arr: SHA1 数组(每个 17 字节)
|
||
# mod_arr: 模块名数组(每个 64 字节)
|
||
# count: 映射条目数
|
||
# mod_name: 要查找的模块名
|
||
#
|
||
# Returns:
|
||
# SHA1 字符串指针(指向 sha1_arr 内部,无需释放),未找到返回 None
|
||
# ============================================================
|
||
def _FindSha1ByModName(sha1_arr: str, mod_arr: str,
|
||
count: int, mod_name: str) -> str:
|
||
"""从模块名查找 SHA1(精确匹配 + 包名回退)
|
||
|
||
精确匹配失败时,尝试 "{mod_name}.__init__" 回退,
|
||
支持 import ast(包)→ ast.__init__ 的 SHA1 查找。
|
||
"""
|
||
if sha1_arr is None or mod_arr is None or mod_name is None:
|
||
return None
|
||
if count <= 0:
|
||
return None
|
||
# 第一遍:精确匹配
|
||
for i in range(count):
|
||
idx: t.CSizeT = t.CSizeT(i) * 64
|
||
if string.strcmp(mod_arr + idx, mod_name) == 0:
|
||
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||
return sha1_arr + sidx
|
||
# 第二遍:包名回退("ast" → "ast.__init__")
|
||
nm_len: t.CSizeT = string.strlen(mod_name)
|
||
init_buf: bytes = stdlib.malloc(nm_len + 12)
|
||
if init_buf is not None:
|
||
viperlib.snprintf(init_buf, nm_len + 12, "%s.__init__", mod_name)
|
||
for i in range(count):
|
||
idx2: t.CSizeT = t.CSizeT(i) * 64
|
||
if string.strcmp(mod_arr + idx2, init_buf) == 0:
|
||
sidx2: t.CSizeT = t.CSizeT(i) * 17
|
||
stdlib.free(init_buf)
|
||
return sha1_arr + sidx2
|
||
stdlib.free(init_buf)
|
||
return None
|
||
# ============================================================
|
||
# _AddSha1ToSet - 将 SHA1 加入集合(去重)
|
||
#
|
||
# 检查 SHA1 是否已在集合中,若不在则加入。返回新的 count。
|
||
#
|
||
# Args:
|
||
# set_buf: SHA1 集合缓冲区(每个 17 字节)
|
||
# count: 当前集合中的 SHA1 数量
|
||
# sha1: 要加入的 SHA1
|
||
#
|
||
# Returns:
|
||
# 新的 count(如果已存在则不变)
|
||
# ============================================================
|
||
def _AddSha1ToSet(set_buf: str, count: int, sha1: str) -> int:
|
||
"""将 SHA1 加入集合,返回新 count"""
|
||
if set_buf is None or sha1 is None:
|
||
return count
|
||
for i in range(count):
|
||
idx: t.CSizeT = t.CSizeT(i) * 17
|
||
if string.strcmp(set_buf + idx, sha1) == 0:
|
||
return count
|
||
if count < StubMerger.MAX_INCLUDES_SHA1:
|
||
idx: t.CSizeT = t.CSizeT(count) * 17
|
||
string.strcpy(set_buf + idx, sha1)
|
||
return count + 1
|
||
return count
|