chore(vm): 归档解释器 tdc_vm_run.py 到正确语义 (VM 返回 = 栈顶/切片)

做了什么:
- 修正 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)
This commit is contained in:
yml2213
2026-10-11 22:15:51 +08:00
parent 2e7aaff9ec
commit eed7004754
+24 -3
View File
@@ -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 # 共享关键事件