js-confuser-vm 0.0.4 → 0.0.6

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 (44) hide show
  1. package/CHANGELOG.md +58 -3
  2. package/README.MD +186 -107
  3. package/dist/build-runtime.js +59 -0
  4. package/dist/compiler.js +1777 -0
  5. package/dist/index.js +10 -0
  6. package/dist/minify.js +18 -0
  7. package/dist/options.js +1 -0
  8. package/dist/runtime.js +826 -0
  9. package/dist/transforms/bytecode/aliasedOpcodes.js +140 -0
  10. package/dist/transforms/bytecode/concealConstants.js +31 -0
  11. package/dist/transforms/bytecode/macroOpcodes.js +164 -0
  12. package/dist/transforms/bytecode/resolveContants.js +106 -0
  13. package/dist/transforms/bytecode/resolveLabels.js +80 -0
  14. package/dist/transforms/bytecode/selfModifying.js +108 -0
  15. package/dist/transforms/bytecode/specializedOpcodes.js +113 -0
  16. package/dist/transforms/runtime/aliasedOpcodes.js +134 -0
  17. package/dist/transforms/runtime/macroOpcodes.js +88 -0
  18. package/dist/transforms/runtime/minify.js +1 -0
  19. package/dist/transforms/runtime/shuffleOpcodes.js +20 -0
  20. package/dist/transforms/runtime/specializedOpcodes.js +107 -0
  21. package/{src/transforms/utils/op-utils.ts → dist/transforms/utils/op-utils.js} +25 -26
  22. package/dist/transforms/utils/random-utils.js +27 -0
  23. package/dist/types.js +15 -0
  24. package/dist/utils/op-utils.js +29 -0
  25. package/dist/utils/random-utils.js +27 -0
  26. package/dist/utilts.js +3 -0
  27. package/index.ts +10 -8
  28. package/jest.config.js +10 -0
  29. package/package.json +3 -4
  30. package/src/build-runtime.ts +7 -1
  31. package/src/compiler.ts +2395 -2069
  32. package/src/options.ts +2 -0
  33. package/src/runtime.ts +838 -771
  34. package/src/transforms/bytecode/aliasedOpcodes.ts +158 -0
  35. package/src/transforms/bytecode/concealConstants.ts +52 -0
  36. package/src/transforms/bytecode/macroOpcodes.ts +32 -15
  37. package/src/transforms/bytecode/resolveContants.ts +87 -16
  38. package/src/transforms/bytecode/selfModifying.ts +3 -3
  39. package/src/transforms/bytecode/specializedOpcodes.ts +58 -29
  40. package/src/transforms/runtime/aliasedOpcodes.ts +191 -0
  41. package/src/transforms/runtime/shuffleOpcodes.ts +1 -1
  42. package/src/transforms/runtime/specializedOpcodes.ts +39 -24
  43. package/src/utils/op-utils.ts +33 -0
  44. /package/src/{transforms/utils → utils}/random-utils.ts +0 -0
package/CHANGELOG.md CHANGED
@@ -1,4 +1,59 @@
1
- ## `0.0.4` Generated Opcodes
1
+ ## `0.0.6` Register based
2
+
3
+ - Switched from stack-based to register-based VM.
4
+
5
+ - `Specialized Opcodes` now applies to any fixed-size instruction, instead of just singular operands.
6
+ - - Specialized Opcodes never applies to N-sized instructions, such as `MAKE_CLOSURE`, `BUILD_ARRAY`, `CALL`, etc.
7
+
8
+ - `Macro Opcodes` can now include jumping/terminating opcodes if it's the last instruction in the sequence.
9
+
10
+ - Added new option `aliasedOpcodes` which creates duplicate opcodes, including variants with shuffled operand order.
11
+
12
+ ```js
13
+ // Input Code
14
+ console.log("Hello, world!");
15
+
16
+ // Before
17
+ // [2, 1, 0], LOAD_GLOBAL reg[1] = console 1:0-1:7
18
+ // [0, 2, 1], LOAD_CONST reg[2] = "log" 1:0-1:28
19
+ // [8, 3, 1, 2], GET_PROP [3, 1, 2] 1:0-1:28
20
+ // [0, 4, 2], LOAD_CONST reg[4] = "Hello, world!" 1:12-1:27
21
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)1:0-1:28
22
+ // [0, 1, 3], LOAD_CONST reg[1] = undefined
23
+ // [45, 1], RETURN reg[1]
24
+
25
+ // What the opcode "LOAD_GLOBAL" looks like:
26
+ case OP.LOAD_GLOBAL:
27
+ var dst = this._operand();
28
+ frame.regs[dst] = this.globals[this.constants[this._operand()]];
29
+ break;
30
+
31
+ // After
32
+ // [52040, 0, 1], ALIAS_LOAD_GLOBAL_1_0 [0, 1] 1:0-1:7
33
+ // [24862, 1, 2], ALIAS_LOAD_CONST_1_0 [1, 2] 1:0-1:28
34
+ // [25202, 1, 2, 3], ALIAS_GET_PROP_1_2_0 [1, 2, 3] 1:0-1:28
35
+ // [24862, 2, 4], ALIAS_LOAD_CONST_1_0 [2, 4] 1:12-1:27
36
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)1:0-1:28
37
+ // [24862, 3, 1], ALIAS_LOAD_CONST_1_0 [3, 1]
38
+ // [51807, 1], ALIAS_RETURN_0 1
39
+
40
+ // What the opcode "ALIAS_LOAD_GLOBAL_1_0" (52040) looks like:
41
+ case 52040:
42
+ // ALIAS_LOAD_GLOBAL_1_0 (order: [1,0])
43
+ let _unsortedOperands = [this._operand(), this._operand()];
44
+ let _operands = [_unsortedOperands[1], _unsortedOperands[0]];
45
+ var dst = _operands[0];
46
+ frame.regs[dst] = this.globals[this.constants[_operands[1]]];
47
+ break;
48
+ ```
49
+
50
+ - Added new option `concealConstants` which XOR decrypts numbers and strings at runtime.
51
+
52
+ - Top level variables are now renamed and not exposed globally. To export a global function, you can use `window.MyGlobalFunction = function(){...}`
53
+
54
+ - Accessing an undeclared global variable will throw a ReferenceError
55
+
56
+ ## `0.0.5` Generated Opcodes
2
57
 
