Mercurial > hg > Events > OSC2019
changeset 11:70bdd820b91d
merge
author | anatofuz <anatofuz@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 19 Apr 2019 18:53:36 +0900 |
parents | 4b1eb4d69695 (diff) 7fd82a802a66 (current diff) |
children | 58cd4dd86896 |
files | |
diffstat | 3 files changed, 1038 insertions(+), 119 deletions(-) [+] |
line wrap: on
line diff
--- a/slide.html Fri Apr 19 18:23:10 2019 +0900 +++ b/slide.html Fri Apr 19 18:53:36 2019 +0900 @@ -105,13 +105,37 @@ <div class='slide'> <!-- _S9SLIDE_ --> +<h2 id="内容">内容</h2> +<ul> + <li>Perl6とは?</li> + <li>スクリプト言語処理系の動き</li> + <li>Perl6の内部構造 + <ul> + <li>NQP</li> + <li>MoarVM</li> + </ul> + </li> + <li>MoarVMのバイトコード実行</li> + <li>まとめ</li> +</ul> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> <h2 id="perl6とは">Perl6とは</h2> <ul> - <li>当初Perl5の時期バージョンとして開発されていたプログラミング言語</li> + <li>当初Perl5の時期バージョンとして開発されていたプログラミング言語 + <ul> + <li>現在は別の言語として開発がそれぞれ進んでいる</li> + </ul> + </li> <li>仕様と実装が分離しており, 現在はテストが仕様となっている</li> - <li>実装は複数存在しているが,現在主流な実装はRakudoとなっている</li> - <li>言語的にはスクリプト言語であり, 漸進的型付き言語となっている</li> - <li>MoarVM, JVMで動作する</li> + <li>実装は歴史上複数存在しているが,主流な実装はRakudo</li> + <li>言語的にはスクリプト言語であり, 漸進的型付き言語</li> + <li>動作環境は、独自のVMのMoarVM, JVM、一部JavaScript上で動作する</li> </ul> <p><img src="2000px-Camelia.svg.png" alt="" style="width: 31%; height: auto;" /></p> @@ -122,10 +146,68 @@ <div class='slide'> <!-- _S9SLIDE_ --> +<h2 id="現在のperl6">現在のPerl6</h2> + +<ul> + <li>現在のバージョンは <code>6.d</code></li> + <li><a href="https://perl6.github.io/6pad/">ブラウザ上で実行可能な環境</a>が存在する</li> + <li><a href="https://commaide.com/">IDE</a>が開発されている</li> + <li>WebApplicationFrameworkなども開発されており、 Perl5のモジュールを移行したものがいくつか存在する</li> + <li>日本では趣味のプロダクト以外社会では使用されていない + <ul> + <li>海外では実際に使われているケースも存在する</li> + </ul> + </li> + <li>処理速度では一部Perl5に勝っているが、それでも大分遅い</li> +</ul> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="参考perl5のソースコード">[参考]Perl5のソースコード</h2> + +<ul> + <li>Perl5時代 + <ul> + <li>スカラ、配列、ハッシュの3種類</li> + <li>それぞれの変数への参照であるリファレンスが使用可能</li> + </ul> + </li> +</ul> + +<pre><code class="language-perl">use ustrict; +use warnings; + +my $scalar_value = "hello!"; +print "$scalar_value\n"; + +my @array = (1..10); +print "$array[0]\n"; + +my %hash = ( this_is_key => "this_is_value"); +print "$hash{this_is_key}\n"; + +my $hash_ref = \%hash; +print "$hash_ref->{this_is_key}\n"; +</code></pre> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> <h2 id="perl6のソースコード概要">Perl6のソースコード概要</h2> <ul> - <li>Perl5の文法とは比較的変更が多い</li> + <li>Perl5の文法とは比較的変更が多い + <ul> + <li>雰囲気は似ている</li> + </ul> + </li> <li>変数がオブジェクトと化した事により, 変数からsayメソッドを呼ぶことが可能</li> </ul> @@ -194,6 +276,28 @@ fizzbuzz($_).say for 1..15; </code></pre> +<ul> + <li>型を利用したFizzBuzz</li> +</ul> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="スクリプト言語">スクリプト言語</h2> +<ul> + <li>Perl6は現状コンパイルすることはできない + <ul> + <li>スクリプト言語の分類</li> + </ul> + </li> + <li>現在広く使われているスクリプト言語(Perl,Python,Ruby…)などとPerl6の構成は類似している</li> + <li>今回はPerl6の実装を追いながら、最近のスクリプト言語処理系の大まかな実装を理解する</li> +</ul> + + </div> @@ -218,10 +322,43 @@ <div class='slide'> <!-- _S9SLIDE_ --> +<h2 id="perl6以外のスクリプト言語">Perl6以外のスクリプト言語</h2> + +<ul> + <li>現在使われているプロセスVMは言語に組み込まれているものが多い</li> + <li>JVMやElixirなどのVMは複数の言語で使用されている</li> + <li>Java + <ul> + <li>JVM</li> + </ul> + </li> + <li>Ruby + <ul> + <li>YARV</li> + </ul> + </li> + <li>Python + <ul> + <li>PythonVM</li> + </ul> + </li> + <li>Elixir + <ul> + <li>BEAM</li> + </ul> + </li> +</ul> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> <h2 id="perl6の処理系の構成">Perl6の処理系の構成</h2> <ul> - <li>Perl6の処理系は現在はRakudoと呼ばれる(歴史上複数存在する)</li> + <li>Perl6の処理系で現在主流なものはRakudoと呼ばれる実装である(歴史上複数存在する)</li> <li>Rakudoは3つのレイヤーから構成されている <ul> <li>Perl6インタプリタ</li> @@ -229,8 +366,7 @@ <li>Perl6のバイトコードを解釈するMoarVM</li> </ul> </li> - <li>このうちPerl6インタプリタとNQPはNQP自身で記述されている</li> - <li>MoarVMはC言語で記述されている</li> + <li>Perl6/NQPがフロントエンドに相当し、MoarVMがバックエンドに相当する</li> </ul> @@ -239,12 +375,52 @@ <div class='slide'> <!-- _S9SLIDE_ --> +<h2 id="rakudoの構成図">Rakudoの構成図</h2> + +<p><img src="fig/Rakudo_System_overview.png" alt="" /></p> + +<p>(http://brrt-to-the-future.blogspot.com/2015/03/advancing-jit-compiler.html)</p> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> <h2 id="perl6とnqp">Perl6とNQP</h2> <ul> - <li>NQP(NotQuitPerl Perlっぽい別の言語)でRakudoを記述している</li> + <li>NQP(NotQuitPerl Perl) + <ul> + <li>Perl6のサブセット。Perl6っぽい言語</li> + </ul> + </li> + <li>Perl6、 NQP自体がNQPで記述されている</li> <li>NQPもNQPで記述されている為、 セルフビルド(自分自身で自分自身をコンパイルする)を行う</li> <li>NQPはPerl6の文法をベースにしているが、 制約がいくつか存在する</li> + <li>元々はPerl6の主力実装がParrotだった時代に登場 + <ul> + <li>文法がアップデートされており、当時の資料は古くなっている</li> + </ul> + </li> +</ul> + +<pre><code>my $value := "hello!"; +say($value); +</code></pre> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="nqpスクリプト">NQPスクリプト</h2> + +<ul> + <li>変数は束縛 <code>:=</code> を使う</li> + <li>関数の間に空白を入れてはいけない</li> + <li>再帰呼び出しを使うフィボナッチ数列</li> </ul> <pre><code>#! nqp @@ -254,12 +430,29 @@ my $N := 29; -my $t0 := nqp::time_n(); my $z := fib($N); -my $t1 := nqp::time_n(); nqp::say("fib($N) = " ~ fib($N)); -nqp::say("time = " ~ ($t1-$t0)); +</code></pre> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="nqpスクリプトnまでの整数の和">NQPスクリプト(nまでの整数の和)</h2> + +<pre><code class="language-perl6">sub add_test($n){ + my $sum := 0; + while ( $n > 1) { + $sum := $sum + $n; + --$n; + } + return $sum; +} + +say(add_test(10000)); </code></pre> @@ -268,37 +461,37 @@ <div class='slide'> <!-- _S9SLIDE_ --> -<h2 id="プログラミング言語とvm">プログラミング言語とVM</h2> +<h2 id="nqp">NQP</h2> + <ul> - <li>最近のスクリプト言語は、 ソースコードを直接解釈せず、バイトコードに変換しVMが評価する - <ul> - <li>全体的な処理速度の向上の為</li> - <li>実装を分離することでの見通しの良さ</li> - </ul> - </li> - <li>言語処理系の実行にのみ動作するVM(プロセスVM)</li> - <li>他言語の環境 + <li>NQPはPerl6の中で一番レイヤーが低い言語</li> + <li>その為、 実行するVMのオペコード(処理単位)を使用することができる</li> + <li>NQPオペコードは、 Perl6の内部の抽象構文木でも使用されている</li> + <li>また、 Perl6と同様に型を指定することが可能</li> +</ul> + +<pre><code class="language-perl6">sub add_test(int $n){ + mu $sum := 0; + while nqp::isgt_i($n,1) { + $sum := nqp::add_i($sum,$n); + $n := nqp::sub_i($n,1); + } + return $sum; +} +</code></pre> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="nqpとmoarvm">NQPとMoarVM</h2> +<ul> + <li>NQPそのものは実行することはできない</li> + <li>NQPの実行にはMoarVM/JVMが必要となる <ul> - <li>Java - <ul> - <li>JVM</li> - </ul> - </li> - <li>Ruby - <ul> - <li>YARV</li> - </ul> - </li> - <li>Python - <ul> - <li>PythonVM</li> - </ul> - </li> - <li>Elixir - <ul> - <li>BEAM</li> - </ul> - </li> + <li>NQPコンパイラが各VMに対応したバイトコードに変換する</li> </ul> </li> </ul> @@ -309,13 +502,29 @@ <div class='slide'> <!-- _S9SLIDE_ --> -<h2 id="perl6のvmの構成">Perl6のVMの構成</h2> +<h2 id="perl6のvm">Perl6のVM</h2> <ul> - <li>MoarVMと呼ばれるVM</li> - <li>C言語で記述されている</li> + <li>MoarVM, JVM , JavaScriptが選択可能 + <ul> + <li>メインで開発されているのはMoarVMであり、 他のVMは機能が実装されていないものが存在する</li> + </ul> + </li> + <li><code>rakudo-star</code> というPerl6のパッケージ環境では、 MoarVMがデフォルトでインストールされる</li> +</ul> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="moarvm">MoarVM</h2> +<ul> + <li>C言語で記述されているPerl6専用の仮想機械</li> <li>レジスタマシン <ul> <li>型情報を持つレジスタに対しての演算として処理される</li> + <li>Rubyなどはスタックマシンとして実装されている</li> </ul> </li> <li>LuaJITなどを利用したJITコンパイルなども可能</li> @@ -331,9 +540,147 @@ <h2 id="バイトコード">バイトコード</h2> <ul> <li>Perl6も、Rakudo/NQPはバイトコードに変換され、 バイトコードをVMが実行する</li> - <li>バイトコード実行部分は、 命令に対応するバイト列を読み込み、 解釈し、 次の命令を読み取ることを繰り返す</li> + <li>Perl6/NQPはバイトコードにコンパイルすることが可能 + <ul> + <li>直接実行することはできない</li> + </ul> + </li> +</ul> + +<pre><code>$nqp --target=mbc --output=fib.moarvm fib.nqp +</code></pre> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="バイトコードとmoarvm">バイトコードとMoarVM</h2> + +<ul> + <li>MoarVMバイトコードはMoarVMの実行バイナリ <code>moar</code> でディスアセンブルすることが可能</li> </ul> +<pre><code> annotation: add_test.nqp:1 +00003 const_i64_16 loc_2_int, 0 +00004 hllboxtype_i loc_3_obj +00005 box_i loc_3_obj, loc_2_int, loc_3_obj +00006 set loc_1_obj, loc_3_obj + label_1: +00007 decont loc_3_obj, loc_0_obj +00008 smrt_numify loc_4_num, loc_3_obj +00009 const_i64_16 loc_2_int, 1 +00010 coerce_in loc_5_num, loc_2_int +00011 gt_n loc_2_int, loc_4_num, loc_5_num +00012 unless_i loc_2_int, label_2(00031) +00013 osrpoint + annotation: add_test.nqp:3 +00014 decont loc_3_obj, loc_1_obj +00015 smrt_numify loc_5_num, loc_3_obj +00016 decont loc_3_obj, loc_0_obj +00017 smrt_numify loc_4_num, loc_3_obj +00018 add_n loc_4_num, loc_5_num, loc_4_num +00019 hllboxtype_n loc_3_obj +00020 box_n loc_3_obj, loc_4_num, loc_3_obj +00021 set loc_1_obj, loc_3_obj +00022 decont loc_3_obj, loc_0_obj +00023 smrt_numify loc_4_num, loc_3_obj +00024 coerce_ni loc_6_int, loc_4_num +00025 const_i64_16 loc_7_int, 1 +00026 sub_i loc_7_int, loc_6_int, loc_7_int +00027 hllboxtype_i loc_3_obj +00028 box_i loc_3_obj, loc_7_int, loc_3_obj +00029 set loc_0_obj, loc_3_obj +00030 goto label_1(00007) +</code></pre> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="nqpとバイトコードの対応">NQPとバイトコードの対応</h2> + +<pre><code>say(add_test(10000)); +</code></pre> + +<pre><code> annotation: add_test.nqp:1 + label_1: +00020 getlex_no loc_7_obj, '&say' +00021 decont loc_7_obj, loc_7_obj +00022 const_s loc_3_str, '&add_test' +00023 getlexstatic_o loc_8_obj, loc_3_str +00024 decont loc_8_obj, loc_8_obj +00025 const_i64_16 loc_5_int, 10000 +00026 prepargs Callsite_1 +00027 arg_i 0, loc_5_int +00028 invoke_o loc_8_obj, loc_8_obj +00029 prepargs Callsite_0 +00030 arg_o 0, loc_8_obj +00031 invoke_v loc_7_obj +00032 null loc_7_obj +00033 return_o loc_7_obj +</code></pre> + +<ul> + <li>Perl6の変数は直接実態を参照せず、中身が入っているコンテナを参照するようになっている。</li> + <li>その為 <code>decont</code> 命令で、コンテナの中身をレジスタに設定する必要がある</li> + <li><code>const_i64_16</code> などは64bitの数という意味で、 <code>int</code> 型としてレジスタに登録している</li> + <li><code>prepargs</code> で引数の確認を行い, <code>invoke_o</code> で実際にサブルーチンに移行する</li> +</ul> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="nqpとバイトコードの対応-1">NQPとバイトコードの対応</h2> + +<pre><code>my $sum := 0; +</code></pre> + +<pre><code> annotation: add_test.nqp:1 +00003 const_i64_16 loc_2_int, 0 +00004 hllboxtype_i loc_3_obj +00005 box_i loc_3_obj, loc_2_int, loc_3_obj +00006 set loc_1_obj, loc_3_obj +</code></pre> + +<ul> + <li>まず <code>loc_2</code> レジスタをint型の整数0で初期化する</li> + <li>変数 <code>$sum</code> はint型の指定がないので、 obj型で登録しなければならない</li> + <li>その為, 整数として登録された <code>loc_2</code> から、 obj型に一旦キャストし、 <code>loc_3</code> レジスタに設定したものを、 <code>loc_1</code> レジスタに設定する</li> +</ul> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="nqpとバイトコードの対応-2">NQPとバイトコードの対応</h2> + +<pre><code> while ( $n > 1) { +</code></pre> + +<pre><code> label_1: +00007 decont loc_3_obj, loc_0_obj +00008 smrt_numify loc_4_num, loc_3_obj +00009 const_i64_16 loc_2_int, 1 +00010 coerce_in loc_5_num, loc_2_int +00011 gt_n loc_2_int, loc_4_num, loc_5_num +00012 unless_i loc_2_int, label_2(00031) +00013 osrpoint +</code></pre> + +<ul> + <li>変数 <code>$n</code> と 整数 <code>1</code> を大小比較する為、 まず <code>$n</code> から値を取り出す</li> + <li>比較にもint型の指定がない為、 <code>num</code> 型にキャストし、 <code>num</code> 型のレジスタでの大小を比較する</li> + <li>比較命令は <code>gt_n</code> であり、 結果により <code>unless_i</code> 命令で、別のラベルにジャンプする</li> +</ul> </div>
--- a/slide.md Fri Apr 19 18:23:10 2019 +0900 +++ b/slide.md Fri Apr 19 18:53:36 2019 +0900 @@ -9,18 +9,62 @@ - Rakudoの内部で利用されているVMや, Perl6のサブセットなどについて探索します - スクリプト言語で主に使われているバイトコードインタプリタの気持ちになります +## 内容 +- Perl6とは? +- スクリプト言語処理系の動き +- Perl6の内部構造 + - NQP + - MoarVM +- MoarVMのバイトコード実行 +- まとめ + ## Perl6とは - 当初Perl5の時期バージョンとして開発されていたプログラミング言語 + - 現在は別の言語として開発がそれぞれ進んでいる - 仕様と実装が分離しており, 現在はテストが仕様となっている -- 実装は複数存在しているが,現在主流な実装はRakudoとなっている -- 言語的にはスクリプト言語であり, 漸進的型付き言語となっている -- MoarVM, JVMで動作する +- 実装は歴史上複数存在しているが,主流な実装はRakudo +- 言語的にはスクリプト言語であり, 漸進的型付き言語 +- 動作環境は、独自のVMのMoarVM, JVM、一部JavaScript上で動作する <img src="2000px-Camelia.svg.png" alt="" style="width: 31%; height: auto;"> +## 現在のPerl6 + +- 現在のバージョンは `6.d` +- [ブラウザ上で実行可能な環境](https://perl6.github.io/6pad/)が存在する +- [IDE](https://commaide.com/)が開発されている +- WebApplicationFrameworkなども開発されており、 Perl5のモジュールを移行したものがいくつか存在する +- 日本では趣味のプロダクト以外社会では使用されていない + - 海外では実際に使われているケースも存在する +- 処理速度では一部Perl5に勝っているが、それでも大分遅い + +## [参考]Perl5のソースコード + +- Perl5時代 + − スカラ、配列、ハッシュの3種類 + - それぞれの変数への参照であるリファレンスが使用可能 + +```perl +use ustrict; +use warnings; + +my $scalar_value = "hello!"; +print "$scalar_value\n"; + +my @array = (1..10); +print "$array[0]\n"; + +my %hash = ( this_is_key => "this_is_value"); +print "$hash{this_is_key}\n"; + +my $hash_ref = \%hash; +print "$hash_ref->{this_is_key}\n"; +``` + ## Perl6のソースコード概要 - Perl5の文法とは比較的変更が多い + - 雰囲気は似ている - 変数がオブジェクトと化した事により, 変数からsayメソッドを呼ぶことが可能 ``` @@ -74,6 +118,16 @@ fizzbuzz($_).say for 1..15; ``` + +- 型を利用したFizzBuzz + +## スクリプト言語 +- Perl6は現状コンパイルすることはできない + - スクリプト言語の分類 + +- 現在広く使われているスクリプト言語(Perl,Python,Ruby...)などとPerl6の構成は類似している +- 今回はPerl6の実装を追いながら、最近のスクリプト言語処理系の大まかな実装を理解する + ## スクリプト言語処理系 - スクリプト言語は入力として与えられたソースコードを、 直接評価せずにバイトコードにコンパイルする形式が主流となっている - その為スクリプト言語の実装は大きく2つで構成されている @@ -82,24 +136,55 @@ <img src="fig/bytecode_sample_generally_lang.svg" width="80%"> + +## Perl6以外のスクリプト言語 + +- 現在使われているプロセスVMは言語に組み込まれているものが多い +- JVMやElixirなどのVMは複数の言語で使用されている +- Java + - JVM +- Ruby + - YARV +- Python + - PythonVM +- Elixir + - BEAM + ## Perl6の処理系の構成 -- Perl6の処理系は現在はRakudoと呼ばれる(歴史上複数存在する) +- Perl6の処理系で現在主流なものはRakudoと呼ばれる実装である(歴史上複数存在する) - Rakudoは3つのレイヤーから構成されている - Perl6インタプリタ - Perl6インタプリタを記述するPerl6のサブセットNQP - Perl6のバイトコードを解釈するMoarVM -- このうちPerl6インタプリタとNQPはNQP自身で記述されている -- MoarVMはC言語で記述されている +- Perl6/NQPがフロントエンドに相当し、MoarVMがバックエンドに相当する + +## Rakudoの構成図 +![](fig/Rakudo_System_overview.png) - +(http://brrt-to-the-future.blogspot.com/2015/03/advancing-jit-compiler.html) ## Perl6とNQP -- NQP(NotQuitPerl Perlっぽい別の言語)でRakudoを記述している +- NQP(NotQuitPerl Perl) + - Perl6のサブセット。Perl6っぽい言語 +- Perl6、 NQP自体がNQPで記述されている - NQPもNQPで記述されている為、 セルフビルド(自分自身で自分自身をコンパイルする)を行う - NQPはPerl6の文法をベースにしているが、 制約がいくつか存在する +- 元々はPerl6の主力実装がParrotだった時代に登場 + - 文法がアップデートされており、当時の資料は古くなっている + +``` +my $value := "hello!"; +say($value); +``` + +## NQPスクリプト + +- 変数は束縛 `:=` を使う +− 関数の間に空白を入れてはいけない +- 再帰呼び出しを使うフィボナッチ数列 ``` #! nqp @@ -109,38 +194,178 @@ my $N := 29; -my $t0 := nqp::time_n(); my $z := fib($N); -my $t1 := nqp::time_n(); nqp::say("fib($N) = " ~ fib($N)); -nqp::say("time = " ~ ($t1-$t0)); +``` + +## NQPスクリプト(nまでの整数の和) + +```perl6 +sub add_test($n){ + my $sum := 0; + while ( $n > 1) { + $sum := $sum + $n; + --$n; + } + return $sum; +} + +say(add_test(10000)); ``` -## プログラミング言語とVM -- 最近のスクリプト言語は、 ソースコードを直接解釈せず、バイトコードに変換しVMが評価する - - 全体的な処理速度の向上の為 - - 実装を分離することでの見通しの良さ -- 言語処理系の実行にのみ動作するVM(プロセスVM) -- 他言語の環境 - - Java - - JVM - - Ruby - - YARV - - Python - - PythonVM - - Elixir - - BEAM +## NQP + +- NQPはPerl6の中で一番レイヤーが低い言語 +- その為、 実行するVMのオペコード(処理単位)を使用することができる +- NQPオペコードは、 Perl6の内部の抽象構文木でも使用されている +- また、 Perl6と同様に型を指定することが可能 -## Perl6のVMの構成 -- MoarVMと呼ばれるVM -- C言語で記述されている +```perl6 +sub add_test(int $n){ + mu $sum := 0; + while nqp::isgt_i($n,1) { + $sum := nqp::add_i($sum,$n); + $n := nqp::sub_i($n,1); + } + return $sum; +} +``` + +## NQPとMoarVM +- NQPそのものは実行することはできない +- NQPの実行にはMoarVM/JVMが必要となる + - NQPコンパイラが各VMに対応したバイトコードに変換する + +## Perl6のVM +- MoarVM, JVM , JavaScriptが選択可能 + - メインで開発されているのはMoarVMであり、 他のVMは機能が実装されていないものが存在する +- `rakudo-star` というPerl6のパッケージ環境では、 MoarVMがデフォルトでインストールされる + +## MoarVM +- C言語で記述されているPerl6専用の仮想機械 - レジスタマシン - 型情報を持つレジスタに対しての演算として処理される + - Rubyなどはスタックマシンとして実装されている - LuaJITなどを利用したJITコンパイルなども可能 - Perl6やNQPは、MoarVMに対してライブラリなどを設定して起動する + + ## バイトコード - Perl6も、Rakudo/NQPはバイトコードに変換され、 バイトコードをVMが実行する -- バイトコード実行部分は、 命令に対応するバイト列を読み込み、 解釈し、 次の命令を読み取ることを繰り返す +- Perl6/NQPはバイトコードにコンパイルすることが可能 + - 直接実行することはできない + +``` +$nqp --target=mbc --output=fib.moarvm fib.nqp +``` + +## バイトコードとMoarVM + + +- MoarVMバイトコードはMoarVMの実行バイナリ `moar` でディスアセンブルすることが可能 + + +``` + annotation: add_test.nqp:1 +00003 const_i64_16 loc_2_int, 0 +00004 hllboxtype_i loc_3_obj +00005 box_i loc_3_obj, loc_2_int, loc_3_obj +00006 set loc_1_obj, loc_3_obj + label_1: +00007 decont loc_3_obj, loc_0_obj +00008 smrt_numify loc_4_num, loc_3_obj +00009 const_i64_16 loc_2_int, 1 +00010 coerce_in loc_5_num, loc_2_int +00011 gt_n loc_2_int, loc_4_num, loc_5_num +00012 unless_i loc_2_int, label_2(00031) +00013 osrpoint + annotation: add_test.nqp:3 +00014 decont loc_3_obj, loc_1_obj +00015 smrt_numify loc_5_num, loc_3_obj +00016 decont loc_3_obj, loc_0_obj +00017 smrt_numify loc_4_num, loc_3_obj +00018 add_n loc_4_num, loc_5_num, loc_4_num +00019 hllboxtype_n loc_3_obj +00020 box_n loc_3_obj, loc_4_num, loc_3_obj +00021 set loc_1_obj, loc_3_obj +00022 decont loc_3_obj, loc_0_obj +00023 smrt_numify loc_4_num, loc_3_obj +00024 coerce_ni loc_6_int, loc_4_num +00025 const_i64_16 loc_7_int, 1 +00026 sub_i loc_7_int, loc_6_int, loc_7_int +00027 hllboxtype_i loc_3_obj +00028 box_i loc_3_obj, loc_7_int, loc_3_obj +00029 set loc_0_obj, loc_3_obj +00030 goto label_1(00007) +``` + +## NQPとバイトコードの対応 + +``` +say(add_test(10000)); +``` +``` + annotation: add_test.nqp:1 + label_1: +00020 getlex_no loc_7_obj, '&say' +00021 decont loc_7_obj, loc_7_obj +00022 const_s loc_3_str, '&add_test' +00023 getlexstatic_o loc_8_obj, loc_3_str +00024 decont loc_8_obj, loc_8_obj +00025 const_i64_16 loc_5_int, 10000 +00026 prepargs Callsite_1 +00027 arg_i 0, loc_5_int +00028 invoke_o loc_8_obj, loc_8_obj +00029 prepargs Callsite_0 +00030 arg_o 0, loc_8_obj +00031 invoke_v loc_7_obj +00032 null loc_7_obj +00033 return_o loc_7_obj +``` + +- Perl6の変数は直接実態を参照せず、中身が入っているコンテナを参照するようになっている。 +- その為 `decont` 命令で、コンテナの中身をレジスタに設定する必要がある +- `const_i64_16` などは64bitの数という意味で、 `int` 型としてレジスタに登録している +- `prepargs` で引数の確認を行い, `invoke_o` で実際にサブルーチンに移行する + +## NQPとバイトコードの対応 + +``` +my $sum := 0; +``` + +``` + annotation: add_test.nqp:1 +00003 const_i64_16 loc_2_int, 0 +00004 hllboxtype_i loc_3_obj +00005 box_i loc_3_obj, loc_2_int, loc_3_obj +00006 set loc_1_obj, loc_3_obj +``` + +- まず `loc_2` レジスタをint型の整数0で初期化する +- 変数 `$sum` はint型の指定がないので、 obj型で登録しなければならない +- その為, 整数として登録された `loc_2` から、 obj型に一旦キャストし、 `loc_3` レジスタに設定したものを、 `loc_1` レジスタに設定する + +## NQPとバイトコードの対応 + +``` + while ( $n > 1) { +``` + +``` + label_1: +00007 decont loc_3_obj, loc_0_obj +00008 smrt_numify loc_4_num, loc_3_obj +00009 const_i64_16 loc_2_int, 1 +00010 coerce_in loc_5_num, loc_2_int +00011 gt_n loc_2_int, loc_4_num, loc_5_num +00012 unless_i loc_2_int, label_2(00031) +00013 osrpoint +``` + +- 変数 `$n` と 整数 `1` を大小比較する為、 まず `$n` から値を取り出す +− 比較にもint型の指定がない為、 `num` 型にキャストし、 `num` 型のレジスタでの大小を比較する +- 比較命令は `gt_n` であり、 結果により `unless_i` 命令で、別のラベルにジャンプする
--- a/slide.pdf.html Fri Apr 19 18:23:10 2019 +0900 +++ b/slide.pdf.html Fri Apr 19 18:53:36 2019 +0900 @@ -89,13 +89,37 @@ <div class='slide'> <!-- _S9SLIDE_ --> +<h2 id="内容">内容</h2> +<ul> + <li>Perl6とは?</li> + <li>スクリプト言語処理系の動き</li> + <li>Perl6の内部構造 + <ul> + <li>NQP</li> + <li>MoarVM</li> + </ul> + </li> + <li>MoarVMのバイトコード実行</li> + <li>まとめ</li> +</ul> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> <h2 id="perl6とは">Perl6とは</h2> <ul> - <li>当初Perl5の時期バージョンとして開発されていたプログラミング言語</li> + <li>当初Perl5の時期バージョンとして開発されていたプログラミング言語 + <ul> + <li>現在は別の言語として開発がそれぞれ進んでいる</li> + </ul> + </li> <li>仕様と実装が分離しており, 現在はテストが仕様となっている</li> - <li>実装は複数存在しているが,現在主流な実装はRakudoとなっている</li> - <li>言語的にはスクリプト言語であり, 漸進的型付き言語となっている</li> - <li>MoarVM, JVMで動作する</li> + <li>実装は歴史上複数存在しているが,主流な実装はRakudo</li> + <li>言語的にはスクリプト言語であり, 漸進的型付き言語</li> + <li>動作環境は、独自のVMのMoarVM, JVM、一部JavaScript上で動作する</li> </ul> <p><img src="2000px-Camelia.svg.png" alt="" style="width: 31%; height: auto;" /></p> @@ -106,10 +130,68 @@ <div class='slide'> <!-- _S9SLIDE_ --> +<h2 id="現在のperl6">現在のPerl6</h2> + +<ul> + <li>現在のバージョンは <code>6.d</code></li> + <li><a href="https://perl6.github.io/6pad/">ブラウザ上で実行可能な環境</a>が存在する</li> + <li><a href="https://commaide.com/">IDE</a>が開発されている</li> + <li>WebApplicationFrameworkなども開発されており、 Perl5のモジュールを移行したものがいくつか存在する</li> + <li>日本では趣味のプロダクト以外社会では使用されていない + <ul> + <li>海外では実際に使われているケースも存在する</li> + </ul> + </li> + <li>処理速度では一部Perl5に勝っているが、それでも大分遅い</li> +</ul> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="参考perl5のソースコード">[参考]Perl5のソースコード</h2> + +<ul> + <li>Perl5時代 + <ul> + <li>スカラ、配列、ハッシュの3種類</li> + <li>それぞれの変数への参照であるリファレンスが使用可能</li> + </ul> + </li> +</ul> + +<pre><code class="language-perl">use ustrict; +use warnings; + +my $scalar_value = "hello!"; +print "$scalar_value\n"; + +my @array = (1..10); +print "$array[0]\n"; + +my %hash = ( this_is_key => "this_is_value"); +print "$hash{this_is_key}\n"; + +my $hash_ref = \%hash; +print "$hash_ref->{this_is_key}\n"; +</code></pre> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> <h2 id="perl6のソースコード概要">Perl6のソースコード概要</h2> <ul> - <li>Perl5の文法とは比較的変更が多い</li> + <li>Perl5の文法とは比較的変更が多い + <ul> + <li>雰囲気は似ている</li> + </ul> + </li> <li>変数がオブジェクトと化した事により, 変数からsayメソッドを呼ぶことが可能</li> </ul> @@ -178,6 +260,28 @@ fizzbuzz($_).say for 1..15; </code></pre> +<ul> + <li>型を利用したFizzBuzz</li> +</ul> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="スクリプト言語">スクリプト言語</h2> +<ul> + <li>Perl6は現状コンパイルすることはできない + <ul> + <li>スクリプト言語の分類</li> + </ul> + </li> + <li>現在広く使われているスクリプト言語(Perl,Python,Ruby…)などとPerl6の構成は類似している</li> + <li>今回はPerl6の実装を追いながら、最近のスクリプト言語処理系の大まかな実装を理解する</li> +</ul> + + </div> @@ -202,10 +306,43 @@ <div class='slide'> <!-- _S9SLIDE_ --> +<h2 id="perl6以外のスクリプト言語">Perl6以外のスクリプト言語</h2> + +<ul> + <li>現在使われているプロセスVMは言語に組み込まれているものが多い</li> + <li>JVMやElixirなどのVMは複数の言語で使用されている</li> + <li>Java + <ul> + <li>JVM</li> + </ul> + </li> + <li>Ruby + <ul> + <li>YARV</li> + </ul> + </li> + <li>Python + <ul> + <li>PythonVM</li> + </ul> + </li> + <li>Elixir + <ul> + <li>BEAM</li> + </ul> + </li> +</ul> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> <h2 id="perl6の処理系の構成">Perl6の処理系の構成</h2> <ul> - <li>Perl6の処理系は現在はRakudoと呼ばれる(歴史上複数存在する)</li> + <li>Perl6の処理系で現在主流なものはRakudoと呼ばれる実装である(歴史上複数存在する)</li> <li>Rakudoは3つのレイヤーから構成されている <ul> <li>Perl6インタプリタ</li> @@ -213,8 +350,7 @@ <li>Perl6のバイトコードを解釈するMoarVM</li> </ul> </li> - <li>このうちPerl6インタプリタとNQPはNQP自身で記述されている</li> - <li>MoarVMはC言語で記述されている</li> + <li>Perl6/NQPがフロントエンドに相当し、MoarVMがバックエンドに相当する</li> </ul> @@ -223,12 +359,52 @@ <div class='slide'> <!-- _S9SLIDE_ --> +<h2 id="rakudoの構成図">Rakudoの構成図</h2> + +<p><img src="fig/Rakudo_System_overview.png" alt="" /></p> + +<p>(http://brrt-to-the-future.blogspot.com/2015/03/advancing-jit-compiler.html)</p> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> <h2 id="perl6とnqp">Perl6とNQP</h2> <ul> - <li>NQP(NotQuitPerl Perlっぽい別の言語)でRakudoを記述している</li> + <li>NQP(NotQuitPerl Perl) + <ul> + <li>Perl6のサブセット。Perl6っぽい言語</li> + </ul> + </li> + <li>Perl6、 NQP自体がNQPで記述されている</li> <li>NQPもNQPで記述されている為、 セルフビルド(自分自身で自分自身をコンパイルする)を行う</li> <li>NQPはPerl6の文法をベースにしているが、 制約がいくつか存在する</li> + <li>元々はPerl6の主力実装がParrotだった時代に登場 + <ul> + <li>文法がアップデートされており、当時の資料は古くなっている</li> + </ul> + </li> +</ul> + +<pre><code>my $value := "hello!"; +say($value); +</code></pre> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="nqpスクリプト">NQPスクリプト</h2> + +<ul> + <li>変数は束縛 <code>:=</code> を使う</li> + <li>関数の間に空白を入れてはいけない</li> + <li>再帰呼び出しを使うフィボナッチ数列</li> </ul> <pre><code>#! nqp @@ -238,12 +414,29 @@ my $N := 29; -my $t0 := nqp::time_n(); my $z := fib($N); -my $t1 := nqp::time_n(); nqp::say("fib($N) = " ~ fib($N)); -nqp::say("time = " ~ ($t1-$t0)); +</code></pre> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="nqpスクリプトnまでの整数の和">NQPスクリプト(nまでの整数の和)</h2> + +<pre><code class="language-perl6">sub add_test($n){ + my $sum := 0; + while ( $n > 1) { + $sum := $sum + $n; + --$n; + } + return $sum; +} + +say(add_test(10000)); </code></pre> @@ -252,37 +445,37 @@ <div class='slide'> <!-- _S9SLIDE_ --> -<h2 id="プログラミング言語とvm">プログラミング言語とVM</h2> +<h2 id="nqp">NQP</h2> + <ul> - <li>最近のスクリプト言語は、 ソースコードを直接解釈せず、バイトコードに変換しVMが評価する - <ul> - <li>全体的な処理速度の向上の為</li> - <li>実装を分離することでの見通しの良さ</li> - </ul> - </li> - <li>言語処理系の実行にのみ動作するVM(プロセスVM)</li> - <li>他言語の環境 + <li>NQPはPerl6の中で一番レイヤーが低い言語</li> + <li>その為、 実行するVMのオペコード(処理単位)を使用することができる</li> + <li>NQPオペコードは、 Perl6の内部の抽象構文木でも使用されている</li> + <li>また、 Perl6と同様に型を指定することが可能</li> +</ul> + +<pre><code class="language-perl6">sub add_test(int $n){ + mu $sum := 0; + while nqp::isgt_i($n,1) { + $sum := nqp::add_i($sum,$n); + $n := nqp::sub_i($n,1); + } + return $sum; +} +</code></pre> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="nqpとmoarvm">NQPとMoarVM</h2> +<ul> + <li>NQPそのものは実行することはできない</li> + <li>NQPの実行にはMoarVM/JVMが必要となる <ul> - <li>Java - <ul> - <li>JVM</li> - </ul> - </li> - <li>Ruby - <ul> - <li>YARV</li> - </ul> - </li> - <li>Python - <ul> - <li>PythonVM</li> - </ul> - </li> - <li>Elixir - <ul> - <li>BEAM</li> - </ul> - </li> + <li>NQPコンパイラが各VMに対応したバイトコードに変換する</li> </ul> </li> </ul> @@ -293,13 +486,29 @@ <div class='slide'> <!-- _S9SLIDE_ --> -<h2 id="perl6のvmの構成">Perl6のVMの構成</h2> +<h2 id="perl6のvm">Perl6のVM</h2> <ul> - <li>MoarVMと呼ばれるVM</li> - <li>C言語で記述されている</li> + <li>MoarVM, JVM , JavaScriptが選択可能 + <ul> + <li>メインで開発されているのはMoarVMであり、 他のVMは機能が実装されていないものが存在する</li> + </ul> + </li> + <li><code>rakudo-star</code> というPerl6のパッケージ環境では、 MoarVMがデフォルトでインストールされる</li> +</ul> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="moarvm">MoarVM</h2> +<ul> + <li>C言語で記述されているPerl6専用の仮想機械</li> <li>レジスタマシン <ul> <li>型情報を持つレジスタに対しての演算として処理される</li> + <li>Rubyなどはスタックマシンとして実装されている</li> </ul> </li> <li>LuaJITなどを利用したJITコンパイルなども可能</li> @@ -315,9 +524,147 @@ <h2 id="バイトコード">バイトコード</h2> <ul> <li>Perl6も、Rakudo/NQPはバイトコードに変換され、 バイトコードをVMが実行する</li> - <li>バイトコード実行部分は、 命令に対応するバイト列を読み込み、 解釈し、 次の命令を読み取ることを繰り返す</li> + <li>Perl6/NQPはバイトコードにコンパイルすることが可能 + <ul> + <li>直接実行することはできない</li> + </ul> + </li> +</ul> + +<pre><code>$nqp --target=mbc --output=fib.moarvm fib.nqp +</code></pre> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="バイトコードとmoarvm">バイトコードとMoarVM</h2> + +<ul> + <li>MoarVMバイトコードはMoarVMの実行バイナリ <code>moar</code> でディスアセンブルすることが可能</li> </ul> +<pre><code> annotation: add_test.nqp:1 +00003 const_i64_16 loc_2_int, 0 +00004 hllboxtype_i loc_3_obj +00005 box_i loc_3_obj, loc_2_int, loc_3_obj +00006 set loc_1_obj, loc_3_obj + label_1: +00007 decont loc_3_obj, loc_0_obj +00008 smrt_numify loc_4_num, loc_3_obj +00009 const_i64_16 loc_2_int, 1 +00010 coerce_in loc_5_num, loc_2_int +00011 gt_n loc_2_int, loc_4_num, loc_5_num +00012 unless_i loc_2_int, label_2(00031) +00013 osrpoint + annotation: add_test.nqp:3 +00014 decont loc_3_obj, loc_1_obj +00015 smrt_numify loc_5_num, loc_3_obj +00016 decont loc_3_obj, loc_0_obj +00017 smrt_numify loc_4_num, loc_3_obj +00018 add_n loc_4_num, loc_5_num, loc_4_num +00019 hllboxtype_n loc_3_obj +00020 box_n loc_3_obj, loc_4_num, loc_3_obj +00021 set loc_1_obj, loc_3_obj +00022 decont loc_3_obj, loc_0_obj +00023 smrt_numify loc_4_num, loc_3_obj +00024 coerce_ni loc_6_int, loc_4_num +00025 const_i64_16 loc_7_int, 1 +00026 sub_i loc_7_int, loc_6_int, loc_7_int +00027 hllboxtype_i loc_3_obj +00028 box_i loc_3_obj, loc_7_int, loc_3_obj +00029 set loc_0_obj, loc_3_obj +00030 goto label_1(00007) +</code></pre> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="nqpとバイトコードの対応">NQPとバイトコードの対応</h2> + +<pre><code>say(add_test(10000)); +</code></pre> + +<pre><code> annotation: add_test.nqp:1 + label_1: +00020 getlex_no loc_7_obj, '&say' +00021 decont loc_7_obj, loc_7_obj +00022 const_s loc_3_str, '&add_test' +00023 getlexstatic_o loc_8_obj, loc_3_str +00024 decont loc_8_obj, loc_8_obj +00025 const_i64_16 loc_5_int, 10000 +00026 prepargs Callsite_1 +00027 arg_i 0, loc_5_int +00028 invoke_o loc_8_obj, loc_8_obj +00029 prepargs Callsite_0 +00030 arg_o 0, loc_8_obj +00031 invoke_v loc_7_obj +00032 null loc_7_obj +00033 return_o loc_7_obj +</code></pre> + +<ul> + <li>Perl6の変数は直接実態を参照せず、中身が入っているコンテナを参照するようになっている。</li> + <li>その為 <code>decont</code> 命令で、コンテナの中身をレジスタに設定する必要がある</li> + <li><code>const_i64_16</code> などは64bitの数という意味で、 <code>int</code> 型としてレジスタに登録している</li> + <li><code>prepargs</code> で引数の確認を行い, <code>invoke_o</code> で実際にサブルーチンに移行する</li> +</ul> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="nqpとバイトコードの対応-1">NQPとバイトコードの対応</h2> + +<pre><code>my $sum := 0; +</code></pre> + +<pre><code> annotation: add_test.nqp:1 +00003 const_i64_16 loc_2_int, 0 +00004 hllboxtype_i loc_3_obj +00005 box_i loc_3_obj, loc_2_int, loc_3_obj +00006 set loc_1_obj, loc_3_obj +</code></pre> + +<ul> + <li>まず <code>loc_2</code> レジスタをint型の整数0で初期化する</li> + <li>変数 <code>$sum</code> はint型の指定がないので、 obj型で登録しなければならない</li> + <li>その為, 整数として登録された <code>loc_2</code> から、 obj型に一旦キャストし、 <code>loc_3</code> レジスタに設定したものを、 <code>loc_1</code> レジスタに設定する</li> +</ul> + + + +</div> + +<div class='slide'> + <!-- _S9SLIDE_ --> +<h2 id="nqpとバイトコードの対応-2">NQPとバイトコードの対応</h2> + +<pre><code> while ( $n > 1) { +</code></pre> + +<pre><code> label_1: +00007 decont loc_3_obj, loc_0_obj +00008 smrt_numify loc_4_num, loc_3_obj +00009 const_i64_16 loc_2_int, 1 +00010 coerce_in loc_5_num, loc_2_int +00011 gt_n loc_2_int, loc_4_num, loc_5_num +00012 unless_i loc_2_int, label_2(00031) +00013 osrpoint +</code></pre> + +<ul> + <li>変数 <code>$n</code> と 整数 <code>1</code> を大小比較する為、 まず <code>$n</code> から値を取り出す</li> + <li>比較にもint型の指定がない為、 <code>num</code> 型にキャストし、 <code>num</code> 型のレジスタでの大小を比較する</li> + <li>比較命令は <code>gt_n</code> であり、 結果により <code>unless_i</code> 命令で、別のラベルにジャンプする</li> +</ul> </div>