スタックはスタックを駆動するか、Java仮想マシンのバイトコードをマシンPhantom OSのバイトコードに変換します

Phantom OSは、永続的なRAMに仮想バイトコードマシンをアプリケーションレベルで含む実験的なオペレーティングシステムです。



OS Phantomが既存のコードを移行するために計画されている2つの重要なファントムパスの1つは、JavaバイトコードからPhantomバイトコードへの変換です。



これらの仮想マシンは、偶然ではありますがほぼ同じであると言わなければなりません。 Phantom仮想マシンは、私がまだJavskayaについて何も知らなかったときに設計されましたが、おそらく、目標の類似性が決定の類似性につながったと思われます。



両方の車が積み上げられています。 両方とも、2つの個別のスタックで動作します-オブジェクトを操作するためのスタック(スタック上にあるのはリンクのみ)と、計算のためのバイナリスタックです。 Phantom Machineには、関数フレームと例外トラップ用の個別のスタックもあります。 この部分がJVMでどのように配置されているかはまだわかりませんが、根本的に異なる方法とはほとんど思えません。



当然、スタックされたマシンの一連の操作は、2つのドロップと似ています。



しかし、もちろん、非常に大きな違いがあります。



まず、Phantom仮想マシンは、使いにくい環境でアプリケーションコードを実行するように設計されています。 Javaは、各プログラムが個別のアドレス空間に存在するという事実から始まり、その周りにあるのは「私たちの」コードだけです。 このファントムは、異なるユーザーのアプリケーションと異なるプログラム間の直接呼び出しを可能にします。これには、同じ呼び出しやオブジェクトのインターフェース全般を含む、仮想マシンのいくつかの側面に対する厳しい態度が必要です。 たとえば、呼び出されたメソッドが「適切に」動作するという事実に依存することはできません。スタックへのアクセスを許可したり、戻り値の有無に依存することはできません。 メソッド、関数、静的関数の違いは保証できません。 つまり、電話をかけるのは私たちであると想定できますが、反対側で「スリップ」したのは不明です。



とは言っても、Phantomの呼び出しは完全に統合されています-常にメソッド呼び出し(これがあり、クラスがあります)であり、値が常に返されます。これはvoidメソッドではnullに等しく、呼び出し元のコードによって明示的に破棄されます。 これにより、コールエラーが発生した場合でも、コールの件名として表示されない場合でも、コールおよびリターンプロトコルが尊重されます。



整数の操作には違いがあります。 Javaは、オブジェクトとは異なるタイプの別のカテゴリ、「クラス」タイプ(java.lang.Integerおよびint)に区別します。 コンパイラはこの事実をうまく隠すことがありますが、内部では異なります。 ここでの幻は、最大主義に向かっています。 全体が正直なオブジェクトです。 整数スタックにプルし、そこで「非目的」バイナリ形式でカウントできますが、変数に割り当てられるかパラメーターで渡されると、オブジェクトの形式に戻ります。 ちなみに、これはメソッド呼び出しプロトコルの均一性の要件からも続きます。全体とオブジェクトを返すメソッドは、プロトコルの下で同一です。 (明らかに、他の「積分」型-long、float、doubleにも同じことが当てはまります。)



他にも違いがあります。たとえば、Javaがネイティブメソッドと呼ぶ接続プロトコルなどです。 Phantomでは、これらは「システムコール」であり、メソッドコールレベルでは、通常の「正直な」メソッドと変わりません。 (このメソッドのコードには、OSカーネルを「残す」ための特別な指示が含まれていますが、これはメソッドの「外部」には表示されません。これにより、VMTを置き換えることにより、従来の方法でそのようなメソッドを継承およびオーバーライドできます。)



少なくとも、あるスタックマシンのバイトコードを別のスタックマシンのバイトコードに変換することは基本的なタスクのようです(少なくとも私には思えました)。 結局のところ、あちこちにスタックがあり、操作の90%はまったく同じです。 まあ、整数加算のFantomovskyとJavaバイトコードに違いはありません:スタックから2つの整数を上げ、加算し、結果をスタックに置きます。



