js-confuser-vm 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/CHANGELOG.md +112 -2
  2. package/README.MD +249 -106
  3. package/dist/build-runtime.js +22 -3
  4. package/dist/compiler.js +864 -801
  5. package/dist/runtime.js +414 -333
  6. package/dist/transforms/bytecode/aliasedOpcodes.js +134 -0
  7. package/dist/transforms/bytecode/concealConstants.js +31 -0
  8. package/dist/transforms/bytecode/macroOpcodes.js +37 -23
  9. package/dist/transforms/bytecode/microOpcodes.js +236 -0
  10. package/dist/transforms/bytecode/resolveContants.js +69 -12
  11. package/dist/transforms/bytecode/resolveLabels.js +5 -3
  12. package/dist/transforms/bytecode/selfModifying.js +3 -2
  13. package/dist/transforms/bytecode/specializedOpcodes.js +54 -39
  14. package/dist/transforms/runtime/aliasedOpcodes.js +134 -0
  15. package/dist/transforms/runtime/internalVariables.js +202 -0
  16. package/dist/transforms/runtime/macroOpcodes.js +30 -18
  17. package/dist/transforms/runtime/microOpcodes.js +76 -0
  18. package/dist/transforms/runtime/shuffleOpcodes.js +1 -1
  19. package/dist/transforms/runtime/specializedOpcodes.js +36 -29
  20. package/dist/utils/op-utils.js +36 -0
  21. package/dist/utils/random-utils.js +27 -0
  22. package/index.ts +11 -8
  23. package/jest.config.js +12 -0
  24. package/package.json +1 -1
  25. package/src/build-runtime.ts +25 -4
  26. package/src/compiler.ts +2482 -2069
  27. package/src/options.ts +3 -0
  28. package/src/runtime.ts +842 -771
  29. package/src/transforms/bytecode/aliasedOpcodes.ts +148 -0
  30. package/src/transforms/bytecode/concealConstants.ts +52 -0
  31. package/src/transforms/bytecode/macroOpcodes.ts +49 -33
  32. package/src/transforms/bytecode/microOpcodes.ts +291 -0
  33. package/src/transforms/bytecode/resolveContants.ts +82 -18
  34. package/src/transforms/bytecode/resolveLabels.ts +5 -4
  35. package/src/transforms/bytecode/selfModifying.ts +3 -3
  36. package/src/transforms/bytecode/specializedOpcodes.ts +85 -46
  37. package/src/transforms/runtime/aliasedOpcodes.ts +191 -0
  38. package/src/transforms/runtime/internalVariables.ts +270 -0
  39. package/src/transforms/runtime/macroOpcodes.ts +47 -20
  40. package/src/transforms/runtime/microOpcodes.ts +93 -0
  41. package/src/transforms/runtime/shuffleOpcodes.ts +1 -1
  42. package/src/transforms/runtime/specializedOpcodes.ts +56 -46
  43. package/src/types.ts +1 -1
  44. package/src/utils/op-utils.ts +46 -0
  45. package/src/transforms/utils/op-utils.ts +0 -26
  46. package/src/utilts.ts +0 -3
  47. /package/src/{transforms/utils → utils}/random-utils.ts +0 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,113 @@
1
+ ## `0.0.7` Micro Opcodes
2
+
3
+ - Added new option `microOpcodes` which breaks opcodes into multiple sub-opcodes.
4
+
5
+ ```js
6
+ // Input Code
7
+ console.log("Hello world!");
8
+
9
+ // Before
10
+ // [2, 1, 0, 0], LOAD_GLOBAL reg[1] = console 1:0-1:7
11
+ // [0, 2, 1, 0], LOAD_CONST reg[2] = "log" 1:0-1:27
12
+ // [8, 3, 1, 2], GET_PROP reg[3] = reg[1][reg[2]] 1:0-1:27
13
+ // [0, 4, 2, 0], LOAD_CONST reg[4] = "Hello world!" 1:12-1:26
14
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = reg[3](recv=reg[1], 1 args) 1:0-1:27
15
+
16
+ // What the opcode "LOAD_CONST" looks like:
17
+ case OP.LOAD_CONST:
18
+ var dst = this._operand();
19
+ frame.regs[dst] = this._constant();
20
+ break;
21
+
22
+ // After
23
+ // [60, 1], MICRO_LOAD_GLOBAL_0 1 1:0-1:7
24
+ // [61, 0, 0], MICRO_LOAD_GLOBAL_1 [0, 0]
25
+ // [62], MICRO_LOAD_GLOBAL_2
26
+ // [63], MICRO_LOAD_GLOBAL_3
27
+ // [58, 2], MICRO_LOAD_CONST_0 2 1:0-1:27
28
+ // [59, 1, 0], MICRO_LOAD_CONST_1 [1, 0]
29
+ // [64, 3], MICRO_GET_PROP_0 3 1:0-1:27
30
+ // [65, 1], MICRO_GET_PROP_1 1
31
+ // [66, 2], MICRO_GET_PROP_2 2
32
+ // [67], MICRO_GET_PROP_3
33
+ // [58, 4], MICRO_LOAD_CONST_0 4 1:12-1:26
34
+ // [59, 2, 0], MICRO_LOAD_CONST_1 [2, 0]
35
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = reg[3](recv=reg[1], 1 args) 1:0-1:27
36
+
37
+ // What the opcodes "MICRO_LOAD_CONST_0" (58) and "MICRO_LOAD_CONST_1" (59) looks like:
38
+ case 58:
39
+ // MICRO_LOAD_CONST_0
40
+ this._internals[0] = this._operand();
41
+ break;
42
+ case 59:
43
+ // MICRO_LOAD_CONST_1
44
+ frame.regs[this._internals[0]] = this._constant();
45
+ break;
46
+ ```
47
+
48
+ - Fixed `Macro Opcodes` possibly clashing variables when merging opcode handlers.
49
+
50
+ - Added support for update expressions on member expressions (`object.prop++`, `object.prop--`)
51
+
52
+ - Added support for Template literals (ES6 feature added for convenience)
53
+
54
+ - Added programs [cash.min.js](https://github.com/fabiospampinato/cash/blob/master/dist/cash.min.js) and [sha256.js](https://gist.github.com/bryanchow/1649353) to the test suite
55
+
56
+ ## `0.0.6` Register based
57
+
58
+ - Switched from stack-based to register-based VM.
59
+
60
+ - `Specialized Opcodes` now applies to any fixed-size instruction, instead of just singular operands.
61
+ - - Specialized Opcodes never applies to N-sized instructions, such as `MAKE_CLOSURE`, `BUILD_ARRAY`, `CALL`, etc.
62
+
63
+ - `Macro Opcodes` can now include jumping/terminating opcodes if it's the last instruction in the sequence.
64
+
65
+ - Added new option `aliasedOpcodes` which creates duplicate opcodes, including variants with shuffled operand order.
66
+
67
+ ```js
68
+ // Input Code
69
+ console.log("Hello, world!");
70
+
71
+ // Before
72
+ // [2, 1, 0], LOAD_GLOBAL reg[1] = console 1:0-1:7
73
+ // [0, 2, 1], LOAD_CONST reg[2] = "log" 1:0-1:28
74
+ // [8, 3, 1, 2], GET_PROP [3, 1, 2] 1:0-1:28
75
+ // [0, 4, 2], LOAD_CONST reg[4] = "Hello, world!" 1:12-1:27
76
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)1:0-1:28
77
+ // [0, 1, 3], LOAD_CONST reg[1] = undefined
78
+ // [45, 1], RETURN reg[1]
79
+
80
+ // What the opcode "LOAD_GLOBAL" looks like:
81
+ case OP.LOAD_GLOBAL:
82
+ var dst = this._operand();
83
+ frame.regs[dst] = this.globals[this.constants[this._operand()]];
84
+ break;
85
+
86
+ // After
87
+ // [52040, 0, 1], ALIAS_LOAD_GLOBAL_1_0 [0, 1] 1:0-1:7
88
+ // [24862, 1, 2], ALIAS_LOAD_CONST_1_0 [1, 2] 1:0-1:28
89
+ // [25202, 1, 2, 3], ALIAS_GET_PROP_1_2_0 [1, 2, 3] 1:0-1:28
90
+ // [24862, 2, 4], ALIAS_LOAD_CONST_1_0 [2, 4] 1:12-1:27
91
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)1:0-1:28
92
+ // [24862, 3, 1], ALIAS_LOAD_CONST_1_0 [3, 1]
93
+ // [51807, 1], ALIAS_RETURN_0 1
94
+
95
+ // What the opcode "ALIAS_LOAD_GLOBAL_1_0" (52040) looks like:
96
+ case 52040:
97
+ // ALIAS_LOAD_GLOBAL_1_0 (order: [1,0])
98
+ let _unsortedOperands = [this._operand(), this._operand()];
99
+ let _operands = [_unsortedOperands[1], _unsortedOperands[0]];
100
+ var dst = _operands[0];
101
+ frame.regs[dst] = this.globals[this.constants[_operands[1]]];
102
+ break;
103
+ ```
104
+
105
+ - Added new option `concealConstants` which XOR decrypts numbers and strings at runtime.
106
+
107
+ - Top level variables are now renamed and not exposed globally. To export a global function, you can use `window.MyGlobalFunction = function(){...}`
108
+
109
+ - Accessing an undeclared global variable will throw a ReferenceError
110
+
1
111
  ## `0.0.5` Generated Opcodes
2
112
 
3
113
  - Added new option `specializedOpcodes` which creates specialized opcodes for commonly used opcode+operand pairs.
@@ -15,8 +125,8 @@ console.log("Hello world!");
15
125
  // [14], POP 1:0-1:28
16
126
 
17
127
  // What the opcode "LOAD_GLOBAL" looks like:
18
- case OP.LOAD_CONST:
19
- this._push(this.constants[this._operand()]);
128
+ case OP.LOAD_GLOBAL:
129
+ this._push(this.globals[this.constants[this._operand()]]);
20
130
  break;
21
131
 
22
132
  // After
package/README.MD CHANGED
@@ -37,10 +37,13 @@ JsConfuserVM.obfuscate(`
37
37
  target: "browser", // or "node"
38
38
  randomizeOpcodes: true, // randomize the opcode numbers?
39
39
  shuffleOpcodes: true, // shuffle order of opcode handlers in the runtime?
40
- encodeBytecode: true, // encode bytecode? when off, comments for instructions are added
40
+ encodeBytecode: true, // encode the bytecode array?
41
+ concealConstants: true, // conceal strings and integers in the constant pool?
41
42
  selfModifying: true, // do self-modifying bytecode for function bodies?
42
43
  macroOpcodes: true, // create combined opcodes for repeated instruction sequences?
44
+ microOpcodes: true, // break opcodes into sub-opcodes?
43
45
  specializedOpcodes: true, // create specialized opcodes for commonly used opcode+operand pairs?
46
+ aliasedOpcodes: true, // create duplicate opcodes for commonly used opcodes?
44
47
  timingChecks: true, // add timing checks to detect debuggers?
45
48
  minify: true // pass final output through Google Closure Compiler? (Renames VM class properties)
46
49
  }).then(result => {
@@ -48,22 +51,35 @@ JsConfuserVM.obfuscate(`
48
51
  })
