Vì vậy, bạn muốn biết thời gian chạy xử lý ngoại lệ như thế nào?
Chuẩn bị thất vọng.
Vì không. ObjC không có ABI xử lý ngoại lệ, chỉ có SPI mà bạn đã tìm thấy. Không nghi ngờ gì nữa, bạn cũng đã phát hiện ra rằng ABI Objective-C ngoại lệ thực sự là chính xác như là C++ exception handling ABI. Để kết thúc, hãy bắt đầu với một số mã.
#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");
}
}
Chạy qua kêu vang với -ObjC -O3
(và bị tước một lượng kinh tởm của thông tin debug), chúng tôi có được điều này:
_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
Nếu bạn biên dịch nó với ObjC++ có gì thay đổi. (Vâng, đó không phải là hoàn toàn đúng sự thật. _objc_terminate
cuối cùng biến thành một bước nhảy vào thói quen cá nhân ___clang_call_terminate
của clang). Nhưng dù sao, mã này có thể được chia thành 3 phần quan trọng. Đầu tiên là từ _main
đến đầu số LBB0_2
hoặc nơi khối thử của chúng tôi diễn ra. Bởi vì chúng tôi đang blatantly ném một ngoại lệ và bắt nó trong khối try
của chúng tôi, trình biên dịch đã đi trước và loại bỏ các chi nhánh xung quanh LBB0_2
và di chuyển thẳng đến xử lý bắt. Tại thời điểm này Objective-C, hoặc CoreFoundation chính xác hơn, đã thiết lập một đối tượng ngoại lệ cho chúng ta và libC++ đã bắt đầu tìm kiếm một trình xử lý ngoại lệ trong giai đoạn thư giãn cần thiết.
Khối mã quan trọng thứ hai là từ LBB0_2
đến cuối LBB0_11
nơi các khối catch
và finally
của chúng tôi hoạt động. Bởi vì tất cả là tốt, tất cả các mã dưới đây là chết (và hy vọng bị tước trong phát hành), nhưng hãy tưởng tượng nó không phải là.
Phần thứ ba là từ LBB0_8
trên xuống nơi trình biên dịch sẽ phát ra một bước nhảy từ NSLog trong LBB0_2
nếu chúng tôi đã làm điều gì đó ngu ngốc như, nói, cố gắng không để bắt ngoại lệ của chúng tôi. Trình xử lý này thay vì lật một chút sau khi gọi vào số objc_begin_catch
khiến chúng tôi rẽ nhánh trên ret
và di chuyển lên objc_exception_rethrow()
cho trình xử lý thư giãn mà chúng tôi đã loại bỏ bóng và tiếp tục tìm kiếm trình xử lý ở một nơi khác. Tất nhiên, chúng tôi là chính, vì vậy không có xử lý khác, và std::terminate
được gọi khi chúng tôi rời khỏi.
Tất cả điều này để nói rằng bạn sẽ có một khoảng thời gian tồi tệ nếu bạn muốn thử viết nội dung này bằng tay. Tất cả các hàm __cxa_*
và ObjC SPI ném xung quanh các đối tượng ngoại lệ theo cách bạn không thể dựa vào và (nhiều bi quan) xử lý được phát ra trong một very tight order để đảm bảo hợp đồng C++ ABI được đáp ứng bởi vì nếu nó không phải là yêu cầu cụ thể std::terminate
được gọi là.Nếu bạn muốn tham gia vai trò lắng nghe tích cực, bạn được phép redefine the exception handling stuff với các chức năng của riêng bạn và Mục tiêu-C có objc_setUncaughtExceptionHandler
, objc_setExceptionMatcher
objc_setExceptionPreprocessor
.
Xem xét obj-C++, bạn có muốn thực hiện việc tự giải phóng không? – hamstergene
Eugene, tôi không chắc chắn tôi làm theo ... Tôi đang tìm một ví dụ loại giống như một uncaughtException tôi đã có thể tìm ra ở đây: https://gist.github.com/1073294#file_uncaught_exception. m, nhưng tôi đoán cái gì đó giống như một loại 'begin_try' và' end_try'. – TooTallNate
Việc lắp ráp khối try/catch thực sự hiển thị các cuộc gọi đến objc_begin_catch và objc_end_catch. Bạn đã thử xem qua đó để xem chúng được viện dẫn như thế nào? –