Pulled out instrumentation into its own class separate from trace.

This is in preparation for Ian's debugger changes. The instrumentation
still needs support for debugging, which I'll add later.

Change-Id: I29ce0af1ff2eaec8f6d2f54963263381363ebf72
diff --git a/src/instrumentation.cc b/src/instrumentation.cc
new file mode 100644
index 0000000..d796aef
--- /dev/null
+++ b/src/instrumentation.cc
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#include "instrumentation.h"
+
+#include <sys/uio.h>
+
+#include "class_linker.h"
+#include "debugger.h"
+#include "dex_cache.h"
+#if !defined(ART_USE_LLVM_COMPILER)
+#include "oat/runtime/oat_support_entrypoints.h"
+#endif
+#include "object_utils.h"
+#include "os.h"
+#include "scoped_thread_state_change.h"
+#include "thread.h"
+#include "thread_list.h"
+#include "trace.h"
+
+namespace art {
+
+static bool InstallStubsClassVisitor(Class* klass, void*)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+  for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
+    AbstractMethod* method = klass->GetDirectMethod(i);
+    if (instrumentation->GetSavedCodeFromMap(method) == NULL) {
+      instrumentation->SaveAndUpdateCode(method);
+    }
+  }
+
+  for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
+    AbstractMethod* method = klass->GetVirtualMethod(i);
+    if (instrumentation->GetSavedCodeFromMap(method) == NULL) {
+      instrumentation->SaveAndUpdateCode(method);
+    }
+  }
+  return true;
+}
+
+static bool UninstallStubsClassVisitor(Class* klass, void*)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+  for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
+    AbstractMethod* method = klass->GetDirectMethod(i);
+    if (instrumentation->GetSavedCodeFromMap(method) != NULL) {
+      instrumentation->ResetSavedCode(method);
+    }
+  }
+
+  for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
+    AbstractMethod* method = klass->GetVirtualMethod(i);
+    if (instrumentation->GetSavedCodeFromMap(method) != NULL) {
+      instrumentation->ResetSavedCode(method);
+    }
+  }
+  return true;
+}
+
+static void InstrumentationRestoreStack(Thread* self, void*) NO_THREAD_SAFETY_ANALYSIS {
+  struct RestoreStackVisitor : public StackVisitor {
+    RestoreStackVisitor(Thread* self)
+        : StackVisitor(self->GetManagedStack(), self->GetInstrumentationStack(), NULL), self_(self) {}
+
+    virtual bool VisitFrame() {
+      if (self_->IsInstrumentationStackEmpty()) {
+        return false;  // Stop.
+      }
+      uintptr_t pc = GetReturnPc();
+      if (IsInstrumentationExitPc(pc)) {
+        InstrumentationStackFrame instrumentation_frame = self_->PopInstrumentationStackFrame();
+        SetReturnPc(instrumentation_frame.return_pc_);
+        CHECK(GetMethod() == instrumentation_frame.method_);
+      }
+      return true;  // Continue.
+    }
+
+    Thread* self_;
+  };
+  RestoreStackVisitor visitor(self);
+  visitor.WalkStack();
+}
+
+Instrumentation::~Instrumentation() {
+  delete trace_;
+}
+
+void Instrumentation::InstallStubs() {
+  Runtime::Current()->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, NULL);
+}
+
+void Instrumentation::UninstallStubs() {
+  Thread* self = Thread::Current();
+  Locks::thread_list_lock_->AssertNotHeld(self);
+  Runtime::Current()->GetClassLinker()->VisitClasses(UninstallStubsClassVisitor, NULL);
+  MutexLock mu(self, *Locks::thread_list_lock_);
+  Runtime::Current()->GetThreadList()->ForEach(InstrumentationRestoreStack, NULL);
+}
+
+void Instrumentation::AddSavedCodeToMap(const AbstractMethod* method, const void* code) {
+  saved_code_map_.Put(method, code);
+}
+
+void Instrumentation::RemoveSavedCodeFromMap(const AbstractMethod* method) {
+  saved_code_map_.erase(method);
+}
+
+const void* Instrumentation::GetSavedCodeFromMap(const AbstractMethod* method) {
+  typedef SafeMap<const AbstractMethod*, const void*>::const_iterator It; // TODO: C++0x auto
+  It it = saved_code_map_.find(method);
+  if (it == saved_code_map_.end()) {
+    return NULL;
+  } else {
+    return it->second;
+  }
+}
+
+void Instrumentation::SaveAndUpdateCode(AbstractMethod* method) {
+#if defined(ART_USE_LLVM_COMPILER)
+  UNUSED(method);
+  UNIMPLEMENTED(FATAL);
+#else
+  void* instrumentation_stub = GetInstrumentationEntryPoint();
+  CHECK(GetSavedCodeFromMap(method) == NULL);
+  AddSavedCodeToMap(method, method->GetCode());
+  method->SetCode(instrumentation_stub);
+#endif
+}
+
+void Instrumentation::ResetSavedCode(AbstractMethod* method) {
+  CHECK(GetSavedCodeFromMap(method) != NULL);
+  method->SetCode(GetSavedCodeFromMap(method));
+  RemoveSavedCodeFromMap(method);
+}
+
+Trace* Instrumentation::GetTrace() const {
+  return trace_;
+}
+
+void Instrumentation::SetTrace(Trace* trace) {
+  trace_ = trace;
+}
+
+void Instrumentation::RemoveTrace() {
+  delete trace_;
+  trace_ = NULL;
+}
+
+uint32_t InstrumentationMethodUnwindFromCode(Thread* self) {
+  Trace* trace = Runtime::Current()->GetInstrumentation()->GetTrace();
+  InstrumentationStackFrame instrumentation_frame = self->PopInstrumentationStackFrame();
+  AbstractMethod* method = instrumentation_frame.method_;
+  uint32_t lr = instrumentation_frame.return_pc_;
+
+  trace->LogMethodTraceEvent(self, method, Trace::kMethodTraceUnwind);
+
+  return lr;
+}
+
+}  // namespace art