[VM] Use one instruction to unwind frame and return instead of two on ARM

This reduces AOT flutter gallery RX size by 0.81 %.

Issue https://github.com/dart-lang/sdk/issues/33274

Change-Id: I1a3c3f48af9ae5d89d3d89da1d86c798145dbd99
Reviewed-on: https://dart-review.googlesource.com/72383
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
diff --git a/runtime/vm/compiler/assembler/assembler_arm.cc b/runtime/vm/compiler/assembler/assembler_arm.cc
index bf1f12f..397c4e9 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm.cc
@@ -3007,8 +3007,8 @@
   }
 }
 
-void Assembler::LeaveFrame(RegList regs) {
-  ASSERT((regs & (1 << PC)) == 0);  // Must not pop PC.
+void Assembler::LeaveFrame(RegList regs, bool allow_pop_pc) {
+  ASSERT(allow_pop_pc || (regs & (1 << PC)) == 0);  // Must not pop PC.
   if ((regs & (1 << FP)) != 0) {
     // Use FP to set SP.
     sub(SP, FP, Operand(4 * NumRegsBelowFP(regs)));
@@ -3122,18 +3122,26 @@
   AddImmediate(SP, -extra_size);
 }
 
-void Assembler::LeaveDartFrame(RestorePP restore_pp) {
-  if (restore_pp == kRestoreCallerPP) {
-    ldr(PP,
-        Address(FP, compiler_frame_layout.saved_caller_pp_from_fp * kWordSize));
-    set_constant_pool_allowed(false);
-  }
+void Assembler::LeaveDartFrame() {
+  ldr(PP,
+      Address(FP, compiler_frame_layout.saved_caller_pp_from_fp * kWordSize));
+  set_constant_pool_allowed(false);
 
   // This will implicitly drop saved PP, PC marker due to restoring SP from FP
   // first.
   LeaveFrame((1 << FP) | (1 << LR));
 }
 
+void Assembler::LeaveDartFrameAndReturn() {
+  ldr(PP,
+      Address(FP, compiler_frame_layout.saved_caller_pp_from_fp * kWordSize));
+  set_constant_pool_allowed(false);
+
+  // This will implicitly drop saved PP, PC marker due to restoring SP from FP
+  // first.
+  LeaveFrame((1 << FP) | (1 << PC), /*allow_pop_pc=*/true);
+}
+
 void Assembler::EnterStubFrame() {
   EnterDartFrame(0);
 }
diff --git a/runtime/vm/compiler/assembler/assembler_arm.h b/runtime/vm/compiler/assembler/assembler_arm.h
index 90d554c..6669caa 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.h
+++ b/runtime/vm/compiler/assembler/assembler_arm.h
@@ -1010,7 +1010,7 @@
 
   // Function frame setup and tear down.
   void EnterFrame(RegList regs, intptr_t frame_space);
-  void LeaveFrame(RegList regs);
+  void LeaveFrame(RegList regs, bool allow_pop_pc = false);
   void Ret();
   void ReserveAlignedFrameSpace(intptr_t frame_space);
 
@@ -1026,7 +1026,22 @@
   // enable easy access to the RawInstruction object of code corresponding
   // to this frame.
   void EnterDartFrame(intptr_t frame_size);
-  void LeaveDartFrame(RestorePP restore_pp = kRestoreCallerPP);
+
+  void LeaveDartFrame();
+
+  // Leaves the frame and returns.
+  //
+  // The difference to "LeaveDartFrame(); Ret();" is that we return using
+  //
+  //   ldmia sp!, {fp, pc}
+  //
+  // instead of
+  //
+  //   ldmia sp!, {fp, lr}
+  //   blx lr
+  //
+  // This means that our return must go to ARM mode (and not thumb).
+  void LeaveDartFrameAndReturn();
 
   // Set up a Dart frame for a function compiled for on-stack replacement.
   // The frame layout is a normal Dart frame, but the frame is partially set
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 54d7abd..733efaf 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -138,8 +138,7 @@
   __ Bind(&stack_ok);
 #endif
   ASSERT(__ constant_pool_allowed());
-  __ LeaveDartFrame();  // Disallows constant pool use.
-  __ Ret();
+  __ LeaveDartFrameAndReturn();  // Disallows constant pool use.
   // This ReturnInstr may be emitted out of order by the optimizer. The next
   // block may be a target expecting a properly set constant pool pointer.
   __ set_constant_pool_allowed(true);
diff --git a/runtime/vm/object_arm_test.cc b/runtime/vm/object_arm_test.cc
index 4bebaef..5f9f3d7 100644
--- a/runtime/vm/object_arm_test.cc
+++ b/runtime/vm/object_arm_test.cc
@@ -36,8 +36,7 @@
   const String& string_object =
       String::ZoneHandle(String::New(str, Heap::kOld));
   __ LoadObject(R0, string_object);
-  __ LeaveDartFrame();
-  __ Ret();
+  __ LeaveDartFrameAndReturn();
 }
 
 // Generate a dart code sequence that embeds a smi object in it.
diff --git a/runtime/vm/stub_code_arm_test.cc b/runtime/vm/stub_code_arm_test.cc
index e717208..a006d7a 100644
--- a/runtime/vm/stub_code_arm_test.cc
+++ b/runtime/vm/stub_code_arm_test.cc
@@ -46,8 +46,7 @@
   __ CallRuntime(kAllocateArrayRuntimeEntry, argc);
   __ AddImmediate(SP, argc * kWordSize);
   __ Pop(R0);  // Pop return value from return slot.
-  __ LeaveDartFrame();
-  __ Ret();
+  __ LeaveDartFrameAndReturn();
 }
 
 TEST_CASE(CallRuntimeStubCode) {
@@ -83,8 +82,7 @@
   __ LoadObject(R2, rhs_index);
   __ LoadObject(R3, length);
   __ CallRuntime(kCaseInsensitiveCompareUC16RuntimeEntry, 4);
-  __ LeaveDartFrame();
-  __ Ret();  // Return value is in R0.
+  __ LeaveDartFrameAndReturn();  // Return value is in R0.
 }
 
 TEST_CASE(CallLeafRuntimeStubCode) {