summaryrefslogtreecommitdiff
path: root/compiler/optimizing/instruction_simplifier.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/instruction_simplifier.cc')
-rw-r--r--compiler/optimizing/instruction_simplifier.cc125
1 files changed, 124 insertions, 1 deletions
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 788dc60b23..914e44a18d 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -20,6 +20,7 @@
#include "class_linker-inl.h"
#include "class_root-inl.h"
#include "data_type-inl.h"
+#include "driver/compiler_options.h"
#include "escape.h"
#include "intrinsics.h"
#include "intrinsics_utils.h"
@@ -124,6 +125,7 @@ class InstructionSimplifierVisitor : public HGraphDelegateVisitor {
void SimplifyAllocationIntrinsic(HInvoke* invoke);
void SimplifyVarHandleIntrinsic(HInvoke* invoke);
+ bool CanUseKnownBootImageVarHandle(HInvoke* invoke);
static bool CanEnsureNotNullAt(HInstruction* input, HInstruction* at);
CodeGenerator* codegen_;
@@ -2884,7 +2886,7 @@ void InstructionSimplifierVisitor::SimplifyVarHandleIntrinsic(HInvoke* invoke) {
}
size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
- if (expected_coordinates_count == 1u) {
+ if (expected_coordinates_count != 0u) {
HInstruction* object = invoke->InputAt(1);
// The following has been ensured by static checks in the instruction builder.
DCHECK(object->GetType() == DataType::Type::kReference);
@@ -2898,6 +2900,127 @@ void InstructionSimplifierVisitor::SimplifyVarHandleIntrinsic(HInvoke* invoke) {
optimizations.SetSkipObjectNullCheck();
}
}
+
+ if (CanUseKnownBootImageVarHandle(invoke)) {
+ optimizations.SetUseKnownBootImageVarHandle();
+ }
+}
+
+bool InstructionSimplifierVisitor::CanUseKnownBootImageVarHandle(HInvoke* invoke) {
+ // If the `VarHandle` comes from a static final field of an initialized class in
+ // the boot image, we can do the checks at compile time. We do this optimization only
+ // for AOT and only for field handles when we can avoid all checks. This avoids the
+ // possibility of the code concurrently messing with the `VarHandle` using reflection,
+ // we simply perform the operation with the `VarHandle` as seen at compile time.
+ // TODO: Extend this to arrays to support the `AtomicIntegerArray` class.
+ const CompilerOptions& compiler_options = codegen_->GetCompilerOptions();
+ if (!compiler_options.IsAotCompiler()) {
+ return false;
+ }
+ size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
+ if (expected_coordinates_count == 2u) {
+ return false;
+ }
+ HInstruction* var_handle_instruction = invoke->InputAt(0);
+ if (var_handle_instruction->IsNullCheck()) {
+ var_handle_instruction = var_handle_instruction->InputAt(0);
+ }
+ if (!var_handle_instruction->IsStaticFieldGet()) {
+ return false;
+ }
+ ArtField* field = var_handle_instruction->AsStaticFieldGet()->GetFieldInfo().GetField();
+ DCHECK(field->IsStatic());
+ if (!field->IsFinal()) {
+ return false;
+ }
+ ScopedObjectAccess soa(Thread::Current());
+ ObjPtr<mirror::Class> declaring_class = field->GetDeclaringClass();
+ if (!declaring_class->IsVisiblyInitialized()) {
+ // During AOT compilation, dex2oat ensures that initialized classes are visibly initialized.
+ DCHECK(!declaring_class->IsInitialized());
+ return false;
+ }
+ HLoadClass* load_class = var_handle_instruction->InputAt(0)->AsLoadClass();
+ if (kIsDebugBuild) {
+ bool is_in_boot_image = false;
+ if (Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(declaring_class)) {
+ is_in_boot_image = true;
+ } else if (compiler_options.IsBootImage() || compiler_options.IsBootImageExtension()) {
+ std::string storage;
+ const char* descriptor = declaring_class->GetDescriptor(&storage);
+ is_in_boot_image = compiler_options.IsImageClass(descriptor);
+ }
+ CHECK_EQ(is_in_boot_image, load_class->IsInBootImage());
+ }
+ if (!load_class->IsInBootImage()) {
+ return false;
+ }
+
+ // Get the `VarHandle` object and check its class.
+ ObjPtr<mirror::Class> expected_var_handle_class;
+ switch (expected_coordinates_count) {
+ case 0:
+ expected_var_handle_class = GetClassRoot<mirror::StaticFieldVarHandle>();
+ break;
+ default:
+ DCHECK_EQ(expected_coordinates_count, 1u);
+ expected_var_handle_class = GetClassRoot<mirror::FieldVarHandle>();
+ break;
+ }
+ ObjPtr<mirror::Object> var_handle_object = field->GetObject(declaring_class);
+ if (var_handle_object == nullptr || var_handle_object->GetClass() != expected_var_handle_class) {
+ return false;
+ }
+ ObjPtr<mirror::VarHandle> var_handle = ObjPtr<mirror::VarHandle>::DownCast(var_handle_object);
+
+ // Check access mode.
+ mirror::VarHandle::AccessMode access_mode =
+ mirror::VarHandle::GetAccessModeByIntrinsic(invoke->GetIntrinsic());
+ if (!var_handle->IsAccessModeSupported(access_mode)) {
+ return false;
+ }
+
+ // Check argument types.
+ ObjPtr<mirror::Class> var_type = var_handle->GetVarType();
+ mirror::VarHandle::AccessModeTemplate access_mode_template =
+ mirror::VarHandle::GetAccessModeTemplate(access_mode);
+ // Note: The data type of input arguments does not need to match the type from shorty
+ // due to implicit conversions or avoiding unnecessary conversions before narrow stores.
+ DataType::Type type = (access_mode_template == mirror::VarHandle::AccessModeTemplate::kGet)
+ ? invoke->GetType()
+ : GetDataTypeFromShorty(invoke, invoke->GetNumberOfArguments() - 1u);
+ if (type != DataTypeFromPrimitive(var_type->GetPrimitiveType())) {
+ return false;
+ }
+ if (type == DataType::Type::kReference) {
+ uint32_t arguments_start = /* VarHandle object */ 1u + expected_coordinates_count;
+ uint32_t number_of_arguments = invoke->GetNumberOfArguments();
+ for (size_t arg_index = arguments_start; arg_index != number_of_arguments; ++arg_index) {
+ HInstruction* arg = invoke->InputAt(arg_index);
+ DCHECK_EQ(arg->GetType(), DataType::Type::kReference);
+ if (!arg->IsNullConstant()) {
+ ReferenceTypeInfo arg_type_info = arg->GetReferenceTypeInfo();
+ if (!arg_type_info.IsValid() ||
+ !var_type->IsAssignableFrom(arg_type_info.GetTypeHandle().Get())) {
+ return false;
+ }
+ }
+ }
+ }
+
+ // Check the first coordinate.
+ if (expected_coordinates_count != 0u) {
+ ObjPtr<mirror::Class> coordinate0_type = var_handle->GetCoordinateType0();
+ DCHECK(coordinate0_type != nullptr);
+ ReferenceTypeInfo object_type_info = invoke->InputAt(1)->GetReferenceTypeInfo();
+ if (!object_type_info.IsValid() ||
+ !coordinate0_type->IsAssignableFrom(object_type_info.GetTypeHandle().Get())) {
+ return false;
+ }
+ }
+
+ // All required checks passed.
+ return true;
}
void InstructionSimplifierVisitor::VisitInvoke(HInvoke* instruction) {