ART: Fix 004-ReferenceMap run test

This patch adds a new option to ArtMethod::ToNativeQuickPc to select
the order of iteration over stack maps. The method is only used by
the runtime to find native_pc of catch blocks, but also by the
004-ReferenceMap test which uses it to find native_pc of a safepoint.

Change-Id: Idb2b34aabf1ac7249c30a00806af7d63d7e682dd
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 65f41cc..26839ec 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -223,7 +223,9 @@
   return DexFile::kDexNoIndex;
 }
 
-uintptr_t ArtMethod::ToNativeQuickPc(const uint32_t dex_pc, bool abort_on_failure) {
+uintptr_t ArtMethod::ToNativeQuickPc(const uint32_t dex_pc,
+                                     bool is_catch_handler,
+                                     bool abort_on_failure) {
   const void* entry_point = GetQuickOatEntryPoint(sizeof(void*));
   if (IsOptimized(sizeof(void*))) {
     // Optimized code does not have a mapping table. Search for the dex-to-pc
@@ -231,9 +233,12 @@
     CodeInfo code_info = GetOptimizedCodeInfo();
     StackMapEncoding encoding = code_info.ExtractEncoding();
 
-    // Assume the caller needs the mapping for a catch handler. If there are
-    // multiple stack maps for this dex_pc, it will hit the catch stack map first.
-    StackMap stack_map = code_info.GetCatchStackMapForDexPc(dex_pc, encoding);
+    // All stack maps are stored in the same CodeItem section, safepoint stack
+    // maps first, then catch stack maps. We use `is_catch_dex_pc` to select the
+    // order of iteration.
+    StackMap stack_map =
+        LIKELY(is_catch_handler) ? code_info.GetCatchStackMapForDexPc(dex_pc, encoding)
+                                 : code_info.GetStackMapForDexPc(dex_pc, encoding);
     if (stack_map.IsValid()) {
       return reinterpret_cast<uintptr_t>(entry_point) + stack_map.GetNativePcOffset(encoding);
     }
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 3f2161f..6c3b13f 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -442,7 +442,9 @@
       SHARED_REQUIRES(Locks::mutator_lock_);
 
   // Converts a dex PC to a native PC.
-  uintptr_t ToNativeQuickPc(const uint32_t dex_pc, bool abort_on_failure = true)
+  uintptr_t ToNativeQuickPc(const uint32_t dex_pc,
+                            bool is_catch_handler,
+                            bool abort_on_failure = true)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
   MethodReference ToMethodReference() SHARED_REQUIRES(Locks::mutator_lock_) {
diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc
index 33d756e..9f84bd2 100644
--- a/runtime/exception_test.cc
+++ b/runtime/exception_test.cc
@@ -186,13 +186,15 @@
     fake_stack.push_back(0);
   }
 
-  fake_stack.push_back(method_g_->ToNativeQuickPc(dex_pc));  // return pc
+  fake_stack.push_back(
+      method_g_->ToNativeQuickPc(dex_pc, /* is_catch_handler */ false));  // return pc
 
   // Create/push fake 16byte stack frame for method g
   fake_stack.push_back(reinterpret_cast<uintptr_t>(method_g_));
   fake_stack.push_back(0);
   fake_stack.push_back(0);
-  fake_stack.push_back(method_f_->ToNativeQuickPc(dex_pc));  // return pc
+  fake_stack.push_back(
+      method_g_->ToNativeQuickPc(dex_pc, /* is_catch_handler */ false));  // return pc
 
   // Create/push fake 16byte stack frame for method f
   fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_));
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index b9d76b4..c905b63 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -97,7 +97,8 @@
       if (found_dex_pc != DexFile::kDexNoIndex) {
         exception_handler_->SetHandlerMethod(method);
         exception_handler_->SetHandlerDexPc(found_dex_pc);
-        exception_handler_->SetHandlerQuickFramePc(method->ToNativeQuickPc(found_dex_pc));
+        exception_handler_->SetHandlerQuickFramePc(
+            method->ToNativeQuickPc(found_dex_pc, /* is_catch_handler */ true));
         exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
         return false;  // End stack walk.
       }
diff --git a/test/004-ReferenceMap/stack_walk_refmap_jni.cc b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
index 767e1de..55a77ac 100644
--- a/test/004-ReferenceMap/stack_walk_refmap_jni.cc
+++ b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
@@ -22,7 +22,9 @@
 #define CHECK_REGS_CONTAIN_REFS(dex_pc, abort_if_not_found, ...) do { \
   int t[] = {__VA_ARGS__}; \
   int t_size = sizeof(t) / sizeof(*t); \
-  uintptr_t native_quick_pc = m->ToNativeQuickPc(dex_pc, abort_if_not_found); \
+  uintptr_t native_quick_pc = m->ToNativeQuickPc(dex_pc, \
+                                                 /* is_catch_handler */ false, \
+                                                 abort_if_not_found); \
   if (native_quick_pc != UINTPTR_MAX) { \
     CheckReferences(t, t_size, m->NativeQuickPcOffset(native_quick_pc)); \
   } \