diff slide.html @ 18:1fc9d0bd924f default tip

update
author anatofuz <anatofuz@cr.ie.u-ryukyu.ac.jp>
date Sat, 20 Apr 2019 18:06:35 +0900
parents a176ea5c0264
children
line wrap: on
line diff
--- a/slide.html	Fri Apr 19 23:22:02 2019 +0900
+++ b/slide.html	Sat Apr 20 18:06:35 2019 +0900
@@ -139,7 +139,12 @@
     </ul>
   </li>
   <li>仕様と実装が分離しており, 現在はテストが仕様となっている</li>
-  <li>実装は歴史上複数存在しているが,主流な実装はRakudo</li>
+  <li>実装は歴史上複数存在しているが,主流な実装はRakudo
+    <ul>
+      <li>Haskellで実装されたPugs</li>
+      <li>Pythonとの共同基板を目指したParrot</li>
+    </ul>
+  </li>
   <li>言語的にはスクリプト言語であり, 漸進的型付き言語</li>
   <li>動作環境は、独自のVMのMoarVM, JVM、一部JavaScript上で動作する</li>
 </ul>
@@ -384,7 +389,7 @@
   <!-- _S9SLIDE_ -->
 <h2 id="rakudoの構成図">Rakudoの構成図</h2>
 