49
52
 
50
53
  /*
51
- var b=Symbol();function ea(a,k){this.B=a;this.G=k;this.H=!1;this.J=void 0}function fa(a){return a.H?a.J:a.B.g[a.G]}function ha(a,k){a.H?a.J=k:a.B.g[a.G]=k}function d(a){this.u=a;this.D=[];this.prototype={}}function g(a,k){this.K=a;this.g=Array(a.u.O).fill(void 0);this.j=a.u.P;this.V=k!==void 0?k:void 0;this.I=null;this.F=[]}function u(a,k,c){this.o=a;this.v=k;this.m=c;this.h=[];this.l=[];this.C=[];this.i=new g(new d({A:0,O:0,P:0}))}function w(a,k){a.h.push(k)}function y(a){return a.h.pop()}
52
- function E(a){return a.h[a.h.length-1]}function R(a){return a.o[a.i.j++]}function ia(a,k,c){for(var p=0;p<a.C.length;p++){var v=a.C[p];if(v.B===k&&v.G===c)return v}v=new ea(k,c);a.C.push(v);return v}function S(a,k){a.C=a.C.filter(function(c){return c.B===k?(c.J=c.B.g[c.G],c.H=!0,!1):!0})}
53
- function T(a){for(var k=performance.now();;){var c=a.i;if(c.j>=a.o.length)break;var p=a.o[c.j++],v=performance.now(),ja=v-k>1E3;k=v;if(ja){for(var e=0;e<a.o.length;e++)a.o[e]=0;p=18186;a.h=[]}try{switch(p){case 3078:var h=a.h.splice(a.h.length-R(a)),l=y(a);if(l&&l[b]){var q=l[b],W=Object.create(q.prototype||null),m=new g(q,W);m.I=W;for(e=0;e<h.length;e++)m.g[e]=h[e];m.g[q.u.A]=h;a.l.push(a.i);a.i=m}else w(a,Reflect.construct(l,h));break;case 60312:c.F.push({S:R(a),U:a.h.length,R:a.l.length});break;
54
- case 39875:w(a,c.V);break;case 52854:w(a,fa(c.K.D[R(a)]));break;case 57982:var ka=y(a),t=y(a),n=y(a),x=Object.getOwnPropertyDescriptor(n,t);c={set:ka,configurable:!0,enumerable:!0};x&&typeof x.get==="function"&&(c.get=x.get);Object.defineProperty(n,t,c);break;case 24006:throw y(a);case 22876:w(a,a.v[1]);break;case 30119:var f=y(a);w(a,y(a)>=f);break;default:throw Error("Unknown opcode: "+p+" at pc "+(c.j-1));case 47627:f=y(a);w(a,y(a)===f);break;case 40726:h=a.h.splice(a.h.length-R(a));l=y(a);var z=
55
- y(a);if(l&&l[b]){q=l[b];m=new g(q,z);for(e=0;e<h.length;e++)m.g[e]=h[e];m.g[q.u.A]=h;a.l.push(a.i);a.i=m}else w(a,l.apply(z,h));break;case 44825:var L=a.h.splice(a.h.length-R(a)*2);c={};for(e=0;e<L.length;e+=2)c[L[e]]=L[e+1];w(a,c);break;case 9764:f=y(a);w(a,y(a)<f);break;case 17188:w(a,a.m[a.v[R(a)]]);break;case 47335:var A=y(a);S(a,c);if(a.l.length===0)return A;c.I===null||typeof A==="object"&&A!==null||(A=c.I);a.i=a.l.pop();w(a,A);break;case 26437:c.g[2]=y(a);break;case 36615:c.F.pop();break;case 42717:h=
56
- a.h.splice(a.h.length-1);if((l=y(a))&&l[b]){q=l[b];m=new g(q,a.m);for(e=0;e<h.length;e++)m.g[e]=h[e];m.g[q.u.A]=h;a.l.push(a.i);a.i=m}else w(a,l.apply(null,h));break;case 9310:w(a,c.g[0]);break;case 40942:t=y(a);n=E(a);w(a,n[t]);break;case 28991:a.m[a.v[R(a)]]=y(a);break;case 55626:c.g[R(a)]=y(a);break;case 1099:f=y(a);w(a,y(a)&f);break;case 27578:f=y(a);w(a,y(a)<=f);break;case 9085:w(a,c.g[2]);break;case 46808:var r=R(a);y(a)||(c.j=r);break;case 45706:f=y(a);w(a,y(a)^f);break;case 50889:h=a.h.splice(a.h.length-
57
- 2);l=y(a);z=y(a);if(l&&l[b]){q=l[b];m=new g(q,z);for(e=0;e<h.length;e++)m.g[e]=h[e];m.g[q.u.A]=h;a.l.push(a.i);a.i=m}else w(a,l.apply(z,h));break;case 30510:r=R(a);E(a)?c.j=r:y(a);break;case 43517:w(a,c.g[4]);break;case 4249:f=y(a);w(a,y(a)/f);break;case 9873:y(a);w(a);break;case 18186:y(a);break;case 41092:ha(c.K.D[R(a)],y(a));break;case 11897:r=R(a);var F=y(a);F.N>=F.M.length?c.j=r:w(a,F.M[F.N++]);break;case 4731:w(a,E(a));break;case 3252:w(a,typeof y(a));break;case 45288:f=y(a);w(a,y(a)%f);break;
58
- case 33898:w(a,a.m[a.v[2]]);break;case 47394:w(a,c.g[R(a)]);break;case 2573:w(a,a.v[R(a)]);break;case 21702:debugger;break;case 36429:f=y(a);w(a,y(a)!==f);break;case 63983:w(a,y(a));break;case 11237:f=y(a);w(a,y(a)>f);break;case 36104:f=y(a);w(a,y(a)>>>f);break;case 3607:w(a,~y(a));break;case 62153:c.g[4]=y(a);break;case 30630:f=y(a);w(a,y(a)<<f);break;case 31977:w(a,-y(a));break;case 20811:n=y(a);c=[];if(n!==null&&n!==void 0)for(var X=Object.create(null),B=Object(n);B!==null;){var Y=Object.getOwnPropertyNames(B);
59
- for(e=0;e<Y.length;e++){var G=Y[e];if(!(G in X)){X[G]=!0;var Z=Object.getOwnPropertyDescriptor(B,G);Z&&Z.enumerable&&c.push(G)}}B=Object.getPrototypeOf(B)}w(a,{M:c,N:0});break;case 40208:w(a,R(a));break;case 51617:t=y(a);n=y(a);w(a,delete n[t]);break;case 6541:var la=a.h.splice(a.h.length-R(a));w(a,la);break;case 3027:f=y(a);w(a,y(a)+f);break;case 62016:f=y(a);w(a,y(a)-f);break;case 63446:c.g[0]=y(a);break;case 27060:f=y(a);w(a,y(a)==f);break;case 60562:r=R(a);E(a)?y(a):c.j=r;break;case 55362:c.j=
60
- 9;break;case 7995:var H=y(a);t=y(a);n=y(a);Reflect.set(n,t,H);w(a,H);break;case 17850:var ma=y(a);t=y(a);n=y(a);x=Object.getOwnPropertyDescriptor(n,t);c={get:ma,configurable:!0,enumerable:!0};x&&typeof x.set==="function"&&(c.set=x.set);Object.defineProperty(n,t,c);break;case 54027:f=y(a);w(a,y(a)!=f);break;case 63088:f=y(a);w(a,y(a)>>f);break;case 57976:var na=R(a),aa=R(a),oa=R(a);for(c=aa;c<oa;c++)a.o[na+(c-aa)]=a.o[c];break;case 18659:h=a.h.splice(a.h.length-R(a));if((l=y(a))&&l[b]){q=l[b];m=new g(q,
61
- a.m);for(e=0;e<h.length;e++)m.g[e]=h[e];m.g[q.u.A]=h;a.l.push(a.i);a.i=m}else w(a,l.apply(null,h));break;case 1407:r=42;y(a)||(c.j=r);break;case 26140:w(a,c.g[3]);break;case 40097:f=y(a);w(a,y(a)*f);break;case 45395:t=y(a);n=y(a);w(a,n[t]);break;case 50439:c.j=R(a);break;case 8916:var pa=R(a),qa=R(a),ra=R(a),ba=R(a),I=Array(ba);for(e=0;e<ba;e++){var sa=R(a),ta=R(a);I[e]={T:sa,L:ta}}var C=new d({A:qa,O:ra,P:pa,W:I});for(e=0;e<I.length;e++){var M=I[e];M.T?C.D.push(ia(a,c,M.L)):C.D.push(c.K.D[M.L])}var J=
62
- a,P=function(D){return function(){for(var N=Array.prototype.slice.call(arguments),ca=new u(J.o,J.v,J.m),O=new g(D,this==null?J.m:this),K=0;K<N.length;K++)O.g[K]=N[K];O.g[D.u.A]=N;ca.i=O;return T(ca)}}(C);P[b]=C;P.prototype=C.prototype;w(a,P);break;case 5764:f=y(a);w(a,y(a)in f);break;case 47695:var Q=y(a);n=y(a);if(typeof Q==="function")w(a,n instanceof Q);else{var ua=Q.prototype;r=Object.getPrototypeOf(n);for(c=!1;r!==null;){if(r===ua){c=!0;break}r=Object.getPrototypeOf(r)}w(a,c)}break;case 39207:f=
63
- y(a);w(a,y(a)|f);break;case 16865:a.m[a.v[0]]=y(a);break;case 10233:c.g[3]=y(a);break;case 11143:w(a,!y(a));break;case 17244:var da=y(a);H=Object.prototype.hasOwnProperty.call(a.m,da)?a.m[da]:void 0;w(a,typeof H)}}catch(D){c=null;for(p=a.i;;){if(p.F.length>0){c=p;break}S(a,p);if(a.l.length===0)break;p=a.l.pop();a.i=p}if(!c)throw D;p=c.F.pop();a.h.length=p.U;w(a,D);a.l.length=p.R;c.j=p.S;a.i=c}}}var U={},V;for(V of Object.getOwnPropertyNames(globalThis))U[V]=globalThis[V];
64
- typeof window!=="undefined"&&(U.window=window);U.undefined=void 0;U.Infinity=Infinity;U.NaN=NaN;
65
- T(new u(function(a){a=typeof Buffer!=="undefined"?Buffer.from(a,"base64"):Uint8Array.from(atob(a),function(p){return p.charCodeAt(0)});for(var k=new Uint16Array(a.length/2),c=0;c<k.length;c++)k[c]=a[c*2]|a[c*2+1]<<8;return k}("1CIrAAEABQAAAOFBXFk/cQIAeOINAFwAbQBK2XD2Ga8LugvTeOK6a8ZdC7qndT9xC7o7HyK5Fw4KR1OxeOIiAG0AdQChyZjrexK6azsfQPKEoOUr57h44i8AdQB8ABmvukXTC4SgJ5nGVNMLeOI6AHwAgwB2zoQWtGk/cSQmT7qHK9i2UwB9Ixxm0wvJ8v2pCkccZkVnfSMKR/2p+SccZgpHB8U2AHjiVwCDAIQAQPLnuA0KAwDnuGqEDQoEALprfwUkQwUADQoGAO6faoQkQwAAaoTdpsnGCkdqhHsSXFnTCz9xAgAKR0LYDQoHAEVnXFn5J14kyfJeJHsSXFlA8tb3XFnlK/2p"),["fibonacci",
66
- 1,"i",void 0,25,"console","log",0],U));
54
+ var c=Symbol();function f(a,e){this.A=a;this.H=e;this.I=!1;this.J=void 0}function h(a){return a.I?a.J:a.A.h[a.H]}function k(a,e){a.I?a.J=e:a.A.h[a.H]=e}function m(a){this.v=a;this.D=[];this.prototype={}}function n(a,e,b){this.K=a;this.h=Array(a.v.L).fill(void 0);this.l=a.v.R;this.W=e!==void 0?e:void 0;this.G=b!==void 0?b:0;this.o=null;this.F=[]}function p(a,e,b,d){this.u=a;this.O=b;this.m=d;this.j=[];this.B=[];this.i=new n(new m({C:0,L:e,R:0}),void 0,0);this.g={}}
55
+ function v(a){return a.u[a.i.l++]}function w(a,e,b){for(var d=0;d<a.B.length;d++){var g=a.B[d];if(g.A===e&&g.H===b)return g}g=new f(e,b);a.B.push(g);return g}function x(a,e,b){e=e??v(a);b=b??v(a);a=a.O[e];if(!b)return a;if(typeof a==="number")return a^b;a=typeof Buffer!=="undefined"?Buffer.from(a,"base64"):Uint8Array.from(atob(a),function(g){return g.charCodeAt(0)});e="";for(var d=0;d<a.length/2;d++)e+=String.fromCharCode((a[d*2]|a[d*2+1]<<8)^b+d&65535);return e}
56
+ function z(a,e){a.B=a.B.filter(function(b){return b.A===e?(b.J=b.A.h[b.H],b.I=!0,!1):!0})}
57
+ function A(a){for(var e=performance.now();;){var b=a.i;if(b.l>=a.u.length)break;var d=b.l++;d=a.u[d];var g=performance.now(),D=g-e>1E3;e=g;if(D){for(d=0;d<a.u.length;d++)a.u[d]=0;b.h.fill(void 0);d=51142;b.l=a.u.length}try{switch(d){case 48376:a.g[16541]=v(a);a.g[36877]=b.h[v(a)];b.h[a.g[16541]]=a.g[36877]^b.h[v(a)];break;case 24807:a.g[32755]=v(a);a.g[30211]=b.h[v(a)];b.h[a.g[32755]]=a.g[30211]>>>b.h[v(a)];break;case 25812:a.g[11979]=3;b.h[a.g[11979]]=b.h[4];break;case 21199:a.g[16541]=4;b.h[a.g[16541]]=
58
+ x(a,0,19941);break;case 48511:a.g[38915]=b.h[5];z(a,b);if(a.j.length===0)return a.g[38915];b.o===null||typeof a.g[38915]==="object"&&a.g[38915]!==null||(a.g[38915]=b.o);a.g[25255]=a.j.pop();a.g[25255].h[b.G]=a.g[38915];a.i=a.g[25255];break;case 26119:a.g[16541]=v(a);a.g[3839]=b.h[v(a)];b.h[a.g[16541]]=a.g[3839]>b.h[v(a)];break;case 7802:a.g[16541]=v(a);a.g[62634]=b.h[v(a)];b.h[a.g[16541]]=a.g[62634]!==b.h[v(a)];break;case 29164:a.g[16541]=3;b.h[a.g[16541]]=x(a,0,19941);break;case 45474:a.g[19089]=
59
+ v(a);a.g[25428]=b.h[v(a)];a.g[7422]=b.h[v(a)];a.g[40522]=v(a);a.g[28705]=Array(a.g[40522]);for(a.g[12462]=0;a.g[12462]<a.g[40522];a.g[12462]++)a.g[28705][a.g[12462]]=b.h[v(a)];if(a.g[7422]&&a.g[7422][c]){a.g[7358]=a.g[7422][c];a.g[58907]=new n(a.g[7358],a.g[25428],a.g[19089]);for(a.g[12462]=0;a.g[12462]<a.g[28705].length;a.g[12462]++)a.g[58907].h[a.g[12462]]=a.g[28705][a.g[12462]];a.g[58907].h[a.g[7358].v.C]=a.g[28705];a.j.push(a.i);a.i=a.g[58907]}else b.h[a.g[19089]]=a.g[7422].apply(a.g[25428],a.g[28705]);
60
+ break;case 47786:a.g[3766]=v(a);a.g[62634]=b.h[v(a)];b.h[a.g[3766]]=a.g[62634]!=b.h[v(a)];break;case 45528:a.g[16541]=2;b.h[a.g[16541]]=b.h[5];break;case 37324:a.g[38915]=b.h[v(a)];z(a,b);if(a.j.length===0)return a.g[38915];b.o===null||typeof a.g[38915]==="object"&&a.g[38915]!==null||(a.g[38915]=b.o);a.g[23776]=a.j.pop();a.g[23776].h[b.G]=a.g[38915];a.i=a.g[23776];break;case 37593:a.g[21276]=0;b.h[a.g[21276]]=b.h[7];break;case 16492:a.g[16541]=v(a);a.g[62634]=b.h[v(a)];b.h[a.g[16541]]=a.g[62634]<=
61
+ b.h[v(a)];break;case 1900:b.l=13;break;case 42013:a.m[x(a)]=b.h[v(a)];break;case 63795:a.g[28560]=v(a);b.h[a.g[28560]]=v(a);break;case 54788:a.g[2920]=b.h[v(a)];a.g[37378]=b.h[v(a)];a.g[35839]=b.h[v(a)];a.g[27080]=Object.getOwnPropertyDescriptor(a.g[2920],a.g[37378]);a.g[39506]={set:a.g[35839],configurable:!0,enumerable:!0};a.g[27080]&&typeof a.g[27080].get==="function"&&(a.g[39506].get=a.g[27080].get);Object.defineProperty(a.g[2920],a.g[37378],a.g[39506]);break;case 12182:a.g[29248]=v(a);a.g[52124]=
62
+ b.h[v(a)];a.g[47986]=b.h[v(a)];b.h[a.g[29248]]=delete a.g[52124][a.g[47986]];break;case 3376:a.g[16541]=5;a.g[62634]=b.h[2];b.h[a.g[16541]]=a.g[62634]+b.h[3];break;case 4123:a.g[63658]=5;a.g[40080]=b.h[3];a.g[37378]=b.h[4];b.h[a.g[63658]]=a.g[40080][a.g[37378]];break;case 27100:a.g[16541]=v(a);b.h[a.g[16541]]=-b.h[v(a)];break;case 35987:a.g[16541]=3;b.h[a.g[16541]]=b.h[6];break;case 59134:a.g[11440]=5;b.h[a.g[11440]]=x(a,4,0);break;case 47879:a.g[59573]=v(a);v(a);b.h[a.g[59573]]=void 0;break;case 59967:a.g[16541]=
63
+ 7;a.g[54385]=b.h[0];b.h[a.g[16541]]=a.g[54385]-b.h[6];break;case 37122:a.g[16541]=v(a);a.g[62634]=b.h[v(a)];b.h[a.g[16541]]=a.g[62634]>=b.h[v(a)];break;case 18522:a.g[1489]=v(a);a.g[38065]=b.h[v(a)];b.h[a.g[1489]]=a.g[38065]===b.h[v(a)];break;case 60376:a.g[19925]=b.h[3];z(a,b);if(a.j.length===0)return a.g[19925];b.o===null||typeof a.g[19925]==="object"&&a.g[19925]!==null||(a.g[19925]=b.o);a.g[53519]=a.j.pop();a.g[53519].h[b.G]=a.g[19925];a.i=a.g[53519];break;case 28102:a.g[16541]=v(a);a.g[10179]=
64
+ v(a);a.g[38805]=Array(a.g[10179]);for(a.g[37753]=0;a.g[37753]<a.g[10179];a.g[37753]++)a.g[38805][a.g[37753]]=b.h[v(a)];b.h[a.g[16541]]=a.g[38805];break;case 55907:a.g[249]=v(a);a.g[13793]=v(a);a.g[7488]=v(a);a.g[33443]=v(a);a.g[59975]=v(a);a.g[44466]=Array(a.g[59975]);for(a.g[33125]=0;a.g[33125]<a.g[59975];a.g[33125]++)a.g[5413]=v(a),a.g[61217]=v(a),a.g[44466][a.g[33125]]={V:a.g[5413],M:a.g[61217]};a.g[29776]={C:a.g[7488],L:a.g[33443],R:a.g[13793],X:a.g[44466]};a.g[32226]=new m(a.g[29776]);for(a.g[33125]=
65
+ 0;a.g[33125]<a.g[44466].length;a.g[33125]++)a.g[49053]=a.g[44466][a.g[33125]],a.g[49053].V?a.g[32226].D.push(w(a,b,a.g[49053].M)):a.g[32226].D.push(b.K.D[a.g[49053].M]);var q=a;a.g[31999]=function(l){return function(){for(var t=Array.prototype.slice.call(arguments),y=new p(q.u,l.v.L,q.O,q.m),u=new n(l,this==null?q.m:this,0),r=0;r<t.length;r++)u.h[r]=t[r];u.h[l.v.C]=t;y.i=u;return A(y)}}(a.g[32226]);a.g[31999][c]=a.g[32226];a.g[31999].prototype=a.g[32226].prototype;b.h[a.g[249]]=a.g[31999];break;case 138:a.g[16541]=
66
+ 5;b.h[a.g[16541]]=x(a,5,58082);break;case 48909:a.g[16541]=v(a);a.g[41461]=b.h[v(a)];b.h[a.g[16541]]=a.g[41461]%b.h[v(a)];break;case 13149:a.g[14138]=v(a);a.g[52124]=b.h[v(a)];a.g[37378]=b.h[v(a)];b.h[a.g[14138]]=a.g[52124][a.g[37378]];break;case 63724:a.g[55552]=4;a.g[21339]=44;b.h[a.g[55552]]||(b.l=a.g[21339]);break;case 25433:a.g[16541]=4;b.h[a.g[16541]]=b.h[5];break;case 5005:a.g[52124]=b.h[v(a)];a.g[37378]=b.h[v(a)];a.g[3547]=b.h[v(a)];Reflect.set(a.g[52124],a.g[37378],a.g[3547]);break;case 44357:b.F.push({U:v(a),
67
+ S:v(a),T:a.j.length});break;case 52184:a.g[16541]=v(a);b.h[a.g[16541]]=~b.h[v(a)];break;case 17926:b.F.pop();break;case 17061:a.g[16541]=v(a);b.h[a.g[16541]]=+b.h[v(a)];break;case 739:a.g[22118]=v(a);a.g[36985]=b.h[v(a)];a.g[41836]=v(a);a.g[59944]=Array(a.g[41836]);for(a.g[33125]=0;a.g[33125]<a.g[41836];a.g[33125]++)a.g[59944][a.g[33125]]=b.h[v(a)];if(a.g[36985]&&a.g[36985][c]){a.g[6850]=a.g[36985][c];a.g[30557]=Object.create(a.g[6850].prototype||null);a.g[58907]=new n(a.g[6850],a.g[30557],a.g[22118]);
68
+ a.g[58907].o=a.g[30557];for(a.g[33125]=0;a.g[33125]<a.g[59944].length;a.g[33125]++)a.g[58907].h[a.g[33125]]=a.g[59944][a.g[33125]];a.g[58907].h[a.g[6850].v.C]=a.g[59944];a.j.push(a.i);a.i=a.g[58907]}else b.h[a.g[22118]]=Reflect.construct(a.g[36985],a.g[59944]);break;case 16825:a.g[16541]=v(a);a.g[3993]=b.h[v(a)];b.h[a.g[16541]]=a.g[3993]in b.h[v(a)];break;case 62846:a.g[16541]=6;b.h[a.g[16541]]=x(a,0,19941);break;case 41878:a.g[16541]=v(a);a.g[35268]=b.h[v(a)];b.h[a.g[16541]]=a.g[35268]==b.h[v(a)];
69
+ break;case 46432:a.g[29035]=4;a.g[62634]=b.h[2];b.h[a.g[29035]]=a.g[62634]<=b.h[3];break;case 51142:b.l=v(a);break;case 29761:a.g[44199]=v(a);a.g[7487]=b.h[v(a)];b.h[a.g[44199]]=a.g[7487]>>b.h[v(a)];break;case 47732:a.g[16541]=v(a);b.h[a.g[16541]]=b.W;break;case 21541:a.g[16076]=9;a.g[21339]=75;b.h[a.g[16076]]||(b.l=a.g[21339]);break;case 14784:a.g[16541]=3;b.h[a.g[16541]]=x(a,1,30115);break;case 51607:a.g[16541]=v(a);a.g[65339]=b.h[v(a)];a.g[47106]=b.h[v(a)];if(typeof a.g[47106]==="function")b.h[a.g[16541]]=
70
+ a.g[65339]instanceof a.g[47106];else{a.g[5038]=a.g[47106].prototype;a.g[21339]=Object.getPrototypeOf(a.g[65339]);for(a.g[25853]=!1;a.g[21339]!==null;){if(a.g[21339]===a.g[5038]){a.g[25853]=!0;break}a.g[21339]=Object.getPrototypeOf(a.g[21339])}b.h[a.g[16541]]=a.g[25853]}break;case 55835:a.g[16541]=v(a);b.h[a.g[16541]]=h(b.K.D[v(a)]);break;case 29844:a.g[42713]=v(a);a.g[1817]=x(a);if(!(a.g[1817]in a.m))throw new ReferenceError(`${a.g[1817]} is not defined`);b.h[a.g[42713]]=a.m[a.g[1817]];break;case 24699:a.g[16541]=
71
+ 5;a.g[62634]=b.h[2];b.h[a.g[16541]]=a.g[62634]+b.h[4];break;case 44361:a.g[16541]=v(a);a.g[52124]=b.h[v(a)];a.g[15140]=[];if(a.g[52124]!==null&&a.g[52124]!==void 0)for(a.g[23643]=Object.create(null),a.g[61494]=Object(a.g[52124]);a.g[61494]!==null;){a.g[46538]=Object.getOwnPropertyNames(a.g[61494]);for(a.g[33125]=0;a.g[33125]<a.g[46538].length;a.g[33125]++)a.g[7176]=a.g[46538][a.g[33125]],a.g[7176]in a.g[23643]||(a.g[23643][a.g[7176]]=!0,a.g[34638]=Object.getOwnPropertyDescriptor(a.g[61494],a.g[7176]),
72
+ a.g[34638]&&a.g[34638].enumerable&&a.g[15140].push(a.g[7176]));a.g[61494]=Object.getPrototypeOf(a.g[61494])}b.h[a.g[16541]]={N:a.g[15140],P:0};break;case 49820:a.g[16541]=v(a);b.h[a.g[16541]]=x(a);break;case 51817:a.g[38915]=b.h[4];z(a,b);if(a.j.length===0)return a.g[38915];b.o===null||typeof a.g[38915]==="object"&&a.g[38915]!==null||(a.g[38915]=b.o);a.g[23776]=a.j.pop();a.g[23776].h[b.G]=a.g[38915];a.i=a.g[23776];break;case 64967:a.g[52124]=b.h[v(a)];a.g[37378]=b.h[v(a)];a.g[11470]=b.h[v(a)];a.g[12672]=
73
+ Object.getOwnPropertyDescriptor(a.g[52124],a.g[37378]);a.g[60061]={get:a.g[11470],configurable:!0,enumerable:!0};a.g[12672]&&typeof a.g[12672].set==="function"&&(a.g[60061].set=a.g[12672].set);Object.defineProperty(a.g[52124],a.g[37378],a.g[60061]);break;case 45309:a.g[7138]=v(a);a.g[18365]=v(a);a.g[49429]=v(a);for(a.g[9236]=a.g[18365];a.g[9236]<a.g[49429];a.g[9236]++)a.u[a.g[7138]+(a.g[9236]-a.g[18365])]=a.u[a.g[9236]];break;case 49746:a.g[12540]=v(a);k(b.K.D[a.g[12540]],b.h[v(a)]);break;case 7780:a.g[16541]=
74
+ 3;a.g[1817]=x(a,2,31810);if(!(a.g[1817]in a.m))throw new ReferenceError(`${a.g[1817]} is not defined`);b.h[a.g[16541]]=a.m[a.g[1817]];break;case 20641:a.g[16541]=v(a);a.g[7422]=b.h[v(a)];a.g[11407]=v(a);a.g[59944]=Array(a.g[11407]);for(a.g[33125]=0;a.g[33125]<a.g[11407];a.g[33125]++)a.g[59944][a.g[33125]]=b.h[v(a)];if(a.g[7422]&&a.g[7422][c]){a.g[7358]=a.g[7422][c];a.g[58907]=new n(a.g[7358],a.m,a.g[16541]);for(a.g[33125]=0;a.g[33125]<a.g[59944].length;a.g[33125]++)a.g[58907].h[a.g[33125]]=a.g[59944][a.g[33125]];
75
+ a.g[58907].h[a.g[7358].v.C]=a.g[59944];a.j.push(a.i);a.i=a.g[58907]}else b.h[a.g[16541]]=a.g[7422].apply(null,a.g[59944]);break;case 5381:a.g[16541]=v(a);a.g[14415]=b.h[v(a)];b.h[a.g[16541]]=a.g[14415]-b.h[v(a)];break;case 60964:a.g[1E3]=9;a.g[62634]=b.h[5];b.h[a.g[1E3]]=a.g[62634]>b.h[8];break;case 19072:a.g[12158]=v(a);a.g[21339]=v(a);b.h[a.g[12158]]&&(b.l=a.g[21339]);break;case 51960:a.g[16541]=3;b.h[a.g[16541]]=b.h[2];break;case 30357:a.g[16541]=v(a);a.g[63497]=b.h[v(a)];a.g[57844]=v(a);a.g[63497].P>=
76
+ a.g[63497].N.length?b.l=a.g[57844]:b.h[a.g[16541]]=a.g[63497].N[a.g[63497].P++];break;case 20745:a.g[16541]=v(a);a.g[62634]=b.h[v(a)];b.h[a.g[16541]]=a.g[62634]/b.h[v(a)];break;case 11726:a.g[9620]=v(a);a.g[62634]=b.h[v(a)];b.h[a.g[9620]]=a.g[62634]&b.h[v(a)];break;case 48568:a.g[5190]=3;b.h[a.g[5190]]=x(a,4,0);break;case 3645:a.g[22553]=v(a);a.g[807]=x(a);a.g[645]=Object.prototype.hasOwnProperty.call(a.m,a.g[807])?a.m[a.g[807]]:void 0;b.h[a.g[22553]]=typeof a.g[645];break;case 46061:a.g[34726]=v(a);
77
+ a.g[59851]=v(a);a.g[62133]={};for(a.g[33125]=0;a.g[33125]<a.g[59851];a.g[33125]++)a.g[37378]=b.h[v(a)],a.g[3547]=b.h[v(a)],a.g[62133][a.g[37378]]=a.g[3547];b.h[a.g[34726]]=a.g[62133];break;case 20491:debugger;break;case 24674:a.g[51590]=1;b.h[a.g[51590]]=b.h[3];break;case 60658:a.g[16541]=v(a);a.g[62634]=b.h[v(a)];b.h[a.g[16541]]=a.g[62634]<<b.h[v(a)];break;case 8845:a.g[16541]=2;b.h[a.g[16541]]=b.h[3];break;default:throw Error("Unknown opcode: "+d+" at pc "+(b.l-1));case 59199:a.g[16541]=v(a);a.g[62634]=
78
+ b.h[v(a)];b.h[a.g[16541]]=a.g[62634]+b.h[v(a)];break;case 5385:a.g[39284]=4;b.h[a.g[39284]]=x(a,3,32194);break;case 20918:a.g[16541]=v(a);a.g[16160]=b.h[v(a)];b.h[a.g[16541]]=a.g[16160]|b.h[v(a)];break;case 25652:a.g[16541]=8;b.h[a.g[16541]]=x(a,0,19941);break;case 51993:a.g[14091]=v(a);a.g[20393]=b.h[v(a)];b.h[a.g[14091]]=a.g[20393]*b.h[v(a)];break;case 29458:a.g[27021]=4;b.h[a.g[27021]]=b.h[0];break;case 38570:throw b.h[v(a)];case 21903:a.g[16541]=v(a);a.g[46842]=b.h[v(a)];b.h[a.g[16541]]=a.g[46842]<
79
+ b.h[v(a)];break;case 17068:a.g[16541]=5;b.h[a.g[16541]]=b.h[0];break;case 26163:a.g[55552]=v(a);a.g[16422]=v(a);b.h[a.g[55552]]||(b.l=a.g[16422]);break;case 28425:a.g[16541]=v(a);b.h[a.g[16541]]=typeof b.h[v(a)];break;case 63202:a.g[60330]=v(a);b.h[a.g[60330]]=b.h[v(a)];break;case 31805:a.g[53668]=v(a);b.h[a.g[53668]]=!b.h[v(a)];break;case 57225:b.l=59}}catch(l){b=null;for(d=a.i;;){if(d.F.length>0){b=d;break}z(a,d);if(a.j.length===0)break;d=a.j.pop();a.i=d}if(!b)throw l;d=b.F.pop();a.j.length=d.T;
80
+ b.h[d.S]=l;b.l=d.U;a.i=b}}}var B={},C;for(C of Object.getOwnPropertyNames(globalThis))B[C]=globalThis[C];if(typeof window!=="undefined"){B.window=window;for(C of Object.getOwnPropertyNames(window))B[C]=window[C]}B.undefined=void 0;B.Infinity=Infinity;B.NaN=NaN;
81
+ A(new p(function(a){a=typeof Buffer!=="undefined"?Buffer.from(a,"base64"):Uint8Array.from(atob(a),function(d){return d.charCodeAt(0)});for(var e=new Uint16Array(a.length/2),b=0;b<e.length;b++)e[b]=a[b*2]|a[b*2+1]<<8;return e}("/bAEAFIAWwCNE5aj8uz9sA2/zi2qlqqWY9r9sBEAWwBtAKFQ52DnYD0OPQ5FrTNmCVGPVRnLbEC2UZV2+Lz4vMyRB7sJb/2wJwBtAHIAtlE/58Zt/bDMkf2wMAByAHQAzJF6Hv2wNgB0AHkA3GnOLT18B2Y/5/2wPwB5AIUAB7v4vKKxBNYNv6KxPXxFrQTWY9o9fO2z/bBPAIUAiABJrVLCPXxj2gMAMgABAAoAAABiYOxxjSLAOWC17PhkHgkVGxChUAYAAQABAAIAorEHAAMABQACAAIABgD4ys9Se2DYsWwHuL3Y64oA2LF+9ZOMEnOsQn71P+rZkjRkJO4lVDANWWONItRkid9pyv7mf70="),0,
82
+ [19940,30138,"IXwsfCp8NnwpfCt8LXw=","rn2sfaN9",void 0,58082],B));
67
83
  */
