Use ArtMethod* .bss entries for HInvokeStaticOrDirect.

Test: m test-art-host-gtest
Test: testrunner.py --host
Test: testrunner.py --target
Test: Nexus 6P boots.
Test: Build aosp_mips64-userdebug.
Bug: 30627598
Change-Id: I0e54fdd2e91e983d475b7a04d40815ba89ae3d4f
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index a816522..888de45 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -246,6 +246,9 @@
     }
     // Readjust to be non-inclusive upper bound.
     bss_end_ += sizeof(uint32_t);
+    // Find bss methods if present.
+    bss_methods_ =
+        const_cast<uint8_t*>(FindDynamicSymbolAddress("oatbssmethods", &symbol_error_msg));
     // Find bss roots if present.
     bss_roots_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatbssroots", &symbol_error_msg));
   }
@@ -311,51 +314,63 @@
                               cause.c_str());
     return false;
   }
-  const uint8_t* oat = Begin();
-  oat += sizeof(OatHeader);
-  if (oat > End()) {
-    *error_msg = StringPrintf("In oat file '%s' found truncated OatHeader", GetLocation().c_str());
-    return false;
-  }
-
-  oat += GetOatHeader().GetKeyValueStoreSize();
-  if (oat > End()) {
-    *error_msg = StringPrintf("In oat file '%s' found truncated variable-size data: "
-                                  "%p + %zu + %u <= %p",
+  PointerSize pointer_size = GetInstructionSetPointerSize(GetOatHeader().GetInstructionSet());
+  size_t key_value_store_size =
+      (Size() >= sizeof(OatHeader)) ? GetOatHeader().GetKeyValueStoreSize() : 0u;
+  if (Size() < sizeof(OatHeader) + key_value_store_size) {
+    *error_msg = StringPrintf("In oat file '%s' found truncated OatHeader, "
+                                  "size = %zu < %zu + %zu",
                               GetLocation().c_str(),
-                              Begin(),
+                              Size(),
                               sizeof(OatHeader),
-                              GetOatHeader().GetKeyValueStoreSize(),
-                              End());
+                              key_value_store_size);
     return false;
   }
 
-  if (!IsAligned<alignof(GcRoot<mirror::Object>)>(bss_begin_) ||
-      !IsAligned<alignof(GcRoot<mirror::Object>)>(bss_roots_) ||
+  size_t oat_dex_files_offset = GetOatHeader().GetOatDexFilesOffset();
+  if (oat_dex_files_offset < GetOatHeader().GetHeaderSize() || oat_dex_files_offset > Size()) {
+    *error_msg = StringPrintf("In oat file '%s' found invalid oat dex files offset: "
+                                  "%zu is not in [%zu, %zu]",
+                              GetLocation().c_str(),
+                              oat_dex_files_offset,
+                              GetOatHeader().GetHeaderSize(),
+                              Size());
+    return false;
+  }
+  const uint8_t* oat = Begin() + oat_dex_files_offset;  // Jump to the OatDexFile records.
+
+  DCHECK_GE(static_cast<size_t>(pointer_size), alignof(GcRoot<mirror::Object>));
+  if (!IsAligned<kPageSize>(bss_begin_) ||
+      !IsAlignedParam(bss_methods_, static_cast<size_t>(pointer_size)) ||
+      !IsAlignedParam(bss_roots_, static_cast<size_t>(pointer_size)) ||
       !IsAligned<alignof(GcRoot<mirror::Object>)>(bss_end_)) {
     *error_msg = StringPrintf("In oat file '%s' found unaligned bss symbol(s): "
-                                  "begin = %p, roots = %p, end = %p",
+                                  "begin = %p, methods_ = %p, roots = %p, end = %p",
                               GetLocation().c_str(),
                               bss_begin_,
+                              bss_methods_,
                               bss_roots_,
                               bss_end_);
     return false;
   }
 
-  if (bss_roots_ != nullptr && (bss_roots_ < bss_begin_ || bss_roots_ > bss_end_)) {
-    *error_msg = StringPrintf("In oat file '%s' found bss roots outside .bss: "
-                                  "%p is outside range [%p, %p]",
+  if ((bss_methods_ != nullptr && (bss_methods_ < bss_begin_ || bss_methods_ > bss_end_)) ||
+      (bss_roots_ != nullptr && (bss_roots_ < bss_begin_ || bss_roots_ > bss_end_)) ||
+      (bss_methods_ != nullptr && bss_roots_ != nullptr && bss_methods_ > bss_roots_)) {
+    *error_msg = StringPrintf("In oat file '%s' found bss symbol(s) outside .bss or unordered: "
+                                  "begin = %p, methods_ = %p, roots = %p, end = %p",
                               GetLocation().c_str(),
-                              bss_roots_,
                               bss_begin_,
+                              bss_methods_,
+                              bss_roots_,
                               bss_end_);
     return false;
   }
 
-  PointerSize pointer_size = GetInstructionSetPointerSize(GetOatHeader().GetInstructionSet());
-  uint8_t* dex_cache_arrays = (bss_begin_ == bss_roots_) ? nullptr : bss_begin_;
+  uint8_t* after_arrays = (bss_methods_ != nullptr) ? bss_methods_ : bss_roots_;  // May be null.
+  uint8_t* dex_cache_arrays = (bss_begin_ == after_arrays) ? nullptr : bss_begin_;
   uint8_t* dex_cache_arrays_end =
-      (bss_begin_ == bss_roots_) ? nullptr : (bss_roots_ != nullptr) ? bss_roots_ : bss_end_;
+      (bss_begin_ == after_arrays) ? nullptr : (after_arrays != nullptr) ? after_arrays : bss_end_;
   DCHECK_EQ(dex_cache_arrays != nullptr, dex_cache_arrays_end != nullptr);
   uint32_t dex_file_count = GetOatHeader().GetDexFileCount();
   oat_dex_files_storage_.reserve(dex_file_count);
@@ -529,6 +544,55 @@
       return false;
     }
 
+    uint32_t method_bss_mapping_offset;
+    if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &method_bss_mapping_offset))) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated "
+                                    "after method bss mapping offset",
+                                GetLocation().c_str(),
+                                i,
+                                dex_file_location.c_str());
+      return false;
+    }
+    const bool readable_method_bss_mapping_size =
+        method_bss_mapping_offset != 0u &&
+        method_bss_mapping_offset <= Size() &&
+        IsAligned<alignof(MethodBssMapping)>(method_bss_mapping_offset) &&
+        Size() - method_bss_mapping_offset >= MethodBssMapping::ComputeSize(0);
+    const MethodBssMapping* method_bss_mapping = readable_method_bss_mapping_size
+        ? reinterpret_cast<const MethodBssMapping*>(Begin() + method_bss_mapping_offset)
+        : nullptr;
+    if (method_bss_mapping_offset != 0u &&
+        (UNLIKELY(method_bss_mapping == nullptr) ||
+            UNLIKELY(method_bss_mapping->size() == 0u) ||
+            UNLIKELY(Size() - method_bss_mapping_offset <
+                     MethodBssMapping::ComputeSize(method_bss_mapping->size())))) {
+      *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with unaligned or "
+                                    " truncated method bss mapping, offset %u of %zu, length %zu",
+                                GetLocation().c_str(),
+                                i,
+                                dex_file_location.c_str(),
+                                method_bss_mapping_offset,
+                                Size(),
+                                method_bss_mapping != nullptr ? method_bss_mapping->size() : 0u);
+      return false;
+    }
+    if (kIsDebugBuild && method_bss_mapping != nullptr) {
+      const MethodBssMappingEntry* prev_entry = nullptr;
+      for (const MethodBssMappingEntry& entry : *method_bss_mapping) {
+        CHECK_ALIGNED_PARAM(entry.bss_offset, static_cast<size_t>(pointer_size));
+        CHECK_LT(entry.bss_offset, BssSize());
+        CHECK_LE(POPCOUNT(entry.index_mask) * static_cast<size_t>(pointer_size),  entry.bss_offset);
+        size_t index_mask_span = (entry.index_mask != 0u) ? 16u - CTZ(entry.index_mask) : 0u;
+        CHECK_LE(index_mask_span, entry.method_index);
+        if (prev_entry != nullptr) {
+          CHECK_LT(prev_entry->method_index, entry.method_index - index_mask_span);
+        }
+        prev_entry = &entry;
+      }
+      CHECK_LT(prev_entry->method_index,
+               reinterpret_cast<const DexFile::Header*>(dex_file_pointer)->method_ids_size_);
+    }
+
     uint8_t* current_dex_cache_arrays = nullptr;
     if (dex_cache_arrays != nullptr) {
       // All DexCache types except for CallSite have their instance counts in the
@@ -569,6 +633,7 @@
                                               dex_file_checksum,
                                               dex_file_pointer,
                                               lookup_table_data,
+                                              method_bss_mapping,
                                               class_offsets_pointer,
                                               current_dex_cache_arrays);
     oat_dex_files_storage_.push_back(oat_dex_file);
