HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Nougat 7.0
|
7.0.0_r31
下载
查看原文件
收藏
根目录
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 "art_field-inl.h" #include "art_method-inl.h" #include "base/arena_allocator.h" #include "base/casts.h" #include "base/logging.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/value_object.h" #include "class_linker-inl.h" #include "class_table-inl.h" #include "compiler_callbacks.h" #include "debugger.h" #include "dex_file-inl.h" #include "entrypoints/entrypoint_utils.h" #include "entrypoints/runtime_asm_entrypoints.h" #include "experimental_flags.h" #include "gc_root-inl.h" #include "gc/accounting/card_table-inl.h" #include "gc/accounting/heap_bitmap-inl.h" #include "gc/heap.h" #include "gc/scoped_gc_critical_section.h" #include "gc/space/image_space.h" #include "handle_scope-inl.h" #include "image-inl.h" #include "intern_table.h" #include "interpreter/interpreter.h" #include "jit/jit.h" #include "jit/jit_code_cache.h" #include "jit/offline_profiling_info.h" #include "leb128.h" #include "linear_alloc.h" #include "mirror/class.h" #include "mirror/class-inl.h" #include "mirror/class_loader.h" #include "mirror/dex_cache-inl.h" #include "mirror/field.h" #include "mirror/iftable-inl.h" #include "mirror/method.h" #include "mirror/object-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 "native/dalvik_system_DexFile.h" #include "oat.h" #include "oat_file.h" #include "oat_file-inl.h" #include "oat_file_assistant.h" #include "oat_file_manager.h" #include "object_lock.h" #include "os.h" #include "runtime.h" #include "ScopedLocalRef.h" #include "scoped_thread_state_change.h" #include "thread-inl.h" #include "trace.h" #include "utils.h" #include "utils/dex_cache_arrays_layout-inl.h" #include "verifier/method_verifier.h" #include "well_known_classes.h" namespace art { static constexpr bool kSanityCheckObjects = kIsDebugBuild; static constexpr bool kVerifyArtMethodDeclaringClasses = kIsDebugBuild; static void ThrowNoClassDefFoundError(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2))) SHARED_REQUIRES(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) SHARED_REQUIRES(Locks::mutator_lock_) { ArtMethod* method = self->GetCurrentMethod(nullptr); StackHandleScope<1> hs(self); Handle
class_loader(hs.NewHandle(method != nullptr ? method->GetDeclaringClass()->GetClassLoader() : nullptr)); mirror::Class* 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->FindDeclaredDirectMethod( "
", "(Ljava/lang/String;)V", class_linker->GetImagePointerSize()); return exception_init_method != nullptr; } // Helper for ThrowEarlierClassFailure. Throws the stored error. static void HandleEarlierVerifyError(Thread* self, ClassLinker* class_linker, mirror::Class* c) SHARED_REQUIRES(Locks::mutator_lock_) { mirror::Object* obj = c->GetVerifyError(); 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, PrettyDescriptor(c).c_str()); } else { self->ThrowNewException(descriptor, nullptr); } } else { // Previous error has been stored as an instance. Just rethrow. mirror::Class* throwable_class = self->DecodeJObject(WellKnownClasses::java_lang_Throwable)->AsClass(); mirror::Class* error_class = obj->GetClass(); CHECK(throwable_class->IsAssignableFrom(error_class)); self->SetException(obj->AsThrowable()); } self->AssertPendingException(); } void ClassLinker::ThrowEarlierClassFailure(mirror::Class* 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 (c->GetVerifyError() != nullptr) { mirror::Object* verify_error = c->GetVerifyError(); if (verify_error->IsClass()) { extra = PrettyDescriptor(verify_error->AsClass()); } else { extra = verify_error->AsThrowable()->Dump(); } } LOG(INFO) << "Rejecting re-init on previously-failed class " << PrettyClass(c) << ": " << extra; } CHECK(c->IsErroneous()) << PrettyClass(c) << " " << c->GetStatus(); Thread* self = Thread::Current(); if (runtime->IsAotCompiler()) { // At compile time, accurate errors and NCDFE are disabled to speed compilation. mirror::Throwable* pre_allocated = runtime->GetPreAllocatedNoClassDefFoundError(); self->SetException(pre_allocated); } else { if (c->GetVerifyError() != nullptr) { // Rethrow stored error. HandleEarlierVerifyError(self, this, c); } if (c->GetVerifyError() == 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;", PrettyDescriptor(c).c_str()); } } } static void VlogClassInitializationFailure(Handle
klass) SHARED_REQUIRES(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) SHARED_REQUIRES(Locks::mutator_lock_) { Thread* self = Thread::Current(); JNIEnv* env = self->GetJniEnv(); ScopedLocalRef
cause(env, env->ExceptionOccurred()); CHECK(cause.get() != nullptr); 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 { explicit 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) SHARED_REQUIRES(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) << PrettyField(field); // 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) // dex_lock_ is recursive as it may be used in stack dumping. : dex_lock_("ClassLinker dex lock", kDefaultMutexLevel), dex_cache_boot_image_class_lookup_required_(false), failed_dex_cache_class_lookups_(0), class_roots_(nullptr), array_iftable_(nullptr), find_array_class_cache_next_victim_(0), init_done_(false), log_new_class_table_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_(sizeof(void*)) { 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) { mirror::Class* 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()); if (!ValidPointerSize(image_pointer_size_)) { *error_msg = StringPrintf("Invalid image pointer size: %zu", image_pointer_size_); return false; } // 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.Get() != nullptr); mirror::Class::SetClassClass(java_lang_Class.Get()); java_lang_Class->SetClass(java_lang_Class.Get()); if (kUseBakerOrBrooksReadBarrier) { java_lang_Class->AssertReadBarrierPointer(); } java_lang_Class->SetClassSize(class_class_size); java_lang_Class->SetPrimitiveType(Primitive::kPrimNot); heap->DecrementDisableMovingGC(self); // AllocClass(mirror::Class*) 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.Get() != nullptr); // backfill Object as the super class of Class. java_lang_Class->SetSuperClass(java_lang_Object.Get()); mirror::Class::SetStatus(java_lang_Object, mirror::Class::kStatusLoaded, 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())); // 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, mirror::Class::kStatusResolved, 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, mirror::Class::kStatusResolved, 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()); // 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, mirror::Class::kStatusResolved, 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 and DexCache need to be rerun through FindSystemClass to finish init mirror::Class::SetStatus(java_lang_Object, mirror::Class::kStatusNotReady, self); CheckSystemClass(self, java_lang_Object, "Ljava/lang/Object;"); CHECK_EQ(java_lang_Object->GetObjectSize(), mirror::Object::InstanceSize()); mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusNotReady, self); CheckSystemClass(self, java_lang_String, "Ljava/lang/String;"); mirror::Class::SetStatus(java_lang_DexCache, mirror::Class::kStatusNotReady, self); CheckSystemClass(self, java_lang_DexCache, "Ljava/lang/DexCache;"); CHECK_EQ(java_lang_DexCache->GetObjectSize(), mirror::DexCache::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.Get() != nullptr); auto java_io_Serializable = hs.NewHandle(FindSystemClass(self, "Ljava/io/Serializable;")); CHECK(java_io_Serializable.Get() != 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, 0)); CHECK_EQ(java_io_Serializable.Get(), mirror::Class::GetDirectInterface(self, class_array_class, 1)); CHECK_EQ(java_lang_Cloneable.Get(), mirror::Class::GetDirectInterface(self, object_array_class, 0)); CHECK_EQ(java_io_Serializable.Get(), mirror::Class::GetDirectInterface(self, object_array_class, 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); // 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, mirror::Class::kStatusNotReady, 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)); // Ensure void type is resolved in the core's dex cache so java.lang.Void is correctly // initialized. { const DexFile& dex_file = java_lang_Object->GetDexFile(); const DexFile::TypeId* void_type_id = dex_file.FindTypeId("V"); CHECK(void_type_id != nullptr); uint16_t void_type_idx = dex_file.GetIndexForTypeId(*void_type_id); // Now we resolve void type so the dex cache contains it. We use java.lang.Object class // as referrer so the used dex cache is core's one. mirror::Class* resolved_type = ResolveType(dex_file, void_type_idx, java_lang_Object.Get()); CHECK_EQ(resolved_type, GetClassRoot(kPrimitiveVoid)); self->AssertNoPendingException(); } // 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 mirror::Class* java_lang_ref_Reference = GetClassRoot(kJavaLangRefReference); mirror::Class* java_lang_ref_FinalizerReference = 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); mirror::Class* 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) { mirror::Class* 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(); } } } static void SanityCheckArtMethod(ArtMethod* m, mirror::Class* expected_class, const std::vector
& spaces) SHARED_REQUIRES(Locks::mutator_lock_) { if (m->IsRuntimeMethod()) { mirror::Class* declaring_class = m->GetDeclaringClassUnchecked(); CHECK(declaring_class == nullptr) << declaring_class << " " << PrettyMethod(m); } else if (m->IsCopied()) { CHECK(m->GetDeclaringClass() != nullptr) << PrettyMethod(m); } else if (expected_class != nullptr) { CHECK_EQ(m->GetDeclaringClassUnchecked(), expected_class) << PrettyMethod(m); } if (!spaces.empty()) { bool contains = false; for (gc::space::ImageSpace* space : spaces) { auto& header = space->GetImageHeader(); size_t offset = reinterpret_cast
(m) - space->Begin(); const ImageSection& methods = header.GetMethodsSection(); contains = contains || methods.Contains(offset); const ImageSection& runtime_methods = header.GetRuntimeMethodsSection(); contains = contains || runtime_methods.Contains(offset); } CHECK(contains) << m << " not found"; } } static void SanityCheckArtMethodPointerArray(mirror::PointerArray* arr, mirror::Class* expected_class, size_t pointer_size, const std::vector
& spaces) SHARED_REQUIRES(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, spaces); } } } static void SanityCheckArtMethodPointerArray(ArtMethod** arr, size_t size, size_t pointer_size, const std::vector
& spaces) SHARED_REQUIRES(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().GetImageSection( ImageHeader::kSectionDexCacheArrays).Contains(offset)) { contains = true; break; } } CHECK(contains); } for (size_t j = 0; j < size; ++j) { ArtMethod* method = mirror::DexCache::GetElementPtrSize(arr, j, pointer_size); // expected_class == null means we are a dex cache. if (method != nullptr) { SanityCheckArtMethod(method, nullptr, spaces); } } } static void SanityCheckObjectsCallback(mirror::Object* obj, void* arg ATTRIBUTE_UNUSED) SHARED_REQUIRES(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); } auto* runtime = Runtime::Current(); auto image_spaces = runtime->GetHeap()->GetBootImageSpaces(); auto pointer_size = runtime->GetClassLinker()->GetImagePointerSize(); for (auto& m : klass->GetMethods(pointer_size)) { SanityCheckArtMethod(&m, klass, image_spaces); } auto* vtable = klass->GetVTable(); if (vtable != nullptr) { SanityCheckArtMethodPointerArray(vtable, nullptr, pointer_size, image_spaces); } if (klass->ShouldHaveEmbeddedImtAndVTable()) { for (size_t i = 0; i < mirror::Class::kImtSize; ++i) { SanityCheckArtMethod( klass->GetEmbeddedImTableEntry(i, pointer_size), nullptr, image_spaces); } for (int32_t i = 0; i < klass->GetEmbeddedVTableLength(); ++i) { SanityCheckArtMethod(klass->GetEmbeddedVTableEntry(i, pointer_size), nullptr, image_spaces); } } auto* iftable = klass->GetIfTable(); if (iftable != nullptr) { for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) { if (iftable->GetMethodArrayCount(i) > 0) { SanityCheckArtMethodPointerArray( iftable->GetMethodArray(i), nullptr, pointer_size, image_spaces); } } } } } // Set image methods' entry point to interpreter. class SetInterpreterEntrypointArtMethodVisitor : public ArtMethodVisitor { public: explicit SetInterpreterEntrypointArtMethodVisitor(size_t image_pointer_size) : image_pointer_size_(image_pointer_size) {} void Visit(ArtMethod* method) OVERRIDE SHARED_REQUIRES(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 size_t 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; size_t pointer_size; ArtMethod* m; bool error; }; static void CheckTrampolines(mirror::Object* obj, void* arg) NO_THREAD_SAFETY_ANALYSIS { if (obj->IsClass()) { mirror::Class* klass = obj->AsClass(); TrampolineCheckData* d = reinterpret_cast
(arg); for (ArtMethod& m : klass->GetMethods(d->pointer_size)) { const void* entrypoint = m.GetEntryPointFromQuickCompiledCodePtrSize(d->pointer_size); if (entrypoint == d->quick_resolution_trampoline || entrypoint == d->quick_imt_conflict_trampoline || entrypoint == d->quick_generic_jni_trampoline || entrypoint == d->quick_to_interpreter_bridge_trampoline) { d->m = &m; d->error = true; return; } } } } 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()); image_pointer_size_ = spaces[0]->GetImageHeader().GetPointerSize(); if (!ValidPointerSize(image_pointer_size_)) { *error_msg = StringPrintf("Invalid image pointer size: %zu", image_pointer_size_); return false; } 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_ != sizeof(void*)) { *error_msg = StringPrintf("Runtime must use current image pointer size: %zu vs %zu", image_pointer_size_, sizeof(void*)); return false; } } dex_cache_boot_image_class_lookup_required_ = true; 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.GetImageFileLocationOatChecksum(), 0U); 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_); spaces[i]->GetLiveBitmap()->Walk(CheckTrampolines, &data); if (data.error) { ArtMethod* m = data.m; LOG(ERROR) << "Found a broken 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)); mirror::Class* 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::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)); 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())); } FinishInit(self); VLOG(startup) << __FUNCTION__ << " exiting"; return true; } bool ClassLinker::IsBootClassLoader(ScopedObjectAccessAlreadyRunnable& soa, mirror::ClassLoader* class_loader) { return class_loader == nullptr || class_loader->GetClass() == soa.Decode
(WellKnownClasses::java_lang_BootClassLoader); } static mirror::String* GetDexPathListElementName(ScopedObjectAccessUnchecked& soa, mirror::Object* element) SHARED_REQUIRES(Locks::mutator_lock_) { ArtField* const dex_file_field = soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile); ArtField* const dex_file_name_field = soa.DecodeField(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()) << PrettyTypeOf(element); mirror::Object* dex_file = dex_file_field->GetObject(element); if (dex_file == nullptr) { return nullptr; } mirror::Object* const name_object = dex_file_name_field->GetObject(dex_file); if (name_object != nullptr) { return name_object->AsString(); } return nullptr; } static bool FlattenPathClassLoader(mirror::ClassLoader* class_loader, std::list
* out_dex_file_names, std::string* error_msg) SHARED_REQUIRES(Locks::mutator_lock_) { DCHECK(out_dex_file_names != nullptr); DCHECK(error_msg != nullptr); ScopedObjectAccessUnchecked soa(Thread::Current()); ArtField* const dex_path_list_field = soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList); ArtField* const dex_elements_field = soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements); CHECK(dex_path_list_field != nullptr); CHECK(dex_elements_field != nullptr); while (!ClassLinker::IsBootClassLoader(soa, class_loader)) { if (class_loader->GetClass() != soa.Decode
(WellKnownClasses::dalvik_system_PathClassLoader)) { *error_msg = StringPrintf("Unknown class loader type %s", PrettyTypeOf(class_loader).c_str()); // Unsupported class loader. return false; } mirror::Object* dex_path_list = dex_path_list_field->GetObject(class_loader); if (dex_path_list != nullptr) { // DexPathList has an array dexElements of Elements[] which each contain a dex file. mirror::Object* dex_elements_obj = dex_elements_field->GetObject(dex_path_list); // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look // at the mCookie which is a DexFile vector. if (dex_elements_obj != nullptr) { mirror::ObjectArray
* dex_elements = dex_elements_obj->AsObjectArray
(); // Reverse order since we insert the parent at the front. for (int32_t i = dex_elements->GetLength() - 1; i >= 0; --i) { mirror::Object* const element = dex_elements->GetWithoutChecks(i); if (element == nullptr) { *error_msg = StringPrintf("Null dex element at index %d", i); return false; } mirror::String* const name = GetDexPathListElementName(soa, element); if (name == nullptr) { *error_msg = StringPrintf("Null name for dex element at index %d", i); return false; } out_dex_file_names->push_front(name); } } } class_loader = class_loader->GetParent(); } return true; } class FixupArtMethodArrayVisitor : public ArtMethodVisitor { public: explicit FixupArtMethodArrayVisitor(const ImageHeader& header) : header_(header) {} virtual void Visit(ArtMethod* method) SHARED_REQUIRES(Locks::mutator_lock_) { GcRoot
* resolved_types = method->GetDexCacheResolvedTypes(sizeof(void*)); const bool is_copied = method->IsCopied(); if (resolved_types != nullptr) { bool in_image_space = false; if (kIsDebugBuild || is_copied) { in_image_space = header_.GetImageSection(ImageHeader::kSectionDexCacheArrays).Contains( reinterpret_cast
(resolved_types) - header_.GetImageBegin()); } // Must be in image space for non-miranda method. DCHECK(is_copied || in_image_space) << resolved_types << " is not in image starting at " << reinterpret_cast
(header_.GetImageBegin()); if (!is_copied || in_image_space) { // Go through the array so that we don't need to do a slow map lookup. method->SetDexCacheResolvedTypes(*reinterpret_cast
**>(resolved_types), sizeof(void*)); } } ArtMethod** resolved_methods = method->GetDexCacheResolvedMethods(sizeof(void*)); if (resolved_methods != nullptr) { bool in_image_space = false; if (kIsDebugBuild || is_copied) { in_image_space = header_.GetImageSection(ImageHeader::kSectionDexCacheArrays).Contains( reinterpret_cast
(resolved_methods) - header_.GetImageBegin()); } // Must be in image space for non-miranda method. DCHECK(is_copied || in_image_space) << resolved_methods << " is not in image starting at " << reinterpret_cast
(header_.GetImageBegin()); if (!is_copied || in_image_space) { // Go through the array so that we don't need to do a slow map lookup. method->SetDexCacheResolvedMethods(*reinterpret_cast
(resolved_methods), sizeof(void*)); } } } private: const ImageHeader& header_; }; class VerifyClassInTableArtMethodVisitor : public ArtMethodVisitor { public: explicit VerifyClassInTableArtMethodVisitor(ClassTable* table) : table_(table) {} virtual void Visit(ArtMethod* method) SHARED_REQUIRES(Locks::mutator_lock_, Locks::classlinker_classes_lock_) { mirror::Class* klass = method->GetDeclaringClass(); if (klass != nullptr && !Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) { CHECK_EQ(table_->LookupByDescriptor(klass), klass) << PrettyClass(klass); } } private: ClassTable* const table_; }; class VerifyDeclaringClassVisitor : public ArtMethodVisitor { public: VerifyDeclaringClassVisitor() SHARED_REQUIRES(Locks::mutator_lock_, Locks::heap_bitmap_lock_) : live_bitmap_(Runtime::Current()->GetHeap()->GetLiveBitmap()) {} virtual void Visit(ArtMethod* method) SHARED_REQUIRES(Locks::mutator_lock_, Locks::heap_bitmap_lock_) { mirror::Class* klass = method->GetDeclaringClassUnchecked(); if (klass != nullptr) { CHECK(live_bitmap_->Test(klass)) << "Image method has unmarked declaring class"; } } private: gc::accounting::HeapBitmap* const live_bitmap_; }; bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( gc::space::ImageSpace* space, Handle
class_loader, Handle
> dex_caches, ClassTable::ClassSet* new_class_set, bool* out_forward_dex_cache_array, std::string* out_error_msg) { DCHECK(out_forward_dex_cache_array != nullptr); DCHECK(out_error_msg != nullptr); Thread* const self = Thread::Current(); gc::Heap* const heap = Runtime::Current()->GetHeap(); const ImageHeader& header = space->GetImageHeader(); { // Add image classes into the class table for the class loader, and fixup the dex caches and // class loader fields. WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); ClassTable* table = InsertClassTableForClassLoader(class_loader.Get()); // Dex cache array fixup is all or nothing, we must reject app images that have mixed since we // rely on clobering the dex cache arrays in the image to forward to bss. size_t num_dex_caches_with_bss_arrays = 0; const size_t num_dex_caches = dex_caches->GetLength(); for (size_t i = 0; i < num_dex_caches; i++) { mirror::DexCache* const dex_cache = dex_caches->Get(i); const DexFile* const dex_file = dex_cache->GetDexFile(); const OatFile::OatDexFile* oat_dex_file = dex_file->GetOatDexFile(); if (oat_dex_file != nullptr && oat_dex_file->GetDexCacheArrays() != nullptr) { ++num_dex_caches_with_bss_arrays; } } *out_forward_dex_cache_array = num_dex_caches_with_bss_arrays != 0; if (*out_forward_dex_cache_array) { if (num_dex_caches_with_bss_arrays != num_dex_caches) { // Reject application image since we cannot forward only some of the dex cache arrays. // TODO: We could get around this by having a dedicated forwarding slot. It should be an // uncommon case. *out_error_msg = StringPrintf("Dex caches in bss does not match total: %zu vs %zu", num_dex_caches_with_bss_arrays, num_dex_caches); return false; } } // Only add the classes to the class loader after the points where we can return false. for (size_t i = 0; i < num_dex_caches; i++) { mirror::DexCache* const dex_cache = dex_caches->Get(i); const DexFile* const dex_file = dex_cache->GetDexFile(); const OatFile::OatDexFile* oat_dex_file = dex_file->GetOatDexFile(); if (oat_dex_file != nullptr && oat_dex_file->GetDexCacheArrays() != nullptr) { // If the oat file expects the dex cache arrays to be in the BSS, then allocate there and // copy over the arrays. DCHECK(dex_file != nullptr); const size_t num_strings = dex_file->NumStringIds(); const size_t num_types = dex_file->NumTypeIds(); const size_t num_methods = dex_file->NumMethodIds(); const size_t num_fields = dex_file->NumFieldIds(); CHECK_EQ(num_strings, dex_cache->NumStrings()); CHECK_EQ(num_types, dex_cache->NumResolvedTypes()); CHECK_EQ(num_methods, dex_cache->NumResolvedMethods()); CHECK_EQ(num_fields, dex_cache->NumResolvedFields()); DexCacheArraysLayout layout(image_pointer_size_, dex_file); uint8_t* const raw_arrays = oat_dex_file->GetDexCacheArrays(); // The space is not yet visible to the GC, we can avoid the read barriers and use // std::copy_n. if (num_strings != 0u) { GcRoot
* const image_resolved_strings = dex_cache->GetStrings(); GcRoot
* const strings = reinterpret_cast
*>(raw_arrays + layout.StringsOffset()); for (size_t j = 0; kIsDebugBuild && j < num_strings; ++j) { DCHECK(strings[j].IsNull()); } std::copy_n(image_resolved_strings, num_strings, strings); dex_cache->SetStrings(strings); } if (num_types != 0u) { GcRoot
* const image_resolved_types = dex_cache->GetResolvedTypes(); GcRoot
* const types = reinterpret_cast
*>(raw_arrays + layout.TypesOffset()); for (size_t j = 0; kIsDebugBuild && j < num_types; ++j) { DCHECK(types[j].IsNull()); } std::copy_n(image_resolved_types, num_types, types); // Store a pointer to the new location for fast ArtMethod patching without requiring map. // This leaves random garbage at the start of the dex cache array, but nobody should ever // read from it again. *reinterpret_cast
**>(image_resolved_types) = types; dex_cache->SetResolvedTypes(types); } if (num_methods != 0u) { ArtMethod** const methods = reinterpret_cast
( raw_arrays + layout.MethodsOffset()); ArtMethod** const image_resolved_methods = dex_cache->GetResolvedMethods(); for (size_t j = 0; kIsDebugBuild && j < num_methods; ++j) { DCHECK(methods[j] == nullptr); } std::copy_n(image_resolved_methods, num_methods, methods); // Store a pointer to the new location for fast ArtMethod patching without requiring map. *reinterpret_cast
(image_resolved_methods) = methods; dex_cache->SetResolvedMethods(methods); } if (num_fields != 0u) { ArtField** const fields = reinterpret_cast
(raw_arrays + layout.FieldsOffset()); for (size_t j = 0; kIsDebugBuild && j < num_fields; ++j) { DCHECK(fields[j] == nullptr); } std::copy_n(dex_cache->GetResolvedFields(), num_fields, fields); dex_cache->SetResolvedFields(fields); } } { WriterMutexLock mu2(self, dex_lock_); // Make sure to do this after we update the arrays since we store the resolved types array // in DexCacheData in RegisterDexFileLocked. We need the array pointer to be the one in the // BSS. mirror::DexCache* existing_dex_cache = FindDexCacheLocked(self, *dex_file, /*allow_failure*/true); CHECK(existing_dex_cache == nullptr); StackHandleScope<1> hs3(self); RegisterDexFileLocked(*dex_file, hs3.NewHandle(dex_cache)); } GcRoot
* const types = dex_cache->GetResolvedTypes(); const size_t num_types = dex_cache->NumResolvedTypes(); if (new_class_set == nullptr) { for (int32_t j = 0; j < static_cast
(num_types); j++) { // The image space is not yet added to the heap, avoid read barriers. mirror::Class* klass = types[j].Read(); // There may also be boot image classes, if (space->HasAddress(klass)) { DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError); // Update the class loader from the one in the image class loader to the one that loaded // the app image. klass->SetClassLoader(class_loader.Get()); // The resolved type could be from another dex cache, go through the dex cache just in // case. May be null for array classes. if (klass->GetDexCacheStrings() != nullptr) { DCHECK(!klass->IsArrayClass()); klass->SetDexCacheStrings(klass->GetDexCache()->GetStrings()); } // If there are multiple dex caches, there may be the same class multiple times // in different dex caches. Check for this since inserting will add duplicates // otherwise. if (num_dex_caches > 1) { mirror::Class* existing = table->LookupByDescriptor(klass); if (existing != nullptr) { DCHECK_EQ(existing, klass) << PrettyClass(klass); } else { table->Insert(klass); } } else { table->Insert(klass); } // Double checked VLOG to avoid overhead. if (VLOG_IS_ON(image)) { VLOG(image) << PrettyClass(klass) << " " << klass->GetStatus(); if (!klass->IsArrayClass()) { VLOG(image) << "From " << klass->GetDexCache()->GetDexFile()->GetBaseLocation(); } VLOG(image) << "Direct methods"; for (ArtMethod& m : klass->GetDirectMethods(sizeof(void*))) { VLOG(image) << PrettyMethod(&m); } VLOG(image) << "Virtual methods"; for (ArtMethod& m : klass->GetVirtualMethods(sizeof(void*))) { VLOG(image) << PrettyMethod(&m); } } } else { DCHECK(klass == nullptr || heap->ObjectIsInBootImageSpace(klass)) << klass << " " << PrettyClass(klass); } } } if (kIsDebugBuild) { for (int32_t j = 0; j < static_cast
(num_types); j++) { // The image space is not yet added to the heap, avoid read barriers. mirror::Class* klass = types[j].Read(); if (space->HasAddress(klass)) { DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError); if (kIsDebugBuild) { if (new_class_set != nullptr) { auto it = new_class_set->Find(GcRoot
(klass)); DCHECK(it != new_class_set->end()); DCHECK_EQ(it->Read(), klass); mirror::Class* super_class = klass->GetSuperClass(); if (super_class != nullptr && !heap->ObjectIsInBootImageSpace(super_class)) { auto it2 = new_class_set->Find(GcRoot
(super_class)); DCHECK(it2 != new_class_set->end()); DCHECK_EQ(it2->Read(), super_class); } } else { DCHECK_EQ(table->LookupByDescriptor(klass), klass); mirror::Class* super_class = klass->GetSuperClass(); if (super_class != nullptr && !heap->ObjectIsInBootImageSpace(super_class)) { CHECK_EQ(table->LookupByDescriptor(super_class), super_class); } } } if (kIsDebugBuild) { for (ArtMethod& m : klass->GetDirectMethods(sizeof(void*))) { const void* code = m.GetEntryPointFromQuickCompiledCode(); const void* oat_code = m.IsInvokable() ? GetQuickOatCodeFor(&m) : code; if (!IsQuickResolutionStub(code) && !IsQuickGenericJniStub(code) && !IsQuickToInterpreterBridge(code) && !m.IsNative()) { DCHECK_EQ(code, oat_code) << PrettyMethod(&m); } } for (ArtMethod& m : klass->GetVirtualMethods(sizeof(void*))) { const void* code = m.GetEntryPointFromQuickCompiledCode(); const void* oat_code = m.IsInvokable() ? GetQuickOatCodeFor(&m) : code; if (!IsQuickResolutionStub(code) && !IsQuickGenericJniStub(code) && !IsQuickToInterpreterBridge(code) && !m.IsNative()) { DCHECK_EQ(code, oat_code) << PrettyMethod(&m); } } } } } } } } if (*out_forward_dex_cache_array) { ScopedTrace timing("Fixup ArtMethod dex cache arrays"); FixupArtMethodArrayVisitor visitor(header); header.VisitPackedArtMethods(&visitor, space->Begin(), sizeof(void*)); Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader.Get()); } if (kVerifyArtMethodDeclaringClasses) { ScopedTrace timing("Verify declaring classes"); ReaderMutexLock rmu(self, *Locks::heap_bitmap_lock_); VerifyDeclaringClassVisitor visitor; header.VisitPackedArtMethods(&visitor, space->Begin(), sizeof(void*)); } return true; } // Update the class loader and resolved string dex cache array of classes. Should only be used on // classes in the image space. class UpdateClassLoaderAndResolvedStringsVisitor { public: UpdateClassLoaderAndResolvedStringsVisitor(gc::space::ImageSpace* space, mirror::ClassLoader* class_loader, bool forward_strings) : space_(space), class_loader_(class_loader), forward_strings_(forward_strings) {} bool operator()(mirror::Class* klass) const SHARED_REQUIRES(Locks::mutator_lock_) { if (forward_strings_) { GcRoot
* strings = klass->GetDexCacheStrings(); if (strings != nullptr) { DCHECK( space_->GetImageHeader().GetImageSection(ImageHeader::kSectionDexCacheArrays).Contains( reinterpret_cast
(strings) - space_->Begin())) << "String dex cache array for " << PrettyClass(klass) << " is not in app image"; // Dex caches have already been updated, so take the strings pointer from there. GcRoot
* new_strings = klass->GetDexCache()->GetStrings(); DCHECK_NE(strings, new_strings); klass->SetDexCacheStrings(new_strings); } } // Finally, update class loader. klass->SetClassLoader(class_loader_); return true; } gc::space::ImageSpace* const space_; mirror::ClassLoader* const class_loader_; const bool forward_strings_; }; static std::unique_ptr
OpenOatDexFile(const OatFile* oat_file, const char* location, std::string* error_msg) SHARED_REQUIRES(Locks::mutator_lock_) { DCHECK(error_msg != nullptr); std::unique_ptr
dex_file; const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(location, nullptr); if (oat_dex_file == nullptr) { *error_msg = StringPrintf("Failed finding oat dex file for %s %s", oat_file->GetLocation().c_str(), location); 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(Thread::Current(), __FUNCTION__); const ImageHeader& header = space->GetImageHeader(); mirror::Object* 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++) { mirror::DexCache* 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; } 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.Get() != nullptr; const ImageHeader& header = space->GetImageHeader(); mirror::Object* 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(); StackHandleScope<2> hs(self); Handle
> dex_caches( hs.NewHandle(dex_caches_object->AsObjectArray
())); Handle
> class_roots(hs.NewHandle( header.GetImageRoot(ImageHeader::kClassRoots)->AsObjectArray
())); const OatFile* oat_file = space->GetOatFile(); std::unordered_set
image_class_loaders; // 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; } DCHECK(class_roots.Get() != 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; } } 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; } StackHandleScope<1> hs2(self); MutableHandle
h_dex_cache(hs2.NewHandle
(nullptr)); for (int32_t i = 0; i < dex_caches->GetLength(); i++) { h_dex_cache.Assign(dex_caches->Get(i)); std::string dex_file_location(h_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. h_dex_cache->SetDexFile(dex_file.get()); // Check that each class loader resolved the same way. // TODO: Store image class loaders as image roots. GcRoot
* const types = h_dex_cache->GetResolvedTypes(); for (int32_t j = 0, num_types = h_dex_cache->NumResolvedTypes(); j < num_types; j++) { mirror::Class* klass = types[j].Read(); if (klass != nullptr) { DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError); mirror::ClassLoader* image_class_loader = klass->GetClassLoader(); image_class_loaders.insert(image_class_loader); } } } else { if (kSanityCheckObjects) { SanityCheckArtMethodPointerArray(h_dex_cache->GetResolvedMethods(), h_dex_cache->NumResolvedMethods(), image_pointer_size_, heap->GetBootImageSpaces()); } // Register dex files, keep track of existing ones that are conflicts. AppendToBootClassPath(*dex_file.get(), h_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. for (mirror::ClassLoader* image_class_loader : image_class_loaders) { if (IsBootClassLoader(soa, image_class_loader)) { // The dex cache can reference types from the boot class loader. continue; } std::list
image_dex_file_names; std::string temp_error_msg; if (!FlattenPathClassLoader(image_class_loader, &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) { mirror::Object* element = elements->GetWithoutChecks(i); if (element != nullptr) { // If we are somewhere in the middle of the array, there may be nulls at the end. loader_dex_file_names.push_back(GetDexPathListElementName(soa, element)); } } // 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 (mirror::String* name : image_dex_file_names) { VLOG(image) << name->ToModifiedUtf8(); } VLOG(image) << "Loader dex files " << loader_dex_file_names.size(); for (mirror::String* 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) { heap->VisitObjects(SanityCheckObjectsCallback, nullptr); } } // 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_); } 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.GetImageSection(ImageHeader::kSectionClassTable); 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); if (!app_image) { dex_cache_boot_image_class_lookup_required_ = false; } VLOG(image) << "Adding class table classes took " << PrettyDuration(NanoTime() - start_time2); } if (app_image) { bool forward_dex_cache_arrays = false; if (!UpdateAppImageClassLoadersAndDexCaches(space, class_loader, dex_caches, added_class_table ? &temp_set : nullptr, /*out*/&forward_dex_cache_arrays, /*out*/error_msg)) { return false; } // Update class loader and resolved strings. If added_class_table is false, the resolved // strings were forwarded UpdateAppImageClassLoadersAndDexCaches. UpdateClassLoaderAndResolvedStringsVisitor visitor(space, class_loader.Get(), forward_dex_cache_arrays); if (added_class_table) { for (GcRoot
& root : temp_set) { visitor(root.Read()); } } // forward_dex_cache_arrays is true iff we copied all of the dex cache arrays into the .bss. // In this case, madvise away the dex cache arrays section of the image to reduce RAM usage and // mark as PROT_NONE to catch any invalid accesses. if (forward_dex_cache_arrays) { const ImageSection& dex_cache_section = header.GetImageSection( ImageHeader::kSectionDexCacheArrays); uint8_t* section_begin = AlignUp(space->Begin() + dex_cache_section.Offset(), kPageSize); uint8_t* section_end = AlignDown(space->Begin() + dex_cache_section.End(), kPageSize); if (section_begin < section_end) { madvise(section_begin, section_end - section_begin, MADV_DONTNEED); mprotect(section_begin, section_end - section_begin, PROT_NONE); VLOG(image) << "Released and protected dex cache array image section from " << reinterpret_cast
(section_begin) << "-" << reinterpret_cast
(section_end); } } } 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. VerifyClassInTableArtMethodVisitor visitor2(class_table); header.VisitPackedArtMethods(&visitor2, space->Begin(), sizeof(void*)); } VLOG(class_linker) << "Adding image space took " << PrettyDuration(NanoTime() - start_time); return true; } bool ClassLinker::ClassInClassTable(mirror::Class* 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_); BufferedRootVisitor
buffered_visitor( visitor, RootInfo(kRootStickyClass)); 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. boot_class_table_.VisitRoots(buffered_visitor); // If tracing is enabled, then mark all the class loaders to prevent unloading. if (tracing_enabled) { for (const ClassLoaderData& data : class_loaders_) { GcRoot
root(GcRoot
(self->DecodeJObject(data.weak_root))); root.VisitRoot(visitor, RootInfo(kRootVMInternal)); } } } else if ((flags & kVisitRootFlagNewRoots) != 0) { for (auto& root : new_class_roots_) { mirror::Class* old_ref = root.Read
(); root.VisitRoot(visitor, RootInfo(kRootStickyClass)); mirror::Class* new_ref = root.Read
(); // Concurrent moving GC marked new roots through the to-space invariant. CHECK_EQ(new_ref, old_ref); } } buffered_visitor.Flush(); // Flush before clearing new_class_roots_. if ((flags & kVisitRootFlagClearRootLog) != 0) { new_class_roots_.clear(); } if ((flags & kVisitRootFlagStartLoggingNewRoots) != 0) { log_new_class_table_roots_ = true; } else if ((flags & kVisitRootFlagStopLoggingNewRoots) != 0) { log_new_class_table_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(mirror::ClassLoader* class_loader) SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_) OVERRIDE { ClassTable* const class_table = class_loader->GetClassTable(); if (!done_ && class_table != nullptr && !class_table->Visit(*visitor_)) { // If the visitor ClassTable returns false it means that we don't need to continue. done_ = true; } } private: 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) { if (dex_cache_boot_image_class_lookup_required_) { AddBootImageClassesToClassTable(); } 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(self, __FUNCTION__); VisitClassesInternal(visitor); } else { VisitClassesInternal(visitor); } } class GetClassesInToVector : public ClassVisitor { public: bool operator()(mirror::Class* 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()(mirror::Class* klass) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) { ++index_; if (index_ <= arr_->GetLength()) { arr_->Set(index_ - 1, klass); return true; } return false; } bool Succeeded() const SHARED_REQUIRES(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. Thread* const self = Thread::Current(); if (!kMovingClasses) { ScopedAssertNoThreadSuspension nts(self, __FUNCTION__); GetClassesInToVector accumulator; VisitClasses(&accumulator); for (mirror::Class* klass : accumulator.classes_) { if (!visitor->operator()(klass)) { return; } } } else { 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; } mirror::Class* class_type = mirror::Class::GetJavaLangClass(); mirror::Class* array_of_class = FindArrayClass(self, &class_type); classes.Assign( mirror::ObjectArray
::Alloc(self, array_of_class, class_table_size)); CHECK(classes.Get() != 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. mirror::Class* 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(); Thread* const self = Thread::Current(); for (const ClassLoaderData& data : class_loaders_) { DeleteClassLoader(self, data); } class_loaders_.clear(); } void ClassLinker::DeleteClassLoader(Thread* self, const ClassLoaderData& data) { 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) { code_cache->RemoveMethodsIn(self, *data.allocator); } } delete data.allocator; delete data.class_table; } mirror::PointerArray* ClassLinker::AllocPointerArray(Thread* self, size_t length) { return down_cast
(image_pointer_size_ == 8u ? static_cast
(mirror::LongArray::Alloc(self, length)) : static_cast
(mirror::IntArray::Alloc(self, length))); } mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, const DexFile& dex_file, LinearAlloc* linear_alloc) { StackHandleScope<6> hs(self); auto dex_cache(hs.NewHandle(down_cast
( GetClassRoot(kJavaLangDexCache)->AllocObject(self)))); if (dex_cache.Get() == nullptr) { self->AssertPendingOOMException(); return nullptr; } auto location(hs.NewHandle(intern_table_->InternStrong(dex_file.GetLocation().c_str()))); if (location.Get() == nullptr) { self->AssertPendingOOMException(); return nullptr; } DexCacheArraysLayout layout(image_pointer_size_, &dex_file); uint8_t* raw_arrays = nullptr; if (dex_file.GetOatDexFile() != nullptr && dex_file.GetOatDexFile()->GetDexCacheArrays() != nullptr) { raw_arrays = dex_file.GetOatDexFile()->GetDexCacheArrays(); } else if (dex_file.NumStringIds() != 0u || dex_file.NumTypeIds() != 0u || dex_file.NumMethodIds() != 0u || dex_file.NumFieldIds() != 0u) { // NOTE: We "leak" the raw_arrays because we never destroy the dex cache. DCHECK(image_pointer_size_ == 4u || image_pointer_size_ == 8u); // Zero-initialized. raw_arrays = reinterpret_cast
(linear_alloc->Alloc(self, layout.Size())); } GcRoot
* strings = (dex_file.NumStringIds() == 0u) ? nullptr : reinterpret_cast
*>(raw_arrays + layout.StringsOffset()); GcRoot
* types = (dex_file.NumTypeIds() == 0u) ? nullptr : reinterpret_cast
*>(raw_arrays + layout.TypesOffset()); ArtMethod** methods = (dex_file.NumMethodIds() == 0u) ? nullptr : reinterpret_cast
(raw_arrays + layout.MethodsOffset()); ArtField** fields = (dex_file.NumFieldIds() == 0u) ? nullptr : reinterpret_cast
(raw_arrays + layout.FieldsOffset()); if (kIsDebugBuild) { // Sanity check to make sure all the dex cache arrays are empty. b/28992179 for (size_t i = 0; i < dex_file.NumStringIds(); ++i) { CHECK(strings[i].Read
() == nullptr); } for (size_t i = 0; i < dex_file.NumTypeIds(); ++i) { CHECK(types[i].Read
() == nullptr); } for (size_t i = 0; i < dex_file.NumMethodIds(); ++i) { CHECK(mirror::DexCache::GetElementPtrSize(methods, i, image_pointer_size_) == nullptr); } for (size_t i = 0; i < dex_file.NumFieldIds(); ++i) { CHECK(mirror::DexCache::GetElementPtrSize(fields, i, image_pointer_size_) == nullptr); } } dex_cache->Init(&dex_file, location.Get(), strings, dex_file.NumStringIds(), types, dex_file.NumTypeIds(), methods, dex_file.NumMethodIds(), fields, dex_file.NumFieldIds(), image_pointer_size_); return dex_cache.Get(); } mirror::Class* ClassLinker::AllocClass(Thread* self, mirror::Class* 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); mirror::Object* 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, mirror::Class* klass) { DCHECK(klass != nullptr); // For temporary classes we must wait for them to be retired. if (init_done_ && klass->IsTemp()) { CHECK(!klass->IsResolved()); if (klass->IsErroneous()) { 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->IsErroneous()) { lock.WaitIgnoringInterrupts(); } if (h_class->IsErroneous()) { ThrowEarlierClassFailure(h_class.Get()); return nullptr; } CHECK(h_class->IsRetired()); // Get the updated class from class table. klass = LookupClass(self, descriptor, ComputeModifiedUtf8Hash(descriptor), h_class.Get()->GetClassLoader()); } // Wait for the class if it has not already been linked. if (!klass->IsResolved() && !klass->IsErroneous()) { StackHandleScope<1> hs(self); HandleWrapper
h_class(hs.NewHandleWrapper(&klass)); ObjectLock
lock(self, h_class); // Check for circular dependencies between classes. if (!h_class->IsResolved() && h_class->GetClinitThreadId() == self->GetTid()) { ThrowClassCircularityError(h_class.Get()); mirror::Class::SetStatus(h_class, mirror::Class::kStatusError, self); return nullptr; } // Wait for the pending initialization to complete. while (!h_class->IsResolved() && !h_class->IsErroneous()) { lock.WaitIgnoringInterrupts(); } } if (klass->IsErroneous()) { ThrowEarlierClassFailure(klass); return nullptr; } // Return the loaded class. No exceptions should be pending. CHECK(klass->IsResolved()) << PrettyClass(klass); self->AssertNoPendingException(); return klass; } 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 = dex_file->FindClassDef(descriptor, hash); if (dex_class_def != nullptr) { return ClassPathEntry(dex_file, dex_class_def); } } return ClassPathEntry(nullptr, nullptr); } bool ClassLinker::FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& soa, Thread* self, const char* descriptor, size_t hash, Handle
class_loader, mirror::Class** result) { // Termination case: boot class-loader. if (IsBootClassLoader(soa, class_loader.Get())) { // The boot class loader, search the boot class path. ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_); if (pair.second != nullptr) { mirror::Class* 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(); } } else { *result = nullptr; } return true; } // Unsupported class-loader? if (class_loader->GetClass() != soa.Decode
(WellKnownClasses::dalvik_system_PathClassLoader)) { *result = nullptr; return false; } // Handles as RegisterDexFile may allocate dex caches (and cause thread suspension). StackHandleScope<4> hs(self); Handle
h_parent(hs.NewHandle(class_loader->GetParent())); bool recursive_result = FindClassInPathClassLoader(soa, self, descriptor, hash, h_parent, result); if (!recursive_result) { // Something wrong up the chain. return false; } if (*result != nullptr) { // Found the class up the chain. return true; } // Handle this step. // Handle as if this is the child PathClassLoader. // The class loader is a PathClassLoader which inherits from BaseDexClassLoader. // We need to get the DexPathList and loop through it. ArtField* const cookie_field = soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie); ArtField* const dex_file_field = soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile); mirror::Object* dex_path_list = soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList)-> GetObject(class_loader.Get()); if (dex_path_list != nullptr && dex_file_field != nullptr && cookie_field != nullptr) { // DexPathList has an array dexElements of Elements[] which each contain a dex file. mirror::Object* dex_elements_obj = soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements)-> GetObject(dex_path_list); // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look // at the mCookie which is a DexFile vector. if (dex_elements_obj != nullptr) { Handle
> dex_elements = hs.NewHandle(dex_elements_obj->AsObjectArray
()); for (int32_t i = 0; i < dex_elements->GetLength(); ++i) { mirror::Object* element = dex_elements->GetWithoutChecks(i); if (element == nullptr) { // Should never happen, fall back to java code to throw a NPE. break; } mirror::Object* dex_file = dex_file_field->GetObject(element); if (dex_file != nullptr) { mirror::LongArray* long_array = cookie_field->GetObject(dex_file)->AsLongArray(); if (long_array == nullptr) { // This should never happen so log a warning. LOG(WARNING) << "Null DexFile::mCookie for " << descriptor; break; } int32_t long_array_size = long_array->GetLength(); // First element is the oat file. for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) { const DexFile* cp_dex_file = reinterpret_cast
(static_cast
( long_array->GetWithoutChecks(j))); const DexFile::ClassDef* dex_class_def = cp_dex_file->FindClassDef(descriptor, hash); if (dex_class_def != nullptr) { mirror::Class* klass = DefineClass(self, descriptor, hash, class_loader, *cp_dex_file, *dex_class_def); if (klass == nullptr) { CHECK(self->IsExceptionPending()) << descriptor; self->ClearException(); // TODO: Is it really right to break here, and not check the other dex files? return true; } *result = klass; return true; } } } } } self->AssertNoPendingException(); } // Result is still null from the parent call, no need to set it again... return true; } 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(); 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. mirror::Class* klass = LookupClass(self, descriptor, hash, class_loader.Get()); if (klass != nullptr) { return EnsureResolved(self, descriptor, klass); } // Class is not yet loaded. if (descriptor[0] == '[') { return CreateArrayClass(self, descriptor, hash, class_loader); } else if (class_loader.Get() == nullptr) { // 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. mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError(); self->SetException(pre_allocated); return nullptr; } } else { ScopedObjectAccessUnchecked soa(self); mirror::Class* cp_klass; if (FindClassInPathClassLoader(soa, self, descriptor, hash, class_loader, &cp_klass)) { // The chain was understood. So the value in cp_klass is either the class we were looking // for, or not found. if (cp_klass != nullptr) { return cp_klass; } // TODO: We handle the boot classpath loader in FindClassInPathClassLoader. Try to unify this // and the branch above. TODO: throw the right exception here. // We'll let the Java-side rediscover all this and throw the exception with the right stack // trace. } if (Runtime::Current()->IsAotCompiler()) { // Oops, compile-time, can't run actual class-loader code. mirror::Throwable* pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError(); self->SetException(pre_allocated); return nullptr; } ScopedLocalRef
class_loader_object(soa.Env(), soa.AddLocalReference
(class_loader.Get())); std::string class_name_string(DescriptorToDot(descriptor)); 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 (self->IsExceptionPending()) { // If the ClassLoader threw, pass that exception up. return nullptr; } else if (result.get() == nullptr) { // 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; } else { // success, return mirror::Class* return soa.Decode
(result.get()); } } UNREACHABLE(); } 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)); } } if (klass.Get() == 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.Get() == nullptr)) { self->AssertPendingOOMException(); return nullptr; } mirror::DexCache* dex_cache = RegisterDexFile(dex_file, class_loader.Get()); if (dex_cache == nullptr) { self->AssertPendingOOMException(); return nullptr; } klass->SetDexCache(dex_cache); SetupClass(dex_file, dex_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()); // Add the newly loaded class to the loaded classes table. mirror::Class* 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, dex_file, dex_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, mirror::Class::kStatusError, self); } return nullptr; } // Finish loading (if necessary) by finding parents CHECK(!klass->IsLoaded()); if (!LoadSuperAndInterfaces(klass, dex_file)) { // Loading failed. if (!klass->IsErroneous()) { mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); } return nullptr; } CHECK(klass->IsLoaded()); // Link the class (if necessary) CHECK(!klass->IsResolved()); // TODO: Use fast jobjects? auto interfaces = hs.NewHandle
>(nullptr); MutableHandle
h_new_class = hs.NewHandle
(nullptr); if (!LinkClass(self, descriptor, klass, interfaces, &h_new_class)) { // Linking failed. if (!klass->IsErroneous()) { mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); } return nullptr; } self->AssertNoPendingException(); CHECK(h_new_class.Get() != nullptr) << descriptor; CHECK(h_new_class->IsResolved()) << descriptor; // Instrumentation may have updated entrypoints for all methods of all // classes. However it could not update methods of this class while we // were loading it. Now the class is resolved, we can update entrypoints // as required by instrumentation. if (Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()) { // We must be in the kRunnable state to prevent instrumentation from // suspending all threads to update entrypoints while we are doing it // for this class. DCHECK_EQ(self->GetState(), kRunnable); Runtime::Current()->GetInstrumentation()->InstallStubsForClass(h_new_class.Get()); } /* * We send CLASS_PREPARE events to the debugger from here. The * definition of "preparation" is creating the static fields for a * class and initializing them to the standard default values, but not * executing any code (that comes later, during "initialization"). * * We did the static preparation in LinkClass. * * The class has been prepared and resolved but possibly not yet verified * at this point. */ Dbg::PostClassPrepare(h_new_class.Get()); // Notify native debugger of the new class and its layout. jit::Jit::NewTypeLoadedIfUsingJit(h_new_class.Get()); return h_new_class.Get(); } uint32_t ClassLinker::SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def) { const uint8_t* class_data = dex_file.GetClassData(dex_class_def); size_t num_ref = 0; size_t num_8 = 0; size_t num_16 = 0; size_t num_32 = 0; size_t num_64 = 0; if (class_data != nullptr) { // We allow duplicate definitions of the same field in a class_data_item // but ignore the repeated indexes here, b/21868015. uint32_t last_field_idx = DexFile::kDexNoIndex; for (ClassDataItemIterator it(dex_file, class_data); it.HasNextStaticField(); it.Next()) { uint32_t field_idx = it.GetMemberIndex(); // Ordering enforced by DexFileVerifier. DCHECK(last_field_idx == DexFile::kDexNoIndex || last_field_idx <= field_idx); if (UNLIKELY(field_idx == last_field_idx)) { continue; } last_field_idx = field_idx; const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx); const char* descriptor = dex_file.GetFieldTypeDescriptor(field_id); char c = descriptor[0]; switch (c) { case 'L': case '[': num_ref++; break; case 'J': case 'D': num_64++; break; case 'I': case 'F': num_32++; break; case 'S': case 'C': num_16++; break; case 'B': case 'Z': num_8++; break; default: LOG(FATAL) << "Unknown descriptor: " << c; UNREACHABLE(); } } } return mirror::Class::ComputeClassSize(false, 0, num_8, num_16, num_32, num_64, num_ref, image_pointer_size_); } OatFile::OatClass ClassLinker::FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, bool* found) { DCHECK_NE(class_def_idx, DexFile::kDexNoIndex16); const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); if (oat_dex_file == nullptr) { *found = false; return OatFile::OatClass::Invalid(); } *found = true; return oat_dex_file->GetOatClass(class_def_idx); } static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint16_t class_def_idx, uint32_t method_idx) { const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx); const uint8_t* class_data = dex_file.GetClassData(class_def); CHECK(class_data != nullptr); ClassDataItemIterator it(dex_file, class_data); // Skip fields while (it.HasNextStaticField()) { it.Next(); } while (it.HasNextInstanceField()) { it.Next(); } // Process methods size_t class_def_method_index = 0; while (it.HasNextDirectMethod()) { if (it.GetMemberIndex() == method_idx) { return class_def_method_index; } class_def_method_index++; it.Next(); } while (it.HasNextVirtualMethod()) { if (it.GetMemberIndex() == method_idx) { return class_def_method_index; } class_def_method_index++; it.Next(); } DCHECK(!it.HasNext()); LOG(FATAL) << "Failed to find method index " << method_idx << " in " << dex_file.GetLocation(); UNREACHABLE(); } const OatFile::OatMethod ClassLinker::FindOatMethodFor(ArtMethod* method, bool* found) { // Although we overwrite the trampoline of non-static methods, we may get here via the resolution // method for direct methods (or virtual methods made direct). mirror::Class* declaring_class = method->GetDeclaringClass(); size_t oat_method_index; if (method->IsStatic() || method->IsDirect()) { // Simple case where the oat method index was stashed at load time. oat_method_index = method->GetMethodIndex(); } else { // We're invoking a virtual method directly (thanks to sharpening), compute the oat_method_index // by search for its position in the declared virtual methods. oat_method_index = declaring_class->NumDirectMethods(); bool found_virtual = false; for (ArtMethod& art_method : declaring_class->GetVirtualMethods(image_pointer_size_)) { // Check method index instead of identity in case of duplicate method definitions. if (method->GetDexMethodIndex() == art_method.GetDexMethodIndex()) { found_virtual = true; break; } oat_method_index++; } CHECK(found_virtual) << "Didn't find oat method index for virtual method: " << PrettyMethod(method); } DCHECK_EQ(oat_method_index, GetOatMethodIndexFromMethodIndex(*declaring_class->GetDexCache()->GetDexFile(), method->GetDeclaringClass()->GetDexClassDefIndex(), method->GetDexMethodIndex())); OatFile::OatClass oat_class = FindOatClass(*declaring_class->GetDexCache()->GetDexFile(), declaring_class->GetDexClassDefIndex(), found); if (!(*found)) { return OatFile::OatMethod::Invalid(); } return oat_class.GetOatMethod(oat_method_index); } // Special case to get oat code without overwriting a trampoline. const void* ClassLinker::GetQuickOatCodeFor(ArtMethod* method) { CHECK(method->IsInvokable()) << PrettyMethod(method); if (method->IsProxyMethod()) { return GetQuickProxyInvokeHandler(); } bool found; OatFile::OatMethod oat_method = FindOatMethodFor(method, &found); if (found) { auto* code = oat_method.GetQuickCode(); if (code != nullptr) { return code; } } if (method->IsNative()) { // No code and native? Use generic trampoline. return GetQuickGenericJniStub(); } return GetQuickToInterpreterBridge(); } const void* ClassLinker::GetOatMethodQuickCodeFor(ArtMethod* method) { if (method->IsNative() || !method->IsInvokable() || method->IsProxyMethod()) { return nullptr; } bool found; OatFile::OatMethod oat_method = FindOatMethodFor(method, &found); if (found) { return oat_method.GetQuickCode(); } return nullptr; } bool ClassLinker::ShouldUseInterpreterEntrypoint(ArtMethod* method, const void* quick_code) { if (UNLIKELY(method->IsNative() || method->IsProxyMethod())) { return false; } if (quick_code == nullptr) { return true; } Runtime* runtime = Runtime::Current(); instrumentation::Instrumentation* instr = runtime->GetInstrumentation(); if (instr->InterpretOnly()) { return true; } if (runtime->GetClassLinker()->IsQuickToInterpreterBridge(quick_code)) { // Doing this check avoids doing compiled/interpreter transitions. return true; } if (Dbg::IsForcedInterpreterNeededForCalling(Thread::Current(), method)) { // Force the use of interpreter when it is required by the debugger. return true; } if (runtime->IsNativeDebuggable()) { DCHECK(runtime->UseJitCompilation() && runtime->GetJit()->JitAtFirstUse()); // If we are doing native debugging, ignore application's AOT code, // since we want to JIT it with extra stackmaps for native debugging. // On the other hand, keep all AOT code from the boot image, since the // blocking JIT would results in non-negligible performance impact. return !runtime->GetHeap()->IsInBootImageOatFile(quick_code); } if (Dbg::IsDebuggerActive()) { // Boot image classes may be AOT-compiled as non-debuggable. // This is not suitable for the Java debugger, so ignore the AOT code. return runtime->GetHeap()->IsInBootImageOatFile(quick_code); } return false; } void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) { DCHECK(klass->IsInitialized()) << PrettyDescriptor(klass); if (klass->NumDirectMethods() == 0) { return; // No direct methods => no static methods. } Runtime* runtime = Runtime::Current(); if (!runtime->IsStarted()) { if (runtime->IsAotCompiler() || runtime->GetHeap()->HasBootImageSpace()) { return; // OAT file unavailable. } } const DexFile& dex_file = klass->GetDexFile(); const DexFile::ClassDef* dex_class_def = klass->GetClassDef(); CHECK(dex_class_def != nullptr); const uint8_t* class_data = dex_file.GetClassData(*dex_class_def); // There should always be class data if there were direct methods. CHECK(class_data != nullptr) << PrettyDescriptor(klass); ClassDataItemIterator it(dex_file, class_data); // Skip fields while (it.HasNextStaticField()) { it.Next(); } while (it.HasNextInstanceField()) { it.Next(); } bool has_oat_class; OatFile::OatClass oat_class = FindOatClass(dex_file, klass->GetDexClassDefIndex(), &has_oat_class); // Link the code of methods skipped by LinkCode. for (size_t method_index = 0; it.HasNextDirectMethod(); ++method_index, it.Next()) { ArtMethod* method = klass->GetDirectMethod(method_index, image_pointer_size_); if (!method->IsStatic()) { // Only update static methods. continue; } const void* quick_code = nullptr; if (has_oat_class) { OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index); quick_code = oat_method.GetQuickCode(); } // Check whether the method is native, in which case it's generic JNI. if (quick_code == nullptr && method->IsNative()) { quick_code = GetQuickGenericJniStub(); } else if (ShouldUseInterpreterEntrypoint(method, quick_code)) { // Use interpreter entry point. quick_code = GetQuickToInterpreterBridge(); } runtime->GetInstrumentation()->UpdateMethodsCode(method, quick_code); } // Ignore virtual methods on the iterator. } void ClassLinker::EnsureThrowsInvocationError(ArtMethod* method) { DCHECK(method != nullptr); DCHECK(!method->IsInvokable()); method->SetEntryPointFromQuickCompiledCodePtrSize(quick_to_interpreter_bridge_trampoline_, image_pointer_size_); } void ClassLinker::LinkCode(ArtMethod* method, const OatFile::OatClass* oat_class, uint32_t class_def_method_index) { Runtime* const runtime = Runtime::Current(); if (runtime->IsAotCompiler()) { // The following code only applies to a non-compiler runtime. return; } // Method shouldn't have already been linked. DCHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr); if (oat_class != nullptr) { // Every kind of method should at least get an invoke stub from the oat_method. // non-abstract methods also get their code pointers. const OatFile::OatMethod oat_method = oat_class->GetOatMethod(class_def_method_index); oat_method.LinkMethod(method); } // Install entry point from interpreter. const void* quick_code = method->GetEntryPointFromQuickCompiledCode(); bool enter_interpreter = ShouldUseInterpreterEntrypoint(method, quick_code); if (!method->IsInvokable()) { EnsureThrowsInvocationError(method); return; } if (method->IsStatic() && !method->IsConstructor()) { // For static methods excluding the class initializer, install the trampoline. // It will be replaced by the proper entry point by ClassLinker::FixupStaticTrampolines // after initializing class (see ClassLinker::InitializeClass method). method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionStub()); } else if (quick_code == nullptr && method->IsNative()) { method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub()); } else if (enter_interpreter) { // Set entry point from compiled code if there's no code or in interpreter only mode. method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge()); } if (method->IsNative()) { // Unregistering restores the dlsym lookup stub. method->UnregisterNative(); if (enter_interpreter || quick_code == nullptr) { // We have a native method here without code. Then it should have either the generic JNI // trampoline as entrypoint (non-static), or the resolution trampoline (static). // TODO: this doesn't handle all the cases where trampolines may be installed. const void* entry_point = method->GetEntryPointFromQuickCompiledCode(); DCHECK(IsQuickGenericJniStub(entry_point) || IsQuickResolutionStub(entry_point)); } } } void ClassLinker::SetupClass(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def, Handle
klass, mirror::ClassLoader* class_loader) { CHECK(klass.Get() != nullptr); CHECK(klass->GetDexCache() != nullptr); CHECK_EQ(mirror::Class::kStatusNotReady, klass->GetStatus()); const char* descriptor = dex_file.GetClassDescriptor(dex_class_def); CHECK(descriptor != nullptr); klass->SetClass(GetClassRoot(kJavaLangClass)); uint32_t access_flags = dex_class_def.GetJavaAccessFlags(); CHECK_EQ(access_flags & ~kAccJavaFlagsMask, 0U); klass->SetAccessFlags(access_flags); klass->SetClassLoader(class_loader); DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot); mirror::Class::SetStatus(klass, mirror::Class::kStatusIdx, nullptr); klass->SetDexClassDefIndex(dex_file.GetIndexForClassDef(dex_class_def)); klass->SetDexTypeIndex(dex_class_def.class_idx_); CHECK(klass->GetDexCacheStrings() != nullptr); } void ClassLinker::LoadClass(Thread* self, const DexFile& dex_file, const DexFile::ClassDef& dex_class_def, Handle
klass) { const uint8_t* class_data = dex_file.GetClassData(dex_class_def); if (class_data == nullptr) { return; // no fields or methods - for example a marker interface } bool has_oat_class = false; if (Runtime::Current()->IsStarted() && !Runtime::Current()->IsAotCompiler()) { OatFile::OatClass oat_class = FindOatClass(dex_file, klass->GetDexClassDefIndex(), &has_oat_class); if (has_oat_class) { LoadClassMembers(self, dex_file, class_data, klass, &oat_class); } } if (!has_oat_class) { LoadClassMembers(self, dex_file, class_data, klass, nullptr); } } LengthPrefixedArray
* ClassLinker::AllocArtFieldArray(Thread* self, LinearAlloc* allocator, size_t length) { if (length == 0) { return nullptr; } // If the ArtField alignment changes, review all uses of LengthPrefixedArray
. static_assert(alignof(ArtField) == 4, "ArtField alignment is expected to be 4."); size_t storage_size = LengthPrefixedArray
::ComputeSize(length); void* array_storage = allocator->Alloc(self, storage_size); auto* ret = new(array_storage) LengthPrefixedArray
(length); CHECK(ret != nullptr); std::uninitialized_fill_n(&ret->At(0), length, ArtField()); return ret; } LengthPrefixedArray
* ClassLinker::AllocArtMethodArray(Thread* self, LinearAlloc* allocator, size_t length) { if (length == 0) { return nullptr; } const size_t method_alignment = ArtMethod::Alignment(image_pointer_size_); const size_t method_size = ArtMethod::Size(image_pointer_size_); const size_t storage_size = LengthPrefixedArray
::ComputeSize(length, method_size, method_alignment); void* array_storage = allocator->Alloc(self, storage_size); auto* ret = new (array_storage) LengthPrefixedArray
(length); CHECK(ret != nullptr); for (size_t i = 0; i < length; ++i) { new(reinterpret_cast
(&ret->At(i, method_size, method_alignment))) ArtMethod; } return ret; } LinearAlloc* ClassLinker::GetAllocatorForClassLoader(mirror::ClassLoader* class_loader) { if (class_loader == nullptr) { return Runtime::Current()->GetLinearAlloc(); } LinearAlloc* allocator = class_loader->GetAllocator(); DCHECK(allocator != nullptr); return allocator; } LinearAlloc* ClassLinker::GetOrCreateAllocatorForClassLoader(mirror::ClassLoader* class_loader) { if (class_loader == nullptr) { return Runtime::Current()->GetLinearAlloc(); } WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); LinearAlloc* allocator = class_loader->GetAllocator(); if (allocator == nullptr) { RegisterClassLoader(class_loader); allocator = class_loader->GetAllocator(); CHECK(allocator != nullptr); } return allocator; } void ClassLinker::LoadClassMembers(Thread* self, const DexFile& dex_file, const uint8_t* class_data, Handle
klass, const OatFile::OatClass* oat_class) { { // Note: We cannot have thread suspension until the field and method arrays are setup or else // Class::VisitFieldRoots may miss some fields or methods. ScopedAssertNoThreadSuspension nts(self, __FUNCTION__); // Load static fields. // We allow duplicate definitions of the same field in a class_data_item // but ignore the repeated indexes here, b/21868015. LinearAlloc* const allocator = GetAllocatorForClassLoader(klass->GetClassLoader()); ClassDataItemIterator it(dex_file, class_data); LengthPrefixedArray
* sfields = AllocArtFieldArray(self, allocator, it.NumStaticFields()); size_t num_sfields = 0; uint32_t last_field_idx = 0u; for (; it.HasNextStaticField(); it.Next()) { uint32_t field_idx = it.GetMemberIndex(); DCHECK_GE(field_idx, last_field_idx); // Ordering enforced by DexFileVerifier. if (num_sfields == 0 || LIKELY(field_idx > last_field_idx)) { DCHECK_LT(num_sfields, it.NumStaticFields()); LoadField(it, klass, &sfields->At(num_sfields)); ++num_sfields; last_field_idx = field_idx; } } // Load instance fields. LengthPrefixedArray
* ifields = AllocArtFieldArray(self, allocator, it.NumInstanceFields()); size_t num_ifields = 0u; last_field_idx = 0u; for (; it.HasNextInstanceField(); it.Next()) { uint32_t field_idx = it.GetMemberIndex(); DCHECK_GE(field_idx, last_field_idx); // Ordering enforced by DexFileVerifier. if (num_ifields == 0 || LIKELY(field_idx > last_field_idx)) { DCHECK_LT(num_ifields, it.NumInstanceFields()); LoadField(it, klass, &ifields->At(num_ifields)); ++num_ifields; last_field_idx = field_idx; } } if (UNLIKELY(num_sfields != it.NumStaticFields()) || UNLIKELY(num_ifields != it.NumInstanceFields())) { LOG(WARNING) << "Duplicate fields in class " << PrettyDescriptor(klass.Get()) << " (unique static fields: " << num_sfields << "/" << it.NumStaticFields() << ", unique instance fields: " << num_ifields << "/" << it.NumInstanceFields() << ")"; // NOTE: Not shrinking the over-allocated sfields/ifields, just setting size. if (sfields != nullptr) { sfields->SetSize(num_sfields); } if (ifields != nullptr) { ifields->SetSize(num_ifields); } } // Set the field arrays. klass->SetSFieldsPtr(sfields); DCHECK_EQ(klass->NumStaticFields(), num_sfields); klass->SetIFieldsPtr(ifields); DCHECK_EQ(klass->NumInstanceFields(), num_ifields); // Load methods. klass->SetMethodsPtr( AllocArtMethodArray(self, allocator, it.NumDirectMethods() + it.NumVirtualMethods()), it.NumDirectMethods(), it.NumVirtualMethods()); size_t class_def_method_index = 0; uint32_t last_dex_method_index = DexFile::kDexNoIndex; size_t last_class_def_method_index = 0; // TODO These should really use the iterators. for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) { ArtMethod* method = klass->GetDirectMethodUnchecked(i, image_pointer_size_); LoadMethod(self, dex_file, it, klass, method); LinkCode(method, oat_class, class_def_method_index); uint32_t it_method_index = it.GetMemberIndex(); if (last_dex_method_index == it_method_index) { // duplicate case method->SetMethodIndex(last_class_def_method_index); } else { method->SetMethodIndex(class_def_method_index); last_dex_method_index = it_method_index; last_class_def_method_index = class_def_method_index; } class_def_method_index++; } for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) { ArtMethod* method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_); LoadMethod(self, dex_file, it, klass, method); DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i); LinkCode(method, oat_class, class_def_method_index); class_def_method_index++; } DCHECK(!it.HasNext()); } // Ensure that the card is marked so that remembered sets pick up native roots. Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(klass.Get()); self->AllowThreadSuspension(); } void ClassLinker::LoadField(const ClassDataItemIterator& it, Handle
klass, ArtField* dst) { const uint32_t field_idx = it.GetMemberIndex(); dst->SetDexFieldIndex(field_idx); dst->SetDeclaringClass(klass.Get()); dst->SetAccessFlags(it.GetFieldAccessFlags()); } void ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file, const ClassDataItemIterator& it, Handle
klass, ArtMethod* dst) { uint32_t dex_method_idx = it.GetMemberIndex(); const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx); const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_); ScopedAssertNoThreadSuspension ants(self, "LoadMethod"); dst->SetDexMethodIndex(dex_method_idx); dst->SetDeclaringClass(klass.Get()); dst->SetCodeItemOffset(it.GetMethodCodeItemOffset()); dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods(), image_pointer_size_); dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes(), image_pointer_size_); uint32_t access_flags = it.GetMethodAccessFlags(); if (UNLIKELY(strcmp("finalize", method_name) == 0)) { // Set finalizable flag on declaring class. if (strcmp("V", dex_file.GetShorty(method_id.proto_idx_)) == 0) { // Void return type. if (klass->GetClassLoader() != nullptr) { // All non-boot finalizer methods are flagged. klass->SetFinalizable(); } else { std::string temp; const char* klass_descriptor = klass->GetDescriptor(&temp); // The Enum class declares a "final" finalize() method to prevent subclasses from // introducing a finalizer. We don't want to set the finalizable flag for Enum or its // subclasses, so we exclude it here. // We also want to avoid setting the flag on Object, where we know that finalize() is // empty. if (strcmp(klass_descriptor, "Ljava/lang/Object;") != 0 && strcmp(klass_descriptor, "Ljava/lang/Enum;") != 0) { klass->SetFinalizable(); } } } } else if (method_name[0] == '<') { // Fix broken access flags for initializers. Bug 11157540. bool is_init = (strcmp("
", method_name) == 0); bool is_clinit = !is_init && (strcmp("
", method_name) == 0); if (UNLIKELY(!is_init && !is_clinit)) { LOG(WARNING) << "Unexpected '<' at start of method name " << method_name; } else { if (UNLIKELY((access_flags & kAccConstructor) == 0)) { LOG(WARNING) << method_name << " didn't have expected constructor access flag in class " << PrettyDescriptor(klass.Get()) << " in dex file " << dex_file.GetLocation(); access_flags |= kAccConstructor; } } } dst->SetAccessFlags(access_flags); } void ClassLinker::AppendToBootClassPath(Thread* self, const DexFile& dex_file) { StackHandleScope<1> hs(self); Handle
dex_cache(hs.NewHandle(AllocDexCache( self, dex_file, Runtime::Current()->GetLinearAlloc()))); CHECK(dex_cache.Get() != nullptr) << "Failed to allocate dex cache for " << dex_file.GetLocation(); AppendToBootClassPath(dex_file, dex_cache); } void ClassLinker::AppendToBootClassPath(const DexFile& dex_file, Handle
dex_cache) { CHECK(dex_cache.Get() != nullptr) << dex_file.GetLocation(); boot_class_path_.push_back(&dex_file); RegisterDexFile(dex_file, dex_cache); } void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, Handle
dex_cache) { Thread* const self = Thread::Current(); dex_lock_.AssertExclusiveHeld(self); CHECK(dex_cache.Get() != nullptr) << dex_file.GetLocation(); // For app images, the dex cache location may be a suffix of the dex file location since the // dex file location is an absolute path. const std::string dex_cache_location = dex_cache->GetLocation()->ToModifiedUtf8(); const size_t dex_cache_length = dex_cache_location.length(); CHECK_GT(dex_cache_length, 0u) << dex_file.GetLocation(); std::string dex_file_location = dex_file.GetLocation(); CHECK_GE(dex_file_location.length(), dex_cache_length) << dex_cache_location << " " << dex_file.GetLocation(); // Take suffix. const std::string dex_file_suffix = dex_file_location.substr( dex_file_location.length() - dex_cache_length, dex_cache_length); // Example dex_cache location is SettingsProvider.apk and // dex file location is /system/priv-app/SettingsProvider/SettingsProvider.apk CHECK_EQ(dex_cache_location, dex_file_suffix); // Clean up pass to remove null dex caches. // Null dex caches can occur due to class unloading and we are lazily removing null entries. JavaVMExt* const vm = self->GetJniEnv()->vm; for (auto it = dex_caches_.begin(); it != dex_caches_.end(); ) { DexCacheData data = *it; if (self->IsJWeakCleared(data.weak_root)) { vm->DeleteWeakGlobalRef(self, data.weak_root); it = dex_caches_.erase(it); } else { ++it; } } jweak dex_cache_jweak = vm->AddWeakGlobalRef(self, dex_cache.Get()); dex_cache->SetDexFile(&dex_file); DexCacheData data; data.weak_root = dex_cache_jweak; data.dex_file = dex_cache->GetDexFile(); data.resolved_types = dex_cache->GetResolvedTypes(); dex_caches_.push_back(data); } mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file, mirror::ClassLoader* class_loader) { Thread* self = Thread::Current(); { ReaderMutexLock mu(self, dex_lock_); mirror::DexCache* dex_cache = FindDexCacheLocked(self, dex_file, true); if (dex_cache != nullptr) { return dex_cache; } } LinearAlloc* const linear_alloc = GetOrCreateAllocatorForClassLoader(class_loader); DCHECK(linear_alloc != nullptr); ClassTable* table; { WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); table = InsertClassTableForClassLoader(class_loader); } // Don't alloc while holding the lock, since allocation may need to // suspend all threads and another thread may need the dex_lock_ to // get to a suspend point. StackHandleScope<1> hs(self); Handle
h_dex_cache(hs.NewHandle(AllocDexCache(self, dex_file, linear_alloc))); { WriterMutexLock mu(self, dex_lock_); mirror::DexCache* dex_cache = FindDexCacheLocked(self, dex_file, true); if (dex_cache != nullptr) { return dex_cache; } if (h_dex_cache.Get() == nullptr) { self->AssertPendingOOMException(); return nullptr; } RegisterDexFileLocked(dex_file, h_dex_cache); } table->InsertStrongRoot(h_dex_cache.Get()); return h_dex_cache.Get(); } void ClassLinker::RegisterDexFile(const DexFile& dex_file, Handle
dex_cache) { WriterMutexLock mu(Thread::Current(), dex_lock_); RegisterDexFileLocked(dex_file, dex_cache); } mirror::DexCache* ClassLinker::FindDexCache(Thread* self, const DexFile& dex_file, bool allow_failure) { ReaderMutexLock mu(self, dex_lock_); return FindDexCacheLocked(self, dex_file, allow_failure); } mirror::DexCache* ClassLinker::FindDexCacheLocked(Thread* self, const DexFile& dex_file, bool allow_failure) { // Search assuming unique-ness of dex file. for (const DexCacheData& data : dex_caches_) { // Avoid decoding (and read barriers) other unrelated dex caches. if (data.dex_file == &dex_file) { mirror::DexCache* dex_cache = down_cast
(self->DecodeJObject(data.weak_root)); if (dex_cache != nullptr) { return dex_cache; } else { break; } } } if (allow_failure) { return nullptr; } std::string location(dex_file.GetLocation()); // Failure, dump diagnostic and abort. for (const DexCacheData& data : dex_caches_) { mirror::DexCache* dex_cache = down_cast
(self->DecodeJObject(data.weak_root)); if (dex_cache != nullptr) { LOG(ERROR) << "Registered dex file " << dex_cache->GetDexFile()->GetLocation(); } } LOG(FATAL) << "Failed to find DexCache for DexFile " << location; UNREACHABLE(); } void ClassLinker::FixupDexCaches(ArtMethod* resolution_method) { Thread* const self = Thread::Current(); ReaderMutexLock mu(self, dex_lock_); for (const DexCacheData& data : dex_caches_) { if (!self->IsJWeakCleared(data.weak_root)) { mirror::DexCache* dex_cache = down_cast
( self->DecodeJObject(data.weak_root)); if (dex_cache != nullptr) { dex_cache->Fixup(resolution_method, image_pointer_size_); } } } } mirror::Class* ClassLinker::CreatePrimitiveClass(Thread* self, Primitive::Type type) { mirror::Class* klass = AllocClass(self, mirror::Class::PrimitiveClassSize(image_pointer_size_)); if (UNLIKELY(klass == nullptr)) { self->AssertPendingOOMException(); return nullptr; } return InitializePrimitiveClass(klass, type); } mirror::Class* ClassLinker::InitializePrimitiveClass(mirror::Class* primitive_class, Primitive::Type type) { CHECK(primitive_class != nullptr); // Must hold lock on object when initializing. Thread* self = Thread::Current(); StackHandleScope<1> hs(self); Handle
h_class(hs.NewHandle(primitive_class)); ObjectLock
lock(self, h_class); h_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract); h_class->SetPrimitiveType(type); mirror::Class::SetStatus(h_class, mirror::Class::kStatusInitialized, self); const char* descriptor = Primitive::Descriptor(type); mirror::Class* existing = InsertClass(descriptor, h_class.Get(), ComputeModifiedUtf8Hash(descriptor)); CHECK(existing == nullptr) << "InitPrimitiveClass(" << type << ") failed"; return h_class.Get(); } // Create an array class (i.e. the class object for the array, not the // array itself). "descriptor" looks like "[C" or "[[[[B" or // "[Ljava/lang/String;". // // If "descriptor" refers to an array of primitives, look up the // primitive type's internally-generated class object. // // "class_loader" is the class loader of the class that's referring to // us. It's used to ensure that we're looking for the element type in // the right context. It does NOT become the class loader for the // array class; that always comes from the base element class. // // Returns null with an exception raised on failure. mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descriptor, size_t hash, Handle
class_loader) { // Identify the underlying component type CHECK_EQ('[', descriptor[0]); StackHandleScope<2> hs(self); MutableHandle
component_type(hs.NewHandle(FindClass(self, descriptor + 1, class_loader))); if (component_type.Get() == nullptr) { DCHECK(self->IsExceptionPending()); // We need to accept erroneous classes as component types. const size_t component_hash = ComputeModifiedUtf8Hash(descriptor + 1); component_type.Assign(LookupClass(self, descriptor + 1, component_hash, class_loader.Get())); if (component_type.Get() == nullptr) { DCHECK(self->IsExceptionPending()); return nullptr; } else { self->ClearException(); } } if (UNLIKELY(component_type->IsPrimitiveVoid())) { ThrowNoClassDefFoundError("Attempt to create array of void primitive type"); return nullptr; } // See if the component type is already loaded. Array classes are // always associated with the class loader of their underlying // element type -- an array of Strings goes with the loader for // java/lang/String -- so we need to look for it there. (The // caller should have checked for the existence of the class // before calling here, but they did so with *their* class loader, // not the component type's loader.) // // If we find it, the caller adds "loader" to the class' initiating // loader list, which should prevent us from going through this again. // // This call is unnecessary if "loader" and "component_type->GetClassLoader()" // are the same, because our caller (FindClass) just did the // lookup. (Even if we get this wrong we still have correct behavior, // because we effectively do this lookup again when we add the new // class to the hash table --- necessary because of possible races with // other threads.) if (class_loader.Get() != component_type->GetClassLoader()) { mirror::Class* new_class = LookupClass(self, descriptor, hash, component_type->GetClassLoader()); if (new_class != nullptr) { return new_class; } } // Fill out the fields in the Class. // // It is possible to execute some methods against arrays, because // all arrays are subclasses of java_lang_Object_, so we need to set // up a vtable. We can just point at the one in java_lang_Object_. // // Array classes are simple enough that we don't need to do a full // link step. auto new_class = hs.NewHandle
(nullptr); if (UNLIKELY(!init_done_)) { // Classes that were hand created, ie not by FindSystemClass if (strcmp(descriptor, "[Ljava/lang/Class;") == 0) { new_class.Assign(GetClassRoot(kClassArrayClass)); } else if (strcmp(descriptor, "[Ljava/lang/Object;") == 0) { new_class.Assign(GetClassRoot(kObjectArrayClass)); } else if (strcmp(descriptor, GetClassRootDescriptor(kJavaLangStringArrayClass)) == 0) { new_class.Assign(GetClassRoot(kJavaLangStringArrayClass)); } else if (strcmp(descriptor, "[C") == 0) { new_class.Assign(GetClassRoot(kCharArrayClass)); } else if (strcmp(descriptor, "[I") == 0) { new_class.Assign(GetClassRoot(kIntArrayClass)); } else if (strcmp(descriptor, "[J") == 0) { new_class.Assign(GetClassRoot(kLongArrayClass)); } } if (new_class.Get() == nullptr) { new_class.Assign(AllocClass(self, mirror::Array::ClassSize(image_pointer_size_))); if (new_class.Get() == nullptr) { self->AssertPendingOOMException(); return nullptr; } new_class->SetComponentType(component_type.Get()); } ObjectLock
lock(self, new_class); // Must hold lock on object when initializing. DCHECK(new_class->GetComponentType() != nullptr); mirror::Class* java_lang_Object = GetClassRoot(kJavaLangObject); new_class->SetSuperClass(java_lang_Object); new_class->SetVTable(java_lang_Object->GetVTable()); new_class->SetPrimitiveType(Primitive::kPrimNot); new_class->SetClassLoader(component_type->GetClassLoader()); if (component_type->IsPrimitive()) { new_class->SetClassFlags(mirror::kClassFlagNoReferenceFields); } else { new_class->SetClassFlags(mirror::kClassFlagObjectArray); } mirror::Class::SetStatus(new_class, mirror::Class::kStatusLoaded, self); { ArtMethod* imt[mirror::Class::kImtSize]; std::fill_n(imt, arraysize(imt), Runtime::Current()->GetImtUnimplementedMethod()); new_class->PopulateEmbeddedImtAndVTable(imt, image_pointer_size_); } mirror::Class::SetStatus(new_class, mirror::Class::kStatusInitialized, self); // don't need to set new_class->SetObjectSize(..) // because Object::SizeOf delegates to Array::SizeOf // All arrays have java/lang/Cloneable and java/io/Serializable as // interfaces. We need to set that up here, so that stuff like // "instanceof" works right. // // Note: The GC could run during the call to FindSystemClass, // so we need to make sure the class object is GC-valid while we're in // there. Do this by clearing the interface list so the GC will just // think that the entries are null. // Use the single, global copies of "interfaces" and "iftable" // (remember not to free them for arrays). { mirror::IfTable* array_iftable = array_iftable_.Read(); CHECK(array_iftable != nullptr); new_class->SetIfTable(array_iftable); } // Inherit access flags from the component type. int access_flags = new_class->GetComponentType()->GetAccessFlags(); // Lose any implementation detail flags; in particular, arrays aren't finalizable. access_flags &= kAccJavaFlagsMask; // Arrays can't be used as a superclass or interface, so we want to add "abstract final" // and remove "interface". access_flags |= kAccAbstract | kAccFinal; access_flags &= ~kAccInterface; new_class->SetAccessFlags(access_flags); mirror::Class* existing = InsertClass(descriptor, new_class.Get(), hash); if (existing == nullptr) { jit::Jit::NewTypeLoadedIfUsingJit(new_class.Get()); return new_class.Get(); } // Another thread must have loaded the class after we // started but before we finished. Abandon what we've // done. // // (Yes, this happens.) return existing; } mirror::Class* ClassLinker::FindPrimitiveClass(char type) { switch (type) { case 'B': return GetClassRoot(kPrimitiveByte); case 'C': return GetClassRoot(kPrimitiveChar); case 'D': return GetClassRoot(kPrimitiveDouble); case 'F': return GetClassRoot(kPrimitiveFloat); case 'I': return GetClassRoot(kPrimitiveInt); case 'J': return GetClassRoot(kPrimitiveLong); case 'S': return GetClassRoot(kPrimitiveShort); case 'Z': return GetClassRoot(kPrimitiveBoolean); case 'V': return GetClassRoot(kPrimitiveVoid); default: break; } std::string printable_type(PrintableChar(type)); ThrowNoClassDefFoundError("Not a primitive type: %s", printable_type.c_str()); return nullptr; } mirror::Class* ClassLinker::InsertClass(const char* descriptor, mirror::Class* klass, size_t hash) { if (VLOG_IS_ON(class_linker)) { mirror::DexCache* dex_cache = klass->GetDexCache(); std::string source; if (dex_cache != nullptr) { source += " from "; source += dex_cache->GetLocation()->ToModifiedUtf8(); } LOG(INFO) << "Loaded class " << descriptor << source; } WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); mirror::ClassLoader* const class_loader = klass->GetClassLoader(); ClassTable* const class_table = InsertClassTableForClassLoader(class_loader); mirror::Class* existing = class_table->Lookup(descriptor, hash); if (existing != nullptr) { return existing; } if (kIsDebugBuild && !klass->IsTemp() && class_loader == nullptr && dex_cache_boot_image_class_lookup_required_) { // Check a class loaded with the system class loader matches one in the image if the class // is in the image. existing = LookupClassFromBootImage(descriptor); if (existing != nullptr) { CHECK_EQ(klass, existing); } } VerifyObject(klass); class_table->InsertWithHash(klass, hash); if (class_loader != nullptr) { // This is necessary because we need to have the card dirtied for remembered sets. Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader); } if (log_new_class_table_roots_) { new_class_roots_.push_back(GcRoot
(klass)); } return nullptr; } // TODO This should really be in mirror::Class. void ClassLinker::UpdateClassMethods(mirror::Class* klass, LengthPrefixedArray
* new_methods) { klass->SetMethodsPtrUnchecked(new_methods, klass->NumDirectMethods(), klass->NumDeclaredVirtualMethods()); // Need to mark the card so that the remembered sets and mod union tables get updated. Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(klass); } bool ClassLinker::RemoveClass(const char* descriptor, mirror::ClassLoader* class_loader) { WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); ClassTable* const class_table = ClassTableForClassLoader(class_loader); return class_table != nullptr && class_table->Remove(descriptor); } mirror::Class* ClassLinker::LookupClass(Thread* self, const char* descriptor, size_t hash, mirror::ClassLoader* class_loader) { { ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_); ClassTable* const class_table = ClassTableForClassLoader(class_loader); if (class_table != nullptr) { mirror::Class* result = class_table->Lookup(descriptor, hash); if (result != nullptr) { return result; } } } if (class_loader != nullptr || !dex_cache_boot_image_class_lookup_required_) { return nullptr; } // Lookup failed but need to search dex_caches_. mirror::Class* result = LookupClassFromBootImage(descriptor); if (result != nullptr) { result = InsertClass(descriptor, result, hash); } else { // Searching the image dex files/caches failed, we don't want to get into this situation // often as map searches are faster, so after kMaxFailedDexCacheLookups move all image // classes into the class table. constexpr uint32_t kMaxFailedDexCacheLookups = 1000; if (++failed_dex_cache_class_lookups_ > kMaxFailedDexCacheLookups) { AddBootImageClassesToClassTable(); } } return result; } static std::vector
*> GetImageDexCaches( std::vector
image_spaces) SHARED_REQUIRES(Locks::mutator_lock_) { CHECK(!image_spaces.empty()); std::vector
*> dex_caches_vector; for (gc::space::ImageSpace* image_space : image_spaces) { mirror::Object* root = image_space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches); DCHECK(root != nullptr); dex_caches_vector.push_back(root->AsObjectArray
()); } return dex_caches_vector; } void ClassLinker::AddBootImageClassesToClassTable() { if (dex_cache_boot_image_class_lookup_required_) { AddImageClassesToClassTable(Runtime::Current()->GetHeap()->GetBootImageSpaces(), /*class_loader*/nullptr); dex_cache_boot_image_class_lookup_required_ = false; } } void ClassLinker::AddImageClassesToClassTable(std::vector
image_spaces, mirror::ClassLoader* class_loader) { Thread* self = Thread::Current(); WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); ScopedAssertNoThreadSuspension ants(self, "Moving image classes to class table"); ClassTable* const class_table = InsertClassTableForClassLoader(class_loader); std::string temp; std::vector
*> dex_caches_vector = GetImageDexCaches(image_spaces); for (mirror::ObjectArray
* dex_caches : dex_caches_vector) { for (int32_t i = 0; i < dex_caches->GetLength(); i++) { mirror::DexCache* dex_cache = dex_caches->Get(i); GcRoot
* types = dex_cache->GetResolvedTypes(); for (int32_t j = 0, num_types = dex_cache->NumResolvedTypes(); j < num_types; j++) { mirror::Class* klass = types[j].Read(); if (klass != nullptr) { DCHECK_EQ(klass->GetClassLoader(), class_loader); const char* descriptor = klass->GetDescriptor(&temp); size_t hash = ComputeModifiedUtf8Hash(descriptor); mirror::Class* existing = class_table->Lookup(descriptor, hash); if (existing != nullptr) { CHECK_EQ(existing, klass) << PrettyClassAndClassLoader(existing) << " != " << PrettyClassAndClassLoader(klass); } else { class_table->Insert(klass); if (log_new_class_table_roots_) { new_class_roots_.push_back(GcRoot
(klass)); } } } } } } } class MoveClassTableToPreZygoteVisitor : public ClassLoaderVisitor { public: explicit MoveClassTableToPreZygoteVisitor() {} void Visit(mirror::ClassLoader* class_loader) REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_) OVERRIDE { ClassTable* const class_table = class_loader->GetClassTable(); if (class_table != nullptr) { class_table->FreezeSnapshot(); } } }; void ClassLinker::MoveClassTableToPreZygote() { WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); boot_class_table_.FreezeSnapshot(); MoveClassTableToPreZygoteVisitor visitor; VisitClassLoaders(&visitor); } mirror::Class* ClassLinker::LookupClassFromBootImage(const char* descriptor) { ScopedAssertNoThreadSuspension ants(Thread::Current(), "Image class lookup"); std::vector
*> dex_caches_vector = GetImageDexCaches(Runtime::Current()->GetHeap()->GetBootImageSpaces()); for (mirror::ObjectArray
* dex_caches : dex_caches_vector) { for (int32_t i = 0; i < dex_caches->GetLength(); ++i) { mirror::DexCache* dex_cache = dex_caches->Get(i); const DexFile* dex_file = dex_cache->GetDexFile(); // Try binary searching the type index by descriptor. const DexFile::TypeId* type_id = dex_file->FindTypeId(descriptor); if (type_id != nullptr) { uint16_t type_idx = dex_file->GetIndexForTypeId(*type_id); mirror::Class* klass = dex_cache->GetResolvedType(type_idx); if (klass != nullptr) { return klass; } } } } return nullptr; } // Look up classes by hash and descriptor and put all matching ones in the result array. class LookupClassesVisitor : public ClassLoaderVisitor { public: LookupClassesVisitor(const char* descriptor, size_t hash, std::vector
* result) : descriptor_(descriptor), hash_(hash), result_(result) {} void Visit(mirror::ClassLoader* class_loader) SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_) OVERRIDE { ClassTable* const class_table = class_loader->GetClassTable(); mirror::Class* klass = class_table->Lookup(descriptor_, hash_); if (klass != nullptr) { result_->push_back(klass); } } private: const char* const descriptor_; const size_t hash_; std::vector
* const result_; }; void ClassLinker::LookupClasses(const char* descriptor, std::vector
& result) { result.clear(); if (dex_cache_boot_image_class_lookup_required_) { AddBootImageClassesToClassTable(); } Thread* const self = Thread::Current(); ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_); const size_t hash = ComputeModifiedUtf8Hash(descriptor); mirror::Class* klass = boot_class_table_.Lookup(descriptor, hash); if (klass != nullptr) { result.push_back(klass); } LookupClassesVisitor visitor(descriptor, hash, &result); VisitClassLoaders(&visitor); } bool ClassLinker::AttemptSupertypeVerification(Thread* self, Handle
klass, Handle
supertype) { DCHECK(self != nullptr); DCHECK(klass.Get() != nullptr); DCHECK(supertype.Get() != nullptr); if (!supertype->IsVerified() && !supertype->IsErroneous()) { VerifyClass(self, supertype); } if (supertype->IsCompileTimeVerified()) { // Either we are verified or we soft failed and need to retry at runtime. return true; } // If we got this far then we have a hard failure. std::string error_msg = StringPrintf("Rejecting class %s that attempts to sub-type erroneous class %s", PrettyDescriptor(klass.Get()).c_str(), PrettyDescriptor(supertype.Get()).c_str()); LOG(WARNING) << error_msg << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8(); StackHandleScope<1> hs(self); Handle
cause(hs.NewHandle(self->GetException())); if (cause.Get() != nullptr) { // Set during VerifyClass call (if at all). self->ClearException(); } // Change into a verify error. ThrowVerifyError(klass.Get(), "%s", error_msg.c_str()); if (cause.Get() != nullptr) { self->GetException()->SetCause(cause.Get()); } ClassReference ref(klass->GetDexCache()->GetDexFile(), klass->GetDexClassDefIndex()); if (Runtime::Current()->IsAotCompiler()) { Runtime::Current()->GetCompilerCallbacks()->ClassRejected(ref); } // Need to grab the lock to change status. ObjectLock
super_lock(self, klass); mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); return false; } void ClassLinker::VerifyClass(Thread* self, Handle
klass, LogSeverity log_level) { { // TODO: assert that the monitor on the Class is held ObjectLock
lock(self, klass); // Is somebody verifying this now? mirror::Class::Status old_status = klass->GetStatus(); while (old_status == mirror::Class::kStatusVerifying || old_status == mirror::Class::kStatusVerifyingAtRuntime) { lock.WaitIgnoringInterrupts(); CHECK(klass->IsErroneous() || (klass->GetStatus() > old_status)) << "Class '" << PrettyClass(klass.Get()) << "' performed an illegal verification state " << "transition from " << old_status << " to " << klass->GetStatus(); old_status = klass->GetStatus(); } // The class might already be erroneous, for example at compile time if we attempted to verify // this class as a parent to another. if (klass->IsErroneous()) { ThrowEarlierClassFailure(klass.Get()); return; } // Don't attempt to re-verify if already sufficiently verified. if (klass->IsVerified()) { EnsureSkipAccessChecksMethods(klass); return; } if (klass->IsCompileTimeVerified() && Runtime::Current()->IsAotCompiler()) { return; } if (klass->GetStatus() == mirror::Class::kStatusResolved) { mirror::Class::SetStatus(klass, mirror::Class::kStatusVerifying, self); } else { CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime) << PrettyClass(klass.Get()); CHECK(!Runtime::Current()->IsAotCompiler()); mirror::Class::SetStatus(klass, mirror::Class::kStatusVerifyingAtRuntime, self); } // Skip verification if disabled. if (!Runtime::Current()->IsVerificationEnabled()) { mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self); EnsureSkipAccessChecksMethods(klass); return; } } // Verify super class. StackHandleScope<2> hs(self); MutableHandle
supertype(hs.NewHandle(klass->GetSuperClass())); // If we have a superclass and we get a hard verification failure we can return immediately. if (supertype.Get() != nullptr && !AttemptSupertypeVerification(self, klass, supertype)) { CHECK(self->IsExceptionPending()) << "Verification error should be pending."; return; } // Verify all default super-interfaces. // // (1) Don't bother if the superclass has already had a soft verification failure. // // (2) Interfaces shouldn't bother to do this recursive verification because they cannot cause // recursive initialization by themselves. This is because when an interface is initialized // directly it must not initialize its superinterfaces. We are allowed to verify regardless // but choose not to for an optimization. If the interfaces is being verified due to a class // initialization (which would need all the default interfaces to be verified) the class code // will trigger the recursive verification anyway. if ((supertype.Get() == nullptr || supertype->IsVerified()) // See (1) && !klass->IsInterface()) { // See (2) int32_t iftable_count = klass->GetIfTableCount(); MutableHandle
iface(hs.NewHandle
(nullptr)); // Loop through all interfaces this class has defined. It doesn't matter the order. for (int32_t i = 0; i < iftable_count; i++) { iface.Assign(klass->GetIfTable()->GetInterface(i)); DCHECK(iface.Get() != nullptr); // We only care if we have default interfaces and can skip if we are already verified... if (LIKELY(!iface->HasDefaultMethods() || iface->IsVerified())) { continue; } else if (UNLIKELY(!AttemptSupertypeVerification(self, klass, iface))) { // We had a hard failure while verifying this interface. Just return immediately. CHECK(self->IsExceptionPending()) << "Verification error should be pending."; return; } else if (UNLIKELY(!iface->IsVerified())) { // We softly failed to verify the iface. Stop checking and clean up. // Put the iface into the supertype handle so we know what caused us to fail. supertype.Assign(iface.Get()); break; } } } // At this point if verification failed, then supertype is the "first" supertype that failed // verification (without a specific order). If verification succeeded, then supertype is either // null or the original superclass of klass and is verified. DCHECK(supertype.Get() == nullptr || supertype.Get() == klass->GetSuperClass() || !supertype->IsVerified()); // Try to use verification information from the oat file, otherwise do runtime verification. const DexFile& dex_file = *klass->GetDexCache()->GetDexFile(); mirror::Class::Status oat_file_class_status(mirror::Class::kStatusNotReady); bool preverified = VerifyClassUsingOatFile(dex_file, klass.Get(), oat_file_class_status); // If the oat file says the class had an error, re-run the verifier. That way we will get a // precise error message. To ensure a rerun, test: // oat_file_class_status == mirror::Class::kStatusError => !preverified DCHECK(!(oat_file_class_status == mirror::Class::kStatusError) || !preverified); verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure; std::string error_msg; if (!preverified) { Runtime* runtime = Runtime::Current(); verifier_failure = verifier::MethodVerifier::VerifyClass(self, klass.Get(), runtime->GetCompilerCallbacks(), runtime->IsAotCompiler(), log_level, &error_msg); } // Verification is done, grab the lock again. ObjectLock
lock(self, klass); if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) { if (!preverified && verifier_failure != verifier::MethodVerifier::kNoFailure) { VLOG(class_linker) << "Soft verification failure in class " << PrettyDescriptor(klass.Get()) << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8() << " because: " << error_msg; } self->AssertNoPendingException(); // Make sure all classes referenced by catch blocks are resolved. ResolveClassExceptionHandlerTypes(klass); if (verifier_failure == verifier::MethodVerifier::kNoFailure) { // Even though there were no verifier failures we need to respect whether the super-class and // super-default-interfaces were verified or requiring runtime reverification. if (supertype.Get() == nullptr || supertype->IsVerified()) { mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self); } else { CHECK_EQ(supertype->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime); mirror::Class::SetStatus(klass, mirror::Class::kStatusRetryVerificationAtRuntime, self); // Pretend a soft failure occurred so that we don't consider the class verified below. verifier_failure = verifier::MethodVerifier::kSoftFailure; } } else { CHECK_EQ(verifier_failure, verifier::MethodVerifier::kSoftFailure); // Soft failures at compile time should be retried at runtime. Soft // failures at runtime will be handled by slow paths in the generated // code. Set status accordingly. if (Runtime::Current()->IsAotCompiler()) { mirror::Class::SetStatus(klass, mirror::Class::kStatusRetryVerificationAtRuntime, self); } else { mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self); // As this is a fake verified status, make sure the methods are _not_ marked // kAccSkipAccessChecks later. klass->SetVerificationAttempted(); } } } else { VLOG(verifier) << "Verification failed on class " << PrettyDescriptor(klass.Get()) << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8() << " because: " << error_msg; self->AssertNoPendingException(); ThrowVerifyError(klass.Get(), "%s", error_msg.c_str()); mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); } if (preverified || verifier_failure == verifier::MethodVerifier::kNoFailure) { // Class is verified so we don't need to do any access check on its methods. // Let the interpreter know it by setting the kAccSkipAccessChecks flag onto each // method. // Note: we're going here during compilation and at runtime. When we set the // kAccSkipAccessChecks flag when compiling image classes, the flag is recorded // in the image and is set when loading the image. if (UNLIKELY(Runtime::Current()->IsVerificationSoftFail())) { // Never skip access checks if the verification soft fail is forced. // Mark the class as having a verification attempt to avoid re-running the verifier. klass->SetVerificationAttempted(); } else { EnsureSkipAccessChecksMethods(klass); } } } void ClassLinker::EnsureSkipAccessChecksMethods(Handle
klass) { if (!klass->WasVerificationAttempted()) { klass->SetSkipAccessChecksFlagOnAllMethods(image_pointer_size_); klass->SetVerificationAttempted(); } } bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class* klass, mirror::Class::Status& oat_file_class_status) { // If we're compiling, we can only verify the class using the oat file if // we are not compiling the image or if the class we're verifying is not part of // the app. In other words, we will only check for preverification of bootclasspath // classes. if (Runtime::Current()->IsAotCompiler()) { // Are we compiling the bootclasspath? if (Runtime::Current()->GetCompilerCallbacks()->IsBootImage()) { return false; } // We are compiling an app (not the image). // Is this an app class? (I.e. not a bootclasspath class) if (klass->GetClassLoader() != nullptr) { return false; } } const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); // In case we run without an image there won't be a backing oat file. if (oat_dex_file == nullptr) { return false; } // We may be running with a preopted oat file but without image. In this case, // we don't skip verification of skip_access_checks classes to ensure we initialize // dex caches with all types resolved during verification. // We need to trust image classes, as these might be coming out of a pre-opted, quickened boot // image (that we just failed loading), and the verifier can't be run on quickened opcodes when // the runtime isn't started. On the other hand, app classes can be re-verified even if they are // already pre-opted, as then the runtime is started. if (!Runtime::Current()->IsAotCompiler() && !Runtime::Current()->GetHeap()->HasBootImageSpace() && klass->GetClassLoader() != nullptr) { return false; } uint16_t class_def_index = klass->GetDexClassDefIndex(); oat_file_class_status = oat_dex_file->GetOatClass(class_def_index).GetStatus(); if (oat_file_class_status == mirror::Class::kStatusVerified || oat_file_class_status == mirror::Class::kStatusInitialized) { return true; } // If we only verified a subset of the classes at compile time, we can end up with classes that // were resolved by the verifier. if (oat_file_class_status == mirror::Class::kStatusResolved) { return false; } if (oat_file_class_status == mirror::Class::kStatusRetryVerificationAtRuntime) { // Compile time verification failed with a soft error. Compile time verification can fail // because we have incomplete type information. Consider the following: // class ... { // Foo x; // .... () { // if (...) { // v1 gets assigned a type of resolved class Foo // } else { // v1 gets assigned a type of unresolved class Bar // } // iput x = v1 // } } // when we merge v1 following the if-the-else it results in Conflict // (see verifier::RegType::Merge) as we can't know the type of Bar and we could possibly be // allowing an unsafe assignment to the field x in the iput (javac may have compiled this as // it knew Bar was a sub-class of Foo, but for us this may have been moved into a separate apk // at compile time). return false; } if (oat_file_class_status == mirror::Class::kStatusError) { // Compile time verification failed with a hard error. This is caused by invalid instructions // in the class. These errors are unrecoverable. return false; } if (oat_file_class_status == mirror::Class::kStatusNotReady) { // Status is uninitialized if we couldn't determine the status at compile time, for example, // not loading the class. // TODO: when the verifier doesn't rely on Class-es failing to resolve/load the type hierarchy // isn't a problem and this case shouldn't occur return false; } std::string temp; LOG(FATAL) << "Unexpected class status: " << oat_file_class_status << " " << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << klass->GetDescriptor(&temp); UNREACHABLE(); } void ClassLinker::ResolveClassExceptionHandlerTypes(Handle
klass) { for (ArtMethod& method : klass->GetMethods(image_pointer_size_)) { ResolveMethodExceptionHandlerTypes(&method); } } void ClassLinker::ResolveMethodExceptionHandlerTypes(ArtMethod* method) { // similar to DexVerifier::ScanTryCatchBlocks and dex2oat's ResolveExceptionsForMethod. const DexFile::CodeItem* code_item = method->GetDexFile()->GetCodeItem(method->GetCodeItemOffset()); if (code_item == nullptr) { return; // native or abstract method } if (code_item->tries_size_ == 0) { return; // nothing to process } const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item, 0); uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr); for (uint32_t idx = 0; idx < handlers_size; idx++) { CatchHandlerIterator iterator(handlers_ptr); for (; iterator.HasNext(); iterator.Next()) { // Ensure exception types are resolved so that they don't need resolution to be delivered, // unresolved exception types will be ignored by exception delivery if (iterator.GetHandlerTypeIndex() != DexFile::kDexNoIndex16) { mirror::Class* exception_type = ResolveType(iterator.GetHandlerTypeIndex(), method); if (exception_type == nullptr) { DCHECK(Thread::Current()->IsExceptionPending()); Thread::Current()->ClearException(); } } } handlers_ptr = iterator.EndDataPointer(); } } mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa, jstring name, jobjectArray interfaces, jobject loader, jobjectArray methods, jobjectArray throws) { Thread* self = soa.Self(); StackHandleScope<10> hs(self); MutableHandle
klass(hs.NewHandle( AllocClass(self, GetClassRoot(kJavaLangClass), sizeof(mirror::Class)))); if (klass.Get() == nullptr) { CHECK(self->IsExceptionPending()); // OOME. return nullptr; } DCHECK(klass->GetClass() != nullptr); klass->SetObjectSize(sizeof(mirror::Proxy)); // Set the class access flags incl. VerificationAttempted, so we do not try to set the flag on // the methods. klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccVerificationAttempted); klass->SetClassLoader(soa.Decode
(loader)); DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot); klass->SetName(soa.Decode
(name)); klass->SetDexCache(GetClassRoot(kJavaLangReflectProxy)->GetDexCache()); mirror::Class::SetStatus(klass, mirror::Class::kStatusIdx, self); std::string descriptor(GetDescriptorForProxy(klass.Get())); const size_t hash = ComputeModifiedUtf8Hash(descriptor.c_str()); // Needs to be before we insert the class so that the allocator field is set. LinearAlloc* const allocator = GetOrCreateAllocatorForClassLoader(klass->GetClassLoader()); // Insert the class before loading the fields as the field roots // (ArtField::declaring_class_) are only visited from the class // table. There can't be any suspend points between inserting the // class and setting the field arrays below. mirror::Class* existing = InsertClass(descriptor.c_str(), klass.Get(), hash); CHECK(existing == nullptr); // Instance fields are inherited, but we add a couple of static fields... const size_t num_fields = 2; LengthPrefixedArray
* sfields = AllocArtFieldArray(self, allocator, num_fields); klass->SetSFieldsPtr(sfields); // 1. Create a static field 'interfaces' that holds the _declared_ interfaces implemented by // our proxy, so Class.getInterfaces doesn't return the flattened set. ArtField& interfaces_sfield = sfields->At(0); interfaces_sfield.SetDexFieldIndex(0); interfaces_sfield.SetDeclaringClass(klass.Get()); interfaces_sfield.SetAccessFlags(kAccStatic | kAccPublic | kAccFinal); // 2. Create a static field 'throws' that holds exceptions thrown by our methods. ArtField& throws_sfield = sfields->At(1); throws_sfield.SetDexFieldIndex(1); throws_sfield.SetDeclaringClass(klass.Get()); throws_sfield.SetAccessFlags(kAccStatic | kAccPublic | kAccFinal); // Proxies have 1 direct method, the constructor const size_t num_direct_methods = 1; // They have as many virtual methods as the array auto h_methods = hs.NewHandle(soa.Decode
*>(methods)); DCHECK_EQ(h_methods->GetClass(), mirror::Method::ArrayClass()) << PrettyClass(h_methods->GetClass()); const size_t num_virtual_methods = h_methods->GetLength(); // Create the methods array. LengthPrefixedArray
* proxy_class_methods = AllocArtMethodArray( self, allocator, num_direct_methods + num_virtual_methods); // Currently AllocArtMethodArray cannot return null, but the OOM logic is left there in case we // want to throw OOM in the future. if (UNLIKELY(proxy_class_methods == nullptr)) { self->AssertPendingOOMException(); return nullptr; } klass->SetMethodsPtr(proxy_class_methods, num_direct_methods, num_virtual_methods); // Create the single direct method. CreateProxyConstructor(klass, klass->GetDirectMethodUnchecked(0, image_pointer_size_)); // Create virtual method using specified prototypes. // TODO These should really use the iterators. for (size_t i = 0; i < num_virtual_methods; ++i) { auto* virtual_method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_); auto* prototype = h_methods->Get(i)->GetArtMethod(); CreateProxyMethod(klass, prototype, virtual_method); DCHECK(virtual_method->GetDeclaringClass() != nullptr); DCHECK(prototype->GetDeclaringClass() != nullptr); } // The super class is java.lang.reflect.Proxy klass->SetSuperClass(GetClassRoot(kJavaLangReflectProxy)); // Now effectively in the loaded state. mirror::Class::SetStatus(klass, mirror::Class::kStatusLoaded, self); self->AssertNoPendingException(); MutableHandle
new_class = hs.NewHandle
(nullptr); { // Must hold lock on object when resolved. ObjectLock
resolution_lock(self, klass); // Link the fields and virtual methods, creating vtable and iftables. // The new class will replace the old one in the class table. Handle
> h_interfaces( hs.NewHandle(soa.Decode
*>(interfaces))); if (!LinkClass(self, descriptor.c_str(), klass, h_interfaces, &new_class)) { mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); return nullptr; } } CHECK(klass->IsRetired()); CHECK_NE(klass.Get(), new_class.Get()); klass.Assign(new_class.Get()); CHECK_EQ(interfaces_sfield.GetDeclaringClass(), klass.Get()); interfaces_sfield.SetObject
(klass.Get(), soa.Decode