Interpreter tweaks
Increase the amount of inlining and hot function hints in the interpreter
to encourage the hot Execute function to be faster.
Performance is 3x slower than Dalvik+JIT on FibonacciFast and similar
microbenchmarks.
Change-Id: I2b1a0c7545f86036b9b1b5ccac881d06292356d8
diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc
index 33bdf9f..e315710 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -385,8 +385,7 @@
static void DoInvoke(Thread* self, MethodHelper& mh, ShadowFrame& shadow_frame,
const Instruction* inst, InvokeType type, bool is_range,
- JValue* result)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ JValue* result) {
uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
Object* receiver;
if (type == kStatic) {
@@ -474,7 +473,11 @@
static void DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
const Instruction* inst, FindFieldType find_type,
Primitive::Type field_type)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE;
+
+static inline void DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
+ const Instruction* inst, FindFieldType find_type,
+ Primitive::Type field_type) {
bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead);
uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
Field* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
@@ -524,7 +527,11 @@
static void DoFieldPut(Thread* self, ShadowFrame& shadow_frame,
const Instruction* inst, FindFieldType find_type,
Primitive::Type field_type)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE;
+
+static inline void DoFieldPut(Thread* self, ShadowFrame& shadow_frame,
+ const Instruction* inst, FindFieldType find_type,
+ Primitive::Type field_type) {
bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
Field* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
@@ -572,7 +579,7 @@
}
}
-static String* ResolveString(Thread* self, MethodHelper& mh, uint32_t string_idx) {
+static inline String* ResolveString(Thread* self, MethodHelper& mh, uint32_t string_idx) {
Class* java_lang_string_class = String::GetJavaLangString();
if (UNLIKELY(!java_lang_string_class->IsInitialized())) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
@@ -585,7 +592,7 @@
return mh.ResolveString(string_idx);
}
-static void DoIntDivide(Thread* self, ShadowFrame& shadow_frame, size_t result_reg,
+static inline void DoIntDivide(Thread* self, ShadowFrame& shadow_frame, size_t result_reg,
int32_t dividend, int32_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (UNLIKELY(divisor == 0)) {
ThrowArithmeticExceptionDivideByZero(self);
@@ -596,7 +603,7 @@
}
}
-static void DoIntRemainder(Thread* self, ShadowFrame& shadow_frame, size_t result_reg,
+static inline void DoIntRemainder(Thread* self, ShadowFrame& shadow_frame, size_t result_reg,
int32_t dividend, int32_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (UNLIKELY(divisor == 0)) {
ThrowArithmeticExceptionDivideByZero(self);
@@ -607,7 +614,7 @@
}
}
-static void DoLongDivide(Thread* self, ShadowFrame& shadow_frame, size_t result_reg,
+static inline void DoLongDivide(Thread* self, ShadowFrame& shadow_frame, size_t result_reg,
int64_t dividend, int64_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (UNLIKELY(divisor == 0)) {
ThrowArithmeticExceptionDivideByZero(self);
@@ -618,7 +625,7 @@
}
}
-static void DoLongRemainder(Thread* self, ShadowFrame& shadow_frame, size_t result_reg,
+static inline void DoLongRemainder(Thread* self, ShadowFrame& shadow_frame, size_t result_reg,
int64_t dividend, int64_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (UNLIKELY(divisor == 0)) {
ThrowArithmeticExceptionDivideByZero(self);
@@ -629,12 +636,20 @@
}
}
-static const Instruction* FindNextInstructionFollowingException(Thread* self,
- ShadowFrame& shadow_frame,
- uint32_t dex_pc,
- const uint16_t* const insns,
- SirtRef<Object>& this_object_ref,
- instrumentation::Instrumentation* instrumentation) {
+static inline const Instruction* FindNextInstructionFollowingException(Thread* self,
+ ShadowFrame& shadow_frame,
+ uint32_t dex_pc,
+ const uint16_t* insns,
+ SirtRef<Object>& this_object_ref,
+ instrumentation::Instrumentation* instrumentation)
+ ALWAYS_INLINE;
+
+static inline const Instruction* FindNextInstructionFollowingException(Thread* self,
+ ShadowFrame& shadow_frame,
+ uint32_t dex_pc,
+ const uint16_t* insns,
+ SirtRef<Object>& this_object_ref,
+ instrumentation::Instrumentation* instrumentation) {
self->VerifyStack();
ThrowLocation throw_location;
mirror::Throwable* exception = self->GetException(&throw_location);
@@ -670,9 +685,20 @@
inst = inst-> next_function (); \
}
+static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh)
+ __attribute__ ((cold, noreturn, noinline));
+
+static void UnexpectedOpcode(const Instruction* inst, MethodHelper& mh) {
+ LOG(FATAL) << "Unexpected instruction: " << inst->DumpString(&mh.GetDexFile());
+ exit(0); // Unreachable, keep GCC happy.
+}
+
static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) __attribute__ ((hot));
+
+static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register) {
if (UNLIKELY(!shadow_frame.HasReferenceArray())) {
LOG(FATAL) << "Invalid shadow frame for interpreter use";
return JValue();
@@ -692,7 +718,7 @@
shadow_frame.GetMethod(), 0);
}
while (true) {
- if (self->TestAllFlags()) {
+ if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
}
const uint32_t dex_pc = inst->GetDexPc(insns);
@@ -1180,12 +1206,10 @@
float val1 = shadow_frame.GetVRegFloat(inst->VRegB_23x());
float val2 = shadow_frame.GetVRegFloat(inst->VRegC_23x());
int32_t result;
- // TODO: we should not test float equality like this. Reorder comparisons
- // or use a different comparison mechanism.
- if (val1 == val2) {
- result = 0;
- } else if (val1 > val2) {
+ if (val1 > val2) {
result = 1;
+ } else if (val1 == val2) {
+ result = 0;
} else {
result = -1;
}
@@ -1197,12 +1221,10 @@
float val1 = shadow_frame.GetVRegFloat(inst->VRegB_23x());
float val2 = shadow_frame.GetVRegFloat(inst->VRegC_23x());
int32_t result;
- // TODO: we should not test float equality like this. Reorder comparisons
- // or use a different comparison mechanism.
- if (val1 == val2) {
- result = 0;
- } else if (val1 < val2) {
+ if (val1 < val2) {
result = -1;
+ } else if (val1 == val2) {
+ result = 0;
} else {
result = 1;
}
@@ -1214,12 +1236,10 @@
double val1 = shadow_frame.GetVRegDouble(inst->VRegB_23x());
double val2 = shadow_frame.GetVRegDouble(inst->VRegC_23x());
int32_t result;
- // TODO: we should not test double equality like this. Reorder comparisons
- // or use a different comparison mechanism.
- if (val1 == val2) {
- result = 0;
- } else if (val1 > val2) {
+ if (val1 > val2) {
result = 1;
+ } else if (val1 == val2) {
+ result = 0;
} else {
result = -1;
}
@@ -1232,12 +1252,10 @@
double val1 = shadow_frame.GetVRegDouble(inst->VRegB_23x());
double val2 = shadow_frame.GetVRegDouble(inst->VRegC_23x());
int32_t result;
- // TODO: we should not test double equality like this. Reorder comparisons
- // or use a different comparison mechanism.
- if (val1 == val2) {
- result = 0;
- } else if (val1 < val2) {
+ if (val1 < val2) {
result = -1;
+ } else if (val1 == val2) {
+ result = 0;
} else {
result = 1;
}
@@ -2433,9 +2451,12 @@
(inst->VRegC_22b() & 0x1f));
inst = inst->Next_2xx();
break;
- default:
- LOG(FATAL) << "Unexpected instruction: " << inst->DumpString(&mh.GetDexFile());
- break;
+ case Instruction::UNUSED_3E ... Instruction::UNUSED_43:
+ case Instruction::UNUSED_E3 ... Instruction::UNUSED_FF:
+ case Instruction::UNUSED_73:
+ case Instruction::UNUSED_79:
+ case Instruction::UNUSED_7A:
+ UnexpectedOpcode(inst, mh);
}
}
}