Add JIT

Currently disabled by default unless -Xjit is passed in.

The proposed JIT is a method JIT which works by utilizing interpreter
instrumentation to request compilation of hot methods async during
runtime.

JIT options:
-Xjit / -Xnojit
-Xjitcodecachesize:N
-Xjitthreshold:integervalue

The JIT has a shared copy of a compiler driver which is accessed
by worker threads to compile individual methods.

Added JIT code cache and data cache, currently sized at 2 MB
capacity by default. Most apps will only fill a small fraction of
this cache however.

Added support to the compiler for compiling interpreter quickened
byte codes.

Added test target ART_TEST_JIT=TRUE and --jit for run-test.

TODO:
Clean up code cache.
Delete compiled methods after they are added to code cache.
Add more optimizations related to runtime checks e.g. direct pointers
for invokes.
Add method recompilation.
Move instrumentation to DexFile to improve performance and reduce
memory usage.

Bug: 17950037

Change-Id: Ifa5b2684a2d5059ec5a5210733900aafa3c51bca
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