(57)【要約】【課題】  バイトコードをネイティブコードにコンパイルして実行するＪａｖａ（登録商標）仮想マシンにおいて、メソッド呼び出しを効率化すること。【解決手段】  ＪＩＴコンパイルされていないメソッドはインタプリタ１で実行される。また、決まった条件を満たしたメソッドはＪＩＴコンパイラ２によりネイティブコード４にコンパイルされる。ＪＩＴコンパイラ２は、ＪＩＴコンパイルされるメソッドが、フレームを作らないで実行できるかどうかを判別し、そのようなメソッドに対してはフレームを作らないで実行するネイティブコードを生成し、そうでないメソッドに対しては、フレームを作って実行するネイティブコードを生成する。また、ＪＩＴされるすべてのメソッドが、必要になった時にフレームを作るネイティブコードにコンパイルされるようにしてもよい。【選択図】          図１
2005284729.tif 000002
【特許請求の範囲】
【請求項１】
バイトコードをネイティブコードに、プログラム実行中にコンパイルする手段を備えた仮想マシンであって、
上記コンパイルする手段は、これからコンパイルするメソッドが、フレームなしで実行できることを判別する手段と、
フレームなしで実行できる場合には、フレームを作らないで実行できるネイティブコードを生成する手段と、
フレームなしで実行できない場合には、フレームを作って実行するネイティブコードを生成する手段を備えた
ことを特徴とする仮想マシン。
【請求項２】
バイトコードをネイティブコードに、プログラム実行中にコンパイルする手段を備えた仮想マシンであって、
上記コンパイルする手段は、
コンパイルされたメソッドの実行中にフレームが必要な処理が起きたとき、そのメソッドに対応するフレームがインタプリタスタックに作られたかどうか判別するコードと、フレームが作られていない場合に、インタプリタスタックに、実行中のネイティブコードのフレームを作るコードを生成する手段と、
上記インタプリタスタックに、実行中のネイティブコードのオペランドスタックの内容をデキャッシュするコードと、上記インタプリタスタックから実行中のネイティブコードのオペランドスタックの内容をキャッシュするコードを生成する手段を備えた
ことを特徴とする仮想マシン。
【請求項３】
請求項２記載のコンパイルする手段は、これからコンパイルされるメソッドが必ずフレームを必要とすることを判別し、フレームを必要とする場合には、ネイティブコードに、フレームを作るコードを挿入する手段を有する
ことを特徴とする仮想マシン。
【請求項４】
請求項２または請求項３記載のコンパイルする手段は、コンパイル時にバイトコード命令ごとにオペランドスタックの内容の型を計算する手段と、
インタプリタスタックにオペランドスタックの内容をデキャッシュするコードと、
インタプリタスタックからオペランドスタックの内容をキャッシュするコードとを生成する手段を有する
ことを特徴とする仮想マシン。
【請求項５】
バイトコードをネイティブコードに、プログラム実行中にコンパイルする機能を備えた仮想マシンにおけるコンパイルのためのプログラムであって、
上記プログラムは、
コンパイルされたメソッドの実行中にフレームが必要な処理が起きたとき、そのメソッドに対応するフレームがインタープリタスタックに作られたかどうか判別するコードと、フレームが作られていない場合に、インタプリタスタックに、実行中のネイティブコードのフレームを作るコードを生成する処理と、
上記インタプリタスタックに、実行中のネイティブコードのオペランドスタックの内容をデキャッシュするコードと、上記インタープリタスタックから実行中のネイティブコードのオペランドスタックの内容をキャッシュするコードを生成する処理をコンピュータに実行させる
ことを特徴とするプログラム。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は、バイトコードをネイティブコードにコンパイルする仮想マシンに関し、さらに詳細にはＪａｖａ（登録商標）プログラム言語におけるバイトコードをネイティブコードにコンパイルして実行するＪａｖａ（登録商標）仮想マシンに関するものである。なお、Ｊａｖａ（登録商標）はサンマイクロシステムズ社の登録商標であり、以下ジャバともいう。
【背景技術】
【０００２】
近年、家電機器、車載機器などの組み込みシステムにおいてジャバシステムが用いられる事例が増えている。ジャバプログラムはジャバのバイトコードをジャバ仮想マシンで実行するインタプリタ型のため、そのままでは実行効率が悪い。
そこでジャバプログラムのスピードアップの方法の一つとして、バイトコードをＪＩＴｅｄコード（本発明ではネイティブコードという）にコンパイルして実行する、Ｊｕｓｔ  ｉｎ  Ｔｉｍｅ（ＪＩＴ）コンパイルという方法がある
ＪＩＴされたコードは（１）コードそのものの実行効率の改善、（２）メソッド呼び出しの効率化、によってバイトコードの実行より高速になっている。
しかし、上記組み込みシステム等では、メモリ量に制限があり、ＪＩＴコンパイラの動作中にメモリが不足する状況が生ずる。
そこで、破棄可能な既存のＪＩＴｅｄコードの一部あるいは全てを破棄し、それらが占めていた領域を開放することにより、新たな空きメモリを得るという方法が知られている。例えば、特許文献１には、スレッドスタック上でＪＩＴｅｄフレームのみを検出し、アクティブなメソッドを発見し、非アクティブなメソッドのＪＩＴｅｄコードを破棄することで、空きメモリを得る方法が提案されている。上記破棄する作業全体をＪＩＴコード・ガーベジコレクション（ＧＣ）と呼んでいる。
【０００３】
ここで、メソッド呼び出しの効率化について説明する。ジャバ仮想マシンはスレッドごとにインタプリタスタックを持っていて、メソッド呼び出しの時、インタプリタスタックに新しいフレームがプッシュされ、メソッドから復帰する時、フレームがポップされる。
一方、ＪＩＴされたメソッドがＪＩＴされたメソッドを呼び出す時、ネイティブコードのサブルーチン呼び出しと同様、ネイティブスタックにフレームを作る。ネイティブスタックを使った呼び出しはインタプリタスタックを使った呼び出しより低コストなため、プログラムが高速化される。
しかし、ＪＩＴされたメソッドがネイティブスタックを使って呼び出しを行うシステムでは、ガーベジコレクション（ＧＣ）の時のスタックスキャンと、例外が起きた時の例外ハンドリングを、インタプリタスタックだけでなくネイティブスタックでも行わなければならない。
ネイティブスタックは（１）インタプリタスタックと構造が全く異なり、構造はＣＰＵアーキテクチャに依存する、（２）ＪＩＴされたメソッドのフレームだけでなく一般のサブルーチンのフレームも混在する、などの理由でスタックスキャン等が煩雑であるという問題がある。
【０００４】
また、ネイティブスタックを使う呼び出しでは、ジャバプログラムで深い呼び出しや再帰呼び出しがあると、ネイティブスタックが大幅に伸長する。特にクラスの初期化ではスーパークラスの初期化ルーチンが再帰的に起動され、ネイティブスタックが伸長しやすい。組み込み系でないシステムではメモリの制約が少なく、また、一般的にメモリアクセスを制御するハードウエアが実装されていてハードウエア的にネイティブスタックのオーバーフローチェックが行えるので、ネイティブスタックの伸長はそれほど問題にならない。しかし、前記した組み込みシステムではメモリが少なくメモリアクセスを制御するハードウエアが実装されていない場合も多いので、ネイティブスタックの伸長はできるだけ回避したい。
以上のようなことから組み込みシステムでは、ＪＩＴされたコードのメソッド呼び出しもインタプリタスタックを使う方法がある。この方法はメソッド呼び出しの効率化があまり期待できないという欠点があるが、（１）スタックスキャン、例外ハンドリングがＪＩＴされていないメソッドと共通化できる、（２）メソッド呼び出しに伴いインタプリタスタックは伸長するがネイティブスタックは伸長しない、という利点がある。
しかしやはり組み込みシステムでもできるだけインタプリタスタックへフレームを作ることを抑えてメソッド呼び出しを効率化したいという要求がある。
【特許文献１】特開２０００−３５８９０号公報
【発明の開示】
【発明が解決しようとする課題】
【０００５】
従来技術ではＪＩＴされたメソッドの呼び出しにネイティブスタックを使うとスタックスキャン等が煩雑になり、かつ、ネイティブスタックが伸長する問題が起き、一方、メソッドの呼び出しにインタプリタスタックを使うとメソッド呼び出しの高速化が期待できない。
本発明は上記問題を解決し、バイトコードをネイティブコードにコンパイルして実行する、組み込みシステム等に適用されるジャバ仮想マシンにおいて、メソッド呼び出しを効率化することを目的とする。
さらに詳細には、メソッドがフレームを作らずに実行できるかどうか判別し、それらのメソッドがフレームを作らず実行できるネイティブコードを生成するＪＩＴコンパイラを提供することを目的とする。
また、フレームが必要かどうか実行してみなければわからないメソッドを、メソッド実行時に必要になった時にフレームを作るようなネイティブコードを生成するＪＩＴコンパイラを提供することを目的とする。
また、実行時に必ずフレームを必要とするメソッドを判別し、実行時にフレームの有無のチェックを行わないネイティブコードを生成するＪＩＴコンパイラを提供することを目的とする。
さらに、コンパイル時にオペランドスタックの内容の型を計算し、オペランドスタックの内容をキャッシュ、デキャッシュするコードを持つネイティブコードを生成するＪＩＴコンパイラを提供することを目的とする。
【課題を解決するための手段】
【０００６】
（１）本発明の第１の特徴では、これからＪＩＴコンパイルされるメソッドが、フレームを作らないで実行できるかどうかを判別し、そのようなメソッドに対してはフレームを作らないで実行するネイティブコードを生成し（このようなメソッドをフレームレスメソッドという）、そうでないメソッドに対してはフレームを作って実行するネイティブコードを生成する。
フレームレスで実行できるかどうかの判別は、そのメソッドがさらにメソッドを呼び出さない、かつ、メソッド実行中にＧＣが起きない、かつ、メソッドが例外ハンドラを持たない、ということを判別して行う。
フレームレスメソッドではアーギュメントはインタプリタスタックにあり、アーギュメント以外のローカル変数とオペランドスタックはネイティブスタックにある。フレームレスでないメソッドではバイトコードの実行と同じく、ローカル変数もオペランドスタックもインタプリタスタックに持つ。
フレームレスかそうでないかはネイティブコードに付随するフラグで区別が明確になるようにする。ネイティブコードが呼び出される時、フラグを見て、フレームレスでないネイティブコードならばフレームを作り、そうでなければ、フレームを作らないでネイティブコードを実行開始する。従来の方法ではすべてのメソッド呼び出しの時にフレームを作っていたが、本発明の第１の特徴ではフレームがなくても実行できるメソッドはフレームを作らないで実行されるので、実行効率がよくなる。
（２）本発明の第２の特徴では、ＪＩＴされるすべてのメソッドが、必要になった時にフレームを作るネイティブコードにコンパイルされる。
ネイティブコードは、ローカル変数はインタプリタスタックに持ち、オペランドスタックはネイティブスタックに持つ。
ネイティブコード実行中に、メソッドの呼び出し、オブジェクト割付、スタックスキャン、例外、が起きると、ネイティブコードがインタプリタスタックにフレームを作る。またネイティブスタックにあったオペランドスタックの内容をインタプリタスタックにデキャッシュする。メソッド呼び出し、オブジェクト割付、スタックスキャンが完了してネイティブコードの実行が再開される時、インタプリタスタックにあるオペランドスタックの内容をネイティブスタックにキャッシュする。
本発明の第２の特徴によれば、ネイティブコード実行中にメソッドの呼び出し、オブジェクト割付、スタックスキャン、例外が起きなければインタプリタスタックにフレームが作られないので、実行効率がよくなる。
（３）本発明の第３の特徴では、本発明の第２の特徴にさらに、ＪＩＴコンパイルするメソッドが同期メソッドか、または、最初の分岐の前にメソッド呼び出し命令、または、オブジェクト割付命令があるかを判別し、もしそうならばネイティブコードの実行開始直後にフレームを作る。
必ずフレームを必要とするメソッドではネイティブコード実行中、フレームの有無を調べて無ければ作る処理を省略できるので、本発明の第３の特徴によれば、実行効率がよくなる。
（４）本発明の第４の特徴では、本発明の第２の特徴にさらに、コンパイル時、オペランドスタックの内容の型を計算し、インタプリタスタックからのオペランドスタック内容のキャッシュとインタプリタスタックへのオペランドスタック内容のデキャッシュを行うコードをネイティブコードに持つ。
専用のコードは汎用ルーチンより高速なので、本発明の第４の特徴によれば、実行効率がよくなる。
【発明の効果】
【０００７】
本発明によれば、以下の効果を得ることができる。
（１）インタプリタスタックを使うネイティブコードを生成するＪＩＴコンパイラにおいて、実行時にフレームを必要とする処理を行わないメソッドに対しては、フレームなしで実行するネイティブコードを生成しているので、不要なフレームの生成を抑えることができる。
（２）実行時にフレームが必要かどうかコンパイル時にわからないメソッドに対しては、ネイティブコード実行中にフレームが必要になった時だけにフレームを作ることで、不要なフレームの生成を抑えることができる。
（３）実行時に必ずフレームを必要とするメソッドに対しては、ネイティブコードの実行開始直後にフレームを作ることで、ネイティブコード実行中に、フレームが作られたかどうかのチェックを省略することができる。
（４）コンパイル時、オペランドスタックの内容の型を計算し、インタプリタスタックからのオペランドスタック内容のキャッシュと、インタプリタスタックへのオペランドスタック内容のデキャッシュを行うコードを生成することで、高速にオペランドスタックのキャッシュ、デキャッシュを行うコードを生成することができる。
【発明を実施するための最良の形態】
【０００８】
（１）第一の実施の形態
図１に本発明のシステム全体の構成を示す。
コンピュータ１１はハードウエア１２とＯＳ１３を有し、０Ｓ１３上にジャバ仮想マシン１０を備える。
ジャバ仮想マシン１０はインタプリタ１とＪＩＴコンパイラ２を持つ。メソッドのバイトコード３はファイルやネットワークからロードされる。まだＪＩＴされていないメソッドはインタプリタ１で実行される。インタプリタ１でメソッドが実行される時、インタプリタスタック５にフレームが積まれる。決まった条件を満たしたメソッドはＪＩＴコンパイラ２によりネイティブコード４にコンパイルされる。ネイティブコード４が実行される時、条件によって、インタプリタスタック５にフレームが積まれる。
図２に本実施形態における上記ＪＩＴコンパイラ２の機能構成を示す。ＪＩＴコンパイラ２は、メソッドがフレームなしで実行できることを判別するための判別手段２ａと、フレームなしで実行できるネイティブコードを生成するネイティブコード生成手段２ｂと、フレームがある状態で実行できるネイティブコードを生成するネイティブコード生成手段２ｃを有する。
【０００９】
図３にインタプリタでメソッドをＪＩＴするルーチンが呼び出される時の処理を示す。  メソッド呼び出し時に、そのメソッドがＪＩＴされていない場合、何回呼び出されたかをカウントアップし、指定回数以上呼び出されたメソッドがあれば、ＪＩＴを試みる。
すなわち、図３に示すように、メソッドの呼び出しを開始すると、メソッドがＪＩＴされたかを調べる（ステップＳ１）。メソッドがＪＩＴされていれば、ステップＳ６に行き、ネイティブコードの実行を行う。また、ＪＩＴされていなければ、ステップＳ２で、メソッドが呼び出された回数をカウントアップする。
そして、指定回数以上呼び出されたかを調べ（ステップＳ３）、指定回数以上呼び出されていなければ、バイトコードを実行する（ステップＳ５）。また、指定回数以上呼び出されていれば、メソッドをＪＩＴコンパイルし（ステップＳ４）、ネイティブコードを実行する（ステップＳ６）。
【００１０】
図４にメソッドをＪＩＴする時の本実施形態における処理を示す。
まず、ジャバメソッドのみＪＩＴを行う。すなわち、メソッドがジャバメソッドであるかを調べ（ステップＳ１）、ジャバメソッドでなければ処理を終了する。
ジャバメソッドの場合には、このメソッドがフレームなしで実行できるかどうか判別する。この判別は、このメソッドがさらにメソッドを呼び出さない、かつ、メソッド実行中にＧＣが起きない、かつ、メソッドが例外ハンドラを持たない、という条件を満たすかどうかを判別することによって行う（図４のステップＳ２〜Ｓ４）。
上記条件を満たすメソッドに対してはフレームを作らないで実行するネイティブコードを生成し（ステップＳ５）、そうでないメソッドに対してはフレームを作って実行するネイティブコードを生成する（ステップＳ６）。そして、フレーム有無を示すフラグをセットする（ステップＳ７）。
【００１１】
ここでメソッドが他のメソッドを呼び出さないという判別は、メソッドのバイトコードの中にメソッド呼び出し系の命令を含まないということで判別する。
また、メソッド実行中にＧＣが起きないという判別は、メソッドのバイトコードの中にオブジェクト割付系の命令を含まない、かつ、メソッドが同期でない、かつ、同期系の命令を含まない、かつ、ＧＣチェックポイントを入れる必要のある命令を含まないということで判別する。ここでＧＣチェックポイントを入れる必要のある命令とは後方分岐命令とサブルーチン呼び出し命令（ｊｓｒ）である。
厳密の言えば、フレームレスメソッドがネイティブスタック等にオブジェクト参照をキャッシュしていなければ、フレームレスメソッド実行中にＧＣが起きても問題ない。例えば、メソッド実行開始時点でネイティブスタックにオペランドスタックの内容がキャッシュされていない状態ではＧＣが起きても差し支えない。また、メソッドのＪＩＴコンパイル時にオペランドスタックの内容の型チェックをして、オブジェクト参照を含まないようならば、後方分岐命令があってもフレームレスメソッドになりうる。
ＪＩＴされたメソッドは、フレームレスかそうでないかのフラグを持つこととし、上記のようにフレームの有無を示すフラグをセットする。
【００１２】
ジャバのメソッド呼び出しでは呼び出し元メソッドがインタプリタスタックにフレームをプッシュし、続いて呼び出し先メソッドの実行が始まる。
図５に本発明の第１の実施形態による、メソッド呼び出し処理を示す。
最初に、フレームの有無を示すフラグ（前記図４のステップＳ７参照）を参照して、これから呼び出すネイティブコードがフレームレスかどうかを、判断する（ステップＳ１，Ｓ２）。もし、フレームレスメソッドならフレームを作らずにネイティブコードの実行を開始する。そうでなければフレームをプッシュした後（ステップＳ３）、ネイティブコードの実行を開始する。
一方、フレームのポップは呼び出し先メソッドが行う。すなわち、バイトコードの復帰命令をコンパイルする時、フレームレスでないメソッドはフレームをポップする処理を行う部分の処理をコードに入れるが、フレームレスメソッドではそれを入れない。
【００１３】
図６により、フレームレスメソッドが実行される時のインタプリタスタックおよびネイティブスタックの内容を、例を用いて説明する。図６において、図６（ａ）はインタプリタスタックの内容、（ｂ）はネイティブスタックの内容を示す。
このフレームレスメソッドの例では、アーギュメント（引数）はインタプリタスタックにあり、アーギュメント以外のローカル変数とオペランドスタックはネイティブスタックにある。ただし、ＲＩＳＣアーキテクチャのＣＰＵではオペランドスタックの内容をすべてレジスタに持つことも考えられる。
ここでは、ａｌｏａｄ＿０，ｇｅｔｆｉｅｌｄ，ｉｒｅｔｕｒｎというバイトコード列で構成されるメソッドを例に取る。なお、ａｌｏａｄ＿０，ｇｅｔｆｉｅｌｄ，ｉｒｅｔｕｒｎはバイトコード表現であるが、これをネイティブコードにコンパイルしたものが実行される。
この例では、アーギュメントが１個、アーギュメント以外のローカル変数が０個、従ってローカル変数は一個である。
【００１４】
初期状態ではインタプリタスタックにアーギュメントが積まれており、ネイティブスタックは空である（図６(i) ）。
ａｌｏａｄ＿０は０番目のローカル変数をネイティブスタックにプッシュするコードに変換される。このＪＩＴされたコードが実行されると、インタプリタスタックのオブジェクト参照（図６のＡ）がネイティブスタックにプッシュされる（図６(ii)）。
ｇｅｔｆｉｅｌｄはネイティブスタックのトップにあるオブジェクト参照のフィールド値を取得し、オブジェクト参照（図６のＡ）をポップし、フィールド値（図のＢ）をプッシュするコードに変換される。
このＪＩＴされたコードが実行されると、同図に示すように、インタプリタスタックにオブジェクト参照（図６のＡ）がポップされ、ネイティブスタックに、フィールド値（図のＢ）がプッシュされる（図６(iii) ）。
ｉｒｅｔｕｒｎはネイティブスタックのトップにある値を、呼び出し元フレームのオペランドスタックのトップに書き込むコードに変換される。フレームレスメソッドでは常に呼び出し元フレームのオペランドスタックのトップは呼び出し先メソッドの０番目のローカル変数と一致するので、この場合は０番目のローカル変数に書き込むコードに変換される。
このＪＩＴされたコードが実行されると、ネイティブスタックのトップにある値（図のＢ）が、インタプリタスタックに書き込まれる（図６(iv)）。
ここで、呼び出し側のフレームのスタックのトップは、フレームレスメソッド呼び出し時はそのままで、フレームレスメソッドからの復帰の時にアーギュメントサイズ分減らされ、リターン値サイズ分増やされる。
【００１５】
次に、本発明の第２〜第４の実施形態について説明する。
以下に説明する第２〜第４の実施形態は、ＪＩＴされるすべてのメソッドが、必要になった時にフレームを作るネイティブコードにコンパイルされるようにしたものである。
また、第３の実施形態は、上記において、ネイティブコード実行中に必ずフレームが作られるメソッドであるかを調べ、その場合には、ネイティブコードの最初にフレームを作るコードを挿入するようにしたものである。
さらに、第４の実施形態は、上記において、コンパイル時に一命令ごとにオペランドスタックの内容の型を計算し、オペランドスタックのキャッシュ、デキャッシュをおこなうコードを、オペランドスタックの内容にもとづいて生成するようにしたものである。
図７に本発明の第２〜第４の実施形態におけるＪＩＴコンパイラ２の機能構成を示す。  第２〜第４の実施形態のＪＩＴコンパイラ２は、必要になったときにフレームを作る機能を備えたネイティブコードを生成するネイティブコード生成手段２ｄと、メソッドが実行時にフレームを必ず必要とするかを判別する判別手段２ｅと、フレームを必要とするメソッドの場合にフレームを作るネイティブコードを生成する手段２ｆと、スタックマップを計算する計算手段２ｇと、オペランドスタックのキャッシュ、デキャッシュを行うネイティブコードを生成する手段２ｈを有する。
【００１６】
（２）第２の実施形態
図８に本発明の第２の実施の形態によって、メソッドをＪＩＴする時の処理を示す。
本実施形態では、第１の実施の形態のような「フレームを作るメソッド」、「フレームを作らないメソッド」の場合分けがなく、ＪＩＴされるすべてのメソッドが、上記図７に示したネイティブコードコード生成手段２ｄにより、必要になった時にフレームを作るネイティブコードにコンパイルされる。
すなわち、図８に示すように、メソッドがジャバメソッドであるかを調べ（ステップＳ１）、ジャバメソッドでなければ処理を終了し、ジャバメソッドであれば、必要になったときにフレームを作るネイティブコードを生成する（ステップＳ２）。この生成されたネイティブコードは、ネイティブコード実行中に、メソッドの呼び出し、オブジェクト割付、スタックスキャン、例外が起きると、実行時にフレームが作られたかどうかを判別し、まだ作られていなければインタプリタスタックにフレームを作る。
第２の実施の形態によるネイティブコードも、オペランドスタックはネイティブスタックに持つが、ローカル変数はアーギュメントであるものもそうでないものもインタプリタスタックに持つ。ただし、ＲＩＳＣアーキテクチャのＣＰＵではオペランドスタックの内容をすべてレジスタに持つことも考えられる。
【００１７】
図９にネイティブコード実行中のインタプリタスタックの様子を示す。図９（ａ）は実行前のインタプリタスタックの内容を示し、（ｂ）はフレームが作られた状態を示す。
ネイティブコード実行開始時には同図（ａ）に示すように、呼び出し元メソッドのフレームだけがスタックにある。呼び出されたメソッドについてはローカル変数だけがスタックに置かれる。
ネイティブコード実行中に、メソッドの呼び出し、オブジェクト割付、スタックスキャン、例外が起きると、ネイティブコードが、同図（ｂ）に示すように、インタプリタスタックにフレームを作る。またネイティブスタックまたはレジスタにあったオペランドスタックの内容を、インタプリタスタックにデキャッシュ（コピー）する。
さらに、メソッド呼び出し、オブジェクト割付、スタックスキャンが完了してネイティブコードの実行が再開される時、インタプリタスタックにあるオペランドスタックの内容をネイティブスタックまたはレジスタにキャッシュ（コピー）する。
【００１８】
図１０に、バイトコードのｉｆｅｑを例に用いて、必要になった時にフレームを作るネイティブコードについて説明する。
ｉｆｅｑはオペランドスタックの一番上の値をポップしてそれがゼロの時分岐する命令である。この分岐が後方分岐ならば、命令実行前にＧＣリクエストがあった時、ＧＣチェックポイントに入る必要がある。
ここで、ＧＣチェックポイントについて説明する。インタプリタスタックはオブジェクト参照のルートであるためＧＣ時にスキャンする必要がある。ただし実行効率のため、インタプリタスタックの内容が別の場所にキャッシュされていることがある（コンシステントでない）。これはインタプリタ実行時でも同様である。
スタックスキャンを行うためにはすべてのスレッドのインタプリタスタックがコンシステントでなければならない。またＧＣが必要になった時可能なかぎり速やかにＧＣを行うことが必要である。
そこでループの中にはインタプリタスタックがコンシステントでありスタックスキャン可能なＧＣチェックポイントを置かなければならない。ループには必ず後方分岐命令が使われるので、後方分岐命令でチェックポイントを置くようにする（ｊｓｒも同様）。
【００１９】
次に、図１０の処理を、行番号順に説明する。なお、図１０はインテル系ＣＰＵのアセンブラ言語である。
・行１はＧＣリクエストがあるかどうかを取得する処理である。ＧＣリクエストがあればＥＡＸレジスタに非ゼロ、なければゼロが返される。
・行２〜３はＧＣリクエストがない場合ｌａｂｅｌ２へジャンプする処理である。
・行４は今実行中のメソッドのフレームへのポインタを取得する処理である。すでにフレームが作られていればＥＡＸレジスタにフレームへのポインタが返され、まだ作られていなければヌルが返される。
・行5 〜６はすでにフレームが作られていた場合、ｌａｂｅｌ１へジャンプする処理である。
・行７はフレームを作るサブルーチンを呼び出す処理である。
・行９はネイティブスタックにあるオペランドスタックの内容をインタプリタスタックにデキャッシュする処理である。
・行１０はＧＣチェックポイントに入る処理である。
・行１１はインタプリタスタックにあるオペランドスタックの内容をネイティブスタックにキャッシュする処理である。
・行１３〜１５はｉｆｅｑの処理である。すなわちオペランドスタックから１ワードポップして、ゼロであればａｄｄｒｅｓｓ１へジャンプする。ここでａｄｄｒｅｓｓ１はバイトコードのオフセットに対応するネイティブコードの番地である。
第２の実施の形態によるネイティブコードでは復帰する時にフレームの有無を調べ、もしフレームが作られていたらポップし、作られていなければポップしないで、復帰する。
【００２０】
（３）第３の実施の形態
上記第２の実施の形態では、ネイティブコード実行中にメソッドの呼び出し、オブジェクト割付、スタックスキャン、例外が起きるとフレームが作られたかどうか調べ、作られていない場合は作る処理を行うようにしている。
しかし、メソッドが同期メソッドの時、または、最初の分岐の前にメソッド呼び出し命令、または、オブジェクト割付命令がある場合には必ずネイティブコード実行中にフレームが作られる。
したがってこのようなメソッドでは最初からフレームを作ってしまった方が、ネイティブコード実行中にフレームの有無を調べるより効率的である。
第３の実施の形態では、前記図７の判別手段２ｅにより、ＪＩＴコンパイル時にメソッドが同期メソッドか、または、最初の分岐の前にメソッド呼び出し命令、または、オブジェクト割付命令があるかを判別し、もしそうならば、ネイティブコード生成手段２ｆによりフレームを作るネイティブコードを生成し、ネイティブコードの最初に挿入する。
さらに、ネイティブコード実行中にはフレームがすでにできているものとして、メソッド呼び出し命令、オブジェクト割付命令、スタックスキャン、例外のネイティブコードでは、フレームの有無を調べて無ければ作る処理を省略する。
【００２１】
図１１に本発明の第３の実施の形態によって、メソッドをＪＩＴする時の処理を示す。  メソッドがジャバメソッドであるかを調べ（ステップＳ１）、ジャバメソッドでなければ処理を終了し、ジャバメソッドであれば、メソッドが同期メソッドであるかを調べ（ステップＳ１）、同期メソッドであれば、フレームを作って実行するネイティブコードを生成する（ステップＳ５）。また、同期メソッドでない場合には、最初の分岐の前にメソッドの呼び出し、オブジェクトの割付命令があるかを調べ（ステップＳ３）、そうであれば、上記と同様、フレームを作って実行するネイティブコードを生成する（ステップＳ５）。
また、そうでなければ、必要なときにフレームを作って実行するネイティブコードを生成する（ステップＳ４）。
【００２２】
図１２に、常にフレームを持つメソッドの本実施の形態による前記ｉｆｅｑのネイティブコードを示す。
本実施の形態により生成されるネイティブコードは、前記図１０に示した第２の実施の形態のネイティブコードおいて、５、６、７、８行目が省略された形であり、すでにフレームが作られていた場合、ｌａｂｅｌ１へジャンプする処理と、フレームを作るサブルーチンを呼び出す処理が省略されたものである。
【００２３】
（４）第４の実施の形態
前記第２の実施の形態でＪＩＴされたコードの実行中に、オペランドスタックの内容のキャッシュ、デキャッシュが行われる時、オペランドスタックの大きさ（何個値が積まれているか）は実行時にわかる。またメソッド呼び出し時のアーギュメントと戻り値に関しては、メソッドのシグニチャより型もわかる。したがって、これらの情報にもとづいてキャッシュ、デキャッシュは可能である。
しかし、この場合、値の数と型を実行の都度、取得する処理が必要である。
一方、ジャバのバイトコードではどんなパスを通っても、ある命令の実行時におけるオペランドスタックの内容の型は決まっている。すなわち、コンパイル時にキャッシュ、デキャッシュする内容の型が決まっている。したがってあるバイトコード実行中のオペランドスタックの内容に合致したキャッシュ、デキャッシュのためのコードをネイティブコードに入れることができる。
そこで、コンパイル時に、前記図７のスタックマップを計算する計算手段２ｇにより、オペランドスタックの内容の型を求め、オペランドスタックの内容の型に基づいて、ネイティブコードコード生成手段２ｈにより、キャッシュ、デキャッシュするネイティブコードを生成する。このようにすることで、実行の都度、値の数と型を取得する必要がなくなり、汎用ルーチンによるキャッシュ、デキャッシュより実行効率が良い。
以上のように、本実施の形態では、コンパイル時に一命令ごとにオペランドスタックの内容の型を計算し、オペランドスタックのキャッシュ、デキャッシュをおこなうネイティブコードを、オペランドスタックの内容にもとづいて生成する。
【００２４】
図１３に第４の実施の形態による、コンパイル時にオペランドスタックの内容の型を計算する処理を示す。
図１３において、ａｌｏａｄ＿０では、オペランドスタックにオブジェクト参照が積まれる。ｉｌｏａｄ＿１では整数型が積まれる。
ｉｎｖｏｋｅｖｉｒｔｕａｌ  ｊａｖａ．ｌａｎｇ．Ｓｔｒｉｎｇ．ｃｈａｒＡｔ（）はＳｔｒｉｎｇクラスのオブジェクトと一個の整数を引数に取り、一個のｃｈａｒ型を返すメソッドである。
したがって、このメソッドの実行ではオブジェクト参照と整数型がポップされ、図１３に示すように整数型が積まれる。（ジャバではｃｈａｒ型もスタックに積まれる時は３２ｂｉｔ）
【００２５】
この場合ｉｎｖｏｋｅｖｉｒｔｕａｌの前のデキャッシュでは一個のオブジェクト参照と一個の整数型をインタプリタスタックにデキャッシュすればよい。
また、ｉｎｖｏｋｅｖｉｒｔｕａｌの後のキャッシュでは一個の整数型をネイティブスタックまたはレジスタにキャッシュすればよい。
汎用ルーチンでのキャッシュ、デキャッシュではｉｎｖｏｋｅｖｉｒｔｕａｌの時に、呼び出されるメソッド（ここではｊａｖａ．ｌａｎｇ．Ｓｔｒｉｎｇ．ｃｈａｒＡｔ（））のシグニチャを取得し、シグニチャを参照してキャッシュ、デキャッシュを行う必要がある。すなわち、Ｃ言語などで書かれた汎用ルーチンでのデキャッシュ処理の場合、メソッドブロックからメソッドシグニチャを取得し、シグニチャのエントリ（この場合はｃｈａｒ型１個と参照型１個の合計２個）を一つ一つ解析しながらデキャッシュしなければならないが、本発明の第４の実施の形態ではそれが不要になる。
【図面の簡単な説明】
【００２６】
【図１】本発明のシステム全体のブロック図である。
【図２】本発明の第１の実施の形態におけるＪＩＴコンパイラの機能構成を示すブロック図である。
【図３】インタプリタ実行中にメソッドのＪＩＴコンパイルが行われる処理を示す図である。
【図４】フレームレスおよびそうでないメソッドをＪＩＴコンパイルする処理を示す図である。
【図５】フレームレスおよびそうでないメソッドのネイティブコードを実行する処理を示す図である。
【図６】フレームレスメソッド実行中のインタプリタスタックとネイティブスタックの様子を示す図である。
【図７】本発明の第２〜第４の実施の形態におけるＪＩＴコンパイラの機能構成を示すブロック図である。
【図８】実行中にフレームが必要になった時に作るネイティブコードをＪＩＴコンパイルする処理を示す図である。
【図９】ネイティブコード実行中にフレームが作られる様子を示す図である。
【図１０】実行中にフレームが必要になった時に作るネイティブコードの例を示す図である。
【図１１】必ずフレームが作られるメソッドの場合、フレームを作るコードを生成する処理を示す図である。
【図１２】実行中にフレームを必ず作るメソッドのネイティブコードの例を示す図である。
【図１３】コンパイル中にオペランドスタックの内容の型を計算する処理を示す図である。
【符号の説明】
【００２７】
１    インタプリタ
２    ＪＩＴコンパイラ
３    バイトコード
４    ネイティブコード
５    インタプリタスタック
６    ネイティブコードスタック
１０  ジャバ仮想マシン
１１  コンピュータ１１
１２  ハードウエア
１３  ＯＳ
【図１】
2005284729.tif 000003
【図２】
2005284729.tif 000004
【図３】
2005284729.tif 000005
【図４】
2005284729.tif 000006
【図５】
2005284729.tif 000007
【図６】
2005284729.tif 000008
【図７】
2005284729.tif 000009
【図８】
2005284729.tif 000010
【図９】
2005284729.tif 000011
【図１０】
2005284729.tif 000012
【図１１】
2005284729.tif 000013
【図１２】
2005284729.tif 000014
【図１３】
2005284729.tif 000015