title: CbCによるMoarVMの改良 author: Takahiro Shimizu profile: lang: Japanese # 研究目的 - Perl5の後継言語として開発されているPerl6はMoarVMと呼ばれるVMを搭載している. - Perl6はMoarVM,JVM,JavaScript上で動くRakudoと呼ばれる実装と,コンパイラ開発者用のサブセットであるNQPが主な実装となっている. - 現在Perl6及びMoarVMは全体的な速度がPerl5と比較し低下しており,実務として利用できるレベルに達していない. - さらにPerl6の実装自体巨大なcase-switch文など見通しが悪くなっている. - この問題を解決するために現在当研究室で開発している継続を中心にしたContinuation based Cを用いて改良を行う - CbCの設計理念からVMの実装と親和性が高い事も推測できる為,実際にCbCを用いてどのようにVMが実装できるかを検証する # 今週の進捗 - MoarVMのJITのドキュメントを読み始めました # MoarVMのJIT * [Docs](https://github.com/MoarVM/MoarVM/tree/master/docs)を見る * JitCompiler overview * Expression 'Tree' Intermedite Representation * Runtime Configuration * JIT Todo # Lego * MoarMVのJITはLegoと呼ばれているらしい # DynASM * Dynamic Assemler * http://luajit.org/dynasm.html * [luajit](http://luajit.org/)プロジェクトで作られているもの * MoarVMには `3rdparty`ディレクトリ以下に展開されている * x86アーキテクチャのJITコンパイル用のアセンブラのようなものらしい * luaが`dasc`と呼ばれるCに近いアセンブラをCを出力する前に実行 * Cのヘッダーの `#include` している部分を機械語にランタイムで翻訳 * [GitHubのcommit](https://github.com/MoarVM/MoarVM/commit/372d0582ab90d4ddfc43553bbebe4e553a42278d) # DynASM - To get you started, here is a simple code snippet to be pre-processed. The lines starting with '|' (the pipe symbol) are for DynASM: ``` if (ptr != NULL) { | mov eax, foo+17 | mov edx, [eax+esi*2+0x20] | add ebx, [ecx+bar(ptr, 9)] } ``` - After pre-processing you get: ``` if (ptr != NULL) { dasm_put(Dst, 123, foo+17, bar(ptr, 9)); } ``` # Expression Tree - まだ翻訳出来てない... ## syntax - `(` と`)`で括っていくLISPスタイル - wordはPerlの正規表現 `[^\s\(\)#:"']`で表現されるもの - keywordは `:` が途中につく - 先頭に`$`が来るとリファレンスであり,MoarVMのオペランドもしくは宣言済みの変数 - `^`が先頭に来るとマクロであり,`macro:`で宣言可能 - 先頭に`&`だと関数のマクロ ``` (template: sp_p6oget_o (let: (($val (load (add (^p6obody $1) $2) ptr_sz))) (if (nz $val) $val (^vmnull)))) ``` # Instruction Selection * シーケンスを実際にx86に変換する部分 * [Aho etal](https://dl.acm.org/citation.cfm?id=75700)の論文が基本となっているらしい # 書き換え - `spesh/facts.c`を書き換えていこうかなとしています - case文で分岐した後の返り値をstackにどうやって積むかが問題 - 遷移を担当するテーブルの設計 # 書き換え地点 ``` case MVM_OP_const_i64_32: case MVM_OP_const_i64_16: case MVM_OP_const_s: literal_facts(tc, g, ins); //XXX 書き換え goto literal_facts_cbc(tc,g,ins,__return); goto literal_facts(tc, g, ins); break; ``` # target ``` __code literal_facts_cbc(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshIns *ins,__code(*exit)()) { MVMSpeshFacts *tgt_facts = &g->facts[ins->operands[0].reg.orig][ins->operands[0].reg.i]; switch (ins->info->opcode) { case MVM_OP_const_i64: tgt_facts->value.i = ins->operands[1].lit_i64; break; case MVM_OP_const_i32: tgt_facts->value.i = ins->operands[1].lit_i32; break; case MVM_OP_const_i16: tgt_facts->value.i = ins->operands[1].lit_i16; break; case MVM_OP_const_i8: tgt_facts->value.i = ins->operands[1].lit_i8; break; case MVM_OP_const_n32: tgt_facts->value.n = ins->operands[1].lit_n32; break; case MVM_OP_const_n64: tgt_facts->value.n = ins->operands[1].lit_n64; break; case MVM_OP_const_i64_32: tgt_facts->value.i = ins->operands[1].lit_i32; break; case MVM_OP_const_i64_16: tgt_facts->value.i = ins->operands[1].lit_i16; break; case MVM_OP_const_s: tgt_facts->value.s = MVM_cu_string(tc, g->sf->body.cu, ins->operands[1].lit_str_idx); break; default: return; } tgt_facts->flags |= MVM_SPESH_FACT_KNOWN_VALUE; goto (*exit1)(); } ``` # 来週の予定 * JITもう少し読む * JITから書き換える?