-<p><img src="fig/Rakudo_System_overview.png" alt="" /></p>
+<p><img src="fig/Rakudo_overview.svg" alt="" /></p>
 
 <p>(http://brrt-to-the-future.blogspot.com/2015/03/advancing-jit-compiler.html)</p>
 
@@ -749,7 +754,11 @@
 
 <ul>
   <li><code>smrt_numify</code> はレジスタ上のオブジェクトを、 num型に変換し、 別のレジスタに登録する命令</li>
-  <li>今回の整数の比較では、 int型の強制がない為、 数値として比較するためにnum型にキャストしている</li>
+  <li>今回の整数の比較では、 int型の強制がない為、 数値として比較するためにn64型にキャストしている
+    <ul>
+      <li>numはn64型であり、 64ビットの浮動小数点定数の意味</li>
+    </ul>
+  </li>
 </ul>
 
 <p><img src="fig/perl6_num_convert.svg" alt="" /></p>
@@ -760,6 +769,61 @@
 
 <div class='slide'>
   <!-- _S9SLIDE_ -->
+<h2 id="const_i64_16とcoerece_in">const_i64_16とcoerece_in</h2>
+
+<pre><code>    while ( $n &gt; 1) {
+</code></pre>
+
+<pre><code>00009      const_i64_16       loc_2_int, 1
+00010      coerce_in          loc_5_num, loc_2_int
+</code></pre>
+<ul>
+  <li>64ビット整数として1をレジスタ <code>loc_2</code> に設定する</li>
+  <li>その後、 numでの比較のためにキャストし, <code>loc_5</code> レジスタに設定している</li>
+</ul>
+
+
+
+</div>
+
+<div class='slide'>
+  <!-- _S9SLIDE_ -->
+<h2 id="比較とif文の判定">比較とif文の判定</h2>
+
+<pre><code>    while ( $n &gt; 1) {
+</code></pre>
+
+<pre><code>00011      gt_n               loc_2_int, loc_4_num, loc_5_num
+00012      unless_i           loc_2_int, label_2(00031)
+</code></pre>
+
+<ul>
+  <li><code>gt_n</code> で <code>loc_4</code> (nが入っている) レジスタと <code>loc_5</code> (1が入っているレジスタ)を比較する
+    <ul>
+      <li>結果により <code>loc_2</code> レジスタに真偽値がint型で代入される</li>
+    </ul>
+  </li>
+  <li>その結果を <code>unless_i</code> で読み取り、 値が偽であったら <code>label_2(00031)</code> にジャンプする</li>
+</ul>
+
+
+
+</div>
+
+<div class='slide'>
+  <!-- _S9SLIDE_ -->
+<h2 id="c言語での実装へ">C言語での実装へ</h2>
+<ul>
+  <li>今まではスクリプトレベルでの実装を見てきました</li>
+  <li>スクリプトが実行されるVMの実装をCレベルで見ていきましょう</li>
+</ul>
+
+
+
+</div>
+
+<div class='slide'>
+  <!-- _S9SLIDE_ -->
 <h2 id="moarvmのバイトコードインタプリタ部分">MoarVMのバイトコードインタプリタ部分</h2>
 <p>MoarVMなどの言語処理系のバイトコードインタプリタは次のことを繰り返している</p>
 <ol>
@@ -770,7 +834,7 @@
 </ol>
 
 <ul>
-  <li>この部分の実装は大体次のような処理をしている</li>
+  <li>この部分の実装は大体次のようなパターンで記述されている</li>
 </ul>
 
 
@@ -786,7 +850,16 @@
   <li>実行のたびにループで先頭に戻り、次の命令を計算する必要があるので低速</li>
 </ul>
 
-<pre><code>
+<pre><code>    while( pc != NULL) {
+        switch(pc){
+            case ADD_INSTRUCTION:
+                // instruction....
+                break;
+            case SUBD_INSTRUCTION:
+                // instruction....
+                break;
+        }
+    }
 </code></pre>
 
 
@@ -799,6 +872,11 @@
 
 <ul>
   <li>巨大なcase文とループではなく、 次の命令の実行場所に直接jmpで移動する</li>
+  <li>GCC拡張でサポートしている場合「<code>&amp;&amp;ラベル名</code> 」でラベルのアドレスが取得できる
+    <ul>
+      <li>取得したアドレスに対して「goto アドレス」でgoto文でjmpする</li>
+    </ul>
+  </li>
   <li>次の命令に対応するラベルを取得する必要があるが、 ループする必要がなく高速</li>
   <li>ラベルgotoであり、 Cコンパイラの拡張機能として搭載されている
     <ul>
@@ -807,7 +885,19 @@
   </li>
 </ul>
 
-<pre><code>
+<pre><code>    static const void *CODES[] = {&amp;&amp;ADD_INSTRUCTION, &amp;&amp;SUB_INSTRCUTION};
+
+    goto *CODES[pc];
+
+ADD_INSTRUCTION:
+    // instruction...
+    pc++;
+    goto *CODES[pc];
+
+SUB_INSTRUCTION:
+    // instruction...
+    pc++;
+    goto *CODES[pc];
 </code></pre>
 
 
@@ -827,6 +917,326 @@
   <li>一般的にはラベルgotoの方が高速である為、他のスクリプト言語でもラベルgotoが使われている</li>
 </ul>
 
+
+
+</div>
+
+<div class='slide'>
+  <!-- _S9SLIDE_ -->
+<h2 id="moarvmのc言語での実装">MoarVMのC言語での実装</h2>
+
+<ul>
+  <li><a href="https://github.com/MoarVM/MoarVM">GitHub上にリポジトリ</a>がある</li>
+  <li><code>src/core/interp.c</code> がバイトコードインタプリタの実装コード</li>
+  <li>この中でマクロを使いつつ、 バイトコードに対応した命令を処理している</li>
+  <li><code>MVM_interp_run</code>が実際にバイトコードを解釈している</li>
+</ul>
+
+<pre><code>/* This is the interpreter run loop. We have one of these per thread. */
+void MVM_interp_run(MVMThreadContext *tc, void (*initial_invoke)(MVMThreadContext *, void *), void *invoke_data) {
+#if MVM_CGOTO
+#include "oplabels.h"
+#endif
+
+    /* Points to the place in the bytecode right after the current opcode. */
+    /* See the NEXT_OP macro for making sense of this */
+    MVMuint8 *cur_op = NULL;
+
+    /* The current frame's bytecode start. */
+    MVMuint8 *bytecode_start = NULL;
+
+    /* Points to the base of the current register set for the frame we
+     * are presently in. */
+    MVMRegister *reg_base = NULL;
+
+    /* Points to the current compilation unit. */
+    MVMCompUnit *cu = NULL;
+
+    /* The current call site we're constructing. */
+    MVMCallsite *cur_callsite = NULL;
+
+    /* Stash addresses of current op, register base and SC deref base
+     * in the TC; this will be used by anything that needs to switch
+     * the current place we're interpreting. */
+    tc-&gt;interp_cur_op         = &amp;cur_op;
+    tc-&gt;interp_bytecode_start = &amp;bytecode_start;
+    tc-&gt;interp_reg_base       = &amp;reg_base;
+    tc-&gt;interp_cu             = &amp;cu;
+
+    /* With everything set up, do the initial invocation (exactly what this does
+     * varies depending on if this is starting a new thread or is the top-level
+     * program entry point). */
+    initial_invoke(tc, invoke_data);
+</code></pre>
+
+
+
+</div>
+
+<div class='slide'>
+  <!-- _S9SLIDE_ -->
+<h2 id="moarvmのレジスタ構成">MoarVMのレジスタ構成</h2>
+
+<ul>
+  <li>レジスタはそれぞれの型を共用体のデータ構造で持っている</li>
+  <li>型名は各命令の接尾辞に対応している</li>
+</ul>
+
+<pre><code>/* Different views of a register. */
+union MVMRegister {
+    MVMObject         *o;
+    MVMString *s;
+    MVMint8            i8;
+    MVMuint8           u8;
+    MVMint16           i16;
+    MVMuint16          u16;
+    MVMint32           i32;
+    MVMuint32          u32;
+    MVMint64           i64;
+    MVMuint64          u64;
+    MVMnum32           n32;
+    MVMnum64           n64;
+};
+</code></pre>
+
+
+
+</div>
+
+<div class='slide'>
+  <!-- _S9SLIDE_ -->
+<h2 id="mvm_interp_runの登場人物">MVM_interp_runの登場人物</h2>
+
+<ul>
+  <li><code>cur_op</code> が読み取るのバイトコード列の先頭ポインタを保存している</li>
+  <li><code>op</code> が現在実行する命令の数値が入っている</li>
+  <li><code>reg_base</code> がMoarVMのレジスタの集合配列</li>
+</ul>
+
+<pre><code>    /* Points to the place in the bytecode right after the current opcode. */
+    /* See the NEXT_OP macro for making sense of this */
+    MVMuint8 *cur_op = NULL;
+
+    /* The current frame's bytecode start. */
+    MVMuint8 *bytecode_start = NULL;
+
+    /* Points to the base of the current register set for the frame we
+     * are presently in. */
+    MVMRegister *reg_base = NULL;
+</code></pre>
+
+
+
+</div>
+
+<div class='slide'>
+  <!-- _S9SLIDE_ -->
+<h2 id="mvm_interp_runメインループ">MVM_interp_runメインループ</h2>
+
+<ul>
+  <li><code>runloop</code>がメインのループで処理を行っている
+    <ul>
+      <li><code>DISPATCH</code>部分で命令をバイトコード列から取り出している</li>
+    </ul>
+  </li>
+</ul>
+
+<pre><code>    /* Enter runloop. */
+    runloop: {
+        MVMuint16 op;
+
+#if MVM_TRACING
+        if (tracing_enabled) {
+            char *trace_line;
+            trace_line = MVM_exception_backtrace_line(tc, tc-&gt;cur_frame, 0, cur_op);
+            fprintf(stderr, "Op %d%s\n", (int)*((MVMuint16 *)cur_op), trace_line);
+            /* slow tracing is slow. Feel free to speed it. */
+            MVM_free(trace_line);
+        }
+#endif
+
+        /* The ops should be in the same order here as in the oplist file, so
+         * the compiler can can optimise the switch properly. To check if they
+         * are in the same order as the oplist use the
+         * tools/compare-oplist-interp-order.sh helper script. */
+        DISPATCH(NEXT_OP) {
+            OP(no_op):
+                goto NEXT;
+            OP(const_i8):
+            OP(const_i16):
+            OP(const_i32):
+                MVM_exception_throw_adhoc(tc, "const_iX NYI");
+            OP(const_i64):
+                GET_REG(cur_op, 0).i64 = MVM_BC_get_I64(cur_op, 2);
+                cur_op += 10;
+                goto NEXT;
+</code></pre>
+
+
+
+</div>
+
+<div class='slide'>
+  <!-- _S9SLIDE_ -->
+<h2 id="mvm_interp_runメインループ-1">MVM_interp_runメインループ</h2>
+
+<ul>
+  <li><code>DISPATCH</code>はマクロになっている
+    <ul>
+      <li>ラベルgotoが使えるケースはDISPATCHは何も意味を持たない</li>
+      <li>使えない場合はswitch文に展開される
+        <ul>
+          <li><code>op</code> に実行する命令の数値が格納されているので、 これに応じてswitchで飛ぶ</li>
+        </ul>
+      </li>
+    </ul>
+  </li>
+</ul>
+
+<pre><code>#if MVM_CGOTO
+#define DISPATCH(op)
+#define OP(name) OP_ ## name
+#define NEXT *LABELS[NEXT_OP]
+#else
+#define DISPATCH(op) switch (op)
+#define OP(name) case MVM_OP_ ## name
+#define NEXT runloop
+#endif
+</code></pre>
+
+
+
+</div>
+
+<div class='slide'>
+  <!-- _S9SLIDE_ -->
+<h2 id="mvm_interp_runメインループ-2">MVM_interp_runメインループ</h2>
+
+<ul>
+  <li><code>OP</code> が命令のスコープを切るマクロとなっている
+    <ul>
+      <li>gotoが使える場合
+        <ul>
+          <li><code>##name</code> に展開され、 それぞれの命令の名前を持つラベルになる</li>
+        </ul>
+      </li>
+      <li>gotoが使えない場合
+        <ul>
+          <li>case文に展開される</li>
+        </ul>
+      </li>
+    </ul>
+  </li>
+</ul>
+
+<pre><code>#if MVM_CGOTO
+#define DISPATCH(op)
+#define OP(name) OP_ ## name
+#define NEXT *LABELS[NEXT_OP]
+#else
+#define DISPATCH(op) switch (op)
+#define OP(name) case MVM_OP_ ## name
+#define NEXT runloop
+#endif
+</code></pre>
+
+
+
+</div>
+
+<div class='slide'>
+  <!-- _S9SLIDE_ -->
+<h2 id="mvm_interp_runメインループ-3">MVM_interp_runメインループ</h2>
+
+<ul>
+  <li>次の命令には <code>NEXT</code> マクロで移動する
+    <ul>
+      <li>gotoが使える場合
+        <ul>
+          <li>次のラベルに対応したアドレスを配列LABELSから取り出しgotoする</li>
+        </ul>
+      </li>
+      <li>gotoが使えない場合
+        <ul>
+          <li><code>runloop</code>に対してgotoする(先頭へのループ)</li>
+        </ul>
+      </li>
+    </ul>
+  </li>
+</ul>
+
+<pre><code>#if MVM_CGOTO
+#define DISPATCH(op)
+#define OP(name) OP_ ## name
+#define NEXT *LABELS[NEXT_OP]
+#else
+#define DISPATCH(op) switch (op)
+#define OP(name) case MVM_OP_ ## name
+#define NEXT runloop
+#endif
+</code></pre>
+
+
+
+</div>
+
+<div class='slide'>
+  <!-- _S9SLIDE_ -->
+<h2 id="それぞれの命令の実装">それぞれの命令の実装</h2>
+
+<ul>
+  <li>マクロ <code>GET_REG</code> でレジスタ情報を取得する
+    <ul>
+      <li>末尾で型を指定する</li>
+    </ul>
+  </li>
+  <li>よしなに処理をした後に、バイトコード列 <code>cur_op</code> をインクリメントする
+    <ul>
+      <li>計算機のプログラムカウンタを進めることに対応する</li>
+    </ul>
+  </li>
+</ul>
+
+<pre><code>    OP(add_i):
+        GET_REG(cur_op, 0).i64 = GET_REG(cur_op, 2).i64 + GET_REG(cur_op, 4).i64;
+        cur_op += 6;
+        goto NEXT;
+    OP(sub_i):
+        GET_REG(cur_op, 0).i64 = GET_REG(cur_op, 2).i64 - GET_REG(cur_op, 4).i64;
+        cur_op += 6;
+        goto NEXT;
+    OP(mul_i):
+        GET_REG(cur_op, 0).i64 = GET_REG(cur_op, 2).i64 * GET_REG(cur_op, 4).i64;
+        cur_op += 6;
+        goto NEXT;
+</code></pre>
+
+
+
+</div>
+
+<div class='slide'>
+  <!-- _S9SLIDE_ -->
+<h2 id="本日の展示について">本日の展示について</h2>
+
+<ul>
+  <li>現在当研究室で開発しているContinuationBasedC(CbC)で一部Perl6の処理系を書いています</li>
+  <li>また、 CbCを用いたGearsOSの展示も行っています</li>
+</ul>
+
+
+
+</div>
+
+<div class='slide'>
+  <!-- _S9SLIDE_ -->
+<h2 id="まとめ">まとめ</h2>
+<ul>
+  <li>Perl6の内部構造に迫りました</li>
+  <li>スクリプト言語の中身も通常の計算機と同じような処理をしています</li>
+  <li>OSSなので皆さん読んで改造してみましょう!!</li>
+</ul>
+
 </div>