Refactor DecodeDebugLocalInfo

Refactor the function to use a visitor instead of callback.

Test: test-art-ghost
Bug: 112311591
Bug: 77709234

Change-Id: I55385994952373b3fec4f9122400cf3c9d43da3b
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h
index 233f61c..fe05992 100644
--- a/compiler/debug/elf_debug_info_writer.h
+++ b/compiler/debug/elf_debug_info_writer.h
@@ -41,12 +41,6 @@
 namespace art {
 namespace debug {
 
-typedef std::vector<DexFile::LocalInfo> LocalInfos;
-
-static void LocalInfoCallback(void* ctx, const DexFile::LocalInfo& entry) {
-  static_cast<LocalInfos*>(ctx)->push_back(entry);
-}
-
 static std::vector<const char*> GetParamNames(const MethodDebugInfo* mi) {
   std::vector<const char*> names;
   DCHECK(mi->dex_file != nullptr);
@@ -251,11 +245,12 @@
       }
 
       // Write local variables.
-      LocalInfos local_infos;
+      std::vector<DexFile::LocalInfo> local_infos;
       if (accessor.DecodeDebugLocalInfo(is_static,
                                         mi->dex_method_index,
-                                        LocalInfoCallback,
-                                        &local_infos)) {
+                                        [&](const DexFile::LocalInfo& entry) {
+                                          local_infos.push_back(entry);
+                                        })) {
         for (const DexFile::LocalInfo& var : local_infos) {
           if (var.reg_ < accessor.RegistersSize() - accessor.InsSize()) {
             info_.StartTag(DW_TAG_variable);
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 31bc6e3..95d88be 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -751,16 +751,6 @@
 }
 
 /*
- * Callback for dumping locals table entry.
- */
-static void dumpLocalsCb(void* /*context*/, const DexFile::LocalInfo& entry) {
-  const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
-  fprintf(gOutFile, "        0x%04x - 0x%04x reg=%d %s %s %s\n",
-          entry.start_address_, entry.end_address_, entry.reg_,
-          entry.name_, entry.descriptor_, signature);
-}
-
-/*
  * Helper for dumpInstruction(), which builds the string
  * representation for the index in the given instruction.
  * Returns a pointer to a buffer of sufficient size.
@@ -1198,7 +1188,19 @@
     return false;
   });
   fprintf(gOutFile, "      locals        : \n");
-  accessor.DecodeDebugLocalInfo(is_static, idx, dumpLocalsCb, nullptr);
+  accessor.DecodeDebugLocalInfo(is_static,
+                                idx,
+                                [&](const DexFile::LocalInfo& entry) {
+    const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
+    fprintf(gOutFile,
+            "        0x%04x - 0x%04x reg=%d %s %s %s\n",
+            entry.start_address_,
+            entry.end_address_,
+            entry.reg_,
+            entry.name_,
+            entry.descriptor_,
+            signature);
+  });
 }
 
 /*
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 148c0c7..b539f5d 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -1037,17 +1037,6 @@
 }
 
 /*
- * Callback for dumping locals table entry.
- */
-static void DumpLocalsCb(void* context, const DexFile::LocalInfo& entry) {
-  const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
-  FILE* out_file = reinterpret_cast<FILE*>(context);
-  fprintf(out_file, "        0x%04x - 0x%04x reg=%d %s %s %s\n",
-          entry.start_address_, entry.end_address_, entry.reg_,
-          entry.name_, entry.descriptor_, signature);
-}
-
-/*
  * Lookup functions.
  */
 static const char* StringDataByIdx(uint32_t idx, dex_ir::Header* header) {
@@ -1140,8 +1129,18 @@
                                         StringDataByTypeIdx(dchecked_integral_cast<uint16_t>(idx),
                                                             this->header_);
                                   },
-                                  DumpLocalsCb,
-                                  out_file_);
+                                  [&](const DexFile::LocalInfo& entry) {
+                                    const char* signature =
+                                        entry.signature_ != nullptr ? entry.signature_ : "";
+                                    fprintf(out_file_,
+                                            "        0x%04x - 0x%04x reg=%d %s %s %s\n",
+                                            entry.start_address_,
+                                            entry.end_address_,
+                                            entry.reg_,
+                                            entry.name_,
+                                            entry.descriptor_,
+                                            signature);
+                                  });
   }
 }
 
