Added code to allow method tracing from command line.

Crated a set of command line switches to allow method tracing to be
enabled from the command line. They are -Xmethod-trace,
-Xmethod-trace-file, and -Xmethod-trace-file-size.

Change-Id: I7ecaa07aba3d7ca41f2ff3a9a9341d97833afe36
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 06ae301..6ab849a 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1397,7 +1397,15 @@
   const void* trampoline = Runtime::Current()->GetResolutionStubArray(Runtime::kStaticMethod)->GetData();
   for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) {
     Method* method = klass->GetDirectMethod(i);
-    if (method->GetCode() == trampoline) {
+    if (Runtime::Current()->IsMethodTracingActive()) {
+      Trace* tracer = Runtime::Current()->GetTracer();
+      if (tracer->GetSavedCodeFromMap(method) == trampoline) {
+        const void* code = oat_class->GetOatMethod(method_index).GetCode();
+        tracer->ResetSavedCode(method);
+        method->SetCode(code);
+        tracer->SaveAndUpdateCode(method);
+      }
+    } else if (method->GetCode() == trampoline) {
       const void* code = oat_class->GetOatMethod(method_index).GetCode();
       CHECK(code != NULL);
       method->SetCode(code);
@@ -1428,13 +1436,8 @@
   }
 
   if (Runtime::Current()->IsMethodTracingActive()) {
-#if defined(__arm__)
     Trace* tracer = Runtime::Current()->GetTracer();
-    void* trace_stub = reinterpret_cast<void*>(art_trace_entry_from_code);
-    tracer->SaveAndUpdateCode(method.get(), trace_stub);
-#else
-    UNIMPLEMENTED(WARNING);
-#endif
+    tracer->SaveAndUpdateCode(method.get());
   }
 }
 
diff --git a/src/runtime.cc b/src/runtime.cc
index c53ede1..96c4451 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -38,6 +38,7 @@
 #include "space.h"
 #include "thread.h"
 #include "thread_list.h"
+#include "trace.h"
 #include "UniquePtr.h"
 
 // TODO: this drags in cutil/log.h, which conflicts with our logging.h.
@@ -81,6 +82,10 @@
 Runtime::~Runtime() {
   shutting_down_ = true;
 
+  if (IsMethodTracingActive()) {
+    Trace::Shutdown();
+  }
+
   Dbg::StopJdwp();
 
   // Make sure our internal threads are dead before we start tearing down things they're using.
@@ -310,6 +315,10 @@
 //  gLogVerbosity.third_party_jni = true; // TODO: don't check this in!
 //  gLogVerbosity.threads = true; // TODO: don't check this in!
 
+  parsed->method_trace_ = false;
+  parsed->method_trace_file_ = "/data/method-trace-file.bin";
+  parsed->method_trace_file_size_ = 10 * MB;
+
   for (size_t i = 0; i < options.size(); ++i) {
     const std::string option(options[i].first);
     if (true && options[0].first == "-Xzygote") {
@@ -442,6 +451,12 @@
       parsed->host_prefix_ = reinterpret_cast<const char*>(options[i].second);
     } else if (option == "-Xgenregmap" || option == "-Xgc:precise") {
       // We silently ignore these for backwards compatibility.
+    } else if (option == "-Xmethod-trace") {
+      parsed->method_trace_ = true;
+    } else if (StartsWith(option, "-Xmethod-trace-file:")) {
+      parsed->method_trace_file_ = option.substr(strlen("-Xmethod-trace-file:"));
+    } else if (StartsWith(option, "-Xmethod-trace-file-size:")) {
+      parsed->method_trace_file_size_ = ParseIntegerOrDie(option);
     } else {
       if (!ignore_unrecognized) {
         // TODO: print usage via vfprintf
@@ -651,6 +666,14 @@
   }
   CHECK(class_linker_ != NULL);
 
+  method_trace_ = options->method_trace_;
+  method_trace_file_ = options->method_trace_file_;
+  method_trace_file_size_ = options->method_trace_file_size_;
+
+  if (options->method_trace_) {
+    Trace::Start(options->method_trace_file_.c_str(), -1, options->method_trace_file_size_, 0, false);
+  }
+
   VLOG(startup) << "Runtime::Init exiting";
   return true;
 }
diff --git a/src/runtime.h b/src/runtime.h
index a2ec08e..4bbe54e 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -77,6 +77,9 @@
     size_t jni_globals_max_;
     size_t lock_profiling_threshold_;
     std::string stack_trace_file_;
+    bool method_trace_;
+    std::string method_trace_file_;
+    size_t method_trace_file_size_;
     bool (*hook_is_sensitive_thread_)();
     jint (*hook_vfprintf_)(FILE* stream, const char* format, va_list ap);
     void (*hook_exit_)(jint status);
@@ -321,6 +324,9 @@
   bool stats_enabled_;
   RuntimeStats stats_;
 
+  bool method_trace_;
+  std::string method_trace_file_;
+  size_t method_trace_file_size_;
   Trace* tracer_;
 
   typedef std::map<const ClassLoader*, std::vector<const DexFile*> > CompileTimeClassPaths;
diff --git a/src/trace.cc b/src/trace.cc
index b481b74..e4be356 100644
--- a/src/trace.cc
+++ b/src/trace.cc
@@ -108,26 +108,25 @@
   *buf++ = (uint8_t) (val >> 56);
 }
 
-#if defined(__arm__)
-static bool InstallStubsClassVisitor(Class* klass, void* trace_stub) {
+static bool InstallStubsClassVisitor(Class* klass, void*) {
   Trace* tracer = Runtime::Current()->GetTracer();
   for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
     Method* method = klass->GetDirectMethod(i);
-    if (method->GetCode() != trace_stub) {
-      tracer->SaveAndUpdateCode(method, trace_stub);
+    if (tracer->GetSavedCodeFromMap(method) == NULL) {
+      tracer->SaveAndUpdateCode(method);
     }
   }
 
   for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
     Method* method = klass->GetVirtualMethod(i);
-    if (method->GetCode() != trace_stub) {
-      tracer->SaveAndUpdateCode(method, trace_stub);
+    if (tracer->GetSavedCodeFromMap(method) == NULL) {
+      tracer->SaveAndUpdateCode(method);
     }
   }
   return true;
 }
 
-static bool UninstallStubsClassVisitor(Class* klass, void* trace_stub) {
+static bool UninstallStubsClassVisitor(Class* klass, void*) {
   Trace* tracer = Runtime::Current()->GetTracer();
   for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
     Method* method = klass->GetDirectMethod(i);
@@ -146,6 +145,7 @@
 }
 
 static void TraceRestoreStack(Thread* t, void*) {
+#if defined(__arm__)
   uintptr_t trace_exit = reinterpret_cast<uintptr_t>(art_trace_exit_from_code);
 
   Frame frame = t->GetTopOfStack();
@@ -163,8 +163,10 @@
       }
     }
   }
-}
+#else
+  UNIMPLEMENTED(WARNING);
 #endif
+}
 
 void Trace::AddSavedCodeToMap(const Method* method, const void* code) {
   saved_code_map_.insert(std::make_pair(method, code));
@@ -184,10 +186,15 @@
   }
 }
 
