summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/method_handles.cc508
-rw-r--r--runtime/mirror/emulated_stack_frame.cc6
-rw-r--r--runtime/mirror/emulated_stack_frame.h2
3 files changed, 171 insertions, 345 deletions
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index c8e6287804..a775763b16 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -34,6 +34,7 @@
#include "reflection-inl.h"
#include "reflection.h"
#include "thread.h"
+#include "var_handles.h"
#include "well_known_classes.h"
namespace art {
@@ -336,24 +337,6 @@ inline void CopyArgumentsFromCallerFrame(const ShadowFrame& caller_frame,
}
}
-inline bool IsInvoke(const mirror::MethodHandle::Kind handle_kind) {
- return handle_kind <= mirror::MethodHandle::Kind::kLastInvokeKind;
-}
-
-inline bool IsInvokeTransform(const mirror::MethodHandle::Kind handle_kind) {
- return (handle_kind == mirror::MethodHandle::Kind::kInvokeTransform);
-}
-
-inline bool IsInvokeVarHandle(const mirror::MethodHandle::Kind handle_kind) {
- return (handle_kind == mirror::MethodHandle::Kind::kInvokeVarHandle ||
- handle_kind == mirror::MethodHandle::Kind::kInvokeVarHandleExact);
-}
-
-inline bool IsFieldAccess(mirror::MethodHandle::Kind handle_kind) {
- return (handle_kind >= mirror::MethodHandle::Kind::kFirstAccessorKind
- && handle_kind <= mirror::MethodHandle::Kind::kLastAccessorKind);
-}
-
// Calculate the number of ins for a proxy or native method, where we
// can't just look at the code item.
static inline size_t GetInsForProxyOrNativeMethod(ArtMethod* method)
@@ -391,40 +374,10 @@ static inline bool InvokedFromTransform(Handle<mirror::MethodType> callsite_type
return false;
}
-static inline bool MethodHandleInvokeMethod(ArtMethod* called_method,
- Thread* self,
- ShadowFrame& caller_frame,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- // Compute method information.
- CodeItemDataAccessor accessor(called_method->DexInstructionData());
- size_t first_dst_reg;
- if (LIKELY(accessor.HasCodeItem())) {
- uint16_t num_regs = accessor.RegistersSize();
- first_dst_reg = num_regs - accessor.InsSize();
- // Parameter registers go at the end of the shadow frame.
- DCHECK_NE(first_dst_reg, (size_t)-1);
- } else {
- // No local regs for proxy and native methods.
- DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
- first_dst_reg = 0;
- }
-
- PerformCall(self,
- accessor,
- caller_frame.GetMethod(),
- first_dst_reg,
- &caller_frame,
- result,
- interpreter::ShouldStayInSwitchInterpreter(called_method));
- return !self->IsExceptionPending();
-}
-
-static inline bool MethodHandleInvokeTransform(ArtMethod* called_method,
- Handle<mirror::MethodType> callsite_type,
- Handle<mirror::MethodType> callee_type,
- Thread* self,
+static inline bool MethodHandleInvokeTransform(Thread* self,
ShadowFrame& shadow_frame,
- Handle<mirror::MethodHandle> receiver,
+ Handle<mirror::MethodHandle> method_handle,
+ Handle<mirror::MethodType> callsite_type,
const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -435,44 +388,34 @@ static inline bool MethodHandleInvokeTransform(ArtMethod* called_method,
// private MethodHandle.transformInternal(EmulatedStackFrame sf);
//
// This means we need only two vregs :
- // - One for the receiver object.
+ // - One for the method_handle object.
// - One for the only method argument (an EmulatedStackFrame).
static constexpr size_t kNumRegsForTransform = 2;
+ ArtMethod* called_method = method_handle->GetTargetMethod();
CodeItemDataAccessor accessor(called_method->DexInstructionData());
DCHECK_EQ(kNumRegsForTransform, accessor.RegistersSize());
DCHECK_EQ(kNumRegsForTransform, accessor.InsSize());
- ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
- CREATE_SHADOW_FRAME(kNumRegsForTransform, &shadow_frame, called_method, /* dex pc */ 0);
- ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get();
- StackHandleScope<1> hs(self);
- MutableHandle<mirror::EmulatedStackFrame> sf(hs.NewHandle<mirror::EmulatedStackFrame>(nullptr));
- if (InvokedFromTransform(callsite_type)) {
- // 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 = operands->GetOperand(0);
- sf.Assign(ObjPtr<mirror::EmulatedStackFrame>::DownCast(
- shadow_frame.GetVRegReference(first_callee_register)));
- } else {
- 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.
- if (sf == nullptr) {
- DCHECK(self->IsExceptionPending());
- return false;
- }
+ StackHandleScope<2> hs(self);
+ Handle<mirror::MethodType> callee_type(hs.NewHandle(method_handle->GetMethodType()));
+ Handle<mirror::EmulatedStackFrame> sf(
+ hs.NewHandle<mirror::EmulatedStackFrame>(
+ mirror::EmulatedStackFrame::CreateFromShadowFrameAndArgs(
+ self, callsite_type, callee_type, shadow_frame, operands)));
+ if (sf == nullptr) {
+ DCHECK(self->IsExceptionPending());
+ return false;
}
- new_shadow_frame->SetVRegReference(0, receiver.Get());
+ const char* old_cause = self->StartAssertNoThreadSuspension("MethodHandleInvokeTransform");
+ ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
+ CREATE_SHADOW_FRAME(kNumRegsForTransform, &shadow_frame, called_method, /* dex pc */ 0);
+ ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get();
+ new_shadow_frame->SetVRegReference(0, method_handle.Get());
new_shadow_frame->SetVRegReference(1, sf.Get());
+ self->EndAssertNoThreadSuspension(old_cause);
PerformCall(self,
accessor,
@@ -488,7 +431,7 @@ static inline bool MethodHandleInvokeTransform(ArtMethod* called_method,
// If the called transformer method we called has returned a value, then we
// need to copy it back to |result|.
sf->GetReturnValue(self, result);
- return ConvertReturnValue(callsite_type, callee_type, result);
+ return true;
}
inline static ObjPtr<mirror::Class> GetAndInitializeDeclaringClass(Thread* self, ArtField* field)
@@ -512,23 +455,14 @@ inline static ObjPtr<mirror::Class> GetAndInitializeDeclaringClass(Thread* self,
ArtMethod* RefineTargetMethod(Thread* self,
ShadowFrame& shadow_frame,
const mirror::MethodHandle::Kind& handle_kind,
- Handle<mirror::MethodType> handle_type,
- Handle<mirror::MethodType> callsite_type,
+ ObjPtr<mirror::MethodType> handle_type,
const uint32_t receiver_reg,
- ArtMethod* target_method)
- REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* target_method) REQUIRES_SHARED(Locks::mutator_lock_) {
if (handle_kind == mirror::MethodHandle::Kind::kInvokeVirtual ||
handle_kind == mirror::MethodHandle::Kind::kInvokeInterface) {
// For virtual and interface methods ensure target_method points to
// the actual method to invoke.
ObjPtr<mirror::Object> receiver(shadow_frame.GetVRegReference(receiver_reg));
- if (InvokedFromTransform(callsite_type)) {
- // The current receiver is an emulated stack frame, the method's
- // receiver needs to be fetched from there as the emulated frame
- // will be unpacked into a new frame.
- receiver = ObjPtr<mirror::EmulatedStackFrame>::DownCast(receiver)->GetReceiver();
- }
-
ObjPtr<mirror::Class> declaring_class(target_method->GetDeclaringClass());
if (receiver == nullptr || receiver->GetClass() != declaring_class) {
// Verify that _vRegC is an object reference and of the type expected by
@@ -578,58 +512,13 @@ ArtMethod* RefineTargetMethod(Thread* self,
return target_method;
}
-bool DoInvokePolymorphicMethod(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_) {
- StackHandleScope<2> hs(self);
- Handle<mirror::MethodType> handle_type(hs.NewHandle(method_handle->GetMethodType()));
- const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
- DCHECK(IsInvoke(handle_kind));
-
- // Get the method we're actually invoking along with the kind of
- // invoke that is desired. We don't need to perform access checks at this
- // 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 = (operands->GetNumberOfOperands() > 0) ? operands->GetOperand(0) : 0u;
- ArtMethod* called_method = RefineTargetMethod(self,
- shadow_frame,
- handle_kind,
- handle_type,
- callsite_type,
- receiver_reg,
- target_method);
- if (called_method == nullptr) {
- DCHECK(self->IsExceptionPending());
- return false;
- }
-
- if (IsInvokeTransform(handle_kind)) {
- return MethodHandleInvokeTransform(called_method,
- callsite_type,
- handle_type,
- self,
- shadow_frame,
- /* receiver= */ method_handle,
- operands,
- result);
- } else {
- return MethodHandleInvokeMethod(called_method, self, shadow_frame, result);
- }
-}
-
// Helper for getters in invoke-polymorphic.
inline static void MethodHandleFieldGet(Thread* self,
const ShadowFrame& shadow_frame,
ObjPtr<mirror::Object>& obj,
ArtField* field,
Primitive::Type field_type,
- JValue* result)
- REQUIRES_SHARED(Locks::mutator_lock_) {
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
switch (field_type) {
case Primitive::kPrimBoolean:
DoFieldGetCommon<Primitive::kPrimBoolean>(self, shadow_frame, obj, field, result);
@@ -670,8 +559,7 @@ inline bool MethodHandleFieldPut(Thread* self,
ObjPtr<mirror::Object>& obj,
ArtField* field,
Primitive::Type field_type,
- JValue& value)
- REQUIRES_SHARED(Locks::mutator_lock_) {
+ JValue& value) REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(!Runtime::Current()->IsActiveTransaction());
static const bool kTransaction = false; // Not in a transaction.
static const bool kAssignabilityCheck = false; // No access check.
@@ -708,8 +596,7 @@ inline bool MethodHandleFieldPut(Thread* self,
static JValue GetValueFromShadowFrame(const ShadowFrame& shadow_frame,
Primitive::Type field_type,
- uint32_t vreg)
- REQUIRES_SHARED(Locks::mutator_lock_) {
+ uint32_t vreg) REQUIRES_SHARED(Locks::mutator_lock_) {
JValue field_value;
switch (field_type) {
case Primitive::kPrimBoolean:
@@ -803,45 +690,12 @@ bool MethodHandleFieldAccess(Thread* self,
}
}
-bool DoVarHandleInvokeTranslationUnchecked(Thread* self,
- ShadowFrame& shadow_frame,
- mirror::VarHandle::AccessMode access_mode,
- Handle<mirror::VarHandle> vh,
- Handle<mirror::MethodType> vh_type,
- Handle<mirror::MethodType> callsite_type,
- const InstructionOperands* const operands,
- JValue* result)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- DCHECK_EQ(operands->GetNumberOfOperands(), vh_type->NumberOfVRegs());
- DCHECK_EQ(operands->GetNumberOfOperands(), callsite_type->NumberOfVRegs());
- if (!vh->IsAccessModeSupported(access_mode)) {
- ThrowUnsupportedOperationException();
- return false;
- }
-
- const size_t vreg_count = vh_type->NumberOfVRegs();
- ShadowFrameAllocaUniquePtr accessor_frame =
- CREATE_SHADOW_FRAME(vreg_count, nullptr, shadow_frame.GetMethod(), shadow_frame.GetDexPC());
- ShadowFrameGetter getter(shadow_frame, operands);
- static const uint32_t kFirstAccessorReg = 0;
- ShadowFrameSetter setter(accessor_frame.get(), kFirstAccessorReg);
- if (!PerformConversions(self, callsite_type, vh_type, &getter, &setter)) {
- return false;
- }
- RangeInstructionOperands accessor_operands(kFirstAccessorReg, kFirstAccessorReg + vreg_count);
- if (!vh->Access(access_mode, accessor_frame.get(), &accessor_operands, result)) {
- return false;
- }
- return ConvertReturnValue(callsite_type, vh_type, result);
-}
-
bool DoVarHandleInvokeTranslation(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_) {
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
//
// Basic checks that apply in all cases.
//
@@ -884,86 +738,37 @@ bool DoVarHandleInvokeTranslation(Thread* self,
ThrowWrongMethodTypeException(vh_type.Get(), mh_invoke_type.Get());
return false;
}
- } else {
- DCHECK_EQ(method_handle->GetHandleKind(), mirror::MethodHandle::Kind::kInvokeVarHandle);
- if (!mh_invoke_type->IsConvertible(vh_type.Get())) {
- ThrowWrongMethodTypeException(vh_type.Get(), mh_invoke_type.Get());
- return false;
- }
}
Handle<mirror::MethodType> callsite_type_without_varhandle =
hs.NewHandle(mirror::MethodType::CloneWithoutLeadingParameter(self, callsite_type.Get()));
NoReceiverInstructionOperands varhandle_operands(operands);
- return DoVarHandleInvokeTranslationUnchecked(self,
- shadow_frame,
- access_mode,
- vh,
- vh_type,
- callsite_type_without_varhandle,
- &varhandle_operands,
- result);
+ return VarHandleInvokeAccessor(self,
+ shadow_frame,
+ vh,
+ callsite_type_without_varhandle,
+ access_mode,
+ &varhandle_operands,
+ result);
}
-static inline bool MethodHandleInvokeExactInternal(
- 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_) {
- StackHandleScope<1> hs(self);
- Handle<mirror::MethodType> method_handle_type(hs.NewHandle(method_handle->GetMethodType()));
- const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
-
- if (!callsite_type->IsExactMatch(method_handle_type.Get())) {
- ThrowWrongMethodTypeException(method_handle_type.Get(), callsite_type.Get());
- return false;
- }
-
- if (IsFieldAccess(handle_kind)) {
- return MethodHandleFieldAccess(self,
- shadow_frame,
- method_handle,
- callsite_type,
- operands,
- result);
- }
-
- // Slow-path check.
- if (IsInvokeTransform(handle_kind) ||
- InvokedFromTransform(callsite_type)) {
- return DoInvokePolymorphicMethod(self,
- shadow_frame,
- method_handle,
- callsite_type,
- operands,
- result);
- } else if (IsInvokeVarHandle(handle_kind)) {
- return DoVarHandleInvokeTranslation(self,
- shadow_frame,
- method_handle,
- callsite_type,
- operands,
- result);
- }
-
- // On the fast-path. This is equivalent to DoCallPolymorphic without the conversion paths.
+static bool DoMethodHandleInvokeMethod(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::MethodHandle> method_handle,
+ const InstructionOperands* const operands,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
ArtMethod* target_method = method_handle->GetTargetMethod();
uint32_t receiver_reg = (operands->GetNumberOfOperands() > 0) ? operands->GetOperand(0) : 0u;
ArtMethod* called_method = RefineTargetMethod(self,
shadow_frame,
- handle_kind,
- method_handle_type,
- callsite_type,
+ method_handle->GetHandleKind(),
+ method_handle->GetMethodType(),
receiver_reg,
target_method);
if (called_method == nullptr) {
DCHECK(self->IsExceptionPending());
return false;
}
-
// Compute method information.
CodeItemDataAccessor accessor(called_method->DexInstructionData());
uint16_t num_regs;
@@ -980,8 +785,7 @@ static inline bool MethodHandleInvokeExactInternal(
first_dest_reg = 0;
}
- // Allocate shadow frame on the stack.
- const char* old_cause = self->StartAssertNoThreadSuspension("DoCallCommon");
+ const char* old_cause = self->StartAssertNoThreadSuspension("DoMethodHandleInvokeMethod");
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();
@@ -993,7 +797,7 @@ static inline bool MethodHandleInvokeExactInternal(
PerformCall(self,
accessor,
- called_method,
+ shadow_frame.GetMethod(),
first_dest_reg,
new_shadow_frame,
result,
@@ -1004,57 +808,132 @@ static inline bool MethodHandleInvokeExactInternal(
return true;
}
-template <typename T>
-bool InvokeInContext(Thread* self,
- ShadowFrame& shadow_frame,
- Handle<mirror::MethodHandle> method_handle,
- Handle<mirror::MethodType> callsite_type,
- const InstructionOperands* const operands,
- JValue* result,
- T invoker) REQUIRES_SHARED(Locks::mutator_lock_) {
- if (!InvokedFromTransform(callsite_type) || IsInvokeTransform(method_handle->GetHandleKind())) {
- return invoker(self, shadow_frame, method_handle, callsite_type, operands, result);
+static bool MethodHandleInvokeExactInternal(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 (!callsite_type->IsExactMatch(method_handle->GetMethodType())) {
+ ThrowWrongMethodTypeException(method_handle->GetMethodType(), callsite_type.Get());
+ return false;
}
+ switch (method_handle->GetHandleKind()) {
+ case mirror::MethodHandle::Kind::kInvokeDirect:
+ case mirror::MethodHandle::Kind::kInvokeInterface:
+ case mirror::MethodHandle::Kind::kInvokeStatic:
+ case mirror::MethodHandle::Kind::kInvokeSuper:
+ case mirror::MethodHandle::Kind::kInvokeVirtual:
+ return DoMethodHandleInvokeMethod(self, shadow_frame, method_handle, operands, result);
+ case mirror::MethodHandle::Kind::kInstanceGet:
+ case mirror::MethodHandle::Kind::kInstancePut:
+ case mirror::MethodHandle::Kind::kStaticGet:
+ case mirror::MethodHandle::Kind::kStaticPut:
+ return MethodHandleFieldAccess(
+ self, shadow_frame, method_handle, callsite_type, operands, result);
+ case mirror::MethodHandle::Kind::kInvokeTransform:
+ return MethodHandleInvokeTransform(
+ self, shadow_frame, method_handle, callsite_type, operands, result);
+ case mirror::MethodHandle::Kind::kInvokeVarHandle:
+ case mirror::MethodHandle::Kind::kInvokeVarHandleExact:
+ return DoVarHandleInvokeTranslation(
+ self, shadow_frame, method_handle, callsite_type, operands, result);
+ }
+}
+
+static bool MethodHandleInvokeInternal(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_) {
+ StackHandleScope<2> hs(self);
+ Handle<mirror::MethodType> method_handle_type(hs.NewHandle(method_handle->GetMethodType()));
+ // Non-exact invoke behaves as calling mh.asType(newType). In ART, asType() is implemented
+ // as a transformer and it is expensive to call so check first if it's really necessary.
+ //
+ // There are two cases where the asType() transformation can be skipped:
+ //
+ // 1) the call site and type of the MethodHandle match, ie code is calling invoke()
+ // unnecessarily.
+ //
+ // 2) when the call site can be trivially converted to the MethodHandle type due to how
+ // values are represented in the ShadowFrame, ie all registers in the shadow frame are
+ // 32-bit, there is no byte, short, char, etc. So a call site with arguments of these
+ // kinds can be trivially converted to one with int arguments. Similarly if the reference
+ // types are assignable between the call site and MethodHandle type, then as asType()
+ // transformation isn't really doing any work.
+ //
+ // The following IsInPlaceConvertible check determines if either of these opportunities to
+ // skip asType() are true.
+ if (callsite_type->IsInPlaceConvertible(method_handle_type.Get())) {
+ return MethodHandleInvokeExact(
+ self, shadow_frame, method_handle, method_handle_type, operands, result);
+ }
+
+ // Use asType() variant of this MethodHandle to adapt callsite to the target.
+ MutableHandle<mirror::MethodHandle> atc(hs.NewHandle(method_handle->GetAsTypeCache()));
+ if (atc == nullptr || !callsite_type->IsExactMatch(atc->GetMethodType())) {
+ // Cached asType adapter does not exist or is for another call site. Call
+ // MethodHandle::asType() to get an appropriate adapter.
+ ArtMethod* as_type =
+ jni::DecodeArtMethod(WellKnownClasses::java_lang_invoke_MethodHandle_asType);
+ uint32_t as_type_args[] = {
+ static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method_handle.Get())),
+ static_cast<uint32_t>(reinterpret_cast<uintptr_t>(callsite_type.Get()))};
+ JValue atc_result;
+ as_type->Invoke(self, as_type_args, sizeof(as_type_args), &atc_result, "LL");
+ if (atc_result.GetL() == nullptr) {
+ DCHECK(self->IsExceptionPending());
+ return false;
+ }
+ ObjPtr<mirror::MethodHandle> atc_method_handle =
+ down_cast<mirror::MethodHandle*>(atc_result.GetL());
+ atc.Assign(atc_method_handle);
+ DCHECK(!atc.IsNull());
+ }
+
+ return MethodHandleInvokeExact(self, shadow_frame, atc, callsite_type, operands, result);
+}
+
+template <typename T>
+bool InvokeFromTransform(Thread* self,
+ ShadowFrame& caller_frame,
+ Handle<mirror::MethodHandle> method_handle,
+ const InstructionOperands* const caller_operands,
+ JValue* result,
+ T invoker) REQUIRES_SHARED(Locks::mutator_lock_) {
// The MethodHandle invocation has occurred within a Transformer that has created an emulated
// stack frame as context with which to invoke the MethodHandle. We need to unpack this, then
// invoke the MethodHandle in the provided context.
StackHandleScope<2> hs(self);
- size_t first_argument_vreg = operands->GetOperand(0);
- Handle<mirror::EmulatedStackFrame> emulated_stack_frame =
+ const size_t emulated_frame_vreg = caller_operands->GetOperand(0);
+ Handle<mirror::EmulatedStackFrame> emulated_frame =
hs.NewHandle(ObjPtr<mirror::EmulatedStackFrame>::DownCast(
- shadow_frame.GetVRegReference(first_argument_vreg)));
- Handle<mirror::MethodType> effective_callsite_type =
- hs.NewHandle(emulated_stack_frame->GetType());
- uint16_t num_vregs = effective_callsite_type->NumberOfVRegs();
+ caller_frame.GetVRegReference(emulated_frame_vreg)));
+ Handle<mirror::MethodType> callsite_type = hs.NewHandle(emulated_frame->GetType());
+ const uint16_t num_vregs = callsite_type->NumberOfVRegs();
+ const RangeInstructionOperands operands(0, num_vregs);
- RangeInstructionOperands effective_operands(0, num_vregs);
+ const char* old_cause = self->StartAssertNoThreadSuspension("InvokeFromTransform");
ArtMethod* called_method = method_handle->GetTargetMethod(); // invoke / invokeExact.
- // Create a shadow frame
- ShadowFrameAllocaUniquePtr effective_frame =
- CREATE_SHADOW_FRAME(num_vregs, &shadow_frame, called_method, shadow_frame.GetDexPC());
- if (UNLIKELY(effective_operands.GetNumberOfOperands() != 0 &&
- !emulated_stack_frame->WriteToShadowFrame(self,
- effective_callsite_type,
- effective_operands.GetOperand(0),
- effective_frame.get()))) {
- DCHECK(self->IsExceptionPending());
- result->SetL(nullptr);
- return false;
+ ShadowFrameAllocaUniquePtr shadow_frame =
+ CREATE_SHADOW_FRAME(num_vregs, &caller_frame, called_method, caller_frame.GetDexPC());
+ if (num_vregs > 0) {
+ emulated_frame->WriteToShadowFrame(
+ self, callsite_type, operands.GetOperand(0), shadow_frame.get());
}
+ self->EndAssertNoThreadSuspension(old_cause);
+ // Make the created frame visible to the GC.
ScopedStackedShadowFramePusher pusher(
- self, effective_frame.get(), StackedShadowFrameType::kShadowFrameUnderConstruction);
+ self, shadow_frame.get(), StackedShadowFrameType::kShadowFrameUnderConstruction);
// Invoke MethodHandle in newly created context
- bool success = invoker(self,
- *effective_frame.get(),
- method_handle,
- effective_callsite_type,
- &effective_operands,
- result);
+ bool success = invoker(self, *shadow_frame, method_handle, callsite_type, &operands, result);
if (success) {
- emulated_stack_frame->SetReturnValue(self, *result);
+ emulated_frame->SetReturnValue(self, *result);
}
return success;
}
@@ -1067,59 +946,13 @@ bool MethodHandleInvoke(Thread* self,
Handle<mirror::MethodType> callsite_type,
const InstructionOperands* const operands,
JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- auto invoke = [](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_) {
- StackHandleScope<2> hs(self);
- Handle<mirror::MethodType> method_handle_type(hs.NewHandle(method_handle->GetMethodType()));
-
- // Non-exact invoke behaves as calling mh.asType(newType). In ART, asType() is implemented
- // as a transformer and it is expensive to call so check first if it's really necessary.
- //
- // There are two cases where the asType() transformation can be skipped:
- //
- // 1) the call site and type of the MethodHandle match, ie code is calling invoke()
- // unnecessarily.
- //
- // 2) when the call site can be trivally converted to the MethodHandle type due to how
- // values are represented in the ShadowFrame, ie all registers in the shadow frame are
- // 32-bit, there is no byte, short, char, etc. So a call site with arguments of these
- // kinds can be trivially converted to one with int arguments. Similarly if the reference
- // types are assignable between the call site and MethodHandle type, then as asType()
- // transformation isn't really doing any work.
- if (callsite_type->IsInPlaceConvertible(method_handle_type.Get())) {
- return MethodHandleInvokeExact(
- self, shadow_frame, method_handle, method_handle_type, operands, result);
- }
-
- // Use asType() variant of this MethodHandle to adapt callsite to the target.
- MutableHandle<mirror::MethodHandle> atc(hs.NewHandle(method_handle->GetAsTypeCache()));
- if (atc == nullptr || !callsite_type->IsExactMatch(atc->GetMethodType())) {
- // Cached asType adapter does not exist or is for another call site. Call
- // MethodHandle::asType() to get an appropriate adapter.
- ArtMethod* as_type =
- jni::DecodeArtMethod(WellKnownClasses::java_lang_invoke_MethodHandle_asType);
- uint32_t as_type_args[] = {
- static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method_handle.Get())),
- static_cast<uint32_t>(reinterpret_cast<uintptr_t>(callsite_type.Get()))};
- JValue atc_result;
- as_type->Invoke(self, as_type_args, sizeof(as_type_args), &atc_result, "LL");
- if (atc_result.GetL() == nullptr) {
- DCHECK(self->IsExceptionPending());
- return false;
- }
- ObjPtr<mirror::MethodHandle> atc_method_handle =
- down_cast<mirror::MethodHandle*>(atc_result.GetL());
- atc.Assign(atc_method_handle);
- DCHECK(!atc.IsNull());
- }
- return MethodHandleInvokeExact(self, shadow_frame, atc, callsite_type, operands, result);
- };
- return InvokeInContext(
- self, shadow_frame, method_handle, callsite_type, operands, result, invoke);
+ if (InvokedFromTransform(callsite_type)) {
+ return InvokeFromTransform(
+ self, shadow_frame, method_handle, operands, result, MethodHandleInvokeInternal);
+ } else {
+ return MethodHandleInvokeInternal(
+ self, shadow_frame, method_handle, callsite_type, operands, result);
+ }
}
bool MethodHandleInvokeExact(Thread* self,
@@ -1127,19 +960,14 @@ bool MethodHandleInvokeExact(Thread* self,
Handle<mirror::MethodHandle> method_handle,
Handle<mirror::MethodType> callsite_type,
const InstructionOperands* const operands,
- JValue* result)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- auto invoke = [](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_) {
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (InvokedFromTransform(callsite_type)) {
+ return InvokeFromTransform(
+ self, shadow_frame, method_handle, operands, result, MethodHandleInvokeExactInternal);
+ } else {
return MethodHandleInvokeExactInternal(
self, shadow_frame, method_handle, callsite_type, operands, result);
- };
- return InvokeInContext(
- self, shadow_frame, method_handle, callsite_type, operands, result, invoke);
+ }
}
} // namespace art
diff --git a/runtime/mirror/emulated_stack_frame.cc b/runtime/mirror/emulated_stack_frame.cc
index 933cd3632f..4bae657cfd 100644
--- a/runtime/mirror/emulated_stack_frame.cc
+++ b/runtime/mirror/emulated_stack_frame.cc
@@ -180,8 +180,7 @@ ObjPtr<mirror::EmulatedStackFrame> EmulatedStackFrame::CreateFromShadowFrameAndA
// Step 4 : Copy arguments.
ShadowFrameGetter getter(caller_frame, operands);
EmulatedStackFrameAccessor setter(references, stack_frame, stack_frame->GetLength());
- CopyArguments<ShadowFrameGetter, EmulatedStackFrameAccessor>(
- self, caller_type, &getter, &setter);
+ CopyArguments<ShadowFrameGetter, EmulatedStackFrameAccessor>(self, caller_type, &getter, &setter);
// Step 5: Construct the EmulatedStackFrame object.
Handle<EmulatedStackFrame> sf(hs.NewHandle(
@@ -193,7 +192,7 @@ ObjPtr<mirror::EmulatedStackFrame> EmulatedStackFrame::CreateFromShadowFrameAndA
return sf.Get();
}
-bool EmulatedStackFrame::WriteToShadowFrame(Thread* self,
+void EmulatedStackFrame::WriteToShadowFrame(Thread* self,
Handle<mirror::MethodType> callee_type,
const uint32_t first_dest_reg,
ShadowFrame* callee_frame) {
@@ -207,7 +206,6 @@ bool EmulatedStackFrame::WriteToShadowFrame(Thread* self,
ShadowFrameSetter setter(callee_frame, first_dest_reg);
CopyArguments<EmulatedStackFrameAccessor, ShadowFrameSetter>(self, callee_type, &getter, &setter);
- return true;
}
void EmulatedStackFrame::GetReturnValue(Thread* self, JValue* value) {
diff --git a/runtime/mirror/emulated_stack_frame.h b/runtime/mirror/emulated_stack_frame.h
index fef6e3fad9..590f653506 100644
--- a/runtime/mirror/emulated_stack_frame.h
+++ b/runtime/mirror/emulated_stack_frame.h
@@ -47,7 +47,7 @@ class MANAGED EmulatedStackFrame : public Object {
// Writes the contents of this emulated stack frame to the |callee_frame|
// whose type is |callee_type|, starting at |first_dest_reg|.
- bool WriteToShadowFrame(
+ void WriteToShadowFrame(
Thread* self,
Handle<mirror::MethodType> callee_type,
const uint32_t first_dest_reg,