22
Dalvik仮想マシンの アーキテクチャ 発表者 : 僻地の暗黒プログラマ kmt-t

Dalvik仮想マシンのアーキテクチャ

  • Upload
    kmt-t

  • View
    9.982

  • Download
    8

Embed Size (px)

DESCRIPTION

改定しました http://www.slideshare.net/kmt-t/dalvik-10316622

Citation preview

Page 1: Dalvik仮想マシンのアーキテクチャ

Dalvik仮想マシンの

アーキテクチャ

発表者 : 僻地の暗黒プログラマ kmt-t

Page 2: Dalvik仮想マシンのアーキテクチャ

自己紹介

Web上での活動

ハンドルネーム : kmt-t

はてな ID : kmt-t2

Twitter ID : kmt_t

属性

僻地といいながら去年の10月から大阪在住です

組み込みプログラマらしい?

画像処理、ファイルシステムなどのミドルウェア中心

使用する言語はC++(not C)/C#/たまにPython

関数型言語はOcaml/F#派。あまり触れてませんが

Page 3: Dalvik仮想マシンのアーキテクチャ

今後の話の前振り

Dalvik仮想マシン三部作

Dalvik仮想マシンのアーキテクチャ

Dalvikバイトコードのリファレンスの読み方

DEXファイルフォーマット

今回は第一部のみを解説

機会があれば第二部、第三部もやりたい

三部作のゴール

ソースコードを誰でも読めるようにしたい

Page 4: Dalvik仮想マシンのアーキテクチャ

本日の前振り

仮想マシンの基本的なアーキテクチャ スタックマシンとは?レジスタマシンとは?

スレッドインタープリタとは?

Java仮想マシンの詳細についてのリファレンス 「Java仮想マシン仕様 第二版」

ISBN : 489471356X

ガベージコレクションは以下の本が詳しい 「ガベージコレクションのアルゴリズムと実装」

ISBN : 4798025623

Dalvik仮想マシンの「今の」実装は大幅に変わっている

Page 5: Dalvik仮想マシンのアーキテクチャ

アーキテクチャ比較

Java仮想マシン vs Dalvik仮想マシン

Java仮想マシン

スタックマシン

Dalvik仮想マシン

レジスタマシン

両者の違いとトレードオフの関係は?

当然両者一長一短

今回の解説ではこの点をクリアにしたい

Page 6: Dalvik仮想マシンのアーキテクチャ

Java仮想マシン

スタックマシン

計算に使用する値をスタックに積んでいく

スタックから値をポップして、その値で演算

演算結果をスタックに積む

値1

値2

値3

メモリ

値1

値2

値3

演算

Page 7: Dalvik仮想マシンのアーキテクチャ

Dalvik仮想マシン

レジスタマシン (1)

レジスタとよばれる領域を使って計算する

R0

R1

R2

R3

R4

R5

R6

R7

メモリ

演算

Page 8: Dalvik仮想マシンのアーキテクチャ

Dalvik仮想マシン

レジスタマシン (2)

Dalvik仮想マシンは特殊なレジスタマシン

レジスタはメソッドごとに用意される

レジスタはスタック領域に積まれる形で用意される

レジスタ数が可変 (0~65535個)

C言語のローカル変数と扱いは近い

Page 9: Dalvik仮想マシンのアーキテクチャ

Dalvik仮想マシン

レジスタマシン (3)

メソッドAからメソッドBを呼んだ場合のスタック

成長方向

(VM-specific internal goop)

メソッドB R0 (ローカル変数)

メソッドB R1 (ローカル変数)

メソッドB R2 (引数1)

メソッドA R0 (ローカル変数)

メソッドA R1 (ローカル変数)

メソッドA R2(引数1)

メソッドA R3(引数2)

メソッドBレジスタ

メソッドAレジスタ

Page 10: Dalvik仮想マシンのアーキテクチャ

一般的に考えられる

バイトコードのフォーマット

バイトコード命令には最低必要な情報 命令の種類をあらわす「オペコード」

命令の対象となるデータを指す「オペランド」

これは仮想マシンだけでなく本物のCPUも同様

命令のバイナリサイズを命令長と呼ぶ 命令長は短いほうが実行ファイルサイズ的に有利

命令長は可変長、固定長どちらもありうる

Java/Dalvik仮想マシンは可変長

本物のCPUのARM/MIPSなどは固定長

Page 11: Dalvik仮想マシンのアーキテクチャ

バイトコード命令の

バイナリデータの例

バイトコード命令の例 (架空の例)

DEST = SRC1 + SRC2 演算命令

オペコード8bit

(ADD)

オペランド8bit

(DEST

レジスタ番号)

オペランド8bit

(SRC1

レジスタ番号)

オペランド8bit

(SRC2

レジスタ番号)

命令長32bit

Page 12: Dalvik仮想マシンのアーキテクチャ

Java仮想マシンの

バイトコードのフォーマット

オペコードは8bit

オペランドは省略できることが多い

