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