feat(sidecar): meta 增写 STRUCT/VTABLE,REPL 布局恢复改读 meta
- WriteModuleFuncMeta 更名 WriteModuleMeta:追加 STRUCT <name> FIELDS n PACKED 0|1
(opaque → STRUCT <name> OPAQUE)与 VTABLE <class> SLOTS n;数据源改为
Module.NamedTypeHead / GlobalHead,不再有任何 IR 文本反推
- VpiReader REPL 布局改读 {sha1}.meta:新增 _meta_atoi / _repl_meta_scan_layout
按前缀精确匹配解析 STRUCT/VTABLE 行
- 删除旧 .stub.ll 文本解析辅助 _repl_stub_take_name / _repl_stub_body_count
及其 scratch 缓冲 ReplStubNameBuf / _REPL_STUB_NAME_CAP
去 IR 化步骤③;未编译验证。
This commit is contained in:
1 parent
78d3941f7d
commit
35f2070d3b
4 files changed
+123
-169
No files matched your search
@@ -29,7 +29,6 @@ import lib.Projectrans.Config as Config
|
||||
_REPL_STUB_CLS_MAX: t.CDefine = 1024
|
||||
_REPL_STUB_FIELD_MAX: int = 128
|
||||
_REPL_STUB_VT_MAX: int = 128
|
||||
_REPL_STUB_NAME_CAP: sizet = 256
|
||||
_REPL_STUB_TXT_CAP: sizet = 4194304
|
||||
_REPL_STUB_WARN_MAX: int = 10
|
||||
_REPL_STUB_FINISH_PASSES: int = 8
|
||||
@@ -3686,7 +3685,6 @@ ReplStubWarnLeft: int = 0
|
||||
ReplStubTmpCount: int = -1
|
||||
ReplStubTmpPacked: int = 0
|
||||
ReplStubTmpArity: int = 0
|
||||
ReplStubNameBuf: str = None
|
||||
|
||||
|
||||
def _repl_stub_dupstr(pool: memhub.MemBuddy*, src: str) -> str:
|
||||
@@ -3761,105 +3759,31 @@ def _repl_stub_readtext(path: str) -> str:
|
||||
return buf
|
||||
|
||||
|
||||
# 从 txt[pos] 起取一个标识符(跳过 '%' / '@' 前缀与可选引号)写进 ReplStubNameBuf;
|
||||
# 返回名字之后的位置(0 = 失败/超长;合法调用至少前进 2 字符,故 0 可作失败哨兵)
|
||||
def _repl_stub_take_name(txt: str, pos: sizet) -> sizet:
|
||||
global ReplStubNameBuf
|
||||
if txt is None or ReplStubNameBuf is None:
|
||||
return 0
|
||||
n: sizet = string.strlen(txt)
|
||||
i: sizet = pos
|
||||
if i < n and (txt[i] == '%' or txt[i] == '@'):
|
||||
# 从 txt[start, end) 解析十进制整数(跳过前导空格;无数字返回 0)
|
||||
def _meta_atoi(txt: str, start: sizet, end: sizet) -> int:
|
||||
i: sizet = start
|
||||
while i < end and (txt[i] == ' ' or txt[i] == '\t'):
|
||||
i += 1
|
||||
if i >= n:
|
||||
return 0
|
||||
if txt[i] == '\"':
|
||||
neg: int = 0
|
||||
if i < end and txt[i] == '-':
|
||||
neg = 1
|
||||
i += 1
|
||||
k: sizet = 0
|
||||
while i < n and txt[i] != '\"':
|
||||
if k + 1 >= _REPL_STUB_NAME_CAP:
|
||||
return 0
|
||||
ReplStubNameBuf[k] = txt[i]
|
||||
k += 1
|
||||
i += 1
|
||||
if i >= n:
|
||||
return 0
|
||||
ReplStubNameBuf[k] = 0
|
||||
return i + 1
|
||||
k2: sizet = 0
|
||||
while i < n:
|
||||
ch: char = txt[i]
|
||||
if ch == ' ' or ch == '\t' or ch == '=' or ch == ',' or ch == '{' or ch == '}':
|
||||
break
|
||||
if ch == '[' or ch == ']' or ch == '(' or ch == ')' or ch == '*' or ch == '<' or ch == '>':
|
||||
break
|
||||
if k2 + 1 >= _REPL_STUB_NAME_CAP:
|
||||
return 0
|
||||
ReplStubNameBuf[k2] = ch
|
||||
k2 += 1
|
||||
v: int = 0
|
||||
while i < end and txt[i] >= '0' and txt[i] <= '9':
|
||||
v = v * 10 + (int(txt[i]) - 48)
|
||||
i += 1
|
||||
if k2 == 0:
|
||||
return 0
|
||||
ReplStubNameBuf[k2] = 0
|
||||
return i
|
||||
if neg != 0:
|
||||
return -v
|
||||
return v
|
||||
|
||||
|
||||
# 从 txt[pos](应指向 '{')起数顶层字段数:{} / [] / () / <> / "..." 内的逗号不计;
|
||||
# 返回字段数(-1 = 未闭合/格式异常)
|
||||
def _repl_stub_body_count(txt: str, pos: sizet) -> int:
|
||||
if txt is None:
|
||||
return -1
|
||||
n: sizet = string.strlen(txt)
|
||||
i: sizet = pos
|
||||
if i >= n or txt[i] != '{':
|
||||
return -1
|
||||
i += 1
|
||||
depth: int = 0
|
||||
in_str: int = 0
|
||||
cnt: int = 0
|
||||
has: int = 0
|
||||
while i < n:
|
||||
ch: char = txt[i]
|
||||
if in_str != 0:
|
||||
if ch == '\"':
|
||||
in_str = 0
|
||||
i += 1
|
||||
continue
|
||||
if ch == '\"':
|
||||
in_str = 1
|
||||
has = 1
|
||||
i += 1
|
||||
continue
|
||||
if ch == 0:
|
||||
return -1
|
||||
if ch == ',':
|
||||
if depth == 0:
|
||||
cnt += 1
|
||||
i += 1
|
||||
continue
|
||||
if ch == '{' or ch == '[' or ch == '(' or ch == '<':
|
||||
depth += 1
|
||||
has = 1
|
||||
i += 1
|
||||
continue
|
||||
if ch == '}' or ch == ']' or ch == ')' or ch == '>':
|
||||
if ch == '}' and depth == 0:
|
||||
if has == 0:
|
||||
return 0
|
||||
return cnt + 1
|
||||
depth -= 1
|
||||
i += 1
|
||||
continue
|
||||
if ch != ' ' and ch != '\t' and ch != '\n' and ch != '\r':
|
||||
has = 1
|
||||
i += 1
|
||||
return -1
|
||||
|
||||
|
||||
# 扫描存根文本,取 `%"<key>" = type ...` 与 `@...<key>.vtable = ...` 两条元数据,
|
||||
# 结果写全局 scratch:ReplStubTmpCount(字段数 / -1 无此类 / -2 opaque)、
|
||||
# ReplStubTmpPacked、ReplStubTmpArity(.vtable 槽数,0 = 无该全局)
|
||||
def _repl_stub_scan_meta(txt: str, key: str) -> None:
|
||||
# 扫描 {sha1}.meta 文本,取 `STRUCT <key> FIELDS <n> PACKED <0|1>`(或 `STRUCT <key> OPAQUE`)
|
||||
# 与 `VTABLE <key> SLOTS <n>` 两条元数据,结果写全局 scratch:
|
||||
# ReplStubTmpCount(字段数 / -1 无此类 / -2 opaque)、ReplStubTmpPacked、
|
||||
# ReplStubTmpArity(虚表槽数,0 = 无该虚表)。key = "{sha1}.{类名}"。
|
||||
# 逐行、按前缀 strncmp 精确匹配,且 name 之后必须紧跟空格(避免前缀误命中);
|
||||
# 不走 take_name —— 类名可能含泛型下标 [ ] 等字符。
|
||||
def _repl_meta_scan_layout(txt: str, key: str) -> None:
|
||||
global ReplStubTmpCount, ReplStubTmpPacked, ReplStubTmpArity
|
||||
ReplStubTmpCount = -1
|
||||
ReplStubTmpPacked = 0
|
||||
@@ -3868,6 +3792,8 @@ def _repl_stub_scan_meta(txt: str, key: str) -> None:
|
||||
return
|
||||
n: sizet = string.strlen(txt)
|
||||
key_len: sizet = string.strlen(key)
|
||||
if key_len == 0:
|
||||
return
|
||||
i: sizet = 0
|
||||
while i < n:
|
||||
ls: sizet = i
|
||||
@@ -3876,61 +3802,37 @@ def _repl_stub_scan_meta(txt: str, key: str) -> None:
|
||||
le: sizet = i
|
||||
if i < n:
|
||||
i += 1
|
||||
p: sizet = ls
|
||||
while p < le and (txt[p] == ' ' or txt[p] == '\t' or txt[p] == '\r'):
|
||||
p += 1
|
||||
if p >= le:
|
||||
continue
|
||||
c0: char = txt[p]
|
||||
if c0 == '%':
|
||||
# 类型定义行
|
||||
q: sizet = _repl_stub_take_name(txt, p)
|
||||
if q == 0 or q > le:
|
||||
if le > ls and txt[le - 1] == '\r':
|
||||
le -= 1
|
||||
if ls + 7 <= le and string.strncmp(txt + ls, "STRUCT ", 7) == 0:
|
||||
ns: sizet = ls + 7
|
||||
ne: sizet = ns + key_len
|
||||
if ne > le or string.strncmp(txt + ns, key, key_len) != 0:
|
||||
continue
|
||||
if string.strcmp(ReplStubNameBuf, key) != 0:
|
||||
if ne >= le or txt[ne] != ' ':
|
||||
continue
|
||||
# 找 "= type"
|
||||
j: sizet = q
|
||||
while j + 6 < le and string.strncmp(txt + j, "= type", 6) != 0:
|
||||
j += 1
|
||||
if j + 6 >= le:
|
||||
continue
|
||||
j += 6
|
||||
while j < le and (txt[j] == ' ' or txt[j] == '\t'):
|
||||
j += 1
|
||||
if j + 6 <= le and string.strncmp(txt + j, "opaque", 6) == 0:
|
||||
# OPAQUE
|
||||
if ne + 7 <= le and string.strncmp(txt + ne + 1, "OPAQUE", 6) == 0:
|
||||
ReplStubTmpCount = -2
|
||||
continue
|
||||
if j < le and txt[j] == '<':
|
||||
ReplStubTmpPacked = 1
|
||||
j += 1
|
||||
if j < le and txt[j] == '{':
|
||||
ReplStubTmpCount = _repl_stub_body_count(txt, j)
|
||||
# FIELDS <n> PACKED <0|1>
|
||||
if ne + 8 <= le and string.strncmp(txt + ne + 1, "FIELDS ", 7) == 0:
|
||||
ReplStubTmpCount = _meta_atoi(txt, ne + 8, le)
|
||||
ps: sizet = ne + 8
|
||||
while ps < le and txt[ps] >= '0' and txt[ps] <= '9':
|
||||
ps += 1
|
||||
if ps + 8 <= le and string.strncmp(txt + ps + 1, "PACKED ", 7) == 0:
|
||||
ReplStubTmpPacked = _meta_atoi(txt, ps + 8, le)
|
||||
continue
|
||||
if c0 == '@':
|
||||
# 全局变量行:只关心 <key>.vtable
|
||||
q2: sizet = _repl_stub_take_name(txt, p)
|
||||
if q2 == 0 or q2 > le:
|
||||
if ls + 7 <= le and string.strncmp(txt + ls, "VTABLE ", 7) == 0:
|
||||
vs: sizet = ls + 7
|
||||
ve: sizet = vs + key_len
|
||||
if ve > le or string.strncmp(txt + vs, key, key_len) != 0:
|
||||
continue
|
||||
nm_len: sizet = string.strlen(ReplStubNameBuf)
|
||||
if nm_len != key_len + 7:
|
||||
if ve >= le or txt[ve] != ' ':
|
||||
continue
|
||||
if string.strncmp(ReplStubNameBuf, key, key_len) != 0:
|
||||
continue
|
||||
if string.strncmp(ReplStubNameBuf + key_len, ".vtable", 7) != 0:
|
||||
continue
|
||||
j2: sizet = q2
|
||||
while j2 < le and txt[j2] != '=':
|
||||
j2 += 1
|
||||
if j2 >= le:
|
||||
continue
|
||||
j2 += 1
|
||||
while j2 < le and txt[j2] != '{':
|
||||
j2 += 1
|
||||
if j2 < le and txt[j2] == '{':
|
||||
ar: int = _repl_stub_body_count(txt, j2)
|
||||
if ar > 0:
|
||||
ReplStubTmpArity = ar
|
||||
if ve + 7 <= le and string.strncmp(txt + ve + 1, "SLOTS ", 6) == 0:
|
||||
ReplStubTmpArity = _meta_atoi(txt, ve + 7, le)
|
||||
continue
|
||||
return
|
||||
|
||||
@@ -3939,7 +3841,7 @@ def ReplStubLayoutBegin(temp_dir: str) -> int:
|
||||
"""开启会话级"存根布局恢复"(Repl.vp 在 includes 类注册前调用一次);0=成功"""
|
||||
global ReplStubLayoutMode, ReplStubPool, ReplStubTempDir, ReplStubTable
|
||||
global ReplStubCount, ReplStubOk, ReplStubVtOk, ReplStubRefused, ReplStubNoStub
|
||||
global ReplStubWarnLeft, ReplStubNameBuf
|
||||
global ReplStubWarnLeft
|
||||
global ReplStubRefusedNoStub, ReplStubRefusedNoClass, ReplStubRefusedOpaque, ReplStubRefusedParent
|
||||
pool: memhub.MemBuddy* = CompilerFactory.factory.PermPool
|
||||
if pool is None or temp_dir is None:
|
||||
@@ -3952,10 +3854,6 @@ def ReplStubLayoutBegin(temp_dir: str) -> int:
|
||||
if ReplStubTable is None:
|
||||
return 1
|
||||
string.memset(ReplStubTable, 0, 8 * _REPL_STUB_CLS_MAX)
|
||||
ReplStubNameBuf = pool.alloc(_REPL_STUB_NAME_CAP)
|
||||
if ReplStubNameBuf is None:
|
||||
return 1
|
||||
ReplStubNameBuf[0] = 0
|
||||
ReplStubCount = 0
|
||||
ReplStubOk = 0
|
||||
ReplStubVtOk = 0
|
||||
@@ -4508,7 +4406,7 @@ def _repl_stub_add_class(pool: memhub.MemBuddy*,
|
||||
# 存根元数据(缺存根时 LayoutCount 保持"未找到"哨兵;两种成因由 have_stub 区分)
|
||||
e.LayoutCount = _REPL_STUB_NOCOUNT_NOCLASS
|
||||
if txt is not None:
|
||||
_repl_stub_scan_meta(txt, key)
|
||||
_repl_meta_scan_layout(txt, key)
|
||||
e.LayoutCount = ReplStubTmpCount
|
||||
e.VtArity = ReplStubTmpArity
|
||||
if ReplStubTmpPacked != 0:
|
||||
@@ -4564,9 +4462,9 @@ def _repl_stub_collect_module(pool: memhub.MemBuddy*,
|
||||
return 0
|
||||
if src_sha1 is None or src_sha1[0] == '\0' or ReplStubTable is None:
|
||||
return 0
|
||||
# 存根文本(缺失:带父类/虚表的类将因"数据缺失"被明确拒绝,逐个可见)
|
||||
# 布局元数据({sha1}.meta;缺失:带父类/虚表的类将因"数据缺失"被明确拒绝,逐个可见)
|
||||
txt: str = None
|
||||
sp: str = _repl_stub_path(src_sha1, "stub.ll")
|
||||
sp: str = _repl_stub_path(src_sha1, "meta")
|
||||
if sp is not None:
|
||||
txt = _repl_stub_readtext(sp)
|
||||
stdlib.free(sp)
|
||||
@@ -4577,8 +4475,8 @@ def _repl_stub_collect_module(pool: memhub.MemBuddy*,
|
||||
ReplStubNoStub += 1
|
||||
if ReplStubWarnLeft > 0:
|
||||
ReplStubWarnLeft -= 1
|
||||
stdio.printf("includes 类布局: 模块 %s 无 .stub.ll 存根(数据缺失)—— 该模块"
|
||||
"带父类/虚表的类将逐个按『数据缺失』明确拒绝(读不到存根 ⇒ 无"
|
||||
stdio.printf("includes 类布局: 模块 %s 无 .meta 存根(数据缺失)—— 该模块"
|
||||
"带父类/虚表的类将逐个按『数据缺失』明确拒绝(读不到布局元数据 ⇒ 无"
|
||||
"字段数可比,不是字段数不符)。用同一工程先跑一次批处理生成存根,"
|
||||
"再 `--project .\\project.vpj --repl`(TransPyV 目录)即可复用\n",
|
||||
src_sha1)
|
||||
|
||||
@@ -31,21 +31,25 @@ import lib.Stub.StubMerger as StubMerger
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# WriteModuleFuncMeta - 落盘 {sha1}.meta 的函数定义清单(结构化 sidecar)
|
||||
# WriteModuleMeta - 落盘 {sha1}.meta(模块结构化 sidecar:函数清单 + 结构体布局 + 虚表)
|
||||
#
|
||||
# 每行 "FUNC <mangled> DEF|DECL":DEF = 本模块定义了该符号(有函数体,等同 .text.ll 的 define 行),
|
||||
# DECL = 仅声明(等同 .stub.ll 的 declare)。数据源为翻译期模型(Module.FuncHead 链表 +
|
||||
# Function.IsDeclared),与 dump_ir 的 stub/text 判据同源(STUB=IsDeclared==1、TEXT==0),
|
||||
# 取代「从 IR 文本反推 declare-vs-define」。
|
||||
# 行格式(每行一条,纯文本、无嵌套括号):
|
||||
# FUNC <mangled> DEF|DECL DEF=本模块定义了该符号(有函数体,等同 .text.ll 的 define 行)
|
||||
# STRUCT <sha1>.<类名> FIELDS <n> PACKED <0|1> 命名结构体字段数/是否 packed
|
||||
# STRUCT <sha1>.<类名> OPAQUE 前向声明(opaque,无 body)
|
||||
# VTABLE <sha1>.<类名> SLOTS <n> 虚表槽数(全局 @<类名>.vtable 的元素数)
|
||||
# 数据源均为翻译期模型(Module.FuncHead / NamedTypeHead / GlobalHead),与 dump_ir 同源,
|
||||
# 取代「从 IR 文本反推 declare-vs-define / 结构体布局 / 虚表槽数」。
|
||||
#
|
||||
# 写不出(路径/打开失败)即 fail-fast:缺 meta 会使 Phase B+/C 的「声明文件判定」失效。
|
||||
# 写不出(路径/打开失败)即 fail-fast:缺 meta 会使 Phase B+/C 的声明文件判定与
|
||||
# REPL 的布局恢复失效。
|
||||
#
|
||||
# Args: mod 已翻译完成的 LLVM 模块;temp_dir 基础目录;td_len temp_dir 长度;sha1 模块 SHA1
|
||||
# Returns: 0=成功(失败经 VLogger.error 终止进程)
|
||||
# ============================================================
|
||||
def WriteModuleFuncMeta(mod: llvmlite.LLVMModule*, temp_dir: str,
|
||||
td_len: sizet, sha1: str) -> int:
|
||||
"""把本模块的函数定义清单写入 {sha1}.meta"""
|
||||
def WriteModuleMeta(mod: llvmlite.LLVMModule*, temp_dir: str,
|
||||
td_len: sizet, sha1: str) -> int:
|
||||
"""把本模块的函数定义/结构体布局/虚表清单写入 {sha1}.meta"""
|
||||
if mod is None or temp_dir is None or sha1 is None:
|
||||
VLogger.error("meta 写出:参数为空", "Meta")
|
||||
return 1
|
||||
@@ -78,6 +82,58 @@ def WriteModuleFuncMeta(mod: llvmlite.LLVMModule*, temp_dir: str,
|
||||
mf.write(line, string.strlen(line))
|
||||
stdlib.free(line)
|
||||
cur = llvmlite.function_get_next(cur)
|
||||
# 2) 结构体布局:STRUCT <name> FIELDS <n> PACKED <0|1>(opaque → STRUCT <name> OPAQUE)
|
||||
nt: llvmlite.NamedTypeNode* = mod.NamedTypeHead
|
||||
nt_steps: sizet = 0
|
||||
while nt is not None:
|
||||
nt_steps += 1
|
||||
if nt_steps > 100000:
|
||||
VLogger.error("meta 写出:命名类型链表成环/超限", "Meta")
|
||||
break
|
||||
tn: str = llvmlite.get_struct_name(nt.Ty)
|
||||
if tn is not None and tn[0] != '\0':
|
||||
tl: sizet = string.strlen(tn)
|
||||
lb: bytes = stdlib.malloc(tl + 48)
|
||||
if lb is None:
|
||||
VLogger.error("meta 写出:行缓冲分配失败", "Meta")
|
||||
break
|
||||
fc: int = llvmlite.get_struct_fcount(nt.Ty)
|
||||
if fc < 0:
|
||||
viperlib.snprintf(lb, tl + 48, "STRUCT %s OPAQUE\n", tn)
|
||||
else:
|
||||
viperlib.snprintf(lb, tl + 48, "STRUCT %s FIELDS %d PACKED %d\n", tn, fc, nt.IsPacked)
|
||||
mf.write(lb, string.strlen(lb))
|
||||
stdlib.free(lb)
|
||||
nt = nt.Next
|
||||
# 3) 虚表槽数:VTABLE <class> SLOTS <n>(全局名 <class>.vtable,Ty 匿名结构体 fcount=槽数)
|
||||
gv: llvmlite.GlobalVariable* = mod.GlobalHead
|
||||
gv_steps: sizet = 0
|
||||
while gv is not None:
|
||||
gv_steps += 1
|
||||
if gv_steps > 100000:
|
||||
VLogger.error("meta 写出:全局变量链表成环/超限", "Meta")
|
||||
break
|
||||
gn: str = gv.Name
|
||||
if gn is not None:
|
||||
gnl: sizet = string.strlen(gn)
|
||||
if gnl > 7 and string.strcmp(gn + gnl - 7, ".vtable") == 0:
|
||||
base_len: sizet = gnl - 7
|
||||
base: bytes = stdlib.malloc(base_len + 1)
|
||||
if base is not None:
|
||||
string.strncpy(base, gn, base_len)
|
||||
base[base_len] = '\0'
|
||||
ar: int = llvmlite.get_struct_fcount(gv.Ty)
|
||||
if ar < 0:
|
||||
ar = 0
|
||||
lb2: bytes = stdlib.malloc(base_len + 40)
|
||||
if lb2 is None:
|
||||
VLogger.error("meta 写出:行缓冲分配失败", "Meta")
|
||||
else:
|
||||
viperlib.snprintf(lb2, base_len + 40, "VTABLE %s SLOTS %d\n", base, ar)
|
||||
mf.write(lb2, string.strlen(lb2))
|
||||
stdlib.free(lb2)
|
||||
stdlib.free(base)
|
||||
gv = gv.Next
|
||||
mf.close()
|
||||
stdlib.free(mpath)
|
||||
return 0
|
||||
|
||||
Reference in new issue
Block a user