第18章finally節

18.1ミニチュアサブルーチン

以下のような内部方法で最後に句のバイトコードのパフォーマンス「マイクロサブルーチン。」各catch節の終わりにJava仮想マシンは、ブロックとそれに関連する「コール」サブルーチンfinally節をしようとします。finally節の後に(ここ終了し、finally節の最後の文は、正常に終了すると例外がスローされ含まれていない、またはその他のリターン、comimie、休憩、の実装を参照)、本実施形態に属し、サブミニfinally節チェンザ・「戻る」操作。プログラムは、ローカルマイクロサブルーチンへの最初の呼び出し、次の文で継続します。

JSRのJava仮想マシン命令は、マイクロ命令コードをサブルーチンにジャンプすることです。JSR命令は、オペランドの2バイトの長さを使用し、オペランドは、マイクロサブルーチンの先頭に符号オフセット、16ビットから命令JSRを指摘しました。さらに、命令は、同じ機能を実行するJSR、jsr_wであり、それは、より長いオペランド(4バイト長)をサポートしています。JSRまたはjsr_w命令にすると、Java仮想機会、それは占アドレス人々を返し、その後、ミニサブルーチンの先頭から継続されます。リターンアドレスは直ちにJSR jsr_wまたはバイトコードオペコードとオペランドアドレス(オフセットまたはローカルポインタ)です。RETURNADDRESSのアドレスを入力します。

マイクロサブルーチンが完了すると、呼び出しRET命令の後、機能RET命令は、サブルーチンからの操作リターンを実行します。RET命令は、オペランドは、リターンアドレス・インデックスのローカル変数に格納され、一つだけであるオペランド。表18-1は、finally節を処理するオペレーティングコードをまとめたもの。

ミニチュアサブルーチンメソッドを使用してJavaを混同しないでください。Javaメソッドとマイクロサブルーチンが異なる命令セットを使用します。例えば、Javaメソッド呼び出しinvokespecial INVOKEVIRTUALとJavaメソッドの戻り値を返すために使用することができる他の命令は、ireturn、他の命令をareturn。

JSRのJava命令は、メソッドを呼び出すことはありません。それは、同じオペレーティング・プロセスで別のコードにジャンプすることができます。同様に、RET命令は、Javaメソッドの戻りをしない、唯一のメソッドを呼び出すことができ、仮想マシンはJSRオペコードとオペランドの後に同じ位置にジャンプして戻ります。彼らは子供のようにルーチンの方法として、バイトストリームを示すので帳は、バイトコードが実行さfinally節は、「マイクロサブルーチン」と呼ばれています。

18.2非対称コールとリターン

あなたはリターンアドレスはまた、人々JSR命令スタックへの圧力となっているとして、RET命令は、スタックからリターンアドレスをポップする必要があり、と思うかもしれません。ない場合、RET命令そうすることではありません。各サブルーチンの開始時に、リターンアドレスがスタックの最上部からポップされ、ローカル変数に格納され、後、RET命令は、ローカル変数のリターンアドレスから削除されます。finally節(マイクロサブルーチン)自体が例外をスローするか、リターンが含まれている、休憩、継続して他の文になるので、非対称のリターンアドレスに取り組んでのこの方法が必要です。そのためこれらの可能性のため、この命令は、スタックJSR余分なリターンアドレスにプッシュされ、すぐにスタックから削除されなければならない、とするとき、最後にブレーク通じ句、引き続き、リターン、または例外出口を投げるので、この問題はもはやありません考えます。

たとえば、次のコードでは、最終的には、出口句を打破するためのステートメントが含まれています。このコードの実装の結果は()BVALが渡されたパラメータ、このメソッドはfalseを返しますsurpriseTheProgrammerにどのような方法に関係なく、それです。
オペコード/ EX3 / Surprise.javaのでオン//ファイルでCD-ROM
クラス{サプライズ

surpriseTheProgrammerブール静的(ブールBVAL){
(BVAL)一方{
{試みる
trueを返します。
}
最後に{
破ります。
}
}
falseを返します。
}
}

ローカル変数の戻りアドレスの理由うち、上記の例のポイントは、finally節の先頭に堆積されなければなりません。最後に、出口句でステートメントを壊すので、RET命令を実行しません。そのため、Java仮想マシンが返します真の文を実行しません。とき、それwhile文の最後に出口に完成し、実行break文、閉じ括弧でいます。次の文は、推論実行プロセスはまったく同じJava仮想マシンで、falseを返します。

かかわらず、リターンを壊し続ける、または例外をスローすることでfinally節を終了し、それは特性が同じである示しました。これらの例では、finally節の最後にRET命令が実行されないように。それが実行されることはありませんので、我々はそれがスタックからリターンアドレスを削除することを期待することはできません。そのため、仮想マシンは、finally節はローカル変数に開始リターンアドレスに格納されます。

