diff options
Diffstat (limited to 'src/class_linker.cc')
| -rw-r--r-- | src/class_linker.cc | 3959 |
1 files changed, 0 insertions, 3959 deletions
diff --git a/src/class_linker.cc b/src/class_linker.cc deleted file mode 100644 index 8ea4295702..0000000000 --- a/src/class_linker.cc +++ /dev/null @@ -1,3959 +0,0 @@ -/* - * 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 |