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