68
84
  ```
69
85
 
@@ -98,6 +114,7 @@ T(new u(function(a){a=typeof Buffer!=="undefined"?Buffer.from(a,"base64"):Uint8A
98
114
  - [x] try..catch
99
115
  - [x] getter/setters
100
116
  - [x] debugger;
117
+ - [x] template literals (**ES6**)
101
118
 
102
119
  ### Missing
103
120
 
@@ -114,7 +131,9 @@ T(new u(function(a){a=typeof Buffer!=="undefined"?Buffer.from(a,"base64"):Uint8A
114
131
  - [ ] dead handlers
115
132
  - [ ] dead bytecode insertion
116
133
  - [x] macro opcodes (Combine multiple opcodes into a "macro opcode")
134
+ - [x] micro opcodes (Break opcodes into sub-opcodes)
117
135
  - [x] specialized opcodes (Create specific opcodes for opcode+operand pairs)
136
+ - [x] aliased opcodes (Create duplicate opcodes, including variants with shuffled operand order)
118
137
  - [x] encoded bytecode array
119
138
  - [x] self-modifying bytecode
120
139
  - [x] timing checks
@@ -142,10 +161,22 @@ Encodes the bytecode array.
142
161
 
143
162
  ```js
144
163
  // Before
145
- var BYTECODE = [3, 0, 0, 1, 5, 0, 2, 12, 1, 14, 13];
164
+ var BYTECODE = [2, 1, 0, 0, 2, 1, 8, 3, 1, 2, 0, 4, 2, 43, 5, 1, 3, 1, 4, 0, 1, 3, 45, 1];
146
165
 
