1 /*
2  * Copyright (C) 2016 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  * Implementation file of the dexlayout utility.
17  *
18  * This is a tool to read dex files into an internal representation,
19  * reorganize the representation, and emit dex files with a better
20  * file layout.
21  */
22 
23 #include "dex_ir.h"
24 
25 #include "dex/code_item_accessors-inl.h"
26 #include "dex/dex_file_exception_helpers.h"
27 #include "dex/dex_instruction-inl.h"
28 #include "dex_ir_builder.h"
29 
30 namespace art {
31 namespace dex_ir {
32 
ReadVarWidth(const uint8_t ** data,uint8_t length,bool sign_extend)33 static uint64_t ReadVarWidth(const uint8_t** data, uint8_t length, bool sign_extend) {
34   uint64_t value = 0;
35   for (uint32_t i = 0; i <= length; i++) {
36     value |= static_cast<uint64_t>(*(*data)++) << (i * 8);
37   }
38   if (sign_extend) {
39     int shift = (7 - length) * 8;
40     return (static_cast<int64_t>(value) << shift) >> shift;
41   }
42   return value;
43 }
44 
GetDebugInfoStreamSize(const uint8_t * debug_info_stream)45 static uint32_t GetDebugInfoStreamSize(const uint8_t* debug_info_stream) {
46   const uint8_t* stream = debug_info_stream;
47   DecodeUnsignedLeb128(&stream);  // line_start
48   uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
49   for (uint32_t i = 0; i < parameters_size; ++i) {
50     DecodeUnsignedLeb128P1(&stream);  // Parameter name.
51   }
52 
53   for (;;)  {
54     uint8_t opcode = *stream++;
55     switch (opcode) {
56       case DexFile::DBG_END_SEQUENCE:
57         return stream - debug_info_stream;  // end of stream.
58       case DexFile::DBG_ADVANCE_PC:
59         DecodeUnsignedLeb128(&stream);  // addr_diff
60         break;
61       case DexFile::DBG_ADVANCE_LINE:
62         DecodeSignedLeb128(&stream);  // line_diff
63         break;
64       case DexFile::DBG_START_LOCAL:
65         DecodeUnsignedLeb128(&stream);  // register_num
66         DecodeUnsignedLeb128P1(&stream);  // name_idx
67         DecodeUnsignedLeb128P1(&stream);  // type_idx
68         break;
69       case DexFile::DBG_START_LOCAL_EXTENDED:
70         DecodeUnsignedLeb128(&stream);  // register_num
71         DecodeUnsignedLeb128P1(&stream);  // name_idx
72         DecodeUnsignedLeb128P1(&stream);  // type_idx
73         DecodeUnsignedLeb128P1(&stream);  // sig_idx
74         break;
75       case DexFile::DBG_END_LOCAL:
76       case DexFile::DBG_RESTART_LOCAL:
77         DecodeUnsignedLeb128(&stream);  // register_num
78         break;
79       case DexFile::DBG_SET_PROLOGUE_END:
80       case DexFile::DBG_SET_EPILOGUE_BEGIN:
81         break;
82       case DexFile::DBG_SET_FILE: {
83         DecodeUnsignedLeb128P1(&stream);  // name_idx
84         break;
85       }
86       default: {
87         break;
88       }
89     }
90   }
91 }
92 
GetIdFromInstruction(Collections & collections,const Instruction * dec_insn,std::vector<TypeId * > * type_ids,std::vector<StringId * > * string_ids,std::vector<MethodId * > * method_ids,std::vector<FieldId * > * field_ids)93 static bool GetIdFromInstruction(Collections& collections,
94                                  const Instruction* dec_insn,
95                                  std::vector<TypeId*>* type_ids,
96                                  std::vector<StringId*>* string_ids,
97                                  std::vector<MethodId*>* method_ids,
98                                  std::vector<FieldId*>* field_ids) {
99   // Determine index and width of the string.
100   uint32_t index = 0;
101   switch (Instruction::FormatOf(dec_insn->Opcode())) {
102     // SOME NOT SUPPORTED:
103     // case Instruction::k20bc:
104     case Instruction::k21c:
105     case Instruction::k35c:
106     // case Instruction::k35ms:
107     case Instruction::k3rc:
108     // case Instruction::k3rms:
109     // case Instruction::k35mi:
110     // case Instruction::k3rmi:
111     case Instruction::k45cc:
112     case Instruction::k4rcc:
113       index = dec_insn->VRegB();
114       break;
115     case Instruction::k31c:
116       index = dec_insn->VRegB();
117       break;
118     case Instruction::k22c:
119     // case Instruction::k22cs:
120       index = dec_insn->VRegC();
121       break;
122     default:
123       break;
124   }  // switch
125 
126   // Determine index type, and add reference to the appropriate collection.
127   switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
128     case Instruction::kIndexTypeRef:
129       if (index < collections.TypeIdsSize()) {
130         type_ids->push_back(collections.GetTypeId(index));
131         return true;
132       }
133       break;
134     case Instruction::kIndexStringRef:
135       if (index < collections.StringIdsSize()) {
136         string_ids->push_back(collections.GetStringId(index));
137         return true;
138       }
139       break;
140     case Instruction::kIndexMethodRef:
141     case Instruction::kIndexMethodAndProtoRef:
142       if (index < collections.MethodIdsSize()) {
143         method_ids->push_back(collections.GetMethodId(index));
144         return true;
145       }
146       break;
147     case Instruction::kIndexFieldRef:
148       if (index < collections.FieldIdsSize()) {
149         field_ids->push_back(collections.GetFieldId(index));
150         return true;
151       }
152       break;
153     case Instruction::kIndexUnknown:
154     case Instruction::kIndexNone:
155     case Instruction::kIndexVtableOffset:
156     case Instruction::kIndexFieldOffset:
157     default:
158       break;
159   }  // switch
160   return false;
161 }
162 
163 /*
164  * Get all the types, strings, methods, and fields referred to from bytecode.
165  */
GetIdsFromByteCode(Collections & collections,const CodeItem * code,std::vector<TypeId * > * type_ids,std::vector<StringId * > * string_ids,std::vector<MethodId * > * method_ids,std::vector<FieldId * > * field_ids)166 static bool GetIdsFromByteCode(Collections& collections,
167                                const CodeItem* code,
168                                std::vector<TypeId*>* type_ids,
169                                std::vector<StringId*>* string_ids,
170                                std::vector<MethodId*>* method_ids,
171                                std::vector<FieldId*>* field_ids) {
172   bool has_id = false;
173   IterationRange<DexInstructionIterator> instructions = code->Instructions();
174   SafeDexInstructionIterator it(instructions.begin(), instructions.end());
175   for (; !it.IsErrorState() && it < instructions.end(); ++it) {
176     // In case the instruction goes past the end of the code item, make sure to not process it.
177     SafeDexInstructionIterator next = it;
178     ++next;
179     if (next.IsErrorState()) {
180       break;
181     }
182     has_id |= GetIdFromInstruction(collections,
183                                    &it.Inst(),
184                                    type_ids,
185                                    string_ids,
186                                    method_ids,
187                                    field_ids);
188   }  // for
189   return has_id;
190 }
191 
ReadEncodedValue(const DexFile & dex_file,const uint8_t ** data)192 EncodedValue* Collections::ReadEncodedValue(const DexFile& dex_file, const uint8_t** data) {
193   const uint8_t encoded_value = *(*data)++;
194   const uint8_t type = encoded_value & 0x1f;
195   EncodedValue* item = new EncodedValue(type);
196   ReadEncodedValue(dex_file, data, type, encoded_value >> 5, item);
197   return item;
198 }
199 
ReadEncodedValue(const DexFile & dex_file,const uint8_t ** data,uint8_t type,uint8_t length)200 EncodedValue* Collections::ReadEncodedValue(const DexFile& dex_file,
201                                             const uint8_t** data,
202                                             uint8_t type,
203                                             uint8_t length) {
204   EncodedValue* item = new EncodedValue(type);
205   ReadEncodedValue(dex_file, data, type, length, item);
206   return item;
207 }
208 
ReadEncodedValue(const DexFile & dex_file,const uint8_t ** data,uint8_t type,uint8_t length,EncodedValue * item)209 void Collections::ReadEncodedValue(const DexFile& dex_file,
210                                    const uint8_t** data,
211                                    uint8_t type,
212                                    uint8_t length,
213                                    EncodedValue* item) {
214   switch (type) {
215     case DexFile::kDexAnnotationByte:
216       item->SetByte(static_cast<int8_t>(ReadVarWidth(data, length, false)));
217       break;
218     case DexFile::kDexAnnotationShort:
219       item->SetShort(static_cast<int16_t>(ReadVarWidth(data, length, true)));
220       break;
221     case DexFile::kDexAnnotationChar:
222       item->SetChar(static_cast<uint16_t>(ReadVarWidth(data, length, false)));
223       break;
224     case DexFile::kDexAnnotationInt:
225       item->SetInt(static_cast<int32_t>(ReadVarWidth(data, length, true)));
226       break;
227     case DexFile::kDexAnnotationLong:
228       item->SetLong(static_cast<int64_t>(ReadVarWidth(data, length, true)));
229       break;
230     case DexFile::kDexAnnotationFloat: {
231       // Fill on right.
232       union {
233         float f;
234         uint32_t data;
235       } conv;
236       conv.data = static_cast<uint32_t>(ReadVarWidth(data, length, false)) << (3 - length) * 8;
237       item->SetFloat(conv.f);
238       break;
239     }
240     case DexFile::kDexAnnotationDouble: {
241       // Fill on right.
242       union {
243         double d;
244         uint64_t data;
245       } conv;
246       conv.data = ReadVarWidth(data, length, false) << (7 - length) * 8;
247       item->SetDouble(conv.d);
248       break;
249     }
250     case DexFile::kDexAnnotationMethodType: {
251       const uint32_t proto_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
252       item->SetProtoId(GetProtoId(proto_index));
253       break;
254     }
255     case DexFile::kDexAnnotationMethodHandle: {
256       const uint32_t method_handle_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
257       item->SetMethodHandle(GetMethodHandle(method_handle_index));
258       break;
259     }
260     case DexFile::kDexAnnotationString: {
261       const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
262       item->SetStringId(GetStringId(string_index));
263       break;
264     }
265     case DexFile::kDexAnnotationType: {
266       const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
267       item->SetTypeId(GetTypeId(string_index));
268       break;
269     }
270     case DexFile::kDexAnnotationField:
271     case DexFile::kDexAnnotationEnum: {
272       const uint32_t field_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
273       item->SetFieldId(GetFieldId(field_index));
274       break;
275     }
276     case DexFile::kDexAnnotationMethod: {
277       const uint32_t method_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
278       item->SetMethodId(GetMethodId(method_index));
279       break;
280     }
281     case DexFile::kDexAnnotationArray: {
282       EncodedValueVector* values = new EncodedValueVector();
283       const uint32_t offset = *data - dex_file.DataBegin();
284       const uint32_t size = DecodeUnsignedLeb128(data);
285       // Decode all elements.
286       for (uint32_t i = 0; i < size; i++) {
287         values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(dex_file, data)));
288       }
289       EncodedArrayItem* array_item = new EncodedArrayItem(values);
290       if (eagerly_assign_offsets_) {
291         array_item->SetOffset(offset);
292       }
293       item->SetEncodedArray(array_item);
294       break;
295     }
296     case DexFile::kDexAnnotationAnnotation: {
297       AnnotationElementVector* elements = new AnnotationElementVector();
298       const uint32_t type_idx = DecodeUnsignedLeb128(data);
299       const uint32_t size = DecodeUnsignedLeb128(data);
300       // Decode all name=value pairs.
301       for (uint32_t i = 0; i < size; i++) {
302         const uint32_t name_index = DecodeUnsignedLeb128(data);
303         elements->push_back(std::unique_ptr<AnnotationElement>(
304             new AnnotationElement(GetStringId(name_index), ReadEncodedValue(dex_file, data))));
305       }
306       item->SetEncodedAnnotation(new EncodedAnnotation(GetTypeId(type_idx), elements));
307       break;
308     }
309     case DexFile::kDexAnnotationNull:
310       break;
311     case DexFile::kDexAnnotationBoolean:
312       item->SetBoolean(length != 0);
313       break;
314     default:
315       break;
316   }
317 }
318 
CreateStringId(const DexFile & dex_file,uint32_t i)319 void Collections::CreateStringId(const DexFile& dex_file, uint32_t i) {
320   const DexFile::StringId& disk_string_id = dex_file.GetStringId(dex::StringIndex(i));
321   StringData* string_data = new StringData(dex_file.GetStringData(disk_string_id));
322   AddItem(string_datas_map_, string_datas_, string_data, disk_string_id.string_data_off_);
323 
324   StringId* string_id = new StringId(string_data);
325   AddIndexedItem(string_ids_, string_id, StringIdsOffset() + i * StringId::ItemSize(), i);
326 }
327 
CreateTypeId(const DexFile & dex_file,uint32_t i)328 void Collections::CreateTypeId(const DexFile& dex_file, uint32_t i) {
329   const DexFile::TypeId& disk_type_id = dex_file.GetTypeId(dex::TypeIndex(i));
330   TypeId* type_id = new TypeId(GetStringId(disk_type_id.descriptor_idx_.index_));
331   AddIndexedItem(type_ids_, type_id, TypeIdsOffset() + i * TypeId::ItemSize(), i);
332 }
333 
CreateProtoId(const DexFile & dex_file,uint32_t i)334 void Collections::CreateProtoId(const DexFile& dex_file, uint32_t i) {
335   const DexFile::ProtoId& disk_proto_id = dex_file.GetProtoId(i);
336   const DexFile::TypeList* type_list = dex_file.GetProtoParameters(disk_proto_id);
337   TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_);
338 
339   ProtoId* proto_id = new ProtoId(GetStringId(disk_proto_id.shorty_idx_.index_),
340                                   GetTypeId(disk_proto_id.return_type_idx_.index_),
341                                   parameter_type_list);
342   AddIndexedItem(proto_ids_, proto_id, ProtoIdsOffset() + i * ProtoId::ItemSize(), i);
343 }
344 
CreateFieldId(const DexFile & dex_file,uint32_t i)345 void Collections::CreateFieldId(const DexFile& dex_file, uint32_t i) {
346   const DexFile::FieldId& disk_field_id = dex_file.GetFieldId(i);
347   FieldId* field_id = new FieldId(GetTypeId(disk_field_id.class_idx_.index_),
348                                   GetTypeId(disk_field_id.type_idx_.index_),
349                                   GetStringId(disk_field_id.name_idx_.index_));
350   AddIndexedItem(field_ids_, field_id, FieldIdsOffset() + i * FieldId::ItemSize(), i);
351 }
352 
CreateMethodId(const DexFile & dex_file,uint32_t i)353 void Collections::CreateMethodId(const DexFile& dex_file, uint32_t i) {
354   const DexFile::MethodId& disk_method_id = dex_file.GetMethodId(i);
355   MethodId* method_id = new MethodId(GetTypeId(disk_method_id.class_idx_.index_),
356                                      GetProtoId(disk_method_id.proto_idx_),
357                                      GetStringId(disk_method_id.name_idx_.index_));
358   AddIndexedItem(method_ids_, method_id, MethodIdsOffset() + i * MethodId::ItemSize(), i);
359 }
360 
CreateClassDef(const DexFile & dex_file,uint32_t i)361 void Collections::CreateClassDef(const DexFile& dex_file, uint32_t i) {
362   const DexFile::ClassDef& disk_class_def = dex_file.GetClassDef(i);
363   const TypeId* class_type = GetTypeId(disk_class_def.class_idx_.index_);
364   uint32_t access_flags = disk_class_def.access_flags_;
365   const TypeId* superclass = GetTypeIdOrNullPtr(disk_class_def.superclass_idx_.index_);
366 
367   const DexFile::TypeList* type_list = dex_file.GetInterfacesList(disk_class_def);
368   TypeList* interfaces_type_list = CreateTypeList(type_list, disk_class_def.interfaces_off_);
369 
370   const StringId* source_file = GetStringIdOrNullPtr(disk_class_def.source_file_idx_.index_);
371   // Annotations.
372   AnnotationsDirectoryItem* annotations = nullptr;
373   const DexFile::AnnotationsDirectoryItem* disk_annotations_directory_item =
374       dex_file.GetAnnotationsDirectory(disk_class_def);
375   if (disk_annotations_directory_item != nullptr) {
376     annotations = CreateAnnotationsDirectoryItem(
377         dex_file, disk_annotations_directory_item, disk_class_def.annotations_off_);
378   }
379   // Static field initializers.
380   const uint8_t* static_data = dex_file.GetEncodedStaticFieldValuesArray(disk_class_def);
381   EncodedArrayItem* static_values =
382       CreateEncodedArrayItem(dex_file, static_data, disk_class_def.static_values_off_);
383   ClassData* class_data = CreateClassData(
384       dex_file, dex_file.GetClassData(disk_class_def), disk_class_def.class_data_off_);
385   ClassDef* class_def = new ClassDef(class_type, access_flags, superclass, interfaces_type_list,
386                                      source_file, annotations, static_values, class_data);
387   AddIndexedItem(class_defs_, class_def, ClassDefsOffset() + i * ClassDef::ItemSize(), i);
388 }
389 
CreateTypeList(const DexFile::TypeList * dex_type_list,uint32_t offset)390 TypeList* Collections::CreateTypeList(const DexFile::TypeList* dex_type_list, uint32_t offset) {
391   if (dex_type_list == nullptr) {
392     return nullptr;
393   }
394   TypeList* type_list = type_lists_map_.GetExistingObject(offset);
395   if (type_list == nullptr) {
396     TypeIdVector* type_vector = new TypeIdVector();
397     uint32_t size = dex_type_list->Size();
398     for (uint32_t index = 0; index < size; ++index) {
399       type_vector->push_back(GetTypeId(dex_type_list->GetTypeItem(index).type_idx_.index_));
400     }
401     type_list = new TypeList(type_vector);
402     AddItem(type_lists_map_, type_lists_, type_list, offset);
403   }
404   return type_list;
405 }
406 
CreateEncodedArrayItem(const DexFile & dex_file,const uint8_t * static_data,uint32_t offset)407 EncodedArrayItem* Collections::CreateEncodedArrayItem(const DexFile& dex_file,
408                                                       const uint8_t* static_data,
409                                                       uint32_t offset) {
410   if (static_data == nullptr) {
411     return nullptr;
412   }
413   EncodedArrayItem* encoded_array_item = encoded_array_items_map_.GetExistingObject(offset);
414   if (encoded_array_item == nullptr) {
415     uint32_t size = DecodeUnsignedLeb128(&static_data);
416     EncodedValueVector* values = new EncodedValueVector();
417     for (uint32_t i = 0; i < size; ++i) {
418       values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(dex_file, &static_data)));
419     }
420     // TODO: Calculate the size of the encoded array.
421     encoded_array_item = new EncodedArrayItem(values);
422     AddItem(encoded_array_items_map_, encoded_array_items_, encoded_array_item, offset);
423   }
424   return encoded_array_item;
425 }
426 
AddAnnotationsFromMapListSection(const DexFile & dex_file,uint32_t start_offset,uint32_t count)427 void Collections::AddAnnotationsFromMapListSection(const DexFile& dex_file,
428                                                    uint32_t start_offset,
429                                                    uint32_t count) {
430   uint32_t current_offset = start_offset;
431   for (size_t i = 0; i < count; ++i) {
432     // Annotation that we didn't process already, add it to the set.
433     const DexFile::AnnotationItem* annotation = dex_file.GetAnnotationItemAtOffset(current_offset);
434     AnnotationItem* annotation_item = CreateAnnotationItem(dex_file, annotation);
435     DCHECK(annotation_item != nullptr);
436     current_offset += annotation_item->GetSize();
437   }
438 }
439 
CreateAnnotationItem(const DexFile & dex_file,const DexFile::AnnotationItem * annotation)440 AnnotationItem* Collections::CreateAnnotationItem(const DexFile& dex_file,
441                                                   const DexFile::AnnotationItem* annotation) {
442   const uint8_t* const start_data = reinterpret_cast<const uint8_t*>(annotation);
443   const uint32_t offset = start_data - dex_file.DataBegin();
444   AnnotationItem* annotation_item = annotation_items_map_.GetExistingObject(offset);
445   if (annotation_item == nullptr) {
446     uint8_t visibility = annotation->visibility_;
447     const uint8_t* annotation_data = annotation->annotation_;
448     std::unique_ptr<EncodedValue> encoded_value(
449         ReadEncodedValue(dex_file, &annotation_data, DexFile::kDexAnnotationAnnotation, 0));
450     annotation_item = new AnnotationItem(visibility, encoded_value->ReleaseEncodedAnnotation());
451     annotation_item->SetSize(annotation_data - start_data);
452     AddItem(annotation_items_map_, annotation_items_, annotation_item, offset);
453   }
454   return annotation_item;
455 }
456 
457 
CreateAnnotationSetItem(const DexFile & dex_file,const DexFile::AnnotationSetItem * disk_annotations_item,uint32_t offset)458 AnnotationSetItem* Collections::CreateAnnotationSetItem(const DexFile& dex_file,
459     const DexFile::AnnotationSetItem* disk_annotations_item, uint32_t offset) {
460   if (disk_annotations_item == nullptr || (disk_annotations_item->size_ == 0 && offset == 0)) {
461     return nullptr;
462   }
463   AnnotationSetItem* annotation_set_item = annotation_set_items_map_.GetExistingObject(offset);
464   if (annotation_set_item == nullptr) {
465     std::vector<AnnotationItem*>* items = new std::vector<AnnotationItem*>();
466     for (uint32_t i = 0; i < disk_annotations_item->size_; ++i) {
467       const DexFile::AnnotationItem* annotation =
468           dex_file.GetAnnotationItem(disk_annotations_item, i);
469       if (annotation == nullptr) {
470         continue;
471       }
472       AnnotationItem* annotation_item = CreateAnnotationItem(dex_file, annotation);
473       items->push_back(annotation_item);
474     }
475     annotation_set_item = new AnnotationSetItem(items);
476     AddItem(annotation_set_items_map_, annotation_set_items_, annotation_set_item, offset);
477   }
478   return annotation_set_item;
479 }
480 
CreateAnnotationsDirectoryItem(const DexFile & dex_file,const DexFile::AnnotationsDirectoryItem * disk_annotations_item,uint32_t offset)481 AnnotationsDirectoryItem* Collections::CreateAnnotationsDirectoryItem(const DexFile& dex_file,
482     const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset) {
483   AnnotationsDirectoryItem* annotations_directory_item =
484       annotations_directory_items_map_.GetExistingObject(offset);
485   if (annotations_directory_item != nullptr) {
486     return annotations_directory_item;
487   }
488   const DexFile::AnnotationSetItem* class_set_item =
489       dex_file.GetClassAnnotationSet(disk_annotations_item);
490   AnnotationSetItem* class_annotation = nullptr;
491   if (class_set_item != nullptr) {
492     uint32_t item_offset = disk_annotations_item->class_annotations_off_;
493     class_annotation = CreateAnnotationSetItem(dex_file, class_set_item, item_offset);
494   }
495   const DexFile::FieldAnnotationsItem* fields =
496       dex_file.GetFieldAnnotations(disk_annotations_item);
497   FieldAnnotationVector* field_annotations = nullptr;
498   if (fields != nullptr) {
499     field_annotations = new FieldAnnotationVector();
500     for (uint32_t i = 0; i < disk_annotations_item->fields_size_; ++i) {
501       FieldId* field_id = GetFieldId(fields[i].field_idx_);
502       const DexFile::AnnotationSetItem* field_set_item =
503           dex_file.GetFieldAnnotationSetItem(fields[i]);
504       uint32_t annotation_set_offset = fields[i].annotations_off_;
505       AnnotationSetItem* annotation_set_item =
506           CreateAnnotationSetItem(dex_file, field_set_item, annotation_set_offset);
507       field_annotations->push_back(std::unique_ptr<FieldAnnotation>(
508           new FieldAnnotation(field_id, annotation_set_item)));
509     }
510   }
511   const DexFile::MethodAnnotationsItem* methods =
512       dex_file.GetMethodAnnotations(disk_annotations_item);
513   MethodAnnotationVector* method_annotations = nullptr;
514   if (methods != nullptr) {
515     method_annotations = new MethodAnnotationVector();
516     for (uint32_t i = 0; i < disk_annotations_item->methods_size_; ++i) {
517       MethodId* method_id = GetMethodId(methods[i].method_idx_);
518       const DexFile::AnnotationSetItem* method_set_item =
519           dex_file.GetMethodAnnotationSetItem(methods[i]);
520       uint32_t annotation_set_offset = methods[i].annotations_off_;
521       AnnotationSetItem* annotation_set_item =
522           CreateAnnotationSetItem(dex_file, method_set_item, annotation_set_offset);
523       method_annotations->push_back(std::unique_ptr<MethodAnnotation>(
524           new MethodAnnotation(method_id, annotation_set_item)));
525     }
526   }
527   const DexFile::ParameterAnnotationsItem* parameters =
528       dex_file.GetParameterAnnotations(disk_annotations_item);
529   ParameterAnnotationVector* parameter_annotations = nullptr;
530   if (parameters != nullptr) {
531     parameter_annotations = new ParameterAnnotationVector();
532     for (uint32_t i = 0; i < disk_annotations_item->parameters_size_; ++i) {
533       MethodId* method_id = GetMethodId(parameters[i].method_idx_);
534       const DexFile::AnnotationSetRefList* list =
535           dex_file.GetParameterAnnotationSetRefList(&parameters[i]);
536       parameter_annotations->push_back(std::unique_ptr<ParameterAnnotation>(
537           GenerateParameterAnnotation(dex_file, method_id, list, parameters[i].annotations_off_)));
538     }
539   }
540   // TODO: Calculate the size of the annotations directory.
541 annotations_directory_item = new AnnotationsDirectoryItem(
542       class_annotation, field_annotations, method_annotations, parameter_annotations);
543   AddItem(annotations_directory_items_map_,
544           annotations_directory_items_,
545           annotations_directory_item,
546           offset);
547   return annotations_directory_item;
548 }
549 
GenerateParameterAnnotation(const DexFile & dex_file,MethodId * method_id,const DexFile::AnnotationSetRefList * annotation_set_ref_list,uint32_t offset)550 ParameterAnnotation* Collections::GenerateParameterAnnotation(
551     const DexFile& dex_file, MethodId* method_id,
552     const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset) {
553   AnnotationSetRefList* set_ref_list = annotation_set_ref_lists_map_.GetExistingObject(offset);
554   if (set_ref_list == nullptr) {
555     std::vector<AnnotationSetItem*>* annotations = new std::vector<AnnotationSetItem*>();
556     for (uint32_t i = 0; i < annotation_set_ref_list->size_; ++i) {
557       const DexFile::AnnotationSetItem* annotation_set_item =
558           dex_file.GetSetRefItemItem(&annotation_set_ref_list->list_[i]);
559       uint32_t set_offset = annotation_set_ref_list->list_[i].annotations_off_;
560       annotations->push_back(CreateAnnotationSetItem(dex_file, annotation_set_item, set_offset));
561     }
562     set_ref_list = new AnnotationSetRefList(annotations);
563     AddItem(annotation_set_ref_lists_map_, annotation_set_ref_lists_, set_ref_list, offset);
564   }
565   return new ParameterAnnotation(method_id, set_ref_list);
566 }
567 
DedupeOrCreateCodeItem(const DexFile & dex_file,const DexFile::CodeItem * disk_code_item,uint32_t offset,uint32_t dex_method_index)568 CodeItem* Collections::DedupeOrCreateCodeItem(const DexFile& dex_file,
569                                               const DexFile::CodeItem* disk_code_item,
570                                               uint32_t offset,
571                                               uint32_t dex_method_index) {
572   if (disk_code_item == nullptr) {
573     return nullptr;
574   }
575   CodeItemDebugInfoAccessor accessor(dex_file, disk_code_item, dex_method_index);
576   const uint32_t debug_info_offset = accessor.DebugInfoOffset();
577 
578   // Create the offsets pair and dedupe based on it.
579   std::pair<uint32_t, uint32_t> offsets_pair(offset, debug_info_offset);
580   auto existing = code_items_map_.find(offsets_pair);
581   if (existing != code_items_map_.end()) {
582     return existing->second;
583   }
584 
585   const uint8_t* debug_info_stream = dex_file.GetDebugInfoStream(debug_info_offset);
586   DebugInfoItem* debug_info = nullptr;
587   if (debug_info_stream != nullptr) {
588     debug_info = debug_info_items_map_.GetExistingObject(debug_info_offset);
589     if (debug_info == nullptr) {
590       uint32_t debug_info_size = GetDebugInfoStreamSize(debug_info_stream);
591       uint8_t* debug_info_buffer = new uint8_t[debug_info_size];
592       memcpy(debug_info_buffer, debug_info_stream, debug_info_size);
593       debug_info = new DebugInfoItem(debug_info_size, debug_info_buffer);
594       AddItem(debug_info_items_map_, debug_info_items_, debug_info, debug_info_offset);
595     }
596   }
597 
598   uint32_t insns_size = accessor.InsnsSizeInCodeUnits();
599   uint16_t* insns = new uint16_t[insns_size];
600   memcpy(insns, accessor.Insns(), insns_size * sizeof(uint16_t));
601 
602   TryItemVector* tries = nullptr;
603   CatchHandlerVector* handler_list = nullptr;
604   if (accessor.TriesSize() > 0) {
605     tries = new TryItemVector();
606     handler_list = new CatchHandlerVector();
607     for (const DexFile::TryItem& disk_try_item : accessor.TryItems()) {
608       uint32_t start_addr = disk_try_item.start_addr_;
609       uint16_t insn_count = disk_try_item.insn_count_;
610       uint16_t handler_off = disk_try_item.handler_off_;
611       const CatchHandler* handlers = nullptr;
612       for (std::unique_ptr<const CatchHandler>& existing_handlers : *handler_list) {
613         if (handler_off == existing_handlers->GetListOffset()) {
614           handlers = existing_handlers.get();
615           break;
616         }
617       }
618       if (handlers == nullptr) {
619         bool catch_all = false;
620         TypeAddrPairVector* addr_pairs = new TypeAddrPairVector();
621         for (CatchHandlerIterator it(accessor, disk_try_item); it.HasNext(); it.Next()) {
622           const dex::TypeIndex type_index = it.GetHandlerTypeIndex();
623           const TypeId* type_id = GetTypeIdOrNullPtr(type_index.index_);
624           catch_all |= type_id == nullptr;
625           addr_pairs->push_back(std::unique_ptr<const TypeAddrPair>(
626               new TypeAddrPair(type_id, it.GetHandlerAddress())));
627         }
628         handlers = new CatchHandler(catch_all, handler_off, addr_pairs);
629         handler_list->push_back(std::unique_ptr<const CatchHandler>(handlers));
630       }
631       TryItem* try_item = new TryItem(start_addr, insn_count, handlers);
632       tries->push_back(std::unique_ptr<const TryItem>(try_item));
633     }
634     // Manually walk catch handlers list and add any missing handlers unreferenced by try items.
635     const uint8_t* handlers_base = accessor.GetCatchHandlerData();
636     const uint8_t* handlers_data = handlers_base;
637     uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_data);
638     while (handlers_size > handler_list->size()) {
639       bool already_added = false;
640       uint16_t handler_off = handlers_data - handlers_base;
641       for (std::unique_ptr<const CatchHandler>& existing_handlers : *handler_list) {
642         if (handler_off == existing_handlers->GetListOffset()) {
643           already_added = true;
644           break;
645         }
646       }
647       int32_t size = DecodeSignedLeb128(&handlers_data);
648       bool has_catch_all = size <= 0;
649       if (has_catch_all) {
650         size = -size;
651       }
652       if (already_added) {
653         for (int32_t i = 0; i < size; i++) {
654           DecodeUnsignedLeb128(&handlers_data);
655           DecodeUnsignedLeb128(&handlers_data);
656         }
657         if (has_catch_all) {
658           DecodeUnsignedLeb128(&handlers_data);
659         }
660         continue;
661       }
662       TypeAddrPairVector* addr_pairs = new TypeAddrPairVector();
663       for (int32_t i = 0; i < size; i++) {
664         const TypeId* type_id = GetTypeIdOrNullPtr(DecodeUnsignedLeb128(&handlers_data));
665         uint32_t addr = DecodeUnsignedLeb128(&handlers_data);
666         addr_pairs->push_back(
667             std::unique_ptr<const TypeAddrPair>(new TypeAddrPair(type_id, addr)));
668       }
669       if (has_catch_all) {
670         uint32_t addr = DecodeUnsignedLeb128(&handlers_data);
671         addr_pairs->push_back(
672             std::unique_ptr<const TypeAddrPair>(new TypeAddrPair(nullptr, addr)));
673       }
674       const CatchHandler* handler = new CatchHandler(has_catch_all, handler_off, addr_pairs);
675       handler_list->push_back(std::unique_ptr<const CatchHandler>(handler));
676     }
677   }
678 
679   uint32_t size = dex_file.GetCodeItemSize(*disk_code_item);
680   CodeItem* code_item = new CodeItem(accessor.RegistersSize(),
681                                      accessor.InsSize(),
682                                      accessor.OutsSize(),
683                                      debug_info,
684                                      insns_size,
685                                      insns,
686                                      tries,
687                                      handler_list);
688   code_item->SetSize(size);
689 
690   // Add the code item to the map.
691   DCHECK(!code_item->OffsetAssigned());
692   if (eagerly_assign_offsets_) {
693     code_item->SetOffset(offset);
694   }
695   code_items_map_.emplace(offsets_pair, code_item);
696   code_items_.AddItem(code_item);
697 
698   // Add "fixup" references to types, strings, methods, and fields.
699   // This is temporary, as we will probably want more detailed parsing of the
700   // instructions here.
701   std::vector<TypeId*> type_ids;
702   std::vector<StringId*> string_ids;
703   std::vector<MethodId*> method_ids;
704   std::vector<FieldId*> field_ids;
705   if (GetIdsFromByteCode(*this,
706                          code_item,
707                          /*out*/ &type_ids,
708                          /*out*/ &string_ids,
709                          /*out*/ &method_ids,
710                          /*out*/ &field_ids)) {
711     CodeFixups* fixups = new CodeFixups(std::move(type_ids),
712                                         std::move(string_ids),
713                                         std::move(method_ids),
714                                         std::move(field_ids));
715     code_item->SetCodeFixups(fixups);
716   }
717 
718   return code_item;
719 }
720 
GenerateMethodItem(const DexFile & dex_file,ClassDataItemIterator & cdii)721 MethodItem* Collections::GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii) {
722   MethodId* method_id = GetMethodId(cdii.GetMemberIndex());
723   uint32_t access_flags = cdii.GetRawMemberAccessFlags();
724   const DexFile::CodeItem* disk_code_item = cdii.GetMethodCodeItem();
725   // Temporary hack to prevent incorrectly deduping code items if they have the same offset since
726   // they may have different debug info streams.
727   CodeItem* code_item = DedupeOrCreateCodeItem(dex_file,
728                                                disk_code_item,
729                                                cdii.GetMethodCodeItemOffset(),
730                                                cdii.GetMemberIndex());
731   return new MethodItem(access_flags, method_id, code_item);
732 }
733 
CreateClassData(const DexFile & dex_file,const uint8_t * encoded_data,uint32_t offset)734 ClassData* Collections::CreateClassData(
735     const DexFile& dex_file, const uint8_t* encoded_data, uint32_t offset) {
736   // Read the fields and methods defined by the class, resolving the circular reference from those
737   // to classes by setting class at the same time.
738   ClassData* class_data = class_datas_map_.GetExistingObject(offset);
739   if (class_data == nullptr && encoded_data != nullptr) {
740     ClassDataItemIterator cdii(dex_file, encoded_data);
741     // Static fields.
742     FieldItemVector* static_fields = new FieldItemVector();
743     for (; cdii.HasNextStaticField(); cdii.Next()) {
744       FieldId* field_item = GetFieldId(cdii.GetMemberIndex());
745       uint32_t access_flags = cdii.GetRawMemberAccessFlags();
746       static_fields->push_back(std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item)));
747     }
748     // Instance fields.
749     FieldItemVector* instance_fields = new FieldItemVector();
750     for (; cdii.HasNextInstanceField(); cdii.Next()) {
751       FieldId* field_item = GetFieldId(cdii.GetMemberIndex());
752       uint32_t access_flags = cdii.GetRawMemberAccessFlags();
753       instance_fields->push_back(
754           std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item)));
755     }
756     // Direct methods.
757     MethodItemVector* direct_methods = new MethodItemVector();
758     for (; cdii.HasNextDirectMethod(); cdii.Next()) {
759       direct_methods->push_back(std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, cdii)));
760     }
761     // Virtual methods.
762     MethodItemVector* virtual_methods = new MethodItemVector();
763     for (; cdii.HasNextVirtualMethod(); cdii.Next()) {
764       virtual_methods->push_back(std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, cdii)));
765     }
766     class_data = new ClassData(static_fields, instance_fields, direct_methods, virtual_methods);
767     class_data->SetSize(cdii.EndDataPointer() - encoded_data);
768     AddItem(class_datas_map_, class_datas_, class_data, offset);
769   }
770   return class_data;
771 }
772 
CreateCallSitesAndMethodHandles(const DexFile & dex_file)773 void Collections::CreateCallSitesAndMethodHandles(const DexFile& dex_file) {
774   // Iterate through the map list and set the offset of the CallSiteIds and MethodHandleItems.
775   const DexFile::MapList* map = dex_file.GetMapList();
776   for (uint32_t i = 0; i < map->size_; ++i) {
777     const DexFile::MapItem* item = map->list_ + i;
778     switch (item->type_) {
779       case DexFile::kDexTypeCallSiteIdItem:
780         SetCallSiteIdsOffset(item->offset_);
781         break;
782       case DexFile::kDexTypeMethodHandleItem:
783         SetMethodHandleItemsOffset(item->offset_);
784         break;
785       default:
786         break;
787     }
788   }
789   // Populate MethodHandleItems first (CallSiteIds may depend on them).
790   for (uint32_t i = 0; i < dex_file.NumMethodHandles(); i++) {
791     CreateMethodHandleItem(dex_file, i);
792   }
793   // Populate CallSiteIds.
794   for (uint32_t i = 0; i < dex_file.NumCallSiteIds(); i++) {
795     CreateCallSiteId(dex_file, i);
796   }
797 }
798 
CreateCallSiteId(const DexFile & dex_file,uint32_t i)799 void Collections::CreateCallSiteId(const DexFile& dex_file, uint32_t i) {
800   const DexFile::CallSiteIdItem& disk_call_site_id = dex_file.GetCallSiteId(i);
801   const uint8_t* disk_call_item_ptr = dex_file.DataBegin() + disk_call_site_id.data_off_;
802   EncodedArrayItem* call_site_item =
803       CreateEncodedArrayItem(dex_file, disk_call_item_ptr, disk_call_site_id.data_off_);
804 
805   CallSiteId* call_site_id = new CallSiteId(call_site_item);
806   AddIndexedItem(call_site_ids_, call_site_id, CallSiteIdsOffset() + i * CallSiteId::ItemSize(), i);
807 }
808 
CreateMethodHandleItem(const DexFile & dex_file,uint32_t i)809 void Collections::CreateMethodHandleItem(const DexFile& dex_file, uint32_t i) {
810   const DexFile::MethodHandleItem& disk_method_handle = dex_file.GetMethodHandle(i);
811   uint16_t index = disk_method_handle.field_or_method_idx_;
812   DexFile::MethodHandleType type =
813       static_cast<DexFile::MethodHandleType>(disk_method_handle.method_handle_type_);
814   bool is_invoke = type == DexFile::MethodHandleType::kInvokeStatic ||
815                    type == DexFile::MethodHandleType::kInvokeInstance ||
816                    type == DexFile::MethodHandleType::kInvokeConstructor ||
817                    type == DexFile::MethodHandleType::kInvokeDirect ||
818                    type == DexFile::MethodHandleType::kInvokeInterface;
819   static_assert(DexFile::MethodHandleType::kLast == DexFile::MethodHandleType::kInvokeInterface,
820                 "Unexpected method handle types.");
821   IndexedItem* field_or_method_id;
822   if (is_invoke) {
823     field_or_method_id = GetMethodId(index);
824   } else {
825     field_or_method_id = GetFieldId(index);
826   }
827   MethodHandleItem* method_handle = new MethodHandleItem(type, field_or_method_id);
828   AddIndexedItem(method_handle_items_,
829                  method_handle,
830                  MethodHandleItemsOffset() + i * MethodHandleItem::ItemSize(),
831                  i);
832 }
833 
SortVectorsByMapOrder()834 void Collections::SortVectorsByMapOrder() {
835   string_datas_.SortByMapOrder(string_datas_map_.Collection());
836   type_lists_.SortByMapOrder(type_lists_map_.Collection());
837   encoded_array_items_.SortByMapOrder(encoded_array_items_map_.Collection());
838   annotation_items_.SortByMapOrder(annotation_items_map_.Collection());
839   annotation_set_items_.SortByMapOrder(annotation_set_items_map_.Collection());
840   annotation_set_ref_lists_.SortByMapOrder(annotation_set_ref_lists_map_.Collection());
841   annotations_directory_items_.SortByMapOrder(annotations_directory_items_map_.Collection());
842   debug_info_items_.SortByMapOrder(debug_info_items_map_.Collection());
843   code_items_.SortByMapOrder(code_items_map_);
844   class_datas_.SortByMapOrder(class_datas_map_.Collection());
845 }
846 
HeaderOffset(const dex_ir::Collections & collections ATTRIBUTE_UNUSED)847 static uint32_t HeaderOffset(const dex_ir::Collections& collections ATTRIBUTE_UNUSED) {
848   return 0;
849 }
850 
HeaderSize(const dex_ir::Collections & collections ATTRIBUTE_UNUSED)851 static uint32_t HeaderSize(const dex_ir::Collections& collections ATTRIBUTE_UNUSED) {
852   // Size is in elements, so there is only one header.
853   return 1;
854 }
855 
856 // The description of each dex file section type.
857 struct FileSectionDescriptor {
858  public:
859   std::string name;
860   uint16_t type;
861   // A function that when applied to a collection object, gives the size of the section.
862   std::function<uint32_t(const dex_ir::Collections&)> size_fn;
863   // A function that when applied to a collection object, gives the offset of the section.
864   std::function<uint32_t(const dex_ir::Collections&)> offset_fn;
865 };
866 
867 static const FileSectionDescriptor kFileSectionDescriptors[] = {
868   {
869     "Header",
870     DexFile::kDexTypeHeaderItem,
871     &HeaderSize,
872     &HeaderOffset,
873   }, {
874     "StringId",
875     DexFile::kDexTypeStringIdItem,
876     &dex_ir::Collections::StringIdsSize,
877     &dex_ir::Collections::StringIdsOffset
878   }, {
879     "TypeId",
880     DexFile::kDexTypeTypeIdItem,
881     &dex_ir::Collections::TypeIdsSize,
882     &dex_ir::Collections::TypeIdsOffset
883   }, {
884     "ProtoId",
885     DexFile::kDexTypeProtoIdItem,
886     &dex_ir::Collections::ProtoIdsSize,
887     &dex_ir::Collections::ProtoIdsOffset
888   }, {
889     "FieldId",
890     DexFile::kDexTypeFieldIdItem,
891     &dex_ir::Collections::FieldIdsSize,
892     &dex_ir::Collections::FieldIdsOffset
893   }, {
894     "MethodId",
895     DexFile::kDexTypeMethodIdItem,
896     &dex_ir::Collections::MethodIdsSize,
897     &dex_ir::Collections::MethodIdsOffset
898   }, {
899     "ClassDef",
900     DexFile::kDexTypeClassDefItem,
901     &dex_ir::Collections::ClassDefsSize,
902     &dex_ir::Collections::ClassDefsOffset
903   }, {
904     "CallSiteId",
905     DexFile::kDexTypeCallSiteIdItem,
906     &dex_ir::Collections::CallSiteIdsSize,
907     &dex_ir::Collections::CallSiteIdsOffset
908   }, {
909     "MethodHandle",
910     DexFile::kDexTypeMethodHandleItem,
911     &dex_ir::Collections::MethodHandleItemsSize,
912     &dex_ir::Collections::MethodHandleItemsOffset
913   }, {
914     "StringData",
915     DexFile::kDexTypeStringDataItem,
916     &dex_ir::Collections::StringDatasSize,
917     &dex_ir::Collections::StringDatasOffset
918   }, {
919     "TypeList",
920     DexFile::kDexTypeTypeList,
921     &dex_ir::Collections::TypeListsSize,
922     &dex_ir::Collections::TypeListsOffset
923   }, {
924     "EncArr",
925     DexFile::kDexTypeEncodedArrayItem,
926     &dex_ir::Collections::EncodedArrayItemsSize,
927     &dex_ir::Collections::EncodedArrayItemsOffset
928   }, {
929     "Annotation",
930     DexFile::kDexTypeAnnotationItem,
931     &dex_ir::Collections::AnnotationItemsSize,
932     &dex_ir::Collections::AnnotationItemsOffset
933   }, {
934     "AnnoSet",
935     DexFile::kDexTypeAnnotationSetItem,
936     &dex_ir::Collections::AnnotationSetItemsSize,
937     &dex_ir::Collections::AnnotationSetItemsOffset
938   }, {
939     "AnnoSetRL",
940     DexFile::kDexTypeAnnotationSetRefList,
941     &dex_ir::Collections::AnnotationSetRefListsSize,
942     &dex_ir::Collections::AnnotationSetRefListsOffset
943   }, {
944     "AnnoDir",
945     DexFile::kDexTypeAnnotationsDirectoryItem,
946     &dex_ir::Collections::AnnotationsDirectoryItemsSize,
947     &dex_ir::Collections::AnnotationsDirectoryItemsOffset
948   }, {
949     "DebugInfo",
950     DexFile::kDexTypeDebugInfoItem,
951     &dex_ir::Collections::DebugInfoItemsSize,
952     &dex_ir::Collections::DebugInfoItemsOffset
953   }, {
954     "CodeItem",
955     DexFile::kDexTypeCodeItem,
956     &dex_ir::Collections::CodeItemsSize,
957     &dex_ir::Collections::CodeItemsOffset
958   }, {
959     "ClassData",
960     DexFile::kDexTypeClassDataItem,
961     &dex_ir::Collections::ClassDatasSize,
962     &dex_ir::Collections::ClassDatasOffset
963   }
964 };
965 
GetSortedDexFileSections(dex_ir::Header * header,dex_ir::SortDirection direction)966 std::vector<dex_ir::DexFileSection> GetSortedDexFileSections(dex_ir::Header* header,
967                                                              dex_ir::SortDirection direction) {
968   const dex_ir::Collections& collections = header->GetCollections();
969   std::vector<dex_ir::DexFileSection> sorted_sections;
970   // Build the table that will map from offset to color
971   for (const FileSectionDescriptor& s : kFileSectionDescriptors) {
972     sorted_sections.push_back(dex_ir::DexFileSection(s.name,
973                                                      s.type,
974                                                      s.size_fn(collections),
975                                                      s.offset_fn(collections)));
976   }
977   // Sort by offset.
978   std::sort(sorted_sections.begin(),
979             sorted_sections.end(),
980             [=](dex_ir::DexFileSection& a, dex_ir::DexFileSection& b) {
981               if (direction == SortDirection::kSortDescending) {
982                 return a.offset > b.offset;
983               } else {
984                 return a.offset < b.offset;
985               }
986             });
987   return sorted_sections;
988 }
989 
990 }  // namespace dex_ir
991 }  // namespace art
992