summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/utils/assembler_thumb_test_expected.cc.inc2
-rw-r--r--runtime/arch/arm/quick_entrypoints_arm.S73
-rw-r--r--runtime/arch/arm64/quick_entrypoints_arm64.S71
-rw-r--r--runtime/arch/x86/quick_entrypoints_x86.S109
-rw-r--r--runtime/arch/x86_64/quick_entrypoints_x86_64.S76
-rw-r--r--runtime/art_method.cc6
-rw-r--r--runtime/backtrace_helper.cc8
-rw-r--r--runtime/class_linker.cc5
-rw-r--r--runtime/entrypoints/entrypoint_utils.cc14
-rw-r--r--runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc3
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc96
-rw-r--r--runtime/entrypoints/runtime_asm_entrypoints.h12
-rw-r--r--runtime/entrypoints_order_test.cc13
-rw-r--r--runtime/instrumentation.cc174
-rw-r--r--runtime/instrumentation.h57
-rw-r--r--runtime/interpreter/interpreter_common.cc4
-rw-r--r--runtime/jit/jit_code_cache.cc16
-rw-r--r--runtime/quick_exception_handler.cc32
-rw-r--r--runtime/quick_exception_handler.h10
-rw-r--r--runtime/stack.cc41
-rw-r--r--runtime/thread.cc6
-rw-r--r--runtime/thread.h35
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;