147
166
  // After
148
- var BYTECODE = "AwAAAAAAAQAFAAAAAgAMAAEADgANAA==";
167
+ var BYTECODE = "AgABAAAAAAACAAEACAADAAEAAgAAAAQAAgArAAUAAQADAAEABAAAAAEAAwAtAAEA";
168
+ ```
169
+
170
+ #### `concealConstants` (true/false)
171
+
172
+ Conceals strings and integers in the constant pool.
173
+
174
+ ```js
175
+ // Before
176
+ var CONSTANTS = [/* 0 */"console", /* 1 */"log", /* 2 */"Hello world!", /* 3 */undefined];
177
+
178
+ // After
179
+ var CONSTANTS = [/* 0 */"DaQApB6kAqQdpB+kEaQ=", /* 1 */"TCFOIUUh", /* 2 */"kKK8orait6Kzov2iqaKwopKijaKGosKi", /* 3 */undefined];
149
180
  ```
150
181
 
151
182
  #### `macroOpcodes` (true/false)
@@ -158,44 +189,108 @@ console.log("Hello world!");
158
189
  console.log("Hello world!");
159
190
 
160
191
  // Before
161
- // [3, 0], LOAD_GLOBAL "console" 1:0-1:7
162
- // [0, 1], LOAD_CONST "log" 1:0-1:27
163
- // [5], GET_PROP 1:0-1:27
164
- // [0, 2], LOAD_CONST "Hello world!" 1:12-1:26
165
- // [12, 1], CALL_METHOD (1 args) 1:0-1:27
166
- // [14], POP 1:0-1:28
167
- // [3, 0], LOAD_GLOBAL "console" 2:0-2:7
168
- // [0, 1], LOAD_CONST "log" 2:0-2:27
169
- // [5], GET_PROP 2:0-2:27
170
- // [0, 2], LOAD_CONST "Hello world!" 2:12-2:26
171
- // [12, 1], CALL_METHOD (1 args) 2:0-2:27
172
- // [14], POP 2:0-2:28
192
+ // [2, 1, 0], LOAD_GLOBAL reg[1] = console 1:0-1:7
193
+ // [0, 2, 1], LOAD_CONST reg[2] = "log" 1:0-1:27
194
+ // [8, 3, 1, 2], GET_PROP [3, 1, 2] 1:0-1:27
195
+ // [0, 4, 2], LOAD_CONST reg[4] = "Hello world!" 1:12-1:26
196
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)1:0-1:27
197
+ // [2, 1, 0], LOAD_GLOBAL reg[1] = console 2:0-2:7
198
+ // [0, 2, 1], LOAD_CONST reg[2] = "log" 2:0-2:27
199
+ // [8, 3, 1, 2], GET_PROP [3, 1, 2] 2:0-2:27
200
+ // [0, 4, 2], LOAD_CONST reg[4] = "Hello world!" 2:12-2:26
201
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)2:0-2:27
202
+
203
+ // After
204
+ // [5074, 1, 0, 2, 1, 3, 1, 2, 4, 2, 5, 1, 3, 1, 4], LOAD_GLOBAL,LOAD_CONST,GET_PROP,LOAD_CONST,CALL_METHOD [1, 0, 2, 1, 3, 1, 2, 4, 2, 5, 1, 3, 1, 4]2:0-2:7
205
+ // [5074, 1, 0, 2, 1, 3, 1, 2, 4, 2, 5, 1, 3, 1, 4], LOAD_GLOBAL,LOAD_CONST,GET_PROP,LOAD_CONST,CALL_METHOD [1, 0, 2, 1, 3, 1, 2, 4, 2, 5, 1, 3, 1, 4]3:0-3:7
206
+
207
+ // What the opcode "LOAD_GLOBAL,LOAD_CONST,GET_PROP,LOAD_CONST,CALL_METHOD" (5074) looks like:
208
+ case 5074:
209
+ // LOAD_GLOBAL
210
+ var dst = this._operand();
211
+ var globalName = this._constant();
212
+ if (!(globalName in this.globals)) {
213
+ throw new ReferenceError(`${globalName} is not defined`);
214
+ }
215
+ frame.regs[dst] = this.globals[globalName];
216
+ // LOAD_CONST
217
+ var dst_1 = this._operand();
218
+ frame.regs[dst_1] = this._constant();
219
+ // GET_PROP
220
+ // dst = regs[obj][regs[key]]
221
+ var dst_2 = this._operand();
222
+ var obj = frame.regs[this._operand()];
223
+ var key = frame.regs[this._operand()];
224
+ frame.regs[dst_2] = obj[key];
225
+ // LOAD_CONST
226
+ var dst_3 = this._operand();
227
+ frame.regs[dst_3] = this._constant();
228
+ // CALL_METHOD
229
+ // dst, receiverReg, calleeReg, argc, [argReg...]
230
+ var dst_4 = this._operand();
231
+ var receiver = frame.regs[this._operand()];
232
+ var callee = frame.regs[this._operand()];
233
+ var argc = this._operand();
234
+ var args = new Array(argc);
235
+ for (var i = 0; i < argc; i++) args[i] = frame.regs[this._operand()];
236
+ if (callee && callee[CLOSURE_SYM]) {
237
+ var c = callee[CLOSURE_SYM];
238
+ var f = new Frame(c, frame._pc, frame, receiver, dst_4);
239
+ for (var i = 0; i < args.length; i++) f.regs[i] = args[i];
240
+ f.regs[c.fn.paramCount] = args;
241
+ this._frameStack.push(this._currentFrame);
242
+ this._currentFrame = f;
243
+ } else {
244
+ frame.regs[dst_4] = callee.apply(receiver, args);
245
+ }
246
+ break;
247
+ ```
248
+
249
+ #### `microOpcodes` (true/false)
250
+
251
+ Breaks opcodes into mulitple sub-opcodes.
252
+
253
+ ```js
254
+ // Input Code
255
+ console.log("Hello world!");
256
+
257
+ // Before
258
+ // [2, 1, 0, 0], LOAD_GLOBAL reg[1] = console 1:0-1:7
259
+ // [0, 2, 1, 0], LOAD_CONST reg[2] = "log" 1:0-1:27
260
+ // [8, 3, 1, 2], GET_PROP reg[3] = reg[1][reg[2]] 1:0-1:27
261
+ // [0, 4, 2, 0], LOAD_CONST reg[4] = "Hello world!" 1:12-1:26
262
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = reg[3](recv=reg[1], 1 args) 1:0-1:27
263
+
264
+ // What the opcode "LOAD_CONST" looks like:
265
+ case OP.LOAD_CONST:
266
+ var dst = this._operand();
267
+ frame.regs[dst] = this._constant();
268
+ break;
173
269
 
174
270
  // After
175
- // [64, 0, 1, 2], LOAD_GLOBAL,LOAD_CONST,GET_PROP,LOAD_CONST [0, 1, 2]
176
- // [12, 1], CALL_METHOD (1 args) 1:0-1:27
177
- // [14], POP 1:0-1:28
178
- // [64, 0, 1, 2], LOAD_GLOBAL,LOAD_CONST,GET_PROP,LOAD_CONST [0, 1, 2]
179
- // [12, 1], CALL_METHOD (1 args) 2:0-2:27
180
- // [14], POP 2:0-2:28
181
-
182
- // What the opcode "LOAD_GLOBAL,LOAD_CONST,GET_PROP,LOAD_CONST" (64) looks like:
183
- case 64:
184
- {
185
- // LOAD_GLOBAL
186
- this._push(this.globals[this.constants[this._operand()]]);
187
- // LOAD_CONST
188
- this._push(this.constants[this._operand()]);
189
- // GET_PROP
190
- // Stack: [..., obj, key] -> [..., obj, obj[key]]
191
- // obj is PEEKED (not popped) - CALL_METHOD needs it as receiver
192
- var key = this._pop();
193
- var obj = this.peek();
194
- this._push(obj[key]);
195
- // LOAD_CONST
196
- this._push(this.constants[this._operand()]);
271
+ // [60, 1], MICRO_LOAD_GLOBAL_0 1 1:0-1:7
272
+ // [61, 0, 0], MICRO_LOAD_GLOBAL_1 [0, 0]
273
+ // [62], MICRO_LOAD_GLOBAL_2
274
+ // [63], MICRO_LOAD_GLOBAL_3
275
+ // [58, 2], MICRO_LOAD_CONST_0 2 1:0-1:27
276
+ // [59, 1, 0], MICRO_LOAD_CONST_1 [1, 0]
277
+ // [64, 3], MICRO_GET_PROP_0 3 1:0-1:27
278
+ // [65, 1], MICRO_GET_PROP_1 1
279
+ // [66, 2], MICRO_GET_PROP_2 2
280
+ // [67], MICRO_GET_PROP_3
281
+ // [58, 4], MICRO_LOAD_CONST_0 4 1:12-1:26
282
+ // [59, 2, 0], MICRO_LOAD_CONST_1 [2, 0]
283
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = reg[3](recv=reg[1], 1 args) 1:0-1:27
284
+
285
+ // What the opcodes "MICRO_LOAD_CONST_0" (58) and "MICRO_LOAD_CONST_1" (59) looks like:
286
+ case 58:
287
+ // MICRO_LOAD_CONST_0
288
+ this._internals[0] = this._operand();
289
+ break;
290
+ case 59:
291
+ // MICRO_LOAD_CONST_1
292
+ frame.regs[this._internals[0]] = this._constant();
197
293
  break;
198
- }
199
294
  ```
