このページの内容

VMの設定

Wren VMを作るとき、WrenConfiguration構造体へのポインターを渡して、設定を調整します。Wrenにはグローバルな状態がないので、アプリケーションで複数のVMを実行する場合、それぞれを別々に設定できます。

構造体は、次のようになっています。


typedef struct
{
  WrenReallocateFn reallocateFn;
  WrenLoadModuleFn loadModuleFn;
  WrenBindForeignMethodFn bindForeignMethodFn;
  WrenBindForeignClassFn bindForeignClassFn;
  WrenWriteFn writeFn;
  WrenErrorFn errorFn;
  size_t initialHeapSize;
  size_t minHeapSize;
  int heapGrowthPercent;
} WrenConfiguration;

ほとんどのフィールドには、有用な既定値があります。次を呼び出して初期化できますし、そうするべきです。


wrenInitConfiguration(&configuration);

これを呼び出すことで、WrenConfigurationへ新しいフィールドを追加しても、VMへ未初期化の設定を渡さずに済みます。各フィールドの働きを、大まかに分類して説明します。

束縛 #

VMは外の世界から隔離されています。これらのコールバックを使い、VMはインポートするコードや外部機能へのアクセスを要求できます。

loadModuleFn #

インポートしたモジュールを読み込むためにWrenが使うコールバックです。VM自身は、ファイルシステムとのやり取りを知りません。そのため、import文を実行するとき、ホストアプリケーションに頼って、モジュールのソースコードを探し、読み込みます。

この関数のシグネチャは、次のとおりです。


WrenLoadModuleResult loadModule(WrenVM* vm, const char* name)

モジュールをインポートするとき、Wrenは、この関数を呼び出し、モジュール名を渡します。ホストは、そのモジュールのソースコードをWrenLoadModuleResult構造体で返すべきです。


WrenLoadModuleResult myLoadModule(WrenVM* vm, const char* name) {
  WrenLoadModuleResult result = {0};
    result.source = getSourceForModule(name);
  return result;
}

モジュールローダーは、一つのモジュール名につき一度だけ呼び出します。Wrenは内部で結果をキャッシュするので、同じモジュールの後続のインポートでは、すでに読み込んだコードを使います。

ホストアプリケーションが、指定した名前のモジュールを読み込めない場合、戻り値のsourceをNULLにします。Wrenは、それを実行時エラーとして報告します。

import文を使わない場合、設定のloadModuleFnフィールドは、既定値のNULLのままにできます。

さらに、WrenLoadModuleResultには、Wrenがsourceを使い終えたときのコールバックを追加できます。必要なら、メモリーを解放するために使えます。



static void loadModuleComplete(WrenVM* vm, 
                               const char* module,
                               WrenLoadModuleResult result) 
{
  if(result.source) {
    //for example, if we used malloc to allocate
    //our source string, we use free to release it.
    free((void*)result.source);
  }
}

WrenLoadModuleResult myLoadModule(WrenVM* vm, const char* name) {
  WrenLoadModuleResult result = {0};
    result.onComplete = loadModuleComplete;
    result.source = getSourceForModule(name);
  return result;
}

bindForeignMethodFn #

Wrenが外部メソッドを探し、クラスへ束縛するために使うコールバックです。詳細はこのページを参照してください。アプリケーションが外部メソッドを定義しない場合、NULLのままにできます。

bindForeignClassFn #

Wrenが外部クラスを探し、その外部メソッドを取得するために使うコールバックです。詳細はこのページを参照してください。アプリケーションが外部クラスを定義しない場合、NULLのままにできます。

診断 #

これらを使って、最小限の出力を結び付け、コードが期待どおりに動いているか確認できます。

writeFn #

System.print()や関連するほかの関数を呼び出したときに、テキストを出力するためにWrenが使うコールバックです。VMと外の世界との最小限の接続であり、基本的な「printfデバッグ」を行えます。そのシグネチャは、次のとおりです。


void write(WrenVM* vm, const char* text)

Wrenには、この既定の実装はありません。printf()など、テキストを表示する手段へ結び付けるのは、利用者の責任です。NULLのままにすると、System.print()などの呼び出しは、何もせず、出力もありません。

errorFn #

Wrenは、このコールバックでコンパイル時エラーと実行時エラーを報告します。そのシグネチャは、次のとおりです。


void error(
      WrenVM* vm, 
      WrenErrorType type,
      const char* module,
      int line,
      const char* message)

type引数は、次のいずれかです。


typedef enum
{
  // A syntax or resolution error detected at compile time.
  WREN_ERROR_COMPILE,

  // The error message for a runtime error.
  WREN_ERROR_RUNTIME,

  // One entry of a runtime error's stack trace.
  WREN_ERROR_STACK_TRACE
} WrenErrorType;

コンパイルエラーが起きると、errorFnを一度呼び出します。種類WREN_ERROR_COMPILE、エラーが起きたモジュール名と行、エラーメッセージを渡します。

実行時エラーには、スタックトレースがあります。これを扱うため、Wrenは、まずerrorFnを、WREN_ERROR_RUNTIME、モジュールと行なし、実行時エラーのメッセージを使って呼び出します。その後、種類WREN_ERROR_STACK_TRACEを使い、スタックトレースの各行につき一度、errorFnを再び呼び出します。各呼び出しには、メソッドや関数を定義したモジュールと行があり、messageには、メソッドや関数の名前を渡します。

NULLのままにすると、Wrenは、どのエラーも報告しません。

メモリー管理 #

これらのフィールドは、VMによるメモリーの割り当てと管理を制御します。

reallocateFn #

独自のメモリー割り当て関数を指定できます。そのシグネチャは、次のとおりです。


void* reallocate(void* memory, size_t newSize, void* userData)

Wrenは、この一つの関数を使って、メモリーの割り当て、拡大、縮小、解放を行います。割り当てを変更したり解放したりする場合、呼び出し時のmemoryは、そのメモリーブロックへの既存のポインターです。新しいメモリーを要求する場合、memoryはNULLです。

newSizeは、要求するメモリーのバイト数です。メモリーを解放する場合、これは0です。コールバックは、適切な量のメモリーを割り当て、それを返すべきです。

独自のアロケーターを指定しなければ、VMは、reallocとfreeを使う既定のものを使います。

initialHeapSize #

最初のガベージコレクションを起動する前に、VMが割り当てるメモリーの総バイト数を定義します。小さな数値にすると、Wrenが一度に割り当てるメモリー量は減りますが、ガベージコレクションの頻度は増えます。

0に設定すると、Wrenは、既定の10MBを使います。

minHeapSize #

ガベージコレクションの後、次の回収のしきい値は、使用中として残ったバイト数に基づいて決めます。これにより、実際に必要なメモリー量に応じて、Wrenは、自動でメモリー使用量を増減できます。

ヒープが小さくなりすぎないようにするために使えます。小さすぎると、使えるサイズまで再びヒープが大きくなる過程で、何度も回収が起きる場合があります。

0の場合、既定値は1MBです。

heapGrowthPercent #

Wrenは、回収後にまだ使っているメモリー量に基づき、ガベージコレクションの頻度を調整します。この数値で、その調整を制御します。回収後に追加で使うメモリー量を、現在のヒープサイズに対する割合で決めます。

例えば、50とします。ガベージコレクション後、まだ400バイトを使っています。この場合、合計600バイトを割り当てた時点で、次の回収を起動します。(すでに使用中の400バイトも含みます。)

小さな数値にすると、無駄なメモリーは減りますが、ガベージコレクションの頻度は増えます。

0に設定すると、VMは、既定値の50を使います。

← Cデータの保存