HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Android 10
|
10.0.0_r6
下载
查看原文件
收藏
根目录
art
runtime
class_linker.cc
/* * 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "android-base/stringprintf.h" #include "art_field-inl.h" #include "art_method-inl.h" #include "base/arena_allocator.h" #include "base/casts.h" #include "base/leb128.h" #include "base/logging.h" #include "base/os.h" #include "base/quasi_atomic.h" #include "base/scoped_arena_containers.h" #include "base/scoped_flock.h" #include "base/stl_util.h" #include "base/string_view_cpp20.h" #include "base/systrace.h" #include "base/time_utils.h" #include "base/unix_file/fd_file.h" #include "base/utils.h" #include "base/value_object.h" #include "cha.h" #include "class_linker-inl.h" #include "class_loader_utils.h" #include "class_root.h" #include "class_table-inl.h" #include "compiler_callbacks.h" #include "debug_print.h" #include "debugger.h" #include "dex/class_accessor-inl.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_exception_helpers.h" #include "dex/dex_file_loader.h" #include "dex/signature-inl.h" #include "dex/utf.h" #include "entrypoints/entrypoint_utils.h" #include "entrypoints/runtime_asm_entrypoints.h" #include "experimental_flags.h" #include "gc/accounting/card_table-inl.h" #include "gc/accounting/heap_bitmap-inl.h" #include "gc/accounting/space_bitmap-inl.h" #include "gc/heap-visit-objects-inl.h" #include "gc/heap.h" #include "gc/scoped_gc_critical_section.h" #include "gc/space/image_space.h" #include "gc/space/space-inl.h" #include "gc_root-inl.h" #include "handle_scope-inl.h" #include "hidden_api.h" #include "image-inl.h" #include "imt_conflict_table.h" #include "imtable-inl.h" #include "intern_table-inl.h" #include "interpreter/interpreter.h" #include "jit/debugger_interface.h" #include "jit/jit.h" #include "jit/jit_code_cache.h" #include "jni/java_vm_ext.h" #include "jni/jni_internal.h" #include "linear_alloc.h" #include "mirror/array-alloc-inl.h" #include "mirror/array-inl.h" #include "mirror/call_site.h" #include "mirror/class-alloc-inl.h" #include "mirror/class-inl.h" #include "mirror/class.h" #include "mirror/class_ext.h" #include "mirror/class_loader.h" #include "mirror/dex_cache-inl.h" #include "mirror/dex_cache.h" #include "mirror/emulated_stack_frame.h" #include "mirror/field.h" #include "mirror/iftable-inl.h" #include "mirror/method.h" #include "mirror/method_handle_impl.h" #include "mirror/method_handles_lookup.h" #include "mirror/method_type.h" #include "mirror/object-inl.h" #include "mirror/object-refvisitor-inl.h" #include "mirror/object_array-alloc-inl.h" #include "mirror/object_array-inl.h" #include "mirror/object_reference.h" #include "mirror/object_reference-inl.h" #include "mirror/proxy.h" #include "mirror/reference-inl.h" #include "mirror/stack_trace_element.h" #include "mirror/string-inl.h" #include "mirror/throwable.h" #include "mirror/var_handle.h" #include "native/dalvik_system_DexFile.h" #include "nativehelper/scoped_local_ref.h" #include "oat.h" #include "oat_file-inl.h" #include "oat_file.h" #include "oat_file_assistant.h" #include "oat_file_manager.h" #include "object_lock.h" #include "profile/profile_compilation_info.h" #include "runtime.h" #include "runtime_callbacks.h" #include "scoped_thread_state_change-inl.h" #include "thread-inl.h" #include "thread_list.h" #include "trace.h" #include "utils/dex_cache_arrays_layout-inl.h" #include "verifier/class_verifier.h" #include "well_known_classes.h" namespace art { using android::base::StringPrintf; static constexpr bool kSanityCheckObjects = kIsDebugBuild; static constexpr bool kVerifyArtMethodDeclaringClasses = kIsDebugBuild; static void ThrowNoClassDefFoundError(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2))) REQUIRES_SHARED(Locks::mutator_lock_); static void ThrowNoClassDefFoundError(const char* fmt, ...) { va_list args; va_start(args, fmt); Thread* self = Thread::Current(); self->ThrowNewExceptionV("Ljava/lang/NoClassDefFoundError;", fmt, args); va_end(args); } static bool HasInitWithString(Thread* self, ClassLinker* class_linker, const char* descriptor) REQUIRES_SHARED(Locks::mutator_lock_) { ArtMethod* method = self->GetCurrentMethod(nullptr); StackHandleScope<1> hs(self); Handle
class_loader(hs.NewHandle(method != nullptr ? method->GetDeclaringClass()->GetClassLoader() : nullptr)); ObjPtr
exception_class = class_linker->FindClass(self, descriptor, class_loader); if (exception_class == nullptr) { // No exc class ~ no
-with-string. CHECK(self->IsExceptionPending()); self->ClearException(); return false; } ArtMethod* exception_init_method = exception_class->FindConstructor( "(Ljava/lang/String;)V", class_linker->GetImagePointerSize()); return exception_init_method != nullptr; } static ObjPtr
GetVerifyError(ObjPtr
c) REQUIRES_SHARED(Locks::mutator_lock_) { ObjPtr
ext(c->GetExtData()); if (ext == nullptr) { return nullptr; } else { return ext->GetVerifyError(); } } // Helper for ThrowEarlierClassFailure. Throws the stored error. static void HandleEarlierVerifyError(Thread* self, ClassLinker* class_linker, ObjPtr
c) REQUIRES_SHARED(Locks::mutator_lock_) { ObjPtr
obj = GetVerifyError(c); DCHECK(obj != nullptr); self->AssertNoPendingException(); if (obj->IsClass()) { // Previous error has been stored as class. Create a new exception of that type. // It's possible the exception doesn't have a
(String). std::string temp; const char* descriptor = obj->AsClass()->GetDescriptor(&temp); if (HasInitWithString(self, class_linker, descriptor)) { self->ThrowNewException(descriptor, c->PrettyDescriptor().c_str()); } else { self->ThrowNewException(descriptor, nullptr); } } else { // Previous error has been stored as an instance. Just rethrow. ObjPtr
throwable_class = GetClassRoot
(class_linker); ObjPtr
error_class = obj->GetClass(); CHECK(throwable_class->IsAssignableFrom(error_class)); self->SetException(obj->AsThrowable()); } self->AssertPendingException(); } // Ensures that methods have the kAccSkipAccessChecks bit set. We use the // kAccVerificationAttempted bit on the class access flags to determine whether this has been done // before. template
static void EnsureSkipAccessChecksMethods(Handle
klass, PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_) { if (kNeedsVerified) { // To not fail access-flags access checks, push a minimal state. mirror::Class::SetStatus(klass, ClassStatus::kVerified, Thread::Current()); } if (!klass->WasVerificationAttempted()) { klass->SetSkipAccessChecksFlagOnAllMethods(pointer_size); klass->SetVerificationAttempted(); } } void ClassLinker::ThrowEarlierClassFailure(ObjPtr
c, bool wrap_in_no_class_def, bool log) { // The class failed to initialize on a previous attempt, so we want to throw // a NoClassDefFoundError (v2 2.17.5). The exception to this rule is if we // failed in verification, in which case v2 5.4.1 says we need to re-throw // the previous error. Runtime* const runtime = Runtime::Current(); if (!runtime->IsAotCompiler()) { // Give info if this occurs at runtime. std::string extra; ObjPtr
verify_error = GetVerifyError(c); if (verify_error != nullptr) { if (verify_error->IsClass()) { extra = mirror::Class::PrettyDescriptor(verify_error->AsClass()); } else { extra = verify_error->AsThrowable()->Dump(); } } if (log) { LOG(INFO) << "Rejecting re-init on previously-failed class " << c->PrettyClass() << ": " << extra; } } CHECK(c->IsErroneous()) << c->PrettyClass() << " " << c->GetStatus(); Thread* self = Thread::Current(); if (runtime->IsAotCompiler()) { // At compile time, accurate errors and NCDFE are disabled to speed compilation. ObjPtr
pre_allocated = runtime->GetPreAllocatedNoClassDefFoundError(); self->SetException(pre_allocated); } else { ObjPtr
verify_error = GetVerifyError(c); if (verify_error != nullptr) { // Rethrow stored error. HandleEarlierVerifyError(self, this, c); } // TODO This might be wrong if we hit an OOME while allocating the ClassExt. In that case we // might have meant to go down the earlier if statement with the original error but it got // swallowed by the OOM so we end up here. if (verify_error == nullptr || wrap_in_no_class_def) { // If there isn't a recorded earlier error, or this is a repeat throw from initialization, // the top-level exception must be a NoClassDefFoundError. The potentially already pending // exception will be a cause. self->ThrowNewWrappedException("Ljava/lang/NoClassDefFoundError;", c->PrettyDescriptor().c_str()); } } } static void VlogClassInitializationFailure(Handle
klass) REQUIRES_SHARED(Locks::mutator_lock_) { if (VLOG_IS_ON(class_linker)) { std::string temp; LOG(INFO) << "Failed to initialize class " << klass->GetDescriptor(&temp) << " from " << klass->GetLocation() << "\n" << Thread::Current()->GetException()->Dump(); } } static void WrapExceptionInInitializer(Handle
klass) REQUIRES_SHARED(Locks::mutator_lock_) { Thread* self = Thread::Current(); JNIEnv* env = self->GetJniEnv(); ScopedLocalRef
cause(env, env->ExceptionOccurred()); CHECK(cause.get() != nullptr); // Boot classpath classes should not fail initialization. This is a sanity debug check. This // cannot in general be guaranteed, but in all likelihood leads to breakage down the line. if (klass->GetClassLoader() == nullptr && !Runtime::Current()->IsAotCompiler()) { std::string tmp; // We want to LOG(FATAL) on debug builds since this really shouldn't be happening but we need to // make sure to only do it if we don't have AsyncExceptions being thrown around since those // could have caused the error. bool known_impossible = kIsDebugBuild && !Runtime::Current()->AreAsyncExceptionsThrown(); LOG(known_impossible ? FATAL : WARNING) << klass->GetDescriptor(&tmp) << " failed initialization: " << self->GetException()->Dump(); } env->ExceptionClear(); bool is_error = env->IsInstanceOf(cause.get(), WellKnownClasses::java_lang_Error); env->Throw(cause.get()); // We only wrap non-Error exceptions; an Error can just be used as-is. if (!is_error) { self->ThrowNewWrappedException("Ljava/lang/ExceptionInInitializerError;", nullptr); } VlogClassInitializationFailure(klass); } // Gap between two fields in object layout. struct FieldGap { uint32_t start_offset; // The offset from the start of the object. uint32_t size; // The gap size of 1, 2, or 4 bytes. }; struct FieldGapsComparator { FieldGapsComparator() { } bool operator() (const FieldGap& lhs, const FieldGap& rhs) NO_THREAD_SAFETY_ANALYSIS { // Sort by gap size, largest first. Secondary sort by starting offset. // Note that the priority queue returns the largest element, so operator() // should return true if lhs is less than rhs. return lhs.size < rhs.size || (lhs.size == rhs.size && lhs.start_offset > rhs.start_offset); } }; using FieldGaps = std::priority_queue
, FieldGapsComparator>; // Adds largest aligned gaps to queue of gaps. static void AddFieldGap(uint32_t gap_start, uint32_t gap_end, FieldGaps* gaps) { DCHECK(gaps != nullptr); uint32_t current_offset = gap_start; while (current_offset != gap_end) { size_t remaining = gap_end - current_offset; if (remaining >= sizeof(uint32_t) && IsAligned<4>(current_offset)) { gaps->push(FieldGap {current_offset, sizeof(uint32_t)}); current_offset += sizeof(uint32_t); } else if (remaining >= sizeof(uint16_t) && IsAligned<2>(current_offset)) { gaps->push(FieldGap {current_offset, sizeof(uint16_t)}); current_offset += sizeof(uint16_t); } else { gaps->push(FieldGap {current_offset, sizeof(uint8_t)}); current_offset += sizeof(uint8_t); } DCHECK_LE(current_offset, gap_end) << "Overran gap"; } } // Shuffle fields forward, making use of gaps whenever possible. template
static void ShuffleForward(size_t* current_field_idx, MemberOffset* field_offset, std::deque
* grouped_and_sorted_fields, FieldGaps* gaps) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(current_field_idx != nullptr); DCHECK(grouped_and_sorted_fields != nullptr); DCHECK(gaps != nullptr); DCHECK(field_offset != nullptr); DCHECK(IsPowerOfTwo(n)); while (!grouped_and_sorted_fields->empty()) { ArtField* field = grouped_and_sorted_fields->front(); Primitive::Type type = field->GetTypeAsPrimitiveType(); if (Primitive::ComponentSize(type) < n) { break; } if (!IsAligned
(field_offset->Uint32Value())) { MemberOffset old_offset = *field_offset; *field_offset = MemberOffset(RoundUp(field_offset->Uint32Value(), n)); AddFieldGap(old_offset.Uint32Value(), field_offset->Uint32Value(), gaps); } CHECK(type != Primitive::kPrimNot) << field->PrettyField(); // should be primitive types grouped_and_sorted_fields->pop_front(); if (!gaps->empty() && gaps->top().size >= n) { FieldGap gap = gaps->top(); gaps->pop(); DCHECK_ALIGNED(gap.start_offset, n); field->SetOffset(MemberOffset(gap.start_offset)); if (gap.size > n) { AddFieldGap(gap.start_offset + n, gap.start_offset + gap.size, gaps); } } else { DCHECK_ALIGNED(field_offset->Uint32Value(), n); field->SetOffset(*field_offset); *field_offset = MemberOffset(field_offset->Uint32Value() + n); } ++(*current_field_idx); } } ClassLinker::ClassLinker(InternTable* intern_table, bool fast_class_not_found_exceptions) : boot_class_table_(new ClassTable()), failed_dex_cache_class_lookups_(0), class_roots_(nullptr), find_array_class_cache_next_victim_(0), init_done_(false), log_new_roots_(false), intern_table_(intern_table), fast_class_not_found_exceptions_(fast_class_not_found_exceptions), quick_resolution_trampoline_(nullptr), quick_imt_conflict_trampoline_(nullptr), quick_generic_jni_trampoline_(nullptr), quick_to_interpreter_bridge_trampoline_(nullptr), image_pointer_size_(kRuntimePointerSize), cha_(Runtime::Current()->IsAotCompiler() ? nullptr : new ClassHierarchyAnalysis()) { // For CHA disabled during Aot, see b/34193647. CHECK(intern_table_ != nullptr); static_assert(kFindArrayCacheSize == arraysize(find_array_class_cache_), "Array cache size wrong."); std::fill_n(find_array_class_cache_, kFindArrayCacheSize, GcRoot
(nullptr)); } void ClassLinker::CheckSystemClass(Thread* self, Handle
c1, const char* descriptor) { ObjPtr
c2 = FindSystemClass(self, descriptor); if (c2 == nullptr) { LOG(FATAL) << "Could not find class " << descriptor; UNREACHABLE(); } if (c1.Get() != c2) { std::ostringstream os1, os2; c1->DumpClass(os1, mirror::Class::kDumpClassFullDetail); c2->DumpClass(os2, mirror::Class::kDumpClassFullDetail); LOG(FATAL) << "InitWithoutImage: Class mismatch for " << descriptor << ". This is most likely the result of a broken build. Make sure that " << "libcore and art projects match.\n\n" << os1.str() << "\n\n" << os2.str(); UNREACHABLE(); } } bool ClassLinker::InitWithoutImage(std::vector
> boot_class_path, std::string* error_msg) { VLOG(startup) << "ClassLinker::Init"; Thread* const self = Thread::Current(); Runtime* const runtime = Runtime::Current(); gc::Heap* const heap = runtime->GetHeap(); CHECK(!heap->HasBootImageSpace()) << "Runtime has image. We should use it."; CHECK(!init_done_); // Use the pointer size from the runtime since we are probably creating the image. image_pointer_size_ = InstructionSetPointerSize(runtime->GetInstructionSet()); // java_lang_Class comes first, it's needed for AllocClass // The GC can't handle an object with a null class since we can't get the size of this object. heap->IncrementDisableMovingGC(self); StackHandleScope<64> hs(self); // 64 is picked arbitrarily. auto class_class_size = mirror::Class::ClassClassSize(image_pointer_size_); // Allocate the object as non-movable so that there are no cases where Object::IsClass returns // the incorrect result when comparing to-space vs from-space. Handle
java_lang_Class(hs.NewHandle(ObjPtr
::DownCast( heap->AllocNonMovableObject
(self, nullptr, class_class_size, VoidFunctor())))); CHECK(java_lang_Class != nullptr); java_lang_Class->SetClassFlags(mirror::kClassFlagClass); java_lang_Class->SetClass(java_lang_Class.Get()); if (kUseBakerReadBarrier) { java_lang_Class->AssertReadBarrierState(); } java_lang_Class->SetClassSize(class_class_size); java_lang_Class->SetPrimitiveType(Primitive::kPrimNot); heap->DecrementDisableMovingGC(self); // AllocClass(ObjPtr
) can now be used // Class[] is used for reflection support. auto class_array_class_size = mirror::ObjectArray
::ClassSize(image_pointer_size_); Handle
class_array_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), class_array_class_size))); class_array_class->SetComponentType(java_lang_Class.Get()); // java_lang_Object comes next so that object_array_class can be created. Handle
java_lang_Object(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Object::ClassSize(image_pointer_size_)))); CHECK(java_lang_Object != nullptr); // backfill Object as the super class of Class. java_lang_Class->SetSuperClass(java_lang_Object.Get()); mirror::Class::SetStatus(java_lang_Object, ClassStatus::kLoaded, self); java_lang_Object->SetObjectSize(sizeof(mirror::Object)); // Allocate in non-movable so that it's possible to check if a JNI weak global ref has been // cleared without triggering the read barrier and unintentionally mark the sentinel alive. runtime->SetSentinel(heap->AllocNonMovableObject
(self, java_lang_Object.Get(), java_lang_Object->GetObjectSize(), VoidFunctor())); // Initialize the SubtypeCheck bitstring for java.lang.Object and java.lang.Class. if (kBitstringSubtypeCheckEnabled) { // It might seem the lock here is unnecessary, however all the SubtypeCheck // functions are annotated to require locks all the way down. // // We take the lock here to avoid using NO_THREAD_SAFETY_ANALYSIS. MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_); SubtypeCheck
>::EnsureInitialized(java_lang_Object.Get()); SubtypeCheck
>::EnsureInitialized(java_lang_Class.Get()); } // Object[] next to hold class roots. Handle
object_array_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::ObjectArray
::ClassSize(image_pointer_size_)))); object_array_class->SetComponentType(java_lang_Object.Get()); // Setup java.lang.String. // // We make this class non-movable for the unlikely case where it were to be // moved by a sticky-bit (minor) collection when using the Generational // Concurrent Copying (CC) collector, potentially creating a stale reference // in the `klass_` field of one of its instances allocated in the Large-Object // Space (LOS) -- see the comment about the dirty card scanning logic in // art::gc::collector::ConcurrentCopying::MarkingPhase. Handle
java_lang_String(hs.NewHandle( AllocClass* kMovable= */ false>( self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_)))); java_lang_String->SetStringClass(); mirror::Class::SetStatus(java_lang_String, ClassStatus::kResolved, self); // Setup java.lang.ref.Reference. Handle
java_lang_ref_Reference(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Reference::ClassSize(image_pointer_size_)))); java_lang_ref_Reference->SetObjectSize(mirror::Reference::InstanceSize()); mirror::Class::SetStatus(java_lang_ref_Reference, ClassStatus::kResolved, self); // Create storage for root classes, save away our work so far (requires descriptors). class_roots_ = GcRoot
>( mirror::ObjectArray
::Alloc(self, object_array_class.Get(), static_cast
(ClassRoot::kMax))); CHECK(!class_roots_.IsNull()); SetClassRoot(ClassRoot::kJavaLangClass, java_lang_Class.Get()); SetClassRoot(ClassRoot::kJavaLangObject, java_lang_Object.Get()); SetClassRoot(ClassRoot::kClassArrayClass, class_array_class.Get()); SetClassRoot(ClassRoot::kObjectArrayClass, object_array_class.Get()); SetClassRoot(ClassRoot::kJavaLangString, java_lang_String.Get()); SetClassRoot(ClassRoot::kJavaLangRefReference, java_lang_ref_Reference.Get()); // Fill in the empty iftable. Needs to be done after the kObjectArrayClass root is set. java_lang_Object->SetIfTable(AllocIfTable(self, 0)); // Create array interface entries to populate once we can load system classes. object_array_class->SetIfTable(AllocIfTable(self, 2)); DCHECK_EQ(GetArrayIfTable(), object_array_class->GetIfTable()); // Setup the primitive type classes. SetClassRoot(ClassRoot::kPrimitiveBoolean, CreatePrimitiveClass(self, Primitive::kPrimBoolean)); SetClassRoot(ClassRoot::kPrimitiveByte, CreatePrimitiveClass(self, Primitive::kPrimByte)); SetClassRoot(ClassRoot::kPrimitiveChar, CreatePrimitiveClass(self, Primitive::kPrimChar)); SetClassRoot(ClassRoot::kPrimitiveShort, CreatePrimitiveClass(self, Primitive::kPrimShort)); SetClassRoot(ClassRoot::kPrimitiveInt, CreatePrimitiveClass(self, Primitive::kPrimInt)); SetClassRoot(ClassRoot::kPrimitiveLong, CreatePrimitiveClass(self, Primitive::kPrimLong)); SetClassRoot(ClassRoot::kPrimitiveFloat, CreatePrimitiveClass(self, Primitive::kPrimFloat)); SetClassRoot(ClassRoot::kPrimitiveDouble, CreatePrimitiveClass(self, Primitive::kPrimDouble)); SetClassRoot(ClassRoot::kPrimitiveVoid, CreatePrimitiveClass(self, Primitive::kPrimVoid)); // Create int array type for native pointer arrays (for example vtables) on 32-bit archs. Handle
int_array_class(hs.NewHandle( AllocPrimitiveArrayClass(self, java_lang_Class.Get()))); int_array_class->SetComponentType(GetClassRoot(ClassRoot::kPrimitiveInt, this)); SetClassRoot(ClassRoot::kIntArrayClass, int_array_class.Get()); // Create long array type for native pointer arrays (for example vtables) on 64-bit archs. Handle
long_array_class(hs.NewHandle( AllocPrimitiveArrayClass(self, java_lang_Class.Get()))); long_array_class->SetComponentType(GetClassRoot(ClassRoot::kPrimitiveLong, this)); SetClassRoot(ClassRoot::kLongArrayClass, long_array_class.Get()); // now that these are registered, we can use AllocClass() and AllocObjectArray // Set up DexCache. This cannot be done later since AppendToBootClassPath calls AllocDexCache. Handle
java_lang_DexCache(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::DexCache::ClassSize(image_pointer_size_)))); SetClassRoot(ClassRoot::kJavaLangDexCache, java_lang_DexCache.Get()); java_lang_DexCache->SetDexCacheClass(); java_lang_DexCache->SetObjectSize(mirror::DexCache::InstanceSize()); mirror::Class::SetStatus(java_lang_DexCache, ClassStatus::kResolved, self); // Setup dalvik.system.ClassExt Handle
dalvik_system_ClassExt(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::ClassExt::ClassSize(image_pointer_size_)))); SetClassRoot(ClassRoot::kDalvikSystemClassExt, dalvik_system_ClassExt.Get()); mirror::Class::SetStatus(dalvik_system_ClassExt, ClassStatus::kResolved, self); // Set up array classes for string, field, method Handle
object_array_string(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::ObjectArray
::ClassSize(image_pointer_size_)))); object_array_string->SetComponentType(java_lang_String.Get()); SetClassRoot(ClassRoot::kJavaLangStringArrayClass, object_array_string.Get()); LinearAlloc* linear_alloc = runtime->GetLinearAlloc(); // Create runtime resolution and imt conflict methods. runtime->SetResolutionMethod(runtime->CreateResolutionMethod()); runtime->SetImtConflictMethod(runtime->CreateImtConflictMethod(linear_alloc)); runtime->SetImtUnimplementedMethod(runtime->CreateImtConflictMethod(linear_alloc)); // Setup boot_class_path_ and register class_path now that we can use AllocObjectArray to create // DexCache instances. Needs to be after String, Field, Method arrays since AllocDexCache uses // these roots. if (boot_class_path.empty()) { *error_msg = "Boot classpath is empty."; return false; } for (auto& dex_file : boot_class_path) { if (dex_file.get() == nullptr) { *error_msg = "Null dex file."; return false; } AppendToBootClassPath(self, *dex_file); boot_dex_files_.push_back(std::move(dex_file)); } // now we can use FindSystemClass // Set up GenericJNI entrypoint. That is mainly a hack for common_compiler_test.h so that // we do not need friend classes or a publicly exposed setter. quick_generic_jni_trampoline_ = GetQuickGenericJniStub(); if (!runtime->IsAotCompiler()) { // We need to set up the generic trampolines since we don't have an image. quick_resolution_trampoline_ = GetQuickResolutionStub(); quick_imt_conflict_trampoline_ = GetQuickImtConflictStub(); quick_to_interpreter_bridge_trampoline_ = GetQuickToInterpreterBridge(); } // Object, String, ClassExt and DexCache need to be rerun through FindSystemClass to finish init mirror::Class::SetStatus(java_lang_Object, ClassStatus::kNotReady, self); CheckSystemClass(self, java_lang_Object, "Ljava/lang/Object;"); CHECK_EQ(java_lang_Object->GetObjectSize(), mirror::Object::InstanceSize()); mirror::Class::SetStatus(java_lang_String, ClassStatus::kNotReady, self); CheckSystemClass(self, java_lang_String, "Ljava/lang/String;"); mirror::Class::SetStatus(java_lang_DexCache, ClassStatus::kNotReady, self); CheckSystemClass(self, java_lang_DexCache, "Ljava/lang/DexCache;"); CHECK_EQ(java_lang_DexCache->GetObjectSize(), mirror::DexCache::InstanceSize()); mirror::Class::SetStatus(dalvik_system_ClassExt, ClassStatus::kNotReady, self); CheckSystemClass(self, dalvik_system_ClassExt, "Ldalvik/system/ClassExt;"); CHECK_EQ(dalvik_system_ClassExt->GetObjectSize(), mirror::ClassExt::InstanceSize()); // Setup the primitive array type classes - can't be done until Object has a vtable. AllocAndSetPrimitiveArrayClassRoot(self, java_lang_Class.Get(), ClassRoot::kBooleanArrayClass, ClassRoot::kPrimitiveBoolean, "[Z"); AllocAndSetPrimitiveArrayClassRoot( self, java_lang_Class.Get(), ClassRoot::kByteArrayClass, ClassRoot::kPrimitiveByte, "[B"); AllocAndSetPrimitiveArrayClassRoot( self, java_lang_Class.Get(), ClassRoot::kCharArrayClass, ClassRoot::kPrimitiveChar, "[C"); AllocAndSetPrimitiveArrayClassRoot( self, java_lang_Class.Get(), ClassRoot::kShortArrayClass, ClassRoot::kPrimitiveShort, "[S"); CheckSystemClass(self, int_array_class, "[I"); CheckSystemClass(self, long_array_class, "[J"); AllocAndSetPrimitiveArrayClassRoot( self, java_lang_Class.Get(), ClassRoot::kFloatArrayClass, ClassRoot::kPrimitiveFloat, "[F"); AllocAndSetPrimitiveArrayClassRoot( self, java_lang_Class.Get(), ClassRoot::kDoubleArrayClass, ClassRoot::kPrimitiveDouble, "[D"); // Run Class through FindSystemClass. This initializes the dex_cache_ fields and register it // in class_table_. CheckSystemClass(self, java_lang_Class, "Ljava/lang/Class;"); CheckSystemClass(self, class_array_class, "[Ljava/lang/Class;"); CheckSystemClass(self, object_array_class, "[Ljava/lang/Object;"); // Setup the single, global copy of "iftable". auto java_lang_Cloneable = hs.NewHandle(FindSystemClass(self, "Ljava/lang/Cloneable;")); CHECK(java_lang_Cloneable != nullptr); auto java_io_Serializable = hs.NewHandle(FindSystemClass(self, "Ljava/io/Serializable;")); CHECK(java_io_Serializable != nullptr); // We assume that Cloneable/Serializable don't have superinterfaces -- normally we'd have to // crawl up and explicitly list all of the supers as well. object_array_class->GetIfTable()->SetInterface(0, java_lang_Cloneable.Get()); object_array_class->GetIfTable()->SetInterface(1, java_io_Serializable.Get()); // Sanity check Class[] and Object[]'s interfaces. GetDirectInterface may cause thread // suspension. CHECK_EQ(java_lang_Cloneable.Get(), mirror::Class::GetDirectInterface(self, class_array_class.Get(), 0)); CHECK_EQ(java_io_Serializable.Get(), mirror::Class::GetDirectInterface(self, class_array_class.Get(), 1)); CHECK_EQ(java_lang_Cloneable.Get(), mirror::Class::GetDirectInterface(self, object_array_class.Get(), 0)); CHECK_EQ(java_io_Serializable.Get(), mirror::Class::GetDirectInterface(self, object_array_class.Get(), 1)); CHECK_EQ(object_array_string.Get(), FindSystemClass(self, GetClassRootDescriptor(ClassRoot::kJavaLangStringArrayClass))); // End of special init trickery, all subsequent classes may be loaded via FindSystemClass. // Create java.lang.reflect.Proxy root. SetClassRoot(ClassRoot::kJavaLangReflectProxy, FindSystemClass(self, "Ljava/lang/reflect/Proxy;")); // Create java.lang.reflect.Field.class root. ObjPtr
class_root = FindSystemClass(self, "Ljava/lang/reflect/Field;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kJavaLangReflectField, class_root); // Create java.lang.reflect.Field array root. class_root = FindSystemClass(self, "[Ljava/lang/reflect/Field;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kJavaLangReflectFieldArrayClass, class_root); // Create java.lang.reflect.Constructor.class root and array root. class_root = FindSystemClass(self, "Ljava/lang/reflect/Constructor;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kJavaLangReflectConstructor, class_root); class_root = FindSystemClass(self, "[Ljava/lang/reflect/Constructor;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kJavaLangReflectConstructorArrayClass, class_root); // Create java.lang.reflect.Method.class root and array root. class_root = FindSystemClass(self, "Ljava/lang/reflect/Method;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kJavaLangReflectMethod, class_root); class_root = FindSystemClass(self, "[Ljava/lang/reflect/Method;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kJavaLangReflectMethodArrayClass, class_root); // Create java.lang.invoke.CallSite.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/CallSite;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kJavaLangInvokeCallSite, class_root); // Create java.lang.invoke.MethodType.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodType;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kJavaLangInvokeMethodType, class_root); // Create java.lang.invoke.MethodHandleImpl.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodHandleImpl;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kJavaLangInvokeMethodHandleImpl, class_root); SetClassRoot(ClassRoot::kJavaLangInvokeMethodHandle, class_root->GetSuperClass()); // Create java.lang.invoke.MethodHandles.Lookup.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodHandles$Lookup;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kJavaLangInvokeMethodHandlesLookup, class_root); // Create java.lang.invoke.VarHandle.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/VarHandle;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kJavaLangInvokeVarHandle, class_root); // Create java.lang.invoke.FieldVarHandle.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/FieldVarHandle;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kJavaLangInvokeFieldVarHandle, class_root); // Create java.lang.invoke.ArrayElementVarHandle.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/ArrayElementVarHandle;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kJavaLangInvokeArrayElementVarHandle, class_root); // Create java.lang.invoke.ByteArrayViewVarHandle.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/ByteArrayViewVarHandle;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kJavaLangInvokeByteArrayViewVarHandle, class_root); // Create java.lang.invoke.ByteBufferViewVarHandle.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/ByteBufferViewVarHandle;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kJavaLangInvokeByteBufferViewVarHandle, class_root); class_root = FindSystemClass(self, "Ldalvik/system/EmulatedStackFrame;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kDalvikSystemEmulatedStackFrame, class_root); // java.lang.ref classes need to be specially flagged, but otherwise are normal classes // finish initializing Reference class mirror::Class::SetStatus(java_lang_ref_Reference, ClassStatus::kNotReady, self); CheckSystemClass(self, java_lang_ref_Reference, "Ljava/lang/ref/Reference;"); CHECK_EQ(java_lang_ref_Reference->GetObjectSize(), mirror::Reference::InstanceSize()); CHECK_EQ(java_lang_ref_Reference->GetClassSize(), mirror::Reference::ClassSize(image_pointer_size_)); class_root = FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;"); CHECK_EQ(class_root->GetClassFlags(), mirror::kClassFlagNormal); class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagFinalizerReference); class_root = FindSystemClass(self, "Ljava/lang/ref/PhantomReference;"); CHECK_EQ(class_root->GetClassFlags(), mirror::kClassFlagNormal); class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagPhantomReference); class_root = FindSystemClass(self, "Ljava/lang/ref/SoftReference;"); CHECK_EQ(class_root->GetClassFlags(), mirror::kClassFlagNormal); class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagSoftReference); class_root = FindSystemClass(self, "Ljava/lang/ref/WeakReference;"); CHECK_EQ(class_root->GetClassFlags(), mirror::kClassFlagNormal); class_root->SetClassFlags(class_root->GetClassFlags() | mirror::kClassFlagWeakReference); // Setup the ClassLoader, verifying the object_size_. class_root = FindSystemClass(self, "Ljava/lang/ClassLoader;"); class_root->SetClassLoaderClass(); CHECK_EQ(class_root->GetObjectSize(), mirror::ClassLoader::InstanceSize()); SetClassRoot(ClassRoot::kJavaLangClassLoader, class_root); // Set up java.lang.Throwable, java.lang.ClassNotFoundException, and // java.lang.StackTraceElement as a convenience. SetClassRoot(ClassRoot::kJavaLangThrowable, FindSystemClass(self, "Ljava/lang/Throwable;")); SetClassRoot(ClassRoot::kJavaLangClassNotFoundException, FindSystemClass(self, "Ljava/lang/ClassNotFoundException;")); SetClassRoot(ClassRoot::kJavaLangStackTraceElement, FindSystemClass(self, "Ljava/lang/StackTraceElement;")); SetClassRoot(ClassRoot::kJavaLangStackTraceElementArrayClass, FindSystemClass(self, "[Ljava/lang/StackTraceElement;")); SetClassRoot(ClassRoot::kJavaLangClassLoaderArrayClass, FindSystemClass(self, "[Ljava/lang/ClassLoader;")); // Create conflict tables that depend on the class linker. runtime->FixupConflictTables(); FinishInit(self); VLOG(startup) << "ClassLinker::InitFromCompiler exiting"; return true; } static void CreateStringInitBindings(Thread* self, ClassLinker* class_linker) REQUIRES_SHARED(Locks::mutator_lock_) { // Find String.
-> StringFactory bindings. ObjPtr
string_factory_class = class_linker->FindSystemClass(self, "Ljava/lang/StringFactory;"); CHECK(string_factory_class != nullptr); ObjPtr
string_class = GetClassRoot
(class_linker); WellKnownClasses::InitStringInit(string_class, string_factory_class); // Update the primordial thread. self->InitStringEntryPoints(); } void ClassLinker::FinishInit(Thread* self) { VLOG(startup) << "ClassLinker::FinishInit entering"; CreateStringInitBindings(self, this); // Let the heap know some key offsets into java.lang.ref instances // Note: we hard code the field indexes here rather than using FindInstanceField // as the types of the field can't be resolved prior to the runtime being // fully initialized StackHandleScope<3> hs(self); Handle
java_lang_ref_Reference = hs.NewHandle(GetClassRoot
(this)); Handle
java_lang_ref_FinalizerReference = hs.NewHandle(FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;")); ArtField* pendingNext = java_lang_ref_Reference->GetInstanceField(0); CHECK_STREQ(pendingNext->GetName(), "pendingNext"); CHECK_STREQ(pendingNext->GetTypeDescriptor(), "Ljava/lang/ref/Reference;"); ArtField* queue = java_lang_ref_Reference->GetInstanceField(1); CHECK_STREQ(queue->GetName(), "queue"); CHECK_STREQ(queue->GetTypeDescriptor(), "Ljava/lang/ref/ReferenceQueue;"); ArtField* queueNext = java_lang_ref_Reference->GetInstanceField(2); CHECK_STREQ(queueNext->GetName(), "queueNext"); CHECK_STREQ(queueNext->GetTypeDescriptor(), "Ljava/lang/ref/Reference;"); ArtField* referent = java_lang_ref_Reference->GetInstanceField(3); CHECK_STREQ(referent->GetName(), "referent"); CHECK_STREQ(referent->GetTypeDescriptor(), "Ljava/lang/Object;"); ArtField* zombie = java_lang_ref_FinalizerReference->GetInstanceField(2); CHECK_STREQ(zombie->GetName(), "zombie"); CHECK_STREQ(zombie->GetTypeDescriptor(), "Ljava/lang/Object;"); // ensure all class_roots_ are initialized for (size_t i = 0; i < static_cast
(ClassRoot::kMax); i++) { ClassRoot class_root = static_cast
(i); ObjPtr
klass = GetClassRoot(class_root); CHECK(klass != nullptr); DCHECK(klass->IsArrayClass() || klass->IsPrimitive() || klass->GetDexCache() != nullptr); // note SetClassRoot does additional validation. // if possible add new checks there to catch errors early } CHECK(GetArrayIfTable() != nullptr); // disable the slow paths in FindClass and CreatePrimitiveClass now // that Object, Class, and Object[] are setup init_done_ = true; // Under sanitization, the small carve-out to handle stack overflow might not be enough to // initialize the StackOverflowError class (as it might require running the verifier). Instead, // ensure that the class will be initialized. if (kMemoryToolIsAvailable && !Runtime::Current()->IsAotCompiler()) { verifier::ClassVerifier::Init(); // Need to prepare the verifier. ObjPtr
soe_klass = FindSystemClass(self, "Ljava/lang/StackOverflowError;"); if (soe_klass == nullptr || !EnsureInitialized(self, hs.NewHandle(soe_klass), true, true)) { // Strange, but don't crash. LOG(WARNING) << "Could not prepare StackOverflowError."; self->ClearException(); } } VLOG(startup) << "ClassLinker::FinishInit exiting"; } void ClassLinker::RunRootClinits(Thread* self) { for (size_t i = 0; i < static_cast
(ClassRoot::kMax); ++i) { ObjPtr
c = GetClassRoot(ClassRoot(i), this); if (!c->IsArrayClass() && !c->IsPrimitive()) { StackHandleScope<1> hs(self); Handle
h_class(hs.NewHandle(c)); EnsureInitialized(self, h_class, true, true); self->AssertNoPendingException(); } else { DCHECK(c->IsInitialized()); } } } struct TrampolineCheckData { const void* quick_resolution_trampoline; const void* quick_imt_conflict_trampoline; const void* quick_generic_jni_trampoline; const void* quick_to_interpreter_bridge_trampoline; PointerSize pointer_size; ArtMethod* m; bool error; }; bool ClassLinker::InitFromBootImage(std::string* error_msg) { VLOG(startup) << __FUNCTION__ << " entering"; CHECK(!init_done_); Runtime* const runtime = Runtime::Current(); Thread* const self = Thread::Current(); gc::Heap* const heap = runtime->GetHeap(); std::vector
spaces = heap->GetBootImageSpaces(); CHECK(!spaces.empty()); uint32_t pointer_size_unchecked = spaces[0]->GetImageHeader().GetPointerSizeUnchecked(); if (!ValidPointerSize(pointer_size_unchecked)) { *error_msg = StringPrintf("Invalid image pointer size: %u", pointer_size_unchecked); return false; } const ImageHeader& image_header = spaces[0]->GetImageHeader(); image_pointer_size_ = image_header.GetPointerSize(); if (!runtime->IsAotCompiler()) { // Only the Aot compiler supports having an image with a different pointer size than the // runtime. This happens on the host for compiling 32 bit tests since we use a 64 bit libart // compiler. We may also use 32 bit dex2oat on a system with 64 bit apps. if (image_pointer_size_ != kRuntimePointerSize) { *error_msg = StringPrintf("Runtime must use current image pointer size: %zu vs %zu", static_cast
(image_pointer_size_), sizeof(void*)); return false; } } DCHECK(!runtime->HasResolutionMethod()); runtime->SetResolutionMethod(image_header.GetImageMethod(ImageHeader::kResolutionMethod)); runtime->SetImtConflictMethod(image_header.GetImageMethod(ImageHeader::kImtConflictMethod)); runtime->SetImtUnimplementedMethod( image_header.GetImageMethod(ImageHeader::kImtUnimplementedMethod)); runtime->SetCalleeSaveMethod( image_header.GetImageMethod(ImageHeader::kSaveAllCalleeSavesMethod), CalleeSaveType::kSaveAllCalleeSaves); runtime->SetCalleeSaveMethod( image_header.GetImageMethod(ImageHeader::kSaveRefsOnlyMethod), CalleeSaveType::kSaveRefsOnly); runtime->SetCalleeSaveMethod( image_header.GetImageMethod(ImageHeader::kSaveRefsAndArgsMethod), CalleeSaveType::kSaveRefsAndArgs); runtime->SetCalleeSaveMethod( image_header.GetImageMethod(ImageHeader::kSaveEverythingMethod), CalleeSaveType::kSaveEverything); runtime->SetCalleeSaveMethod( image_header.GetImageMethod(ImageHeader::kSaveEverythingMethodForClinit), CalleeSaveType::kSaveEverythingForClinit); runtime->SetCalleeSaveMethod( image_header.GetImageMethod(ImageHeader::kSaveEverythingMethodForSuspendCheck), CalleeSaveType::kSaveEverythingForSuspendCheck); std::vector
oat_files = runtime->GetOatFileManager().RegisterImageOatFiles(spaces); DCHECK(!oat_files.empty()); const OatHeader& default_oat_header = oat_files[0]->GetOatHeader(); quick_resolution_trampoline_ = default_oat_header.GetQuickResolutionTrampoline(); quick_imt_conflict_trampoline_ = default_oat_header.GetQuickImtConflictTrampoline(); quick_generic_jni_trampoline_ = default_oat_header.GetQuickGenericJniTrampoline(); quick_to_interpreter_bridge_trampoline_ = default_oat_header.GetQuickToInterpreterBridge(); if (kIsDebugBuild) { // Check that the other images use the same trampoline. for (size_t i = 1; i < oat_files.size(); ++i) { const OatHeader& ith_oat_header = oat_files[i]->GetOatHeader(); const void* ith_quick_resolution_trampoline = ith_oat_header.GetQuickResolutionTrampoline(); const void* ith_quick_imt_conflict_trampoline = ith_oat_header.GetQuickImtConflictTrampoline(); const void* ith_quick_generic_jni_trampoline = ith_oat_header.GetQuickGenericJniTrampoline(); const void* ith_quick_to_interpreter_bridge_trampoline = ith_oat_header.GetQuickToInterpreterBridge(); if (ith_quick_resolution_trampoline != quick_resolution_trampoline_ || ith_quick_imt_conflict_trampoline != quick_imt_conflict_trampoline_ || ith_quick_generic_jni_trampoline != quick_generic_jni_trampoline_ || ith_quick_to_interpreter_bridge_trampoline != quick_to_interpreter_bridge_trampoline_) { // Make sure that all methods in this image do not contain those trampolines as // entrypoints. Otherwise the class-linker won't be able to work with a single set. TrampolineCheckData data; data.error = false; data.pointer_size = GetImagePointerSize(); data.quick_resolution_trampoline = ith_quick_resolution_trampoline; data.quick_imt_conflict_trampoline = ith_quick_imt_conflict_trampoline; data.quick_generic_jni_trampoline = ith_quick_generic_jni_trampoline; data.quick_to_interpreter_bridge_trampoline = ith_quick_to_interpreter_bridge_trampoline; ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_); auto visitor = [&](mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) { if (obj->IsClass()) { ObjPtr
klass = obj->AsClass(); for (ArtMethod& m : klass->GetMethods(data.pointer_size)) { const void* entrypoint = m.GetEntryPointFromQuickCompiledCodePtrSize(data.pointer_size); if (entrypoint == data.quick_resolution_trampoline || entrypoint == data.quick_imt_conflict_trampoline || entrypoint == data.quick_generic_jni_trampoline || entrypoint == data.quick_to_interpreter_bridge_trampoline) { data.m = &m; data.error = true; return; } } } }; spaces[i]->GetLiveBitmap()->Walk(visitor); if (data.error) { ArtMethod* m = data.m; LOG(ERROR) << "Found a broken ArtMethod: " << ArtMethod::PrettyMethod(m); *error_msg = "Found an ArtMethod with a bad entrypoint"; return false; } } } } class_roots_ = GcRoot
>( ObjPtr
>::DownCast( spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots))); DCHECK_EQ(GetClassRoot
(this)->GetClassFlags(), mirror::kClassFlagClass); ObjPtr
java_lang_Object = GetClassRoot
(this); java_lang_Object->SetObjectSize(sizeof(mirror::Object)); // Allocate in non-movable so that it's possible to check if a JNI weak global ref has been // cleared without triggering the read barrier and unintentionally mark the sentinel alive. runtime->SetSentinel(heap->AllocNonMovableObject
( self, java_lang_Object, java_lang_Object->GetObjectSize(), VoidFunctor())); const std::vector
& boot_class_path_locations = runtime->GetBootClassPathLocations(); CHECK_LE(spaces.size(), boot_class_path_locations.size()); for (size_t i = 0u, size = spaces.size(); i != size; ++i) { // Boot class loader, use a null handle. std::vector
> dex_files; if (!AddImageSpace(spaces[i], ScopedNullHandle
(), /*dex_elements=*/ nullptr, /*dex_location=*/ boot_class_path_locations[i].c_str(), /*out*/&dex_files, error_msg)) { return false; } // Assert that if absolute boot classpath locations were provided, they were // assigned to the loaded dex files. if (kIsDebugBuild && IsAbsoluteLocation(boot_class_path_locations[i])) { for (const auto& dex_file : dex_files) { DCHECK_EQ(DexFileLoader::GetBaseLocation(dex_file->GetLocation()), boot_class_path_locations[i]); } } // Append opened dex files at the end. boot_dex_files_.insert(boot_dex_files_.end(), std::make_move_iterator(dex_files.begin()), std::make_move_iterator(dex_files.end())); } for (const std::unique_ptr
& dex_file : boot_dex_files_) { OatDexFile::MadviseDexFile(*dex_file, MadviseState::kMadviseStateAtLoad); } FinishInit(self); VLOG(startup) << __FUNCTION__ << " exiting"; return true; } void ClassLinker::AddExtraBootDexFiles( Thread* self, std::vector
>&& additional_dex_files) { for (std::unique_ptr
& dex_file : additional_dex_files) { AppendToBootClassPath(self, *dex_file); boot_dex_files_.push_back(std::move(dex_file)); } } bool ClassLinker::IsBootClassLoader(ScopedObjectAccessAlreadyRunnable& soa, ObjPtr
class_loader) { return class_loader == nullptr || soa.Decode
(WellKnownClasses::java_lang_BootClassLoader) == class_loader->GetClass(); } static bool GetDexPathListElementName(ObjPtr
element, ObjPtr
* out_name) REQUIRES_SHARED(Locks::mutator_lock_) { ArtField* const dex_file_field = jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile); ArtField* const dex_file_name_field = jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_fileName); DCHECK(dex_file_field != nullptr); DCHECK(dex_file_name_field != nullptr); DCHECK(element != nullptr); CHECK_EQ(dex_file_field->GetDeclaringClass(), element->GetClass()) << element->PrettyTypeOf(); ObjPtr
dex_file = dex_file_field->GetObject(element); if (dex_file == nullptr) { // Null dex file means it was probably a jar with no dex files, return a null string. *out_name = nullptr; return true; } ObjPtr
name_object = dex_file_name_field->GetObject(dex_file); if (name_object != nullptr) { *out_name = name_object->AsString(); return true; } return false; } static bool GetDexFileNames(ScopedObjectAccessUnchecked& soa, ObjPtr
class_loader, /*out*/std::list
>* dex_files, /*out*/std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) { StackHandleScope<1> hs(soa.Self()); Handle
handle(hs.NewHandle(class_loader)); // Get element names. Sets error to true on failure. auto add_element_names = [&](ObjPtr
element, bool* error) REQUIRES_SHARED(Locks::mutator_lock_) { if (element == nullptr) { *error_msg = "Null dex element"; *error = true; // Null element is a critical error. return false; // Had an error, stop the visit. } ObjPtr
name; if (!GetDexPathListElementName(element, &name)) { *error_msg = "Invalid dex path list element"; *error = true; // Invalid element, make it a critical error. return false; // Stop the visit. } if (name != nullptr) { dex_files->push_front(name); } return true; // Continue with the next Element. }; bool error = VisitClassLoaderDexElements(soa, handle, add_element_names, /*defaultReturn=*/ false); return !error; } static bool CompareClassLoaderTypes(ScopedObjectAccessUnchecked& soa, ObjPtr
image_class_loader, ObjPtr
class_loader, std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) { if (ClassLinker::IsBootClassLoader(soa, class_loader)) { if (!ClassLinker::IsBootClassLoader(soa, image_class_loader)) { *error_msg = "Hierarchies don't match"; return false; } } else if (ClassLinker::IsBootClassLoader(soa, image_class_loader)) { *error_msg = "Hierarchies don't match"; return false; } else if (class_loader->GetClass() != image_class_loader->GetClass()) { *error_msg = StringPrintf("Class loader types don't match %s and %s", image_class_loader->PrettyTypeOf().c_str(), class_loader->PrettyTypeOf().c_str()); return false; } else if (soa.Decode
(WellKnownClasses::dalvik_system_PathClassLoader) != class_loader->GetClass()) { *error_msg = StringPrintf("Unknown class loader type %s", class_loader->PrettyTypeOf().c_str()); // Unsupported class loader. return false; } return true; } static bool CompareDexFiles(const std::list
>& image_dex_files, const std::list
>& loader_dex_files, std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) { bool equal = (image_dex_files.size() == loader_dex_files.size()) && std::equal(image_dex_files.begin(), image_dex_files.end(), loader_dex_files.begin(), [](ObjPtr
lhs, ObjPtr
rhs) REQUIRES_SHARED(Locks::mutator_lock_) { return lhs->Equals(rhs); }); if (!equal) { VLOG(image) << "Image dex files " << image_dex_files.size(); for (ObjPtr
name : image_dex_files) { VLOG(image) << name->ToModifiedUtf8(); } VLOG(image) << "Loader dex files " << loader_dex_files.size(); for (ObjPtr
name : loader_dex_files) { VLOG(image) << name->ToModifiedUtf8(); } *error_msg = "Mismatch in dex files"; } return equal; } static bool CompareClassLoaders(ScopedObjectAccessUnchecked& soa, ObjPtr
image_class_loader, ObjPtr
class_loader, bool check_dex_file_names, std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) { if (!CompareClassLoaderTypes(soa, image_class_loader, class_loader, error_msg)) { return false; } if (ClassLinker::IsBootClassLoader(soa, class_loader)) { // No need to check further. return true; } if (check_dex_file_names) { std::list
> image_dex_files; if (!GetDexFileNames(soa, image_class_loader, &image_dex_files, error_msg)) { return false; } std::list
> loader_dex_files; if (!GetDexFileNames(soa, class_loader, &loader_dex_files, error_msg)) { return false; } if (!CompareDexFiles(image_dex_files, loader_dex_files, error_msg)) { return false; } } ArtField* field = jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders); ObjPtr
shared_libraries_image_loader = field->GetObject(image_class_loader.Ptr()); ObjPtr
shared_libraries_loader = field->GetObject(class_loader.Ptr()); if (shared_libraries_image_loader == nullptr) { if (shared_libraries_loader != nullptr) { *error_msg = "Mismatch in shared libraries"; return false; } } else if (shared_libraries_loader == nullptr) { *error_msg = "Mismatch in shared libraries"; return false; } else { ObjPtr
> array1 = shared_libraries_image_loader->AsObjectArray
(); ObjPtr
> array2 = shared_libraries_loader->AsObjectArray
(); if (array1->GetLength() != array2->GetLength()) { *error_msg = "Mismatch in number of shared libraries"; return false; } for (int32_t i = 0; i < array1->GetLength(); ++i) { // Do a full comparison of the class loaders, including comparing their dex files. if (!CompareClassLoaders(soa, array1->Get(i), array2->Get(i), /*check_dex_file_names=*/ true, error_msg)) { return false; } } } // Do a full comparison of the class loaders, including comparing their dex files. if (!CompareClassLoaders(soa, image_class_loader->GetParent(), class_loader->GetParent(), /*check_dex_file_names=*/ true, error_msg)) { return false; } return true; } class CHAOnDeleteUpdateClassVisitor { public: explicit CHAOnDeleteUpdateClassVisitor(LinearAlloc* alloc) : allocator_(alloc), cha_(Runtime::Current()->GetClassLinker()->GetClassHierarchyAnalysis()), pointer_size_(Runtime::Current()->GetClassLinker()->GetImagePointerSize()), self_(Thread::Current()) {} bool operator()(ObjPtr
klass) REQUIRES_SHARED(Locks::mutator_lock_) { // This class is going to be unloaded. Tell CHA about it. cha_->ResetSingleImplementationInHierarchy(klass, allocator_, pointer_size_); return true; } private: const LinearAlloc* allocator_; const ClassHierarchyAnalysis* cha_; const PointerSize pointer_size_; const Thread* self_; }; /* * A class used to ensure that all strings in an AppImage have been properly * interned, and is only ever run in debug mode. */ class VerifyStringInterningVisitor { public: explicit VerifyStringInterningVisitor(const gc::space::ImageSpace& space) : space_(space), intern_table_(*Runtime::Current()->GetInternTable()) {} void TestObject(ObjPtr
referred_obj) const REQUIRES_SHARED(Locks::mutator_lock_) { if (referred_obj != nullptr && space_.HasAddress(referred_obj.Ptr()) && referred_obj->IsString()) { ObjPtr
referred_str = referred_obj->AsString(); if (kIsDebugBuild) { // Saved to temporary variables to aid in debugging. ObjPtr
strong_lookup_result = intern_table_.LookupStrong(Thread::Current(), referred_str); ObjPtr
weak_lookup_result = intern_table_.LookupWeak(Thread::Current(), referred_str); DCHECK((strong_lookup_result == referred_str) || (weak_lookup_result == referred_str)); } } } void VisitRootIfNonNull( mirror::CompressedReference
* root) const REQUIRES_SHARED(Locks::mutator_lock_) { if (!root->IsNull()) { VisitRoot(root); } } void VisitRoot(mirror::CompressedReference
* root) const REQUIRES_SHARED(Locks::mutator_lock_) { TestObject(root->AsMirrorPtr()); } // Visit Class Fields void operator()(ObjPtr
obj, MemberOffset offset, bool is_static ATTRIBUTE_UNUSED) const REQUIRES_SHARED(Locks::mutator_lock_) { // There could be overlap between ranges, we must avoid visiting the same reference twice. // Avoid the class field since we already fixed it up in FixupClassVisitor. if (offset.Uint32Value() != mirror::Object::ClassOffset().Uint32Value()) { // Updating images, don't do a read barrier. ObjPtr
referred_obj = obj->GetFieldObject
(offset); TestObject(referred_obj); } } void operator()(ObjPtr
klass ATTRIBUTE_UNUSED, ObjPtr
ref) const REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_) { operator()(ref, mirror::Reference::ReferentOffset(), false); } const gc::space::ImageSpace& space_; InternTable& intern_table_; }; /* * This function verifies that string references in the AppImage have been * properly interned. To be considered properly interned a reference must * point to the same version of the string that the intern table does. */ void VerifyStringInterning(gc::space::ImageSpace& space) REQUIRES_SHARED(Locks::mutator_lock_) { const gc::accounting::ContinuousSpaceBitmap* bitmap = space.GetMarkBitmap(); const ImageHeader& image_header = space.GetImageHeader(); const uint8_t* target_base = space.GetMemMap()->Begin(); const ImageSection& objects_section = image_header.GetObjectsSection(); auto objects_begin = reinterpret_cast
(target_base + objects_section.Offset()); auto objects_end = reinterpret_cast
(target_base + objects_section.End()); VerifyStringInterningVisitor visitor(space); bitmap->VisitMarkedRange(objects_begin, objects_end, [&space, &visitor](mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) { if (space.HasAddress(obj)) { if (obj->IsDexCache()) { obj->VisitReferences* kVisitNativeRoots= */ true, kVerifyNone, kWithoutReadBarrier>(visitor, visitor); } else { // Don't visit native roots for non-dex-cache as they can't contain // native references to strings. This is verified during compilation // by ImageWriter::VerifyNativeGCRootInvariants. obj->VisitReferences* kVisitNativeRoots= */ false, kVerifyNone, kWithoutReadBarrier>(visitor, visitor); } } }); } // new_class_set is the set of classes that were read from the class table section in the image. // If there was no class table section, it is null. // Note: using a class here to avoid having to make ClassLinker internals public. class AppImageLoadingHelper { public: static void Update( ClassLinker* class_linker, gc::space::ImageSpace* space, Handle
class_loader, Handle
> dex_caches, ClassTable::ClassSet* new_class_set) REQUIRES(!Locks::dex_lock_) REQUIRES_SHARED(Locks::mutator_lock_); static void HandleAppImageStrings(gc::space::ImageSpace* space) REQUIRES_SHARED(Locks::mutator_lock_); static void UpdateInternStrings( gc::space::ImageSpace* space, bool use_preresolved_strings, const SafeMap
& intern_remap) REQUIRES_SHARED(Locks::mutator_lock_); }; void AppImageLoadingHelper::Update( ClassLinker* class_linker, gc::space::ImageSpace* space, Handle
class_loader, Handle
> dex_caches, ClassTable::ClassSet* new_class_set) REQUIRES(!Locks::dex_lock_) REQUIRES_SHARED(Locks::mutator_lock_) { ScopedTrace app_image_timing("AppImage:Updating"); Thread* const self = Thread::Current(); Runtime* const runtime = Runtime::Current(); gc::Heap* const heap = runtime->GetHeap(); const ImageHeader& header = space->GetImageHeader(); bool load_app_image_startup_cache = runtime->LoadAppImageStartupCache(); { // Register dex caches with the class loader. WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); const size_t num_dex_caches = dex_caches->GetLength(); for (size_t i = 0; i < num_dex_caches; i++) { ObjPtr
dex_cache = dex_caches->Get(i); const DexFile* const dex_file = dex_cache->GetDexFile(); { WriterMutexLock mu2(self, *Locks::dex_lock_); CHECK(!class_linker->FindDexCacheDataLocked(*dex_file).IsValid()); class_linker->RegisterDexFileLocked(*dex_file, dex_cache, class_loader.Get()); } if (!load_app_image_startup_cache) { dex_cache->ClearPreResolvedStrings(); } if (kIsDebugBuild) { CHECK(new_class_set != nullptr); mirror::TypeDexCacheType* const types = dex_cache->GetResolvedTypes(); const size_t num_types = dex_cache->NumResolvedTypes(); for (size_t j = 0; j != num_types; ++j) { // The image space is not yet added to the heap, avoid read barriers. ObjPtr
klass = types[j].load(std::memory_order_relaxed).object.Read(); if (space->HasAddress(klass.Ptr())) { DCHECK(!klass->IsErroneous()) << klass->GetStatus(); auto it = new_class_set->find(ClassTable::TableSlot(klass)); DCHECK(it != new_class_set->end()); DCHECK_EQ(it->Read(), klass); ObjPtr
super_class = klass->GetSuperClass(); if (super_class != nullptr && !heap->ObjectIsInBootImageSpace(super_class)) { auto it2 = new_class_set->find(ClassTable::TableSlot(super_class)); DCHECK(it2 != new_class_set->end()); DCHECK_EQ(it2->Read(), super_class); } for (ArtMethod& m : klass->GetDirectMethods(kRuntimePointerSize)) { const void* code = m.GetEntryPointFromQuickCompiledCode(); const void* oat_code = m.IsInvokable() ? class_linker->GetQuickOatCodeFor(&m) : code; if (!class_linker->IsQuickResolutionStub(code) && !class_linker->IsQuickGenericJniStub(code) && !class_linker->IsQuickToInterpreterBridge(code) && !m.IsNative()) { DCHECK_EQ(code, oat_code) << m.PrettyMethod(); } } for (ArtMethod& m : klass->GetVirtualMethods(kRuntimePointerSize)) { const void* code = m.GetEntryPointFromQuickCompiledCode(); const void* oat_code = m.IsInvokable() ? class_linker->GetQuickOatCodeFor(&m) : code; if (!class_linker->IsQuickResolutionStub(code) && !class_linker->IsQuickGenericJniStub(code) && !class_linker->IsQuickToInterpreterBridge(code) && !m.IsNative()) { DCHECK_EQ(code, oat_code) << m.PrettyMethod(); } } } } } } } if (ClassLinker::kAppImageMayContainStrings) { HandleAppImageStrings(space); if (kIsDebugBuild) { VerifyStringInterning(*space); } } if (kVerifyArtMethodDeclaringClasses) { ScopedTrace timing("AppImage:VerifyDeclaringClasses"); ReaderMutexLock rmu(self, *Locks::heap_bitmap_lock_); gc::accounting::HeapBitmap* live_bitmap = heap->GetLiveBitmap(); header.VisitPackedArtMethods([&](ArtMethod& method) REQUIRES_SHARED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) { ObjPtr
klass = method.GetDeclaringClassUnchecked(); if (klass != nullptr) { CHECK(live_bitmap->Test(klass.Ptr())) << "Image method has unmarked declaring class"; } }, space->Begin(), kRuntimePointerSize); } } void AppImageLoadingHelper::UpdateInternStrings( gc::space::ImageSpace* space, bool use_preresolved_strings, const SafeMap
& intern_remap) { const uint8_t* target_base = space->Begin(); const ImageSection& sro_section = space->GetImageHeader().GetImageStringReferenceOffsetsSection(); const size_t num_string_offsets = sro_section.Size() / sizeof(AppImageReferenceOffsetInfo); InternTable* const intern_table = Runtime::Current()->GetInternTable(); VLOG(image) << "ClassLinker:AppImage:InternStrings:imageStringReferenceOffsetCount = " << num_string_offsets; const auto* sro_base = reinterpret_cast
(target_base + sro_section.Offset()); for (size_t offset_index = 0; offset_index < num_string_offsets; ++offset_index) { uint32_t base_offset = sro_base[offset_index].first; if (HasDexCacheStringNativeRefTag(base_offset)) { base_offset = ClearDexCacheNativeRefTags(base_offset); DCHECK_ALIGNED(base_offset, 2); ObjPtr
dex_cache = reinterpret_cast
(space->Begin() + base_offset); uint32_t string_index = sro_base[offset_index].second; mirror::StringDexCachePair source = dex_cache->GetStrings()[string_index].load(); ObjPtr
referred_string = source.object.Read(); DCHECK(referred_string != nullptr); auto it = intern_remap.find(referred_string.Ptr()); if (it != intern_remap.end()) { // This doesn't use SetResolvedString to maintain consistency with how // we load the string. The index from the source string must be // re-used due to the circular nature of the cache. Because we are not // using a helper function we need to mark the GC card manually. WriteBarrier::ForEveryFieldWrite(dex_cache); dex_cache->GetStrings()[string_index].store( mirror::StringDexCachePair(it->second, source.index)); } else if (!use_preresolved_strings) { dex_cache->GetStrings()[string_index].store( mirror::StringDexCachePair(intern_table->InternStrong(referred_string), source.index)); } } else if (HasDexCachePreResolvedStringNativeRefTag(base_offset)) { if (use_preresolved_strings) { base_offset = ClearDexCacheNativeRefTags(base_offset); DCHECK_ALIGNED(base_offset, 2); ObjPtr
dex_cache = reinterpret_cast
(space->Begin() + base_offset); uint32_t string_index = sro_base[offset_index].second; GcRoot
* preresolved_strings = dex_cache->GetPreResolvedStrings(); // Handle calls to ClearPreResolvedStrings that might occur concurrently by the profile // saver that runs shortly after startup. In case the strings are cleared, there is nothing // to fix up. if (preresolved_strings == nullptr) { continue; } ObjPtr
referred_string = preresolved_strings[string_index].Read(); if (referred_string == nullptr) { continue; } auto it = intern_remap.find(referred_string.Ptr()); if (it != intern_remap.end()) { // Because we are not using a helper function we need to mark the GC card manually. WriteBarrier::ForEveryFieldWrite(dex_cache); dex_cache->GetPreResolvedStrings()[string_index] = GcRoot
(it->second); } } } else { uint32_t raw_member_offset = sro_base[offset_index].second; DCHECK_ALIGNED(base_offset, 2); DCHECK_ALIGNED(raw_member_offset, 2); ObjPtr
obj_ptr = reinterpret_cast
(space->Begin() + base_offset); MemberOffset member_offset(raw_member_offset); ObjPtr
referred_string = obj_ptr->GetFieldObject
(member_offset); DCHECK(referred_string != nullptr); auto it = intern_remap.find(referred_string.Ptr()); if (it != intern_remap.end()) { obj_ptr->SetFieldObject* kTransactionActive= */ false, /* kCheckTransaction= */ false, kVerifyNone, /* kIsVolatile= */ false>(member_offset, it->second); } else if (!use_preresolved_strings) { obj_ptr->SetFieldObject* kTransactionActive= */ false, /* kCheckTransaction= */ false, kVerifyNone, /* kIsVolatile= */ false>( member_offset, intern_table->InternStrong(referred_string)); } } } } void AppImageLoadingHelper::HandleAppImageStrings(gc::space::ImageSpace* space) { // Iterate over the string reference offsets stored in the image and intern // the strings they point to. ScopedTrace timing("AppImage:InternString"); Runtime* const runtime = Runtime::Current(); InternTable* const intern_table = runtime->GetInternTable(); const bool load_startup_cache = runtime->LoadAppImageStartupCache(); // Add the intern table, removing any conflicts. For conflicts, store the new address in a map // for faster lookup. // TODO: Optimize with a bitmap or bloom filter SafeMap
intern_remap; auto func = [&](InternTable::UnorderedSet& interns) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_) { const size_t non_boot_image_strings = intern_table->CountInterns( /*visit_boot_images=*/false, /*visit_non_boot_images=*/true); VLOG(image) << "AppImage:stringsInInternTableSize = " << interns.size(); VLOG(image) << "AppImage:nonBootImageInternStrings = " << non_boot_image_strings; // Visit the smaller of the two sets to compute the intersection. if (interns.size() < non_boot_image_strings) { for (auto it = interns.begin(); it != interns.end(); ) { ObjPtr
string = it->Read(); ObjPtr
existing = intern_table->LookupWeakLocked(string); if (existing == nullptr) { existing = intern_table->LookupStrongLocked(string); } if (existing != nullptr) { intern_remap.Put(string.Ptr(), existing.Ptr()); it = interns.erase(it); } else { ++it; } } } else { intern_table->VisitInterns([&](const GcRoot
& root) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_) { auto it = interns.find(root); if (it != interns.end()) { ObjPtr
existing = root.Read(); intern_remap.Put(it->Read(), existing.Ptr()); it = interns.erase(it); } }, /*visit_boot_images=*/false, /*visit_non_boot_images=*/true); } // Sanity check to ensure correctness. if (kIsDebugBuild) { for (GcRoot
& root : interns) { ObjPtr
string = root.Read(); CHECK(intern_table->LookupWeakLocked(string) == nullptr) << string->ToModifiedUtf8(); CHECK(intern_table->LookupStrongLocked(string) == nullptr) << string->ToModifiedUtf8(); } } }; bool update_intern_strings; if (load_startup_cache) { VLOG(image) << "AppImage:load_startup_cache"; // Only add the intern table if we are using the startup cache. Otherwise, // UpdateInternStrings adds the strings to the intern table. intern_table->AddImageStringsToTable(space, func); update_intern_strings = kIsDebugBuild || !intern_remap.empty(); VLOG(image) << "AppImage:conflictingInternStrings = " << intern_remap.size(); } else { update_intern_strings = true; } // For debug builds, always run the code below to get coverage. if (update_intern_strings) { // Slow path case is when there are conflicting intern strings to fix up. UpdateInternStrings(space, /*use_preresolved_strings=*/ load_startup_cache, intern_remap); } } static std::unique_ptr
OpenOatDexFile(const OatFile* oat_file, const char* location, std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(error_msg != nullptr); std::unique_ptr
dex_file; const OatDexFile* oat_dex_file = oat_file->GetOatDexFile(location, nullptr, error_msg); if (oat_dex_file == nullptr) { return std::unique_ptr
(); } std::string inner_error_msg; dex_file = oat_dex_file->OpenDexFile(&inner_error_msg); if (dex_file == nullptr) { *error_msg = StringPrintf("Failed to open dex file %s from within oat file %s error '%s'", location, oat_file->GetLocation().c_str(), inner_error_msg.c_str()); return std::unique_ptr
(); } if (dex_file->GetLocationChecksum() != oat_dex_file->GetDexFileLocationChecksum()) { *error_msg = StringPrintf("Checksums do not match for %s: %x vs %x", location, dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum()); return std::unique_ptr
(); } return dex_file; } bool ClassLinker::OpenImageDexFiles(gc::space::ImageSpace* space, std::vector
>* out_dex_files, std::string* error_msg) { ScopedAssertNoThreadSuspension nts(__FUNCTION__); const ImageHeader& header = space->GetImageHeader(); ObjPtr
dex_caches_object = header.GetImageRoot(ImageHeader::kDexCaches); DCHECK(dex_caches_object != nullptr); ObjPtr
> dex_caches = dex_caches_object->AsObjectArray
(); const OatFile* oat_file = space->GetOatFile(); for (int32_t i = 0, length = dex_caches->GetLength(); i != length; ++i) { ObjPtr
dex_cache = dex_caches->Get(i); std::string dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8()); std::unique_ptr
dex_file = OpenOatDexFile(oat_file, dex_file_location.c_str(), error_msg); if (dex_file == nullptr) { return false; } dex_cache->SetDexFile(dex_file.get()); out_dex_files->push_back(std::move(dex_file)); } return true; } // Helper class for ArtMethod checks when adding an image. Keeps all required functionality // together and caches some intermediate results. class ImageSanityChecks final { public: static void CheckObjects(gc::Heap* heap, ClassLinker* class_linker) REQUIRES_SHARED(Locks::mutator_lock_) { ImageSanityChecks isc(heap, class_linker); auto visitor = [&](mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(obj != nullptr); CHECK(obj->GetClass() != nullptr) << "Null class in object " << obj; CHECK(obj->GetClass()->GetClass() != nullptr) << "Null class class " << obj; if (obj->IsClass()) { auto klass = obj->AsClass(); for (ArtField& field : klass->GetIFields()) { CHECK_EQ(field.GetDeclaringClass(), klass); } for (ArtField& field : klass->GetSFields()) { CHECK_EQ(field.GetDeclaringClass(), klass); } const PointerSize pointer_size = isc.pointer_size_; for (ArtMethod& m : klass->GetMethods(pointer_size)) { isc.SanityCheckArtMethod(&m, klass); } ObjPtr
vtable = klass->GetVTable(); if (vtable != nullptr) { isc.SanityCheckArtMethodPointerArray(vtable, nullptr); } if (klass->ShouldHaveImt()) { ImTable* imt = klass->GetImt(pointer_size); for (size_t i = 0; i < ImTable::kSize; ++i) { isc.SanityCheckArtMethod(imt->Get(i, pointer_size), nullptr); } } if (klass->ShouldHaveEmbeddedVTable()) { for (int32_t i = 0; i < klass->GetEmbeddedVTableLength(); ++i) { isc.SanityCheckArtMethod(klass->GetEmbeddedVTableEntry(i, pointer_size), nullptr); } } ObjPtr
iftable = klass->GetIfTable(); for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) { if (iftable->GetMethodArrayCount(i) > 0) { isc.SanityCheckArtMethodPointerArray(iftable->GetMethodArray(i), nullptr); } } } }; heap->VisitObjects(visitor); } static void CheckArtMethodDexCacheArray(gc::Heap* heap, ClassLinker* class_linker, mirror::MethodDexCacheType* arr, size_t size) REQUIRES_SHARED(Locks::mutator_lock_) { ImageSanityChecks isc(heap, class_linker); isc.SanityCheckArtMethodDexCacheArray(arr, size); } private: ImageSanityChecks(gc::Heap* heap, ClassLinker* class_linker) : spaces_(heap->GetBootImageSpaces()), pointer_size_(class_linker->GetImagePointerSize()) { space_begin_.reserve(spaces_.size()); method_sections_.reserve(spaces_.size()); runtime_method_sections_.reserve(spaces_.size()); for (gc::space::ImageSpace* space : spaces_) { space_begin_.push_back(space->Begin()); auto& header = space->GetImageHeader(); method_sections_.push_back(&header.GetMethodsSection()); runtime_method_sections_.push_back(&header.GetRuntimeMethodsSection()); } } void SanityCheckArtMethod(ArtMethod* m, ObjPtr
expected_class) REQUIRES_SHARED(Locks::mutator_lock_) { if (m->IsRuntimeMethod()) { ObjPtr
declaring_class = m->GetDeclaringClassUnchecked(); CHECK(declaring_class == nullptr) << declaring_class << " " << m->PrettyMethod(); } else if (m->IsCopied()) { CHECK(m->GetDeclaringClass() != nullptr) << m->PrettyMethod(); } else if (expected_class != nullptr) { CHECK_EQ(m->GetDeclaringClassUnchecked(), expected_class) << m->PrettyMethod(); } if (!spaces_.empty()) { bool contains = false; for (size_t i = 0; !contains && i != space_begin_.size(); ++i) { const size_t offset = reinterpret_cast
(m) - space_begin_[i]; contains = method_sections_[i]->Contains(offset) || runtime_method_sections_[i]->Contains(offset); } CHECK(contains) << m << " not found"; } } void SanityCheckArtMethodPointerArray(ObjPtr
arr, ObjPtr
expected_class) REQUIRES_SHARED(Locks::mutator_lock_) { CHECK(arr != nullptr); for (int32_t j = 0; j < arr->GetLength(); ++j) { auto* method = arr->GetElementPtrSize
(j, pointer_size_); // expected_class == null means we are a dex cache. if (expected_class != nullptr) { CHECK(method != nullptr); } if (method != nullptr) { SanityCheckArtMethod(method, expected_class); } } } void SanityCheckArtMethodDexCacheArray(mirror::MethodDexCacheType* arr, size_t size) REQUIRES_SHARED(Locks::mutator_lock_) { CHECK_EQ(arr != nullptr, size != 0u); if (arr != nullptr) { bool contains = false; for (auto space : spaces_) { auto offset = reinterpret_cast
(arr) - space->Begin(); if (space->GetImageHeader().GetDexCacheArraysSection().Contains(offset)) { contains = true; break; } } CHECK(contains); } for (size_t j = 0; j < size; ++j) { auto pair = mirror::DexCache::GetNativePairPtrSize(arr, j, pointer_size_); ArtMethod* method = pair.object; // expected_class == null means we are a dex cache. if (method != nullptr) { SanityCheckArtMethod(method, nullptr); } } } const std::vector
& spaces_; const PointerSize pointer_size_; // Cached sections from the spaces. std::vector
space_begin_; std::vector
method_sections_; std::vector
runtime_method_sections_; }; static void VerifyAppImage(const ImageHeader& header, const Handle
& class_loader, const Handle
>& dex_caches, ClassTable* class_table, gc::space::ImageSpace* space) REQUIRES_SHARED(Locks::mutator_lock_) { header.VisitPackedArtMethods([&](ArtMethod& method) REQUIRES_SHARED(Locks::mutator_lock_) { ObjPtr
klass = method.GetDeclaringClass(); if (klass != nullptr && !Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) { CHECK_EQ(class_table->LookupByDescriptor(klass), klass) << mirror::Class::PrettyClass(klass); } }, space->Begin(), kRuntimePointerSize); { // Verify that all direct interfaces of classes in the class table are also resolved. std::vector
> classes; auto verify_direct_interfaces_in_table = [&](ObjPtr
klass) REQUIRES_SHARED(Locks::mutator_lock_) { if (!klass->IsPrimitive() && klass->GetClassLoader() == class_loader.Get()) { classes.push_back(klass); } return true; }; class_table->Visit(verify_direct_interfaces_in_table); Thread* self = Thread::Current(); for (ObjPtr
klass : classes) { for (uint32_t i = 0, num = klass->NumDirectInterfaces(); i != num; ++i) { CHECK(klass->GetDirectInterface(self, klass, i) != nullptr) << klass->PrettyDescriptor() << " iface #" << i; } } } // Check that all non-primitive classes in dex caches are also in the class table. for (int32_t i = 0; i < dex_caches->GetLength(); i++) { ObjPtr
dex_cache = dex_caches->Get(i); mirror::TypeDexCacheType* const types = dex_cache->GetResolvedTypes(); for (int32_t j = 0, num_types = dex_cache->NumResolvedTypes(); j < num_types; j++) { ObjPtr
klass = types[j].load(std::memory_order_relaxed).object.Read(); if (klass != nullptr && !klass->IsPrimitive()) { CHECK(class_table->Contains(klass)) << klass->PrettyDescriptor() << " " << dex_cache->GetDexFile()->GetLocation(); } } } } bool ClassLinker::AddImageSpace( gc::space::ImageSpace* space, Handle
class_loader, jobjectArray dex_elements, const char* dex_location, std::vector
>* out_dex_files, std::string* error_msg) { DCHECK(out_dex_files != nullptr); DCHECK(error_msg != nullptr); const uint64_t start_time = NanoTime(); const bool app_image = class_loader != nullptr; const ImageHeader& header = space->GetImageHeader(); ObjPtr
dex_caches_object = header.GetImageRoot(ImageHeader::kDexCaches); DCHECK(dex_caches_object != nullptr); Runtime* const runtime = Runtime::Current(); gc::Heap* const heap = runtime->GetHeap(); Thread* const self = Thread::Current(); // Check that the image is what we are expecting. if (image_pointer_size_ != space->GetImageHeader().GetPointerSize()) { *error_msg = StringPrintf("Application image pointer size does not match runtime: %zu vs %zu", static_cast
(space->GetImageHeader().GetPointerSize()), image_pointer_size_); return false; } size_t expected_image_roots = ImageHeader::NumberOfImageRoots(app_image); if (static_cast
(header.GetImageRoots()->GetLength()) != expected_image_roots) { *error_msg = StringPrintf("Expected %zu image roots but got %d", expected_image_roots, header.GetImageRoots()->GetLength()); return false; } StackHandleScope<3> hs(self); Handle
> dex_caches( hs.NewHandle(dex_caches_object->AsObjectArray
())); Handle
> class_roots(hs.NewHandle( header.GetImageRoot(ImageHeader::kClassRoots)->AsObjectArray
())); MutableHandle
image_class_loader(hs.NewHandle( app_image ? header.GetImageRoot(ImageHeader::kAppImageClassLoader)->AsClassLoader() : nullptr)); DCHECK(class_roots != nullptr); if (class_roots->GetLength() != static_cast
(ClassRoot::kMax)) { *error_msg = StringPrintf("Expected %d class roots but got %d", class_roots->GetLength(), static_cast
(ClassRoot::kMax)); return false; } // Check against existing class roots to make sure they match the ones in the boot image. ObjPtr
> existing_class_roots = GetClassRoots(); for (size_t i = 0; i < static_cast
(ClassRoot::kMax); i++) { if (class_roots->Get(i) != GetClassRoot(static_cast
(i), existing_class_roots)) { *error_msg = "App image class roots must have pointer equality with runtime ones."; return false; } } const OatFile* oat_file = space->GetOatFile(); if (oat_file->GetOatHeader().GetDexFileCount() != static_cast
(dex_caches->GetLength())) { *error_msg = "Dex cache count and dex file count mismatch while trying to initialize from " "image"; return false; } for (int32_t i = 0; i < dex_caches->GetLength(); i++) { ObjPtr
dex_cache = dex_caches->Get(i); std::string dex_file_location = dex_cache->GetLocation()->ToModifiedUtf8(); if (class_loader == nullptr) { // For app images, we'll see the relative location. b/130666977. DCHECK_EQ(dex_location, DexFileLoader::GetBaseLocation(dex_file_location)); } std::unique_ptr
dex_file = OpenOatDexFile(oat_file, dex_file_location.c_str(), error_msg); if (dex_file == nullptr) { return false; } if (app_image) { // The current dex file field is bogus, overwrite it so that we can get the dex file in the // loop below. dex_cache->SetDexFile(dex_file.get()); mirror::TypeDexCacheType* const types = dex_cache->GetResolvedTypes(); for (int32_t j = 0, num_types = dex_cache->NumResolvedTypes(); j < num_types; j++) { ObjPtr
klass = types[j].load(std::memory_order_relaxed).object.Read(); if (klass != nullptr) { DCHECK(!klass->IsErroneous()) << klass->GetStatus(); } } } else { if (kSanityCheckObjects) { ImageSanityChecks::CheckArtMethodDexCacheArray(heap, this, dex_cache->GetResolvedMethods(), dex_cache->NumResolvedMethods()); } // Register dex files, keep track of existing ones that are conflicts. AppendToBootClassPath(*dex_file.get(), dex_cache); } out_dex_files->push_back(std::move(dex_file)); } if (app_image) { ScopedObjectAccessUnchecked soa(Thread::Current()); ScopedAssertNoThreadSuspension sants("Checking app image", soa.Self()); // Check that the class loader resolves the same way as the ones in the image. // Image class loader [A][B][C][image dex files] // Class loader = [???][dex_elements][image dex files] // Need to ensure that [???][dex_elements] == [A][B][C]. // For each class loader, PathClassLoader, the loader checks the parent first. Also the logic // for PathClassLoader does this by looping through the array of dex files. To ensure they // resolve the same way, simply flatten the hierarchy in the way the resolution order would be, // and check that the dex file names are the same. if (IsBootClassLoader(soa, image_class_loader.Get())) { *error_msg = "Unexpected BootClassLoader in app image"; return false; } // The dex files of `class_loader` are not setup yet, so we cannot do a full comparison // of `class_loader` and `image_class_loader` in `CompareClassLoaders`. Therefore, we // special case the comparison of dex files of the two class loaders, but then do full // comparisons for their shared libraries and parent. auto elements = soa.Decode
>(dex_elements); std::list
> loader_dex_file_names; for (size_t i = 0, num_elems = elements->GetLength(); i < num_elems; ++i) { ObjPtr
element = elements->GetWithoutChecks(i); if (element != nullptr) { // If we are somewhere in the middle of the array, there may be nulls at the end. ObjPtr
name; if (GetDexPathListElementName(element, &name) && name != nullptr) { loader_dex_file_names.push_back(name); } } } std::string temp_error_msg; std::list
> image_dex_file_names; bool success = GetDexFileNames( soa, image_class_loader.Get(), &image_dex_file_names, &temp_error_msg); if (success) { // Ignore the number of image dex files since we are adding those to the class loader anyways. CHECK_GE(static_cast
(image_dex_file_names.size()), static_cast
(dex_caches->GetLength())); size_t image_count = image_dex_file_names.size() - dex_caches->GetLength(); image_dex_file_names.resize(image_count); success = success && CompareDexFiles(image_dex_file_names, loader_dex_file_names, &temp_error_msg); success = success && CompareClassLoaders(soa, image_class_loader.Get(), class_loader.Get(), /*check_dex_file_names=*/ false, &temp_error_msg); } if (!success) { *error_msg = StringPrintf("Rejecting application image due to class loader mismatch: '%s'", temp_error_msg.c_str()); return false; } } if (kSanityCheckObjects) { for (int32_t i = 0; i < dex_caches->GetLength(); i++) { ObjPtr
dex_cache = dex_caches->Get(i); for (size_t j = 0; j < dex_cache->NumResolvedFields(); ++j) { auto* field = dex_cache->GetResolvedField(j, image_pointer_size_); if (field != nullptr) { CHECK(field->GetDeclaringClass()->GetClass() != nullptr); } } } if (!app_image) { ImageSanityChecks::CheckObjects(heap, this); } } // Set entry point to interpreter if in InterpretOnly mode. if (!runtime->IsAotCompiler() && runtime->GetInstrumentation()->InterpretOnly()) { // Set image methods' entry point to interpreter. header.VisitPackedArtMethods([&](ArtMethod& method) REQUIRES_SHARED(Locks::mutator_lock_) { if (!method.IsRuntimeMethod()) { DCHECK(method.GetDeclaringClass() != nullptr); if (!method.IsNative() && !method.IsResolutionMethod()) { method.SetEntryPointFromQuickCompiledCodePtrSize(GetQuickToInterpreterBridge(), image_pointer_size_); } } }, space->Begin(), image_pointer_size_); } ClassTable* class_table = nullptr; { WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); class_table = InsertClassTableForClassLoader(class_loader.Get()); } // If we have a class table section, read it and use it for verification in // UpdateAppImageClassLoadersAndDexCaches. ClassTable::ClassSet temp_set; const ImageSection& class_table_section = header.GetClassTableSection(); const bool added_class_table = class_table_section.Size() > 0u; if (added_class_table) { const uint64_t start_time2 = NanoTime(); size_t read_count = 0; temp_set = ClassTable::ClassSet(space->Begin() + class_table_section.Offset(), /*make copy*/false, &read_count); VLOG(image) << "Adding class table classes took " << PrettyDuration(NanoTime() - start_time2); } if (app_image) { AppImageLoadingHelper::Update(this, space, class_loader, dex_caches, &temp_set); { ScopedTrace trace("AppImage:UpdateClassLoaders"); // Update class loader and resolved strings. If added_class_table is false, the resolved // strings were forwarded UpdateAppImageClassLoadersAndDexCaches. ObjPtr
loader(class_loader.Get()); for (const ClassTable::TableSlot& root : temp_set) { // Note: We probably don't need the read barrier unless we copy the app image objects into // the region space. ObjPtr
klass(root.Read()); // Do not update class loader for boot image classes where the app image // class loader is only the initiating loader but not the defining loader. // Avoid read barrier since we are comparing against null. if (klass->GetClassLoader
() != nullptr) { klass->SetClassLoader*kCheckTransaction=*/ false>(loader); } } } if (kBitstringSubtypeCheckEnabled) { // Every class in the app image has initially SubtypeCheckInfo in the // Uninitialized state. // // The SubtypeCheck invariants imply that a SubtypeCheckInfo is at least Initialized // after class initialization is complete. The app image ClassStatus as-is // are almost all ClassStatus::Initialized, and being in the // SubtypeCheckInfo::kUninitialized state is violating that invariant. // // Force every app image class's SubtypeCheck to be at least kIninitialized. // // See also ImageWriter::FixupClass. ScopedTrace trace("AppImage:RecacluateSubtypeCheckBitstrings"); MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_); for (const ClassTable::TableSlot& root : temp_set) { SubtypeCheck
>::EnsureInitialized(root.Read()); } } } if (!oat_file->GetBssGcRoots().empty()) { // Insert oat file to class table for visiting .bss GC roots. class_table->InsertOatFile(oat_file); } if (added_class_table) { WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); class_table->AddClassSet(std::move(temp_set)); } if (kIsDebugBuild && app_image) { // This verification needs to happen after the classes have been added to the class loader. // Since it ensures classes are in the class table. ScopedTrace trace("AppImage:Verify"); VerifyAppImage(header, class_loader, dex_caches, class_table, space); } VLOG(class_linker) << "Adding image space took " << PrettyDuration(NanoTime() - start_time); return true; } bool ClassLinker::ClassInClassTable(ObjPtr
klass) { ClassTable* const class_table = ClassTableForClassLoader(klass->GetClassLoader()); return class_table != nullptr && class_table->Contains(klass); } void ClassLinker::VisitClassRoots(RootVisitor* visitor, VisitRootFlags flags) { // Acquire tracing_enabled before locking class linker lock to prevent lock order violation. Since // enabling tracing requires the mutator lock, there are no race conditions here. const bool tracing_enabled = Trace::IsTracingEnabled(); Thread* const self = Thread::Current(); WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); if (kUseReadBarrier) { // We do not track new roots for CC. DCHECK_EQ(0, flags & (kVisitRootFlagNewRoots | kVisitRootFlagClearRootLog | kVisitRootFlagStartLoggingNewRoots | kVisitRootFlagStopLoggingNewRoots)); } if ((flags & kVisitRootFlagAllRoots) != 0) { // Argument for how root visiting deals with ArtField and ArtMethod roots. // There is 3 GC cases to handle: // Non moving concurrent: // This case is easy to handle since the reference members of ArtMethod and ArtFields are held // live by the class and class roots. // // Moving non-concurrent: // This case needs to call visit VisitNativeRoots in case the classes or dex cache arrays move. // To prevent missing roots, this case needs to ensure that there is no // suspend points between the point which we allocate ArtMethod arrays and place them in a // class which is in the class table. // // Moving concurrent: // Need to make sure to not copy ArtMethods without doing read barriers since the roots are // marked concurrently and we don't hold the classlinker_classes_lock_ when we do the copy. // // Use an unbuffered visitor since the class table uses a temporary GcRoot for holding decoded // ClassTable::TableSlot. The buffered root visiting would access a stale stack location for // these objects. UnbufferedRootVisitor root_visitor(visitor, RootInfo(kRootStickyClass)); boot_class_table_->VisitRoots(root_visitor); // If tracing is enabled, then mark all the class loaders to prevent unloading. if ((flags & kVisitRootFlagClassLoader) != 0 || tracing_enabled) { for (const ClassLoaderData& data : class_loaders_) { GcRoot
root(GcRoot
(self->DecodeJObject(data.weak_root))); root.VisitRoot(visitor, RootInfo(kRootVMInternal)); } } } else if (!kUseReadBarrier && (flags & kVisitRootFlagNewRoots) != 0) { for (auto& root : new_class_roots_) { ObjPtr
old_ref = root.Read
(); root.VisitRoot(visitor, RootInfo(kRootStickyClass)); ObjPtr
new_ref = root.Read
(); // Concurrent moving GC marked new roots through the to-space invariant. CHECK_EQ(new_ref, old_ref); } for (const OatFile* oat_file : new_bss_roots_boot_oat_files_) { for (GcRoot
& root : oat_file->GetBssGcRoots()) { ObjPtr
old_ref = root.Read
(); if (old_ref != nullptr) { DCHECK(old_ref->IsClass()); root.VisitRoot(visitor, RootInfo(kRootStickyClass)); ObjPtr
new_ref = root.Read
(); // Concurrent moving GC marked new roots through the to-space invariant. CHECK_EQ(new_ref, old_ref); } } } } if (!kUseReadBarrier && (flags & kVisitRootFlagClearRootLog) != 0) { new_class_roots_.clear(); new_bss_roots_boot_oat_files_.clear(); } if (!kUseReadBarrier && (flags & kVisitRootFlagStartLoggingNewRoots) != 0) { log_new_roots_ = true; } else if (!kUseReadBarrier && (flags & kVisitRootFlagStopLoggingNewRoots) != 0) { log_new_roots_ = false; } // We deliberately ignore the class roots in the image since we // handle image roots by using the MS/CMS rescanning of dirty cards. } // Keep in sync with InitCallback. Anything we visit, we need to // reinit references to when reinitializing a ClassLinker from a // mapped image. void ClassLinker::VisitRoots(RootVisitor* visitor, VisitRootFlags flags) { class_roots_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal)); VisitClassRoots(visitor, flags); // Instead of visiting the find_array_class_cache_ drop it so that it doesn't prevent class // unloading if we are marking roots. DropFindArrayClassCache(); } class VisitClassLoaderClassesVisitor : public ClassLoaderVisitor { public: explicit VisitClassLoaderClassesVisitor(ClassVisitor* visitor) : visitor_(visitor), done_(false) {} void Visit(ObjPtr
class_loader) REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_) override { ClassTable* const class_table = class_loader->GetClassTable(); if (!done_ && class_table != nullptr) { DefiningClassLoaderFilterVisitor visitor(class_loader, visitor_); if (!class_table->Visit(visitor)) { // If the visitor ClassTable returns false it means that we don't need to continue. done_ = true; } } } private: // Class visitor that limits the class visits from a ClassTable to the classes with // the provided defining class loader. This filter is used to avoid multiple visits // of the same class which can be recorded for multiple initiating class loaders. class DefiningClassLoaderFilterVisitor : public ClassVisitor { public: DefiningClassLoaderFilterVisitor(ObjPtr
defining_class_loader, ClassVisitor* visitor) : defining_class_loader_(defining_class_loader), visitor_(visitor) { } bool operator()(ObjPtr
klass) override REQUIRES_SHARED(Locks::mutator_lock_) { if (klass->GetClassLoader() != defining_class_loader_) { return true; } return (*visitor_)(klass); } const ObjPtr
defining_class_loader_; ClassVisitor* const visitor_; }; ClassVisitor* const visitor_; // If done is true then we don't need to do any more visiting. bool done_; }; void ClassLinker::VisitClassesInternal(ClassVisitor* visitor) { if (boot_class_table_->Visit(*visitor)) { VisitClassLoaderClassesVisitor loader_visitor(visitor); VisitClassLoaders(&loader_visitor); } } void ClassLinker::VisitClasses(ClassVisitor* visitor) { Thread* const self = Thread::Current(); ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_); // Not safe to have thread suspension when we are holding a lock. if (self != nullptr) { ScopedAssertNoThreadSuspension nts(__FUNCTION__); VisitClassesInternal(visitor); } else { VisitClassesInternal(visitor); } } class GetClassesInToVector : public ClassVisitor { public: bool operator()(ObjPtr
klass) override { classes_.push_back(klass); return true; } std::vector
> classes_; }; class GetClassInToObjectArray : public ClassVisitor { public: explicit GetClassInToObjectArray(mirror::ObjectArray
* arr) : arr_(arr), index_(0) {} bool operator()(ObjPtr
klass) override REQUIRES_SHARED(Locks::mutator_lock_) { ++index_; if (index_ <= arr_->GetLength()) { arr_->Set(index_ - 1, klass); return true; } return false; } bool Succeeded() const REQUIRES_SHARED(Locks::mutator_lock_) { return index_ <= arr_->GetLength(); } private: mirror::ObjectArray