1 /**
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "file_items.h"
17 #include "macros.h"
18 #include "utils/bit_utils.h"
19 #include "utils/leb128.h"
20 #include "utils/utf.h"
21
22 #include <iomanip>
23
24 namespace ark::panda_file {
25
26 #include "file_items_gen.inc"
27
28 size_t IndexedItem::itemAllocIdNext_ = 0;
29
30 template <class Tag, class Val>
WriteUlebTaggedValue(Writer * writer,Tag tag,Val v)31 static bool WriteUlebTaggedValue(Writer *writer, Tag tag, Val v)
32 {
33 if (!writer->WriteByte(static_cast<uint8_t>(tag))) {
34 return false;
35 }
36
37 if (!writer->WriteUleb128(v)) {
38 return false;
39 }
40
41 return true;
42 }
43
44 template <class Tag, class Val>
WriteSlebTaggedValue(Writer * writer,Tag tag,Val v)45 static bool WriteSlebTaggedValue(Writer *writer, Tag tag, Val v)
46 {
47 if (!writer->WriteByte(static_cast<uint8_t>(tag))) {
48 return false;
49 }
50
51 if (!writer->WriteSleb128(v)) {
52 return false;
53 }
54
55 return true;
56 }
57
58 template <class Tag, class Val>
WriteTaggedValue(Writer * writer,Tag tag,Val v)59 static bool WriteTaggedValue(Writer *writer, Tag tag, Val v)
60 {
61 if (!writer->WriteByte(static_cast<uint8_t>(tag))) {
62 return false;
63 }
64
65 if (!writer->Write(v)) {
66 return false;
67 }
68
69 return true;
70 }
71
72 template <class Tag>
WriteIdTaggedValue(Writer * writer,Tag tag,BaseItem * item)73 static bool WriteIdTaggedValue(Writer *writer, Tag tag, BaseItem *item)
74 {
75 ASSERT(item->GetOffset() != 0);
76 return WriteTaggedValue(writer, tag, item->GetOffset());
77 }
78
79 // CC-OFFNXT(G.FUN.01-CPP, huge_cyclomatic_complexity[C++], huge_method[C++]) big switch case
ItemTypeToString(ItemTypes type)80 std::string ItemTypeToString(ItemTypes type)
81 {
82 switch (type) {
83 case ItemTypes::ANNOTATION_ITEM:
84 return "annotation_item";
85 case ItemTypes::CATCH_BLOCK_ITEM:
86 return "catch_block_item";
87 case ItemTypes::CLASS_INDEX_ITEM:
88 return "class_index_item";
89 case ItemTypes::CLASS_ITEM:
90 return "class_item";
91 case ItemTypes::CODE_ITEM:
92 return "code_item";
93 case ItemTypes::DEBUG_INFO_ITEM:
94 return "debug_info_item";
95 case ItemTypes::END_ITEM:
96 return "end_item";
97 case ItemTypes::FIELD_INDEX_ITEM:
98 return "field_index_item";
99 case ItemTypes::FIELD_ITEM:
100 return "field_item";
101 case ItemTypes::FOREIGN_CLASS_ITEM:
102 return "foreign_class_item";
103 case ItemTypes::FOREIGN_FIELD_ITEM:
104 return "foreign_field_item";
105 case ItemTypes::FOREIGN_METHOD_ITEM:
106 return "foreign_method_item";
107 case ItemTypes::LINE_NUMBER_PROGRAM_INDEX_ITEM:
108 return "line_number_program_index_item";
109 case ItemTypes::LINE_NUMBER_PROGRAM_ITEM:
110 return "line_number_program_item";
111 case ItemTypes::LITERAL_ARRAY_ITEM:
112 return "literal_array_item";
113 case ItemTypes::LITERAL_ITEM:
114 return "literal_item";
115 case ItemTypes::METHOD_HANDLE_ITEM:
116 return "method_handle_item";
117 case ItemTypes::METHOD_INDEX_ITEM:
118 return "method_index_item";
119 case ItemTypes::METHOD_ITEM:
120 return "method_item";
121 case ItemTypes::PARAM_ANNOTATIONS_ITEM:
122 return "param_annotations_item";
123 case ItemTypes::PRIMITIVE_TYPE_ITEM:
124 return "primitive_type_item";
125 case ItemTypes::PROTO_INDEX_ITEM:
126 return "proto_index_item";
127 case ItemTypes::PROTO_ITEM:
128 return "proto_item";
129 case ItemTypes::REGION_HEADER:
130 return "region_header";
131 case ItemTypes::REGION_SECTION:
132 return "region_section";
133 case ItemTypes::STRING_ITEM:
134 return "string_item";
135 case ItemTypes::TRY_BLOCK_ITEM:
136 return "try_block_item";
137 case ItemTypes::VALUE_ITEM:
138 return "value_item";
139 default:
140 return "";
141 }
142 }
143
GetName() const144 std::string BaseItem::GetName() const
145 {
146 return ItemTypeToString(GetItemType());
147 }
148
StringItem(std::string str)149 StringItem::StringItem(std::string str) : str_(std::move(str))
150 {
151 str_.push_back(0);
152 utf16Length_ = utf::MUtf8ToUtf16Size(utf::CStringAsMutf8(str_.data()));
153 isAscii_ = 1;
154
155 for (auto c : str_) {
156 if (static_cast<uint8_t>(c) > utf::UTF8_1B_MAX) {
157 isAscii_ = 0;
158 break;
159 }
160 }
161 }
162
StringItem(File::StringData data)163 StringItem::StringItem(File::StringData data)
164 : str_(reinterpret_cast<const char *>(data.data)), utf16Length_(data.utf16Length)
165 {
166 }
167
CalculateSize() const168 size_t StringItem::CalculateSize() const
169 {
170 size_t n = str_.size();
171 return leb128::UnsignedEncodingSize((utf16Length_ << 1U) | isAscii_) + n;
172 }
173
Write(Writer * writer)174 bool StringItem::Write(Writer *writer)
175 {
176 ASSERT(GetOffset() == writer->GetOffset());
177 constexpr size_t MAX_LENGTH = 0x7fffffffU;
178 if (utf16Length_ > MAX_LENGTH) {
179 LOG(ERROR, PANDAFILE) << "Writing StringItem with size greater than 0x7fffffffU is not supported!";
180 return false;
181 }
182
183 if (!writer->WriteUleb128((utf16Length_ << 1U) | isAscii_)) {
184 return false;
185 }
186
187 for (auto c : str_) {
188 if (!writer->WriteByte(static_cast<uint8_t>(c))) {
189 return false;
190 }
191 }
192 return true;
193 }
194
CalculateSize() const195 size_t BaseClassItem::CalculateSize() const
196 {
197 return name_.GetSize();
198 }
199
ComputeLayout()200 void BaseClassItem::ComputeLayout()
201 {
202 uint32_t offset = GetOffset();
203
204 ASSERT(offset != 0);
205
206 name_.SetOffset(offset);
207 }
208
Write(Writer * writer)209 bool BaseClassItem::Write(Writer *writer)
210 {
211 ASSERT(GetOffset() == writer->GetOffset());
212 return name_.Write(writer);
213 }
214
CalculateSizeWithoutFieldsAndMethods() const215 size_t ClassItem::CalculateSizeWithoutFieldsAndMethods() const
216 {
217 size_t size = BaseClassItem::CalculateSize() + ID_SIZE + leb128::UnsignedEncodingSize(accessFlags_);
218
219 size += leb128::UnsignedEncodingSize(fields_.size());
220 size += leb128::UnsignedEncodingSize(methods_.size());
221
222 if (!ifaces_.empty()) {
223 size += TAG_SIZE + leb128::UnsignedEncodingSize(ifaces_.size()) + IDX_SIZE * ifaces_.size();
224 }
225
226 if (sourceLang_ != SourceLang::PANDA_ASSEMBLY) {
227 size += TAG_SIZE + sizeof(SourceLang);
228 }
229
230 size += (TAG_SIZE + ID_SIZE) * runtimeAnnotations_.size();
231 size += (TAG_SIZE + ID_SIZE) * annotations_.size();
232 size += (TAG_SIZE + ID_SIZE) * runtimeTypeAnnotations_.size();
233 size += (TAG_SIZE + ID_SIZE) * typeAnnotations_.size();
234
235 if (sourceFile_ != nullptr) {
236 size += TAG_SIZE + ID_SIZE;
237 }
238
239 size += TAG_SIZE; // null tag
240
241 return size;
242 }
243
CalculateSize() const244 size_t ClassItem::CalculateSize() const
245 {
246 size_t size = CalculateSizeWithoutFieldsAndMethods();
247
248 for (auto &field : fields_) {
249 size += field->GetSize();
250 }
251
252 for (auto &method : methods_) {
253 size += method->GetSize();
254 }
255
256 return size;
257 }
258
ComputeLayout()259 void ClassItem::ComputeLayout()
260 {
261 BaseClassItem::ComputeLayout();
262
263 uint32_t offset = GetOffset();
264
265 offset += CalculateSizeWithoutFieldsAndMethods();
266
267 for (auto &field : fields_) {
268 field->SetOffset(offset);
269 field->ComputeLayout();
270 offset += field->GetSize();
271 }
272
273 for (auto &method : methods_) {
274 method->SetOffset(offset);
275 method->ComputeLayout();
276 offset += method->GetSize();
277 }
278 }
279
WriteIfaces(Writer * writer)280 bool ClassItem::WriteIfaces(Writer *writer)
281 {
282 if (!ifaces_.empty()) {
283 if (!writer->WriteByte(static_cast<uint8_t>(ClassTag::INTERFACES))) {
284 return false;
285 }
286
287 if (!writer->WriteUleb128(ifaces_.size())) {
288 return false;
289 }
290
291 for (auto iface : ifaces_) {
292 ASSERT(iface->HasIndex(this));
293 if (!writer->Write<uint16_t>(iface->GetIndex(this))) {
294 return false;
295 }
296 }
297 }
298
299 return true;
300 }
301
WriteAnnotations(Writer * writer)302 bool ClassItem::WriteAnnotations(Writer *writer)
303 {
304 for (auto runtimeAnnotation : runtimeAnnotations_) {
305 if (!WriteIdTaggedValue(writer, ClassTag::RUNTIME_ANNOTATION, runtimeAnnotation)) {
306 return false;
307 }
308 }
309
310 for (auto annotation : annotations_) {
311 if (!WriteIdTaggedValue(writer, ClassTag::ANNOTATION, annotation)) {
312 return false;
313 }
314 }
315
316 for (auto runtimeTypeAnnotation : runtimeTypeAnnotations_) {
317 if (!WriteIdTaggedValue(writer, ClassTag::RUNTIME_TYPE_ANNOTATION, runtimeTypeAnnotation)) {
318 return false;
319 }
320 }
321
322 for (auto typeAnnotation : typeAnnotations_) {
323 if (!WriteIdTaggedValue(writer, ClassTag::TYPE_ANNOTATION, typeAnnotation)) {
324 return false;
325 }
326 }
327
328 return true;
329 }
330
WriteTaggedData(Writer * writer)331 bool ClassItem::WriteTaggedData(Writer *writer)
332 {
333 if (!WriteIfaces(writer)) {
334 return false;
335 }
336
337 if (sourceLang_ != SourceLang::PANDA_ASSEMBLY) {
338 if (!WriteTaggedValue(writer, ClassTag::SOURCE_LANG, static_cast<uint8_t>(sourceLang_))) {
339 return false;
340 }
341 }
342
343 if (!WriteAnnotations(writer)) {
344 return false;
345 }
346
347 if (sourceFile_ != nullptr) {
348 if (!WriteIdTaggedValue(writer, ClassTag::SOURCE_FILE, sourceFile_)) {
349 return false;
350 }
351 }
352
353 return writer->WriteByte(static_cast<uint8_t>(ClassTag::NOTHING));
354 }
355
Write(Writer * writer)356 bool ClassItem::Write(Writer *writer)
357 {
358 if (!BaseClassItem::Write(writer)) {
359 return false;
360 }
361
362 uint32_t offset = superClass_ != nullptr ? superClass_->GetOffset() : 0;
363 if (!writer->Write(offset)) {
364 return false;
365 }
366
367 if (!writer->WriteUleb128(accessFlags_)) {
368 return false;
369 }
370
371 if (!writer->WriteUleb128(fields_.size())) {
372 return false;
373 }
374
375 if (!writer->WriteUleb128(methods_.size())) {
376 return false;
377 }
378
379 if (!WriteTaggedData(writer)) {
380 return false;
381 }
382
383 for (auto &field : fields_) {
384 if (!field->Write(writer)) {
385 return false;
386 }
387 }
388
389 for (auto &method : methods_) {
390 if (!method->Write(writer)) {
391 return false;
392 }
393 }
394
395 return true;
396 }
397
ParamAnnotationsItem(MethodItem * method,bool isRuntimeAnnotations)398 ParamAnnotationsItem::ParamAnnotationsItem(MethodItem *method, bool isRuntimeAnnotations)
399 {
400 for (const auto ¶m : method->GetParams()) {
401 if (isRuntimeAnnotations) {
402 annotations_.push_back(param.GetRuntimeAnnotations());
403 } else {
404 annotations_.push_back(param.GetAnnotations());
405 }
406 }
407
408 if (isRuntimeAnnotations) {
409 method->SetRuntimeParamAnnotationItem(this);
410 } else {
411 method->SetParamAnnotationItem(this);
412 }
413 }
414
CalculateSize() const415 size_t ParamAnnotationsItem::CalculateSize() const
416 {
417 size_t size = sizeof(uint32_t); // size
418
419 for (const auto ¶mAnnotations : annotations_) {
420 size += sizeof(uint32_t); // count
421 size += paramAnnotations.size() * ID_SIZE;
422 }
423
424 return size;
425 }
426
Write(Writer * writer)427 bool ParamAnnotationsItem::Write(Writer *writer)
428 {
429 ASSERT(GetOffset() == writer->GetOffset());
430
431 if (!writer->Write(static_cast<uint32_t>(annotations_.size()))) {
432 return false;
433 }
434
435 for (const auto ¶mAnnotations : annotations_) {
436 if (!writer->Write(static_cast<uint32_t>(paramAnnotations.size()))) {
437 return false;
438 }
439
440 for (auto *item : paramAnnotations) {
441 ASSERT(item->GetOffset() != 0);
442
443 if (!writer->Write(item->GetOffset())) {
444 return false;
445 }
446 }
447 }
448
449 return true;
450 }
451
ProtoItem(TypeItem * retType,const std::vector<MethodParamItem> & params)452 ProtoItem::ProtoItem(TypeItem *retType, const std::vector<MethodParamItem> ¶ms)
453 {
454 size_t n = 0;
455 shorty_.push_back(0);
456 AddType(retType, &n);
457 for (auto &p : params) {
458 AddType(p.GetType(), &n);
459 }
460 }
461
AddType(TypeItem * type,size_t * n)462 void ProtoItem::AddType(TypeItem *type, size_t *n)
463 {
464 constexpr size_t SHORTY_ELEMS_COUNT = std::numeric_limits<uint16_t>::digits / SHORTY_ELEM_SIZE;
465
466 uint16_t v = shorty_.back();
467
468 size_t shift = (*n % SHORTY_ELEMS_COUNT) * SHORTY_ELEM_SIZE;
469
470 v |= static_cast<uint16_t>(static_cast<uint16_t>(type->GetType().GetEncoding()) << shift);
471 shorty_.back() = v;
472
473 if (!type->GetType().IsPrimitive()) {
474 referenceTypes_.push_back(type);
475 AddIndexDependency(type);
476 }
477
478 *n += 1;
479
480 if (*n % SHORTY_ELEMS_COUNT == 0) {
481 shorty_.push_back(0);
482 }
483 }
484
Write(Writer * writer)485 bool ProtoItem::Write(Writer *writer)
486 {
487 ASSERT(GetOffset() == writer->GetOffset());
488 for (auto s : shorty_) {
489 if (!writer->Write(s)) {
490 return false;
491 }
492 }
493
494 for (auto r : referenceTypes_) {
495 ASSERT(r->HasIndex(this));
496 if (!writer->Write<uint16_t>(r->GetIndex(this))) {
497 return false;
498 }
499 }
500
501 return true;
502 }
503
BaseMethodItem(BaseClassItem * cls,StringItem * name,ProtoItem * proto,uint32_t accessFlags)504 BaseMethodItem::BaseMethodItem(BaseClassItem *cls, StringItem *name, ProtoItem *proto, uint32_t accessFlags)
505 : class_(cls), name_(name), proto_(proto), accessFlags_(accessFlags)
506 {
507 AddIndexDependency(cls);
508 AddIndexDependency(proto);
509 }
510
CalculateSize() const511 size_t BaseMethodItem::CalculateSize() const
512 {
513 // class id + proto id + name id + access flags
514 return IDX_SIZE + IDX_SIZE + ID_SIZE + leb128::UnsignedEncodingSize(accessFlags_);
515 }
516
Write(Writer * writer)517 bool BaseMethodItem::Write(Writer *writer)
518 {
519 ASSERT(GetOffset() == writer->GetOffset());
520 ASSERT(class_ != nullptr);
521 ASSERT(class_->HasIndex(this));
522
523 if (!writer->Write<uint16_t>(class_->GetIndex(this))) {
524 return false;
525 }
526
527 ASSERT(proto_->HasIndex(this));
528
529 if (!writer->Write<uint16_t>(proto_->GetIndex(this))) {
530 return false;
531 }
532
533 ASSERT(name_->GetOffset() != 0);
534
535 if (!writer->Write(name_->GetOffset())) {
536 return false;
537 }
538
539 return writer->WriteUleb128(accessFlags_);
540 }
541
MethodItem(ClassItem * cls,StringItem * name,ProtoItem * proto,uint32_t accessFlags,std::vector<MethodParamItem> params)542 MethodItem::MethodItem(ClassItem *cls, StringItem *name, ProtoItem *proto, uint32_t accessFlags,
543 std::vector<MethodParamItem> params)
544 : BaseMethodItem(cls, name, proto, accessFlags), params_(std::move(params))
545 {
546 }
547
CalculateSize() const548 size_t MethodItem::CalculateSize() const
549 {
550 size_t size = BaseMethodItem::CalculateSize();
551
552 if (code_ != nullptr) {
553 size += TAG_SIZE + ID_SIZE;
554 }
555
556 if (sourceLang_ != SourceLang::PANDA_ASSEMBLY) {
557 size += TAG_SIZE + sizeof(SourceLang);
558 }
559
560 size += (TAG_SIZE + ID_SIZE) * runtimeAnnotations_.size();
561
562 if (runtimeParamAnnotations_ != nullptr) {
563 size += TAG_SIZE + ID_SIZE;
564 }
565
566 size += (TAG_SIZE + ID_SIZE) * annotations_.size();
567
568 if (paramAnnotations_ != nullptr) {
569 size += TAG_SIZE + ID_SIZE;
570 }
571
572 size += (TAG_SIZE + ID_SIZE) * runtimeTypeAnnotations_.size();
573 size += (TAG_SIZE + ID_SIZE) * typeAnnotations_.size();
574
575 if (debugInfo_ != nullptr) {
576 size += TAG_SIZE + ID_SIZE;
577 }
578
579 if (profileSize_ != 0) {
580 size += TAG_SIZE + sizeof(profileSize_);
581 }
582
583 size += TAG_SIZE; // null tag
584
585 return size;
586 }
587
WriteRuntimeAnnotations(Writer * writer)588 bool MethodItem::WriteRuntimeAnnotations(Writer *writer)
589 {
590 for (auto runtimeAnnotation : runtimeAnnotations_) {
591 if (!WriteIdTaggedValue(writer, MethodTag::RUNTIME_ANNOTATION, runtimeAnnotation)) {
592 return false;
593 }
594 }
595
596 if (runtimeParamAnnotations_ != nullptr) {
597 if (!WriteIdTaggedValue(writer, MethodTag::RUNTIME_PARAM_ANNOTATION, runtimeParamAnnotations_)) {
598 return false;
599 }
600 }
601
602 return true;
603 }
604
WriteTypeAnnotations(Writer * writer)605 bool MethodItem::WriteTypeAnnotations(Writer *writer)
606 {
607 for (auto runtimeTypeAnnotation : runtimeTypeAnnotations_) {
608 if (!WriteIdTaggedValue(writer, MethodTag::RUNTIME_TYPE_ANNOTATION, runtimeTypeAnnotation)) {
609 return false;
610 }
611 }
612
613 for (auto typeAnnotation : typeAnnotations_) {
614 if (!WriteIdTaggedValue(writer, MethodTag::TYPE_ANNOTATION, typeAnnotation)) {
615 return false;
616 }
617 }
618
619 return true;
620 }
621
WriteTaggedData(Writer * writer)622 bool MethodItem::WriteTaggedData(Writer *writer)
623 {
624 if (code_ != nullptr) {
625 if (!WriteIdTaggedValue(writer, MethodTag::CODE, code_)) {
626 return false;
627 }
628 }
629
630 if (sourceLang_ != SourceLang::PANDA_ASSEMBLY) {
631 if (!WriteTaggedValue(writer, MethodTag::SOURCE_LANG, static_cast<uint8_t>(sourceLang_))) {
632 return false;
633 }
634 }
635
636 if (!WriteRuntimeAnnotations(writer)) {
637 return false;
638 }
639
640 if (debugInfo_ != nullptr) {
641 if (!WriteIdTaggedValue(writer, MethodTag::DEBUG_INFO, debugInfo_)) {
642 return false;
643 }
644 }
645
646 for (auto annotation : annotations_) {
647 if (!WriteIdTaggedValue(writer, MethodTag::ANNOTATION, annotation)) {
648 return false;
649 }
650 }
651
652 if (!WriteTypeAnnotations(writer)) {
653 return false;
654 }
655
656 if (paramAnnotations_ != nullptr) {
657 if (!WriteIdTaggedValue(writer, MethodTag::PARAM_ANNOTATION, paramAnnotations_)) {
658 return false;
659 }
660 }
661
662 if (profileSize_ != 0) {
663 if (!WriteTaggedValue(writer, MethodTag::PROFILE_INFO, static_cast<uint16_t>(profileSize_))) {
664 return false;
665 }
666 }
667
668 return writer->WriteByte(static_cast<uint8_t>(MethodTag::NOTHING));
669 }
670
Write(Writer * writer)671 bool MethodItem::Write(Writer *writer)
672 {
673 if (!BaseMethodItem::Write(writer)) {
674 return false;
675 }
676
677 return WriteTaggedData(writer);
678 }
679
CalculateSize() const680 size_t CodeItem::CatchBlock::CalculateSize() const
681 {
682 ASSERT(type_ == nullptr || type_->HasIndex(method_));
683 uint32_t typeOff = type_ != nullptr ? type_->GetIndex(method_) + 1 : 0;
684 return leb128::UnsignedEncodingSize(typeOff) + leb128::UnsignedEncodingSize(handlerPc_) +
685 leb128::UnsignedEncodingSize(codeSize_);
686 }
687
Write(Writer * writer)688 bool CodeItem::CatchBlock::Write(Writer *writer)
689 {
690 ASSERT(GetOffset() == writer->GetOffset());
691 ASSERT(type_ == nullptr || type_->HasIndex(method_));
692
693 uint32_t typeOff = type_ != nullptr ? type_->GetIndex(method_) + 1 : 0;
694 if (!writer->WriteUleb128(typeOff)) {
695 return false;
696 }
697
698 if (!writer->WriteUleb128(handlerPc_)) {
699 return false;
700 }
701
702 if (!writer->WriteUleb128(codeSize_)) {
703 return false;
704 }
705
706 return true;
707 }
708
ComputeLayout()709 void CodeItem::TryBlock::ComputeLayout()
710 {
711 size_t offset = GetOffset();
712 offset += CalculateSizeWithoutCatchBlocks();
713
714 for (auto &catchBlock : catchBlocks_) {
715 catchBlock.SetOffset(offset);
716 catchBlock.ComputeLayout();
717 offset += catchBlock.GetSize();
718 }
719 }
720
CalculateSizeWithoutCatchBlocks() const721 size_t CodeItem::TryBlock::CalculateSizeWithoutCatchBlocks() const
722 {
723 return leb128::UnsignedEncodingSize(startPc_) + leb128::UnsignedEncodingSize(length_) +
724 leb128::UnsignedEncodingSize(catchBlocks_.size());
725 }
726
CalculateSize() const727 size_t CodeItem::TryBlock::CalculateSize() const
728 {
729 size_t size = CalculateSizeWithoutCatchBlocks();
730
731 for (auto &catchBlock : catchBlocks_) {
732 size += catchBlock.GetSize();
733 }
734
735 return size;
736 }
737
Write(Writer * writer)738 bool CodeItem::TryBlock::Write(Writer *writer)
739 {
740 ASSERT(GetOffset() == writer->GetOffset());
741
742 if (!writer->WriteUleb128(startPc_)) {
743 return false;
744 }
745
746 if (!writer->WriteUleb128(length_)) {
747 return false;
748 }
749
750 if (!writer->WriteUleb128(catchBlocks_.size())) {
751 return false;
752 }
753
754 for (auto &catchBlock : catchBlocks_) {
755 if (!catchBlock.Write(writer)) {
756 return false;
757 }
758 }
759
760 return true;
761 }
762
ComputeLayout()763 void CodeItem::ComputeLayout()
764 {
765 uint32_t offset = GetOffset();
766
767 offset += CalculateSizeWithoutTryBlocks();
768
769 for (auto &tryBlock : tryBlocks_) {
770 tryBlock.SetOffset(offset);
771 tryBlock.ComputeLayout();
772 offset += tryBlock.GetSize();
773 }
774 }
775
CalculateSizeWithoutTryBlocks() const776 size_t CodeItem::CalculateSizeWithoutTryBlocks() const
777 {
778 size_t size = leb128::UnsignedEncodingSize(numVregs_) + leb128::UnsignedEncodingSize(numArgs_) +
779 leb128::UnsignedEncodingSize(instructions_.size()) + leb128::UnsignedEncodingSize(tryBlocks_.size());
780
781 size += instructions_.size();
782
783 return size;
784 }
785
GetCodeSize() const786 size_t CodeItem::GetCodeSize() const
787 {
788 return instructions_.size();
789 }
790
CalculateSize() const791 size_t CodeItem::CalculateSize() const
792 {
793 size_t size = CalculateSizeWithoutTryBlocks();
794
795 for (auto &tryBlock : tryBlocks_) {
796 size += tryBlock.GetSize();
797 }
798
799 return size;
800 }
801
Write(Writer * writer)802 bool CodeItem::Write(Writer *writer)
803 {
804 ASSERT(GetOffset() == writer->GetOffset());
805
806 if (!writer->WriteUleb128(numVregs_)) {
807 return false;
808 }
809
810 if (!writer->WriteUleb128(numArgs_)) {
811 return false;
812 }
813
814 if (!writer->WriteUleb128(instructions_.size())) {
815 return false;
816 }
817
818 if (!writer->WriteUleb128(tryBlocks_.size())) {
819 return false;
820 }
821
822 if (!writer->WriteBytes(instructions_)) {
823 return false;
824 }
825
826 for (auto &tryBlock : tryBlocks_) {
827 if (!tryBlock.Write(writer)) {
828 return false;
829 }
830 }
831
832 return true;
833 }
834
GetAsScalar()835 ScalarValueItem *ValueItem::GetAsScalar()
836 {
837 ASSERT(!IsArray());
838 return static_cast<ScalarValueItem *>(this);
839 }
840
GetAsArray()841 ArrayValueItem *ValueItem::GetAsArray()
842 {
843 ASSERT(IsArray());
844 return static_cast<ArrayValueItem *>(this);
845 }
846
GetULeb128EncodedSize()847 size_t ScalarValueItem::GetULeb128EncodedSize()
848 {
849 switch (GetType()) {
850 case Type::INTEGER:
851 return leb128::UnsignedEncodingSize(GetValue<uint32_t>());
852
853 case Type::LONG:
854 return leb128::UnsignedEncodingSize(GetValue<uint64_t>());
855
856 case Type::ID:
857 return leb128::UnsignedEncodingSize(GetId().GetOffset());
858
859 default:
860 return 0;
861 }
862 }
863
GetSLeb128EncodedSize()864 size_t ScalarValueItem::GetSLeb128EncodedSize()
865 {
866 switch (GetType()) {
867 case Type::INTEGER:
868 return leb128::SignedEncodingSize(static_cast<int32_t>(GetValue<uint32_t>()));
869
870 case Type::LONG:
871 return leb128::SignedEncodingSize(static_cast<int64_t>(GetValue<uint64_t>()));
872
873 default:
874 return 0;
875 }
876 }
877
CalculateSize() const878 size_t ScalarValueItem::CalculateSize() const
879 {
880 size_t size = 0;
881 switch (GetType()) {
882 case Type::INTEGER: {
883 size = sizeof(uint32_t);
884 break;
885 }
886
887 case Type::LONG: {
888 size = sizeof(uint64_t);
889 break;
890 }
891
892 case Type::FLOAT: {
893 size = sizeof(float);
894 break;
895 }
896
897 case Type::DOUBLE: {
898 size = sizeof(double);
899 break;
900 }
901
902 case Type::ID: {
903 size = ID_SIZE;
904 break;
905 }
906 default: {
907 UNREACHABLE();
908 break;
909 }
910 }
911
912 return size;
913 }
914
Alignment()915 size_t ScalarValueItem::Alignment()
916 {
917 return GetSize();
918 }
919
Write(Writer * writer)920 bool ScalarValueItem::Write(Writer *writer)
921 {
922 ASSERT(GetOffset() == writer->GetOffset());
923
924 switch (GetType()) {
925 case Type::INTEGER:
926 return writer->Write(GetValue<uint32_t>());
927
928 case Type::LONG:
929 return writer->Write(GetValue<uint64_t>());
930
931 case Type::FLOAT:
932 return writer->Write(bit_cast<uint32_t>(GetValue<float>()));
933
934 case Type::DOUBLE:
935 return writer->Write(bit_cast<uint64_t>(GetValue<double>()));
936
937 case Type::ID: {
938 ASSERT(GetId().IsValid());
939 return writer->Write(GetId().GetOffset());
940 }
941 default: {
942 UNREACHABLE();
943 break;
944 }
945 }
946
947 return true;
948 }
949
WriteAsUleb128(Writer * writer)950 bool ScalarValueItem::WriteAsUleb128(Writer *writer)
951 {
952 ASSERT(GetOffset() == writer->GetOffset());
953
954 switch (GetType()) {
955 case Type::INTEGER:
956 return writer->WriteUleb128(GetValue<uint32_t>());
957
958 case Type::LONG:
959 return writer->WriteUleb128(GetValue<uint64_t>());
960
961 case Type::ID: {
962 ASSERT(GetId().IsValid());
963 return writer->WriteUleb128(GetId().GetOffset());
964 }
965 default:
966 return false;
967 }
968 }
969
CalculateSize() const970 size_t ArrayValueItem::CalculateSize() const
971 {
972 size_t size = leb128::UnsignedEncodingSize(items_.size()) + items_.size() * GetComponentSize();
973 return size;
974 }
975
ComputeLayout()976 void ArrayValueItem::ComputeLayout()
977 {
978 uint32_t offset = GetOffset();
979
980 ASSERT(offset != 0);
981
982 offset += leb128::UnsignedEncodingSize(items_.size());
983
984 for (auto &item : items_) {
985 item.SetOffset(offset);
986 offset += GetComponentSize();
987 }
988 }
989
Write(Writer * writer)990 bool ArrayValueItem::Write(Writer *writer)
991 {
992 ASSERT(GetOffset() == writer->GetOffset());
993
994 if (!writer->WriteUleb128(items_.size())) {
995 return false;
996 }
997
998 switch (componentType_.GetId()) {
999 case panda_file::Type::TypeId::U1:
1000 case panda_file::Type::TypeId::I8:
1001 case panda_file::Type::TypeId::U8: {
1002 for (auto &item : items_) {
1003 auto value = static_cast<uint8_t>(item.GetValue<uint32_t>());
1004 if (!writer->Write(value)) {
1005 return false;
1006 }
1007 }
1008 break;
1009 }
1010 case panda_file::Type::TypeId::I16:
1011 case panda_file::Type::TypeId::U16: {
1012 for (auto &item : items_) {
1013 auto value = static_cast<uint16_t>(item.GetValue<uint32_t>());
1014 if (!writer->Write(value)) {
1015 return false;
1016 }
1017 }
1018 break;
1019 }
1020 default: {
1021 for (auto &item : items_) {
1022 if (!item.Write(writer)) {
1023 return false;
1024 }
1025 }
1026 break;
1027 }
1028 }
1029
1030 return true;
1031 }
1032
GetComponentSize() const1033 size_t ArrayValueItem::GetComponentSize() const
1034 {
1035 switch (componentType_.GetId()) {
1036 case panda_file::Type::TypeId::U1:
1037 case panda_file::Type::TypeId::I8:
1038 case panda_file::Type::TypeId::U8:
1039 return sizeof(uint8_t);
1040 case panda_file::Type::TypeId::I16:
1041 case panda_file::Type::TypeId::U16:
1042 return sizeof(uint16_t);
1043 case panda_file::Type::TypeId::I32:
1044 case panda_file::Type::TypeId::U32:
1045 case panda_file::Type::TypeId::F32:
1046 return sizeof(uint32_t);
1047 case panda_file::Type::TypeId::I64:
1048 case panda_file::Type::TypeId::U64:
1049 case panda_file::Type::TypeId::F64:
1050 return sizeof(uint64_t);
1051 case panda_file::Type::TypeId::REFERENCE:
1052 return ID_SIZE;
1053 case panda_file::Type::TypeId::VOID:
1054 return 0;
1055 default: {
1056 UNREACHABLE();
1057 // Avoid cpp warning
1058 return 0;
1059 }
1060 }
1061 }
1062
CalculateSize() const1063 size_t LiteralItem::CalculateSize() const
1064 {
1065 size_t size = 0;
1066 switch (GetType()) {
1067 case Type::B1: {
1068 size = sizeof(uint8_t);
1069 break;
1070 }
1071
1072 case Type::B2: {
1073 size = sizeof(uint16_t);
1074 break;
1075 }
1076
1077 case Type::B4: {
1078 size = sizeof(uint32_t);
1079 break;
1080 }
1081
1082 case Type::B8: {
1083 size = sizeof(uint64_t);
1084 break;
1085 }
1086
1087 case Type::STRING:
1088 case Type::METHOD:
1089 case Type::LITERALARRAY: {
1090 size = ID_SIZE;
1091 break;
1092 }
1093
1094 default: {
1095 UNREACHABLE();
1096 break;
1097 }
1098 }
1099
1100 return size;
1101 }
1102
Alignment()1103 size_t LiteralItem::Alignment()
1104 {
1105 return GetSize();
1106 }
1107
GetLiteralArrayFileId() const1108 File::EntityId LiteralItem::GetLiteralArrayFileId() const
1109 {
1110 return File::EntityId(GetValue<LiteralArrayItem *>()->GetOffset());
1111 }
1112
Write(Writer * writer)1113 bool LiteralItem::Write(Writer *writer)
1114 {
1115 ASSERT(GetOffset() == writer->GetOffset());
1116
1117 switch (GetType()) {
1118 case Type::B1: {
1119 return writer->Write(GetValue<uint8_t>());
1120 }
1121 case Type::B2: {
1122 return writer->Write(GetValue<uint16_t>());
1123 }
1124 case Type::B4: {
1125 return writer->Write(GetValue<uint32_t>());
1126 }
1127 case Type::B8: {
1128 return writer->Write(GetValue<uint64_t>());
1129 }
1130 case Type::STRING: {
1131 ASSERT(GetId().IsValid());
1132 return writer->Write(GetId().GetOffset());
1133 }
1134 case Type::METHOD: {
1135 ASSERT(GetMethodId().IsValid());
1136 return writer->Write(GetMethodId().GetOffset());
1137 }
1138 case Type::LITERALARRAY: {
1139 ASSERT(GetLiteralArrayFileId().IsValid());
1140 return writer->Write(GetLiteralArrayFileId().GetOffset());
1141 }
1142 default: {
1143 UNREACHABLE();
1144 break;
1145 }
1146 }
1147
1148 return true;
1149 }
1150
AddItems(const std::vector<LiteralItem> & item)1151 void LiteralArrayItem::AddItems(const std::vector<LiteralItem> &item)
1152 {
1153 items_.assign(item.begin(), item.end());
1154 }
1155
CalculateSize() const1156 size_t LiteralArrayItem::CalculateSize() const
1157 {
1158 size_t size = sizeof(uint32_t);
1159 for (auto &item : items_) {
1160 size += item.CalculateSize();
1161 }
1162
1163 return size;
1164 }
1165
ComputeLayout()1166 void LiteralArrayItem::ComputeLayout()
1167 {
1168 uint32_t offset = GetOffset();
1169
1170 ASSERT(offset != 0);
1171
1172 offset += sizeof(uint32_t);
1173
1174 for (auto &item : items_) {
1175 item.SetOffset(offset);
1176 offset += item.CalculateSize();
1177 }
1178 }
1179
Write(Writer * writer)1180 bool LiteralArrayItem::Write(Writer *writer)
1181 {
1182 ASSERT(GetOffset() == writer->GetOffset());
1183
1184 if (!writer->Write(static_cast<uint32_t>(items_.size()))) {
1185 return false;
1186 }
1187
1188 for (auto &item : items_) {
1189 if (!item.Write(writer)) {
1190 return false;
1191 }
1192 }
1193
1194 return true;
1195 }
1196
BaseFieldItem(BaseClassItem * cls,StringItem * name,TypeItem * type)1197 BaseFieldItem::BaseFieldItem(BaseClassItem *cls, StringItem *name, TypeItem *type)
1198 : class_(cls), name_(name), type_(type)
1199 {
1200 AddIndexDependency(cls);
1201 AddIndexDependency(type);
1202 }
1203
CalculateSize() const1204 size_t BaseFieldItem::CalculateSize() const
1205 {
1206 // class id + type id + name id
1207 return IDX_SIZE + IDX_SIZE + ID_SIZE;
1208 }
1209
Write(Writer * writer)1210 bool BaseFieldItem::Write(Writer *writer)
1211 {
1212 ASSERT(GetOffset() == writer->GetOffset());
1213 ASSERT(class_->HasIndex(this));
1214 ASSERT(type_->HasIndex(this));
1215
1216 if (!writer->Write<uint16_t>(class_->GetIndex(this))) {
1217 return false;
1218 }
1219
1220 if (!writer->Write<uint16_t>(type_->GetIndex(this))) {
1221 return false;
1222 }
1223
1224 return writer->Write(name_->GetOffset());
1225 }
1226
FieldItem(ClassItem * cls,StringItem * name,TypeItem * type,uint32_t accessFlags)1227 FieldItem::FieldItem(ClassItem *cls, StringItem *name, TypeItem *type, uint32_t accessFlags)
1228 : BaseFieldItem(cls, name, type), accessFlags_(accessFlags)
1229 {
1230 }
1231
SetValue(ValueItem * value)1232 void FieldItem::SetValue(ValueItem *value)
1233 {
1234 value_ = value;
1235 value_->SetNeedsEmit(!value_->Is32bit());
1236 }
1237
CalculateSize() const1238 size_t FieldItem::CalculateSize() const
1239 {
1240 size_t size = BaseFieldItem::CalculateSize() + leb128::UnsignedEncodingSize(accessFlags_);
1241
1242 if (value_ != nullptr) {
1243 if (value_->GetType() == ValueItem::Type::INTEGER) {
1244 size += TAG_SIZE + value_->GetAsScalar()->GetSLeb128EncodedSize();
1245 } else {
1246 size += TAG_SIZE + ID_SIZE;
1247 }
1248 }
1249
1250 size += (TAG_SIZE + ID_SIZE) * runtimeAnnotations_.size();
1251 size += (TAG_SIZE + ID_SIZE) * annotations_.size();
1252 size += (TAG_SIZE + ID_SIZE) * runtimeTypeAnnotations_.size();
1253 size += (TAG_SIZE + ID_SIZE) * typeAnnotations_.size();
1254
1255 size += TAG_SIZE; // null tag
1256
1257 return size;
1258 }
1259
WriteValue(Writer * writer)1260 bool FieldItem::WriteValue(Writer *writer)
1261 {
1262 if (value_ == nullptr) {
1263 return true;
1264 }
1265
1266 if (value_->GetType() == ValueItem::Type::INTEGER) {
1267 auto v = static_cast<int32_t>(value_->GetAsScalar()->GetValue<uint32_t>());
1268 if (!WriteSlebTaggedValue(writer, FieldTag::INT_VALUE, v)) {
1269 return false;
1270 }
1271 } else if (value_->GetType() == ValueItem::Type::FLOAT) {
1272 auto v = bit_cast<uint32_t>(value_->GetAsScalar()->GetValue<float>());
1273 if (!WriteTaggedValue(writer, FieldTag::VALUE, v)) {
1274 return false;
1275 }
1276 } else if (value_->GetType() == ValueItem::Type::ID) {
1277 auto id = value_->GetAsScalar()->GetId();
1278 ASSERT(id.GetOffset() != 0);
1279 if (!WriteTaggedValue(writer, FieldTag::VALUE, id.GetOffset())) {
1280 return false;
1281 }
1282 } else {
1283 ASSERT(!value_->Is32bit());
1284 if (!WriteIdTaggedValue(writer, FieldTag::VALUE, value_)) {
1285 return false;
1286 }
1287 }
1288
1289 return true;
1290 }
1291
WriteAnnotations(Writer * writer)1292 bool FieldItem::WriteAnnotations(Writer *writer)
1293 {
1294 for (auto runtimeAnnotation : runtimeAnnotations_) {
1295 if (!WriteIdTaggedValue(writer, FieldTag::RUNTIME_ANNOTATION, runtimeAnnotation)) {
1296 return false;
1297 }
1298 }
1299
1300 for (auto annotation : annotations_) {
1301 if (!WriteIdTaggedValue(writer, FieldTag::ANNOTATION, annotation)) {
1302 return false;
1303 }
1304 }
1305
1306 for (auto runtimeTypeAnnotation : runtimeTypeAnnotations_) {
1307 if (!WriteIdTaggedValue(writer, FieldTag::RUNTIME_TYPE_ANNOTATION, runtimeTypeAnnotation)) {
1308 return false;
1309 }
1310 }
1311
1312 for (auto typeAnnotation : typeAnnotations_) {
1313 if (!WriteIdTaggedValue(writer, FieldTag::TYPE_ANNOTATION, typeAnnotation)) {
1314 return false;
1315 }
1316 }
1317
1318 return true;
1319 }
1320
WriteTaggedData(Writer * writer)1321 bool FieldItem::WriteTaggedData(Writer *writer)
1322 {
1323 if (!WriteValue(writer)) {
1324 return false;
1325 }
1326
1327 if (!WriteAnnotations(writer)) {
1328 return false;
1329 }
1330
1331 return writer->WriteByte(static_cast<uint8_t>(FieldTag::NOTHING));
1332 }
1333
Write(Writer * writer)1334 bool FieldItem::Write(Writer *writer)
1335 {
1336 if (!BaseFieldItem::Write(writer)) {
1337 return false;
1338 }
1339
1340 if (!writer->WriteUleb128(accessFlags_)) {
1341 return false;
1342 }
1343
1344 return WriteTaggedData(writer);
1345 }
1346
CalculateSize() const1347 size_t AnnotationItem::CalculateSize() const
1348 {
1349 // class id + count + (name id + value id) * count + tag size * count
1350 size_t size = IDX_SIZE + sizeof(uint16_t) + (ID_SIZE + ID_SIZE) * elements_.size() + sizeof(uint8_t) * tags_.size();
1351
1352 return size;
1353 }
1354
Write(Writer * writer)1355 bool AnnotationItem::Write(Writer *writer)
1356 {
1357 ASSERT(GetOffset() == writer->GetOffset());
1358 ASSERT(class_->HasIndex(this));
1359
1360 if (!writer->Write<uint16_t>(class_->GetIndex(this))) {
1361 return false;
1362 }
1363
1364 if (!writer->Write(static_cast<uint16_t>(elements_.size()))) {
1365 return false;
1366 }
1367
1368 for (auto elem : elements_) {
1369 ASSERT(elem.GetName()->GetOffset() != 0);
1370 if (!writer->Write(elem.GetName()->GetOffset())) {
1371 return false;
1372 }
1373
1374 ValueItem *valueItem = elem.GetValue();
1375
1376 switch (valueItem->GetType()) {
1377 case ValueItem::Type::INTEGER: {
1378 if (!writer->Write(valueItem->GetAsScalar()->GetValue<uint32_t>())) {
1379 return false;
1380 }
1381 break;
1382 }
1383 case ValueItem::Type::FLOAT: {
1384 if (!writer->Write(bit_cast<uint32_t>(valueItem->GetAsScalar()->GetValue<float>()))) {
1385 return false;
1386 }
1387 break;
1388 }
1389 case ValueItem::Type::ID: {
1390 if (!writer->Write(valueItem->GetAsScalar()->GetId().GetOffset())) {
1391 return false;
1392 }
1393 break;
1394 }
1395 default: {
1396 ASSERT(valueItem->GetOffset() != 0);
1397 if (!writer->Write(valueItem->GetOffset())) {
1398 return false;
1399 }
1400 break;
1401 }
1402 }
1403 }
1404
1405 for (auto tag : tags_) {
1406 if (!writer->Write(tag.GetItem())) {
1407 return false;
1408 }
1409 }
1410
1411 return true;
1412 }
1413
EmitEnd()1414 void LineNumberProgramItemBase::EmitEnd()
1415 {
1416 EmitOpcode(Opcode::END_SEQUENCE);
1417 }
1418
EmitAdvancePc(std::vector<uint8_t> * constantPool,uint32_t value)1419 void LineNumberProgramItemBase::EmitAdvancePc(std::vector<uint8_t> *constantPool, uint32_t value)
1420 {
1421 EmitOpcode(Opcode::ADVANCE_PC);
1422 EmitUleb128(constantPool, value);
1423 }
1424
EmitAdvanceLine(std::vector<uint8_t> * constantPool,int32_t value)1425 void LineNumberProgramItemBase::EmitAdvanceLine(std::vector<uint8_t> *constantPool, int32_t value)
1426 {
1427 EmitOpcode(Opcode::ADVANCE_LINE);
1428 EmitSleb128(constantPool, value);
1429 }
1430
EmitColumn(std::vector<uint8_t> * constantPool,uint32_t pcInc,uint32_t column)1431 void LineNumberProgramItemBase::EmitColumn(std::vector<uint8_t> *constantPool, uint32_t pcInc, uint32_t column)
1432 {
1433 if (pcInc != 0U) {
1434 EmitAdvancePc(constantPool, pcInc);
1435 }
1436 EmitOpcode(Opcode::SET_COLUMN);
1437 EmitUleb128(constantPool, column);
1438 }
1439
EmitStartLocal(std::vector<uint8_t> * constantPool,int32_t registerNumber,StringItem * name,StringItem * type)1440 void LineNumberProgramItemBase::EmitStartLocal(std::vector<uint8_t> *constantPool, int32_t registerNumber,
1441 StringItem *name, StringItem *type)
1442 {
1443 EmitStartLocalExtended(constantPool, registerNumber, name, type, nullptr);
1444 }
1445
EmitStartLocalExtended(std::vector<uint8_t> * constantPool,int32_t registerNumber,StringItem * name,StringItem * type,StringItem * typeSignature)1446 void LineNumberProgramItemBase::EmitStartLocalExtended(std::vector<uint8_t> *constantPool, int32_t registerNumber,
1447 StringItem *name, StringItem *type, StringItem *typeSignature)
1448 {
1449 if (type == nullptr) {
1450 return;
1451 }
1452
1453 ASSERT(name != nullptr);
1454 ASSERT(name->GetOffset() != 0);
1455 ASSERT(type->GetOffset() != 0);
1456
1457 EmitOpcode(typeSignature == nullptr ? Opcode::START_LOCAL : Opcode::START_LOCAL_EXTENDED);
1458 EmitRegister(registerNumber);
1459 EmitUleb128(constantPool, name->GetOffset());
1460 EmitUleb128(constantPool, type->GetOffset());
1461
1462 if (typeSignature != nullptr) {
1463 ASSERT(typeSignature->GetOffset() != 0);
1464 EmitUleb128(constantPool, typeSignature->GetOffset());
1465 }
1466 }
1467
EmitEndLocal(int32_t registerNumber)1468 void LineNumberProgramItemBase::EmitEndLocal(int32_t registerNumber)
1469 {
1470 EmitOpcode(Opcode::END_LOCAL);
1471 EmitRegister(registerNumber);
1472 }
1473
EmitRestartLocal(int32_t registerNumber)1474 void LineNumberProgramItemBase::EmitRestartLocal(int32_t registerNumber)
1475 {
1476 EmitOpcode(Opcode::RESTART_LOCAL);
1477 EmitRegister(registerNumber);
1478 }
1479
EmitSpecialOpcode(uint32_t pcInc,int32_t lineInc)1480 bool LineNumberProgramItemBase::EmitSpecialOpcode(uint32_t pcInc, int32_t lineInc)
1481 {
1482 if (lineInc < LINE_BASE || (lineInc - LINE_BASE) >= LINE_RANGE) {
1483 return false;
1484 }
1485
1486 auto opcode = static_cast<size_t>(lineInc - LINE_BASE) + static_cast<size_t>(pcInc * LINE_RANGE) + OPCODE_BASE;
1487 if (opcode > std::numeric_limits<uint8_t>::max()) {
1488 return false;
1489 }
1490
1491 EmitOpcode(static_cast<uint8_t>(opcode));
1492 return true;
1493 }
1494
EmitPrologueEnd()1495 void LineNumberProgramItemBase::EmitPrologueEnd()
1496 {
1497 EmitOpcode(Opcode::SET_PROLOGUE_END);
1498 }
1499
EmitEpilogueBegin()1500 void LineNumberProgramItemBase::EmitEpilogueBegin()
1501 {
1502 EmitOpcode(Opcode::SET_EPILOGUE_BEGIN);
1503 }
1504
EmitSetFile(std::vector<uint8_t> * constantPool,StringItem * sourceFile)1505 void LineNumberProgramItemBase::EmitSetFile(std::vector<uint8_t> *constantPool, StringItem *sourceFile)
1506 {
1507 ASSERT(sourceFile);
1508 ASSERT(sourceFile->GetOffset() != 0);
1509
1510 EmitOpcode(Opcode::SET_FILE);
1511 EmitUleb128(constantPool, sourceFile->GetOffset());
1512 }
1513
EmitSetSourceCode(std::vector<uint8_t> * constantPool,StringItem * sourceCode)1514 void LineNumberProgramItemBase::EmitSetSourceCode(std::vector<uint8_t> *constantPool, StringItem *sourceCode)
1515 {
1516 ASSERT(sourceCode);
1517 ASSERT(sourceCode->GetOffset() != 0);
1518
1519 EmitOpcode(Opcode::SET_SOURCE_CODE);
1520 EmitUleb128(constantPool, sourceCode->GetOffset());
1521 }
1522
EmitOpcode(Opcode opcode)1523 void LineNumberProgramItemBase::EmitOpcode(Opcode opcode)
1524 {
1525 EmitOpcode(static_cast<uint8_t>(opcode));
1526 }
1527
1528 /* static */
EmitUleb128(std::vector<uint8_t> * data,uint32_t value)1529 void LineNumberProgramItemBase::EmitUleb128(std::vector<uint8_t> *data, uint32_t value)
1530 {
1531 ASSERT(data);
1532
1533 size_t n = leb128::UnsignedEncodingSize(value);
1534 std::vector<uint8_t> out(n);
1535 leb128::EncodeUnsigned(value, out.data());
1536 data->insert(data->end(), out.cbegin(), out.cend());
1537 }
1538
1539 /* static */
EmitSleb128(std::vector<uint8_t> * data,int32_t value)1540 void LineNumberProgramItemBase::EmitSleb128(std::vector<uint8_t> *data, int32_t value)
1541 {
1542 ASSERT(data);
1543
1544 size_t n = leb128::SignedEncodingSize(value);
1545 std::vector<uint8_t> out(n);
1546 leb128::EncodeSigned(value, out.data());
1547 data->insert(data->end(), out.cbegin(), out.cend());
1548 }
1549
EmitOpcode(uint8_t opcode)1550 void LineNumberProgramItem::EmitOpcode(uint8_t opcode)
1551 {
1552 data_.push_back(opcode);
1553 }
1554
EmitRegister(int32_t registerNumber)1555 void LineNumberProgramItem::EmitRegister(int32_t registerNumber)
1556 {
1557 EmitSleb128(&data_, registerNumber);
1558 }
1559
CalculateSize() const1560 size_t LineNumberProgramItem::CalculateSize() const
1561 {
1562 return data_.size();
1563 }
1564
Write(Writer * writer)1565 bool LineNumberProgramItem::Write(Writer *writer)
1566 {
1567 ASSERT(GetOffset() == writer->GetOffset());
1568
1569 return writer->WriteBytes(data_);
1570 }
1571
SetData(std::vector<uint8_t> && data)1572 void LineNumberProgramItem::SetData(std::vector<uint8_t> &&data)
1573 {
1574 data_ = std::move(data);
1575 }
1576
CalculateSize() const1577 size_t DebugInfoItem::CalculateSize() const
1578 {
1579 size_t n = leb128::UnsignedEncodingSize(lineNum_) + leb128::UnsignedEncodingSize(parameters_.size());
1580
1581 for (auto *p : parameters_) {
1582 ASSERT(p == nullptr || p->GetOffset() != 0);
1583 n += leb128::UnsignedEncodingSize(p == nullptr ? 0 : p->GetOffset());
1584 }
1585
1586 n += leb128::UnsignedEncodingSize(constantPool_.size());
1587 n += constantPool_.size();
1588
1589 n += leb128::UnsignedEncodingSize(program_->GetIndex(this));
1590
1591 return n;
1592 }
1593
Write(Writer * writer)1594 bool DebugInfoItem::Write(Writer *writer)
1595 {
1596 ASSERT(GetOffset() == writer->GetOffset());
1597
1598 if (!writer->WriteUleb128(lineNum_)) {
1599 return false;
1600 }
1601
1602 if (!writer->WriteUleb128(parameters_.size())) {
1603 return false;
1604 }
1605
1606 for (auto *p : parameters_) {
1607 ASSERT(p == nullptr || p->GetOffset() != 0);
1608
1609 if (!writer->WriteUleb128(p == nullptr ? 0 : p->GetOffset())) {
1610 return false;
1611 }
1612 }
1613
1614 if (!writer->WriteUleb128(constantPool_.size())) {
1615 return false;
1616 }
1617
1618 if (!writer->WriteBytes(constantPool_)) {
1619 return false;
1620 }
1621
1622 ASSERT(program_ != nullptr);
1623 ASSERT(program_->HasIndex(this));
1624
1625 return writer->WriteUleb128(program_->GetIndex(this));
1626 }
1627
Dump(std::ostream & os) const1628 void DebugInfoItem::Dump(std::ostream &os) const
1629 {
1630 os << "line_start = " << lineNum_ << std::endl;
1631
1632 os << "num_parameters = " << parameters_.size() << std::endl;
1633 for (auto *item : parameters_) {
1634 if (item != nullptr) {
1635 os << " string_item[" << item->GetOffset() << "]" << std::endl;
1636 } else {
1637 os << " string_item[INVALID_OFFSET]" << std::endl;
1638 }
1639 }
1640
1641 os << "constant_pool = [";
1642 for (size_t i = 0; i < constantPool_.size(); i++) {
1643 size_t b = constantPool_[i];
1644 os << "0x" << std::setfill('0') << std::setw(2U) << std::right << std::hex << b << std::dec;
1645 if (i < constantPool_.size() - 1) {
1646 os << ", ";
1647 }
1648 }
1649 os << "]" << std::endl;
1650
1651 os << "line_number_program = line_number_program_idx[";
1652 if (program_ != nullptr && program_->HasIndex(this)) {
1653 os << program_->GetIndex(this);
1654 } else {
1655 os << "NO_INDEX";
1656 }
1657 os << "]";
1658 }
1659
Write(Writer * writer)1660 bool MethodHandleItem::Write(Writer *writer)
1661 {
1662 ASSERT(GetOffset() == writer->GetOffset());
1663
1664 if (!writer->WriteByte(static_cast<uint8_t>(type_))) {
1665 return false;
1666 }
1667
1668 return writer->WriteUleb128(entity_->GetOffset());
1669 }
1670
1671 } // namespace ark::panda_file
1672