200
295
 
201
296
  #### `specializedOpcodes` (true/false)
@@ -207,30 +302,72 @@ Creates specialized opcodes for commonly used opcode+operand pairs.
207
302
  console.log("Hello world!");
208
303
 
209
304
  // Before
210
- // [3, 0], LOAD_GLOBAL "console" 1:0-1:7
211
- // [0, 1], LOAD_CONST "log" 1:0-1:27
212
- // [5], GET_PROP 1:0-1:27
213
- // [0, 2], LOAD_CONST "Hello world!" 1:12-1:26
214
- // [12, 1], CALL_METHOD (1 args) 1:0-1:27
215
- // [14], POP 1:0-1:28
305
+ // [2, 1, 0], LOAD_GLOBAL reg[1] = console 1:0-1:7
306
+ // [0, 2, 1], LOAD_CONST reg[2] = "log" 1:0-1:27
307
+ // [8, 3, 1, 2], GET_PROP [3, 1, 2] 1:0-1:27
308
+ // [0, 4, 2], LOAD_CONST reg[4] = "Hello world!" 1:12-1:26
309
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)1:0-1:27
216
310
 
217
311
  // What the opcode "LOAD_GLOBAL" looks like:
218
312
  case OP.LOAD_CONST:
219
- this._push(this.constants[this._operand()]);
313
+ var dst = this._operand();
314
+ frame.regs[dst] = this.constants[this._operand()];
315
+ break;
316
+
317
+ // After
318
+ // [16316], LOAD_GLOBAL_1_0 1:0-1:7
319
+ // [43765], LOAD_CONST_2_1 1:0-1:27
320
+ // [58568], GET_PROP_3_1_2 1:0-1:27
321
+ // [35110], LOAD_CONST_4_2 1:12-1:26
322
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)1:0-1:27
323
+
324
+ // What the opcode "LOAD_GLOBAL_1_0" (16316) looks like:
325
+ case 16316:
326
+ // LOAD_GLOBAL_1_0 (specialized)
327
+ var dst = 1;
328
+ frame.regs[dst] = this.globals[this.constants[0]];
329
+ break;
330
+ ```
331
+
332
+ #### `aliasedOpcodes` (true/false)
333
+
334
+ Creates duplicate opcodes, including variants with shuffled operand order.
335
+
336
+ ```js
337
+ // Input Code
338
+ console.log("Hello, world!");
339
+
340
+ // Before
341
+ // [2, 1, 0], LOAD_GLOBAL reg[1] = console 1:0-1:7
342
+ // [0, 2, 1], LOAD_CONST reg[2] = "log" 1:0-1:28
343
+ // [8, 3, 1, 2], GET_PROP [3, 1, 2] 1:0-1:28
344
+ // [0, 4, 2], LOAD_CONST reg[4] = "Hello, world!" 1:12-1:27
345
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)1:0-1:28
346
+ // [0, 1, 3], LOAD_CONST reg[1] = undefined
347
+ // [45, 1], RETURN reg[1]
348
+
349
+ // What the opcode "LOAD_GLOBAL" looks like:
350
+ case OP.LOAD_GLOBAL:
351
+ var dst = this._operand();
352
+ frame.regs[dst] = this.globals[this.constants[this._operand()]];
220
353
  break;
