summaryrefslogtreecommitdiff
path: root/compiler/jni/quick/jni_compiler.cc
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2021-03-23 16:32:52 +0000
committer Vladimir Marko <vmarko@google.com> 2021-10-11 11:56:59 +0000
commitd95a1f2ecf322d21ae98bfb7affe0070ddb9bc08 (patch)
tree8fc5fe8370ec051289a34cde7bf3dc5fc7a1ca7f /compiler/jni/quick/jni_compiler.cc
parent507a729e51588f7fa4eac7579d54ce7c96804349 (diff)
Inline IRT frame push/pop into JNI stubs.
Golem results for art-opt-cc (higher is better): linux-ia32 before after NativeDowncallStaticNormal 25.704 26.839 (+4.414%) NativeDowncallStaticNormal6 23.857 25.086 (+5.152%) NativeDowncallStaticNormalRefs6 23.704 25.248 (+6.513%) NativeDowncallVirtualNormal 25.578 27.000 (+5.560%) NativeDowncallVirtualNormal6 23.704 24.925 (+5.153%) NativeDowncallVirtualNormalRefs6 23.704 25.074 (+5.870%) NativeDowncallStaticFast 100.65 149.13 (+48.17%) NativeDowncallStaticFast6 78.304 107.39 (+37.71%) NativeDowncallStaticFastRefs6 76.962 104.45 (+35.71%) NativeDowncallVirtualFast 100.40 147.28 (+46.69%) NativeDowncallVirtualFast6 79.302 106.34 (+34.10%) NativeDowncallVirtualFastRef26 76.617 103.29 (+34.82%) linux-x64 before after NativeDowncallStaticNormal 26.083 26.987 (+3.465%) NativeDowncallStaticNormal6 24.606 25.411 (+3.271%) NativeDowncallStaticNormalRefs6 24.150 25.086 (+3.877%) NativeDowncallVirtualNormal 25.743 26.812 (+4.156%) NativeDowncallVirtualNormal6 24.294 25.248 (+3.927%) NativeDowncallVirtualNormalRefs6 23.857 25.086 (+5.152%) NativeDowncallStaticFast 109.95 133.10 (+21.06%) NativeDowncallStaticFast6 90.274 109.12 (+20.87%) NativeDowncallStaticFastRefs6 87.282 105.29 (+20.63%) NativeDowncallVirtualFast 104.00 127.55 (+22.65%) NativeDowncallVirtualFast6 88.191 106.73 (+21.02%) NativeDowncallVirtualFastRef26 85.530 102.09 (+19.36%) linux-armv7 before after NativeDowncallStaticNormal 6.1148 6.3694 (+4.316%) NativeDowncallStaticNormal6 5.6845 5.9026 (+3.837%) NativeDowncallStaticNormalRefs6 5.4054 5.6022 (+3.641%) NativeDowncallVirtualNormal 5.4726 5.7088 (+4.316%) NativeDowncallVirtualNormal6 5.1789 5.3685 (+3.660%) NativeDowncallVirtualNormalRefs6 4.9140 5.0902 (+3.586%) NativeDowncallStaticFast 16.683 18.058 (+8.239%) NativeDowncallStaticFast6 13.951 14.896 (+6.770%) NativeDowncallStaticFastRefs6 12.279 13.006 (+5.919%) NativeDowncallVirtualFast 16.161 17.848 (+10.44%) NativeDowncallVirtualFast6 14.085 15.196 (+7.892%) NativeDowncallVirtualFastRef26 12.089 12.897 (+6.683%) linux-armv8 before after NativeDowncallStaticNormal 6.0663 6.4229 (+5.879%) NativeDowncallStaticNormal6 5.7252 6.0437 (+5.563%) NativeDowncallStaticNormalRefs6 5.3114 5.5814 (+5.082%) NativeDowncallVirtualNormal 5.8795 6.2651 (+6.558%) NativeDowncallVirtualNormal6 5.6232 5.9494 (+5.801%) NativeDowncallVirtualNormalRefs6 5.1862 5.4429 (+4.948%) NativeDowncallStaticFast 17.638 19.183 (+8.760%) NativeDowncallStaticFast6 14.903 16.161 (+8.438%) NativeDowncallStaticFastRefs6 12.475 13.235 (+6.094%) NativeDowncallVirtualFast 15.826 17.848 (+12.78%) NativeDowncallVirtualFast6 14.064 15.504 (+10.24%) NativeDowncallVirtualFastRef26 11.628 12.475 (+7.285%) Test: m test-art-host-gtest Test: testrunner.py --host --optimizing Test: run-gtests.sh Test: testrunner.py --target --optimizing Bug: 172332525 Change-Id: I5ecfa7a661f08ab63dd2a75d666e1c1b9121935f
Diffstat (limited to 'compiler/jni/quick/jni_compiler.cc')
-rw-r--r--compiler/jni/quick/jni_compiler.cc144
1 files changed, 101 insertions, 43 deletions
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index cdd0263729..25eb919c53 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -50,6 +50,19 @@
namespace art {
+constexpr size_t kIRTCookieSize = JniCallingConvention::SavedLocalReferenceCookieSize();
+
+template <PointerSize kPointerSize>
+static void PushLocalReferenceFrame(JNIMacroAssembler<kPointerSize>* jni_asm,
+ ManagedRegister jni_env_reg,
+ ManagedRegister saved_cookie_reg,
+ ManagedRegister temp_reg);
+template <PointerSize kPointerSize>
+static void PopLocalReferenceFrame(JNIMacroAssembler<kPointerSize>* jni_asm,
+ ManagedRegister jni_env_reg,
+ ManagedRegister saved_cookie_reg,
+ ManagedRegister temp_reg);
+
template <PointerSize kPointerSize>
static void CopyParameter(JNIMacroAssembler<kPointerSize>* jni_asm,
ManagedRuntimeCallingConvention* mr_conv,
@@ -194,11 +207,9 @@ static JniCompiledMethod ArtJniCompileMethodInternal(const CompilerOptions& comp
// method and the current thread.
const char* jni_end_shorty;
if (reference_return && is_synchronized) {
- jni_end_shorty = "ILL";
- } else if (reference_return) {
jni_end_shorty = "IL";
- } else if (is_synchronized) {
- jni_end_shorty = "VL";
+ } else if (reference_return) {
+ jni_end_shorty = "I";
} else {
jni_end_shorty = "V";
}
@@ -275,18 +286,15 @@ static JniCompiledMethod ArtJniCompileMethodInternal(const CompilerOptions& comp
}
// 5. Call into appropriate JniMethodStart passing Thread* so that transition out of Runnable
- // can occur. The result is the saved JNI local state that is restored by the exit call. We
- // abuse the JNI calling convention here, that is guaranteed to support passing 2 pointer
- // arguments.
- constexpr size_t cookie_size = JniCallingConvention::SavedLocalReferenceCookieSize();
- ManagedRegister saved_cookie_register = ManagedRegister::NoRegister();
+ // can occur. We abuse the JNI calling convention here, that is guaranteed to support passing
+ // two pointer arguments.
if (LIKELY(!is_critical_native)) {
// Skip this for @CriticalNative methods. They do not call JniMethodStart.
- ThreadOffset<kPointerSize> jni_start(
+ ThreadOffset<kPointerSize> jni_start =
GetJniEntrypointThreadOffset<kPointerSize>(JniEntrypoint::kStart,
reference_return,
is_synchronized,
- is_fast_native).SizeValue());
+ is_fast_native);
main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
if (is_synchronized) {
// Pass object for locking.
@@ -322,13 +330,33 @@ static JniCompiledMethod ArtJniCompileMethodInternal(const CompilerOptions& comp
if (is_synchronized) { // Check for exceptions from monitor enter.
__ ExceptionPoll(main_out_arg_size);
}
+ }
- // Store into stack_frame[saved_cookie_offset] the return value of JniMethodStart.
- saved_cookie_register = main_jni_conv->SavedLocalReferenceCookieRegister();
- __ Move(saved_cookie_register, main_jni_conv->IntReturnRegister(), cookie_size);
+ // 6. Push local reference frame.
+ // Skip this for @CriticalNative methods, they cannot use any references.
+ ManagedRegister jni_env_reg = ManagedRegister::NoRegister();
+ ManagedRegister saved_cookie_reg = ManagedRegister::NoRegister();
+ ManagedRegister callee_save_temp = ManagedRegister::NoRegister();
+ if (LIKELY(!is_critical_native)) {
+ // To pop the local reference frame later, we shall need the JNI environment pointer
+ // as well as the cookie, so we preserve them across calls in callee-save registers.
+ // Managed callee-saves were already saved, so these registers are now available.
+ ArrayRef<const ManagedRegister> callee_save_scratch_regs =
+ main_jni_conv->CalleeSaveScratchRegisters();
+ CHECK_GE(callee_save_scratch_regs.size(), 3u); // At least 3 for each supported architecture.
+ jni_env_reg = callee_save_scratch_regs[0];
+ saved_cookie_reg = __ CoreRegisterWithSize(callee_save_scratch_regs[1], kIRTCookieSize);
+ callee_save_temp = __ CoreRegisterWithSize(callee_save_scratch_regs[2], kIRTCookieSize);
+
+ // Load the JNI environment pointer.
+ __ LoadRawPtrFromThread(jni_env_reg, Thread::JniEnvOffset<kPointerSize>());
+
+ // Push the local reference frame.
+ PushLocalReferenceFrame<kPointerSize>(
+ jni_asm.get(), jni_env_reg, saved_cookie_reg, callee_save_temp);
}
- // 6. Fill arguments.
+ // 7. Fill arguments.
if (UNLIKELY(is_critical_native)) {
ArenaVector<ArgumentLocation> src_args(allocator.Adapter());
ArenaVector<ArgumentLocation> dest_args(allocator.Adapter());
@@ -388,7 +416,7 @@ static JniCompiledMethod ArtJniCompileMethodInternal(const CompilerOptions& comp
CopyParameter(jni_asm.get(), mr_conv.get(), main_jni_conv.get());
}
- // 7. For static method, create jclass argument as a pointer to the method's declaring class.
+ // 8. For static method, create jclass argument as a pointer to the method's declaring class.
if (is_static) {
main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
main_jni_conv->Next(); // Skip JNIEnv*
@@ -413,18 +441,17 @@ static JniCompiledMethod ArtJniCompileMethodInternal(const CompilerOptions& comp
// Set the iterator back to the incoming Method*.
main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size));
- // 8. Create 1st argument, the JNI environment ptr.
- // Register that will hold local indirect reference table
+ // 9. Create 1st argument, the JNI environment ptr.
if (main_jni_conv->IsCurrentParamInRegister()) {
- ManagedRegister jni_env = main_jni_conv->CurrentParamRegister();
- __ LoadRawPtrFromThread(jni_env, Thread::JniEnvOffset<kPointerSize>());
+ ManagedRegister jni_env_arg = main_jni_conv->CurrentParamRegister();
+ __ Move(jni_env_arg, jni_env_reg, static_cast<size_t>(kPointerSize));
} else {
- FrameOffset jni_env = main_jni_conv->CurrentParamStackOffset();
- __ CopyRawPtrFromThread(jni_env, Thread::JniEnvOffset<kPointerSize>());
+ FrameOffset jni_env_arg_offset = main_jni_conv->CurrentParamStackOffset();
+ __ Store(jni_env_arg_offset, jni_env_reg, static_cast<size_t>(kPointerSize));
}
}
- // 9. Plant call to native code associated with method.
+ // 10. Plant call to native code associated with method.
MemberOffset jni_entrypoint_offset =
ArtMethod::EntryPointFromJniOffset(InstructionSetPointerSize(instruction_set));
if (UNLIKELY(is_critical_native)) {
@@ -442,7 +469,7 @@ static JniCompiledMethod ArtJniCompileMethodInternal(const CompilerOptions& comp
}
}
- // 10. Fix differences in result widths.
+ // 11. Fix differences in result widths.
if (main_jni_conv->RequiresSmallResultTypeExtension()) {
DCHECK(main_jni_conv->HasSmallReturnType());
CHECK(!is_critical_native || !main_jni_conv->UseTailCall());
@@ -458,7 +485,7 @@ static JniCompiledMethod ArtJniCompileMethodInternal(const CompilerOptions& comp
}
}
- // 11. Process return value
+ // 12. Process return value
bool spill_return_value = main_jni_conv->SpillsReturnValue();
FrameOffset return_save_location =
spill_return_value ? main_jni_conv->ReturnValueSaveLocation() : FrameOffset(0);
@@ -504,26 +531,17 @@ static JniCompiledMethod ArtJniCompileMethodInternal(const CompilerOptions& comp
}
end_jni_conv->ResetIterator(FrameOffset(end_out_arg_size));
- // 12. Call JniMethodEnd
- ThreadOffset<kPointerSize> jni_end(
+ // 13. Call JniMethodEnd
+ ThreadOffset<kPointerSize> jni_end =
GetJniEntrypointThreadOffset<kPointerSize>(JniEntrypoint::kEnd,
reference_return,
is_synchronized,
- is_fast_native).SizeValue());
+ is_fast_native);
if (reference_return) {
// Pass result.
SetNativeParameter(jni_asm.get(), end_jni_conv.get(), end_jni_conv->ReturnRegister());
end_jni_conv->Next();
}
- // Pass saved local reference state.
- if (end_jni_conv->IsCurrentParamOnStack()) {
- FrameOffset out_off = end_jni_conv->CurrentParamStackOffset();
- __ Store(out_off, saved_cookie_register, cookie_size);
- } else {
- ManagedRegister out_reg = end_jni_conv->CurrentParamRegister();
- __ Move(out_reg, saved_cookie_register, cookie_size);
- }
- end_jni_conv->Next();
if (is_synchronized) {
// Pass object for unlocking.
if (is_static) {
@@ -563,26 +581,32 @@ static JniCompiledMethod ArtJniCompileMethodInternal(const CompilerOptions& comp
__ CallFromThread(jni_end);
}
- // 13. Reload return value
+ // 14. Reload return value
if (spill_return_value) {
__ Load(mr_conv->ReturnRegister(), return_save_location, mr_conv->SizeOfReturnValue());
}
} // if (!is_critical_native)
- // 14. Move frame up now we're done with the out arg space.
+ // 15. Pop local reference frame.
+ if (!is_critical_native) {
+ PopLocalReferenceFrame<kPointerSize>(
+ jni_asm.get(), jni_env_reg, saved_cookie_reg, callee_save_temp);
+ }
+
+ // 16. Move frame up now we're done with the out arg space.
// @CriticalNative remove out args together with the frame in RemoveFrame().
if (LIKELY(!is_critical_native)) {
__ DecreaseFrameSize(current_out_arg_size);
current_frame_size -= current_out_arg_size;
}
- // 15. Process pending exceptions from JNI call or monitor exit.
+ // 17. Process pending exceptions from JNI call or monitor exit.
// @CriticalNative methods do not need exception poll in the stub.
if (LIKELY(!is_critical_native)) {
__ ExceptionPoll(/* stack_adjust= */ 0);
}
- // 16. Remove activation - need to restore callee save registers since the GC may have changed
+ // 18. Remove activation - need to restore callee save registers since the GC may have changed
// them.
DCHECK_EQ(jni_asm->cfi().GetCurrentCFAOffset(), static_cast<int>(current_frame_size));
if (LIKELY(!is_critical_native) || !main_jni_conv->UseTailCall()) {
@@ -593,7 +617,7 @@ static JniCompiledMethod ArtJniCompileMethodInternal(const CompilerOptions& comp
DCHECK_EQ(jni_asm->cfi().GetCurrentCFAOffset(), static_cast<int>(current_frame_size));
}
- // 17. Read barrier slow path for the declaring class in the method for a static call.
+ // 19. Read barrier slow path for the declaring class in the method for a static call.
// Skip this for @CriticalNative because we're not passing a `jclass` to the native method.
if (kUseReadBarrier && is_static && !is_critical_native) {
__ Bind(jclass_read_barrier_slow_path.get());
@@ -649,7 +673,7 @@ static JniCompiledMethod ArtJniCompileMethodInternal(const CompilerOptions& comp
}
}
- // 18. Finalize code generation
+ // 20. Finalize code generation
__ FinalizeCode();
size_t cs = __ CodeSize();
std::vector<uint8_t> managed_code(cs);
@@ -664,6 +688,40 @@ static JniCompiledMethod ArtJniCompileMethodInternal(const CompilerOptions& comp
ArrayRef<const uint8_t>(*jni_asm->cfi().data()));
}
+template <PointerSize kPointerSize>
+static void PushLocalReferenceFrame(JNIMacroAssembler<kPointerSize>* jni_asm,
+ ManagedRegister jni_env_reg,
+ ManagedRegister saved_cookie_reg,
+ ManagedRegister temp_reg) {
+ const size_t pointer_size = static_cast<size_t>(kPointerSize);
+ const MemberOffset jni_env_cookie_offset = JNIEnvExt::LocalRefCookieOffset(pointer_size);
+ const MemberOffset jni_env_segment_state_offset = JNIEnvExt::SegmentStateOffset(pointer_size);
+
+ // Load the old cookie that we shall need to restore.
+ __ Load(saved_cookie_reg, jni_env_reg, jni_env_cookie_offset, kIRTCookieSize);
+
+ // Set the cookie in JNI environment to the current segment state.
+ __ Load(temp_reg, jni_env_reg, jni_env_segment_state_offset, kIRTCookieSize);
+ __ Store(jni_env_reg, jni_env_cookie_offset, temp_reg, kIRTCookieSize);
+}
+
+template <PointerSize kPointerSize>
+static void PopLocalReferenceFrame(JNIMacroAssembler<kPointerSize>* jni_asm,
+ ManagedRegister jni_env_reg,
+ ManagedRegister saved_cookie_reg,
+ ManagedRegister temp_reg) {
+ const size_t pointer_size = static_cast<size_t>(kPointerSize);
+ const MemberOffset jni_env_cookie_offset = JNIEnvExt::LocalRefCookieOffset(pointer_size);
+ const MemberOffset jni_env_segment_state_offset = JNIEnvExt::SegmentStateOffset(pointer_size);
+
+ // Set the current segment state to the current cookie in JNI environment.
+ __ Load(temp_reg, jni_env_reg, jni_env_cookie_offset, kIRTCookieSize);
+ __ Store(jni_env_reg, jni_env_segment_state_offset, temp_reg, kIRTCookieSize);
+
+ // Restore the cookie in JNI environment to the saved value.
+ __ Store(jni_env_reg, jni_env_cookie_offset, saved_cookie_reg, kIRTCookieSize);
+}
+
// Copy a single parameter from the managed to the JNI calling convention.
template <PointerSize kPointerSize>
static void CopyParameter(JNIMacroAssembler<kPointerSize>* jni_asm,