summaryrefslogtreecommitdiffstats
path: root/runtime/jit
diff options
context:
space:
mode:
authorMathieu Chartier <mathieuc@google.com>2015-02-24 09:37:21 -0800
committerMathieu Chartier <mathieuc@google.com>2015-02-24 10:47:02 -0800
commite5f13e57ff8fa36342beb33830b3ec5942a61cca (patch)
tree02e370ecc4e0d955f28bfc71a41015f94fbb19b7 /runtime/jit
parent354d58ba776866ea7b1c71f0d0848d5aaa013ae3 (diff)
downloadart-e5f13e57ff8fa36342beb33830b3ec5942a61cca.zip
art-e5f13e57ff8fa36342beb33830b3ec5942a61cca.tar.gz
art-e5f13e57ff8fa36342beb33830b3ec5942a61cca.tar.bz2
Revert "Revert "Add JIT""
Added missing EntryPointToCodePointer. This reverts commit a5ca888d715cd0c6c421313211caa1928be3e399. Change-Id: Ia74df0ef3a7babbdcb0466fd24da28e304e3f5af
Diffstat (limited to 'runtime/jit')
-rw-r--r--runtime/jit/jit.cc160
-rw-r--r--runtime/jit/jit.h102
-rw-r--r--runtime/jit/jit_code_cache.cc121
-rw-r--r--runtime/jit/jit_code_cache.h118
-rw-r--r--runtime/jit/jit_instrumentation.cc117
-rw-r--r--runtime/jit/jit_instrumentation.h107
6 files changed, 725 insertions, 0 deletions
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_