Merge "Simplify DexRegisterMap API."
diff --git a/libprofile/profile/profile_compilation_info_test.cc b/libprofile/profile/profile_compilation_info_test.cc
index ead7cba..42c3320 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 1697092..9bea18a 100644
--- a/openjdkjvmti/ti_class.cc
+++ b/openjdkjvmti/ti_class.cc
@@ -715,7 +715,7 @@
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 328e2a1..2a860d9 100644
--- a/openjdkjvmti/ti_field.cc
+++ b/openjdkjvmti/ti_field.cc
@@ -91,7 +91,7 @@
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 c0c312c..d0b7224f 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -345,7 +345,7 @@
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 b276c81..777a1fc 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -574,6 +574,7 @@
"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 78516e3..b0c0e43 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 @@
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 b882f65..0952723 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -484,27 +484,10 @@
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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 afe5c99..1f94c43 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -793,10 +793,6 @@
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 ffa0a90..5cb08dc 100644
--- a/runtime/dex/dex_file_annotations.cc
+++ b/runtime/dex/dex_file_annotations.cc
@@ -849,7 +849,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
// 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 @@
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 @@
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 @@
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 @@
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 9645a7f..bde7891 100644
--- a/runtime/dex/dex_file_annotations.h
+++ b/runtime/dex/dex_file_annotations.h
@@ -41,7 +41,7 @@
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 @@
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 @@
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 37234e1..0ee780d 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 @@
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 7017dd1..0722804 100644
--- a/runtime/interpreter/mterp/arm64/header.S
+++ b/runtime/interpreter/mterp/arm64/header.S
@@ -339,6 +339,7 @@
*/
.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 d5374d2..70f71ff 100644
--- a/runtime/interpreter/mterp/out/mterp_arm64.S
+++ b/runtime/interpreter/mterp/out/mterp_arm64.S
@@ -346,6 +346,7 @@
*/
.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 6f4752f..1eacfe8 100644
--- a/runtime/interpreter/mterp/out/mterp_x86.S
+++ b/runtime/interpreter/mterp/out/mterp_x86.S
@@ -106,11 +106,13 @@
#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 @@
*/
.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 fca2515..ea8f483 100644
--- a/runtime/interpreter/mterp/out/mterp_x86_64.S
+++ b/runtime/interpreter/mterp/out/mterp_x86_64.S
@@ -102,11 +102,13 @@
#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 @@
*/
.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 324637b..939dc61 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 9d826c2..6f31228 100644
--- a/runtime/interpreter/mterp/x86/header.S
+++ b/runtime/interpreter/mterp/x86/header.S
@@ -99,11 +99,13 @@
#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 2f69226..b08419b 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 5563810..4ebe95e 100644
--- a/runtime/interpreter/mterp/x86_64/header.S
+++ b/runtime/interpreter/mterp/x86_64/header.S
@@ -95,11 +95,13 @@
#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 9bb760c..88cfafb 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -388,7 +388,7 @@
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 @@
tmp,
false,
object_class.Get(),
- mirror::String::GetJavaLangString(),
+ GetClassRoot<mirror::String>(),
hs_src,
1,
hs_dst,
@@ -551,7 +551,7 @@
{
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 @@
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 0000000..106a80a
--- /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 e6bfe55..cb2708d 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -1461,12 +1461,12 @@
// 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 e6079c0..8fa2c6c 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 @@
// 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 @@
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 6208a96..b76ca19 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 @@
}
}
-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 @@
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 270ace1..598175b 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -228,15 +228,6 @@
: 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 @@
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 2c12832..cb2d628 100644
--- a/runtime/mirror/var_handle_test.cc
+++ b/runtime/mirror/var_handle_test.cc
@@ -92,8 +92,7 @@
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 @@
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 @@
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 @@
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 @@
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 32d9d68..6384d01 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1979,7 +1979,6 @@
// 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 cbfbb40..73e516c 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -723,6 +723,7 @@
// 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 49db0c8..7ada47d 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -56,9 +56,12 @@
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);
}
}