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

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

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

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

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

5e8c7a93f4cd63b62ced5dd347f1a8e0?s=128

Miyakawa Taku

February 27, 2019
Tweet

Transcript

  1. JVM言語の動き方・動かし方 2019-02-27 JJUGナイトセミナー ハッシュタグ: #jjug 宮川 拓

  2. ⚫ @miyakawa_taku ⚫ JJUG幹事です ⚫ Salesforceで働いてます ⚫ 奄美出身の力士を応援しています☆ ⚫ オレオレJVM言語Kinkを作っています

    http://doc.kink-lang.org/ 自己紹介 #jjug 2/127
  3. 背景 Graal+Truffleは素敵みたい Graal+Truffleの素敵さを納得するため、 言語処理系のかんどころを分かっときたい #jjug 3/127

  4. 演目 言語処理系の構成 コンピュータはどのように プログラムを動かすのか JVMはどのように プログラムを動かすのか JVM言語処理系の構成: Kinkを題材に #jjug 4/127

  5. 演目 言語処理系の構成 コンピュータはどのように プログラムを動かすのか JVMはどのように プログラムを動かすのか JVM言語処理系の構成: Kinkを題材に #jjug 5/127

  6. そもそも 「言語処理系」ってなに? #jjug 6/127

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

    南無阿弥陀仏 この間に必要なソフトウェア一式を 「言語処理系」と呼ぶことにする #jjug 7/127
  8. 言語処理系の二段階 翻訳系 *1 実行系 *1 書かれたプログラム 実行に適した表現: 機械語 or バイトコード

    or ... 実行に適した表現 を コンピュータ上で 実行 #jjug 8/127
  9. 翻訳系 ここはザックリ行きます #jjug 9/127

  10. 翻訳系 書かれたプログラム 実行に適した表現: 機械語 or バイトコード or ... つまりコンパイラ #jjug

    10/127
  11. 翻訳系の中身 書かれたプログラム トークン列 抽象構文木 (AST) 実行に適した表現 字句解析 構文解析 シンボル解決, 型検査,

    最適化,,, " く り か え し ", " 三 回 ", " : ", , , (loop 3 (call (var "念仏") "唱える")) #jjug 11/127
  12. つまり翻訳系は多段階のデータ変換処理 プログラマの多くは、似たような処理を 作った経験があるはず #jjug 12/127

  13. データ投入バッチ タブ区切りテキスト トークン列 抽象構文木 (AST) データベース 字句解析 構文解析 マスタ突合, バリデーション,,,

    "中島敦", "悟浄歎異", 1942, 改行,,, [{"author": "中島敦", "title": "悟浄歎異", "year": 1942},,,] 中島敦 悟浄歎異 1942 深沢七郎 風流夢譚 1960 ,,, やってることは翻訳系と同じ! #jjug 13/127
  14. 翻訳系でやっていることは、 とても馴染み深いデータ変換処理 ただし、型検査や最適化などは、それぞれが 一大トピック #jjug 14/127

  15. 実行系 こっちが今日のメイン #jjug 15/127

  16. 実行系 実行に適した表現 を コンピュータ上で 実行 #jjug 16/127

  17. 誰が実行する? 実行対象 実行の担い手 機械語の プログラム CPUとOS つまりコンピュータそのもの 機械語以外: バイトコード、 木構造など

    実行系のプログラム: JVM, V8, YARVなど コンピュータの真似をする “Java Virtual Machine”! #jjug 17/127
  18. ここから先は、 ◼ コンピュータがどのように プログラムを動かすのか ◼ JVMやJVM言語処理系が、どのように コンピュータを真似するのか を見ていきます #jjug 18/127

  19. 演目 言語処理系の構成 コンピュータはどのように プログラムを動かすのか JVMはどのように プログラムを動かすのか JVM言語処理系の構成: Kinkを題材に #jjug 19/127

  20. サンプルプログラム N = M + 42 ld x5, &M addi

    x6, x5, 42 sd x6, &N 書かれた プログラム RISC-Vの 機械語 プログラム x5, x6: レジスタ &M, &N: 変数の番地 #jjug 20/127
  21. OSの仕事: ローダ #jjug 21/127

  22. OS(ローダ)の仕事 1/2 プログラムが使う仮想アドレス空間を確保 機械語命令列の領域 グローバル変数の領域 100番地 200番地 #jjug 22/127

  23. OS(ローダ)の仕事 2/2 プログラムをアドレス空間にロード *2 #jjug ld x5, &M addi x6,

    x5, 42 sd x6, &N ... M N ... 100番地 200番地 204番地 23/127
  24. CPUの仕事: 計算 #jjug 24/127

  25. CPU CPUの概念図 *3 レ ジ ス タ 群 演 算

    装 置 ( ALU ) メ モ リ デ ー タ 用 ポ ー ト 命 令 用 ポ ー ト Program Counter +4 番 地 命 令 番 地 入 力 演 算 結 果 デ ー タ 次 の 命 令 へ レ ジ ス タ : 計 算 に 使 う 数 値 を 置 い て お く 場 所 Program Counter ( PC ) : 実 行 す る 命 令 の 番 地 を 表 す 特 殊 な レ ジ ス タ 演 算 装 置 ( ALU ) : 加 算 器 と か 除 算 器 と か の 回 路 の か た ま り #jjug 25/127
  26. 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
  27. 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
  28. 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
  29. CPUの仕事: 手続き呼び出し #jjug 29/127

  30. 手続き呼び出し 高度なプログラムでは、手続きの呼び出しに よって処理があちこちにジャンプする foo { ... bar() ... } bar

    { ... return; } call return #jjug 30/127
  31. 手続きbarを呼び出す jal x1, &bar jal命令は次の2つを実行する 1. PC+4をx1に入れる ⚫ PC+4は、jal命令の次の命令の番地 ⚫

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

    ⚫ つまりここでは、PC+4は捨てられる 2. PCにx1を入れる ⚫ x1には、呼び出し元で設定された 戻り番地が入っている ⚫ つまり、呼び出し元にジャンプ=returnする 32/127
  33. OSの仕事: スタックの確保 #jjug 33/127

  34. 呼び出し先でレジスタの値が変えられると、 元の処理が続けられないので困る 呼び出し前後で、レジスタの元の値を 退避しておく領域が必要 → これがスタック領域 #jjug 34/127

  35. スタックの確保 スレッドXの スタック OSはスレッドごとにスタックを確保する #jjug スレッドYの スタック スレッドZの スタック 35/127

  36. スタックの中身 fooの フレーム barの フレーム callしたら呼び出しの作業領域として 「フレーム」を確保する returnしたらフレームを捨てる #jjug スタックの中身のやりくりはプログラムの責任

    36/127
  37. OSの仕事: 動的メモリ確保 #jjug 37/127

  38. 動的メモリ確保 OSは実行中のプログラムの要求に応じて、 仮想アドレス空間を動的に割り当てる #jjug 38/127

  39. 小まとめ: コンピュータはどのように プログラムを動かすのか #jjug 39/127

  40. プログラムを動かすためにコンピュータは ◼ プログラムのロード ◼ 計算 ◼ 手続き呼び出し&スタック管理 ◼ 動的メモリ確保 などを行います

    #jjug 40/127
  41. 演目 言語処理系の構成 コンピュータはどのように プログラムを動かすのか JVMはどのように プログラムを動かすのか JVM言語処理系の構成: Kinkを題材に #jjug 41/127

  42. Java処理系の二段階 翻訳系: javac 実行系: JVM Javaソースコード Javaバイトコード Javaバイトコード を コンピュータ上で

    実行 #jjug 42/127
  43. 実行系はコンピュータの真似をする でも、まったく同じことをする必要はない! ◼ 抽象度の高い枠組みを提供しても良い ◼ コンピュータの機能が使えるのであれば、 そのまま使えば良い ◆ 加算器の回路をシミュレートするより、 add命令を使う方が良い

    #jjug 43/127
  44. コンピュータ, JVM, WebAssemblyの比較 #jjug 44/127

  45. WebAssembly 各種言語をブラウザ上で動かすための実行系 の仕様 JVMと位置づけは似ているが、 構成はかなり異なる #jjug 45/127

  46. オブジェクトシステム コンピュータ WebAssembly JVM オブジェクトシステムは 存在しない Javaクラス&インスタンス #jjug 46/127

  47. メモリ管理 コンピュータ WebAssembly JVM フラットなアドレス領域を 割り当て GCは存在しない オブジェクトの生成を管理 参照関係を追跡して、 不要なオブジェクトをGC

    #jjug 47/127
  48. 手続きの呼び出し コンピュータ WebAssembly JVM アドレスへのジャンプ クラスの仮想関数テーブルを ルックアップ&ジャンプ またはinvokedynamicで 実行時に呼び出し方法を規定 #jjug

    48/127
  49. スタック コンピュータ WebAssembly JVM 他の呼び出しのフレームも 読み書き可能 現在の呼び出しの フレーム以外は 読み書きできない #jjug

    49/127
  50. 計算 コンピュータ WebAssembly JVM PC, ALU, レジスタ, ... 仕様は項書換え系 実装は様々

    バイトコードインタプリタ &JITコンパイラ 計算にはさまざまな実現方法がある #jjug 50/127
  51. 計算: 項書換え系 #jjug 51/127

  52. 項書換え系 ルールに従って項(式の一部)を書き換える (1+2) * 3 3 * 3 9 項書換え系ですべてのプログラムが表せる!

    → ラムダ計算、SKIコンビネータ計算 #jjug 52/127
  53. 項書換え系 利点 ◼ データと演算をひとまとめにするので 理論的に扱いやすい ◼ 数学っぽくてかっこいい 欠点 ◼ 素直に実装すると遅い

    #jjug 53/127
  54. 計算: Metacircular Interpreter #jjug 54/127

  55. Meta-circular Interpreter ASTやそれに類する木構造を再帰的に 手繰って計算を適用する 「ASTを直接評価」という場合はこれのこと #jjug 55/127

  56. Meta-circular Interpreter 利点 ◼ ホスト言語(実行系を記述する言語)の 制御構造が使えるため、実装が楽 欠点 ◼ ホスト言語の制御構造に制約される #jjug

    56/127
  57. 計算: バイトコードインタプリタ #jjug 57/127

  58. バイトコードインタプリタ 命令列の実行をホスト言語上でエミュレート 命令の抽象度は機械語よりも高い ◼ JVMの場合: ◆ new命令: インスタンスを生成 ◆ getfield命令:

    オブジェクトから フィールドの値を取得 #jjug 58/127
  59. バイトコードインタプリタ 実装のイメージ 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
  60. バイトコードインタプリタ 利点 ◼ Javaの場合、クラスファイルの内容が 直接実行できる ◼ スタックを自前で管理する場合、 ホスト言語の制御構造ではできないこと も実現できる 欠点

    ◼ コンピュータよりは遅い #jjug 60/127
  61. 計算?: JITコンパイラ #jjug 61/127

  62. JITコンパイラ 実行系に内蔵された翻訳系のプログラム JVM バイトコード インタプリタ Javaバイトコード を コンピュータ上で 実行 JITコンパイラ

    *4 Javaバイトコード 機械語の命令列 #jjug 62/127
  63. JITコンパイラ 実行系の実行時に ◼ 機械語の命令列を生成して ◼ コード領域を動的確保して ◼ コード領域に機械語命令列を書き込んで ◼ CPUに実行させる!

    #jjug 63/127
  64. JITコンパイラ 利点 ◼ 生成されたコードの実行は速い 欠点 ◼ JITコンパイラの実行自体は重い → よく使われる所だけを対象とする #jjug

    64/127
  65. 小まとめ: JVMはどのように プログラムを動かすのか #jjug 65/127

  66. JVMはコンピュータよりも抽象度の高い 枠組みを提供している ◼ オブジェクトシステム ◼ GC ◼ 仮想関数テーブル経由の呼び出し ◼ スタックフレームの保護

    JVMの計算はバイトコードインタプリタと JITコンパイラの組み合わせで実現される #jjug 66/127
  67. 演目 言語処理系の構成 コンピュータはどのように プログラムを動かすのか JVMはどのように プログラムを動かすのか JVM言語処理系の構成: Kinkを題材に #jjug 67/127

  68. そもそも JVM言語処理系ってなに? #jjug 68/127

  69. JVM言語処理系 本セッションでは ◼ 実行系がJVM上で動く言語処理系、 ◼ または実行系がJVMそのものである 言語処理系、 ◼ ただしJava以外のもの としておきます

    #jjug 69/127
  70. #jjug JVM言語処理系 Scala, Kotlin, Groovy, JRuby, Jython, Clojure, Kawa, Frege,

    Eta, BeanShell, Pnuts, ... and Kink! 70/127
  71. なぜJVM上で 処理系を作るの? #jjug 71/127

  72. #jjug GC JVMにGCが任せられる マルチスレッドの処理系で実用的に動く GCを作ることは、とてもむずかしい ◼ CRubyやCPythonは、各スレッドを 排他的に動かして問題を回避している (Global Interpreter

    Lock) ◼ Luaの処理系は単一スレッドで動く 72/127
  73. #jjug 移植性 つくった処理系がWindowsでもLinuxでも macOSでも動くのは嬉しい 73/127

  74. #jjug 性能 プログラムをJavaバイトコードに翻訳する 場合、JITコンパイルのおかげで速い 74/127

  75. #jjug Java API リッチなJava APIが使える リフレクションのおかげで、 JVM言語の側からJava APIを操作することも 簡単 75/127

  76. JVM言語処理系の構成 #jjug 76/127

  77. 基本的な考え方 JVMの性能面の利点を活かすため、 JVMの仕組みをできればそのまま使いたい そのまま使えない場合は ◼ JVMの仕組みとのマッピングを頑張るか、 ◆ invokedynamicはこれを楽にする命令 ◼ それも難しい場合は自前の仕組みを作る

    #jjug 77/127
  78. JVM言語処理系の構成の傾向 Scala Kotlin Groovy JRuby Kink 実行系が JVMそのもの 実行系に 自前の要素が多い

    #jjug 78/127
  79. ここから先はKink処理系の実装の中で、 JVMの仕組みのどの部分が ◼ 使えるか ◼ 使えないか ◼ 使える可能性があるか を見ていきます #jjug

    79/127
  80. Kinkとその処理系 #jjug 80/127

  81. 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
  82. Kinkの処理系 kinkコマンド 翻訳系 実行系 Qcode Kinkソースコード Qcode: 自前のバイトコード を Javaで実装された

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

    最適化 木構造の中間表現 フラットな中間表現 #jjug 83/127
  84. Kinkの処理系: 実行系 オブジェクト システム メモリ管理 計算 スタック 自前 継承のないオブジェクトシステム JVMのGCに依存

    自前のバイトコードインタプリタ 自前のスタック管理 #jjug 84/127
  85. Kink: オブジェクトシステムと メモリ管理 #jjug 85/127

  86. Kinkは継承のないオブジェクトシステムを 採用しています 最初のオブジェクト指向言語である Simula Iと同様! #jjug 86/127

  87. クラスベースの継承 値 データ X データ Y クラス 親クラス メソッド a

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

    メソッド a メソッド b メソッド b メソッド c delegate-to delegate-to 例: ⚫ JavaScript ⚫ SELF ⚫ Io ※ Luaは変わり種 #jjug 88/127
  89. delegate-to関係、必要? 半端な値としての「プロトタイプ」の 存在が気持ち悪い 言語仕様に現れるべきものじゃなくない? 処理系の実装が裏で頑張ればよくない? #jjug 89/127

  90. Kinkのオブジェクトシステム 値 データ X データ Y メソッド a メソッド b

    メソッド c #jjug 90/127
  91. #jjug 値をつくる 単にnew_val関数を呼び出して値を作る # 色 new_val( 'R' 64 'G' 128

    'B' 255 ) 91/127
  92. #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
  93. #jjug トレイトを使う トレイトはnew_val関数の引数として 展開して使う new_val( # 色のトレイトを展開 ... Color_trait 'R'

    64 'G' 128 'B' 255 ) 93/127
  94. 意味は下記と同じ #jjug new_val( # トレイトが展開された結果 'lightness' { 省略 } '_max'

    { 省略 } '_min' { 省略 } 'R' 64 'G' 128 'B' 255 ) このとおり実装すると無駄が多いので、 そこは実行系が工夫する 94/127
  95. どう実装する? Javaのクラスベースのオブジェクトシステム へのマッピングはしんどい → 自前実装 #jjug 95/127

  96. オブジェクトシステムの実装 Kinkの値: Valクラス commonVarMapping traitVarMapping ownVarMapping 全ての値に共通の フィールド群(不変): k1→v1, k2→v2,,,

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

    k1→v1, k2→v2,,, 値同士の参照関係はJavaオブジェクトの参照関係に マッピングされている → メモリ管理はJavaのGCに丸投げできる #jjug 97/127
  98. Kink: 計算とスタック管理 #jjug 98/127

  99. Kinkは限定継続を使って 例外やコルーチンを実現しています #jjug 99/127

  100. 限定継続とは スタックを切り貼りする仕組み Kinkではreset関数とshift関数の組み合わせで 限定継続を操作 #jjug 100/127

  101. reset & shift: 継続の保存 reset: スタック上にタグを打つ tag resetブロック内の処理 tag shift:

    タグまでの切片を関数(=継続)に保存 tag tag kont = #jjug 101/127
  102. 継続は呼び出せる kont(Val): 継続の呼び出し: 継続に保存されたスタック切片を貼り付ける よその処理 tag #jjug 102/127

  103. スタックをどう実装する? JVMのスタックをそのまま使うのは難しい ◼ JVMにはスタックをプログラムから 操作する方法がない ※ でも世の中には無茶する人がいる ※ Quasarライブラリは例外とバイト コード変換で無理矢理操作

    ※ Project Loomで状況が変わるかも → Kinkは自前のスタックを実装 #jjug 103/127
  104. 計算をどう実装する? KinkプログラムをJavaバイトコードに 翻訳するのは苦労が多そう ◼ 自前のオブジェクトシステム ◆ putfield/getfield命令が使えない ◼ 自前の呼び出しスタック ◆

    invoke*命令が使えない → 自前のバイトコードインタプリタ #jjug 104/127
  105. Kink: 性能 #jjug 105/127

  106. ベンチマーク: たらいまわし関数 #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
  107. #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
  108. プロファイリング #jjug 紫色の部分がスタック操作 バイトコードインタプリタと合わせて、4割~を占める → 自前実行系の限界? 108/127

  109. 性能改善の余地 計算をJVMにプッシュバックすれば 性能改善が期待できる、かも ◼ JRuby方式: ◆ 自前バイトコードから JavaバイトコードへのJITコンパイル ◆ 最も実行される部分は、さらにJVMが

    機械語にJITコンパイルする ◼ Graal+Truffleに期待できる? #jjug 109/127
  110. まとめ #jjug 110/127

  111. JVM言語処理系の構成にはさまざまな バリエーションがある JVMの仕組みがそのまま使えると嬉しい ◼ GC: 自前で作るのは大変! ◼ JITコンパイラ: 計算が速くなる JVMの仕組みへのマッピングはときに大変

    #jjug 111/127
  112. 演目 言語処理系の構成 コンピュータはどのように プログラムを動かすのか JVMはどのように プログラムを動かすのか JVM言語処理系の構成: Kinkを題材に #jjug 112/127

  113. 参考文献 #jjug 113/127

  114. 中田育夫 『コンパイラ: つくりながら学ぶ』, 2017 ◼ コンパイラと実行系をつくる ◼ 易しくて良い本 #jjug 114/127

  115. Abelson, Sussman, Sussman 『Structure and Interpretation of Computer Programs』, 1996

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

    いわゆる「パタヘネ」 ◆ 「ヘネパタ」は別書なので注意! ◼ CPUがプログラムをどうやって動かすか、 という本 #jjug 116/127
  117. Pierce『型システム入門』, 訳書2013 ◼ いわゆる「TAPL」 ◼ 型システムの教科書 ◼ 序盤の3章~7章が特にオススメ ◆ 型を導入する準備として、型のない

    項書換え系が解説されている ◆ 型なしラムダ計算はこれでバッチリ! #jjug 117/127
  118. 中田育夫 『コンパイラの構成と最適化』, 2版, 2009 ◼ 主に最適化の本 ◼ むずかしい #jjug 118/127

  119. 浅井健一 「shift/resetプログラミング入門」, 2011 ◼ 限定継続を紹介する文書 #jjug 119/127

  120. Gasbichler, Sperber 「Final Shift for call/cc: Direct Implementation of Shift

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

    SELF言語の実行系をどうやって高速化 したか ◼ ChromeのJSエンジンであるV8でも参考 にされています: Fast Property Access #jjug 121/127
  122. 脚注 #jjug 122/127

  123. *1 翻訳系、実行系 次の分け方が普通(中田 (2017)) ◼ 変換系 = Translator ◼ 翻訳系

    = Compiler ◼ 通訳系 = Interpreter 変換は翻訳の亜種/一部と割り切りました 「通訳」は分かりづらい、「インタプリタ」 はソースを直接動かすものと誤解されがち、 ということで「実行系」としました #jjug 123/127
  124. *2 プログラムをロード 実際は、プログラムの実行ファイルを、 プロセスの仮想アドレス空間にメモリマップ します ◼ @akachochin 「Linuxのユーザプロセスのメモリマッ プについて」, 2017

    #jjug 124/127
  125. *3 CPUの概念図 Patterson, Hennessy (2017) のFigure 4.11を 参考にしました #jjug 125/127

  126. *4 JITコンパイラ Graalの場合、JITコンパイラの入力は Javaバイトコードに限りません #jjug 126/127

  127. *5 Kinkの翻訳系 ソース: FunHelper#compile #jjug 127/127