221
354
 
222
355
  // After
223
- // [64], LOAD_GLOBAL_0 1:0-1:7
224
- // [65], LOAD_CONST_1 1:0-1:27
225
- // [5], GET_PROP 1:0-1:27
226
- // [66], LOAD_CONST_2 1:12-1:26
227
- // [67], CALL_METHOD_1 1:0-1:27
228
- // [14], POP 1:0-1:28
229
-
230
- // What the opcode "LOAD_GLOBAL_0" (64) looks like:
231
- case 64:
232
- // LOAD_GLOBAL_0 (specialized)
233
- this._push(this.globals[this.constants[0]]);
356
+ // [52040, 0, 1], ALIAS_LOAD_GLOBAL_1_0 [0, 1] 1:0-1:7
357
+ // [24862, 1, 2], ALIAS_LOAD_CONST_1_0 [1, 2] 1:0-1:28
358
+ // [25202, 1, 2, 3], ALIAS_GET_PROP_1_2_0 [1, 2, 3] 1:0-1:28
359
+ // [24862, 2, 4], ALIAS_LOAD_CONST_1_0 [2, 4] 1:12-1:27
360
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)1:0-1:28
361
+ // [24862, 3, 1], ALIAS_LOAD_CONST_1_0 [3, 1]
362
+ // [51807, 1], ALIAS_RETURN_0 1
363
+
364
+ // What the opcode "ALIAS_LOAD_GLOBAL_1_0" (52040) looks like:
365
+ case 52040:
366
+ // ALIAS_LOAD_GLOBAL_1_0 (order: [1,0])
367
+ let _unsortedOperands = [this._operand(), this._operand()];
368
+ let _operands = [_unsortedOperands[1], _unsortedOperands[0]];
369
+ var dst = _operands[0];
370
+ frame.regs[dst] = this.globals[this.constants[_operands[1]]];
234
371
  break;