diff --git a/libdexfile/dex/code_item_accessors-inl.h b/libdexfile/dex/code_item_accessors-inl.h
index c7e876e..bbf2224 100644
--- a/libdexfile/dex/code_item_accessors-inl.h
+++ b/libdexfile/dex/code_item_accessors-inl.h
@@ -184,19 +184,18 @@
   CodeItemDataAccessor::Init(code_item);
 }
 
-template<typename NewLocalCallback>
-inline bool CodeItemDebugInfoAccessor::DecodeDebugLocalInfo(bool is_static,
-                                                            uint32_t method_idx,
-                                                            NewLocalCallback new_local,
-                                                            void* context) const {
+template<typename NewLocalVisitor>
+inline bool CodeItemDebugInfoAccessor::DecodeDebugLocalInfo(
+    bool is_static,
+    uint32_t method_idx,
+    const NewLocalVisitor& new_local) const {
   return dex_file_->DecodeDebugLocalInfo(RegistersSize(),
                                          InsSize(),
                                          InsnsSizeInCodeUnits(),
                                          DebugInfoOffset(),
                                          is_static,
                                          method_idx,
-                                         new_local,
-                                         context);
+                                         new_local);
 }
 
 template <typename Visitor>
diff --git a/libdexfile/dex/code_item_accessors.h b/libdexfile/dex/code_item_accessors.h
index c2aa23c..c307c9f 100644
--- a/libdexfile/dex/code_item_accessors.h
+++ b/libdexfile/dex/code_item_accessors.h
@@ -151,11 +151,10 @@
     return debug_info_offset_;
   }
 
-  template<typename NewLocalCallback>
+  template<typename NewLocalVisitor>
   bool DecodeDebugLocalInfo(bool is_static,
                             uint32_t method_idx,
-                            NewLocalCallback new_local,
-                            void* context) const;
+                            const NewLocalVisitor& new_local) const;
 
   // Visit each parameter in the debug information. Returns the line number.
   // The argument of the Visitor is dex::StringIndex.
diff --git a/libdexfile/dex/dex_file-inl.h b/libdexfile/dex/dex_file-inl.h
index eca9ee9..eae7efc 100644
--- a/libdexfile/dex/dex_file-inl.h
+++ b/libdexfile/dex/dex_file-inl.h
@@ -215,10 +215,9 @@
                                    uint16_t registers_size,
                                    uint16_t ins_size,
                                    uint16_t insns_size_in_code_units,
-                                   IndexToStringData index_to_string_data,
-                                   TypeIndexToStringData type_index_to_string_data,
-                                   NewLocalCallback new_local_callback,
-                                   void* context) {
+                                   const IndexToStringData& index_to_string_data,
+                                   const TypeIndexToStringData& type_index_to_string_data,
+                                   const NewLocalCallback& new_local_callback) {
   if (stream == nullptr) {
     return false;
   }
@@ -278,7 +277,7 @@
         for (uint16_t reg = 0; reg < registers_size; reg++) {
           if (local_in_reg[reg].is_live_) {
             local_in_reg[reg].end_address_ = insns_size_in_code_units;
-            new_local_callback(context, local_in_reg[reg]);
+            new_local_callback(local_in_reg[reg]);
           }
         }
         return true;
@@ -307,7 +306,7 @@
         // Emit what was previously there, if anything
         if (local_in_reg[reg].is_live_) {
           local_in_reg[reg].end_address_ = address;
-          new_local_callback(context, local_in_reg[reg]);
+          new_local_callback(local_in_reg[reg]);
         }
 
         local_in_reg[reg].name_ = index_to_string_data(name_idx);
@@ -329,7 +328,7 @@
         // closed register is sloppy, but harmless if no further action is taken.
         if (local_in_reg[reg].is_live_) {
           local_in_reg[reg].end_address_ = address;
-          new_local_callback(context, local_in_reg[reg]);
+          new_local_callback(local_in_reg[reg]);
           local_in_reg[reg].is_live_ = false;
         }
         break;
@@ -369,8 +368,7 @@
                                    uint32_t debug_info_offset,
                                    bool is_static,
                                    uint32_t method_idx,
-                                   NewLocalCallback new_local_callback,
-                                   void* context) const {
+                                   const NewLocalCallback& new_local_callback) const {
   const uint8_t* const stream = GetDebugInfoStream(debug_info_offset);
   if (stream == nullptr) {
     return false;
@@ -396,8 +394,7 @@
                                 return StringByTypeIdx(dex::TypeIndex(
                                     dchecked_integral_cast<uint16_t>(idx)));
                               },
-                              new_local_callback,
-                              context);
+                              new_local_callback);
 }
 
 template<typename DexDebugNewPosition, typename IndexToStringData>
diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h
index 3e4a481..30d8b6d 100644
--- a/libdexfile/dex/dex_file.h
+++ b/libdexfile/dex/dex_file.h
@@ -874,10 +874,9 @@
                                    uint16_t registers_size,
                                    uint16_t ins_size,
                                    uint16_t insns_size_in_code_units,
-                                   IndexToStringData index_to_string_data,
-                                   TypeIndexToStringData type_index_to_string_data,
-                                   NewLocalCallback new_local,
-                                   void* context);
+                                   const IndexToStringData& index_to_string_data,
+                                   const TypeIndexToStringData& type_index_to_string_data,
+                                   const NewLocalCallback& new_local) NO_THREAD_SAFETY_ANALYSIS;
   template<typename NewLocalCallback>
   bool DecodeDebugLocalInfo(uint32_t registers_size,
                             uint32_t ins_size,
@@ -885,8 +884,7 @@
                             uint32_t debug_info_offset,
                             bool is_static,
                             uint32_t method_idx,
-                            NewLocalCallback new_local,
-                            void* context) const;
+                            const NewLocalCallback& new_local) const;
 
   // Returns false if there is no debugging information or if it cannot be decoded.
   template<typename DexDebugNewPosition, typename IndexToStringData>
diff --git a/libdexfile/dex/dex_file_loader_test.cc b/libdexfile/dex/dex_file_loader_test.cc
index 5bb01dd..5378617 100644
--- a/libdexfile/dex/dex_file_loader_test.cc
+++ b/libdexfile/dex/dex_file_loader_test.cc
@@ -480,10 +480,6 @@
   EXPECT_EQ(raw->StringByTypeIdx(idx), nullptr);
 }
 
-static void Callback(void* context ATTRIBUTE_UNUSED,
-                     const DexFile::LocalInfo& entry ATTRIBUTE_UNUSED) {
-}
-
 TEST_F(DexFileLoaderTest, OpenDexDebugInfoLocalNullType) {
   std::vector<uint8_t> dex_bytes;
   std::unique_ptr<const DexFile> raw = OpenDexFileInMemoryBase64(kRawDexDebugInfoLocalNullType,
@@ -496,7 +492,7 @@
   const DexFile::CodeItem* code_item = raw->GetCodeItem(raw->FindCodeItemOffset(class_def,
                                                                                 kMethodIdx));
   CodeItemDebugInfoAccessor accessor(*raw, code_item, kMethodIdx);
-  ASSERT_TRUE(accessor.DecodeDebugLocalInfo(true, 1, Callback, nullptr));
+  ASSERT_TRUE(accessor.DecodeDebugLocalInfo(true, 1, VoidFunctor()));
 }
 
 }  // namespace art
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index 742a9fa..2958941 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -206,76 +206,59 @@
     return ERR(ABSENT_INFORMATION);
   }
 