@@ -1158,6 +1223,7 @@
       end_(nullptr),
       bss_begin_(nullptr),
       bss_end_(nullptr),
+      bss_methods_(nullptr),
       bss_roots_(nullptr),
       is_executable_(is_executable),
       secondary_lookup_lock_("OatFile secondary lookup lock", kOatFileSecondaryLookupLock) {
@@ -1198,6 +1264,17 @@
   return kIsVdexEnabled ? vdex_->End() : End();
 }
 
+ArrayRef<ArtMethod*> OatFile::GetBssMethods() const {
+  if (bss_methods_ != nullptr) {
+    ArtMethod** methods = reinterpret_cast<ArtMethod**>(bss_methods_);
+    ArtMethod** methods_end =
+        reinterpret_cast<ArtMethod**>(bss_roots_ != nullptr ? bss_roots_ : bss_end_);
+    return ArrayRef<ArtMethod*>(methods, methods_end - methods);
+  } else {
+    return ArrayRef<ArtMethod*>();
+  }
+}
+
 ArrayRef<GcRoot<mirror::Object>> OatFile::GetBssGcRoots() const {
   if (bss_roots_ != nullptr) {
     auto* roots = reinterpret_cast<GcRoot<mirror::Object>*>(bss_roots_);
@@ -1283,6 +1360,7 @@
                                 uint32_t dex_file_location_checksum,
                                 const uint8_t* dex_file_pointer,
                                 const uint8_t* lookup_table_data,
+                                const MethodBssMapping* method_bss_mapping_data,
                                 const uint32_t* oat_class_offsets_pointer,
                                 uint8_t* dex_cache_arrays)
     : oat_file_(oat_file),
@@ -1291,6 +1369,7 @@
       dex_file_location_checksum_(dex_file_location_checksum),
       dex_file_pointer_(dex_file_pointer),
       lookup_table_data_(lookup_table_data),
+      method_bss_mapping_(method_bss_mapping_data),
       oat_class_offsets_pointer_(oat_class_offsets_pointer),
       dex_cache_arrays_(dex_cache_arrays) {
   // Initialize TypeLookupTable.