Add option to never interpret.
Change-Id: Ib6d6170fa60c77c2e6a8844964f14fa0de4c9e7b
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index ecd4de9..6c9cc70 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -518,10 +518,10 @@
Dbg::IsForcedInterpreterNeededForCalling(self, target);
}
-static void ArtInterpreterToCompiledCodeBridge(Thread* self,
- const DexFile::CodeItem* code_item,
- ShadowFrame* shadow_frame,
- JValue* result)
+void ArtInterpreterToCompiledCodeBridge(Thread* self,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame,
+ JValue* result)
SHARED_REQUIRES(Locks::mutator_lock_) {
ArtMethod* method = shadow_frame->GetMethod();
// Ensure static methods are initialized.
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 932d255..949112d 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -980,6 +980,9 @@
return branch_offset <= 0;
}
+void ArtInterpreterToCompiledCodeBridge(Thread* self, const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result);
+
// Explicitly instantiate all DoInvoke functions.
#define EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, _is_range, _do_check) \
template SHARED_REQUIRES(Locks::mutator_lock_) \
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index ca00621..d50cfe6 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -21,6 +21,7 @@
#include "base/stl_util.h" // MakeUnique
#include "experimental_flags.h"
#include "interpreter_common.h"
+#include "jit/jit.h"
#include "safe_math.h"
#include <memory> // std::unique_ptr
@@ -183,9 +184,25 @@
self->AssertNoPendingException();
}
instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+ ArtMethod *method = shadow_frame.GetMethod();
+
if (UNLIKELY(instrumentation->HasMethodEntryListeners())) {
instrumentation->MethodEnterEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
- shadow_frame.GetMethod(), 0);
+ method, 0);
+ }
+
+ if (UNLIKELY(Runtime::Current()->GetJit() != nullptr &&
+ Runtime::Current()->GetJit()->JitAtFirstUse() &&
+ method->HasAnyCompiledCode())) {
+ JValue result;
+
+ // Pop the shadow frame before calling into compiled code.
+ self->PopShadowFrame();
+ ArtInterpreterToCompiledCodeBridge(self, code_item, &shadow_frame, &result);
+ // Push the shadow frame back as the caller will expect it.
+ self->PushShadowFrame(&shadow_frame);
+
+ return result;
}
}
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index c3b75b2..56a213c 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -17,6 +17,7 @@
#include "base/stl_util.h" // MakeUnique
#include "experimental_flags.h"
#include "interpreter_common.h"
+#include "jit/jit.h"
#include "safe_math.h"
#include <memory> // std::unique_ptr
@@ -96,9 +97,26 @@
if (kIsDebugBuild) {
self->AssertNoPendingException();
}
+
+ ArtMethod* method = shadow_frame.GetMethod();
+
if (UNLIKELY(instrumentation->HasMethodEntryListeners())) {
instrumentation->MethodEnterEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
- shadow_frame.GetMethod(), 0);
+ method, 0);
+ }
+
+ if (UNLIKELY(Runtime::Current()->GetJit() != nullptr &&
+ Runtime::Current()->GetJit()->JitAtFirstUse() &&
+ method->HasAnyCompiledCode())) {
+ JValue result;
+
+ // Pop the shadow frame before calling into compiled code.
+ self->PopShadowFrame();
+ ArtInterpreterToCompiledCodeBridge(self, code_item, &shadow_frame, &result);
+ // Push the shadow frame back as the caller will expect it.
+ self->PushShadowFrame(&shadow_frame);
+
+ return result;
}
}
const uint16_t* const insns = code_item->insns_;
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 8f4d24f..f540814 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -202,6 +202,13 @@
}
}
+bool Jit::JitAtFirstUse() {
+ if (instrumentation_cache_ != nullptr) {
+ return instrumentation_cache_->HotMethodThreshold() == 0;
+ }
+ return false;
+}
+
Jit::~Jit() {
DCHECK(!save_profiling_info_ || !ProfileSaver::IsStarted());
if (dump_info_on_shutdown_) {
@@ -217,7 +224,6 @@
}
void Jit::CreateInstrumentationCache(size_t compile_threshold, size_t warmup_threshold) {
- CHECK_GT(compile_threshold, 0U);
instrumentation_cache_.reset(
new jit::JitInstrumentationCache(compile_threshold, warmup_threshold));
}
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index 429edf6..a80f51f 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -86,6 +86,8 @@
// into the specified class linker to the jit debug interface,
void DumpTypeInfoForLoadedTypes(ClassLinker* linker);
+ bool JitAtFirstUse();
+
private:
Jit();
bool LoadCompiler(std::string* error_msg);
@@ -142,6 +144,10 @@
void SetSaveProfilingInfo(bool b) {
save_profiling_info_ = b;
}
+ void SetJitAtFirstUse() {
+ use_jit_ = true;
+ compile_threshold_ = 0;
+ }
private:
bool use_jit_;
diff --git a/runtime/jit/jit_instrumentation.cc b/runtime/jit/jit_instrumentation.cc
index 6b47b67..d597b36 100644
--- a/runtime/jit/jit_instrumentation.cc
+++ b/runtime/jit/jit_instrumentation.cc
@@ -162,6 +162,14 @@
mirror::Object* /*this_object*/,
ArtMethod* method,
uint32_t /*dex_pc*/) {
+ if (UNLIKELY(Runtime::Current()->GetJit()->JitAtFirstUse())) {
+ // The compiler requires a ProfilingInfo object.
+ ProfilingInfo::Create(thread, method, /* retry_allocation */ true);
+ JitCompileTask compile_task(method, JitCompileTask::kCompile);
+ compile_task.Run(thread);
+ return;
+ }
+
instrumentation_cache_->AddSamples(thread, method, 1);
}
diff --git a/runtime/jit/jit_instrumentation.h b/runtime/jit/jit_instrumentation.h
index 620c087..06559ad 100644
--- a/runtime/jit/jit_instrumentation.h
+++ b/runtime/jit/jit_instrumentation.h
@@ -101,6 +101,11 @@
SHARED_REQUIRES(Locks::mutator_lock_);
void CreateThreadPool();
void DeleteThreadPool(Thread* self);
+
+ size_t HotMethodThreshold() const {
+ return hot_method_threshold_;
+ }
+
// Wait until there is no more pending compilation tasks.
void WaitForCompilationToFinish(Thread* self);
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 67d825e..a7881ac 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -65,6 +65,7 @@
DEBUG_ENABLE_SAFEMODE = 1 << 3,
DEBUG_ENABLE_JNI_LOGGING = 1 << 4,
DEBUG_GENERATE_DEBUG_INFO = 1 << 5,
+ DEBUG_ALWAYS_JIT = 1 << 6,
};
Runtime* const runtime = Runtime::Current();
@@ -109,6 +110,13 @@
// This is for backwards compatibility with Dalvik.
debug_flags &= ~DEBUG_ENABLE_ASSERT;
+ if ((debug_flags & DEBUG_ALWAYS_JIT) != 0) {
+ jit::JitOptions* jit_options = runtime->GetJITOptions();
+ CHECK(jit_options != nullptr);
+ jit_options->SetJitAtFirstUse();
+ debug_flags &= ~DEBUG_ALWAYS_JIT;
+ }
+
if (debug_flags != 0) {
LOG(ERROR) << StringPrintf("Unknown bits set in debug_flags: %#x", debug_flags);
}