基本稳定
This commit is contained in:
1 parent
0a10b20dde
commit
a39b5da0f8
27 files changed
+392
-962
No files matched your search
@@ -17,7 +17,7 @@ from .base import (
|
||||
_init_ast, _copy_str, _set_pos, _inherit_pos, _set_parent_list,
|
||||
_binop_from_op, _augop_from_op, _cmpop_from_op,
|
||||
_emit, _emit_str, _emit_int, _dump_list,
|
||||
dump,
|
||||
dump, _op_name,
|
||||
)
|
||||
# 语句节点
|
||||
from .stmts import (
|
||||
|
||||
@@ -553,6 +553,14 @@ def _read_string(lx: Lexer | t.CPtr):
|
||||
conv_buf[wpos] = '\t'
|
||||
elif next_ch == 'r':
|
||||
conv_buf[wpos] = '\r'
|
||||
elif next_ch == 'f':
|
||||
conv_buf[wpos] = '\f'
|
||||
elif next_ch == 'v':
|
||||
conv_buf[wpos] = '\v'
|
||||
elif next_ch == 'a':
|
||||
conv_buf[wpos] = '\a'
|
||||
elif next_ch == 'b':
|
||||
conv_buf[wpos] = '\b'
|
||||
elif next_ch == '\\':
|
||||
conv_buf[wpos] = '\\'
|
||||
elif next_ch == '\'':
|
||||
|
||||
@@ -154,7 +154,7 @@ def a2b_hex(hexstr: str, length: t.CInt) -> str:
|
||||
out[oi] = '\0'
|
||||
return out
|
||||
|
||||
def unhexlify(data: str, length: t.CInt):
|
||||
def unhexlify(data: str, length: t.CInt) -> bytes:
|
||||
return a2b_hex(data, length)
|
||||
|
||||
def b2a_base64(data: str, length: t.CInt) -> str:
|
||||
|
||||
@@ -504,10 +504,10 @@ def _print_global(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
_append_cstr(buf, size, "global ")
|
||||
|
||||
# 类型
|
||||
ty_buf: t.CChar | t.CPtr = pool.alloc(128)
|
||||
ty_buf: t.CChar | t.CPtr = pool.alloc(512)
|
||||
if ty_buf is not None:
|
||||
ty_buf[0] = '\0'
|
||||
TypePrint(ty_buf, 128, gv.Ty, pool)
|
||||
TypePrint(ty_buf, 512, gv.Ty, pool)
|
||||
_append_cstr(buf, size, ty_buf)
|
||||
|
||||
# 初始化值
|
||||
@@ -541,10 +541,10 @@ def _print_global_stub(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
_append_cstr(buf, size, " = external global ")
|
||||
|
||||
# 类型
|
||||
ty_buf: t.CChar | t.CPtr = pool.alloc(128)
|
||||
ty_buf: t.CChar | t.CPtr = pool.alloc(512)
|
||||
if ty_buf is not None:
|
||||
ty_buf[0] = '\0'
|
||||
TypePrint(ty_buf, 128, gv.Ty, pool)
|
||||
TypePrint(ty_buf, 512, gv.Ty, pool)
|
||||
_append_cstr(buf, size, ty_buf)
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import viperlib
|
||||
import string
|
||||
import memhub
|
||||
import stdio
|
||||
import stdlib
|
||||
from linkedlist import GSListNode
|
||||
|
||||
|
||||
@@ -383,8 +384,23 @@ def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
|
||||
pool 用于递归打印子类型时分配临时缓冲区。
|
||||
"""
|
||||
_TypePrintDepth(buf, size, ty, pool, 0)
|
||||
|
||||
|
||||
# 递归深度上限:悬空/自引用的 LLVMType 树(1b reset 后内存被复用)会导致
|
||||
# Ptr(pointee)/Struct(fields)/Func(params) 无限递归,每次递归分配临时缓冲
|
||||
# 造成 OOM(单文件暴涨 900MB 根因)。超过 100 层即停止打印。
|
||||
TYPEPRINT_MAX_DEPTH: t.CDefine = 100
|
||||
|
||||
def _TypePrintDepth(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
ty: LLVMType | t.CPtr, pool: memhub.MemBuddy | t.CPtr,
|
||||
depth: t.CInt):
|
||||
"""带递归深度上限的 TypePrint 内部实现"""
|
||||
if ty is None or buf is None or size == 0:
|
||||
return
|
||||
if depth >= TYPEPRINT_MAX_DEPTH:
|
||||
viperlib.snprintf(buf, size, "...")
|
||||
return
|
||||
buf[0] = '\0'
|
||||
match ty:
|
||||
case LLVMType.Int(bits):
|
||||
@@ -400,7 +416,10 @@ def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
match pointee:
|
||||
case LLVMType.Struct(sfields, sfcount, sname):
|
||||
if sname is not None:
|
||||
viperlib.snprintf(buf, size, "%%\"%s\"*", sname)
|
||||
# 悬空防护:sname 可能指向被 reset 回收/部分复用的 pool 内存,
|
||||
# 用受限打印避免读越界崩溃;完整名在 vtable 生成后由
|
||||
# TypeStr 兜底(stdlib 深拷贝,跨 reset 存活)
|
||||
viperlib.snprintf(buf, size, "%%\"%.40s\"*", sname)
|
||||
return
|
||||
case LLVMType.Void():
|
||||
# Ptr(Void) → i8*(LLVM IR void* 非法)
|
||||
@@ -419,7 +438,7 @@ def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
string.strcpy(buf, "i8*")
|
||||
return
|
||||
# 通用路径: 递归打印 pointee 后追加 '*'
|
||||
TypePrint(buf, size, pointee, pool)
|
||||
_TypePrintDepth(buf, size, pointee, pool, depth + 1)
|
||||
pos: t.CSizeT = string.strlen(buf)
|
||||
if pos + 1 < size:
|
||||
buf[pos] = '*'
|
||||
@@ -431,7 +450,7 @@ def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
# 嵌套指针/数组更易超过 128,使用 512 字节避免截断
|
||||
tmp: t.CChar | t.CPtr = pool.alloc(512)
|
||||
if tmp is not None:
|
||||
TypePrint(tmp, 512, elem_ty, pool)
|
||||
_TypePrintDepth(tmp, 512, elem_ty, pool, depth + 1)
|
||||
_strappend(buf, size, tmp)
|
||||
_strappend(buf, size, "]")
|
||||
case LLVMType.Struct(fields, fcount, name):
|
||||
@@ -440,20 +459,26 @@ def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
viperlib.snprintf(buf, size, "%%\"%s\"", name)
|
||||
else:
|
||||
# 匿名结构体: {ty1, ty2, ...}
|
||||
_print_struct_body(buf, size, fields, pool)
|
||||
_print_struct_body(buf, size, fields, pool, depth)
|
||||
case LLVMType.Func(ret, params, count):
|
||||
# ret (ty1, ty2, ...)
|
||||
TypePrint(buf, size, ret, pool)
|
||||
_TypePrintDepth(buf, size, ret, pool, depth + 1)
|
||||
_strappend(buf, size, " (")
|
||||
cur2: ParamNode | t.CPtr = params
|
||||
first2: t.CInt = 1
|
||||
_pc2: t.CInt = 0
|
||||
# 函数参数类型可能为 SHA1 限定命名结构体指针,512 字节避免截断
|
||||
tmp3: t.CChar | t.CPtr = pool.alloc(512)
|
||||
while cur2 is not None:
|
||||
# 悬空保护:参数链若被 reset 回收后内容复用,可能成环无限循环
|
||||
_pc2 += 1
|
||||
if _pc2 > 200:
|
||||
_strappend(buf, size, "...)")
|
||||
break
|
||||
if first2 == 0:
|
||||
_strappend(buf, size, ", ")
|
||||
if tmp3 is not None:
|
||||
TypePrint(tmp3, 512, cur2.Ty, pool)
|
||||
_TypePrintDepth(tmp3, 512, cur2.Ty, pool, depth + 1)
|
||||
_strappend(buf, size, tmp3)
|
||||
cur2 = cur2.Next
|
||||
first2 = 0
|
||||
@@ -502,7 +527,8 @@ def _strappend(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr)
|
||||
# 供 TypePrint(匿名结构体)和 PrintStructDefinition(命名结构体定义行)复用
|
||||
# ============================================================
|
||||
def _print_struct_body(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
fields: ParamNode | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
|
||||
fields: ParamNode | t.CPtr, pool: memhub.MemBuddy | t.CPtr,
|
||||
depth: t.CInt = 0):
|
||||
"""打印 {ty1, ty2, ...} 到 buf(追加模式,不覆盖已有内容)
|
||||
|
||||
直接在 buf 当前末尾写入字段类型,避免 pool.alloc 返回与 buf 重叠的内存
|
||||
@@ -515,13 +541,18 @@ def _print_struct_body(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
first: t.CInt = 1
|
||||
fidx: t.CInt = 0
|
||||
while cur is not None:
|
||||
# 悬空保护:ParamNode 链若被 reset 回收后内容复用,Next 指针可能成环或
|
||||
# 指向垃圾,无限循环。最多打印 200 个字段即停止,防止 OOM。
|
||||
if fidx >= 200:
|
||||
_strappend(buf, size, "...}")
|
||||
return
|
||||
if first == 0:
|
||||
_strappend(buf, size, ", ")
|
||||
# 直接在 buf 当前末尾位置写入字段类型
|
||||
# TypePrint 首字节置 '\0' 是无害的(pos 处本来就是 '\0')
|
||||
pos: t.CSizeT = string.strlen(buf)
|
||||
if pos + 2 < size:
|
||||
TypePrint(buf + pos, size - pos, cur.Ty, pool)
|
||||
_TypePrintDepth(buf + pos, size - pos, cur.Ty, pool, depth + 1)
|
||||
cur = cur.Next
|
||||
first = 0
|
||||
fidx += 1
|
||||
@@ -574,4 +605,144 @@ def get_struct_name(ty: LLVMType | t.CPtr) -> t.CChar | t.CPtr:
|
||||
return None
|
||||
|
||||
|
||||
def get_struct_fields(ty: LLVMType | t.CPtr) -> ParamNode | t.CPtr:
|
||||
"""获取结构体的字段链表(供跨模块重建 Struct 类型用)"""
|
||||
if ty is None:
|
||||
return None
|
||||
match ty:
|
||||
case LLVMType.Struct(fields, fcount, name):
|
||||
return fields
|
||||
case _:
|
||||
return None
|
||||
|
||||
|
||||
def get_struct_fcount(ty: LLVMType | t.CPtr) -> t.CInt:
|
||||
"""获取结构体的字段数量(供跨模块重建 Struct 类型用)"""
|
||||
if ty is None:
|
||||
return 0
|
||||
match ty:
|
||||
case LLVMType.Struct(fields, fcount, name):
|
||||
return fcount
|
||||
case _:
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# DeepCopyType - 深拷贝 LLVMType 到 stdlib 区(跨文件 reset 存活)
|
||||
#
|
||||
# 背景: 1b 阶段(mark1 之后)新注册的结构体(泛型特化类等),其
|
||||
# struct_ty 是 pool 分配的 LLVMType,所在文件翻译完 reset_to(mark1)
|
||||
# 后指针悬空。_struct_table 中的 entry.Ty 指向它,后续文件遍历
|
||||
# _struct_table(find_struct_by_type/lookup_field 等)时解引用悬空
|
||||
# 指针导致崩溃(0xC0000005)。
|
||||
#
|
||||
# 本函数递归拷贝整棵 LLVMType 树到 stdlib(含 ParamNode 字段链和
|
||||
# 字符串名),保证 entry.Ty 跨文件永久存活。
|
||||
#
|
||||
# 注意: 自引用类型(如 Value 含 Ptr(Value) 字段)会导致无限递归,
|
||||
# 用深度上限防护(超过即返回浅拷贝副本,后续不再递归)。
|
||||
# ============================================================
|
||||
DEEPCOPY_MAX_DEPTH: t.CDefine = 64
|
||||
|
||||
def DeepCopyType(pool: memhub.MemBuddy | t.CPtr,
|
||||
ty: LLVMType | t.CPtr) -> LLVMType | t.CPtr:
|
||||
"""深拷贝 LLVMType 到 stdlib 区(深度限制防自引用递归),失败返回 None"""
|
||||
return _DeepCopyDepth(pool, ty, 0)
|
||||
|
||||
|
||||
def _DeepCopyDepth(pool: memhub.MemBuddy | t.CPtr,
|
||||
ty: LLVMType | t.CPtr, depth: t.CInt) -> LLVMType | t.CPtr:
|
||||
"""带深度上限的深拷贝实现"""
|
||||
if ty is None:
|
||||
return None
|
||||
new_ty: LLVMType | t.CPtr = (LLVMType | t.CPtr)(stdlib.malloc(LLVMType.__sizeof__()))
|
||||
if new_ty is None:
|
||||
return None
|
||||
string.memset(new_ty, 0, LLVMType.__sizeof__())
|
||||
if depth >= DEEPCOPY_MAX_DEPTH:
|
||||
# 深度超限:浅拷贝 tag 后停止递归(复制当前变体但不深拷子类型)
|
||||
match ty:
|
||||
case LLVMType.Int(bits):
|
||||
c.DerefAs(new_ty, LLVMType.Int(bits))
|
||||
case LLVMType.Float(bits):
|
||||
c.DerefAs(new_ty, LLVMType.Float(bits))
|
||||
case LLVMType.Void():
|
||||
c.DerefAs(new_ty, LLVMType.Void())
|
||||
case LLVMType.Label():
|
||||
c.DerefAs(new_ty, LLVMType.Label())
|
||||
case LLVMType.Metadata():
|
||||
c.DerefAs(new_ty, LLVMType.Metadata())
|
||||
case _:
|
||||
c.DerefAs(new_ty, LLVMType.Void())
|
||||
return new_ty
|
||||
match ty:
|
||||
case LLVMType.Int(bits):
|
||||
c.DerefAs(new_ty, LLVMType.Int(bits))
|
||||
case LLVMType.Float(bits):
|
||||
c.DerefAs(new_ty, LLVMType.Float(bits))
|
||||
case LLVMType.Void():
|
||||
c.DerefAs(new_ty, LLVMType.Void())
|
||||
case LLVMType.Label():
|
||||
c.DerefAs(new_ty, LLVMType.Label())
|
||||
case LLVMType.Metadata():
|
||||
c.DerefAs(new_ty, LLVMType.Metadata())
|
||||
case LLVMType.Ptr(pointee):
|
||||
c.DerefAs(new_ty, LLVMType.Ptr(_DeepCopyDepth(pool, pointee, depth + 1)))
|
||||
case LLVMType.Array(elem_ty, count):
|
||||
c.DerefAs(new_ty, LLVMType.Array(_DeepCopyDepth(pool, elem_ty, depth + 1), count))
|
||||
case LLVMType.Func(ret, params, pcount):
|
||||
c.DerefAs(new_ty, LLVMType.Func(
|
||||
_DeepCopyDepth(pool, ret, depth + 1),
|
||||
_DeepCopyParamChain(pool, params, depth + 1), pcount))
|
||||
case LLVMType.Struct(fields, fcount, name):
|
||||
c.DerefAs(new_ty, LLVMType.Struct(
|
||||
_DeepCopyParamChain(pool, fields, depth + 1),
|
||||
fcount, _DeepCopyStr(pool, name)))
|
||||
case _:
|
||||
stdlib.free(new_ty)
|
||||
return None
|
||||
return new_ty
|
||||
|
||||
|
||||
def _DeepCopyParamChain(pool: memhub.MemBuddy | t.CPtr,
|
||||
head: ParamNode | t.CPtr, depth: t.CInt) -> ParamNode | t.CPtr:
|
||||
"""深拷贝 ParamNode 链表到 stdlib"""
|
||||
if head is None:
|
||||
return None
|
||||
first: ParamNode | t.CPtr = None
|
||||
prev: ParamNode | t.CPtr = None
|
||||
cur: ParamNode | t.CPtr = head
|
||||
guard: t.CInt = 0
|
||||
while cur is not None:
|
||||
guard += 1
|
||||
if guard > 512:
|
||||
break
|
||||
node: ParamNode | t.CPtr = (ParamNode | t.CPtr)(stdlib.malloc(PNODE_SIZE))
|
||||
if node is None:
|
||||
break
|
||||
string.memset(node, 0, PNODE_SIZE)
|
||||
node.Ty = _DeepCopyDepth(pool, paramnode_get_ty(cur), depth + 1)
|
||||
node.Next = None
|
||||
if first is None:
|
||||
first = node
|
||||
if prev is not None:
|
||||
prev.Next = node
|
||||
prev = node
|
||||
cur = paramnode_get_next(cur)
|
||||
return first
|
||||
|
||||
|
||||
def _DeepCopyStr(pool: memhub.MemBuddy | t.CPtr, s: t.CChar | t.CPtr) -> t.CChar | t.CPtr:
|
||||
"""深拷贝字符串到 stdlib"""
|
||||
if s is None:
|
||||
return None
|
||||
slen: t.CSizeT = string.strlen(s)
|
||||
copy: t.CChar | t.CPtr = stdlib.malloc(slen + 1)
|
||||
if copy is None:
|
||||
return None
|
||||
string.strcpy(copy, s)
|
||||
return copy
|
||||
|
||||
|
||||
|
||||
|
||||
+116
-6
@@ -4,7 +4,7 @@ import string
|
||||
import atom
|
||||
import viperio
|
||||
import stdio
|
||||
import sys
|
||||
import stdlib
|
||||
|
||||
# ============================================================
|
||||
# memhub - Unified memory management library
|
||||
@@ -26,7 +26,6 @@ MEMBUDDY_MIN_BLOCK: t.CDefine = 32
|
||||
MEMBUDDY_MAX_ORDERS: t.CDefine = 32
|
||||
MEMBUDDY_HEADER_SIZE: t.CDefine = 8
|
||||
|
||||
|
||||
def _align_up(val: t.CSizeT, align: t.CSizeT) -> t.CSizeT:
|
||||
if align == 0: return val
|
||||
return (val + align - 1) & ~(align - 1)
|
||||
@@ -134,7 +133,13 @@ class MemPool(MemManager):
|
||||
def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr:
|
||||
if size == 0: return None
|
||||
aligned: t.CSizeT = _align_up(size, MEMHUB_ALIGN)
|
||||
if self.offset + aligned > self.size: return None
|
||||
if self.offset + aligned > self.size:
|
||||
stdio.printf("\n[OOM] 内存不足 (Out of Memory)\n")
|
||||
stdio.printf("[OOM] 尝试分配: %zu 字节,失败\n", size)
|
||||
stdio.printf("[OOM] MemPool: total=%zu used=%zu (bump allocator, 无释放)\n",
|
||||
self.size, self.offset)
|
||||
stdio.printf("[OOM] 说明: 内存池已耗尽。可能原因: (1) 池大小不足,需增大 POOL_SIZE; (2) 存在内存泄漏。\n")
|
||||
stdlib.exit(1)
|
||||
ptr: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(self.base) + self.offset, t.CPtr)
|
||||
self.offset += aligned
|
||||
if self.offset > self.high_water:
|
||||
@@ -211,8 +216,18 @@ class MemSlab(MemManager):
|
||||
|
||||
def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr:
|
||||
# Slab mode: allocate one block only if requested size <= block_size
|
||||
if self.free_list is None: return None
|
||||
if size > self.block_size: return None
|
||||
if self.free_list is None:
|
||||
stdio.printf("\n[OOM] 内存不足 (Out of Memory)\n")
|
||||
stdio.printf("[OOM] 尝试分配: %zu 字节,失败(free_list 已空)\n", size)
|
||||
stdio.printf("[OOM] MemSlab: block_size=%zu block_count=%zu used=%zu\n",
|
||||
self.block_size, self.block_count, self.used_count)
|
||||
stdio.printf("[OOM] 说明: 内存池已耗尽。可能原因: (1) 池大小不足,需增大 POOL_SIZE; (2) 存在内存泄漏。\n")
|
||||
stdlib.exit(1)
|
||||
if size > self.block_size:
|
||||
stdio.printf("\n[OOM] 内存不足 (Out of Memory)\n")
|
||||
stdio.printf("[OOM] 尝试分配: %zu 字节,失败(超过 block_size=%zu)\n", size, self.block_size)
|
||||
stdio.printf("[OOM] 说明: 请求大小超过 MemSlab 块大小,应改用 MemBuddy/MemPool。\n")
|
||||
stdlib.exit(1)
|
||||
block: t.CVoid | t.CPtr = self.free_list
|
||||
self.free_list = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr)
|
||||
self.used_count += 1
|
||||
@@ -254,6 +269,11 @@ class MemSlab(MemManager):
|
||||
# MemBuddy - Buddy system allocator
|
||||
# Free list head array stored at arena start; subsequent memory managed in power-of-two sized blocks
|
||||
# Thread-safe (spinlock enabled), supports block coalescing
|
||||
#
|
||||
# Checkpoint 支持(供编译器等长任务回收阶段性分配):
|
||||
# mark() → 返回当前分配水位(不分配内存)
|
||||
# reset_to(m) → 释放水位 m 之后分配的所有块(回收到 free list)
|
||||
# 记录栈从 usable 顶部预留 _CHK_RESERVE 字节,不参与 buddy 分配。
|
||||
# ============================================================
|
||||
class MemBuddy(MemManager):
|
||||
# Override parent __provides__: MemBuddy provides both __mbuddy__ and __memmgr__.
|
||||
@@ -265,6 +285,10 @@ class MemBuddy(MemManager):
|
||||
lock_val: t.CVolatile | t.CInt # Spinlock
|
||||
usable: t.CVoid | t.CPtr # Start of usable memory region (skips free_lists)
|
||||
usable_size: t.CSizeT # Size of usable memory (power of two)
|
||||
chk_stack: t.CUInt64T | t.CPtr # Checkpoint 分配记录栈(存 block 地址)
|
||||
chk_cap: t.CSizeT # 记录栈容量(条目数)
|
||||
chk_depth: t.CSizeT # 当前记录深度
|
||||
chk_base: t.CVoid | t.CPtr # 记录栈起始地址(由 stdlib.malloc 分配,独立于 buddy 区)
|
||||
|
||||
def __init__(self, base: t.CVoid | t.CPtr, size: t.CSizeT):
|
||||
self.base = base
|
||||
@@ -274,6 +298,10 @@ class MemBuddy(MemManager):
|
||||
self.lock_val = 0
|
||||
self.usable = None
|
||||
self.usable_size = 0
|
||||
self.chk_stack = None
|
||||
self.chk_cap = 0
|
||||
self.chk_depth = 0
|
||||
self.chk_base = None
|
||||
|
||||
self.lock_val = 0
|
||||
fl_bytes: t.CSizeT = (MEMBUDDY_MAX_ORDERS + 1) * 8
|
||||
@@ -291,6 +319,12 @@ class MemBuddy(MemManager):
|
||||
return
|
||||
|
||||
remaining: t.CSizeT = size - fl_bytes
|
||||
|
||||
# 注意:不能在 __init__ 里预留 checkpoint 记录栈!
|
||||
# buddy 区必须从 fl_bytes 后开始、大小必须是 2 的幂。
|
||||
# 若预留 512KB,remaining = 2^30 - 512KB 不是 2 的幂,
|
||||
# _largest_pow2_le 会取到 2^29 = 512MB,1GB 池直接砍半。
|
||||
# 记录栈改为 mark() 时从 buddy 池懒分配(见 mark())。
|
||||
usable: t.CSizeT = _largest_pow2_le(remaining)
|
||||
|
||||
if usable < MEMBUDDY_MIN_BLOCK:
|
||||
@@ -312,6 +346,60 @@ class MemBuddy(MemManager):
|
||||
# Entire usable memory region as a max_order free block
|
||||
self._fl_push(self.max_order, self.usable)
|
||||
|
||||
# === Checkpoint support ===
|
||||
|
||||
def mark(self) -> t.CSizeT:
|
||||
"""返回当前分配水位(checkpoint)
|
||||
|
||||
记录栈用 stdlib.malloc 分配(64K 条目 × 8B = 512KB,独立于 buddy 区),
|
||||
首次调用时懒分配。这样不占用 buddy 池、不会把 1GB 池砍半、
|
||||
reset_to 也不会误释放栈自身。
|
||||
"""
|
||||
if self.chk_stack is None:
|
||||
# 记录栈用 stdlib.malloc 分配(独立于 buddy 区,避免占用 buddy 池、
|
||||
# 避免 reset_to 误释放栈自身,也避免栈内存与 buddy 块重叠)。
|
||||
cap: t.CSizeT = 64 * 1024
|
||||
base: t.CVoid | t.CPtr = t.CVoid(stdlib.malloc(cap * 8), t.CPtr)
|
||||
if base is None:
|
||||
return 0
|
||||
self.chk_base = base
|
||||
self.chk_stack = (t.CUInt64T | t.CPtr)(t.CVoid(base, t.CPtr))
|
||||
self.chk_cap = cap
|
||||
self.chk_depth = 0
|
||||
return self.chk_depth
|
||||
|
||||
def reset_to(self, mark: t.CSizeT):
|
||||
"""释放水位 mark 之后分配的所有块,回收到 free list
|
||||
|
||||
栈中每个 block:若 header 仍标记为已分配(奇数),_coalesce 归还;
|
||||
若已被单独 free(header==0),跳过避免重复归还。
|
||||
"""
|
||||
if self.chk_stack is None:
|
||||
return
|
||||
if mark >= self.chk_depth:
|
||||
return
|
||||
self._lock()
|
||||
while self.chk_depth > mark:
|
||||
self.chk_depth -= 1
|
||||
block: t.CVoid | t.CPtr = t.CVoid(self.chk_stack[self.chk_depth], t.CPtr)
|
||||
if block is None:
|
||||
continue
|
||||
stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr)
|
||||
stored_val: t.CUInt64T = t.CUInt64T(stored)
|
||||
if (stored_val & 1) == 0:
|
||||
continue # 已被单独 free,跳过
|
||||
order: t.CInt = t.CInt(stored_val >> 1)
|
||||
if order < 0 or order > self.max_order:
|
||||
continue
|
||||
self._coalesce(block, order)
|
||||
self._unlock()
|
||||
|
||||
def reset_all(self):
|
||||
"""回收全部已分配块(等价 reset_to(0))"""
|
||||
if self.chk_stack is None:
|
||||
return
|
||||
self.reset_to(0)
|
||||
|
||||
# === Free list operations ===
|
||||
|
||||
def _fl_push(self, order: t.CInt, block: t.CVoid | t.CPtr):
|
||||
@@ -405,6 +493,24 @@ class MemBuddy(MemManager):
|
||||
order: t.CInt = t.CInt(stored_val >> 1)
|
||||
if order < 0: return 0
|
||||
if order > self.max_order: return 0
|
||||
# 记录栈一致性校验:分配时(alloc)每个 block 地址都会压入 chk_stack。
|
||||
# reset_to(mark) 会把 [mark, chk_depth) 的块弹栈并归还 free list,
|
||||
# 之后这些地址会被重新分配。若一个 header 恰好是合法奇数(假阳性),
|
||||
# 但地址不在当前 chk_stack[0..chk_depth) 存活区间内,说明已被回收,
|
||||
# 不能当作有效指针(否则 _format_func_type_str/TypePrint 会沿垃圾链
|
||||
# 无限分配导致 OOM)。
|
||||
# 注意:chk_stack 容量满(64K)后 alloc 不再记录新块(chk_depth==chk_cap),
|
||||
# 此时无法区分,跳过校验(退化到仅 header 校验,避免误判正常 free)。
|
||||
if self.chk_stack is not None and self.chk_depth < self.chk_cap:
|
||||
alive: t.CInt = 0
|
||||
ci: t.CSizeT = 0
|
||||
while ci < self.chk_depth:
|
||||
if self.chk_stack[ci] == t.CUInt64T(block):
|
||||
alive = 1
|
||||
break
|
||||
ci += 1
|
||||
if alive == 0:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
# === Spinlock ===
|
||||
@@ -430,6 +536,10 @@ class MemBuddy(MemManager):
|
||||
if block is not None:
|
||||
c.DerefAs(block, t.CVoid(t.CUInt64T((order << 1) | 1), t.CPtr))
|
||||
result = t.CVoid(t.CUInt64T(block) + MEMBUDDY_HEADER_SIZE, t.CPtr)
|
||||
# 记录到 checkpoint 栈(供 reset_to 回收)
|
||||
if self.chk_stack is not None and self.chk_depth < self.chk_cap:
|
||||
self.chk_stack[self.chk_depth] = t.CUInt64T(block)
|
||||
self.chk_depth += 1
|
||||
if result is None:
|
||||
# Allocation failure: print memory usage statistics and exit with OOM
|
||||
fb: t.CSizeT = self.free_bytes()
|
||||
@@ -439,7 +549,7 @@ class MemBuddy(MemManager):
|
||||
stdio.printf("[OOM] 内存池: total=%zu used=%zu free=%zu free_blocks=%zu\n",
|
||||
self.usable_size, ub, fb, self.free_count())
|
||||
stdio.printf("[OOM] 说明: 内存池已耗尽。可能原因: (1) 池大小不足,需增大 POOL_SIZE; (2) 存在内存泄漏。\n")
|
||||
sys.exit(1)
|
||||
stdlib.exit(1)
|
||||
self._unlock()
|
||||
return result
|
||||
|
||||
|
||||
+21
-20
@@ -7,106 +7,107 @@ import os._win32
|
||||
import os._posix
|
||||
|
||||
|
||||
# os 包入口
|
||||
# 根据 platmacro.IS_WINDOWS 分派到 _win32 或 _posix 后端
|
||||
# os.path 为跨平台纯字符串操作,直接可用
|
||||
# os package entry point
|
||||
# Dispatches to _win32 or _posix backend based on platmacro.IS_WINDOWS
|
||||
# os.path is for cross-platform pure string operations, can be used directly
|
||||
|
||||
# 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化)
|
||||
# Module-level global MBuddy pointer (initialized by the user in main)
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 文件/目录属性查询
|
||||
# File/Directory Attribute Query
|
||||
# =============================================================================
|
||||
|
||||
def exists(path: str) -> bool:
|
||||
"""检查文件/目录是否存在"""
|
||||
"""Check if the file/directory exists"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.exists(path)
|
||||
return os._posix.exists(path)
|
||||
|
||||
|
||||
def isdir(path: str) -> bool:
|
||||
"""检查路径是否为目录"""
|
||||
"""Check if the path is a directory"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.isdir(path)
|
||||
return os._posix.isdir(path)
|
||||
|
||||
|
||||
def isfile(path: str) -> bool:
|
||||
"""检查路径是否为普通文件"""
|
||||
"""Check if the path is a regular file"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.isfile(path)
|
||||
return os._posix.isfile(path)
|
||||
|
||||
|
||||
def getsize(path: str) -> t.CInt64T:
|
||||
"""返回文件大小(字节)。失败返回 -1。"""
|
||||
"""Returns the file size (in bytes). Returns -1 on failure."""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.getsize(path)
|
||||
return os._posix.getsize(path)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 工作目录
|
||||
# Working Directory
|
||||
# =============================================================================
|
||||
|
||||
def getcwd() -> str:
|
||||
"""返回当前工作目录(通过 _mbuddy 分配内存)"""
|
||||
"""Return the current working directory (memory allocated via _mbuddy)"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.getcwd()
|
||||
return os._posix.getcwd_impl()
|
||||
|
||||
|
||||
def chdir(path: str) -> int:
|
||||
"""切换当前工作目录。成功返回 0,失败返回 -1。"""
|
||||
"""Switch the current working directory. Returns 0 if successful, -1 if it fails."""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.chdir(path)
|
||||
return os._posix.chdir_impl(path)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 文件/目录操作
|
||||
# File/Directory Operations
|
||||
# =============================================================================
|
||||
|
||||
def mkdir(path: str) -> int:
|
||||
"""创建目录。成功返回 0,失败返回 -1。"""
|
||||
"""Create a directory. Returns 0 on success, -1 on failure."""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.mkdir(path)
|
||||
return os._posix.mkdir_impl(path)
|
||||
|
||||
|
||||
def remove(path: str) -> int:
|
||||
"""删除文件。成功返回 0,失败返回 -1。"""
|
||||
"""Delete the file. Returns 0 if successful, -1 if it fails."""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.remove(path)
|
||||
return os._posix.remove(path)
|
||||
|
||||
|
||||
def rmdir(path: str) -> int:
|
||||
"""删除空目录。成功返回 0,失败返回 -1。"""
|
||||
"""Delete empty directories. Returns 0 if successful, -1 if it fails."""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.rmdir(path)
|
||||
return os._posix.rmdir_impl(path)
|
||||
|
||||
|
||||
def rename(old_path: str, new_path: str) -> int:
|
||||
"""重命名/移动文件或目录。成功返回 0,失败返回 -1。"""
|
||||
"""Rename/move a file or directory. Returns 0 on success, -1 on failure."""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.rename(old_path, new_path)
|
||||
return os._posix.rename_impl(old_path, new_path)
|
||||
|
||||
|
||||
def chmod(path: str, mode: int) -> int:
|
||||
"""修改文件权限。成功返回 0,失败返回 -1。
|
||||
Windows 上只处理只读位(S_IWUSR);POSIX 上使用完整权限位。"""
|
||||
"""Modify file permissions. Returns 0 on success, -1 on failure.
|
||||
On Windows, only the read-only bit (S_IWUSR) is handled;
|
||||
On POSIX, full permission bits are used."""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.chmod(path, mode)
|
||||
return os._posix.chmod_impl(path, mode)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 目录列举
|
||||
# Table of Contents Listing
|
||||
# =============================================================================
|
||||
|
||||
def listdir(path: str, out_names: str, max_count: ULONG) -> ULONG:
|
||||
|
||||
+1
-1
@@ -193,7 +193,7 @@ def _rmtree_posix(path: str) -> int:
|
||||
|
||||
path_len: t.CSizeT = len(path)
|
||||
result: int = 0
|
||||
entry: posix.Dirent = posix.readdir(dirp)
|
||||
entry: posix.Dirent | t.CPtr = posix.readdir(dirp)
|
||||
while entry != None:
|
||||
name: str = entry.d_name
|
||||
# Skip . and ..
|
||||
|
||||
+2
-1
@@ -6,4 +6,5 @@ def malloc(size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass
|
||||
def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass
|
||||
def realloc(p: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass
|
||||
def free(p: t.CVoid | t.CPtr) -> t.State: pass
|
||||
def system(cmd: t.CConst | t.CChar | t.CPtr) -> INT | t.State: pass
|
||||
def system(cmd: t.CConst | t.CChar | t.CPtr) -> INT | t.State: pass
|
||||
def exit(status: int) -> t.State: pass
|
||||
@@ -385,5 +385,5 @@ class FileW:
|
||||
def open(filename: str, mode: ULONG, share: ULONG = SHARE_READ) -> File | t.CPtr:
|
||||
return File(filename, mode, share)
|
||||
|
||||
def openw(filename: LPCWSTR, mode: ULONG, share: ULONG = SHARE_READ) -> FileW | t.CPtr:
|
||||
def openw(filename: w32.win32base.LPCWSTR, mode: ULONG, share: ULONG = SHARE_READ) -> FileW | t.CPtr:
|
||||
return FileW(filename, mode, share)
|
||||
@@ -1,3 +1,5 @@
|
||||
# from string import memset, memcpy
|
||||
# from stdio import malloc, free, calloc, realloc
|
||||
from stdint import *
|
||||
import zlib.zdeflate as zdeflate
|
||||
import zlib.zinflate as zinflate
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from stdint import *
|
||||
import stddef
|
||||
import string
|
||||
import stdlib
|
||||
import memhub
|
||||
|
||||
Reference in new issue
Block a user