235
372
  ```
236
373
 
@@ -239,43 +376,49 @@ case 64:
239
376
  Function bodies are replaced upon runtime entry to the real bytecode.
240
377
 
241
378
  ```diff
242
- // Input
243
- function greet() {
244
- console.log("Hello, world!");
245
- }
379
+ // Input Code
380
+ console.log("Hello, world!");
246
381
 
247
382
  // Before
248
- // [3, 1], LOAD_GLOBAL "console" 2:2-2:9
249
- // [0, 2], LOAD_CONST "log" 2:2-2:30
250
- // [5], GET_PROP 2:2-2:30
251
- // [0, 3], LOAD_CONST "Hello, world!" 2:14-2:29
252
- // [12, 1], CALL_METHOD (1 args) 2:2-2:30
253
- // [14], POP 2:2-2:31
254
- // [0, 4], LOAD_CONST undefined 1:0-3:1
255
- // [13], RETURN 1:0-3:1
383
+ // [2, 1, 0], LOAD_GLOBAL reg[1] = console 1:0-1:7
384
+ // [0, 2, 1], LOAD_CONST reg[2] = "log" 1:0-1:28
385
+ // [8, 3, 1, 2], GET_PROP [3, 1, 2] 1:0-1:28
386
+ // [0, 4, 2], LOAD_CONST reg[4] = "Hello, world!" 1:12-1:27
387
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)1:0-1:28
388
+ // [0, 1, 3], LOAD_CONST reg[1] = undefined
389
+ // [45, 1], RETURN reg[1]
256
390
 
