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