(57)【特許請求の範囲】
【請求項１】
複数のメソッドを含むプログラムを処理する方法であって、前記方法は前記プログラムを処理するプロセッサを含むコンピュータにより実行され、前記プロセッサが、
呼び出し後の処理においてインライニングした場合とインライニングしない場合とで同じ結果を返さない第１メソッドの呼び出しを含む第２メソッドに前記第１メソッドのコードをインライニングするステップと、
前記第１メソッドのコードをインライニングする前の状態における、前記第１メソッドと前記第２メソッドの呼び出し関係情報を取得して、後に使用可能な記憶域に格納するステップと、
インライニングされた前記第１メソッドのコードを実行する際に、前記第１メソッドを実行中であることを記憶するためのコードを生成するステップと、
を含む、プログラム処理方法。
【請求項２】
インライニング前から前記第２メソッドに含まれるコードを実行する際に、前記プロセッサが、前記第２メソッドを実行中であることを記憶するためのコードを生成するステップ
をさらに含む、請求項１記載のプログラム処理方法。
【請求項３】
前記第１メソッドと前記第２メソッドの呼び出し関係情報は、前記第１メソッドに関する項目に前記第２メソッドに関する項目を指すポインタを含む
ことを特徴とする、請求項１記載のプログラム処理方法。
【請求項４】
複数のメソッドを含むプログラムであって、前記プログラムは、該プログラムを処理するプロセッサを含むコンピュータにより実行され、呼び出し後の処理においてインライニングした場合とインライニングしない場合とで同じ結果を返さない第１メソッドの呼び出しを含む第２メソッドに、メソッド・インライニングによる前記第１メソッドのコードと、インライニングされた前記第１メソッドのコードを実行する際に、前記第１メソッドを実行中であることを記憶するためのコードとを含み、さらに、前記第１メソッドのコードをインライニングする前の状態における、前記第１メソッドと前記第２メソッドの呼び出し関係情報を含んでいて、前記プログラムの実行時に、実行した各メソッドに関する情報を対応フレームとして格納した記憶領域において、前記呼び出し後の処理においてインライニングした場合とインライニングしない場合とで同じ結果を返さない指定メソッドに関連するフレームを検出する方法であって、前記プロセッサが、
前記記憶領域内の現在検査中のフレームに関連する第３メソッドが前記第２メソッドであるか判断するステップと、
前記第３メソッドが前記第２メソッドである場合には、前記第２メソッドに関連する前記呼び出し関係情報を取得するステップと、
前記呼び出し関係情報中の前記第３メソッドの対応項目を取得するステップと、
前記呼び出し関係情報中の前記第３メソッドの対応項目を用いて、前記第３メソッドの呼び出し元メソッドを取得するステップと、
前記呼び出し元メソッドが前記指定メソッドであるか判断するステップと、
前記呼び出し元メソッドが前記指定メソッドでなかった場合には、前記呼び出し関係情報中の前記呼び出し元メソッドの対応項目から、さらなる呼び出し元メソッドを取得するステップと、
を含み、
前記指定メソッドが検出されるまで、または、前記記憶領域のすべてのフレームを検査するまで、前記指定メソッドであるか判断するステップと、前記さらなる呼び出し元メソッドを取得するステップとを繰り返す検出方法。
【請求項５】
複数のメソッドを含むプログラムをコンピュータに処理させる処理プログラムを格納する記憶媒体であって、
前記処理プログラムは、前記コンピュータに、
呼び出し後の処理においてインライニングした場合とインライニングしない場合とで同じ結果を返さない第１メソッドの呼び出しを含む第２メソッドに前記第１メソッドのコードをインライニングするステップと、
前記第１メソッドのコードをインライニングする前の状態における、前記第１メソッドと前記第２メソッドの呼び出し関係情報を取得して、後に使用可能な記憶域に格納するステップと、
インライニングされた前記第１メソッドのコードを実行する際に、前記第１メソッドを実行中であることを記憶するためのコードを生成するステップと、
を実行させる、記憶媒体。
【請求項６】
インライニング前から前記第２メソッドに含まれるコードを実行する際に、前記第２メソッドを実行中であることを記憶するためのコードを生成するステップ
をさらに実行させる、請求項５記載の記憶媒体。
【請求項７】
複数のメソッドを含むプログラムであって、呼び出し後の処理においてインライニングした場合とインライニングしない場合とで同じ結果を返さない第１メソッドの呼び出しを含む第２メソッドに、メソッド・インライニングによる前記第１メソッドのコードと、インライニングされた前記第１メソッドのコードを実行する際に、前記第１メソッドを実行中であることを記憶するためのコードとを含み、さらに、前記第１メソッドのコードをインライニングする前の状態における、前記第１メソッドと前記第２メソッドの呼び出し関係情報を含んでいて、前記プログラムの実行時に、実行した各メソッドに関する情報を対応フレームとして格納した記憶領域において、前記呼び出し後の処理においてインライニングした場合とインライニングしない場合とで同じ結果を返さない指定メソッドに関連するフレームをコンピュータに検出させる処理プログラムを格納した記憶媒体であって、
前記処理プログラムは、前記コンピュータに、
前記記憶媒体内の現在検査中のフレームに関連する第３メソッドが前記第２メソッドであるか判断するステップと、
前記第３メソッドが前記第２メソッドである場合には、前記第２メソッドに関連する前記呼び出し関係情報を取得するステップと、
前記呼び出し関係情報中の前記第３メソッドの対応項目を取得するステップと、
前記呼び出し関係情報中の前記第３メソッドの対応項目を用いて、前記第３メソッドの呼び出し元メソッドを取得するステップと、
前記呼び出し元メソッドが前記指定メソッドであるか判断するステップと、
前記呼び出し元メソッドが前記指定メソッドでなかった場合には、前記呼び出し関係情報中の前記呼び出し元メソッドの対応項目から、さらなる呼び出し元メソッドを取得するステップと、
を実行させ、
前記指定メソッドが検出されるまで、または、前記記憶領域のすべてのフレームを検査するまで、前記指定メソッドであるか判断するステップと、前記さらなる呼び出し元メソッドを取得するステップとを繰り返し実行させる、記憶媒体。
【発明の詳細な説明】
【０００１】
【発明の属する技術分野】
本発明は、コンパイラにおけるメソッド・インライニングに関し、特に、Ｊａｖａ（Sun Microsystemsの商標）ＪＩＴ（Just In Time）コンパイラ等におけるメソッド・インライニングに関する。
【０００２】
【従来の技術】
Ｊａｖａは言語にセキュリティ・チェック機能を有しており、SecurityManagerクラスに以下に示す５つのメソッドを含んでいる。
（１）getClassContext
スタック上の各フレームに対応するメソッドの属するクラスを配列として返すメソッドである。フレームは、メソッドを実行する際に生成される、当該メソッドに関する情報が記憶される記憶領域である。
（２）currentClassLoader
スタック上のフレームに対応するメソッドの属するクラスで、クラスローダーを有する最新のクラスのクラスローダーそれ自体を返す。クラスローダーとは、まだロードされていないクラスをロードするために使用するメソッド群を有するクラスである。最新とは、最も最近に実行された、ということである。
（３）currentLoadedClass
スタック上のフレームに対応するメソッドの属するクラスで、クラスローダーを有する最新のクラスを返す。
（４）currentDepth
指定したクラスと同じクラスに属する最新のメソッドに対応するフレームの、スタックにおける深さを返す。
（５）classLoaderDepth
クラスローダーを有する最新のクラスに属するメソッドに対応するフレームのスタックにおける深さを返す。
【０００３】
これらのメソッドは、スタック上をトレースし必要な情報を獲得する。一方、メソッド・インライニングは、メソッド呼び出しの除去を目的として、実行時にメソッドを呼び出す代わりにコンパイル時に呼び出し側のメソッドのコードを呼び出し元に取り込んでしまうものである。このため、実行時にスタック上には、インライニングされてしまったメソッドの実行情報は生成されなくなる。もし、インライニングされたメソッドのコード中、又はそのメソッドから呼ばれるメソッド中にSecurityManagerクラスのメソッドが含まれていると、それらが正しい結果を返さずにプログラムの挙動が変わってしまうかもしれないという問題が発生する。従って、従来は末端までの呼び出し関係が完全に見切れており、且つそれらのメソッド呼び出しの中にSecurityManagerクラスのメソッドへの呼び出しが含まれていないことが保証されている場合しか、メソッド・インライニングを実行できなかった。
【０００４】
Ｊａｖａなどのオブジェクト指向言語では、メッセージを容易にオーバーロード可能である。そのためモジュールとしての再利用性や柔軟性は高いものの、前述のような保証ができるような解析をコンパイラが行うことはほとんど困難である。Ｊａｖａでは特殊なメソッドにファイナル（final）という記述子を付けることを許している。このfinalは、末端にあってオーバーロードされないという意味である。一般的に用いられるバーチャル（virtual）メソッド呼び出しは、final属性を伴わないとオーバーライドされる可能性があるため、呼び出し先コードを特定できない。では、final属性を基にメソッド・インライニングを実施すればよいかというと、（ａ）一般のプログラマがfinal属性を用いることはまれであって、（ｂ）たとえプログラムの作者自身がオーバーライドされないメソッド呼び出しであると認識していても、多くの場合final属性による明示的な指示がなされていない、という現状からして、それだけではメソッド・インライニングが適用できる範囲は限られてしまう。
【０００５】
なお、"呼び出し関係が完全に見切れるメソッド呼び出し"とは、呼び出されるメソッドがネイティブ・メソッド（native method）ではなく、且つ、スタティック（static）呼び出し、非バーチャル（non-virtual）呼び出し、又はfinal属性のついたvirtualメソッド呼び出しのいずれかで呼び出されるメソッド呼び出しを意味する。nativeメソッドとは、Ｃ言語等Ｊａｖａ以外の言語で書かれ且つコンパイル済のコードで構成されるメソッドである。また、static呼び出しとは、(static)という記述子を付けて定義されたメソッド（static メソッド）に対する呼び出しである。staticメソッドは、オブジェクトを使用せずに呼び出すメソッドであり、他のメソッドによりオーバーロードされることはない。従って、static呼び出しでは常に実行されるメソッドを一意に決定することができる。
【０００６】
【発明が解決しようとする課題】
よって、本発明の目的は、Ｊａｖａのようなセキュリティ機能を有する言語においてメソッド・インライニングによる実行最適化の適用範囲を増大させることである。
【０００７】
さらに、メソッド・インライニングをＪａｖａのＪＩＴ（Just In Time）コンパイラにおいて可能にすることも目的である。
【０００８】
また、メソッド・インライニングを実施する際に、メソッド・インライニングを実施しない場合のスタック情報を再現できるようにすることも目的である。
【０００９】
Ｊａｖａのような言語において、呼び出された後の処理が不確定なメソッドの呼び出し及び自己再帰を含むメソッドに対し、テイル・リカージョン（Tail Recursion）によるループ化を可能にすることも目的である。
【００１０】
さらに、当該ループ化において繰り返し数を把握できるようにすることも目的である。
【００１１】
メソッド・インライニングを実施した場合に、メソッド・インライニング前のメソッド間の呼び出し関係を保存できるようにすることも目的である。
【００１２】
メソッド・インライニングを実施した場合に、どのメソッドのコードを実行しているか判断できるようにすることも目的である。
【００１３】
【課題を解決するための手段】
以上の目的を達成するために、本発明には以下のような態様がある。
第１の態様においては、呼び出された後の処理が不確定なメソッドの呼び出し及び自己再帰を含むメソッドに対し、テイル・リカージョン（テイル・リカージョンは末尾再帰状態をあらわす）のループ化に必要なコードを生成するステップと、ループの繰り返し数をカウントするためのコードを生成するステップとを含む。このようなコードを含むプログラムを実行すれば、ループの繰り返し数をカウントできるので、SecurityManagerの動作時にスタックの深さを補正できる。よって、Ｊａｖａのような言語においてもテイル・リカージョンのループ化で最適化を図ることができる。
【００１４】
上記ループの繰り返し数をカウントするためのコードを生成するステップは、プログラム実行時にスタック上に作業領域を生成するステップを含むようにすることができる。また、ループの繰り返し数のカウントを初期化するコードをループ化に必要なコードの前に生成することも考えられる。さらに、SecurityManagerの動作時に本処理が実施されていることを簡単に検出できるように、ループ化に必要なコードの生成を表すフラグをセットするステップを含むようにすることも考えられる。
【００１５】
一方、呼び出された後の処理が不確定なメソッドの呼び出し及び自己再帰を含み、テイル・リカージョンのループ化に必要なコードと当該ループの繰り返し数をカウントするためのコードとを含む第１メソッドを含むプログラムの実行時に、実行した各メソッドに関する情報を対応フレームとして格納した記憶領域における、所定の条件を満たす指定メソッドに関連するフレームの深さを検出するために、SecurityManagerは、記憶領域内の現在検査中のフレームに関連する第２メソッドが指定メソッドであるか判断するステップと、第２メソッドが指定メソッドでない場合には、第２メソッドが第１メソッドであるか判断するステップと、第２メソッドが第１メソッドである場合、ループの繰り返し数をカウントするためのコードによるカウント値を用いて、第２メソッドに関連するフレームの記憶領域における深さを検出するステップとを実行する。これにより、テイル・リカージョンによるメソッド・インライニングが実施されても、何等の影響を受けなくなる。カウンタ値により補正を実施することにより、インライニングを実施しない場合のスタック情報を再現できる。
【００１６】
また、第２メソッドが指定メソッドであって、当該指定メソッドに関連するフレームを検査するまでに第１メソッドに関連するフレームを検査していた場合には、第１メソッドのカウント値により補正された、記憶領域の最初のフレームから第２メソッドに関連するフレームまでの深さを返すステップをさらに実行する。前段落よりさらにスタックを深くトレースした場合の処理である。
【００１７】
さらに、第２メソッドが第１メソッドでない場合、深さを１加算し、第２メソッドを次のフレームに関連するメソッドに変更するステップをさらに実行する場合がある。スタックのトレースは、指定メソッドが検出されるまで又は全てのスタックのフレームをトレースし終えるまで実行される。
【００１８】
なお、第１メソッドがループ化に必要なコードを含んでいることを表すフラグを含んでいる場合には、第２メソッドが第１メソッドであるか判断する時に、当該フラグの有無を検査すればよい。
【００１９】
本発明の第２の態様は、呼び出された後の処理が不確定な第１メソッドの呼び出しを含む第２メソッドに第１メソッドのコードをインライニングするステップと、第１メソッドのコードをインライニングする前の状態における、第１メソッドと第２メソッドの呼び出し関係を取得して、後に使用可能な記憶域に格納するステップと、インライニングされた第１メソッドのコードを実行する際に、第１メソッドを実行中であることを記憶するためのコードを生成するステップとを含む。よって、SecurityManagerの動作時には、メソッド・インライニング前のメソッド間の呼び出し関係及びどのメソッドのコードを実行しているか判断できるようになり、メソッド・インライニングによる実行最適化の適用範囲を増大させることができる。
【００２０】
第１メソッドと区別するために、インライニング前から第２メソッドに含まれるコードを実行する際に、第２メソッドを実行中であることを記憶するためのコードを生成するステップをさらに含むようにすることもできる。さらに、第１メソッドと第２メソッドの呼び出し関係は、第１メソッドに関する項目に第２メソッドに関する項目を指すポインタを含むようにすることも考えられる。
【００２１】
一方、複数のメソッドを含むプログラムであって、呼び出された後の処理が不確定な第１メソッドの呼び出しを含む第２メソッドに、メソッド・インライニングによる第１メソッドのコードと、インライニングされた第１メソッドのコードを実行する際に、第１メソッドを実行中であることを記憶するためのコードとを含み、第１メソッドのコードをインライニングする前の状態における、第１メソッドと第２メソッドの呼び出し関係を含む、上記プログラムの実行時に、実行した各メソッドに関する情報を対応フレームとして格納した記憶領域において、所定の条件を満たす指定メソッドに関連するフレームを検出するために、SecurityManagerは、記憶領域内の現在検査中のフレームに関連する第３メソッドが第２メソッドであるか判断するステップと、第３メソッドが第２メソッドである場合には、第２メソッドに関連する呼び出し関係を取得するステップと、呼び出し関係中の第３メソッドの対応項目を取得するステップと、呼び出し関係中の第３メソッドの対応項目を用いて、第３メソッドの呼び出し元メソッドを取得するステップと、呼び出し元メソッドが指定メソッドであるか判断するステップとを実行する。これにより、メソッド・インライニングが実施されても、メソッド・インライニングを実施しない場合のスタック情報を再現できるようなったので、メソッド・インライニングの影響を除去できた。
【００２２】
また、呼び出し元メソッドが指定メソッドでなかった場合には、呼び出し関係中の呼び出し元メソッドの対応項目から、さらなる呼び出し元メソッドを取得するステップを実行する場合もある。スタックのトレースは、第１の態様と同じで、指定メソッドが検出されるまで又は全てのスタックのフレームをトレースし終えるまで実行される。
【００２３】
なお、本発明の第１の態様及び第２の態様は、共に、ＪＩＴコンパイラがＪａｖａのバイトコードに対して実施することを念頭にしているが、ＪＩＴコンパイラ内の中間コード等に対して実施することも可能である。また、他の言語であれば、通常のコンパイラで、プログラマの書いたプログラムに対して実施することも考えられる。
【００２４】
以上本発明の処理のフローを説明したが、本発明はこれらの処理を実施する装置や、コンピュータにこれらの処理を実施させるプログラムの形態によっても実現可能である。このプログラムを、フロッピー・ディスクやＣＤ−ＲＯＭ等の記憶媒体又は他の形態の記憶装置に格納することは、当業者が普通に行う事項である。
【００２５】
【発明の実施の形態】
本発明の装置構成を図１を用いて説明する。サーバ・コンピュータ１及びクライアント・コンピュータ５はネットワーク３を介して接続されている。クライアント・コンピュータ５は、ＪａｖａＶＭ（Virtual Machine）５２及びＯＳ（Operating System）５３及びハードウエア（ＣＰＵ及びメモリを含む）５５を含む。さらに、ＪａｖａＶＭ５２は、Ｊａｖａインタープリタ５４又はＪａｖａ  ＪＩＴコンパイラ５６、及びセキュリティ・マネージャ（SecurityManager）６０を含む。インタープリタ５４及びＪＩＴコンパイラ５６の両者を有している場合もある。なお、クライアント・コンピュータ５は、通常のコンピュータの他、メモリの大きさが小さかったり、ハードディスク等の補助記憶装置を含まないような、いわゆるネットワーク・コンピュータや情報家電の場合もある。
【００２６】
サーバ・コンピュータ１では、Ｊａｖａソースコード１０は、Ｊａｖａコンパイラ１２によりコンパイルされる。このコンパイルの結果が、バイトコード１４である。このバイトコード１４は、ネットワーク３を介してクライアント・コンピュータ５に送信される。バイトコード１４は、クライアント・コンピュータ５内のＷＷＷブラウザ（World Wide Web Browser）などに設けられたＪａｖａ仮想マシン（Java VM）５２にとってネイティブ・コードであり、実際ハードウエア５５のＣＰＵにて実行する場合には、Ｊａｖａインタープリタ５４や、ＪａｖａＪＩＴコンパイラ５６を用いる。インタープリタ５４は、実行時にバイトコード１４をデコードし、命令ごとに用意される処理ルーチンを呼び出して実行する。一方、ＪＩＴコンパイラ５６は、バイトコードを事前にあるいは実行する直前にコンパイラを用いてマシン・コード５８に変換してそれをＣＰＵで実行する。
【００２７】
本発明は、図１におけるＪＩＴコンパイラ５６の処理に関する。以下、例を用いて処理のフローを説明する。
（１）実施例１（Tail Recursionによるループ化を実施する場合）
表１にサンプル・プログラムを示す。但し、実際にはバイトコードに関して処理は実行されるが、バイトコードでは分かりにくいので、以下のような擬似コードにて表す。
【表１】
10: class test {
20:    public final int f( int x )
30:    {
40:           if ( x==0) {
50:                 return  0;
60:           } else
70:                 h(x);
80:                 return f(x-1);
90:           }
100:    }
110:    public void h( int x )
120:    {
130:       ......
140:    }
150: }
なお、行番号は説明のためだけに付けてある。
【００２８】
表１のサンプル・コードは、final属性を有するメソッドｆ（第２０行乃至第１００行）と、メソッドｆから呼び出され（第７０行）、final属性が付されていないメソッドｈ（第１１０行乃至第１４０行）が示されている。メソッドｆにおいては、さらに自己再帰することが示されている（第８０行）。
【００２９】
これを従来手法に従って、テイル・リカージョンのループ化を実施すると、以下のようになる。
【表２】
0003813019.tif 000002
第２３０行と第２８０行にテイル・リカージョンのループ化に必要なコードが生成された。
【００３０】
表１を実行した場合には、図２のようなフレームがスタック上に生成される。すなわち、ステップ１ではメソッドｆについてのフレームが１つ生成され、ステップ２ではメソッドｈのフレームが１つ生成される。ポインタは前のメソッドｆを指す。さらに、ステップ３では、メソッドｈの実行が終了して再帰的にメソッドｆを呼ぶので、メソッドｈのフレームは消えて、メソッドｆのフレームがもう一つできる。ポインタは前のメソッドｆのフレームを指す。再帰的に呼ばれたメソッドｆはその中でメソッドｈを呼ぶので、ステップ４ではメソッドｈのフレームが生成され、そのポインタはその前のメソッドｆのフレームを指す。メソッドｈの実行が終わると、メソッドｈのフレームは消えて、メソッドｆを再度再帰的に呼ぶ。これによりステップ５におけるメソッドｆのフレームが生成される。ポインタは自身を呼び出したメソッドｆのフレームを指す。さらに、再帰的に呼び出したメソッドｆはその中でメソッドｈを呼び出すので、このメソッドｈのフレームが生成される。ポインタは呼び出したメソッドｆを指す。このように、表１を実行した場合には、メソッドｆのフレームが次々に生成されていく形となる。
【００３１】
一方、表２を実行した場合には、図３のようなフレームがスタック上に生成される。すなわち、ステップ１ではメソッドｆについてのフレームが１つ生成され、ステップ２ではメソッドｈのフレームが１つ生成される。ポインタは前のメソッドｆを指す。さらに、ステップ３では、メソッドｈの実行が終了して、メソッドｈのフレームが消去される。この時、もう新たにメソッドｆは呼び出されないので、新たなフレームは生成されない。ステップ４では、新たな繰り返しでメソッドｈが呼び出されるので、メソッドｈのフレームが再度生成される。そして、メソッドｈの実行が終了すれば、そのフレームは消去される（ステップ５）。また、新たな繰り返しでメソッドｈが呼び出されれば、メソッドｈのフレームが生成される（ステップ６）。
【００３２】
このように、図２と図３とを比較するとステップ３以降スタック情報は異なるので、もし、メソッドｈにおいてSecurityManagerクラスの例えばcurrentDepthメソッドが呼び出された場合には、ステップ３以降であれば、返されるスタックの深さの値は当然異なる。
【００３３】
実施例１では、この差異を埋めるために、ＪＩＴコンパイラにおいては以下の処理を実施する（図４）。まず、以下の説明のため、用語を定義しておく。
ｃｂ（class block）：Ｊａｖａのクラス情報を表す構造体へのポインタ。クラスに属する全てのメソッド情報（下記）を参照することができる。
ｍｂ（method block）：Ｊａｖａのメソッド情報を表す構造体へのポインタ（methodblock）。メソッドの属するクラスのｃｂへのポインタを有する。
mb-<CompiledCode：コンパイルされたコードの先頭アドレスを設定する領域
mb-<CompiledCodeInfo：メソッドに対するフラグを設定する領域
【００３４】
まず、表２に示したように、テイル・リカージョンのループ化に必要なコードを生成する（ステップ１０２０）。そして、本処理が実施されていることを表すために、mb-<CompiledCodeInfoにフラグを立てる（ステップ１０３０）。そして、ループの繰り返し回数をカウントするために、ローカル変数（ここでは変数１とする）領域を１つ増やす（ステップ１０４０）。ローカル変数領域はスタック上に確保されるので、自動的にスタック上に作業領域を一つ確保したことになる。さらに、ループの戻り点より前に変数１を−１で初期化するためのコードと、戻り点より後に変数１を１インクメントするコードを生成する（ステップ１０５０）。ここでフレームとはプログラム実行時に各メソッドの実行毎にその実行コンテキストに対応して生成される作業領域である。スタックは通常計算機の実行環境で作業領域を提供する手法の一つである。コンパイルされたコードの実行では、通常フレームはスタック上に割り当てられる。バイトコードで表現すると、以下のようになる。
【表３】
プログラムの開始点:
iconst_m1
istore >変数１<
ループの戻り点:
iinc >変数１< 1
iconst_m1で−１をスタックに積んで、istoreで−１を変数１に格納したことを表す。iincは変数１を１インクメントすることを表す。
【００３５】
発明を分かりやすくするために、表２からどのように変換されるかを表４に示す。
【表４】
0003813019.tif 000003
第４３０行及び第４５０行にステップ１０５０（図４）で生成されたコードに対応するものが表されていることが分かる。
【００３６】
図４の処理がなされ、必要なコンパイル処理が実施されると、マシン・コード５８が生成されるので、このマシン・コード５８をＣＰＵにて実行する。マシン・コード５８実行時には、オリジナル（表１）のプログラムでメソッドｈが呼び出された時のメソッドｆの再帰呼び出しされた回数（スタックの深さ）が変数１によりカウントされる。
【００３７】
次に、SecurityManagerのスタック・トレース時の動作を説明する。最初に、表１のコードのままである場合の、SecurityManagerの処理フローを表５に示す。
【表５】
0003813019.tif 000004
まず、フレームからメソッド情報を取り出し、メソッド・ブロックからクラスが取得する。もし、このクラスが目的のクラス（指定されたクラス）である場合には、SecurityManagerの処理を実施する。一方、目的のクラスでない場合には、深さ（depth）値をインクメントして次のフレームについて処理を繰り返す。
【００３８】
では、本発明のSecurityManagerでは、以下のような処理を実施することにより、深さ値を補正する。
【表６】
0003813019.tif 000005
表５と異なるのは、ｃｂが目的のクラスでなければ、mb-<CompiledCodeInfoにフラグが設定されているか、すなわち本発明が実施されているかどうかを判断し、もしフラグが設定されている場合には、Tail Recursionにより増加しなくなったスタックの深さの値を補正する（depth += 変数１）部分である。このようにカウントしていた値（変数１）を用いて通常のトレースでカウントされた深さ値を補正することにより、図２と図３の差を埋めることができる。
【００３９】
（２）実施例２（テイル・リカージョン以外のvirtualメソッド・インライニングの場合の処理）
表７にサンプル・プログラムを表す。擬似コードである点は変わらない。
【表７】
600: class test{
610:    public void f ( int x )
620:    {
630:           for ( int i=0; i>x; i++ ){
640:                     g(i);
650:                     h(i);
660:           }
670:    }
680:    public final void g ( int x )
690:    {
700:           h( x*x );
710:           h( x+x );
720:    }
730:    public void h ( int x )
740:    {
750:     ........
760:     }
770: }
行番号は以下の説明のためだけに付されている。
【００４０】
表７のサンプル・プログラムでは、メソッドｇはfinal属性が付されているのでこれ以上オーバーライドされないため、メソッドｇに対する呼び出しの際には必ずメソッドｇが実行される。一方、メソッドｈはfinal属性が付されていないvirtualメソッドであるため、実際に実行されるメソッドをコンパイル時には特定できない。よって、従来ではこのようなプログラムに対してメソッド・インライニングを実施できなかった。
【００４１】
表８に、メソッド・インライニングを実施した後のプログラムを示す。
【表８】
800: class test{
810:    public void f ( int x )
820:    {
830:           for ( int i=0; i>x; i++ ){
840:                     h( i*i );
850:                     h( i+i );
860:                     h(i);
870:           }
880:    }
890:    public void h ( int x )
900:    {
910:     ........
920:     }
930: }
第８４０行及び第８５０行がメソッド・インライニングにより埋め込まれたコードである。
【００４２】
では、この表７を実行した場合のスタックのフレーム状況を図５に示す。第６１０行が実行されると（ステップ１）、メソッドｆのフレームが生成される。第６４０号が実行されると（ステップ２）、メソッドｇのフレームが生成される。メソッドｇは、メソッドｈを呼ぶので、メソッドｈのフレームが生成される（ステップ３）。第７００行の分のメソッドｈが実行されると、一度メソッドｈのフレームは消滅するが、第７１０行の分のメソッドｈが実行されるので、再度メソッドｈのフレームが生成される（ステップ４）。第７１０行分のメソッドｈが実行されると、メソッドｇの実行が終了するので、メソッドｇのフレームは消滅する。その後メソッドｆにおいてメソッドｈが呼び出されるので、メソッドｈのフレームが生成される（ステップ５）。
【００４３】
一方、表８を実行した場合のスタックのフレーム状況を図６に示す。最初のステップ１は同じであるが、表７ではメソッドｇは存在しないので、いきなりメソッドｈが呼ばれる（第８４０行）。そして、メソッドｈのフレームが生成される（ステップ２）。以降、第８５０行のメソッドｈの実行、第８６０行のメソッドｈの実行に合わせて、ステップ３及びステップ４の状態になる。
【００４４】
図５及び図６を参照すれば、メソッドｇに関するフレームが生成されないことが分かる。メソッドｇを実行している中で呼ばれたメソッドｈでSecurityManagerが呼ばれるかもしれない。この場合、インライニングする前と同じ結果を返さない。
【００４５】
そこで図７のような処理をＪＩＴコンパイラは実行する。最初に、本発明の処理を実行していることを示すために、mb-<CompiledCodeInfoにフラグを設定する（ステップ１１２０）。次に、インライニング処理を実行する（ステップ１１３０）。この際、末端まで呼び出し関係が見切れていないメソッド呼び出しを検出する。このメソッド呼び出しは、各メソッド呼び出しに対してインライニング処理を再帰的に行うことで検出可能である。すなわち、メソッド呼び出しを含まない末端のメソッドまで到達できたかどうかで判断できる。例えば、表８のプログラムでは、virtualメソッドとしてメソッドｈが３つ存在していることが分かる。
【００４６】
そして、このステップ１１３０により検出されたメソッド呼び出しに関する呼び出し関係情報を作成し、格納する（ステップ１１４０）。この呼び出し関係情報は、例えば図８のようなものである。識別番号は、メソッド・インライニングのベースとなるメソッド及びインラインされた各メソッドに対し一意に設定する。ここでは、インラインを行うベースとなるメソッドを根とし、インラインされたメソッドをノードとし、それらの間のメソッドの呼び出し関係をリンクとする木構造において、根から順に深さ優先探索（depth first search）を行って、後順（postorder）で０から１ずつインクリメントしながら値を設定する。そして、各行は、それぞれを呼び出したメソッドのメソッド・ブロックｍｂと、本呼び出し関係情報における、呼び出し元メソッドを表す要素へのポインタを保持している。そして、最終的には、インラインを行うベースとなるメソッド・ブロックｍｂと、ｎｕｌｌが格納される。表８の例では、呼び出し関係を見切れないvirtualメソッドとして、メソッドｈの呼び出しが３つ存在している（第８４０行乃至第８６０行）。第８４０行及び第８５０行の呼び出しは、メソッドｇからの呼び出しがインライニングされたもので、第８６０行の呼び出しはメソッドｆ自身からの呼び出しである。よって、インライニングを行うベースとなるメソッドはメソッドｆであり、インライニングされたメソッドはメソッドｇである。これを後順にすると、メソッドｇが識別番号０で、メソッドｆが識別番号１となる。以上から、表８の呼び出し関係情報は、以下のようになる。
０：｛メソッドｇのｍｂ，配列要素１のアドレス｝
１：｛メソッドｆのｍｂ，ｎｕｌｌ｝
【００４７】
なお、この配列の先頭アドレスを、コンパイルされたコードの直前に格納する。メソッド・ブロックｍｂからこの配列へのアクセスは、例えば*(((long *)(mb-<CompiledCode))-1)というアドレスに設定する等により取得できる。以下 、このように設定されているものとして説明する。
【００４８】
そして、メソッド呼び出しを行ったメソッドの識別番号を格納するため、ローカル変数（変数２）領域を１増やす（ステップ１１５０）。また、ステップ１１２０において検出されたメソッド呼び出しの直前に、当該メソッドの呼び出し元の識別番号を変数２に設定するコードを生成する（ステップ１１６０）。表８の例では、第８４０行及第８５０行のメソッドｈの呼び出しは、メソッドｇによる呼び出し（メソッドｇのコード）であるから、このメソッドｈの呼び出し前に変数２にメソッドｇの識別番号０を格納するコードを生成する。また、第８６０行のメソッドｈの呼び出しは、メソッドｆが呼び出し元（メソッドｆのコード）であるから、メソッドｆの識別番号１を変数２に格納するコードを生成する。バイトコードで表現すると、以下のとおりになる。
【表９】
iconst >識別番号<
istore >変数２<
これを表８の例では２か所に生成する。すなわち、第８３０行の後及び第８５０行の後である。
【００４９】
コンパイル後の状態を分かりやすいように表８の変形として表現すると、以下のとおりになる。
【表１０】
1300: class test{
1310:    public void f ( int x )
1320:    {
1330:           for ( int i=0; i>x; i++ ){
1340:                     >変数２< = 0;
1350:                     h( i*i );
1360:                     h( i+i );
1370:                     >変数２< = 1;
1380:                     h(i);
1390:           }
1400:    }
1410:    public void h ( int x )
1420:    {
1430:     ........
1440:     }
1450: }
第１３４０行及び第１３７０行に呼び出し関係をトレースするための情報を格納する変数２についてのコードが生成される。
【００５０】
図７の処理がなされ、必要なコンパイル処理が実施されると、マシン・コード５８が生成されるので、このマシン・コード５８をＣＰＵにて実行する。マシン・コード５８実行時には、変数２にどのメソッドによる呼び出し（どのメソッドのコードを実行中）であるかの情報（識別番号）が格納される。すなわち、変数２が０を格納している場合には、メソッドｇによる呼び出し（元々メソッドｇのコードを実行中）であり、変数２に１が格納されている場合には、メソッドｆによる呼び出し（元々メソッドｆのコードを実行中）である。
【００５１】
次にSecurityManagerの処理を説明する。従来のSecurityManagerは、表５に表したとおりに処理を実施する。一方、以下に本発明におけるSecurityManagerの処理を表す。
【表１１】
1500: int depth = 0;
1510: for (スタック中のフレームを順にトレースする)
1520: {
1530:   mb = フレームからメソッド情報を取り出す。
1540:   cb = mb-<fb.class  //メソッド・ブロックからクラスを取得する
1550:   if (mb-<CompiledCodeInfoにフラグが設定されているか)
1560:   {
1570:   void * 呼び出し関係情報配列 = *(((long *)(mb-<CompiledCode))-1)
1580:   void * 要素アドレス = 呼び出し関係情報配列[変数２]
1590:   for ( ;要素アドレス!=NULL; 要素アドレス=要素アドレス[1] ) {
1600:       mb = 要素アドレス[0];
1610:       cb = mb-<fb.class;
1620:       if ( cb が目的のクラスか )
1630:       {
1640:            >cbに対するSecurityManagerの処理<
1650:            return depth;
1660:       }
1670:       depth ++;
1680:    }
1690:   }
1700:   else
1710:  {
1720:     if ( cbが目的のクラスか )
1730:     {
1740:            >cbに対するSecurityManagerの処理<
1750:            return depth;
1760:     }
1770:  }
【００５２】
第１５３０行では、検査しているフレームからメソッド情報を取り出し、第１５４０行でそのメソッド情報からそのメソッドのクラス情報を取り出す。第１５５０行から第１６９０行までは、本発明において異なる処理をする部分である。第１５５０行では、先に述べたように本発明が実施されているかどうかをフラグにて判断する。そして、１５７０行では、当該メソッドの格納領域の直前に呼び出し関係情報の配列が格納されているので、そのアドレスにアクセスする。第１５８０行では、呼び出し関係情報の配列において変数２に格納された識別番号の所の要素アドレスを取得する。第１５９０行では、配列要素アドレスがＮＵＬＬになるまで、第１６８０行までを繰り返すことを表しており、繰り返すごとに、配列の右側（図８の例）に格納された、呼び出し元メソッドを表す配列要素のアドレスを配列要素アドレスとする。第１６００行では、取得した配列要素アドレスの、図８の例では左側の列に記憶されたメソッド・ブロックｍｂを取得し、第１６１０行でそのｍｂからそのメソッドのクラスを取得する。そして第１６２０行でそのクラスが目的のクラスかどうか検査する。もし目的のクラスであれば、第１６４０行で、SecurityManagerの処理を実施する。一方、そうでない場合には深さ値を１インクリメントして第１５９０行に戻る。図５及び図６において示したように、スタックの深さも異なるためである。
【００５３】
以上述べた部分が従来と異なる部分であって、本発明が実施されていない場合には、従来と同じ処理を実施するようになっている（第１７１０行乃至第１７７０行）。
【００５４】
以上本発明の実施例を２つ別々に述べたが、これらは２つ同時に実行することができる。例えば、表１２のようなプログラムは、表１３のようなプログラムになる。
【００５５】
【表１２】
0003813019.tif 000006
【表１３】
0003813019.tif 000007
【００５６】
また、本願発明は、ＪａｖａＶＭ５２内のＪＩＴコンパイラ５６とSecutityManager６０に関するものであるが、ＪａｖａＶＭ５２全体又はその一部、特に本願発明に関連する部分をハードウエア、特に半導体チップにて実装することも考えられる。
【００５７】
【効果】
Ｊａｖａのようなセキュリティ機能を有する言語においてメソッド・インライニングによる実行最適化の適用範囲を増大させることができた。
【００５８】
メソッド・インライニングがＪａｖａのＪＩＴ（Just In Time）コンパイラにおいても可能になった。
【００５９】
また、メソッド・インライニングを実施する際に、メソッド・インライニングを実施しない場合のスタック情報を再現できるようにすることもできた。
【００６０】
Ｊａｖａのような言語において、呼び出された後の処理が不確定なメソッドの呼び出し及び自己再帰を含むメソッドに対し、テイル・リカージョン（Tail Recursion）によるループ化が可能になった。
【００６１】
さらに、当該ループ化において繰り返し数を把握できるようになった。
【００６２】
メソッド・インライニングを実施した場合に、メソッド・インライニング前のメソッド間の呼び出し関係を保存できるようにすることもできた。
【００６３】
メソッド・インライニングを実施した場合に、どのメソッドのコードを実行しているか判断できるようになった。
【図面の簡単な説明】
【図１】本願発明の装置構成を表す図である。
【図２】従来（表１）におけるスタックの状態を表す図である。
【図３】実施例１におけるスタックの状態を表す図である。
【図４】実施例１におけるＪＩＴコンパイラの処理フローを表す図である。
【図５】従来（表７）におけるスタックの状態を表す図である。
【図６】実施例２におおけるスタックの状態を表す図である。
【図７】実施例２におけるＪＩＴコンパイラの処理フローを表す図である。
【図８】呼び出し関係情報の配列を表す図である。
【符号の説明】
１  サーバ・コンピュータ
３  ネットワーク
５  クライアント・コンピュータ
５２  ＪａｖａＶＭ
５４  Ｊａｖａインタプリタ
５６  Ｊａｖａ  ＪＩＴコンパイラ
５８  マシンコード
６０  セキュリティ・マネージャ
５３  ＯＳ
５５  ハードウエア（ＣＰＵ及びメモリを含む）
【図１】
0003813019.tif 000008
【図２】
0003813019.tif 000009
【図３】
0003813019.tif 000010
【図４】
0003813019.tif 000011
【図５】
0003813019.tif 000012
【図６】
0003813019.tif 000013
【図７】
0003813019.tif 000014
【図８】
0003813019.tif 000015