-void Trace::SaveAndUpdateCode(Method* method, const void* new_code) {
+void Trace::SaveAndUpdateCode(Method* method) {
+#if defined(__arm__)
+  void* trace_stub = reinterpret_cast<void*>(art_trace_entry_from_code);
   CHECK(GetSavedCodeFromMap(method) == NULL);
   AddSavedCodeToMap(method, method->GetCode());
-  method->SetCode(new_code);
+  method->SetCode(trace_stub);
+#else
+  UNIMPLEMENTED(WARNING);
+#endif
 }
 
 void Trace::ResetSavedCode(Method* method) {
@@ -214,7 +221,7 @@
       trace_file = OS::FileFromFd("tracefile", trace_fd);
     }
     if (trace_file == NULL) {
-      PLOG(ERROR) << "Unable to open trace file '" << trace_filename;
+      PLOG(ERROR) << "Unable to open trace file '" << trace_filename << "'";
       Thread::Current()->ThrowNewException("Ljava/lang/RuntimeException;",
           StringPrintf("Unable to open trace file '%s'", trace_filename).c_str());
       Runtime::Current()->GetThreadList()->ResumeAll(false);
@@ -245,6 +252,15 @@
   Runtime::Current()->GetThreadList()->ResumeAll(false);
 }
 
+void Trace::Shutdown() {
+  if (!Runtime::Current()->IsMethodTracingActive()) {
+    LOG(INFO) << "Trace shutdown requested, but no trace currently running";
+    return;
+  }
+  Runtime::Current()->GetTracer()->FinishTracing();
+  Runtime::Current()->DisableMethodTracing();
+}
+
 void Trace::BeginTracing() {
   // Set the start time of tracing.
   start_time_ = MicroTime();
@@ -406,27 +422,17 @@
 }
 
 void Trace::InstallStubs() {
-#if defined(__arm__)
-  void* trace_stub = reinterpret_cast<void*>(art_trace_entry_from_code);
-  Runtime::Current()->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, trace_stub);
-#else
-  UNIMPLEMENTED(WARNING);
-#endif
+  Runtime::Current()->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, NULL);
 }
 
 void Trace::UninstallStubs() {
-#if defined(__arm__)
-  void* trace_stub = reinterpret_cast<void*>(art_trace_entry_from_code);
-  Runtime::Current()->GetClassLinker()->VisitClasses(UninstallStubsClassVisitor, trace_stub);
+  Runtime::Current()->GetClassLinker()->VisitClasses(UninstallStubsClassVisitor, NULL);
 
   // Restore stacks of all threads
   {
     ScopedThreadListLock thread_list_lock;
     Runtime::Current()->GetThreadList()->ForEach(TraceRestoreStack, NULL);
   }
-#else
-  UNIMPLEMENTED(WARNING);
-#endif
 }
 
 }  // namespace art
diff --git a/src/trace.h b/src/trace.h
index c84e99e..d545b14 100644
--- a/src/trace.h
+++ b/src/trace.h
@@ -52,6 +52,7 @@
 
   static void Start(const char* trace_filename, int trace_fd, int buffer_size, int flags, bool direct_to_ddms);
   static void Stop();
+  static void Shutdown();
 
   void LogMethodTraceEvent(Thread* self, const Method* method, TraceEvent event);
 
@@ -59,7 +60,7 @@
   void RemoveSavedCodeFromMap(const Method* method);
   const void* GetSavedCodeFromMap(const Method* method);
 
-  void SaveAndUpdateCode(Method* method, const void* new_code);
+  void SaveAndUpdateCode(Method* method);
   void ResetSavedCode(Method* method);
 
  private: