Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  class_linker_test.cc

  Sprache: C
 

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "class_linker.h"

#include <memory>
#include <string>
#include <string_view>

#include "android-base/strings.h"
#include "art_field-inl.h"
#include "art_method-inl.h"
#include "base/pointer_size.h"
#include "class_linker-inl.h"
#include "class_root-inl.h"
#include "common_runtime_test.h"
#include "dex/dex_file_types.h"
#include "dex/signature-inl.h"
#include "dex/standard_dex_file.h"
#include "entrypoints/entrypoint_utils-inl.h"
#include "experimental_flags.h"
#include "gc/heap.h"
#include "handle_scope-inl.h"
#include "mirror/accessible_object.h"
#include "mirror/array-alloc-inl.h"
#include "mirror/call_site.h"
#include "mirror/class-inl.h"
#include "mirror/class_ext.h"
#include "mirror/dex_cache.h"
#include "mirror/emulated_stack_frame.h"
#include "mirror/executable.h"
#include "mirror/field.h"
#include "mirror/method_handle_impl.h"
#include "mirror/method_handles_lookup.h"
#include "mirror/method_type-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-alloc-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/proxy.h"
#include "mirror/reference.h"
#include "mirror/stack_frame_info.h"
#include "mirror/stack_trace_element.h"
#include "mirror/string-inl.h"
#include "mirror/var_handle.h"
#include "mirror/virtual_thread_context.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-current-inl.h"

namespace art HIDDEN {

class ClassLinkerTest : public CommonRuntimeTest {
 protected:
  void AssertNonExistentClass(const std::string& descriptor)
      REQUIRES_SHARED(Locks::mutator_lock_) {
    Thread* self = Thread::Current();
    EXPECT_TRUE(class_linker_->FindSystemClass(self, descriptor.c_str()) == nullptr);
    EXPECT_TRUE(self->IsExceptionPending());
    StackHandleScope<1> hs(self);
    Handle<mirror::Object> exception = hs.NewHandle<mirror::Object>(self->GetException());
    self->ClearException();
    ObjPtr<mirror::Class> exception_class =
        class_linker_->FindSystemClass(self, "Ljava/lang/NoClassDefFoundError;");
    EXPECT_TRUE(exception->InstanceOf(exception_class));
  }

  void AssertPrimitiveClass(const std::string& descriptor)
      REQUIRES_SHARED(Locks::mutator_lock_) {
    Thread* self = Thread::Current();
    AssertPrimitiveClass(descriptor, class_linker_->FindSystemClass(self, descriptor.c_str()));
  }

  void AssertPrimitiveClass(const std::string& descriptor, ObjPtr<mirror::Class> primitive)
      REQUIRES_SHARED(Locks::mutator_lock_) {
    ASSERT_TRUE(primitive != nullptr);
    ASSERT_TRUE(primitive->GetClass() != nullptr);
    ASSERT_OBJ_PTR_EQ(primitive->GetClass(), primitive->GetClass()->GetClass());
    EXPECT_TRUE(primitive->GetClass()->GetSuperClass() != nullptr);
    std::string temp;
    ASSERT_STREQ(descriptor.c_str(), primitive->GetDescriptor(&temp));
    EXPECT_TRUE(primitive->GetSuperClass() == nullptr);
    EXPECT_FALSE(primitive->HasSuperClass());
    EXPECT_TRUE(primitive->GetClassLoader() == nullptr);
    EXPECT_EQ(ClassStatus::kVisiblyInitialized, primitive->GetStatus());
    EXPECT_FALSE(primitive->IsErroneous());
    EXPECT_TRUE(primitive->IsLoaded());
    EXPECT_TRUE(primitive->IsResolved());
    EXPECT_FALSE(primitive->IsErroneousResolved());
    EXPECT_TRUE(primitive->IsVerified());
    EXPECT_TRUE(primitive->IsInitialized());
    EXPECT_FALSE(primitive->IsArrayInstance());
    EXPECT_FALSE(primitive->IsArrayClass());
    EXPECT_TRUE(primitive->GetComponentType() == nullptr);
    EXPECT_FALSE(primitive->IsInterface());
    EXPECT_TRUE(primitive->IsPublic());
    EXPECT_TRUE(primitive->IsFinal());
    EXPECT_TRUE(primitive->IsPrimitive());
    EXPECT_FALSE(primitive->IsSynthetic());
    EXPECT_EQ(0U, primitive->NumDirectMethods());
    EXPECT_EQ(0U, primitive->NumVirtualMethods());
    EXPECT_EQ(0U, primitive->NumFields());
    EXPECT_EQ(0U, primitive->NumDirectInterfaces());
    EXPECT_FALSE(primitive->HasVTable());
    EXPECT_EQ(0, primitive->GetIfTableCount());
    EXPECT_TRUE(primitive->GetIfTable() != nullptr);
    EXPECT_EQ(primitive->GetIfTable()->Count(), 0u);
    EXPECT_EQ(kAccPublic | kAccFinal | kAccAbstract, primitive->GetAccessFlags());
  }

  void AssertObjectClass(ObjPtr<mirror::Class> JavaLangObject)
      REQUIRES_SHARED(Locks::mutator_lock_) {
    ASSERT_TRUE(JavaLangObject != nullptr);
    ASSERT_TRUE(JavaLangObject->GetClass() != nullptr);
    ASSERT_OBJ_PTR_EQ(JavaLangObject->GetClass(), JavaLangObject->GetClass()->GetClass());
    EXPECT_OBJ_PTR_EQ(JavaLangObject, JavaLangObject->GetClass()->GetSuperClass());
    std::string temp;
    ASSERT_STREQ(JavaLangObject->GetDescriptor(&temp), "Ljava/lang/Object;");
    EXPECT_TRUE(JavaLangObject->GetSuperClass() == nullptr);
    EXPECT_FALSE(JavaLangObject->HasSuperClass());
    EXPECT_TRUE(JavaLangObject->GetClassLoader() == nullptr);
    {
      Thread* self = Thread::Current();
      StackHandleScope<1> hs(self);
      HandleWrapperObjPtr<mirror::Class> h(hs.NewHandleWrapper(&JavaLangObject));
      ScopedThreadSuspension sts(self, ThreadState::kNative);
      class_linker_->MakeInitializedClassesVisiblyInitialized(self, /*wait=*/ true);
      // HandleWrapperObjPtr restores JavaLangObject here after becoming runnable again.
    }
    EXPECT_EQ(ClassStatus::kVisiblyInitialized, JavaLangObject->GetStatus());
    EXPECT_FALSE(JavaLangObject->IsErroneous());
    EXPECT_TRUE(JavaLangObject->IsLoaded());
    EXPECT_TRUE(JavaLangObject->IsResolved());
    EXPECT_FALSE(JavaLangObject->IsErroneousResolved());
    EXPECT_TRUE(JavaLangObject->IsVerified());
    EXPECT_TRUE(JavaLangObject->IsInitialized());
    EXPECT_FALSE(JavaLangObject->IsArrayInstance());
    EXPECT_FALSE(JavaLangObject->IsArrayClass());
    EXPECT_TRUE(JavaLangObject->GetComponentType() == nullptr);
    EXPECT_FALSE(JavaLangObject->IsInterface());
    EXPECT_TRUE(JavaLangObject->IsPublic());
    EXPECT_FALSE(JavaLangObject->IsFinal());
    EXPECT_FALSE(JavaLangObject->IsPrimitive());
    EXPECT_FALSE(JavaLangObject->IsSynthetic());
    EXPECT_EQ(4U, JavaLangObject->NumDirectMethods());
    EXPECT_EQ(11U, JavaLangObject->NumVirtualMethods());
    EXPECT_EQ(2U, JavaLangObject->NumFields());
    EXPECT_STREQ(JavaLangObject->GetField(0)->GetName(), "shadow$_klass_");
    EXPECT_FALSE(JavaLangObject->GetField(0)->IsStatic());
    EXPECT_STREQ(JavaLangObject->GetField(1)->GetName(), "shadow$_monitor_");
    EXPECT_FALSE(JavaLangObject->GetField(1)->IsStatic());

    EXPECT_EQ(0U, JavaLangObject->NumDirectInterfaces());

    PointerSize pointer_size = class_linker_->GetImagePointerSize();
    ArtMethod* unimplemented = runtime_->GetImtUnimplementedMethod();
    ImTable* imt = JavaLangObject->GetImt(pointer_size);
    ASSERT_NE(nullptr, imt);
    for (size_t i = 0; i < ImTable::kSize; ++i) {
      ASSERT_EQ(unimplemented, imt->Get(i, pointer_size));
    }
  }

  void AssertArrayClass(const std::string& array_descriptor,
                        const std::string& component_type,
                        ObjPtr<mirror::ClassLoader> class_loader)
      REQUIRES_SHARED(Locks::mutator_lock_) {
    Thread* self = Thread::Current();
    StackHandleScope<2> hs(self);
    Handle<mirror::ClassLoader> loader(hs.NewHandle(class_loader));
    Handle<mirror::Class> array = hs.NewHandle(FindClass(array_descriptor.c_str(), loader));
    std::string temp;
    EXPECT_STREQ(component_type.c_str(), array->GetComponentType()->GetDescriptor(&temp));
    EXPECT_OBJ_PTR_EQ(loader.Get(), array->GetClassLoader());
    EXPECT_EQ(kAccFinal | kAccAbstract, (array->GetAccessFlags() & (kAccFinal | kAccAbstract)));
    AssertArrayClass(array_descriptor, array);
  }

  void AssertArrayClass(const std::string& array_descriptor, Handle<mirror::Class> array)
      REQUIRES_SHARED(Locks::mutator_lock_) {
    ASSERT_TRUE(array != nullptr);
    ASSERT_TRUE(array->GetClass() != nullptr);
    ASSERT_OBJ_PTR_EQ(array->GetClass(), array->GetClass()->GetClass());
    EXPECT_TRUE(array->GetClass()->GetSuperClass() != nullptr);
    std::string temp;
    ASSERT_STREQ(array_descriptor.c_str(), array->GetDescriptor(&temp));
    EXPECT_TRUE(array->GetSuperClass() != nullptr);
    Thread* self = Thread::Current();
    EXPECT_OBJ_PTR_EQ(class_linker_->FindSystemClass(self, "Ljava/lang/Object;"),
                      array->GetSuperClass());
    EXPECT_TRUE(array->HasSuperClass());
    ASSERT_TRUE(array->GetComponentType() != nullptr);
    ASSERT_GT(strlen(array->GetComponentType()->GetDescriptor(&temp)), 0U);
    EXPECT_EQ(ClassStatus::kVisiblyInitialized, array->GetStatus());
    EXPECT_FALSE(array->IsErroneous());
    EXPECT_TRUE(array->IsLoaded());
    EXPECT_TRUE(array->IsResolved());
    EXPECT_FALSE(array->IsErroneousResolved());
    EXPECT_TRUE(array->IsVerified());
    EXPECT_TRUE(array->IsInitialized());
    EXPECT_FALSE(array->IsArrayInstance());
    EXPECT_TRUE(array->IsArrayClass());
    EXPECT_FALSE(array->IsInterface());
    EXPECT_EQ(array->GetComponentType()->IsPublic(), array->IsPublic());
    EXPECT_TRUE(array->IsFinal());
    EXPECT_FALSE(array->IsPrimitive());
    EXPECT_FALSE(array->IsSynthetic());
    EXPECT_EQ(0U, array->NumDirectMethods());
    EXPECT_EQ(0U, array->NumVirtualMethods());
    EXPECT_EQ(0U, array->NumFields());
    EXPECT_EQ(2U, array->NumDirectInterfaces());
    EXPECT_TRUE(array->ShouldHaveImt());
    EXPECT_TRUE(array->ShouldHaveEmbeddedVTable());
    EXPECT_EQ(2, array->GetIfTableCount());
    ASSERT_TRUE(array->GetIfTable() != nullptr);
    ObjPtr<mirror::Class> direct_interface0 = array->GetDirectInterface(0);
    EXPECT_TRUE(direct_interface0 != nullptr);
    EXPECT_STREQ(direct_interface0->GetDescriptor(&temp), "Ljava/lang/Cloneable;");
    ObjPtr<mirror::Class> direct_interface1 = array->GetDirectInterface(1);
    EXPECT_STREQ(direct_interface1->GetDescriptor(&temp), "Ljava/io/Serializable;");
    EXPECT_OBJ_PTR_EQ(class_linker_->FindArrayClass(self, array->GetComponentType()), array.Get());

    PointerSize pointer_size = class_linker_->GetImagePointerSize();
    ObjPtr<mirror::Class> JavaLangObject =
        class_linker_->FindSystemClass(self, "Ljava/lang/Object;");
    ImTable* JavaLangObject_imt = JavaLangObject->GetImt(pointer_size);
    // IMT of a array class should be shared with the IMT of the java.lag.Object
    ASSERT_EQ(JavaLangObject_imt, array->GetImt(pointer_size));
  }

