Refactor the compilers out of libart. This builds three separate compilers and dynamically links with the right one at runtime. Change-Id: I59d22b9884f41de733c09f97e29ee290236d5f4b
diff --git a/src/card_table.cc b/src/card_table.cc index 386b27c..dc61c0a 100644 --- a/src/card_table.cc +++ b/src/card_table.cc
@@ -21,6 +21,7 @@ #include "heap.h" #include "heap_bitmap.h" #include "logging.h" +#include "runtime.h" #include "utils.h" namespace art { @@ -96,6 +97,7 @@ } void CardTable::Scan(byte* heap_begin, byte* heap_end, Callback* visitor, void* arg) const { + Heap* heap = Runtime::Current()->GetHeap(); byte* card_cur = CardFromAddr(heap_begin); byte* card_end = CardFromAddr(heap_end); while (card_cur < card_end) { @@ -110,7 +112,7 @@ } if (run > 0) { byte* run_end = &card_cur[run]; - Heap::GetLiveBits()->VisitRange(reinterpret_cast<uintptr_t>(AddrFromCard(run_start)), + heap->GetLiveBits()->VisitRange(reinterpret_cast<uintptr_t>(AddrFromCard(run_start)), reinterpret_cast<uintptr_t>(AddrFromCard(run_end)), visitor, arg); }
diff --git a/src/check_jni.cc b/src/check_jni.cc index 6dc47f7..b8a492d 100644 --- a/src/check_jni.cc +++ b/src/check_jni.cc
@@ -23,6 +23,7 @@ #include "logging.h" #include "object_utils.h" #include "scoped_jni_thread_state.h" +#include "space.h" #include "thread.h" #include "runtime.h" @@ -196,7 +197,7 @@ * obj will be NULL. Otherwise, obj should always be non-NULL * and valid. */ - if (obj != NULL && !Heap::IsHeapAddress(obj)) { + if (obj != NULL && !Runtime::Current()->GetHeap()->IsHeapAddress(obj)) { LOG(ERROR) << "JNI ERROR: field operation on invalid " << GetIndirectRefKind(java_object) << ": " << java_object; JniAbort(); return; @@ -234,7 +235,7 @@ ScopedJniThreadState ts(env_); Object* o = Decode<Object*>(ts, java_object); - if (o == NULL || !Heap::IsHeapAddress(o)) { + if (o == NULL || !Runtime::Current()->GetHeap()->IsHeapAddress(o)) { LOG(ERROR) << "JNI ERROR: field operation on invalid " << GetIndirectRefKind(java_object) << ": " << java_object; JniAbort(); return; @@ -449,7 +450,7 @@ Class* c = reinterpret_cast<Class*>(Thread::Current()->DecodeJObject(jc)); if (c == NULL) { msg += "NULL"; - } else if (c == kInvalidIndirectRefObject || !Heap::IsHeapAddress(c)) { + } else if (c == kInvalidIndirectRefObject || !Runtime::Current()->GetHeap()->IsHeapAddress(c)) { StringAppendF(&msg, "INVALID POINTER:%p", jc); } else if (!c->IsClass()) { msg += "INVALID NON-CLASS OBJECT OF TYPE:" + PrettyTypeOf(c); @@ -617,8 +618,9 @@ ScopedJniThreadState ts(env_); Object* obj = Decode<Object*>(ts, java_object); - if (!Heap::IsHeapAddress(obj)) { - LOG(ERROR) << "JNI ERROR: " << what << " is an invalid " << GetIndirectRefKind(java_object) << ": " << java_object; + if (!Runtime::Current()->GetHeap()->IsHeapAddress(obj)) { + LOG(ERROR) << "JNI ERROR: " << what << " is an invalid " << GetIndirectRefKind(java_object) << ": " + << java_object << " (" << obj << ")"; JniAbort(); return false; } @@ -676,8 +678,8 @@ ScopedJniThreadState ts(env_); Array* a = Decode<Array*>(ts, java_array); - if (!Heap::IsHeapAddress(a)) { - LOG(ERROR) << "JNI ERROR: jarray is an invalid " << GetIndirectRefKind(java_array) << ": " << reinterpret_cast<void*>(java_array); + if (!Runtime::Current()->GetHeap()->IsHeapAddress(a)) { + LOG(ERROR) << "JNI ERROR: jarray is an invalid " << GetIndirectRefKind(java_array) << ": " << reinterpret_cast<void*>(java_array) << " (" << a << ")"; JniAbort(); } else if (!a->IsArrayInstance()) { LOG(ERROR) << "JNI ERROR: jarray argument has non-array type: " << PrettyTypeOf(a); @@ -699,7 +701,7 @@ return NULL; } Field* f = DecodeField(fid); - if (!Heap::IsHeapAddress(f)) { + if (!Runtime::Current()->GetHeap()->IsHeapAddress(f)) { LOG(ERROR) << "JNI ERROR: invalid jfieldID: " << fid; JniAbort(); return NULL; @@ -714,7 +716,7 @@ return NULL; } Method* m = DecodeMethod(mid); - if (!Heap::IsHeapAddress(m)) { + if (!Runtime::Current()->GetHeap()->IsHeapAddress(m)) { LOG(ERROR) << "JNI ERROR: invalid jmethodID: " << mid; JniAbort(); return NULL; @@ -736,7 +738,7 @@ ScopedJniThreadState ts(env_); Object* o = Decode<Object*>(ts, java_object); - if (o != NULL && !Heap::IsHeapAddress(o)) { + if (o != NULL && !Runtime::Current()->GetHeap()->IsHeapAddress(o)) { // TODO: when we remove work_around_app_jni_bugs, this should be impossible. LOG(ERROR) << "JNI ERROR: native code passing in reference to invalid " << GetIndirectRefKind(java_object) << ": " << java_object; JniAbort();
diff --git a/src/class_linker.cc b/src/class_linker.cc index dd7f099..06ae301 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc
@@ -241,7 +241,8 @@ CHECK(!init_done_); // java_lang_Class comes first, it's needed for AllocClass - SirtRef<Class> java_lang_Class(down_cast<Class*>(Heap::AllocObject(NULL, sizeof(ClassClass)))); + Heap* heap = Runtime::Current()->GetHeap(); + SirtRef<Class> java_lang_Class(down_cast<Class*>(heap->AllocObject(NULL, sizeof(ClassClass)))); CHECK(java_lang_Class.get() != NULL); java_lang_Class->SetClass(java_lang_Class.get()); java_lang_Class->SetClassSize(sizeof(ClassClass)); @@ -484,7 +485,8 @@ Class* java_lang_ref_ReferenceQueue = FindSystemClass("Ljava/lang/ref/ReferenceQueue;"); Class* java_lang_ref_FinalizerReference = FindSystemClass("Ljava/lang/ref/FinalizerReference;"); - Heap::SetWellKnownClasses(java_lang_ref_FinalizerReference, java_lang_ref_ReferenceQueue); + Heap* heap = Runtime::Current()->GetHeap(); + heap->SetWellKnownClasses(java_lang_ref_FinalizerReference, java_lang_ref_ReferenceQueue); const DexFile& java_lang_dex = FindDexFile(java_lang_ref_Reference->GetDexCache()); @@ -518,7 +520,7 @@ CHECK_EQ(java_lang_dex.GetFieldId(zombie->GetDexFieldIndex()).type_idx_, GetClassRoot(kJavaLangObject)->GetDexTypeIndex()); - Heap::SetReferenceOffsets(referent->GetOffset(), + heap->SetReferenceOffsets(referent->GetOffset(), queue->GetOffset(), queueNext->GetOffset(), pendingNext->GetOffset(), @@ -566,8 +568,9 @@ const char* class_path = Runtime::Current()->GetClassPathString().c_str(); + Heap* heap = Runtime::Current()->GetHeap(); std::string boot_image_option_string("--boot-image="); - boot_image_option_string += Heap::GetSpaces()[0]->AsImageSpace()->GetImageFilename(); + boot_image_option_string += heap->GetSpaces()[0]->AsImageSpace()->GetImageFilename(); const char* boot_image_option = boot_image_option_string.c_str(); std::string dex_file_option_string("--dex-file="); @@ -871,8 +874,9 @@ VLOG(startup) << "ClassLinker::InitFromImage entering"; CHECK(!init_done_); - const std::vector<Space*>& spaces = Heap::GetSpaces(); - for (size_t i = 0; i < spaces.size(); i++) { + Heap* heap = Runtime::Current()->GetHeap(); + const std::vector<Space*>& spaces = heap->GetSpaces(); + for (size_t i = 0; i < spaces.size(); ++i) { if (spaces[i]->IsImageSpace()) { ImageSpace* space = spaces[i]->AsImageSpace(); OatFile* oat_file = OpenOat(space); @@ -907,7 +911,7 @@ } } - HeapBitmap* heap_bitmap = Heap::GetLiveBits(); + HeapBitmap* heap_bitmap = heap->GetLiveBits(); DCHECK(heap_bitmap != NULL); // reinit clases_ table @@ -1065,7 +1069,8 @@ Class* ClassLinker::AllocClass(Class* java_lang_Class, size_t class_size) { DCHECK_GE(class_size, sizeof(Class)); - SirtRef<Class> klass(Heap::AllocObject(java_lang_Class, class_size)->AsClass()); + Heap* heap = Runtime::Current()->GetHeap(); + SirtRef<Class> klass(heap->AllocObject(java_lang_Class, class_size)->AsClass()); klass->SetPrimitiveType(Primitive::kPrimNot); // default to not being primitive klass->SetClassSize(class_size); return klass.get(); @@ -1147,7 +1152,7 @@ return DefineClass(descriptor, NULL, *pair.first, *pair.second); } - } else if (ClassLoader::UseCompileTimeClassPath()) { + } else if (Runtime::Current()->UseCompileTimeClassPath()) { // first try the boot class path Class* system_class = FindSystemClass(descriptor); if (system_class != NULL) { @@ -1158,7 +1163,7 @@ // next try the compile time class path const std::vector<const DexFile*>& class_path - = ClassLoader::GetCompileTimeClassPath(class_loader); + = Runtime::Current()->GetCompileTimeClassPath(class_loader); DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, class_path); if (pair.second != NULL) { return DefineClass(descriptor, class_loader, *pair.first, *pair.second); @@ -1320,7 +1325,7 @@ const OatFile::OatClass* ClassLinker::GetOatClass(const DexFile& dex_file, const char* descriptor) { DCHECK(descriptor != NULL); - if (!Runtime::Current()->IsStarted() || ClassLoader::UseCompileTimeClassPath()) { + if (!Runtime::Current()->IsStarted() || Runtime::Current()->UseCompileTimeClassPath()) { return NULL; } const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file); @@ -2032,7 +2037,7 @@ if (!Runtime::Current()->IsStarted()) { return false; } - if (ClassLoader::UseCompileTimeClassPath()) { + if (Runtime::Current()->UseCompileTimeClassPath()) { return false; } const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc index 8c97cf1..a6a58d6 100644 --- a/src/class_linker_test.cc +++ b/src/class_linker_test.cc
@@ -964,7 +964,7 @@ // case 2, get the initialized storage from StaticsFromCode.getS0 SirtRef<ClassLoader> class_loader(LoadDex("StaticsFromCode")); - const DexFile* dex_file = ClassLoader::GetCompileTimeClassPath(class_loader.get())[0]; + const DexFile* dex_file = Runtime::Current()->GetCompileTimeClassPath(class_loader.get())[0]; CHECK(dex_file != NULL); Class* klass = class_linker_->FindClass("LStaticsFromCode;", class_loader.get());
diff --git a/src/class_loader.cc b/src/class_loader.cc index 6b6297b..3adb4ec 100644 --- a/src/class_loader.cc +++ b/src/class_loader.cc
@@ -21,27 +21,6 @@ namespace art { -bool ClassLoader::use_compile_time_class_path = false; -ClassLoader::Table ClassLoader::compile_time_class_paths_; - -const std::vector<const DexFile*>& ClassLoader::GetCompileTimeClassPath(const ClassLoader* class_loader) { - Runtime* runtime = Runtime::Current(); - if (class_loader == NULL) { - return runtime->GetClassLinker()->GetBootClassPath(); - } - CHECK(ClassLoader::UseCompileTimeClassPath()); - Table::const_iterator it = compile_time_class_paths_.find(class_loader); - CHECK(it != compile_time_class_paths_.end()); - return it->second; -} - -void ClassLoader::SetCompileTimeClassPath(const ClassLoader* class_loader, - std::vector<const DexFile*>& class_path) { - CHECK(!Runtime::Current()->IsStarted()); - use_compile_time_class_path = true; - compile_time_class_paths_[class_loader] = class_path; -} - // TODO: get global references for these Class* PathClassLoader::dalvik_system_PathClassLoader_ = NULL; @@ -49,7 +28,7 @@ CHECK(!Runtime::Current()->IsStarted()); DCHECK(dalvik_system_PathClassLoader_ != NULL); SirtRef<PathClassLoader> p(down_cast<PathClassLoader*>(dalvik_system_PathClassLoader_->AllocObject())); - SetCompileTimeClassPath(p.get(), dex_files); + Runtime::Current()->SetCompileTimeClassPath(p.get(), dex_files); return p.get(); }
diff --git a/src/class_loader.h b/src/class_loader.h index 018cea9..8d1c696 100644 --- a/src/class_loader.h +++ b/src/class_loader.h
@@ -17,7 +17,6 @@ #ifndef ART_SRC_CLASS_LOADER_H_ #define ART_SRC_CLASS_LOADER_H_ -#include <map> #include <vector> #include "dex_file.h" @@ -27,31 +26,18 @@ // C++ mirror of java.lang.ClassLoader class MANAGED ClassLoader : public Object { - public: - static const std::vector<const DexFile*>& GetCompileTimeClassPath(const ClassLoader* class_loader); - static void SetCompileTimeClassPath(const ClassLoader* class_loader, std::vector<const DexFile*>& class_path); - static bool UseCompileTimeClassPath() { - return use_compile_time_class_path; - } - private: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". Object* packages_; ClassLoader* parent_; Object* proxyCache_; - typedef std::map<const ClassLoader*, std::vector<const DexFile*> > Table; - static Table compile_time_class_paths_; - - static bool use_compile_time_class_path; - friend struct ClassLoaderOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(ClassLoader); }; // C++ mirror of dalvik.system.BaseDexClassLoader -// TODO: add MANAGED when class_path_ removed -class BaseDexClassLoader : public ClassLoader { +class MANAGED BaseDexClassLoader : public ClassLoader { private: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". String* original_path_; @@ -62,8 +48,7 @@ }; // C++ mirror of dalvik.system.PathClassLoader -// TODO: add MANAGED when class_path_ removed -class PathClassLoader : public BaseDexClassLoader { +class MANAGED PathClassLoader : public BaseDexClassLoader { public: static PathClassLoader* AllocCompileTime(std::vector<const DexFile*>& dex_files); static void SetClass(Class* dalvik_system_PathClassLoader); @@ -76,4 +61,4 @@ } // namespace art -#endif // ART_SRC_OBJECT_H_ +#endif // ART_SRC_CLASS_LOADER_H_
diff --git a/src/common_test.h b/src/common_test.h index dfee9b9..7da5c77 100644 --- a/src/common_test.h +++ b/src/common_test.h
@@ -355,7 +355,7 @@ compiler_->GetCompilerLLVM()->SetElfFileName("gtest"); #endif - Heap::VerifyHeap(); // Check for heap corruption before the test + Runtime::Current()->GetHeap()->VerifyHeap(); // Check for heap corruption before the test } virtual void TearDown() { @@ -398,7 +398,7 @@ compiler_.reset(); STLDeleteElements(&opened_dex_files_); - Heap::VerifyHeap(); // Check for heap corruption after the test + Runtime::Current()->GetHeap()->VerifyHeap(); // Check for heap corruption after the test } std::string GetLibCoreDexFileName() {
diff --git a/src/compiler.cc b/src/compiler.cc index 332ea25..9539972 100644 --- a/src/compiler.cc +++ b/src/compiler.cc
@@ -18,6 +18,7 @@ #include <vector> +#include <dlfcn.h> #include <sys/mman.h> #include <unistd.h> @@ -31,6 +32,7 @@ #include "oat_file.h" #include "object_utils.h" #include "runtime.h" +#include "space.h" #include "stl_util.h" #include "timing_logger.h" @@ -44,13 +46,6 @@ namespace art { -#if !defined(ART_USE_LLVM_COMPILER) -CompiledMethod* oatCompileMethod(Compiler& compiler, const DexFile::CodeItem* code_item, - uint32_t access_flags, uint32_t method_idx, - const ClassLoader* class_loader, - const DexFile& dex_file, InstructionSet); -#endif - namespace arm { ByteArray* CreateAbstractMethodErrorStub(); CompiledInvokeStub* ArmCreateInvokeStub(bool is_static, const char* shorty, uint32_t shorty_len); @@ -213,6 +208,28 @@ DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);; }; +static std::string MakeCompilerSoName(InstructionSet instruction_set) { + // TODO: is the ARM/Thumb2 instruction set distinction really buying us anything, + // or just causing hassle like this? + if (instruction_set == kThumb2) { + instruction_set = kArm; + } + + std::ostringstream instruction_set_name_os; + instruction_set_name_os << instruction_set; + std::string instruction_set_name(instruction_set_name_os.str()); + for (size_t i = 0; i < instruction_set_name.size(); ++i) { + instruction_set_name[i] = toupper(instruction_set_name[i]); + } +#ifndef NDEBUG + const char* suffix = "d"; +#else + const char* suffix = ""; +#endif + std::string name(StringPrintf("art%s-compiler-%s", suffix, instruction_set_name.c_str())); + return StringPrintf(OS_SHARED_LIB_FORMAT_STR, name.c_str()); +} + Compiler::Compiler(InstructionSet instruction_set, bool image, size_t thread_count, bool support_debugging, const std::set<std::string>* image_classes) : instruction_set_(instruction_set), @@ -226,12 +243,28 @@ thread_count_(thread_count), support_debugging_(support_debugging), stats_(new AOTCompilationStats), - image_classes_(image_classes) -#if defined(ART_USE_LLVM_COMPILER) - , + image_classes_(image_classes), +#if !defined(ART_USE_LLVM_COMPILER) + compiler_library_(NULL), + compiler_(NULL) +#else compiler_llvm_(new compiler_llvm::CompilerLLVM(this, instruction_set)) #endif - { +{ + std::string compiler_so_name(MakeCompilerSoName(instruction_set)); + compiler_library_ = dlopen(compiler_so_name.c_str(), RTLD_LAZY); + if (compiler_library_ == NULL) { + LOG(FATAL) << "Couldn't find compiler library " << compiler_so_name << ": " << dlerror(); + } + VLOG(compiler) << "dlopen(\"" << compiler_so_name << "\", RTLD_LAZY) returned " << compiler_library_; + + compiler_ = reinterpret_cast<CompilerFn>(dlsym(compiler_library_, "oatCompileMethod")); + if (compiler_ == NULL) { + LOG(FATAL) << "Couldn't find \"oatCompileMethod\" in compiler library " << compiler_so_name << ": " << dlerror(); + } + + VLOG(compiler) << "dlsym(compiler_library, \"oatCompileMethod\") returned " << reinterpret_cast<void*>(compiler_); + CHECK(!Runtime::Current()->IsStarted()); if (!image_) { CHECK(image_classes_ == NULL); @@ -251,6 +284,10 @@ MutexLock mu(compiled_invoke_stubs_lock_); STLDeleteValues(&compiled_invoke_stubs_); } + if (compiler_library_ != NULL) { + VLOG(compiler) << "dlclose(" << compiler_library_ << ")"; + dlclose(compiler_library_); + } } ByteArray* Compiler::CreateResolutionStub(InstructionSet instruction_set, @@ -1064,8 +1101,8 @@ #if defined(ART_USE_LLVM_COMPILER) compiled_method = compiler_llvm_->CompileDexMethod(&oat_compilation_unit); #else - compiled_method = oatCompileMethod(*this, code_item, access_flags, method_idx, class_loader, - dex_file, kThumb2); + compiled_method = (*compiler_)(*this, code_item, access_flags, method_idx, class_loader, + dex_file); #endif CHECK(compiled_method != NULL) << PrettyMethod(method_idx, dex_file); }
diff --git a/src/compiler.h b/src/compiler.h index 639ab4f..31ee613 100644 --- a/src/compiler.h +++ b/src/compiler.h
@@ -203,6 +203,14 @@ #if defined(ART_USE_LLVM_COMPILER) UniquePtr<compiler_llvm::CompilerLLVM> compiler_llvm_; +#else + void* compiler_library_; + typedef CompiledMethod* (*CompilerFn)(Compiler& compiler, + const DexFile::CodeItem* code_item, + uint32_t access_flags, uint32_t method_idx, + const ClassLoader* class_loader, + const DexFile& dex_file); + CompilerFn compiler_; #endif DISALLOW_COPY_AND_ASSIGN(Compiler);
diff --git a/src/compiler/Compiler.h b/src/compiler/Compiler.h index 1e0439b..8636e11 100644 --- a/src/compiler/Compiler.h +++ b/src/compiler/Compiler.h
@@ -40,15 +40,7 @@ */ #define MAX_ASSEMBLER_RETRIES 50 -typedef enum OatInstructionSetType { - DALVIK_OAT_NONE = 0, - DALVIK_OAT_ARM, - DALVIK_OAT_THUMB2, - DALVIK_OAT_X86, - DALVIK_OAT_MIPS32 -} OatInstructionSetType; - -/* Supress optimization if corresponding bit set */ +/* Suppress optimization if corresponding bit set */ enum optControlVector { kLoadStoreElimination = 0, kLoadHoisting, @@ -183,9 +175,6 @@ bool oatArchInit(void); bool oatStartup(void); void oatShutdown(void); -CompiledMethod* oatCompileMethod(Compiler& compiler, bool is_direct, - uint32_t method_idx, const ClassLoader* class_loader, - const DexFile& dex_file, OatInstructionSetType); void oatScanAllClassPointers(void (*callback)(void* ptr)); void oatInitializeSSAConversion(struct CompilationUnit* cUnit); int oatConvertSSARegToDalvik(const struct CompilationUnit* cUnit, int ssaReg); @@ -220,4 +209,10 @@ } // namespace art +extern "C" art::CompiledMethod* oatCompileMethod(art::Compiler& compiler, + const art::DexFile::CodeItem* code_item, + uint32_t access_flags, uint32_t method_idx, + const art::ClassLoader* class_loader, + const art::DexFile& dex_file); + #endif // ART_SRC_COMPILER_COMPILER_H_
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h index 6bda522..2515713 100644 --- a/src/compiler/CompilerIR.h +++ b/src/compiler/CompilerIR.h
@@ -307,7 +307,7 @@ bool methodTraceSupport; // For TraceView profiling struct RegisterPool* regPool; int optRound; // round number to tell an LIR's age - OatInstructionSetType instructionSet; + InstructionSet instructionSet; /* Number of total regs used in the whole cUnit after SSA transformation */ int numSSARegs; /* Map SSA reg i to the Dalvik[15..0]/Sub[31..16] pair. */
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc index 7988829..4271722 100644 --- a/src/compiler/Frontend.cc +++ b/src/compiler/Frontend.cc
@@ -724,15 +724,20 @@ } } -/* - * Compile a method. - */ -CompiledMethod* oatCompileMethod(Compiler& compiler, - const DexFile::CodeItem* code_item, - uint32_t access_flags, uint32_t method_idx, - const ClassLoader* class_loader, - const DexFile& dex_file, - InstructionSet insnSet) +void oatInit(CompilationUnit* cUnit, const Compiler& compiler) { + if (!oatArchInit()) { + LOG(FATAL) << "Failed to initialize oat"; + } + if (!oatHeapInit(cUnit)) { + LOG(FATAL) << "Failed to initialize oat heap"; + } +} + +CompiledMethod* oatCompileMethodInternal(Compiler& compiler, + const DexFile::CodeItem* code_item, + uint32_t access_flags, uint32_t method_idx, + const ClassLoader* class_loader, + const DexFile& dex_file) { VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "..."; @@ -746,6 +751,7 @@ memset(cUnit.get(), 0, sizeof(*cUnit)); oatInit(cUnit.get(), compiler); + cUnit->compiler = &compiler; cUnit->class_linker = class_linker; cUnit->dex_file = &dex_file; @@ -754,7 +760,7 @@ cUnit->code_item = code_item; cUnit->access_flags = access_flags; cUnit->shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx)); - cUnit->instructionSet = (OatInstructionSetType)insnSet; + cUnit->instructionSet = compiler.GetInstructionSet(); cUnit->insns = code_item->insns_; cUnit->insnsSize = code_item->insns_size_in_code_units_; cUnit->numIns = code_item->ins_size_; @@ -943,7 +949,7 @@ (1 << kPromoteRegs); if (cUnit->printMe) { LOG(INFO) << "Compiler: " << PrettyMethod(method_idx, dex_file) - << " too big: " << cUnit->numBlocks; + << " too big: " << cUnit->numBlocks; } } } @@ -1027,14 +1033,14 @@ return result; } -void oatInit(CompilationUnit* cUnit, const Compiler& compiler) -{ - if (!oatArchInit()) { - LOG(FATAL) << "Failed to initialize oat"; - } - if (!oatHeapInit(cUnit)) { - LOG(FATAL) << "Failed to initialize oat heap"; - } -} - } // namespace art + +extern "C" art::CompiledMethod* oatCompileMethod(art::Compiler& compiler, + const art::DexFile::CodeItem* code_item, + uint32_t access_flags, uint32_t method_idx, + const art::ClassLoader* class_loader, + const art::DexFile& dex_file) +{ + CHECK_EQ(compiler.GetInstructionSet(), art::oatInstructionSet()); + return art::oatCompileMethodInternal(compiler, code_item, access_flags, method_idx, class_loader, dex_file); +}
diff --git a/src/compiler/Ralloc.cc b/src/compiler/Ralloc.cc index 3353437..abc573e 100644 --- a/src/compiler/Ralloc.cc +++ b/src/compiler/Ralloc.cc
@@ -406,9 +406,10 @@ } /* Figure out the frame size */ - cUnit->numPadding = (STACK_ALIGN_WORDS - + static const int kStackAlignWords = kStackAlignment/sizeof(uint32_t); + cUnit->numPadding = (kStackAlignWords - (cUnit->numCoreSpills + cUnit->numFPSpills + cUnit->numRegs + - cUnit->numOuts + 2)) & (STACK_ALIGN_WORDS-1); + cUnit->numOuts + 2)) & (kStackAlignWords - 1); cUnit->frameSize = (cUnit->numCoreSpills + cUnit->numFPSpills + cUnit->numRegs + cUnit->numOuts + cUnit->numPadding + 2) * 4;
diff --git a/src/compiler/codegen/CodegenFactory.cc b/src/compiler/codegen/CodegenFactory.cc index b27efe0..8a6e1bc 100644 --- a/src/compiler/codegen/CodegenFactory.cc +++ b/src/compiler/codegen/CodegenFactory.cc
@@ -266,7 +266,7 @@ } /* - * Utiltiy to load the current Method*. Broken out + * Utility to load the current Method*. Broken out * to allow easy change between placing the current Method* in a * dedicated register or its home location in the frame. */
diff --git a/src/compiler/codegen/CompilerCodegen.h b/src/compiler/codegen/CompilerCodegen.h index 1b54be9..9537e46 100644 --- a/src/compiler/codegen/CompilerCodegen.h +++ b/src/compiler/codegen/CompilerCodegen.h
@@ -51,7 +51,7 @@ void oatInitializeRegAlloc(CompilationUnit* cUnit); /* Implemented in codegen/<target>/<target_variant>/ArchVariant.c */ -OatInstructionSetType oatInstructionSet(void); +InstructionSet oatInstructionSet(); /* * Implemented in codegen/<target>/<target_variant>/ArchVariant.c
diff --git a/src/compiler/codegen/Optimizer.h b/src/compiler/codegen/Optimizer.h index 74a5b75..06c7732 100644 --- a/src/compiler/codegen/Optimizer.h +++ b/src/compiler/codegen/Optimizer.h
@@ -21,9 +21,6 @@ namespace art { -#define STACK_ALIGN_WORDS 4 -#define STACK_ALIGNMENT (STACK_ALIGN_WORDS * 4) - /* Forward declarations */ struct CompilationUnit; struct LIR;
diff --git a/src/compiler/codegen/RallocUtil.cc b/src/compiler/codegen/RallocUtil.cc index 232b304..cfda721 100644 --- a/src/compiler/codegen/RallocUtil.cc +++ b/src/compiler/codegen/RallocUtil.cc
@@ -1227,23 +1227,4 @@ return oatVRegOffset(cUnit, oatS2VReg(cUnit, sReg)); } - -/* Return sp-relative offset in bytes using Method* */ -extern int oatVRegOffset(const DexFile::CodeItem* code_item, - uint32_t core_spills, uint32_t fp_spills, - size_t frame_size, int reg) -{ - int numIns = code_item->ins_size_; - int numRegs = code_item->registers_size_ - numIns; - int numOuts = code_item->outs_size_; - int numSpills = __builtin_popcount(core_spills) + - __builtin_popcount(fp_spills); - int numPadding = (STACK_ALIGN_WORDS - - (numSpills + numRegs + numOuts + 2)) & (STACK_ALIGN_WORDS-1); - int regsOffset = (numOuts + numPadding + 1) * 4; - int insOffset = frame_size + 4; - return (reg < numRegs) ? regsOffset + (reg << 2) : - insOffset + ((reg - numRegs) << 2); -} - } // namespace art
diff --git a/src/compiler/codegen/arm/armv7-a-neon/ArchVariant.cc b/src/compiler/codegen/arm/armv7-a-neon/ArchVariant.cc index 77844fc..dcf3a99 100644 --- a/src/compiler/codegen/arm/armv7-a-neon/ArchVariant.cc +++ b/src/compiler/codegen/arm/armv7-a-neon/ArchVariant.cc
@@ -20,9 +20,9 @@ * Determine the initial instruction set to be used for this trace. * Later components may decide to change this. */ -OatInstructionSetType oatInstructionSet(void) +InstructionSet oatInstructionSet() { - return DALVIK_OAT_THUMB2; + return kThumb2; } /* Architecture-specific initializations and checks go here */
diff --git a/src/compiler/codegen/arm/armv7-a/ArchVariant.cc b/src/compiler/codegen/arm/armv7-a/ArchVariant.cc index 77844fc..dcf3a99 100644 --- a/src/compiler/codegen/arm/armv7-a/ArchVariant.cc +++ b/src/compiler/codegen/arm/armv7-a/ArchVariant.cc
@@ -20,9 +20,9 @@ * Determine the initial instruction set to be used for this trace. * Later components may decide to change this. */ -OatInstructionSetType oatInstructionSet(void) +InstructionSet oatInstructionSet() { - return DALVIK_OAT_THUMB2; + return kThumb2; } /* Architecture-specific initializations and checks go here */
diff --git a/src/compiler/codegen/mips/mips/ArchVariant.cc b/src/compiler/codegen/mips/mips/ArchVariant.cc index 6d29fc5..6b04d70 100644 --- a/src/compiler/codegen/mips/mips/ArchVariant.cc +++ b/src/compiler/codegen/mips/mips/ArchVariant.cc
@@ -25,9 +25,9 @@ * Determine the initial instruction set to be used for this trace. * Later components may decide to change this. */ -OatInstructionSetType oatInstructionSet(void) +InstructionSet oatInstructionSet() { - return DALVIK_OAT_MIPS32; + return kMips; } /* Architecture-specific initializations and checks go here */
diff --git a/src/compiler/codegen/x86/x86/ArchVariant.cc b/src/compiler/codegen/x86/x86/ArchVariant.cc index 93b17e1..944311c 100644 --- a/src/compiler/codegen/x86/x86/ArchVariant.cc +++ b/src/compiler/codegen/x86/x86/ArchVariant.cc
@@ -25,9 +25,9 @@ * Determine the initial instruction set to be used for this trace. * Later components may decide to change this. */ -OatInstructionSetType oatInstructionSet(void) +InstructionSet oatInstructionSet() { - return DALVIK_OAT_X86; + return kX86; } /* Architecture-specific initializations and checks go here */
diff --git a/src/compiler_test.cc b/src/compiler_test.cc index 417d352..272f838 100644 --- a/src/compiler_test.cc +++ b/src/compiler_test.cc
@@ -33,7 +33,7 @@ protected: void CompileAll(const ClassLoader* class_loader) { - compiler_->CompileAll(class_loader, ClassLoader::GetCompileTimeClassPath(class_loader)); + compiler_->CompileAll(class_loader, Runtime::Current()->GetCompileTimeClassPath(class_loader)); MakeAllExecutable(class_loader); } @@ -54,7 +54,7 @@ void MakeAllExecutable(const ClassLoader* class_loader) { const std::vector<const DexFile*>& class_path - = ClassLoader::GetCompileTimeClassPath(class_loader); + = Runtime::Current()->GetCompileTimeClassPath(class_loader); for (size_t i = 0; i != class_path.size(); ++i) { const DexFile* dex_file = class_path[i]; CHECK(dex_file != NULL); @@ -126,6 +126,7 @@ } TEST_F(CompilerTest, AbstractMethodErrorStub) { +#if defined(__arm__) CompileVirtualMethod(NULL, "java.lang.Class", "isFinalizable", "()Z"); CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V"); @@ -139,7 +140,6 @@ jobject jobj_ = env_->NewObject(c_class, constructor); ASSERT_TRUE(jobj_ != NULL); -#if defined(__arm__) Class* jlame = class_linker_->FindClass("Ljava/lang/AbstractMethodError;", class_loader.get()); // Force non-virtual call to AbstractClass foo, will throw AbstractMethodError exception. env_->CallNonvirtualVoidMethod(jobj_, class_, mid_);
diff --git a/src/dalvik_system_VMDebug.cc b/src/dalvik_system_VMDebug.cc index 5f4b6d9..62a1f43 100644 --- a/src/dalvik_system_VMDebug.cc +++ b/src/dalvik_system_VMDebug.cc
@@ -240,7 +240,7 @@ if (c == NULL) { return 0; } - return Heap::CountInstances(c, countAssignable); + return Runtime::Current()->GetHeap()->CountInstances(c, countAssignable); } JNINativeMethod gMethods[] = {
diff --git a/src/dalvik_system_VMRuntime.cc b/src/dalvik_system_VMRuntime.cc index c8a3a4c..cca5d2b 100644 --- a/src/dalvik_system_VMRuntime.cc +++ b/src/dalvik_system_VMRuntime.cc
@@ -19,6 +19,7 @@ #include "jni_internal.h" #include "object.h" #include "object_utils.h" +#include "scoped_heap_lock.h" #include "space.h" #include "thread.h" @@ -32,11 +33,11 @@ namespace { jfloat VMRuntime_getTargetHeapUtilization(JNIEnv*, jobject) { - return Heap::GetTargetHeapUtilization(); + return Runtime::Current()->GetHeap()->GetTargetHeapUtilization(); } void VMRuntime_nativeSetTargetHeapUtilization(JNIEnv*, jobject, jfloat target) { - Heap::SetTargetHeapUtilization(target); + Runtime::Current()->GetHeap()->SetTargetHeapUtilization(target); } void VMRuntime_startJitCompilation(JNIEnv*, jobject) { @@ -91,7 +92,7 @@ } void VMRuntime_clearGrowthLimit(JNIEnv*, jobject) { - Heap::ClearGrowthLimit(); + Runtime::Current()->GetHeap()->ClearGrowthLimit(); } jboolean VMRuntime_isDebuggerActive(JNIEnv*, jobject) { @@ -132,7 +133,7 @@ // running with CheckJNI forces you to obey the strictest rules. if (!env_ext->check_jni) { LOG(INFO) << "Turning on JNI app bug workarounds for target SDK version " - << targetSdkVersion << "..."; + << targetSdkVersion << "..."; env_ext->vm->work_around_app_jni_bugs = true; } } @@ -140,10 +141,11 @@ void VMRuntime_trimHeap(JNIEnv* env, jobject) { ScopedHeapLock heap_lock; - size_t alloc_space_size = Heap::GetAllocSpace()->Size(); - float utilization = static_cast<float>(Heap::GetBytesAllocated()) / alloc_space_size; + Heap* heap = Runtime::Current()->GetHeap(); + size_t alloc_space_size = heap->GetAllocSpace()->Size(); + float utilization = static_cast<float>(heap->GetBytesAllocated()) / alloc_space_size; uint64_t start_ns = NanoTime(); - Heap::GetAllocSpace()->Trim(); + heap->GetAllocSpace()->Trim(); LOG(INFO) << "Parallel heap trimming took " << PrettyDuration(NanoTime() - start_ns) << " on a " << PrettySize(alloc_space_size) << " heap with " << static_cast<int>(100 * utilization) << "% utilization";
diff --git a/src/dalvik_system_VMStack.cc b/src/dalvik_system_VMStack.cc index 7425847..37ee8b2 100644 --- a/src/dalvik_system_VMStack.cc +++ b/src/dalvik_system_VMStack.cc
@@ -17,6 +17,7 @@ #include "jni_internal.h" #include "class_loader.h" #include "object.h" +#include "scoped_heap_lock.h" #include "thread_list.h" #include "JniConstants.h" // Last to avoid problems with LOG redefinition.
diff --git a/src/debugger.cc b/src/debugger.cc index 95e8849..1480ee73 100644 --- a/src/debugger.cc +++ b/src/debugger.cc
@@ -1631,7 +1631,7 @@ CHECK_EQ(width, sizeof(JDWP::ObjectId)); Object* o = reinterpret_cast<Object*>(f.GetVReg(m, reg)); VLOG(jdwp) << "get array local " << reg << " = " << o; - if (o != NULL && !Heap::IsHeapAddress(o)) { + if (o != NULL && !Runtime::Current()->GetHeap()->IsHeapAddress(o)) { LOG(FATAL) << "Register " << reg << " expected to hold array: " << o; } JDWP::SetObjectId(buf+1, gRegistry->Add(o)); @@ -1647,7 +1647,7 @@ CHECK_EQ(width, sizeof(JDWP::ObjectId)); Object* o = reinterpret_cast<Object*>(f.GetVReg(m, reg)); VLOG(jdwp) << "get object local " << reg << " = " << o; - if (o != NULL && !Heap::IsHeapAddress(o)) { + if (o != NULL && !Runtime::Current()->GetHeap()->IsHeapAddress(o)) { LOG(FATAL) << "Register " << reg << " expected to hold object: " << o; } tag = TagFromObject(o); @@ -2572,15 +2572,16 @@ * [u4]: current number of objects allocated */ uint8_t heap_count = 1; + Heap* heap = Runtime::Current()->GetHeap(); std::vector<uint8_t> bytes; JDWP::Append4BE(bytes, heap_count); JDWP::Append4BE(bytes, 1); // Heap id (bogus; we only have one heap). JDWP::Append8BE(bytes, MilliTime()); JDWP::Append1BE(bytes, reason); - JDWP::Append4BE(bytes, Heap::GetMaxMemory()); // Max allowed heap size in bytes. - JDWP::Append4BE(bytes, Heap::GetTotalMemory()); // Current heap size in bytes. - JDWP::Append4BE(bytes, Heap::GetBytesAllocated()); - JDWP::Append4BE(bytes, Heap::GetObjectsAllocated()); + JDWP::Append4BE(bytes, heap->GetMaxMemory()); // Max allowed heap size in bytes. + JDWP::Append4BE(bytes, heap->GetTotalMemory()); // Current heap size in bytes. + JDWP::Append4BE(bytes, heap->GetBytesAllocated()); + JDWP::Append4BE(bytes, heap->GetObjectsAllocated()); CHECK_EQ(bytes.size(), 4U + (heap_count * (4 + 8 + 1 + 4 + 4 + 4 + 4))); Dbg::DdmSendChunk(CHUNK_TYPE("HPIF"), bytes); } @@ -2736,7 +2737,7 @@ // If we're looking at the native heap, we'll just return // (SOLIDITY_HARD, KIND_NATIVE) for all allocated chunks. - if (is_native_heap || !Heap::IsLiveObjectLocked(o)) { + if (is_native_heap || !Runtime::Current()->GetHeap()->IsLiveObjectLocked(o)) { return HPSG_STATE(SOLIDITY_HARD, KIND_NATIVE); } @@ -2746,7 +2747,7 @@ return HPSG_STATE(SOLIDITY_HARD, KIND_OBJECT); } - if (!Heap::IsHeapAddress(c)) { + if (!Runtime::Current()->GetHeap()->IsHeapAddress(c)) { LOG(WARNING) << "Invalid class for managed heap object: " << o << " " << c; return HPSG_STATE(SOLIDITY_HARD, KIND_UNKNOWN); } @@ -2810,7 +2811,8 @@ // dlmalloc_inspect_all(HeapChunkContext::HeapChunkCallback, &context); UNIMPLEMENTED(WARNING) << "Native heap send heap segments"; } else { - Heap::GetAllocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context); + Heap* heap = Runtime::Current()->GetHeap(); + heap->GetAllocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context); } // Finally, send a heap end chunk.
diff --git a/src/dex2oat.cc b/src/dex2oat.cc index d5d036f..b8d782b 100644 --- a/src/dex2oat.cc +++ b/src/dex2oat.cc
@@ -240,9 +240,10 @@ const std::string& oat_filename, const std::string& oat_location) { // If we have an existing boot image, position new space after its oat file - if (Heap::GetSpaces().size() > 1) { + Heap* heap = Runtime::Current()->GetHeap(); + if (heap->GetSpaces().size() > 1) { ImageSpace* last_image_space = NULL; - const std::vector<Space*>& spaces = Heap::GetSpaces(); + const std::vector<Space*>& spaces = heap->GetSpaces(); for (size_t i=0; i < spaces.size(); i++) { if (spaces[i]->IsImageSpace()) { last_image_space = spaces[i]->AsImageSpace(); @@ -250,7 +251,7 @@ } CHECK(last_image_space != NULL); CHECK(last_image_space->IsImageSpace()); - CHECK(!Heap::GetSpaces()[Heap::GetSpaces().size()-1]->IsImageSpace()); + CHECK(!heap->GetSpaces()[heap->GetSpaces().size()-1]->IsImageSpace()); byte* oat_limit_addr = last_image_space->GetImageHeader().GetOatEnd(); image_base = RoundUp(reinterpret_cast<uintptr_t>(oat_limit_addr), kPageSize); }
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc index 5b8102a..91dd4ea 100644 --- a/src/dex_verifier.cc +++ b/src/dex_verifier.cc
@@ -4030,47 +4030,61 @@ return NULL; } -Mutex DexVerifier::gc_maps_lock_("verifier gc maps lock"); -DexVerifier::GcMapTable DexVerifier::gc_maps_; +Mutex* DexVerifier::gc_maps_lock_ = NULL; +DexVerifier::GcMapTable* DexVerifier::gc_maps_ = NULL; + +void DexVerifier::InitGcMaps() { + gc_maps_lock_ = new Mutex("verifier GC maps lock"); + MutexLock mu(*gc_maps_lock_); + gc_maps_ = new DexVerifier::GcMapTable; +} + +void DexVerifier::DeleteGcMaps() { + MutexLock mu(*gc_maps_lock_); + STLDeleteValues(gc_maps_); +} void DexVerifier::SetGcMap(Compiler::MethodReference ref, const std::vector<uint8_t>& gc_map) { - MutexLock mu(gc_maps_lock_); + MutexLock mu(*gc_maps_lock_); const std::vector<uint8_t>* existing_gc_map = GetGcMap(ref); if (existing_gc_map != NULL) { CHECK(*existing_gc_map == gc_map); delete existing_gc_map; } - gc_maps_[ref] = &gc_map; + (*gc_maps_)[ref] = &gc_map; CHECK(GetGcMap(ref) != NULL); } const std::vector<uint8_t>* DexVerifier::GetGcMap(Compiler::MethodReference ref) { - MutexLock mu(gc_maps_lock_); - GcMapTable::const_iterator it = gc_maps_.find(ref); - if (it == gc_maps_.end()) { + MutexLock mu(*gc_maps_lock_); + GcMapTable::const_iterator it = gc_maps_->find(ref); + if (it == gc_maps_->end()) { return NULL; } CHECK(it->second != NULL); return it->second; } -void DexVerifier::DeleteGcMaps() { - MutexLock mu(gc_maps_lock_); - STLDeleteValues(&gc_maps_); +static Mutex& GetRejectedClassesLock() { + static Mutex rejected_classes_lock("verifier rejected classes lock"); + return rejected_classes_lock; } -Mutex DexVerifier::rejected_classes_lock_("verifier rejected classes lock"); -std::set<Compiler::ClassReference> DexVerifier::rejected_classes_; +static std::set<Compiler::ClassReference>& GetRejectedClasses() { + static std::set<Compiler::ClassReference> rejected_classes; + return rejected_classes; +} void DexVerifier::AddRejectedClass(Compiler::ClassReference ref) { - MutexLock mu(rejected_classes_lock_); - rejected_classes_.insert(ref); + MutexLock mu(GetRejectedClassesLock()); + GetRejectedClasses().insert(ref); CHECK(IsClassRejected(ref)); } bool DexVerifier::IsClassRejected(Compiler::ClassReference ref) { - MutexLock mu(rejected_classes_lock_); - return (rejected_classes_.find(ref) != rejected_classes_.end()); + MutexLock mu(GetRejectedClassesLock()); + std::set<Compiler::ClassReference>& rejected_classes(GetRejectedClasses()); + return (rejected_classes.find(ref) != rejected_classes.end()); } #if defined(ART_USE_LLVM_COMPILER)
diff --git a/src/dex_verifier.h b/src/dex_verifier.h index c2785c6..17826e7 100644 --- a/src/dex_verifier.h +++ b/src/dex_verifier.h
@@ -910,6 +910,7 @@ void Dump(std::ostream& os); static const std::vector<uint8_t>* GetGcMap(Compiler::MethodReference ref); + static void InitGcMaps(); static void DeleteGcMaps(); static bool IsClassRejected(Compiler::ClassReference ref); @@ -1289,15 +1290,12 @@ return insn_flags_[work_insn_idx_]; } - typedef std::map<const Compiler::MethodReference, const std::vector<uint8_t>*> GcMapTable; // All the GC maps that the verifier has created - static Mutex gc_maps_lock_; - static GcMapTable gc_maps_; + typedef std::map<const Compiler::MethodReference, const std::vector<uint8_t>*> GcMapTable; + static Mutex* gc_maps_lock_; + static GcMapTable* gc_maps_; static void SetGcMap(Compiler::MethodReference ref, const std::vector<uint8_t>& gc_map); - // Set of rejected classes that skip compilation - static Mutex rejected_classes_lock_; - static std::set<Compiler::ClassReference> rejected_classes_; static void AddRejectedClass(Compiler::ClassReference ref); RegTypeCache reg_types_;
diff --git a/src/heap.cc b/src/heap.cc index e153214..b9e41c0 100644 --- a/src/heap.cc +++ b/src/heap.cc
@@ -29,6 +29,7 @@ #include "object.h" #include "object_utils.h" #include "os.h" +#include "scoped_heap_lock.h" #include "space.h" #include "stl_util.h" #include "thread_list.h" @@ -37,39 +38,6 @@ namespace art { -std::vector<Space*> Heap::spaces_; - -AllocSpace* Heap::alloc_space_ = NULL; - -size_t Heap::num_bytes_allocated_ = 0; - -size_t Heap::num_objects_allocated_ = 0; - -bool Heap::is_gc_running_ = false; - -HeapBitmap* Heap::mark_bitmap_ = NULL; - -HeapBitmap* Heap::live_bitmap_ = NULL; - -CardTable* Heap::card_table_ = NULL; - -bool Heap::card_marking_disabled_ = false; - -Class* Heap::java_lang_ref_FinalizerReference_ = NULL; -Class* Heap::java_lang_ref_ReferenceQueue_ = NULL; - -MemberOffset Heap::reference_referent_offset_ = MemberOffset(0); -MemberOffset Heap::reference_queue_offset_ = MemberOffset(0); -MemberOffset Heap::reference_queueNext_offset_ = MemberOffset(0); -MemberOffset Heap::reference_pendingNext_offset_ = MemberOffset(0); -MemberOffset Heap::finalizer_reference_zombie_offset_ = MemberOffset(0); - -float Heap::target_utilization_ = 0.5; - -Mutex* Heap::lock_ = NULL; - -bool Heap::verify_objects_ = false; - static void UpdateFirstAndLastSpace(Space** first_space, Space** last_space, Space* space) { if (*first_space == NULL) { *first_space = space; @@ -161,10 +129,29 @@ return true; } -void Heap::Init(size_t initial_size, size_t growth_limit, size_t capacity, - const std::string& original_image_file_name) { +Heap::Heap(size_t initial_size, size_t growth_limit, size_t capacity, + const std::string& original_image_file_name) + : lock_(NULL), + alloc_space_(NULL), + mark_bitmap_(NULL), + live_bitmap_(NULL), + card_table_(NULL), + card_marking_disabled_(false), + is_gc_running_(false), + num_bytes_allocated_(0), + num_objects_allocated_(0), + java_lang_ref_FinalizerReference_(NULL), + java_lang_ref_ReferenceQueue_(NULL), + reference_referent_offset_(0), + reference_queue_offset_(0), + reference_queueNext_offset_(0), + reference_pendingNext_offset_(0), + finalizer_reference_zombie_offset_(0), + target_utilization_(0.5), + verify_objects_(false) +{ if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) { - LOG(INFO) << "Heap::Init entering"; + LOG(INFO) << "Heap() entering"; } // Compute the bounds of all spaces for allocating live and mark bitmaps @@ -228,7 +215,7 @@ } // Mark image objects in the live bitmap - for (size_t i = 0; i < spaces_.size(); i++) { + for (size_t i = 0; i < spaces_.size(); ++i) { Space* space = spaces_[i]; if (space->IsImageSpace()) { space->AsImageSpace()->RecordImageAllocations(live_bitmap.get()); @@ -254,7 +241,7 @@ num_bytes_allocated_ = 0; num_objects_allocated_ = 0; - // It's still to early to take a lock because there are no threads yet, + // It's still too early to take a lock because there are no threads yet, // but we can create the heap lock now. We don't create it earlier to // make it clear that you can't use locks during heap initialization. lock_ = new Mutex("Heap lock", kHeapLock); @@ -262,11 +249,16 @@ Heap::EnableObjectValidation(); if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) { - LOG(INFO) << "Heap::Init exiting"; + LOG(INFO) << "Heap() exiting"; } } -void Heap::Destroy() { +void Heap::AddSpace(Space* space) { + spaces_.push_back(space); +} + +Heap::~Heap() { + VLOG(heap) << "~Heap()"; // We can't take the heap lock here because there might be a daemon thread suspended with the // heap lock held. We know though that no non-daemon threads are executing, and we know that // all daemon threads are suspended, and we also know that the threads list have been deleted, so @@ -305,7 +297,7 @@ if (obj == NULL || !IsAligned<kObjectAlignment>(obj)) { return false; } - for (size_t i = 0; i < spaces_.size(); i++) { + for (size_t i = 0; i < spaces_.size(); ++i) { if (spaces_[i]->Contains(obj)) { return true; } @@ -362,12 +354,12 @@ void Heap::VerificationCallback(Object* obj, void* arg) { DCHECK(obj != NULL); - Heap::VerifyObjectLocked(obj); + reinterpret_cast<Heap*>(arg)->VerifyObjectLocked(obj); } void Heap::VerifyHeap() { ScopedHeapLock heap_lock; - live_bitmap_->Walk(Heap::VerificationCallback, NULL); + live_bitmap_->Walk(Heap::VerificationCallback, this); } void Heap::RecordAllocationLocked(AllocSpace* space, const Object* obj) {
diff --git a/src/heap.h b/src/heap.h index 2fd381c..ccc2d23 100644 --- a/src/heap.h +++ b/src/heap.h
@@ -17,6 +17,7 @@ #ifndef ART_SRC_HEAP_H_ #define ART_SRC_HEAP_H_ +#include <string> #include <vector> #include "card_table.h" @@ -50,57 +51,58 @@ // Create a heap with the requested sizes. The possible empty // image_file_names names specify Spaces to load based on // ImageWriter output. - static void Init(size_t starting_size, size_t growth_limit, size_t capacity, - const std::string& image_file_name); + explicit Heap(size_t starting_size, size_t growth_limit, size_t capacity, + const std::string& image_file_name); - static void Destroy(); + ~Heap(); // Allocates and initializes storage for an object instance. - static Object* AllocObject(Class* klass, size_t num_bytes); + Object* AllocObject(Class* klass, size_t num_bytes); // Check sanity of given reference. Requires the heap lock. #if VERIFY_OBJECT_ENABLED - static void VerifyObject(const Object *obj); + void VerifyObject(const Object *obj); #else - static void VerifyObject(const Object *obj) {} + void VerifyObject(const Object *obj) {} #endif // Check sanity of all live references. Requires the heap lock. - static void VerifyHeap(); + void VerifyHeap(); // A weaker test than IsLiveObject or VerifyObject that doesn't require the heap lock, // and doesn't abort on error, allowing the caller to report more // meaningful diagnostics. - static bool IsHeapAddress(const Object* obj); + bool IsHeapAddress(const Object* obj); + // Returns true if 'obj' is a live heap object, false otherwise (including for invalid addresses). // Requires the heap lock to be held. - static bool IsLiveObjectLocked(const Object* obj); + bool IsLiveObjectLocked(const Object* obj); // Initiates an explicit garbage collection. - static void CollectGarbage(bool clear_soft_references); + void CollectGarbage(bool clear_soft_references); // Implements java.lang.Runtime.maxMemory. - static int64_t GetMaxMemory(); + int64_t GetMaxMemory(); // Implements java.lang.Runtime.totalMemory. - static int64_t GetTotalMemory(); + int64_t GetTotalMemory(); // Implements java.lang.Runtime.freeMemory. - static int64_t GetFreeMemory(); + int64_t GetFreeMemory(); // Implements VMDebug.countInstancesOfClass. - static int64_t CountInstances(Class* c, bool count_assignable); + int64_t CountInstances(Class* c, bool count_assignable); // Removes the growth limit on the alloc space so it may grow to its maximum capacity. Used to // implement dalvik.system.VMRuntime.clearGrowthLimit. - static void ClearGrowthLimit(); + void ClearGrowthLimit(); // Target ideal heap utilization ratio, implements // dalvik.system.VMRuntime.getTargetHeapUtilization. - static float GetTargetHeapUtilization() { + float GetTargetHeapUtilization() { return target_utilization_; } // Set target ideal heap utilization ratio, implements // dalvik.system.VMRuntime.setTargetHeapUtilization. - static void SetTargetHeapUtilization(float target) { + void SetTargetHeapUtilization(float target) { DCHECK_GT(target, 0.0f); // asserted in Java code DCHECK_LT(target, 1.0f); target_utilization_ = target; @@ -108,186 +110,182 @@ // For the alloc space, sets the maximum number of bytes that the heap is allowed to allocate // from the system. Doesn't allow the space to exceed its growth limit. - static void SetIdealFootprint(size_t max_allowed_footprint); + void SetIdealFootprint(size_t max_allowed_footprint); // Blocks the caller until the garbage collector becomes idle. - static void WaitForConcurrentGcToComplete(); + void WaitForConcurrentGcToComplete(); - static pid_t GetLockOwner(); // For SignalCatcher. - static void Lock(); - static void Unlock(); - static void AssertLockHeld() { + pid_t GetLockOwner(); // For SignalCatcher. + void Lock(); + void Unlock(); + void AssertLockHeld() { lock_->AssertHeld(); } - static void AssertLockNotHeld() { + void AssertLockNotHeld() { lock_->AssertNotHeld(); } - static const std::vector<Space*>& GetSpaces() { + const std::vector<Space*>& GetSpaces() { return spaces_; } - static HeapBitmap* GetLiveBits() { + HeapBitmap* GetLiveBits() { return live_bitmap_; } - static HeapBitmap* GetMarkBits() { + HeapBitmap* GetMarkBits() { return mark_bitmap_; } - static void SetWellKnownClasses(Class* java_lang_ref_FinalizerReference, + void SetWellKnownClasses(Class* java_lang_ref_FinalizerReference, Class* java_lang_ref_ReferenceQueue); - static void SetReferenceOffsets(MemberOffset reference_referent_offset, - MemberOffset reference_queue_offset, - MemberOffset reference_queueNext_offset, - MemberOffset reference_pendingNext_offset, - MemberOffset finalizer_reference_zombie_offset); + void SetReferenceOffsets(MemberOffset reference_referent_offset, + MemberOffset reference_queue_offset, + MemberOffset reference_queueNext_offset, + MemberOffset reference_pendingNext_offset, + MemberOffset finalizer_reference_zombie_offset); - static Object* GetReferenceReferent(Object* reference); - static void ClearReferenceReferent(Object* reference); + Object* GetReferenceReferent(Object* reference); + void ClearReferenceReferent(Object* reference); // Returns true if the reference object has not yet been enqueued. - static bool IsEnqueuable(const Object* ref); - static void EnqueueReference(Object* ref, Object** list); - static void EnqueuePendingReference(Object* ref, Object** list); - static Object* DequeuePendingReference(Object** list); + bool IsEnqueuable(const Object* ref); + void EnqueueReference(Object* ref, Object** list); + void EnqueuePendingReference(Object* ref, Object** list); + Object* DequeuePendingReference(Object** list); - static MemberOffset GetReferencePendingNextOffset() { + MemberOffset GetReferencePendingNextOffset() { DCHECK_NE(reference_pendingNext_offset_.Uint32Value(), 0U); return reference_pendingNext_offset_; } - static MemberOffset GetFinalizerReferenceZombieOffset() { + MemberOffset GetFinalizerReferenceZombieOffset() { DCHECK_NE(finalizer_reference_zombie_offset_.Uint32Value(), 0U); return finalizer_reference_zombie_offset_; } - static void EnableObjectValidation() { + void EnableObjectValidation() { #if VERIFY_OBJECT_ENABLED - Heap::VerifyHeap(); + VerifyHeap(); #endif verify_objects_ = true; } - static void DisableObjectValidation() { + void DisableObjectValidation() { verify_objects_ = false; } // Callers must hold the heap lock. - static void RecordFreeLocked(size_t freed_objects, size_t freed_bytes); + void RecordFreeLocked(size_t freed_objects, size_t freed_bytes); // Must be called if a field of an Object in the heap changes, and before any GC safe-point. // The call is not needed if NULL is stored in the field. - static void WriteBarrierField(const Object* dest, MemberOffset offset, const Object* new_val) { + void WriteBarrierField(const Object* dest, MemberOffset offset, const Object* new_val) { if (!card_marking_disabled_) { card_table_->MarkCard(dest); } } // Write barrier for array operations that update many field positions - static void WriteBarrierArray(const Object* dest, int pos, size_t len) { + void WriteBarrierArray(const Object* dest, int pos, size_t len) { if (UNLIKELY(!card_marking_disabled_)) { card_table_->MarkCard(dest); } } - static CardTable* GetCardTable() { + CardTable* GetCardTable() { return card_table_; } - static void DisableCardMarking() { + void DisableCardMarking() { // TODO: we shouldn't need to disable card marking, this is here to help the image_writer card_marking_disabled_ = true; } - static void AddFinalizerReference(Thread* self, Object* object); + void AddFinalizerReference(Thread* self, Object* object); - static size_t GetBytesAllocated() { return num_bytes_allocated_; } - static size_t GetObjectsAllocated() { return num_objects_allocated_; } + size_t GetBytesAllocated() { return num_bytes_allocated_; } + size_t GetObjectsAllocated() { return num_objects_allocated_; } - static AllocSpace* GetAllocSpace() { + AllocSpace* GetAllocSpace() { return alloc_space_; } private: // Allocates uninitialized storage. - static Object* AllocateLocked(size_t num_bytes); - static Object* AllocateLocked(AllocSpace* space, size_t num_bytes); + Object* AllocateLocked(size_t num_bytes); + Object* AllocateLocked(AllocSpace* space, size_t num_bytes); // Pushes a list of cleared references out to the managed heap. - static void EnqueueClearedReferences(Object** cleared_references); + void EnqueueClearedReferences(Object** cleared_references); - static void RequestHeapTrim(); + void RequestHeapTrim(); - static void RecordAllocationLocked(AllocSpace* space, const Object* object); - static void RecordImageAllocations(Space* space); + void RecordAllocationLocked(AllocSpace* space, const Object* object); + void RecordImageAllocations(Space* space); - static void CollectGarbageInternal(bool clear_soft_references); + void CollectGarbageInternal(bool clear_soft_references); // Given the current contents of the alloc space, increase the allowed heap footprint to match // the target utilization ratio. This should only be called immediately after a full garbage // collection. - static void GrowForUtilization(); + void GrowForUtilization(); - static void AddSpace(Space* space) { - spaces_.push_back(space); - } + void AddSpace(Space* space); - static void VerifyObjectLocked(const Object *obj); + void VerifyObjectLocked(const Object *obj); static void VerificationCallback(Object* obj, void* arg); - static Mutex* lock_; + Mutex* lock_; - static std::vector<Space*> spaces_; + std::vector<Space*> spaces_; // default Space for allocations - static AllocSpace* alloc_space_; + AllocSpace* alloc_space_; - static HeapBitmap* mark_bitmap_; + HeapBitmap* mark_bitmap_; - static HeapBitmap* live_bitmap_; + HeapBitmap* live_bitmap_; - static CardTable* card_table_; + CardTable* card_table_; // Used by the image writer to disable card marking on copied objects // TODO: remove - static bool card_marking_disabled_; + bool card_marking_disabled_; // True while the garbage collector is running. - static bool is_gc_running_; + bool is_gc_running_; - // Number of bytes allocated. Adjusted after each allocation and - // free. - static size_t num_bytes_allocated_; + // Number of bytes allocated. Adjusted after each allocation and free. + size_t num_bytes_allocated_; - // Number of objects allocated. Adjusted after each allocation and - // free. - static size_t num_objects_allocated_; + // Number of objects allocated. Adjusted after each allocation and free. + size_t num_objects_allocated_; - static Class* java_lang_ref_FinalizerReference_; - static Class* java_lang_ref_ReferenceQueue_; + Class* java_lang_ref_FinalizerReference_; + Class* java_lang_ref_ReferenceQueue_; // offset of java.lang.ref.Reference.referent - static MemberOffset reference_referent_offset_; + MemberOffset reference_referent_offset_; // offset of java.lang.ref.Reference.queue - static MemberOffset reference_queue_offset_; + MemberOffset reference_queue_offset_; // offset of java.lang.ref.Reference.queueNext - static MemberOffset reference_queueNext_offset_; + MemberOffset reference_queueNext_offset_; // offset of java.lang.ref.Reference.pendingNext - static MemberOffset reference_pendingNext_offset_; + MemberOffset reference_pendingNext_offset_; // offset of java.lang.ref.FinalizerReference.zombie - static MemberOffset finalizer_reference_zombie_offset_; + MemberOffset finalizer_reference_zombie_offset_; // Target ideal heap utilization ratio - static float target_utilization_; + float target_utilization_; - static bool verify_objects_; + bool verify_objects_; FRIEND_TEST(SpaceTest, AllocAndFree); FRIEND_TEST(SpaceTest, AllocAndFreeList); @@ -296,20 +294,6 @@ DISALLOW_IMPLICIT_CONSTRUCTORS(Heap); }; -class ScopedHeapLock { - public: - ScopedHeapLock() { - Heap::Lock(); - } - - ~ScopedHeapLock() { - Heap::Unlock(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(ScopedHeapLock); -}; - } // namespace art #endif // ART_SRC_HEAP_H_
diff --git a/src/heap_test.cc b/src/heap_test.cc index 2035ce8..0077a77 100644 --- a/src/heap_test.cc +++ b/src/heap_test.cc
@@ -21,11 +21,12 @@ class HeapTest : public CommonTest {}; TEST_F(HeapTest, ClearGrowthLimit) { - int64_t max_memory_before = Heap::GetMaxMemory(); - int64_t total_memory_before = Heap::GetTotalMemory(); - Heap::ClearGrowthLimit(); - int64_t max_memory_after = Heap::GetMaxMemory(); - int64_t total_memory_after = Heap::GetTotalMemory(); + Heap* heap = Runtime::Current()->GetHeap(); + int64_t max_memory_before = heap->GetMaxMemory(); + int64_t total_memory_before = heap->GetTotalMemory(); + heap->ClearGrowthLimit(); + int64_t max_memory_after = heap->GetMaxMemory(); + int64_t total_memory_after = heap->GetTotalMemory(); EXPECT_GE(max_memory_after, max_memory_before); EXPECT_GE(total_memory_after, total_memory_before); } @@ -41,7 +42,7 @@ } } - Heap::CollectGarbage(false); + Runtime::Current()->GetHeap()->CollectGarbage(false); } } // namespace art
diff --git a/src/hprof/hprof.cc b/src/hprof/hprof.cc index 4d5cae1..6de9c64 100644 --- a/src/hprof/hprof.cc +++ b/src/hprof/hprof.cc
@@ -30,6 +30,7 @@ #include "logging.h" #include "object.h" #include "object_utils.h" +#include "scoped_heap_lock.h" #include "stringprintf.h" #include <cutils/open_memstream.h> @@ -763,9 +764,10 @@ ThreadList* thread_list = Runtime::Current()->GetThreadList(); thread_list->SuspendAll(); + Runtime* runtime = Runtime::Current(); Hprof hprof(fileName, fd, false, directToDdms); - Runtime::Current()->VisitRoots(HprofRootVisitor, &hprof); - Heap::GetLiveBits()->Walk(HprofBitmapCallback, &hprof); + runtime->VisitRoots(HprofRootVisitor, &hprof); + runtime->GetHeap()->GetLiveBits()->Walk(HprofBitmapCallback, &hprof); // TODO: write a HEAP_SUMMARY record int success = hprof.Finish() ? 0 : -1; thread_list->ResumeAll();
diff --git a/src/image_test.cc b/src/image_test.cc index fb87a49..e886e49 100644 --- a/src/image_test.cc +++ b/src/image_test.cc
@@ -38,7 +38,7 @@ ASSERT_TRUE(success_oat); // Force all system classes into memory - for (size_t i = 0; i < java_lang_dex_file_->NumClassDefs(); i++) { + for (size_t i = 0; i < java_lang_dex_file_->NumClassDefs(); ++i) { const DexFile::ClassDef& class_def = java_lang_dex_file_->GetClassDef(i); const char* descriptor = java_lang_dex_file_->GetClassDescriptor(class_def); Class* klass = class_linker_->FindSystemClass(descriptor); @@ -59,8 +59,9 @@ file->ReadFully(&image_header, sizeof(image_header)); ASSERT_TRUE(image_header.IsValid()); - ASSERT_EQ(1U, Heap::GetSpaces().size()); - Space* space = Heap::GetSpaces()[0]; + Heap* heap = Runtime::Current()->GetHeap(); + ASSERT_EQ(1U, heap->GetSpaces().size()); + Space* space = heap->GetSpaces()[0]; ASSERT_FALSE(space->IsImageSpace()); ASSERT_TRUE(space != NULL); ASSERT_GE(sizeof(image_header) + space->Size(), static_cast<size_t>(file->Length())); @@ -84,15 +85,16 @@ ASSERT_TRUE(runtime_->GetJniDlsymLookupStub() != NULL); - ASSERT_EQ(2U, Heap::GetSpaces().size()); - ASSERT_TRUE(Heap::GetSpaces()[0]->IsImageSpace()); - ASSERT_FALSE(Heap::GetSpaces()[1]->IsImageSpace()); + Heap* heap = Runtime::Current()->GetHeap(); + ASSERT_EQ(2U, heap->GetSpaces().size()); + ASSERT_TRUE(heap->GetSpaces()[0]->IsImageSpace()); + ASSERT_FALSE(heap->GetSpaces()[1]->IsImageSpace()); - ImageSpace* image_space = Heap::GetSpaces()[0]->AsImageSpace(); + ImageSpace* image_space = heap->GetSpaces()[0]->AsImageSpace(); byte* image_begin = image_space->Begin(); byte* image_end = image_space->End(); CHECK_EQ(requested_image_base, reinterpret_cast<uintptr_t>(image_begin)); - for (size_t i = 0; i < dex->NumClassDefs(); i++) { + for (size_t i = 0; i < dex->NumClassDefs(); ++i) { const DexFile::ClassDef& class_def = dex->GetClassDef(i); const char* descriptor = dex->GetClassDescriptor(class_def); Class* klass = class_linker_->FindSystemClass(descriptor);
diff --git a/src/image_writer.cc b/src/image_writer.cc index 23c2029..4579c0c 100644 --- a/src/image_writer.cc +++ b/src/image_writer.cc
@@ -39,8 +39,6 @@ namespace art { -std::map<const Object*, size_t> ImageWriter::offsets_; - bool ImageWriter::Write(const std::string& image_filename, uintptr_t image_begin, const std::string& oat_filename, @@ -50,7 +48,8 @@ CHECK_NE(image_begin, 0U); image_begin_ = reinterpret_cast<byte*>(image_begin); - const std::vector<Space*>& spaces = Heap::GetSpaces(); + Heap* heap = Runtime::Current()->GetHeap(); + const std::vector<Space*>& spaces = heap->GetSpaces(); // currently just write the last space, assuming it is the space that was being used for allocation CHECK_GE(spaces.size(), 1U); source_space_ = spaces[spaces.size()-1]; @@ -74,15 +73,15 @@ PruneNonImageClasses(); // Remove junk ComputeLazyFieldsForImageClasses(); // Add useful information ComputeEagerResolvedStrings(); - Heap::CollectGarbage(false); // Remove garbage - Heap::GetAllocSpace()->Trim(); // Trim size of source_space + heap->CollectGarbage(false); // Remove garbage + heap->GetAllocSpace()->Trim(); // Trim size of source_space if (!AllocMemory()) { return false; } #ifndef NDEBUG CheckNonImageClassesRemoved(); #endif - Heap::DisableCardMarking(); + heap->DisableCardMarking(); CalculateNewObjectOffsets(); CopyAndFixupObjects(); @@ -147,7 +146,7 @@ } void ImageWriter::ComputeEagerResolvedStrings() { - HeapBitmap* heap_bitmap = Heap::GetLiveBits(); + HeapBitmap* heap_bitmap = Runtime::Current()->GetHeap()->GetLiveBits(); DCHECK(heap_bitmap != NULL); heap_bitmap->Walk(ComputeEagerResolvedStringsCallback, this); // TODO: add Space-limited Walk } @@ -228,7 +227,7 @@ if (image_classes_ == NULL) { return; } - Heap::GetLiveBits()->Walk(CheckNonImageClassesRemovedCallback, this); + Runtime::Current()->GetHeap()->GetLiveBits()->Walk(CheckNonImageClassesRemovedCallback, this); } void ImageWriter::CheckNonImageClassesRemovedCallback(Object* obj, void* arg) { @@ -262,18 +261,18 @@ // if it is a string, we want to intern it if its not interned. if (obj->GetClass()->IsStringClass()) { // we must be an interned string that was forward referenced and already assigned - if (IsImageOffsetAssigned(obj)) { + if (image_writer->IsImageOffsetAssigned(obj)) { DCHECK_EQ(obj, obj->AsString()->Intern()); return; } SirtRef<String> interned(obj->AsString()->Intern()); if (obj != interned.get()) { - if (!IsImageOffsetAssigned(interned.get())) { + if (!image_writer->IsImageOffsetAssigned(interned.get())) { // interned obj is after us, allocate its location early image_writer->AssignImageOffset(interned.get()); } // point those looking for this object to the interned version. - SetImageOffset(obj, GetImageOffset(interned.get())); + image_writer->SetImageOffset(obj, image_writer->GetImageOffset(interned.get())); return; } // else (obj == interned), nothing to do but fall through to the normal case @@ -328,7 +327,7 @@ void ImageWriter::CalculateNewObjectOffsets() { SirtRef<ObjectArray<Object> > image_roots(CreateImageRoots()); - HeapBitmap* heap_bitmap = Heap::GetLiveBits(); + HeapBitmap* heap_bitmap = Runtime::Current()->GetHeap()->GetLiveBits(); DCHECK(heap_bitmap != NULL); DCHECK_EQ(0U, image_end_); @@ -353,10 +352,11 @@ } void ImageWriter::CopyAndFixupObjects() { - HeapBitmap* heap_bitmap = Heap::GetLiveBits(); + Heap* heap = Runtime::Current()->GetHeap(); + HeapBitmap* heap_bitmap = heap->GetLiveBits(); DCHECK(heap_bitmap != NULL); // TODO: heap validation can't handle this fix up pass - Heap::DisableObjectValidation(); + heap->DisableObjectValidation(); heap_bitmap->Walk(CopyAndFixupObjectsCallback, this); // TODO: add Space-limited Walk }
diff --git a/src/image_writer.h b/src/image_writer.h index 9d46c06..35a3c02 100644 --- a/src/image_writer.h +++ b/src/image_writer.h
@@ -51,8 +51,6 @@ bool AllocMemory(); - static std::map<const Object*, size_t> offsets_; - // we use the lock word to store the offset of the object in the image void AssignImageOffset(Object* object) { DCHECK(object != NULL); @@ -60,26 +58,30 @@ image_end_ += RoundUp(object->SizeOf(), 8); // 64-bit alignment DCHECK_LT(image_end_, image_->Size()); } - static void SetImageOffset(Object* object, size_t offset) { + + void SetImageOffset(Object* object, size_t offset) { DCHECK(object != NULL); DCHECK_NE(offset, 0U); DCHECK(!IsImageOffsetAssigned(object)); offsets_[object] = offset; } - static size_t IsImageOffsetAssigned(const Object* object) { + + size_t IsImageOffsetAssigned(const Object* object) const { DCHECK(object != NULL); return offsets_.find(object) != offsets_.end(); } - static size_t GetImageOffset(const Object* object) { + + size_t GetImageOffset(const Object* object) const { DCHECK(object != NULL); DCHECK(IsImageOffsetAssigned(object)); - return offsets_[object]; + return offsets_.find(object)->second; } bool InSourceSpace(const Object* object) const { DCHECK(source_space_ != NULL); return source_space_->Contains(object); } + Object* GetImageAddress(const Object* object) const { if (object == NULL) { return NULL; @@ -90,6 +92,7 @@ } return reinterpret_cast<Object*>(image_begin_ + GetImageOffset(object)); } + Object* GetLocalAddress(const Object* object) const { size_t offset = GetImageOffset(object); byte* dst = image_->Begin() + offset; @@ -134,6 +137,8 @@ void FixupStaticFields(const Class* orig, Class* copy); void FixupFields(const Object* orig, Object* copy, uint32_t ref_offsets, bool is_static); + std::map<const Object*, size_t> offsets_; + // oat file with code for this image UniquePtr<OatFile> oat_file_;
diff --git a/src/indirect_reference_table.h b/src/indirect_reference_table.h index f6cab95..78617f8 100644 --- a/src/indirect_reference_table.h +++ b/src/indirect_reference_table.h
@@ -96,7 +96,7 @@ */ typedef void* IndirectRef; -/* Magic failure values; must not pass Heap::ValidateObject() or Heap::IsHeapAddress(). */ +// Magic failure values; must not pass Heap::ValidateObject() or Heap::IsHeapAddress(). static Object* const kInvalidIndirectRefObject = reinterpret_cast<Object*>(0xdead4321); static Object* const kClearedJniWeakGlobal = reinterpret_cast<Object*>(0xdead1234); @@ -327,6 +327,7 @@ static Offset SegmentStateOffset() { return Offset(OFFSETOF_MEMBER(IndirectReferenceTable, segment_state_)); } + private: /* * Extract the table index from an indirect reference.
diff --git a/src/java_lang_Runtime.cc b/src/java_lang_Runtime.cc index 96337af..07af162 100644 --- a/src/java_lang_Runtime.cc +++ b/src/java_lang_Runtime.cc
@@ -31,7 +31,7 @@ void Runtime_gc(JNIEnv*, jclass) { ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable); - Heap::CollectGarbage(false); + Runtime::Current()->GetHeap()->CollectGarbage(false); } void Runtime_nativeExit(JNIEnv* env, jclass, jint status, jboolean isExit) { @@ -67,15 +67,15 @@ } jlong Runtime_maxMemory(JNIEnv* env, jclass) { - return Heap::GetMaxMemory(); + return Runtime::Current()->GetHeap()->GetMaxMemory(); } jlong Runtime_totalMemory(JNIEnv* env, jclass) { - return Heap::GetTotalMemory(); + return Runtime::Current()->GetHeap()->GetTotalMemory(); } jlong Runtime_freeMemory(JNIEnv* env, jclass) { - return Heap::GetFreeMemory(); + return Runtime::Current()->GetHeap()->GetFreeMemory(); } static JNINativeMethod gMethods[] = {
diff --git a/src/java_lang_System.cc b/src/java_lang_System.cc index b48cee9..22a9cc6 100644 --- a/src/java_lang_System.cc +++ b/src/java_lang_System.cc
@@ -192,7 +192,7 @@ // Yes. Bulk copy. COMPILE_ASSERT(sizeof(width) == sizeof(uint32_t), move32_assumes_Object_references_are_32_bit); move32(dstBytes + dstPos * width, srcBytes + srcPos * width, length * width); - Heap::WriteBarrierArray(dstArray, dstPos, length); + Runtime::Current()->GetHeap()->WriteBarrierArray(dstArray, dstPos, length); return; } @@ -233,7 +233,7 @@ } } - Heap::WriteBarrierArray(dstArray, dstPos, length); + Runtime::Current()->GetHeap()->WriteBarrierArray(dstArray, dstPos, length); if (i != length) { std::string actualSrcType(PrettyTypeOf(o)); std::string dstType(PrettyTypeOf(dstArray));
diff --git a/src/logging.cc b/src/logging.cc index a4fa45b..18fe99b 100644 --- a/src/logging.cc +++ b/src/logging.cc
@@ -24,9 +24,9 @@ LogVerbosity gLogVerbosity; -Mutex& GetLoggingLock() { - static Mutex lock("LogMessage lock"); - return lock; +static Mutex& GetLoggingLock() { + static Mutex logging_lock("LogMessage lock"); + return logging_lock; } LogMessage::~LogMessage() {
diff --git a/src/mark_sweep.cc b/src/mark_sweep.cc index 952bf85..e5e0835 100644 --- a/src/mark_sweep.cc +++ b/src/mark_sweep.cc
@@ -38,8 +38,10 @@ void MarkSweep::Init() { mark_stack_ = MarkStack::Create(); - mark_bitmap_ = Heap::GetMarkBits(); - live_bitmap_ = Heap::GetLiveBits(); + + heap_ = Runtime::Current()->GetHeap(); + mark_bitmap_ = heap_->GetMarkBits(); + live_bitmap_ = heap_->GetLiveBits(); // TODO: if concurrent, clear the card table. @@ -100,8 +102,8 @@ // Marks all objects that are in images and have been touched by the mutator void MarkSweep::ScanDirtyImageRoots() { - const std::vector<Space*>& spaces = Heap::GetSpaces(); - CardTable* card_table = Heap::GetCardTable(); + const std::vector<Space*>& spaces = heap_->GetSpaces(); + CardTable* card_table = heap_->GetCardTable(); for (size_t i = 0; i < spaces.size(); ++i) { if (spaces[i]->IsImageSpace()) { byte* begin = spaces[i]->Begin(); @@ -135,7 +137,7 @@ CHECK(cleared_reference_list_ == NULL); void* arg = reinterpret_cast<void*>(this); - const std::vector<Space*>& spaces = Heap::GetSpaces(); + const std::vector<Space*>& spaces = heap_->GetSpaces(); for (size_t i = 0; i < spaces.size(); ++i) { #ifndef NDEBUG uintptr_t begin = reinterpret_cast<uintptr_t>(spaces[i]->Begin()); @@ -181,11 +183,18 @@ SweepJniWeakGlobals(); } +struct SweepCallbackContext { + Heap* heap; + AllocSpace* space; +}; + void MarkSweep::SweepCallback(size_t num_ptrs, Object** ptrs, void* arg) { // TODO: lock heap if concurrent size_t freed_objects = num_ptrs; size_t freed_bytes = 0; - AllocSpace* space = static_cast<AllocSpace*>(arg); + SweepCallbackContext* context = static_cast<SweepCallbackContext*>(arg); + Heap* heap = context->heap; + AllocSpace* space = context->space; // Use a bulk free, that merges consecutive objects before freeing or free per object? // Documentation suggests better free performance with merging, but this may be at the expensive // of allocation. @@ -195,7 +204,7 @@ for (size_t i = 0; i < num_ptrs; ++i) { Object* obj = static_cast<Object*>(ptrs[i]); freed_bytes += space->AllocationSize(obj); - Heap::GetLiveBits()->Clear(obj); + heap->GetLiveBits()->Clear(obj); } // AllocSpace::FreeList clears the value in ptrs, so perform after clearing the live bit space->FreeList(num_ptrs, ptrs); @@ -203,25 +212,27 @@ for (size_t i = 0; i < num_ptrs; ++i) { Object* obj = static_cast<Object*>(ptrs[i]); freed_bytes += space->AllocationSize(obj); - Heap::GetLiveBits()->Clear(obj); + heap->GetLiveBits()->Clear(obj); space->Free(obj); } } - Heap::RecordFreeLocked(freed_objects, freed_bytes); + heap->RecordFreeLocked(freed_objects, freed_bytes); // TODO: unlock heap if concurrent } void MarkSweep::Sweep() { SweepSystemWeaks(); - const std::vector<Space*>& spaces = Heap::GetSpaces(); + const std::vector<Space*>& spaces = heap_->GetSpaces(); + SweepCallbackContext scc; + scc.heap = heap_; for (size_t i = 0; i < spaces.size(); ++i) { if (!spaces[i]->IsImageSpace()) { uintptr_t begin = reinterpret_cast<uintptr_t>(spaces[i]->Begin()); uintptr_t end = reinterpret_cast<uintptr_t>(spaces[i]->End()); - void* arg = static_cast<void*>(spaces[i]); + scc.space = spaces[i]->AsAllocSpace(); HeapBitmap::SweepWalk(*live_bitmap_, *mark_bitmap_, begin, end, - &MarkSweep::SweepCallback, arg); + &MarkSweep::SweepCallback, reinterpret_cast<void*>(&scc)); } } } @@ -283,7 +294,7 @@ } inline void MarkSweep::CheckReference(const Object* obj, const Object* ref, MemberOffset offset, bool is_static) { - AllocSpace* alloc_space = Heap::GetAllocSpace(); + AllocSpace* alloc_space = heap_->GetAllocSpace(); if (alloc_space->Contains(ref)) { bool is_marked = mark_bitmap_->Test(ref); if(!is_marked) { @@ -292,7 +303,7 @@ << "' (" << (void*)ref << ") in '" << PrettyTypeOf(obj) << "' (" << (void*)obj << ") at offset " << (void*)offset.Int32Value() << " wasn't marked"; - bool obj_marked = Heap::GetCardTable()->IsDirty(obj); + bool obj_marked = heap_->GetCardTable()->IsDirty(obj); if (!obj_marked) { LOG(WARNING) << "Object '" << PrettyTypeOf(obj) << "' (" << (void*)obj << ") contains references to the alloc space, but wasn't card marked"; @@ -386,8 +397,8 @@ Class* klass = obj->GetClass(); DCHECK(klass != NULL); DCHECK(klass->IsReferenceClass()); - Object* pending = obj->GetFieldObject<Object*>(Heap::GetReferencePendingNextOffset(), false); - Object* referent = Heap::GetReferenceReferent(obj); + Object* pending = obj->GetFieldObject<Object*>(heap_->GetReferencePendingNextOffset(), false); + Object* referent = heap_->GetReferenceReferent(obj); if (pending == NULL && referent != NULL && !IsMarked(referent)) { Object** list = NULL; if (klass->IsSoftReferenceClass()) { @@ -400,7 +411,7 @@ list = &phantom_reference_list_; } DCHECK(list != NULL) << PrettyClass(klass) << " " << std::hex << klass->GetAccessFlags(); - Heap::EnqueuePendingReference(obj, list); + heap_->EnqueuePendingReference(obj, list); } } @@ -452,7 +463,7 @@ // Scan anything that's on the mark stack. void MarkSweep::ProcessMarkStack() { - Space* alloc_space = Heap::GetAllocSpace(); + Space* alloc_space = heap_->GetAllocSpace(); while (!mark_stack_->IsEmpty()) { const Object* obj = mark_stack_->Pop(); if (alloc_space->Contains(obj)) { @@ -474,8 +485,8 @@ Object* clear = NULL; size_t counter = 0; while (*list != NULL) { - Object* ref = Heap::DequeuePendingReference(list); - Object* referent = Heap::GetReferenceReferent(ref); + Object* ref = heap_->DequeuePendingReference(list); + Object* referent = heap_->GetReferenceReferent(ref); if (referent == NULL) { // Referent was cleared by the user during marking. continue; @@ -488,7 +499,7 @@ } if (!is_marked) { // Referent is white, queue it for clearing. - Heap::EnqueuePendingReference(ref, &clear); + heap_->EnqueuePendingReference(ref, &clear); } } *list = clear; @@ -503,13 +514,13 @@ void MarkSweep::ClearWhiteReferences(Object** list) { DCHECK(list != NULL); while (*list != NULL) { - Object* ref = Heap::DequeuePendingReference(list); - Object* referent = Heap::GetReferenceReferent(ref); + Object* ref = heap_->DequeuePendingReference(list); + Object* referent = heap_->GetReferenceReferent(ref); if (referent != NULL && !IsMarked(referent)) { // Referent is white, clear it. - Heap::ClearReferenceReferent(ref); - if (Heap::IsEnqueuable(ref)) { - Heap::EnqueueReference(ref, &cleared_reference_list_); + heap_->ClearReferenceReferent(ref); + if (heap_->IsEnqueuable(ref)) { + heap_->EnqueueReference(ref, &cleared_reference_list_); } } } @@ -521,18 +532,18 @@ // referent field is cleared. void MarkSweep::EnqueueFinalizerReferences(Object** list) { DCHECK(list != NULL); - MemberOffset zombie_offset = Heap::GetFinalizerReferenceZombieOffset(); + MemberOffset zombie_offset = heap_->GetFinalizerReferenceZombieOffset(); bool has_enqueued = false; while (*list != NULL) { - Object* ref = Heap::DequeuePendingReference(list); - Object* referent = Heap::GetReferenceReferent(ref); + Object* ref = heap_->DequeuePendingReference(list); + Object* referent = heap_->GetReferenceReferent(ref); if (referent != NULL && !IsMarked(referent)) { MarkObject(referent); // If the referent is non-null the reference must queuable. - DCHECK(Heap::IsEnqueuable(ref)); + DCHECK(heap_->IsEnqueuable(ref)); ref->SetFieldObject(zombie_offset, referent, false); - Heap::ClearReferenceReferent(ref); - Heap::EnqueueReference(ref, &cleared_reference_list_); + heap_->ClearReferenceReferent(ref); + heap_->EnqueueReference(ref, &cleared_reference_list_); has_enqueued = true; } }
diff --git a/src/mark_sweep.h b/src/mark_sweep.h index c675675..dce4b52 100644 --- a/src/mark_sweep.h +++ b/src/mark_sweep.h
@@ -25,11 +25,16 @@ namespace art { class Class; +class Heap; class Object; class MarkSweep { public: MarkSweep() : + mark_stack_(NULL), + heap_(NULL), + mark_bitmap_(NULL), + live_bitmap_(NULL), finger_(NULL), condemned_(NULL), soft_reference_list_(NULL), @@ -162,8 +167,8 @@ MarkStack* mark_stack_; + Heap* heap_; HeapBitmap* mark_bitmap_; - HeapBitmap* live_bitmap_; Object* finger_;
diff --git a/src/mutex.cc b/src/mutex.cc index f7c3143..340a075 100644 --- a/src/mutex.cc +++ b/src/mutex.cc
@@ -61,6 +61,7 @@ int rc = pthread_mutex_destroy(&mutex_); if (rc != 0) { errno = rc; + // TODO: should we just not log at all if shutting down? this could be the logging mutex! bool shutting_down = Runtime::Current()->IsShuttingDown(); PLOG(shutting_down ? WARNING : FATAL) << "pthread_mutex_destroy failed for " << name_; }
diff --git a/src/oat_writer.cc b/src/oat_writer.cc index 5f97927..dcdff9a 100644 --- a/src/oat_writer.cc +++ b/src/oat_writer.cc
@@ -277,7 +277,7 @@ Class::Status status = (compiled_class != NULL) ? compiled_class->GetStatus() : Class::kStatusNotReady; CHECK(gc_map_size != 0 || is_native || status < Class::kStatusVerified) - << PrettyMethod(method_idx, *dex_file); + << &gc_map << " " << gc_map_size << " " << (is_native ? "true" : "false") << " " << (status < Class::kStatusVerified) << " " << status << " " << PrettyMethod(method_idx, *dex_file); #endif // Deduplicate GC maps
diff --git a/src/oatdump.cc b/src/oatdump.cc index 4b492aa..5574bb7 100644 --- a/src/oatdump.cc +++ b/src/oatdump.cc
@@ -543,7 +543,7 @@ oat_dumper_.reset(new OatDumper(*oat_file)); os_ << "OBJECTS:\n" << std::flush; - HeapBitmap* heap_bitmap = Heap::GetLiveBits(); + HeapBitmap* heap_bitmap = Runtime::Current()->GetHeap()->GetLiveBits(); DCHECK(heap_bitmap != NULL); heap_bitmap->Walk(ImageDumper::Callback, this); os_ << "\n"; @@ -1125,7 +1125,8 @@ return EXIT_FAILURE; } - ImageSpace* image_space = Heap::GetSpaces()[Heap::GetSpaces().size()-2]->AsImageSpace(); + Heap* heap = Runtime::Current()->GetHeap(); + ImageSpace* image_space = heap->GetSpaces()[heap->GetSpaces().size()-2]->AsImageSpace(); CHECK(image_space != NULL); const ImageHeader& image_header = image_space->GetImageHeader(); if (!image_header.IsValid()) {
diff --git a/src/object.cc b/src/object.cc index 0f5f1ec..2e98f4f 100644 --- a/src/object.cc +++ b/src/object.cc
@@ -57,7 +57,8 @@ // Object::SizeOf gets the right size even if we're an array. // Using c->AllocObject() here would be wrong. size_t num_bytes = SizeOf(); - SirtRef<Object> copy(Heap::AllocObject(c, num_bytes)); + Heap* heap = Runtime::Current()->GetHeap(); + SirtRef<Object> copy(heap->AllocObject(c, num_bytes)); if (copy.get() == NULL) { return NULL; } @@ -70,7 +71,7 @@ memcpy(dst_bytes + offset, src_bytes + offset, num_bytes - offset); if (c->IsFinalizable()) { - Heap::AddFinalizerReference(Thread::Current(), copy.get()); + heap->AddFinalizerReference(Thread::Current(), copy.get()); } return copy.get(); @@ -676,7 +677,7 @@ // TODO: decide whether we want this check. It currently fails during bootstrap. // DCHECK(!Runtime::Current()->IsStarted() || IsInitializing()) << PrettyClass(this); DCHECK_GE(this->object_size_, sizeof(Object)); - return Heap::AllocObject(this, this->object_size_); + return Runtime::Current()->GetHeap()->AllocObject(this, this->object_size_); } void Class::SetClassSize(size_t new_class_size) { @@ -1251,7 +1252,8 @@ return NULL; } - Array* array = down_cast<Array*>(Heap::AllocObject(array_class, size)); + Heap* heap = Runtime::Current()->GetHeap(); + Array* array = down_cast<Array*>(heap->AllocObject(array_class, size)); if (array != NULL) { DCHECK(array->IsArrayInstance()); array->SetLength(component_count);
diff --git a/src/object.h b/src/object.h index 89b9df4..b3a4805 100644 --- a/src/object.h +++ b/src/object.h
@@ -279,20 +279,20 @@ T GetFieldObject(MemberOffset field_offset, bool is_volatile) const { DCHECK(Thread::Current() == NULL || Thread::Current()->CanAccessDirectReferences()); T result = reinterpret_cast<T>(GetField32(field_offset, is_volatile)); - Heap::VerifyObject(result); + Runtime::Current()->GetHeap()->VerifyObject(result); return result; } void SetFieldObject(MemberOffset field_offset, const Object* new_value, bool is_volatile, bool this_is_valid = true) { - Heap::VerifyObject(new_value); + Runtime::Current()->GetHeap()->VerifyObject(new_value); SetField32(field_offset, reinterpret_cast<uint32_t>(new_value), is_volatile, this_is_valid); if (new_value != NULL) { - Heap::WriteBarrierField(this, field_offset, new_value); + Runtime::Current()->GetHeap()->WriteBarrierField(this, field_offset, new_value); } } uint32_t GetField32(MemberOffset field_offset, bool is_volatile) const { - Heap::VerifyObject(this); + Runtime::Current()->GetHeap()->VerifyObject(this); const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset.Int32Value(); const int32_t* word_addr = reinterpret_cast<const int32_t*>(raw_addr); if (UNLIKELY(is_volatile)) { @@ -304,7 +304,7 @@ void SetField32(MemberOffset field_offset, uint32_t new_value, bool is_volatile, bool this_is_valid = true) { if (this_is_valid) { - Heap::VerifyObject(this); + Runtime::Current()->GetHeap()->VerifyObject(this); } byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value(); uint32_t* word_addr = reinterpret_cast<uint32_t*>(raw_addr); @@ -323,7 +323,7 @@ } uint64_t GetField64(MemberOffset field_offset, bool is_volatile) const { - Heap::VerifyObject(this); + Runtime::Current()->GetHeap()->VerifyObject(this); const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset.Int32Value(); const int64_t* addr = reinterpret_cast<const int64_t*>(raw_addr); if (UNLIKELY(is_volatile)) { @@ -336,7 +336,7 @@ } void SetField64(MemberOffset field_offset, uint64_t new_value, bool is_volatile) { - Heap::VerifyObject(this); + Runtime::Current()->GetHeap()->VerifyObject(this); byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value(); int64_t* addr = reinterpret_cast<int64_t*>(raw_addr); if (UNLIKELY(is_volatile)) { @@ -2035,11 +2035,12 @@ MemberOffset src_offset(DataOffset(sizeof(Object*)).Int32Value() + src_pos * sizeof(Object*)); MemberOffset dst_offset(DataOffset(sizeof(Object*)).Int32Value() + dst_pos * sizeof(Object*)); Class* array_class = dst->GetClass(); + Heap* heap = Runtime::Current()->GetHeap(); if (array_class == src->GetClass()) { // No need for array store checks if arrays are of the same type for (size_t i = 0; i < length; i++) { Object* object = src->GetFieldObject<Object*>(src_offset, false); - Heap::VerifyObject(object); + heap->VerifyObject(object); // directly set field, we do a bulk write barrier at the end dst->SetField32(dst_offset, reinterpret_cast<uint32_t>(object), false, true); src_offset = MemberOffset(src_offset.Uint32Value() + sizeof(Object*)); @@ -2054,14 +2055,14 @@ dst->ThrowArrayStoreException(object); return; } - Heap::VerifyObject(object); + heap->VerifyObject(object); // directly set field, we do a bulk write barrier at the end dst->SetField32(dst_offset, reinterpret_cast<uint32_t>(object), false, true); src_offset = MemberOffset(src_offset.Uint32Value() + sizeof(Object*)); dst_offset = MemberOffset(dst_offset.Uint32Value() + sizeof(Object*)); } } - Heap::WriteBarrierArray(dst, dst_pos, length); + heap->WriteBarrierArray(dst, dst_pos, length); } }
diff --git a/src/object_test.cc b/src/object_test.cc index b431d0a..3abe702 100644 --- a/src/object_test.cc +++ b/src/object_test.cc
@@ -192,7 +192,7 @@ TEST_F(ObjectTest, StaticFieldFromCode) { // pretend we are trying to access 'Static.s0' from StaticsFromCode.<clinit> SirtRef<ClassLoader> class_loader(LoadDex("StaticsFromCode")); - const DexFile* dex_file = ClassLoader::GetCompileTimeClassPath(class_loader.get())[0]; + const DexFile* dex_file = Runtime::Current()->GetCompileTimeClassPath(class_loader.get())[0]; CHECK(dex_file != NULL); Class* klass = class_linker_->FindClass("LStaticsFromCode;", class_loader.get());
diff --git a/src/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/src/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc index 51983ea..c5db4f6 100644 --- a/src/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc +++ b/src/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -16,6 +16,7 @@ #include "debugger.h" #include "logging.h" +#include "scoped_heap_lock.h" #include "stack.h" #include "thread_list.h"
diff --git a/src/runtime.cc b/src/runtime.cc index 22f4329..c53ede1 100644 --- a/src/runtime.cc +++ b/src/runtime.cc
@@ -47,12 +47,11 @@ Runtime* Runtime::instance_ = NULL; -Mutex Runtime::abort_lock_("abort lock"); - Runtime::Runtime() : is_compiler_(false), is_zygote_(false), default_stack_size_(Thread::kDefaultStackSize), + heap_(NULL), monitor_list_(NULL), thread_list_(NULL), intern_table_(NULL), @@ -69,7 +68,8 @@ exit_(NULL), abort_(NULL), stats_enabled_(false), - tracer_(NULL) { + tracer_(NULL), + use_compile_time_class_path_(false) { for (int i = 0; i < Runtime::kLastTrampolineMethodType; i++) { resolution_stub_array_[i] = NULL; } @@ -92,7 +92,7 @@ delete monitor_list_; delete class_linker_; - Heap::Destroy(); + delete heap_; verifier::DexVerifier::DeleteGcMaps(); delete intern_table_; delete java_vm_; @@ -129,10 +129,15 @@ } }; +static Mutex& GetAbortLock() { + static Mutex abort_lock("abort lock"); + return abort_lock; +} + void Runtime::Abort(const char* file, int line) { // Ensure that we don't have multiple threads trying to abort at once, // which would result in significantly worse diagnostics. - MutexLock mu(abort_lock_); + MutexLock mu(GetAbortLock()); // Get any pending output out of the way. fflush(NULL); @@ -294,6 +299,17 @@ parsed->hook_exit_ = exit; parsed->hook_abort_ = abort; +// gLogVerbosity.class_linker = true; // TODO: don't check this in! +// gLogVerbosity.compiler = true; // TODO: don't check this in! +// gLogVerbosity.heap = true; // TODO: don't check this in! +// gLogVerbosity.gc = true; // TODO: don't check this in! +// gLogVerbosity.jdwp = true; // TODO: don't check this in! +// gLogVerbosity.jni = true; // TODO: don't check this in! +// gLogVerbosity.monitor = true; // TODO: don't check this in! +// gLogVerbosity.startup = true; // TODO: don't check this in! +// gLogVerbosity.third_party_jni = true; // TODO: don't check this in! +// gLogVerbosity.threads = true; // TODO: don't check this in! + for (size_t i = 0; i < options.size(); ++i) { const std::string option(options[i].first); if (true && options[0].first == "-Xzygote") { @@ -469,7 +485,7 @@ } void CreateSystemClassLoader() { - if (ClassLoader::UseCompileTimeClassPath()) { + if (Runtime::Current()->UseCompileTimeClassPath()) { return; } @@ -605,10 +621,12 @@ thread_list_ = new ThreadList; intern_table_ = new InternTable; - Heap::Init(options->heap_initial_size_, - options->heap_growth_limit_, - options->heap_maximum_size_, - options->image_); + verifier::DexVerifier::InitGcMaps(); + + heap_ = new Heap(options->heap_initial_size_, + options->heap_growth_limit_, + options->heap_maximum_size_, + options->image_); BlockSignals(); @@ -623,8 +641,8 @@ // Set us to runnable so tools using a runtime can allocate and GC by default Thread::Current()->SetState(Thread::kRunnable); - CHECK_GE(Heap::GetSpaces().size(), 1U); - if (Heap::GetSpaces()[0]->IsImageSpace()) { + CHECK_GE(GetHeap()->GetSpaces().size(), 1U); + if (GetHeap()->GetSpaces()[0]->IsImageSpace()) { class_linker_ = ClassLinker::CreateFromImage(intern_table_); } else { CHECK(options->boot_class_path_ != NULL); @@ -697,7 +715,7 @@ } void Runtime::DumpLockHolders(std::ostream& os) { - pid_t heap_lock_owner = Heap::GetLockOwner(); + pid_t heap_lock_owner = GetHeap()->GetLockOwner(); pid_t thread_list_lock_owner = GetThreadList()->GetLockOwner(); pid_t classes_lock_owner = GetClassLinker()->GetClassesLockOwner(); pid_t dex_lock_owner = GetClassLinker()->GetDexLockOwner(); @@ -971,4 +989,20 @@ return tracer_; } +const std::vector<const DexFile*>& Runtime::GetCompileTimeClassPath(const ClassLoader* class_loader) { + if (class_loader == NULL) { + return GetClassLinker()->GetBootClassPath(); + } + CHECK(UseCompileTimeClassPath()); + CompileTimeClassPaths::const_iterator it = compile_time_class_paths_.find(class_loader); + CHECK(it != compile_time_class_paths_.end()); + return it->second; +} + +void Runtime::SetCompileTimeClassPath(const ClassLoader* class_loader, std::vector<const DexFile*>& class_path) { + CHECK(!IsStarted()); + use_compile_time_class_path_ = true; + compile_time_class_paths_[class_loader] = class_path; +} + } // namespace art
diff --git a/src/runtime.h b/src/runtime.h index 36f0084..a2ec08e 100644 --- a/src/runtime.h +++ b/src/runtime.h
@@ -20,6 +20,7 @@ #include <stdio.h> #include <iosfwd> +#include <map> #include <string> #include <utility> #include <vector> @@ -148,6 +149,10 @@ return default_stack_size_; } + Heap* GetHeap() const { + return heap_; + } + InternTable* GetInternTable() const { return intern_table_; } @@ -232,6 +237,12 @@ bool IsMethodTracingActive() const; Trace* GetTracer() const; + bool UseCompileTimeClassPath() const { + return use_compile_time_class_path_; + } + const std::vector<const DexFile*>& GetCompileTimeClassPath(const ClassLoader* class_loader); + void SetCompileTimeClassPath(const ClassLoader* class_loader, std::vector<const DexFile*>& class_path); + private: static void PlatformAbort(const char*, int); @@ -246,6 +257,9 @@ void StartDaemonThreads(); void StartSignalCatcher(); + // A pointer to the active runtime or NULL. + static Runtime* instance_; + bool is_compiler_; bool is_zygote_; @@ -268,6 +282,8 @@ // The default stack size for managed threads created by the runtime. size_t default_stack_size_; + Heap* heap_; + MonitorList* monitor_list_; ThreadList* thread_list_; @@ -307,10 +323,9 @@ Trace* tracer_; - // A pointer to the active runtime or NULL. - static Runtime* instance_; - - static Mutex abort_lock_; + typedef std::map<const ClassLoader*, std::vector<const DexFile*> > CompileTimeClassPaths; + CompileTimeClassPaths compile_time_class_paths_; + bool use_compile_time_class_path_; DISALLOW_COPY_AND_ASSIGN(Runtime); };
diff --git a/src/runtime_support.cc b/src/runtime_support.cc index 6531eb2..92b5203 100644 --- a/src/runtime_support.cc +++ b/src/runtime_support.cc
@@ -512,7 +512,7 @@ intptr_t value = *arg_ptr; Object** value_as_jni_rep = reinterpret_cast<Object**>(value); Object* value_as_work_around_rep = value_as_jni_rep != NULL ? *value_as_jni_rep : NULL; - CHECK(Heap::IsHeapAddress(value_as_work_around_rep)); + CHECK(Runtime::Current()->GetHeap()->IsHeapAddress(value_as_work_around_rep)); *arg_ptr = reinterpret_cast<intptr_t>(value_as_work_around_rep); }
diff --git a/src/scoped_heap_lock.h b/src/scoped_heap_lock.h new file mode 100644 index 0000000..0dee589 --- /dev/null +++ b/src/scoped_heap_lock.h
@@ -0,0 +1,42 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef ART_SRC_SCOPED_HEAP_LOCK_H_ +#define ART_SRC_SCOPED_HEAP_LOCK_H_ + +#include "heap.h" +#include "macros.h" +#include "runtime.h" + +namespace art { + +class ScopedHeapLock { + public: + ScopedHeapLock() { + Runtime::Current()->GetHeap()->Lock(); + } + + ~ScopedHeapLock() { + Runtime::Current()->GetHeap()->Unlock(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ScopedHeapLock); +}; + +} // namespace art + +#endif // ART_SRC_SCOPED_HEAP_LOCK_H_
diff --git a/src/signal_catcher.cc b/src/signal_catcher.cc index 4230834..bc358ed 100644 --- a/src/signal_catcher.cc +++ b/src/signal_catcher.cc
@@ -30,6 +30,7 @@ #include "heap.h" #include "os.h" #include "runtime.h" +#include "scoped_heap_lock.h" #include "thread.h" #include "thread_list.h" #include "utils.h" @@ -131,7 +132,7 @@ void SignalCatcher::HandleSigUsr1() { LOG(INFO) << "SIGUSR1 forcing GC (no HPROF)"; - Heap::CollectGarbage(false); + Runtime::Current()->GetHeap()->CollectGarbage(false); } int SignalCatcher::WaitForSignal(sigset_t& mask) {
diff --git a/src/space.cc b/src/space.cc index 6d5a31a..78fcdf5 100644 --- a/src/space.cc +++ b/src/space.cc
@@ -176,13 +176,14 @@ // Callback from dlmalloc when it needs to increase the footprint extern "C" void* art_heap_morecore(void* mspace, intptr_t increment) { - AllocSpace* space = Heap::GetAllocSpace(); + Heap* heap = Runtime::Current()->GetHeap(); + AllocSpace* space = heap->GetAllocSpace(); if (LIKELY(space->GetMspace() == mspace)) { return space->MoreCore(increment); } else { // Exhaustively search alloc spaces - const std::vector<Space*>& spaces = Heap::GetSpaces(); - for (size_t i = 0; i < spaces.size(); i++) { + const std::vector<Space*>& spaces = heap->GetSpaces(); + for (size_t i = 0; i < spaces.size(); ++i) { if (spaces[i]->IsAllocSpace()) { AllocSpace* space = spaces[i]->AsAllocSpace(); if (mspace == space->GetMspace()) { @@ -191,7 +192,7 @@ } } LOG(FATAL) << "Unexpected call to art_heap_morecore. mspace: " << mspace - << " increment: " << increment; + << " increment: " << increment; return NULL; } }
diff --git a/src/space_test.cc b/src/space_test.cc index eb4fa86..16ffb08 100644 --- a/src/space_test.cc +++ b/src/space_test.cc
@@ -75,7 +75,7 @@ ASSERT_TRUE(space != NULL); // Make space findable to the heap, will also delete space when runtime is cleaned up - Heap::AddSpace(space); + Runtime::Current()->GetHeap()->AddSpace(space); // Succeeds, fits without adjusting the footprint limit. Object* ptr1 = space->AllocWithoutGrowth(1 * MB); @@ -117,7 +117,7 @@ ASSERT_TRUE(space != NULL); // Make space findable to the heap, will also delete space when runtime is cleaned up - Heap::AddSpace(space); + Runtime::Current()->GetHeap()->AddSpace(space); // Succeeds, fits without adjusting the max allowed footprint. Object* lots_of_objects[1024]; @@ -309,7 +309,7 @@ EXPECT_EQ(space->NonGrowthLimitCapacity(), capacity); // Make space findable to the heap, will also delete space when runtime is cleaned up - Heap::AddSpace(space); + Runtime::Current()->GetHeap()->AddSpace(space); // In this round we don't allocate with growth and therefore can't grow past the initial size. // This effectively makes the growth_limit the initial_size, so assert this.
diff --git a/src/stack.cc b/src/stack.cc index 7da20b0..4623ec1 100644 --- a/src/stack.cc +++ b/src/stack.cc
@@ -23,10 +23,6 @@ namespace art { -int oatVRegOffset(const DexFile::CodeItem* code_item, - uint32_t core_spills, uint32_t fp_spills, - size_t frame_size, int reg); - bool Frame::HasMethod() const { return GetMethod() != NULL && (!GetMethod()->IsCalleeSaveMethod()); } @@ -53,9 +49,26 @@ *reinterpret_cast<uintptr_t*>(pc_addr) = pc; } +/* Return sp-relative offset in bytes using Method* */ +static int GetVRegOffset(const DexFile::CodeItem* code_item, + uint32_t core_spills, uint32_t fp_spills, + size_t frame_size, int reg) +{ + static const int kStackAlignWords = kStackAlignment/sizeof(uint32_t); + int numIns = code_item->ins_size_; + int numRegs = code_item->registers_size_ - numIns; + int numOuts = code_item->outs_size_; + int numSpills = __builtin_popcount(core_spills) + __builtin_popcount(fp_spills); + int numPadding = (kStackAlignWords - (numSpills + numRegs + numOuts + 2)) & (kStackAlignWords - 1); + int regsOffset = (numOuts + numPadding + 1) * 4; + int insOffset = frame_size + 4; + return (reg < numRegs) ? regsOffset + (reg << 2) : + insOffset + ((reg - numRegs) << 2); +} + uint32_t Frame::GetVReg(const DexFile::CodeItem* code_item, uint32_t core_spills, uint32_t fp_spills, size_t frame_size, int vreg) const { - int offset = oatVRegOffset(code_item, core_spills, fp_spills, frame_size, vreg); + int offset = GetVRegOffset(code_item, core_spills, fp_spills, frame_size, vreg); byte* vreg_addr = reinterpret_cast<byte*>(sp_) + offset; return *reinterpret_cast<uint32_t*>(vreg_addr); } @@ -77,7 +90,7 @@ uint32_t core_spills = m->GetCoreSpillMask(); uint32_t fp_spills = m->GetFpSpillMask(); size_t frame_size = m->GetFrameSizeInBytes(); - int offset = oatVRegOffset(code_item, core_spills, fp_spills, frame_size, vreg); + int offset = GetVRegOffset(code_item, core_spills, fp_spills, frame_size, vreg); byte* vreg_addr = reinterpret_cast<byte*>(sp_) + offset; *reinterpret_cast<uint32_t*>(vreg_addr) = new_value; }
diff --git a/src/sun_misc_Unsafe.cc b/src/sun_misc_Unsafe.cc index 68cd4f7..a561690 100644 --- a/src/sun_misc_Unsafe.cc +++ b/src/sun_misc_Unsafe.cc
@@ -70,7 +70,7 @@ int result = android_atomic_release_cas(reinterpret_cast<int32_t>(expectedValue), reinterpret_cast<int32_t>(newValue), address); if (result == 0) { - Heap::WriteBarrierField(obj, MemberOffset(offset), newValue); + Runtime::Current()->GetHeap()->WriteBarrierField(obj, MemberOffset(offset), newValue); } return (result == 0); }
diff --git a/src/thread.cc b/src/thread.cc index ee3bf26..ac0922d 100644 --- a/src/thread.cc +++ b/src/thread.cc
@@ -68,7 +68,7 @@ static Method* gUncaughtExceptionHandler_uncaughtException = NULL; void Thread::InitCardTable() { - card_table_ = Heap::GetCardTable()->GetBiasedBegin(); + card_table_ = Runtime::Current()->GetHeap()->GetCardTable()->GetBiasedBegin(); } void Thread::InitFunctionPointers() { @@ -540,7 +540,7 @@ #ifndef NDEBUG if (sp != NULL) { Method* m = *sp; - Heap::VerifyObject(m); + Runtime::Current()->GetHeap()->VerifyObject(m); DCHECK((m == NULL) || m->IsMethod()); } #endif @@ -1056,7 +1056,7 @@ JniAbort(NULL); } else { if (result != kInvalidIndirectRefObject) { - Heap::VerifyObject(result); + Runtime::Current()->GetHeap()->VerifyObject(result); } } return result;
diff --git a/src/thread_list.cc b/src/thread_list.cc index e780e2c..b2cf676 100644 --- a/src/thread_list.cc +++ b/src/thread_list.cc
@@ -19,6 +19,7 @@ #include <unistd.h> #include "debugger.h" +#include "scoped_heap_lock.h" namespace art { @@ -458,8 +459,9 @@ // started, we wait until it's over. Which means that if there's now another GC pending, our // suspend count is non-zero, so switching to the runnable state will suspend us. // TODO: find a better solution! - Heap::Lock(); - Heap::Unlock(); + { + ScopedHeapLock heap_lock; + } self->SetState(Thread::kRunnable); }