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