1 /**
2 * Copyright (c) 2021-2025 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 auto itemType = it->second->GetBaseItemType();
559 if (itemType != ItemTypes::DEBUG_INFO_ITEM) {
560 LOG(FATAL, PANDAFILE) << "ItemType Error " << static_cast<int>(itemType);
561 }
562 return static_cast<DebugInfoItem *>(it->second);
563 }
564
565 panda_file::DebugInfoDataAccessor debugAcc(*file_, debugInfoId);
566
567 const auto lnpId = file_->GetIdFromPointer(debugAcc.GetLineNumberProgram());
568
569 LineNumberProgramItem *lnpItem;
570
571 if (auto oldLnp = itemsDone_.find(lnpId); oldLnp != itemsDone_.end()) {
572 ASSERT(oldLnp->second->GetItemType() == ItemTypes::LINE_NUMBER_PROGRAM_ITEM);
573 lnpItem = static_cast<LineNumberProgramItem *>(oldLnp->second);
574 container_.IncRefLineNumberProgramItem(lnpItem);
575 } else {
576 lnpItem = container_.CreateLineNumberProgramItem();
577 itemsDone_.emplace(lnpId, lnpItem);
578 }
579
580 auto *debugInfoItem = container_.CreateItem<DebugInfoItem>(lnpItem);
581 itemsDone_.insert({debugInfoId, static_cast<BaseItem *>(debugInfoItem)});
582
583 debugInfoItem->SetLineNumber(debugAcc.GetLineStart());
584 debugAcc.EnumerateParameters([this, &debugInfoItem](File::EntityId paramId) {
585 auto data = file_->GetStringData(paramId);
586 std::string itemStr(utf::Mutf8AsCString(data.data));
587 auto *stringItem = container_.GetOrCreateStringItem(itemStr);
588 debugInfoItem->AddParameter(stringItem);
589 });
590 debugInfoItem->SetBaseItemType(ItemTypes::DEBUG_INFO_ITEM);
591 return debugInfoItem;
592 }
593
GetCatchTypeItem(CodeDataAccessor::CatchBlock & catchBlock,File::EntityId methodId,MethodItem * methodItem)594 BaseClassItem *FileReader::GetCatchTypeItem(CodeDataAccessor::CatchBlock &catchBlock, File::EntityId methodId,
595 MethodItem *methodItem)
596 {
597 BaseClassItem *catchTypeItem = nullptr;
598 auto typeIdx = catchBlock.GetTypeIdx();
599 if (typeIdx != panda_file::INVALID_INDEX) {
600 File::EntityId catchClsId = file_->ResolveClassIndex(methodId, catchBlock.GetTypeIdx());
601 if (file_->IsExternal(catchClsId)) {
602 catchTypeItem = CreateForeignClassItem(catchClsId);
603 } else {
604 catchTypeItem = CreateClassItem(catchClsId);
605 }
606 methodItem->AddIndexDependency(catchTypeItem);
607 }
608 return catchTypeItem;
609 }
610
SetMethodCodeIfPresent(std::optional<File::EntityId> & codeId,MethodItem * methodItem,File::EntityId & methodId)611 void FileReader::SetMethodCodeIfPresent(std::optional<File::EntityId> &codeId, MethodItem *methodItem,
612 File::EntityId &methodId)
613 {
614 CodeDataAccessor codeAcc(*file_, codeId.value());
615 std::vector<uint8_t> instructions(codeAcc.GetCodeSize());
616 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
617 instructions.assign(codeAcc.GetInstructions(), codeAcc.GetInstructions() + codeAcc.GetCodeSize());
618 auto *codeItem =
619 container_.CreateItem<CodeItem>(codeAcc.GetNumVregs(), codeAcc.GetNumArgs(), std::move(instructions));
620
621 codeAcc.EnumerateTryBlocks([this, &methodItem, &methodId, &codeItem](CodeDataAccessor::TryBlock &tryBlock) {
622 std::vector<CodeItem::CatchBlock> catchBlocks;
623 tryBlock.EnumerateCatchBlocks(
624 [this, &methodItem, &methodId, &catchBlocks](CodeDataAccessor::CatchBlock &catchBlock) {
625 BaseClassItem *catchTypeItem = this->GetCatchTypeItem(catchBlock, methodId, methodItem);
626 catchBlocks.emplace_back(CodeItem::CatchBlock(methodItem, catchTypeItem, catchBlock.GetHandlerPc(),
627 catchBlock.GetCodeSize()));
628 return true;
629 });
630 codeItem->AddTryBlock(CodeItem::TryBlock(tryBlock.GetStartPc(), tryBlock.GetLength(), std::move(catchBlocks)));
631 return true;
632 });
633
634 methodItem->SetCode(codeItem);
635 }
636
SetRetType(ProtoDataAccessor & protoAcc,size_t & referenceNum)637 TypeItem *FileReader::SetRetType(ProtoDataAccessor &protoAcc, size_t &referenceNum)
638
639 {
640 Type retType = protoAcc.GetReturnType();
641 TypeItem *retTypeItem = nullptr;
642 if (retType.IsPrimitive()) {
643 retTypeItem = container_.GetOrCreatePrimitiveTypeItem(retType);
644 } else {
645 const File::EntityId typeClsId = protoAcc.GetReferenceType(referenceNum);
646 if (file_->IsExternal(typeClsId)) {
647 retTypeItem = CreateForeignClassItem(typeClsId);
648 } else {
649 retTypeItem = CreateClassItem(typeClsId);
650 }
651 referenceNum++;
652 }
653 return retTypeItem;
654 }
655
CreateMethodItem(ClassItem * cls,File::EntityId methodId)656 MethodItem *FileReader::CreateMethodItem(ClassItem *cls, File::EntityId methodId)
657 {
658 auto it = itemsDone_.find(methodId);
659 if (it != itemsDone_.end()) {
660 return static_cast<MethodItem *>(it->second);
661 }
662
663 MethodDataAccessor methodAcc(*file_, methodId);
664 auto data = file_->GetStringData(methodAcc.GetNameId());
665 std::string methodName(utf::Mutf8AsCString(data.data));
666 auto *methodStrItem = container_.GetOrCreateStringItem(methodName);
667
668 ProtoDataAccessor protoAcc(*file_, methodAcc.GetProtoId());
669 size_t referenceNum = 0;
670 TypeItem *retTypeItem = SetRetType(protoAcc, referenceNum);
671 ASSERT(retTypeItem != nullptr);
672 auto paramItems = CreateMethodParamItems(&protoAcc, &methodAcc, referenceNum);
673 // Double check if we done this method while computing params
674 auto itCheck = itemsDone_.find(methodId);
675 if (itCheck != itemsDone_.end()) {
676 return static_cast<MethodItem *>(itCheck->second);
677 }
678 auto *protoItem = container_.GetOrCreateProtoItem(retTypeItem, paramItems);
679
680 auto *methodItem = cls->AddMethod(methodStrItem, protoItem, methodAcc.GetAccessFlags(), std::move(paramItems));
681
682 if (methodItem->HasRuntimeParamAnnotations()) {
683 container_.CreateItem<ParamAnnotationsItem>(methodItem, true);
684 }
685
686 if (methodItem->HasParamAnnotations()) {
687 container_.CreateItem<ParamAnnotationsItem>(methodItem, false);
688 }
689
690 itemsDone_.insert({methodId, static_cast<BaseItem *>(methodItem)});
691
692 methodAcc.EnumerateAnnotations(
693 [this, &methodItem](File::EntityId annId) { methodItem->AddAnnotation(CreateAnnotationItem(annId)); });
694
695 methodAcc.EnumerateRuntimeAnnotations(
696 [this, &methodItem](File::EntityId annId) { methodItem->AddRuntimeAnnotation(CreateAnnotationItem(annId)); });
697
698 methodAcc.EnumerateTypeAnnotations(
699 [this, &methodItem](File::EntityId annId) { methodItem->AddTypeAnnotation(CreateAnnotationItem(annId)); });
700
701 methodAcc.EnumerateRuntimeTypeAnnotations([this, &methodItem](File::EntityId annId) {
702 methodItem->AddRuntimeTypeAnnotation(CreateAnnotationItem(annId));
703 });
704
705 auto codeId = methodAcc.GetCodeId();
706 if (codeId) {
707 SetMethodCodeIfPresent(codeId, methodItem, methodId);
708 }
709
710 auto debugInfoId = methodAcc.GetDebugInfoId();
711 if (debugInfoId) {
712 methodItem->SetDebugInfo(CreateDebugInfoItem(debugInfoId.value()));
713 }
714
715 auto sourceLang = methodAcc.GetSourceLang();
716 if (sourceLang) {
717 methodItem->SetSourceLang(sourceLang.value());
718 }
719
720 return methodItem;
721 }
722
CreateMethodHandleItem(File::EntityId mhId)723 MethodHandleItem *FileReader::CreateMethodHandleItem(File::EntityId mhId)
724 {
725 (void)mhId;
726 ASSERT(false);
727 return nullptr; // STUB
728 }
729
SetFieldValue(FieldItem * fieldItem,Type fieldType,FieldDataAccessor & fieldAcc)730 void FileReader::SetFieldValue(FieldItem *fieldItem, Type fieldType, FieldDataAccessor &fieldAcc)
731 {
732 switch (fieldType.GetId()) {
733 case Type::TypeId::U1:
734 case Type::TypeId::I8:
735 case Type::TypeId::U8:
736 SetIntegerFieldValue<uint8_t>(&fieldAcc, fieldItem);
737 break;
738 case Type::TypeId::I16:
739 case Type::TypeId::U16:
740 SetIntegerFieldValue<uint16_t>(&fieldAcc, fieldItem);
741 break;
742 case Type::TypeId::I32:
743 case Type::TypeId::U32:
744 SetIntegerFieldValue<uint32_t>(&fieldAcc, fieldItem);
745 break;
746 case Type::TypeId::I64:
747 case Type::TypeId::U64:
748 SetIntegerFieldValue<uint64_t>(&fieldAcc, fieldItem);
749 break;
750 case Type::TypeId::F32:
751 SetFloatFieldValue<float>(&fieldAcc, fieldItem);
752 break;
753 case Type::TypeId::F64:
754 SetFloatFieldValue<double>(&fieldAcc, fieldItem);
755 break;
756 case Type::TypeId::REFERENCE:
757 SetStringFieldValue(&fieldAcc, fieldItem);
758 break;
759 case Type::TypeId::TAGGED:
760 default:
761 UNREACHABLE();
762 break;
763 }
764 }
765
CreateFieldItem(ClassItem * cls,File::EntityId fieldId)766 FieldItem *FileReader::CreateFieldItem(ClassItem *cls, File::EntityId fieldId)
767 {
768 auto it = itemsDone_.find(fieldId);
769 if (it != itemsDone_.end()) {
770 return static_cast<FieldItem *>(it->second);
771 }
772
773 FieldDataAccessor fieldAcc(*file_, fieldId);
774
775 auto data = file_->GetStringData(fieldAcc.GetNameId());
776 std::string stringName(utf::Mutf8AsCString(data.data));
777 auto *fieldName = container_.GetOrCreateStringItem(stringName);
778 Type fieldType = Type::GetTypeFromFieldEncoding(fieldAcc.GetType());
779
780 TypeItem *fieldTypeItem = nullptr;
781 if (fieldType.IsReference()) {
782 File::EntityId typeId(fieldAcc.GetType());
783 if (file_->IsExternal(typeId)) {
784 fieldTypeItem = CreateForeignClassItem(typeId);
785 } else {
786 fieldTypeItem = CreateClassItem(typeId);
787 // Double check if we done this field while generated class item
788 auto itCheck = itemsDone_.find(fieldId);
789 if (itCheck != itemsDone_.end()) {
790 return static_cast<FieldItem *>(itCheck->second);
791 }
792 }
793 } else {
794 fieldTypeItem = container_.GetOrCreatePrimitiveTypeItem(fieldType.GetId());
795 }
796
797 ASSERT(fieldTypeItem != nullptr);
798
799 FieldItem *fieldItem = cls->AddField(fieldName, fieldTypeItem, fieldAcc.GetAccessFlags());
800 itemsDone_.insert({fieldId, static_cast<BaseItem *>(fieldItem)});
801
802 SetFieldValue(fieldItem, fieldType, fieldAcc);
803
804 fieldAcc.EnumerateAnnotations(
805 [this, &fieldItem](File::EntityId annId) { fieldItem->AddAnnotation(CreateAnnotationItem(annId)); });
806
807 fieldAcc.EnumerateRuntimeAnnotations(
808 [this, &fieldItem](File::EntityId annId) { fieldItem->AddRuntimeAnnotation(CreateAnnotationItem(annId)); });
809
810 fieldAcc.EnumerateRuntimeTypeAnnotations(
811 [this, &fieldItem](File::EntityId annId) { fieldItem->AddRuntimeTypeAnnotation(CreateAnnotationItem(annId)); });
812
813 fieldAcc.EnumerateTypeAnnotations(
814 [this, &fieldItem](File::EntityId annId) { fieldItem->AddTypeAnnotation(CreateAnnotationItem(annId)); });
815
816 return fieldItem;
817 }
818
CreateForeignMethodItem(BaseClassItem * fcls,File::EntityId methodId)819 ForeignMethodItem *FileReader::CreateForeignMethodItem(BaseClassItem *fcls, File::EntityId methodId)
820 {
821 auto it = itemsDone_.find(methodId);
822 if (it != itemsDone_.end()) {
823 return static_cast<ForeignMethodItem *>(it->second);
824 }
825
826 MethodDataAccessor methodAcc(*file_, methodId);
827 auto data = file_->GetStringData(methodAcc.GetNameId());
828 std::string methodName(utf::Mutf8AsCString(data.data));
829 auto *methodStrItem = container_.GetOrCreateStringItem(methodName);
830
831 ProtoDataAccessor protoAcc(*file_, methodAcc.GetProtoId());
832 Type retType = protoAcc.GetReturnType();
833 size_t referenceNum = 0;
834 TypeItem *retTypeItem = nullptr;
835 if (retType.IsPrimitive()) {
836 retTypeItem = container_.GetOrCreatePrimitiveTypeItem(retType);
837 } else {
838 const File::EntityId typeClsId = protoAcc.GetReferenceType(referenceNum);
839 if (file_->IsExternal(typeClsId)) {
840 retTypeItem = CreateForeignClassItem(typeClsId);
841 } else {
842 retTypeItem = CreateClassItem(typeClsId);
843 }
844 referenceNum++;
845 }
846 ASSERT(retTypeItem != nullptr);
847 auto paramItems = CreateMethodParamItems(&protoAcc, &methodAcc, referenceNum);
848 // Double check if we done this method while computing params
849 auto itCheck = itemsDone_.find(methodId);
850 if (itCheck != itemsDone_.end()) {
851 return static_cast<ForeignMethodItem *>(itCheck->second);
852 }
853 auto *protoItem = container_.GetOrCreateProtoItem(retTypeItem, paramItems);
854
855 auto *methodItem =
856 container_.CreateItem<ForeignMethodItem>(fcls, methodStrItem, protoItem, methodAcc.GetAccessFlags());
857
858 itemsDone_.insert({methodId, static_cast<BaseItem *>(methodItem)});
859
860 return methodItem;
861 }
862
CreateForeignFieldItem(BaseClassItem * fcls,File::EntityId fieldId)863 ForeignFieldItem *FileReader::CreateForeignFieldItem(BaseClassItem *fcls, File::EntityId fieldId)
864 {
865 auto it = itemsDone_.find(fieldId);
866 if (it != itemsDone_.end()) {
867 return static_cast<ForeignFieldItem *>(it->second);
868 }
869
870 FieldDataAccessor fieldAcc(*file_, fieldId);
871
872 auto data = file_->GetStringData(fieldAcc.GetNameId());
873 std::string stringName(utf::Mutf8AsCString(data.data));
874 auto *fieldName = container_.GetOrCreateStringItem(stringName);
875 Type fieldType = Type::GetTypeFromFieldEncoding(fieldAcc.GetType());
876 TypeItem *fieldTypeItem = nullptr;
877 if (fieldType.IsReference()) {
878 File::EntityId typeId(fieldAcc.GetType());
879 if (file_->IsExternal(typeId)) {
880 fieldTypeItem = CreateForeignClassItem(typeId);
881 } else {
882 fieldTypeItem = CreateClassItem(typeId);
883 // Double check if we done this field while generated class item
884 auto itCheck = itemsDone_.find(fieldId);
885 if (itCheck != itemsDone_.end()) {
886 return static_cast<ForeignFieldItem *>(itCheck->second);
887 }
888 }
889 } else {
890 fieldTypeItem = container_.GetOrCreatePrimitiveTypeItem(fieldType.GetId());
891 }
892
893 ASSERT(fieldTypeItem != nullptr);
894
895 auto *fieldItem =
896 container_.CreateItem<ForeignFieldItem>(fcls, fieldName, fieldTypeItem, fieldAcc.GetAccessFlags());
897 itemsDone_.insert({fieldId, static_cast<BaseItem *>(fieldItem)});
898
899 return fieldItem;
900 }
901
CreateForeignClassItem(File::EntityId classId)902 ForeignClassItem *FileReader::CreateForeignClassItem(File::EntityId classId)
903 {
904 auto it = itemsDone_.find(classId);
905 if (it != itemsDone_.end()) {
906 return static_cast<ForeignClassItem *>(it->second);
907 }
908
909 std::string className(utf::Mutf8AsCString(file_->GetStringData(classId).data));
910 auto *classItem = container_.GetOrCreateForeignClassItem(className);
911
912 itemsDone_.insert({classId, static_cast<BaseItem *>(classItem)});
913
914 return classItem;
915 }
916
CheckAndGetExistingFileItem(File::EntityId id,ItemTypes itemType)917 BaseItem *FileReader::CheckAndGetExistingFileItem(File::EntityId id, ItemTypes itemType)
918 {
919 auto it = itemsDone_.find(id);
920 if (it != itemsDone_.end()) {
921 auto iType = it->second->GetItemType();
922 if (iType != itemType) {
923 LOG(FATAL, PANDAFILE) << ItemTypeToString(itemType) << " ItemType Error " << static_cast<int>(iType);
924 }
925 return it->second;
926 }
927 return nullptr;
928 }
929
CreateClassItem(File::EntityId classId)930 ClassItem *FileReader::CreateClassItem(File::EntityId classId)
931 {
932 BaseItem *item = CheckAndGetExistingFileItem(classId, ItemTypes::CLASS_ITEM);
933 if (item != nullptr) {
934 return static_cast<ClassItem *>(item);
935 }
936 ClassDataAccessor classAcc(*file_, classId);
937
938 std::string className(utf::Mutf8AsCString(file_->GetStringData(classId).data));
939 auto *classItem = container_.GetOrCreateClassItem(className);
940
941 itemsDone_.insert({classId, static_cast<BaseItem *>(classItem)});
942
943 classItem->SetAccessFlags(classAcc.GetAccessFlags());
944
945 auto sourceLangOpt = classAcc.GetSourceLang();
946 if (sourceLangOpt) {
947 classItem->SetSourceLang(sourceLangOpt.value());
948 }
949
950 auto superClassId = classAcc.GetSuperClassId();
951 if (superClassId.GetOffset() != 0) {
952 if (superClassId.GetOffset() == classId.GetOffset()) {
953 LOG(FATAL, PANDAFILE) << "Class " << className << " has cyclic inheritance";
954 }
955
956 if (file_->IsExternal(superClassId)) {
957 classItem->SetSuperClass(CreateForeignClassItem(superClassId));
958 } else {
959 classItem->SetSuperClass(CreateClassItem(superClassId));
960 }
961 }
962
963 classAcc.EnumerateInterfaces([this, &classItem](File::EntityId ifaceId) {
964 if (file_->IsExternal(ifaceId)) {
965 classItem->AddInterface(CreateForeignClassItem(ifaceId));
966 } else {
967 classItem->AddInterface(CreateClassItem(ifaceId));
968 }
969 });
970
971 classAcc.EnumerateAnnotations(
972 [this, &classItem](File::EntityId annId) { classItem->AddAnnotation(CreateAnnotationItem(annId)); });
973
974 classAcc.EnumerateRuntimeAnnotations(
975 [this, &classItem](File::EntityId annId) { classItem->AddRuntimeAnnotation(CreateAnnotationItem(annId)); });
976
977 classAcc.EnumerateTypeAnnotations(
978 [this, &classItem](File::EntityId annId) { classItem->AddTypeAnnotation(CreateAnnotationItem(annId)); });
979
980 classAcc.EnumerateFields(
981 [this, &classItem](FieldDataAccessor &fieldAcc) { CreateFieldItem(classItem, fieldAcc.GetFieldId()); });
982
983 classAcc.EnumerateMethods(
984 [this, &classItem](MethodDataAccessor &methodAcc) { CreateMethodItem(classItem, methodAcc.GetMethodId()); });
985
986 auto sourceFileId = classAcc.GetSourceFileId();
987 if (sourceFileId) {
988 std::string sourceFile = utf::Mutf8AsCString(file_->GetStringData(sourceFileId.value()).data);
989 classItem->SetSourceFile(container_.GetOrCreateStringItem(sourceFile));
990 }
991
992 ASSERT(classItem != nullptr);
993
994 return classItem;
995 }
996
ReadLiteralArrayItems()997 bool FileReader::ReadLiteralArrayItems()
998 {
999 const auto litArraysId = file_->GetLiteralArraysId();
1000 LiteralDataAccessor litArrayAccessor(*file_, litArraysId);
1001 size_t numLitarrays = litArrayAccessor.GetLiteralNum();
1002
1003 for (size_t i = 0; i < numLitarrays; i++) {
1004 auto id = litArrayAccessor.GetLiteralArrayId(i);
1005 if (!CreateLiteralArrayItem(&litArrayAccessor, id, i)) {
1006 return false;
1007 }
1008 }
1009
1010 return true;
1011 }
1012
TryCreateMethodItem(File::EntityId methodId)1013 bool FileReader::TryCreateMethodItem(File::EntityId methodId)
1014 {
1015 MethodDataAccessor methodAcc(*file_, methodId);
1016 File::EntityId classId(methodAcc.GetClassId());
1017 if (file_->IsExternal(classId)) {
1018 auto *fclassItem = CreateForeignClassItem(classId);
1019 ASSERT(file_->IsExternal(methodId));
1020 if (CreateForeignMethodItem(fclassItem, methodId) == nullptr) {
1021 return false;
1022 }
1023 } else {
1024 auto *classItem = CreateClassItem(classId);
1025 if (file_->IsExternal(methodId)) {
1026 if (CreateForeignMethodItem(classItem, methodId) == nullptr) {
1027 return false;
1028 }
1029 } else if (CreateMethodItem(classItem, methodId) == nullptr) {
1030 return false;
1031 }
1032 }
1033
1034 return true;
1035 }
1036
TryCreateFieldItem(File::EntityId fieldId)1037 bool FileReader::TryCreateFieldItem(File::EntityId fieldId)
1038 {
1039 FieldDataAccessor fieldAcc(*file_, fieldId);
1040 File::EntityId classId(fieldAcc.GetClassId());
1041 if (file_->IsExternal(classId)) {
1042 ASSERT(file_->IsExternal(fieldId));
1043 auto *fclassItem = CreateForeignClassItem(fieldAcc.GetClassId());
1044 if (CreateForeignFieldItem(fclassItem, fieldId) == nullptr) {
1045 return false;
1046 }
1047 } else {
1048 auto *classItem = CreateClassItem(fieldAcc.GetClassId());
1049 if (file_->IsExternal(fieldId)) {
1050 if (CreateForeignFieldItem(classItem, fieldId) == nullptr) {
1051 return false;
1052 }
1053 } else if (CreateFieldItem(classItem, fieldId) == nullptr) {
1054 return false;
1055 }
1056 }
1057
1058 return true;
1059 }
1060
ReadRegionHeaders()1061 bool FileReader::ReadRegionHeaders()
1062 {
1063 auto indexHeaders = file_->GetRegionHeaders();
1064 for (const auto &header : indexHeaders) {
1065 auto methodIndex = file_->GetMethodIndex(&header);
1066 for (auto methodId : methodIndex) {
1067 if (!TryCreateMethodItem(methodId)) {
1068 return false;
1069 }
1070 }
1071 auto fieldIndex = file_->GetFieldIndex(&header);
1072 for (auto fieldId : fieldIndex) {
1073 if (!TryCreateFieldItem(fieldId)) {
1074 return false;
1075 }
1076 }
1077 }
1078 return true;
1079 }
1080
ReadClasses()1081 bool FileReader::ReadClasses()
1082 {
1083 const auto classIdx = file_->GetClasses();
1084
1085 for (unsigned int id : classIdx) {
1086 File::EntityId eid(id);
1087 if (file_->IsExternal(eid)) {
1088 CreateForeignClassItem(eid);
1089 } else {
1090 CreateClassItem(eid);
1091 }
1092 }
1093
1094 return true;
1095 }
1096
UpdateDebugInfoDependecies(File::EntityId debugInfoId)1097 void FileReader::UpdateDebugInfoDependecies(File::EntityId debugInfoId)
1098 {
1099 auto updater = FileReaderDebugInfoUpdater(file_.get(), &container_);
1100 updater.Scrap(debugInfoId);
1101 }
1102
UpdateDebugInfo(DebugInfoItem * debugInfoItem,File::EntityId debugInfoId)1103 void FileReader::UpdateDebugInfo(DebugInfoItem *debugInfoItem, File::EntityId debugInfoId)
1104 {
1105 auto updater = FileReaderDebugInfoUpdater(file_.get(), &container_);
1106 updater.Emit(debugInfoItem->GetLineNumberProgram(), debugInfoItem->GetConstantPool(), debugInfoId);
1107 }
1108
InstCheckByFlags(BytecodeInstruction & inst,MethodItem * methodItem,const std::map<BaseItem *,File::EntityId> & reverseDone)1109 void FileReader::InstCheckByFlags(BytecodeInstruction &inst, MethodItem *methodItem,
1110 const std::map<BaseItem *, File::EntityId> &reverseDone)
1111 {
1112 using Flags = ark::BytecodeInst<ark::BytecodeInstMode::FAST>::Flags;
1113
1114 if (inst.HasFlag(Flags::TYPE_ID)) {
1115 BytecodeId bId = inst.GetId();
1116 File::Index idx = bId.AsIndex();
1117 File::EntityId methodId = reverseDone.find(methodItem)->second;
1118 File::EntityId oldId = file_->ResolveClassIndex(methodId, idx);
1119 ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1120 auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1121 methodItem->AddIndexDependency(idxItem);
1122 } else if (inst.HasFlag(Flags::METHOD_ID) || inst.HasFlag(Flags::STATIC_METHOD_ID)) {
1123 BytecodeId bId = inst.GetId();
1124 File::Index idx = bId.AsIndex();
1125 File::EntityId methodId = reverseDone.find(methodItem)->second;
1126 File::EntityId oldId = file_->ResolveMethodIndex(methodId, idx);
1127 ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1128 auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1129 methodItem->AddIndexDependency(idxItem);
1130 } else if (inst.HasFlag(Flags::FIELD_ID) || inst.HasFlag(Flags::STATIC_FIELD_ID)) {
1131 BytecodeId bId = inst.GetId();
1132 File::Index idx = bId.AsIndex();
1133 File::EntityId methodId = reverseDone.find(methodItem)->second;
1134 File::EntityId oldId = file_->ResolveFieldIndex(methodId, idx);
1135 ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1136 auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1137 methodItem->AddIndexDependency(idxItem);
1138 } else if (inst.HasFlag(Flags::STRING_ID)) {
1139 BytecodeId bId = inst.GetId();
1140 File::EntityId oldId = bId.AsFileId();
1141 auto data = file_->GetStringData(oldId);
1142 std::string itemStr(utf::Mutf8AsCString(data.data));
1143 container_.GetOrCreateStringItem(itemStr);
1144 }
1145 }
1146
UpdateCodeAndDebugInfoDependencies(const std::map<BaseItem *,File::EntityId> & reverseDone)1147 void FileReader::UpdateCodeAndDebugInfoDependencies(const std::map<BaseItem *, File::EntityId> &reverseDone)
1148 {
1149 auto *classMap = container_.GetClassMap();
1150
1151 // First pass, add dependencies bytecode -> new items
1152 for (const auto &it : *classMap) {
1153 auto *baseClassItem = it.second;
1154 if (baseClassItem->IsForeign()) {
1155 continue;
1156 }
1157 auto *classItem = static_cast<ClassItem *>(baseClassItem);
1158 classItem->VisitMethods([this, &reverseDone](BaseItem *paramItem) {
1159 auto *methodItem = static_cast<MethodItem *>(paramItem);
1160 auto *codeItem = methodItem->GetCode();
1161 if (codeItem == nullptr) {
1162 return true;
1163 }
1164
1165 auto *debugInfoItem = methodItem->GetDebugInfo();
1166 if (debugInfoItem != nullptr) {
1167 UpdateDebugInfoDependecies(reverseDone.find(debugInfoItem)->second);
1168 }
1169
1170 size_t offset = 0;
1171 BytecodeInstruction inst(codeItem->GetInstructions()->data());
1172 while (offset < codeItem->GetCodeSize()) {
1173 InstCheckByFlags(inst, methodItem, reverseDone);
1174
1175 offset += inst.GetSize();
1176 inst = inst.GetNext();
1177 }
1178 return true;
1179 });
1180 }
1181 }
1182
InstUpdateId(CodeItem * codeItem,MethodItem * methodItem,std::map<BaseItem *,File::EntityId> & reverseDone)1183 void FileReader::InstUpdateId(CodeItem *codeItem, MethodItem *methodItem,
1184 std::map<BaseItem *, File::EntityId> &reverseDone)
1185 {
1186 using Flags = ark::BytecodeInst<ark::BytecodeInstMode::FAST>::Flags;
1187
1188 size_t offset = 0;
1189 BytecodeInstruction inst(codeItem->GetInstructions()->data());
1190 while (offset < codeItem->GetCodeSize()) {
1191 if (inst.HasFlag(Flags::TYPE_ID)) {
1192 BytecodeId bId = inst.GetId();
1193 File::Index idx = bId.AsIndex();
1194
1195 File::EntityId methodId = reverseDone.find(methodItem)->second;
1196 File::EntityId oldId = file_->ResolveClassIndex(methodId, idx);
1197 ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1198
1199 auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1200 uint32_t index = idxItem->GetIndex(methodItem);
1201 inst.UpdateId(BytecodeId(index));
1202 } else if (inst.HasFlag(Flags::METHOD_ID) || inst.HasFlag(Flags::STATIC_METHOD_ID)) {
1203 BytecodeId bId = inst.GetId();
1204 File::Index idx = bId.AsIndex();
1205
1206 File::EntityId methodId = reverseDone.find(methodItem)->second;
1207 File::EntityId oldId = file_->ResolveMethodIndex(methodId, idx);
1208 ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1209
1210 auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1211 uint32_t index = idxItem->GetIndex(methodItem);
1212 inst.UpdateId(BytecodeId(index));
1213 } else if (inst.HasFlag(Flags::FIELD_ID) || inst.HasFlag(Flags::STATIC_FIELD_ID)) {
1214 BytecodeId bId = inst.GetId();
1215 File::Index idx = bId.AsIndex();
1216
1217 File::EntityId methodId = reverseDone.find(methodItem)->second;
1218 File::EntityId oldId = file_->ResolveFieldIndex(methodId, idx);
1219 ASSERT(itemsDone_.find(oldId) != itemsDone_.end());
1220
1221 auto *idxItem = static_cast<IndexedItem *>(itemsDone_.find(oldId)->second);
1222 uint32_t index = idxItem->GetIndex(methodItem);
1223 inst.UpdateId(BytecodeId(index));
1224 } else if (inst.HasFlag(Flags::STRING_ID)) {
1225 BytecodeId bId = inst.GetId();
1226 File::EntityId oldId = bId.AsFileId();
1227 auto data = file_->GetStringData(oldId);
1228
1229 std::string itemStr(utf::Mutf8AsCString(data.data));
1230 auto *stringItem = container_.GetOrCreateStringItem(itemStr);
1231 inst.UpdateId(BytecodeId(stringItem->GetFileId().GetOffset()));
1232 }
1233
1234 offset += inst.GetSize();
1235 inst = inst.GetNext();
1236 }
1237 }
1238
ComputeLayoutAndUpdateIndices()1239 void FileReader::ComputeLayoutAndUpdateIndices()
1240 {
1241 std::map<BaseItem *, File::EntityId> reverseDone;
1242 for (const auto &it : itemsDone_) {
1243 reverseDone.insert({it.second, it.first});
1244 }
1245
1246 auto *classMap = container_.GetClassMap();
1247
1248 UpdateCodeAndDebugInfoDependencies(reverseDone);
1249
1250 container_.ComputeLayout();
1251
1252 // Second pass, update debug info
1253 for (const auto &it : *classMap) {
1254 auto *baseClassItem = it.second;
1255 if (baseClassItem->IsForeign()) {
1256 continue;
1257 }
1258 auto *classItem = static_cast<ClassItem *>(baseClassItem);
1259 classItem->VisitMethods([this, &reverseDone](BaseItem *paramItem) {
1260 auto *methodItem = static_cast<MethodItem *>(paramItem);
1261 auto *codeItem = methodItem->GetCode();
1262 if (codeItem == nullptr) {
1263 return true;
1264 }
1265
1266 auto *debugInfoItem = methodItem->GetDebugInfo();
1267 if (debugInfoItem != nullptr) {
1268 UpdateDebugInfo(debugInfoItem, reverseDone.find(debugInfoItem)->second);
1269 }
1270
1271 return true;
1272 });
1273 }
1274
1275 container_.DeduplicateItems(false);
1276 container_.ComputeLayout();
1277
1278 std::unordered_set<CodeItem *> codeItemsDone;
1279
1280 // Third pass, update bytecode indices
1281 for (const auto &it : *classMap) {
1282 auto *baseClassItem = it.second;
1283 if (baseClassItem->IsForeign()) {
1284 continue;
1285 }
1286 auto *classItem = static_cast<ClassItem *>(baseClassItem);
1287 classItem->VisitMethods([this, &reverseDone, &codeItemsDone](BaseItem *paramItem) {
1288 auto *methodItem = static_cast<MethodItem *>(paramItem);
1289 auto *codeItem = methodItem->GetCode();
1290
1291 auto codeIt = codeItemsDone.find(codeItem);
1292 if (codeItem == nullptr || codeIt != codeItemsDone.end()) {
1293 return true;
1294 }
1295
1296 InstUpdateId(codeItem, methodItem, reverseDone);
1297
1298 codeItemsDone.insert(codeItem);
1299
1300 return true;
1301 });
1302 }
1303 }
1304
1305 } // namespace ark::panda_file
1306