オープンソースの小型・軽量スクリプトエンジン「 Vnano (VCSSL nano) 」のコンセプト

RINEARN

オープンソースで2018年内公開見込み!
"eval用途" のVCSSLサブセット「 Vnano 」

RINEARNでは現在、 プログラミング言語VCSSLのサブセット(※後述)として、 小型・軽量のスクリプト言語 & 処理エンジン「 Vnano (ブイナノ、由来は VCSSL nano の略)」の開発が進行中です。

ここでの "サブセット" とは、 既存の言語やソフトウェアの全機能・仕様( いわゆる "フルセット" )から取捨選択し、 目的に応じて一部を抜き出した「 部分機能版 」といった意味です。 Vnano は、Java※1 で記述された一般のソフトウェア上に搭載し、 計算式の評価やちょっとしたスクリプト処理などの、 いわゆる eval 的な機能を提供する事を目的とした、 VCSSLのサブセットです。

Vnano はオープンソースの形態で2018年内の公開を目指しており、 開発は既に終盤に差し掛かっていますが、 この RINEARN Web サイトで発表するのは今回が初めてとなります。 そこで、今回はまず Vnano のコンセプト = 構想や目指している方向性 について紹介しましょう!

- 関連記事・Webページ -
- この記事の目次 -

前提となるVCSSL

Vnano の本題に入る前に、まず前提となるVCSSLについて軽く触れておきましょう。 VCSSLは、RINEARN において2011年より開発・公開している簡易プログラミング言語です。 VCSSLの実行環境自体は全てJava言語で実装されており、 インストール不要でUSBメモリーなどで持ち運んでも使える事が特徴の一つです。

VCSSL

VCSSLは、元々は電卓ソフト上で関数定義や自動計算を行うための言語であった事から、 学習コストを抑えつつ短いコードを手短に記述できるよう、 C言語系の単純化した文法を採用しています。 コードの第一印象はまさに「 ソフトウェア上のスクリプト機能としてありがちなCっぽい簡易言語 」といったところでしょうか。

このようなシンプルな文法に、2D/3Dの簡易描画機能やグラフプロット機能などを標準で組み合わせて、 ちょっとしたデータ解析や可視化・計算ツールなどを、手軽にオールインワンで作ってどこでも使えるようにしたのが、現在のVCSSLです。

Vnano のコンセプトと具体例

ソフトウェア上でのスクリプト処理機能の提供のみに特化した、VCSSLのコンパクトなサブセット「 Vnano 」

Vnano は、VCSSL からそのような付属機能の部分を削り、 先述した「 ソフトウェア上のスクリプト機能としてありがちなCっぽい簡易言語 」という部分のみを抜き出して、 可能な限りコンパクトにまとめたサブセットです。

用途もそのものずばりで、 Vnanoでは、処理エンジンを一般のソフトウェア※2 上に搭載し、計算式の評価やちょっとしたスクリプト処理などの機能を提供する 事に目的を絞っています。 例えばソフトウェア上で、ユーザーが入力した計算式に基づいて処理を行ったり、 もしくは、比較的複雑な手続き処理の内容を設定ファイルに記述してカスタマイズできるようにしたり、といった場面で使用する事を想定しています。

※2: 現時点では、VnanoのエンジンはJava言語による実装が唯一であるため、搭載対象のソフトウェアはJava言語で記述されている事が前提となります。 ただし、将来的には他言語への移植も行うかもしれません。

式の値を評価(計算)する例

より具体的なイメージをお伝えするため、例を挙げながら見てみましょう。 Java言語で開発している何らかのソフトウェア上で、 コンパイル時ではなく、実行時に文字列として得られる計算式( 例えば "1 + 2" )などの値を求めたい場合があったとします。

現在のJava言語には、実行時に文字列をJavaのコードと解釈して実行する機能こそありませんが、 その代わりに他のスクリプト言語のエンジンと連携し、文字列をその言語のコードとして解釈・実行する 「 スクリプトAPI(パッケージは javax.script)」が標準でサポートされています。 このAPIにより、スクリプトエンジン側が対応してさえいれば、 Java側からは ScriptEngine インターフェースを実装したクラスの eval メソッドを呼ぶだけで、 簡単に文字列を各種スクリプト言語のコードとして実行する事ができます。

そしてVnanoのエンジンはこのAPIに対応しており、Java言語で記述されたコード上で、 以下のように簡単に文字列内の式 "1 + 2" の値を計算させる事ができます:

