summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Orion Hodson <oth@google.com> 2017-11-10 15:32:38 +0000
committer Orion Hodson <oth@google.com> 2017-11-13 10:13:13 +0000
commit960d4f7c5f6a464aa00b8f393cc88996c55464f3 (patch)
treedcc69d9ab9b36afd5b22a0dbbf0e6279f8a26cf6
parente983b1658589e2a3d12620846b7e2351af26afa6 (diff)
ART: Simplify MethodHandle invocations
Use an operand iterator rather than passing arguments for both range and varargs operands. Test: art/test.py --host -j32 Change-Id: Ia42398773bd3732d917e19c25aa431b1e1369320
-rw-r--r--runtime/dex_instruction.cc10
-rw-r--r--runtime/dex_instruction.h47
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc30
-rw-r--r--runtime/interpreter/interpreter_common.cc103
-rw-r--r--runtime/method_handles.cc295
-rw-r--r--runtime/method_handles.h58
-rw-r--r--runtime/mirror/emulated_stack_frame.cc24
-rw-r--r--runtime/mirror/emulated_stack_frame.h4
8 files changed, 265 insertions, 306 deletions
diff --git a/runtime/dex_instruction.cc b/runtime/dex_instruction.cc
index e64c0f62c2..6ebe2286e8 100644
--- a/runtime/dex_instruction.cc
+++ b/runtime/dex_instruction.cc
@@ -548,4 +548,14 @@ std::ostream& operator<<(std::ostream& os, const Instruction::Code& code) {
return os << Instruction::Name(code);
}
+uint32_t RangeInstructionOperands::GetOperand(size_t operand_index) const {
+ DCHECK_LT(operand_index, GetNumberOfOperands());
+ return first_operand_ + operand_index;
+}
+
+uint32_t VarArgsInstructionOperands::GetOperand(size_t operand_index) const {
+ DCHECK_LT(operand_index, GetNumberOfOperands());
+ return operands_[operand_index];
+}
+
} // namespace art
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
index 09c78b2428..4041820616 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex_instruction.h
@@ -689,6 +689,53 @@ std::ostream& operator<<(std::ostream& os, const Instruction::Format& format);
std::ostream& operator<<(std::ostream& os, const Instruction::Flags& flags);
std::ostream& operator<<(std::ostream& os, const Instruction::VerifyFlag& vflags);
+// Base class for accessing instruction operands. Unifies operand
+// access for instructions that have range and varargs forms
+// (e.g. invoke-polymoprhic/range and invoke-polymorphic).
+class InstructionOperands {
+ public:
+ explicit InstructionOperands(size_t num_operands) : num_operands_(num_operands) {}
+ virtual ~InstructionOperands() {}
+ virtual uint32_t GetOperand(size_t index) const = 0;
+ size_t GetNumberOfOperands() const { return num_operands_; }
+
+ private:
+ size_t num_operands_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(InstructionOperands);
+};
+
+// Class for accessing operands for instructions with a range format
+// (e.g. 3rc and 4rcc).
+class RangeInstructionOperands FINAL : public InstructionOperands {
+ public:
+ RangeInstructionOperands(uint32_t first_operand, size_t num_operands)
+ : InstructionOperands(num_operands), first_operand_(first_operand) {}
+ ~RangeInstructionOperands() {}
+ uint32_t GetOperand(size_t operand_index) const OVERRIDE;
+
+ private:
+ const uint32_t first_operand_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(RangeInstructionOperands);
+};
+
+// Class for accessing operands for instructions with a variable
+// number of arguments format (e.g. 35c and 45cc).
+class VarArgsInstructionOperands FINAL : public InstructionOperands {
+ public:
+ VarArgsInstructionOperands(const uint32_t (&operands)[Instruction::kMaxVarArgRegs],
+ size_t num_operands)
+ : InstructionOperands(num_operands), operands_(operands) {}
+ ~VarArgsInstructionOperands() {}
+ uint32_t GetOperand(size_t operand_index) const OVERRIDE;
+
+ private:
+ const uint32_t (&operands_)[Instruction::kMaxVarArgRegs];
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(VarArgsInstructionOperands);
+};
+
} // namespace art
#endif // ART_RUNTIME_DEX_INSTRUCTION_H_
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 127b5d7028..22c9a1d31a 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -2649,28 +2649,24 @@ extern "C" uintptr_t artInvokePolymorphic(
// Call DoInvokePolymorphic with |is_range| = true, as shadow frame has argument registers in
// consecutive order.
- uint32_t unused_args[Instruction::kMaxVarArgRegs] = {};
- uint32_t first_callee_arg = first_arg + 1;
-
+ RangeInstructionOperands operands(first_arg + 1, num_vregs - 1);
bool isExact = (jni::EncodeArtMethod(resolved_method) ==
WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact);
bool success = false;
if (isExact) {
- success = MethodHandleInvokeExact<true/*is_range*/>(self,
- *shadow_frame,
- method_handle,
- method_type,
- unused_args,
- first_callee_arg,
- result);
+ success = MethodHandleInvokeExact(self,
+ *shadow_frame,
+ method_handle,
+ method_type,
+ &operands,
+ result);
} else {
- success = MethodHandleInvoke<true/*is_range*/>(self,
- *shadow_frame,
- method_handle,
- method_type,
- unused_args,
- first_callee_arg,
- result);
+ success = MethodHandleInvoke(self,
+ *shadow_frame,
+ method_handle,
+ method_type,
+ &operands,
+ result);
}
DCHECK(success || self->IsExceptionPending());
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 0a1ae36167..d2d017e118 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -644,52 +644,47 @@ static bool DoMethodHandleInvokeCommon(Thread* self,
// arguments either from a range or an array of arguments depending
// on whether the DEX instruction is invoke-polymorphic/range or
// invoke-polymorphic. The array here is for the latter.
- uint32_t args[Instruction::kMaxVarArgRegs] = {};
if (UNLIKELY(is_range)) {
// VRegC is the register holding the method handle. Arguments passed
// to the method handle's target do not include the method handle.
- uint32_t first_arg = inst->VRegC_4rcc() + 1;
- static const bool kIsRange = true;
+ RangeInstructionOperands operands(inst->VRegC_4rcc() + 1, inst->VRegA_4rcc() - 1);
if (invoke_exact) {
- return art::MethodHandleInvokeExact<kIsRange>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args /* unused */,
- first_arg,
- result);
+ return MethodHandleInvokeExact(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ &operands,
+ result);
} else {
- return art::MethodHandleInvoke<kIsRange>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args /* unused */,
- first_arg,
- result);
+ return MethodHandleInvoke(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ &operands,
+ result);
}
} else {
// Get the register arguments for the invoke.
+ uint32_t args[Instruction::kMaxVarArgRegs] = {};
inst->GetVarArgs(args, inst_data);
// Drop the first register which is the method handle performing the invoke.
memmove(args, args + 1, sizeof(args[0]) * (Instruction::kMaxVarArgRegs - 1));
args[Instruction::kMaxVarArgRegs - 1] = 0;
- static const bool kIsRange = false;
+ VarArgsInstructionOperands operands(args, inst->VRegA_45cc() - 1);
if (invoke_exact) {
- return art::MethodHandleInvokeExact<kIsRange>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- args[0],
- result);
+ return MethodHandleInvokeExact(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ &operands,
+ result);
} else {
- return art::MethodHandleInvoke<kIsRange>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- args[0],
- result);
+ return MethodHandleInvoke(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ &operands,
+ result);
}
}
}
@@ -1180,17 +1175,13 @@ static ObjPtr<mirror::CallSite> InvokeBootstrapMethod(Thread* self,
// Invoke the bootstrap method handle.
JValue result;
-
- // This array of arguments is unused. DoMethodHandleInvokeExact() operates on either a
- // an argument array or a range, but always takes an array argument.
- uint32_t args_unused[Instruction::kMaxVarArgRegs];
- bool invoke_success = art::MethodHandleInvokeExact<true /* is_range */>(self,
- *bootstrap_frame,
- bootstrap,
- bootstrap_method_type,
- args_unused,
- 0,
- &result);
+ RangeInstructionOperands operands(0, vreg);
+ bool invoke_success = MethodHandleInvokeExact(self,
+ *bootstrap_frame,
+ bootstrap,
+ bootstrap_method_type,
+ &operands,
+ &result);
if (!invoke_success) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -1273,21 +1264,25 @@ bool DoInvokeCustom(Thread* self,
Handle<mirror::MethodHandle> target = hs.NewHandle(call_site->GetTarget());
Handle<mirror::MethodType> target_method_type = hs.NewHandle(target->GetMethodType());
DCHECK_EQ(static_cast<size_t>(inst->VRegA()), target_method_type->NumberOfVRegs());
-
- uint32_t args[Instruction::kMaxVarArgRegs];
if (is_range) {
- args[0] = inst->VRegC_3rc();
+ RangeInstructionOperands operands(inst->VRegC_3rc(), inst->VRegA_3rc());
+ return MethodHandleInvokeExact(self,
+ shadow_frame,
+ target,
+ target_method_type,
+ &operands,
+ result);
} else {
+ uint32_t args[Instruction::kMaxVarArgRegs];
inst->GetVarArgs(args, inst_data);
+ VarArgsInstructionOperands operands(args, inst->VRegA_35c());
+ return MethodHandleInvokeExact(self,
+ shadow_frame,
+ target,
+ target_method_type,
+ &operands,
+ result);
}
-
- return art::MethodHandleInvokeExact<is_range>(self,
- shadow_frame,
- target,
- target_method_type,
- args,
- args[0],
- result);
}
template <bool is_range>
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 5a5d5713a8..8eb31c1ef8 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -299,17 +299,14 @@ bool ConvertJValueCommon(
namespace {
-template <bool is_range>
inline void CopyArgumentsFromCallerFrame(const ShadowFrame& caller_frame,
ShadowFrame* callee_frame,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
- const size_t first_dst_reg,
- const size_t num_regs)
+ const InstructionOperands* const operands,
+ const size_t first_dst_reg)
REQUIRES_SHARED(Locks::mutator_lock_) {
- for (size_t i = 0; i < num_regs; ++i) {
+ for (size_t i = 0; i < operands->GetNumberOfOperands(); ++i) {
size_t dst_reg = first_dst_reg + i;
- size_t src_reg = is_range ? (first_arg + i) : args[i];
+ size_t src_reg = operands->GetOperand(i);
// Uint required, so that sign extension does not make this wrong on 64-bit systems
uint32_t src_value = caller_frame.GetVReg(src_reg);
ObjPtr<mirror::Object> o = caller_frame.GetVRegReference<kVerifyNone>(src_reg);
@@ -324,15 +321,13 @@ inline void CopyArgumentsFromCallerFrame(const ShadowFrame& caller_frame,
}
}
-template <bool is_range>
inline bool ConvertAndCopyArgumentsFromCallerFrame(
Thread* self,
Handle<mirror::MethodType> callsite_type,
Handle<mirror::MethodType> callee_type,
const ShadowFrame& caller_frame,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
- uint32_t first_dst_reg,
+ uint32_t first_dest_reg,
+ const InstructionOperands* const operands,
ShadowFrame* callee_frame)
REQUIRES_SHARED(Locks::mutator_lock_) {
ObjPtr<mirror::ObjectArray<mirror::Class>> from_types(callsite_type->GetPTypes());
@@ -344,15 +339,14 @@ inline bool ConvertAndCopyArgumentsFromCallerFrame(
return false;
}
- ShadowFrameGetter<is_range> getter(first_arg, args, caller_frame);
- ShadowFrameSetter setter(callee_frame, first_dst_reg);
-
- return PerformConversions<ShadowFrameGetter<is_range>, ShadowFrameSetter>(self,
- callsite_type,
- callee_type,
- &getter,
- &setter,
- num_method_params);
+ ShadowFrameGetter getter(operands, caller_frame);
+ ShadowFrameSetter setter(callee_frame, first_dest_reg);
+ return PerformConversions<ShadowFrameGetter, ShadowFrameSetter>(self,
+ callsite_type,
+ callee_type,
+ &getter,
+ &setter,
+ num_method_params);
}
inline bool IsInvoke(const mirror::MethodHandle::Kind handle_kind) {
@@ -406,14 +400,12 @@ static inline bool IsCallerTransformer(Handle<mirror::MethodType> callsite_type)
return false;
}
-template <bool is_range>
static inline bool MethodHandleInvokeMethod(ArtMethod* called_method,
Handle<mirror::MethodType> callsite_type,
Handle<mirror::MethodType> target_type,
Thread* self,
ShadowFrame& shadow_frame,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
+ const InstructionOperands* const operands,
JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
// Compute method information.
const DexFile::CodeItem* code_item = called_method->GetCodeItem();
@@ -455,12 +447,10 @@ static inline bool MethodHandleInvokeMethod(ArtMethod* called_method,
if (callsite_type->IsExactMatch(target_type.Get())) {
// This is an exact invoke, we can take the fast path of just copying all
// registers without performing any argument conversions.
- CopyArgumentsFromCallerFrame<is_range>(shadow_frame,
- new_shadow_frame,
- args,
- first_arg,
- first_dest_reg,
- num_input_regs);
+ CopyArgumentsFromCallerFrame(shadow_frame,
+ new_shadow_frame,
+ operands,
+ first_dest_reg);
} else {
// This includes the case where we're entering this invoke-polymorphic
// from a transformer method. In that case, the callsite_type will contain
@@ -471,7 +461,7 @@ static inline bool MethodHandleInvokeMethod(ArtMethod* called_method,
is_caller_transformer = true;
// The emulated stack frame is the first and only argument when we're coming
// through from a transformer.
- size_t first_arg_register = (is_range) ? first_arg : args[0];
+ size_t first_arg_register = operands->GetOperand(0);
ObjPtr<mirror::EmulatedStackFrame> emulated_stack_frame(
reinterpret_cast<mirror::EmulatedStackFrame*>(
shadow_frame.GetVRegReference(first_arg_register)));
@@ -488,14 +478,13 @@ static inline bool MethodHandleInvokeMethod(ArtMethod* called_method,
ThrowWrongMethodTypeException(target_type.Get(), callsite_type.Get());
return false;
}
- if (!ConvertAndCopyArgumentsFromCallerFrame<is_range>(self,
- callsite_type,
- target_type,
- shadow_frame,
- args,
- first_arg,
- first_dest_reg,
- new_shadow_frame)) {
+ if (!ConvertAndCopyArgumentsFromCallerFrame(self,
+ callsite_type,
+ target_type,
+ shadow_frame,
+ first_dest_reg,
+ operands,
+ new_shadow_frame)) {
DCHECK(self->IsExceptionPending());
result->SetL(0);
return false;
@@ -521,7 +510,7 @@ static inline bool MethodHandleInvokeMethod(ArtMethod* called_method,
// we need to copy the result back out to the emulated stack frame.
if (is_caller_transformer) {
StackHandleScope<2> hs(self);
- size_t first_callee_register = is_range ? (first_arg) : args[0];
+ size_t first_callee_register = operands->GetOperand(0);
Handle<mirror::EmulatedStackFrame> emulated_stack_frame(
hs.NewHandle(reinterpret_cast<mirror::EmulatedStackFrame*>(
shadow_frame.GetVRegReference(first_callee_register))));
@@ -541,15 +530,13 @@ static inline bool MethodHandleInvokeMethod(ArtMethod* called_method,
return ConvertReturnValue(callsite_type, target_type, result);
}
-template <bool is_range>
static inline bool MethodHandleInvokeTransform(ArtMethod* called_method,
Handle<mirror::MethodType> callsite_type,
Handle<mirror::MethodType> callee_type,
Thread* self,
ShadowFrame& shadow_frame,
Handle<mirror::MethodHandle> receiver,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
// This can be fixed to two, because the method we're calling here
@@ -578,16 +565,15 @@ static inline bool MethodHandleInvokeTransform(ArtMethod* called_method,
// If we're entering this transformer from another transformer, we can pass
// through the handle directly to the callee, instead of having to
// instantiate a new stack frame based on the shadow frame.
- size_t first_callee_register = is_range ? first_arg : args[0];
+ size_t first_callee_register = operands->GetOperand(0);
sf.Assign(reinterpret_cast<mirror::EmulatedStackFrame*>(
shadow_frame.GetVRegReference(first_callee_register)));
} else {
- sf.Assign(mirror::EmulatedStackFrame::CreateFromShadowFrameAndArgs<is_range>(self,
- callsite_type,
- callee_type,
- shadow_frame,
- first_arg,
- args));
+ sf.Assign(mirror::EmulatedStackFrame::CreateFromShadowFrameAndArgs(self,
+ callsite_type,
+ callee_type,
+ shadow_frame,
+ operands));
// Something went wrong while creating the emulated stack frame, we should
// throw the pending exception.
@@ -699,13 +685,11 @@ ArtMethod* RefineTargetMethod(Thread* self,
return target_method;
}
-template <bool is_range>
bool DoInvokePolymorphicMethod(Thread* self,
ShadowFrame& shadow_frame,
Handle<mirror::MethodHandle> method_handle,
Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
StackHandleScope<1> hs(self);
@@ -718,7 +702,7 @@ bool DoInvokePolymorphicMethod(Thread* self,
// point because they would have been performed on our behalf at the point
// of creation of the method handle.
ArtMethod* target_method = method_handle->GetTargetMethod();
- uint32_t receiver_reg = is_range ? first_arg: args[0];
+ uint32_t receiver_reg = (operands->GetNumberOfOperands() > 0) ? operands->GetOperand(0) : 0u;
ArtMethod* called_method = RefineTargetMethod(self,
shadow_frame,
handle_kind,
@@ -743,24 +727,22 @@ bool DoInvokePolymorphicMethod(Thread* self,
Handle<mirror::MethodType> callee_type =
(handle_kind == mirror::MethodHandle::Kind::kInvokeCallSiteTransform) ? callsite_type
: handle_type;
- return MethodHandleInvokeTransform<is_range>(called_method,
- callsite_type,
- callee_type,
- self,
- shadow_frame,
- method_handle /* receiver */,
- args,
- first_arg,
- result);
+ return MethodHandleInvokeTransform(called_method,
+ callsite_type,
+ callee_type,
+ self,
+ shadow_frame,
+ method_handle /* receiver */,
+ operands,
+ result);
} else {
- return MethodHandleInvokeMethod<is_range>(called_method,
- callsite_type,
- handle_type,
- self,
- shadow_frame,
- args,
- first_arg,
- result);
+ return MethodHandleInvokeMethod(called_method,
+ callsite_type,
+ handle_type,
+ self,
+ shadow_frame,
+ operands,
+ result);
}
}
@@ -884,23 +866,21 @@ static JValue GetValueFromShadowFrame(const ShadowFrame& shadow_frame,
return field_value;
}
-template <bool is_range, bool do_conversions>
+template <bool do_conversions>
bool MethodHandleFieldAccess(Thread* self,
ShadowFrame& shadow_frame,
Handle<mirror::MethodHandle> method_handle,
Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
+ const InstructionOperands* const operands,
JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
StackHandleScope<1> hs(self);
Handle<mirror::MethodType> handle_type(hs.NewHandle(method_handle->GetMethodType()));
const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
ArtField* field = method_handle->GetTargetField();
Primitive::Type field_type = field->GetTypeAsPrimitiveType();
-
switch (handle_kind) {
case mirror::MethodHandle::kInstanceGet: {
- size_t obj_reg = is_range ? first_arg : args[0];
+ size_t obj_reg = operands->GetOperand(0);
ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(obj_reg);
MethodHandleFieldGet(self, shadow_frame, obj, field, field_type, result);
if (do_conversions && !ConvertReturnValue(callsite_type, handle_type, result)) {
@@ -923,8 +903,8 @@ bool MethodHandleFieldAccess(Thread* self,
return true;
}
case mirror::MethodHandle::kInstancePut: {
- size_t obj_reg = is_range ? first_arg : args[0];
- size_t value_reg = is_range ? (first_arg + 1) : args[1];
+ size_t obj_reg = operands->GetOperand(0);
+ size_t value_reg = operands->GetOperand(1);
const size_t kPTypeIndex = 1;
// Use ptypes instead of field type since we may be unboxing a reference for a primitive
// field. The field type is incorrect for this case.
@@ -948,7 +928,7 @@ bool MethodHandleFieldAccess(Thread* self,
DCHECK(self->IsExceptionPending());
return false;
}
- size_t value_reg = is_range ? first_arg : args[0];
+ size_t value_reg = operands->GetOperand(0);
const size_t kPTypeIndex = 0;
// Use ptypes instead of field type since we may be unboxing a reference for a primitive
// field. The field type is incorrect for this case.
@@ -971,13 +951,11 @@ bool MethodHandleFieldAccess(Thread* self,
}
}
-template <bool is_range>
static inline bool MethodHandleInvokeInternal(Thread* self,
ShadowFrame& shadow_frame,
Handle<mirror::MethodHandle> method_handle,
Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
@@ -989,32 +967,28 @@ static inline bool MethodHandleInvokeInternal(Thread* self,
return false;
}
const bool do_convert = true;
- return MethodHandleFieldAccess<is_range, do_convert>(
+ return MethodHandleFieldAccess<do_convert>(
self,
shadow_frame,
method_handle,
callsite_type,
- args,
- first_arg,
+ operands,
result);
}
- return DoInvokePolymorphicMethod<is_range>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- first_arg,
- result);
+ return DoInvokePolymorphicMethod(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ operands,
+ result);
}
-template <bool is_range>
static inline bool MethodHandleInvokeExactInternal(
Thread* self,
ShadowFrame& shadow_frame,
Handle<mirror::MethodHandle> method_handle,
Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
StackHandleScope<1> hs(self);
@@ -1027,29 +1001,27 @@ static inline bool MethodHandleInvokeExactInternal(
const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
if (IsFieldAccess(handle_kind)) {
const bool do_convert = false;
- return MethodHandleFieldAccess<is_range, do_convert>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- first_arg,
- result);
- }
-
- // Slow-path check.
- if (IsInvokeTransform(handle_kind) || IsCallerTransformer(callsite_type)) {
- return DoInvokePolymorphicMethod<is_range>(self,
+ return MethodHandleFieldAccess<do_convert>(self,
shadow_frame,
method_handle,
callsite_type,
- args,
- first_arg,
+ operands,
result);
}
+ // Slow-path check.
+ if (IsInvokeTransform(handle_kind) || IsCallerTransformer(callsite_type)) {
+ return DoInvokePolymorphicMethod(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ operands,
+ result);
+ }
+
// On the fast-path. This is equivalent to DoCallPolymoprhic without the conversion paths.
ArtMethod* target_method = method_handle->GetTargetMethod();
- uint32_t receiver_reg = is_range ? first_arg : args[0];
+ uint32_t receiver_reg = (operands->GetNumberOfOperands() > 0) ? operands->GetOperand(0) : 0u;
ArtMethod* called_method = RefineTargetMethod(self,
shadow_frame,
handle_kind,
@@ -1085,12 +1057,10 @@ static inline bool MethodHandleInvokeExactInternal(
ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
CREATE_SHADOW_FRAME(num_regs, &shadow_frame, called_method, /* dex pc */ 0);
ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get();
- CopyArgumentsFromCallerFrame<is_range>(shadow_frame,
- new_shadow_frame,
- args,
- first_arg,
- first_dest_reg,
- num_input_regs);
+ CopyArgumentsFromCallerFrame(shadow_frame,
+ new_shadow_frame,
+ operands,
+ first_dest_reg);
self->EndAssertNoThreadSuspension(old_cause);
bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint(
@@ -1110,43 +1080,37 @@ static inline bool MethodHandleInvokeExactInternal(
} // namespace
-template <bool is_range>
-inline bool MethodHandleInvoke(Thread* self,
- ShadowFrame& shadow_frame,
- Handle<mirror::MethodHandle> method_handle,
- Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
- JValue* result)
+bool MethodHandleInvoke(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::MethodHandle> method_handle,
+ Handle<mirror::MethodType> callsite_type,
+ const InstructionOperands* const operands,
+ JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (UNLIKELY(callsite_type->IsExactMatch(method_handle->GetMethodType()))) {
// A non-exact invoke that can be invoked exactly.
- return MethodHandleInvokeExactInternal<is_range>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- first_arg,
- result);
+ return MethodHandleInvokeExactInternal(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ operands,
+ result);
} else {
- return MethodHandleInvokeInternal<is_range>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- first_arg,
- result);
+ return MethodHandleInvokeInternal(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ operands,
+ result);
}
}
-template <bool is_range>
bool MethodHandleInvokeExact(Thread* self,
- ShadowFrame& shadow_frame,
- Handle<mirror::MethodHandle> method_handle,
- Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
- JValue* result)
+ ShadowFrame& shadow_frame,
+ Handle<mirror::MethodHandle> method_handle,
+ Handle<mirror::MethodType> callsite_type,
+ const InstructionOperands* const operands,
+ JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
// We need to check the nominal type of the handle in addition to the
// real type. The "nominal" type is present when MethodHandle.asType is
@@ -1160,39 +1124,20 @@ bool MethodHandleInvokeExact(Thread* self,
}
if (LIKELY(!nominal_type->IsExactMatch(method_handle->GetMethodType()))) {
// Different nominal type means we have to treat as non-exact.
- return MethodHandleInvokeInternal<is_range>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- first_arg,
- result);
+ return MethodHandleInvokeInternal(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ operands,
+ result);
}
}
- return MethodHandleInvokeExactInternal<is_range>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- first_arg,
- result);
+ return MethodHandleInvokeExactInternal(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ operands,
+ result);
}
-#define EXPLICIT_DO_METHOD_HANDLE_METHOD(_name, _is_range) \
- template REQUIRES_SHARED(Locks::mutator_lock_) \
- bool MethodHandle##_name<_is_range>( \
- Thread* self, \
- ShadowFrame& shadow_frame, \
- Handle<mirror::MethodHandle> method_handle, \
- Handle<mirror::MethodType> callsite_type, \
- const uint32_t (&args)[Instruction::kMaxVarArgRegs], \
- uint32_t first_arg, \
- JValue* result)
-
-EXPLICIT_DO_METHOD_HANDLE_METHOD(Invoke, true);
-EXPLICIT_DO_METHOD_HANDLE_METHOD(Invoke, false);
-EXPLICIT_DO_METHOD_HANDLE_METHOD(InvokeExact, true);
-EXPLICIT_DO_METHOD_HANDLE_METHOD(InvokeExact, false);
-#undef EXPLICIT_DO_METHOD_HANDLE_METHOD
-
} // namespace art
diff --git a/runtime/method_handles.h b/runtime/method_handles.h
index 930b8db63e..bc74bf23d2 100644
--- a/runtime/method_handles.h
+++ b/runtime/method_handles.h
@@ -126,50 +126,40 @@ bool PerformConversions(Thread* self,
int32_t num_conversions) REQUIRES_SHARED(Locks::mutator_lock_);
// A convenience class that allows for iteration through a list of
-// input argument registers |arg| for non-range invokes or a list of
-// consecutive registers starting with a given based for range
-// invokes.
-//
-// This is used to iterate over input arguments while performing standard
-// argument conversions.
-template <bool is_range>
+// input argument registers. This is used to iterate over input
+// arguments while performing standard argument conversions.
class ShadowFrameGetter {
public:
- ShadowFrameGetter(size_t first_src_reg,
- const uint32_t (&arg)[Instruction::kMaxVarArgRegs],
- const ShadowFrame& shadow_frame) :
- first_src_reg_(first_src_reg),
- arg_(arg),
- shadow_frame_(shadow_frame),
- arg_index_(0) {
- }
+ ShadowFrameGetter(const InstructionOperands* const operands, const ShadowFrame& shadow_frame)
+ : operands_(operands), operand_index_(0), shadow_frame_(shadow_frame) {}
ALWAYS_INLINE uint32_t Get() REQUIRES_SHARED(Locks::mutator_lock_) {
- const uint32_t next = (is_range ? first_src_reg_ + arg_index_ : arg_[arg_index_]);
- ++arg_index_;
-
- return shadow_frame_.GetVReg(next);
+ return shadow_frame_.GetVReg(Next());
}
ALWAYS_INLINE int64_t GetLong() REQUIRES_SHARED(Locks::mutator_lock_) {
- const uint32_t next = (is_range ? first_src_reg_ + arg_index_ : arg_[arg_index_]);
- arg_index_ += 2;
-
- return shadow_frame_.GetVRegLong(next);
+ return shadow_frame_.GetVRegLong(NextLong());
}
ALWAYS_INLINE ObjPtr<mirror::Object> GetReference() REQUIRES_SHARED(Locks::mutator_lock_) {
- const uint32_t next = (is_range ? first_src_reg_ + arg_index_ : arg_[arg_index_]);
- ++arg_index_;
-
- return shadow_frame_.GetVRegReference(next);
+ return shadow_frame_.GetVRegReference(Next());
}
private:
- const size_t first_src_reg_;
- const uint32_t (&arg_)[Instruction::kMaxVarArgRegs];
+ uint32_t Next() {
+ const uint32_t next = operands_->GetOperand(operand_index_);
+ operand_index_ += 1;
+ return next;
+ }
+ uint32_t NextLong() {
+ const uint32_t next = operands_->GetOperand(operand_index_);
+ operand_index_ += 2;
+ return next;
+ }
+
+ const InstructionOperands* const operands_;
+ size_t operand_index_; // the next register operand to read from frame
const ShadowFrame& shadow_frame_;
- size_t arg_index_;
};
// A convenience class that allows values to be written to a given shadow frame,
@@ -201,23 +191,19 @@ class ShadowFrameSetter {
size_t arg_index_;
};
-template <bool is_range>
bool MethodHandleInvoke(Thread* self,
ShadowFrame& shadow_frame,
Handle<mirror::MethodHandle> method_handle,
Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
+ const InstructionOperands* const args,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
-template <bool is_range>
bool MethodHandleInvokeExact(Thread* self,
ShadowFrame& shadow_frame,
Handle<mirror::MethodHandle> method_handle,
Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
+ const InstructionOperands* const args,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/mirror/emulated_stack_frame.cc b/runtime/mirror/emulated_stack_frame.cc
index f82bfbfaef..5757992167 100644
--- a/runtime/mirror/emulated_stack_frame.cc
+++ b/runtime/mirror/emulated_stack_frame.cc
@@ -139,14 +139,12 @@ class EmulatedStackFrameAccessor {
DISALLOW_COPY_AND_ASSIGN(EmulatedStackFrameAccessor);
};
-template <bool is_range>
mirror::EmulatedStackFrame* EmulatedStackFrame::CreateFromShadowFrameAndArgs(
Thread* self,
Handle<mirror::MethodType> caller_type,
Handle<mirror::MethodType> callee_type,
const ShadowFrame& caller_frame,
- const uint32_t first_src_reg,
- const uint32_t (&arg)[Instruction::kMaxVarArgRegs]) {
+ const InstructionOperands* const operands) {
StackHandleScope<6> hs(self);
// Step 1: We must throw a WrongMethodTypeException if there's a mismatch in the
@@ -185,9 +183,9 @@ mirror::EmulatedStackFrame* EmulatedStackFrame::CreateFromShadowFrameAndArgs(
}
// Step 4 : Perform argument conversions (if required).
- ShadowFrameGetter<is_range> getter(first_src_reg, arg, caller_frame);
+ ShadowFrameGetter getter(operands, caller_frame);
EmulatedStackFrameAccessor setter(references, stack_frame, stack_frame->GetLength());
- if (!PerformConversions<ShadowFrameGetter<is_range>, EmulatedStackFrameAccessor>(
+ if (!PerformConversions<ShadowFrameGetter, EmulatedStackFrameAccessor>(
self, caller_type, callee_type, &getter, &setter, num_method_params)) {
return nullptr;
}
@@ -289,21 +287,5 @@ void EmulatedStackFrame::VisitRoots(RootVisitor* visitor) {
static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
}
-// Explicit CreateFromShadowFrameAndArgs template function declarations.
-#define EXPLICIT_CREATE_FROM_SHADOW_FRAME_AND_ARGS_DECL(_is_range) \
- template REQUIRES_SHARED(Locks::mutator_lock_) \
- mirror::EmulatedStackFrame* EmulatedStackFrame::CreateFromShadowFrameAndArgs<_is_range>( \
- Thread* self, \
- Handle<mirror::MethodType> caller_type, \
- Handle<mirror::MethodType> callee_type, \
- const ShadowFrame& caller_frame, \
- const uint32_t first_src_reg, \
- const uint32_t (&arg)[Instruction::kMaxVarArgRegs]) \
-
-EXPLICIT_CREATE_FROM_SHADOW_FRAME_AND_ARGS_DECL(true);
-EXPLICIT_CREATE_FROM_SHADOW_FRAME_AND_ARGS_DECL(false);
-#undef EXPLICIT_CREATE_FROM_SHADOW_FRAME_AND_ARGS_DECL
-
-
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/emulated_stack_frame.h b/runtime/mirror/emulated_stack_frame.h
index 76859ef1c8..b6aa949ec3 100644
--- a/runtime/mirror/emulated_stack_frame.h
+++ b/runtime/mirror/emulated_stack_frame.h
@@ -35,14 +35,12 @@ class MANAGED EmulatedStackFrame : public Object {
public:
// Creates an emulated stack frame whose type is |frame_type| from
// a shadow frame.
- template <bool is_range>
static mirror::EmulatedStackFrame* CreateFromShadowFrameAndArgs(
Thread* self,
Handle<mirror::MethodType> args_type,
Handle<mirror::MethodType> frame_type,
const ShadowFrame& caller_frame,
- const uint32_t first_src_reg,
- const uint32_t (&arg)[Instruction::kMaxVarArgRegs]) REQUIRES_SHARED(Locks::mutator_lock_);
+ const InstructionOperands* const operands) REQUIRES_SHARED(Locks::mutator_lock_);
// Writes the contents of this emulated stack frame to the |callee_frame|
// whose type is |callee_type|, starting at |first_dest_reg|.