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