summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorVladimir Marko <vmarko@google.com>2021-01-27 09:49:29 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-01-27 09:49:29 +0000
commita19ee52e3ae7edab7af8b22c7bb5dc2a3bf09b0a (patch)
treec25bc624819d5e09cd0a81123d6cbbe9f29c0b60 /compiler
parent9093699266d680074b7549b4ad17b162ad89e30f (diff)
parent853367b85d8e58fa7de8b8b7bc9810da9147fcd8 (diff)
arm: Fix and improve JNI frame entry/exit. am: 853367b85d
Original change: https://android-review.googlesource.com/c/platform/art/+/1556126 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: Ib267250f991d39f0625e2ccaa23a6ca004c8560b
Diffstat (limited to 'compiler')
-rw-r--r--compiler/jni/jni_cfi_test_expected.inc13
-rw-r--r--compiler/utils/arm/jni_macro_assembler_arm_vixl.cc62
2 files changed, 68 insertions, 7 deletions
diff --git a/compiler/jni/jni_cfi_test_expected.inc b/compiler/jni/jni_cfi_test_expected.inc
index 49e5a09c2e5..02b1c7a3522 100644
--- a/compiler/jni/jni_cfi_test_expected.inc
+++ b/compiler/jni/jni_cfi_test_expected.inc
@@ -15,8 +15,9 @@ static constexpr uint8_t expected_cfi_kThumb2[] = {
0x4E, 0x0E, 0xA0, 0x01, 0x42, 0x0E, 0x80, 0x01, 0x0A, 0x42, 0x0E, 0x5C,
0x44, 0x0E, 0x1C, 0x06, 0x50, 0x06, 0x51, 0x06, 0x52, 0x06, 0x53, 0x06,
0x54, 0x06, 0x55, 0x06, 0x56, 0x06, 0x57, 0x06, 0x58, 0x06, 0x59, 0x06,
- 0x5A, 0x06, 0x5B, 0x06, 0x5C, 0x06, 0x5D, 0x06, 0x5E, 0x06, 0x5F, 0x4A,
- 0x0B, 0x0E, 0x80, 0x01,
+ 0x5A, 0x06, 0x5B, 0x06, 0x5C, 0x06, 0x5D, 0x06, 0x5E, 0x06, 0x5F, 0x44,
+ 0x0E, 0x00, 0xC5, 0xC6, 0xC7, 0xC8, 0xCA, 0xCB, 0xCE, 0x46, 0x0B, 0x0E,
+ 0x80, 0x01,
};
// 0x00000000: push {r5,r6,r7,r8,r10,r11,lr}
// 0x00000004: .cfi_def_cfa_offset: 28
@@ -78,6 +79,14 @@ static constexpr uint8_t expected_cfi_kThumb2[] = {
// 0x00000020: .cfi_restore_extended: r94
// 0x00000020: .cfi_restore_extended: r95
// 0x00000020: pop {r5,r6,r7,r8,r10,r11,lr}
+// 0x00000024: .cfi_def_cfa_offset: 0
+// 0x00000024: .cfi_restore: r5
+// 0x00000024: .cfi_restore: r6
+// 0x00000024: .cfi_restore: r7
+// 0x00000024: .cfi_restore: r8
+// 0x00000024: .cfi_restore: r10
+// 0x00000024: .cfi_restore: r11
+// 0x00000024: .cfi_restore: r14
// 0x00000024: ldr r8, [tr, #48] ; is_gc_marking
// 0x00000028: bx lr
// 0x0000002a: .cfi_restore_state
diff --git a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
index 85b253c4c57..38167fbeb0c 100644
--- a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
+++ b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
@@ -98,7 +98,17 @@ void ArmVIXLJNIMacroAssembler::BuildFrame(size_t frame_size,
fp_spill_mask |= 1 << reg.AsArm().AsSRegister();
}
}
- if (core_spill_mask != 0u) {
+ if (core_spill_mask == (1u << lr.GetCode()) &&
+ fp_spill_mask == 0u &&
+ frame_size == 2 * kFramePointerSize &&
+ !method_reg.IsRegister()) {
+ // Special case: Only LR to push and one word to skip. Do this with a single
+ // 16-bit PUSH instruction by arbitrarily pushing r3 (without CFI for r3).
+ core_spill_mask |= 1u << r3.GetCode();
+ ___ Push(RegisterList(core_spill_mask));
+ cfi().AdjustCFAOffset(2 * kFramePointerSize);
+ cfi().RelOffset(DWARFReg(lr), kFramePointerSize);
+ } else if (core_spill_mask != 0u) {
___ Push(RegisterList(core_spill_mask));
cfi().AdjustCFAOffset(POPCOUNT(core_spill_mask) * kFramePointerSize);
cfi().RelOffsetForMany(DWARFReg(r0), 0, core_spill_mask, kFramePointerSize);
@@ -131,7 +141,6 @@ void ArmVIXLJNIMacroAssembler::RemoveFrame(size_t frame_size,
ArrayRef<const ManagedRegister> callee_save_regs,
bool may_suspend) {
CHECK_ALIGNED(frame_size, kAapcsStackAlignment);
- cfi().RememberState();
// Compute callee saves to pop.
RegList core_spill_mask = 0u;
@@ -144,6 +153,32 @@ void ArmVIXLJNIMacroAssembler::RemoveFrame(size_t frame_size,
}
}
+ // Pop LR to PC unless we need to emit some read barrier code just before returning.
+ bool emit_code_before_return =
+ (kEmitCompilerReadBarrier && kUseBakerReadBarrier) &&
+ (may_suspend || (kIsDebugBuild && emit_run_time_checks_in_debug_mode_));
+ if ((core_spill_mask & (1u << lr.GetCode())) != 0u && !emit_code_before_return) {
+ DCHECK_EQ(core_spill_mask & (1u << pc.GetCode()), 0u);
+ core_spill_mask ^= (1u << lr.GetCode()) | (1u << pc.GetCode());
+ }
+
+ // If there are no FP registers to pop and we pop PC, we can avoid emitting any CFI.
+ if (fp_spill_mask == 0u && (core_spill_mask & (1u << pc.GetCode())) != 0u) {
+ if (frame_size == POPCOUNT(core_spill_mask) * kFramePointerSize) {
+ // Just pop all registers and avoid CFI.
+ ___ Pop(RegisterList(core_spill_mask));
+ return;
+ } else if (frame_size == 8u && core_spill_mask == (1u << pc.GetCode())) {
+ // Special case: One word to ignore and one to pop to PC. We are free to clobber the
+ // caller-save register r3 on return, so use a 16-bit POP instruction and avoid CFI.
+ ___ Pop(RegisterList((1u << r3.GetCode()) | (1u << pc.GetCode())));
+ return;
+ }
+ }
+
+ // We shall need to adjust CFI and restore it after the frame exit sequence.
+ cfi().RememberState();
+
// Decrease frame to start of callee saves.
size_t pop_values = POPCOUNT(core_spill_mask) + POPCOUNT(fp_spill_mask);
CHECK_GE(frame_size, pop_values * kFramePointerSize);
@@ -160,9 +195,24 @@ void ArmVIXLJNIMacroAssembler::RemoveFrame(size_t frame_size,
cfi().RestoreMany(DWARFReg(s0), fp_spill_mask);
}
- // Pop core callee saves and LR.
+ // Pop core callee saves.
if (core_spill_mask != 0u) {
- ___ Pop(RegisterList(core_spill_mask));
+ if (IsPowerOfTwo(core_spill_mask) &&
+ core_spill_mask != (1u << pc.GetCode()) &&
+ WhichPowerOf2(core_spill_mask) >= 8) {
+ // FIXME(vixl): vixl fails to transform a pop with single high register
+ // to a post-index STR (also known as POP encoding T3) and emits the LDMIA
+ // (also known as POP encoding T2) which is UNPREDICTABLE for 1 register.
+ // So we have to explicitly do the transformation here. Bug: 178048807
+ vixl32::Register reg(WhichPowerOf2(core_spill_mask));
+ ___ Ldr(reg, MemOperand(sp, kFramePointerSize, PostIndex));
+ } else {
+ ___ Pop(RegisterList(core_spill_mask));
+ }
+ if ((core_spill_mask & (1u << pc.GetCode())) == 0u) {
+ cfi().AdjustCFAOffset(-kFramePointerSize * POPCOUNT(core_spill_mask));
+ cfi().RestoreMany(DWARFReg(r0), core_spill_mask);
+ }
}
if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
@@ -193,7 +243,9 @@ void ArmVIXLJNIMacroAssembler::RemoveFrame(size_t frame_size,
}
// Return to LR.
- ___ Bx(vixl32::lr);
+ if ((core_spill_mask & (1u << pc.GetCode())) == 0u) {
+ ___ Bx(vixl32::lr);
+ }
// The CFI should be restored for any code that follows the exit block.
cfi().RestoreState();