  void AssertMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
    EXPECT_TRUE(method != nullptr);
    EXPECT_TRUE(method->GetDeclaringClass() != nullptr);
    EXPECT_TRUE(method->GetName() != nullptr);
    EXPECT_TRUE(method->GetSignature() != Signature::NoSignature());
  }

  void AssertField(ObjPtr<mirror::Class> klass, ArtField* field)
      REQUIRES_SHARED(Locks::mutator_lock_) {
    EXPECT_TRUE(field != nullptr);
    EXPECT_OBJ_PTR_EQ(klass, field->GetDeclaringClass());
    EXPECT_TRUE(field->GetName() != nullptr);
    EXPECT_TRUE(field->ResolveType() != nullptr);
  }

  void AssertClass(const std::string& descriptor, Handle<mirror::Class> klass)
      REQUIRES_SHARED(Locks::mutator_lock_) {
    std::string temp;
    EXPECT_STREQ(descriptor.c_str(), klass->GetDescriptor(&temp));
    if (descriptor == "Ljava/lang/Object;") {
      EXPECT_FALSE(klass->HasSuperClass());
    } else {
      EXPECT_TRUE(klass->HasSuperClass());
      EXPECT_TRUE(klass->GetSuperClass() != nullptr);
    }
    EXPECT_TRUE(klass->GetClass() != nullptr);
    EXPECT_OBJ_PTR_EQ(klass->GetClass(), klass->GetClass()->GetClass());
    EXPECT_TRUE(klass->GetDexCache() != nullptr);
    EXPECT_TRUE(klass->IsLoaded());
    EXPECT_TRUE(klass->IsResolved());
    EXPECT_FALSE(klass->IsErroneousResolved());
    EXPECT_FALSE(klass->IsErroneous());
    EXPECT_FALSE(klass->IsArrayClass());
    EXPECT_TRUE(klass->GetComponentType() == nullptr);
    EXPECT_TRUE(klass->IsInSamePackage(klass.Get()));
    std::string temp2;
    EXPECT_TRUE(mirror::Class::IsInSamePackage(klass->GetDescriptor(&temp),
                                               klass->GetDescriptor(&temp2)));
    if (klass->IsInterface()) {
      EXPECT_TRUE(klass->IsAbstract());
      for (ArtMethod& m : klass->GetMethods(kRuntimePointerSize)) {
        EXPECT_TRUE(m.IsStatic() || m.IsPrivate() || m.IsVirtual());
      }
    } else {
      if (!klass->IsSynthetic()) {
        EXPECT_NE(0U, klass->NumDirectMethods());
      }
    }
    EXPECT_EQ(klass->IsInterface(), !klass->HasVTable());
    ObjPtr<mirror::IfTable> iftable = klass->GetIfTable();
    for (int i = 0; i < klass->GetIfTableCount(); i++) {
      ObjPtr<mirror::Class> interface = iftable->GetInterface(i);
      ASSERT_TRUE(interface != nullptr);
      if (klass->IsInterface()) {
        EXPECT_EQ(0U, iftable->GetMethodArrayCount(i));
      } else {
        EXPECT_EQ(interface->NumDeclaredVirtualMethods(), iftable->GetMethodArrayCount(i));
      }
    }
    if (klass->IsAbstract()) {
      EXPECT_FALSE(klass->IsFinal());
    } else {
      EXPECT_FALSE(klass->IsAnnotation());
    }
    if (klass->IsFinal()) {
      EXPECT_FALSE(klass->IsAbstract());
      EXPECT_FALSE(klass->IsAnnotation());
    }
    if (klass->IsAnnotation()) {
      EXPECT_FALSE(klass->IsFinal());
      EXPECT_TRUE(klass->IsAbstract());
    }

    EXPECT_FALSE(klass->IsPrimitive());
    EXPECT_TRUE(klass->CanAccess(klass.Get()));

    for (ArtMethod& method : klass->GetDeclaredMethods(kRuntimePointerSize)) {
      AssertMethod(&method);
      EXPECT_NE(method.IsVirtual(), method.IsDirect());
      EXPECT_OBJ_PTR_EQ(klass.Get(), method.GetDeclaringClass());
    }

    for (ArtMethod& method : klass->GetCopiedMethods(kRuntimePointerSize)) {
      AssertMethod(&method);
      EXPECT_FALSE(method.IsDirect());
      EXPECT_TRUE(method.IsCopied());
      EXPECT_TRUE(method.GetDeclaringClass()->IsInterface())
          << "declaring class: " << method.GetDeclaringClass()->PrettyClass();
      EXPECT_TRUE(method.GetDeclaringClass()->IsAssignableFrom(klass.Get()))
          << "declaring class: " << method.GetDeclaringClass()->PrettyClass();
    }

    for (size_t i = 0; i < klass->NumFields(); i++) {
      ArtField* field = klass->GetField(i);
      AssertField(klass.Get(), field);
    }

    // Confirm that all instances field offsets are packed together at the start.
    EXPECT_GE(klass->ComputeNumInstanceFields(), klass->NumReferenceInstanceFields());
    MemberOffset start_ref_offset = klass->GetFirstReferenceInstanceFieldOffset();
    MemberOffset end_ref_offset(start_ref_offset.Uint32Value() +
                                klass->NumReferenceInstanceFields() *
                                    sizeof(mirror::HeapReference<mirror::Object>));
    MemberOffset current_ref_offset = start_ref_offset;
    for (size_t i = 0; i < klass->NumFields(); i++) {
      ArtField* field = klass->GetField(i);
      if (field->IsStatic()) {
        continue;
      }
      ObjPtr<mirror::Class> field_type = field->ResolveType();
      ASSERT_TRUE(field_type != nullptr);
      if (!field->IsPrimitiveType()) {
        ASSERT_TRUE(!field_type->IsPrimitive());
        ASSERT_EQ(current_ref_offset.Uint32Value(), field->GetOffset().Uint32Value());
        if (current_ref_offset.Uint32Value() == end_ref_offset.Uint32Value()) {
          // While Reference.referent is not primitive, the ClassLinker
          // treats it as such so that the garbage collector won't scan it.
          EXPECT_EQ(field->PrettyField(), "java.lang.Object java.lang.ref.Reference.referent");
        } else {
          current_ref_offset = MemberOffset(current_ref_offset.Uint32Value() +
                                            sizeof(mirror::HeapReference<mirror::Object>));
        }
      } else {
        if (field->GetOffset().Uint32Value() < end_ref_offset.Uint32Value()) {
          // Shuffled before references.
          ASSERT_LT(field->GetOffset().Uint32Value(), start_ref_offset.Uint32Value());
          CHECK(!IsAligned<4>(field->GetOffset().Uint32Value()));
        }
      }
    }
    ASSERT_EQ(end_ref_offset.Uint32Value(), current_ref_offset.Uint32Value());

    uint32_t total_num_reference_instance_fields = 0;
    ObjPtr<mirror::Class> k = klass.Get();
    while (k != nullptr) {
      total_num_reference_instance_fields += k->NumReferenceInstanceFields();
      k = k->GetSuperClass();
    }
    EXPECT_GE(total_num_reference_instance_fields, 1U);  // Should always have Object's class.
    if ((klass->GetReferenceInstanceOffsets() & mirror::Class::kVisitReferencesSlowpathMask) == 0 &&
        klass->ShouldHaveEmbeddedVTable()) {
      // The reference instance offsets have a bit set for each reference offset.
      // +1 for Object's class.
      EXPECT_EQ(static_cast<uint32_t>(POPCOUNT(klass->GetReferenceInstanceOffsets())) + 1,
                total_num_reference_instance_fields);
    }
  }

  void AssertDexFileClass(ObjPtr<mirror::ClassLoader> class_loader, const std::string&&nbsp;descriptor)
      REQUIRES_SHARED(Locks::mutator_lock_) {
    ASSERT_FALSE(descriptor.empty());
    Thread* self = Thread::Current();
    StackHandleScope<1> hs(self);
    Handle<mirror::Class> klass(
        hs.NewHandle(class_linker_->FindSystemClass(self, descriptor.c_str())));
    ASSERT_TRUE(klass != nullptr) << " Class: " << descriptor.c_str();
    std::string temp;
    EXPECT_STREQ(descriptor.c_str(), klass->GetDescriptor(&temp));
    EXPECT_OBJ_PTR_EQ(class_loader, klass->GetClassLoader());
    if (klass->IsPrimitive()) {
      AssertPrimitiveClass(descriptor, klass.Get());
    } else if (klass->IsArrayClass()) {
      AssertArrayClass(descriptor, klass);
    } else {
      AssertClass(descriptor, klass);
    }
  }

  void AssertDexFile(const DexFile& dex, ObjPtr<mirror::ClassLoader> class_loader)
      REQUIRES_SHARED(Locks::mutator_lock_) {
    // Verify all the classes defined in this file
    for (size_t i = 0; i < dex.NumClassDefs(); i++) {
      const dex::ClassDef& class_def = dex.GetClassDef(i);
      const char* descriptor = dex.GetClassDescriptor(class_def);
      AssertDexFileClass(class_loader, descriptor);
    }
    // Verify all the types referenced by this file
    for (size_t i = 0; i < dex.NumTypeIds(); i++) {
      const dex::TypeId& type_id = dex.GetTypeId(dex::TypeIndex(i));
      const char* descriptor = dex.GetTypeDescriptor(type_id);
      AssertDexFileClass(class_loader, descriptor);
    }
    TestRootVisitor visitor;
    class_linker_->VisitRoots(&visitor, kVisitRootFlagAllRoots);
  }

  class TestRootVisitor : public SingleRootVisitor {
   public:
    void VisitRoot(mirror::Object* root, [[maybe_unused]] const RootInfo& info) override {
      EXPECT_TRUE(root != nullptr);
    }
  };
};

class ClassLinkerMethodHandlesTest : public ClassLinkerTest {
 protected:
  void SetUpRuntimeOptions(RuntimeOptions* options) override {
    CommonRuntimeTest::SetUpRuntimeOptions(options);
  }
};

struct CheckOffset {
  size_t cpp_offset;
  const char* java_name;
  CheckOffset(size_t c, const char* j) : cpp_offset(c), java_name(j) {}
};

template <typename T>
struct CheckOffsets {
  CheckOffsets(bool is_static_in, const char* class_descriptor_in)
      : is_static(is_static_in), class_descriptor(class_descriptor_in) {}
  bool is_static;
  std::string class_descriptor;
  std::vector<CheckOffset> offsets;

