1 /**
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <cstddef>
17 #include <cstdint>
18
19 #include "annotation_data_accessor.h"
20 #include "bytecode_instruction.h"
21 #include "code_data_accessor.h"
22 #include "field_data_accessor.h"
23 #include "file.h"
24 #include "debug_info_updater-inl.h"
25 #include "file_items.h"
26 #include "libpandafile/file_reader.h"
27 #include "libpandafile/bytecode_instruction-inl.h"
28 #include "libpandafile/line_number_program.h"
29 #include "libpandafile/literal_data_accessor-inl.h"
30 #include "libpandafile/class_data_accessor-inl.h"
31 #include "libpandafile/proto_data_accessor-inl.h"
32 #include "libpandafile/code_data_accessor-inl.h"
33 #include "libpandafile/debug_data_accessor-inl.h"
34 #include "libpandafile/field_data_accessor-inl.h"
35 #include "libpandafile/method_data_accessor-inl.h"
36
37 #include "libpandabase/utils/utf.h"
38 #include "proto_data_accessor.h"
39
40 namespace ark::panda_file {
41
42 namespace {
43 class FileReaderDebugInfoUpdater : public DebugInfoUpdater<FileReaderDebugInfoUpdater> {
44 public:
45 using Super = DebugInfoUpdater<FileReaderDebugInfoUpdater>;
46
FileReaderDebugInfoUpdater(const File * file,ItemContainer * cont)47 FileReaderDebugInfoUpdater(const File *file, ItemContainer *cont) : Super(file), cont_(cont) {}
48
GetOrCreateStringItem(const std::string & s)49 StringItem *GetOrCreateStringItem(const std::string &s)
50 {
51 return cont_->GetOrCreateStringItem(s);
52 }
53
GetType(File::EntityId typeId,const std::string & typeName)54 BaseClassItem *GetType(File::EntityId typeId, const std::string &typeName)
55 {
56 if (GetFile()->IsExternal(typeId)) {
57 return cont_->GetOrCreateForeignClassItem(typeName);
58 }
59 return cont_->GetOrCreateClassItem(typeName);
60 }
61
62 private:
63 ItemContainer *cont_;
64 };
65 } // namespace
66
ReadContainer(bool shouldRebuildIndices)67 bool FileReader::ReadContainer(bool shouldRebuildIndices)
68 {
69 const File::Header *header = file_->GetHeader();
70 LOG_IF(header->quickenedFlag, FATAL, PANDAFILE) << "File " << file_->GetFullFileName() << " is already quickened";
71
72 if (!ReadClasses()) {
73 return false;
74 }
75 if (!ReadLiteralArrayItems()) {
76 return false;
77 }
78 if (!ReadRegionHeaders()) {
79 return false;
80 }
81
82 if (shouldRebuildIndices) {
83 ComputeLayoutAndUpdateIndices();
84 }
85
86 return true;
87 }
88
89 template <typename T>
EmplaceLiteralArray(const panda_file::LiteralDataAccessor::LiteralValue & value,std::vector<panda_file::LiteralItem> & literalArray,std::unique_ptr<const File> & file)90 static void EmplaceLiteralArray(const panda_file::LiteralDataAccessor::LiteralValue &value,
91 std::vector<panda_file::LiteralItem> &literalArray, std::unique_ptr<const File> &file)
92 {
93 File::EntityId id(std::get<uint32_t>(value));
94 auto sp = file->GetSpanFromId(id);
95 auto len = helpers::Read<sizeof(uint32_t)>(&sp);
96 literalArray.emplace_back(len);
97 for (size_t i = 0; i < len; i++) {
98 auto v = helpers::Read<sizeof(T)>(&sp);
99 literalArray.emplace_back(v);
100 }
101 }
102
EmplaceLiteralString(const panda_file::LiteralDataAccessor::LiteralValue & value,std::vector<panda_file::LiteralItem> & literalArray,std::unique_ptr<const File> & file,ItemContainer & container)103 static void EmplaceLiteralString(const panda_file::LiteralDataAccessor::LiteralValue &value,
104 std::vector<panda_file::LiteralItem> &literalArray, std::unique_ptr<const File> &file,
105 ItemContainer &container)
106 {
107 File::EntityId id(std::get<uint32_t>(value));
108 auto data = file->GetStringData(id);
109 std::string itemStr(utf::Mutf8AsCString(data.data));
110 auto *stringItem = container.GetOrCreateStringItem(itemStr);
111 literalArray.emplace_back(stringItem);
112 }
113
EmplaceLiteralArrayString(const panda_file::LiteralDataAccessor::LiteralValue & value,std::vector<panda_file::LiteralItem> & literalArray,std::unique_ptr<const File> & file,ItemContainer & container)114 static void EmplaceLiteralArrayString(const panda_file::LiteralDataAccessor::LiteralValue &value,
115 std::vector<panda_file::LiteralItem> &literalArray,
116 std::unique_ptr<const File> &file, ItemContainer &container)
117 {
118 File::EntityId id(std::get<uint32_t>(value));
119 auto sp = file->GetSpanFromId(id);
120 auto len = helpers::Read<sizeof(uint32_t)>(&sp);
121 literalArray.emplace_back(len);
122 for (size_t i = 0; i < len; i++) {
123 File::EntityId strId(helpers::Read<sizeof(uint32_t)>(&sp));
124 auto data = file->GetStringData(strId);
125 std::string itemStr(utf::Mutf8AsCString(data.data));
126 auto *stringItem = container.GetOrCreateStringItem(itemStr);
127 literalArray.emplace_back(stringItem);
128 }
129 }
130
EmplaceLiteralVals(std::vector<panda_file::LiteralItem> & literalArray,const panda_file::LiteralDataAccessor::LiteralValue & value,const panda_file::LiteralTag & tag)131 void FileReader::EmplaceLiteralVals(std::vector<panda_file::LiteralItem> &literalArray,
132 const panda_file::LiteralDataAccessor::LiteralValue &value,
133 const panda_file::LiteralTag &tag)
134 {
135 literalArray.emplace_back(static_cast<uint8_t>(tag));
136 switch (tag) {
137 case panda_file::LiteralTag::BOOL: {
138 literalArray.emplace_back(static_cast<uint8_t>(std::get<bool>(value)));
139 break;
140 }
141 case panda_file::LiteralTag::TAGVALUE:
142 case panda_file::LiteralTag::ACCESSOR:
143 case panda_file::LiteralTag::NULLVALUE: {
144 literalArray.emplace_back(std::get<uint8_t>(value));
145 break;
146 }
147 case panda_file::LiteralTag::ARRAY_U1:
148 case panda_file::LiteralTag::ARRAY_I8:
149 case panda_file::LiteralTag::ARRAY_U8: {
150 EmplaceLiteralArray<uint8_t>(value, literalArray, file_);
151 break;
152 }
153 case panda_file::LiteralTag::ARRAY_I16:
154 case panda_file::LiteralTag::ARRAY_U16: {
155 EmplaceLiteralArray<uint16_t>(value, literalArray, file_);
156 break;
157 }
158 case panda_file::LiteralTag::INTEGER: {
159 literalArray.emplace_back(std::get<uint32_t>(value));
160 break;
161 }
162 case panda_file::LiteralTag::ARRAY_I32:
163 case panda_file::LiteralTag::ARRAY_U32:
164 case panda_file::LiteralTag::ARRAY_F32: {
165 EmplaceLiteralArray<uint32_t>(value, literalArray, file_);
166 break;
167 }
168 case panda_file::LiteralTag::ARRAY_I64:
169 case panda_file::LiteralTag::ARRAY_U64:
170 case panda_file::LiteralTag::ARRAY_F64: {
171 EmplaceLiteralArray<uint64_t>(value, literalArray, file_);
172 break;
173 }
174 case panda_file::LiteralTag::FLOAT: {
175 literalArray.emplace_back(bit_cast<uint32_t>(std::get<float>(value)));
176 break;
177 }
178 case panda_file::LiteralTag::DOUBLE: {
179 literalArray.emplace_back(bit_cast<uint64_t>(std::get<double>(value)));
180 break;
181 }
182 case panda_file::LiteralTag::STRING: {
183 EmplaceLiteralString(value, literalArray, file_, container_);
184 break;
185 }
186 case panda_file::LiteralTag::ARRAY_STRING: {
187 EmplaceLiteralArrayString(value, literalArray, file_, container_);
188 break;
189 }
190 case panda_file::LiteralTag::METHOD:
191 case panda_file::LiteralTag::GENERATORMETHOD:
192 case panda_file::LiteralTag::ASYNCMETHOD:
193 case panda_file::LiteralTag::ASYNCGENERATORMETHOD: {
194 File::EntityId methodId(std::get<uint32_t>(value));
195 MethodDataAccessor methodAcc(*file_, methodId);
196 File::EntityId classId(methodAcc.GetClassId());
197 auto *classItem = CreateClassItem(classId);
198 literalArray.emplace_back(CreateMethodItem(classItem, methodId));
199 break;
200 }
201 default:
202 UNREACHABLE();
203 }
204 }
205
206 /* static */
CreateLiteralArrayItem(LiteralDataAccessor * litArrayAccessor,File::EntityId arrayId,uint32_t index)207 bool FileReader::CreateLiteralArrayItem(LiteralDataAccessor *litArrayAccessor, File::EntityId arrayId, uint32_t index)
208 {
209 auto it = itemsDone_.find(arrayId);
210 if (it != itemsDone_.end()) {
211 return true;
212 }
213
214 LiteralArrayItem *item = container_.GetOrCreateLiteralArrayItem(std::to_string(index));
215 itemsDone_.insert({arrayId, static_cast<BaseItem *>(item)});
216
217 std::vector<panda_file::LiteralItem> literalArray;
218
219 litArrayAccessor->EnumerateLiteralVals(
220 arrayId, [&literalArray, this](const panda_file::LiteralDataAccessor::LiteralValue &value,
221 const panda_file::LiteralTag &tag) {
222 this->EmplaceLiteralVals(literalArray, value, tag);
223 });
224
225 item->AddItems(literalArray);
226
227 return true;
228 }
229
230 template <typename T>
GeneratePrimitiveItemLesserInt32(AnnotationDataAccessor::Elem & annElem,ItemContainer & container,ark::panda_file::Type::TypeId typeId)231 static ValueItem *GeneratePrimitiveItemLesserInt32(AnnotationDataAccessor::Elem &annElem, ItemContainer &container,
232 ark::panda_file::Type::TypeId typeId)
233 {
234 auto array = annElem.GetArrayValue();
235 std::vector<ScalarValueItem> items;
236 for (size_t j = 0; j < array.GetCount(); j++) {
237 ScalarValueItem scalar(static_cast<uint32_t>(array.Get<T>(j)));
238 items.emplace_back(std::move(scalar));
239 }
240 return static_cast<ValueItem *>(container.CreateItem<ArrayValueItem>(Type(typeId), std::move(items)));
241 }
242
243 template <typename T>
GeneratePrimitiveItem(AnnotationDataAccessor::Elem & annElem,ItemContainer & container,ark::panda_file::Type::TypeId typeId)244 static ValueItem *GeneratePrimitiveItem(AnnotationDataAccessor::Elem &annElem, ItemContainer &container,
245 ark::panda_file::Type::TypeId typeId)
246 {
247 auto array = annElem.GetArrayValue();
248 std::vector<ScalarValueItem> items;
249 for (size_t j = 0; j < array.GetCount(); j++) {
250 ScalarValueItem scalar(array.Get<T>(j));
251 items.emplace_back(std::move(scalar));
252 }
253 return static_cast<ValueItem *>(container.CreateItem<ArrayValueItem>(Type(typeId), std::move(items)));
254 }
255
256 // NOLINTNEXTLINE(readability-function-size)
SetElemValueItem(AnnotationDataAccessor::Tag & annTag,AnnotationDataAccessor::Elem & annElem)257 ValueItem *FileReader::SetElemValueItem(AnnotationDataAccessor::Tag &annTag, AnnotationDataAccessor::Elem &annElem)
258 {
259 switch (annTag.GetItem()) {
260 case '1':
261 case '2':
262 case '3': {
263 auto scalar = annElem.GetScalarValue();
264 return container_.GetOrCreateIntegerValueItem(scalar.Get<uint8_t>());
265 }
266 case '4':
267 case '5': {
268 auto scalar = annElem.GetScalarValue();
269 return container_.GetOrCreateIntegerValueItem(scalar.Get<uint16_t>());
270 }
271 case '6':
272 case '7': {
273 auto scalar = annElem.GetScalarValue();
274 return container_.GetOrCreateIntegerValueItem(scalar.Get<uint32_t>());
275 }
276 case '8':
277 case '9': {
278 auto scalar = annElem.GetScalarValue();
279 return container_.GetOrCreateLongValueItem(scalar.Get<uint64_t>());
280 }
281 case 'A': {
282 auto scalar = annElem.GetScalarValue();
283 return container_.GetOrCreateFloatValueItem(scalar.Get<float>());
284 }
285 case 'B': {
286 auto scalar = annElem.GetScalarValue();
287 return container_.GetOrCreateDoubleValueItem(scalar.Get<double>());
288 }
289 case 'C': {
290 auto scalar = annElem.GetScalarValue();
291 const File::EntityId strId(scalar.Get<uint32_t>());
292 auto data = file_->GetStringData(strId);
293 std::string itemStr(utf::Mutf8AsCString(data.data));
294 auto *strItem = container_.GetOrCreateStringItem(itemStr);
295 return container_.GetOrCreateIdValueItem(strItem);
296 }
297 case 'D': {
298 auto scalar = annElem.GetScalarValue();
299 const File::EntityId classId {scalar.Get<uint32_t>()};
300 return container_.GetOrCreateIdValueItem(CreateGenericClassItem(classId));
301 }
302 case 'E': {
303 auto scalar = annElem.GetScalarValue();
304 const File::EntityId methodId {scalar.Get<uint32_t>()};
305 MethodDataAccessor methodAcc(*file_, methodId);
306 auto *clsItem = CreateGenericClassItem(methodAcc.GetClassId());
307 return container_.GetOrCreateIdValueItem(CreateGenericMethodItem(clsItem, methodId));
308 }
309 case 'F': {
310 auto scalar = annElem.GetScalarValue();
311 const File::EntityId fieldId {scalar.Get<uint32_t>()};
312 FieldDataAccessor fieldAcc(*file_, fieldId);
313 auto *clsItem = CreateGenericClassItem(fieldAcc.GetClassId());
314 return container_.GetOrCreateIdValueItem(CreateGenericFieldItem(clsItem, fieldId));
315 }
316 case 'G': {
317 auto scalar = annElem.GetScalarValue();
318 const File::EntityId annItemId {scalar.Get<uint32_t>()};
319 return container_.GetOrCreateIdValueItem(CreateAnnotationItem(annItemId));
320 }
321 case 'J': {
322 LOG(FATAL, PANDAFILE) << "MethodHandle is not supported so far";
323 break;
324 }
325 case '*': {
326 return container_.GetOrCreateIntegerValueItem(0);
327 }
328 case 'K': {
329 return GeneratePrimitiveItemLesserInt32<uint8_t>(annElem, container_, Type::TypeId::U1);
330 }
331 case 'L': {
332 return GeneratePrimitiveItemLesserInt32<uint8_t>(annElem, container_, Type::TypeId::I8);
333 }
334 case 'M': {
335 return GeneratePrimitiveItemLesserInt32<uint8_t>(annElem, container_, Type::TypeId::U8);
336 }
337 case 'N': {
338 return GeneratePrimitiveItemLesserInt32<uint16_t>(annElem, container_, Type::TypeId::I16);
339 }
340 case 'O': {
341 return GeneratePrimitiveItemLesserInt32<uint16_t>(annElem, container_, Type::TypeId::U16);
342 }
343 case 'P': {
344 return GeneratePrimitiveItem<uint32_t>(annElem, container_, Type::TypeId::I32);
345 }
346 case 'Q': {
347 return GeneratePrimitiveItem<uint32_t>(annElem, container_, Type::TypeId::U32);
348 }
349 case 'R': {
350 return GeneratePrimitiveItem<uint64_t>(annElem, container_, Type::TypeId::I64);
351 }
352 case 'S': {
353 return GeneratePrimitiveItem<uint64_t>(annElem, container_, Type::TypeId::U64);
354 }
355 case 'T': {
356 return GeneratePrimitiveItem<float>(annElem, container_, Type::TypeId::F32);
357 }
358 case 'U': {
359 return GeneratePrimitiveItem<double>(annElem, container_, Type::TypeId::F64);
360 }
361 case 'V': {
362 auto array = annElem.GetArrayValue();
363 std::vector<ScalarValueItem> items;
364 for (size_t j = 0; j < array.GetCount(); j++) {
365 const File::EntityId strId(array.Get<uint32_t>(j));
366 auto data = file_->GetStringData(strId);
367 std::string itemStr(utf::Mutf8AsCString(data.data));
368 items.emplace_back(ScalarValueItem(container_.GetOrCreateStringItem(itemStr)));
369 }
370 return static_cast<ValueItem *>(
371 container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
372 }
373 case 'W': {
374 auto array = annElem.GetArrayValue();
375 std::vector<ScalarValueItem> items;
376 for (size_t j = 0; j < array.GetCount(); j++) {
377 const File::EntityId classId {array.Get<uint32_t>(j)};
378 BaseClassItem *clsItem = nullptr;
379 if (file_->IsExternal(classId)) {
380 clsItem = CreateForeignClassItem(classId);
381 } else {
382 clsItem = CreateClassItem(classId);
383 }
384 ASSERT(clsItem != nullptr);
385 items.emplace_back(ScalarValueItem(clsItem));
386 }
387 return static_cast<ValueItem *>(
388 container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
389 }
390 case 'X': {
391 auto array = annElem.GetArrayValue();
392 std::vector<ScalarValueItem> items;
393 for (size_t j = 0; j < array.GetCount(); j++) {
394 const File::EntityId methodId {array.Get<uint32_t>(j)};
395 MethodDataAccessor methodAcc(*file_, methodId);
396 auto *clsItem = CreateGenericClassItem(methodAcc.GetClassId());
397 items.emplace_back(ScalarValueItem(CreateGenericMethodItem(clsItem, methodId)));
398 }
399 return static_cast<ValueItem *>(
400 container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
401 }
402 case 'Y': {
403 auto array = annElem.GetArrayValue();
404 std::vector<ScalarValueItem> items;
405 for (size_t j = 0; j < array.GetCount(); j++) {
406 const File::EntityId fieldId {array.Get<uint32_t>(j)};
407 FieldDataAccessor fieldAcc(*file_, fieldId);
408 auto *clsItem = CreateGenericClassItem(fieldAcc.GetClassId());
409 items.emplace_back(ScalarValueItem(CreateGenericFieldItem(clsItem, fieldId)));
410 }
411 return static_cast<ValueItem *>(
412 container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
413 }
414 case 'H': {
415 // ARRAY can appear for empty arrays only
416 ASSERT(annElem.GetArrayValue().GetCount() == 0);
417 return static_cast<ValueItem *>(
418 container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::VOID), std::vector<ScalarValueItem>()));
419 }
420 case 'Z': {
421 auto array = annElem.GetArrayValue();
422 std::vector<ScalarValueItem> items;
423 for (size_t j = 0; j < array.GetCount(); j++) {
424 const File::EntityId annItemId {array.Get<uint32_t>(j)};
425 items.emplace_back(CreateAnnotationItem(annItemId));
426 }
427 return static_cast<ValueItem *>(
428 container_.CreateItem<ArrayValueItem>(Type(Type::TypeId::REFERENCE), std::move(items)));
429 }
430 case '@': {
431 // NOTE(nsizov): support it
432 LOG(FATAL, PANDAFILE) << "MethodHandle is not supported so far";
433 break;
434 }
435 // array
436 case 'I':
437 // VOID(I) and ARRAY(H) value should not appear
438 default:
439 UNREACHABLE();
440 }
441 return nullptr;
442 }
443
CreateAnnotationItem(File::EntityId annId)444 AnnotationItem *FileReader::CreateAnnotationItem(File::EntityId annId)
445 {
446 auto it = itemsDone_.find(annId);
447 if (it != itemsDone_.end()) {
448 return static_cast<AnnotationItem *>(it->second);
449 }
450
451 AnnotationDataAccessor annAcc(*file_, annId);
452 File::EntityId annClassId {annAcc.GetClassId()};
453 AnnotationItem *annItem = nullptr;
454
455 if (!file_->IsExternal(annClassId)) {
456 auto *annClassItem = CreateClassItem(annClassId);
457 annItem = container_.CreateItem<AnnotationItem>(annClassItem, std::vector<AnnotationItem::Elem>(),
458 std::vector<AnnotationItem::Tag>());
459 } else {
460 auto *annClassItem = CreateForeignClassItem(annClassId);
461 annItem = container_.CreateItem<AnnotationItem>(annClassItem, std::vector<AnnotationItem::Elem>(),
462 std::vector<AnnotationItem::Tag>());
463 }
464
465 ASSERT(annItem != nullptr);
466
467 itemsDone_.insert({annId, static_cast<BaseItem *>(annItem)});
468
469 std::vector<AnnotationItem::Elem> itemElements;
470 std::vector<AnnotationItem::Tag> tagElements;
471
472 for (size_t i = 0; i < annAcc.GetCount(); i++) {
473 AnnotationDataAccessor::Tag annTag = annAcc.GetTag(i);
474 AnnotationDataAccessor::Elem annElem = annAcc.GetElement(i);
475 ValueItem *elemValueItem = SetElemValueItem(annTag, annElem);
476
477 ASSERT(elemValueItem != nullptr);
478
479 tagElements.emplace_back(AnnotationItem::Tag(static_cast<char>(annTag.GetItem())));
480 File::EntityId nameId(annElem.GetNameId());
481 std::string annotNameStr(utf::Mutf8AsCString(file_->GetStringData(nameId).data));
482 auto elemNameItem = container_.GetOrCreateStringItem(annotNameStr);
483 itemElements.emplace_back(AnnotationItem::Elem(elemNameItem, elemValueItem));
484 }
485
486 annItem->SetElements(std::move(itemElements));
487 annItem->SetTags(std::move(tagElements));
488
489 return annItem;
490 }
491
CreateParamTypeItem(ProtoDataAccessor * protoAcc,size_t paramNum,size_t referenceNum)492 TypeItem *FileReader::CreateParamTypeItem(ProtoDataAccessor *protoAcc, size_t paramNum, size_t referenceNum)
493 {
494 Type paramType = protoAcc->GetArgType(paramNum);
495 TypeItem *paramTypeItem = nullptr;
496 if (paramType.IsPrimitive()) {
497 paramTypeItem = container_.GetOrCreatePrimitiveTypeItem(paramType);
498 } else {
499 const File::EntityId typeClsId = protoAcc->GetReferenceType(referenceNum);
500 if (file_->IsExternal(typeClsId)) {
501 paramTypeItem = CreateForeignClassItem(typeClsId);
502 } else {
503 paramTypeItem = CreateClassItem(typeClsId);
504 }
505 }
506
507 ASSERT(paramTypeItem != nullptr);
508
509 return paramTypeItem;
510 }
511
CreateMethodParamItems(ProtoDataAccessor * protoAcc,MethodDataAccessor * methodAcc,size_t referenceNum)512 std::vector<MethodParamItem> FileReader::CreateMethodParamItems(ProtoDataAccessor *protoAcc,
513 MethodDataAccessor *methodAcc, size_t referenceNum)
514 {
515 std::vector<MethodParamItem> paramItems;
516
517 for (size_t i = 0; i < protoAcc->GetNumArgs(); i++) {
518 TypeItem *paramTypeItem = CreateParamTypeItem(protoAcc, i, referenceNum);
519 if (paramTypeItem->GetType().IsReference()) {
520 referenceNum++;
521 }
522 paramItems.emplace_back(MethodParamItem(paramTypeItem));
523 }
524
525 auto paramAnnId = methodAcc->GetParamAnnotationId();
526 if (paramAnnId) {
527 ParamAnnotationsDataAccessor paramAcc(*file_, paramAnnId.value());
528 for (size_t i = 0; i < protoAcc->GetNumArgs(); i++) {
529 ParamAnnotationsDataAccessor::AnnotationArray annArr = paramAcc.GetAnnotationArray(i);
530 annArr.EnumerateAnnotations([this, ¶mItems, &i](File::EntityId annId) {
531 auto annItem = CreateAnnotationItem(annId);
532 paramItems[i].AddAnnotation(annItem);
533 });
534 }
535 }
536
537 auto runtimeParamAnnId = methodAcc->GetRuntimeParamAnnotationId();
538 if (runtimeParamAnnId) {
539 ParamAnnotationsDataAccessor paramAcc(*file_, runtimeParamAnnId.value());
540 for (size_t i = 0; i < protoAcc->GetNumArgs(); i++) {
541 ParamAnnotationsDataAccessor::AnnotationArray annArr = paramAcc.GetAnnotationArray(i);
542 annArr.EnumerateAnnotations([this, ¶mItems, &i](File::EntityId annId) {
543 auto annItem = CreateAnnotationItem(annId);
544 paramItems[i].AddRuntimeAnnotation(annItem);
545 });
546 }
547 }
548
549 return paramItems;
550 }
551
CreateDebugInfoItem(File::EntityId debugInfoId)552 DebugInfoItem *FileReader::CreateDebugInfoItem(File::EntityId debugInfoId)
553 {
554 auto it = itemsDone_.find(debugInfoId);
555 if (it != itemsDone_.end()) {
556 return static_cast<DebugInfoItem *>(it->second);
557 }
558
559 panda_file::DebugInfoDataAccessor debugAcc(*file_, debugInfoId);
560
561 const auto lnpId = file_->GetIdFromPointer(debugAcc.GetLineNumberProgram());
562
563 LineNumberProgramItem *lnpItem;
564
565 if (auto oldLnp = itemsDone_.find(lnpId); oldLnp != itemsDone_.end()) {
566 ASSERT(oldLnp->second->GetItemType() == ItemTypes::LINE_NUMBER_PROGRAM_ITEM);
567 lnpItem = static_cast<LineNumberProgramItem *>(oldLnp->second);
568 container_.IncRefLineNumberProgramItem(lnpItem);
569 } else {
570 lnpItem = container_.CreateLineNumberProgramItem();
571 itemsDone_.emplace(lnpId, lnpItem);
572 }
573
574 auto *debugInfoItem = container_.CreateItem<DebugInfoItem>(lnpItem);
575 itemsDone_.insert({debugInfoId, static_cast<BaseItem *>(debugInfoItem)});
576
577 debugInfoItem->SetLineNumber(debugAcc.GetLineStart());
578 debugAcc.EnumerateParameters([this, &debugInfoItem](File::EntityId paramId) {
579 auto data = file_->GetStringData(paramId);
580 std::string itemStr(utf::Mutf8AsCString(data.data));
581 auto *stringItem = container_.GetOrCreateStringItem(itemStr);
582 debugInfoItem->AddParameter(stringItem);
583 });
584
585 return debugInfoItem;
586 }
587
GetCatchTypeItem(CodeDataAccessor::CatchBlock & catchBlock,File::EntityId methodId,MethodItem * methodItem)588 BaseClassItem *FileReader::GetCatchTypeItem(CodeDataAccessor::CatchBlock &catchBlock, File::EntityId methodId,
589 MethodItem *methodItem)
590 {
591 BaseClassItem *catchTypeItem = nullptr;
592 auto typeIdx = catchBlock.GetTypeIdx();
593 if (typeIdx != panda_file::INVALID_INDEX) {
594 File::EntityId catchClsId = file_->ResolveClassIndex(methodId, catchBlock.GetTypeIdx());
595 if (file_->IsExternal(catchClsId)) {
596 catchTypeItem = CreateForeignClassItem(catchClsId);
597 } else {
598 catchTypeItem = CreateClassItem(catchClsId);
599 }
600 methodItem->AddIndexDependency(catchTypeItem);
601 }
602 return catchTypeItem;
603 }
604
SetMethodCodeIfPresent(std::optional<File::EntityId> & codeId,MethodItem * methodItem,File::EntityId & methodId)605 void FileReader::SetMethodCodeIfPresent(std::optional<File::EntityId> &codeId, MethodItem *methodItem,
606 File::EntityId &methodId)
607 {
608 CodeDataAccessor codeAcc(*file_, codeId.value());
609 std::vector<uint8_t> instructions(codeAcc.GetCodeSize());
610 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
611 instructions.assign(codeAcc.GetInstructions(), codeAcc.GetInstructions() + codeAcc.GetCodeSize());
612 auto *codeItem =
613 container_.CreateItem<CodeItem>(codeAcc.GetNumVregs(), codeAcc.GetNumArgs(), std::move(instructions));
614
615 codeAcc.EnumerateTryBlocks([this, &methodItem, &methodId, &codeItem](CodeDataAccessor::TryBlock &tryBlock) {
616 std::vector<CodeItem::CatchBlock> catchBlocks;
617 tryBlock.EnumerateCatchBlocks(
618 [this, &methodItem, &methodId, &catchBlocks](CodeDataAccessor::CatchBlock &catchBlock) {
619 BaseClassItem *catchTypeItem = this->GetCatchTypeItem(catchBlock, methodId, methodItem);
620 catchBlocks.emplace_back(CodeItem::CatchBlock(methodItem, catchTypeItem, catchBlock.GetHandlerPc(),
621 catchBlock.GetCodeSize()));
622 return true;
623 });
624 codeItem->AddTryBlock(CodeItem::TryBlock(tryBlock.GetStartPc(), tryBlock.GetLength(), std::move(catchBlocks)));
625 return true;
626 });
627
628 methodItem->SetCode(codeItem);
629 }
630
SetRetType(ProtoDataAccessor & protoAcc,size_t & referenceNum)631 TypeItem *FileReader::SetRetType(ProtoDataAccessor &protoAcc, size_t &referenceNum)
632
633 {
634 Type retType = protoAcc.GetReturnType();
635 TypeItem *retTypeItem = nullptr;
636 if (retType.IsPrimitive()) {
637 retTypeItem = container_.GetOrCreatePrimitiveTypeItem(retType);
638 } else {
639 const File::EntityId typeClsId = protoAcc.GetReferenceType(referenceNum);
640 if (file_->IsExternal(typeClsId)) {
641 retTypeItem = CreateForeignClassItem(typeClsId);
642 } else {
643 retTypeItem = CreateClassItem(typeClsId);
644 }
645 referenceNum++;
646 }
647 return retTypeItem;
648 }
649
CreateMethodItem(ClassItem * cls,File::EntityId methodId)650 MethodItem *FileReader::CreateMethodItem(ClassItem *cls, File::EntityId methodId)
651 {
652 auto it = itemsDone_.find(methodId);
653 if (it != itemsDone_.end()) {
654 return static_cast<MethodItem *>(it->second);
655 }
656
657 MethodDataAccessor methodAcc(*file_, methodId);
658 auto data = file_->GetStringData(methodAcc.GetNameId());
659 std::string methodName(utf::Mutf8AsCString(data.data));
660 auto *methodStrItem = container_.GetOrCreateStringItem(methodName);
661
662 ProtoDataAccessor protoAcc(*file_, methodAcc.GetProtoId());
663 size_t referenceNum = 0;
664 TypeItem *retTypeItem = SetRetType(protoAcc, referenceNum);
665 ASSERT(retTypeItem != nullptr);
666 auto paramItems = CreateMethodParamItems(&protoAcc, &methodAcc, referenceNum);
667 // Double check if we done this method while computing params
668 auto itCheck = itemsDone_.find(methodId);
669 if (itCheck != itemsDone_.end()) {
670 return static_cast<MethodItem *>(itCheck->second);
671 }
672 auto *protoItem = container_.GetOrCreateProtoItem(retTypeItem, paramItems);
673
674 auto *methodItem = cls->AddMethod(methodStrItem, protoItem, methodAcc.GetAccessFlags(), std::move(paramItems));
675
676 if (methodItem->HasRuntimeParamAnnotations()) {
677 container_.CreateItem<ParamAnnotationsItem>(methodItem, true);
678 }
679
680 if (methodItem->HasParamAnnotations()) {
681 container_.CreateItem<ParamAnnotationsItem>(methodItem, false);
682 }
683
684 itemsDone_.insert({methodId, static_cast<BaseItem *>(methodItem)});
685
686 methodAcc.EnumerateAnnotations(
687 [this, &methodItem](File::EntityId annId) { methodItem->AddAnnotation(CreateAnnotationItem(annId)); });
688
689 methodAcc.EnumerateRuntimeAnnotations(
690 [this, &methodItem](File::EntityId annId) { methodItem->AddRuntimeAnnotation(CreateAnnotationItem(annId)); });
691
692 methodAcc.EnumerateTypeAnnotations(
693 [this, &methodItem](File::EntityId annId) { methodItem->AddTypeAnnotation(CreateAnnotationItem(annId)); });
694
695 methodAcc.EnumerateRuntimeTypeAnnotations([this, &methodItem](File::EntityId annId) {
696 methodItem->AddRuntimeTypeAnnotation(CreateAnnotationItem(annId));
697 });
698
699 auto codeId = methodAcc.GetCodeId();
700 if (codeId) {
701 SetMethodCodeIfPresent(codeId, methodItem, methodId);
702 }
703
704 auto debugInfoId = methodAcc.GetDebugInfoId();
705 if (debugInfoId) {
706 methodItem->SetDebugInfo(CreateDebugInfoItem(debugInfoId.value()));
707 }
708
709 auto sourceLang = methodAcc.GetSourceLang();
710 if (sourceLang) {
711 methodItem->SetSourceLang(sourceLang.value());
712 }
713
714 return methodItem;
715 }
716
CreateMethodHandleItem(File::EntityId mhId)717 MethodHandleItem *FileReader::CreateMethodHandleItem(File::EntityId mhId)
718 {
719 (void)mhId;
720 ASSERT(false);
721 return nullptr; // STUB
722 }
723
SetFieldValue(FieldItem * fieldItem,Type fieldType,FieldDataAccessor & fieldAcc)724 void FileReader::SetFieldValue(FieldItem *fieldItem, Type fieldType, FieldDataAccessor &fieldAcc)
725 {
726 switch (fieldType.GetId()) {
727 case Type::TypeId::U1:
728 case Type::TypeId::I8:
729 case Type::TypeId::U8:
730 SetIntegerFieldValue<uint8_t>(&fieldAcc, fieldItem);
731 break;
732 case Type::TypeId::I16:
733 case Type::TypeId::U16:
734 SetIntegerFieldValue<uint16_t>(&fieldAcc, fieldItem);
735 break;
736 case Type::TypeId::I32:
737 case Type::TypeId::U32:
738 SetIntegerFieldValue<uint32_t>(&fieldAcc, fieldItem);
739 break;
740 case Type::TypeId::I64:
741 case Type::TypeId::U64:
742 SetIntegerFieldValue<uint64_t>(&fieldAcc, fieldItem);
743 break;
744 case Type::TypeId::F32:
745 SetFloatFieldValue<float>(&fieldAcc, fieldItem);
746 break;
747 case Type::TypeId::F64:
748 SetFloatFieldValue<double>(&fieldAcc, fieldItem);
749 break;
750 case Type::TypeId::REFERENCE:
751 SetStringFieldValue(&fieldAcc, fieldItem);
752 break;
753 case Type::TypeId::TAGGED:
754 default:
755 UNREACHABLE();
756 break;
757 }
758 }
759
CreateFieldItem(ClassItem * cls,File::EntityId fieldId)760 FieldItem *FileReader::CreateFieldItem(ClassItem *cls, File::EntityId fieldId)
761 {
762 auto it = itemsDone_.find(fieldId);
763 if (it != itemsDone_.end()) {
764 return static_cast<FieldItem *>(it->second);
765 }
766
767 FieldDataAccessor fieldAcc(*file_, fieldId);
768
769 auto data = file_->GetStringData(fieldAcc.GetNameId());
770 std::string stringName(utf::Mutf8AsCString(data.data));
771 auto *fieldName = container_.GetOrCreateStringItem(stringName);
772 Type fieldType = Type::GetTypeFromFieldEncoding(fieldAcc.GetType());
773
774 TypeItem *fieldTypeItem = nullptr;
775 if (fieldType.IsReference()) {
776 File::EntityId typeId(fieldAcc.GetType());
777 if (file_->IsExternal(typeId)) {
778 fieldTypeItem = CreateForeignClassItem(typeId);
779 } else {
780 fieldTypeItem = CreateClassItem(typeId);
781 // Double check if we done this field while generated class item
782 auto itCheck = itemsDone_.find(fieldId);
783 if (itCheck != itemsDone_.end()) {
784 return static_cast<FieldItem *>(itCheck->second);
785 }
786 }
787 } else {
788 fieldTypeItem = container_.GetOrCreatePrimitiveTypeItem(fieldType.GetId());
789 }
790
791 ASSERT(fieldTypeItem != nullptr);
792
793 FieldItem *fieldItem = cls->AddField(fieldName, fieldTypeItem, fieldAcc.GetAccessFlags());
794 itemsDone_.insert({fieldId, static_cast<BaseItem *>(fieldItem)});
795
796 SetFieldValue(fieldItem, fieldType, fieldAcc);
797
798 fieldAcc.EnumerateAnnotations(
799 [this, &fieldItem](File::EntityId annId) { fieldItem->AddAnnotation(CreateAnnotationItem(annId)); });
800
801 fieldAcc.EnumerateRuntimeAnnotations(
802 [this, &fieldItem](File::EntityId annId) { fieldItem->AddRuntimeAnnotation(CreateAnnotationItem(annId)); });
803
804 fieldAcc.EnumerateRuntimeTypeAnnotations(
805 [this, &fieldItem](File::EntityId annId) { fieldItem->AddRuntimeTypeAnnotation(CreateAnnotationItem(annId)); });
806
807 fieldAcc.EnumerateTypeAnnotations(
808 [this, &fieldItem](File::EntityId annId) { fieldItem->AddTypeAnnotation(CreateAnnotationItem(annId)); });
809
810 return fieldItem;
811 }
812
CreateForeignMethodItem(BaseClassItem * fcls,File::EntityId methodId)813 ForeignMethodItem *FileReader::CreateForeignMethodItem(BaseClassItem *fcls, File::EntityId methodId)
814 {
815 auto it = itemsDone_.find(methodId);
816 if (it != itemsDone_.end()) {
817 return static_cast<ForeignMethodItem *>(it->second);
818 }
819
820 MethodDataAccessor methodAcc(*file_, methodId);
821 auto data = file_->GetStringData(methodAcc.GetNameId());
822 std::string methodName(utf::Mutf8AsCString(data.data));
823 auto *methodStrItem = container_.GetOrCreateStringItem(methodName);
824
825 ProtoDataAccessor protoAcc(*file_, methodAcc.GetProtoId());
826 Type retType = protoAcc.GetReturnType();
827 size_t referenceNum = 0;
828 TypeItem *retTypeItem = nullptr;
829 if (retType.IsPrimitive()) {
830 retTypeItem = container_.GetOrCreatePrimitiveTypeItem(retType);
831 } else {
832 const File::EntityId typeClsId = protoAcc.GetReferenceType(referenceNum);
833 if (file_->IsExternal(typeClsId)) {
834 retTypeItem = CreateForeignClassItem(typeClsId);
835 } else {
836 retTypeItem = CreateClassItem(typeClsId);
837 }
838 referenceNum++;
839 }
840 ASSERT(retTypeItem != nullptr);
841 auto paramItems = CreateMethodParamItems(&protoAcc, &methodAcc, referenceNum);
842 // Double check if we done this method while computing params
843 auto itCheck = itemsDone_.find(methodId);
844 if (itCheck != itemsDone_.end()) {
845 return static_cast<ForeignMethodItem *>(itCheck->second);
846 }
847 auto *protoItem = container_.GetOrCreateProtoItem(retTypeItem, paramItems);
848
849 auto *methodItem =
850 container_.CreateItem<ForeignMethodItem>(fcls, methodStrItem, protoItem, methodAcc.GetAccessFlags());
851
852 itemsDone_.insert({methodId, static_cast<BaseItem *>(methodItem)});
853
854 return methodItem;
855 }
856
CreateForeignFieldItem(BaseClassItem * fcls,File::EntityId fieldId)857 ForeignFieldItem *FileReader::CreateForeignFieldItem(BaseClassItem *fcls, File::EntityId fieldId)
858 {
859 auto it = itemsDone_.find(fieldId);
860 if (it != itemsDone_.end()) {
861 return static_cast<ForeignFieldItem *>(it->second);
862 }
863
864 FieldDataAccessor fieldAcc(*file_, fieldId);
865
866 auto data = file_->GetStringData(fieldAcc.GetNameId());
867 std::string stringName(utf::Mutf8AsCString(data.data));
868 auto *fieldName = container_.GetOrCreateStringItem(stringName);
869 Type fieldType = Type::GetTypeFromFieldEncoding(fieldAcc.GetType());
870 TypeItem *fieldTypeItem = nullptr;
871 if (fieldType.IsReference()) {
872 File::EntityId typeId(fieldAcc.GetType());
873 if (file_->IsExternal(typeId)) {
874 fieldTypeItem = CreateForeignClassItem(typeId);
875 } else {
876 fieldTypeItem = CreateClassItem(typeId);
877 // Double check if we done this field while generated class item
878 auto itCheck = itemsDone_.find(fieldId);
879 if (itCheck != itemsDone_.end()) {
880 return static_cast<ForeignFieldItem *>(itCheck->second);
881 }
882 }
883 } else {
884 fieldTypeItem = container_.GetOrCreatePrimitiveTypeItem(fieldType.GetId());
885 }
886
887 ASSERT(fieldTypeItem != nullptr);
888
889 auto *fieldItem = container_.CreateItem<ForeignFieldItem>(fcls, fieldName, fieldTypeItem);
890 itemsDone_.insert({fieldId, static_cast<BaseItem *>(fieldItem)});
891
892 return fieldItem;
893 }
894
CreateForeignClassItem(File::EntityId classId)895 ForeignClassItem *FileReader::CreateForeignClassItem(File::EntityId classId)
896 {
897 auto it = itemsDone_.find(classId);
898 if (it != itemsDone_.end()) {
899 return static_cast<ForeignClassItem *>(it->second);
900 }
901
902 std::string className(utf::Mutf8AsCString(file_->GetStringData(classId).data));
903 auto *classItem = container_.GetOrCreateForeignClassItem(className);
904
905 itemsDone_.insert({classId, static_cast<BaseItem *>(classItem)});
906
907 return classItem;
908 }
909
CreateClassItem(File::EntityId classId)910 ClassItem *FileReader::CreateClassItem(File::EntityId classId)
911 {
912 auto it = itemsDone_.find(classId);
913 if (it != itemsDone_.end()) {
914 return static_cast<ClassItem *>(it->second);
915 }
916 ClassDataAccessor classAcc(*file_, classId);
917
918 std::string className(utf::Mutf8AsCString(file_->GetStringData(classId).data));
919 auto *classItem = container_.GetOrCreateClassItem(className);
920
921 itemsDone_.insert({classId, static_cast<BaseItem *>(classItem)});
922
923 classItem->SetAccessFlags(classAcc.GetAccessFlags());
924
925 auto sourceLangOpt = classAcc.GetSourceLang();
926 if (sourceLangOpt) {
927 classItem->SetSourceLang(sourceLangOpt.value());
928 }
929
930 auto superClassId = classAcc.GetSuperClassId();
931 if (superClassId.GetOffset() != 0) {
932 if (superClassId.GetOffset() == classId.GetOffset()) {
933 LOG(FATAL, PANDAFILE) << "Class " << className << " has cyclic inheritance";
934 }
935
936 if (file_->IsExternal(superClassId)) {
937 classItem->SetSuperClass(CreateForeignClassItem(superClassId));
938 } else {
939 classItem->SetSuperClass(CreateClassItem(superClassId));
940 }
941 }
942
943 classAcc.EnumerateInterfaces([this, &classItem](File::EntityId ifaceId) {
944 if (file_->IsExternal(ifaceId)) {
945 classItem->AddInterface(CreateForeignClassItem(ifaceId));
946 } else {
947 classItem->AddInterface(CreateClassItem(ifaceId));
948 }
949 });
950
951 classAcc.EnumerateAnnotations(
952 [this, &classItem](File::EntityId annId) { classItem->AddAnnotation(CreateAnnotationItem(annId)); });
953
954 classAcc.EnumerateRuntimeAnnotations(
955 [this, &classItem](File::EntityId annId) { classItem->AddRuntimeAnnotation(CreateAnnotationItem(annId)); });
956
957 classAcc.EnumerateTypeAnnotations(
958 [this, &classItem](File::EntityId annId) { classItem->AddTypeAnnotation(CreateAnnotationItem(annId)); });
959
960 classAcc.EnumerateFields(
961 [this, &classItem](FieldDataAccessor &fieldAcc) { CreateFieldItem(classItem, fieldAcc.GetFieldId()); });
962
963 classAcc.EnumerateMethods(
964 [this, &classItem](MethodDataAccessor &methodAcc) { CreateMethodItem(classItem, methodAcc.GetMethodId()); });
965
966 auto sourceFileId = classAcc.GetSourceFileId();
967 if (sourceFileId) {
968 std::string sourceFile = utf::Mutf8AsCString(file_->GetStringData(sourceFileId.value()).data);
969 classItem->SetSourceFile(container_.GetOrCreateStringItem(sourceFile));
970 }
971
972 ASSERT(classItem != nullptr);
973
974 return classItem;
975 }
976
ReadLiteralArrayItems()977 bool FileReader::ReadLiteralArrayItems()
978 {
979 const auto litArraysId = file_->GetLiteralArraysId();
980 LiteralDataAccessor litArrayAccessor(*file_, litArraysId);
981 size_t numLitarrays = litArrayAccessor.GetLiteralNum();
982
983 for (size_t i = 0; i < numLitarrays; i++) {
984 auto id = litArrayAccessor.GetLiteralArrayId(i);
985 if (!CreateLiteralArrayItem(&litArrayAccessor, id, i)) {
986 return false;
987 }
988 }
989
990 return true;
991 }
992
ReadRegionHeaders()993 bool FileReader::ReadRegionHeaders()
994 {
995 auto indexHeaders = file_->GetRegionHeaders();
996 for (const auto &header : indexHeaders) {
997 auto methodIndex = file_->GetMethodIndex(&header);
998 for (auto methodId : methodIndex) {
999 MethodDataAccessor methodAcc(*file_, methodId);
1000 File::EntityId classId(methodAcc.GetClassId());
1001 if (file_->IsExternal(classId)) {
1002 auto *fclassItem = CreateForeignClassItem(classId);
1003 ASSERT(file_->IsExternal(methodId));
1004 if (CreateForeignMethodItem(fclassItem, methodId) == nullptr) {
1005 return false;
1006 }
1007 } else {
1008 auto *classItem = CreateClassItem(classId);
1009 if (file_->IsExternal(methodId)) {
1010 if (CreateForeignMethodItem(classItem, methodId) == nullptr) {
1011 return false;
1012 }
1013 } else if (CreateMethodItem(classItem, methodId) == nullptr) {
1014 return false;
1015 }
1016 }
1017 }
1018 auto fieldIndex = file_->GetFieldIndex(&header);
1019 for (auto fieldId : fieldIndex) {
1020 FieldDataAccessor fieldAcc(*file_, fieldId);
1021 File::EntityId classId(fieldAcc.GetClassId());
1022 if (file_->IsExternal(classId)) {
1023 ASSERT(file_->IsExternal(fieldId));
1024 auto *fclassItem = CreateForeignClassItem(fieldAcc.GetClassId());
1025 if (CreateForeignFieldItem(fclassItem, fieldId) == nullptr) {
1026 return false;
1027 }
1028 } else {
1029 auto *classItem = CreateClassItem(fieldAcc.GetClassId());
1030 if (file_->IsExternal(fieldId)) {
1031 if (CreateForeignFieldItem(classItem, fieldId) == nullptr) {
1032 return false;
1033 }
1034 } else if (CreateFieldItem(classItem, fieldId) == nullptr) {
1035 return false;
1036 }
1037 }
1038 }
1039 }
1040 return true;
1041 }
1042
ReadClasses()1043 bool FileReader::ReadClasses()
1044 {
1045 const auto classIdx = file_->GetClasses();
1046
1047 for (unsigned int id : classIdx) {
1048 File::EntityId eid(id);
1049 if (file_->IsExternal(eid)) {
1050 CreateForeignClassItem(eid);
1051 } else {
1052 CreateClassItem(eid);
1053 }
1054 }
1055
1056 return true;
1057 }
1058
UpdateDebugInfoDependecies(File::EntityId debugInfoId)1059 void FileReader::UpdateDebugInfoDependecies(File::EntityId debugInfoId)
1060 {
1061 auto updater = FileReaderDebugInfoUpdater(file_.get(), &container_);
1062 updater.Scrap(debugInfoId);
1063 }
1064
UpdateDebugInfo(DebugInfoItem * debugInfoItem,File::EntityId debugInfoId)1065 void FileReader::UpdateDebugInfo(DebugInfoItem *debugInfoItem, File::EntityId debugInfoId)
1066 {
1067 auto updater = FileReaderDebugInfoUpdater(file_.get(), &container_);
1068 updater.Emit(debugInfoItem->GetLineNumberProgram(), debugInfoItem->GetConstantPool(), debugInfoId);
1069 }
1070
InstCheckByFlags(BytecodeInstruction & inst,MethodItem * methodItem,const std::map<BaseItem *,File::EntityId> & reverseDone)1071 void FileReader::InstCheckByFlags(BytecodeInstruction &inst, MethodItem *methodItem,
1072 const std::map<BaseItem *, File::EntityId> &reverseDone)
1073 {
1074 using Flags = ark::BytecodeInst<ark::BytecodeInstMode::FAST>::Flags;
1075
1076 if (inst.HasFlag(Flags::TYPE_ID)) {
1077 BytecodeId bId = inst.GetId();
1078 File::Index idx = bId.AsIndex();
1079 File::EntityId methodId = reverseDone.find(methodItem)->second;
1080 File::EntityId oldId = file_->ResolveClassIndex(methodId, idx);
1081 ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1082 auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1083 methodItem->AddIndexDependency(idxItem);
1084 } else if (inst.HasFlag(Flags::METHOD_ID)) {
1085 BytecodeId bId = inst.GetId();
1086 File::Index idx = bId.AsIndex();
1087 File::EntityId methodId = reverseDone.find(methodItem)->second;
1088 File::EntityId oldId = file_->ResolveMethodIndex(methodId, idx);
1089 ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1090 auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1091 methodItem->AddIndexDependency(idxItem);
1092 } else if (inst.HasFlag(Flags::FIELD_ID)) {
1093 BytecodeId bId = inst.GetId();
1094 File::Index idx = bId.AsIndex();
1095 File::EntityId methodId = reverseDone.find(methodItem)->second;
1096 File::EntityId oldId = file_->ResolveFieldIndex(methodId, idx);
1097 ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1098 auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1099 methodItem->AddIndexDependency(idxItem);
1100 } else if (inst.HasFlag(Flags::STRING_ID)) {
1101 BytecodeId bId = inst.GetId();
1102 File::EntityId oldId = bId.AsFileId();
1103 auto data = file_->GetStringData(oldId);
1104 std::string itemStr(utf::Mutf8AsCString(data.data));
1105 container_.GetOrCreateStringItem(itemStr);
1106 }
1107 }
1108
UpdateCodeAndDebugInfoDependencies(const std::map<BaseItem *,File::EntityId> & reverseDone)1109 void FileReader::UpdateCodeAndDebugInfoDependencies(const std::map<BaseItem *, File::EntityId> &reverseDone)
1110 {
1111 auto *classMap = container_.GetClassMap();
1112
1113 // First pass, add dependencies bytecode -> new items
1114 for (const auto &it : *classMap) {
1115 auto *baseClassItem = it.second;
1116 if (baseClassItem->IsForeign()) {
1117 continue;
1118 }
1119 auto *classItem = static_cast<ClassItem *>(baseClassItem);
1120 classItem->VisitMethods([this, &reverseDone](BaseItem *paramItem) {
1121 auto *methodItem = static_cast<MethodItem *>(paramItem);
1122 auto *codeItem = methodItem->GetCode();
1123 if (codeItem == nullptr) {
1124 return true;
1125 }
1126
1127 auto *debugInfoItem = methodItem->GetDebugInfo();
1128 if (debugInfoItem != nullptr) {
1129 UpdateDebugInfoDependecies(reverseDone.find(debugInfoItem)->second);
1130 }
1131
1132 size_t offset = 0;
1133 BytecodeInstruction inst(codeItem->GetInstructions()->data());
1134 while (offset < codeItem->GetCodeSize()) {
1135 InstCheckByFlags(inst, methodItem, reverseDone);
1136
1137 offset += inst.GetSize();
1138 inst = inst.GetNext();
1139 }
1140 return true;
1141 });
1142 }
1143 }
1144
ComputeLayoutAndUpdateIndices()1145 void FileReader::ComputeLayoutAndUpdateIndices()
1146 {
1147 using Flags = ark::BytecodeInst<ark::BytecodeInstMode::FAST>::Flags;
1148
1149 std::map<BaseItem *, File::EntityId> reverseDone;
1150 for (const auto &it : itemsDone_) {
1151 reverseDone.insert({it.second, it.first});
1152 }
1153
1154 auto *classMap = container_.GetClassMap();
1155
1156 UpdateCodeAndDebugInfoDependencies(reverseDone);
1157
1158 container_.ComputeLayout();
1159
1160 // Second pass, update debug info
1161 for (const auto &it : *classMap) {
1162 auto *baseClassItem = it.second;
1163 if (baseClassItem->IsForeign()) {
1164 continue;
1165 }
1166 auto *classItem = static_cast<ClassItem *>(baseClassItem);
1167 classItem->VisitMethods([this, &reverseDone](BaseItem *paramItem) {
1168 auto *methodItem = static_cast<MethodItem *>(paramItem);
1169 auto *codeItem = methodItem->GetCode();
1170 if (codeItem == nullptr) {
1171 return true;
1172 }
1173
1174 auto *debugInfoItem = methodItem->GetDebugInfo();
1175 if (debugInfoItem != nullptr) {
1176 UpdateDebugInfo(debugInfoItem, reverseDone.find(debugInfoItem)->second);
1177 }
1178
1179 return true;
1180 });
1181 }
1182
1183 container_.DeduplicateItems(false);
1184 container_.ComputeLayout();
1185
1186 std::unordered_set<CodeItem *> codeItemsDone;
1187
1188 // Third pass, update bytecode indices
1189 for (const auto &it : *classMap) {
1190 auto *baseClassItem = it.second;
1191 if (baseClassItem->IsForeign()) {
1192 continue;
1193 }
1194 auto *classItem = static_cast<ClassItem *>(baseClassItem);
1195 classItem->VisitMethods([this, &reverseDone, &codeItemsDone](BaseItem *paramItem) {
1196 auto *methodItem = static_cast<MethodItem *>(paramItem);
1197 auto *codeItem = methodItem->GetCode();
1198
1199 auto codeIt = codeItemsDone.find(codeItem);
1200 if (codeItem == nullptr || codeIt != codeItemsDone.end()) {
1201 return true;
1202 }
1203
1204 size_t offset = 0;
1205 BytecodeInstruction inst(codeItem->GetInstructions()->data());
1206 while (offset < codeItem->GetCodeSize()) {
1207 if (inst.HasFlag(Flags::TYPE_ID)) {
1208 BytecodeId bId = inst.GetId();
1209 File::Index idx = bId.AsIndex();
1210 File::EntityId methodId = reverseDone.find(methodItem)->second;
1211 File::EntityId oldId = file_->ResolveClassIndex(methodId, idx);
1212 ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1213 auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1214 uint32_t index = idxItem->GetIndex(methodItem);
1215 inst.UpdateId(BytecodeId(index));
1216 } else if (inst.HasFlag(Flags::METHOD_ID)) {
1217 BytecodeId bId = inst.GetId();
1218 File::Index idx = bId.AsIndex();
1219 File::EntityId methodId = reverseDone.find(methodItem)->second;
1220 File::EntityId oldId = file_->ResolveMethodIndex(methodId, idx);
1221 ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1222 auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1223 uint32_t index = idxItem->GetIndex(methodItem);
1224 inst.UpdateId(BytecodeId(index));
1225 } else if (inst.HasFlag(Flags::FIELD_ID)) {
1226 BytecodeId bId = inst.GetId();
1227 File::Index idx = bId.AsIndex();
1228 File::EntityId methodId = reverseDone.find(methodItem)->second;
1229 File::EntityId oldId = file_->ResolveFieldIndex(methodId, idx);
1230 ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1231 auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1232 uint32_t index = idxItem->GetIndex(methodItem);
1233 inst.UpdateId(BytecodeId(index));
1234 } else if (inst.HasFlag(Flags::STRING_ID)) {
1235 BytecodeId bId = inst.GetId();
1236 File::EntityId oldId = bId.AsFileId();
1237 auto data = file_->GetStringData(oldId);
1238 std::string itemStr(utf::Mutf8AsCString(data.data));
1239 auto *stringItem = container_.GetOrCreateStringItem(itemStr);
1240 inst.UpdateId(BytecodeId(stringItem->GetFileId().GetOffset()));
1241 }
1242
1243 offset += inst.GetSize();
1244 inst = inst.GetNext();
1245 }
1246
1247 codeItemsDone.insert(codeItem);
1248
1249 return true;
1250 });
1251 }
1252 }
1253
1254 } // namespace ark::panda_file
1255