JavaScriptのバイトコード（逆アセンブル疑似コード）の見方

Node.jsをインストールしてコマンドプロンプト（もしくはWindows Power Shell）から以下のコマンドを打ってください。
```
# node --print-bytecode <ファイル名>.js
```
基本的なことですが、JavaScriptはスクリプト型言語だが、内部ではバイトコードが生成されて、そのバイトコードがさらにネイティブなマシンコードに変換され高速に動作するようになっています。

バイトコードは仮想的なマシンコードでレジスタをもつスタックマシンとして動作します。

まあ堅苦しいことは抜きにして、実際に簡単なサンプルコードで早速バイトコードを読んでみましょう。

なおここで言っているバイトコードとは、V8のバイトコードになります。

V8はGoogleのオープンソースJavaScriptエンジンです。Chrome、Node.js、およびその他の多くのアプリケーションでV8が使用されています。

■簡単なJavaScriptのサンプルコードとそのバイトコードの対応
【JavaScriptコード】
```
  1 var a=1999;
  2 var b=3121;
  3 var c=659;
  4 function muladd1(x,y,z) {
  5         let r=x+y*z;
  6         return r;
  7 }
  8 function muladd2(x,y,z) {
  9         let r=x*y+z;
 10         return r;
 11 }
 12 function func_example(x,y,z) {
 13         var d=muladd1(x,y,z)+muladd2(x,y,z);
 14         if (d==341) {
 15                 return 333;
 16         }
 17         return 777;
 18
 19 }
 20
 21 var e=func_example(a,b,c);
 22 console.log(e);
```
【バイトコード】
1行目～3行目、21行目～22行目
```
1行目～3行目、21行目～22行目
    StackCheck                                     # スタックチェック
    LdaSmi.Wide [1999]                             # 即値1999をアキュムレータレジスタにロードする
    StaCurrentContextSlot [4]                      # アキュムレータレジスタからCurrentContextSlot[4]にストア
    LdaSmi.Wide [3121]                             # 即値3121をアキュムレータレジスタにロードする
    StaCurrentContextSlot [5]                      # アキュムレータレジスタからCurrentContextSlot[5]にストア
    LdaSmi.Wide [659]                              # 即値659をアキュムレータレジスタにロードする
    StaCurrentContextSlot [6]                      # アキュムレータレジスタからCurrentContextSlot[6]にストア
    LdaImmutableCurrentContextSlot [4]             # CurrentContextSlot[4]からアキュムレータレジスタにロードする
    Star r4                                        # アキュムレータレジスタからレジスタr4にストア
    LdaImmutableCurrentContextSlot [5]             # CurrentContextSlot[5]からアキュムレータレジスタにロードする
    Star r5                                        # アキュムレータレジスタからレジスタr5にストア
    LdaImmutableCurrentContextSlot [6]             # CurrentContextSlot[6]からアキュムレータレジスタにロードする
    Star r6                                        # アキュムレータレジスタからレジスタr6にストア
    CallUndefinedReceiver r0, r4-r6, [0]           # func_example関数(レジスタr0にアドレスが入っている)を呼び出す
                                                   # 実引数リストは、r4-r6番に入っている
    Star r1                                        # 返却値が入っているアキュムレータレジスタをレジスタr1にストア
    LdaGlobal [4], [2]                             # グローバル変数eのアドレスをアキュムレータレジスタにロード
    Star r4                                        # アキュムレータレジスタをレジスタr4にストア
    LdaNamedProperty r4, [5], [4]                  # 名前付けられた属性(r4)をアキュムレートレジスタにロード
    Star r3                                        # console.log関数のアドレスをレジスタr3にストア
    CallProperty1 r3, r4, r1, [6]                  # レジスタr4の属性でレジスタr1のある値を引数にしてレジスタr3の関数を呼び出す	
    LdaUndefined                                   # 定数"undefined"をアキュムレータレジスタにロードする
    Return                                         # アキュムレータレジスタの値を返却する
Constant pool (size = 6)

[generated bytecode for function: muladd1]
Parameter count 4
Register count 1
Frame size 8
    StackCheck                                     # スタックチェック
    Ldar a2                                        # 第3引数が入ったレジスタa2をアキュムレートレジスタにロードする。
    Mul a1, [1]                                    # アキュムレータレジスタと第2引数が入ったレジスタa1を掛け算して
                                                   # アキュムレータレジスタに結果を格納する
    Add a0, [0]                                    # アキュムレータレジスタと第1引数が入ったレジスタa0を足し算して
                                                   # アキュムレータレジスタに結果を格納する
    Star r0                                        # アキュムレータレジスタの値をレジスタr0にストアする
    Return                                         # アキュムレータレジスタの値を返却する
Constant pool (size = 0)
Handler Table (size = 0)

[generated bytecode for function: muladd2]
Parameter count 4
Register count 2
Frame size 16
    StackCheck                                     # スタックチェック
    Ldar a1                                        # 第2引数が入ったレジスタa1をアキュムレートレジスタにロードする。
    Mul a0, [1]                                    # アキュムレータレジスタと第1引数が入ったレジスタa0を掛け算して
                                                   # アキュムレータレジスタに結果を格納する
    Star r1                                        # アキュムレータレジスタをレジスタr1にストアする
    Ldar a2                                        # 第3引数が入ったレジスタa2をアキュムレートレジスタにロードする。
    Add r1, [0]                                    # アキュムレータレジスタとレジスタr1を足し算して
                                                   # アキュムレータレジスタに結果を格納する
    Star r0                                        # アキュムレータレジスタの値をレジスタr0にストアする
    Return                                         # アキュムレータレジスタの値を返却する
Constant pool (size = 0)
Handler Table (size = 0)

[generated bytecode for function: func_example]
Parameter count 4
Register count 6
Frame size 48
    StackCheck                                     # スタックチェック
    LdaImmutableCurrentContextSlot [4]             # CurrentContextSlot[4](muladd1の関数アドレス)からアキュムレータレジスタにロードする
    Star r1                                        # アキュムレータレジスタをレジスタr1にストアする
    Mov a0, r2                                     # 第1引数が入ったレジスタa0をレジスタr2に移動する
    Mov a1, r3                                     # 第2引数が入ったレジスタa1をレジスタr3に移動する
    Mov a2, r4                                     # 第3引数が入ったレジスタa2をレジスタr4に移動する
    CallUndefinedReceiver r1, r2-r4, [1]           # muladd1関数(レジスタr1にアドレスが入っている)を呼び出す
                                                   # 実引数リストは、r2-r4番に入っている
    Star r1                                        # 返却値が入っているアキュムレータレジスタをレジスタr1にストア
    LdaImmutableCurrentContextSlot [5]             # CurrentContextSlot[5](muladd2の関数アドレス)からアキュムレータレジスタにロードする
    Star r2                                        # アキュムレータレジスタからレジスタr2にストア
    Mov a0, r3                                     # 第1引数が入ったレジスタa0をレジスタr3に移動する
    Mov a1, r4                                     # 第2引数が入ったレジスタa1をレジスタr4に移動する
    Mov a2, r5                                     # 第3引数が入ったレジスタa2をレジスタr5に移動する
    CallUndefinedReceiver r2, r3-r5, [3]           # muladd2関数(レジスタr2にアドレスが入っている)を呼び出す
                                                   # 実引数リストは、r3-r5番に入っている
    Add r1, [0]                                    # アキュムレータレジスタとレジスタr1を足し算して
                                                   # アキュムレータレジスタに結果を格納する
    Star r0                                        # 返却値が入っているアキュムレータレジスタをレジスタr0にストア
    LdaSmi.Wide [341]                              # 即値341をアキュムレータレジスタにロードする
    TestEqual r0, [5]                              # アキュムレータレジスタとレジスタr0が等しいかテストする
    JumpIfFalse [7] (000000AA7251FD80 @ 58)        # もし比較結果がFALSEなら000000AA7251FD80番地にジャンプする
    LdaSmi.Wide [333]                              # 即値333をアキュムレータレジスタにロードする
    Return                                         # アキュムレータレジスタの値を返却する
000000AA7251FD80 @ 58
    LdaSmi.Wide [777]                              # 即値777をアキュムレータレジスタにロードする
    Return                                         # アキュムレータレジスタの値を返却する
Constant pool (size = 0)
Handler Table (size = 0)
```

大分、JavaScriptのバイトコードに慣れてきたのではないでしょうか。

JavaScriptのバイトコードに関する仕様書やドキュメントらしきものはないため、何かのお役に立てばよいかと思っています。

■各バイトコード命令の簡単な意味
●StackCheck
スタックポインタがスタックのlimit値を超えているかどうかチェックする命令
・・・工事中・・・

■その他
●意味不明な[数値]
関数のいわゆるフィードバックベクトルのインデックス。
フィードバックベクトルには、パフォーマンスの最適化に使用される実行時情報が含まれているが、バイトコードを読む分にはとりあえずは無視してよい。

■参考文献
・[Understanding V8’s Bytecode by @fhinkel](https://medium.com/dailyjs/understanding-v8s-bytecode-317d46c94775)
・[Ignition: V8 Interpreter](https://docs.google.com/document/d/11T2CRex9hXxoJwbYqVQ32yIPMh0uouUZLdyrtmMoL44/mobilebasic)
・[V8 Iginition Interpreter - abcdefGets](https://abcdef.gets.b6n.ch/entry/2017/05/01/173433)
・[The Journey of the Code](https://blog.ghaiklor.com/2019/07/23/the-journey-of-the-code/)