diff options
29 files changed, 431 insertions, 395 deletions
diff --git a/libprofile/profile/profile_compilation_info_test.cc b/libprofile/profile/profile_compilation_info_test.cc index ead7cba60b..42c3320ea5 100644 --- a/libprofile/profile/profile_compilation_info_test.cc +++ b/libprofile/profile/profile_compilation_info_test.cc @@ -17,20 +17,14 @@ #include <gtest/gtest.h> #include <stdio.h> -#include "art_method-inl.h" +#include "base/arena_allocator.h" +#include "base/common_art_test.h" #include "base/unix_file/fd_file.h" -#include "class_linker-inl.h" -#include "common_runtime_test.h" #include "dex/dex_file.h" #include "dex/dex_file_loader.h" #include "dex/method_reference.h" #include "dex/type_reference.h" -#include "handle_scope-inl.h" -#include "linear_alloc.h" -#include "mirror/class-inl.h" -#include "mirror/class_loader.h" #include "profile/profile_compilation_info.h" -#include "scoped_thread_state_change-inl.h" #include "ziparchive/zip_writer.h" namespace art { @@ -39,31 +33,14 @@ using Hotness = ProfileCompilationInfo::MethodHotness; static constexpr size_t kMaxMethodIds = 65535; -class ProfileCompilationInfoTest : public CommonRuntimeTest { +class ProfileCompilationInfoTest : public CommonArtTest { public: - void PostRuntimeCreate() OVERRIDE { - allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool())); + void SetUp() OVERRIDE { + CommonArtTest::SetUp(); + allocator_.reset(new ArenaAllocator(&pool_)); } protected: - std::vector<ArtMethod*> GetVirtualMethods(jobject class_loader, - const std::string& clazz) { - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - Thread* self = Thread::Current(); - ScopedObjectAccess soa(self); - StackHandleScope<1> hs(self); - Handle<mirror::ClassLoader> h_loader( - hs.NewHandle(self->DecodeJObject(class_loader)->AsClassLoader())); - ObjPtr<mirror::Class> klass = class_linker->FindClass(self, clazz.c_str(), h_loader); - - const auto pointer_size = class_linker->GetImagePointerSize(); - std::vector<ArtMethod*> methods; - for (auto& m : klass->GetVirtualMethods(pointer_size)) { - methods.push_back(&m); - } - return methods; - } - bool AddMethod(const std::string& dex_location, uint32_t checksum, uint16_t method_index, @@ -97,89 +74,6 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { return static_cast<uint32_t>(file.GetFd()); } - bool SaveProfilingInfo( - const std::string& filename, - const std::vector<ArtMethod*>& methods, - const std::set<DexCacheResolvedClasses>& resolved_classes, - Hotness::Flag flags) { - ProfileCompilationInfo info; - std::vector<ProfileMethodInfo> profile_methods; - ScopedObjectAccess soa(Thread::Current()); - for (ArtMethod* method : methods) { - profile_methods.emplace_back( - MethodReference(method->GetDexFile(), method->GetDexMethodIndex())); - } - if (!info.AddMethods(profile_methods, flags) || !info.AddClasses(resolved_classes)) { - return false; - } - if (info.GetNumberOfMethods() != profile_methods.size()) { - return false; - } - ProfileCompilationInfo file_profile; - if (!file_profile.Load(filename, false)) { - return false; - } - if (!info.MergeWith(file_profile)) { - return false; - } - - return info.Save(filename, nullptr); - } - - // Saves the given art methods to a profile backed by 'filename' and adds - // some fake inline caches to it. The added inline caches are returned in - // the out map `profile_methods_map`. - bool SaveProfilingInfoWithFakeInlineCaches( - const std::string& filename, - const std::vector<ArtMethod*>& methods, - Hotness::Flag flags, - /*out*/ SafeMap<ArtMethod*, ProfileMethodInfo>* profile_methods_map) { - ProfileCompilationInfo info; - std::vector<ProfileMethodInfo> profile_methods; - ScopedObjectAccess soa(Thread::Current()); - for (ArtMethod* method : methods) { - std::vector<ProfileMethodInfo::ProfileInlineCache> caches; - // Monomorphic - for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) { - std::vector<TypeReference> classes; - classes.emplace_back(method->GetDexFile(), dex::TypeIndex(0)); - caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); - } - // Polymorphic - for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) { - std::vector<TypeReference> classes; - for (uint16_t k = 0; k < InlineCache::kIndividualCacheSize / 2; k++) { - classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k)); - } - caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); - } - // Megamorphic - for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) { - std::vector<TypeReference> classes; - for (uint16_t k = 0; k < 2 * InlineCache::kIndividualCacheSize; k++) { - classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k)); - } - caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); - } - // Missing types - for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) { - std::vector<TypeReference> classes; - caches.emplace_back(dex_pc, /*is_missing_types*/true, classes); - } - ProfileMethodInfo pmi(MethodReference(method->GetDexFile(), - method->GetDexMethodIndex()), - caches); - profile_methods.push_back(pmi); - profile_methods_map->Put(method, pmi); - } - - if (!info.AddMethods(profile_methods, flags) - || info.GetNumberOfMethods() != profile_methods.size()) { - return false; - } - return info.Save(filename, nullptr); - } - // Creates an inline cache which will be destructed at the end of the test. ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() { used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap( @@ -187,35 +81,6 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { return used_inline_caches.back().get(); } - ProfileCompilationInfo::OfflineProfileMethodInfo ConvertProfileMethodInfo( - const ProfileMethodInfo& pmi) { - ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap(); - ProfileCompilationInfo::OfflineProfileMethodInfo offline_pmi(ic_map); - SafeMap<DexFile*, uint8_t> dex_map; // dex files to profile index - for (const auto& inline_cache : pmi.inline_caches) { - ProfileCompilationInfo::DexPcData& dex_pc_data = - ic_map->FindOrAdd( - inline_cache.dex_pc, ProfileCompilationInfo::DexPcData(allocator_.get()))->second; - if (inline_cache.is_missing_types) { - dex_pc_data.SetIsMissingTypes(); - } - for (const auto& class_ref : inline_cache.classes) { - uint8_t dex_profile_index = dex_map.FindOrAdd(const_cast<DexFile*>(class_ref.dex_file), - static_cast<uint8_t>(dex_map.size()))->second; - dex_pc_data.AddClass(dex_profile_index, class_ref.TypeIndex()); - if (dex_profile_index >= offline_pmi.dex_references.size()) { - // This is a new dex. - const std::string& dex_key = ProfileCompilationInfo::GetProfileDexFileKey( - class_ref.dex_file->GetLocation()); - offline_pmi.dex_references.emplace_back(dex_key, - class_ref.dex_file->GetLocationChecksum(), - class_ref.dex_file->NumMethodIds()); - } - } - } - return offline_pmi; - } - // Creates an offline profile used for testing inline caches. ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo() { ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap(); @@ -261,7 +126,7 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { ProfileCompilationInfo::InlineCacheMap* ic_map = const_cast<ProfileCompilationInfo::InlineCacheMap*>(pmi->inline_caches); for (auto it : *ic_map) { - for (uint16_t k = 0; k <= 2 * InlineCache::kIndividualCacheSize; k++) { + for (uint16_t k = 0; k <= 2 * ProfileCompilationInfo::kIndividualInlineCacheSize; k++) { it.second.AddClass(0, dex::TypeIndex(k)); } } @@ -327,6 +192,7 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { static constexpr int kProfileMagicSize = 4; static constexpr int kProfileVersionSize = 4; + MallocArenaPool pool_; std::unique_ptr<ArenaAllocator> allocator_; // Cache of inline caches generated during tests. @@ -335,61 +201,6 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches; }; -TEST_F(ProfileCompilationInfoTest, SaveArtMethods) { - ScratchFile profile; - - Thread* self = Thread::Current(); - jobject class_loader; - { - ScopedObjectAccess soa(self); - class_loader = LoadDex("ProfileTestMultiDex"); - } - ASSERT_NE(class_loader, nullptr); - - // Save virtual methods from Main. - std::set<DexCacheResolvedClasses> resolved_classes; - std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;"); - ASSERT_TRUE(SaveProfilingInfo( - profile.GetFilename(), main_methods, resolved_classes, Hotness::kFlagPostStartup)); - - // Check that what we saved is in the profile. - ProfileCompilationInfo info1; - ASSERT_TRUE(info1.Load(GetFd(profile))); - ASSERT_EQ(info1.GetNumberOfMethods(), main_methods.size()); - { - ScopedObjectAccess soa(self); - for (ArtMethod* m : main_methods) { - Hotness h = info1.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); - ASSERT_TRUE(h.IsHot()); - ASSERT_TRUE(h.IsPostStartup()); - } - } - - // Save virtual methods from Second. - std::vector<ArtMethod*> second_methods = GetVirtualMethods(class_loader, "LSecond;"); - ASSERT_TRUE(SaveProfilingInfo( - profile.GetFilename(), second_methods, resolved_classes, Hotness::kFlagStartup)); - - // Check that what we saved is in the profile (methods form Main and Second). - ProfileCompilationInfo info2; - ASSERT_TRUE(profile.GetFile()->ResetOffset()); - ASSERT_TRUE(info2.Load(GetFd(profile))); - ASSERT_EQ(info2.GetNumberOfMethods(), main_methods.size() + second_methods.size()); - { - ScopedObjectAccess soa(self); - for (ArtMethod* m : main_methods) { - Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); - ASSERT_TRUE(h.IsHot()); - ASSERT_TRUE(h.IsPostStartup()); - } - for (ArtMethod* m : second_methods) { - Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); - ASSERT_TRUE(h.IsHot()); - ASSERT_TRUE(h.IsStartup()); - } - } -} - TEST_F(ProfileCompilationInfoTest, SaveFd) { ScratchFile profile; @@ -722,48 +533,6 @@ TEST_F(ProfileCompilationInfoTest, MissingTypesInlineCaches) { ASSERT_TRUE(*loaded_pmi1 == pmi_extra); } -TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) { - ScratchFile profile; - - Thread* self = Thread::Current(); - jobject class_loader; - { - ScopedObjectAccess soa(self); - class_loader = LoadDex("ProfileTestMultiDex"); - } - ASSERT_NE(class_loader, nullptr); - - // Save virtual methods from Main. - std::set<DexCacheResolvedClasses> resolved_classes; - std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;"); - - SafeMap<ArtMethod*, ProfileMethodInfo> profile_methods_map; - ASSERT_TRUE(SaveProfilingInfoWithFakeInlineCaches( - profile.GetFilename(), main_methods, Hotness::kFlagStartup, &profile_methods_map)); - - // Check that what we saved is in the profile. - ProfileCompilationInfo info; - ASSERT_TRUE(info.Load(GetFd(profile))); - ASSERT_EQ(info.GetNumberOfMethods(), main_methods.size()); - { - ScopedObjectAccess soa(self); - for (ArtMethod* m : main_methods) { - Hotness h = info.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); - ASSERT_TRUE(h.IsHot()); - ASSERT_TRUE(h.IsStartup()); - const ProfileMethodInfo& pmi = profile_methods_map.find(m)->second; - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> offline_pmi = - info.GetMethod(m->GetDexFile()->GetLocation(), - m->GetDexFile()->GetLocationChecksum(), - m->GetDexMethodIndex()); - ASSERT_TRUE(offline_pmi != nullptr); - ProfileCompilationInfo::OfflineProfileMethodInfo converted_pmi = - ConvertProfileMethodInfo(pmi); - ASSERT_EQ(converted_pmi, *offline_pmi); - } - } -} - TEST_F(ProfileCompilationInfoTest, InvalidChecksumInInlineCache) { ScratchFile profile; diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc index 16970921ab..9bea18a763 100644 --- a/openjdkjvmti/ti_class.cc +++ b/openjdkjvmti/ti_class.cc @@ -715,7 +715,7 @@ jvmtiError ClassUtil::GetClassSignature(jvmtiEnv* env, if (!klass->IsProxyClass() && klass->GetDexCache() != nullptr) { art::StackHandleScope<1> hs(soa.Self()); art::Handle<art::mirror::Class> h_klass = hs.NewHandle(klass); - art::mirror::ObjectArray<art::mirror::String>* str_array = + art::ObjPtr<art::mirror::ObjectArray<art::mirror::String>> str_array = art::annotations::GetSignatureAnnotationForClass(h_klass); if (str_array != nullptr) { std::ostringstream oss; diff --git a/openjdkjvmti/ti_field.cc b/openjdkjvmti/ti_field.cc index 328e2a1e40..2a860d9f43 100644 --- a/openjdkjvmti/ti_field.cc +++ b/openjdkjvmti/ti_field.cc @@ -91,7 +91,7 @@ jvmtiError FieldUtil::GetFieldName(jvmtiEnv* env, if (generic_ptr != nullptr) { *generic_ptr = nullptr; if (!art_field->GetDeclaringClass()->IsProxyClass()) { - art::mirror::ObjectArray<art::mirror::String>* str_array = + art::ObjPtr<art::mirror::ObjectArray<art::mirror::String>> str_array = art::annotations::GetSignatureAnnotationForField(art_field); if (str_array != nullptr) { std::ostringstream oss; diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc index c0c312c490..d0b7224f93 100644 --- a/openjdkjvmti/ti_method.cc +++ b/openjdkjvmti/ti_method.cc @@ -345,7 +345,7 @@ jvmtiError MethodUtil::GetMethodName(jvmtiEnv* env, if (generic_ptr != nullptr) { *generic_ptr = nullptr; if (!art_method->GetDeclaringClass()->IsProxyClass()) { - art::mirror::ObjectArray<art::mirror::String>* str_array = + art::ObjPtr<art::mirror::ObjectArray<art::mirror::String>> str_array = art::annotations::GetSignatureAnnotationForMethod(art_method); if (str_array != nullptr) { std::ostringstream oss; diff --git a/runtime/Android.bp b/runtime/Android.bp index b276c81d5a..777a1fc5ee 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -574,6 +574,7 @@ art_cc_test { "interpreter/safe_math_test.cc", "interpreter/unstarted_runtime_test.cc", "jdwp/jdwp_options_test.cc", + "jit/profiling_info_test.cc", "jni/java_vm_ext_test.cc", "method_handles_test.cc", "mirror/dex_cache_test.cc", diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc index 78516e3aeb..b0c0e43e35 100644 --- a/runtime/arch/stub_test.cc +++ b/runtime/arch/stub_test.cc @@ -21,6 +21,7 @@ #include "base/callee_save_type.h" #include "base/enums.h" #include "class_linker-inl.h" +#include "class_root.h" #include "common_runtime_test.h" #include "entrypoints/quick/quick_entrypoints_enum.h" #include "imt_conflict_table.h" @@ -2096,7 +2097,7 @@ TEST_F(StubTest, ReadBarrierForRoot) { EXPECT_FALSE(self->IsExceptionPending()); - GcRoot<mirror::Class>& root = mirror::String::java_lang_String_; + GcRoot<mirror::Class> root(GetClassRoot<mirror::String>()); size_t result = Invoke3(reinterpret_cast<size_t>(&root), 0U, 0U, readBarrierForRootSlow, self); EXPECT_FALSE(self->IsExceptionPending()); diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index b882f65a9e..095272394a 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -484,27 +484,10 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b mirror::ObjectArray<mirror::Object>::ClassSize(image_pointer_size_)))); object_array_class->SetComponentType(java_lang_Object.Get()); - // Setup the char (primitive) class to be used for char[]. - Handle<mirror::Class> char_class(hs.NewHandle( - AllocClass(self, java_lang_Class.Get(), - mirror::Class::PrimitiveClassSize(image_pointer_size_)))); - // The primitive char class won't be initialized by - // InitializePrimitiveClass until line 459, but strings (and - // internal char arrays) will be allocated before that and the - // component size, which is computed from the primitive type, needs - // to be set here. - char_class->SetPrimitiveType(Primitive::kPrimChar); - - // Setup the char[] class to be used for String. - Handle<mirror::Class> char_array_class(hs.NewHandle( - AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); - char_array_class->SetComponentType(char_class.Get()); - // Setup String. Handle<mirror::Class> java_lang_String(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_)))); java_lang_String->SetStringClass(); - mirror::String::SetClass(java_lang_String.Get()); mirror::Class::SetStatus(java_lang_String, ClassStatus::kResolved, self); // Setup java.lang.ref.Reference. @@ -523,7 +506,6 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b SetClassRoot(ClassRoot::kJavaLangObject, java_lang_Object.Get()); SetClassRoot(ClassRoot::kClassArrayClass, class_array_class.Get()); SetClassRoot(ClassRoot::kObjectArrayClass, object_array_class.Get()); - SetClassRoot(ClassRoot::kCharArrayClass, char_array_class.Get()); SetClassRoot(ClassRoot::kJavaLangString, java_lang_String.Get()); SetClassRoot(ClassRoot::kJavaLangRefReference, java_lang_ref_Reference.Get()); @@ -533,6 +515,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // Setup the primitive type classes. SetClassRoot(ClassRoot::kPrimitiveBoolean, CreatePrimitiveClass(self, Primitive::kPrimBoolean)); SetClassRoot(ClassRoot::kPrimitiveByte, CreatePrimitiveClass(self, Primitive::kPrimByte)); + SetClassRoot(ClassRoot::kPrimitiveChar, CreatePrimitiveClass(self, Primitive::kPrimChar)); SetClassRoot(ClassRoot::kPrimitiveShort, CreatePrimitiveClass(self, Primitive::kPrimShort)); SetClassRoot(ClassRoot::kPrimitiveInt, CreatePrimitiveClass(self, Primitive::kPrimInt)); SetClassRoot(ClassRoot::kPrimitiveLong, CreatePrimitiveClass(self, Primitive::kPrimLong)); @@ -543,13 +526,13 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // Create array interface entries to populate once we can load system classes. array_iftable_ = GcRoot<mirror::IfTable>(AllocIfTable(self, 2)); - // Create int array type for AllocDexCache (done in AppendToBootClassPath). + // Create int array type for native pointer arrays (for example vtables) on 32-bit archs. Handle<mirror::Class> int_array_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); int_array_class->SetComponentType(GetClassRoot(ClassRoot::kPrimitiveInt, this)); SetClassRoot(ClassRoot::kIntArrayClass, int_array_class.Get()); - // Create long array type for AllocDexCache (done in AppendToBootClassPath). + // Create long array type for native pointer arrays (for example vtables) on 64-bit archs. Handle<mirror::Class> long_array_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); long_array_class->SetComponentType(GetClassRoot(ClassRoot::kPrimitiveLong, this)); @@ -604,10 +587,6 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // now we can use FindSystemClass - // run char class through InitializePrimitiveClass to finish init - InitializePrimitiveClass(char_class.Get(), Primitive::kPrimChar); - SetClassRoot(ClassRoot::kPrimitiveChar, char_class.Get()); // needs descriptor - // Set up GenericJNI entrypoint. That is mainly a hack for common_compiler_test.h so that // we do not need friend classes or a publicly exposed setter. quick_generic_jni_trampoline_ = GetQuickGenericJniStub(); @@ -636,7 +615,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b SetClassRoot(ClassRoot::kByteArrayClass, FindSystemClass(self, "[B")); - CheckSystemClass(self, char_array_class, "[C"); + SetClassRoot(ClassRoot::kCharArrayClass, FindSystemClass(self, "[C")); SetClassRoot(ClassRoot::kShortArrayClass, FindSystemClass(self, "[S")); @@ -685,7 +664,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b FindSystemClass(self, "Ljava/lang/reflect/Proxy;")); // Create java.lang.reflect.Field.class root. - auto* class_root = FindSystemClass(self, "Ljava/lang/reflect/Field;"); + ObjPtr<mirror::Class> class_root = FindSystemClass(self, "Ljava/lang/reflect/Field;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kJavaLangReflectField, class_root); @@ -1014,10 +993,6 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) { spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots))); mirror::Class::SetClassClass(GetClassRoot(ClassRoot::kJavaLangClass, this)); - // 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<mirror::String>(this)); - ObjPtr<mirror::Class> java_lang_Object = GetClassRoot<mirror::Object>(this); java_lang_Object->SetObjectSize(sizeof(mirror::Object)); // Allocate in non-movable so that it's possible to check if a JNI weak global ref has been @@ -2109,7 +2084,6 @@ void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor) { ClassLinker::~ClassLinker() { mirror::Class::ResetClass(); - mirror::String::ResetClass(); Thread* const self = Thread::Current(); for (const ClassLoaderData& data : class_loaders_) { // CHA unloading analysis is not needed. No negative consequences are expected because @@ -3561,20 +3535,13 @@ ClassLinker::DexCacheData ClassLinker::FindDexCacheDataLocked(const DexFile& dex } mirror::Class* ClassLinker::CreatePrimitiveClass(Thread* self, Primitive::Type type) { - ObjPtr<mirror::Class> klass = + ObjPtr<mirror::Class> primitive_class = AllocClass(self, mirror::Class::PrimitiveClassSize(image_pointer_size_)); - if (UNLIKELY(klass == nullptr)) { + if (UNLIKELY(primitive_class == nullptr)) { self->AssertPendingOOMException(); return nullptr; } - return InitializePrimitiveClass(klass, type); -} - -mirror::Class* ClassLinker::InitializePrimitiveClass(ObjPtr<mirror::Class> primitive_class, - Primitive::Type type) { - CHECK(primitive_class != nullptr); // Must hold lock on object when initializing. - Thread* self = Thread::Current(); StackHandleScope<1> hs(self); Handle<mirror::Class> h_class(hs.NewHandle(primitive_class)); ObjectLock<mirror::Class> lock(self, h_class); @@ -3668,8 +3635,6 @@ mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descripto new_class.Assign(GetClassRoot<mirror::ObjectArray<mirror::Object>>(this)); } else if (strcmp(descriptor, "[Ljava/lang/String;") == 0) { new_class.Assign(GetClassRoot<mirror::ObjectArray<mirror::String>>(this)); - } else if (strcmp(descriptor, "[C") == 0) { - new_class.Assign(GetClassRoot<mirror::CharArray>(this)); } else if (strcmp(descriptor, "[I") == 0) { new_class.Assign(GetClassRoot<mirror::IntArray>(this)); } else if (strcmp(descriptor, "[J") == 0) { diff --git a/runtime/class_linker.h b/runtime/class_linker.h index afe5c99990..1f94c43408 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -793,10 +793,6 @@ class ClassLinker { mirror::Class* CreatePrimitiveClass(Thread* self, Primitive::Type type) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - mirror::Class* InitializePrimitiveClass(ObjPtr<mirror::Class> primitive_class, - Primitive::Type type) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Roles::uninterruptible_); mirror::Class* CreateArrayClass(Thread* self, const char* descriptor, diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc index ffa0a9065a..5cb08dc278 100644 --- a/runtime/dex/dex_file_annotations.cc +++ b/runtime/dex/dex_file_annotations.cc @@ -849,7 +849,8 @@ ObjPtr<mirror::Object> GetAnnotationValue(const ClassData& klass, return annotation_value.value_.GetL(); } -mirror::ObjectArray<mirror::String>* GetSignatureValue(const ClassData& klass, +static ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureValue( + const ClassData& klass, const DexFile::AnnotationSetItem* annotation_set) REQUIRES_SHARED(Locks::mutator_lock_) { const DexFile& dex_file = klass.GetDexFile(); @@ -860,12 +861,9 @@ mirror::ObjectArray<mirror::String>* GetSignatureValue(const ClassData& klass, if (annotation_item == nullptr) { return nullptr; } - ObjPtr<mirror::Class> string_class = mirror::String::GetJavaLangString(); - Handle<mirror::Class> string_array_class(hs.NewHandle( - Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &string_class))); - if (string_array_class == nullptr) { - return nullptr; - } + Handle<mirror::Class> string_array_class = + hs.NewHandle(GetClassRoot<mirror::ObjectArray<mirror::String>>()); + DCHECK(string_array_class != nullptr); ObjPtr<mirror::Object> obj = GetAnnotationValue(klass, annotation_item, "value", string_array_class, DexFile::kDexAnnotationArray); @@ -880,19 +878,16 @@ ObjPtr<mirror::ObjectArray<mirror::Class>> GetThrowsValue( const DexFile::AnnotationSetItem* annotation_set) REQUIRES_SHARED(Locks::mutator_lock_) { const DexFile& dex_file = klass.GetDexFile(); - StackHandleScope<1> hs(Thread::Current()); const DexFile::AnnotationItem* annotation_item = SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/Throws;", DexFile::kDexVisibilitySystem); if (annotation_item == nullptr) { return nullptr; } - ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass(); - Handle<mirror::Class> class_array_class(hs.NewHandle( - Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &class_class))); - if (class_array_class == nullptr) { - return nullptr; - } + StackHandleScope<1> hs(Thread::Current()); + Handle<mirror::Class> class_array_class = + hs.NewHandle(GetClassRoot<mirror::ObjectArray<mirror::Class>>()); + DCHECK(class_array_class != nullptr); ObjPtr<mirror::Object> obj = GetAnnotationValue(klass, annotation_item, "value", class_array_class, DexFile::kDexAnnotationArray); @@ -1020,7 +1015,7 @@ ObjPtr<mirror::ObjectArray<mirror::Object>> GetAnnotationsForField(ArtField* fie return ProcessAnnotationSet(field_class, annotation_set, DexFile::kDexVisibilityRuntime); } -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForField(ArtField* field) { +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForField(ArtField* field) { const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForField(field); if (annotation_set == nullptr) { return nullptr; @@ -1171,9 +1166,10 @@ ObjPtr<mirror::Object> GetAnnotationForMethodParameter(ArtMethod* method, annotation_class); } -bool GetParametersMetadataForMethod(ArtMethod* method, - MutableHandle<mirror::ObjectArray<mirror::String>>* names, - MutableHandle<mirror::IntArray>* access_flags) { +bool GetParametersMetadataForMethod( + ArtMethod* method, + /*out*/ MutableHandle<mirror::ObjectArray<mirror::String>>* names, + /*out*/ MutableHandle<mirror::IntArray>* access_flags) { const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); if (annotation_set == nullptr) { @@ -1193,12 +1189,10 @@ bool GetParametersMetadataForMethod(ArtMethod* method, StackHandleScope<4> hs(Thread::Current()); // Extract the parameters' names String[]. - ObjPtr<mirror::Class> string_class = mirror::String::GetJavaLangString(); - Handle<mirror::Class> string_array_class(hs.NewHandle( - Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &string_class))); - if (UNLIKELY(string_array_class == nullptr)) { - return false; - } + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + Handle<mirror::Class> string_array_class = + hs.NewHandle(GetClassRoot<mirror::ObjectArray<mirror::String>>(class_linker)); + DCHECK(string_array_class != nullptr); ClassData data(method); Handle<mirror::Object> names_obj = @@ -1212,10 +1206,8 @@ bool GetParametersMetadataForMethod(ArtMethod* method, } // Extract the parameters' access flags int[]. - Handle<mirror::Class> int_array_class(hs.NewHandle(GetClassRoot<mirror::IntArray>())); - if (UNLIKELY(int_array_class == nullptr)) { - return false; - } + Handle<mirror::Class> int_array_class(hs.NewHandle(GetClassRoot<mirror::IntArray>(class_linker))); + DCHECK(int_array_class != nullptr); Handle<mirror::Object> access_flags_obj = hs.NewHandle(GetAnnotationValue(data, annotation_item, @@ -1226,12 +1218,12 @@ bool GetParametersMetadataForMethod(ArtMethod* method, return false; } - names->Assign(names_obj.Get()->AsObjectArray<mirror::String>()); - access_flags->Assign(access_flags_obj.Get()->AsIntArray()); + names->Assign(names_obj->AsObjectArray<mirror::String>()); + access_flags->Assign(access_flags_obj->AsIntArray()); return true; } -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method) { +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForMethod(ArtMethod* method) { const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); if (annotation_set == nullptr) { return nullptr; @@ -1345,12 +1337,9 @@ ObjPtr<mirror::ObjectArray<mirror::Class>> GetDeclaredClasses(Handle<mirror::Cla return nullptr; } StackHandleScope<1> hs(Thread::Current()); - ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass(); - Handle<mirror::Class> class_array_class(hs.NewHandle( - Runtime::Current()->GetClassLinker()->FindArrayClass(hs.Self(), &class_class))); - if (class_array_class == nullptr) { - return nullptr; - } + Handle<mirror::Class> class_array_class = + hs.NewHandle(GetClassRoot<mirror::ObjectArray<mirror::Class>>()); + DCHECK(class_array_class != nullptr); ObjPtr<mirror::Object> obj = GetAnnotationValue(data, annotation_item, "value", class_array_class, DexFile::kDexAnnotationArray); @@ -1446,7 +1435,7 @@ ObjPtr<mirror::Object> GetEnclosingMethod(Handle<mirror::Class> klass) { DexFile::kDexAnnotationMethod); } -bool GetInnerClass(Handle<mirror::Class> klass, ObjPtr<mirror::String>* name) { +bool GetInnerClass(Handle<mirror::Class> klass, /*out*/ ObjPtr<mirror::String>* name) { ClassData data(klass); const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); if (annotation_set == nullptr) { @@ -1513,7 +1502,8 @@ bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) { return true; } -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForClass(Handle<mirror::Class> klass) { +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForClass( + Handle<mirror::Class> klass) { ClassData data(klass); const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); if (annotation_set == nullptr) { diff --git a/runtime/dex/dex_file_annotations.h b/runtime/dex/dex_file_annotations.h index 9645a7febd..bde7891091 100644 --- a/runtime/dex/dex_file_annotations.h +++ b/runtime/dex/dex_file_annotations.h @@ -41,7 +41,7 @@ ObjPtr<mirror::Object> GetAnnotationForField(ArtField* field, REQUIRES_SHARED(Locks::mutator_lock_); ObjPtr<mirror::ObjectArray<mirror::Object>> GetAnnotationsForField(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_); -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForField(ArtField* field) +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForField(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_); bool IsFieldAnnotationPresent(ArtField* field, Handle<mirror::Class> annotation_class) REQUIRES_SHARED(Locks::mutator_lock_); @@ -64,11 +64,11 @@ ObjPtr<mirror::Object> GetAnnotationForMethodParameter(ArtMethod* method, uint32_t parameter_idx, Handle<mirror::Class> annotation_class) REQUIRES_SHARED(Locks::mutator_lock_); -bool GetParametersMetadataForMethod(ArtMethod* method, - MutableHandle<mirror::ObjectArray<mirror::String>>* names, - MutableHandle<mirror::IntArray>* access_flags) - REQUIRES_SHARED(Locks::mutator_lock_); -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method) +bool GetParametersMetadataForMethod( + ArtMethod* method, + /*out*/ MutableHandle<mirror::ObjectArray<mirror::String>>* names, + /*out*/ MutableHandle<mirror::IntArray>* access_flags) REQUIRES_SHARED(Locks::mutator_lock_); +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); // Check whether `method` is annotated with `annotation_class`. // If `lookup_in_resolved_boot_classes` is true, look up any of the @@ -101,12 +101,12 @@ ObjPtr<mirror::Class> GetEnclosingClass(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); ObjPtr<mirror::Object> GetEnclosingMethod(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); -bool GetInnerClass(Handle<mirror::Class> klass, ObjPtr<mirror::String>* name) +bool GetInnerClass(Handle<mirror::Class> klass, /*out*/ ObjPtr<mirror::String>* name) REQUIRES_SHARED(Locks::mutator_lock_); bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) REQUIRES_SHARED(Locks::mutator_lock_); -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForClass(Handle<mirror::Class> klass) - REQUIRES_SHARED(Locks::mutator_lock_); +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForClass( + Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); const char* GetSourceDebugExtension(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); bool IsClassAnnotationPresent(Handle<mirror::Class> klass, diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 37234e1462..0ee780d32d 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -35,6 +35,7 @@ #include "base/macros.h" #include "base/mutex.h" #include "class_linker-inl.h" +#include "class_root.h" #include "common_dex_operations.h" #include "common_throws.h" #include "dex/dex_file-inl.h" @@ -328,7 +329,7 @@ static inline ObjPtr<mirror::String> ResolveString(Thread* self, ShadowFrame& shadow_frame, dex::StringIndex string_idx) REQUIRES_SHARED(Locks::mutator_lock_) { - ObjPtr<mirror::Class> java_lang_string_class = mirror::String::GetJavaLangString(); + ObjPtr<mirror::Class> java_lang_string_class = GetClassRoot<mirror::String>(); if (UNLIKELY(!java_lang_string_class->IsInitialized())) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); StackHandleScope<1> hs(self); diff --git a/runtime/interpreter/mterp/arm64/header.S b/runtime/interpreter/mterp/arm64/header.S index 7017dd149c..0722804265 100644 --- a/runtime/interpreter/mterp/arm64/header.S +++ b/runtime/interpreter/mterp/arm64/header.S @@ -339,6 +339,7 @@ codes. */ .macro ENTRY name .type \name, #function + .hidden \name // Hide this as a global symbol, so we do not incur plt calls. .global \name /* Cache alignment for function entry */ .balign 16 diff --git a/runtime/interpreter/mterp/out/mterp_arm64.S b/runtime/interpreter/mterp/out/mterp_arm64.S index d5374d2a8a..70f71ff2bc 100644 --- a/runtime/interpreter/mterp/out/mterp_arm64.S +++ b/runtime/interpreter/mterp/out/mterp_arm64.S @@ -346,6 +346,7 @@ codes. */ .macro ENTRY name .type \name, #function + .hidden \name // Hide this as a global symbol, so we do not incur plt calls. .global \name /* Cache alignment for function entry */ .balign 16 diff --git a/runtime/interpreter/mterp/out/mterp_x86.S b/runtime/interpreter/mterp/out/mterp_x86.S index 6f4752f312..1eacfe8736 100644 --- a/runtime/interpreter/mterp/out/mterp_x86.S +++ b/runtime/interpreter/mterp/out/mterp_x86.S @@ -106,11 +106,13 @@ unspecified registers or condition codes. #define SIZE(start,end) // Mac OS' symbols have an _ prefix. #define SYMBOL(name) _ ## name + #define ASM_HIDDEN .private_extern #else #define MACRO_LITERAL(value) $value #define FUNCTION_TYPE(name) .type name, @function #define SIZE(start,end) .size start, .-end #define SYMBOL(name) name + #define ASM_HIDDEN .hidden #endif .macro PUSH _reg @@ -339,6 +341,7 @@ unspecified registers or condition codes. */ .text + ASM_HIDDEN SYMBOL(ExecuteMterpImpl) .global SYMBOL(ExecuteMterpImpl) FUNCTION_TYPE(ExecuteMterpImpl) diff --git a/runtime/interpreter/mterp/out/mterp_x86_64.S b/runtime/interpreter/mterp/out/mterp_x86_64.S index fca2515698..ea8f483e95 100644 --- a/runtime/interpreter/mterp/out/mterp_x86_64.S +++ b/runtime/interpreter/mterp/out/mterp_x86_64.S @@ -102,11 +102,13 @@ unspecified registers or condition codes. #define SIZE(start,end) // Mac OS' symbols have an _ prefix. #define SYMBOL(name) _ ## name + #define ASM_HIDDEN .private_extern #else #define MACRO_LITERAL(value) $value #define FUNCTION_TYPE(name) .type name, @function #define SIZE(start,end) .size start, .-end #define SYMBOL(name) name + #define ASM_HIDDEN .hidden #endif .macro PUSH _reg @@ -325,6 +327,7 @@ unspecified registers or condition codes. */ .text + ASM_HIDDEN SYMBOL(ExecuteMterpImpl) .global SYMBOL(ExecuteMterpImpl) FUNCTION_TYPE(ExecuteMterpImpl) diff --git a/runtime/interpreter/mterp/x86/entry.S b/runtime/interpreter/mterp/x86/entry.S index 324637bf9a..939dc61d95 100644 --- a/runtime/interpreter/mterp/x86/entry.S +++ b/runtime/interpreter/mterp/x86/entry.S @@ -18,6 +18,7 @@ */ .text + ASM_HIDDEN SYMBOL(ExecuteMterpImpl) .global SYMBOL(ExecuteMterpImpl) FUNCTION_TYPE(ExecuteMterpImpl) diff --git a/runtime/interpreter/mterp/x86/header.S b/runtime/interpreter/mterp/x86/header.S index 9d826c2ce2..6f31228005 100644 --- a/runtime/interpreter/mterp/x86/header.S +++ b/runtime/interpreter/mterp/x86/header.S @@ -99,11 +99,13 @@ unspecified registers or condition codes. #define SIZE(start,end) // Mac OS' symbols have an _ prefix. #define SYMBOL(name) _ ## name + #define ASM_HIDDEN .private_extern #else #define MACRO_LITERAL(value) $$value #define FUNCTION_TYPE(name) .type name, @function #define SIZE(start,end) .size start, .-end #define SYMBOL(name) name + #define ASM_HIDDEN .hidden #endif .macro PUSH _reg diff --git a/runtime/interpreter/mterp/x86_64/entry.S b/runtime/interpreter/mterp/x86_64/entry.S index 2f69226206..b08419b219 100644 --- a/runtime/interpreter/mterp/x86_64/entry.S +++ b/runtime/interpreter/mterp/x86_64/entry.S @@ -18,6 +18,7 @@ */ .text + ASM_HIDDEN SYMBOL(ExecuteMterpImpl) .global SYMBOL(ExecuteMterpImpl) FUNCTION_TYPE(ExecuteMterpImpl) diff --git a/runtime/interpreter/mterp/x86_64/header.S b/runtime/interpreter/mterp/x86_64/header.S index 55638106ed..4ebe95e987 100644 --- a/runtime/interpreter/mterp/x86_64/header.S +++ b/runtime/interpreter/mterp/x86_64/header.S @@ -95,11 +95,13 @@ unspecified registers or condition codes. #define SIZE(start,end) // Mac OS' symbols have an _ prefix. #define SYMBOL(name) _ ## name + #define ASM_HIDDEN .private_extern #else #define MACRO_LITERAL(value) $$value #define FUNCTION_TYPE(name) .type name, @function #define SIZE(start,end) .size start, .-end #define SYMBOL(name) name + #define ASM_HIDDEN .hidden #endif .macro PUSH _reg diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc index 9bb760c6b7..88cfafba47 100644 --- a/runtime/interpreter/unstarted_runtime_test.cc +++ b/runtime/interpreter/unstarted_runtime_test.cc @@ -388,7 +388,7 @@ TEST_F(UnstartedRuntimeTest, StringCharAt) { TEST_F(UnstartedRuntimeTest, StringInit) { Thread* self = Thread::Current(); ScopedObjectAccess soa(self); - ObjPtr<mirror::Class> klass = mirror::String::GetJavaLangString(); + ObjPtr<mirror::Class> klass = GetClassRoot<mirror::String>(); ArtMethod* method = klass->FindConstructor("(Ljava/lang/String;)V", Runtime::Current()->GetClassLinker()->GetImagePointerSize()); @@ -537,7 +537,7 @@ TEST_F(UnstartedRuntimeTest, SystemArrayCopyObjectArrayTest) { tmp, false, object_class.Get(), - mirror::String::GetJavaLangString(), + GetClassRoot<mirror::String>(), hs_src, 1, hs_dst, @@ -551,7 +551,7 @@ TEST_F(UnstartedRuntimeTest, SystemArrayCopyObjectArrayTest) { { StackHandleScope<3> hs_src(self); hs_src.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "1")); - hs_src.NewHandle(mirror::String::GetJavaLangString()); + hs_src.NewHandle(GetClassRoot<mirror::String>()); hs_src.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "3")); StackHandleScope<3> hs_dst(self); @@ -568,7 +568,7 @@ TEST_F(UnstartedRuntimeTest, SystemArrayCopyObjectArrayTest) { tmp, true, object_class.Get(), - mirror::String::GetJavaLangString(), + GetClassRoot<mirror::String>(), hs_src, 0, hs_dst, diff --git a/runtime/jit/profiling_info_test.cc b/runtime/jit/profiling_info_test.cc new file mode 100644 index 0000000000..106a80a568 --- /dev/null +++ b/runtime/jit/profiling_info_test.cc @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2016 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 <gtest/gtest.h> +#include <stdio.h> + +#include "art_method-inl.h" +#include "base/unix_file/fd_file.h" +#include "class_linker-inl.h" +#include "common_runtime_test.h" +#include "dex/dex_file.h" +#include "dex/dex_file_loader.h" +#include "dex/method_reference.h" +#include "dex/type_reference.h" +#include "handle_scope-inl.h" +#include "linear_alloc.h" +#include "mirror/class-inl.h" +#include "mirror/class_loader.h" +#include "profile/profile_compilation_info.h" +#include "scoped_thread_state_change-inl.h" +#include "ziparchive/zip_writer.h" + +namespace art { + +using Hotness = ProfileCompilationInfo::MethodHotness; + +static constexpr size_t kMaxMethodIds = 65535; + +class ProfileCompilationInfoTest : public CommonRuntimeTest { + public: + void PostRuntimeCreate() OVERRIDE { + allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool())); + } + + protected: + std::vector<ArtMethod*> GetVirtualMethods(jobject class_loader, + const std::string& clazz) { + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + Thread* self = Thread::Current(); + ScopedObjectAccess soa(self); + StackHandleScope<1> hs(self); + Handle<mirror::ClassLoader> h_loader( + hs.NewHandle(self->DecodeJObject(class_loader)->AsClassLoader())); + ObjPtr<mirror::Class> klass = class_linker->FindClass(self, clazz.c_str(), h_loader); + + const auto pointer_size = class_linker->GetImagePointerSize(); + std::vector<ArtMethod*> methods; + for (auto& m : klass->GetVirtualMethods(pointer_size)) { + methods.push_back(&m); + } + return methods; + } + + bool AddMethod(const std::string& dex_location, + uint32_t checksum, + uint16_t method_index, + ProfileCompilationInfo* info) { + return info->AddMethodIndex(Hotness::kFlagHot, + dex_location, + checksum, + method_index, + kMaxMethodIds); + } + + bool AddMethod(const std::string& dex_location, + uint32_t checksum, + uint16_t method_index, + const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi, + ProfileCompilationInfo* info) { + return info->AddMethod( + dex_location, checksum, method_index, kMaxMethodIds, pmi, Hotness::kFlagPostStartup); + } + + bool AddClass(const std::string& dex_location, + uint32_t checksum, + dex::TypeIndex type_index, + ProfileCompilationInfo* info) { + DexCacheResolvedClasses classes(dex_location, dex_location, checksum, kMaxMethodIds); + classes.AddClass(type_index); + return info->AddClasses({classes}); + } + + uint32_t GetFd(const ScratchFile& file) { + return static_cast<uint32_t>(file.GetFd()); + } + + bool SaveProfilingInfo( + const std::string& filename, + const std::vector<ArtMethod*>& methods, + const std::set<DexCacheResolvedClasses>& resolved_classes, + Hotness::Flag flags) { + ProfileCompilationInfo info; + std::vector<ProfileMethodInfo> profile_methods; + ScopedObjectAccess soa(Thread::Current()); + for (ArtMethod* method : methods) { + profile_methods.emplace_back( + MethodReference(method->GetDexFile(), method->GetDexMethodIndex())); + } + if (!info.AddMethods(profile_methods, flags) || !info.AddClasses(resolved_classes)) { + return false; + } + if (info.GetNumberOfMethods() != profile_methods.size()) { + return false; + } + ProfileCompilationInfo file_profile; + if (!file_profile.Load(filename, false)) { + return false; + } + if (!info.MergeWith(file_profile)) { + return false; + } + + return info.Save(filename, nullptr); + } + + // Saves the given art methods to a profile backed by 'filename' and adds + // some fake inline caches to it. The added inline caches are returned in + // the out map `profile_methods_map`. + bool SaveProfilingInfoWithFakeInlineCaches( + const std::string& filename, + const std::vector<ArtMethod*>& methods, + Hotness::Flag flags, + /*out*/ SafeMap<ArtMethod*, ProfileMethodInfo>* profile_methods_map) { + ProfileCompilationInfo info; + std::vector<ProfileMethodInfo> profile_methods; + ScopedObjectAccess soa(Thread::Current()); + for (ArtMethod* method : methods) { + std::vector<ProfileMethodInfo::ProfileInlineCache> caches; + // Monomorphic + for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) { + std::vector<TypeReference> classes; + classes.emplace_back(method->GetDexFile(), dex::TypeIndex(0)); + caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); + } + // Polymorphic + for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) { + std::vector<TypeReference> classes; + for (uint16_t k = 0; k < InlineCache::kIndividualCacheSize / 2; k++) { + classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k)); + } + caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); + } + // Megamorphic + for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) { + std::vector<TypeReference> classes; + for (uint16_t k = 0; k < 2 * InlineCache::kIndividualCacheSize; k++) { + classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k)); + } + caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); + } + // Missing types + for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) { + std::vector<TypeReference> classes; + caches.emplace_back(dex_pc, /*is_missing_types*/true, classes); + } + ProfileMethodInfo pmi(MethodReference(method->GetDexFile(), + method->GetDexMethodIndex()), + caches); + profile_methods.push_back(pmi); + profile_methods_map->Put(method, pmi); + } + + if (!info.AddMethods(profile_methods, flags) + || info.GetNumberOfMethods() != profile_methods.size()) { + return false; + } + return info.Save(filename, nullptr); + } + + // Creates an inline cache which will be destructed at the end of the test. + ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() { + used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap( + std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile))); + return used_inline_caches.back().get(); + } + + ProfileCompilationInfo::OfflineProfileMethodInfo ConvertProfileMethodInfo( + const ProfileMethodInfo& pmi) { + ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap(); + ProfileCompilationInfo::OfflineProfileMethodInfo offline_pmi(ic_map); + SafeMap<DexFile*, uint8_t> dex_map; // dex files to profile index + for (const auto& inline_cache : pmi.inline_caches) { + ProfileCompilationInfo::DexPcData& dex_pc_data = + ic_map->FindOrAdd( + inline_cache.dex_pc, ProfileCompilationInfo::DexPcData(allocator_.get()))->second; + if (inline_cache.is_missing_types) { + dex_pc_data.SetIsMissingTypes(); + } + for (const auto& class_ref : inline_cache.classes) { + uint8_t dex_profile_index = dex_map.FindOrAdd(const_cast<DexFile*>(class_ref.dex_file), + static_cast<uint8_t>(dex_map.size()))->second; + dex_pc_data.AddClass(dex_profile_index, class_ref.TypeIndex()); + if (dex_profile_index >= offline_pmi.dex_references.size()) { + // This is a new dex. + const std::string& dex_key = ProfileCompilationInfo::GetProfileDexFileKey( + class_ref.dex_file->GetLocation()); + offline_pmi.dex_references.emplace_back(dex_key, + class_ref.dex_file->GetLocationChecksum(), + class_ref.dex_file->NumMethodIds()); + } + } + } + return offline_pmi; + } + + // Cannot sizeof the actual arrays so hard code the values here. + // They should not change anyway. + static constexpr int kProfileMagicSize = 4; + static constexpr int kProfileVersionSize = 4; + + std::unique_ptr<ArenaAllocator> allocator_; + + // Cache of inline caches generated during tests. + // This makes it easier to pass data between different utilities and ensure that + // caches are destructed at the end of the test. + std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches; +}; + +TEST_F(ProfileCompilationInfoTest, SaveArtMethods) { + ScratchFile profile; + + Thread* self = Thread::Current(); + jobject class_loader; + { + ScopedObjectAccess soa(self); + class_loader = LoadDex("ProfileTestMultiDex"); + } + ASSERT_NE(class_loader, nullptr); + + // Save virtual methods from Main. + std::set<DexCacheResolvedClasses> resolved_classes; + std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;"); + ASSERT_TRUE(SaveProfilingInfo( + profile.GetFilename(), main_methods, resolved_classes, Hotness::kFlagPostStartup)); + + // Check that what we saved is in the profile. + ProfileCompilationInfo info1; + ASSERT_TRUE(info1.Load(GetFd(profile))); + ASSERT_EQ(info1.GetNumberOfMethods(), main_methods.size()); + { + ScopedObjectAccess soa(self); + for (ArtMethod* m : main_methods) { + Hotness h = info1.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); + ASSERT_TRUE(h.IsHot()); + ASSERT_TRUE(h.IsPostStartup()); + } + } + + // Save virtual methods from Second. + std::vector<ArtMethod*> second_methods = GetVirtualMethods(class_loader, "LSecond;"); + ASSERT_TRUE(SaveProfilingInfo( + profile.GetFilename(), second_methods, resolved_classes, Hotness::kFlagStartup)); + + // Check that what we saved is in the profile (methods form Main and Second). + ProfileCompilationInfo info2; + ASSERT_TRUE(profile.GetFile()->ResetOffset()); + ASSERT_TRUE(info2.Load(GetFd(profile))); + ASSERT_EQ(info2.GetNumberOfMethods(), main_methods.size() + second_methods.size()); + { + ScopedObjectAccess soa(self); + for (ArtMethod* m : main_methods) { + Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); + ASSERT_TRUE(h.IsHot()); + ASSERT_TRUE(h.IsPostStartup()); + } + for (ArtMethod* m : second_methods) { + Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); + ASSERT_TRUE(h.IsHot()); + ASSERT_TRUE(h.IsStartup()); + } + } +} + +TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) { + ScratchFile profile; + + Thread* self = Thread::Current(); + jobject class_loader; + { + ScopedObjectAccess soa(self); + class_loader = LoadDex("ProfileTestMultiDex"); + } + ASSERT_NE(class_loader, nullptr); + + // Save virtual methods from Main. + std::set<DexCacheResolvedClasses> resolved_classes; + std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;"); + + SafeMap<ArtMethod*, ProfileMethodInfo> profile_methods_map; + ASSERT_TRUE(SaveProfilingInfoWithFakeInlineCaches( + profile.GetFilename(), main_methods, Hotness::kFlagStartup, &profile_methods_map)); + + // Check that what we saved is in the profile. + ProfileCompilationInfo info; + ASSERT_TRUE(info.Load(GetFd(profile))); + ASSERT_EQ(info.GetNumberOfMethods(), main_methods.size()); + { + ScopedObjectAccess soa(self); + for (ArtMethod* m : main_methods) { + Hotness h = info.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); + ASSERT_TRUE(h.IsHot()); + ASSERT_TRUE(h.IsStartup()); + const ProfileMethodInfo& pmi = profile_methods_map.find(m)->second; + std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> offline_pmi = + info.GetMethod(m->GetDexFile()->GetLocation(), + m->GetDexFile()->GetLocationChecksum(), + m->GetDexMethodIndex()); + ASSERT_TRUE(offline_pmi != nullptr); + ProfileCompilationInfo::OfflineProfileMethodInfo converted_pmi = + ConvertProfileMethodInfo(pmi); + ASSERT_EQ(converted_pmi, *offline_pmi); + } + } +} + +} // namespace art diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index e6bfe5551a..cb2708d0cb 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -1461,12 +1461,12 @@ template<VerifyObjectFlags kVerifyFlags> void Class::GetAccessFlagsDCheck() { // circularity issue during loading the names of its members DCHECK(IsIdxLoaded<kVerifyFlags>() || IsRetired<kVerifyFlags>() || IsErroneous<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>() || - this == String::GetJavaLangString()) + this == GetClassRoot<String>()) << "IsIdxLoaded=" << IsIdxLoaded<kVerifyFlags>() << " IsRetired=" << IsRetired<kVerifyFlags>() << " IsErroneous=" << IsErroneous<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>() - << " IsString=" << (this == String::GetJavaLangString()) + << " IsString=" << (this == GetClassRoot<String>()) << " status= " << GetStatus<kVerifyFlags>() << " descriptor=" << PrettyDescriptor(); } diff --git a/runtime/mirror/string-inl.h b/runtime/mirror/string-inl.h index e6079c0cba..8fa2c6cf7f 100644 --- a/runtime/mirror/string-inl.h +++ b/runtime/mirror/string-inl.h @@ -25,6 +25,7 @@ #include "base/globals.h" #include "base/utils.h" #include "class.h" +#include "class_root.h" #include "common_throws.h" #include "dex/utf.h" #include "gc/heap-inl.h" @@ -211,7 +212,8 @@ inline String* String::Alloc(Thread* self, int32_t utf16_length_with_flag, // http://b/23528461 size_t alloc_size = RoundUp(size, kObjectAlignment); - Class* string_class = GetJavaLangString(); + Runtime* runtime = Runtime::Current(); + ObjPtr<Class> string_class = GetClassRoot<String>(runtime->GetClassLinker()); // Check for overflow and throw OutOfMemoryError if this was an unreasonable request. // Do this by comparing with the maximum length that will _not_ cause an overflow. const size_t overflow_length = (-header_size) / block_size; // Unsigned arithmetic. @@ -227,7 +229,7 @@ inline String* String::Alloc(Thread* self, int32_t utf16_length_with_flag, return nullptr; } - gc::Heap* heap = Runtime::Current()->GetHeap(); + gc::Heap* heap = runtime->GetHeap(); return down_cast<String*>( heap->AllocObjectWithAllocator<kIsInstrumented, true>(self, string_class, alloc_size, allocator_type, pre_fence_visitor)); diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc index 6208a962e5..b76ca1968a 100644 --- a/runtime/mirror/string.cc +++ b/runtime/mirror/string.cc @@ -35,9 +35,6 @@ namespace art { namespace mirror { -// TODO: get global references for these -GcRoot<Class> String::java_lang_String_; - int32_t String::FastIndexOf(int32_t ch, int32_t start) { int32_t count = GetLength(); if (start < 0) { @@ -52,18 +49,6 @@ int32_t String::FastIndexOf(int32_t ch, int32_t start) { } } -void String::SetClass(ObjPtr<Class> java_lang_String) { - CHECK(java_lang_String_.IsNull()); - CHECK(java_lang_String != nullptr); - CHECK(java_lang_String->IsStringClass()); - java_lang_String_ = GcRoot<Class>(java_lang_String); -} - -void String::ResetClass() { - CHECK(!java_lang_String_.IsNull()); - java_lang_String_ = GcRoot<Class>(nullptr); -} - int String::ComputeHashCode() { int32_t hash_code = 0; if (IsCompressed()) { @@ -372,10 +357,6 @@ int32_t String::CompareTo(ObjPtr<String> rhs) { return count_diff; } -void String::VisitRoots(RootVisitor* visitor) { - java_lang_String_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - CharArray* String::ToCharArray(Thread* self) { StackHandleScope<1> hs(self); Handle<String> string(hs.NewHandle(this)); diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h index 270ace1036..598175b749 100644 --- a/runtime/mirror/string.h +++ b/runtime/mirror/string.h @@ -228,15 +228,6 @@ class MANAGED String FINAL : public Object { : length; } - static Class* GetJavaLangString() REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(!java_lang_String_.IsNull()); - return java_lang_String_.Read(); - } - - static void SetClass(ObjPtr<Class> java_lang_String) REQUIRES_SHARED(Locks::mutator_lock_); - static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - // Returns a human-readable equivalent of 'descriptor'. So "I" would be "int", // "[[I" would be "int[][]", "[Ljava/lang/String;" would be // "java.lang.String[]", and so forth. @@ -281,10 +272,7 @@ class MANAGED String FINAL : public Object { uint8_t value_compressed_[0]; }; - static GcRoot<Class> java_lang_String_; - friend struct art::StringOffsets; // for verifying offset information - ART_FRIEND_TEST(art::StubTest, ReadBarrierForRoot); // For java_lang_String_. DISALLOW_IMPLICIT_CONSTRUCTORS(String); }; diff --git a/runtime/mirror/var_handle_test.cc b/runtime/mirror/var_handle_test.cc index 2c1283225d..cb2d628b5b 100644 --- a/runtime/mirror/var_handle_test.cc +++ b/runtime/mirror/var_handle_test.cc @@ -92,8 +92,7 @@ class VarHandleTest : public CommonRuntimeTest { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); Handle<Class> var_type = hs.NewHandle(view_array_class->GetComponentType()); Handle<Class> index_type = hs.NewHandle(class_linker->FindPrimitiveClass('I')); - ObjPtr<mirror::Class> byte_class = class_linker->FindPrimitiveClass('B'); - Handle<Class> byte_array_class(hs.NewHandle(class_linker->FindArrayClass(self, &byte_class))); + Handle<Class> byte_array_class(hs.NewHandle(GetClassRoot<mirror::ByteArray>())); InitializeVarHandle(bvh.Get(), var_type, byte_array_class, index_type, access_modes_bit_mask); bvh->SetFieldBoolean<false>(ByteArrayViewVarHandle::NativeByteOrderOffset(), native_byte_order); return bvh.Get(); @@ -234,8 +233,7 @@ static MethodType* MethodTypeOf(const std::string& method_descriptor) { ScopedObjectAccess soa(self); StackHandleScope<3> hs(self); int ptypes_count = static_cast<int>(descriptors.size()) - 1; - ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass(); - ObjPtr<mirror::Class> array_of_class = class_linker->FindArrayClass(self, &class_type); + ObjPtr<mirror::Class> array_of_class = GetClassRoot<mirror::ObjectArray<mirror::Class>>(); Handle<ObjectArray<Class>> ptypes = hs.NewHandle( ObjectArray<Class>::Alloc(Thread::Current(), array_of_class, ptypes_count)); Handle<mirror::ClassLoader> boot_class_loader = hs.NewHandle<mirror::ClassLoader>(nullptr); @@ -599,10 +597,10 @@ TEST_F(VarHandleTest, ArrayElementVarHandle) { VarHandle::AccessMode::kGetAndBitwiseXorRelease, VarHandle::AccessMode::kGetAndBitwiseXorAcquire); - ObjPtr<mirror::Class> string_class = mirror::String::GetJavaLangString(); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - Handle<Class> string_array_class(hs.NewHandle(class_linker->FindArrayClass(self, &string_class))); - Handle<mirror::ArrayElementVarHandle> vh(hs.NewHandle(CreateArrayElementVarHandle(self, string_array_class, mask))); + Handle<mirror::Class> string_array_class = hs.NewHandle( + GetClassRoot<mirror::ObjectArray<mirror::String>>()); + Handle<mirror::ArrayElementVarHandle> vh( + hs.NewHandle(CreateArrayElementVarHandle(self, string_array_class, mask))); EXPECT_FALSE(vh.IsNull()); // Check access modes @@ -746,11 +744,10 @@ TEST_F(VarHandleTest, ByteArrayViewVarHandle) { VarHandle::AccessMode::kGetAndBitwiseXor, VarHandle::AccessMode::kGetAndBitwiseXorAcquire); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - ObjPtr<mirror::Class> char_class = class_linker->FindPrimitiveClass('C'); - Handle<Class> char_array_class(hs.NewHandle(class_linker->FindArrayClass(self, &char_class))); + Handle<Class> char_array_class(hs.NewHandle(GetClassRoot<mirror::CharArray>())); const bool native_byte_order = true; - Handle<mirror::ByteArrayViewVarHandle> vh(hs.NewHandle(CreateByteArrayViewVarHandle(self, char_array_class, native_byte_order, mask))); + Handle<mirror::ByteArrayViewVarHandle> vh( + hs.NewHandle(CreateByteArrayViewVarHandle(self, char_array_class, native_byte_order, mask))); EXPECT_FALSE(vh.IsNull()); EXPECT_EQ(native_byte_order, vh->GetNativeByteOrder()); @@ -895,11 +892,10 @@ TEST_F(VarHandleTest, ByteBufferViewVarHandle) { VarHandle::AccessMode::kGetAndBitwiseXor, VarHandle::AccessMode::kGetAndBitwiseXorAcquire); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - ObjPtr<mirror::Class> double_class = class_linker->FindPrimitiveClass('D'); - Handle<Class> double_array_class(hs.NewHandle(class_linker->FindArrayClass(self, &double_class))); + Handle<Class> double_array_class(hs.NewHandle(GetClassRoot<mirror::DoubleArray>())); const bool native_byte_order = false; - Handle<mirror::ByteBufferViewVarHandle> vh(hs.NewHandle(CreateByteBufferViewVarHandle(self, double_array_class, native_byte_order, mask))); + Handle<mirror::ByteBufferViewVarHandle> vh(hs.NewHandle( + CreateByteBufferViewVarHandle(self, double_array_class, native_byte_order, mask))); EXPECT_FALSE(vh.IsNull()); EXPECT_EQ(native_byte_order, vh->GetNativeByteOrder()); diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 32d9d68d0d..6384d01aaf 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1979,7 +1979,6 @@ void Runtime::VisitConstantRoots(RootVisitor* visitor) { // Visit the classes held as static in mirror classes, these can be visited concurrently and only // need to be visited once per GC since they never change. mirror::Class::VisitRoots(visitor); - mirror::String::VisitRoots(visitor); mirror::ClassExt::VisitRoots(visitor); // Visiting the roots of these ArtMethods is not currently required since all the GcRoots are // null. diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc index cbfbb4000a..73e516c7bf 100644 --- a/runtime/verifier/reg_type.cc +++ b/runtime/verifier/reg_type.cc @@ -723,6 +723,7 @@ const RegType& RegType::Merge(const RegType& incoming_type, // mechanics to continue. return reg_types->FromUnresolvedMerge(*this, incoming_type, verifier); } else { // Two reference types, compute Join + // Do not cache the classes as ClassJoin() can suspend and invalidate ObjPtr<>s. DCHECK(GetClass() != nullptr && !GetClass()->IsPrimitive()); DCHECK(incoming_type.GetClass() != nullptr && !incoming_type.GetClass()->IsPrimitive()); ObjPtr<mirror::Class> join_class = ClassJoin(GetClass(), incoming_type.GetClass()); diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc index 49db0c82b5..7ada47d304 100644 --- a/test/137-cfi/cfi.cc +++ b/test/137-cfi/cfi.cc @@ -56,9 +56,12 @@ static void CauseSegfault() { extern "C" JNIEXPORT jboolean JNICALL Java_Main_sleep(JNIEnv*, jobject, jint, jboolean, jdouble) { // Keep pausing. + struct timespec ts = { .tv_sec = 100, .tv_nsec = 0 }; printf("Going to sleep\n"); for (;;) { - sleep(1); + // Use nanosleep since it gets to the system call quickly and doesn't + // have any points at which an unwind will fail. + nanosleep(&ts, nullptr); } } |