-  struct LocalVariableContext {
-    explicit LocalVariableContext(jvmtiEnv* jenv) : env_(jenv), variables_(), err_(OK) {}
+  std::vector<jvmtiLocalVariableEntry> variables;
+  jvmtiError err = OK;
 
-    static void Callback(void* raw_ctx, const art::DexFile::LocalInfo& entry) {
-      reinterpret_cast<LocalVariableContext*>(raw_ctx)->Insert(entry);
+  auto release = [&](jint* out_entry_count_ptr, jvmtiLocalVariableEntry** out_table_ptr) {
+    jlong table_size = sizeof(jvmtiLocalVariableEntry) * variables.size();
+    if (err != OK ||
+        (err = env->Allocate(table_size,
+                              reinterpret_cast<unsigned char**>(out_table_ptr))) != OK) {
+      for (jvmtiLocalVariableEntry& e : variables) {
+        env->Deallocate(reinterpret_cast<unsigned char*>(e.name));
+        env->Deallocate(reinterpret_cast<unsigned char*>(e.signature));
+        env->Deallocate(reinterpret_cast<unsigned char*>(e.generic_signature));
+      }
+      return err;
     }
-
-    void Insert(const art::DexFile::LocalInfo& entry) {
-      if (err_ != OK) {
-        return;
-      }
-      JvmtiUniquePtr<char[]> name_str = CopyString(env_, entry.name_, &err_);
-      if (err_ != OK) {
-        return;
-      }
-      JvmtiUniquePtr<char[]> sig_str = CopyString(env_, entry.descriptor_, &err_);
-      if (err_ != OK) {
-        return;
-      }
-      JvmtiUniquePtr<char[]> generic_sig_str = CopyString(env_, entry.signature_, &err_);
-      if (err_ != OK) {
-        return;
-      }
-      variables_.push_back({
-        .start_location = static_cast<jlocation>(entry.start_address_),
-        .length = static_cast<jint>(entry.end_address_ - entry.start_address_),
-        .name = name_str.release(),
-        .signature = sig_str.release(),
-        .generic_signature = generic_sig_str.release(),
-        .slot = entry.reg_,
-      });
-    }
-
-    jvmtiError Release(jint* out_entry_count_ptr, jvmtiLocalVariableEntry** out_table_ptr) {
-      jlong table_size = sizeof(jvmtiLocalVariableEntry) * variables_.size();
-      if (err_ != OK ||
-          (err_ = env_->Allocate(table_size,
-                                 reinterpret_cast<unsigned char**>(out_table_ptr))) != OK) {
-        Cleanup();
-        return err_;
-      } else {
-        *out_entry_count_ptr = variables_.size();
-        memcpy(*out_table_ptr, variables_.data(), table_size);
-        return OK;
-      }
-    }
-
-    void Cleanup() {
-      for (jvmtiLocalVariableEntry& e : variables_) {
-        env_->Deallocate(reinterpret_cast<unsigned char*>(e.name));
-        env_->Deallocate(reinterpret_cast<unsigned char*>(e.signature));
-        env_->Deallocate(reinterpret_cast<unsigned char*>(e.generic_signature));
-      }
-    }
-
-    jvmtiEnv* env_;
-    std::vector<jvmtiLocalVariableEntry> variables_;
-    jvmtiError err_;
+    *out_entry_count_ptr = variables.size();
+    memcpy(*out_table_ptr, variables.data(), table_size);
+    return OK;
   };
 
-  LocalVariableContext context(env);
+  auto visitor = [&](const art::DexFile::LocalInfo& entry) {
+    if (err != OK) {
+      return;
+    }
+    JvmtiUniquePtr<char[]> name_str = CopyString(env, entry.name_, &err);
+    if (err != OK) {
+      return;
+    }
+    JvmtiUniquePtr<char[]> sig_str = CopyString(env, entry.descriptor_, &err);
+    if (err != OK) {
+      return;
+    }
+    JvmtiUniquePtr<char[]> generic_sig_str = CopyString(env, entry.signature_, &err);
+    if (err != OK) {
+      return;
+    }
+    variables.push_back({
+      .start_location = static_cast<jlocation>(entry.start_address_),
+      .length = static_cast<jint>(entry.end_address_ - entry.start_address_),
+      .name = name_str.release(),
+      .signature = sig_str.release(),
+      .generic_signature = generic_sig_str.release(),
+      .slot = entry.reg_,
+    });
+  };
+
   if (!accessor.DecodeDebugLocalInfo(art_method->IsStatic(),
                                      art_method->GetDexMethodIndex(),
-                                     LocalVariableContext::Callback,
-                                     &context)) {
+                                     visitor)) {
     // Something went wrong with decoding the debug information. It might as well not be there.
     return ERR(ABSENT_INFORMATION);
-  } else {
-    return context.Release(entry_count_ptr, table_ptr);
   }
+  return release(entry_count_ptr, table_ptr);
 }
 
 jvmtiError MethodUtil::GetMaxLocals(jvmtiEnv* env ATTRIBUTE_UNUSED,
@@ -614,55 +597,25 @@
     if (!accessor.HasCodeItem()) {
       return ERR(OPAQUE_FRAME);
     }
-
-    struct GetLocalVariableInfoContext {
-      explicit GetLocalVariableInfoContext(jint slot,
-                                          uint32_t pc,
-                                          std::string* out_descriptor,
-                                          art::Primitive::Type* out_type)
-          : found_(false), jslot_(slot), pc_(pc), descriptor_(out_descriptor), type_(out_type) {
-        *descriptor_ = "";
-        *type_ = art::Primitive::kPrimVoid;
+    bool found = false;
+    *type = art::Primitive::kPrimVoid;
+    descriptor->clear();
+    auto visitor = [&](const art::DexFile::LocalInfo& entry) {
+      if (!found &&
+          entry.start_address_ <= dex_pc &&
+          entry.end_address_ > dex_pc &&
+          entry.reg_ == slot_) {
+        found = true;
+        *type = art::Primitive::GetType(entry.descriptor_[0]);
+        *descriptor = entry.descriptor_;
       }
-
-      static void Callback(void* raw_ctx, const art::DexFile::LocalInfo& entry) {
-        reinterpret_cast<GetLocalVariableInfoContext*>(raw_ctx)->Handle(entry);
-      }
-
-      void Handle(const art::DexFile::LocalInfo& entry) {
-        if (found_) {
-          return;
-        } else if (entry.start_address_ <= pc_ &&
-                   entry.end_address_ > pc_ &&
-                   entry.reg_ == jslot_) {
-          found_ = true;
-          *type_ = art::Primitive::GetType(entry.descriptor_[0]);
-          *descriptor_ = entry.descriptor_;
-        }
-        return;
-      }
-
-      bool found_;
-      jint jslot_;
-      uint32_t pc_;
-      std::string* descriptor_;
-      art::Primitive::Type* type_;
     };
-
-    GetLocalVariableInfoContext context(slot_, dex_pc, descriptor, type);
-    if (!dex_file->DecodeDebugLocalInfo(accessor.RegistersSize(),
-                                        accessor.InsSize(),
-                                        accessor.InsnsSizeInCodeUnits(),
-                                        accessor.DebugInfoOffset(),
-                                        method->IsStatic(),
-                                        method->GetDexMethodIndex(),
-                                        GetLocalVariableInfoContext::Callback,
-                                        &context) || !context.found_) {
+    if (!accessor.DecodeDebugLocalInfo(method->IsStatic(), method->GetDexMethodIndex(), visitor) ||
+        !found) {
       // Something went wrong with decoding the debug information. It might as well not be there.
       return ERR(INVALID_SLOT);
-    } else {
-      return OK;
     }
+    return OK;
   }
 
   jvmtiError result_;
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 7b4fa6e..b108920 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -1700,37 +1700,6 @@
 
 void Dbg::OutputVariableTable(JDWP::RefTypeId, JDWP::MethodId method_id, bool with_generic,
                               JDWP::ExpandBuf* pReply) {
-  struct DebugCallbackContext {
-    ArtMethod* method;
-    JDWP::ExpandBuf* pReply;
-    size_t variable_count;
-    bool with_generic;
-
-    static void Callback(void* context, const DexFile::LocalInfo& entry)
-        REQUIRES_SHARED(Locks::mutator_lock_) {
-      DebugCallbackContext* pContext = reinterpret_cast<DebugCallbackContext*>(context);
-
-      uint16_t slot = entry.reg_;
-      VLOG(jdwp) << StringPrintf("    %2zd: %d(%d) '%s' '%s' '%s' actual slot=%d mangled slot=%d",
-                                 pContext->variable_count, entry.start_address_,
-                                 entry.end_address_ - entry.start_address_,
-                                 entry.name_, entry.descriptor_, entry.signature_, slot,
-                                 MangleSlot(slot, pContext->method));
-
-      slot = MangleSlot(slot, pContext->method);
-
-      expandBufAdd8BE(pContext->pReply, entry.start_address_);
-      expandBufAddUtf8String(pContext->pReply, entry.name_);
-      expandBufAddUtf8String(pContext->pReply, entry.descriptor_);
-      if (pContext->with_generic) {
-        expandBufAddUtf8String(pContext->pReply, entry.signature_);
-      }
-      expandBufAdd4BE(pContext->pReply, entry.end_address_- entry.start_address_);
-      expandBufAdd4BE(pContext->pReply, slot);
-
-      ++pContext->variable_count;
-    }
-  };
   ArtMethod* m = FromMethodId(method_id);
   CodeItemDebugInfoAccessor accessor(m->DexInstructionDebugInfo());
 
@@ -1742,24 +1711,39 @@
   size_t variable_count_offset = expandBufGetLength(pReply);
   expandBufAdd4BE(pReply, 0);
 
-  DebugCallbackContext context;
-  context.method = m;
-  context.pReply = pReply;
-  context.variable_count = 0;
-  context.with_generic = with_generic;
+  size_t variable_count = 0;
 
   if (accessor.HasCodeItem()) {
-    m->GetDexFile()->DecodeDebugLocalInfo(accessor.RegistersSize(),
-                                          accessor.InsSize(),
-                                          accessor.InsnsSizeInCodeUnits(),
-                                          accessor.DebugInfoOffset(),
-                                          m->IsStatic(),
-                                          m->GetDexMethodIndex(),
-                                          DebugCallbackContext::Callback,
-                                          &context);
+    accessor.DecodeDebugLocalInfo(m->IsStatic(),
+                                  m->GetDexMethodIndex(),
+                                  [&](const DexFile::LocalInfo& entry)
+        REQUIRES_SHARED(Locks::mutator_lock_) {
+      uint16_t slot = entry.reg_;
+      VLOG(jdwp) << StringPrintf("    %2zd: %d(%d) '%s' '%s' '%s' actual slot=%d mangled slot=%d",
+                                 variable_count,
+                                 entry.start_address_,
+                                 entry.end_address_ - entry.start_address_,
+                                 entry.name_,
+                                 entry.descriptor_, entry.signature_,
+                                 slot,
+                                 MangleSlot(slot, m));
+
+      slot = MangleSlot(slot, m);
+
+      expandBufAdd8BE(pReply, entry.start_address_);
+      expandBufAddUtf8String(pReply, entry.name_);
+      expandBufAddUtf8String(pReply, entry.descriptor_);
+      if (with_generic) {
+        expandBufAddUtf8String(pReply, entry.signature_);
+      }
+      expandBufAdd4BE(pReply, entry.end_address_- entry.start_address_);
+      expandBufAdd4BE(pReply, slot);
+
+      ++variable_count;
+    });
   }
 
-  JDWP::Set4BE(expandBufGetBuffer(pReply) + variable_count_offset, context.variable_count);
+  JDWP::Set4BE(expandBufGetBuffer(pReply) + variable_count_offset, variable_count);
 }
 
 void Dbg::OutputMethodReturnValue(JDWP::MethodId method_id, const JValue* return_value,
diff --git a/tools/dexanalyze/dexanalyze_strings.cc b/tools/dexanalyze/dexanalyze_strings.cc
index de5c34e..dcadb59 100644
--- a/tools/dexanalyze/dexanalyze_strings.cc
+++ b/tools/dexanalyze/dexanalyze_strings.cc
@@ -119,8 +119,25 @@
       return false;
     }
     const uint8_t* prefix_data = &dictionary_.prefix_data_[prefix_offset];
-    return memcmp(prefix_data, data, prefix_len) == 0u &&
-        memcmp(suffix_data, data + prefix_len, len - prefix_len) == 0u;
+    if ((true)) {
+      return memcmp(prefix_data, data, prefix_len) == 0u &&
+          memcmp(suffix_data, data + prefix_len, len - prefix_len) == 0u;
+    } else {
+      len -= prefix_len;
+      while (prefix_len != 0u) {
+        if (*prefix_data++ != *data++) {
+          return false;
+        }
+        --prefix_len;
+      }
+      while (len != 0u) {
+        if (*suffix_data++ != *data++) {
+          return false;
+        }
+        --len;
+      }
+      return true;
+    }
   }
 
  public:
@@ -164,7 +181,6 @@
   std::vector<uint32_t> string_offsets_;
 };
 
-
 // Node value = (distance from root) * (occurrences - 1).
 class MatchTrie {
  public: