From 3b588e09eac6fb2aff64595e2232e479703850fc Mon Sep 17 00:00:00 2001 From: Sebastien Hertz Date: Wed, 11 Sep 2013 14:33:18 +0200 Subject: Optimize instruction data fetch in interpreter. The computed goto implementation prevents the compiler from detecting we are loading the first 16 bits of instruction twice: first one to get the opcode and second one to fetch first instruction's operand(s) like vA and vB. We now load the 16 bits into a local variable and decode opcode and operands from this variable. And do the same in the switch-based implementation for consistency. The performance improvement is 5% in average on benchmark applications suite. Also remove unused "Thread* self" parameter from DoIGetQuick and DoIPutQuick. Bug: 10703860 Change-Id: I83026ed6e78f642ac3dcdc6edbb6056fe012005f --- runtime/interpreter/interpreter_common.h | 50 +++++++++++++++----------------- 1 file changed, 23 insertions(+), 27 deletions(-) (limited to 'runtime/interpreter/interpreter_common.h') diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 794891e..ec1f942 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -123,12 +123,12 @@ bool DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame, // specialization. template static bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, - const Instruction* inst) + const Instruction* inst, uint16_t inst_data) NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE; template static inline bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, - const Instruction* inst) { + const Instruction* inst, uint16_t inst_data) { bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead); uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c(); ArtField* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self, @@ -142,13 +142,13 @@ static inline bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, if (is_static) { obj = f->GetDeclaringClass(); } else { - obj = shadow_frame.GetVRegReference(inst->VRegB_22c()); + obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data)); if (UNLIKELY(obj == NULL)) { ThrowNullPointerExceptionForFieldAccess(shadow_frame.GetCurrentLocationForThrow(), f, true); return false; } } - uint32_t vregA = is_static ? inst->VRegA_21c() : inst->VRegA_22c(); + uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data); switch (field_type) { case Primitive::kPrimBoolean: shadow_frame.SetVReg(vregA, f->GetBoolean(obj)); @@ -180,14 +180,12 @@ static inline bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, // TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template // specialization. template -static bool DoIGetQuick(Thread* self, ShadowFrame& shadow_frame, - const Instruction* inst) +static bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE; template -static inline bool DoIGetQuick(Thread* self, ShadowFrame& shadow_frame, - const Instruction* inst) { - Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c()); +static inline bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) { + Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data)); if (UNLIKELY(obj == NULL)) { // We lost the reference to the field index so we cannot get a more // precised exception message. @@ -196,7 +194,7 @@ static inline bool DoIGetQuick(Thread* self, ShadowFrame& shadow_frame, } MemberOffset field_offset(inst->VRegC_22c()); const bool is_volatile = false; // iget-x-quick only on non volatile fields. - const uint32_t vregA = inst->VRegA_22c(); + const uint32_t vregA = inst->VRegA_22c(inst_data); switch (field_type) { case Primitive::kPrimInt: shadow_frame.SetVReg(vregA, static_cast(obj->GetField32(field_offset, is_volatile))); @@ -217,12 +215,12 @@ static inline bool DoIGetQuick(Thread* self, ShadowFrame& shadow_frame, // specialization. template static bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, - const Instruction* inst) + const Instruction* inst, uint16_t inst_data) NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE; template static inline bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, - const Instruction* inst) { + const Instruction* inst, uint16_t inst_data) { bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite); uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c(); ArtField* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self, @@ -236,14 +234,14 @@ static inline bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, if (is_static) { obj = f->GetDeclaringClass(); } else { - obj = shadow_frame.GetVRegReference(inst->VRegB_22c()); + obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data)); if (UNLIKELY(obj == NULL)) { ThrowNullPointerExceptionForFieldAccess(shadow_frame.GetCurrentLocationForThrow(), f, false); return false; } } - uint32_t vregA = is_static ? inst->VRegA_21c() : inst->VRegA_22c(); + uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data); switch (field_type) { case Primitive::kPrimBoolean: f->SetBoolean(obj, shadow_frame.GetVReg(vregA)); @@ -275,14 +273,12 @@ static inline bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, // TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template // specialization. template -static bool DoIPutQuick(Thread* self, ShadowFrame& shadow_frame, - const Instruction* inst) +static bool DoIPutQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE; template -static inline bool DoIPutQuick(Thread* self, ShadowFrame& shadow_frame, - const Instruction* inst) { - Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c()); +static inline bool DoIPutQuick(ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) { + Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data)); if (UNLIKELY(obj == NULL)) { // We lost the reference to the field index so we cannot get a more // precised exception message. @@ -291,7 +287,7 @@ static inline bool DoIPutQuick(Thread* self, ShadowFrame& shadow_frame, } MemberOffset field_offset(inst->VRegC_22c()); const bool is_volatile = false; // iput-x-quick only on non volatile fields. - const uint32_t vregA = inst->VRegA_22c(); + const uint32_t vregA = inst->VRegA_22c(inst_data); switch (field_type) { case Primitive::kPrimInt: obj->SetField32(field_offset, shadow_frame.GetVReg(vregA), is_volatile); @@ -387,14 +383,14 @@ static inline bool DoLongRemainder(ShadowFrame& shadow_frame, size_t result_reg, // Returns true on success, otherwise throws an exception and returns false. template bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame, - Thread* self, JValue* result) NO_THREAD_SAFETY_ANALYSIS; + Thread* self, JValue* result) NO_THREAD_SAFETY_ANALYSIS; -static inline int32_t DoPackedSwitch(const Instruction* inst, - const ShadowFrame& shadow_frame) +static inline int32_t DoPackedSwitch(const Instruction* inst, const ShadowFrame& shadow_frame, + uint16_t inst_data) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(inst->Opcode() == Instruction::PACKED_SWITCH); const uint16_t* switch_data = reinterpret_cast(inst) + inst->VRegB_31t(); - int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t()); + int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data)); DCHECK_EQ(switch_data[0], static_cast(Instruction::kPackedSwitchSignature)); uint16_t size = switch_data[1]; DCHECK_GT(size, 0); @@ -412,12 +408,12 @@ static inline int32_t DoPackedSwitch(const Instruction* inst, } } -static inline int32_t DoSparseSwitch(const Instruction* inst, - const ShadowFrame& shadow_frame) +static inline int32_t DoSparseSwitch(const Instruction* inst, const ShadowFrame& shadow_frame, + uint16_t inst_data) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(inst->Opcode() == Instruction::SPARSE_SWITCH); const uint16_t* switch_data = reinterpret_cast(inst) + inst->VRegB_31t(); - int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t()); + int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t(inst_data)); DCHECK_EQ(switch_data[0], static_cast(Instruction::kSparseSwitchSignature)); uint16_t size = switch_data[1]; DCHECK_GT(size, 0); -- cgit v1.1