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(const std::string_view & lang)32 std::optional<panda::panda_file::SourceLang> LanguageFromString(const 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 const auto bc_version = GetVersionByApi(ItemContainer::GetApi(), ItemContainer::GetSubApi());
506 if (bc_version.value().front() >= API_12) {
507 // no need to emit protoItem
508 SetNeedsEmit(false);
509 }
510 }
511
AddType(TypeItem * type,size_t * n)512 void ProtoItem::AddType(TypeItem *type, size_t *n)
513 {
514 constexpr size_t SHORTY_ELEMS_COUNT = std::numeric_limits<uint16_t>::digits / SHORTY_ELEM_SIZE;
515
516 uint16_t v = shorty_.back();
517
518 size_t shift = (*n % SHORTY_ELEMS_COUNT) * SHORTY_ELEM_SIZE;
519
520 v |= static_cast<uint16_t>(static_cast<uint16_t>(type->GetType().GetEncoding()) << shift);
521 shorty_.back() = v;
522
523 if (!type->GetType().IsPrimitive()) {
524 reference_types_.push_back(type);
525 AddIndexDependency(type);
526 }
527
528 *n += 1;
529
530 if (*n % SHORTY_ELEMS_COUNT == 0) {
531 shorty_.push_back(0);
532 }
533 }
534
Write(Writer * writer)535 bool ProtoItem::Write(Writer *writer)
536 {
537 ASSERT(GetOffset() == writer->GetOffset());
538 for (auto s : shorty_) {
539 if (!writer->Write(s)) {
540 return false;
541 }
542 }
543
544 for (auto r : reference_types_) {
545 ASSERT(r->HasIndex(this));
546 if (!writer->Write<uint16_t>(r->GetIndex(this))) {
547 return false;
548 }
549 }
550
551 return true;
552 }
553
BaseMethodItem(BaseClassItem * cls,StringItem * name,ProtoItem * proto,uint32_t access_flags,ItemContainer * container)554 BaseMethodItem::BaseMethodItem(BaseClassItem *cls, StringItem *name, ProtoItem *proto, uint32_t access_flags,
555 ItemContainer *container)
556 : IndexedItem(container), class_(cls), name_(name), proto_(proto), access_flags_(access_flags)
557 {
558 AddIndexDependency(cls);
559 AddIndexDependency(proto);
560 }
561
CalculateSize() const562 size_t BaseMethodItem::CalculateSize() const
563 {
564 // class id + proto id + name id + access flags
565 return IDX_SIZE + IDX_SIZE + ID_SIZE + leb128::UnsignedEncodingSize(access_flags_);
566 }
567
Write(Writer * writer)568 bool BaseMethodItem::Write(Writer *writer)
569 {
570 ASSERT(GetOffset() == writer->GetOffset());
571 ASSERT(class_ != nullptr);
572 ASSERT(class_->HasIndex(this));
573
574 if (!writer->Write<uint16_t>(class_->GetIndex(this))) {
575 return false;
576 }
577
578 const auto bc_version = GetVersionByApi(ItemContainer::GetApi(), ItemContainer::GetSubApi());
579 if (bc_version.value().front() >= API_12) {
580 // reserve [proto_idx] field, write invalid index
581 if (!writer->Write<uint16_t>(INVALID_INDEX_16)) {
582 return false;
583 }
584 } else {
585 ASSERT(proto_->HasIndex(this));
586
587 if (!writer->Write<uint16_t>(proto_->GetIndex(this))) {
588 return false;
589 }
590 }
591
592 ASSERT(name_->GetOffset() != 0);
593
594 if (!writer->Write(name_->GetOffset())) {
595 return false;
596 }
597
598 return writer->WriteUleb128(access_flags_);
599 }
600
MethodItem(ClassItem * cls,StringItem * name,ProtoItem * proto,uint32_t access_flags,std::vector<MethodParamItem> params,ItemContainer * container)601 MethodItem::MethodItem(ClassItem *cls, StringItem *name, ProtoItem *proto, uint32_t access_flags,
602 std::vector<MethodParamItem> params, ItemContainer *container)
603 : BaseMethodItem(cls, name, proto, access_flags, container),
604 params_(std::move(params)),
605 source_lang_(SourceLang::PANDA_ASSEMBLY),
606 code_(nullptr),
607 debug_info_(nullptr)
608 {
609 }
610
CalculateSize() const611 size_t MethodItem::CalculateSize() const
612 {
613 size_t size = BaseMethodItem::CalculateSize();
614
615 if (code_ != nullptr) {
616 size += TAG_SIZE + ID_SIZE;
617 }
618
619 if (source_lang_ != SourceLang::PANDA_ASSEMBLY) {
620 size += TAG_SIZE + sizeof(SourceLang);
621 }
622
623 size += (TAG_SIZE + ID_SIZE) * runtime_annotations_.size();
624
625 if (runtime_param_annotations_ != nullptr) {
626 size += TAG_SIZE + ID_SIZE;
627 }
628
629 size += (TAG_SIZE + ID_SIZE) * annotations_.size();
630
631 if (param_annotations_ != nullptr) {
632 size += TAG_SIZE + ID_SIZE;
633 }
634
635 size += (TAG_SIZE + ID_SIZE) * runtime_type_annotations_.size();
636 size += (TAG_SIZE + ID_SIZE) * type_annotations_.size();
637
638 if (debug_info_ != nullptr) {
639 size += TAG_SIZE + ID_SIZE;
640 }
641
642 size += TAG_SIZE; // null tag
643
644 return size;
645 }
646
WriteRuntimeAnnotations(Writer * writer)647 bool MethodItem::WriteRuntimeAnnotations(Writer *writer)
648 {
649 for (auto runtime_annotation : runtime_annotations_) {
650 if (!WriteIdTaggedValue(writer, MethodTag::RUNTIME_ANNOTATION, runtime_annotation)) {
651 return false;
652 }
653 }
654
655 if (runtime_param_annotations_ != nullptr) {
656 if (!WriteIdTaggedValue(writer, MethodTag::RUNTIME_PARAM_ANNOTATION, runtime_param_annotations_)) {
657 return false;
658 }
659 }
660
661 return true;
662 }
663
WriteTypeAnnotations(Writer * writer)664 bool MethodItem::WriteTypeAnnotations(Writer *writer)
665 {
666 for (auto runtime_type_annotation : runtime_type_annotations_) {
667 if (!WriteIdTaggedValue(writer, MethodTag::RUNTIME_TYPE_ANNOTATION, runtime_type_annotation)) {
668 return false;
669 }
670 }
671
672 for (auto type_annotation : type_annotations_) {
673 if (!WriteIdTaggedValue(writer, MethodTag::TYPE_ANNOTATION, type_annotation)) {
674 return false;
675 }
676 }
677
678 return true;
679 }
680
WriteTaggedData(Writer * writer)681 bool MethodItem::WriteTaggedData(Writer *writer)
682 {
683 if (code_ != nullptr) {
684 if (!WriteIdTaggedValue(writer, MethodTag::CODE, code_)) {
685 return false;
686 }
687 }
688
689 if (source_lang_ != SourceLang::PANDA_ASSEMBLY) {
690 if (!WriteTaggedValue(writer, MethodTag::SOURCE_LANG, static_cast<uint8_t>(source_lang_))) {
691 return false;
692 }
693 }
694
695 if (!WriteRuntimeAnnotations(writer)) {
696 return false;
697 }
698
699 if (debug_info_ != nullptr) {
700 if (!WriteIdTaggedValue(writer, MethodTag::DEBUG_INFO, debug_info_)) {
701 return false;
702 }
703 }
704
705 for (auto annotation : annotations_) {
706 if (!WriteIdTaggedValue(writer, MethodTag::ANNOTATION, annotation)) {
707 return false;
708 }
709 }
710
711 if (!WriteTypeAnnotations(writer)) {
712 return false;
713 }
714
715 if (param_annotations_ != nullptr) {
716 if (!WriteIdTaggedValue(writer, MethodTag::PARAM_ANNOTATION, param_annotations_)) {
717 return false;
718 }
719 }
720
721 return writer->WriteByte(static_cast<uint8_t>(MethodTag::NOTHING));
722 }
723
Write(Writer * writer)724 bool MethodItem::Write(Writer *writer)
725 {
726 if (!BaseMethodItem::Write(writer)) {
727 return false;
728 }
729
730 return WriteTaggedData(writer);
731 }
732
CalculateSize() const733 size_t CodeItem::CatchBlock::CalculateSize() const
734 {
735 ASSERT(type_ == nullptr || type_->HasIndex(method_));
736 uint32_t type_off = type_ != nullptr ? type_->GetIndex(method_) + 1 : 0;
737 return leb128::UnsignedEncodingSize(type_off) + leb128::UnsignedEncodingSize(handler_pc_) +
738 leb128::UnsignedEncodingSize(code_size_);
739 }
740
Write(Writer * writer)741 bool CodeItem::CatchBlock::Write(Writer *writer)
742 {
743 ASSERT(GetOffset() == writer->GetOffset());
744 ASSERT(type_ == nullptr || type_->HasIndex(method_));
745
746 uint32_t type_off = type_ != nullptr ? type_->GetIndex(method_) + 1 : 0;
747
748 if (!writer->WriteUleb128(type_off)) {
749 return false;
750 }
751
752 if (!writer->WriteUleb128(handler_pc_)) {
753 return false;
754 }
755
756 if (!writer->WriteUleb128(code_size_)) {
757 return false;
758 }
759
760 return true;
761 }
762
ComputeLayout()763 void CodeItem::TryBlock::ComputeLayout()
764 {
765 size_t offset = GetOffset();
766 offset += CalculateSizeWithoutCatchBlocks();
767
768 for (auto &catch_block : catch_blocks_) {
769 catch_block.SetOffset(offset);
770 catch_block.ComputeLayout();
771 offset += catch_block.GetSize();
772 }
773 }
774
CalculateSizeWithoutCatchBlocks() const775 size_t CodeItem::TryBlock::CalculateSizeWithoutCatchBlocks() const
776 {
777 return leb128::UnsignedEncodingSize(start_pc_) + leb128::UnsignedEncodingSize(length_) +
778 leb128::UnsignedEncodingSize(catch_blocks_.size());
779 }
780
CalculateSize() const781 size_t CodeItem::TryBlock::CalculateSize() const
782 {
783 size_t size = CalculateSizeWithoutCatchBlocks();
784
785 for (auto &catch_block : catch_blocks_) {
786 size += catch_block.GetSize();
787 }
788
789 return size;
790 }
791
Write(Writer * writer)792 bool CodeItem::TryBlock::Write(Writer *writer)
793 {
794 ASSERT(GetOffset() == writer->GetOffset());
795
796 if (!writer->WriteUleb128(start_pc_)) {
797 return false;
798 }
799
800 if (!writer->WriteUleb128(length_)) {
801 return false;
802 }
803
804 if (!writer->WriteUleb128(catch_blocks_.size())) {
805 return false;
806 }
807
808 for (auto &catch_block : catch_blocks_) {
809 if (!catch_block.Write(writer)) {
810 return false;
811 }
812 }
813
814 return true;
815 }
816
ComputeLayout()817 void CodeItem::ComputeLayout()
818 {
819 uint32_t offset = GetOffset();
820
821 offset += CalculateSizeWithoutTryBlocks();
822
823 for (auto &try_block : try_blocks_) {
824 try_block.SetOffset(offset);
825 try_block.ComputeLayout();
826 offset += try_block.GetSize();
827 }
828 }
829
CalculateSizeWithoutTryBlocks() const830 size_t CodeItem::CalculateSizeWithoutTryBlocks() const
831 {
832 size_t size = leb128::UnsignedEncodingSize(num_vregs_) + leb128::UnsignedEncodingSize(num_args_) +
833 leb128::UnsignedEncodingSize(instructions_.size()) + leb128::UnsignedEncodingSize(try_blocks_.size());
834
835 size += instructions_.size();
836
837 return size;
838 }
839
GetCodeSize() const840 size_t CodeItem::GetCodeSize() const
841 {
842 return instructions_.size();
843 }
844
CalculateSize() const845 size_t CodeItem::CalculateSize() const
846 {
847 size_t size = CalculateSizeWithoutTryBlocks();
848
849 for (auto &try_block : try_blocks_) {
850 size += try_block.GetSize();
851 }
852
853 return size;
854 }
855
Write(Writer * writer)856 bool CodeItem::Write(Writer *writer)
857 {
858 ASSERT(GetOffset() == writer->GetOffset());
859
860 if (!writer->WriteUleb128(num_vregs_)) {
861 return false;
862 }
863
864 if (!writer->WriteUleb128(num_args_)) {
865 return false;
866 }
867
868 if (!writer->WriteUleb128(instructions_.size())) {
869 return false;
870 }
871
872 if (!writer->WriteUleb128(try_blocks_.size())) {
873 return false;
874 }
875
876 if (!writer->WriteBytes(instructions_)) {
877 return false;
878 }
879
880 for (auto &try_block : try_blocks_) {
881 if (!try_block.Write(writer)) {
882 return false;
883 }
884 }
885
886 return true;
887 }
888
GetAsScalar()889 ScalarValueItem *ValueItem::GetAsScalar()
890 {
891 ASSERT(!IsArray());
892 return static_cast<ScalarValueItem *>(this);
893 }
894
GetAsArray()895 ArrayValueItem *ValueItem::GetAsArray()
896 {
897 ASSERT(IsArray());
898 return static_cast<ArrayValueItem *>(this);
899 }
900
GetULeb128EncodedSize()901 size_t ScalarValueItem::GetULeb128EncodedSize()
902 {
903 switch (GetType()) {
904 case Type::INTEGER:
905 return leb128::UnsignedEncodingSize(GetValue<uint32_t>());
906
907 case Type::LONG:
908 return leb128::UnsignedEncodingSize(GetValue<uint64_t>());
909
910 case Type::ID:
911 return leb128::UnsignedEncodingSize(GetId().GetOffset());
912
913 default:
914 return 0;
915 }
916 }
917
GetSLeb128EncodedSize()918 size_t ScalarValueItem::GetSLeb128EncodedSize()
919 {
920 switch (GetType()) {
921 case Type::INTEGER:
922 return leb128::SignedEncodingSize(static_cast<int32_t>(GetValue<uint32_t>()));
923
924 case Type::LONG:
925 return leb128::SignedEncodingSize(static_cast<int64_t>(GetValue<uint64_t>()));
926
927 default:
928 return 0;
929 }
930 }
931
CalculateSize() const932 size_t ScalarValueItem::CalculateSize() const
933 {
934 size_t size = 0;
935 switch (GetType()) {
936 case Type::INTEGER: {
937 size = sizeof(uint32_t);
938 break;
939 }
940
941 case Type::LONG: {
942 size = sizeof(uint64_t);
943 break;
944 }
945
946 case Type::FLOAT: {
947 size = sizeof(float);
948 break;
949 }
950
951 case Type::DOUBLE: {
952 size = sizeof(double);
953 break;
954 }
955
956 case Type::ID: {
957 size = ID_SIZE;
958 break;
959 }
960 default: {
961 UNREACHABLE();
962 break;
963 }
964 }
965
966 return size;
967 }
968
Alignment()969 size_t ScalarValueItem::Alignment()
970 {
971 return GetSize();
972 }
973
Write(Writer * writer)974 bool ScalarValueItem::Write(Writer *writer)
975 {
976 ASSERT(GetOffset() == writer->GetOffset());
977
978 switch (GetType()) {
979 case Type::INTEGER:
980 return writer->Write(GetValue<uint32_t>());
981
982 case Type::LONG:
983 return writer->Write(GetValue<uint64_t>());
984
985 case Type::FLOAT:
986 return writer->Write(bit_cast<uint32_t>(GetValue<float>()));
987
988 case Type::DOUBLE:
989 return writer->Write(bit_cast<uint64_t>(GetValue<double>()));
990
991 case Type::ID: {
992 ASSERT(GetId().IsValid());
993 return writer->Write(GetId().GetOffset());
994 }
995 default: {
996 UNREACHABLE();
997 break;
998 }
999 }
1000
1001 return true;
1002 }
1003
WriteAsUleb128(Writer * writer)1004 bool ScalarValueItem::WriteAsUleb128(Writer *writer)
1005 {
1006 ASSERT(GetOffset() == writer->GetOffset());
1007
1008 switch (GetType()) {
1009 case Type::INTEGER:
1010 return writer->WriteUleb128(GetValue<uint32_t>());
1011
1012 case Type::LONG:
1013 return writer->WriteUleb128(GetValue<uint64_t>());
1014
1015 case Type::ID: {
1016 ASSERT(GetId().IsValid());
1017 return writer->WriteUleb128(GetId().GetOffset());
1018 }
1019 default:
1020 return false;
1021 }
1022 }
1023
CalculateSize() const1024 size_t ArrayValueItem::CalculateSize() const
1025 {
1026 size_t size = leb128::UnsignedEncodingSize(items_.size()) + items_.size() * GetComponentSize();
1027 return size;
1028 }
1029
ComputeLayout()1030 void ArrayValueItem::ComputeLayout()
1031 {
1032 uint32_t offset = GetOffset();
1033
1034 ASSERT(offset != 0);
1035
1036 offset += leb128::UnsignedEncodingSize(items_.size());
1037
1038 for (auto &item : items_) {
1039 item.SetOffset(offset);
1040 offset += GetComponentSize();
1041 }
1042 }
1043
Write(Writer * writer)1044 bool ArrayValueItem::Write(Writer *writer)
1045 {
1046 ASSERT(GetOffset() == writer->GetOffset());
1047
1048 if (!writer->WriteUleb128(items_.size())) {
1049 return false;
1050 }
1051
1052 switch (component_type_.GetId()) {
1053 case panda_file::Type::TypeId::U1:
1054 case panda_file::Type::TypeId::I8:
1055 case panda_file::Type::TypeId::U8: {
1056 for (auto &item : items_) {
1057 auto value = static_cast<uint8_t>(item.GetValue<uint32_t>());
1058 if (!writer->Write(value)) {
1059 return false;
1060 }
1061 }
1062 break;
1063 }
1064 case panda_file::Type::TypeId::I16:
1065 case panda_file::Type::TypeId::U16: {
1066 for (auto &item : items_) {
1067 auto value = static_cast<uint16_t>(item.GetValue<uint32_t>());
1068 if (!writer->Write(value)) {
1069 return false;
1070 }
1071 }
1072 break;
1073 }
1074 default: {
1075 for (auto &item : items_) {
1076 if (!item.Write(writer)) {
1077 return false;
1078 }
1079 }
1080 break;
1081 }
1082 }
1083
1084 return true;
1085 }
1086
GetComponentSize() const1087 size_t ArrayValueItem::GetComponentSize() const
1088 {
1089 switch (component_type_.GetId()) {
1090 case panda_file::Type::TypeId::U1:
1091 case panda_file::Type::TypeId::I8:
1092 case panda_file::Type::TypeId::U8:
1093 return sizeof(uint8_t);
1094 case panda_file::Type::TypeId::I16:
1095 case panda_file::Type::TypeId::U16:
1096 return sizeof(uint16_t);
1097 case panda_file::Type::TypeId::I32:
1098 case panda_file::Type::TypeId::U32:
1099 case panda_file::Type::TypeId::F32:
1100 return sizeof(uint32_t);
1101 case panda_file::Type::TypeId::I64:
1102 case panda_file::Type::TypeId::U64:
1103 case panda_file::Type::TypeId::F64:
1104 return sizeof(uint64_t);
1105 case panda_file::Type::TypeId::REFERENCE:
1106 return ID_SIZE;
1107 case panda_file::Type::TypeId::VOID:
1108 return 0;
1109 default: {
1110 UNREACHABLE();
1111 // Avoid cpp warning
1112 return 0;
1113 }
1114 }
1115 }
1116
CalculateSize() const1117 size_t LiteralItem::CalculateSize() const
1118 {
1119 size_t size = 0;
1120 switch (GetType()) {
1121 case Type::B1: {
1122 size = sizeof(uint8_t);
1123 break;
1124 }
1125
1126 case Type::B2: {
1127 size = sizeof(uint16_t);
1128 break;
1129 }
1130
1131 case Type::B4: {
1132 size = sizeof(uint32_t);
1133 break;
1134 }
1135
1136 case Type::B8: {
1137 size = sizeof(uint64_t);
1138 break;
1139 }
1140
1141 case Type::STRING:
1142 case Type::METHOD:
1143 case Type::LITERALARRAY: {
1144 size = ID_SIZE;
1145 break;
1146 }
1147
1148 default: {
1149 UNREACHABLE();
1150 break;
1151 }
1152 }
1153
1154 return size;
1155 }
1156
Alignment()1157 size_t LiteralItem::Alignment()
1158 {
1159 return GetSize();
1160 }
1161
GetLiteralArrayFileId() const1162 File::EntityId LiteralItem::GetLiteralArrayFileId() const
1163 {
1164 return File::EntityId(GetValue<LiteralArrayItem *>()->GetOffset());
1165 }
1166
Write(Writer * writer)1167 bool LiteralItem::Write(Writer *writer)
1168 {
1169 ASSERT(GetOffset() == writer->GetOffset());
1170
1171 switch (GetType()) {
1172 case Type::B1: {
1173 return writer->Write(GetValue<uint8_t>());
1174 }
1175 case Type::B2: {
1176 return writer->Write(GetValue<uint16_t>());
1177 }
1178 case Type::B4: {
1179 return writer->Write(GetValue<uint32_t>());
1180 }
1181 case Type::B8: {
1182 return writer->Write(GetValue<uint64_t>());
1183 }
1184 case Type::STRING: {
1185 ASSERT(GetId().IsValid());
1186 return writer->Write(GetId().GetOffset());
1187 }
1188 case Type::METHOD: {
1189 ASSERT(GetMethodId().IsValid());
1190 return writer->Write(GetMethodId().GetOffset());
1191 }
1192 case Type::LITERALARRAY: {
1193 ASSERT(GetLiteralArrayFileId().IsValid());
1194 return writer->Write(GetLiteralArrayFileId().GetOffset());
1195 }
1196 default: {
1197 UNREACHABLE();
1198 break;
1199 }
1200 }
1201
1202 return true;
1203 }
1204
AddItems(const std::vector<LiteralItem> & item)1205 void LiteralArrayItem::AddItems(const std::vector<LiteralItem> &item)
1206 {
1207 items_.assign(item.begin(), item.end());
1208 }
1209
CalculateSize() const1210 size_t LiteralArrayItem::CalculateSize() const
1211 {
1212 size_t size = sizeof(uint32_t);
1213 for (auto &item : items_) {
1214 size += item.CalculateSize();
1215 }
1216
1217 return size;
1218 }
1219
ComputeLayout()1220 void LiteralArrayItem::ComputeLayout()
1221 {
1222 uint32_t offset = GetOffset();
1223
1224 ASSERT(offset != 0);
1225
1226 offset += sizeof(uint32_t);
1227
1228 for (auto &item : items_) {
1229 item.SetOffset(offset);
1230 offset += item.CalculateSize();
1231 }
1232 }
1233
Write(Writer * writer)1234 bool LiteralArrayItem::Write(Writer *writer)
1235 {
1236 ASSERT(GetOffset() == writer->GetOffset());
1237
1238 if (!writer->Write(static_cast<uint32_t>(items_.size()))) {
1239 return false;
1240 }
1241
1242 for (auto &item : items_) {
1243 if (!item.Write(writer)) {
1244 return false;
1245 }
1246 }
1247
1248 return true;
1249 }
1250
BaseFieldItem(BaseClassItem * cls,StringItem * name,TypeItem * type,ItemContainer * container)1251 BaseFieldItem::BaseFieldItem(BaseClassItem *cls, StringItem *name, TypeItem *type, ItemContainer *container)
1252 : IndexedItem(container), class_(cls), name_(name), type_(type)
1253 {
1254 AddIndexDependency(cls);
1255 AddIndexDependency(type);
1256 }
1257
CalculateSize() const1258 size_t BaseFieldItem::CalculateSize() const
1259 {
1260 // class id + type id + name id
1261 return IDX_SIZE + IDX_SIZE + ID_SIZE;
1262 }
1263
Write(Writer * writer)1264 bool BaseFieldItem::Write(Writer *writer)
1265 {
1266 ASSERT(GetOffset() == writer->GetOffset());
1267 ASSERT(class_->HasIndex(this));
1268 ASSERT(type_->HasIndex(this));
1269
1270 if (!writer->Write<uint16_t>(class_->GetIndex(this))) {
1271 return false;
1272 }
1273
1274 if (!writer->Write<uint16_t>(type_->GetIndex(this))) {
1275 return false;
1276 }
1277
1278 return writer->Write(name_->GetOffset());
1279 }
1280
FieldItem(ClassItem * cls,StringItem * name,TypeItem * type,uint32_t access_flags,ItemContainer * container)1281 FieldItem::FieldItem(ClassItem *cls, StringItem *name, TypeItem *type, uint32_t access_flags, ItemContainer *container)
1282 : BaseFieldItem(cls, name, type, container), access_flags_(access_flags), value_(nullptr)
1283 {
1284 }
1285
SetValue(ValueItem * value)1286 void FieldItem::SetValue(ValueItem *value)
1287 {
1288 value_ = value;
1289 value_->SetNeedsEmit(!value_->Is32bit());
1290 }
1291
CalculateSize() const1292 size_t FieldItem::CalculateSize() const
1293 {
1294 size_t size = BaseFieldItem::CalculateSize() + leb128::UnsignedEncodingSize(access_flags_);
1295
1296 if (value_ != nullptr) {
1297 if (value_->GetType() == ValueItem::Type::INTEGER) {
1298 size += TAG_SIZE + value_->GetAsScalar()->GetSLeb128EncodedSize();
1299 } else {
1300 size += TAG_SIZE + ID_SIZE;
1301 }
1302 }
1303
1304 size += (TAG_SIZE + ID_SIZE) * runtime_annotations_.size();
1305 size += (TAG_SIZE + ID_SIZE) * annotations_.size();
1306 size += (TAG_SIZE + ID_SIZE) * runtime_type_annotations_.size();
1307 size += (TAG_SIZE + ID_SIZE) * type_annotations_.size();
1308
1309 size += TAG_SIZE; // null tag
1310
1311 return size;
1312 }
1313
WriteValue(Writer * writer)1314 bool FieldItem::WriteValue(Writer *writer)
1315 {
1316 if (value_ == nullptr) {
1317 return true;
1318 }
1319
1320 if (value_->GetType() == ValueItem::Type::INTEGER) {
1321 auto v = static_cast<int32_t>(value_->GetAsScalar()->GetValue<uint32_t>());
1322 if (!WriteSlebTaggedValue(writer, FieldTag::INT_VALUE, v)) {
1323 return false;
1324 }
1325 } else if (value_->GetType() == ValueItem::Type::FLOAT) {
1326 auto v = bit_cast<uint32_t>(value_->GetAsScalar()->GetValue<float>());
1327 if (!WriteTaggedValue(writer, FieldTag::VALUE, v)) {
1328 return false;
1329 }
1330 } else if (value_->GetType() == ValueItem::Type::ID) {
1331 auto id = value_->GetAsScalar()->GetId();
1332 ASSERT(id.GetOffset() != 0);
1333 if (!WriteTaggedValue(writer, FieldTag::VALUE, id.GetOffset())) {
1334 return false;
1335 }
1336 } else {
1337 ASSERT(!value_->Is32bit());
1338 if (!WriteIdTaggedValue(writer, FieldTag::VALUE, value_)) {
1339 return false;
1340 }
1341 }
1342
1343 return true;
1344 }
1345
WriteAnnotations(Writer * writer)1346 bool FieldItem::WriteAnnotations(Writer *writer)
1347 {
1348 for (auto runtime_annotation : runtime_annotations_) {
1349 if (!WriteIdTaggedValue(writer, FieldTag::RUNTIME_ANNOTATION, runtime_annotation)) {
1350 return false;
1351 }
1352 }
1353
1354 for (auto annotation : annotations_) {
1355 if (!WriteIdTaggedValue(writer, FieldTag::ANNOTATION, annotation)) {
1356 return false;
1357 }
1358 }
1359
1360 for (auto runtime_type_annotation : runtime_type_annotations_) {
1361 if (!WriteIdTaggedValue(writer, FieldTag::RUNTIME_TYPE_ANNOTATION, runtime_type_annotation)) {
1362 return false;
1363 }
1364 }
1365
1366 for (auto type_annotation : type_annotations_) {
1367 if (!WriteIdTaggedValue(writer, FieldTag::TYPE_ANNOTATION, type_annotation)) {
1368 return false;
1369 }
1370 }
1371
1372 return true;
1373 }
1374
WriteTaggedData(Writer * writer)1375 bool FieldItem::WriteTaggedData(Writer *writer)
1376 {
1377 if (!WriteValue(writer)) {
1378 return false;
1379 }
1380
1381 if (!WriteAnnotations(writer)) {
1382 return false;
1383 }
1384
1385 return writer->WriteByte(static_cast<uint8_t>(FieldTag::NOTHING));
1386 }
1387
Write(Writer * writer)1388 bool FieldItem::Write(Writer *writer)
1389 {
1390 if (!BaseFieldItem::Write(writer)) {
1391 return false;
1392 }
1393
1394 if (!writer->WriteUleb128(access_flags_)) {
1395 return false;
1396 }
1397
1398 return WriteTaggedData(writer);
1399 }
1400
CalculateSize() const1401 size_t AnnotationItem::CalculateSize() const
1402 {
1403 // class id + count + (name id + value id) * count + tag size * count
1404 size_t size = IDX_SIZE + sizeof(uint16_t) + (ID_SIZE + ID_SIZE) * elements_.size() + sizeof(uint8_t) * tags_.size();
1405
1406 return size;
1407 }
1408
Write(Writer * writer)1409 bool AnnotationItem::Write(Writer *writer)
1410 {
1411 ASSERT(GetOffset() == writer->GetOffset());
1412 ASSERT(class_->HasIndex(this));
1413
1414 if (!writer->Write<uint16_t>(class_->GetIndex(this))) {
1415 return false;
1416 }
1417
1418 if (!writer->Write(static_cast<uint16_t>(elements_.size()))) {
1419 return false;
1420 }
1421
1422 for (auto elem : elements_) {
1423 ASSERT(elem.GetName()->GetOffset() != 0);
1424 if (!writer->Write(elem.GetName()->GetOffset())) {
1425 return false;
1426 }
1427
1428 ValueItem *value_item = elem.GetValue();
1429
1430 switch (value_item->GetType()) {
1431 case ValueItem::Type::INTEGER: {
1432 if (!writer->Write(value_item->GetAsScalar()->GetValue<uint32_t>())) {
1433 return false;
1434 }
1435 break;
1436 }
1437 case ValueItem::Type::FLOAT: {
1438 if (!writer->Write(bit_cast<uint32_t>(value_item->GetAsScalar()->GetValue<float>()))) {
1439 return false;
1440 }
1441 break;
1442 }
1443 case ValueItem::Type::ID: {
1444 if (!writer->Write(value_item->GetAsScalar()->GetId().GetOffset())) {
1445 return false;
1446 }
1447 break;
1448 }
1449 default: {
1450 ASSERT(value_item->GetOffset() != 0);
1451 if (!writer->Write(value_item->GetOffset())) {
1452 return false;
1453 }
1454 break;
1455 }
1456 }
1457 }
1458
1459 for (auto tag : tags_) {
1460 if (!writer->Write(tag.GetItem())) {
1461 return false;
1462 }
1463 }
1464
1465 return true;
1466 }
1467
EmitEnd()1468 void LineNumberProgramItem::EmitEnd()
1469 {
1470 EmitOpcode(Opcode::END_SEQUENCE);
1471 }
1472
EmitAdvancePc(std::vector<uint8_t> * constant_pool,uint32_t value)1473 void LineNumberProgramItem::EmitAdvancePc(std::vector<uint8_t> *constant_pool, uint32_t value)
1474 {
1475 EmitOpcode(Opcode::ADVANCE_PC);
1476 EmitUleb128(constant_pool, value);
1477 }
1478
EmitAdvanceLine(std::vector<uint8_t> * constant_pool,int32_t value)1479 void LineNumberProgramItem::EmitAdvanceLine(std::vector<uint8_t> *constant_pool, int32_t value)
1480 {
1481 EmitOpcode(Opcode::ADVANCE_LINE);
1482 EmitSleb128(constant_pool, value);
1483 }
1484
EmitColumn(std::vector<uint8_t> * constant_pool,uint32_t pc_inc,uint32_t column)1485 void LineNumberProgramItem::EmitColumn(std::vector<uint8_t> *constant_pool, uint32_t pc_inc, uint32_t column)
1486 {
1487 if (pc_inc != 0U) {
1488 EmitAdvancePc(constant_pool, pc_inc);
1489 }
1490 EmitOpcode(Opcode::SET_COLUMN);
1491 EmitUleb128(constant_pool, column);
1492 }
1493
EmitStartLocal(std::vector<uint8_t> * constant_pool,int32_t register_number,StringItem * name,StringItem * type)1494 void LineNumberProgramItem::EmitStartLocal(std::vector<uint8_t> *constant_pool, int32_t register_number,
1495 StringItem *name, StringItem *type)
1496 {
1497 EmitStartLocalExtended(constant_pool, register_number, name, type, nullptr);
1498 }
1499
EmitStartLocalExtended(std::vector<uint8_t> * constant_pool,int32_t register_number,StringItem * name,StringItem * type,StringItem * type_signature)1500 void LineNumberProgramItem::EmitStartLocalExtended(std::vector<uint8_t> *constant_pool, int32_t register_number,
1501 StringItem *name, StringItem *type, StringItem *type_signature)
1502 {
1503 ASSERT(name != nullptr);
1504 ASSERT(type != nullptr);
1505 EmitOpcode(type_signature == nullptr ? Opcode::START_LOCAL : Opcode::START_LOCAL_EXTENDED);
1506 EmitRegister(register_number);
1507 ASSERT(name->GetOffset() != 0);
1508 EmitUleb128(constant_pool, name->GetOffset());
1509 ASSERT(type->GetOffset() != 0);
1510 EmitUleb128(constant_pool, type->GetOffset());
1511
1512 if (type_signature != nullptr) {
1513 ASSERT(type_signature->GetOffset() != 0);
1514 EmitUleb128(constant_pool, type_signature->GetOffset());
1515 }
1516 }
1517
EmitEndLocal(int32_t register_number)1518 void LineNumberProgramItem::EmitEndLocal(int32_t register_number)
1519 {
1520 EmitOpcode(Opcode::END_LOCAL);
1521 EmitRegister(register_number);
1522 }
1523
EmitRestartLocal(int32_t register_number)1524 void LineNumberProgramItem::EmitRestartLocal(int32_t register_number)
1525 {
1526 EmitOpcode(Opcode::RESTART_LOCAL);
1527 EmitRegister(register_number);
1528 }
1529
EmitSpecialOpcode(uint32_t pc_inc,int32_t line_inc)1530 bool LineNumberProgramItem::EmitSpecialOpcode(uint32_t pc_inc, int32_t line_inc)
1531 {
1532 if (line_inc < LINE_BASE || (line_inc - LINE_BASE) >= LINE_RANGE) {
1533 return false;
1534 }
1535
1536 auto opcode = static_cast<size_t>(line_inc - LINE_BASE) + static_cast<size_t>(pc_inc * LINE_RANGE) + OPCODE_BASE;
1537 if (opcode > std::numeric_limits<uint8_t>::max()) {
1538 return false;
1539 }
1540
1541 data_.push_back(static_cast<uint8_t>(opcode));
1542 return true;
1543 }
1544
EmitPrologEnd()1545 void LineNumberProgramItem::EmitPrologEnd()
1546 {
1547 EmitOpcode(Opcode::SET_PROLOGUE_END);
1548 }
1549
EmitEpilogBegin()1550 void LineNumberProgramItem::EmitEpilogBegin()
1551 {
1552 EmitOpcode(Opcode::SET_EPILOGUE_BEGIN);
1553 }
1554
EmitSetFile(std::vector<uint8_t> * constant_pool,StringItem * source_file)1555 void LineNumberProgramItem::EmitSetFile(std::vector<uint8_t> *constant_pool, StringItem *source_file)
1556 {
1557 EmitOpcode(Opcode::SET_FILE);
1558
1559 if (source_file == nullptr) {
1560 return;
1561 }
1562 ASSERT(source_file->GetOffset() != 0);
1563 EmitUleb128(constant_pool, source_file->GetOffset());
1564 }
1565
EmitSetSourceCode(std::vector<uint8_t> * constant_pool,StringItem * source_code)1566 void LineNumberProgramItem::EmitSetSourceCode(std::vector<uint8_t> *constant_pool, StringItem *source_code)
1567 {
1568 EmitOpcode(Opcode::SET_SOURCE_CODE);
1569
1570 if (source_code == nullptr) {
1571 return;
1572 }
1573
1574 ASSERT(source_code->GetOffset() != 0);
1575 EmitUleb128(constant_pool, source_code->GetOffset());
1576 }
1577
EmitOpcode(Opcode opcode)1578 void LineNumberProgramItem::EmitOpcode(Opcode opcode)
1579 {
1580 data_.push_back(static_cast<uint8_t>(opcode));
1581 }
1582
EmitRegister(int32_t register_number)1583 void LineNumberProgramItem::EmitRegister(int32_t register_number)
1584 {
1585 EmitSleb128(&data_, register_number);
1586 }
1587
1588 /* static */
EmitUleb128(std::vector<uint8_t> * data,uint32_t value)1589 void LineNumberProgramItem::EmitUleb128(std::vector<uint8_t> *data, uint32_t value)
1590 {
1591 size_t n = leb128::UnsignedEncodingSize(value);
1592 std::vector<uint8_t> out(n);
1593 leb128::EncodeUnsigned(value, out.data());
1594
1595 if (data == nullptr) {
1596 return;
1597 }
1598
1599 data->insert(data->end(), out.cbegin(), out.cend());
1600 }
1601
1602 /* static */
EmitSleb128(std::vector<uint8_t> * data,int32_t value)1603 void LineNumberProgramItem::EmitSleb128(std::vector<uint8_t> *data, int32_t value)
1604 {
1605 size_t n = leb128::SignedEncodingSize(value);
1606 std::vector<uint8_t> out(n);
1607 leb128::EncodeSigned(value, out.data());
1608 data->insert(data->end(), out.cbegin(), out.cend());
1609 }
1610
CalculateSize() const1611 size_t LineNumberProgramItem::CalculateSize() const
1612 {
1613 return data_.size();
1614 }
1615
Write(Writer * writer)1616 bool LineNumberProgramItem::Write(Writer *writer)
1617 {
1618 ASSERT(GetOffset() == writer->GetOffset());
1619
1620 return writer->WriteBytes(data_);
1621 }
1622
SetData(std::vector<uint8_t> && data)1623 void LineNumberProgramItem::SetData(std::vector<uint8_t> &&data)
1624 {
1625 data_ = std::move(data);
1626 }
1627
CalculateSize() const1628 size_t DebugInfoItem::CalculateSize() const
1629 {
1630 size_t n = leb128::UnsignedEncodingSize(line_num_) + leb128::UnsignedEncodingSize(parameters_.size());
1631
1632 for (auto *p : parameters_) {
1633 ASSERT(p == nullptr || p->GetOffset() != 0);
1634 n += leb128::UnsignedEncodingSize(p == nullptr ? 0 : p->GetOffset());
1635 }
1636
1637 n += leb128::UnsignedEncodingSize(constant_pool_.size());
1638 n += constant_pool_.size();
1639
1640 n += leb128::UnsignedEncodingSize(program_->GetIndex(this));
1641
1642 return n;
1643 }
1644
Write(Writer * writer)1645 bool DebugInfoItem::Write(Writer *writer)
1646 {
1647 ASSERT(GetOffset() == writer->GetOffset());
1648
1649 if (!writer->WriteUleb128(line_num_)) {
1650 return false;
1651 }
1652
1653 if (!writer->WriteUleb128(parameters_.size())) {
1654 return false;
1655 }
1656
1657 for (auto *p : parameters_) {
1658 ASSERT(p == nullptr || p->GetOffset() != 0);
1659
1660 if (!writer->WriteUleb128(p == nullptr ? 0 : p->GetOffset())) {
1661 return false;
1662 }
1663 }
1664
1665 if (!writer->WriteUleb128(constant_pool_.size())) {
1666 return false;
1667 }
1668
1669 if (!writer->WriteBytes(constant_pool_)) {
1670 return false;
1671 }
1672
1673 ASSERT(program_ != nullptr);
1674 ASSERT(program_->HasIndex(this));
1675
1676 return writer->WriteUleb128(program_->GetIndex(this));
1677 }
1678
Dump(std::ostream & os) const1679 void DebugInfoItem::Dump(std::ostream &os) const
1680 {
1681 os << "line_start = " << line_num_ << std::endl;
1682
1683 os << "num_parameters = " << parameters_.size() << std::endl;
1684 for (auto *item : parameters_) {
1685 if (item != nullptr) {
1686 os << " string_item[" << item->GetOffset() << "]" << std::endl;
1687 } else {
1688 os << " string_item[INVALID_OFFSET]" << std::endl;
1689 }
1690 }
1691
1692 os << "constant_pool = [";
1693 for (size_t i = 0; i < constant_pool_.size(); i++) {
1694 size_t b = constant_pool_[i];
1695 os << "0x" << std::setfill('0') << std::setw(2U) << std::right << std::hex << b << std::dec;
1696 if (i < constant_pool_.size() - 1) {
1697 os << ", ";
1698 }
1699 }
1700 os << "]" << std::endl;
1701
1702 os << "line_number_program = line_number_program_idx[";
1703 if (program_ != nullptr && program_->HasIndex(this)) {
1704 os << program_->GetIndex(this);
1705 } else {
1706 os << "NO_INDEX";
1707 }
1708 os << "]";
1709 }
1710
Write(Writer * writer)1711 bool MethodHandleItem::Write(Writer *writer)
1712 {
1713 ASSERT(GetOffset() == writer->GetOffset());
1714
1715 if (!writer->WriteByte(static_cast<uint8_t>(type_))) {
1716 return false;
1717 }
1718
1719 return writer->WriteUleb128(entity_->GetOffset());
1720 }
1721
1722 } // namespace panda::panda_file
1723