summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2021-07-21 16:20:54 +0000
committer Vladimir Marko <vmarko@google.com> 2021-07-21 16:21:35 +0000
commit4a889b7f1e58368f0ffd795eaa24f2f493ccab8d (patch)
tree6449e59690e4219f3b3c1beba3631ecb586a584d
parent5d446a37192427b4d24ca9add5d8e2409f665c4d (diff)
Revert "Compile time null checks for VarHandle intrinsics."
This reverts commit b3a7a6a72d7b91ee5507bd7314a3aae3948e6f29. Reason for revert: Breaks ART baseline compiler. Bug: 191765508 Change-Id: Ida63660e0149c4847f015950f95282e61add7204
-rw-r--r--compiler/optimizing/instruction_simplifier.cc137
-rw-r--r--compiler/optimizing/intrinsics.h8
-rw-r--r--compiler/optimizing/intrinsics_arm64.cc107
-rw-r--r--compiler/optimizing/intrinsics_arm_vixl.cc111
-rw-r--r--compiler/optimizing/intrinsics_x86.cc112
-rw-r--r--compiler/optimizing/intrinsics_x86_64.cc74
6 files changed, 331 insertions, 218 deletions
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index a7d049ac00..a6104effd7 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -22,7 +22,6 @@
#include "data_type-inl.h"
#include "escape.h"
#include "intrinsics.h"
-#include "intrinsics_utils.h"
#include "mirror/class-inl.h"
#include "optimizing/nodes.h"
#include "scoped_thread_state_change-inl.h"
@@ -124,7 +123,6 @@ class InstructionSimplifierVisitor : public HGraphDelegateVisitor {
void SimplifyNPEOnArgN(HInvoke* invoke, size_t);
void SimplifyReturnThis(HInvoke* invoke);
void SimplifyAllocationIntrinsic(HInvoke* invoke);
- void SimplifyVarHandleIntrinsic(HInvoke* invoke);
CodeGenerator* codegen_;
OptimizingCompilerStats* stats_;
@@ -2764,108 +2762,6 @@ void InstructionSimplifierVisitor::SimplifyAllocationIntrinsic(HInvoke* invoke)
}
}
-void InstructionSimplifierVisitor::SimplifyVarHandleIntrinsic(HInvoke* invoke) {
- DCHECK(invoke->IsInvokePolymorphic());
- VarHandleOptimizations optimizations(invoke);
- size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
- if (expected_coordinates_count > 2u) {
- optimizations.SetDoNotIntrinsify();
- return;
- }
- if (expected_coordinates_count != 0u) {
- // Except for static fields (no coordinates), the first coordinate must be a reference.
- // Do not intrinsify if the reference is null as we would always go to slow path anyway.
- HInstruction* object = invoke->InputAt(1);
- if (object->GetType() != DataType::Type::kReference || object->IsNullConstant()) {
- optimizations.SetDoNotIntrinsify();
- return;
- }
- // Test whether we can avoid the null check on the object.
- if (CanEnsureNotNullAt(object, invoke)) {
- optimizations.SetSkipObjectNullCheck();
- }
- }
- if (expected_coordinates_count == 2u) {
- // For arrays and views, the second coordinate must be convertible to `int`.
- // In this context, `boolean` is not convertible but we have to look at the shorty
- // as compiler transformations can give the invoke a valid boolean input.
- DataType::Type index_type = GetDataTypeFromShorty(invoke, 2);
- if (index_type == DataType::Type::kBool ||
- DataType::Kind(index_type) != DataType::Type::kInt32) {
- optimizations.SetDoNotIntrinsify();
- return;
- }
- }
-
- uint32_t number_of_arguments = invoke->GetNumberOfArguments();
- DataType::Type return_type = invoke->GetType();
- mirror::VarHandle::AccessModeTemplate access_mode_template =
- mirror::VarHandle::GetAccessModeTemplateByIntrinsic(invoke->GetIntrinsic());
- switch (access_mode_template) {
- case mirror::VarHandle::AccessModeTemplate::kGet:
- // The return type should be the same as varType, so it shouldn't be void.
- if (return_type == DataType::Type::kVoid) {
- optimizations.SetDoNotIntrinsify();
- return;
- }
- break;
- case mirror::VarHandle::AccessModeTemplate::kSet:
- if (return_type != DataType::Type::kVoid) {
- optimizations.SetDoNotIntrinsify();
- return;
- }
- break;
- case mirror::VarHandle::AccessModeTemplate::kCompareAndSet: {
- if (return_type != DataType::Type::kBool) {
- optimizations.SetDoNotIntrinsify();
- return;
- }
- uint32_t expected_value_index = number_of_arguments - 2;
- uint32_t new_value_index = number_of_arguments - 1;
- DataType::Type expected_value_type = GetDataTypeFromShorty(invoke, expected_value_index);
- DataType::Type new_value_type = GetDataTypeFromShorty(invoke, new_value_index);
- if (expected_value_type != new_value_type) {
- optimizations.SetDoNotIntrinsify();
- return;
- }
- break;
- }
- case mirror::VarHandle::AccessModeTemplate::kCompareAndExchange: {
- uint32_t expected_value_index = number_of_arguments - 2;
- uint32_t new_value_index = number_of_arguments - 1;
- DataType::Type expected_value_type = GetDataTypeFromShorty(invoke, expected_value_index);
- DataType::Type new_value_type = GetDataTypeFromShorty(invoke, new_value_index);
- if (expected_value_type != new_value_type || return_type != expected_value_type) {
- optimizations.SetDoNotIntrinsify();
- return;
- }
- break;
- }
- case mirror::VarHandle::AccessModeTemplate::kGetAndUpdate: {
- DataType::Type value_type = GetDataTypeFromShorty(invoke, number_of_arguments - 1);
- if (IsVarHandleGetAndAdd(invoke) &&
- (value_type == DataType::Type::kReference || value_type == DataType::Type::kBool)) {
- // We should only add numerical types.
- optimizations.SetDoNotIntrinsify();
- return;
- } else if (IsVarHandleGetAndBitwiseOp(invoke) && !DataType::IsIntegralType(value_type)) {
- // We can only apply operators to bitwise integral types.
- // Note that bitwise VarHandle operations accept a non-integral boolean type and
- // perform the appropriate logical operation. However, the result is the same as
- // using the bitwise operation on our boolean representation and this fits well
- // with DataType::IsIntegralType() treating the compiler type kBool as integral.
- optimizations.SetDoNotIntrinsify();
- return;
- }
- if (value_type != return_type) {
- optimizations.SetDoNotIntrinsify();
- return;
- }
- break;
- }
- }
-}
-
void InstructionSimplifierVisitor::VisitInvoke(HInvoke* instruction) {
switch (instruction->GetIntrinsic()) {
case Intrinsics::kStringEquals:
@@ -2913,39 +2809,6 @@ void InstructionSimplifierVisitor::VisitInvoke(HInvoke* instruction) {
case Intrinsics::kStringBuilderToString:
SimplifyAllocationIntrinsic(instruction);
break;
- case Intrinsics::kVarHandleCompareAndExchange:
- case Intrinsics::kVarHandleCompareAndExchangeAcquire:
- case Intrinsics::kVarHandleCompareAndExchangeRelease:
- case Intrinsics::kVarHandleCompareAndSet:
- case Intrinsics::kVarHandleGet:
- case Intrinsics::kVarHandleGetAcquire:
- case Intrinsics::kVarHandleGetAndAdd:
- case Intrinsics::kVarHandleGetAndAddAcquire:
- case Intrinsics::kVarHandleGetAndAddRelease:
- case Intrinsics::kVarHandleGetAndBitwiseAnd:
- case Intrinsics::kVarHandleGetAndBitwiseAndAcquire:
- case Intrinsics::kVarHandleGetAndBitwiseAndRelease:
- case Intrinsics::kVarHandleGetAndBitwiseOr:
- case Intrinsics::kVarHandleGetAndBitwiseOrAcquire:
- case Intrinsics::kVarHandleGetAndBitwiseOrRelease:
- case Intrinsics::kVarHandleGetAndBitwiseXor:
- case Intrinsics::kVarHandleGetAndBitwiseXorAcquire:
- case Intrinsics::kVarHandleGetAndBitwiseXorRelease:
- case Intrinsics::kVarHandleGetAndSet:
- case Intrinsics::kVarHandleGetAndSetAcquire:
- case Intrinsics::kVarHandleGetAndSetRelease:
- case Intrinsics::kVarHandleGetOpaque:
- case Intrinsics::kVarHandleGetVolatile:
- case Intrinsics::kVarHandleSet:
- case Intrinsics::kVarHandleSetOpaque:
- case Intrinsics::kVarHandleSetRelease:
- case Intrinsics::kVarHandleSetVolatile:
- case Intrinsics::kVarHandleWeakCompareAndSet:
- case Intrinsics::kVarHandleWeakCompareAndSetAcquire:
- case Intrinsics::kVarHandleWeakCompareAndSetPlain:
- case Intrinsics::kVarHandleWeakCompareAndSetRelease:
- SimplifyVarHandleIntrinsic(instruction);
- break;
case Intrinsics::kIntegerRotateRight:
case Intrinsics::kLongRotateRight:
case Intrinsics::kIntegerRotateLeft:
diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h
index 9bc8c5126b..62b5faa7d0 100644
--- a/compiler/optimizing/intrinsics.h
+++ b/compiler/optimizing/intrinsics.h
@@ -224,14 +224,6 @@ class SystemArrayCopyOptimizations : public IntrinsicOptimizations {
DISALLOW_COPY_AND_ASSIGN(SystemArrayCopyOptimizations);
};
-class VarHandleOptimizations : public IntrinsicOptimizations {
- public:
- explicit VarHandleOptimizations(HInvoke* invoke) : IntrinsicOptimizations(invoke) {}
-
- INTRINSIC_OPTIMIZATION(DoNotIntrinsify, 0); // One of the checks is statically known to fail.
- INTRINSIC_OPTIMIZATION(SkipObjectNullCheck, 1); // Not applicable for static fields.
-};
-
#undef INTRISIC_OPTIMIZATION
//
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 800e5bdd52..d0c64c2230 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -4045,7 +4045,6 @@ static void GenerateVarHandleStaticFieldCheck(HInvoke* invoke,
static void GenerateVarHandleInstanceFieldChecks(HInvoke* invoke,
CodeGeneratorARM64* codegen,
SlowPathCodeARM64* slow_path) {
- VarHandleOptimizations optimizations(invoke);
MacroAssembler* masm = codegen->GetVIXLAssembler();
Register varhandle = InputRegisterAt(invoke, 0);
Register object = InputRegisterAt(invoke, 1);
@@ -4054,9 +4053,7 @@ static void GenerateVarHandleInstanceFieldChecks(HInvoke* invoke,
const MemberOffset coordinate_type1_offset = mirror::VarHandle::CoordinateType1Offset();
// Null-check the object.
- if (!optimizations.GetSkipObjectNullCheck()) {
- __ Cbz(object, slow_path->GetEntryLabel());
- }
+ __ Cbz(object, slow_path->GetEntryLabel());
UseScratchRegisterScope temps(masm);
Register temp = temps.AcquireW();
@@ -4093,7 +4090,6 @@ static DataType::Type GetVarHandleExpectedValueType(HInvoke* invoke,
static void GenerateVarHandleArrayChecks(HInvoke* invoke,
CodeGeneratorARM64* codegen,
VarHandleSlowPathARM64* slow_path) {
- VarHandleOptimizations optimizations(invoke);
MacroAssembler* masm = codegen->GetVIXLAssembler();
Register varhandle = InputRegisterAt(invoke, 0);
Register object = InputRegisterAt(invoke, 1);
@@ -4110,9 +4106,7 @@ static void GenerateVarHandleArrayChecks(HInvoke* invoke,
const MemberOffset array_length_offset = mirror::Array::LengthOffset();
// Null-check the object.
- if (!optimizations.GetSkipObjectNullCheck()) {
- __ Cbz(object, slow_path->GetEntryLabel());
- }
+ __ Cbz(object, slow_path->GetEntryLabel());
UseScratchRegisterScope temps(masm);
Register temp = temps.AcquireW();
@@ -4268,6 +4262,91 @@ static void GenerateVarHandleTarget(HInvoke* invoke,
}
}
+static bool HasVarHandleIntrinsicImplementation(HInvoke* invoke) {
+ size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
+ if (expected_coordinates_count > 2u) {
+ // Invalid coordinate count. This invoke shall throw at runtime.
+ return false;
+ }
+ if (expected_coordinates_count != 0u &&
+ invoke->InputAt(1)->GetType() != DataType::Type::kReference) {
+ // Except for static fields (no coordinates), the first coordinate must be a reference.
+ return false;
+ }
+ if (expected_coordinates_count == 2u) {
+ // For arrays and views, the second coordinate must be convertible to `int`.
+ // In this context, `boolean` is not convertible but we have to look at the shorty
+ // as compiler transformations can give the invoke a valid boolean input.
+ DataType::Type index_type = GetDataTypeFromShorty(invoke, 2);
+ if (index_type == DataType::Type::kBool ||
+ DataType::Kind(index_type) != DataType::Type::kInt32) {
+ return false;
+ }
+ }
+
+ uint32_t number_of_arguments = invoke->GetNumberOfArguments();
+ DataType::Type return_type = invoke->GetType();
+ mirror::VarHandle::AccessModeTemplate access_mode_template =
+ mirror::VarHandle::GetAccessModeTemplateByIntrinsic(invoke->GetIntrinsic());
+ switch (access_mode_template) {
+ case mirror::VarHandle::AccessModeTemplate::kGet:
+ // The return type should be the same as varType, so it shouldn't be void.
+ if (return_type == DataType::Type::kVoid) {
+ return false;
+ }
+ break;
+ case mirror::VarHandle::AccessModeTemplate::kSet:
+ if (return_type != DataType::Type::kVoid) {
+ return false;
+ }
+ break;
+ case mirror::VarHandle::AccessModeTemplate::kCompareAndSet: {
+ if (return_type != DataType::Type::kBool) {
+ return false;
+ }
+ uint32_t expected_value_index = number_of_arguments - 2;
+ uint32_t new_value_index = number_of_arguments - 1;
+ DataType::Type expected_value_type = GetDataTypeFromShorty(invoke, expected_value_index);
+ DataType::Type new_value_type = GetDataTypeFromShorty(invoke, new_value_index);
+ if (expected_value_type != new_value_type) {
+ return false;
+ }
+ break;
+ }
+ case mirror::VarHandle::AccessModeTemplate::kCompareAndExchange: {
+ uint32_t expected_value_index = number_of_arguments - 2;
+ uint32_t new_value_index = number_of_arguments - 1;
+ DataType::Type expected_value_type = GetDataTypeFromShorty(invoke, expected_value_index);
+ DataType::Type new_value_type = GetDataTypeFromShorty(invoke, new_value_index);
+ if (expected_value_type != new_value_type || return_type != expected_value_type) {
+ return false;
+ }
+ break;
+ }
+ case mirror::VarHandle::AccessModeTemplate::kGetAndUpdate: {
+ DataType::Type value_type = GetDataTypeFromShorty(invoke, number_of_arguments - 1);
+ if (IsVarHandleGetAndAdd(invoke) &&
+ (value_type == DataType::Type::kReference || value_type == DataType::Type::kBool)) {
+ // We should only add numerical types.
+ return false;
+ } else if (IsVarHandleGetAndBitwiseOp(invoke) && !DataType::IsIntegralType(value_type)) {
+ // We can only apply operators to bitwise integral types.
+ // Note that bitwise VarHandle operations accept a non-integral boolean type and
+ // perform the appropriate logical operation. However, the result is the same as
+ // using the bitwise operation on our boolean representation and this fits well
+ // with DataType::IsIntegralType() treating the compiler type kBool as integral.
+ return false;
+ }
+ if (value_type != return_type) {
+ return false;
+ }
+ break;
+ }
+ }
+
+ return true;
+}
+
static LocationSummary* CreateVarHandleCommonLocations(HInvoke* invoke) {
size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
DataType::Type return_type = invoke->GetType();
@@ -4320,8 +4399,7 @@ static LocationSummary* CreateVarHandleCommonLocations(HInvoke* invoke) {
}
static void CreateVarHandleGetLocations(HInvoke* invoke) {
- VarHandleOptimizations optimizations(invoke);
- if (optimizations.GetDoNotIntrinsify()) {
+ if (!HasVarHandleIntrinsicImplementation(invoke)) {
return;
}
@@ -4447,8 +4525,7 @@ void IntrinsicCodeGeneratorARM64::VisitVarHandleGetVolatile(HInvoke* invoke) {
}
static void CreateVarHandleSetLocations(HInvoke* invoke) {
- VarHandleOptimizations optimizations(invoke);
- if (optimizations.GetDoNotIntrinsify()) {
+ if (!HasVarHandleIntrinsicImplementation(invoke)) {
return;
}
@@ -4553,8 +4630,7 @@ void IntrinsicCodeGeneratorARM64::VisitVarHandleSetVolatile(HInvoke* invoke) {
}
static void CreateVarHandleCompareAndSetOrExchangeLocations(HInvoke* invoke, bool return_success) {
- VarHandleOptimizations optimizations(invoke);
- if (optimizations.GetDoNotIntrinsify()) {
+ if (!HasVarHandleIntrinsicImplementation(invoke)) {
return;
}
@@ -4901,8 +4977,7 @@ void IntrinsicCodeGeneratorARM64::VisitVarHandleWeakCompareAndSetRelease(HInvoke
static void CreateVarHandleGetAndUpdateLocations(HInvoke* invoke,
GetAndUpdateOp get_and_update_op) {
- VarHandleOptimizations optimizations(invoke);
- if (optimizations.GetDoNotIntrinsify()) {
+ if (!HasVarHandleIntrinsicImplementation(invoke)) {
return;
}
diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc
index f1dfa9e008..2a2f245025 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -3891,7 +3891,6 @@ static void GenerateVarHandleStaticFieldCheck(HInvoke* invoke,
static void GenerateVarHandleInstanceFieldChecks(HInvoke* invoke,
CodeGeneratorARMVIXL* codegen,
SlowPathCodeARMVIXL* slow_path) {
- VarHandleOptimizations optimizations(invoke);
ArmVIXLAssembler* assembler = codegen->GetAssembler();
vixl32::Register varhandle = InputRegisterAt(invoke, 0);
vixl32::Register object = InputRegisterAt(invoke, 1);
@@ -3900,10 +3899,8 @@ static void GenerateVarHandleInstanceFieldChecks(HInvoke* invoke,
const MemberOffset coordinate_type1_offset = mirror::VarHandle::CoordinateType1Offset();
// Null-check the object.
- if (!optimizations.GetSkipObjectNullCheck()) {
- __ Cmp(object, 0);
- __ B(eq, slow_path->GetEntryLabel());
- }
+ __ Cmp(object, 0);
+ __ B(eq, slow_path->GetEntryLabel());
// Use the first temporary register, whether it's for the declaring class or the offset.
// It is not used yet at this point.
@@ -3944,7 +3941,6 @@ static DataType::Type GetVarHandleExpectedValueType(HInvoke* invoke,
static void GenerateVarHandleArrayChecks(HInvoke* invoke,
CodeGeneratorARMVIXL* codegen,
VarHandleSlowPathARMVIXL* slow_path) {
- VarHandleOptimizations optimizations(invoke);
ArmVIXLAssembler* assembler = codegen->GetAssembler();
vixl32::Register varhandle = InputRegisterAt(invoke, 0);
vixl32::Register object = InputRegisterAt(invoke, 1);
@@ -3961,10 +3957,8 @@ static void GenerateVarHandleArrayChecks(HInvoke* invoke,
const MemberOffset array_length_offset = mirror::Array::LengthOffset();
// Null-check the object.
- if (!optimizations.GetSkipObjectNullCheck()) {
- __ Cmp(object, 0);
- __ B(eq, slow_path->GetEntryLabel());
- }
+ __ Cmp(object, 0);
+ __ B(eq, slow_path->GetEntryLabel());
// Use the offset temporary register. It is not used yet at this point.
vixl32::Register temp = RegisterFrom(invoke->GetLocations()->GetTemp(0u));
@@ -4120,6 +4114,91 @@ static void GenerateVarHandleTarget(HInvoke* invoke,
}
}
+static bool HasVarHandleIntrinsicImplementation(HInvoke* invoke) {
+ size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
+ if (expected_coordinates_count > 2u) {
+ // Invalid coordinate count. This invoke shall throw at runtime.
+ return false;
+ }
+ if (expected_coordinates_count != 0u &&
+ invoke->InputAt(1)->GetType() != DataType::Type::kReference) {
+ // Except for static fields (no coordinates), the first coordinate must be a reference.
+ return false;
+ }
+ if (expected_coordinates_count == 2u) {
+ // For arrays and views, the second coordinate must be convertible to `int`.
+ // In this context, `boolean` is not convertible but we have to look at the shorty
+ // as compiler transformations can give the invoke a valid boolean input.
+ DataType::Type index_type = GetDataTypeFromShorty(invoke, 2);
+ if (index_type == DataType::Type::kBool ||
+ DataType::Kind(index_type) != DataType::Type::kInt32) {
+ return false;
+ }
+ }
+
+ uint32_t number_of_arguments = invoke->GetNumberOfArguments();
+ DataType::Type return_type = invoke->GetType();
+ mirror::VarHandle::AccessModeTemplate access_mode_template =
+ mirror::VarHandle::GetAccessModeTemplateByIntrinsic(invoke->GetIntrinsic());
+ switch (access_mode_template) {
+ case mirror::VarHandle::AccessModeTemplate::kGet:
+ // The return type should be the same as varType, so it shouldn't be void.
+ if (return_type == DataType::Type::kVoid) {
+ return false;
+ }
+ break;
+ case mirror::VarHandle::AccessModeTemplate::kSet:
+ if (return_type != DataType::Type::kVoid) {
+ return false;
+ }
+ break;
+ case mirror::VarHandle::AccessModeTemplate::kCompareAndSet: {
+ if (return_type != DataType::Type::kBool) {
+ return false;
+ }
+ uint32_t expected_value_index = number_of_arguments - 2;
+ uint32_t new_value_index = number_of_arguments - 1;
+ DataType::Type expected_value_type = GetDataTypeFromShorty(invoke, expected_value_index);
+ DataType::Type new_value_type = GetDataTypeFromShorty(invoke, new_value_index);
+ if (expected_value_type != new_value_type) {
+ return false;
+ }
+ break;
+ }
+ case mirror::VarHandle::AccessModeTemplate::kCompareAndExchange: {
+ uint32_t expected_value_index = number_of_arguments - 2;
+ uint32_t new_value_index = number_of_arguments - 1;
+ DataType::Type expected_value_type = GetDataTypeFromShorty(invoke, expected_value_index);
+ DataType::Type new_value_type = GetDataTypeFromShorty(invoke, new_value_index);
+ if (expected_value_type != new_value_type || return_type != expected_value_type) {
+ return false;
+ }
+ break;
+ }
+ case mirror::VarHandle::AccessModeTemplate::kGetAndUpdate: {
+ DataType::Type value_type = GetDataTypeFromShorty(invoke, number_of_arguments - 1);
+ if (IsVarHandleGetAndAdd(invoke) &&
+ (value_type == DataType::Type::kReference || value_type == DataType::Type::kBool)) {
+ // We should only add numerical types.
+ return false;
+ } else if (IsVarHandleGetAndBitwiseOp(invoke) && !DataType::IsIntegralType(value_type)) {
+ // We can only apply operators to bitwise integral types.
+ // Note that bitwise VarHandle operations accept a non-integral boolean type and
+ // perform the appropriate logical operation. However, the result is the same as
+ // using the bitwise operation on our boolean representation and this fits well
+ // with DataType::IsIntegralType() treating the compiler type kBool as integral.
+ return false;
+ }
+ if (value_type != return_type) {
+ return false;
+ }
+ break;
+ }
+ }
+
+ return true;
+}
+
static LocationSummary* CreateVarHandleCommonLocations(HInvoke* invoke) {
size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
DataType::Type return_type = invoke->GetType();
@@ -4172,8 +4251,7 @@ static LocationSummary* CreateVarHandleCommonLocations(HInvoke* invoke) {
static void CreateVarHandleGetLocations(HInvoke* invoke,
CodeGeneratorARMVIXL* codegen,
bool atomic) {
- VarHandleOptimizations optimizations(invoke);
- if (optimizations.GetDoNotIntrinsify()) {
+ if (!HasVarHandleIntrinsicImplementation(invoke)) {
return;
}
@@ -4321,8 +4399,7 @@ void IntrinsicCodeGeneratorARMVIXL::VisitVarHandleGetVolatile(HInvoke* invoke) {
static void CreateVarHandleSetLocations(HInvoke* invoke,
CodeGeneratorARMVIXL* codegen,
bool atomic) {
- VarHandleOptimizations optimizations(invoke);
- if (optimizations.GetDoNotIntrinsify()) {
+ if (!HasVarHandleIntrinsicImplementation(invoke)) {
return;
}
@@ -4484,8 +4561,7 @@ void IntrinsicCodeGeneratorARMVIXL::VisitVarHandleSetVolatile(HInvoke* invoke) {
}
static void CreateVarHandleCompareAndSetOrExchangeLocations(HInvoke* invoke, bool return_success) {
- VarHandleOptimizations optimizations(invoke);
- if (optimizations.GetDoNotIntrinsify()) {
+ if (!HasVarHandleIntrinsicImplementation(invoke)) {
return;
}
@@ -4816,8 +4892,7 @@ void IntrinsicCodeGeneratorARMVIXL::VisitVarHandleWeakCompareAndSetRelease(HInvo
static void CreateVarHandleGetAndUpdateLocations(HInvoke* invoke,
GetAndUpdateOp get_and_update_op) {
- VarHandleOptimizations optimizations(invoke);
- if (optimizations.GetDoNotIntrinsify()) {
+ if (!HasVarHandleIntrinsicImplementation(invoke)) {
return;
}
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index bed9ebe4b4..d11bfa27d3 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -3291,20 +3291,81 @@ void IntrinsicCodeGeneratorX86::VisitIntegerDivideUnsigned(HInvoke* invoke) {
__ Bind(slow_path->GetExitLabel());
}
-static bool HasVarHandleIntrinsicImplementation(HInvoke* invoke) {
- VarHandleOptimizations optimizations(invoke);
- if (optimizations.GetDoNotIntrinsify()) {
- return false;
- }
-
+static bool IsValidFieldVarHandleExpected(HInvoke* invoke) {
size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
- DCHECK_LE(expected_coordinates_count, 2u); // Filtered by the `DoNotIntrinsify` flag above.
if (expected_coordinates_count > 1u) {
// Only static and instance fields VarHandle are supported now.
- // TODO: add support for arrays and views.
return false;
}
+ if (expected_coordinates_count == 1u &&
+ invoke->InputAt(1)->GetType() != DataType::Type::kReference) {
+ // For instance fields, the source object must be a reference
+ return false;
+ }
+
+ uint32_t number_of_arguments = invoke->GetNumberOfArguments();
+ DataType::Type return_type = invoke->GetType();
+ mirror::VarHandle::AccessModeTemplate access_mode_template =
+ mirror::VarHandle::GetAccessModeTemplateByIntrinsic(invoke->GetIntrinsic());
+ switch (access_mode_template) {
+ case mirror::VarHandle::AccessModeTemplate::kGet:
+ // The return type should be the same as varType, so it shouldn't be void.
+ if (return_type == DataType::Type::kVoid) {
+ return false;
+ }
+ break;
+ case mirror::VarHandle::AccessModeTemplate::kSet:
+ if (return_type != DataType::Type::kVoid) {
+ return false;
+ }
+ break;
+ case mirror::VarHandle::AccessModeTemplate::kCompareAndSet: {
+ if (return_type != DataType::Type::kBool) {
+ return false;
+ }
+ uint32_t expected_value_index = number_of_arguments - 2;
+ uint32_t new_value_index = number_of_arguments - 1;
+ DataType::Type expected_value_type = GetDataTypeFromShorty(invoke, expected_value_index);
+ DataType::Type new_value_type = GetDataTypeFromShorty(invoke, new_value_index);
+
+ if (expected_value_type != new_value_type) {
+ return false;
+ }
+ break;
+ }
+ case mirror::VarHandle::AccessModeTemplate::kGetAndUpdate: {
+ DataType::Type value_type = GetDataTypeFromShorty(invoke, number_of_arguments - 1);
+ if (IsVarHandleGetAndAdd(invoke) &&
+ (value_type == DataType::Type::kReference || value_type == DataType::Type::kBool)) {
+ // We should only add numerical types.
+ return false;
+ } else if (IsVarHandleGetAndBitwiseOp(invoke) && !DataType::IsIntegralType(value_type)) {
+ // We can only apply operators to bitwise integral types.
+ // Note that bitwise VarHandle operations accept a non-integral boolean type and
+ // perform the appropriate logical operation. However, the result is the same as
+ // using the bitwise operation on our boolean representation and this fits well
+ // with DataType::IsIntegralType() treating the compiler type kBool as integral.
+ return false;
+ }
+ if (value_type != return_type) {
+ return false;
+ }
+ break;
+ }
+ case mirror::VarHandle::AccessModeTemplate::kCompareAndExchange: {
+ uint32_t expected_value_index = number_of_arguments - 2;
+ uint32_t new_value_index = number_of_arguments - 1;
+ DataType::Type expected_value_type = GetDataTypeFromShorty(invoke, expected_value_index);
+ DataType::Type new_value_type = GetDataTypeFromShorty(invoke, new_value_index);
+
+ if (expected_value_type != new_value_type || return_type != expected_value_type) {
+ return false;
+ }
+ break;
+ }
+ }
+
return true;
}
@@ -3365,15 +3426,11 @@ static void GenerateSubTypeObjectCheck(Register object,
__ Bind(&type_matched);
}
-static void GenerateVarHandleInstanceFieldChecks(HInvoke* invoke,
- Register temp,
- SlowPathCode* slow_path,
- X86Assembler* assembler) {
- VarHandleOptimizations optimizations(invoke);
- LocationSummary* locations = invoke->GetLocations();
- Register varhandle_object = locations->InAt(0).AsRegister<Register>();
- Register object = locations->InAt(1).AsRegister<Register>();
-
+static void GenerateVarHandleInstanceFieldObjectCheck(Register varhandle_object,
+ Register object,
+ Register temp,
+ SlowPathCode* slow_path,
+ X86Assembler* assembler) {
const uint32_t coordtype0_offset = mirror::VarHandle::CoordinateType0Offset().Uint32Value();
const uint32_t coordtype1_offset = mirror::VarHandle::CoordinateType1Offset().Uint32Value();
@@ -3384,10 +3441,8 @@ static void GenerateVarHandleInstanceFieldChecks(HInvoke* invoke,
__ j(kNotEqual, slow_path->GetEntryLabel());
// Check if the object is null
- if (!optimizations.GetSkipObjectNullCheck()) {
- __ testl(object, object);
- __ j(kZero, slow_path->GetEntryLabel());
- }
+ __ testl(object, object);
+ __ j(kZero, slow_path->GetEntryLabel());
// Check the object's class against coordinateType0.
GenerateSubTypeObjectCheck(object,
@@ -3435,7 +3490,8 @@ static void GenerateVarHandleCommonChecks(HInvoke *invoke,
GenerateVarHandleStaticFieldCheck(vh_object, slow_path, assembler);
break;
case 1u: {
- GenerateVarHandleInstanceFieldChecks(invoke, temp, slow_path, assembler);
+ Register object = locations->InAt(1).AsRegister<Register>();
+ GenerateVarHandleInstanceFieldObjectCheck(vh_object, object, temp, slow_path, assembler);
break;
}
default:
@@ -3547,7 +3603,7 @@ static void CreateVarHandleGetLocations(HInvoke* invoke) {
return;
}
- if (!HasVarHandleIntrinsicImplementation(invoke)) {
+ if (!IsValidFieldVarHandleExpected(invoke)) {
return;
}
@@ -3670,7 +3726,7 @@ static void CreateVarHandleSetLocations(HInvoke* invoke) {
return;
}
- if (!HasVarHandleIntrinsicImplementation(invoke)) {
+ if (!IsValidFieldVarHandleExpected(invoke)) {
return;
}
@@ -3840,7 +3896,7 @@ static void CreateVarHandleGetAndSetLocations(HInvoke* invoke) {
return;
}
- if (!HasVarHandleIntrinsicImplementation(invoke)) {
+ if (!IsValidFieldVarHandleExpected(invoke)) {
return;
}
@@ -4011,7 +4067,7 @@ static void CreateVarHandleCompareAndSetOrExchangeLocations(HInvoke* invoke) {
return;
}
- if (!HasVarHandleIntrinsicImplementation(invoke)) {
+ if (!IsValidFieldVarHandleExpected(invoke)) {
return;
}
@@ -4194,7 +4250,7 @@ static void CreateVarHandleGetAndAddLocations(HInvoke* invoke) {
return;
}
- if (!HasVarHandleIntrinsicImplementation(invoke)) {
+ if (!IsValidFieldVarHandleExpected(invoke)) {
return;
}
@@ -4344,7 +4400,7 @@ static void CreateVarHandleGetAndBitwiseOpLocations(HInvoke* invoke) {
return;
}
- if (!HasVarHandleIntrinsicImplementation(invoke)) {
+ if (!IsValidFieldVarHandleExpected(invoke)) {
return;
}
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 42323a5bd8..359f886946 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -3129,7 +3129,6 @@ static void GenerateVarHandleStaticFieldCheck(HInvoke* invoke,
static void GenerateVarHandleInstanceFieldChecks(HInvoke* invoke,
CodeGeneratorX86_64* codegen,
SlowPathCode* slow_path) {
- VarHandleOptimizations optimizations(invoke);
X86_64Assembler* assembler = codegen->GetAssembler();
LocationSummary* locations = invoke->GetLocations();
@@ -3141,10 +3140,8 @@ static void GenerateVarHandleInstanceFieldChecks(HInvoke* invoke,
const MemberOffset coordinate_type1_offset = mirror::VarHandle::CoordinateType1Offset();
// Null-check the object.
- if (!optimizations.GetSkipObjectNullCheck()) {
- __ testl(object, object);
- __ j(kZero, slow_path->GetEntryLabel());
- }
+ __ testl(object, object);
+ __ j(kZero, slow_path->GetEntryLabel());
// Check that the VarHandle references an instance field by checking that
// coordinateType1 == null. coordinateType0 should be not null, but this is handled by the
@@ -3245,18 +3242,73 @@ static bool HasVarHandleIntrinsicImplementation(HInvoke* invoke) {
return false;
}
- VarHandleOptimizations optimizations(invoke);
- if (optimizations.GetDoNotIntrinsify()) {
- return false;
- }
-
size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
- DCHECK_LE(expected_coordinates_count, 2u); // Filtered by the `DoNotIntrinsify` flag above.
if (expected_coordinates_count > 1u) {
// Only static and instance fields VarHandle are supported now.
// TODO: add support for arrays and views.
return false;
}
+ if (expected_coordinates_count != 0u &&
+ invoke->InputAt(1)->GetType() != DataType::Type::kReference) {
+ // Except for static fields (no coordinates), the first coordinate must be a reference.
+ return false;
+ }
+
+ uint32_t number_of_arguments = invoke->GetNumberOfArguments();
+ DataType::Type return_type = invoke->GetType();
+ mirror::VarHandle::AccessModeTemplate access_mode_template =
+ mirror::VarHandle::GetAccessModeTemplateByIntrinsic(invoke->GetIntrinsic());
+ switch (access_mode_template) {
+ case mirror::VarHandle::AccessModeTemplate::kGet:
+ // The return type should be the same as varType, so it shouldn't be void.
+ if (return_type == DataType::Type::kVoid) {
+ return false;
+ }
+ break;
+ case mirror::VarHandle::AccessModeTemplate::kSet:
+ if (return_type != DataType::Type::kVoid) {
+ return false;
+ }
+ break;
+ case mirror::VarHandle::AccessModeTemplate::kCompareAndSet: {
+ if (return_type != DataType::Type::kBool) {
+ return false;
+ }
+ DataType::Type expected_type = GetDataTypeFromShorty(invoke, number_of_arguments - 2);
+ DataType::Type new_value_type = GetDataTypeFromShorty(invoke, number_of_arguments - 1);
+ if (expected_type != new_value_type) {
+ return false;
+ }
+ break;
+ }
+ case mirror::VarHandle::AccessModeTemplate::kCompareAndExchange: {
+ DataType::Type expected_type = GetDataTypeFromShorty(invoke, number_of_arguments - 2);
+ DataType::Type new_value_type = GetDataTypeFromShorty(invoke, number_of_arguments - 1);
+ if (expected_type != new_value_type || return_type != expected_type) {
+ return false;
+ }
+ break;
+ }
+ case mirror::VarHandle::AccessModeTemplate::kGetAndUpdate: {
+ DataType::Type value_type = GetDataTypeFromShorty(invoke, number_of_arguments - 1);
+ if (IsVarHandleGetAndAdd(invoke) &&
+ (value_type == DataType::Type::kReference || value_type == DataType::Type::kBool)) {
+ // We should only add numerical types.
+ return false;
+ } else if (IsVarHandleGetAndBitwiseOp(invoke) && !DataType::IsIntegralType(value_type)) {
+ // We can only apply operators to bitwise integral types.
+ // Note that bitwise VarHandle operations accept a non-integral boolean type and
+ // perform the appropriate logical operation. However, the result is the same as
+ // using the bitwise operation on our boolean representation and this fits well
+ // with DataType::IsIntegralType() treating the compiler type kBool as integral.
+ return false;
+ }
+ if (return_type != value_type) {
+ return false;
+ }
+ break;
+ }
+ }
return true;
}