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