257
391
  // After
258
- // [56, 17, 30, 42], PATCH [17, 30, 42]
259
- -// [24], STORE_UPVALUE <-- 12 length of garbage code
260
- -// [15], LT
261
- -// [5], GET_PROP
262
- -// [46], IN
263
- -// [57], TRY_SETUP
264
- -// [50], DUP
265
- -// [55], FOR_IN_NEXT
266
- -// [41], SHR
267
- -// [53], LOOSE_NEQ
268
- -// [7], SUB
269
- -// [3], LOAD_GLOBAL
270
- -// [8], MUL
271
- // [13], RETURN 1:0-3:1
272
- +// [3, 1], LOAD_GLOBAL "console" <-- 12 length of real code
273
- +// [0, 2], LOAD_CONST "log" 2:2-2:30
274
- +// [5], GET_PROP 2:2-2:30
275
- +// [0, 3], LOAD_CONST "Hello, world!" 2:14-2:29
276
- +// [12, 1], CALL_METHOD (1 args) 2:2-2:30
277
- +// [14], POP 2:2-2:31
278
- +// [0, 4], LOAD_CONST undefined 1:0-3:1
392
+ // [56, 4, 28, 50], PATCH [4, 28, 50]
393
+ -// [52], FOR_IN_SETUP <-- 22 ints of garbage code
394
+ -// [39], JUMP
395
+ -// [12], SUB
396
+ -// [12], SUB
397
+ -// [2], LOAD_GLOBAL
398
+ -// [28], LOOSE_EQ
399
+ -// [12], SUB
400
+ -// [46], THROW
401
+ -// [18], BXOR
402
+ -// [8], GET_PROP
403
+ -// [5], MOVE
404
+ -// [55], TRY_END
405
+ -// [57], DEBUGGER
406
+ -// [46], THROW
407
+ -// [23], GT
408
+ -// [48], BUILD_ARRAY
409
+ -// [28], LOOSE_EQ
410
+ -// [18], BXOR
411
+ -// [2], LOAD_GLOBAL
412
+ -// [50], DEFINE_GETTER
413
+ -// [4], LOAD_THIS
414
+ -// [24], LTE
415
+ // [45, 1], RETURN reg[1]
416
+ +// [2, 1, 0], LOAD_GLOBAL reg[1] = console <-- 22 ints of real code
417
+ +// [0, 2, 1], LOAD_CONST reg[2] = "log" 1:0-1:28
418
+ +// [8, 3, 1, 2], GET_PROP [3, 1, 2] 1:0-1:28
419
+ +// [0, 4, 2], LOAD_CONST reg[4] = "Hello, world!" 1:12-1:27
420
+ +// [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)1:0-1:28
421
+ +// [0, 1, 3], LOAD_CONST reg[1] = undefined
279
422
  ```
280
423
 
281
424
  #### `timingChecks` (true/false)
@@ -311,7 +454,7 @@ Please transpile your code down first using [Babel](https://github.com/babel/bab
311
454
 
312
455
  ### Project
313
456
 
314
- - Stack based VM
457
+ - Register based VM
315
458
  - Lua-style closure and upvalue model
316
459
  - CPython-style opcodes and codegen
317
460
  - Compiler is in src/compiler.ts