JavaScriptで、for文の初期化部分においてletで宣言された変数は本当にループごとに異なるインスタンスになるのか

# 前回
[JavaScriptで、なぜfor文の初期化部分においてletで宣言された変数はループごとに異なるインスタンスを持ちうるのか](https://qiita.com/khond/items/2d22c6b297d58ec914f5)の続き。
# 疑問
前回の調査で、規格上では「ループ各回で環境が作成される」ことがわかった。そうすると「結構コスト高な気が…」という気がしてくる。

実際、前回の例のようにクロージャがループ内で作成される場合は、ループ各回で作成されるクロージャ内でそれぞれの環境を参照しているため、ループ各回で環境の生成が必要となる。

```javascript
const functions = [];
for (let i = 0; i < 3; i++) {
  functions.push(() => console.log(i));
}
functions[0]();
functions[1]();
functions[2]();
```

だが、以下のようなfor

```javascript
for (let i = 0; i < 3; i++) {
    console.log(i);
}
```

で、クロージャ作成が無い場合は、ループ各回で作成した環境は他のどこからも参照されないので、ループ内の環境は一つでも動作は同じである。最適化してくれるのではないか?
# 調査
実際にNode.jsでどう処理されるか調べてみた。Node.jsは[V8](https://v8.dev/)を実行エンジンとして採用している。最適化するかどうかに関してはV8での話限定になってしまうが、最適化されるか? という調査観点からすれば十分である。
## V8
基本動作は[Firing up the Ignition interpreter](https://v8.dev/blog/ignition-interpreter)で述べられている。
通常JavaScriptエンジンはJITコンパイルしてスクリプトを実行するが、JITコンパイルされたコードはメモリをたくさん使ってしまう場合があるなどオーバーヘッドがある。多くはこのオーバーヘッドは無駄なので、V8ではスクリプトをバイトコード列にコンパイルし、そのバイトコードを実行するインタプリタ(Ignition)を作った。
(実行回数が多いなどパフォーマンス上影響が大きい部分は最適化したJITコンパイラ(Crankshaft/TurboFan)でコンパイルしたコードを実行する)

結局はIgnitionのバイトコードがスクリプト実行の元となるので、ここで生成されたバイトコードを見れば動きがわかるはずだ。
## Ignition
Ignitionはレジスタマシンで、特別なレジスタであるaccumulatorを持った構造である。JVMなどはスタックマシンであるが、レジスタマシン/スタックマシンの違いによりバイトコードのサイズや実行速度などが変わってくる。レジスタマシンは、オペランドの指定が必要なためバイトコードサイズが大きくなるが、実行速度が速い傾向がある。Ignitionでは自動的に入出力指定されるaccumulatorを持たせることでオペランド指定を減らし、実行速度を維持しつつバイトコードサイズも減らそうとしたのだろう。
[Ignition Design Doc](https://docs.google.com/document/d/11T2CRex9hXxoJwbYqVQ32yIPMh0uouUZLdyrtmMoL44/edit#heading=h.hgnc6jue1xwq)
> In order to reduce the size of the bytecode stream, Ignition has an accumulator register, which is used by many bytecodes as implicit input and output register. 

### ニーモニック
バイトコードに関する概要が[Understanding V8's Bytecode](https://medium.com/dailyjs/understanding-v8s-bytecode-317d46c94775)で述べられている。
よく出てくる略語は以下。

|略語|実際の語|意味|
|--|--|--|
|Ld|Load|メモリや直値でレジスタに値を読み込む|
|St|Store|レジスタからメモリやレジスタに値を書き込む|
|a|accumulator|accumulatorを対象レジスタとして指定する|
|Smi|Small integer|整数直値|
|r|register|レジスタ指定|

これらの略語を勘案すると、なんとなく以下のような気がしてくる。

|ニーモニック|意味|
|--|--|
|LdaZero|accumulatorの値を0にする|
|LdaSmi 3|accumulatorの値を3にする|
|Star r2|accumulatorの値をr2に書き込む|
|LdaGlobal 0|Global環境で0で指定されるオブジェクトをaccumulatorに読み込む|
|LdaNamedProperty r2 1|r2が指すオブジェクトにおいて1で指定されるプロパティをaccumulatorに読み込む|

ぱっと見でわかりそうなものもある。

|ニーモニック|意味|
|--|--|
|TestLessThan r0|accumulatorの値がr0の値より小かどうか判定(し、結果をフラグなどに記録)|
|JumpIfFalse 28|フラグを見てfalseだったら28ワード先にジャンプする|
|Inc|accumulatorの値に1を加算する|

など。正確な動作はV8のソースとか見ればわかるだろうが、今回の目的はそこまでは必要ないので略する。
## バイトコードを見る
読める気になったところで、実際にバイトコードを見てみる。
### クロージャを作る場合
まずはループ各回で環境が作られる様子を確認したい。以下のjsファイルを作る。

```javascript:let-for-closures.js
const letFunctions = [];

function letClosures() {
  for (let i = 0; i < 3; i++) { 
    letFunctions.push(() => console.log(i));
  }
}

letClosures();
letFunctions.forEach(f => f());

```

Node.jsでコンパイルする。`--print-bytecode`オプションでバイトコードが出力される。これだけだと出力が膨大になるので、`--print-bytecode-filter`オプションを指定して出力範囲を見たい関数だけにする。

```
% node --print-bytecode --print-bytecode-filter=letClosures let-for-closures.js
[generated bytecode for function: letClosures (0x0a271c6a0e31 <SharedFunctionInfo letClosures>)]
Parameter count 1
Register count 8
Frame size 64
   45 E> 0xa271c6a1656 @    0 : a7                StackCheck 
   65 S> 0xa271c6a1657 @    1 : 0b                LdaZero 
         0xa271c6a1658 @    2 : 26 f8             Star r3
         0xa271c6a165a @    4 : 26 fb             Star r0
         0xa271c6a165c @    6 : 0c 01             LdaSmi [1]
         0xa271c6a165e @    8 : 26 fa             Star r1
  130 E> 0xa271c6a1660 @   10 : a7                StackCheck 
         0xa271c6a1661 @   11 : 82 00             CreateBlockContext [0]
         0xa271c6a1663 @   13 : 16 f7             PushContext r4
         0xa271c6a1665 @   15 : 0f                LdaTheHole 
         0xa271c6a1666 @   16 : 1d 04             StaCurrentContextSlot [4]
         0xa271c6a1668 @   18 : 25 fb             Ldar r0
         0xa271c6a166a @   20 : 1d 04             StaCurrentContextSlot [4]
         0xa271c6a166c @   22 : 0c 01             LdaSmi [1]
         0xa271c6a166e @   24 : 67 fa 00          TestEqual r1, [0]
         0xa271c6a1671 @   27 : 9a 07             JumpIfFalse [7] (0xa271c6a1678 @ 34)
         0xa271c6a1673 @   29 : 0b                LdaZero 
         0xa271c6a1674 @   30 : 26 fa             Star r1
         0xa271c6a1676 @   32 : 8b 08             Jump [8] (0xa271c6a167e @ 40)
   76 S> 0xa271c6a1678 @   34 : 1a 04             LdaCurrentContextSlot [4]
         0xa271c6a167a @   36 : 4c 01             Inc [1]
   76 E> 0xa271c6a167c @   38 : 1d 04             StaCurrentContextSlot [4]
         0xa271c6a167e @   40 : 0c 01             LdaSmi [1]
         0xa271c6a1680 @   42 : 26 f9             Star r2
   70 S> 0xa271c6a1682 @   44 : 1a 04             LdaCurrentContextSlot [4]
         0xa271c6a1684 @   46 : 26 f6             Star r5
         0xa271c6a1686 @   48 : 0c 03             LdaSmi [3]
   70 E> 0xa271c6a1688 @   50 : 69 f6 02          TestLessThan r5, [2]
         0xa271c6a168b @   53 : 9a 04             JumpIfFalse [4] (0xa271c6a168f @ 57)
         0xa271c6a168d @   55 : 8b 06             Jump [6] (0xa271c6a1693 @ 61)
         0xa271c6a168f @   57 : 17 f7             PopContext r4
         0xa271c6a1691 @   59 : 8b 3d             Jump [61] (0xa271c6a16ce @ 120)
         0xa271c6a1693 @   61 : 0c 01             LdaSmi [1]
         0xa271c6a1695 @   63 : 67 f9 03          TestEqual r2, [3]
         0xa271c6a1698 @   66 : 9a 26             JumpIfFalse [38] (0xa271c6a16be @ 104)
   52 E> 0xa271c6a169a @   68 : a7                StackCheck 
   87 S> 0xa271c6a169b @   69 : 19 f7 04 00       LdaImmutableContextSlot r4, [4], [0]
         0xa271c6a169f @   73 : ac 01             ThrowReferenceErrorIfHole [1]
         0xa271c6a16a1 @   75 : 26 f5             Star r6
  100 E> 0xa271c6a16a3 @   77 : 28 f5 02 04       LdaNamedProperty r6, [2], [4]
         0xa271c6a16a7 @   81 : 26 f6             Star r5
         0xa271c6a16a9 @   83 : 81 03 00 02       CreateClosure [3], [0], #2
         0xa271c6a16ad @   87 : 26 f4             Star r7
  100 E> 0xa271c6a16af @   89 : 59 f6 f5 f4 06    CallProperty1 r5, r6, r7, [6]
         0xa271c6a16b4 @   94 : 0b                LdaZero 
         0xa271c6a16b5 @   95 : 26 f9             Star r2
         0xa271c6a16b7 @   97 : 1a 04             LdaCurrentContextSlot [4]
         0xa271c6a16b9 @   99 : 26 fb             Star r0
         0xa271c6a16bb @  101 : 8a 28 01          JumpLoop [40], [1] (0xa271c6a1693 @ 61)
         0xa271c6a16be @  104 : 0c 01             LdaSmi [1]
  130 E> 0xa271c6a16c0 @  106 : 67 f9 08          TestEqual r2, [8]
         0xa271c6a16c3 @  109 : 9a 06             JumpIfFalse [6] (0xa271c6a16c9 @ 115)
         0xa271c6a16c5 @  111 : 17 f7             PopContext r4
         0xa271c6a16c7 @  113 : 8b 07             Jump [7] (0xa271c6a16ce @ 120)
         0xa271c6a16c9 @  115 : 17 f7             PopContext r4
         0xa271c6a16cb @  117 : 8a 6b 00          JumpLoop [107], [0] (0xa271c6a1660 @ 10)
         0xa271c6a16ce @  120 : 0d                LdaUndefined 
  132 S> 0xa271c6a16cf @  121 : ab                Return 
Constant pool (size = 4)
Handler Table (size = 0)
0
1
2
```

ひとつひとつ見ていく。

```
   65 S> 0xa271c6a1657 @    1 : 0b                LdaZero 
         0xa271c6a1658 @    2 : 26 f8             Star r3
         0xa271c6a165a @    4 : 26 fb             Star r0
         0xa271c6a165c @    6 : 0c 01             LdaSmi [1]
         0xa271c6a165e @    8 : 26 fa             Star r1
```

`r0`と`r3`を0にし、`r1`を`1`にしている。この`0`はあとの変数`i`の初期値に使用する。

```
  130 E> 0x59e8e561660 @   10 : a7                StackCheck 
         0x59e8e561661 @   11 : 82 00             CreateBlockContext [0]
         0x59e8e561663 @   13 : 16 f7             PushContext r4
         0x59e8e561665 @   15 : 0f                LdaTheHole 
         0x59e8e561666 @   16 : 1d 04             StaCurrentContextSlot [4]
         0x59e8e561668 @   18 : 25 fb             Ldar r0
         0x59e8e56166a @   20 : 1d 04             StaCurrentContextSlot [4]
```

- `0xa271c6a1661`で`CreateBlockContext`があり、その後`PushContext r4`がある。これは環境を作って一つ中の環境に移っているということ。
- その後、`LdaTheHole`以下で、環境内の変数(`i`)を無効値で初期化→`r0`の値(`=0`)で書き換えている。
    - (スクリプトの`for (let i = 0;…`の値を`1`に書き換えると、`r0`が`1`になるので、`1`が`i`の初期値として書き込まれる)

```
         0x59e8e56166c @   22 : 0c 01             LdaSmi [1]
         0x59e8e56166e @   24 : 67 fa 00          TestEqual r1, [0]
         0x59e8e561671 @   27 : 9a 07             JumpIfFalse [7] (0x59e8e561678 @ 34)
         0x59e8e561673 @   29 : 0b                LdaZero 
         0x59e8e561674 @   30 : 26 fa             Star r1
         0x59e8e561676 @   32 : 8b 08             Jump [8] (0x59e8e56167e @ 40)
   76 S> 0x59e8e561678 @   34 : 1a 04             LdaCurrentContextSlot [4]
         0x59e8e56167a @   36 : 4c 01             Inc [1]
   76 E> 0x59e8e56167c @   38 : 1d 04             StaCurrentContextSlot [4]
```

- 最初は`r1`の値は`1`なので、`JumpIfFalse`ではジャンプしない。`r1`を`0`にして`0x59e8e56167e`へジャンプ。このジャンプは、`+1`(`Inc`)する処理を初回は飛ばすように機能する。これにより、すでに初期値が入っているところに余計に`+1`されないようにしている。
- 2回目以降に来たときは`r1`が`0`になっているので、変数`i`を`+1`する処理が入る。

```
         0x59e8e56167e @   40 : 0c 01             LdaSmi [1]
         0x59e8e561680 @   42 : 26 f9             Star r2
   70 S> 0x59e8e561682 @   44 : 1a 04             LdaCurrentContextSlot [4]
         0x59e8e561684 @   46 : 26 f6             Star r5
         0x59e8e561686 @   48 : 0c 03             LdaSmi [3]
   70 E> 0x59e8e561688 @   50 : 69 f6 02          TestLessThan r5, [2]
         0x59e8e56168b @   53 : 9a 04             JumpIfFalse [4] (0x59e8e56168f @ 57)
         0x59e8e56168d @   55 : 8b 06             Jump [6] (0x59e8e561693 @ 61)
         0x59e8e56168f @   57 : 17 f7             PopContext r4
         0x59e8e561691 @   59 : 8b 3d             Jump [61] (0x59e8e5616ce @ 120)
```

- `r2`を`1`にし、
- 変数`i`の値を`r5`に入れる。
- `r5`を`3`と比較して、(`3 < r5`が)falseなら`0x2ec0ffaa168f`にジャンプ。ジャンプすると`PopContext`して環境を一つ外に移して最後の方にジャンプしている。ということはループを抜ける処理である。つまり「変数`i`が`3`より小でないならループを終わる 」なので、forのループ判定をここでやっていることがわかる。

```
         0x59e8e561693 @   61 : 0c 01             LdaSmi [1]
         0x59e8e561695 @   63 : 67 f9 03          TestEqual r2, [3]
         0x59e8e561698 @   66 : 9a 26             JumpIfFalse [38] (0x59e8e5616be @ 104)
   52 E> 0x59e8e56169a @   68 : a7                StackCheck 
   87 S> 0x59e8e56169b @   69 : 19 f7 04 00       LdaImmutableContextSlot r4, [4], [0]
         0x59e8e56169f @   73 : ac 01             ThrowReferenceErrorIfHole [1]
         0x59e8e5616a1 @   75 : 26 f5             Star r6
  100 E> 0x59e8e5616a3 @   77 : 28 f5 02 04       LdaNamedProperty r6, [2], [4]
         0x59e8e5616a7 @   81 : 26 f6             Star r5
         0x59e8e5616a9 @   83 : 81 03 00 02       CreateClosure [3], [0], #2
         0x59e8e5616ad @   87 : 26 f4             Star r7
  100 E> 0x59e8e5616af @   89 : 59 f6 f5 f4 06    CallProperty1 r5, r6, r7, [6]

```

- `r2`が`1`でなかったら`0x59e8e5616be`にジャンプするが、いまは`1`なので進む。
- ImmutableContextSlotから`r6`に値を格納。Immutableなので、変数`letFunctions`である。`letFunctions`の中のプロパティを`r5`に入れて、クロージャを作って`r5`を呼び出している。`r5`は関数ということなので、これは`letFunctions.push(() => console.log(i))`における`push()`の呼び出しである。作ったクロージャを配列に追加しているところ。

```
         0x59e8e5616b4 @   94 : 0b                LdaZero 
         0x59e8e5616b5 @   95 : 26 f9             Star r2
         0x59e8e5616b7 @   97 : 1a 04             LdaCurrentContextSlot [4]
         0x59e8e5616b9 @   99 : 26 fb             Star r0
         0x59e8e5616bb @  101 : 8a 28 01          JumpLoop [40], [1] (0x59e8e561693 @ 61)
```

- `r2`を`0`にして、変数`i`の値を`r0`へ。その後`0x59e8e561693`へ戻る。
- `0x59e8e561693`では`r2`が`0`なので、今回は`0x59e8e5616be`へ。

```
         0x59e8e5616be @  104 : 0c 01             LdaSmi [1]
  130 E> 0x59e8e5616c0 @  106 : 67 f9 08          TestEqual r2, [8]
         0x59e8e5616c3 @  109 : 9a 06             JumpIfFalse [6] (0x59e8e5616c9 @ 115)
         0x59e8e5616c5 @  111 : 17 f7             PopContext r4
         0x59e8e5616c7 @  113 : 8b 07             Jump [7] (0x59e8e5616ce @ 120)
         0x59e8e5616c9 @  115 : 17 f7             PopContext r4
         0x59e8e5616cb @  117 : 8a 6b 00          JumpLoop [107], [0] (0x59e8e561660 @ 10)
```

- `r2`が`0`なのでまたジャンプ。`0x59e8e5616c9`へ。
- `0x59e8e5616c9`では`PopContext`して環境を一つ外にし、その後ループの先頭の方、`0x59e8e561660`にジャンプ。
- `0x59e8e561660`では、新しく環境を作って、変数`i`の値を`r0`で初期化。`r0`はループ途中の値でいまは`1`なので、`i`の値が`1`として新しい環境が作られる。ループが進むたびに`+1`されていくので、[前回](https://qiita.com/khond/items/2d22c6b297d58ec914f5#environment-records)のループ時の環境の図のようになっている。

```
         0x59e8e5616ce @  120 : 0d                LdaUndefined 
  132 S> 0x59e8e5616cf @  121 : ab                Return 
```

- ループが終わるのは`i >= 3`のとき。`0x59e8e56168f`では`PopContext`して環境を一つ外にして`0x59e8e5616ce`に来る。
- `LdaUndefined`では関数`letClosures()`の戻り値を設定している。この関数は値を返さないので、`undefined`となる。関数の戻り値はaccumulatorで受け渡しされるようだ。

ループ内でクロージャを作る場合は、ループ各回で環境が作成されていそうなことがわかった。つまり、変数`i`はループ各回で異なるインスタンスになっている。
### クロージャを作らない場合
つぎはループ内でクロージャを作らない場合。以下のjsファイルを作る。

```javascript:let-for-simple.js
function letFor() {
  for (let i = 0; i < 3; i++) { 
    console.log(i);
  }
}

letFor();
```

同様にバイトコードを出力する。

```
% node --print-bytecode --print-bytecode-filter=letFor let-for-simple.js
[generated bytecode for function: letFor (0x0f1943760df1 <SharedFunctionInfo letFor>)]
Parameter count 1
Register count 3
Frame size 24
   15 E> 0xf19437614be @    0 : a7                StackCheck 
   35 S> 0xf19437614bf @    1 : 0b                LdaZero 
         0xf19437614c0 @    2 : 26 fb             Star r0
   40 S> 0xf19437614c2 @    4 : 0c 03             LdaSmi [3]
   40 E> 0xf19437614c4 @    6 : 69 fb 00          TestLessThan r0, [0]
         0xf19437614c7 @    9 : 9a 1c             JumpIfFalse [28] (0xf19437614e3 @ 37)
   22 E> 0xf19437614c9 @   11 : a7                StackCheck 
   57 S> 0xf19437614ca @   12 : 13 00 01          LdaGlobal [0], [1]
         0xf19437614cd @   15 : 26 f9             Star r2
   65 E> 0xf19437614cf @   17 : 28 f9 01 03       LdaNamedProperty r2, [1], [3]
         0xf19437614d3 @   21 : 26 fa             Star r1
   65 E> 0xf19437614d5 @   23 : 59 fa f9 fb 05    CallProperty1 r1, r2, r0, [5]
   46 S> 0xf19437614da @   28 : 25 fb             Ldar r0
         0xf19437614dc @   30 : 4c 07             Inc [7]
         0xf19437614de @   32 : 26 fb             Star r0
         0xf19437614e0 @   34 : 8a 1e 00          JumpLoop [30], [0] (0xf19437614c2 @ 4)
         0xf19437614e3 @   37 : 0d                LdaUndefined 
   77 S> 0xf19437614e4 @   38 : ab                Return 
Constant pool (size = 2)
Handler Table (size = 0)
0
1
2
```

短い。

- `r0`を`0`にし、`3`と比較。ここはループ判定とわかる。
- `0xf19437614ca`以下は、`console.log(i)`の呼び出しということは先ほど見てきた`letFunctions.push()`からすぐにわかる。
- その後`r0`の値を`+1`して、ループの頭に戻っている。

すなわち、環境も作らず、`PushContext`/`PopContext`もない。変数`i`はレジスタ`r0`を割り当てている。いちいち環境に格納するまでもない、ということである。このように最適化によって環境を作る処理が省略されている。

# 結論
クロージャがある場合はループの各回で環境が作られるが、必要ないところではちゃんと最適化されていることがわかった。

## varだと?
### クロージャを作る場合

```
[generated bytecode for function: varClosures (0x3b4588b60e31 <SharedFunctionInfo varClosures>)]
Parameter count 1
Register count 4
Frame size 32
         0x3b4588b61626 @    0 : 84 00 01          CreateFunctionContext [0], [1]
         0x3b4588b61629 @    3 : 16 fb             PushContext r0
   45 E> 0x3b4588b6162b @    5 : a7                StackCheck 
   65 S> 0x3b4588b6162c @    6 : 0b                LdaZero 
   65 E> 0x3b4588b6162d @    7 : 1d 04             StaCurrentContextSlot [4]
   70 S> 0x3b4588b6162f @    9 : 1a 04             LdaCurrentContextSlot [4]
         0x3b4588b61631 @   11 : 26 fa             Star r1
         0x3b4588b61633 @   13 : 0c 03             LdaSmi [3]
   70 E> 0x3b4588b61635 @   15 : 69 fa 00          TestLessThan r1, [0]
         0x3b4588b61638 @   18 : 9a 25             JumpIfFalse [37] (0x3b4588b6165d @ 55)
   52 E> 0x3b4588b6163a @   20 : a7                StackCheck 
   87 S> 0x3b4588b6163b @   21 : 19 fb 04 00       LdaImmutableContextSlot r0, [4], [0]
         0x3b4588b6163f @   25 : ac 01             ThrowReferenceErrorIfHole [1]
         0x3b4588b61641 @   27 : 26 f9             Star r2
  100 E> 0x3b4588b61643 @   29 : 28 f9 02 01       LdaNamedProperty r2, [2], [1]
         0x3b4588b61647 @   33 : 26 fa             Star r1
         0x3b4588b61649 @   35 : 81 03 00 02       CreateClosure [3], [0], #2
         0x3b4588b6164d @   39 : 26 f8             Star r3
  100 E> 0x3b4588b6164f @   41 : 59 fa f9 f8 03    CallProperty1 r1, r2, r3, [3]
   76 S> 0x3b4588b61654 @   46 : 1a 04             LdaCurrentContextSlot [4]
         0x3b4588b61656 @   48 : 4c 05             Inc [5]
   76 E> 0x3b4588b61658 @   50 : 1d 04             StaCurrentContextSlot [4]
         0x3b4588b6165a @   52 : 8a 2b 00          JumpLoop [43], [0] (0x3b4588b6162f @ 9)
         0x3b4588b6165d @   55 : 0d                LdaUndefined 
  132 S> 0x3b4588b6165e @   56 : ab                Return 
Constant pool (size = 4)
Handler Table (size = 0)
3
3
3
```

- `CreateFunctionContext`が最初に実行され、環境はそれ以外作られない。`var`は関数内スコープとなるので、直感的な予想とも合致する。

### クロージャを作らない場合

今回は関数内で他にvar/let/constで宣言された変数とかがないため、letと同じ結果が得られる。

```
[generated bytecode for function: varFor (0x0d1a8bba0df1 <SharedFunctionInfo varFor>)]
Parameter count 1
Register count 3
Frame size 24
   15 E> 0xd1a8bba14be @    0 : a7                StackCheck 
   35 S> 0xd1a8bba14bf @    1 : 0b                LdaZero 
         0xd1a8bba14c0 @    2 : 26 fb             Star r0
   40 S> 0xd1a8bba14c2 @    4 : 0c 03             LdaSmi [3]
   40 E> 0xd1a8bba14c4 @    6 : 69 fb 00          TestLessThan r0, [0]
         0xd1a8bba14c7 @    9 : 9a 1c             JumpIfFalse [28] (0xd1a8bba14e3 @ 37)
   22 E> 0xd1a8bba14c9 @   11 : a7                StackCheck 
   57 S> 0xd1a8bba14ca @   12 : 13 00 01          LdaGlobal [0], [1]
         0xd1a8bba14cd @   15 : 26 f9             Star r2
   65 E> 0xd1a8bba14cf @   17 : 28 f9 01 03       LdaNamedProperty r2, [1], [3]
         0xd1a8bba14d3 @   21 : 26 fa             Star r1
   65 E> 0xd1a8bba14d5 @   23 : 59 fa f9 fb 05    CallProperty1 r1, r2, r0, [5]
   46 S> 0xd1a8bba14da @   28 : 25 fb             Ldar r0
         0xd1a8bba14dc @   30 : 4c 07             Inc [7]
         0xd1a8bba14de @   32 : 26 fb             Star r0
         0xd1a8bba14e0 @   34 : 8a 1e 00          JumpLoop [30], [0] (0xd1a8bba14c2 @ 4)
         0xd1a8bba14e3 @   37 : 0d                LdaUndefined 
   77 S> 0xd1a8bba14e4 @   38 : ab                Return 
Constant pool (size = 2)
Handler Table (size = 0)
0
1
2
```

(おわり)