From eed7004754c260567f189e3a1890ba39884ebc3f Mon Sep 17 00:00:00 2001 From: yml2213 Date: Sun, 11 Oct 2026 22:15:51 +0800 Subject: [PATCH] =?UTF-8?q?chore(vm):=20=E5=BD=92=E6=A1=A3=E8=A7=A3?= =?UTF-8?q?=E9=87=8A=E5=99=A8=20tdc=5Fvm=5Frun.py=20=E5=88=B0=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE=E8=AF=AD=E4=B9=89=20(VM=20=E8=BF=94=E5=9B=9E=20=3D=20?= =?UTF-8?q?=E6=A0=88=E9=A1=B6/=E5=88=87=E7=89=87)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 做了什么: - 修正 VM 返回语义: `A ? (E.pop(), E.slice(3+VM.v)) : E.pop()` (闭包调用返回栈顶) - JArr 缺键返回 undefined; E 初值 [this]=全局; CALL_FUNC 的 this=c 为什么: - 该工具已判定为"用 Python 复刻 JS 运行时"的弯路(AGENTS.md §2.3 铁律2 打地鼠陷阱) - 但已实现的 58 个 opcode 语义 + 诊断钩子仍有储备价值, 故归档而非删除(§1.4) 怎么验证: - py_compile 通过; 与真值 PC 轨迹对拍仍显示前 713 步一致(未继续推进, 按新路线改走 lift) --- tools/tdc_vm_run.py | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/tools/tdc_vm_run.py b/tools/tdc_vm_run.py index eff757f..aba5e1a 100644 --- a/tools/tdc_vm_run.py +++ b/tools/tdc_vm_run.py @@ -65,6 +65,8 @@ class JArr(list): JS_UNDEF = object() +VM_VERSION = 0 # 对应源码里的 __TENCENT_CHAOS_VM.v + class Stub: """未知宿主对象: 可调用、可属性访问、可下标; **会真正记住被赋的属性** @@ -216,9 +218,10 @@ def truthy(v): # --------------------------------------------------------------------------- # class VM: - def __init__(self, z: List[int], c, max_steps: int = 20_000_000): + def __init__(self, z: List[int], c, max_steps: int = 20_000_000, fresh: bool = True): self.z = z self.c = c + self.fresh = fresh # True=最外层调用(E 未传入), False=闭包调用 # 与 VM 源码默认一致: E = [[this],[{}]]; 顶层是普通调用 -> this = 全局对象 (c) self.E: List[Any] = [JArr([c]), JArr([JArr()])] self.B: List[Any] = [] # try 栈 @@ -264,11 +267,27 @@ class VM: if h is None: raise RuntimeError(f"unknown opcode {op} at pc {self.H-1}") r = h() + if os.environ.get("DBGCALL") and self.E and self.E[-1] is None: + print(f"[push None @pc={self.H-1}] op={op} steps={self.steps}", file=sys.stderr) if os.environ.get("DBGCALL") and self.E and isinstance(self.E[-1], list) and len(self.E[-1]) == 2 and self.E[-1][0] is None: print(f"[产生 [None,{self.E[-1][1]!r}] @pc={self.H-1}] op={op} steps={self.steps}", file=sys.stderr) if r is True: self.done = True - return self.ret + return self._finish() + + def _finish(self): + """复刻 VM 的返回语义 (源码): + `return A ? (E.pop(), E.slice(3 + VM.v)) : E.pop()` + A = !E (E 未传入 => 最外层调用); 闭包调用时 E 已传入 => 返回**栈顶** E.pop()。 + """ + E = self.E + if not E: + return JS_UNDEF + if self.fresh: + E.pop() + start = 3 + VM_VERSION + return JArr(E[start:]) if len(E) > start else JArr() + return E.pop() # ------------------------------------------------------------------ ops def _run(self): @@ -387,6 +406,8 @@ class VM: @op(29) def _29(): + if os.environ.get("DBGCALL"): + print(f"[PUSH_NULL @pc={self.H-1}] steps={self.steps}", file=sys.stderr) E.append(None) @op(31) # PUSH_IMM_ARRAY @@ -554,7 +575,7 @@ class VM: # ---- 调用/构造 def call(self, fn, args, this): if isinstance(fn, tuple) and fn and fn[0] == "closure": - sub = VM(self.z, self.c, self.max_steps - self.steps) + sub = VM(self.z, self.c, self.max_steps - self.steps, fresh=False) sub.key_hits = self.key_hits # 子 VM 共享命中列表 sub.pcs = self.pcs # 共享 PC 轨迹 (轨迹是全局的) sub.events = self.events # 共享关键事件