xptcall
とは何ですか?
xptcall
は、低レベルの XPCOM メソッド呼び出しのための小さなライブラリです。プラットフォーム固有の C/C++ とアセンブラ言語のコードを使って実装されています。異なる言語間の呼び出しと異なるスレッドへのメソッド呼び出しを容易にするためのものです。 Mozillaをあらゆるプラットフォーム上で動作させるためには、このコードを移植する必要があります。
なぜ xptcall
があるのですか?
xptcall
があるのは、以下の二つの理由によります:
- XPCOM インタフェースの任意のメソッドを実行できるようにするため。
- 任意の XPCOM インタフェースを実装しているかのように、動的に振舞いを変えられるようにするため。
どちらの仕組みも XPConnect にとって必要なものです。また、xpcom/proxy
もこれらの仕組みを利用しています。将来的には、他のサブシステムでも使われるかもしれません。
xptcall
のアプローチの方が、スタブコードの生成により、すべてのインタフェースの呼び出しと実装をサポートするアプローチよりも良いということで、選択されました。この xptcall
のアプローチは、コアなプラットフォーム固有のコードを必要とします。しかし、メモリ使用量が最小で済み、そして任意の正当な XPCOM インタフェースとともに動作できるように拡張できます。しかも各プラットフォームごとに追加のコンパイル済みコードを付加する必要がないのです。
xptcall
は、実際には何をするのでしょうか?
これが、コアとなる invoke 関数の宣言です:
XPTC_PUBLIC_API(nsresult) XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, PRUint32 paramCount, nsXPTCVariant* params);
nsXPTCVariant
は、共用体のデータです。これは、目的の関数にパラメータとして渡される型で区別されます (型として void*
も使えるので、任意のポインター型を表現することができます)。
正しいパラメータセットを与えることで、この関数を使って任意の XPCOM インタフェースの任意のメソッドを呼び出すことができます。 XPConnect は、タイプライブラリ ファイルの情報を使用して、任意の XPCOM インタフェースを JavaScript にマッピングし、XPTC_InvokeByIndex
を使って JavaScript から XPCOM を呼び出すことができるようになります。タイプライブラリの情報を使うことで、 XPConnect は、関数のパラメータを変換でき、そしてこの呼び出しをするのに必要な nsXPTCVariant
型の配列を組み立てることができます。
xptcall
の スタブ (あるいは偽装) の仕組みにより、実行時に、任意の XPCOM インタフェースのふりをすることができるクラスを実装できるようになります。これは、xptcall
が、関数の汎用的なスタブへのポインタが並べられた vtbl を提供することで実現されます。これらのスタブは、呼び出しを共通の関数に転送します。この共通の関数は、タイプライブラリの情報を使って、パラメータを取り出します。そして、プラットフォーム固有の呼び出し規約に従って、パラメータを保持するバリアント型の配列を組み立てます。その後、継承したメソッドを呼び出すことで、任意の処理を実行することができます。このコードは、呼び出しから戻る時に、プラットフォーム固有の後始末も行います。
これらはすべて動作しており、現在、様々なプラットフォーム 上の Mozilla で使われています。
なぜ xptcall
を、単に C や C++ で実装することができないのですか?
これらの二つの仕組みでは、完全にクロスプラットフォームにできないからです。あるいは、汎用的にすべて C や C++ で行うこともできないからです。それがどうしてなのかを、ひとつずつ見てみましょう。
invoke では、任意の呼び出しのフレームを組み立てて、それを実行できるコードが必要になります。C++ のコンパイラは、そのような呼び出しのフレームをいつも組み立てています。しかし、コンパイラは、呼び出し先の固有のシグネチャーのためにカスタマイズしたフレームを コンパイル時に 組み立てます。 xptcall
は、任意の正当な XPCOM メソッドシグネチャーを呼び出せなければなりません。そしてシグネチャーは実行時に特定する必要があるのです。
stubs は、任意の XPCOM インタフェースのすべてのメソッド (祖先のメソッドも含む) の全ての vtbl を実装しているかのように振舞わなければなりません。これを行ういくつかの方法があります。実行時にコンパイラを動かして、スタブの動的に組み立てとロードを行うことができます。あるいは、プラットフォーム固有のコードを書いて、インタフェース固有の vtbl とメソッドのスタブを組み立てる方法もあります。私は、ひとつの巨大な vtbl と多くの小さな汎用のスタブを使う方法を選びました。これにより、プラットフォーム固有のコードは可能な限り小さくなるのです。もう一度言うと、これをすべて行うコードを C で書くことはできません。 varargs を使って一部実現することはできますが、それでは十分ではありません。
もし、何か確実な方法があって、クロスプラットフォームな方法で、かつ/またはアセンブラ言語のコードを使わずに必要な機能を実現することができるのであれば、教えてください。
xptcall
は、Mozilla のプラットフォームとして必要なものですか?
はい。Mozilla は、xptcall
がきちんと移植されていないと、正しく動作しないでしょう。無機能のスタブコードがあるので、サポートされていないプラットフォーム上でも xptcall
をビルドできるようになっています。しかし XPConnect に依存しているブラウザ機能は、すべて実行に失敗するでしょう。プラットフォーム上で xptcall
が機能しないと、問題が起きるでしょう。 xptcall
が、どこででも動作するように取り組んでいく必要があります!
どのプラットフォームがサポートされていますか?
増加中のリストです:
他のリソースは、どこにあるでしょう?
コードは xpcom/reflect/xptcall
にあります。
新しい移植のためのガイドは xpcom/reflect/xptcall/porting.html
にあります。
原文書の情報
- 著者: John Bandhauer <[email protected]>
- 初出: 1999 年 09 月 02 日