VMプラグイン作成おぼえがき

まずは成功体験ということで絶対値を求めるプリミティブメソッドを作ってみた。
(本当は'Hello'を返すものとかにしたかったんだけど、Stringクラスとchar*型の間の扱いがよくわからなかった。)

プラグイン用クラス

SmartSyntaxInterpreterPluginのサブクラスにする。
ここで使ったクラス名.cのファイルが出来ることになる。
クラス名がAで始まってるのは単にVMMakerやエクスプローラの欄で探しやすいから。

SmartSyntaxInterpreterPlugin subclass: #APlugin
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'APlugin'

プリミティブメソッド本体
primitive:がプリミティブである宣言。
asOop:がCのintからオブジェクトポインタへの変換。

primitiveAbs: num
	| ret |
	self primitive: 'primitiveAbs' parameters: #(#SmallInteger).
	num < 0 ifTrue: [ret:=num*-1] ifFalse: [ret:=num].
	^ret asOop: SmallInteger

テスト用クラス

ワークスペース等から直接プリミティブメソッドが呼び出せなさそうなのでテスト用クラスを作る。

Object subclass: #APluginTest
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'APlugin'

テスト用クラスメソッド
クラスメソッドにしたのは単にnewを書く手間を省きたいから。
1行目がプリミティブ呼び出し。これは失敗しても次の行に進んでしまうので、
2行目でノーティファイアを出している。

abs: num
	<primitive: 'primitiveAbs' module: 'APlugin'>
	self primitiveFailed

VMMakerでCに変換

ワールドメニュー→open→VMMaker
Path to platforms code:のFind Pathをクリックしてソースディレクトリを指定(Crossとwin32の上位のディレクトリ)
この時点でSave Configurationする。
Plugins not builtの中からAPluginをドラッグしてExternal Pluginsにドロップ
ドロップしたAPluginsを右クリックしてgenerate pluginを実行
これで、win32/plugins に APlugin/APlugin.c が出来る。

Cのコンパイル

一応記念に変換されたCのコードを貼っておく。
データ形式の変換等があるが、基本的に同じ処理をしているのがわかる。

EXPORT(int) primitiveAbs(void) {
	int ret;
	int num;
	int _return_value;

	num = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	if (num < 0) {
		ret = num * -1;
	} else {
		ret = num;
	}
	_return_value = interpreterProxy->integerObjectOf(ret);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(2, _return_value);
	return null;
}

コンパイルはwin32ディレクトリにcdして用意されてるバッチファイルを使う。
といっても単にmakeを呼び出してるだけだけど。

> build.bat APlugin.dll

これで win32/release に APlugin.dll が出来る。
出来たdllを現在実行しているsqueak.exeと同じディレクトリにコピーすればメソッド呼び出しがあった時点で自動的に読み込む。
しかしdllでエラーが起こるとVMごと落ちることがあるので、その前にイメージをsaveしておいた方がよい。
なお次回以降、デバッグ、再ビルドしたときは、以下を実行してファイルのロックをはずしてからコピーする。

Smalltalk unloadModule: 'APlugin'

実行テスト

以下をprint itして3が返ってくればOK。

APluginTest abs: -3

動かないときのための、現在読み込んでいるプラグインのリストアップ方法。

Smalltalk listLoadedModules