code/VnanoExampleAdd.java

このコード内で重要なのは、14行目の

code/eval1add2.txt

の箇所で、ここでVnanoエンジンに「 1 + 2 」の式を文字列で渡し、その評価(計算)結果を int 型変数 value で受け取っています。

さて、このコードをコンパイルする際に、特別なものは一切不要です。 実行する際に、ただ1個のJARファイル「 Vnano.jar 」にクラスパスが通っているだけで、 自動的にVnanoのエンジンが検索・取得されて動作します。

このコードでは説明のため、エンジンから返された結果を表示するようにしていますが、実際に実行すると、以下のようにVnanoによる 1 + 2 の計算結果が表示されます:

式の値: 3

ここではコードを簡単にするために、コード内に決め打ちで計算式の文字列 "1 + 2" を記述しましたが、 もちろん実行時に動的に決まる文字列でも処理できます。

逐次処理や制御構文の使用、搭載ソフトウェア側のメソッドやフィールドの参照も可能

式の評価以外にも、通常のプログラムのように、複数の文を上から順に実行する逐次処理や、 if / for / while 文といった制御構文も使用可能です。以下が実際の例です:

code/VnanoExampleSum.java

スクリプトを実行しているのは18〜24行目の部分です:

code/evalfor.txt

行っている事としては、1 から変数 LOOP_MAX までの数の和を、for文を用いて計算して、結果を output 関数に渡しています。 ところでこの変数 LOOP_MAX や output 関数は、Vnano内のものではなく、 Java言語のコード側の33〜36行目で、フィールド・メソッドとして定義されているものです。 それを 14〜15行目でリフレクションを用いて、Vnanoのエンジンに接続しています。 このようにエンジンに接続されたフィールド・メソッドは、Vnano側のコードから参照できるようになります。

実行結果は以下の通りです:

スクリプトからの出力: 5050

このように、Java言語で記述した output メソッドをスクリプト内から呼び出して、値を表示する事ができています。

必要最小限のコンパクトな仕様と実装

標準の組み込み関数やライブラリ等は無し ―
必要となる機能のみを搭載ソフトウェア側で実装・接続する設計方針

さて、Vnanoでは上の例で示したように、搭載ソフトウェア側で(Java言語によって)記述したフィールドやメソッドをエンジンに接続し、スクリプト内から使用する事ができます。 その代わり、デフォルトで使用できる組み込み関数や標準ライブラリのようなものは基本的にありません。 これには理由があります。

というのも、単体で使用する言語とは違い、ソフトウェア上のスクリプト機能としての言語では、 「 何でもできる 」ような汎用性は必ずしもプラスではなく、 用途によっては逆にマイナスにもなってしまうからです。

例えば、単にユーザーが入力した数式の値を求めたいだけの場面において、 その式の中でファイルの読み書きや削除などを行う関数を呼べる必要性は全くありません。 逆に、そのソフトウェアに要求される厳格さのレベルや利用形態によっては、 そのような事ができてしまう状態自体が NG という場合もあるはずです(極端な例としては、ネットワーク上の不特定のユーザーから式が入力される場合など)。

そのような厳格さが特に要求されるような場面においては、ソフトウェア上のスクリプト機能では、 そのソフトウェアの開発者が事前に厳選した機能のみが使用でき、想定を超えた余計な事はできないようにブロックする必要が出てきます。 そのような背景から、文字列をプログラムのコードとして実行する機能が標準でサポートされている ( 即ち言語組み込みの eval 関数を持つ ) 言語においても、場面によってはそれでは自由度が高く強力過ぎるために使用せず、 必要最小限の機能のみを持つ式/文の解釈・実行処理(いわゆる簡易パーサ)が自主開発されるようなケースもあるでしょう。

このような事も踏まえて、最初からソフトウェア上のスクリプト機能の提供のみに的を絞っているVnanoでは、 それを搭載するソフトウェアの開発者が、その想定用途で必要となる(最小限の)組み込み関数・変数のみを個別に用意し、 エンジンに接続してサポートするという方針を採用しています。 デフォルトでは、スクリプト内からは外側に対してデータの受け渡しや処理の呼び出しを一切できないサンドボックス状態で、 そこから必要に応じて、上で例示したように特定のデータや処理にアクセスする手段を追加するわけです。