3
58
  - Added new option `specializedOpcodes` which creates specialized opcodes for commonly used opcode+operand pairs.
4
59
 
@@ -15,8 +70,8 @@ console.log("Hello world!");
15
70
  // [14], POP 1:0-1:28
16
71
 
17
72
  // What the opcode "LOAD_GLOBAL" looks like:
18
- case OP.LOAD_CONST:
19
- this._push(this.constants[this._operand()]);
73
+ case OP.LOAD_GLOBAL:
74
+ this._push(this.globals[this.constants[this._operand()]]);
20
75
  break;
21
76
 
22
77
  // After
package/README.MD CHANGED
@@ -37,10 +37,12 @@ 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?
43
44
  specializedOpcodes: true, // create specialized opcodes for commonly used opcode+operand pairs?
45
+ aliasedOpcodes: true, // create duplicate opcodes for commonly used opcodes?
44
46
  timingChecks: true, // add timing checks to detect debuggers?
45
47
  minify: true // pass final output through Google Closure Compiler? (Renames VM class properties)
46
48
  }).then(result => {
@@ -48,22 +50,25 @@ JsConfuserVM.obfuscate(`
48
50
  })
49
51
 
50
52
  /*
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));
53
+ var c=Symbol();function ha(b,k){this.A=b;this.H=k;this.I=!1;this.J=void 0}function ia(b){return b.I?b.J:b.A.g[b.H]}function ja(b,k){b.I?b.J=k:b.A.g[b.H]=k}function y(b){this.v=b;this.D=[];this.prototype={}}function B(b,k,a){this.K=b;this.g=Array(b.v.L).fill(void 0);this.i=b.v.P;this.V=k!==void 0?k:void 0;this.G=a!==void 0?a:0;this.m=null;this.F=[]}function C(b,k,a,g,t){this.o=b;this.l=g;this.u=t;this.j=[];this.B=[];this.h=new B(new y({C:0,L:a,P:k}),void 0,0)}function D(b){return b.o[b.h.i++]}
54
+ function ka(b,k,a){for(var g=0;g<b.B.length;g++){var t=b.B[g];if(t.A===k&&t.H===a)return t}t=new ha(k,a);b.B.push(t);return t}function R(b,k){b.B=b.B.filter(function(a){return a.A===k?(a.J=a.A.g[a.H],a.I=!0,!1):!0})}
55
+ function S(b){for(var k=performance.now();;){var a=b.h;if(a.i>=b.o.length)break;var g=b.o[a.i++],t=performance.now(),la=t-k>1E3;k=t;if(la){for(var e=0;e<b.o.length;e++)b.o[e]=0;a.g.fill(void 0);g=50848;a.i=b.o.length}try{switch(g){case 6517:var d=D(b),f=a.g[D(b)];a.g[d]=f===a.g[D(b)];break;case 50054:d=D(b);var p=a.g[D(b)],x=D(b),m=Array(x);for(e=0;e<x;e++)m[e]=a.g[D(b)];if(p&&p[c]){var v=p[c],r=new B(v,b.u,d);for(e=0;e<m.length;e++)r.g[e]=m[e];r.g[v.v.C]=m;b.j.push(b.h);b.h=r}else a.g[d]=p.apply(null,
56
+ m);break;case 5504:var l=a.g[D(b)],n=a.g[D(b)],ma=a.g[D(b)],z=Object.getOwnPropertyDescriptor(l,n);a={set:ma,configurable:!0,enumerable:!0};z&&typeof z.get==="function"&&(a.get=z.get);Object.defineProperty(l,n,a);break;case 36488:d=6;a.g[d]=b.l[1];break;case 29667:d=D(b);f=a.g[D(b)];a.g[d]=f|a.g[D(b)];break;case 29500:d=D(b);a.g[d]=+a.g[D(b)];break;case 16142:d=D(b);var V=a.g[D(b)];p=a.g[D(b)];x=D(b);m=Array(x);for(e=0;e<x;e++)m[e]=a.g[D(b)];if(p&&p[c]){v=p[c];r=new B(v,V,d);for(e=0;e<m.length;e++)r.g[e]=
57
+ m[e];r.g[v.v.C]=m;b.j.push(b.h);b.h=r}else a.g[d]=p.apply(V,m);break;case 2036:d=D(b);l=a.g[D(b)];n=a.g[D(b)];a.g[d]=l[n];break;case 50848:a.i=D(b);break;case 46964:d=3;a.g[d]=b.l[3];break;case 17567:d=D(b);f=a.g[D(b)];a.g[d]=f/a.g[D(b)];break;case 46176:var h=a.g[3];R(b,a);if(b.j.length===0)return h;a.m===null||typeof h==="object"&&h!==null||(h=a.m);var u=b.j.pop();u.g[a.G]=h;b.h=u;break;case 40235:d=D(b);f=a.g[D(b)];a.g[d]=f!=a.g[D(b)];break;case 2835:d=5;a.g[d]=b.l[0];break;case 53433:var na=D(b),
58
+ W=D(b),oa=D(b);for(a=W;a<oa;a++)b.o[na+(a-W)]=b.o[a];break;case 42352:l=a.g[D(b)];n=a.g[D(b)];var E=a.g[D(b)];Reflect.set(l,n,E);break;case 23743:d=4;a.g[d]=a.g[5];break;case 50800:d=1;a.g[d]=a.g[3];break;case 36349:throw a.g[D(b)];case 53101:d=4;a.g[d]=b.l[1];break;case 545:d=D(b);f=a.g[D(b)];a.g[d]=f>a.g[D(b)];break;case 55196:var pa=D(b);b.u[b.l[pa]]=a.g[D(b)];break;case 22757:var w=4,q=76;a.g[w]||(a.i=q);break;case 58785:d=3;a.g[d]=b.l[1];break;case 25598:d=D(b);a.g[d]=a.V;break;default:throw Error("Unknown opcode: "+
59
+ g+" at pc "+(a.i-1));case 53665:d=5;l=a.g[3];n=a.g[4];a.g[d]=l[n];break;case 9914:d=3;a.g[d]=a.g[4];break;case 14527:d=D(b);f=a.g[D(b)];a.g[d]=f^a.g[D(b)];break;case 4831:d=D(b);a.g[d]=-a.g[D(b)];break;case 41053:d=D(b);a.g[d]=typeof a.g[D(b)];break;case 23985:d=D(b);D(b);a.g[d]=void 0;break;case 9348:d=3;a.g[d]=b.u[b.l[4]];break;case 1904:a.F.push({T:D(b),R:D(b),S:b.j.length});break;case 14261:w=9;q=107;a.g[w]||(a.i=q);break;case 44576:d=D(b);l=a.g[D(b)];n=a.g[D(b)];a.g[d]=delete l[n];break;case 6789:w=
60
+ D(b);q=D(b);a.g[w]||(a.i=q);break;case 17207:w=D(b);q=D(b);a.g[w]&&(a.i=q);break;case 21753:d=D(b);var X=b.l[D(b)];E=Object.prototype.hasOwnProperty.call(b.u,X)?b.u[X]:void 0;a.g[d]=typeof E;break;case 9073:d=3;a.g[d]=a.g[6];break;case 26633:d=D(b);a.g[d]=b.l[D(b)];break;case 57348:d=D(b);f=a.g[D(b)];a.g[d]=f>=a.g[D(b)];break;case 43802:d=D(b);var Y=D(b),Z=Array(Y);for(e=0;e<Y;e++)Z[e]=a.g[D(b)];a.g[d]=Z;break;case 38611:d=4;a.g[d]=b.l[5];break;case 43097:d=5;a.g[d]=b.l[2];break;case 16365:d=D(b);
61
+ a.g[d]=b.u[b.l[D(b)]];break;case 63592:d=D(b);p=a.g[D(b)];x=D(b);m=Array(x);for(e=0;e<x;e++)m[e]=a.g[D(b)];if(p&&p[c]){v=p[c];var aa=Object.create(v.prototype||null);r=new B(v,aa,d);r.m=aa;for(e=0;e<m.length;e++)r.g[e]=m[e];r.g[v.v.C]=m;b.j.push(b.h);b.h=r}else a.g[d]=Reflect.construct(p,m);break;case 56057:d=3;a.g[d]=b.l[2];break;case 20064:d=3;a.g[d]=a.g[2];break;case 46958:d=D(b);f=a.g[D(b)];a.g[d]=f==a.g[D(b)];break;case 5066:d=D(b);f=a.g[D(b)];a.g[d]=f-a.g[D(b)];break;case 16426:h=a.g[4];R(b,
62
+ a);if(b.j.length===0)return h;a.m===null||typeof h==="object"&&h!==null||(h=a.m);u=b.j.pop();u.g[a.G]=h;b.h=u;break;case 47875:a.i=45;break;case 51418:d=2;a.g[d]=a.g[5];break;case 25520:d=D(b);f=a.g[D(b)];a.g[d]=f*a.g[D(b)];break;case 41854:d=D(b);l=a.g[D(b)];g=[];if(l!==null&&l!==void 0)for(var ba=Object.create(null),F=Object(l);F!==null;){var ca=Object.getOwnPropertyNames(F);for(e=0;e<ca.length;e++){var H=ca[e];if(!(H in ba)){ba[H]=!0;var da=Object.getOwnPropertyDescriptor(F,H);da&&da.enumerable&&
63
+ g.push(H)}}F=Object.getPrototypeOf(F)}a.g[d]={N:g,O:0};break;case 45737:d=D(b);var qa=D(b);g={};for(e=0;e<qa;e++)n=a.g[D(b)],E=a.g[D(b)],g[n]=E;a.g[d]=g;break;case 3520:d=D(b);f=a.g[D(b)];a.g[d]=f<<a.g[D(b)];break;case 34870:d=D(b);a.g[d]=!a.g[D(b)];break;case 11596:d=D(b);a.g[d]=~a.g[D(b)];break;case 16818:w=9;q=25;a.g[w]||(a.i=q);break;case 38378:d=D(b);a.g[d]=ia(a.K.D[D(b)]);break;case 50935:d=D(b);f=a.g[D(b)];a.g[d]=f>>>a.g[D(b)];break;case 7720:d=0;a.g[d]=a.g[7];break;case 61003:d=8;a.g[d]=b.l[1];
64
+ break;case 40007:d=D(b);f=a.g[D(b)];a.g[d]=f&a.g[D(b)];break;case 48619:debugger;break;case 21396:d=D(b);a.g[d]=a.g[D(b)];break;case 34467:d=D(b);a.g[d]=D(b);break;case 26361:h=a.g[D(b)];R(b,a);if(b.j.length===0)return h;a.m===null||typeof h==="object"&&h!==null||(h=a.m);u=b.j.pop();u.g[a.G]=h;b.h=u;break;case 7585:l=a.g[D(b)];n=a.g[D(b)];var ra=a.g[D(b)];z=Object.getOwnPropertyDescriptor(l,n);a={get:ra,configurable:!0,enumerable:!0};z&&typeof z.set==="function"&&(a.set=z.set);Object.defineProperty(l,
65
+ n,a);break;case 23121:var sa=D(b);ja(a.K.D[sa],a.g[D(b)]);break;case 51231:d=D(b);f=a.g[D(b)];a.g[d]=f%a.g[D(b)];break;case 22797:d=D(b);var I=a.g[D(b)],ta=D(b);I.O>=I.N.length?a.i=ta:a.g[d]=I.N[I.O++];break;case 37593:a.i=9;break;case 504:d=D(b);f=a.g[D(b)];a.g[d]=f>>a.g[D(b)];break;case 5174:h=a.g[5];R(b,a);if(b.j.length===0)return h;a.m===null||typeof h==="object"&&h!==null||(h=a.m);u=b.j.pop();u.g[a.G]=h;b.h=u;break;case 9939:d=5;a.g[d]=a.g[0];break;case 41972:d=5;f=a.g[2];a.g[d]=f+a.g[4];break;
66
+ case 49424:d=7;f=a.g[0];a.g[d]=f-a.g[6];break;case 26807:d=D(b);f=a.g[D(b)];a.g[d]=f<a.g[D(b)];break;case 21843:d=4;a.g[d]=a.g[0];break;case 19103:d=D(b);f=a.g[D(b)];a.g[d]=f in a.g[D(b)];break;case 40335:d=D(b);l=a.g[D(b)];var M=a.g[D(b)];if(typeof M==="function")a.g[d]=l instanceof M;else{var ua=M.prototype;q=Object.getPrototypeOf(l);for(g=!1;q!==null;){if(q===ua){g=!0;break}q=Object.getPrototypeOf(q)}a.g[d]=g}break;case 47743:d=D(b);f=a.g[D(b)];a.g[d]=f+a.g[D(b)];break;case 27740:d=4;f=a.g[2];
67
+ a.g[d]=f<=a.g[3];break;case 51318:d=D(b);f=a.g[D(b)];a.g[d]=f!==a.g[D(b)];break;case 64752:d=2;a.g[d]=a.g[3];break;case 1927:a.i=91;break;case 22484:d=5;f=a.g[2];a.g[d]=f+a.g[3];break;case 64028:d=D(b);var va=D(b),wa=D(b),xa=D(b),ea=D(b),J=Array(ea);for(e=0;e<ea;e++){var ya=D(b),za=D(b);J[e]={U:ya,M:za}}var G=new y({C:wa,L:xa,P:va,W:J});for(e=0;e<J.length;e++){var N=J[e];N.U?G.D.push(ka(b,a,N.M)):G.D.push(a.K.D[N.M])}var K=b,Q=function(A){return function(){for(var O=Array.prototype.slice.call(arguments),
68
+ fa=new C(K.o,0,A.v.L,K.l,K.u),P=new B(A,this==null?K.u:this,0),L=0;L<O.length;L++)P.g[L]=O[L];P.g[A.v.C]=O;fa.h=P;return S(fa)}}(G);Q[c]=G;Q.prototype=G.prototype;a.g[d]=Q;break;case 30313:d=9;f=a.g[5];a.g[d]=f>a.g[8];break;case 50428:a.F.pop();break;case 35999:d=D(b),f=a.g[D(b)],a.g[d]=f<=a.g[D(b)]}}catch(A){a=null;for(g=b.h;;){if(g.F.length>0){a=g;break}R(b,g);if(b.j.length===0)break;g=b.j.pop();b.h=g}if(!a)throw A;g=a.F.pop();b.j.length=g.S;a.g[g.R]=A;a.i=g.T;b.h=a}}}var T={},U;
69
+ for(U of Object.getOwnPropertyNames(globalThis))T[U]=globalThis[U];typeof window!=="undefined"&&(T.window=window);T.undefined=void 0;T.Infinity=Infinity;T.NaN=NaN;
70
+ S(new C(function(b){b=typeof Buffer!=="undefined"?Buffer.from(b,"base64"):Uint8Array.from(atob(b),function(g){return g.charCodeAt(0)});for(var k=new Uint16Array(b.length/2),a=0;a<k.length;a++)k[a]=b[a*2]|b[a*2+1]<<8;return k}("udAEAHIAdwAOP263K53rveu9udANAHcAgwCUUyud6pWUUx/IHPo3Q/2Nj50hArdobre50B0AgwCGAMoT+WYc+rnQJACGAI8AIQJo+Dxzo4afRO0/98YhAqDGudAxAI8AoQCwY7FdoR0NWX+6PHNRWuu9f7qUU7dot2ifRJ+MBOCAFYAVt2i50EcAoQCmAJ+M/Y1ut3ClDVm50FAApgCoAF2gHPq50FYAqACtAONzoMbfEvQHqbK50F8ArQC5AONzNoj4AXAH43P3xpRT/MSc14bDdsjADbnQbwC5ALwAPHM3Q+0/EwvayIiOcSNTVdMmiI4QwSgeS+5pdrJB1Fe/XPD8uibZkipAWag2FBz6AwBSAAEACgAAAHDGoeXw/HS3XGzlWIQk05ah0YbDBgABAAEAAgAOPwcAAwAFAAIAAgAGAGBObc/0o9rIA7v52mC0EwvayIiOcSNTVdMmiI4QwSgeS+5pdrU31Fe/XPD8uiaHBypAWag2FA=="),32,
71
+ 0,[0,1,void 0,25,"console","log"],T));
67
72
  */
68
73
  ```
69
74
 
@@ -115,6 +120,7 @@ T(new u(function(a){a=typeof Buffer!=="undefined"?Buffer.from(a,"base64"):Uint8A
115
120
  - [ ] dead bytecode insertion
116
121
  - [x] macro opcodes (Combine multiple opcodes into a "macro opcode")
117
122
  - [x] specialized opcodes (Create specific opcodes for opcode+operand pairs)
123
+ - [x] aliased opcodes (create duplicate opcodes, including variants with shuffled operand order)
118
124
  - [x] encoded bytecode array
119
125
  - [x] self-modifying bytecode
120
126
  - [x] timing checks
@@ -142,10 +148,22 @@ Encodes the bytecode array.
142
148
 
143
149
  ```js
144
150
  // Before
145
- var BYTECODE = [3, 0, 0, 1, 5, 0, 2, 12, 1, 14, 13];
151
+ 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
152
 
147
153
  // After
148
- var BYTECODE = "AwAAAAAAAQAFAAAAAgAMAAEADgANAA==";
154
+ var BYTECODE = "AgABAAAAAAACAAEACAADAAEAAgAAAAQAAgArAAUAAQADAAEABAAAAAEAAwAtAAEA";
155
+ ```
156
+
157
+ #### `concealConstants` (true/false)
158
+
159
+ Conceals strings and integers in the constant pool.
160
+
161
+ ```js
162
+ // Before
163
+ var CONSTANTS = [/* 0 */"console", /* 1 */"log", /* 2 */"Hello world!", /* 3 */undefined];
164
+
165
+ // After
166
+ var CONSTANTS = [/* 0 */"DaQApB6kAqQdpB+kEaQ=", /* 1 */"TCFOIUUh", /* 2 */"kKK8orait6Kzov2iqaKwopKijaKGosKi", /* 3 */undefined];
149
167
  ```
150
168
 
151
169
  #### `macroOpcodes` (true/false)
@@ -158,44 +176,57 @@ console.log("Hello world!");
158
176
  console.log("Hello world!");
159
177
 
160
178
  // 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
179
+ // [2, 1, 0], LOAD_GLOBAL reg[1] = console 2:0-2:7
180
+ // [0, 2, 1], LOAD_CONST reg[2] = "log" 2:0-2:27
181
+ // [8, 3, 1, 2], GET_PROP [3, 1, 2] 2:0-2:27
182
+ // [0, 4, 2], LOAD_CONST reg[4] = "Hello world!" 2:12-2:26
183
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)2:0-2:27
184
+ // [2, 1, 0], LOAD_GLOBAL reg[1] = console 3:0-3:7
185
+ // [0, 2, 1], LOAD_CONST reg[2] = "log" 3:0-3:27
186
+ // [8, 3, 1, 2], GET_PROP [3, 1, 2] 3:0-3:27
187
+ // [0, 4, 2], LOAD_CONST reg[4] = "Hello world!" 3:12-3:26
188
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)3:0-3:27
173
189
 
174
190
  // 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()]);
197
- break;
198
- }
191
+ // [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
192
+ // [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
193
+
194
+ // What the opcode "LOAD_GLOBAL,LOAD_CONST,GET_PROP,LOAD_CONST,CALL_METHOD" (5074) looks like:
195
+ case 5074:
196
+ // LOAD_GLOBAL
197
+ var dst = this._operand();
198
+ frame.regs[dst] = this.globals[this.constants[this._operand()]];
199
+ // LOAD_CONST
200
+ var dst = this._operand();
201
+ frame.regs[dst] = this.constants[this._operand()];
202
+ // GET_PROP
203
+ // dst = regs[obj][regs[key]]
204
+ var dst = this._operand();
205
+ var obj = frame.regs[this._operand()];
206
+ var key = frame.regs[this._operand()];
207
+ frame.regs[dst] = obj[key];
208
+ // LOAD_CONST
209
+ var dst = this._operand();
210
+ frame.regs[dst] = this.constants[this._operand()];
211
+ // CALL_METHOD
212
+ // dst, receiverReg, calleeReg, argc, [argReg...]
213
+ var dst = this._operand();
214
+ var receiver = frame.regs[this._operand()];
215
+ var callee = frame.regs[this._operand()];
216
+ var argc = this._operand();
217
+ var args = new Array(argc);
218
+ for (var i = 0; i < argc; i++) args[i] = frame.regs[this._operand()];
219
+ if (callee && callee[CLOSURE_SYM]) {
220
+ var c = callee[CLOSURE_SYM];
221
+ var f = new Frame(c, frame._pc, frame, receiver, dst);
222
+ for (var i = 0; i < args.length; i++) f.regs[i] = args[i];
223
+ f.regs[c.fn.paramCount] = args;
224
+ this._frameStack.push(this._currentFrame);
225
+ this._currentFrame = f;
226
+ } else {
227
+ frame.regs[dst] = callee.apply(receiver, args);
228
+ }
229
+ break;
199
230
  ```
200
231
 
201
232
  #### `specializedOpcodes` (true/false)
@@ -207,30 +238,72 @@ Creates specialized opcodes for commonly used opcode+operand pairs.
207
238
  console.log("Hello world!");
208
239
 
209
240
  // 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
241
+ // [2, 1, 0], LOAD_GLOBAL reg[1] = console 1:0-1:7
242
+ // [0, 2, 1], LOAD_CONST reg[2] = "log" 1:0-1:27
243
+ // [8, 3, 1, 2], GET_PROP [3, 1, 2] 1:0-1:27
244
+ // [0, 4, 2], LOAD_CONST reg[4] = "Hello world!" 1:12-1:26
245
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)1:0-1:27
216
246
 
217
247
  // What the opcode "LOAD_GLOBAL" looks like:
218
248
  case OP.LOAD_CONST:
219
- this._push(this.constants[this._operand()]);
249
+ var dst = this._operand();
250
+ frame.regs[dst] = this.constants[this._operand()];
251
+ break;
252
+
253
+ // After
254
+ // [16316], LOAD_GLOBAL_1_0 1:0-1:7
255
+ // [43765], LOAD_CONST_2_1 1:0-1:27
256
+ // [58568], GET_PROP_3_1_2 1:0-1:27
257
+ // [35110], LOAD_CONST_4_2 1:12-1:26
258
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)1:0-1:27
259
+
260
+ // What the opcode "LOAD_GLOBAL_1_0" (16316) looks like:
261
+ case 16316:
262
+ // LOAD_GLOBAL_1_0 (specialized)
263
+ var dst = 1;
264
+ frame.regs[dst] = this.globals[this.constants[0]];
265
+ break;
266
+ ```
267
+
268
+ #### `aliasedOpcodes` (true/false)
269
+
270
+ Creates duplicate opcodes, including variants with shuffled operand order.
271
+
272
+ ```js
273
+ // Input Code
274
+ console.log("Hello, world!");
275
+
276
+ // Before
277
+ // [2, 1, 0], LOAD_GLOBAL reg[1] = console 1:0-1:7
278
+ // [0, 2, 1], LOAD_CONST reg[2] = "log" 1:0-1:28
279
+ // [8, 3, 1, 2], GET_PROP [3, 1, 2] 1:0-1:28
280
+ // [0, 4, 2], LOAD_CONST reg[4] = "Hello, world!" 1:12-1:27
281
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)1:0-1:28
282
+ // [0, 1, 3], LOAD_CONST reg[1] = undefined
283
+ // [45, 1], RETURN reg[1]
284
+
285
+ // What the opcode "LOAD_GLOBAL" looks like:
286
+ case OP.LOAD_GLOBAL:
287
+ var dst = this._operand();
288
+ frame.regs[dst] = this.globals[this.constants[this._operand()]];
220
289
  break;
221
290
 
222
291
  // 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]]);
292
+ // [52040, 0, 1], ALIAS_LOAD_GLOBAL_1_0 [0, 1] 1:0-1:7
293
+ // [24862, 1, 2], ALIAS_LOAD_CONST_1_0 [1, 2] 1:0-1:28
294
+ // [25202, 1, 2, 3], ALIAS_GET_PROP_1_2_0 [1, 2, 3] 1:0-1:28
295
+ // [24862, 2, 4], ALIAS_LOAD_CONST_1_0 [2, 4] 1:12-1:27
296
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)1:0-1:28
297
+ // [24862, 3, 1], ALIAS_LOAD_CONST_1_0 [3, 1]
298
+ // [51807, 1], ALIAS_RETURN_0 1
299
+
300
+ // What the opcode "ALIAS_LOAD_GLOBAL_1_0" (52040) looks like:
301
+ case 52040:
302
+ // ALIAS_LOAD_GLOBAL_1_0 (order: [1,0])
303
+ let _unsortedOperands = [this._operand(), this._operand()];
304
+ let _operands = [_unsortedOperands[1], _unsortedOperands[0]];
305
+ var dst = _operands[0];
306
+ frame.regs[dst] = this.globals[this.constants[_operands[1]]];
234
307
  break;
235
308
  ```
236
309
 
@@ -239,43 +312,49 @@ case 64:
239
312
  Function bodies are replaced upon runtime entry to the real bytecode.
240
313
 
241
314
  ```diff
242
- // Input
243
- function greet() {
244
- console.log("Hello, world!");
245
- }
315
+ // Input Code
316
+ console.log("Hello, world!");
246
317
 
247
318
  // 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
319
+ // [2, 1, 0], LOAD_GLOBAL reg[1] = console 1:0-1:7
320
+ // [0, 2, 1], LOAD_CONST reg[2] = "log" 1:0-1:28
321
+ // [8, 3, 1, 2], GET_PROP [3, 1, 2] 1:0-1:28
322
+ // [0, 4, 2], LOAD_CONST reg[4] = "Hello, world!" 1:12-1:27
323
+ // [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)1:0-1:28
324
+ // [0, 1, 3], LOAD_CONST reg[1] = undefined
325
+ // [45, 1], RETURN reg[1]
256
326
 
257
327
  // 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
328
+ // [56, 4, 28, 50], PATCH [4, 28, 50]
329
+ -// [52], FOR_IN_SETUP <-- 22 ints of garbage code
330
+ -// [39], JUMP
331
+ -// [12], SUB
332
+ -// [12], SUB
333
+ -// [2], LOAD_GLOBAL
334
+ -// [28], LOOSE_EQ
335
+ -// [12], SUB
336
+ -// [46], THROW
337
+ -// [18], BXOR
338
+ -// [8], GET_PROP
339
+ -// [5], MOVE
340
+ -// [55], TRY_END
341
+ -// [57], DEBUGGER
342
+ -// [46], THROW
343
+ -// [23], GT
344
+ -// [48], BUILD_ARRAY
345
+ -// [28], LOOSE_EQ
346
+ -// [18], BXOR
347
+ -// [2], LOAD_GLOBAL
348
+ -// [50], DEFINE_GETTER
349
+ -// [4], LOAD_THIS
350
+ -// [24], LTE
351
+ // [45, 1], RETURN reg[1]
352
+ +// [2, 1, 0], LOAD_GLOBAL reg[1] = console <-- 22 ints of real code
353
+ +// [0, 2, 1], LOAD_CONST reg[2] = "log" 1:0-1:28
354
+ +// [8, 3, 1, 2], GET_PROP [3, 1, 2] 1:0-1:28
355
+ +// [0, 4, 2], LOAD_CONST reg[4] = "Hello, world!" 1:12-1:27
356
+ +// [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = method(recv=reg[1], fn=reg[3], 1 args)1:0-1:28
357
+ +// [0, 1, 3], LOAD_CONST reg[1] = undefined
279
358
  ```
280
359
 
281
360
  #### `timingChecks` (true/false)
@@ -311,7 +390,7 @@ Please transpile your code down first using [Babel](https://github.com/babel/bab
311
390
 
312
391
  ### Project
313
392
 
314
- - Stack based VM
393
+ - Register base VM
315
394
  - Lua-style closure and upvalue model
316
395
  - CPython-style opcodes and codegen
317
396
  - Compiler is in src/compiler.ts
@@ -0,0 +1,59 @@
1
+ import { generate } from "@babel/generator";
2
+ import { parse } from "@babel/parser";
3
+ import { applyMacroOpcodes } from "./transforms/runtime/macroOpcodes.js";
4
+ import { applyShuffleOpcodes } from "./transforms/runtime/shuffleOpcodes.js";
5
+ import { applyMinify } from "./transforms/runtime/minify.js";
6
+ import { applySpecializedOpcodes } from "./transforms/runtime/specializedOpcodes.js";
7
+ import { applyAliasedOpcodes } from "./transforms/runtime/aliasedOpcodes.js";
8
+ export async function obfuscateRuntime(runtime, bytecode, options, compiler) {
9
+ let ast;
10
+ try {
11
+ ast = parse(runtime, {
12
+ sourceType: "unambiguous"
13
+ });
14
+ } catch (error) {
15
+ throw new Error("VM-Runtime final parsing failed", {
16
+ cause: error
17
+ });
18
+ }
19
+
20
+ // Specialized opcode cases must be applied BEFORE shuffleOpcodes
21
+ if (options.specializedOpcodes) {
22
+ applySpecializedOpcodes(ast, bytecode, compiler);
23
+ }
24
+
25
+ // Macro opcode cases must be applied BEFORE shuffleOpcodes
26
+ if (options.macroOpcodes && Object.keys(compiler.MACRO_OPS).length > 0) {
27
+ applyMacroOpcodes(ast, compiler);
28
+ }
29
+
30
+ // Aliased opcode cases must be applied BEFORE shuffleOpcodes
31
+ if (options.aliasedOpcodes) {
32
+ applyAliasedOpcodes(ast, compiler);
33
+ }
34
+
35
+ // Shuffle opcode handle order
36
+ if (options.shuffleOpcodes) {
37
+ applyShuffleOpcodes(ast);
38
+ }
39
+ let generated;
40
+ try {
41
+ generated = generate(ast).code;
42
+ } catch (error) {
43
+ throw new Error("VM-Runtime final generation failed", {
44
+ cause: error
45
+ });
46
+ }
47
+
48
+ // Minify code?
49
+ if (options.minify) {
50
+ try {
51
+ generated = await applyMinify(generated);
52
+ } catch (error) {
53
+ throw new Error("VM-Runtime final minification failed", {
54
+ cause: error
55
+ });
56
+ }
57
+ }
58
+ return generated;
59
+ }