YAPC::Tokyo前夜祭でのLTです
NQPMoarVM八雲アナグラ @AnaTofuZ YAPC::Tokyo 2019 前夜祭
View Slide
my $self = shift;• 八雲アナグラ ( id:AnaTofuZ )• Okinawa.pm と Perl入学式in沖縄から来ました• 本業は沖縄の大学生 (4年次) (出身は沖縄で無いので詐欺と呼ばれる) • 今日飲みすぎて明日トークできない気がする
Perl6 ?• 明日もいっぱいトークされるPerl6• MoarVMやJVMやJSで動くRakudoが現在の実装が主流です
Perl6• 突然ですが, Perl6 (Rakudo)はどの様に プログラムされているのでしょうか • MoarVMで動くことは知っていても, Perl6自体何でプログラミングされているか あまり情報がない様な…• 皆さんが愛用しているPerl5はCで記述されています
Perl6 ?• ではPerl6もC…?
• ではPerl6もC…?➡ MoarVMはCですが,Perl6自体はCではないのです…Perl6 ?
• ではPerl6もC…?➡ MoarVMはCですが,Perl6自体はCではないのです… • Perl6はPerl6自身で記述されていますPerl6 ?
• ではPerl6もC…?➡ MoarVMはCですが,Perl6自体はCではないのです… △Perl6はPerl6自身で記述されていますPerl6 ?
• ではPerl6もC…?➡ MoarVMはCですが,Perl6自体はCではないのです…△Perl6はPerl6自身で記述されています• Perl6はNQPというPerl6のサブセットで記述されていますPerl6 ?
NQP• NQPとはNotQuitPerlの略で, Perlっぽい言語• NQPはNQP自体で記述されており, Rakudoをいれると同時に入る• 基本的にはPerl6と同じ文法だが,制約がある. しかし結構機能が揃っている(hash/array/class, twisigil…)• もともとはPerl6主力実装がParrot時代に登場したが 文法がアップデートされており, Parrot時代の解説は古い
NQP• 変数宣言はPerl5/Perl6と同じmyで行う.安心• 代入ではなく,束縛 “ :=“ しか使えない.• $i++はできないが,++$i; は出来る#!/usr/bin/env nqpmy $hoge := "Hello";my $foo := 2018;++$foo;say($foo);
NQP• 再帰呼び出し的なフィボナッチ#! nqpsub fib($n) {$n < 2 ?? $n !! fib($n-1) + fib($n - 2);}my $N := 29;my $z := fib($N);say("fib($N) = " ~ fib($N));
nsub add_test($n) {my $sum := 0;while ($n > 1) {$sum := $sum + $n;--$n;}return $sum;}say(add_test(10000));
NQP• NQPはNQPオペコードというMoarVMのバイトコードに (ほぼ)一対一で対応する処理を使う事ができる• popなどの配列操作はオペコードを利用することで可能となる• NQPオペコードは, Perl6が抽象構文木にも使用されている• MoarVMとJVMの間では実装状況が異なる (基本はMoarVMのほうがいろいろ実装されている)
n• オペコード+型を指定してみるsub add_test (int $n) {my int $sum := 0;while nqp::isgt_i($n,1) {$sum := nqp::add_i($sum,$n);$n := nqp::sub_i($n,1);}return $sum;}say(add_test(10000));
NQP• Perl6は斬新的型月言語であり, NQPも型を持つ• 変数に型を指定することや, 利用するNQPオペコードに 型を指定することが可能• 実行するコードによっては型を指定すると高速に動くケースも存在する
NQP• 引数や数に型を指定することが可能#! nqpsub fib(int $n) {$n < 2 ?? $n !! fib($n-1) + fib($n - 2);}my int $N := 29;my $z := fib($N);say("fib($N) = " ~ fib($N));
NQP MoarVM• NQPはMoarVM上で実行される• NQPからMoarVMバイトコードにコンパイルする事が可能 (直接実行したい場合は工夫が必要)• バイトコードはMoarVMでMoarVMが実行する命令を書いた アセンブリのようにダンプする事が可能$nqp --target=mbc --output=fib.moarvm fib.nqp$moar --dump fibtype.moarvm
NQP MoarVM• 2引数を受け取って足すだけのコード2種類で書いてみるsub add_test($left,$right) {return $left + $right;}say(add_test(2000,19)); sub add_test(int $left,int $right) {return nqp::add_i($left,$right);}my int $n := 2000;my int $m := 19;say(add_test($n,$m));
name : add_testInstructions :00000 checkarity 2, 200001 param_rp_o loc_0_obj, 000002 param_rp_o loc_1_obj, 100003 paramnamesusedannotation: add.nqp:100004 decont loc_4_obj, loc_0_obj00005 smrt_numify loc_3_num, loc_4_obj00006 decont loc_4_obj, loc_1_obj00007 smrt_numify loc_5_num, loc_4_obj00008 add_n loc_5_num, loc_3_num, loc_5_num00009 hllboxtype_n loc_4_obj00010 box_n loc_4_obj, loc_5_num, loc_4_obj00011 throwpayloadlex loc_4_obj, 32, loc_4_obj00012 goto label_1(00015)
name : add_test Instructions :00000 checkarity 2, 200001 param_rp_i loc_0_int, 000002 param_rp_i loc_1_int, 100003 paramnamesusedannotation: addtype2.nqp:100004 add_i loc_3_int, loc_0_int,loc_1_int00005 hllboxtype_i loc_4_obj00006 box_i loc_4_obj, loc_3_int,loc_4_obj00007 throwpayloadlex loc_4_obj, 32,• 型が有ると実行が早くなる事も
MoarVM• MoarVMバイトコードはMoarVMが頑張って実行する• 以前はバイトコードがある分だけfor + switch/case文で ループしつつバイトコードに対応する命令を実行していた• ループとswitchは遅いので最近はCのラベルに対してgotoするやり方で実行されている(ちょっと速くなった)• id:anatofuzがこの辺を卒研で独自にいろいろしている
MoarVMBEE@JόΠτίʔυDVS@PQ όΠτίʔυBEE@JϨδελू߹cͷϥϕϧBEE@J <>൪
MoarVM όΠτίʔυDVS@PQ όΠτίʔυBEE@JϨδελू߹cͷϥϕϧBEE@J <>൪
MoarVMBEE@J <>൪ όΠτίʔυDVS@PQ όΠτίʔυBEE@JϨδελू߹cͷϥϕϧgoto
MoarVM όΠτίʔυDVS@PQ όΠτίʔυBEE@JϨδελू߹ <>൪cͷϥϕϧgotoBEE@J <>൪
MoarVM όΠτίʔυDVS@PQ όΠτίʔυBEE@JϨδελू߹cͷϥϕϧgotoBEE@J <>൪
NQP• NQPのリポジトリにいくつか入っています• rubyish(NQPで作成されたRubyエミュレーター)• NQPそのもの• Rakudo
NQP• 文献が日本語/英語ともに少ない(Perl6はそこそこあるけど…)• 実装はしたがドキュメントに乗っていないオペコードも存在 (issueに「このオペコードのドキュメント書いて!」「わからん」などのやり取りがある)• Perl6の文法を取り入れているので,Perl6を知らないと 所々読めない文法が存在する (Twigilなどが使える)• 仕様は今後も変わる可能性がある• 関数と()の間に空白をいれると死ぬ• REPLが変数を保存しない(1行に全部書く必要がある)
NQPͰHappyPerl6Hack!!