したがって、ランタイムが例外処理をどのようにしているか知りたいですか?
ご了承ください。
だからです。 ObjCには例外処理ABIがありません。あなたがすでに見つけたSPIだけです。間違いなくObjective-C例外ABIが実際にC++ exception handling ABIと全く同じものであることも発見しました。そのために、いくつかのコードを始めましょう。
#include <Foundation/Foundation.h>
int main(int argc, char **argv) {
@try {
@throw [NSException exceptionWithName:@"ExceptionalCircumstances" reason:@"Drunk on power" userInfo:nil];
} @catch(...) {
NSLog(@"Catch");
} @finally {
NSLog(@"Finally");
}
}
-ObjC -O3
と打ち鳴らす介して実行(およびデバッグ情報の嫌な量を剥奪)私たちは、この取得:にObjC++ 何もを変更しないと、あなたがそれをコンパイルする場合
_main: ## @main
push rbp
mov rbp, rsp
push r14
push rbx
mov rdi, qword ptr [rip + L_OBJC_CLASSLIST_REFERENCES_$_]
mov rsi, qword ptr [rip + L_OBJC_SELECTOR_REFERENCES_]
lea rdx, qword ptr [rip + L__unnamed_cfstring_]
lea rcx, qword ptr [rip + L__unnamed_cfstring_2]
xor r8d, r8d
call qword ptr [rip + [email protected]]
mov rdi, rax
call _objc_exception_throw
LBB0_2:
mov rdi, rax
call _objc_begin_catch
lea rdi, qword ptr [rip + L__unnamed_cfstring_4]
xor eax, eax
call _NSLog
call _objc_end_catch
xor ebx, ebx
LBB0_8:
lea rdi, qword ptr [rip + L__unnamed_cfstring_6]
xor eax, eax
call _NSLog
test bl, bl
jne LBB0_10
LBB0_11:
xor eax, eax
pop rbx
pop r14
pop rbp
ret
LBB0_5:
mov rbx, rax
call _objc_end_catch
jmp LBB0_7
LBB0_6:
mov rbx, rax
LBB0_7:
mov rdi, rbx
call _objc_begin_catch
mov bl, 1
jmp LBB0_8
LBB0_12:
mov r14, rax
test bl, bl
je LBB0_14
jmp LBB0_13
LBB0_10:
call _objc_exception_rethrow
jmp LBB0_11
LBB0_16: ## %.thread
mov r14, rax
LBB0_13:
call _objc_end_catch
LBB0_14:
mov rdi, r14
call __Unwind_Resume
LBB0_15:
call _objc_terminate
を。 (まあ、それは完全に真実ではありません。最後の_objc_terminate
は、clangの個人的な___clang_call_terminate
ルーチンへのジャンプに変わります)。とにかく、このコードは3つの重要なセクションに分けられます。最初は_main
からLBB0_2
の開始点までです。またはtryブロックが発生します。例外的に例外がスローされ、try
ブロックにキャッチされているため、コンパイラはLBB0_2
周辺のブランチを削除し、キャッチハンドラにまっすぐ移動しました。この時点で、Objective-C、またはより正確にCoreFoundationは、私たちのために例外オブジェクトを設定しており、libC++は、必要な巻き戻し段階で例外ハンドラを検索し始めました。
コードの2番目に重要なブロックはLBB0_2
から私たちのcatch
とfinally
ブロックが住んLBB0_11
の終わりにあります。すべてがうまくなっているので、この下のコードはすべて死んでいます(そして、うまくいけばリリースで取り除かれます)が、それはそうではないと想像してみましょう。
3番目の部分は、コンパイラがNSLogからのジャンプをLBB0_2
に送り出したところのLBB0_8
です。私たちが例外を捕まえようとしなかったような何か愚かなことをしたら、このハンドラは、objc_begin_catch
を呼び出した後にちょっと反転して、ret
の周りを分岐し、ボールを落としたハンドラを知らせるobjc_exception_rethrow()
に移動し、ハンドラの検索を続けます。もちろん、私たちはメインなので、他のハンドラはありません。std::terminate
が呼び出されます。
これは、あなたが手でこのものを書き込もうとすると悪い時を過すと言います。 __cxa_*
とObjC SPI関数はすべて、頼りにいらない方法で例外オブジェクトを投げ込みます。very tight orderで放出されたハンドラは、C++ ABI契約が満たされているかどうかを確認するために使用されます。std::terminate
呼び出される。能動的なリスニングの役割を果たす場合は、自分自身の機能でredefine the exception handling stuffを許可し、Objective-Cはobjc_setUncaughtExceptionHandler
、objc_setExceptionMatcher
objc_setExceptionPreprocessor
を持ちます。
obj-C++を考慮すると、スタックを巻き戻したいと思いますか? – hamstergene
ユージン、私は私が従うかどうかはわかりません...私は、uncaughtExceptionのようなものの例を探しています。ここで私が理解できたのは、https://gist.github.com/1073294#file_uncaught_exceptionです。しかし、私は 'begin_try'や' end_try'のようなものを推測しています。 – TooTallNate
try/catchブロックのアセンブリは実際にobjc_begin_catchとobjc_end_catchの呼び出しを示します。あなたはそれを見て、どのように呼び出されているか見てみましたか? –