スタックマシンなので命令の対象データがスタックトップに決まっている命令が多いため

そのため、Java仮想マシンのバイトコードはオペコードのみの8bit命令が多い

Page 13: Dalvik仮想マシンのアーキテクチャ

Dalvik仮想マシンの

バイトコードのフォーマット

オペコードは8bit

レジスタを指すオペランドは最大16bit レジスタは最大65535個あるため

Java仮想マシンのような省略は不可

3オペランドの命令の場合、普通に考えると、オペコード8bit、オペランド16bit*3=48bitで命令長が56bitになる

命令長は必ず16bitでアライメント 命令長的にはJava仮想マシンに比べて不利

Page 14: Dalvik仮想マシンのアーキテクチャ

Dalvik仮想マシンの

バイトコードの工夫

レジスタが多いため、オペランドが巨大化

この問題を解決するため、「すべての命令ですべてのレジスタを参照」しない

多くの命令はレジスタ番号0~15または0~256

までのレジスタしか参照できない

オペランドサイズを4bitまたは8bitに圧縮

これでもJava仮想マシンより命令長は長い

Page 15: Dalvik仮想マシンのアーキテクチャ

命令数が多いことによる問題点

レジスタマシンにしたのは何故か?

スタックマシンは命令長が短い代わりにスタック操作のための命令の挿入が必要

つまり命令数はJava仮想マシンの方が多い

命令数が多くなるのを嫌ったのでは?

インタープリタのパフォーマンス上非常に不利

インタープリタは命令そのものの処理より、命令毎に発生するオーバーヘッドのほうが非常に大きい

JITコンパイラを使えばこのオーバーヘッドは回避できる。JITコンパイラで高速化できる理由は主にこの点が大きい

Page 16: Dalvik仮想マシンのアーキテクチャ

一般的なインタープリタ実装

擬似コードで書くと以下のような感じ

普通の感覚では特に問題ないように思える

実は非常にオーバヘッドが大きなコード

どの辺りがオーバヘッドが大きいのか?

# INSTR = 現在実行中のバイトコード命令 # TBL = オペコードに対応した処理の関数テーブル LOOP : FUNC = TBL[INSTR->OPCODE] CALL FUNC(INSTR) # 関数呼び出し NEXT INSTR # 次の命令に移動する GOTO LOOP # 繰り返し

Page 17: Dalvik仮想マシンのアーキテクチャ

一般的なインタープリタの問題点

ジャンプ命令が必要な箇所が多い

命令ごとにループを回す箇所のジャンプ

命令実行ルーチンに飛ぶためのジャンプ

命令実行ルーチンから戻るためのジャンプ

ジャンプは最悪10CPUサイクル以上かかる重い処理

メモリアクセス

テーブル参照のメモリアクセス

命令処理に対し数十倍のオーバーヘッド

命令処理内容が単なる加算だとすると、それ自体は1CPUサイクル(ARMの場合)程度で完了

Page 18: Dalvik仮想マシンのアーキテクチャ

Dalvik仮想マシンのインタープリタ

スレッドインタープリタ方式 # 最初の命令処理ルーチンのアドレスをBASE_ADDRとする # 各命令処理ルーチンの間隔は64バイトでアライメント .ALIGN 64 OP_A : … # ここで命令実行 NEXT INSTR # 次の命令に移動する GOTO BASE_ADDR + 64 * INSTR->OPCODE .ALIGN 64 OP_B : … # ここで命令実行 NEXT INSTR # 次の命令に移動する GOTO BASE_ADDR + 64 * INSTR->OPCODE

… # 以下繰り返し

Page 19: Dalvik仮想マシンのアーキテクチャ

Dalvik仮想マシン

インタープリタの改善点

ジャンプ命令が必要な箇所が少ない

命令処理の最後に一回ジャンプするだけ

メモリアクセス

テーブル参照が存在しない

命令処理に対し数倍程度のオーバーヘッド

唯一のジャンプがCPUが分岐予測できない

最新のARMプロセッサだとパイプラインストールで十数CPUサイクルのロス

Page 20: Dalvik仮想マシンのアーキテクチャ

まとめ

Dalvik仮想マシンではインタープリタを改善すべく工夫されている それでも命令毎のオーバーヘッドは大きい

依然としてバイトコードの命令数は少ないほうが良い

以上をまとめると バイナリサイズはJava仮想マシンの方がだいぶん小さい

実行速度はDalvik仮想マシンの方が高速にできる「かもしれない」

Page 21: Dalvik仮想マシンのアーキテクチャ

今後の予定

Dalvikバイトコードのリファレンスの読み方

今回解説した内容をベースにDalvikバイトコードのリファレンスの読み方を次回解説したい

ここまでいけば自力でインタープリタのソースは読めるようになる

みんなでDalvik仮想マシンを語れるように

Page 22: Dalvik仮想マシンのアーキテクチャ

以上で発表は終わりです

ご静聴ありがとうございました!