summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/Android.common_build.mk21
-rw-r--r--compiler/dex/quick/codegen_util.cc4
-rw-r--r--compiler/dex/verification_results.cc9
-rw-r--r--compiler/dex/verification_results.h1
-rw-r--r--compiler/driver/compiler_driver.cc42
-rw-r--r--compiler/driver/compiler_driver.h4
-rw-r--r--compiler/driver/dex_compilation_unit.h6
-rw-r--r--dex2oat/dex2oat.cc29
-rw-r--r--test/004-JniTest/jni_test.cc20
9 files changed, 93 insertions, 43 deletions
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index 5dd9f1534c..63469703f2 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -259,16 +259,21 @@ ifeq ($(HOST_OS),linux)
art_target_non_debug_cflags += -Wframe-larger-than=1728
endif
-ifndef LIBART_IMG_HOST_BASE_ADDRESS
- $(error LIBART_IMG_HOST_BASE_ADDRESS unset)
-endif
-ART_HOST_CFLAGS += $(art_cflags) -DART_BASE_ADDRESS=$(LIBART_IMG_HOST_BASE_ADDRESS)
-ART_HOST_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES=default
+# DALVIK_VM_LIB will be empty for VM-less builds. Avoid $(error) calls here because
+# LIBART_IMG_XXX variables won't be defined.
+ifneq ($(DALVIK_VM_LIB),)
+ ifndef LIBART_IMG_HOST_BASE_ADDRESS
+ $(error LIBART_IMG_HOST_BASE_ADDRESS unset)
+ endif
+ ART_HOST_CFLAGS += $(art_cflags) -DART_BASE_ADDRESS=$(LIBART_IMG_HOST_BASE_ADDRESS)
+ ART_HOST_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES=default
-ifndef LIBART_IMG_TARGET_BASE_ADDRESS
- $(error LIBART_IMG_TARGET_BASE_ADDRESS unset)
+ ifndef LIBART_IMG_TARGET_BASE_ADDRESS
+ $(error LIBART_IMG_TARGET_BASE_ADDRESS unset)
+ endif
+ ART_TARGET_CFLAGS += $(art_cflags) \
+ -DART_TARGET -DART_BASE_ADDRESS=$(LIBART_IMG_TARGET_BASE_ADDRESS)
endif
-ART_TARGET_CFLAGS += $(art_cflags) -DART_TARGET -DART_BASE_ADDRESS=$(LIBART_IMG_TARGET_BASE_ADDRESS)
ART_HOST_NON_DEBUG_CFLAGS := $(art_host_non_debug_cflags)
ART_TARGET_NON_DEBUG_CFLAGS := $(art_target_non_debug_cflags)
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 58bcee2124..00217549b0 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -775,6 +775,10 @@ void Mir2Lir::CreateNativeGcMap() {
": " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
native_gc_map_builder.AddEntry(native_offset, references);
}
+
+ // Maybe not necessary, but this could help prevent errors where we access the verified method
+ // after it has been deleted.
+ mir_graph_->GetCurrentDexCompilationUnit()->ClearVerifiedMethod();
}
/* Determine the offset of each literal field */
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index 4929b5b2b0..932a532e56 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -84,6 +84,15 @@ const VerifiedMethod* VerificationResults::GetVerifiedMethod(MethodReference ref
return (it != verified_methods_.end()) ? it->second : nullptr;
}
+void VerificationResults::RemoveVerifiedMethod(MethodReference ref) {
+ WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
+ auto it = verified_methods_.find(ref);
+ if (it != verified_methods_.end()) {
+ delete it->second;
+ verified_methods_.erase(it);
+ }
+}
+
void VerificationResults::AddRejectedClass(ClassReference ref) {
{
WriterMutexLock mu(Thread::Current(), rejected_classes_lock_);
diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h
index 0e7923fbc3..7fc2a2363d 100644
--- a/compiler/dex/verification_results.h
+++ b/compiler/dex/verification_results.h
@@ -48,6 +48,7 @@ class VerificationResults {
const VerifiedMethod* GetVerifiedMethod(MethodReference ref)
LOCKS_EXCLUDED(verified_methods_lock_);
+ void RemoveVerifiedMethod(MethodReference ref) LOCKS_EXCLUDED(verified_methods_lock_);
void AddRejectedClass(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
bool IsClassRejected(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index ab9f41a4b3..e4274712d4 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -23,6 +23,10 @@
#include <vector>
#include <unistd.h>
+#ifndef __APPLE__
+#include <malloc.h> // For mallinfo
+#endif
+
#include "base/stl_util.h"
#include "base/timing_logger.h"
#include "class_linker.h"
@@ -497,6 +501,7 @@ void CompilerDriver::CompileAll(jobject class_loader,
TimingLogger* timings) {
DCHECK(!Runtime::Current()->IsStarted());
std::unique_ptr<ThreadPool> thread_pool(new ThreadPool("Compiler driver thread pool", thread_count_ - 1));
+ VLOG(compiler) << "Before precompile " << GetMemoryUsageString();
PreCompile(class_loader, dex_files, thread_pool.get(), timings);
Compile(class_loader, dex_files, thread_pool.get(), timings);
if (dump_stats_) {
@@ -593,20 +598,25 @@ void CompilerDriver::Resolve(jobject class_loader, const std::vector<const DexFi
void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
ThreadPool* thread_pool, TimingLogger* timings) {
LoadImageClasses(timings);
+ VLOG(compiler) << "LoadImageClasses: " << GetMemoryUsageString();
Resolve(class_loader, dex_files, thread_pool, timings);
+ VLOG(compiler) << "Resolve: " << GetMemoryUsageString();
if (!compiler_options_->IsVerificationEnabled()) {
- LOG(INFO) << "Verify none mode specified, skipping verification.";
+ VLOG(compiler) << "Verify none mode specified, skipping verification.";
SetVerified(class_loader, dex_files, thread_pool, timings);
return;
}
Verify(class_loader, dex_files, thread_pool, timings);
+ VLOG(compiler) << "Verify: " << GetMemoryUsageString();
InitializeClasses(class_loader, dex_files, thread_pool, timings);
+ VLOG(compiler) << "InitializeClasses: " << GetMemoryUsageString();
UpdateImageClasses(timings);
+ VLOG(compiler) << "UpdateImageClasses: " << GetMemoryUsageString();
}
bool CompilerDriver::IsImageClass(const char* descriptor) const {
@@ -2002,6 +2012,7 @@ void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFi
CHECK(dex_file != nullptr);
CompileDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
}
+ VLOG(compiler) << "Compile: " << GetMemoryUsageString();
}
void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, size_t class_def_index) {
@@ -2128,6 +2139,7 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t
bool compilation_enabled) {
CompiledMethod* compiled_method = nullptr;
uint64_t start_ns = kTimeCompileMethod ? NanoTime() : 0;
+ MethodReference method_ref(&dex_file, method_idx);
if ((access_flags & kAccNative) != 0) {
// Are we interpreting only and have support for generic JNI down calls?
@@ -2141,7 +2153,6 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t
} else if ((access_flags & kAccAbstract) != 0) {
// Abstract methods don't have code.
} else {
- MethodReference method_ref(&dex_file, method_idx);
bool compile = compilation_enabled &&
verification_results_->IsCandidateForCompilation(method_ref, access_flags);
if (compile) {
@@ -2178,16 +2189,18 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t
// When compiling with PIC, there should be zero non-relative linker patches
CHECK(!compile_pic || non_relative_linker_patch_count == 0u);
- MethodReference ref(&dex_file, method_idx);
- DCHECK(GetCompiledMethod(ref) == nullptr) << PrettyMethod(method_idx, dex_file);
+ DCHECK(GetCompiledMethod(method_ref) == nullptr) << PrettyMethod(method_idx, dex_file);
{
MutexLock mu(self, compiled_methods_lock_);
- compiled_methods_.Put(ref, compiled_method);
+ compiled_methods_.Put(method_ref, compiled_method);
non_relative_linker_patch_count_ += non_relative_linker_patch_count;
}
- DCHECK(GetCompiledMethod(ref) != nullptr) << PrettyMethod(method_idx, dex_file);
+ DCHECK(GetCompiledMethod(method_ref) != nullptr) << PrettyMethod(method_idx, dex_file);
}
+ // Done compiling, delete the verified method to reduce native memory usage.
+ verification_results_->RemoveVerifiedMethod(method_ref);
+
if (self->IsExceptionPending()) {
ScopedObjectAccess soa(self);
LOG(FATAL) << "Unexpected exception compiling: " << PrettyMethod(method_idx, dex_file) << "\n"
@@ -2337,4 +2350,21 @@ bool CompilerDriver::SkipCompilation(const std::string& method_name) {
}
return !compile;
}
+
+std::string CompilerDriver::GetMemoryUsageString() const {
+ std::ostringstream oss;
+ const ArenaPool* arena_pool = GetArenaPool();
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ oss << "arena alloc=" << PrettySize(arena_pool->GetBytesAllocated());
+ oss << " java alloc=" << PrettySize(heap->GetBytesAllocated());
+#ifdef HAVE_MALLOC_H
+ struct mallinfo info = mallinfo();
+ const size_t allocated_space = static_cast<size_t>(info.uordblks);
+ const size_t free_space = static_cast<size_t>(info.fordblks);
+ oss << " native alloc=" << PrettySize(allocated_space) << " free="
+ << PrettySize(free_space);
+#endif
+ return oss.str();
+}
+
} // namespace art
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index d837dbc9cd..615e0d0db4 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -39,6 +39,7 @@
#include "thread_pool.h"
#include "utils/arena_allocator.h"
#include "utils/dedupe_set.h"
+#include "dex/verified_method.h"
namespace art {
@@ -398,6 +399,9 @@ class CompilerDriver {
// Should the compiler run on this method given profile information?
bool SkipCompilation(const std::string& method_name);
+ // Get memory usage during compilation.
+ std::string GetMemoryUsageString() const;
+
private:
// These flags are internal to CompilerDriver for collecting INVOKE resolution statistics.
// The only external contract is that unresolved method has flags 0 and resolved non-0.
diff --git a/compiler/driver/dex_compilation_unit.h b/compiler/driver/dex_compilation_unit.h
index 84f57991c3..03ae489da1 100644
--- a/compiler/driver/dex_compilation_unit.h
+++ b/compiler/driver/dex_compilation_unit.h
@@ -102,6 +102,10 @@ class DexCompilationUnit {
return verified_method_;
}
+ void ClearVerifiedMethod() {
+ verified_method_ = nullptr;
+ }
+
const std::string& GetSymbol();
private:
@@ -117,7 +121,7 @@ class DexCompilationUnit {
const uint16_t class_def_idx_;
const uint32_t dex_method_idx_;
const uint32_t access_flags_;
- const VerifiedMethod* const verified_method_;
+ const VerifiedMethod* verified_method_;
std::string symbol_;
};
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index a1ac2f0761..d7669e1104 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -25,10 +25,6 @@
#include <string>
#include <vector>
-#ifndef __APPLE__
-#include <malloc.h> // For mallinfo
-#endif
-
#if defined(__linux__) && defined(__arm__)
#include <sys/personality.h>
#include <sys/utsname.h>
@@ -987,6 +983,12 @@ class Dex2Oat FINAL {
return true;
}
+ void EraseOatFile() {
+ DCHECK(oat_file_.get() != nullptr);
+ oat_file_->Erase();
+ oat_file_.reset();
+ }
+
// Set up the environment for compilation. Includes starting the runtime and loading/opening the
// boot class path.
bool Setup() {
@@ -1301,7 +1303,6 @@ class Dex2Oat FINAL {
if (!driver_->WriteElf(android_root_, is_host_, dex_files_, oat_writer.get(),
oat_file_.get())) {
LOG(ERROR) << "Failed to write ELF file " << oat_file_->GetPath();
- oat_file_->Erase();
return false;
}
}
@@ -1609,20 +1610,9 @@ class Dex2Oat FINAL {
}
void LogCompletionTime() {
- std::ostringstream mallinfostr;
-#ifdef HAVE_MALLOC_H
- struct mallinfo info = mallinfo();
- const size_t allocated_space = static_cast<size_t>(info.uordblks);
- const size_t free_space = static_cast<size_t>(info.fordblks);
- mallinfostr << " native alloc=" << PrettySize(allocated_space) << " free="
- << PrettySize(free_space);
-#endif
- const ArenaPool* arena_pool = driver_->GetArenaPool();
- gc::Heap* heap = Runtime::Current()->GetHeap();
LOG(INFO) << "dex2oat took " << PrettyDuration(NanoTime() - start_ns_)
- << " (threads: " << thread_count_ << ")"
- << " arena alloc=" << PrettySize(arena_pool->GetBytesAllocated())
- << " java alloc=" << PrettySize(heap->GetBytesAllocated()) << mallinfostr.str();
+ << " (threads: " << thread_count_ << ") "
+ << driver_->GetMemoryUsageString();
}
std::unique_ptr<CompilerOptions> compiler_options_;
@@ -1712,6 +1702,7 @@ static int CompileImage(Dex2Oat& dex2oat) {
// Create the boot.oat.
if (!dex2oat.CreateOatFile()) {
+ dex2oat.EraseOatFile();
return EXIT_FAILURE;
}
@@ -1756,6 +1747,7 @@ static int CompileApp(Dex2Oat& dex2oat) {
// Create the app oat.
if (!dex2oat.CreateOatFile()) {
+ dex2oat.EraseOatFile();
return EXIT_FAILURE;
}
@@ -1813,6 +1805,7 @@ static int dex2oat(int argc, char** argv) {
LOG(INFO) << CommandLine();
if (!dex2oat.Setup()) {
+ dex2oat.EraseOatFile();
return EXIT_FAILURE;
}
diff --git a/test/004-JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc
index c2877be02e..544cbc503e 100644
--- a/test/004-JniTest/jni_test.cc
+++ b/test/004-JniTest/jni_test.cc
@@ -294,20 +294,20 @@ static void testShallowGetCallingClassLoader(JNIEnv* env) {
assert(!env->ExceptionCheck());
// Create a string object.
- jobject library_string = env->NewStringUTF("arttest");
+ jobject library_string = env->NewStringUTF("non_existing_library");
assert(library_string != nullptr);
assert(!env->ExceptionCheck());
env->CallStaticVoidMethod(system_clazz, loadLibraryMethodId, library_string);
- if (env->ExceptionCheck()) {
- // At most we expect UnsatisfiedLinkError.
- jthrowable thrown = env->ExceptionOccurred();
- env->ExceptionClear();
-
- jclass unsatisfied_link_error_clazz = env->FindClass("java/lang/UnsatisfiedLinkError");
- jclass thrown_class = env->GetObjectClass(thrown);
- assert(env->IsSameObject(unsatisfied_link_error_clazz, thrown_class));
- }
+ assert(env->ExceptionCheck());
+
+ // We expect UnsatisfiedLinkError.
+ jthrowable thrown = env->ExceptionOccurred();
+ env->ExceptionClear();
+
+ jclass unsatisfied_link_error_clazz = env->FindClass("java/lang/UnsatisfiedLinkError");
+ jclass thrown_class = env->GetObjectClass(thrown);
+ assert(env->IsSameObject(unsatisfied_link_error_clazz, thrown_class));
}
}