diff --git a/tools/tdc_vm_run.py b/tools/tdc_vm_run.py index 215a34e..eff757f 100644 --- a/tools/tdc_vm_run.py +++ b/tools/tdc_vm_run.py @@ -41,13 +41,16 @@ class JArr(list): self._ext: Dict[str, Any] = {} def __getitem__(self, k): + # JS 数组/对象: 缺失的属性是 undefined (不是 null!), 这点必须严格 if isinstance(k, int) or (isinstance(k, str) and k.lstrip("-").isdigit()): i = int(k) try: return list.__getitem__(self, i) except IndexError: - return None - return self._ext.get(k) + return JS_UNDEF + if k in self._ext: + return self._ext[k] + return JS_UNDEF def __setitem__(self, k, v): if isinstance(k, int) or (isinstance(k, str) and k.lstrip("-").isdigit()): @@ -216,7 +219,8 @@ class VM: def __init__(self, z: List[int], c, max_steps: int = 20_000_000): self.z = z self.c = c - self.E: List[Any] = [JArr([None]), JArr([JArr()])] # 与 VM 默认一致: [[this],[{}]] + # 与 VM 源码默认一致: E = [[this],[{}]]; 顶层是普通调用 -> this = 全局对象 (c) + self.E: List[Any] = [JArr([c]), JArr([JArr()])] self.B: List[Any] = [] # try 栈 self.w = None # 异常标志 self.H = 0 @@ -259,7 +263,10 @@ class VM: h = self.OP.get(op) if h is None: raise RuntimeError(f"unknown opcode {op} at pc {self.H-1}") - if h() is True: + r = h() + 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 @@ -391,7 +398,10 @@ class VM: a = E.pop() idx = E.pop() cell = E[idx[0]] if isinstance(idx, list) else E[idx] - E.append([cell[0] if isinstance(cell, list) and cell else JS_UNDEF, a]) + val = cell[0] if isinstance(cell, list) and cell else JS_UNDEF + if os.environ.get("DBGCALL") and (val is None or val is JS_UNDEF): + print(f"[MAKE_REG_PROP_REF @{self.H-1}] reg={idx[0] if isinstance(idx,list) else idx} val={val!r} cell={str(cell)[:40]}", file=sys.stderr) + E.append([val, a]) @op(34) # CALL_METHOD n def _34(): @@ -550,6 +560,11 @@ class VM: sub.events = self.events # 共享关键事件 sub.trace = self.trace sub.trace_full = self.trace_full + if os.environ.get("DBGCALL"): + print(f"[invoke closure target=@{fn[1]}] caps={fn[2]} params={fn[3]} args={[str(a)[:20] for a in args]}", file=sys.stderr) + for (q, r) in fn[2]: + src = self.E[r] if r < len(self.E) else "" + print(f" cap r{q} <- parent r{r} = {str(src)[:50]}", file=sys.stderr) sub.E = [JArr() for _ in range(32)] sub.E[0] = JArr([this]); sub.E[1] = JArr([JArr(args)]); sub.E[2] = JArr([fn]) for (q, r) in fn[2]: