diff options
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r-- | runtime/class_linker.cc | 3959 |
1 files changed, 3959 insertions, 0 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc new file mode 100644 index 000000000..8ea429570 --- /dev/null +++ b/runtime/class_linker.cc @@ -0,0 +1,3959 @@ +/* + * 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 <fcntl.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <deque> +#include <string> +#include <utility> +#include <vector> + +#include "base/casts.h" +#include "base/logging.h" +#include "base/stl_util.h" +#include "base/unix_file/fd_file.h" +#include "class_linker-inl.h" +#include "debugger.h" +#include "dex_file-inl.h" +#include "gc/accounting/card_table-inl.h" +#include "gc/accounting/heap_bitmap.h" +#include "gc/heap.h" +#include "gc/space/image_space.h" +#include "intern_table.h" +#include "interpreter/interpreter.h" +#include "leb128.h" +#include "oat.h" +#include "oat_file.h" +#include "mirror/class.h" +#include "mirror/class-inl.h" +#include "mirror/class_loader.h" +#include "mirror/dex_cache-inl.h" +#include "mirror/field-inl.h" +#include "mirror/iftable-inl.h" +#include "mirror/abstract_method.h" +#include "mirror/abstract_method-inl.h" +#include "mirror/object-inl.h" +#include "mirror/object_array-inl.h" +#include "mirror/proxy.h" +#include "mirror/stack_trace_element.h" +#include "object_utils.h" +#include "os.h" +#include "runtime.h" +#include "runtime_support.h" +#if defined(ART_USE_PORTABLE_COMPILER) +#include "runtime_support_llvm.h" +#endif +#include "ScopedLocalRef.h" +#include "scoped_thread_state_change.h" +#include "sirt_ref.h" +#include "stack_indirect_reference_table.h" +#include "thread.h" +#include "UniquePtr.h" +#include "utils.h" +#include "verifier/method_verifier.h" +#include "well_known_classes.h" + +namespace art { + +extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh, + const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, JValue* result); + +static void ThrowNoClassDefFoundError(const char* fmt, ...) + __attribute__((__format__(__printf__, 1, 2))) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +static void ThrowNoClassDefFoundError(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + Thread* self = Thread::Current(); + ThrowLocation throw_location = self->GetCurrentLocationForThrow(); + self->ThrowNewExceptionV(throw_location, "Ljava/lang/NoClassDefFoundError;", fmt, args); + va_end(args); +} + +static void ThrowEarlierClassFailure(mirror::Class* c) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + // 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. + if (!Runtime::Current()->IsCompiler()) { // Give info if this occurs at runtime. + LOG(INFO) << "Rejecting re-init on previously-failed class " << PrettyClass(c); + } + + CHECK(c->IsErroneous()) << PrettyClass(c) << " " << c->GetStatus(); + Thread* self = Thread::Current(); + ThrowLocation throw_location = self->GetCurrentLocationForThrow(); + if (c->GetVerifyErrorClass() != NULL) { + // TODO: change the verifier to store an _instance_, with a useful detail message? + ClassHelper ve_ch(c->GetVerifyErrorClass()); + self->ThrowNewException(throw_location, ve_ch.GetDescriptor(), PrettyDescriptor(c).c_str()); + } else { + self->ThrowNewException(throw_location, "Ljava/lang/NoClassDefFoundError;", + PrettyDescriptor(c).c_str()); + } +} + +static void WrapExceptionInInitializer() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Thread* self = Thread::Current(); + JNIEnv* env = self->GetJniEnv(); + + ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred()); + CHECK(cause.get() != NULL); + + 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) { + ThrowLocation throw_location = self->GetCurrentLocationForThrow(); + self->ThrowNewWrappedException(throw_location, "Ljava/lang/ExceptionInInitializerError;", NULL); + } +} + +static size_t Hash(const char* s) { + // This is the java.lang.String hashcode for convenience, not interoperability. + size_t hash = 0; + for (; *s != '\0'; ++s) { + hash = hash * 31 + *s; + } + return hash; +} + +const char* ClassLinker::class_roots_descriptors_[] = { + "Ljava/lang/Class;", + "Ljava/lang/Object;", + "[Ljava/lang/Class;", + "[Ljava/lang/Object;", + "Ljava/lang/String;", + "Ljava/lang/DexCache;", + "Ljava/lang/ref/Reference;", + "Ljava/lang/reflect/Constructor;", + "Ljava/lang/reflect/Field;", + "Ljava/lang/reflect/AbstractMethod;", + "Ljava/lang/reflect/Method;", + "Ljava/lang/reflect/Proxy;", + "[Ljava/lang/String;", + "[Ljava/lang/reflect/AbstractMethod;", + "[Ljava/lang/reflect/Field;", + "[Ljava/lang/reflect/Method;", + "Ljava/lang/ClassLoader;", + "Ljava/lang/Throwable;", + "Ljava/lang/ClassNotFoundException;", + "Ljava/lang/StackTraceElement;", + "Z", + "B", + "C", + "D", + "F", + "I", + "J", + "S", + "V", + "[Z", + "[B", + "[C", + "[D", + "[F", + "[I", + "[J", + "[S", + "[Ljava/lang/StackTraceElement;", +}; + +ClassLinker* ClassLinker::CreateFromCompiler(const std::vector<const DexFile*>& boot_class_path, + InternTable* intern_table) { + CHECK_NE(boot_class_path.size(), 0U); + UniquePtr<ClassLinker> class_linker(new ClassLinker(intern_table)); + class_linker->InitFromCompiler(boot_class_path); + return class_linker.release(); +} + +ClassLinker* ClassLinker::CreateFromImage(InternTable* intern_table) { + UniquePtr<ClassLinker> class_linker(new ClassLinker(intern_table)); + class_linker->InitFromImage(); + return class_linker.release(); +} + +ClassLinker::ClassLinker(InternTable* intern_table) + // dex_lock_ is recursive as it may be used in stack dumping. + : dex_lock_("ClassLinker dex lock", kDefaultMutexLevel), + class_roots_(NULL), + array_iftable_(NULL), + init_done_(false), + is_dirty_(false), + intern_table_(intern_table), + portable_resolution_trampoline_(NULL), + quick_resolution_trampoline_(NULL) { + CHECK_EQ(arraysize(class_roots_descriptors_), size_t(kClassRootsMax)); +} + +void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class_path) { + VLOG(startup) << "ClassLinker::Init"; + CHECK(Runtime::Current()->IsCompiler()); + + CHECK(!init_done_); + + // java_lang_Class comes first, it's needed for AllocClass + Thread* self = Thread::Current(); + gc::Heap* heap = Runtime::Current()->GetHeap(); + SirtRef<mirror::Class> + java_lang_Class(self, + down_cast<mirror::Class*>(heap->AllocObject(self, NULL, + sizeof(mirror::ClassClass)))); + CHECK(java_lang_Class.get() != NULL); + mirror::Class::SetClassClass(java_lang_Class.get()); + java_lang_Class->SetClass(java_lang_Class.get()); + java_lang_Class->SetClassSize(sizeof(mirror::ClassClass)); + // AllocClass(mirror::Class*) can now be used + + // Class[] is used for reflection support. + SirtRef<mirror::Class> class_array_class(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class))); + class_array_class->SetComponentType(java_lang_Class.get()); + + // java_lang_Object comes next so that object_array_class can be created. + SirtRef<mirror::Class> java_lang_Object(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class))); + CHECK(java_lang_Object.get() != NULL); + // backfill Object as the super class of Class. + java_lang_Class->SetSuperClass(java_lang_Object.get()); + java_lang_Object->SetStatus(mirror::Class::kStatusLoaded); + + // Object[] next to hold class roots. + SirtRef<mirror::Class> object_array_class(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class))); + object_array_class->SetComponentType(java_lang_Object.get()); + + // Setup the char class to be used for char[]. + SirtRef<mirror::Class> char_class(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class))); + + // Setup the char[] class to be used for String. + SirtRef<mirror::Class> char_array_class(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class))); + char_array_class->SetComponentType(char_class.get()); + mirror::CharArray::SetArrayClass(char_array_class.get()); + + // Setup String. + SirtRef<mirror::Class> java_lang_String(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::StringClass))); + mirror::String::SetClass(java_lang_String.get()); + java_lang_String->SetObjectSize(sizeof(mirror::String)); + java_lang_String->SetStatus(mirror::Class::kStatusResolved); + + // Create storage for root classes, save away our work so far (requires descriptors). + class_roots_ = mirror::ObjectArray<mirror::Class>::Alloc(self, object_array_class.get(), kClassRootsMax); + CHECK(class_roots_ != NULL); + 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()); + + // 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_ = AllocIfTable(self, 2); + + // Create int array type for AllocDexCache (done in AppendToBootClassPath). + SirtRef<mirror::Class> int_array_class(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class))); + int_array_class->SetComponentType(GetClassRoot(kPrimitiveInt)); + mirror::IntArray::SetArrayClass(int_array_class.get()); + SetClassRoot(kIntArrayClass, int_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. + SirtRef<mirror::Class> + java_lang_DexCache(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::DexCacheClass))); + SetClassRoot(kJavaLangDexCache, java_lang_DexCache.get()); + java_lang_DexCache->SetObjectSize(sizeof(mirror::DexCacheClass)); + java_lang_DexCache->SetStatus(mirror::Class::kStatusResolved); + + // Constructor, Field, Method, and AbstractMethod are necessary so that FindClass can link members. + SirtRef<mirror::Class> java_lang_reflect_Field(self, AllocClass(self, java_lang_Class.get(), + sizeof(mirror::FieldClass))); + CHECK(java_lang_reflect_Field.get() != NULL); + java_lang_reflect_Field->SetObjectSize(sizeof(mirror::Field)); + SetClassRoot(kJavaLangReflectField, java_lang_reflect_Field.get()); + java_lang_reflect_Field->SetStatus(mirror::Class::kStatusResolved); + mirror::Field::SetClass(java_lang_reflect_Field.get()); + + SirtRef<mirror::Class> java_lang_reflect_AbstractMethod(self, AllocClass(self, java_lang_Class.get(), + sizeof(mirror::AbstractMethodClass))); + CHECK(java_lang_reflect_AbstractMethod.get() != NULL); + java_lang_reflect_AbstractMethod->SetObjectSize(sizeof(mirror::AbstractMethod)); + SetClassRoot(kJavaLangReflectAbstractMethod, java_lang_reflect_AbstractMethod.get()); + java_lang_reflect_AbstractMethod->SetStatus(mirror::Class::kStatusResolved); + + SirtRef<mirror::Class> java_lang_reflect_Constructor(self, AllocClass(self, java_lang_Class.get(), + sizeof(mirror::AbstractMethodClass))); + CHECK(java_lang_reflect_Constructor.get() != NULL); + java_lang_reflect_Constructor->SetObjectSize(sizeof(mirror::Constructor)); + java_lang_reflect_Constructor->SetSuperClass(java_lang_reflect_AbstractMethod.get()); + SetClassRoot(kJavaLangReflectConstructor, java_lang_reflect_Constructor.get()); + java_lang_reflect_Constructor->SetStatus(mirror::Class::kStatusResolved); + + SirtRef<mirror::Class> java_lang_reflect_Method(self, AllocClass(self, java_lang_Class.get(), + sizeof(mirror::AbstractMethodClass))); + CHECK(java_lang_reflect_Method.get() != NULL); + java_lang_reflect_Method->SetObjectSize(sizeof(mirror::Method)); + java_lang_reflect_Method->SetSuperClass(java_lang_reflect_AbstractMethod.get()); + SetClassRoot(kJavaLangReflectMethod, java_lang_reflect_Method.get()); + java_lang_reflect_Method->SetStatus(mirror::Class::kStatusResolved); + + mirror::AbstractMethod::SetClasses(java_lang_reflect_Constructor.get(), + java_lang_reflect_Method.get()); + + // Set up array classes for string, field, method + SirtRef<mirror::Class> object_array_string(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class))); + object_array_string->SetComponentType(java_lang_String.get()); + SetClassRoot(kJavaLangStringArrayClass, object_array_string.get()); + + SirtRef<mirror::Class> object_array_abstract_method(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class))); + object_array_abstract_method->SetComponentType(java_lang_reflect_AbstractMethod.get()); + SetClassRoot(kJavaLangReflectAbstractMethodArrayClass, object_array_abstract_method.get()); + + SirtRef<mirror::Class> object_array_field(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class))); + object_array_field->SetComponentType(java_lang_reflect_Field.get()); + SetClassRoot(kJavaLangReflectFieldArrayClass, object_array_field.get()); + + SirtRef<mirror::Class> object_array_method(self, AllocClass(self, java_lang_Class.get(), sizeof(mirror::Class))); + object_array_method->SetComponentType(java_lang_reflect_Method.get()); + SetClassRoot(kJavaLangReflectMethodArrayClass, object_array_method.get()); + + // 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. + CHECK_NE(0U, boot_class_path.size()); + for (size_t i = 0; i != boot_class_path.size(); ++i) { + const DexFile* dex_file = boot_class_path[i]; + CHECK(dex_file != NULL); + AppendToBootClassPath(*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 + + // Object, String and DexCache need to be rerun through FindSystemClass to finish init + java_lang_Object->SetStatus(mirror::Class::kStatusNotReady); + mirror::Class* Object_class = FindSystemClass("Ljava/lang/Object;"); + CHECK_EQ(java_lang_Object.get(), Object_class); + CHECK_EQ(java_lang_Object->GetObjectSize(), sizeof(mirror::Object)); + java_lang_String->SetStatus(mirror::Class::kStatusNotReady); + mirror::Class* String_class = FindSystemClass("Ljava/lang/String;"); + CHECK_EQ(java_lang_String.get(), String_class); + CHECK_EQ(java_lang_String->GetObjectSize(), sizeof(mirror::String)); + java_lang_DexCache->SetStatus(mirror::Class::kStatusNotReady); + mirror::Class* DexCache_class = FindSystemClass("Ljava/lang/DexCache;"); + CHECK_EQ(java_lang_String.get(), String_class); + CHECK_EQ(java_lang_DexCache.get(), DexCache_class); + CHECK_EQ(java_lang_DexCache->GetObjectSize(), sizeof(mirror::DexCache)); + + // Setup the primitive array type classes - can't be done until Object has a vtable. + SetClassRoot(kBooleanArrayClass, FindSystemClass("[Z")); + mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass)); + + SetClassRoot(kByteArrayClass, FindSystemClass("[B")); + mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass)); + + mirror::Class* found_char_array_class = FindSystemClass("[C"); + CHECK_EQ(char_array_class.get(), found_char_array_class); + + SetClassRoot(kShortArrayClass, FindSystemClass("[S")); + mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass)); + + mirror::Class* found_int_array_class = FindSystemClass("[I"); + CHECK_EQ(int_array_class.get(), found_int_array_class); + + SetClassRoot(kLongArrayClass, FindSystemClass("[J")); + mirror::LongArray::SetArrayClass(GetClassRoot(kLongArrayClass)); + + SetClassRoot(kFloatArrayClass, FindSystemClass("[F")); + mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass)); + + SetClassRoot(kDoubleArrayClass, FindSystemClass("[D")); + mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass)); + + mirror::Class* found_class_array_class = FindSystemClass("[Ljava/lang/Class;"); + CHECK_EQ(class_array_class.get(), found_class_array_class); + + mirror::Class* found_object_array_class = FindSystemClass("[Ljava/lang/Object;"); + CHECK_EQ(object_array_class.get(), found_object_array_class); + + // Setup the single, global copy of "iftable". + mirror::Class* java_lang_Cloneable = FindSystemClass("Ljava/lang/Cloneable;"); + CHECK(java_lang_Cloneable != NULL); + mirror::Class* java_io_Serializable = FindSystemClass("Ljava/io/Serializable;"); + CHECK(java_io_Serializable != NULL); + // 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_->SetInterface(0, java_lang_Cloneable); + array_iftable_->SetInterface(1, java_io_Serializable); + + // Sanity check Class[] and Object[]'s interfaces. + ClassHelper kh(class_array_class.get(), this); + CHECK_EQ(java_lang_Cloneable, kh.GetDirectInterface(0)); + CHECK_EQ(java_io_Serializable, kh.GetDirectInterface(1)); + kh.ChangeClass(object_array_class.get()); + CHECK_EQ(java_lang_Cloneable, kh.GetDirectInterface(0)); + CHECK_EQ(java_io_Serializable, kh.GetDirectInterface(1)); + // Run Class, Constructor, Field, and Method through FindSystemClass. This initializes their + // dex_cache_ fields and register them in classes_. + mirror::Class* Class_class = FindSystemClass("Ljava/lang/Class;"); + CHECK_EQ(java_lang_Class.get(), Class_class); + + java_lang_reflect_AbstractMethod->SetStatus(mirror::Class::kStatusNotReady); + mirror::Class* Abstract_method_class = FindSystemClass("Ljava/lang/reflect/AbstractMethod;"); + CHECK_EQ(java_lang_reflect_AbstractMethod.get(), Abstract_method_class); + + // Method extends AbstractMethod so must reset after. + java_lang_reflect_Method->SetStatus(mirror::Class::kStatusNotReady); + mirror::Class* Method_class = FindSystemClass("Ljava/lang/reflect/Method;"); + CHECK_EQ(java_lang_reflect_Method.get(), Method_class); + + // Constructor extends AbstractMethod so must reset after. + java_lang_reflect_Constructor->SetStatus(mirror::Class::kStatusNotReady); + mirror::Class* Constructor_class = FindSystemClass("Ljava/lang/reflect/Constructor;"); + CHECK_EQ(java_lang_reflect_Constructor.get(), Constructor_class); + + java_lang_reflect_Field->SetStatus(mirror::Class::kStatusNotReady); + mirror::Class* Field_class = FindSystemClass("Ljava/lang/reflect/Field;"); + CHECK_EQ(java_lang_reflect_Field.get(), Field_class); + + mirror::Class* String_array_class = FindSystemClass(class_roots_descriptors_[kJavaLangStringArrayClass]); + CHECK_EQ(object_array_string.get(), String_array_class); + + mirror::Class* Abstract_method_array_class = + FindSystemClass(class_roots_descriptors_[kJavaLangReflectAbstractMethodArrayClass]); + CHECK_EQ(object_array_abstract_method.get(), Abstract_method_array_class); + + mirror::Class* Field_array_class = FindSystemClass(class_roots_descriptors_[kJavaLangReflectFieldArrayClass]); + CHECK_EQ(object_array_field.get(), Field_array_class); + + mirror::Class* Method_array_class = + FindSystemClass(class_roots_descriptors_[kJavaLangReflectMethodArrayClass]); + CHECK_EQ(object_array_method.get(), Method_array_class); + + // End of special init trickery, subsequent classes may be loaded via FindSystemClass. + + // Create java.lang.reflect.Proxy root. + mirror::Class* java_lang_reflect_Proxy = FindSystemClass("Ljava/lang/reflect/Proxy;"); + SetClassRoot(kJavaLangReflectProxy, java_lang_reflect_Proxy); + + // java.lang.ref classes need to be specially flagged, but otherwise are normal classes + mirror::Class* java_lang_ref_Reference = FindSystemClass("Ljava/lang/ref/Reference;"); + SetClassRoot(kJavaLangRefReference, java_lang_ref_Reference); + mirror::Class* java_lang_ref_FinalizerReference = FindSystemClass("Ljava/lang/ref/FinalizerReference;"); + java_lang_ref_FinalizerReference->SetAccessFlags( + java_lang_ref_FinalizerReference->GetAccessFlags() | + kAccClassIsReference | kAccClassIsFinalizerReference); + mirror::Class* java_lang_ref_PhantomReference = FindSystemClass("Ljava/lang/ref/PhantomReference;"); + java_lang_ref_PhantomReference->SetAccessFlags( + java_lang_ref_PhantomReference->GetAccessFlags() | + kAccClassIsReference | kAccClassIsPhantomReference); + mirror::Class* java_lang_ref_SoftReference = FindSystemClass("Ljava/lang/ref/SoftReference;"); + java_lang_ref_SoftReference->SetAccessFlags( + java_lang_ref_SoftReference->GetAccessFlags() | kAccClassIsReference); + mirror::Class* java_lang_ref_WeakReference = FindSystemClass("Ljava/lang/ref/WeakReference;"); + java_lang_ref_WeakReference->SetAccessFlags( + java_lang_ref_WeakReference->GetAccessFlags() | + kAccClassIsReference | kAccClassIsWeakReference); + + // Setup the ClassLoader, verifying the object_size_. + mirror::Class* java_lang_ClassLoader = FindSystemClass("Ljava/lang/ClassLoader;"); + CHECK_EQ(java_lang_ClassLoader->GetObjectSize(), sizeof(mirror::ClassLoader)); + SetClassRoot(kJavaLangClassLoader, java_lang_ClassLoader); + + // Set up java.lang.Throwable, java.lang.ClassNotFoundException, and + // java.lang.StackTraceElement as a convenience. + SetClassRoot(kJavaLangThrowable, FindSystemClass("Ljava/lang/Throwable;")); + mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable)); + SetClassRoot(kJavaLangClassNotFoundException, FindSystemClass("Ljava/lang/ClassNotFoundException;")); + SetClassRoot(kJavaLangStackTraceElement, FindSystemClass("Ljava/lang/StackTraceElement;")); + SetClassRoot(kJavaLangStackTraceElementArrayClass, FindSystemClass("[Ljava/lang/StackTraceElement;")); + mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement)); + + FinishInit(); + + VLOG(startup) << "ClassLinker::InitFromCompiler exiting"; +} + +void ClassLinker::FinishInit() { + 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_ReferenceQueue = FindSystemClass("Ljava/lang/ref/ReferenceQueue;"); + mirror::Class* java_lang_ref_FinalizerReference = FindSystemClass("Ljava/lang/ref/FinalizerReference;"); + + const DexFile& java_lang_dex = *java_lang_ref_Reference->GetDexCache()->GetDexFile(); + + mirror::Field* pendingNext = java_lang_ref_Reference->GetInstanceField(0); + FieldHelper fh(pendingNext, this); + CHECK_STREQ(fh.GetName(), "pendingNext"); + CHECK_EQ(java_lang_dex.GetFieldId(pendingNext->GetDexFieldIndex()).type_idx_, + java_lang_ref_Reference->GetDexTypeIndex()); + + mirror::Field* queue = java_lang_ref_Reference->GetInstanceField(1); + fh.ChangeField(queue); + CHECK_STREQ(fh.GetName(), "queue"); + CHECK_EQ(java_lang_dex.GetFieldId(queue->GetDexFieldIndex()).type_idx_, + java_lang_ref_ReferenceQueue->GetDexTypeIndex()); + + mirror::Field* queueNext = java_lang_ref_Reference->GetInstanceField(2); + fh.ChangeField(queueNext); + CHECK_STREQ(fh.GetName(), "queueNext"); + CHECK_EQ(java_lang_dex.GetFieldId(queueNext->GetDexFieldIndex()).type_idx_, + java_lang_ref_Reference->GetDexTypeIndex()); + + mirror::Field* referent = java_lang_ref_Reference->GetInstanceField(3); + fh.ChangeField(referent); + CHECK_STREQ(fh.GetName(), "referent"); + CHECK_EQ(java_lang_dex.GetFieldId(referent->GetDexFieldIndex()).type_idx_, + GetClassRoot(kJavaLangObject)->GetDexTypeIndex()); + + mirror::Field* zombie = java_lang_ref_FinalizerReference->GetInstanceField(2); + fh.ChangeField(zombie); + CHECK_STREQ(fh.GetName(), "zombie"); + CHECK_EQ(java_lang_dex.GetFieldId(zombie->GetDexFieldIndex()).type_idx_, + GetClassRoot(kJavaLangObject)->GetDexTypeIndex()); + + gc::Heap* heap = Runtime::Current()->GetHeap(); + heap->SetReferenceOffsets(referent->GetOffset(), + queue->GetOffset(), + queueNext->GetOffset(), + pendingNext->GetOffset(), + zombie->GetOffset()); + + // ensure all class_roots_ are initialized + for (size_t i = 0; i < kClassRootsMax; i++) { + ClassRoot class_root = static_cast<ClassRoot>(i); + mirror::Class* klass = GetClassRoot(class_root); + CHECK(klass != NULL); + DCHECK(klass->IsArrayClass() || klass->IsPrimitive() || klass->GetDexCache() != NULL); + // note SetClassRoot does additional validation. + // if possible add new checks there to catch errors early + } + + CHECK(array_iftable_ != NULL); + + // 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()) { + EnsureInitialized(GetClassRoot(ClassRoot(i)), true, true); + self->AssertNoPendingException(); + } + } +} + +bool ClassLinker::GenerateOatFile(const std::string& dex_filename, + int oat_fd, + const std::string& oat_cache_filename) { + std::string dex2oat_string(GetAndroidRoot()); + dex2oat_string += (kIsDebugBuild ? "/bin/dex2oatd" : "/bin/dex2oat"); + const char* dex2oat = dex2oat_string.c_str(); + + const char* class_path = Runtime::Current()->GetClassPathString().c_str(); + + gc::Heap* heap = Runtime::Current()->GetHeap(); + std::string boot_image_option_string("--boot-image="); + boot_image_option_string += heap->GetImageSpace()->GetImageFilename(); + const char* boot_image_option = boot_image_option_string.c_str(); + + std::string dex_file_option_string("--dex-file="); + dex_file_option_string += dex_filename; + const char* dex_file_option = dex_file_option_string.c_str(); + + std::string oat_fd_option_string("--oat-fd="); + StringAppendF(&oat_fd_option_string, "%d", oat_fd); + const char* oat_fd_option = oat_fd_option_string.c_str(); + + std::string oat_location_option_string("--oat-location="); + oat_location_option_string += oat_cache_filename; + const char* oat_location_option = oat_location_option_string.c_str(); + + // fork and exec dex2oat + pid_t pid = fork(); + if (pid == 0) { + // no allocation allowed between fork and exec + + // change process groups, so we don't get reaped by ProcessManager + setpgid(0, 0); + + VLOG(class_linker) << dex2oat + << " --runtime-arg -Xms64m" + << " --runtime-arg -Xmx64m" + << " --runtime-arg -classpath" + << " --runtime-arg " << class_path +#if !defined(ART_TARGET) + << " --host" +#endif + << " " << boot_image_option + << " " << dex_file_option + << " " << oat_fd_option + << " " << oat_location_option; + + execl(dex2oat, dex2oat, + "--runtime-arg", "-Xms64m", + "--runtime-arg", "-Xmx64m", + "--runtime-arg", "-classpath", + "--runtime-arg", class_path, +#if !defined(ART_TARGET) + "--host", +#endif + boot_image_option, + dex_file_option, + oat_fd_option, + oat_location_option, + NULL); + + PLOG(FATAL) << "execl(" << dex2oat << ") failed"; + return false; + } else { + // wait for dex2oat to finish + int status; + pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); + if (got_pid != pid) { + PLOG(ERROR) << "waitpid failed: wanted " << pid << ", got " << got_pid; + return false; + } + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + LOG(ERROR) << dex2oat << " failed with dex-file=" << dex_filename; + return false; + } + } + return true; +} + +void ClassLinker::RegisterOatFile(const OatFile& oat_file) { + WriterMutexLock mu(Thread::Current(), dex_lock_); + RegisterOatFileLocked(oat_file); +} + +void ClassLinker::RegisterOatFileLocked(const OatFile& oat_file) { + dex_lock_.AssertExclusiveHeld(Thread::Current()); + if (kIsDebugBuild) { + for (size_t i = 0; i < oat_files_.size(); ++i) { + CHECK_NE(&oat_file, oat_files_[i]) << oat_file.GetLocation(); + } + } + oat_files_.push_back(&oat_file); +} + +OatFile* ClassLinker::OpenOat(const gc::space::ImageSpace* space) { + WriterMutexLock mu(Thread::Current(), dex_lock_); + const Runtime* runtime = Runtime::Current(); + const ImageHeader& image_header = space->GetImageHeader(); + // Grab location but don't use Object::AsString as we haven't yet initialized the roots to + // check the down cast + mirror::String* oat_location = + down_cast<mirror::String*>(image_header.GetImageRoot(ImageHeader::kOatLocation)); + std::string oat_filename; + oat_filename += runtime->GetHostPrefix(); + oat_filename += oat_location->ToModifiedUtf8(); + runtime->GetHeap()->UnReserveOatFileAddressRange(); + OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, image_header.GetOatDataBegin()); + VLOG(startup) << "ClassLinker::OpenOat entering oat_filename=" << oat_filename; + if (oat_file == NULL) { + LOG(ERROR) << "Failed to open oat file " << oat_filename << " referenced from image."; + return NULL; + } + uint32_t oat_checksum = oat_file->GetOatHeader().GetChecksum(); + uint32_t image_oat_checksum = image_header.GetOatChecksum(); + if (oat_checksum != image_oat_checksum) { + LOG(ERROR) << "Failed to match oat file checksum " << std::hex << oat_checksum + << " to expected oat checksum " << std::hex << image_oat_checksum + << " in image"; + return NULL; + } + RegisterOatFileLocked(*oat_file); + VLOG(startup) << "ClassLinker::OpenOat exiting"; + return oat_file; +} + +const OatFile* ClassLinker::FindOpenedOatFileForDexFile(const DexFile& dex_file) { + ReaderMutexLock mu(Thread::Current(), dex_lock_); + return FindOpenedOatFileFromDexLocation(dex_file.GetLocation()); +} + +const OatFile* ClassLinker::FindOpenedOatFileFromDexLocation(const std::string& dex_location) { + for (size_t i = 0; i < oat_files_.size(); i++) { + const OatFile* oat_file = oat_files_[i]; + DCHECK(oat_file != NULL); + const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location, false); + if (oat_dex_file != NULL) { + return oat_file; + } + } + return NULL; +} + +const DexFile* ClassLinker::FindDexFileInOatLocation(const std::string& dex_location, + uint32_t dex_location_checksum, + const std::string& oat_location) { + UniquePtr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, NULL)); + if (oat_file.get() == NULL) { + return NULL; + } + Runtime* runtime = Runtime::Current(); + const ImageHeader& image_header = runtime->GetHeap()->GetImageSpace()->GetImageHeader(); + if (oat_file->GetOatHeader().GetImageFileLocationOatChecksum() != image_header.GetOatChecksum()) { + return NULL; + } + if (oat_file->GetOatHeader().GetImageFileLocationOatDataBegin() + != reinterpret_cast<uint32_t>(image_header.GetOatDataBegin())) { + return NULL; + } + const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location); + if (oat_dex_file == NULL) { + return NULL; + } + if (oat_dex_file->GetDexFileLocationChecksum() != dex_location_checksum) { + return NULL; + } + RegisterOatFileLocked(*oat_file.release()); + return oat_dex_file->OpenDexFile(); +} + +const DexFile* ClassLinker::FindOrCreateOatFileForDexLocation(const std::string& dex_location, + const std::string& oat_location) { + WriterMutexLock mu(Thread::Current(), dex_lock_); + return FindOrCreateOatFileForDexLocationLocked(dex_location, oat_location); +} + +const DexFile* ClassLinker::FindOrCreateOatFileForDexLocationLocked(const std::string& dex_location, + const std::string& oat_location) { + uint32_t dex_location_checksum; + if (!DexFile::GetChecksum(dex_location, dex_location_checksum)) { + LOG(ERROR) << "Failed to compute checksum '" << dex_location << "'"; + return NULL; + } + + // Check if we already have an up-to-date output file + const DexFile* dex_file = FindDexFileInOatLocation(dex_location, + dex_location_checksum, + oat_location); + if (dex_file != NULL) { + return dex_file; + } + + // Generate the output oat file for the dex file + UniquePtr<File> file(OS::OpenFile(oat_location.c_str(), true)); + if (file.get() == NULL) { + LOG(ERROR) << "Failed to create oat file: " << oat_location; + return NULL; + } + if (!GenerateOatFile(dex_location, file->Fd(), oat_location)) { + LOG(ERROR) << "Failed to generate oat file: " << oat_location; + return NULL; + } + const OatFile* oat_file = OatFile::Open(oat_location, oat_location, NULL); + if (oat_file == NULL) { + LOG(ERROR) << "Failed to open generated oat file: " << oat_location; + return NULL; + } + RegisterOatFileLocked(*oat_file); + const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location); + if (oat_dex_file == NULL) { + LOG(ERROR) << "Failed to find dex file in generated oat file: " << oat_location; + return NULL; + } + return oat_dex_file->OpenDexFile(); +} + +bool ClassLinker::VerifyOatFileChecksums(const OatFile* oat_file, + const std::string& dex_location, + uint32_t dex_location_checksum) { + Runtime* runtime = Runtime::Current(); + const ImageHeader& image_header = runtime->GetHeap()->GetImageSpace()->GetImageHeader(); + uint32_t image_oat_checksum = image_header.GetOatChecksum(); + uint32_t image_oat_data_begin = reinterpret_cast<uint32_t>(image_header.GetOatDataBegin()); + bool image_check = ((oat_file->GetOatHeader().GetImageFileLocationOatChecksum() == image_oat_checksum) + && (oat_file->GetOatHeader().GetImageFileLocationOatDataBegin() == image_oat_data_begin)); + + const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location); + if (oat_dex_file == NULL) { + LOG(ERROR) << "oat file " << oat_file->GetLocation() + << " does not contain contents for " << dex_location; + std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file->GetOatDexFiles(); + for (size_t i = 0; i < oat_dex_files.size(); i++) { + const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i]; + LOG(ERROR) << "oat file " << oat_file->GetLocation() + << " contains contents for " << oat_dex_file->GetDexFileLocation(); + } + return false; + } + bool dex_check = dex_location_checksum == oat_dex_file->GetDexFileLocationChecksum(); + + if (image_check && dex_check) { + return true; + } + + if (!image_check) { + std::string image_file(image_header.GetImageRoot( + ImageHeader::kOatLocation)->AsString()->ToModifiedUtf8()); + LOG(WARNING) << "oat file " << oat_file->GetLocation() + << " mismatch ( " << std::hex << oat_file->GetOatHeader().GetImageFileLocationOatChecksum() + << ", " << oat_file->GetOatHeader().GetImageFileLocationOatDataBegin() + << ") with " << image_file + << " (" << image_oat_checksum << ", " << std::hex << image_oat_data_begin << ")"; + } + if (!dex_check) { + LOG(WARNING) << "oat file " << oat_file->GetLocation() + << " mismatch ( " << std::hex << oat_dex_file->GetDexFileLocationChecksum() + << ") with " << dex_location + << " (" << std::hex << dex_location_checksum << ")"; + } + return false; +} + +const DexFile* ClassLinker::VerifyAndOpenDexFileFromOatFile(const OatFile* oat_file, + const std::string& dex_location, + uint32_t dex_location_checksum) { + bool verified = VerifyOatFileChecksums(oat_file, dex_location, dex_location_checksum); + if (!verified) { + return NULL; + } + RegisterOatFileLocked(*oat_file); + return oat_file->GetOatDexFile(dex_location)->OpenDexFile(); +} + +const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const std::string& dex_location) { + WriterMutexLock mu(Thread::Current(), dex_lock_); + + const OatFile* open_oat_file = FindOpenedOatFileFromDexLocation(dex_location); + if (open_oat_file != NULL) { + return open_oat_file->GetOatDexFile(dex_location)->OpenDexFile(); + } + + // Look for an existing file next to dex. for example, for + // /foo/bar/baz.jar, look for /foo/bar/baz.odex. + std::string odex_filename(OatFile::DexFilenameToOdexFilename(dex_location)); + const OatFile* oat_file = FindOatFileFromOatLocationLocked(odex_filename); + if (oat_file != NULL) { + uint32_t dex_location_checksum; + if (!DexFile::GetChecksum(dex_location, dex_location_checksum)) { + // If no classes.dex found in dex_location, it has been stripped, assume oat is up-to-date. + // This is the common case in user builds for jar's and apk's in the /system directory. + const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location); + CHECK(oat_dex_file != NULL) << odex_filename << " " << dex_location; + RegisterOatFileLocked(*oat_file); + return oat_dex_file->OpenDexFile(); + } + const DexFile* dex_file = VerifyAndOpenDexFileFromOatFile(oat_file, + dex_location, + dex_location_checksum); + if (dex_file != NULL) { + return dex_file; + } + } + // Look for an existing file in the dalvik-cache, validating the result if found + // not found in /foo/bar/baz.odex? try /data/dalvik-cache/foo@bar@baz.jar@classes.dex + std::string cache_location(GetDalvikCacheFilenameOrDie(dex_location)); + oat_file = FindOatFileFromOatLocationLocked(cache_location); + if (oat_file != NULL) { + uint32_t dex_location_checksum; + if (!DexFile::GetChecksum(dex_location, dex_location_checksum)) { + LOG(WARNING) << "Failed to compute checksum: " << dex_location; + return NULL; + } + const DexFile* dex_file = VerifyAndOpenDexFileFromOatFile(oat_file, + dex_location, + dex_location_checksum); + if (dex_file != NULL) { + return dex_file; + } + if (TEMP_FAILURE_RETRY(unlink(oat_file->GetLocation().c_str())) != 0) { + PLOG(FATAL) << "Failed to remove obsolete oat file " << oat_file->GetLocation(); + } + } + LOG(INFO) << "Failed to open oat file from " << odex_filename << " or " << cache_location << "."; + + // Try to generate oat file if it wasn't found or was obsolete. + std::string oat_cache_filename(GetDalvikCacheFilenameOrDie(dex_location)); + return FindOrCreateOatFileForDexLocationLocked(dex_location, oat_cache_filename); +} + +const OatFile* ClassLinker::FindOpenedOatFileFromOatLocation(const std::string& oat_location) { + for (size_t i = 0; i < oat_files_.size(); i++) { + const OatFile* oat_file = oat_files_[i]; + DCHECK(oat_file != NULL); + if (oat_file->GetLocation() == oat_location) { + return oat_file; + } + } + return NULL; +} + +const OatFile* ClassLinker::FindOatFileFromOatLocation(const std::string& oat_location) { + ReaderMutexLock mu(Thread::Current(), dex_lock_); + return FindOatFileFromOatLocationLocked(oat_location); +} + +const OatFile* ClassLinker::FindOatFileFromOatLocationLocked(const std::string& oat_location) { + const OatFile* oat_file = FindOpenedOatFileFromOatLocation(oat_location); + if (oat_file != NULL) { + return oat_file; + } + + oat_file = OatFile::Open(oat_location, oat_location, NULL); + if (oat_file == NULL) { + return NULL; + } + return oat_file; +} + +void ClassLinker::InitFromImage() { + VLOG(startup) << "ClassLinker::InitFromImage entering"; + CHECK(!init_done_); + + gc::Heap* heap = Runtime::Current()->GetHeap(); + gc::space::ImageSpace* space = heap->GetImageSpace(); + OatFile* oat_file = OpenOat(space); + CHECK(oat_file != NULL) << "Failed to open oat file for image"; + CHECK_EQ(oat_file->GetOatHeader().GetImageFileLocationOatChecksum(), 0U); + CHECK_EQ(oat_file->GetOatHeader().GetImageFileLocationOatDataBegin(), 0U); + CHECK(oat_file->GetOatHeader().GetImageFileLocation().empty()); + portable_resolution_trampoline_ = oat_file->GetOatHeader().GetPortableResolutionTrampoline(); + quick_resolution_trampoline_ = oat_file->GetOatHeader().GetQuickResolutionTrampoline(); + mirror::Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches); + mirror::ObjectArray<mirror::DexCache>* dex_caches = + dex_caches_object->AsObjectArray<mirror::DexCache>(); + + mirror::ObjectArray<mirror::Class>* class_roots = + space->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)->AsObjectArray<mirror::Class>(); + class_roots_ = class_roots; + + // 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)); + + CHECK_EQ(oat_file->GetOatHeader().GetDexFileCount(), + static_cast<uint32_t>(dex_caches->GetLength())); + Thread* self = Thread::Current(); + for (int i = 0; i < dex_caches->GetLength(); i++) { + SirtRef<mirror::DexCache> dex_cache(self, dex_caches->Get(i)); + const std::string& dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8()); + const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file_location); + CHECK(oat_dex_file != NULL) << oat_file->GetLocation() << " " << dex_file_location; + const DexFile* dex_file = oat_dex_file->OpenDexFile(); + if (dex_file == NULL) { + LOG(FATAL) << "Failed to open dex file " << dex_file_location + << " from within oat file " << oat_file->GetLocation(); + } + + CHECK_EQ(dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum()); + + AppendToBootClassPath(*dex_file, dex_cache); + } + + // Set classes on AbstractMethod early so that IsMethod tests can be performed during the live + // bitmap walk. + mirror::AbstractMethod::SetClasses(GetClassRoot(kJavaLangReflectConstructor), + GetClassRoot(kJavaLangReflectMethod)); + + // reinit clases_ table + { + ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_); + heap->FlushAllocStack(); + heap->GetLiveBitmap()->Walk(InitFromImageCallback, this); + } + + // reinit class_roots_ + mirror::Class::SetClassClass(class_roots->Get(kJavaLangClass)); + class_roots_ = class_roots; + + // reinit array_iftable_ from any array class instance, they should be == + array_iftable_ = GetClassRoot(kObjectArrayClass)->GetIfTable(); + DCHECK(array_iftable_ == GetClassRoot(kBooleanArrayClass)->GetIfTable()); + // String class root was set above + mirror::Field::SetClass(GetClassRoot(kJavaLangReflectField)); + 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)); + + FinishInit(); + + VLOG(startup) << "ClassLinker::InitFromImage exiting"; +} + +void ClassLinker::InitFromImageCallback(mirror::Object* obj, void* arg) { + DCHECK(obj != NULL); + DCHECK(arg != NULL); + ClassLinker* class_linker = reinterpret_cast<ClassLinker*>(arg); + + if (obj->GetClass()->IsStringClass()) { + class_linker->intern_table_->RegisterStrong(obj->AsString()); + return; + } + if (obj->IsClass()) { + // restore class to ClassLinker::classes_ table + mirror::Class* klass = obj->AsClass(); + ClassHelper kh(klass, class_linker); + mirror::Class* existing = class_linker->InsertClass(kh.GetDescriptor(), klass, true); + DCHECK(existing == NULL) << kh.GetDescriptor(); + return; + } + + // Set entry points to interpreter for methods in interpreter only mode. + if (obj->IsMethod()) { + mirror::AbstractMethod* method = obj->AsMethod(); + if (Runtime::Current()->GetInstrumentation()->InterpretOnly() && !method->IsNative()) { + method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterEntry); + if (method != Runtime::Current()->GetResolutionMethod()) { + method->SetEntryPointFromCompiledCode(GetInterpreterEntryPoint()); + } + } + } +} + +// 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, void* arg, bool clean_dirty) { + visitor(class_roots_, arg); + Thread* self = Thread::Current(); + { + ReaderMutexLock mu(self, dex_lock_); + for (size_t i = 0; i < dex_caches_.size(); i++) { + visitor(dex_caches_[i], arg); + } + } + + { + ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_); + typedef Table::const_iterator It; // TODO: C++0x auto + for (It it = classes_.begin(), end = classes_.end(); it != end; ++it) { + visitor(it->second, arg); + } + + // We deliberately ignore the class roots in the image since we + // handle image roots by using the MS/CMS rescanning of dirty cards. + } + + visitor(array_iftable_, arg); + if (clean_dirty) { + is_dirty_ = false; + } +} + +void ClassLinker::VisitClasses(ClassVisitor* visitor, void* arg) const { + ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + typedef Table::const_iterator It; // TODO: C++0x auto + for (It it = classes_.begin(), end = classes_.end(); it != end; ++it) { + if (!visitor(it->second, arg)) { + return; + } + } + for (It it = image_classes_.begin(), end = image_classes_.end(); it != end; ++it) { + if (!visitor(it->second, arg)) { + return; + } + } +} + +static bool GetClassesVisitor(mirror::Class* c, void* arg) { + std::set<mirror::Class*>* classes = reinterpret_cast<std::set<mirror::Class*>*>(arg); + classes->insert(c); + return true; +} + +void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor, void* arg) const { + std::set<mirror::Class*> classes; + VisitClasses(GetClassesVisitor, &classes); + typedef std::set<mirror::Class*>::const_iterator It; // TODO: C++0x auto + for (It it = classes.begin(), end = classes.end(); it != end; ++it) { + if (!visitor(*it, arg)) { + return; + } + } +} + + +ClassLinker::~ClassLinker() { + mirror::Class::ResetClass(); + mirror::String::ResetClass(); + mirror::Field::ResetClass(); + mirror::AbstractMethod::ResetClasses(); + mirror::BooleanArray::ResetArrayClass(); + mirror::ByteArray::ResetArrayClass(); + mirror::CharArray::ResetArrayClass(); + mirror::DoubleArray::ResetArrayClass(); + mirror::FloatArray::ResetArrayClass(); + mirror::IntArray::ResetArrayClass(); + mirror::LongArray::ResetArrayClass(); + mirror::ShortArray::ResetArrayClass(); + mirror::Throwable::ResetClass(); + mirror::StackTraceElement::ResetClass(); + STLDeleteElements(&boot_class_path_); + STLDeleteElements(&oat_files_); +} + +mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, const DexFile& dex_file) { + gc::Heap* heap = Runtime::Current()->GetHeap(); + mirror::Class* dex_cache_class = GetClassRoot(kJavaLangDexCache); + SirtRef<mirror::DexCache> dex_cache(self, + down_cast<mirror::DexCache*>(heap->AllocObject(self, dex_cache_class, + dex_cache_class->GetObjectSize()))); + if (dex_cache.get() == NULL) { + return NULL; + } + SirtRef<mirror::String> + location(self, intern_table_->InternStrong(dex_file.GetLocation().c_str())); + if (location.get() == NULL) { + return NULL; + } + SirtRef<mirror::ObjectArray<mirror::String> > + strings(self, AllocStringArray(self, dex_file.NumStringIds())); + if (strings.get() == NULL) { + return NULL; + } + SirtRef<mirror::ObjectArray<mirror::Class> > + types(self, AllocClassArray(self, dex_file.NumTypeIds())); + if (types.get() == NULL) { + return NULL; + } + SirtRef<mirror::ObjectArray<mirror::AbstractMethod> > + methods(self, AllocAbstractMethodArray(self, dex_file.NumMethodIds())); + if (methods.get() == NULL) { + return NULL; + } + SirtRef<mirror::ObjectArray<mirror::Field> > + fields(self, AllocFieldArray(self, dex_file.NumFieldIds())); + if (fields.get() == NULL) { + return NULL; + } + SirtRef<mirror::ObjectArray<mirror::StaticStorageBase> > + initialized_static_storage(self, + AllocObjectArray<mirror::StaticStorageBase>(self, dex_file.NumTypeIds())); + if (initialized_static_storage.get() == NULL) { + return NULL; + } + + dex_cache->Init(&dex_file, + location.get(), + strings.get(), + types.get(), + methods.get(), + fields.get(), + initialized_static_storage.get()); + return dex_cache.get(); +} + +mirror::Class* ClassLinker::AllocClass(Thread* self, mirror::Class* java_lang_Class, + size_t class_size) { + DCHECK_GE(class_size, sizeof(mirror::Class)); + gc::Heap* heap = Runtime::Current()->GetHeap(); + SirtRef<mirror::Class> klass(self, + heap->AllocObject(self, java_lang_Class, class_size)->AsClass()); + klass->SetPrimitiveType(Primitive::kPrimNot); // default to not being primitive + klass->SetClassSize(class_size); + return klass.get(); +} + +mirror::Class* ClassLinker::AllocClass(Thread* self, size_t class_size) { + return AllocClass(self, GetClassRoot(kJavaLangClass), class_size); +} + +mirror::Field* ClassLinker::AllocField(Thread* self) { + return down_cast<mirror::Field*>(GetClassRoot(kJavaLangReflectField)->AllocObject(self)); +} + +mirror::Method* ClassLinker::AllocMethod(Thread* self) { + return down_cast<mirror::Method*>(GetClassRoot(kJavaLangReflectMethod)->AllocObject(self)); +} + +mirror::Constructor* ClassLinker::AllocConstructor(Thread* self) { + return down_cast<mirror::Constructor*>(GetClassRoot(kJavaLangReflectConstructor)->AllocObject(self)); +} + +mirror::ObjectArray<mirror::StackTraceElement>* ClassLinker::AllocStackTraceElementArray(Thread* self, + size_t length) { + return mirror::ObjectArray<mirror::StackTraceElement>::Alloc(self, + GetClassRoot(kJavaLangStackTraceElementArrayClass), + length); +} + +static mirror::Class* EnsureResolved(Thread* self, mirror::Class* klass) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(klass != NULL); + // Wait for the class if it has not already been linked. + if (!klass->IsResolved() && !klass->IsErroneous()) { + ObjectLock lock(self, klass); + // Check for circular dependencies between classes. + if (!klass->IsResolved() && klass->GetClinitThreadId() == self->GetTid()) { + ThrowClassCircularityError(klass); + klass->SetStatus(mirror::Class::kStatusError); + return NULL; + } + // Wait for the pending initialization to complete. + while (!klass->IsResolved() && !klass->IsErroneous()) { + lock.WaitIgnoringInterrupts(); + } + } + if (klass->IsErroneous()) { + ThrowEarlierClassFailure(klass); + return NULL; + } + // Return the loaded class. No exceptions should be pending. + CHECK(klass->IsResolved()) << PrettyClass(klass); + self->AssertNoPendingException(); + return klass; +} + +mirror::Class* ClassLinker::FindSystemClass(const char* descriptor) { + return FindClass(descriptor, NULL); +} + +mirror::Class* ClassLinker::FindClass(const char* descriptor, mirror::ClassLoader* class_loader) { + DCHECK_NE(*descriptor, '\0') << "descriptor is empty string"; + Thread* self = Thread::Current(); + DCHECK(self != NULL); + 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]); + } + // Find the class in the loaded classes table. + mirror::Class* klass = LookupClass(descriptor, class_loader); + if (klass != NULL) { + return EnsureResolved(self, klass); + } + // Class is not yet loaded. + if (descriptor[0] == '[') { + return CreateArrayClass(descriptor, class_loader); + + } else if (class_loader == NULL) { + DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, boot_class_path_); + if (pair.second != NULL) { + return DefineClass(descriptor, NULL, *pair.first, *pair.second); + } + + } else if (Runtime::Current()->UseCompileTimeClassPath()) { + // first try the boot class path + mirror::Class* system_class = FindSystemClass(descriptor); + if (system_class != NULL) { + return system_class; + } + CHECK(self->IsExceptionPending()); + self->ClearException(); + + // next try the compile time class path + const std::vector<const DexFile*>* class_path; + { + ScopedObjectAccessUnchecked soa(Thread::Current()); + ScopedLocalRef<jobject> jclass_loader(soa.Env(), soa.AddLocalReference<jobject>(class_loader)); + class_path = &Runtime::Current()->GetCompileTimeClassPath(jclass_loader.get()); + } + + DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, *class_path); + if (pair.second != NULL) { + return DefineClass(descriptor, class_loader, *pair.first, *pair.second); + } + + } else { + ScopedObjectAccessUnchecked soa(self->GetJniEnv()); + ScopedLocalRef<jobject> class_loader_object(soa.Env(), + soa.AddLocalReference<jobject>(class_loader)); + std::string class_name_string(DescriptorToDot(descriptor)); + ScopedLocalRef<jobject> result(soa.Env(), NULL); + { + ScopedThreadStateChange tsc(self, kNative); + ScopedLocalRef<jobject> class_name_object(soa.Env(), + soa.Env()->NewStringUTF(class_name_string.c_str())); + if (class_name_object.get() == NULL) { + return NULL; + } + CHECK(class_loader_object.get() != NULL); + result.reset(soa.Env()->CallObjectMethod(class_loader_object.get(), + WellKnownClasses::java_lang_ClassLoader_loadClass, + class_name_object.get())); + } + if (soa.Self()->IsExceptionPending()) { + // If the ClassLoader threw, pass that exception up. + return NULL; + } else if (result.get() == NULL) { + // broken loader - throw NPE to be compatible with Dalvik + ThrowNullPointerException(NULL, StringPrintf("ClassLoader.loadClass returned null for %s", + class_name_string.c_str()).c_str()); + return NULL; + } else { + // success, return mirror::Class* + return soa.Decode<mirror::Class*>(result.get()); + } + } + + ThrowNoClassDefFoundError("Class %s not found", PrintableString(descriptor).c_str()); + return NULL; +} + +mirror::Class* ClassLinker::DefineClass(const StringPiece& descriptor, + mirror::ClassLoader* class_loader, + const DexFile& dex_file, + const DexFile::ClassDef& dex_class_def) { + Thread* self = Thread::Current(); + SirtRef<mirror::Class> klass(self, NULL); + // Load the class from the dex file. + if (!init_done_) { + // finish up init of hand crafted class_roots_ + if (descriptor == "Ljava/lang/Object;") { + klass.reset(GetClassRoot(kJavaLangObject)); + } else if (descriptor == "Ljava/lang/Class;") { + klass.reset(GetClassRoot(kJavaLangClass)); + } else if (descriptor == "Ljava/lang/String;") { + klass.reset(GetClassRoot(kJavaLangString)); + } else if (descriptor == "Ljava/lang/DexCache;") { + klass.reset(GetClassRoot(kJavaLangDexCache)); + } else if (descriptor == "Ljava/lang/reflect/Field;") { + klass.reset(GetClassRoot(kJavaLangReflectField)); + } else if (descriptor == "Ljava/lang/reflect/AbstractMethod;") { + klass.reset(GetClassRoot(kJavaLangReflectAbstractMethod)); + } else if (descriptor == "Ljava/lang/reflect/Constructor;") { + klass.reset(GetClassRoot(kJavaLangReflectConstructor)); + } else if (descriptor == "Ljava/lang/reflect/Method;") { + klass.reset(GetClassRoot(kJavaLangReflectMethod)); + } else { + klass.reset(AllocClass(self, SizeOfClass(dex_file, dex_class_def))); + } + } else { + klass.reset(AllocClass(self, SizeOfClass(dex_file, dex_class_def))); + } + klass->SetDexCache(FindDexCache(dex_file)); + LoadClass(dex_file, dex_class_def, klass, class_loader); + // Check for a pending exception during load + if (self->IsExceptionPending()) { + klass->SetStatus(mirror::Class::kStatusError); + return NULL; + } + ObjectLock lock(self, klass.get()); + klass->SetClinitThreadId(self->GetTid()); + // Add the newly loaded class to the loaded classes table. + SirtRef<mirror::Class> existing(self, InsertClass(descriptor, klass.get(), false)); + if (existing.get() != NULL) { + // We failed to insert because we raced with another thread. + return EnsureResolved(self, existing.get()); + } + // Finish loading (if necessary) by finding parents + CHECK(!klass->IsLoaded()); + if (!LoadSuperAndInterfaces(klass, dex_file)) { + // Loading failed. + klass->SetStatus(mirror::Class::kStatusError); + lock.NotifyAll(); + return NULL; + } + CHECK(klass->IsLoaded()); + // Link the class (if necessary) + CHECK(!klass->IsResolved()); + if (!LinkClass(klass, NULL)) { + // Linking failed. + klass->SetStatus(mirror::Class::kStatusError); + lock.NotifyAll(); + return NULL; + } + CHECK(klass->IsResolved()); + + /* + * 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(klass.get()); + + return klass.get(); +} + +// Precomputes size that will be needed for Class, matching LinkStaticFields +size_t ClassLinker::SizeOfClass(const DexFile& dex_file, + const DexFile::ClassDef& dex_class_def) { + const byte* class_data = dex_file.GetClassData(dex_class_def); + size_t num_ref = 0; + size_t num_32 = 0; + size_t num_64 = 0; + if (class_data != NULL) { + for (ClassDataItemIterator it(dex_file, class_data); it.HasNextStaticField(); it.Next()) { + const DexFile::FieldId& field_id = dex_file.GetFieldId(it.GetMemberIndex()); + const char* descriptor = dex_file.GetFieldTypeDescriptor(field_id); + char c = descriptor[0]; + if (c == 'L' || c == '[') { + num_ref++; + } else if (c == 'J' || c == 'D') { + num_64++; + } else { + num_32++; + } + } + } + // start with generic class data + size_t size = sizeof(mirror::Class); + // follow with reference fields which must be contiguous at start + size += (num_ref * sizeof(uint32_t)); + // if there are 64-bit fields to add, make sure they are aligned + if (num_64 != 0 && size != RoundUp(size, 8)) { // for 64-bit alignment + if (num_32 != 0) { + // use an available 32-bit field for padding + num_32--; + } + size += sizeof(uint32_t); // either way, we are adding a word + DCHECK_EQ(size, RoundUp(size, 8)); + } + // tack on any 64-bit fields now that alignment is assured + size += (num_64 * sizeof(uint64_t)); + // tack on any remaining 32-bit fields + size += (num_32 * sizeof(uint32_t)); + return size; +} + +const OatFile::OatClass* ClassLinker::GetOatClass(const DexFile& dex_file, const char* descriptor) { + DCHECK(descriptor != NULL); + const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file); + CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << descriptor; + const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation()); + CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << descriptor; + uint32_t class_def_index; + bool found = dex_file.FindClassDefIndex(descriptor, class_def_index); + CHECK(found) << dex_file.GetLocation() << " " << descriptor; + const OatFile::OatClass* oat_class = oat_dex_file->GetOatClass(class_def_index); + CHECK(oat_class != NULL) << dex_file.GetLocation() << " " << descriptor; + return oat_class; +} + +static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint32_t method_idx) { + const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); + const DexFile::TypeId& type_id = dex_file.GetTypeId(method_id.class_idx_); + const DexFile::ClassDef* class_def = dex_file.FindClassDef(dex_file.GetTypeDescriptor(type_id)); + CHECK(class_def != NULL); + const byte* class_data = dex_file.GetClassData(*class_def); + CHECK(class_data != NULL); + 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(); + return 0; +} + +const OatFile::OatMethod ClassLinker::GetOatMethodFor(const mirror::AbstractMethod* method) { + // 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(); + size_t end = declaring_class->NumVirtualMethods(); + bool found = false; + for (size_t i = 0; i < end; i++) { + if (declaring_class->GetVirtualMethod(i) == method) { + found = true; + break; + } + oat_method_index++; + } + CHECK(found) << "Didn't find oat method index for virtual method: " << PrettyMethod(method); + } + ClassHelper kh(declaring_class); + UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(kh.GetDexFile(), kh.GetDescriptor())); + CHECK(oat_class.get() != NULL); + DCHECK_EQ(oat_method_index, + GetOatMethodIndexFromMethodIndex(*declaring_class->GetDexCache()->GetDexFile(), + method->GetDexMethodIndex())); + + return oat_class->GetOatMethod(oat_method_index); +} + +// Special case to get oat code without overwriting a trampoline. +const void* ClassLinker::GetOatCodeFor(const mirror::AbstractMethod* method) { + CHECK(!method->IsAbstract()) << PrettyMethod(method); + const void* result = GetOatMethodFor(method).GetCode(); + if (result == NULL) { + // No code? You must mean to go into the interpreter. + result = GetInterpreterEntryPoint(); + } + return result; +} + +const void* ClassLinker::GetOatCodeFor(const DexFile& dex_file, uint32_t method_idx) { + const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); + const char* descriptor = dex_file.GetTypeDescriptor(dex_file.GetTypeId(method_id.class_idx_)); + uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, method_idx); + UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(dex_file, descriptor)); + CHECK(oat_class.get() != NULL); + return oat_class->GetOatMethod(oat_method_idx).GetCode(); +} + +// Returns true if the method must run with interpreter, false otherwise. +static bool NeedsInterpreter(const mirror::AbstractMethod* method, const void* code) { + if (code == NULL) { + // No code: need interpreter. + return true; + } + // If interpreter mode is enabled, every method (except native and proxy) must + // be run with interpreter. + return Runtime::Current()->GetInstrumentation()->InterpretOnly() && + !method->IsNative() && !method->IsProxyMethod(); +} + +void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) { + ClassHelper kh(klass); + const DexFile::ClassDef* dex_class_def = kh.GetClassDef(); + CHECK(dex_class_def != NULL); + const DexFile& dex_file = kh.GetDexFile(); + const byte* class_data = dex_file.GetClassData(*dex_class_def); + if (class_data == NULL) { + return; // no fields or methods - for example a marker interface + } + Runtime* runtime = Runtime::Current(); + if (!runtime->IsStarted() || runtime->UseCompileTimeClassPath()) { + // OAT file unavailable + return; + } + UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(dex_file, kh.GetDescriptor())); + CHECK(oat_class.get() != NULL); + ClassDataItemIterator it(dex_file, class_data); + // Skip fields + while (it.HasNextStaticField()) { + it.Next(); + } + while (it.HasNextInstanceField()) { + it.Next(); + } + // Link the code of methods skipped by LinkCode + for (size_t method_index = 0; it.HasNextDirectMethod(); ++method_index, it.Next()) { + mirror::AbstractMethod* method = klass->GetDirectMethod(method_index); + if (!method->IsStatic()) { + // Only update static methods. + continue; + } + const void* code = oat_class->GetOatMethod(method_index).GetCode(); + const bool enter_interpreter = NeedsInterpreter(method, code); + if (enter_interpreter) { + // Use interpreter entry point. + code = GetInterpreterEntryPoint(); + } + runtime->GetInstrumentation()->UpdateMethodsCode(method, code); + } + // Ignore virtual methods on the iterator. +} + +static void LinkCode(SirtRef<mirror::AbstractMethod>& method, const OatFile::OatClass* oat_class, + uint32_t method_index) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + // Method shouldn't have already been linked. + DCHECK(method->GetEntryPointFromCompiledCode() == NULL); + // 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(method_index); + oat_method.LinkMethod(method.get()); + + // Install entry point from interpreter. + Runtime* runtime = Runtime::Current(); + bool enter_interpreter = NeedsInterpreter(method.get(), method->GetEntryPointFromCompiledCode()); + if (enter_interpreter) { + method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterEntry); + } else { + method->SetEntryPointFromInterpreter(artInterpreterToQuickEntry); + } + + if (method->IsAbstract()) { + method->SetEntryPointFromCompiledCode(GetAbstractMethodErrorStub()); + 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->SetEntryPointFromCompiledCode(GetResolutionTrampoline(runtime->GetClassLinker())); + } else if (enter_interpreter) { + // Set entry point from compiled code if there's no code or in interpreter only mode. + method->SetEntryPointFromCompiledCode(GetInterpreterEntryPoint()); + } + + if (method->IsNative()) { + // Unregistering restores the dlsym lookup stub. + method->UnregisterNative(Thread::Current()); + } + + // Allow instrumentation its chance to hijack code. + runtime->GetInstrumentation()->UpdateMethodsCode(method.get(), + method->GetEntryPointFromCompiledCode()); +} + +void ClassLinker::LoadClass(const DexFile& dex_file, + const DexFile::ClassDef& dex_class_def, + SirtRef<mirror::Class>& klass, + mirror::ClassLoader* class_loader) { + CHECK(klass.get() != NULL); + CHECK(klass->GetDexCache() != NULL); + CHECK_EQ(mirror::Class::kStatusNotReady, klass->GetStatus()); + const char* descriptor = dex_file.GetClassDescriptor(dex_class_def); + CHECK(descriptor != NULL); + + klass->SetClass(GetClassRoot(kJavaLangClass)); + uint32_t access_flags = dex_class_def.access_flags_; + // Make sure that none of our runtime-only flags are set. + // TODO: JACK CLASS ACCESS (HACK TO BE REMOVED) + CHECK_EQ(access_flags & ~(kAccJavaFlagsMask | kAccClassJack), 0U); + klass->SetAccessFlags(access_flags); + klass->SetClassLoader(class_loader); + DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot); + klass->SetStatus(mirror::Class::kStatusIdx); + + klass->SetDexTypeIndex(dex_class_def.class_idx_); + + // Load fields fields. + const byte* class_data = dex_file.GetClassData(dex_class_def); + if (class_data == NULL) { + return; // no fields or methods - for example a marker interface + } + ClassDataItemIterator it(dex_file, class_data); + Thread* self = Thread::Current(); + if (it.NumStaticFields() != 0) { + klass->SetSFields(AllocFieldArray(self, it.NumStaticFields())); + } + if (it.NumInstanceFields() != 0) { + klass->SetIFields(AllocFieldArray(self, it.NumInstanceFields())); + } + for (size_t i = 0; it.HasNextStaticField(); i++, it.Next()) { + SirtRef<mirror::Field> sfield(self, AllocField(self)); + klass->SetStaticField(i, sfield.get()); + LoadField(dex_file, it, klass, sfield); + } + for (size_t i = 0; it.HasNextInstanceField(); i++, it.Next()) { + SirtRef<mirror::Field> ifield(self, AllocField(self)); + klass->SetInstanceField(i, ifield.get()); + LoadField(dex_file, it, klass, ifield); + } + + UniquePtr<const OatFile::OatClass> oat_class; + if (Runtime::Current()->IsStarted() && !Runtime::Current()->UseCompileTimeClassPath()) { + oat_class.reset(GetOatClass(dex_file, descriptor)); + } + + // Load methods. + if (it.NumDirectMethods() != 0) { + // TODO: append direct methods to class object + klass->SetDirectMethods(AllocAbstractMethodArray(self, it.NumDirectMethods())); + } + if (it.NumVirtualMethods() != 0) { + // TODO: append direct methods to class object + klass->SetVirtualMethods(AllocMethodArray(self, it.NumVirtualMethods())); + } + size_t class_def_method_index = 0; + for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) { + SirtRef<mirror::AbstractMethod> method(self, LoadMethod(self, dex_file, it, klass)); + klass->SetDirectMethod(i, method.get()); + if (oat_class.get() != NULL) { + LinkCode(method, oat_class.get(), class_def_method_index); + } + method->SetMethodIndex(class_def_method_index); + class_def_method_index++; + } + for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) { + SirtRef<mirror::AbstractMethod> method(self, LoadMethod(self, dex_file, it, klass)); + klass->SetVirtualMethod(i, method.get()); + DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i); + if (oat_class.get() != NULL) { + LinkCode(method, oat_class.get(), class_def_method_index); + } + class_def_method_index++; + } + DCHECK(!it.HasNext()); +} + +void ClassLinker::LoadField(const DexFile& /*dex_file*/, const ClassDataItemIterator& it, + SirtRef<mirror::Class>& klass, SirtRef<mirror::Field>& dst) { + uint32_t field_idx = it.GetMemberIndex(); + dst->SetDexFieldIndex(field_idx); + dst->SetDeclaringClass(klass.get()); + dst->SetAccessFlags(it.GetMemberAccessFlags()); +} + +mirror::AbstractMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file, + const ClassDataItemIterator& it, + SirtRef<mirror::Class>& klass) { + uint32_t dex_method_idx = it.GetMemberIndex(); + const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx); + StringPiece method_name(dex_file.GetMethodName(method_id)); + + mirror::AbstractMethod* dst = NULL; + if (method_name == "<init>") { + dst = AllocConstructor(self); + } else { + dst = AllocMethod(self); + } + DCHECK(dst->IsMethod()) << PrettyDescriptor(dst->GetClass()); + + const char* old_cause = self->StartAssertNoThreadSuspension("LoadMethod"); + dst->SetDexMethodIndex(dex_method_idx); + dst->SetDeclaringClass(klass.get()); + + if (method_name == "finalize") { + // Create the prototype for a signature of "()V" + const DexFile::StringId* void_string_id = dex_file.FindStringId("V"); + if (void_string_id != NULL) { + const DexFile::TypeId* void_type_id = + dex_file.FindTypeId(dex_file.GetIndexForStringId(*void_string_id)); + if (void_type_id != NULL) { + std::vector<uint16_t> no_args; + const DexFile::ProtoId* finalizer_proto = + dex_file.FindProtoId(dex_file.GetIndexForTypeId(*void_type_id), no_args); + if (finalizer_proto != NULL) { + // We have the prototype in the dex file + if (klass->GetClassLoader() != NULL) { // All non-boot finalizer methods are flagged + klass->SetFinalizable(); + } else { + StringPiece klass_descriptor(dex_file.StringByTypeIdx(klass->GetDexTypeIndex())); + // 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 (klass_descriptor != "Ljava/lang/Object;" && + klass_descriptor != "Ljava/lang/Enum;") { + klass->SetFinalizable(); + } + } + } + } + } + } + dst->SetCodeItemOffset(it.GetMethodCodeItemOffset()); + dst->SetAccessFlags(it.GetMemberAccessFlags()); + + dst->SetDexCacheStrings(klass->GetDexCache()->GetStrings()); + dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods()); + dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes()); + dst->SetDexCacheInitializedStaticStorage(klass->GetDexCache()->GetInitializedStaticStorage()); + + CHECK(dst->IsMethod()); + + self->EndAssertNoThreadSuspension(old_cause); + return dst; +} + +void ClassLinker::AppendToBootClassPath(const DexFile& dex_file) { + Thread* self = Thread::Current(); + SirtRef<mirror::DexCache> dex_cache(self, AllocDexCache(self, dex_file)); + AppendToBootClassPath(dex_file, dex_cache); +} + +void ClassLinker::AppendToBootClassPath(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) { + CHECK(dex_cache.get() != NULL) << dex_file.GetLocation(); + boot_class_path_.push_back(&dex_file); + RegisterDexFile(dex_file, dex_cache); +} + +bool ClassLinker::IsDexFileRegisteredLocked(const DexFile& dex_file) const { + dex_lock_.AssertSharedHeld(Thread::Current()); + for (size_t i = 0; i != dex_caches_.size(); ++i) { + if (dex_caches_[i]->GetDexFile() == &dex_file) { + return true; + } + } + return false; +} + +bool ClassLinker::IsDexFileRegistered(const DexFile& dex_file) const { + ReaderMutexLock mu(Thread::Current(), dex_lock_); + return IsDexFileRegisteredLocked(dex_file); +} + +void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) { + dex_lock_.AssertExclusiveHeld(Thread::Current()); + CHECK(dex_cache.get() != NULL) << dex_file.GetLocation(); + CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation())); + dex_caches_.push_back(dex_cache.get()); + dex_cache->SetDexFile(&dex_file); + Dirty(); +} + +void ClassLinker::RegisterDexFile(const DexFile& dex_file) { + Thread* self = Thread::Current(); + { + ReaderMutexLock mu(self, dex_lock_); + if (IsDexFileRegisteredLocked(dex_file)) { + return; + } + } + // 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. + SirtRef<mirror::DexCache> dex_cache(self, AllocDexCache(self, dex_file)); + { + WriterMutexLock mu(self, dex_lock_); + if (IsDexFileRegisteredLocked(dex_file)) { + return; + } + RegisterDexFileLocked(dex_file, dex_cache); + } +} + +void ClassLinker::RegisterDexFile(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) { + WriterMutexLock mu(Thread::Current(), dex_lock_); + RegisterDexFileLocked(dex_file, dex_cache); +} + +mirror::DexCache* ClassLinker::FindDexCache(const DexFile& dex_file) const { + ReaderMutexLock mu(Thread::Current(), dex_lock_); + // Search assuming unique-ness of dex file. + for (size_t i = 0; i != dex_caches_.size(); ++i) { + mirror::DexCache* dex_cache = dex_caches_[i]; + if (dex_cache->GetDexFile() == &dex_file) { + return dex_cache; + } + } + // Search matching by location name. + std::string location(dex_file.GetLocation()); + for (size_t i = 0; i != dex_caches_.size(); ++i) { + mirror::DexCache* dex_cache = dex_caches_[i]; + if (dex_cache->GetDexFile()->GetLocation() == location) { + return dex_cache; + } + } + // Failure, dump diagnostic and abort. + for (size_t i = 0; i != dex_caches_.size(); ++i) { + mirror::DexCache* dex_cache = dex_caches_[i]; + LOG(ERROR) << "Registered dex file " << i << " = " << dex_cache->GetDexFile()->GetLocation(); + } + LOG(FATAL) << "Failed to find DexCache for DexFile " << location; + return NULL; +} + +void ClassLinker::FixupDexCaches(mirror::AbstractMethod* resolution_method) const { + ReaderMutexLock mu(Thread::Current(), dex_lock_); + for (size_t i = 0; i != dex_caches_.size(); ++i) { + dex_caches_[i]->Fixup(resolution_method); + } +} + +mirror::Class* ClassLinker::CreatePrimitiveClass(Thread* self, Primitive::Type type) { + return InitializePrimitiveClass(AllocClass(self, sizeof(mirror::Class)), type); +} + +mirror::Class* ClassLinker::InitializePrimitiveClass(mirror::Class* primitive_class, Primitive::Type type) { + CHECK(primitive_class != NULL); + // Must hold lock on object when initializing. + ObjectLock lock(Thread::Current(), primitive_class); + primitive_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract); + primitive_class->SetPrimitiveType(type); + primitive_class->SetStatus(mirror::Class::kStatusInitialized); + mirror::Class* existing = InsertClass(Primitive::Descriptor(type), primitive_class, false); + CHECK(existing == NULL) << "InitPrimitiveClass(" << type << ") failed"; + return primitive_class; +} + +// 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(const std::string& descriptor, + mirror::ClassLoader* class_loader) { + CHECK_EQ('[', descriptor[0]); + + // Identify the underlying component type + mirror::Class* component_type = FindClass(descriptor.substr(1).c_str(), class_loader); + if (component_type == NULL) { + DCHECK(Thread::Current()->IsExceptionPending()); + return NULL; + } + + // 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 != component_type->GetClassLoader()) { + mirror::Class* new_class = LookupClass(descriptor.c_str(), component_type->GetClassLoader()); + if (new_class != NULL) { + 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. + Thread* self = Thread::Current(); + SirtRef<mirror::Class> new_class(self, NULL); + if (!init_done_) { + // Classes that were hand created, ie not by FindSystemClass + if (descriptor == "[Ljava/lang/Class;") { + new_class.reset(GetClassRoot(kClassArrayClass)); + } else if (descriptor == "[Ljava/lang/Object;") { + new_class.reset(GetClassRoot(kObjectArrayClass)); + } else if (descriptor == class_roots_descriptors_[kJavaLangStringArrayClass]) { + new_class.reset(GetClassRoot(kJavaLangStringArrayClass)); + } else if (descriptor == class_roots_descriptors_[kJavaLangReflectAbstractMethodArrayClass]) { + new_class.reset(GetClassRoot(kJavaLangReflectAbstractMethodArrayClass)); + } else if (descriptor == class_roots_descriptors_[kJavaLangReflectFieldArrayClass]) { + new_class.reset(GetClassRoot(kJavaLangReflectFieldArrayClass)); + } else if (descriptor == class_roots_descriptors_[kJavaLangReflectMethodArrayClass]) { + new_class.reset(GetClassRoot(kJavaLangReflectMethodArrayClass)); + } else if (descriptor == "[C") { + new_class.reset(GetClassRoot(kCharArrayClass)); + } else if (descriptor == "[I") { + new_class.reset(GetClassRoot(kIntArrayClass)); + } + } + if (new_class.get() == NULL) { + new_class.reset(AllocClass(self, sizeof(mirror::Class))); + if (new_class.get() == NULL) { + return NULL; + } + new_class->SetComponentType(component_type); + } + ObjectLock lock(self, new_class.get()); // Must hold lock on object when initializing. + DCHECK(new_class->GetComponentType() != NULL); + 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()); + new_class->SetStatus(mirror::Class::kStatusInitialized); + // 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). + CHECK(array_iftable_ != NULL); + 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(), false); + if (existing == NULL) { + 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 (Primitive::GetType(type)) { + case Primitive::kPrimByte: + return GetClassRoot(kPrimitiveByte); + case Primitive::kPrimChar: + return GetClassRoot(kPrimitiveChar); + case Primitive::kPrimDouble: + return GetClassRoot(kPrimitiveDouble); + case Primitive::kPrimFloat: + return GetClassRoot(kPrimitiveFloat); + case Primitive::kPrimInt: + return GetClassRoot(kPrimitiveInt); + case Primitive::kPrimLong: + return GetClassRoot(kPrimitiveLong); + case Primitive::kPrimShort: + return GetClassRoot(kPrimitiveShort); + case Primitive::kPrimBoolean: + return GetClassRoot(kPrimitiveBoolean); + case Primitive::kPrimVoid: + return GetClassRoot(kPrimitiveVoid); + case Primitive::kPrimNot: + break; + } + std::string printable_type(PrintableChar(type)); + ThrowNoClassDefFoundError("Not a primitive type: %s", printable_type.c_str()); + return NULL; +} + +mirror::Class* ClassLinker::InsertClass(const StringPiece& descriptor, mirror::Class* klass, + bool image_class) { + if (VLOG_IS_ON(class_linker)) { + mirror::DexCache* dex_cache = klass->GetDexCache(); + std::string source; + if (dex_cache != NULL) { + source += " from "; + source += dex_cache->GetLocation()->ToModifiedUtf8(); + } + LOG(INFO) << "Loaded class " << descriptor << source; + } + size_t hash = StringPieceHash()(descriptor); + WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + Table& classes = image_class ? image_classes_ : classes_; + mirror::Class* existing = + LookupClassLocked(descriptor.data(), klass->GetClassLoader(), hash, classes); +#ifndef NDEBUG + // Check we don't have the class in the other table in error + Table& other_classes = image_class ? classes_ : image_classes_; + CHECK(LookupClassLocked(descriptor.data(), klass->GetClassLoader(), hash, other_classes) == NULL); +#endif + if (existing != NULL) { + return existing; + } + Runtime::Current()->GetHeap()->VerifyObject(klass); + classes.insert(std::make_pair(hash, klass)); + Dirty(); + return NULL; +} + +bool ClassLinker::RemoveClass(const char* descriptor, const mirror::ClassLoader* class_loader) { + size_t hash = Hash(descriptor); + WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + typedef Table::iterator It; // TODO: C++0x auto + // TODO: determine if its better to search classes_ or image_classes_ first + ClassHelper kh; + for (It it = classes_.lower_bound(hash), end = classes_.end(); it != end && it->first == hash; + ++it) { + mirror::Class* klass = it->second; + kh.ChangeClass(klass); + if (strcmp(kh.GetDescriptor(), descriptor) == 0 && klass->GetClassLoader() == class_loader) { + classes_.erase(it); + return true; + } + } + for (It it = image_classes_.lower_bound(hash), end = classes_.end(); + it != end && it->first == hash; ++it) { + mirror::Class* klass = it->second; + kh.ChangeClass(klass); + if (strcmp(kh.GetDescriptor(), descriptor) == 0 && klass->GetClassLoader() == class_loader) { + image_classes_.erase(it); + return true; + } + } + return false; +} + +mirror::Class* ClassLinker::LookupClass(const char* descriptor, + const mirror::ClassLoader* class_loader) { + size_t hash = Hash(descriptor); + ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + // TODO: determine if its better to search classes_ or image_classes_ first + mirror::Class* klass = NULL; + // Use image class only if the class_loader is null. + if (class_loader == NULL) { + klass = LookupClassLocked(descriptor, class_loader, hash, image_classes_); + } + if (klass != NULL) { + return klass; + } + return LookupClassLocked(descriptor, class_loader, hash, classes_); +} + +mirror::Class* ClassLinker::LookupClassLocked(const char* descriptor, + const mirror::ClassLoader* class_loader, + size_t hash, const Table& classes) { + ClassHelper kh(NULL, this); + typedef Table::const_iterator It; // TODO: C++0x auto + for (It it = classes.lower_bound(hash), end = classes_.end(); it != end && it->first == hash; ++it) { + mirror::Class* klass = it->second; + kh.ChangeClass(klass); + if (strcmp(descriptor, kh.GetDescriptor()) == 0 && klass->GetClassLoader() == class_loader) { +#ifndef NDEBUG + for (++it; it != end && it->first == hash; ++it) { + mirror::Class* klass2 = it->second; + kh.ChangeClass(klass2); + CHECK(!(strcmp(descriptor, kh.GetDescriptor()) == 0 && klass2->GetClassLoader() == class_loader)) + << PrettyClass(klass) << " " << klass << " " << klass->GetClassLoader() << " " + << PrettyClass(klass2) << " " << klass2 << " " << klass2->GetClassLoader(); + } +#endif + return klass; + } + } + return NULL; +} + +void ClassLinker::LookupClasses(const char* descriptor, std::vector<mirror::Class*>& classes) { + classes.clear(); + size_t hash = Hash(descriptor); + ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + typedef Table::const_iterator It; // TODO: C++0x auto + // TODO: determine if its better to search classes_ or image_classes_ first + ClassHelper kh(NULL, this); + for (It it = classes_.lower_bound(hash), end = classes_.end(); it != end && it->first == hash; ++it) { + mirror::Class* klass = it->second; + kh.ChangeClass(klass); + if (strcmp(descriptor, kh.GetDescriptor()) == 0) { + classes.push_back(klass); + } + } + for (It it = image_classes_.lower_bound(hash), end = classes_.end(); it != end && it->first == hash; ++it) { + mirror::Class* klass = it->second; + kh.ChangeClass(klass); + if (strcmp(descriptor, kh.GetDescriptor()) == 0) { + classes.push_back(klass); + } + } +} + +void ClassLinker::VerifyClass(mirror::Class* klass) { + // TODO: assert that the monitor on the Class is held + Thread* self = Thread::Current(); + ObjectLock lock(self, klass); + + // Don't attempt to re-verify if already sufficiently verified. + if (klass->IsVerified() || + (klass->IsCompileTimeVerified() && Runtime::Current()->IsCompiler())) { + return; + } + + // 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); + return; + } + + if (klass->GetStatus() == mirror::Class::kStatusResolved) { + klass->SetStatus(mirror::Class::kStatusVerifying); + } else { + CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime) + << PrettyClass(klass); + CHECK(!Runtime::Current()->IsCompiler()); + klass->SetStatus(mirror::Class::kStatusVerifyingAtRuntime); + } + + // Verify super class. + mirror::Class* super = klass->GetSuperClass(); + if (super != NULL) { + // Acquire lock to prevent races on verifying the super class. + ObjectLock lock(self, super); + + if (!super->IsVerified() && !super->IsErroneous()) { + Runtime::Current()->GetClassLinker()->VerifyClass(super); + } + if (!super->IsCompileTimeVerified()) { + std::string error_msg(StringPrintf("Rejecting class %s that attempts to sub-class erroneous class %s", + PrettyDescriptor(klass).c_str(), + PrettyDescriptor(super).c_str())); + LOG(ERROR) << error_msg << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8(); + SirtRef<mirror::Throwable> cause(self, self->GetException(NULL)); + if (cause.get() != NULL) { + self->ClearException(); + } + ThrowVerifyError(klass, "%s", error_msg.c_str()); + if (cause.get() != NULL) { + self->GetException(NULL)->SetCause(cause.get()); + } + klass->SetStatus(mirror::Class::kStatusError); + return; + } + } + + // 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, oat_file_class_status); + if (oat_file_class_status == mirror::Class::kStatusError) { + LOG(WARNING) << "Skipping runtime verification of erroneous class " << PrettyDescriptor(klass) + << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8(); + ThrowVerifyError(klass, "Rejecting class %s because it failed compile-time verification", + PrettyDescriptor(klass).c_str()); + klass->SetStatus(mirror::Class::kStatusError); + return; + } + verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure; + std::string error_msg; + if (!preverified) { + verifier_failure = verifier::MethodVerifier::VerifyClass(klass, error_msg, + Runtime::Current()->IsCompiler()); + } + if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) { + if (!preverified && verifier_failure != verifier::MethodVerifier::kNoFailure) { + LOG(WARNING) << "Soft verification failure in class " << PrettyDescriptor(klass) + << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8() + << " because: " << error_msg; + } + self->AssertNoPendingException(); + // Make sure all classes referenced by catch blocks are resolved. + ResolveClassExceptionHandlerTypes(dex_file, klass); + if (verifier_failure == verifier::MethodVerifier::kNoFailure) { + klass->SetStatus(mirror::Class::kStatusVerified); + } 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()->IsCompiler()) { + klass->SetStatus(mirror::Class::kStatusRetryVerificationAtRuntime); + } else { + klass->SetStatus(mirror::Class::kStatusVerified); + } + } + } else { + LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(klass) + << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8() + << " because: " << error_msg; + self->AssertNoPendingException(); + ThrowVerifyError(klass, "%s", error_msg.c_str()); + klass->SetStatus(mirror::Class::kStatusError); + } + if (preverified || verifier_failure == verifier::MethodVerifier::kNoFailure) { + // Class is verified so we don't need to do any access check in its methods. + // Let the interpreter know it by setting the kAccPreverified flag onto each + // method. + // Note: we're going here during compilation and at runtime. When we set the + // kAccPreverified flag when compiling image classes, the flag is recorded + // in the image and is set when loading the image. + klass->SetPreverifiedFlagOnAllMethods(); + } +} + +bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class* klass, + mirror::Class::Status& oat_file_class_status) { + if (!Runtime::Current()->IsStarted()) { + return false; + } + if (Runtime::Current()->UseCompileTimeClassPath()) { + return false; + } + const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file); + CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass); + const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation()); + CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass); + const char* descriptor = ClassHelper(klass).GetDescriptor(); + uint32_t class_def_index; + bool found = dex_file.FindClassDefIndex(descriptor, class_def_index); + CHECK(found) << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor; + UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(class_def_index)); + CHECK(oat_class.get() != NULL) + << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor; + oat_file_class_status = oat_class->GetStatus(); + if (oat_file_class_status == mirror::Class::kStatusVerified || + oat_file_class_status == mirror::Class::kStatusInitialized) { + return true; + } + 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; + } + LOG(FATAL) << "Unexpected class status: " << oat_file_class_status + << " " << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor; + + return false; +} + +void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file, mirror::Class* klass) { + for (size_t i = 0; i < klass->NumDirectMethods(); i++) { + ResolveMethodExceptionHandlerTypes(dex_file, klass->GetDirectMethod(i)); + } + for (size_t i = 0; i < klass->NumVirtualMethods(); i++) { + ResolveMethodExceptionHandlerTypes(dex_file, klass->GetVirtualMethod(i)); + } +} + +void ClassLinker::ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, + mirror::AbstractMethod* method) { + // similar to DexVerifier::ScanTryCatchBlocks and dex2oat's ResolveExceptionsForMethod. + const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->GetCodeItemOffset()); + if (code_item == NULL) { + return; // native or abstract method + } + if (code_item->tries_size_ == 0) { + return; // nothing to process + } + const byte* handlers_ptr = DexFile::GetCatchHandlerData(*code_item, 0); + uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr); + ClassLinker* linker = Runtime::Current()->GetClassLinker(); + 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 = linker->ResolveType(iterator.GetHandlerTypeIndex(), method); + if (exception_type == NULL) { + DCHECK(Thread::Current()->IsExceptionPending()); + Thread::Current()->ClearException(); + } + } + } + handlers_ptr = iterator.EndDataPointer(); + } +} + +static void CheckProxyConstructor(mirror::AbstractMethod* constructor); +static void CheckProxyMethod(mirror::AbstractMethod* method, + SirtRef<mirror::AbstractMethod>& prototype); + +mirror::Class* ClassLinker::CreateProxyClass(mirror::String* name, + mirror::ObjectArray<mirror::Class>* interfaces, + mirror::ClassLoader* loader, + mirror::ObjectArray<mirror::AbstractMethod>* methods, + mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >* throws) { + Thread* self = Thread::Current(); + SirtRef<mirror::Class> klass(self, AllocClass(self, GetClassRoot(kJavaLangClass), + sizeof(mirror::SynthesizedProxyClass))); + CHECK(klass.get() != NULL); + DCHECK(klass->GetClass() != NULL); + klass->SetObjectSize(sizeof(mirror::Proxy)); + klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal); + klass->SetClassLoader(loader); + DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot); + klass->SetName(name); + mirror::Class* proxy_class = GetClassRoot(kJavaLangReflectProxy); + klass->SetDexCache(proxy_class->GetDexCache()); + + klass->SetStatus(mirror::Class::kStatusIdx); + + klass->SetDexTypeIndex(DexFile::kDexNoIndex16); + + // Instance fields are inherited, but we add a couple of static fields... + klass->SetSFields(AllocFieldArray(self, 2)); + // 1. Create a static field 'interfaces' that holds the _declared_ interfaces implemented by + // our proxy, so Class.getInterfaces doesn't return the flattened set. + SirtRef<mirror::Field> interfaces_sfield(self, AllocField(self)); + klass->SetStaticField(0, interfaces_sfield.get()); + 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. + SirtRef<mirror::Field> throws_sfield(self, AllocField(self)); + klass->SetStaticField(1, throws_sfield.get()); + throws_sfield->SetDexFieldIndex(1); + throws_sfield->SetDeclaringClass(klass.get()); + throws_sfield->SetAccessFlags(kAccStatic | kAccPublic | kAccFinal); + + // Proxies have 1 direct method, the constructor + klass->SetDirectMethods(AllocAbstractMethodArray(self, 1)); + klass->SetDirectMethod(0, CreateProxyConstructor(self, klass, proxy_class)); + + // Create virtual method using specified prototypes + size_t num_virtual_methods = methods->GetLength(); + klass->SetVirtualMethods(AllocMethodArray(self, num_virtual_methods)); + for (size_t i = 0; i < num_virtual_methods; ++i) { + SirtRef<mirror::AbstractMethod> prototype(self, methods->Get(i)); + klass->SetVirtualMethod(i, CreateProxyMethod(self, klass, prototype)); + } + + klass->SetSuperClass(proxy_class); // The super class is java.lang.reflect.Proxy + klass->SetStatus(mirror::Class::kStatusLoaded); // Class is now effectively in the loaded state + self->AssertNoPendingException(); + + // Link the fields and virtual methods, creating vtable and iftables + if (!LinkClass(klass, interfaces)) { + klass->SetStatus(mirror::Class::kStatusError); + return NULL; + } + { + ObjectLock lock(self, klass.get()); // Must hold lock on object when initializing. + interfaces_sfield->SetObject(klass.get(), interfaces); + throws_sfield->SetObject(klass.get(), throws); + klass->SetStatus(mirror::Class::kStatusInitialized); + } + + // sanity checks + if (kIsDebugBuild) { + CHECK(klass->GetIFields() == NULL); + CheckProxyConstructor(klass->GetDirectMethod(0)); + for (size_t i = 0; i < num_virtual_methods; ++i) { + SirtRef<mirror::AbstractMethod> prototype(self, methods->Get(i)); + CheckProxyMethod(klass->GetVirtualMethod(i), prototype); + } + + std::string interfaces_field_name(StringPrintf("java.lang.Class[] %s.interfaces", + name->ToModifiedUtf8().c_str())); + CHECK_EQ(PrettyField(klass->GetStaticField(0)), interfaces_field_name); + + std::string throws_field_name(StringPrintf("java.lang.Class[][] %s.throws", + name->ToModifiedUtf8().c_str())); + CHECK_EQ(PrettyField(klass->GetStaticField(1)), throws_field_name); + + mirror::SynthesizedProxyClass* synth_proxy_class = + down_cast<mirror::SynthesizedProxyClass*>(klass.get()); + CHECK_EQ(synth_proxy_class->GetInterfaces(), interfaces); + CHECK_EQ(synth_proxy_class->GetThrows(), throws); + } + return klass.get(); +} + +std::string ClassLinker::GetDescriptorForProxy(const mirror::Class* proxy_class) { + DCHECK(proxy_class->IsProxyClass()); + mirror::String* name = proxy_class->GetName(); + DCHECK(name != NULL); + return DotToDescriptor(name->ToModifiedUtf8().c_str()); +} + +mirror::AbstractMethod* ClassLinker::FindMethodForProxy(const mirror::Class* proxy_class, + const mirror::AbstractMethod* proxy_method) { + DCHECK(proxy_class->IsProxyClass()); + DCHECK(proxy_method->IsProxyMethod()); + // Locate the dex cache of the original interface/Object + mirror::DexCache* dex_cache = NULL; + { + mirror::ObjectArray<mirror::Class>* resolved_types = proxy_method->GetDexCacheResolvedTypes(); + ReaderMutexLock mu(Thread::Current(), dex_lock_); + for (size_t i = 0; i != dex_caches_.size(); ++i) { + if (dex_caches_[i]->GetResolvedTypes() == resolved_types) { + dex_cache = dex_caches_[i]; + break; + } + } + } + CHECK(dex_cache != NULL); + uint32_t method_idx = proxy_method->GetDexMethodIndex(); + mirror::AbstractMethod* resolved_method = dex_cache->GetResolvedMethod(method_idx); + CHECK(resolved_method != NULL); + return resolved_method; +} + + +mirror::AbstractMethod* ClassLinker::CreateProxyConstructor(Thread* self, + SirtRef<mirror::Class>& klass, + mirror::Class* proxy_class) { + // Create constructor for Proxy that must initialize h + mirror::ObjectArray<mirror::AbstractMethod>* proxy_direct_methods = + proxy_class->GetDirectMethods(); + CHECK_EQ(proxy_direct_methods->GetLength(), 15); + mirror::AbstractMethod* proxy_constructor = proxy_direct_methods->Get(2); + // Clone the existing constructor of Proxy (our constructor would just invoke it so steal its + // code_ too) + mirror::AbstractMethod* constructor = + down_cast<mirror::AbstractMethod*>(proxy_constructor->Clone(self)); + // Make this constructor public and fix the class to be our Proxy version + constructor->SetAccessFlags((constructor->GetAccessFlags() & ~kAccProtected) | kAccPublic); + constructor->SetDeclaringClass(klass.get()); + return constructor; +} + +static void CheckProxyConstructor(mirror::AbstractMethod* constructor) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + CHECK(constructor->IsConstructor()); + MethodHelper mh(constructor); + CHECK_STREQ(mh.GetName(), "<init>"); + CHECK_EQ(mh.GetSignature(), std::string("(Ljava/lang/reflect/InvocationHandler;)V")); + DCHECK(constructor->IsPublic()); +} + +mirror::AbstractMethod* ClassLinker::CreateProxyMethod(Thread* self, SirtRef<mirror::Class>& klass, + SirtRef<mirror::AbstractMethod>& prototype) { + // Ensure prototype is in dex cache so that we can use the dex cache to look up the overridden + // prototype method + prototype->GetDeclaringClass()->GetDexCache()->SetResolvedMethod(prototype->GetDexMethodIndex(), + prototype.get()); + // We steal everything from the prototype (such as DexCache, invoke stub, etc.) then specialize + // as necessary + mirror::AbstractMethod* method = down_cast<mirror::AbstractMethod*>(prototype->Clone(self)); + + // Set class to be the concrete proxy class and clear the abstract flag, modify exceptions to + // the intersection of throw exceptions as defined in Proxy + method->SetDeclaringClass(klass.get()); + method->SetAccessFlags((method->GetAccessFlags() & ~kAccAbstract) | kAccFinal); + + // At runtime the method looks like a reference and argument saving method, clone the code + // related parameters from this method. + mirror::AbstractMethod* refs_and_args = + Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs); + method->SetCoreSpillMask(refs_and_args->GetCoreSpillMask()); + method->SetFpSpillMask(refs_and_args->GetFpSpillMask()); + method->SetFrameSizeInBytes(refs_and_args->GetFrameSizeInBytes()); +#if !defined(ART_USE_PORTABLE_COMPILER) + method->SetEntryPointFromCompiledCode(reinterpret_cast<void*>(art_quick_proxy_invoke_handler)); +#else + method->SetEntryPointFromCompiledCode(reinterpret_cast<void*>(art_portable_proxy_invoke_handler)); +#endif + method->SetEntryPointFromInterpreter(artInterpreterToQuickEntry); + + return method; +} + +static void CheckProxyMethod(mirror::AbstractMethod* method, + SirtRef<mirror::AbstractMethod>& prototype) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + // Basic sanity + CHECK(!prototype->IsFinal()); + CHECK(method->IsFinal()); + CHECK(!method->IsAbstract()); + + // The proxy method doesn't have its own dex cache or dex file and so it steals those of its + // interface prototype. The exception to this are Constructors and the Class of the Proxy itself. + CHECK_EQ(prototype->GetDexCacheStrings(), method->GetDexCacheStrings()); + CHECK_EQ(prototype->GetDexCacheResolvedMethods(), method->GetDexCacheResolvedMethods()); + CHECK_EQ(prototype->GetDexCacheResolvedTypes(), method->GetDexCacheResolvedTypes()); + CHECK_EQ(prototype->GetDexCacheInitializedStaticStorage(), + method->GetDexCacheInitializedStaticStorage()); + CHECK_EQ(prototype->GetDexMethodIndex(), method->GetDexMethodIndex()); + + MethodHelper mh(method); + MethodHelper mh2(prototype.get()); + CHECK_STREQ(mh.GetName(), mh2.GetName()); + CHECK_STREQ(mh.GetShorty(), mh2.GetShorty()); + // More complex sanity - via dex cache + CHECK_EQ(mh.GetReturnType(), mh2.GetReturnType()); +} + +bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_run_clinit, bool can_init_statics) { + CHECK(klass->IsResolved() || klass->IsErroneous()) + << PrettyClass(klass) << ": state=" << klass->GetStatus(); + + Thread* self = Thread::Current(); + + mirror::AbstractMethod* clinit = NULL; + { + // see JLS 3rd edition, 12.4.2 "Detailed Initialization Procedure" for the locking protocol + ObjectLock lock(self, klass); + + if (klass->GetStatus() == mirror::Class::kStatusInitialized) { + return true; + } + + if (klass->IsErroneous()) { + ThrowEarlierClassFailure(klass); + return false; + } + + if (klass->GetStatus() == mirror::Class::kStatusResolved || + klass->GetStatus() == mirror::Class::kStatusRetryVerificationAtRuntime) { + VerifyClass(klass); + if (klass->GetStatus() != mirror::Class::kStatusVerified) { + if (klass->GetStatus() == mirror::Class::kStatusError) { + CHECK(self->IsExceptionPending()); + } + return false; + } + } + + clinit = klass->FindDeclaredDirectMethod("<clinit>", "()V"); + if (clinit != NULL && !can_run_clinit) { + // if the class has a <clinit> but we can't run it during compilation, + // don't bother going to kStatusInitializing. We return false so that + // sub-classes don't believe this class is initialized. + // Opportunistically link non-static methods, TODO: don't initialize and dirty pages + // in second pass. + return false; + } + + // If the class is kStatusInitializing, either this thread is + // initializing higher up the stack or another thread has beat us + // to initializing and we need to wait. Either way, this + // invocation of InitializeClass will not be responsible for + // running <clinit> and will return. + if (klass->GetStatus() == mirror::Class::kStatusInitializing) { + // We caught somebody else in the act; was it us? + if (klass->GetClinitThreadId() == self->GetTid()) { + // Yes. That's fine. Return so we can continue initializing. + return true; + } + // No. That's fine. Wait for another thread to finish initializing. + return WaitForInitializeClass(klass, self, lock); + } + + if (!ValidateSuperClassDescriptors(klass)) { + klass->SetStatus(mirror::Class::kStatusError); + lock.NotifyAll(); + return false; + } + + DCHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << PrettyClass(klass); + + klass->SetClinitThreadId(self->GetTid()); + klass->SetStatus(mirror::Class::kStatusInitializing); + } + + uint64_t t0 = NanoTime(); + + if (!InitializeSuperClass(klass, can_run_clinit, can_init_statics)) { + // Super class initialization failed, this can be because we can't run + // super-class class initializers in which case we'll be verified. + // Otherwise this class is erroneous. + if (!can_run_clinit) { + CHECK(klass->IsVerified()); + } else { + CHECK(klass->IsErroneous()); + } + // Signal to any waiting threads that saw this class as initializing. + ObjectLock lock(self, klass); + lock.NotifyAll(); + return false; + } + + bool has_static_field_initializers = InitializeStaticFields(klass); + + if (clinit != NULL) { + if (Runtime::Current()->IsStarted()) { + JValue result; + clinit->Invoke(self, NULL, 0, &result, 'V'); + } else { + art::interpreter::EnterInterpreterFromInvoke(self, clinit, NULL, NULL, NULL); + } + } + + FixupStaticTrampolines(klass); + + uint64_t t1 = NanoTime(); + + bool success = true; + { + ObjectLock lock(self, klass); + + if (self->IsExceptionPending()) { + WrapExceptionInInitializer(); + klass->SetStatus(mirror::Class::kStatusError); + success = false; + } else { + RuntimeStats* global_stats = Runtime::Current()->GetStats(); + RuntimeStats* thread_stats = self->GetStats(); + ++global_stats->class_init_count; + ++thread_stats->class_init_count; + global_stats->class_init_time_ns += (t1 - t0); + thread_stats->class_init_time_ns += (t1 - t0); + // Set the class as initialized except if we can't initialize static fields and static field + // initialization is necessary. + if (!can_init_statics && has_static_field_initializers) { + klass->SetStatus(mirror::Class::kStatusVerified); // Don't leave class in initializing state. + success = false; + } else { + klass->SetStatus(mirror::Class::kStatusInitialized); + } + if (VLOG_IS_ON(class_linker)) { + ClassHelper kh(klass); + LOG(INFO) << "Initialized class " << kh.GetDescriptor() << " from " << kh.GetLocation(); + } + } + lock.NotifyAll(); + } + return success; +} + +bool ClassLinker::WaitForInitializeClass(mirror::Class* klass, Thread* self, ObjectLock& lock) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + while (true) { + self->AssertNoPendingException(); + lock.WaitIgnoringInterrupts(); + + // When we wake up, repeat the test for init-in-progress. If + // there's an exception pending (only possible if + // "interruptShouldThrow" was set), bail out. + if (self->IsExceptionPending()) { + WrapExceptionInInitializer(); + klass->SetStatus(mirror::Class::kStatusError); + return false; + } + // Spurious wakeup? Go back to waiting. + if (klass->GetStatus() == mirror::Class::kStatusInitializing) { + continue; + } + if (klass->GetStatus() == mirror::Class::kStatusVerified && Runtime::Current()->IsCompiler()) { + // Compile time initialization failed. + return false; + } + if (klass->IsErroneous()) { + // The caller wants an exception, but it was thrown in a + // different thread. Synthesize one here. + ThrowNoClassDefFoundError("<clinit> failed for class %s; see exception in other thread", + PrettyDescriptor(klass).c_str()); + return false; + } + if (klass->IsInitialized()) { + return true; + } + LOG(FATAL) << "Unexpected class status. " << PrettyClass(klass) << " is " << klass->GetStatus(); + } + LOG(FATAL) << "Not Reached" << PrettyClass(klass); +} + +bool ClassLinker::ValidateSuperClassDescriptors(const mirror::Class* klass) { + if (klass->IsInterface()) { + return true; + } + // begin with the methods local to the superclass + if (klass->HasSuperClass() && + klass->GetClassLoader() != klass->GetSuperClass()->GetClassLoader()) { + const mirror::Class* super = klass->GetSuperClass(); + for (int i = super->GetVTable()->GetLength() - 1; i >= 0; --i) { + const mirror::AbstractMethod* method = klass->GetVTable()->Get(i); + if (method != super->GetVTable()->Get(i) && + !IsSameMethodSignatureInDifferentClassContexts(method, super, klass)) { + ThrowLinkageError(klass, "Class %s method %s resolves differently in superclass %s", + PrettyDescriptor(klass).c_str(), PrettyMethod(method).c_str(), + PrettyDescriptor(super).c_str()); + return false; + } + } + } + mirror::IfTable* iftable = klass->GetIfTable(); + for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) { + mirror::Class* interface = iftable->GetInterface(i); + if (klass->GetClassLoader() != interface->GetClassLoader()) { + for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) { + const mirror::AbstractMethod* method = iftable->GetMethodArray(i)->Get(j); + if (!IsSameMethodSignatureInDifferentClassContexts(method, interface, + method->GetDeclaringClass())) { + ThrowLinkageError(klass, "Class %s method %s resolves differently in interface %s", + PrettyDescriptor(method->GetDeclaringClass()).c_str(), + PrettyMethod(method).c_str(), + PrettyDescriptor(interface).c_str()); + return false; + } + } + } + } + return true; +} + +// Returns true if classes referenced by the signature of the method are the +// same classes in klass1 as they are in klass2. +bool ClassLinker::IsSameMethodSignatureInDifferentClassContexts(const mirror::AbstractMethod* method, + const mirror::Class* klass1, + const mirror::Class* klass2) { + if (klass1 == klass2) { + return true; + } + const DexFile& dex_file = *method->GetDeclaringClass()->GetDexCache()->GetDexFile(); + const DexFile::ProtoId& proto_id = + dex_file.GetMethodPrototype(dex_file.GetMethodId(method->GetDexMethodIndex())); + for (DexFileParameterIterator it(dex_file, proto_id); it.HasNext(); it.Next()) { + const char* descriptor = it.GetDescriptor(); + if (descriptor == NULL) { + break; + } + if (descriptor[0] == 'L' || descriptor[0] == '[') { + // Found a non-primitive type. + if (!IsSameDescriptorInDifferentClassContexts(descriptor, klass1, klass2)) { + return false; + } + } + } + // Check the return type + const char* descriptor = dex_file.GetReturnTypeDescriptor(proto_id); + if (descriptor[0] == 'L' || descriptor[0] == '[') { + if (!IsSameDescriptorInDifferentClassContexts(descriptor, klass1, klass2)) { + return false; + } + } + return true; +} + +// Returns true if the descriptor resolves to the same class in the context of klass1 and klass2. +bool ClassLinker::IsSameDescriptorInDifferentClassContexts(const char* descriptor, + const mirror::Class* klass1, + const mirror::Class* klass2) { + CHECK(descriptor != NULL); + CHECK(klass1 != NULL); + CHECK(klass2 != NULL); + if (klass1 == klass2) { + return true; + } + mirror::Class* found1 = FindClass(descriptor, klass1->GetClassLoader()); + if (found1 == NULL) { + Thread::Current()->ClearException(); + } + mirror::Class* found2 = FindClass(descriptor, klass2->GetClassLoader()); + if (found2 == NULL) { + Thread::Current()->ClearException(); + } + return found1 == found2; +} + +bool ClassLinker::InitializeSuperClass(mirror::Class* klass, bool can_run_clinit, bool can_init_fields) { + CHECK(klass != NULL); + if (!klass->IsInterface() && klass->HasSuperClass()) { + mirror::Class* super_class = klass->GetSuperClass(); + if (!super_class->IsInitialized()) { + CHECK(!super_class->IsInterface()); + // Must hold lock on object when initializing and setting status. + Thread* self = Thread::Current(); + ObjectLock lock(self, klass); + bool super_initialized = InitializeClass(super_class, can_run_clinit, can_init_fields); + // TODO: check for a pending exception + if (!super_initialized) { + if (!can_run_clinit) { + // Don't set status to error when we can't run <clinit>. + CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusInitializing) << PrettyClass(klass); + klass->SetStatus(mirror::Class::kStatusVerified); + return false; + } + klass->SetStatus(mirror::Class::kStatusError); + klass->NotifyAll(self); + return false; + } + } + } + return true; +} + +bool ClassLinker::EnsureInitialized(mirror::Class* c, bool can_run_clinit, bool can_init_fields) { + DCHECK(c != NULL); + if (c->IsInitialized()) { + return true; + } + + Thread* self = Thread::Current(); + ScopedThreadStateChange tsc(self, kRunnable); + bool success = InitializeClass(c, can_run_clinit, can_init_fields); + if (!success) { + CHECK(self->IsExceptionPending() || !can_run_clinit) << PrettyClass(c); + } + return success; +} + +void ClassLinker::ConstructFieldMap(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def, + mirror::Class* c, SafeMap<uint32_t, mirror::Field*>& field_map) { + mirror::ClassLoader* cl = c->GetClassLoader(); + const byte* class_data = dex_file.GetClassData(dex_class_def); + ClassDataItemIterator it(dex_file, class_data); + for (size_t i = 0; it.HasNextStaticField(); i++, it.Next()) { + field_map.Put(i, ResolveField(dex_file, it.GetMemberIndex(), c->GetDexCache(), cl, true)); + } +} + +bool ClassLinker::InitializeStaticFields(mirror::Class* klass) { + size_t num_static_fields = klass->NumStaticFields(); + if (num_static_fields == 0) { + return false; + } + mirror::DexCache* dex_cache = klass->GetDexCache(); + // TODO: this seems like the wrong check. do we really want !IsPrimitive && !IsArray? + if (dex_cache == NULL) { + return false; + } + ClassHelper kh(klass); + const DexFile::ClassDef* dex_class_def = kh.GetClassDef(); + CHECK(dex_class_def != NULL); + const DexFile& dex_file = kh.GetDexFile(); + EncodedStaticFieldValueIterator it(dex_file, dex_cache, klass->GetClassLoader(), + this, *dex_class_def); + + if (it.HasNext()) { + // We reordered the fields, so we need to be able to map the field indexes to the right fields. + SafeMap<uint32_t, mirror::Field*> field_map; + ConstructFieldMap(dex_file, *dex_class_def, klass, field_map); + for (size_t i = 0; it.HasNext(); i++, it.Next()) { + it.ReadValueToField(field_map.Get(i)); + } + return true; + } + return false; +} + +bool ClassLinker::LinkClass(SirtRef<mirror::Class>& klass, + mirror::ObjectArray<mirror::Class>* interfaces) { + CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus()); + if (!LinkSuperClass(klass)) { + return false; + } + if (!LinkMethods(klass, interfaces)) { + return false; + } + if (!LinkInstanceFields(klass)) { + return false; + } + if (!LinkStaticFields(klass)) { + return false; + } + CreateReferenceInstanceOffsets(klass); + CreateReferenceStaticOffsets(klass); + CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus()); + klass->SetStatus(mirror::Class::kStatusResolved); + return true; +} + +bool ClassLinker::LoadSuperAndInterfaces(SirtRef<mirror::Class>& klass, const DexFile& dex_file) { + CHECK_EQ(mirror::Class::kStatusIdx, klass->GetStatus()); + StringPiece descriptor(dex_file.StringByTypeIdx(klass->GetDexTypeIndex())); + const DexFile::ClassDef* class_def = dex_file.FindClassDef(descriptor); + CHECK(class_def != NULL); + uint16_t super_class_idx = class_def->superclass_idx_; + if (super_class_idx != DexFile::kDexNoIndex16) { + mirror::Class* super_class = ResolveType(dex_file, super_class_idx, klass.get()); + if (super_class == NULL) { + DCHECK(Thread::Current()->IsExceptionPending()); + return false; + } + // Verify + if (!klass->CanAccess(super_class)) { + ThrowIllegalAccessError(klass.get(), "Class %s extended by class %s is inaccessible", + PrettyDescriptor(super_class).c_str(), + PrettyDescriptor(klass.get()).c_str()); + return false; + } + klass->SetSuperClass(super_class); + } + const DexFile::TypeList* interfaces = dex_file.GetInterfacesList(*class_def); + if (interfaces != NULL) { + for (size_t i = 0; i < interfaces->Size(); i++) { + uint16_t idx = interfaces->GetTypeItem(i).type_idx_; + mirror::Class* interface = ResolveType(dex_file, idx, klass.get()); + if (interface == NULL) { + DCHECK(Thread::Current()->IsExceptionPending()); + return false; + } + // Verify + if (!klass->CanAccess(interface)) { + // TODO: the RI seemed to ignore this in my testing. + ThrowIllegalAccessError(klass.get(), "Interface %s implemented by class %s is inaccessible", + PrettyDescriptor(interface).c_str(), + PrettyDescriptor(klass.get()).c_str()); + return false; + } + } + } + // Mark the class as loaded. + klass->SetStatus(mirror::Class::kStatusLoaded); + return true; +} + +bool ClassLinker::LinkSuperClass(SirtRef<mirror::Class>& klass) { + CHECK(!klass->IsPrimitive()); + mirror::Class* super = klass->GetSuperClass(); + if (klass.get() == GetClassRoot(kJavaLangObject)) { + if (super != NULL) { + ThrowClassFormatError(klass.get(), "java.lang.Object must not have a superclass"); + return false; + } + return true; + } + if (super == NULL) { + ThrowLinkageError(klass.get(), "No superclass defined for class %s", + PrettyDescriptor(klass.get()).c_str()); + return false; + } + // Verify + if (super->IsFinal() || super->IsInterface()) { + ThrowIncompatibleClassChangeError(klass.get(), "Superclass %s of %s is %s", + PrettyDescriptor(super).c_str(), + PrettyDescriptor(klass.get()).c_str(), + super->IsFinal() ? "declared final" : "an interface"); + return false; + } + if (!klass->CanAccess(super)) { + ThrowIllegalAccessError(klass.get(), "Superclass %s is inaccessible to class %s", + PrettyDescriptor(super).c_str(), + PrettyDescriptor(klass.get()).c_str()); + return false; + } + + // Inherit kAccClassIsFinalizable from the superclass in case this class doesn't override finalize. + if (super->IsFinalizable()) { + klass->SetFinalizable(); + } + + // Inherit reference flags (if any) from the superclass. + int reference_flags = (super->GetAccessFlags() & kAccReferenceFlagsMask); + if (reference_flags != 0) { + klass->SetAccessFlags(klass->GetAccessFlags() | reference_flags); + } + // Disallow custom direct subclasses of java.lang.ref.Reference. + if (init_done_ && super == GetClassRoot(kJavaLangRefReference)) { + ThrowLinkageError(klass.get(), + "Class %s attempts to subclass java.lang.ref.Reference, which is not allowed", + PrettyDescriptor(klass.get()).c_str()); + return false; + } + +#ifndef NDEBUG + // Ensure super classes are fully resolved prior to resolving fields.. + while (super != NULL) { + CHECK(super->IsResolved()); + super = super->GetSuperClass(); + } +#endif + return true; +} + +// Populate the class vtable and itable. Compute return type indices. +bool ClassLinker::LinkMethods(SirtRef<mirror::Class>& klass, + mirror::ObjectArray<mirror::Class>* interfaces) { + if (klass->IsInterface()) { + // No vtable. + size_t count = klass->NumVirtualMethods(); + if (!IsUint(16, count)) { + ThrowClassFormatError(klass.get(), "Too many methods on interface: %zd", count); + return false; + } + for (size_t i = 0; i < count; ++i) { + klass->GetVirtualMethodDuringLinking(i)->SetMethodIndex(i); + } + // Link interface method tables + return LinkInterfaceMethods(klass, interfaces); + } else { + // Link virtual and interface method tables + return LinkVirtualMethods(klass) && LinkInterfaceMethods(klass, interfaces); + } + return true; +} + +bool ClassLinker::LinkVirtualMethods(SirtRef<mirror::Class>& klass) { + Thread* self = Thread::Current(); + if (klass->HasSuperClass()) { + uint32_t max_count = klass->NumVirtualMethods() + klass->GetSuperClass()->GetVTable()->GetLength(); + size_t actual_count = klass->GetSuperClass()->GetVTable()->GetLength(); + CHECK_LE(actual_count, max_count); + // TODO: do not assign to the vtable field until it is fully constructed. + SirtRef<mirror::ObjectArray<mirror::AbstractMethod> > + vtable(self, klass->GetSuperClass()->GetVTable()->CopyOf(self, max_count)); + // See if any of our virtual methods override the superclass. + MethodHelper local_mh(NULL, this); + MethodHelper super_mh(NULL, this); + for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) { + mirror::AbstractMethod* local_method = klass->GetVirtualMethodDuringLinking(i); + local_mh.ChangeMethod(local_method); + size_t j = 0; + for (; j < actual_count; ++j) { + mirror::AbstractMethod* super_method = vtable->Get(j); + super_mh.ChangeMethod(super_method); + if (local_mh.HasSameNameAndSignature(&super_mh)) { + if (klass->CanAccessMember(super_method->GetDeclaringClass(), super_method->GetAccessFlags())) { + if (super_method->IsFinal()) { + ThrowLinkageError(klass.get(), "Method %s overrides final method in class %s", + PrettyMethod(local_method).c_str(), + super_mh.GetDeclaringClassDescriptor()); + return false; + } + vtable->Set(j, local_method); + local_method->SetMethodIndex(j); + break; + } else { + LOG(WARNING) << "Before Android 4.1, method " << PrettyMethod(local_method) + << " would have incorrectly overridden the package-private method in " + << PrettyDescriptor(super_mh.GetDeclaringClassDescriptor()); + } + } + } + if (j == actual_count) { + // Not overriding, append. + vtable->Set(actual_count, local_method); + local_method->SetMethodIndex(actual_count); + actual_count += 1; + } + } + if (!IsUint(16, actual_count)) { + ThrowClassFormatError(klass.get(), "Too many methods defined on class: %zd", actual_count); + return false; + } + // Shrink vtable if possible + CHECK_LE(actual_count, max_count); + if (actual_count < max_count) { + vtable.reset(vtable->CopyOf(self, actual_count)); + } + klass->SetVTable(vtable.get()); + } else { + CHECK(klass.get() == GetClassRoot(kJavaLangObject)); + uint32_t num_virtual_methods = klass->NumVirtualMethods(); + if (!IsUint(16, num_virtual_methods)) { + ThrowClassFormatError(klass.get(), "Too many methods: %d", num_virtual_methods); + return false; + } + SirtRef<mirror::ObjectArray<mirror::AbstractMethod> > + vtable(self, AllocMethodArray(self, num_virtual_methods)); + for (size_t i = 0; i < num_virtual_methods; ++i) { + mirror::AbstractMethod* virtual_method = klass->GetVirtualMethodDuringLinking(i); + vtable->Set(i, virtual_method); + virtual_method->SetMethodIndex(i & 0xFFFF); + } + klass->SetVTable(vtable.get()); + } + return true; +} + +bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, + mirror::ObjectArray<mirror::Class>* interfaces) { + size_t super_ifcount; + if (klass->HasSuperClass()) { + super_ifcount = klass->GetSuperClass()->GetIfTableCount(); + } else { + super_ifcount = 0; + } + size_t ifcount = super_ifcount; + ClassHelper kh(klass.get(), this); + uint32_t num_interfaces = interfaces == NULL ? kh.NumDirectInterfaces() : interfaces->GetLength(); + ifcount += num_interfaces; + for (size_t i = 0; i < num_interfaces; i++) { + mirror::Class* interface = interfaces == NULL ? kh.GetDirectInterface(i) : interfaces->Get(i); + ifcount += interface->GetIfTableCount(); + } + if (ifcount == 0) { + // Class implements no interfaces. + DCHECK_EQ(klass->GetIfTableCount(), 0); + DCHECK(klass->GetIfTable() == NULL); + return true; + } + if (ifcount == super_ifcount) { + // Class implements same interfaces as parent, are any of these not marker interfaces? + bool has_non_marker_interface = false; + mirror::IfTable* super_iftable = klass->GetSuperClass()->GetIfTable(); + for (size_t i = 0; i < ifcount; ++i) { + if (super_iftable->GetMethodArrayCount(i) > 0) { + has_non_marker_interface = true; + break; + } + } + if (!has_non_marker_interface) { + // Class just inherits marker interfaces from parent so recycle parent's iftable. + klass->SetIfTable(super_iftable); + return true; + } + } + Thread* self = Thread::Current(); + SirtRef<mirror::IfTable> iftable(self, AllocIfTable(self, ifcount)); + if (super_ifcount != 0) { + mirror::IfTable* super_iftable = klass->GetSuperClass()->GetIfTable(); + for (size_t i = 0; i < super_ifcount; i++) { + mirror::Class* super_interface = super_iftable->GetInterface(i); + iftable->SetInterface(i, super_interface); + } + } + // Flatten the interface inheritance hierarchy. + size_t idx = super_ifcount; + for (size_t i = 0; i < num_interfaces; i++) { + mirror::Class* interface = interfaces == NULL ? kh.GetDirectInterface(i) : interfaces->Get(i); + DCHECK(interface != NULL); + if (!interface->IsInterface()) { + ClassHelper ih(interface); + ThrowIncompatibleClassChangeError(klass.get(), "Class %s implements non-interface class %s", + PrettyDescriptor(klass.get()).c_str(), + PrettyDescriptor(ih.GetDescriptor()).c_str()); + return false; + } + // Check if interface is already in iftable + bool duplicate = false; + for (size_t j = 0; j < idx; j++) { + mirror::Class* existing_interface = iftable->GetInterface(j); + if (existing_interface == interface) { + duplicate = true; + break; + } + } + if (!duplicate) { + // Add this non-duplicate interface. + iftable->SetInterface(idx++, interface); + // Add this interface's non-duplicate super-interfaces. + for (int32_t j = 0; j < interface->GetIfTableCount(); j++) { + mirror::Class* super_interface = interface->GetIfTable()->GetInterface(j); + bool super_duplicate = false; + for (size_t k = 0; k < idx; k++) { + mirror::Class* existing_interface = iftable->GetInterface(k); + if (existing_interface == super_interface) { + super_duplicate = true; + break; + } + } + if (!super_duplicate) { + iftable->SetInterface(idx++, super_interface); + } + } + } + } + // Shrink iftable in case duplicates were found + if (idx < ifcount) { + iftable.reset(down_cast<mirror::IfTable*>(iftable->CopyOf(self, idx * mirror::IfTable::kMax))); + ifcount = idx; + } else { + CHECK_EQ(idx, ifcount); + } + klass->SetIfTable(iftable.get()); + + // If we're an interface, we don't need the vtable pointers, so we're done. + if (klass->IsInterface()) { + return true; + } + std::vector<mirror::AbstractMethod*> miranda_list; + MethodHelper vtable_mh(NULL, this); + MethodHelper interface_mh(NULL, this); + for (size_t i = 0; i < ifcount; ++i) { + mirror::Class* interface = iftable->GetInterface(i); + size_t num_methods = interface->NumVirtualMethods(); + if (num_methods > 0) { + mirror::ObjectArray<mirror::AbstractMethod>* method_array = + AllocMethodArray(self, num_methods); + iftable->SetMethodArray(i, method_array); + mirror::ObjectArray<mirror::AbstractMethod>* vtable = klass->GetVTableDuringLinking(); + for (size_t j = 0; j < num_methods; ++j) { + mirror::AbstractMethod* interface_method = interface->GetVirtualMethod(j); + interface_mh.ChangeMethod(interface_method); + int32_t k; + // For each method listed in the interface's method list, find the + // matching method in our class's method list. We want to favor the + // subclass over the superclass, which just requires walking + // back from the end of the vtable. (This only matters if the + // superclass defines a private method and this class redefines + // it -- otherwise it would use the same vtable slot. In .dex files + // those don't end up in the virtual method table, so it shouldn't + // matter which direction we go. We walk it backward anyway.) + for (k = vtable->GetLength() - 1; k >= 0; --k) { + mirror::AbstractMethod* vtable_method = vtable->Get(k); + vtable_mh.ChangeMethod(vtable_method); + if (interface_mh.HasSameNameAndSignature(&vtable_mh)) { + if (!vtable_method->IsAbstract() && !vtable_method->IsPublic()) { + ThrowIllegalAccessError(klass.get(), + "Method '%s' implementing interface method '%s' is not public", + PrettyMethod(vtable_method).c_str(), + PrettyMethod(interface_method).c_str()); + return false; + } + method_array->Set(j, vtable_method); + break; + } + } + if (k < 0) { + SirtRef<mirror::AbstractMethod> miranda_method(self, NULL); + for (size_t mir = 0; mir < miranda_list.size(); mir++) { + mirror::AbstractMethod* mir_method = miranda_list[mir]; + vtable_mh.ChangeMethod(mir_method); + if (interface_mh.HasSameNameAndSignature(&vtable_mh)) { + miranda_method.reset(miranda_list[mir]); + break; + } + } + if (miranda_method.get() == NULL) { + // point the interface table at a phantom slot + miranda_method.reset(down_cast<mirror::AbstractMethod*>(interface_method->Clone(self))); + miranda_list.push_back(miranda_method.get()); + } + method_array->Set(j, miranda_method.get()); + } + } + } + } + if (!miranda_list.empty()) { + int old_method_count = klass->NumVirtualMethods(); + int new_method_count = old_method_count + miranda_list.size(); + klass->SetVirtualMethods((old_method_count == 0) + ? AllocMethodArray(self, new_method_count) + : klass->GetVirtualMethods()->CopyOf(self, new_method_count)); + + SirtRef<mirror::ObjectArray<mirror::AbstractMethod> > + vtable(self, klass->GetVTableDuringLinking()); + CHECK(vtable.get() != NULL); + int old_vtable_count = vtable->GetLength(); + int new_vtable_count = old_vtable_count + miranda_list.size(); + vtable.reset(vtable->CopyOf(self, new_vtable_count)); + for (size_t i = 0; i < miranda_list.size(); ++i) { + mirror::AbstractMethod* method = miranda_list[i]; + // Leave the declaring class alone as type indices are relative to it + method->SetAccessFlags(method->GetAccessFlags() | kAccMiranda); + method->SetMethodIndex(0xFFFF & (old_vtable_count + i)); + klass->SetVirtualMethod(old_method_count + i, method); + vtable->Set(old_vtable_count + i, method); + } + // TODO: do not assign to the vtable field until it is fully constructed. + klass->SetVTable(vtable.get()); + } + + mirror::ObjectArray<mirror::AbstractMethod>* vtable = klass->GetVTableDuringLinking(); + for (int i = 0; i < vtable->GetLength(); ++i) { + CHECK(vtable->Get(i) != NULL); + } + +// klass->DumpClass(std::cerr, Class::kDumpClassFullDetail); + + return true; +} + +bool ClassLinker::LinkInstanceFields(SirtRef<mirror::Class>& klass) { + CHECK(klass.get() != NULL); + return LinkFields(klass, false); +} + +bool ClassLinker::LinkStaticFields(SirtRef<mirror::Class>& klass) { + CHECK(klass.get() != NULL); + size_t allocated_class_size = klass->GetClassSize(); + bool success = LinkFields(klass, true); + CHECK_EQ(allocated_class_size, klass->GetClassSize()); + return success; +} + +struct LinkFieldsComparator { + explicit LinkFieldsComparator(FieldHelper* fh) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) + : fh_(fh) {} + // No thread safety analysis as will be called from STL. Checked lock held in constructor. + bool operator()(const mirror::Field* field1, const mirror::Field* field2) + NO_THREAD_SAFETY_ANALYSIS { + // First come reference fields, then 64-bit, and finally 32-bit + fh_->ChangeField(field1); + Primitive::Type type1 = fh_->GetTypeAsPrimitiveType(); + fh_->ChangeField(field2); + Primitive::Type type2 = fh_->GetTypeAsPrimitiveType(); + bool isPrimitive1 = type1 != Primitive::kPrimNot; + bool isPrimitive2 = type2 != Primitive::kPrimNot; + bool is64bit1 = isPrimitive1 && (type1 == Primitive::kPrimLong || type1 == Primitive::kPrimDouble); + bool is64bit2 = isPrimitive2 && (type2 == Primitive::kPrimLong || type2 == Primitive::kPrimDouble); + int order1 = (!isPrimitive1 ? 0 : (is64bit1 ? 1 : 2)); + int order2 = (!isPrimitive2 ? 0 : (is64bit2 ? 1 : 2)); + if (order1 != order2) { + return order1 < order2; + } + + // same basic group? then sort by string. + fh_->ChangeField(field1); + StringPiece name1(fh_->GetName()); + fh_->ChangeField(field2); + StringPiece name2(fh_->GetName()); + return name1 < name2; + } + + FieldHelper* fh_; +}; + +bool ClassLinker::LinkFields(SirtRef<mirror::Class>& klass, bool is_static) { + size_t num_fields = + is_static ? klass->NumStaticFields() : klass->NumInstanceFields(); + + mirror::ObjectArray<mirror::Field>* fields = + is_static ? klass->GetSFields() : klass->GetIFields(); + + // Initialize size and field_offset + size_t size; + MemberOffset field_offset(0); + if (is_static) { + size = klass->GetClassSize(); + field_offset = mirror::Class::FieldsOffset(); + } else { + mirror::Class* super_class = klass->GetSuperClass(); + if (super_class != NULL) { + CHECK(super_class->IsResolved()); + field_offset = MemberOffset(super_class->GetObjectSize()); + } + size = field_offset.Uint32Value(); + } + + CHECK_EQ(num_fields == 0, fields == NULL); + + // we want a relatively stable order so that adding new fields + // minimizes disruption of C++ version such as Class and Method. + std::deque<mirror::Field*> grouped_and_sorted_fields; + for (size_t i = 0; i < num_fields; i++) { + grouped_and_sorted_fields.push_back(fields->Get(i)); + } + FieldHelper fh(NULL, this); + std::sort(grouped_and_sorted_fields.begin(), + grouped_and_sorted_fields.end(), + LinkFieldsComparator(&fh)); + + // References should be at the front. + size_t current_field = 0; + size_t num_reference_fields = 0; + for (; current_field < num_fields; current_field++) { + mirror::Field* field = grouped_and_sorted_fields.front(); + fh.ChangeField(field); + Primitive::Type type = fh.GetTypeAsPrimitiveType(); + bool isPrimitive = type != Primitive::kPrimNot; + if (isPrimitive) { + break; // past last reference, move on to the next phase + } + grouped_and_sorted_fields.pop_front(); + num_reference_fields++; + fields->Set(current_field, field); + field->SetOffset(field_offset); + field_offset = MemberOffset(field_offset.Uint32Value() + sizeof(uint32_t)); + } + + // Now we want to pack all of the double-wide fields together. If + // we're not aligned, though, we want to shuffle one 32-bit field + // into place. If we can't find one, we'll have to pad it. + if (current_field != num_fields && !IsAligned<8>(field_offset.Uint32Value())) { + for (size_t i = 0; i < grouped_and_sorted_fields.size(); i++) { + mirror::Field* field = grouped_and_sorted_fields[i]; + fh.ChangeField(field); + Primitive::Type type = fh.GetTypeAsPrimitiveType(); + CHECK(type != Primitive::kPrimNot); // should only be working on primitive types + if (type == Primitive::kPrimLong || type == Primitive::kPrimDouble) { + continue; + } + fields->Set(current_field++, field); + field->SetOffset(field_offset); + // drop the consumed field + grouped_and_sorted_fields.erase(grouped_and_sorted_fields.begin() + i); + break; + } + // whether we found a 32-bit field for padding or not, we advance + field_offset = MemberOffset(field_offset.Uint32Value() + sizeof(uint32_t)); + } + + // Alignment is good, shuffle any double-wide fields forward, and + // finish assigning field offsets to all fields. + DCHECK(current_field == num_fields || IsAligned<8>(field_offset.Uint32Value())); + while (!grouped_and_sorted_fields.empty()) { + mirror::Field* field = grouped_and_sorted_fields.front(); + grouped_and_sorted_fields.pop_front(); + fh.ChangeField(field); + Primitive::Type type = fh.GetTypeAsPrimitiveType(); + CHECK(type != Primitive::kPrimNot); // should only be working on primitive types + fields->Set(current_field, field); + field->SetOffset(field_offset); + field_offset = MemberOffset(field_offset.Uint32Value() + + ((type == Primitive::kPrimLong || type == Primitive::kPrimDouble) + ? sizeof(uint64_t) + : sizeof(uint32_t))); + current_field++; + } + + // We lie to the GC about the java.lang.ref.Reference.referent field, so it doesn't scan it. + if (!is_static && + StringPiece(ClassHelper(klass.get(), this).GetDescriptor()) == "Ljava/lang/ref/Reference;") { + // We know there are no non-reference fields in the Reference classes, and we know + // that 'referent' is alphabetically last, so this is easy... + CHECK_EQ(num_reference_fields, num_fields); + fh.ChangeField(fields->Get(num_fields - 1)); + CHECK_STREQ(fh.GetName(), "referent"); + --num_reference_fields; + } + +#ifndef NDEBUG + // Make sure that all reference fields appear before + // non-reference fields, and all double-wide fields are aligned. + bool seen_non_ref = false; + for (size_t i = 0; i < num_fields; i++) { + mirror::Field* field = fields->Get(i); + if (false) { // enable to debug field layout + LOG(INFO) << "LinkFields: " << (is_static ? "static" : "instance") + << " class=" << PrettyClass(klass.get()) + << " field=" << PrettyField(field) + << " offset=" << field->GetField32(MemberOffset(mirror::Field::OffsetOffset()), + false); + } + fh.ChangeField(field); + Primitive::Type type = fh.GetTypeAsPrimitiveType(); + bool is_primitive = type != Primitive::kPrimNot; + if (StringPiece(ClassHelper(klass.get(), this).GetDescriptor()) == "Ljava/lang/ref/Reference;" && + StringPiece(fh.GetName()) == "referent") { + is_primitive = true; // We lied above, so we have to expect a lie here. + } + if (is_primitive) { + if (!seen_non_ref) { + seen_non_ref = true; + DCHECK_EQ(num_reference_fields, i); + } + } else { + DCHECK(!seen_non_ref); + } + } + if (!seen_non_ref) { + DCHECK_EQ(num_fields, num_reference_fields); + } +#endif + size = field_offset.Uint32Value(); + // Update klass + if (is_static) { + klass->SetNumReferenceStaticFields(num_reference_fields); + klass->SetClassSize(size); + } else { + klass->SetNumReferenceInstanceFields(num_reference_fields); + if (!klass->IsVariableSize()) { + DCHECK_GE(size, sizeof(mirror::Object)) << ClassHelper(klass.get(), this).GetDescriptor(); + klass->SetObjectSize(size); + } + } + return true; +} + +// Set the bitmap of reference offsets, refOffsets, from the ifields +// list. +void ClassLinker::CreateReferenceInstanceOffsets(SirtRef<mirror::Class>& klass) { + uint32_t reference_offsets = 0; + mirror::Class* super_class = klass->GetSuperClass(); + if (super_class != NULL) { + reference_offsets = super_class->GetReferenceInstanceOffsets(); + // If our superclass overflowed, we don't stand a chance. + if (reference_offsets == CLASS_WALK_SUPER) { + klass->SetReferenceInstanceOffsets(reference_offsets); + return; + } + } + CreateReferenceOffsets(klass, false, reference_offsets); +} + +void ClassLinker::CreateReferenceStaticOffsets(SirtRef<mirror::Class>& klass) { + CreateReferenceOffsets(klass, true, 0); +} + +void ClassLinker::CreateReferenceOffsets(SirtRef<mirror::Class>& klass, bool is_static, + uint32_t reference_offsets) { + size_t num_reference_fields = + is_static ? klass->NumReferenceStaticFieldsDuringLinking() + : klass->NumReferenceInstanceFieldsDuringLinking(); + const mirror::ObjectArray<mirror::Field>* fields = + is_static ? klass->GetSFields() : klass->GetIFields(); + // All of the fields that contain object references are guaranteed + // to be at the beginning of the fields list. + for (size_t i = 0; i < num_reference_fields; ++i) { + // Note that byte_offset is the offset from the beginning of + // object, not the offset into instance data + const mirror::Field* field = fields->Get(i); + MemberOffset byte_offset = field->GetOffsetDuringLinking(); + CHECK_EQ(byte_offset.Uint32Value() & (CLASS_OFFSET_ALIGNMENT - 1), 0U); + if (CLASS_CAN_ENCODE_OFFSET(byte_offset.Uint32Value())) { + uint32_t new_bit = CLASS_BIT_FROM_OFFSET(byte_offset.Uint32Value()); + CHECK_NE(new_bit, 0U); + reference_offsets |= new_bit; + } else { + reference_offsets = CLASS_WALK_SUPER; + break; + } + } + // Update fields in klass + if (is_static) { + klass->SetReferenceStaticOffsets(reference_offsets); + } else { + klass->SetReferenceInstanceOffsets(reference_offsets); + } +} + +mirror::String* ClassLinker::ResolveString(const DexFile& dex_file, + uint32_t string_idx, mirror::DexCache* dex_cache) { + DCHECK(dex_cache != NULL); + mirror::String* resolved = dex_cache->GetResolvedString(string_idx); + if (resolved != NULL) { + return resolved; + } + const DexFile::StringId& string_id = dex_file.GetStringId(string_idx); + int32_t utf16_length = dex_file.GetStringLength(string_id); + const char* utf8_data = dex_file.GetStringData(string_id); + mirror::String* string = intern_table_->InternStrong(utf16_length, utf8_data); + dex_cache->SetResolvedString(string_idx, string); + return string; +} + +mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, + uint16_t type_idx, + mirror::DexCache* dex_cache, + mirror::ClassLoader* class_loader) { + DCHECK(dex_cache != NULL); + mirror::Class* resolved = dex_cache->GetResolvedType(type_idx); + if (resolved == NULL) { + const char* descriptor = dex_file.StringByTypeIdx(type_idx); + resolved = FindClass(descriptor, class_loader); + if (resolved != NULL) { + // TODO: we used to throw here if resolved's class loader was not the + // boot class loader. This was to permit different classes with the + // same name to be loaded simultaneously by different loaders + dex_cache->SetResolvedType(type_idx, resolved); + } else { + Thread* self = Thread::Current(); + CHECK(self->IsExceptionPending()) + << "Expected pending exception for failed resolution of: " << descriptor; + // Convert a ClassNotFoundException to a NoClassDefFoundError. + SirtRef<mirror::Throwable> cause(self, self->GetException(NULL)); + if (cause->InstanceOf(GetClassRoot(kJavaLangClassNotFoundException))) { + Thread::Current()->ClearException(); + ThrowNoClassDefFoundError("Failed resolution of: %s", descriptor); + self->GetException(NULL)->SetCause(cause.get()); + } + } + } + return resolved; +} + +mirror::AbstractMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, + uint32_t method_idx, + mirror::DexCache* dex_cache, + mirror::ClassLoader* class_loader, + const mirror::AbstractMethod* referrer, + InvokeType type) { + DCHECK(dex_cache != NULL); + // Check for hit in the dex cache. + mirror::AbstractMethod* resolved = dex_cache->GetResolvedMethod(method_idx); + if (resolved != NULL) { + return resolved; + } + // Fail, get the declaring class. + const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); + mirror::Class* klass = ResolveType(dex_file, method_id.class_idx_, dex_cache, class_loader); + if (klass == NULL) { + DCHECK(Thread::Current()->IsExceptionPending()); + return NULL; + } + // Scan using method_idx, this saves string compares but will only hit for matching dex + // caches/files. + switch (type) { + case kDirect: // Fall-through. + case kStatic: + resolved = klass->FindDirectMethod(dex_cache, method_idx); + break; + case kInterface: + resolved = klass->FindInterfaceMethod(dex_cache, method_idx); + DCHECK(resolved == NULL || resolved->GetDeclaringClass()->IsInterface()); + break; + case kSuper: // Fall-through. + case kVirtual: + resolved = klass->FindVirtualMethod(dex_cache, method_idx); + break; + default: + LOG(FATAL) << "Unreachable - invocation type: " << type; + } + if (resolved == NULL) { + // Search by name, which works across dex files. + const char* name = dex_file.StringDataByIdx(method_id.name_idx_); + std::string signature(dex_file.CreateMethodSignature(method_id.proto_idx_, NULL)); + switch (type) { + case kDirect: // Fall-through. + case kStatic: + resolved = klass->FindDirectMethod(name, signature); + break; + case kInterface: + resolved = klass->FindInterfaceMethod(name, signature); + DCHECK(resolved == NULL || resolved->GetDeclaringClass()->IsInterface()); + break; + case kSuper: // Fall-through. + case kVirtual: + resolved = klass->FindVirtualMethod(name, signature); + break; + } + } + if (resolved != NULL) { + // We found a method, check for incompatible class changes. + if (resolved->CheckIncompatibleClassChange(type)) { + resolved = NULL; + } + } + if (resolved != NULL) { + // Be a good citizen and update the dex cache to speed subsequent calls. + dex_cache->SetResolvedMethod(method_idx, resolved); + return resolved; + } else { + // We failed to find the method which means either an access error, an incompatible class + // change, or no such method. First try to find the method among direct and virtual methods. + const char* name = dex_file.StringDataByIdx(method_id.name_idx_); + std::string signature(dex_file.CreateMethodSignature(method_id.proto_idx_, NULL)); + switch (type) { + case kDirect: + case kStatic: + resolved = klass->FindVirtualMethod(name, signature); + break; + case kInterface: + case kVirtual: + case kSuper: + resolved = klass->FindDirectMethod(name, signature); + break; + } + + // If we found something, check that it can be accessed by the referrer. + if (resolved != NULL && referrer != NULL) { + mirror::Class* methods_class = resolved->GetDeclaringClass(); + mirror::Class* referring_class = referrer->GetDeclaringClass(); + if (!referring_class->CanAccess(methods_class)) { + ThrowIllegalAccessErrorClassForMethodDispatch(referring_class, methods_class, + referrer, resolved, type); + return NULL; + } else if (!referring_class->CanAccessMember(methods_class, + resolved->GetAccessFlags())) { + ThrowIllegalAccessErrorMethod(referring_class, resolved); + return NULL; + } + } + + // Otherwise, throw an IncompatibleClassChangeError if we found something, and check interface + // methods and throw if we find the method there. If we find nothing, throw a NoSuchMethodError. + switch (type) { + case kDirect: + case kStatic: + if (resolved != NULL) { + ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer); + } else { + resolved = klass->FindInterfaceMethod(name, signature); + if (resolved != NULL) { + ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer); + } else { + ThrowNoSuchMethodError(type, klass, name, signature); + } + } + break; + case kInterface: + if (resolved != NULL) { + ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer); + } else { + resolved = klass->FindVirtualMethod(name, signature); + if (resolved != NULL) { + ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer); + } else { + ThrowNoSuchMethodError(type, klass, name, signature); + } + } + break; + case kSuper: + ThrowNoSuchMethodError(type, klass, name, signature); + break; + case kVirtual: + if (resolved != NULL) { + ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer); + } else { + resolved = klass->FindInterfaceMethod(name, signature); + if (resolved != NULL) { + ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer); + } else { + ThrowNoSuchMethodError(type, klass, name, signature); + } + } + break; + } + DCHECK(Thread::Current()->IsExceptionPending()); + return NULL; + } +} + +mirror::Field* ClassLinker::ResolveField(const DexFile& dex_file, + uint32_t field_idx, + mirror::DexCache* dex_cache, + mirror::ClassLoader* class_loader, + bool is_static) { + DCHECK(dex_cache != NULL); + mirror::Field* resolved = dex_cache->GetResolvedField(field_idx); + if (resolved != NULL) { + return resolved; + } + const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx); + mirror::Class* klass = ResolveType(dex_file, field_id.class_idx_, dex_cache, class_loader); + if (klass == NULL) { + DCHECK(Thread::Current()->IsExceptionPending()); + return NULL; + } + + if (is_static) { + resolved = klass->FindStaticField(dex_cache, field_idx); + } else { + resolved = klass->FindInstanceField(dex_cache, field_idx); + } + + if (resolved == NULL) { + const char* name = dex_file.GetFieldName(field_id); + const char* type = dex_file.GetFieldTypeDescriptor(field_id); + if (is_static) { + resolved = klass->FindStaticField(name, type); + } else { + resolved = klass->FindInstanceField(name, type); + } + if (resolved == NULL) { + ThrowNoSuchFieldError(is_static ? "static " : "instance ", klass, type, name); + return NULL; + } + } + dex_cache->SetResolvedField(field_idx, resolved); + return resolved; +} + +mirror::Field* ClassLinker::ResolveFieldJLS(const DexFile& dex_file, + uint32_t field_idx, + mirror::DexCache* dex_cache, + mirror::ClassLoader* class_loader) { + DCHECK(dex_cache != NULL); + mirror::Field* resolved = dex_cache->GetResolvedField(field_idx); + if (resolved != NULL) { + return resolved; + } + const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx); + mirror::Class* klass = ResolveType(dex_file, field_id.class_idx_, dex_cache, class_loader); + if (klass == NULL) { + DCHECK(Thread::Current()->IsExceptionPending()); + return NULL; + } + + const char* name = dex_file.GetFieldName(field_id); + const char* type = dex_file.GetFieldTypeDescriptor(field_id); + resolved = klass->FindField(name, type); + if (resolved != NULL) { + dex_cache->SetResolvedField(field_idx, resolved); + } else { + ThrowNoSuchFieldError("", klass, type, name); + } + return resolved; +} + +const char* ClassLinker::MethodShorty(uint32_t method_idx, mirror::AbstractMethod* referrer, + uint32_t* length) { + mirror::Class* declaring_class = referrer->GetDeclaringClass(); + mirror::DexCache* dex_cache = declaring_class->GetDexCache(); + const DexFile& dex_file = *dex_cache->GetDexFile(); + const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); + return dex_file.GetMethodShorty(method_id, length); +} + +void ClassLinker::DumpAllClasses(int flags) const { + // TODO: at the time this was written, it wasn't safe to call PrettyField with the ClassLinker + // lock held, because it might need to resolve a field's type, which would try to take the lock. + std::vector<mirror::Class*> all_classes; + { + ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + typedef Table::const_iterator It; // TODO: C++0x auto + for (It it = classes_.begin(), end = classes_.end(); it != end; ++it) { + all_classes.push_back(it->second); + } + for (It it = image_classes_.begin(), end = image_classes_.end(); it != end; ++it) { + all_classes.push_back(it->second); + } + } + + for (size_t i = 0; i < all_classes.size(); ++i) { + all_classes[i]->DumpClass(std::cerr, flags); + } +} + +void ClassLinker::DumpForSigQuit(std::ostream& os) const { + ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + os << "Loaded classes: " << image_classes_.size() << " image classes; " + << classes_.size() << " allocated classes\n"; +} + +size_t ClassLinker::NumLoadedClasses() const { + ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + return classes_.size() + image_classes_.size(); +} + +pid_t ClassLinker::GetClassesLockOwner() { + return Locks::classlinker_classes_lock_->GetExclusiveOwnerTid(); +} + +pid_t ClassLinker::GetDexLockOwner() { + return dex_lock_.GetExclusiveOwnerTid(); +} + +void ClassLinker::SetClassRoot(ClassRoot class_root, mirror::Class* klass) { + DCHECK(!init_done_); + + DCHECK(klass != NULL); + DCHECK(klass->GetClassLoader() == NULL); + + DCHECK(class_roots_ != NULL); + DCHECK(class_roots_->Get(class_root) == NULL); + class_roots_->Set(class_root, klass); +} + +} // namespace art |