1use anyhow::{Result, bail};
2
3use std::collections::HashMap;
4
5use crate::model::{ConstPools, Tjs2File, Tjs2Object, Variant};
6use crate::vmcodes::vm;
7
8const NEG_REG_MAX: i32 = 8; const FAT_NORMAL: i32 = 0;
17const FAT_EXPAND: i32 = 1;
18const FAT_UNNAMED_EXPAND: i32 = 2;
19
20pub fn emit_executable_tjs(file: &Tjs2File) -> Result<String> {
21 let mut out = String::new();
22
23 out.push_str("// Generated by tjs2dec (experimental)\n");
24 out.push_str(
25 "// This is a low-level, semantics-oriented re-materialization of TJS2 bytecode.\n",
26 );
27
28 out.push_str("function __tjs2dec_truthy(v) { return v ? true : false; }\n");
29 out.push_str("function __tjs2dec_to_int(v) { v = Number(v); if (isNaN(v)) return 0; return v < 0 ? Math.ceil(v) : Math.floor(v); }\n");
30 out.push_str("function __tjs2dec_idiv(a,b) { a = Number(a); b = Number(b); if (b == 0) return 0; var q = a / b; return q < 0 ? Math.ceil(q) : Math.floor(q); }\n");
31 out.push_str("function __tjs2dec_get_prop(o, k, ignore) { return ignore ? &(o[k]) : o[k]; }\n");
32 out.push_str("function __tjs2dec_set_prop(o, k, v, ignore) { if (ignore) &(o[k]) = v; else o[k] = v; }\n");
33 out.push_str("function __tjs2dec_del_prop(o, k) { return delete o[k]; }\n");
34 out.push_str("function __tjs2dec_expand_args(dst, v) {\n");
35 out.push_str(" if (v == void) return;\n");
36 out.push_str(" // Best-effort expansion: treat Array-like values as sequences.\n");
37 out.push_str(" if (v instanceof Array) {\n");
38 out.push_str(" for (var i = 0; i < v.length; i++) dst.push(v[i]);\n");
39 out.push_str(" return;\n");
40 out.push_str(" }\n");
41 out.push_str(" // If the value is not an Array, push it as-is.\n");
42 out.push_str(" dst.push(v);\n");
43 out.push_str("}\n\n");
44
45 out.push_str("var __tjs2dec_objs = [];\n\n");
46
47 for obj in &file.objects {
49 out.push_str(&emit_object(obj, &file.const_pools)?);
50 out.push('\n');
51 out.push_str(&format!(
52 "__tjs2dec_objs[{idx}] = __tjs2dec_obj_{idx};\n\n",
53 idx = obj.index
54 ));
55 }
56
57 out.push_str("// Entry point\n");
58 out.push_str(&format!("__tjs2dec_objs[{}]();\n", file.toplevel));
59
60 Ok(out)
61}
62
63fn emit_object(obj: &Tjs2Object, pools: &ConstPools) -> Result<String> {
64 let mut out = String::new();
65
66 out.push_str(&format!("function __tjs2dec_obj_{}() {{\n", obj.index));
67
68 let maxv = if obj.max_variable_count < 0 {
70 0
71 } else {
72 obj.max_variable_count
73 };
74 let mut reg_names: Vec<String> = Vec::new();
75 for i in 0..maxv {
76 reg_names.push(format!("r{}", i));
77 }
78 for i in 1..=NEG_REG_MAX {
79 reg_names.push(format!("rN{}", i));
80 }
81
82 let mut i = 0usize;
84 while i < reg_names.len() {
85 let end = (i + 16).min(reg_names.len());
86 out.push_str(" var ");
87 out.push_str(®_names[i..end].join(", "));
88 out.push_str(";\n");
89 i = end;
90 }
91
92 out.push_str(" // Negative registers are used for special VM bindings.\n");
94 out.push_str(" // rN1: this, rN2: global, rN3: arguments (best-effort).\n");
95 out.push_str(" rN1 = this;\n");
96 out.push_str(" rN2 = global;\n");
97 out.push_str(" rN3 = arguments;\n");
98 for k in 4..=NEG_REG_MAX {
99 out.push_str(&format!(" rN{} = void;\n", k));
100 }
101 out.push('\n');
102
103 out.push_str(" // vdata (per-object)\n");
105 out.push_str(" var __d = [\n");
106 for (di, v) in obj.data.iter().enumerate() {
107 out.push_str(" ");
108 out.push_str(&variant_to_tjs(v, pools, obj.index));
109 out.push_str(&format!(", // *{}\n", di));
110 }
111 out.push_str(" ];\n\n");
112
113 out.push_str(" function __get_reg(i) {\n");
115 out.push_str(" switch (i) {\n");
116 for r in 0..maxv {
117 out.push_str(&format!(" case {}: return r{};\n", r, r));
118 }
119 for r in 1..=NEG_REG_MAX {
120 out.push_str(&format!(" case -{}: return rN{};\n", r, r));
121 }
122 out.push_str(" default: return void;\n");
123 out.push_str(" }\n");
124 out.push_str(" }\n\n");
125
126 out.push_str(" function __set_reg(i, v) {\n");
127 out.push_str(" switch (i) {\n");
128 for r in 0..maxv {
129 out.push_str(&format!(" case {}: r{} = v; break;\n", r, r));
130 }
131 for r in 1..=NEG_REG_MAX {
132 out.push_str(&format!(" case -{}: rN{} = v; break;\n", r, r));
133 }
134 out.push_str(" default: break;\n");
135 out.push_str(" }\n");
136 out.push_str(" }\n\n");
137
138 out.push_str(" var __this = this;\n");
139 out.push_str(" var __rv = void;\n");
140 out.push_str(" var __flag = false;\n");
141 out.push_str(" var __try = []; // stack of [catch_ip, ex_reg]\n");
142 out.push_str(" var ip = 0;\n\n");
143
144 out.push_str(" while (true) {\n");
145 out.push_str(" try {\n");
146 out.push_str(" switch (ip) {\n");
147
148 let code = &obj.code;
149
150 let disasm_txt = crate::disasm::disassemble_object(obj, pools)?;
152 let mut disasm_map: HashMap<usize, String> = HashMap::new();
153 for line in disasm_txt.lines() {
154 if let Some((addr, rest)) = line.split_once(' ') {
155 if let Ok(a) = addr.parse::<usize>() {
156 disasm_map.insert(a, rest.to_string());
157 }
158 }
159 }
160
161 let mut pc: usize = 0;
162 while pc < code.len() {
163 let line = disasm_map
164 .get(&pc)
165 .cloned()
166 .unwrap_or_else(|| vm::name(code[pc]).to_string());
167 let size = insn_len(code, pc)?;
168 let case_code = emit_case(obj, pools, pc, &line, size)?;
169 out.push_str(&case_code);
170 pc += size;
171 }
172
173 out.push_str(" default:\n");
174 out.push_str(" throw \"Invalid instruction pointer: \" + ip;\n");
175 out.push_str(" }\n");
176 out.push_str(" } catch (__e) {\n");
177 out.push_str(" if (__try.length > 0) {\n");
178 out.push_str(" var __h = __try.pop();\n");
179 out.push_str(" __set_reg(__h[1], __e);\n");
180 out.push_str(" ip = __h[0];\n");
181 out.push_str(" continue;\n");
182 out.push_str(" }\n");
183 out.push_str(" throw __e;\n");
184 out.push_str(" }\n");
185 out.push_str(" }\n");
186
187 out.push_str("}\n");
188
189 Ok(out)
190}
191
192fn emit_build_args(
193 code: &[i32],
194 pc: usize,
195 st: usize,
196 argc: i32,
197 r: &impl Fn(i32) -> String,
198) -> String {
199 let mut s = String::new();
200
201 if argc == -1 {
202 s.push_str(" __args = arguments;\n");
204 return s;
205 }
206
207 if argc == -2 {
208 let num = code.get(pc + st).copied().unwrap_or(0) as usize;
210 let base = pc + st + 1;
211 for j in 0..num {
212 let ty = code.get(base + j * 2).copied().unwrap_or(0);
213 let v = code.get(base + j * 2 + 1).copied().unwrap_or(0);
214 match ty {
215 0 => s.push_str(&format!(" __args.push({});\n", r(v))),
216 1 => s.push_str(&format!(
217 " __tjs2dec_expand_args(__args, {});\n",
218 r(v)
219 )),
220 2 => s.push_str(" __tjs2dec_expand_args(__args, arguments);\n"),
221 _ => s.push_str(&format!(" __args.push({});\n", r(v))),
222 }
223 }
224 return s;
225 }
226
227 let n = if argc < 0 { 0 } else { argc as usize };
228 for j in 0..n {
229 let v = code.get(pc + st + j).copied().unwrap_or(0);
230 s.push_str(&format!(" __args.push({});\n", r(v)));
231 }
232 s
233}
234
235fn emit_op2_prop(
236 out: &mut String,
237 code: &[i32],
238 pc: usize,
239 kind: i32,
240 r: &impl Fn(i32) -> String,
241 op: &str,
242 is_idiv: bool,
243) -> Result<()> {
244 match kind {
245 0 => {
246 ensure(code, pc, 3)?;
247 let a = code[pc + 1];
248 let b = code[pc + 2];
249 if is_idiv {
250 out.push_str(&format!(
251 " {} = __tjs2dec_idiv({}, {});\n",
252 r(a),
253 r(a),
254 r(b)
255 ));
256 } else {
257 out.push_str(&format!(
258 " {} = ({} {} {});\n",
259 r(a),
260 r(a),
261 op,
262 r(b)
263 ));
264 }
265 }
266 1 => {
267 ensure(code, pc, 5)?;
268 let dst = code[pc + 1];
269 let objr = code[pc + 2];
270 let key = code[pc + 3];
271 let rhs = code[pc + 4];
272 out.push_str(&format!(" var __k = __d[{}];\n", key));
273 out.push_str(&format!(
274 " var __t = __tjs2dec_get_prop({}, __k, false);\n",
275 r(objr)
276 ));
277 if is_idiv {
278 out.push_str(&format!(
279 " __t = __tjs2dec_idiv(__t, {});\n",
280 r(rhs)
281 ));
282 } else {
283 out.push_str(&format!(" __t = (__t {} {});\n", op, r(rhs)));
284 }
285 out.push_str(&format!(
286 " __tjs2dec_set_prop({}, __k, __t, false);\n",
287 r(objr)
288 ));
289 if dst != 0 {
290 out.push_str(&format!(
291 " {} = __t;
292",
293 r(dst)
294 ));
295 }
296 }
297 2 => {
298 ensure(code, pc, 5)?;
299 let dst = code[pc + 1];
300 let objr = code[pc + 2];
301 let keyr = code[pc + 3];
302 let rhs = code[pc + 4];
303 out.push_str(&format!(" var __k = {};\n", r(keyr)));
304 out.push_str(&format!(
305 " var __t = __tjs2dec_get_prop({}, __k, false);\n",
306 r(objr)
307 ));
308 if is_idiv {
309 out.push_str(&format!(
310 " __t = __tjs2dec_idiv(__t, {});\n",
311 r(rhs)
312 ));
313 } else {
314 out.push_str(&format!(" __t = (__t {} {});\n", op, r(rhs)));
315 }
316 out.push_str(&format!(
317 " __tjs2dec_set_prop({}, __k, __t, false);\n",
318 r(objr)
319 ));
320 if dst != 0 {
321 out.push_str(&format!(
322 " {} = __t;
323",
324 r(dst)
325 ));
326 }
327 }
328 3 => {
329 ensure(code, pc, 4)?;
330 let dst = code[pc + 1];
331 let propr = code[pc + 2];
332 let rhs = code[pc + 3];
333
334 out.push_str(&format!(
336 " var __p = {};
337",
338 r(propr)
339 ));
340 out.push_str(
341 " var __t = *__p;
342",
343 );
344 if is_idiv {
345 out.push_str(&format!(
346 " __t = __tjs2dec_idiv(__t, {});
347",
348 r(rhs)
349 ));
350 } else {
351 out.push_str(&format!(
352 " __t = (__t {} {});
353",
354 op,
355 r(rhs)
356 ));
357 }
358 out.push_str(
359 " *__p = __t;
360",
361 );
362 if dst != 0 {
363 out.push_str(&format!(
364 " {} = __t;
365",
366 r(dst)
367 ));
368 }
369 }
370 _ => {
371 out.push_str(&format!(
372 " throw \"Unimplemented opcode: {} (unknown op2_prop kind) at ip={}\n\";
373",
374 code[pc], pc
375 ));
376 }
377 }
378 Ok(())
379}
380
381fn emit_case(
382 obj: &Tjs2Object,
383 pools: &ConstPools,
384 pc: usize,
385 insn_str: &str,
386 size: usize,
387) -> Result<String> {
388 let code = &obj.code;
389 let op = code[pc];
390
391 let mut out = String::new();
392 out.push_str(&format!(" case {}: // {:08} {}\n", pc, pc, insn_str));
393
394 let r = |idx: i32| -> String { reg_name(idx) };
396
397 match op {
399 x if x == vm::VM_NOP => {
400 out.push_str(&format!(" ip += {};\n continue;\n", size));
401 }
402 x if x == vm::VM_DEBUGGER => {
403 out.push_str(&format!(" ip += {};\n continue;\n", size));
404 }
405
406 x if x == vm::VM_CONST => {
408 ensure(code, pc, 3)?;
409 let dst = code[pc + 1];
410 let src = code[pc + 2];
411 out.push_str(&format!(" {} = __d[{}];\n", r(dst), src));
412 out.push_str(" ip += 3;\n continue;\n");
413 }
414 x if x == vm::VM_CP => {
415 ensure(code, pc, 3)?;
416 let dst = code[pc + 1];
417 let src = code[pc + 2];
418 out.push_str(&format!(" {} = {};\n", r(dst), r(src)));
419 out.push_str(" ip += 3;\n continue;\n");
420 }
421 x if x == vm::VM_CL => {
422 ensure(code, pc, 2)?;
423 let rr = code[pc + 1];
424 out.push_str(&format!(" {} = void;\n", r(rr)));
425 out.push_str(" ip += 2;\n continue;\n");
426 }
427 x if x == vm::VM_CCL => {
428 ensure(code, pc, 4)?;
429 let base = code[pc + 1];
430 let count = code[pc + 2];
431 let step = code[pc + 3];
432 out.push_str(" // ccl base,count,step\n");
433 out.push_str(&format!(
434 " for (var __i = 0; __i < {}; __i += {}) {{ __set_reg({} + __i, void); }}\n",
435 count, step, base
436 ));
437 out.push_str(" ip += 4;\n continue;\n");
438 }
439
440 x if x == vm::VM_TT => {
442 ensure(code, pc, 2)?;
443 let rr = code[pc + 1];
444 out.push_str(&format!(
445 " __flag = __tjs2dec_truthy({});\n",
446 r(rr)
447 ));
448 out.push_str(" ip += 2;\n continue;\n");
449 }
450 x if x == vm::VM_TF => {
451 ensure(code, pc, 2)?;
452 let rr = code[pc + 1];
453 out.push_str(&format!(
454 " __flag = !__tjs2dec_truthy({});\n",
455 r(rr)
456 ));
457 out.push_str(" ip += 2;\n continue;\n");
458 }
459 x if x == vm::VM_NF => {
460 ensure(code, pc, 1)?;
461 out.push_str(" __flag = !__flag;\n");
462 out.push_str(" ip += 1;\n continue;\n");
463 }
464 x if x == vm::VM_SETF => {
465 ensure(code, pc, 2)?;
466 let rr = code[pc + 1];
467 out.push_str(&format!(" {} = true;\n", r(rr)));
468 out.push_str(" ip += 2;\n continue;\n");
469 }
470 x if x == vm::VM_SETNF => {
471 ensure(code, pc, 2)?;
472 let rr = code[pc + 1];
473 out.push_str(&format!(" {} = false;\n", r(rr)));
474 out.push_str(" ip += 2;\n continue;\n");
475 }
476
477 x if x == vm::VM_CEQ => {
479 ensure(code, pc, 3)?;
480 let a = code[pc + 1];
481 let b = code[pc + 2];
482 out.push_str(&format!(" __flag = ({} == {});\n", r(a), r(b)));
483 out.push_str(" ip += 3;\n continue;\n");
484 }
485 x if x == vm::VM_CDEQ => {
486 ensure(code, pc, 3)?;
487 let a = code[pc + 1];
488 let b = code[pc + 2];
489 out.push_str(&format!(" __flag = ({} === {});\n", r(a), r(b)));
490 out.push_str(" ip += 3;\n continue;\n");
491 }
492 x if x == vm::VM_CLT => {
493 ensure(code, pc, 3)?;
494 let a = code[pc + 1];
495 let b = code[pc + 2];
496 out.push_str(&format!(" __flag = ({} < {});\n", r(a), r(b)));
497 out.push_str(" ip += 3;\n continue;\n");
498 }
499 x if x == vm::VM_CGT => {
500 ensure(code, pc, 3)?;
501 let a = code[pc + 1];
502 let b = code[pc + 2];
503 out.push_str(&format!(" __flag = ({} > {});\n", r(a), r(b)));
504 out.push_str(" ip += 3;\n continue;\n");
505 }
506 x if x == vm::VM_CHKINS => {
507 ensure(code, pc, 3)?;
508 let a = code[pc + 1];
509 let b = code[pc + 2];
510 out.push_str(&format!(" __flag = ({} in {});\n", r(a), r(b)));
511 out.push_str(" ip += 3;\n continue;\n");
512 }
513
514 x if x == vm::VM_JMP => {
516 ensure(code, pc, 2)?;
517 let tgt = code[pc + 1];
518 out.push_str(&format!(" ip = {};\n continue;\n", tgt));
519 }
520 x if x == vm::VM_JF => {
521 ensure(code, pc, 2)?;
522 let tgt = code[pc + 1];
523 out.push_str(&format!(
524 " if (!__flag) {{ ip = {}; }} else {{ ip += 2; }}\n continue;\n",
525 tgt
526 ));
527 }
528 x if x == vm::VM_JNF => {
529 ensure(code, pc, 2)?;
530 let tgt = code[pc + 1];
531 out.push_str(&format!(
532 " if (__flag) {{ ip = {}; }} else {{ ip += 2; }}\n continue;\n",
533 tgt
534 ));
535 }
536
537 x if x == vm::VM_LNOT => {
539 ensure(code, pc, 2)?;
540 let rr = code[pc + 1];
541 out.push_str(&format!(
542 " {} = !__tjs2dec_truthy({});\n",
543 r(rr),
544 r(rr)
545 ));
546 out.push_str(" ip += 2;\n continue;\n");
547 }
548 x if x == vm::VM_BNOT => {
549 ensure(code, pc, 2)?;
550 let rr = code[pc + 1];
551 out.push_str(&format!(" {} = ~({});\n", r(rr), r(rr)));
552 out.push_str(" ip += 2;\n continue;\n");
553 }
554 x if x == vm::VM_CHS => {
555 ensure(code, pc, 2)?;
556 let rr = code[pc + 1];
557 out.push_str(&format!(" {} = -({});\n", r(rr), r(rr)));
558 out.push_str(" ip += 2;\n continue;\n");
559 }
560 x if x == vm::VM_TYPEOF => {
561 ensure(code, pc, 2)?;
562 let rr = code[pc + 1];
563 out.push_str(&format!(" {} = typeof({});\n", r(rr), r(rr)));
564 out.push_str(" ip += 2;\n continue;\n");
565 }
566 x if x == vm::VM_EVAL || x == vm::VM_EEXP => {
567 ensure(code, pc, 2)?;
568 let rr = code[pc + 1];
569 out.push_str(&format!(" {} = eval({});\n", r(rr), r(rr)));
570 out.push_str(" ip += 2;\n continue;\n");
571 }
572 x if x == vm::VM_ASC => {
573 ensure(code, pc, 2)?;
574 let rr = code[pc + 1];
575 out.push_str(&format!(" {} = String({});\n", r(rr), r(rr)));
576 out.push_str(" ip += 2;\n continue;\n");
577 }
578 x if x == vm::VM_CHR => {
579 ensure(code, pc, 2)?;
580 let rr = code[pc + 1];
581 out.push_str(&format!(
582 " {} = String.fromCharCode({});\n",
583 r(rr),
584 r(rr)
585 ));
586 out.push_str(" ip += 2;\n continue;\n");
587 }
588 x if x == vm::VM_NUM => {
589 ensure(code, pc, 2)?;
590 let rr = code[pc + 1];
591 out.push_str(&format!(" {} = Number({});\n", r(rr), r(rr)));
592 out.push_str(" ip += 2;\n continue;\n");
593 }
594 x if x == vm::VM_INV => {
595 ensure(code, pc, 2)?;
596 let rr = code[pc + 1];
597 out.push_str(&format!(
598 " {} = ({} instanceof Variant ? {} : {});\n",
599 r(rr),
600 r(rr),
601 r(rr),
602 r(rr)
603 ));
604 out.push_str(" ip += 2;\n continue;\n");
605 }
606 x if x == vm::VM_CHKINV => {
607 ensure(code, pc, 2)?;
608 let rr = code[pc + 1];
609 out.push_str(&format!(
610 " if (({} instanceof Variant) == false) throw \"CHKINV failed\";\n",
611 r(rr)
612 ));
613 out.push_str(" ip += 2;\n continue;\n");
614 }
615 x if x == vm::VM_INT => {
616 ensure(code, pc, 2)?;
617 let rr = code[pc + 1];
618 out.push_str(&format!(
619 " {} = __tjs2dec_to_int({});\n",
620 r(rr),
621 r(rr)
622 ));
623 out.push_str(" ip += 2;\n continue;\n");
624 }
625 x if x == vm::VM_REAL => {
626 ensure(code, pc, 2)?;
627 let rr = code[pc + 1];
628 out.push_str(&format!(" {} = Number({});\n", r(rr), r(rr)));
629 out.push_str(" ip += 2;\n continue;\n");
630 }
631 x if x == vm::VM_STR => {
632 ensure(code, pc, 2)?;
633 let rr = code[pc + 1];
634 out.push_str(&format!(" {} = String({});\n", r(rr), r(rr)));
635 out.push_str(" ip += 2;\n continue;\n");
636 }
637 x if x == vm::VM_OCTET => {
638 ensure(code, pc, 2)?;
639 let rr = code[pc + 1];
640 out.push_str(&format!(" {} = {};\n", r(rr), r(rr)));
641 out.push_str(" ip += 2;\n continue;\n");
642 }
643
644 x if x >= vm::VM_INC && x <= vm::VM_INCP => match x - vm::VM_INC {
646 0 => {
647 ensure(code, pc, 2)?;
648 let rr = code[pc + 1];
649 out.push_str(&format!(" {} = ({} + 1);\n", r(rr), r(rr)));
650 out.push_str(" ip += 2;\n continue;\n");
651 }
652 1 => {
653 ensure(code, pc, 4)?;
654 let dst = code[pc + 1];
655 let objr = code[pc + 2];
656 let key = code[pc + 3];
657 out.push_str(&format!(" var __k = __d[{}];\n", key));
658 out.push_str(&format!(
659 " var __t = __tjs2dec_get_prop({}, __k, false);\n",
660 r(objr)
661 ));
662 out.push_str(" __t = (__t + 1);\n");
663 out.push_str(&format!(
664 " __tjs2dec_set_prop({}, __k, __t, false);\n",
665 r(objr)
666 ));
667 if dst != 0 {
668 out.push_str(&format!(
669 " {} = __t;
670",
671 r(dst)
672 ));
673 }
674 out.push_str(
675 " ip += 4;
676 continue;
677",
678 );
679 }
680 2 => {
681 ensure(code, pc, 4)?;
682 let dst = code[pc + 1];
683 let objr = code[pc + 2];
684 let keyr = code[pc + 3];
685 out.push_str(&format!(" var __k = {};\n", r(keyr)));
686 out.push_str(&format!(
687 " var __t = __tjs2dec_get_prop({}, __k, false);\n",
688 r(objr)
689 ));
690 out.push_str(" __t = (__t + 1);\n");
691 out.push_str(&format!(
692 " __tjs2dec_set_prop({}, __k, __t, false);\n",
693 r(objr)
694 ));
695 if dst != 0 {
696 out.push_str(&format!(
697 " {} = __t;
698",
699 r(dst)
700 ));
701 }
702 out.push_str(
703 " ip += 4;
704 continue;
705",
706 );
707 }
708 3 => {
709 ensure(code, pc, 3)?;
710 let dst = code[pc + 1];
711 let propr = code[pc + 2];
712 out.push_str(&format!(
713 " var __p = {};
714",
715 r(propr)
716 ));
717 out.push_str(
718 " var __t = *__p;
719",
720 );
721 out.push_str(
722 " __t = (__t + 1);
723",
724 );
725 out.push_str(
726 " *__p = __t;
727",
728 );
729 if dst != 0 {
730 out.push_str(&format!(
731 " {} = __t;
732",
733 r(dst)
734 ));
735 }
736 out.push_str(
737 " ip += 3;
738 continue;
739",
740 );
741 }
742 _ => {}
743 },
744 x if x >= vm::VM_DEC && x <= vm::VM_DECP => match x - vm::VM_DEC {
745 0 => {
746 ensure(code, pc, 2)?;
747 let rr = code[pc + 1];
748 out.push_str(&format!(" {} = ({} - 1);\n", r(rr), r(rr)));
749 out.push_str(" ip += 2;\n continue;\n");
750 }
751 1 => {
752 ensure(code, pc, 4)?;
753 let dst = code[pc + 1];
754 let objr = code[pc + 2];
755 let key = code[pc + 3];
756 out.push_str(&format!(" var __k = __d[{}];\n", key));
757 out.push_str(&format!(
758 " var __t = __tjs2dec_get_prop({}, __k, false);\n",
759 r(objr)
760 ));
761 out.push_str(" __t = (__t - 1);\n");
762 out.push_str(&format!(
763 " __tjs2dec_set_prop({}, __k, __t, false);\n",
764 r(objr)
765 ));
766 if dst != 0 {
767 out.push_str(&format!(
768 " {} = __t;
769",
770 r(dst)
771 ));
772 }
773 out.push_str(
774 " ip += 4;
775 continue;
776",
777 );
778 }
779 2 => {
780 ensure(code, pc, 4)?;
781 let dst = code[pc + 1];
782 let objr = code[pc + 2];
783 let keyr = code[pc + 3];
784 out.push_str(&format!(" var __k = {};\n", r(keyr)));
785 out.push_str(&format!(
786 " var __t = __tjs2dec_get_prop({}, __k, false);\n",
787 r(objr)
788 ));
789 out.push_str(" __t = (__t - 1);\n");
790 out.push_str(&format!(
791 " __tjs2dec_set_prop({}, __k, __t, false);\n",
792 r(objr)
793 ));
794 if dst != 0 {
795 out.push_str(&format!(
796 " {} = __t;
797",
798 r(dst)
799 ));
800 }
801 out.push_str(
802 " ip += 4;
803 continue;
804",
805 );
806 }
807 3 => {
808 ensure(code, pc, 3)?;
809 let dst = code[pc + 1];
810 let propr = code[pc + 2];
811 out.push_str(&format!(
812 " var __p = {};
813",
814 r(propr)
815 ));
816 out.push_str(
817 " var __t = *__p;
818",
819 );
820 out.push_str(
821 " __t = (__t - 1);
822",
823 );
824 out.push_str(
825 " *__p = __t;
826",
827 );
828 if dst != 0 {
829 out.push_str(&format!(
830 " {} = __t;
831",
832 r(dst)
833 ));
834 }
835 out.push_str(
836 " ip += 3;
837 continue;
838",
839 );
840 }
841 _ => {}
842 },
843
844 x if x >= vm::VM_LOR && x <= vm::VM_LORP => match x - vm::VM_LOR {
846 0 => {
847 ensure(code, pc, 3)?;
848 let a = code[pc + 1];
849 let b = code[pc + 2];
850 out.push_str(&format!(
851 " {} = (__tjs2dec_truthy({}) || __tjs2dec_truthy({}));\n",
852 r(a),
853 r(a),
854 r(b)
855 ));
856 out.push_str(" ip += 3;\n continue;\n");
857 }
858 1 => {
859 ensure(code, pc, 5)?;
860 let dst = code[pc + 1];
861 let objr = code[pc + 2];
862 let key = code[pc + 3];
863 let rhs = code[pc + 4];
864 out.push_str(&format!(" var __k = __d[{}];\n", key));
865 out.push_str(&format!(
866 " var __t = __tjs2dec_get_prop({}, __k, false);\n",
867 r(objr)
868 ));
869 out.push_str(&format!(
870 " __t = (__tjs2dec_truthy(__t) || __tjs2dec_truthy({}));\n",
871 r(rhs)
872 ));
873 out.push_str(&format!(
874 " __tjs2dec_set_prop({}, __k, __t, false);\n",
875 r(objr)
876 ));
877 if dst != 0 {
878 out.push_str(&format!(
879 " {} = __t;
880",
881 r(dst)
882 ));
883 }
884 out.push_str(
885 " ip += 5;
886 continue;
887",
888 );
889 }
890 2 => {
891 ensure(code, pc, 5)?;
892 let dst = code[pc + 1];
893 let objr = code[pc + 2];
894 let keyr = code[pc + 3];
895 let rhs = code[pc + 4];
896 out.push_str(&format!(" var __k = {};\n", r(keyr)));
897 out.push_str(&format!(
898 " var __t = __tjs2dec_get_prop({}, __k, false);\n",
899 r(objr)
900 ));
901 out.push_str(&format!(
902 " __t = (__tjs2dec_truthy(__t) || __tjs2dec_truthy({}));\n",
903 r(rhs)
904 ));
905 out.push_str(&format!(
906 " __tjs2dec_set_prop({}, __k, __t, false);\n",
907 r(objr)
908 ));
909 if dst != 0 {
910 out.push_str(&format!(
911 " {} = __t;
912",
913 r(dst)
914 ));
915 }
916 out.push_str(
917 " ip += 5;
918 continue;
919",
920 );
921 }
922 3 => {
923 ensure(code, pc, 4)?;
924 let dst = code[pc + 1];
925 let propr = code[pc + 2];
926 let rhs = code[pc + 3];
927 out.push_str(&format!(
928 " var __p = {};
929",
930 r(propr)
931 ));
932 out.push_str(
933 " var __a = *__p;
934",
935 );
936 out.push_str(&format!(
937 " var __b = {};
938",
939 r(rhs)
940 ));
941 out.push_str(&format!(
942 " var __t = (__tjs2dec_truthy(__a) || __tjs2dec_truthy(__b));
943"
944 ));
945 out.push_str(
946 " *__p = __t;
947",
948 );
949 if dst != 0 {
950 out.push_str(&format!(
951 " {} = __t;
952",
953 r(dst)
954 ));
955 }
956 out.push_str(
957 " ip += 4;
958 continue;
959",
960 );
961 }
962 _ => {}
963 },
964 x if x >= vm::VM_LAND && x <= vm::VM_LANDP => match x - vm::VM_LAND {
965 0 => {
966 ensure(code, pc, 3)?;
967 let a = code[pc + 1];
968 let b = code[pc + 2];
969 out.push_str(&format!(
970 " {} = (__tjs2dec_truthy({}) && __tjs2dec_truthy({}));\n",
971 r(a),
972 r(a),
973 r(b)
974 ));
975 out.push_str(" ip += 3;\n continue;\n");
976 }
977 1 => {
978 ensure(code, pc, 5)?;
979 let dst = code[pc + 1];
980 let objr = code[pc + 2];
981 let key = code[pc + 3];
982 let rhs = code[pc + 4];
983 out.push_str(&format!(" var __k = __d[{}];\n", key));
984 out.push_str(&format!(
985 " var __t = __tjs2dec_get_prop({}, __k, false);\n",
986 r(objr)
987 ));
988 out.push_str(&format!(
989 " __t = (__tjs2dec_truthy(__t) && __tjs2dec_truthy({}));\n",
990 r(rhs)
991 ));
992 out.push_str(&format!(
993 " __tjs2dec_set_prop({}, __k, __t, false);\n",
994 r(objr)
995 ));
996 if dst != 0 {
997 out.push_str(&format!(
998 " {} = __t;
999",
1000 r(dst)
1001 ));
1002 }
1003 out.push_str(
1004 " ip += 5;
1005 continue;
1006",
1007 );
1008 }
1009 2 => {
1010 ensure(code, pc, 5)?;
1011 let dst = code[pc + 1];
1012 let objr = code[pc + 2];
1013 let keyr = code[pc + 3];
1014 let rhs = code[pc + 4];
1015 out.push_str(&format!(" var __k = {};\n", r(keyr)));
1016 out.push_str(&format!(
1017 " var __t = __tjs2dec_get_prop({}, __k, false);\n",
1018 r(objr)
1019 ));
1020 out.push_str(&format!(
1021 " __t = (__tjs2dec_truthy(__t) && __tjs2dec_truthy({}));\n",
1022 r(rhs)
1023 ));
1024 out.push_str(&format!(
1025 " __tjs2dec_set_prop({}, __k, __t, false);\n",
1026 r(objr)
1027 ));
1028 if dst != 0 {
1029 out.push_str(&format!(
1030 " {} = __t;
1031",
1032 r(dst)
1033 ));
1034 }
1035 out.push_str(
1036 " ip += 5;
1037 continue;
1038",
1039 );
1040 }
1041 3 => {
1042 ensure(code, pc, 4)?;
1043 let dst = code[pc + 1];
1044 let propr = code[pc + 2];
1045 let rhs = code[pc + 3];
1046 out.push_str(&format!(
1047 " var __p = {};
1048",
1049 r(propr)
1050 ));
1051 out.push_str(
1052 " var __a = *__p;
1053",
1054 );
1055 out.push_str(&format!(
1056 " var __b = {};
1057",
1058 r(rhs)
1059 ));
1060 out.push_str(&format!(
1061 " var __t = (__tjs2dec_truthy(__a) && __tjs2dec_truthy(__b));
1062"
1063 ));
1064 out.push_str(
1065 " *__p = __t;
1066",
1067 );
1068 if dst != 0 {
1069 out.push_str(&format!(
1070 " {} = __t;
1071",
1072 r(dst)
1073 ));
1074 }
1075 out.push_str(
1076 " ip += 4;
1077 continue;
1078",
1079 );
1080 }
1081 _ => {}
1082 },
1083 x if x >= vm::VM_BOR && x <= vm::VM_BORP => {
1085 emit_op2_prop(&mut out, code, pc, x - vm::VM_BOR, &r, "|", false)?;
1086 out.push_str(&format!(" ip += {};\n continue;\n", size));
1087 }
1088 x if x >= vm::VM_BXOR && x <= vm::VM_BXORP => {
1089 emit_op2_prop(&mut out, code, pc, x - vm::VM_BXOR, &r, "^", false)?;
1090 out.push_str(&format!(" ip += {};\n continue;\n", size));
1091 }
1092 x if x >= vm::VM_BAND && x <= vm::VM_BANDP => {
1093 emit_op2_prop(&mut out, code, pc, x - vm::VM_BAND, &r, "&", false)?;
1094 out.push_str(&format!(" ip += {};\n continue;\n", size));
1095 }
1096 x if x >= vm::VM_SAR && x <= vm::VM_SARP => {
1097 emit_op2_prop(&mut out, code, pc, x - vm::VM_SAR, &r, ">>", false)?;
1098 out.push_str(&format!(" ip += {};\n continue;\n", size));
1099 }
1100 x if x >= vm::VM_SAL && x <= vm::VM_SALP => {
1101 emit_op2_prop(&mut out, code, pc, x - vm::VM_SAL, &r, "<<", false)?;
1102 out.push_str(&format!(" ip += {};\n continue;\n", size));
1103 }
1104 x if x >= vm::VM_SR && x <= vm::VM_SRP => {
1105 emit_op2_prop(&mut out, code, pc, x - vm::VM_SR, &r, ">>>", false)?;
1106 out.push_str(&format!(" ip += {};\n continue;\n", size));
1107 }
1108 x if x >= vm::VM_ADD && x <= vm::VM_ADDP => {
1109 emit_op2_prop(&mut out, code, pc, x - vm::VM_ADD, &r, "+", false)?;
1110 out.push_str(&format!(" ip += {};\n continue;\n", size));
1111 }
1112 x if x >= vm::VM_SUB && x <= vm::VM_SUBP => {
1113 emit_op2_prop(&mut out, code, pc, x - vm::VM_SUB, &r, "-", false)?;
1114 out.push_str(&format!(" ip += {};\n continue;\n", size));
1115 }
1116 x if x >= vm::VM_MOD && x <= vm::VM_MODP => {
1117 emit_op2_prop(&mut out, code, pc, x - vm::VM_MOD, &r, "%", false)?;
1118 out.push_str(&format!(" ip += {};\n continue;\n", size));
1119 }
1120 x if x >= vm::VM_DIV && x <= vm::VM_DIVP => {
1121 emit_op2_prop(&mut out, code, pc, x - vm::VM_DIV, &r, "/", false)?;
1122 out.push_str(&format!(" ip += {};\n continue;\n", size));
1123 }
1124 x if x >= vm::VM_MUL && x <= vm::VM_MULP => {
1125 emit_op2_prop(&mut out, code, pc, x - vm::VM_MUL, &r, "*", false)?;
1126 out.push_str(&format!(" ip += {};\n continue;\n", size));
1127 }
1128 x if x >= vm::VM_IDIV && x <= vm::VM_IDIVP => {
1129 emit_op2_prop(&mut out, code, pc, x - vm::VM_IDIV, &r, "/", true)?;
1130 out.push_str(&format!(" ip += {};\n continue;\n", size));
1131 }
1132
1133 x if x == vm::VM_DELD || x == vm::VM_TYPEOFD => {
1135 ensure(code, pc, 4)?;
1136 let dst = code[pc + 1];
1137 let objr = code[pc + 2];
1138 let key = code[pc + 3];
1139 if x == vm::VM_DELD {
1140 out.push_str(&format!(
1141 " {} = __tjs2dec_del_prop({}, __d[{}], false);\n",
1142 r(dst),
1143 r(objr),
1144 key
1145 ));
1146 } else {
1147 out.push_str(&format!(
1148 " {} = typeof(__tjs2dec_get_prop({}, __d[{}], false));\n",
1149 r(dst),
1150 r(objr),
1151 key
1152 ));
1153 }
1154 out.push_str(" ip += 4;\n continue;\n");
1155 }
1156 x if x == vm::VM_DELI || x == vm::VM_TYPEOFI => {
1157 ensure(code, pc, 4)?;
1158 let dst = code[pc + 1];
1159 let objr = code[pc + 2];
1160 let keyr = code[pc + 3];
1161 if x == vm::VM_DELI {
1162 out.push_str(&format!(
1163 " {} = __tjs2dec_del_prop({}, {}, false);\n",
1164 r(dst),
1165 r(objr),
1166 r(keyr)
1167 ));
1168 } else {
1169 out.push_str(&format!(
1170 " {} = typeof(__tjs2dec_get_prop({}, {}, false));\n",
1171 r(dst),
1172 r(objr),
1173 r(keyr)
1174 ));
1175 }
1176 out.push_str(" ip += 4;\n continue;\n");
1177 }
1178
1179 x if x == vm::VM_GPD || x == vm::VM_GPDS => {
1181 ensure(code, pc, 4)?;
1182 let dst = code[pc + 1];
1183 let objr = code[pc + 2];
1184 let key = code[pc + 3];
1185 let ign = if x == vm::VM_GPDS { "true" } else { "false" };
1186 out.push_str(&format!(
1187 " {} = __tjs2dec_get_prop({}, __d[{}], {});\n",
1188 r(dst),
1189 r(objr),
1190 key,
1191 ign
1192 ));
1193 out.push_str(" ip += 4;\n continue;\n");
1194 }
1195 x if x == vm::VM_GPI || x == vm::VM_GPIS => {
1196 ensure(code, pc, 4)?;
1197 let dst = code[pc + 1];
1198 let objr = code[pc + 2];
1199 let keyr = code[pc + 3];
1200 let ign = if x == vm::VM_GPIS { "true" } else { "false" };
1201 out.push_str(&format!(
1202 " {} = __tjs2dec_get_prop({}, {}, {});\n",
1203 r(dst),
1204 r(objr),
1205 r(keyr),
1206 ign
1207 ));
1208 out.push_str(" ip += 4;\n continue;\n");
1209 }
1210
1211 x if x == vm::VM_SPD || x == vm::VM_SPDS || x == vm::VM_SPDE || x == vm::VM_SPDEH => {
1213 ensure(code, pc, 4)?;
1214 let objr = code[pc + 1];
1215 let key = code[pc + 2];
1216 let valr = code[pc + 3];
1217 let ign = if x == vm::VM_SPDS { "true" } else { "false" };
1218 out.push_str(&format!(
1219 " __tjs2dec_set_prop({}, __d[{}], {}, {});\n",
1220 r(objr),
1221 key,
1222 r(valr),
1223 ign
1224 ));
1225 out.push_str(" ip += 4;\n continue;\n");
1226 }
1227 x if x == vm::VM_SPI || x == vm::VM_SPIS || x == vm::VM_SPIE => {
1228 ensure(code, pc, 4)?;
1229 let objr = code[pc + 1];
1230 let keyr = code[pc + 2];
1231 let valr = code[pc + 3];
1232 let ign = if x == vm::VM_SPIS { "true" } else { "false" };
1233 out.push_str(&format!(
1234 " __tjs2dec_set_prop({}, {}, {}, {});\n",
1235 r(objr),
1236 r(keyr),
1237 r(valr),
1238 ign
1239 ));
1240 out.push_str(" ip += 4;\n continue;\n");
1241 }
1242
1243 x if x == vm::VM_CALL || x == vm::VM_NEW => {
1245 ensure(code, pc, size)?;
1246 let dst = code[pc + 1];
1247 let func = code[pc + 2];
1248 let argc = code[pc + 3];
1249 out.push_str(" var __args = [];\n");
1250 out.push_str(&format!(" var __f = {};\n", r(func)));
1251 out.push_str(&emit_build_args(code, pc, 4, argc, &r));
1252 if x == vm::VM_NEW {
1253 out.push_str(&format!(" {} = new __f(...__args);\n", r(dst)));
1254 } else {
1255 out.push_str(&format!(
1256 " {} = __f.apply(__this, __args);\n",
1257 r(dst)
1258 ));
1259 }
1260 out.push_str(&format!(" ip += {};\n continue;\n", size));
1261 }
1262 x if x == vm::VM_CALLD => {
1263 ensure(code, pc, size)?;
1264 let dst = code[pc + 1];
1266 let objr = code[pc + 2];
1267 let key = code[pc + 3];
1268 let tmp = code[pc + 4];
1269 let argc = code[pc + 5];
1270 out.push_str(" var __args = [];\n");
1271 out.push_str(&format!(" var __o = {};\n", r(objr)));
1272 out.push_str(&format!(" var __m = __d[{}];\n", key));
1273 out.push_str(" var __f = __tjs2dec_get_prop(__o, __m, false);\n");
1274 out.push_str(&format!(" {} = __f;\n", r(tmp)));
1275 out.push_str(&emit_build_args(code, pc, 6, argc, &r));
1276 out.push_str(&format!(" {} = __f.apply(__o, __args);\n", r(dst)));
1277 out.push_str(&format!(" ip += {};\n continue;\n", size));
1278 }
1279 x if x == vm::VM_CALLI => {
1280 ensure(code, pc, size)?;
1281 let dst = code[pc + 1];
1283 let objr = code[pc + 2];
1284 let keyr = code[pc + 3];
1285 let tmp = code[pc + 4];
1286 let argc = code[pc + 5];
1287 out.push_str(" var __args = [];\n");
1288 out.push_str(&format!(" var __o = {};\n", r(objr)));
1289 out.push_str(&format!(" var __m = {};\n", r(keyr)));
1290 out.push_str(" var __f = __tjs2dec_get_prop(__o, __m, false);\n");
1291 out.push_str(&format!(" {} = __f;\n", r(tmp)));
1292 out.push_str(&emit_build_args(code, pc, 6, argc, &r));
1293 out.push_str(&format!(" {} = __f.apply(__o, __args);\n", r(dst)));
1294 out.push_str(&format!(" ip += {};\n continue;\n", size));
1295 }
1296
1297 x if x == vm::VM_SETP || x == vm::VM_GETP => {
1299 ensure(code, pc, 3)?;
1300 let a = code[pc + 1];
1301 let b = code[pc + 2];
1302 if op == vm::VM_GETP {
1303 if a != 0 {
1305 out.push_str(&format!(
1306 " {} = *{};
1307",
1308 r(a),
1309 r(b)
1310 ));
1311 } else {
1312 out.push_str(&format!(
1313 " var __tmp = *{};
1314",
1315 r(b)
1316 ));
1317 }
1318 } else {
1319 out.push_str(&format!(
1321 " *{} = {};
1322",
1323 r(a),
1324 r(b)
1325 ));
1326 }
1327 out.push_str(
1328 " ip += 3;
1329 continue;
1330",
1331 );
1332 }
1333
1334 x if x == vm::VM_SRV => {
1336 ensure(code, pc, 2)?;
1337 let rr = code[pc + 1];
1338 out.push_str(&format!(" __rv = {};\n", r(rr)));
1339 out.push_str(" ip += 2;\n continue;\n");
1340 }
1341 x if x == vm::VM_GLOBAL => {
1342 ensure(code, pc, 2)?;
1343 let rr = code[pc + 1];
1344 out.push_str(&format!(" {} = global;\n", r(rr)));
1345 out.push_str(" ip += 2;\n continue;\n");
1346 }
1347 x if x == vm::VM_THROW => {
1348 ensure(code, pc, 2)?;
1349 let rr = code[pc + 1];
1350 out.push_str(&format!(" throw {};\n", r(rr)));
1351 }
1352
1353 x if x == vm::VM_ENTRY => {
1355 ensure(code, pc, 3)?;
1356 let catch_ip = code[pc + 1];
1357 let exr = code[pc + 2];
1358 out.push_str(&format!(" __try.push([{}, {}]);\n", catch_ip, exr));
1359 out.push_str(" ip += 3;\n continue;\n");
1360 }
1361 x if x == vm::VM_EXTRY => {
1362 ensure(code, pc, 1)?;
1363 out.push_str(" if (__try.length > 0) __try.pop();\n");
1364 out.push_str(" ip += 1;\n continue;\n");
1365 }
1366
1367 x if x == vm::VM_CHGTHIS => {
1369 ensure(code, pc, 3)?;
1370 let save = code[pc + 1];
1371 let newt = code[pc + 2];
1372 out.push_str(&format!(" {} = __this;\n", r(save)));
1373 out.push_str(&format!(" __this = {};\n", r(newt)));
1374 out.push_str(" ip += 3;\n continue;\n");
1375 }
1376 x if x == vm::VM_ADDCI => {
1377 ensure(code, pc, 3)?;
1378 out.push_str(" ip += 3;\n continue;\n");
1379 }
1380 x if x == vm::VM_REGMEMBER => {
1381 ensure(code, pc, 1)?;
1382 out.push_str(" ip += 1;\n continue;\n");
1383 }
1384
1385 x if x == vm::VM_RET => {
1387 ensure(code, pc, 1)?;
1388 out.push_str(" return __rv;\n");
1389 }
1390
1391 _ => {
1392 out.push_str(&format!(
1393 " throw \"Unimplemented opcode: {} ({}) at ip={}\";\n",
1394 op,
1395 insn_str.split_whitespace().next().unwrap_or("?"),
1396 pc
1397 ));
1398 }
1399 }
1400
1401 Ok(out)
1402}
1403
1404fn emit_call_like(code: &[i32], pc: usize, obj: &Tjs2Object, op: i32) -> Result<(String, usize)> {
1405 let mut out = String::new();
1411 let r = |idx: i32| -> String { reg_name(idx) };
1412
1413 match op {
1414 x if x == vm::VM_CALL || x == vm::VM_NEW => {
1415 ensure(code, pc, 4)?;
1416 let dst = code[pc + 1];
1417 let func = code[pc + 2];
1418 let argc = code[pc + 3];
1419 if argc >= 0 {
1420 let n = argc as usize;
1421 ensure(code, pc, 4 + n)?;
1422 let mut args = Vec::with_capacity(n);
1423 for j in 0..n {
1424 args.push(r(code[pc + 4 + j]));
1425 }
1426 if op == vm::VM_NEW {
1427 out.push_str(&format!(
1428 " {} = new {}({});\n",
1429 r(dst),
1430 r(func),
1431 args.join(", ")
1432 ));
1433 } else {
1434 out.push_str(&format!(
1435 " {} = {}({});\n",
1436 r(dst),
1437 r(func),
1438 args.join(", ")
1439 ));
1440 }
1441 return Ok((out, 4 + n));
1442 }
1443
1444 if argc == -1 {
1445 if op == vm::VM_NEW {
1447 out.push_str(&format!(" // Omit-args NEW is not representable without eval; falling back.\n"));
1450 out.push_str(&format!(" {} = new {}();\n", r(dst), r(func)));
1451 } else {
1452 out.push_str(&format!(" {} = {}(...);\n", r(dst), r(func)));
1453 }
1454 return Ok((out, 4));
1455 }
1456
1457 if argc == -2 {
1458 ensure(code, pc, 5)?;
1459 let num = code[pc + 4] as usize;
1460 ensure(code, pc, 5 + num * 2)?;
1461 out.push_str(" var __args = [];\n");
1462 for j in 0..num {
1463 let ty = code[pc + 5 + j * 2];
1464 let v = code[pc + 5 + j * 2 + 1];
1465 match ty {
1466 FAT_NORMAL => {
1467 out.push_str(&format!(" __args.push({});\n", r(v)));
1468 }
1469 FAT_EXPAND => {
1470 out.push_str(&format!(
1471 " __tjs2dec_expand_args(__args, {});\n",
1472 r(v)
1473 ));
1474 }
1475 FAT_UNNAMED_EXPAND => {
1476 out.push_str(" // Unnamed expand: best-effort ignored.\n");
1477 }
1478 _ => {
1479 out.push_str(&format!(" throw \"Bad FAT type: {}\";\n", ty));
1480 }
1481 }
1482 }
1483 if op == vm::VM_NEW {
1484 out.push_str(&format!(" {} = new {}();\n", r(dst), r(func)));
1487 } else {
1488 out.push_str(&format!(
1489 " {} = {}.apply(this, __args);\n",
1490 r(dst),
1491 r(func)
1492 ));
1493 }
1494 return Ok((out, 5 + num * 2));
1495 }
1496
1497 out.push_str(&format!(" {} = {}();\n", r(dst), r(func)));
1499 Ok((out, 4))
1500 }
1501 x if x == vm::VM_CALLD => {
1502 ensure(code, pc, 5)?;
1503 let dst = code[pc + 1];
1504 let objr = code[pc + 2];
1505 let memd = code[pc + 3];
1506 let argc = code[pc + 4];
1507
1508 let mem_expr = format!("__d[{}]", memd);
1510
1511 if argc >= 0 {
1512 let n = argc as usize;
1513 ensure(code, pc, 5 + n)?;
1514 let mut args = Vec::with_capacity(n);
1515 for j in 0..n {
1516 args.push(r(code[pc + 5 + j]));
1517 }
1518 out.push_str(&format!(
1519 " {} = {}[{}]({});\n",
1520 r(dst),
1521 r(objr),
1522 mem_expr,
1523 args.join(", ")
1524 ));
1525 return Ok((out, 5 + n));
1526 }
1527 if argc == -1 {
1528 out.push_str(&format!(
1529 " {} = {}[{}](...);\n",
1530 r(dst),
1531 r(objr),
1532 mem_expr
1533 ));
1534 return Ok((out, 5));
1535 }
1536 if argc == -2 {
1537 ensure(code, pc, 6)?;
1538 let num = code[pc + 5] as usize;
1539 ensure(code, pc, 6 + num * 2)?;
1540 out.push_str(" var __args = [];\n");
1541 for j in 0..num {
1542 let ty = code[pc + 6 + j * 2];
1543 let v = code[pc + 6 + j * 2 + 1];
1544 match ty {
1545 FAT_NORMAL => out.push_str(&format!(" __args.push({});\n", r(v))),
1546 FAT_EXPAND => out.push_str(&format!(
1547 " __tjs2dec_expand_args(__args, {});\n",
1548 r(v)
1549 )),
1550 FAT_UNNAMED_EXPAND => {
1551 out.push_str(" // Unnamed expand: best-effort ignored.\n")
1552 }
1553 _ => out.push_str(&format!(" throw \"Bad FAT type: {}\";\n", ty)),
1554 }
1555 }
1556 out.push_str(&format!(
1557 " {} = {}[{}].apply({}, __args);\n",
1558 r(dst),
1559 r(objr),
1560 mem_expr,
1561 r(objr)
1562 ));
1563 return Ok((out, 6 + num * 2));
1564 }
1565
1566 out.push_str(&format!(
1567 " {} = {}[{}]();\n",
1568 r(dst),
1569 r(objr),
1570 mem_expr
1571 ));
1572 Ok((out, 5))
1573 }
1574 x if x == vm::VM_CALLI => {
1575 ensure(code, pc, 5)?;
1576 let dst = code[pc + 1];
1577 let objr = code[pc + 2];
1578 let memr = code[pc + 3];
1579 let argc = code[pc + 4];
1580 if argc >= 0 {
1581 let n = argc as usize;
1582 ensure(code, pc, 5 + n)?;
1583 let mut args = Vec::with_capacity(n);
1584 for j in 0..n {
1585 args.push(r(code[pc + 5 + j]));
1586 }
1587 out.push_str(&format!(
1588 " {} = {}[{}]({});\n",
1589 r(dst),
1590 r(objr),
1591 r(memr),
1592 args.join(", ")
1593 ));
1594 return Ok((out, 5 + n));
1595 }
1596 if argc == -1 {
1597 out.push_str(&format!(
1598 " {} = {}[{}](...);\n",
1599 r(dst),
1600 r(objr),
1601 r(memr)
1602 ));
1603 return Ok((out, 5));
1604 }
1605 if argc == -2 {
1606 ensure(code, pc, 6)?;
1607 let num = code[pc + 5] as usize;
1608 ensure(code, pc, 6 + num * 2)?;
1609 out.push_str(" var __args = [];\n");
1610 for j in 0..num {
1611 let ty = code[pc + 6 + j * 2];
1612 let v = code[pc + 6 + j * 2 + 1];
1613 match ty {
1614 FAT_NORMAL => out.push_str(&format!(" __args.push({});\n", r(v))),
1615 FAT_EXPAND => out.push_str(&format!(
1616 " __tjs2dec_expand_args(__args, {});\n",
1617 r(v)
1618 )),
1619 FAT_UNNAMED_EXPAND => {
1620 out.push_str(" // Unnamed expand: best-effort ignored.\n")
1621 }
1622 _ => out.push_str(&format!(" throw \"Bad FAT type: {}\";\n", ty)),
1623 }
1624 }
1625 out.push_str(&format!(
1626 " {} = {}[{}].apply({}, __args);\n",
1627 r(dst),
1628 r(objr),
1629 r(memr),
1630 r(objr)
1631 ));
1632 return Ok((out, 6 + num * 2));
1633 }
1634 out.push_str(&format!(
1635 " {} = {}[{}]();\n",
1636 r(dst),
1637 r(objr),
1638 r(memr)
1639 ));
1640 Ok((out, 5))
1641 }
1642 _ => bail!("emit_call_like called with non-call opcode {}", op),
1643 }
1644}
1645
1646fn reg_name(idx: i32) -> String {
1647 if idx >= 0 {
1648 format!("r{}", idx)
1649 } else {
1650 format!("rN{}", -idx)
1651 }
1652}
1653
1654fn variant_to_tjs(v: &Variant, pools: &ConstPools, _obj_index: usize) -> String {
1655 match v {
1656 Variant::Void => "void".to_string(),
1657 Variant::NullObject => "null".to_string(),
1658 Variant::Unknown => "void /* Unknown */".to_string(),
1659 Variant::String(i) => {
1660 let s = pools
1661 .strings
1662 .get(*i as usize)
1663 .map(|x| x.as_str())
1664 .unwrap_or("");
1665 quote_tjs_string(s)
1666 }
1667 Variant::Octet(i) => {
1668 format!("void /* Octet #{} (not materialized) */", i)
1671 }
1672 Variant::Real(i) => pools
1673 .doubles
1674 .get(*i as usize)
1675 .copied()
1676 .unwrap_or(0.0)
1677 .to_string(),
1678 Variant::Byte(i) => pools
1679 .bytes
1680 .get(*i as usize)
1681 .copied()
1682 .unwrap_or(0)
1683 .to_string(),
1684 Variant::Short(i) => pools
1685 .shorts
1686 .get(*i as usize)
1687 .copied()
1688 .unwrap_or(0)
1689 .to_string(),
1690 Variant::Integer(i) => pools
1691 .ints
1692 .get(*i as usize)
1693 .copied()
1694 .unwrap_or(0)
1695 .to_string(),
1696 Variant::Long(i) => pools
1697 .longs
1698 .get(*i as usize)
1699 .copied()
1700 .unwrap_or(0)
1701 .to_string(),
1702 Variant::InterObject(i) => format!("__tjs2dec_objs[{}]", i),
1703 Variant::InterGenerator(i) => format!("__tjs2dec_objs[{}] /* InterGenerator */", i),
1704 }
1705}
1706
1707fn quote_tjs_string(s: &str) -> String {
1708 let mut out = String::new();
1709 out.push('"');
1710 for ch in s.chars() {
1711 match ch {
1712 '\\' => out.push_str("\\\\"),
1713 '"' => out.push_str("\\\""),
1714 '\n' => out.push_str("\\n"),
1715 '\r' => out.push_str("\\r"),
1716 '\t' => out.push_str("\\t"),
1717 _ => out.push(ch),
1718 }
1719 }
1720 out.push('"');
1721 out
1722}
1723
1724fn ensure(code: &[i32], i: usize, need: usize) -> Result<()> {
1725 if i + need > code.len() {
1726 bail!(
1727 "truncated instruction at {}: need {}, code_len {}",
1728 i,
1729 need,
1730 code.len()
1731 );
1732 }
1733 Ok(())
1734}
1735
1736fn insn_len(code: &[i32], pc: usize) -> Result<usize> {
1737 let op = code[pc];
1738
1739 if op == vm::VM_CONST {
1740 return Ok(3);
1741 }
1742 for base in [
1743 vm::VM_CP,
1744 vm::VM_CEQ,
1745 vm::VM_CDEQ,
1746 vm::VM_CLT,
1747 vm::VM_CGT,
1748 vm::VM_CHKINS,
1749 vm::VM_ADDCI,
1750 vm::VM_CHGTHIS,
1751 ] {
1752 if op == base {
1753 return Ok(3);
1754 }
1755 }
1756 for base in [
1757 vm::VM_CL,
1758 vm::VM_SRV,
1759 vm::VM_GLOBAL,
1760 vm::VM_THROW,
1761 vm::VM_TT,
1762 vm::VM_TF,
1763 vm::VM_SETF,
1764 vm::VM_SETNF,
1765 vm::VM_LNOT,
1766 vm::VM_BNOT,
1767 vm::VM_ASC,
1768 vm::VM_CHR,
1769 vm::VM_NUM,
1770 vm::VM_CHS,
1771 vm::VM_INV,
1772 vm::VM_CHKINV,
1773 vm::VM_TYPEOF,
1774 vm::VM_EVAL,
1775 vm::VM_EEXP,
1776 vm::VM_INT,
1777 vm::VM_REAL,
1778 vm::VM_STR,
1779 vm::VM_OCTET,
1780 ] {
1781 if op == base {
1782 return Ok(2);
1783 }
1784 }
1785 if op == vm::VM_CCL {
1786 return Ok(3);
1787 }
1788 for base in [vm::VM_JF, vm::VM_JNF, vm::VM_JMP] {
1789 if op == base {
1790 return Ok(2);
1791 }
1792 }
1793 if op == vm::VM_ENTRY {
1794 return Ok(3);
1795 }
1796 for base in [
1797 vm::VM_RET,
1798 vm::VM_NOP,
1799 vm::VM_NF,
1800 vm::VM_EXTRY,
1801 vm::VM_REGMEMBER,
1802 vm::VM_DEBUGGER,
1803 ] {
1804 if op == base {
1805 return Ok(1);
1806 }
1807 }
1808 if op == vm::VM_SETP || op == vm::VM_GETP {
1809 return Ok(3);
1810 }
1811 if op == vm::VM_DELD || op == vm::VM_TYPEOFD {
1812 return Ok(4);
1813 }
1814 if op == vm::VM_DELI || op == vm::VM_TYPEOFI {
1815 return Ok(4);
1816 }
1817 if op == vm::VM_GPD || op == vm::VM_GPDS {
1818 return Ok(4);
1819 }
1820 if op == vm::VM_SPD || op == vm::VM_SPDE || op == vm::VM_SPDEH || op == vm::VM_SPDS {
1821 return Ok(4);
1822 }
1823 if op == vm::VM_GPI || op == vm::VM_GPIS {
1824 return Ok(4);
1825 }
1826 if op == vm::VM_SPI || op == vm::VM_SPIE || op == vm::VM_SPIS {
1827 return Ok(4);
1828 }
1829
1830 for base in [vm::VM_INC, vm::VM_DEC] {
1832 if op == base {
1833 return Ok(2);
1834 }
1835 if op == base + 1 {
1836 return Ok(4);
1837 }
1838 if op == base + 2 {
1839 return Ok(4);
1840 }
1841 if op == base + 3 {
1842 return Ok(3);
1843 }
1844 }
1845 for base in [
1847 vm::VM_LOR,
1848 vm::VM_LAND,
1849 vm::VM_BOR,
1850 vm::VM_BXOR,
1851 vm::VM_BAND,
1852 vm::VM_SAR,
1853 vm::VM_SAL,
1854 vm::VM_SR,
1855 vm::VM_ADD,
1856 vm::VM_SUB,
1857 vm::VM_MOD,
1858 vm::VM_DIV,
1859 vm::VM_IDIV,
1860 vm::VM_MUL,
1861 ] {
1862 if op == base {
1863 return Ok(3);
1864 }
1865 if op == base + 1 {
1866 return Ok(5);
1867 }
1868 if op == base + 2 {
1869 return Ok(5);
1870 }
1871 if op == base + 3 {
1872 return Ok(4);
1873 }
1874 }
1875
1876 if op == vm::VM_CALL || op == vm::VM_NEW {
1878 ensure(code, pc, 4)?;
1879 let argc = code[pc + 3];
1880 if argc >= 0 {
1881 return Ok(4 + argc as usize);
1882 }
1883 if argc == -1 {
1884 return Ok(4);
1885 }
1886 if argc == -2 {
1887 ensure(code, pc, 5)?;
1888 let num = code[pc + 4] as usize;
1889 return Ok(5 + num * 2);
1890 }
1891 return Ok(4);
1892 }
1893 if op == vm::VM_CALLD || op == vm::VM_CALLI {
1894 ensure(code, pc, 5)?;
1895 let argc = code[pc + 4];
1896 if argc >= 0 {
1897 return Ok(5 + argc as usize);
1898 }
1899 if argc == -1 {
1900 return Ok(5);
1901 }
1902 if argc == -2 {
1903 ensure(code, pc, 6)?;
1904 let num = code[pc + 5] as usize;
1905 return Ok(6 + num * 2);
1906 }
1907 return Ok(5);
1908 }
1909
1910 Ok(1)
1911}