  bool Check() REQUIRES_SHARED(Locks::mutator_lock_) {
    Thread* self = Thread::Current();
    ObjPtr<mirror::Class> klass =
        Runtime::Current()->GetClassLinker()->FindSystemClass(self, class_descriptor.c_str());
    CHECK(klass != nullptr) << class_descriptor;
    CHECK(klass->IsMirrored()) << class_descriptor;

    bool error = false;

    // Classes have a different size due to padding field. Strings are variable length.
    if (!klass->IsClassClass() && !klass->IsStringClass() && !is_static) {
      // The RoundUp is required for some mirror classes that have a gap at the end,
      // such as AccessibleObject, ByteArrayViewVarHandle and ByteBufferViewVarHandle.
      // For example, the AccessibleObject has size 9 according to the class linker.
      // However, the C++ sizeof(AccessibleObject) is 12 bytes due to alignment, even
      // though members in C++ subclasses are actually starting at offset 9.
      //
      // TODO: We could define a subclass with a `uint8_t` member and check its offset instead.
      static constexpr size_t kPackAlignment = 4;
      size_t expected_size = RoundUp(klass->GetObjectSize(), kPackAlignment);
      if (sizeof(T) != expected_size) {
        LOG(ERROR) << "Class size mismatch:"
           << " class=" << class_descriptor
           << " Java=" << expected_size
           << " C++=" << sizeof(T);
        error = true;
      }
    }

    size_t num_fields =
        is_static ? klass->ComputeNumStaticFields() : klass->ComputeNumInstanceFields();
    if (offsets.size() != num_fields) {
      LOG(ERROR) << "Field count mismatch:"
         << " class=" << class_descriptor
         << " Java=" << num_fields
         << " C++=" << offsets.size();
      error = true;
    }

    size_t j = 0;
    for (size_t i = 0; i < offsets.size(); i++) {
      ArtField* field = nullptr;
      do {
        field = klass->GetField(j++);
      } while (field->IsStatic() != is_static);
      std::string_view field_name(field->GetName());
      if (field_name != offsets[i].java_name) {
        error = true;
      }
    }
    j = 0;
    if (error) {
      for (size_t i = 0; i < offsets.size(); i++) {
        CheckOffset& offset = offsets[i];
        ArtField* field = nullptr;
        do {
          field = klass->GetField(j++);
        } while (field->IsStatic() != is_static);
        std::string_view field_name(field->GetName());
        if (field_name != offsets[i].java_name) {
          LOG(ERROR) << "JAVA FIELD ORDER MISMATCH NEXT LINE:";
        }
        LOG(ERROR) << "Java field order:"
           << " i=" << i << " class=" << class_descriptor
           << " Java=" << field_name
           << " CheckOffsets=" << offset.java_name;
      }
    }

    j = 0;
    for (size_t i = 0; i < offsets.size(); i++) {
      CheckOffset& offset = offsets[i];
      ArtField* field = nullptr;
      do {
        field = klass->GetField(j++);
      } while (field->IsStatic() != is_static);
      if (field->GetOffset().Uint32Value() != offset.cpp_offset) {
        error = true;
      }
    }
    j = 0;
    if (error) {
      for (size_t i = 0; i < offsets.size(); i++) {
        CheckOffset& offset = offsets[i];
        ArtField* field = nullptr;
        do {
          field = klass->GetField(j++);
        } while (field->IsStatic() != is_static);
        if (field->GetOffset().Uint32Value() != offset.cpp_offset) {
          LOG(ERROR) << "OFFSET MISMATCH NEXT LINE:";
        }
        LOG(ERROR) << "Offset: class=" << class_descriptor << " field=" << offset.java_name
           << " Java=" << field->GetOffset().Uint32Value() << " C++=" << offset.cpp_offset;
      }
    }

    return !error;
  };

  void addOffset(size_t offset, const char* name) {
    offsets.push_back(CheckOffset(offset, name));
  }

 private:
  DISALLOW_IMPLICIT_CONSTRUCTORS(CheckOffsets);
};

// Note that ClassLinkerTest.ValidateFieldOrderOfJavaCppUnionClasses
// is first since if it is failing, others are unlikely to succeed.

struct ObjectOffsets : public CheckOffsets<mirror::Object> {
  ObjectOffsets() : CheckOffsets<mirror::Object>(false"Ljava/lang/Object;") {
    addOffset(OFFSETOF_MEMBER(mirror::Object, klass_), "shadow$_klass_");
    addOffset(OFFSETOF_MEMBER(mirror::Object, monitor_), "shadow$_monitor_");
  }
};

struct ClassOffsets : public CheckOffsets<mirror::Class> {
  ClassOffsets() : CheckOffsets<mirror::Class>(false"Ljava/lang/Class;") {
    addOffset(OFFSETOF_MEMBER(mirror::Class, access_flags_), "accessFlags");
    addOffset(OFFSETOF_MEMBER(mirror::Class, class_flags_), "classFlags");
    addOffset(OFFSETOF_MEMBER(mirror::Class, class_loader_), "classLoader");
    addOffset(OFFSETOF_MEMBER(mirror::Class, class_size_), "classSize");
    addOffset(OFFSETOF_MEMBER(mirror::Class, clinit_thread_id_or_hash_), "clinitThreadIdOrHash");
    addOffset(OFFSETOF_MEMBER(mirror::Class, component_type_), "componentType");
    addOffset(OFFSETOF_MEMBER(mirror::Class, dex_cache_), "dexCache");
    addOffset(OFFSETOF_MEMBER(mirror::Class, dex_class_def_idx_), "dexClassDefIndex");
    addOffset(OFFSETOF_MEMBER(mirror::Class, dex_type_idx_), "dexTypeIndex");
    addOffset(OFFSETOF_MEMBER(mirror::Class, ext_data_), "extData");
    addOffset(OFFSETOF_MEMBER(mirror::Class, fields_), "fields");
    addOffset(OFFSETOF_MEMBER(mirror::Class, iftable_), "ifTable");
    addOffset(OFFSETOF_MEMBER(mirror::Class, methods_), "methods");
    addOffset(OFFSETOF_MEMBER(mirror::Class, name_), "name");
    addOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_instance_fields_),
              "numReferenceInstanceFields");
    addOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_static_fields_),
              "numReferenceStaticFields");
    addOffset(OFFSETOF_MEMBER(mirror::Class, object_size_), "objectSize");
    addOffset(OFFSETOF_MEMBER(mirror::Class, object_size_alloc_fast_path_),
              "objectSizeAllocFastPath");
    addOffset(OFFSETOF_MEMBER(mirror::Class, primitive_type_), "primitiveType");
    addOffset(OFFSETOF_MEMBER(mirror::Class, reference_instance_offsets_),
              "referenceInstanceOffsets");
    addOffset(OFFSETOF_MEMBER(mirror::Class, status_), "status");
    addOffset(OFFSETOF_MEMBER(mirror::Class, super_class_), "superClass");
    addOffset(OFFSETOF_MEMBER(mirror::Class, vtable_), "vtable");
  }
};

struct ClassExtOffsets : public CheckOffsets<mirror::ClassExt> {
  ClassExtOffsets() : CheckOffsets<mirror::ClassExt>(false"Ldalvik/system/ClassExt;"{
    addOffset(OFFSETOF_MEMBER(mirror::ClassExt, class_value_map_), "classValueMap");
    addOffset(OFFSETOF_MEMBER(mirror::ClassExt, erroneous_state_error_), "erroneousStateError");
    addOffset(OFFSETOF_MEMBER(mirror::ClassExt, instance_jfield_ids_), "instanceJfieldIDs");
    addOffset(OFFSETOF_MEMBER(mirror::ClassExt, jmethod_ids_), "jmethodIDs");
    addOffset(OFFSETOF_MEMBER(mirror::ClassExt, obsolete_class_), "obsoleteClass");
    addOffset(OFFSETOF_MEMBER(mirror::ClassExt, obsolete_dex_caches_), "obsoleteDexCaches");
    addOffset(OFFSETOF_MEMBER(mirror::ClassExt, obsolete_methods_), "obsoleteMethods");
    addOffset(OFFSETOF_MEMBER(mirror::ClassExt, original_dex_file_), "originalDexFile");
    addOffset(OFFSETOF_MEMBER(mirror::ClassExt, pre_redefine_class_def_index_),
              "preRedefineClassDefIndex");
    addOffset(OFFSETOF_MEMBER(mirror::ClassExt, pre_redefine_dex_file_ptr_),
              "preRedefineDexFilePtr");
    addOffset(OFFSETOF_MEMBER(mirror::ClassExt, static_jfield_ids_), "staticJfieldIDs");
  }
};

struct StringOffsets : public CheckOffsets<mirror::String> {
  StringOffsets() : CheckOffsets<mirror::String>(false"Ljava/lang/String;") {
    addOffset(OFFSETOF_MEMBER(mirror::String, count_), "count");
    addOffset(OFFSETOF_MEMBER(mirror::String, hash_code_), "hash");
  }
};

struct ThrowableOffsets : public CheckOffsets<mirror::Throwable> {
  ThrowableOffsets() : CheckOffsets<mirror::Throwable>(false"Ljava/lang/Throwable;") {
    addOffset(OFFSETOF_MEMBER(mirror::Throwable, backtrace_), "backtrace");
    addOffset(OFFSETOF_MEMBER(mirror::Throwable, cause_), "cause");
    addOffset(OFFSETOF_MEMBER(mirror::Throwable, detail_message_), "detailMessage");
    addOffset(OFFSETOF_MEMBER(mirror::Throwable, stack_trace_), "stackTrace");
    addOffset(OFFSETOF_MEMBER(mirror::Throwable, suppressed_exceptions_), "suppressedExceptions");
  }
};

struct StackTraceElementOffsets : public CheckOffsets<mirror::StackTraceElement> {
  StackTraceElementOffsets() : CheckOffsets<mirror::StackTraceElement>(
      false"Ljava/lang/StackTraceElement;") {
    addOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, declaring_class_), "declaringClass");
    addOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, file_name_), "fileName");
    addOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, line_number_), "lineNumber");
    addOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, method_name_), "methodName");
  }
};

struct StackFrameInfoOffsets : public CheckOffsets<mirror::StackFrameInfo> {
  StackFrameInfoOffsets() : CheckOffsets<mirror::StackFrameInfo>(
      false"Ljava/lang/StackFrameInfo;") {
    addOffset(OFFSETOF_MEMBER(mirror::StackFrameInfo, bci_), "bci");
    addOffset(OFFSETOF_MEMBER(mirror::StackFrameInfo, declaring_class_), "declaringClass");
    addOffset(OFFSETOF_MEMBER(mirror::StackFrameInfo, file_name_), "fileName");
    addOffset(OFFSETOF_MEMBER(mirror::StackFrameInfo, line_number_), "lineNumber");
    addOffset(OFFSETOF_MEMBER(mirror::StackFrameInfo, method_name_), "methodName");
    addOffset(OFFSETOF_MEMBER(mirror::StackFrameInfo, method_type_), "methodType");
    addOffset(OFFSETOF_MEMBER(mirror::StackFrameInfo, retain_class_ref_), "retainClassRef");
    addOffset(OFFSETOF_MEMBER(mirror::StackFrameInfo, ste_), "ste");
  }
};

struct ClassLoaderOffsets : public CheckOffsets<mirror::ClassLoader> {
  ClassLoaderOffsets() : CheckOffsets<mirror::ClassLoader>(false"Ljava/lang/ClassLoader;") {
    addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, allocator_), "allocator");
    addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, class_table_), "classTable");
    addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, name_), "name");
    addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, packages_), "packages");
    addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, parent_), "parent");
    addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, proxyCache_), "proxyCache");
  }
};

struct ProxyOffsets : public CheckOffsets<mirror::Proxy> {
  ProxyOffsets() : CheckOffsets<mirror::Proxy>(false"Ljava/lang/reflect/Proxy;") {
    addOffset(OFFSETOF_MEMBER(mirror::Proxy, h_), "h");
  }
};

struct DexCacheOffsets : public CheckOffsets<mirror::DexCache> {
  DexCacheOffsets() : CheckOffsets<mirror::DexCache>(false"Ljava/lang/DexCache;") {
    addOffset(OFFSETOF_MEMBER(mirror::DexCache, class_loader_), "classLoader");
    addOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_file_), "dexFile");
    addOffset(OFFSETOF_MEMBER(mirror::DexCache, location_), "location");
    addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_call_sites_), "resolvedCallSites");
    addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_fields_), "resolvedFields");
    addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_fields_array_), "resolvedFieldsArray");
    addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_method_types_), "resolvedMethodTypes");
    addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_method_types_array_),
              "resolvedMethodTypesArray");
    addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_methods_), "resolvedMethods");
    addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_methods_array_), "resolvedMethodsArray");
    addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_types_), "resolvedTypes");
    addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_types_array_), "resolvedTypesArray");
    addOffset(OFFSETOF_MEMBER(mirror::DexCache, strings_), "strings");
    addOffset(OFFSETOF_MEMBER(mirror::DexCache, strings_array_), "stringsArray");
  }
};

struct ReferenceOffsets : public CheckOffsets<mirror::Reference> {
  ReferenceOffsets() : CheckOffsets<mirror::Reference>(false"Ljava/lang/ref/Reference;") {
    addOffset(OFFSETOF_MEMBER(mirror::Reference, pending_next_), "pendingNext");
    addOffset(OFFSETOF_MEMBER(mirror::Reference, queue_), "queue");
    addOffset(OFFSETOF_MEMBER(mirror::Reference, queue_next_), "queueNext");
    addOffset(OFFSETOF_MEMBER(mirror::Reference, referent_), "referent");
  }
};

