comparison Paper/anatofuz.tex @ 48:443de29ac349

fix section names
author Takahiro SHIMIZU <anatofuz@cr.ie.u-ryukyu.ac.jp>
date Fri, 09 Nov 2018 19:15:06 +0900
parents 6fc015dd380b
children 933dbfa8f06f
comparison
equal deleted inserted replaced
47:6fc015dd380b 48:443de29ac349
1 % withpage: ページ番号をつける (著者確認用) 1 % withpage: ページ番号をつける (著者確認用)
2 % english: 英語原稿用フォーマット 2 % english: 英語原稿用フォーマット
3 \documentclass{ipsjprosym} 3 \documentclass{ipsjprosym}
4 %\documentclass[withpage,english]{ipsjprosym} 4 %\documentclass[withpage, english]{ipsjprosym}
5 5
6 \usepackage[dvipdfmx]{graphicx} 6 \usepackage[dvipdfmx]{graphicx}
7 \usepackage{latexsym} 7 \usepackage{latexsym}
8 \usepackage{comment} 8 \usepackage{comment}
9 \usepackage{listings} 9 \usepackage{listings}
10 \lstset{ 10 \lstset{
11 language=C, 11 language=C,
12 tabsize=2, 12 tabsize=2,
13 frame=single, 13 frame=single,
14 basicstyle={\ttfamily\footnotesize},% 14 basicstyle={\ttfamily\footnotesize}, %
15 identifierstyle={\footnotesize},% 15 identifierstyle={\footnotesize}, %
16 commentstyle={\footnotesize\itshape},% 16 commentstyle={\footnotesize\itshape}, %
17 keywordstyle={\footnotesize\bfseries},% 17 keywordstyle={\footnotesize\bfseries}, %
18 ndkeywordstyle={\footnotesize},% 18 ndkeywordstyle={\footnotesize}, %
19 stringstyle={\footnotesize\ttfamily}, 19 stringstyle={\footnotesize\ttfamily},
20 breaklines=true, 20 breaklines=true,
21 captionpos=b, 21 captionpos=b,
22 columns=[l]{fullflexible},% 22 columns=[l]{fullflexible}, %
23 xrightmargin=0zw,% 23 xrightmargin=0zw, %
24 xleftmargin=1zw,% 24 xleftmargin=1zw, %
25 aboveskip=1zw, 25 aboveskip=1zw,
26 numberstyle={\scriptsize},% 26 numberstyle={\scriptsize}, %
27 stepnumber=1, 27 stepnumber=1,
28 numbersep=0.5zw,% 28 numbersep=0.5zw, %
29 lineskip=-0.5ex, 29 lineskip=-0.5ex,
30 } 30 }
31 \renewcommand{\lstlistingname}{Code} 31 \renewcommand{\lstlistingname}{Code}
32 \usepackage{caption} 32 \usepackage{caption}
33 \captionsetup[lstlisting]{font={small,tt}} 33 \captionsetup[lstlisting]{font={small, tt}}
34 \usepackage{url} 34 \usepackage{url}
35 \begin{document} 35 \begin{document}
36 36
37 % Title, Author %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 37 % Title, Author %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38 \title{CbCを用いたPerl6処理系} 38 \title{CbCを用いたPerl6処理系}
39 39
40 %\affiliate{IPSJ}{情報処理学会} 40 %\affiliate{IPSJ}{情報処理学会}
41 \affiliate{IERYUKYU}{琉球大学工学部情報工学科} 41 \affiliate{IERYUKYU}{琉球大学工学部情報工学科}
42 42
45 45
46 %概要 46 %概要
47 \begin{abstract} 47 \begin{abstract}
48 スクリプト言語であるPerl5の後継言語としてPerl6が現在開発されている. 48 スクリプト言語であるPerl5の後継言語としてPerl6が現在開発されている.
49 Perl6は設計と実装が区分されており様々な処理系が開発されている.現在主流なPerl6はRakudoと言われるプロジェクトである. 49 Perl6は設計と実装が区分されており様々な処理系が開発されている.現在主流なPerl6はRakudoと言われるプロジェクトである.
50 RakudoではPerl6自体をNQP(NotQuitPerl)と言われるPerl6のサブセットで記述し,NQPをVMが解釈するという処理流れになっている. 50 RakudoではPerl6自体をNQP(NotQuitPerl)と言われるPerl6のサブセットで記述し, NQPをVMが解釈するという処理流れになっている.
51 このVMは任意のVMが選択できるようになっており,現在はMoarVM,JavaVM,Javascriptが動作環境として選択可能である. 51 このVMは任意のVMが選択できるようになっており, 現在はMoarVM,JavaVM,Javascriptが動作環境として選択可能である.
52 主に利用されているVMにCで書かれたMoarVMが存在する. 52 主に利用されているVMにCで書かれたMoarVMが存在する.
53 MoarVMはJITコンパイルなどをサポートしているが,全体的な起動時間及び処理速度がPerl5と比較し非常に低速である. 53 MoarVMはJITコンパイルなどをサポートしているが, 全体的な起動時間及び処理速度がPerl5と比較し非常に低速である.
54 この問題を解決するためにContinuation based C (CbC)という言語を一部用いてMoarVMの書き換えを行う. 54 この問題を解決するためにContinuation based C (CbC)という言語を一部用いてMoarVMの書き換えを行う.
55 本論文ではCbCを用いたMoarVMの書き換えを検討し,得られた知見について述べる. 55 本論文ではCbCを用いたMoarVMの書き換えを検討し, 得られた知見について述べる.
56 56
57 57
58 \end{abstract} 58 \end{abstract}
59 59
60 \begin{jkeyword} 60 \begin{jkeyword}
61 プログラミング言語, コンパイラ, CbC, Perl6, MoarVM 61 プログラミング言語, コンパイラ, CbC, Perl6, MoarVM
62 \end{jkeyword} 62 \end{jkeyword}
63 63
64 \maketitle 64 \maketitle
65 65
66 % Body %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 66 % Body %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
67 \section{研究目的} 67 \section{CbCを用いた言語処理系の実装}
68 現在も広く使われているスクリプト言語PerlことPerl5の後継言語としてPerl6が開発されている. 68 当研究室ではContinuation Based C(以下CbC)という言語を開発している.
69 Perl6は設計と実装が区分されており,現在広く使われている実装はRakudoと呼ばれるプロジェクトである. 69 CbCはCよりきめ細やかな単位で実装する事が可能である為, 言語処理系に応用すれば効率的な開発,実行が出来ると期待される.
70 Rakudoの実装はPerl6コンパイラ開発者用のサブセットであるNQP(NotQuitPerl)で実装されているPerl6の事を指す. 70 現在活発に開発が進んでいる言語にPerl6がある.
71 現在RakudoはNQPを解釈できる実行環境として,C言語で実装されたMoarVM,JVM,Javascript上で動作する様に開発されている. 71 Perl6はMoarVMと呼ばれるVMを中心としたRakudoと呼ばれる実装が現在の主流となっている.
72 Rakudoとして主に使われている処理系はMoarVMであるが,MoarVMの処理時間がPerl5などの多くのスクリプト言語と比較し非常に低速である. 72 Rakudoは処理速度が他のプログラミング言語と比較しても非常に低速である.
73 その為現在日本国内ではPerl6を実務として利用するケースは概ね存在しない. 73 その為現在日本国内ではPerl6を実務として利用するケースは概ね存在しない.
74 Perl6の持つ言語機能や型システムは非常に柔軟かつ強力であるため実用的な処理速度に達すれば言語の利用件数が向上することが期待される. 74 Perl6の持つ言語機能や型システムは非常に柔軟かつ強力であるため実用的な処理速度に達すれば言語の利用件数が向上することが期待される.
75 この問題を解決するために現在当研究室で開発しているContinuation Based C(以下CbC)を用いて改良を行う. 75 その為本研究では, CbCを用いた言語処理系の実装の一例としてMoarVMをCbCで構築したCbCMoarVMを実装する.
76 CbCはCよりさらにきめ細やかな記述が可能であるためスクリプト言語などのプログラミング言語の記述と親和性が高い事が推測される. 76 本研究はCbCをスクリプト言語の実装に適応した場合, どのような利点やプログラミング上の問題点に遭遇するかCbCの応用としての側面でも行う.
77 本研究はCbCをスクリプト言語の実装に適応した場合,どのような利点やプログラミング上の問題点に遭遇するかCbCの応用としての側面でも行う. 77 本稿ではまずCbC, Perl6の特徴及び現在の実装について述べ,本研究で行ったCbCで書き換えたMoarVMについてデバッグ手法も含め解説する.
78 本稿ではまずCbC,Perl6の特徴及び現在の実装について述べ,本研究で行ったCbCで書き換えたMoarVMについてデバッグ手法も含め解説する. 78 そして本研究で得られたCbCを言語処理系に適応した場合の利点と欠点について述べ, 今後の展望について記載する.
79 そして本研究で得られたCbCを言語処理系に適応した場合の利点と欠点について述べ,今後の展望について記載する.
80 79
81 \section{CbC} 80 \section{CbC}
82 \subsection{CbCの概要} 81 \subsection{CbCの概要}
83 CbCは当研究室で開発しているプログラミング言語である. 82 CbCは当研究室で開発しているプログラミング言語である.
84 Cレベルでのプログラミングを行う場合,本来プログラマが行いたい処理の他にmallocなどを利用したメモリのアロケートやエラーハンドリングなどを記述する必要がある. 83 Cレベルでのプログラミングを行う場合, 本来プログラマが行いたい処理の他にmallocなどを利用したメモリのアロケートやエラーハンドリングなどを記述する必要がある.
85 これらの処理をmeta computationと呼ぶ.これらmeta computationと通常の処理を分離することでバグの原因がmeta computation側にあるか処理側にあるかの分離などが可能となる. 84 これらの処理をmeta computationと呼ぶ.これらmeta computationと通常の処理を分離することでバグの原因がmeta computation側にあるか処理側にあるかの分離などが可能となる.
86 しかしC言語などを用いたプログラミングでmeta computationの分離を行おうとすると,それぞれ事細かに関数やクラスを分割せねばならず容易ではない. 85 しかしC言語などを用いたプログラミングでmeta computationの分離を行おうとすると, それぞれ事細かに関数やクラスを分割せねばならず容易ではない.
87 CbCでは関数よりmeta computationを細かく記述する為にCodeGearという単位を導入した. 86 CbCでは関数よりmeta computationを細かく記述する為にCodeGearという単位を導入した.
88 またCodeGearの実行に必要なデータをDataGearという単位で受け渡す. 87 またCodeGearの実行に必要なデータをDataGearという単位で受け渡す.
89 CbCではCodeGear,DataGearを基本単位として記述するプログラミングスタイルを取る. 88 CbCではCodeGear, DataGearを基本単位として記述するプログラミングスタイルを取る.
90 89
91 \subsection{CodeGearとDataGear} 90 \subsection{CodeGearとDataGear}
92 CbCではCの関数の代わりにCodeGearを導入する. 91 CbCではCの関数の代わりにCodeGearを導入する.
93 CodeGearはCの関数宣言の型名の代わりに\_\_codeと書くことで 宣言できる. 92 CodeGearはCの関数宣言の型名の代わりに\_\_codeと書くことで 宣言できる.
94 \_\_codeはCbCコンパイラの扱いはvoidと同じ型であるが,CbCプログラミングではCodeGearである事を示す識別子としての意味で利用する. 93 \_\_codeはCbCコンパイラの扱いはvoidと同じ型であるが, CbCプログラミングではCodeGearである事を示す識別子としての意味で利用する.
95 CodeGear間の移動はgoto文によって記述する. 94 CodeGear間の移動はgoto文によって記述する.
96 \lstinputlisting[label=cbcexample, caption=cbc\_example.cbc]{./src/cbc_example.cbc} 95 \lstinputlisting[label=cbcexample, caption=cbc\_example.cbc]{./src/cbc_example.cbc}
97 Code\ref{cbcexample}に示すCbCのコードではmain関数からcs1,cs2に遷移し,最終的にdataの値が2となる. 96 Code\ref{cbcexample}に示すCbCのコードではmain関数からcs1, cs2に遷移し,最終的にdataの値が2となる.
98 CodeGear間の入出力の受け渡しは引数を利用する.この引数は小さなDataGearであると言える. 97 CodeGear間の入出力の受け渡しは引数を利用する.この引数は小さなDataGearであると言える.
99 98
100 \subsection{軽量継続} 99 \subsection{軽量継続}
101 %TBD 100 %TBD
102 CbCでは次のCodeGearに移行する際,Cのgoto文を利用する. 101 CbCでは次のCodeGearに移行する際, Cのgoto文を利用する.
103 通常のCの関数呼び出しの場合,スタックポインタを操作しローカル変数などをスタックに保存する. 102 通常のCの関数呼び出しの場合, スタックポインタを操作しローカル変数などをスタックに保存する.
104 CbCの場合スタックフレームを操作せず,レジスタの値を変更せずそのまま次のCodeGearに遷移する事が可能である. 103 CbCの場合スタックフレームを操作せず, レジスタの値を変更せずそのまま次のCodeGearに遷移する事が可能である.
105 通常Sechemeのcall/ccなどの継続は現在の位置までの情報を環境として所持した状態で遷移する. 104 通常Sechemeのcall/ccなどの継続は現在の位置までの情報を環境として所持した状態で遷移する.
106 対してCbCは環境を持たず遷移する為,通常の継続と比較して軽量であることから軽量継続であると言える. 105 対してCbCは環境を持たず遷移する為, 通常の継続と比較して軽量であることから軽量継続であると言える.
107 CbCは軽量継続を利用するためレジスタレベルでのきめ細やかな実装が可能となっている. 106 CbCは軽量継続を利用するためレジスタレベルでのきめ細やかな実装が可能となっている.
108 107
109 \subsection{現在の実装} 108 \subsection{現在の実装}
110 CbCは現在主要なCコンパイラであるgcc及びllvmをバックエンドとしたclang上の2種類の実装が存在する. 109 CbCは現在主要なCコンパイラであるgcc及びllvmをバックエンドとしたclang上の2種類の実装が存在する.
111 gccはバージョン9.0.0に,clangは7.0.0に対応している. 110 gccはバージョン9.0.0に, clangは7.0.0に対応している.
112 111
113 \subsection{CbCコンパイラのバグ} 112 \subsection{CbCコンパイラのバグ}
114 % 局所変数のポインタを握ったままgotoするとtail callにならない 113 % 局所変数のポインタを握ったままgotoするとtail callにならない
115 CbCコンパイラは現在も開発中であり幾つかのバグが発見されている. 114 CbCコンパイラは現在も開発中であり幾つかのバグが発見されている.
116 まずCodeGear内で宣言した局所変数のポインタを別の変数などで確保した状態でgotoしてしまうとtail call最適化が切られる. 115 まずCodeGear内で宣言した局所変数のポインタを別の変数などで確保した状態でgotoしてしまうとtail call最適化が切られる.
117 これはただの関数呼び出しになってしまう為,直接的な被害はないもののCbCとしての利点が損なわれてしまう. 116 これはただの関数呼び出しになってしまう為, 直接的な被害はないもののCbCとしての利点が損なわれてしまう.
118 また本来は操作しないはずのスタック領域の操作が入ってしまうため,プログラマの意図と反したスタックポインタなのど操作が行われてしまいバグが発生する可能性が存在する. 117 また本来は操作しないはずのスタック領域の操作が入ってしまうため, プログラマの意図と反したスタックポインタなのど操作が行われてしまいバグが発生する可能性が存在する.
119 118
120 \subsection{CbCとCの互換性} 119 \subsection{CbCとCの互換性}
121 CbCコンパイラは内部的に与えられているソースコードがCbCであるかどうかを判断する. 120 CbCコンパイラは内部的に与えられているソースコードがCbCであるかどうかを判断する.
122 この際にCodeGearを利用していない場合は通常のCプログラムとして動作する. 121 この際にCodeGearを利用していない場合は通常のCプログラムとして動作する.
123 その為今回検証するMoarVMのビルドにおいてもCbCで書き換えたソースコードがあるMoarVMと,手を加えていないオリジナルのMoarVMの2種類を同一のCbCコンパイラでビルドする事が可能である. 122 その為今回検証するMoarVMのビルドにおいてもCbCで書き換えたソースコードがあるMoarVMと, 手を加えていないオリジナルのMoarVMの2種類を同一のCbCコンパイラでビルドする事が可能である.
124 123
125 またCからCbCへの遷移時に,再びCの関数に戻るように実装したい場合がある. 124 またCからCbCへの遷移時に, 再びCの関数に戻るように実装したい場合がある.
126 その際は環境付きgotoと呼ばれる手法を取る.これは\_CbC\_return及び\_CbC\_environmentという変数を渡す. 125 その際は環境付きgotoと呼ばれる手法を取る.これは\_CbC\_return及び\_CbC\_environmentという変数を渡す.
127 この変数は\_CbC\_returnが元の環境に戻る際に利用するCodeGearを指し,\_CbC\_environmentは復帰時に戻す元の環境である. 126 この変数は\_CbC\_returnが元の環境に戻る際に利用するCodeGearを指し, \_CbC\_environmentは復帰時に戻す元の環境である.
128 復帰する場合,呼び出した位置には帰らず,呼び出した関数の終了する位置に帰る. 127 復帰する場合, 呼び出した位置には帰らず,呼び出した関数の終了する位置に帰る.
129 \lstinputlisting[label=cbcreturn, caption=環境付き継続の例]{./src/return.cbc} 128 \lstinputlisting[label=cbcreturn, caption=環境付き継続の例]{./src/return.cbc}
130 Code\ref{cbcreturn}に示す例ではc\_funcから環境付き継続でがcsに継続している. 129 Code\ref{cbcreturn}に示す例ではc\_funcから環境付き継続でがcsに継続している.
131 通常c\_funcの返り値は-1であるが,csから環境付き継続でmainに帰る為にcsから渡される1がtestの値となる. 130 通常c\_funcの返り値は-1であるが, csから環境付き継続でmainに帰る為にcsから渡される1がtestの値となる.
132 131
133 132
134 \subsection{言語処理系におけるCbCの応用} 133 \subsection{言語処理系におけるCbCの応用}
135 CbCを言語処理系,特にスクリプト言語に応用すると幾つかの箇所に置いて利点があると推測される. 134 CbCを言語処理系, 特にスクリプト言語に応用すると幾つかの箇所に置いて利点があると推測される.
136 CbCにおけるCodeGearはコンパイラの基本ブロックに相当する. 135 CbCにおけるCodeGearはコンパイラの基本ブロックに相当する.
137 その為従来のスクリプト言語では主にcase文で記述していた命令コードディスパッチの箇所をCodeGearの遷移として記述する事が可能である. 136 その為従来のスクリプト言語では主にcase文で記述していた命令コードディスパッチの箇所をCodeGearの遷移として記述する事が可能である.
138 CbCは状態を単位として記述が可能であるため,命令コードなどにおける状態を利用するスクリプト言語の実装は応用例として適していると考えられる. 137 CbCは状態を単位として記述が可能であるため, 命令コードなどにおける状態を利用するスクリプト言語の実装は応用例として適していると考えられる.
139 138
140 \section{Perl6の概要} 139 \section{Perl6の概要}
141 この章では現在までのPerl6の遍歴及びPerl6の言語的な特徴について記載する. 140 この章では現在までのPerl6の遍歴及びPerl6の言語的な特徴について記載する.
142 \subsection{Perl6の構想と初期の処理系} 141 \subsection{Perl6の構想と初期の処理系}
143 Perl6は2002年にLarryWallがPerlを置き換える言語として設計を開始した. 142 Perl6は2002年にLarryWallがPerlを置き換える言語として設計を開始した.
144 Perl5の言語的な問題点であるオブジェクト指向機能の強力なサポートなどを取り入れた言語として設計された. 143 Perl5の言語的な問題点であるオブジェクト指向機能の強力なサポートなどを取り入れた言語として設計された.
145 Perl5は設計と実装が同一であり,Larryらによって書かれたC実装のみだった.Perl6は設計と実装が分離しており様々な処理系が開発されてきた. 144 Perl5は設計と実装が同一であり, Larryらによって書かれたC実装のみだった.Perl6は設計と実装が分離しており様々な処理系が開発されてきた.
146 まず2005年に唐鳳によってHaskellで実装されたPugs\cite{pugs}が登場した. 145 まず2005年に唐鳳によってHaskellで実装されたPugs\cite{pugs}が登場した.
147 Pugsは最初に登場したPerl6実装であり,この実装を基にしてPerl6の仕様も修正された. 146 Pugsは最初に登場したPerl6実装であり, この実装を基にしてPerl6の仕様も修正された.
148 現在Pugsは歴史的な実装となっており,更新はされていない. 147 現在Pugsは歴史的な実装となっており, 更新はされていない.
149 148
150 \subsection{Parrot} 149 \subsection{Parrot}
151 その後Pythonとの共同動作環境としてParrot\cite{parrot}が実装された. 150 その後Pythonとの共同動作環境としてParrot\cite{parrot}が実装された.
152 ParrotはPASMと呼ばれるバイトコードを解釈可能なレジスタマシンである. 151 ParrotはPASMと呼ばれるバイトコードを解釈可能なレジスタマシンである.
153 ParrotでのPerl6の実装はNQP(NotQuitPerl)と呼ばれるPerl6のサブセットでPerl6を記述するというアイディアの基実装された. 152 ParrotでのPerl6の実装はNQP(NotQuitPerl)と呼ばれるPerl6のサブセットでPerl6を記述するというアイディアの基実装された.
154 ParrotVMは2006年のversion8.1.0が最後のリリースである. 153 ParrotVMは2006年のversion8.1.0が最後のリリースである.
155 こちらもPugsと同様に現在のPerl6プロジェクトでは歴史的な実装とされている. 154 こちらもPugsと同様に現在のPerl6プロジェクトでは歴史的な実装とされている.
156 現在主に使用されている実装であるRakudoは2010年にRakudo-Starという一連のツール郡としてリリースされた. 155 現在主に使用されている実装であるRakudoは2010年にRakudo-Starという一連のツール郡としてリリースされた.
157 156
158 Perl6は言語仕様及び処理実装がPerl5と大幅に異なっており,言語的な互換性が存在しない. 157 Perl6は言語仕様及び処理実装がPerl5と大幅に異なっており, 言語的な互換性が存在しない.
159 従って現在ではPerl6とPerl5は別言語としての開発方針になっている. 158 従って現在ではPerl6とPerl5は別言語としての開発方針になっている.
160 Perl6は現在有力な処理系であるRakudoから名前を取りRakuという別名がつけられている. 159 Perl6は現在有力な処理系であるRakudoから名前を取りRakuという別名がつけられている.
161 160
162 \subsection{Rakudo} 161 \subsection{Rakudo}
163 162
164 RakudoとはParrotで構想に上がったNQP,NQPに基づくPerl6を基にしたプロジェクトである. 163 RakudoとはParrotで構想に上がったNQP, NQPに基づくPerl6を基にしたプロジェクトである.
165 RakudoがPerl6のコンパイラかつインタプリタであると考えても良い. 164 RakudoがPerl6のコンパイラかつインタプリタであると考えても良い.
166 Rakudoは図\ref{fig:perl6construction}に示す構成になっている. 165 Rakudoは図\ref{fig:perl6construction}に示す構成になっている.
167 Rakudoにおけるコンパイラとは厳密には2種類存在する. 166 Rakudoにおけるコンパイラとは厳密には2種類存在する.
168 まず第1のものがPerl6,もしくはNQPをMoarVM,JVMのバイトコードに変換するNQPコンパイラである. 167 まず第1のものがPerl6, もしくはNQPをMoarVM,JVMのバイトコードに変換するNQPコンパイラである.
169 次にそのNQPが出力したバイトコードをネイティブコードに変換するVMの2種類である. 168 次にそのNQPが出力したバイトコードをネイティブコードに変換するVMの2種類である.
170 このVMは現在MoarVM,JavaVM,Javascriptを選択可能である. 169 このVMは現在MoarVM, JavaVM,Javascriptを選択可能である.
171 Rakudo及びNQP projectではこのNQPコンパイラの部分をフロントエンド,VMの部分をバックエンド\cite{rani1}と呼称している. 170 Rakudo及びNQP projectではこのNQPコンパイラの部分をフロントエンド, VMの部分をバックエンド\cite{rani1}と呼称している.
172 NQPで主に書かれ,MoarVMなどNQPが動作する環境で動くPerl6のことをRakudoと呼ぶ. 171 NQPで主に書かれ, MoarVMなどNQPが動作する環境で動くPerl6のことをRakudoと呼ぶ.
173 Perl6はNQP以外にものNQPを拡張したPerl6自身で書かれている箇所が存在し,これはNQPコンパイラ側でMoarVMが解釈可能な形へ変換を行う. 172 Perl6はNQP以外にものNQPを拡張したPerl6自身で書かれている箇所が存在し, これはNQPコンパイラ側でMoarVMが解釈可能な形へ変換を行う.
174 173
175 \begin{figure}[ht] 174 \begin{figure}[ht]
176 \begin{center} 175 \begin{center}
177 \includegraphics[width=70mm]{fig/perl6nqp.pdf} 176 \includegraphics[width=70mm]{fig/perl6nqp.pdf}
178 \end{center} 177 \end{center}
180 \label{fig:perl6construction} 179 \label{fig:perl6construction}
181 \end{figure} 180 \end{figure}
182 181
183 \subsection{NQP} 182 \subsection{NQP}
184 183
185 RakudoにおけるNQP\cite{nqp}は現在MoarVM,JVM上で動作し,MoarVMを一部利用することでNodeJSからも動作させる事が可能である. 184 RakudoにおけるNQP\cite{nqp}は現在MoarVM, JVM上で動作し,MoarVMを一部利用することでNodeJSからも動作させる事が可能である.
186 NQPはPerl6のサブセットであるため主な文法などはPerl6に準拠しているが幾つか異なる点が存在する. 185 NQPはPerl6のサブセットであるため主な文法などはPerl6に準拠しているが幾つか異なる点が存在する.
187 NQPは最終的にはNQP自身でブートストラップする言語であるが,ビルドの最初にはすでに書かれたMoarvMByteCodeを必要とする. 186 NQPは最終的にはNQP自身でブートストラップする言語であるが, ビルドの最初にはすでに書かれたMoarvMByteCodeを必要とする.
188 このMoarVMByteCodeの状態をStage0と言い,ディレクトリ名として設定されている. 187 このMoarVMByteCodeの状態をStage0と言い, ディレクトリ名として設定されている.
189 Perl6の一部はNQPを拡張したもので書かれている為,Rakudoを動作させる為にはMoarVMなどのVM,VMに対応させる様にビルドしたNQPがそれぞれ必要となる. 188 Perl6の一部はNQPを拡張したもので書かれている為, Rakudoを動作させる為にはMoarVMなどのVM,VMに対応させる様にビルドしたNQPがそれぞれ必要となる.
190 現在のNQPではMoarVM,JVMに対応するStage0はそれぞれMoarVMBytecode,jarファイルが用意されており,Javascriptではバイトコードの代わりにランタイム独自のModuleLoaderなどが設計されている. 189 現在のNQPではMoarVM, JVMに対応するStage0はそれぞれMoarVMBytecode,jarファイルが用意されており,Javascriptではバイトコードの代わりにランタイム独自のModuleLoaderなどが設計されている.
191 MoarVMのModuleLoaderはStage0にあるMoarVMBytecodeで書かれた一連のファイルが該当する. 190 MoarVMのModuleLoaderはStage0にあるMoarVMBytecodeで書かれた一連のファイルが該当する.
192 191
193 192
194 Stage0にあるファイルをMoarVMに与えることでnqpのインタプリタが実行される様になっている. 193 Stage0にあるファイルをMoarVMに与えることでnqpのインタプリタが実行される様になっている.
195 これはStage0の一連のファイルはMoarVMBytecodeなどで記述されたNQPコンパイラのモジュールである為である. 194 これはStage0の一連のファイルはMoarVMBytecodeなどで記述されたNQPコンパイラのモジュールである為である.
196 NQPは6modelと呼ばれるオブジェクトモデルを採用としているが,これを構築する為に必要なNQPCORE,正規表現系のQRegex,MoarVMのModuleLoaderなどがMoarVMBytecodeで記述されている.これらMoarVMBytecodeの拡張子は.MoarVMである. 195 NQPは6modelと呼ばれるオブジェクトモデルを採用としているが, これを構築する為に必要なNQPCORE,正規表現系のQRegex,MoarVMのModuleLoaderなどがMoarVMBytecodeで記述されている.これらMoarVMBytecodeの拡張子は.MoarVMである.
197 MoarVMに対してStage0のディレクトリにライブラリパスを設定し,nqp.MoarVMを実行させることでnqpの対話型環境が起動する. 196 MoarVMに対してStage0のディレクトリにライブラリパスを設定し, nqp.MoarVMを実行させることでnqpの対話型環境が起動する.
198 197
199 \begin{figure}[ht] 198 \begin{figure}[ht]
200 \begin{center} 199 \begin{center}
201 \includegraphics[width=70mm]{fig/stagenqp.pdf} 200 \includegraphics[width=70mm]{fig/stagenqp.pdf}
202 \end{center} 201 \end{center}
204 \label{fig:nqpbuild} 203 \label{fig:nqpbuild}
205 \end{figure} 204 \end{figure}
206 205
207 NQPのビルドフローを図\ref{fig:nqpbuild}に示す. 206 NQPのビルドフローを図\ref{fig:nqpbuild}に示す.
208 実際にperl6を動かすためにはself buildしたNQPコンパイラが必要となる.その為にstage0を利用してStage1をビルドしNQPコンパイラを作成する. 207 実際にperl6を動かすためにはself buildしたNQPコンパイラが必要となる.その為にstage0を利用してStage1をビルドしNQPコンパイラを作成する.
209 Stage1は中間的な出力であり,生成されたNQPファイルはStage2と同一であるが,MoarVMBytecodeが異なる. 208 Stage1は中間的な出力であり, 生成されたNQPファイルはStage2と同一であるが,MoarVMBytecodeが異なる.
210 Perl6では完全なセルフコンパイルを実行したNQPが要求される為,Stage1を利用してもう一度ビルドを行いStage2を作成する. 209 Perl6では完全なセルフコンパイルを実行したNQPが要求される為, Stage1を利用してもう一度ビルドを行いStage2を作成する.
211 210
212 Perl6のテストスイートである「Roast\cite{roast}」やドキュメントなどによって設計が定まっているPerl6とは異なりNQP自身の設計は今後も変更になる可能性が開発者から公表されている. 211 Perl6のテストスイートである「Roast\cite{roast}」やドキュメントなどによって設計が定まっているPerl6とは異なりNQP自身の設計は今後も変更になる可能性が開発者から公表されている.
213 現在の公表されているNQPのオペコードはNQPのリポジトリ\cite{nqpopcode}に記述されているものである. 212 現在の公表されているNQPのオペコードはNQPのリポジトリ\cite{nqpopcode}に記述されているものである.
214 213
215 214
216 \subsection{Rakudo Perl6} 215 \subsection{Rakudo Perl6}
217 Rakudo実装上におけるPerl6はRakudo Perl6と呼ばれているGitリポジトリで管理されているプログラムのことである. 216 Rakudo実装上におけるPerl6はRakudo Perl6と呼ばれているGitリポジトリで管理されているプログラムのことである.
218 前述した通りRakudo Perl6はPerl6のサブセットであるNQPを用いて記述されている. 217 前述した通りRakudo Perl6はPerl6のサブセットであるNQPを用いて記述されている.
219 従ってyaccやlexと言ったPerl5の文字解析,構文解析に利用していたプログラムは利用せず,NQP側で構文定義などを行っている. 218 従ってyaccやlexと言ったPerl5の文字解析, 構文解析に利用していたプログラムは利用せず,NQP側で構文定義などを行っている.
220 NQPはNQP自身でBootstrappingされている為,Rakudo Perl6のbuild時にはNQPの実行環境として要したVM,それに基づいてbuildしたNQPがそれぞれ必要となる. 219 NQPはNQP自身でBootstrappingされている為, Rakudo Perl6のbuild時にはNQPの実行環境として要したVM,それに基づいてbuildしたNQPがそれぞれ必要となる.
221 220
222 言語的な特徴としては独自にPerl6の文法を拡張可能なGrammer,Perl5と比較した場合のオブジェクト指向言語としての進化も見られる. 221 言語的な特徴としては独自にPerl6の文法を拡張可能なGrammer, Perl5と比較した場合のオブジェクト指向言語としての進化も見られる.
223 またPerl6は漸進的型付け言語である. 222 またPerl6は漸進的型付け言語である.
224 従来のPerlの様に変数に代入する対象の型や文脈に応じて型を変更する動的型言語としての側面を持ちつつ独自に定義した型を始めとする様々な型に静的に変数の型を設定する事が可能である. 223 従来のPerlの様に変数に代入する対象の型や文脈に応じて型を変更する動的型言語としての側面を持ちつつ独自に定義した型を始めとする様々な型に静的に変数の型を設定する事が可能である.
225 224
226 225
227 \subsection{現在のPerl6} 226 \subsection{現在のPerl6}
228 Perl6の言語仕様\cite{perl6design}とその時点での実装状況をまとめた公式ドキュメント\cite{perl6doc}は分離している. 227 Perl6の言語仕様\cite{perl6design}とその時点での実装状況をまとめた公式ドキュメント\cite{perl6doc}は分離している.
229 従来は言語仕様は自然言語の仕様書であったが,現在はテストスイートである「Roast\cite{roast}」そのものと定義されている. 228 従来は言語仕様は自然言語の仕様書であったが, 現在はテストスイートである「Roast\cite{roast}」そのものと定義されている.
230 現在のPerl6の仕様を読む場合Roastを確認し,現在rakudo上に実装されている機能を見る場合は公式ドキュメントを確認する必要がある. 229 現在のPerl6の仕様を読む場合Roastを確認し, 現在rakudo上に実装されている機能を見る場合は公式ドキュメントを確認する必要がある.
231 230
232 \subsection{処理速度} 231 \subsection{処理速度}
233 現在のPerl6が他のプログラミング言語と比較した場合どのような違いがでるのか計測した. 232 現在のPerl6が他のプログラミング言語と比較した場合どのような違いがでるのか計測した.
234 mac osの/var/log/system.logファイルから正規表現でログ中のプログラムが書き込んだ回数を個別に数え上げるというものである. 233 mac osの/var/log/system.logファイルから正規表現でログ中のプログラムが書き込んだ回数を個別に数え上げるというものである.
235 今回はファイルを231Kと3GBの二種類用意し,どの様な違いが出るのか測定した. 234 今回はファイルを231Kと3GBの二種類用意し, どの様な違いが出るのか測定した.
236 235
237 測定した環境は次の通りである. 236 測定した環境は次の通りである.
238 237
239 \begin{itemize} 238 \begin{itemize}
240 \item Perl6 (MoarVM) ver.2018.04.01 239 \item Perl6 (MoarVM) ver.2018.04.01
252 231K & 0.86 & 21.48 & 0.06 & 0.27 & 0.04 \\ 251 231K & 0.86 & 21.48 & 0.06 & 0.27 & 0.04 \\
253 3G & 2331.08 & 1665.56 & 101.16 & 48.85 & 41.35\\ \hline 252 3G & 2331.08 & 1665.56 & 101.16 & 48.85 & 41.35\\ \hline
254 \end{tabular} 253 \end{tabular}
255 \end{table} 254 \end{table}
256 255
257 計測結果からファイルサイズが小さい場合はMoarVMよりJVMに乗せたPerl6が低速であるが,ファイルサイズが大きい場合はJavaのJITが働くためMoarVMより高速に動いていると推測できる. 256 計測結果からファイルサイズが小さい場合はMoarVMよりJVMに乗せたPerl6が低速であるが, ファイルサイズが大きい場合はJavaのJITが働くためMoarVMより高速に動いていると推測できる.
258 257
259 %# 計測(3GB) 258 %# 計測(3GB)
260 259
261 %* Perl5c 260 %* Perl5c
262 % * 41.35s 261 % * 41.35s
287 % * 21.48s 286 % * 21.48s
288 287
289 288
290 \section{CbCによるMoarVM} 289 \section{CbCによるMoarVM}
291 この章では改良を行ったPerl6処理系であるMoarVMについて述べる. 290 この章では改良を行ったPerl6処理系であるMoarVMについて述べる.
292 今回改良を行ったMoarVMは2018.04.01,nqpは2018.04-3-g45ab6e3バージョンで行っている. 291 今回改良を行ったMoarVMは2018.04.01, nqpは2018.04-3-g45ab6e3バージョンで行っている.
293 \subsection{方針} 292 \subsection{方針}
294 MoarVMそのものをCbCで書き換えることも考えられるがMoarVM自体既に巨大なプロジェクトである為すべてを書き換える事は困難である. 293 MoarVMそのものをCbCで書き換えることも考えられるがMoarVM自体既に巨大なプロジェクトである為すべてを書き換える事は困難である.
295 その為まず比較的CbCで書き換えることが容易な箇所を修正する. 294 その為まず比較的CbCで書き換えることが容易な箇所を修正する.
296 前章までに述べた通りCbCのCodeGearはコンパイラの基本ブロックに該当する. 295 前章までに述べた通りCbCのCodeGearはコンパイラの基本ブロックに該当する.
297 従ってMoarVMにおける基本ブロックの箇所をCodeGearに書き換える事が可能である. 296 従ってMoarVMにおける基本ブロックの箇所をCodeGearに書き換える事が可能である.
298 MoarVMにおける基本ブロックはインタプリタが実行するバイトコードごとの処理に該当する. 297 MoarVMにおける基本ブロックはインタプリタが実行するバイトコードごとの処理に該当する.
299 298
300 \subsection{MoarByteCodeのディスパッチ} 299 \subsection{MoarByteCodeのディスパッチ}
301 MoarVMのバイトコードインタプリタはsrc/core/interp.cで定義されている. 300 MoarVMのバイトコードインタプリタはsrc/core/interp.cで定義されている.
302 この中の関数MVM\_interp\_runで命令に応じた処理を実行する. 301 この中の関数MVM\_interp\_runで命令に応じた処理を実行する.
303 関数内では命令列が保存されているcur\_op,現在と次の命令を指し示すop,Threadの環境が保存されているThreadcontextなどの変数を利用する. 302 関数内では命令列が保存されているcur\_op, 現在と次の命令を指し示すop,Threadの環境が保存されているThreadcontextなどの変数を利用する.
304 命令実行は大きく二種類の動作があり,Code\ref{orig_macro}に示すCのgotoが利用できる場合はMVM\_CGOTOフラグが立ちラベル遷移を利用する. 303 命令実行は大きく二種類の動作があり, Code\ref{orig_macro}に示すCのgotoが利用できる場合はMVM\_CGOTOフラグが立ちラベル遷移を利用する.
305 それ以外の場合は巨大なcase文として命令を実行する. 304 それ以外の場合は巨大なcase文として命令を実行する.
306 305
307 ラベル遷移を利用する場合はラベルテーブルにアクセスし,テーブルに登録されているアドレスを取得し,マクロNEXTで遷移する. 306 ラベル遷移を利用する場合はラベルテーブルにアクセスし, テーブルに登録されているアドレスを取得し,マクロNEXTで遷移する.
308 Code\ref{cbc_dispatch_c}に示すno\_opは何もせず次の命令に移動する為,NEXTのみ記述されている. 307 Code\ref{cbc_dispatch_c}に示すno\_opは何もせず次の命令に移動する為, NEXTのみ記述されている.
309 308
310 このラベルテーブルの中身はラベルが変換されたアドレスであるため,実際に呼ばれている命令コードの名前はデバッガレベルでは確認できない. 309 このラベルテーブルの中身はラベルが変換されたアドレスであるため, 実際に呼ばれている命令コードの名前はデバッガレベルでは確認できない.
311 Cレベルでのデバッグ時にはアドレスと実際に呼ばれる箇所を確認する事に手間がかかる. 310 Cレベルでのデバッグ時にはアドレスと実際に呼ばれる箇所を確認する事に手間がかかる.
312 巨大なcase文として実行された場合,実行時間が遅いだけでなく,ラベル遷移と共存させて記述を行っている為Cのソースコードにおける可読性も低下する. 311 巨大なcase文として実行された場合, 実行時間が遅いだけでなく,ラベル遷移と共存させて記述を行っている為Cのソースコードにおける可読性も低下する.
313 312
314 313
315 \lstinputlisting[label=orig_macro, caption=interp.cのマクロ部分]{./src/orig_macro.c} 314 \lstinputlisting[label=orig_macro, caption=interp.cのマクロ部分]{./src/orig_macro.c}
316 315
317 \lstinputlisting[label=dispatch_c, caption=オリジナル版MoarVMのバイトコードディスパッチ]{./src/dispatch.c} 316 \lstinputlisting[label=dispatch_c, caption=オリジナル版MoarVMのバイトコードディスパッチ]{./src/dispatch.c}
318 317
319 interp.cでは命令コードのディスパッチはマクロを利用したcur\_opの計算及びラベルの遷移,もしくはマクロDISPATCHが展開するswitch文で行われていた. 318 interp.cでは命令コードのディスパッチはマクロを利用したcur\_opの計算及びラベルの遷移, もしくはマクロDISPATCHが展開するswitch文で行われていた.
320 CbCMoarVMではこの問題を解決するために,それぞれの命令に対応するCodeGearを作成し,CodeGear名前を要素として持つCbCのCodeGearのテーブルを作成した. 319 CbCMoarVMではこの問題を解決するために, それぞれの命令に対応するCodeGearを作成し,CodeGear名前を要素として持つCbCのCodeGearのテーブルを作成した.
321 このCodeGearのテーブルを参照するCodeGearはcbc\_nextであり,この中のマクロNEXTはinterp.cのマクロNEXTをCbC用に書き直したものである. 320 このCodeGearのテーブルを参照するCodeGearはcbc\_nextであり, この中のマクロNEXTはinterp.cのマクロNEXTをCbC用に書き直したものである.
322 321
323 \lstinputlisting[label=cbc_dispatch_c, caption=CbCMoarVMのバイトコードディスパッチ]{./src/cbc-interp-next.cbc} 322 \lstinputlisting[label=cbc_dispatch_c, caption=CbCMoarVMのバイトコードディスパッチ]{./src/cbc-interp-next.cbc}
324 323
325 \subsection{命令実行箇所のCodeGearへの変換} 324 \subsection{命令実行箇所のCodeGearへの変換}
326 ラベルテーブルやcase文のswitch相当の命令実行箇所をCbCに変換し,CodeGearの遷移として利用する. 325 ラベルテーブルやcase文のswitch相当の命令実行箇所をCbCに変換し, CodeGearの遷移として利用する.
327 interp.cはCode\ref{dispatch_c}に示すスタイルで記述されている. 326 interp.cはCode\ref{dispatch_c}に示すスタイルで記述されている.
328 327
329 328
330 329
331 OP(.*)の.*に該当する箇所はバイトコードの名前である.通常このブロックにはLABELから遷移する為,バイトコードの名前はLABELSの配列の添字に変換されている. 330 OP(.*)の.*に該当する箇所はバイトコードの名前である.通常このブロックにはLABELから遷移する為, バイトコードの名前はLABELSの配列の添字に変換されている.
332 そのため対象となるCodeGearをLABLESの並びと対応させ,CodeGearの配列CODESとして設定すればCodeGearの名前は問わない. 331 そのため対象となるCodeGearをLABLESの並びと対応させ, CodeGearの配列CODESとして設定すればCodeGearの名前は問わない.
333 今回はCodeGearである事を示す為にsuffixとしてcbc\_をつける. 332 今回はCodeGearである事を示す為にsuffixとしてcbc\_をつける.
334 333
335 334
336 命令の実行処理でMoarVMのレジスタであるreg\_baseや命令列cur\_opなどの情報を利用しているが,これらはMVM\_interp\_run内のローカル変数として利用している. 335 命令の実行処理でMoarVMのレジスタであるreg\_baseや命令列cur\_opなどの情報を利用しているが, これらはMVM\_interp\_run内のローカル変数として利用している.
337 ラベルを利用しているオリジナル版では同一関数内であるためアクセス可能であるが,CodeGear間の移動で命令を表現するCbCではアクセスできない. 336 ラベルを利用しているオリジナル版では同一関数内であるためアクセス可能であるが, CodeGear間の移動で命令を表現するCbCではアクセスできない.
338 その為インタプリタの情報を集約した構造体interを定義し,この構造体へのポインタであるINTERP型の変数iをCodeGearの入出力として与える. 337 その為インタプリタの情報を集約した構造体interを定義し, この構造体へのポインタであるINTERP型の変数iをCodeGearの入出力として与える.
339 CodeGear内ではINTERPを経由することでインタプリタの各種情報にアクセスする. 338 CodeGear内ではINTERPを経由することでインタプリタの各種情報にアクセスする.
340 CodeGear間の遷移ではレジスタの値の調整は行われない為,入力引数を使ってレジスタマッピングを管理できる. 339 CodeGear間の遷移ではレジスタの値の調整は行われない為, 入力引数を使ってレジスタマッピングを管理できる.
341 その為INTERPのメンバであるMoarVMのレジスタそのものをアーキテクチャのレジスタ上に乗せる事が可能である. 340 その為INTERPのメンバであるMoarVMのレジスタそのものをアーキテクチャのレジスタ上に乗せる事が可能である.
342 341
343 命令実行中のCodeGearの遷移を図\ref{fig:perl6cbcinter}に示す. 342 命令実行中のCodeGearの遷移を図\ref{fig:perl6cbcinter}に示す.
344 この中で実線で書かれている部分はCbCのgoto文で遷移し,波線の箇所は通常のCの関数呼び出しとなっている. 343 この中で実線で書かれている部分はCbCのgoto文で遷移し, 波線の箇所は通常のCの関数呼び出しとなっている.
345 344
346 現在のCbCMoarVMは次の命令セットのディスパッチをcbc\_nextが行っていた. 345 現在のCbCMoarVMは次の命令セットのディスパッチをcbc\_nextが行っていた.
347 その為cbc\_nextから命令コードに対応するCodeGearに継続し,CodeGearからcbc\_nextに継続するサイクルが基本の流れである. 346 その為cbc\_nextから命令コードに対応するCodeGearに継続し, CodeGearからcbc\_nextに継続するサイクルが基本の流れである.
348 CodeGear内からCの関数は問題なく呼ぶ事が可能であるため,Cの関数を利用する処理は変更せず記述する事ができる. 347 CodeGear内からCの関数は問題なく呼ぶ事が可能であるため, Cの関数を利用する処理は変更せず記述する事ができる.
349 また変換対象はswitch文であるため,breakせず次のcaseに移行した場合に対応するように別のCodeGearに継続し,その後cbc\_nextに継続するパターンも存在する. 348 また変換対象はswitch文であるため, breakせず次のcaseに移行した場合に対応するように別のCodeGearに継続し,その後cbc\_nextに継続するパターンも存在する.
350 349
351 \lstinputlisting[label=cbc_codesegs_c, caption=CbCMoarVMのバイトコードに対応するCodeGear]{./src/cbc_codesegs.cbc} 350 \lstinputlisting[label=cbc_codesegs_c, caption=CbCMoarVMのバイトコードに対応するCodeGear]{./src/cbc_codesegs.cbc}
352 351
353 \begin{figure}[ht] 352 \begin{figure}[ht]
354 \begin{center} 353 \begin{center}
355 \includegraphics[width=70mm]{fig/cbc_next.pdf} 354 \includegraphics[width=70mm]{fig/cbc_next.pdf}
356 \end{center} 355 \end{center}
357 \caption{CbCにおけるMoarVMバイトコードインタプリタ内の状態遷移} 356 \caption{CbCにおけるMoarVMバイトコードインタプリタ内の状態遷移}
358 \label{fig:perl6cbcinter} 357 \label{fig:perl6cbcinter}
359 \end{figure} 358 \end{figure}
360 359
361 バイトコードの数は膨大である為,すべてを手作業で変換する事は望ましくない. 360 バイトコードの数は膨大である為, すべてを手作業で変換する事は望ましくない.
362 本研究ではPerlScriptを用いてinterp.cからCbCのCodeGearを自動生成するスクリプトを作成した. 361 本研究ではPerlScriptを用いてinterp.cからCbCのCodeGearを自動生成するスクリプトを作成した.
363 このスクリプトでは以下の修正手続きを実行する. 362 このスクリプトでは以下の修正手続きを実行する.
364 363
365 \begin{itemize} 364 \begin{itemize}
366 \item OP(.*)の.*部分をCodeGearの名前として,先頭にcbc\_をつけた上で設定する. 365 \item OP(.*)の.*部分をCodeGearの名前として, 先頭にcbc\_をつけた上で設定する.
367 \item cur\_opなど構造体INTERのメンバ変数はポインタiから参照するように修正する 366 \item cur\_opなど構造体INTERのメンバ変数はポインタiから参照するように修正する
368 \item GC対策のためマクロMVMROOTを使い局所変数のポインタをスタックに積む箇所は,局所変数をstatic化する 367 \item GC対策のためマクロMVMROOTを使い局所変数のポインタをスタックに積む箇所は, 局所変数をstatic化する
369 \item 末尾のgoto NEXTをgoto cbc\_next(i)に修正する 368 \item 末尾のgoto NEXTをgoto cbc\_next(i)に修正する
370 \item case文で下のcase文に落ちている箇所は,case文に対応するCodeGearに遷移する様にgoto文を付け加える 369 \item case文で下のcase文に落ちている箇所は, case文に対応するCodeGearに遷移する様にgoto文を付け加える
371 \end{itemize} 370 \end{itemize}
372 371
373 372
374 上記Code\ref{cbc_codesegs_c}ではcbc\_const\_i8などがcase文の下のcase部分に該当するcbc\_const\_i64に遷移する様に変換されている. 373 上記Code\ref{cbc_codesegs_c}ではcbc\_const\_i8などがcase文の下のcase部分に該当するcbc\_const\_i64に遷移する様に変換されている.
375 またcbc\_pushcompscではMVMROOTに局所変数scを渡している為,これをstaticで宣言し直している. 374 またcbc\_pushcompscではMVMROOTに局所変数scを渡している為, これをstaticで宣言し直している.
376 375
377 現在CbCで記述されたOSであるGearsOSにはInterfaceが導入されている. 376 現在CbCで記述されたOSであるGearsOSにはInterfaceが導入されている.
378 これはJavaのinterface,Haskellの型クラスに該当する概念であり,次のCodeGearにInterface経由で継続する事が可能である. 377 これはJavaのinterface, Haskellの型クラスに該当する概念であり,次のCodeGearにInterface経由で継続する事が可能である.
379 Interfaceは現在のMoarVMには実装されていない為,今後ThreadeCodeの実装を行うにあたり導入を検討している. 378 Interfaceは現在のMoarVMには実装されていない為, 今後ThreadeCodeの実装を行うにあたり導入を検討している.
380
381 \subsection{Threaded Code}
382 現在のMoarVMは次の命令をバイトコードからディスパッチし決定後,ラベルジャンプを利用し実行している.
383 この処理ではディスパッチの箇所にコストが掛かってしまう.
384 CbCをMoarVMに導入することで,バイトコード列を直接サブルーチンコールの列に置き換えてしまう事が可能である.
385 これはCbCが基本ブロックの単位と対応している為である.
386 CbCでは現在ディスパッチを行うCodeGearであるcbc\_nextを利用しているが,Threaded Codeを実装するにあたり,
387 cbc\_nextと次のCodeGearに直接遷移するcbc\_fixt\_nextの実装を予定している.
388
389 また段階的に現在8バイト列を1命令コードとして使用しているが,これを16バイトなどに拡張し2命令を同時に扱えるように実装する事なども検討している.
390
391 %CbCはCodeGearで末尾最適化(Tail call optimization)を行う.
392 %これはCodeGearは必ず関数呼び出しではなくgotoで次の状態に遷移する為にスタック領域の操作が必要とならない為である.
393 %現在のCbCコンパイラの実装ではCodeGearからCの関数に戻る場合は末尾最適化を切り,CodeSegment間の遷移では末尾最適化が行われる.
394 %末尾最適化を応用することでContinuation-passingスタイルのThreaded Codeの実装が可能となる.\cite{threadedcode}
395 %またCodeGear自体を直接次の遷移先として設定することも可能であるため,CbCならThrededCodeを実装するアプローチが複数検討出来る.
396
397 %現在のCbCMoarVMは次の命令セットのディスパッチをcbc\_nextというCodeGearで処理している.
398 %これは元のMoarVMの命令ディスパッチで行われる現在のオペコードを示すcur\_opと命令列opの操作及び次のラベルに遷移するマクロに該当する.
399 %CbCMoarVMではラベルに対しての遷移の代わりにMoarVMの命令のCodeGearの集合体である配列CODESにアクセスし,その要素であるCodeSegmentに対して遷移する形を取っている.
400 %この一連の処理がオーバーヘッドになる為,今後はcbc\_fixt\_nextというCodeGearを導入し直接次の命令に該当するCodeSegmentへgotoする様に実装する予定である.
401
402 \subsubsection{perlcc}
403 Perl5においてはperlccというモジュールが開発されている.
404 これはPerl5内部で利用しているPerlバイトコードを,PerlのC APIであるXS言語の様なCのソースファイルに埋め込み,それをCコンパイルでコンパイルするというものである.
405 perlccを利用することでPerlインタプリタが無い状況でも可動するバイナリファイルを作成する事が可能である.
406 しかしPerlccはPerlスクリプトが複雑になるほど正確にCに移植を行う事が出来ず,現在ではPerlのコアモジュールから外されている.
407 PerlccはPerlのバイトコードをCへの変換のみ行う為,Cで実装されているPerl経由で実行した場合と処理速度はほぼ変わらない.
408 またPerlccで生成されたCのソースコードは難解であり,これをデバッグするのが困難でもある.
409 MoarVMでthreaded codeを実現出来た場合,その箇所のみCbCプログラムとして切り出す事が可能である為perlccと似たツールを作成することも可能である.
410 この場合,Perl6を通常動かした際とは異なりバイトコードインタプリタに到達する前の処理が無くなる為多少の高速化が望めると推測できる.
411
412 \subsection{Cのインライン展開}
413 CbCのCodeGearはgoto文で遷移するため,次のCodeGearが一意に決定している場合Cコンパイラ側でインライン展開する事が可能である.
414 CodeGearがインライン展開される限界については別途研究する必要があるが,CbCを利用した場合その箇所でもコストを低く設計する事が可能である.
415 379
416 \section{MoarVMのデバッグ} 380 \section{MoarVMのデバッグ}
417 381
418 MoarVM自体のデバッグはMoarVMのリポジトリにテストコードが付随していない為単体では実行不可能である. 382 MoarVM自体のデバッグはMoarVMのリポジトリにテストコードが付随していない為単体では実行不可能である.
419 本研究ではMoarVMのデバッグにおけるCデバッガの使用方法とMoarVMのテスト方法についても考案する. 383 本研究ではMoarVMのデバッグにおけるCデバッガの使用方法とMoarVMのテスト方法についても考案する.
420   384  
421 \subsection{MoarVMのBytecodeのデバッグ} 385 \subsection{MoarVMのBytecodeのデバッグ}
422 moarに対してMoarVM bytecodeをdumpオプションを付けて読み込ませるとMoarVMのbytecodeがアセンブラの様に出力される. 386 moarに対してMoarVM bytecodeをdumpオプションを付けて読み込ませるとMoarVMのbytecodeがアセンブラの様に出力される.
423 しかしこれはMoarVMが実行したbytecodeのトレースではなくMoarVM bytecodeを変換したものに過ぎない. 387 しかしこれはMoarVMが実行したbytecodeのトレースではなくMoarVM bytecodeを変換したものに過ぎない.
424 また,明らかに異なる挙動を示す両者のmoarを利用しても同じ結果が返ってきてしまう. 388 また, 明らかに異なる挙動を示す両者のmoarを利用しても同じ結果が返ってきてしまう.
425 そのため今回のMoarVMBytecodeインタプリタの実装のデバッグにはこの方法は適さない. 389 そのため今回のMoarVMBytecodeインタプリタの実装のデバッグにはこの方法は適さない.
426 従って実際に実行した命令を確認するにはgdbなどのCデバッガを利用してMoarVMを直接トレースする必要がある. 390 従って実際に実行した命令を確認するにはgdbなどのCデバッガを利用してMoarVMを直接トレースする必要がある.
427 391
428 CbC側はCode\ref{cbc_b}に示す様にcbc\_nextにbreak pointを設定する. 392 CbC側はCode\ref{cbc_b}に示す様にcbc\_nextにbreak pointを設定する.
429 オリジナル側は次のオペコードの設定のマクロにダミーの関数を呼び出すように修正し,そこにbreak pointを設定する. 393 オリジナル側は次のオペコードの設定のマクロにダミーの関数を呼び出すように修正し, そこにbreak pointを設定する.
430 CbC側ではCodeGearの名前をデバッガ上で直接確認できるが,オリジナル版はLABLEの配列の添え字から自分でどのオペコードに対応しているかをデバッガの外で探す必要がある. 394 CbC側ではCodeGearの名前をデバッガ上で直接確認できるが, オリジナル版はLABLEの配列の添え字から自分でどのオペコードに対応しているかをデバッガの外で探す必要がある.
431 395
432 添字を確認するためにはCode\ref{orig_b}に示すようにオリジナルのMoarVMの場合cur\_opの値をMVMuint16のポインタでキャストし,これが指す値を出力する. 396 添字を確認するためにはCode\ref{orig_b}に示すようにオリジナルのMoarVMの場合cur\_opの値をMVMuint16のポインタでキャストし, これが指す値を出力する.
433 break pointを掛けているダミー関数ではcur\_opにアクセスする事が出来ない為,スタックフレームを一つupする必要がある. 397 break pointを掛けているダミー関数ではcur\_opにアクセスする事が出来ない為, スタックフレームを一つupする必要がある.
434 \lstinputlisting[label=cbc_b, caption=CbCMoarVMに対してのbreak point設定]{./src/cbc_breakpoint.txt} 398 \lstinputlisting[label=cbc_b, caption=CbCMoarVMに対してのbreak point設定]{./src/cbc_breakpoint.txt}
435 \lstinputlisting[label=orig_b, caption=オリジナル版MoarVMに対してのbreak point設定]{./src/origin_b_set.txt} 399 \lstinputlisting[label=orig_b, caption=オリジナル版MoarVMに対してのbreak point設定]{./src/origin_b_set.txt}
436 400
437 401
438 \subsection{MoarVMの並列デバッグ手法} 402 \subsection{MoarVMの並列デバッグ手法}
439 しかしMoarVMが実行する命令は膨大な数がある. 403 しかしMoarVMが実行する命令は膨大な数がある.
440 その為gdbでMoarVMをCbCとオリジナル版での並列デバッグを人間が同時に行うことは困難である. 404 その為gdbでMoarVMをCbCとオリジナル版での並列デバッグを人間が同時に行うことは困難である.
441 Perlなどのスクリプトを用いて自動的に解析したいため,ログを残す為にscriptコマンドを実行した状態でgdbを起動する. 405 Perlなどのスクリプトを用いて自動的に解析したいため, ログを残す為にscriptコマンドを実行した状態でgdbを起動する.
442 トレースでは実行した命令名のみ取得できれば良い為,Code\ref{cbc_b},\ref{orig_b}でdebug pointにcommandとして設定している様に,設定されたcur\_opの値を出力し続けるのみの動きを導入する. 406 トレースでは実行した命令名のみ取得できれば良い為, Code\ref{cbc_b}, \ref{orig_b}でdebug pointにcommandとして設定している様に,設定されたcur\_opの値を出力し続けるのみの動きを導入する.
443 407
444 実際に実行したログ・ファイルの一部をそれぞれCode\ref{debug_origmoar},\ref{debug_cbcmoar}に示す. 408 実際に実行したログ・ファイルの一部をそれぞれCode\ref{debug_origmoar}, \ref{debug_cbcmoar}に示す.
445 \lstinputlisting[label=debug_origmoar, caption=オリジナル版MoarVMのバイトコードのトレース]{./src/origin_breakpoint.txt} 409 \lstinputlisting[label=debug_origmoar, caption=オリジナル版MoarVMのバイトコードのトレース]{./src/origin_breakpoint.txt}
446 \lstinputlisting[label=debug_cbcmoar, caption=CbCMoarVMのバイトコードのトレース]{./src/trace_cbc.txt} 410 \lstinputlisting[label=debug_cbcmoar, caption=CbCMoarVMのバイトコードのトレース]{./src/trace_cbc.txt}
447 411
448 オリジナル版では実際に実行する命令処理はラベルに変換されてしまう為名前をデバッガ上では出力できないが,CbCでは出力する事が可能である. 412 オリジナル版では実際に実行する命令処理はラベルに変換されてしまう為名前をデバッガ上では出力できないが, CbCでは出力する事が可能である.
449 CbCとオリジナルのCODES,LABELの添字は対応している為,ログの解析を行う際はそれぞれの添字を抽出し違いが発生している箇所を探索する. 413 CbCとオリジナルのCODES, LABELの添字は対応している為,ログの解析を行う際はそれぞれの添字を抽出し違いが発生している箇所を探索する.
450 これらはscriptコマンドが作成したログを元に異なる箇所を発見するスクリプトを用意し自動化する. 414 これらはscriptコマンドが作成したログを元に異なる箇所を発見するスクリプトを用意し自動化する.(Code \ref{logs2.txt})
451 \lstinputlisting[label=logs2, caption=バイトコードの差分検知の一部分]{./src/logs2.txt} 415 \lstinputlisting[label=logs2.txt, caption=バイトコードの差分検知の一部分]{./src/logs2.txt}
452 416
453 違いが生じている箇所が発見できた場合,その前後のCodeGear及びディスパッチ部分にbreak pointをかけ,それぞれの変数の挙動を比較する. 417 違いが生じている箇所が発見できた場合, その前後のCodeGear及びディスパッチ部分にbreak pointをかけ,それぞれの変数の挙動を比較する.
454 主にcbc\_return系の命令が実行されている場合は,その直前で命令を切り替えるcbc\_invoke系統の命令が呼ばれているが,この周辺で何かしらの違いが発生している可能性が高い. 418 主にcbc\_return系の命令が実行されている場合は, その直前で命令を切り替えるcbc\_invoke系統の命令が呼ばれているが,この周辺で何かしらの違いが発生している可能性が高い.
455 また主に次のCodeGearに遷移する際にCbCコンパイラのバグが生じている可能性もある為,アセンブラレベルの命令を確認しながらデバッグを進めることとなる. 419 また主に次のCodeGearに遷移する際にCbCコンパイラのバグが生じている可能性もある為, アセンブラレベルの命令を確認しながらデバッグを進めることとなる.
456 420
457 \subsection{MoarVMのテスト方法} 421 \subsection{MoarVMのテスト方法}
458 422
459 MoarVMは単体で実行する事が不可能である. 423 MoarVMは単体で実行する事が不可能である.
460 またNQPのリポジトリに付随するテストはnqpで書かれている為,MoarVMのテストはNQPリポジトリのファイルを直接使う場合は出来ない. 424 またNQPのリポジトリに付随するテストはnqpで書かれている為, MoarVMのテストはNQPリポジトリのファイルを直接使う場合は出来ない.
461 今回は正常に動くMoarVM,NQPを用意しnqpを経由してデバッグ 425 今回は正常に動くMoarVM, NQPを用意しnqpを経由してデバッグ
462 426
463 \subsection{CbCコンパイラによるバグ} 427 \subsection{CbCコンパイラによるバグ}
464 現在までのCbCは複数個の入出力をCodeGearに与えるユースケースで利用していた. 428 現在までのCbCは複数個の入出力をCodeGearに与えるユースケースで利用していた.
465 CbCコンパイラ自身はそれぞれ用意したテストスイートを通化するものの,MoarVMの様な巨大なプロジェクトのCSをコンパイルを実行する場合,予期せぬバグが発生した. 429 CbCコンパイラ自身はそれぞれ用意したテストスイートを通化するものの, MoarVMの様な巨大なプロジェクトのCSをコンパイルを実行する場合,予期せぬバグが発生した.
466 主にCodeGear間のgotoにおけるtail callフラグの除去や,DataGearとして渡している構造体の変数のアドレスがスタックポインタの値より上位に来てしまい,通常のCの関数をcallした際にローカル変数の領域がDataGearのアドレスの周辺を利用してしまう. 430 主にCodeGear間のgotoにおけるtail callフラグの除去や, DataGearとして渡している構造体の変数のアドレスがスタックポインタの値より上位に来てしまい,通常のCの関数をcallした際にローカル変数の領域がDataGearのアドレスの周辺を利用してしまう.
467 その為DataGearの構造体の値が書き換わり,CからDataGearにreturnした際にDataGearの構造体が破壊されるバグである. 431 その為DataGearの構造体の値が書き換わり, CからDataGearにreturnした際にDataGearの構造体が破壊されるバグである.
468 このバグは先程の並列デバッグを行いながらプログラムカウンタや変数の動きをトレースする事などで発見することが出来る. 432 このバグは先程の並列デバッグを行いながらプログラムカウンタや変数の動きをトレースする事などで発見することが出来る.
469 現状ではCbCコンパイラがプログラマの意図と反する挙動を取るためCbCコンパイラのバグを回避するプログラミングが要求されている. 433 現状ではCbCコンパイラがプログラマの意図と反する挙動を取るためCbCコンパイラのバグを回避するプログラミングが要求されている.
470 本来コンパイラ側のバグを回避するプログラミングをプログラマに要求する事は好ましくない. 434 本来コンパイラ側のバグを回避するプログラミングをプログラマに要求する事は好ましくない.
471 従ってCbCコンパイラ自身の信頼性を向上させる事も今後の課題となっている. 435 従ってCbCコンパイラ自身の信頼性を向上させる事も今後の課題となっている.
472 436
473 また現在はclang上に実装したCbCコンパイラではCodeGear内部のtaill call除去のエラーが発生してしまう為コンパイルする事が出来ない. 437 また現在はclang上に実装したCbCコンパイラではCodeGear内部のtaill call除去のエラーが発生してしまう為コンパイルする事が出来ない.
474 その為現在はgcc上に実装したcbcコンパイラを利用しgdbを利用しデバッグを行う. 438 その為現在はgcc上に実装したcbcコンパイラを利用しgdbを利用しデバッグを行う.
475 439
476 440
477 \section{CbCを用いる事についての利点と欠点} 441 \section{CbCMoarVMの利点と欠点}
478 MoarVMの様な巨大なスクリプト言語処理系にCbCを適応した所現在までに複数の利点と欠点が発見された. 442 MoarVMの様な巨大なスクリプト言語処理系にCbCを適応した所現在までに複数の利点と欠点が発見された.
479 本章ではまず利点を述べ,次に現段階でのCbCを適応した場合の欠点について考察する. 443 本章ではまず利点を述べ, 次に現段階でのCbCを適応した場合の欠点について考察する.
480 444
481 \subsection{利点} 445
482 \subsection{コード分割} 446 オリジナルのMoarVMでは命令コードに対応する箇所はラベルジャンプ, もしくはswitch文で実装されていた.
483 オリジナルのMoarVMでは命令コードに対応する箇所はラベルジャンプ,もしくはswitch文で実装されていた.
484 その為同じCファイルに命令コードの実行の定義が存在しなければならない. 447 その為同じCファイルに命令コードの実行の定義が存在しなければならない.
485 今後MoarVMに新たなバイトコードが導入されていく事を考えるとinterp.cが巨大になる可能性がある. 448 今後MoarVMに新たなバイトコードが導入されていく事を考えるとinterp.cが巨大になる可能性がある.
486 関数単位での処理の比重が偏る事に加え, 449 関数単位での処理の比重が偏る事に加え,
487 switch文中に書かれている処理は他の関数から呼ぶ事が出来ないため,余計な手間がかかる箇所が発生すると考えられる. 450 switch文中に書かれている処理は他の関数から呼ぶ事が出来ないため, 余計な手間がかかる箇所が発生すると考えられる.
488 451
489 CbCMoarVMの場合,CodeGearとして基本ブロックを記述出来る為オリジナルのMoarVMの様にswtich文のブロック中に書く必要性が無くなる. 452
490 その為類似する命令系をコード分割し,モジュール化する事が可能である. 453 CbCMoarVMの場合, CodeGearとして基本ブロックを記述出来る為オリジナルのMoarVMの様にswtich文のブロック中に書く必要性が無くなる.
454 その為類似する命令系をコード分割し, モジュール化する事が可能である.
491 またCbCはgoto文で遷移する以外は通常のCの関数と同じ扱いをする事が可能である. 455 またCbCはgoto文で遷移する以外は通常のCの関数と同じ扱いをする事が可能である.
492 従ってCodeGear内部の処理を別の箇所から使用する事も可能となる為再利用性も向上する. 456 従ってCodeGear内部の処理を別の箇所から使用する事も可能となる為再利用性も向上する.
493 457
494 \subsection{ThreadeCode} 458
495 ThrededCodeを実装する場合,通常命令ディスパッチの箇所と,実際に実行される命令処理を大幅に変更しなければならない. 459 ThrededCodeを実装する場合, 通常命令ディスパッチの箇所と,実際に実行される命令処理を大幅に変更しなければならない.
496 CbCを用いた実装の場合,命令処理はただのCodeGearの集合である. 460 CbCを用いた実装の場合, 命令処理はただのCodeGearの集合である.
497 その為CodeGearをThrededCodeに対応した並びとして選択する事ができれば命令処理部分の修正をほぼせずにThrededCodeを実現する事が可能である. 461 その為CodeGearをThrededCodeに対応した並びとして選択する事ができれば命令処理部分の修正をほぼせずにThrededCodeを実現する事が可能である.
498 462
499 またCodeGearはバイトコードレベルと同じ扱いができるため,ThrededCodeそのものを分離して最適化をかける事が可能である. 463 またCodeGearはバイトコードレベルと同じ扱いができるため, ThrededCodeそのものを分離して最適化をかける事が可能である.
500 これもCodeGearが関数単位として分離できる事からの利点である. 464 これもCodeGearが関数単位として分離できる事からの利点である.
501 465
502 466
503 \subsubsection{MoarVMのデバッグ}
504 MoarVMのバイトコードインタプリタの箇所はオリジナルの実装ではラベルジャンプを用いて実装されている. 467 MoarVMのバイトコードインタプリタの箇所はオリジナルの実装ではラベルジャンプを用いて実装されている.
505 その為,直接ラベルにbreak pointをかける事が出来ない. 468 その為, 直接ラベルにbreak pointをかける事が出来ない.
506 作業者がデバッガが読み込んでいるCソースコードの位置を把握し,行番号を指定してdebug pointを設定する必要があった. 469 作業者がデバッガが読み込んでいるCソースコードの位置を把握し, 行番号を指定してdebug pointを設定する必要があった.
507 470
508 CbCMoarVMの場合,CodeGear単位でバイトコードの処理単位を記述している為,通常の関数と同じく直接CodeGearにデバッグポイントをかける事が可能である. 471 CbCMoarVMの場合, CodeGear単位でバイトコードの処理単位を記述している為,通常の関数と同じく直接CodeGearにデバッグポイントをかける事が可能である.
509 これはCプログラミングの関数に対してのデバッグで,状態ごとにbreak pointをかける事が出来ることを意味する. 472 これはCプログラミングの関数に対してのデバッグで, 状態ごとにbreak pointをかける事が出来ることを意味する.
510 通常のC言語で言語処理系を実装した場合と比較して扱いやすくなっていると言える. 473 通常のC言語で言語処理系を実装した場合と比較して扱いやすくなっていると言える.
511 さらにラベルテーブルでの管理場合,次のバイトコード箇所は数値でしか確認できず,実際にどこに飛ぶのかはラベルテーブル内と数値を作業者が手作業で確認する必要があった. 474 さらにラベルテーブルでの管理場合, 次のバイトコード箇所は数値でしか確認できず,実際にどこに飛ぶのかはラベルテーブル内と数値を作業者が手作業で確認する必要があった.
512 スクリプトなどを組めば効率化は出来るがデバッガ上で完結しない為手間がかかる. 475 スクリプトなどを組めば効率化は出来るがデバッガ上で完結しない為手間がかかる.
513 CbC実装ではCODESテーブル内は次のCodeGearの名前が入っている為,数値からCodeGearの名前をデバッガ上で確認する事が出来る. 476 CbC実装ではCODESテーブル内は次のCodeGearの名前が入っている為, 数値からCodeGearの名前をデバッガ上で確認する事が出来る
514 477
515 \subsection{JITコンパイルの応用} 478
516 現在MoarVMはLuaJit\cite{luajit}を搭載しJITコンパイルを行っている. 479 現在MoarVMはLuaJit\cite{luajit}を搭載しJITコンパイルを行っている.
517 LuaJITそのものをCbCに適応させるわけではないが,CbCのABIにJITされたコードを合わせる事が可能であると推測できる. 480 LuaJITそのものをCbCに適応させるわけではないが, CbCのABIにJITされたコードを合わせる事が可能であると推測できる.
518 % \subsection{単純なループ処理の測定} 481 % \subsection{単純なループ処理の測定}
519 % 簡単な例題としてfor文を用いて100000回ループさせ,ある変数をインクリメントするというプログラムを作成する. 482 % 簡単な例題としてfor文を用いて100000回ループさせ, ある変数をインクリメントするというプログラムを作成する.
520 % 今回の評価対象としてPerl6は2018年4月にリリースされたMoarVM,NQP,Rakudoの実装を用いる. 483 % 今回の評価対象としてPerl6は2018年4月にリリースされたMoarVM, NQP,Rakudoの実装を用いる.
521 % Perl5は5.26.2を利用した. 484 % Perl5は5.26.2を利用した.
522 485
523 % \begin{table}[htb] 486 % \begin{table}[htb]
524 % \begin{tabular}{|c|c|c|} \hline 487 % \begin{tabular}{|c|c|c|} \hline
525 % ループ回数 & Perl5 (sec) & Perl6(sec) \\ \hline \hline 488 % ループ回数 & Perl5 (sec) & Perl6(sec) \\ \hline \hline
526 % 1000000 & 0.131 & 1.444 \\ \hline 489 % 1000000 & 0.131 & 1.444 \\ \hline
527 % 10000000 & 0.131 & 1.444 \\ \hline 490 % 10000000 & 0.131 & 1.444 \\ \hline
528 % 100000000 & 3.258 & 124.69 \\ \hline 491 % 100000000 & 3.258 & 124.69 \\ \hline
529 % \end{tabular} 492 % \end{tabular}
530 % \end{table} 493 % \end{table}
531 494 本来処理系は広く使われる為に著名なOSSなどを利用して開発するのが良いが, CbCプロジェクトの認知度が低いという現状がある.
532 \subsection{欠点} 495
533 本来処理系は広く使われる為に著名なOSSなどを利用して開発するのが良いが,CbCプロジェクトの認知度が低いという現状がある. 496 また, 前章までに複数述べた通りCbCコンパイラが現在非常にバグを発生させやすい状態になっている.
534 497 CbCコンパイラはgccとllvm/clangに実装している為, これらのアップデートに追従する必要がある.
535 また,前章までに複数述べた通りCbCコンパイラが現在非常にバグを発生させやすい状態になっている. 498 しかしコンパイラのバージョンに応じてCbCで利用するコンパイラ内のAPIが異なる場合が多く, APIの変更に伴う修正作業などを行う必要がある.
536 CbCコンパイラはgccとllvm/clangに実装している為,これらのアップデートに追従する必要がある. 499
537 しかしコンパイラのバージョンに応じてCbCで利用するコンパイラ内のAPIが異なる場合が多く,APIの変更に伴う修正作業などを行う必要がある. 500 CbCMoarVMではCからCodeGearへ, CodeGearからCへの遷移などが複数回繰り返されているが,この処理中のCodeGearでのtail callの強制が非常に難関である.
538 501 tail callの強制には関数定義の箇所や引数, スタック領域のサイズ修正などを行う必要がある.
539 CbCMoarVMではCからCodeGearへ,CodeGearからCへの遷移などが複数回繰り返されているが,この処理中のCodeGearでのtail callの強制が非常に難関である.
540 tail callの強制には関数定義の箇所や引数,スタック領域のサイズ修正などを行う必要がある.
541 現在のバグではCodeGear内部での不要なスタック操作命令を完全に排除しきれていない. 502 現在のバグではCodeGear内部での不要なスタック操作命令を完全に排除しきれていない.
542 503
543 またCodeGearからCに帰る場合,環境付き継続を行う必要がある. 504 またCodeGearからCに帰る場合, 環境付き継続を行う必要がある.
544 Cの関数の末尾でCodeGearを呼び出している場合など環境付き継続を使用しなくても良いケースは存在するが,頻繁にCとCbCを行き来する場合記述が冗長になる可能性はある. 505 Cの関数の末尾でCodeGearを呼び出している場合など環境付き継続を使用しなくても良いケースは存在するが, 頻繁にCとCbCを行き来する場合記述が冗長になる可能性はある.
545 506
546 \section{今後の課題} 507 \section{Threaded Code}
508 現在のMoarVMは次の命令をバイトコードからディスパッチし決定後, ラベルジャンプを利用し実行している.
509 この処理ではディスパッチの箇所にコストが掛かってしまう.
510 CbCをMoarVMに導入することで, バイトコード列を直接サブルーチンコールの列に置き換えてしまう事が可能である.
511 これはCbCが基本ブロックの単位と対応している為である.
512 CbCでは現在ディスパッチを行うCodeGearであるcbc\_nextを利用しているが, Threaded Codeを実装するにあたり,
513 cbc\_nextと次のCodeGearに直接遷移するcbc\_fixt\_nextの実装を予定している.
514
515 また段階的に現在8バイト列を1命令コードとして使用しているが, これを16バイトなどに拡張し2命令を同時に扱えるように実装する事なども検討している.
516
517 %CbCはCodeGearで末尾最適化(Tail call optimization)を行う.
518 %これはCodeGearは必ず関数呼び出しではなくgotoで次の状態に遷移する為にスタック領域の操作が必要とならない為である.
519 %現在のCbCコンパイラの実装ではCodeGearからCの関数に戻る場合は末尾最適化を切り, CodeSegment間の遷移では末尾最適化が行われる.
520 %末尾最適化を応用することでContinuation-passingスタイルのThreaded Codeの実装が可能となる.\cite{threadedcode}
521 %またCodeGear自体を直接次の遷移先として設定することも可能であるため, CbCならThrededCodeを実装するアプローチが複数検討出来る.
522
523 %現在のCbCMoarVMは次の命令セットのディスパッチをcbc\_nextというCodeGearで処理している.
524 %これは元のMoarVMの命令ディスパッチで行われる現在のオペコードを示すcur\_opと命令列opの操作及び次のラベルに遷移するマクロに該当する.
525 %CbCMoarVMではラベルに対しての遷移の代わりにMoarVMの命令のCodeGearの集合体である配列CODESにアクセスし, その要素であるCodeSegmentに対して遷移する形を取っている.
526 %この一連の処理がオーバーヘッドになる為, 今後はcbc\_fixt\_nextというCodeGearを導入し直接次の命令に該当するCodeSegmentへgotoする様に実装する予定である.
527
528 Perl5においてはperlccというモジュールが開発されている.
529 これはPerl5内部で利用しているPerlバイトコードを, PerlのC APIであるXS言語の様なCのソースファイルに埋め込み,それをCコンパイルでコンパイルするというものである.
530 perlccを利用することでPerlインタプリタが無い状況でも可動するバイナリファイルを作成する事が可能である.
531 しかしPerlccはPerlスクリプトが複雑になるほど正確にCに移植を行う事が出来ず, 現在ではPerlのコアモジュールから外されている.
532 PerlccはPerlのバイトコードをCへの変換のみ行う為, Cで実装されているPerl経由で実行した場合と処理速度はほぼ変わらない.
533 またPerlccで生成されたCのソースコードは難解であり, これをデバッグするのが困難でもある.
534 MoarVMでthreaded codeを実現出来た場合, その箇所のみCbCプログラムとして切り出す事が可能である為perlccと似たツールを作成することも可能である.
535 CレベルでもPerlccの様に内部構造をCの関数化すればThrededCodeの様な物を構築できるが, CbCと比較して処理の単位が明確ではない為高速化は見込めない.
536 CbCを用いたThrededCodeでPerlccの様なツールを作成した場合, CodeGearの単位が正常に機能すればCbCのCodeGearがThrededCodeをより効率化出来ると推測できる.
537
538
539 CbCのCodeGearはgoto文で遷移するため, 次のCodeGearが一意に決定している場合Cコンパイラ側でインライン展開する事が可能である.
540 CodeGearがインライン展開される限界については別途研究する必要があるが, CbCを利用した場合CodeGear単位でインライン展開が可能である.
541 その為, ThrededCodeを実装する場合に決定した次のCodeGearをインライン展開する事が可能である.
542 従ってThreadeCodeを実現するにあたり新たな処理系を開発する必要がなく, 既存の資源を利用してThreadeCodeが実現出来る.
543 これを繰り返す事でPerlccなどと比較してより高速化したThrededCodeが実現できる.
544
545
546 \section{まとめ}
547 本論文ではCbCによってPerl6の処理系であるMoarVMインタプリタの一部改良とその手法を示した. 547 本論文ではCbCによってPerl6の処理系であるMoarVMインタプリタの一部改良とその手法を示した.
548 CbCのCodeGear部分を用いることできめ細やかな記述が出来,デバッグし辛い箇所もbreakpointの設定などが容易になった. 548 CbCMoarVMではオリジナルのMoarVMと比較して以下の様な利点が見られた.
549 549
550 今後CbCでの開発をより深く行っていくにあたり,CbCコンパイラそのものの信頼性を向上させる必要がある. 550 \begin{itemize}
551 MoarVMの開発を行うにあたり新たに発見された複数のバグを修正し,より安定するコンパイラにする為に改良を行う. 551 \item CodeGear単位で命令処理を記述する事が可能となり, モジュール化が可能となった.
552 552 \item ThreadeCodeを実装する際に効率的に実装ができる見込みが立った.
553 現在CbCMoarVMで直接バイトコードを入力した場合のnqpのテストはJVM,Javascriptのテストを除く中で80\%パスする. 553 \item CodeGearを導入した命令単位での最適化が可能となった.
554 また数値の計算と出力などの簡単なNQPの例題を作成し,オリジナルのNQP,MoarVMでバイトコード化したものを入力した際も正常に動作している. 554 \item break pointを命令の処理単位でかける事可能となった.
555 \end{itemize}
556
557 今後CbCでの開発をより深く行っていくにあたり, CbCコンパイラそのものの信頼性を向上させる必要がある.
558 MoarVMの開発を行うにあたり新たに発見された複数のバグを修正し, より安定するコンパイラにする為に改良を行う.
559
560 現在CbCMoarVMで直接バイトコードを入力した場合のnqpのテストはJVM, Javascriptのテストを除く中で80\%パスする.
561 また数値の計算と出力などの簡単なNQPの例題を作成し, オリジナルのNQP,MoarVMでバイトコード化したものを入力した際も正常に動作している.
555 しかしNQPのセルフビルドは現在オブジェクトの生成に一部失敗している為成功していない. 562 しかしNQPのセルフビルドは現在オブジェクトの生成に一部失敗している為成功していない.
556 今後はさらに複雑な例題やNQPのセルフビルド,Perl6の動作を行っていく. 563 今後はさらに複雑な例題やNQPのセルフビルド, Perl6の動作を行っていく.
557 564
558 MoarVMではGCからオブジェクトを守る為にMVMROOTというマクロを利用し,局所変数のポインタをスタックに登録する処理を行っている. 565 MoarVMではGCからオブジェクトを守る為にMVMROOTというマクロを利用し, 局所変数のポインタをスタックに登録する処理を行っている.
559 GCの制御を効率的に行えば本来は必要ない処理であり,実行するとCodeGearの優位性が損なわれてしまう. 566 GCの制御を効率的に行えば本来は必要ない処理であり, 実行するとCodeGearの優位性が損なわれてしまう.
560 従ってMoarVMのGCの最適化を行う. 567 従ってMoarVMのGCの最適化を行う.
561 568
562 また高速化という面では,Perlの特徴である正規表現に着目し,正規表現の表現のみ高速で動く最適化の導入なども検討している. 569 また高速化という面では, Perlの特徴である正規表現に着目し,正規表現の表現のみ高速で動く最適化の導入なども検討している.
563 他にrakudoのコンパイラ系統からCbCのコードを直接生成させ,それをllvmでコンパイルすることによってLLVMの最適化フェーズを得て 570 他にrakudoのコンパイラ系統からCbCのコードを直接生成させ, それをllvmでコンパイルすることによってLLVMの最適化フェーズを得て
564 高速化することも可能であると推測できる. 571 高速化することも可能であると推測できる.
565 572
566 Perl6の開発は非常に活発に行われている為,CbCMoarVMの最新版の追従も課題となっている. 573 Perl6の開発は非常に活発に行われている為, CbCMoarVMの最新版の追従も課題となっている.
567 現在はinterp.cからPerlスクリプトを用いて自動でCbCのCodeGearを生成している. 574 現在はinterp.cからPerlスクリプトを用いて自動でCbCのCodeGearを生成している.
568 今後の開発領域の拡大と共により効率的にCbCコードへの自動変換も複数のCコードに対応する様に開発を行っていく. 575 今後の開発領域の拡大と共により効率的にCbCコードへの自動変換も複数のCコードに対応する様に開発を行っていく.
569 576
570 %å\subsection{MoarVMの処理流れ} 577 %å\subsection{MoarVMの処理流れ}
571 %MoarVMはC言語で実装されており,Perl5で記述されたConfigure.plを 578 %MoarVMはC言語で実装されており, Perl5で記述されたConfigure.plを
572 579
573 580
574 % BibTeX を使用する場合 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 581 % BibTeX を使用する場合 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
575 \nocite{*} 582 \nocite{*}
576 \bibliographystyle{ipsjsort} 583 \bibliographystyle{ipsjsort}