x86_64: Implement VarHandle.compareAnd{Set,Exchange} for fields.
Reuse `GenCAS` function and extend it to support `compareAndExchange`
operation in addition to `compareAndSet`. For convenience, split it into
three functions for integral types, floating-point types and references,
as these cases are handled differently and require different number of
temporary registers.
Also, rename CreateIntIntIntIntIntToInt to CreateUnsafeCASLocations and
use RAX for output to take advantage of the CMPXCHG side-effect.
Benchmarks improvements (using benchmarks provided by
https://android-review.googlesource.com/1420959):
benchmark before after
----------------------------------------------------------
CompareAndSetStaticFieldInt 2.843 0.00910
CompareAndSetStaticFieldString 3.256 0.01017
CompareAndSetFieldInt 3.161 0.00910
CompareAndSetFieldString 3.486 0.01017
WeakCompareAndSetStaticFieldInt 2.820 0.00895
WeakCompareAndSetStaticFieldString 3.222 0.01016
WeakCompareAndSetFieldInt 3.144 0.00910
WeakCompareAndSetFieldString 3.454 0.01018
WeakCompareAndSetPlainStaticFieldInt 2.819 0.00896
WeakCompareAndSetPlainStaticFieldString 3.227 0.01016
WeakCompareAndSetPlainFieldInt 3.150 0.00909
WeakCompareAndSetPlainFieldString 3.456 0.01019
WeakCompareAndSetAcquireStaticFieldInt 2.822 0.00896
WeakCompareAndSetAcquireStaticFieldString 3.226 0.01016
WeakCompareAndSetAcquireFieldInt 3.148 0.00910
WeakCompareAndSetAcquireFieldString 3.455 0.01020
WeakCompareAndSetReleaseStaticFieldInt 2.820 0.00895
WeakCompareAndSetReleaseStaticFieldString 3.223 0.01015
WeakCompareAndSetReleaseFieldInt 3.143 0.00910
WeakCompareAndSetReleaseFieldString 3.458 0.01013
CompareAndExchangeStaticFieldInt 2.765 0.00895
CompareAndExchangeStaticFieldString 3.183 0.01012
CompareAndExchangeFieldInt 3.076 0.00907
CompareAndExchangeFieldString 3.443 0.01015
CompareAndExchangeAcquireStaticFieldInt 2.774 0.00895
CompareAndExchangeAcquireStaticFieldString 3.177 0.01012
CompareAndExchangeAcquireFieldInt 3.092 0.00907
CompareAndExchangeAcquireFieldString 3.453 0.01015
CompareAndExchangeReleaseStaticFieldInt 2.796 0.00895
CompareAndExchangeReleaseStaticFieldString 3.193 0.01014
CompareAndExchangeReleaseFieldInt 3.105 0.00909
CompareAndExchangeReleaseFieldString 3.451 0.01015
Bug: 65872996
Test: lunch aosp_cf_x86_64_phone-userdebug \
&& art/test.py --host -r -t 712-varhandle-invocations --64
Test: Repeat with ART_USE_READ_BARRIER=false.
Test: Repeat with ART_HEAP_POISONING=true.
Change-Id: I816f9c6a3786efe921fe445536f9ea3ddae801d5
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index da9a1ab..f205979 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -34,6 +34,7 @@
#include "mirror/array-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object_reference.h"
+#include "mirror/var_handle.h"
#include "scoped_thread_state_change-inl.h"
#include "thread.h"
#include "utils/assembler.h"
@@ -594,11 +595,17 @@
DCHECK(locations->CanCall());
DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
// This slow path is only used by the UnsafeCASObject intrinsic.
- DCHECK((instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
+ DCHECK((instruction_->IsInvoke() && instruction_->GetLocations()->Intrinsified()))
<< "Unexpected instruction in read barrier marking and field updating slow path: "
<< instruction_->DebugName();
DCHECK(instruction_->GetLocations()->Intrinsified());
- DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kUnsafeCASObject);
+ Intrinsics intrinsic = instruction_->AsInvoke()->GetIntrinsic();
+ static constexpr auto kVarHandleCAS = mirror::VarHandle::AccessModeTemplate::kCompareAndSet;
+ static constexpr auto kVarHandleCAX =
+ mirror::VarHandle::AccessModeTemplate::kCompareAndExchange;
+ DCHECK(intrinsic == Intrinsics::kUnsafeCASObject ||
+ mirror::VarHandle::GetAccessModeTemplateByIntrinsic(intrinsic) == kVarHandleCAS ||
+ mirror::VarHandle::GetAccessModeTemplateByIntrinsic(intrinsic) == kVarHandleCAX);
__ Bind(GetEntryLabel());
if (unpoison_ref_before_marking_) {
@@ -1625,6 +1632,8 @@
HConstant* constant = source.GetConstant();
if (constant->IsLongConstant()) {
Load64BitValue(dest, constant->AsLongConstant()->GetValue());
+ } else if (constant->IsDoubleConstant()) {
+ Load64BitValue(dest, GetInt64ValueOf(constant));
} else {
Load32BitValue(dest, GetInt32ValueOf(constant));
}