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