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:
+24
-3
@@ -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 # 共享关键事件
|
||||
|
||||
Reference in New Issue
Block a user