• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_LIBDEXFILE_DEX_DEX_FILE_INL_H_
18 #define ART_LIBDEXFILE_DEX_DEX_FILE_INL_H_
19 
20 #include "base/casts.h"
21 #include "base/leb128.h"
22 #include "base/stringpiece.h"
23 #include "compact_dex_file.h"
24 #include "dex_file.h"
25 #include "invoke_type.h"
26 #include "standard_dex_file.h"
27 
28 namespace art {
29 
GetStringLength(const StringId & string_id)30 inline int32_t DexFile::GetStringLength(const StringId& string_id) const {
31   const uint8_t* ptr = DataBegin() + string_id.string_data_off_;
32   return DecodeUnsignedLeb128(&ptr);
33 }
34 
GetStringDataAndUtf16Length(const StringId & string_id,uint32_t * utf16_length)35 inline const char* DexFile::GetStringDataAndUtf16Length(const StringId& string_id,
36                                                         uint32_t* utf16_length) const {
37   DCHECK(utf16_length != nullptr) << GetLocation();
38   const uint8_t* ptr = DataBegin() + string_id.string_data_off_;
39   *utf16_length = DecodeUnsignedLeb128(&ptr);
40   return reinterpret_cast<const char*>(ptr);
41 }
42 
GetStringData(const StringId & string_id)43 inline const char* DexFile::GetStringData(const StringId& string_id) const {
44   uint32_t ignored;
45   return GetStringDataAndUtf16Length(string_id, &ignored);
46 }
47 
StringDataAndUtf16LengthByIdx(dex::StringIndex idx,uint32_t * utf16_length)48 inline const char* DexFile::StringDataAndUtf16LengthByIdx(dex::StringIndex idx,
49                                                           uint32_t* utf16_length) const {
50   if (!idx.IsValid()) {
51     *utf16_length = 0;
52     return nullptr;
53   }
54   const StringId& string_id = GetStringId(idx);
55   return GetStringDataAndUtf16Length(string_id, utf16_length);
56 }
57 
StringDataByIdx(dex::StringIndex idx)58 inline const char* DexFile::StringDataByIdx(dex::StringIndex idx) const {
59   uint32_t unicode_length;
60   return StringDataAndUtf16LengthByIdx(idx, &unicode_length);
61 }
62 
StringByTypeIdx(dex::TypeIndex idx,uint32_t * unicode_length)63 inline const char* DexFile::StringByTypeIdx(dex::TypeIndex idx, uint32_t* unicode_length) const {
64   if (!idx.IsValid()) {
65     return nullptr;
66   }
67   const TypeId& type_id = GetTypeId(idx);
68   return StringDataAndUtf16LengthByIdx(type_id.descriptor_idx_, unicode_length);
69 }
70 
StringByTypeIdx(dex::TypeIndex idx)71 inline const char* DexFile::StringByTypeIdx(dex::TypeIndex idx) const {
72   if (!idx.IsValid()) {
73     return nullptr;
74   }
75   const TypeId& type_id = GetTypeId(idx);
76   return StringDataByIdx(type_id.descriptor_idx_);
77 }
78 
GetTypeDescriptor(const TypeId & type_id)79 inline const char* DexFile::GetTypeDescriptor(const TypeId& type_id) const {
80   return StringDataByIdx(type_id.descriptor_idx_);
81 }
82 
GetFieldTypeDescriptor(const FieldId & field_id)83 inline const char* DexFile::GetFieldTypeDescriptor(const FieldId& field_id) const {
84   const DexFile::TypeId& type_id = GetTypeId(field_id.type_idx_);
85   return GetTypeDescriptor(type_id);
86 }
87 
GetFieldName(const FieldId & field_id)88 inline const char* DexFile::GetFieldName(const FieldId& field_id) const {
89   return StringDataByIdx(field_id.name_idx_);
90 }
91 
GetMethodDeclaringClassDescriptor(const MethodId & method_id)92 inline const char* DexFile::GetMethodDeclaringClassDescriptor(const MethodId& method_id) const {
93   const DexFile::TypeId& type_id = GetTypeId(method_id.class_idx_);
94   return GetTypeDescriptor(type_id);
95 }
96 
GetMethodSignature(const MethodId & method_id)97 inline const Signature DexFile::GetMethodSignature(const MethodId& method_id) const {
98   return Signature(this, GetProtoId(method_id.proto_idx_));
99 }
100 
GetProtoSignature(const ProtoId & proto_id)101 inline const Signature DexFile::GetProtoSignature(const ProtoId& proto_id) const {
102   return Signature(this, proto_id);
103 }
104 
GetMethodName(const MethodId & method_id)105 inline const char* DexFile::GetMethodName(const MethodId& method_id) const {
106   return StringDataByIdx(method_id.name_idx_);
107 }
108 
GetMethodShorty(uint32_t idx)109 inline const char* DexFile::GetMethodShorty(uint32_t idx) const {
110   return StringDataByIdx(GetProtoId(GetMethodId(idx).proto_idx_).shorty_idx_);
111 }
112 
GetMethodShorty(const MethodId & method_id)113 inline const char* DexFile::GetMethodShorty(const MethodId& method_id) const {
114   return StringDataByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_);
115 }
116 
GetMethodShorty(const MethodId & method_id,uint32_t * length)117 inline const char* DexFile::GetMethodShorty(const MethodId& method_id, uint32_t* length) const {
118   // Using the UTF16 length is safe here as shorties are guaranteed to be ASCII characters.
119   return StringDataAndUtf16LengthByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_, length);
120 }
121 
GetClassDescriptor(const ClassDef & class_def)122 inline const char* DexFile::GetClassDescriptor(const ClassDef& class_def) const {
123   return StringByTypeIdx(class_def.class_idx_);
124 }
125 
GetReturnTypeDescriptor(const ProtoId & proto_id)126 inline const char* DexFile::GetReturnTypeDescriptor(const ProtoId& proto_id) const {
127   return StringByTypeIdx(proto_id.return_type_idx_);
128 }
129 
GetShorty(uint32_t proto_idx)130 inline const char* DexFile::GetShorty(uint32_t proto_idx) const {
131   const ProtoId& proto_id = GetProtoId(proto_idx);
132   return StringDataByIdx(proto_id.shorty_idx_);
133 }
134 
GetTryItems(const DexInstructionIterator & code_item_end,uint32_t offset)135 inline const DexFile::TryItem* DexFile::GetTryItems(const DexInstructionIterator& code_item_end,
136                                                     uint32_t offset) {
137   return reinterpret_cast<const TryItem*>
138       (RoundUp(reinterpret_cast<uintptr_t>(&code_item_end.Inst()), TryItem::kAlignment)) + offset;
139 }
140 
DexFileStringEquals(const DexFile * df1,dex::StringIndex sidx1,const DexFile * df2,dex::StringIndex sidx2)141 static inline bool DexFileStringEquals(const DexFile* df1, dex::StringIndex sidx1,
142                                        const DexFile* df2, dex::StringIndex sidx2) {
143   uint32_t s1_len;  // Note: utf16 length != mutf8 length.
144   const char* s1_data = df1->StringDataAndUtf16LengthByIdx(sidx1, &s1_len);
145   uint32_t s2_len;
146   const char* s2_data = df2->StringDataAndUtf16LengthByIdx(sidx2, &s2_len);
147   return (s1_len == s2_len) && (strcmp(s1_data, s2_data) == 0);
148 }
149 
150 inline bool Signature::operator==(const Signature& rhs) const {
151   if (dex_file_ == nullptr) {
152     return rhs.dex_file_ == nullptr;
153   }
154   if (rhs.dex_file_ == nullptr) {
155     return false;
156   }
157   if (dex_file_ == rhs.dex_file_) {
158     return proto_id_ == rhs.proto_id_;
159   }
160   uint32_t lhs_shorty_len;  // For a shorty utf16 length == mutf8 length.
161   const char* lhs_shorty_data = dex_file_->StringDataAndUtf16LengthByIdx(proto_id_->shorty_idx_,
162                                                                          &lhs_shorty_len);
163   StringPiece lhs_shorty(lhs_shorty_data, lhs_shorty_len);
164   {
165     uint32_t rhs_shorty_len;
166     const char* rhs_shorty_data =
167         rhs.dex_file_->StringDataAndUtf16LengthByIdx(rhs.proto_id_->shorty_idx_,
168                                                      &rhs_shorty_len);
169     StringPiece rhs_shorty(rhs_shorty_data, rhs_shorty_len);
170     if (lhs_shorty != rhs_shorty) {
171       return false;  // Shorty mismatch.
172     }
173   }
174   if (lhs_shorty[0] == 'L') {
175     const DexFile::TypeId& return_type_id = dex_file_->GetTypeId(proto_id_->return_type_idx_);
176     const DexFile::TypeId& rhs_return_type_id =
177         rhs.dex_file_->GetTypeId(rhs.proto_id_->return_type_idx_);
178     if (!DexFileStringEquals(dex_file_, return_type_id.descriptor_idx_,
179                              rhs.dex_file_, rhs_return_type_id.descriptor_idx_)) {
180       return false;  // Return type mismatch.
181     }
182   }
183   if (lhs_shorty.find('L', 1) != StringPiece::npos) {
184     const DexFile::TypeList* params = dex_file_->GetProtoParameters(*proto_id_);
185     const DexFile::TypeList* rhs_params = rhs.dex_file_->GetProtoParameters(*rhs.proto_id_);
186     // We found a reference parameter in the matching shorty, so both lists must be non-empty.
187     DCHECK(params != nullptr);
188     DCHECK(rhs_params != nullptr);
189     uint32_t params_size = params->Size();
190     DCHECK_EQ(params_size, rhs_params->Size());  // Parameter list size must match.
191     for (uint32_t i = 0; i < params_size; ++i) {
192       const DexFile::TypeId& param_id = dex_file_->GetTypeId(params->GetTypeItem(i).type_idx_);
193       const DexFile::TypeId& rhs_param_id =
194           rhs.dex_file_->GetTypeId(rhs_params->GetTypeItem(i).type_idx_);
195       if (!DexFileStringEquals(dex_file_, param_id.descriptor_idx_,
196                                rhs.dex_file_, rhs_param_id.descriptor_idx_)) {
197         return false;  // Parameter type mismatch.
198       }
199     }
200   }
201   return true;
202 }
203 
204 inline
GetMethodInvokeType(const DexFile::ClassDef & class_def)205 InvokeType ClassDataItemIterator::GetMethodInvokeType(const DexFile::ClassDef& class_def) const {
206   if (HasNextDirectMethod()) {
207     if ((GetRawMemberAccessFlags() & kAccStatic) != 0) {
208       return kStatic;
209     } else {
210       return kDirect;
211     }
212   } else {
213     DCHECK_EQ(GetRawMemberAccessFlags() & kAccStatic, 0U);
214     if ((class_def.access_flags_ & kAccInterface) != 0) {
215       return kInterface;
216     } else if ((GetRawMemberAccessFlags() & kAccConstructor) != 0) {
217       return kSuper;
218     } else {
219       return kVirtual;
220     }
221   }
222 }
223 
224 template<typename NewLocalCallback, typename IndexToStringData, typename TypeIndexToStringData>
DecodeDebugLocalInfo(const uint8_t * stream,const std::string & location,const char * declaring_class_descriptor,const std::vector<const char * > & arg_descriptors,const std::string & method_name,bool is_static,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)225 bool DexFile::DecodeDebugLocalInfo(const uint8_t* stream,
226                                    const std::string& location,
227                                    const char* declaring_class_descriptor,
228                                    const std::vector<const char*>& arg_descriptors,
229                                    const std::string& method_name,
230                                    bool is_static,
231                                    uint16_t registers_size,
232                                    uint16_t ins_size,
233                                    uint16_t insns_size_in_code_units,
234                                    IndexToStringData index_to_string_data,
235                                    TypeIndexToStringData type_index_to_string_data,
236                                    NewLocalCallback new_local_callback,
237                                    void* context) {
238   if (stream == nullptr) {
239     return false;
240   }
241   std::vector<LocalInfo> local_in_reg(registers_size);
242 
243   uint16_t arg_reg = registers_size - ins_size;
244   if (!is_static) {
245     const char* descriptor = declaring_class_descriptor;
246     local_in_reg[arg_reg].name_ = "this";
247     local_in_reg[arg_reg].descriptor_ = descriptor;
248     local_in_reg[arg_reg].signature_ = nullptr;
249     local_in_reg[arg_reg].start_address_ = 0;
250     local_in_reg[arg_reg].reg_ = arg_reg;
251     local_in_reg[arg_reg].is_live_ = true;
252     arg_reg++;
253   }
254 
255   DecodeUnsignedLeb128(&stream);  // Line.
256   uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
257   uint32_t i;
258   if (parameters_size != arg_descriptors.size()) {
259     LOG(ERROR) << "invalid stream - problem with parameter iterator in " << location
260                << " for method " << method_name;
261     return false;
262   }
263   for (i = 0; i < parameters_size && i < arg_descriptors.size(); ++i) {
264     if (arg_reg >= registers_size) {
265       LOG(ERROR) << "invalid stream - arg reg >= reg size (" << arg_reg
266                  << " >= " << registers_size << ") in " << location;
267       return false;
268     }
269     uint32_t name_idx = DecodeUnsignedLeb128P1(&stream);
270     const char* descriptor = arg_descriptors[i];
271     local_in_reg[arg_reg].name_ = index_to_string_data(name_idx);
272     local_in_reg[arg_reg].descriptor_ = descriptor;
273     local_in_reg[arg_reg].signature_ = nullptr;
274     local_in_reg[arg_reg].start_address_ = 0;
275     local_in_reg[arg_reg].reg_ = arg_reg;
276     local_in_reg[arg_reg].is_live_ = true;
277     switch (*descriptor) {
278       case 'D':
279       case 'J':
280         arg_reg += 2;
281         break;
282       default:
283         arg_reg += 1;
284         break;
285     }
286   }
287 
288   uint32_t address = 0;
289   for (;;)  {
290     uint8_t opcode = *stream++;
291     switch (opcode) {
292       case DBG_END_SEQUENCE:
293         // Emit all variables which are still alive at the end of the method.
294         for (uint16_t reg = 0; reg < registers_size; reg++) {
295           if (local_in_reg[reg].is_live_) {
296             local_in_reg[reg].end_address_ = insns_size_in_code_units;
297             new_local_callback(context, local_in_reg[reg]);
298           }
299         }
300         return true;
301       case DBG_ADVANCE_PC:
302         address += DecodeUnsignedLeb128(&stream);
303         break;
304       case DBG_ADVANCE_LINE:
305         DecodeSignedLeb128(&stream);  // Line.
306         break;
307       case DBG_START_LOCAL:
308       case DBG_START_LOCAL_EXTENDED: {
309         uint16_t reg = DecodeUnsignedLeb128(&stream);
310         if (reg >= registers_size) {
311           LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= "
312                      << registers_size << ") in " << location;
313           return false;
314         }
315 
316         uint32_t name_idx = DecodeUnsignedLeb128P1(&stream);
317         uint16_t descriptor_idx = DecodeUnsignedLeb128P1(&stream);
318         uint32_t signature_idx = dex::kDexNoIndex;
319         if (opcode == DBG_START_LOCAL_EXTENDED) {
320           signature_idx = DecodeUnsignedLeb128P1(&stream);
321         }
322 
323         // Emit what was previously there, if anything
324         if (local_in_reg[reg].is_live_) {
325           local_in_reg[reg].end_address_ = address;
326           new_local_callback(context, local_in_reg[reg]);
327         }
328 
329         local_in_reg[reg].name_ = index_to_string_data(name_idx);
330         local_in_reg[reg].descriptor_ = type_index_to_string_data(descriptor_idx);;
331         local_in_reg[reg].signature_ = index_to_string_data(signature_idx);
332         local_in_reg[reg].start_address_ = address;
333         local_in_reg[reg].reg_ = reg;
334         local_in_reg[reg].is_live_ = true;
335         break;
336       }
337       case DBG_END_LOCAL: {
338         uint16_t reg = DecodeUnsignedLeb128(&stream);
339         if (reg >= registers_size) {
340           LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= "
341                      << registers_size << ") in " << location;
342           return false;
343         }
344         // If the register is live, close it properly. Otherwise, closing an already
345         // closed register is sloppy, but harmless if no further action is taken.
346         if (local_in_reg[reg].is_live_) {
347           local_in_reg[reg].end_address_ = address;
348           new_local_callback(context, local_in_reg[reg]);
349           local_in_reg[reg].is_live_ = false;
350         }
351         break;
352       }
353       case DBG_RESTART_LOCAL: {
354         uint16_t reg = DecodeUnsignedLeb128(&stream);
355         if (reg >= registers_size) {
356           LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= "
357                      << registers_size << ") in " << location;
358           return false;
359         }
360         // If the register is live, the "restart" is superfluous,
361         // and we don't want to mess with the existing start address.
362         if (!local_in_reg[reg].is_live_) {
363           local_in_reg[reg].start_address_ = address;
364           local_in_reg[reg].is_live_ = true;
365         }
366         break;
367       }
368       case DBG_SET_PROLOGUE_END:
369       case DBG_SET_EPILOGUE_BEGIN:
370         break;
371       case DBG_SET_FILE:
372         DecodeUnsignedLeb128P1(&stream);  // name.
373         break;
374       default:
375         address += (opcode - DBG_FIRST_SPECIAL) / DBG_LINE_RANGE;
376         break;
377     }
378   }
379 }
380 
381 template<typename NewLocalCallback>
DecodeDebugLocalInfo(uint32_t registers_size,uint32_t ins_size,uint32_t insns_size_in_code_units,uint32_t debug_info_offset,bool is_static,uint32_t method_idx,NewLocalCallback new_local_callback,void * context)382 bool DexFile::DecodeDebugLocalInfo(uint32_t registers_size,
383                                    uint32_t ins_size,
384                                    uint32_t insns_size_in_code_units,
385                                    uint32_t debug_info_offset,
386                                    bool is_static,
387                                    uint32_t method_idx,
388                                    NewLocalCallback new_local_callback,
389                                    void* context) const {
390   const uint8_t* const stream = GetDebugInfoStream(debug_info_offset);
391   if (stream == nullptr) {
392     return false;
393   }
394   std::vector<const char*> arg_descriptors;
395   DexFileParameterIterator it(*this, GetMethodPrototype(GetMethodId(method_idx)));
396   for (; it.HasNext(); it.Next()) {
397     arg_descriptors.push_back(it.GetDescriptor());
398   }
399   return DecodeDebugLocalInfo(stream,
400                               GetLocation(),
401                               GetMethodDeclaringClassDescriptor(GetMethodId(method_idx)),
402                               arg_descriptors,
403                               this->PrettyMethod(method_idx),
404                               is_static,
405                               registers_size,
406                               ins_size,
407                               insns_size_in_code_units,
408                               [this](uint32_t idx) {
409                                 return StringDataByIdx(dex::StringIndex(idx));
410                               },
411                               [this](uint32_t idx) {
412                                 return StringByTypeIdx(dex::TypeIndex(
413                                     dchecked_integral_cast<uint16_t>(idx)));
414                               },
415                               new_local_callback,
416                               context);
417 }
418 
419 template<typename DexDebugNewPosition, typename IndexToStringData>
DecodeDebugPositionInfo(const uint8_t * stream,IndexToStringData index_to_string_data,DexDebugNewPosition position_functor,void * context)420 bool DexFile::DecodeDebugPositionInfo(const uint8_t* stream,
421                                       IndexToStringData index_to_string_data,
422                                       DexDebugNewPosition position_functor,
423                                       void* context) {
424   if (stream == nullptr) {
425     return false;
426   }
427 
428   PositionInfo entry = PositionInfo();
429   entry.line_ = DecodeUnsignedLeb128(&stream);
430   uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
431   for (uint32_t i = 0; i < parameters_size; ++i) {
432     DecodeUnsignedLeb128P1(&stream);  // Parameter name.
433   }
434 
435   for (;;)  {
436     uint8_t opcode = *stream++;
437     switch (opcode) {
438       case DBG_END_SEQUENCE:
439         return true;  // end of stream.
440       case DBG_ADVANCE_PC:
441         entry.address_ += DecodeUnsignedLeb128(&stream);
442         break;
443       case DBG_ADVANCE_LINE:
444         entry.line_ += DecodeSignedLeb128(&stream);
445         break;
446       case DBG_START_LOCAL:
447         DecodeUnsignedLeb128(&stream);  // reg.
448         DecodeUnsignedLeb128P1(&stream);  // name.
449         DecodeUnsignedLeb128P1(&stream);  // descriptor.
450         break;
451       case DBG_START_LOCAL_EXTENDED:
452         DecodeUnsignedLeb128(&stream);  // reg.
453         DecodeUnsignedLeb128P1(&stream);  // name.
454         DecodeUnsignedLeb128P1(&stream);  // descriptor.
455         DecodeUnsignedLeb128P1(&stream);  // signature.
456         break;
457       case DBG_END_LOCAL:
458       case DBG_RESTART_LOCAL:
459         DecodeUnsignedLeb128(&stream);  // reg.
460         break;
461       case DBG_SET_PROLOGUE_END:
462         entry.prologue_end_ = true;
463         break;
464       case DBG_SET_EPILOGUE_BEGIN:
465         entry.epilogue_begin_ = true;
466         break;
467       case DBG_SET_FILE: {
468         uint32_t name_idx = DecodeUnsignedLeb128P1(&stream);
469         entry.source_file_ = index_to_string_data(name_idx);
470         break;
471       }
472       default: {
473         int adjopcode = opcode - DBG_FIRST_SPECIAL;
474         entry.address_ += adjopcode / DBG_LINE_RANGE;
475         entry.line_ += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
476         if (position_functor(context, entry)) {
477           return true;  // early exit.
478         }
479         entry.prologue_end_ = false;
480         entry.epilogue_begin_ = false;
481         break;
482       }
483     }
484   }
485 }
486 
487 template<typename DexDebugNewPosition>
DecodeDebugPositionInfo(uint32_t debug_info_offset,DexDebugNewPosition position_functor,void * context)488 bool DexFile::DecodeDebugPositionInfo(uint32_t debug_info_offset,
489                                       DexDebugNewPosition position_functor,
490                                       void* context) const {
491   return DecodeDebugPositionInfo(GetDebugInfoStream(debug_info_offset),
492                                  [this](uint32_t idx) {
493                                    return StringDataByIdx(dex::StringIndex(idx));
494                                  },
495                                  position_functor,
496                                  context);
497 }
498 
AsCompactDexFile()499 inline const CompactDexFile* DexFile::AsCompactDexFile() const {
500   DCHECK(IsCompactDexFile());
501   return down_cast<const CompactDexFile*>(this);
502 }
503 
AsStandardDexFile()504 inline const StandardDexFile* DexFile::AsStandardDexFile() const {
505   DCHECK(IsStandardDexFile());
506   return down_cast<const StandardDexFile*>(this);
507 }
508 
509 // Get the base of the encoded data for the given DexCode.
GetCatchHandlerData(const DexInstructionIterator & code_item_end,uint32_t tries_size,uint32_t offset)510 inline const uint8_t* DexFile::GetCatchHandlerData(const DexInstructionIterator& code_item_end,
511                                                    uint32_t tries_size,
512                                                    uint32_t offset) {
513   const uint8_t* handler_data =
514       reinterpret_cast<const uint8_t*>(GetTryItems(code_item_end, tries_size));
515   return handler_data + offset;
516 }
517 
518 template <typename Visitor>
VisitMethods(const DexFile * dex_file,const Visitor & visitor)519 inline void DexFile::ClassDef::VisitMethods(const DexFile* dex_file, const Visitor& visitor) const {
520   const uint8_t* class_data = dex_file->GetClassData(*this);
521   if (class_data != nullptr) {
522     ClassDataItemIterator it(*dex_file, class_data);
523     it.SkipAllFields();
524     for (; it.HasNext(); it.Next()) {
525       visitor(it);
526     }
527   }
528 }
529 
530 }  // namespace art
531 
532 #endif  // ART_LIBDEXFILE_DEX_DEX_FILE_INL_H_
533