diff options
author | 2022-12-16 18:38:16 +0000 | |
---|---|---|
committer | 2023-01-16 09:52:42 +0000 | |
commit | e52e4fb74e9f13009af4ffbfb2e5103ce035a94b (patch) | |
tree | f8ed6faeb6204eb3e3c67b1b88f49a4482a43ebe | |
parent | e92bc531dc1eeb50cd4f46e2fb4ea581a24b45ac (diff) |
We no longer use instrumentation stubs remove the support code
Remove the code to handle instrumentation stubs. We no longer use them.
Bug: 206029744
Test: art/test.py
Change-Id: I2b7eabf80bd34989314c0d2b299d7b1b35de0b85
22 files changed, 29 insertions, 834 deletions
diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc index b220068b31..79cf029b79 100644 --- a/compiler/utils/assembler_thumb_test_expected.cc.inc +++ b/compiler/utils/assembler_thumb_test_expected.cc.inc @@ -155,7 +155,7 @@ const char* const VixlJniHelpersResults = { " 224: f8d9 8024 ldr.w r8, [r9, #36]\n" " 228: 4770 bx lr\n" " 22a: f8d9 009c ldr.w r0, [r9, #156]\n" - " 22e: f8d9 e2d4 ldr.w lr, [r9, #724]\n" + " 22e: f8d9 e2d0 ldr.w lr, [r9, #720]\n" " 232: 47f0 blx lr\n" }; diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S index 26561461d7..1709c95a5a 100644 --- a/runtime/arch/arm/quick_entrypoints_arm.S +++ b/runtime/arch/arm/quick_entrypoints_arm.S @@ -1586,79 +1586,6 @@ END art_quick_to_interpreter_bridge ONE_ARG_RUNTIME_EXCEPTION art_invoke_obsolete_method_stub, artInvokeObsoleteMethod /* - * Routine that intercepts method calls and returns. - */ - .extern artInstrumentationMethodEntryFromCode - .extern artInstrumentationMethodExitFromCode -ENTRY art_quick_instrumentation_entry - @ Make stack crawlable and clobber r2 and r3 (post saving) - SETUP_SAVE_REFS_AND_ARGS_FRAME r2 - @ preserve r0 (not normally an arg) knowing there is a spare slot in kSaveRefsAndArgs. - str r0, [sp, #4] - mov r2, rSELF @ pass Thread::Current - mov r3, sp @ pass SP - blx artInstrumentationMethodEntryFromCode @ (Method*, Object*, Thread*, SP) - cbz r0, .Ldeliver_instrumentation_entry_exception - .cfi_remember_state - @ Deliver exception if we got nullptr as function. - mov r12, r0 @ r12 holds reference to code - ldr r0, [sp, #4] @ restore r0 - RESTORE_SAVE_REFS_AND_ARGS_FRAME - adr lr, art_quick_instrumentation_exit + /* thumb mode */ 1 - @ load art_quick_instrumentation_exit into lr in thumb mode - REFRESH_MARKING_REGISTER - bx r12 @ call method with lr set to art_quick_instrumentation_exit -.Ldeliver_instrumentation_entry_exception: - CFI_RESTORE_STATE_AND_DEF_CFA sp, FRAME_SIZE_SAVE_REFS_AND_ARGS - @ Deliver exception for art_quick_instrumentation_entry placed after - @ art_quick_instrumentation_exit so that the fallthrough works. - RESTORE_SAVE_REFS_AND_ARGS_FRAME - DELIVER_PENDING_EXCEPTION -END art_quick_instrumentation_entry - -ENTRY art_quick_instrumentation_exit - mov lr, #0 @ link register is to here, so clobber with 0 for later checks - SETUP_SAVE_EVERYTHING_FRAME r2 - - add r3, sp, #8 @ store fpr_res pointer, in kSaveEverything frame - add r2, sp, #136 @ store gpr_res pointer, in kSaveEverything frame - mov r1, sp @ pass SP - mov r0, rSELF @ pass Thread::Current - blx artInstrumentationMethodExitFromCode @ (Thread*, SP, gpr_res*, fpr_res*) - - cbz r0, .Ldo_deliver_instrumentation_exception - @ Deliver exception if we got nullptr as function. - .cfi_remember_state - cbnz r1, .Ldeoptimize - // Normal return. - str r0, [sp, #FRAME_SIZE_SAVE_EVERYTHING - 4] - @ Set return pc. - RESTORE_SAVE_EVERYTHING_FRAME - REFRESH_MARKING_REGISTER - bx lr -.Ldo_deliver_instrumentation_exception: - CFI_RESTORE_STATE_AND_DEF_CFA sp, FRAME_SIZE_SAVE_EVERYTHING - DELIVER_PENDING_EXCEPTION_FRAME_READY -.Ldeoptimize: - str r1, [sp, #FRAME_SIZE_SAVE_EVERYTHING - 4] - @ Set return pc. - RESTORE_SAVE_EVERYTHING_FRAME - // Jump to art_quick_deoptimize. - b art_quick_deoptimize -END art_quick_instrumentation_exit - - /* - * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization - * will long jump to the upcall with a special exception of -1. - */ - .extern artDeoptimize -ENTRY art_quick_deoptimize - SETUP_SAVE_EVERYTHING_FRAME r0 - mov r0, rSELF @ pass Thread::Current - blx artDeoptimize @ (Thread*) -END art_quick_deoptimize - - /* * Compiled code has requested that we deoptimize into the interpreter. The deoptimization * will long jump to the interpreter bridge. */ diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S index 1df24c1223..9f86a76bc8 100644 --- a/runtime/arch/arm64/quick_entrypoints_arm64.S +++ b/runtime/arch/arm64/quick_entrypoints_arm64.S @@ -1963,77 +1963,6 @@ END art_quick_to_interpreter_bridge */ ONE_ARG_RUNTIME_EXCEPTION art_invoke_obsolete_method_stub, artInvokeObsoleteMethod - -// -// Instrumentation-related stubs -// - .extern artInstrumentationMethodEntryFromCode -ENTRY art_quick_instrumentation_entry - SETUP_SAVE_REFS_AND_ARGS_FRAME - - mov x20, x0 // Preserve method reference in a callee-save. - - mov x2, xSELF - mov x3, sp // Pass SP - bl artInstrumentationMethodEntryFromCode // (Method*, Object*, Thread*, SP) - - mov xIP0, x0 // x0 = result of call. - mov x0, x20 // Reload method reference. - - RESTORE_SAVE_REFS_AND_ARGS_FRAME // Note: will restore xSELF - REFRESH_MARKING_REGISTER - cbz xIP0, 1f // Deliver the pending exception if method is null. - adr xLR, art_quick_instrumentation_exit - br xIP0 // Tail-call method with lr set to art_quick_instrumentation_exit. - -1: - DELIVER_PENDING_EXCEPTION -END art_quick_instrumentation_entry - - .extern artInstrumentationMethodExitFromCode -ENTRY art_quick_instrumentation_exit - mov xLR, #0 // Clobber LR for later checks. - SETUP_SAVE_EVERYTHING_FRAME - - add x3, sp, #16 // Pass floating-point result pointer, in kSaveEverything frame. - add x2, sp, #272 // Pass integer result pointer, in kSaveEverything frame. - mov x1, sp // Pass SP. - mov x0, xSELF // Pass Thread. - bl artInstrumentationMethodExitFromCode // (Thread*, SP, gpr_res*, fpr_res*) - - cbz x0, .Ldo_deliver_instrumentation_exception - .cfi_remember_state - // Handle error - cbnz x1, .Ldeoptimize - // Normal return. - str x0, [sp, #FRAME_SIZE_SAVE_EVERYTHING - 8] - // Set return pc. - RESTORE_SAVE_EVERYTHING_FRAME - REFRESH_MARKING_REGISTER - br lr -.Ldo_deliver_instrumentation_exception: - CFI_RESTORE_STATE_AND_DEF_CFA sp, FRAME_SIZE_SAVE_EVERYTHING - DELIVER_PENDING_EXCEPTION_FRAME_READY -.Ldeoptimize: - str x1, [sp, #FRAME_SIZE_SAVE_EVERYTHING - 8] - // Set return pc. - RESTORE_SAVE_EVERYTHING_FRAME - // Jump to art_quick_deoptimize. - b art_quick_deoptimize -END art_quick_instrumentation_exit - - /* - * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization - * will long jump to the upcall with a special exception of -1. - */ - .extern artDeoptimize -ENTRY art_quick_deoptimize - SETUP_SAVE_EVERYTHING_FRAME - mov x0, xSELF // Pass thread. - bl artDeoptimize // (Thread*) - brk 0 -END art_quick_deoptimize - /* * Compiled code has requested that we deoptimize into the interpreter. The deoptimization * will long jump to the upcall with a special exception of -1. diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S index c768229b32..479f46da67 100644 --- a/runtime/arch/x86/quick_entrypoints_x86.S +++ b/runtime/arch/x86/quick_entrypoints_x86.S @@ -1789,115 +1789,6 @@ END_FUNCTION art_quick_to_interpreter_bridge ONE_ARG_RUNTIME_EXCEPTION art_invoke_obsolete_method_stub, artInvokeObsoleteMethod /* - * Routine that intercepts method calls and returns. - */ -DEFINE_FUNCTION art_quick_instrumentation_entry - SETUP_SAVE_REFS_AND_ARGS_FRAME edx - PUSH eax // Save eax which will be clobbered by the callee-save method. - subl LITERAL(16), %esp // Align stack (12 bytes) and reserve space for the SP argument - CFI_ADJUST_CFA_OFFSET(16) // (4 bytes). We lack the scratch registers to calculate the SP - // right now, so we will just fill it in later. - pushl %fs:THREAD_SELF_OFFSET // Pass Thread::Current(). - CFI_ADJUST_CFA_OFFSET(4) - PUSH ecx // Pass receiver. - PUSH eax // Pass Method*. - leal 32(%esp), %eax // Put original SP into eax - movl %eax, 12(%esp) // set SP - call SYMBOL(artInstrumentationMethodEntryFromCode) // (Method*, Object*, Thread*, SP) - - addl LITERAL(28), %esp // Pop arguments upto saved Method*. - CFI_ADJUST_CFA_OFFSET(-28) - - testl %eax, %eax - jz 1f // Test for null return (indicating exception) and handle it. - - movl 60(%esp), %edi // Restore edi. - movl %eax, 60(%esp) // Place code* over edi, just under return pc. - SETUP_PC_REL_BASE ebx, .Linstrumentation_entry_pc_rel_base - leal SYMBOL(art_quick_instrumentation_exit) - .Linstrumentation_entry_pc_rel_base(%ebx), %ebx - // Place instrumentation exit as return pc. ebx holds the GOT computed on entry. - movl %ebx, 64(%esp) - movl 0(%esp), %eax // Restore eax. - // Restore FPRs (extra 4 bytes of offset due to EAX push at top). - movsd 8(%esp), %xmm0 - movsd 16(%esp), %xmm1 - movsd 24(%esp), %xmm2 - movsd 32(%esp), %xmm3 - - // Restore GPRs. - movl 40(%esp), %ecx // Restore ecx. - movl 44(%esp), %edx // Restore edx. - movl 48(%esp), %ebx // Restore ebx. - movl 52(%esp), %ebp // Restore ebp. - movl 56(%esp), %esi // Restore esi. - addl LITERAL(60), %esp // Wind stack back upto code*. - CFI_ADJUST_CFA_OFFSET(-60) - ret // Call method (and pop). -1: - // Make caller handle exception - addl LITERAL(4), %esp - CFI_ADJUST_CFA_OFFSET(-4) - RESTORE_SAVE_REFS_AND_ARGS_FRAME - DELIVER_PENDING_EXCEPTION -END_FUNCTION art_quick_instrumentation_entry - -DEFINE_FUNCTION_CUSTOM_CFA art_quick_instrumentation_exit, 0 - pushl LITERAL(0) // Push a fake return PC as there will be none on the stack. - CFI_ADJUST_CFA_OFFSET(4) - SETUP_SAVE_EVERYTHING_FRAME ebx - - movl %esp, %ecx // Remember SP - subl LITERAL(8), %esp // Align stack. - CFI_ADJUST_CFA_OFFSET(8) - PUSH edx // Save gpr return value. edx and eax need to be together, - // which isn't the case in kSaveEverything frame. - PUSH eax - leal 32(%esp), %eax // Get pointer to fpr_result, in kSaveEverything frame - movl %esp, %edx // Get pointer to gpr_result - PUSH eax // Pass fpr_result - PUSH edx // Pass gpr_result - PUSH ecx // Pass SP - pushl %fs:THREAD_SELF_OFFSET // Pass Thread::Current. - CFI_ADJUST_CFA_OFFSET(4) - - call SYMBOL(artInstrumentationMethodExitFromCode) // (Thread*, SP, gpr_result*, fpr_result*) - // Return result could have been changed if it's a reference. - movl 16(%esp), %ecx - movl %ecx, (80+32)(%esp) - addl LITERAL(32), %esp // Pop arguments and grp_result. - CFI_ADJUST_CFA_OFFSET(-32) - - testl %eax, %eax // Check if we returned error. - jz .Ldo_deliver_instrumentation_exception - testl %edx, %edx - jnz .Ldeoptimize - // Normal return. - movl %eax, FRAME_SIZE_SAVE_EVERYTHING-4(%esp) // Set return pc. - RESTORE_SAVE_EVERYTHING_FRAME - ret -.Ldeoptimize: - mov %edx, (FRAME_SIZE_SAVE_EVERYTHING-4)(%esp) // Set return pc. - RESTORE_SAVE_EVERYTHING_FRAME - jmp SYMBOL(art_quick_deoptimize) -.Ldo_deliver_instrumentation_exception: - DELIVER_PENDING_EXCEPTION_FRAME_READY -END_FUNCTION art_quick_instrumentation_exit - - /* - * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization - * will long jump to the upcall with a special exception of -1. - */ -DEFINE_FUNCTION art_quick_deoptimize - SETUP_SAVE_EVERYTHING_FRAME ebx - subl LITERAL(12), %esp // Align stack. - CFI_ADJUST_CFA_OFFSET(12) - pushl %fs:THREAD_SELF_OFFSET // Pass Thread::Current(). - CFI_ADJUST_CFA_OFFSET(4) - call SYMBOL(artDeoptimize) // (Thread*) - UNREACHABLE -END_FUNCTION art_quick_deoptimize - - /* * Compiled code has requested that we deoptimize into the interpreter. The deoptimization * will long jump to the interpreter bridge. */ diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S index babd1bc6b2..5a568d3155 100644 --- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S +++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S @@ -1655,82 +1655,6 @@ END_FUNCTION art_quick_to_interpreter_bridge ONE_ARG_RUNTIME_EXCEPTION art_invoke_obsolete_method_stub, artInvokeObsoleteMethod /* - * Routine that intercepts method calls and returns. - */ -DEFINE_FUNCTION art_quick_instrumentation_entry -#if defined(__APPLE__) - int3 - int3 -#else - SETUP_SAVE_REFS_AND_ARGS_FRAME - - movq %rdi, %r12 // Preserve method pointer in a callee-save. - - movq %gs:THREAD_SELF_OFFSET, %rdx // Pass thread. - movq %rsp, %rcx // Pass SP. - - call SYMBOL(artInstrumentationMethodEntryFromCode) // (Method*, Object*, Thread*, SP) - - // %rax = result of call. - testq %rax, %rax - jz 1f - - movq %r12, %rdi // Reload method pointer. - leaq art_quick_instrumentation_exit(%rip), %r12 // Set up return through instrumentation - movq %r12, FRAME_SIZE_SAVE_REFS_AND_ARGS-8(%rsp) // exit. - - RESTORE_SAVE_REFS_AND_ARGS_FRAME - - jmp *%rax // Tail call to intended method. -1: - RESTORE_SAVE_REFS_AND_ARGS_FRAME - DELIVER_PENDING_EXCEPTION -#endif // __APPLE__ -END_FUNCTION art_quick_instrumentation_entry - -DEFINE_FUNCTION_CUSTOM_CFA art_quick_instrumentation_exit, 0 - pushq LITERAL(0) // Push a fake return PC as there will be none on the stack. - CFI_ADJUST_CFA_OFFSET(8) - - SETUP_SAVE_EVERYTHING_FRAME - - leaq 16(%rsp), %rcx // Pass floating-point result pointer, in kSaveEverything frame. - leaq 144(%rsp), %rdx // Pass integer result pointer, in kSaveEverything frame. - movq %rsp, %rsi // Pass SP. - movq %gs:THREAD_SELF_OFFSET, %rdi // Pass Thread. - - call SYMBOL(artInstrumentationMethodExitFromCode) // (Thread*, SP, gpr_res*, fpr_res*) - - testq %rax, %rax // Check if we have a return-pc to go to. If we don't then there was - // an exception - jz .Ldo_deliver_instrumentation_exception - testq %rdx, %rdx - jnz .Ldeoptimize - // Normal return. - movq %rax, FRAME_SIZE_SAVE_EVERYTHING-8(%rsp) // Set return pc. - RESTORE_SAVE_EVERYTHING_FRAME - ret -.Ldeoptimize: - movq %rdx, FRAME_SIZE_SAVE_EVERYTHING-8(%rsp) // Set return pc. - RESTORE_SAVE_EVERYTHING_FRAME - // Jump to art_quick_deoptimize. - jmp SYMBOL(art_quick_deoptimize) -.Ldo_deliver_instrumentation_exception: - DELIVER_PENDING_EXCEPTION_FRAME_READY -END_FUNCTION art_quick_instrumentation_exit - - /* - * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization - * will long jump to the upcall with a special exception of -1. - */ -DEFINE_FUNCTION art_quick_deoptimize - SETUP_SAVE_EVERYTHING_FRAME // Stack should be aligned now. - movq %gs:THREAD_SELF_OFFSET, %rdi // Pass Thread. - call SYMBOL(artDeoptimize) // (Thread*) - UNREACHABLE -END_FUNCTION art_quick_deoptimize - - /* * Compiled code has requested that we deoptimize into the interpreter. The deoptimization * will long jump to the interpreter bridge. */ diff --git a/runtime/art_method.cc b/runtime/art_method.cc index 2ff145d263..b500d9b592 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -585,10 +585,6 @@ bool ArtMethod::EqualParameters(Handle<mirror::ObjectArray<mirror::Class>> param } const OatQuickMethodHeader* ArtMethod::GetOatQuickMethodHeader(uintptr_t pc) { - // Our callers should make sure they don't pass the instrumentation exit pc, - // as this method does not look at the side instrumentation stack. - DCHECK_NE(pc, reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc())); - if (IsRuntimeMethod()) { return nullptr; } @@ -614,7 +610,6 @@ const OatQuickMethodHeader* ArtMethod::GetOatQuickMethodHeader(uintptr_t pc) { if (!class_linker->IsQuickGenericJniStub(existing_entry_point) && !class_linker->IsQuickResolutionStub(existing_entry_point) && !class_linker->IsQuickToInterpreterBridge(existing_entry_point) && - existing_entry_point != GetQuickInstrumentationEntryPoint() && existing_entry_point != GetInvokeObsoleteMethodStub()) { OatQuickMethodHeader* method_header = OatQuickMethodHeader::FromEntryPoint(existing_entry_point); @@ -656,7 +651,6 @@ const OatQuickMethodHeader* ArtMethod::GetOatQuickMethodHeader(uintptr_t pc) { // to different entrypoints or to a JIT-compiled JNI stub. DCHECK(class_linker->IsQuickGenericJniStub(existing_entry_point) || class_linker->IsQuickResolutionStub(existing_entry_point) || - existing_entry_point == GetQuickInstrumentationEntryPoint() || (jit != nullptr && jit->GetCodeCache()->ContainsPc(existing_entry_point))) << " entrypoint: " << existing_entry_point << " size: " << OatQuickMethodHeader::FromEntryPoint(existing_entry_point)->GetCodeSize() diff --git a/runtime/backtrace_helper.cc b/runtime/backtrace_helper.cc index d76a5013a3..260843d7dc 100644 --- a/runtime/backtrace_helper.cc +++ b/runtime/backtrace_helper.cc @@ -131,14 +131,6 @@ bool BacktraceCollector::CollectImpl(unwindstack::Unwinder* unwinder) { CHECK_LT(num_frames_, max_depth_); out_frames_[num_frames_++] = static_cast<uintptr_t>(it->pc); - // Expected early end: Instrumentation breaks unwinding (b/138296821). - // Inexact compare because the unwinder does not give us exact return address, - // but rather it tries to guess the address of the preceding call instruction. - size_t exit_pc = reinterpret_cast<size_t>(GetQuickInstrumentationExitPc()); - if (exit_pc - 4 <= it->pc && it->pc <= exit_pc) { - return true; - } - if (kStrictUnwindChecks) { if (it->function_name.empty()) { return false; diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index f5a4ce689c..e109a505b6 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1195,11 +1195,6 @@ void ClassLinker::RunRootClinits(Thread* self) { for (ArtField* field : static_fields_of_classes_to_initialize) { EnsureRootInitialized(this, self, field->GetDeclaringClass()); } - - // This invariant is important since otherwise we will have the entire proxy invoke system - // confused. - DCHECK_NE(WellKnownClasses::java_lang_reflect_Proxy_init->GetEntryPointFromQuickCompiledCode(), - GetQuickInstrumentationEntryPoint()); } ALWAYS_INLINE diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc index ae6e98a544..e6d0adb1be 100644 --- a/runtime/entrypoints/entrypoint_utils.cc +++ b/runtime/entrypoints/entrypoint_utils.cc @@ -211,9 +211,8 @@ static inline std::pair<ArtMethod*, uintptr_t> DoGetCalleeSaveMethodOuterCallerA static inline ArtMethod* DoGetCalleeSaveMethodCaller(ArtMethod* outer_method, uintptr_t caller_pc, bool do_caller_check) - REQUIRES_SHARED(Locks::mutator_lock_) { - ArtMethod* caller = outer_method; - if (LIKELY(caller_pc != reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()))) { + REQUIRES_SHARED(Locks::mutator_lock_) { + ArtMethod* caller = outer_method; if (outer_method != nullptr) { const OatQuickMethodHeader* current_code = outer_method->GetOatQuickMethodHeader(caller_pc); DCHECK(current_code != nullptr); @@ -236,14 +235,7 @@ static inline ArtMethod* DoGetCalleeSaveMethodCaller(ArtMethod* outer_method, visitor.WalkStack(); CHECK_EQ(caller, visitor.caller); } - } else { - // We're instrumenting, just use the StackVisitor which knows how to - // handle instrumented frames. - NthCallerVisitor visitor(Thread::Current(), 1, true); - visitor.WalkStack(); - caller = visitor.caller; - } - return caller; + return caller; } ArtMethod* GetCalleeSaveMethodCaller(ArtMethod** sp, CalleeSaveType type, bool do_caller_check) diff --git a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc index 89d5c18551..277bc7bf06 100644 --- a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc @@ -48,11 +48,10 @@ NO_RETURN static void artDeoptimizeImpl(Thread* self, } else { exception_handler.DeoptimizeStack(skip_method_exit_callbacks); } - uintptr_t return_pc = exception_handler.UpdateInstrumentationStack(); if (exception_handler.IsFullFragmentDone()) { exception_handler.DoLongJump(true); } else { - exception_handler.DeoptimizePartialFragmentFixup(return_pc); + exception_handler.DeoptimizePartialFragmentFixup(); // We cannot smash the caller-saves, as we need the ArtMethod in a parameter register that would // be caller-saved. This has the downside that we cannot track incorrect register usage down the // line. diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 4baf60c4ea..559662cf9a 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -996,96 +996,6 @@ void RememberForGcArgumentVisitor::FixupReferences() { } } -extern "C" const void* artInstrumentationMethodEntryFromCode(ArtMethod* method, - mirror::Object* this_object, - Thread* self, - ArtMethod** sp) - REQUIRES_SHARED(Locks::mutator_lock_) { - const void* result; - // Instrumentation changes the stack. Thus, when exiting, the stack cannot be verified, so skip - // that part. - ScopedQuickEntrypointChecks sqec(self, kIsDebugBuild, false); - instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); - DCHECK(!method->IsProxyMethod()) - << "Proxy method " << method->PrettyMethod() - << " (declaring class: " << method->GetDeclaringClass()->PrettyClass() << ")" - << " should not hit instrumentation entrypoint."; - DCHECK(!instrumentation->IsDeoptimized(method)) << method->PrettyMethod(); - // This will get the entry point either from the oat file, the JIT or the appropriate bridge - // method if none of those can be found. - result = instrumentation->GetCodeForInvoke(method); - DCHECK_NE(result, GetQuickInstrumentationEntryPoint()) << method->PrettyMethod(); - bool interpreter_entry = Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(result); - bool is_static = method->IsStatic(); - uint32_t shorty_len; - const char* shorty = - method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(&shorty_len); - - ScopedObjectAccessUnchecked soa(self); - RememberForGcArgumentVisitor visitor(sp, is_static, shorty, shorty_len, &soa); - visitor.VisitArguments(); - - StackHandleScope<2> hs(self); - Handle<mirror::Object> h_object(hs.NewHandle(is_static ? nullptr : this_object)); - - // Ensure that the called method's class is initialized. - if (method->StillNeedsClinitCheck()) { - Handle<mirror::Class> h_class = hs.NewHandle(method->GetDeclaringClass()); - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) { - visitor.FixupReferences(); - DCHECK(self->IsExceptionPending()); - return nullptr; - } - } - - DCHECK(!method->IsRuntimeMethod()); - instrumentation->PushInstrumentationStackFrame(self, - is_static ? nullptr : h_object.Get(), - method, - reinterpret_cast<uintptr_t>( - QuickArgumentVisitor::GetCallingPcAddr(sp)), - QuickArgumentVisitor::GetCallingPc(sp), - interpreter_entry); - - visitor.FixupReferences(); - if (UNLIKELY(self->IsExceptionPending())) { - return nullptr; - } - CHECK(result != nullptr) << method->PrettyMethod(); - return result; -} - -extern "C" TwoWordReturn artInstrumentationMethodExitFromCode(Thread* self, - ArtMethod** sp, - uint64_t* gpr_result, - uint64_t* fpr_result) - REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK_EQ(reinterpret_cast<uintptr_t>(self), reinterpret_cast<uintptr_t>(Thread::Current())); - CHECK(gpr_result != nullptr); - CHECK(fpr_result != nullptr); - // Instrumentation exit stub must not be entered with a pending exception. - CHECK(!self->IsExceptionPending()) << "Enter instrumentation exit stub with pending exception " - << self->GetException()->Dump(); - // Compute address of return PC and check that it currently holds 0. - constexpr size_t return_pc_offset = - RuntimeCalleeSaveFrame::GetReturnPcOffset(CalleeSaveType::kSaveEverything); - uintptr_t* return_pc_addr = reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(sp) + - return_pc_offset); - CHECK_EQ(*return_pc_addr, 0U); - - // Pop the frame filling in the return pc. The low half of the return value is 0 when - // deoptimization shouldn't be performed with the high-half having the return address. When - // deoptimization should be performed the low half is zero and the high-half the address of the - // deoptimization entry point. - instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); - TwoWordReturn return_or_deoptimize_pc = instrumentation->PopInstrumentationStackFrame( - self, return_pc_addr, gpr_result, fpr_result); - if (self->IsExceptionPending() || self->ObserveAsyncException()) { - return GetTwoWordFailureValue(); - } - return return_or_deoptimize_pc; -} - static std::string DumpInstruction(ArtMethod* method, uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_) { if (dex_pc == static_cast<uint32_t>(-1)) { @@ -1128,12 +1038,6 @@ static void DumpB74410240DebugData(ArtMethod** sp) REQUIRES_SHARED(Locks::mutato (reinterpret_cast<uint8_t*>(sp) + callee_return_pc_offset)); ArtMethod* outer_method = *caller_sp; - if (UNLIKELY(caller_pc == reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()))) { - LOG(FATAL_WITHOUT_ABORT) << "Method: " << outer_method->PrettyMethod() - << " native pc: " << caller_pc << " Instrumented!"; - return; - } - const OatQuickMethodHeader* current_code = outer_method->GetOatQuickMethodHeader(caller_pc); CHECK(current_code != nullptr); CHECK(current_code->IsOptimized()); diff --git a/runtime/entrypoints/runtime_asm_entrypoints.h b/runtime/entrypoints/runtime_asm_entrypoints.h index c4e62e5b87..951398dc04 100644 --- a/runtime/entrypoints/runtime_asm_entrypoints.h +++ b/runtime/entrypoints/runtime_asm_entrypoints.h @@ -79,21 +79,9 @@ static inline const void* GetQuickDeoptimizationEntryPoint() { return reinterpret_cast<const void*>(art_quick_deoptimize); } -// Return address of instrumentation entry point used by non-interpreter based tracing. -extern "C" void art_quick_instrumentation_entry(void*); -static inline const void* GetQuickInstrumentationEntryPoint() { - return reinterpret_cast<const void*>(art_quick_instrumentation_entry); -} - // Stub to deoptimize from compiled code. extern "C" void art_quick_deoptimize_from_compiled_code(DeoptimizationKind); -// The return_pc of instrumentation exit stub. -extern "C" void art_quick_instrumentation_exit(); -static inline const void* GetQuickInstrumentationExitPc() { - return reinterpret_cast<const void*>(art_quick_instrumentation_exit); -} - extern "C" void* art_quick_string_builder_append(uint32_t format); extern "C" void art_quick_compile_optimized(ArtMethod*, Thread*); extern "C" void art_quick_method_entry_hook(ArtMethod*, Thread*); diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc index 50fa0ab0fb..be1c58dd6d 100644 --- a/runtime/entrypoints_order_test.cc +++ b/runtime/entrypoints_order_test.cc @@ -98,9 +98,8 @@ class EntrypointsOrderTest : public CommonArtTest { EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, monitor_enter_object, top_handle_scope, sizeof(void*)); EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, top_handle_scope, class_loader_override, sizeof(void*)); EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, class_loader_override, long_jump_context, sizeof(void*)); - EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, long_jump_context, instrumentation_stack, sizeof(void*)); - EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, instrumentation_stack, stacked_shadow_frame_record, - sizeof(void*)); + EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, long_jump_context, + stacked_shadow_frame_record, sizeof(void*)); EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stacked_shadow_frame_record, deoptimization_context_stack, sizeof(void*)); EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, deoptimization_context_stack, @@ -109,9 +108,7 @@ class EntrypointsOrderTest : public CommonArtTest { EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, name, pthread_self, sizeof(void*)); EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, pthread_self, last_no_thread_suspension_cause, sizeof(void*)); - EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, last_no_thread_suspension_cause, checkpoint_function, - sizeof(void*)); - EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, checkpoint_function, active_suspend_barriers, + EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, last_no_thread_suspension_cause, active_suspend_barriers, sizeof(void*)); EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, active_suspend_barriers, thread_local_start, sizeof(Thread::tls_ptr_sized_values::active_suspend_barriers)); @@ -119,7 +116,9 @@ class EntrypointsOrderTest : public CommonArtTest { EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_pos, thread_local_end, sizeof(void*)); EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_end, thread_local_limit, sizeof(void*)); EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_limit, thread_local_objects, sizeof(void*)); - EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_objects, jni_entrypoints, sizeof(size_t)); + EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_objects, checkpoint_function, sizeof(size_t)); + EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, checkpoint_function, jni_entrypoints, + sizeof(void*)); // Skip across the entrypoints structures. EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, rosalloc_runs, thread_local_alloc_stack_top, diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index 0863ddf68a..60511b546c 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -108,8 +108,7 @@ class InstallStubsClassVisitor : public ClassVisitor { }; Instrumentation::Instrumentation() - : current_force_deopt_id_(0), - instrumentation_stubs_installed_(false), + : instrumentation_stubs_installed_(false), instrumentation_level_(InstrumentationLevel::kInstrumentNothing), forced_interpret_only_(false), have_method_entry_listeners_(false), @@ -188,8 +187,7 @@ static bool CanHandleInitializationCheck(const void* code) { return class_linker->IsQuickResolutionStub(code) || class_linker->IsQuickToInterpreterBridge(code) || class_linker->IsQuickGenericJniStub(code) || - (code == interpreter::GetNterpWithClinitEntryPoint()) || - (code == GetQuickInstrumentationEntryPoint()); + (code == interpreter::GetNterpWithClinitEntryPoint()); } static bool IsProxyInit(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) { @@ -262,9 +260,6 @@ static void UpdateEntryPoints(ArtMethod* method, const void* quick_code) CHECK_EQ(reinterpret_cast<uintptr_t>(quick_code) & 1, 1u); } } - if (IsProxyInit(method)) { - CHECK_NE(quick_code, GetQuickInstrumentationEntryPoint()); - } const Instrumentation* instr = Runtime::Current()->GetInstrumentation(); if (instr->EntryExitStubsInstalled()) { DCHECK(CodeSupportsEntryExitHooks(quick_code, method)); @@ -686,7 +681,6 @@ void Instrumentation::DeoptimizeAllThreadFrames() { Locks::mutator_lock_->AssertExclusiveHeld(self); InstrumentThreadStack(t, /* deopt_all_frames= */ true); }); - current_force_deopt_id_++; } static bool HasEvent(Instrumentation::InstrumentationEvent expected, uint32_t events) { @@ -906,12 +900,7 @@ void Instrumentation::MaybeRestoreInstrumentationStack() { no_remaining_deopts = no_remaining_deopts && !t->IsForceInterpreter() && - !t->HasDebuggerShadowFrames() && - std::all_of(t->GetInstrumentationStack()->cbegin(), - t->GetInstrumentationStack()->cend(), - [&](const auto& frame) REQUIRES_SHARED(Locks::mutator_lock_) { - return frame.second.force_deopt_id_ == current_force_deopt_id_; - }); + !t->HasDebuggerShadowFrames(); }); if (no_remaining_deopts) { Runtime::Current()->GetThreadList()->ForEach(InstrumentationRestoreStack, this); @@ -1023,8 +1012,6 @@ std::string Instrumentation::EntryPointString(const void* code) { return "interpreter"; } else if (class_linker->IsQuickResolutionStub(code)) { return "resolution"; - } else if (code == GetQuickInstrumentationEntryPoint()) { - return "instrumentation"; } else if (jit != nullptr && jit->GetCodeCache()->ContainsPc(code)) { return "jit"; } else if (code == GetInvokeObsoleteMethodStub()) { @@ -1251,8 +1238,7 @@ const void* Instrumentation::GetCodeForInvoke(ArtMethod* method) { // If we don't have the instrumentation, the resolution stub, or the // interpreter, just return the current entrypoint, // assuming it's the most optimized. - if (code != GetQuickInstrumentationEntryPoint() && - !class_linker->IsQuickResolutionStub(code) && + if (!class_linker->IsQuickResolutionStub(code) && !class_linker->IsQuickToInterpreterBridge(code)) { return code; } @@ -1442,40 +1428,6 @@ void Instrumentation::ExceptionHandledEvent(Thread* thread, } } -void Instrumentation::PushInstrumentationStackFrame(Thread* self, - ObjPtr<mirror::Object> this_object, - ArtMethod* method, - uintptr_t stack_ptr, - uintptr_t lr, - bool interpreter_entry) { - DCHECK(!self->IsExceptionPending()); - std::map<uintptr_t, instrumentation::InstrumentationStackFrame>* stack = - self->GetInstrumentationStack(); - if (kVerboseInstrumentation) { - LOG(INFO) << "Entering " << ArtMethod::PrettyMethod(method) << " from PC " - << reinterpret_cast<void*>(lr); - } - - // We send the enter event before pushing the instrumentation frame to make cleanup easier. If the - // event causes an exception we can simply send the unwind event and return. - StackHandleScope<1> hs(self); - Handle<mirror::Object> h_this(hs.NewHandle(this_object)); - if (!interpreter_entry) { - MethodEnterEvent(self, method); - if (self->IsExceptionPending()) { - MethodUnwindEvent(self, method, 0); - return; - } - } - - // We have a callee-save frame meaning this value is guaranteed to never be 0. - DCHECK(!self->IsExceptionPending()); - - instrumentation::InstrumentationStackFrame instrumentation_frame( - h_this.Get(), method, lr, interpreter_entry, current_force_deopt_id_); - stack->insert({stack_ptr, instrumentation_frame}); -} - DeoptimizationMethodType Instrumentation::GetDeoptimizationMethodType(ArtMethod* method) { if (method->IsRuntimeMethod()) { // Certain methods have strict requirement on whether the dex instruction @@ -1612,10 +1564,7 @@ bool Instrumentation::ShouldDeoptimizeCaller(Thread* self, uintptr_t caller_sp) { if (caller == nullptr || caller->IsNative() || - caller->IsRuntimeMethod() || - caller_pc == reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc())) { - // If caller_pc is QuickInstrumentationExit then deoptimization will be handled by the - // instrumentation exit trampoline so we don't need to handle deoptimizations here. + caller->IsRuntimeMethod()) { // We need to check for a deoptimization here because when a redefinition happens it is // not safe to use any compiled code because the field offsets might change. For native // methods, we don't embed any field offsets so no need to check for a deoptimization. @@ -1656,118 +1605,5 @@ bool Instrumentation::ShouldDeoptimizeCaller(Thread* self, return false; } -TwoWordReturn Instrumentation::PopInstrumentationStackFrame(Thread* self, - uintptr_t* return_pc_addr, - uint64_t* gpr_result, - uint64_t* fpr_result) { - DCHECK(gpr_result != nullptr); - DCHECK(fpr_result != nullptr); - // Do the pop. - std::map<uintptr_t, instrumentation::InstrumentationStackFrame>* stack = - self->GetInstrumentationStack(); - CHECK_GT(stack->size(), 0U); - auto it = stack->find(reinterpret_cast<uintptr_t>(return_pc_addr)); - CHECK(it != stack->end()); - InstrumentationStackFrame instrumentation_frame = it->second; - stack->erase(it); - - // Set return PC and check the consistency of the stack. - // We don't cache the return pc value in a local as it may change after - // sending a method exit event. - *return_pc_addr = instrumentation_frame.return_pc_; - self->VerifyStack(); - - ArtMethod* method = instrumentation_frame.method_; - DCHECK(!method->IsRuntimeMethod()); - - bool is_ref; - JValue return_value = GetReturnValue(method, &is_ref, gpr_result, fpr_result); - StackHandleScope<1> hs(self); - MutableHandle<mirror::Object> res(hs.NewHandle<mirror::Object>(nullptr)); - if (is_ref) { - // Take a handle to the return value so we won't lose it if we suspend. - DCHECK_ALIGNED(return_value.GetL(), kObjectAlignment); - res.Assign(return_value.GetL()); - } - if (!instrumentation_frame.interpreter_entry_) { - DCHECK(!method->IsRuntimeMethod()); - // Note that sending the event may change the contents of *return_pc_addr. - MethodExitEvent(self, instrumentation_frame.method_, OptionalFrame{}, return_value); - } - - // Deoptimize if the caller needs to continue execution in the interpreter. Do nothing if we get - // back to an upcall. - NthCallerVisitor visitor(self, 1, true); - visitor.WalkStack(true); - // Check if we forced all threads to deoptimize in the time between this frame being created and - // now. - bool should_deoptimize_frame = instrumentation_frame.force_deopt_id_ != current_force_deopt_id_; - bool deoptimize = ShouldDeoptimizeCaller(self, visitor) || should_deoptimize_frame; - - if (is_ref) { - // Restore the return value if it's a reference since it might have moved. - *reinterpret_cast<mirror::Object**>(gpr_result) = res.Get(); - } - - if (deoptimize) { - // NthCallerVisitor also takes inlined frames into consideration, so visitor.caller points to - // the inlined function. We need the actual method corresponding to the return_pc_addr to check - // if the method is deoptimizeable. So fetch the outer method. - if (Runtime::Current()->IsAsyncDeoptimizeable(visitor.GetOuterMethod(), *return_pc_addr)) { - if (kVerboseInstrumentation) { - LOG(INFO) << "Deoptimizing " - << visitor.caller->PrettyMethod() - << " by returning from " - << method->PrettyMethod() - << " with result " - << std::hex << return_value.GetJ() << std::dec - << " in " - << *self; - } - DeoptimizationMethodType deopt_method_type = GetDeoptimizationMethodType(method); - self->PushDeoptimizationContext(return_value, - is_ref, - /* exception= */ nullptr, - /* from_code= */ false, - deopt_method_type); - return GetTwoWordSuccessValue( - *return_pc_addr, reinterpret_cast<uintptr_t>(GetQuickDeoptimizationEntryPoint())); - } else { - VLOG(deopt) << "Got a deoptimization request on un-deoptimizable " - << visitor.caller->PrettyMethod() << " at PC " - << reinterpret_cast<void*>(*return_pc_addr); - } - } - - if (kVerboseInstrumentation) { - LOG(INFO) << "Returning from " << method->PrettyMethod() << " to PC " - << reinterpret_cast<void*>(*return_pc_addr); - } - return GetTwoWordSuccessValue(0, *return_pc_addr); -} - -uintptr_t Instrumentation::PopInstrumentationStackUntil(Thread* self, uintptr_t pop_until) const { - std::map<uintptr_t, instrumentation::InstrumentationStackFrame>* stack = - self->GetInstrumentationStack(); - // Pop all instrumentation frames below `pop_until`. - uintptr_t return_pc = 0u; - for (auto i = stack->begin(); i != stack->end() && i->first <= pop_until;) { - if (kVerboseInstrumentation) { - LOG(INFO) << "Popping for deoptimization " << i->second.method_->PrettyMethod(); - } - return_pc = i->second.return_pc_; - i = stack->erase(i); - } - return return_pc; -} - -std::string InstrumentationStackFrame::Dump() const { - std::ostringstream os; - os << ArtMethod::PrettyMethod(method_) << ":" - << reinterpret_cast<void*>(return_pc_) << " this=" << reinterpret_cast<void*>(this_object_) - << " force_deopt_id=" << force_deopt_id_; - return os.str(); -} - } // namespace instrumentation } // namespace art diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h index aecad1f6e6..3d868ebc09 100644 --- a/runtime/instrumentation.h +++ b/runtime/instrumentation.h @@ -235,7 +235,7 @@ class Instrumentation { void AddListener(InstrumentationListener* listener, uint32_t events) REQUIRES(Locks::mutator_lock_, !Locks::thread_list_lock_, !Locks::classlinker_classes_lock_); - // Removes a listener possibly removing instrumentation stubs. + // Removes listeners for the specified events. void RemoveListener(InstrumentationListener* listener, uint32_t events) REQUIRES(Locks::mutator_lock_, !Locks::thread_list_lock_, !Locks::classlinker_classes_lock_); @@ -536,36 +536,9 @@ class Instrumentation { bool NeedsSlowInterpreterForMethod(Thread* self, ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); - // Called when an instrumented method is entered. The intended link register (lr) is saved so - // that returning causes a branch to the method exit stub. Generates method enter events. - void PushInstrumentationStackFrame(Thread* self, - ObjPtr<mirror::Object> this_object, - ArtMethod* method, - uintptr_t stack_pointer, - uintptr_t lr, - bool interpreter_entry) - REQUIRES_SHARED(Locks::mutator_lock_); - DeoptimizationMethodType GetDeoptimizationMethodType(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); - // Called when an instrumented method is exited. Removes the pushed instrumentation frame - // returning the intended link register. Generates method exit events. The gpr_result and - // fpr_result pointers are pointers to the locations where the integer/pointer and floating point - // result values of the function are stored. Both pointers must always be valid but the values - // held there will only be meaningful if interpreted as the appropriate type given the function - // being returned from. - TwoWordReturn PopInstrumentationStackFrame(Thread* self, - uintptr_t* return_pc_addr, - uint64_t* gpr_result, - uint64_t* fpr_result) - REQUIRES_SHARED(Locks::mutator_lock_); - - // Pops instrumentation frames until the specified stack_pointer from the current thread. Returns - // the return pc for the last instrumentation frame that's popped. - uintptr_t PopInstrumentationStackUntil(Thread* self, uintptr_t stack_pointer) const - REQUIRES_SHARED(Locks::mutator_lock_); - // Call back for configure stubs. void InstallStubsForClass(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); @@ -675,11 +648,6 @@ class Instrumentation { void UpdateMethodsCodeImpl(ArtMethod* method, const void* new_code) REQUIRES_SHARED(Locks::mutator_lock_); - // A counter that's incremented every time a DeoptimizeAllFrames. We check each - // InstrumentationStackFrames creation id against this number and if they differ we deopt even if - // we could otherwise continue running. - uint64_t current_force_deopt_id_ GUARDED_BY(Locks::mutator_lock_); - // Have we hijacked ArtMethod::code_ so that it calls instrumentation/interpreter code? bool instrumentation_stubs_installed_; @@ -779,29 +747,6 @@ class Instrumentation { std::ostream& operator<<(std::ostream& os, Instrumentation::InstrumentationEvent rhs); std::ostream& operator<<(std::ostream& os, Instrumentation::InstrumentationLevel rhs); -// An element in the instrumentation side stack maintained in art::Thread. -struct InstrumentationStackFrame { - InstrumentationStackFrame(mirror::Object* this_object, - ArtMethod* method, - uintptr_t return_pc, - bool interpreter_entry, - uint64_t force_deopt_id) - : this_object_(this_object), - method_(method), - return_pc_(return_pc), - interpreter_entry_(interpreter_entry), - force_deopt_id_(force_deopt_id) { - } - - std::string Dump() const REQUIRES_SHARED(Locks::mutator_lock_); - - mirror::Object* this_object_; - ArtMethod* method_; - uintptr_t return_pc_; - bool interpreter_entry_; - uint64_t force_deopt_id_; -}; - } // namespace instrumentation } // namespace art diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index 404eb69829..033b4da84a 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -92,10 +92,6 @@ bool ShouldStayInSwitchInterpreter(ArtMethod* method) } const void* code = method->GetEntryPointFromQuickCompiledCode(); - if (code == GetQuickInstrumentationEntryPoint()) { - code = Runtime::Current()->GetInstrumentation()->GetCodeForInvoke(method); - } - return Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(code); } diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index 1ab1c77039..4271a09283 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -1060,22 +1060,6 @@ class MarkCodeClosure final : public Closure { /* context= */ nullptr, art::StackVisitor::StackWalkKind::kSkipInlinedFrames); - if (kIsDebugBuild) { - // The stack walking code queries the side instrumentation stack if it - // sees an instrumentation exit pc, so the JIT code of methods in that stack - // must have been seen. We check this below. - for (const auto& it : *thread->GetInstrumentationStack()) { - // The 'method_' in InstrumentationStackFrame is the one that has return_pc_ in - // its stack frame, it is not the method owning return_pc_. We just pass null to - // LookupMethodHeader: the method is only checked against in debug builds. - OatQuickMethodHeader* method_header = - code_cache_->LookupMethodHeader(it.second.return_pc_, /* method= */ nullptr); - if (method_header != nullptr) { - const void* code = method_header->GetCode(); - CHECK(bitmap_->Test(FromCodeToAllocation(code))); - } - } - } barrier_->Pass(Thread::Current()); } diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index 8aac7020bd..fd57b4ae83 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -53,8 +53,6 @@ QuickExceptionHandler::QuickExceptionHandler(Thread* self, bool is_deoptimizatio : self_(self), context_(self->GetLongJumpContext()), is_deoptimization_(is_deoptimization), - method_tracing_active_(is_deoptimization || - Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()), handler_quick_frame_(nullptr), handler_quick_frame_pc_(0), handler_method_header_(nullptr), @@ -253,8 +251,6 @@ void QuickExceptionHandler::FindCatch(ObjPtr<mirror::Throwable> exception, exception_ref); } while (!popped_to_top); - // Pop off frames on instrumentation stack to keep it in sync with what is on the stack. - instr->PopInstrumentationStackUntil(self_, reinterpret_cast<uintptr_t>(handler_quick_frame_)); if (!clear_exception_) { // Put exception back in root set with clear throw location. self_->SetException(exception_ref.Get()); @@ -722,21 +718,8 @@ void QuickExceptionHandler::DeoptimizeSingleFrame(DeoptimizationKind kind) { PrepareForLongJumpToInvokeStubOrInterpreterBridge(); } -void QuickExceptionHandler::DeoptimizePartialFragmentFixup(uintptr_t return_pc) { - // At this point, the instrumentation stack has been updated. We need to install - // the real return pc on stack, in case instrumentation stub is stored there, - // so that the interpreter bridge code can return to the right place. JITed - // frames in Java debuggable runtimes may not have an instrumentation stub, so - // update the PC only when required. - uintptr_t* pc_addr = reinterpret_cast<uintptr_t*>(handler_quick_frame_); - CHECK(pc_addr != nullptr); - pc_addr--; - if (return_pc != 0 && - (*reinterpret_cast<uintptr_t*>(pc_addr)) == - reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc())) { - *reinterpret_cast<uintptr_t*>(pc_addr) = return_pc; - } - +void QuickExceptionHandler::DeoptimizePartialFragmentFixup() { + CHECK(handler_quick_frame_ != nullptr); // Architecture-dependent work. This is to get the LR right for x86 and x86-64. if (kRuntimeISA == InstructionSet::kX86 || kRuntimeISA == InstructionSet::kX86_64) { // On x86, the return address is on the stack, so just reuse it. Otherwise we would have to @@ -746,17 +729,6 @@ void QuickExceptionHandler::DeoptimizePartialFragmentFixup(uintptr_t return_pc) } } -uintptr_t QuickExceptionHandler::UpdateInstrumentationStack() { - DCHECK(is_deoptimization_) << "Non-deoptimization handlers should use FindCatch"; - uintptr_t return_pc = 0; - if (method_tracing_active_) { - instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); - return_pc = instrumentation->PopInstrumentationStackUntil( - self_, reinterpret_cast<uintptr_t>(handler_quick_frame_)); - } - return return_pc; -} - void QuickExceptionHandler::DoLongJump(bool smash_caller_saves) { // Place context back on thread so it will be available when we continue. self_->ReleaseLongJumpContext(context_); diff --git a/runtime/quick_exception_handler.h b/runtime/quick_exception_handler.h index 81c907ee0d..f3ce6241de 100644 --- a/runtime/quick_exception_handler.h +++ b/runtime/quick_exception_handler.h @@ -75,13 +75,7 @@ class QuickExceptionHandler { // on whether that single frame covers full or partial fragment. void DeoptimizeSingleFrame(DeoptimizationKind kind) REQUIRES_SHARED(Locks::mutator_lock_); - void DeoptimizePartialFragmentFixup(uintptr_t return_pc) - REQUIRES_SHARED(Locks::mutator_lock_); - - // Update the instrumentation stack by removing all methods that will be unwound - // by the exception being thrown. - // Return the return pc of the last frame that's unwound. - uintptr_t UpdateInstrumentationStack() REQUIRES_SHARED(Locks::mutator_lock_); + void DeoptimizePartialFragmentFixup() REQUIRES_SHARED(Locks::mutator_lock_); // Set up environment before delivering an exception to optimized code. void SetCatchEnvironmentForOptimizedHandler(StackVisitor* stack_visitor) @@ -157,8 +151,6 @@ class QuickExceptionHandler { Context* const context_; // Should we deoptimize the stack? const bool is_deoptimization_; - // Is method tracing active? - const bool method_tracing_active_; // Quick frame with found handler or last frame if no handler found. ArtMethod** handler_quick_frame_; // PC to branch to for the handler. diff --git a/runtime/stack.cc b/runtime/stack.cc index 7b70d4165f..d7d5851130 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -840,17 +840,15 @@ void StackVisitor::WalkStack(bool include_transitions) { cur_oat_quick_method_header_ = OatQuickMethodHeader::FromCodePointer(code); } else { // We are sure we are not running GenericJni here. Though the entry point could still be - // GenericJnistub. The entry point is usually JITed, AOT or instrumentation stub when - // instrumentation is enabled. It could be lso a resolution stub if the class isn't - // visibly initialized yet. + // GenericJnistub. The entry point is usually JITed or AOT code. It could be lso a + // resolution stub if the class isn't visibly initialized yet. const void* existing_entry_point = method->GetEntryPointFromQuickCompiledCode(); CHECK(existing_entry_point != nullptr); Runtime* runtime = Runtime::Current(); ClassLinker* class_linker = runtime->GetClassLinker(); // Check whether we can quickly get the header from the current entrypoint. if (!class_linker->IsQuickGenericJniStub(existing_entry_point) && - !class_linker->IsQuickResolutionStub(existing_entry_point) && - existing_entry_point != GetQuickInstrumentationEntryPoint()) { + !class_linker->IsQuickResolutionStub(existing_entry_point)) { cur_oat_quick_method_header_ = OatQuickMethodHeader::FromEntryPoint(existing_entry_point); } else { @@ -917,39 +915,8 @@ void StackVisitor::WalkStack(bool include_transitions) { // Compute PC for next stack frame from return PC. size_t frame_size = frame_info.FrameSizeInBytes(); uintptr_t return_pc_addr = GetReturnPcAddr(); - uintptr_t return_pc = *reinterpret_cast<uintptr_t*>(return_pc_addr); - - if (UNLIKELY(reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()) == return_pc)) { - // While profiling, the return pc is restored from the side stack, except when walking - // the stack for an exception where the side stack will be unwound in VisitFrame. - const std::map<uintptr_t, instrumentation::InstrumentationStackFrame>& - instrumentation_stack = *thread_->GetInstrumentationStack(); - auto it = instrumentation_stack.find(return_pc_addr); - CHECK(it != instrumentation_stack.end()); - const instrumentation::InstrumentationStackFrame& instrumentation_frame = it->second; - if (GetMethod() == - Runtime::Current()->GetCalleeSaveMethod(CalleeSaveType::kSaveAllCalleeSaves)) { - // Skip runtime save all callee frames which are used to deliver exceptions. - } else if (instrumentation_frame.interpreter_entry_) { - ArtMethod* callee = - Runtime::Current()->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsAndArgs); - CHECK_EQ(GetMethod(), callee) << "Expected: " << ArtMethod::PrettyMethod(callee) - << " Found: " << ArtMethod::PrettyMethod(GetMethod()); - } else if (!instrumentation_frame.method_->IsRuntimeMethod()) { - // Trampolines get replaced with their actual method in the stack, - // so don't do the check below for runtime methods. - // Instrumentation generally doesn't distinguish between a method's obsolete and - // non-obsolete version. - CHECK_EQ(instrumentation_frame.method_->GetNonObsoleteMethod(), - GetMethod()->GetNonObsoleteMethod()) - << "Expected: " - << ArtMethod::PrettyMethod(instrumentation_frame.method_->GetNonObsoleteMethod()) - << " Found: " << ArtMethod::PrettyMethod(GetMethod()->GetNonObsoleteMethod()); - } - return_pc = instrumentation_frame.return_pc_; - } - cur_quick_frame_pc_ = return_pc; + cur_quick_frame_pc_ = *reinterpret_cast<uintptr_t*>(return_pc_addr); uint8_t* next_frame = reinterpret_cast<uint8_t*>(cur_quick_frame_) + frame_size; cur_quick_frame_ = reinterpret_cast<ArtMethod**>(next_frame); diff --git a/runtime/thread.cc b/runtime/thread.cc index dc5cd3c513..78f9174886 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -2447,8 +2447,6 @@ Thread::Thread(bool daemon) wait_cond_ = new ConditionVariable("a thread wait condition variable", *wait_mutex_); tlsPtr_.mutator_lock = Locks::mutator_lock_; DCHECK(tlsPtr_.mutator_lock != nullptr); - tlsPtr_.instrumentation_stack = - new std::map<uintptr_t, instrumentation::InstrumentationStackFrame>; tlsPtr_.name.store(kThreadNameDuringStartup, std::memory_order_relaxed); static_assert((sizeof(Thread) % 4) == 0U, @@ -2635,7 +2633,6 @@ Thread::~Thread() { CleanupCpu(); } - delete tlsPtr_.instrumentation_stack; SetCachedThreadName(nullptr); // Deallocate name. delete tlsPtr_.deps_or_stack_trace_sample.stack_trace_sample; @@ -4434,9 +4431,6 @@ void Thread::VisitRoots(RootVisitor* visitor) { RootCallbackVisitor visitor_to_callback(visitor, thread_id); ReferenceMapVisitor<RootCallbackVisitor, kPrecise> mapper(this, &context, visitor_to_callback); mapper.template WalkStack<StackVisitor::CountTransitions::kNo>(false); - for (auto& entry : *GetInstrumentationStack()) { - visitor->VisitRootIfNonNull(&entry.second.this_object_, RootInfo(kRootVMInternal, thread_id)); - } } #pragma GCC diagnostic pop diff --git a/runtime/thread.h b/runtime/thread.h index 6c74dd9689..95d06cf6f6 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -1166,22 +1166,6 @@ class Thread { void RemoveDebuggerShadowFrameMapping(size_t frame_id) REQUIRES_SHARED(Locks::mutator_lock_); - // While getting this map requires shared the mutator lock, manipulating it - // should actually follow these rules: - // (1) The owner of this map (the thread) can change it with its mutator lock. - // (2) Other threads can read this map when the owner is suspended and they - // hold the mutator lock. - // (3) Other threads can change this map when owning the mutator lock exclusively. - // - // The reason why (3) needs the mutator lock exclusively (and not just having - // the owner suspended) is that we don't want other threads to concurrently read the map. - // - // TODO: Add a class abstraction to express these rules. - std::map<uintptr_t, instrumentation::InstrumentationStackFrame>* GetInstrumentationStack() - REQUIRES_SHARED(Locks::mutator_lock_) { - return tlsPtr_.instrumentation_stack; - } - std::vector<ArtMethod*>* GetStackTraceSample() const { DCHECK(!IsAotCompiler()); return tlsPtr_.deps_or_stack_trace_sample.stack_trace_sample; @@ -1936,19 +1920,18 @@ class Thread { top_handle_scope(nullptr), class_loader_override(nullptr), long_jump_context(nullptr), - instrumentation_stack(nullptr), stacked_shadow_frame_record(nullptr), deoptimization_context_stack(nullptr), frame_id_to_shadow_frame(nullptr), name(nullptr), pthread_self(0), last_no_thread_suspension_cause(nullptr), - checkpoint_function(nullptr), thread_local_start(nullptr), thread_local_pos(nullptr), thread_local_end(nullptr), thread_local_limit(nullptr), thread_local_objects(0), + checkpoint_function(nullptr), thread_local_alloc_stack_top(nullptr), thread_local_alloc_stack_end(nullptr), mutator_lock(nullptr), @@ -2031,14 +2014,6 @@ class Thread { // Thread local, lazily allocated, long jump context. Used to deliver exceptions. Context* long_jump_context; - // Additional stack used by method instrumentation to store method and return pc values. - // Stored as a pointer since std::map is not PACKED. - // !DO NOT CHANGE! to std::unordered_map: the users of this map require an - // ordered iteration on the keys (which are stack addresses). - // Also see Thread::GetInstrumentationStack for the requirements on - // manipulating and reading this map. - std::map<uintptr_t, instrumentation::InstrumentationStackFrame>* instrumentation_stack; - // For gc purpose, a shadow frame record stack that keeps track of: // 1) shadow frames under construction. // 2) deoptimization shadow frames. @@ -2064,10 +2039,6 @@ class Thread { // If no_thread_suspension_ is > 0, what is causing that assertion. const char* last_no_thread_suspension_cause; - // Pending checkpoint function or null if non-pending. If this checkpoint is set and someone\ - // requests another checkpoint, it goes to the checkpoint overflow list. - Closure* checkpoint_function GUARDED_BY(Locks::thread_suspend_count_lock_); - // Pending barriers that require passing or NULL if non-pending. Installation guarding by // Locks::thread_suspend_count_lock_. // They work effectively as art::Barrier, but implemented directly using AtomicInteger and futex @@ -2088,6 +2059,10 @@ class Thread { size_t thread_local_objects; + // Pending checkpoint function or null if non-pending. If this checkpoint is set and someone\ + // requests another checkpoint, it goes to the checkpoint overflow list. + Closure* checkpoint_function GUARDED_BY(Locks::thread_suspend_count_lock_); + // Entrypoint function pointers. // TODO: move this to more of a global offset table model to avoid per-thread duplication. JniEntryPoints jni_entrypoints; |