Increment hotness in nterp when doing lookups.

Test: test.py
Test: google/perf/app-transition/app-transition-to-recents
Bug: 112676029
Bug: 157402634
Change-Id: Ibe08720b442c5050062db1104be2d3a62641e629
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index f7fe27d..8bf38d3 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -88,6 +88,7 @@
 #include "imtable-inl.h"
 #include "intern_table-inl.h"
 #include "interpreter/interpreter.h"
+#include "interpreter/mterp/nterp.h"
 #include "jit/debugger_interface.h"
 #include "jit/jit.h"
 #include "jit/jit_code_cache.h"
diff --git a/runtime/interpreter/mterp/arm64ng/main.S b/runtime/interpreter/mterp/arm64ng/main.S
index ea04b45..d1ff448 100644
--- a/runtime/interpreter/mterp/arm64ng/main.S
+++ b/runtime/interpreter/mterp/arm64ng/main.S
@@ -313,7 +313,7 @@
     ldr x0, [sp]
     ldrh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
     add x2, x2, #1
-    and w2, w2, #0xffff
+    and w2, w2, #NTERP_HOTNESS_MASK
     strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
     // If the counter overflows, handle this in the runtime.
     cbz w2, NterpHandleHotnessOverflow
@@ -382,7 +382,7 @@
     ldr x0, [sp]
     ldrh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
     add x2, x2, #1
-    and w2, w2, #0xffff
+    and w2, w2, #NTERP_HOTNESS_MASK
     strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
     // If the counter overflows, handle this in the runtime.
     cbz w2, 2f
diff --git a/runtime/interpreter/mterp/mterp.h b/runtime/interpreter/mterp/mterp.h
index 7813fca..bc057c2 100644
--- a/runtime/interpreter/mterp/mterp.h
+++ b/runtime/interpreter/mterp/mterp.h
@@ -28,24 +28,15 @@
 extern "C" void* artMterpAsmInstructionStart[];
 extern "C" void* artMterpAsmInstructionEnd[];
 
-extern "C" void* artNterpAsmInstructionStart[];
-extern "C" void* artNterpAsmInstructionEnd[];
-
 namespace art {
 
-class ArtMethod;
 class Thread;
 
 namespace interpreter {
 
 void InitMterpTls(Thread* self);
 void CheckMterpAsmConstants();
-void CheckNterpAsmConstants();
 bool CanUseMterp();
-bool IsNterpSupported();
-bool CanRuntimeUseNterp();
-bool CanMethodUseNterp(ArtMethod* method);
-const void* GetNterpEntryPoint();
 
 // Poison value for TestExportPC.  If we segfault with this value, it means that a mterp
 // handler for a recent opcode failed to export the Dalvik PC prior to a possible exit from
@@ -56,9 +47,6 @@
 
 constexpr size_t kMterpHandlerSize = 128;
 
-// The maximum we will allow an nterp frame to be.
-constexpr size_t kMaxNterpFrame = 3 * KB;
-
 }  // namespace interpreter
 }  // namespace art
 
diff --git a/runtime/interpreter/mterp/nterp.cc b/runtime/interpreter/mterp/nterp.cc
index 2eb3650..95b4243 100644
--- a/runtime/interpreter/mterp/nterp.cc
+++ b/runtime/interpreter/mterp/nterp.cc
@@ -17,7 +17,7 @@
 /*
  * Mterp entry point and support functions.
  */
-#include "mterp.h"
+#include "nterp.h"
 
 #include "base/quasi_atomic.h"
 #include "dex/dex_instruction_utils.h"
@@ -45,7 +45,7 @@
   return method->SkipAccessChecks() &&
       !method->IsNative() &&
       method->GetDexFile()->IsStandardDexFile() &&
-      NterpGetFrameSize(method) < kMaxNterpFrame;
+      NterpGetFrameSize(method) < kNterpMaxFrame;
 }
 
 const void* GetNterpEntryPoint() {
@@ -71,6 +71,24 @@
   }
 }
 
