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