Merge "Fix bug in CardTable::ModifyCardsAtomic."
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index f5bb85a..364a8bc 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -141,24 +141,25 @@
CompilationUnit::~CompilationUnit() {
}
-// TODO: Add a cumulative version of logging, and combine with dex2oat --dump-timing
void CompilationUnit::StartTimingSplit(const char* label) {
- if (enable_debug & (1 << kDebugTimings)) {
+ if (compiler_driver->GetDumpPasses()) {
timings.StartSplit(label);
}
}
void CompilationUnit::NewTimingSplit(const char* label) {
- if (enable_debug & (1 << kDebugTimings)) {
+ if (compiler_driver->GetDumpPasses()) {
timings.NewSplit(label);
}
}
void CompilationUnit::EndTiming() {
- if (enable_debug & (1 << kDebugTimings)) {
+ if (compiler_driver->GetDumpPasses()) {
timings.EndSplit();
- LOG(INFO) << "TIMINGS " << PrettyMethod(method_idx, *dex_file);
- LOG(INFO) << Dumpable<TimingLogger>(timings);
+ if (enable_debug & (1 << kDebugTimings)) {
+ LOG(INFO) << "TIMINGS " << PrettyMethod(method_idx, *dex_file);
+ LOG(INFO) << Dumpable<TimingLogger>(timings);
+ }
}
}
@@ -316,6 +317,9 @@
}
cu.EndTiming();
+ compiler.GetTimingsLogger().Start();
+ compiler.GetTimingsLogger().AddLogger(cu.timings);
+ compiler.GetTimingsLogger().End();
return result;
}
diff --git a/compiler/dex/pass_driver.cc b/compiler/dex/pass_driver.cc
index 99541ac..820dc5a 100644
--- a/compiler/dex/pass_driver.cc
+++ b/compiler/dex/pass_driver.cc
@@ -25,7 +25,20 @@
namespace art {
-PassDriver::PassDriver(CompilationUnit* const cu, bool create_default_passes) : cu_(cu) {
+namespace { // anonymous namespace
+
+/**
+ * @brief Helper function to create a single instance of a given Pass and can be shared across the threads
+ */
+template <typename PassType>
+const Pass* GetPassInstance() {
+ static const PassType pass;
+ return &pass;
+}
+
+} // anonymous namespace
+
+PassDriver::PassDriver(CompilationUnit* cu, bool create_default_passes) : cu_(cu) {
dump_cfg_folder_ = "/sdcard/";
// If need be, create the default passes.
@@ -39,7 +52,7 @@
pass_map_.clear();
}
-void PassDriver::InsertPass(Pass* new_pass, bool warn_override) {
+void PassDriver::InsertPass(const Pass* new_pass, bool warn_override) {
assert(new_pass != 0);
// Get name here to not do it all over the method.
@@ -47,7 +60,7 @@
// Do we want to warn the user about squashing a pass?
if (warn_override == false) {
- SafeMap<std::string, Pass* >::iterator it = pass_map_.find(name);
+ auto it = pass_map_.find(name);
if (it != pass_map_.end()) {
LOG(INFO) << "Pass name " << name << " already used, overwriting pass";
@@ -71,16 +84,16 @@
* Disadvantage is the passes can't change their internal states depending on CompilationUnit:
* - This is not yet an issue: no current pass would require it.
*/
- static UniquePtr<Pass> *passes[] = {
- new UniquePtr<Pass>(new CodeLayout()),
- new UniquePtr<Pass>(new SSATransformation()),
- new UniquePtr<Pass>(new ConstantPropagation()),
- new UniquePtr<Pass>(new InitRegLocations()),
- new UniquePtr<Pass>(new MethodUseCount()),
- new UniquePtr<Pass>(new NullCheckEliminationAndTypeInferenceInit()),
- new UniquePtr<Pass>(new NullCheckEliminationAndTypeInference()),
- new UniquePtr<Pass>(new BBCombine()),
- new UniquePtr<Pass>(new BBOptimizations()),
+ static const Pass* passes[] = {
+ GetPassInstance<CodeLayout>(),
+ GetPassInstance<SSATransformation>(),
+ GetPassInstance<ConstantPropagation>(),
+ GetPassInstance<InitRegLocations>(),
+ GetPassInstance<MethodUseCount>(),
+ GetPassInstance<NullCheckEliminationAndTypeInferenceInit>(),
+ GetPassInstance<NullCheckEliminationAndTypeInference>(),
+ GetPassInstance<BBCombine>(),
+ GetPassInstance<BBOptimizations>(),
};
// Get number of elements in the array.
@@ -90,17 +103,17 @@
// - Map is used for the lookup
// - List is used for the pass walk
for (unsigned int i = 0; i < nbr; i++) {
- InsertPass(passes[i]->get());
+ InsertPass(passes[i]);
}
}
-void PassDriver::HandlePassFlag(CompilationUnit* c_unit, Pass* pass) {
+void PassDriver::HandlePassFlag(CompilationUnit* c_unit, const Pass* pass) {
// Unused parameters for the moment.
UNUSED(c_unit);
UNUSED(pass);
}
-void PassDriver::DispatchPass(CompilationUnit* c_unit, Pass* curPass) {
+void PassDriver::DispatchPass(CompilationUnit* c_unit, const Pass* curPass) {
DataflowIterator* iterator = 0;
LOG(DEBUG) << "Dispatching " << curPass->GetName();
@@ -147,13 +160,13 @@
}
}
-void PassDriver::ApplyPass(CompilationUnit* c_unit, Pass* curPass) {
+void PassDriver::ApplyPass(CompilationUnit* c_unit, const Pass* curPass) {
curPass->Start(c_unit);
DispatchPass(c_unit, curPass);
curPass->End(c_unit);
}
-bool PassDriver::RunPass(CompilationUnit* c_unit, Pass* curPass, bool time_split) {
+bool PassDriver::RunPass(CompilationUnit* c_unit, const Pass* curPass, bool time_split) {
// Paranoid: c_unit or curPass cannot be 0, and the pass should have a name.
if (c_unit == 0 || curPass == 0 || (strcmp(curPass->GetName(), "") == 0)) {
return false;
@@ -200,7 +213,7 @@
return false;
}
- Pass* curPass = GetPass(pass_name);
+ const Pass* curPass = GetPass(pass_name);
if (curPass != 0) {
return RunPass(c_unit, curPass);
@@ -211,8 +224,7 @@
}
void PassDriver::Launch() {
- for (std::list<Pass* >::iterator it = pass_list_.begin(); it != pass_list_.end(); it++) {
- Pass* curPass = *it;
+ for (const Pass *curPass : pass_list_) {
RunPass(cu_, curPass, true);
}
}
@@ -220,14 +232,13 @@
void PassDriver::PrintPassNames() const {
LOG(INFO) << "Loop Passes are:";
- for (std::list<Pass* >::const_iterator it = pass_list_.begin(); it != pass_list_.end(); it++) {
- const Pass* curPass = *it;
+ for (const Pass *curPass : pass_list_) {
LOG(INFO) << "\t-" << curPass->GetName();
}
}
-Pass* PassDriver::GetPass(const std::string& name) const {
- SafeMap<std::string, Pass*>::const_iterator it = pass_map_.find(name);
+const Pass* PassDriver::GetPass(const std::string& name) const {
+ auto it = pass_map_.find(name);
if (it != pass_map_.end()) {
return it->second;
diff --git a/compiler/dex/pass_driver.h b/compiler/dex/pass_driver.h
index 29da351..d580460 100644
--- a/compiler/dex/pass_driver.h
+++ b/compiler/dex/pass_driver.h
@@ -33,7 +33,7 @@
*/
class PassDriver {
public:
- explicit PassDriver(CompilationUnit* const cu, bool create_default_passes = true);
+ explicit PassDriver(CompilationUnit* cu, bool create_default_passes = true);
~PassDriver();
@@ -42,7 +42,7 @@
* @param new_pass the new Pass to insert in the map and list.
* @param warn_override warn if the name of the Pass is already used.
*/
- void InsertPass(Pass *new_pass, bool warn_override = true);
+ void InsertPass(const Pass* new_pass, bool warn_override = true);
/**
* @brief Run a pass using the name as key.
@@ -57,25 +57,25 @@
* @param time_split do we want a time split request(default: false)?
* @return whether the pass was applied.
*/
- bool RunPass(CompilationUnit* c_unit, Pass* pass, bool time_split = false);
+ bool RunPass(CompilationUnit* c_unit, const Pass* pass, bool time_split = false);
void Launch();
- void HandlePassFlag(CompilationUnit* c_unit, Pass* pass);
+ void HandlePassFlag(CompilationUnit* c_unit, const Pass* pass);
/**
* @brief Apply a patch: perform start/work/end functions.
*/
- void ApplyPass(CompilationUnit* c_unit, Pass* pass);
+ void ApplyPass(CompilationUnit* c_unit, const Pass* pass);
/**
* @brief Dispatch a patch: walk the BasicBlocks depending on the traversal mode
*/
- void DispatchPass(CompilationUnit* c_unit, Pass* pass);
+ void DispatchPass(CompilationUnit* c_unit, const Pass* pass);
void PrintPassNames() const;
- Pass* GetPass(const std::string& name) const;
+ const Pass* GetPass(const std::string& name) const;
const char *GetDumpCFGFolder() const {
return dump_cfg_folder_;
@@ -85,10 +85,10 @@
void CreatePasses();
/** @brief The Pass Map: contains name -> pass for quick lookup. */
- SafeMap<std::string, Pass*> pass_map_;
+ SafeMap<std::string, const Pass*> pass_map_;
/** @brief List of passes: provides the order to execute the passes. */
- std::list<Pass*> pass_list_;
+ std::list<const Pass*> pass_list_;
/** @brief The CompilationUnit on which to execute the passes on. */
CompilationUnit* const cu_;
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 5edc8b6..714dc4c 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -341,7 +341,7 @@
CompilerBackend compiler_backend, InstructionSet instruction_set,
InstructionSetFeatures instruction_set_features,
bool image, DescriptorSet* image_classes, size_t thread_count,
- bool dump_stats)
+ bool dump_stats, bool dump_passes, CumulativeLogger* timer)
: verified_methods_data_(verified_methods_data),
method_inliner_map_(method_inliner_map),
compiler_backend_(compiler_backend),
@@ -356,6 +356,8 @@
start_ns_(0),
stats_(new AOTCompilationStats),
dump_stats_(dump_stats),
+ dump_passes_(dump_passes),
+ timings_logger_(timer),
compiler_library_(NULL),
compiler_(NULL),
compiler_context_(NULL),
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 9e31624..aabdf2f 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -22,6 +22,7 @@
#include <vector>
#include "base/mutex.h"
+#include "base/timing_logger.h"
#include "class_reference.h"
#include "compiled_class.h"
#include "compiled_method.h"
@@ -97,7 +98,8 @@
CompilerBackend compiler_backend, InstructionSet instruction_set,
InstructionSetFeatures instruction_set_features,
bool image, DescriptorSet* image_classes,
- size_t thread_count, bool dump_stats);
+ size_t thread_count, bool dump_stats, bool dump_passes,
+ CumulativeLogger* timer);
~CompilerDriver();
@@ -267,6 +269,14 @@
return thread_count_;
}
+ bool GetDumpPasses() const {
+ return dump_passes_;
+ }
+
+ CumulativeLogger& GetTimingsLogger() const {
+ return *timings_logger_;
+ }
+
class PatchInformation {
public:
const DexFile& GetDexFile() const {
@@ -436,6 +446,9 @@
UniquePtr<AOTCompilationStats> stats_;
bool dump_stats_;
+ const bool dump_passes_;
+
+ CumulativeLogger* const timings_logger_;
typedef void (*CompilerCallbackFn)(CompilerDriver& driver);
typedef MutexLock* (*CompilerMutexLockFn)(CompilerDriver& driver);
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 2434262..12d8212 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -82,10 +82,11 @@
verified_methods_data_.reset(new VerifiedMethodsData);
method_inliner_map_.reset(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr);
callbacks_.Reset(verified_methods_data_.get(), method_inliner_map_.get());
+ CumulativeLogger timer("Compilation times");
compiler_driver_.reset(new CompilerDriver(verified_methods_data_.get(),
method_inliner_map_.get(),
compiler_backend, insn_set,
- insn_features, false, NULL, 2, true));
+ insn_features, false, NULL, 2, true, true, &timer));
jobject class_loader = NULL;
if (kCompile) {
TimingLogger timings("OatTest::WriteRead", false, false);
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 26fac23..20fafe2 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -249,7 +249,9 @@
bool image,
UniquePtr<CompilerDriver::DescriptorSet>& image_classes,
bool dump_stats,
- TimingLogger& timings) {
+ bool dump_passes,
+ TimingLogger& timings,
+ CumulativeLogger& compiler_phases_timings) {
// SirtRef and ClassLoader creation needs to come after Runtime::Create
jobject class_loader = NULL;
Thread* self = Thread::Current();
@@ -276,7 +278,9 @@
image,
image_classes.release(),
thread_count_,
- dump_stats));
+ dump_stats,
+ dump_passes,
+ &compiler_phases_timings));
if (compiler_backend_ == kPortable) {
driver->SetBitcodeFileName(bitcode_filename);
@@ -650,6 +654,7 @@
static int dex2oat(int argc, char** argv) {
TimingLogger timings("compiler", false, false);
+ CumulativeLogger compiler_phases_timings("compilation times");
InitLogging(argv);
@@ -703,6 +708,7 @@
bool is_host = false;
bool dump_stats = false;
bool dump_timing = false;
+ bool dump_passes = false;
bool dump_slow_timing = kIsDebugBuild;
bool watch_dog_enabled = !kIsTargetBuild;
@@ -796,6 +802,8 @@
runtime_args.push_back(argv[i]);
} else if (option == "--dump-timing") {
dump_timing = true;
+ } else if (option == "--dump-passes") {
+ dump_passes = true;
} else if (option == "--dump-stats") {
dump_stats = true;
} else {
@@ -1067,7 +1075,9 @@
image,
image_classes,
dump_stats,
- timings));
+ dump_passes,
+ timings,
+ compiler_phases_timings));
if (compiler.get() == NULL) {
LOG(ERROR) << "Failed to create oat file: " << oat_location;
@@ -1143,6 +1153,9 @@
if (dump_timing || (dump_slow_timing && timings.GetTotalNs() > MsToNs(1000))) {
LOG(INFO) << Dumpable<TimingLogger>(timings);
}
+ if (dump_passes) {
+ LOG(INFO) << Dumpable<CumulativeLogger>(compiler.get()->GetTimingsLogger());
+ }
return EXIT_SUCCESS;
}
@@ -1185,6 +1198,9 @@
if (dump_timing || (dump_slow_timing && timings.GetTotalNs() > MsToNs(1000))) {
LOG(INFO) << Dumpable<TimingLogger>(timings);
}
+ if (dump_passes) {
+ LOG(INFO) << Dumpable<CumulativeLogger>(compiler_phases_timings);
+ }
// Everything was successfully written, do an explicit exit here to avoid running Runtime
// destructors that take time (bug 10645725) unless we're a debug build or running on valgrind.
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 131ebf8..b1117a2 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -540,7 +540,8 @@
bool ClassLinker::GenerateOatFile(const char* dex_filename,
int oat_fd,
- const char* oat_cache_filename) {
+ const char* oat_cache_filename,
+ std::string* error_msg) {
Locks::mutator_lock_->AssertNotHeld(Thread::Current()); // Avoid starving GC.
std::string dex2oat_string(GetAndroidRoot());
dex2oat_string += (kIsDebugBuild ? "/bin/dex2oatd" : "/bin/dex2oat");
@@ -633,15 +634,13 @@
int status;
pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
if (got_pid != pid) {
- ScopedObjectAccess soa(Thread::Current());
- ThrowIOException("Failed to create oat file. Waitpid failed: wanted %d, got %d", pid,
- got_pid);
+ *error_msg = StringPrintf("Failed to create oat file. Waitpid failed: wanted %d, got %d",
+ pid, got_pid);
return false;
}
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
- ScopedObjectAccess soa(Thread::Current());
- ThrowIOException("Failed to create oat file. %s failed with dex-file '%s'", dex2oat,
- dex_filename);
+ *error_msg = StringPrintf("Failed to create oat file. %s failed with dex-file '%s'",
+ dex2oat, dex_filename);
return false;
}
}
@@ -827,10 +826,24 @@
<< oat_location << "': " << *error_msg;
error_msg->clear();
+ {
+ // We might have registered an outdated OatFile in FindDexFileInOatLocation().
+ // Get rid of it as its MAP_PRIVATE mapping may not reflect changes we're about to do.
+ WriterMutexLock mu(Thread::Current(), dex_lock_);
+ for (size_t i = 0; i < oat_files_.size(); ++i) {
+ if (oat_location == oat_files_[i]->GetLocation()) {
+ VLOG(class_linker) << "De-registering old OatFile: " << oat_location;
+ delete oat_files_[i];
+ oat_files_.erase(oat_files_.begin() + i);
+ break;
+ }
+ }
+ }
+
// Generate the output oat file for the dex file
VLOG(class_linker) << "Generating oat file " << oat_location << " for " << dex_location;
- if (!GenerateOatFile(dex_location, scoped_flock.GetFile().Fd(), oat_location)) {
- CHECK(Thread::Current()->IsExceptionPending());
+ if (!GenerateOatFile(dex_location, scoped_flock.GetFile().Fd(), oat_location, error_msg)) {
+ CHECK(!error_msg->empty());
return nullptr;
}
const OatFile* oat_file = OatFile::Open(oat_location, oat_location, NULL,
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index d468e1e..8722de3 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -251,7 +251,8 @@
// Generate an oat file from a dex file
bool GenerateOatFile(const char* dex_filename,
int oat_fd,
- const char* oat_cache_filename);
+ const char* oat_cache_filename,
+ std::string* error_msg);
LOCKS_EXCLUDED(Locks::mutator_lock_);
const OatFile* FindOatFileFromOatLocation(const std::string& location,
diff --git a/runtime/common_test.h b/runtime/common_test.h
index ee95d5b..a75a513 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -474,12 +474,13 @@
}
}
class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
+ CumulativeLogger timer("Compilation times");
compiler_driver_.reset(new CompilerDriver(verified_methods_data_.get(),
method_inliner_map_.get(),
compiler_backend, instruction_set,
instruction_set_features,
true, new CompilerDriver::DescriptorSet,
- 2, true));
+ 2, true, true, &timer));
}
// We typically don't generate an image in unit tests, disable this optimization by default.
compiler_driver_->SetSupportBootImageFixup(false);
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 39e838f..97b34ef 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -16,7 +16,7 @@
#include "mem_map.h"
-#include <backtrace/backtrace.h>
+#include <backtrace/BacktraceMap.h>
#include "base/stringprintf.h"
#include "ScopedFd.h"
@@ -32,12 +32,16 @@
#if !defined(NDEBUG)
-static std::ostream& operator<<(std::ostream& os, backtrace_map_info_t* rhs) {
- for (backtrace_map_info_t* m = rhs; m != NULL; m = m->next) {
- os << StringPrintf("0x%08x-0x%08x %c%c %s\n",
- static_cast<uint32_t>(m->start),
- static_cast<uint32_t>(m->end),
- m->is_readable ? 'r' : '-', m->is_executable ? 'x' : '-', m->name);
+static std::ostream& operator<<(
+ std::ostream& os,
+ std::pair<BacktraceMap::const_iterator, BacktraceMap::const_iterator> iters) {
+ for (BacktraceMap::const_iterator it = iters.first; it != iters.second; ++it) {
+ os << StringPrintf("0x%08x-0x%08x %c%c%c %s\n",
+ static_cast<uint32_t>(it->start),
+ static_cast<uint32_t>(it->end),
+ (it->flags & PROT_READ) ? 'r' : '-',
+ (it->flags & PROT_WRITE) ? 'w' : '-',
+ (it->flags & PROT_EXEC) ? 'x' : '-', it->name.c_str());
}
return os;
}
@@ -47,20 +51,24 @@
return;
}
- uint32_t base = reinterpret_cast<size_t>(addr);
- uint32_t limit = base + byte_count;
+ uintptr_t base = reinterpret_cast<uintptr_t>(addr);
+ uintptr_t limit = base + byte_count;
- backtrace_map_info_t* map_info_list = backtrace_create_map_info_list(getpid());
- for (backtrace_map_info_t* m = map_info_list; m != NULL; m = m->next) {
- CHECK(!(base >= m->start && base < m->end) // start of new within old
- && !(limit > m->start && limit < m->end) // end of new within old
- && !(base <= m->start && limit > m->end)) // start/end of new includes all of old
+ BacktraceMap map(getpid());
+ if (!map.Build()) {
+ PLOG(WARNING) << "Failed to build process map";
+ return;
+ }
+ for (BacktraceMap::const_iterator it = map.begin(); it != map.end(); ++it) {
+ CHECK(!(base >= it->start && base < it->end) // start of new within old
+ && !(limit > it->start && limit < it->end) // end of new within old
+ && !(base <= it->start && limit > it->end)) // start/end of new includes all of old
<< StringPrintf("Requested region 0x%08x-0x%08x overlaps with existing map 0x%08x-0x%08x (%s)\n",
base, limit,
- static_cast<uint32_t>(m->start), static_cast<uint32_t>(m->end), m->name)
- << map_info_list;
+ static_cast<uint32_t>(it->start), static_cast<uint32_t>(it->end),
+ it->name.c_str())
+ << std::make_pair(it, map.end());
}
- backtrace_destroy_map_info_list(map_info_list);
}
#else
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 600045f..45a2eed 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -120,7 +120,9 @@
outputName.c_str(), &error_msg);
}
if (dex_file == nullptr) {
- CHECK_EQ(env->ExceptionCheck(), JNI_TRUE);
+ ScopedObjectAccess soa(env);
+ CHECK(!error_msg.empty());
+ ThrowIOException("%s", error_msg.c_str());
return 0;
}
return static_cast<jint>(reinterpret_cast<uintptr_t>(dex_file));
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 2ad4c4a..a293043 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -16,6 +16,7 @@
#include "utils.h"
+#include <inttypes.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/syscall.h>
@@ -1035,17 +1036,17 @@
return "";
}
-static const char* CleanMapName(const char* map_name) {
- if (map_name == NULL) {
+static std::string CleanMapName(const backtrace_map_t* map) {
+ if (map == NULL || map->name.empty()) {
return "???";
}
// Turn "/usr/local/google/home/enh/clean-dalvik-dev/out/host/linux-x86/lib/libartd.so"
// into "libartd.so".
- const char* last_slash = strrchr(map_name, '/');
- if (last_slash != NULL) {
- map_name = last_slash + 1;
+ size_t last_slash = map->name.rfind('/');
+ if (last_slash == std::string::npos) {
+ return map->name;
}
- return map_name;
+ return map->name.substr(last_slash);
}
void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix, bool include_count) {
@@ -1058,25 +1059,24 @@
return;
}
- for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
+ for (Backtrace::const_iterator it = backtrace->begin();
+ it != backtrace->end(); ++it) {
// We produce output like this:
// ] #00 unwind_backtrace_thread+536 [0x55d75bb8] (libbacktrace.so)
- const backtrace_frame_data_t* frame = backtrace->GetFrame(i);
-
os << prefix;
if (include_count) {
- os << StringPrintf("#%02zu ", i);
+ os << StringPrintf("#%02zu ", it->num);
}
- if (frame->func_name) {
- os << frame->func_name;
+ if (!it->func_name.empty()) {
+ os << it->func_name;
} else {
os << "???";
}
- if (frame->func_offset != 0) {
- os << "+" << frame->func_offset;
+ if (it->func_offset != 0) {
+ os << "+" << it->func_offset;
}
- os << StringPrintf(" [%p]", reinterpret_cast<void*>(frame->pc));
- os << " (" << CleanMapName(frame->map_name) << ")\n";
+ os << StringPrintf(" [%p]", reinterpret_cast<void*>(it->pc));
+ os << " (" << CleanMapName(it->map) << ")\n";
}
}