Exception的throw try catch的实现(待续
已下面java code为例:
public class ZygoteInit { ... public static void main(String argv[]) {} try { ... if (abiList == null) { throw new RuntimeException("No ABI list supplied."); } ... } |
对应的汇编实现为:
0x74542405: ldr.w r0, [pc, #504] ; 0x74542600 ; java.lang.RuntimeException0x74542409: ldr.w lr, [r9, #300] ; 0x12c ; art::ArtThread.tlsPtr_.quick_entrypoints.pAllocObjectInitialized0x7454240d: mov r1, r100x7454240f: blx lr0x74542411: mov r11, r00x74542413: ldr.w r0, [r10, #20]0x74542417: movw r2, #59620 ; 0xe8e40x7454241b: ldr r1, [r0, r2]0x7454241d: str r1, [sp, #52] ; 0x340x7454241f: ldr.w lr, [pc, #372] ; 0x745425940x74542423: ldr r2, [sp, #52] ; 0x340x74542425: ldr.w r0, [pc, #432] ; 0x745425d8 ; java.lang.RuntimeException.<init> "(Ljava/lang/String;)V"0x74542429: mov r1, r110x7454242b: ldr.w r12, [r1]0x7454242f: blx lr0x74542431: ldr.w lr, [r9, #564] ; 0x234 ; art::ArtThread.tlsPtr_.quick_entrypoints.pDeliverException0x74542435: mov r0, r110x74542437: blx lr |
12、new的Native实现已经分析了new RuntimeException("No ABI list supplied.")的过程,这里再分析throw的实现。
明显,throw的操作跟这个pDeliverException相关,而这个pDeliverException指向的是art_quick_deliver_exception()。
(gdb) p *('art::Thread' *)0xb4f07800$77 = { ... tlsPtr_ = { ... quick_entrypoints = { ... pTestSuspend = 0xb4cb1211 <art_quick_test_suspend+1>, pDeliverException = 0xb4cafcb1 <art_quick_deliver_exception+1>, pThrowArrayBounds = 0xb4cafd11 <art_quick_throw_array_bounds+1>, pThrowDivZero = 0xb4cafcf1 <art_quick_throw_div_zero+1>, pThrowNoSuchMethod = 0xb4cafd51 <art_quick_throw_no_such_method+1>, pThrowNullPointer = 0xb4cafcd1 <art_quick_throw_null_pointer_exception+1>, pThrowStackOverflow = 0xb4cafd31 <art_quick_throw_stack_overflow+1>, ... |
这个值是线程初始化的时候赋上去的:
void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, PortableEntryPoints* ppoints, QuickEntryPoints* qpoints) { // Interpreter ipoints->pInterpreterToInterpreterBridge = artInterpreterToInterpreterBridge; ipoints->pInterpreterToCompiledCodeBridge = artInterpreterToCompiledCodeBridge; ... // Thread qpoints->pTestSuspend = art_quick_test_suspend; // Throws qpoints->pDeliverException = art_quick_deliver_exception; qpoints->pThrowArrayBounds = art_quick_throw_array_bounds; qpoints->pThrowDivZero = art_quick_throw_div_zero; qpoints->pThrowNoSuchMethod = art_quick_throw_no_such_method; qpoints->pThrowNullPointer = art_quick_throw_null_pointer_exception; qpoints->pThrowStackOverflow = art_quick_throw_stack_overflow;}; |
看看这个art_quick_deliver_exception()的实现:
.macro ONE_ARG_RUNTIME_EXCEPTION c_name, cxx_name .extern \cxx_nameENTRY \c_name SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context mov r1, r9 @ pass Thread::Current mov r2, sp @ pass SP b \cxx_name @ \cxx_name(Thread*, SP) bkptEND \c_name.endmONE_ARG_RUNTIME_EXCEPTION art_quick_deliver_exception, artDeliverExceptionFromCode |
最终会调用artDeliverExceptionFromCode()
extern "C" void artDeliverExceptionFromCode(mirror::Throwable* exception, Thread* self, StackReference<mirror::ArtMethod>* sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll); ThrowLocation throw_location = self->GetCurrentLocationForThrow(); if (exception == NULL) { self->ThrowNewException(throw_location, "Ljava/lang/NullPointerException;", "throw with null exception"); } else { self->SetException(throw_location, exception); } self->QuickDeliverException();} |
这个函数先调用Tread类的GetCurrentLocationForThrow()获取抛出异常的函数信息,
然后调用Tread类的SetException()将ThrowLocation和Exception写入Thread的tlsPtr_成员的exception和throw_location中。
再调用Tread类的QuickDeliverException(),找到Exception对应的catch代码块,并跳转到对应代码块中。
ThrowLocation Thread::GetCurrentLocationForThrow() { Context* context = GetLongJumpContext(); CurrentMethodVisitor visitor(this, context, true); visitor.WalkStack(false); ReleaseLongJumpContext(context); return ThrowLocation(visitor.this_object_, visitor.method_, visitor.dex_pc_);} |
void SetException(const ThrowLocation& throw_location, mirror::Throwable* new_exception) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { CHECK(new_exception != NULL); // TODO: DCHECK(!IsExceptionPending()); tlsPtr_.exception = new_exception; tlsPtr_.throw_location = throw_location;} |
重点是QuickDeliverException():
void Thread::QuickDeliverException() { // Get exception from thread. ThrowLocation throw_location; mirror::Throwable* exception = GetException(&throw_location); bool is_exception_reported = IsExceptionReportedToInstrumentation(); ClearException(); bool is_deoptimization = (exception == GetDeoptimizationException()); QuickExceptionHandler exception_handler(this, is_deoptimization); if (is_deoptimization) { exception_handler.DeoptimizeStack(); } else { exception_handler.FindCatch(throw_location, exception, is_exception_reported); } exception_handler.UpdateInstrumentationStack(); exception_handler.DoLongJump(); LOG(FATAL) << "UNREACHABLE";} |
先通过QuickExceptionHandler::FindCatch()在回溯调用栈,找到try catch块,
然后再调用QuickExceptionHandler::DoLongJump()跳转到catch块里。
void QuickExceptionHandler::FindCatch(const ThrowLocation& throw_location, mirror::Throwable* exception, bool is_exception_reported) { StackHandleScope<1> hs(self_); Handle<mirror::Throwable> exception_ref(hs.NewHandle(exception)); // Walk the stack to find catch handler or prepare for deoptimization. CatchBlockStackVisitor visitor(self_, context_, &exception_ref, this); visitor.WalkStack(true); ...}void QuickExceptionHandler::DoLongJump() { // Place context back on thread so it will be available when we continue. self_->ReleaseLongJumpContext(context_); context_->SetSP(reinterpret_cast<uintptr_t>(handler_quick_frame_)); CHECK_NE(handler_quick_frame_pc_, 0u); context_->SetPC(handler_quick_frame_pc_); context_->SmashCallerSaves(); context_->DoLongJump();} |
找到try catch的方法是,用CatchBlockStackVisitor类回溯栈:
class CatchBlockStackVisitor FINAL : public StackVisitor { public: CatchBlockStackVisitor(Thread* self, Context* context, Handle<mirror::Throwable>* exception, QuickExceptionHandler* exception_handler) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : StackVisitor(self, context), self_(self), exception_(exception), exception_handler_(exception_handler) { } bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtMethod* method = GetMethod(); exception_handler_->SetHandlerFrameDepth(GetFrameDepth()); if (method == nullptr) { ... return false; // End stack walk. } if (method->IsRuntimeMethod()) { ... return true; } StackHandleScope<1> hs(self_); return HandleTryItems(hs.NewHandle(method)); } private: bool HandleTryItems(Handle<mirror::ArtMethod> method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { uint32_t dex_pc = DexFile::kDexNoIndex; if (!method->IsNative()) { dex_pc = GetDexPc(); } if (dex_pc != DexFile::kDexNoIndex) { bool clear_exception = false; StackHandleScope<1> hs(Thread::Current()); Handle<mirror::Class> to_find(hs.NewHandle((*exception_)->GetClass())); uint32_t found_dex_pc = mirror::ArtMethod::FindCatchBlock(method, to_find, dex_pc, &clear_exception); exception_handler_->SetClearException(clear_exception); if (found_dex_pc != DexFile::kDexNoIndex) { exception_handler_->SetHandlerMethod(method.Get()); exception_handler_->SetHandlerDexPc(found_dex_pc); exception_handler_->SetHandlerQuickFramePc(method->ToNativePc(found_dex_pc)); exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame()); return false; // End stack walk. } } return true; // Continue stack walk. } |
这里调用mirror::ArtMethod::FindCatchBlock()方法,从dex文件里查找try catch块:
uint32_t ArtMethod::FindCatchBlock(Handle<ArtMethod> h_this, Handle<Class> exception_type, uint32_t dex_pc, bool* has_no_move_exception) { MethodHelper mh(h_this); const DexFile::CodeItem* code_item = h_this->GetCodeItem(); // Set aside the exception while we resolve its type. Thread* self = Thread::Current(); ThrowLocation throw_location; StackHandleScope<1> hs(self); Handle<mirror::Throwable> exception(hs.NewHandle(self->GetException(&throw_location))); bool is_exception_reported = self->IsExceptionReportedToInstrumentation(); self->ClearException(); // Default to handler not found. uint32_t found_dex_pc = DexFile::kDexNoIndex; // Iterate over the catch handlers associated with dex_pc. for (CatchHandlerIterator it(*code_item, dex_pc); it.HasNext(); it.Next()) { uint16_t iter_type_idx = it.GetHandlerTypeIndex(); // Catch all case if (iter_type_idx == DexFile::kDexNoIndex16) { //这里是catch all found_dex_pc = it.GetHandlerAddress(); break; } // Does this catch exception type apply? Class* iter_exception_type = mh.GetClassFromTypeIdx(iter_type_idx); if (UNLIKELY(iter_exception_type == nullptr)) { ... } else if (iter_exception_type->IsAssignableFrom(exception_type.Get())) { //如果catch的exception是当前exception的父类,则found found_dex_pc = it.GetHandlerAddress(); break; } } ... return found_dex_pc;} |
如果想了解DexFile中查找try catch语句的方法,可以研究CatchHandlerIterator()类,这里就不深究了。
浙公网安备 33010602011771号