diff options
author | 2021-02-08 16:16:13 +0000 | |
---|---|---|
committer | 2021-02-23 14:34:43 +0000 | |
commit | cedec9db0a9accfdcf5eb695879e0b2caf2c34cb (patch) | |
tree | 99fd71a3ef398a471507ed815c4a175805ad51f3 /compiler/jni/quick/calling_convention.h | |
parent | 0ccc970b3c00b172e3cff8e10da13dd6323ccd52 (diff) |
Do not create HandleScope for JNI transitions.
We previously crated a HandleScope in the JNI transition
frame to hold references passed as jobject (jclass, etc.)
to the native function and these references were actually
spilled twice during the transition.
We now construct the jobject as a pointer to the reference
spilled in the reserved out vreg area in the caller's frame.
And the jclass for static methods is just a pointer to the
method's declaring class. This reduces the amount of work
required in the JNI transition, both on entry (in compiled
stubs) and exit (in JniMethodEnd*).
Some additional work is required when GC visits references
of a native method as we need to walk over the method's
shorty which was unnecessary for a HandleScope.
Also fix Thread::InitStackHwm() to calculate correct stack
size needed by the new Thread::IsJniTransitionReference().
The results for StringToBytesBenchmark on blueline little
cores running at fixed frequency 1420800 are approximately
arm64 (medians from 3 runs) before after
timeGetBytesAscii EMPTY 447.33 436.86
timeGetBytesIso88591 EMPTY 440.52 431.13
timeGetBytesUtf8 EMPTY 432.31 409.82
arm (medians from 3 runs) before after
timeGetBytesAscii EMPTY 500.53 490.87
timeGetBytesIso88591 EMPTY 496.45 495.30
timeGetBytesUtf8 EMPTY 488.84 472.68
Test: m test-art-host-gtest
Test: testrunner.py --host
Test: testrunner.py --host --gcstress
Test: testrunner.py --host --jit-on-first-use
Test: testrunner.py --host --jit-on-first-use --gcstress
Test: run-gtests.sh
Test: testrunner.py --target --optimizing
Test: boots.
Bug: 172332525
Change-Id: I658f9d87071587b3e89f31c65feca976a11e9cc2
Diffstat (limited to 'compiler/jni/quick/calling_convention.h')
-rw-r--r-- | compiler/jni/quick/calling_convention.h | 49 |
1 files changed, 10 insertions, 39 deletions
diff --git a/compiler/jni/quick/calling_convention.h b/compiler/jni/quick/calling_convention.h index 005ae910d1..56792637a2 100644 --- a/compiler/jni/quick/calling_convention.h +++ b/compiler/jni/quick/calling_convention.h @@ -21,7 +21,6 @@ #include "base/array_ref.h" #include "base/enums.h" #include "dex/primitive.h" -#include "handle_scope.h" #include "thread.h" #include "utils/managed_register.h" @@ -81,7 +80,6 @@ class CallingConvention : public DeletableArenaObject<kArenaAllocCallingConventi : itr_slots_(0), itr_refs_(0), itr_args_(0), itr_longs_and_doubles_(0), itr_float_and_doubles_(0), displacement_(0), frame_pointer_size_(frame_pointer_size), - handle_scope_pointer_size_(sizeof(StackReference<mirror::Object>)), is_static_(is_static), is_synchronized_(is_synchronized), shorty_(shorty) { num_args_ = (is_static ? 0 : 1) + strlen(shorty) - 1; @@ -211,8 +209,6 @@ class CallingConvention : public DeletableArenaObject<kArenaAllocCallingConventi FrameOffset displacement_; // The size of a pointer. const PointerSize frame_pointer_size_; - // The size of a reference entry within the handle scope. - const size_t handle_scope_pointer_size_; private: const bool is_static_; @@ -345,32 +341,12 @@ class JniCallingConvention : public CallingConvention { virtual ManagedRegister CurrentParamRegister() = 0; virtual FrameOffset CurrentParamStackOffset() = 0; - // Iterator interface extension for JNI - FrameOffset CurrentParamHandleScopeEntryOffset(); - - // Position of handle scope and interior fields - FrameOffset HandleScopeOffset() const { - return FrameOffset(this->displacement_.Int32Value() + static_cast<size_t>(frame_pointer_size_)); - // above Method reference - } - - FrameOffset HandleScopeLinkOffset() const { - return FrameOffset(HandleScopeOffset().Int32Value() + - HandleScope::LinkOffset(frame_pointer_size_)); - } - - FrameOffset HandleScopeNumRefsOffset() const { - return FrameOffset(HandleScopeOffset().Int32Value() + - HandleScope::NumberOfReferencesOffset(frame_pointer_size_)); - } + virtual ~JniCallingConvention() {} - FrameOffset HandleReferencesOffset() const { - return FrameOffset(HandleScopeOffset().Int32Value() + - HandleScope::ReferencesOffset(frame_pointer_size_)); + size_t SavedLocalReferenceCookieSize() const { + return 4u; } - virtual ~JniCallingConvention() {} - bool IsCriticalNative() const { return is_critical_native_; } @@ -397,6 +373,13 @@ class JniCallingConvention : public CallingConvention { return_type == Primitive::kPrimChar; } + // Does the transition back spill the return value in the stack frame? + bool SpillsReturnValue() const { + // Exclude return value for @CriticalNative methods for optimization speed. + // References are passed directly to the "end method" and there is nothing to save for `void`. + return !IsCriticalNative() && !IsReturnAReference() && SizeOfReturnValue() != 0u; + } + protected: // Named iterator positions enum IteratorPos { @@ -415,24 +398,12 @@ class JniCallingConvention : public CallingConvention { protected: size_t NumberOfExtraArgumentsForJni() const; - // Does the transition have a StackHandleScope? - bool HasHandleScope() const { - // Exclude HandleScope for @CriticalNative methods for optimization speed. - return !IsCriticalNative(); - } - // Does the transition have a local reference segment state? bool HasLocalReferenceSegmentState() const { // Exclude local reference segment states for @CriticalNative methods for optimization speed. return !IsCriticalNative(); } - // Does the transition back spill the return value in the stack frame? - bool SpillsReturnValue() const { - // Exclude return value for @CriticalNative methods for optimization speed. - return !IsCriticalNative(); - } - // Are there extra JNI arguments (JNIEnv* and maybe jclass)? bool HasExtraArgumentsForJni() const { // @CriticalNative jni implementations exclude both JNIEnv* and the jclass/jobject parameters. |