1467 lines
52 KiB
Python
1467 lines
52 KiB
Python
"""pagedoo shop CHAOS VM(108 opcode)纯 Python 移植 — mall PlaceOrder 加密地基。
|
|
|
|
对应浏览器 `p_5c660516.*` chunk 内的 `__TENCENT_CHAOS_VM`(pagedoo 变体,108 opcode 0..107)。
|
|
与 goods 侧(pyvm/algorithm.py,116 opcode)同属 CHAOS VM 家族:语义相同,opcode 编号不同(F-2055)。
|
|
JS 语义辅助复用 algorithm.py(_ic/i32/js_add/js_index/JSObject/JSFunction 等)。
|
|
|
|
当前验证锚点:
|
|
- 帧 e215058(encodeURI + %XX 解码 → 字节数组):Node 重放返回输入 JSON 串的 UTF-8 字节(F-2059)
|
|
- 帧 e377650 变换核心:Node 指令级复现(F-2060,254937/254938 一致)
|
|
输出编排帧链(e454218/e423160 getter 链)仍依赖 VM C 栈续延语义,见 cases/yyb-chaos-vm-xmidas-webnewencrypt.md 未决项。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import math
|
|
from pathlib import Path
|
|
|
|
from .algorithm import (
|
|
UNDEF,
|
|
HostFunction,
|
|
JSDate,
|
|
JSFunction,
|
|
JSObject,
|
|
Window,
|
|
_ic,
|
|
h_decodeuri,
|
|
h_decodeuricomponent,
|
|
h_encodeuri,
|
|
h_encodeuricomponent,
|
|
h_isnan,
|
|
h_math_abs,
|
|
h_math_ceil,
|
|
h_math_floor,
|
|
h_math_max,
|
|
h_math_min,
|
|
h_math_pow,
|
|
h_math_round,
|
|
h_math_sqrt,
|
|
h_new_date,
|
|
h_parsefloat,
|
|
h_parseint,
|
|
h_string_fromcharcode,
|
|
i32,
|
|
js_add,
|
|
js_apply,
|
|
js_call,
|
|
js_del,
|
|
js_eq,
|
|
js_index,
|
|
js_keys,
|
|
js_new,
|
|
js_num,
|
|
js_set,
|
|
js_str,
|
|
js_truthy,
|
|
js_typeof,
|
|
shl,
|
|
shr,
|
|
ushr,
|
|
)
|
|
|
|
REPLAY = Path(__file__).resolve().parent.parent / "replay"
|
|
|
|
__all__ = ["REPLAY", "PagedooVM", "run_frame"]
|
|
|
|
|
|
# ---------------------------------------------------------------- 辅助
|
|
|
|
|
|
def _cmp_lt(a, b):
|
|
try:
|
|
return a < b
|
|
except Exception: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
|
return False
|
|
|
|
|
|
def _cmp_le(a, b):
|
|
try:
|
|
return a <= b
|
|
except Exception: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
|
return False
|
|
|
|
|
|
def _cmp_gt(a, b):
|
|
try:
|
|
return a > b
|
|
except Exception: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
|
return False
|
|
|
|
|
|
def _cmp_ge(a, b):
|
|
try:
|
|
return a >= b
|
|
except Exception: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
|
return False
|
|
|
|
|
|
# ---------------------------------------------------------------- 宿主函数
|
|
|
|
|
|
def h_arr_push(this, *args):
|
|
if this is UNDEF or this is None:
|
|
this = []
|
|
if len(args) == 1:
|
|
this.append(args[0])
|
|
else:
|
|
this.extend(args)
|
|
return len(this)
|
|
|
|
|
|
def h_arr_shift(this):
|
|
if not this:
|
|
return UNDEF
|
|
return this.pop(0)
|
|
|
|
|
|
def h_arr_join(this, sep=None):
|
|
if sep is None:
|
|
sep = ","
|
|
return sep.join("" if x is UNDEF or x is None else js_str(x) for x in this)
|
|
|
|
|
|
def h_arr_slice(this, a=None, b=None):
|
|
n = len(this)
|
|
if a is None or a is UNDEF:
|
|
a = 0
|
|
if b is None or b is UNDEF:
|
|
b = n
|
|
a = int(a) if not isinstance(a, float) or not math.isnan(a) else 0
|
|
b = int(b) if not isinstance(b, float) or not math.isnan(b) else n
|
|
if a < 0:
|
|
a = max(0, n + a)
|
|
if b < 0:
|
|
b = max(0, n + b)
|
|
return list(this[a:b])
|
|
|
|
|
|
def h_arr_indexof(this, x, frm=0):
|
|
try:
|
|
return this.index(x, frm)
|
|
except ValueError:
|
|
return -1
|
|
|
|
|
|
def h_arr_concat(this, *others):
|
|
out = list(this)
|
|
for o in others:
|
|
if isinstance(o, list):
|
|
out.extend(o)
|
|
else:
|
|
out.append(o)
|
|
return out
|
|
|
|
|
|
def h_arr_pop(this):
|
|
if not this:
|
|
return UNDEF
|
|
return this.pop()
|
|
|
|
|
|
def h_arr_unshift(this, *vals):
|
|
for v in reversed(vals):
|
|
this.insert(0, v)
|
|
return len(this)
|
|
|
|
|
|
def h_arr_reverse(this):
|
|
this.reverse()
|
|
return this
|
|
|
|
|
|
def h_arr_splice(this, start, delete_count=0, *items):
|
|
n = len(this)
|
|
if start < 0:
|
|
start = max(0, n + start)
|
|
if delete_count is UNDEF or delete_count is None:
|
|
delete_count = n - start
|
|
removed = this[start : start + delete_count]
|
|
del this[start : start + delete_count]
|
|
for i, it in enumerate(items):
|
|
this.insert(start + i, it)
|
|
return removed
|
|
|
|
|
|
def h_arr_map(this, fn):
|
|
return [js_call(fn, UNDEF, [x]) for x in this]
|
|
|
|
|
|
def h_arr_foreach(this, fn):
|
|
for x in this:
|
|
js_call(fn, UNDEF, [x])
|
|
return UNDEF
|
|
|
|
|
|
def h_arr_filter(this, fn):
|
|
return [x for x in this if js_truthy(js_call(fn, UNDEF, [x]))]
|
|
|
|
|
|
def h_char_code_at(this, s, i=0):
|
|
if isinstance(this, str) and isinstance(s, int) and 0 <= s < len(this):
|
|
return ord(this[s])
|
|
return float("nan")
|
|
|
|
|
|
def h_char_at(this, i=0):
|
|
if isinstance(this, str) and isinstance(i, int) and 0 <= i < len(this):
|
|
return this[i]
|
|
return ""
|
|
|
|
|
|
def h_str_indexof(this, search, frm=0):
|
|
if not isinstance(this, str):
|
|
return -1
|
|
try:
|
|
return this.index(search, frm)
|
|
except ValueError:
|
|
return -1
|
|
|
|
|
|
def h_str_slice(this, a=None, b=None):
|
|
return this[a:b] if isinstance(this, str) else ""
|
|
|
|
|
|
def h_str_split(this, sep=None):
|
|
return this.split(sep) if isinstance(this, str) else [this]
|
|
|
|
|
|
def h_str_tolower(this):
|
|
return this.lower() if isinstance(this, str) else this
|
|
|
|
|
|
def h_str_toupper(this):
|
|
return this.upper() if isinstance(this, str) else this
|
|
|
|
|
|
def h_str_substr(this, start=0, length=None):
|
|
if not isinstance(this, str):
|
|
return ""
|
|
n = len(this)
|
|
if start < 0:
|
|
start = max(0, n + start)
|
|
if length is None or length is UNDEF:
|
|
return this[start:]
|
|
return this[start : start + int(length)]
|
|
|
|
|
|
def h_str_substring(this, start=0, end=None):
|
|
if not isinstance(this, str):
|
|
return ""
|
|
if end is None or end is UNDEF:
|
|
end = len(this)
|
|
start = max(0, min(int(start), len(this)))
|
|
end = max(0, min(int(end), len(this)))
|
|
if start > end:
|
|
start, end = end, start
|
|
return this[start:end]
|
|
|
|
|
|
def h_str_tostring(this):
|
|
return js_str(this)
|
|
|
|
|
|
def h_object_ctor(this, *args):
|
|
if len(args) == 1 and args[0] is not UNDEF and args[0] is not None:
|
|
return args[0]
|
|
return JSObject()
|
|
|
|
|
|
def _js_to_py(v):
|
|
"""JSON.stringify 辅助:把 JS 值转 JSON 可序列化。"""
|
|
if v is UNDEF:
|
|
return None
|
|
if isinstance(v, list):
|
|
return [_js_to_py(x) for x in v]
|
|
if isinstance(v, JSObject):
|
|
keys = v._d if hasattr(v, "_d") else {}
|
|
return {
|
|
k: _js_to_py(val)
|
|
for k, val in (keys.items() if isinstance(keys, dict) else [])
|
|
}
|
|
if isinstance(v, Window):
|
|
return {}
|
|
return v
|
|
|
|
|
|
def _py_to_js(v):
|
|
if isinstance(v, dict):
|
|
o = JSObject()
|
|
for k, val in v.items():
|
|
o.set(k, _py_to_js(val))
|
|
return o
|
|
if isinstance(v, list):
|
|
return [_py_to_js(x) for x in v]
|
|
return v
|
|
|
|
|
|
def _pg_index(obj, key):
|
|
"""pagedoo 专用 js_index:补充字符串原型方法(goods 侧不需要)。"""
|
|
if isinstance(obj, JSDate):
|
|
if key == "getTime":
|
|
return HostFunction(
|
|
lambda this: this.t if isinstance(this, JSDate) else obj.t, "getTime"
|
|
)
|
|
if key == "toString":
|
|
return HostFunction(lambda this: str(this), "toString")
|
|
if key == "valueOf":
|
|
return HostFunction(
|
|
lambda this: this.t if isinstance(this, JSDate) else obj.t, "valueOf"
|
|
)
|
|
if isinstance(obj, str) and isinstance(key, str):
|
|
if key == "length":
|
|
return len(obj)
|
|
if key == "charCodeAt":
|
|
return HostFunction(h_char_code_at, "charCodeAt")
|
|
if key == "charAt":
|
|
return HostFunction(h_char_at, "charAt")
|
|
if key == "indexOf":
|
|
return HostFunction(h_str_indexof, "indexOf")
|
|
if key == "slice":
|
|
return HostFunction(h_str_slice, "slice")
|
|
if key == "split":
|
|
return HostFunction(h_str_split, "split")
|
|
if key == "toLowerCase":
|
|
return HostFunction(h_str_tolower, "toLowerCase")
|
|
if key == "toUpperCase":
|
|
return HostFunction(h_str_toupper, "toUpperCase")
|
|
if key == "toString":
|
|
return HostFunction(h_str_tostring, "toString")
|
|
if key == "substr":
|
|
return HostFunction(h_str_substr, "substr")
|
|
if key == "substring":
|
|
return HostFunction(h_str_substring, "substring")
|
|
return js_index(obj, key)
|
|
|
|
|
|
# ---------------------------------------------------------------- VM
|
|
|
|
|
|
class PagedooVM:
|
|
"""pagedoo CHAOS VM 解释器(108 opcode,0..107)。
|
|
|
|
bytecode: 字节码数组(如 vm/bytecode-478657.json)
|
|
constants: 常量数组(浏览器调用第 4 参,即 globals)
|
|
window: 宿主环境对象(JSObject/Window)
|
|
"""
|
|
|
|
def __init__(self, bytecode, constants, window, random_seed=None):
|
|
self.o = bytecode
|
|
self.constants = constants
|
|
self.window = window
|
|
self.inst_id = 0
|
|
self.use_init_c = False
|
|
self.init_c = None
|
|
self._root_this = UNDEF
|
|
self._host_log = []
|
|
import random as _r
|
|
|
|
self._random = _r
|
|
if random_seed is not None:
|
|
self._random.seed(random_seed)
|
|
self._hosts = self._build_hosts()
|
|
|
|
def _build_hosts(self):
|
|
m = {}
|
|
m["Math"] = JSObject()
|
|
m["Math"].set(
|
|
"random", HostFunction(lambda this: self._random.random(), "random")
|
|
)
|
|
m["Math"].set("floor", HostFunction(h_math_floor, "floor"))
|
|
m["Math"].set("round", HostFunction(h_math_round, "round"))
|
|
m["Math"].set("ceil", HostFunction(h_math_ceil, "ceil"))
|
|
m["Math"].set("min", HostFunction(h_math_min, "min"))
|
|
m["Math"].set("max", HostFunction(h_math_max, "max"))
|
|
m["Math"].set("abs", HostFunction(h_math_abs, "abs"))
|
|
m["Math"].set("pow", HostFunction(h_math_pow, "pow"))
|
|
m["Math"].set("sqrt", HostFunction(h_math_sqrt, "sqrt"))
|
|
m["parseInt"] = HostFunction(h_parseint, "parseInt")
|
|
m["parseFloat"] = HostFunction(h_parsefloat, "parseFloat")
|
|
m["isNaN"] = HostFunction(h_isnan, "isNaN")
|
|
m["encodeURI"] = HostFunction(h_encodeuri, "encodeURI")
|
|
m["encodeURIComponent"] = HostFunction(
|
|
h_encodeuricomponent, "encodeURIComponent"
|
|
)
|
|
m["decodeURI"] = HostFunction(h_decodeuri, "decodeURI")
|
|
m["decodeURIComponent"] = HostFunction(
|
|
h_decodeuricomponent, "decodeURIComponent"
|
|
)
|
|
m["String"] = JSObject()
|
|
m["String"].set(
|
|
"fromCharCode", HostFunction(h_string_fromcharcode, "fromCharCode")
|
|
)
|
|
m["Date"] = HostFunction(h_new_date, "Date")
|
|
m["Array"] = JSObject()
|
|
m["Array"].set(
|
|
"isArray", HostFunction(lambda this, x: isinstance(x, list), "isArray")
|
|
)
|
|
m["Object"] = HostFunction(h_object_ctor, "Object")
|
|
m["Number"] = HostFunction(
|
|
lambda this, x=None: js_num(x) if x is not None and x is not UNDEF else 0.0,
|
|
"Number",
|
|
)
|
|
m["Boolean"] = HostFunction(
|
|
lambda this, x=None: (
|
|
bool(js_truthy(x)) if x is not None and x is not UNDEF else False
|
|
),
|
|
"Boolean",
|
|
)
|
|
jso = JSObject()
|
|
jso.set(
|
|
"stringify",
|
|
HostFunction(
|
|
lambda this, x, *a: json.dumps(_js_to_py(x), ensure_ascii=False),
|
|
"stringify",
|
|
),
|
|
)
|
|
jso.set(
|
|
"parse", HostFunction(lambda this, s: _py_to_js(json.loads(s)), "parse")
|
|
)
|
|
m["JSON"] = jso
|
|
m["RegExp"] = HostFunction(lambda this, *a: JSObject(), "RegExp")
|
|
# Array.prototype 方法挂到 Array 对象上(VM 通过 i[A].push 等调用)
|
|
proto = JSObject()
|
|
for name, fn in [
|
|
("push", h_arr_push),
|
|
("shift", h_arr_shift),
|
|
("join", h_arr_join),
|
|
("slice", h_arr_slice),
|
|
("indexOf", h_arr_indexof),
|
|
("concat", h_arr_concat),
|
|
("pop", h_arr_pop),
|
|
("unshift", h_arr_unshift),
|
|
("reverse", h_arr_reverse),
|
|
("splice", h_arr_splice),
|
|
("map", h_arr_map),
|
|
("forEach", h_arr_foreach),
|
|
("filter", h_arr_filter),
|
|
]:
|
|
proto.set(name, HostFunction(fn, name))
|
|
m["Array.prototype"] = proto
|
|
return m
|
|
|
|
def host(self, name):
|
|
h = self.window.get(name)
|
|
if h is not UNDEF:
|
|
return h
|
|
return self._hosts.get(name, UNDEF)
|
|
|
|
def make(self, entry, args, s, n, t):
|
|
return JSFunction(self, entry, args, s, n, t)
|
|
|
|
# -- 原型方法查找:i[A].push(...) 形式,i[A] 是数组 --
|
|
def _arr_method(self, name):
|
|
p = self._hosts.get("Array.prototype")
|
|
if p is not UNDEF and isinstance(p, JSObject):
|
|
v = p.get(name)
|
|
if v is not UNDEF:
|
|
return v
|
|
return UNDEF
|
|
|
|
def run(self, fn: JSFunction, call_args, trace=None, csnap=None):
|
|
self.inst_id += 1
|
|
if trace is not None:
|
|
self._trace = trace
|
|
self._csnap = csnap
|
|
if self.use_init_c and self.init_c is not None:
|
|
C = self.init_c
|
|
self.use_init_c = False
|
|
else:
|
|
root_this = getattr(self, "_root_this", UNDEF)
|
|
C = [fn.s, fn.n, fn.args, root_this, call_args, fn, self.o, 0]
|
|
C = list(C)
|
|
p = UNDEF
|
|
u = fn.entry
|
|
d = [] # 异常续延栈(JS C)
|
|
t = UNDEF # 最近异常值(op3/op52)
|
|
o = self.o
|
|
l = fn.t # 异常处理器(JS l)
|
|
_get = _pg_index
|
|
_set = js_set
|
|
_arr = self._arr_method
|
|
|
|
while True:
|
|
try:
|
|
while True:
|
|
u += 1
|
|
op = o[u]
|
|
if (
|
|
op in (0, 4, 11, 18, 23, 26, 43, 44, 48, 50, 84, 107)
|
|
and len(self._host_log) < 2000
|
|
):
|
|
# 记录调用目标(简化)
|
|
_tgt = o[u + 2]
|
|
try:
|
|
_tv = C[_tgt] if 0 <= _tgt < len(C) else UNDEF
|
|
_tr = (
|
|
type(_tv).__name__
|
|
if not isinstance(
|
|
_tv, (int, float, str, bool, type(None))
|
|
)
|
|
else repr(_tv)[:30]
|
|
)
|
|
self._host_log.append((op, u, _tr))
|
|
except Exception: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
|
self._host_log.append((op, u, "?"))
|
|
if (
|
|
getattr(self, "_trace", None) is not None
|
|
and len(self._trace) < 500000
|
|
):
|
|
self._trace.append((op, u))
|
|
if self._csnap is not None and len(self._csnap) < 500:
|
|
snap = []
|
|
for _si in range(min(42, len(C))):
|
|
_v = C[_si]
|
|
if isinstance(_v, str):
|
|
snap.append("s:" + _v[:30])
|
|
elif isinstance(_v, list):
|
|
snap.append(f"a[{len(_v)}]")
|
|
elif _v is UNDEF:
|
|
snap.append("u")
|
|
elif _v is None:
|
|
snap.append("n")
|
|
elif isinstance(_v, (int, float, bool)):
|
|
snap.append(_v)
|
|
else:
|
|
snap.append("o")
|
|
self._csnap.append((op, u, snap))
|
|
# ---------------- opcode dispatch(108,逐条对照 interpreter-clean.js)----------------
|
|
# 约定:S() 读下一个槽索引操作数并取 C[slot];imm 直接读。
|
|
if op == 0:
|
|
# for(h=[],f=c[++u];f>0;f--)h.push(i[c[++u]]);i[A]=i[B].apply(i[C],h)
|
|
f = o[u + 1]
|
|
u += 1
|
|
h = []
|
|
for _ in range(f):
|
|
h.append(_get(C, o[u + 1]))
|
|
u += 1
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, js_apply(_get(C, b), _get(C, c), h))
|
|
elif op == 1:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, js_num(_get(C, b)) - js_num(_get(C, c)))
|
|
elif op == 2:
|
|
a = o[u + 1]
|
|
u += 1
|
|
_set(C, a, False)
|
|
elif op == 3:
|
|
a = o[u + 1]
|
|
u += 1
|
|
_set(C, a, t)
|
|
elif op == 4:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
dd = o[u + 4]
|
|
u += 4
|
|
_set(C, a, js_call(_get(C, b), p, [_get(C, c), _get(C, dd)]))
|
|
elif op == 5:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
u += 2
|
|
_set(C, a, _get(C, b))
|
|
c = o[u + 1]
|
|
dd = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
_set(C, c, _get(_get(C, dd), imm))
|
|
e = o[u + 1]
|
|
u += 1
|
|
_set(C, e, "")
|
|
elif op == 6:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, _cmp_lt(js_num(_get(C, b)), js_num(_get(C, c))))
|
|
elif op == 7:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, js_del(_get(C, b), _get(C, c)))
|
|
elif op == 8:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm1 = o[u + 3]
|
|
u += 3
|
|
_set(C, a, _get(_get(C, b), imm1))
|
|
c = o[u + 1]
|
|
dd = o[u + 2]
|
|
imm2 = o[u + 3]
|
|
u += 3
|
|
_set(C, c, _get(_get(C, dd), imm2))
|
|
elif op == 9:
|
|
if d:
|
|
d.pop()
|
|
elif op == 10:
|
|
f = o[u + 1]
|
|
u += 1
|
|
h = []
|
|
for _ in range(f):
|
|
h.append(_get(C, o[u + 1]))
|
|
u += 1
|
|
dest = o[u + 1]
|
|
off = o[u + 2]
|
|
u += 2
|
|
_set(C, dest, self.make(u + off, h, C[0], C[1], l))
|
|
elif op == 11:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, js_call(_get(C, b), p, [_get(C, c)]))
|
|
elif op == 12:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
_set(C, a, shl(js_num(_get(C, b)), imm))
|
|
elif op == 13:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
dd = o[u + 4]
|
|
e = o[u + 5]
|
|
u += 5
|
|
_set(C, a, _get(C, b))
|
|
v = _cmp_lt(js_num(_get(C, dd)), js_num(_get(C, e)))
|
|
_set(C, c, v)
|
|
u0 = u
|
|
if js_truthy(v):
|
|
u = u0 + o[u0 + 1]
|
|
else:
|
|
u = u0 + o[u0 + 2]
|
|
elif op == 14:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, i32(_ic(_get(C, b))) | i32(_ic(_get(C, c))))
|
|
elif op == 15:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
_set(C, a, js_num(_get(C, b)) - imm)
|
|
elif op == 16:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
u += 2
|
|
_set(C, a, js_new(_get(C, b), []))
|
|
elif op == 17:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
_set(C, a, "")
|
|
_set(C, b, js_str(_get(C, b)) + chr(imm & 0xFFFF))
|
|
elif op == 18:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
dd = o[u + 4]
|
|
e = o[u + 5]
|
|
f = o[u + 6]
|
|
u += 6
|
|
_set(
|
|
C,
|
|
a,
|
|
js_call(
|
|
_get(C, b),
|
|
_get(C, c),
|
|
[_get(C, dd), _get(C, e), _get(C, f)],
|
|
),
|
|
)
|
|
elif op == 19:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
u += 2
|
|
_set(C, a, _get(C, b))
|
|
c = o[u + 1]
|
|
imm = o[u + 2]
|
|
u += 2
|
|
_set(C, c, imm)
|
|
dd = o[u + 1]
|
|
e = o[u + 2]
|
|
u += 2
|
|
_set(C, dd, _get(C, e))
|
|
elif op == 20:
|
|
a = o[u + 1]
|
|
u += 1
|
|
_set(C, a, "")
|
|
elif op == 21:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, _get(_get(C, b), _get(C, c)))
|
|
dd = o[u + 1]
|
|
e = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
v = _cmp_gt(js_num(_get(C, e)), imm)
|
|
_set(C, dd, v)
|
|
u0 = u
|
|
if js_truthy(v):
|
|
u = u0 + o[u0 + 1]
|
|
else:
|
|
u = u0 + o[u0 + 2]
|
|
elif op == 22:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, js_num(_get(C, b)) * js_num(_get(C, c)))
|
|
elif op == 23:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
dd = o[u + 4]
|
|
u += 4
|
|
_set(C, a, js_call(_get(C, b), _get(C, c), [_get(C, dd)]))
|
|
elif op == 24:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
u += 2
|
|
_set(C, a, js_num(_get(C, b)))
|
|
c = o[u + 1]
|
|
dd = o[u + 2]
|
|
u += 2
|
|
_set(C, c, js_num(_get(C, dd)) + 1)
|
|
e = o[u + 1]
|
|
f = o[u + 2]
|
|
u += 2
|
|
_set(C, e, _get(C, f))
|
|
elif op == 25:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
dd = o[u + 4]
|
|
e = o[u + 5]
|
|
u += 5
|
|
_set(
|
|
C,
|
|
a,
|
|
js_new(_get(C, b), [_get(C, c), _get(C, dd), _get(C, e)]),
|
|
)
|
|
elif op == 26:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, _get(_get(C, b), _get(C, c)))
|
|
dd = o[u + 1]
|
|
e = o[u + 2]
|
|
f = o[u + 3]
|
|
g = o[u + 4]
|
|
u += 4
|
|
_set(C, dd, js_call(_get(C, e), _get(C, f), [_get(C, g)]))
|
|
hh = o[u + 1]
|
|
ii = o[u + 2]
|
|
j = o[u + 3]
|
|
kk = o[u + 4]
|
|
ll = o[u + 5]
|
|
u += 5
|
|
_set(
|
|
C,
|
|
hh,
|
|
js_call(
|
|
_get(C, ii), _get(C, j), [_get(C, kk), _get(C, ll)]
|
|
),
|
|
)
|
|
elif op == 27:
|
|
a = o[u + 1]
|
|
n = o[u + 2]
|
|
u += 2
|
|
_set(C, a, [UNDEF] * int(n))
|
|
elif op == 28:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, i32(_ic(_get(C, b))) ^ i32(_ic(_get(C, c))))
|
|
elif op == 29:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
_set(C, a, _cmp_gt(js_num(_get(C, b)), imm))
|
|
elif op == 30:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, i32(_ic(_get(C, b))) & i32(_ic(_get(C, c))))
|
|
elif op == 31:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
u += 2
|
|
_set(C, a, _get(C, b))
|
|
c = o[u + 1]
|
|
dd = o[u + 2]
|
|
u += 2
|
|
_set(C, c, js_num(_get(C, dd)))
|
|
e = o[u + 1]
|
|
f = o[u + 2]
|
|
u += 2
|
|
_set(C, e, js_num(_get(C, f)) + 1)
|
|
elif op == 32:
|
|
# u += i[A] ? c[++u] : c[(++u,++u)] —— LHS u 在 body 开始读取
|
|
u0 = u
|
|
a = o[u0 + 1]
|
|
if js_truthy(_get(C, a)):
|
|
u = u0 + o[u0 + 2]
|
|
else:
|
|
u = u0 + o[u0 + 3]
|
|
elif op == 33:
|
|
a = o[u + 1]
|
|
imm = o[u + 2]
|
|
u += 2
|
|
_set(C, a, js_str(_get(C, a)) + chr(imm & 0xFFFF))
|
|
b = o[u + 1]
|
|
c = o[u + 2]
|
|
dd = o[u + 3]
|
|
u += 3
|
|
_set(C, b, _get(_get(C, c), _get(C, dd)))
|
|
elif op == 34:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
u += 2
|
|
_set(C, a, js_typeof(_get(C, b)))
|
|
elif op == 35:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, _cmp_le(js_num(_get(C, b)), js_num(_get(C, c))))
|
|
elif op == 36:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
u += 2
|
|
_set(C, a, -js_num(_get(C, b)))
|
|
elif op == 37:
|
|
a = o[u + 1]
|
|
u += 1
|
|
_set(C, a, True)
|
|
elif op == 38:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(
|
|
C,
|
|
a,
|
|
isinstance(_get(C, b), type(_get(C, c)))
|
|
if isinstance(_get(C, c), type)
|
|
else False,
|
|
)
|
|
elif op == 39:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
_set(C, a, js_add(_get(C, b), imm))
|
|
elif op == 40:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
js_set(_get(C, a), _get(C, b), _get(C, c))
|
|
elif op == 41:
|
|
a = o[u + 1]
|
|
imm = o[u + 2]
|
|
u += 2
|
|
_set(C, a, imm)
|
|
b = o[u + 1]
|
|
u += 1
|
|
_set(C, b, _get(C, b))
|
|
c = o[u + 1]
|
|
dd = o[u + 2]
|
|
e = o[u + 3]
|
|
u += 3
|
|
_set(C, c, _cmp_lt(js_num(_get(C, dd)), js_num(_get(C, e))))
|
|
elif op == 42:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, js_num(_get(C, b)) / js_num(_get(C, c)))
|
|
elif op == 43:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
dd = o[u + 4]
|
|
e = o[u + 5]
|
|
u += 5
|
|
_set(
|
|
C,
|
|
a,
|
|
js_call(_get(C, b), _get(C, c), [_get(C, dd), _get(C, e)]),
|
|
)
|
|
elif op == 44:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
u += 2
|
|
_bv = _get(C, b)
|
|
if getattr(self, "_dbg_u", None) == u:
|
|
print(
|
|
f" [dbg] op44@{u}: A={a} B={b} i[B]={type(_bv).__name__}: {str(_bv)[:80]}"
|
|
)
|
|
_set(C, a, js_call(_bv, p, []))
|
|
elif op == 45:
|
|
a = o[u + 1]
|
|
u += 1
|
|
_set(C, a, p)
|
|
b = o[u + 1]
|
|
n = o[u + 2]
|
|
u += 2
|
|
_set(C, b, [UNDEF] * int(n))
|
|
c = o[u + 1]
|
|
u += 1
|
|
_set(C, c, "")
|
|
elif op == 46:
|
|
a = o[u + 1]
|
|
u += 1
|
|
obj = JSObject()
|
|
_set(C, a, obj)
|
|
b = o[u + 1]
|
|
imm = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
js_set(_get(C, b), imm, _get(C, c))
|
|
dd = o[u + 1]
|
|
imm2 = o[u + 2]
|
|
e = o[u + 3]
|
|
u += 3
|
|
js_set(_get(C, dd), imm2, _get(C, e))
|
|
elif op == 47:
|
|
a = o[u + 1]
|
|
imm = o[u + 2]
|
|
u += 2
|
|
_set(C, a, js_str(_get(C, a)) + chr(imm & 0xFFFF))
|
|
elif op == 48:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
dd = o[u + 4]
|
|
u += 4
|
|
_set(C, a, js_call(_get(C, b), _get(C, c), [_get(C, dd)]))
|
|
e = o[u + 1]
|
|
f = o[u + 2]
|
|
g = o[u + 3]
|
|
hh = o[u + 4]
|
|
ii = o[u + 5]
|
|
j = o[u + 6]
|
|
u += 6
|
|
_set(
|
|
C,
|
|
e,
|
|
js_call(_get(C, f), _get(C, g), [_get(C, hh), _get(C, ii)]),
|
|
)
|
|
return _get(C, j)
|
|
elif op == 49:
|
|
a = o[u + 1]
|
|
u += 1
|
|
_set(C, a, JSObject())
|
|
elif op == 50:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
dd = o[u + 4]
|
|
u += 4
|
|
_set(C, a, js_call(_get(C, b), p, [_get(C, c), _get(C, dd)]))
|
|
elif op == 51:
|
|
a = o[u + 1]
|
|
imm = o[u + 2]
|
|
u += 2
|
|
_set(C, a, js_str(_get(C, a)) + chr(imm & 0xFFFF))
|
|
f = o[u + 1]
|
|
u += 1
|
|
h = []
|
|
for _ in range(f):
|
|
h.append(_get(C, o[u + 1]))
|
|
u += 1
|
|
dest = o[u + 1]
|
|
off = o[u + 2]
|
|
u += 2
|
|
frame = self.make(u + off, h, C[0], C[1], l)
|
|
_set(C, dest, frame)
|
|
b = o[u + 1]
|
|
c = o[u + 2]
|
|
e = o[u + 3]
|
|
u += 3
|
|
js_set(_get(C, b), _get(C, c), _get(C, e))
|
|
elif op == 52:
|
|
t = _get(C, o[u + 1])
|
|
u += 1
|
|
raise _VMThrow(t)
|
|
elif op == 53:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
u += 2
|
|
_set(C, a, js_num(_get(C, b)))
|
|
elif op == 54:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
_set(C, a, _cmp_lt(js_num(_get(C, b)), imm))
|
|
elif op == 55:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, _get(_get(C, b), _get(C, c)))
|
|
elif op == 56:
|
|
# C.push(u+c[++u]) —— LHS u 在 c[++u] 前读取,且 u 推进 1
|
|
u0 = u
|
|
imm = o[u0 + 1]
|
|
d.append(u0 + imm)
|
|
u = u0 + 1
|
|
elif op == 57:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, _cmp_ge(js_num(_get(C, b)), js_num(_get(C, c))))
|
|
elif op == 58:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, js_eq(_get(C, b), _get(C, c)))
|
|
elif op == 59:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
u += 2
|
|
_set(C, a, js_keys(_get(C, b)))
|
|
elif op == 60:
|
|
u += o[u + 1]
|
|
elif op == 61:
|
|
a = o[u + 1]
|
|
imm = o[u + 2]
|
|
b = o[u + 3]
|
|
u += 3
|
|
js_set(_get(C, a), imm, _get(C, b))
|
|
elif op == 62:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
u += 2
|
|
_set(C, a, _get(C, b))
|
|
c = o[u + 1]
|
|
dd = o[u + 2]
|
|
e = o[u + 3]
|
|
u += 3
|
|
js_set(_get(C, c), _get(C, dd), _get(C, e))
|
|
elif op == 63:
|
|
return _get(C, o[u + 1])
|
|
elif op == 64:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
_set(C, a, _get(_get(C, b), imm))
|
|
c = o[u + 1]
|
|
u += 1
|
|
_set(C, c, "")
|
|
dd = o[u + 1]
|
|
imm2 = o[u + 2]
|
|
u += 2
|
|
_set(C, dd, js_str(_get(C, dd)) + chr(imm2 & 0xFFFF))
|
|
elif op == 65:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, shr(js_num(_get(C, b)), js_num(_get(C, c))))
|
|
elif op == 66:
|
|
a = o[u + 1]
|
|
imm1 = o[u + 2]
|
|
u += 2
|
|
_set(C, a, js_str(_get(C, a)) + chr(imm1 & 0xFFFF))
|
|
b = o[u + 1]
|
|
imm2 = o[u + 2]
|
|
u += 2
|
|
_set(C, b, js_str(_get(C, b)) + chr(imm2 & 0xFFFF))
|
|
elif op == 67:
|
|
a = o[u + 1]
|
|
u += 1
|
|
_set(C, a, p)
|
|
elif op == 68:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, _get(_get(C, b), _get(C, c)))
|
|
dd = o[u + 1]
|
|
e = o[u + 2]
|
|
u += 2
|
|
_set(C, dd, _get(C, e))
|
|
f = o[u + 1]
|
|
u += 1
|
|
_set(C, f, "")
|
|
elif op == 69:
|
|
a = o[u + 1]
|
|
imm = o[u + 2]
|
|
u += 2
|
|
_set(C, a, js_num(_get(C, a)) - imm)
|
|
b = o[u + 1]
|
|
c = o[u + 2]
|
|
dd = o[u + 3]
|
|
e = o[u + 4]
|
|
u += 4
|
|
_set(C, b, js_new(_get(C, c), [_get(C, dd), _get(C, e)]))
|
|
f = o[u + 1]
|
|
g = o[u + 2]
|
|
u += 2
|
|
_set(C, f, _get(C, g))
|
|
elif op == 70:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
_set(C, a, i32(_ic(_get(C, b))) | imm)
|
|
elif op == 71:
|
|
f = o[u + 1]
|
|
u += 1
|
|
h = []
|
|
for _ in range(f):
|
|
h.append(_get(C, o[u + 1]))
|
|
u += 1
|
|
dest = o[u + 1]
|
|
off = o[u + 2]
|
|
u += 2
|
|
_set(C, dest, self.make(u + off, h, C[0], C[1], l))
|
|
elif op == 72:
|
|
a = o[u + 1]
|
|
u += 1
|
|
_set(C, a, None)
|
|
elif op == 73:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
_set(C, a, i32(_ic(_get(C, b))) & imm)
|
|
elif op == 74:
|
|
a = o[u + 1]
|
|
imm1 = o[u + 2]
|
|
b = o[u + 3]
|
|
u += 3
|
|
js_set(_get(C, a), imm1, _get(C, b))
|
|
c = o[u + 1]
|
|
u += 1
|
|
obj = JSObject()
|
|
_set(C, c, obj)
|
|
dd = o[u + 1]
|
|
imm2 = o[u + 2]
|
|
e = o[u + 3]
|
|
u += 3
|
|
js_set(_get(C, dd), imm2, _get(C, e))
|
|
elif op == 75:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
_set(C, a, shr(js_num(_get(C, b)), imm))
|
|
elif op == 76:
|
|
a = o[u + 1]
|
|
imm = o[u + 2]
|
|
b = o[u + 3]
|
|
u += 3
|
|
_set(C, a, imm + js_num(_get(C, b)))
|
|
elif op == 77:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
dd = o[u + 4]
|
|
u += 4
|
|
_set(C, a, js_new(_get(C, b), [_get(C, c), _get(C, dd)]))
|
|
elif op == 78:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, ushr(js_num(_get(C, b)), js_num(_get(C, c))))
|
|
elif op == 79:
|
|
a = o[u + 1]
|
|
u += 1
|
|
_set(C, a, js_num(_get(C, a)) + 1)
|
|
elif op == 80:
|
|
a = o[u + 1]
|
|
imm = o[u + 2]
|
|
u += 2
|
|
_set(C, a, imm)
|
|
elif op == 81:
|
|
a = o[u + 1]
|
|
imm = o[u + 2]
|
|
b = o[u + 3]
|
|
u += 3
|
|
_set(C, a, imm - js_num(_get(C, b)))
|
|
elif op == 82:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, _cmp_gt(js_num(_get(C, b)), js_num(_get(C, c))))
|
|
elif op == 83:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
_set(C, a, ushr(js_num(_get(C, b)), imm))
|
|
elif op == 84:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, js_call(_get(C, b), _get(C, c), []))
|
|
elif op == 85:
|
|
a = o[u + 1]
|
|
imm1 = o[u + 2]
|
|
b = o[u + 3]
|
|
u += 3
|
|
js_set(_get(C, a), imm1, _get(C, b))
|
|
c = o[u + 1]
|
|
imm2 = o[u + 2]
|
|
dd = o[u + 3]
|
|
u += 3
|
|
js_set(_get(C, c), imm2, _get(C, dd))
|
|
e = o[u + 1]
|
|
u += 1
|
|
_set(C, e, "")
|
|
elif op == 86:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
u += 2
|
|
h = _get(C, a)
|
|
if h is not UNDEF and h is not None and len(h):
|
|
_set(C, b, True)
|
|
c = o[u + 1]
|
|
u += 1
|
|
_set(C, c, h.pop(0))
|
|
else:
|
|
_set(C, b, False)
|
|
u += 1
|
|
elif op == 87:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
_set(C, a, _get(_get(C, b), imm))
|
|
elif op == 88:
|
|
a = o[u + 1]
|
|
u += 1
|
|
_set(C, a, js_num(_get(C, a)) - 1)
|
|
elif op == 89:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, shl(js_num(_get(C, b)), js_num(_get(C, c))))
|
|
elif op == 90:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, js_eq(_get(C, b), _get(C, c)))
|
|
elif op == 91:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, js_new(_get(C, b), [_get(C, c)]))
|
|
elif op == 92:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
_set(C, a, _cmp_le(js_num(_get(C, b)), imm))
|
|
elif op == 93:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, js_num(_get(C, b)) % js_num(_get(C, c)))
|
|
elif op == 94:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
_set(C, a, i32(_ic(_get(C, b))) ^ imm)
|
|
elif op == 95:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, js_new(_get(C, b), [_get(C, c)]))
|
|
dd = o[u + 1]
|
|
e = o[u + 2]
|
|
u += 2
|
|
_set(C, dd, _get(C, e))
|
|
f = o[u + 1]
|
|
imm = o[u + 2]
|
|
u += 2
|
|
_set(C, f, imm)
|
|
elif op == 96:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
obj2 = _get(C, c)
|
|
_set(
|
|
C,
|
|
a,
|
|
_get(C, b) in obj2
|
|
if isinstance(obj2, (list, dict, JSObject))
|
|
else False,
|
|
)
|
|
elif op == 97:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
u += 2
|
|
_set(C, a, not js_truthy(_get(C, b)))
|
|
elif op == 98:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
_set(C, a, _cmp_ge(js_num(_get(C, b)), imm))
|
|
elif op == 99:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, js_add(_get(C, b), _get(C, c)))
|
|
elif op == 100:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm = o[u + 3]
|
|
u += 3
|
|
_set(C, a, _get(C, b) == imm)
|
|
elif op == 101:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
_set(C, a, js_eq(_get(C, b), _get(C, c)))
|
|
elif op == 102:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
u += 2
|
|
_set(C, a, _get(C, b))
|
|
elif op == 103:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
imm1 = o[u + 3]
|
|
u += 3
|
|
_set(C, a, _get(_get(C, b), imm1))
|
|
c = o[u + 1]
|
|
dd = o[u + 2]
|
|
u += 2
|
|
_set(C, c, _get(C, dd))
|
|
e = o[u + 1]
|
|
f = o[u + 2]
|
|
imm2 = o[u + 3]
|
|
u += 3
|
|
_set(C, e, _get(_get(C, f), imm2))
|
|
elif op == 104:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
u += 2
|
|
_set(C, a, js_num(_get(C, b)))
|
|
elif op == 105:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
c = o[u + 3]
|
|
u += 3
|
|
v = _get(_get(C, b), _get(C, c))
|
|
_set(C, a, v)
|
|
dd = o[u + 1]
|
|
e = o[u + 2]
|
|
f = o[u + 3]
|
|
u += 3
|
|
js_set(_get(C, dd), _get(C, e), _get(C, f))
|
|
u0 = u
|
|
u = u0 + o[u0 + 1]
|
|
elif op == 106:
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
u += 2
|
|
_set(C, a, ~i32(_ic(_get(C, b))))
|
|
elif op == 107:
|
|
f = o[u + 1]
|
|
u += 1
|
|
h = []
|
|
for _ in range(f):
|
|
h.append(_get(C, o[u + 1]))
|
|
u += 1
|
|
a = o[u + 1]
|
|
b = o[u + 2]
|
|
u += 2
|
|
_set(C, a, js_apply(_get(C, b), p, h))
|
|
else:
|
|
raise RuntimeError(f"未知 opcode {op} @u={u}")
|
|
|
|
except _VMThrow as ex:
|
|
t = ex.value
|
|
if d:
|
|
u = d.pop()
|
|
continue
|
|
if l is not UNDEF and l is not None:
|
|
return js_call(l, UNDEF, [t, C, []])
|
|
raise
|
|
except Exception:
|
|
if d:
|
|
u = d.pop()
|
|
continue
|
|
raise
|
|
|
|
|
|
class _VMThrow(Exception):
|
|
def __init__(self, value):
|
|
super().__init__("vm throw")
|
|
self.value = value
|
|
|
|
|
|
# ---------------------------------------------------------------- 便捷入口
|
|
|
|
|
|
def _mk_window(vmlog=None):
|
|
from .algorithm import Window
|
|
|
|
w = Window()
|
|
for k in ("window", "self", "globalThis", "top", "parent", "frames"):
|
|
w.set(k, w)
|
|
w.set("document", JSObject())
|
|
w.set("navigator", JSObject())
|
|
w.set("location", JSObject())
|
|
w.set("localStorage", JSObject())
|
|
w.set("sessionStorage", JSObject())
|
|
w.set("screen", JSObject())
|
|
w.set("history", JSObject())
|
|
w.set("XMLHttpRequest", HostFunction(lambda this, *a: None, "XHR"))
|
|
w.set("fetch", HostFunction(lambda this, *a: None, "fetch"))
|
|
return w
|
|
|
|
|
|
def run_frame(
|
|
entry, h, bytecode, constants, window=None, call_args=(), random_seed=None
|
|
):
|
|
"""便捷入口:用 pagedoo VM 执行指定 entry 的帧(h 为创建参数数组)。"""
|
|
if window is None:
|
|
window = _mk_window()
|
|
vm = PagedooVM(bytecode, constants, window, random_seed=random_seed)
|
|
# 挂宿主
|
|
for k, v in vm._hosts.items():
|
|
if k != "Array.prototype" and window.get(k) is UNDEF:
|
|
window.set(k, v)
|
|
frame = vm.make(entry, h, window, constants, None)
|
|
return vm.run(frame, list(call_args)), vm
|