HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Pie
|
9.0.0_r8
下载
查看原文件
收藏
根目录
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 "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/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_table-inl.h" #include "compiler_callbacks.h" #include "debug_print.h" #include "debugger.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/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.h" #include "interpreter/interpreter.h" #include "java_vm_ext.h" #include "jit/debugger_interface.h" #include "jit/jit.h" #include "jit/jit_code_cache.h" #include "jit/profile_compilation_info.h" #include "jni_internal.h" #include "linear_alloc.h" #include "mirror/call_site.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-inl.h" #include "mirror/proxy.h" #include "mirror/reference-inl.h" #include "mirror/stack_trace_element.h" #include "mirror/string-inl.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 "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/method_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 mirror::Object* 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 = self->DecodeJObject(WellKnownClasses::java_lang_Throwable)->AsClass(); ObjPtr
error_class = obj->GetClass(); CHECK(throwable_class->IsAssignableFrom(error_class)); self->SetException(obj->AsThrowable()); } self->AssertPendingException(); } void ClassLinker::ThrowEarlierClassFailure(ObjPtr
c, bool wrap_in_no_class_def) { // 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; if (GetVerifyError(c) != nullptr) { ObjPtr
verify_error = GetVerifyError(c); if (verify_error->IsClass()) { extra = mirror::Class::PrettyDescriptor(verify_error->AsClass()); } else { extra = verify_error->AsThrowable()->Dump(); } } 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 { if (GetVerifyError(c) != 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 (GetVerifyError(c) == 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; LOG(kIsDebugBuild ? 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); } }; typedef std::priority_queue
, FieldGapsComparator> FieldGaps; // 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) : boot_class_table_(new ClassTable()), failed_dex_cache_class_lookups_(0), class_roots_(nullptr), array_iftable_(nullptr), find_array_class_cache_next_victim_(0), init_done_(false), log_new_roots_(false), intern_table_(intern_table), 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_); Handle
java_lang_Class(hs.NewHandle(down_cast
( heap->AllocNonMovableObject
(self, nullptr, class_class_size, VoidFunctor())))); CHECK(java_lang_Class != nullptr); mirror::Class::SetClassClass(java_lang_Class.Get()); 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 the char (primitive) class to be used for char[]. Handle
char_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Class::PrimitiveClassSize(image_pointer_size_)))); // The primitive char class won't be initialized by // InitializePrimitiveClass until line 459, but strings (and // internal char arrays) will be allocated before that and the // component size, which is computed from the primitive type, needs // to be set here. char_class->SetPrimitiveType(Primitive::kPrimChar); // Setup the char[] class to be used for String. Handle
char_array_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); char_array_class->SetComponentType(char_class.Get()); mirror::CharArray::SetArrayClass(char_array_class.Get()); // Setup String. Handle
java_lang_String(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_)))); java_lang_String->SetStringClass(); mirror::String::SetClass(java_lang_String.Get()); 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_)))); mirror::Reference::SetClass(java_lang_ref_Reference.Get()); 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(), kClassRootsMax)); CHECK(!class_roots_.IsNull()); SetClassRoot(kJavaLangClass, java_lang_Class.Get()); SetClassRoot(kJavaLangObject, java_lang_Object.Get()); SetClassRoot(kClassArrayClass, class_array_class.Get()); SetClassRoot(kObjectArrayClass, object_array_class.Get()); SetClassRoot(kCharArrayClass, char_array_class.Get()); SetClassRoot(kJavaLangString, java_lang_String.Get()); SetClassRoot(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)); // Setup the primitive type classes. SetClassRoot(kPrimitiveBoolean, CreatePrimitiveClass(self, Primitive::kPrimBoolean)); SetClassRoot(kPrimitiveByte, CreatePrimitiveClass(self, Primitive::kPrimByte)); SetClassRoot(kPrimitiveShort, CreatePrimitiveClass(self, Primitive::kPrimShort)); SetClassRoot(kPrimitiveInt, CreatePrimitiveClass(self, Primitive::kPrimInt)); SetClassRoot(kPrimitiveLong, CreatePrimitiveClass(self, Primitive::kPrimLong)); SetClassRoot(kPrimitiveFloat, CreatePrimitiveClass(self, Primitive::kPrimFloat)); SetClassRoot(kPrimitiveDouble, CreatePrimitiveClass(self, Primitive::kPrimDouble)); SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass(self, Primitive::kPrimVoid)); // Create array interface entries to populate once we can load system classes. array_iftable_ = GcRoot
(AllocIfTable(self, 2)); // Create int array type for AllocDexCache (done in AppendToBootClassPath). Handle
int_array_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); int_array_class->SetComponentType(GetClassRoot(kPrimitiveInt)); mirror::IntArray::SetArrayClass(int_array_class.Get()); SetClassRoot(kIntArrayClass, int_array_class.Get()); // Create long array type for AllocDexCache (done in AppendToBootClassPath). Handle
long_array_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); long_array_class->SetComponentType(GetClassRoot(kPrimitiveLong)); mirror::LongArray::SetArrayClass(long_array_class.Get()); SetClassRoot(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(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(kDalvikSystemClassExt, dalvik_system_ClassExt.Get()); mirror::ClassExt::SetClass(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(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 // run char class through InitializePrimitiveClass to finish init InitializePrimitiveClass(char_class.Get(), Primitive::kPrimChar); SetClassRoot(kPrimitiveChar, char_class.Get()); // needs descriptor // 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. SetClassRoot(kBooleanArrayClass, FindSystemClass(self, "[Z")); mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass)); SetClassRoot(kByteArrayClass, FindSystemClass(self, "[B")); mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass)); CheckSystemClass(self, char_array_class, "[C"); SetClassRoot(kShortArrayClass, FindSystemClass(self, "[S")); mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass)); CheckSystemClass(self, int_array_class, "[I"); CheckSystemClass(self, long_array_class, "[J"); SetClassRoot(kFloatArrayClass, FindSystemClass(self, "[F")); mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass)); SetClassRoot(kDoubleArrayClass, FindSystemClass(self, "[D")); mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass)); // 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. array_iftable_.Read()->SetInterface(0, java_lang_Cloneable.Get()); array_iftable_.Read()->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(kJavaLangStringArrayClass))); // End of special init trickery, all subsequent classes may be loaded via FindSystemClass. // Create java.lang.reflect.Proxy root. SetClassRoot(kJavaLangReflectProxy, FindSystemClass(self, "Ljava/lang/reflect/Proxy;")); // Create java.lang.reflect.Field.class root. auto* class_root = FindSystemClass(self, "Ljava/lang/reflect/Field;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangReflectField, class_root); mirror::Field::SetClass(class_root); // Create java.lang.reflect.Field array root. class_root = FindSystemClass(self, "[Ljava/lang/reflect/Field;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangReflectFieldArrayClass, class_root); mirror::Field::SetArrayClass(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(kJavaLangReflectConstructor, class_root); mirror::Constructor::SetClass(class_root); class_root = FindSystemClass(self, "[Ljava/lang/reflect/Constructor;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangReflectConstructorArrayClass, class_root); mirror::Constructor::SetArrayClass(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(kJavaLangReflectMethod, class_root); mirror::Method::SetClass(class_root); class_root = FindSystemClass(self, "[Ljava/lang/reflect/Method;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangReflectMethodArrayClass, class_root); mirror::Method::SetArrayClass(class_root); // Create java.lang.invoke.CallSite.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/CallSite;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangInvokeCallSite, class_root); mirror::CallSite::SetClass(class_root); // Create java.lang.invoke.MethodType.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodType;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangInvokeMethodType, class_root); mirror::MethodType::SetClass(class_root); // Create java.lang.invoke.MethodHandleImpl.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodHandleImpl;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangInvokeMethodHandleImpl, class_root); mirror::MethodHandleImpl::SetClass(class_root); // Create java.lang.invoke.MethodHandles.Lookup.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodHandles$Lookup;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangInvokeMethodHandlesLookup, class_root); mirror::MethodHandlesLookup::SetClass(class_root); // Create java.lang.invoke.VarHandle.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/VarHandle;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangInvokeVarHandle, class_root); mirror::VarHandle::SetClass(class_root); // Create java.lang.invoke.FieldVarHandle.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/FieldVarHandle;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangInvokeFieldVarHandle, class_root); mirror::FieldVarHandle::SetClass(class_root); // Create java.lang.invoke.ArrayElementVarHandle.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/ArrayElementVarHandle;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangInvokeArrayElementVarHandle, class_root); mirror::ArrayElementVarHandle::SetClass(class_root); // Create java.lang.invoke.ByteArrayViewVarHandle.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/ByteArrayViewVarHandle;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangInvokeByteArrayViewVarHandle, class_root); mirror::ByteArrayViewVarHandle::SetClass(class_root); // Create java.lang.invoke.ByteBufferViewVarHandle.class root class_root = FindSystemClass(self, "Ljava/lang/invoke/ByteBufferViewVarHandle;"); CHECK(class_root != nullptr); SetClassRoot(kJavaLangInvokeByteBufferViewVarHandle, class_root); mirror::ByteBufferViewVarHandle::SetClass(class_root); class_root = FindSystemClass(self, "Ldalvik/system/EmulatedStackFrame;"); CHECK(class_root != nullptr); SetClassRoot(kDalvikSystemEmulatedStackFrame, class_root); mirror::EmulatedStackFrame::SetClass(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(kJavaLangClassLoader, class_root); // Set up java.lang.Throwable, java.lang.ClassNotFoundException, and // java.lang.StackTraceElement as a convenience. SetClassRoot(kJavaLangThrowable, FindSystemClass(self, "Ljava/lang/Throwable;")); mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable)); SetClassRoot(kJavaLangClassNotFoundException, FindSystemClass(self, "Ljava/lang/ClassNotFoundException;")); SetClassRoot(kJavaLangStackTraceElement, FindSystemClass(self, "Ljava/lang/StackTraceElement;")); SetClassRoot(kJavaLangStackTraceElementArrayClass, FindSystemClass(self, "[Ljava/lang/StackTraceElement;")); mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement)); // Create conflict tables that depend on the class linker. runtime->FixupConflictTables(); FinishInit(self); VLOG(startup) << "ClassLinker::InitFromCompiler exiting"; return true; } void ClassLinker::FinishInit(Thread* self) { VLOG(startup) << "ClassLinker::FinishInit entering"; // 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<2> hs(self); Handle
java_lang_ref_Reference = hs.NewHandle(GetClassRoot(kJavaLangRefReference)); 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 < kClassRootsMax; 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(!array_iftable_.IsNull()); // disable the slow paths in FindClass and CreatePrimitiveClass now // that Object, Class, and Object[] are setup init_done_ = true; VLOG(startup) << "ClassLinker::FinishInit exiting"; } void ClassLinker::RunRootClinits() { Thread* self = Thread::Current(); for (size_t i = 0; i < ClassLinker::kClassRootsMax; ++i) { ObjPtr
c = GetClassRoot(ClassRoot(i)); if (!c->IsArrayClass() && !c->IsPrimitive()) { StackHandleScope<1> hs(self); Handle
h_class(hs.NewHandle(GetClassRoot(ClassRoot(i)))); EnsureInitialized(self, h_class, true, true); self->AssertNoPendingException(); } } } // Set image methods' entry point to interpreter. class SetInterpreterEntrypointArtMethodVisitor : public ArtMethodVisitor { public: explicit SetInterpreterEntrypointArtMethodVisitor(PointerSize image_pointer_size) : image_pointer_size_(image_pointer_size) {} void Visit(ArtMethod* method) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { if (kIsDebugBuild && !method->IsRuntimeMethod()) { CHECK(method->GetDeclaringClass() != nullptr); } if (!method->IsNative() && !method->IsRuntimeMethod() && !method->IsResolutionMethod()) { method->SetEntryPointFromQuickCompiledCodePtrSize(GetQuickToInterpreterBridge(), image_pointer_size_); } } private: const PointerSize image_pointer_size_; DISALLOW_COPY_AND_ASSIGN(SetInterpreterEntrypointArtMethodVisitor); }; 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; } image_pointer_size_ = spaces[0]->GetImageHeader().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; } } std::vector
oat_files = runtime->GetOatFileManager().RegisterImageOatFiles(spaces); DCHECK(!oat_files.empty()); const OatHeader& default_oat_header = oat_files[0]->GetOatHeader(); CHECK_EQ(default_oat_header.GetImageFileLocationOatDataBegin(), 0U); const char* image_file_location = oat_files[0]->GetOatHeader(). GetStoreValueByKey(OatHeader::kImageLocationKey); CHECK(image_file_location == nullptr || *image_file_location == 0); 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
>( down_cast
*>( spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots))); mirror::Class::SetClassClass(class_roots_.Read()->Get(kJavaLangClass)); // Special case of setting up the String class early so that we can test arbitrary objects // as being Strings or not mirror::String::SetClass(GetClassRoot(kJavaLangString)); ObjPtr
java_lang_Object = GetClassRoot(kJavaLangObject); 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())); // reinit array_iftable_ from any array class instance, they should be == array_iftable_ = GcRoot
(GetClassRoot(kObjectArrayClass)->GetIfTable()); DCHECK_EQ(array_iftable_.Read(), GetClassRoot(kBooleanArrayClass)->GetIfTable()); // String class root was set above mirror::Field::SetClass(GetClassRoot(kJavaLangReflectField)); mirror::Field::SetArrayClass(GetClassRoot(kJavaLangReflectFieldArrayClass)); mirror::Constructor::SetClass(GetClassRoot(kJavaLangReflectConstructor)); mirror::Constructor::SetArrayClass(GetClassRoot(kJavaLangReflectConstructorArrayClass)); mirror::Method::SetClass(GetClassRoot(kJavaLangReflectMethod)); mirror::Method::SetArrayClass(GetClassRoot(kJavaLangReflectMethodArrayClass)); mirror::CallSite::SetClass(GetClassRoot(kJavaLangInvokeCallSite)); mirror::MethodHandleImpl::SetClass(GetClassRoot(kJavaLangInvokeMethodHandleImpl)); mirror::MethodHandlesLookup::SetClass(GetClassRoot(kJavaLangInvokeMethodHandlesLookup)); mirror::MethodType::SetClass(GetClassRoot(kJavaLangInvokeMethodType)); mirror::VarHandle::SetClass(GetClassRoot(kJavaLangInvokeVarHandle)); mirror::FieldVarHandle::SetClass(GetClassRoot(kJavaLangInvokeFieldVarHandle)); mirror::ArrayElementVarHandle::SetClass(GetClassRoot(kJavaLangInvokeArrayElementVarHandle)); mirror::ByteArrayViewVarHandle::SetClass(GetClassRoot(kJavaLangInvokeByteArrayViewVarHandle)); mirror::ByteBufferViewVarHandle::SetClass(GetClassRoot(kJavaLangInvokeByteBufferViewVarHandle)); mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference)); mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass)); mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass)); mirror::CharArray::SetArrayClass(GetClassRoot(kCharArrayClass)); mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass)); mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass)); mirror::IntArray::SetArrayClass(GetClassRoot(kIntArrayClass)); mirror::LongArray::SetArrayClass(GetClassRoot(kLongArrayClass)); mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass)); mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable)); mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement)); mirror::EmulatedStackFrame::SetClass(GetClassRoot(kDalvikSystemEmulatedStackFrame)); mirror::ClassExt::SetClass(GetClassRoot(kDalvikSystemClassExt)); for (gc::space::ImageSpace* image_space : spaces) { // Boot class loader, use a null handle. std::vector
> dex_files; if (!AddImageSpace(image_space, ScopedNullHandle
(), /*dex_elements*/nullptr, /*dex_location*/nullptr, /*out*/&dex_files, error_msg)) { return false; } // 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; } 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 FlattenPathClassLoader(ObjPtr
class_loader, std::list
>* out_dex_file_names, std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(out_dex_file_names != nullptr); DCHECK(error_msg != nullptr); ScopedObjectAccessUnchecked soa(Thread::Current()); StackHandleScope<1> hs(soa.Self()); Handle
handle(hs.NewHandle(class_loader)); while (!ClassLinker::IsBootClassLoader(soa, class_loader)) { 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; } // 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 = false; // Invalid element is not a critical error. return false; // Stop the visit. } if (name != nullptr) { out_dex_file_names->push_front(name.Ptr()); } return true; // Continue with the next Element. }; bool error = VisitClassLoaderDexElements(soa, handle, add_element_names, /* error */ false); if (error) { // An error occurred during DexPathList Element visiting. return false; } class_loader = class_loader->GetParent(); } 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_; }; class VerifyDeclaringClassVisitor : public ArtMethodVisitor { public: VerifyDeclaringClassVisitor() REQUIRES_SHARED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) : live_bitmap_(Runtime::Current()->GetHeap()->GetLiveBitmap()) {} virtual void Visit(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"; } } private: gc::accounting::HeapBitmap* const live_bitmap_; }; class FixupInternVisitor { public: ALWAYS_INLINE ObjPtr
TryInsertIntern(mirror::Object* obj) const REQUIRES_SHARED(Locks::mutator_lock_) { if (obj != nullptr && obj->IsString()) { const auto intern = Runtime::Current()->GetInternTable()->InternStrong(obj->AsString()); return intern; } return obj; } ALWAYS_INLINE void VisitRootIfNonNull( mirror::CompressedReference
* root) const REQUIRES_SHARED(Locks::mutator_lock_) { if (!root->IsNull()) { VisitRoot(root); } } ALWAYS_INLINE void VisitRoot(mirror::CompressedReference
* root) const REQUIRES_SHARED(Locks::mutator_lock_) { root->Assign(TryInsertIntern(root->AsMirrorPtr())); } // Visit Class Fields ALWAYS_INLINE 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. // Only string fields are fixed, don't do a verify. mirror::Object* ref = obj->GetFieldObject
( offset); obj->SetFieldObject
(offset, TryInsertIntern(ref)); } } void operator()(ObjPtr
klass ATTRIBUTE_UNUSED, ObjPtr
ref) const REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_) { this->operator()(ref, mirror::Reference::ReferentOffset(), false); } void operator()(mirror::Object* obj) const REQUIRES_SHARED(Locks::mutator_lock_) { if (obj->IsDexCache()) { obj->VisitReferences
(*this, *this); } else { // Don't visit native roots for non-dex-cache obj->VisitReferences
(*this, *this); } } }; // 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 AppImageClassLoadersAndDexCachesHelper { 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_); }; void AppImageClassLoadersAndDexCachesHelper::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_) { Thread* const self = Thread::Current(); gc::Heap* const heap = Runtime::Current()->GetHeap(); const ImageHeader& header = space->GetImageHeader(); { // 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 (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) { // Fixup all the literal strings happens at app images which are supposed to be interned. ScopedTrace timing("Fixup String Intern in image and dex_cache"); const auto& image_header = space->GetImageHeader(); const auto bitmap = space->GetMarkBitmap(); // bitmap of objects const uint8_t* target_base = space->GetMemMap()->Begin(); const ImageSection& objects_section = image_header.GetObjectsSection(); uintptr_t objects_begin = reinterpret_cast
(target_base + objects_section.Offset()); uintptr_t objects_end = reinterpret_cast
(target_base + objects_section.End()); FixupInternVisitor fixup_intern_visitor; bitmap->VisitMarkedRange(objects_begin, objects_end, fixup_intern_visitor); } if (kVerifyArtMethodDeclaringClasses) { ScopedTrace timing("Verify declaring classes"); ReaderMutexLock rmu(self, *Locks::heap_bitmap_lock_); VerifyDeclaringClassVisitor visitor; header.VisitPackedArtMethods(&visitor, space->Begin(), kRuntimePointerSize); } } // Update the class loader. Should only be used on classes in the image space. class UpdateClassLoaderVisitor { public: UpdateClassLoaderVisitor(gc::space::ImageSpace* space, ObjPtr
class_loader) : space_(space), class_loader_(class_loader) {} bool operator()(ObjPtr
klass) const REQUIRES_SHARED(Locks::mutator_lock_) { // 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. if (klass->GetClassLoader() != nullptr) { klass->SetClassLoader(class_loader_); } return true; } gc::space::ImageSpace* const space_; ObjPtr
const class_loader_; }; 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 OatFile::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); mirror::ObjectArray
* dex_caches = dex_caches_object->AsObjectArray
(); const OatFile* oat_file = space->GetOatFile(); 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()); 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 auto pointer_size = isc.pointer_size_; for (auto& m : klass->GetMethods(pointer_size)) { isc.SanityCheckArtMethod(&m, klass); } auto* 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); } } mirror::IfTable* 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_) { { class VerifyClassInTableArtMethodVisitor : public ArtMethodVisitor { public: explicit VerifyClassInTableArtMethodVisitor(ClassTable* table) : table_(table) {} virtual void Visit(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_, Locks::classlinker_classes_lock_) { ObjPtr
klass = method->GetDeclaringClass(); if (klass != nullptr && !Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) { CHECK_EQ(table_->LookupByDescriptor(klass), klass) << mirror::Class::PrettyClass(klass); } } private: ClassTable* const table_; }; VerifyClassInTableArtMethodVisitor visitor(class_table); header.VisitPackedArtMethods(&visitor, 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
())); static_assert(ImageHeader::kClassLoader + 1u == ImageHeader::kImageRootsMax, "Class loader should be the last image root."); MutableHandle
image_class_loader(hs.NewHandle( app_image ? header.GetImageRoot(ImageHeader::kClassLoader)->AsClassLoader() : nullptr)); DCHECK(class_roots != nullptr); if (class_roots->GetLength() != static_cast
(kClassRootsMax)) { *error_msg = StringPrintf("Expected %d class roots but got %d", class_roots->GetLength(), static_cast
(kClassRootsMax)); return false; } // Check against existing class roots to make sure they match the ones in the boot image. for (size_t i = 0; i < kClassRootsMax; i++) { if (class_roots->Get(i) != GetClassRoot(static_cast
(i))) { *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()); // TODO: Only store qualified paths. // If non qualified, qualify it. if (dex_file_location.find('/') == std::string::npos) { std::string dex_location_path = dex_location; const size_t pos = dex_location_path.find_last_of('/'); CHECK_NE(pos, std::string::npos); dex_location_path = dex_location_path.substr(0, pos + 1); // Keep trailing '/' dex_file_location = dex_location_path + 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()); // 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 laoder 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; } std::list
> image_dex_file_names; std::string temp_error_msg; if (!FlattenPathClassLoader(image_class_loader.Get(), &image_dex_file_names, &temp_error_msg)) { *error_msg = StringPrintf("Failed to flatten image class loader hierarchy '%s'", temp_error_msg.c_str()); return false; } std::list
> loader_dex_file_names; if (!FlattenPathClassLoader(class_loader.Get(), &loader_dex_file_names, &temp_error_msg)) { *error_msg = StringPrintf("Failed to flatten class loader hierarchy '%s'", temp_error_msg.c_str()); return false; } // Add the temporary dex path list elements at the end. auto elements = soa.Decode
>(dex_elements); 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); } } } // 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(); // Check that the dex file names match. bool equal = image_count == loader_dex_file_names.size(); if (equal) { auto it1 = image_dex_file_names.begin(); auto it2 = loader_dex_file_names.begin(); for (size_t i = 0; equal && i < image_count; ++i, ++it1, ++it2) { equal = equal && (*it1)->Equals(*it2); } } if (!equal) { VLOG(image) << "Image dex files " << image_dex_file_names.size(); for (ObjPtr
name : image_dex_file_names) { VLOG(image) << name->ToModifiedUtf8(); } VLOG(image) << "Loader dex files " << loader_dex_file_names.size(); for (ObjPtr
name : loader_dex_file_names) { VLOG(image) << name->ToModifiedUtf8(); } *error_msg = "Rejecting application image due to class loader mismatch"; // Ignore class loader mismatch for now since these would just use possibly incorrect // oat code anyways. The structural class check should be done in the parent. } } if (kSanityCheckObjects) { for (int32_t i = 0; i < dex_caches->GetLength(); i++) { auto* 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()) { SetInterpreterEntrypointArtMethodVisitor visitor(image_pointer_size_); header.VisitPackedArtMethods(&visitor, space->Begin(), image_pointer_size_); } if (!app_image) { // Make the string intern table and class table immutable for boot image. // PIC app oat files may mmap a read-only copy into their own .bss section, // so enforce that the data in the boot image tables remains unchanged. // // We cannot do that for app image even after the fixup as some interned // String references may actually end up pointing to moveable Strings. uint8_t* const_section_begin = space->Begin() + header.GetBootImageConstantTablesOffset(); CheckedCall(mprotect, "protect constant tables", const_section_begin, header.GetBootImageConstantTablesSize(), PROT_READ); } 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) { AppImageClassLoadersAndDexCachesHelper::Update(this, space, class_loader, dex_caches, &temp_set); // Update class loader and resolved strings. If added_class_table is false, the resolved // strings were forwarded UpdateAppImageClassLoadersAndDexCaches. UpdateClassLoaderVisitor visitor(space, class_loader.Get()); for (const ClassTable::TableSlot& root : temp_set) { visitor(root.Read()); } 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("Recalculate app image SubtypeCheck bitstrings"); 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("VerifyAppImage"); 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); array_iftable_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal)); // 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); } ObjPtr
const 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
* const arr_; int32_t index_; }; void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor) { // TODO: it may be possible to avoid secondary storage if we iterate over dex caches. The problem // is avoiding duplicates. if (!kMovingClasses) { ScopedAssertNoThreadSuspension nts(__FUNCTION__); GetClassesInToVector accumulator; VisitClasses(&accumulator); for (ObjPtr
klass : accumulator.classes_) { if (!visitor->operator()(klass)) { return; } } } else { Thread* const self = Thread::Current(); StackHandleScope<1> hs(self); auto classes = hs.NewHandle
>(nullptr); // We size the array assuming classes won't be added to the class table during the visit. // If this assumption fails we iterate again. while (true) { size_t class_table_size; { ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_); // Add 100 in case new classes get loaded when we are filling in the object array. class_table_size = NumZygoteClasses() + NumNonZygoteClasses() + 100; } ObjPtr
class_type = mirror::Class::GetJavaLangClass(); ObjPtr
array_of_class = FindArrayClass(self, &class_type); classes.Assign( mirror::ObjectArray
::Alloc(self, array_of_class, class_table_size)); CHECK(classes != nullptr); // OOME. GetClassInToObjectArray accumulator(classes.Get()); VisitClasses(&accumulator); if (accumulator.Succeeded()) { break; } } for (int32_t i = 0; i < classes->GetLength(); ++i) { // If the class table shrank during creation of the clases array we expect null elements. If // the class table grew then the loop repeats. If classes are created after the loop has // finished then we don't visit. ObjPtr
klass = classes->Get(i); if (klass != nullptr && !visitor->operator()(klass)) { return; } } } } ClassLinker::~ClassLinker() { mirror::Class::ResetClass(); mirror::Constructor::ResetClass(); mirror::Field::ResetClass(); mirror::Method::ResetClass(); mirror::Reference::ResetClass(); mirror::StackTraceElement::ResetClass(); mirror::String::ResetClass(); mirror::Throwable::ResetClass(); mirror::BooleanArray::ResetArrayClass(); mirror::ByteArray::ResetArrayClass(); mirror::CharArray::ResetArrayClass(); mirror::Constructor::ResetArrayClass(); mirror::DoubleArray::ResetArrayClass(); mirror::Field::ResetArrayClass(); mirror::FloatArray::ResetArrayClass(); mirror::Method::ResetArrayClass(); mirror::IntArray::ResetArrayClass(); mirror::LongArray::ResetArrayClass(); mirror::ShortArray::ResetArrayClass(); mirror::CallSite::ResetClass(); mirror::MethodType::ResetClass(); mirror::MethodHandleImpl::ResetClass(); mirror::MethodHandlesLookup::ResetClass(); mirror::VarHandle::ResetClass(); mirror::FieldVarHandle::ResetClass(); mirror::ArrayElementVarHandle::ResetClass(); mirror::ByteArrayViewVarHandle::ResetClass(); mirror::ByteBufferViewVarHandle::ResetClass(); mirror::EmulatedStackFrame::ResetClass(); Thread* const self = Thread::Current(); for (const ClassLoaderData& data : class_loaders_) { // CHA unloading analysis is not needed. No negative consequences are expected because // all the classloaders are deleted at the same time. DeleteClassLoader(self, data, false /*cleanup_cha*/); } class_loaders_.clear(); } void ClassLinker::DeleteClassLoader(Thread* self, const ClassLoaderData& data, bool cleanup_cha) { Runtime* const runtime = Runtime::Current(); JavaVMExt* const vm = runtime->GetJavaVM(); vm->DeleteWeakGlobalRef(self, data.weak_root); // Notify the JIT that we need to remove the methods and/or profiling info. if (runtime->GetJit() != nullptr) { jit::JitCodeCache* code_cache = runtime->GetJit()->GetCodeCache(); if (code_cache != nullptr) { // For the JIT case, RemoveMethodsIn removes the CHA dependencies. code_cache->RemoveMethodsIn(self, *data.allocator); } } else if (cha_ != nullptr) { // If we don't have a JIT, we need to manually remove the CHA dependencies manually. cha_->RemoveDependenciesForLinearAlloc(data.allocator); } // Cleanup references to single implementation ArtMethods that will be deleted. if (cleanup_cha) { CHAOnDeleteUpdateClassVisitor visitor(data.allocator); data.class_table->Visit
(visitor); } delete data.allocator; delete data.class_table; } mirror::PointerArray* ClassLinker::AllocPointerArray(Thread* self, size_t length) { return down_cast
( image_pointer_size_ == PointerSize::k64 ? static_cast
(mirror::LongArray::Alloc(self, length)) : static_cast
(mirror::IntArray::Alloc(self, length))); } mirror::DexCache* ClassLinker::AllocDexCache(ObjPtr
* out_location, Thread* self, const DexFile& dex_file) { StackHandleScope<1> hs(self); DCHECK(out_location != nullptr); auto dex_cache(hs.NewHandle(ObjPtr
::DownCast( GetClassRoot(kJavaLangDexCache)->AllocObject(self)))); if (dex_cache == nullptr) { self->AssertPendingOOMException(); return nullptr; } ObjPtr
location = intern_table_->InternStrong(dex_file.GetLocation().c_str()); if (location == nullptr) { self->AssertPendingOOMException(); return nullptr; } *out_location = location; return dex_cache.Get(); } mirror::DexCache* ClassLinker::AllocAndInitializeDexCache(Thread* self, const DexFile& dex_file, LinearAlloc* linear_alloc) { ObjPtr
location = nullptr; ObjPtr
dex_cache = AllocDexCache(&location, self, dex_file); if (dex_cache != nullptr) { WriterMutexLock mu(self, *Locks::dex_lock_); DCHECK(location != nullptr); mirror::DexCache::InitializeDexCache(self, dex_cache, location, &dex_file, linear_alloc, image_pointer_size_); } return dex_cache.Ptr(); } mirror::Class* ClassLinker::AllocClass(Thread* self, ObjPtr
java_lang_Class, uint32_t class_size) { DCHECK_GE(class_size, sizeof(mirror::Class)); gc::Heap* heap = Runtime::Current()->GetHeap(); mirror::Class::InitializeClassVisitor visitor(class_size); ObjPtr
k = kMovingClasses ? heap->AllocObject
(self, java_lang_Class, class_size, visitor) : heap->AllocNonMovableObject
(self, java_lang_Class, class_size, visitor); if (UNLIKELY(k == nullptr)) { self->AssertPendingOOMException(); return nullptr; } return k->AsClass(); } mirror::Class* ClassLinker::AllocClass(Thread* self, uint32_t class_size) { return AllocClass(self, GetClassRoot(kJavaLangClass), class_size); } mirror::ObjectArray
* ClassLinker::AllocStackTraceElementArray( Thread* self, size_t length) { return mirror::ObjectArray
::Alloc( self, GetClassRoot(kJavaLangStackTraceElementArrayClass), length); } mirror::Class* ClassLinker::EnsureResolved(Thread* self, const char* descriptor, ObjPtr
klass) { DCHECK(klass != nullptr); if (kIsDebugBuild) { StackHandleScope<1> hs(self); HandleWrapperObjPtr
h = hs.NewHandleWrapper(&klass); Thread::PoisonObjectPointersIfDebug(); } // For temporary classes we must wait for them to be retired. if (init_done_ && klass->IsTemp()) { CHECK(!klass->IsResolved()); if (klass->IsErroneousUnresolved()) { ThrowEarlierClassFailure(klass); return nullptr; } StackHandleScope<1> hs(self); Handle
h_class(hs.NewHandle(klass)); ObjectLock
lock(self, h_class); // Loop and wait for the resolving thread to retire this class. while (!h_class->IsRetired() && !h_class->IsErroneousUnresolved()) { lock.WaitIgnoringInterrupts(); } if (h_class->IsErroneousUnresolved()) { ThrowEarlierClassFailure(h_class.Get()); return nullptr; } CHECK(h_class->IsRetired()); // Get the updated class from class table. klass = LookupClass(self, descriptor, h_class.Get()->GetClassLoader()); } // Wait for the class if it has not already been linked. size_t index = 0; // Maximum number of yield iterations until we start sleeping. static const size_t kNumYieldIterations = 1000; // How long each sleep is in us. static const size_t kSleepDurationUS = 1000; // 1 ms. while (!klass->IsResolved() && !klass->IsErroneousUnresolved()) { StackHandleScope<1> hs(self); HandleWrapperObjPtr
h_class(hs.NewHandleWrapper(&klass)); { ObjectTryLock
lock(self, h_class); // Can not use a monitor wait here since it may block when returning and deadlock if another // thread has locked klass. if (lock.Acquired()) { // Check for circular dependencies between classes, the lock is required for SetStatus. if (!h_class->IsResolved() && h_class->GetClinitThreadId() == self->GetTid()) { ThrowClassCircularityError(h_class.Get()); mirror::Class::SetStatus(h_class, ClassStatus::kErrorUnresolved, self); return nullptr; } } } { // Handle wrapper deals with klass moving. ScopedThreadSuspension sts(self, kSuspended); if (index < kNumYieldIterations) { sched_yield(); } else { usleep(kSleepDurationUS); } } ++index; } if (klass->IsErroneousUnresolved()) { ThrowEarlierClassFailure(klass); return nullptr; } // Return the loaded class. No exceptions should be pending. CHECK(klass->IsResolved()) << klass->PrettyClass(); self->AssertNoPendingException(); return klass.Ptr(); } typedef std::pair
ClassPathEntry; // Search a collection of DexFiles for a descriptor ClassPathEntry FindInClassPath(const char* descriptor, size_t hash, const std::vector
& class_path) { for (const DexFile* dex_file : class_path) { const DexFile::ClassDef* dex_class_def = OatDexFile::FindClassDef(*dex_file, descriptor, hash); if (dex_class_def != nullptr) { return ClassPathEntry(dex_file, dex_class_def); } } return ClassPathEntry(nullptr, nullptr); } bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnable& soa, Thread* self, const char* descriptor, size_t hash, Handle
class_loader, ObjPtr
* result) { // Termination case: boot class loader. if (IsBootClassLoader(soa, class_loader.Get())) { *result = FindClassInBootClassLoaderClassPath(self, descriptor, hash); return true; } if (IsPathOrDexClassLoader(soa, class_loader)) { // For regular path or dex class loader the search order is: // - parent // - class loader dex files // Handles as RegisterDexFile may allocate dex caches (and cause thread suspension). StackHandleScope<1> hs(self); Handle
h_parent(hs.NewHandle(class_loader->GetParent())); if (!FindClassInBaseDexClassLoader(soa, self, descriptor, hash, h_parent, result)) { return false; // One of the parents is not supported. } if (*result != nullptr) { return true; // Found the class up the chain. } // Search the current class loader classpath. *result = FindClassInBaseDexClassLoaderClassPath(soa, descriptor, hash, class_loader); return true; } if (IsDelegateLastClassLoader(soa, class_loader)) { // For delegate last, the search order is: // - boot class path // - class loader dex files // - parent *result = FindClassInBootClassLoaderClassPath(self, descriptor, hash); if (*result != nullptr) { return true; // The class is part of the boot class path. } *result = FindClassInBaseDexClassLoaderClassPath(soa, descriptor, hash, class_loader); if (*result != nullptr) { return true; // Found the class in the current class loader } // Handles as RegisterDexFile may allocate dex caches (and cause thread suspension). StackHandleScope<1> hs(self); Handle
h_parent(hs.NewHandle(class_loader->GetParent())); return FindClassInBaseDexClassLoader(soa, self, descriptor, hash, h_parent, result); } // Unsupported class loader. *result = nullptr; return false; } // Finds the class in the boot class loader. // If the class is found the method returns the resolved class. Otherwise it returns null. ObjPtr
ClassLinker::FindClassInBootClassLoaderClassPath(Thread* self, const char* descriptor, size_t hash) { ObjPtr
result = nullptr; ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_); if (pair.second != nullptr) { ObjPtr
klass = LookupClass(self, descriptor, hash, nullptr); if (klass != nullptr) { result = EnsureResolved(self, descriptor, klass); } else { result = DefineClass(self, descriptor, hash, ScopedNullHandle
(), *pair.first, *pair.second); } if (result == nullptr) { CHECK(self->IsExceptionPending()) << descriptor; self->ClearException(); } } return result; } ObjPtr
ClassLinker::FindClassInBaseDexClassLoaderClassPath( ScopedObjectAccessAlreadyRunnable& soa, const char* descriptor, size_t hash, Handle
class_loader) { DCHECK(IsPathOrDexClassLoader(soa, class_loader) || IsDelegateLastClassLoader(soa, class_loader)) << "Unexpected class loader for descriptor " << descriptor; ObjPtr
ret; auto define_class = [&](const DexFile* cp_dex_file) REQUIRES_SHARED(Locks::mutator_lock_) { const DexFile::ClassDef* dex_class_def = OatDexFile::FindClassDef(*cp_dex_file, descriptor, hash); if (dex_class_def != nullptr) { ObjPtr
klass = DefineClass(soa.Self(), descriptor, hash, class_loader, *cp_dex_file, *dex_class_def); if (klass == nullptr) { CHECK(soa.Self()->IsExceptionPending()) << descriptor; soa.Self()->ClearException(); // TODO: Is it really right to break here, and not check the other dex files? } ret = klass; return false; // Found a Class (or error == nullptr), stop visit. } return true; // Continue with the next DexFile. }; VisitClassLoaderDexFiles(soa, class_loader, define_class); return ret; } mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor, Handle
class_loader) { DCHECK_NE(*descriptor, '\0') << "descriptor is empty string"; DCHECK(self != nullptr); self->AssertNoPendingException(); self->PoisonObjectPointers(); // For DefineClass, CreateArrayClass, etc... if (descriptor[1] == '\0') { // only the descriptors of primitive types should be 1 character long, also avoid class lookup // for primitive classes that aren't backed by dex files. return FindPrimitiveClass(descriptor[0]); } const size_t hash = ComputeModifiedUtf8Hash(descriptor); // Find the class in the loaded classes table. ObjPtr
klass = LookupClass(self, descriptor, hash, class_loader.Get()); if (klass != nullptr) { return EnsureResolved(self, descriptor, klass); } // Class is not yet loaded. if (descriptor[0] != '[' && class_loader == nullptr) { // Non-array class and the boot class loader, search the boot class path. ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_); if (pair.second != nullptr) { return DefineClass(self, descriptor, hash, ScopedNullHandle
(), *pair.first, *pair.second); } else { // The boot class loader is searched ahead of the application class loader, failures are // expected and will be wrapped in a ClassNotFoundException. Use the pre-allocated error to // trigger the chaining with a proper stack trace. ObjPtr
pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError(); self->SetException(pre_allocated); return nullptr; } } ObjPtr
result_ptr; bool descriptor_equals; if (descriptor[0] == '[') { result_ptr = CreateArrayClass(self, descriptor, hash, class_loader); DCHECK_EQ(result_ptr == nullptr, self->IsExceptionPending()); DCHECK(result_ptr == nullptr || result_ptr->DescriptorEquals(descriptor)); descriptor_equals = true; } else { ScopedObjectAccessUnchecked soa(self); bool known_hierarchy = FindClassInBaseDexClassLoader(soa, self, descriptor, hash, class_loader, &result_ptr); if (result_ptr != nullptr) { // The chain was understood and we found the class. We still need to add the class to // the class table to protect from racy programs that can try and redefine the path list // which would change the Class> returned for subsequent evaluation of const-class. DCHECK(known_hierarchy); DCHECK(result_ptr->DescriptorEquals(descriptor)); descriptor_equals = true; } else { // Either the chain wasn't understood or the class wasn't found. // // If the chain was understood but we did not find the class, let the Java-side // rediscover all this and throw the exception with the right stack trace. Note that // the Java-side could still succeed for racy programs if another thread is actively // modifying the class loader's path list. if (!self->CanCallIntoJava()) { // Oops, we can't call into java so we can't run actual class-loader code. // This is true for e.g. for the compiler (jit or aot). ObjPtr
pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError(); self->SetException(pre_allocated); return nullptr; } // Inlined DescriptorToDot(descriptor) with extra validation. // // Throw NoClassDefFoundError early rather than potentially load a class only to fail // the DescriptorEquals() check below and give a confusing error message. For example, // when native code erroneously calls JNI GetFieldId() with signature "java/lang/String" // instead of "Ljava/lang/String;", the message below using the "dot" names would be // "class loader [...] returned class java.lang.String instead of java.lang.String". size_t descriptor_length = strlen(descriptor); if (UNLIKELY(descriptor[0] != 'L') || UNLIKELY(descriptor[descriptor_length - 1] != ';') || UNLIKELY(memchr(descriptor + 1, '.', descriptor_length - 2) != nullptr)) { ThrowNoClassDefFoundError("Invalid descriptor: %s.", descriptor); return nullptr; } std::string class_name_string(descriptor + 1, descriptor_length - 2); std::replace(class_name_string.begin(), class_name_string.end(), '/', '.'); ScopedLocalRef
class_loader_object( soa.Env(), soa.AddLocalReference
(class_loader.Get())); ScopedLocalRef
result(soa.Env(), nullptr); { ScopedThreadStateChange tsc(self, kNative); ScopedLocalRef
class_name_object( soa.Env(), soa.Env()->NewStringUTF(class_name_string.c_str())); if (class_name_object.get() == nullptr) { DCHECK(self->IsExceptionPending()); // OOME. return nullptr; } CHECK(class_loader_object.get() != nullptr); result.reset(soa.Env()->CallObjectMethod(class_loader_object.get(), WellKnownClasses::java_lang_ClassLoader_loadClass, class_name_object.get())); } if (result.get() == nullptr && !self->IsExceptionPending()) { // broken loader - throw NPE to be compatible with Dalvik ThrowNullPointerException(StringPrintf("ClassLoader.loadClass returned null for %s", class_name_string.c_str()).c_str()); return nullptr; } result_ptr = soa.Decode
(result.get()); // Check the name of the returned class. descriptor_equals = (result_ptr != nullptr) && result_ptr->DescriptorEquals(descriptor); } } if (self->IsExceptionPending()) { // If the ClassLoader threw or array class allocation failed, pass that exception up. // However, to comply with the RI behavior, first check if another thread succeeded. result_ptr = LookupClass(self, descriptor, hash, class_loader.Get()); if (result_ptr != nullptr && !result_ptr->IsErroneous()) { self->ClearException(); return EnsureResolved(self, descriptor, result_ptr); } return nullptr; } // Try to insert the class to the class table, checking for mismatch. ObjPtr
old; { WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); ClassTable* const class_table = InsertClassTableForClassLoader(class_loader.Get()); old = class_table->Lookup(descriptor, hash); if (old == nullptr) { old = result_ptr; // For the comparison below, after releasing the lock. if (descriptor_equals) { class_table->InsertWithHash(result_ptr.Ptr(), hash); Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader.Get()); } // else throw below, after releasing the lock. } } if (UNLIKELY(old != result_ptr)) { // Return `old` (even if `!descriptor_equals`) to mimic the RI behavior for parallel // capable class loaders. (All class loaders are considered parallel capable on Android.) mirror::Class* loader_class = class_loader->GetClass(); const char* loader_class_name = loader_class->GetDexFile().StringByTypeIdx(loader_class->GetDexTypeIndex()); LOG(WARNING) << "Initiating class loader of type " << DescriptorToDot(loader_class_name) << " is not well-behaved; it returned a different Class for racing loadClass(\"" << DescriptorToDot(descriptor) << "\")."; return EnsureResolved(self, descriptor, old); } if (UNLIKELY(!descriptor_equals)) { std::string result_storage; const char* result_name = result_ptr->GetDescriptor(&result_storage); std::string loader_storage; const char* loader_class_name = class_loader->GetClass()->GetDescriptor(&loader_storage); ThrowNoClassDefFoundError( "Initiating class loader of type %s returned class %s instead of %s.", DescriptorToDot(loader_class_name).c_str(), DescriptorToDot(result_name).c_str(), DescriptorToDot(descriptor).c_str()); return nullptr; } // success, return mirror::Class* return result_ptr.Ptr(); } mirror::Class* ClassLinker::DefineClass(Thread* self, const char* descriptor, size_t hash, Handle
class_loader, const DexFile& dex_file, const DexFile::ClassDef& dex_class_def) { StackHandleScope<3> hs(self); auto klass = hs.NewHandle
(nullptr); // Load the class from the dex file. if (UNLIKELY(!init_done_)) { // finish up init of hand crafted class_roots_ if (strcmp(descriptor, "Ljava/lang/Object;") == 0) { klass.Assign(GetClassRoot(kJavaLangObject)); } else if (strcmp(descriptor, "Ljava/lang/Class;") == 0) { klass.Assign(GetClassRoot(kJavaLangClass)); } else if (strcmp(descriptor, "Ljava/lang/String;") == 0) { klass.Assign(GetClassRoot(kJavaLangString)); } else if (strcmp(descriptor, "Ljava/lang/ref/Reference;") == 0) { klass.Assign(GetClassRoot(kJavaLangRefReference)); } else if (strcmp(descriptor, "Ljava/lang/DexCache;") == 0) { klass.Assign(GetClassRoot(kJavaLangDexCache)); } else if (strcmp(descriptor, "Ldalvik/system/ClassExt;") == 0) { klass.Assign(GetClassRoot(kDalvikSystemClassExt)); } } if (klass == nullptr) { // Allocate a class with the status of not ready. // Interface object should get the right size here. Regular class will // figure out the right size later and be replaced with one of the right // size when the class becomes resolved. klass.Assign(AllocClass(self, SizeOfClassWithoutEmbeddedTables(dex_file, dex_class_def))); } if (UNLIKELY(klass == nullptr)) { self->AssertPendingOOMException(); return nullptr; } // Get the real dex file. This will return the input if there aren't any callbacks or they do // nothing. DexFile const* new_dex_file = nullptr; DexFile::ClassDef const* new_class_def = nullptr; // TODO We should ideally figure out some way to move this after we get a lock on the klass so it // will only be called once. Runtime::Current()->GetRuntimeCallbacks()->ClassPreDefine(descriptor, klass, class_loader, dex_file, dex_class_def, &new_dex_file, &new_class_def); // Check to see if an exception happened during runtime callbacks. Return if so. if (self->IsExceptionPending()) { return nullptr; } ObjPtr
dex_cache = RegisterDexFile(*new_dex_file, class_loader.Get()); if (dex_cache == nullptr) { self->AssertPendingException(); return nullptr; } klass->SetDexCache(dex_cache); SetupClass(*new_dex_file, *new_class_def, klass, class_loader.Get()); // Mark the string class by setting its access flag. if (UNLIKELY(!init_done_)) { if (strcmp(descriptor, "Ljava/lang/String;") == 0) { klass->SetStringClass(); } } ObjectLock
lock(self, klass); klass->SetClinitThreadId(self->GetTid()); // Make sure we have a valid empty iftable even if there are errors. klass->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable()); // Add the newly loaded class to the loaded classes table. ObjPtr
existing = InsertClass(descriptor, klass.Get(), hash); if (existing != nullptr) { // We failed to insert because we raced with another thread. Calling EnsureResolved may cause // this thread to block. return EnsureResolved(self, descriptor, existing); } // Load the fields and other things after we are inserted in the table. This is so that we don't // end up allocating unfree-able linear alloc resources and then lose the race condition. The // other reason is that the field roots are only visited from the class table. So we need to be // inserted before we allocate / fill in these fields. LoadClass(self, *new_dex_file, *new_class_def, klass); if (self->IsExceptionPending()) { VLOG(class_linker) << self->GetException()->Dump(); // An exception occured during load, set status to erroneous while holding klass' lock in case // notification is necessary. if (!klass->IsErroneous()) { mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self); } return nullptr; } // Finish loading (if necessary) by finding parents CHECK(!klass->IsLoaded()); if (!LoadSuperAndInterfaces(klass, *new_dex_file)) { // Loading failed. if (!klass->IsErroneous()) { mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self); } return nullptr; } CHECK(klass->IsLoaded()); // At this point the class is loaded. Publish a ClassLoad event. // Note: this may be a temporary class. It is a listener's responsibility to handle this. Runtime::Current()->GetRuntimeCallbacks()->ClassLoad(klass); // Link the class (if necessary) CHECK(!klass->IsResolved()); // TODO: Use fast jobjects? auto interfaces = hs.NewHandle
>(nullptr); MutableHandle
h_new_class = hs.NewHandle