summaryrefslogtreecommitdiff
path: root/compiler/jni/quick/calling_convention.cc
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2021-02-08 16:16:13 +0000
committer Vladimir Marko <vmarko@google.com> 2021-02-23 14:34:43 +0000
commitcedec9db0a9accfdcf5eb695879e0b2caf2c34cb (patch)
tree99fd71a3ef398a471507ed815c4a175805ad51f3 /compiler/jni/quick/calling_convention.cc
parent0ccc970b3c00b172e3cff8e10da13dd6323ccd52 (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.cc')
-rw-r--r--compiler/jni/quick/calling_convention.cc40
1 files changed, 15 insertions, 25 deletions
diff --git a/compiler/jni/quick/calling_convention.cc b/compiler/jni/quick/calling_convention.cc
index 194375671e..2127f7309a 100644
--- a/compiler/jni/quick/calling_convention.cc
+++ b/compiler/jni/quick/calling_convention.cc
@@ -19,6 +19,7 @@
#include <android-base/logging.h>
#include "arch/instruction_set.h"
+#include "indirect_reference_table.h"
#ifdef ART_ENABLE_CODEGEN_arm
#include "jni/quick/arm/calling_convention_arm.h"
@@ -173,25 +174,24 @@ size_t JniCallingConvention::ReferenceCount() const {
}
FrameOffset JniCallingConvention::SavedLocalReferenceCookieOffset() const {
- size_t references_size = handle_scope_pointer_size_ * ReferenceCount(); // size excluding header
- return FrameOffset(HandleReferencesOffset().Int32Value() + references_size);
+ // The cookie goes after the method pointer.
+ DCHECK_EQ(SavedLocalReferenceCookieSize(), sizeof(IRTSegmentState));
+ DCHECK(HasLocalReferenceSegmentState());
+ return FrameOffset(displacement_.SizeValue() + static_cast<size_t>(frame_pointer_size_));
}
FrameOffset JniCallingConvention::ReturnValueSaveLocation() const {
- if (LIKELY(HasHandleScope())) {
- // Initial offset already includes the displacement.
- // -- Remove the additional local reference cookie offset if we don't have a handle scope.
- const size_t saved_local_reference_cookie_offset =
- SavedLocalReferenceCookieOffset().Int32Value();
- // Segment state is 4 bytes long
- const size_t segment_state_size = 4;
- return FrameOffset(saved_local_reference_cookie_offset + segment_state_size);
- } else {
- // Include only the initial Method* as part of the offset.
- CHECK_LT(displacement_.SizeValue(),
- static_cast<size_t>(std::numeric_limits<int32_t>::max()));
- return FrameOffset(displacement_.Int32Value() + static_cast<size_t>(frame_pointer_size_));
+ // The saved return value goes at a properly aligned slot after the cookie.
+ DCHECK(SpillsReturnValue());
+ size_t cookie_offset = SavedLocalReferenceCookieOffset().SizeValue() - displacement_.SizeValue();
+ size_t return_value_offset = cookie_offset + SavedLocalReferenceCookieSize();
+ const size_t return_value_size = SizeOfReturnValue();
+ DCHECK(return_value_size == 4u || return_value_size == 8u) << return_value_size;
+ DCHECK_ALIGNED(return_value_offset, 4u);
+ if (return_value_size == 8u) {
+ return_value_offset = RoundUp(return_value_offset, 8u);
}
+ return FrameOffset(displacement_.SizeValue() + return_value_offset);
}
bool JniCallingConvention::HasNext() {
@@ -285,16 +285,6 @@ bool JniCallingConvention::IsCurrentParamALong() {
}
}
-// Return position of handle scope entry holding reference at the current iterator
-// position
-FrameOffset JniCallingConvention::CurrentParamHandleScopeEntryOffset() {
- CHECK(IsCurrentParamAReference());
- CHECK_LT(HandleScopeLinkOffset(), HandleScopeNumRefsOffset());
- int result = HandleReferencesOffset().Int32Value() + itr_refs_ * handle_scope_pointer_size_;
- CHECK_GT(result, HandleScopeNumRefsOffset().Int32Value());
- return FrameOffset(result);
-}
-
size_t JniCallingConvention::CurrentParamSize() const {
if (IsCurrentArgExtraForJni()) {
return static_cast<size_t>(frame_pointer_size_); // JNIEnv or jobject/jclass