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