summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastien Hertz <shertz@google.com>2013-12-16 11:31:45 +0100
committerSebastien Hertz <shertz@google.com>2013-12-17 15:13:03 +0100
commit9119c5f9e4f447f4209d51cff66d1aace510ce5e (patch)
treed6f5c783b8a43a849bcc0c4cfeaffd3f1b062bcd
parentd5c0587bc26a820646950b634275ba10ab06c995 (diff)
downloadart-9119c5f9e4f447f4209d51cff66d1aace510ce5e.zip
art-9119c5f9e4f447f4209d51cff66d1aace510ce5e.tar.gz
art-9119c5f9e4f447f4209d51cff66d1aace510ce5e.tar.bz2
Cleanup invoke's receiver handling in interpreter.
To comply with a moving collector, we used to load invoke's receiver (for non static methods only) from the caller shadow frame after resolving the method itself (in case the garbage collector is triggered inside) but before passing invoke arguments, including loading receiver from the caller's shadow frame into the callee's shadow frame. Therefore, we used to load the receiver 3 times in the fast path but only twice in the slow path. The slow path is rarely used (only in method requiring extra runtime checks) so we now move this extra reload to the slow path. Therefore an invoke using the fast path loads the receiver twice while the slow path loads it 3 times. I don't expect much improvement here. The main reason is to keep extra code in the slow path. Change-Id: I10e96b10de4b8c2992e276bd564bc3e2f191779c
-rw-r--r--runtime/interpreter/interpreter_common.cc27
-rw-r--r--runtime/interpreter/interpreter_common.h11
-rw-r--r--runtime/stack.h2
3 files changed, 17 insertions, 23 deletions
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 5b9e55f..1d40293 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -38,7 +38,7 @@ static inline void AssignRegister(ShadowFrame& new_shadow_frame, const ShadowFra
}
template<bool is_range, bool do_assignability_check>
-bool DoCall(ArtMethod* method, Object* receiver, Thread* self, ShadowFrame& shadow_frame,
+bool DoCall(ArtMethod* method, Thread* self, ShadowFrame& shadow_frame,
const Instruction* inst, uint16_t inst_data, JValue* result) {
// Compute method information.
MethodHelper mh(method);
@@ -66,17 +66,6 @@ bool DoCall(ArtMethod* method, Object* receiver, Thread* self, ShadowFrame& shad
const DexFile::TypeList* params = mh.GetParameterTypeList();
const char* shorty = mh.GetShorty();
- // Handle receiver apart since it's not part of the shorty.
- size_t dest_reg = first_dest_reg;
- size_t arg_offset = 0;
- if (receiver != NULL) {
- DCHECK(!method->IsStatic());
- new_shadow_frame->SetVRegReference(dest_reg, receiver);
- ++dest_reg;
- ++arg_offset;
- } else {
- DCHECK(method->IsStatic());
- }
// TODO: find a cleaner way to separate non-range and range information without duplicating code.
uint32_t arg[5]; // only used in invoke-XXX.
uint32_t vregC; // only used in invoke-XXX-range.
@@ -85,6 +74,16 @@ bool DoCall(ArtMethod* method, Object* receiver, Thread* self, ShadowFrame& shad
} else {
inst->GetArgs(arg, inst_data);
}
+
+ // Handle receiver apart since it's not part of the shorty.
+ size_t dest_reg = first_dest_reg;
+ size_t arg_offset = 0;
+ if (!method->IsStatic()) {
+ size_t receiver_reg = (is_range) ? vregC : arg[0];
+ new_shadow_frame->SetVRegReference(dest_reg, shadow_frame.GetVRegReference(receiver_reg));
+ ++dest_reg;
+ ++arg_offset;
+ }
for (size_t shorty_pos = 0; dest_reg < num_regs; ++shorty_pos, ++dest_reg, ++arg_offset) {
DCHECK_LT(shorty_pos + 1, mh.GetShortyLength());
const size_t src_reg = (is_range) ? vregC + arg_offset : arg[arg_offset];
@@ -333,8 +332,8 @@ static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
// Explicit DoCall template function declarations.
#define EXPLICIT_DO_CALL_TEMPLATE_DECL(_is_range, _do_assignability_check) \
template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) \
- bool DoCall<_is_range, _do_assignability_check>(ArtMethod* method, Object* receiver, \
- Thread* self, ShadowFrame& shadow_frame, \
+ bool DoCall<_is_range, _do_assignability_check>(ArtMethod* method, Thread* self, \
+ ShadowFrame& shadow_frame, \
const Instruction* inst, uint16_t inst_data, \
JValue* result)
EXPLICIT_DO_CALL_TEMPLATE_DECL(false, false);
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index a9b8909..4481210 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -87,7 +87,7 @@ static inline void DoMonitorExit(Thread* self, Object* ref) NO_THREAD_SAFETY_ANA
// DoInvokeVirtualQuick functions.
// Returns true on success, otherwise throws an exception and returns false.
template<bool is_range, bool do_assignability_check>
-bool DoCall(ArtMethod* method, Object* receiver, Thread* self, ShadowFrame& shadow_frame,
+bool DoCall(ArtMethod* method, Thread* self, ShadowFrame& shadow_frame,
const Instruction* inst, uint16_t inst_data, JValue* result);
// Handles invoke-XXX/range instructions.
@@ -101,10 +101,6 @@ static inline bool DoInvoke(Thread* self, ShadowFrame& shadow_frame, const Instr
ArtMethod* const method = FindMethodFromCode<type, do_access_check>(method_idx, receiver,
shadow_frame.GetMethod(),
self);
- if (type != kStatic) {
- // Reload the vreg since the GC may have moved the object.
- receiver = shadow_frame.GetVRegReference(vregC);
- }
if (UNLIKELY(method == nullptr)) {
CHECK(self->IsExceptionPending());
result->SetJ(0);
@@ -114,8 +110,7 @@ static inline bool DoInvoke(Thread* self, ShadowFrame& shadow_frame, const Instr
result->SetJ(0);
return false;
} else {
- return DoCall<is_range, do_access_check>(method, receiver, self, shadow_frame, inst,
- inst_data, result);
+ return DoCall<is_range, do_access_check>(method, self, shadow_frame, inst, inst_data, result);
}
}
@@ -145,7 +140,7 @@ static inline bool DoInvokeVirtualQuick(Thread* self, ShadowFrame& shadow_frame,
return false;
} else {
// No need to check since we've been quickened.
- return DoCall<is_range, false>(method, receiver, self, shadow_frame, inst, inst_data, result);
+ return DoCall<is_range, false>(method, self, shadow_frame, inst, inst_data, result);
}
}
diff --git a/runtime/stack.h b/runtime/stack.h
index 3d6b06a..590f406 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -160,7 +160,7 @@ class ShadowFrame {
<< ") is in protected space, reference array " << true;
}
// If the vreg reference is not equal to the vreg then the vreg reference is stale.
- if (reinterpret_cast<uint32_t>(ref) != vregs_[i]) {
+ if (UNLIKELY(reinterpret_cast<uint32_t>(ref) != vregs_[i])) {
return nullptr;
}
return ref;