以下に概説する方法は、tryブロックは、2つの出口点を有する、tryブロックを含む完全finally節、一例です。この例では、2つの出口点は、return文です。
オペコード/ EX1 / Nostalgia.javaでオン//ファイルでCD-ROM
クラスノスタルジア{

静的INT giveMeThatOldFashionedBoolean(ブールBVAL){
試み{
(BVAL){場合に
1を返します。
}
0を返します。
}
最後に{
するSystem.out.printlnは( "旧式になりました。")。
}
}
}
方法giveMeThatOldFashionedBoolean()被编译为如下的字节码:
// tryブロックのためのバイトコードシーケンス:
0 iload_0 //ローカル変数0(BVALパラメータ)を押し
1 // 11 ifeqポップ整数、等しい場合は0〜 、11へのジャンプ(ちょうど// if文過去):IF(BVAL){}
4 iconst_1で//プッシュINT 1
ローカルに// INT(1)ポップ、店舗
5 istore_1 //変数1
//ジャンプします以下のためのミニサブルーチン
6 JSR 24 // finally節
9 iload_1 //ローカル変数1(1)プッシュ
:スタック(1)の上に//戻りINT
; 10 ireturn //リターン1
11 iconst_0 //プッシュINT 0
// INT(0)をポップし、ローカルに格納
// istore_1 12変数1つ
のためのミニサブルーチンへジャンプ//
13 JSR 24 // finally節は
16 iload_l //ローカル変数1(0)を押し
0(スタックの一番上に戻る// INTを):

17 ireturn //リターン0;
// catch節のためのバイトコードシーケンスキャッチは、その
tryブロック内からスローされた例外の//あらゆる種類。
//スローされた例外への参照をポップ、
ローカル変数2に18 astore_2 //格納
するためのミニサブルーチンへジャンプ//
19 JSR 24 // finally節
//スローする(参照プッシュ
22 aload_2 //例外)ローカル変数2から
23 athrow //再スロー同じ例外

最終的には実装//ミニチュアサブルーチン
//ブロックを。
//ローカルに保存し、リターンアドレスをポップ
24 astore_3 //変数3
java.lang.System.outへの参照を取得します//

25 getstatic#7 <フィールドに、java.io.PrintStreamうち>
に// Puah参照"ガット昔ながらの。"
//文字列定数プールから
28 LDC#1 <文字列"昔ながらのガット。">
//呼び出しSystem.out.printIn()

30 INVOKEVIRTUAL#8
<方法ボイド印刷(java.lang.Stringで)>
ローカルに格納されたリターンアドレスへ戻る//
33 RET 3 //変数3

バイトコードのtryブロックはほかに、JSRは、catch節の指示があり、2つのJSR命令が含まれています。あなたはtryブロックで例外の実行中に投げた場合は、文の最後のブロックは、次に実行します。したがって、catch節は、バイトコードでコンパイラに追加されます。したがって、この句は唯一の句マイクロサブルーチン最後に記述し、その後、同様の例外をスロー呼び出さキャッチ。0〜17の間の全てのアドレス(含む)(すなわち、すべてのtryブロックのバイトコードを達成するために)スローされた例外は、開始アドレスからキャッチ18である:ことgiveMeThatOldFashionedBoolean下に記載されている例外テーブル()メソッド句の処理。
テーブル例外:
対象から入力するため
の任意の18 18 0は
finally節の開始、スタックリターンアドレスのポップ上部はローカル変数及び3に記憶されています。最後に、ローカル変数3のリターンアドレスから取得した句、ret命令の終わり。
HopAroundがjavacの()メソッドによって生成されたバイトコードであるとして次の
例外テーブル:
対象から入力する
2いずれかを4 10
2 31 31は任意です
hopAround()閉じ括弧にfinally節のリターンを行うことによって、第1のストリップの方法、それはfinally文を続けるリターンを行うことによって、句秒です。最初の句は最終的にそのret命令を通って外に出ます。finally節が第二の出口を継続するためと、それはそのRET命令を実行しません。文はwhileループの先頭にジャンプするには、Java仮想マシンを行い続けます。この方法でreturn文にもかかわらず、このreturn文の実装前に、それはその後締結し、二finally節が実行されます。このサイクルは、死のサイクルです。finally節で文を続けるこのメソッドが返すことはできません、return文を置き換えます。

第2のマイコンのサブルーチンでバイトコードにfinally節の実装をジャンプするreturn文を達成するために、なお、戻り値は、ローカル変数に格納されています。マイクロサブルーチンリターン(そこには常に文を続ける返す前に実行されるため、上記の場合には、それは、返すことはありません)した後、ローカル変数の戻り値1、およびリターンから削除。

このプロセスは、finally節が途中で終了する前に値を返すために、Java仮想マシンを強調しています。iの値は、リターンにfinally節を実行した後であるが、仮想マシンの実行には、iのfinally節値の前に戻りますが。そのため、finally節は、iの値を変更しても、この方法は、私が実行されないfinally節前の値を返します。あなたがメソッドの復帰に値を変更するには、最後に句を使用する必要がある場合は、戻り値の上にfinally節が更新されて返すように、finally節でreturn文を追加する必要があります。

 

おすすめ

転載: www.cnblogs.com/mongotea/p/11980086.html