(57)【特許請求の範囲】
【請求項１】
プログラムコード内の命令に応答してプロセスを実行するデータ処理システムであって、該データ処理システムは、
命令ポインターに応答してプログラムコード内の命令をフェッチし一連の命令を与える命令フェッチ論理であって、前記命令はジャンプアドレスを有する第１のジャンプ命令と、対応する呼出ポイントに関連したスタックの部分の文脈情報と共に、ジャンプアドレスを有する第２のジャンプ命令を更に備える命令フェッチ論理と、
命令フェッチ論理に接続され、第１および第２のジャンプ命令を検出し、シーケンス内の現在の命令を復号する命令復号論理と、
命令復号論理に接続され、復号された命令を実行する実行資源と、
命令フェッチ論理および命令復号論理に接続され、命令ポインターを更新する論理であって、前記命令復号論理によって第２のジャンプ命令が検出された場合、第２のジャンプ命令の長さと第２のジャンプ命令の文脈情報の長さを命令ポインターに加えて命令ポインターを更新する論理と、および、
前記第２のジャンプ命令の文脈情報をもちいて、呼び出された関数により発生させられた例外を管理し、スタックをアンワインドする例外マネジャー、
を含むシステム。
【請求項２】
請求項１に記載のシステムにおいて、前記第２のジャンプ命令は可変長の文脈情報を含み、かつ前記命令ポインターを更新する論理は前記文脈情報と同じ長さを持つデータ領域をジャンプするシステム。
【請求項３】
データ処理システムのプログラムコードにおける命令処理方法であって、該処理方法は、
命令をアドレス可能なメモリのプログラムコード内に格納するステップであって、命令は、ジャンプアドレスを有する第１のジャンプ命令と、対応する呼出ポイントに関連したスタックの部分の文脈情報と共に、ジャンプアドレスを有する第２のジャンプ命令を備え、
アドレス可能なメモリ内のアドレスを識別する命令ポインターに応答してメモリから一連の命令をフェッチするステップと、
第１および第２のジャンプ命令の検出を含む、シーケンス内の現在の命令を復号するステップと、
現在の命令の長さを命令ポインターに加え、もし前記現在の命令が第２のジャンプ命令であると前記現在の命令を復号するステップが検出したならば、更に前記第２のジャンプ命令の文脈情報の長さを前記命令ポインターに加えるステップと、
例外条件が満たされたら例外マネジャーを呼び出すステップと、
例外マネジャーの呼び出しに応答して、命令ポインターの値を引数として使用した関数により決定されるアドレス可能なメモリ内のアドレスにおける文脈情報を読み出し、スタックをアンワインドするステップと、
を含む方法。
【請求項４】
請求項３に記載の方法において、第２のジャンプ命令の文脈情報は、対応する第２のジャンプ命令に関連した文脈データを格納するためメモリ位置のポインターを有する、方法。
【請求項５】
請求項３に記載の方法において、前記第２のジャンプ命令の文脈情報は、複数のバイトのフォーマットを特定するフィールドを含む複数のデータバイトを有する、方法。
【発明の詳細な説明】
【０００１】
【発明の属する技術分野】
本発明は一般的にソフトウェアプログラムの信頼性を高めその挙動を改善するシステムおよび方法に関する。特に、本発明はデジタルコンピュータ上で作動するプログラムが例外条件および実行時プログラムエラーから回復できることを保証するタスクにおいてソフトウェア開発者を支援する例外処理システムおよび方法に関する。
【０００２】
【従来の技術】
デジタルコンピュータは所望のタスクを遂行する前に、適切な命令セットを受信しなければならない。コンピュータのマイクロプロセッサにより実行され、集約的に“コンピュータプログラム”と呼ばれるこれらの命令はコンピュータの操作を指令する。
【０００３】
コンピュータは本質的に“機械符号”、すなわちコンピュータのマイクロプロセッサにより特定命令として解釈される特定のタスクを実施する低水準命令、しか理解できない。機械語すなわち機械符号はコンピュータが実際に理解できる唯一の言語であるため、他のプログラミング言語は全て人間がコンピュータに特定のタスクを実施させられるようにする“人間”言語の構成方法を表すものである。
【０００４】
人間は機械符号で有意プログラムを構成することができるが、実際上今日のソフトウェア開発は全て１つ以上の利用可能なプログラミング言語を利用している。最も広く使用されているプログラミング言語は、Ｃ＋＋／Ｃもしくはパスカル等の、“高水準”言語である。
【０００５】
“コンパイラ”と呼ばれるプログラムがこれらの命令を必要な機械語へ変換する。この変換の文脈において、高水準言語で書かれるプログラムは“原始コード”もしくは原始（ソース）プログラムと呼ばれる。コンパイラの最終出力は“目的モジュール”であり、それは目的プロセッサが実行する命令を含んでいる。目的モジュールはコンピュータの操作を命令する符号を含んではいるが、目的モジュール自体はコンピュータにより直接実行できる形式ではない。それは最終実行可能プログラムが生成される前に“リンキング”操作を経なければならない。
【０００６】
リンキングは１つ以上のコンパイルされた目的モジュールを結合すなわちリンキングして実行可能プログラムを作り出すための一般的プロセスと考えることができる。通常、このタスクは“リンカー”と呼ばれるプログラムの任務である。典型的な操作では、リンカーはユーザもしくは一体化されたコンパイラからリンク操作に含めたい目的モジュールのリストを受け取る。リンカーは指定されたオブジェクトおよびライブラリファイルからの目的モジュールを走査する。必要に応じて相互接続参照を導出した後で、リンカーはプログラムのモジュールからの目的コードをオペレーティングシステムプログラムローダにより理解されるフォーマットで構成することにより実行可能なイメージを構成する。リンキングの最終結果は実行可能な符号（典型的には．．ｅｘｅ  ファイル）であり、それはテストおよび品質保証の後で適切なインストレーションおよび使用命令を有するユーザへ通されるか、あるいは埋込コンピュータシステムを有する製品内にインストールするために工場へ通される。
【０００７】
プログラムの開発はおおむね試行錯誤プロセスである。プログラム開発サイクルから生じるエラーは、コンパイル時間エラー、リンケージエラー、実行時エラー、およびプログラマコントロールを越える予期せぬ故障により実行時に生じるエラーを含む広いクラスへ分割することができる。このような予期せぬ故障の例としてネットワークを介して共有される外部資源の故障、およびネットワークの故障が含まれる。適切な開発方法および品質保証によりコンパイルエラー（シンタクスおよびフォーマット違反等）およびリンケージエラー（ライブラリおよびグローバルネーミング矛盾等）の両方が除去されるが、実行時エラーは系統だった解消がしにくい。事実、実行時エラーの最重要性は通常それをユーザが発見しユーザに重大なフラストレーションを与えるという事実から生じる。適切に処理されなければ、実行時エラーにより簡単に実行が中断（終止）され、システムは問題ある状態とされユーザは何が悪く次に何をすべきか判らない。実行時エラー問題を追跡できない多くの理由がある。第１に、プログラム実行中に全てのユーザアクションを予測するのは困難である。良心的なプログラマーであれば役立つメニューおよびプロンプトによりユーザを案内し、各ユーザ応答の有効性を調べるコードの挿入に努めるが、実際上は、任意のユーザ入力を予測して応答するのは重大なプログラミングへの挑戦となる。
【０００８】
第２に、プログラム実行の展開につれて必要となるさまざまなハードエゥアおよびソフトウェア資源の利用可能性を予測することは困難であり、しばしば不可能である。例えば、実行中のプログラムはその実行のさまざまなポイントにおいて、それがないとプログラムを有用に続けられない、ＲＡＭ（ランダムアクセスメモリ）およびディスク記憶装置割当を要求することがある。同様に、実行中のプログラムはオペレーティングシステム、ライブラリ、もしくはさまざまな理由によりプログラマーコントロールを越えていてその時点では利用できない他のルーチンを呼び出すことがある。一般的なエラーは、例えば、プログラムがネットワークエラーにより利用不能なファイルへのアクセスを求める場合に生じる。ハードエゥア資源の例外により、プログラムは回避的アクションをとるかあるいは単に終止（エグジットもしくはアボート）しなければならない。この種の例外は同じプログラム内の１組の独立したユーザアプリケーションもしくは１組の独立した実行スレッド（ｔｈｒｅａｄ）が同じ資源を共有しなければならない最新の計算環境では特によく起こることである。
【０００９】
資源のアベイラビリティおよび予期せぬユーザアクションの他に、もう１つの実行時エラー源としてコンパイレーションやリンケージ中に検出不能な本来のコーディングバグが含まれる。例えば、コンパイラーにより正当なものとして受け入れられた数式からその変数成分のある値に対する実行時エラーを生じることがある。典型的なケースは“÷０”エラーおよび式を正しく評価できない類似の状況である。このようなエラーは予測可能であり理論上は回避できる。しかしながら、実際上は従来の例外処理には各式を評価する前に変数値の条件付テストの過剰なハードコード化が伴い、それに無効な評価をバイパスするアドホックルーチンが続く。この方法はいかにも長たらしくエラーを生じやすい。
【００１０】
現在プログラム開発に使用されている大概の高水準言語は、一般的に必要なオペレーションセットを別々な名称のサブルーチン、手順、もしくは関数（ファンクション）内に密閉することができるモジュール性の概念を使用している。符号化されると、このようなサブルーチンはそれらをメインプログラム内の任意のポイントから“呼び出す”ことにより簡約することができる。さらに、サブルーチンがサブルーチンを呼び出すことができ、大概の場合実行中のプログラムはめったに命令の線形シーケンスではない。例えば、Ｃ言語では一連の関数を呼び出すｍａｉｎ（）プログラムが書き込まれ、各関数が関数を呼び出すことができる。全てがうまく行けば、コントロールは最後にｍａｉｎ（）へ戻る。関数呼出しのこの入れ子構造によりプログラムの構造が単純化されるが、同時に例外処理が複雑化する。関数呼出しの本質は任意の引数（すなわち、パラメータ）を目的関数へ通し、関数の実行可能なコードを保持しているメモリ部へコントロールを転送し、呼出しの結果を返し、同時に原始関数呼出しが行われたポイントのすぐ後で後続する実行が再開されることを保証するのに十分な情報を格納しなければならないことである。従来技術で既知のこの関数呼出し機構は、通常呼出しの前、間、および後でデータおよびメモリアドレスのオン及びオフでスタックに対してプッシュ及びプルして達成される。スタックは通常ＬＩＦＯ（後入れ、先出し）データ構造として構成されるメモリの単なる専用部である。スタックは通常プログラマーにより直接操作されず、プログラマーにより符号化される関数呼出しの結果としてその内容が変えられる。プログラムはしばしばヒープと呼ばれるメモリの他の部分に直接アクセスを有し、例外処理のキー要素にはこの不可欠資源の管理が含まれる。
【００１１】
関数呼出しが成功した後でスタックはアンワインド（ｕｎｗｉｎｄ）される、すなわち、スタック上に“押し込まれた”全データが逆の順序で“ポップ”オフされ、スタックはさらなる関数呼出しに対する準備が完了している呼出前状態とされ、呼出しを行った関数で実行が再開される。関数呼出しは任意レベルで入れ子構造とすることができるため、スタックはプログラムの適切な実行に絶対必要な復帰値および命令ポインターの不可欠で複雑なシーケンスを維持しなければならない。最後に、何の問題もなければコントロールはｍａｉｎ（）へ戻り、ｍａｉｎ（）の最後の関数呼出しに成功した後でプログラムは終止する。このアンワインディングプロセスに何らかの割り込みがあれば、不平衡なスタックとなって予測不能な結果を生じる。例えば、呼び出された関数はスタックの頂部において関数のスタックフレームと呼ばれる特定部分内でその引数を見つけることを予期するが、スタックが不平衡であれば関数は誤ったデータを引き抜いて実行時エラーがさらに混合される。
【００１２】
明らかに、入れ子構造関数内で生じる例外条件およびエラーにより特に困難な問題が生じる。この問題に対処するためにいくつかの例外処理方法が試みられている。例えば、１つの方法は独立変数もしくは正規の復帰値に対する特別な範囲の値として各関数にエラー表示を返させることである。次に、例外条件の即時負担が呼出関数にかかってくる。呼出関数は対処できなければ、その呼出関数へエラー表示を返さなければならず、例外を処理できる関数に達するかもしくはｍａｉｎ（）に達するまで連鎖をさかのぼる。ｍａｉｎ（）は問題を修正できなければ、恐らく多分ユーザに対する説明メッセージをディスプレイして、できるだけ優雅に終止する。
【００１３】
例として、ｍａｉｎ（）がｆｕｎｃＡ（）を呼び出し、次にそれがｆｕｎｃＢ（）を呼び出すものとする。ｆｕｎｃＢ（）は、例えば、成功に対するゼロもしくは失敗理由を示す正の数を返すようにプログラムされる。例えば、ｆｕｎｃＢ（）は“不十分メモリ”に対して１、“ファイル見つからず”に対して２、等を返す。ｆｕｎｃＡ（）は常にｆｕｎｃＢ（）から返される値をテストする。このテストが成功を示す場合には、ｆｕｎｃＡ（）はコントロールを続行し最後にｍａｉｎ（）へ返す。ｆｕｎｃＢ（）が“不十分メモリ”であることを検出すると、ｆｕｎｃＡ（）は状況を修正し（“ごみ集め”もしくはヒープのデフラグメント化により）次にｆｕｎｃＢ（）を再度呼び出すことができる。しかし、“ファイル見つからず”エラーを検出すると、ｆｕｎｃＡ（）はウォーニングを表示する以外にこの状況に対処する手段がない。継続不能であるため、ｆｕｎｃＡ（）はｍａｉｎ（）へエラー値を返さなければならない。もちろん、ｍａｉｎ（）がこのエラー処置に何ができるかは特定のアプリケーションによって決まる。
【００１４】
この“エラー連鎖”方式の利点はスタックが常に正しくアンワインドされることであるが、いくつかの重大な欠点がある。チェーン内の各関数はその被呼関数内に生じる予測を“捜す”コードを課せられる。このコードはどの予測を処理することができどの予測を呼出関数へ返さなければならないかも“判断”しなければならない。関数呼出しが深い入れ子構造とされており、異なる予測タイプ数が増加すると、予測のテストおよび連鎖はエラーを生じやすいプログラミング上の主要な悩みの種となる。良く方式化され、読み易く、保守可能な符号に対する著しい障害は前記した簡単な例から明白である。ｆｕｎｃＡ（）から返される例外を処理するようにされると、ｍａｉｎ（）は例外のタイプおよびどこで例外が生じるかの両方を知る必要がある。例外のタイプはエラーコードから明白であるが、それがｆｕｎｃＡ（）ではなくｆｕｎｃＢ（）内で生じたという事実や、問題が変化して拡張される場合には、チェーン内の他の関数の中にはエラーコーディングを付加しないと即座には明白にならないものが出てくる。
【００１５】
この問題に対する１つの返答は任意の関数の任意のポイントから、識別子ラベルにより与えられるアドレスにおける、メモリ内の任意の場所に常駐するルーチンへコントロールを転送することができるグローバル（すなわち、長い）ｇｏ  ｔｏ  ｌａｂｅ命令である。この方式の元では、先行する例のｆｕｎｃＢ（）は関数チェーンへエラーコードを返す必要はないが、エラーを検出したら適切な例外ハンドラーへ直接コントロールを送ることができる。
【００１６】
例えば、ｎｏ−ｍｅｍ−ハンドラーにおける例外ハンドラーは“不十分メモリ”エラーをすべて処理し、必要ならば、ｓｅｒｒの値を使用してどの関数内でエラーが生じたを確認するものと推定される。本技術では、ｆｕｎｃＢ（）が“不十分メモリ”例外を“スロー（ｔｈｒｏｗ）”し、ｎｏ−ｍｅｍ−ハンドラーにおけるルーチンが例外を“キャッチ（ｃａｔｃｈ）”する。
【００１７】
この簡単なグローバルｇｏ  ｔｏ方法には各例外ハンドラーに対して単一の読出可能場所を提供する利点があるが、実際上は他の問題が生じる。第１に、ＣおよびＣ＋＋言語における標準ｇｏ  ｔｏ命令は関数内でしか作動せず、関数間でコントロールを転送するために必要な長距離パワーを欠く。第２に、前記したように、ハンドラーへの直接転送はスタックを正しくアンワインドすることができない。最後に、最初の２つの難点に関連して、スロー関数にコントロールを返すことができる付加機構が必要である。ハンドラーがエラーを“修正”できるこれらの場合にスロー関数の実行を再開するために、例外処理機構はスロー関数の状態や文脈の保存および回復をできなければならない。
【００１８】
例えば、ｆｕｎｃＢ（）が例外をスローする場合、その局所変数は特定値を保持している。名称からお判りのように、局所変数の範囲および存在は関数の“寿命”に制限され、関数がコントロールを手放すと消滅する。これらの局所値および中央プロセッサのレジスタ内の現在値等の他のパラメータはｆｕｎｃＢ（）の状態を構成する。特に、この状態にはスタック状態および実行を再開すべきメモリ内の場所をマークする現在のＩＰ（命令ポインター）が含まれる。この状態はハンドラーが呼び出される前に完全に保存し、次にｆｕｎｃＢ（）の実行を安全に再開できる前に完全に回復しなければならない。
【００１９】
グローバルｇｏ  ｔｏ“解決策”のいくつかの欠陥は２つの標準Ｃライブラリ関数、ｓｅｔｊｍｐ（）およびｌｏｎｇｊｍｐ（）の導入により緩和されている。整合するｌｏｎｇｊｍｐ（）が別の関数内に呼び出される場合には、ｓｅｔｊｍｐ（）はコントロールを再開すべきポイントにおいて任意の関数内に呼び出すことができる。典型的に、ｌｏｎｇｊｍｐ（）は例外がスローされる場合に呼び出される。ｓｅｔｊｍｐ（）は引数として現在関数の状態が保存されるプログラマー供給メモリバッファへの（ポインター）のアドレスをとる。前記したように、この状態はｓｅｔｊｍｐ（）呼出しの直後に実行を再開するのに必要な、現在命令ポインターＩＰ（プログラムカウンタＰＣとも呼ばれる）を含む、プロセッサレジスタを保持する。ｇｏ  ｔｏとは異なり、ｌｏｎｇｊｍｐ（）は異なる関数間で次のようにコントロールを転送することができる。ｌｏｎｇｊｍｐ（）はその引数の１つとして整合するｓｅｔｊｍｐ（）内で使用される同じバッファーアドレスをとる。呼び出されると、ｌｏｎｇｊｍｐ（）はｓｅｔｊｍｐ（）により保存される状態を回復し、格納されたＩＰ内で見つかるアドレス、すなわちｓｅｔｊｍｐ（）呼出しに続く命令、へコントロールを転送する。さらに、ｌｏｎｇｊｍｐ（）はｓｅｔｊｍｐ（）を呼び出した関数内でテストすることができる第２のニューメリック引数をとり、特定のどのｌｏｎｇｊｍｐ（）が飛び越しを生じたかを確認する機構を提供する。
【００２０】
ｆｕｎｃＡ（）、ｆｕｎｃＢ（）、もしくはそれらが呼び出す任意の関数、もしくはこれらの関数が呼び出す任意の関数（以下、同様）において、ステートメント“ｌｏｎｇｊｍｐ（ａＪｍｐＢｕｆ，状態）；”はｉｎ  ｒｅｔｖａｌの値状態を返すために特殊状況においてｆｕｎｃＡ（）内のｓｅｔｊｍｐ（）が“呼び出され”、続いてｆｕｎｃＡ（）内のｉｆ（ｒｅｔｖａｌ）ラインへコントロールが復帰されることを保証する。後続関数内に任意のｌｏｎｇｊｍｐ（）呼出しがない場合には、ｓｅｔｊｍｐ（）はゼロ（偽）へ戻りｉｆ（ｒｅｔｖａｌ）テストは失敗する。したがって、ｓｅｔｊｍｐ（）およびｌｏｎｇｊｍｐ（）対により例外処理用グローバルｇｏ  ｔｏ方法が提供される。例外ハンドラーは任意の簡便な関数セット内へ密閉することができ、適切な処理の後で、所望によりコントロールは例外が生じた関数へ安全に転送し戻すことができる。
【００２１】
しかしながら、ｓｅｔｊｍｐ（）／ｌｏｎｇｊｍｐ（）解決策には欠点もある。第１に、ｌｏｎｇｊｍｐ（）が戻る関数がまだアクティブであるという保証がない。前例では、ｆｎａ（）が既に戻っていて、整合するｌｏｎｇｊｍｐ（）に遭遇する前にスタック上のその場所を手放すことがある。この問題に対する唯一の解決策はｍａｉｎ（）プログラムへのｓｅｔｊｍｐ（）呼出しを制限することである。第２に、入れ子構造ｓｅｔｊｍｐ（）およびｌｏｎｇｊｍｐ（）内のスタックアンワインディング問題は慎重なエクスプリシットプログラミングを必要とすることである。最後に、多くのポピュラーなプログラミングオーバレイおよびバーチュアルメモリ技術が特殊なスタックを使用しており、関数の状態がｓｅｔｊｍｐ（）により完全には格納されない。つまり、今日の方法では例外処理問題に適切に取り組むことができない。
【００２２】
Ｃ＋＋等の言語では局所変数の状態はさらに複雑であり、局所変数やオブジェクトは消去関数（ｄｅｓｔｒｕｃｔｏｒ）として知られる特殊な関連関数を持たなければならず、それは消滅する前に呼び出されなければならない。
【００２３】
例えばＣ＋＋その他の高水準言語等のあるプログラミング言語は例外のプログラミングを容易にし、前記した方式を置換および拡張する特定の機構を有する。しかしながら、これらの機構の実施は複雑である。速度とスペース間のトレードオフ状況へ至る問題があり、それは従来技術でよく立証されている。
【００２４】
特定の問題は復帰アドレスの位置（ロケーション）を呼出関数へ最適にマップする方法、呼出関数のスタックをハンドラーのポイントへアンワインドするのに必要な情報、もしくは関数“ｔｅｒｍｉｎａｔｅ（）”を呼び出す判断ポイントに関連する。復帰アドレスへマップしなければならない情報はスタック−フレーム、すなわち回復レジスタ、をアンワインドしスタックポインターを回復するための必要データおよび一般的なスタックレイアウトに関する情報を保持するテーブルへのポインターを含み、かつこのフレーム内に許されキャッチされた例外の記述を含んでいる。あるいは、テーブル情報をコンパクト化してポインターの替わりに格納することができる。スタック−フレームの最適レイアウトはそれを呼び出す関数に非常に依存し、復帰アドレスおよびスタックポインターの値および／もしくは特別なインプリメンテーションに応用できるフレームポインターよりも多くの情報がなければ推定できない。例外ハンドラーのインプリメンテーションは、例外状況でしか使用されないため、例外がスローされない場合にはできるだけ少ないオーバヘッドを与えることが望ましい。
【００２５】
従来技術で支配的なインプリメンテーションはプログラムカウンタベーステーブルに関連している。しかしながら、復帰アドレスの現在値を使用してプログラムカウンタ範囲のテーブルを調べる時間はプログラムのサイズに関連する。典型的に使用される２進探索では、探索時間は対数的にプログラム内の呼出数に基づいている。もちろん、この探索技術は従来技術で既知のハッシュ関数等を使用して最適化することができる。しかしながら、ハッシュ関数解決策を使用している既知のインプリメンテーションはなく、恐らくそれは余分なリンカーステップが導入されて探索時間は多くの設計者にとって重要と考えられないためである。
【００２６】
別の実施例は復帰アドレスに近い例外を呼び出すコード内にアドレスされる位置に格納することにより情報を見つけだすための情報を提供することに基づいている。しかしながら、従来技術では従来の呼出技術を使用して呼出コード内の余分な情報をスキップするのにプログラムスペースやプロセッサオーバーヘッドが必要である。例えば、プログラムスペースを費やす未使用データやアドレスフィールドを有するｎｏ  ｏｐｅｒａｔｉｏｎ  ＮＯＰ等のデータフロー上に目に見える影響のない任意の命令、もしくは未使用データを移すｍｏｖｅ命令等により、スキップは復帰時に実施することができ、未使用フィールドもしくはデータはプログラムスペースおよびプロセッサオーバーヘッドを費やす例外ハンドラーに対する所望情報を保持する。Ｃｈａｓｅ，Ｉｍｐｌｅｍｅｎｔａｔｉｏｎ  ｏｆＥｘｃｅｐｔｉｏｎ  Ｈａｎｄｌｉｎｇ，Ｐａｒｔ１，Ｔｈｅ  ｊｏｕｒｎａｌ  ｏｆ  Ｃ  Ｌａｍｇｕａｇｅ  Ｔｒａｎｓｌａｔｉｏｎ（ＩＳＳＮ１０４２−５７２１），Ｖｏｌｕｍｅ５，Ｎｕｍｂｅｒ４，Ｊｕｎｅ１９９４（ｓｅｃｏｎｄ  ｐａｒｔ  ｉｎ  Ｖｏｌｕｍｅ６，Ｎｕｍｂｅｒ１，Ｓｅｐｔｅｍｂｅｒ１９９４）参照。
【００２７】
【発明が解決しようとする課題】
本発明に従って、符号内文脈（イン−コード  コンテキスト）データはプロセッサにより認識される特殊呼出命令（コール  インストラクション）に内蔵（インコーポレート）される。情報は関数（ファンクション）呼出時にスキップされスタックのアンワインディング時に読み出される。情報に実際にアクセスする正規の実行中は決して必要ではないため、命令フェッチング内に含まれるキャッシュ等のマシンからの外部実行時間従属性を除けば、正規の命令に較べて割増サイクルコスト無しで実行するようにこの特殊呼出命令をインプリメントすることができる。情報は例外処理中しかアクセスされない。
【００２８】
スキップされる情報量は好ましくは固定しており、特定スタックレイアウト用情報へのポインター、局所トライブロックに関する情報、およびクリーンアップ情報を含むのに十分な、もしくはポインターおよび圧縮した文脈データを保持するのに十分なデータを保持する。実際の文脈データは奇もしくは負となることのないアドレス等の取り決めを使用して圧縮し、符号内情報がスタックアンワインディングに必要な実際のデータを含むようにすることができる。したがって、スキップした情報は例外をスローさせる命令内のフィールドと見なすことができる。あるいは、スキップは命令の副作用と見なすことができる。
【００２９】
したがって、本発明により文脈データを有するサブルーチンへの飛び越しを表す新しいコマンドラベルＪＳＲＣを有する新しいマイクロプロセッサその他のデータ処理システムが提供される。新しいコマンドは従来のサブルーチンコマンドへの飛び越しの特徴を全て有し、文脈テーブル、実際の文脈データ、もしくはその組合せへのアドレスを含む長いワードが加えられている。文脈情報は例外がスローされる時に所与の関数コードのどの部分が実行されるかを追跡し続けるのに使用される。関数が実行されている時に任意のポイントで例外が生じると、スタックフレームを捨てる前にどのようなクリーンアップが必要であるか、また例外中にアクティブであるトライブロックが存在するかどうかをシステムは文脈テーブルにより確認することができる。所与の関数に対して、文脈テーブルが構成されそれはこれらのプロセスに使用される関数の有効なレイアウトを記述する。この文脈データはコンパイラにより作り出され、それは前記したように符号内文脈データを含む新しい命令によりトライブロック内に包まれる関数呼出しをコンパイルする。後述するように、この命令はそれを符号内文脈データを含まない標準ＪＳＲ命令と対比させれば理解することができる。
【００３０】
整合のための文脈レコードを探索する必要がないため、より迅速なアンワインディング中にスタックからポップされる各関数に対する文脈テーブルを捜し出せることを除けば、例外マネジャー内のスタックアンワインダーは従来技術と同じようにスタックをアンワインドする。ＪＳＲＣ命令の符号内文脈データは正しい文脈レコードへ直接行くのに使用される。
【００３１】
【課題を解決するための手段】
したがって、本発明は命令セット内の命令に応答してプロセスを実行するデータ処理システムとして特徴づけることができる。本システムは命令ポインターもしくはプログラムカウンタに応答して命令セット内の命令をフェッチし一連の命令を与える命令フェッチ論理を含んでいる。命令セットは正規の長さを有する文脈呼出命令（例えば、ＪＳＲＣ）を含み、文脈呼出命令に応答して例外マネジャーの実行に利用される明確な長さを有する符号内文脈データが続く。命令復号論理が命令フェッチ論理に接続されてシーケンス内の現在命令を復号して実行する。命令復号論理は文脈呼出命令を検出する論理を含んでいる。実行資源が命令復号論理に接続されていて復号された命令を実行する。論理が命令フェッチ論理に接続されていて命令復号論理による文脈呼出命令の検出に応答して命令ポインターを更新する。検出に応答して、命令ポインターは符号内文脈データを飛び越してシーケンス内の別の命令へ行き、符号内データが命令の正常な処理に影響を及ぼさないようにされる。
【００３２】
本発明のもう１つのアスペクトに従って、本システムは命令フェッチ論理に接続されたプログラム記憶装置が含まれ、その中の命令ポインターに応答してアクセス可能な位置に命令セット内の命令が格納される。符号内文脈データはゼロバイト以上のオフセット量だけ文脈呼出命令に続いて格納され、命令ポインターを更新する論理は明確な長さに等しい長さを有するオフセットでデータのフィールドを飛び越す。
【００３３】
前記したように、命令シーケンスはアンワインド情報により特徴づけられる１つ以上の関数、および１つ以上の関数をアンワインドして文脈呼出命令を処理するのに使用されるレイアウト情報を含んでいる。符号内文脈データは少なくともアンワインド情報のサブセット、および／もしくはレイアウト情報のサブセットを含んでいる。別のシステムでは、符号内文脈データは文脈呼出命令に使用する文脈に関する情報を格納するメモリ位置へのポインターを含んでいる。別の実施例では、符号内文脈データはデータの複数バイトを含み、かつ複数バイトに対するフォーマットを指定するフィールドを含んでいる。したがって、例えば、フィールドは複数バイトがイミディエイト文脈データを含むかどうか、また複数バイトが別のメモリ位置内の文脈データへのポインターを含むかどうかを示す。
【００３４】
本発明の別のアスペクトにしたがって、命令復号論理がさらに処理を行うことなくプログラムカウンタを自動的にアップグレードできるように、符号内文脈データの明確な長さが予め定められている。別の実施例では、符号内文脈データの明確な長さは命令復号時に決定することができる。
【００３５】
本発明はまたアドレス可能なメモリ内の命令セットからの命令を格納することを含む、データ処理システム内の命令を処理する方法としても特徴づけることができる。前記したように、命令セットは文脈呼出命令を含んでいる。本方法はアドレス可能なメモリ内のアドレスを識別する命令ポインターに応答してメモリから一連の命令をフェッチすることを含んでいる。次に、現在命令が文脈呼出命令の検出を含めて復号される。文脈呼出命令の検出に応答して、文脈呼出命令の正規の長さプラス文脈データの明確な長さで命令ポインターが更新され、さもなくば適切であれば任意のオペランドを含む現在命令の長さで命令ポインターが更新される。次に、文脈呼出命令が実行されて正規の呼出命令のように関数を呼び出す。呼び出される関数は通常正規の呼出命令からと同じ手段で復帰する。しかしながら、呼び出される関数が正規には復帰せずに例外がスローされ、スタックアンワインディングがこの呼出ポイントに達するまで処理されないようになる場合には、命令ポインターの関数に応答して決定されるアドレス可能なメモリ内のアドレスにおいて、スタックアンワインダーは符号内文脈データを読み出す。符号内文脈データは次に任意の局所例外ハンドラー、スタックレイアウトおよびクリーンナップ情報を見つけだすのに必要な情報を保持する。
【００３６】
したがって、本発明によりプログラムを実行するコンピュータシステムが提供される。本システムはマイクロプロセッサおよび関数引数および局所データを格納するスタックメモリを含むメモリを含んでいる。マイクロプロセッサで実行可能なマイクロプロセッサ内の命令セットが、命令セットにより定義される言語を使用してプログラムの表現を実行するのに必要なデータフローおよびコントロールフローを提供する。１つ以上の命令が文脈呼出命令からなっている。特殊関数呼出命令は関数呼出に対する認知した復帰アドレスに関して固定点における符号内文脈データを運ぶデータフィールド、もしくはその効果への特殊関数呼出命令内の他のアドレッシング副作用に関連している。データフィールドは関数引数のレイアウトに関する情報、１実施例における同期もしくは非同期例外情報の関数アンワインディングに必要な局所データおよび情報を保持するのに十分な大きさである。あるいは、データフィールドは関数引数のレイアウトに関する情報の位置を検索するのに必要な情報、関数のアンワインディングおよび同期もしくは非同期例外情報の処理に必要な局所データおよび情報を保持するのに十分な大きさである。データフィールドは指名された関数呼出命令の実行時間へ特定的に加えることのないようにマイクロプロセッサにより処理される。好ましい実施例は、あたかもここに完全に記載されているかのように本開示の一部としてここに組み入れられている、“Ｔｅｃｈｎｉｃａｌ  Ｐｕｂｌｉｃａｔｉｏｎｓ，ＡｘｉｓＣｏｍｍｕｎｉｃａｔｉｏｎｓ，Ｓｃｈｅｅｌｅｖａｇｅｎ１６，Ｓ−２２３７０Ｌｕｎｄ，ＳＷＥＤＥＮ”もしくは＜ｃｕｐ−ｔｐｕｂ＠ａｘｉｓ．ｃｏｍ＞から入手できる‘ＡＸＩＳ  ＥＴＲＡＫ：ＣＲＩＳ  ＰｒｏｇｒａｍｍｅｒｓＲｅｆｅｒｅｎｃｅ’１９９４年編集に記載されたＡＸＩＳ  Ｃｏｍｍｕｎｉｃａｔｉｏｎｓ  ＡＢのＣＲＩＳアーキテクチュア内のＪＳＲ命令のバリエーションである。
【００３７】
【発明の実施の形態】
Ａ．システムハードウェア
本発明は図１のシステム２０のようなコンピュータシステム上で実施することができ、それは中央プロセッサ２０、主記憶装置２４、および例えば入出力コントローラ、キーボード、ポインティングデバイス（例えば、マウス、トラックボール、ペンデバイス等）、ディスプレイデバイス、および大容量記憶装置（例えば、ハードディスク）を含む周辺装置２６を含んでいる。所望により、プリンティング装置等の付加入出力装置をシステム２０に設けることができる。図からお判りのように、システムのさまざまなコンポーネントがシステムバスもしくは同様のアーキテクチュアを介して通信を行う。
【００３８】
Ｂ．システムソフトウェア
以下の説明は本発明の現在好ましい実施例に焦点を合わせ、それはＭＳ−ＤＯＳ（登録商標）、マッキントッシュ（登録商標）、ＵＮＩＸ（登録商標）、ＮｅｘｔＳｔｅｐ（登録商標）、マイクロソフトウィンドウズ（登録商標）等を含む、コマンドラインもしくはＧＵＩベースの、多様なプラットフォームおよび環境に有利に応用することができる。したがって、下記の典型的な実施例は説明用であって制約的なものではない。
【００３９】
図１に示すように、コンピュータシステムの操作を制御するために実行可能プログラム３２が提供される。システムメモリ２４内およびディスクメモリ上に格納されるプログラムはカーネルすなわちオペレーティングシステム（ＯＳ）を含み典型的にはウィンドウズシェルもしくはインターフェイスである。ある埋込システムでは、ユーザインターフェイスは設けられない。アプリケーションプログラムやウィンドウズアプリケーションプログラム等の１つ以上のアプリケーションプログラムをシステムで実行するために“ロードする”ことができる（すなわち、記憶装置からメモリへ転送）。プログラム３２はシステムおよびアプリケーションプログラムを開発するための本発明の開発システム１５０も含んでいる。図からお判りのように、開発システム１５０はＯＳを介して直接インターフェイスするコンポーネントだけでなく、ウィンドウズシェルを介してシステムとインターフェイスするコンポーネントを含んでいる。
【００４０】
本例における開発システム１５０はカリフォルニア州、スコッツバレイのボーランドインターナショナル社から入手できるＢｏｒｌａｎｄ  Ｒｅｇｉｓｔｅｒｅｄ  ＴＭＣ＋＋（登録商標）を含んでいる。一方、アプリケーションソフトウェアはワードプロセッシング、データベース、スプレッドシート、テキストエディター、コントロールアプリケーション、ネットワークアプライアンスドライバソフトウェア、その他のユーザおよび埋込アプリケーションを含む多様なアプリケーションソフトウェアの中の任意の１つとすることができる。
【００４１】
ＣＰＵ２２はサポート論理１４９を含み、本発明に従って例外を処理する特殊ＪＳＲＣ命令をサポートするコンポーネントを含む開発システム１５０を含んで入る。
【００４２】
Ｄ．開発システム
図２に詳細に示すように、本発明の開発システム１５０はコンパイラー１５３、およびリンカー１８０を含んでいる。インターフェイスを介して、デベロッパーユーザはコンパイラー１５３にソースモジュール１６１を供給する。インターフェイスはコマンドライン駆動であってＩｎｔｅｇｒａｔｅｄ  Ｄｅｖｅｌｏｐｍｅｎｔ  Ｅｎｖｉｒｏｎｍｅｎｔ（ＩＤＥ）インターフェイスを含み、前者はコマンドラインパラメータを介してユーザコマンドを受け入れ、後者はそのメニューイング同値（メニュー用イクイバレント値）を提供する。ソースコードリスティング１６１からおよびヘッダーズ／インクルーズファイル１５１から、コンパイラー１５３は“コンパイルする”すなわちオブジェクトモジュール１６３を発生する。コンパイラー１５３はコード内の適切な位置において特殊ＪＳＲＣ命令を挿入し、関連する文脈データを計算する。文脈データのフォーマットに応じて、文脈データの符号内部分が方式化されＪＳＲＣ命令自体に続く所定長を有するフィールド内のオブジェクトモジュール内に配置される。文脈データの平衡（バランス）は実行されるプログラムに関連する他の文脈データ内に配置され、文脈データの平衡が含まれるテーブル内の位置への符号内文脈データ内にポインターが含まれる。別のシステムでは、所与の呼出しに対する文脈データを圧縮して符号内文脈データフィールド内に完全に含めることができる。次に、リンカー１８０はオブジェクトモジュール１６３をライブラリ１７１と“リンク”すなわち結合させて実行可能なプログラム１６５（図１のブロック３２に対応する）を発生し、それは目的プロセッサ（例えば、図１のプロセッサ２２）により実行することができる。標準ライブラリ１７１は、グラフィックス、Ｉ／Ｏルーチン、スタートアップコード、等の予めコンパイルされた標準ルーチンを含んでいる。本発明のＪＳＲＣ技術に従ってプログラム１６５内の実行時エラーを処理するためにデバッガー１８１が設けられている。ボーランドインターナショナル社から直接入手可能な、Ｂｏｒｌａｎｄ  Ｒｅｇｉｓｒｅｔｅｄ  ＴＭ  Ｃ＋＋により従来技術の代表的な開発システム１５０の一般的動作の説明を行う。
【００４３】
デバッガー１８１は実行時エラーおよび／もしくはプログラム１６５やライブラリ１７１内からスローされる例外をキャッチするために設けることができる。デバッガーはライブラリ１７１から来るかあるいはコンパイラー１５３により内部発生コード１６５として発行することができる例外処理モジュールのアクションに介入する。例外がスローされる時にコンパイラー１５３により発行されるコードから呼び出される、例外処理モジュール（例外マネジャー）はスタックのアンワインディング、ローカルオブジェクトのクリーンナップ、例外ハンドラーのロケーティングおよび実行を管理する。例外処理モジュールは実行可能コード１６５の一部である。例外処理モジュールは本発明のＪＳＲＣ技術に従った文脈データを使用する。
【００４４】
デバッガーモジュール１８１だけでなく実行可能プログラム１６５内の例外ハンドラーには例外のスローイングおよびキャッチングに応答して符号内文脈データへアクセスする資源が設けられている。後述するように、スローされた例外に対する符号内文脈データの位置はマイクロプロセッサのプログラムカウンタ内の値の関数により決定することができる。符号内文脈データがＪＳＲＣ命令の終りおよび常時ＪＳＲＣ命令内にあるオペランドからゼロバイトだけオフセットされ、かつ例えば４バイトの所定長を有する本実施例では、符号内文脈データの位置は単にプログラムカウンタマイナス４バイトである。プログラムカウンタの制御の説明については後述する。
【００４５】
従来技術における例外処理ロケーティング問題に関する詳細な背景については米国特許第５，６２８，０１６号、その他を参照されたい。
【００４６】
アセンブリコードおよび２進レベルにおける標準ＪＳＲＣ命令と比較した場合の、本発明の符号内文脈データ命令ＪＳＲＣを有するサブルーチンへの飛び越しのインプリメンテーションを図３に示す。
【００４７】
第１行３０１には、オペランドとしてラベル“Ａ ｆｕｎｃｔｉｏｎ”を伴うＪＳＲ命令のアセンブリコードが明示されている。オペランド“Ａ ｆｕｎｃｔｉｏｎ”は１６進の０ｘ１３５ｅｆ３８２の値で表される。第２行は、最下位バイト（８２）が最初に、実行可能ファイル内に記憶される２進値を示す。第３行は本発明に従ったＪＳＲＣ命令のレイアウトを示し、パラメータとして関数“Ａ ｆｕｎｃｔｉｏｎ”のアドレスを、かつ文脈テーブル“Ｔｈｉｓ ｃｏｎｔｅｘｔ ｔａｂｌｅ”のアドレスとして符号内文脈を伴っている。この命令に対する２進値を３０３行に示す。１６進のこの文脈テーブルのアドレスは９ｘ５５７７ａａｃｃで表される。
【００４８】
命令の別の実施例はＪＳＲおよびＪＳＲＣ命令内の引数としてパラメータではなくレジスタへの参照を伴っている。したがって、３０５行には引数としてレジスタアドレスＲ５を伴う標準ＪＳＲ命令が示されている。ＪＳＲ命令に対するこの実施例において、レジスタＲ５への参照は命令内の最下位バイトにより運ばれる。その２進表現を３０６行に示す。引数としてレジスタアドレスＲ５を伴う本発明に従ったＪＳＲＣ命令を３０７行に示す。２進表現を３０８行に示す。
【００４９】
本例において、ＪＳＲＣ命令の表現１６進表現は０ｘｂｄ３ｆでありＪＳＲＣ命令の表現１６進表現は０ｘ３ｄ３ｆである。
【００５０】
圧縮された文脈データを伴う実施例では、下記の例に従ってフィールドを決定することができる。ここで、７個の汎用レジスタｒ０からｒ６があるものとする。この呼出ポイントに必要な文脈情報はスタックレイアウト、トライブロック文脈、消去を必要とするローカルオブジェクト、および例外ハンドラーａｋａ．キャッチブロックを含むものとする。
【００５１】
一般的なケースでは消去関数（ｄｅｓｔｒｕｃｔｏｒｓ）を呼び出す必要のあるオブジェクトは無く、この呼出ポイントに対する“オープン”トライ−ブロックやキャッチ−ブロックも無く、圧縮されたフォーマットはこれらのリストが空であることを示唆するものとする。
【００５２】
また、この文脈のベースとしてスタックポインターが使用されるものとする。
これらの３１ビットがまさにスタックレイアウトを符号化しなければならず、好ましい実施例においてそれは、下記のものである。
・呼ぶ側（ｃａｌｌｅｒ）の復帰アドレスへのオフセット。
・どのレジスタが保存されるか。
・局所変数に割り当てられるスタック量。
【００５３】
正規のケースではスタックフレームは１６ｋバイトよりも大きくなく、呼ぶ側の復帰アドレスへのオフセットに対して１４ビットをとる。局所変数も１６ｋバイトまで、すなわちさらに１４ビット、をとることができる。保存されるレジスタ数はほとんどの場合７よりも少なく（ｒ０かに上へ連続してｒ６で止まる場合が多い）、それに対しては３ビットで済む。
ビット＃：  意味
０          文脈は圧縮形式＝１，テーブルへのポインター＝０。
０ビットが１であれば、
１．．１４    ＰＣ（復帰アドレス）を保存した呼ぶ側のオフセット。
１５．．２８  バイトでカウントした局所変数の量（スタックポインターに必要な調整）
２９．．３１  保存したレジスタ上の符号化情報：無し、ｒ０，ｒ０．．ｒ１，．．．，ｒ０．．ｒ６
【００５４】
第２のフィールドは第１および第３のフィールドから演繹することができ、そのためここでさらに情報を適合することができ、恐らくは前に想定した空リストからのものである。例えば、単純化されたテーブルへのコード内のこの位置からのオフセットとして恐らく１５ビットを使用することができる。
【００５５】
この圧縮フォーマットは大概の呼出文脈についてこの情報を有するいかなるテーブルも発行する必要がないことを意味し、たくさんのメモリを省くことができる。
【００５６】
したがって、特定のインスタンスについて符号内文脈データが適切でなければ、コンパイラーはコンパイルされるオブジェクトモジュール内の適切な位置にＪＳＲコードを挿入する。ＪＳＲＣ符号内文脈データが適切であるインスタンスについては、コンパイラーは例示する形式でＪＳＲＣ命令を挿入する。
【００５７】
命令の実行において、この技術を使用するプロセッサに関連するプログラムカウンタおよび命令フェッチ論理はＪＳＲＣ命令の検出に応答してプログラムカウンタ、もしくは正規の処理において読み出される必要のない符号内文脈データ周りの他の同等の命令ポインターを増分する。本発明に従ってＪＳＲＣ命令を実行するように構成されたマイクロプロセッサの構造、およびＪＳＲＣ命令の文脈内のプログラムカウンタを増分する論理を図４および図５に示す。図４は本発明に従って実現されるプロセッサすなわちＣＰＵの略図である。それは複数の関数ユニット４００を含んでいる。関数ユニット４００は算術および論理関数の実行ユニット、本発明のＪＳＲＣ命令を検出して復号する論理を含む命令復号論理、プログラムカウンタ更新論理（ＰＣ更新）、およびプログラムカウンタと他の命令の実行結果に応答してプロセッサが実行する一連の命令を発生するのに使用される命令フェッチ論理含んでいる。したがって、命令フェッチ論理は命令キャッシュ、分岐命令等の管理を行う。
【００５８】
関数ユニット４００はバスインターフェイスを介してライン４０１によりシステムバスに接続されている。ライン４０１は入力データを運び出力データを供給する１つ以上のバスを構成する。また、命令記憶装置からの命令およびデータと命令を検索するアドレスがバスインターフェイスを介して供給される。プロセッサ内に、一般的にレジスタファイルと呼ばれる典型的に複数のジェネラルレジスタが設けられている。典型的に、それはライン４０３，４０４を介して関数ユニットへオペランドを供給し、格納すべき結果をライン４０５を介して関数ユニットから受信する３ポートメモリユニットである。
【００５９】
図４では、プログラムカウンタ４０６はジェネラルレジスタファイル４０２から独立したレジスタとして図示されている。もちろん、さまざまな実施例においてそれはレジスタファイルの一部と見なすことができる。プログラムカウンタ４０６はライン４０７を介して関数ユニット内のプログラムカウンタ更新論理に接続されており、ライン４０８を介してプログラムカウンタ値を関数ユニットへ送り返し、それは命令フェッチ論理および他の関数ユニットにより使用される。
【００６０】
本発明に従って、プロセッサの関数ユニットはＪＳＲＣ命令を認識し、それに応答してプログラムカウンタの更新を制御するようにされている。
【００６１】
図４のシステムで使用するプログラムカウンタ更新論理の単純化したバージョンを図５に示す。図３について前記したように、ＪＳＲおよびＪＳＲＣ命令は、コード内のオペランドを運ぶ第１のフォーマットおよび命令の一部としてレジスタ識別子を運ぶ第２のフォーマットを含む、さまざまなアドレッシングモードに対して多様なフォーマットをとる。
【００６２】
図５に示すＰＣ更新論理は、本質的に、ライン５０１からのプログラムカウンタの値ＰＣをＪＳＲＣ命令が認識されていることを示す信号により制御される第１のセレクタ５０２の出力、および命令がそれよりも多くのスペースを占めるオペランドを運ぶかどうかを示す信号により制御される第２のセレクタ５０３の出力を加算する加算器からなっている。したがって、オペランドを運ばない命令の場合には、セレクタ５０３の出力は命令長、例えば２バイト、である。命令がオペランドを運びかつ復号論理がオペランドを読み出している場合には、セレクタ５０３の出力はオペランドの長さとなり、それは図３の例では４バイトである。命令がＪＳＲＣ命令であれば、セレクタ５０３の出力を符号内文脈データの長さと結合しなければならない。したがって、セレクタ５０２はＪＳＲＣ命令が認識されなければゼロバイトであり、ＪＳＲＣ命令が認識されれば所定の文脈長である。これらの３つの値は加算器５００により加算され、更新プログラムカウンタ値としてプログラムカウンタへ戻される。ＪＳＲＣ命令の場合のこの更新プログラムカウンタ値は例外マネジャーが符号内文脈データを見つけるのに利用される。
【００６３】
図５の実施例では、文脈長は特別なＪＳＲＣ命令に関連する所定値である。さまざまな実施例において、文脈データの長さはサブルーチン命令への飛び越しの特別なインプリメンテーションもしくはインスタンスの必要性に従って変えることができる。したがって、サブルーチン命令への飛び越しはさまざまな文脈長さに対して２つ以上のインスタンス内で行うことができる。この場合、プログラムカウンタ更新論理はＪＳＲＣの特別なインスタンスを認識して適切な文脈長さを加えなければならないことがある。あるいは、ＪＳＲＣ命令はプログラムカウンタに加えられる文脈長さに等しい値をパラメータとして運ぶことができる。この場合、文脈長さは別の状況ではプロセッサの関数ユニットにより供給される汎用レジスタから検索することができる。
【００６４】
本発明に従ってＪＳＲおよびＪＳＲＣ命令を実行するプロセスを説明するのに図６を利用する。第１行において、ＪＳＲ命令を説明する。プロセッサは命令を実行する時は、最初に命令を読み出し、命令を復号しプログラムカウンタをサイクル１からサイクルＮ１までの命令に続く位置へ更新する。サイクルＮ１からサイクルＮ２までこの命令を伴うオペランドがあれば読み出される。プログラムカウンタはオペランドの後の位置へ更新される。サイクルＮ２からサイクルＮ３までにおいて、プログラムカウンタはサブルーチンに対する復帰アドレスの位置に格納され、スタックポインター等の関連する任意のエンティティはＪＳＲ命令に対する標準実行プロセスに従って更新される。サイクルＮ３からサイクルＮ４までにおいて、呼出しの目的において次の命令が読み出され、サブルーチンが実行される。
【００６５】
ＪＳＲＣ命令に従って、サイクル１からサイクルＮ１までにおいて、命令が読み出されて復号される。プログラムカウンタは命令の後の位置へ更新される。サイクルＮ１からサイクルＮ２までにおいて、オペランドが読み出されプログラムカウンタはオペランドの位置プラス本実施例では固定サイズである符号内文脈データの長さの位置へ更新される。サイクルＮ２からサイクルＮ３までにおいて、プログラムカウンタは復帰アドレスの位置に格納され関連する任意のエンティティが更新される。サイクルＮ３からサイクルＮ４までにおいて、呼出しのアドレスにおいて次の命令が読み出されサブルーチンが実行される。
【００６６】
しかしながら、例外マネジャーはプログラムカウンタ値の関数を使用して符号内文脈データを読み出してデータを見つけ出す必要がある。特に、データの始めはプログラムカウンタの値プラス符号語の長さよりも小さいゼロのオフセットに等しい関数により決定される。このようにして、符号内文脈データは呼出関数と自動的に関連づけられる。また、符号内文脈データは正規の処理に干渉したり正規の実行に割増サイクルを要することがない。
【００６７】
したがって、好ましい実施例では、文脈もしくは文脈へのポインターは４よりも小さい復帰アドレスのオフセットに配置される。復帰アドレスが見つかると、例外マネジャーは探索テーブルや整合値を必要とせずに符号内文脈データを見つけ出す。
【００６８】
本実施例では、符号内文脈データ内の情報は４バイトすなわち３２ビットである。３２ビットは文脈もしくは文脈ポインター、もしくはその組合せである。好ましい実施例では、データに対する３２ビットの好ましい制限（ａｌｉｇｎｍｅｎｔ）がある。この仮定を使用して、３２ビットの残りがポインターであるかある情報が固定された圧縮文脈データであるかを最下位ビットにおいて符号化することができる。したがって、本発明のＪＳＲＣ符号化文脈データを利用できる例外マネジャーおよびスタックウォーカ関数に対する擬似符号は下記のようになる。
0004398538.tif 000002
0004398538.tif 000003
【００６９】
0004398538.tif 000004
【００７０】
［上記の擬似コードは下記の訳文であることが、念のために注意される。］
【００７１】
【表１】
0004398538.tif 000005
【００７２】
【表２】
0004398538.tif 000006
【００７３】
Ｃ＋＋言語に対する本発明の好ましい実施例におけるコンパイラーは例外テーブルを発生する責任がある。本発明に従って、コンパイラーは例外テーブルの一部もしくは例外テーブルへのポインターをＪＳＲＣ命令に関連する符号内文脈データとして提供するように修正される。
【００７４】
本発明のＪＳＲＣ命令がＣ＋＋言語に従って利用されるプログラムの擬似コードの例を下記に示す。
【００７５】
【表３】
0004398538.tif 000007
【００７６】
【表４】
0004398538.tif 000008
【００７７】
【表５】
0004398538.tif 000009
【００７８】
ＪＳＲＣ命令を使用する抽出コードの１例がある。ｃａｔｃｈａｌｌ（）関数が他のどこかから呼び出され、本例および図７の目的に対して呼出チェーンの頂部にある。
【００７９】
ＪＳＲＣ命令が利用されるプログラム内の最初のインスタンスは、例外文脈情報が利用される最初の呼出ポイント（ライン２４）である。この情報には、本例では、復帰アドレスをどのように見つけるかを含めて、ｆｏｏ １をどのように消去するか、“ｍｉｄｄｌｅｍａｎ（）”からスタックフレーム（レジスタ等）をどのように回復するかが含まれる。ライン２５については、その宣言内のノースロー“ｔｈｒｏｗ（）”属性からお判りのように、関数ｗｏｎｔ ｔｈｒｏｗはいかなる例外もスローしないため、文脈情報は不要である。次の呼出ポイント（ライン２６）において、文脈情報が格納される。このポイントにおいて、文脈情報はｆｏｏ ２をどのように消去するか、ｆｏｏ １をどのように消去するか、“ｍｉｄｄｌｅｍａｎ（）”からスタックフレームをどのようにアンワインドするかのために必要であり、復帰アドレスをどのように見つけるかを含んでいる。次の呼出ポイントはライン３３における標準関数“ｓｔｒｎｃｐｙ（）”へであるが、例外をスローすることがないため（コンパイラーもしくはここには含まれないそのヘッダーファイル内の宣言から知られている）、文脈情報は不要であり正規のＪＳＲ呼出命令が使用される。その後の呼出ポイントはライン３４における関数ｆ（）である。この呼出ポイントに対する文脈情報には、ｉｎｄｉｒｅｃｔに対してどのように復帰アドレスを見つけるかを含めて、“ｉｎｄｉｒｅｃｔ（）”からどのようにスタックフレームを回復するかが含まれている。次に、ライン４０における“ｍｉｄｄｌｅｍａｎ（）”呼出しに対して例外文脈情報が利用される。この情報はスローすべきクラス、スローしたオブジェクトをどこへコピーすべきかという状態およびハンドラーの位置、復帰アドレスをどのように見つけるかを含めて“ｄｏｉｔ（）”関数からどのようにスタックフレームを回復すべきかという状態をキャツチする。例外文脈情報が格納される次の呼出ポイントはｃａｔｃｈａｌｌ（）内のライン５２における“ｄｏｉｔ（）”である。このポイントにおいて、文脈情報は何でもキャツチすることを示し、ハンドラーの位置および、復帰アドレスをどのように見つけるかを含めて、スタックフレームをどのように回復するかの状態を識別する。本例では、ライン６３においてスローされる例外がある。このポイントにおいて、スローン（ｔｈｒｏｗｎ）オブジェクトが生成される。ハンドラー探索およびスタックアンワインディングが開始される。このコードは他の例外情報を含まないため、スタックがアンワインドされて関連する例外情報が調べられる。
【００８０】
前記したコード例に従ったスタックの成長を図７に示す。本例では、プロセスは“ｃａｔｃｈａｌｌ”関数への呼出しにより開始される。スタックはライン７００における呼出し側の復帰アドレスにより成長し、ライン７０１において“ｃａｔｃｈａｌｌ”が打ちのめすレジスタを保存する。“ｃａｔｃｈａｌｌ”ルーチンは“ｄｏｉｔ”関数を呼び出す。スタックはライン７０２において復帰アドレスを“ｃａｔｃｈａｌｌ”内へ格納することにより成長し、ライン７０３において“ｄｏｉｔ”により打ちのめされるレジスタを保存し、例外がスローされる時に記入されるライン７０４におけるオブジェクト“ｗｈａｔ  ｉｓ  ｔｈｒｏｗｎ”用の記憶領域を確保し、整合するトライブロックがここで見つけだされる。“ｄｏｉｔ”関数はｍｉｄｄｌｅｍａｎ関数を呼び出す。このポイントにおいてスタックは“ｄｏｉｔ”（ライン７０５）内への復帰アドレスにより成長し、ライン７０６において“ｍｉｄｄｌｅｍａｎ”が打ちのめすレジスタを保存し、ライン７０７および７０８内にオブジェクトｆｏｏ １およびｆｏｏ ２用の記憶領域を確保する。“ｍｉｄｄｌｅｍａｎ”関数は“ｉｎｄｉｒｅｃｔ”関数を呼び出す。それが生じると、スタックはライン７０９における“ｍｉｄｄｌｅｍａｎ”、ライン７１０において“ｉｎｄｉｒｅｃｔ”が打ちのめすレジスタ、およびライン７１１における局所アレイ“ｓ”用記憶領域内へ復帰アドレスを格納することにより成長する。関数“ｍａｙｂｅ ｔｈｒｏｗ”も呼び出される。このポイントにおいて、“ｉｎｄｉｒｅｃｔ”内への復帰アドレスはライン７１２において格納され、スローポイントにおいて既知の“ｍａｙｂｅ ｔｈｒｏｗ”が打ちのめすレジスタはライン７１３において格納される。ｍａｙｂｅ ｔｈｒｏｗにおいて、例外をスローする条件が満たされると、“Ｔｏ ｂｅ ｔｈｒｏｗｎ”タイプのオブジェクトがスローされる。スタックアンワインディングおよび例外ハンドラー探索は保存した復帰アドレスに関する文脈情報を使用する。スローイング関数のイミディエイト文脈、すなわち、保存したレジスタおよび呼出し側の復帰アドレスのオフセットはコンピレーション時に知られており、“スロー”において直接使用することができる。
【００８１】
このスタックは図８に示すような例外マネジャーを使用してアンワインドしなければならない。ブロック８００に示すプログラム開始において、パラメータＥｘｃｅｐｔｉｏｎｓＩｎＰｒｏｇｒｅｓｓはゼロであり例外スタックは空である。ＥｘｃｅｐｔｉｏｎｓＩｎＰｒｏｇｒｅｓｓを使用して、カウンタは未処理例外のトラッキングを簡単にする。プロセス内でキャッチされない任意の例外によりカウンタは非ゼロへ戻されるようになる。例外スタックデータ構造が入れ子型例外を処理するのに使用される。すなわち、スタックアンワインディングを行っている時に消去関数呼出中に例外がスローされることがあるが、消去関数呼出しの内側が留意される。例外スタックによりこのタイプの処理が可能とされる。
【００８２】
ブロック８０１に示すように例外がスローされると、一時的ＯｂｊｅｃｔＴｏＴｈｒｏｗが生成され例外スタック上へ押しつけられる。スローされたオブジェクト用記憶領域はインプリメンテーションに依存する。しかしながら、好ましくは新しいオブジェクトがそこから割り当てられるヒープとは独立した、ヒープを使用しなければならない。一時的オブジェクトの消去は、恐らくは常時偽であるが一時的オブジェクトを生成する時だけ真である状態変数（ＴｅｍｐＩｎＣｒｅａｔｉｏｎ）を加えて、例外から守らなければならない。次に、アルゴリズムが進行して関数文脈をスローもしくはリスローポイントの現在長位置に等しく設定する。累積文脈は回復するレジスタが無いに等しく設定され、進行変数内の例外は増分される（ブロック８０２）。次に、トライブロック文脈が関数文脈のトライブロック文脈に等しく設定される（ブロック８０３）。図７の例では、それは“スロー”が実行される関数の文脈である；ライン７１３周りの“ｍａｙｂｅ ｔｈｒｏｗ（）”。
【００８３】
トライブロック文脈のオブジェクトリスト内の各対に対して、ブロック８０４に示すように、このようなオブジェクトに対する消去関数が呼び出される（ブロック８０５）。これらのオペレーションが消去関数もしくはコピー構成子を呼び出す場合には、これらの呼出しはいかなる例外も通さないことを確かめなければならない。それは“ｔｒｙ｛〔ｃａｌｌ〕｝ｃａｔｃｈ（．．．）｛ｔｅｒｍｉｎａｔｅ（）；｝”ブロックの効果内に呼出しを包んで達成される。
【００８４】
消去関数が呼び出された後で、スローするオブジェクトに整合するハンドラーに対するトライブロック文脈がハンドラーリストで探索される（ブロック８０６）。ブロック８０７において、ハンドラーが見つかるかどうか判断される。フロー図から、関数例外宣言は表明されないように見える。しかしながら、関数の最外部となる暗黙のトライブロックを加えるコンパイラーによりインプリメントされるものと思われ、それが任意のバイオレーションをキャッチして、“ｕｎｅｘｐｅｃｔｅｄ（）”，“ｔｅｒｍｉｎａｔｅ（）”への呼出しもしくは“ｔｈｒｏｗ  ｓｔｄ：：ｂａｄ ｅｘｃｅｐｔｉｏｎ”の効果へ変換する。
【００８５】
ブロック８０７においてハンドラーが見つからない場合には、ブロック８０８においてトライブロック文脈が関数文脈の最外部であるかどうかがアルゴリズムにより確認される。最外部であれば、アルゴリズムはブロック８０９へ移行する。このポイントにおいて、関数文脈は累積文脈へ加えられる。このオペレーションは回復レジスタの効果を集めスタックポインターの調整を累積することである。それは即座に実施する必要はないが、効果は思い出してハンドラーへ飛び越す前に実施しなければならない。また、このポイントにおいて、関数文脈は現在の関数文脈の関数として外部関数文脈に等しく設定される。それは本発明を使用する位置である。文脈が符号語内で符号化されていても文脈情報を有するテーブルへのポインター内で符号化されていても、“外部関数文脈”は文脈呼出関数内の符号語を使用して見つけられる。“ＯｕｔｅｒＦｕｎｃｔｉｏｎＣｏｎｔｅｘｔ（）”関数は図７に示すプログラムカウンタｆ（ＰＣ）の関数と同じである。したがって、図７の矢符７２０はスタックのアンワインディングにおいて遭遇する最初の呼出ポイントに対するプログラムカウンタの関数として関数文脈を見つけだす（例えばＪＳＲＣ命令を使用して）技術を示す。
【００８６】
ブロック８００９の後で、アルゴリズムはブロック８０３へループしてプロセスを繰り返す。このようにして、プロセスは図７に示す矢符７２０から矢符７２１、矢符７２２、矢符７２３、矢符７２４、矢符７２５、矢符７２６、矢符７２７、矢符７２８の経路に従って、スローしたオブジェクトのタイプと一致する“キャッチ”を有するトライブロックが見つかるまでスタックをアンワインドする。
【００８７】
ブロック８００８において、トライブロック文脈が最外部関数文脈でなければ、トライブロック文脈は外部トライブロック（トライブロック文脈）に等しく設定され、アルゴリズムはブロック８０４へループバックして新しい文脈情報を走査する。このオペレーションは、リンクされたリストあるいはテーブルあるいは他のインプリメンテーションであっても、文脈情報内のオブジェクトリストおよびハンドルリストの単純な走査にすぎない（ブロック８１０）。
【００８８】
ブロック８０７においてハンドラーが見つかると、アルゴリズムはブロック８１１へ分岐する。ブロック８１１において、ハンドラー記述トリプル内に指定されたオブジェクトがコピーされる。ＥｘｃｅｐｔｉｏｎＩｎＰｒｏｇｒｅｓｓカウンタは１だけ減分され、スタックポインターおよび他のレジスタが累積文脈を使用して回復され、プログラムはハンドラーへ飛び越す。次に、ブロック８１２に示すように、ハンドラーがトライブロックをエグジットすると、例外スタックがポップされスローする現在のオブジェクトに対する消去関数が呼び出される。スローするオブジェクトの記憶領域がデアロケートされ、アルゴリズムは正規の実行へ戻る。ブロック８１１の後で例外がスローされると、プロセスは８１３においてリスローブロックへループバックする。リスローブロックの最初のステップは、ブロック８１４において例外スタックが空であるかどうかを確認することである。空であれば、プロセスはブロック８１５で終端する。例外スタックが空でなければ、例外オブジェクトは例外スタックの頂部に設定され（ブロック８１６）、プロセスはブロック８０２へループする。
【００８９】
本発明の好ましい実施例の前記説明は例示および説明の目的でなされたものである。それは完璧なものではなく、本発明を開示した厳密な形式に限定するものでもない。明らかに、当業者ならばさまざまな修正および変更が自明であろう。本発明の範囲は特許請求の範囲およびそれと同等のものにより明記されるものとする。
【００９０】
著作権通告
本発明文献の一部に著作権保護の対象となる材料が含まれている。著作権所有者は特許局の特許ファイルや記録に記載された特許文献や特許開示を誰でもファクシミリで複写することに異議はないが、それ以外はあらゆる著作権を保有するものとする。
【図面の簡単な説明】
【図１】本発明の文脈呼出命令を実行するプロセッサを含むコンピュータシステムの単純化したブロック図。
【図２】図１のコンピュータシステムもしくは本発明のＪＳＲＣ命令用資源を含むソフトウェアをコンパイルする他のコンピュータシステムにより実行される開発システム用ソフトウェアアーキテクチュアを示す図。
【図３】正規の呼出命令と比較した特定の実施例に関するＪＳＲＣ命令のレイアウトを示す図。
【図４】本発明のＪＳＲＣ命令を処理する資源を含む本発明に従ったマイクロプロセッサの単純化したブロック図。
【図５】本発明に従ったプログラムカウンタ更新論理の単純化したブロック図。
【図６】正規の呼出命令と比較した本発明に従ったマイクロプロセッサ内のＪＳＲＣ命令の処理を説明する図。
【図７】本発明の説明に使用するスタック成長および文脈データを示す図。
【図８】本発明に従った例外マネジャーの１実施例のフロー図。
【符号の説明】
２０  システム
２２  中央プロセッサ
２４  主記憶装置
２６  周辺装置
アワ  システムバス
３２  実行プログラム
１４９  論理
１５０  開発システム
１５１  ｈｅａｄｅｒｓ／ｉｎｃｌｕｄｅｓファイル
１５３  コンパイラー
１６１  ソースコードリスティング
１６３，１８３  オブジェクトモジュール
１６５  実行可能プログラム
１７１  標準ライブラリ
１８０  リンカー
１８１  デバッガー
４００  関数ユニット
４０１，４０３，４０４，４０５，４０７，４０８，５０１  ライン
４０２  ジェネラルレジスタ
４０６  プログラムカウンタ
５００  加算器
５０２，５０３  セレクタ
【図１】
0004398538.tif 000010
【図２】
0004398538.tif 000011
【図３】
0004398538.tif 000012
【図４】
0004398538.tif 000013
【図５】
0004398538.tif 000014
【図６】
0004398538.tif 000015
【図７】
0004398538.tif 000016
【図８】
0004398538.tif 000017