From: Andreas Gampe Date: Tue, 26 Apr 2016 03:08:55 +0000 (-0700) Subject: ART: Log all monitor operations to systrace X-Git-Tag: android-x86-7.1-r1~45^2~109^2 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=fc6898769ae1ef91ec3e41c0a273401213cb82cd;p=android-x86%2Fart.git ART: Log all monitor operations to systrace Add a VLOG option ("-verbose:systrace-locks") to log all monitor operations to systrace. This requires non-fastpath thread entrypoints, and ATRACE tags for locking and unlocking. Do a bit of cleanup to the entrypoint initialization to share common setup. Bug: 28423466 Change-Id: Ie67e4aa946ec15f8fcf8cb7134c5d3cff0119ab3 --- diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h index c0a00cce7..4797540c3 100644 --- a/cmdline/cmdline_types.h +++ b/cmdline/cmdline_types.h @@ -620,6 +620,8 @@ struct CmdlineType : CmdlineTypeParser { log_verbosity.verifier = true; } else if (verbose_options[j] == "image") { log_verbosity.image = true; + } else if (verbose_options[j] == "systrace-locks") { + log_verbosity.systrace_lock_logging = true; } else { return Result::Usage(std::string("Unknown -verbose option ") + verbose_options[j]); } diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc index e358ff879..f0e9ac517 100644 --- a/runtime/arch/arm/entrypoints_init_arm.cc +++ b/runtime/arch/arm/entrypoints_init_arm.cc @@ -17,6 +17,7 @@ #include "entrypoints/jni/jni_entrypoints.h" #include "entrypoints/quick/quick_alloc_entrypoints.h" #include "entrypoints/quick/quick_default_externs.h" +#include "entrypoints/quick/quick_default_init_entrypoints.h" #include "entrypoints/quick/quick_entrypoints.h" #include "entrypoints/entrypoint_utils.h" #include "entrypoints/math_entrypoints.h" @@ -47,67 +48,12 @@ extern "C" int __aeabi_idivmod(int32_t, int32_t); // [DIV|REM]_INT[_2ADDR|_LIT8 extern "C" int64_t __aeabi_ldivmod(int64_t, int64_t); void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) { - // JNI - jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub; - - // Alloc - ResetQuickAllocEntryPoints(qpoints); + DefaultInitEntryPoints(jpoints, qpoints); // Cast qpoints->pInstanceofNonTrivial = artIsAssignableFromCode; qpoints->pCheckCast = art_quick_check_cast; - // DexCache - qpoints->pInitializeStaticStorage = art_quick_initialize_static_storage; - qpoints->pInitializeTypeAndVerifyAccess = art_quick_initialize_type_and_verify_access; - qpoints->pInitializeType = art_quick_initialize_type; - qpoints->pResolveString = art_quick_resolve_string; - - // Field - qpoints->pSet8Instance = art_quick_set8_instance; - qpoints->pSet8Static = art_quick_set8_static; - qpoints->pSet16Instance = art_quick_set16_instance; - qpoints->pSet16Static = art_quick_set16_static; - qpoints->pSet32Instance = art_quick_set32_instance; - qpoints->pSet32Static = art_quick_set32_static; - qpoints->pSet64Instance = art_quick_set64_instance; - qpoints->pSet64Static = art_quick_set64_static; - qpoints->pSetObjInstance = art_quick_set_obj_instance; - qpoints->pSetObjStatic = art_quick_set_obj_static; - qpoints->pGetByteInstance = art_quick_get_byte_instance; - qpoints->pGetBooleanInstance = art_quick_get_boolean_instance; - qpoints->pGetShortInstance = art_quick_get_short_instance; - qpoints->pGetCharInstance = art_quick_get_char_instance; - qpoints->pGet32Instance = art_quick_get32_instance; - qpoints->pGet64Instance = art_quick_get64_instance; - qpoints->pGetObjInstance = art_quick_get_obj_instance; - qpoints->pGetByteStatic = art_quick_get_byte_static; - qpoints->pGetBooleanStatic = art_quick_get_boolean_static; - qpoints->pGetShortStatic = art_quick_get_short_static; - qpoints->pGetCharStatic = art_quick_get_char_static; - qpoints->pGet32Static = art_quick_get32_static; - qpoints->pGet64Static = art_quick_get64_static; - qpoints->pGetObjStatic = art_quick_get_obj_static; - - // Array - qpoints->pAputObjectWithNullAndBoundCheck = art_quick_aput_obj_with_null_and_bound_check; - qpoints->pAputObjectWithBoundCheck = art_quick_aput_obj_with_bound_check; - qpoints->pAputObject = art_quick_aput_obj; - qpoints->pHandleFillArrayData = art_quick_handle_fill_data; - - // JNI - qpoints->pJniMethodStart = JniMethodStart; - qpoints->pJniMethodStartSynchronized = JniMethodStartSynchronized; - qpoints->pJniMethodEnd = JniMethodEnd; - qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized; - qpoints->pJniMethodEndWithReference = JniMethodEndWithReference; - qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized; - qpoints->pQuickGenericJniTrampoline = art_quick_generic_jni_trampoline; - - // Locks - qpoints->pLockObject = art_quick_lock_object; - qpoints->pUnlockObject = art_quick_unlock_object; - // Math qpoints->pIdivmod = __aeabi_idivmod; qpoints->pLdiv = __aeabi_ldivmod; @@ -154,35 +100,6 @@ void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) { qpoints->pStringCompareTo = art_quick_string_compareto; qpoints->pMemcpy = memcpy; - // Invocation - qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline; - qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline; - qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge; - qpoints->pInvokeDirectTrampolineWithAccessCheck = - art_quick_invoke_direct_trampoline_with_access_check; - qpoints->pInvokeInterfaceTrampolineWithAccessCheck = - art_quick_invoke_interface_trampoline_with_access_check; - qpoints->pInvokeStaticTrampolineWithAccessCheck = - art_quick_invoke_static_trampoline_with_access_check; - qpoints->pInvokeSuperTrampolineWithAccessCheck = - art_quick_invoke_super_trampoline_with_access_check; - qpoints->pInvokeVirtualTrampolineWithAccessCheck = - art_quick_invoke_virtual_trampoline_with_access_check; - - // Thread - qpoints->pTestSuspend = art_quick_test_suspend; - - // Throws - qpoints->pDeliverException = art_quick_deliver_exception; - qpoints->pThrowArrayBounds = art_quick_throw_array_bounds; - qpoints->pThrowDivZero = art_quick_throw_div_zero; - qpoints->pThrowNoSuchMethod = art_quick_throw_no_such_method; - qpoints->pThrowNullPointer = art_quick_throw_null_pointer_exception; - qpoints->pThrowStackOverflow = art_quick_throw_stack_overflow; - - // Deoptimization from compiled code. - qpoints->pDeoptimize = art_quick_deoptimize_from_compiled_code; - // Read barrier. qpoints->pReadBarrierJni = ReadBarrierJni; qpoints->pReadBarrierMark = artReadBarrierMark; diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S index da7db1dbb..10b8747a7 100644 --- a/runtime/arch/arm/quick_entrypoints_arm.S +++ b/runtime/arch/arm/quick_entrypoints_arm.S @@ -544,6 +544,15 @@ ENTRY art_quick_lock_object DELIVER_PENDING_EXCEPTION END art_quick_lock_object +ENTRY art_quick_lock_object_no_inline + SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2 @ save callee saves in case we block + mov r1, r9 @ pass Thread::Current + bl artLockObjectFromCode @ (Object* obj, Thread*) + RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME + RETURN_IF_RESULT_IS_ZERO + DELIVER_PENDING_EXCEPTION +END art_quick_lock_object_no_inline + /* * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure. * r0 holds the possibly null object to lock. @@ -601,6 +610,16 @@ ENTRY art_quick_unlock_object DELIVER_PENDING_EXCEPTION END art_quick_unlock_object +ENTRY art_quick_unlock_object_no_inline + @ save callee saves in case exception allocation triggers GC + SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2 + mov r1, r9 @ pass Thread::Current + bl artUnlockObjectFromCode @ (Object* obj, Thread*) + RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME + RETURN_IF_RESULT_IS_ZERO + DELIVER_PENDING_EXCEPTION +END art_quick_unlock_object_no_inline + /* * Entry from managed code that calls artIsAssignableFromCode and on failure calls * artThrowClassCastException. diff --git a/runtime/arch/arm64/entrypoints_init_arm64.cc b/runtime/arch/arm64/entrypoints_init_arm64.cc index 4db941174..1618cedef 100644 --- a/runtime/arch/arm64/entrypoints_init_arm64.cc +++ b/runtime/arch/arm64/entrypoints_init_arm64.cc @@ -17,6 +17,7 @@ #include "entrypoints/jni/jni_entrypoints.h" #include "entrypoints/quick/quick_alloc_entrypoints.h" #include "entrypoints/quick/quick_default_externs.h" +#include "entrypoints/quick/quick_default_init_entrypoints.h" #include "entrypoints/quick/quick_entrypoints.h" #include "entrypoints/entrypoint_utils.h" #include "entrypoints/math_entrypoints.h" @@ -30,67 +31,12 @@ extern "C" uint32_t artIsAssignableFromCode(const mirror::Class* klass, const mirror::Class* ref_class); void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) { - // JNI - jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub; - - // Alloc - ResetQuickAllocEntryPoints(qpoints); + DefaultInitEntryPoints(jpoints, qpoints); // Cast qpoints->pInstanceofNonTrivial = artIsAssignableFromCode; qpoints->pCheckCast = art_quick_check_cast; - // DexCache - qpoints->pInitializeStaticStorage = art_quick_initialize_static_storage; - qpoints->pInitializeTypeAndVerifyAccess = art_quick_initialize_type_and_verify_access; - qpoints->pInitializeType = art_quick_initialize_type; - qpoints->pResolveString = art_quick_resolve_string; - - // Field - qpoints->pSet8Instance = art_quick_set8_instance; - qpoints->pSet8Static = art_quick_set8_static; - qpoints->pSet16Instance = art_quick_set16_instance; - qpoints->pSet16Static = art_quick_set16_static; - qpoints->pSet32Instance = art_quick_set32_instance; - qpoints->pSet32Static = art_quick_set32_static; - qpoints->pSet64Instance = art_quick_set64_instance; - qpoints->pSet64Static = art_quick_set64_static; - qpoints->pSetObjInstance = art_quick_set_obj_instance; - qpoints->pSetObjStatic = art_quick_set_obj_static; - qpoints->pGetBooleanInstance = art_quick_get_boolean_instance; - qpoints->pGetByteInstance = art_quick_get_byte_instance; - qpoints->pGetCharInstance = art_quick_get_char_instance; - qpoints->pGetShortInstance = art_quick_get_short_instance; - qpoints->pGet32Instance = art_quick_get32_instance; - qpoints->pGet64Instance = art_quick_get64_instance; - qpoints->pGetObjInstance = art_quick_get_obj_instance; - qpoints->pGetBooleanStatic = art_quick_get_boolean_static; - qpoints->pGetByteStatic = art_quick_get_byte_static; - qpoints->pGetCharStatic = art_quick_get_char_static; - qpoints->pGetShortStatic = art_quick_get_short_static; - qpoints->pGet32Static = art_quick_get32_static; - qpoints->pGet64Static = art_quick_get64_static; - qpoints->pGetObjStatic = art_quick_get_obj_static; - - // Array - qpoints->pAputObjectWithNullAndBoundCheck = art_quick_aput_obj_with_null_and_bound_check; - qpoints->pAputObjectWithBoundCheck = art_quick_aput_obj_with_bound_check; - qpoints->pAputObject = art_quick_aput_obj; - qpoints->pHandleFillArrayData = art_quick_handle_fill_data; - - // JNI - qpoints->pJniMethodStart = JniMethodStart; - qpoints->pJniMethodStartSynchronized = JniMethodStartSynchronized; - qpoints->pJniMethodEnd = JniMethodEnd; - qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized; - qpoints->pJniMethodEndWithReference = JniMethodEndWithReference; - qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized; - qpoints->pQuickGenericJniTrampoline = art_quick_generic_jni_trampoline; - - // Locks - qpoints->pLockObject = art_quick_lock_object; - qpoints->pUnlockObject = art_quick_unlock_object; - // Math // TODO null entrypoints not needed for ARM64 - generate inline. qpoints->pCmpgDouble = nullptr; @@ -137,35 +83,6 @@ void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) { qpoints->pStringCompareTo = art_quick_string_compareto; qpoints->pMemcpy = memcpy; - // Invocation - qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline; - qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline; - qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge; - qpoints->pInvokeDirectTrampolineWithAccessCheck = - art_quick_invoke_direct_trampoline_with_access_check; - qpoints->pInvokeInterfaceTrampolineWithAccessCheck = - art_quick_invoke_interface_trampoline_with_access_check; - qpoints->pInvokeStaticTrampolineWithAccessCheck = - art_quick_invoke_static_trampoline_with_access_check; - qpoints->pInvokeSuperTrampolineWithAccessCheck = - art_quick_invoke_super_trampoline_with_access_check; - qpoints->pInvokeVirtualTrampolineWithAccessCheck = - art_quick_invoke_virtual_trampoline_with_access_check; - - // Thread - qpoints->pTestSuspend = art_quick_test_suspend; - - // Throws - qpoints->pDeliverException = art_quick_deliver_exception; - qpoints->pThrowArrayBounds = art_quick_throw_array_bounds; - qpoints->pThrowDivZero = art_quick_throw_div_zero; - qpoints->pThrowNoSuchMethod = art_quick_throw_no_such_method; - qpoints->pThrowNullPointer = art_quick_throw_null_pointer_exception; - qpoints->pThrowStackOverflow = art_quick_throw_stack_overflow; - - // Deoptimization from compiled code. - qpoints->pDeoptimize = art_quick_deoptimize_from_compiled_code; - // Read barrier. qpoints->pReadBarrierJni = ReadBarrierJni; qpoints->pReadBarrierMark = artReadBarrierMark; diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S index 1cdda2d19..7774106da 100644 --- a/runtime/arch/arm64/quick_entrypoints_arm64.S +++ b/runtime/arch/arm64/quick_entrypoints_arm64.S @@ -1113,6 +1113,14 @@ ENTRY art_quick_lock_object RETURN_IF_W0_IS_ZERO_OR_DELIVER END art_quick_lock_object +ENTRY art_quick_lock_object_no_inline + SETUP_REFS_ONLY_CALLEE_SAVE_FRAME // save callee saves in case we block + mov x1, xSELF // pass Thread::Current + bl artLockObjectFromCode // (Object* obj, Thread*) + RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME + RETURN_IF_W0_IS_ZERO_OR_DELIVER +END art_quick_lock_object_no_inline + /* * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure. * x0 holds the possibly null object to lock. @@ -1171,6 +1179,14 @@ ENTRY art_quick_unlock_object RETURN_IF_W0_IS_ZERO_OR_DELIVER END art_quick_unlock_object +ENTRY art_quick_unlock_object_no_inline + SETUP_REFS_ONLY_CALLEE_SAVE_FRAME // save callee saves in case exception allocation triggers GC + mov x1, xSELF // pass Thread::Current + bl artUnlockObjectFromCode // (Object* obj, Thread*) + RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME + RETURN_IF_W0_IS_ZERO_OR_DELIVER +END art_quick_unlock_object_no_inline + /* * Entry from managed code that calls artIsAssignableFromCode and on failure calls * artThrowClassCastException. diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc index 51eb77f40..45e33a850 100644 --- a/runtime/arch/mips/entrypoints_init_mips.cc +++ b/runtime/arch/mips/entrypoints_init_mips.cc @@ -59,6 +59,9 @@ extern "C" int64_t __divdi3(int64_t, int64_t); extern "C" int64_t __moddi3(int64_t, int64_t); void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) { + // Note: MIPS has asserts checking for the type of entrypoint. Don't move it + // to InitDefaultEntryPoints(). + // JNI jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub; @@ -167,9 +170,14 @@ void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) { "Non-direct C stub marked direct."); // Locks - qpoints->pLockObject = art_quick_lock_object; + if (UNLIKELY(VLOG_IS_ON(systrace_lock_logging))) { + qpoints->pLockObject = art_quick_lock_object_no_inline; + qpoints->pUnlockObject = art_quick_unlock_object_no_inline; + } else { + qpoints->pLockObject = art_quick_lock_object; + qpoints->pUnlockObject = art_quick_unlock_object; + } static_assert(!IsDirectEntrypoint(kQuickLockObject), "Non-direct C stub marked direct."); - qpoints->pUnlockObject = art_quick_unlock_object; static_assert(!IsDirectEntrypoint(kQuickUnlockObject), "Non-direct C stub marked direct."); // Math diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S index 8939a488e..3ee26afc4 100644 --- a/runtime/arch/mips/quick_entrypoints_mips.S +++ b/runtime/arch/mips/quick_entrypoints_mips.S @@ -906,6 +906,16 @@ ENTRY art_quick_lock_object RETURN_IF_ZERO END art_quick_lock_object +ENTRY art_quick_lock_object_no_inline + beqz $a0, .Lart_quick_throw_null_pointer_exception_gp_set + nop + SETUP_REFS_ONLY_CALLEE_SAVE_FRAME # save callee saves in case we block + la $t9, artLockObjectFromCode + jalr $t9 # (Object* obj, Thread*) + move $a1, rSELF # pass Thread::Current + RETURN_IF_ZERO +END art_quick_lock_object_no_inline + /* * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure. */ @@ -920,6 +930,16 @@ ENTRY art_quick_unlock_object RETURN_IF_ZERO END art_quick_unlock_object +ENTRY art_quick_unlock_object_no_inline + beqz $a0, .Lart_quick_throw_null_pointer_exception_gp_set + nop + SETUP_REFS_ONLY_CALLEE_SAVE_FRAME # save callee saves in case exception allocation triggers GC + la $t9, artUnlockObjectFromCode + jalr $t9 # (Object* obj, Thread*) + move $a1, rSELF # pass Thread::Current + RETURN_IF_ZERO +END art_quick_unlock_object_no_inline + /* * Entry from managed code that calls artCheckCastFromCode and delivers exception on failure. */ diff --git a/runtime/arch/mips64/entrypoints_init_mips64.cc b/runtime/arch/mips64/entrypoints_init_mips64.cc index 4bdb38e51..030c12707 100644 --- a/runtime/arch/mips64/entrypoints_init_mips64.cc +++ b/runtime/arch/mips64/entrypoints_init_mips64.cc @@ -18,6 +18,7 @@ #include "entrypoints/jni/jni_entrypoints.h" #include "entrypoints/quick/quick_alloc_entrypoints.h" #include "entrypoints/quick/quick_default_externs.h" +#include "entrypoints/quick/quick_default_init_entrypoints.h" #include "entrypoints/quick/quick_entrypoints.h" #include "entrypoints/entrypoint_utils.h" #include "entrypoints/math_entrypoints.h" @@ -57,67 +58,12 @@ extern "C" int64_t __divdi3(int64_t, int64_t); extern "C" int64_t __moddi3(int64_t, int64_t); void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) { - // JNI - jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub; - - // Alloc - ResetQuickAllocEntryPoints(qpoints); + DefaultInitEntryPoints(jpoints, qpoints); // Cast qpoints->pInstanceofNonTrivial = artIsAssignableFromCode; qpoints->pCheckCast = art_quick_check_cast; - // DexCache - qpoints->pInitializeStaticStorage = art_quick_initialize_static_storage; - qpoints->pInitializeTypeAndVerifyAccess = art_quick_initialize_type_and_verify_access; - qpoints->pInitializeType = art_quick_initialize_type; - qpoints->pResolveString = art_quick_resolve_string; - - // Field - qpoints->pSet8Instance = art_quick_set8_instance; - qpoints->pSet8Static = art_quick_set8_static; - qpoints->pSet16Instance = art_quick_set16_instance; - qpoints->pSet16Static = art_quick_set16_static; - qpoints->pSet32Instance = art_quick_set32_instance; - qpoints->pSet32Static = art_quick_set32_static; - qpoints->pSet64Instance = art_quick_set64_instance; - qpoints->pSet64Static = art_quick_set64_static; - qpoints->pSetObjInstance = art_quick_set_obj_instance; - qpoints->pSetObjStatic = art_quick_set_obj_static; - qpoints->pGetBooleanInstance = art_quick_get_boolean_instance; - qpoints->pGetByteInstance = art_quick_get_byte_instance; - qpoints->pGetCharInstance = art_quick_get_char_instance; - qpoints->pGetShortInstance = art_quick_get_short_instance; - qpoints->pGet32Instance = art_quick_get32_instance; - qpoints->pGet64Instance = art_quick_get64_instance; - qpoints->pGetObjInstance = art_quick_get_obj_instance; - qpoints->pGetBooleanStatic = art_quick_get_boolean_static; - qpoints->pGetByteStatic = art_quick_get_byte_static; - qpoints->pGetCharStatic = art_quick_get_char_static; - qpoints->pGetShortStatic = art_quick_get_short_static; - qpoints->pGet32Static = art_quick_get32_static; - qpoints->pGet64Static = art_quick_get64_static; - qpoints->pGetObjStatic = art_quick_get_obj_static; - - // Array - qpoints->pAputObjectWithNullAndBoundCheck = art_quick_aput_obj_with_null_and_bound_check; - qpoints->pAputObjectWithBoundCheck = art_quick_aput_obj_with_bound_check; - qpoints->pAputObject = art_quick_aput_obj; - qpoints->pHandleFillArrayData = art_quick_handle_fill_data; - - // JNI - qpoints->pJniMethodStart = JniMethodStart; - qpoints->pJniMethodStartSynchronized = JniMethodStartSynchronized; - qpoints->pJniMethodEnd = JniMethodEnd; - qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized; - qpoints->pJniMethodEndWithReference = JniMethodEndWithReference; - qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized; - qpoints->pQuickGenericJniTrampoline = art_quick_generic_jni_trampoline; - - // Locks - qpoints->pLockObject = art_quick_lock_object; - qpoints->pUnlockObject = art_quick_unlock_object; - // Math qpoints->pCmpgDouble = CmpgDouble; qpoints->pCmpgFloat = CmpgFloat; @@ -144,35 +90,6 @@ void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) { qpoints->pStringCompareTo = art_quick_string_compareto; qpoints->pMemcpy = memcpy; - // Invocation - qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline; - qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline; - qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge; - qpoints->pInvokeDirectTrampolineWithAccessCheck = - art_quick_invoke_direct_trampoline_with_access_check; - qpoints->pInvokeInterfaceTrampolineWithAccessCheck = - art_quick_invoke_interface_trampoline_with_access_check; - qpoints->pInvokeStaticTrampolineWithAccessCheck = - art_quick_invoke_static_trampoline_with_access_check; - qpoints->pInvokeSuperTrampolineWithAccessCheck = - art_quick_invoke_super_trampoline_with_access_check; - qpoints->pInvokeVirtualTrampolineWithAccessCheck = - art_quick_invoke_virtual_trampoline_with_access_check; - - // Thread - qpoints->pTestSuspend = art_quick_test_suspend; - - // Throws - qpoints->pDeliverException = art_quick_deliver_exception; - qpoints->pThrowArrayBounds = art_quick_throw_array_bounds; - qpoints->pThrowDivZero = art_quick_throw_div_zero; - qpoints->pThrowNoSuchMethod = art_quick_throw_no_such_method; - qpoints->pThrowNullPointer = art_quick_throw_null_pointer_exception; - qpoints->pThrowStackOverflow = art_quick_throw_stack_overflow; - - // Deoptimization from compiled code. - qpoints->pDeoptimize = art_quick_deoptimize_from_compiled_code; - // TODO - use lld/scd instructions for Mips64 // Atomic 64-bit load/store qpoints->pA64Load = QuasiAtomic::Read64; diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S index 5d0c94c63..8f1a35a69 100644 --- a/runtime/arch/mips64/quick_entrypoints_mips64.S +++ b/runtime/arch/mips64/quick_entrypoints_mips64.S @@ -971,6 +971,15 @@ ENTRY art_quick_lock_object RETURN_IF_ZERO END art_quick_lock_object +ENTRY art_quick_lock_object_no_inline + beq $a0, $zero, .Lart_quick_throw_null_pointer_exception_gp_set + nop + SETUP_REFS_ONLY_CALLEE_SAVE_FRAME # save callee saves in case we block + jal artLockObjectFromCode # (Object* obj, Thread*) + move $a1, rSELF # pass Thread::Current + RETURN_IF_ZERO +END art_quick_lock_object_no_inline + /* * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure. */ @@ -984,6 +993,15 @@ ENTRY art_quick_unlock_object RETURN_IF_ZERO END art_quick_unlock_object +ENTRY art_quick_unlock_object_no_inline + beq $a0, $zero, .Lart_quick_throw_null_pointer_exception_gp_set + nop + SETUP_REFS_ONLY_CALLEE_SAVE_FRAME # save callee saves in case exception allocation triggers GC + jal artUnlockObjectFromCode # (Object* obj, Thread*) + move $a1, rSELF # pass Thread::Current + RETURN_IF_ZERO +END art_quick_unlock_object_no_inline + /* * Entry from managed code that calls artCheckCastFromCode and delivers exception on failure. */ diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc index e593f39fd..15a857146 100644 --- a/runtime/arch/x86/entrypoints_init_x86.cc +++ b/runtime/arch/x86/entrypoints_init_x86.cc @@ -17,6 +17,7 @@ #include "entrypoints/jni/jni_entrypoints.h" #include "entrypoints/quick/quick_alloc_entrypoints.h" #include "entrypoints/quick/quick_default_externs.h" +#include "entrypoints/quick/quick_default_init_entrypoints.h" #include "entrypoints/quick/quick_entrypoints.h" #include "entrypoints/runtime_asm_entrypoints.h" #include "interpreter/interpreter.h" @@ -33,67 +34,12 @@ extern "C" mirror::Object* art_quick_read_barrier_slow(mirror::Object*, mirror:: extern "C" mirror::Object* art_quick_read_barrier_for_root_slow(GcRoot*); void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) { - // JNI - jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub; - - // Alloc - ResetQuickAllocEntryPoints(qpoints); + DefaultInitEntryPoints(jpoints, qpoints); // Cast qpoints->pInstanceofNonTrivial = art_quick_is_assignable; qpoints->pCheckCast = art_quick_check_cast; - // DexCache - qpoints->pInitializeStaticStorage = art_quick_initialize_static_storage; - qpoints->pInitializeTypeAndVerifyAccess = art_quick_initialize_type_and_verify_access; - qpoints->pInitializeType = art_quick_initialize_type; - qpoints->pResolveString = art_quick_resolve_string; - - // Field - qpoints->pSet8Instance = art_quick_set8_instance; - qpoints->pSet8Static = art_quick_set8_static; - qpoints->pSet16Instance = art_quick_set16_instance; - qpoints->pSet16Static = art_quick_set16_static; - qpoints->pSet32Instance = art_quick_set32_instance; - qpoints->pSet32Static = art_quick_set32_static; - qpoints->pSet64Instance = art_quick_set64_instance; - qpoints->pSet64Static = art_quick_set64_static; - qpoints->pSetObjInstance = art_quick_set_obj_instance; - qpoints->pSetObjStatic = art_quick_set_obj_static; - qpoints->pGetByteInstance = art_quick_get_byte_instance; - qpoints->pGetBooleanInstance = art_quick_get_boolean_instance; - qpoints->pGetShortInstance = art_quick_get_short_instance; - qpoints->pGetCharInstance = art_quick_get_char_instance; - qpoints->pGet32Instance = art_quick_get32_instance; - qpoints->pGet64Instance = art_quick_get64_instance; - qpoints->pGetObjInstance = art_quick_get_obj_instance; - qpoints->pGetByteStatic = art_quick_get_byte_static; - qpoints->pGetBooleanStatic = art_quick_get_boolean_static; - qpoints->pGetShortStatic = art_quick_get_short_static; - qpoints->pGetCharStatic = art_quick_get_char_static; - qpoints->pGet32Static = art_quick_get32_static; - qpoints->pGet64Static = art_quick_get64_static; - qpoints->pGetObjStatic = art_quick_get_obj_static; - - // Array - qpoints->pAputObjectWithNullAndBoundCheck = art_quick_aput_obj_with_null_and_bound_check; - qpoints->pAputObjectWithBoundCheck = art_quick_aput_obj_with_bound_check; - qpoints->pAputObject = art_quick_aput_obj; - qpoints->pHandleFillArrayData = art_quick_handle_fill_data; - - // JNI - qpoints->pJniMethodStart = JniMethodStart; - qpoints->pJniMethodStartSynchronized = JniMethodStartSynchronized; - qpoints->pJniMethodEnd = JniMethodEnd; - qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized; - qpoints->pJniMethodEndWithReference = JniMethodEndWithReference; - qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized; - qpoints->pQuickGenericJniTrampoline = art_quick_generic_jni_trampoline; - - // Locks - qpoints->pLockObject = art_quick_lock_object; - qpoints->pUnlockObject = art_quick_unlock_object; - // More math. qpoints->pCos = cos; qpoints->pSin = sin; @@ -128,35 +74,6 @@ void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) { qpoints->pStringCompareTo = art_quick_string_compareto; qpoints->pMemcpy = art_quick_memcpy; - // Invocation - qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline; - qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline; - qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge; - qpoints->pInvokeDirectTrampolineWithAccessCheck = - art_quick_invoke_direct_trampoline_with_access_check; - qpoints->pInvokeInterfaceTrampolineWithAccessCheck = - art_quick_invoke_interface_trampoline_with_access_check; - qpoints->pInvokeStaticTrampolineWithAccessCheck = - art_quick_invoke_static_trampoline_with_access_check; - qpoints->pInvokeSuperTrampolineWithAccessCheck = - art_quick_invoke_super_trampoline_with_access_check; - qpoints->pInvokeVirtualTrampolineWithAccessCheck = - art_quick_invoke_virtual_trampoline_with_access_check; - - // Thread - qpoints->pTestSuspend = art_quick_test_suspend; - - // Throws - qpoints->pDeliverException = art_quick_deliver_exception; - qpoints->pThrowArrayBounds = art_quick_throw_array_bounds; - qpoints->pThrowDivZero = art_quick_throw_div_zero; - qpoints->pThrowNoSuchMethod = art_quick_throw_no_such_method; - qpoints->pThrowNullPointer = art_quick_throw_null_pointer_exception; - qpoints->pThrowStackOverflow = art_quick_throw_stack_overflow; - - // Deoptimize - qpoints->pDeoptimize = art_quick_deoptimize_from_compiled_code; - // Read barrier. qpoints->pReadBarrierJni = ReadBarrierJni; qpoints->pReadBarrierMark = art_quick_read_barrier_mark; diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S index 551ec6880..229601b1d 100644 --- a/runtime/arch/x86/quick_entrypoints_x86.S +++ b/runtime/arch/x86/quick_entrypoints_x86.S @@ -960,6 +960,22 @@ DEFINE_FUNCTION art_quick_lock_object RETURN_IF_EAX_ZERO END_FUNCTION art_quick_lock_object +DEFINE_FUNCTION art_quick_lock_object_no_inline + SETUP_REFS_ONLY_CALLEE_SAVE_FRAME ebx, ebx // save ref containing registers for GC + // Outgoing argument set up + subl LITERAL(8), %esp // alignment padding + CFI_ADJUST_CFA_OFFSET(8) + pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current() + CFI_ADJUST_CFA_OFFSET(4) + PUSH eax // pass object + call SYMBOL(artLockObjectFromCode) // artLockObjectFromCode(object, Thread*) + addl LITERAL(16), %esp // pop arguments + CFI_ADJUST_CFA_OFFSET(-16) + RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address + RETURN_IF_EAX_ZERO +END_FUNCTION art_quick_lock_object_no_inline + + DEFINE_FUNCTION art_quick_unlock_object testl %eax, %eax // null check object/eax jz .Lslow_unlock @@ -1015,6 +1031,21 @@ DEFINE_FUNCTION art_quick_unlock_object RETURN_IF_EAX_ZERO END_FUNCTION art_quick_unlock_object +DEFINE_FUNCTION art_quick_unlock_object_no_inline + SETUP_REFS_ONLY_CALLEE_SAVE_FRAME ebx, ebx // save ref containing registers for GC + // Outgoing argument set up + subl LITERAL(8), %esp // alignment padding + CFI_ADJUST_CFA_OFFSET(8) + pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current() + CFI_ADJUST_CFA_OFFSET(4) + PUSH eax // pass object + call SYMBOL(artUnlockObjectFromCode) // artUnlockObjectFromCode(object, Thread*) + addl LITERAL(16), %esp // pop arguments + CFI_ADJUST_CFA_OFFSET(-16) + RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address + RETURN_IF_EAX_ZERO +END_FUNCTION art_quick_unlock_object_no_inline + DEFINE_FUNCTION art_quick_is_assignable PUSH eax // alignment padding PUSH ecx // pass arg2 - obj->klass diff --git a/runtime/arch/x86_64/entrypoints_init_x86_64.cc b/runtime/arch/x86_64/entrypoints_init_x86_64.cc index 0a5d14a16..2f7f5aaa4 100644 --- a/runtime/arch/x86_64/entrypoints_init_x86_64.cc +++ b/runtime/arch/x86_64/entrypoints_init_x86_64.cc @@ -17,6 +17,7 @@ #include "entrypoints/jni/jni_entrypoints.h" #include "entrypoints/quick/quick_alloc_entrypoints.h" #include "entrypoints/quick/quick_default_externs.h" +#include "entrypoints/quick/quick_default_init_entrypoints.h" #include "entrypoints/quick/quick_entrypoints.h" #include "entrypoints/math_entrypoints.h" #include "entrypoints/runtime_asm_entrypoints.h" @@ -38,67 +39,12 @@ void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) { UNUSED(jpoints, qpoints); UNIMPLEMENTED(FATAL); #else - // JNI - jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub; - - // Alloc - ResetQuickAllocEntryPoints(qpoints); + DefaultInitEntryPoints(jpoints, qpoints); // Cast qpoints->pInstanceofNonTrivial = art_quick_assignable_from_code; qpoints->pCheckCast = art_quick_check_cast; - // DexCache - qpoints->pInitializeStaticStorage = art_quick_initialize_static_storage; - qpoints->pInitializeTypeAndVerifyAccess = art_quick_initialize_type_and_verify_access; - qpoints->pInitializeType = art_quick_initialize_type; - qpoints->pResolveString = art_quick_resolve_string; - - // Field - qpoints->pSet8Instance = art_quick_set8_instance; - qpoints->pSet8Static = art_quick_set8_static; - qpoints->pSet16Instance = art_quick_set16_instance; - qpoints->pSet16Static = art_quick_set16_static; - qpoints->pSet32Instance = art_quick_set32_instance; - qpoints->pSet32Static = art_quick_set32_static; - qpoints->pSet64Instance = art_quick_set64_instance; - qpoints->pSet64Static = art_quick_set64_static; - qpoints->pSetObjInstance = art_quick_set_obj_instance; - qpoints->pSetObjStatic = art_quick_set_obj_static; - qpoints->pGetByteInstance = art_quick_get_byte_instance; - qpoints->pGetBooleanInstance = art_quick_get_boolean_instance; - qpoints->pGetShortInstance = art_quick_get_short_instance; - qpoints->pGetCharInstance = art_quick_get_char_instance; - qpoints->pGet32Instance = art_quick_get32_instance; - qpoints->pGet64Instance = art_quick_get64_instance; - qpoints->pGetObjInstance = art_quick_get_obj_instance; - qpoints->pGetByteStatic = art_quick_get_byte_static; - qpoints->pGetBooleanStatic = art_quick_get_boolean_static; - qpoints->pGetShortStatic = art_quick_get_short_static; - qpoints->pGetCharStatic = art_quick_get_char_static; - qpoints->pGet32Static = art_quick_get32_static; - qpoints->pGet64Static = art_quick_get64_static; - qpoints->pGetObjStatic = art_quick_get_obj_static; - - // Array - qpoints->pAputObjectWithNullAndBoundCheck = art_quick_aput_obj_with_null_and_bound_check; - qpoints->pAputObjectWithBoundCheck = art_quick_aput_obj_with_bound_check; - qpoints->pAputObject = art_quick_aput_obj; - qpoints->pHandleFillArrayData = art_quick_handle_fill_data; - - // JNI - qpoints->pJniMethodStart = JniMethodStart; - qpoints->pJniMethodStartSynchronized = JniMethodStartSynchronized; - qpoints->pJniMethodEnd = JniMethodEnd; - qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized; - qpoints->pJniMethodEndWithReference = JniMethodEndWithReference; - qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized; - qpoints->pQuickGenericJniTrampoline = art_quick_generic_jni_trampoline; - - // Locks - qpoints->pLockObject = art_quick_lock_object; - qpoints->pUnlockObject = art_quick_unlock_object; - // More math. qpoints->pCos = cos; qpoints->pSin = sin; @@ -132,35 +78,6 @@ void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) { qpoints->pStringCompareTo = art_quick_string_compareto; qpoints->pMemcpy = art_quick_memcpy; - // Invocation - qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline; - qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline; - qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge; - qpoints->pInvokeDirectTrampolineWithAccessCheck = - art_quick_invoke_direct_trampoline_with_access_check; - qpoints->pInvokeInterfaceTrampolineWithAccessCheck = - art_quick_invoke_interface_trampoline_with_access_check; - qpoints->pInvokeStaticTrampolineWithAccessCheck = - art_quick_invoke_static_trampoline_with_access_check; - qpoints->pInvokeSuperTrampolineWithAccessCheck = - art_quick_invoke_super_trampoline_with_access_check; - qpoints->pInvokeVirtualTrampolineWithAccessCheck = - art_quick_invoke_virtual_trampoline_with_access_check; - - // Thread - qpoints->pTestSuspend = art_quick_test_suspend; - - // Throws - qpoints->pDeliverException = art_quick_deliver_exception; - qpoints->pThrowArrayBounds = art_quick_throw_array_bounds; - qpoints->pThrowDivZero = art_quick_throw_div_zero; - qpoints->pThrowNoSuchMethod = art_quick_throw_no_such_method; - qpoints->pThrowNullPointer = art_quick_throw_null_pointer_exception; - qpoints->pThrowStackOverflow = art_quick_throw_stack_overflow; - - // Deoptimize - qpoints->pDeoptimize = art_quick_deoptimize_from_compiled_code; - // Read barrier. qpoints->pReadBarrierJni = ReadBarrierJni; qpoints->pReadBarrierMark = art_quick_read_barrier_mark; diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S index 26e668e7a..562ee2d81 100644 --- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S +++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S @@ -994,6 +994,14 @@ DEFINE_FUNCTION art_quick_lock_object RETURN_IF_EAX_ZERO END_FUNCTION art_quick_lock_object +DEFINE_FUNCTION art_quick_lock_object_no_inline + SETUP_REFS_ONLY_CALLEE_SAVE_FRAME + movq %gs:THREAD_SELF_OFFSET, %rsi // pass Thread::Current() + call SYMBOL(artLockObjectFromCode) // artLockObjectFromCode(object, Thread*) + RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address + RETURN_IF_EAX_ZERO +END_FUNCTION art_quick_lock_object_no_inline + DEFINE_FUNCTION art_quick_unlock_object testl %edi, %edi // null check object/edi jz .Lslow_unlock @@ -1037,6 +1045,14 @@ DEFINE_FUNCTION art_quick_unlock_object RETURN_IF_EAX_ZERO END_FUNCTION art_quick_unlock_object +DEFINE_FUNCTION art_quick_unlock_object_no_inline + SETUP_REFS_ONLY_CALLEE_SAVE_FRAME + movq %gs:THREAD_SELF_OFFSET, %rsi // pass Thread::Current() + call SYMBOL(artUnlockObjectFromCode) // artUnlockObjectFromCode(object, Thread*) + RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address + RETURN_IF_EAX_ZERO +END_FUNCTION art_quick_unlock_object_no_inline + DEFINE_FUNCTION art_quick_check_cast PUSH rdi // Save args for exc PUSH rsi diff --git a/runtime/base/logging.h b/runtime/base/logging.h index 97280c3a0..3b5b8b54a 100644 --- a/runtime/base/logging.h +++ b/runtime/base/logging.h @@ -56,6 +56,7 @@ struct LogVerbosity { bool threads; bool verifier; bool image; + bool systrace_lock_logging; // Enabled with "-verbose:sys-locks". }; // Global log verbosity setting, initialized by InitLogging. diff --git a/runtime/entrypoints/quick/quick_default_externs.h b/runtime/entrypoints/quick/quick_default_externs.h index 4e01d8031..f3a0d2f3e 100644 --- a/runtime/entrypoints/quick/quick_default_externs.h +++ b/runtime/entrypoints/quick/quick_default_externs.h @@ -77,6 +77,10 @@ extern "C" void art_quick_handle_fill_data(void*, void*); extern "C" void art_quick_lock_object(art::mirror::Object*); extern "C" void art_quick_unlock_object(art::mirror::Object*); +// Lock entrypoints that do not inline any behavior (e.g., thin-locks). +extern "C" void art_quick_lock_object_no_inline(art::mirror::Object*); +extern "C" void art_quick_unlock_object_no_inline(art::mirror::Object*); + // Math entrypoints. extern "C" int64_t art_quick_d2l(double); extern "C" int64_t art_quick_f2l(float); diff --git a/runtime/entrypoints/quick/quick_default_init_entrypoints.h b/runtime/entrypoints/quick/quick_default_init_entrypoints.h new file mode 100644 index 000000000..5dafa8b59 --- /dev/null +++ b/runtime/entrypoints/quick/quick_default_init_entrypoints.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_DEFAULT_INIT_ENTRYPOINTS_H_ +#define ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_DEFAULT_INIT_ENTRYPOINTS_H_ + +#include "base/logging.h" +#include "entrypoints/jni/jni_entrypoints.h" +#include "entrypoints/runtime_asm_entrypoints.h" +#include "quick_alloc_entrypoints.h" +#include "quick_default_externs.h" +#include "quick_entrypoints.h" + +namespace art { + +void DefaultInitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) { + // JNI + jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub; + + // Alloc + ResetQuickAllocEntryPoints(qpoints); + + // DexCache + qpoints->pInitializeStaticStorage = art_quick_initialize_static_storage; + qpoints->pInitializeTypeAndVerifyAccess = art_quick_initialize_type_and_verify_access; + qpoints->pInitializeType = art_quick_initialize_type; + qpoints->pResolveString = art_quick_resolve_string; + + // Field + qpoints->pSet8Instance = art_quick_set8_instance; + qpoints->pSet8Static = art_quick_set8_static; + qpoints->pSet16Instance = art_quick_set16_instance; + qpoints->pSet16Static = art_quick_set16_static; + qpoints->pSet32Instance = art_quick_set32_instance; + qpoints->pSet32Static = art_quick_set32_static; + qpoints->pSet64Instance = art_quick_set64_instance; + qpoints->pSet64Static = art_quick_set64_static; + qpoints->pSetObjInstance = art_quick_set_obj_instance; + qpoints->pSetObjStatic = art_quick_set_obj_static; + qpoints->pGetByteInstance = art_quick_get_byte_instance; + qpoints->pGetBooleanInstance = art_quick_get_boolean_instance; + qpoints->pGetShortInstance = art_quick_get_short_instance; + qpoints->pGetCharInstance = art_quick_get_char_instance; + qpoints->pGet32Instance = art_quick_get32_instance; + qpoints->pGet64Instance = art_quick_get64_instance; + qpoints->pGetObjInstance = art_quick_get_obj_instance; + qpoints->pGetByteStatic = art_quick_get_byte_static; + qpoints->pGetBooleanStatic = art_quick_get_boolean_static; + qpoints->pGetShortStatic = art_quick_get_short_static; + qpoints->pGetCharStatic = art_quick_get_char_static; + qpoints->pGet32Static = art_quick_get32_static; + qpoints->pGet64Static = art_quick_get64_static; + qpoints->pGetObjStatic = art_quick_get_obj_static; + + // Array + qpoints->pAputObjectWithNullAndBoundCheck = art_quick_aput_obj_with_null_and_bound_check; + qpoints->pAputObjectWithBoundCheck = art_quick_aput_obj_with_bound_check; + qpoints->pAputObject = art_quick_aput_obj; + qpoints->pHandleFillArrayData = art_quick_handle_fill_data; + + // JNI + qpoints->pJniMethodStart = JniMethodStart; + qpoints->pJniMethodStartSynchronized = JniMethodStartSynchronized; + qpoints->pJniMethodEnd = JniMethodEnd; + qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized; + qpoints->pJniMethodEndWithReference = JniMethodEndWithReference; + qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized; + qpoints->pQuickGenericJniTrampoline = art_quick_generic_jni_trampoline; + + // Locks + if (UNLIKELY(VLOG_IS_ON(systrace_lock_logging))) { + qpoints->pLockObject = art_quick_lock_object_no_inline; + qpoints->pUnlockObject = art_quick_unlock_object_no_inline; + } else { + qpoints->pLockObject = art_quick_lock_object; + qpoints->pUnlockObject = art_quick_unlock_object; + } + + // Invocation + qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline; + qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline; + qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge; + qpoints->pInvokeDirectTrampolineWithAccessCheck = + art_quick_invoke_direct_trampoline_with_access_check; + qpoints->pInvokeInterfaceTrampolineWithAccessCheck = + art_quick_invoke_interface_trampoline_with_access_check; + qpoints->pInvokeStaticTrampolineWithAccessCheck = + art_quick_invoke_static_trampoline_with_access_check; + qpoints->pInvokeSuperTrampolineWithAccessCheck = + art_quick_invoke_super_trampoline_with_access_check; + qpoints->pInvokeVirtualTrampolineWithAccessCheck = + art_quick_invoke_virtual_trampoline_with_access_check; + + // Thread + qpoints->pTestSuspend = art_quick_test_suspend; + + // Throws + qpoints->pDeliverException = art_quick_deliver_exception; + qpoints->pThrowArrayBounds = art_quick_throw_array_bounds; + qpoints->pThrowDivZero = art_quick_throw_div_zero; + qpoints->pThrowNoSuchMethod = art_quick_throw_no_such_method; + qpoints->pThrowNullPointer = art_quick_throw_null_pointer_exception; + qpoints->pThrowStackOverflow = art_quick_throw_stack_overflow; + + // Deoptimize + qpoints->pDeoptimize = art_quick_deoptimize_from_compiled_code; +}; + +} // namespace art + +#endif // ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_DEFAULT_INIT_ENTRYPOINTS_H_ diff --git a/runtime/monitor.cc b/runtime/monitor.cc index c646cb56c..bf26f7753 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -215,6 +215,85 @@ void Monitor::SetObject(mirror::Object* object) { obj_ = GcRoot(object); } +// Note: Adapted from CurrentMethodVisitor in thread.cc. We must not resolve here. + +struct NthCallerWithDexPcVisitor FINAL : public StackVisitor { + explicit NthCallerWithDexPcVisitor(Thread* thread, size_t frame) + SHARED_REQUIRES(Locks::mutator_lock_) + : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFramesNoResolve), + method_(nullptr), + dex_pc_(0), + current_frame_number_(0), + wanted_frame_number_(frame) {} + bool VisitFrame() OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) { + ArtMethod* m = GetMethod(); + if (m == nullptr || m->IsRuntimeMethod()) { + // Runtime method, upcall, or resolution issue. Skip. + return true; + } + + // Is this the requested frame? + if (current_frame_number_ == wanted_frame_number_) { + method_ = m; + dex_pc_ = GetDexPc(false /* abort_on_error*/); + return false; + } + + // Look for more. + current_frame_number_++; + return true; + } + + ArtMethod* method_; + uint32_t dex_pc_; + + private: + size_t current_frame_number_; + const size_t wanted_frame_number_; +}; + +// This function is inlined and just helps to not have the VLOG and ATRACE check at all the +// potential tracing points. +void Monitor::AtraceMonitorLock(Thread* self, mirror::Object* obj, bool is_wait) { + if (UNLIKELY(VLOG_IS_ON(systrace_lock_logging) && ATRACE_ENABLED())) { + AtraceMonitorLockImpl(self, obj, is_wait); + } +} + +void Monitor::AtraceMonitorLockImpl(Thread* self, mirror::Object* obj, bool is_wait) { + // Wait() requires a deeper call stack to be useful. Otherwise you'll see "Waiting at + // Object.java". Assume that we'll wait a nontrivial amount, so it's OK to do a longer + // stack walk than if !is_wait. + NthCallerWithDexPcVisitor visitor(self, is_wait ? 1U : 0U); + visitor.WalkStack(false); + const char* prefix = is_wait ? "Waiting on " : "Locking "; + + const char* filename; + int32_t line_number; + TranslateLocation(visitor.method_, visitor.dex_pc_, &filename, &line_number); + + // It would be nice to have a stable "ID" for the object here. However, the only stable thing + // would be the identity hashcode. But we cannot use IdentityHashcode here: For one, there are + // times when it is unsafe to make that call (see stack dumping for an explanation). More + // importantly, we would have to give up on thin-locking when adding systrace locks, as the + // identity hashcode is stored in the lockword normally (so can't be used with thin-locks). + // + // Because of thin-locks we also cannot use the monitor id (as there is no monitor). Monitor ids + // also do not have to be stable, as the monitor may be deflated. + std::string tmp = StringPrintf("%s %d at %s:%d", + prefix, + (obj == nullptr ? -1 : static_cast(reinterpret_cast(obj))), + (filename != nullptr ? filename : "null"), + line_number); + ATRACE_BEGIN(tmp.c_str()); +} + +void Monitor::AtraceMonitorUnlock() { + if (UNLIKELY(VLOG_IS_ON(systrace_lock_logging))) { + ATRACE_END(); + } +} + std::string Monitor::PrettyContentionInfo(const std::string& owner_name, pid_t owner_tid, ArtMethod* owners_method, @@ -246,10 +325,10 @@ void Monitor::Lock(Thread* self) { if (lock_profiling_threshold_ != 0) { locking_method_ = self->GetCurrentMethod(&locking_dex_pc_); } - return; + break; } else if (owner_ == self) { // Recursive. lock_count_++; - return; + break; } // Contended. const bool log_contention = (lock_profiling_threshold_ != 0); @@ -348,6 +427,8 @@ void Monitor::Lock(Thread* self) { monitor_lock_.Lock(self); // Reacquire locks in order. --num_waiters_; } + + AtraceMonitorLock(self, GetObject(), false /* is_wait */); } static void ThrowIllegalMonitorStateExceptionF(const char* fmt, ...) @@ -457,6 +538,7 @@ bool Monitor::Unlock(Thread* self) { } if (owner == self) { // We own the monitor, so nobody else can be in here. + AtraceMonitorUnlock(); if (lock_count_ == 0) { owner_ = nullptr; locking_method_ = nullptr; @@ -523,6 +605,11 @@ void Monitor::Wait(Thread* self, int64_t ms, int32_t ns, uintptr_t saved_dex_pc = locking_dex_pc_; locking_dex_pc_ = 0; + AtraceMonitorUnlock(); // For the implict Unlock() just above. This will only end the deepest + // nesting, but that is enough for the visualization, and corresponds to + // the single Lock() we do afterwards. + AtraceMonitorLock(self, GetObject(), true /* is_wait */); + bool was_interrupted = false; { // Update thread state. If the GC wakes up, it'll ignore us, knowing @@ -586,6 +673,8 @@ void Monitor::Wait(Thread* self, int64_t ms, int32_t ns, self->ThrowNewException("Ljava/lang/InterruptedException;", nullptr); } + AtraceMonitorUnlock(); // End Wait(). + // Re-acquire the monitor and lock. Lock(self); monitor_lock_.Lock(self); @@ -775,6 +864,7 @@ mirror::Object* Monitor::MonitorEnter(Thread* self, mirror::Object* obj) { case LockWord::kUnlocked: { LockWord thin_locked(LockWord::FromThinLockId(thread_id, 0, lock_word.ReadBarrierState())); if (h_obj->CasLockWordWeakSequentiallyConsistent(lock_word, thin_locked)) { + AtraceMonitorLock(self, h_obj.Get(), false /* is_wait */); // CasLockWord enforces more than the acquire ordering we need here. return h_obj.Get(); // Success! } @@ -790,10 +880,12 @@ mirror::Object* Monitor::MonitorEnter(Thread* self, mirror::Object* obj) { lock_word.ReadBarrierState())); if (!kUseReadBarrier) { h_obj->SetLockWord(thin_locked, true); + AtraceMonitorLock(self, h_obj.Get(), false /* is_wait */); return h_obj.Get(); // Success! } else { // Use CAS to preserve the read barrier state. if (h_obj->CasLockWordWeakSequentiallyConsistent(lock_word, thin_locked)) { + AtraceMonitorLock(self, h_obj.Get(), false /* is_wait */); return h_obj.Get(); // Success! } } @@ -830,7 +922,7 @@ mirror::Object* Monitor::MonitorEnter(Thread* self, mirror::Object* obj) { continue; // Start from the beginning. default: { LOG(FATAL) << "Invalid monitor state " << lock_word.GetState(); - return h_obj.Get(); + UNREACHABLE(); } } } @@ -869,11 +961,17 @@ bool Monitor::MonitorExit(Thread* self, mirror::Object* obj) { if (!kUseReadBarrier) { DCHECK_EQ(new_lw.ReadBarrierState(), 0U); h_obj->SetLockWord(new_lw, true); + if (ATRACE_ENABLED()) { + ATRACE_END(); + } // Success! return true; } else { // Use CAS to preserve the read barrier state. if (h_obj->CasLockWordWeakSequentiallyConsistent(lock_word, new_lw)) { + if (ATRACE_ENABLED()) { + ATRACE_END(); + } // Success! return true; } diff --git a/runtime/monitor.h b/runtime/monitor.h index 8c7496b52..7b4b8f946 100644 --- a/runtime/monitor.h +++ b/runtime/monitor.h @@ -250,6 +250,17 @@ class Monitor { uint32_t GetOwnerThreadId() REQUIRES(!monitor_lock_); + // Support for systrace output of monitor operations. + ALWAYS_INLINE static void AtraceMonitorLock(Thread* self, + mirror::Object* obj, + bool is_wait) + SHARED_REQUIRES(Locks::mutator_lock_); + static void AtraceMonitorLockImpl(Thread* self, + mirror::Object* obj, + bool is_wait) + SHARED_REQUIRES(Locks::mutator_lock_); + ALWAYS_INLINE static void AtraceMonitorUnlock(); + static uint32_t lock_profiling_threshold_; Mutex monitor_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;