struct FinalizerReferenceOffsets : public CheckOffsets<mirror::FinalizerReference> {
  FinalizerReferenceOffsets() : CheckOffsets<mirror::FinalizerReference>(
      false"Ljava/lang/ref/FinalizerReference;") {
    addOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, next_), "next");
    addOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, prev_), "prev");
    addOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, zombie_), "zombie");
  }
};

struct AccessibleObjectOffsets : public CheckOffsets<mirror::AccessibleObject> {
  AccessibleObjectOffsets() : CheckOffsets<mirror::AccessibleObject>(
      false"Ljava/lang/reflect/AccessibleObject;") {
    addOffset(mirror::AccessibleObject::FlagOffset().Uint32Value(), "override");
  }
};

struct FieldOffsets : public CheckOffsets<mirror::Field> {
  FieldOffsets() : CheckOffsets<mirror::Field>(false"Ljava/lang/reflect/Field;") {
    addOffset(OFFSETOF_MEMBER(mirror::Field, access_flags_), "accessFlags");
    addOffset(OFFSETOF_MEMBER(mirror::Field, art_field_index_), "artFieldIndex");
    addOffset(OFFSETOF_MEMBER(mirror::Field, declaring_class_), "declaringClass");
    addOffset(OFFSETOF_MEMBER(mirror::Field, offset_), "offset");
    addOffset(OFFSETOF_MEMBER(mirror::Field, type_), "type");
  }
};

struct ExecutableOffsets : public CheckOffsets<mirror::Executable> {
  ExecutableOffsets() : CheckOffsets<mirror::Executable>(
      false"Ljava/lang/reflect/Executable;") {
    addOffset(OFFSETOF_MEMBER(mirror::Executable, access_flags_), "accessFlags");
    addOffset(OFFSETOF_MEMBER(mirror::Executable, art_method_), "artMethod");
    addOffset(OFFSETOF_MEMBER(mirror::Executable, declaring_class_), "declaringClass");
    addOffset(OFFSETOF_MEMBER(mirror::Executable, declaring_class_of_overridden_method_),
              "declaringClassOfOverriddenMethod");
    addOffset(OFFSETOF_MEMBER(mirror::Executable, dex_method_index_), "dexMethodIndex");
    addOffset(OFFSETOF_MEMBER(mirror::Executable, has_real_parameter_data_),
              "hasRealParameterData");
    addOffset(OFFSETOF_MEMBER(mirror::Executable, parameters_), "parameters");
  }
};

struct MethodTypeOffsets : public CheckOffsets<mirror::MethodType> {
  MethodTypeOffsets() : CheckOffsets<mirror::MethodType>(
      false"Ljava/lang/invoke/MethodType;") {
    addOffset(OFFSETOF_MEMBER(mirror::MethodType, form_), "form");
    addOffset(OFFSETOF_MEMBER(mirror::MethodType, method_descriptor_), "methodDescriptor");
    addOffset(OFFSETOF_MEMBER(mirror::MethodType, p_types_), "ptypes");
    addOffset(OFFSETOF_MEMBER(mirror::MethodType, r_type_), "rtype");
    addOffset(OFFSETOF_MEMBER(mirror::MethodType, wrap_alt_), "wrapAlt");
  }
};

struct MethodHandleOffsets : public CheckOffsets<mirror::MethodHandle> {
  MethodHandleOffsets() : CheckOffsets<mirror::MethodHandle>(
      false"Ljava/lang/invoke/MethodHandle;") {
    addOffset(OFFSETOF_MEMBER(mirror::MethodHandle, art_field_or_method_), "artFieldOrMethod");
    addOffset(OFFSETOF_MEMBER(mirror::MethodHandle, as_type_cache_), "asTypeCache");
    addOffset(OFFSETOF_MEMBER(mirror::MethodHandle, cached_spread_invoker_),
              "cachedSpreadInvoker");
    addOffset(OFFSETOF_MEMBER(mirror::MethodHandle, handle_kind_), "handleKind");
    addOffset(OFFSETOF_MEMBER(mirror::MethodHandle, method_type_), "type");
  }
};

struct MethodHandleImplOffsets : public CheckOffsets<mirror::MethodHandleImpl> {
  MethodHandleImplOffsets() : CheckOffsets<mirror::MethodHandleImpl>(
      false"Ljava/lang/invoke/MethodHandleImpl;") {
    addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, field_), "field");
    addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, target_), "target");
    addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, target_class_or_info_),
              "targetClassOrMethodHandleInfo");
  }
};

struct MethodHandlesLookupOffsets : public CheckOffsets<mirror::MethodHandlesLookup> {
  MethodHandlesLookupOffsets() : CheckOffsets<mirror::MethodHandlesLookup>(
      false"Ljava/lang/invoke/MethodHandles$Lookup;") {
    addOffset(OFFSETOF_MEMBER(mirror::MethodHandlesLookup, allowed_modes_), "allowedModes");
    addOffset(OFFSETOF_MEMBER(mirror::MethodHandlesLookup, lookup_class_), "lookupClass");
  }
};

struct EmulatedStackFrameOffsets : public CheckOffsets<mirror::EmulatedStackFrame> {
  EmulatedStackFrameOffsets() : CheckOffsets<mirror::EmulatedStackFrame>(
      false"Ldalvik/system/EmulatedStackFrame;") {
    addOffset(OFFSETOF_MEMBER(mirror::EmulatedStackFrame, references_), "references");
    addOffset(OFFSETOF_MEMBER(mirror::EmulatedStackFrame, stack_frame_), "stackFrame");
    addOffset(OFFSETOF_MEMBER(mirror::EmulatedStackFrame, type_), "type");
  }
};

struct CallSiteOffsets : public CheckOffsets<mirror::CallSite> {
  CallSiteOffsets() : CheckOffsets<mirror::CallSite>(
      false"Ljava/lang/invoke/CallSite;") {
    addOffset(OFFSETOF_MEMBER(mirror::CallSite, target_), "target");
  }
};

struct VarHandleOffsets : public CheckOffsets<mirror::VarHandle> {
  VarHandleOffsets() : CheckOffsets<mirror::VarHandle>(
      false"Ljava/lang/invoke/VarHandle;") {
    addOffset(OFFSETOF_MEMBER(mirror::VarHandle, access_modes_bit_mask_), "accessModesBitMask");
    addOffset(OFFSETOF_MEMBER(mirror::VarHandle, coordinate_type0_), "coordinateType0");
    addOffset(OFFSETOF_MEMBER(mirror::VarHandle, coordinate_type1_), "coordinateType1");
    addOffset(OFFSETOF_MEMBER(mirror::VarHandle, var_type_), "varType");
  }
};

struct FieldVarHandleOffsets : public CheckOffsets<mirror::FieldVarHandle> {
  FieldVarHandleOffsets() : CheckOffsets<mirror::FieldVarHandle>(
      false"Ljava/lang/invoke/FieldVarHandle;") {
    addOffset(OFFSETOF_MEMBER(mirror::FieldVarHandle, art_field_), "artField");
  }
};

struct StaticFieldVarHandleOffsets : public CheckOffsets<mirror::StaticFieldVarHandle> {
  StaticFieldVarHandleOffsets() : CheckOffsets<mirror::StaticFieldVarHandle>(
      false"Ljava/lang/invoke/StaticFieldVarHandle;") {
    addOffset(OFFSETOF_MEMBER(mirror::StaticFieldVarHandle, declaring_class_), "declaringClass");
  }
};

struct ArrayElementVarHandleOffsets : public CheckOffsets<mirror::ArrayElementVarHandle> {
  ArrayElementVarHandleOffsets() : CheckOffsets<mirror::ArrayElementVarHandle>(
      false"Ljava/lang/invoke/ArrayElementVarHandle;") {
  }
};

struct ByteArrayViewVarHandleOffsets : public CheckOffsets<mirror::ByteArrayViewVarHandle> {
  ByteArrayViewVarHandleOffsets() : CheckOffsets<mirror::ByteArrayViewVarHandle>(
      false"Ljava/lang/invoke/ByteArrayViewVarHandle;") {
    addOffset(OFFSETOF_MEMBER(mirror::ByteArrayViewVarHandle, native_byte_order_),
              "nativeByteOrder");
  }
};

struct ByteBufferViewVarHandleOffsets : public CheckOffsets<mirror::ByteBufferViewVarHandle> {
  ByteBufferViewVarHandleOffsets() : CheckOffsets<mirror::ByteBufferViewVarHandle>(
      false"Ljava/lang/invoke/ByteBufferViewVarHandle;") {
    addOffset(OFFSETOF_MEMBER(mirror::ByteBufferViewVarHandle, native_byte_order_),
              "nativeByteOrder");
  }
};

struct MemorySegmentVarHandleOffsets : public CheckOffsets<mirror::MemorySegmentVarHandle> {
  MemorySegmentVarHandleOffsets()
      : CheckOffsets<mirror::MemorySegmentVarHandle>(false,
                                                     "Ljava/lang/invoke/MemorySegmentVarHandle;") {
    addOffset(OFFSETOF_MEMBER(mirror::MemorySegmentVarHandle, byte_alignment_), "byteAlignment");
    addOffset(OFFSETOF_MEMBER(mirror::MemorySegmentVarHandle, native_byte_order_),
              "nativeByteOrder");
  }
};

struct VirtualThreadContextOffsets : public CheckOffsets<mirror::VirtualThreadContext> {
  VirtualThreadContextOffsets()
      : CheckOffsets<mirror::VirtualThreadContext>(false"Ldalvik/system/VirtualThreadContext;") {
    addOffset(OFFSETOF_MEMBER(mirror::VirtualThreadContext, carrier_name_), "carrierName");
    addOffset(OFFSETOF_MEMBER(mirror::VirtualThreadContext, id_), "id");
    addOffset(OFFSETOF_MEMBER(mirror::VirtualThreadContext, monitor_thread_id_), "monitorThreadId");
    addOffset(OFFSETOF_MEMBER(mirror::VirtualThreadContext, monitor_thread_id_cleanable_),
              "monitorThreadIdCleanable");
    addOffset(OFFSETOF_MEMBER(mirror::VirtualThreadContext, parked_states_), "parkedStates");
    addOffset(OFFSETOF_MEMBER(mirror::VirtualThreadContext, pinned_carrier_thread_),
              "pinnedCarrierThread");
    addOffset(OFFSETOF_MEMBER(mirror::VirtualThreadContext, target_), "target");
  }
};

struct VirtualThreadFrameOffsets : public CheckOffsets<mirror::VirtualThreadFrame> {
  VirtualThreadFrameOffsets()
      : CheckOffsets<mirror::VirtualThreadFrame>(false"Ldalvik/system/VirtualThreadFrame;") {
    addOffset(OFFSETOF_MEMBER(mirror::VirtualThreadFrame, declaring_class_), "declaringClass");
    addOffset(OFFSETOF_MEMBER(mirror::VirtualThreadFrame, frame_), "frame");
    addOffset(OFFSETOF_MEMBER(mirror::VirtualThreadFrame, refs_), "refs");
  }
};

