Merge "ART: Add dex::ProtoIndex"
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index f573337..fb556f4 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -771,7 +771,7 @@
 
 void CodeGenerator::GenerateLoadMethodTypeRuntimeCall(HLoadMethodType* method_type) {
   LocationSummary* locations = method_type->GetLocations();
-  MoveConstant(locations->GetTemp(0), method_type->GetProtoIndex());
+  MoveConstant(locations->GetTemp(0), method_type->GetProtoIndex().index_);
   CheckEntrypointTypes<kQuickResolveMethodType, void*, uint32_t>();
   InvokeRuntime(kQuickResolveMethodType, method_type, method_type->GetDexPc());
 }
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 35a3945..0e20a65 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -1055,7 +1055,7 @@
 bool HInstructionBuilder::BuildInvokePolymorphic(const Instruction& instruction ATTRIBUTE_UNUSED,
                                                  uint32_t dex_pc,
                                                  uint32_t method_idx,
-                                                 uint32_t proto_idx,
+                                                 dex::ProtoIndex proto_idx,
                                                  uint32_t number_of_vreg_arguments,
                                                  bool is_range,
                                                  uint32_t* args,
@@ -1896,17 +1896,17 @@
   }
 }
 
-void HInstructionBuilder::BuildLoadMethodHandle(uint16_t proto_idx, uint32_t dex_pc) {
+void HInstructionBuilder::BuildLoadMethodHandle(uint16_t method_handle_index, uint32_t dex_pc) {
   const DexFile& dex_file = *dex_compilation_unit_->GetDexFile();
-  HLoadMethodHandle* load_method_handle =
-      new (allocator_) HLoadMethodHandle(graph_->GetCurrentMethod(), proto_idx, dex_file, dex_pc);
+  HLoadMethodHandle* load_method_handle = new (allocator_) HLoadMethodHandle(
+      graph_->GetCurrentMethod(), method_handle_index, dex_file, dex_pc);
   AppendInstruction(load_method_handle);
 }
 
-void HInstructionBuilder::BuildLoadMethodType(uint16_t proto_idx, uint32_t dex_pc) {
+void HInstructionBuilder::BuildLoadMethodType(dex::ProtoIndex proto_index, uint32_t dex_pc) {
   const DexFile& dex_file = *dex_compilation_unit_->GetDexFile();
   HLoadMethodType* load_method_type =
-      new (allocator_) HLoadMethodType(graph_->GetCurrentMethod(), proto_idx, dex_file, dex_pc);
+      new (allocator_) HLoadMethodType(graph_->GetCurrentMethod(), proto_index, dex_file, dex_pc);
   AppendInstruction(load_method_type);
 }
 
@@ -2189,7 +2189,7 @@
 
     case Instruction::INVOKE_POLYMORPHIC: {
       uint16_t method_idx = instruction.VRegB_45cc();
-      uint16_t proto_idx = instruction.VRegH_45cc();
+      dex::ProtoIndex proto_idx(instruction.VRegH_45cc());
       uint32_t number_of_vreg_arguments = instruction.VRegA_45cc();
       uint32_t args[5];
       instruction.GetVarArgs(args);
@@ -2205,7 +2205,7 @@
 
     case Instruction::INVOKE_POLYMORPHIC_RANGE: {
       uint16_t method_idx = instruction.VRegB_4rcc();
-      uint16_t proto_idx = instruction.VRegH_4rcc();
+      dex::ProtoIndex proto_idx(instruction.VRegH_4rcc());
       uint32_t number_of_vreg_arguments = instruction.VRegA_4rcc();
       uint32_t register_index = instruction.VRegC_4rcc();
       return BuildInvokePolymorphic(instruction,
@@ -2949,7 +2949,7 @@
     }
 
     case Instruction::CONST_METHOD_TYPE: {
-      uint16_t proto_idx = instruction.VRegB_21c();
+      dex::ProtoIndex proto_idx(instruction.VRegB_21c());
       BuildLoadMethodType(proto_idx, dex_pc);
       UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
       break;
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index 95ffa6b..9d886a8 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -178,7 +178,7 @@
   bool BuildInvokePolymorphic(const Instruction& instruction,
                               uint32_t dex_pc,
                               uint32_t method_idx,
-                              uint32_t proto_idx,
+                              dex::ProtoIndex proto_idx,
                               uint32_t number_of_vreg_arguments,
                               bool is_range,
                               uint32_t* args,
@@ -240,11 +240,11 @@
   bool LoadClassNeedsAccessCheck(Handle<mirror::Class> klass)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  // Builds a `HLoadMethodHandle` loading the given `method_handle_idx`.
+  // Builds a `HLoadMethodHandle` loading the given `method_handle_index`.
   void BuildLoadMethodHandle(uint16_t method_handle_idx, uint32_t dex_pc);
 
-  // Builds a `HLoadMethodType` loading the given `proto_idx`.
-  void BuildLoadMethodType(uint16_t proto_idx, uint32_t dex_pc);
+  // Builds a `HLoadMethodType` loading the given `proto_index`.
+  void BuildLoadMethodType(dex::ProtoIndex proto_index, uint32_t dex_pc);
 
   // Returns the outer-most compiling method's class.
   ObjPtr<mirror::Class> GetOutermostCompilingClass() const;
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index a7c2d0b..e786502 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -6548,7 +6548,7 @@
 class HLoadMethodType FINAL : public HInstruction {
  public:
   HLoadMethodType(HCurrentMethod* current_method,
-                  uint16_t proto_idx,
+                  dex::ProtoIndex proto_index,
                   const DexFile& dex_file,
                   uint32_t dex_pc)
       : HInstruction(kLoadMethodType,
@@ -6556,7 +6556,7 @@
                      SideEffectsForArchRuntimeCalls(),
                      dex_pc),
         special_input_(HUserRecord<HInstruction*>(current_method)),
-        proto_idx_(proto_idx),
+        proto_index_(proto_index),
         dex_file_(dex_file) {
   }
 
@@ -6568,7 +6568,7 @@
 
   bool IsClonable() const OVERRIDE { return true; }
 
-  uint16_t GetProtoIndex() const { return proto_idx_; }
+  dex::ProtoIndex GetProtoIndex() const { return proto_index_; }
 
   const DexFile& GetDexFile() const { return dex_file_; }
 
@@ -6585,7 +6585,7 @@
   // The special input is the HCurrentMethod for kRuntimeCall.
   HUserRecord<HInstruction*> special_input_;
 
-  const uint16_t proto_idx_;
+  const dex::ProtoIndex proto_index_;
   const DexFile& dex_file_;
 };
 
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 9536381..e72d49e 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -786,11 +786,10 @@
 static std::unique_ptr<char[]> indexString(const DexFile* pDexFile,
                                            const Instruction* pDecInsn,
                                            size_t bufSize) {
-  static const u4 kInvalidIndex = std::numeric_limits<u4>::max();
   std::unique_ptr<char[]> buf(new char[bufSize]);
   // Determine index and width of the string.
   u4 index = 0;
-  u4 secondary_index = kInvalidIndex;
+  u2 secondary_index = 0;
   u4 width = 4;
   switch (Instruction::FormatOf(pDecInsn->Opcode())) {
     // SOME NOT SUPPORTED:
@@ -898,7 +897,7 @@
                                              signature.ToString().c_str());
       }
       if (secondary_index < pDexFile->GetHeader().proto_ids_size_) {
-        const DexFile::ProtoId& protoId = pDexFile->GetProtoId(secondary_index);
+        const DexFile::ProtoId& protoId = pDexFile->GetProtoId(dex::ProtoIndex(secondary_index));
         const Signature signature = pDexFile->GetProtoSignature(protoId);
         proto = signature.ToString();
       }
@@ -916,7 +915,7 @@
       break;
     case Instruction::kIndexProtoRef:
       if (index < pDexFile->GetHeader().proto_ids_size_) {
-        const DexFile::ProtoId& protoId = pDexFile->GetProtoId(index);
+        const DexFile::ProtoId& protoId = pDexFile->GetProtoId(dex::ProtoIndex(index));
         const Signature signature = pDexFile->GetProtoSignature(protoId);
         const std::string& proto = signature.ToString();
         outSize = snprintf(buf.get(), bufSize, "%s // proto@%0*x", proto.c_str(), width, index);
@@ -1705,7 +1704,7 @@
   dex::StringIndex method_name_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i);
   const char* method_name = pDexFile->StringDataByIdx(method_name_idx);
   it.Next();
-  uint32_t method_type_idx = static_cast<uint32_t>(it.GetJavaValue().i);
+  dex::ProtoIndex method_type_idx = static_cast<dex::ProtoIndex>(it.GetJavaValue().i);
   const DexFile::ProtoId& method_type_id = pDexFile->GetProtoId(method_type_idx);
   std::string method_type = pDexFile->GetProtoSignature(method_type_id).ToString();
   it.Next();
@@ -1763,7 +1762,7 @@
         break;
       case EncodedArrayValueIterator::ValueType::kMethodType: {
         type = "MethodType";
-        uint32_t proto_idx = static_cast<uint32_t>(it.GetJavaValue().i);
+        dex::ProtoIndex proto_idx = static_cast<dex::ProtoIndex>(it.GetJavaValue().i);
         const DexFile::ProtoId& proto_id = pDexFile->GetProtoId(proto_idx);
         value = pDexFile->GetProtoSignature(proto_id).ToString();
         break;
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index 1525d53..b7d9db6 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -332,7 +332,7 @@
 }
 
 void Collections::CreateProtoId(const DexFile& dex_file, uint32_t i) {
-  const DexFile::ProtoId& disk_proto_id = dex_file.GetProtoId(i);
+  const DexFile::ProtoId& disk_proto_id = dex_file.GetProtoId(dex::ProtoIndex(i));
   const DexFile::TypeList* type_list = dex_file.GetProtoParameters(disk_proto_id);
   TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_);
 
@@ -353,7 +353,7 @@
 void Collections::CreateMethodId(const DexFile& dex_file, uint32_t i) {
   const DexFile::MethodId& disk_method_id = dex_file.GetMethodId(i);
   MethodId* method_id = new MethodId(GetTypeId(disk_method_id.class_idx_.index_),
-                                     GetProtoId(disk_method_id.proto_idx_),
+                                     GetProtoId(disk_method_id.proto_idx_.index_),
                                      GetStringId(disk_method_id.name_idx_.index_));
   AddIndexedItem(method_ids_, method_id, MethodIdsOffset() + i * MethodId::ItemSize(), i);
 }
diff --git a/libdexfile/dex/dex_file-inl.h b/libdexfile/dex/dex_file-inl.h
index d1b3200..e78e8d7 100644
--- a/libdexfile/dex/dex_file-inl.h
+++ b/libdexfile/dex/dex_file-inl.h
@@ -127,7 +127,7 @@
   return StringByTypeIdx(proto_id.return_type_idx_);
 }
 
-inline const char* DexFile::GetShorty(uint32_t proto_idx) const {
+inline const char* DexFile::GetShorty(dex::ProtoIndex proto_idx) const {
   const ProtoId& proto_id = GetProtoId(proto_idx);
   return StringDataByIdx(proto_id.shorty_idx_);
 }
diff --git a/libdexfile/dex/dex_file.cc b/libdexfile/dex/dex_file.cc
index 8cfee66..9de260c 100644
--- a/libdexfile/dex/dex_file.cc
+++ b/libdexfile/dex/dex_file.cc
@@ -281,7 +281,7 @@
   // Binary search MethodIds knowing that they are sorted by class_idx, name_idx then proto_idx
   const dex::TypeIndex class_idx = GetIndexForTypeId(declaring_klass);
   const dex::StringIndex name_idx = GetIndexForStringId(name);
-  const uint16_t proto_idx = GetIndexForProtoId(signature);
+  const dex::ProtoIndex proto_idx = GetIndexForProtoId(signature);
   int32_t lo = 0;
   int32_t hi = NumMethodIds() - 1;
   while (hi >= lo) {
@@ -373,7 +373,8 @@
   int32_t hi = NumProtoIds() - 1;
   while (hi >= lo) {
     int32_t mid = (hi + lo) / 2;
-    const DexFile::ProtoId& proto = GetProtoId(mid);
+    const dex::ProtoIndex proto_idx = static_cast<dex::ProtoIndex>(mid);
+    const DexFile::ProtoId& proto = GetProtoId(proto_idx);
     int compare = return_type_idx.index_ - proto.return_type_idx_.index_;
     if (compare == 0) {
       DexFileParameterIterator it(*this, proto);
@@ -777,6 +778,11 @@
 
 namespace dex {
 
+std::ostream& operator<<(std::ostream& os, const ProtoIndex& index) {
+  os << "ProtoIndex[" << index.index_ << "]";
+  return os;
+}
+
 std::ostream& operator<<(std::ostream& os, const StringIndex& index) {
   os << "StringIndex[" << index.index_ << "]";
   return os;
diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h
index 4ca735a..87d2c48 100644
--- a/libdexfile/dex/dex_file.h
+++ b/libdexfile/dex/dex_file.h
@@ -189,7 +189,7 @@
   // Raw method_id_item.
   struct MethodId {
     dex::TypeIndex class_idx_;   // index into type_ids_ array for defining class
-    uint16_t proto_idx_;         // index into proto_ids_ array for method prototype
+    dex::ProtoIndex proto_idx_;  // index into proto_ids_ array for method prototype
     dex::StringIndex name_idx_;  // index into string_ids_ array for method name
 
    private:
@@ -692,15 +692,15 @@
   }
 
   // Returns the ProtoId at the specified index.
-  const ProtoId& GetProtoId(uint16_t idx) const {
-    DCHECK_LT(idx, NumProtoIds()) << GetLocation();
-    return proto_ids_[idx];
+  const ProtoId& GetProtoId(dex::ProtoIndex idx) const {
+    DCHECK_LT(idx.index_, NumProtoIds()) << GetLocation();
+    return proto_ids_[idx.index_];
   }
 
-  uint16_t GetIndexForProtoId(const ProtoId& proto_id) const {
+  dex::ProtoIndex GetIndexForProtoId(const ProtoId& proto_id) const {
     CHECK_GE(&proto_id, proto_ids_) << GetLocation();
     CHECK_LT(&proto_id, proto_ids_ + header_->proto_ids_size_) << GetLocation();
-    return &proto_id - proto_ids_;
+    return dex::ProtoIndex(&proto_id - proto_ids_);
   }
 
   // Looks up a proto id for a given return type and signature type list
@@ -722,7 +722,7 @@
   const Signature CreateSignature(const StringPiece& signature) const;
 
   // Returns the short form method descriptor for the given prototype.
-  const char* GetShorty(uint32_t proto_idx) const;
+  const char* GetShorty(dex::ProtoIndex proto_idx) const;
 
   const TypeList* GetProtoParameters(const ProtoId& proto_id) const {
     return DataPointer<TypeList>(proto_id.parameters_off_);
diff --git a/libdexfile/dex/dex_file_types.h b/libdexfile/dex/dex_file_types.h
index 2bb70ff..d4fb3de 100644
--- a/libdexfile/dex/dex_file_types.h
+++ b/libdexfile/dex/dex_file_types.h
@@ -25,73 +25,67 @@
 
 constexpr uint32_t kDexNoIndex = 0xFFFFFFFF;
 
-class StringIndex {
+template<typename T>
+class DexIndex {
  public:
-  uint32_t index_;
+  T index_;
 
-  constexpr StringIndex() : index_(std::numeric_limits<decltype(index_)>::max()) {}
-  explicit constexpr StringIndex(uint32_t idx) : index_(idx) {}
+  constexpr DexIndex() : index_(std::numeric_limits<decltype(index_)>::max()) {}
+  explicit constexpr DexIndex(T idx) : index_(idx) {}
 
   bool IsValid() const {
     return index_ != std::numeric_limits<decltype(index_)>::max();
   }
-  static StringIndex Invalid() {
-    return StringIndex(std::numeric_limits<decltype(index_)>::max());
+  static constexpr DexIndex Invalid() {
+    return DexIndex(std::numeric_limits<decltype(index_)>::max());
   }
-
-  bool operator==(const StringIndex& other) const {
+  bool operator==(const DexIndex& other) const {
     return index_ == other.index_;
   }
-  bool operator!=(const StringIndex& other) const {
+  bool operator!=(const DexIndex& other) const {
     return index_ != other.index_;
   }
-  bool operator<(const StringIndex& other) const {
+  bool operator<(const DexIndex& other) const {
     return index_ < other.index_;
   }
-  bool operator<=(const StringIndex& other) const {
+  bool operator<=(const DexIndex& other) const {
     return index_ <= other.index_;
   }
-  bool operator>(const StringIndex& other) const {
+  bool operator>(const DexIndex& other) const {
     return index_ > other.index_;
   }
-  bool operator>=(const StringIndex& other) const {
+  bool operator>=(const DexIndex& other) const {
     return index_ >= other.index_;
   }
 };
+
+class ProtoIndex : public DexIndex<uint16_t> {
+ public:
+  ProtoIndex() {}
+  explicit constexpr ProtoIndex(uint16_t index) : DexIndex<decltype(index_)>(index) {}
+  static constexpr ProtoIndex Invalid() {
+    return ProtoIndex(std::numeric_limits<decltype(index_)>::max());
+  }
+};
+std::ostream& operator<<(std::ostream& os, const ProtoIndex& index);
+
+class StringIndex : public DexIndex<uint32_t> {
+ public:
+  StringIndex() {}
+  explicit constexpr StringIndex(uint32_t index) : DexIndex<decltype(index_)>(index) {}
+  static constexpr StringIndex Invalid() {
+    return StringIndex(std::numeric_limits<decltype(index_)>::max());
+  }
+};
 std::ostream& operator<<(std::ostream& os, const StringIndex& index);
 
-class TypeIndex {
+class TypeIndex : public DexIndex<uint16_t> {
  public:
-  uint16_t index_;
-
-  constexpr TypeIndex() : index_(std::numeric_limits<decltype(index_)>::max()) {}
-  explicit constexpr TypeIndex(uint16_t idx) : index_(idx) {}
-
-  bool IsValid() const {
-    return index_ != std::numeric_limits<decltype(index_)>::max();
-  }
-  static TypeIndex Invalid() {
+  TypeIndex() {}
+  explicit constexpr TypeIndex(uint16_t index) : DexIndex<uint16_t>(index) {}
+  static constexpr TypeIndex Invalid() {
     return TypeIndex(std::numeric_limits<decltype(index_)>::max());
   }
-
-  bool operator==(const TypeIndex& other) const {
-    return index_ == other.index_;
-  }
-  bool operator!=(const TypeIndex& other) const {
-    return index_ != other.index_;
-  }
-  bool operator<(const TypeIndex& other) const {
-    return index_ < other.index_;
-  }
-  bool operator<=(const TypeIndex& other) const {
-    return index_ <= other.index_;
-  }
-  bool operator>(const TypeIndex& other) const {
-    return index_ > other.index_;
-  }
-  bool operator>=(const TypeIndex& other) const {
-    return index_ >= other.index_;
-  }
 };
 std::ostream& operator<<(std::ostream& os, const TypeIndex& index);
 
@@ -100,15 +94,21 @@
 
 namespace std {
 
+template<> struct hash<art::dex::ProtoIndex> {
+  size_t operator()(const art::dex::ProtoIndex& index) const {
+    return hash<decltype(index.index_)>()(index.index_);
+  }
+};
+
 template<> struct hash<art::dex::StringIndex> {
   size_t operator()(const art::dex::StringIndex& index) const {
-    return hash<uint32_t>()(index.index_);
+    return hash<decltype(index.index_)>()(index.index_);
   }
 };
 
 template<> struct hash<art::dex::TypeIndex> {
   size_t operator()(const art::dex::TypeIndex& index) const {
-    return hash<uint16_t>()(index.index_);
+    return hash<decltype(index.index_)>()(index.index_);
   }
 };
 
diff --git a/libdexfile/dex/dex_file_verifier.cc b/libdexfile/dex/dex_file_verifier.cc
index a32f64e..78db8b9 100644
--- a/libdexfile/dex/dex_file_verifier.cc
+++ b/libdexfile/dex/dex_file_verifier.cc
@@ -127,8 +127,9 @@
   return &dex_file_->GetMethodId(idx);
 }
 
-const DexFile::ProtoId* DexFileVerifier::CheckLoadProtoId(uint32_t idx, const char* err_string) {
-  if (UNLIKELY(!CheckIndex(idx, dex_file_->NumProtoIds(), err_string))) {
+const DexFile::ProtoId* DexFileVerifier::CheckLoadProtoId(dex::ProtoIndex idx,
+                                                          const char* err_string) {
+  if (UNLIKELY(!CheckIndex(idx.index_, dex_file_->NumProtoIds(), err_string))) {
     return nullptr;
   }
   return &dex_file_->GetProtoId(idx);
@@ -2208,7 +2209,7 @@
   }
 
   // Check that the proto id is valid.
-  if (UNLIKELY(!CheckIndex(item->proto_idx_, dex_file_->NumProtoIds(),
+  if (UNLIKELY(!CheckIndex(item->proto_idx_.index_, dex_file_->NumProtoIds(),
                            "inter_method_id_item proto_idx"))) {
     return false;
   }
diff --git a/libdexfile/dex/dex_file_verifier.h b/libdexfile/dex/dex_file_verifier.h
index 04d8d71..43d1093 100644
--- a/libdexfile/dex/dex_file_verifier.h
+++ b/libdexfile/dex/dex_file_verifier.h
@@ -164,7 +164,7 @@
   // error if not. If there is an error, null is returned.
   const DexFile::FieldId* CheckLoadFieldId(uint32_t idx, const char* error_fmt);
   const DexFile::MethodId* CheckLoadMethodId(uint32_t idx, const char* error_fmt);
-  const DexFile::ProtoId* CheckLoadProtoId(uint32_t idx, const char* error_fmt);
+  const DexFile::ProtoId* CheckLoadProtoId(dex::ProtoIndex idx, const char* error_fmt);
 
   void ErrorStringPrintf(const char* fmt, ...)
       __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR;
diff --git a/libdexfile/dex/dex_file_verifier_test.cc b/libdexfile/dex/dex_file_verifier_test.cc
index f82081f..c9bac0f 100644
--- a/libdexfile/dex/dex_file_verifier_test.cc
+++ b/libdexfile/dex/dex_file_verifier_test.cc
@@ -161,7 +161,7 @@
       "method_id_proto_idx",
       [](DexFile* dex_file) {
         DexFile::MethodId* method_id = const_cast<DexFile::MethodId*>(&dex_file->GetMethodId(0));
-        method_id->proto_idx_ = 0xFF;
+        method_id->proto_idx_ = dex::ProtoIndex(0xFF);
       },
       "inter_method_id_item proto_idx");
 
@@ -1425,12 +1425,13 @@
           CHECK_LT(method_idx + 1u, dex_file->NumMethodIds());
           CHECK_EQ(dex_file->GetMethodId(method_idx).name_idx_,
                    dex_file->GetMethodId(method_idx + 1).name_idx_);
-          CHECK_EQ(dex_file->GetMethodId(method_idx).proto_idx_ + 1u,
-                   dex_file->GetMethodId(method_idx + 1).proto_idx_);
+          CHECK_EQ(dex_file->GetMethodId(method_idx).proto_idx_.index_ + 1u,
+                   dex_file->GetMethodId(method_idx + 1).proto_idx_.index_);
           // Their return types should be the same.
-          uint32_t proto1_idx = dex_file->GetMethodId(method_idx).proto_idx_;
+          dex::ProtoIndex proto1_idx = dex_file->GetMethodId(method_idx).proto_idx_;
           const DexFile::ProtoId& proto1 = dex_file->GetProtoId(proto1_idx);
-          const DexFile::ProtoId& proto2 = dex_file->GetProtoId(proto1_idx + 1u);
+          dex::ProtoIndex proto2_idx(proto1_idx.index_ + 1u);
+          const DexFile::ProtoId& proto2 = dex_file->GetProtoId(proto2_idx);
           CHECK_EQ(proto1.return_type_idx_, proto2.return_type_idx_);
           // And the first should not have any parameters while the second should have some.
           CHECK(!DexFileParameterIterator(*dex_file, proto1).HasNext());
diff --git a/libdexfile/dex/dex_instruction.cc b/libdexfile/dex/dex_instruction.cc
index 8862181..8378211 100644
--- a/libdexfile/dex/dex_instruction.cc
+++ b/libdexfile/dex/dex_instruction.cc
@@ -467,10 +467,10 @@
     case k45cc: {
       uint32_t arg[kMaxVarArgRegs];
       GetVarArgs(arg);
-      uint32_t method_idx = VRegB_45cc();
-      uint32_t proto_idx = VRegH_45cc();
+      uint16_t method_idx = VRegB_45cc();
+      dex::ProtoIndex proto_idx(VRegH_45cc());
       os << opcode << " {";
-      for (int i = 0; i < VRegA_45cc(); ++i) {
+      for (uint32_t i = 0; i < VRegA_45cc(); ++i) {
         if (i != 0) {
           os << ", ";
         }
@@ -478,7 +478,8 @@
       }
       os << "}";
       if (file != nullptr) {
-        os << ", " << file->PrettyMethod(method_idx) << ", " << file->GetShorty(proto_idx)
+        os << ", " << file->PrettyMethod(method_idx)
+           << ", " << file->GetShorty(proto_idx)
            << " // ";
       } else {
         os << ", ";
@@ -490,18 +491,19 @@
       switch (Opcode()) {
         case INVOKE_POLYMORPHIC_RANGE: {
           if (file != nullptr) {
-            uint32_t method_idx = VRegB_4rcc();
-            uint32_t proto_idx = VRegH_4rcc();
+            uint16_t method_idx = VRegB_4rcc();
+            dex::ProtoIndex proto_idx(VRegH_4rcc());
             os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc())
-               << "}, " << file->PrettyMethod(method_idx) << ", " << file->GetShorty(proto_idx)
+               << "}, " << file->PrettyMethod(method_idx)
+               << ", " << file->GetShorty(dex::ProtoIndex(proto_idx))
                << " // method@" << method_idx << ", proto@" << proto_idx;
             break;
           }
         }
         FALLTHROUGH_INTENDED;
         default: {
-          uint32_t method_idx = VRegB_4rcc();
-          uint32_t proto_idx = VRegH_4rcc();
+          uint16_t method_idx = VRegB_4rcc();
+          dex::ProtoIndex proto_idx(VRegH_4rcc());
           os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc())
              << "}, method@" << method_idx << ", proto@" << proto_idx;
         }
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 9c8b438..be9e08f 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -8174,7 +8174,7 @@
 
 ObjPtr<mirror::MethodType> ClassLinker::ResolveMethodType(
     Thread* self,
-    uint32_t proto_idx,
+    dex::ProtoIndex proto_idx,
     Handle<mirror::DexCache> dex_cache,
     Handle<mirror::ClassLoader> class_loader) {
   DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
@@ -8236,7 +8236,7 @@
 }
 
 ObjPtr<mirror::MethodType> ClassLinker::ResolveMethodType(Thread* self,
-                                                          uint32_t proto_idx,
+                                                          dex::ProtoIndex proto_idx,
                                                           ArtMethod* referrer) {
   StackHandleScope<2> hs(self);
   Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 60cff9e..52ecf82 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -416,14 +416,14 @@
   // Resolve a method type with a given ID from the DexFile associated with a given DexCache
   // and ClassLoader, storing the result in the DexCache.
   ObjPtr<mirror::MethodType> ResolveMethodType(Thread* self,
-                                               uint32_t proto_idx,
+                                               dex::ProtoIndex proto_idx,
                                                Handle<mirror::DexCache> dex_cache,
                                                Handle<mirror::ClassLoader> class_loader)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
 
   ObjPtr<mirror::MethodType> ResolveMethodType(Thread* self,
-                                               uint32_t proto_idx,
+                                               dex::ProtoIndex proto_idx,
                                                ArtMethod* referrer)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
diff --git a/runtime/dex/art_dex_file_loader_test.cc b/runtime/dex/art_dex_file_loader_test.cc
index 274a6df..c0090e6 100644
--- a/runtime/dex/art_dex_file_loader_test.cc
+++ b/runtime/dex/art_dex_file_loader_test.cc
@@ -286,7 +286,7 @@
 
 TEST_F(ArtDexFileLoaderTest, FindProtoId) {
   for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) {
-    const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(i);
+    const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(dex::ProtoIndex(i));
     const DexFile::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find);
     std::vector<dex::TypeIndex> to_find_types;
     if (to_find_tl != nullptr) {
@@ -297,7 +297,7 @@
     const DexFile::ProtoId* found =
         java_lang_dex_file_->FindProtoId(to_find.return_type_idx_, to_find_types);
     ASSERT_TRUE(found != nullptr);
-    EXPECT_EQ(java_lang_dex_file_->GetIndexForProtoId(*found), i);
+    EXPECT_EQ(java_lang_dex_file_->GetIndexForProtoId(*found), dex::ProtoIndex(i));
   }
 }
 
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index a58946a..7fc8db3 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -268,7 +268,7 @@
 }
 
 ObjPtr<mirror::MethodType> ResolveMethodTypeFromCode(ArtMethod* referrer,
-                                                     uint32_t proto_idx) {
+                                                     dex::ProtoIndex proto_idx) {
   Thread::PoisonObjectPointersIfDebug();
   ObjPtr<mirror::MethodType> method_type =
       referrer->GetDexCache()->GetResolvedMethodType(proto_idx);
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 0a3b5df..e33de9c 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -158,7 +158,7 @@
     REQUIRES_SHARED(Locks::mutator_lock_)
     REQUIRES(!Roles::uninterruptible_);
 
-ObjPtr<mirror::MethodType> ResolveMethodTypeFromCode(ArtMethod* referrer, uint32_t proto_idx)
+ObjPtr<mirror::MethodType> ResolveMethodTypeFromCode(ArtMethod* referrer, dex::ProtoIndex proto_idx)
     REQUIRES_SHARED(Locks::mutator_lock_)
     REQUIRES(!Roles::uninterruptible_);
 
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index cf9ddd8..fa536c7 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -200,7 +200,7 @@
   auto caller_and_outer = GetCalleeSaveMethodCallerAndOuterMethod(self,
                                                                   CalleeSaveType::kSaveEverything);
   ArtMethod* caller = caller_and_outer.caller;
-  ObjPtr<mirror::MethodType> result = ResolveMethodTypeFromCode(caller, proto_idx);
+  ObjPtr<mirror::MethodType> result = ResolveMethodTypeFromCode(caller, dex::ProtoIndex(proto_idx));
   return result.Ptr();
 }
 
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 39429c5..7e3c3db 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -2766,7 +2766,7 @@
   const Instruction& inst = caller_method->DexInstructions().InstructionAt(dex_pc);
   DCHECK(inst.Opcode() == Instruction::INVOKE_POLYMORPHIC ||
          inst.Opcode() == Instruction::INVOKE_POLYMORPHIC_RANGE);
-  const uint32_t proto_idx = inst.VRegH();
+  const dex::ProtoIndex proto_idx(inst.VRegH());
   const char* shorty = caller_method->GetDexFile()->GetShorty(proto_idx);
   const size_t shorty_length = strlen(shorty);
   static const bool kMethodIsStatic = false;  // invoke() and invokeExact() are not static.
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 8a85ee4..ded8cef 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -626,7 +626,8 @@
 
   // The vRegH value gives the index of the proto_id associated with this
   // signature polymorphic call site.
-  const uint32_t callsite_proto_id = (is_range) ? inst->VRegH_4rcc() : inst->VRegH_45cc();
+  const uint16_t vRegH = (is_range) ? inst->VRegH_4rcc() : inst->VRegH_45cc();
+  const dex::ProtoIndex callsite_proto_id(vRegH);
 
   // Call through to the classlinker and ask it to resolve the static type associated
   // with the callsite. This information is stored in the dex cache so it's
@@ -783,10 +784,10 @@
     return false;
   }
 
-  const uint32_t vRegH = is_var_args ? inst->VRegH_45cc() : inst->VRegH_4rcc();
+  const uint16_t vRegH = is_var_args ? inst->VRegH_45cc() : inst->VRegH_4rcc();
   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
   Handle<mirror::MethodType> callsite_type(hs.NewHandle(
-      class_linker->ResolveMethodType(self, vRegH, shadow_frame.GetMethod())));
+      class_linker->ResolveMethodType(self, dex::ProtoIndex(vRegH), shadow_frame.GetMethod())));
   // This implies we couldn't resolve one or more types in this VarHandle.
   if (UNLIKELY(callsite_type == nullptr)) {
     CHECK(self->IsExceptionPending());
@@ -965,9 +966,10 @@
       StackHandleScope<2> hs(self);
       Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
       Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
-      uint32_t index = static_cast<uint32_t>(encoded_value->GetI());
+      dex::ProtoIndex proto_idx(encoded_value->GetC());
       ClassLinker* cl = Runtime::Current()->GetClassLinker();
-      ObjPtr<mirror::MethodType> o = cl->ResolveMethodType(self, index, dex_cache, class_loader);
+      ObjPtr<mirror::MethodType> o =
+          cl->ResolveMethodType(self, proto_idx, dex_cache, class_loader);
       if (UNLIKELY(o.IsNull())) {
         DCHECK(self->IsExceptionPending());
         return false;
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 0818e06..67a0349 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -217,7 +217,7 @@
 }
 
 static inline ObjPtr<mirror::MethodType> ResolveMethodType(Thread* self,
-                                                           uint32_t method_type_index,
+                                                           dex::ProtoIndex method_type_index,
                                                            ArtMethod* referrer)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 283885e..5c7838c 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -565,7 +565,7 @@
         PREAMBLE();
         ClassLinker* cl = Runtime::Current()->GetClassLinker();
         ObjPtr<mirror::MethodType> mt = cl->ResolveMethodType(self,
-                                                              inst->VRegB_21c(),
+                                                              dex::ProtoIndex(inst->VRegB_21c()),
                                                               shadow_frame.GetMethod());
         if (UNLIKELY(mt == nullptr)) {
           HANDLE_PENDING_EXCEPTION();
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 2a9ef2c..1b39a74 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -408,7 +408,8 @@
                                        ShadowFrame* shadow_frame,
                                        Thread* self)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  ObjPtr<mirror::MethodType> mt = ResolveMethodType(self, index, shadow_frame->GetMethod());
+  ObjPtr<mirror::MethodType> mt =
+      ResolveMethodType(self, dex::ProtoIndex(index), shadow_frame->GetMethod());
   if (UNLIKELY(mt == nullptr)) {
     return true;
   }
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index 7a4876c..72f1443 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -127,23 +127,23 @@
   }
 }
 
-inline uint32_t DexCache::MethodTypeSlotIndex(uint32_t proto_idx) {
+inline uint32_t DexCache::MethodTypeSlotIndex(dex::ProtoIndex proto_idx) {
   DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
-  DCHECK_LT(proto_idx, GetDexFile()->NumProtoIds());
-  const uint32_t slot_idx = proto_idx % kDexCacheMethodTypeCacheSize;
+  DCHECK_LT(proto_idx.index_, GetDexFile()->NumProtoIds());
+  const uint32_t slot_idx = proto_idx.index_ % kDexCacheMethodTypeCacheSize;
   DCHECK_LT(slot_idx, NumResolvedMethodTypes());
   return slot_idx;
 }
 
-inline MethodType* DexCache::GetResolvedMethodType(uint32_t proto_idx) {
+inline MethodType* DexCache::GetResolvedMethodType(dex::ProtoIndex proto_idx) {
   return GetResolvedMethodTypes()[MethodTypeSlotIndex(proto_idx)].load(
-      std::memory_order_relaxed).GetObjectForIndex(proto_idx);
+      std::memory_order_relaxed).GetObjectForIndex(proto_idx.index_);
 }
 
-inline void DexCache::SetResolvedMethodType(uint32_t proto_idx, MethodType* resolved) {
+inline void DexCache::SetResolvedMethodType(dex::ProtoIndex proto_idx, MethodType* resolved) {
   DCHECK(resolved != nullptr);
   GetResolvedMethodTypes()[MethodTypeSlotIndex(proto_idx)].store(
-      MethodTypeDexCachePair(resolved, proto_idx), std::memory_order_relaxed);
+      MethodTypeDexCachePair(resolved, proto_idx.index_), std::memory_order_relaxed);
   // TODO: Fine-grained marking, so that we don't need to go through all arrays in full.
   Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(this);
 }
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index d940964..9aff9ec 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -307,9 +307,9 @@
   ALWAYS_INLINE void ClearResolvedField(uint32_t idx, PointerSize ptr_size)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  MethodType* GetResolvedMethodType(uint32_t proto_idx) REQUIRES_SHARED(Locks::mutator_lock_);
+  MethodType* GetResolvedMethodType(dex::ProtoIndex proto_idx) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  void SetResolvedMethodType(uint32_t proto_idx, MethodType* resolved)
+  void SetResolvedMethodType(dex::ProtoIndex proto_idx, MethodType* resolved)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   CallSite* GetResolvedCallSite(uint32_t call_site_idx) REQUIRES_SHARED(Locks::mutator_lock_);
@@ -432,7 +432,7 @@
   uint32_t TypeSlotIndex(dex::TypeIndex type_idx) REQUIRES_SHARED(Locks::mutator_lock_);
   uint32_t FieldSlotIndex(uint32_t field_idx) REQUIRES_SHARED(Locks::mutator_lock_);
   uint32_t MethodSlotIndex(uint32_t method_idx) REQUIRES_SHARED(Locks::mutator_lock_);
-  uint32_t MethodTypeSlotIndex(uint32_t proto_idx) REQUIRES_SHARED(Locks::mutator_lock_);
+  uint32_t MethodTypeSlotIndex(dex::ProtoIndex proto_idx) REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
   void Init(const DexFile* dex_file,
diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc
index d2bff2c..97e0ce6 100644
--- a/runtime/mirror/dex_cache_test.cc
+++ b/runtime/mirror/dex_cache_test.cc
@@ -169,9 +169,9 @@
 
   for (size_t i = 0; i < dex_file.NumProtoIds(); ++i) {
     const MethodTypeDexCachePair pair = method_types_cache[i].load(std::memory_order_relaxed);
-    if (pair.index == method1_id.proto_idx_) {
+    if (dex::ProtoIndex(pair.index) == method1_id.proto_idx_) {
       ASSERT_EQ(method1_type.Get(), pair.object.Read());
-    } else if (pair.index == method2_id.proto_idx_) {
+    } else if (dex::ProtoIndex(pair.index) == method2_id.proto_idx_) {
       ASSERT_EQ(method2_type.Get(), pair.object.Read());
     } else {
       ASSERT_TRUE(false);
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 3518d2f..92ee98a 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -3086,7 +3086,8 @@
         DCHECK(HasFailures());
         break;
       }
-      const uint32_t proto_idx = (is_range) ? inst->VRegH_4rcc() : inst->VRegH_45cc();
+      const uint16_t vRegH = (is_range) ? inst->VRegH_4rcc() : inst->VRegH_45cc();
+      const dex::ProtoIndex proto_idx(vRegH);
       const char* return_descriptor =
           dex_file_->GetReturnTypeDescriptor(dex_file_->GetProtoId(proto_idx));
       const RegType& return_type =
@@ -3117,7 +3118,7 @@
       CallSiteArrayValueIterator it(*dex_file_, dex_file_->GetCallSiteId(call_site_idx));
       it.Next();  // Skip to name.
       it.Next();  // Skip to method type of the method handle
-      const uint32_t proto_idx = static_cast<uint32_t>(it.GetJavaValue().i);
+      const dex::ProtoIndex proto_idx(it.GetJavaValue().c);
       const DexFile::ProtoId& proto_id = dex_file_->GetProtoId(proto_idx);
       DexFileParameterIterator param_it(*dex_file_, proto_id);
       // Treat method as static as it has yet to be determined.
@@ -4190,7 +4191,8 @@
 
   if (UNLIKELY(method_type == METHOD_POLYMORPHIC)) {
     // Process the signature of the calling site that is invoking the method handle.
-    DexFileParameterIterator it(*dex_file_, dex_file_->GetProtoId(inst->VRegH()));
+    dex::ProtoIndex proto_idx(inst->VRegH());
+    DexFileParameterIterator it(*dex_file_, dex_file_->GetProtoId(proto_idx));
     return VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, res_method);
   } else {
     // Process the target method's signature.