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