// C++ fields must exactly match the fields in the Java classes. If this fails,
// reorder the fields in the C++ class. Managed class fields are ordered by
// ClassLinker::LinkFieldsHelper::LinkFields.
TEST_F(ClassLinkerTest, ValidateFieldOrderOfJavaCppUnionClasses) {
  ScopedObjectAccess soa(Thread::Current());
  EXPECT_TRUE(ObjectOffsets().Check());
  EXPECT_TRUE(ClassOffsets().Check());
  EXPECT_TRUE(ClassExtOffsets().Check());
  EXPECT_TRUE(StringOffsets().Check());
  EXPECT_TRUE(ThrowableOffsets().Check());
  EXPECT_TRUE(StackTraceElementOffsets().Check());
  EXPECT_TRUE(ClassLoaderOffsets().Check());
  EXPECT_TRUE(ProxyOffsets().Check());
  EXPECT_TRUE(DexCacheOffsets().Check());
  EXPECT_TRUE(ReferenceOffsets().Check());
  EXPECT_TRUE(FinalizerReferenceOffsets().Check());
  EXPECT_TRUE(AccessibleObjectOffsets().Check());
  EXPECT_TRUE(FieldOffsets().Check());
  EXPECT_TRUE(ExecutableOffsets().Check());
  EXPECT_TRUE(MethodTypeOffsets().Check());
  EXPECT_TRUE(MethodHandleOffsets().Check());
  EXPECT_TRUE(MethodHandleImplOffsets().Check());
  EXPECT_TRUE(MethodHandlesLookupOffsets().Check());
  EXPECT_TRUE(EmulatedStackFrameOffsets().Check());
  EXPECT_TRUE(CallSiteOffsets().Check());
  EXPECT_TRUE(VarHandleOffsets().Check());
  EXPECT_TRUE(FieldVarHandleOffsets().Check());
  EXPECT_TRUE(ArrayElementVarHandleOffsets().Check());
  EXPECT_TRUE(ByteArrayViewVarHandleOffsets().Check());
  EXPECT_TRUE(ByteBufferViewVarHandleOffsets().Check());
  EXPECT_TRUE(StackFrameInfoOffsets().Check());
  EXPECT_TRUE(MemorySegmentVarHandleOffsets().Check());
  EXPECT_TRUE(VirtualThreadContextOffsets().Check());
  EXPECT_TRUE(VirtualThreadFrameOffsets().Check());
}

TEST_F(ClassLinkerTest, FindClassNonexistent) {
  ScopedObjectAccess soa(Thread::Current());
  AssertNonExistentClass("NoSuchClass;");
  AssertNonExistentClass("LNoSuchClass;");
}

TEST_F(ClassLinkerTest, GetDexFiles) {
  ScopedObjectAccess soa(Thread::Current());

  jobject jclass_loader = LoadDex("Nested");
  std::vector<const DexFile*> dex_files(GetDexFiles(jclass_loader));
  ASSERT_EQ(dex_files.size(), 1U);
  EXPECT_TRUE(dex_files[0]->GetLocation().ends_with("Nested.jar"));

  jobject jclass_loader2 = LoadDex("MultiDex");
  std::vector<const DexFile*> dex_files2(GetDexFiles(jclass_loader2));
  ASSERT_EQ(dex_files2.size(), 2U);
  EXPECT_TRUE(dex_files2[0]->GetLocation().ends_with("MultiDex.jar"));
}

TEST_F(ClassLinkerTest, GetDexFilesFromMultiDexContainer) {
  ScopedObjectAccess soa(Thread::Current());

  jobject jclass_loader = LoadDex("MultiDexContainer");
  std::vector<const DexFile*> dex_files(GetDexFiles(jclass_loader));
  ASSERT_EQ(dex_files.size(), 2U);
  EXPECT_TRUE(dex_files[0]->GetLocation().ends_with("MultiDexContainer.jar"));
}

TEST_F(ClassLinkerTest, FindClassNested) {
  ScopedObjectAccess soa(Thread::Current());
  StackHandleScope<1> hs(soa.Self());
  Handle<mirror::ClassLoader> class_loader(
      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Nested"))));

  ObjPtr<mirror::Class> outer = FindClass("LNested;", class_loader);
  ASSERT_TRUE(outer != nullptr);
  EXPECT_EQ(0U, outer->NumVirtualMethods());
  EXPECT_EQ(1U, outer->NumDirectMethods());

  ObjPtr<mirror::Class> inner = FindClass("LNested$Inner;", class_loader);
  ASSERT_TRUE(inner != nullptr);
  EXPECT_EQ(0U, inner->NumVirtualMethods());
  EXPECT_EQ(1U, inner->NumDirectMethods());
}

TEST_F(ClassLinkerTest, FindClass_Primitives) {
  ScopedObjectAccess soa(Thread::Current());
  const std::string expected("BCDFIJSZV");
  for (int ch = 1; ch < 256; ++ch) {
    std::string descriptor;
    descriptor.push_back(ch);
    if (expected.find(ch) == std::string::npos) {
      AssertNonExistentClass(descriptor);
    } else {
      AssertPrimitiveClass(descriptor);
    }
  }
}

TEST_F(ClassLinkerTest, FindClass) {
  ScopedObjectAccess soa(Thread::Current());
  StackHandleScope<2> hs(soa.Self());
  Handle<mirror::Class> JavaLangObject = hs.NewHandle(
      class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"));
  AssertObjectClass(JavaLangObject.Get());

  Handle<mirror::ClassLoader> class_loader(
      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass"))));
  AssertNonExistentClass("LMyClass;");
  ObjPtr<mirror::Class> MyClass = FindClass("LMyClass;", class_loader);
  ASSERT_TRUE(MyClass != nullptr);
  ASSERT_TRUE(MyClass->GetClass() != nullptr);
  ASSERT_OBJ_PTR_EQ(MyClass->GetClass(), MyClass->GetClass()->GetClass());
  EXPECT_OBJ_PTR_EQ(JavaLangObject.Get(), MyClass->GetClass()->GetSuperClass());
  std::string temp;
  ASSERT_STREQ(MyClass->GetDescriptor(&temp), "LMyClass;");
  EXPECT_OBJ_PTR_EQ(MyClass->GetSuperClass(), JavaLangObject.Get());
  EXPECT_TRUE(MyClass->HasSuperClass());
  EXPECT_OBJ_PTR_EQ(class_loader.Get(), MyClass->GetClassLoader());
  EXPECT_EQ(ClassStatus::kResolved, MyClass->GetStatus());
  EXPECT_FALSE(MyClass->IsErroneous());
  EXPECT_TRUE(MyClass->IsLoaded());
  EXPECT_TRUE(MyClass->IsResolved());
  EXPECT_FALSE(MyClass->IsErroneousResolved());
  EXPECT_FALSE(MyClass->IsVerified());
  EXPECT_FALSE(MyClass->IsInitialized());
  EXPECT_FALSE(MyClass->IsArrayInstance());
  EXPECT_FALSE(MyClass->IsArrayClass());
  EXPECT_TRUE(MyClass->GetComponentType() == nullptr);
  EXPECT_FALSE(MyClass->IsInterface());
  EXPECT_FALSE(MyClass->IsPublic());
  EXPECT_FALSE(MyClass->IsFinal());
  EXPECT_FALSE(MyClass->IsPrimitive());
  EXPECT_FALSE(MyClass->IsSynthetic());
  EXPECT_EQ(1U, MyClass->NumDirectMethods());
  EXPECT_EQ(0U, MyClass->NumVirtualMethods());
  EXPECT_EQ(0U, MyClass->NumFields());
  EXPECT_EQ(0U, MyClass->NumDirectInterfaces());

  EXPECT_OBJ_PTR_EQ(JavaLangObject->GetClass()->GetClass(), MyClass->GetClass()->GetClass());

  // created by class_linker
  AssertArrayClass("[C""C", nullptr);
  AssertArrayClass("[Ljava/lang/Object;""Ljava/lang/Object;", nullptr);
  // synthesized on the fly
  AssertArrayClass("[[C""[C", nullptr);
  AssertArrayClass("[[[LMyClass;""[[LMyClass;", class_loader.Get());
  // or not available at all
  AssertNonExistentClass("[[[[LNonExistentClass;");
}

TEST_F(ClassLinkerTest, LookupResolvedType) {
  ScopedObjectAccess soa(Thread::Current());
  StackHandleScope<1> hs(soa.Self());
  Handle<mirror::ClassLoader> class_loader(
      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass"))));
  AssertNonExistentClass("LMyClass;");
  ObjPtr<mirror::Class> klass = FindClass("LMyClass;", class_loader);
  dex::TypeIndex type_idx = klass->GetClassDef()->class_idx_;
  ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
  EXPECT_OBJ_PTR_EQ(
      class_linker_->LookupResolvedType(type_idx, dex_cache, class_loader.Get()),
      klass);
  // Zero out the resolved type and make sure LookupResolvedType still finds it.
  dex_cache->ClearResolvedType(type_idx);
  EXPECT_TRUE(dex_cache->GetResolvedType(type_idx) == nullptr);
  EXPECT_OBJ_PTR_EQ(
      class_linker_->LookupResolvedType(type_idx, dex_cache, class_loader.Get()),
      klass);
}

TEST_F(ClassLinkerTest, LookupResolvedTypeArray) {
  ScopedObjectAccess soa(Thread::Current());
  StackHandleScope<2> hs(soa.Self());
  Handle<mirror::ClassLoader> class_loader(
      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("AllFields"))));
  // Get the AllFields class for the dex cache and dex file.
  ObjPtr<mirror::Class> all_fields_klass = FindClass("LAllFields;", class_loader);
  ASSERT_TRUE(all_fields_klass != nullptr);
  Handle<mirror::DexCache> dex_cache = hs.NewHandle(all_fields_klass->GetDexCache());
  const DexFile& dex_file = *dex_cache->GetDexFile();
  // Get the index of the array class we want to test.
  const dex::TypeId* array_id = dex_file.FindTypeId("[Ljava/lang/Object;");
  ASSERT_TRUE(array_id != nullptr);
  dex::TypeIndex array_idx = dex_file.GetIndexForTypeId(*array_id);
  // Check that the array class wasn't resolved yet.
  EXPECT_TRUE(
      class_linker_->LookupResolvedType(array_idx, dex_cache.Get(), class_loader.Get()) == nullptr);
  // Resolve the array class we want to test.
  ObjPtr<mirror::Class> array_klass = FindClass("[Ljava/lang/Object;", class_loader);
  ASSERT_TRUE(array_klass != nullptr);
  // Test that LookupResolvedType() finds the array class.
  EXPECT_OBJ_PTR_EQ(
      class_linker_->LookupResolvedType(array_idx, dex_cache.Get(), class_loader.Get()),
      array_klass);
  // Zero out the resolved type and make sure LookupResolvedType() still finds it.
  dex_cache->ClearResolvedType(array_idx);
  EXPECT_TRUE(dex_cache->GetResolvedType(array_idx) == nullptr);
  EXPECT_OBJ_PTR_EQ(
      class_linker_->LookupResolvedType(array_idx, dex_cache.Get(), class_loader.Get()),
      array_klass);
}

TEST_F(ClassLinkerTest, LookupResolvedTypeErroneousInit) {
  ScopedObjectAccess soa(Thread::Current());
  StackHandleScope<3> hs(soa.Self());
  Handle<mirror::ClassLoader> class_loader(
      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("ErroneousInit"))));
  AssertNonExistentClass("LErroneousInit;");
  Handle<mirror::Class> klass = hs.NewHandle(FindClass("LErroneousInit;", class_loader));
  ASSERT_TRUE(klass != nullptr);
  dex::TypeIndex type_idx = klass->GetClassDef()->class_idx_;
  Handle<mirror::DexCache> dex_cache = hs.NewHandle(klass->GetDexCache());
  EXPECT_OBJ_PTR_EQ(
      class_linker_->LookupResolvedType(type_idx, dex_cache.Get(), class_loader.Get()),
      klass.Get());
  // Zero out the resolved type and make sure LookupResolvedType still finds it.
  dex_cache->ClearResolvedType(type_idx);
  EXPECT_TRUE(dex_cache->GetResolvedType(type_idx) == nullptr);
  EXPECT_OBJ_PTR_EQ(
      class_linker_->LookupResolvedType(type_idx, dex_cache.Get(), class_loader.Get()),
      klass.Get());
  // Force initialization to turn the class erroneous.
  bool initialized = class_linker_->EnsureInitialized(soa.Self(),
                                                      klass,
                                                      /* can_init_fields= */ true,
                                                      /* can_init_parents= */ true);
  EXPECT_FALSE(initialized);
  EXPECT_TRUE(soa.Self()->IsExceptionPending());
  soa.Self()->ClearException();
  // Check that the LookupResolvedType() can still find the resolved type.
  EXPECT_OBJ_PTR_EQ(
      class_linker_->LookupResolvedType(type_idx, dex_cache.Get(), class_loader.Get()),
      klass.Get());
  // Zero out the resolved type and make sure LookupResolvedType() still finds it.
  dex_cache->ClearResolvedType(type_idx);
  EXPECT_TRUE(dex_cache->GetResolvedType(type_idx) == nullptr);
  EXPECT_OBJ_PTR_EQ(
      class_linker_->LookupResolvedType(type_idx, dex_cache.Get(), class_loader.Get()),
      klass.Get());
}

