Avoid VarHandle checks for boot image field VarHandles.

And use the field offset as seen at compile time.

Implemented for x86-64, arm and arm64 but not for x86
with incomplete set of `VarHandle` intrinsics.

Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Test: run-gtests.sh
Test: testrunner.py --target --optimizing
Bug: 191765508
Change-Id: If68b0287c8823e69c493dcefb7e61dc34d69fb4f
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index 8794d5a..17cf3d3 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -171,6 +171,11 @@
   dex::TypeIndex type_index = load_class->GetTypeIndex();
   const CompilerOptions& compiler_options = codegen->GetCompilerOptions();
 
+  auto is_class_in_current_boot_image = [&]() {
+    return (compiler_options.IsBootImage() || compiler_options.IsBootImageExtension()) &&
+           compiler_options.IsImageClass(dex_file.StringByTypeIdx(type_index));
+  };
+
   bool is_in_boot_image = false;
   HLoadClass::LoadKind desired_load_kind = HLoadClass::LoadKind::kInvalid;
 
@@ -181,12 +186,17 @@
     // locations of target classes. The additional register pressure
     // for using the ArtMethod* should be considered.
     desired_load_kind = HLoadClass::LoadKind::kReferrersClass;
+    // Determine whether the referrer's class is in the boot image.
+    is_in_boot_image = is_class_in_current_boot_image();
   } else if (load_class->NeedsAccessCheck()) {
     DCHECK_EQ(load_class->GetLoadKind(), HLoadClass::LoadKind::kRuntimeCall);
     if (klass != nullptr) {
       // Resolved class that needs access check must be really inaccessible
       // and the access check is bound to fail. Just emit the runtime call.
       desired_load_kind = HLoadClass::LoadKind::kRuntimeCall;
+      // Determine whether the class is in the boot image.
+      is_in_boot_image = Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass.Get()) ||
+                         is_class_in_current_boot_image();
     } else if (compiler_options.IsJitCompiler()) {
       // Unresolved class while JITting means that either we never hit this
       // instruction or it failed. Either way, just emit the runtime call.
@@ -222,6 +232,9 @@
       if (!compiler_options.GetCompilePic()) {
         // Test configuration, do not sharpen.
         desired_load_kind = HLoadClass::LoadKind::kRuntimeCall;
+        // Determine whether the class is in the boot image.
+        is_in_boot_image = Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass.Get()) ||
+                           is_class_in_current_boot_image();
       } else if (klass != nullptr && runtime->GetHeap()->ObjectIsInBootImageSpace(klass.Get())) {
         DCHECK(compiler_options.IsBootImageExtension());
         is_in_boot_image = true;