diff options
| -rw-r--r-- | Android.mk | 18 | ||||
| -rw-r--r-- | oatdump/oatdump.cc | 19 | ||||
| -rw-r--r-- | runtime/debugger.cc | 4 | ||||
| -rw-r--r-- | runtime/gc/heap.cc | 2 | ||||
| -rw-r--r-- | runtime/indenter.h | 27 | ||||
| -rw-r--r-- | runtime/instrumentation.cc | 52 | ||||
| -rw-r--r-- | runtime/instrumentation.h | 13 | ||||
| -rw-r--r-- | runtime/runtime.cc | 49 | ||||
| -rw-r--r-- | runtime/runtime.h | 5 |
9 files changed, 114 insertions, 75 deletions
diff --git a/Android.mk b/Android.mk index 3112ab0288..8024a3d357 100644 --- a/Android.mk +++ b/Android.mk @@ -305,6 +305,8 @@ build-art-target: $(ART_TARGET_EXECUTABLES) $(ART_TARGET_TEST_EXECUTABLES) $(TAR ######################################################################## # oatdump targets +ART_DUMP_OAT_PATH ?= $(OUT_DIR) + .PHONY: dump-oat dump-oat: dump-oat-core dump-oat-boot @@ -314,29 +316,29 @@ dump-oat-core: dump-oat-core-host dump-oat-core-target .PHONY: dump-oat-core-host ifeq ($(ART_BUILD_HOST),true) dump-oat-core-host: $(HOST_CORE_IMG_OUT) $(OATDUMP) - $(OATDUMP) --image=$(HOST_CORE_IMG_OUT) --output=/tmp/core.host.oatdump.txt --host-prefix="" - @echo Output in /tmp/core.host.oatdump.txt + $(OATDUMP) --image=$(HOST_CORE_IMG_OUT) --output=$(ART_DUMP_OAT_PATH)/core.host.oatdump.txt --host-prefix="" + @echo Output in $(ART_DUMP_OAT_PATH)/core.host.oatdump.txt endif .PHONY: dump-oat-core-target ifeq ($(ART_BUILD_TARGET),true) dump-oat-core-target: $(TARGET_CORE_IMG_OUT) $(OATDUMP) - $(OATDUMP) --image=$(TARGET_CORE_IMG_OUT) --output=/tmp/core.target.oatdump.txt - @echo Output in /tmp/core.target.oatdump.txt + $(OATDUMP) --image=$(TARGET_CORE_IMG_OUT) --output=$(ART_DUMP_OAT_PATH)/core.target.oatdump.txt + @echo Output in $(ART_DUMP_OAT_PATH)/core.target.oatdump.txt endif .PHONY: dump-oat-boot ifeq ($(ART_BUILD_TARGET_NDEBUG),true) dump-oat-boot: $(TARGET_BOOT_IMG_OUT) $(OATDUMP) - $(OATDUMP) --image=$(TARGET_BOOT_IMG_OUT) --output=/tmp/boot.oatdump.txt - @echo Output in /tmp/boot.oatdump.txt + $(OATDUMP) --image=$(TARGET_BOOT_IMG_OUT) --output=$(ART_DUMP_OAT_PATH)/boot.oatdump.txt + @echo Output in $(ART_DUMP_OAT_PATH)/boot.oatdump.txt endif .PHONY: dump-oat-Calculator ifeq ($(ART_BUILD_TARGET_NDEBUG),true) dump-oat-Calculator: $(TARGET_OUT_APPS)/Calculator.odex $(TARGET_BOOT_IMG_OUT) $(OATDUMP) - $(OATDUMP) --oat-file=$< --output=/tmp/Calculator.oatdump.txt - @echo Output in /tmp/Calculator.oatdump.txt + $(OATDUMP) --oat-file=$< --output=$(ART_DUMP_OAT_PATH)/Calculator.oatdump.txt + @echo Output in $(ART_DUMP_OAT_PATH)/Calculator.oatdump.txt endif ######################################################################## diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index b9716d556f..90276c2678 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -715,14 +715,25 @@ class ImageDumper { if (image_root_object->IsObjectArray()) { Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count); std::ostream indent2_os(&indent2_filter); - // TODO: replace down_cast with AsObjectArray (g++ currently has a problem with this) mirror::ObjectArray<mirror::Object>* image_root_object_array - = down_cast<mirror::ObjectArray<mirror::Object>*>(image_root_object); - // = image_root_object->AsObjectArray<Object>(); + = image_root_object->AsObjectArray<mirror::Object>(); for (int i = 0; i < image_root_object_array->GetLength(); i++) { mirror::Object* value = image_root_object_array->Get(i); + size_t run = 0; + for (int32_t j = i + 1; j < image_root_object_array->GetLength(); j++) { + if (value == image_root_object_array->Get(j)) { + run++; + } else { + break; + } + } + if (run == 0) { + indent2_os << StringPrintf("%d: ", i); + } else { + indent2_os << StringPrintf("%d to %zd: ", i, i + run); + i = i + run; + } if (value != NULL) { - indent2_os << i << ": "; PrettyObjectValue(indent2_os, value->GetClass(), value); } else { indent2_os << i << ": null\n"; diff --git a/runtime/debugger.cc b/runtime/debugger.cc index bdcf6ac6ab..0eecd28831 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -3489,9 +3489,9 @@ void Dbg::SetAllocTrackingEnabled(bool enabled) { recent_allocation_records_ = new AllocRecord[gAllocRecordMax]; CHECK(recent_allocation_records_ != NULL); } - Runtime::Current()->InstrumentQuickAllocEntryPoints(); + Runtime::Current()->GetInstrumentation()->InstrumentQuickAllocEntryPoints(); } else { - Runtime::Current()->UninstrumentQuickAllocEntryPoints(); + Runtime::Current()->GetInstrumentation()->UninstrumentQuickAllocEntryPoints(); delete[] recent_allocation_records_; recent_allocation_records_ = NULL; } diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 804c66932e..de3ab0eb9d 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -237,7 +237,7 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max CHECK_NE(max_allowed_footprint_, 0U); if (running_on_valgrind_) { - Runtime::Current()->InstrumentQuickAllocEntryPoints(); + Runtime::Current()->GetInstrumentation()->InstrumentQuickAllocEntryPoints(); } if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) { diff --git a/runtime/indenter.h b/runtime/indenter.h index c432e1ba8d..d055d4e3f4 100644 --- a/runtime/indenter.h +++ b/runtime/indenter.h @@ -17,6 +17,7 @@ #ifndef ART_RUNTIME_INDENTER_H_ #define ART_RUNTIME_INDENTER_H_ +#include "base/logging.h" #include "base/macros.h" #include <streambuf> @@ -30,16 +31,28 @@ class Indenter : public std::streambuf { private: int_type overflow(int_type c) { - if (c != std::char_traits<char>::eof()) { - if (indent_next_) { - for (size_t i = 0; i < count_; ++i) { - out_sbuf_->sputc(text_); + if (UNLIKELY(c == std::char_traits<char>::eof())) { + out_sbuf_->pubsync(); + return c; + } + if (indent_next_) { + for (size_t i = 0; i < count_; ++i) { + int_type r = out_sbuf_->sputc(text_); + if (UNLIKELY(r != text_)) { + out_sbuf_->pubsync(); + r = out_sbuf_->sputc(text_); + CHECK_EQ(r, text_) << "Error writing to buffer. Disk full?"; } } - out_sbuf_->sputc(c); - indent_next_ = (c == '\n'); } - return std::char_traits<char>::not_eof(c); + indent_next_ = (c == '\n'); + int_type r = out_sbuf_->sputc(c); + if (UNLIKELY(r != c)) { + out_sbuf_->pubsync(); + r = out_sbuf_->sputc(c); + CHECK_EQ(r, c) << "Error writing to buffer. Disk full?"; + } + return r; } int sync() { diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index 8316bc56b3..4070324faf 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -39,6 +39,9 @@ #include "thread_list.h" namespace art { + +extern void SetQuickAllocEntryPointsInstrumented(bool instrumented); + namespace instrumentation { // Do we want to deoptimize for method entry and exit listeners or just try to intercept @@ -391,6 +394,55 @@ void Instrumentation::ConfigureStubs(bool require_entry_exit_stubs, bool require } } +static void ResetQuickAllocEntryPointsForThread(Thread* thread, void* arg) { + thread->ResetQuickAllocEntryPointsForThread(); +} + +void Instrumentation::InstrumentQuickAllocEntryPoints() { + // TODO: the read of quick_alloc_entry_points_instrumentation_counter_ is racey and this code + // should be guarded by a lock. + DCHECK_GE(quick_alloc_entry_points_instrumentation_counter_, 0U); + bool enable_instrumentation = (quick_alloc_entry_points_instrumentation_counter_ == 0); + quick_alloc_entry_points_instrumentation_counter_++; + if (enable_instrumentation) { + // Instrumentation wasn't enabled so enable it. + SetQuickAllocEntryPointsInstrumented(true); + Runtime* runtime = Runtime::Current(); + if (runtime->IsStarted()) { + ThreadList* tl = runtime->GetThreadList(); + Thread* self = Thread::Current(); + tl->SuspendAll(); + { + MutexLock mu(self, *Locks::thread_list_lock_); + tl->ForEach(ResetQuickAllocEntryPointsForThread, NULL); + } + tl->ResumeAll(); + } + } +} + +void Instrumentation::UninstrumentQuickAllocEntryPoints() { + // TODO: the read of quick_alloc_entry_points_instrumentation_counter_ is racey and this code + // should be guarded by a lock. + DCHECK_GT(quick_alloc_entry_points_instrumentation_counter_, 0U); + quick_alloc_entry_points_instrumentation_counter_--; + bool disable_instrumentation = (quick_alloc_entry_points_instrumentation_counter_ == 0); + if (disable_instrumentation) { + SetQuickAllocEntryPointsInstrumented(false); + Runtime* runtime = Runtime::Current(); + if (runtime->IsStarted()) { + ThreadList* tl = Runtime::Current()->GetThreadList(); + Thread* self = Thread::Current(); + tl->SuspendAll(); + { + MutexLock mu(self, *Locks::thread_list_lock_); + tl->ForEach(ResetQuickAllocEntryPointsForThread, NULL); + } + tl->ResumeAll(); + } + } +} + void Instrumentation::UpdateMethodsCode(mirror::ArtMethod* method, const void* code) const { if (LIKELY(!instrumentation_stubs_installed_)) { method->SetEntryPointFromCompiledCode(code); diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h index 7a0aaf7858..25a4eec976 100644 --- a/runtime/instrumentation.h +++ b/runtime/instrumentation.h @@ -104,7 +104,8 @@ class Instrumentation { have_method_entry_listeners_(false), have_method_exit_listeners_(false), have_method_unwind_listeners_(false), have_dex_pc_listeners_(false), have_exception_caught_listeners_(false), - interpreter_handler_table_(kMainHandlerTable) {} + interpreter_handler_table_(kMainHandlerTable), + quick_alloc_entry_points_instrumentation_counter_(0) {} // Add a listener to be notified of the masked together sent of instrumentation events. This // suspend the runtime to install stubs. You are expected to hold the mutator lock as a proxy @@ -123,6 +124,9 @@ class Instrumentation { return interpreter_handler_table_; } + void InstrumentQuickAllocEntryPoints() LOCKS_EXCLUDED(Locks::thread_list_lock_); + void UninstrumentQuickAllocEntryPoints() LOCKS_EXCLUDED(Locks::thread_list_lock_); + // Update the code of a method respecting any installed stubs. void UpdateMethodsCode(mirror::ArtMethod* method, const void* code) const; @@ -289,9 +293,14 @@ class Instrumentation { std::list<InstrumentationListener*> dex_pc_listeners_ GUARDED_BY(Locks::mutator_lock_); std::list<InstrumentationListener*> exception_caught_listeners_ GUARDED_BY(Locks::mutator_lock_); - // Current interpreter handler table. This is updated each time the thread state flags are modified. + // Current interpreter handler table. This is updated each time the thread state flags are + // modified. InterpreterHandlerTable interpreter_handler_table_; + // Greater than 0 if quick alloc entry points instrumented. + // TODO: The access and changes to this is racy and should be guarded by a lock. + size_t quick_alloc_entry_points_instrumentation_counter_; + DISALLOW_COPY_AND_ASSIGN(Instrumentation); }; diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 34cf45b4c7..53c9b2efbb 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -102,8 +102,7 @@ Runtime::Runtime() use_compile_time_class_path_(false), main_thread_group_(NULL), system_thread_group_(NULL), - system_class_loader_(NULL), - quick_alloc_entry_points_instrumentation_counter_(0) { + system_class_loader_(NULL) { for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) { callee_save_methods_[i] = NULL; } @@ -1077,9 +1076,9 @@ void Runtime::SetStatsEnabled(bool new_state) { GetStats()->Clear(~0); // TODO: wouldn't it make more sense to clear _all_ threads' stats? Thread::Current()->GetStats()->Clear(~0); - InstrumentQuickAllocEntryPoints(); + GetInstrumentation()->InstrumentQuickAllocEntryPoints(); } else { - UninstrumentQuickAllocEntryPoints(); + GetInstrumentation()->UninstrumentQuickAllocEntryPoints(); } stats_enabled_ = new_state; } @@ -1336,46 +1335,4 @@ void Runtime::SetCompileTimeClassPath(jobject class_loader, std::vector<const De compile_time_class_paths_.Put(class_loader, class_path); } -static void ResetQuickAllocEntryPointsForThread(Thread* thread, void* arg) { - thread->ResetQuickAllocEntryPointsForThread(); -} - -void SetQuickAllocEntryPointsInstrumented(bool instrumented); - -void Runtime::InstrumentQuickAllocEntryPoints() { - ThreadList* tl = thread_list_; - Thread* self = Thread::Current(); - tl->SuspendAll(); - { - MutexLock mu(self, *Locks::runtime_shutdown_lock_); - MutexLock mu2(self, *Locks::thread_list_lock_); - DCHECK_GE(quick_alloc_entry_points_instrumentation_counter_, 0); - int old_counter = quick_alloc_entry_points_instrumentation_counter_++; - if (old_counter == 0) { - // If it was disabled, enable it. - SetQuickAllocEntryPointsInstrumented(true); - tl->ForEach(ResetQuickAllocEntryPointsForThread, NULL); - } - } - tl->ResumeAll(); -} - -void Runtime::UninstrumentQuickAllocEntryPoints() { - ThreadList* tl = thread_list_; - Thread* self = Thread::Current(); - tl->SuspendAll(); - { - MutexLock mu(self, *Locks::runtime_shutdown_lock_); - MutexLock mu2(self, *Locks::thread_list_lock_); - DCHECK_GT(quick_alloc_entry_points_instrumentation_counter_, 0); - int new_counter = --quick_alloc_entry_points_instrumentation_counter_; - if (new_counter == 0) { - // Disable it if the counter becomes zero. - SetQuickAllocEntryPointsInstrumented(false); - tl->ForEach(ResetQuickAllocEntryPointsForThread, NULL); - } - } - tl->ResumeAll(); -} - } // namespace art diff --git a/runtime/runtime.h b/runtime/runtime.h index 0ce2642c98..24b4c87666 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -442,9 +442,6 @@ class Runtime { const std::vector<const DexFile*>& GetCompileTimeClassPath(jobject class_loader); void SetCompileTimeClassPath(jobject class_loader, std::vector<const DexFile*>& class_path); - void InstrumentQuickAllocEntryPoints(); - void UninstrumentQuickAllocEntryPoints(); - private: static void InitPlatformSignalHandlers(); @@ -567,8 +564,6 @@ class Runtime { // As returned by ClassLoader.getSystemClassLoader(). jobject system_class_loader_; - int quick_alloc_entry_points_instrumentation_counter_; - DISALLOW_COPY_AND_ASSIGN(Runtime); }; |