WIP 快照:includes 现有改动(含 M2.4 new 描述符的语法支持)
语法侧(M2.4):ast/base.vp 枚举尾部追加 ASTKind.New;ast/exprs.vp 新增 NEW_SRC_*/NEW_LIFE_* 与 class New;ast/parser.vp 新增 _is_new_expr/_parse_new_expr(new 为软关键字,不进 Keyword 表,new=1/new.x/new(1) 仍是标识符);ast/__init__.vp 再导出 New 与常量。 其余为既有 WIP 改动一并快照,保持基线一致(39 文件,+312/-237)。 未纳入:ctraits.vpi(已删除)、ctraits.vpnci、tomllib/(均未跟踪)。
This commit is contained in:
1 parent
e3cdb190dc
commit
e25e8958f0
39 files changed
+312
-237
No files matched your search
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
import memhub
|
||||
import string
|
||||
import json
|
||||
@@ -28,7 +27,7 @@ class dict:
|
||||
mb: memhub.MemBuddy = memhub.MemBuddy(arena, arena_size)
|
||||
d: dict = dict(mb)
|
||||
d.set_int("x", 42)
|
||||
p: t.CPtr = d["x"]
|
||||
p: rawptr = d["x"]
|
||||
v: int = c.Deref((int*)(p)) # int value stored as i32; read it back with an int* view
|
||||
|
||||
# Nested dict
|
||||
@@ -82,7 +81,7 @@ class dict:
|
||||
Use typed methods such as set_int / set_str for persistent storage."""
|
||||
self._set_variant_raw(key, VARIANT_PTR, val)
|
||||
|
||||
def _set_variant_raw(self, key: str, vtype: int, ptr: t.CPtr):
|
||||
def _set_variant_raw(self, key: str, vtype: int, ptr: rawptr):
|
||||
"""Internal method: store Variant entry (vtype + ptr). No automatic address resolution."""
|
||||
idx: sizet = self._find(key)
|
||||
if idx < self.__count__:
|
||||
@@ -143,7 +142,7 @@ class dict:
|
||||
"""Store nested dictionary pointer (VARIANT_DICT)."""
|
||||
self._set_variant_raw(key, VARIANT_DICT, val)
|
||||
|
||||
def set_list(self, key: str, val: t.CPtr):
|
||||
def set_list(self, key: str, val: rawptr):
|
||||
"""Store nested list pointer (VARIANT_LIST)."""
|
||||
self._set_variant_raw(key, VARIANT_LIST, val)
|
||||
|
||||
@@ -166,7 +165,7 @@ class dict:
|
||||
vtype_ptr: int* = int*(self.__values__ + idx * _VARIANT_SIZE)
|
||||
return vtype_ptr[0]
|
||||
|
||||
def get(self, key: str, default: t.CPtr) -> t.CPtr:
|
||||
def get(self, key: str, default: rawptr) -> rawptr:
|
||||
"""Return value pointer; return default pointer if key does not exist."""
|
||||
idx: sizet = self._find(key)
|
||||
if idx >= self.__count__:
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import t
|
||||
|
||||
|
||||
# Variant type tags (fixed enumeration + custom pointer type)
|
||||
define VARIANT_NONE = 0 # Untyped / null value
|
||||
define VARIANT_INT = 1 # int (i64)
|
||||
|
||||
+6
-6
@@ -1,4 +1,4 @@
|
||||
import t, c
|
||||
import t
|
||||
import string
|
||||
import memhub
|
||||
import stdio
|
||||
@@ -90,14 +90,14 @@ class ParsedArgs:
|
||||
if self._ht.__contains__(name) == 0:
|
||||
return 0
|
||||
ptr: t.CPtr = self._ht[name]
|
||||
return c.Deref(int(uint64(ptr), t.CPtr))
|
||||
return *(int*(ptr))
|
||||
|
||||
def get_bool(self, name: str) -> bool:
|
||||
"""Fetch boolean value. Returns false if key not found."""
|
||||
if self._ht.__contains__(name) == 0:
|
||||
return False
|
||||
ptr: t.CPtr = self._ht[name]
|
||||
return c.Deref(int(uint64(ptr), t.CPtr)) != 0
|
||||
ptr: rawptr = self._ht[name]
|
||||
return *(int*(ptr)) != 0
|
||||
|
||||
def has(self, name: str) -> bool:
|
||||
"""Check whether specified key exists."""
|
||||
@@ -128,11 +128,11 @@ class ArgumentParser:
|
||||
__mbuddy__: memhub.MemBuddy*
|
||||
|
||||
def __new__(self, prog: str = "", description: str = "",
|
||||
pool: memhub.MemBuddy* = None) -> t.CPtr:
|
||||
pool: memhub.MemBuddy* = None) -> rawptr:
|
||||
mb: memhub.MemBuddy* = pool
|
||||
if mb is None:
|
||||
mb = _mbuddy
|
||||
ret: t.CPtr = mb.alloc(40)
|
||||
ret: rawptr = mb.alloc(40)
|
||||
return ret
|
||||
|
||||
def __init__(self, prog: str = "", description: str = "",
|
||||
|
||||
+5
-2
@@ -1,7 +1,6 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
|
||||
|
||||
# Import submodule
|
||||
from .tokens import (
|
||||
@@ -37,6 +36,10 @@ from .exprs import (
|
||||
Constant, NamedExpr, Attribute, Subscript, Starred, Name,
|
||||
List, Tuple, Slice,
|
||||
Call, Compare, OpNode,
|
||||
# M2.4 `new` 描述符分配节点与描述符常量
|
||||
New,
|
||||
NEW_SRC_DEFAULT, NEW_SRC_STACK, NEW_SRC_HEAP, NEW_SRC_MEMGR,
|
||||
NEW_LIFE_DEFAULT, NEW_LIFE_SLIFE, NEW_LIFE_HLIFE,
|
||||
|
||||
name_get_id, constant_get_str_val,
|
||||
binop_get_left, binop_get_right,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
|
||||
+2
-1
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
@@ -44,6 +43,8 @@ enum ASTKind:
|
||||
MatchClass, MatchStar, MatchAs, MatchOr
|
||||
# Soft keyword statement (appended last to keep existing enum values unchanged)
|
||||
FallThrough
|
||||
# `new` 描述符分配表达式(M2.4;同样只在枚举尾部追加,既有取值不变)
|
||||
New
|
||||
|
||||
|
||||
# ============================================================
|
||||
|
||||
+69
-2
@@ -1,8 +1,6 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
from .base import (
|
||||
AST, ExprNode, ASTKind, ASTCtx, OpKind,
|
||||
_init_ast, _copy_str, _set_parent_list,
|
||||
@@ -326,6 +324,75 @@ class Call(ExprNode):
|
||||
return pos
|
||||
|
||||
|
||||
# ============================================================
|
||||
# New Node(M2.4:`new` 描述符分配)
|
||||
# ============================================================
|
||||
# 两条正交轴,各取其一;顺序无关;重复/冲突在解析期即报错。
|
||||
# 来源 SourceKind:缺省 = heap(D3)
|
||||
define NEW_SRC_DEFAULT = 0
|
||||
define NEW_SRC_STACK = 1
|
||||
define NEW_SRC_HEAP = 2
|
||||
define NEW_SRC_MEMGR = 3
|
||||
# 生命期 LifeKind:缺省由来源决定(stack→slife,heap/memgr→hlife)
|
||||
define NEW_LIFE_DEFAULT = 0
|
||||
define NEW_LIFE_SLIFE = 1
|
||||
define NEW_LIFE_HLIFE = 2
|
||||
|
||||
|
||||
class New(ExprNode):
|
||||
"""New(Source: CInt, Life: CInt, memgr: AST | CPtr, func: AST, args: list[AST | CPtr])"""
|
||||
Source: int # SourceKind(NEW_SRC_*)
|
||||
Life: int # LifeKind(NEW_LIFE_*)
|
||||
memgr: AST* # `memgr(x)` 的 x;无 memgr 描述符时为 None
|
||||
func: AST* # 被构造的类型/可调用(`new ... T(args)` 里的 T)
|
||||
args: list[AST*]*
|
||||
|
||||
def __new__(self, pool: memhub.MemManager*,
|
||||
Source: int,
|
||||
Life: int,
|
||||
memgr: AST*,
|
||||
func: AST*,
|
||||
args: list[AST*]*):
|
||||
ptr: New* = pool.alloc(New.__sizeof__())
|
||||
if ptr: string.memset(ptr, 0, New.__sizeof__())
|
||||
return ptr
|
||||
|
||||
def __init__(self, pool: memhub.MemManager*,
|
||||
Source: int,
|
||||
Life: int,
|
||||
memgr: AST*,
|
||||
func: AST*,
|
||||
args: list[AST*]*):
|
||||
_init_ast(self, pool, 0, 0)
|
||||
self.Source = Source
|
||||
self.Life = Life
|
||||
self.memgr = memgr
|
||||
self.func = func
|
||||
self.args = args
|
||||
_set_parent_list(args, self)
|
||||
|
||||
def kind(self) -> int:
|
||||
return ASTKind.New
|
||||
|
||||
def type_name(self) -> str:
|
||||
return "New"
|
||||
|
||||
def dump(self, buf: str, size: sizet, pos: sizet) -> sizet:
|
||||
pos = _emit(buf, size, pos, "New(")
|
||||
if self.memgr is not None:
|
||||
pos = _emit(buf, size, pos, ", memgr=")
|
||||
pos = self.memgr.dump(buf, size, pos)
|
||||
pos = _emit(buf, size, pos, ", func=")
|
||||
if self.func is not None:
|
||||
pos = self.func.dump(buf, size, pos)
|
||||
else:
|
||||
pos = _emit(buf, size, pos, "None")
|
||||
pos = _emit(buf, size, pos, ", args=")
|
||||
pos = _dump_list(self.args, buf, size, pos)
|
||||
pos = _emit(buf, size, pos, ")")
|
||||
return pos
|
||||
|
||||
|
||||
# ============================================================
|
||||
# BoolOp Node
|
||||
# ============================================================
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
|
||||
+114
-27
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
@@ -17,7 +16,9 @@ from .exprs import (
|
||||
ListComp, SetComp, DictComp, GeneratorExp,
|
||||
Await, Yield, YieldFrom, FormattedValue, JoinedStr,
|
||||
Constant, NamedExpr, Attribute, Subscript, Starred, Name,
|
||||
List, Tuple, Slice, Call, Compare, OpNode,
|
||||
List, Tuple, Slice, Call, Compare, OpNode, New,
|
||||
NEW_SRC_DEFAULT, NEW_SRC_STACK, NEW_SRC_HEAP, NEW_SRC_MEMGR,
|
||||
NEW_LIFE_DEFAULT, NEW_LIFE_SLIFE, NEW_LIFE_HLIFE,
|
||||
)
|
||||
from .stmts import (
|
||||
Module, Expression, Interactive, FunctionType,
|
||||
@@ -1780,6 +1781,90 @@ def _parse_slice(ps: Parser*) -> AST*:
|
||||
return lower
|
||||
|
||||
|
||||
def _is_new_expr(ps: Parser*) -> int:
|
||||
"""是否 `new` 描述符表达式(软关键字判定)。
|
||||
|
||||
`new` 是软关键字:只有紧跟一个**普通名**(描述符 hlife/slife/stack/heap/memgr 或类型名
|
||||
`T(args)`)时才当关键字。`new = 1`、`new.x`、`new(1)`、`for new in ...` 都仍是标识符。
|
||||
"""
|
||||
if _is_named_soft(ps, "new") == 0: return 0
|
||||
nxt: Token* = ps.cur.next
|
||||
if nxt is None: return 0
|
||||
if nxt.type != TokenType.Name: return 0
|
||||
if nxt.kw_subtype != Keyword.NotKeyword: return 0
|
||||
return 1
|
||||
|
||||
|
||||
def _parse_new_expr(ps: Parser*) -> AST*:
|
||||
"""`new [Descriptor...] T(args)`:描述符顺序无关、各轴最多一次(冲突即报错)。
|
||||
|
||||
结果恒为 `T*`;来源缺省 = heap(D3),生命期缺省由来源决定(语义侧落地)。
|
||||
"""
|
||||
lineno: int = _cur_lineno(ps)
|
||||
col: int = _cur_col(ps)
|
||||
_advance(ps) # 吃掉 `new`
|
||||
src: int = NEW_SRC_DEFAULT
|
||||
life: int = NEW_LIFE_DEFAULT
|
||||
memgr_arg: AST* = None
|
||||
while True:
|
||||
if _is_named_soft(ps, "hlife") != 0:
|
||||
if life != NEW_LIFE_DEFAULT:
|
||||
_record_parse_err(ps)
|
||||
ps.error_count += 1
|
||||
return None
|
||||
life = NEW_LIFE_HLIFE
|
||||
_advance(ps)
|
||||
continue
|
||||
if _is_named_soft(ps, "slife") != 0:
|
||||
if life != NEW_LIFE_DEFAULT:
|
||||
_record_parse_err(ps)
|
||||
ps.error_count += 1
|
||||
return None
|
||||
life = NEW_LIFE_SLIFE
|
||||
_advance(ps)
|
||||
continue
|
||||
if _is_named_soft(ps, "stack") != 0:
|
||||
if src != NEW_SRC_DEFAULT:
|
||||
_record_parse_err(ps)
|
||||
ps.error_count += 1
|
||||
return None
|
||||
src = NEW_SRC_STACK
|
||||
_advance(ps)
|
||||
continue
|
||||
if _is_named_soft(ps, "heap") != 0:
|
||||
if src != NEW_SRC_DEFAULT:
|
||||
_record_parse_err(ps)
|
||||
ps.error_count += 1
|
||||
return None
|
||||
src = NEW_SRC_HEAP
|
||||
_advance(ps)
|
||||
continue
|
||||
if _is_named_soft(ps, "memgr") != 0:
|
||||
if src != NEW_SRC_DEFAULT:
|
||||
_record_parse_err(ps)
|
||||
ps.error_count += 1
|
||||
return None
|
||||
_advance(ps) # memgr
|
||||
if _expect_op(ps, TokOp.LPar) == 0: return None
|
||||
_skip_nl(ps)
|
||||
memgr_arg = _parse_test(ps)
|
||||
if memgr_arg is None: return None
|
||||
if _expect_op(ps, TokOp.RPar) == 0: return None
|
||||
src = NEW_SRC_MEMGR
|
||||
continue
|
||||
break
|
||||
# 类型/可调用 + 实参:复用普通表达式解析,要求结果恰好是一个 Call(`T(args)`)
|
||||
callee: AST* = _parse_atom_expr(ps)
|
||||
if callee is None or callee.kind() != ASTKind.Call:
|
||||
_record_parse_err(ps)
|
||||
ps.error_count += 1
|
||||
return None
|
||||
cl: Call* = Call*(callee)
|
||||
node: New* = New(ps.pool, src, life, memgr_arg, cl.func, cl.args)
|
||||
_set_pos(node, lineno, col, 0, 0)
|
||||
return node
|
||||
|
||||
|
||||
def _parse_atom(ps: Parser*) -> AST*:
|
||||
"""atom: the smallest unit of expression"""
|
||||
ttype: int = _cur_type(ps)
|
||||
@@ -1787,6 +1872,8 @@ def _parse_atom(ps: Parser*) -> AST*:
|
||||
col: int = _cur_col(ps)
|
||||
|
||||
if ttype == TokenType.Name:
|
||||
# M2.4 `new` 描述符分配(软关键字):仅当后面确实跟着描述符/类型调用时才当关键字
|
||||
if _is_new_expr(ps) != 0: return _parse_new_expr(ps)
|
||||
kw: int = _cur_kw(ps)
|
||||
if kw == Keyword.True_:
|
||||
_advance(ps)
|
||||
@@ -2449,31 +2536,31 @@ def _parse_array_prefix_declarator(ps: Parser*) -> AST*:
|
||||
return carray
|
||||
|
||||
|
||||
def _IsCTypedefAnnotation(ann: AST*) -> int:
|
||||
"""1 if the annotation is a typedef marker (bare CTypedef / t.CTypedef / a union containing it).
|
||||
|
||||
Used to parse a typedef's right-hand side as a **type**: `X: t.CTypedef = const uint16*`
|
||||
synthesizes descriptors and the `*` suffix through _parse_type_ann (the annotation rule),
|
||||
so both sides agree. TPC's vast Parser._IsCTypedefAnnotation uses the same name-based test.
|
||||
"""
|
||||
if ann is None: return 0
|
||||
kd: int = ann.kind()
|
||||
if kd == ASTKind.Attribute:
|
||||
at: Attribute* = Attribute*(ann)
|
||||
if at.attr is not None and string.strcmp(at.attr, "CTypedef") == 0: return 1
|
||||
return 0
|
||||
if kd == ASTKind.Name:
|
||||
nm: Name* = Name*(ann)
|
||||
if nm.id is not None and string.strcmp(nm.id, "CTypedef") == 0: return 1
|
||||
return 0
|
||||
if kd == ASTKind.BinOp:
|
||||
bo: BinOp* = BinOp*(ann)
|
||||
if bo.left is not None and _IsCTypedefAnnotation(bo.left) != 0: return 1
|
||||
if bo.right is not None and _IsCTypedefAnnotation(bo.right) != 0: return 1
|
||||
return 0
|
||||
return 0
|
||||
|
||||
|
||||
def _IsCTypedefAnnotation(ann: AST*) -> int:
|
||||
"""1 if the annotation is a typedef marker (bare CTypedef / t.CTypedef / a union containing it).
|
||||
|
||||
Used to parse a typedef's right-hand side as a **type**: `X: t.CTypedef = const uint16*`
|
||||
synthesizes descriptors and the `*` suffix through _parse_type_ann (the annotation rule),
|
||||
so both sides agree. TPC's vast Parser._IsCTypedefAnnotation uses the same name-based test.
|
||||
"""
|
||||
if ann is None: return 0
|
||||
kd: int = ann.kind()
|
||||
if kd == ASTKind.Attribute:
|
||||
at: Attribute* = Attribute*(ann)
|
||||
if at.attr is not None and string.strcmp(at.attr, "CTypedef") == 0: return 1
|
||||
return 0
|
||||
if kd == ASTKind.Name:
|
||||
nm: Name* = Name*(ann)
|
||||
if nm.id is not None and string.strcmp(nm.id, "CTypedef") == 0: return 1
|
||||
return 0
|
||||
if kd == ASTKind.BinOp:
|
||||
bo: BinOp* = BinOp*(ann)
|
||||
if bo.left is not None and _IsCTypedefAnnotation(bo.left) != 0: return 1
|
||||
if bo.right is not None and _IsCTypedefAnnotation(bo.right) != 0: return 1
|
||||
return 0
|
||||
return 0
|
||||
|
||||
|
||||
def _parse_type_ann(ps: Parser*) -> AST*:
|
||||
"""Parse a type annotation: descriptor prefixes (const / volatile / __attribute__) and C-style pointer
|
||||
suffixes (* / **), field-identical to TPC's expansion. `static` is invalid here; missing type / non-type
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import t, c
|
||||
|
||||
|
||||
define ATOMIC_RELAXED = 0
|
||||
define ATOMIC_CONSUME = 1
|
||||
define ATOMIC_ACQUIRE = 2
|
||||
@@ -11,8 +8,8 @@ define ATOMIC_SEQ_CST = 5
|
||||
|
||||
def __atomic_test_and_set(ptr: uint64*, order: int) -> bool:
|
||||
result: uint8 = 1
|
||||
c.Asm(f"""mov al, 1
|
||||
xchg byte ptr [{c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}], al
|
||||
__asm__(f"""mov al, 1
|
||||
xchg byte ptr [{asminp(ptr, ASM_DESCR.REG_ANY)}], al
|
||||
mov $0, al""",
|
||||
out = [asmout(result, ASM_DESCR.OUTPUT_REG)],
|
||||
op = [ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX])
|
||||
@@ -20,7 +17,7 @@ def __atomic_test_and_set(ptr: uint64*, order: int) -> bool:
|
||||
|
||||
|
||||
def __atomic_clear(ptr: uint64*, order: int):
|
||||
__asm__(f"""mov byte ptr [{c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}], 0""",
|
||||
__asm__(f"""mov byte ptr [{asminp(ptr, ASM_DESCR.REG_ANY)}], 0""",
|
||||
inp = [asminp(ptr, ASM_DESCR.REG_ANY)],
|
||||
op = [ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import t, c
|
||||
|
||||
|
||||
# ==============================================
|
||||
# Base64 Encoder & Decoder, pure bare-metal implementation
|
||||
# ==============================================
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import t, c
|
||||
import t
|
||||
import stdlib
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import stdint as __stdint
|
||||
import t
|
||||
|
||||
|
||||
|
||||
+1
-2
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
from w32.win32base import *
|
||||
from w32.win32sync import (
|
||||
@@ -42,7 +41,7 @@ class Condition:
|
||||
def release(self):
|
||||
LeaveCriticalSection(&self.cs)
|
||||
|
||||
def __enter__(self) -> 'Condition' | t.CPtr:
|
||||
def __enter__(self) -> Condition*:
|
||||
self.acquire()
|
||||
return self
|
||||
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdlib
|
||||
|
||||
|
||||
novirtual class Coroutine:
|
||||
"""Coroutine frame handle (M1: __ptr__ holds the frame pointer returned by create_<name>()).
|
||||
Pure handle semantics: never instantiated or polymorphically dispatched, the compiler intercepts all coro.* calls; user code uses t.CPtr as the handle."""
|
||||
@@ -43,7 +38,7 @@ def coro_gather(a: Coroutine) -> int:
|
||||
# M4 placeholder: the compiler inlines coro.coro_gather(frames...) into a concurrent-advance loop.
|
||||
return 0
|
||||
|
||||
def coro_exception_msg(c: Coroutine) -> t.CPtr:
|
||||
def coro_exception_msg(c: Coroutine) -> rawptr:
|
||||
# M7 placeholder: the compiler inlines coro.coro_exception_msg(frame) into a frame msg-slot read.
|
||||
# Note: TPV (Viper) does not support bare null; use t.CPtr(0) to build a null pointer (compatible with both compilers).
|
||||
return None
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
"""ctraits — Compile-time type trait library
|
||||
|
||||
Provides compile-time type predicates with no runtime code generated.
|
||||
All functions are evaluated exclusively at compile time and can be combined with the conditional
|
||||
compilation statements cif / celif / celse.
|
||||
"""
|
||||
import t
|
||||
|
||||
def isptr(x: t.CType) -> bool:
|
||||
"""Compile-time predicate to determine whether the type of x is a pointer.
|
||||
|
||||
Returns True if x is a pointer type (ptr_count > 0); otherwise returns False.
|
||||
Can be used alongside cif to implement conditional compilation.
|
||||
|
||||
Example:
|
||||
cif ctraits.isptr(my_var):
|
||||
# This branch compiles only when my_var is a pointer type
|
||||
...
|
||||
"""
|
||||
pass
|
||||
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
from w32.win32base import *
|
||||
from w32.win32sync import CreateEventA, SetEvent, ResetEvent, WaitForSingleObject
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#
|
||||
# Covers the three deflate block types (stored/fixed/dynamic); does not decode CRC.
|
||||
# ============================================================
|
||||
import t, c
|
||||
import stdlib
|
||||
import string
|
||||
import w32.fileio as fileio
|
||||
@@ -132,11 +131,11 @@ class GzipFile:
|
||||
_g_bits: uint64 = 0
|
||||
_g_bitcnt: int = 0
|
||||
_g_pos: sizet = 0
|
||||
_g_src: t.CPtr = None
|
||||
_g_src: rawptr = None
|
||||
_g_src_len: sizet = 0
|
||||
|
||||
|
||||
def gzip_isize(src: t.CPtr, src_len: sizet) -> uint32:
|
||||
def gzip_isize(src: rawptr, src_len: sizet) -> uint32:
|
||||
"""gzip trailing ISIZE (little-endian u32): original length hint."""
|
||||
if src is None or src_len < 4:
|
||||
return 0
|
||||
@@ -150,7 +149,7 @@ def gzip_isize(src: t.CPtr, src_len: sizet) -> uint32:
|
||||
return uint32(v64)
|
||||
|
||||
|
||||
def _reset(src: t.CPtr, src_len: sizet):
|
||||
def _reset(src: rawptr, src_len: sizet):
|
||||
global _g_bits, _g_bitcnt, _g_pos, _g_src, _g_src_len
|
||||
_g_bits = 0
|
||||
_g_bitcnt = 0
|
||||
@@ -315,8 +314,8 @@ def _cl_order_set(arr: int*, idx: int, val: int):
|
||||
# ============================================================
|
||||
# Core decompression (module-private)
|
||||
# ============================================================
|
||||
def _gzip_decode(src: t.CPtr, src_len: sizet,
|
||||
dst: t.CPtr, dst_cap: sizet) -> LONG:
|
||||
def _gzip_decode(src: rawptr, src_len: sizet,
|
||||
dst: rawptr, dst_cap: sizet) -> LONG:
|
||||
if src is None or dst is None or src_len < 18 or dst_cap == 0:
|
||||
return -1
|
||||
ub: uchar* = src
|
||||
|
||||
+2
-3
@@ -1,5 +1,4 @@
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
# ==============================================
|
||||
@@ -41,8 +40,8 @@ class md5:
|
||||
state: [4]uint32 = [
|
||||
0x67452301, 0xefcdab89,
|
||||
0x98badcfe, 0x10325476
|
||||
] # 4 32-bit state registers
|
||||
count: uint64 = 0 # processed bits
|
||||
] # 4 32-bit state registers
|
||||
count: uint64 = 0 # processed bits
|
||||
buf: [MD5_BLOCK_LEN]uint8
|
||||
# Initialize MD5 context
|
||||
def __init__(self):
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
|
||||
# ==============================================
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
# ==============================================
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
import string
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
# hashtable - Open-addressing hash table library
|
||||
# Linear probing for collision resolution, supports auto-resizing and tombstone deletion
|
||||
# Key type fixed as str (i8*), value type is void* (generic pointer)
|
||||
import t, c
|
||||
import string
|
||||
import memhub
|
||||
import stdio
|
||||
from stdint import *
|
||||
|
||||
# Empty slot marker (hash == 0)
|
||||
|
||||
+6
-7
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
@@ -26,9 +25,9 @@ class JsonValue:
|
||||
int_val: int64
|
||||
float_val: double
|
||||
str_val: str
|
||||
next: 'JsonValue' | t.CPtr
|
||||
next: JsonValue*
|
||||
key: str
|
||||
child: 'JsonValue' | t.CPtr
|
||||
child: JsonValue*
|
||||
child_count: sizet
|
||||
|
||||
def __new__(self, pool: memhub.MemManager*):
|
||||
@@ -77,7 +76,7 @@ class JsonValue:
|
||||
def __len__(self) -> sizet:
|
||||
return self.child_count
|
||||
|
||||
def __getitem__(self, key: str) -> 'JsonValue' | t.CPtr:
|
||||
def __getitem__(self, key: str) -> JsonValue*:
|
||||
"""Python-style get: v["key"] returns an object field."""
|
||||
if self.vtype != JSON_OBJECT:
|
||||
return None
|
||||
@@ -91,7 +90,7 @@ class JsonValue:
|
||||
cur = cur.next
|
||||
return None
|
||||
|
||||
def __setitem__(self, key: str, val: 'JsonValue' | t.CPtr):
|
||||
def __setitem__(self, key: str, val: JsonValue*):
|
||||
"""Python-style set: v["key"] = val."""
|
||||
if self.vtype != JSON_OBJECT or key == None or val == None:
|
||||
return
|
||||
@@ -116,7 +115,7 @@ class JsonValue:
|
||||
val.key = kbuf
|
||||
self._append_child(val)
|
||||
|
||||
def get_item(self, index: sizet) -> 'JsonValue' | t.CPtr:
|
||||
def get_item(self, index: sizet) -> JsonValue*:
|
||||
"""Get an array element by index: v.get_item(0)."""
|
||||
if self.vtype != JSON_ARRAY and self.vtype != JSON_OBJECT:
|
||||
return None
|
||||
@@ -133,7 +132,7 @@ class JsonValue:
|
||||
"""Internal: allocate from current object's mpool (reserved; currently returns None)."""
|
||||
return None
|
||||
|
||||
def _append_child(self, child: 'JsonValue' | t.CPtr):
|
||||
def _append_child(self, child: JsonValue*):
|
||||
if self.child == None:
|
||||
self.child = child
|
||||
else:
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
from w32.win32base import *
|
||||
from w32.win32sync import CRITICAL_SECTION, InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection, DeleteCriticalSection, TryEnterCriticalSection
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import t, c
|
||||
|
||||
|
||||
define IS_WINDOWS = 1
|
||||
define IS_WIN64 = 1
|
||||
define IS_X86_64 = 1
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
|
||||
|
||||
@@ -6,7 +5,7 @@ from stdint import *
|
||||
# POSIX Type Alias
|
||||
# Note: ssize_t has already been defined as t.CPtrDiffT in stdint.py, so we won’t repeat it here.
|
||||
# =============================================================================
|
||||
DIR: t.CTypedef = t.CPtr # Opaque directory stream handle
|
||||
DIR: t.CTypedef = rawptr # Opaque directory stream handle
|
||||
mode_t: t.CTypedef = uint32 # File mode/permission bits
|
||||
pid_t: t.CTypedef = int32 # Process ID
|
||||
off_t: t.CTypedef = int64 # File offset (Linux x86_64)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# vrandom - Hardware Random Number Generation Library
|
||||
# Implemented using inline assembly based on x86 RDRAND / RDSEED instructions
|
||||
import t, c
|
||||
import math
|
||||
|
||||
|
||||
@@ -14,21 +13,21 @@ define RDSEED_RETRY_LIMIT = 100
|
||||
# ============================================================
|
||||
def rdrand16() -> uint16:
|
||||
val: uint32 = 0
|
||||
__asm__(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
__asm__(f"rdrand {asmout(val, ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[asmout(val, ASM_DESCR.OUTPUT_REG)],
|
||||
op=[ASM_DESCR.CLOBBER_CC])
|
||||
return uint16(val)
|
||||
|
||||
def rdrand32() -> uint32:
|
||||
val: uint32 = 0
|
||||
__asm__(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
__asm__(f"rdrand {asmout(val, ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[asmout(val, ASM_DESCR.OUTPUT_REG)],
|
||||
op=[ASM_DESCR.CLOBBER_CC])
|
||||
return val
|
||||
|
||||
def rdrand64() -> uint64:
|
||||
val: uint64 = 0
|
||||
__asm__(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
__asm__(f"rdrand {asmout(val, ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[asmout(val, ASM_DESCR.OUTPUT_REG)],
|
||||
op=[ASM_DESCR.CLOBBER_CC])
|
||||
return val
|
||||
@@ -39,21 +38,21 @@ def rdrand64() -> uint64:
|
||||
# ============================================================
|
||||
def rdseed16() -> uint16:
|
||||
val: uint32 = 0
|
||||
__asm__(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
__asm__(f"rdseed {asmout(val, ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[asmout(val, ASM_DESCR.OUTPUT_REG)],
|
||||
op=[ASM_DESCR.CLOBBER_CC])
|
||||
return uint16(val)
|
||||
|
||||
def rdseed32() -> uint32:
|
||||
val: uint32 = 0
|
||||
__asm__(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
__asm__(f"rdseed {asmout(val, ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[asmout(val, ASM_DESCR.OUTPUT_REG)],
|
||||
op=[ASM_DESCR.CLOBBER_CC])
|
||||
return val
|
||||
|
||||
def rdseed64() -> uint64:
|
||||
val: uint64 = 0
|
||||
__asm__(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
__asm__(f"rdseed {asmout(val, ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[asmout(val, ASM_DESCR.OUTPUT_REG)],
|
||||
op=[ASM_DESCR.CLOBBER_CC])
|
||||
return val
|
||||
@@ -66,9 +65,9 @@ def rdseed64() -> uint64:
|
||||
def rdrand16_step(p: uint16*) -> int:
|
||||
val: uint32 = 0
|
||||
ok: uint32 = 0
|
||||
c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
__asm__(f"""rdrand {asmout(val, ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
movzx {asmout(ok, ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[asmout(val, ASM_DESCR.OUTPUT_REG), asmout(ok, ASM_DESCR.OUTPUT_REG)],
|
||||
op=[ASM_DESCR.CLOBBER_CC, ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = uint16(val)
|
||||
@@ -77,9 +76,9 @@ def rdrand16_step(p: uint16*) -> int:
|
||||
def rdrand32_step(p: uint32*) -> int:
|
||||
val: uint32 = 0
|
||||
ok: uint32 = 0
|
||||
c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
__asm__(f"""rdrand {asmout(val, ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
movzx {asmout(ok, ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[asmout(val, ASM_DESCR.OUTPUT_REG), asmout(ok, ASM_DESCR.OUTPUT_REG)],
|
||||
op=[ASM_DESCR.CLOBBER_CC, ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = val
|
||||
@@ -88,9 +87,9 @@ def rdrand32_step(p: uint32*) -> int:
|
||||
def rdrand64_step(p: uint64*) -> int:
|
||||
val: uint64 = 0
|
||||
ok: uint32 = 0
|
||||
c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
__asm__(f"""rdrand {asmout(val, ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
movzx {asmout(ok, ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[asmout(val, ASM_DESCR.OUTPUT_REG), asmout(ok, ASM_DESCR.OUTPUT_REG)],
|
||||
op=[ASM_DESCR.CLOBBER_CC, ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = val
|
||||
@@ -99,9 +98,9 @@ def rdrand64_step(p: uint64*) -> int:
|
||||
def rdseed16_step(p: uint16*) -> int:
|
||||
val: uint32 = 0
|
||||
ok: uint32 = 0
|
||||
c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
__asm__(f"""rdseed {asmout(val, ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
movzx {asmout(ok, ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[asmout(val, ASM_DESCR.OUTPUT_REG), asmout(ok, ASM_DESCR.OUTPUT_REG)],
|
||||
op=[ASM_DESCR.CLOBBER_CC, ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = uint16(val)
|
||||
@@ -110,9 +109,9 @@ def rdseed16_step(p: uint16*) -> int:
|
||||
def rdseed32_step(p: uint32*) -> int:
|
||||
val: uint32 = 0
|
||||
ok: uint32 = 0
|
||||
c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
__asm__(f"""rdseed {asmout(val, ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
movzx {asmout(ok, ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[asmout(val, ASM_DESCR.OUTPUT_REG), asmout(ok, ASM_DESCR.OUTPUT_REG)],
|
||||
op=[ASM_DESCR.CLOBBER_CC, ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = val
|
||||
@@ -121,9 +120,9 @@ def rdseed32_step(p: uint32*) -> int:
|
||||
def rdseed64_step(p: uint64*) -> int:
|
||||
val: uint64 = 0
|
||||
ok: uint32 = 0
|
||||
c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
__asm__(f"""rdseed {asmout(val, ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
movzx {asmout(ok, ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[asmout(val, ASM_DESCR.OUTPUT_REG), asmout(ok, ASM_DESCR.OUTPUT_REG)],
|
||||
op=[ASM_DESCR.CLOBBER_CC, ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = val
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
from w32.win32base import *
|
||||
from w32.win32sync import (
|
||||
@@ -38,7 +37,7 @@ class RWLock:
|
||||
def release_write(self):
|
||||
ReleaseSRWLockExclusive(&self.lock)
|
||||
|
||||
def __enter__(self) -> 'RWLock' | t.CPtr:
|
||||
def __enter__(self) -> RWLock*:
|
||||
self.acquire_write()
|
||||
return self
|
||||
|
||||
|
||||
@@ -25,24 +25,19 @@ _mbuddy: memhub.MemBuddy*
|
||||
|
||||
def copyfile(src: str, dst: str) -> int:
|
||||
"""Copy file content. Returns 0, otherwise -1."""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return _copyfile_win32(src, dst)
|
||||
return _copyfile_posix(src, dst)
|
||||
return _copyfile_win32(src, dst) if platmacro.IS_WINDOWS else _copyfile_posix(src, dst)
|
||||
|
||||
|
||||
def _copyfile_win32(src: str, dst: str) -> int:
|
||||
"""Windows: Use CopyFileA kernel implementation (efficient)."""
|
||||
result: BOOL = w32.win32file.CopyFileA(src, dst, 0)
|
||||
if result == 0:
|
||||
return -1
|
||||
return 0
|
||||
return -1 if result == 0 else 0
|
||||
|
||||
|
||||
def _copyfile_posix(src: str, dst: str) -> int:
|
||||
"""POSIX: Manual file read/write loop copy"""
|
||||
fd_in: INT = posix.open(src, posix.O_RDONLY, 0)
|
||||
if fd_in < 0:
|
||||
return -1
|
||||
if fd_in < 0: return -1
|
||||
fd_out: INT = posix.open(dst, posix.O_WRONLY | posix.O_CREAT | posix.O_TRUNC, 0o644)
|
||||
if fd_out < 0:
|
||||
posix.close(fd_in)
|
||||
@@ -52,17 +47,16 @@ def _copyfile_posix(src: str, dst: str) -> int:
|
||||
posix.close(fd_in)
|
||||
posix.close(fd_out)
|
||||
return -1
|
||||
n: ssize_t = 0
|
||||
n: sizet = 0
|
||||
result: int = 0
|
||||
n = posix.read(fd_in, buf, COPY_BUF_SIZE)
|
||||
while n > 0:
|
||||
written: ssize_t = posix.write(fd_out, buf, sizet(n))
|
||||
written: sizet = posix.write(fd_out, buf, sizet(n))
|
||||
if written < 0:
|
||||
result = -1
|
||||
break
|
||||
n = posix.read(fd_in, buf, COPY_BUF_SIZE)
|
||||
if n < 0:
|
||||
result = -1
|
||||
if n < 0: result = -1
|
||||
_mbuddy.free(buf)
|
||||
posix.close(fd_in)
|
||||
posix.close(fd_out)
|
||||
@@ -75,9 +69,7 @@ def _copyfile_posix(src: str, dst: str) -> int:
|
||||
|
||||
def copy(src: str, dst: str) -> int:
|
||||
"""Copy file and preserve permissions/metadata (POSIX only). Returns 0, otherwise -1."""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return _copy_win32(src, dst)
|
||||
return _copy_posix(src, dst)
|
||||
return _copy_win32(src, dst) if platmacro.IS_WINDOWS else _copy_posix(src, dst)
|
||||
|
||||
|
||||
def _copy_win32(src: str, dst: str) -> int:
|
||||
@@ -88,11 +80,9 @@ def _copy_win32(src: str, dst: str) -> int:
|
||||
def _copy_posix(src: str, dst: str) -> int:
|
||||
"""POSIX: Copy file and preserve permissions (stat+chmod). Returns 0, otherwise -1."""
|
||||
result: int = _copyfile_posix(src, dst)
|
||||
if result != 0:
|
||||
return -1
|
||||
if result != 0: return -1
|
||||
st: posix.Stat = posix.Stat()
|
||||
if posix.stat(src, &st) == 0:
|
||||
posix.chmod(dst, st.st_mode)
|
||||
if posix.stat(src, &st) == 0: posix.chmod(dst, st.st_mode)
|
||||
return 0
|
||||
|
||||
|
||||
@@ -102,9 +92,7 @@ def _copy_posix(src: str, dst: str) -> int:
|
||||
|
||||
def rmtree(path: str) -> int:
|
||||
"""Recursively delete a directory tree. Returns 0 on success and -1 on failure."""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return _rmtree_win32(path)
|
||||
return _rmtree_posix(path)
|
||||
return _rmtree_win32(path) if platmacro.IS_WINDOWS else - _rmtree_posix(path)
|
||||
|
||||
|
||||
def _rmtree_win32(path: str) -> int:
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import string
|
||||
import platmacro
|
||||
@@ -127,15 +126,15 @@ def _MakeAddr(host: str, port: INT) -> SocketAddr:
|
||||
if he_raw is not None:
|
||||
# he_raw.h_addr_list → he_raw->h_addr_list (char**)
|
||||
# c.Deref(uint64(he_raw.h_addr_list, t.CPtr)) → *(uint64_t*)(he_raw->h_addr_list) → h_addr_list[0]
|
||||
ip_ptr: u64 = u64(c.Deref(uint64(he_raw.h_addr_list, t.CPtr)))
|
||||
ip_ptr: u64 = u64(*(uint64*(he_raw.h_addr_list)))
|
||||
if ip_ptr != 0:
|
||||
addr.addr = u32(c.Deref(uint32(ip_ptr, t.CPtr)))
|
||||
addr.addr = u32(*(uint32*(ip_ptr)))
|
||||
else:
|
||||
he: HostEnt* = gethostbyname(host)
|
||||
if he is not None:
|
||||
ip_ptr: u64 = u64(c.Deref(uint64(he.h_addr_list, t.CPtr)))
|
||||
ip_ptr: u64 = u64(*(uint64*(he.h_addr_list)))
|
||||
if ip_ptr != 0:
|
||||
addr.addr = u32(c.Deref(uint32(ip_ptr, t.CPtr)))
|
||||
addr.addr = u32(*(uint32*(ip_ptr)))
|
||||
|
||||
return addr
|
||||
|
||||
@@ -175,7 +174,7 @@ def _ParseIPv4(ip_str: str, out_addr: u32*) -> bool:
|
||||
result = result | (u32(parts[1]) << 16)
|
||||
result = result | (u32(parts[2]) << 8)
|
||||
result = result | u32(parts[3])
|
||||
c.DerefAs(out_addr, result)
|
||||
*out_addr = result
|
||||
return True
|
||||
|
||||
|
||||
|
||||
+48
-52
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
from w32.win32base import *
|
||||
import string
|
||||
@@ -525,8 +524,8 @@ class TracebackState():
|
||||
ContextBuf: VOIDPTR # CONTEXT buffer (calloc, 16-byte aligned)
|
||||
FrameBuf: VOIDPTR # STACKFRAME64 buffer (calloc)
|
||||
LineBuf: bytes # output line buffer
|
||||
FrameAddr: t.CArray[uint64, TRACEBACK_FRAME_BUF] # collected frames, innermost first
|
||||
FrameScan: t.CArray[int32, TRACEBACK_FRAME_BUF] # 0 = authoritative, 1 = inferred (ScanStack)
|
||||
FrameAddr: [TRACEBACK_FRAME_BUF]uint64 # collected frames, innermost first
|
||||
FrameScan: [TRACEBACK_FRAME_BUF]int32 # 0 = authoritative, 1 = inferred (ScanStack)
|
||||
FrameCount: int # frames collected so far (also the printed frame count)
|
||||
|
||||
|
||||
@@ -577,7 +576,7 @@ def DiagEnabled() -> int:
|
||||
global _DiagFlag
|
||||
if _DiagFlag >= 0:
|
||||
return _DiagFlag
|
||||
Val: t.CArray[char, 8]
|
||||
Val: [8]char
|
||||
Val[0] = char(0)
|
||||
R: DWORD = GetEnvironmentVariableA("TRACEBACK_DIAG", &Val, DWORD(8))
|
||||
_DiagFlag = 0
|
||||
@@ -630,7 +629,7 @@ def EmitToFile(N: int):
|
||||
if _DumpFileFailWarned != 0:
|
||||
return
|
||||
_DumpFileFailWarned = 1
|
||||
LB: t.CArray[char, 160]
|
||||
LB: [160]char
|
||||
M: int = stdio.snprintf(&LB, sizet(160),
|
||||
"[traceback] WARN: stack dump file write failed (further file-write failures not reported)\n")
|
||||
if M <= 0:
|
||||
@@ -667,15 +666,15 @@ def EmitLine(N: int):
|
||||
# Line-number prefix: shift the buffer right by the prefix length, then write the prefix.
|
||||
if DiagEnabled() != 0:
|
||||
_DumpLineNo = _DumpLineNo + 1
|
||||
Pfx: t.CArray[char, 32]
|
||||
Pfx: [32]char
|
||||
Pl: int = stdio.snprintf(&Pfx, sizet(32), " [dump#%d] ", _DumpLineNo)
|
||||
if Pl > 0:
|
||||
# Keep room for the trailing '\0' after prefixing.
|
||||
if N + Pl > TRACEBACK_LINE_CAP - 1:
|
||||
N = TRACEBACK_LINE_CAP - 1 - Pl
|
||||
# Move the trailing '\0' too (N+1) so the buffer stays NUL-terminated.
|
||||
string.memmove(t.CPtr(_State.LineBuf + int(Pl)), t.CPtr(_State.LineBuf), sizet(N + 1))
|
||||
string.memmove(t.CPtr(_State.LineBuf), &Pfx, sizet(Pl))
|
||||
string.memmove(rawptr(_State.LineBuf + int(Pl)), rawptr(_State.LineBuf), sizet(N + 1))
|
||||
string.memmove(rawptr(_State.LineBuf), &Pfx, sizet(Pl))
|
||||
N = N + Pl
|
||||
WriteConsoleOnly(N)
|
||||
EmitToFile(N)
|
||||
@@ -718,7 +717,7 @@ def EmitEarlyCode(Text: str, Code: ULONG):
|
||||
N: int = stdio.snprintf(_State.LineBuf, sizet(TRACEBACK_LINE_CAP), "%s(GetLastError=%u)\n", Text, Code)
|
||||
EmitLine(N)
|
||||
return
|
||||
LB: t.CArray[char, 256]
|
||||
LB: [256]char
|
||||
N2: int = stdio.snprintf(&LB, sizet(256), "%s(GetLastError=%u)\n", Text, Code)
|
||||
if N2 <= 0:
|
||||
return
|
||||
@@ -890,7 +889,7 @@ def LoadMapFile(hFile: HANDLE, Size: int64) -> int:
|
||||
Got: ULONG = 0
|
||||
if wf.ReadFile(hFile, Buf, ULONG(Size), &Got, None) == 0:
|
||||
Err: ULONG = GetLastError()
|
||||
stdlib.free(t.CPtr(Buf))
|
||||
stdlib.free(Buf)
|
||||
if _State != None and _State.LineBuf != None:
|
||||
RN: int = stdio.snprintf(_State.LineBuf, sizet(TRACEBACK_LINE_CAP),
|
||||
"[traceback] WARN: read <exe>.stackmap failed (GetLastError=%u),"
|
||||
@@ -898,14 +897,14 @@ def LoadMapFile(hFile: HANDLE, Size: int64) -> int:
|
||||
EmitLine(RN)
|
||||
return 0
|
||||
if sizet(Got) != sizet(Size):
|
||||
stdlib.free(t.CPtr(Buf))
|
||||
stdlib.free(Buf)
|
||||
return MapFailPlain(Size, "read fewer bytes than the file size")
|
||||
# Header: magic / version / entry_count / str_count / str_bytes
|
||||
if ReadU32(Buf, 0) != uint32(TRACEBACK_MAP_MAGIC):
|
||||
stdlib.free(t.CPtr(Buf))
|
||||
stdlib.free(Buf)
|
||||
return MapFailHdr(Size, "magic is not \"TPCS\" (writer/reader endianness or offset mismatch)", Buf)
|
||||
if ReadU32(Buf, 4) != uint32(TRACEBACK_MAP_VERSION):
|
||||
stdlib.free(t.CPtr(Buf))
|
||||
stdlib.free(Buf)
|
||||
return MapFailHdr(Size, "version is not 1 (stackmap written by another TPC version)", Buf)
|
||||
Cnt: uint32 = ReadU32(Buf, 8)
|
||||
StrCnt: uint32 = ReadU32(Buf, 12)
|
||||
@@ -915,16 +914,16 @@ def LoadMapFile(hFile: HANDLE, Size: int64) -> int:
|
||||
+ uint64(Cnt) * uint64(TRACEBACK_ENTRY_SIZE) \
|
||||
+ uint64(SBytes)
|
||||
if Need > uint64(Size):
|
||||
stdlib.free(t.CPtr(Buf))
|
||||
stdlib.free(Buf)
|
||||
return MapFailHdr(Size, "20+entry_count*20+str_bytes exceeds end of file "
|
||||
"(header corrupt or file truncated)", Buf)
|
||||
if SBytes == 0:
|
||||
stdlib.free(t.CPtr(Buf))
|
||||
stdlib.free(Buf)
|
||||
return MapFailHdr(Size, "str_bytes is 0 (string pool missing)", Buf)
|
||||
# The last pool byte must be '\0' so any later %s print stays inside the pool.
|
||||
PoolEnd: int = TRACEBACK_MAP_HEADER + int(Cnt) * TRACEBACK_ENTRY_SIZE + int(SBytes) - 1
|
||||
if Buf[PoolEnd] != 0:
|
||||
stdlib.free(t.CPtr(Buf))
|
||||
stdlib.free(Buf)
|
||||
return MapFailHdr(Size, "string pool does not end with '\\0' (pool corrupt)", Buf)
|
||||
# Full-table check: strictly ascending rva + string offsets inside the pool.
|
||||
Prev: uint64 = 0
|
||||
@@ -932,17 +931,17 @@ def LoadMapFile(hFile: HANDLE, Size: int64) -> int:
|
||||
Off: int = TRACEBACK_MAP_HEADER + int(i) * TRACEBACK_ENTRY_SIZE
|
||||
Cur: uint64 = ReadU64(Buf, Off)
|
||||
if i > 0 and Cur <= Prev:
|
||||
stdlib.free(t.CPtr(Buf))
|
||||
stdlib.free(Buf)
|
||||
return MapFailEntry(Size, int(i),
|
||||
"record rva not strictly ascending (breaks binary search)", Cur)
|
||||
Prev = Cur
|
||||
FO: uint32 = ReadU32(Buf, Off + TRACEBACK_ENTRY_FILEOFF)
|
||||
FN: uint32 = ReadU32(Buf, Off + TRACEBACK_ENTRY_FUNCOFF)
|
||||
if uint64(FO) >= uint64(SBytes):
|
||||
stdlib.free(t.CPtr(Buf))
|
||||
stdlib.free(Buf)
|
||||
return MapFailEntry(Size, int(i), "file_off outside the string pool", uint64(FO))
|
||||
if FN != 0 and uint64(FN) >= uint64(SBytes):
|
||||
stdlib.free(t.CPtr(Buf))
|
||||
stdlib.free(Buf)
|
||||
return MapFailEntry(Size, int(i),
|
||||
"func_off is neither 0 (no name) nor inside the string pool",
|
||||
uint64(FN))
|
||||
@@ -989,13 +988,13 @@ def EmitSourceText(Path: str, LineNo: int):
|
||||
if _State == None or _State.LineBuf == None or LineNo <= 0:
|
||||
return
|
||||
h: HANDLE = wf.CreateFileA(Path, wf.GENERIC_READ, wf.FILE_SHARE_READ | wf.FILE_SHARE_WRITE,
|
||||
t.CPtr(0), wf.OPEN_EXISTING, wf.FILE_ATTRIBUTE_NORMAL, t.CPtr(0))
|
||||
None, wf.OPEN_EXISTING, wf.FILE_ATTRIBUTE_NORMAL, None)
|
||||
if h == INVALID_HANDLE_VALUE:
|
||||
return
|
||||
Chunk: t.CArray[char, TRACEBACK_SRC_CHUNK]
|
||||
Src: t.CArray[char, TRACEBACK_LINE_CAP]
|
||||
Chunk: [TRACEBACK_SRC_CHUNK]char
|
||||
Src: [TRACEBACK_LINE_CAP]char
|
||||
Line: int = 1
|
||||
Out: int = 0 # bytes collected for the target line
|
||||
Out: int = 0 # bytes collected for the target line
|
||||
Done: int = 0
|
||||
while Done == 0:
|
||||
Got: ULONG = 0
|
||||
@@ -1115,7 +1114,7 @@ def EmitFrame(Addr: uint64, Base: uint64, Scanned: int):
|
||||
# ============================================================
|
||||
|
||||
def ReadMemCb(hProcess: HANDLE, Addr: ULONGLONG, Buf: VOIDPTR, Size: DWORD,
|
||||
pRead: t.CPtr) -> BOOL:
|
||||
pRead: rawptr) -> BOOL:
|
||||
"""This module's stand-in for the StackWalk64 memory callback (PREAD_PROCESS_MEMORY_ROUTINE64).
|
||||
|
||||
Not kernel32!ReadProcessMemory directly:
|
||||
@@ -1129,7 +1128,7 @@ def ReadMemCb(hProcess: HANDLE, Addr: ULONGLONG, Buf: VOIDPTR, Size: DWORD,
|
||||
Passing this function by name as a t.CPtr mirrors SetConsoleCtrlHandler(CtrlHandler).
|
||||
"""
|
||||
Read: sizet = 0
|
||||
R: BOOL = wm.ReadProcessMemory(hProcess, t.CPtr(Addr), Buf, sizet(Size), &Read)
|
||||
R: BOOL = wm.ReadProcessMemory(hProcess, rawptr(Addr), Buf, sizet(Size), &Read)
|
||||
if pRead != None:
|
||||
Rd: uint32* = (uint32*)(pRead)
|
||||
Rd[0] = uint32(Read)
|
||||
@@ -1299,7 +1298,7 @@ def WalkRbpChain(Rip: uint64, Rbp: uint64, Base: uint64) -> int:
|
||||
Cur: uint64 = Rbp
|
||||
i: int = 1
|
||||
HProc: HANDLE = wp.GetCurrentProcess()
|
||||
Two: t.CArray[uint64, 2] # [0] = [rbp] (caller rbp), [1] = [rbp+8] (return address)
|
||||
Two: [2]uint64 # [0] = [rbp] (caller rbp), [1] = [rbp+8] (return address)
|
||||
while i < TRACEBACK_MAX_FRAMES:
|
||||
# Raw readings + decision for this step, produced before any early reject.
|
||||
Rd: sizet = 0
|
||||
@@ -1319,7 +1318,7 @@ def WalkRbpChain(Rip: uint64, Rbp: uint64, Base: uint64) -> int:
|
||||
# Read 16 bytes via ReadProcessMemory (invalid/unreadable addresses return 0 without
|
||||
# faulting); dereferencing a wild rbp directly would crash, which the primary path
|
||||
# must never do.
|
||||
OkRead: BOOL = wm.ReadProcessMemory(HProc, t.CPtr(Cur), &Two, sizet(16), &Rd)
|
||||
OkRead: BOOL = wm.ReadProcessMemory(HProc, rawptr(Cur), &Two, sizet(16), &Rd)
|
||||
if OkRead == 0 or sizet(Rd) < sizet(16):
|
||||
# GetLastError must be read immediately after ReadProcessMemory.
|
||||
RpmErr = GetLastError()
|
||||
@@ -1401,8 +1400,8 @@ def ScanStack(StartIndex: int, Rsp: uint64, Base: uint64) -> int:
|
||||
HProc: HANDLE = wp.GetCurrentProcess()
|
||||
Upper: uint64 = Rsp + uint64(TRACEBACK_SCAN_MAX_BYTES)
|
||||
ModEnd: uint64 = Base + uint64(TRACEBACK_MODULE_MAX)
|
||||
Words: t.CArray[uint64, TRACEBACK_SCAN_CHUNK_WORDS] # 4 KiB chunk buffer (local)
|
||||
Found: t.CArray[uint64, TRACEBACK_SCAN_MAX_HITS] # deduplicated candidate return addresses
|
||||
Words: [TRACEBACK_SCAN_CHUNK_WORDS]uint64 # 4 KiB chunk buffer (local)
|
||||
Found: [TRACEBACK_SCAN_MAX_HITS]uint64 # deduplicated candidate return addresses
|
||||
Hits: int = 0
|
||||
Prev: uint64 = 0 # [A-8]: previous word unknown at chunk start, 0 (one less confirmation)
|
||||
Addr: uint64 = Rsp
|
||||
@@ -1414,7 +1413,7 @@ def ScanStack(StartIndex: int, Rsp: uint64, Base: uint64) -> int:
|
||||
EmitLine(D0)
|
||||
while Addr < Upper:
|
||||
Rd: sizet = 0
|
||||
OkRead: BOOL = wm.ReadProcessMemory(HProc, t.CPtr(Addr), &Words, sizet(TRACEBACK_SCAN_CHUNK_BYTES), &Rd)
|
||||
OkRead: BOOL = wm.ReadProcessMemory(HProc, rawptr(Addr), &Words, sizet(TRACEBACK_SCAN_CHUNK_BYTES), &Rd)
|
||||
N: int = int(sizet(Rd) / sizet(8)) # u64 words actually read in this chunk
|
||||
if OkRead == 0 or N <= 0:
|
||||
Er: ULONG = GetLastError()
|
||||
@@ -1630,7 +1629,7 @@ def DumpMainThread(IsBreak: int) -> int:
|
||||
string.memset(_State.ContextBuf, 0, wp.CONTEXT.__sizeof__())
|
||||
ctx: wp.CONTEXT* = (wp.CONTEXT*)(_State.ContextBuf)
|
||||
ctx.ContextFlags = uint32(wp.CONTEXT_FULL)
|
||||
if wp.GetThreadContext(hThread, t.CPtr(_State.ContextBuf)) == 0:
|
||||
if wp.GetThreadContext(hThread, rawptr(_State.ContextBuf)) == 0:
|
||||
N = stdio.snprintf(_State.LineBuf, sizet(TRACEBACK_LINE_CAP),
|
||||
" fallback: GetThreadContext failed (GetLastError=%u), cannot dump stack\n",
|
||||
GetLastError())
|
||||
@@ -1749,8 +1748,8 @@ def DumpMainThread(IsBreak: int) -> int:
|
||||
# shrink the dump whenever dbghelp fails. Locals only: the handler thread allocates
|
||||
# nothing (same discipline as ScanStack's chunk buffers).
|
||||
SavedCount: int = _State.FrameCount
|
||||
SaveAddrBuf: t.CArray[uint64, TRACEBACK_FRAME_BUF]
|
||||
SaveScanBuf: t.CArray[int32, TRACEBACK_FRAME_BUF]
|
||||
SaveAddrBuf: [TRACEBACK_FRAME_BUF]uint64
|
||||
SaveScanBuf: [TRACEBACK_FRAME_BUF]int32
|
||||
for si in range(SavedCount):
|
||||
SaveAddrBuf[si] = _State.FrameAddr[si]
|
||||
SaveScanBuf[si] = _State.FrameScan[si]
|
||||
@@ -1832,11 +1831,10 @@ def DumpCrashThread(Info: VOIDPTR) -> int:
|
||||
EmitText("=== TPC crash dump (unhandled exception; the process keeps terminating) ===\n")
|
||||
HProc: HANDLE = wp.GetCurrentProcess()
|
||||
Rd: sizet = 0
|
||||
Two: t.CArray[uint64, 2] # [0] = EXCEPTION_RECORD*, [1] = CONTEXT* (EXCEPTION_POINTERS)
|
||||
Two: [2]uint64 # [0] = EXCEPTION_RECORD*, [1] = CONTEXT* (EXCEPTION_POINTERS)
|
||||
Two[0] = 0
|
||||
Two[1] = 0
|
||||
if wm.ReadProcessMemory(HProc, t.CPtr(Info), &Two, sizet(16), &Rd) == 0 \
|
||||
or sizet(Rd) < sizet(16):
|
||||
if wm.ReadProcessMemory(HProc, rawptr(Info), &Two, sizet(16), &Rd) == 0 or sizet(Rd) < sizet(16):
|
||||
EmitText(" fallback: EXCEPTION_POINTERS unreadable, crash dump skipped\n")
|
||||
AtomicLeaveDump()
|
||||
return 0
|
||||
@@ -1853,10 +1851,10 @@ def DumpCrashThread(Info: VOIDPTR) -> int:
|
||||
# u32[10..11] ExceptionInformation[1] (offset 0x28 = the faulting DATA address).
|
||||
# The two ExceptionInformation fields are only filled for access violations (code 0xC0000005);
|
||||
# they are printed unconditionally because a hard crash is exactly when raw numbers beat guesses.
|
||||
RecWords: t.CArray[uint32, 12]
|
||||
RecWords: [12]uint32
|
||||
RecWords[0] = 0
|
||||
if Rec != 0:
|
||||
if wm.ReadProcessMemory(HProc, t.CPtr(Rec), &RecWords, sizet(48), &Rd) != 0 \
|
||||
if wm.ReadProcessMemory(HProc, rawptr(Rec), &RecWords, sizet(48), &Rd) != 0 \
|
||||
and sizet(Rd) >= sizet(48):
|
||||
Code = RecWords[0]
|
||||
ExAddr = uint64(RecWords[4]) | (uint64(RecWords[5]) << 32)
|
||||
@@ -1871,9 +1869,7 @@ def DumpCrashThread(Info: VOIDPTR) -> int:
|
||||
EmitText(" fallback: CONTEXT pointer null, crash dump skipped\n")
|
||||
AtomicLeaveDump()
|
||||
return 0
|
||||
if wm.ReadProcessMemory(HProc, t.CPtr(CtxPtr), t.CPtr(_State.ContextBuf),
|
||||
wp.CONTEXT.__sizeof__(), &Rd) == 0 \
|
||||
or sizet(Rd) < sizet(wp.CONTEXT.__sizeof__()):
|
||||
if wm.ReadProcessMemory(HProc, rawptr(CtxPtr), rawptr(_State.ContextBuf), wp.CONTEXT.__sizeof__(), &Rd) == 0 or sizet(Rd) < sizet(wp.CONTEXT.__sizeof__()):
|
||||
EmitText(" fallback: CONTEXT unreadable, crash dump skipped\n")
|
||||
AtomicLeaveDump()
|
||||
return 0
|
||||
@@ -1906,7 +1902,7 @@ def DumpCrashThread(Info: VOIDPTR) -> int:
|
||||
# follow. The RBP chain and the stack scan stay as fallbacks, exactly as in the Ctrl+C path.
|
||||
Frames: int = 0
|
||||
if DbgHelpUsable() != 0:
|
||||
Frames = WalkViaDbgHelp(HProc, wp.GetCurrentThread(), t.CPtr(_State.ContextBuf), Base)
|
||||
Frames = WalkViaDbgHelp(HProc, wp.GetCurrentThread(), rawptr(_State.ContextBuf), Base)
|
||||
if Frames <= 1:
|
||||
_State.FrameCount = 0
|
||||
Frames = WalkRbpChain(Rip, Rbp, Base)
|
||||
@@ -1993,20 +1989,20 @@ def Install() -> int:
|
||||
return 0
|
||||
Plen: ULONG = wf.GetModuleFileNameA(None, Pb, ULONG(TRACEBACK_PATH_CAP))
|
||||
if Plen == 0 or sizet(Plen) >= sizet(TRACEBACK_PATH_CAP):
|
||||
stdlib.free(t.CPtr(Pb))
|
||||
stdlib.free(Pb)
|
||||
EmitEarly("[traceback] WARN: GetModuleFileNameA failed, ctrl handler not installed\n")
|
||||
return 0
|
||||
if sizet(Plen) + 16 > sizet(TRACEBACK_PATH_CAP):
|
||||
# 16 bytes of slack covers both ".stackmap" (10) and ".stackdump.txt" (16).
|
||||
stdlib.free(t.CPtr(Pb))
|
||||
stdlib.free(Pb)
|
||||
EmitEarly("[traceback] WARN: exe path too long to append suffix safely, ctrl handler not installed\n")
|
||||
return 0
|
||||
string.strcpy(str(Pb + int(Plen)), ".stackmap")
|
||||
# (2) sidecar existence = master switch (absent -> return immediately, no side effects).
|
||||
hFile: HANDLE = wf.CreateFileA(Pb, wf.GENERIC_READ, wf.FILE_SHARE_READ, t.CPtr(0), wf.OPEN_EXISTING, wf.FILE_ATTRIBUTE_NORMAL, t.CPtr(0))
|
||||
hFile: HANDLE = wf.CreateFileA(Pb, wf.GENERIC_READ, wf.FILE_SHARE_READ, None, wf.OPEN_EXISTING, wf.FILE_ATTRIBUTE_NORMAL, None)
|
||||
if hFile == INVALID_HANDLE_VALUE:
|
||||
Err0: ULONG = GetLastError()
|
||||
stdlib.free(t.CPtr(Pb))
|
||||
stdlib.free(Pb)
|
||||
if Err0 != ULONG(ERROR_FILE_NOT_FOUND):
|
||||
EmitEarlyCode("[traceback] WARN: cannot open <exe>.stackmap, ctrl handler not installed ", Err0)
|
||||
return 0
|
||||
@@ -2015,14 +2011,14 @@ def Install() -> int:
|
||||
# __sizeof__() allocation below covers them and the memset zeroes FrameCount.
|
||||
_State = stdlib.malloc(TracebackState.__sizeof__())
|
||||
if _State == None:
|
||||
stdlib.free(t.CPtr(Pb))
|
||||
stdlib.free(Pb)
|
||||
CloseHandle(hFile)
|
||||
EmitEarly("[traceback] WARN: state alloc failed, ctrl handler not installed\n")
|
||||
return 0
|
||||
string.memset(_State, 0, TracebackState.__sizeof__())
|
||||
_State.LineBuf = stdlib.malloc(TRACEBACK_LINE_CAP)
|
||||
_State.ContextBuf = t.CPtr(stdlib.calloc(1, wp.CONTEXT.__sizeof__()))
|
||||
_State.FrameBuf = t.CPtr(stdlib.calloc(1, dbg.STACKFRAME64.__sizeof__()))
|
||||
_State.ContextBuf = rawptr(stdlib.calloc(1, wp.CONTEXT.__sizeof__()))
|
||||
_State.FrameBuf = rawptr(stdlib.calloc(1, dbg.STACKFRAME64.__sizeof__()))
|
||||
_State.OutHandle = wf.GetStdHandle(wf.STD_ERROR_HANDLE)
|
||||
if _State.OutHandle == None or _State.OutHandle == INVALID_HANDLE_VALUE:
|
||||
_State.OutHandle = wf.GetStdHandle(wf.STD_OUTPUT_HANDLE)
|
||||
@@ -2033,7 +2029,7 @@ def Install() -> int:
|
||||
# Name the missing buffer now (not later in the callback thread); any missing buffer makes
|
||||
# Install return 0. _State exists here, so EmitEarly forwards to EmitText; if LineBuf is
|
||||
# the missing one, EmitEarly falls back to a direct WriteFile and the notice is not lost.
|
||||
stdlib.free(t.CPtr(Pb))
|
||||
stdlib.free(Pb)
|
||||
CloseHandle(hFile)
|
||||
if _State.LineBuf == None:
|
||||
EmitEarly("[traceback] WARN: LineBuf alloc failed, ctrl handler not installed\n")
|
||||
@@ -2049,7 +2045,7 @@ def Install() -> int:
|
||||
# written too. Raw UTF-8 bytes, unaffected by the console code page; kept open for the
|
||||
# whole process lifetime.
|
||||
string.strcpy(str(Pb + int(Plen)), ".stackdump.txt")
|
||||
_DumpFile = wf.CreateFileA(Pb, TRACEBACK_FILE_APPEND_DATA, wf.FILE_SHARE_READ | wf.FILE_SHARE_WRITE, t.CPtr(0), wf.OPEN_ALWAYS, wf.FILE_ATTRIBUTE_NORMAL, t.CPtr(0))
|
||||
_DumpFile = wf.CreateFileA(Pb, TRACEBACK_FILE_APPEND_DATA, wf.FILE_SHARE_READ | wf.FILE_SHARE_WRITE, None, wf.OPEN_ALWAYS, wf.FILE_ATTRIBUTE_NORMAL, None)
|
||||
if _DumpFile == INVALID_HANDLE_VALUE:
|
||||
_DumpFile = None
|
||||
EmitText("[traceback] WARN: cannot open stack dump file, console-only output\n")
|
||||
@@ -2065,7 +2061,7 @@ def Install() -> int:
|
||||
else:
|
||||
LoadMapFile(hFile, int64(Sz.QuadPart))
|
||||
CloseHandle(hFile)
|
||||
stdlib.free(t.CPtr(Pb))
|
||||
stdlib.free(Pb)
|
||||
# (5) dbghelp initialization (must happen here: Install runs at startup on the main thread,
|
||||
# while the Ctrl+C/Break callbacks run on new threads where dbghelp's module enumeration
|
||||
# may be unavailable) + the two cross-module callback addresses, resolved dynamically.
|
||||
|
||||
+2
-8
@@ -1,7 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
|
||||
|
||||
class Buf:
|
||||
data: char*
|
||||
length: sizet
|
||||
@@ -32,13 +28,11 @@ class Buf:
|
||||
if self.length < self.capacity: self.data[self.length] = 0
|
||||
return n
|
||||
|
||||
def cstr(self) -> char*:
|
||||
return self.data
|
||||
def cstr(self) -> char*: return self.data
|
||||
|
||||
def reset(self):
|
||||
self.length = 0
|
||||
if self.data != None and self.capacity > 0:
|
||||
self.data[0] = 0
|
||||
if self.data != None and self.capacity > 0: self.data[0] = 0
|
||||
|
||||
def __enter__(self) -> Buf*: return self
|
||||
def __exit__(self): self.reset()
|
||||
|
||||
+4
-5
@@ -1,6 +1,5 @@
|
||||
import viperio
|
||||
from stdarg import arg
|
||||
import t
|
||||
|
||||
|
||||
define TEMP_BUF_SIZE = 68
|
||||
@@ -39,8 +38,8 @@ def _check_special_float(fv: double) -> int:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
# The 4th parameter MUST stay named `args`: the printf wrappers forward their own va_list pointer
|
||||
# here (vprintf style), and the `arg()` sugar resolves the forwarded va_list by that name.
|
||||
# The 4th parameter MUST stay named `args`: the printf wrappers forward their own va_list pointer
|
||||
# here (vprintf style), and the `arg()` sugar resolves the forwarded va_list by that name.
|
||||
export def vsnprintf(buf: bytes, size: sizet, fmt: str, args: str) -> int:
|
||||
if fmt is None: return 0
|
||||
# Length detection mode: when buf is None, only calculate the formatted length, without actually writing
|
||||
@@ -138,7 +137,7 @@ export def vsnprintf(buf: bytes, size: sizet, fmt: str, args: str) -> int:
|
||||
else:
|
||||
ptr_i: int = arg()
|
||||
elif *fmt == 115:
|
||||
s: str = arg(t.CPtr)
|
||||
s: str = arg(rawptr)
|
||||
if s is None: s = "(None)"
|
||||
slen: int = 0
|
||||
sc: str = s
|
||||
@@ -481,7 +480,7 @@ export def vsnprintf(buf: bytes, size: sizet, fmt: str, args: str) -> int:
|
||||
ptr += _step
|
||||
pad_count -= 1
|
||||
elif *fmt == 112:
|
||||
ptr_val: uint64 = uint64(arg(t.CPtr))
|
||||
ptr_val: uint64 = uint64(arg(rawptr))
|
||||
if ptr_val == 0:
|
||||
temp[0] = 40
|
||||
temp[1] = 110
|
||||
|
||||
+1
-1
@@ -623,7 +623,7 @@ vzeroupper""",
|
||||
op=[ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm2', 'rcx', 'r8', 'r10'])
|
||||
|
||||
|
||||
def simd_dot_array(a: t.CPtr, b: t.CPtr, n: sizet, out: t.CPtr):
|
||||
def simd_dot_array(a: double*, b: double*, n: sizet, out: double):
|
||||
"""AVX2 batch: out[0] = dot(a[0:n], b[0:n]) using FMA accumulation"""
|
||||
__asm__(f"""mov rcx, {asminp(n, ASM_DESCR.REG_ANY)}
|
||||
shr rcx, 2
|
||||
|
||||
+3
-3
@@ -13,12 +13,12 @@ from rwlock import RWLock
|
||||
class Thread:
|
||||
"""Thread class, wraps Windows CreateThread.
|
||||
|
||||
Thread callback signature: def thread_func(arg: t.CPtr) -> t.CPtr
|
||||
Thread callback signature: def thread_func(arg: rawptr) -> rawptr
|
||||
Note: Windows API limits the return value to DWORD (32-bit), so 64-bit pointers will be truncated.
|
||||
If you need to return a 64-bit result, pass it via the arg parameter struct.
|
||||
|
||||
Usage:
|
||||
def worker(arg: t.CPtr) -> t.CPtr:
|
||||
def worker(arg: rawptr) -> rawptr:
|
||||
# thread logic
|
||||
return NULL
|
||||
|
||||
@@ -84,7 +84,7 @@ class local:
|
||||
Usage:
|
||||
tls: local = local()
|
||||
tls.set(value_ptr)
|
||||
val: t.CPtr = tls.get()
|
||||
val: rawptr = tls.get()
|
||||
"""
|
||||
index: ULONG
|
||||
|
||||
|
||||
Reference in new issue
Block a user