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