翻訳への最初のアプローチは、JavaバイトコードからPhantomへの順次変換のモデルに正確に依存していました。 これは直線的に行うことができないことがすぐに明らかになりました。 絶対に。 Javaコードを解析するときにスタックの「作業」を「解決」し、中間表現を合成する必要があります。 そのような翻訳者の一部は書かれており、不適切と判断されました-複雑さは考えられるすべての境界を超えていました。 たとえば、ローカルでは、呼び出しの時点で、呼び出しがオブジェクト呼び出し(最初のパラメーターはこれ)であるかどうかを調べることは完全に不可能です。 Javaはすべて同じですが、それは私たちにとって重要です。 あなたはそれを理解することができますが、多くの努力をする必要があります。 アナライザーのみを作成すればよいという条件さえありました。非常に信頼性の高いPhantomバイトコードを生成するコンパイラーバックエンドは、その時点で安定していました(「ネイティブ」言語のコンパイラーが準備ができて安定していたため)。



この時点で、スートと呼ばれるフレームワークの腕に落ちなければ、仕事は行き詰まっていたでしょう。 もともとは、Javaバイトコードの静的分析とインスツルメンテーションを目的としていたため、説明したタスクに理想的に適していました。 すすは、JVMファイルクラスを解析し、非常に健全な内部表現を生成します。これは、コンパクト(1.5ダースタイプのノード)に基づく操作のツリーと、タイプおよびその他のメタ情報に関する情報です。



この時点から、変換は壊滅的に単純になります。実際、ツリーをツリーに変換する必要があります。 ちなみに、Dalvik(Andrid VMバイトコード)のサポートを取得します。



これは、すべてがクラウドレスになったと言うことではありません。 最初のプリミティブJavaクラスはすでにコンパイルに合格しており、コンパイラの単体テストの作業が開始されていますが。 まだ多くの問題があります。



たとえば、ファントムでは、「内部」実装を持つクラスからの継承は禁止されていました。 同時に、Javaはjava.lang.Stringをinternal.Stringではなく文字列として「使用」します。 しかし、それは大丈夫です! オブジェクトの比較ではさらに困難です。 Javaでは、整数と文字列の==は異なる動作をし、それぞれ値と参照を比較します。 より一貫性のあるPhantomは、値と参照の比較を明確に区別します。つまり、== and!=演算子の単純な変換が問題を引き起こします。タイプを整理するか、ベースに「javascript」バイトコードを入力する必要があります。 これは「ずさん」ですが、非常に簡単です。



一般に、当初は、Javaタイプシステムは、Javaブランチ内の仮想仮想マシンタイプツリーに表示することでカプセル化する必要があると想定されていました。 実際、私はこれをあきらめました。 これは解決するよりも多くの問題を引き起こすようです。



ばかげた問題は、パブリックフィールドへのアクセスでした:ファントムには...何もありません。 一般的に。 メソッドのみ。 問題を回避するには、ゲッターとセッターの自動生成と使用が必要でした。 これはおそらく問題でもあります-現在、典型的な「Java」名のgetVariable / setVariableが与えられており、競合を引き起こす可能性があります。 どうやら、「生成された」メソッドの名前を特別にし、メソッドの通常の名前空間からアクセスできないようにする必要がありますが、これを行うことも少し残念です-パブリックセッターゲッターの自動生成は値を適用します。



次の問題は、同期プリミティブです。 Javaでは、同期ポイントは任意のオブジェクトにできます。 このために、各Phantomオブジェクトに特別なフィールドを保持したくありませんが、何らかの方法でオブジェクトを「完成」させる必要があります。 さらに、同期だけでなく、たとえば、弱いリンクのメカニズムでは、追加のエンティティをオブジェクトに「ハング」させる必要があります。 現時点では、これはオブジェクトのタイトルフィールドを介して行われることになっています。このフィールドでは、必要に応じて、1つまたは複数のオブジェクトを特別なケースに対応させることができます。 ほとんどの「線形」オブジェクトの場合、このフィールドは空で、何か特別なことが行われた場合にのみ入力されます。



ふう おそらく、そもそもこれにセミコロンを付けてください。



まあ、はい、それがすべてです-オープンソース。 OSでの作業に参加したい場合、またはプロジェクトに既製の仮想マシンが必要な場合、プロジェクトはphantomuserlandキーを使用してgithubに簡単に配置できます。



All Articles