Revert^2 "MethodHandle composability fix"
This reverts commit 6ed5c4f64809902169a8943aa1671085bf423c31.
Reason for revert: no longer calling abstract method.
Bug: 206407164
Test: art/tools/buildbot-build.sh --host
Test: art/tools/run-libcore-tests.sh --mode host --variant X32 --debug
Change-Id: I939ead996c4c03210e2bdfc2993a24fb01ee69c7
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 78e7561..bce5bf3 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -16,20 +16,24 @@
#include "method_handles-inl.h"
+#include "android-base/macros.h"
#include "android-base/stringprintf.h"
-
#include "class_root-inl.h"
#include "common_dex_operations.h"
#include "common_throws.h"
#include "interpreter/shadow_frame-inl.h"
+#include "interpreter/shadow_frame.h"
#include "jvalue-inl.h"
#include "mirror/class-inl.h"
#include "mirror/emulated_stack_frame-inl.h"
+#include "mirror/emulated_stack_frame.h"
#include "mirror/method_handle_impl-inl.h"
+#include "mirror/method_handle_impl.h"
#include "mirror/method_type-inl.h"
#include "mirror/var_handle.h"
#include "reflection-inl.h"
#include "reflection.h"
+#include "thread.h"
#include "well_known_classes.h"
namespace art {
@@ -402,7 +406,7 @@
// Returns true iff. the callsite type for a polymorphic invoke is transformer
// like, i.e that it has a single input argument whose type is
// dalvik.system.EmulatedStackFrame.
-static inline bool IsCallerTransformer(Handle<mirror::MethodType> callsite_type)
+static inline bool InvokedFromTransform(Handle<mirror::MethodType> callsite_type)
REQUIRES_SHARED(Locks::mutator_lock_) {
ObjPtr<mirror::ObjectArray<mirror::Class>> param_types(callsite_type->GetPTypes());
if (param_types->GetLength() == 1) {
@@ -474,7 +478,7 @@
// a single argument of type dalvik.system.EmulatedStackFrame. In that
// case, we'll have to unmarshal the EmulatedStackFrame into the
// new_shadow_frame and perform argument conversions on it.
- if (IsCallerTransformer(callsite_type)) {
+ if (InvokedFromTransform(callsite_type)) {
is_caller_transformer = true;
// The emulated stack frame is the first and only argument when we're coming
// through from a transformer.
@@ -582,7 +586,7 @@
StackHandleScope<1> hs(self);
MutableHandle<mirror::EmulatedStackFrame> sf(hs.NewHandle<mirror::EmulatedStackFrame>(nullptr));
- if (IsCallerTransformer(callsite_type)) {
+ 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.
@@ -657,7 +661,7 @@
// 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 (IsCallerTransformer(callsite_type)) {
+ 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.
@@ -1162,7 +1166,7 @@
// Slow-path check.
if (IsInvokeTransform(handle_kind) ||
- IsCallerTransformer(callsite_type)) {
+ InvokedFromTransform(callsite_type)) {
return DoInvokePolymorphicMethod(self,
shadow_frame,
method_handle,
@@ -1179,7 +1183,7 @@
result);
}
- // On the fast-path. This is equivalent to DoCallPolymoprhic without the conversion paths.
+ // On the fast-path. This is equivalent to DoCallPolymorphic without the conversion paths.
ArtMethod* target_method = method_handle->GetTargetMethod();
uint32_t receiver_reg = (operands->GetNumberOfOperands() > 0) ? operands->GetOperand(0) : 0u;
ArtMethod* called_method = RefineTargetMethod(self,
@@ -1227,7 +1231,7 @@
called_method, called_method->GetEntryPointFromQuickCompiledCode());
PerformCall(self,
accessor,
- shadow_frame.GetMethod(),
+ called_method,
first_dest_reg,
new_shadow_frame,
result,
@@ -1238,31 +1242,86 @@
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);
+ }
+
+ // 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 =
+ 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();
+
+ RangeInstructionOperands effective_operands(0, num_vregs);
+ 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;
+ }
+
+ ScopedStackedShadowFramePusher pusher(
+ self, effective_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);
+ if (success) {
+ emulated_stack_frame->SetReturnValue(self, *result);
+ }
+ return success;
+}
+
} // namespace
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(self,
- shadow_frame,
- method_handle,
- callsite_type,
- operands,
- result);
- } else {
- return MethodHandleInvokeInternal(self,
- shadow_frame,
- method_handle,
- callsite_type,
- operands,
- 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_) {
+ 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_) {
+ if (UNLIKELY(callsite_type->IsExactMatch(method_handle->GetMethodType()))) {
+ // A non-exact invoke that can be invoked exactly.
+ return MethodHandleInvokeExactInternal(
+ self, shadow_frame, method_handle, callsite_type, operands, result);
+ } else {
+ return MethodHandleInvokeInternal(
+ self, shadow_frame, method_handle, callsite_type, operands, result);
+ }
+ };
+ return InvokeInContext(
+ self, shadow_frame, method_handle, callsite_type, operands, result, invoke);
}
bool MethodHandleInvokeExact(Thread* self,
@@ -1272,32 +1331,33 @@
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
- // called any handle, and results in the declared type of the handle
- // changing.
- ObjPtr<mirror::MethodType> nominal_type(method_handle->GetNominalType());
- if (UNLIKELY(nominal_type != nullptr)) {
- if (UNLIKELY(!callsite_type->IsExactMatch(nominal_type.Ptr()))) {
- ThrowWrongMethodTypeException(nominal_type.Ptr(), callsite_type.Get());
- return false;
+ 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_) {
+ // 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
+ // called any handle, and results in the declared type of the handle
+ // changing.
+ ObjPtr<mirror::MethodType> nominal_type(method_handle->GetNominalType());
+ if (UNLIKELY(nominal_type != nullptr)) {
+ if (UNLIKELY(!callsite_type->IsExactMatch(nominal_type.Ptr()))) {
+ ThrowWrongMethodTypeException(nominal_type.Ptr(), callsite_type.Get());
+ return false;
+ }
+ if (LIKELY(!nominal_type->IsExactMatch(method_handle->GetMethodType()))) {
+ // Different nominal type means we have to treat as non-exact.
+ return MethodHandleInvokeInternal(
+ self, shadow_frame, method_handle, callsite_type, operands, result);
+ }
}
- if (LIKELY(!nominal_type->IsExactMatch(method_handle->GetMethodType()))) {
- // Different nominal type means we have to treat as non-exact.
- return MethodHandleInvokeInternal(self,
- shadow_frame,
- method_handle,
- callsite_type,
- operands,
- result);
- }
- }
- return MethodHandleInvokeExactInternal(self,
- shadow_frame,
- method_handle,
- callsite_type,
- operands,
- result);
+ 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