• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "assembly-emitter.h"
17 
18 #include <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     if (!program.isGeneratedFromMergedAbc) {
418         auto it = program.record_table.find(record_name);
419         if (it == program.record_table.cend()) {
420             SetLastError("Record " + record_name + " not found");
421             return nullptr;
422         }
423 
424         auto &record = it->second;
425         if (!record.metadata->IsAnnotation()) {
426             SetLastError("Record " + record_name + " isn't annotation");
427             return nullptr;
428         }
429     }
430 
431     std::vector<AnnotationItem::Elem> item_elements;
432     std::vector<AnnotationItem::Tag> tag_elements;
433 
434     for (const auto &element : annotation.GetElements()) {
435         auto name = element.GetName();
436         auto *value = element.GetValue();
437 
438         auto value_type = value->GetType();
439 
440         uint8_t tag_type;
441 
442         if (value_type == Value::Type::ARRAY && !value->GetAsArray()->GetValues().empty()) {
443             auto array_element_type = value->GetAsArray()->GetComponentType();
444             tag_type = static_cast<uint8_t>(Value::GetArrayTypeAsChar(array_element_type));
445         } else {
446             tag_type = static_cast<uint8_t>(Value::GetTypeAsChar(value_type));
447         }
448 
449         ASSERT(tag_type != '0');
450 
451         auto *item = CreateValueItem(container, value, program, entities);
452         if (item == nullptr) {
453             SetLastError("Cannot create value item for annotation element " + name + ": " + GetLastError());
454             return nullptr;
455         }
456 
457         item_elements.emplace_back(container->GetOrCreateStringItem(name), item);
458         tag_elements.emplace_back(tag_type);
459     }
460 
461     auto *cls = entities.class_items.find(record_name)->second;
462     return container->CreateItem<AnnotationItem>(cls, std::move(item_elements), std::move(tag_elements));
463 }
464 
CreateMethodHandleItem(ItemContainer * container,const MethodHandle & mh,const std::unordered_map<std::string,BaseFieldItem * > & fields,const std::unordered_map<std::string,BaseMethodItem * > & methods)465 MethodHandleItem *AsmEmitter::CreateMethodHandleItem(ItemContainer *container, const MethodHandle &mh,
466                                                      const std::unordered_map<std::string, BaseFieldItem *> &fields,
467                                                      const std::unordered_map<std::string, BaseMethodItem *> &methods)
468 {
469     MethodHandleItem *item = nullptr;
470     switch (mh.type) {
471         case panda_file::MethodHandleType::PUT_STATIC:
472         case panda_file::MethodHandleType::GET_STATIC:
473         case panda_file::MethodHandleType::PUT_INSTANCE:
474         case panda_file::MethodHandleType::GET_INSTANCE: {
475             item = container->CreateItem<MethodHandleItem>(mh.type, fields.at(mh.item_name));
476             break;
477         }
478         case panda_file::MethodHandleType::INVOKE_STATIC:
479         case panda_file::MethodHandleType::INVOKE_INSTANCE:
480         case panda_file::MethodHandleType::INVOKE_CONSTRUCTOR:
481         case panda_file::MethodHandleType::INVOKE_DIRECT:
482         case panda_file::MethodHandleType::INVOKE_INTERFACE: {
483             item = container->CreateItem<MethodHandleItem>(mh.type, methods.at(mh.item_name));
484             break;
485         }
486         default:
487             UNREACHABLE();
488             break;
489     }
490     return item;
491 }
492 
493 /* static */
494 template <class T>
AddAnnotations(T * item,ItemContainer * container,const AnnotationMetadata & metadata,const Program & program,const AsmEmitter::AsmEntityCollections & entities)495 bool AsmEmitter::AddAnnotations(T *item, ItemContainer *container, const AnnotationMetadata &metadata,
496                                 const Program &program, const AsmEmitter::AsmEntityCollections &entities)
497 {
498     for (const auto &annotation : metadata.GetAnnotations()) {
499         auto *annotation_item = CreateAnnotationItem(container, annotation, program, entities);
500         if (annotation_item == nullptr) {
501             return false;
502         }
503 
504         /**
505          * When abc is used as input, the function annotation and its corresponding record
506          * are placed into two different programs, which causes the record to be missing
507          * from the record_table of the program that contains the function annotation.
508          */
509         if (program.isGeneratedFromMergedAbc &&
510             program.record_table.find(annotation.GetName()) == program.record_table.cend()) {
511             item->AddAnnotation(annotation_item);
512             continue;
513         }
514 
515         auto &record = program.record_table.find(annotation.GetName())->second;
516         if (record.metadata->IsRuntimeAnnotation()) {
517             item->AddRuntimeAnnotation(annotation_item);
518         } else if (record.metadata->IsAnnotation()) {
519             item->AddAnnotation(annotation_item);
520         } else if (record.metadata->IsRuntimeTypeAnnotation()) {
521             item->AddRuntimeTypeAnnotation(annotation_item);
522         } else if (record.metadata->IsTypeAnnotation()) {
523             item->AddTypeAnnotation(annotation_item);
524         }
525     }
526 
527     return true;
528 }
529 
530 template <class T>
AddDependencyByIndex(MethodItem * method,const Ins & insn,const std::unordered_map<std::string,T * > & items,size_t idx=0)531 static bool AddDependencyByIndex(MethodItem *method, const Ins &insn,
532                                  const std::unordered_map<std::string, T *> &items, size_t idx = 0)
533 {
534     if (idx >= insn.ids.size()) {
535         return false;
536     };
537     const auto &id = insn.ids[idx];
538     auto it = items.find(id);
539     ASSERT(it != items.cend());
540     auto *item = it->second;
541     ASSERT(item->GetIndexType() != panda_file::IndexType::NONE);
542     method->AddIndexDependency(item);
543     return true;
544 }
545 
AddBytecodeIndexDependencies(MethodItem * method,const Function & func,const AsmEmitter::AsmEntityCollections & entities)546 static bool AddBytecodeIndexDependencies(MethodItem *method, const Function &func,
547                                          const AsmEmitter::AsmEntityCollections &entities)
548 {
549     for (const auto &insn : func.ins) {
550         if (insn.opcode == Opcode::INVALID) {
551             continue;
552         }
553 
554         if (insn.opcode == Opcode::DEFINECLASSWITHBUFFER) {
555             if (!AddDependencyByIndex(method, insn, entities.method_items)) {
556                 return false;
557             }
558             if (!AddDependencyByIndex(method, insn, entities.literalarray_items, 1)) {
559                 return false;
560             }
561             continue;
562         }
563 
564         if (insn.opcode == Opcode::CALLRUNTIME_DEFINESENDABLECLASS) {
565             if (!AddDependencyByIndex(method, insn, entities.method_items)) {
566                 return false;
567             }
568             if (!AddDependencyByIndex(method, insn, entities.literalarray_items, 1)) {
569                 return false;
570             }
571             continue;
572         }
573 
574         if (insn.HasFlag(InstFlags::METHOD_ID)) {
575             if (!AddDependencyByIndex(method, insn, entities.method_items)) {
576                 return false;
577             }
578             continue;
579         }
580 
581         if (insn.HasFlag(InstFlags::STRING_ID)) {
582             if (!AddDependencyByIndex(method, insn, entities.string_items)) {
583                 return false;
584             }
585             continue;
586         }
587 
588         if (insn.HasFlag(InstFlags::LITERALARRAY_ID)) {
589             if (!AddDependencyByIndex(method, insn, entities.literalarray_items)) {
590                 return false;
591             }
592         }
593     }
594     return true;
595 }
596 
597 /* static */
MakeStringItems(ItemContainer * items,const Program & program,AsmEmitter::AsmEntityCollections & entities)598 void AsmEmitter::MakeStringItems(ItemContainer *items, const Program &program,
599                                  AsmEmitter::AsmEntityCollections &entities)
600 {
601     for (const auto &s : program.strings) {
602         auto *item = items->GetOrCreateStringItem(s);
603         entities.string_items.insert({s, item});
604     }
605 }
606 
607 /* static */
MakeLiteralItems(ItemContainer * items,const Program & program,AsmEmitter::AsmEntityCollections & entities)608 void AsmEmitter::MakeLiteralItems(ItemContainer *items, const Program &program,
609                                   AsmEmitter::AsmEntityCollections &entities)
610 {
611     for (const auto &[id, l] : program.literalarray_table) {
612         auto *literal_array_item = items->GetOrCreateLiteralArrayItem(id);
613         entities.literalarray_items.insert({id, literal_array_item});
614     }
615 
616     for (const auto &[id, l] : program.literalarray_table) {
617         auto *literal_array_item = entities.literalarray_items.find(id)->second;
618         std::vector<panda_file::LiteralItem> literal_array;
619         for (auto &literal : l.literals_) {
620             std::unique_ptr<ScalarValue> value;
621             switch (literal.tag_) {
622                 case panda_file::LiteralTag::ARRAY_U1: {
623                     ASSERT(program.array_types.find(Type("u1", 1)) != program.array_types.end());
624                     value = std::make_unique<ScalarValue>(
625                         ScalarValue::Create<Value::Type::U1>(static_cast<bool>(std::get<bool>(literal.value_))));
626                     break;
627                 }
628                 case panda_file::LiteralTag::ARRAY_U8: {
629                     ASSERT(program.array_types.find(Type("u8", 1)) != program.array_types.end());
630                     value = std::make_unique<ScalarValue>(
631                         ScalarValue::Create<Value::Type::U8>(std::get<uint8_t>(literal.value_)));
632                     break;
633                 }
634                 case panda_file::LiteralTag::ARRAY_I8: {
635                     ASSERT(program.array_types.find(Type("i8", 1)) != program.array_types.end());
636                     value = std::make_unique<ScalarValue>(
637                         ScalarValue::Create<Value::Type::I8>(std::get<uint8_t>(literal.value_)));
638                     break;
639                 }
640                 case panda_file::LiteralTag::ARRAY_U16: {
641                     ASSERT(program.array_types.find(Type("u16", 1)) != program.array_types.end());
642                     value = std::make_unique<ScalarValue>(
643                         ScalarValue::Create<Value::Type::U16>(std::get<uint16_t>(literal.value_)));
644                     break;
645                 }
646                 case panda_file::LiteralTag::ARRAY_I16: {
647                     ASSERT(program.array_types.find(Type("i16", 1)) != program.array_types.end());
648                     value = std::make_unique<ScalarValue>(
649                         ScalarValue::Create<Value::Type::I16>(std::get<uint16_t>(literal.value_)));
650                     break;
651                 }
652                 case panda_file::LiteralTag::ARRAY_U32: {
653                     ASSERT(program.array_types.find(Type("u32", 1)) != program.array_types.end());
654                     value = std::make_unique<ScalarValue>(
655                         ScalarValue::Create<Value::Type::U32>(std::get<uint32_t>(literal.value_)));
656                     break;
657                 }
658                 case panda_file::LiteralTag::ARRAY_I32: {
659                     ASSERT(program.array_types.find(Type("i32", 1)) != program.array_types.end());
660                     value = std::make_unique<ScalarValue>(
661                         ScalarValue::Create<Value::Type::I32>(std::get<uint32_t>(literal.value_)));
662                     break;
663                 }
664                 case panda_file::LiteralTag::ARRAY_U64: {
665                     ASSERT(program.array_types.find(Type("u64", 1)) != program.array_types.end());
666                     value = std::make_unique<ScalarValue>(
667                         ScalarValue::Create<Value::Type::U64>(std::get<uint64_t>(literal.value_)));
668                     break;
669                 }
670                 case panda_file::LiteralTag::ARRAY_I64: {
671                     ASSERT(program.array_types.find(Type("i64", 1)) != program.array_types.end());
672                     value = std::make_unique<ScalarValue>(
673                         ScalarValue::Create<Value::Type::I64>(std::get<uint64_t>(literal.value_)));
674                     break;
675                 }
676                 case panda_file::LiteralTag::ARRAY_F32: {
677                     ASSERT(program.array_types.find(Type("f32", 1)) != program.array_types.end());
678                     value = std::make_unique<ScalarValue>(
679                         ScalarValue::Create<Value::Type::F32>(std::get<float>(literal.value_)));
680                     break;
681                 }
682                 case panda_file::LiteralTag::ARRAY_F64: {
683                     ASSERT(program.array_types.find(Type("f64", 1)) != program.array_types.end());
684                     value = std::make_unique<ScalarValue>(
685                         ScalarValue::Create<Value::Type::F64>(std::get<double>(literal.value_)));
686                     break;
687                 }
688                 case panda_file::LiteralTag::ARRAY_STRING:
689                     ASSERT(program.array_types.find(Type(
690                         Type::FromDescriptor(panda::panda_file::GetStringClassDescriptor(program.lang)), 1)) !=
691                            program.array_types.end());
692                     value = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::STRING>(
693                         std::string_view(std::get<std::string>(literal.value_))));
694                     break;
695                 case panda_file::LiteralTag::TAGVALUE:
696                 case panda_file::LiteralTag::ACCESSOR:
697                 case panda_file::LiteralTag::NULLVALUE:
698                 case panda_file::LiteralTag::BUILTINTYPEINDEX:
699                     value = std::make_unique<ScalarValue>(
700                         ScalarValue::Create<Value::Type::U8>(static_cast<uint8_t>(std::get<uint8_t>(literal.value_))));
701                     break;
702                 case panda_file::LiteralTag::BOOL:
703                     value = std::make_unique<ScalarValue>(
704                         ScalarValue::Create<Value::Type::U8>(static_cast<uint8_t>(std::get<bool>(literal.value_))));
705                     break;
706                 case panda_file::LiteralTag::METHODAFFILIATE:
707                     value = std::make_unique<ScalarValue>(
708                         ScalarValue::Create<Value::Type::U16>(std::get<uint16_t>(literal.value_)));
709                     break;
710                 case panda_file::LiteralTag::INTEGER:
711                 case panda_file::LiteralTag::LITERALBUFFERINDEX:
712                     value = std::make_unique<ScalarValue>(
713                         ScalarValue::Create<Value::Type::I32>(std::get<uint32_t>(literal.value_)));
714                     break;
715                 case panda_file::LiteralTag::FLOAT:
716                     value = std::make_unique<ScalarValue>(
717                         ScalarValue::Create<Value::Type::F32>(std::get<float>(literal.value_)));
718                     break;
719                 case panda_file::LiteralTag::DOUBLE:
720                     value = std::make_unique<ScalarValue>(
721                         ScalarValue::Create<Value::Type::F64>(std::get<double>(literal.value_)));
722                     break;
723                 case panda_file::LiteralTag::STRING:
724                     value = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::STRING>(
725                         std::string_view(std::get<std::string>(literal.value_))));
726                     break;
727                 case panda_file::LiteralTag::METHOD:
728                 case panda_file::LiteralTag::GETTER:
729                 case panda_file::LiteralTag::SETTER:
730                 case panda_file::LiteralTag::GENERATORMETHOD:
731                 case panda_file::LiteralTag::ASYNCGENERATORMETHOD:
732                     value = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::METHOD>(
733                         std::string_view(std::get<std::string>(literal.value_))));
734                     break;
735                 case panda_file::LiteralTag::LITERALARRAY:
736                     value = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::LITERALARRAY>(
737                         std::string_view(std::get<std::string>(literal.value_))));
738                     break;
739                 default:
740                     UNREACHABLE();
741             }
742 
743             // the return pointer of vector element should not be rewrited
744             CreateLiteralItem(items, value.get(), &literal_array, entities);
745         }
746         literal_array_item->AddItems(literal_array);
747     }
748 }
749 
750 /* static */
MakeArrayTypeItems(ItemContainer * items,const Program & program,AsmEmitter::AsmEntityCollections & entities)751 void AsmEmitter::MakeArrayTypeItems(ItemContainer *items, const Program &program,
752                                     AsmEmitter::AsmEntityCollections &entities)
753 {
754     for (const auto &t : program.array_types) {
755         auto *foreign_record = items->GetOrCreateForeignClassItem(t.GetDescriptor());
756         entities.class_items.insert({t.GetName(), foreign_record});
757     }
758 }
759 
760 /* 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)761 bool AsmEmitter::HandleRecordAsForeign(
762     ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities,
763     const std::unordered_map<panda_file::Type::TypeId, PrimitiveTypeItem *> &primitive_types, const std::string &name,
764     const Record &rec)
765 {
766     Type record_type = Type::FromName(name);
767     auto *foreign_record = items->GetOrCreateForeignClassItem(record_type.GetDescriptor(rec.conflict));
768     entities.class_items.insert({name, foreign_record});
769     for (const auto &f : rec.field_list) {
770         ASSERT(f.metadata->IsForeign());
771         auto *field_name = items->GetOrCreateStringItem(pandasm::DeMangleName(f.name));
772         std::string full_field_name = name + "." + f.name;
773         if (!f.metadata->IsForeign()) {
774             SetLastError("External record " + name + " has a non-external field " + f.name);
775             return false;
776         }
777         auto *type_item = GetTypeItem(items, primitive_types, f.type, program);
778         if (type_item == nullptr) {
779             SetLastError("Field " + full_field_name + " has undefined type");
780             return false;
781         }
782         auto *field = items->CreateItem<ForeignFieldItem>(foreign_record, field_name, type_item);
783         entities.field_items.insert({full_field_name, field});
784     }
785     return true;
786 }
787 
788 /* static */
HandleBaseRecord(ItemContainer * items,const Program & program,const std::string & name,const Record & base_rec,ClassItem * record)789 bool AsmEmitter::HandleBaseRecord(ItemContainer *items, const Program &program, const std::string &name,
790                                   const Record &base_rec, ClassItem *record)
791 {
792     auto base_name = base_rec.metadata->GetBase();
793     if (!base_name.empty()) {
794         auto it = program.record_table.find(base_name);
795         if (it == program.record_table.cend()) {
796             SetLastError("Base record " + base_name + " is not defined for record " + name);
797             return false;
798         }
799         auto &rec = it->second;
800         Type base_type(base_name, 0);
801         if (rec.metadata->IsForeign()) {
802             record->SetSuperClass(items->GetOrCreateForeignClassItem(base_type.GetDescriptor(rec.conflict)));
803         } else {
804             record->SetSuperClass(items->GetOrCreateClassItem(base_type.GetDescriptor(rec.conflict)));
805         }
806     }
807     return true;
808 }
809 
810 /* static */
HandleInterfaces(ItemContainer * items,const Program & program,const std::string & name,const Record & rec,ClassItem * record)811 bool AsmEmitter::HandleInterfaces(ItemContainer *items, const Program &program, const std::string &name,
812                                   const Record &rec, ClassItem *record)
813 {
814     auto ifaces = rec.metadata->GetInterfaces();
815     for (const auto &item : ifaces) {
816         auto it = program.record_table.find(item);
817         if (it == program.record_table.cend()) {
818             SetLastError("Interface record " + item + " is not defined for record " + name);
819             return false;
820         }
821         auto &iface = it->second;
822         Type iface_type(item, 0);
823         if (iface.metadata->IsForeign()) {
824             record->AddInterface(items->GetOrCreateForeignClassItem(iface_type.GetDescriptor(iface.conflict)));
825         } else {
826             record->AddInterface(items->GetOrCreateClassItem(iface_type.GetDescriptor(iface.conflict)));
827         }
828     }
829     return true;
830 }
831 
832 /* 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)833 bool AsmEmitter::HandleFields(ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities,
834                               const std::unordered_map<panda_file::Type::TypeId, PrimitiveTypeItem *> &primitive_types,
835                               const std::string &name, const Record &rec, ClassItem *record)
836 {
837     for (const auto &f : rec.field_list) {
838         std::string full_field_name = name + "." + f.name;
839         if (entities.field_items.find(full_field_name) != entities.field_items.end()) {
840             continue;
841         }
842         auto *field_name = items->GetOrCreateStringItem(pandasm::DeMangleName(f.name));
843         auto *type_item = GetTypeItem(items, primitive_types, f.type, program);
844         if (type_item == nullptr) {
845             SetLastError("Field " + full_field_name + " has undefined type");
846             return false;
847         }
848         BaseFieldItem *field;
849         if (f.metadata->IsForeign()) {
850             field = items->CreateItem<ForeignFieldItem>(record, field_name, type_item);
851         } else {
852             field = record->AddField(field_name, type_item, f.metadata->GetAccessFlags());
853         }
854         entities.field_items.insert({full_field_name, field});
855     }
856     return true;
857 }
858 
859 /* 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)860 bool AsmEmitter::HandleRecord(ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities,
861                               const std::unordered_map<panda_file::Type::TypeId, PrimitiveTypeItem *> &primitive_types,
862                               const std::string &name, const Record &rec)
863 {
864     Type record_type = Type::FromName(name);
865     auto *record = items->GetOrCreateClassItem(record_type.GetDescriptor(rec.conflict));
866     entities.class_items.insert({name, record});
867 
868     record->SetAccessFlags(rec.metadata->GetAccessFlags());
869     record->SetSourceLang(rec.language);
870 
871     if (!rec.source_file.empty()) {
872         auto *source_file_item = items->GetOrCreateStringItem(rec.source_file);
873         record->SetSourceFile(source_file_item);
874     }
875 
876     if (!HandleBaseRecord(items, program, name, rec, record)) {
877         return false;
878     }
879 
880     if (!HandleInterfaces(items, program, name, rec, record)) {
881         return false;
882     }
883 
884     if (!HandleFields(items, program, entities, primitive_types, name, rec, record)) {
885         return false;
886     }
887 
888     return true;
889 }
890 
891 /* static */
MakeRecordItems(ItemContainer * items,const Program & program,AsmEmitter::AsmEntityCollections & entities,const std::unordered_map<panda_file::Type::TypeId,PrimitiveTypeItem * > & primitive_types)892 bool AsmEmitter::MakeRecordItems(
893     ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities,
894     const std::unordered_map<panda_file::Type::TypeId, PrimitiveTypeItem *> &primitive_types)
895 {
896     for (const auto &[name, rec] : program.record_table) {
897         if (rec.metadata->IsForeign()) {
898             if (!HandleRecordAsForeign(items, program, entities, primitive_types, name, rec)) {
899                 return false;
900             }
901         } else {
902             if (!HandleRecord(items, program, entities, primitive_types, name, rec)) {
903                 return false;
904             }
905         }
906     }
907     return true;
908 }
909 
910 /* static */
GetMethodName(ItemContainer * items,const Function & func,const std::string & name)911 StringItem *AsmEmitter::GetMethodName(ItemContainer *items, const Function &func, const std::string &name)
912 {
913     if (func.metadata->IsCtor()) {
914         return items->GetOrCreateStringItem(panda::panda_file::GetCtorName(func.language));
915     } else if (func.metadata->IsCctor()) {
916         return items->GetOrCreateStringItem(panda::panda_file::GetCctorName(func.language));
917     } else {
918         return items->GetOrCreateStringItem(GetItemName(name));
919     }
920 }
921 
922 /* static */
HandleAreaForInner(ItemContainer * items,const Program & program,ClassItem ** area,ForeignClassItem ** foreign_area,const std::string & name,const std::string & record_owner_name)923 bool AsmEmitter::HandleAreaForInner(ItemContainer *items, const Program &program, ClassItem **area,
924                                     ForeignClassItem **foreign_area, const std::string &name,
925                                     const std::string &record_owner_name)
926 {
927     auto iter = program.record_table.find(record_owner_name);
928     if (iter != program.record_table.end()) {
929         auto &rec = iter->second;
930         Type record_owner_type = Type::FromName(record_owner_name);
931         auto descriptor = record_owner_type.GetDescriptor(rec.conflict);
932         if (rec.metadata->IsForeign()) {
933             *foreign_area = items->GetOrCreateForeignClassItem(descriptor);
934             if (*foreign_area == nullptr) {
935                 SetLastError("Unable to create external record " + iter->first);
936                 return false;
937             }
938         } else {
939             *area = items->GetOrCreateClassItem(descriptor);
940             (*area)->SetAccessFlags(rec.metadata->GetAccessFlags());
941         }
942     } else {
943         SetLastError("Function " + name + " is bound to undefined record " + record_owner_name);
944         return false;
945     }
946     return true;
947 }
948 
949 /* static */
HandleRecordOnwer(ItemContainer * items,const Program & program,ClassItem ** area,ForeignClassItem ** foreign_area,const std::string & name,const std::string & record_owner_name)950 bool AsmEmitter::HandleRecordOnwer(ItemContainer *items, const Program &program, ClassItem **area,
951                                    ForeignClassItem **foreign_area, const std::string &name,
952                                    const std::string &record_owner_name)
953 {
954     if (record_owner_name.empty()) {
955         *area = items->GetOrCreateGlobalClassItem();
956         (*area)->SetAccessFlags(ACC_PUBLIC);
957         (*area)->SetSourceLang(program.lang);
958     } else {
959         if (!HandleAreaForInner(items, program, area, foreign_area, name, record_owner_name)) {
960             return false;
961         }
962     }
963     return true;
964 }
965 
966 /* 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)967 bool AsmEmitter::HandleFunctionParams(
968     ItemContainer *items, const Program &program, size_t idx, const std::string &name, const Function &func,
969     const std::unordered_map<panda_file::Type::TypeId, PrimitiveTypeItem *> &primitive_types,
970     std::vector<MethodParamItem> &params)
971 {
972     for (size_t i = idx; i < func.params.size(); i++) {
973         const auto &p = func.params[i].type;
974         auto *type_item = GetTypeItem(items, primitive_types, p, program);
975         if (type_item == nullptr) {
976             SetLastError("Argument " + std::to_string(i) + " of function " + name + " has undefined type");
977             return false;
978         }
979         params.emplace_back(type_item);
980     }
981     return true;
982 }
983 
984 /* static */
HandleFunctionLocalVariables(ItemContainer * items,const Function & func,const std::string & name)985 bool AsmEmitter::HandleFunctionLocalVariables(ItemContainer *items, const Function &func, const std::string &name)
986 {
987     for (const auto &v : func.local_variable_debug) {
988         if (v.name.empty()) {
989             SetLastError("Function '" + name + "' has an empty local variable name");
990             return false;
991         }
992         if (v.signature.empty()) {
993             SetLastError("Function '" + name + "' has an empty local variable signature");
994             return false;
995         }
996         items->GetOrCreateStringItem(v.name);
997         // Skip signature and signature type for parameters
998         ASSERT(v.reg >= 0);
999         if (func.IsParameter(v.reg)) {
1000             continue;
1001         }
1002         items->GetOrCreateStringItem(v.signature);
1003         if (!v.signature_type.empty()) {
1004             items->GetOrCreateStringItem(v.signature_type);
1005         }
1006     }
1007     return true;
1008 }
1009 
1010 /* 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)1011 bool AsmEmitter::CreateMethodItem(ItemContainer *items, AsmEmitter::AsmEntityCollections &entities,
1012                                   const Function &func, TypeItem *type_item, ClassItem *area,
1013                                   ForeignClassItem *foreign_area, uint32_t access_flags, StringItem *method_name,
1014                                   const std::string &mangled_name, const std::string &name,
1015                                   std::vector<MethodParamItem> &params)
1016 {
1017     auto *proto = items->GetOrCreateProtoItem(type_item, params);
1018     BaseMethodItem *method;
1019     if (foreign_area == nullptr) {
1020         if (func.metadata->IsForeign()) {
1021             method = items->CreateItem<ForeignMethodItem>(area, method_name, proto, access_flags);
1022         } else {
1023             method = area->AddMethod(method_name, proto, access_flags, params);
1024             method->SetFunctionKind(func.GetFunctionKind());
1025         }
1026     } else {
1027         if (!func.metadata->IsForeign()) {
1028             SetLastError("Non-external function " + name + " is bound to external record");
1029             return false;
1030         }
1031         method = items->CreateItem<ForeignMethodItem>(foreign_area, method_name, proto, access_flags);
1032     }
1033     entities.method_items.insert({mangled_name, method});
1034     if (!func.metadata->IsForeign()) {
1035         if (!func.source_file.empty()) {
1036             items->GetOrCreateStringItem(func.source_file);
1037         }
1038         if (!func.source_code.empty()) {
1039             items->GetOrCreateStringItem(func.source_code);
1040         }
1041     }
1042     return true;
1043 }
1044 
1045 /* 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)1046 bool AsmEmitter::MakeFunctionItems(
1047     ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities,
1048     const std::unordered_map<panda_file::Type::TypeId, PrimitiveTypeItem *> &primitive_types, bool emit_debug_info)
1049 {
1050     for (const auto &f : program.function_table) {
1051         const auto &[mangled_name, func] = f;
1052 
1053         auto name = pandasm::DeMangleName(mangled_name);
1054 
1055         StringItem *method_name = GetMethodName(items, func, name);
1056 
1057         ClassItem *area = nullptr;
1058         ForeignClassItem *foreign_area = nullptr;
1059 
1060         std::string record_owner_name = GetOwnerName(name);
1061         if (!HandleRecordOnwer(items, program, &area, &foreign_area, name, record_owner_name)) {
1062             return false;
1063         }
1064 
1065         auto params = std::vector<MethodParamItem> {};
1066 
1067         uint32_t access_flags = func.metadata->GetAccessFlags();
1068 
1069         if (func.params.empty() || func.params[0].type.GetName() != record_owner_name) {
1070             access_flags |= ACC_STATIC;
1071         }
1072 
1073         bool is_static = (access_flags & ACC_STATIC) != 0;
1074         size_t idx = is_static ? 0 : 1;
1075 
1076         if (!HandleFunctionParams(items, program, idx, name, func, primitive_types, params)) {
1077             return false;
1078         }
1079 
1080         if (emit_debug_info && !HandleFunctionLocalVariables(items, func, name)) {
1081             return false;
1082         }
1083 
1084         auto *type_item = GetTypeItem(items, primitive_types, func.return_type, program);
1085         if (type_item == nullptr) {
1086             SetLastError("Function " + name + " has undefined return type");
1087             return false;
1088         }
1089 
1090         if (!CreateMethodItem(items, entities, func, type_item, area, foreign_area, access_flags, method_name,
1091                               mangled_name, name, params)) {
1092             return false;
1093         }
1094     }
1095     return true;
1096 }
1097 
CheckDuplicateField(ValueItem & value_item,FieldItem & field_item,std::string & field_name)1098 bool AsmEmitter::CheckDuplicateField(ValueItem &value_item, FieldItem &field_item, std::string &field_name)
1099 {
1100     if (!field_item.GetValue()) {
1101         return true;
1102     }
1103 
1104     if (field_item.GetValue()->IsArray() || value_item.IsArray()) {
1105         SetLastError("Duplicated array type field {" + field_name + "} is not supported.");
1106         return false;
1107     }
1108 
1109     if (field_item.GetValue()->GetAsScalar() == value_item.GetAsScalar()) {
1110         return true;
1111     }
1112     SetLastError("Field {" + field_name + "} has different value.");
1113     return false;
1114 }
1115 
FillFields(ItemContainer * items,const Program & program,const panda::pandasm::Record & record,const AsmEmitter::AsmEntityCollections & entities)1116 bool AsmEmitter::FillFields(ItemContainer *items, const Program &program, const panda::pandasm::Record &record,
1117                             const AsmEmitter::AsmEntityCollections &entities)
1118 {
1119     for (const auto &field : record.field_list) {
1120         auto field_name = record.name + "." + field.name;
1121         auto *field_item = static_cast<FieldItem *>(Find(entities.field_items, field_name));
1122         if (!AddAnnotations(field_item, items, *field.metadata, program, entities)) {
1123             SetLastError("Cannot emit annotations for field " + field_name + ": " + GetLastError());
1124             return false;
1125         }
1126 
1127         auto res = field.metadata->GetValue();
1128         if (res) {
1129             auto value = res.value();
1130             auto *item = CreateValueItem(items, &value, program, entities);
1131             if (!CheckDuplicateField(*item, *field_item, field_name)) {
1132                 return false;
1133             }
1134             field_item->SetValue(item);
1135         }
1136     }
1137     return true;
1138 }
1139 
1140 /* static */
MakeRecordAnnotations(ItemContainer * items,const Program & program,const AsmEmitter::AsmEntityCollections & entities)1141 bool AsmEmitter::MakeRecordAnnotations(ItemContainer *items, const Program &program,
1142                                        const AsmEmitter::AsmEntityCollections &entities)
1143 {
1144     for (const auto &[name, record] : program.record_table) {
1145         if (record.metadata->IsForeign()) {
1146             continue;
1147         }
1148 
1149         auto *class_item = static_cast<ClassItem *>(Find(entities.class_items, name));
1150         if (!AddAnnotations(class_item, items, *record.metadata, program, entities)) {
1151             SetLastError("Cannot emit annotations for record " + record.name + ": " + GetLastError());
1152             return false;
1153         }
1154 
1155         if (!FillFields(items, program, record, entities)) {
1156             return false;
1157         }
1158     }
1159     return true;
1160 }
1161 
1162 /* static */
SetCodeAndDebugInfo(ItemContainer * items,MethodItem * method,const Function & func,bool emit_debug_info)1163 void AsmEmitter::SetCodeAndDebugInfo(ItemContainer *items, MethodItem *method, const Function &func,
1164                                      bool emit_debug_info)
1165 {
1166     auto *code = items->CreateItem<CodeItem>();
1167     method->SetCode(code);
1168     code->AddMethod(method);  // we need it for Profile-Guided optimization
1169 
1170     if (!emit_debug_info && !func.CanThrow()) {
1171         return;
1172     }
1173 
1174     auto *line_number_program = items->CreateLineNumberProgramItem();
1175     auto *debug_info = items->CreateItem<DebugInfoItem>(line_number_program);
1176     if (emit_debug_info) {
1177         for (const auto &v : func.local_variable_debug) {
1178             ASSERT(v.reg >= 0);
1179             if (func.IsParameter(v.reg)) {
1180                 debug_info->AddParameter(items->GetOrCreateStringItem(v.name));
1181             }
1182         }
1183     } else {
1184         auto nparams = method->GetParams().size();
1185         for (size_t i = 0; i < nparams; i++) {
1186             debug_info->AddParameter(nullptr);
1187         }
1188     }
1189     method->SetDebugInfo(debug_info);
1190 }
1191 
1192 /* static */
AddMethodAndParamsAnnotations(ItemContainer * items,const Program & program,const AsmEmitter::AsmEntityCollections & entities,MethodItem * method,const Function & func)1193 bool AsmEmitter::AddMethodAndParamsAnnotations(ItemContainer *items, const Program &program,
1194                                                const AsmEmitter::AsmEntityCollections &entities, MethodItem *method,
1195                                                const Function &func)
1196 {
1197     if (!AddAnnotations(method, items, *func.metadata, program, entities)) {
1198         SetLastError("Cannot emit annotations for function " + func.name + ": " + GetLastError());
1199         return false;
1200     }
1201 
1202     auto &param_items = method->GetParams();
1203     for (size_t proto_idx = 0; proto_idx < param_items.size(); proto_idx++) {
1204         size_t param_idx = method->IsStatic() ? proto_idx : proto_idx + 1;
1205         auto &param_item = param_items[proto_idx];
1206         // The parameter metadata of ArkTS is always of a default value instead of a dynamically
1207         // generated one from ArkTS sources, so it is created here to reduce the compilation memory.
1208         auto metadata = extensions::MetadataExtension::CreateParamMetadata(pandasm::extensions::Language::ECMASCRIPT);
1209         if (!AddAnnotations(&param_item, items, *metadata, program, entities)) {
1210             SetLastError("Cannot emit annotations for parameter a" + std::to_string(param_idx) + "of function " +
1211                          func.name + ": " + GetLastError());
1212             return false;
1213         }
1214     }
1215 
1216     if (method->HasRuntimeParamAnnotations()) {
1217         items->CreateItem<ParamAnnotationsItem>(method, true);
1218     }
1219 
1220     if (method->HasParamAnnotations()) {
1221         items->CreateItem<ParamAnnotationsItem>(method, false);
1222     }
1223 
1224     return true;
1225 }
1226 
1227 /* static */
MakeFunctionDebugInfoAndAnnotations(ItemContainer * items,const Program & program,const AsmEmitter::AsmEntityCollections & entities,bool emit_debug_info)1228 bool AsmEmitter::MakeFunctionDebugInfoAndAnnotations(ItemContainer *items, const Program &program,
1229                                                      const AsmEmitter::AsmEntityCollections &entities,
1230                                                      bool emit_debug_info)
1231 {
1232     for (const auto &[name, func] : program.function_table) {
1233         if (func.metadata->IsForeign()) {
1234             continue;
1235         }
1236 
1237         auto *method = static_cast<MethodItem *>(Find(entities.method_items, name));
1238 
1239         SetCodeAndDebugInfo(items, method, func, emit_debug_info);
1240         if (!AddBytecodeIndexDependencies(method, func, entities)) {
1241             return false;
1242         }
1243 
1244         method->SetSourceLang(func.language);
1245 
1246         if (!AddMethodAndParamsAnnotations(items, program, entities, method, func)) {
1247             return false;
1248         }
1249     }
1250     return true;
1251 }
1252 
1253 /* static */
FillMap(PandaFileToPandaAsmMaps * maps,AsmEmitter::AsmEntityCollections & entities)1254 void AsmEmitter::FillMap(PandaFileToPandaAsmMaps *maps, AsmEmitter::AsmEntityCollections &entities)
1255 {
1256     for (const auto &[name, method] : entities.method_items) {
1257         maps->methods.insert({method->GetFileId().GetOffset(), std::string(name)});
1258     }
1259 
1260     for (const auto &[name, field] : entities.field_items) {
1261         maps->fields.insert({field->GetFileId().GetOffset(), std::string(name)});
1262     }
1263 
1264     for (const auto &[name, cls] : entities.class_items) {
1265         maps->classes.insert({cls->GetFileId().GetOffset(), std::string(name)});
1266     }
1267 
1268     for (const auto &[name, str] : entities.string_items) {
1269         maps->strings.insert({str->GetFileId().GetOffset(), std::string(name)});
1270     }
1271 
1272     for (const auto &[name, arr] : entities.literalarray_items) {
1273         maps->literalarrays.emplace(arr->GetFileId().GetOffset(), name);
1274     }
1275 }
1276 
1277 /* 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)1278 void AsmEmitter::EmitDebugInfo(ItemContainer *items, const Program &program, const std::vector<uint8_t> *bytes,
1279                                const MethodItem *method, const Function &func, const std::string &name,
1280                                bool emit_debug_info)
1281 {
1282     auto *debug_info = method->GetDebugInfo();
1283     if (debug_info == nullptr) {
1284         return;
1285     }
1286 
1287     auto *line_number_program = debug_info->GetLineNumberProgram();
1288     auto *constant_pool = debug_info->GetConstantPool();
1289 
1290     std::string record_name = GetOwnerName(name);
1291     std::string record_source_file;
1292     if (!record_name.empty()) {
1293         auto &rec = program.record_table.find(record_name)->second;
1294         record_source_file = rec.source_file;
1295     }
1296 
1297     if (!func.source_file.empty() && func.source_file != record_source_file) {
1298         if (!func.source_code.empty()) {
1299             auto *source_code_item = items->GetOrCreateStringItem(func.source_code);
1300             ASSERT(source_code_item->GetOffset() != 0);
1301             line_number_program->EmitSetSourceCode(constant_pool, source_code_item);
1302         }
1303         auto *source_file_item = items->GetOrCreateStringItem(func.source_file);
1304         ASSERT(source_file_item->GetOffset() != 0);
1305         line_number_program->EmitSetFile(constant_pool, source_file_item);
1306     }
1307     func.BuildLineNumberProgram(debug_info, *bytes, items, constant_pool, emit_debug_info);
1308 }
1309 
1310 /* static */
EmitFunctions(ItemContainer * items,const Program & program,const AsmEmitter::AsmEntityCollections & entities,bool emit_debug_info)1311 bool AsmEmitter::EmitFunctions(ItemContainer *items, const Program &program,
1312                                const AsmEmitter::AsmEntityCollections &entities, bool emit_debug_info)
1313 {
1314     for (const auto &f : program.function_table) {
1315         const auto &[name, func] = f;
1316 
1317         if (func.metadata->IsForeign()) {
1318             continue;
1319         }
1320 
1321         auto emitter = BytecodeEmitter {};
1322         auto *method = static_cast<MethodItem *>(Find(entities.method_items, name));
1323         if (!func.Emit(emitter, method, entities.method_items, entities.field_items, entities.class_items,
1324                        entities.string_items, entities.literalarray_items)) {
1325             SetLastError("Internal error during emitting function: " + func.name);
1326             return false;
1327         }
1328 
1329         auto *code = method->GetCode();
1330         code->SetNumVregs(func.regs_num);
1331         code->SetNumArgs(func.GetParamsNum());
1332 
1333         auto num_ins = static_cast<size_t>(
1334             std::count_if(func.ins.begin(), func.ins.end(), [](auto it) { return it.opcode != Opcode::INVALID; }));
1335         code->SetNumInstructions(num_ins);
1336 
1337         auto *bytes = code->GetInstructions();
1338         auto status = emitter.Build(static_cast<std::vector<unsigned char> *>(bytes));
1339         if (status != BytecodeEmitter::ErrorCode::SUCCESS) {
1340             SetLastError("Internal error during emitting binary code, status=" +
1341                          std::to_string(static_cast<int>(status)));
1342             return false;
1343         }
1344         auto try_blocks = func.BuildTryBlocks(method, entities.class_items, *bytes);
1345         for (auto &try_block : try_blocks) {
1346             code->AddTryBlock(try_block);
1347         }
1348 
1349         EmitDebugInfo(items, program, bytes, method, func, name, emit_debug_info);
1350     }
1351     return true;
1352 }
1353 
1354 /* static */
MakeItemsForSingleProgram(ItemContainer * items,const Program & program,bool emit_debug_info,AsmEmitter::AsmEntityCollections & entities,std::unordered_map<panda_file::Type::TypeId,PrimitiveTypeItem * > primitive_types)1355 bool AsmEmitter::MakeItemsForSingleProgram(ItemContainer *items, const Program &program, bool emit_debug_info,
1356     AsmEmitter::AsmEntityCollections &entities,
1357     std::unordered_map<panda_file::Type::TypeId, PrimitiveTypeItem *> primitive_types)
1358 {
1359     MakeStringItems(items, program, entities);
1360     MakeArrayTypeItems(items, program, entities);
1361     if (!MakeRecordItems(items, program, entities, primitive_types)) {
1362         return false;
1363     }
1364     if (!MakeFunctionItems(items, program, entities, primitive_types, emit_debug_info)) {
1365         return false;
1366     }
1367     MakeLiteralItems(items, program, entities);
1368     // Add annotations for records and fields
1369     if (!MakeRecordAnnotations(items, program, entities)) {
1370         return false;
1371     }
1372     return true;
1373 }
1374 
EmitPrograms(const std::string & filename,const std::vector<Program * > & progs,bool emit_debug_info,uint8_t api,std::string subApi)1375 bool AsmEmitter::EmitPrograms(const std::string &filename, const std::vector<Program *> &progs, bool emit_debug_info,
1376                               uint8_t api, std::string subApi)
1377 {
1378     ASSERT(!progs.empty());
1379 
1380     ItemContainer::SetApi(api);
1381     ItemContainer::SetSubApi(subApi);
1382     auto items = ItemContainer {};
1383     auto primitive_types = CreatePrimitiveTypes(&items);
1384     auto entities = AsmEmitter::AsmEntityCollections {};
1385     SetLastError("");
1386 
1387     for (auto *prog : progs) {
1388         if (!MakeItemsForSingleProgram(&items, *prog, emit_debug_info, entities, primitive_types)) {
1389             return false;
1390         }
1391         prog->strings.clear();
1392         prog->literalarray_table.clear();
1393         prog->array_types.clear();
1394     }
1395 
1396     for (auto *prog : progs) {
1397         if (!MakeFunctionDebugInfoAndAnnotations(&items, *prog, entities, emit_debug_info)) {
1398             return false;
1399         }
1400         prog->function_synonyms.clear();
1401     }
1402 
1403     items.ReLayout();
1404     items.ComputeLayout();
1405 
1406     for (auto *prog : progs) {
1407         if (!EmitFunctions(&items, *prog, entities, emit_debug_info)) {
1408             return false;
1409         }
1410         prog->function_table.clear();
1411         prog->record_table.clear();
1412     }
1413 
1414     auto writer = FileWriter(filename);
1415     if (!writer) {
1416         SetLastError("Unable to open" + filename + " for writing");
1417         return false;
1418     }
1419 
1420     return items.Write(&writer);
1421 }
1422 
1423 /* static */
Emit(ItemContainer * items,const Program & program,PandaFileToPandaAsmMaps * maps,bool emit_debug_info,panda::panda_file::pgo::ProfileOptimizer * profile_opt)1424 bool AsmEmitter::Emit(ItemContainer *items, const Program &program, PandaFileToPandaAsmMaps *maps, bool emit_debug_info,
1425                       panda::panda_file::pgo::ProfileOptimizer *profile_opt)
1426 {
1427     auto primitive_types = CreatePrimitiveTypes(items);
1428 
1429     auto entities = AsmEmitter::AsmEntityCollections {};
1430 
1431     SetLastError("");
1432 
1433     if (!MakeItemsForSingleProgram(items, program, emit_debug_info, entities, primitive_types)) {
1434         return false;
1435     }
1436 
1437     // Add Code and DebugInfo items last due to they have variable size that depends on bytecode
1438     if (!MakeFunctionDebugInfoAndAnnotations(items, program, entities, emit_debug_info)) {
1439         return false;
1440     }
1441 
1442     if (profile_opt != nullptr) {
1443         items->ReorderItems(profile_opt);
1444     }
1445 
1446     items->ComputeLayout();
1447 
1448     if (maps != nullptr) {
1449         FillMap(maps, entities);
1450     }
1451 
1452     if (!EmitFunctions(items, program, entities, emit_debug_info)) {
1453         return false;
1454     }
1455 
1456     return true;
1457 }
1458 
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)1459 bool AsmEmitter::Emit(Writer *writer, const Program &program, std::map<std::string, size_t> *stat,
1460                       PandaFileToPandaAsmMaps *maps, bool debug_info,
1461                       panda::panda_file::pgo::ProfileOptimizer *profile_opt, uint8_t api, std::string subApi)
1462 {
1463     ItemContainer::SetApi(api);
1464     ItemContainer::SetSubApi(subApi);
1465     auto items = ItemContainer {};
1466     if (!Emit(&items, program, maps, debug_info, profile_opt)) {
1467         return false;
1468     }
1469 
1470     if (stat != nullptr) {
1471         *stat = items.GetStat();
1472     }
1473 
1474     return items.Write(writer);
1475 }
1476 
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)1477 bool AsmEmitter::Emit(const std::string &filename, const Program &program, std::map<std::string, size_t> *stat,
1478                       PandaFileToPandaAsmMaps *maps, bool debug_info,
1479                       panda::panda_file::pgo::ProfileOptimizer *profile_opt, uint8_t api, std::string subApi)
1480 {
1481     auto writer = FileWriter(filename);
1482     if (!writer) {
1483         SetLastError("Unable to open" + filename + " for writing");
1484         return false;
1485     }
1486     return Emit(&writer, program, stat, maps, debug_info, profile_opt, api, subApi);
1487 }
1488 
Emit(const Program & program,PandaFileToPandaAsmMaps * maps,uint8_t api,std::string subApi)1489 std::unique_ptr<const panda_file::File> AsmEmitter::Emit(const Program &program, PandaFileToPandaAsmMaps *maps,
1490                                                          uint8_t api, std::string subApi)
1491 {
1492     ItemContainer::SetApi(api);
1493     ItemContainer::SetSubApi(subApi);
1494     auto items = ItemContainer {};
1495     if (!Emit(&items, program, maps)) {
1496         return nullptr;
1497     }
1498 
1499     size_t size = items.ComputeLayout();
1500     auto *buffer = new std::byte[size];
1501 
1502     auto writer = MemoryBufferWriter(reinterpret_cast<uint8_t *>(buffer), size);
1503     if (!items.Write(&writer)) {
1504         return nullptr;
1505     }
1506 
1507     os::mem::ConstBytePtr ptr(
1508         buffer, size, [](std::byte *buffer_ptr, [[maybe_unused]] size_t param_size) noexcept { delete[] buffer_ptr; });
1509     return panda_file::File::OpenFromMemory(std::move(ptr));
1510 }
1511 
GetTypeItem(ItemContainer * items,const std::unordered_map<panda_file::Type::TypeId,PrimitiveTypeItem * > & primitive_types,const Type & type,const Program & program)1512 TypeItem *AsmEmitter::GetTypeItem(
1513     ItemContainer *items, const std::unordered_map<panda_file::Type::TypeId, PrimitiveTypeItem *> &primitive_types,
1514     const Type &type, const Program &program)
1515 {
1516     if (!type.IsObject()) {
1517         return Find(primitive_types, type.GetId());
1518     }
1519 
1520     if (type.IsArray()) {
1521         return items->GetOrCreateForeignClassItem(type.GetDescriptor());
1522     }
1523 
1524     const auto &name = type.GetName();
1525     auto iter = program.record_table.find(name);
1526     if (iter == program.record_table.end()) {
1527         return nullptr;
1528     }
1529 
1530     auto &rec = iter->second;
1531 
1532     if (rec.metadata->IsForeign()) {
1533         return items->GetOrCreateForeignClassItem(type.GetDescriptor());
1534     }
1535 
1536     return items->GetOrCreateClassItem(type.GetDescriptor());
1537 }
1538 
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) const1539 bool Function::Emit(BytecodeEmitter &emitter, panda_file::MethodItem *method,
1540                     const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
1541                     const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
1542                     const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
1543                     const std::unordered_map<std::string, panda_file::StringItem *> &strings,
1544                     const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays) const
1545 {
1546     auto labels = std::unordered_map<std::string_view, panda::Label> {};
1547 
1548     for (const auto &insn : ins) {
1549         if (insn.set_label) {
1550             labels.insert_or_assign(insn.label, emitter.CreateLabel());
1551         }
1552     }
1553 
1554     for (const auto &insn : ins) {
1555         if (insn.set_label) {
1556             auto search = labels.find(insn.label);
1557             ASSERT(search != labels.end());
1558             emitter.Bind(search->second);
1559         }
1560 
1561         if (insn.opcode != Opcode::INVALID) {
1562             if (!insn.Emit(emitter, method, methods, fields, classes, strings, literalarrays, labels)) {
1563                 return false;
1564             }
1565         }
1566     }
1567 
1568     return true;
1569 }
1570 
TryEmitPc(panda_file::LineNumberProgramItem * program,std::vector<uint8_t> * constant_pool,uint32_t & pc_inc)1571 static void TryEmitPc(panda_file::LineNumberProgramItem *program, std::vector<uint8_t> *constant_pool,
1572                       uint32_t &pc_inc)
1573 {
1574     if (pc_inc) {
1575         program->EmitAdvancePc(constant_pool, pc_inc);
1576         pc_inc = 0;
1577     }
1578 }
1579 
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) const1580 void Function::EmitLocalVariable(panda_file::LineNumberProgramItem *program, ItemContainer *container,
1581                                  std::vector<uint8_t> *constant_pool, uint32_t &pc_inc, size_t instruction_number,
1582                                  size_t variable_index) const
1583 {
1584     ASSERT(variable_index < local_variable_debug.size());
1585     const auto &v = local_variable_debug[variable_index];
1586     ASSERT(!IsParameter(v.reg));
1587     if (instruction_number == v.start) {
1588         TryEmitPc(program, constant_pool, pc_inc);
1589         StringItem *variable_name = container->GetOrCreateStringItem(v.name);
1590         StringItem *variable_type = container->GetOrCreateStringItem(v.signature);
1591         if (v.signature_type.empty()) {
1592             program->EmitStartLocal(constant_pool, v.reg, variable_name, variable_type);
1593         } else {
1594             StringItem *type_signature = container->GetOrCreateStringItem(v.signature_type);
1595             program->EmitStartLocalExtended(constant_pool, v.reg, variable_name, variable_type, type_signature);
1596         }
1597     }
1598 
1599     if (instruction_number == (v.start + v.length)) {
1600         TryEmitPc(program, constant_pool, pc_inc);
1601         program->EmitEndLocal(v.reg);
1602     }
1603 }
1604 
GetLineNumber(size_t i) const1605 size_t Function::GetLineNumber(size_t i) const
1606 {
1607     return ins[i].ins_debug.line_number;
1608 }
1609 
GetColumnNumber(size_t i) const1610 uint32_t Function::GetColumnNumber(size_t i) const
1611 {
1612     return ins[i].ins_debug.column_number;
1613 }
1614 
EmitNumber(panda_file::LineNumberProgramItem * program,std::vector<uint8_t> * constant_pool,uint32_t pc_inc,int32_t line_inc) const1615 void Function::EmitNumber(panda_file::LineNumberProgramItem *program, std::vector<uint8_t> *constant_pool,
1616                           uint32_t pc_inc, int32_t line_inc) const
1617 {
1618     if (!program->EmitSpecialOpcode(pc_inc, line_inc)) {
1619         if (pc_inc) {
1620             program->EmitAdvancePc(constant_pool, pc_inc);
1621             if (!program->EmitSpecialOpcode(0, line_inc)) {
1622                 program->EmitAdvanceLine(constant_pool, line_inc);
1623                 program->EmitSpecialOpcode(0, 0);
1624             }
1625         } else {
1626             program->EmitAdvanceLine(constant_pool, line_inc);
1627             program->EmitSpecialOpcode(0, 0);
1628         }
1629     }
1630 }
1631 
EmitLineNumber(panda_file::LineNumberProgramItem * program,std::vector<uint8_t> * constant_pool,int32_t & prev_line_number,uint32_t & pc_inc,size_t instruction_number) const1632 void Function::EmitLineNumber(panda_file::LineNumberProgramItem *program, std::vector<uint8_t> *constant_pool,
1633                               int32_t &prev_line_number, uint32_t &pc_inc, size_t instruction_number) const
1634 {
1635     int32_t line_inc = static_cast<int32_t>(GetLineNumber(instruction_number)) - prev_line_number;
1636     if (line_inc) {
1637         prev_line_number = static_cast<int32_t>(GetLineNumber(instruction_number));
1638         EmitNumber(program, constant_pool, pc_inc, line_inc);
1639         pc_inc = 0;
1640     }
1641 }
1642 
EmitColumnNumber(panda_file::LineNumberProgramItem * program,std::vector<uint8_t> * constant_pool,uint32_t & prev_column_number,uint32_t & pc_inc,size_t instruction_number) const1643 void Function::EmitColumnNumber(panda_file::LineNumberProgramItem *program, std::vector<uint8_t> *constant_pool,
1644                                 uint32_t &prev_column_number, uint32_t &pc_inc, size_t instruction_number) const
1645 {
1646     auto cn = GetColumnNumber(instruction_number);
1647     if (cn != prev_column_number) {
1648         program->EmitColumn(constant_pool, pc_inc, cn);
1649         pc_inc = 0;
1650         prev_column_number = cn;
1651     }
1652 }
1653 
CollectLocalVariable(std::vector<Function::LocalVariablePair> & local_variable_info) const1654 void Function::CollectLocalVariable(std::vector<Function::LocalVariablePair> &local_variable_info) const
1655 {
1656     for (size_t i = 0; i < local_variable_debug.size(); i++) {
1657         const auto &v = local_variable_debug[i];
1658         if (IsParameter(v.reg)) {
1659             continue;
1660         }
1661         local_variable_info.emplace_back(v.start, i);
1662         local_variable_info.emplace_back(v.start + v.length, i);
1663     }
1664 
1665     std::sort(local_variable_info.begin(), local_variable_info.end(),
1666         [this](const Function::LocalVariablePair &a, const Function::LocalVariablePair &b) {
1667         auto a_var = this->local_variable_debug[a.variable_index];
1668         auto b_var = this->local_variable_debug[b.variable_index];
1669         // If the same register is first used by a_var, and then used by b_var, the ending position of a_var needs
1670         // to be equal or less then the starting position of b_var. This is to keep the order in local_variable_debug
1671         // to make sure that if the usage of a_var start first, it will end first.
1672         if (a.insn_order == b.insn_order && a_var.reg == b_var.reg) {
1673             return a_var.start < b_var.start;
1674         }
1675         return a.insn_order < b.insn_order;
1676     });
1677 }
1678 
BuildLineNumberProgram(panda_file::DebugInfoItem * debug_item,const std::vector<uint8_t> & bytecode,ItemContainer * container,std::vector<uint8_t> * constant_pool,bool emit_debug_info) const1679 void Function::BuildLineNumberProgram(panda_file::DebugInfoItem *debug_item, const std::vector<uint8_t> &bytecode,
1680                                       ItemContainer *container, std::vector<uint8_t> *constant_pool,
1681                                       bool emit_debug_info) const
1682 {
1683     auto *program = debug_item->GetLineNumberProgram();
1684 
1685     if (ins.empty()) {
1686         program->EmitEnd();
1687         return;
1688     }
1689 
1690     uint32_t pc_inc = 0;
1691     auto prev_line_number = static_cast<int32_t>(GetLineNumber(0));
1692     uint32_t prev_column_number = std::numeric_limits<uint32_t>::max();
1693     BytecodeInstruction bi(bytecode.data());
1694     debug_item->SetLineNumber(static_cast<uint32_t>(prev_line_number));
1695 
1696     std::vector<Function::LocalVariablePair> local_variable_info;
1697     if (emit_debug_info) {
1698         CollectLocalVariable(local_variable_info);
1699     }
1700     const size_t num_ins = ins.size();
1701     size_t start = 0;
1702     auto iter = local_variable_info.begin();
1703     do {
1704         size_t end = emit_debug_info && iter != local_variable_info.end() ? iter->insn_order : num_ins;
1705         for (size_t i = start; i < end; i++) {
1706             /**
1707              * If you change the continue condition of this loop, you need to synchronously modify the same condition
1708              * of the BuildMapFromPcToIns method in the optimizer-bytecode.cpp.
1709              **/
1710             if (ins[i].opcode == Opcode::INVALID) {
1711                 continue;
1712             }
1713             if (emit_debug_info || ins[i].CanThrow()) {
1714                 EmitLineNumber(program, constant_pool, prev_line_number, pc_inc, i);
1715             }
1716             if (emit_debug_info) {
1717                 EmitColumnNumber(program, constant_pool, prev_column_number, pc_inc, i);
1718             }
1719             pc_inc += bi.GetSize();
1720             bi = bi.GetNext();
1721         }
1722         if (iter == local_variable_info.end()) {
1723             break;
1724         }
1725         if (emit_debug_info) {
1726             EmitLocalVariable(program, container, constant_pool, pc_inc, end, iter->variable_index);
1727         }
1728         start = end;
1729         iter++;
1730     } while (true);
1731 
1732     program->EmitEnd();
1733 }
1734 
MakeOrderAndOffsets(const std::vector<uint8_t> & bytecode) const1735 Function::TryCatchInfo Function::MakeOrderAndOffsets(const std::vector<uint8_t> &bytecode) const
1736 {
1737     std::unordered_map<std::string_view, size_t> try_catch_labels;
1738     std::unordered_map<std::string, std::vector<const CatchBlock *>> try_catch_map;
1739     std::vector<std::string> try_catch_order;
1740 
1741     for (auto &catch_block : catch_blocks) {
1742         try_catch_labels.insert_or_assign(catch_block.try_begin_label, 0);
1743         try_catch_labels.insert_or_assign(catch_block.try_end_label, 0);
1744         try_catch_labels.insert_or_assign(catch_block.catch_begin_label, 0);
1745         try_catch_labels.insert_or_assign(catch_block.catch_end_label, 0);
1746 
1747         std::string try_key = catch_block.try_begin_label + ":" + catch_block.try_end_label;
1748         auto it = try_catch_map.find(try_key);
1749         if (it == try_catch_map.cend()) {
1750             std::tie(it, std::ignore) = try_catch_map.try_emplace(try_key);
1751             try_catch_order.push_back(try_key);
1752         }
1753         it->second.push_back(&catch_block);
1754     }
1755 
1756     BytecodeInstruction bi(bytecode.data());
1757     size_t pc_offset = 0;
1758 
1759     for (size_t i = 0; i < ins.size(); i++) {
1760         if (ins[i].set_label) {
1761             auto it = try_catch_labels.find(ins[i].label);
1762             if (it != try_catch_labels.cend()) {
1763                 try_catch_labels[ins[i].label] = pc_offset;
1764             }
1765         }
1766         if (ins[i].opcode == Opcode::INVALID) {
1767             continue;
1768         }
1769 
1770         pc_offset += bi.GetSize();
1771         bi = bi.GetNext();
1772     }
1773 
1774     return Function::TryCatchInfo {try_catch_labels, try_catch_map, try_catch_order};
1775 }
1776 
BuildTryBlocks(MethodItem * method,const std::unordered_map<std::string,BaseClassItem * > & class_items,const std::vector<uint8_t> & bytecode) const1777 std::vector<CodeItem::TryBlock> Function::BuildTryBlocks(
1778     MethodItem *method, const std::unordered_map<std::string, BaseClassItem *> &class_items,
1779     const std::vector<uint8_t> &bytecode) const
1780 {
1781     std::vector<CodeItem::TryBlock> try_blocks;
1782 
1783     if (ins.empty()) {
1784         return try_blocks;
1785     }
1786 
1787     Function::TryCatchInfo tcs = MakeOrderAndOffsets(bytecode);
1788 
1789     for (const auto &t_key : tcs.try_catch_order) {
1790         auto kv = tcs.try_catch_map.find(t_key);
1791         ASSERT(kv != tcs.try_catch_map.cend());
1792         auto &try_catch_blocks = kv->second;
1793 
1794         ASSERT(!try_catch_blocks.empty());
1795 
1796         std::vector<CodeItem::CatchBlock> catch_block_items;
1797 
1798         for (auto *catch_block : try_catch_blocks) {
1799             auto class_name = catch_block->exception_record;
1800 
1801             BaseClassItem *class_item = nullptr;
1802             if (!class_name.empty()) {
1803                 auto it = class_items.find(class_name);
1804                 ASSERT(it != class_items.cend());
1805                 class_item = it->second;
1806             }
1807 
1808             auto handler_pc_offset = tcs.try_catch_labels[catch_block->catch_begin_label];
1809             auto handler_code_size = tcs.try_catch_labels[catch_block->catch_end_label] - handler_pc_offset;
1810             catch_block_items.emplace_back(method, class_item, handler_pc_offset, handler_code_size);
1811         }
1812 
1813         auto try_start_pc_offset = tcs.try_catch_labels[try_catch_blocks[0]->try_begin_label];
1814         auto try_end_pc_offset = tcs.try_catch_labels[try_catch_blocks[0]->try_end_label];
1815         ASSERT(try_end_pc_offset >= try_start_pc_offset);
1816         try_blocks.emplace_back(try_start_pc_offset, try_end_pc_offset - try_start_pc_offset, catch_block_items);
1817     }
1818 
1819     return try_blocks;
1820 }
1821 
DebugDump() const1822 void Function::DebugDump() const
1823 {
1824     std::cerr << "name: " << name << std::endl;
1825     for (const auto &i : ins) {
1826         std::cerr << i.ToString("\n", true, regs_num);
1827     }
1828 }
1829 
GetOwnerName(std::string name)1830 std::string GetOwnerName(std::string name)
1831 {
1832     name = DeMangleName(name);
1833     auto super_pos = name.find_last_of(PARSE_AREA_MARKER);
1834     if (super_pos == std::string::npos) {
1835         return "";
1836     }
1837 
1838     return name.substr(0, super_pos);
1839 }
1840 
GetItemName(std::string name)1841 std::string GetItemName(std::string name)
1842 {
1843     name = DeMangleName(name);
1844     auto super_pos = name.find_last_of(PARSE_AREA_MARKER);
1845     if (super_pos == std::string::npos) {
1846         return name;
1847     }
1848 
1849     return name.substr(super_pos + 1);
1850 }
1851 
1852 }  // namespace panda::pandasm
1853