+inline void UpdateHotness(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
+  // The hotness we will add to a method when we perform a
+  // field/method/class/string lookup.
+  constexpr uint16_t kNterpHotnessLookup = 0xff;
+
+  // Convert to uint32_t to handle uint16_t overflow.
+  uint32_t counter = method->GetCounter();
+  uint32_t new_counter = counter + kNterpHotnessLookup;
+  if ((new_counter & kNterpHotnessMask) == 0) {
+    // Let the nterp code actually call the compilation: we want to make sure
+    // there's at least a second execution of the method or a back-edge to avoid
+    // compiling straightline initialization methods.
+    method->SetCounter(kNterpHotnessMask - 1);
+  } else {
+    method->SetCounter(new_counter);
+  }
+}
+
 template<typename T>
 inline void UpdateCache(Thread* self, uint16_t* dex_pc_ptr, T value) {
   DCHECK(kUseReadBarrier) << "Nterp only works with read barriers";
@@ -129,6 +147,7 @@
 
 extern "C" size_t NterpGetMethod(Thread* self, ArtMethod* caller, uint16_t* dex_pc_ptr)
     REQUIRES_SHARED(Locks::mutator_lock_) {
+  UpdateHotness(caller);
   const Instruction* inst = Instruction::At(dex_pc_ptr);
   InvokeType invoke_type = kStatic;
   uint16_t method_index = 0;
@@ -320,6 +339,7 @@
 
 extern "C" size_t NterpGetStaticField(Thread* self, ArtMethod* caller, uint16_t* dex_pc_ptr)
     REQUIRES_SHARED(Locks::mutator_lock_) {
+  UpdateHotness(caller);
   const Instruction* inst = Instruction::At(dex_pc_ptr);
   uint16_t field_index = inst->VRegB_21c();
   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
@@ -360,6 +380,7 @@
                                                 ArtMethod* caller,
                                                 uint16_t* dex_pc_ptr)
     REQUIRES_SHARED(Locks::mutator_lock_) {
+  UpdateHotness(caller);
   const Instruction* inst = Instruction::At(dex_pc_ptr);
   uint16_t field_index = inst->VRegC_22c();
   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
@@ -387,6 +408,7 @@
                                                          ArtMethod* caller,
                                                          uint16_t* dex_pc_ptr)
     REQUIRES_SHARED(Locks::mutator_lock_) {
+  UpdateHotness(caller);
   const Instruction* inst = Instruction::At(dex_pc_ptr);
   dex::TypeIndex index;
   switch (inst->Opcode()) {
@@ -446,6 +468,7 @@
   switch (inst->Opcode()) {
     case Instruction::CONST_STRING:
     case Instruction::CONST_STRING_JUMBO: {
+      UpdateHotness(caller);
       dex::StringIndex string_index(
           (inst->Opcode() == Instruction::CONST_STRING)
               ? inst->VRegB_21c()
diff --git a/runtime/interpreter/mterp/nterp.h b/runtime/interpreter/mterp/nterp.h
new file mode 100644
index 0000000..a1bf941
--- /dev/null
+++ b/runtime/interpreter/mterp/nterp.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_INTERPRETER_MTERP_NTERP_H_
+#define ART_RUNTIME_INTERPRETER_MTERP_NTERP_H_
+
+#include "base/globals.h"
+
+extern "C" void* artNterpAsmInstructionStart[];
+extern "C" void* artNterpAsmInstructionEnd[];
+
+namespace art {
+
+class ArtMethod;
+
+namespace interpreter {
+
+void CheckNterpAsmConstants();
+bool IsNterpSupported();
+bool CanRuntimeUseNterp();
+bool CanMethodUseNterp(ArtMethod* method);
+const void* GetNterpEntryPoint();
+
+// The hotness threshold where we trigger JIT compilation or OSR.
+constexpr uint16_t kNterpHotnessMask = 0xffff;
+
+// The maximum we allow an nterp frame to be.
+constexpr size_t kNterpMaxFrame = 3 * KB;
+
+// The maximum size for each nterp opcode handler.
+constexpr size_t kNterpHandlerSize = 128;
+
+}  // namespace interpreter
+}  // namespace art
+
+#endif  // ART_RUNTIME_INTERPRETER_MTERP_NTERP_H_
diff --git a/runtime/interpreter/mterp/x86_64ng/main.S b/runtime/interpreter/mterp/x86_64ng/main.S
index a890245..16bd1e4 100644
--- a/runtime/interpreter/mterp/x86_64ng/main.S
+++ b/runtime/interpreter/mterp/x86_64ng/main.S
@@ -255,6 +255,9 @@
     GOTO_NEXT
 3:
     movq (%rsp), %rdi
+#if (NTERP_HOTNESS_MASK != 0xffff)
+#error "Nterp x86_64 expects Nterp hotness mask to be 0xffff"
+#endif
     addw $$1, ART_METHOD_HOTNESS_COUNT_OFFSET(%rdi)
     // If the counter overflows, handle this in the runtime.
     jo NterpHandleHotnessOverflow
@@ -741,6 +744,9 @@
 // Increase method hotness and do suspend check before starting executing the method.
 .macro START_EXECUTING_INSTRUCTIONS
    movq (%rsp), %rdi
+#if (NTERP_HOTNESS_MASK != 0xffff)
+#error "Nterp x86_64 expects Nterp hotness mask to be 0xffff"
+#endif
    addw $$1, ART_METHOD_HOTNESS_COUNT_OFFSET(%rdi)
    jo 2f
    testl $$(THREAD_SUSPEND_OR_CHECKPOINT_REQUEST), rSELF:THREAD_FLAGS_OFFSET
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index 853db10..e604738 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -27,7 +27,7 @@
 #include "compilation_kind.h"
 #include "handle.h"
 #include "offsets.h"
-#include "interpreter/mterp/mterp.h"
+#include "interpreter/mterp/nterp.h"
 #include "jit/debugger_interface.h"
 #include "jit/profile_saver_options.h"
 #include "obj_ptr.h"
diff --git a/runtime/nterp_helpers.cc b/runtime/nterp_helpers.cc
index d622241..7e76bc3 100644
--- a/runtime/nterp_helpers.cc
+++ b/runtime/nterp_helpers.cc
@@ -17,7 +17,7 @@
 #include "art_method-inl.h"
 #include "dex/code_item_accessors.h"
 #include "entrypoints/quick/callee_save_frame.h"
-#include "interpreter/interpreter_mterp_impl.h"
+#include "interpreter/mterp/nterp.h"
 #include "nterp_helpers.h"
 #include "oat_quick_method_header.h"
 #include "quick/quick_method_frame_info.h"
diff --git a/runtime/oat_quick_method_header.cc b/runtime/oat_quick_method_header.cc
index bbc3bfa..543ff72 100644
--- a/runtime/oat_quick_method_header.cc
+++ b/runtime/oat_quick_method_header.cc
@@ -20,7 +20,7 @@
 #include "art_method.h"
 #include "dex/dex_file_types.h"
 #include "interpreter/interpreter_mterp_impl.h"
-#include "interpreter/mterp/mterp.h"
+#include "interpreter/mterp/nterp.h"
 #include "nterp_helpers.h"
 #include "scoped_thread_state_change-inl.h"
 #include "stack_map.h"
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 58a73cc..a5e2f44 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -30,6 +30,7 @@
 #include "entrypoints/runtime_asm_entrypoints.h"
 #include "gc/space/image_space.h"
 #include "gc/space/space-inl.h"
+#include "interpreter/mterp/nterp.h"
 #include "interpreter/shadow_frame-inl.h"
 #include "jit/jit.h"
 #include "jit/jit_code_cache.h"
@@ -766,7 +767,7 @@
       // 2 words HandleScope overhead
       // 3+3 register spills
       // const size_t kMaxExpectedFrameSize = (256 + 2 + 3 + 3) * sizeof(word);
-      const size_t kMaxExpectedFrameSize = interpreter::kMaxNterpFrame;
+      const size_t kMaxExpectedFrameSize = interpreter::kNterpMaxFrame;
       CHECK_LE(frame_size, kMaxExpectedFrameSize) << method->PrettyMethod();
       size_t return_pc_offset = GetCurrentQuickFrameInfo().GetReturnPcOffset();
       CHECK_LT(return_pc_offset, frame_size);
diff --git a/tools/cpp-define-generator/globals.def b/tools/cpp-define-generator/globals.def
index 6706fed..50ca3d6 100644
--- a/tools/cpp-define-generator/globals.def
+++ b/tools/cpp-define-generator/globals.def
@@ -23,6 +23,7 @@
 #include "gc/accounting/card_table.h"
 #include "gc/heap.h"
 #include "interpreter/mterp/mterp.h"
+#include "interpreter/mterp/nterp.h"
 #include "jit/jit.h"
 #include "mirror/object.h"
 #include "mirror/object_reference.h"
@@ -80,3 +81,5 @@
            std::memory_order_relaxed)
 ASM_DEFINE(STACK_OVERFLOW_RESERVED_BYTES,
            GetStackOverflowReservedBytes(art::kRuntimeISA))
+ASM_DEFINE(NTERP_HOTNESS_MASK,
+           art::interpreter::kNterpHotnessMask)