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