• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 "assembly-emitter.h"
17 
18 #include "bytecode_instruction-inl.h"
19 #include "emit-item.h"
20 #include "mangling.h"
21 
22 namespace {
23 
24 using panda::os::file::Mode;
25 using panda::os::file::Open;
26 using panda::panda_file::AnnotationItem;
27 using panda::panda_file::ArrayValueItem;
28 using panda::panda_file::BaseClassItem;
29 using panda::panda_file::BaseFieldItem;
30 using panda::panda_file::BaseMethodItem;
31 using panda::panda_file::ClassItem;
32 using panda::panda_file::CodeItem;
33 using panda::panda_file::DebugInfoItem;
34 using panda::panda_file::FieldItem;
35 using panda::panda_file::FileWriter;
36 using panda::panda_file::ForeignClassItem;
37 using panda::panda_file::ForeignFieldItem;
38 using panda::panda_file::ForeignMethodItem;
39 using panda::panda_file::ItemContainer;
40 using panda::panda_file::LineNumberProgramItem;
41 using panda::panda_file::MemoryBufferWriter;
42 using panda::panda_file::MethodHandleItem;
43 using panda::panda_file::MethodItem;
44 using panda::panda_file::MethodParamItem;
45 using panda::panda_file::ParamAnnotationsItem;
46 using panda::panda_file::PrimitiveTypeItem;
47 using panda::panda_file::ProtoItem;
48 using panda::panda_file::ScalarValueItem;
49 using panda::panda_file::StringItem;
50 using panda::panda_file::Type;
51 using panda::panda_file::TypeItem;
52 using panda::panda_file::ValueItem;
53 using panda::panda_file::Writer;
54 using panda::panda_file::LiteralArrayItem;
55 
CreatePrimitiveTypes(ItemContainer * container)56 std::unordered_map<Type::TypeId, PrimitiveTypeItem *> CreatePrimitiveTypes(ItemContainer *container)
57 {
58     auto res = std::unordered_map<Type::TypeId, PrimitiveTypeItem *> {};
59     res.insert({Type::TypeId::VOID, container->GetOrCreatePrimitiveTypeItem(Type::TypeId::VOID)});
60     res.insert({Type::TypeId::U1, container->GetOrCreatePrimitiveTypeItem(Type::TypeId::U1)});
61     res.insert({Type::TypeId::I8, container->GetOrCreatePrimitiveTypeItem(Type::TypeId::I8)});
62     res.insert({Type::TypeId::U8, container->GetOrCreatePrimitiveTypeItem(Type::TypeId::U8)});
63     res.insert({Type::TypeId::I16, container->GetOrCreatePrimitiveTypeItem(Type::TypeId::I16)});
64     res.insert({Type::TypeId::U16, container->GetOrCreatePrimitiveTypeItem(Type::TypeId::U16)});
65     res.insert({Type::TypeId::I32, container->GetOrCreatePrimitiveTypeItem(Type::TypeId::I32)});
66     res.insert({Type::TypeId::U32, container->GetOrCreatePrimitiveTypeItem(Type::TypeId::U32)});
67     res.insert({Type::TypeId::I64, container->GetOrCreatePrimitiveTypeItem(Type::TypeId::I64)});
68     res.insert({Type::TypeId::U64, container->GetOrCreatePrimitiveTypeItem(Type::TypeId::U64)});
69     res.insert({Type::TypeId::F32, container->GetOrCreatePrimitiveTypeItem(Type::TypeId::F32)});
70     res.insert({Type::TypeId::F64, container->GetOrCreatePrimitiveTypeItem(Type::TypeId::F64)});
71     res.insert({Type::TypeId::TAGGED, container->GetOrCreatePrimitiveTypeItem(Type::TypeId::TAGGED)});
72     return res;
73 }
74 
75 template <class T>
Find(const T & map,typename T::key_type key)76 typename T::mapped_type Find(const T &map, typename T::key_type key)
77 {
78     auto res = map.find(key);
79     ASSERT(res != map.end());
80     return res->second;
81 }
82 
83 }  // anonymous namespace
84 
85 namespace panda::pandasm {
86 
87 /* static */
88 std::string AsmEmitter::last_error("");
89 
GetTypeId(Value::Type type)90 static panda_file::Type::TypeId GetTypeId(Value::Type type)
91 {
92     switch (type) {
93         case Value::Type::U1:
94             return panda_file::Type::TypeId::U1;
95         case Value::Type::I8:
96             return panda_file::Type::TypeId::I8;
97         case Value::Type::U8:
98             return panda_file::Type::TypeId::U8;
99         case Value::Type::I16:
100             return panda_file::Type::TypeId::I16;
101         case Value::Type::U16:
102             return panda_file::Type::TypeId::U16;
103         case Value::Type::I32:
104             return panda_file::Type::TypeId::I32;
105         case Value::Type::U32:
106             return panda_file::Type::TypeId::U32;
107         case Value::Type::I64:
108             return panda_file::Type::TypeId::I64;
109         case Value::Type::U64:
110             return panda_file::Type::TypeId::U64;
111         case Value::Type::F32:
112             return panda_file::Type::TypeId::F32;
113         case Value::Type::F64:
114             return panda_file::Type::TypeId::F64;
115         case Value::Type::VOID:
116             return panda_file::Type::TypeId::VOID;
117         default:
118             return panda_file::Type::TypeId::REFERENCE;
119     }
120 }
121 
122 /* static */
GetMethodSignatureFromProgram(const std::string & name,const Program & program)123 std::string AsmEmitter::GetMethodSignatureFromProgram(const std::string &name, const Program &program)
124 {
125     if (IsSignatureOrMangled(name)) {
126         return name;
127     }
128 
129     const auto it_synonym = program.function_synonyms.find(name);
130     const bool is_method_known = (it_synonym != program.function_synonyms.end());
131     const bool is_single_synonym = (is_method_known && (it_synonym->second.size() == 1));
132     if (is_single_synonym) {
133         return it_synonym->second[0];
134     } else {
135         SetLastError("More than one alternative for method " + name);
136         return std::string("");
137     }
138 }
139 
140 /* static */
CreateLiteralItem(ItemContainer * container,const Value * value,std::vector<panda_file::LiteralItem> * out,const AsmEmitter::AsmEntityCollections & entities)141 panda_file::LiteralItem *AsmEmitter::CreateLiteralItem(
142     ItemContainer *container, const Value *value, std::vector<panda_file::LiteralItem> *out,
143     const AsmEmitter::AsmEntityCollections &entities)
144 {
145     ASSERT(out != nullptr);
146 
147     auto value_type = value->GetType();
148 
149     switch (value_type) {
150         case Value::Type::U1:
151         case Value::Type::I8:
152         case Value::Type::U8: {
153             auto v = value->GetAsScalar()->GetValue<uint8_t>();
154             out->emplace_back(v);
155             return &out->back();
156         }
157         case Value::Type::I16:
158         case Value::Type::U16: {
159             auto v = value->GetAsScalar()->GetValue<uint16_t>();
160             out->emplace_back(v);
161             return &out->back();
162         }
163         case Value::Type::I32:
164         case Value::Type::U32:
165         case Value::Type::STRING_NULLPTR: {
166             auto v = value->GetAsScalar()->GetValue<uint32_t>();
167             out->emplace_back(v);
168             return &out->back();
169         }
170         case Value::Type::I64:
171         case Value::Type::U64: {
172             auto v = value->GetAsScalar()->GetValue<uint64_t>();
173             out->emplace_back(v);
174             return &out->back();
175         }
176         case Value::Type::F32: {
177             auto v = bit_cast<uint32_t>(value->GetAsScalar()->GetValue<float>());
178             out->emplace_back(v);
179             return &out->back();
180         }
181         case Value::Type::F64: {
182             auto v = bit_cast<uint64_t>(value->GetAsScalar()->GetValue<double>());
183             out->emplace_back(v);
184             return &out->back();
185         }
186         case Value::Type::STRING: {
187             auto *string_item = container->GetOrCreateStringItem(value->GetAsScalar()->GetValue<std::string>());
188             out->emplace_back(string_item);
189             return &out->back();
190         }
191         case Value::Type::METHOD: {
192             auto name = value->GetAsScalar()->GetValue<std::string>();
193             auto method_item = static_cast<panda::panda_file::MethodItem *>(Find(entities.method_items, name));
194             out->emplace_back(method_item);
195             return &out->back();
196         }
197         case Value::Type::LITERALARRAY: {
198             auto key = value->GetAsScalar()->GetValue<std::string>();
199             auto lit_item = Find(entities.literalarray_items, key);
200             out->emplace_back(lit_item);
201             return &out->back();
202         }
203         default:
204             return nullptr;
205     }
206 }
207 
208 /* static */
CreateScalarStringValueItem(ItemContainer * container,const Value * value,std::vector<ScalarValueItem> * out)209 ScalarValueItem *AsmEmitter::CreateScalarStringValueItem(ItemContainer *container, const Value *value,
210                                                          std::vector<ScalarValueItem> *out)
211 {
212     auto *string_item = container->GetOrCreateStringItem(value->GetAsScalar()->GetValue<std::string>());
213     if (out != nullptr) {
214         out->emplace_back(string_item, container);
215         return &out->back();
216     }
217 
218     return container->CreateItem<ScalarValueItem>(string_item);
219 }
220 
221 /* static */
CreateScalarRecordValueItem(ItemContainer * container,const Value * value,std::vector<ScalarValueItem> * out,const std::unordered_map<std::string,BaseClassItem * > & classes)222 ScalarValueItem *AsmEmitter::CreateScalarRecordValueItem(
223     ItemContainer *container, const Value *value, std::vector<ScalarValueItem> *out,
224     const std::unordered_map<std::string, BaseClassItem *> &classes)
225 {
226     auto type = value->GetAsScalar()->GetValue<Type>();
227     BaseClassItem *class_item;
228     if (type.IsObject()) {
229         auto name = type.GetName();
230         auto it = classes.find(name);
231         if (it == classes.cend()) {
232             return nullptr;
233         }
234 
235         class_item = it->second;
236     } else {
237         class_item = container->GetOrCreateForeignClassItem(type.GetDescriptor());
238     }
239 
240     if (out != nullptr) {
241         out->emplace_back(class_item, container);
242         return &out->back();
243     }
244 
245     return container->CreateItem<ScalarValueItem>(class_item);
246 }
247 
248 /* static */
CreateScalarMethodValueItem(ItemContainer * container,const Value * value,std::vector<ScalarValueItem> * out,const Program & program,const std::unordered_map<std::string,BaseMethodItem * > & methods)249 ScalarValueItem *AsmEmitter::CreateScalarMethodValueItem(
250     ItemContainer *container, const Value *value, std::vector<ScalarValueItem> *out, const Program &program,
251     const std::unordered_map<std::string, BaseMethodItem *> &methods)
252 {
253     auto name = value->GetAsScalar()->GetValue<std::string>();
254 
255     name = GetMethodSignatureFromProgram(name, program);
256 
257     auto it = methods.find(name);
258     if (it == methods.cend()) {
259         return nullptr;
260     }
261 
262     auto *method_item = it->second;
263     if (out != nullptr) {
264         out->emplace_back(method_item, container);
265         return &out->back();
266     }
267 
268     return container->CreateItem<ScalarValueItem>(method_item);
269 }
270 
271 /* static */
CreateScalarLiteralArrayItem(ItemContainer * container,const Value * value,std::vector<ScalarValueItem> * out,const Program & program,const std::unordered_map<std::string,LiteralArrayItem * > & literalarrays)272 ScalarValueItem *AsmEmitter::CreateScalarLiteralArrayItem(
273     ItemContainer *container, const Value *value, std::vector<ScalarValueItem> *out, const Program &program,
274     const std::unordered_map<std::string, LiteralArrayItem *> &literalarrays)
275 {
276     auto name = value->GetAsScalar()->GetValue<std::string>();
277     auto it = literalarrays.find(name);
278     ASSERT(it != literalarrays.end());
279     auto *literalarray_item = it->second;
280     if (out != nullptr) {
281         out->emplace_back(literalarray_item, container);
282         return &out->back();
283     }
284 
285     return container->CreateItem<ScalarValueItem>(literalarray_item);
286 }
287 
288 /* static */
CreateScalarEnumValueItem(ItemContainer * container,const Value * value,std::vector<ScalarValueItem> * out,const std::unordered_map<std::string,BaseFieldItem * > & fields)289 ScalarValueItem *AsmEmitter::CreateScalarEnumValueItem(ItemContainer *container, const Value *value,
290                                                        std::vector<ScalarValueItem> *out,
291                                                        const std::unordered_map<std::string, BaseFieldItem *> &fields)
292 {
293     auto name = value->GetAsScalar()->GetValue<std::string>();
294     auto it = fields.find(name);
295     if (it == fields.cend()) {
296         return nullptr;
297     }
298 
299     auto *field_item = it->second;
300     if (out != nullptr) {
301         out->emplace_back(field_item, container);
302         return &out->back();
303     }
304 
305     return container->CreateItem<ScalarValueItem>(field_item);
306 }
307 
308 /* static */
CreateScalarAnnotationValueItem(ItemContainer * container,const Value * value,std::vector<ScalarValueItem> * out,const Program & program,const AsmEmitter::AsmEntityCollections & entities)309 ScalarValueItem *AsmEmitter::CreateScalarAnnotationValueItem(
310     ItemContainer *container, const Value *value, std::vector<ScalarValueItem> *out, const Program &program,
311     const AsmEmitter::AsmEntityCollections &entities)
312 {
313     auto annotation = value->GetAsScalar()->GetValue<AnnotationData>();
314     auto *annotation_item = CreateAnnotationItem(container, annotation, program, entities);
315     if (annotation_item == nullptr) {
316         return nullptr;
317     }
318 
319     if (out != nullptr) {
320         out->emplace_back(annotation_item, container);
321         return &out->back();
322     }
323 
324     return container->CreateItem<ScalarValueItem>(annotation_item);
325 }
326 
327 /* static */
CreateScalarValueItem(ItemContainer * container,const Value * value,std::vector<ScalarValueItem> * out,const Program & program,const AsmEmitter::AsmEntityCollections & entities)328 ScalarValueItem *AsmEmitter::CreateScalarValueItem(ItemContainer *container, const Value *value,
329                                                    std::vector<ScalarValueItem> *out, const Program &program,
330                                                    const AsmEmitter::AsmEntityCollections &entities)
331 {
332     auto value_type = value->GetType();
333 
334     switch (value_type) {
335         case Value::Type::U1:
336         case Value::Type::I8:
337         case Value::Type::U8:
338         case Value::Type::I16:
339         case Value::Type::U16:
340         case Value::Type::I32:
341         case Value::Type::U32:
342         case Value::Type::STRING_NULLPTR: {
343             return CreateScalarPrimValueItem<uint32_t>(container, value, out);
344         }
345         case Value::Type::I64:
346         case Value::Type::U64: {
347             return CreateScalarPrimValueItem<uint64_t>(container, value, out);
348         }
349         case Value::Type::F32: {
350             return CreateScalarPrimValueItem<float>(container, value, out);
351         }
352         case Value::Type::F64: {
353             return CreateScalarPrimValueItem<double>(container, value, out);
354         }
355         case Value::Type::STRING: {
356             return CreateScalarStringValueItem(container, value, out);
357         }
358         case Value::Type::RECORD: {
359             return CreateScalarRecordValueItem(container, value, out, entities.class_items);
360         }
361         case Value::Type::METHOD: {
362             return CreateScalarMethodValueItem(container, value, out, program, entities.method_items);
363         }
364         case Value::Type::ENUM: {
365             return CreateScalarEnumValueItem(container, value, out, entities.field_items);
366         }
367         case Value::Type::ANNOTATION: {
368             return CreateScalarAnnotationValueItem(container, value, out, program, entities);
369         }
370         case Value::Type::LITERALARRAY: {
371             return CreateScalarLiteralArrayItem(container, value, out, program, entities.literalarray_items);
372         }
373         default: {
374             UNREACHABLE();
375             return nullptr;
376         }
377     }
378 }
379 
380 /* static */
CreateValueItem(ItemContainer * container,const Value * value,const Program & program,const AsmEmitter::AsmEntityCollections & entities)381 ValueItem *AsmEmitter::CreateValueItem(ItemContainer *container, const Value *value, const Program &program,
382                                        const AsmEmitter::AsmEntityCollections &entities)
383 {
384     switch (value->GetType()) {
385         case Value::Type::ARRAY: {
386             std::vector<ScalarValueItem> elements;
387             for (const auto &elem_value : value->GetAsArray()->GetValues()) {
388                 auto *item =
389                     CreateScalarValueItem(container, &elem_value, &elements, program, entities);
390                 if (item == nullptr) {
391                     return nullptr;
392                 }
393             }
394 
395             auto component_type = value->GetAsArray()->GetComponentType();
396             return container->CreateItem<ArrayValueItem>(panda_file::Type(GetTypeId(component_type)),
397                                                          std::move(elements));
398         }
399         default: {
400             return CreateScalarValueItem(container, value, nullptr, program, entities);
401         }
402     }
403 }
404 
405 /* static */
CreateAnnotationItem(ItemContainer * container,const AnnotationData & annotation,const Program & program,const AsmEmitter::AsmEntityCollections & entities)406 AnnotationItem *AsmEmitter::CreateAnnotationItem(ItemContainer *container, const AnnotationData &annotation,
407     const Program &program, const AsmEmitter::AsmEntityCollections &entities)
408 {
409     auto record_name = annotation.GetName();
410     if (!program.isGeneratedFromMergedAbc) {
411         auto it = program.record_table.find(record_name);
412         if (it == program.record_table.cend()) {
413             SetLastError("Record " + record_name + " not found");
414             return nullptr;
415         }
416 
417         auto &record = it->second;
418         // For an imported custom annotation, it will be represented as external.
419         if (!record.metadata->IsAnnotation() && !record.metadata->IsForeign()) {
420             SetLastError("Record " + record_name + " isn't annotation");
421             return nullptr;
422         }
423     }
424 
425     std::vector<AnnotationItem::Elem> item_elements;
426     std::vector<AnnotationItem::Tag> tag_elements;
427 
428     for (const auto &element : annotation.GetElements()) {
429         auto name = element.GetName();
430         auto *value = element.GetValue();
431 
432         auto value_type = value->GetType();
433 
434         uint8_t tag_type;
435 
436         if (value_type == Value::Type::ARRAY && !value->GetAsArray()->GetValues().empty()) {
437             auto array_element_type = value->GetAsArray()->GetComponentType();
438             tag_type = static_cast<uint8_t>(Value::GetArrayTypeAsChar(array_element_type));
439         } else {
440             tag_type = static_cast<uint8_t>(Value::GetTypeAsChar(value_type));
441         }
442 
443         ASSERT(tag_type != '0');
444 
445         auto *item = CreateValueItem(container, value, program, entities);
446         if (item == nullptr) {
447             SetLastError("Cannot create value item for annotation element " + name + ": " + GetLastError());
448             return nullptr;
449         }
450 
451         item_elements.emplace_back(container->GetOrCreateStringItem(name), item);
452         tag_elements.emplace_back(tag_type);
453     }
454 
455     auto *cls = entities.class_items.find(record_name)->second;
456     return container->CreateItem<AnnotationItem>(cls, std::move(item_elements), std::move(tag_elements));
457 }
458 
CreateMethodHandleItem(ItemContainer * container,const MethodHandle & mh,const std::unordered_map<std::string,BaseFieldItem * > & fields,const std::unordered_map<std::string,BaseMethodItem * > & methods)459 MethodHandleItem *AsmEmitter::CreateMethodHandleItem(ItemContainer *container, const MethodHandle &mh,
460                                                      const std::unordered_map<std::string, BaseFieldItem *> &fields,
461                                                      const std::unordered_map<std::string, BaseMethodItem *> &methods)
462 {
463     MethodHandleItem *item = nullptr;
464     switch (mh.type) {
465         case panda_file::MethodHandleType::PUT_STATIC:
466         case panda_file::MethodHandleType::GET_STATIC:
467         case panda_file::MethodHandleType::PUT_INSTANCE:
468         case panda_file::MethodHandleType::GET_INSTANCE: {
469             item = container->CreateItem<MethodHandleItem>(mh.type, fields.at(mh.item_name));
470             break;
471         }
472         case panda_file::MethodHandleType::INVOKE_STATIC:
473         case panda_file::MethodHandleType::INVOKE_INSTANCE:
474         case panda_file::MethodHandleType::INVOKE_CONSTRUCTOR:
475         case panda_file::MethodHandleType::INVOKE_DIRECT:
476         case panda_file::MethodHandleType::INVOKE_INTERFACE: {
477             item = container->CreateItem<MethodHandleItem>(mh.type, methods.at(mh.item_name));
478             break;
479         }
480         default:
481             UNREACHABLE();
482             break;
483     }
484     return item;
485 }
486 
487 /* static */
488 template <class T>
AddAnnotations(T * item,ItemContainer * container,const AnnotationMetadata & metadata,const Program & program,const AsmEmitter::AsmEntityCollections & entities)489 bool AsmEmitter::AddAnnotations(T *item, ItemContainer *container, const AnnotationMetadata &metadata,
490                                 const Program &program, const AsmEmitter::AsmEntityCollections &entities)
491 {
492     for (const auto &annotation : metadata.GetAnnotations()) {
493         auto *annotation_item = CreateAnnotationItem(container, annotation, program, entities);
494         if (annotation_item == nullptr) {
495             return false;
496         }
497 
498         /**
499          * When abc is used as input, the function annotation and its corresponding record
500          * are placed into two different programs, which causes the record to be missing
501          * from the record_table of the program that contains the function annotation.
502          */
503         if (program.isGeneratedFromMergedAbc &&
504             program.record_table.find(annotation.GetName()) == program.record_table.cend()) {
505             item->AddAnnotation(annotation_item);
506             continue;
507         }
508 
509         auto &record = program.record_table.find(annotation.GetName())->second;
510         if (record.metadata->IsRuntimeAnnotation()) {
511             item->AddRuntimeAnnotation(annotation_item);
512         } else if (record.metadata->IsAnnotation()) {
513             item->AddAnnotation(annotation_item);
514         } else if (record.metadata->IsRuntimeTypeAnnotation()) {
515             item->AddRuntimeTypeAnnotation(annotation_item);
516         } else if (record.metadata->IsTypeAnnotation()) {
517             item->AddTypeAnnotation(annotation_item);
518         }
519     }
520 
521     return true;
522 }
523 
524 template <class T>
AddDependencyByIndex(MethodItem * method,const InsPtr & insn,const std::unordered_map<std::string,T * > & items,size_t idx=0)525 static bool AddDependencyByIndex(MethodItem *method, const InsPtr &insn,
526                                  const std::unordered_map<std::string, T *> &items, size_t idx = 0)
527 {
528     auto ids = insn->Ids();
529     if (idx >= ids.size()) {
530         return false;
531     };
532     const auto &id = ids[idx];
533     auto it = items.find(id);
534     ASSERT(it != items.cend());
535     auto *item = it->second;
536     ASSERT(item->GetIndexType() != panda_file::IndexType::NONE);
537     method->AddIndexDependency(item);
538     return true;
539 }
540 
AddBytecodeIndexDependencies(MethodItem * method,const Function & func,const AsmEmitter::AsmEntityCollections & entities)541 static bool AddBytecodeIndexDependencies(MethodItem *method, const Function &func,
542                                          const AsmEmitter::AsmEntityCollections &entities)
543 {
544     for (const auto &insn : func.ins) {
545         if (insn->opcode == Opcode::INVALID) {
546             continue;
547         }
548 
549         if (insn->opcode == Opcode::DEFINECLASSWITHBUFFER) {
550             if (!AddDependencyByIndex(method, insn, entities.method_items)) {
551                 return false;
552             }
553             if (!AddDependencyByIndex(method, insn, entities.literalarray_items, 1)) {
554                 return false;
555             }
556             continue;
557         }
558 
559         if (insn->opcode == Opcode::CALLRUNTIME_DEFINESENDABLECLASS) {
560             if (!AddDependencyByIndex(method, insn, entities.method_items)) {
561                 return false;
562             }
563             if (!AddDependencyByIndex(method, insn, entities.literalarray_items, 1)) {
564                 return false;
565             }
566             continue;
567         }
568 
569         if (insn->HasFlag(InstFlags::METHOD_ID)) {
570             if (!AddDependencyByIndex(method, insn, entities.method_items)) {
571                 return false;
572             }
573             continue;
574         }
575 
576         if (insn->HasFlag(InstFlags::STRING_ID)) {
577             if (!AddDependencyByIndex(method, insn, entities.string_items)) {
578                 return false;
579             }
580             continue;
581         }
582 
583         if (insn->HasFlag(InstFlags::LITERALARRAY_ID)) {
584             if (!AddDependencyByIndex(method, insn, entities.literalarray_items)) {
585                 return false;
586             }
587         }
588     }
589     return true;
590 }
591 
592 /* static */
MakeStringItems(ItemContainer * items,const Program & program,AsmEmitter::AsmEntityCollections & entities)593 void AsmEmitter::MakeStringItems(ItemContainer *items, const Program &program,
594                                  AsmEmitter::AsmEntityCollections &entities)
595 {
596     for (const auto &s : program.strings) {
597         auto *item = items->GetOrCreateStringItem(s);
598         entities.string_items.insert({s, item});
599     }
600 }
601 
602 /* static */
MakeLiteralItems(ItemContainer * items,const Program & program,AsmEmitter::AsmEntityCollections & entities)603 void AsmEmitter::MakeLiteralItems(ItemContainer *items, const Program &program,
604                                   AsmEmitter::AsmEntityCollections &entities)
605 {
606     for (const auto &[id, l] : program.literalarray_table) {
607         auto *literal_array_item = items->GetOrCreateLiteralArrayItem(id);
608         entities.literalarray_items.insert({id, literal_array_item});
609     }
610 
611     for (const auto &[id, l] : program.literalarray_table) {
612         auto *literal_array_item = entities.literalarray_items.find(id)->second;
613         std::vector<panda_file::LiteralItem> literal_array;
614         for (auto &literal : l.literals_) {
615             std::unique_ptr<ScalarValue> value;
616             switch (literal.tag_) {
617                 case panda_file::LiteralTag::ARRAY_U1: {
618                     ASSERT(program.array_types.find(Type("u1", 1)) != program.array_types.end());
619                     value = std::make_unique<ScalarValue>(
620                         ScalarValue::Create<Value::Type::U1>(static_cast<bool>(std::get<bool>(literal.value_))));
621                     break;
622                 }
623                 case panda_file::LiteralTag::ARRAY_U8: {
624                     ASSERT(program.array_types.find(Type("u8", 1)) != program.array_types.end());
625                     value = std::make_unique<ScalarValue>(
626                         ScalarValue::Create<Value::Type::U8>(std::get<uint8_t>(literal.value_)));
627                     break;
628                 }
629                 case panda_file::LiteralTag::ARRAY_I8: {
630                     ASSERT(program.array_types.find(Type("i8", 1)) != program.array_types.end());
631                     value = std::make_unique<ScalarValue>(
632                         ScalarValue::Create<Value::Type::I8>(std::get<uint8_t>(literal.value_)));
633                     break;
634                 }
635                 case panda_file::LiteralTag::ARRAY_U16: {
636                     ASSERT(program.array_types.find(Type("u16", 1)) != program.array_types.end());
637                     value = std::make_unique<ScalarValue>(
638                         ScalarValue::Create<Value::Type::U16>(std::get<uint16_t>(literal.value_)));
639                     break;
640                 }
641                 case panda_file::LiteralTag::ARRAY_I16: {
642                     ASSERT(program.array_types.find(Type("i16", 1)) != program.array_types.end());
643                     value = std::make_unique<ScalarValue>(
644                         ScalarValue::Create<Value::Type::I16>(std::get<uint16_t>(literal.value_)));
645                     break;
646                 }
647                 case panda_file::LiteralTag::ARRAY_U32: {
648                     ASSERT(program.array_types.find(Type("u32", 1)) != program.array_types.end());
649                     value = std::make_unique<ScalarValue>(
650                         ScalarValue::Create<Value::Type::U32>(std::get<uint32_t>(literal.value_)));
651                     break;
652                 }
653                 case panda_file::LiteralTag::ARRAY_I32: {
654                     ASSERT(program.array_types.find(Type("i32", 1)) != program.array_types.end());
655                     value = std::make_unique<ScalarValue>(
656                         ScalarValue::Create<Value::Type::I32>(std::get<uint32_t>(literal.value_)));
657                     break;
658                 }
659                 case panda_file::LiteralTag::ARRAY_U64: {
660                     ASSERT(program.array_types.find(Type("u64", 1)) != program.array_types.end());
661                     value = std::make_unique<ScalarValue>(
662                         ScalarValue::Create<Value::Type::U64>(std::get<uint64_t>(literal.value_)));
663                     break;
664                 }
665                 case panda_file::LiteralTag::ARRAY_I64: {
666                     ASSERT(program.array_types.find(Type("i64", 1)) != program.array_types.end());
667                     value = std::make_unique<ScalarValue>(
668                         ScalarValue::Create<Value::Type::I64>(std::get<uint64_t>(literal.value_)));
669                     break;
670                 }
671                 case panda_file::LiteralTag::ARRAY_F32: {
672                     ASSERT(program.array_types.find(Type("f32", 1)) != program.array_types.end());
673                     value = std::make_unique<ScalarValue>(
674                         ScalarValue::Create<Value::Type::F32>(std::get<float>(literal.value_)));
675                     break;
676                 }
677                 case panda_file::LiteralTag::ARRAY_F64: {
678                     ASSERT(program.array_types.find(Type("f64", 1)) != program.array_types.end());
679                     value = std::make_unique<ScalarValue>(
680                         ScalarValue::Create<Value::Type::F64>(std::get<double>(literal.value_)));
681                     break;
682                 }
683                 case panda_file::LiteralTag::ARRAY_STRING:
684                     ASSERT(program.array_types.find(Type(
685                         Type::FromDescriptor(panda::panda_file::GetStringClassDescriptor(program.lang)), 1)) !=
686                            program.array_types.end());
687                     value = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::STRING>(
688                         std::string_view(std::get<std::string>(literal.value_))));
689                     break;
690                 case panda_file::LiteralTag::TAGVALUE:
691                 case panda_file::LiteralTag::ACCESSOR:
692                 case panda_file::LiteralTag::NULLVALUE:
693                 case panda_file::LiteralTag::BUILTINTYPEINDEX:
694                     value = std::make_unique<ScalarValue>(
695                         ScalarValue::Create<Value::Type::U8>(static_cast<uint8_t>(std::get<uint8_t>(literal.value_))));
696                     break;
697                 case panda_file::LiteralTag::BOOL:
698                     value = std::make_unique<ScalarValue>(
699                         ScalarValue::Create<Value::Type::U8>(static_cast<uint8_t>(std::get<bool>(literal.value_))));
700                     break;
701                 case panda_file::LiteralTag::METHODAFFILIATE:
702                     value = std::make_unique<ScalarValue>(
703                         ScalarValue::Create<Value::Type::U16>(std::get<uint16_t>(literal.value_)));
704                     break;
705                 case panda_file::LiteralTag::INTEGER:
706                 case panda_file::LiteralTag::LITERALBUFFERINDEX:
707                     value = std::make_unique<ScalarValue>(
708                         ScalarValue::Create<Value::Type::I32>(std::get<uint32_t>(literal.value_)));
709                     break;
710                 case panda_file::LiteralTag::FLOAT:
711                     value = std::make_unique<ScalarValue>(
712                         ScalarValue::Create<Value::Type::F32>(std::get<float>(literal.value_)));
713                     break;
714                 case panda_file::LiteralTag::DOUBLE:
715                     value = std::make_unique<ScalarValue>(
716                         ScalarValue::Create<Value::Type::F64>(std::get<double>(literal.value_)));
717                     break;
718                 case panda_file::LiteralTag::STRING:
719                 case panda_file::LiteralTag::ETS_IMPLEMENTS:
720                     value = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::STRING>(
721                         std::string_view(std::get<std::string>(literal.value_))));
722                     break;
723                 case panda_file::LiteralTag::METHOD:
724                 case panda_file::LiteralTag::GETTER:
725                 case panda_file::LiteralTag::SETTER:
726                 case panda_file::LiteralTag::GENERATORMETHOD:
727                 case panda_file::LiteralTag::ASYNCGENERATORMETHOD:
728                     value = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::METHOD>(
729                         std::string_view(std::get<std::string>(literal.value_))));
730                     break;
731                 case panda_file::LiteralTag::LITERALARRAY:
732                     value = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::LITERALARRAY>(
733                         std::string_view(std::get<std::string>(literal.value_))));
734                     break;
735                 default:
736                     UNREACHABLE();
737             }
738 
739             // the return pointer of vector element should not be rewrited
740             CreateLiteralItem(items, value.get(), &literal_array, entities);
741         }
742         literal_array_item->AddItems(literal_array);
743     }
744 }
745 
746 /* static */
MakeArrayTypeItems(ItemContainer * items,const Program & program,AsmEmitter::AsmEntityCollections & entities)747 void AsmEmitter::MakeArrayTypeItems(ItemContainer *items, const Program &program,
748                                     AsmEmitter::AsmEntityCollections &entities)
749 {
750     for (const auto &t : program.array_types) {
751         auto *foreign_record = items->GetOrCreateForeignClassItem(t.GetDescriptor());
752         entities.class_items.insert({t.GetName(), foreign_record});
753     }
754 }
755 
756 /* static */
HandleRecordAsForeign(ItemContainer * items,const Program & program,AsmEmitter::AsmEntityCollections & entities,const std::unordered_map<panda_file::Type::TypeId,PrimitiveTypeItem * > & primitive_types,const std::string & name,const Record & rec)757 bool AsmEmitter::HandleRecordAsForeign(
758     ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities,
759     const std::unordered_map<panda_file::Type::TypeId, PrimitiveTypeItem *> &primitive_types, const std::string &name,
760     const Record &rec)
761 {
762     Type record_type = Type::FromName(name);
763     auto *foreign_record = items->GetOrCreateForeignClassItem(record_type.GetDescriptor(rec.conflict));
764     entities.class_items.insert({name, foreign_record});
765     for (const auto &f : rec.field_list) {
766         ASSERT(f.metadata->IsForeign());
767         auto *field_name = items->GetOrCreateStringItem(pandasm::DeMangleName(f.name));
768         std::string full_field_name = name + "." + f.name;
769         if (!f.metadata->IsForeign()) {
770             SetLastError("External record " + name + " has a non-external field " + f.name);
771             return false;
772         }
773         auto *type_item = GetTypeItem(items, primitive_types, f.type, program);
774         if (type_item == nullptr) {
775             SetLastError("Field " + full_field_name + " has undefined type");
776             return false;
777         }
778         auto *field = items->CreateItem<ForeignFieldItem>(foreign_record, field_name, type_item);
779         entities.field_items.insert({full_field_name, field});
780     }
781     return true;
782 }
783 
784 /* static */
HandleBaseRecord(ItemContainer * items,const Program & program,const std::string & name,const Record & base_rec,ClassItem * record)785 bool AsmEmitter::HandleBaseRecord(ItemContainer *items, const Program &program, const std::string &name,
786                                   const Record &base_rec, ClassItem *record)
787 {
788     auto base_name = base_rec.metadata->GetBase();
789     if (!base_name.empty()) {
790         auto it = program.record_table.find(base_name);
791         if (it == program.record_table.cend()) {
792             SetLastError("Base record " + base_name + " is not defined for record " + name);
793             return false;
794         }
795         auto &rec = it->second;
796         Type base_type(base_name, 0);
797         if (rec.metadata->IsForeign()) {
798             record->SetSuperClass(items->GetOrCreateForeignClassItem(base_type.GetDescriptor(rec.conflict)));
799         } else {
800             record->SetSuperClass(items->GetOrCreateClassItem(base_type.GetDescriptor(rec.conflict)));
801         }
802     }
803     return true;
804 }
805 
806 /* static */
HandleInterfaces(ItemContainer * items,const Program & program,const std::string & name,const Record & rec,ClassItem * record)807 bool AsmEmitter::HandleInterfaces(ItemContainer *items, const Program &program, const std::string &name,
808                                   const Record &rec, ClassItem *record)
809 {
810     auto ifaces = rec.metadata->GetInterfaces();
811     for (const auto &item : ifaces) {
812         auto it = program.record_table.find(item);
813         if (it == program.record_table.cend()) {
814             SetLastError("Interface record " + item + " is not defined for record " + name);
815             return false;
816         }
817         auto &iface = it->second;
818         Type iface_type(item, 0);
819         if (iface.metadata->IsForeign()) {
820             record->AddInterface(items->GetOrCreateForeignClassItem(iface_type.GetDescriptor(iface.conflict)));
821         } else {
822             record->AddInterface(items->GetOrCreateClassItem(iface_type.GetDescriptor(iface.conflict)));
823         }
824     }
825     return true;
826 }
827 
828 /* static */
HandleFields(ItemContainer * items,const Program & program,AsmEmitter::AsmEntityCollections & entities,const std::unordered_map<panda_file::Type::TypeId,PrimitiveTypeItem * > & primitive_types,const std::string & name,const Record & rec,ClassItem * record)829 bool AsmEmitter::HandleFields(ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities,
830                               const std::unordered_map<panda_file::Type::TypeId, PrimitiveTypeItem *> &primitive_types,
831                               const std::string &name, const Record &rec, ClassItem *record)
832 {
833     for (const auto &f : rec.field_list) {
834         std::string full_field_name = name + "." + f.name;
835         if (entities.field_items.find(full_field_name) != entities.field_items.end()) {
836             continue;
837         }
838         auto *field_name = items->GetOrCreateStringItem(pandasm::DeMangleName(f.name));
839         auto *type_item = GetTypeItem(items, primitive_types, f.type, program);
840         if (type_item == nullptr) {
841             SetLastError("Field " + full_field_name + " has undefined type");
842             return false;
843         }
844         BaseFieldItem *field;
845         if (f.metadata->IsForeign()) {
846             field = items->CreateItem<ForeignFieldItem>(record, field_name, type_item);
847         } else {
848             field = record->AddField(field_name, type_item, f.metadata->GetAccessFlags());
849         }
850         entities.field_items.insert({full_field_name, field});
851     }
852     return true;
853 }
854 
855 /* static */
HandleRecord(ItemContainer * items,const Program & program,AsmEmitter::AsmEntityCollections & entities,const std::unordered_map<panda_file::Type::TypeId,PrimitiveTypeItem * > & primitive_types,const std::string & name,const Record & rec)856 bool AsmEmitter::HandleRecord(ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities,
857                               const std::unordered_map<panda_file::Type::TypeId, PrimitiveTypeItem *> &primitive_types,
858                               const std::string &name, const Record &rec)
859 {
860     Type record_type = Type::FromName(name);
861     auto *record = items->GetOrCreateClassItem(record_type.GetDescriptor(rec.conflict));
862     entities.class_items.insert({name, record});
863 
864     record->SetAccessFlags(rec.metadata->GetAccessFlags());
865     record->SetSourceLang(rec.language);
866 
867     if (!rec.source_file.empty()) {
868         auto *source_file_item = items->GetOrCreateStringItem(rec.source_file);
869         record->SetSourceFile(source_file_item);
870     }
871 
872     if (!HandleBaseRecord(items, program, name, rec, record)) {
873         return false;
874     }
875 
876     if (!HandleInterfaces(items, program, name, rec, record)) {
877         return false;
878     }
879 
880     if (!HandleFields(items, program, entities, primitive_types, name, rec, record)) {
881         return false;
882     }
883 
884     return true;
885 }
886 
887 /* static */
MakeRecordItems(ItemContainer * items,const Program & program,AsmEmitter::AsmEntityCollections & entities,const std::unordered_map<panda_file::Type::TypeId,PrimitiveTypeItem * > & primitive_types)888 bool AsmEmitter::MakeRecordItems(
889     ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities,
890     const std::unordered_map<panda_file::Type::TypeId, PrimitiveTypeItem *> &primitive_types)
891 {
892     for (const auto &[name, rec] : program.record_table) {
893         if (rec.metadata->IsForeign()) {
894             if (!HandleRecordAsForeign(items, program, entities, primitive_types, name, rec)) {
895                 return false;
896             }
897         } else {
898             if (!HandleRecord(items, program, entities, primitive_types, name, rec)) {
899                 return false;
900             }
901         }
902     }
903     return true;
904 }
905 
906 /* static */
GetMethodName(ItemContainer * items,const Function & func,const std::string & name)907 StringItem *AsmEmitter::GetMethodName(ItemContainer *items, const Function &func, const std::string &name)
908 {
909     if (func.metadata->IsCtor()) {
910         return items->GetOrCreateStringItem(panda::panda_file::GetCtorName(func.language));
911     } else if (func.metadata->IsCctor()) {
912         return items->GetOrCreateStringItem(panda::panda_file::GetCctorName(func.language));
913     } else {
914         return items->GetOrCreateStringItem(GetItemName(name));
915     }
916 }
917 
918 /* static */
HandleAreaForInner(ItemContainer * items,const Program & program,ClassItem ** area,ForeignClassItem ** foreign_area,const std::string & name,const std::string & record_owner_name)919 bool AsmEmitter::HandleAreaForInner(ItemContainer *items, const Program &program, ClassItem **area,
920                                     ForeignClassItem **foreign_area, const std::string &name,
921                                     const std::string &record_owner_name)
922 {
923     auto iter = program.record_table.find(record_owner_name);
924     if (iter != program.record_table.end()) {
925         auto &rec = iter->second;
926         Type record_owner_type = Type::FromName(record_owner_name);
927         auto descriptor = record_owner_type.GetDescriptor(rec.conflict);
928         if (rec.metadata->IsForeign()) {
929             *foreign_area = items->GetOrCreateForeignClassItem(descriptor);
930             if (*foreign_area == nullptr) {
931                 SetLastError("Unable to create external record " + iter->first);
932                 return false;
933             }
934         } else {
935             *area = items->GetOrCreateClassItem(descriptor);
936             (*area)->SetAccessFlags(rec.metadata->GetAccessFlags());
937         }
938     } else {
939         SetLastError("Function " + name + " is bound to undefined record " + record_owner_name);
940         return false;
941     }
942     return true;
943 }
944 
945 /* static */
HandleRecordOnwer(ItemContainer * items,const Program & program,ClassItem ** area,ForeignClassItem ** foreign_area,const std::string & name,const std::string & record_owner_name)946 bool AsmEmitter::HandleRecordOnwer(ItemContainer *items, const Program &program, ClassItem **area,
947                                    ForeignClassItem **foreign_area, const std::string &name,
948                                    const std::string &record_owner_name)
949 {
950     if (record_owner_name.empty()) {
951         *area = items->GetOrCreateGlobalClassItem();
952         (*area)->SetAccessFlags(ACC_PUBLIC);
953         (*area)->SetSourceLang(program.lang);
954     } else {
955         if (!HandleAreaForInner(items, program, area, foreign_area, name, record_owner_name)) {
956             return false;
957         }
958     }
959     return true;
960 }
961 
962 /* static */
HandleFunctionParams(ItemContainer * items,const Program & program,size_t idx,const std::string & name,const Function & func,const std::unordered_map<panda_file::Type::TypeId,PrimitiveTypeItem * > & primitive_types,std::vector<MethodParamItem> & params)963 bool AsmEmitter::HandleFunctionParams(
964     ItemContainer *items, const Program &program, size_t idx, const std::string &name, const Function &func,
965     const std::unordered_map<panda_file::Type::TypeId, PrimitiveTypeItem *> &primitive_types,
966     std::vector<MethodParamItem> &params)
967 {
968     for (size_t i = idx; i < func.params.size(); i++) {
969         const auto &p = func.params[i].type;
970         auto *type_item = GetTypeItem(items, primitive_types, p, program);
971         if (type_item == nullptr) {
972             SetLastError("Argument " + std::to_string(i) + " of function " + name + " has undefined type");
973             return false;
974         }
975         params.emplace_back(type_item);
976     }
977     return true;
978 }
979 
980 /* static */
HandleFunctionLocalVariables(ItemContainer * items,const Function & func,const std::string & name)981 bool AsmEmitter::HandleFunctionLocalVariables(ItemContainer *items, const Function &func, const std::string &name)
982 {
983     for (const auto &v : func.local_variable_debug) {
984         if (v.name.empty()) {
985             SetLastError("Function '" + name + "' has an empty local variable name");
986             return false;
987         }
988         if (v.signature.empty()) {
989             SetLastError("Function '" + name + "' has an empty local variable signature");
990             return false;
991         }
992         items->GetOrCreateStringItem(v.name);
993         // Skip signature and signature type for parameters
994         ASSERT(v.reg >= 0);
995         if (func.IsParameter(v.reg)) {
996             continue;
997         }
998         items->GetOrCreateStringItem(v.signature);
999         if (!v.signature_type.empty()) {
1000             items->GetOrCreateStringItem(v.signature_type);
1001         }
1002     }
1003     return true;
1004 }
1005 
1006 /* static */
CreateMethodItem(ItemContainer * items,AsmEmitter::AsmEntityCollections & entities,const Function & func,TypeItem * type_item,ClassItem * area,ForeignClassItem * foreign_area,uint32_t access_flags,StringItem * method_name,const std::string & mangled_name,const std::string & name,std::vector<MethodParamItem> & params)1007 bool AsmEmitter::CreateMethodItem(ItemContainer *items, AsmEmitter::AsmEntityCollections &entities,
1008                                   const Function &func, TypeItem *type_item, ClassItem *area,
1009                                   ForeignClassItem *foreign_area, uint32_t access_flags, StringItem *method_name,
1010                                   const std::string &mangled_name, const std::string &name,
1011                                   std::vector<MethodParamItem> &params)
1012 {
1013     auto *proto = items->GetOrCreateProtoItem(type_item, params);
1014     BaseMethodItem *method;
1015     if (foreign_area == nullptr) {
1016         if (func.metadata->IsForeign()) {
1017             method = items->CreateItem<ForeignMethodItem>(area, method_name, proto, access_flags);
1018         } else {
1019             method = area->AddMethod(method_name, proto, access_flags, params);
1020             method->SetFunctionKind(func.GetFunctionKind());
1021         }
1022     } else {
1023         if (!func.metadata->IsForeign()) {
1024             SetLastError("Non-external function " + name + " is bound to external record");
1025             return false;
1026         }
1027         method = items->CreateItem<ForeignMethodItem>(foreign_area, method_name, proto, access_flags);
1028     }
1029     entities.method_items.insert({mangled_name, method});
1030     if (!func.metadata->IsForeign()) {
1031         if (!func.source_file.empty()) {
1032             items->GetOrCreateStringItem(func.source_file);
1033         }
1034         if (!func.source_code.empty()) {
1035             items->GetOrCreateStringItem(func.source_code);
1036         }
1037     }
1038     return true;
1039 }
1040 
1041 /* static */
MakeFunctionItems(ItemContainer * items,const Program & program,AsmEmitter::AsmEntityCollections & entities,const std::unordered_map<panda_file::Type::TypeId,PrimitiveTypeItem * > & primitive_types,bool emit_debug_info)1042 bool AsmEmitter::MakeFunctionItems(
1043     ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities,
1044     const std::unordered_map<panda_file::Type::TypeId, PrimitiveTypeItem *> &primitive_types, bool emit_debug_info)
1045 {
1046     for (const auto &f : program.function_table) {
1047         const auto &[mangled_name, func] = f;
1048 
1049         auto name = pandasm::DeMangleName(mangled_name);
1050 
1051         StringItem *method_name = GetMethodName(items, func, name);
1052 
1053         ClassItem *area = nullptr;
1054         ForeignClassItem *foreign_area = nullptr;
1055 
1056         std::string record_owner_name = GetOwnerName(name);
1057         if (!HandleRecordOnwer(items, program, &area, &foreign_area, name, record_owner_name)) {
1058             return false;
1059         }
1060 
1061         auto params = std::vector<MethodParamItem> {};
1062 
1063         uint32_t access_flags = func.metadata->GetAccessFlags();
1064 
1065         if (func.params.empty() || func.params[0].type.GetName() != record_owner_name) {
1066             access_flags |= ACC_STATIC;
1067         }
1068 
1069         bool is_static = (access_flags & ACC_STATIC) != 0;
1070         size_t idx = is_static ? 0 : 1;
1071 
1072         if (!HandleFunctionParams(items, program, idx, name, func, primitive_types, params)) {
1073             return false;
1074         }
1075 
1076         if (emit_debug_info && !HandleFunctionLocalVariables(items, func, name)) {
1077             return false;
1078         }
1079 
1080         auto *type_item = GetTypeItem(items, primitive_types, func.return_type, program);
1081         if (type_item == nullptr) {
1082             SetLastError("Function " + name + " has undefined return type");
1083             return false;
1084         }
1085 
1086         if (!CreateMethodItem(items, entities, func, type_item, area, foreign_area, access_flags, method_name,
1087                               mangled_name, name, params)) {
1088             return false;
1089         }
1090     }
1091     return true;
1092 }
1093 
CheckDuplicateField(ValueItem & value_item,FieldItem & field_item,std::string & field_name)1094 bool AsmEmitter::CheckDuplicateField(ValueItem &value_item, FieldItem &field_item, std::string &field_name)
1095 {
1096     if (!field_item.GetValue()) {
1097         return true;
1098     }
1099 
1100     if (field_item.GetValue()->IsArray() || value_item.IsArray()) {
1101         SetLastError("Duplicated array type field {" + field_name + "} is not supported.");
1102         return false;
1103     }
1104 
1105     if (field_item.GetValue()->GetAsScalar() == value_item.GetAsScalar()) {
1106         return true;
1107     }
1108     SetLastError("Field {" + field_name + "} has different value.");
1109     return false;
1110 }
1111 
FillFields(ItemContainer * items,const Program & program,const panda::pandasm::Record & record,const AsmEmitter::AsmEntityCollections & entities)1112 bool AsmEmitter::FillFields(ItemContainer *items, const Program &program, const panda::pandasm::Record &record,
1113                             const AsmEmitter::AsmEntityCollections &entities)
1114 {
1115     for (const auto &field : record.field_list) {
1116         auto field_name = record.name + "." + field.name;
1117         auto *field_item = static_cast<FieldItem *>(Find(entities.field_items, field_name));
1118         if (!AddAnnotations(field_item, items, *field.metadata, program, entities)) {
1119             SetLastError("Cannot emit annotations for field " + field_name + ": " + GetLastError());
1120             return false;
1121         }
1122 
1123         auto res = field.metadata->GetValue();
1124         if (res) {
1125             auto value = res.value();
1126             auto *item = CreateValueItem(items, &value, program, entities);
1127             if (!CheckDuplicateField(*item, *field_item, field_name)) {
1128                 return false;
1129             }
1130             field_item->SetValue(item);
1131         }
1132     }
1133     return true;
1134 }
1135 
1136 /* static */
MakeRecordAnnotations(ItemContainer * items,const Program & program,const AsmEmitter::AsmEntityCollections & entities)1137 bool AsmEmitter::MakeRecordAnnotations(ItemContainer *items, const Program &program,
1138                                        const AsmEmitter::AsmEntityCollections &entities)
1139 {
1140     for (const auto &[name, record] : program.record_table) {
1141         if (record.metadata->IsForeign()) {
1142             continue;
1143         }
1144 
1145         auto *class_item = static_cast<ClassItem *>(Find(entities.class_items, name));
1146         if (!AddAnnotations(class_item, items, *record.metadata, program, entities)) {
1147             SetLastError("Cannot emit annotations for record " + record.name + ": " + GetLastError());
1148             return false;
1149         }
1150 
1151         if (!FillFields(items, program, record, entities)) {
1152             return false;
1153         }
1154     }
1155     return true;
1156 }
1157 
1158 /* static */
SetCodeAndDebugInfo(ItemContainer * items,MethodItem * method,const Function & func,bool emit_debug_info)1159 void AsmEmitter::SetCodeAndDebugInfo(ItemContainer *items, MethodItem *method, const Function &func,
1160                                      bool emit_debug_info)
1161 {
1162     auto *code = items->CreateItem<CodeItem>();
1163     method->SetCode(code);
1164     code->AddMethod(method);  // we need it for Profile-Guided optimization
1165 
1166     if (!emit_debug_info && !func.CanThrow()) {
1167         return;
1168     }
1169 
1170     auto *line_number_program = items->CreateLineNumberProgramItem();
1171     auto *debug_info = items->CreateItem<DebugInfoItem>(line_number_program);
1172     if (emit_debug_info) {
1173         for (const auto &v : func.local_variable_debug) {
1174             ASSERT(v.reg >= 0);
1175             if (func.IsParameter(v.reg)) {
1176                 debug_info->AddParameter(items->GetOrCreateStringItem(v.name));
1177             }
1178         }
1179     } else {
1180         auto nparams = method->GetParams().size();
1181         for (size_t i = 0; i < nparams; i++) {
1182             debug_info->AddParameter(nullptr);
1183         }
1184     }
1185     method->SetDebugInfo(debug_info);
1186 }
1187 
1188 /* static */
AddMethodAndParamsAnnotations(ItemContainer * items,const Program & program,const AsmEmitter::AsmEntityCollections & entities,MethodItem * method,const Function & func)1189 bool AsmEmitter::AddMethodAndParamsAnnotations(ItemContainer *items, const Program &program,
1190                                                const AsmEmitter::AsmEntityCollections &entities, MethodItem *method,
1191                                                const Function &func)
1192 {
1193     if (!AddAnnotations(method, items, *func.metadata, program, entities)) {
1194         SetLastError("Cannot emit annotations for function " + func.name + ": " + GetLastError());
1195         return false;
1196     }
1197 
1198     auto &param_items = method->GetParams();
1199     for (size_t proto_idx = 0; proto_idx < param_items.size(); proto_idx++) {
1200         size_t param_idx = method->IsStatic() ? proto_idx : proto_idx + 1;
1201         auto &param_item = param_items[proto_idx];
1202         // The parameter metadata of ArkTS is always of a default value instead of a dynamically
1203         // generated one from ArkTS sources, so it is created here to reduce the compilation memory.
1204         auto metadata = extensions::MetadataExtension::CreateParamMetadata(pandasm::extensions::Language::ECMASCRIPT);
1205         if (!AddAnnotations(&param_item, items, *metadata, program, entities)) {
1206             SetLastError("Cannot emit annotations for parameter a" + std::to_string(param_idx) + "of function " +
1207                          func.name + ": " + GetLastError());
1208             return false;
1209         }
1210     }
1211 
1212     if (method->HasRuntimeParamAnnotations()) {
1213         items->CreateItem<ParamAnnotationsItem>(method, true);
1214     }
1215 
1216     if (method->HasParamAnnotations()) {
1217         items->CreateItem<ParamAnnotationsItem>(method, false);
1218     }
1219 
1220     return true;
1221 }
1222 
1223 /* static */
MakeFunctionDebugInfoAndAnnotations(ItemContainer * items,const Program & program,const AsmEmitter::AsmEntityCollections & entities,bool emit_debug_info)1224 bool AsmEmitter::MakeFunctionDebugInfoAndAnnotations(ItemContainer *items, const Program &program,
1225                                                      const AsmEmitter::AsmEntityCollections &entities,
1226                                                      bool emit_debug_info)
1227 {
1228     for (const auto &[name, func] : program.function_table) {
1229         if (func.metadata->IsForeign()) {
1230             continue;
1231         }
1232 
1233         auto *method = static_cast<MethodItem *>(Find(entities.method_items, name));
1234 
1235         SetCodeAndDebugInfo(items, method, func, emit_debug_info);
1236         if (!AddBytecodeIndexDependencies(method, func, entities)) {
1237             return false;
1238         }
1239 
1240         method->SetSourceLang(func.language);
1241 
1242         if (!AddMethodAndParamsAnnotations(items, program, entities, method, func)) {
1243             return false;
1244         }
1245     }
1246     return true;
1247 }
1248 
1249 /* static */
FillMap(PandaFileToPandaAsmMaps * maps,AsmEmitter::AsmEntityCollections & entities)1250 void AsmEmitter::FillMap(PandaFileToPandaAsmMaps *maps, AsmEmitter::AsmEntityCollections &entities)
1251 {
1252     for (const auto &[name, method] : entities.method_items) {
1253         maps->methods.insert({method->GetFileId().GetOffset(), std::string(name)});
1254     }
1255 
1256     for (const auto &[name, field] : entities.field_items) {
1257         maps->fields.insert({field->GetFileId().GetOffset(), std::string(name)});
1258     }
1259 
1260     for (const auto &[name, cls] : entities.class_items) {
1261         maps->classes.insert({cls->GetFileId().GetOffset(), std::string(name)});
1262     }
1263 
1264     for (const auto &[name, str] : entities.string_items) {
1265         maps->strings.insert({str->GetFileId().GetOffset(), std::string(name)});
1266     }
1267 
1268     for (const auto &[name, arr] : entities.literalarray_items) {
1269         maps->literalarrays.emplace(arr->GetFileId().GetOffset(), name);
1270     }
1271 }
1272 
1273 /* static */
EmitDebugInfo(ItemContainer * items,const Program & program,const std::vector<uint8_t> * bytes,const MethodItem * method,const Function & func,const std::string & name,bool emit_debug_info)1274 void AsmEmitter::EmitDebugInfo(ItemContainer *items, const Program &program, const std::vector<uint8_t> *bytes,
1275                                const MethodItem *method, const Function &func, const std::string &name,
1276                                bool emit_debug_info)
1277 {
1278     auto *debug_info = method->GetDebugInfo();
1279     if (debug_info == nullptr) {
1280         return;
1281     }
1282 
1283     auto *line_number_program = debug_info->GetLineNumberProgram();
1284     auto *constant_pool = debug_info->GetConstantPool();
1285 
1286     std::string record_name = GetOwnerName(name);
1287     std::string record_source_file;
1288     if (!record_name.empty()) {
1289         auto &rec = program.record_table.find(record_name)->second;
1290         record_source_file = rec.source_file;
1291     }
1292 
1293     if (!func.source_file.empty() && func.source_file != record_source_file) {
1294         if (!func.source_code.empty()) {
1295             auto *source_code_item = items->GetOrCreateStringItem(func.source_code);
1296             ASSERT(source_code_item->GetOffset() != 0);
1297             line_number_program->EmitSetSourceCode(constant_pool, source_code_item);
1298         }
1299         auto *source_file_item = items->GetOrCreateStringItem(func.source_file);
1300         ASSERT(source_file_item->GetOffset() != 0);
1301         line_number_program->EmitSetFile(constant_pool, source_file_item);
1302     }
1303     func.BuildLineNumberProgram(debug_info, *bytes, items, constant_pool, emit_debug_info);
1304 }
1305 
1306 /* static */
EmitFunctions(ItemContainer * items,const Program & program,const AsmEmitter::AsmEntityCollections & entities,bool emit_debug_info)1307 bool AsmEmitter::EmitFunctions(ItemContainer *items, const Program &program,
1308                                const AsmEmitter::AsmEntityCollections &entities, bool emit_debug_info)
1309 {
1310     for (const auto &f : program.function_table) {
1311         const auto &[name, func] = f;
1312 
1313         if (func.metadata->IsForeign()) {
1314             continue;
1315         }
1316 
1317         auto emitter = BytecodeEmitter {};
1318         auto *method = static_cast<MethodItem *>(Find(entities.method_items, name));
1319         if (!func.Emit(emitter, method, entities.method_items, entities.field_items, entities.class_items,
1320                        entities.string_items, entities.literalarray_items)) {
1321             SetLastError("Internal error during emitting function: " + func.name);
1322             return false;
1323         }
1324 
1325         auto *code = method->GetCode();
1326         code->SetNumVregs(func.regs_num);
1327         code->SetNumArgs(func.GetParamsNum());
1328 
1329         auto num_ins = static_cast<size_t>(
1330             std::count_if(func.ins.begin(), func.ins.end(), [](auto &it) { return it->opcode != Opcode::INVALID; }));
1331         code->SetNumInstructions(num_ins);
1332 
1333         auto *bytes = code->GetInstructions();
1334         auto status = emitter.Build(static_cast<std::vector<unsigned char> *>(bytes));
1335         if (status != BytecodeEmitter::ErrorCode::SUCCESS) {
1336             SetLastError("Internal error during emitting binary code, status=" +
1337                          std::to_string(static_cast<int>(status)));
1338             return false;
1339         }
1340         auto try_blocks = func.BuildTryBlocks(method, entities.class_items, *bytes);
1341         for (auto &try_block : try_blocks) {
1342             code->AddTryBlock(try_block);
1343         }
1344 
1345         EmitDebugInfo(items, program, bytes, method, func, name, emit_debug_info);
1346     }
1347     return true;
1348 }
1349 
1350 /* static */
MakeItemsForSingleProgram(ItemContainer * items,const Program & program,bool emit_debug_info,AsmEmitter::AsmEntityCollections & entities,std::unordered_map<panda_file::Type::TypeId,PrimitiveTypeItem * > primitive_types)1351 bool AsmEmitter::MakeItemsForSingleProgram(ItemContainer *items, const Program &program, bool emit_debug_info,
1352     AsmEmitter::AsmEntityCollections &entities,
1353     std::unordered_map<panda_file::Type::TypeId, PrimitiveTypeItem *> primitive_types)
1354 {
1355     MakeStringItems(items, program, entities);
1356     MakeArrayTypeItems(items, program, entities);
1357     if (!MakeRecordItems(items, program, entities, primitive_types)) {
1358         return false;
1359     }
1360     if (!MakeFunctionItems(items, program, entities, primitive_types, emit_debug_info)) {
1361         return false;
1362     }
1363     MakeLiteralItems(items, program, entities);
1364     // Add annotations for records and fields
1365     if (!MakeRecordAnnotations(items, program, entities)) {
1366         return false;
1367     }
1368     return true;
1369 }
1370 
EmitPrograms(const std::string & filename,const std::vector<Program * > & progs,bool emit_debug_info,const EmitterConfig & emitterConfig)1371 bool AsmEmitter::EmitPrograms(const std::string &filename, const std::vector<Program *> &progs, bool emit_debug_info,
1372                               const EmitterConfig &emitterConfig)
1373 {
1374     ASSERT(!progs.empty());
1375 
1376     ItemContainer::SetApi(emitterConfig.api);
1377     ItemContainer::SetSubApi(emitterConfig.subApi);
1378     auto items = ItemContainer {};
1379     auto primitive_types = CreatePrimitiveTypes(&items);
1380     auto entities = AsmEmitter::AsmEntityCollections {};
1381     SetLastError("");
1382 
1383     for (auto *prog : progs) {
1384         if (!MakeItemsForSingleProgram(&items, *prog, emit_debug_info, entities, primitive_types)) {
1385             return false;
1386         }
1387         prog->strings.clear();
1388         prog->literalarray_table.clear();
1389         prog->array_types.clear();
1390     }
1391 
1392     for (auto *prog : progs) {
1393         if (!MakeFunctionDebugInfoAndAnnotations(&items, *prog, entities, emit_debug_info)) {
1394             return false;
1395         }
1396         prog->function_synonyms.clear();
1397     }
1398 
1399     items.ReLayout();
1400     items.ComputeLayout();
1401     {
1402         auto queue_emit = new EmitFunctionsQueue(emitterConfig.fileThreadCount, items, progs, entities,
1403                                                  emit_debug_info);
1404         queue_emit->Schedule();
1405         queue_emit->Consume();
1406         queue_emit->Wait();
1407         delete queue_emit;
1408         queue_emit = nullptr;
1409     }
1410 
1411     auto writer = FileWriter(filename);
1412     if (!writer) {
1413         SetLastError("Unable to open" + filename + " for writing");
1414         return false;
1415     }
1416 
1417     return items.Write(&writer, !emitterConfig.isDebug);
1418 }
1419 
1420 /* static */
Emit(ItemContainer * items,const Program & program,PandaFileToPandaAsmMaps * maps,bool emit_debug_info,panda::panda_file::pgo::ProfileOptimizer * profile_opt)1421 bool AsmEmitter::Emit(ItemContainer *items, const Program &program, PandaFileToPandaAsmMaps *maps, bool emit_debug_info,
1422                       panda::panda_file::pgo::ProfileOptimizer *profile_opt)
1423 {
1424     auto primitive_types = CreatePrimitiveTypes(items);
1425 
1426     auto entities = AsmEmitter::AsmEntityCollections {};
1427 
1428     SetLastError("");
1429 
1430     if (!MakeItemsForSingleProgram(items, program, emit_debug_info, entities, primitive_types)) {
1431         return false;
1432     }
1433 
1434     // Add Code and DebugInfo items last due to they have variable size that depends on bytecode
1435     if (!MakeFunctionDebugInfoAndAnnotations(items, program, entities, emit_debug_info)) {
1436         return false;
1437     }
1438 
1439     if (profile_opt != nullptr) {
1440         items->ReorderItems(profile_opt);
1441     }
1442 
1443     items->ComputeLayout();
1444 
1445     if (maps != nullptr) {
1446         FillMap(maps, entities);
1447     }
1448 
1449     if (!EmitFunctions(items, program, entities, emit_debug_info)) {
1450         return false;
1451     }
1452 
1453     return true;
1454 }
1455 
Emit(Writer * writer,const Program & program,std::map<std::string,size_t> * stat,PandaFileToPandaAsmMaps * maps,bool debug_info,panda::panda_file::pgo::ProfileOptimizer * profile_opt,uint8_t api,std::string subApi)1456 bool AsmEmitter::Emit(Writer *writer, const Program &program, std::map<std::string, size_t> *stat,
1457                       PandaFileToPandaAsmMaps *maps, bool debug_info,
1458                       panda::panda_file::pgo::ProfileOptimizer *profile_opt, uint8_t api, std::string subApi)
1459 {
1460     ItemContainer::SetApi(api);
1461     ItemContainer::SetSubApi(subApi);
1462     auto items = ItemContainer {};
1463     if (!Emit(&items, program, maps, debug_info, profile_opt)) {
1464         return false;
1465     }
1466 
1467     if (stat != nullptr) {
1468         *stat = items.GetStat();
1469     }
1470 
1471     return items.Write(writer);
1472 }
1473 
Emit(const std::string & filename,const Program & program,std::map<std::string,size_t> * stat,PandaFileToPandaAsmMaps * maps,bool debug_info,panda::panda_file::pgo::ProfileOptimizer * profile_opt,uint8_t api,std::string subApi)1474 bool AsmEmitter::Emit(const std::string &filename, const Program &program, std::map<std::string, size_t> *stat,
1475                       PandaFileToPandaAsmMaps *maps, bool debug_info,
1476                       panda::panda_file::pgo::ProfileOptimizer *profile_opt, uint8_t api, std::string subApi)
1477 {
1478     auto writer = FileWriter(filename);
1479     if (!writer) {
1480         SetLastError("Unable to open" + filename + " for writing");
1481         return false;
1482     }
1483     return Emit(&writer, program, stat, maps, debug_info, profile_opt, api, subApi);
1484 }
1485 
Emit(const Program & program,PandaFileToPandaAsmMaps * maps,uint8_t api,std::string subApi)1486 std::unique_ptr<const panda_file::File> AsmEmitter::Emit(const Program &program, PandaFileToPandaAsmMaps *maps,
1487                                                          uint8_t api, std::string subApi)
1488 {
1489     ItemContainer::SetApi(api);
1490     ItemContainer::SetSubApi(subApi);
1491     auto items = ItemContainer {};
1492     if (!Emit(&items, program, maps)) {
1493         return nullptr;
1494     }
1495 
1496     size_t size = items.ComputeLayout();
1497     auto *buffer = new std::byte[size];
1498 
1499     auto writer = MemoryBufferWriter(reinterpret_cast<uint8_t *>(buffer), size);
1500     if (!items.Write(&writer)) {
1501         return nullptr;
1502     }
1503 
1504     os::mem::ConstBytePtr ptr(
1505         buffer, size, [](std::byte *buffer_ptr, [[maybe_unused]] size_t param_size) noexcept { delete[] buffer_ptr; });
1506     return panda_file::File::OpenFromMemory(std::move(ptr));
1507 }
1508 
GetTypeItem(ItemContainer * items,const std::unordered_map<panda_file::Type::TypeId,PrimitiveTypeItem * > & primitive_types,const Type & type,const Program & program)1509 TypeItem *AsmEmitter::GetTypeItem(
1510     ItemContainer *items, const std::unordered_map<panda_file::Type::TypeId, PrimitiveTypeItem *> &primitive_types,
1511     const Type &type, const Program &program)
1512 {
1513     if (!type.IsObject()) {
1514         return Find(primitive_types, type.GetId());
1515     }
1516 
1517     if (type.IsArray()) {
1518         return items->GetOrCreateForeignClassItem(type.GetDescriptor());
1519     }
1520 
1521     const auto &name = type.GetName();
1522     if (name == STRING_CLASS_NAME) {
1523         return items->GetOrCreateForeignClassItem(type.GetDescriptor());
1524     }
1525 
1526     auto iter = program.record_table.find(name);
1527     if (iter == program.record_table.end()) {
1528         return nullptr;
1529     }
1530 
1531     auto &rec = iter->second;
1532 
1533     if (rec.metadata->IsForeign()) {
1534         return items->GetOrCreateForeignClassItem(type.GetDescriptor());
1535     }
1536 
1537     return items->GetOrCreateClassItem(type.GetDescriptor());
1538 }
1539 
Emit(BytecodeEmitter & emitter,panda_file::MethodItem * method,const std::unordered_map<std::string,panda_file::BaseMethodItem * > & methods,const std::unordered_map<std::string,panda_file::BaseFieldItem * > & fields,const std::unordered_map<std::string,panda_file::BaseClassItem * > & classes,const std::unordered_map<std::string,panda_file::StringItem * > & strings,const std::unordered_map<std::string,panda_file::LiteralArrayItem * > & literalarrays) const1540 bool Function::Emit(BytecodeEmitter &emitter, panda_file::MethodItem *method,
1541                     const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
1542                     const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
1543                     const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
1544                     const std::unordered_map<std::string, panda_file::StringItem *> &strings,
1545                     const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays) const
1546 {
1547     auto labels = std::unordered_map<std::string_view, panda::Label> {};
1548 
1549     for (const auto &insn : ins) {
1550         if (insn->IsLabel()) {
1551             labels.insert_or_assign(insn->Label(), emitter.CreateLabel());
1552         }
1553     }
1554 
1555     for (const auto &insn : ins) {
1556         if (insn->IsLabel()) {
1557             auto search = labels.find(insn->Label());
1558             ASSERT(search != labels.end());
1559             emitter.Bind(search->second);
1560         }
1561 
1562         if (insn->opcode != Opcode::INVALID) {
1563             if (!Ins::Emit(emitter, insn, method, methods, fields, classes, strings, literalarrays, labels)) {
1564                 return false;
1565             }
1566         }
1567     }
1568 
1569     return true;
1570 }
1571 
TryEmitPc(panda_file::LineNumberProgramItem * program,std::vector<uint8_t> * constant_pool,uint32_t & pc_inc)1572 static void TryEmitPc(panda_file::LineNumberProgramItem *program, std::vector<uint8_t> *constant_pool,
1573                       uint32_t &pc_inc)
1574 {
1575     if (pc_inc) {
1576         program->EmitAdvancePc(constant_pool, pc_inc);
1577         pc_inc = 0;
1578     }
1579 }
1580 
EmitLocalVariable(panda_file::LineNumberProgramItem * program,const ItemContainer * container,std::vector<uint8_t> * constant_pool,const LocalVarEmitContext & context) const1581 void Function::EmitLocalVariable(panda_file::LineNumberProgramItem *program, const ItemContainer *container,
1582                                  std::vector<uint8_t> *constant_pool, const LocalVarEmitContext &context) const
1583 {
1584     ASSERT(context.variable_index < local_variable_debug.size());
1585     const auto &v = local_variable_debug[context.variable_index];
1586     ASSERT(!IsParameter(v.reg));
1587     if (context.instruction_number == v.start) {
1588         TryEmitPc(program, constant_pool, context.pc_inc);
1589         StringItem *variable_name = container->GetStringItem(v.name);
1590         ASSERT(variable_name->GetOffset() != 0);
1591         StringItem *variable_type = container->GetStringItem(v.signature);
1592         ASSERT(variable_type->GetOffset() != 0);
1593         if (v.signature_type.empty()) {
1594             program->EmitStartLocal(constant_pool, v.reg, variable_name, variable_type);
1595         } else {
1596             StringItem *type_signature = container->GetStringItem(v.signature_type);
1597             ASSERT(type_signature->GetOffset() != 0);
1598             program->EmitStartLocalExtended(constant_pool, v.reg, variable_name, variable_type, type_signature);
1599         }
1600     }
1601 
1602     if (context.instruction_number == (v.start + v.length)) {
1603         TryEmitPc(program, constant_pool, context.pc_inc);
1604         program->EmitEndLocal(v.reg);
1605     }
1606 }
1607 
GetLineNumber(size_t i) const1608 size_t Function::GetLineNumber(size_t i) const
1609 {
1610     return ins[i]->ins_debug.line_number;
1611 }
1612 
GetColumnNumber(size_t i) const1613 uint32_t Function::GetColumnNumber(size_t i) const
1614 {
1615     return ins[i]->ins_debug.column_number;
1616 }
1617 
EmitNumber(panda_file::LineNumberProgramItem * program,std::vector<uint8_t> * constant_pool,uint32_t pc_inc,int32_t line_inc) const1618 void Function::EmitNumber(panda_file::LineNumberProgramItem *program, std::vector<uint8_t> *constant_pool,
1619                           uint32_t pc_inc, int32_t line_inc) const
1620 {
1621     if (!program->EmitSpecialOpcode(pc_inc, line_inc)) {
1622         if (pc_inc) {
1623             program->EmitAdvancePc(constant_pool, pc_inc);
1624             if (!program->EmitSpecialOpcode(0, line_inc)) {
1625                 program->EmitAdvanceLine(constant_pool, line_inc);
1626                 program->EmitSpecialOpcode(0, 0);
1627             }
1628         } else {
1629             program->EmitAdvanceLine(constant_pool, line_inc);
1630             program->EmitSpecialOpcode(0, 0);
1631         }
1632     }
1633 }
1634 
EmitLineNumber(panda_file::LineNumberProgramItem * program,std::vector<uint8_t> * constant_pool,int32_t & prev_line_number,uint32_t & pc_inc,size_t instruction_number) const1635 void Function::EmitLineNumber(panda_file::LineNumberProgramItem *program, std::vector<uint8_t> *constant_pool,
1636                               int32_t &prev_line_number, uint32_t &pc_inc, size_t instruction_number) const
1637 {
1638     int32_t line_inc = static_cast<int32_t>(GetLineNumber(instruction_number)) - prev_line_number;
1639     if (line_inc) {
1640         prev_line_number = static_cast<int32_t>(GetLineNumber(instruction_number));
1641         EmitNumber(program, constant_pool, pc_inc, line_inc);
1642         pc_inc = 0;
1643     }
1644 }
1645 
EmitColumnNumber(panda_file::LineNumberProgramItem * program,std::vector<uint8_t> * constant_pool,uint32_t & prev_column_number,uint32_t & pc_inc,size_t instruction_number) const1646 void Function::EmitColumnNumber(panda_file::LineNumberProgramItem *program, std::vector<uint8_t> *constant_pool,
1647                                 uint32_t &prev_column_number, uint32_t &pc_inc, size_t instruction_number) const
1648 {
1649     auto cn = GetColumnNumber(instruction_number);
1650     if (cn != prev_column_number) {
1651         program->EmitColumn(constant_pool, pc_inc, cn);
1652         pc_inc = 0;
1653         prev_column_number = cn;
1654     }
1655 }
1656 
CollectLocalVariable(std::vector<Function::LocalVariablePair> & local_variable_info) const1657 void Function::CollectLocalVariable(std::vector<Function::LocalVariablePair> &local_variable_info) const
1658 {
1659     for (size_t i = 0; i < local_variable_debug.size(); i++) {
1660         const auto &v = local_variable_debug[i];
1661         if (IsParameter(v.reg)) {
1662             continue;
1663         }
1664         local_variable_info.emplace_back(v.start, i);
1665         local_variable_info.emplace_back(v.start + v.length, i);
1666     }
1667 
1668     std::sort(local_variable_info.begin(), local_variable_info.end(),
1669         [this](const Function::LocalVariablePair &a, const Function::LocalVariablePair &b) {
1670         auto a_var = this->local_variable_debug[a.variable_index];
1671         auto b_var = this->local_variable_debug[b.variable_index];
1672         // If the same register is first used by a_var, and then used by b_var, the ending position of a_var needs
1673         // to be equal or less then the starting position of b_var. This is to keep the order in local_variable_debug
1674         // to make sure that if the usage of a_var start first, it will end first.
1675         if (a.insn_order == b.insn_order && a_var.reg == b_var.reg) {
1676             return a_var.start < b_var.start;
1677         }
1678         return a.insn_order < b.insn_order;
1679     });
1680 }
1681 
BuildLineNumberProgram(panda_file::DebugInfoItem * debug_item,const std::vector<uint8_t> & bytecode,const ItemContainer * container,std::vector<uint8_t> * constant_pool,bool emit_debug_info) const1682 void Function::BuildLineNumberProgram(panda_file::DebugInfoItem *debug_item, const std::vector<uint8_t> &bytecode,
1683                                       const ItemContainer *container, std::vector<uint8_t> *constant_pool,
1684                                       bool emit_debug_info) const
1685 {
1686     auto *program = debug_item->GetLineNumberProgram();
1687 
1688     if (ins.empty()) {
1689         program->EmitEnd();
1690         return;
1691     }
1692 
1693     uint32_t pc_inc = 0;
1694     auto prev_line_number = static_cast<int32_t>(GetLineNumber(0));
1695     uint32_t prev_column_number = std::numeric_limits<uint32_t>::max();
1696     BytecodeInstruction bi(bytecode.data());
1697     debug_item->SetLineNumber(static_cast<uint32_t>(prev_line_number));
1698 
1699     std::vector<Function::LocalVariablePair> local_variable_info;
1700     if (emit_debug_info) {
1701         CollectLocalVariable(local_variable_info);
1702     }
1703     const size_t num_ins = ins.size();
1704     size_t start = 0;
1705     auto iter = local_variable_info.begin();
1706     do {
1707         size_t end = emit_debug_info && iter != local_variable_info.end() ? iter->insn_order : num_ins;
1708         for (size_t i = start; i < end; i++) {
1709             /**
1710              * If you change the continue condition of this loop, you need to synchronously modify the same condition
1711              * of the BuildMapFromPcToIns method in the optimizer-bytecode.cpp.
1712              **/
1713             if (ins[i]->opcode == Opcode::INVALID) {
1714                 continue;
1715             }
1716             if (emit_debug_info || ins[i]->CanThrow()) {
1717                 EmitLineNumber(program, constant_pool, prev_line_number, pc_inc, i);
1718             }
1719             if (emit_debug_info) {
1720                 EmitColumnNumber(program, constant_pool, prev_column_number, pc_inc, i);
1721             }
1722             pc_inc += bi.GetSize();
1723             bi = bi.GetNext();
1724         }
1725         if (iter == local_variable_info.end()) {
1726             break;
1727         }
1728         if (emit_debug_info) {
1729             LocalVarEmitContext context{pc_inc, end, iter->variable_index};
1730             EmitLocalVariable(program, container, constant_pool, context);
1731         }
1732         start = end;
1733         iter++;
1734     } while (true);
1735 
1736     program->EmitEnd();
1737 }
1738 
MakeOrderAndOffsets(const std::vector<uint8_t> & bytecode) const1739 Function::TryCatchInfo Function::MakeOrderAndOffsets(const std::vector<uint8_t> &bytecode) const
1740 {
1741     std::unordered_map<std::string_view, size_t> try_catch_labels;
1742     std::unordered_map<std::string, std::vector<const CatchBlock *>> try_catch_map;
1743     std::vector<std::string> try_catch_order;
1744 
1745     for (auto &catch_block : catch_blocks) {
1746         try_catch_labels.insert_or_assign(catch_block.try_begin_label, 0);
1747         try_catch_labels.insert_or_assign(catch_block.try_end_label, 0);
1748         try_catch_labels.insert_or_assign(catch_block.catch_begin_label, 0);
1749         try_catch_labels.insert_or_assign(catch_block.catch_end_label, 0);
1750 
1751         std::string try_key = catch_block.try_begin_label + ":" + catch_block.try_end_label;
1752         auto it = try_catch_map.find(try_key);
1753         if (it == try_catch_map.cend()) {
1754             std::tie(it, std::ignore) = try_catch_map.try_emplace(try_key);
1755             try_catch_order.push_back(try_key);
1756         }
1757         it->second.push_back(&catch_block);
1758     }
1759 
1760     BytecodeInstruction bi(bytecode.data());
1761     size_t pc_offset = 0;
1762 
1763     for (size_t i = 0; i < ins.size(); i++) {
1764         if (ins[i]->IsLabel()) {
1765             auto it = try_catch_labels.find(ins[i]->Label());
1766             if (it != try_catch_labels.cend()) {
1767                 try_catch_labels[ins[i]->Label()] = pc_offset;
1768             }
1769         }
1770         if (ins[i]->opcode == Opcode::INVALID) {
1771             continue;
1772         }
1773 
1774         pc_offset += bi.GetSize();
1775         bi = bi.GetNext();
1776     }
1777 
1778     return Function::TryCatchInfo {try_catch_labels, try_catch_map, try_catch_order};
1779 }
1780 
BuildTryBlocks(MethodItem * method,const std::unordered_map<std::string,BaseClassItem * > & class_items,const std::vector<uint8_t> & bytecode) const1781 std::vector<CodeItem::TryBlock> Function::BuildTryBlocks(
1782     MethodItem *method, const std::unordered_map<std::string, BaseClassItem *> &class_items,
1783     const std::vector<uint8_t> &bytecode) const
1784 {
1785     std::vector<CodeItem::TryBlock> try_blocks;
1786 
1787     if (ins.empty()) {
1788         return try_blocks;
1789     }
1790 
1791     Function::TryCatchInfo tcs = MakeOrderAndOffsets(bytecode);
1792 
1793     for (const auto &t_key : tcs.try_catch_order) {
1794         auto kv = tcs.try_catch_map.find(t_key);
1795         ASSERT(kv != tcs.try_catch_map.cend());
1796         auto &try_catch_blocks = kv->second;
1797 
1798         ASSERT(!try_catch_blocks.empty());
1799 
1800         std::vector<CodeItem::CatchBlock> catch_block_items;
1801 
1802         for (auto *catch_block : try_catch_blocks) {
1803             auto class_name = catch_block->exception_record;
1804 
1805             BaseClassItem *class_item = nullptr;
1806             if (!class_name.empty()) {
1807                 auto it = class_items.find(class_name);
1808                 ASSERT(it != class_items.cend());
1809                 class_item = it->second;
1810             }
1811 
1812             auto handler_pc_offset = tcs.try_catch_labels[catch_block->catch_begin_label];
1813             auto handler_code_size = tcs.try_catch_labels[catch_block->catch_end_label] - handler_pc_offset;
1814             catch_block_items.emplace_back(method, class_item, handler_pc_offset, handler_code_size);
1815         }
1816 
1817         auto try_start_pc_offset = tcs.try_catch_labels[try_catch_blocks[0]->try_begin_label];
1818         auto try_end_pc_offset = tcs.try_catch_labels[try_catch_blocks[0]->try_end_label];
1819         ASSERT(try_end_pc_offset >= try_start_pc_offset);
1820         try_blocks.emplace_back(try_start_pc_offset, try_end_pc_offset - try_start_pc_offset, catch_block_items);
1821     }
1822 
1823     return try_blocks;
1824 }
1825 
DebugDump() const1826 void Function::DebugDump() const
1827 {
1828     std::cerr << "name: " << name << std::endl;
1829     for (const auto &i : ins) {
1830         std::cerr << i->ToString("\n", true, regs_num);
1831     }
1832 }
1833 
GetOwnerName(std::string name)1834 std::string GetOwnerName(std::string name)
1835 {
1836     name = DeMangleName(name);
1837     auto super_pos = name.find_last_of(PARSE_AREA_MARKER);
1838     if (super_pos == std::string::npos) {
1839         return "";
1840     }
1841 
1842     return name.substr(0, super_pos);
1843 }
1844 
GetItemName(std::string name)1845 std::string GetItemName(std::string name)
1846 {
1847     name = DeMangleName(name);
1848     auto super_pos = name.find_last_of(PARSE_AREA_MARKER);
1849     if (super_pos == std::string::npos) {
1850         return name;
1851     }
1852 
1853     return name.substr(super_pos + 1);
1854 }
1855 
1856 }  // namespace panda::pandasm
1857