TEST_F(ClassLinkerTest, LibCore) {
  ScopedObjectAccess soa(Thread::Current());
  ASSERT_TRUE(java_lang_dex_file_ != nullptr);
  AssertDexFile(*java_lang_dex_file_, nullptr);
}

// The first reference array element must be a multiple of 4 bytes from the
// start of the object
TEST_F(ClassLinkerTest, ValidateObjectArrayElementsOffset) {
  ScopedObjectAccess soa(Thread::Current());
  ObjPtr<mirror::Class> array_class =
      class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;");
  ObjPtr<mirror::ObjectArray<mirror::String>> array =
      mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), array_class, 0);
  uintptr_t data_offset =
      reinterpret_cast<uintptr_t>(array->GetRawData(sizeof(mirror::HeapReference<mirror::String>),
                                                    0));
  if (sizeof(mirror::HeapReference<mirror::String>) == sizeof(int32_t)) {
    EXPECT_TRUE(IsAligned<4>(data_offset));  // Check 4 byte alignment.
  } else {
    EXPECT_TRUE(IsAligned<8>(data_offset));  // Check 8 byte alignment.
  }
}

TEST_F(ClassLinkerTest, ValidatePrimitiveArrayElementsOffset) {
  ScopedObjectAccess soa(Thread::Current());
  StackHandleScope<5> hs(soa.Self());
  Handle<mirror::LongArray> long_array(hs.NewHandle(mirror::LongArray::Alloc(soa.Self(), 0)));
  EXPECT_OBJ_PTR_EQ(class_linker_->FindSystemClass(soa.Self(), "[J"), long_array->GetClass());
  uintptr_t data_offset = reinterpret_cast<uintptr_t>(long_array->GetData());
  EXPECT_TRUE(IsAligned<8>(data_offset));  // Longs require 8 byte alignment

  Handle<mirror::DoubleArray> double_array(hs.NewHandle(mirror::DoubleArray::Alloc(soa.Self(), 0)));
  EXPECT_OBJ_PTR_EQ(class_linker_->FindSystemClass(soa.Self(), "[D"), double_array->GetClass());
  data_offset = reinterpret_cast<uintptr_t>(double_array->GetData());
  EXPECT_TRUE(IsAligned<8>(data_offset));  // Doubles require 8 byte alignment

  Handle<mirror::IntArray> int_array(hs.NewHandle(mirror::IntArray::Alloc(soa.Self(), 0)));
  EXPECT_OBJ_PTR_EQ(class_linker_->FindSystemClass(soa.Self(), "[I"), int_array->GetClass());
  data_offset = reinterpret_cast<uintptr_t>(int_array->GetData());
  EXPECT_TRUE(IsAligned<4>(data_offset));  // Ints require 4 byte alignment

  Handle<mirror::CharArray> char_array(hs.NewHandle(mirror::CharArray::Alloc(soa.Self(), 0)));
  EXPECT_OBJ_PTR_EQ(class_linker_->FindSystemClass(soa.Self(), "[C"), char_array->GetClass());
  data_offset = reinterpret_cast<uintptr_t>(char_array->GetData());
  EXPECT_TRUE(IsAligned<2>(data_offset));  // Chars require 2 byte alignment

  Handle<mirror::ShortArray> short_array(hs.NewHandle(mirror::ShortArray::Alloc(soa.Self(), 0)));
  EXPECT_OBJ_PTR_EQ(class_linker_->FindSystemClass(soa.Self(), "[S"), short_array->GetClass());
  data_offset = reinterpret_cast<uintptr_t>(short_array->GetData());
  EXPECT_TRUE(IsAligned<2>(data_offset));  // Shorts require 2 byte alignment

  // Take it as given that bytes and booleans have byte alignment
}

