Implement object lock and unlock entrypoints for x86-64
This patch adds implementation for art_quick_lock_object and
art_quick_unlock_object stubs for x86-64 and enables their
testing in stub_test.
Change-Id: Ia373c9b0ebc7ebb959968464cf55607afd5384b0
Signed-off-by: Alexei Zavjalov <alexei.zavjalov@intel.com>
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 437beb5..8fbca94 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -183,12 +183,12 @@
}
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
extern "C" void art_quick_lock_object(void);
#endif
TEST_F(StubTest, LockObject) {
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
Thread* self = Thread::Current();
// Create an object
ScopedObjectAccess soa(self);
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index cac6cfd..9ccf6c9 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -661,13 +661,61 @@
TWO_ARG_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode, RETURN_IF_EAX_ZERO
DEFINE_FUNCTION art_quick_lock_object
- int3
- int3
+ testl %edi, %edi // Null check object/rdi.
+ jz .Lslow_lock
+.Lretry_lock:
+ movl LOCK_WORD_OFFSET(%edi), %ecx // ecx := lock word.
+ test LITERAL(0xC0000000), %ecx // Test the 2 high bits.
+ jne .Lslow_lock // Slow path if either of the two high bits are set.
+ movl %gs:THREAD_ID_OFFSET, %edx // edx := thread id
+ test %ecx, %ecx
+ jnz .Lalready_thin // Lock word contains a thin lock.
+ // unlocked case - %edx holds thread id with count of 0
+ xor %eax, %eax // eax == 0 for comparison with lock word in cmpxchg
+ lock cmpxchg %edx, LOCK_WORD_OFFSET(%edi)
+ jnz .Lretry_lock // cmpxchg failed retry
+ ret
+.Lalready_thin:
+ cmpw %cx, %dx // do we hold the lock already?
+ jne .Lslow_lock
+ addl LITERAL(65536), %ecx // increment recursion count
+ test LITERAL(0xC0000000), %ecx // overflowed if either of top two bits are set
+ jne .Lslow_lock // count overflowed so go slow
+ movl %ecx, LOCK_WORD_OFFSET(%edi) // update lockword, cmpxchg not necessary as we hold lock
+ ret
+.Lslow_lock:
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+ movq %gs:THREAD_SELF_OFFSET, %rsi // pass Thread::Current()
+ movq %rsp, %rdx // pass SP
+ call PLT_SYMBOL(artLockObjectFromCode) // artLockObjectFromCode(object, Thread*, SP)
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+ RETURN_IF_EAX_ZERO
END_FUNCTION art_quick_lock_object
DEFINE_FUNCTION art_quick_unlock_object
- int3
- int3
+ testl %edi, %edi // null check object/edi
+ jz .Lslow_unlock
+ movl LOCK_WORD_OFFSET(%edi), %ecx // ecx := lock word
+ movl %gs:THREAD_ID_OFFSET, %edx // edx := thread id
+ test %ecx, %ecx
+ jb .Lslow_unlock // lock word contains a monitor
+ cmpw %cx, %dx // does the thread id match?
+ jne .Lslow_unlock
+ cmpl LITERAL(65536), %ecx
+ jae .Lrecursive_thin_unlock
+ movl LITERAL(0), LOCK_WORD_OFFSET(%edi)
+ ret
+.Lrecursive_thin_unlock:
+ subl LITERAL(65536), %ecx
+ mov %ecx, LOCK_WORD_OFFSET(%edi)
+ ret
+.Lslow_unlock:
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+ movq %gs:THREAD_SELF_OFFSET, %rsi // pass Thread::Current()
+ movq %rsp, %rdx // pass SP
+ call PLT_SYMBOL(artUnlockObjectFromCode) // artUnlockObjectFromCode(object, Thread*, SP)
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+ RETURN_IF_EAX_ZERO
END_FUNCTION art_quick_unlock_object
DEFINE_FUNCTION art_quick_is_assignable