summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/Android.bp1
-rw-r--r--runtime/method_handles.cc106
-rw-r--r--runtime/method_handles.h6
-rw-r--r--runtime/native/java_lang_invoke_MethodHandle.cc48
-rw-r--r--runtime/native/java_lang_invoke_MethodHandle.h28
-rw-r--r--runtime/runtime.cc2
-rw-r--r--runtime/well_known_classes.cc3
-rw-r--r--runtime/well_known_classes.h1
-rw-r--r--test/958-methodhandle-stackframe/src-art/Main.java2
9 files changed, 128 insertions, 69 deletions
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 795ea04c2a..0e950b28a9 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -231,6 +231,7 @@ libart_cc_defaults {
"native/java_lang_Thread.cc",
"native/java_lang_Throwable.cc",
"native/java_lang_VMClassLoader.cc",
+ "native/java_lang_invoke_MethodHandle.cc",
"native/java_lang_invoke_MethodHandleImpl.cc",
"native/java_lang_ref_FinalizerReference.cc",
"native/java_lang_ref_Reference.cc",
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 185b9aea1f..1327a24905 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -357,23 +357,6 @@ static inline size_t GetInsForProxyOrNativeMethod(ArtMethod* method)
return num_ins;
}
-// 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 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) {
- ObjPtr<mirror::Class> param(param_types->GetWithoutChecks(0));
- // NB Comparing descriptor here as it appears faster in cycle simulation than using:
- // param == WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_EmulatedStackFrame)
- // Costs are 98 vs 173 cycles per invocation.
- return param->DescriptorEquals("Ldalvik/system/EmulatedStackFrame;");
- }
-
- return false;
-}
-
static inline bool MethodHandleInvokeTransform(Thread* self,
ShadowFrame& shadow_frame,
Handle<mirror::MethodHandle> method_handle,
@@ -893,48 +876,6 @@ static bool MethodHandleInvokeInternal(Thread* self,
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);
- const size_t emulated_frame_vreg = caller_operands->GetOperand(0);
- Handle<mirror::EmulatedStackFrame> emulated_frame =
- hs.NewHandle(ObjPtr<mirror::EmulatedStackFrame>::DownCast(
- 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);
-
- const char* old_cause = self->StartAssertNoThreadSuspension("InvokeFromTransform");
- ShadowFrameAllocaUniquePtr shadow_frame = CREATE_SHADOW_FRAME(num_vregs,
- &caller_frame,
- caller_frame.GetMethod(),
- 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, shadow_frame.get(), StackedShadowFrameType::kShadowFrameUnderConstruction);
-
- // Invoke MethodHandle in newly created context
- bool success = invoker(self, *shadow_frame, method_handle, callsite_type, &operands, result);
- if (success) {
- emulated_frame->SetReturnValue(self, *result);
- }
- return success;
-}
-
} // namespace
bool MethodHandleInvoke(Thread* self,
@@ -943,13 +884,8 @@ bool MethodHandleInvoke(Thread* self,
Handle<mirror::MethodType> callsite_type,
const InstructionOperands* const operands,
JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- 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,
@@ -958,13 +894,47 @@ bool MethodHandleInvokeExact(Thread* self,
Handle<mirror::MethodType> callsite_type,
const InstructionOperands* const operands,
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);
+}
+
+void MethodHandleInvokeExactWithFrame(Thread* self,
+ Handle<mirror::MethodHandle> method_handle,
+ Handle<mirror::EmulatedStackFrame> emulated_frame)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ StackHandleScope<1> hs(self);
+ Handle<mirror::MethodType> callsite_type = hs.NewHandle(emulated_frame->GetType());
+
+ // Copy arguments from the EmalatedStackFrame to a ShadowFrame.
+ const uint16_t num_vregs = callsite_type->NumberOfVRegs();
+
+ const char* old_cause = self->StartAssertNoThreadSuspension("EmulatedStackFrame to ShadowFrame");
+ ArtMethod* invoke_exact =
+ jni::DecodeArtMethod(WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact);
+ ShadowFrameAllocaUniquePtr shadow_frame =
+ CREATE_SHADOW_FRAME(num_vregs, /*link*/ nullptr, invoke_exact, /*dex_pc*/ 0);
+ emulated_frame->WriteToShadowFrame(self, callsite_type, 0, shadow_frame.get());
+ self->EndAssertNoThreadSuspension(old_cause);
+
+ ManagedStack fragment;
+ self->PushManagedStackFragment(&fragment);
+ self->PushShadowFrame(shadow_frame.get());
+
+ JValue result;
+ RangeInstructionOperands operands(0, num_vregs);
+ bool success = MethodHandleInvokeExact(self,
+ *shadow_frame.get(),
+ method_handle,
+ callsite_type,
+ &operands,
+ &result);
+ DCHECK_NE(success, self->IsExceptionPending());
+ if (success) {
+ emulated_frame->SetReturnValue(self, result);
}
+
+ self->PopShadowFrame();
+ self->PopManagedStackFragment(fragment);
}
} // namespace art
diff --git a/runtime/method_handles.h b/runtime/method_handles.h
index a098bc6783..510b6e1678 100644
--- a/runtime/method_handles.h
+++ b/runtime/method_handles.h
@@ -29,6 +29,7 @@ namespace art {
class ShadowFrame;
namespace mirror {
+class EmulatedStackFrame;
class MethodHandle;
class MethodType;
} // namespace mirror
@@ -150,6 +151,11 @@ bool MethodHandleInvokeExact(Thread* self,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
+void MethodHandleInvokeExactWithFrame(Thread* self,
+ Handle<mirror::MethodHandle> method_handle,
+ Handle<mirror::EmulatedStackFrame> stack_frame)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
} // namespace art
#endif // ART_RUNTIME_METHOD_HANDLES_H_
diff --git a/runtime/native/java_lang_invoke_MethodHandle.cc b/runtime/native/java_lang_invoke_MethodHandle.cc
new file mode 100644
index 0000000000..5309a28a09
--- /dev/null
+++ b/runtime/native/java_lang_invoke_MethodHandle.cc
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "java_lang_invoke_MethodHandle.h"
+
+#include "nativehelper/jni_macros.h"
+
+#include "handle_scope-inl.h"
+#include "jni/jni_internal.h"
+#include "method_handles.h"
+#include "mirror/field.h"
+#include "mirror/emulated_stack_frame.h"
+#include "mirror/method_handle_impl.h"
+#include "native_util.h"
+#include "scoped_thread_state_change-inl.h"
+
+namespace art {
+
+static void MethodHandle_invokeExactWithFrame(JNIEnv* env, jobject thiz, jobject arguments) {
+ ScopedObjectAccess soa(env);
+ StackHandleScope<2> hs(soa.Self());
+ auto handle = hs.NewHandle(soa.Decode<mirror::MethodHandle>(thiz));
+ auto frame = hs.NewHandle(soa.Decode<mirror::EmulatedStackFrame>(arguments));
+ MethodHandleInvokeExactWithFrame(soa.Self(), handle, frame);
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(MethodHandle, invokeExactWithFrame, "(Ldalvik/system/EmulatedStackFrame;)V")
+};
+
+void register_java_lang_invoke_MethodHandle(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("java/lang/invoke/MethodHandle");
+}
+
+} // namespace art
diff --git a/runtime/native/java_lang_invoke_MethodHandle.h b/runtime/native/java_lang_invoke_MethodHandle.h
new file mode 100644
index 0000000000..1f38ac7b27
--- /dev/null
+++ b/runtime/native/java_lang_invoke_MethodHandle.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_NATIVE_JAVA_LANG_INVOKE_METHODHANDLE_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_INVOKE_METHODHANDLE_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_invoke_MethodHandle(JNIEnv* env);
+
+} // namespace art
+
+#endif // ART_RUNTIME_NATIVE_JAVA_LANG_INVOKE_METHODHANDLE_H_
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index b2fc369877..c3f6471b1b 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -130,6 +130,7 @@
#include "native/java_lang_Thread.h"
#include "native/java_lang_Throwable.h"
#include "native/java_lang_VMClassLoader.h"
+#include "native/java_lang_invoke_MethodHandle.h"
#include "native/java_lang_invoke_MethodHandleImpl.h"
#include "native/java_lang_ref_FinalizerReference.h"
#include "native/java_lang_ref_Reference.h"
@@ -2178,6 +2179,7 @@ void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) {
register_dalvik_system_ZygoteHooks(env);
register_java_lang_Class(env);
register_java_lang_Object(env);
+ register_java_lang_invoke_MethodHandle(env);
register_java_lang_invoke_MethodHandleImpl(env);
register_java_lang_ref_FinalizerReference(env);
register_java_lang_reflect_Array(env);
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index c56b93329f..cf9e321bd6 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -105,6 +105,7 @@ jmethodID WellKnownClasses::java_lang_Float_floatToRawIntBits;
jmethodID WellKnownClasses::java_lang_Float_valueOf;
jmethodID WellKnownClasses::java_lang_Integer_valueOf;
jmethodID WellKnownClasses::java_lang_invoke_MethodHandle_asType;
+jmethodID WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact;
jmethodID WellKnownClasses::java_lang_invoke_MethodHandles_lookup;
jmethodID WellKnownClasses::java_lang_invoke_MethodHandles_Lookup_findConstructor;
jmethodID WellKnownClasses::java_lang_Long_valueOf;
@@ -407,6 +408,7 @@ void WellKnownClasses::InitFieldsAndMethodsOnly(JNIEnv* env) {
java_lang_Daemons_stop = CacheMethod(env, java_lang_Daemons, true, "stop", "()V");
java_lang_Daemons_waitForDaemonStart = CacheMethod(env, java_lang_Daemons, true, "waitForDaemonStart", "()V");
java_lang_invoke_MethodHandle_asType = CacheMethod(env, "java/lang/invoke/MethodHandle", false, "asType", "(Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;");
+ java_lang_invoke_MethodHandle_invokeExact = CacheMethod(env, "java/lang/invoke/MethodHandle", false, "invokeExact", "([Ljava/lang/Object;)Ljava/lang/Object;");
java_lang_invoke_MethodHandles_lookup = CacheMethod(env, "java/lang/invoke/MethodHandles", true, "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;");
java_lang_invoke_MethodHandles_Lookup_findConstructor = CacheMethod(env, "java/lang/invoke/MethodHandles$Lookup", false, "findConstructor", "(Ljava/lang/Class;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;");
@@ -608,6 +610,7 @@ void WellKnownClasses::Clear() {
java_lang_Float_valueOf = nullptr;
java_lang_Integer_valueOf = nullptr;
java_lang_invoke_MethodHandle_asType = nullptr;
+ java_lang_invoke_MethodHandle_invokeExact = nullptr;
java_lang_invoke_MethodHandles_lookup = nullptr;
java_lang_invoke_MethodHandles_Lookup_findConstructor = nullptr;
java_lang_Long_valueOf = nullptr;
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 67a47f0f43..c334f5d416 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -118,6 +118,7 @@ struct WellKnownClasses {
static jmethodID java_lang_Float_valueOf;
static jmethodID java_lang_Integer_valueOf;
static jmethodID java_lang_invoke_MethodHandle_asType;
+ static jmethodID java_lang_invoke_MethodHandle_invokeExact;
static jmethodID java_lang_invoke_MethodHandles_lookup;
static jmethodID java_lang_invoke_MethodHandles_Lookup_findConstructor;
static jmethodID java_lang_Long_valueOf;
diff --git a/test/958-methodhandle-stackframe/src-art/Main.java b/test/958-methodhandle-stackframe/src-art/Main.java
index bb3ce9a760..e85f5b8727 100644
--- a/test/958-methodhandle-stackframe/src-art/Main.java
+++ b/test/958-methodhandle-stackframe/src-art/Main.java
@@ -76,7 +76,7 @@ public class Main {
@Override
public void transform(EmulatedStackFrame stackFrame) throws Throwable {
- delegate.invoke(stackFrame);
+ invokeFromTransform(delegate, stackFrame);
}
}