diff --git a/App/lib/Phase/BuildPipeline.vp b/App/lib/Phase/BuildPipeline.vp index 851997d..3251b25 100644 --- a/App/lib/Phase/BuildPipeline.vp +++ b/App/lib/Phase/BuildPipeline.vp @@ -1,5 +1,4 @@ import lib.core.Gen.GenApi as GenApi -import t, c from stdint import * import stdio import string @@ -262,8 +261,8 @@ class BuildResult: OutputPath: str ErrorMsg: str - def __new__(self) -> t.CPtr: - return t.CPtr(_mbuddy.alloc(BuildResult.__sizeof__())) + def __new__(self) -> rawptr: + return rawptr(_mbuddy.alloc(BuildResult.__sizeof__())) def __init__(self): self.Success = 0 @@ -576,12 +575,12 @@ def _run_cmd_wait(cmd: str) -> int: string.memset(&sa, 0, win32.win32base.SECURITY_ATTRIBUTES.__sizeof__()) string.memset(&pi, 0, win32process.PROCESS_INFORMATION.__sizeof__()) sa.nLength = win32.win32base.SECURITY_ATTRIBUTES.__sizeof__() - sa.lpSecurityDescriptor = t.CPtr(0) + sa.lpSecurityDescriptor = None sa.bInheritHandle = 1 si.cb = win32process.STARTUPINFOA.__sizeof__() # create_flags=0: the child inherits the parent console (output shown, like system); # si.dwFlags stays 0 after memset (no STARTF_USESTDHANDLES, no std handles). - ok: int = win32process.CreateProcessA(t.CPtr(0), cmd_line, t.CPtr(0), t.CPtr(0), 1, 0, t.CPtr(0), t.CPtr(0), &si, &pi) + ok: int = win32process.CreateProcessA(None, cmd_line, None, None, 1, 0, None, None, &si, &pi) # CreateProcessA failure diagnostics: read GetLastError immediately (later calls overwrite # it). Use warning, not error (error would sys.exit in a worker thread). if ok == 0: @@ -597,10 +596,10 @@ def _run_cmd_wait(cmd: str) -> int: return int(exit_code) -def _llc_task_worker(arg: t.CPtr) -> t.CPtr: +def _llc_task_worker(arg: rawptr) -> rawptr: """llc thread entry: only calls _run_cmd_wait, no pool allocation (thread-safe).""" task: LlcTask* = (LlcTask*)(arg) - if task is None: return t.CPtr(0) + if task is None: return None # MLIR backend: validate (mlir-opt) -> lower (mlir-translate), then ASan opt -> llc if task.MlirOptCmd is not None: mo_rc: int = _run_cmd_wait(task.MlirOptCmd) @@ -608,21 +607,21 @@ def _llc_task_worker(arg: t.CPtr) -> t.CPtr: task.ExitCode = mo_rc task.FailStage = LLC_STAGE_MLIR_OPT task.Result = 1 - return t.CPtr(0) + return None if task.MlirTranslateCmd is not None: mt_rc: int = _run_cmd_wait(task.MlirTranslateCmd) if mt_rc != 0: task.ExitCode = mt_rc task.FailStage = LLC_STAGE_MLIR_TRANSLATE task.Result = 1 - return t.CPtr(0) + return None if task.OptCmd is not None: opt_rc: int = _run_cmd_wait(task.OptCmd) if opt_rc != 0: task.ExitCode = opt_rc task.FailStage = LLC_STAGE_ASAN_OPT task.Result = 1 - return t.CPtr(0) + return None llc_rc: int = _run_cmd_wait(task.LlcCmd) task.ExitCode = llc_rc if llc_rc != 0: @@ -631,7 +630,7 @@ def _llc_task_worker(arg: t.CPtr) -> t.CPtr: else: task.FailStage = LLC_STAGE_NONE task.Result = 0 - return t.CPtr(0) + return None def run_llc_parallel(tasks: bytes, task_count: int, max_threads: int) -> int: @@ -650,7 +649,7 @@ def run_llc_parallel(tasks: bytes, task_count: int, max_threads: int) -> int: return 0 if max_threads <= 0: max_threads = 1 # Thread-handle array: list[str] (str=bytes=i8*, explicit elem_size=8) stores handles; - # list[t.CPtr] append crashes reading page zero. Grab the handle right after start(). + # list[rawptr] append crashes reading page zero. Grab the handle right after start(). handles: list[str]* = list[str](_mbuddy, 8) if handles is None: VLogger.error("run_llc_parallel: failed to allocate thread handle array", "PhaseB") @@ -664,13 +663,13 @@ def run_llc_parallel(tasks: bytes, task_count: int, max_threads: int) -> int: # spawn this batch for j in range(int(batch_n)): tsk: LlcTask* = (LlcTask*)(uint64(tasks) + sizet(batch_start + j) * slot_size) - th: vthreading.Thread* = vthreading.Thread(_llc_task_worker, t.CPtr(tsk)) + th: vthreading.Thread* = vthreading.Thread(_llc_task_worker, rawptr(tsk)) th.start() # Read the handle right after start() (the Thread object's stack slot may be # reused; reading self.handle at join could see a cleared/overwritten value). - handles.append(t.CPtr(th.handle)) + handles.append(rawptr(th.handle)) for j in range(int(batch_n)): - h_j: t.CPtr = t.CPtr(handles.get(batch_start + j)) + h_j: rawptr = rawptr(handles.get(batch_start + j)) wr: uint32 = win32sync.WaitForSingleObject(h_j, 600000) if wr != 0: VLogger.error("llc thread join timeout/failure (not finished within 600 seconds)", "PhaseB") win32.win32base.CloseHandle(h_j) @@ -1052,8 +1051,8 @@ class TbPeLayout: SizeOfImage: uint64 TextRva: uint64 - def __new__(self) -> t.CPtr: - return t.CPtr(_mbuddy.alloc(TbPeLayout.__sizeof__())) + def __new__(self) -> rawptr: + return rawptr(_mbuddy.alloc(TbPeLayout.__sizeof__())) def __init__(self): self.Ok = 0 @@ -1071,8 +1070,8 @@ class TbDump: FuncCap: int FuncCount: int - def __new__(self) -> t.CPtr: - return t.CPtr(_mbuddy.alloc(TbDump.__sizeof__())) + def __new__(self) -> rawptr: + return rawptr(_mbuddy.alloc(TbDump.__sizeof__())) def __init__(self): self.RowBuf = None @@ -1090,8 +1089,8 @@ class TbPool: Offs: bytes OffCount: int - def __new__(self) -> t.CPtr: - return t.CPtr(_mbuddy.alloc(TbPool.__sizeof__())) + def __new__(self) -> rawptr: + return rawptr(_mbuddy.alloc(TbPool.__sizeof__())) def __init__(self): self.Pool = None @@ -1118,9 +1117,12 @@ def _tb_rd_u32(buf: bytes, off: sizet) -> uint32: def _tb_rd_u64(buf: bytes, off: sizet) -> uint64: - lo: uint64 = uint64(_tb_rd_u32(buf, off)) - hi: uint64 = uint64(_tb_rd_u32(buf, off + 4)) - return lo | (hi << 32) + # Assemble via memcpy instead of u32 widening + shifts: the manual form left 0xFFFFFFFF in + # the high half (a stale register/slot), which then looked like a wild pointer in the + # stackmap tables. memcpy is exact and little-endian on x86-64. + v: uint64 = 0 + string.memcpy(&v, buf + off, 8) + return v def _tb_wr_u32(buf: bytes, off: sizet, v: uint64): @@ -1131,8 +1133,18 @@ def _tb_wr_u32(buf: bytes, off: sizet, v: uint64): def _tb_wr_u64(buf: bytes, off: sizet, v: uint64): - _tb_wr_u32(buf, off, v & 0xFFFFFFFF) - _tb_wr_u32(buf, off + 4, (v >> 32) & 0xFFFFFFFF) + string.memcpy(buf + off, &v, 8) + + +def _tb_wr_ptr(buf: bytes, off: sizet, p: str): + """Store a string pointer into a byte table without a ptr->int cast. + + Do NOT write `memcpy(buf + off, &p, 8)`: passing `&p` (i8**) to a `rawptr` parameter is + currently compiled as a dereference (it copies the string's first 8 bytes instead of the + pointer value), so go through a typed slot instead. + """ + slot: str* = str*(buf + off) + slot[0] = p # ---- tiny string helpers (no re module) ---- @@ -1142,6 +1154,18 @@ def _tb_cc(s: str, i: sizet) -> int: return int(s[i]) & 0xFF +def _tb_str_ok(s: str) -> int: + """Return 1 when s is a plausible user-space string pointer (not 0, -1 or garbage). + + DWARF/objdump text is parsed into pointer-bearing tables; a single bad slot would later be + dereferenced by _tb_cc/strlen and crash the compiler with ASan "unknown address 0xffff...". + Callers use this to reject such a slot at the boundary instead of storing it. + """ + if s is None: return 0 + v: uint64 = uint64(s) + return 1 if v >= 65536 and v <= 0x7FFFFFFFFFFF else 0 + + def _tb_contains(s: str, sub: str) -> int: if s is None or sub is None: return 0 return 1 if string.strstr(s, sub) is not None else 0 @@ -1331,7 +1355,13 @@ def _tb_quoted_after(mb: memhub.MemBuddy*, s: str, key: str) -> str: def _tb_dir_lookup(dirs: bytes, count: int, idx: int) -> str: for i in range(int(count)): - if int(_tb_rd_u32(dirs, sizet(i) * TB_DIR_SIZE)) == idx: return rawptr(_tb_rd_u64(dirs, sizet(i) * TB_DIR_SIZE + 8)) + if int(_tb_rd_u32(dirs, sizet(i) * TB_DIR_SIZE)) == idx: + p: uint64 = _tb_rd_u64(dirs, sizet(i) * TB_DIR_SIZE + 8) + # fail-fast: a wild name pointer would crash inside _tb_is_abs_path/strlen later. + if p < 65536 or p > 0x7FFFFFFFFFFF: + VLogger.error(f"--traceback: internal error: DWARF directory record {i} has an invalid name pointer ({p})", "TRACEBACK") + return None + return rawptr(p) return None @@ -1345,8 +1375,20 @@ def _tb_resolve_file(mb: memhub.MemBuddy*, files: bytes, fcount: int, dirs: byte """Resolve a file-table entry to a path (absolute name wins, else dir join).""" roff: sizet = sizet(frec) * TB_FILE_SIZE cached: uint64 = _tb_rd_u64(files, roff + 24) - if cached != 0: return rawptr(cached) - name: str = rawptr(_tb_rd_u64(files, roff + 8)) + if cached != 0: + # fail-fast: a wild cached path would crash inside strlen/is_abs_path below; report the + # record that carries it together with the table state instead. + if cached < 65536 or cached > 0x7FFFFFFFFFFF: + VLogger.error(f"--traceback: internal error: DWARF file record {frec} has an invalid cached path pointer ({cached})", "TRACEBACK") + return None + return rawptr(cached) + nptr: uint64 = _tb_rd_u64(files, roff + 8) + if nptr < 65536 or nptr > 0x7FFFFFFFFFFF: + ridx: uint64 = uint64(_tb_rd_u32(files, roff)) + rdir: uint64 = uint64(_tb_rd_u32(files, roff + 4)) + VLogger.error(f"--traceback: internal error: DWARF file record {frec} has an invalid name pointer ({nptr}); record idx={ridx} dir_index={rdir}, records in table={fcount}", "TRACEBACK") + return None + name: str = rawptr(nptr) path: str = name if name is not None and _tb_is_abs_path(name) == 0: didx: int = int(_tb_rd_u32(files, roff + 4)) @@ -1357,7 +1399,7 @@ def _tb_resolve_file(mb: memhub.MemBuddy*, files: bytes, fcount: int, dirs: byte if root is not None and _tb_is_abs_path(root) != 0: base = _tb_join(mb, root, base) path = _tb_join(mb, base, name) if path is None or string.strlen(path) == 0: path = "??" - _tb_wr_u64(files, roff + 24, uint64(path)) + _tb_wr_ptr(files, roff + 24, path) return path @@ -1371,6 +1413,10 @@ def _tb_grow_rec(mb: memhub.MemBuddy*, buf: bytes, old_cap: int, rec_size: int, def _tb_emit_row(mb: memhub.MemBuddy*, d: TbDump*, addr: uint64, path: str, line: int, fname: str = None) -> int: if d is None: return 1 + # Every row must carry a file path. A caller that could not resolve one passes None (or a + # wild sentinel); storing that as-is makes the later strlen() sizing pass fault. Normalise to + # the stackmap's existing "??" convention (the DWARF path already does the same). + if _tb_str_ok(path) == 0: path = "??" if d.RowCount >= d.RowCap: ncap: int = d.RowCap * 2 nb: bytes = _tb_grow_rec(mb, d.RowBuf, d.RowCap, TB_ROW_SIZE, ncap) @@ -1381,11 +1427,10 @@ def _tb_emit_row(mb: memhub.MemBuddy*, d: TbDump*, addr: uint64, path: str, line d.RowCap = ncap off: sizet = sizet(d.RowCount) * TB_ROW_SIZE _tb_wr_u64(d.RowBuf, off, addr) - _tb_wr_u64(d.RowBuf, off + TB_ROW_OFF_FILE, uint64(path)) + _tb_wr_ptr(d.RowBuf, off + TB_ROW_OFF_FILE, path) _tb_wr_u32(d.RowBuf, off + TB_ROW_OFF_LINE, uint64(line)) - fv: uint64 = 0 - if fname is not None: fv = uint64(fname) - _tb_wr_u64(d.RowBuf, off + TB_ROW_OFF_FUNC, fv) + if _tb_str_ok(fname) != 0: _tb_wr_ptr(d.RowBuf, off + TB_ROW_OFF_FUNC, fname) + else: _tb_wr_u64(d.RowBuf, off + TB_ROW_OFF_FUNC, 0) d.RowCount = d.RowCount + 1 d.RawRowCount = d.RawRowCount + 1 return 0 @@ -1404,7 +1449,7 @@ def _tb_emit_func(mb: memhub.MemBuddy*, d: TbDump*, low: uint64, high: uint64, n off: sizet = sizet(d.FuncCount) * TB_FUNC_SIZE _tb_wr_u64(d.FuncBuf, off, low) _tb_wr_u64(d.FuncBuf, off + 8, high) - _tb_wr_u64(d.FuncBuf, off + 16, uint64(name)) + _tb_wr_ptr(d.FuncBuf, off + 16, name) d.FuncCount = d.FuncCount + 1 return 0 @@ -1549,10 +1594,10 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*: if in_line != 0: if _tb_startswith(st, "debug_line[") != 0: # new CU: commit pending file, reset both tables - if pkind == 1 and pname is not None and file_count < TB_FILE_CAP: + if pkind == 1 and _tb_str_ok(pname) != 0 and file_count < TB_FILE_CAP: _tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE, uint64(pidx)) _tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE + 4, uint64(pdir)) - _tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, uint64(pname)) + _tb_wr_ptr(files, sizet(file_count) * TB_FILE_SIZE + 8, pname) _tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 24, uint64(0)) file_count += 1 pkind = 0 @@ -1562,10 +1607,10 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*: file_count = 0 continue if _tb_startswith(st, "file_names[") != 0: - if pkind == 1 and pname is not None and file_count < TB_FILE_CAP: + if pkind == 1 and _tb_str_ok(pname) != 0 and file_count < TB_FILE_CAP: _tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE, uint64(pidx)) _tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE + 4, uint64(pdir)) - _tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, uint64(pname)) + _tb_wr_ptr(files, sizet(file_count) * TB_FILE_SIZE + 8, pname) _tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 24, uint64(0)) file_count += 1 pname = None @@ -1574,10 +1619,10 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*: pidx = _tb_bracket_idx(st) continue if _tb_startswith(st, "directory_names[") != 0 or _tb_startswith(st, "include_directories[") != 0: - if pkind == 1 and pname is not None and file_count < TB_FILE_CAP: + if pkind == 1 and _tb_str_ok(pname) != 0 and file_count < TB_FILE_CAP: _tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE, uint64(pidx)) _tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE + 4, uint64(pdir)) - _tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, uint64(pname)) + _tb_wr_ptr(files, sizet(file_count) * TB_FILE_SIZE + 8, pname) _tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 24, uint64(0)) file_count += 1 pname = None @@ -1586,9 +1631,13 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*: val: str = _tb_value_after_sep(_tb_after_bracket(st)) if val is not None and _tb_len_trimmed(val) > 0: if dir_count < TB_DIR_CAP: - _tb_wr_u32(dirs, sizet(dir_count) * TB_DIR_SIZE, uint64(pidx)) - _tb_wr_u64(dirs, sizet(dir_count) * TB_DIR_SIZE + 8, uint64(_tb_unquote(mb, val))) - dir_count += 1 + dname: str = _tb_unquote(mb, val) + if _tb_str_ok(dname) != 0: + _tb_wr_u32(dirs, sizet(dir_count) * TB_DIR_SIZE, uint64(pidx)) + _tb_wr_ptr(dirs, sizet(dir_count) * TB_DIR_SIZE + 8, dname) + dir_count += 1 + else: + VLogger.warning("--traceback: ignoring a DWARF directory entry whose name could not be copied", "TRACEBACK") pkind = 0 else: pkind = 2 continue @@ -1596,9 +1645,9 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*: val2: str = _tb_unquote(mb, _tb_ltrim(st + 5)) if pkind == 1: pname = val2 else: - if dir_count < TB_DIR_CAP and val2 is not None: + if dir_count < TB_DIR_CAP and _tb_str_ok(val2) != 0: _tb_wr_u32(dirs, sizet(dir_count) * TB_DIR_SIZE, uint64(pidx)) - _tb_wr_u64(dirs, sizet(dir_count) * TB_DIR_SIZE + 8, uint64(val2)) + _tb_wr_ptr(dirs, sizet(dir_count) * TB_DIR_SIZE + 8, val2) dir_count += 1 pkind = 0 continue @@ -1608,10 +1657,10 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*: pdir = _tb_parse_dec(_tb_ltrim(st + 10)) continue if _tb_startswith(st, "Address") != 0 and _tb_contains(st, "Column") != 0: - if pkind == 1 and pname is not None and file_count < TB_FILE_CAP: + if pkind == 1 and _tb_str_ok(pname) != 0 and file_count < TB_FILE_CAP: _tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE, uint64(pidx)) _tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE + 4, uint64(pdir)) - _tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, uint64(pname)) + _tb_wr_ptr(files, sizet(file_count) * TB_FILE_SIZE + 8, pname) _tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 24, uint64(0)) file_count += 1 pkind = 0 @@ -1619,10 +1668,10 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*: pdir = 0 continue if _tb_cc(linebuf, 0) == 48 and _tb_cc(linebuf, 1) == 120: - if pkind == 1 and pname is not None and file_count < TB_FILE_CAP: + if pkind == 1 and _tb_str_ok(pname) != 0 and file_count < TB_FILE_CAP: _tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE, uint64(pidx)) _tb_wr_u32(files, sizet(file_count) * TB_FILE_SIZE + 4, uint64(pdir)) - _tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 8, uint64(pname)) + _tb_wr_ptr(files, sizet(file_count) * TB_FILE_SIZE + 8, pname) _tb_wr_u64(files, sizet(file_count) * TB_FILE_SIZE + 24, uint64(0)) file_count += 1 pkind = 0 @@ -1657,7 +1706,7 @@ def _tb_parse_dump(mb: memhub.MemBuddy*, dump: str) -> TbDump*: # ---- DWARF debug_info subprogram parsing ---- if _tb_contains(linebuf, "DW_TAG_") != 0: - if in_prog != 0 and cur_has_low != 0 and cname is not None and string.strlen(cname) > 0: + if in_prog != 0 and cur_has_low != 0 and _tb_str_ok(cname) != 0 and string.strlen(cname) > 0: hi: uint64 = cur_low + 1 if cur_has_high != 0: hi = cur_high @@ -1734,8 +1783,8 @@ class TbCallParse: Grp: bytes # array of TB_GRP_SIZE slots GrpCap: int - def __new__(self) -> t.CPtr: - return t.CPtr(_mbuddy.alloc(TbCallParse.__sizeof__())) + def __new__(self) -> rawptr: + return rawptr(_mbuddy.alloc(TbCallParse.__sizeof__())) def __init__(self): self.Cr = None @@ -1776,8 +1825,8 @@ def _tb_grp_get(grp: bytes, cap: int, caller: str, callee: str, do_insert: int) if uint64(_tb_rd_u32(grp, off + TB_GRP_OFF_USED)) == 0: if do_insert == 0: return -1 _tb_wr_u32(grp, off + TB_GRP_OFF_USED, uint64(1)) - _tb_wr_u64(grp, off + TB_GRP_OFF_CALLER, uint64(caller)) - _tb_wr_u64(grp, off + TB_GRP_OFF_CALLEE, uint64(callee)) + _tb_wr_ptr(grp, off + TB_GRP_OFF_CALLER, caller) + _tb_wr_ptr(grp, off + TB_GRP_OFF_CALLEE, callee) _tb_wr_u32(grp, off + TB_GRP_OFF_HEAD, uint64(TB_IDX_NONE)) _tb_wr_u32(grp, off + TB_GRP_OFF_TAIL, uint64(TB_IDX_NONE)) _tb_wr_u32(grp, off + TB_GRP_OFF_CURSOR, uint64(TB_IDX_NONE)) @@ -1811,9 +1860,9 @@ def _tb_cp_add_cr(mb: memhub.MemBuddy*, cp: TbCallParse*, caller: str, callee: s cp.Cr = nb cp.CrCap = ncap off: sizet = sizet(cp.CrN) * TB_CR_SIZE - _tb_wr_u64(cp.Cr, off + TB_CR_OFF_CALLER, uint64(caller)) - _tb_wr_u64(cp.Cr, off + TB_CR_OFF_CALLEE, uint64(callee)) - _tb_wr_u64(cp.Cr, off + TB_CR_OFF_FILE, uint64(file)) + _tb_wr_ptr(cp.Cr, off + TB_CR_OFF_CALLER, caller) + _tb_wr_ptr(cp.Cr, off + TB_CR_OFF_CALLEE, callee) + _tb_wr_ptr(cp.Cr, off + TB_CR_OFF_FILE, file) _tb_wr_u32(cp.Cr, off + TB_CR_OFF_LINE, uint64(line)) _tb_wr_u32(cp.Cr, off + TB_CR_OFF_NEXT, uint64(TB_IDX_NONE)) cp.CrN = cp.CrN + 1 @@ -1830,8 +1879,8 @@ def _tb_cp_add_fr(mb: memhub.MemBuddy*, cp: TbCallParse*, sym: str, file: str, d cp.Fr = nb cp.FrCap = ncap off: sizet = sizet(cp.FrN) * TB_FR_SIZE - _tb_wr_u64(cp.Fr, off + TB_FR_OFF_SYM, uint64(sym)) - _tb_wr_u64(cp.Fr, off + TB_FR_OFF_FILE, uint64(file)) + _tb_wr_ptr(cp.Fr, off + TB_FR_OFF_SYM, sym) + _tb_wr_ptr(cp.Fr, off + TB_FR_OFF_FILE, file) _tb_wr_u32(cp.Fr, off + TB_FR_OFF_DEFLINE, uint64(defline)) cp.FrN = cp.FrN + 1 return 0 @@ -1853,6 +1902,10 @@ def _tb_read_whole(mb: memhub.MemBuddy*, path: str) -> str: got: LONG = f.read_all(buf, sizet(sz) + 2) f.close() if got < 0: return None + # NUL-terminate at the actually read length. The pool buffer is NOT zero-filled (MemBuddy's + # diagnostic fill is 0xCD), so without this the caller's strlen() walks into uninitialised + # bytes and can run past the end of the arena. + buf[got] = 0 return buf @@ -1873,7 +1926,7 @@ def _tb_parse_f_line(mb: memhub.MemBuddy*, s: str, a: sizet, b: sizet, cp: TbCal defline: int = int(_tb_parse_dec(s + p)) p = f3 + 1 file: str = _tb_dup_span(mb, s + p, b - p) - if sym is None or file is None: return 0 + if _tb_str_ok(sym) == 0 or _tb_str_ok(file) == 0: return 0 return _tb_cp_add_fr(mb, cp, sym, file, defline) @@ -1899,7 +1952,7 @@ def _tb_parse_c_line(mb: memhub.MemBuddy*, s: str, a: sizet, b: sizet, cp: TbCal line: int = int(_tb_parse_dec(s + p)) p = e4 + 1 file: str = _tb_dup_span(mb, s + p, b - p) - if caller is None or callee is None or file is None: return 0 + if _tb_str_ok(caller) == 0 or _tb_str_ok(callee) == 0 or _tb_str_ok(file) == 0: return 0 return _tb_cp_add_cr(mb, cp, caller, callee, file, line) @@ -1967,7 +2020,7 @@ def _tb_build_groups(mb: memhub.MemBuddy*, cp: TbCallParse*) -> int: def _tb_emit_call_row(mb: memhub.MemBuddy*, d: TbDump*, cp: TbCallParse*, img_lo: uint64, caller: str, callee: str, ret_va: uint64) -> int: """Emit a row for a return address from the next unconsumed C record of (caller, callee).""" - if caller is None or callee is None or cp.Grp is None or ret_va < img_lo: return 0 + if _tb_str_ok(caller) == 0 or _tb_str_ok(callee) == 0 or cp.Grp is None or ret_va < img_lo: return 0 slot: int = _tb_grp_get(cp.Grp, cp.GrpCap, caller, callee, 0) if slot < 0: return 0 goff: sizet = sizet(slot) * TB_GRP_SIZE @@ -1984,11 +2037,11 @@ def _tb_emit_call_row(mb: memhub.MemBuddy*, d: TbDump*, cp: TbCallParse*, img_lo def _tb_emit_entry_row(mb: memhub.MemBuddy*, d: TbDump*, cp: TbCallParse*, img_lo: uint64, addr: uint64, sym: str) -> int: """Emit a fallback function-entry row for an objdump label sym (file/line from the F record).""" - if sym is None or cp.Fr is None or cp.FrN <= 0 or addr < img_lo: return 0 + if _tb_str_ok(sym) == 0 or cp.Fr is None or cp.FrN <= 0 or addr < img_lo: return 0 for i in range(int(cp.FrN)): off: sizet = sizet(i) * TB_FR_SIZE s: str = rawptr(_tb_rd_u64(cp.Fr, off + TB_FR_OFF_SYM)) - if s is not None and string.strcmp(s, sym) == 0: + if _tb_str_ok(s) != 0 and string.strcmp(s, sym) == 0: file: str = rawptr(_tb_rd_u64(cp.Fr, off + TB_FR_OFF_FILE)) dl: int = int(_tb_rd_u32(cp.Fr, off + TB_FR_OFF_DEFLINE)) return _tb_emit_row(mb, d, addr, file, dl, sym) @@ -2066,7 +2119,7 @@ def _tb_scan_objdump(mb: memhub.MemBuddy*, dump: str, img_lo: uint64, d: TbDump* j: sizet = lb while j < le and _tb_cc(dump, j) != 62: j += 1 cur_func = _tb_dup_span(mb, dump + lb, j - lb) - if cur_func is not None: _tb_emit_entry_row(mb, d, cp, img_lo, laddr, cur_func) + if _tb_str_ok(cur_func) != 0: _tb_emit_entry_row(mb, d, cp, img_lo, laddr, cur_func) continue # ---- instruction line `ADDR: bytes mnemonic operands` ---- k: sizet = ls @@ -2275,7 +2328,14 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int: pool_need: sizet = 1 i = 0 while i < uniq: - pth: str = rawptr(_tb_rd_u64(d.RowBuf, sizet(i) * TB_ROW_SIZE + TB_ROW_OFF_FILE)) + fptr: uint64 = _tb_rd_u64(d.RowBuf, sizet(i) * TB_ROW_SIZE + TB_ROW_OFF_FILE) + # fail-fast: Windows x64 user addresses stay below 0x7FFF_FFFF_FFFF; anything else is a + # wild pointer (0, -1 or an uninitialised slot). Report the record instead of letting + # strlen walk off into unmapped memory (ASan access-violation at 0xffffffffffffffff). + if fptr < 65536 or fptr > 0x7FFFFFFFFFFF: + VLogger.error(f"--traceback: internal error: line record {i} carries an invalid file-path pointer ({fptr})", "TRACEBACK") + return 1 + pth: str = rawptr(fptr) pool_need += string.strlen(pth) + 1 i += 1 # our rows carry the function name directly (string pool); DWARF rows take it from the subprogram table. @@ -2283,13 +2343,21 @@ def WriteStackMap(mb: memhub.MemBuddy*, exe_path: str) -> int: while i < uniq: fp: uint64 = _tb_rd_u64(d.RowBuf, sizet(i) * TB_ROW_SIZE + TB_ROW_OFF_FUNC) if fp != 0: + if fp > 0x7FFFFFFFFFFF: + VLogger.error(f"--traceback: internal error: line record {i} carries an invalid function-name pointer ({fp})", "TRACEBACK") + return 1 fns: str = rawptr(fp) - if fns is not None: pool_need += string.strlen(fns) + 1 + pool_need += string.strlen(fns) + 1 i += 1 i = 0 while i < fkept: - nm0: str = rawptr(_tb_rd_u64(d.FuncBuf, sizet(i) * TB_FUNC_SIZE + 16)) - if nm0 is not None: pool_need += string.strlen(nm0) + 1 + nmf: uint64 = _tb_rd_u64(d.FuncBuf, sizet(i) * TB_FUNC_SIZE + 16) + if nmf != 0: + if nmf > 0x7FFFFFFFFFFF: + VLogger.error(f"--traceback: internal error: subprogram record {i} carries an invalid name pointer ({nmf})", "TRACEBACK") + return 1 + nm0: str = rawptr(nmf) + pool_need += string.strlen(nm0) + 1 i += 1 p: TbPool* = TbPool() if p is None: diff --git a/App/lib/Phase/Phase1/Phase1Main.vp b/App/lib/Phase/Phase1/Phase1Main.vp index 828968f..c431327 100644 --- a/App/lib/Phase/Phase1/Phase1Main.vp +++ b/App/lib/Phase/Phase1/Phase1Main.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import string import stdlib @@ -368,10 +367,10 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg class_names_buf: bytes = mb.alloc(sizet(Phase1.MAX_CLASSES) * Phase1.CLASS_NAME_LEN) parent_names_buf: bytes = mb.alloc(sizet(Phase1.MAX_CLASSES) * Phase1.CLASS_NAME_LEN) def_sha1s_buf: bytes = mb.alloc(Phase1.MAX_CLASSES * Phase1.SHA1_LEN) - topo_order: t.CPtr = mb.alloc(4 * Phase1.MAX_FILE_DEPS) - topo_count_box: t.CPtr = mb.alloc(4) - generic_file_indices: t.CPtr = mb.alloc(4 * Phase1.MAX_FILE_DEPS) - generic_file_count_box: t.CPtr = mb.alloc(4) + topo_order: rawptr = mb.alloc(4 * Phase1.MAX_FILE_DEPS) + topo_count_box: rawptr = mb.alloc(4) + generic_file_indices: rawptr = mb.alloc(4 * Phase1.MAX_FILE_DEPS) + generic_file_count_box: rawptr = mb.alloc(4) if generic_file_indices is not None: string.memset(generic_file_indices, 0, 4 * Phase1.MAX_FILE_DEPS) if generic_file_count_box is not None: string.memset(generic_file_count_box, 0, 4) topo_count: int = 0 @@ -427,7 +426,7 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str, log: VLogg file_idx: int = int(i) if topo_count > 0: od_addr: uint64 = uint64(topo_order) + i * 4 - od_ptr: int* = (int*)(t.CPtr(od_addr)) + od_ptr: int* = int*(od_addr) if od_ptr is not None: file_idx = od_ptr[0] entry_addr_r: uint64 = uint64(result.Entries) + file_idx * entry_size diff --git a/App/lib/Phase/Phase1/Phase1Scan.vp b/App/lib/Phase/Phase1/Phase1Scan.vp index 3c4985a..0cf3573 100644 --- a/App/lib/Phase/Phase1/Phase1Scan.vp +++ b/App/lib/Phase/Phase1/Phase1Scan.vp @@ -1,31 +1,14 @@ -import t, c from stdint import * import string import stdlib import memhub -import viperlib -import sys import win32.fileio as fileio -import win32.win32file -import win32.win32base import ast -import mlirlite 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 import lib.core.Gen.GenApi as GenApi @@ -40,7 +23,7 @@ import lib.core.Gen.GenApi as GenApi # _ScanClassInheritance - pre-scan includes files, parse ASTs and collect ClassDef # names/parent names into flat byte arrays; returns the class count (-1 on failure). -def _ScanClassInheritance(mb: memhub.MemBuddy*, result: 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, generic_file_indices: t.CPtr, generic_file_count_box: t.CPtr) -> int: +def _ScanClassInheritance(mb: memhub.MemBuddy*, result: 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, generic_file_indices: rawptr, generic_file_count_box: rawptr) -> int: """Pre-scan includes files and collect class inheritance info.""" if result is None: return -1 # The three flat buffers are mb.alloc'ed by the caller; a NULL buffer would make @@ -322,7 +305,7 @@ def _AnnIsContainer(ann: ast.AST*) -> int: return 0 -def _ScanTreeForContainers(node: ast.AST*, need_list_box: t.CPtr, need_dict_box: t.CPtr, depth: int = 0): +def _ScanTreeForContainers(node: ast.AST*, need_list_box: rawptr, need_dict_box: rawptr, depth: int = 0): """Recursively scan the AST for list/dict container usage.""" # Recursion depth guard: a self-referential AST cycle would recurse until the # stack is exhausted; fail-fast abort. diff --git a/App/lib/Phase/Phase1/Phase1Topo.vp b/App/lib/Phase/Phase1/Phase1Topo.vp index 0ae6962..6223329 100644 --- a/App/lib/Phase/Phase1/Phase1Topo.vp +++ b/App/lib/Phase/Phase1/Phase1Topo.vp @@ -1,30 +1,14 @@ -import t, c from stdint import * import string import stdlib import memhub -import viperlib -import win32.fileio as fileio -import win32.win32file -import win32.win32base -import ast -import mlirlite -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 - topologically sort source files by class inheritance and import dependencies. @@ -32,7 +16,7 @@ import lib.Phase.Phase1 as Phase1 # _TopoSortFiles - topologically sort files by class inheritance (Kahn). # Builds a "file SHA1 -> dependency SHA1 set" map, computes in-degrees (parent-file first), then outputs the order; returns 0 or -1. -def _TopoSortFiles(mb: memhub.MemBuddy*, result: 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: +def _TopoSortFiles(mb: memhub.MemBuddy*, result: 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: rawptr, out_count: rawptr, temp_dir: str, td_len_ts: sizet) -> int: """Topologically sort files by class inheritance and import dependencies.""" if result is None or out_order is None or out_count is None: return -1 @@ -44,9 +28,9 @@ def _TopoSortFiles(mb: memhub.MemBuddy*, result: IncludesScanner.ScanResult*, re # 取消整数提升后,模块属性 CDefine(Phase1.MAX_*) 按最小位宽物化为 i16/i8;三段乘积 256*16*17=69632 会在 i16 回绕, # 首乘数显式 sizet() 加宽到 64 位。上一行 256*17=4352 未超 i16,故无需改。 file_deps_buf: bytes = mb.alloc(sizet(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) + file_dep_counts: rawptr = mb.alloc(Phase1.MAX_FILE_DEPS * 4) + file_indegrees: rawptr = mb.alloc(Phase1.MAX_FILE_DEPS * 4) + file_processed: rawptr = 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) diff --git a/App/lib/Phase/Phase1/__init__.vp b/App/lib/Phase/Phase1/__init__.vp index be77413..2756109 100644 --- a/App/lib/Phase/Phase1/__init__.vp +++ b/App/lib/Phase/Phase1/__init__.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import memhub diff --git a/App/lib/Phase/Phase2/__init__.vp b/App/lib/Phase/Phase2/__init__.vp index a9054d6..79ea7ca 100644 --- a/App/lib/Phase/Phase2/__init__.vp +++ b/App/lib/Phase/Phase2/__init__.vp @@ -1,5 +1,4 @@ import lib.core.Gen.GenApi as GenApi -import t, c from stdint import * import stdio import string @@ -38,8 +37,7 @@ define SRC_BUF_SIZE = 1048576 # Max source files (recursive scanning grows the count; too small truncates the list -> undefined symbol) define MAX_SRC_FILES = 128 -@t.NoVTable -class SrcFileEntry: +novirtual class SrcFileEntry: """Source file entry""" Path: str # full path Sha1: str # first 16 chars of SHA1 diff --git a/App/lib/Projectrans/Config.vp b/App/lib/Projectrans/Config.vp index c8b3062..60dd966 100644 --- a/App/lib/Projectrans/Config.vp +++ b/App/lib/Projectrans/Config.vp @@ -1,8 +1,6 @@ -import t, c from stdint import * import memhub import string -import stdio import stdlib import viperlib import lib.core.VLogger as VLogger @@ -112,6 +110,17 @@ def Load_project_config(path: str) -> int: # Read linker.flags array, join into a space-separated string ld_flags_val: JsonValue* = linker["flags"] LinkerFlags = _join_flags_array(ld_flags_val) + # mingw-w64:同时链接 -lmsvcrt 与 -lucrt 时,GNU ld 会从两个 import 库各拉出一个都定义 + # __imp_ 的成员(现场:__imp_ldexp 同时出现在 libmsvcrt 与 + # libapi-ms-win-crt-math),直接报 "multiple definition"。lld 按需解析 import 库不会冲突, + # 仓库默认链接命令也一直是 lld;项目配置漏写 -fuse-ld 时在这里补齐,避免逐个测试改配置。 + if LinkerCmd is not None and LinkerFlags is not None and string.strstr(LinkerCmd, "clang") is not None: + if string.strstr(LinkerFlags, "-fuse-ld") is None and string.strstr(LinkerFlags, "-lucrt") is not None: + lf_cap: sizet = string.strlen(LinkerFlags) + 32 + lf_new: str = _mbuddy.alloc(lf_cap) + if lf_new is not None: + viperlib.snprintf(lf_new, lf_cap, "-fuse-ld=lld %s", LinkerFlags) + LinkerFlags = lf_new # Read linker.static_libs array: explicit static libs (.a/.obj); joined raw here, # then resolved to abs paths against project_dir in resolve_paths. sl_val: JsonValue* = linker["static_libs"] diff --git a/App/lib/Projectrans/Utils.vp b/App/lib/Projectrans/Utils.vp index 1219f84..0f9c316 100644 --- a/App/lib/Projectrans/Utils.vp +++ b/App/lib/Projectrans/Utils.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import memhub import string diff --git a/App/lib/Projectrans/__init__.vp b/App/lib/Projectrans/__init__.vp index 50b4cf9..7adfb80 100644 --- a/App/lib/Projectrans/__init__.vp +++ b/App/lib/Projectrans/__init__.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * from .Config import Load_project_config, resolve_paths diff --git a/App/lib/Stub/StubGen/Converter.vp b/App/lib/Stub/StubGen/Converter.vp index c3d823f..41992ad 100644 --- a/App/lib/Stub/StubGen/Converter.vp +++ b/App/lib/Stub/StubGen/Converter.vp @@ -1,6 +1,5 @@ import lib.core.Gen.GenApi as GenApi import lib.core.VLogger as VLogger -import t, c from stdint import * import ast import string diff --git a/App/lib/Stub/StubGen/VpiReader.vp b/App/lib/Stub/StubGen/VpiReader.vp index 7f7e059..c071330 100644 --- a/App/lib/Stub/StubGen/VpiReader.vp +++ b/App/lib/Stub/StubGen/VpiReader.vp @@ -1,7 +1,6 @@ import lib.core.Gen.GenApi as GenApi import lib.core.Gen.GenTypes as GenTypes import lib.core.CompilerFactory as CompilerFactory -import t, c from stdint import * import ast import string diff --git a/App/lib/Stub/StubMerger/StubMergerBuild.vp b/App/lib/Stub/StubMerger/StubMergerBuild.vp index 151eca5..8ef997d 100644 --- a/App/lib/Stub/StubMerger/StubMergerBuild.vp +++ b/App/lib/Stub/StubMerger/StubMergerBuild.vp @@ -1,5 +1,4 @@ import lib.core.Gen.GenApi as GenApi -import t, c from stdint import * import memhub import string @@ -197,9 +196,9 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, # 2b. --traceback: force the traceback runtime module into the reachable set (TPC: used_includes.add('traceback')). # Its Install() symbol and the @llvm.global_ctors ctor come only from compiling this module, so a missing file is fail-fast. if BuildPipeline._traceback_mode != 0: - tb_abs: t.CPtr = stdlib.malloc(8) - tb_rel: t.CPtr = stdlib.malloc(8) - tb_inc: t.CPtr = stdlib.malloc(8) + tb_abs: rawptr = stdlib.malloc(8) + tb_rel: rawptr = stdlib.malloc(8) + tb_inc: rawptr = stdlib.malloc(8) tb_found: int = -1 if tb_abs is not None and tb_rel is not None and tb_inc is not None: tb_abs_slot: sizet* = (sizet*)(tb_abs) @@ -230,7 +229,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, processed[0] = '\0' proc_len: sizet = 0 reachable_count: int = 0 - wl_pos: t.CPtr = stdlib.malloc(8) + wl_pos: rawptr = stdlib.malloc(8) if wl_pos is None: stdlib.free(worklist) stdlib.free(processed) @@ -289,9 +288,9 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, continue # includes: resolve on demand via the filesystem (unreferenced includes are never touched) - out_abs: t.CPtr = stdlib.malloc(8) - out_rel: t.CPtr = stdlib.malloc(8) - out_inc: t.CPtr = stdlib.malloc(8) + out_abs: rawptr = stdlib.malloc(8) + out_rel: rawptr = stdlib.malloc(8) + out_inc: rawptr = stdlib.malloc(8) if out_abs is None or out_rel is None or out_inc is None: if out_abs is not None: stdlib.free(out_abs) if out_rel is not None: stdlib.free(out_rel) @@ -299,10 +298,10 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str, temp_dir: str, stdlib.free(mod_buf) continue # Defensive init of the output slots (the success path always writes all). The slot union must use (sizet*): - # t.CPtr* collapses to t.CPtr and [0] becomes a 1-byte access, truncating the pointer (0x2e crash root cause). - abs_slot: sizet* = (sizet*)(out_abs) - rel_slot: sizet* = (sizet*)(out_rel) - inc_slot: sizet* = (sizet*)(out_inc) + # rawptr* collapses to rawptr and [0] becomes a 1-byte access, truncating the pointer (0x2e crash root cause). + abs_slot: sizet* = sizet*(out_abs) + rel_slot: sizet* = sizet*(out_rel) + inc_slot: sizet* = sizet*(out_inc) abs_slot[0] = 0 rel_slot[0] = 0 inc_slot[0] = 0 diff --git a/App/lib/Stub/StubMerger/StubMergerCollect.vp b/App/lib/Stub/StubMerger/StubMergerCollect.vp index 5066266..9239d72 100644 --- a/App/lib/Stub/StubMerger/StubMergerCollect.vp +++ b/App/lib/Stub/StubMerger/StubMergerCollect.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import memhub import string diff --git a/App/lib/Stub/StubMerger/StubMergerIR.vp b/App/lib/Stub/StubMerger/StubMergerIR.vp index a558e7c..03e68bc 100644 --- a/App/lib/Stub/StubMerger/StubMergerIR.vp +++ b/App/lib/Stub/StubMerger/StubMergerIR.vp @@ -1,5 +1,4 @@ import lib.core.Gen.GenApi as GenApi -import t, c from stdint import * import memhub import string diff --git a/App/lib/Stub/StubMerger/StubMergerStore.vp b/App/lib/Stub/StubMerger/StubMergerStore.vp index a3e837c..ccbb94f 100644 --- a/App/lib/Stub/StubMerger/StubMergerStore.vp +++ b/App/lib/Stub/StubMerger/StubMergerStore.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import memhub import string diff --git a/App/lib/Stub/StubMerger/StubMergerTopo.vp b/App/lib/Stub/StubMerger/StubMergerTopo.vp index 35e8120..0eccb1c 100644 --- a/App/lib/Stub/StubMerger/StubMergerTopo.vp +++ b/App/lib/Stub/StubMerger/StubMergerTopo.vp @@ -1,29 +1,11 @@ -import t, c from stdint import * -import memhub import string import stdlib -import mlirlite -import win32.win32file as win32file -import win32.win32base as win32base -import win32.fileio as fileio -import viperlib -import sys -import ast -import lib.core.VLogger as VLogger -import lib.core.IncludesScanner as IncludesScanner -import lib.core.Gen.Translator 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 - reverse-topological sort of reachable includes (dependencies first). # Functions live in this module; cross-module globals are accessed via StubMerger._xxx. @@ -33,9 +15,9 @@ import lib.Stub.StubMerger as StubMerger def BuildTopoSortedIndices(store_count: int, store_sha1_arr: bytes, store_mod_arr: bytes, reachable_set: bytes, reachable_count: int, sorted_idx: sizet*) -> int: """Reverse-topologically sort reachable includes (dependencies first); store indices go to 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: sizet* = (sizet*)(stdlib.malloc(8 * (store_count + 1))) - queue: sizet* = (sizet*)(stdlib.malloc(8 * (store_count + 1))) - rel_idx: sizet* = (sizet*)(stdlib.malloc(8 * (store_count + 1))) + indegree: sizet* = sizet*(stdlib.malloc(8 * (store_count + 1))) + queue: sizet* = sizet*(stdlib.malloc(8 * (store_count + 1))) + rel_idx: sizet* = sizet*(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) diff --git a/App/lib/Stub/StubMerger/__init__.vp b/App/lib/Stub/StubMerger/__init__.vp index 8c4e753..685bdb9 100644 --- a/App/lib/Stub/StubMerger/__init__.vp +++ b/App/lib/Stub/StubMerger/__init__.vp @@ -1,22 +1,5 @@ -import t, c from stdint import * import memhub -import string -import stdlib -import mlirlite -import win32.win32file as win32file -import win32.win32base as win32base -import win32.fileio as fileio -import viperlib -import sys -import ast -import lib.core.VLogger as VLogger -import lib.core.IncludesScanner as IncludesScanner -import lib.core.Gen.Translator 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 # StubMerger - merges dependency stub declarations into the main IR (Phase2 core): diff --git a/App/lib/core/CompilerFactory.vp b/App/lib/core/CompilerFactory.vp index 497e69d..48007a1 100644 --- a/App/lib/core/CompilerFactory.vp +++ b/App/lib/core/CompilerFactory.vp @@ -1,4 +1,3 @@ -import t, c import memhub diff --git a/App/lib/core/Diag.vp b/App/lib/core/Diag.vp index 0b9abeb..da91469 100644 --- a/App/lib/core/Diag.vp +++ b/App/lib/core/Diag.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import string import stdio @@ -38,7 +37,7 @@ define DIAG_MAX_FRAMES = 32 # 调用链上限(与 TypeGenMixin.TRACE_MAX 对 # (import 触发依赖加载 / 泛型特化 / 函数体翻译)时的触发点, # 用于"从错误发生点向外展示触发过程"。 # 所有字符串都用 stdlib 深拷贝:编译期池会回绕,不能借用池内指针。 -class DiagEntry: +struct DiagEntry: # 字段名不要与"本模块 import 的类名"重名:TPC 的类型/符号表按**非限定名**索引 # (Gen.structs / SymbolTable / _mangle_func_name),曾把本字段的 `File` 与 # `win32.fileio.File` 撞在一起,导致同模块 `fileio.File(...)` 的构造调用把 diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index 33f0b9a..e8ad06a 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import ast import mlirlite @@ -922,7 +921,7 @@ novirtual class AssignGenMixin: return 0 def _annotation_has_cptr_marker(self, annot: ast.AST*) -> int: - """Return 1 if the annotation union carries a CPtr marker (the star form ` | t.CPtr`).""" + """Return 1 if the annotation union carries a CPtr marker (the star form ` | rawptr`).""" if annot is None: return 0 k: int = annot.kind() if k == ast.ASTKind.Attribute: @@ -2796,6 +2795,10 @@ novirtual class AssignGenMixin: lv_target_ty: mlirlite.LLVMType* = None if alloca.Ty is not None: lv_target_ty = alloca.Ty.Pointee rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aa.value, None, 0, trans, lv_target_ty, "local variable annotation") + if rhs_val is None: + # fail-fast: 右值翻译失败时绝不能静默跳过整条声明(此前直接落到 `if rhs_val is + # not None` 之外,变量永远保持未初始化,运行期读到栈垃圾后断言崩溃)。 + self.Gen.TypeGenErr.fatal_error(aa, f"the right-hand side of the declaration of '{nm.id}' could not be translated (type inference failed; see the preceding diagnostic)", "TypeError") if rhs_val is not None: # Fix degraded annotation: rebuild the alloca with the precise RHS struct type precise_rhs_ty: mlirlite.LLVMType* = None @@ -3239,10 +3242,16 @@ novirtual class AssignGenMixin: if sub_alloca is not None and sub_alloca.Ty is not None and sub_alloca.Ty.Pointee != 0 and self.Gen.ExprGenBase.is_ptr_type(sub_alloca.Ty) != 0: sub_pointee: mlirlite.LLVMType* = sub_alloca.Ty.Pointee cls_nm_set: str = self.Gen.StructGen.get_class_name_by_type(pool, sub_pointee) - obj_val_set: mlirlite.Value* = mlirlite.build_load(builder, sub_pointee, sub_alloca) - # Pointer variable (X*): sub_pointee is Ptr(Struct); load it to inspect the inner struct - if cls_nm_set is None and obj_val_set is not None and self.Gen.ExprGenBase.is_ptr_type(sub_pointee) != 0 and sub_pointee.Pointee != 0: - cls_nm_set = self.Gen.StructGen.get_class_name_by_type(pool, sub_pointee.Pointee) + obj_val_set: mlirlite.Value* = None + # 值类型对象槽(`d: dict = dict(bd)`):槽地址就是 self 指针。 + # 此前无条件 load,值类型会传出整个 struct 值当 self(非法), + # 指针类型才需要先 load 出对象指针。 + if cls_nm_set is not None: obj_val_set = sub_alloca + else: + obj_val_set = mlirlite.build_load(builder, sub_pointee, sub_alloca) + # Pointer variable (X*): sub_pointee is Ptr(Struct); load it to inspect the inner struct + if obj_val_set is not None and self.Gen.ExprGenBase.is_ptr_type(sub_pointee) != 0 and sub_pointee.Pointee != 0: + cls_nm_set = self.Gen.StructGen.get_class_name_by_type(pool, sub_pointee.Pointee) if cls_nm_set is not None and obj_val_set is not None: key_val_set: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, sub_asgn.slice, None, 0, trans) if key_val_set is not None: diff --git a/App/lib/core/Gen/AsyncGenMixin.vp b/App/lib/core/Gen/AsyncGenMixin.vp index 74ba61d..7340d41 100644 --- a/App/lib/core/Gen/AsyncGenMixin.vp +++ b/App/lib/core/Gen/AsyncGenMixin.vp @@ -1,5 +1,4 @@ import lib.core.Gen.GenTypes as GenTypes -import t, c from stdint import * import ast import mlirlite diff --git a/App/lib/core/Gen/BaseGenMixin.vp b/App/lib/core/Gen/BaseGenMixin.vp index ce43529..2da6ed8 100644 --- a/App/lib/core/Gen/BaseGenMixin.vp +++ b/App/lib/core/Gen/BaseGenMixin.vp @@ -1,6 +1,5 @@ import lib.core.Gen.GenTypes as GenTypes import lib.core.Gen.Generator as Generator -import t, c from stdint import * import memhub import mlirlite diff --git a/App/lib/core/Gen/Call/CallGenBase.vp b/App/lib/core/Gen/Call/CallGenBase.vp index 05bbbb4..1b3cc89 100644 --- a/App/lib/core/Gen/Call/CallGenBase.vp +++ b/App/lib/core/Gen/Call/CallGenBase.vp @@ -2,7 +2,6 @@ import lib.core.Gen.GenTypes as GenTypes import lib.core.Gen.Generator as Generator import lib.core.Gen.GenApi as GenApi import lib.core.Gen.Translator as HT -import t, c from stdint import * import ast import mlirlite @@ -130,9 +129,9 @@ novirtual class CallGenBase: def _auto_addr_mode(self, name: str, idx: int) -> int: """Return the value-reference mode for parameter idx of a callee symbol name (0 if none/unknown).""" if self.AutoAddrModes is None or name is None or idx < 0: return 0 - v: t.CPtr = self.AutoAddrModes.__getitem__(name) + v: rawptr = self.AutoAddrModes.__getitem__(name) if v is None: return 0 - modes: str = t.CPtr(v) + modes: str = rawptr(v) i: int = 0 while i < idx and modes[i] != char(0): i += 1 if i != idx: return 0 @@ -1298,7 +1297,7 @@ novirtual class CallGenBase: if use_bare != 0: viperlib.snprintf(key_buf, key_len, "%s.%s", class_sha1, method_name) else: viperlib.snprintf(key_buf, key_len, "%s.%s.%s", class_sha1, class_name, method_name) - v: t.CPtr = ht.__getitem__(key_buf) + v: rawptr = ht.__getitem__(key_buf) stdlib.free(key_buf) if v is None: return None return rawptr(v) diff --git a/App/lib/core/Gen/Call/CallGenCBuiltin.vp b/App/lib/core/Gen/Call/CallGenCBuiltin.vp index ecd3623..56fc13a 100644 --- a/App/lib/core/Gen/Call/CallGenCBuiltin.vp +++ b/App/lib/core/Gen/Call/CallGenCBuiltin.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import ast import mlirlite @@ -786,8 +785,8 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase): string.memset(operands, 0, operand_size * ASM_MAX_OPERANDS) # Clobber name array: 8 bytes/slot, capacity ASM_MAX_CLOBBERS, decoupled from - # the operand limit; a single-level t.CPtr buffer with slots cast to str*. - clobbers: t.CPtr = pool.alloc(8 * ASM_MAX_CLOBBERS) + # the operand limit; a single-level rawptr buffer with slots cast to str*. + clobbers: rawptr = pool.alloc(8 * ASM_MAX_CLOBBERS) if clobbers is None: return None string.memset(clobbers, 0, 8 * ASM_MAX_CLOBBERS) diff --git a/App/lib/core/Gen/Call/CallGenCall.vp b/App/lib/core/Gen/Call/CallGenCall.vp index 7923625..ed1f3a8 100644 --- a/App/lib/core/Gen/Call/CallGenCall.vp +++ b/App/lib/core/Gen/Call/CallGenCall.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import ast import mlirlite @@ -165,18 +164,18 @@ novirtual class CallGenCall(CallGenBase.CallGenBase): # 跨模块:本文件指令表为空,改查对方模块 .vpi 的 esce=/escn= f_ci = self.Gen.CallGenBase.lookup_escape_dir_via_vpi(sha_ci, class_name, method_name, 0) n_ci = self.Gen.CallGenBase.lookup_escape_dir_via_vpi(sha_ci, class_name, method_name, 1) - if f_ci != 0 or n_ci != 0: esc_mask_ci = (esc_mask_ci | f_ci) & (~n_ci) - # 同命裁剪(构造器路径):被构造对象的生命期由**调用方**(CallGenCtor)算出并经 - # recv_life 传入 —— 这里只有 self_ptr(LLVM 值),拿不到 AST/生命期。 - # recv_life == -1 = 未知 → **不做裁剪**(与接这条之前的行为完全一致)。 - # 对象在本帧(裸 `T()` / `new stack` / `slife`)时,其余实参也都在本帧即可清位。 - if recv_life >= 0 and esc_mask_ci != 0: - if recv_life == GenTypes.LIFE_FRAME or recv_life == GenTypes.LIFE_VALUE: - hard_ci: int = GenApi.get_param_escapes_hard_method(pool, class_name, method_name) - fld_ci: int = esc_mask_ci & (~hard_ci) - if fld_ci != 0: - can_ci2: sizet = len(arg_nodes) - cl_ci: int = self.Gen.CallGen._FrameArgsEscapeClearsMethod(trans, None, arg_nodes, can_ci2, fld_ci) + if f_ci != 0 or n_ci != 0: esc_mask_ci = (esc_mask_ci | f_ci) & (~n_ci) + # 同命裁剪(构造器路径):被构造对象的生命期由**调用方**(CallGenCtor)算出并经 + # recv_life 传入 —— 这里只有 self_ptr(LLVM 值),拿不到 AST/生命期。 + # recv_life == -1 = 未知 → **不做裁剪**(与接这条之前的行为完全一致)。 + # 对象在本帧(裸 `T()` / `new stack` / `slife`)时,其余实参也都在本帧即可清位。 + if recv_life >= 0 and esc_mask_ci != 0: + if recv_life == GenTypes.LIFE_FRAME or recv_life == GenTypes.LIFE_VALUE: + hard_ci: int = GenApi.get_param_escapes_hard_method(pool, class_name, method_name) + fld_ci: int = esc_mask_ci & (~hard_ci) + if fld_ci != 0: + can_ci2: sizet = len(arg_nodes) + cl_ci: int = self.Gen.CallGen._FrameArgsEscapeClearsMethod(trans, None, arg_nodes, can_ci2, fld_ci) if cl_ci != 0: esc_mask_ci = esc_mask_ci & (~cl_ci) if esc_mask_ci != 0: dummy_ptr_ci: mlirlite.LLVMType* = mlirlite.Ptr(pool, mlirlite.Int8(pool)) @@ -343,7 +342,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase): while tail is not None and mlirlite.value_get_next(tail) is not None: tail = mlirlite.value_get_next(tail) # Default-argument filling: if the call site supplies fewer args than the # definition, fill the missing ones (defined default, else zero). - mdf_defaults: t.CPtr = None + mdf_defaults: rawptr = None mdf_default_count: int = 0 mdf_param_count: int = 0 if trans is not None and trans._funcs is not None: @@ -555,17 +554,17 @@ novirtual class CallGenCall(CallGenBase.CallGenBase): if uint64(self_ptr.Ty) != uint64(cmop_i8_ptr_ty): cmop_bar_ptr = mlirlite.build_bitcast(builder, self_ptr, cmop_i8_ptr_ty) if cmop_bar_ptr is not None: mlirlite.build_load(builder, cmop_i8_ty, cmop_bar_ptr, 1) return call_res_cmop - def _MarkWillFreeArgName(self, trans: HT.Translator*, arg_node: ast.AST*) -> int: - """P2 willFree:把实参变量槽标为"已失效";只处理简单变量名(1=标记过 / 0=未处理)。 - - 与模块级调用同一口径(VarEntry.Freed):该槽其后被读 / 取地址 / 再传时,由 - ExprGenName.translate_name_value 或 ExprGenOps 的 AddrOf 分支报 LifetimeError。""" - if trans is None or arg_node is None: return 0 - if arg_node.kind() != ast.ASTKind.Name: return 0 - nm: ast.Name* = ast.Name*(arg_node) - if nm.id is None: return 0 - return self.Gen.VarGen._FreedMark(self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)) - + def _MarkWillFreeArgName(self, trans: HT.Translator*, arg_node: ast.AST*) -> int: + """P2 willFree:把实参变量槽标为"已失效";只处理简单变量名(1=标记过 / 0=未处理)。 + + 与模块级调用同一口径(VarEntry.Freed):该槽其后被读 / 取地址 / 再传时,由 + ExprGenName.translate_name_value 或 ExprGenOps 的 AddrOf 分支报 LifetimeError。""" + if trans is None or arg_node is None: return 0 + if arg_node.kind() != ast.ASTKind.Name: return 0 + nm: ast.Name* = ast.Name*(arg_node) + if nm.id is None: return 0 + return self.Gen.VarGen._FreedMark(self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)) + # _translate_method_call - translate obj.method(args) into a call with the # object pointer (obj_ptr, an alloca of Ptr(StructTy)) as the self argument. @@ -586,27 +585,27 @@ novirtual class CallGenCall(CallGenBase.CallGenBase): # 跨模块回退(v3):本文件摘要表按文件重置,跨模块只能查 .vpi 落盘的摘要 sha_mc = self.Gen.StructGen.get_struct_sha1(class_name) pk_mc: int = self.Gen.CallGenBase.lookup_escape_via_vpi(pool, sha_mc, class_name, method_name) - if pk_mc != 0: esc_mask_mc = int(pk_mc & 4294967295) - # 跨模块常量特化:用实参常量套用对方模块 .vpi 落盘的守卫记录(形参位含 self 偏移) - if esc_mask_mc != 0: - cl_mc: int = self.Gen.CallGenBase.lookup_escape_clears_via_vpi(pool, sha_mc, class_name, method_name, cargs_mc, len(cargs_mc), 1) + if pk_mc != 0: esc_mask_mc = int(pk_mc & 4294967295) + # 跨模块常量特化:用实参常量套用对方模块 .vpi 落盘的守卫记录(形参位含 self 偏移) + if esc_mask_mc != 0: + cl_mc: int = self.Gen.CallGenBase.lookup_escape_clears_via_vpi(pool, sha_mc, class_name, method_name, cargs_mc, len(cargs_mc), 1) if cl_mc != 0: esc_mask_mc = esc_mask_mc & (~cl_mc) # 跨过程常量特化(P3 收尾):同文件能拿到方法体时,用常量实参重算摘要(形参位含 self 偏移) if esc_mask_mc != 0: can_rf: sizet = len(cargs_mc) - esc_mask_mc = GenApi.refine_escape_mask_method(pool, class_name, method_name, cargs_mc, can_rf, esc_mask_mc) - # 同命裁剪(**方法路径,此前缺失**):只清"写进形参对象字段"那一类位 —— 若其余实参(含 - # 接收者)也都在本帧,则接收者与本帧同命、并不真的逃逸。现场:`h.set_q(l)`,h 是 - # `new heap slife S()`(生命期本就是 FRAME)、l 是栈数组 → 两都在本帧 → 不该报。 - if esc_mask_mc != 0: - hard_mc: int = GenApi.get_param_escapes_hard_method(pool, class_name, method_name) - fld_mc: int = esc_mask_mc & (~hard_mc) - if fld_mc != 0: - recv_mc: ast.AST* = None - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - recv_mc = ast.Attribute*(cl.func).value - can_sf: sizet = len(cargs_mc) - cl_sfm: int = self.Gen.CallGen._FrameArgsEscapeClearsMethod(trans, recv_mc, cargs_mc, can_sf, fld_mc) + esc_mask_mc = GenApi.refine_escape_mask_method(pool, class_name, method_name, cargs_mc, can_rf, esc_mask_mc) + # 同命裁剪(**方法路径,此前缺失**):只清"写进形参对象字段"那一类位 —— 若其余实参(含 + # 接收者)也都在本帧,则接收者与本帧同命、并不真的逃逸。现场:`h.set_q(l)`,h 是 + # `new heap slife S()`(生命期本就是 FRAME)、l 是栈数组 → 两都在本帧 → 不该报。 + if esc_mask_mc != 0: + hard_mc: int = GenApi.get_param_escapes_hard_method(pool, class_name, method_name) + fld_mc: int = esc_mask_mc & (~hard_mc) + if fld_mc != 0: + recv_mc: ast.AST* = None + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + recv_mc = ast.Attribute*(cl.func).value + can_sf: sizet = len(cargs_mc) + cl_sfm: int = self.Gen.CallGen._FrameArgsEscapeClearsMethod(trans, recv_mc, cargs_mc, can_sf, fld_mc) if cl_sfm != 0: esc_mask_mc = esc_mask_mc & (~cl_sfm) # 声明式指令最终裁决(@life(escape/noescape):unsafe 但强制),在推断/回退之后最后套用 f_mc: int = GenApi.get_param_escape_force_method(pool, class_name, method_name) @@ -1191,7 +1190,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase): # Default-argument filling when the call supplies fewer args than the # definition; look up the function's defaults info. - mdf_defaults: t.CPtr = None + mdf_defaults: rawptr = None mdf_default_count: int = 0 mdf_param_count: int = 0 if trans is not None and trans._funcs is not None: diff --git a/App/lib/core/Gen/Call/CallGenCtor.vp b/App/lib/core/Gen/Call/CallGenCtor.vp index 3f00034..4a471af 100644 --- a/App/lib/core/Gen/Call/CallGenCtor.vp +++ b/App/lib/core/Gen/Call/CallGenCtor.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import ast import mlirlite @@ -149,7 +148,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase): new_ptr: mlirlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name, "__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct, is_volatile, cargs) if new_ptr is not None: storage_ptr = new_ptr - # __new__ declares `-> t.CPtr` (i8*) but the class type is Ptr(struct_ty). + # __new__ declares `-> rawptr` (i8*) but the class type is Ptr(struct_ty). # Using it directly degrades method dispatch; bitcast is a zero-cost type-layer fix. if new_ptr.Ty is not None: nw_ty: mlirlite.LLVMType* = mlirlite.Ptr(pool, struct_ty) @@ -711,7 +710,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase): new_ptr: mlirlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, class_name, "__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct, is_volatile, cargs) if new_ptr is not None: storage_ptr = new_ptr - # __new__ declares `-> t.CPtr` (i8*) but the class type is Ptr(struct_ty). + # __new__ declares `-> rawptr` (i8*) but the class type is Ptr(struct_ty). # Using it directly degrades method dispatch; bitcast is a zero-cost type-layer fix. if new_ptr.Ty is not None: nw_ty: mlirlite.LLVMType* = mlirlite.Ptr(pool, struct_ty) @@ -1184,7 +1183,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase): new_ptr: mlirlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, spec_name, "__new__", tmp, extra_args, arg_count, trans, None, gc_volatile, gc_arg_nodes) if new_ptr is not None: storage_ptr = new_ptr - # __new__ declares `-> t.CPtr` (i8*) but the class type is Ptr(struct_ty). + # __new__ declares `-> rawptr` (i8*) but the class type is Ptr(struct_ty). # Using it directly degrades method dispatch; bitcast is a zero-cost type-layer fix. if new_ptr.Ty is not None: nw_ty: mlirlite.LLVMType* = mlirlite.Ptr(pool, struct_ty) diff --git a/App/lib/core/Gen/Call/CallGenDispatch.vp b/App/lib/core/Gen/Call/CallGenDispatch.vp index 29ebe6e..b4faf3b 100644 --- a/App/lib/core/Gen/Call/CallGenDispatch.vp +++ b/App/lib/core/Gen/Call/CallGenDispatch.vp @@ -2,7 +2,6 @@ import lib.core.Gen.GenTypes as GenTypes import lib.core.Gen.Generator as Generator import lib.core.Gen.Expr.ExprGenCls as ExprGenCls import lib.core.Gen.Expr.ExprGenName as ExprGenName -import t, c from stdint import * import ast import mlirlite @@ -28,7 +27,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): # _tc_h0_generic_func - generic function call: infer/specialize type args, then emit the call. # Must run before normal function/constructor dispatch; hit_box marks handled void calls. - def _tc_h0_generic_func(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: t.CPtr = None) -> mlirlite.Value*: + def _tc_h0_generic_func(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: rawptr = None) -> mlirlite.Value*: if cl is None or trans is None: return None if self.Gen.ClassGenGeneric.GenericFuncKeys is None: return None if cl.func is None: return None @@ -148,7 +147,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): if string.strcmp(kw.arg, ag.arg) == 0: return int(ki) return -1 - def _emit_generic_func_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, trans: HT.Translator*, cl: ast.Call*, spec_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: t.CPtr = None) -> mlirlite.Value*: + def _emit_generic_func_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, trans: HT.Translator*, cl: ast.Call*, spec_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: rawptr = None) -> mlirlite.Value*: """Emit the specialized-function call, coercing args to the specialized param types.""" func: mlirlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, spec_name) if func is None: @@ -189,7 +188,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): # reads its first field as a string and emits illegal IR. Use the looked-up symbol name. return mlirlite.build_call(builder, spec_name, head, int(can), ret_ty, 0) - def _tc_h1_super_ctraits(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: t.CPtr = None) -> mlirlite.Value*: + def _tc_h1_super_ctraits(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: rawptr = None) -> mlirlite.Value*: """Compile-time super()/ctraits detection; sets hit_box on interception, else returns None.""" # super().method(args) -> static call to the parent method. Must intercept before attribute # dispatch, else Call(super) is treated as a plain function call and lookup hits self/vtable. @@ -221,7 +220,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): return mlirlite.const_int32(pool, 0) return None - def _tc_h2_c_special(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: t.CPtr = None) -> mlirlite.Value*: + def _tc_h2_c_special(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: rawptr = None) -> mlirlite.Value*: """Special c.Deref/Asm/LLVMIR calls; marks hit_box for void calls, else returns None.""" # __asm__(...) / __llvmir__(...) sugar: bare calls equal c.Asm(...) / c.LLVMIR(...). Must # intercept before the c.* attribute branch, since the bare cl.func is a Name. @@ -301,7 +300,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): return self.Gen.AsyncGen.translate_coro_gather(builder, pool, mod, cl, trans) return None - def _tc_h3_stdarg_cast(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet) -> mlirlite.Value*: + def _tc_h3_stdarg_cast(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet) -> mlirlite.Value*: """stdarg sugar and str/int/bool built-in casts; returns None when unmatched.""" # stdarg sugar (va_arg / arg / va_start / va_end): these are declared as pass bodies in # stdarg.vp and handled here at translation time by emitting LLVM va_arg / intrinsic calls. @@ -362,16 +361,16 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): return None return None - def _tc_h4_type_casts(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet) -> mlirlite.Value*: + def _tc_h4_type_casts(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet) -> mlirlite.Value*: """t.XXX / typedef type casts; returns None when unmatched.""" - # Detect t.XXX type casts (uint64(ptr), t.CPtr(val), int(val), ...): when func is t.XXX and + # Detect t.XXX type casts (uint64(ptr), rawptr(val), int(val), ...): when func is t.XXX and # XXX is a known type, treat it as a cast; once confirmed, never fall through to cross-module calls. if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: tc_at: ast.Attribute* = ast.Attribute*(cl.func) if tc_at.value is not None and tc_at.value.kind() == ast.ASTKind.Name: tc_mod_nm: ast.Name* = ast.Name*(tc_at.value) if tc_mod_nm.id is not None and string.strcmp(tc_mod_nm.id, "t") == 0: - # t.CType(value, TypeName, t.CPtr) casts value to TypeName*; TypeName is a type + # t.CType(value, TypeName, rawptr) casts value to TypeName*; TypeName is a type # name (not a value), so it must be handled explicitly or it falls through to a FATAL. if string.strcmp(func_name, "CType") == 0 and can >= 2: cty_node: ast.AST* = cargs.get(1) @@ -388,7 +387,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): cty_arg3: ast.AST* = cargs.get(2) cty_is_cptr: int = 0 if cty_arg3 is not None: - # Form 1: t.CPtr (Attribute) + # Form 1: rawptr (Attribute) if cty_arg3.kind() == ast.ASTKind.Attribute: cty_at3: ast.Attribute* = ast.Attribute*(cty_arg3) if cty_at3.attr is not None and string.strcmp(cty_at3.attr, "CPtr") == 0: @@ -413,7 +412,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): if cty_val is not None: return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, cty_val, ctype_target, cty_arg0, trans) # t.CType confirmed: even if type resolution fails, do not fall through to a cross-module FATAL return None - # CConst is a const marker: CConst(val, t.CPtr) -> Ptr(i8) (const void*). Without + # CConst is a const marker: CConst(val, rawptr) -> Ptr(i8) (const void*). Without # this it emits an undefined @CConst; single-arg CConst(x) returns the value unchanged. if string.strcmp(func_name, "CConst") == 0: if can >= 2: @@ -425,13 +424,13 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): target_ty: mlirlite.LLVMType* = self.Gen.TypeGenResolve.map_t_type(pool, func_name) if target_ty is not None: tc_effective_can: sizet = can - # Two-arg form: int(val, t.CPtr) -> Ptr(target_ty). void* is illegal in LLVM, + # Two-arg form: int(val, rawptr) -> Ptr(target_ty). void* is illegal in LLVM, # so CVoid* must be represented as i8*. if can == 2: tc_arg2_node: ast.AST* = cargs.get(1) tc_arg2_is_cptr: int = 0 if tc_arg2_node is not None: - # Form 1: t.CPtr (Attribute form) + # Form 1: rawptr (Attribute form) if tc_arg2_node.kind() == ast.ASTKind.Attribute: tc_arg2_at: ast.Attribute* = ast.Attribute*(tc_arg2_node) if tc_arg2_at.attr is not None and string.strcmp(tc_arg2_at.attr, "CPtr") == 0: @@ -513,13 +512,13 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): imp_gp = trans._imported_modules fi_gp = trans._from_imports bare_ty = self.Gen.TypeGenResolve.resolve_annotation_type(pool, gp_ast, imp_gp, fi_gp, trans, 0) - # Generic two-arg form T(val, t.CPtr) -> Ptr(T), aligned with int(val, t.CPtr) -> Ptr(i32); + # Generic two-arg form T(val, rawptr) -> Ptr(T), aligned with int(val, rawptr) -> Ptr(i32); # without it the two-arg call misses the can==1 branch and misreports an undefined bare call. if bare_ty is not None and can == 2: bare_arg2_node: ast.AST* = cargs.get(1) bare_arg2_is_cptr: int = 0 if bare_arg2_node is not None: - # Form 1: t.CPtr (Attribute form) + # Form 1: rawptr (Attribute form) if bare_arg2_node.kind() == ast.ASTKind.Attribute: bare_arg2_at: ast.Attribute* = ast.Attribute*(bare_arg2_node) if bare_arg2_at.attr is not None and string.strcmp(bare_arg2_at.attr, "CPtr") == 0: @@ -552,7 +551,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): return None - def _tc_h5_sizeof_len_isinst(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet) -> mlirlite.Value*: + def _tc_h5_sizeof_len_isinst(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet) -> mlirlite.Value*: """__sizeof__/len/isinstance built-ins; returns None when unmatched.""" # Detect ClassName.__sizeof__() and return the struct size constant (i64); it is a builtin, # not a cross-module call. Supports e.g. Argument.__sizeof__() and module-qualified classes. @@ -616,7 +615,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): # dot after a sha1 prefix. Union types (X*) and rawptr[X] both have pointer size 8. if string.strstr(sz_cls_name, "|") is not None: return mlirlite.const_int64(pool, 8) if string.strncmp(sz_cls_name, "rawptr[", 7) == 0: return mlirlite.const_int64(pool, 8) - # A trailing '*' means pointer size 8 (rawptr[T] == t.CPtr[T] == T*). Must check + # A trailing '*' means pointer size 8 (rawptr[T] == rawptr[T] == T*). Must check # trailing, not strrchr, since containers like list[{sha}.AST*] also contain '*'. _sz_len_s: sizet = string.strlen(sz_cls_name) while _sz_len_s > 0 and sz_cls_name[_sz_len_s - 1] == ' ': _sz_len_s -= 1 @@ -828,7 +827,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): return mlirlite.build_call(builder, len_mangled_x, len_self_x, 1, len_ret_x, 0) # fail-fast: the class has no __len__ (compile-time error, matching TPC # HandlesExprBuiltin._FailFastLenUnsupported wording). - self.Gen.TypeGenErr.fatal_error(len_arg_node, f"len() argument type '{len_cls_nm}' has no __len__ method. len() only supports fixed-size arrays/array pointers (t.CArray[T, N]), i8* (str/bytes), or structs with __len__; non-i8 bare pointers/scalar pointers have no length semantics: use str/bytes for strings, record the length yourself when the element count is needed, or use t.CPtr[Element] and maintain the element count explicitly", "TypeError") + self.Gen.TypeGenErr.fatal_error(len_arg_node, f"len() argument type '{len_cls_nm}' has no __len__ method. len() only supports fixed-size arrays/array pointers (t.CArray[T, N]), i8* (str/bytes), or structs with __len__; non-i8 bare pointers/scalar pointers have no length semantics: use str/bytes for strings, record the length yourself when the element count is needed, or use rawptr[Element] and maintain the element count explicitly", "TypeError") # Non-struct: str (Ptr(Int8)) uses strlen; other types fail fast len_arg_ty: mlirlite.LLVMType* = mlirlite.value_get_ty(len_val) len_is_str: int = 0 @@ -861,7 +860,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): return mlirlite.build_call(builder, "strlen", len_coerced, 1, i64_ty_ln2, 0) # fail-fast: not a string/array/object, so length is unavailable (matching TPC # HandlesExprBuiltin._FailFastLenUnsupported wording). - self.Gen.TypeGenErr.fatal_error(len_arg_node, "len() argument type not supported (not a string/array/object). len() only supports fixed-size arrays/array pointers (t.CArray[T, N]), i8* (str/bytes), or structs with __len__; non-i8 bare pointers/scalar pointers have no length semantics: use str/bytes for strings, record the length yourself when the element count is needed, or use t.CPtr[Element] and maintain the element count explicitly", "TypeError") + self.Gen.TypeGenErr.fatal_error(len_arg_node, "len() argument type not supported (not a string/array/object). len() only supports fixed-size arrays/array pointers (t.CArray[T, N]), i8* (str/bytes), or structs with __len__; non-i8 bare pointers/scalar pointers have no length semantics: use str/bytes for strings, record the length yourself when the element count is needed, or use rawptr[Element] and maintain the element count explicitly", "TypeError") # Detect isinstance(): runtime vtable subclass-set comparison. obj's head vtable pointer must # be in {Cls and all subclass vtables}; NoVTable targets fall back to a compile-time check. @@ -873,7 +872,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): return None - def _tc_h6_method_dispatch(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: t.CPtr = None) -> mlirlite.Value*: + def _tc_h6_method_dispatch(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*, func_name: str, cargs: list[ast.AST*]*, can: sizet, hit_box: rawptr = None) -> mlirlite.Value*: """Static class/method/receiver/self.field/list built-ins; sets hit_box, else returns None.""" # REnum.kind() compiles to a __tag read (offset 0, type from the field declaration): bitcast obj # to __tag* + load. Four criteria detect REnum, incl. pointee __tag and X.field annotations. @@ -917,7 +916,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): rk_ve: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, rk_nm.id) rk_annot_raw: str = self.Gen.VarGen.var_annot_class_name(rk_ve) if rk_annot_raw is not None: - # Truncate the union/generic suffix (" | t.CPtr" / "[...]") + # Truncate the union/generic suffix (" | rawptr" / "[...]") rk_ae: sizet = 0 while rk_annot_raw[rk_ae] != '\0' and rk_annot_raw[rk_ae] != ' ' and rk_annot_raw[rk_ae] != '|' and rk_annot_raw[rk_ae] != '[': rk_ae += 1 rk_ab: str = pool.alloc(rk_ae + 1) diff --git a/App/lib/core/Gen/Call/CallGenFd.vp b/App/lib/core/Gen/Call/CallGenFd.vp index b8fea40..7b46c99 100644 --- a/App/lib/core/Gen/Call/CallGenFd.vp +++ b/App/lib/core/Gen/Call/CallGenFd.vp @@ -1,5 +1,4 @@ import lib.core.Gen.GenTypes as GenTypes -import t, c from stdint import * import ast import mlirlite diff --git a/App/lib/core/Gen/Call/CallGenLeafKit.vp b/App/lib/core/Gen/Call/CallGenLeafKit.vp index a009942..1414141 100644 --- a/App/lib/core/Gen/Call/CallGenLeafKit.vp +++ b/App/lib/core/Gen/Call/CallGenLeafKit.vp @@ -1,5 +1,4 @@ import lib.core.Gen.GenTypes as GenTypes -import t, c from stdint import * import ast import mlirlite @@ -863,7 +862,7 @@ novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin): return None - def add_func_to_table(self, funcs: GenTypes.FuncEntry*, func_count: int, name: str, func: mlirlite.Function*, max_count: int, defaults: t.CPtr = None, default_count: int = 0, param_count: int = 0, pool: memhub.MemBuddy* = None, def_sha1: str = None) -> int: + def add_func_to_table(self, funcs: GenTypes.FuncEntry*, func_count: int, name: str, func: mlirlite.Function*, max_count: int, defaults: rawptr = None, default_count: int = 0, param_count: int = 0, pool: memhub.MemBuddy* = None, def_sha1: str = None) -> int: """Add a function to a func table; returns 0 on success""" if name is None or func is None or funcs is None: return 1 if func_count >= max_count: return 1 @@ -1021,7 +1020,7 @@ novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin): return 1 - def _register_global_defaults(self, name: str, defaults: t.CPtr, default_count: int, param_count: int, def_sha1: str = None) -> int: + def _register_global_defaults(self, name: str, defaults: rawptr, default_count: int, param_count: int, def_sha1: str = None) -> int: """Register a function's default arguments in the global table; returns 0 on success""" if name is None or defaults is None: return 1 if self._init_global_defaults_table() == 0: return 1 @@ -1066,7 +1065,7 @@ novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin): string.memset(kinds, 0, default_count * 4) string.memset(ints, 0, default_count * 8) string.memset(strs, 0, default_count * 8) - dl: list[ast.AST*]* = (list[ast.AST*] | t.CPtr)(uint64(defaults)) + dl: list[ast.AST*]* = list[ast.AST*]*(uint64(defaults)) di: int for di in range(int(default_count)): dnode: ast.AST* = dl.get(di) diff --git a/App/lib/core/Gen/Call/CallGenLib.vp b/App/lib/core/Gen/Call/CallGenLib.vp index 449824e..a9971ac 100644 --- a/App/lib/core/Gen/Call/CallGenLib.vp +++ b/App/lib/core/Gen/Call/CallGenLib.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import ast import mlirlite @@ -151,7 +150,7 @@ novirtual class CallGenLib(CallGenBase.CallGenBase): i2 += 1 return new_head - # _coerce_args_to_def_params: coerce cross-module call args to vpi definition-side param + # _coerce_args_to_def_params: coerce cross-module call args to vpi definition-side param # types so call/declare/define widths match; bare C-lib names use the C-lib path instead. def _coerce_args_to_def_params(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, call_name: str, head: mlirlite.Value*, count: int, cargs: list[ast.AST*]* = None, self_off: int = 0, trans: HT.Translator* = None) -> mlirlite.Value*: """Coerce cross-module call args to vpi definition-side param types; returns the rebuilt chain""" @@ -231,7 +230,7 @@ novirtual class CallGenLib(CallGenBase.CallGenBase): if cls_nm is not None: stdlib.free(cls_nm) return new_head - # _coerce_arg_value_to_ty: convert one arg Value to the target param type -- same-width ints + # _coerce_arg_value_to_ty: convert one arg Value to the target param type -- same-width ints # pass through, narrow/wide ints trunc/extend, mismatched pointers bitcast; else unchanged. def _coerce_arg_value_to_ty(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, val: mlirlite.Value*, tgt_ty: mlirlite.LLVMType*, node: ast.AST* = None, trans: HT.Translator* = None, tpl_src: int = 0) -> mlirlite.Value*: """Convert one argument Value to the target param type; leaves it unchanged when unsafe""" diff --git a/App/lib/core/Gen/Call/CallGenMixin.vp b/App/lib/core/Gen/Call/CallGenMixin.vp index b91c8d9..a90e2cc 100644 --- a/App/lib/core/Gen/Call/CallGenMixin.vp +++ b/App/lib/core/Gen/Call/CallGenMixin.vp @@ -1,14 +1,11 @@ import lib.core.Gen.GenTypes as GenTypes -import t, c from stdint import * import ast import mlirlite import memhub import string -import stdio import stdlib import viperlib -import lib.core.VLogger as VLogger import lib.core.Gen.Translator as HT import lib.core.Gen.Type.TypeSpec as TSpec import lib.Stub.StubGen.VpiReader as VpiReader @@ -148,7 +145,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase): cur_param = mlirlite.param_get_next(cur_param) return 0 - def translate_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, node: ast.AST*, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator* = None) -> mlirlite.Value*: + def translate_call(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, node: ast.AST*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator* = None) -> mlirlite.Value*: """Translate a Call node and return the result Value.""" cl: ast.Call* = ast.Call*(node) # Static symbols must not be used cross-module: fail fast on mod.fn(...) hitting another @@ -276,7 +273,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase): if h0_hit_val != 0: return None # super()/ctraits detection: a void method yields None but is handled, so hit_box must # separate "handled" from "missed"; otherwise super() falls through and reports undefined. - h1_hit: t.CPtr = stdlib.malloc(4) + h1_hit: rawptr = stdlib.malloc(4) if h1_hit is not None: h1_hit[0] = 0 _tc_h1_super_ctraits_res: mlirlite.Value* = self.Gen.CallGenDispatch._tc_h1_super_ctraits(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h1_hit) h1_hit_val: int = 0 @@ -340,7 +337,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase): # c.Asm/c.LLVMIR special calls return None when void but are handled, so use hit_box to # separate "missed"; otherwise they fall through to the external-function path and mis-report. - h2_hit: t.CPtr = stdlib.malloc(4) + h2_hit: rawptr = stdlib.malloc(4) if h2_hit is not None: h2_hit[0] = 0 _tc_h2_c_special_res: mlirlite.Value* = self.Gen.CallGenDispatch._tc_h2_c_special(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h2_hit) h2_hit_val: int = 0 @@ -363,7 +360,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase): # Method dispatch may succeed yet return None (e.g. void __before_init__/__init__), so hit_box # must separate "recognized method" from "missed"; otherwise the object name is looked up as a module. - h6_hit: t.CPtr = stdlib.malloc(4) + h6_hit: rawptr = stdlib.malloc(4) if h6_hit is not None: h6_hit[0] = 0 _tc_h6_method_dispatch_res: mlirlite.Value* = self.Gen.CallGenDispatch._tc_h6_method_dispatch(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h6_hit) h6_hit_val: int = 0 @@ -781,7 +778,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase): found_func = bi_decl # Use accessors to bypass stub type restrictions. found_ret_ty: mlirlite.LLVMType* = None - found_params: t.CPtr = None + found_params: rawptr = None if found_func is not None: found_ret_ty = mlirlite.function_get_ret_ty(found_func) found_params = mlirlite.function_get_params(found_func) @@ -912,7 +909,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase): return self.Gen.CallGenLeafKit.translate_closure_call(pool, builder, mod, fp_alloca, cargs, can, trans) # ---- M3: session-function table hit -> take the ctx function-pointer slot and call indirectly ---- # Placed last in the found_func-is-None block so locals/closures shadow session functions; only foreign bare names reach the table. - sfn_box: t.CPtr = None + sfn_box: rawptr = None if trans is not None and trans.ReplCtx is not None and (cl.func is None or cl.func.kind() == ast.ASTKind.Name): sfn_box = stdlib.malloc(4) if sfn_box is not None: @@ -1069,7 +1066,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase): # Default-argument filling: when fewer args than params, fill the gaps; the defaults array is # right-aligned to args (defaults[0] maps to args[offset], offset = param_count - default_count). if can > 0 or (can == 0 and cargs is not None): - df_defaults: t.CPtr = None + df_defaults: rawptr = None df_default_count: int = 0 df_param_count: int = 0 # Compute the callee module SHA1 as a qualifier key (module.func -> that module; bare -> current), @@ -1142,7 +1139,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase): df_arg_val: mlirlite.Value* = None if gd_entry is not None: df_arg_val = self.Gen.CallGenLeafKit._build_const_from_snapshot(pool, mod, gd_entry, df_di, trans, builder) if df_arg_val is None and df_defaults is not None: - df_defaults_list: list[ast.AST*]* = (list[ast.AST*] | t.CPtr)(uint64(df_defaults)) + df_defaults_list: list[ast.AST*]* = list[ast.AST*]*(df_defaults) df_default_node: ast.AST* = df_defaults_list.get(df_di) if df_default_node is not None: df_arg_val = self.Gen.ExprGen.translate_value(builder, pool, mod, df_default_node, None, 0, trans) if df_arg_val is not None: diff --git a/App/lib/core/Gen/Call/CallGenProp.vp b/App/lib/core/Gen/Call/CallGenProp.vp index af7c59d..0715e3a 100644 --- a/App/lib/core/Gen/Call/CallGenProp.vp +++ b/App/lib/core/Gen/Call/CallGenProp.vp @@ -1,6 +1,5 @@ import lib.core.Gen.GenTypes as GenTypes import lib.core.Gen.GenApi as GenApi -import t, c from stdint import * import ast import mlirlite @@ -74,10 +73,10 @@ novirtual class CallGenProp(CallGenBase.CallGenBase): if cls_sha1_rt is None or self._dep_text_ll_exists(pool, cls_sha1_rt) == 0: call_ret_ty = mlirlite.Int32(pool) else: call_ret_ty = self._fail_method_ret_ty(method_name, None, class_name, None, cls_sha1_rt) - # Value-reference (&T / &temp T) params: auto-address the user args before param-type - # coercion (self/obj or the classmethod cls occupies index 0, skipped via start_idx). - call_head = self._apply_auto_addr_to_call_args(builder, pool, mod, trans, call_name, arg_nodes, call_head, call_count, start_idx) - + # Value-reference (&T / &temp T) params: auto-address the user args before param-type + # coercion (self/obj or the classmethod cls occupies index 0, skipped via start_idx). + call_head = self._apply_auto_addr_to_call_args(builder, pool, mod, trans, call_name, arg_nodes, call_head, call_count, start_idx) + # Coerce args to the declared param types (same as _translate_method_call); target func: found_func, # else the mangled module declare. Otherwise call(i32) vs declare(i64) mismatches and llc errors. tgt_func_pc: mlirlite.Function* = found_func diff --git a/App/lib/core/Gen/Call/CallGenVa.vp b/App/lib/core/Gen/Call/CallGenVa.vp index 5e02ac0..a24d271 100644 --- a/App/lib/core/Gen/Call/CallGenVa.vp +++ b/App/lib/core/Gen/Call/CallGenVa.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import ast import mlirlite @@ -17,7 +16,7 @@ novirtual class CallGenVa(CallGenBase.CallGenBase): # _func_has_eh_params - whether callee signature has try-except EH out params (main excluded) # ============================================================ - def _va_arg_get_alloca_ptr(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, arg_node: ast.AST*, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*) -> mlirlite.Value*: + def _va_arg_get_alloca_ptr(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, arg_node: ast.AST*, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*) -> mlirlite.Value*: """Return the alloca pointer of a va_list variable without loading it.""" if arg_node is None: return None # Name node: look up the alloca pointer from the symbol table (no load) @@ -37,7 +36,7 @@ novirtual class CallGenVa(CallGenBase.CallGenBase): # Type node present but unresolvable: fail-fast, never fall back to i32 (would read the vararg slot at the wrong width) self.Gen.TypeGenErr.fatal_error(type_node, "va_arg type resolution failed", "TypeError") return mlirlite.Int32(pool) - def _translate_va_arg_sugar(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, cargs: list[ast.AST*]*, can: sizet, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*) -> mlirlite.Value*: + def _translate_va_arg_sugar(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, cargs: list[ast.AST*]*, can: sizet, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*) -> mlirlite.Value*: """Emit a va_arg instruction reading the next variadic argument from the va_list.""" if can == 0 or cargs is None: return mlirlite.const_int32(pool, 0) @@ -67,7 +66,7 @@ novirtual class CallGenVa(CallGenBase.CallGenBase): # Emit the va_arg instruction return mlirlite.build_va_arg(builder, ap_ptr, read_ty) - def _translate_arg_sugar(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, cargs: list[ast.AST*]*, can: sizet, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*) -> mlirlite.Value*: + def _translate_arg_sugar(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cl: ast.Call*, cargs: list[ast.AST*]*, can: sizet, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*) -> mlirlite.Value*: """Emit va_arg reading from the enclosing variadic's own va_list or a forwarded va_list.""" # arg() has two forms: # (1) Own-variadic form: inside `def f(a, *args)`, trans._va_list_ptr is the i8* address of @@ -104,7 +103,7 @@ novirtual class CallGenVa(CallGenBase.CallGenBase): # Emit va_arg, using va_ptr as the va_list address (own buffer or forwarded pointer) return mlirlite.build_va_arg(builder, va_ptr, read_ty) - def _translate_va_start_sugar(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cargs: list[ast.AST*]*, can: sizet, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*) -> mlirlite.Value*: + def _translate_va_start_sugar(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cargs: list[ast.AST*]*, can: sizet, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*) -> mlirlite.Value*: """Emit llvm.va_start to initialize the va_list (the second C-ABI argument is unused).""" if can == 0 or cargs is None: return mlirlite.const_int32(pool, 0) @@ -122,7 +121,7 @@ novirtual class CallGenVa(CallGenBase.CallGenBase): void_ty_vs: mlirlite.LLVMType* = mlirlite.Void(pool) mlirlite.build_call(builder, "llvm.va_start", ap_i8, 1, void_ty_vs, 0) return mlirlite.const_int32(pool, 0) - def _translate_va_end_sugar(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cargs: list[ast.AST*]*, can: sizet, funcs_ptr: t.CPtr, func_count: int, trans: HT.Translator*) -> mlirlite.Value*: + def _translate_va_end_sugar(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, cargs: list[ast.AST*]*, can: sizet, funcs_ptr: rawptr, func_count: int, trans: HT.Translator*) -> mlirlite.Value*: """Emit llvm.va_end to clean up the va_list (a no-op on most platforms).""" if can == 0 or cargs is None: return mlirlite.const_int32(pool, 0) @@ -180,7 +179,7 @@ novirtual class CallGenVa(CallGenBase.CallGenBase): fixed_count: int = -1 if func is not None and func.IsVarArg == 1: fixed_count = self._get_func_fixed_param_count(func) else: - # Fall back to the known variadic C-lib signature table (snprintf etc.) when func is None (stub not yet injected) + # Fall back to the known variadic C-lib signature table (snprintf etc.) when func is None (stub not yet injected) # or IsVarArg=0 (ad hoc declare); otherwise i32 varargs aren't promoted and the Win64 8-byte slot keeps only 4 bytes. fixed_count = self._get_known_vararg_cfunc_fixed_count(call_name) if fixed_count < 0: return 0 diff --git a/App/lib/core/Gen/Call/CallGenVt.vp b/App/lib/core/Gen/Call/CallGenVt.vp index 7dbc128..10a544d 100644 --- a/App/lib/core/Gen/Call/CallGenVt.vp +++ b/App/lib/core/Gen/Call/CallGenVt.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import ast import mlirlite diff --git a/App/lib/core/Gen/Class/ClassGenBase.vp b/App/lib/core/Gen/Class/ClassGenBase.vp index 7a0cb50..a64bd39 100644 --- a/App/lib/core/Gen/Class/ClassGenBase.vp +++ b/App/lib/core/Gen/Class/ClassGenBase.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import ast import memhub diff --git a/App/lib/core/Gen/Class/ClassGenDef.vp b/App/lib/core/Gen/Class/ClassGenDef.vp index 4dd727c..22ec3f1 100644 --- a/App/lib/core/Gen/Class/ClassGenDef.vp +++ b/App/lib/core/Gen/Class/ClassGenDef.vp @@ -1,5 +1,4 @@ import lib.core.Gen.GenTypes as GenTypes -import t, c from stdint import * import ast import mlirlite diff --git a/App/lib/core/Gen/Class/ClassGenEnum.vp b/App/lib/core/Gen/Class/ClassGenEnum.vp index 6dd7b6c..806c6d8 100644 --- a/App/lib/core/Gen/Class/ClassGenEnum.vp +++ b/App/lib/core/Gen/Class/ClassGenEnum.vp @@ -1,5 +1,4 @@ import lib.core.Gen.GenTypes as GenTypes -import t, c from stdint import * import ast import mlirlite diff --git a/App/lib/core/Gen/Class/ClassGenGeneric.vp b/App/lib/core/Gen/Class/ClassGenGeneric.vp index c810611..997b59c 100644 --- a/App/lib/core/Gen/Class/ClassGenGeneric.vp +++ b/App/lib/core/Gen/Class/ClassGenGeneric.vp @@ -1,5 +1,4 @@ import lib.core.Gen.GenTypes as GenTypes -import t, c from stdint import * import ast import mlirlite @@ -579,7 +578,7 @@ novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase): if self.GenericClassNames is None or class_name is None: return None # Assign the list to a local to trigger type inference (avoids field __len__ failure) names_local: list[str]* = self.GenericClassNames - nodes_local: list[ast.ClassDef*] | t.CPtr = self.GenericClassNodes + nodes_local: list[ast.ClassDef*]* = self.GenericClassNodes cn: sizet = len(names_local) i: sizet for i in range(int(cn)): diff --git a/App/lib/core/Gen/Class/ClassGenMixin.vp b/App/lib/core/Gen/Class/ClassGenMixin.vp index 8aa5a93..b71e7e0 100644 --- a/App/lib/core/Gen/Class/ClassGenMixin.vp +++ b/App/lib/core/Gen/Class/ClassGenMixin.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * from . import ClassGenBase diff --git a/App/lib/core/Gen/DebugInfoGen.vp b/App/lib/core/Gen/DebugInfoGen.vp index 56ca7ca..3b01450 100644 --- a/App/lib/core/Gen/DebugInfoGen.vp +++ b/App/lib/core/Gen/DebugInfoGen.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import mlirlite import memhub diff --git a/App/lib/core/Gen/Expr/ExprGenAttr.vp b/App/lib/core/Gen/Expr/ExprGenAttr.vp index 09dd85c..0d433a1 100644 --- a/App/lib/core/Gen/Expr/ExprGenAttr.vp +++ b/App/lib/core/Gen/Expr/ExprGenAttr.vp @@ -1,11 +1,9 @@ import lib.core.Gen.GenTypes as GenTypes -import t, c from stdint import * import ast import mlirlite import memhub import string -import stdio import stdlib import viperlib import lib.core.Gen.Translator as HT diff --git a/App/lib/core/Gen/Expr/ExprGenBase.vp b/App/lib/core/Gen/Expr/ExprGenBase.vp index 29fdab5..0bf84a8 100644 --- a/App/lib/core/Gen/Expr/ExprGenBase.vp +++ b/App/lib/core/Gen/Expr/ExprGenBase.vp @@ -1,11 +1,9 @@ import lib.core.Gen.Generator as Generator -import t, c from stdint import * import ast import mlirlite import memhub import string -import stdlib import viperlib import lib.core.Gen.Translator as HT import lib.Projectrans.Utils as Utils diff --git a/App/lib/core/Gen/Expr/ExprGenCdef.vp b/App/lib/core/Gen/Expr/ExprGenCdef.vp index bcdc143..8970683 100644 --- a/App/lib/core/Gen/Expr/ExprGenCdef.vp +++ b/App/lib/core/Gen/Expr/ExprGenCdef.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import ast import mlirlite diff --git a/App/lib/core/Gen/Expr/ExprGenCls.vp b/App/lib/core/Gen/Expr/ExprGenCls.vp index 8715d7b..920af50 100644 --- a/App/lib/core/Gen/Expr/ExprGenCls.vp +++ b/App/lib/core/Gen/Expr/ExprGenCls.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import ast import mlirlite diff --git a/App/lib/core/Gen/Expr/ExprGenConst.vp b/App/lib/core/Gen/Expr/ExprGenConst.vp index d41e095..f048190 100644 --- a/App/lib/core/Gen/Expr/ExprGenConst.vp +++ b/App/lib/core/Gen/Expr/ExprGenConst.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import ast import mlirlite diff --git a/App/lib/core/Gen/Expr/ExprGenFstr.vp b/App/lib/core/Gen/Expr/ExprGenFstr.vp index c024ee0..132297f 100644 --- a/App/lib/core/Gen/Expr/ExprGenFstr.vp +++ b/App/lib/core/Gen/Expr/ExprGenFstr.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import ast import mlirlite diff --git a/App/lib/core/Gen/Expr/ExprGenMixin.vp b/App/lib/core/Gen/Expr/ExprGenMixin.vp index 5ebbd65..4263857 100644 --- a/App/lib/core/Gen/Expr/ExprGenMixin.vp +++ b/App/lib/core/Gen/Expr/ExprGenMixin.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import ast import memhub @@ -28,7 +27,7 @@ novirtual class ExprGenMixin(ExprGenBase.ExprGenBase): """Expression-handling mixin (pure methods, no state fields).""" # Translate a value expression (RHS dispatch) - module-level version. - def translate_value(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, node: ast.AST*, funcs_ptr: t.CPtr = None, func_count: int = 0, trans: HT.Translator* = None, target_ty: mlirlite.LLVMType* = None, use_ctx: str = None) -> mlirlite.Value*: + def translate_value(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, node: ast.AST*, funcs_ptr: rawptr = None, func_count: int = 0, trans: HT.Translator* = None, target_ty: mlirlite.LLVMType* = None, use_ctx: str = None) -> mlirlite.Value*: """Translate a value expression to an LLVM Value (depth-guard wrapper; see _translate_value_impl). target_ty = assignment/parameter type context; use_ctx = real call site for CDefine width checks.""" if trans is not None: @@ -38,7 +37,7 @@ novirtual class ExprGenMixin(ExprGenBase.ExprGenBase): if trans is not None: trans.TranslateDepth -= 1 return rv - def _translate_value_impl(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, node: ast.AST*, funcs_ptr: t.CPtr = None, func_count: int = 0, trans: HT.Translator* = None, target_ty: mlirlite.LLVMType* = None, use_ctx: str = None) -> mlirlite.Value*: + def _translate_value_impl(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, node: ast.AST*, funcs_ptr: rawptr = None, func_count: int = 0, trans: HT.Translator* = None, target_ty: mlirlite.LLVMType* = None, use_ctx: str = None) -> mlirlite.Value*: """Translate a value expression to an LLVM Value.""" if node is None: return None k: int = node.kind() diff --git a/App/lib/core/Gen/Expr/ExprGenName.vp b/App/lib/core/Gen/Expr/ExprGenName.vp index a729556..903ef21 100644 --- a/App/lib/core/Gen/Expr/ExprGenName.vp +++ b/App/lib/core/Gen/Expr/ExprGenName.vp @@ -1,5 +1,4 @@ import lib.core.Gen.GenTypes as GenTypes -import t, c from stdint import * import ast import mlirlite @@ -44,7 +43,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase): if trans is not None: if self.Gen.VarGen._FreedCheck(self.Gen.VarGen.lookup_var(trans.SymTab, nm_id)) != 0: self.Gen.TypeGenErr.fatal_error(node, f"cannot use '{nm_id}': already released by a @life(willFree(...)) call", "LifetimeError") - # CDefine compile-time constant: return the constant (float -> double, int -> i32). + # CDefine compile-time constant: return the constant (float -> double, int -> i32). # Existing variables win over CDefine table entries injected from vpi stubs (lookup_var guard). cdef_val_d: double = self.Gen.TypeGenCDef.lookup_cdefine_double(nm_id) if self.Gen.TypeGenCDef.is_cdefine_found() != 0: @@ -55,10 +54,10 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase): cdef_sv: str = self.Gen.TypeGenCDef.lookup_cdefine_string(nm_id) if cdef_sv is not None: return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, cdef_sv, trans) self.Gen.TypeGenErr.fatal_error(node, f"CDefine string value missing: {nm_id}", "InternalCompilerError") - # 浮点常量:声明为 32 位 float(`define PI: float = ...`)时直接出 f32 常量, - # 否则出 f64 —— 出 f64 会把后续 f32 字面量整体提升成 double(fpext/cvtss2sd)。 - if self.Gen.TypeGenCDef.is_cdefine_double() != 0: - if self.Gen.TypeGenCDef.is_cdefine_float32() != 0: return mlirlite.ConstFloat(pool, mlirlite.Float(pool), cdef_val_d) + # 浮点常量:声明为 32 位 float(`define PI: float = ...`)时直接出 f32 常量, + # 否则出 f64 —— 出 f64 会把后续 f32 字面量整体提升成 double(fpext/cvtss2sd)。 + if self.Gen.TypeGenCDef.is_cdefine_double() != 0: + if self.Gen.TypeGenCDef.is_cdefine_float32() != 0: return mlirlite.ConstFloat(pool, mlirlite.Float(pool), cdef_val_d) return mlirlite.ConstFloat(pool, mlirlite.Double(pool), cdef_val_d) # Integer CDefine: re-look-up the full 64-bit value (a double round-trip loses # precision and would generate a wrong constant). @@ -474,7 +473,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase): # Is a list type: load out the list object pointer builder: mlirlite.IRBuilder* = trans._cur_builder return mlirlite.build_load(builder, pointee, alloca) - # _nonlocal_subscript_ptr - element pointer for a nonlocal array/pointer subscript: read the + # _nonlocal_subscript_ptr - element pointer for a nonlocal array/pointer subscript: read the # shared heap address from env (_load_raw_var_ptr), bitcast, then GEP (the outer alloca is unusable). def _nonlocal_subscript_ptr(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, trans: HT.Translator*, nm_id: str, idx_val: mlirlite.Value*) -> mlirlite.Value*: """Element pointer for a nonlocal array/pointer subscript (env heap addr -> bitcast -> GEP).""" @@ -592,6 +591,24 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase): elem_ptr_ty_v: mlirlite.LLVMType* = mlirlite.Ptr(pool, elem_ty_v) casted_v: mlirlite.Value* = mlirlite.build_bitcast(builder, elem_addr_v, elem_ptr_ty_v) if casted_v is not None: return mlirlite.build_load(builder, elem_ty_v, casted_v) + # 值类型类实例(`d: dict = dict(bd)`):槽里就是对象本身,`d[k]` 必须按 + # 类的 `__getitem__` 调用编译,self 传槽地址(= &对象)。此前这里直接 + # return None,调用方(AnnAssign)又对 None 静默不写,整条语句凭空消失 + # ——现场:p1/p2/p3 全未赋值,随后解引用栈垃圾断言崩溃。 + cls_nm_val: str = self.Gen.StructGen.get_class_name_by_type(pool, pointee) + if not (cls_nm_val is None): + gi_lookup_val: str = pool.alloc(128) + if gi_lookup_val is not None: + viperlib.snprintf(gi_lookup_val, 128, "%s.__getitem__", cls_nm_val) + if self.Gen.CallGenBase.find_func_in_module(mod, gi_lookup_val) is not None: + arg_vals_val: sizet* = pool.alloc(8) + if not (arg_vals_val is None): + arg_vals_val[0] = sizet(idx_val) + ret_val_sub: mlirlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, cls_nm_val, "__getitem__", alloca, arg_vals_val, 1, trans, sub) + if not (ret_val_sub is None): return ret_val_sub + # 非 list、无 __getitem__ 的结构体值不可下标:按对象大小 GEP 是非法 IR, + # 明确 fail-fast,绝不静默返回 None(调用方会把整条语句丢掉)。 + self.Gen.TypeGenErr.fatal_error(node, f"cannot subscript the value-type object '{nm.id}' of type '{lsn_v}' (the class defines no __getitem__); use a pointer variable ('T*') or define __getitem__", "TypeError") return None case mlirlite.LLVMType.Ptr(inner_ty): # Check whether inner_ty is list[T]; list subscripts go through __getitem__ (inline), not pointer traversal @@ -876,6 +893,19 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase): if ptr_val is None: return None gep_r: mlirlite.Value* = mlirlite.build_gep(builder, inner_ty, ptr_val, idx_val) return gep_r + case mlirlite.LLVMType.Struct(_fs_gsp, _fc_gsp, _lsn_gsp): + # 值类型类实例(`d: dict = dict(bd)`):槽里是对象本身,`d[k] = v` + # 只能走类的 `__setitem__`。定义了 __setitem__ 时返回 None,交由 + # 赋值路径的 __setitem__ 重载分支(self 用槽地址);否则按对象数组 + # GEP 会生成非法 IR,明确 fail-fast 而不是静默。 + cls_nm_val_gsp: str = self.Gen.StructGen.get_class_name_by_type(pool, pointee) + if not (cls_nm_val_gsp is None): + si_lookup_val: str = pool.alloc(128) + if si_lookup_val is not None: + viperlib.snprintf(si_lookup_val, 128, "%s.__setitem__", cls_nm_val_gsp) + if self.Gen.CallGenBase.find_func_in_module(mod, si_lookup_val) is not None: return None + self.Gen.TypeGenErr.fatal_error(node, f"cannot index the value-type object '{nm.id}' of type '{_lsn_gsp}' (the class defines no __setitem__); use a pointer variable ('T*') or define __setitem__", "TypeError") + return None case _: # Plain scalar pointee (e.g. i64/i32/i8): GEP directly to the idx-th element; union type # (IsPtrElement=1, pointee i8 but 8-byte pointer elements) uses an i8* stride instead. diff --git a/App/lib/core/Gen/Expr/ExprGenOps.vp b/App/lib/core/Gen/Expr/ExprGenOps.vp index 9d08187..34da536 100644 --- a/App/lib/core/Gen/Expr/ExprGenOps.vp +++ b/App/lib/core/Gen/Expr/ExprGenOps.vp @@ -1,5 +1,4 @@ import lib.core.Gen.GenTypes as GenTypes -import t, c from stdint import * import ast import mlirlite @@ -208,6 +207,17 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase): mod_nm: ast.Name* = ast.Name*(at.value) if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0 and at.attr is not None: if self._type_name_unsigned(at.attr) != 0: return 1 + return 0 + # Plain function call: widen by the callee's **declared return type**. Without this, + # `uint64(f())` with `def f() -> uint32` emitted `sext i32 -> i64` (verified in the + # generated IR), so a u32 with bit 31 set grew 0xFFFFFFFF in the high half — a real + # value 0x88691F61 became 0xFFFFFFFF88691F61 (stackmap pointers were mangled this way). + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + func_nm_u: ast.Name* = ast.Name*(cl.func) + if func_nm_u.id is not None: + fe_fn_u: GenTypes.FuncEntry* = self.Gen.CallGenLeafKit.find_func_entry_global(func_nm_u.id) + if fe_fn_u is not None and fe_fn_u.Spec is not None: + if TSpec.SpecIsUnsigned(fe_fn_u.Spec.Ret) != 0: return 1 return 0 if k == ast.ASTKind.Name: nm: ast.Name* = ast.Name*(node) @@ -774,7 +784,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase): case mlirlite.LLVMType.Func(_, _, _): # 函数指针变量(嵌套函数名在符号表里是 Ptr(Func)):变量本身就是 # 那个函数地址,`&f` 应给出它的值 Ptr(Func)(一级),而不是变量 - # 地址 Ptr(Ptr(Func))(二级)——否则传给 callback: t.CPtr 会因 + # 地址 Ptr(Ptr(Func))(二级)——否则传给 callback: rawptr 会因 # 级数不符报 CastError(source level 2 -> target level 1)。 fp_ty_ao: mlirlite.LLVMType* = mlirlite.Ptr(pool, ao2) return mlirlite.build_load(builder, fp_ty_ao, v_ao) @@ -835,7 +845,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase): return tmp_slot_ao # translate_boolop - BoolOp(op, values): short-circuit evaluation returning i1. # and: a false short-circuits to merge (returns a's i1); or: a true short-circuits; the last value is evaluated then branches to merge; merge phis all i1 edges. - def translate_boolop(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, node: ast.AST*, funcs_ptr: t.CPtr = None, func_count: int = 0, trans: HT.Translator* = None) -> mlirlite.Value*: + def translate_boolop(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, node: ast.AST*, funcs_ptr: rawptr = None, func_count: int = 0, trans: HT.Translator* = None) -> mlirlite.Value*: """Translate boolean and/or with short-circuit evaluation, returning i1.""" bo: ast.BoolOp* = ast.BoolOp*(node) if bo is None: return None diff --git a/App/lib/core/Gen/Func/FuncGenBase.vp b/App/lib/core/Gen/Func/FuncGenBase.vp index e9ecf13..e31211f 100644 --- a/App/lib/core/Gen/Func/FuncGenBase.vp +++ b/App/lib/core/Gen/Func/FuncGenBase.vp @@ -1,11 +1,9 @@ -import t, c from stdint import * import ast import mlirlite import memhub import string import viperlib -import stdio import stdlib import lib.core.VLogger as VLogger import lib.core.Gen.Translator as HT diff --git a/App/lib/core/Gen/Func/FuncGenDef.vp b/App/lib/core/Gen/Func/FuncGenDef.vp index a263426..0b76e2b 100644 --- a/App/lib/core/Gen/Func/FuncGenDef.vp +++ b/App/lib/core/Gen/Func/FuncGenDef.vp @@ -1,6 +1,5 @@ import lib.core.Gen.GenTypes as GenTypes import lib.core.Gen.Func.FuncGenMixin as FuncGenMixin -import t, c from stdint import * import ast import mlirlite @@ -173,7 +172,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase): # Extract default-argument info. Note: assign the attribute to an explicitly typed list[...]* local before # calling __len__(), otherwise the list type is not recognized and the GEP base becomes i32 0 (llc error). fd_args_node: ast.Arguments* = fd.args - fd_defaults: t.CPtr = None + fd_defaults: rawptr = None fd_default_count: int = 0 fd_param_count: int = 0 if fd_args_node is not None: @@ -510,7 +509,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase): if func_section is not None: mlirlite.function_set_attr_group(func, func_section) # Extract default-argument info - tfd_defaults: t.CPtr = None + tfd_defaults: rawptr = None tfd_default_count: int = 0 tfd_param_count: int = 0 if args_node is not None: diff --git a/App/lib/core/Gen/Func/FuncGenMixin.vp b/App/lib/core/Gen/Func/FuncGenMixin.vp index 1f01da8..6cbef36 100644 --- a/App/lib/core/Gen/Func/FuncGenMixin.vp +++ b/App/lib/core/Gen/Func/FuncGenMixin.vp @@ -1,5 +1,4 @@ import lib.core.Gen.GenTypes as GenTypes -import t, c from stdint import * import ast import mlirlite @@ -83,7 +82,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase): # types go into the param_tys buffer (CVoid skipped, aligning with alloca indices). imported_modules: str = trans._imported_modules from_imports: str = trans._from_imports - param_tys: t.CPtr = pool.alloc(8 * 64) + param_tys: rawptr = pool.alloc(8 * 64) if param_tys is not None: string.memset(param_tys, 0, 8 * 64) param_count: int = 0 if fd.args is not None: @@ -192,8 +191,8 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase): old_insw: int = trans._in_switch_case # Separate nonlocal buffer: sharing [0] would overwrite the parent's set (ClosureTest2 # Test 7: level2's b clobbers level1's a). Restored after translation. - saved_nl_names: t.CPtr = trans._nonlocal_names - saved_nl_types: t.CPtr = trans._nonlocal_types + saved_nl_names: rawptr = trans._nonlocal_names + saved_nl_types: rawptr = trans._nonlocal_types # 7. Switch to the nested function scope and clear scope names trans._cur_func = func @@ -778,7 +777,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase): # ============================================================ # _collect_chain_nonlocals - recursively gather nonlocal names in the nested chain (deduped) - def _collect_chain_nonlocals(self, trans: HT.Translator*, node: ast.AST*, names: t.CPtr, count: int) -> int: + def _collect_chain_nonlocals(self, trans: HT.Translator*, node: ast.AST*, names: rawptr, count: int) -> int: """Recursively collect all nonlocal declaration names in a nested FunctionDef chain (deduped)""" if node is None or names is None: return count fd: ast.FunctionDef* = ast.FunctionDef*(node) @@ -898,7 +897,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase): param_names: str = pool.alloc(32 * 64) # 64 params x 32-byte names if param_names is None: return None string.memset(param_names, 0, 32 * 64) - param_tys: t.CPtr = pool.alloc(8 * 64) # LLVMType pointer slots + param_tys: rawptr = pool.alloc(8 * 64) # LLVMType pointer slots if param_tys is None: return None string.memset(param_tys, 0, 8 * 64) param_count: int = 0 @@ -935,10 +934,10 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase): cap_names: str = pool.alloc(64 * 64) # 64 captures x 64-byte names if cap_names is None: return None string.memset(cap_names, 0, 64 * 64) - cap_allocas: t.CPtr = pool.alloc(8 * 64) # Parent alloca pointer slots + cap_allocas: rawptr = pool.alloc(8 * 64) # Parent alloca pointer slots if cap_allocas is None: return None string.memset(cap_allocas, 0, 8 * 64) - cap_tys: t.CPtr = pool.alloc(8 * 64) # Capture variable type slots + cap_tys: rawptr = pool.alloc(8 * 64) # Capture variable type slots if cap_tys is None: return None string.memset(cap_tys, 0, 8 * 64) cap_count: int = self._lambda_scan_body(trans, lam.body, param_names, param_count, cap_names, cap_allocas, cap_tys, 0) @@ -1148,7 +1147,7 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase): # ============================================================ # _lambda_scan_body - recursively collect outer Name refs into cap_names/cap_allocas/cap_tys - def _lambda_scan_body(self, trans: HT.Translator*, node: ast.AST*, param_names: str, param_count: int, cap_names: str, cap_allocas: t.CPtr, cap_tys: t.CPtr, cap_count: int) -> int: + def _lambda_scan_body(self, trans: HT.Translator*, node: ast.AST*, param_names: str, param_count: int, cap_names: str, cap_allocas: rawptr, cap_tys: rawptr, cap_count: int) -> int: """Recursively scan lambda body Name references and collect captured variables""" if node is None or trans is None: return cap_count k: int = node.kind() diff --git a/App/lib/core/Gen/GenApi.vp b/App/lib/core/Gen/GenApi.vp index 86329ee..2dd3b3d 100644 --- a/App/lib/core/Gen/GenApi.vp +++ b/App/lib/core/Gen/GenApi.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import ast import mlirlite @@ -687,52 +686,52 @@ def _WillFreeArgIndex(fn: ast.FunctionDef*, arg: ast.AST*) -> int: return idx -def get_param_escapes_hard(name: str) -> int: - """本文件函数"硬逃逸位"掩码(全局写 / 返回形参 / 传递闭包 / base 未定的字段写);0 = 无记录""" - if _g_gen is not None: return _g_gen.StructGen.get_param_escapes_hard(name) - return 0 - - -def get_param_escapes_hard_method(pool: memhub.MemBuddy*, class_name: str, method_name: str) -> int: - """方法版硬逃逸位:查 "Class.method" 并沿 MRO 回退""" - if _g_gen is not None: return _g_gen.StructGen.get_param_escapes_hard_method(pool, class_name, method_name) - return 0 - - -# ---- 声明式指令(@life(escape/noescape))的最终裁决掩码 ---- -# 契约表与推断表分开:调用点在所有推断/裁剪之后最后套用,任何推导都不能推翻。 -def get_param_escape_force(name: str) -> int: - """`@life(escape(...))` 强制逃逸位掩码;0 = 无该标注""" - if _g_gen is not None: return _g_gen.StructGen.get_param_escape_force(name) - return 0 - - -def get_param_noescape_force(name: str) -> int: - """`@life(noescape(...))` 强制不逃逸位掩码;0 = 无该标注""" - if _g_gen is not None: return _g_gen.StructGen.get_param_noescape_force(name) - return 0 - - -def get_param_escape_force_method(pool: memhub.MemBuddy*, class_name: str, method_name: str) -> int: - """方法版 `@life(escape(...))` 掩码:查 "Class.method" 并沿 MRO 回退""" - if _g_gen is not None: return _g_gen.StructGen.get_param_escape_force_method(pool, class_name, method_name) - return 0 - - -def get_param_noescape_force_method(pool: memhub.MemBuddy*, class_name: str, method_name: str) -> int: - """方法版 `@life(noescape(...))` 掩码:查 "Class.method" 并沿 MRO 回退""" - if _g_gen is not None: return _g_gen.StructGen.get_param_noescape_force_method(pool, class_name, method_name) - return 0 - - -# escape_leak_line - **错误路径专用**:被调者第 want_pi 号形参的"首个逃逸写入点"行号。 -# 只在 fail-fast 报错时调用(会重扫一次被调者函数体);跨模块拿不到 AST 时返回 0。 -def escape_leak_line(name: str, want_pi: int) -> int: - """形参 want_pi 的逃逸点行号;0 = 未知(含跨模块)""" - if _g_gen is not None: return _g_gen.StructGen.escape_leak_line(name, want_pi) - return 0 - - +def get_param_escapes_hard(name: str) -> int: + """本文件函数"硬逃逸位"掩码(全局写 / 返回形参 / 传递闭包 / base 未定的字段写);0 = 无记录""" + if _g_gen is not None: return _g_gen.StructGen.get_param_escapes_hard(name) + return 0 + + +def get_param_escapes_hard_method(pool: memhub.MemBuddy*, class_name: str, method_name: str) -> int: + """方法版硬逃逸位:查 "Class.method" 并沿 MRO 回退""" + if _g_gen is not None: return _g_gen.StructGen.get_param_escapes_hard_method(pool, class_name, method_name) + return 0 + + +# ---- 声明式指令(@life(escape/noescape))的最终裁决掩码 ---- +# 契约表与推断表分开:调用点在所有推断/裁剪之后最后套用,任何推导都不能推翻。 +def get_param_escape_force(name: str) -> int: + """`@life(escape(...))` 强制逃逸位掩码;0 = 无该标注""" + if _g_gen is not None: return _g_gen.StructGen.get_param_escape_force(name) + return 0 + + +def get_param_noescape_force(name: str) -> int: + """`@life(noescape(...))` 强制不逃逸位掩码;0 = 无该标注""" + if _g_gen is not None: return _g_gen.StructGen.get_param_noescape_force(name) + return 0 + + +def get_param_escape_force_method(pool: memhub.MemBuddy*, class_name: str, method_name: str) -> int: + """方法版 `@life(escape(...))` 掩码:查 "Class.method" 并沿 MRO 回退""" + if _g_gen is not None: return _g_gen.StructGen.get_param_escape_force_method(pool, class_name, method_name) + return 0 + + +def get_param_noescape_force_method(pool: memhub.MemBuddy*, class_name: str, method_name: str) -> int: + """方法版 `@life(noescape(...))` 掩码:查 "Class.method" 并沿 MRO 回退""" + if _g_gen is not None: return _g_gen.StructGen.get_param_noescape_force_method(pool, class_name, method_name) + return 0 + + +# escape_leak_line - **错误路径专用**:被调者第 want_pi 号形参的"首个逃逸写入点"行号。 +# 只在 fail-fast 报错时调用(会重扫一次被调者函数体);跨模块拿不到 AST 时返回 0。 +def escape_leak_line(name: str, want_pi: int) -> int: + """形参 want_pi 的逃逸点行号;0 = 未知(含跨模块)""" + if _g_gen is not None: return _g_gen.StructGen.escape_leak_line(name, want_pi) + return 0 + + def get_param_willfree(name: str) -> int: """本文件函数的 willFree 形参掩码(第 k 位=第 k 个形参在本调用后失效);无记录返回 0""" if _g_gen is not None: return _g_gen.StructGen.get_param_willfree(name) diff --git a/App/lib/core/Gen/GenTypes.vp b/App/lib/core/Gen/GenTypes.vp index ca6b23f..c224023 100644 --- a/App/lib/core/Gen/GenTypes.vp +++ b/App/lib/core/Gen/GenTypes.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import ast import mlirlite diff --git a/App/lib/core/Gen/Generator.vp b/App/lib/core/Gen/Generator.vp index 101816b..1ddfa36 100644 --- a/App/lib/core/Gen/Generator.vp +++ b/App/lib/core/Gen/Generator.vp @@ -1,6 +1,5 @@ import string import lib.core.CompilerFactory as CompilerFactory -import t, c from stdint import * import stdio import stdlib diff --git a/App/lib/core/Gen/ImportsGenMixin.vp b/App/lib/core/Gen/ImportsGenMixin.vp index bce4511..41b3600 100644 --- a/App/lib/core/Gen/ImportsGenMixin.vp +++ b/App/lib/core/Gen/ImportsGenMixin.vp @@ -1,5 +1,4 @@ import lib.core.Gen.Generator as Generator -import t, c from stdint import * import ast import memhub @@ -213,7 +212,7 @@ novirtual class ImportsGenMixin: # lookup; else fall back to scanning. orig None means a first occurrence with no alias. if from_imports == self.CurFromImportsPtr and self.CurFromImportsOrigs is not None: if self.CurFromImportsOrigs.__contains__(local_name) != 0: - v_o: t.CPtr = self.CurFromImportsOrigs.__getitem__(local_name) + v_o: rawptr = self.CurFromImportsOrigs.__getitem__(local_name) if v_o is not None: return rawptr(v_o) # Index miss or None value never returns None directly (the real string may still # contain the name); fall through to scanning (correctness first). @@ -275,10 +274,10 @@ novirtual class ImportsGenMixin: name_is_star: int = 0 if string.strlen(name) == 1 and name[0] == '*': name_is_star = 1 if name_is_star == 0: - v_f: t.CPtr = self.CurFromImportsMods.__getitem__(name) + v_f: rawptr = self.CurFromImportsMods.__getitem__(name) if v_f is not None: return rawptr(v_f) if allow_star_fallback != 0: - sv_f: t.CPtr = self.CurFromImportsMods.__getitem__("*") + sv_f: rawptr = self.CurFromImportsMods.__getitem__("*") if sv_f is not None: return rawptr(sv_f) # Neither exact nor star hit in the index never returns None (an incomplete index # misses imported names, causing _op_head NameError); fall through to scanning. @@ -326,15 +325,15 @@ novirtual class ImportsGenMixin: # for `from .X import Y`). Idempotent; memory is stdlib.malloc'd to persist across phases. def register_reexport(self, mod_sha1: str, func_name: str, source_module: str) -> int: """Register a re-export mapping; returns 0 on success, -1 on failure.""" - if mod_sha1 is None or func_name is None or source_module is None: return -1 - # fail-fast: the table is a flat slab with fixed slots (17 bytes for the SHA1, 64 for the - # name/module). strncpy used to clamp silently, after which lookup_reexport's full-name - # strcmp never matched (or matched another module sharing the 63-byte prefix). - if string.strlen(mod_sha1) > 16: - self.Gen.TypeGenErr.fatal_error(None, "re-export module SHA1 is longer than its 16-byte table slot", "OverflowError") - if string.strlen(func_name) > 62: - self.Gen.TypeGenErr.fatal_error(None, f"re-exported name '{func_name}' exceeds the 62-byte table slot; shorten the identifier", "OverflowError") - if string.strlen(source_module) > 62: + if mod_sha1 is None or func_name is None or source_module is None: return -1 + # fail-fast: the table is a flat slab with fixed slots (17 bytes for the SHA1, 64 for the + # name/module). strncpy used to clamp silently, after which lookup_reexport's full-name + # strcmp never matched (or matched another module sharing the 63-byte prefix). + if string.strlen(mod_sha1) > 16: + self.Gen.TypeGenErr.fatal_error(None, "re-export module SHA1 is longer than its 16-byte table slot", "OverflowError") + if string.strlen(func_name) > 62: + self.Gen.TypeGenErr.fatal_error(None, f"re-exported name '{func_name}' exceeds the 62-byte table slot; shorten the identifier", "OverflowError") + if string.strlen(source_module) > 62: self.Gen.TypeGenErr.fatal_error(None, f"re-export source module '{source_module}' exceeds the 62-byte table slot; shorten the module name", "OverflowError") # Lazy initialization if self.ReexportSha1s is None: diff --git a/App/lib/core/Gen/MatchGenMixin.vp b/App/lib/core/Gen/MatchGenMixin.vp index b3057ee..ba0f8ba 100644 --- a/App/lib/core/Gen/MatchGenMixin.vp +++ b/App/lib/core/Gen/MatchGenMixin.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import ast import mlirlite diff --git a/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp b/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp index 798f838..5039279 100644 --- a/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp +++ b/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp @@ -1,6 +1,5 @@ import lib.core.Gen.GenTypes as GenTypes import lib.core.Gen.Generator as Generator -import t, c from stdint import * import ast import mlirlite @@ -434,13 +433,13 @@ novirtual class StmtGenCifMixin: if rt.value is not None: # f-string escape (return f"..."): its buffer lives on this frame's stack and dies on # return; copy it out explicitly (GenApi.escape_fstring_copy) before returning it. - GenApi.fail_if_fstring_escape(rt.value, "function return value") - # A2(§14.3 第 6 条,方案 A):定义端对 `return <本帧存储>` 的**声明感知** fail-fast。 - # A2 移除了"一律拦"的旧判据(定义端分不清"交出本帧"与"借出调用方的存储"), - # 但也不能一律放:判据收敛到被调者自己的 `@life(ret(...))` —— `ret(frame)` 或 - # `ret(borrows=<该形参>)` 放行;无声明 / 声明为非帧 → LifetimeError。 - # 实现见 AssignGenMixin.check_return_frame_decl。 - self.Gen.AssignGen.check_return_frame_decl(trans, rt.value) + GenApi.fail_if_fstring_escape(rt.value, "function return value") + # A2(§14.3 第 6 条,方案 A):定义端对 `return <本帧存储>` 的**声明感知** fail-fast。 + # A2 移除了"一律拦"的旧判据(定义端分不清"交出本帧"与"借出调用方的存储"), + # 但也不能一律放:判据收敛到被调者自己的 `@life(ret(...))` —— `ret(frame)` 或 + # `ret(borrows=<该形参>)` 放行;无声明 / 声明为非帧 → LifetimeError。 + # 实现见 AssignGenMixin.check_return_frame_decl。 + self.Gen.AssignGen.check_return_frame_decl(trans, rt.value) # return a, b → pack an anonymous struct value (multi-return, return type tuple[T1,T2]) if rt.value.kind() == ast.ASTKind.Tuple: rtp: ast.Tuple* = ast.Tuple*(rt.value) @@ -511,6 +510,15 @@ novirtual class StmtGenCifMixin: ret_val_ty: mlirlite.LLVMType* = None cur_func_rv: mlirlite.Function* = trans._cur_func if cur_func_rv is not None: ret_val_ty = mlirlite.function_get_ret_ty(cur_func_rv) + # `return <闭包变量>` 且返回注解是 t.Callable:闭包对象是 {fn_ptr, env_ptr}, + # 不是裸函数指针。调用方把结果存进 t.Callable 变量后 `f()` 会按裸函数指针直调, + # 跳到堆地址崩溃(ClosureCallTest 现场)。这里明确 fail-fast,要求用 rawptr/t.CPtr。 + if rt.value.kind() == ast.ASTKind.Name and trans is not None and trans.CurFuncRetAnnot is not None: + clo_nm_rv: ast.Name* = ast.Name*(rt.value) + if clo_nm_rv.id is not None and self.Gen.CallGenLeafKit.is_closure_name(clo_nm_rv.id) != 0: + clo_ret_rv: mlirlite.LLVMType* = self.Gen.TypeGenErr.try_extract_callable_ret(pool, trans.CurFuncRetAnnot, trans._imported_modules, trans._from_imports, trans) + if clo_ret_rv is not None: + self.Gen.TypeGenErr.fatal_error(rt, f"the return annotation is t.Callable (a bare function pointer) but the returned value is the closure variable '{clo_nm_rv.id}'. A closure is a (fn_ptr, env_ptr) object; storing it where a t.Callable is expected makes the caller jump into heap data. Annotate the return as rawptr / t.CPtr instead", "TypeError") # [C1] return-annotation context: record this return's direct value node so a bare # generic ctor (`return Stack()` in `-> Stack[int]`) specializes via CurFuncRetAnnot. trans.CurRetNode = rt.value @@ -770,23 +778,23 @@ novirtual class StmtGenCifMixin: mlirlite.build_br(builder, merge_bb) else_branches_merge = 1 - # 生命期汇合:有 else → 与 then 末状态 Meet;无 else → 与 if 前状态 Meet(else 路径=跳过) - if has_else == 1: self.Gen.VarGen.life_join(life_snap1) - else: self.Gen.VarGen.life_join(life_snap0) - - # willFree 失效槽表合流:只有"到达合流的路径"参与(否则会把"分支体内 free 后 return" - # 的失效态错误地带到合流之后——fileio.vp 的 `if …: free(buf); return None` 即此现场)。 - # 两分支都到达 → 求交(curr=else 末态 ∩ then 末态); - # 仅 then 到达 → 取 then 末态; - # 仅 else/无 else → 取 else 末态(无 else 时即 if 前状态)。 - if has_else == 1: - if then_branches_merge != 0 and else_branches_merge != 0: - self.Gen.VarGen.freed_join(freed_snap1) - elif then_branches_merge != 0: - self.Gen.VarGen.freed_restore(freed_snap1) - else: - self.Gen.VarGen.freed_restore(freed_snap0) - + # 生命期汇合:有 else → 与 then 末状态 Meet;无 else → 与 if 前状态 Meet(else 路径=跳过) + if has_else == 1: self.Gen.VarGen.life_join(life_snap1) + else: self.Gen.VarGen.life_join(life_snap0) + + # willFree 失效槽表合流:只有"到达合流的路径"参与(否则会把"分支体内 free 后 return" + # 的失效态错误地带到合流之后——fileio.vp 的 `if …: free(buf); return None` 即此现场)。 + # 两分支都到达 → 求交(curr=else 末态 ∩ then 末态); + # 仅 then 到达 → 取 then 末态; + # 仅 else/无 else → 取 else 末态(无 else 时即 if 前状态)。 + if has_else == 1: + if then_branches_merge != 0 and else_branches_merge != 0: + self.Gen.VarGen.freed_join(freed_snap1) + elif then_branches_merge != 0: + self.Gen.VarGen.freed_restore(freed_snap1) + else: + self.Gen.VarGen.freed_restore(freed_snap0) + # 7. merge reachability (used by tail-flow checks): without else cond_br always reaches # merge; with else, any branch br reaching merge suffices; only all-return is unreachable. trans._ctrl_merge_reachable = 1 diff --git a/App/lib/core/Gen/Stmt/StmtGenDeclMixin.vp b/App/lib/core/Gen/Stmt/StmtGenDeclMixin.vp index 99773a2..177343a 100644 --- a/App/lib/core/Gen/Stmt/StmtGenDeclMixin.vp +++ b/App/lib/core/Gen/Stmt/StmtGenDeclMixin.vp @@ -1,5 +1,4 @@ import lib.core.Gen.GenTypes as GenTypes -import t, c from stdint import * import ast import mlirlite diff --git a/App/lib/core/Gen/Stmt/StmtGenMixin.vp b/App/lib/core/Gen/Stmt/StmtGenMixin.vp index ae14c5d..238df34 100644 --- a/App/lib/core/Gen/Stmt/StmtGenMixin.vp +++ b/App/lib/core/Gen/Stmt/StmtGenMixin.vp @@ -1,7 +1,6 @@ import lib.core.Gen.GenTypes as GenTypes import lib.core.Gen.Generator as Generator import lib.core.Gen.Call.CallGenFd as CallGenFd -import t, c from stdint import * import ast import mlirlite @@ -177,49 +176,49 @@ novirtual class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin): mlirlite.build_call(builder, dl_fn_name, dl_self, 2, dl_ret, 0) return 0 - # translate_assert - translate `assert cond[, msg]` into a single testcheck.check(...) call: - # a true condition is silent (ok_msg=None), a false one reports FAIL via the standard path - # (no printf/exit/exception; the checker prints nothing when the condition holds). - def translate_assert(self, trans: HT.Translator*, node: ast.AST*) -> int: - """Translate an assert statement; returns 0""" - if trans is None or node is None: return 0 - asn: ast.Assert* = ast.Assert*(node) - if asn is None or asn.test is None: return 0 - pool: memhub.MemBuddy* = trans.Pool - builder: mlirlite.IRBuilder* = trans._cur_builder - mod: mlirlite.LLVMModule* = trans.Module - if pool is None or builder is None or mod is None: return 0 - - # Resolve the message argument: omitted -> "assertion failed". A non-string literal is - # rejected here (clear report); a non-string expression is caught by the call's int->ptr rule. - msg_node: ast.AST* = asn.msg - if msg_node is None: - msg_node = ast.Constant(pool, ast.CONST_STR, 0, 0.0, "assertion failed", node.lineno, node.col_offset) - if msg_node is None: return 0 - elif msg_node.kind() == ast.ASTKind.Constant: - msg_c: ast.Constant* = ast.Constant*(msg_node) - if msg_c is None or msg_c.const_kind != ast.CONST_STR: - self.Gen.TypeGenErr.fatal_error(msg_node, "assert message must be a string (str)", "TypeError") - return 0 - - # Synthesize `testcheck.check(, None, )` and reuse the normal call translation - # (cross-module name resolution + argument coercion stay in one place). - none_node: ast.AST* = ast.Constant(pool, ast.CONST_NONE, 0, 0.0, None, node.lineno, node.col_offset) - if none_node is None: return 0 - args_list: list[ast.AST*]* = list[ast.AST*](pool, 8) - if args_list is None: return 0 - args_list.append(asn.test) - args_list.append(none_node) - args_list.append(msg_node) - mod_name_node: ast.AST* = ast.Name(pool, "testcheck", ast.ASTCtx.Load) - if mod_name_node is None: return 0 - check_attr: ast.AST* = ast.Attribute(pool, mod_name_node, "check", ast.ASTCtx.Load) - if check_attr is None: return 0 - call_node: ast.AST* = ast.Call(pool, check_attr, args_list, None) - if call_node is None: return 0 - self.Gen.ExprGen.translate_value(builder, pool, mod, call_node, trans._funcs, trans._func_count, trans) - return 0 - + # translate_assert - translate `assert cond[, msg]` into a single testcheck.check(...) call: + # a true condition is silent (ok_msg=None), a false one reports FAIL via the standard path + # (no printf/exit/exception; the checker prints nothing when the condition holds). + def translate_assert(self, trans: HT.Translator*, node: ast.AST*) -> int: + """Translate an assert statement; returns 0""" + if trans is None or node is None: return 0 + asn: ast.Assert* = ast.Assert*(node) + if asn is None or asn.test is None: return 0 + pool: memhub.MemBuddy* = trans.Pool + builder: mlirlite.IRBuilder* = trans._cur_builder + mod: mlirlite.LLVMModule* = trans.Module + if pool is None or builder is None or mod is None: return 0 + + # Resolve the message argument: omitted -> "assertion failed". A non-string literal is + # rejected here (clear report); a non-string expression is caught by the call's int->ptr rule. + msg_node: ast.AST* = asn.msg + if msg_node is None: + msg_node = ast.Constant(pool, ast.CONST_STR, 0, 0.0, "assertion failed", node.lineno, node.col_offset) + if msg_node is None: return 0 + elif msg_node.kind() == ast.ASTKind.Constant: + msg_c: ast.Constant* = ast.Constant*(msg_node) + if msg_c is None or msg_c.const_kind != ast.CONST_STR: + self.Gen.TypeGenErr.fatal_error(msg_node, "assert message must be a string (str)", "TypeError") + return 0 + + # Synthesize `testcheck.check(, None, )` and reuse the normal call translation + # (cross-module name resolution + argument coercion stay in one place). + none_node: ast.AST* = ast.Constant(pool, ast.CONST_NONE, 0, 0.0, None, node.lineno, node.col_offset) + if none_node is None: return 0 + args_list: list[ast.AST*]* = list[ast.AST*](pool, 8) + if args_list is None: return 0 + args_list.append(asn.test) + args_list.append(none_node) + args_list.append(msg_node) + mod_name_node: ast.AST* = ast.Name(pool, "testcheck", ast.ASTCtx.Load) + if mod_name_node is None: return 0 + check_attr: ast.AST* = ast.Attribute(pool, mod_name_node, "check", ast.ASTCtx.Load) + if check_attr is None: return 0 + call_node: ast.AST* = ast.Call(pool, check_attr, args_list, None) + if call_node is None: return 0 + self.Gen.ExprGen.translate_value(builder, pool, mod, call_node, trans._funcs, trans._func_count, trans) + return 0 + # translate_try - try/except translation. Exception = (i32 code, i8* msg); # except X statically expands X and all descendant exception codes. def translate_try(self, trans: HT.Translator*, node: ast.AST*) -> int: diff --git a/App/lib/core/Gen/Translator.vp b/App/lib/core/Gen/Translator.vp index 843850f..958de00 100644 --- a/App/lib/core/Gen/Translator.vp +++ b/App/lib/core/Gen/Translator.vp @@ -1,6 +1,5 @@ import lib.core.Gen.GenApi as GenApi import lib.core.Gen.GenTypes as GenTypes -import t, c from stdint import * import ast import mlirlite @@ -204,7 +203,7 @@ novirtual class Translator: _lambda_count: int # Set of nonlocal variables across the function chain (collected by pre-scan). # The outermost function allocates their heaps and stores addresses in @nlheap.{sha1}.{name}. - _nl_chain_names: t.CPtr + _nl_chain_names: rawptr _nl_chain_count: int # Chain-nonlocal heap built flag (built once per function): reset to 0 on entering a function, # set to 1 by _prepare_chain_nonlocals. Shared by nested definitions to avoid double malloc. @@ -694,8 +693,8 @@ novirtual class Translator: """Detect list/dict container usage and inject container-class visibility.""" if tree is None or tree.children is None: return # Use stack buffers to pass detection results (4-byte int pointers across helper calls) - need_list_box: t.CPtr = stdlib.malloc(4) - need_dict_box: t.CPtr = stdlib.malloc(4) + need_list_box: rawptr = stdlib.malloc(4) + need_dict_box: rawptr = stdlib.malloc(4) if need_list_box is None or need_dict_box is None: if need_list_box is not None: stdlib.free(need_list_box) if need_dict_box is not None: stdlib.free(need_dict_box) @@ -809,7 +808,7 @@ novirtual class Translator: stdlib.free(nm_buf) return 0 - def _scan_container_usage(self, node: ast.AST*, need_list_box: t.CPtr, need_dict_box: t.CPtr): + def _scan_container_usage(self, node: ast.AST*, need_list_box: rawptr, need_dict_box: rawptr): """Recursively scan AST statement structure for list/dict container usage.""" if node is None: return k: int = node.kind() @@ -843,7 +842,7 @@ novirtual class Translator: n_s: sizet = len(ch_s) for ci_s in range(int(n_s)): self._scan_container_usage(ch_s.get(ci_s), need_list_box, need_dict_box) - def _check_container_type_node(self, node: ast.AST*, need_list_box: t.CPtr, need_dict_box: t.CPtr): + def _check_container_type_node(self, node: ast.AST*, need_list_box: rawptr, need_dict_box: rawptr): """Check whether a type-position node is list/dict, recursing through Name/Subscript/BinOp.""" if node is None: return k: int = node.kind() diff --git a/App/lib/core/Gen/TranslatorGenMixin.vp b/App/lib/core/Gen/TranslatorGenMixin.vp index ec6d3c9..e7e26e0 100644 --- a/App/lib/core/Gen/TranslatorGenMixin.vp +++ b/App/lib/core/Gen/TranslatorGenMixin.vp @@ -1,5 +1,4 @@ import lib.core.Gen.Generator as Generator -import t, c from stdint import * import ast import mlirlite diff --git a/App/lib/core/Gen/Type/TypeGenBase.vp b/App/lib/core/Gen/Type/TypeGenBase.vp index 2c025d9..a0a0dbf 100644 --- a/App/lib/core/Gen/Type/TypeGenBase.vp +++ b/App/lib/core/Gen/Type/TypeGenBase.vp @@ -1,15 +1,11 @@ import lib.core.Gen.Type.TypeGenMixin as TypeGenMixin import lib.core.Gen.GenTypes as GenTypes import lib.core.Gen.Generator as Generator -import t, c from stdint import * import ast -import mlirlite import memhub import hashtable import string -import viperlib -import stdio import stdlib import lib.core.VLogger as VLogger import lib.Stub.StubMerger as StubMerger @@ -49,9 +45,9 @@ novirtual class TypeGenBase: # 判定"是不是浮点常量"一律用 `!= 0`(既有调用处口径不变),只有浮点常量物化处区分 64/32: # `define PI: float = 3.14159...` 必须直接出 f32 常量,否则与 f32 字面量混算会多出 fpext。 CDefineDoubleFlags: list[int]* - CDefineStrFlags: list[int]* # 1=string value (e.g. ZLIB_VERSION: t.CDefine = "1.3.2") - # 值表达式的**位宽**(bit);0=未知(按值推断)。来源:右侧显式强转(如 WORD(0x0080))优先, - # 否则声明注解(define X: WORD = ... 的 T)。物化时据此定宽,避免小位宽常量被提升为 i32。 + CDefineStrFlags: list[int]* # 1=string value (e.g. ZLIB_VERSION: t.CDefine = "1.3.2") + # 值表达式的**位宽**(bit);0=未知(按值推断)。来源:右侧显式强转(如 WORD(0x0080))优先, + # 否则声明注解(define X: WORD = ... 的 T)。物化时据此定宽,避免小位宽常量被提升为 i32。 CDefineBits: list[int]* CDefineIsDouble: int CDefineIsStr: int @@ -126,7 +122,7 @@ novirtual class TypeGenBase: self.CDefineNames = None self.CDefineValues = None self.CDefineDoubleFlags = None - self.CDefineStrFlags = None + self.CDefineStrFlags = None self.CDefineBits = None self.CDefineIsDouble = 0 self.CDefineIsStr = 0 diff --git a/App/lib/core/Gen/Type/TypeGenCDef.vp b/App/lib/core/Gen/Type/TypeGenCDef.vp index b87be48..d96681d 100644 --- a/App/lib/core/Gen/Type/TypeGenCDef.vp +++ b/App/lib/core/Gen/Type/TypeGenCDef.vp @@ -1,15 +1,9 @@ -import t, c from stdint import * -import ast -import mlirlite import memhub import string import viperlib import stdio -import stdlib import lib.core.VLogger as VLogger -import lib.core.Gen.Translator as HT -import lib.Stub.StubMerger as StubMerger import lib.core.CompilerFactory as CompilerFactory @@ -21,14 +15,14 @@ define CDEFINE_IDX_CAP = 4096 # Index hash constants (32-bit FNV-1a) define CDEF_IDX_FNV_OFFSET = 2166136261 define CDEF_IDX_FNV_PRIME = 16777619 -define CDEF_IDX_FNV_MASK = 4294967295 - -# CDefine 浮点常量的宽度种类(CDefineDoubleFlags / XmodCdefDoubleFlags 条目编码)。 -# 1=f64(double,默认),2=f32(float);0 表示非浮点。既有读取处一律按 `!= 0` 判定 -# "是浮点常量",故 f32 天然兼容;只有浮点常量的物化处需要区分 64/32。 -# 必须写明 `: int`:无注解 define 按**值的最小可存宽度**物化(1/2 → i8), -# 直接当实参调用 `list[int].append(x: int)` 会落成 `i8 != i32`(mlir-opt 校验失败)。 -define CDEFINE_FLOAT_KIND_F64: int = 1 +define CDEF_IDX_FNV_MASK = 4294967295 + +# CDefine 浮点常量的宽度种类(CDefineDoubleFlags / XmodCdefDoubleFlags 条目编码)。 +# 1=f64(double,默认),2=f32(float);0 表示非浮点。既有读取处一律按 `!= 0` 判定 +# "是浮点常量",故 f32 天然兼容;只有浮点常量的物化处需要区分 64/32。 +# 必须写明 `: int`:无注解 define 按**值的最小可存宽度**物化(1/2 → i8), +# 直接当实参调用 `list[int].append(x: int)` 会落成 `i8 != i32`(mlir-opt 校验失败)。 +define CDEFINE_FLOAT_KIND_F64: int = 1 define CDEFINE_FLOAT_KIND_F32: int = 2 @@ -454,7 +448,7 @@ novirtual class TypeGenCDef(TypeGenBase.TypeGenBase): if self.CDefineNames is not None: self.CDefineNames.clear() if self.CDefineValues is not None: self.CDefineValues.clear() if self.CDefineDoubleFlags is not None: self.CDefineDoubleFlags.clear() - if self.CDefineStrFlags is not None: self.CDefineStrFlags.clear() + if self.CDefineStrFlags is not None: self.CDefineStrFlags.clear() if self.CDefineBits is not None: self.CDefineBits.clear() # Clear index slots (store index+1; 0=empty) and reset Built to 0 (empty table and index # in sync, matching a freshly built table before its first register). diff --git a/App/lib/core/Gen/Type/TypeGenCType.vp b/App/lib/core/Gen/Type/TypeGenCType.vp index 4ff7af4..c26205e 100644 --- a/App/lib/core/Gen/Type/TypeGenCType.vp +++ b/App/lib/core/Gen/Type/TypeGenCType.vp @@ -1,15 +1,9 @@ -import t, c from stdint import * import ast -import mlirlite import memhub import string -import viperlib -import stdio import stdlib import lib.core.VLogger as VLogger -import lib.core.Gen.Translator as HT -import lib.Stub.StubMerger as StubMerger import lib.core.CompilerFactory as CompilerFactory diff --git a/App/lib/core/Gen/Type/TypeGenErr.vp b/App/lib/core/Gen/Type/TypeGenErr.vp index 27dc554..2881b35 100644 --- a/App/lib/core/Gen/Type/TypeGenErr.vp +++ b/App/lib/core/Gen/Type/TypeGenErr.vp @@ -1,6 +1,4 @@ import lib.core.Gen.GenTypes as GenTypes -import lib.core.Gen.Generator as Generator -import t, c from stdint import * import ast import mlirlite @@ -8,13 +6,7 @@ import memhub import string import viperlib import stdio -import stdlib -import sys -import win32.fileio as fileio -import lib.core.VLogger as VLogger import lib.core.Diag as Diag -import lib.Stub.StubMerger as StubMerger -import lib.core.CompilerFactory as CompilerFactory import lib.core.Gen.Translator as HT import lib.core.Gen.Type.TypeGenBase as TypeGenBase @@ -85,14 +77,14 @@ novirtual class TypeGenErr(TypeGenBase.TypeGenBase): Diag.finish() return 0 - # [TEMP-DIAG] 定位“报错位置”问题用(定位完删除):把决策输入打出来 - # node=节点原始行号(0=合成) curarg=当前实参行号 trace=栈深 top=栈最内层行号 - ti_top: int = -1 - if self.Gen.TypeGenBase.TraceCount > 0: - tf_d: GenTypes.TraceFrame* = self.Gen.TypeGenBase._get_trace_frame(self.Gen.TypeGenBase.TraceCount - 1) - if tf_d is not None: ti_top = tf_d.lineno - stdio.printf("[TEMP-DIAG] node=%d curarg=%d trace=%d top=%d -> shown=%d\n", - raw_line, self.Gen.TypeGenBase.CurArgLine, self.Gen.TypeGenBase.TraceCount, ti_top, lineno) + # [TEMP-DIAG] 定位“报错位置”问题用(定位完删除):把决策输入打出来 + # node=节点原始行号(0=合成) curarg=当前实参行号 trace=栈深 top=栈最内层行号 + ti_top: int = -1 + if self.Gen.TypeGenBase.TraceCount > 0: + tf_d: GenTypes.TraceFrame* = self.Gen.TypeGenBase._get_trace_frame(self.Gen.TypeGenBase.TraceCount - 1) + if tf_d is not None: ti_top = tf_d.lineno + stdio.printf("[TEMP-DIAG] node=%d curarg=%d trace=%d top=%d -> shown=%d\n", + raw_line, self.Gen.TypeGenBase.CurArgLine, self.Gen.TypeGenBase.TraceCount, ti_top, lineno) Diag.begin(ent, err_type, msg) # 调用链帧(按"自外向内"顺序)**由本类遍历**(只有它拿得到 TraceFrame),填入 entry。 for i in range(int(self.Gen.TypeGenBase.TraceCount)): diff --git a/App/lib/core/Gen/Type/TypeGenMixin.vp b/App/lib/core/Gen/Type/TypeGenMixin.vp index e1cd8ab..afc2ac5 100644 --- a/App/lib/core/Gen/Type/TypeGenMixin.vp +++ b/App/lib/core/Gen/Type/TypeGenMixin.vp @@ -1,17 +1,4 @@ -import t, c from stdint import * -import ast -import mlirlite -import memhub -import string -import stdio -import sys -import stdlib -import viperlib -import win32.fileio as fileio -import lib.core.CompilerFactory as CompilerFactory -import lib.core.VLogger as VLogger -import lib.core.Gen.Translator as HT import lib.core.Gen.Type.TypeGenBase as TypeGenBase diff --git a/App/lib/core/Gen/Type/TypeGenResolve.vp b/App/lib/core/Gen/Type/TypeGenResolve.vp index 9a681fd..3d9857a 100644 --- a/App/lib/core/Gen/Type/TypeGenResolve.vp +++ b/App/lib/core/Gen/Type/TypeGenResolve.vp @@ -1,9 +1,6 @@ import lib.core.Gen.GenTypes as GenTypes import lib.core.Gen.GenApi as GenApi -import lib.core.Gen.Generator as Generator -import lib.core.Gen.Type.TypeGenCType as TypeGenCType import lib.core.Gen.Type.TypeGenMixin as TypeGenMixin -import t, c from stdint import * import ast import mlirlite @@ -11,21 +8,18 @@ import memhub import hashtable import string import viperlib -import stdio import stdlib import lib.core.VLogger as VLogger import lib.core.Gen.Translator as HT -import lib.Stub.StubMerger as StubMerger import lib.Stub.StubMerger.StubMergerStore as StubMergerStore import lib.Stub.StubGen.VpiReader as VpiReader import lib.core.CompilerFactory as CompilerFactory import lib.Projectrans.Config as Config - import lib.core.Gen.Type.TypeGenBase as TypeGenBase -import lib.core.Gen.Type.TypeGenCDef as TypeGenCDef import win32.fileio as fileio + # ============================================================ # TypeGenResolve - split out of TypeGenMixin (stage D): type mapping / annotation resolution. novirtual class TypeGenResolve(TypeGenBase.TypeGenBase): @@ -1198,10 +1192,10 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase): key_buf[mod_len] = '|' string.strncpy(key_buf + mod_len + 1, attr, attr_len) key_buf[key_len] = '\0' - v: t.CPtr = self.LibTypedefTypeMap.__getitem__(key_buf) + v: rawptr = self.LibTypedefTypeMap.__getitem__(key_buf) stdlib.free(key_buf) if v is None: return None - return t.CPtr(v) + return rawptr(v) def _lookup_library_typedef(self, pool: memhub.MemBuddy*, mod: str, attr: str) -> str: """Look up "attr: t.CTypedef = TYPE" in a library module source, returning TYPE or None.""" if mod is None or attr is None: return None diff --git a/App/lib/core/Gen/Type/TypeSpec.vp b/App/lib/core/Gen/Type/TypeSpec.vp index 2675562..5de4d88 100644 --- a/App/lib/core/Gen/Type/TypeSpec.vp +++ b/App/lib/core/Gen/Type/TypeSpec.vp @@ -1,4 +1,3 @@ -import t, c from stdint import * import mlirlite import memhub @@ -115,8 +114,7 @@ def SpecSignFromTypeName(name: str) -> int: # TypeSpec - type descriptor. PtrLevel alone is ambiguous for Ptr(i8), so element # semantics use the (ElemBits, IsElemPtr, DerefBase) triple replacing IsPtrElement. -@t.NoVTable -class TypeSpec: +novirtual class TypeSpec: """Unified type descriptor""" Kind: int # one of TS_* Bits: int # bit width; 0 for non-int/float @@ -140,8 +138,7 @@ class TypeSpec: # TypeSpecArena - interning table (object-owned, not global): Keys/Specs/Count/Cap. -@t.NoVTable -class TypeSpecArena: +novirtual class TypeSpecArena: """TypeSpec interning table; dedups by canonical text key (one instance per type)""" Keys: bytes Specs: sizet* diff --git a/App/lib/core/Gen/VarGenMixin.vp b/App/lib/core/Gen/VarGenMixin.vp index f418a54..10973d8 100644 --- a/App/lib/core/Gen/VarGenMixin.vp +++ b/App/lib/core/Gen/VarGenMixin.vp @@ -3,7 +3,6 @@ import lib.core.Gen.Generator as Generator import lib.core.Gen.Type.TypeSpec as TSpec from MatchGenMixin import SCOPE_MATCH import lib.core.Gen.Translator as HT -import t, c from stdint import * import ast import mlirlite @@ -934,7 +933,7 @@ novirtual class VarGenMixin: # ---- repl_try_session_func_call - indirect call to a session function (M3 core) ---- # On a hit, load the address from the ctx slot, prepend ctx, coerce args to the table signature, and call_indirect (hit=1). - def repl_try_session_func_call(self, trans: HT.Translator*, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, func_name: str, cargs: list[ast.AST*]*, can: int, kw_count: int, node: ast.AST*, hit: t.CPtr) -> mlirlite.Value*: + def repl_try_session_func_call(self, trans: HT.Translator*, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, mod: mlirlite.LLVMModule*, func_name: str, cargs: list[ast.AST*]*, can: int, kw_count: int, node: ast.AST*, hit: rawptr) -> mlirlite.Value*: """Session function call: return the call result on hit (void returns None but hit is set)""" if trans is None or trans.ReplCtx is None or pool is None or builder is None: return None if func_name is None or hit is None: return None @@ -965,7 +964,7 @@ novirtual class VarGenMixin: self.Gen.TypeGenErr.fatal_error(node, f"REPL: failed to read the address of session function '{func_name}'", "InternalCompilerError") return None # (2) Resolve param types before building the signature (token -> LLVM type; unsupported -> error) - ptypes: t.CPtr = pool.alloc(8 * GenTypes.REPL_FUNC_PARAM_MAX) + ptypes: rawptr = pool.alloc(8 * GenTypes.REPL_FUNC_PARAM_MAX) if ptypes is None: return None string.memset(ptypes, 0, 8 * GenTypes.REPL_FUNC_PARAM_MAX) ai_chk: int @@ -1347,7 +1346,7 @@ novirtual class VarGenMixin: i8_ptr_ty: mlirlite.LLVMType* = mlirlite.Ptr(pool, mlirlite.Int8(pool)) pv: mlirlite.Value* = val if val.Ty is not None and self.Gen.ExprGenBase.is_ptr_type(val.Ty) != 0 and self.Gen.AssignGen._stg_ty_equal(pool, val.Ty, i8_ptr_ty) == 0: - # Skip when already an i8 pointer (str/bytes/t.CPtr) - LLVM rejects same-type bitcast + # Skip when already an i8 pointer (str/bytes/rawptr) - LLVM rejects same-type bitcast pv = mlirlite.build_bitcast(builder, val, i8_ptr_ty) if pv is None: return 1 # Pointer -> i64 (ptrtoint): the host reads it as an integer then inttoptrs it back to an address diff --git a/App/lib/core/IncludesScanner.vp b/App/lib/core/IncludesScanner.vp index bb9b560..fd6a9b4 100644 --- a/App/lib/core/IncludesScanner.vp +++ b/App/lib/core/IncludesScanner.vp @@ -1,8 +1,6 @@ -import t, c from stdint import * import memhub import string -import stdio import stdlib import win32.win32file as win32file import win32.win32base as win32base @@ -11,7 +9,6 @@ import hashlib import viperlib import lib.Projectrans.Utils as Utils import lib.core.VLogger as VLogger -import lib.Projectrans.Config as Config # IncludesScanner - recursive scan of the includes directory (Win32 FindFirstFileA/ @@ -311,8 +308,8 @@ def _PathExistsA(path: str) -> int: # _TryResolveModuleFile - try one candidate path and write outputs (1=hit, 0=miss); -# out_abs_path/out_rel_path/out_inc_dir are t.CPtr output slots. -def _TryResolveModuleFile(inc_dir: str, rel_seg: bytes, rel_len: sizet, suffix: str, out_abs_path: t.CPtr, out_rel_path: t.CPtr, out_inc_dir: t.CPtr) -> int: +# out_abs_path/out_rel_path/out_inc_dir are rawptr output slots. +def _TryResolveModuleFile(inc_dir: str, rel_seg: bytes, rel_len: sizet, suffix: str, out_abs_path: rawptr, out_rel_path: rawptr, out_inc_dir: rawptr) -> int: if inc_dir is None or rel_seg is None or suffix is None: return 0 inc_len: sizet = string.strlen(inc_dir) suf_len: sizet = string.strlen(suffix) @@ -346,7 +343,7 @@ def _TryResolveModuleFile(inc_dir: str, rel_seg: bytes, rel_len: sizet, suffix: return 0 string.strcpy(inc_buf, inc_dir) # Write output slots (stdlib deep copies; caller frees). Slots must be cast to - # (sizet*): t.CPtr* folds to t.CPtr and [0] becomes a 1-byte access. + # (sizet*): rawptr* folds to rawptr and [0] becomes a 1-byte access. if out_abs_path is not None: abs_slot: sizet* = (sizet*)(out_abs_path) abs_slot[0] = sizet(cand) @@ -363,7 +360,7 @@ def _TryResolveModuleFile(inc_dir: str, rel_seg: bytes, rel_len: sizet, suffix: # ResolveModuleToPath - module name -> file path, resolved on demand (no full scan). # Tries each includes dir, preferring file modules over packages. Returns 0 found, 1 not. -def ResolveModuleToPath(includes_dirs: str, mod_name: str, out_abs_path: t.CPtr, out_rel_path: t.CPtr, out_inc_dir: t.CPtr) -> int: +def ResolveModuleToPath(includes_dirs: str, mod_name: str, out_abs_path: rawptr, out_rel_path: rawptr, out_inc_dir: rawptr) -> int: if includes_dirs is None or mod_name is None: return 1 mn_len: sizet = string.strlen(mod_name) if mn_len == 0: return 1 diff --git a/App/lib/core/VLogger.vp b/App/lib/core/VLogger.vp index 0808b2b..57e632b 100644 --- a/App/lib/core/VLogger.vp +++ b/App/lib/core/VLogger.vp @@ -1,7 +1,5 @@ -import t, c from stdint import * import stdio -import stdlib import memhub import sys import win32.win32console as win32cmd @@ -33,7 +31,7 @@ def repl_abort() -> int: return 0 -def set_repl_jmpbuf(buf: t.CPtr) -> int: +def set_repl_jmpbuf(buf: rawptr) -> int: """Register the REPL jmp_buf; idempotent at each fragment entry.""" global _repl_jmpbuf _repl_jmpbuf = buf @@ -196,7 +194,7 @@ log: Logger* def init_logger(): """Initialize the global logger instance.""" global logger, log - raw: t.CPtr = _mbuddy.alloc(Logger.__sizeof__()) + raw: rawptr = _mbuddy.alloc(Logger.__sizeof__()) # if raw is None: return None (memory management still unclear) logger = raw logger.__before_init__() diff --git a/App/lib/core/builtin/ViperBuild.vp b/App/lib/core/builtin/ViperBuild.vp index dd8e4ce..1473566 100644 --- a/App/lib/core/builtin/ViperBuild.vp +++ b/App/lib/core/builtin/ViperBuild.vp @@ -1,12 +1,9 @@ """Compiler-side implementation of the `viperbuild` built-in macro library (--src Pass 0).""" -import t, c from stdint import * from win32.win32base import * import memhub import string -import stdio import stdlib -import viperlib import ast import win32.win32file as win32file import lib.Projectrans.Utils as Utils @@ -796,9 +793,9 @@ def _ResolveModuleToFile(module_name: str) -> str: """Resolve a module name to a local project file path; None if not found.""" if module_name is None or _search_dirs is None: return None if string.strlen(module_name) == 0: return None - out_abs: t.CPtr = stdlib.malloc(8) - out_rel: t.CPtr = stdlib.malloc(8) - out_inc: t.CPtr = stdlib.malloc(8) + out_abs: rawptr = stdlib.malloc(8) + out_rel: rawptr = stdlib.malloc(8) + out_inc: rawptr = stdlib.malloc(8) if out_abs is None or out_rel is None or out_inc is None: if out_abs is not None: stdlib.free(out_abs) if out_rel is not None: stdlib.free(out_rel) diff --git a/App/main.vp b/App/main.vp index 667537e..e515050 100644 --- a/App/main.vp +++ b/App/main.vp @@ -21,7 +21,6 @@ import memhub import argparse import win32.win32console as win32cmd import win32.win32base as win32base -import win32.fileio as fileio import sys import ast import os @@ -31,10 +30,6 @@ import os.path import shutil import mlirlite import subprocess -import viperlib -import t, c -import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild -import lib.Stub.StubMerger.StubMergerCollect as StubMergerCollect import lib.Phase.Phase1.Phase1Main as Phase1Main