Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JVM言語の動き方・動かし方 /make-jvm-lang

Miyakawa Taku
February 27, 2019

JVM言語の動き方・動かし方 /make-jvm-lang

言語処理系一般の仕組みを腑分けして、JVM言語の動き方・動かし方を把握します。

• 言語処理系の構成
• コンピュータはどのようにプログラムを動かすのか
• JVMはどのようにプログラムを動かすのか
• JVM言語処理系の構成: Kinkを題材に

本資料をCC BY 4.0ライセンスにもとづいて提供します。
https://creativecommons.org/licenses/by/4.0/deed.ja

Miyakawa Taku

February 27, 2019
Tweet

More Decks by Miyakawa Taku

Other Decks in Programming

Transcript

  1. 本セッションにおける用語定義 書かれた プログラム くりかえし 三回: 念仏.唱える コンピュータ上での 実行 南無阿弥陀仏 南無阿弥陀仏

    南無阿弥陀仏 この間に必要なソフトウェア一式を 「言語処理系」と呼ぶことにする #jjug 7/127
  2. 翻訳系の中身 書かれたプログラム トークン列 抽象構文木 (AST) 実行に適した表現 字句解析 構文解析 シンボル解決, 型検査,

    最適化,,, " く り か え し ", " 三 回 ", " : ", , , (loop 3 (call (var "念仏") "唱える")) #jjug 11/127
  3. データ投入バッチ タブ区切りテキスト トークン列 抽象構文木 (AST) データベース 字句解析 構文解析 マスタ突合, バリデーション,,,

    "中島敦", "悟浄歎異", 1942, 改行,,, [{"author": "中島敦", "title": "悟浄歎異", "year": 1942},,,] 中島敦 悟浄歎異 1942 深沢七郎 風流夢譚 1960 ,,, やってることは翻訳系と同じ! #jjug 13/127
  4. 誰が実行する? 実行対象 実行の担い手 機械語の プログラム CPUとOS つまりコンピュータそのもの 機械語以外: バイトコード、 木構造など

    実行系のプログラム: JVM, V8, YARVなど コンピュータの真似をする “Java Virtual Machine”! #jjug 17/127
  5. サンプルプログラム N = M + 42 ld x5, &M addi

    x6, x5, 42 sd x6, &N 書かれた プログラム RISC-Vの 機械語 プログラム x5, x6: レジスタ &M, &N: 変数の番地 #jjug 20/127
  6. CPU CPUの概念図 *3 レ ジ ス タ 群 演 算

    装 置 ( ALU ) メ モ リ デ ー タ 用 ポ ー ト 命 令 用 ポ ー ト Program Counter +4 番 地 命 令 番 地 入 力 演 算 結 果 デ ー タ 次 の 命 令 へ レ ジ ス タ : 計 算 に 使 う 数 値 を 置 い て お く 場 所 Program Counter ( PC ) : 実 行 す る 命 令 の 番 地 を 表 す 特 殊 な レ ジ ス タ 演 算 装 置 ( ALU ) : 加 算 器 と か 除 算 器 と か の 回 路 の か た ま り #jjug 25/127
  7. CPU ld x5, &M レ ジ ス タ 群 演

    算 装 置 ( ALU ) メ モ リ デ ー タ 用 ポ ー ト 命 令 用 ポ ー ト Program Counter +4 1) 100 6) x5 7) +4 3) &M=200 4) &M=200 5) M=3 1) 実行する命令の番地 2) 命 令 5) M =3 をロード #jjug 2) 命令をロード 3, 4) M の番地 6) 3 をx5 レジスタに書き込み 7) +4 して次の命令の番地へ 26/127
  8. CPU addi x6, x5, 42 レ ジ ス タ 群

    演 算 装 置 ( ALU ) メ モ リ デ ー タ 用 ポ ー ト 命 令 用 ポ ー ト Program Counter +4 1) 104 3) x5 8) +4 5) 42 1) 実行する命令の番地 2) 命 令 5) 即 値 をALU に入力 4) x5=3 6) 和=45 7) x6 #jjug 3, 4) x5 =3 をALU に入力 2) 命令をロード 6, 7) 和をx6 レジスタに 8) +4 して次の命令の番地へ 27/127
  9. CPU sd x6, &N レ ジ ス タ 群 演

    算 装 置 ( ALU ) メ モ リ デ ー タ 用 ポ ー ト 命 令 用 ポ ー ト Program Counter +4 1) 108 5) x6 7) +4 3) &N=204 4) &N=204 6) x6=45 1) 実行する命令の番地 2) 命 令 5, 6) x6 =45 をN に書き込み #jjug 3, 4) N の番地 2) 命令をロード 7) +4 して次の命令の番地へ 28/127
  10. 手続きbarを呼び出す jal x1, &bar jal命令は次の2つを実行する 1. PC+4をx1に入れる ⚫ PC+4は、jal命令の次の命令の番地 ⚫

    あとでこの戻り番地に戻ってくる 2. PCに&barを入れる ⚫ つまり、barの命令列にジャンプする #jjug 31/127
  11. 手続きbarから戻る jalr x0, x1 #jjug jalr命令は次の2つを実行する 1. PC+4をx0に入れる ⚫ x0は、入れた値が捨てられる特殊なレジスタ

    ⚫ つまりここでは、PC+4は捨てられる 2. PCにx1を入れる ⚫ x1には、呼び出し元で設定された 戻り番地が入っている ⚫ つまり、呼び出し元にジャンプ=returnする 32/127
  12. 計算 コンピュータ WebAssembly JVM PC, ALU, レジスタ, ... 仕様は項書換え系 実装は様々

    バイトコードインタプリタ &JITコンパイラ 計算にはさまざまな実現方法がある #jjug 50/127
  13. バイトコードインタプリタ 実装のイメージ for (int pc = 0; pc < instructions_len;

    ++pc) { long insn = instructions[pc]; switch (get_opcode(insn)) { case GETFIELD: obj *obj = datastack[--sp]; sym field_sym = get_operand(insn); datastack[sp++] = obj->get_field(field_sym); break; case SETFIELD: ... } } #jjug 59/127
  14. Kinkってこんな言語 :new_dog <- { new_val( 'bark' { 'Bow' } 'howl'

    { 'Wow' } ) } :Dog <- new_dog stdout.print_line(Dog.bark) # => Bow stdout.print_line(Dog.howl) # => Wow :Another_dog <- new_dog Another_dog:howl <- { 'Grrr' } stdout.print_line(Another_dog.bark) # => Bow stdout.print_line(Another_dog.howl) # => Grrr #jjug Kink言語マニュアル: 特徴 81/127
  15. Kinkの処理系 kinkコマンド 翻訳系 実行系 Qcode Kinkソースコード Qcode: 自前のバイトコード を Javaで実装された

    インタプリタで実行 ひとつのコマンドで翻訳系・実行系をまかなう RubyやPythonなどと同様 #jjug 82/127
  16. Kinkの処理系: 翻訳系 *5 ソースコード トークン列 AST Qcode Itree Wire 最適化

    最適化 木構造の中間表現 フラットな中間表現 #jjug 83/127
  17. クラスベースの継承 値 データ X データ Y クラス 親クラス メソッド a

    メソッド b メソッド b メソッド c instance-of is-a 例: ⚫ Java ⚫ Smalltalk ⚫ Ruby ⚫ C++ #jjug 87/127
  18. プロトタイプベースの継承 値 データ X データ Y プロト タイプ プロト の親

    メソッド a メソッド b メソッド b メソッド c delegate-to delegate-to 例: ⚫ JavaScript ⚫ SELF ⚫ Io ※ Luaは変わり種 #jjug 88/127
  19. #jjug トレイト 複数の値で共有するフィールドのかたまりを トレイトと呼ぶ(実体はただの配列) # 色のトレイト :Color_trait <- [ 'lightness'

    {[:C] (C._max + C._min) // 2 } '_max' {[:C] [C.R C.G C.B].fold(0 COMPARE$max) } '_min' {[:C] [C.R C.G C.B].fold(255 COMPARE$min) } ] 92/127
  20. 意味は下記と同じ #jjug new_val( # トレイトが展開された結果 'lightness' { 省略 } '_max'

    { 省略 } '_min' { 省略 } 'R' 64 'G' 128 'B' 255 ) このとおり実装すると無駄が多いので、 そこは実行系が工夫する 94/127
  21. オブジェクトシステムの実装 Kinkの値: Valクラス commonVarMapping traitVarMapping ownVarMapping 全ての値に共通の フィールド群(不変): k1→v1, k2→v2,,,

    複数の値に共有される フィールド群(不変): k1→v1, k2→v2,,, 値固有の フィールド群(可変): k1→v1, k2→v2,,, #jjug 96/127
  22. メモリ管理 Kinkの値: Valクラス commonVarMapping traitVarMapping ownVarMapping k1→v1, k2→v2,,, k1→v1, k2→v2,,,

    k1→v1, k2→v2,,, 値同士の参照関係はJavaオブジェクトの参照関係に マッピングされている → メモリ管理はJavaのGCに丸投げできる #jjug 97/127
  23. reset & shift: 継続の保存 reset: スタック上にタグを打つ tag resetブロック内の処理 tag shift:

    タグまでの切片を関数(=継続)に保存 tag tag kont = #jjug 101/127
  24. ベンチマーク: たらいまわし関数 #jjug :tarai <- {(:X :Y :Z) (X <=

    Y).if_else( { Y } { tarai( tarai(X - 1 Y Z) tarai(Y - 1 Z X) tarai(Z - 1 X Y) ) } ) } tarai(13 6 0) 106/127
  25. #jjug tarai(13 6 0) 3.8 秒 7.7 秒 12.0 秒

    30.3 秒 43.5 秒 Ruby 2.5.1 Python 3.6.7 GNU awk 4.1.4 GNU bc 1.07.1 Kink @ Xeon E5-2699 v4 107/127
  26. Abelson, Sussman, Sussman 『Structure and Interpretation of Computer Programs』, 1996

    ◼ いわゆる「SICP」 ◼ Scheme言語の上で、Scheme言語の 実行系を作ろう!という本 ◼ 5章がバイトコードインタプリタ ◆ 自前のメモリ管理も扱われています #jjug 115/127
  27. Patterson, Hennessy 『Computer Organization and Design: RISC-V Edition』, 2017 ◼

    いわゆる「パタヘネ」 ◆ 「ヘネパタ」は別書なので注意! ◼ CPUがプログラムをどうやって動かすか、 という本 #jjug 116/127
  28. Gasbichler, Sperber 「Final Shift for call/cc: Direct Implementation of Shift

    and Reset」, 2002 ◼ Scheme処理系に限定継続を実装したよ、 という論文 ◼ Kinkにおける限定継続の実装は、3節の 「Direct Implementation」に該当する #jjug 120/127
  29. Chambers, Ungar, Lee 「An Efficient Implementation of SELF」, 1991 ◼

    SELF言語の実行系をどうやって高速化 したか ◼ ChromeのJSエンジンであるV8でも参考 にされています: Fast Property Access #jjug 121/127
  30. *1 翻訳系、実行系 次の分け方が普通(中田 (2017)) ◼ 変換系 = Translator ◼ 翻訳系

    = Compiler ◼ 通訳系 = Interpreter 変換は翻訳の亜種/一部と割り切りました 「通訳」は分かりづらい、「インタプリタ」 はソースを直接動かすものと誤解されがち、 ということで「実行系」としました #jjug 123/127