TEST_F(ClassLinkerTest, TwoClassLoadersOneClass) {
  ScopedObjectAccess soa(Thread::Current());
  StackHandleScope<3> hs(soa.Self());
  Handle<mirror::ClassLoader> class_loader_1(
      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass"))));
  Handle<mirror::ClassLoader> class_loader_2(
      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass"))));
  Handle<mirror::Class> MyClass_1 = hs.NewHandle(FindClass("LMyClass;", class_loader_1));
  ObjPtr<mirror::Class> MyClass_2 = FindClass("LMyClass;", class_loader_2);
  EXPECT_TRUE(MyClass_1 != nullptr);
  EXPECT_TRUE(MyClass_2 != nullptr);
  EXPECT_OBJ_PTR_NE(MyClass_1.Get(), MyClass_2);
}

TEST_F(ClassLinkerTest, StaticFields) {
  ScopedObjectAccess soa(Thread::Current());
  StackHandleScope<2> hs(soa.Self());
  Handle<mirror::ClassLoader> class_loader(
      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Statics"))));
  Handle<mirror::Class> statics = hs.NewHandle(FindClass("LStatics;", class_loader));
  class_linker_->EnsureInitialized(soa.Self(), statics, truetrue);

  // Static final primitives that are initialized by a compile-time constant
  // expression resolve to a copy of a constant value from the constant pool.
  // So <clinit> should be null.
  ArtMethod* clinit = statics->FindClassMethod("<clinit>""()V", kRuntimePointerSize);
  EXPECT_TRUE(clinit == nullptr);

  EXPECT_EQ(9U, statics->NumFields());

  ArtField* s0 = statics->FindStaticField("s0""Z");
  EXPECT_EQ(s0->GetTypeAsPrimitiveType(), Primitive::kPrimBoolean);
  EXPECT_EQ(true, s0->GetBoolean(statics.Get()));
  s0->SetBoolean<false>(statics.Get(), false);

  ArtField* s1 = statics->FindStaticField("s1""B");
  EXPECT_EQ(s1->GetTypeAsPrimitiveType(), Primitive::kPrimByte);
  EXPECT_EQ(5, s1->GetByte(statics.Get()));
  s1->SetByte<false>(statics.Get(), 6);

  ArtField* s2 = statics->FindStaticField("s2""C");
  EXPECT_EQ(s2->GetTypeAsPrimitiveType(), Primitive::kPrimChar);
  EXPECT_EQ('a', s2->GetChar(statics.Get()));
  s2->SetChar<false>(statics.Get(), 'b');

  ArtField* s3 = statics->FindStaticField("s3""S");
  EXPECT_EQ(s3->GetTypeAsPrimitiveType(), Primitive::kPrimShort);
  EXPECT_EQ(-536, s3->GetShort(statics.Get()));
  s3->SetShort<false>(statics.Get(), -535);

  ArtField* s4 = statics->FindStaticField("s4""I");
  EXPECT_EQ(s4->GetTypeAsPrimitiveType(), Primitive::kPrimInt);
  EXPECT_EQ(2000000000, s4->GetInt(statics.Get()));
  s4->SetInt<false>(statics.Get(), 2000000001);

  ArtField* s5 = statics->FindStaticField("s5""J");
  EXPECT_EQ(s5->GetTypeAsPrimitiveType(), Primitive::kPrimLong);
  EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong(statics.Get()));
  s5->SetLong<false>(statics.Get(), INT64_C(0x34567890abcdef12));

  ArtField* s6 = statics->FindStaticField("s6""F");
  EXPECT_EQ(s6->GetTypeAsPrimitiveType(), Primitive::kPrimFloat);
  EXPECT_DOUBLE_EQ(0.5, s6->GetFloat(statics.Get()));
  s6->SetFloat<false>(statics.Get(), 0.75);

  ArtField* s7 = statics->FindStaticField("s7""D");
  EXPECT_EQ(s7->GetTypeAsPrimitiveType(), Primitive::kPrimDouble);
  EXPECT_DOUBLE_EQ(16777217.0, s7->GetDouble(statics.Get()));
  s7->SetDouble<false>(statics.Get(), 16777219);

  ArtField* s8 = statics->FindStaticField("s8""Ljava/lang/String;");
  EXPECT_EQ(s8->GetTypeAsPrimitiveType(), Primitive::kPrimNot);
  EXPECT_TRUE(s8->GetObject(statics.Get())->AsString()->Equals("android"));
  ObjPtr<mirror::String> str_value = mirror::String::AllocFromModifiedUtf8(soa.Self(), "robot");
  s8->SetObject<false>(s8->GetDeclaringClass(), str_value);

  // TODO: Remove EXPECT_FALSE when GCC can handle EXPECT_EQ
  // http://code.google.com/p/googletest/issues/detail?id=322
  EXPECT_FALSE(s0->GetBoolean(statics.Get()));
  EXPECT_EQ(6, s1->GetByte(statics.Get()));
  EXPECT_EQ('b', s2->GetChar(statics.Get()));
  EXPECT_EQ(-535, s3->GetShort(statics.Get()));
  EXPECT_EQ(2000000001, s4->GetInt(statics.Get()));
  EXPECT_EQ(INT64_C(0x34567890abcdef12), s5->GetLong(statics.Get()));
  EXPECT_FLOAT_EQ(0.75, s6->GetFloat(statics.Get()));
  EXPECT_DOUBLE_EQ(16777219.0, s7->GetDouble(statics.Get()));
  EXPECT_TRUE(s8->GetObject(statics.Get())->AsString()->Equals("robot"));
}

TEST_F(ClassLinkerTest, Interfaces) {
  ScopedObjectAccess soa(Thread::Current());
  StackHandleScope<6> hs(soa.Self());
  Handle<mirror::ClassLoader> class_loader(
      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Interfaces"))));
  Handle<mirror::Class> I = hs.NewHandle(FindClass("LInterfaces$I;", class_loader));
  Handle<mirror::Class> J = hs.NewHandle(FindClass("LInterfaces$J;", class_loader));
  Handle<mirror::Class> K = hs.NewHandle(FindClass("LInterfaces$K;", class_loader));
  Handle<mirror::Class> A = hs.NewHandle(FindClass("LInterfaces$A;", class_loader));
  Handle<mirror::Class> B = hs.NewHandle(FindClass("LInterfaces$B;", class_loader));
  EXPECT_TRUE(I->IsAssignableFrom(A.Get()));
  EXPECT_TRUE(J->IsAssignableFrom(A.Get()));
  EXPECT_TRUE(J->IsAssignableFrom(K.Get()));
  EXPECT_TRUE(K->IsAssignableFrom(B.Get()));
  EXPECT_TRUE(J->IsAssignableFrom(B.Get()));

  const std::string_view void_sig("()V");
  ArtMethod* Ii = I->FindClassMethod("i", void_sig, kRuntimePointerSize);
  ArtMethod* Jj1 = J->FindClassMethod("j1", void_sig, kRuntimePointerSize);
  ArtMethod* Jj2 = J->FindClassMethod("j2", void_sig, kRuntimePointerSize);
  ArtMethod* Kj1 = K->FindInterfaceMethod("j1", void_sig, kRuntimePointerSize);
  ArtMethod* Kj2 = K->FindInterfaceMethod("j2", void_sig, kRuntimePointerSize);
  ArtMethod* Kk = K->FindInterfaceMethod("k", void_sig, kRuntimePointerSize);
  ArtMethod* Ai = A->FindClassMethod("i", void_sig, kRuntimePointerSize);
  ArtMethod* Aj1 = A->FindClassMethod("j1", void_sig, kRuntimePointerSize);
  ArtMethod* Aj2 = A->FindClassMethod("j2", void_sig, kRuntimePointerSize);
  ASSERT_TRUE(Ii != nullptr);
  ASSERT_FALSE(Ii->IsDirect());
  ASSERT_TRUE(Jj1 != nullptr);
  ASSERT_FALSE(Jj1->IsDirect());
  ASSERT_TRUE(Jj2 != nullptr);
  ASSERT_FALSE(Jj2->IsDirect());
  ASSERT_TRUE(Kj1 != nullptr);
  ASSERT_TRUE(Kj2 != nullptr);
  ASSERT_TRUE(Kk != nullptr);
  ASSERT_TRUE(Ai != nullptr);
  ASSERT_FALSE(Ai->IsDirect());
  ASSERT_TRUE(Aj1 != nullptr);
  ASSERT_FALSE(Aj1->IsDirect());
  ASSERT_TRUE(Aj2 != nullptr);
  ASSERT_FALSE(Aj2->IsDirect());
  EXPECT_NE(Ii, Ai);
  EXPECT_NE(Jj1, Aj1);
  EXPECT_NE(Jj2, Aj2);
  EXPECT_EQ(Kj1, Jj1);
  EXPECT_EQ(Kj2, Jj2);
  EXPECT_EQ(Ai, A->FindVirtualMethodForInterface(Ii, kRuntimePointerSize));
  EXPECT_EQ(Aj1, A->FindVirtualMethodForInterface(Jj1, kRuntimePointerSize));
  EXPECT_EQ(Aj2, A->FindVirtualMethodForInterface(Jj2, kRuntimePointerSize));
  EXPECT_EQ(Ai, A->FindVirtualMethodForVirtualOrInterface(Ii, kRuntimePointerSize));
  EXPECT_EQ(Aj1, A->FindVirtualMethodForVirtualOrInterface(Jj1, kRuntimePointerSize));
  EXPECT_EQ(Aj2, A->FindVirtualMethodForVirtualOrInterface(Jj2, kRuntimePointerSize));

  ArtField* Afoo = A->FindStaticField("foo""Ljava/lang/String;");
  ArtField* Bfoo = B->FindStaticField("foo""Ljava/lang/String;");
  ArtField* Jfoo = J->FindStaticField("foo""Ljava/lang/String;");
  ArtField* Kfoo = K->FindStaticField("foo""Ljava/lang/String;");
  ASSERT_TRUE(Afoo != nullptr);
  EXPECT_EQ(Afoo, Bfoo);
  EXPECT_EQ(Afoo, Jfoo);
  EXPECT_EQ(Afoo, Kfoo);
}

TEST_F(ClassLinkerTest, ResolveVerifyAndClinit) {
  // pretend we are trying to get the static storage for the StaticsFromCode class.

  // case 1, get the uninitialized storage from StaticsFromCode.<clinit>
  // case 2, get the initialized storage from StaticsFromCode.getS0

  ScopedObjectAccess soa(Thread::Current());
  jobject jclass_loader = LoadDex("StaticsFromCode");
  const DexFile* dex_file = GetFirstDexFile(jclass_loader);
  StackHandleScope<1> hs(soa.Self());
  Handle<mirror::ClassLoader> class_loader(
      hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
  ObjPtr<mirror::Class> klass = FindClass("LStaticsFromCode;", class_loader);
  ArtMethod* clinit = klass->FindClassInitializer(kRuntimePointerSize);
  ArtMethod* getS0 =
      klass->FindClassMethod("getS0""()Ljava/lang/Object;", kRuntimePointerSize);
  ASSERT_TRUE(getS0 != nullptr);
  ASSERT_TRUE(getS0->IsStatic());
  const dex::TypeId* type_id = dex_file->FindTypeId("LStaticsFromCode;");
  ASSERT_TRUE(type_id != nullptr);
  dex::TypeIndex type_idx = dex_file->GetIndexForTypeId(*type_id);
  ObjPtr<mirror::Class> uninit = ResolveVerifyAndClinit(type_idx,
                                                        clinit,
                                                        soa.Self(),
                                                        /* can_run_clinit= */ true,
                                                        /* verify_access= */ false);
  EXPECT_TRUE(uninit != nullptr);
  EXPECT_FALSE(uninit->IsInitialized());
  ObjPtr<mirror::Class> init = ResolveVerifyAndClinit(type_idx,
                                                      getS0,
                                                      soa.Self(),
                                                      /* can_run_clinit= */ true,
                                                      /* verify_access= */ false);
  EXPECT_TRUE(init != nullptr);
  EXPECT_TRUE(init->IsInitialized());
}

TEST_F(ClassLinkerTest, ErroneousClass) {
  ScopedObjectAccess soa(Thread::Current());
  jobject jclass_loader = LoadMultiDex("ErroneousA""ErroneousB");
  StackHandleScope<1> hs(soa.Self());
  Handle<mirror::ClassLoader> class_loader(
      hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
  hs.Self()->AssertNoPendingException();
  const char* descriptor = "LErroneous;";
  ObjPtr<mirror::Class> klass = FindClass(descriptor, class_loader);
  // Erronenous since we are extending final class.
  hs.Self()->AssertPendingException();
  EXPECT_TRUE(klass == nullptr);
  klass = class_linker_->LookupClass(soa.Self(), descriptor, class_loader.Get());
  EXPECT_FALSE(klass == nullptr);
  EXPECT_TRUE(klass->IsErroneous());
  EXPECT_TRUE(klass->GetIfTable() != nullptr);
}

TEST_F(ClassLinkerTest, FinalizableBit) {
  ScopedObjectAccess soa(Thread::Current());
  ObjPtr<mirror::Class> c;

  // Object has a finalize method, but we know it's empty.
  c = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;");
  EXPECT_FALSE(c->IsFinalizable());

  // Enum has a finalize method to prevent its subclasses from implementing one.
  c = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Enum;");
  EXPECT_FALSE(c->IsFinalizable());

  // RoundingMode is an enum.
  c = class_linker_->FindSystemClass(soa.Self(), "Ljava/math/RoundingMode;");
  EXPECT_FALSE(c->IsFinalizable());

  // RandomAccessFile extends Object and overrides finalize.
  c = class_linker_->FindSystemClass(soa.Self(), "Ljava/io/RandomAccessFile;");
  EXPECT_TRUE(c->IsFinalizable());

  // FileInputStream is finalizable and extends InputStream which isn't.
  c = class_linker_->FindSystemClass(soa.Self(), "Ljava/io/InputStream;");
  EXPECT_FALSE(c->IsFinalizable());
  c = class_linker_->FindSystemClass(soa.Self(), "Ljava/io/FileInputStream;");
  EXPECT_TRUE(c->IsFinalizable());

  // ScheduledThreadPoolExecutor doesn't have a finalize method but
  // extends ThreadPoolExecutor which does.
  c = class_linker_->FindSystemClass(soa.Self(), "Ljava/util/concurrent/ThreadPoolExecutor;");
  EXPECT_TRUE(c->IsFinalizable());
  c = class_linker_->FindSystemClass(soa.Self(), "Ljava/util/concurrent/ScheduledThreadPoolExecutor;");
  EXPECT_TRUE(c->IsFinalizable());
}

TEST_F(ClassLinkerTest, ClassRootDescriptors) {
  ScopedObjectAccess soa(Thread::Current());
  std::string temp;
  for (size_t i = 0; i < static_cast<size_t>(ClassRoot::kMax); i++) {
    ObjPtr<mirror::Class> klass = GetClassRoot(ClassRoot(i), class_linker_);
    EXPECT_GT(strlen(klass->GetDescriptor(&temp)), 0U);
    EXPECT_STREQ(klass->GetDescriptor(&temp), GetClassRootDescriptor(ClassRoot(i))) << " i = " << i;
  }
}

TEST_F(ClassLinkerTest, ValidatePredefinedClassSizes) {
  ScopedObjectAccess soa(Thread::Current());
  ScopedNullHandle<mirror::ClassLoader> class_loader;
  ObjPtr<mirror::Class> c;

  c = FindClass("Ljava/lang/Class;", class_loader);
  ASSERT_TRUE(c != nullptr);
  EXPECT_EQ(c->GetClassSize(), mirror::Class::ClassClassSize(kRuntimePointerSize));

  c = FindClass("Ljava/lang/Object;", class_loader);
  ASSERT_TRUE(c != nullptr);
  EXPECT_EQ(c->GetClassSize(), mirror::Object::ClassSize(kRuntimePointerSize));

  c = FindClass("Ljava/lang/String;", class_loader);
  ASSERT_TRUE(c != nullptr);
  EXPECT_EQ(c->GetClassSize(), mirror::String::ClassSize(kRuntimePointerSize));

  c = FindClass("Ljava/lang/DexCache;", class_loader);
  ASSERT_TRUE(c != nullptr);
  EXPECT_EQ(c->GetClassSize(), mirror::DexCache::ClassSize(kRuntimePointerSize));
}

static void CheckMethod(ArtMethod* method, bool verified)
    REQUIRES_SHARED(Locks::mutator_lock_) {
  if (!method->IsNative() && !method->IsAbstract()) {
    EXPECT_EQ((method->GetAccessFlags() & kAccSkipAccessChecks) != 0U, verified)
        << method->PrettyMethod(true);
  }
}

static void CheckVerificationAttempted(ObjPtr<mirror::Class> c, bool preverified)
    REQUIRES_SHARED(Locks::mutator_lock_) {
  for (auto& m : c->GetMethods(kRuntimePointerSize)) {
    CheckMethod(&m, preverified);
  }
}

TEST_F(ClassLinkerTest, Preverified_InitializedBoot) {
  ScopedObjectAccess soa(Thread::Current());

  ObjPtr<mirror::Class> JavaLangObject =
      class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;");
  ASSERT_TRUE(JavaLangObject != nullptr);
  EXPECT_TRUE(JavaLangObject->IsInitialized()) << "Not testing already initialized class from the "
                                                  "core";
  CheckVerificationAttempted(JavaLangObject, true);
}

TEST_F(ClassLinkerTest, Preverified_UninitializedBoot) {
  ScopedObjectAccess soa(Thread::Current());

  StackHandleScope<1> hs(soa.Self());

  Handle<mirror::Class> security_manager(hs.NewHandle(class_linker_->FindSystemClass(
      soa.Self(), "Ljava/lang/SecurityManager;")));
  EXPECT_FALSE(security_manager->IsInitialized()) << "Not testing uninitialized class from the "
                                                     "core";

  CheckVerificationAttempted(security_manager.Get(), false);

  class_linker_->EnsureInitialized(soa.Self(), security_manager, truetrue);
  CheckVerificationAttempted(security_manager.Get(), true);
}

TEST_F(ClassLinkerTest, Preverified_App) {
  ScopedObjectAccess soa(Thread::Current());

  StackHandleScope<2> hs(soa.Self());
  Handle<mirror::ClassLoader> class_loader(
      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Statics"))));
  Handle<mirror::Class> statics = hs.NewHandle(FindClass("LStatics;", class_loader));

  CheckVerificationAttempted(statics.Get(), false);

  class_linker_->EnsureInitialized(soa.Self(), statics, truetrue);
  CheckVerificationAttempted(statics.Get(), true);
}

TEST_F(ClassLinkerTest, IsBootStrapClassLoaded) {
  ScopedObjectAccess soa(Thread::Current());

  StackHandleScope<3> hs(soa.Self());
  Handle<mirror::ClassLoader> class_loader(
      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Statics"))));

  // java.lang.Object is a bootstrap class.
  Handle<mirror::Class> jlo_class(
      hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;")));
  ASSERT_TRUE(jlo_class != nullptr);
  EXPECT_TRUE(jlo_class->IsBootStrapClassLoaded());

  // Statics is not a bootstrap class.
  Handle<mirror::Class> statics = hs.NewHandle(FindClass("LStatics;", class_loader));
  ASSERT_TRUE(statics != nullptr);
  EXPECT_FALSE(statics->IsBootStrapClassLoaded());
}

// Regression test for b/26799552.
TEST_F(ClassLinkerTest, RegisterDexFileName) {
  ScopedObjectAccess soa(Thread::Current());
  StackHandleScope<2> hs(soa.Self());
  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
  MutableHandle<mirror::DexCache> dex_cache(hs.NewHandle<mirror::DexCache>(nullptr));
  {
    ReaderMutexLock mu(soa.Self(), *Locks::dex_lock_);
    for (const auto& entry : class_linker->GetDexCachesData()) {
      const ClassLinker::DexCacheData& data = entry.second;
      dex_cache.Assign(soa.Self()->DecodeJObject(data.weak_root)->AsDexCache());
      if (dex_cache != nullptr) {
        break;
      }
    }
    ASSERT_TRUE(dex_cache != nullptr);
  }
  const uint16_t data[] = { 0x20AC, 0x20A1 };
  Handle<mirror::String> location(hs.NewHandle(mirror::String::AllocFromUtf16(soa.Self(),
                                                                              arraysize(data),
                                                                              data)));
  const DexFile* old_dex_file = dex_cache->GetDexFile();
  class_linker->RemoveDexFromCaches(*old_dex_file);

  auto container =
      std::make_shared<MemoryDexFileContainer>(old_dex_file->Begin(), old_dex_file->Size());
  std::unique_ptr<DexFile> dex_file(new StandardDexFile(
      old_dex_file->Begin(), location->ToModifiedUtf8(), 0u, nullptr, std::move(container)));
  // Make a copy of the dex cache with changed name.
  dex_cache.Assign(class_linker->AllocAndInitializeDexCache(Thread::Current(),
                                                            *dex_file,
                                                            /* class_loader= */ nullptr));
  DCHECK_EQ(dex_cache->GetLocation()->CompareTo(location.Get()), 0);
  {
    WriterMutexLock mu(soa.Self(), *Locks::dex_lock_);
    // Check that inserting with a UTF16 name works.
    class_linker->RegisterDexFileLocked(*dex_file, dex_cache.Get(), /* class_loader= */ nullptr);
  }
}

TEST_F(ClassLinkerMethodHandlesTest, TestResolveMethodTypes) {
  ScopedObjectAccess soa(Thread::Current());
  StackHandleScope<7> hs(soa.Self());

  Handle<mirror::ClassLoader> class_loader(
      hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MethodTypes"))));
  Handle<mirror::Class> method_types = hs.NewHandle(FindClass("LMethodTypes;", class_loader));
  class_linker_->EnsureInitialized(soa.Self(), method_types, truetrue);

  ArtMethod* method1 = method_types->FindClassMethod(
      "method1",
      "(Ljava/lang/String;)Ljava/lang/String;",
      kRuntimePointerSize);
  ASSERT_TRUE(method1 != nullptr);
  ASSERT_FALSE(method1->IsDirect());

  const DexFile& dex_file = *(method1->GetDexFile());
  Handle<mirror::DexCache> dex_cache = hs.NewHandle(
      class_linker_->FindDexCache(soa.Self(), dex_file));

  const dex::MethodId& method1_id = dex_file.GetMethodId(method1->GetDexMethodIndex());

  // This is the MethodType corresponding to the prototype of
  // String MethodTypes# method1(String).
  // Its RType = Ljava/lang/String;
  // Its PTypes = { Ljava/lang/String; }
  Handle<mirror::MethodType> method1_type = hs.NewHandle(
      class_linker_->ResolveMethodType(soa.Self(), method1_id.proto_idx_, dex_cache, class_loader));

  // Assert that the method type was resolved successfully.
  ASSERT_TRUE(method1_type != nullptr);

  // Assert that the return type and the method arguments are as we expect.
  Handle<mirror::Class> string_class = hs.NewHandle(FindClass("Ljava/lang/String;", class_loader));
  ASSERT_OBJ_PTR_EQ(string_class.Get(), method1_type->GetRType());
  ASSERT_OBJ_PTR_EQ(string_class.Get(), method1_type->GetPTypes()->Get(0));

  // Resolve the method type again and assert that we get back the same value.
  Handle<mirror::MethodType> method1_type2 = hs.NewHandle(
      class_linker_->ResolveMethodType(soa.Self(), method1_id.proto_idx_, dex_cache, class_loader));
  ASSERT_OBJ_PTR_EQ(method1_type.Get(), method1_type2.Get());

  // Resolve the MethodType associated with a different method signature
  // and assert it's different.
  ArtMethod* method2 = method_types->FindClassMethod(
      "method2",
      "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
      kRuntimePointerSize);
  ASSERT_TRUE(method2 != nullptr);
  ASSERT_FALSE(method2->IsDirect());
  const dex::MethodId& method2_id = dex_file.GetMethodId(method2->GetDexMethodIndex());
  Handle<mirror::MethodType> method2_type = hs.NewHandle(
      class_linker_->ResolveMethodType(soa.Self(), method2_id.proto_idx_, dex_cache, class_loader));
  ASSERT_OBJ_PTR_NE(method1_type.Get(), method2_type.Get());
}

// Verify that ClassLinker's CreateWellknownClassLoader works as expected
// by creating a chain of class loaders with various dex files.
TEST_F(ClassLinkerTest, CreateWellKnownClassLoader) {
  // LoadDexIn*ClassLoader methods already assert that the parent loader is the expected one.
  // No need to check again.
  jobject class_loader_a = LoadDexInPathClassLoader("MyClass", nullptr);
  jobject class_loader_b = LoadDexInDelegateLastClassLoader("Nested", class_loader_a);
  jobject class_loader_c = LoadDexInPathClassLoader("MultiDex", class_loader_b);
  LoadDexInDelegateLastClassLoader("Interfaces", class_loader_c);
}

TEST_F(ClassLinkerTest, PrettyClass) {
  ScopedObjectAccess soa(Thread::Current());
  EXPECT_EQ("null", mirror::Class::PrettyClass(nullptr));
  ObjPtr<mirror::Class> c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;");
  ASSERT_TRUE(c != nullptr);
  ObjPtr<mirror::Object> o = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), c, 0);
  EXPECT_EQ("java.lang.Class<java.lang.String[]>", mirror::Class::PrettyClass(o->GetClass()));
}

TEST_F(ClassLinkerTest, PrettyClassAndClassLoader) {
  ScopedObjectAccess soa(Thread::Current());
  EXPECT_EQ("null", mirror::Class::PrettyClassAndClassLoader(nullptr));
  ObjPtr<mirror::Class> c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;");
  ASSERT_TRUE(c != nullptr);
  ObjPtr<mirror::Object> o = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), c, 0);
  EXPECT_EQ("java.lang.Class<java.lang.String[],null>",
            mirror::Class::PrettyClassAndClassLoader(o->GetClass()));
}

TEST_F(ClassLinkerTest, PrettyField) {
  ScopedObjectAccess soa(Thread::Current());
  EXPECT_EQ("null", ArtField::PrettyField(nullptr));

  ObjPtr<mirror::Class> java_lang_String = class_linker_->FindSystemClass(soa.Self(),
                                                                          "Ljava/lang/String;");

  ArtField* f;
  f = java_lang_String->FindDeclaredInstanceField("count""I");
  EXPECT_EQ("int java.lang.String.count", f->PrettyField());
  EXPECT_EQ("java.lang.String.count", f->PrettyField(false));
}

TEST_F(ClassLinkerTest, JniShortName_JniLongName) {
  ScopedObjectAccess soa(Thread::Current());
  ObjPtr<mirror::Class> c = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/String;");
  ASSERT_TRUE(c != nullptr);
  ArtMethod* m;

  m = c->FindClassMethod("charAt""(I)C", kRuntimePointerSize);
  ASSERT_TRUE(m != nullptr);
  ASSERT_FALSE(m->IsDirect());
  EXPECT_EQ("Java_java_lang_String_charAt", m->JniShortName());
  EXPECT_EQ("Java_java_lang_String_charAt__I", m->JniLongName());

  m = c->FindClassMethod("indexOf""(Ljava/lang/String;I)I", kRuntimePointerSize);
  ASSERT_TRUE(m != nullptr);
  ASSERT_FALSE(m->IsDirect());
  EXPECT_EQ("Java_java_lang_String_indexOf", m->JniShortName());
  EXPECT_EQ("Java_java_lang_String_indexOf__Ljava_lang_String_2I", m->JniLongName());

  m = c->FindClassMethod("copyValueOf""([CII)Ljava/lang/String;", kRuntimePointerSize);
  ASSERT_TRUE(m != nullptr);
  ASSERT_TRUE(m->IsStatic());
  EXPECT_EQ("Java_java_lang_String_copyValueOf", m->JniShortName());
  EXPECT_EQ("Java_java_lang_String_copyValueOf___3CII", m->JniLongName());
}

class ClassLinkerClassLoaderTest : public ClassLinkerTest {
 protected:
  // Verifies that the class identified by the given descriptor is loaded with
  // the expected_class_loader_obj when search from class_loader_to_search_obj.
  // When expected_class_loader_obj is null the check will be done against BootClassLoader.
  void VerifyClassResolution(const std::string& descriptor,
                             jobject class_loader_to_search_obj,
                             jobject expected_class_loader_obj,
                             bool should_find = true) {
    Thread* self = Thread::Current();
    ScopedObjectAccess soa(self);
    StackHandleScope<3> hs(self);
    Handle<mirror::ClassLoader> class_loader_to_search(
        hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_to_search_obj)));

    Handle<mirror::Class> klass =
        hs.NewHandle(FindClass(descriptor.c_str(), class_loader_to_search));

    if (!should_find) {
      if (self->IsExceptionPending()) {
        self->ClearException();
      }
      ASSERT_TRUE(klass == nullptr);
    } else if (expected_class_loader_obj == nullptr) {
      ASSERT_TRUE(ClassLinker::IsBootClassLoader(klass->GetClassLoader()));
    } else {
      ASSERT_TRUE(klass != nullptr) << descriptor;
      Handle<mirror::ClassLoader> expected_class_loader(
          hs.NewHandle(soa.Decode<mirror::ClassLoader>(expected_class_loader_obj)));
      ASSERT_OBJ_PTR_EQ(klass->GetClassLoader(), expected_class_loader.Get());
    }
  }
};

TEST_F(ClassLinkerClassLoaderTest, CreatePathClassLoader) {
  jobject class_loader_a = LoadDexInPathClassLoader("ForClassLoaderA", nullptr);
  VerifyClassResolution("LDefinedInA;", class_loader_a, class_loader_a);
  VerifyClassResolution("Ljava/lang/String;", class_loader_a, nullptr);
  VerifyClassResolution("LDefinedInB;", class_loader_a, nullptr, /*should_find=*/ false);
}

TEST_F(ClassLinkerClassLoaderTest, CreateDelegateLastClassLoader) {
  jobject class_loader_a = LoadDexInDelegateLastClassLoader("ForClassLoaderA", nullptr);
  VerifyClassResolution("LDefinedInA;", class_loader_a, class_loader_a);
  VerifyClassResolution("Ljava/lang/String;", class_loader_a, nullptr);
  VerifyClassResolution("LDefinedInB;", class_loader_a, nullptr, /*should_find=*/ false);
}

TEST_F(ClassLinkerClassLoaderTest, CreateClassLoaderChain) {
  // The chain is
  //    ClassLoaderA (PathClassLoader, defines: A, AB, AC, AD)
  //       ^
  //       |
  //    ClassLoaderB (DelegateLastClassLoader, defines: B, AB, BC, BD)
  //       ^
  //       |
  //    ClassLoaderC (PathClassLoader, defines: C, AC, BC, CD)
  //       ^
  //       |
  //    ClassLoaderD (DelegateLastClassLoader, defines: D, AD, BD, CD)

  jobject class_loader_a = LoadDexInPathClassLoader("ForClassLoaderA", nullptr);
  jobject class_loader_b = LoadDexInDelegateLastClassLoader("ForClassLoaderB", class_loader_a);
  jobject class_loader_c = LoadDexInPathClassLoader("ForClassLoaderC", class_loader_b);
  jobject class_loader_d = LoadDexInDelegateLastClassLoader("ForClassLoaderD", class_loader_c);

  // Verify exclusive classes (present in only one class loader).
  VerifyClassResolution("LDefinedInD;", class_loader_d, class_loader_d);
  VerifyClassResolution("LDefinedInC;", class_loader_d, class_loader_c);
  VerifyClassResolution("LDefinedInB;", class_loader_d, class_loader_b);
  VerifyClassResolution("LDefinedInA;", class_loader_d, class_loader_a);

  // Verify classes that are defined in multiple classloader.

  // Classes defined in B should be found in B even if they are defined in A or C because
  // B is a DelegateLastClassLoader.
  VerifyClassResolution("LDefinedInAB;", class_loader_d, class_loader_b);
  VerifyClassResolution("LDefinedInABC;", class_loader_d, class_loader_b);
  VerifyClassResolution("LDefinedInBC;", class_loader_d, class_loader_b);

  // Classes defined in D should be found in D even if they are defined in parent class loaders
  // as well because D is a DelegateLastClassLoader.
  VerifyClassResolution("LDefinedInAD;", class_loader_d, class_loader_d);
  VerifyClassResolution("LDefinedInBD;", class_loader_d, class_loader_d);
  VerifyClassResolution("LDefinedInCD;", class_loader_d, class_loader_d);


  // Classes not defined in the DelegateLastClassLoaders (i.e. D or B) should be found
  // in the top parent.
  VerifyClassResolution("LDefinedInAC;", class_loader_d, class_loader_a);

  // Check that we don't find an undefined class.
  VerifyClassResolution("LNotDefined;", class_loader_d, nullptr, /*should_find=*/ false);
}

}  // namespace art

Messung V0.5 in Prozent
C=91 H=93 G=91

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet am  2026-06-29) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik