diff options
| -rw-r--r-- | runtime/Android.bp | 1 | ||||
| -rw-r--r-- | runtime/method_handles.cc | 106 | ||||
| -rw-r--r-- | runtime/method_handles.h | 6 | ||||
| -rw-r--r-- | runtime/native/java_lang_invoke_MethodHandle.cc | 48 | ||||
| -rw-r--r-- | runtime/native/java_lang_invoke_MethodHandle.h | 28 | ||||
| -rw-r--r-- | runtime/runtime.cc | 2 | ||||
| -rw-r--r-- | runtime/well_known_classes.cc | 3 | ||||
| -rw-r--r-- | runtime/well_known_classes.h | 1 | ||||
| -rw-r--r-- | test/958-methodhandle-stackframe/src-art/Main.java | 2 |
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); } } |