Revert "Revert "Add JIT""

Added missing EntryPointToCodePointer.

This reverts commit a5ca888d715cd0c6c421313211caa1928be3e399.

Change-Id: Ia74df0ef3a7babbdcb0466fd24da28e304e3f5af
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
new file mode 100644
index 0000000..539c181
--- /dev/null
+++ b/runtime/jit/jit.cc
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2014 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 "jit.h"
+
+#include <dlfcn.h>
+
+#include "entrypoints/runtime_asm_entrypoints.h"
+#include "interpreter/interpreter.h"
+#include "jit_code_cache.h"
+#include "jit_instrumentation.h"
+#include "mirror/art_method-inl.h"
+#include "runtime.h"
+#include "runtime_options.h"
+#include "thread_list.h"
+#include "utils.h"
+
+namespace art {
+namespace jit {
+
+JitOptions* JitOptions::CreateFromRuntimeArguments(const RuntimeArgumentMap& options) {
+  if (!options.GetOrDefault(RuntimeArgumentMap::UseJIT)) {
+    return nullptr;
+  }
+  auto* jit_options = new JitOptions;
+  jit_options->code_cache_capacity_ =
+      options.GetOrDefault(RuntimeArgumentMap::JITCodeCacheCapacity);
+  jit_options->compile_threshold_ =
+      options.GetOrDefault(RuntimeArgumentMap::JITCompileThreshold);
+  return jit_options;
+}
+
+Jit::Jit()
+    : jit_library_handle_(nullptr), jit_compiler_handle_(nullptr), jit_load_(nullptr),
+      jit_compile_method_(nullptr) {
+}
+
+Jit* Jit::Create(JitOptions* options, std::string* error_msg) {
+  std::unique_ptr<Jit> jit(new Jit);
+  if (!jit->LoadCompiler(error_msg)) {
+    return nullptr;
+  }
+  jit->code_cache_.reset(JitCodeCache::Create(options->GetCodeCacheCapacity(), error_msg));
+  if (jit->GetCodeCache() == nullptr) {
+    return nullptr;
+  }
+  LOG(INFO) << "JIT created with code_cache_capacity="
+      << PrettySize(options->GetCodeCacheCapacity())
+      << " compile_threshold=" << options->GetCompileThreshold();
+  return jit.release();
+}
+
+bool Jit::LoadCompiler(std::string* error_msg) {
+  jit_library_handle_ = dlopen(
+      kIsDebugBuild ? "libartd-compiler.so" : "libart-compiler.so", RTLD_NOW);
+  if (jit_library_handle_ == nullptr) {
+    std::ostringstream oss;
+    oss << "JIT could not load libart-compiler.so: " << dlerror();
+    *error_msg = oss.str();
+    return false;
+  }
+  jit_load_ = reinterpret_cast<void* (*)(CompilerCallbacks**)>(
+      dlsym(jit_library_handle_, "jit_load"));
+  if (jit_load_ == nullptr) {
+    dlclose(jit_library_handle_);
+    *error_msg = "JIT couldn't find jit_load entry point";
+    return false;
+  }
+  jit_unload_ = reinterpret_cast<void (*)(void*)>(
+      dlsym(jit_library_handle_, "jit_unload"));
+  if (jit_unload_ == nullptr) {
+    dlclose(jit_library_handle_);
+    *error_msg = "JIT couldn't find jit_unload entry point";
+    return false;
+  }
+  jit_compile_method_ = reinterpret_cast<bool (*)(void*, mirror::ArtMethod*, Thread*)>(
+      dlsym(jit_library_handle_, "jit_compile_method"));
+  if (jit_compile_method_ == nullptr) {
+    dlclose(jit_library_handle_);
+    *error_msg = "JIT couldn't find jit_compile_method entry point";
+    return false;
+  }
+  CompilerCallbacks* callbacks = nullptr;
+  VLOG(jit) << "Calling JitLoad interpreter_only="
+      << Runtime::Current()->GetInstrumentation()->InterpretOnly();
+  jit_compiler_handle_ = (jit_load_)(&callbacks);
+  if (jit_compiler_handle_ == nullptr) {
+    dlclose(jit_library_handle_);
+    *error_msg = "JIT couldn't load compiler";
+    return false;
+  }
+  if (callbacks == nullptr) {
+    dlclose(jit_library_handle_);
+    *error_msg = "JIT compiler callbacks were not set";
+    jit_compiler_handle_ = nullptr;
+    return false;
+  }
+  compiler_callbacks_ = callbacks;
+  return true;
+}
+
+bool Jit::CompileMethod(mirror::ArtMethod* method, Thread* self) {
+  DCHECK(!method->IsRuntimeMethod());
+  const bool result = jit_compile_method_(jit_compiler_handle_, method, self);
+  if (result) {
+    method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
+  }
+  return result;
+}
+
+void Jit::CreateThreadPool() {
+  CHECK(instrumentation_cache_.get() != nullptr);
+  instrumentation_cache_->CreateThreadPool();
+}
+
+void Jit::DeleteThreadPool() {
+  if (instrumentation_cache_.get() != nullptr) {
+    instrumentation_cache_->DeleteThreadPool();
+  }
+}
+
+Jit::~Jit() {
+  DeleteThreadPool();
+  if (jit_compiler_handle_ != nullptr) {
+    jit_unload_(jit_compiler_handle_);
+  }
+  if (jit_library_handle_ != nullptr) {
+    dlclose(jit_library_handle_);
+  }
+}
+
+void Jit::CreateInstrumentationCache(size_t compile_threshold) {
+  CHECK_GT(compile_threshold, 0U);
+  Runtime* const runtime = Runtime::Current();
+  runtime->GetThreadList()->SuspendAll();
+  // Add Jit interpreter instrumentation, tells the interpreter when to notify the jit to compile
+  // something.
+  instrumentation_cache_.reset(new jit::JitInstrumentationCache(compile_threshold));
+  runtime->GetInstrumentation()->AddListener(
+      new jit::JitInstrumentationListener(instrumentation_cache_.get()),
+      instrumentation::Instrumentation::kMethodEntered |
+      instrumentation::Instrumentation::kBackwardBranch);
+  runtime->GetThreadList()->ResumeAll();
+}
+
+}  // namespace jit
+}  // namespace art
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
new file mode 100644
index 0000000..b80015f
--- /dev/null
+++ b/runtime/jit/jit.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2014 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_RUNTIME_JIT_JIT_H_
+#define ART_RUNTIME_JIT_JIT_H_
+
+#include <unordered_map>
+
+#include "instrumentation.h"
+
+#include "atomic.h"
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "gc_root.h"
+#include "jni.h"
+#include "object_callbacks.h"
+#include "thread_pool.h"
+
+namespace art {
+
+class CompilerCallbacks;
+struct RuntimeArgumentMap;
+
+namespace jit {
+
+class JitCodeCache;
+class JitInstrumentationCache;
+class JitOptions;
+
+class Jit {
+ public:
+  static constexpr bool kStressMode = kIsDebugBuild;
+  static constexpr size_t kDefaultCompileThreshold = kStressMode ? 1 : 1000;
+
+  virtual ~Jit();
+  static Jit* Create(JitOptions* options, std::string* error_msg);
+  bool CompileMethod(mirror::ArtMethod* method, Thread* self)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void CreateInstrumentationCache(size_t compile_threshold);
+  void CreateThreadPool();
+  CompilerCallbacks* GetCompilerCallbacks() {
+    return compiler_callbacks_;
+  }
+  const JitCodeCache* GetCodeCache() const {
+    return code_cache_.get();
+  }
+  JitCodeCache* GetCodeCache() {
+    return code_cache_.get();
+  }
+  void DeleteThreadPool();
+
+ private:
+  Jit();
+  bool LoadCompiler(std::string* error_msg);
+
+  // JIT compiler
+  void* jit_library_handle_;
+  void* jit_compiler_handle_;
+  void* (*jit_load_)(CompilerCallbacks**);
+  void (*jit_unload_)(void*);
+  bool (*jit_compile_method_)(void*, mirror::ArtMethod*, Thread*);
+
+  std::unique_ptr<jit::JitInstrumentationCache> instrumentation_cache_;
+  std::unique_ptr<jit::JitCodeCache> code_cache_;
+  CompilerCallbacks* compiler_callbacks_;  // Owned by the jit compiler.
+};
+
+class JitOptions {
+ public:
+  static JitOptions* CreateFromRuntimeArguments(const RuntimeArgumentMap& options);
+  size_t GetCompileThreshold() const {
+    return compile_threshold_;
+  }
+  size_t GetCodeCacheCapacity() const {
+    return code_cache_capacity_;
+  }
+
+ private:
+  size_t code_cache_capacity_;
+  size_t compile_threshold_;
+
+  JitOptions() : code_cache_capacity_(0), compile_threshold_(0) {
+  }
+};
+
+}  // namespace jit
+}  // namespace art
+
+#endif  // ART_RUNTIME_JIT_JIT_H_
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
new file mode 100644
index 0000000..8d4965e
--- /dev/null
+++ b/runtime/jit/jit_code_cache.cc
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2014 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 "jit_code_cache.h"
+
+#include <sstream>
+
+#include "mem_map.h"
+#include "mirror/art_method-inl.h"
+#include "oat_file-inl.h"
+
+namespace art {
+namespace jit {
+
+JitCodeCache* JitCodeCache::Create(size_t capacity, std::string* error_msg) {
+  CHECK_GT(capacity, 0U);
+  CHECK_LT(capacity, kMaxCapacity);
+  std::string error_str;
+  // Map name specific for android_os_Debug.cpp accounting.
+  MemMap* map = MemMap::MapAnonymous("jit-code-cache", nullptr, capacity,
+                                     PROT_READ | PROT_WRITE | PROT_EXEC, false, &error_str);
+  if (map == nullptr) {
+    std::ostringstream oss;
+    oss << "Failed to create read write execute cache: " << error_str << " size=" << capacity;
+    *error_msg = oss.str();
+    return nullptr;
+  }
+  return new JitCodeCache(map);
+}
+
+JitCodeCache::JitCodeCache(MemMap* mem_map)
+    : lock_("Jit code cache", kJitCodeCacheLock), num_methods_(0) {
+  VLOG(jit) << "Created jit code cache size=" << PrettySize(mem_map->Size());
+  mem_map_.reset(mem_map);
+  uint8_t* divider = mem_map->Begin() + RoundUp(mem_map->Size() / 4, kPageSize);
+  // Data cache is 1 / 4 of the map. TODO: Make this variable?
+  // Put data at the start.
+  data_cache_ptr_ = mem_map->Begin();
+  data_cache_end_ = divider;
+  data_cache_begin_ = data_cache_ptr_;
+  mprotect(data_cache_ptr_, data_cache_end_ - data_cache_begin_, PROT_READ | PROT_WRITE);
+  // Code cache after.
+  code_cache_begin_ = divider;
+  code_cache_ptr_ = divider;
+  code_cache_end_ = mem_map->End();
+}
+
+bool JitCodeCache::ContainsMethod(mirror::ArtMethod* method) const {
+  return ContainsCodePtr(method->GetEntryPointFromQuickCompiledCode());
+}
+
+bool JitCodeCache::ContainsCodePtr(const void* ptr) const {
+  return ptr >= code_cache_begin_ && ptr < code_cache_end_;
+}
+
+void JitCodeCache::FlushInstructionCache() {
+  UNIMPLEMENTED(FATAL);
+  // TODO: Investigate if we need to do this.
+  // __clear_cache(reinterpret_cast<char*>(code_cache_begin_), static_cast<int>(CodeCacheSize()));
+}
+
+uint8_t* JitCodeCache::ReserveCode(Thread* self, size_t size) {
+  MutexLock mu(self, lock_);
+  if (size > CodeCacheRemain()) {
+    return nullptr;
+  }
+  code_cache_ptr_ += size;
+  return code_cache_ptr_ - size;
+}
+
+uint8_t* JitCodeCache::AddDataArray(Thread* self, const uint8_t* begin, const uint8_t* end) {
+  MutexLock mu(self, lock_);
+  const size_t size = end - begin;
+  if (size > DataCacheRemain()) {
+    return nullptr;  // Out of space in the data cache.
+  }
+  std::copy(begin, end, data_cache_ptr_);
+  data_cache_ptr_ += size;
+  return data_cache_ptr_ - size;
+}
+
+const void* JitCodeCache::GetCodeFor(mirror::ArtMethod* method) {
+  const void* code = method->GetEntryPointFromQuickCompiledCode();
+  if (ContainsCodePtr(code)) {
+    return code;
+  }
+  MutexLock mu(Thread::Current(), lock_);
+  auto it = method_code_map_.find(method);
+  if (it != method_code_map_.end()) {
+    return it->second;
+  }
+  return nullptr;
+}
+
+void JitCodeCache::SaveCompiledCode(mirror::ArtMethod* method, const void* old_code_ptr) {
+  DCHECK_EQ(method->GetEntryPointFromQuickCompiledCode(), old_code_ptr);
+  DCHECK(ContainsCodePtr(old_code_ptr)) << PrettyMethod(method) << " old_code_ptr="
+      << old_code_ptr;
+  MutexLock mu(Thread::Current(), lock_);
+  auto it = method_code_map_.find(method);
+  if (it != method_code_map_.end()) {
+    return;
+  }
+  method_code_map_.Put(method, old_code_ptr);
+}
+
+}  // namespace jit
+}  // namespace art
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
new file mode 100644
index 0000000..aa8c717
--- /dev/null
+++ b/runtime/jit/jit_code_cache.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2014 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_RUNTIME_JIT_JIT_CODE_CACHE_H_
+#define ART_RUNTIME_JIT_JIT_CODE_CACHE_H_
+
+#include "instrumentation.h"
+
+#include "atomic.h"
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "gc_root.h"
+#include "jni.h"
+#include "oat_file.h"
+#include "object_callbacks.h"
+#include "safe_map.h"
+#include "thread_pool.h"
+
+namespace art {
+
+class CompiledMethod;
+class CompilerCallbacks;
+
+namespace mirror {
+class ArtMethod;
+}  // namespcae mirror
+
+namespace jit {
+
+class JitInstrumentationCache;
+
+class JitCodeCache {
+ public:
+  static constexpr size_t kMaxCapacity = 1 * GB;
+  static constexpr size_t kDefaultCapacity = 2 * MB;
+
+  static JitCodeCache* Create(size_t capacity, std::string* error_msg);
+
+  const uint8_t* CodeCachePtr() const {
+    return code_cache_ptr_;
+  }
+  size_t CodeCacheSize() const {
+    return code_cache_ptr_ - code_cache_begin_;
+  }
+  size_t CodeCacheRemain() const {
+    return code_cache_end_ - code_cache_ptr_;
+  }
+  size_t DataCacheSize() const {
+    return data_cache_ptr_ - data_cache_begin_;
+  }
+  size_t DataCacheRemain() const {
+    return data_cache_end_ - data_cache_ptr_;
+  }
+  size_t NumMethods() const {
+    return num_methods_;
+  }
+
+  bool ContainsMethod(mirror::ArtMethod* method) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  bool ContainsCodePtr(const void* ptr) const;
+
+  uint8_t* ReserveCode(Thread* self, size_t size) LOCKS_EXCLUDED(lock_);
+
+  uint8_t* AddDataArray(Thread* self, const uint8_t* begin, const uint8_t* end)
+      LOCKS_EXCLUDED(lock_);
+
+  // Get code for a method, returns null if it is not in the jit cache.
+  const void* GetCodeFor(mirror::ArtMethod* method)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
+
+  void SaveCompiledCode(mirror::ArtMethod* method, const void* old_code_ptr)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
+
+ private:
+  // Takes ownership of code_mem_map.
+  explicit JitCodeCache(MemMap* code_mem_map);
+  void FlushInstructionCache();
+
+  Mutex lock_;
+  // Mem map which holds code and data. We do this since we need to have 32 bit offsets from method
+  // headers in code cache which point to things in the data cache. If the maps are more than 4GB
+  // apart, having multiple maps wouldn't work.
+  std::unique_ptr<MemMap> mem_map_;
+  // Code cache section.
+  uint8_t* code_cache_ptr_;
+  const uint8_t* code_cache_begin_;
+  const uint8_t* code_cache_end_;
+  // Data cache section.
+  uint8_t* data_cache_ptr_;
+  const uint8_t* data_cache_begin_;
+  const uint8_t* data_cache_end_;
+  size_t num_methods_;
+  // TODO: This relies on methods not moving.
+  // This map holds code for methods if they were deoptimized by the instrumentation stubs. This is
+  // required since we have to implement ClassLinker::GetQuickOatCodeFor for walking stacks.
+  SafeMap<mirror::ArtMethod*, const void*> method_code_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(JitCodeCache);
+};
+
+
+}  // namespace jit
+}  // namespace art
+
+#endif  // ART_RUNTIME_JIT_JIT_CODE_CACHE_H_
diff --git a/runtime/jit/jit_instrumentation.cc b/runtime/jit/jit_instrumentation.cc
new file mode 100644
index 0000000..160e678
--- /dev/null
+++ b/runtime/jit/jit_instrumentation.cc
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2014 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 "jit_instrumentation.h"
+
+#include "jit.h"
+#include "jit_code_cache.h"
+#include "mirror/art_method-inl.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+namespace jit {
+
+class JitCompileTask : public Task {
+ public:
+  explicit JitCompileTask(mirror::ArtMethod* method, JitInstrumentationCache* cache)
+      : method_(method), cache_(cache) {
+  }
+
+  virtual void Run(Thread* self) OVERRIDE {
+    ScopedObjectAccess soa(self);
+    VLOG(jit) << "JitCompileTask compiling method " << PrettyMethod(method_);
+    if (Runtime::Current()->GetJit()->CompileMethod(method_, self)) {
+      cache_->SignalCompiled(self, method_);
+    } else {
+      VLOG(jit) << "Failed to compile method " << PrettyMethod(method_);
+    }
+  }
+
+  virtual void Finalize() OVERRIDE {
+    delete this;
+  }
+
+ private:
+  mirror::ArtMethod* const method_;
+  JitInstrumentationCache* const cache_;
+};
+
+JitInstrumentationCache::JitInstrumentationCache(size_t hot_method_threshold)
+    : lock_("jit instrumentation lock"), hot_method_threshold_(hot_method_threshold) {
+}
+
+void JitInstrumentationCache::CreateThreadPool() {
+  thread_pool_.reset(new ThreadPool("Jit thread pool", 1));
+}
+
+void JitInstrumentationCache::DeleteThreadPool() {
+  thread_pool_.reset();
+}
+
+void JitInstrumentationCache::SignalCompiled(Thread* self, mirror::ArtMethod* method) {
+  ScopedObjectAccessUnchecked soa(self);
+  jmethodID method_id = soa.EncodeMethod(method);
+  MutexLock mu(self, lock_);
+  auto it = samples_.find(method_id);
+  if (it != samples_.end()) {
+    samples_.erase(it);
+  }
+}
+
+void JitInstrumentationCache::AddSamples(Thread* self, mirror::ArtMethod* method, size_t count) {
+  ScopedObjectAccessUnchecked soa(self);
+  // Since we don't have on-stack replacement, some methods can remain in the interpreter longer
+  // than we want resulting in samples even after the method is compiled.
+  if (method->IsClassInitializer() ||
+      Runtime::Current()->GetJit()->GetCodeCache()->ContainsMethod(method)) {
+    return;
+  }
+  jmethodID method_id = soa.EncodeMethod(method);
+  bool is_hot = false;
+  {
+    MutexLock mu(self, lock_);
+    size_t sample_count = 0;
+    auto it = samples_.find(method_id);
+    if (it != samples_.end()) {
+      it->second += count;
+      sample_count = it->second;
+    } else {
+      sample_count = count;
+      samples_.insert(std::make_pair(method_id, count));
+    }
+    // If we have enough samples, mark as hot and request Jit compilation.
+    if (sample_count >= hot_method_threshold_ && sample_count - count < hot_method_threshold_) {
+      is_hot = true;
+    }
+  }
+  if (is_hot) {
+    if (thread_pool_.get() != nullptr) {
+      thread_pool_->AddTask(self, new JitCompileTask(method->GetInterfaceMethodIfProxy(), this));
+      thread_pool_->StartWorkers(self);
+    } else {
+      VLOG(jit) << "Compiling hot method " << PrettyMethod(method);
+      Runtime::Current()->GetJit()->CompileMethod(method->GetInterfaceMethodIfProxy(), self);
+    }
+  }
+}
+
+JitInstrumentationListener::JitInstrumentationListener(JitInstrumentationCache* cache)
+    : instrumentation_cache_(cache) {
+  CHECK(instrumentation_cache_ != nullptr);
+}
+
+}  // namespace jit
+}  // namespace art
diff --git a/runtime/jit/jit_instrumentation.h b/runtime/jit/jit_instrumentation.h
new file mode 100644
index 0000000..9576f4b
--- /dev/null
+++ b/runtime/jit/jit_instrumentation.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2014 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_RUNTIME_JIT_JIT_INSTRUMENTATION_H_
+#define ART_RUNTIME_JIT_JIT_INSTRUMENTATION_H_
+
+#include <unordered_map>
+
+#include "instrumentation.h"
+
+#include "atomic.h"
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "gc_root.h"
+#include "jni.h"
+#include "object_callbacks.h"
+#include "thread_pool.h"
+
+namespace art {
+namespace mirror {
+  class ArtField;
+  class ArtMethod;
+  class Class;
+  class Object;
+  class Throwable;
+}  // namespace mirror
+union JValue;
+class Thread;
+class ThrowLocation;
+
+namespace jit {
+
+// Keeps track of which methods are hot.
+class JitInstrumentationCache {
+ public:
+  explicit JitInstrumentationCache(size_t hot_method_threshold);
+  void AddSamples(Thread* self, mirror::ArtMethod* method, size_t samples)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void SignalCompiled(Thread* self, mirror::ArtMethod* method)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void CreateThreadPool();
+  void DeleteThreadPool();
+
+ private:
+  Mutex lock_;
+  std::unordered_map<jmethodID, size_t> samples_;
+  size_t hot_method_threshold_;
+  std::unique_ptr<ThreadPool> thread_pool_;
+};
+
+class JitInstrumentationListener : public instrumentation::InstrumentationListener {
+ public:
+  explicit JitInstrumentationListener(JitInstrumentationCache* cache);
+
+  virtual void MethodEntered(Thread* thread, mirror::Object* /*this_object*/,
+                             mirror::ArtMethod* method, uint32_t /*dex_pc*/)
+      OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    instrumentation_cache_->AddSamples(thread, method, 1);
+  }
+  virtual void MethodExited(Thread* /*thread*/, mirror::Object* /*this_object*/,
+                            mirror::ArtMethod* /*method*/, uint32_t /*dex_pc*/,
+                            const JValue& /*return_value*/)
+      OVERRIDE { }
+  virtual void MethodUnwind(Thread* /*thread*/, mirror::Object* /*this_object*/,
+                            mirror::ArtMethod* /*method*/, uint32_t /*dex_pc*/) OVERRIDE { }
+  virtual void FieldRead(Thread* /*thread*/, mirror::Object* /*this_object*/,
+                         mirror::ArtMethod* /*method*/, uint32_t /*dex_pc*/,
+                         mirror::ArtField* /*field*/) OVERRIDE { }
+  virtual void FieldWritten(Thread* /*thread*/, mirror::Object* /*this_object*/,
+                            mirror::ArtMethod* /*method*/, uint32_t /*dex_pc*/,
+                            mirror::ArtField* /*field*/, const JValue& /*field_value*/)
+      OVERRIDE { }
+  virtual void ExceptionCaught(Thread* /*thread*/, const ThrowLocation& /*throw_location*/,
+                               mirror::ArtMethod* /*catch_method*/, uint32_t /*catch_dex_pc*/,
+                               mirror::Throwable* /*exception_object*/) OVERRIDE { }
+
+  virtual void DexPcMoved(Thread* /*self*/, mirror::Object* /*this_object*/,
+                          mirror::ArtMethod* /*method*/, uint32_t /*new_dex_pc*/) OVERRIDE { }
+
+  // We only care about how many dex instructions were executed in the Jit.
+  virtual void BackwardBranch(Thread* thread, mirror::ArtMethod* method, int32_t dex_pc_offset)
+      OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    CHECK_LE(dex_pc_offset, 0);
+    instrumentation_cache_->AddSamples(thread, method, 1);
+  }
+
+ private:
+  JitInstrumentationCache* const instrumentation_cache_;
+};
+
+}  // namespace jit
+}  // namespace art
+
+#endif  // ART_RUNTIME_JIT_JIT_INSTRUMENTATION_H_