Improve `CanMethodUseNterp()`.

Avoid repeated reading of method's access flags and
repeated construction of `CodeItemDataAccessor`.
Avoid unnecessary rounding.

Test: testrunner.py --host --interpreter
Change-Id: I7390d5fc19f0e89a80c0b4ffe48a190eea21d998
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 308a070..16350e7 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -357,17 +357,19 @@
   }
 
   void SetMemorySharedMethod() REQUIRES_SHARED(Locks::mutator_lock_) {
-    if (!IsIntrinsic() && !IsAbstract()) {
+    uint32_t access_flags = GetAccessFlags();
+    if (!IsIntrinsic(access_flags) && !IsAbstract(access_flags)) {
       AddAccessFlags(kAccMemorySharedMethod);
       SetHotCounter();
     }
   }
 
   void ClearMemorySharedMethod() REQUIRES_SHARED(Locks::mutator_lock_) {
-    if (IsIntrinsic() || IsAbstract()) {
+    uint32_t access_flags = GetAccessFlags();
+    if (IsIntrinsic(access_flags) || IsAbstract(access_flags)) {
       return;
     }
-    if (IsMemorySharedMethod()) {
+    if (IsMemorySharedMethod(access_flags)) {
       ClearAccessFlags(kAccMemorySharedMethod);
     }
   }
@@ -797,7 +799,11 @@
   }
 
   bool HasCodeItem() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return !IsRuntimeMethod() && !IsNative() && !IsProxyMethod() && !IsAbstract();
+    uint32_t access_flags = GetAccessFlags();
+    return !IsNative(access_flags) &&
+           !IsAbstract(access_flags) &&
+           !IsRuntimeMethod() &&
+           !IsProxyMethod();
   }
 
   // We need to explicitly indicate whether the code item is obtained from the compact dex file,
diff --git a/runtime/nterp_helpers.cc b/runtime/nterp_helpers.cc
index 12afa3a..fb2046c 100644
--- a/runtime/nterp_helpers.cc
+++ b/runtime/nterp_helpers.cc
@@ -120,9 +120,7 @@
       static_cast<size_t>(InstructionSetPointerSize(isa));
 }
 
-static uint16_t GetNumberOfOutRegs(ArtMethod* method, InstructionSet isa)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  CodeItemDataAccessor accessor(method->DexInstructionData());
+static uint16_t GetNumberOfOutRegs(const CodeItemDataAccessor& accessor, InstructionSet isa) {
   uint16_t out_regs = accessor.OutsSize();
   switch (isa) {
     case InstructionSet::kX86: {
@@ -136,14 +134,23 @@
   return out_regs;
 }
 
-size_t NterpGetFrameSize(ArtMethod* method, InstructionSet isa) {
+static uint16_t GetNumberOfOutRegs(ArtMethod* method, InstructionSet isa)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  CodeItemDataAccessor accessor(method->DexInstructionData());
+  return GetNumberOfOutRegs(accessor, isa);
+}
+
+// Note: There may be two pieces of alignment but there is no need to align
+// out args to `kPointerSize` separately before aligning to kStackAlignment.
+// This allows using the size without padding for the maximum frame size check
+// in `CanMethodUseNterp()`.
+static size_t NterpGetFrameSizeWithoutPadding(ArtMethod* method, InstructionSet isa)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
   CodeItemDataAccessor accessor(method->DexInstructionData());
   const uint16_t num_regs = accessor.RegistersSize();
-  const uint16_t out_regs = GetNumberOfOutRegs(method, isa);
+  const uint16_t out_regs = GetNumberOfOutRegs(accessor, isa);
   size_t pointer_size = static_cast<size_t>(InstructionSetPointerSize(isa));
 
-  // Note: There may be two pieces of alignment but there is no need to align
-  // out args to `kPointerSize` separately before aligning to kStackAlignment.
   DCHECK(IsAlignedParam(kStackAlignment, pointer_size));
   DCHECK(IsAlignedParam(NterpGetFrameEntrySize(isa), pointer_size));
   DCHECK(IsAlignedParam(kVRegSize * 2, pointer_size));
@@ -154,7 +161,13 @@
       pointer_size +  // saved dex pc
       (out_regs * kVRegSize) +  // out arguments
       pointer_size;  // method
-  return RoundUp(frame_size, kStackAlignment);
+  return frame_size;
+}
+
+// The frame size nterp will use for the given method.
+static inline size_t NterpGetFrameSize(ArtMethod* method, InstructionSet isa)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  return RoundUp(NterpGetFrameSizeWithoutPadding(method, isa), kStackAlignment);
 }
 
 QuickMethodFrameInfo NterpFrameInfo(ArtMethod** frame) {
@@ -162,7 +175,7 @@
       RuntimeCalleeSaveFrame::GetCoreSpills(CalleeSaveType::kSaveAllCalleeSaves);
   uint32_t fp_spills =
       RuntimeCalleeSaveFrame::GetFpSpills(CalleeSaveType::kSaveAllCalleeSaves);
-  return QuickMethodFrameInfo(NterpGetFrameSize(*frame), core_spills, fp_spills);
+  return QuickMethodFrameInfo(NterpGetFrameSize(*frame, kRuntimeISA), core_spills, fp_spills);
 }
 
 uintptr_t NterpGetRegistersArray(ArtMethod** frame) {
@@ -206,13 +219,20 @@
 }
 
 bool CanMethodUseNterp(ArtMethod* method, InstructionSet isa) {
-  return !method->IsNative() &&
-      method->IsInvokable() &&
-      !method->MustCountLocks() &&
+  uint32_t access_flags = method->GetAccessFlags();
+  if (ArtMethod::IsNative(access_flags) ||
+      !ArtMethod::IsInvokable(access_flags) ||
+      ArtMethod::MustCountLocks(access_flags) ||
       // Proxy methods do not go through the JIT like other methods, so we don't
       // run them with nterp.
-      !method->IsProxyMethod() &&
-      NterpGetFrameSize(method, isa) <= interpreter::kNterpMaxFrame;
+      method->IsProxyMethod()) {
+    return false;
+  }
+  // There is no need to add the alignment padding size for comparison with aligned limit.
+  size_t frame_size_without_padding = NterpGetFrameSizeWithoutPadding(method, isa);
+  DCHECK_EQ(NterpGetFrameSize(method, isa), RoundUp(frame_size_without_padding, kStackAlignment));
+  static_assert(IsAligned<kStackAlignment>(interpreter::kNterpMaxFrame));
+  return frame_size_without_padding <= interpreter::kNterpMaxFrame;
 }
 
 }  // namespace art
diff --git a/runtime/nterp_helpers.h b/runtime/nterp_helpers.h
index 0f9e758..236059b 100644
--- a/runtime/nterp_helpers.h
+++ b/runtime/nterp_helpers.h
@@ -24,12 +24,6 @@
 class ArtMethod;
 
 /**
- * The frame size nterp will use for the given method.
- */
-size_t NterpGetFrameSize(ArtMethod* method, InstructionSet isa = kRuntimeISA)
-    REQUIRES_SHARED(Locks::mutator_lock_);
-
-/**
  * Returns the QuickMethodFrameInfo of the given frame corresponding to the
  * given method.
  */