JVMことはじめ その1: クラスファイル

# この記事は何?

最近趣味で[JVMを作り始めた](https://github.com/maekawatoshiki/ferrugo)ので，その過程で得た知見とかを書いていく記事です．
今回は，クラスファイルに焦点を当てていきます．

# 参考文献

参考文献は一番最後に書くものだと思ってたけど，最初に書いても良いんじゃないだろうか.

- [Java Virtual Machine Specification](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html) - まさしくJVMの規格書．一番信頼できるし，わからないことがあればとりあえずここを見る．
- [Javaのクラスファイルをjavapとバイナリエディタで読む](https://dev.classmethod.jp/server-side/java/classfile-reading/) - 軽くクラスファイルの内部に触れてみようとして，最初に見つけた記事．とてもわかりやすかった．

# クラスファイルの構造

[規格](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.1)より抜粋．

```c
ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}
```

``uN``はNバイトの符号なし整数を表現しているようです．
それでは最初のフィールドから見ていきましょう．

## magic 

クラスファイルの先頭に位置する``magic``には定数``CAFEBABE``(16進数)が入ります．CAFEBABEという値になった理由は色々あるようです．
わかりやすい値なので，これで誰でもクラスファイルと気づくことができますね．

## minor_version, major_version

正直説明することがないですね．(マイナー|メジャー)バージョン情報です．

## constant_pool_count

後述する``constant_pool``のエントリの数**-1**を表しています．

## constant_pool

前述した``constant_pool_count``の値によって長さの変わる配列です．型も``cp_info``と見慣れないものになっています．

とりあえず，[``cp_info``の中身](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4)を見てみましょう．

```c
cp_info {
    u1 tag;
    u1 info[];
}
```

``tag``はその``cp_info``が何を表しているのか(=Constant Type)を示すものです．``info``は``tag``によって大きさが変わります．
Constant Typeと``tag``の値の対応は以下のようになっています．

| Constant Type | tagの値 |
|:---:|:---:|
| CONSTANT_Class | 7 |
| CONSTANT_Fieldref | 9 |
| CONSTANT_Methodref | 10 |
| CONSTANT_InterfaceMethodref | 11 |
| CONSTANT_String | 8 |
| CONSTANT_Integer | 3 |
| CONSTANT_Float | 4 |
| CONSTANT_Long | 5 |
| CONSTANT_Double | 6 |
| CONSTANT_NameAndType | 12 |
| CONSTANT_Utf8 | 1 |
| CONSTANT_MethodHandle | 15 |
| CONSTANT_MethodType | 16 |
| CONSTANT_InvokeDynamic | 18 |

``tag``の値，Constant Typeは色々あって一つづつ説明していると長くなるので，とりあえずはカット．詳しく知りたい方は，[規格のこのあたりから](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.1)を読めば幸せになれると思います．

### ハマったところとか

- ``constant_pool``の0番目の要素は存在しません．もう少し詳しく言うと，0番目はデータが存在しないことを表現するのに使います．だから，``constant_pool[constant_pool_count-1]``．
- CONSTANT_Utf8で表されるUTF-8文字列はヌル終端じゃなかった．(C言語脳なので，文字列はNULLで終わるものだと思っていた)
- Constant Typeが``CONSTANT_Long``や``Constant_Double``の時は，特殊なケースなので注意すること．

>All 8-byte constants take up two entries in the constant_pool table of the class file. If a CONSTANT_Long_info or CONSTANT_Double_info structure is the item in the constant_pool table at index n, then the next usable item in the pool is located at index n+2. The constant_pool index n+1 must be valid but is considered unusable.
https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.5

## access_flags

アクセス権限とかその他色々を表すフラグです．規格によると，今は8種類あるようです．

| フラグの名前 | 値 | 説明 |
|:------:|:--------:|:-------:|
| ACC_PUBLIC | 0x0001 | publicであることを表す．パッケージの外部からアクセスされるかもしれないってことですね |
| ACC_FINAL | 0x0010 | final. いかなるサブクラスも許されない，と．|
| ACC_SUPER | 0x0020 | ``invokespecial``という命令によって呼び出された時に，スーパークラスのメソッドを扱う．|
| ACC_INTERFACE | 0x0200 | インターフェース．クラスじゃないよ． |
| ACC_ABSTRACT | 0x0400 | abstract．インスタンス化，ダメゼッタイ． |
| ACC_SYNTHETIC | 0x1000 | synthetic．コンパイラが勝手に作る．|
| ACC_ANNOTATION | 0x2000 | アノテーション型 |
| ACC_ENUM | 0x4000 | enumですね |

## this_class, super_class

前述の``constant_pool``のうち，

- ``this_class``の表す値のインデックスに位置するのが，そのクラスの名前
- ``super_class``の表す値のインデックスに位置するのが，スーパークラスの名前

となっています．

名前というのは(というかクラスファイルに含まれる文字列は)UTF-8で表されているようで，先ほど登場したConstant TypeのCONSTANT_Utf8に対応します．

## interfaces_count

このクラス，またはインターフェース型の直接のスーパーインターフェースの数を表します．要するに，後述の``interfaces``の要素数です．

## interfaces

``interfaces``の要素の表す値は，``constant_pool``のインデックスとなっています．
対応する``constant_pool``の値のConstant TypeはCONSTANT_Class_info(CONSTANT_Classが表す構造体)である必要があります．

特に面白くないですね．

## fields_count

このクラス，またはインターフェース型で定義されているフィールドの数．
後述の``fields``の要素数でもある．

## fields

``field_info``という謎の型でできた配列．[定義](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.5)はこうなっています．

```c
field_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}
```

``attribute_info``という，またもや知らない型が出てきましたが，とりあえずは置いておきましょう．

### access_flags

先程も``access_flags``というフィールドを見た気がしますが，それとはまた別のものです．

| 名前 | Value | Interpretation |
|:--:|:--:|:--:|
| ACC_PUBLIC | 0x0001 | public．|
| ACC_PRIVATE | 0x0002 | private．そのクラス内でのみ利用可．|
| ACC_PROTECTED | 0x0004 | protected．サブクラスからアクセスされるかもね. |
| ACC_STATIC | 0x0008 | static. |
| ACC_FINAL | 0x0010 | final．オブジェクトが生成された後には直接代入されない(JLS §17.5になんか書いてあるらしい). |
| ACC_VOLATILE | 0x0040 | volatile．キャッシュできない. |
| ACC_TRANSIENT | 0x0080 | transient．persistent object managerから書き込まれたり読み込まれたりしない．|
| ACC_SYNTHETIC | 0x1000 | synthetic．|
| ACC_ENUM | 0x4000 | enumの要素. |

### name_index, descriptor_index

両方とも，``constant_pool``への参照値(インデックスですね)を表します．

``name_index``の指す先には，``fibo``などフィールドの名前が含まれます．

``descriptor_index``の指す先には，``(I)I``などの型情報が含まれます．基本的には``(X)Y``という形式で，Xが引数，Yが返却値の型を表しているようです．

### attribute...

また後で解説します．結構重要な位置を占めるものなので．

## methods_count, methods

このクラス，またはインターフェース型で定義されているメソッドのことを表している．．．というのは，もはや説明の必要はないでしょう．

前述の``fields_count``と``fields``に似ている，といいますか，同じです．

``method_info``も``field_info``と同じ．

```c
method_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}
```

## attribute_count

後述する``attributes``の要素数．

## attributes

クラスファイルの中でも一番最後のフィールドです．そして，``fields``や``methods``の中ですでに何度も現れている型である[attribute_info](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7)で構成されています．

```c
attribute_info {
    u2 attribute_name_index;
    u4 attribute_length;
    u1 info[attribute_length];
}
```

``attribute_name_index``は``constant_pool``への参照値．アトリビュートの名前を表します．
``attribute_length``は，``info``の長さのようです．``info``はアトリビュートの名前によって内容が変わります．

現在はこんなに種類のあるアトリビュート↓ この一つひとつに対応する構造体があり，それが``info``の中に収まっているわけです．

| アトリビュートの名前 |
|:--:|
| ConstantValue                        | 
| Code                                 | 
| StackMapTable                        | 
| Exceptions                           | 
| InnerClasses                         | 
| EnclosingMethod                      | 
| Synthetic                            | 
| Signature                            | 
| SourceFile                           | 
| SourceDebugExtension                 | 
| LineNumberTable                      | 
| LocalVariableTable                   | 
| LocalVariableTypeTable               | 
| Deprecated                           | 
| RuntimeVisibleAnnotations            | 
| RuntimeInvisibleAnnotations          | 
| RuntimeVisibleParameterAnnotations   | 
| RuntimeInvisibleParameterAnnotations | 
| AnnotationDefault                    | 
| BootstrapMethods                     | 


# 実践

ここまでクラスファイルの中身を見てきましたが，これだけではわかった気にはなれませんね．
実際のクラスファイルを見てみます．

以下のようなJavaコードを考えます．

```java:Add.java
class Add {
  public static int add(int x, int y) {
    return x + y;
  }
}
```

コンパイルして，xxdで見てみる．

```
$ javac Add.java
$ xxd Add.class
00000000: cafe babe 0000 0034 000f 0a00 0300 0c07  .......4........
00000010: 000d 0700 0e01 0006 3c69 6e69 743e 0100  ........<init>..
00000020: 0328 2956 0100 0443 6f64 6501 000f 4c69  .()V...Code...Li
00000030: 6e65 4e75 6d62 6572 5461 626c 6501 0003  neNumberTable...
00000040: 6164 6401 0005 2849 4929 4901 000a 536f  add...(II)I...So
00000050: 7572 6365 4669 6c65 0100 0841 6464 2e6a  urceFile...Add.j
00000060: 6176 610c 0004 0005 0100 0341 6464 0100  ava........Add..
00000070: 106a 6176 612f 6c61 6e67 2f4f 626a 6563  .java/lang/Objec
00000080: 7400 2000 0200 0300 0000 0000 0200 0000  t. .............
00000090: 0400 0500 0100 0600 0000 1d00 0100 0100  ................
000000a0: 0000 052a b700 01b1 0000 0001 0007 0000  ...*............
000000b0: 0006 0001 0000 0001 0009 0008 0009 0001  ................
000000c0: 0006 0000 001c 0002 0002 0000 0004 1a1b  ................
000000d0: 60ac 0000 0001 0007 0000 0006 0001 0000  `...............
000000e0: 0003 0001 000a 0000 0002 000b            ............
```

さあ，ここまでで学んだ知識を使って読んでいきましょう．．．と言いたかったのですが．．．

![Untitled Diagram (3).png](https://qiita-image-store.s3.amazonaws.com/0/69622/6272c4a2-ba45-7ce7-eb94-e5e84b9c9d0d.png)

ここまで作って，力尽きました．すいません．(いつか全部埋めて置き換える)

どうしても全部読みたい！という方は規格とにらめっこするか，[私のコードのここらへん](https://github.com/maekawatoshiki/ferrugo/tree/master/src/class/classfile)を参照すれば幸せになれるはず．

# 最後に

普段，記事を書いたりするなどのOutputがなかったので書いてみました．
一応シリーズ物なので，次はJVMがクラスファイルを読み込んでどう実行するのかについて書きたいなぁなんて思っています．

批評などコメントは大歓迎です．