diff options
| author | 2015-10-12 18:26:42 +0000 | |
|---|---|---|
| committer | 2015-10-12 18:26:42 +0000 | |
| commit | a9c9d6abf5a37588f4eb1de7d3a12042a9fb3f81 (patch) | |
| tree | 9261034fd1b7aee95679024d29fba2761dbf2c1b | |
| parent | da458691d0d8023dee973f5b04633e243219c311 (diff) | |
| parent | 18656fefc7e68e2549a8fa93455074d359d1efa8 (diff) | |
Merge "Unload oat files"
| -rw-r--r-- | runtime/class_linker.cc | 37 | ||||
| -rw-r--r-- | runtime/common_runtime_test.cc | 3 | ||||
| -rw-r--r-- | runtime/native/dalvik_system_DexFile.cc | 155 | ||||
| -rw-r--r-- | runtime/native/dalvik_system_DexFile.h | 4 | ||||
| -rw-r--r-- | runtime/oat_file_assistant_test.cc | 3 | ||||
| -rw-r--r-- | runtime/oat_file_manager.cc | 33 | ||||
| -rw-r--r-- | runtime/oat_file_manager.h | 9 | ||||
| -rw-r--r-- | test/141-class-unload/expected.txt | 1 | ||||
| -rw-r--r-- | test/141-class-unload/src/Main.java | 24 |
9 files changed, 175 insertions, 94 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 6fa8fc1f66..5ff4bc1621 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -41,25 +41,20 @@ #include "compiler_callbacks.h" #include "debugger.h" #include "dex_file-inl.h" +#include "entrypoints/entrypoint_utils.h" #include "entrypoints/runtime_asm_entrypoints.h" #include "gc_root-inl.h" #include "gc/accounting/card_table-inl.h" #include "gc/accounting/heap_bitmap.h" #include "gc/heap.h" #include "gc/space/image_space.h" -#include "handle_scope.h" +#include "handle_scope-inl.h" #include "intern_table.h" #include "interpreter/interpreter.h" #include "jit/jit.h" #include "jit/jit_code_cache.h" #include "leb128.h" #include "linear_alloc.h" -#include "oat.h" -#include "oat_file.h" -#include "oat_file-inl.h" -#include "oat_file_assistant.h" -#include "oat_file_manager.h" -#include "object_lock.h" #include "mirror/class.h" #include "mirror/class-inl.h" #include "mirror/class_loader.h" @@ -73,12 +68,17 @@ #include "mirror/reference-inl.h" #include "mirror/stack_trace_element.h" #include "mirror/string-inl.h" +#include "native/dalvik_system_DexFile.h" +#include "oat.h" +#include "oat_file.h" +#include "oat_file-inl.h" +#include "oat_file_assistant.h" +#include "oat_file_manager.h" +#include "object_lock.h" #include "os.h" #include "runtime.h" -#include "entrypoints/entrypoint_utils.h" #include "ScopedLocalRef.h" #include "scoped_thread_state_change.h" -#include "handle_scope-inl.h" #include "thread-inl.h" #include "trace.h" #include "utils.h" @@ -1429,13 +1429,18 @@ bool ClassLinker::FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& break; } int32_t long_array_size = long_array->GetLength(); - for (int32_t j = 0; j < long_array_size; ++j) { + // First element is the oat file. + for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) { const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>( long_array->GetWithoutChecks(j))); const DexFile::ClassDef* dex_class_def = cp_dex_file->FindClassDef(descriptor, hash); if (dex_class_def != nullptr) { - mirror::Class* klass = DefineClass(self, descriptor, hash, class_loader, - *cp_dex_file, *dex_class_def); + mirror::Class* klass = DefineClass(self, + descriptor, + hash, + class_loader, + *cp_dex_file, + *dex_class_def); if (klass == nullptr) { CHECK(self->IsExceptionPending()) << descriptor; self->ClearException(); @@ -5794,9 +5799,13 @@ jobject ClassLinker::CreatePathClassLoader(Thread* self, std::vector<const DexFi for (const DexFile* dex_file : dex_files) { StackHandleScope<3> hs2(self); - Handle<mirror::LongArray> h_long_array = hs2.NewHandle(mirror::LongArray::Alloc(self, 1)); + // CreatePathClassLoader is only used by gtests. Index 0 of h_long_array is supposed to be the + // oat file but we can leave it null. + Handle<mirror::LongArray> h_long_array = hs2.NewHandle(mirror::LongArray::Alloc( + self, + kDexFileIndexStart + 1)); DCHECK(h_long_array.Get() != nullptr); - h_long_array->Set(0, reinterpret_cast<intptr_t>(dex_file)); + h_long_array->Set(kDexFileIndexStart, reinterpret_cast<intptr_t>(dex_file)); Handle<mirror::Object> h_dex_file = hs2.NewHandle( cookie_field->GetDeclaringClass()->AllocObject(self)); diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc index 56c5d1a2c3..b6b514177a 100644 --- a/runtime/common_runtime_test.cc +++ b/runtime/common_runtime_test.cc @@ -42,6 +42,7 @@ #include "mirror/class-inl.h" #include "mirror/class_loader.h" #include "mem_map.h" +#include "native/dalvik_system_DexFile.h" #include "noop_compiler_callbacks.h" #include "os.h" #include "primitive.h" @@ -516,7 +517,7 @@ std::vector<const DexFile*> CommonRuntimeTest::GetDexFiles(jobject jclass_loader mirror::LongArray* long_array = cookie_field->GetObject(dex_file)->AsLongArray(); DCHECK(long_array != nullptr); int32_t long_array_size = long_array->GetLength(); - for (int32_t j = 0; j < long_array_size; ++j) { + for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) { const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>( long_array->GetWithoutChecks(j))); if (cp_dex_file == nullptr) { diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 4850b6fe85..1a6beadd37 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -40,13 +40,16 @@ namespace art { -static std::unique_ptr<std::vector<const DexFile*>> -ConvertJavaArrayToNative(JNIEnv* env, jobject arrayObject) { +static bool ConvertJavaArrayToDexFiles( + JNIEnv* env, + jobject arrayObject, + /*out*/ std::vector<const DexFile*>& dex_files, + /*out*/ const OatFile*& oat_file) { jarray array = reinterpret_cast<jarray>(arrayObject); jsize array_size = env->GetArrayLength(array); if (env->ExceptionCheck() == JNI_TRUE) { - return std::unique_ptr<std::vector<const DexFile*>>(); + return false; } // TODO: Optimize. On 32bit we can use an int array. @@ -54,27 +57,24 @@ ConvertJavaArrayToNative(JNIEnv* env, jobject arrayObject) { jlong* long_data = env->GetLongArrayElements(reinterpret_cast<jlongArray>(array), &is_long_data_copied); if (env->ExceptionCheck() == JNI_TRUE) { - return std::unique_ptr<std::vector<const DexFile*>>(); + return false; } - std::unique_ptr<std::vector<const DexFile*>> ret(new std::vector<const DexFile*>()); - ret->reserve(array_size); - for (jsize i = 0; i < array_size; ++i) { - ret->push_back(reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(*(long_data + i)))); + oat_file = reinterpret_cast<const OatFile*>(static_cast<uintptr_t>(long_data[kOatFileIndex])); + dex_files.reserve(array_size - 1); + for (jsize i = kDexFileIndexStart; i < array_size; ++i) { + dex_files.push_back(reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(long_data[i]))); } env->ReleaseLongArrayElements(reinterpret_cast<jlongArray>(array), long_data, JNI_ABORT); - if (env->ExceptionCheck() == JNI_TRUE) { - return std::unique_ptr<std::vector<const DexFile*>>(); - } - - return ret; + return env->ExceptionCheck() != JNI_TRUE; } -static jlongArray ConvertNativeToJavaArray(JNIEnv* env, - std::vector<std::unique_ptr<const DexFile>>& vec) { - size_t vec_size = vec.size(); - jlongArray long_array = env->NewLongArray(static_cast<jsize>(vec_size)); +static jlongArray ConvertDexFilesToJavaArray(JNIEnv* env, + const OatFile* oat_file, + std::vector<std::unique_ptr<const DexFile>>& vec) { + // Add one for the oat file. + jlongArray long_array = env->NewLongArray(static_cast<jsize>(1u + vec.size())); if (env->ExceptionCheck() == JNI_TRUE) { return nullptr; } @@ -85,10 +85,9 @@ static jlongArray ConvertNativeToJavaArray(JNIEnv* env, return nullptr; } - jlong* tmp = long_data; - for (auto& dex_file : vec) { - *tmp = reinterpret_cast<uintptr_t>(dex_file.get()); - tmp++; + long_data[kOatFileIndex] = reinterpret_cast<uintptr_t>(oat_file); + for (size_t i = 0; i < vec.size(); ++i) { + long_data[kDexFileIndexStart + i] = reinterpret_cast<uintptr_t>(vec[i].get()); } env->ReleaseLongArrayElements(long_array, long_data, 0); @@ -165,13 +164,15 @@ static jobject DexFile_openDexFileNative( ClassLinker* linker = runtime->GetClassLinker(); std::vector<std::unique_ptr<const DexFile>> dex_files; std::vector<std::string> error_msgs; + const OatFile* oat_file = nullptr; dex_files = runtime->GetOatFileManager().OpenDexFilesFromOat(sourceName.c_str(), outputName.c_str(), - &error_msgs); + /*out*/ &oat_file, + /*out*/ &error_msgs); if (!dex_files.empty()) { - jlongArray array = ConvertNativeToJavaArray(env, dex_files); + jlongArray array = ConvertDexFilesToJavaArray(env, oat_file, dex_files); if (array == nullptr) { ScopedObjectAccess soa(env); for (auto& dex_file : dex_files) { @@ -197,43 +198,54 @@ static jobject DexFile_openDexFileNative( } static jboolean DexFile_closeDexFile(JNIEnv* env, jclass, jobject cookie) { - ScopedObjectAccess soa(env); - mirror::Object* dex_files_object = soa.Decode<mirror::Object*>(cookie); - if (dex_files_object == nullptr) { - ThrowNullPointerException("cookie == null"); + std::vector<const DexFile*> dex_files; + const OatFile* oat_file; + if (!ConvertJavaArrayToDexFiles(env, cookie, dex_files, oat_file)) { + Thread::Current()->AssertPendingException(); return JNI_FALSE; } - mirror::LongArray* dex_files = dex_files_object->AsLongArray(); - - // Delete dex files associated with this dalvik.system.DexFile since there should not be running - // code using it. dex_files is a vector due to multidex. - ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); + Runtime* const runtime = Runtime::Current(); bool all_deleted = true; - for (int32_t i = 0, count = dex_files->GetLength(); i < count; ++i) { - auto* dex_file = reinterpret_cast<DexFile*>(dex_files->Get(i)); - if (dex_file == nullptr) { - continue; - } - // Only delete the dex file if the dex cache is not found to prevent runtime crashes if there - // are calls to DexFile.close while the ART DexFile is still in use. - if (class_linker->FindDexCache(soa.Self(), *dex_file, true) == nullptr) { - // Clear the element in the array so that we can call close again. - dex_files->Set(i, 0); - delete dex_file; - } else { - all_deleted = false; + { + ScopedObjectAccess soa(env); + mirror::Object* dex_files_object = soa.Decode<mirror::Object*>(cookie); + mirror::LongArray* long_dex_files = dex_files_object->AsLongArray(); + // Delete dex files associated with this dalvik.system.DexFile since there should not be running + // code using it. dex_files is a vector due to multidex. + ClassLinker* const class_linker = runtime->GetClassLinker(); + int32_t i = kDexFileIndexStart; // Oat file is at index 0. + for (const DexFile* dex_file : dex_files) { + if (dex_file != nullptr) { + // Only delete the dex file if the dex cache is not found to prevent runtime crashes if there + // are calls to DexFile.close while the ART DexFile is still in use. + if (class_linker->FindDexCache(soa.Self(), *dex_file, true) == nullptr) { + // Clear the element in the array so that we can call close again. + long_dex_files->Set(i, 0); + delete dex_file; + } else { + all_deleted = false; + } + } + ++i; } } - // TODO: Also unmap the OatFile for this dalvik.system.DexFile. - + if (all_deleted) { + // If all of the dex files are no longer in use we can unmap the corresponding oat file. + VLOG(class_linker) << "Unregistering " << oat_file; + runtime->GetOatFileManager().UnRegisterAndDeleteOatFile(oat_file); + } return all_deleted ? JNI_TRUE : JNI_FALSE; } -static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, jobject javaLoader, +static jclass DexFile_defineClassNative(JNIEnv* env, + jclass, + jstring javaName, + jobject javaLoader, jobject cookie) { - std::unique_ptr<std::vector<const DexFile*>> dex_files = ConvertJavaArrayToNative(env, cookie); - if (dex_files.get() == nullptr) { + std::vector<const DexFile*> dex_files; + const OatFile* oat_file; + if (!ConvertJavaArrayToDexFiles(env, cookie, /*out*/ dex_files, /*out*/ oat_file)) { VLOG(class_linker) << "Failed to find dex_file"; DCHECK(env->ExceptionCheck()); return nullptr; @@ -246,7 +258,7 @@ static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, j } const std::string descriptor(DotToDescriptor(class_name.c_str())); const size_t hash(ComputeModifiedUtf8Hash(descriptor.c_str())); - for (auto& dex_file : *dex_files) { + for (auto& dex_file : dex_files) { const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor.c_str(), hash); if (dex_class_def != nullptr) { ScopedObjectAccess soa(env); @@ -255,8 +267,12 @@ static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, j StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> class_loader( hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader))); - mirror::Class* result = class_linker->DefineClass(soa.Self(), descriptor.c_str(), hash, - class_loader, *dex_file, *dex_class_def); + mirror::Class* result = class_linker->DefineClass(soa.Self(), + descriptor.c_str(), + hash, + class_loader, + *dex_file, + *dex_class_def); if (result != nullptr) { VLOG(class_linker) << "DexFile_defineClassNative returning " << result << " for " << class_name.c_str(); @@ -277,8 +293,9 @@ struct CharPointerComparator { // Note: this can be an expensive call, as we sort out duplicates in MultiDex files. static jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jobject cookie) { - std::unique_ptr<std::vector<const DexFile*>> dex_files = ConvertJavaArrayToNative(env, cookie); - if (dex_files.get() == nullptr) { + const OatFile* oat_file = nullptr; + std::vector<const DexFile*> dex_files; + if (!ConvertJavaArrayToDexFiles(env, cookie, /*out */ dex_files, /* out */ oat_file)) { DCHECK(env->ExceptionCheck()); return nullptr; } @@ -286,7 +303,7 @@ static jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jobject cookie // Push all class descriptors into a set. Use set instead of unordered_set as we want to // retrieve all in the end. std::set<const char*, CharPointerComparator> descriptors; - for (auto& dex_file : *dex_files) { + for (auto& dex_file : dex_files) { for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) { const DexFile::ClassDef& class_def = dex_file->GetClassDef(i); const char* descriptor = dex_file->GetClassDescriptor(class_def); @@ -295,7 +312,8 @@ static jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jobject cookie } // Now create output array and copy the set into it. - jobjectArray result = env->NewObjectArray(descriptors.size(), WellKnownClasses::java_lang_String, + jobjectArray result = env->NewObjectArray(descriptors.size(), + WellKnownClasses::java_lang_String, nullptr); if (result != nullptr) { auto it = descriptors.begin(); @@ -313,9 +331,11 @@ static jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jobject cookie return result; } -static jint GetDexOptNeeded(JNIEnv* env, const char* filename, - const char* pkgname, const char* instruction_set, const jboolean defer) { - +static jint GetDexOptNeeded(JNIEnv* env, + const char* filename, + const char* pkgname, + const char* instruction_set, + const jboolean defer) { if ((filename == nullptr) || !OS::FileExists(filename)) { LOG(ERROR) << "DexFile_getDexOptNeeded file '" << filename << "' does not exist"; ScopedLocalRef<jclass> fnfe(env, env->FindClass("java/io/FileNotFoundException")); @@ -365,8 +385,12 @@ static jint GetDexOptNeeded(JNIEnv* env, const char* filename, return oat_file_assistant.GetDexOptNeeded(); } -static jint DexFile_getDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename, - jstring javaPkgname, jstring javaInstructionSet, jboolean defer) { +static jint DexFile_getDexOptNeeded(JNIEnv* env, + jclass, + jstring javaFilename, + jstring javaPkgname, + jstring javaInstructionSet, + jboolean defer) { ScopedUtfChars filename(env, javaFilename); if (env->ExceptionCheck()) { return 0; @@ -379,8 +403,11 @@ static jint DexFile_getDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename, return 0; } - return GetDexOptNeeded(env, filename.c_str(), pkgname.c_str(), - instruction_set.c_str(), defer); + return GetDexOptNeeded(env, + filename.c_str(), + pkgname.c_str(), + instruction_set.c_str(), + defer); } // public API, null pkgname diff --git a/runtime/native/dalvik_system_DexFile.h b/runtime/native/dalvik_system_DexFile.h index 7585ab972c..77d219dfad 100644 --- a/runtime/native/dalvik_system_DexFile.h +++ b/runtime/native/dalvik_system_DexFile.h @@ -18,9 +18,13 @@ #define ART_RUNTIME_NATIVE_DALVIK_SYSTEM_DEXFILE_H_ #include <jni.h> +#include <unistd.h> namespace art { +constexpr size_t kOatFileIndex = 0; +constexpr size_t kDexFileIndexStart = 1; + class DexFile; void register_dalvik_system_DexFile(JNIEnv* env); diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index de4e8ec717..cef8702937 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -961,13 +961,16 @@ class RaceGenerateTask : public Task { // we can verify only one oat file was loaded for the dex location. std::vector<std::unique_ptr<const DexFile>> dex_files; std::vector<std::string> error_msgs; + const OatFile* oat_file = nullptr; dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat( dex_location_.c_str(), oat_location_.c_str(), + &oat_file, &error_msgs); CHECK(!dex_files.empty()) << Join(error_msgs, '\n'); CHECK(dex_files[0]->GetOatDexFile() != nullptr) << dex_files[0]->GetLocation(); loaded_oat_file_ = dex_files[0]->GetOatDexFile()->GetOatFile(); + CHECK_EQ(loaded_oat_file_, oat_file); } const OatFile* GetLoadedOatFile() const { diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc index 73b065feaa..f7a2943244 100644 --- a/runtime/oat_file_manager.cc +++ b/runtime/oat_file_manager.cc @@ -33,9 +33,10 @@ namespace art { static constexpr bool kDuplicateClassesCheck = false; const OatFile* OatFileManager::RegisterOatFile(std::unique_ptr<const OatFile> oat_file) { - ReaderMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_); + WriterMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_); DCHECK(oat_file != nullptr); if (kIsDebugBuild) { + CHECK(oat_files_.find(oat_file) == oat_files_.end()); for (const std::unique_ptr<const OatFile>& existing : oat_files_) { CHECK_NE(oat_file.get(), existing.get()) << oat_file->GetLocation(); // Check that we don't have an oat file with the same address. Copies of the same oat file @@ -44,8 +45,19 @@ const OatFile* OatFileManager::RegisterOatFile(std::unique_ptr<const OatFile> oa } } have_non_pic_oat_file_ = have_non_pic_oat_file_ || !oat_file->IsPic(); - oat_files_.push_back(std::move(oat_file)); - return oat_files_.back().get(); + const OatFile* ret = oat_file.get(); + oat_files_.insert(std::move(oat_file)); + return ret; +} + +void OatFileManager::UnRegisterAndDeleteOatFile(const OatFile* oat_file) { + WriterMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_); + DCHECK(oat_file != nullptr); + std::unique_ptr<const OatFile> compare(oat_file); + auto it = oat_files_.find(compare); + CHECK(it != oat_files_.end()); + oat_files_.erase(it); + compare.release(); } const OatFile* OatFileManager::FindOpenedOatFileFromOatLocation(const std::string& oat_location) @@ -95,17 +107,9 @@ class DexFileAndClassPair : ValueObject { current_class_index_(current_class_index), from_loaded_oat_(from_loaded_oat) {} - DexFileAndClassPair(DexFileAndClassPair&& rhs) { - *this = std::move(rhs); - } + DexFileAndClassPair(DexFileAndClassPair&& rhs) = default; - DexFileAndClassPair& operator=(DexFileAndClassPair&& rhs) { - cached_descriptor_ = rhs.cached_descriptor_; - dex_file_ = std::move(rhs.dex_file_); - current_class_index_ = rhs.current_class_index_; - from_loaded_oat_ = rhs.from_loaded_oat_; - return *this; - } + DexFileAndClassPair& operator=(DexFileAndClassPair&& rhs) = default; const char* GetCachedDescriptor() const { return cached_descriptor_; @@ -127,6 +131,7 @@ class DexFileAndClassPair : ValueObject { void Next() { ++current_class_index_; + cached_descriptor_ = nullptr; } size_t GetCurrentClassIndex() const { @@ -253,6 +258,7 @@ bool OatFileManager::HasCollisions(const OatFile* oat_file, std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( const char* dex_location, const char* oat_location, + const OatFile** out_oat_file, std::vector<std::string>* error_msgs) { CHECK(dex_location != nullptr); CHECK(error_msgs != nullptr); @@ -311,6 +317,7 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( if (accept_oat_file) { VLOG(class_linker) << "Registering " << oat_file->GetLocation(); source_oat_file = RegisterOatFile(std::move(oat_file)); + *out_oat_file = source_oat_file; } } diff --git a/runtime/oat_file_manager.h b/runtime/oat_file_manager.h index 3059cb5bb7..0e4912bce9 100644 --- a/runtime/oat_file_manager.h +++ b/runtime/oat_file_manager.h @@ -18,6 +18,7 @@ #define ART_RUNTIME_OAT_FILE_MANAGER_H_ #include <memory> +#include <set> #include <string> #include <vector> @@ -49,6 +50,9 @@ class OatFileManager { const OatFile* RegisterOatFile(std::unique_ptr<const OatFile> oat_file) REQUIRES(!Locks::oat_file_manager_lock_); + void UnRegisterAndDeleteOatFile(const OatFile* oat_file) + REQUIRES(!Locks::oat_file_manager_lock_); + // Find the first opened oat file with the same location, returns null if there are none. const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location) const REQUIRES(!Locks::oat_file_manager_lock_); @@ -86,7 +90,8 @@ class OatFileManager { std::vector<std::unique_ptr<const DexFile>> OpenDexFilesFromOat( const char* dex_location, const char* oat_location, - /*out*/std::vector<std::string>* error_msgs) + /*out*/ const OatFile** out_oat_file, + /*out*/ std::vector<std::string>* error_msgs) REQUIRES(!Locks::oat_file_manager_lock_, !Locks::mutator_lock_); private: @@ -95,7 +100,7 @@ class OatFileManager { bool HasCollisions(const OatFile* oat_file, /*out*/std::string* error_msg) const REQUIRES(!Locks::oat_file_manager_lock_); - std::vector<std::unique_ptr<const OatFile>> oat_files_ GUARDED_BY(Locks::oat_file_manager_lock_); + std::set<std::unique_ptr<const OatFile>> oat_files_ GUARDED_BY(Locks::oat_file_manager_lock_); bool have_non_pic_oat_file_; DISALLOW_COPY_AND_ASSIGN(OatFileManager); }; diff --git a/test/141-class-unload/expected.txt b/test/141-class-unload/expected.txt index 53d7abecaf..11de660c43 100644 --- a/test/141-class-unload/expected.txt +++ b/test/141-class-unload/expected.txt @@ -21,3 +21,4 @@ null JNI_OnLoad called class null false test JNI_OnUnload called +Number of loaded unload-ex maps 0 diff --git a/test/141-class-unload/src/Main.java b/test/141-class-unload/src/Main.java index 3cc43accbe..0640b364c9 100644 --- a/test/141-class-unload/src/Main.java +++ b/test/141-class-unload/src/Main.java @@ -14,6 +14,9 @@ * limitations under the License. */ +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; import java.lang.ref.WeakReference; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -43,11 +46,28 @@ public class Main { testStackTrace(constructor); // Stress test to make sure we dont leak memory. stressTest(constructor); + // Test that the oat files are unloaded. + testOatFilesUnloaded(getPid()); } catch (Exception e) { System.out.println(e); } } + private static void testOatFilesUnloaded(int pid) throws Exception { + BufferedReader reader = new BufferedReader(new FileReader ("/proc/" + pid + "/maps")); + String line; + int count = 0; + Runtime.getRuntime().gc(); + System.runFinalization(); + while ((line = reader.readLine()) != null) { + if (line.contains("@141-class-unload-ex.jar")) { + System.out.println(line); + ++count; + } + } + System.out.println("Number of loaded unload-ex maps " + count); + } + private static void stressTest(Constructor constructor) throws Exception { for (int i = 0; i <= 100; ++i) { setUpUnloadLoader(constructor, false); @@ -163,4 +183,8 @@ public class Main { loadLibrary.invoke(intHolder, nativeLibraryName); return new WeakReference(loader); } + + private static int getPid() throws Exception { + return Integer.parseInt(new File("/proc/self").getCanonicalFile().getName()); + } } |