ある程度の改造も前提としたコンパクトなエンジン実装 ―
コア言語からもいくつかの機能を削減

このような「 必要最小限 」のコンセプトは、もちろんエンジンの実装規模を抑えられるというメリットもあります。 特に、Vnano は単体で使用する言語処理系ではなく、 ソフトウェア上に搭載して使用する以上、実装のコンパクトさは、個々のソフトウェアに合わせた細かい調整や改造がしやすくなるという利点にも繋がります。

VnanoはVCSSLのサブセットですが、処理エンジンは新たにゼロから設計し直したものとなります。 その理由はいくつかありますが、最も大きい点は、現在のVCSSLエンジンでは開発初期にオープンソース化をあまり意識していなかったため、 その複雑さと実装規模が、手軽にソースコードをカスタマイズ(調整や改造)して使うような用途に適していないためです。 Vnanoのエンジンでは、最初からそのような使い方を想定して設計しているため、 実装規模をなるべくコンパクトにし、コード記述の複雑性も抑える事を重視したものとなっています。

また、VCSSLからライブラリを除いたコア言語部分の仕様においても、Vnanoでは用途的にあまり必要でない機能をいくつか削減しています。 具体的には、ジェネリクスや構造体、多倍長演算型や複素数型などはVnanoではサポートされません。 また、現時点ではスクリプト内での関数定義もサポートしない見込みです。 これは、そもそも搭載ソフトウェア側が提供するメソッドを関数として呼び出せるため、 わざわざスクリプト内で定義可能とするメリットが薄い事と、 用途によってはできない方が好ましい場合もあるためです。 ただし、関数定義については後々の判断でオプション扱いでサポートする可能性もあります。
( 後日追記: 最終的には、やはり関数定義はサポートする事になりました。 正式リリース時点では、オプションで関数定義の可否を選択できるようにもなる見込みです。 )

これらの "仕様の軽量化" により、Vnanoのエンジンは、現状のVCSSLのエンジンに比べてかなりコンパクトに収まっています (なお、VCSSLも将来的にはオープンソース化を検討しており、その際は今回のVnanoのエンジンを土台として、機能を拡張していく形での開発を考えています)。

実装だけでなく、クラスライブラリの仕様書やガイドのようなドキュメント類についても、同時進行で整備を進めています。

倍精度で数百MFLOPS〜GFLOPSクラスの演算速度

性能面でも、仕様をコンパクトに抑える事は有利に働きます。 また、Vnanoではエンジンをゼロから新開発するにあたって、VCSSLのエンジンで処理速度のネックとなっていた古い構造を改めて、頭から尻尾までを根本的に刷新する事ができました。 そのため、既に現時点のベンチマークテストにおいても、Vnanoの演算速度は少なくともVCSSL比で数倍以上は見込める事が確認できています。

具体的な例としては、動作周波数が 1.6GHz(ベースクロック)- 2.3GHz(TB時)のモバイル向け省電力プロセッサ上において、 倍精度浮動小数点数のスカラ演算で概ね 260 MFLOPS(毎秒2.6億回) 後日更新: 400MFLOPS(毎秒4億回)程度、ベクトル演算においては 5 GFLOPS(毎秒50億回)弱のスコアを確認しています。 ※性能は共にピーク値です。

ベクトル演算ベンチマークスコア
ベクトル演算ベンチマークスコア(64-bit倍精度浮動小数点数)

この演算速度には、仕様の軽量化の効果だけでなく、中間コードの実行レイヤーに新たにベクトルレジスタ型の仮想マシンを採用した事も効いています。 この仮想マシンでは、特に演算対象データが全てCPUの1次キャッシュ内に収まる場合のベクトル演算において、SIMD有効時に、CPUの動作クロックを上回るGFLOPSクラスの倍精度演算速度(ピーク値)を発揮可能です。 スカラ演算においても、ベクトル演算とは別に最適化した処理が行われる事により、ピーク値で数百MFLOPSクラスのパフォーマンスを発揮します。

この仮想マシンは元々、将来的なVCSSLの性能向上のために設計を進めてきた新しい仮想マシンで、Vnanoではそれを初めて採用しています。

Vnanoのエンジンの実装に関しては、また後の回で詳しくお伝えします!

※1: OracleとJavaは、Oracle Corporation 及びその子会社、関連会社の米国及びその他の国における登録商標です。文中の社名、商品名等は各社の商標または登録商標である場合があります。